New cisco icons, and a fix in element.h
[dia.git] / app / commands.c
blob09354c9cb368407cbe5bb66415c89fb59b931117
1 /* Dia -- an diagram creation/manipulation program
2 * Copyright (C) 1998 Alexander Larsson *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 #include <config.h>
20 #ifdef HAVE_UNISTD_H
21 # include <unistd.h>
22 #endif
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <math.h>
29 #include <glib.h>
31 #include <gdk-pixbuf/gdk-pixbuf.h>
32 #include <gtk/gtk.h>
34 /* Added by Andrew Ferrier: for use of gnome_about_new() */
36 #ifdef GNOME
37 # include <gnome.h>
38 #endif
40 #ifdef G_OS_WIN32
42 * Instead of polluting the Dia namespace with windoze headers, declare the
43 * required prototype here. This is bad style, but not as bad as namespace
44 * clashes to be resolved without C++ --hb
46 long __stdcall
47 ShellExecuteA (long hwnd,
48 const char* lpOperation,
49 const char* lpFile,
50 const char* lpParameters,
51 const char* lpDirectory,
52 int nShowCmd);
53 #endif
55 #include "paginate_psprint.h"
56 #ifdef G_OS_WIN32
57 # include "paginate_gdiprint.h"
58 #endif
59 #include "intl.h"
60 #include "commands.h"
61 #include "app_procs.h"
62 #include "diagram.h"
63 #include "display.h"
64 #include "object_ops.h"
65 #include "cut_n_paste.h"
66 #include "load_save.h"
67 #include "utils.h"
68 #include "message.h"
69 #include "grid.h"
70 #include "properties.h"
71 #include "propinternals.h"
72 #include "preferences.h"
73 #include "layer_dialog.h"
74 #include "connectionpoint_ops.h"
75 #include "undo.h"
76 #include "pagesetup.h"
77 #include "text.h"
78 #include "dia_dirs.h"
79 #include "focus.h"
80 #include <gdk/gdk.h>
81 #include <gdk/gdkkeysyms.h>
82 #include "lib/properties.h"
83 #include "dia-props.h"
84 #include "diagram_tree_window.h"
85 #include "authors.h" /* master contributors data */
87 GdkPixbuf *logo;
89 void file_quit_callback(gpointer data, guint action, GtkWidget *widget)
91 app_exit();
94 void
95 file_pagesetup_callback(gpointer data, guint action, GtkWidget *widget)
97 Diagram *dia;
99 dia = ddisplay_active_diagram();
100 if (!dia) return;
101 create_page_setup_dlg(dia);
104 void
105 file_print_callback(gpointer data, guint action, GtkWidget *widget)
107 Diagram *dia;
109 dia = ddisplay_active_diagram();
110 if (!dia) return;
111 #ifdef G_OS_WIN32
112 /* This option could be used with Gnome too. Does it make sense there ? */
113 if (!prefs.prefer_psprint)
114 diagram_print_gdi(dia);
115 else
116 #endif
117 diagram_print_ps(dia);
120 void
121 file_close_callback(gpointer data, guint action, GtkWidget *widget)
123 /* some people use tear-off menus and insist to close non existing displays */
124 if (ddisplay_active())
125 ddisplay_close(ddisplay_active());
128 void
129 file_new_callback(gpointer data, guint action, GtkWidget *widget)
131 Diagram *dia;
132 DDisplay *ddisp;
133 static int untitled_nr = 1;
134 char buffer[24];
136 g_snprintf(buffer, 24, _("Diagram%d.dia"), untitled_nr++);
138 dia = new_diagram(buffer);
139 ddisp = new_display(dia);
140 diagram_tree_add(diagram_tree(), dia);
143 void
144 file_preferences_callback(gpointer data, guint action, GtkWidget *widget)
146 prefs_show();
150 void
151 edit_copy_callback(gpointer data, guint action, GtkWidget *widget)
153 GList *copy_list;
154 DDisplay *ddisp;
156 ddisp = ddisplay_active();
157 if (!ddisp) return;
158 copy_list = parent_list_affected(diagram_get_sorted_selected(ddisp->diagram));
160 cnp_store_objects(object_copy_list(copy_list));
161 g_list_free(copy_list);
163 ddisplay_do_update_menu_sensitivity(ddisp);
166 void
167 edit_cut_callback(gpointer data, guint action, GtkWidget *widget)
169 GList *cut_list;
170 DDisplay *ddisp;
171 Change *change;
173 ddisp = ddisplay_active();
174 if (!ddisp) return;
176 diagram_selected_break_external(ddisp->diagram);
178 cut_list = parent_list_affected(diagram_get_sorted_selected(ddisp->diagram));
180 cnp_store_objects(object_copy_list(cut_list));
182 change = undo_delete_objects_children(ddisp->diagram, cut_list);
183 (change->apply)(change, ddisp->diagram);
185 ddisplay_do_update_menu_sensitivity(ddisp);
186 diagram_flush(ddisp->diagram);
189 diagram_modified(ddisp->diagram);
190 undo_set_transactionpoint(ddisp->diagram->undo);
194 void
195 edit_paste_callback(gpointer data, guint action, GtkWidget *widget)
197 GList *paste_list;
198 DDisplay *ddisp;
199 Point paste_corner;
200 Point delta;
201 Change *change;
203 ddisp = ddisplay_active();
204 if (!ddisp) return;
206 if (!cnp_exist_stored_objects()) {
207 message_warning(_("No existing object to paste.\n"));
208 return;
211 paste_list = cnp_get_stored_objects(); /* Gets a copy */
213 paste_corner = object_list_corner(paste_list);
215 delta.x = ddisp->visible.left - paste_corner.x;
216 delta.y = ddisp->visible.top - paste_corner.y;
218 /* Move down some 10% of the visible area. */
219 delta.x += (ddisp->visible.right - ddisp->visible.left)*0.1;
220 delta.y += (ddisp->visible.bottom - ddisp->visible.top)*0.1;
222 object_list_move_delta(paste_list, &delta);
224 change = undo_insert_objects(ddisp->diagram, paste_list, 0);
225 (change->apply)(change, ddisp->diagram);
227 diagram_modified(ddisp->diagram);
228 undo_set_transactionpoint(ddisp->diagram->undo);
230 diagram_remove_all_selected(ddisp->diagram, TRUE);
231 diagram_select_list(ddisp->diagram, paste_list);
233 diagram_flush(ddisp->diagram);
237 * ALAN: Paste should probably paste to different position, feels
238 * wrong somehow. ALAN: The offset should increase a little each time
239 * if you paste/duplicate several times in a row, because it is
240 * clearer what is happening than if you were to piling them all in
241 * one place.
243 * completely untested, basically it is copy+paste munged together
245 void
246 edit_duplicate_callback(gpointer data, guint action, GtkWidget *widget)
248 GList *duplicate_list;
249 DDisplay *ddisp;
250 Point duplicate_corner;
251 Point delta;
252 Change *change;
254 ddisp = ddisplay_active();
255 if (!ddisp) return;
256 duplicate_list = object_copy_list(diagram_get_sorted_selected(ddisp->diagram));
257 duplicate_corner = object_list_corner(duplicate_list);
259 /* Move down some 10% of the visible area. */
260 delta.x = (ddisp->visible.right - ddisp->visible.left)*0.05;
261 delta.y = (ddisp->visible.bottom - ddisp->visible.top)*0.05;
263 object_list_move_delta(duplicate_list, &delta);
265 change = undo_insert_objects(ddisp->diagram, duplicate_list, 0);
266 (change->apply)(change, ddisp->diagram);
268 diagram_modified(ddisp->diagram);
269 undo_set_transactionpoint(ddisp->diagram->undo);
271 diagram_remove_all_selected(ddisp->diagram, TRUE);
272 diagram_select_list(ddisp->diagram, duplicate_list);
274 diagram_flush(ddisp->diagram);
276 ddisplay_do_update_menu_sensitivity(ddisp);
282 /* Signal handler for getting the clipboard contents */
283 /* Note that the clipboard is for M$-style cut/copy/paste copying, while
284 the selection is for Unix-style mark-and-copy. We can't really do
285 mark-and-copy.
288 static void
289 insert_text(DDisplay *ddisp, Focus *focus, const gchar *text)
291 ObjectChange *change = NULL;
292 int modified = FALSE, any_modified = FALSE;
293 DiaObject *obj = focus_get_object(focus);
295 while (text != NULL) {
296 gchar *next_line = g_utf8_strchr(text, -1, '\n');
297 if (next_line != text) {
298 gint len = g_utf8_strlen(text, (next_line-text));
299 modified = (*focus->key_event)(focus, GDK_A, text, len, &change);
301 if (next_line != NULL) {
302 modified = (*focus->key_event)(focus, GDK_Return, "\n", 1, &change);
303 text = g_utf8_next_char(next_line);
304 } else {
305 text = NULL;
307 { /* Make sure object updates its data: */
308 Point p = obj->position;
309 (obj->ops->move)(obj,&p); }
311 /* Perhaps this can be improved */
312 object_add_updates(obj, ddisp->diagram);
314 if (modified && (change != NULL)) {
315 undo_object_change(ddisp->diagram, obj, change);
316 any_modified = TRUE;
319 diagram_flush(ddisp->diagram);
322 if (any_modified) {
323 diagram_modified(ddisp->diagram);
324 undo_set_transactionpoint(ddisp->diagram->undo);
329 static void
330 received_clipboard_handler(GtkClipboard *clipboard,
331 const gchar *text,
332 gpointer data) {
333 Focus *focus = active_focus();
334 DDisplay *ddisp = (DDisplay *)data;
336 if (text == NULL) return;
338 if ((focus == NULL) || (!focus->has_focus)) return;
340 if (!g_utf8_validate(text, -1, NULL)) {
341 message_error("Not valid UTF8");
342 return;
345 insert_text(ddisp, focus, text);
348 static PropDescription text_prop_singleton_desc[] = {
349 { "text", PROP_TYPE_TEXT },
350 PROP_DESC_END};
352 static void
353 make_text_prop_singleton(GPtrArray **props, TextProperty **prop)
355 *props = prop_list_from_descs(text_prop_singleton_desc,pdtpp_true);
356 g_assert((*props)->len == 1);
358 *prop = g_ptr_array_index((*props),0);
359 g_free((*prop)->text_data);
360 (*prop)->text_data = NULL;
364 void
365 edit_copy_text_callback(gpointer data, guint action, GtkWidget *widget)
367 Focus *focus = active_focus();
368 DDisplay *ddisp;
369 DiaObject *obj;
370 GPtrArray *textprops;
371 TextProperty *prop;
373 if ((focus == NULL) || (!focus->has_focus)) return;
375 ddisp = ddisplay_active();
376 if (!ddisp) return;
378 obj = focus_get_object(focus);
380 if (obj->ops->get_props == NULL)
381 return;
383 make_text_prop_singleton(&textprops,&prop);
384 /* Get the first text property */
385 obj->ops->get_props(obj, textprops);
387 /* GTK docs claim the selection clipboard is ignored on Win32.
388 * The "clipboard" clipboard is mostly ignored in Unix
390 #ifdef G_OS_WIN32
391 gtk_clipboard_set_text(gtk_clipboard_get(GDK_NONE),
392 prop->text_data, -1);
393 #else
394 gtk_clipboard_set_text(gtk_clipboard_get(GDK_SELECTION_PRIMARY),
395 prop->text_data, -1);
396 #endif
397 prop_list_free(textprops);
400 void
401 edit_cut_text_callback(gpointer data, guint action, GtkWidget *widget)
403 Focus *focus = active_focus();
404 DDisplay *ddisp;
405 DiaObject *obj;
406 Text *text;
407 GPtrArray *textprops;
408 TextProperty *prop;
409 ObjectChange *change;
411 if ((focus == NULL) || (!focus->has_focus)) return;
413 ddisp = ddisplay_active();
414 if (!ddisp) return;
416 obj = focus_get_object(focus);
417 text = (Text*)focus->user_data;
419 if (obj->ops->get_props == NULL)
420 return;
422 make_text_prop_singleton(&textprops,&prop);
423 /* Get the first text property */
424 obj->ops->get_props(obj, textprops);
426 /* GTK docs claim the selection clipboard is ignored on Win32.
427 * The "clipboard" clipboard is mostly ignored in Unix
429 #ifdef G_OS_WIN32
430 gtk_clipboard_set_text(gtk_clipboard_get(GDK_NONE),
431 prop->text_data, -1);
432 #else
433 gtk_clipboard_set_text(gtk_clipboard_get(GDK_SELECTION_PRIMARY),
434 prop->text_data, -1);
435 #endif
437 prop_list_free(textprops);
439 if (text_delete_all(text, &change)) {
440 object_add_updates(obj, ddisp->diagram);
441 undo_object_change(ddisp->diagram, obj, change);
442 undo_set_transactionpoint(ddisp->diagram->undo);
443 diagram_modified(ddisp->diagram);
444 diagram_flush(ddisp->diagram);
448 void
449 edit_paste_text_callback(gpointer data, guint action, GtkWidget *widget)
451 DDisplay *ddisp;
453 ddisp = ddisplay_active();
454 if (!ddisp) return;
456 #ifdef G_OS_WIN32
457 gtk_clipboard_request_text(gtk_clipboard_get(GDK_NONE),
458 received_clipboard_handler, ddisp);
459 #else
460 gtk_clipboard_request_text(gtk_clipboard_get(GDK_SELECTION_PRIMARY),
461 received_clipboard_handler, ddisp);
462 #endif
465 void
466 edit_delete_callback(gpointer data, guint action, GtkWidget *widget)
468 GList *delete_list;
469 DDisplay *ddisp;
471 Change *change;
473 ddisp = ddisplay_active();
474 if (!ddisp) return;
476 diagram_selected_break_external(ddisp->diagram);
478 delete_list = diagram_get_sorted_selected(ddisp->diagram);
479 change = undo_delete_objects_children(ddisp->diagram, delete_list);
480 (change->apply)(change, ddisp->diagram);
481 g_list_free(delete_list);
483 diagram_modified(ddisp->diagram);
485 ddisplay_do_update_menu_sensitivity(ddisp);
486 diagram_flush(ddisp->diagram);
488 undo_set_transactionpoint(ddisp->diagram->undo);
491 void
492 edit_undo_callback(gpointer data, guint action, GtkWidget *widget)
494 Diagram *dia;
496 dia = ddisplay_active_diagram();
497 if (!dia) return;
499 undo_revert_to_last_tp(dia->undo);
500 diagram_modified(dia);
502 diagram_flush(dia);
505 void
506 edit_redo_callback(gpointer data, guint action, GtkWidget *widget)
508 Diagram *dia;
510 dia = ddisplay_active_diagram();
511 if (!dia) return;
513 undo_apply_to_next_tp(dia->undo);
514 diagram_modified(dia);
516 diagram_flush(dia);
519 void
520 help_manual_callback(gpointer data, guint action, GtkWidget *widget)
522 #ifdef GNOME
523 gnome_help_display("dia", NULL, NULL);
524 #else
525 char *helpdir, *helpindex = NULL, *command;
526 guint bestscore = G_MAXINT;
527 GDir *dp;
528 const char *dentry;
529 GError *error = NULL;
531 helpdir = dia_get_data_directory("help");
532 if (!helpdir) {
533 message_warning(_("Could not find help directory"));
534 return;
537 /* search through helpdir for the helpfile that matches the user's locale */
538 dp = g_dir_open (helpdir, 0, &error);
539 if (!dp) {
540 message_warning(_("Could not open help directory:\n%s"),
541 error->message);
542 g_error_free (error);
543 return;
546 while ((dentry = g_dir_read_name(dp)) != NULL) {
547 guint score;
549 score = intl_score_locale(dentry);
550 if (score < bestscore) {
551 if (helpindex)
552 g_free(helpindex);
553 #ifdef G_OS_WIN32
554 /* use HTML Help on win32 if available */
555 helpindex = g_strconcat(helpdir, G_DIR_SEPARATOR_S, dentry,
556 G_DIR_SEPARATOR_S "dia-manual.chm", NULL);
557 if (!g_file_test(helpindex, G_FILE_TEST_EXISTS)) {
558 helpindex = g_strconcat(helpdir, G_DIR_SEPARATOR_S, dentry,
559 G_DIR_SEPARATOR_S "index.html", NULL);
561 #else
562 helpindex = g_strconcat(helpdir, G_DIR_SEPARATOR_S, dentry,
563 G_DIR_SEPARATOR_S "index.html", NULL);
564 #endif
565 bestscore = score;
568 g_dir_close (dp);
569 g_free(helpdir);
570 if (!helpindex) {
571 message_warning(_("Could not find help directory"));
572 return;
575 #ifdef G_OS_WIN32
576 # define SW_SHOWNORMAL 1
577 ShellExecuteA (0, "open", helpindex, NULL, helpdir, SW_SHOWNORMAL);
578 #else
579 command = getenv("BROWSER");
580 command = g_strdup_printf("%s 'file://%s' &", command ? command : "gnome-open", helpindex);
581 system(command);
582 g_free(command);
583 #endif
585 g_free(helpindex);
586 #endif
589 void
590 help_about_callback(gpointer data, guint action, GtkWidget *widget)
592 #ifdef GNOME
594 /* Take advantage of gnome_about_new(),
595 * which is much cleaner and GNOME2 HIG compliant,
596 * Originally implemented by Xing Wang, modified
597 * by Andrew Ferrier.
599 * Note: in this function there is no need to discriminate
600 * between the different kinds of 'authors'.
603 static GtkWidget *about;
606 * Translators should localize the following string
607 * which will give them credit in the About box.
608 * E.g. "Fulano de Tal <fulano@detal.com>"
611 gchar *translators = _("translator_credits-PLEASE_ADD_YOURSELF_HERE");
612 gchar logo_file[100];
614 if (!about) {
615 GdkPixbuf *logo;
617 gchar* datadir = dia_get_data_directory("");
618 g_snprintf(logo_file, sizeof(logo_file),
619 "%s%sdia_logo.png", datadir, G_DIR_SEPARATOR_S);
621 logo = gdk_pixbuf_new_from_file(logo_file, NULL);
622 g_free(datadir);
624 about = gnome_about_new(
625 _("Dia"),
626 VERSION,
627 _("Copyright (C) 1998-2005 The Free Software Foundation and the authors"),
628 _("Dia is a program for drawing structured diagrams.\n"
629 "Please visit http://www.gnome.org/projects/dia for more information."),
630 authors,
631 documentors,
632 (strcmp (translators, "translator_credits-PLEASE_ADD_YOURSELF_HERE")
633 ? translators : NULL),
634 logo);
636 if (logo)
637 g_object_unref (logo);
639 g_signal_connect (about, "destroy",
640 G_CALLBACK (gtk_widget_destroyed),
641 &about);
644 gtk_widget_show_now (about);
646 #else
648 /* No GNOME, fall back to the old GTK method */
650 const gint nauthors = (sizeof(authors) / sizeof(authors[0])) - 1;
651 const gint ndocumentors = (sizeof(documentors) / sizeof(documentors[0])) - 1;
653 GtkWidget *dialog;
654 GtkWidget *vbox;
655 GtkWidget *table;
656 GtkWidget *bbox;
657 GtkWidget *frame;
658 GtkWidget *label;
659 GtkWidget *button;
660 char str[100];
661 gint i;
663 GtkWidget *gpixmap;
665 dialog = gtk_dialog_new ();
666 gtk_window_set_role (GTK_WINDOW (dialog), "about_dialog");
667 gtk_window_set_title (GTK_WINDOW (dialog), _("About Dia"));
668 gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
669 gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER);
670 g_signal_connect (GTK_OBJECT (dialog), "destroy",
671 G_CALLBACK (gtk_widget_destroy),
672 GTK_OBJECT (dialog));
674 vbox = gtk_vbox_new (FALSE, 1);
675 gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
676 gtk_container_add (GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), vbox);
678 if (!logo) {
679 gchar* datadir = dia_get_data_directory("");
680 g_snprintf(str, sizeof(str), "%s%sdia_logo.png", datadir, G_DIR_SEPARATOR_S);
681 logo = gdk_pixbuf_new_from_file(str, NULL);
682 g_free(datadir);
685 if (logo) {
686 GdkPixmap *pixmap;
687 GdkBitmap *bitmap;
689 frame = gtk_frame_new (NULL);
690 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
691 gtk_container_set_border_width (GTK_CONTAINER (frame), 1);
692 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, TRUE, 1);
694 gdk_pixbuf_render_pixmap_and_mask(logo, &pixmap, &bitmap, 128);
695 gpixmap = gtk_pixmap_new(pixmap, bitmap);
696 gdk_pixmap_unref(pixmap);
697 if (bitmap) gdk_bitmap_unref(bitmap);
698 gtk_container_add (GTK_CONTAINER(frame), gpixmap);
701 frame = gtk_frame_new (NULL);
702 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
703 gtk_container_set_border_width (GTK_CONTAINER (frame), 1);
704 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, TRUE, 1);
706 table = gtk_table_new(3, 2, FALSE);
707 gtk_container_set_border_width (GTK_CONTAINER (table), 1);
708 gtk_container_add (GTK_CONTAINER (frame), table);
710 g_snprintf(str, sizeof(str), _("Dia v %s by Alexander Larsson"), VERSION);
711 label = gtk_label_new (str);
712 gtk_table_attach(GTK_TABLE(table), label, 0,2, 0,1,
713 GTK_FILL|GTK_EXPAND, GTK_FILL, 0,2);
715 /* Exact spelling is Ch&eacute;p&eacute;lov (using *ML entities) */
716 label = gtk_label_new(_("Maintainers: Lars Clausen and Cyrille Chepelov"));
717 gtk_table_attach(GTK_TABLE(table), label, 0,2, 1,2,
718 GTK_FILL|GTK_EXPAND, GTK_FILL, 0,2);
720 label = gtk_label_new (_("Please visit http://www.gnome.org/projects/dia "
721 "for more information"));
722 gtk_table_attach(GTK_TABLE(table), label, 0,2, 2,3,
723 GTK_FILL|GTK_EXPAND, GTK_FILL, 0,2);
725 label = gtk_label_new (_("Contributors:"));
726 gtk_table_attach(GTK_TABLE(table), label, 0,2, 3,4,
727 GTK_FILL|GTK_EXPAND, GTK_FILL, 0,2);
729 for (i = 0; i < nauthors; i++) {
730 label = gtk_label_new(authors[i]);
731 gtk_table_attach(GTK_TABLE(table), label, i%2,i%2+1, i/2+4,i/2+5,
732 GTK_FILL|GTK_EXPAND, GTK_FILL, 0,0);
735 for (i = nauthors; i < nauthors + ndocumentors; i++) {
736 label = gtk_label_new(documentors[i - nauthors]);
737 gtk_table_attach(GTK_TABLE(table), label, i%2,i%2+1, i/2+4,i/2+5,
738 GTK_FILL|GTK_EXPAND, GTK_FILL, 0,0);
741 gtk_table_set_col_spacings(GTK_TABLE(table), 1);
742 gtk_table_set_row_spacings(GTK_TABLE(table), 1);
744 bbox = gtk_hbutton_box_new();
745 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), bbox, TRUE, TRUE, 5);
746 gtk_button_box_set_child_size(GTK_BUTTON_BOX(bbox), 80, 0);
747 gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 10);
749 button = gtk_button_new_from_stock(GTK_STOCK_OK);
750 gtk_container_add(GTK_CONTAINER(bbox), button);
751 g_signal_connect_swapped(GTK_OBJECT (button), "clicked",
752 G_CALLBACK(gtk_widget_destroy),
753 GTK_OBJECT(dialog));
755 gtk_widget_show_all (dialog);
757 #endif /* GNOME */
760 void
761 view_zoom_in_callback(gpointer data, guint action, GtkWidget *widget)
763 DDisplay *ddisp;
764 Point middle;
765 Rectangle *visible;
767 ddisp = ddisplay_active();
768 if (!ddisp) return;
769 visible = &ddisp->visible;
770 middle.x = visible->left*0.5 + visible->right*0.5;
771 middle.y = visible->top*0.5 + visible->bottom*0.5;
773 ddisplay_zoom(ddisp, &middle, M_SQRT2);
776 void
777 view_zoom_out_callback(gpointer data, guint action, GtkWidget *widget)
779 DDisplay *ddisp;
780 Point middle;
781 Rectangle *visible;
783 ddisp = ddisplay_active();
784 if (!ddisp) return;
785 visible = &ddisp->visible;
786 middle.x = visible->left*0.5 + visible->right*0.5;
787 middle.y = visible->top*0.5 + visible->bottom*0.5;
789 ddisplay_zoom(ddisp, &middle, M_SQRT1_2);
792 void
793 view_zoom_set_callback(gpointer data, guint action, GtkWidget *widget)
795 DDisplay *ddisp;
796 real scale;
797 Point middle;
798 Rectangle *visible;
800 ddisp = ddisplay_active();
801 if (!ddisp) return;
802 visible = &ddisp->visible;
803 middle.x = visible->left*0.5 + visible->right*0.5;
804 middle.y = visible->top*0.5 + visible->bottom*0.5;
806 scale = ((real) action)/1000.0 * DDISPLAY_NORMAL_ZOOM;
808 ddisplay_zoom(ddisp, &middle, scale / ddisp->zoom_factor);
811 void
812 view_show_cx_pts_callback(gpointer data, guint action, GtkWidget *widget)
814 DDisplay *ddisp;
815 int old_val;
817 ddisp = ddisplay_active();
818 if (!ddisp) return;
820 old_val = ddisp->show_cx_pts;
821 ddisp->show_cx_pts = GTK_CHECK_MENU_ITEM(widget)->active;
823 if (old_val != ddisp->show_cx_pts) {
824 ddisplay_add_update_all(ddisp);
825 ddisplay_flush(ddisp);
829 void
830 view_unfullscreen(void)
832 DDisplay *ddisp;
833 GtkMenuItem *item;
835 ddisp = ddisplay_active();
836 if (!ddisp) return;
838 /* find the menuitem */
839 item = menus_get_item_from_path ("<Display>/View/Fullscreen", NULL);
840 if (item && GTK_CHECK_MENU_ITEM(item)->active) {
841 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM(item), FALSE);
845 void
846 view_fullscreen_callback(gpointer data, guint action, GtkWidget *widget)
848 DDisplay *ddisp;
849 int fs;
851 ddisp = ddisplay_active();
852 if (!ddisp) return;
854 fs = GTK_CHECK_MENU_ITEM(widget)->active;
856 if (fs) /* it is already toggled */
857 gtk_window_fullscreen(GTK_WINDOW(ddisp->shell));
858 else
859 gtk_window_unfullscreen(GTK_WINDOW(ddisp->shell));
862 void
863 view_aa_callback(gpointer data, guint action, GtkWidget *widget)
865 DDisplay *ddisp;
866 int aa;
868 ddisp = ddisplay_active();
869 if (!ddisp) return;
871 aa = GTK_CHECK_MENU_ITEM(widget)->active;
873 if (aa != ddisp->aa_renderer) {
874 ddisplay_set_renderer(ddisp, aa);
875 ddisplay_add_update_all(ddisp);
876 ddisplay_flush(ddisp);
880 void
881 view_visible_grid_callback(gpointer data, guint action, GtkWidget *widget)
883 DDisplay *ddisp;
884 int old_val;
886 ddisp = ddisplay_active();
887 if (!ddisp) return;
889 old_val = ddisp->grid.visible;
890 ddisp->grid.visible = GTK_CHECK_MENU_ITEM(widget)->active;
892 if (old_val != ddisp->grid.visible) {
893 ddisplay_add_update_all(ddisp);
894 ddisplay_flush(ddisp);
898 void
899 view_snap_to_grid_callback(gpointer data, guint action, GtkWidget *widget)
901 DDisplay *ddisp;
903 ddisp = ddisplay_active();
904 if (!ddisp) return;
906 ddisplay_set_snap_to_grid(ddisp, GTK_CHECK_MENU_ITEM(widget)->active);
909 void
910 view_snap_to_objects_callback(gpointer data, guint action, GtkWidget *widget)
912 DDisplay *ddisp;
914 ddisp = ddisplay_active();
915 if (!ddisp) return;
917 ddisplay_set_snap_to_objects(ddisp, GTK_CHECK_MENU_ITEM(widget)->active);
920 void view_toggle_rulers_callback(gpointer data, guint action, GtkWidget*widget)
922 DDisplay *ddisp;
924 ddisp = ddisplay_active();
925 if (!ddisp) return;
927 /* The following is borrowed straight from the Gimp: */
929 /* This routine use promiscuous knowledge of gtk internals
930 * in order to hide and show the rulers "smoothly". This
931 * is kludgy and a hack and may break if gtk is changed
932 * internally.
934 if (!GTK_CHECK_MENU_ITEM(widget)->active) {
935 if (GTK_WIDGET_VISIBLE (ddisp->origin)) {
936 gtk_widget_unmap (ddisp->origin);
937 gtk_widget_unmap (ddisp->hrule);
938 gtk_widget_unmap (ddisp->vrule);
940 GTK_WIDGET_UNSET_FLAGS (ddisp->origin, GTK_VISIBLE);
941 GTK_WIDGET_UNSET_FLAGS (ddisp->hrule, GTK_VISIBLE);
942 GTK_WIDGET_UNSET_FLAGS (ddisp->vrule, GTK_VISIBLE);
944 gtk_widget_queue_resize (GTK_WIDGET (ddisp->origin->parent));
946 } else {
947 if (!GTK_WIDGET_VISIBLE (ddisp->origin)) {
948 GTK_WIDGET_SET_FLAGS (ddisp->origin, GTK_VISIBLE);
949 GTK_WIDGET_SET_FLAGS (ddisp->hrule, GTK_VISIBLE);
950 GTK_WIDGET_SET_FLAGS (ddisp->vrule, GTK_VISIBLE);
952 gtk_widget_map (ddisp->origin);
953 gtk_widget_map (ddisp->hrule);
954 gtk_widget_map (ddisp->vrule);
956 gtk_widget_queue_resize (GTK_WIDGET (ddisp->origin->parent));
961 extern void
962 view_new_view_callback(gpointer data, guint action, GtkWidget *widget)
964 Diagram *dia;
966 dia = ddisplay_active_diagram();
967 if (!dia) return;
969 new_display(dia);
972 void
973 view_show_all_callback(gpointer data, guint action, GtkWidget *widget)
975 DDisplay *ddisp;
976 Diagram *dia;
977 real magnify_x, magnify_y;
978 int width, height;
979 Point middle;
981 ddisp = ddisplay_active();
982 if (!ddisp) return;
983 dia = ddisp->diagram;
985 width = dia_renderer_get_width_pixels (ddisp->renderer);
986 height = dia_renderer_get_height_pixels (ddisp->renderer);
988 /* if there is something selected show that instead of all exisiting objects */
989 if (dia->data->selected) {
990 GList *list = dia->data->selected;
991 Rectangle extents = ((DiaObject*)list->data)->bounding_box;
992 list = g_list_next(list);
993 while (list) {
994 DiaObject *obj = (DiaObject *)list->data;
995 rectangle_union(&extents, &(obj->bounding_box));
996 list = g_list_next(list);
998 magnify_x = (real)width / (extents.right - extents.left) / ddisp->zoom_factor;
999 magnify_y = (real)height / (extents.bottom - extents.top) / ddisp->zoom_factor;
1000 middle.x = extents.left + (extents.right - extents.left) / 2.0;
1001 middle.y = extents.top + (extents.bottom - extents.top) / 2.0;
1002 } else {
1003 magnify_x = (real)width /
1004 (dia->data->extents.right - dia->data->extents.left) / ddisp->zoom_factor;
1005 magnify_y = (real)height /
1006 (dia->data->extents.bottom - dia->data->extents.top) / ddisp->zoom_factor;
1008 middle.x = dia->data->extents.left +
1009 (dia->data->extents.right - dia->data->extents.left) / 2.0;
1010 middle.y = dia->data->extents.top +
1011 (dia->data->extents.bottom - dia->data->extents.top) / 2.0;
1014 ddisplay_zoom (ddisp, &middle,
1015 ((magnify_x<magnify_y)?magnify_x:magnify_y)/1.05);
1017 ddisplay_update_scrollbars(ddisp);
1018 ddisplay_add_update_all(ddisp);
1019 ddisplay_flush(ddisp);
1022 void
1023 view_redraw_callback(gpointer data, guint action, GtkWidget *widget)
1025 DDisplay *ddisp;
1026 ddisp = ddisplay_active();
1027 if (!ddisp) return;
1028 ddisplay_add_update_all(ddisp);
1029 ddisplay_flush(ddisp);
1032 void
1033 view_diagram_properties_callback(gpointer data, guint action, GtkWidget *widget)
1035 DDisplay *ddisp;
1037 ddisp = ddisplay_active();
1038 if (!ddisp) return;
1039 diagram_properties_show(ddisp->diagram);
1043 void
1044 objects_place_over_callback(gpointer data, guint action, GtkWidget *widget)
1046 diagram_place_over_selected(ddisplay_active_diagram());
1049 void
1050 objects_place_under_callback(gpointer data, guint action, GtkWidget *widget)
1052 diagram_place_under_selected(ddisplay_active_diagram());
1055 void
1056 objects_place_up_callback(gpointer data, guint action, GtkWidget *widget)
1058 diagram_place_up_selected(ddisplay_active_diagram());
1061 void
1062 objects_place_down_callback(gpointer data, guint action, GtkWidget *widget)
1064 diagram_place_down_selected(ddisplay_active_diagram());
1067 void
1068 objects_parent_callback(gpointer data, guint action, GtkWidget *widget)
1070 diagram_parent_selected(ddisplay_active_diagram());
1073 void
1074 objects_unparent_callback(gpointer data, guint action, GtkWidget *widget)
1076 diagram_unparent_selected(ddisplay_active_diagram());
1079 void
1080 objects_unparent_children_callback(gpointer data, guint action, GtkWidget *widget)
1082 diagram_unparent_children_selected(ddisplay_active_diagram());
1085 void
1086 objects_group_callback(gpointer data, guint action, GtkWidget *widget)
1088 DDisplay *ddisp;
1090 ddisp = ddisplay_active();
1091 if (!ddisp) return;
1092 diagram_group_selected(ddisplay_active_diagram());
1093 ddisplay_do_update_menu_sensitivity(ddisp);
1096 void
1097 objects_ungroup_callback(gpointer data, guint action, GtkWidget *widget)
1099 DDisplay *ddisp;
1101 ddisp = ddisplay_active();
1102 if (!ddisp) return;
1103 diagram_ungroup_selected(ddisplay_active_diagram());
1104 ddisplay_do_update_menu_sensitivity(ddisp);
1107 void
1108 dialogs_properties_callback(gpointer data, guint action, GtkWidget *widget)
1110 Diagram *dia;
1111 DiaObject *selected;
1113 dia = ddisplay_active_diagram();
1114 if (!dia) return;
1116 if (dia->data->selected != NULL) {
1117 selected = dia->data->selected->data;
1118 properties_show(dia, selected);
1119 } else {
1120 diagram_properties_show(dia);
1124 void
1125 dialogs_layers_callback(gpointer data, guint action, GtkWidget *widget)
1127 layer_dialog_set_diagram(ddisplay_active_diagram());
1128 layer_dialog_show();
1132 void
1133 objects_align_h_callback(gpointer data, guint action, GtkWidget *widget)
1135 int align;
1136 Diagram *dia;
1137 GList *objects;
1139 align = action;
1141 dia = ddisplay_active_diagram();
1142 if (!dia) return;
1143 objects = dia->data->selected;
1145 object_add_updates_list(objects, dia);
1146 object_list_align_h(objects, dia, align);
1147 diagram_update_connections_selection(dia);
1148 object_add_updates_list(objects, dia);
1149 diagram_modified(dia);
1150 diagram_flush(dia);
1152 undo_set_transactionpoint(dia->undo);
1155 void
1156 objects_align_v_callback(gpointer data, guint action, GtkWidget *widget)
1158 int align;
1159 Diagram *dia;
1160 GList *objects;
1162 align = action;
1164 dia = ddisplay_active_diagram();
1165 if (!dia) return;
1166 objects = dia->data->selected;
1168 object_add_updates_list(objects, dia);
1169 object_list_align_v(objects, dia, align);
1170 diagram_update_connections_selection(dia);
1171 object_add_updates_list(objects, dia);
1172 diagram_modified(dia);
1173 diagram_flush(dia);
1175 undo_set_transactionpoint(dia->undo);