summaryrefslogtreecommitdiff
path: root/src/linux/NodeStyleEditor.m
diff options
context:
space:
mode:
Diffstat (limited to 'src/linux/NodeStyleEditor.m')
-rw-r--r--src/linux/NodeStyleEditor.m469
1 files changed, 469 insertions, 0 deletions
diff --git a/src/linux/NodeStyleEditor.m b/src/linux/NodeStyleEditor.m
new file mode 100644
index 0000000..38f78ca
--- /dev/null
+++ b/src/linux/NodeStyleEditor.m
@@ -0,0 +1,469 @@
+/*
+ * Copyright 2011 Alex Merry <dev@randomguy3.me.uk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#import "NodeStyleEditor.h"
+#import "NodeStyle.h"
+#import "NodeStyle+Gtk.h"
+#import "Shape.h"
+
+static const guint row_count = 5;
+
+// {{{ Internal interfaces
+// {{{ GTK+ Callbacks
+static void style_name_edit_changed_cb (GtkEditable *widget, NodeStyleEditor *editor);
+static void style_shape_combo_changed_cb (GtkComboBox *widget, NodeStyleEditor *editor);
+static void stroke_color_changed_cb (GtkColorButton *widget, NodeStyleEditor *editor);
+static void fill_color_changed_cb (GtkColorButton *widget, NodeStyleEditor *editor);
+static void make_stroke_safe_button_clicked_cb (GtkButton *widget, NodeStyleEditor *editor);
+static void make_fill_safe_button_clicked_cb (GtkButton *widget, NodeStyleEditor *editor);
+static void scale_adjustment_changed_cb (GtkAdjustment *widget, NodeStyleEditor *editor);
+// }}}
+// {{{ Notifications
+
+@interface NodeStyleEditor (Notifications)
+- (void) shapeDictionaryReplaced:(NSNotification*)n;
+- (void) nameChangedTo:(NSString*)value;
+- (void) shapeNameChangedTo:(NSString*)value;
+- (void) strokeColorChangedTo:(GdkColor)value;
+- (void) makeStrokeColorTexSafe;
+- (void) fillColorChangedTo:(GdkColor)value;
+- (void) makeFillColorTexSafe;
+- (void) scaleChangedTo:(double)value;
+@end
+
+// }}}
+// {{{ Private
+
+@interface NodeStyleEditor (Private)
+- (void) loadShapeNames;
+- (void) setActiveShapeName:(NSString*)name;
+@end
+
+// }}}
+// }}}
+// {{{ API
+
+@implementation NodeStyleEditor
+
+- (void) _addWidget:(GtkWidget*)w withLabel:(gchar *)label atRow:(guint)row {
+ NSAssert(row < row_count, @"row_count is wrong!");
+
+ GtkWidget *l = gtk_label_new (label);
+ gtk_widget_show (l);
+ gtk_widget_show (w);
+
+ gtk_table_attach (table, l,
+ 0, 1, row, row+1, // l, r, t, b
+ GTK_FILL, // x opts
+ GTK_FILL | GTK_EXPAND, // y opts
+ 5, // x padding
+ 0); // y padding
+
+ gtk_table_attach (table, w,
+ 1, 2, row, row+1, // l, r, t, b
+ GTK_FILL | GTK_EXPAND, // x opts
+ GTK_FILL | GTK_EXPAND, // y opts
+ 0, // x padding
+ 0); // y padding
+}
+
+- (GtkWidget*) _createMakeColorTexSafeButton:(NSString*)type {
+ GtkWidget *b = gtk_button_new ();
+ GtkWidget *icon = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_BUTTON);
+ gtk_widget_show (icon);
+ gtk_container_add (GTK_CONTAINER (b), icon);
+ NSString *ttip = [NSString stringWithFormat:@"The %@ colour is not a predefined TeX colour.\nClick here to choose the nearest TeX-safe colour.", type];
+ gtk_widget_set_tooltip_text (b, [ttip UTF8String]);
+ return b;
+}
+
+- (id) init {
+ self = [super init];
+
+ if (self != nil) {
+ style = nil;
+ table = GTK_TABLE (gtk_table_new (row_count, 2, FALSE));
+ gtk_widget_set_sensitive (GTK_WIDGET (table), FALSE);
+ blockSignals = NO;
+
+ /**
+ * Name
+ */
+ nameEdit = GTK_ENTRY (gtk_entry_new ());
+ g_object_ref_sink (nameEdit);
+ [self _addWidget:GTK_WIDGET (nameEdit)
+ withLabel:"Name"
+ atRow:0];
+ g_signal_connect (G_OBJECT (nameEdit),
+ "changed",
+ G_CALLBACK (style_name_edit_changed_cb),
+ self);
+
+
+ /**
+ * Shape
+ */
+ GtkListStore *store = gtk_list_store_new (1, G_TYPE_STRING);
+ shapeNameCombo = GTK_COMBO_BOX (gtk_combo_box_new_with_model (GTK_TREE_MODEL (store)));
+ GtkCellRenderer *cellRend = gtk_cell_renderer_text_new ();
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (shapeNameCombo),
+ cellRend,
+ TRUE);
+ gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (shapeNameCombo), cellRend, "text", 0);
+ g_object_ref_sink (shapeNameCombo);
+ [self _addWidget:GTK_WIDGET (shapeNameCombo)
+ withLabel:"Shape"
+ atRow:1];
+ g_signal_connect (G_OBJECT (shapeNameCombo),
+ "changed",
+ G_CALLBACK (style_shape_combo_changed_cb),
+ self);
+
+
+ /**
+ * Stroke colour
+ */
+ GtkWidget *strokeBox = gtk_hbox_new (FALSE, 0);
+ [self _addWidget:strokeBox
+ withLabel:"Stroke colour"
+ atRow:2];
+ strokeColorButton = GTK_COLOR_BUTTON (gtk_color_button_new ());
+ g_object_ref_sink (strokeColorButton);
+ gtk_widget_show (GTK_WIDGET (strokeColorButton));
+ gtk_box_pack_start (GTK_BOX (strokeBox), GTK_WIDGET (strokeColorButton),
+ FALSE, FALSE, 0);
+ makeStrokeTexSafeButton = [self _createMakeColorTexSafeButton:@"stroke"];
+ g_object_ref_sink (makeStrokeTexSafeButton);
+ gtk_box_pack_start (GTK_BOX (strokeBox), makeStrokeTexSafeButton,
+ FALSE, FALSE, 0);
+ g_signal_connect (G_OBJECT (strokeColorButton),
+ "color-set",
+ G_CALLBACK (stroke_color_changed_cb),
+ self);
+ g_signal_connect (G_OBJECT (makeStrokeTexSafeButton),
+ "clicked",
+ G_CALLBACK (make_stroke_safe_button_clicked_cb),
+ self);
+
+
+ /**
+ * Fill colour
+ */
+ GtkWidget *fillBox = gtk_hbox_new (FALSE, 0);
+ [self _addWidget:fillBox
+ withLabel:"Fill colour"
+ atRow:3];
+ fillColorButton = GTK_COLOR_BUTTON (gtk_color_button_new ());
+ g_object_ref_sink (fillColorButton);
+ gtk_widget_show (GTK_WIDGET (fillColorButton));
+ gtk_box_pack_start (GTK_BOX (fillBox), GTK_WIDGET (fillColorButton),
+ FALSE, FALSE, 0);
+ makeFillTexSafeButton = [self _createMakeColorTexSafeButton:@"fill"];
+ g_object_ref_sink (makeFillTexSafeButton);
+ gtk_box_pack_start (GTK_BOX (fillBox), makeFillTexSafeButton,
+ FALSE, FALSE, 0);
+ g_signal_connect (G_OBJECT (fillColorButton),
+ "color-set",
+ G_CALLBACK (fill_color_changed_cb),
+ self);
+ g_signal_connect (G_OBJECT (makeFillTexSafeButton),
+ "clicked",
+ G_CALLBACK (make_fill_safe_button_clicked_cb),
+ self);
+
+
+ /**
+ * Scale
+ */
+ scaleAdj = GTK_ADJUSTMENT (gtk_adjustment_new (
+ 1.0, // value
+ 0.0, // lower
+ 50.0, // upper
+ 0.20, // step
+ 1.0, // page
+ 0.0)); // (irrelevant)
+ g_object_ref_sink (scaleAdj);
+ GtkWidget *scaleSpin = gtk_spin_button_new (scaleAdj, 0.0, 2);
+ [self _addWidget:scaleSpin
+ withLabel:"Scale"
+ atRow:4];
+ g_signal_connect (G_OBJECT (scaleAdj),
+ "value-changed",
+ G_CALLBACK (scale_adjustment_changed_cb),
+ self);
+
+ [self loadShapeNames];
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(shapeDictionaryReplaced:)
+ name:@"ShapeDictionaryReplaced"
+ object:[Shape class]];
+ }
+
+ return self;
+}
+
+- (void) dealloc {
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+
+ g_object_unref (nameEdit);
+ g_object_unref (shapeNameCombo);
+ g_object_unref (strokeColorButton);
+ g_object_unref (makeStrokeTexSafeButton);
+ g_object_unref (fillColorButton);
+ g_object_unref (makeFillTexSafeButton);
+ g_object_unref (scaleAdj);
+ g_object_unref (table);
+ [style release];
+
+ [super dealloc];
+}
+
+- (NodeStyle*) style {
+ return style;
+}
+
+- (void) setStyle:(NodeStyle*)s {
+ blockSignals = YES;
+ NodeStyle *oldStyle = style;
+ style = [s retain];
+
+ if (style != nil) {
+ gtk_widget_set_sensitive (GTK_WIDGET (table), TRUE);
+
+ gtk_entry_set_text(nameEdit, [[style name] UTF8String]);
+
+ [self setActiveShapeName:[style shapeName]];
+
+ GdkColor c = [style strokeColor];
+ gtk_color_button_set_color(strokeColorButton, &c);
+
+ gtk_widget_set_visible (makeStrokeTexSafeButton, ([[style strokeColorRGB] name] == nil));
+
+ c = [style fillColor];
+ gtk_color_button_set_color(fillColorButton, &c);
+
+ gtk_widget_set_visible (makeFillTexSafeButton, ([[style fillColorRGB] name] == nil));
+
+ gtk_adjustment_set_value(scaleAdj, [style scale]);
+ } else {
+ gtk_entry_set_text(nameEdit, "");
+ [self setActiveShapeName:nil];
+ gtk_widget_set_visible (makeStrokeTexSafeButton, FALSE);
+ gtk_widget_set_visible (makeFillTexSafeButton, FALSE);
+ gtk_adjustment_set_value(scaleAdj, 1.0);
+ gtk_widget_set_sensitive (GTK_WIDGET (table), FALSE);
+ }
+
+ [oldStyle release];
+ blockSignals = NO;
+}
+
+- (GtkWidget*) widget {
+ return GTK_WIDGET (table);
+}
+
+@end
+
+// }}}
+// {{{ Notifications
+
+@implementation NodeStyleEditor (Notifications)
+- (void) shapeDictionaryReplaced:(NSNotification*)n {
+ blockSignals = YES;
+
+ [self loadShapeNames];
+ [self setActiveShapeName:[style shapeName]];
+
+ blockSignals = NO;
+}
+
+- (void) nameChangedTo:(NSString*)value {
+ [style setName:value];
+}
+
+- (void) shapeNameChangedTo:(NSString*)value {
+ [style setShapeName:value];
+}
+
+- (void) strokeColorChangedTo:(GdkColor)value {
+ [style setStrokeColor:value];
+ gtk_widget_set_visible (makeStrokeTexSafeButton,
+ [[style strokeColorRGB] name] == nil);
+}
+
+- (void) makeStrokeColorTexSafe {
+ if (style != nil) {
+ [[style strokeColorRGB] setToClosestHashed];
+ GdkColor color = [style strokeColor];
+ gtk_color_button_set_color(strokeColorButton, &color);
+ gtk_widget_set_visible (makeStrokeTexSafeButton, FALSE);
+ }
+}
+
+- (void) fillColorChangedTo:(GdkColor)value {
+ [style setFillColor:value];
+ gtk_widget_set_visible (makeFillTexSafeButton,
+ [[style fillColorRGB] name] == nil);
+}
+
+- (void) makeFillColorTexSafe {
+ if (style != nil) {
+ [[style fillColorRGB] setToClosestHashed];
+ GdkColor color = [style fillColor];
+ gtk_color_button_set_color(fillColorButton, &color);
+ gtk_widget_set_visible (makeFillTexSafeButton, FALSE);
+ }
+}
+
+- (void) scaleChangedTo:(double)value {
+ [style setScale:value];
+}
+@end
+
+// }}}
+// {{{ Private
+
+@implementation NodeStyleEditor (Private)
+- (BOOL) signalsBlocked { return blockSignals; }
+
+- (void) loadShapeNames {
+ blockSignals = YES;
+
+ gtk_combo_box_set_active (shapeNameCombo, -1);
+
+ GtkListStore *list = GTK_LIST_STORE (gtk_combo_box_get_model (shapeNameCombo));
+ gtk_list_store_clear (list);
+
+ NSEnumerator *en = [[Shape shapeDictionary] keyEnumerator];
+ NSString *shapeName;
+ GtkTreeIter iter;
+ while ((shapeName = [en nextObject]) != nil) {
+ gtk_list_store_append (list, &iter);
+ gtk_list_store_set (list, &iter, 0, [shapeName UTF8String], -1);
+ }
+
+ blockSignals = NO;
+}
+
+- (void) setActiveShapeName:(NSString*)name {
+ if (name == nil) {
+ gtk_combo_box_set_active (shapeNameCombo, -1);
+ return;
+ }
+ const gchar *shapeName = [name UTF8String];
+
+ GtkTreeModel *model = gtk_combo_box_get_model (shapeNameCombo);
+ GtkTreeIter iter;
+ if (gtk_tree_model_get_iter_first (model, &iter)) {
+ do {
+ gchar *rowShapeName;
+ gtk_tree_model_get (model, &iter, 0, &rowShapeName, -1);
+ if (g_strcmp0 (shapeName, rowShapeName) == 0) {
+ gtk_combo_box_set_active_iter (shapeNameCombo, &iter);
+ g_free (rowShapeName);
+ return;
+ }
+ g_free (rowShapeName);
+ } while (gtk_tree_model_iter_next (model, &iter));
+ }
+}
+@end
+
+// }}}
+// {{{ GTK+ callbacks
+
+static void style_name_edit_changed_cb (GtkEditable *widget, NodeStyleEditor *editor) {
+ if ([editor signalsBlocked])
+ return;
+
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ const gchar *contents = gtk_entry_get_text (GTK_ENTRY (widget));
+ [editor nameChangedTo:[NSString stringWithUTF8String:contents]];
+
+ [pool drain];
+}
+
+static void style_shape_combo_changed_cb (GtkComboBox *widget, NodeStyleEditor *editor) {
+ if ([editor signalsBlocked])
+ return;
+
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ GtkTreeIter iter;
+ gtk_combo_box_get_active_iter (widget, &iter);
+ gchar *shapeName = NULL;
+ gtk_tree_model_get (gtk_combo_box_get_model (widget), &iter, 0, &shapeName, -1);
+ [editor shapeNameChangedTo:[NSString stringWithUTF8String:shapeName]];
+ g_free (shapeName);
+
+ [pool drain];
+}
+
+static void stroke_color_changed_cb (GtkColorButton *widget, NodeStyleEditor *editor) {
+ if ([editor signalsBlocked])
+ return;
+
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ GdkColor color;
+ gtk_color_button_get_color (widget, &color);
+ [editor strokeColorChangedTo:color];
+
+ [pool drain];
+}
+
+static void fill_color_changed_cb (GtkColorButton *widget, NodeStyleEditor *editor) {
+ if ([editor signalsBlocked])
+ return;
+
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ GdkColor color;
+ gtk_color_button_get_color (widget, &color);
+ [editor fillColorChangedTo:color];
+
+ [pool drain];
+}
+
+static void make_stroke_safe_button_clicked_cb (GtkButton *widget, NodeStyleEditor *editor) {
+ if ([editor signalsBlocked])
+ return;
+
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ [editor makeStrokeColorTexSafe];
+ [pool drain];
+}
+
+static void make_fill_safe_button_clicked_cb (GtkButton *widget, NodeStyleEditor *editor) {
+ if ([editor signalsBlocked])
+ return;
+
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ [editor makeFillColorTexSafe];
+ [pool drain];
+}
+
+static void scale_adjustment_changed_cb (GtkAdjustment *adj, NodeStyleEditor *editor) {
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ [editor scaleChangedTo:gtk_adjustment_get_value (adj)];
+ [pool drain];
+}
+
+// }}}
+
+// vim:ft=objc:ts=4:noet:sts=4:sw=4:foldmethod=marker