linewidth is now working for PS_SOLID
[dia.git] / app / commands.c
blob6533bd4e195d0446847a1282220f32bdd95ab25a
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 ddisplay_close(ddisplay_active());
126 void
127 file_new_callback(gpointer data, guint action, GtkWidget *widget)
129 Diagram *dia;
130 DDisplay *ddisp;
131 static int untitled_nr = 1;
132 char buffer[24];
134 g_snprintf(buffer, 24, _("Diagram%d.dia"), untitled_nr++);
136 dia = new_diagram(buffer);
137 ddisp = new_display(dia);
138 diagram_tree_add(diagram_tree(), dia);
141 void
142 file_preferences_callback(gpointer data, guint action, GtkWidget *widget)
144 prefs_show();
148 void
149 edit_copy_callback(gpointer data, guint action, GtkWidget *widget)
151 GList *copy_list;
152 DDisplay *ddisp;
154 ddisp = ddisplay_active();
155 if (!ddisp) return;
156 copy_list = parent_list_affected(diagram_get_sorted_selected(ddisp->diagram));
158 cnp_store_objects(object_copy_list(copy_list));
159 g_list_free(copy_list);
161 ddisplay_do_update_menu_sensitivity(ddisp);
164 void
165 edit_cut_callback(gpointer data, guint action, GtkWidget *widget)
167 GList *cut_list;
168 DDisplay *ddisp;
169 Change *change;
171 ddisp = ddisplay_active();
172 if (!ddisp) return;
174 diagram_selected_break_external(ddisp->diagram);
176 cut_list = parent_list_affected(diagram_get_sorted_selected(ddisp->diagram));
178 cnp_store_objects(object_copy_list(cut_list));
180 change = undo_delete_objects_children(ddisp->diagram, cut_list);
181 (change->apply)(change, ddisp->diagram);
183 ddisplay_do_update_menu_sensitivity(ddisp);
184 diagram_flush(ddisp->diagram);
187 diagram_modified(ddisp->diagram);
188 undo_set_transactionpoint(ddisp->diagram->undo);
192 void
193 edit_paste_callback(gpointer data, guint action, GtkWidget *widget)
195 GList *paste_list;
196 DDisplay *ddisp;
197 Point paste_corner;
198 Point delta;
199 Change *change;
201 ddisp = ddisplay_active();
202 if (!ddisp) return;
204 if (!cnp_exist_stored_objects()) {
205 message_warning(_("No existing object to paste.\n"));
206 return;
209 paste_list = cnp_get_stored_objects(); /* Gets a copy */
211 paste_corner = object_list_corner(paste_list);
213 delta.x = ddisp->visible.left - paste_corner.x;
214 delta.y = ddisp->visible.top - paste_corner.y;
216 /* Move down some 10% of the visible area. */
217 delta.x += (ddisp->visible.right - ddisp->visible.left)*0.1;
218 delta.y += (ddisp->visible.bottom - ddisp->visible.top)*0.1;
220 object_list_move_delta(paste_list, &delta);
222 change = undo_insert_objects(ddisp->diagram, paste_list, 0);
223 (change->apply)(change, ddisp->diagram);
225 diagram_modified(ddisp->diagram);
226 undo_set_transactionpoint(ddisp->diagram->undo);
228 diagram_remove_all_selected(ddisp->diagram, TRUE);
229 diagram_select_list(ddisp->diagram, paste_list);
231 diagram_flush(ddisp->diagram);
235 * ALAN: Paste should probably paste to different position, feels
236 * wrong somehow. ALAN: The offset should increase a little each time
237 * if you paste/duplicate several times in a row, because it is
238 * clearer what is happening than if you were to piling them all in
239 * one place.
241 * completely untested, basically it is copy+paste munged together
243 void
244 edit_duplicate_callback(gpointer data, guint action, GtkWidget *widget)
246 GList *duplicate_list;
247 DDisplay *ddisp;
248 Point duplicate_corner;
249 Point delta;
250 Change *change;
252 ddisp = ddisplay_active();
253 if (!ddisp) return;
254 duplicate_list = object_copy_list(diagram_get_sorted_selected(ddisp->diagram));
255 duplicate_corner = object_list_corner(duplicate_list);
257 /* Move down some 10% of the visible area. */
258 delta.x = (ddisp->visible.right - ddisp->visible.left)*0.05;
259 delta.y = (ddisp->visible.bottom - ddisp->visible.top)*0.05;
261 object_list_move_delta(duplicate_list, &delta);
263 change = undo_insert_objects(ddisp->diagram, duplicate_list, 0);
264 (change->apply)(change, ddisp->diagram);
266 diagram_modified(ddisp->diagram);
267 undo_set_transactionpoint(ddisp->diagram->undo);
269 diagram_remove_all_selected(ddisp->diagram, TRUE);
270 diagram_select_list(ddisp->diagram, duplicate_list);
272 diagram_flush(ddisp->diagram);
274 ddisplay_do_update_menu_sensitivity(ddisp);
280 /* Signal handler for getting the clipboard contents */
281 /* Note that the clipboard is for M$-style cut/copy/paste copying, while
282 the selection is for Unix-style mark-and-copy. We can't really do
283 mark-and-copy.
286 static void
287 insert_text(DDisplay *ddisp, Focus *focus, const gchar *text)
289 ObjectChange *change = NULL;
290 int modified = FALSE, any_modified = FALSE;
291 DiaObject *obj = focus->obj;
293 while (text != NULL) {
294 gchar *next_line = g_utf8_strchr(text, -1, '\n');
295 if (next_line != text) {
296 gint len = g_utf8_strlen(text, (next_line-text));
297 modified = (*focus->key_event)(focus, GDK_A, text, len, &change);
299 if (next_line != NULL) {
300 modified = (*focus->key_event)(focus, GDK_Return, "\n", 1, &change);
301 text = g_utf8_next_char(next_line);
302 } else {
303 text = NULL;
305 { /* Make sure object updates its data: */
306 Point p = obj->position;
307 (obj->ops->move)(obj,&p); }
309 /* Perhaps this can be improved */
310 object_add_updates(obj, ddisp->diagram);
312 if (modified && (change != NULL)) {
313 undo_object_change(ddisp->diagram, obj, change);
314 any_modified = TRUE;
317 diagram_flush(ddisp->diagram);
320 if (any_modified) {
321 diagram_modified(ddisp->diagram);
322 undo_set_transactionpoint(ddisp->diagram->undo);
327 static void
328 received_clipboard_handler(GtkClipboard *clipboard,
329 const gchar *text,
330 gpointer data) {
331 Focus *focus = active_focus();
332 DDisplay *ddisp = (DDisplay *)data;
334 if (text == NULL) return;
336 if ((focus == NULL) || (!focus->has_focus)) return;
338 if (!g_utf8_validate(text, -1, NULL)) {
339 message_error("Not valid UTF8");
340 return;
343 insert_text(ddisp, focus, text);
346 static PropDescription text_prop_singleton_desc[] = {
347 { "text", PROP_TYPE_TEXT },
348 PROP_DESC_END};
350 static void
351 make_text_prop_singleton(GPtrArray **props, TextProperty **prop)
353 *props = prop_list_from_descs(text_prop_singleton_desc,pdtpp_true);
354 g_assert((*props)->len == 1);
356 *prop = g_ptr_array_index((*props),0);
357 g_free((*prop)->text_data);
358 (*prop)->text_data = NULL;
362 void
363 edit_copy_text_callback(gpointer data, guint action, GtkWidget *widget)
365 Focus *focus = active_focus();
366 DDisplay *ddisp;
367 DiaObject *obj;
368 GPtrArray *textprops;
369 TextProperty *prop;
371 if ((focus == NULL) || (!focus->has_focus)) return;
373 ddisp = ddisplay_active();
374 if (!ddisp) return;
376 obj = focus->obj;
378 if (obj->ops->get_props == NULL)
379 return;
381 make_text_prop_singleton(&textprops,&prop);
382 /* Get the first text property */
383 obj->ops->get_props(obj, textprops);
385 /* GTK docs claim the selection clipboard is ignored on Win32.
386 * The "clipboard" clipboard is mostly ignored in Unix
388 #ifdef G_OS_WIN32
389 gtk_clipboard_set_text(gtk_clipboard_get(GDK_NONE),
390 prop->text_data, -1);
391 #else
392 gtk_clipboard_set_text(gtk_clipboard_get(GDK_SELECTION_PRIMARY),
393 prop->text_data, -1);
394 #endif
395 prop_list_free(textprops);
398 void
399 edit_cut_text_callback(gpointer data, guint action, GtkWidget *widget)
401 Focus *focus = active_focus();
402 DDisplay *ddisp;
403 DiaObject *obj;
404 Text *text;
405 GPtrArray *textprops;
406 TextProperty *prop;
407 ObjectChange *change;
409 if ((focus == NULL) || (!focus->has_focus)) return;
411 ddisp = ddisplay_active();
412 if (!ddisp) return;
414 obj = focus->obj;
415 text = (Text *)focus->user_data;
417 if (obj->ops->get_props == NULL)
418 return;
420 make_text_prop_singleton(&textprops,&prop);
421 /* Get the first text property */
422 obj->ops->get_props(obj, textprops);
424 /* GTK docs claim the selection clipboard is ignored on Win32.
425 * The "clipboard" clipboard is mostly ignored in Unix
427 #ifdef G_OS_WIN32
428 gtk_clipboard_set_text(gtk_clipboard_get(GDK_NONE),
429 prop->text_data, -1);
430 #else
431 gtk_clipboard_set_text(gtk_clipboard_get(GDK_SELECTION_PRIMARY),
432 prop->text_data, -1);
433 #endif
435 prop_list_free(textprops);
437 if (text_delete_all(text, &change)) {
438 object_add_updates(obj, ddisp->diagram);
439 undo_object_change(ddisp->diagram, obj, change);
440 undo_set_transactionpoint(ddisp->diagram->undo);
441 diagram_modified(ddisp->diagram);
442 diagram_flush(ddisp->diagram);
446 void
447 edit_paste_text_callback(gpointer data, guint action, GtkWidget *widget)
449 DDisplay *ddisp;
451 ddisp = ddisplay_active();
452 if (!ddisp) return;
454 #ifdef G_OS_WIN32
455 gtk_clipboard_request_text(gtk_clipboard_get(GDK_NONE),
456 received_clipboard_handler, ddisp);
457 #else
458 gtk_clipboard_request_text(gtk_clipboard_get(GDK_SELECTION_PRIMARY),
459 received_clipboard_handler, ddisp);
460 #endif
463 void
464 edit_delete_callback(gpointer data, guint action, GtkWidget *widget)
466 GList *delete_list;
467 GList *ptr;
468 DDisplay *ddisp;
470 Change *change;
472 ddisp = ddisplay_active();
473 if (!ddisp) return;
475 diagram_selected_break_external(ddisp->diagram);
477 delete_list = diagram_get_sorted_selected(ddisp->diagram);
478 change = undo_delete_objects_children(ddisp->diagram, delete_list);
479 (change->apply)(change, ddisp->diagram);
480 g_list_free(delete_list);
482 diagram_modified(ddisp->diagram);
484 ddisplay_do_update_menu_sensitivity(ddisp);
485 diagram_flush(ddisp->diagram);
487 undo_set_transactionpoint(ddisp->diagram->undo);
490 void
491 edit_undo_callback(gpointer data, guint action, GtkWidget *widget)
493 Diagram *dia;
495 dia = ddisplay_active_diagram();
496 if (!dia) return;
498 undo_revert_to_last_tp(dia->undo);
499 diagram_modified(dia);
501 diagram_flush(dia);
504 void
505 edit_redo_callback(gpointer data, guint action, GtkWidget *widget)
507 Diagram *dia;
509 dia = ddisplay_active_diagram();
510 if (!dia) return;
512 undo_apply_to_next_tp(dia->undo);
513 diagram_modified(dia);
515 diagram_flush(dia);
518 void
519 help_manual_callback(gpointer data, guint action, GtkWidget *widget)
521 char *helpdir, *helpindex = NULL, *command;
522 guint bestscore = G_MAXINT;
523 GDir *dp;
524 const char *dentry;
525 GError *error = NULL;
527 helpdir = dia_get_data_directory("help");
528 if (!helpdir) {
529 message_warning(_("Could not find help directory"));
530 return;
533 /* search through helpdir for the helpfile that matches the user's locale */
534 dp = g_dir_open (helpdir, 0, &error);
535 if (!dp) {
536 message_warning(_("Could not open help directory:\n%s"),
537 error->message);
538 g_error_free (error);
539 return;
542 while ((dentry = g_dir_read_name(dp)) != NULL) {
543 guint score;
545 score = intl_score_locale(dentry);
546 if (score < bestscore) {
547 if (helpindex)
548 g_free(helpindex);
549 #ifdef G_OS_WIN32
550 /* use HTML Help on win32 if available */
551 helpindex = g_strconcat(helpdir, G_DIR_SEPARATOR_S, dentry,
552 G_DIR_SEPARATOR_S "dia-manual.chm", NULL);
553 if (!g_file_test(helpindex, G_FILE_TEST_EXISTS)) {
554 helpindex = g_strconcat(helpdir, G_DIR_SEPARATOR_S, dentry,
555 G_DIR_SEPARATOR_S "index.html", NULL);
557 #else
558 helpindex = g_strconcat(helpdir, G_DIR_SEPARATOR_S, dentry,
559 G_DIR_SEPARATOR_S "index.html", NULL);
560 #endif
561 bestscore = score;
564 g_dir_close (dp);
565 g_free(helpdir);
566 if (!helpindex) {
567 message_warning(_("Could not find help directory"));
568 return;
571 #ifdef G_OS_WIN32
572 #define SW_SHOWNORMAL 1
573 ShellExecuteA (0, "open", helpindex, NULL, helpdir, SW_SHOWNORMAL);
574 #else
575 command = getenv("BROWSER");
576 command = g_strdup_printf("%s 'file://%s' &", command ? command : "netscape", helpindex);
577 system(command);
578 g_free(command);
579 #endif
581 g_free(helpindex);
584 void
585 help_about_callback(gpointer data, guint action, GtkWidget *widget)
587 #ifdef GNOME
589 /* Take advantage of gnome_about_new(),
590 * which is much cleaner and GNOME2 HIG compliant,
591 * Originally implemented by Xing Wang, modified
592 * by Andrew Ferrier.
594 * Note: in this function there is no need to discriminate
595 * between the different kinds of 'authors'.
598 static GtkWidget *about;
601 * Translators should localize the following string
602 * which will give them credit in the About box.
603 * E.g. "Fulano de Tal <fulano@detal.com>"
606 gchar *translators = _("translator_credits-PLEASE_ADD_YOURSELF_HERE");
607 gchar logo_file[100];
609 if (!about) {
610 GdkPixbuf *logo;
612 gchar* datadir = dia_get_data_directory("");
613 g_snprintf(logo_file, sizeof(logo_file),
614 "%s%sdia_logo.png", datadir, G_DIR_SEPARATOR_S);
616 logo = gdk_pixbuf_new_from_file(logo_file, NULL);
617 g_free(datadir);
619 about = gnome_about_new(
620 _("Dia"),
621 VERSION,
622 _("Copyright (C) 1998-2002 The Free Software Foundation and the authors"),
623 _("Dia is a program for drawing structured diagrams.\n"
624 "Please visit http://www.gnome.org/projects/dia for more information."),
625 authors,
626 documentors,
627 (strcmp (translators, "translator_credits-PLEASE_ADD_YOURSELF_HERE")
628 ? translators : NULL),
629 logo);
631 if (logo)
632 g_object_unref (logo);
634 g_signal_connect (about, "destroy",
635 G_CALLBACK (gtk_widget_destroyed),
636 &about);
639 gtk_widget_show_now (about);
641 #else
643 /* No GNOME, fall back to the old GTK method */
645 const gint nauthors = (sizeof(authors) / sizeof(authors[0])) - 1;
646 const gint ndocumentors = (sizeof(documentors) / sizeof(documentors[0])) - 1;
648 GtkWidget *dialog;
649 GtkWidget *vbox;
650 GtkWidget *table;
651 GtkWidget *bbox;
652 GtkWidget *frame;
653 GtkWidget *label;
654 GtkWidget *button;
655 char str[100];
656 gint i;
658 GtkWidget *gpixmap;
660 dialog = gtk_dialog_new ();
661 gtk_window_set_role (GTK_WINDOW (dialog), "about_dialog");
662 gtk_window_set_title (GTK_WINDOW (dialog), _("About Dia"));
663 gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
664 gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER);
665 g_signal_connect (GTK_OBJECT (dialog), "destroy",
666 G_CALLBACK (gtk_widget_destroy),
667 GTK_OBJECT (dialog));
669 vbox = gtk_vbox_new (FALSE, 1);
670 gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
671 gtk_container_add (GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), vbox);
673 if (!logo) {
674 gchar* datadir = dia_get_data_directory("");
675 g_snprintf(str, sizeof(str), "%s%sdia_logo.png", datadir, G_DIR_SEPARATOR_S);
676 logo = gdk_pixbuf_new_from_file(str, NULL);
677 g_free(datadir);
680 if (logo) {
681 GdkPixmap *pixmap;
682 GdkBitmap *bitmap;
684 frame = gtk_frame_new (NULL);
685 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
686 gtk_container_set_border_width (GTK_CONTAINER (frame), 1);
687 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, TRUE, 1);
689 gdk_pixbuf_render_pixmap_and_mask(logo, &pixmap, &bitmap, 128);
690 gpixmap = gtk_pixmap_new(pixmap, bitmap);
691 gdk_pixmap_unref(pixmap);
692 if (bitmap) gdk_bitmap_unref(bitmap);
693 gtk_container_add (GTK_CONTAINER(frame), gpixmap);
696 frame = gtk_frame_new (NULL);
697 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
698 gtk_container_set_border_width (GTK_CONTAINER (frame), 1);
699 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, TRUE, 1);
701 table = gtk_table_new(3, 2, FALSE);
702 gtk_container_set_border_width (GTK_CONTAINER (table), 1);
703 gtk_container_add (GTK_CONTAINER (frame), table);
705 g_snprintf(str, sizeof(str), _("Dia v %s by Alexander Larsson"), VERSION);
706 label = gtk_label_new (str);
707 gtk_table_attach(GTK_TABLE(table), label, 0,2, 0,1,
708 GTK_FILL|GTK_EXPAND, GTK_FILL, 0,2);
710 /* Exact spelling is Ch&eacute;p&eacute;lov (using *ML entities) */
711 label = gtk_label_new(_("Maintainers: Lars Clausen and Cyrille Chepelov"));
712 gtk_table_attach(GTK_TABLE(table), label, 0,2, 1,2,
713 GTK_FILL|GTK_EXPAND, GTK_FILL, 0,2);
715 label = gtk_label_new (_("Please visit http://www.gnome.org/projects/dia "
716 "for more information"));
717 gtk_table_attach(GTK_TABLE(table), label, 0,2, 2,3,
718 GTK_FILL|GTK_EXPAND, GTK_FILL, 0,2);
720 label = gtk_label_new (_("Contributors:"));
721 gtk_table_attach(GTK_TABLE(table), label, 0,2, 3,4,
722 GTK_FILL|GTK_EXPAND, GTK_FILL, 0,2);
724 for (i = 0; i < nauthors; i++) {
725 label = gtk_label_new(authors[i]);
726 gtk_table_attach(GTK_TABLE(table), label, i%2,i%2+1, i/2+4,i/2+5,
727 GTK_FILL|GTK_EXPAND, GTK_FILL, 0,0);
730 for (i = nauthors; i < nauthors + ndocumentors; i++) {
731 label = gtk_label_new(documentors[i - nauthors]);
732 gtk_table_attach(GTK_TABLE(table), label, i%2,i%2+1, i/2+4,i/2+5,
733 GTK_FILL|GTK_EXPAND, GTK_FILL, 0,0);
736 gtk_table_set_col_spacings(GTK_TABLE(table), 1);
737 gtk_table_set_row_spacings(GTK_TABLE(table), 1);
739 bbox = gtk_hbutton_box_new();
740 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), bbox, TRUE, TRUE, 5);
741 gtk_button_box_set_child_size(GTK_BUTTON_BOX(bbox), 80, 0);
742 gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 10);
744 button = gtk_button_new_from_stock(GTK_STOCK_OK);
745 gtk_container_add(GTK_CONTAINER(bbox), button);
746 g_signal_connect_swapped(GTK_OBJECT (button), "clicked",
747 G_CALLBACK(gtk_widget_destroy),
748 GTK_OBJECT(dialog));
750 gtk_widget_show_all (dialog);
752 #endif /* GNOME */
755 void
756 view_zoom_in_callback(gpointer data, guint action, GtkWidget *widget)
758 DDisplay *ddisp;
759 Point middle;
760 Rectangle *visible;
762 ddisp = ddisplay_active();
763 if (!ddisp) return;
764 visible = &ddisp->visible;
765 middle.x = visible->left*0.5 + visible->right*0.5;
766 middle.y = visible->top*0.5 + visible->bottom*0.5;
768 ddisplay_zoom(ddisp, &middle, M_SQRT2);
771 void
772 view_zoom_out_callback(gpointer data, guint action, GtkWidget *widget)
774 DDisplay *ddisp;
775 Point middle;
776 Rectangle *visible;
778 ddisp = ddisplay_active();
779 if (!ddisp) return;
780 visible = &ddisp->visible;
781 middle.x = visible->left*0.5 + visible->right*0.5;
782 middle.y = visible->top*0.5 + visible->bottom*0.5;
784 ddisplay_zoom(ddisp, &middle, M_SQRT1_2);
787 void
788 view_zoom_set_callback(gpointer data, guint action, GtkWidget *widget)
790 DDisplay *ddisp;
791 real scale;
792 Point middle;
793 Rectangle *visible;
795 ddisp = ddisplay_active();
796 if (!ddisp) return;
797 visible = &ddisp->visible;
798 middle.x = visible->left*0.5 + visible->right*0.5;
799 middle.y = visible->top*0.5 + visible->bottom*0.5;
801 scale = ((real) action)/1000.0 * DDISPLAY_NORMAL_ZOOM;
803 ddisplay_zoom(ddisp, &middle, scale / ddisp->zoom_factor);
806 void
807 view_show_cx_pts_callback(gpointer data, guint action, GtkWidget *widget)
809 DDisplay *ddisp;
810 int old_val;
812 ddisp = ddisplay_active();
813 if (!ddisp) return;
815 old_val = ddisp->show_cx_pts;
816 ddisp->show_cx_pts = GTK_CHECK_MENU_ITEM(widget)->active;
818 if (old_val != ddisp->show_cx_pts) {
819 ddisplay_add_update_all(ddisp);
820 ddisplay_flush(ddisp);
824 void
825 view_aa_callback(gpointer data, guint action, GtkWidget *widget)
827 DDisplay *ddisp;
828 int aa;
830 ddisp = ddisplay_active();
831 if (!ddisp) return;
833 aa = GTK_CHECK_MENU_ITEM(widget)->active;
835 if (aa != ddisp->aa_renderer) {
836 ddisplay_set_renderer(ddisp, aa);
837 ddisplay_add_update_all(ddisp);
838 ddisplay_flush(ddisp);
842 void
843 view_visible_grid_callback(gpointer data, guint action, GtkWidget *widget)
845 DDisplay *ddisp;
846 int old_val;
848 ddisp = ddisplay_active();
849 if (!ddisp) return;
851 old_val = ddisp->grid.visible;
852 ddisp->grid.visible = GTK_CHECK_MENU_ITEM(widget)->active;
854 if (old_val != ddisp->grid.visible) {
855 ddisplay_add_update_all(ddisp);
856 ddisplay_flush(ddisp);
860 void
861 view_snap_to_grid_callback(gpointer data, guint action, GtkWidget *widget)
863 DDisplay *ddisp;
865 ddisp = ddisplay_active();
866 if (!ddisp) return;
868 ddisplay_set_snap_to_grid(ddisp, GTK_CHECK_MENU_ITEM(widget)->active);
871 void view_toggle_rulers_callback(gpointer data, guint action, GtkWidget*widget)
873 DDisplay *ddisp;
875 ddisp = ddisplay_active();
876 if (!ddisp) return;
878 /* The following is borrowed straight from the Gimp: */
880 /* This routine use promiscuous knowledge of gtk internals
881 * in order to hide and show the rulers "smoothly". This
882 * is kludgy and a hack and may break if gtk is changed
883 * internally.
885 if (!GTK_CHECK_MENU_ITEM(widget)->active) {
886 if (GTK_WIDGET_VISIBLE (ddisp->origin)) {
887 gtk_widget_unmap (ddisp->origin);
888 gtk_widget_unmap (ddisp->hrule);
889 gtk_widget_unmap (ddisp->vrule);
891 GTK_WIDGET_UNSET_FLAGS (ddisp->origin, GTK_VISIBLE);
892 GTK_WIDGET_UNSET_FLAGS (ddisp->hrule, GTK_VISIBLE);
893 GTK_WIDGET_UNSET_FLAGS (ddisp->vrule, GTK_VISIBLE);
895 gtk_widget_queue_resize (GTK_WIDGET (ddisp->origin->parent));
897 } else {
898 if (!GTK_WIDGET_VISIBLE (ddisp->origin)) {
899 GTK_WIDGET_SET_FLAGS (ddisp->origin, GTK_VISIBLE);
900 GTK_WIDGET_SET_FLAGS (ddisp->hrule, GTK_VISIBLE);
901 GTK_WIDGET_SET_FLAGS (ddisp->vrule, GTK_VISIBLE);
903 gtk_widget_map (ddisp->origin);
904 gtk_widget_map (ddisp->hrule);
905 gtk_widget_map (ddisp->vrule);
907 gtk_widget_queue_resize (GTK_WIDGET (ddisp->origin->parent));
912 extern void
913 view_new_view_callback(gpointer data, guint action, GtkWidget *widget)
915 Diagram *dia;
917 dia = ddisplay_active_diagram();
918 if (!dia) return;
920 new_display(dia);
923 void
924 view_show_all_callback(gpointer data, guint action, GtkWidget *widget)
926 DDisplay *ddisp;
927 Diagram *dia;
928 real magnify_x, magnify_y;
929 int width, height;
930 Point middle;
932 ddisp = ddisplay_active();
933 if (!ddisp) return;
934 dia = ddisp->diagram;
936 width = dia_renderer_get_width_pixels (ddisp->renderer);
937 height = dia_renderer_get_height_pixels (ddisp->renderer);
939 magnify_x = (real)width /
940 (dia->data->extents.right - dia->data->extents.left) / ddisp->zoom_factor;
941 magnify_y = (real)height /
942 (dia->data->extents.bottom - dia->data->extents.top) / ddisp->zoom_factor;
944 middle.x = dia->data->extents.left +
945 (dia->data->extents.right - dia->data->extents.left) / 2.0;
946 middle.y = dia->data->extents.top +
947 (dia->data->extents.bottom - dia->data->extents.top) / 2.0;
949 ddisplay_zoom (ddisp, &middle, (magnify_x<magnify_y)?magnify_x:magnify_y);
951 ddisplay_update_scrollbars(ddisp);
952 ddisplay_add_update_all(ddisp);
953 ddisplay_flush(ddisp);
956 void
957 view_redraw_callback(gpointer data, guint action, GtkWidget *widget)
959 DDisplay *ddisp;
960 ddisp = ddisplay_active();
961 if (!ddisp) return;
962 ddisplay_add_update_all(ddisp);
963 ddisplay_flush(ddisp);
966 void
967 view_diagram_properties_callback(gpointer data, guint action, GtkWidget *widget)
969 DDisplay *ddisp;
971 ddisp = ddisplay_active();
972 if (!ddisp) return;
973 diagram_properties_show(ddisp->diagram);
977 void
978 objects_place_over_callback(gpointer data, guint action, GtkWidget *widget)
980 diagram_place_over_selected(ddisplay_active_diagram());
983 void
984 objects_place_under_callback(gpointer data, guint action, GtkWidget *widget)
986 diagram_place_under_selected(ddisplay_active_diagram());
989 void
990 objects_place_up_callback(gpointer data, guint action, GtkWidget *widget)
992 diagram_place_up_selected(ddisplay_active_diagram());
995 void
996 objects_place_down_callback(gpointer data, guint action, GtkWidget *widget)
998 diagram_place_down_selected(ddisplay_active_diagram());
1001 void
1002 objects_parent_callback(gpointer data, guint action, GtkWidget *widget)
1004 diagram_parent_selected(ddisplay_active_diagram());
1007 void
1008 objects_unparent_callback(gpointer data, guint action, GtkWidget *widget)
1010 diagram_unparent_selected(ddisplay_active_diagram());
1013 void
1014 objects_unparent_children_callback(gpointer data, guint action, GtkWidget *widget)
1016 diagram_unparent_children_selected(ddisplay_active_diagram());
1019 void
1020 objects_group_callback(gpointer data, guint action, GtkWidget *widget)
1022 diagram_group_selected(ddisplay_active_diagram());
1025 void
1026 objects_ungroup_callback(gpointer data, guint action, GtkWidget *widget)
1028 diagram_ungroup_selected(ddisplay_active_diagram());
1031 void
1032 dialogs_properties_callback(gpointer data, guint action, GtkWidget *widget)
1034 Diagram *dia;
1035 DiaObject *selected;
1037 dia = ddisplay_active_diagram();
1038 if (!dia) return;
1040 if (dia->data->selected != NULL) {
1041 selected = dia->data->selected->data;
1042 properties_show(dia, selected);
1043 } else {
1044 diagram_properties_show(dia);
1048 void
1049 dialogs_layers_callback(gpointer data, guint action, GtkWidget *widget)
1051 layer_dialog_set_diagram(ddisplay_active_diagram());
1052 layer_dialog_show();
1056 void
1057 objects_align_h_callback(gpointer data, guint action, GtkWidget *widget)
1059 int align;
1060 Diagram *dia;
1061 GList *objects;
1063 align = action;
1065 dia = ddisplay_active_diagram();
1066 if (!dia) return;
1067 objects = dia->data->selected;
1069 object_add_updates_list(objects, dia);
1070 object_list_align_h(objects, dia, align);
1071 diagram_update_connections_selection(dia);
1072 object_add_updates_list(objects, dia);
1073 diagram_modified(dia);
1074 diagram_flush(dia);
1076 undo_set_transactionpoint(dia->undo);
1079 void
1080 objects_align_v_callback(gpointer data, guint action, GtkWidget *widget)
1082 int align;
1083 Diagram *dia;
1084 GList *objects;
1086 align = action;
1088 dia = ddisplay_active_diagram();
1089 if (!dia) return;
1090 objects = dia->data->selected;
1092 object_add_updates_list(objects, dia);
1093 object_list_align_v(objects, dia, align);
1094 diagram_update_connections_selection(dia);
1095 object_add_updates_list(objects, dia);
1096 diagram_modified(dia);
1097 diagram_flush(dia);
1099 undo_set_transactionpoint(dia->undo);