Removed debugging include.
[dia.git] / app / layer_dialog.c
blob8a31d156ff61936ab1d22a78192d77fba55f78c5
1 /* Dia -- an diagram creation/manipulation program
2 * Copyright (C) 1998 Alexander Larsson
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 /* Parts of this file are derived from the file layers_dialog.c in the Gimp:
21 * The GIMP -- an image manipulation program
22 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
29 #include <assert.h>
30 #include <string.h>
31 #include <gdk/gdkkeysyms.h>
32 #include <gtk/gtk.h>
34 #include "intl.h"
36 #include "layer_dialog.h"
37 #include "persistence.h"
38 #include "widgets.h"
39 #include "interface.h"
41 #include "dia-app-icons.h"
43 static struct LayerDialog *layer_dialog = NULL;
45 typedef struct _ButtonData ButtonData;
47 struct _ButtonData {
48 gchar *stock_name;
49 gpointer callback;
50 char *tooltip;
53 enum LayerChangeType {
54 TYPE_DELETE_LAYER,
55 TYPE_ADD_LAYER,
56 TYPE_RAISE_LAYER,
57 TYPE_LOWER_LAYER,
60 struct LayerChange {
61 Change change;
63 enum LayerChangeType type;
64 Layer *layer;
65 int index;
66 int applied;
69 struct LayerVisibilityChange {
70 Change change;
72 GList *original_visibility;
73 Layer *layer;
74 gboolean is_exclusive;
75 int applied;
78 /** If TRUE, we're in the middle of a internal call to
79 * dia_layer_widget_*_toggled and should not make undo, update diagram etc.
81 * If these calls were not done by simulating button presses, we could avoid
82 * this hack.
84 static gboolean internal_call = FALSE;
86 static Change *
87 undo_layer(Diagram *dia, Layer *layer, enum LayerChangeType, int index);
88 static struct LayerVisibilityChange *
89 undo_layer_visibility(Diagram *dia, Layer *layer, gboolean exclusive);
90 static void
91 layer_visibility_change_apply(struct LayerVisibilityChange *change,
92 Diagram *dia);
94 static void layer_dialog_new_callback(GtkWidget *widget, gpointer gdata);
95 static void layer_dialog_raise_callback(GtkWidget *widget, gpointer gdata);
96 static void layer_dialog_lower_callback(GtkWidget *widget, gpointer gdata);
97 static void layer_dialog_delete_callback(GtkWidget *widget, gpointer gdata);
98 static void layer_dialog_edit_layer(DiaLayerWidget *layer_widget);
100 static ButtonData buttons[] = {
101 { GTK_STOCK_ADD, layer_dialog_new_callback, N_("New Layer") },
102 { GTK_STOCK_GO_UP, layer_dialog_raise_callback, N_("Raise Layer") },
103 { GTK_STOCK_GO_DOWN, layer_dialog_lower_callback, N_("Lower Layer") },
104 { GTK_STOCK_DELETE, layer_dialog_delete_callback, N_("Delete Layer") },
107 enum {
108 BUTTON_NEW = 0,
109 BUTTON_RAISE,
110 BUTTON_LOWER,
111 BUTTON_DELETE
114 #define BUTTON_EVENT_MASK GDK_EXPOSURE_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | \
115 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
117 static int num_buttons = sizeof(buttons)/sizeof(ButtonData);
119 #define NORMAL 0
120 #define SELECTED 1
121 #define INSENSITIVE 2
123 static GtkWidget *
124 create_button_box(GtkWidget *parent)
126 GtkWidget *button;
127 GtkWidget *button_box;
128 int i;
130 button_box = gtk_hbox_new (TRUE, 1);
132 for (i=0;i<num_buttons;i++) {
133 button = gtk_button_new_from_stock(buttons[i].stock_name);
134 g_signal_connect_swapped (GTK_OBJECT (button), "clicked",
135 G_CALLBACK(buttons[i].callback),
136 GTK_OBJECT (parent));
138 if (tool_tips != NULL)
139 gtk_tooltips_set_tip (tool_tips, button, gettext(buttons[i].tooltip), NULL);
141 gtk_box_pack_start (GTK_BOX(button_box), button, TRUE, TRUE, 0);
143 layer_dialog->buttons[i] = button;
145 gtk_widget_show (button);
148 return button_box;
151 static gint
152 layer_list_events (GtkWidget *widget,
153 GdkEvent *event)
155 GdkEventKey *kevent;
156 GdkEventButton *bevent;
157 GtkWidget *event_widget;
158 DiaLayerWidget *layer_widget;
160 event_widget = gtk_get_event_widget (event);
162 if (GTK_IS_LIST_ITEM (event_widget)) {
163 layer_widget = DIA_LAYER_WIDGET(event_widget);
165 switch (event->type) {
166 case GDK_BUTTON_PRESS:
167 bevent = (GdkEventButton *) event;
168 break;
170 case GDK_2BUTTON_PRESS:
171 bevent = (GdkEventButton *) event;
172 layer_dialog_edit_layer(layer_widget);
173 return TRUE;
175 case GDK_KEY_PRESS:
176 kevent = (GdkEventKey *) event;
177 switch (kevent->keyval) {
178 case GDK_Up:
179 /* printf ("up arrow\n"); */
180 break;
181 case GDK_Down:
182 /* printf ("down arrow\n"); */
183 break;
184 default:
185 return FALSE;
187 return TRUE;
189 default:
190 break;
194 return FALSE;
197 static gboolean
198 layer_dialog_delete(GtkWidget *widget, gpointer data)
200 gtk_widget_hide(widget);
201 /* We're caching, so don't destroy */
202 return TRUE;
205 void
206 create_layer_dialog(void)
208 GtkWidget *dialog;
209 GtkWidget *vbox;
210 GtkWidget *hbox;
211 GtkWidget *label;
212 GtkWidget *omenu;
213 GtkWidget *menu;
214 GtkWidget *list;
215 GtkWidget *separator;
216 GtkWidget *scrolled_win;
217 GtkWidget *button_box;
218 GtkWidget *button;
220 layer_dialog = g_new(struct LayerDialog, 1);
222 layer_dialog->diagram = NULL;
224 layer_dialog->dialog = dialog = gtk_dialog_new ();
225 gtk_window_set_title (GTK_WINDOW (dialog), _("Layers"));
226 gtk_window_set_role (GTK_WINDOW (dialog), "layer_window");
227 gtk_window_set_resizable (GTK_WINDOW (dialog), TRUE);
229 g_signal_connect (GTK_OBJECT (dialog), "delete_event",
230 G_CALLBACK(layer_dialog_delete), NULL);
231 g_signal_connect (GTK_OBJECT (dialog), "destroy",
232 G_CALLBACK(gtk_widget_destroyed),
233 &(layer_dialog->dialog));
235 vbox = GTK_DIALOG(dialog)->vbox;
237 hbox = gtk_hbox_new(FALSE, 1);
239 label = gtk_label_new(_("Diagram:"));
240 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2);
241 gtk_widget_show (label);
243 layer_dialog->diagram_omenu = omenu = gtk_option_menu_new();
244 gtk_box_pack_start(GTK_BOX(hbox), omenu, TRUE, TRUE, 2);
245 gtk_widget_show (omenu);
247 menu = gtk_menu_new();
248 gtk_option_menu_set_menu(GTK_OPTION_MENU(omenu), menu);
250 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 2);
251 gtk_widget_show (hbox);
253 separator = gtk_hseparator_new();
254 gtk_box_pack_start(GTK_BOX(vbox), separator, FALSE, FALSE, 2);
255 gtk_widget_show (separator);
257 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
258 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
259 GTK_POLICY_AUTOMATIC,
260 GTK_POLICY_AUTOMATIC);
261 gtk_box_pack_start (GTK_BOX (vbox), scrolled_win, TRUE, TRUE, 2);
263 layer_dialog->layer_list = list = gtk_list_new();
265 gtk_list_set_selection_mode (GTK_LIST (list), GTK_SELECTION_BROWSE);
266 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled_win), list);
267 gtk_container_set_focus_vadjustment (GTK_CONTAINER (list),
268 gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (scrolled_win)));
269 gtk_widget_show (scrolled_win);
270 gtk_widget_show (list);
272 g_signal_connect (GTK_OBJECT (list), "event",
273 (GtkSignalFunc) layer_list_events,
274 NULL);
276 button_box = create_button_box(dialog);
278 gtk_box_pack_start (GTK_BOX (vbox), button_box, FALSE, FALSE, 2);
279 gtk_widget_show (button_box);
281 gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area),
284 button = gtk_button_new_from_stock (GTK_STOCK_CLOSE);
285 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area),
286 button, TRUE, TRUE, 0);
287 g_signal_connect_swapped(GTK_OBJECT (button), "clicked",
288 G_CALLBACK(gtk_widget_hide),
289 GTK_OBJECT(dialog));
291 gtk_widget_show (button);
293 persistence_register_window(GTK_WINDOW(dialog));
295 layer_dialog_update_diagram_list();
298 static void
299 dia_layer_select_callback(GtkWidget *widget, gpointer data)
301 DiaLayerWidget *lw;
302 lw = DIA_LAYER_WIDGET(widget);
304 diagram_remove_all_selected(lw->dia, TRUE);
305 diagram_update_extents(lw->dia);
306 data_set_active_layer(lw->dia->data, lw->layer);
307 diagram_add_update_all(lw->dia);
308 diagram_flush(lw->dia);
310 internal_call = TRUE;
311 if (lw->connect_off) { /* If the user wants this off, it becomes so */
312 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(lw->connectable), FALSE);
313 } else {
314 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(lw->connectable), TRUE);
316 internal_call = FALSE;
319 static void
320 dia_layer_deselect_callback(GtkWidget *widget, gpointer data)
322 DiaLayerWidget *lw = DIA_LAYER_WIDGET(widget);
324 /** If layer dialog or diagram is missing, we are so dead. */
325 if (layer_dialog == NULL || layer_dialog->diagram == NULL) return;
327 internal_call = TRUE;
328 /** Set to on if the user has requested so. */
329 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(lw->connectable),
330 lw->connect_on);
331 internal_call = FALSE;
335 static void
336 layer_dialog_new_callback(GtkWidget *widget, gpointer gdata)
338 Layer *layer;
339 Diagram *dia;
340 GtkWidget *selected;
341 GList *list = NULL;
342 GtkWidget *layer_widget;
343 int pos;
344 static int next_layer_num = 1;
346 dia = layer_dialog->diagram;
348 if (dia != NULL) {
349 gchar* new_layer_name = g_strdup_printf(_("New layer %d"),
350 next_layer_num++);
351 layer = new_layer(new_layer_name, dia->data);
353 assert(GTK_LIST(layer_dialog->layer_list)->selection != NULL);
354 selected = GTK_LIST(layer_dialog->layer_list)->selection->data;
355 pos = gtk_list_child_position(GTK_LIST(layer_dialog->layer_list), selected);
357 data_add_layer_at(dia->data, layer, dia->data->layers->len - pos);
359 diagram_add_update_all(dia);
360 diagram_flush(dia);
362 layer_widget = dia_layer_widget_new(dia, layer);
363 gtk_widget_show(layer_widget);
365 list = g_list_prepend(list, layer_widget);
367 gtk_list_insert_items(GTK_LIST(layer_dialog->layer_list), list, pos);
369 gtk_list_select_item(GTK_LIST(layer_dialog->layer_list), pos);
371 undo_layer(dia, layer, TYPE_ADD_LAYER, dia->data->layers->len - pos);
372 undo_set_transactionpoint(dia->undo);
376 static void
377 layer_dialog_delete_callback(GtkWidget *widget, gpointer gdata)
379 Diagram *dia;
380 GtkWidget *selected;
381 Layer *layer;
382 int pos;
384 dia = layer_dialog->diagram;
386 if ((dia != NULL) && (dia->data->layers->len>1)) {
387 assert(GTK_LIST(layer_dialog->layer_list)->selection != NULL);
388 selected = GTK_LIST(layer_dialog->layer_list)->selection->data;
390 layer = dia->data->active_layer;
392 data_delete_layer(dia->data, layer);
393 diagram_add_update_all(dia);
394 diagram_flush(dia);
396 pos = gtk_list_child_position(GTK_LIST(layer_dialog->layer_list), selected);
397 gtk_container_remove(GTK_CONTAINER(layer_dialog->layer_list), selected);
399 undo_layer(dia, layer, TYPE_DELETE_LAYER,
400 dia->data->layers->len - pos);
401 undo_set_transactionpoint(dia->undo);
403 if (--pos<0)
404 pos = 0;
406 gtk_list_select_item(GTK_LIST(layer_dialog->layer_list), pos);
410 static void
411 layer_dialog_raise_callback(GtkWidget *widget, gpointer gdata)
413 Layer *layer;
414 Diagram *dia;
415 GtkWidget *selected;
416 GList *list = NULL;
417 int pos;
419 dia = layer_dialog->diagram;
421 if ((dia != NULL) && (dia->data->layers->len>1)) {
422 assert(GTK_LIST(layer_dialog->layer_list)->selection != NULL);
423 selected = GTK_LIST(layer_dialog->layer_list)->selection->data;
425 pos = gtk_list_child_position(GTK_LIST(layer_dialog->layer_list), selected);
427 if (pos > 0) {
428 layer = DIA_LAYER_WIDGET(selected)->layer;
429 data_raise_layer(dia->data, layer);
431 list = g_list_prepend(list, selected);
433 gtk_widget_ref(selected);
435 gtk_list_remove_items(GTK_LIST(layer_dialog->layer_list),
436 list);
438 gtk_list_insert_items(GTK_LIST(layer_dialog->layer_list),
439 list, pos - 1);
441 gtk_widget_unref(selected);
443 gtk_list_select_item(GTK_LIST(layer_dialog->layer_list), pos-1);
445 diagram_add_update_all(dia);
446 diagram_flush(dia);
448 undo_layer(dia, layer, TYPE_RAISE_LAYER, 0);
449 undo_set_transactionpoint(dia->undo);
455 static void
456 layer_dialog_lower_callback(GtkWidget *widget, gpointer gdata)
458 Layer *layer;
459 Diagram *dia;
460 GtkWidget *selected;
461 GList *list = NULL;
462 int pos;
464 dia = layer_dialog->diagram;
466 if ((dia != NULL) && (dia->data->layers->len>1)) {
467 assert(GTK_LIST(layer_dialog->layer_list)->selection != NULL);
468 selected = GTK_LIST(layer_dialog->layer_list)->selection->data;
470 pos = gtk_list_child_position(GTK_LIST(layer_dialog->layer_list), selected);
472 if (pos < dia->data->layers->len-1) {
473 layer = DIA_LAYER_WIDGET(selected)->layer;
474 data_lower_layer(dia->data, layer);
476 list = g_list_prepend(list, selected);
478 gtk_widget_ref(selected);
480 gtk_list_remove_items(GTK_LIST(layer_dialog->layer_list),
481 list);
483 gtk_list_insert_items(GTK_LIST(layer_dialog->layer_list),
484 list, pos + 1);
486 gtk_widget_unref(selected);
488 gtk_list_select_item(GTK_LIST(layer_dialog->layer_list), pos+1);
490 diagram_add_update_all(dia);
491 diagram_flush(dia);
493 undo_layer(dia, layer, TYPE_LOWER_LAYER, 0);
494 undo_set_transactionpoint(dia->undo);
501 static void
502 layer_dialog_select_diagram_callback(GtkWidget *widget, gpointer gdata)
504 Diagram *dia = (Diagram *) gdata;
506 layer_dialog_set_diagram(dia);
509 void
510 layer_dialog_update_diagram_list(void)
512 GtkWidget *new_menu;
513 GtkWidget *menu_item;
514 GList *dia_list;
515 Diagram *dia;
516 char *filename;
517 int i;
518 int current_nr;
520 if (layer_dialog == NULL || layer_dialog->dialog == NULL) {
521 if (!dia_open_diagrams())
522 return; /* shortcut; maybe session end w/o this dialog */
523 else
524 create_layer_dialog();
527 new_menu = gtk_menu_new();
529 current_nr = -1;
531 i = 0;
532 dia_list = dia_open_diagrams();
533 while (dia_list != NULL) {
534 dia = (Diagram *) dia_list->data;
536 if (dia == layer_dialog->diagram) {
537 current_nr = i;
540 filename = strrchr(dia->filename, G_DIR_SEPARATOR);
541 if (filename==NULL) {
542 filename = dia->filename;
543 } else {
544 filename++;
547 menu_item = gtk_menu_item_new_with_label(filename);
549 g_signal_connect (GTK_OBJECT (menu_item), "activate",
550 (GtkSignalFunc) layer_dialog_select_diagram_callback,
551 (gpointer) dia);
553 gtk_menu_append( GTK_MENU(new_menu), menu_item);
554 gtk_widget_show (menu_item);
556 dia_list = g_list_next(dia_list);
557 i++;
560 if (dia_open_diagrams()==NULL) {
561 menu_item = gtk_menu_item_new_with_label (_("none"));
562 g_signal_connect (GTK_OBJECT (menu_item), "activate",
563 (GtkSignalFunc) layer_dialog_select_diagram_callback,
564 (gpointer) NULL);
565 gtk_menu_append( GTK_MENU(new_menu), menu_item);
566 gtk_widget_show (menu_item);
569 gtk_option_menu_remove_menu(GTK_OPTION_MENU(layer_dialog->diagram_omenu));
571 gtk_option_menu_set_menu(GTK_OPTION_MENU(layer_dialog->diagram_omenu),
572 new_menu);
574 gtk_option_menu_set_history(GTK_OPTION_MENU(layer_dialog->diagram_omenu),
575 current_nr);
576 gtk_menu_set_active(GTK_MENU(new_menu), current_nr);
578 if (current_nr == -1) {
579 dia = NULL;
580 if (dia_open_diagrams()!=NULL) {
581 dia = (Diagram *) dia_open_diagrams()->data;
583 layer_dialog_set_diagram(dia);
587 void
588 layer_dialog_show()
590 if (layer_dialog == NULL || layer_dialog->dialog == NULL)
591 create_layer_dialog();
592 gtk_window_present(GTK_WINDOW(layer_dialog->dialog));
596 * Used to avoid writing to possibly already deleted layer in
597 * dia_layer_widget_connectable_toggled(). Must be called before
598 * e.g. gtk_list_clear_items() cause that will emit the toggled
599 * signal to last focus widget. See bug #329096
601 static void
602 _layer_widget_clear_layer (GtkWidget *widget, gpointer user_data)
604 DiaLayerWidget *lw = DIA_LAYER_WIDGET(widget);
605 lw->layer = NULL;
608 void
609 layer_dialog_set_diagram(Diagram *dia)
611 DiagramData *data;
612 GtkWidget *layer_widget;
613 Layer *layer;
614 Layer *active_layer = NULL;
615 int sel_pos;
616 int i,j;
618 if (dia!=NULL)
619 active_layer = dia->data->active_layer;
621 if (layer_dialog == NULL || layer_dialog->dialog == NULL)
622 create_layer_dialog(); /* May have been destroyed */
624 gtk_container_foreach (GTK_LIST(layer_dialog->layer_list),
625 _layer_widget_clear_layer, NULL);
626 gtk_list_clear_items(GTK_LIST(layer_dialog->layer_list), 0, -1);
627 layer_dialog->diagram = dia;
628 if (dia != NULL) {
629 i = g_list_index(dia_open_diagrams(), dia);
630 if (i >= 0)
631 gtk_option_menu_set_history(GTK_OPTION_MENU(layer_dialog->diagram_omenu),
635 if (dia != NULL) {
636 data = dia->data;
638 sel_pos = 0;
639 for (i=data->layers->len-1,j=0;i>=0;i--,j++) {
640 layer = (Layer *) g_ptr_array_index(data->layers, i);
641 layer_widget = dia_layer_widget_new(dia, layer);
642 gtk_widget_show(layer_widget);
643 gtk_container_add(GTK_CONTAINER(layer_dialog->layer_list), layer_widget);
644 if (layer==active_layer)
645 sel_pos = j;
647 gtk_list_select_item(GTK_LIST(layer_dialog->layer_list), sel_pos);
653 /******* DiaLayerWidget: *****/
655 /* The connectability buttons don't quite behave the way they should.
656 * The shift-click behaviour messes up the active layer.
657 * To fix this, we need to rework the code so that the setting of
658 * connect_on and connect_off is not tied to the button toggling,
659 * but determined by what caused it (creation, user selection,
660 * shift-selection).
663 static void
664 dia_layer_widget_unrealize(GtkWidget *widget)
666 DiaLayerWidget *lw = DIA_LAYER_WIDGET(widget);
668 if (lw->edit_dialog != NULL) {
669 gtk_widget_destroy(lw->edit_dialog->dialog);
670 g_free(lw->edit_dialog);
671 lw->edit_dialog = NULL;
674 (* GTK_WIDGET_CLASS (gtk_type_class(gtk_list_item_get_type ()))->unrealize) (widget);
677 static void
678 dia_layer_widget_class_init(DiaLayerWidgetClass *klass)
680 GtkObjectClass *object_class;
681 GtkWidgetClass *widget_class;
683 object_class = (GtkObjectClass*) klass;
684 widget_class = (GtkWidgetClass*) klass;
686 widget_class->unrealize = dia_layer_widget_unrealize;
689 static void
690 dia_layer_widget_set_connectable(DiaLayerWidget *widget, gboolean on)
692 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget->connectable), on);
695 static void
696 dia_layer_widget_exclusive_connectable(DiaLayerWidget *layer_widget)
698 GList *list;
699 DiaLayerWidget *lw;
700 Layer *layer;
701 int connectable = FALSE;
702 int i;
704 /* First determine if _any_ other layer widgets are set to connectable */
705 for (i=0;i<layer_widget->dia->data->layers->len;i++) {
706 layer = g_ptr_array_index(layer_widget->dia->data->layers, i);
707 if (layer_widget->layer != layer) {
708 connectable |= layer->connectable;
712 /* Now, toggle the connectability for all layers except the specified one */
713 list = GTK_LIST(layer_dialog->layer_list)->children;
714 while (list) {
715 lw = DIA_LAYER_WIDGET(list->data);
716 if (lw != layer_widget)
717 dia_layer_widget_set_connectable(lw, !connectable);
718 else {
719 dia_layer_widget_set_connectable(lw, TRUE);
721 gtk_widget_queue_draw(GTK_WIDGET(lw));
723 list = g_list_next(list);
727 static gboolean shifted = FALSE;
729 static gboolean
730 dia_layer_widget_button_event(GtkWidget *widget,
731 GdkEventButton *event,
732 gpointer userdata)
734 DiaLayerWidget *lw = DIA_LAYER_WIDGET(userdata);
736 shifted = event->state & GDK_SHIFT_MASK;
737 internal_call = FALSE;
738 /* Redraw the label? */
739 gtk_widget_queue_draw(GTK_WIDGET(lw));
740 return FALSE;
743 static void
744 dia_layer_widget_connectable_toggled(GtkToggleButton *widget,
745 gpointer userdata)
747 DiaLayerWidget *lw = DIA_LAYER_WIDGET(userdata);
748 if (!lw->layer)
749 return;
750 if (shifted) {
751 shifted = FALSE;
752 internal_call = TRUE;
753 dia_layer_widget_exclusive_connectable(lw);
754 internal_call = FALSE;
755 } else {
756 lw->layer->connectable = gtk_toggle_button_get_active(widget);
758 if (lw->layer == lw->dia->data->active_layer) {
759 lw->connect_off = !gtk_toggle_button_get_active(widget);
760 if (lw->connect_off) lw->connect_on = FALSE;
761 } else {
762 lw->connect_on = gtk_toggle_button_get_active(widget);
763 if (lw->connect_on) lw->connect_off = FALSE;
765 gtk_widget_queue_draw(GTK_WIDGET(lw));
766 if (!internal_call) {
767 diagram_add_update_all(lw->dia);
768 diagram_flush(lw->dia);
772 static void
773 dia_layer_widget_visible_clicked(GtkToggleButton *widget,
774 gpointer userdata)
776 DiaLayerWidget *lw = DIA_LAYER_WIDGET(userdata);
777 struct LayerVisibilityChange *change;
779 /* Have to use this internal_call hack 'cause there's no way to switch
780 * a toggle button without causing the 'clicked' event:(
782 if (!internal_call) {
783 Diagram *dia = lw->dia;
784 change = undo_layer_visibility(dia, lw->layer, shifted);
785 /** This apply kills 'lw', thus we have to hold onto 'lw->dia' */
786 layer_visibility_change_apply(change, dia);
787 undo_set_transactionpoint(dia->undo);
791 static void
792 dia_layer_widget_init(DiaLayerWidget *lw)
794 GtkWidget *hbox;
795 GtkWidget *visible;
796 GtkWidget *connectable;
797 GtkWidget *label;
799 hbox = gtk_hbox_new(FALSE, 0);
801 lw->dia = NULL;
802 lw->layer = NULL;
803 lw->edit_dialog = NULL;
805 lw->connect_on = FALSE;
806 lw->connect_off = FALSE;
808 lw->visible = visible =
809 dia_toggle_button_new_with_icons(dia_visible_icon, dia_visible_empty_icon);
811 g_signal_connect(G_OBJECT(visible), "button-release-event",
812 G_CALLBACK(dia_layer_widget_button_event), lw);
813 g_signal_connect(G_OBJECT(visible), "button-press-event",
814 G_CALLBACK(dia_layer_widget_button_event), lw);
815 g_signal_connect(G_OBJECT(visible), "clicked",
816 G_CALLBACK(dia_layer_widget_visible_clicked), lw);
817 gtk_box_pack_start (GTK_BOX (hbox), visible, FALSE, TRUE, 2);
818 gtk_widget_show(visible);
820 /*gtk_image_new_from_stock(GTK_STOCK_CONNECT,
821 GTK_ICON_SIZE_BUTTON), */
822 lw->connectable = connectable =
823 dia_toggle_button_new_with_icons(dia_connectable_icon,
824 dia_connectable_empty_icon);
826 g_signal_connect(G_OBJECT(connectable), "button-release-event",
827 G_CALLBACK(dia_layer_widget_button_event), lw);
828 g_signal_connect(G_OBJECT(connectable), "button-press-event",
829 G_CALLBACK(dia_layer_widget_button_event), lw);
830 g_signal_connect(G_OBJECT(connectable), "clicked",
831 G_CALLBACK(dia_layer_widget_connectable_toggled), lw);
833 gtk_box_pack_start (GTK_BOX (hbox), connectable, FALSE, TRUE, 2);
834 gtk_widget_show(connectable);
836 lw->label = label = gtk_label_new("layer_default_label");
837 gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
838 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 0);
839 gtk_widget_show(label);
841 gtk_widget_show(hbox);
843 gtk_container_add(GTK_CONTAINER(lw), hbox);
845 g_signal_connect (GTK_OBJECT (lw), "select",
846 (GtkSignalFunc) dia_layer_select_callback,
847 (gpointer) NULL);
848 g_signal_connect (GTK_OBJECT (lw), "deselect",
849 (GtkSignalFunc) dia_layer_deselect_callback,
850 (gpointer) NULL);
853 GtkType
854 dia_layer_widget_get_type(void)
856 static GtkType dlw_type = 0;
858 if (!dlw_type) {
859 static const GtkTypeInfo dlw_info = {
860 "DiaLayerWidget",
861 sizeof (DiaLayerWidget),
862 sizeof (DiaLayerWidgetClass),
863 (GtkClassInitFunc) dia_layer_widget_class_init,
864 (GtkObjectInitFunc) dia_layer_widget_init,
865 NULL,
866 NULL,
867 (GtkClassInitFunc) NULL,
870 dlw_type = gtk_type_unique (gtk_list_item_get_type (), &dlw_info);
873 return dlw_type;
876 GtkWidget *
877 dia_layer_widget_new(Diagram *dia, Layer *layer)
879 GtkWidget *widget;
881 widget = GTK_WIDGET ( gtk_type_new (dia_layer_widget_get_type ()));
882 dia_layer_set_layer(DIA_LAYER_WIDGET(widget), dia, layer);
884 /* These may get toggled when the button is set without the widget being
885 * selected first. */
886 DIA_LAYER_WIDGET(widget)->connect_on = FALSE;
887 DIA_LAYER_WIDGET(widget)->connect_off = FALSE;
889 return widget;
892 /** Layer has either been selected or created */
893 void
894 dia_layer_set_layer(DiaLayerWidget *widget, Diagram *dia, Layer *layer)
896 widget->dia = dia;
897 widget->layer = layer;
899 dia_layer_update_from_layer(widget);
902 void
903 dia_layer_update_from_layer (DiaLayerWidget *widget)
905 internal_call = TRUE;
906 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget->visible),
907 widget->layer->visible);
909 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget->connectable),
910 widget->layer->connectable);
911 internal_call = FALSE;
913 gtk_label_set_text (GTK_LABEL (widget->label), widget->layer->name);
918 * The edit layer attributes dialog
921 static void
922 edit_layer_ok_callback (GtkWidget *w, gpointer client_data)
924 EditLayerDialog *dialog;
925 Layer *layer;
927 dialog = (EditLayerDialog *) client_data;
928 layer = dialog->layer_widget->layer;
930 g_free (layer->name);
931 layer->name = g_strdup (gtk_entry_get_text (GTK_ENTRY (dialog->name_entry)));
933 diagram_add_update_all (dialog->layer_widget->dia);
934 diagram_flush (dialog->layer_widget->dia);
936 dia_layer_update_from_layer (dialog->layer_widget);
938 dialog->layer_widget->edit_dialog = NULL;
939 gtk_widget_destroy (dialog->dialog);
940 g_free (dialog);
943 static void
944 edit_layer_cancel_callback (GtkWidget *w,
945 gpointer client_data)
947 EditLayerDialog *dialog;
949 dialog = (EditLayerDialog *) client_data;
951 dialog->layer_widget->edit_dialog = NULL;
952 if (dialog->dialog != NULL)
953 gtk_widget_destroy (dialog->dialog);
954 g_free (dialog);
957 static gint
958 edit_layer_delete_callback (GtkWidget *w,
959 GdkEvent *e,
960 gpointer client_data)
962 edit_layer_cancel_callback (w, client_data);
964 return TRUE;
967 static void
968 layer_dialog_edit_layer (DiaLayerWidget *layer_widget)
970 EditLayerDialog *dialog;
971 GtkWidget *vbox;
972 GtkWidget *hbox;
973 GtkWidget *label;
974 GtkWidget *button;
976 /* the new dialog structure */
977 dialog = (EditLayerDialog *) g_malloc (sizeof (EditLayerDialog));
978 dialog->layer_widget = layer_widget;
980 /* the dialog */
981 dialog->dialog = gtk_dialog_new ();
982 gtk_window_set_role (GTK_WINDOW (dialog->dialog), "edit_layer_attrributes");
983 gtk_window_set_title (GTK_WINDOW (dialog->dialog), _("Edit Layer Attributes"));
984 gtk_window_set_position (GTK_WINDOW (dialog->dialog), GTK_WIN_POS_MOUSE);
986 /* handle the wm close signal */
987 g_signal_connect (GTK_OBJECT (dialog->dialog), "delete_event",
988 G_CALLBACK (edit_layer_delete_callback),
989 dialog);
990 g_signal_connect (GTK_OBJECT (dialog->dialog), "destroy",
991 G_CALLBACK (gtk_widget_destroy),
992 &dialog->dialog);
994 /* the main vbox */
995 vbox = gtk_vbox_new (FALSE, 1);
996 gtk_container_set_border_width (GTK_CONTAINER (vbox), 2);
997 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog->dialog)->vbox), vbox, TRUE, TRUE, 0);
999 /* the name entry hbox, label and entry */
1000 hbox = gtk_hbox_new (FALSE, 1);
1001 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
1002 label = gtk_label_new (_("Layer name:"));
1003 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
1004 gtk_widget_show (label);
1005 dialog->name_entry = gtk_entry_new ();
1006 gtk_box_pack_start (GTK_BOX (hbox), dialog->name_entry, TRUE, TRUE, 0);
1007 gtk_entry_set_text (GTK_ENTRY (dialog->name_entry), layer_widget->layer->name);
1008 gtk_widget_show (dialog->name_entry);
1009 gtk_widget_show (hbox);
1011 button = gtk_button_new_from_stock (GTK_STOCK_OK);
1012 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
1013 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog->dialog)->action_area),
1014 button, TRUE, TRUE, 0);
1015 g_signal_connect (GTK_OBJECT (button), "clicked",
1016 G_CALLBACK(edit_layer_ok_callback),
1017 dialog);
1018 gtk_widget_grab_default (button);
1019 gtk_widget_show (button);
1021 button = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
1022 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
1023 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog->dialog)->action_area),
1024 button, TRUE, TRUE, 0);
1025 g_signal_connect (GTK_OBJECT (button), "clicked",
1026 G_CALLBACK(edit_layer_cancel_callback),
1027 dialog);
1028 gtk_widget_show (button);
1030 gtk_widget_show (vbox);
1031 gtk_widget_show (dialog->dialog);
1033 layer_widget->edit_dialog = dialog;
1037 /******** layer changes: */
1039 static void
1040 layer_change_apply(struct LayerChange *change, Diagram *dia)
1042 change->applied = 1;
1044 switch (change->type) {
1045 case TYPE_DELETE_LAYER:
1046 data_delete_layer(dia->data, change->layer);
1047 break;
1048 case TYPE_ADD_LAYER:
1049 data_add_layer_at(dia->data, change->layer, change->index);
1050 break;
1051 case TYPE_RAISE_LAYER:
1052 data_raise_layer(dia->data, change->layer);
1053 break;
1054 case TYPE_LOWER_LAYER:
1055 data_lower_layer(dia->data, change->layer);
1056 break;
1059 diagram_add_update_all(dia);
1061 if (layer_dialog->diagram == dia) {
1062 layer_dialog_set_diagram(dia);
1066 static void
1067 layer_change_revert(struct LayerChange *change, Diagram *dia)
1069 switch (change->type) {
1070 case TYPE_DELETE_LAYER:
1071 data_add_layer_at(dia->data, change->layer, change->index);
1072 break;
1073 case TYPE_ADD_LAYER:
1074 data_delete_layer(dia->data, change->layer);
1075 break;
1076 case TYPE_RAISE_LAYER:
1077 data_lower_layer(dia->data, change->layer);
1078 break;
1079 case TYPE_LOWER_LAYER:
1080 data_raise_layer(dia->data, change->layer);
1081 break;
1084 diagram_add_update_all(dia);
1086 if (layer_dialog->diagram == dia) {
1087 layer_dialog_set_diagram(dia);
1090 change->applied = 0;
1093 static void
1094 layer_change_free(struct LayerChange *change)
1096 switch (change->type) {
1097 case TYPE_DELETE_LAYER:
1098 if (change->applied) {
1099 layer_destroy(change->layer);
1101 break;
1102 case TYPE_ADD_LAYER:
1103 if (!change->applied) {
1104 layer_destroy(change->layer);
1106 break;
1107 case TYPE_RAISE_LAYER:
1108 break;
1109 case TYPE_LOWER_LAYER:
1110 break;
1114 static Change *
1115 undo_layer(Diagram *dia, Layer *layer, enum LayerChangeType type, int index)
1117 struct LayerChange *change;
1119 change = g_new0(struct LayerChange, 1);
1121 change->change.apply = (UndoApplyFunc) layer_change_apply;
1122 change->change.revert = (UndoRevertFunc) layer_change_revert;
1123 change->change.free = (UndoFreeFunc) layer_change_free;
1125 change->type = type;
1126 change->layer = layer;
1127 change->index = index;
1128 change->applied = 1;
1130 undo_push_change(dia->undo, (Change *) change);
1131 return (Change *)change;
1134 static void
1135 layer_visibility_change_apply(struct LayerVisibilityChange *change,
1136 Diagram *dia)
1138 GPtrArray *layers;
1139 Layer *layer = change->layer;
1140 int visible = FALSE;
1141 int i;
1143 if (change->is_exclusive) {
1144 /* First determine if _any_ other layer widgets are set to visible.
1145 * If there is, exclusive switching turns all off. */
1146 for (i=0;i<dia->data->layers->len;i++) {
1147 Layer *temp_layer = g_ptr_array_index(dia->data->layers, i);
1148 if (temp_layer != layer) {
1149 visible |= temp_layer->visible;
1153 /* Now, toggle the visibility for all layers except the specified one */
1154 layers = dia->data->layers;
1155 for (i = 0; i < layers->len; i++) {
1156 Layer *temp_layer = (Layer *) g_ptr_array_index(layers, i);
1157 if (temp_layer == layer) {
1158 temp_layer->visible = TRUE;
1159 } else {
1160 temp_layer->visible = !visible;
1163 } else {
1164 layer->visible = !layer->visible;
1166 diagram_add_update_all(dia);
1168 if (layer_dialog->diagram == dia) {
1169 layer_dialog_set_diagram(dia);
1173 /** Revert to the visibility before this change was applied.
1175 static void
1176 layer_visibility_change_revert(struct LayerVisibilityChange *change,
1177 Diagram *dia)
1179 GList *vis = change->original_visibility;
1180 GPtrArray *layers = dia->data->layers;
1181 int i;
1183 for (i = 0; vis != NULL && i < layers->len; vis = g_list_next(vis), i++) {
1184 Layer *layer = (Layer*) g_ptr_array_index(layers, i);
1185 layer->visible = (gboolean)vis->data;
1188 if (vis != NULL || i < layers->len) {
1189 printf("Internal error: visibility undo has %d visibilities, but %d layers\n",
1190 g_list_length(change->original_visibility), layers->len);
1193 diagram_add_update_all(dia);
1195 if (layer_dialog->diagram == dia) {
1196 layer_dialog_set_diagram(dia);
1200 static void
1201 layer_visibility_change_free(struct LayerVisibilityChange *change)
1203 g_list_free(change->original_visibility);
1206 static struct LayerVisibilityChange *
1207 undo_layer_visibility(Diagram *dia, Layer *layer, gboolean exclusive)
1209 struct LayerVisibilityChange *change;
1210 GList *visibilities = NULL;
1211 int i;
1212 GPtrArray *layers = dia->data->layers;
1214 change = g_new0(struct LayerVisibilityChange, 1);
1216 change->change.apply = (UndoApplyFunc) layer_visibility_change_apply;
1217 change->change.revert = (UndoRevertFunc) layer_visibility_change_revert;
1218 change->change.free = (UndoFreeFunc) layer_visibility_change_free;
1220 for (i = 0; i < layers->len; i++) {
1221 Layer *temp_layer = (Layer *) g_ptr_array_index(layers, i);
1222 visibilities = g_list_append(visibilities, (gpointer)temp_layer->visible);
1225 change->original_visibility = visibilities;
1226 change->layer = layer;
1227 change->is_exclusive = exclusive;
1229 undo_push_change(dia->undo, (Change *) change);
1230 return change;