UML class fix bigtime.
[dia.git] / app / display.c
blob01be5ca4a09cf1a93fc5cbc502e8320b700330fe
1 /* Dia -- an diagram creation/manipulation program
2 * Copyright (C) 1998 Alexander Larsson
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
23 #include <string.h>
24 #include <stdio.h>
25 #include <math.h>
26 #include <gdk/gdkkeysyms.h>
28 #ifdef GNOME
29 #include <gnome.h>
30 #endif
32 #include "intl.h"
34 #include "display.h"
35 #include "group.h"
36 #include "interface.h"
37 #include "focus.h"
38 #include "color.h"
39 #include "handle_ops.h"
40 #include "connectionpoint_ops.h"
41 #include "menus.h"
42 #include "cut_n_paste.h"
43 #include "message.h"
44 #include "preferences.h"
45 #include "app_procs.h"
46 #include "layer_dialog.h"
47 #include "load_save.h"
48 #include "dia-props.h"
49 #include "render_gdk.h"
50 #include "render_libart.h"
52 static GHashTable *display_ht = NULL;
53 static GdkCursor *current_cursor = NULL;
55 GdkCursor *default_cursor = NULL;
57 static DDisplay *active_display = NULL;
60 typedef struct _IRectangle {
61 int top, bottom;
62 int left,right;
63 } IRectangle;
65 static guint display_hash(DDisplay *ddisp);
67 static void
68 update_zoom_status(DDisplay *ddisp)
70 GtkWidget *zoomcombo;
71 gchar zoom_text[7];
73 zoomcombo = ddisp->zoom_status;
74 sprintf (zoom_text, "%.1f%%",
75 ddisp->zoom_factor * 100.0 / DDISPLAY_NORMAL_ZOOM);
76 gtk_entry_set_text(GTK_ENTRY(gtk_object_get_user_data(GTK_OBJECT(zoomcombo))),
77 zoom_text);
80 static void
81 update_modified_status(DDisplay *ddisp)
83 GtkStatusbar *statusbar;
84 guint context_id;
86 if (diagram_is_modified(ddisp->diagram))
88 statusbar = GTK_STATUSBAR (ddisp->modified_status);
89 context_id = gtk_statusbar_get_context_id (statusbar, "Changed");
91 gtk_statusbar_pop (statusbar, context_id);
92 gtk_statusbar_push (statusbar, context_id, _("Diagram modified!"));
94 else
96 statusbar = GTK_STATUSBAR (ddisp->modified_status);
97 context_id = gtk_statusbar_get_context_id (statusbar, "Changed");
99 gtk_statusbar_pop (statusbar, context_id);
103 static void
104 selection_changed (Diagram* dia, int n, DDisplay* ddisp)
106 GtkStatusbar *statusbar;
107 guint context_id;
109 statusbar = GTK_STATUSBAR (ddisp->modified_status);
110 context_id = gtk_statusbar_get_context_id (statusbar, "Selection");
112 if (n > 1)
114 gchar *msg;
116 msg = g_strdup_printf (_("Selection of %d objects"), n);
117 gtk_statusbar_pop (statusbar, context_id);
118 gtk_statusbar_push (statusbar, context_id, msg);
119 g_free (msg);
121 else if (n == 1)
123 /* find the selected objects name - and display it */
124 DiaObject *object = (DiaObject *)ddisp->diagram->data->selected->data;
125 gchar *name = object_get_displayname (object);
126 gchar *msg = g_strdup_printf (_("Selected '%s'"), name);
128 gtk_statusbar_pop (statusbar, context_id);
129 gtk_statusbar_push (statusbar, context_id, msg);
131 g_free (name);
132 g_free (msg);
134 else
136 gtk_statusbar_pop (statusbar, context_id);
140 DDisplay *
141 new_display(Diagram *dia)
143 DDisplay *ddisp;
144 char *filename;
145 int embedded = app_is_embedded();
146 Rectangle visible;
147 GtkMenuItem* im_menu_item;
148 GtkWidget* im_menu;
149 GtkWidget* im_menu_tearoff;
150 static gboolean input_methods_done = FALSE;
152 ddisp = g_new0(DDisplay,1);
154 ddisp->menu_bar = NULL;
155 ddisp->mbar_item_factory = NULL;
157 ddisp->rulers = NULL;
159 ddisp->visible_grid = NULL;
160 ddisp->snap_to_grid = NULL;
161 ddisp->show_cx_pts_mitem = NULL;
162 #ifdef HAVE_LIBART
163 ddisp->antialiased = NULL;
164 #endif
166 /* initialize the whole struct to 0 so that we are sure to catch errors.*/
167 memset (&ddisp->updatable_menu_items, 0, sizeof (UpdatableMenuItems));
169 ddisp->diagram = dia;
170 /* Every display has it's own reference */
171 g_object_ref(dia);
173 ddisp->grid.visible = prefs.grid.visible;
174 ddisp->grid.snap = prefs.grid.snap;
176 ddisp->show_cx_pts = prefs.show_cx_pts;
178 ddisp->autoscroll = TRUE;
179 ddisp->mainpoint_magnetism = TRUE;
181 ddisp->aa_renderer = 0;
182 ddisp->renderer = new_gdk_renderer(ddisp);
184 ddisp->update_areas = NULL;
185 ddisp->display_areas = NULL;
186 ddisp->update_id = 0;
188 filename = strrchr(dia->filename, G_DIR_SEPARATOR);
189 if (filename==NULL) {
190 filename = dia->filename;
191 } else {
192 filename++;
195 diagram_add_ddisplay(dia, ddisp);
196 g_signal_connect (dia, "selection_changed", G_CALLBACK(selection_changed), ddisp);
197 ddisp->origo.x = 0.0;
198 ddisp->origo.y = 0.0;
199 ddisp->zoom_factor = prefs.new_view.zoom/100.0*DDISPLAY_NORMAL_ZOOM;
200 if ((ddisp->diagram) && (ddisp->diagram->data)) {
201 Rectangle *extents = &ddisp->diagram->data->extents;
203 visible.left = extents->left;
204 visible.top = extents->top;
205 } else {
206 visible.left = 0.0;
207 visible.top = 0.0;
209 visible.right = visible.left + prefs.new_view.width/ddisp->zoom_factor;
210 visible.bottom = visible.top + prefs.new_view.height/ddisp->zoom_factor;
212 ddisp->visible = visible;
214 ddisp->im_context = gtk_im_multicontext_new();
215 g_signal_connect (G_OBJECT (ddisp->im_context), "commit",
216 G_CALLBACK (ddisplay_im_context_commit), ddisp);
217 ddisp->preedit_string = NULL;
218 g_signal_connect (G_OBJECT (ddisp->im_context), "preedit_changed",
219 G_CALLBACK (ddisplay_im_context_preedit_changed),
220 ddisp);
221 ddisp->preedit_attrs = NULL;
223 create_display_shell(ddisp, prefs.new_view.width, prefs.new_view.height,
224 filename, prefs.new_view.use_menu_bar, !embedded);
226 ddisplay_update_statusbar (ddisp);
228 ddisplay_set_origo(ddisp, visible.left, visible.top);
229 ddisp->visible = visible; /* force the visible area extents */
230 ddisplay_update_scrollbars(ddisp);
231 ddisplay_add_update_all(ddisp);
233 if (!display_ht)
234 display_ht = g_hash_table_new ((GHashFunc) display_hash, NULL);
236 if (!embedded)
237 ddisplay_set_cursor(ddisp, current_cursor);
239 g_hash_table_insert (display_ht, ddisp->shell, ddisp);
240 g_hash_table_insert (display_ht, ddisp->canvas, ddisp);
243 if (!input_methods_done) {
244 im_menu_item = menus_get_item_from_path("<Display>/Input Methods", NULL);
245 if (im_menu_item) {
246 im_menu = gtk_menu_new();
247 im_menu_tearoff = gtk_tearoff_menu_item_new();
248 gtk_menu_shell_append(GTK_MENU_SHELL(im_menu),im_menu_tearoff);
249 gtk_im_multicontext_append_menuitems(
250 GTK_IM_MULTICONTEXT(ddisp->im_context),
251 GTK_MENU_SHELL(im_menu));
253 gtk_menu_item_set_submenu( GTK_MENU_ITEM(im_menu_item), im_menu);
254 input_methods_done = TRUE;
258 return ddisp; /* set the user data */
261 static guint
262 display_hash(DDisplay *ddisp)
264 return (gulong) ddisp;
267 void
268 ddisplay_transform_coords_double(DDisplay *ddisp,
269 coord x, coord y,
270 double *xi, double *yi)
272 Rectangle *visible = &ddisp->visible;
273 double width = dia_renderer_get_width_pixels (ddisp->renderer);
274 double height = dia_renderer_get_height_pixels (ddisp->renderer);
276 *xi = (x - visible->left) * (real)width / (visible->right - visible->left);
277 *yi = (y - visible->top) * (real)height / (visible->bottom - visible->top);
281 void
282 ddisplay_transform_coords(DDisplay *ddisp,
283 coord x, coord y,
284 int *xi, int *yi)
286 Rectangle *visible = &ddisp->visible;
287 int width = dia_renderer_get_width_pixels (ddisp->renderer);
288 int height = dia_renderer_get_height_pixels (ddisp->renderer);
290 *xi = ROUND ( (x - visible->left) * (real)width /
291 (visible->right - visible->left) );
292 *yi = ROUND ( (y - visible->top) * (real)height /
293 (visible->bottom - visible->top) );
296 /* Takes real length and returns pixel length */
297 real
298 ddisplay_transform_length(DDisplay *ddisp, real len)
300 return len * ddisp->zoom_factor;
303 /* Takes pixel length and returns real length */
304 real
305 ddisplay_untransform_length(DDisplay *ddisp, real len)
307 return len / ddisp->zoom_factor;
311 void
312 ddisplay_untransform_coords(DDisplay *ddisp,
313 int xi, int yi,
314 coord *x, coord *y)
316 Rectangle *visible = &ddisp->visible;
317 int width = dia_renderer_get_width_pixels (ddisp->renderer);
318 int height = dia_renderer_get_height_pixels (ddisp->renderer);
320 *x = visible->left + xi*(visible->right - visible->left) / (real)width;
321 *y = visible->top + yi*(visible->bottom - visible->top) / (real)height;
325 void
326 ddisplay_add_update_pixels(DDisplay *ddisp, Point *point,
327 int pixel_width, int pixel_height)
329 Rectangle rect;
330 real size_x, size_y;
332 size_x = ddisplay_untransform_length(ddisp, pixel_width+1);
333 size_y = ddisplay_untransform_length(ddisp, pixel_height+1);
335 rect.left = point->x - size_x/2.0;
336 rect.top = point->y - size_y/2.0;
337 rect.right = point->x + size_x/2.0;
338 rect.bottom = point->y + size_y/2.0;
340 ddisplay_add_update(ddisp, &rect);
343 /** Free display_areas list */
344 static void
345 ddisplay_free_display_areas(DDisplay *ddisp)
347 GSList *l;
348 l = ddisp->display_areas;
349 while(l!=NULL) {
350 g_free(l->data);
351 l = g_slist_next(l);
353 g_slist_free(ddisp->display_areas);
354 ddisp->display_areas = NULL;
357 /** Free update_areas list */
358 static void
359 ddisplay_free_update_areas(DDisplay *ddisp)
361 GSList *l;
362 l = ddisp->update_areas;
363 while(l!=NULL) {
364 g_free(l->data);
365 l = g_slist_next(l);
367 g_slist_free(ddisp->update_areas);
368 ddisp->update_areas = NULL;
371 /** Marks the entire visible area for update.
372 * Throws out old updates, since everything will be updated anyway.
374 void
375 ddisplay_add_update_all(DDisplay *ddisp)
377 if (ddisp->update_areas != NULL) {
378 ddisplay_free_update_areas(ddisp);
380 if (ddisp->display_areas != NULL) {
381 ddisplay_free_display_areas(ddisp);
383 ddisplay_add_update(ddisp, &ddisp->visible);
386 /** Marks a rectangle for update, with a pixel border around it.
388 void
389 ddisplay_add_update_with_border(DDisplay *ddisp, Rectangle *rect,
390 int pixel_border)
392 Rectangle r;
393 real size = ddisplay_untransform_length(ddisp, pixel_border+1);
395 r.left = rect->left-size;
396 r.top = rect->top-size;
397 r.right = rect->right+size;
398 r.bottom = rect->bottom+size;
400 ddisplay_add_update(ddisp, &r);
403 void
404 ddisplay_add_update(DDisplay *ddisp, Rectangle *rect)
406 Rectangle *r;
407 int top,bottom,left,right;
408 Rectangle *visible;
409 int width = dia_renderer_get_width_pixels (ddisp->renderer);
410 int height = dia_renderer_get_height_pixels (ddisp->renderer);
412 if (!rectangle_intersects(rect, &ddisp->visible))
413 return;
415 /* Temporarily just do a union of all rectangles: */
416 if (ddisp->update_areas==NULL) {
417 r = g_new(Rectangle,1);
418 *r = *rect;
419 rectangle_intersection(r, &ddisp->visible);
420 ddisp->update_areas = g_slist_prepend(ddisp->update_areas, r);
421 } else {
422 r = (Rectangle *) ddisp->update_areas->data;
423 rectangle_union(r, rect);
424 rectangle_intersection(r, &ddisp->visible);
427 visible = &ddisp->visible;
428 left = floor( (r->left - visible->left) * (real)width /
429 (visible->right - visible->left) ) - 1;
430 top = floor( (r->top - visible->top) * (real)height /
431 (visible->bottom - visible->top) ) - 1;
432 right = ceil( (r->right - visible->left) * (real)width /
433 (visible->right - visible->left) ) + 1;
434 bottom = ceil( (r->bottom - visible->top) * (real)height /
435 (visible->bottom - visible->top) ) + 1;
437 ddisplay_add_display_area(ddisp,
438 left, top,
439 right, bottom);
442 void
443 ddisplay_add_display_area(DDisplay *ddisp,
444 int left, int top,
445 int right, int bottom)
447 IRectangle *r;
449 if (left < 0)
450 left = 0;
451 if (top < 0)
452 top = 0;
453 if (right > dia_renderer_get_width_pixels (ddisp->renderer))
454 right = dia_renderer_get_width_pixels (ddisp->renderer);
455 if (bottom > dia_renderer_get_height_pixels (ddisp->renderer))
456 bottom = dia_renderer_get_height_pixels (ddisp->renderer);
458 /* draw some rectangles to show where updates are...*/
459 /* gdk_draw_rectangle(ddisp->canvas->window, ddisp->canvas->style->black_gc, TRUE, left, top, right-left,bottom-top); */
461 /* Temporarily just do a union of all Irectangles: */
462 if (ddisp->display_areas==NULL) {
463 r = g_new(IRectangle,1);
464 r->top = top; r->bottom = bottom;
465 r->left = left; r->right = right;
466 ddisp->display_areas = g_slist_prepend(ddisp->display_areas, r);
467 } else {
468 r = (IRectangle *) ddisp->display_areas->data;
470 r->top = MIN( r->top, top );
471 r->bottom = MAX( r->bottom, bottom );
472 r->left = MIN( r->left, left );
473 r->right = MAX( r->right, right );
477 static gboolean
478 ddisplay_update_handler(DDisplay *ddisp)
480 GSList *l;
481 IRectangle *ir;
482 Rectangle *r, totrect;
483 DiaInteractiveRendererInterface *renderer;
485 /* Renders updates to pixmap + copies display_areas to canvas(screen) */
486 renderer = DIA_GET_INTERACTIVE_RENDERER_INTERFACE (ddisp->renderer);
488 /* Only update if update_areas exist */
489 l = ddisp->update_areas;
490 if (l != NULL)
492 totrect = *(Rectangle *) l->data;
494 g_return_val_if_fail ( renderer->clip_region_clear != NULL
495 && renderer->clip_region_add_rect != NULL, FALSE);
497 renderer->clip_region_clear (ddisp->renderer);
499 while(l!=NULL) {
500 r = (Rectangle *) l->data;
502 rectangle_union(&totrect, r);
503 renderer->clip_region_add_rect (ddisp->renderer, r);
505 l = g_slist_next(l);
507 /* Free update_areas list: */
508 ddisplay_free_update_areas(ddisp);
510 totrect.left -= 0.1;
511 totrect.right += 0.1;
512 totrect.top -= 0.1;
513 totrect.bottom += 0.1;
515 ddisplay_render_pixmap(ddisp, &totrect);
518 l = ddisp->display_areas;
519 while(l!=NULL) {
520 ir = (IRectangle *) l->data;
522 g_return_val_if_fail (renderer->copy_to_window, FALSE);
523 renderer->copy_to_window(ddisp->renderer,
524 ddisp->canvas->window,
525 ir->left, ir->top,
526 ir->right - ir->left, ir->bottom - ir->top);
528 l = g_slist_next(l);
531 ddisplay_free_display_areas(ddisp);
533 ddisp->update_id = 0;
535 return FALSE;
538 void
539 ddisplay_flush(DDisplay *ddisp)
541 /* if no update is queued, queue update */
542 if (!ddisp->update_id)
543 ddisp->update_id = gtk_idle_add((GtkFunction) ddisplay_update_handler,
544 ddisp);
547 static void
548 ddisplay_obj_render(DiaObject *obj, DiaRenderer *renderer,
549 int active_layer,
550 gpointer data)
552 DDisplay *ddisp = (DDisplay *)data;
553 int i;
555 DIA_RENDERER_GET_CLASS(renderer)->draw_object(renderer, obj);
556 if (ddisp->show_cx_pts &&
557 obj->parent_layer != NULL && obj->parent_layer->connectable) {
558 for (i=0;i<obj->num_connections;i++) {
559 connectionpoint_draw(obj->connections[i], ddisp);
564 void
565 ddisplay_render_pixmap(DDisplay *ddisp, Rectangle *update)
567 GList *list;
568 DiaObject *obj;
569 int i;
570 DiaInteractiveRendererInterface *renderer;
571 GTimer *timer;
573 if (ddisp->renderer==NULL) {
574 printf("ERROR! Renderer was NULL!!\n");
575 return;
578 renderer = DIA_GET_INTERACTIVE_RENDERER_INTERFACE (ddisp->renderer);
580 /* Erase background */
581 g_return_if_fail (renderer->fill_pixel_rect != NULL);
582 DIA_RENDERER_GET_CLASS(ddisp->renderer)->begin_render(ddisp->renderer);
583 renderer->fill_pixel_rect (ddisp->renderer,
584 0, 0,
585 dia_renderer_get_width_pixels (ddisp->renderer),
586 dia_renderer_get_height_pixels (ddisp->renderer),
587 &ddisp->diagram->data->bg_color);
589 /* Draw grid */
590 grid_draw(ddisp, update);
591 pagebreak_draw(ddisp, update);
593 timer = g_timer_new();
594 data_render(ddisp->diagram->data, ddisp->renderer, update,
595 ddisplay_obj_render, (gpointer) ddisp);
596 g_print ("data_render(%g%%) took %g seconds\n", ddisp->zoom_factor * 5.0, g_timer_elapsed (timer, NULL));
597 g_timer_destroy (timer);
598 /* Draw handles for all selected objects */
599 list = ddisp->diagram->data->selected;
600 while (list!=NULL) {
601 obj = (DiaObject *) list->data;
603 for (i=0;i<obj->num_handles;i++) {
604 handle_draw(obj->handles[i], ddisp);
606 list = g_list_next(list);
608 DIA_RENDERER_GET_CLASS(ddisp->renderer)->end_render(ddisp->renderer);
611 void
612 ddisplay_update_scrollbars(DDisplay *ddisp)
614 Rectangle *extents = &ddisp->diagram->data->extents;
615 Rectangle *visible = &ddisp->visible;
616 GtkAdjustment *hsbdata, *vsbdata;
618 hsbdata = ddisp->hsbdata;
619 /* Horizontal: */
620 hsbdata->lower = MIN(extents->left, visible->left);
621 hsbdata->upper = MAX(extents->right, visible->right);
622 hsbdata->page_size = visible->right - visible->left - 0.0001;
623 /* remove some to fix strange behaviour in gtk_range_adjustment_changed */
624 hsbdata->page_increment = (visible->right - visible->left) / 2.0;
625 hsbdata->step_increment = (visible->right - visible->left) / 10.0;
626 hsbdata->value = visible->left;
628 g_signal_emit_by_name (G_OBJECT (ddisp->hsbdata), "changed");
630 /* Vertical: */
631 vsbdata = ddisp->vsbdata;
632 vsbdata->lower = MIN(extents->top, visible->top);
633 vsbdata->upper = MAX(extents->bottom, visible->bottom);
634 vsbdata->page_size = visible->bottom - visible->top - 0.00001;
635 /* remove some to fix strange behaviour in gtk_range_adjustment_changed */
636 vsbdata->page_increment = (visible->bottom - visible->top) / 2.0;
637 vsbdata->step_increment = (visible->bottom - visible->top) / 10.0;
638 vsbdata->value = visible->top;
640 g_signal_emit_by_name (G_OBJECT (ddisp->vsbdata), "changed");
643 void
644 ddisplay_set_origo(DDisplay *ddisp, coord x, coord y)
646 Rectangle *extents = &ddisp->diagram->data->extents;
647 Rectangle *visible = &ddisp->visible;
648 int width, height;
650 /* updaterar origo+visible+rulers */
651 ddisp->origo.x = x;
652 ddisp->origo.y = y;
654 if (ddisp->zoom_factor<DDISPLAY_MIN_ZOOM)
655 ddisp->zoom_factor = DDISPLAY_MIN_ZOOM;
657 if (ddisp->zoom_factor > DDISPLAY_MAX_ZOOM)
658 ddisp->zoom_factor = DDISPLAY_MAX_ZOOM;
660 width = dia_renderer_get_width_pixels (ddisp->renderer);
661 height = dia_renderer_get_height_pixels (ddisp->renderer);
663 visible->left = ddisp->origo.x;
664 visible->top = ddisp->origo.y;
665 visible->right = ddisp->origo.x + ddisplay_untransform_length(ddisp, width);
666 visible->bottom = ddisp->origo.y + ddisplay_untransform_length(ddisp, height);
668 gtk_ruler_set_range (GTK_RULER (ddisp->hrule),
669 visible->left,
670 visible->right,
671 0.0f /* position*/,
672 MAX(extents->right, visible->right)/* max_size*/);
673 gtk_ruler_set_range (GTK_RULER (ddisp->vrule),
674 visible->top,
675 visible->bottom,
676 0.0f /* position*/,
677 MAX(extents->bottom, visible->bottom)/* max_size*/);
680 void
681 ddisplay_zoom(DDisplay *ddisp, Point *point, real magnify)
683 Rectangle *visible;
684 real width, height;
686 visible = &ddisp->visible;
688 width = (visible->right - visible->left)/magnify;
689 height = (visible->bottom - visible->top)/magnify;
691 if ((ddisp->zoom_factor <= DDISPLAY_MIN_ZOOM) && (magnify<=1.0))
692 return;
693 if ((ddisp->zoom_factor >= DDISPLAY_MAX_ZOOM) && (magnify>=1.0))
694 return;
696 ddisp->zoom_factor *= magnify;
698 ddisplay_set_origo(ddisp, point->x - width/2.0, point->y - height/2.0);
700 ddisplay_update_scrollbars(ddisp);
701 ddisplay_add_update_all(ddisp);
702 ddisplay_flush(ddisp);
704 update_zoom_status (ddisp);
707 /** Set the display's snap-to-grid setting, updating menu and button
708 * in the process */
709 void
710 ddisplay_set_snap_to_grid(DDisplay *ddisp, gboolean snap)
712 GtkCheckMenuItem *snap_to_grid;
713 ddisp->grid.snap = snap;
715 if (ddisp->menu_bar == NULL) {
716 snap_to_grid = GTK_CHECK_MENU_ITEM(menus_get_item_from_path("<Display>/View/Snap To Grid", NULL));
717 } else {
718 snap_to_grid = GTK_CHECK_MENU_ITEM(menus_get_item_from_path("<DisplayMBar>/View/Snap To Grid", ddisp->mbar_item_factory));
721 /* Currently, this can cause double emit, but that's a small problem.
723 gtk_check_menu_item_set_active(snap_to_grid,
724 ddisp->grid.snap);
725 ddisplay_update_statusbar(ddisp);
728 /** Update the button showing whether snap-to-grid is on */
729 static void
730 update_snap_grid_status(DDisplay *ddisp)
732 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ddisp->grid_status),
733 ddisp->grid.snap);
736 /** Set the display's mainpoint magnetism setting, updating menu and button
737 * in the process */
738 void
739 ddisplay_set_snap_to_objects(DDisplay *ddisp, gboolean magnetic)
741 GtkCheckMenuItem *mainpoint_magnetism;
742 ddisp->mainpoint_magnetism = magnetic;
744 if (ddisp->menu_bar == NULL) {
745 mainpoint_magnetism = GTK_CHECK_MENU_ITEM(menus_get_item_from_path("<Display>/View/Snap To Objects", NULL));
746 } else {
747 mainpoint_magnetism = GTK_CHECK_MENU_ITEM(menus_get_item_from_path("<DisplayMBar>/View/Snap To Objects", ddisp->mbar_item_factory));
750 /* Currently, this can cause double emit, but that's a small problem.
752 gtk_check_menu_item_set_active(mainpoint_magnetism,
753 ddisp->mainpoint_magnetism);
754 ddisplay_update_statusbar(ddisp);
757 /** Update the button showing whether mainpoint magnetism is on */
758 static void
759 update_mainpoint_status(DDisplay *ddisp)
761 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ddisp->mainpoint_status),
762 ddisp->mainpoint_magnetism);
765 /** Scroll display to where point x,y (window coords) is visible */
766 gboolean
767 ddisplay_autoscroll(DDisplay *ddisp, int x, int y)
769 guint16 width, height;
770 Point scroll;
772 if (! ddisp->autoscroll)
773 return FALSE;
775 scroll.x = scroll.y = 0;
777 width = GTK_WIDGET(ddisp->canvas)->allocation.width;
778 height = GTK_WIDGET(ddisp->canvas)->allocation.height;
780 if (x < 0)
782 scroll.x = x;
784 else if ( x > width)
786 scroll.x = x - width;
789 if (y < 0)
791 scroll.y = y;
793 else if (y > height)
795 scroll.y = y - height;
798 if ((scroll.x != 0) || (scroll.y != 0))
800 gboolean scrolled;
802 scroll.x = ddisplay_untransform_length(ddisp, scroll.x);
803 scroll.y = ddisplay_untransform_length(ddisp, scroll.y);
805 scrolled = ddisplay_scroll(ddisp, &scroll);
807 if (scrolled) {
808 ddisplay_flush(ddisp);
809 return TRUE;
812 return FALSE;
815 /** Scroll the display by delta (diagram coords) */
816 gboolean
817 ddisplay_scroll(DDisplay *ddisp, Point *delta)
819 Rectangle *visible = &ddisp->visible;
820 real width = visible->right - visible->left;
821 real height = visible->bottom - visible->top;
823 Rectangle extents = ddisp->diagram->data->extents;
824 real ex_width = extents.right - extents.left;
825 real ex_height = extents.bottom - extents.top;
827 Point new_origo = ddisp->origo;
828 point_add(&new_origo, delta);
830 rectangle_union(&extents, visible);
832 if (new_origo.x < extents.left - ex_width)
833 new_origo.x = extents.left - ex_width;
835 if (new_origo.x+width > extents.right + ex_width)
836 new_origo.x = extents.right - width + ex_width;
838 if (new_origo.y < extents.top - ex_height)
839 new_origo.y = extents.top - ex_height;
841 if (new_origo.y+height > extents.bottom + ex_height)
842 new_origo.y = extents.bottom - height + ex_height;
844 if ( (new_origo.x != ddisp->origo.x) ||
845 (new_origo.y != ddisp->origo.y) ) {
846 ddisplay_set_origo(ddisp, new_origo.x, new_origo.y);
847 ddisplay_update_scrollbars(ddisp);
848 ddisplay_add_update_all(ddisp);
849 return TRUE;
851 return FALSE;
854 void ddisplay_scroll_up(DDisplay *ddisp)
856 Point delta;
858 delta.x = 0;
859 delta.y = -(ddisp->visible.bottom - ddisp->visible.top)/4.0;
861 ddisplay_scroll(ddisp, &delta);
864 void ddisplay_scroll_down(DDisplay *ddisp)
866 Point delta;
868 delta.x = 0;
869 delta.y = (ddisp->visible.bottom - ddisp->visible.top)/4.0;
871 ddisplay_scroll(ddisp, &delta);
874 void ddisplay_scroll_left(DDisplay *ddisp)
876 Point delta;
878 delta.x = -(ddisp->visible.right - ddisp->visible.left)/4.0;
879 delta.y = 0;
881 ddisplay_scroll(ddisp, &delta);
884 void ddisplay_scroll_right(DDisplay *ddisp)
886 Point delta;
888 delta.x = (ddisp->visible.right - ddisp->visible.left)/4.0;
889 delta.y = 0;
891 ddisplay_scroll(ddisp, &delta);
894 /** Scroll display to have the diagram point p at the center.
895 * Returns TRUE if anything changed. */
896 gboolean
897 ddisplay_scroll_center_point(DDisplay *ddisp, Point *p)
899 Point center;
901 /* Find current center */
902 center.x = (ddisp->visible.right+ddisp->visible.left)/2;
903 center.y = (ddisp->visible.top+ddisp->visible.bottom)/2;
905 point_sub(p, &center);
906 return ddisplay_scroll(ddisp, p);
909 /** Scroll display so that obj is centered.
910 * Returns TRUE if anything changed. */
911 gboolean
912 ddisplay_scroll_to_object(DDisplay *ddisp, DiaObject *obj)
914 Rectangle r = obj->bounding_box;
916 Point p;
917 p.x = (r.left+r.right)/2;
918 p.y = (r.top+r.bottom)/2;
920 return ddisplay_scroll_center_point(ddisp, &p);
923 void
924 ddisplay_set_renderer(DDisplay *ddisp, int aa_renderer)
926 int width, height;
928 if (ddisp->renderer)
929 g_object_unref (ddisp->renderer);
931 ddisp->aa_renderer = aa_renderer;
933 width = ddisp->canvas->allocation.width;
934 height = ddisp->canvas->allocation.height;
936 if (ddisp->aa_renderer){
937 ddisp->renderer = new_libart_renderer(
938 dia_transform_new (&ddisp->visible,
939 &ddisp->zoom_factor), 1);
940 } else {
941 ddisp->renderer = new_gdk_renderer(ddisp);
944 dia_renderer_set_size(ddisp->renderer, ddisp->canvas->window, width, height);
947 void
948 ddisplay_resize_canvas(DDisplay *ddisp,
949 int width, int height)
951 if (ddisp->renderer==NULL) {
952 if (ddisp->aa_renderer)
953 ddisp->renderer = new_libart_renderer(
954 dia_transform_new (&ddisp->visible,
955 &ddisp->zoom_factor), 1);
956 else
957 ddisp->renderer = new_gdk_renderer(ddisp);
960 dia_renderer_set_size(ddisp->renderer, ddisp->canvas->window, width, height);
962 ddisplay_set_origo(ddisp, ddisp->origo.x, ddisp->origo.y);
964 ddisplay_add_update_all(ddisp);
965 ddisplay_flush(ddisp);
968 DDisplay *
969 ddisplay_active(void)
971 return active_display;
974 Diagram *
975 ddisplay_active_diagram(void)
977 DDisplay *ddisp = ddisplay_active ();
979 if (!ddisp) return NULL;
980 return ddisp->diagram;
983 static void
984 ddisp_destroy(DDisplay *ddisp)
986 if (ddisp->update_id) {
987 gtk_idle_remove(ddisp->update_id);
988 ddisp->update_id = 0;
991 g_signal_handlers_disconnect_by_func (ddisp->diagram, selection_changed, ddisp);
993 g_object_unref (G_OBJECT (ddisp->im_context));
994 ddisp->im_context = NULL;
996 ddisplay_im_context_preedit_reset(ddisp, active_focus());
998 /* This calls ddisplay_really_destroy */
999 gtk_widget_destroy (ddisp->shell);
1002 static void
1003 are_you_sure_close_dialog_respond(GtkWidget *widget, /* the dialog */
1004 gint response_id,
1005 gpointer user_data) /* the display */
1007 DDisplay *ddisp = (DDisplay *)user_data;
1009 switch (response_id) {
1010 case GTK_RESPONSE_YES :
1011 /* save changes */
1012 diagram_save(ddisp->diagram, ddisp->diagram->filename);
1014 if (ddisp->update_id) {
1015 gtk_idle_remove(ddisp->update_id);
1016 ddisp->update_id = 0;
1018 /* fall through */
1019 case GTK_RESPONSE_NO :
1020 ddisp_destroy (ddisp);
1021 /* fall through */
1022 case GTK_RESPONSE_CANCEL :
1023 case GTK_RESPONSE_NONE :
1024 case GTK_RESPONSE_DELETE_EVENT : /* closing via window manager */
1025 gtk_widget_destroy(widget);
1026 break;
1027 default :
1028 g_assert_not_reached();
1032 void
1033 ddisplay_close(DDisplay *ddisp)
1035 Diagram *dia;
1036 GtkWidget *dialog, *button;
1037 gchar *fname;
1038 gchar *msg;
1040 g_return_if_fail(ddisp != NULL);
1042 dia = ddisp->diagram;
1044 if ( (dia->display_count > 1) ||
1045 (!diagram_is_modified(dia)) ) {
1046 ddisp_destroy(ddisp);
1047 return;
1050 fname = dia->filename;
1051 if (!fname)
1052 fname = _("<unnamed>");
1053 msg = g_strdup_printf (
1054 _("The diagram '%s'\n"
1055 "has not been saved. Save changes now?"),
1056 fname);
1058 dialog = gtk_message_dialog_new(GTK_WINDOW (ddisp->shell),
1059 GTK_DIALOG_MODAL,
1060 GTK_MESSAGE_QUESTION,
1061 GTK_BUTTONS_NONE, /* no standard buttons */
1062 msg,
1063 NULL);
1064 g_free (msg);
1065 gtk_window_set_title (GTK_WINDOW(dialog), _("Close Diagram"));
1067 button = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
1068 gtk_dialog_add_action_widget (GTK_DIALOG(dialog), button, GTK_RESPONSE_CANCEL);
1070 button = gtk_button_new_with_label (_("Discard Changes"));
1071 gtk_dialog_add_action_widget (GTK_DIALOG(dialog), button, GTK_RESPONSE_NO);
1073 /* button = gtk_button_new_with_label (_("Save and Close")); */
1074 button = gtk_button_new_from_stock (GTK_STOCK_SAVE);
1075 gtk_dialog_add_action_widget (GTK_DIALOG(dialog), button, GTK_RESPONSE_YES);
1076 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
1077 gtk_dialog_set_default_response (GTK_DIALOG(dialog), GTK_RESPONSE_YES);
1079 g_signal_connect (G_OBJECT (dialog), "response",
1080 G_CALLBACK(are_you_sure_close_dialog_respond),
1081 ddisp);
1083 gtk_widget_show_all(dialog);
1086 void
1087 display_update_menu_state(DDisplay *ddisp)
1089 GtkCheckMenuItem *rulers;
1090 GtkCheckMenuItem *visible_grid;
1091 GtkCheckMenuItem *snap_to_grid;
1092 GtkCheckMenuItem *show_cx_pts;
1093 #ifdef HAVE_LIBART
1094 GtkCheckMenuItem *antialiased;
1095 #endif
1097 if (ddisp->menu_bar == NULL) {
1098 rulers = GTK_CHECK_MENU_ITEM(menus_get_item_from_path("<Display>/View/Show Rulers", NULL));
1099 visible_grid = GTK_CHECK_MENU_ITEM(menus_get_item_from_path("<Display>/View/Show Grid", NULL));
1100 snap_to_grid = GTK_CHECK_MENU_ITEM(menus_get_item_from_path("<Display>/View/Snap To Grid", NULL));
1101 show_cx_pts =
1102 GTK_CHECK_MENU_ITEM(menus_get_item_from_path("<Display>/View/Show Connection Points", NULL));
1103 #ifdef HAVE_LIBART
1104 antialiased = GTK_CHECK_MENU_ITEM(menus_get_item_from_path("<Display>/View/AntiAliased", NULL));
1105 #endif
1106 } else {
1107 rulers = GTK_CHECK_MENU_ITEM(menus_get_item_from_path("<DisplayMBar>/View/Show Rulers", ddisp->mbar_item_factory));
1108 visible_grid = GTK_CHECK_MENU_ITEM(menus_get_item_from_path("<DisplayMBar>/View/Show Grid", ddisp->mbar_item_factory));
1109 snap_to_grid = GTK_CHECK_MENU_ITEM(menus_get_item_from_path("<DisplayMBar>/View/Snap To Grid", ddisp->mbar_item_factory));
1110 show_cx_pts =
1111 GTK_CHECK_MENU_ITEM(menus_get_item_from_path("<DisplayMBar>/View/Show Connection Points", ddisp->mbar_item_factory));
1112 #ifdef HAVE_LIBART
1113 antialiased = GTK_CHECK_MENU_ITEM(menus_get_item_from_path("<DisplayMBar>/View/AntiAliased", ddisp->mbar_item_factory));
1114 #endif
1118 ddisplay_do_update_menu_sensitivity (ddisp);
1120 gtk_check_menu_item_set_active(rulers,
1121 GTK_WIDGET_VISIBLE (ddisp->hrule) ? 1 : 0);
1122 gtk_check_menu_item_set_active(visible_grid,
1123 ddisp->grid.visible);
1124 gtk_check_menu_item_set_active(snap_to_grid,
1125 ddisp->grid.snap);
1126 gtk_check_menu_item_set_active(show_cx_pts,
1127 ddisp->show_cx_pts);
1128 #ifdef HAVE_LIBART
1129 gtk_check_menu_item_set_active(antialiased,
1130 ddisp->aa_renderer);
1131 #endif
1134 void
1135 ddisplay_do_update_menu_sensitivity (DDisplay *ddisp)
1137 Diagram *dia;
1139 dia = ddisp->diagram;
1140 if (ddisp->menu_bar) {
1141 diagram_update_menubar_sensitivity(dia, &ddisp->updatable_menu_items);
1143 else {
1144 diagram_update_popupmenu_sensitivity(dia);
1150 /* This is called when ddisp->shell is destroyed... */
1151 void
1152 ddisplay_really_destroy(DDisplay *ddisp)
1154 if (active_display == ddisp)
1155 display_set_active(NULL);
1158 if (ddisp->diagram) {
1159 diagram_remove_ddisplay(ddisp->diagram, ddisp);
1160 /* if we are the last user of the diagram it will be unref'ed */
1161 g_object_unref(ddisp->diagram);
1162 ddisp->diagram = NULL;
1165 g_object_unref (ddisp->renderer);
1166 ddisp->renderer = NULL;
1168 g_hash_table_remove(display_ht, ddisp->shell);
1169 g_hash_table_remove(display_ht, ddisp->canvas);
1171 /* Free update_areas list: */
1172 ddisplay_free_update_areas(ddisp);
1173 /* Free display_areas list */
1174 ddisplay_free_display_areas(ddisp);
1176 g_free(ddisp);
1180 void
1181 ddisplay_set_title(DDisplay *ddisp, char *title)
1183 gtk_window_set_title (GTK_WINDOW (ddisp->shell), title);
1186 void
1187 ddisplay_set_all_cursor(GdkCursor *cursor)
1189 Diagram *dia;
1190 DDisplay *ddisp;
1191 GList *list;
1192 GSList *slist;
1194 current_cursor = cursor;
1196 list = dia_open_diagrams();
1197 while (list != NULL) {
1198 dia = (Diagram *) list->data;
1200 slist = dia->displays;
1201 while (slist != NULL) {
1202 ddisp = (DDisplay *) slist->data;
1204 ddisplay_set_cursor(ddisp, cursor);
1206 slist = g_slist_next(slist);
1209 list = g_list_next(list);
1213 void
1214 ddisplay_set_cursor(DDisplay *ddisp, GdkCursor *cursor)
1216 gdk_window_set_cursor(ddisp->canvas->window, cursor);
1219 void
1220 ddisplay_update_statusbar(DDisplay *ddisp)
1222 update_zoom_status (ddisp);
1223 update_snap_grid_status (ddisp);
1224 update_mainpoint_status (ddisp);
1225 update_modified_status (ddisp);
1228 void
1229 display_set_active(DDisplay *ddisp)
1231 if (ddisp != active_display) {
1232 active_display = ddisp;
1234 /* perform notification here (such as switch layers dialog) */
1235 layer_dialog_set_diagram(ddisp ? ddisp->diagram : NULL);
1236 diagram_properties_set_diagram(ddisp ? ddisp->diagram : NULL);
1238 if (ddisp) {
1239 display_update_menu_state(ddisp);
1241 if (prefs.toolbox_on_top) {
1242 gtk_window_set_transient_for(GTK_WINDOW(interface_get_toolbox_shell()),
1243 GTK_WINDOW(ddisp->shell));
1244 } else {
1245 gtk_window_set_transient_for(GTK_WINDOW(interface_get_toolbox_shell()),
1246 NULL);
1252 void
1253 ddisplay_im_context_preedit_reset(DDisplay *ddisp, Focus *focus)
1255 if (ddisp->preedit_string != NULL) {
1256 if (focus != NULL) {
1257 int i;
1258 ObjectChange *change;
1260 for (i = 0; i < g_utf8_strlen(ddisp->preedit_string, -1); i++) {
1261 (focus->key_event)(focus, GDK_BackSpace, NULL, 0, &change);
1265 g_free(ddisp->preedit_string);
1266 ddisp->preedit_string = NULL;
1268 if (ddisp->preedit_attrs != NULL) {
1269 pango_attr_list_unref(ddisp->preedit_attrs);
1270 ddisp->preedit_attrs = NULL;