From 58ceedc38ed430535508360adde7b5b6d76b08e6 Mon Sep 17 00:00:00 2001 From: Alex Merry Date: Mon, 17 Dec 2012 19:09:06 +0000 Subject: Allow node and edge styles to be applied to selection Brings back some old functionality, but in a more compact way. --- tikzit/src/gtk/SelectionPane.m | 432 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 432 insertions(+) create mode 100644 tikzit/src/gtk/SelectionPane.m (limited to 'tikzit/src/gtk/SelectionPane.m') diff --git a/tikzit/src/gtk/SelectionPane.m b/tikzit/src/gtk/SelectionPane.m new file mode 100644 index 0000000..2931258 --- /dev/null +++ b/tikzit/src/gtk/SelectionPane.m @@ -0,0 +1,432 @@ +/* + * Copyright 2011-2012 Alex Merry + * + * 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 . + */ + +#import "SelectionPane.h" + +#import "Configuration.h" +#import "EdgeStylesModel.h" +#import "NodeStylesModel.h" +#import "TikzDocument.h" + +#import "gtkhelpers.h" + +// {{{ Internal interfaces + +static void node_style_changed_cb (GtkComboBox *widget, SelectionPane *pane); +static void apply_node_style_button_cb (GtkButton *widget, SelectionPane *pane); +static void clear_node_style_button_cb (GtkButton *widget, SelectionPane *pane); +static void edge_style_changed_cb (GtkComboBox *widget, SelectionPane *pane); +static void apply_edge_style_button_cb (GtkButton *widget, SelectionPane *pane); +static void clear_edge_style_button_cb (GtkButton *widget, SelectionPane *pane); + +static void setup_style_cell_layout (GtkCellLayout *cell_layout, gint pixbuf_col, gint name_col); + +@interface SelectionPane (Notifications) +- (void) nodeSelectionChanged:(NSNotification*)n; +- (void) edgeSelectionChanged:(NSNotification*)n; +@end + +@interface SelectionPane (Private) +- (void) _updateNodeStyleButtons; +- (void) _updateEdgeStyleButtons; +- (NodeStyle*) _selectedNodeStyle; +- (EdgeStyle*) _selectedEdgeStyle; +- (void) _applyNodeStyle; +- (void) _clearNodeStyle; +- (void) _applyEdgeStyle; +- (void) _clearEdgeStyle; +@end + +// }}} +// {{{ API + +@implementation SelectionPane + +- (id) init { + [self release]; + return nil; +} + +- (id) initWithStyleManager:(StyleManager*)sm { + return [self initWithNodeStylesModel:[NodeStylesModel modelWithStyleManager:sm] + andEdgeStylesModel:[EdgeStylesModel modelWithStyleManager:sm]]; +} + +- (id) initWithNodeStylesModel:(NodeStylesModel*)nsm + andEdgeStylesModel:(EdgeStylesModel*)esm { + self = [super init]; + + if (self) { + nodeStylesModel = [nsm retain]; + edgeStylesModel = [esm retain]; + + layout = gtk_vbox_new (FALSE, 0); + g_object_ref_sink (layout); + gtk_widget_show (layout); + + GtkWidget *label = gtk_label_new ("Selection"); + label_set_bold (GTK_LABEL (label)); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (layout), label, + FALSE, FALSE, 0); + + GtkWidget *lvl1_box = gtk_vbox_new (FALSE, 0); + gtk_box_pack_start (GTK_BOX (layout), lvl1_box, + FALSE, FALSE, 3); + + nodeStyleCombo = gtk_combo_box_new_with_model ([nodeStylesModel model]); + g_object_ref_sink (nodeStyleCombo); + setup_style_cell_layout (GTK_CELL_LAYOUT (nodeStyleCombo), + NODE_STYLES_ICON_COL, + NODE_STYLES_NAME_COL); + g_signal_connect (G_OBJECT (nodeStyleCombo), + "changed", + G_CALLBACK (node_style_changed_cb), + self); + gtk_box_pack_start (GTK_BOX (lvl1_box), nodeStyleCombo, + FALSE, FALSE, 0); + + GtkWidget *lvl2_box = gtk_hbox_new (FALSE, 0); + gtk_box_pack_start (GTK_BOX (lvl1_box), lvl2_box, + FALSE, FALSE, 0); + + applyNodeStyleButton = gtk_button_new_with_label ("Apply"); + g_object_ref_sink (applyNodeStyleButton); + gtk_widget_set_tooltip_text (applyNodeStyleButton, "Apply style to selected nodes"); + gtk_widget_set_sensitive (applyNodeStyleButton, FALSE); + g_signal_connect (G_OBJECT (applyNodeStyleButton), + "clicked", + G_CALLBACK (apply_node_style_button_cb), + self); + gtk_box_pack_start (GTK_BOX (lvl2_box), applyNodeStyleButton, + FALSE, FALSE, 0); + + clearNodeStyleButton = gtk_button_new_with_label ("Clear"); + g_object_ref_sink (clearNodeStyleButton); + gtk_widget_set_tooltip_text (clearNodeStyleButton, "Clear style from selected nodes"); + gtk_widget_set_sensitive (clearNodeStyleButton, FALSE); + g_signal_connect (G_OBJECT (clearNodeStyleButton), + "clicked", + G_CALLBACK (clear_node_style_button_cb), + self); + gtk_box_pack_start (GTK_BOX (lvl2_box), clearNodeStyleButton, + FALSE, FALSE, 0); + + lvl1_box = gtk_vbox_new (FALSE, 0); + gtk_box_pack_start (GTK_BOX (layout), lvl1_box, + FALSE, FALSE, 3); + + edgeStyleCombo = gtk_combo_box_new_with_model ([edgeStylesModel model]); + g_object_ref_sink (edgeStyleCombo); + setup_style_cell_layout (GTK_CELL_LAYOUT (edgeStyleCombo), + EDGE_STYLES_ICON_COL, + EDGE_STYLES_NAME_COL); + g_signal_connect (G_OBJECT (edgeStyleCombo), + "changed", + G_CALLBACK (edge_style_changed_cb), + self); + gtk_box_pack_start (GTK_BOX (lvl1_box), edgeStyleCombo, + FALSE, FALSE, 0); + + lvl2_box = gtk_hbox_new (FALSE, 0); + gtk_box_pack_start (GTK_BOX (lvl1_box), lvl2_box, + FALSE, FALSE, 0); + + applyEdgeStyleButton = gtk_button_new_with_label ("Apply"); + g_object_ref_sink (applyEdgeStyleButton); + gtk_widget_set_tooltip_text (applyEdgeStyleButton, "Apply style to selected edges"); + gtk_widget_set_sensitive (applyEdgeStyleButton, FALSE); + g_signal_connect (G_OBJECT (applyEdgeStyleButton), + "clicked", + G_CALLBACK (apply_edge_style_button_cb), + self); + gtk_box_pack_start (GTK_BOX (lvl2_box), applyEdgeStyleButton, + FALSE, FALSE, 0); + + clearEdgeStyleButton = gtk_button_new_with_label ("Clear"); + g_object_ref_sink (clearEdgeStyleButton); + gtk_widget_set_tooltip_text (clearEdgeStyleButton, "Clear style from selected edges"); + gtk_widget_set_sensitive (clearEdgeStyleButton, FALSE); + g_signal_connect (G_OBJECT (clearEdgeStyleButton), + "clicked", + G_CALLBACK (clear_edge_style_button_cb), + self); + gtk_box_pack_start (GTK_BOX (lvl2_box), clearEdgeStyleButton, + FALSE, FALSE, 0); + + gtk_widget_show_all (layout); + } + + return self; +} + +- (void) dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; + + g_object_unref (nodeStyleCombo); + g_object_unref (applyNodeStyleButton); + g_object_unref (clearNodeStyleButton); + g_object_unref (edgeStyleCombo); + g_object_unref (applyEdgeStyleButton); + g_object_unref (clearEdgeStyleButton); + + g_object_unref (layout); + + [nodeStylesModel release]; + [edgeStylesModel release]; + + [document release]; + + [super dealloc]; +} + +- (TikzDocument*) document { + return document; +} + +- (void) setDocument:(TikzDocument*)doc { + if (document != nil) { + [[NSNotificationCenter defaultCenter] + removeObserver:self + name:nil + object:[document pickSupport]]; + } + + [doc retain]; + [document release]; + document = doc; + + if (doc != nil) { + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(nodeSelectionChanged:) + name:@"NodeSelectionChanged" object:[doc pickSupport]]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(edgeSelectionChanged:) + name:@"EdgeSelectionChanged" object:[doc pickSupport]]; + } + + [self _updateNodeStyleButtons]; + [self _updateEdgeStyleButtons]; +} + +- (BOOL) visible { + return gtk_widget_get_visible (layout); +} + +- (void) setVisible:(BOOL)visible { + gtk_widget_set_visible (layout, visible); +} + +- (GtkWidget*) gtkWidget { + return layout; +} + +- (void) loadConfiguration:(Configuration*)config { + NSString *nodeStyleName = [config stringEntry:@"SelectedNodeStyle" + inGroup:@"SelectionPane" + withDefault:nil]; + NodeStyle *nodeStyle = [[nodeStylesModel styleManager] nodeStyleForName:nodeStyleName]; + if (nodeStyle == nil) { + gtk_combo_box_set_active (GTK_COMBO_BOX (nodeStyleCombo), -1); + } else { + GtkTreeIter *iter = [nodeStylesModel iterFromStyle:nodeStyle]; + if (iter) { + gtk_combo_box_set_active_iter (GTK_COMBO_BOX (nodeStyleCombo), iter); + gtk_tree_iter_free (iter); + } + } + + NSString *edgeStyleName = [config stringEntry:@"SelectedEdgeStyle" + inGroup:@"SelectionPane" + withDefault:nil]; + EdgeStyle *edgeStyle = [[edgeStylesModel styleManager] edgeStyleForName:edgeStyleName]; + if (edgeStyle == nil) { + gtk_combo_box_set_active (GTK_COMBO_BOX (edgeStyleCombo), -1); + } else { + GtkTreeIter *iter = [edgeStylesModel iterFromStyle:edgeStyle]; + if (iter) { + gtk_combo_box_set_active_iter (GTK_COMBO_BOX (edgeStyleCombo), iter); + gtk_tree_iter_free (iter); + } + } +} + +- (void) saveConfiguration:(Configuration*)config { + [config setStringEntry:@"SelectedNodeStyle" + inGroup:@"SelectionPane" + value:[[self _selectedNodeStyle] name]]; + [config setStringEntry:@"SelectedEdgeStyle" + inGroup:@"SelectionPane" + value:[[self _selectedEdgeStyle] name]]; +} + +@end + +// }}} +// {{{ Notifications + +@implementation SelectionPane (Notifications) +- (void) nodeSelectionChanged:(NSNotification*)n { + [self _updateNodeStyleButtons]; +} + +- (void) edgeSelectionChanged:(NSNotification*)n { + [self _updateEdgeStyleButtons]; +} +@end + +// }}} +// {{{ Private + +@implementation SelectionPane (Private) +- (void) _updateNodeStyleButtons { + gboolean hasNodeSelection = [[[document pickSupport] selectedNodes] count] > 0; + + gtk_widget_set_sensitive (applyNodeStyleButton, + hasNodeSelection && [self _selectedNodeStyle] != nil); + gtk_widget_set_sensitive (clearNodeStyleButton, hasNodeSelection); +} + +- (void) _updateEdgeStyleButtons { + gboolean hasEdgeSelection = [[[document pickSupport] selectedEdges] count] > 0; + + gtk_widget_set_sensitive (applyEdgeStyleButton, + hasEdgeSelection && [self _selectedEdgeStyle] != nil); + gtk_widget_set_sensitive (clearEdgeStyleButton, hasEdgeSelection); +} + +- (NodeStyle*) _selectedNodeStyle { + GtkTreeIter iter; + if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (nodeStyleCombo), &iter)) { + return [nodeStylesModel styleFromIter:&iter]; + } else { + return nil; + } +} + +- (EdgeStyle*) _selectedEdgeStyle { + GtkTreeIter iter; + if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (edgeStyleCombo), &iter)) { + return [edgeStylesModel styleFromIter:&iter]; + } else { + return nil; + } +} + +- (void) _applyNodeStyle { + [document startModifyNodes:[[document pickSupport] selectedNodes]]; + + NodeStyle *style = [self _selectedNodeStyle]; + for (Node *node in [[document pickSupport] selectedNodes]) { + [node setStyle:style]; + } + + [document endModifyNodes]; +} + +- (void) _clearNodeStyle { + [document startModifyNodes:[[document pickSupport] selectedNodes]]; + + for (Node *node in [[document pickSupport] selectedNodes]) { + [node setStyle:nil]; + } + + [document endModifyNodes]; +} + +- (void) _applyEdgeStyle { + [document startModifyEdges:[[document pickSupport] selectedEdges]]; + + EdgeStyle *style = [self _selectedEdgeStyle]; + for (Edge *edge in [[document pickSupport] selectedEdges]) { + [edge setStyle:style]; + } + + [document endModifyEdges]; +} + +- (void) _clearEdgeStyle { + [document startModifyEdges:[[document pickSupport] selectedEdges]]; + + for (Edge *edge in [[document pickSupport] selectedEdges]) { + [edge setStyle:nil]; + } + + [document endModifyEdges]; +} +@end + +// }}} +// {{{ GTK+ callbacks + +static void node_style_changed_cb (GtkComboBox *widget, SelectionPane *pane) { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + [pane _updateNodeStyleButtons]; + [pool drain]; +} + +static void apply_node_style_button_cb (GtkButton *widget, SelectionPane *pane) { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + [pane _applyNodeStyle]; + [pool drain]; +} + +static void clear_node_style_button_cb (GtkButton *widget, SelectionPane *pane) { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + [pane _clearNodeStyle]; + [pool drain]; +} + +static void edge_style_changed_cb (GtkComboBox *widget, SelectionPane *pane) { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + [pane _updateEdgeStyleButtons]; + [pool drain]; +} + +static void apply_edge_style_button_cb (GtkButton *widget, SelectionPane *pane) { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + [pane _applyEdgeStyle]; + [pool drain]; +} + +static void clear_edge_style_button_cb (GtkButton *widget, SelectionPane *pane) { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + [pane _clearEdgeStyle]; + [pool drain]; +} + +// }}} +// +static void setup_style_cell_layout (GtkCellLayout *cell_layout, gint pixbuf_col, gint name_col) { + gtk_cell_layout_clear (cell_layout); + GtkCellRenderer *pixbuf_renderer = gtk_cell_renderer_pixbuf_new (); + gtk_cell_layout_pack_start (cell_layout, pixbuf_renderer, FALSE); + gtk_cell_layout_set_attributes ( + cell_layout, + pixbuf_renderer, + "pixbuf", pixbuf_col, + NULL); + GtkCellRenderer *text_renderer = gtk_cell_renderer_text_new (); + gtk_cell_layout_pack_start (cell_layout, text_renderer, FALSE); + gtk_cell_layout_set_attributes ( + cell_layout, + text_renderer, + "text", name_col, + NULL); +} + +// vim:ft=objc:ts=8:et:sts=4:sw=4:foldmethod=marker -- cgit v1.2.3