1 /* Dia -- an diagram creation/manipulation program
2 * Copyright (C) 1998 Alexander Larsson
3 *
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.
8 *
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.
13 *
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.
17 */
18
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
22
23 #include <string.h>
24 #include <stdio.h>
25 #include <math.h>
26
27 #ifdef GNOME
28 #undef GTK_DISABLE_DEPRECATED
29 #include <gnome.h>
30 #endif
31
32 #include <gdk/gdkkeysyms.h>
33
34 #include "intl.h"
35
36 #include "display.h"
37 #include "group.h"
38 #include "interface.h"
39 #include "focus.h"
40 #include "color.h"
41 #include "object.h"
42 #include "handle_ops.h"
43 #include "connectionpoint_ops.h"
44 #include "menus.h"
45 #include "cut_n_paste.h"
46 #include "message.h"
47 #include "preferences.h"
48 #include "app_procs.h"
49 #include "layer_dialog.h"
50 #include "load_save.h"
51 #include "dia-props.h"
52 #include "render_gdk.h"
53 #include "diatransform.h"
54
55 static GHashTable *display_ht = NULL;
56 static GdkCursor *current_cursor = NULL;
57
58 GdkCursor *default_cursor = NULL;
59
60 static DDisplay *active_display = NULL;
61
62
63 typedef struct _IRectangle {
64 int top, bottom;
65 int left,right;
66 } IRectangle;
67
68 static guint display_hash(DDisplay *ddisp);
69
70 static void
update_zoom_status(DDisplay * ddisp)71 update_zoom_status(DDisplay *ddisp)
72 {
73 gchar* zoom_text;
74
75 if (is_integrated_ui ())
76 {
77 zoom_text = g_strdup_printf("%.0f%%",
78 ddisp->zoom_factor * 100.0 / DDISPLAY_NORMAL_ZOOM);
79
80 integrated_ui_toolbar_set_zoom_text (ddisp->common_toolbar, zoom_text);
81 }
82 else
83 {
84 GtkWidget *zoomcombo;
85 zoom_text = g_strdup_printf("%.1f%%",
86 ddisp->zoom_factor * 100.0 / DDISPLAY_NORMAL_ZOOM);
87 zoomcombo = ddisp->zoom_status;
88 gtk_entry_set_text(GTK_ENTRY (g_object_get_data (G_OBJECT(zoomcombo), "user_data")),
89 zoom_text);
90 }
91
92 g_free(zoom_text); /* Copied by gtk_entry_set_text */
93 }
94
95 static void
selection_changed(Diagram * dia,int n,DDisplay * ddisp)96 selection_changed (Diagram* dia, int n, DDisplay* ddisp)
97 {
98 GtkStatusbar *statusbar;
99 guint context_id;
100
101 /* nothing to do if there is no display with the diagram anymore */
102 if (g_slist_length(dia->displays) < 1)
103 return;
104
105 statusbar = GTK_STATUSBAR (ddisp->modified_status);
106 context_id = gtk_statusbar_get_context_id (statusbar, "Selection");
107
108 if (n > 1)
109 {
110 gchar *msg;
111
112 /* http://www.gnu.org/software/gettext/manual/html_chapter/gettext_10.html#SEC150
113 * Althoug the single objects wont get triggered here some languages have variations on the other numbers
114 */
115 msg = g_strdup_printf (ngettext ("Selection of %d object", "Selection of %d objects", n), n);
116 gtk_statusbar_pop (statusbar, context_id);
117 gtk_statusbar_push (statusbar, context_id, msg);
118 g_free (msg);
119 }
120 else if (n == 1)
121 {
122 /* find the selected objects name - and display it */
123 DiaObject *object = (DiaObject *)ddisp->diagram->data->selected->data;
124 gchar *name = object_get_displayname (object);
125 gchar *msg = g_strdup_printf (_("Selected '%s'"), name);
126
127 gtk_statusbar_pop (statusbar, context_id);
128 gtk_statusbar_push (statusbar, context_id, msg);
129
130 g_free (name);
131 g_free (msg);
132 }
133 else
134 {
135 gtk_statusbar_pop (statusbar, context_id);
136 }
137 /* selection-changed signal can also be emitted from outside of the dia core */
138 ddisplay_do_update_menu_sensitivity (ddisp);
139 }
140
141 static void
append_im_menu(DDisplay * ddisp,GtkAction * action)142 append_im_menu (DDisplay* ddisp, GtkAction* action)
143 {
144 GSList *proxies;
145 GtkWidget *im_menu;
146 /* GtkWidget *im_menu_tearoff; */
147
148 proxies = gtk_action_get_proxies (action);
149 while (proxies) {
150 if (GTK_IS_MENU_ITEM (proxies->data)) {
151 im_menu = gtk_menu_new ();
152 /* tearoff should be added depending on gtk settings
153 im_menu_tearoff = gtk_tearoff_menu_item_new ();
154 gtk_menu_shell_append (GTK_MENU_SHELL(im_menu), im_menu_tearoff);
155 */
156 gtk_im_multicontext_append_menuitems (
157 GTK_IM_MULTICONTEXT(ddisp->im_context),
158 GTK_MENU_SHELL(im_menu));
159 gtk_menu_item_set_submenu (GTK_MENU_ITEM(proxies->data), im_menu);
160 gtk_widget_show (GTK_WIDGET (proxies->data));
161 gtk_widget_show (GTK_WIDGET (im_menu));
162 }
163 proxies = proxies->next;
164 }
165 }
166
167 /** Initialize the various GTK-level thinks in a display after the internal
168 * data has been set.
169 * @param ddisp A display with all non-GTK/GDK items set.
170 */
171 static void
initialize_display_widgets(DDisplay * ddisp)172 initialize_display_widgets(DDisplay *ddisp)
173 {
174 GtkAction* im_menu_item;
175 static gboolean input_methods_done = FALSE;
176 Diagram *dia = ddisp->diagram;
177 gchar *filename;
178
179 /* ddisp->renderer = new_gdk_renderer(ddisp);*/
180
181 ddisp->im_context = gtk_im_multicontext_new();
182 g_signal_connect (G_OBJECT (ddisp->im_context), "commit",
183 G_CALLBACK (ddisplay_im_context_commit), ddisp);
184 ddisp->preedit_string = NULL;
185 g_signal_connect (G_OBJECT (ddisp->im_context), "preedit_changed",
186 G_CALLBACK (ddisplay_im_context_preedit_changed),
187 ddisp);
188 ddisp->preedit_attrs = NULL;
189
190 filename = strrchr(dia->filename, G_DIR_SEPARATOR);
191 if (filename==NULL) {
192 filename = dia->filename;
193 } else {
194 filename++;
195 }
196 create_display_shell(ddisp, prefs.new_view.width, prefs.new_view.height,
197 filename, prefs.new_view.use_menu_bar, !app_is_embedded());
198
199 ddisplay_update_statusbar (ddisp);
200
201 ddisplay_set_origo(ddisp, ddisp->visible.left, ddisp->visible.top);
202 ddisplay_update_scrollbars(ddisp);
203 ddisplay_add_update_all(ddisp);
204
205 if (!display_ht)
206 display_ht = g_hash_table_new ((GHashFunc) display_hash, NULL);
207
208 if (!app_is_embedded())
209 ddisplay_set_cursor(ddisp, current_cursor);
210
211 g_hash_table_insert (display_ht, ddisp->shell, ddisp);
212 g_hash_table_insert (display_ht, ddisp->canvas, ddisp);
213
214 if (!input_methods_done) {
215 im_menu_item = menus_get_action ("InputMethods");
216 g_assert (im_menu_item);
217 append_im_menu (ddisp, im_menu_item);
218 input_methods_done = TRUE;
219 }
220 /* the diagram menubar gets recreated for every diagram */
221 if (ddisp->menu_bar) {
222 im_menu_item = gtk_action_group_get_action (ddisp->actions, "InputMethods");
223 g_assert (im_menu_item);
224 append_im_menu (ddisp, im_menu_item);
225 }
226 }
227
228 /** Make a copy of an existing display. The original does not need to have
229 * the various GTK-related fields initialized, and so can just have been read
230 * from a savefile.
231 * Note that size and position are not handled here yet, but taken from prefs.
232 * @param A display object with non-GTK/GDK fields initialized (same fields as
233 * new_display initializes before calling initialize_display_widgets()).
234 * @returns A newly allocated display, inserted into the diagram list, with
235 * same basic layout as the original.
236 */
237 DDisplay *
copy_display(DDisplay * orig_ddisp)238 copy_display(DDisplay *orig_ddisp)
239 {
240 DDisplay *ddisp;
241 Diagram *dia = orig_ddisp->diagram;
242
243 ddisp = g_new0(DDisplay,1);
244
245 ddisp->diagram = orig_ddisp->diagram;
246 /* Every display has its own reference */
247 g_object_ref(dia);
248
249 ddisp->grid = orig_ddisp->grid;
250
251 ddisp->show_cx_pts = orig_ddisp->show_cx_pts;
252
253
254 ddisp->autoscroll = orig_ddisp->autoscroll;
255 ddisp->mainpoint_magnetism = orig_ddisp->mainpoint_magnetism;
256
257 ddisp->aa_renderer = orig_ddisp->aa_renderer;
258
259 ddisp->update_areas = orig_ddisp->update_areas;
260 ddisp->display_areas = orig_ddisp->display_areas;
261 ddisp->update_id = 0;
262
263 diagram_add_ddisplay(dia, ddisp);
264 g_signal_connect (dia, "selection_changed", G_CALLBACK(selection_changed), ddisp);
265 ddisp->origo = orig_ddisp->origo;
266 ddisp->zoom_factor = orig_ddisp->zoom_factor;
267 ddisp->visible = orig_ddisp->visible;
268
269 initialize_display_widgets(ddisp);
270 return ddisp; /* set the user data */
271 }
272
273
274 /** Create a new display for a diagram, using prefs settings.
275 * @param dia Otherwise initialize diagram to create a display for.
276 * @returns A newly created display.
277 */
278 DDisplay *
new_display(Diagram * dia)279 new_display(Diagram *dia)
280 {
281 DDisplay *ddisp;
282 Rectangle visible;
283
284 ddisp = g_new0(DDisplay,1);
285
286 ddisp->diagram = dia;
287 /* Every display has it's own reference */
288 g_object_ref(dia);
289
290 ddisp->grid.visible = prefs.grid.visible;
291 ddisp->grid.snap = prefs.grid.snap;
292
293 ddisp->show_cx_pts = prefs.show_cx_pts;
294
295 ddisp->autoscroll = TRUE;
296 ddisp->mainpoint_magnetism = prefs.snap_object;
297
298 ddisp->aa_renderer = prefs.view_antialised;
299
300 ddisp->update_areas = NULL;
301 ddisp->display_areas = NULL;
302 ddisp->update_id = 0;
303
304 diagram_add_ddisplay(dia, ddisp);
305 g_signal_connect (dia, "selection_changed", G_CALLBACK(selection_changed), ddisp);
306 ddisp->origo.x = 0.0;
307 ddisp->origo.y = 0.0;
308 ddisp->zoom_factor = prefs.new_view.zoom/100.0*DDISPLAY_NORMAL_ZOOM;
309 if ((ddisp->diagram) && (ddisp->diagram->data)) {
310 Rectangle *extents = &ddisp->diagram->data->extents;
311
312 visible.left = extents->left;
313 visible.top = extents->top;
314 } else {
315 visible.left = 0.0;
316 visible.top = 0.0;
317 }
318 visible.right = visible.left + prefs.new_view.width/ddisp->zoom_factor;
319 visible.bottom = visible.top + prefs.new_view.height/ddisp->zoom_factor;
320
321 ddisp->visible = visible;
322
323 initialize_display_widgets(ddisp);
324 return ddisp; /* set the user data */
325 }
326
327 static guint
display_hash(DDisplay * ddisp)328 display_hash(DDisplay *ddisp)
329 {
330 return (gulong) ddisp;
331 }
332
333 void
ddisplay_transform_coords_double(DDisplay * ddisp,coord x,coord y,double * xi,double * yi)334 ddisplay_transform_coords_double(DDisplay *ddisp,
335 coord x, coord y,
336 double *xi, double *yi)
337 {
338 Rectangle *visible = &ddisp->visible;
339 double width = dia_renderer_get_width_pixels (ddisp->renderer);
340 double height = dia_renderer_get_height_pixels (ddisp->renderer);
341
342 *xi = (x - visible->left) * (real)width / (visible->right - visible->left);
343 *yi = (y - visible->top) * (real)height / (visible->bottom - visible->top);
344 }
345
346
347 void
ddisplay_transform_coords(DDisplay * ddisp,coord x,coord y,int * xi,int * yi)348 ddisplay_transform_coords(DDisplay *ddisp,
349 coord x, coord y,
350 int *xi, int *yi)
351 {
352 Rectangle *visible = &ddisp->visible;
353 int width = dia_renderer_get_width_pixels (ddisp->renderer);
354 int height = dia_renderer_get_height_pixels (ddisp->renderer);
355
356 *xi = ROUND ( (x - visible->left) * (real)width /
357 (visible->right - visible->left) );
358 *yi = ROUND ( (y - visible->top) * (real)height /
359 (visible->bottom - visible->top) );
360 }
361
362 /* Takes real length and returns pixel length */
363 real
ddisplay_transform_length(DDisplay * ddisp,real len)364 ddisplay_transform_length(DDisplay *ddisp, real len)
365 {
366 return len * ddisp->zoom_factor;
367 }
368
369 /* Takes pixel length and returns real length */
370 real
ddisplay_untransform_length(DDisplay * ddisp,real len)371 ddisplay_untransform_length(DDisplay *ddisp, real len)
372 {
373 return len / ddisp->zoom_factor;
374 }
375
376
377 void
ddisplay_untransform_coords(DDisplay * ddisp,int xi,int yi,coord * x,coord * y)378 ddisplay_untransform_coords(DDisplay *ddisp,
379 int xi, int yi,
380 coord *x, coord *y)
381 {
382 Rectangle *visible = &ddisp->visible;
383 int width = dia_renderer_get_width_pixels (ddisp->renderer);
384 int height = dia_renderer_get_height_pixels (ddisp->renderer);
385
386 *x = visible->left + xi*(visible->right - visible->left) / (real)width;
387 *y = visible->top + yi*(visible->bottom - visible->top) / (real)height;
388 }
389
390
391 void
ddisplay_add_update_pixels(DDisplay * ddisp,Point * point,int pixel_width,int pixel_height)392 ddisplay_add_update_pixels(DDisplay *ddisp, Point *point,
393 int pixel_width, int pixel_height)
394 {
395 Rectangle rect;
396 real size_x, size_y;
397
398 size_x = ddisplay_untransform_length(ddisp, pixel_width+1);
399 size_y = ddisplay_untransform_length(ddisp, pixel_height+1);
400
401 rect.left = point->x - size_x/2.0;
402 rect.top = point->y - size_y/2.0;
403 rect.right = point->x + size_x/2.0;
404 rect.bottom = point->y + size_y/2.0;
405
406 ddisplay_add_update(ddisp, &rect);
407 }
408
409 /** Free display_areas list */
410 static void
ddisplay_free_display_areas(DDisplay * ddisp)411 ddisplay_free_display_areas(DDisplay *ddisp)
412 {
413 GSList *l;
414 l = ddisp->display_areas;
415 while(l!=NULL) {
416 g_free(l->data);
417 l = g_slist_next(l);
418 }
419 g_slist_free(ddisp->display_areas);
420 ddisp->display_areas = NULL;
421 }
422
423 /** Free update_areas list */
424 static void
ddisplay_free_update_areas(DDisplay * ddisp)425 ddisplay_free_update_areas(DDisplay *ddisp)
426 {
427 GSList *l;
428 l = ddisp->update_areas;
429 while(l!=NULL) {
430 g_free(l->data);
431 l = g_slist_next(l);
432 }
433 g_slist_free(ddisp->update_areas);
434 ddisp->update_areas = NULL;
435 }
436
437 /** Marks the entire visible area for update.
438 * Throws out old updates, since everything will be updated anyway.
439 */
440 void
ddisplay_add_update_all(DDisplay * ddisp)441 ddisplay_add_update_all(DDisplay *ddisp)
442 {
443 if (ddisp->update_areas != NULL) {
444 ddisplay_free_update_areas(ddisp);
445 }
446 if (ddisp->display_areas != NULL) {
447 ddisplay_free_display_areas(ddisp);
448 }
449 ddisplay_add_update(ddisp, &ddisp->visible);
450 }
451
452 /** Marks a rectangle for update, with a pixel border around it.
453 */
454 void
ddisplay_add_update_with_border(DDisplay * ddisp,Rectangle * rect,int pixel_border)455 ddisplay_add_update_with_border(DDisplay *ddisp, Rectangle *rect,
456 int pixel_border)
457 {
458 Rectangle r;
459 real size = ddisplay_untransform_length(ddisp, pixel_border+1);
460
461 r.left = rect->left-size;
462 r.top = rect->top-size;
463 r.right = rect->right+size;
464 r.bottom = rect->bottom+size;
465
466 ddisplay_add_update(ddisp, &r);
467 }
468
469 void
ddisplay_add_update(DDisplay * ddisp,Rectangle * rect)470 ddisplay_add_update(DDisplay *ddisp, Rectangle *rect)
471 {
472 Rectangle *r;
473 int top,bottom,left,right;
474 Rectangle *visible;
475 int width, height;
476
477 if (!ddisp->renderer)
478 return; /* can happen at creation time of the diagram */
479 width = dia_renderer_get_width_pixels (ddisp->renderer);
480 height = dia_renderer_get_height_pixels (ddisp->renderer);
481
482 if (!rectangle_intersects(rect, &ddisp->visible))
483 return;
484
485 /* Temporarily just do a union of all rectangles: */
486 if (ddisp->update_areas==NULL) {
487 r = g_new(Rectangle,1);
488 *r = *rect;
489 rectangle_intersection(r, &ddisp->visible);
490 ddisp->update_areas = g_slist_prepend(ddisp->update_areas, r);
491 } else {
492 r = (Rectangle *) ddisp->update_areas->data;
493 rectangle_union(r, rect);
494 rectangle_intersection(r, &ddisp->visible);
495 }
496
497 visible = &ddisp->visible;
498 left = floor( (r->left - visible->left) * (real)width /
499 (visible->right - visible->left) ) - 1;
500 top = floor( (r->top - visible->top) * (real)height /
501 (visible->bottom - visible->top) ) - 1;
502 right = ceil( (r->right - visible->left) * (real)width /
503 (visible->right - visible->left) ) + 1;
504 bottom = ceil( (r->bottom - visible->top) * (real)height /
505 (visible->bottom - visible->top) ) + 1;
506
507 ddisplay_add_display_area(ddisp,
508 left, top,
509 right, bottom);
510 }
511
512 void
ddisplay_add_display_area(DDisplay * ddisp,int left,int top,int right,int bottom)513 ddisplay_add_display_area(DDisplay *ddisp,
514 int left, int top,
515 int right, int bottom)
516 {
517 IRectangle *r;
518
519 if (!ddisp->renderer)
520 return; /* if we don't have a renderer yet prefer ignoring over crashing */
521 if (left < 0)
522 left = 0;
523 if (top < 0)
524 top = 0;
525 if (right > dia_renderer_get_width_pixels (ddisp->renderer))
526 right = dia_renderer_get_width_pixels (ddisp->renderer);
527 if (bottom > dia_renderer_get_height_pixels (ddisp->renderer))
528 bottom = dia_renderer_get_height_pixels (ddisp->renderer);
529
530 /* draw some rectangles to show where updates are...*/
531 /* gdk_draw_rectangle(ddisp->canvas->window, ddisp->canvas->style->black_gc, TRUE, left, top, right-left,bottom-top); */
532
533 /* Temporarily just do a union of all Irectangles: */
534 if (ddisp->display_areas==NULL) {
535 r = g_new(IRectangle,1);
536 r->top = top; r->bottom = bottom;
537 r->left = left; r->right = right;
538 ddisp->display_areas = g_slist_prepend(ddisp->display_areas, r);
539 } else {
540 r = (IRectangle *) ddisp->display_areas->data;
541
542 r->top = MIN( r->top, top );
543 r->bottom = MAX( r->bottom, bottom );
544 r->left = MIN( r->left, left );
545 r->right = MAX( r->right, right );
546 }
547 }
548
549 static gboolean
ddisplay_update_handler(DDisplay * ddisp)550 ddisplay_update_handler(DDisplay *ddisp)
551 {
552 GSList *l;
553 IRectangle *ir;
554 Rectangle *r, totrect;
555 DiaInteractiveRendererInterface *renderer;
556
557 /* Renders updates to pixmap + copies display_areas to canvas(screen) */
558 renderer = DIA_GET_INTERACTIVE_RENDERER_INTERFACE (ddisp->renderer);
559
560 /* Only update if update_areas exist */
561 l = ddisp->update_areas;
562 if (l != NULL)
563 {
564 totrect = *(Rectangle *) l->data;
565
566 g_return_val_if_fail ( renderer->clip_region_clear != NULL
567 && renderer->clip_region_add_rect != NULL, FALSE);
568
569 renderer->clip_region_clear (ddisp->renderer);
570
571 while(l!=NULL) {
572 r = (Rectangle *) l->data;
573
574 rectangle_union(&totrect, r);
575 renderer->clip_region_add_rect (ddisp->renderer, r);
576
577 l = g_slist_next(l);
578 }
579 /* Free update_areas list: */
580 ddisplay_free_update_areas(ddisp);
581
582 totrect.left -= 0.1;
583 totrect.right += 0.1;
584 totrect.top -= 0.1;
585 totrect.bottom += 0.1;
586
587 ddisplay_render_pixmap(ddisp, &totrect);
588 }
589
590 l = ddisp->display_areas;
591 while(l!=NULL) {
592 ir = (IRectangle *) l->data;
593
594 g_return_val_if_fail (renderer->copy_to_window, FALSE);
595 renderer->copy_to_window(ddisp->renderer,
596 ddisp->canvas->window,
597 ir->left, ir->top,
598 ir->right - ir->left, ir->bottom - ir->top);
599
600 l = g_slist_next(l);
601 }
602
603 ddisplay_free_display_areas(ddisp);
604
605 ddisp->update_id = 0;
606
607 return FALSE;
608 }
609
610 void
ddisplay_flush(DDisplay * ddisp)611 ddisplay_flush(DDisplay *ddisp)
612 {
613 /* if no update is queued, queue update */
614 if (!ddisp->update_id)
615 ddisp->update_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, (GSourceFunc)ddisplay_update_handler, ddisp, NULL);
616 }
617
618 static void
ddisplay_obj_render(DiaObject * obj,DiaRenderer * renderer,int active_layer,gpointer data)619 ddisplay_obj_render(DiaObject *obj, DiaRenderer *renderer,
620 int active_layer,
621 gpointer data)
622 {
623 DDisplay *ddisp = (DDisplay *)data;
624 int i;
625
626 DIA_RENDERER_GET_CLASS(renderer)->draw_object(renderer, obj);
627 if (ddisp->show_cx_pts &&
628 obj->parent_layer != NULL && obj->parent_layer->connectable) {
629 for (i=0;i<obj->num_connections;i++) {
630 connectionpoint_draw(obj->connections[i], ddisp);
631 }
632 }
633 }
634
635 void
ddisplay_render_pixmap(DDisplay * ddisp,Rectangle * update)636 ddisplay_render_pixmap(DDisplay *ddisp, Rectangle *update)
637 {
638 GList *list;
639 DiaObject *obj;
640 int i;
641 DiaInteractiveRendererInterface *renderer;
642 #ifdef TRACES
643 GTimer *timer;
644 #endif
645
646 if (ddisp->renderer==NULL) {
647 printf("ERROR! Renderer was NULL!!\n");
648 return;
649 }
650
651 renderer = DIA_GET_INTERACTIVE_RENDERER_INTERFACE (ddisp->renderer);
652
653 /* Erase background */
654 g_return_if_fail (renderer->fill_pixel_rect != NULL);
655 DIA_RENDERER_GET_CLASS(ddisp->renderer)->begin_render(ddisp->renderer);
656 renderer->fill_pixel_rect (ddisp->renderer,
657 0, 0,
658 dia_renderer_get_width_pixels (ddisp->renderer),
659 dia_renderer_get_height_pixels (ddisp->renderer),
660 &ddisp->diagram->data->bg_color);
661
662 /* Draw grid */
663 grid_draw(ddisp, update);
664 pagebreak_draw(ddisp, update);
665
666 #ifdef TRACES
667 timer = g_timer_new();
668 #endif
669 data_render(ddisp->diagram->data, ddisp->renderer, update,
670 ddisplay_obj_render, (gpointer) ddisp);
671 #ifdef TRACES
672 g_print ("data_render(%g%%) took %g seconds\n", ddisp->zoom_factor * 5.0, g_timer_elapsed (timer, NULL));
673 g_timer_destroy (timer);
674 #endif
675 /* Draw handles for all selected objects */
676 list = ddisp->diagram->data->selected;
677 while (list!=NULL) {
678 obj = (DiaObject *) list->data;
679
680 for (i=0;i<obj->num_handles;i++) {
681 handle_draw(obj->handles[i], ddisp);
682 }
683 list = g_list_next(list);
684 }
685 DIA_RENDERER_GET_CLASS(ddisp->renderer)->end_render(ddisp->renderer);
686 }
687
688 void
ddisplay_update_scrollbars(DDisplay * ddisp)689 ddisplay_update_scrollbars(DDisplay *ddisp)
690 {
691 Rectangle *extents = &ddisp->diagram->data->extents;
692 Rectangle *visible = &ddisp->visible;
693 GtkAdjustment *hsbdata, *vsbdata;
694
695 hsbdata = ddisp->hsbdata;
696 /* Horizontal: */
697 hsbdata->lower = MIN(extents->left, visible->left);
698 hsbdata->upper = MAX(extents->right, visible->right);
699 hsbdata->page_size = visible->right - visible->left - 0.0001;
700 /* remove some to fix strange behaviour in gtk_range_adjustment_changed */
701 hsbdata->page_increment = (visible->right - visible->left) / 2.0;
702 hsbdata->step_increment = (visible->right - visible->left) / 10.0;
703 hsbdata->value = visible->left;
704
705 g_signal_emit_by_name (G_OBJECT (ddisp->hsbdata), "changed");
706
707 /* Vertical: */
708 vsbdata = ddisp->vsbdata;
709 vsbdata->lower = MIN(extents->top, visible->top);
710 vsbdata->upper = MAX(extents->bottom, visible->bottom);
711 vsbdata->page_size = visible->bottom - visible->top - 0.00001;
712 /* remove some to fix strange behaviour in gtk_range_adjustment_changed */
713 vsbdata->page_increment = (visible->bottom - visible->top) / 2.0;
714 vsbdata->step_increment = (visible->bottom - visible->top) / 10.0;
715 vsbdata->value = visible->top;
716
717 g_signal_emit_by_name (G_OBJECT (ddisp->vsbdata), "changed");
718 }
719
720 void
ddisplay_set_origo(DDisplay * ddisp,coord x,coord y)721 ddisplay_set_origo(DDisplay *ddisp, coord x, coord y)
722 {
723 Rectangle *extents = &ddisp->diagram->data->extents;
724 Rectangle *visible = &ddisp->visible;
725 int width, height;
726
727 /* updaterar origo+visible+rulers */
728 ddisp->origo.x = x;
729 ddisp->origo.y = y;
730
731 if (ddisp->zoom_factor<DDISPLAY_MIN_ZOOM)
732 ddisp->zoom_factor = DDISPLAY_MIN_ZOOM;
733
734 if (ddisp->zoom_factor > DDISPLAY_MAX_ZOOM)
735 ddisp->zoom_factor = DDISPLAY_MAX_ZOOM;
736
737 width = dia_renderer_get_width_pixels (ddisp->renderer);
738 height = dia_renderer_get_height_pixels (ddisp->renderer);
739
740 visible->left = ddisp->origo.x;
741 visible->top = ddisp->origo.y;
742 visible->right = ddisp->origo.x + ddisplay_untransform_length(ddisp, width);
743 visible->bottom = ddisp->origo.y + ddisplay_untransform_length(ddisp, height);
744
745 gtk_ruler_set_range (GTK_RULER (ddisp->hrule),
746 visible->left,
747 visible->right,
748 0.0f /* position*/,
749 MAX(extents->right, visible->right)/* max_size*/);
750 gtk_ruler_set_range (GTK_RULER (ddisp->vrule),
751 visible->top,
752 visible->bottom,
753 0.0f /* position*/,
754 MAX(extents->bottom, visible->bottom)/* max_size*/);
755 }
756
757 void
ddisplay_zoom(DDisplay * ddisp,Point * point,real magnify)758 ddisplay_zoom(DDisplay *ddisp, Point *point, real magnify)
759 {
760 Rectangle *visible;
761 real width, height, old_zoom;
762
763 visible = &ddisp->visible;
764
765 if ((ddisp->zoom_factor <= DDISPLAY_MIN_ZOOM) && (magnify<=1.0))
766 return;
767 if ((ddisp->zoom_factor >= DDISPLAY_MAX_ZOOM) && (magnify>=1.0))
768 return;
769
770 old_zoom = ddisp->zoom_factor;
771 ddisp->zoom_factor = old_zoom * magnify;
772
773 /* clip once more */
774 if (ddisp->zoom_factor < DDISPLAY_MIN_ZOOM)
775 ddisp->zoom_factor = DDISPLAY_MIN_ZOOM;
776 else if (ddisp->zoom_factor > DDISPLAY_MAX_ZOOM)
777 ddisp->zoom_factor = DDISPLAY_MAX_ZOOM;
778
779 /* the real one used - after clipping */
780 magnify = ddisp->zoom_factor / old_zoom;
781 width = (visible->right - visible->left)/magnify;
782 height = (visible->bottom - visible->top)/magnify;
783
784
785 ddisplay_set_origo(ddisp, point->x - width/2.0, point->y - height/2.0);
786
787 ddisplay_update_scrollbars(ddisp);
788 ddisplay_add_update_all(ddisp);
789 ddisplay_flush(ddisp);
790
791 update_zoom_status (ddisp);
792 }
793
794 /*
795 When using the mouse wheel button to zoom in and out, it is more
796 intuitive to maintain the drawing zoom center-point based on the
797 cursor position. This can help orientation and prevent the drawing
798 from "jumping" around while zooming in and out.
799 */
800 void
ddisplay_zoom_centered(DDisplay * ddisp,Point * point,real magnify)801 ddisplay_zoom_centered(DDisplay *ddisp, Point *point, real magnify)
802 {
803 Rectangle *visible;
804 real width, height;
805 /* cursor position ratios */
806 real rx,ry;
807
808 if ((ddisp->zoom_factor <= DDISPLAY_MIN_ZOOM) && (magnify<=1.0))
809 return;
810 if ((ddisp->zoom_factor >= DDISPLAY_MAX_ZOOM) && (magnify>=1.0))
811 return;
812
813 visible = &ddisp->visible;
814
815 /* calculate cursor position ratios */
816 rx = (point->x-visible->left)/(visible->right - visible->left);
817 ry = (point->y-visible->top)/(visible->bottom - visible->top);
818
819 width = (visible->right - visible->left)/magnify;
820 height = (visible->bottom - visible->top)/magnify;
821
822 ddisp->zoom_factor *= magnify;
823
824 /* set new origin based on the calculated ratios before zooming */
825 ddisplay_set_origo(ddisp, point->x-(width*rx),point->y-(height*ry));
826
827 ddisplay_update_scrollbars(ddisp);
828 ddisplay_add_update_all(ddisp);
829 ddisplay_flush(ddisp);
830
831 update_zoom_status (ddisp);
832 }
833
834 /** Set the display's snap-to-grid setting, updating menu and button
835 * in the process */
836 void
ddisplay_set_snap_to_grid(DDisplay * ddisp,gboolean snap)837 ddisplay_set_snap_to_grid(DDisplay *ddisp, gboolean snap)
838 {
839 GtkToggleAction *snap_to_grid;
840 ddisp->grid.snap = snap;
841
842 if (ddisp->menu_bar == NULL) {
843 snap_to_grid = GTK_TOGGLE_ACTION (menus_get_action ("ViewSnaptogrid"));
844 if (is_integrated_ui ())
845 integrated_ui_toolbar_grid_snap_synchronize_to_display (ddisp);
846 } else {
847 snap_to_grid = GTK_TOGGLE_ACTION (gtk_action_group_get_action (ddisp->actions, "ViewSnaptogrid"));
848 }
849 /* Currently, this can cause double emit, but that's a small problem.
850 */
851 gtk_toggle_action_set_active (snap_to_grid, ddisp->grid.snap);
852 ddisplay_update_statusbar(ddisp);
853 }
854
855 /** Update the button showing whether snap-to-grid is on */
856 static void
update_snap_grid_status(DDisplay * ddisp)857 update_snap_grid_status(DDisplay *ddisp)
858 {
859 if (ddisp->grid_status)
860 {
861 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ddisp->grid_status),
862 ddisp->grid.snap);
863 }
864 }
865
866 /** Set the display's mainpoint magnetism setting, updating menu and button
867 * in the process */
868 void
ddisplay_set_snap_to_objects(DDisplay * ddisp,gboolean magnetic)869 ddisplay_set_snap_to_objects(DDisplay *ddisp, gboolean magnetic)
870 {
871 GtkToggleAction *mainpoint_magnetism;
872 ddisp->mainpoint_magnetism = magnetic;
873
874 if (ddisp->menu_bar == NULL) {
875 mainpoint_magnetism = GTK_TOGGLE_ACTION (menus_get_action ("ViewSnaptoobjects"));
876 if (is_integrated_ui ())
877 integrated_ui_toolbar_object_snap_synchronize_to_display (ddisp);
878 } else {
879 mainpoint_magnetism = GTK_TOGGLE_ACTION (gtk_action_group_get_action (ddisp->actions, "ViewSnaptoobjects"));
880 }
881
882 /* Currently, this can cause double emit, but that's a small problem.
883 */
884 gtk_toggle_action_set_active (mainpoint_magnetism, ddisp->mainpoint_magnetism);
885 ddisplay_update_statusbar(ddisp);
886 }
887
888 /** Update the button showing whether mainpoint magnetism is on */
889 static void
update_mainpoint_status(DDisplay * ddisp)890 update_mainpoint_status(DDisplay *ddisp)
891 {
892 if (ddisp->mainpoint_status)
893 {
894 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ddisp->mainpoint_status),
895 ddisp->mainpoint_magnetism);
896 }
897 }
898
899 /** Scroll display to where point x,y (window coords) is visible */
900 gboolean
ddisplay_autoscroll(DDisplay * ddisp,int x,int y)901 ddisplay_autoscroll(DDisplay *ddisp, int x, int y)
902 {
903 guint16 width, height;
904 Point scroll;
905
906 if (! ddisp->autoscroll)
907 return FALSE;
908
909 scroll.x = scroll.y = 0;
910
911 width = GTK_WIDGET(ddisp->canvas)->allocation.width;
912 height = GTK_WIDGET(ddisp->canvas)->allocation.height;
913
914 if (x < 0)
915 {
916 scroll.x = x;
917 }
918 else if ( x > width)
919 {
920 scroll.x = x - width;
921 }
922
923 if (y < 0)
924 {
925 scroll.y = y;
926 }
927 else if (y > height)
928 {
929 scroll.y = y - height;
930 }
931
932 if ((scroll.x != 0) || (scroll.y != 0))
933 {
934 gboolean scrolled;
935
936 scroll.x = ddisplay_untransform_length(ddisp, scroll.x);
937 scroll.y = ddisplay_untransform_length(ddisp, scroll.y);
938
939 scrolled = ddisplay_scroll(ddisp, &scroll);
940
941 if (scrolled) {
942 ddisplay_flush(ddisp);
943 return TRUE;
944 }
945 }
946 return FALSE;
947 }
948
949 /** Scroll the display by delta (diagram coords) */
950 gboolean
ddisplay_scroll(DDisplay * ddisp,Point * delta)951 ddisplay_scroll(DDisplay *ddisp, Point *delta)
952 {
953 Rectangle *visible = &ddisp->visible;
954 real width = visible->right - visible->left;
955 real height = visible->bottom - visible->top;
956
957 Rectangle extents = ddisp->diagram->data->extents;
958 real ex_width = extents.right - extents.left;
959 real ex_height = extents.bottom - extents.top;
960
961 Point new_origo = ddisp->origo;
962 point_add(&new_origo, delta);
963
964 rectangle_union(&extents, visible);
965
966 if (new_origo.x < extents.left - ex_width)
967 new_origo.x = extents.left - ex_width;
968
969 if (new_origo.x+width > extents.right + ex_width)
970 new_origo.x = extents.right - width + ex_width;
971
972 if (new_origo.y < extents.top - ex_height)
973 new_origo.y = extents.top - ex_height;
974
975 if (new_origo.y+height > extents.bottom + ex_height)
976 new_origo.y = extents.bottom - height + ex_height;
977
978 if ( (new_origo.x != ddisp->origo.x) ||
979 (new_origo.y != ddisp->origo.y) ) {
980 ddisplay_set_origo(ddisp, new_origo.x, new_origo.y);
981 ddisplay_update_scrollbars(ddisp);
982 ddisplay_add_update_all(ddisp);
983 return TRUE;
984 }
985 return FALSE;
986 }
987
ddisplay_scroll_up(DDisplay * ddisp)988 void ddisplay_scroll_up(DDisplay *ddisp)
989 {
990 Point delta;
991
992 delta.x = 0;
993 delta.y = -(ddisp->visible.bottom - ddisp->visible.top)/4.0;
994
995 ddisplay_scroll(ddisp, &delta);
996 }
997
ddisplay_scroll_down(DDisplay * ddisp)998 void ddisplay_scroll_down(DDisplay *ddisp)
999 {
1000 Point delta;
1001
1002 delta.x = 0;
1003 delta.y = (ddisp->visible.bottom - ddisp->visible.top)/4.0;
1004
1005 ddisplay_scroll(ddisp, &delta);
1006 }
1007
ddisplay_scroll_left(DDisplay * ddisp)1008 void ddisplay_scroll_left(DDisplay *ddisp)
1009 {
1010 Point delta;
1011
1012 delta.x = -(ddisp->visible.right - ddisp->visible.left)/4.0;
1013 delta.y = 0;
1014
1015 ddisplay_scroll(ddisp, &delta);
1016 }
1017
ddisplay_scroll_right(DDisplay * ddisp)1018 void ddisplay_scroll_right(DDisplay *ddisp)
1019 {
1020 Point delta;
1021
1022 delta.x = (ddisp->visible.right - ddisp->visible.left)/4.0;
1023 delta.y = 0;
1024
1025 ddisplay_scroll(ddisp, &delta);
1026 }
1027
1028 /** Scroll display to have the diagram point p at the center.
1029 * Returns TRUE if anything changed. */
1030 gboolean
ddisplay_scroll_center_point(DDisplay * ddisp,Point * p)1031 ddisplay_scroll_center_point(DDisplay *ddisp, Point *p)
1032 {
1033 Point center;
1034
1035 /* Find current center */
1036 center.x = (ddisp->visible.right+ddisp->visible.left)/2;
1037 center.y = (ddisp->visible.top+ddisp->visible.bottom)/2;
1038
1039 point_sub(p, ¢er);
1040 return ddisplay_scroll(ddisp, p);
1041 }
1042
1043 /** Scroll display so that obj is centered.
1044 * Returns TRUE if anything changed. */
1045 gboolean
ddisplay_scroll_to_object(DDisplay * ddisp,DiaObject * obj)1046 ddisplay_scroll_to_object(DDisplay *ddisp, DiaObject *obj)
1047 {
1048 Rectangle r = obj->bounding_box;
1049
1050 Point p;
1051 p.x = (r.left+r.right)/2;
1052 p.y = (r.top+r.bottom)/2;
1053
1054 display_set_active(ddisp);
1055 return ddisplay_scroll_center_point(ddisp, &p);
1056 }
1057
1058 /** Ensure the object is visible but minimize scrolling
1059 */
1060 gboolean
ddisplay_present_object(DDisplay * ddisp,DiaObject * obj)1061 ddisplay_present_object(DDisplay *ddisp, DiaObject *obj)
1062 {
1063 const Rectangle *r = dia_object_get_enclosing_box(obj);
1064 const Rectangle *v = &ddisp->visible;
1065
1066 display_set_active(ddisp);
1067 if (!rectangle_in_rectangle(v, r)) {
1068 Point delta = { 0, 0 };
1069
1070 if ((r->right - r->left) > (v->right - v->left)) /* object bigger than visible area */
1071 delta.x = (r->left - v->left + r->right - v->right) / 2;
1072 else if (r->left < v->left)
1073 delta.x = r->left - v->left;
1074 else if (r->right > v->right)
1075 delta.x = r->right - v->right;
1076
1077 if ((r->bottom - r->top) > (v->bottom - v->top)) /* object bigger than visible area */
1078 delta.y = (r->top - v->top + r->bottom - v->bottom) / 2;
1079 else if (r->top < v->top)
1080 delta.y = r->top - v->top;
1081 else if (r->bottom > v->bottom)
1082 delta.y = r->bottom - v->bottom;
1083
1084 ddisplay_scroll(ddisp, &delta);
1085 return TRUE;
1086 }
1087 return FALSE;
1088 }
1089
1090 /**
1091 * Kind of dirty way to init an antialiased renderer, there should be some plug-in interface to do this.
1092 * Now with the Libart renderer being a plug-in and the cairo renderer having issues with highlighting
1093 * ( http://bugzilla.gnome.org/show_bug.cgi?id=576548 ) it seems reasonable to have default at
1094 * Libart, also becuase you loose less when it is switched off ;-)
1095 */
1096 static DiaRenderer *
new_aa_renderer(DDisplay * ddisp)1097 new_aa_renderer (DDisplay *ddisp)
1098 {
1099 GType renderer_type;
1100
1101 renderer_type = g_type_from_name ("DiaLibartRenderer");
1102 if (renderer_type) {
1103 DiaRenderer *renderer = g_object_new(renderer_type, NULL);
1104 g_object_set (renderer,
1105 "transform", dia_transform_new (&ddisp->visible, &ddisp->zoom_factor),
1106 NULL);
1107 return renderer;
1108 }
1109
1110 renderer_type = g_type_from_name ("DiaCairoInteractiveRenderer");
1111 if (renderer_type) {
1112 DiaRenderer *renderer = g_object_new(renderer_type, NULL);
1113 g_object_set (renderer,
1114 "zoom", &ddisp->zoom_factor,
1115 "rect", &ddisp->visible,
1116 NULL);
1117 return renderer;
1118 }
1119
1120 /* we really should not come here but instead disable the menu command earlier */
1121 message_warning (_("No anti-aliased renderer found"));
1122 /* fallback: built-in libart renderer */
1123 return new_gdk_renderer (ddisp);
1124 }
1125
1126 void
ddisplay_set_renderer(DDisplay * ddisp,int aa_renderer)1127 ddisplay_set_renderer(DDisplay *ddisp, int aa_renderer)
1128 {
1129 int width, height;
1130
1131 /* dont mix new renderer with old updates */
1132 if (ddisp->update_id) {
1133 g_source_remove (ddisp->update_id);
1134 ddisp->update_id = 0;
1135 }
1136
1137 if (ddisp->renderer)
1138 g_object_unref (ddisp->renderer);
1139
1140 ddisp->aa_renderer = aa_renderer;
1141
1142 width = ddisp->canvas->allocation.width;
1143 height = ddisp->canvas->allocation.height;
1144
1145 if (ddisp->aa_renderer){
1146 ddisp->renderer = new_aa_renderer (ddisp);
1147 } else {
1148 ddisp->renderer = new_gdk_renderer(ddisp);
1149 }
1150
1151 dia_renderer_set_size(ddisp->renderer, ddisp->canvas->window, width, height);
1152 }
1153
1154 void
ddisplay_resize_canvas(DDisplay * ddisp,int width,int height)1155 ddisplay_resize_canvas(DDisplay *ddisp,
1156 int width, int height)
1157 {
1158 if (ddisp->renderer==NULL) {
1159 if (ddisp->aa_renderer)
1160 ddisp->renderer = new_aa_renderer (ddisp);
1161 else
1162 ddisp->renderer = new_gdk_renderer(ddisp);
1163 }
1164
1165 dia_renderer_set_size(ddisp->renderer, ddisp->canvas->window, width, height);
1166
1167 ddisplay_set_origo(ddisp, ddisp->origo.x, ddisp->origo.y);
1168
1169 ddisplay_add_update_all(ddisp);
1170 ddisplay_flush(ddisp);
1171 }
1172
1173 DDisplay *
ddisplay_active(void)1174 ddisplay_active(void)
1175 {
1176 return active_display;
1177 }
1178
1179 Diagram *
ddisplay_active_diagram(void)1180 ddisplay_active_diagram(void)
1181 {
1182 DDisplay *ddisp = ddisplay_active ();
1183
1184 if (!ddisp) return NULL;
1185 return ddisp->diagram;
1186 }
1187
1188 static void
ddisp_destroy(DDisplay * ddisp)1189 ddisp_destroy(DDisplay *ddisp)
1190 {
1191 g_signal_handlers_disconnect_by_func (ddisp->diagram, selection_changed, ddisp);
1192
1193 g_object_unref (G_OBJECT (ddisp->im_context));
1194 ddisp->im_context = NULL;
1195
1196 ddisplay_im_context_preedit_reset(ddisp, get_active_focus((DiagramData *) ddisp->diagram));
1197
1198 /* This calls ddisplay_really_destroy */
1199 if (ddisp->is_standalone_window)
1200 gtk_widget_destroy (ddisp->shell);
1201 else {
1202 gtk_widget_destroy (ddisp->container);
1203 ddisplay_really_destroy (ddisp);
1204 }
1205 }
1206
1207 static void
are_you_sure_close_dialog_respond(GtkWidget * widget,gint response_id,gpointer user_data)1208 are_you_sure_close_dialog_respond(GtkWidget *widget, /* the dialog */
1209 gint response_id,
1210 gpointer user_data) /* the display */
1211 {
1212 DDisplay *ddisp = (DDisplay *)user_data;
1213 gboolean close_ddisp = TRUE;
1214
1215 switch (response_id) {
1216 case GTK_RESPONSE_YES :
1217 /* save changes */
1218 if (!diagram_save(ddisp->diagram, ddisp->diagram->filename))
1219 close_ddisp = FALSE;
1220
1221 if (ddisp->update_id && close_ddisp) {
1222 g_source_remove (ddisp->update_id);
1223 ddisp->update_id = 0;
1224 }
1225 /* fall through */
1226 case GTK_RESPONSE_NO :
1227 if (close_ddisp)
1228 ddisp_destroy (ddisp);
1229 /* fall through */
1230 case GTK_RESPONSE_CANCEL :
1231 case GTK_RESPONSE_NONE :
1232 case GTK_RESPONSE_DELETE_EVENT : /* closing via window manager */
1233 gtk_widget_destroy(widget);
1234 break;
1235 default :
1236 g_assert_not_reached();
1237 }
1238 }
1239
1240 void
ddisplay_close(DDisplay * ddisp)1241 ddisplay_close(DDisplay *ddisp)
1242 {
1243 Diagram *dia;
1244 GtkWidget *dialog, *button;
1245 gchar *fname;
1246
1247 g_return_if_fail(ddisp != NULL);
1248
1249 dia = ddisp->diagram;
1250
1251 if ( (g_slist_length(dia->displays) > 1) ||
1252 (!diagram_is_modified(dia)) ) {
1253 ddisp_destroy(ddisp);
1254 return;
1255 }
1256
1257 fname = dia->filename;
1258 if (!fname)
1259 fname = _("<unnamed>");
1260
1261 dialog = gtk_message_dialog_new(GTK_WINDOW (ddisp->shell),
1262 GTK_DIALOG_MODAL,
1263 GTK_MESSAGE_QUESTION,
1264 GTK_BUTTONS_NONE, /* no standard buttons */
1265 _("Closing diagram without saving"));
1266 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
1267 _("The diagram '%s'\n"
1268 "has not been saved. Save changes now?"), fname);
1269 gtk_window_set_title (GTK_WINDOW(dialog), _("Close Diagram"));
1270
1271 button = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
1272 gtk_dialog_add_action_widget (GTK_DIALOG(dialog), button, GTK_RESPONSE_CANCEL);
1273
1274 button = gtk_button_new_with_mnemonic (_("_Discard Changes"));
1275 gtk_dialog_add_action_widget (GTK_DIALOG(dialog), button, GTK_RESPONSE_NO);
1276
1277 /* button = gtk_button_new_with_label (_("Save and Close")); */
1278 button = gtk_button_new_from_stock (GTK_STOCK_SAVE);
1279 gtk_dialog_add_action_widget (GTK_DIALOG(dialog), button, GTK_RESPONSE_YES);
1280 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
1281 gtk_dialog_set_default_response (GTK_DIALOG(dialog), GTK_RESPONSE_YES);
1282
1283 g_signal_connect (G_OBJECT (dialog), "response",
1284 G_CALLBACK(are_you_sure_close_dialog_respond),
1285 ddisp);
1286
1287 gtk_widget_show_all(dialog);
1288 }
1289
1290 void
display_update_menu_state(DDisplay * ddisp)1291 display_update_menu_state(DDisplay *ddisp)
1292 {
1293 GtkToggleAction *rulers;
1294 GtkToggleAction *visible_grid;
1295 GtkToggleAction *snap_to_grid;
1296 GtkToggleAction *show_cx_pts;
1297 GtkToggleAction *antialiased;
1298
1299 if (ddisp->menu_bar == NULL) {
1300 rulers = GTK_TOGGLE_ACTION (menus_get_action ("ViewShowrulers"));
1301 visible_grid = GTK_TOGGLE_ACTION (menus_get_action ("ViewShowgrid"));
1302 snap_to_grid = GTK_TOGGLE_ACTION (menus_get_action ("ViewSnaptogrid"));
1303 show_cx_pts = GTK_TOGGLE_ACTION (menus_get_action ("ViewShowconnectionpoints"));
1304 antialiased = GTK_TOGGLE_ACTION (menus_get_action ("ViewAntialiased"));
1305 } else {
1306 rulers = GTK_TOGGLE_ACTION (gtk_action_group_get_action (ddisp->actions, "ViewShowrulers"));
1307 visible_grid = GTK_TOGGLE_ACTION (gtk_action_group_get_action (ddisp->actions, "ViewShowgrid"));
1308 snap_to_grid = GTK_TOGGLE_ACTION (gtk_action_group_get_action (ddisp->actions, "ViewSnaptogrid"));
1309 show_cx_pts = GTK_TOGGLE_ACTION (gtk_action_group_get_action (ddisp->actions, "ViewShowconnectionpoints"));
1310
1311 antialiased = GTK_TOGGLE_ACTION (gtk_action_group_get_action (ddisp->actions, "ViewAntialiased"));
1312 }
1313 gtk_action_set_sensitive (menus_get_action ("ViewAntialiased"),
1314 g_type_from_name ("DiaCairoInteractiveRenderer") != 0 || g_type_from_name ("DiaLibartRenderer") != 0);
1315
1316
1317 ddisplay_do_update_menu_sensitivity (ddisp);
1318
1319 gtk_toggle_action_set_active (rulers, display_get_rulers_showing(ddisp));
1320 gtk_toggle_action_set_active (visible_grid,
1321 ddisp->grid.visible);
1322 gtk_toggle_action_set_active (snap_to_grid,
1323 ddisp->grid.snap);
1324 gtk_toggle_action_set_active (show_cx_pts,
1325 ddisp->show_cx_pts);
1326
1327 gtk_toggle_action_set_active (antialiased,
1328 ddisp->aa_renderer);
1329 }
1330
1331 void
ddisplay_do_update_menu_sensitivity(DDisplay * ddisp)1332 ddisplay_do_update_menu_sensitivity (DDisplay *ddisp)
1333 {
1334 Diagram *dia;
1335
1336 if (ddisp == NULL) {
1337 return;
1338 }
1339 dia = ddisp->diagram;
1340 diagram_update_menu_sensitivity (dia);
1341 }
1342
1343
1344
1345 /* This is called when ddisp->shell is destroyed... */
1346 void
ddisplay_really_destroy(DDisplay * ddisp)1347 ddisplay_really_destroy(DDisplay *ddisp)
1348 {
1349 if (active_display == ddisp)
1350 display_set_active(NULL);
1351
1352 /* last chance to avoid crashing in the idle update */
1353 if (ddisp->update_id) {
1354 g_source_remove (ddisp->update_id);
1355 ddisp->update_id = 0;
1356 }
1357
1358 if (ddisp->diagram) {
1359 diagram_remove_ddisplay(ddisp->diagram, ddisp);
1360 /* if we are the last user of the diagram it will be unref'ed */
1361 g_object_unref(ddisp->diagram);
1362 ddisp->diagram = NULL;
1363 }
1364
1365 g_object_unref (ddisp->renderer);
1366 ddisp->renderer = NULL;
1367
1368 g_hash_table_remove(display_ht, ddisp->shell);
1369 g_hash_table_remove(display_ht, ddisp->canvas);
1370
1371 /* Free update_areas list: */
1372 ddisplay_free_update_areas(ddisp);
1373 /* Free display_areas list */
1374 ddisplay_free_display_areas(ddisp);
1375
1376 g_free(ddisp);
1377 }
1378
1379
1380 void
ddisplay_set_title(DDisplay * ddisp,char * title)1381 ddisplay_set_title(DDisplay *ddisp, char *title)
1382 {
1383 if (ddisp->is_standalone_window)
1384 gtk_window_set_title (GTK_WINDOW (ddisp->shell), title);
1385 else
1386 {
1387 GtkNotebook *notebook = g_object_get_data (G_OBJECT (ddisp->shell),
1388 DIA_MAIN_NOTEBOOK);
1389 /* Find the page with ddisp then set the label on the tab */
1390 gint num_pages = gtk_notebook_get_n_pages (notebook);
1391 gint num;
1392 GtkWidget *page;
1393 for (num = 0 ; num < num_pages ; num++)
1394 {
1395 page = gtk_notebook_get_nth_page (notebook,num);
1396 if (g_object_get_data (G_OBJECT (page), "DDisplay") == ddisp)
1397 {
1398 GtkLabel *label = g_object_get_data (G_OBJECT (page), "tab-label");
1399 /* not using the passed in title here, because it may be too long */
1400 gchar *name = diagram_get_name(ddisp->diagram);
1401 gtk_label_set_text(label,name);
1402 g_free(name);
1403 break;
1404 }
1405 }
1406 /* now modify the application window title */
1407 {
1408 const gchar *pname = g_get_prgname();
1409 gchar *fulltitle = g_strdup_printf ("%s - %s", title, pname ? pname : "Dia");
1410 gtk_window_set_title (GTK_WINDOW (ddisp->shell), fulltitle);
1411 g_free(fulltitle);
1412 }
1413 }
1414 }
1415
1416 void
ddisplay_set_all_cursor(GdkCursor * cursor)1417 ddisplay_set_all_cursor(GdkCursor *cursor)
1418 {
1419 Diagram *dia;
1420 DDisplay *ddisp;
1421 GList *list;
1422 GSList *slist;
1423
1424 current_cursor = cursor;
1425
1426 list = dia_open_diagrams();
1427 while (list != NULL) {
1428 dia = (Diagram *) list->data;
1429
1430 slist = dia->displays;
1431 while (slist != NULL) {
1432 ddisp = (DDisplay *) slist->data;
1433
1434 ddisplay_set_cursor(ddisp, cursor);
1435
1436 slist = g_slist_next(slist);
1437 }
1438
1439 list = g_list_next(list);
1440 }
1441 }
1442
1443 void
ddisplay_set_cursor(DDisplay * ddisp,GdkCursor * cursor)1444 ddisplay_set_cursor(DDisplay *ddisp, GdkCursor *cursor)
1445 {
1446 if (ddisp->canvas->window)
1447 gdk_window_set_cursor(ddisp->canvas->window, cursor);
1448 }
1449
1450 /** Returns whether the rulers are currently showing on the display.
1451 */
display_get_rulers_showing(DDisplay * ddisp)1452 gboolean display_get_rulers_showing(DDisplay *ddisp) {
1453 return ddisp->rulers_are_showing;
1454 }
1455
1456
1457 /**
1458 * Shows the rulers and sets flag ddisp->rulers_are_showing. This
1459 * is needed to detect whether a show() has been issued. There is a
1460 * delay between the time that gtk_widget_show() is called and the time
1461 * when GTK_WIDGET_IS_VISIBLE(w) will indicate true.
1462 * @param ddisp The display to show the rulers on.
1463 */
display_rulers_show(DDisplay * ddisp)1464 void display_rulers_show (DDisplay *ddisp)
1465 {
1466 if (ddisp)
1467 {
1468 GtkWidget *parent = GTK_WIDGET (ddisp->origin->parent);
1469
1470 gtk_widget_show (ddisp->origin);
1471 gtk_widget_show (ddisp->hrule);
1472 gtk_widget_show (ddisp->vrule);
1473
1474 if (GTK_WIDGET_VISIBLE (parent))
1475 gtk_widget_queue_resize (parent);
1476
1477 ddisp->rulers_are_showing = TRUE;
1478 }
1479 }
1480
1481 /**
1482 * Hides the rulers and resets the flag ddisp->rulers_are_showing. This
1483 * is needed to detect whether a hide() has been issued. There is a
1484 * delay between the time that gtk_widget_hide() is called and the time
1485 * when GTK_WIDGET_IS_VISIBLE(w) will indicate false.
1486 * @param ddisp The display to hide the rulers on.
1487 */
display_rulers_hide(DDisplay * ddisp)1488 void display_rulers_hide (DDisplay *ddisp)
1489 {
1490 if (ddisp)
1491 {
1492 GtkWidget *parent = GTK_WIDGET (ddisp->origin->parent);
1493
1494 gtk_widget_hide (ddisp->origin);
1495 gtk_widget_hide (ddisp->hrule);
1496 gtk_widget_hide (ddisp->vrule);
1497
1498 if (GTK_WIDGET_VISIBLE (parent))
1499 gtk_widget_queue_resize (parent);
1500
1501 ddisp->rulers_are_showing = FALSE;
1502 }
1503 }
1504
1505 void
ddisplay_update_statusbar(DDisplay * ddisp)1506 ddisplay_update_statusbar(DDisplay *ddisp)
1507 {
1508 update_zoom_status (ddisp);
1509 update_snap_grid_status (ddisp);
1510 update_mainpoint_status (ddisp);
1511 }
1512
1513 void
display_set_active(DDisplay * ddisp)1514 display_set_active(DDisplay *ddisp)
1515 {
1516 if (ddisp != active_display) {
1517 active_display = ddisp;
1518
1519 /* perform notification here (such as switch layers dialog) */
1520 layer_dialog_set_diagram(ddisp ? ddisp->diagram : NULL);
1521 diagram_properties_set_diagram(ddisp ? ddisp->diagram : NULL);
1522
1523 if (ddisp) {
1524 if (ddisp->is_standalone_window)
1525 {
1526 display_update_menu_state(ddisp);
1527
1528 if (prefs.toolbox_on_top) {
1529 gtk_window_set_transient_for(GTK_WINDOW(interface_get_toolbox_shell()),
1530 GTK_WINDOW(ddisp->shell));
1531 } else {
1532 gtk_window_set_transient_for(GTK_WINDOW(interface_get_toolbox_shell()),
1533 NULL);
1534 }
1535 } else {
1536 GtkNotebook *notebook = g_object_get_data (G_OBJECT (ddisp->shell),
1537 DIA_MAIN_NOTEBOOK);
1538 /* Find the page with ddisp then set the label on the tab */
1539 gint num_pages = gtk_notebook_get_n_pages (notebook);
1540 gint num;
1541 GtkWidget *page;
1542 for (num = 0 ; num < num_pages ; num++)
1543 {
1544 page = gtk_notebook_get_nth_page (notebook,num);
1545 if (g_object_get_data (G_OBJECT (page), "DDisplay") == ddisp)
1546 {
1547 gtk_notebook_set_current_page (notebook,num);
1548 break;
1549 }
1550 }
1551 /* synchronize_ui_to_active_display (ddisp); */
1552 /* updates display title, etc */
1553 diagram_modified(ddisp->diagram);
1554
1555 /* ZOOM */
1556 update_zoom_status (ddisp);
1557
1558 /* Snap to grid */
1559 ddisplay_set_snap_to_grid (ddisp, ddisp->grid.snap); /* menus */
1560
1561 /* Object snapping */
1562 ddisplay_set_snap_to_objects (ddisp, ddisp->mainpoint_magnetism);
1563
1564 display_update_menu_state (ddisp);
1565
1566 gtk_window_present (GTK_WINDOW(ddisp->shell));
1567 }
1568 } else {
1569 /* TODO: Prevent gtk_window_set_transient_for() in Integrated UI case */
1570 gtk_window_set_transient_for(GTK_WINDOW(interface_get_toolbox_shell()),
1571 NULL);
1572 }
1573 }
1574 }
1575
1576 void
ddisplay_im_context_preedit_reset(DDisplay * ddisp,Focus * focus)1577 ddisplay_im_context_preedit_reset(DDisplay *ddisp, Focus *focus)
1578 {
1579 if (ddisp->preedit_string != NULL) {
1580 if (focus != NULL) {
1581 int i;
1582 ObjectChange *change;
1583
1584 for (i = 0; i < g_utf8_strlen(ddisp->preedit_string, -1); i++) {
1585 (focus->key_event)(focus, GDK_BackSpace, NULL, 0, &change);
1586 }
1587 }
1588
1589 g_free(ddisp->preedit_string);
1590 ddisp->preedit_string = NULL;
1591 }
1592 if (ddisp->preedit_attrs != NULL) {
1593 pango_attr_list_unref(ddisp->preedit_attrs);
1594 ddisp->preedit_attrs = NULL;
1595 }
1596 }
1597
1598 /** Get the active focus for the given display, or NULL.
1599 *
1600 * @param ddisp Display to get active focus for. This display need not
1601 * be the currently active display.
1602 * @returns The focus that is active for the given display, or NULL if no
1603 * focus is active (i.e. no text is being edited).
1604 */
1605 Focus *
ddisplay_active_focus(DDisplay * ddisp)1606 ddisplay_active_focus(DDisplay *ddisp)
1607 {
1608 return ddisp ? ddisp->active_focus : NULL;
1609 }
1610
1611 /** Set the currently active focus for this display. This field should be
1612 * set to non-null when a text is being edited and to null when no text
1613 * is being edited. Only textedit.c really needs to call this function.
1614 *
1615 * @param ddisp The display to set active focus for.
1616 * @param focus The focus that should be active for this display. May be
1617 * NULL, indicating that no text is currently being edited on
1618 * this display.
1619 */
1620 void
ddisplay_set_active_focus(DDisplay * ddisp,Focus * focus)1621 ddisplay_set_active_focus(DDisplay *ddisp, Focus *focus)
1622 {
1623 ddisp->active_focus = focus;
1624 }
1625
1626 void
ddisplay_show_all(DDisplay * ddisp)1627 ddisplay_show_all (DDisplay *ddisp)
1628 {
1629 Diagram *dia;
1630 real magnify_x, magnify_y;
1631 int width, height;
1632 Point middle;
1633
1634 g_return_if_fail (ddisp != NULL);
1635
1636 dia = ddisp->diagram;
1637
1638 width = dia_renderer_get_width_pixels (ddisp->renderer);
1639 height = dia_renderer_get_height_pixels (ddisp->renderer);
1640
1641 /* if there is something selected show that instead of all exisiting objects */
1642 if (dia->data->selected) {
1643 GList *list = dia->data->selected;
1644 Rectangle extents = *dia_object_get_enclosing_box ((DiaObject*)list->data);
1645 list = g_list_next(list);
1646 while (list) {
1647 DiaObject *obj = (DiaObject *)list->data;
1648 rectangle_union(&extents, dia_object_get_enclosing_box (obj));
1649 list = g_list_next(list);
1650 }
1651 magnify_x = (real)width / (extents.right - extents.left) / ddisp->zoom_factor;
1652 magnify_y = (real)height / (extents.bottom - extents.top) / ddisp->zoom_factor;
1653 middle.x = extents.left + (extents.right - extents.left) / 2.0;
1654 middle.y = extents.top + (extents.bottom - extents.top) / 2.0;
1655 } else {
1656 magnify_x = (real)width /
1657 (dia->data->extents.right - dia->data->extents.left) / ddisp->zoom_factor;
1658 magnify_y = (real)height /
1659 (dia->data->extents.bottom - dia->data->extents.top) / ddisp->zoom_factor;
1660
1661 middle.x = dia->data->extents.left +
1662 (dia->data->extents.right - dia->data->extents.left) / 2.0;
1663 middle.y = dia->data->extents.top +
1664 (dia->data->extents.bottom - dia->data->extents.top) / 2.0;
1665 }
1666
1667 ddisplay_zoom (ddisp, &middle,
1668 ((magnify_x<magnify_y)?magnify_x:magnify_y)/1.05);
1669
1670 ddisplay_update_scrollbars(ddisp);
1671 ddisplay_add_update_all(ddisp);
1672 ddisplay_flush(ddisp);
1673 }
1674