1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
4 * (GLABELS) Label and Business Card Creation program for GNOME
6 * view_object.c: GLabels label object base class
8 * Copyright (C) 2001-2007 Jim Evins <evins@snaught.com>.
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #include "view-object.h"
32 /*========================================================*/
33 /* Private constants and macros. */
34 /*========================================================*/
36 #define HANDLE_FILL_RGBA_ARGS 0.0, 0.75, 0.0, 0.4
37 #define HANDLE_OUTLINE_RGBA_ARGS 0.0, 0.0, 0.0, 0.8
39 #define HANDLE_OUTLINE_WIDTH_PIXELS 1.0
40 #define HANDLE_PIXELS 7
42 /*========================================================*/
44 /*========================================================*/
46 struct _glViewObjectPrivate {
48 glLabelObject *object;
51 glViewObjectHandlesStyle handles_style;
53 GtkWidget *property_editor;
56 /*========================================================*/
57 /* Private globals. */
58 /*========================================================*/
61 /*========================================================*/
62 /* Private function prototypes. */
63 /*========================================================*/
65 static void gl_view_object_finalize (GObject *object);
67 static void object_removed_cb (glViewObject *view_object,
68 glLabelObject *object);
70 static void object_top_cb (glViewObject *view_object,
71 glLabelObject *object);
73 static void object_bottom_cb (glViewObject *view_object,
74 glLabelObject *object);
81 /*****************************************************************************/
82 /* Boilerplate object stuff. */
83 /*****************************************************************************/
84 G_DEFINE_TYPE (glViewObject, gl_view_object, G_TYPE_OBJECT);
87 gl_view_object_class_init (glViewObjectClass *class)
89 GObjectClass *object_class = G_OBJECT_CLASS (class);
91 gl_debug (DEBUG_VIEW, "START");
93 gl_view_object_parent_class = g_type_class_peek_parent (class);
95 object_class->finalize = gl_view_object_finalize;
97 gl_debug (DEBUG_VIEW, "END");
101 gl_view_object_init (glViewObject *view_object)
103 gl_debug (DEBUG_VIEW, "START");
105 view_object->priv = g_new0 (glViewObjectPrivate, 1);
107 gl_debug (DEBUG_VIEW, "END");
111 gl_view_object_finalize (GObject *object)
113 glViewObject *view_object = GL_VIEW_OBJECT (object);
116 gl_debug (DEBUG_VIEW, "START");
118 g_return_if_fail (object && GL_IS_VIEW_OBJECT (object));
120 view = view_object->priv->view;
121 view->object_list = g_list_remove (view->object_list, object);
122 view->selected_object_list =
123 g_list_remove (view->selected_object_list, object);
125 g_object_unref (view_object->priv->object);
126 if (view_object->priv->property_editor) {
127 gl_debug (DEBUG_VIEW, "Destroy editor");
128 g_object_unref (G_OBJECT(view_object->priv->property_editor));
130 g_free (view_object->priv);
132 G_OBJECT_CLASS (gl_view_object_parent_class)->finalize (object);
134 gl_debug (DEBUG_VIEW, "END");
137 /*****************************************************************************/
138 /* NEW object view. */
139 /*****************************************************************************/
141 gl_view_object_new (void)
143 glViewObject *view_object;
145 gl_debug (DEBUG_VIEW, "START");
147 view_object = g_object_new (gl_view_object_get_type(), NULL);
149 gl_debug (DEBUG_VIEW, "END");
151 return G_OBJECT (view_object);
154 /*****************************************************************************/
155 /* Set parent view to which this object view belongs. */
156 /*****************************************************************************/
158 gl_view_object_set_view (glViewObject *view_object,
161 gl_debug (DEBUG_VIEW, "START");
163 g_return_if_fail (view_object && GL_IS_VIEW_OBJECT (view_object));
164 g_return_if_fail (view && GL_IS_VIEW (view));
166 view_object->priv->view = view;
168 view->object_list = g_list_append (view->object_list, view_object);
170 g_signal_connect_swapped (G_OBJECT (view_object->priv->object), "changed",
171 G_CALLBACK (gl_view_update), view);
172 g_signal_connect_swapped (G_OBJECT (view_object->priv->object), "moved",
173 G_CALLBACK (gl_view_update), view);
175 gl_debug (DEBUG_VIEW, "END");
178 /*****************************************************************************/
179 /* Set Label object to follow. */
180 /*****************************************************************************/
182 gl_view_object_set_object (glViewObject *view_object,
183 glLabelObject *object,
184 glViewObjectHandlesStyle style)
186 gl_debug (DEBUG_VIEW, "START");
188 g_return_if_fail (view_object && GL_IS_VIEW_OBJECT (view_object));
189 g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
191 view_object->priv->object = g_object_ref (G_OBJECT (object));
192 view_object->priv->handles_style = style;
194 g_signal_connect_swapped (G_OBJECT (object), "removed",
195 G_CALLBACK (object_removed_cb), view_object);
196 g_signal_connect_swapped (G_OBJECT (object), "top",
197 G_CALLBACK (object_top_cb), view_object);
198 g_signal_connect_swapped (G_OBJECT (object), "bottom",
199 G_CALLBACK (object_bottom_cb), view_object);
201 gl_debug (DEBUG_VIEW, "END");
204 /*---------------------------------------------------------------------------*/
205 /* PRIVATE. Handle object "removed" signal. */
206 /*---------------------------------------------------------------------------*/
208 object_removed_cb (glViewObject *view_object,
209 glLabelObject *object)
212 gl_debug (DEBUG_VIEW, "START");
214 g_return_if_fail (view_object && GL_IS_VIEW_OBJECT (view_object));
215 g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
217 view = gl_view_object_get_view (view_object);
218 view->object_list = g_list_remove (view->object_list, view_object);
219 g_object_unref (G_OBJECT (view_object));
221 gl_debug (DEBUG_VIEW, "END");
224 /*---------------------------------------------------------------------------*/
225 /* PRIVATE. Handle object "top" signal. */
226 /*---------------------------------------------------------------------------*/
228 object_top_cb (glViewObject *view_object,
229 glLabelObject *object)
232 gl_debug (DEBUG_VIEW, "START");
234 g_return_if_fail (view_object && GL_IS_VIEW_OBJECT (view_object));
235 g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
237 view = gl_view_object_get_view (view_object);
239 /* Move to end of list, representing front most object */
240 view->object_list = g_list_remove (view->object_list, view_object);
241 view->object_list = g_list_append (view->object_list, view_object);
243 gl_debug (DEBUG_VIEW, "END");
246 /*---------------------------------------------------------------------------*/
247 /* PRIVATE. Handle object "removed" signal. */
248 /*---------------------------------------------------------------------------*/
250 object_bottom_cb (glViewObject *view_object,
251 glLabelObject *object)
254 gl_debug (DEBUG_VIEW, "START");
256 g_return_if_fail (view_object && GL_IS_VIEW_OBJECT (view_object));
257 g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
259 view = gl_view_object_get_view (view_object);
261 /* Move to front of list, representing rear most object */
262 view->object_list = g_list_remove (view->object_list, view_object);
263 view->object_list = g_list_prepend (view->object_list, view_object);
265 gl_debug (DEBUG_VIEW, "END");
268 /*****************************************************************************/
269 /* Return parent view associated with this view. */
270 /*****************************************************************************/
272 gl_view_object_get_view (glViewObject *view_object)
274 gl_debug (DEBUG_VIEW, "START");
276 g_return_val_if_fail (view_object && GL_IS_VIEW_OBJECT (view_object), NULL);
278 gl_debug (DEBUG_VIEW, "END");
280 return view_object->priv->view;
283 /*****************************************************************************/
284 /* Return label object that we are following. */
285 /*****************************************************************************/
287 gl_view_object_get_object (glViewObject *view_object)
289 gl_debug (DEBUG_VIEW, "START");
291 g_return_val_if_fail (view_object && GL_IS_VIEW_OBJECT (view_object), NULL);
293 gl_debug (DEBUG_VIEW, "END");
295 return view_object->priv->object;
298 /*****************************************************************************/
299 /* Get property editor. */
300 /*****************************************************************************/
302 gl_view_object_get_editor (glViewObject *view_object)
304 gl_debug (DEBUG_VIEW, "START");
306 g_return_val_if_fail (view_object && GL_IS_VIEW_OBJECT (view_object), NULL);
308 if ( GL_VIEW_OBJECT_GET_CLASS(view_object)->construct_editor != NULL ) {
310 if (view_object->priv->property_editor == NULL) {
311 view_object->priv->property_editor =
312 GL_VIEW_OBJECT_GET_CLASS(view_object)->construct_editor (view_object);
314 g_signal_connect (G_OBJECT (view_object->priv->property_editor),
316 G_CALLBACK (gtk_widget_destroyed),
317 &view_object->priv->property_editor);
319 gtk_widget_show (view_object->priv->property_editor);
324 gl_debug (DEBUG_VIEW, "END");
326 return view_object->priv->property_editor;
330 /*****************************************************************************/
332 /*****************************************************************************/
334 gl_view_object_select (glViewObject *view_object)
336 gl_debug (DEBUG_VIEW, "START");
338 gl_view_select_object(view_object->priv->view, view_object);
340 gl_debug (DEBUG_VIEW, "END");
343 /*****************************************************************************/
344 /* Is object at (x,y)? */
345 /*****************************************************************************/
347 gl_view_object_at (glViewObject *view_object,
352 glLabelObject *object = view_object->priv->object;
354 cairo_matrix_t matrix;
355 gboolean return_val = FALSE;
357 gl_debug (DEBUG_VIEW, "START");
359 g_return_val_if_fail (view_object && GL_IS_VIEW_OBJECT (view_object), FALSE);
360 g_return_val_if_fail (object && GL_IS_LABEL_OBJECT (object), FALSE);
362 gl_label_object_get_position (object, &x0, &y0);
363 gl_label_object_get_matrix (object, &matrix);
366 cairo_translate (cr, x0, y0);
367 cairo_transform (cr, &matrix);
369 cairo_device_to_user (cr, &x, &y);
371 if ( GL_VIEW_OBJECT_GET_CLASS(view_object)->object_at != NULL ) {
373 return_val = GL_VIEW_OBJECT_GET_CLASS(view_object)->object_at (view_object, cr, x, y);
381 gl_debug (DEBUG_VIEW, "END");
385 /*--------------------------------------------------------------------------*/
386 /* Create handle path */
387 /*--------------------------------------------------------------------------*/
389 create_handle_path (cairo_t *cr,
390 glLabelObject *object,
395 gl_debug (DEBUG_VIEW, "START");
398 x_handle - HANDLE_PIXELS/scale/2, y_handle - HANDLE_PIXELS/scale/2,
399 HANDLE_PIXELS/scale, HANDLE_PIXELS/scale);
401 gl_debug (DEBUG_VIEW, "END");
404 /*****************************************************************************/
405 /* Draw object handles */
406 /*****************************************************************************/
408 gl_view_object_draw_handles (glViewObject *view_object,
411 glLabelObject *object = view_object->priv->object;
413 cairo_matrix_t matrix;
417 gl_debug (DEBUG_VIEW, "START");
419 g_return_if_fail (view_object && GL_IS_VIEW_OBJECT (view_object));
420 g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
422 scale = view_object->priv->view->home_scale * view_object->priv->view->zoom;
424 gl_label_object_get_position (object, &x0, &y0);
425 gl_label_object_get_matrix (object, &matrix);
427 gl_label_object_get_size (GL_LABEL_OBJECT(object), &w, &h);
431 cairo_translate (cr, x0, y0);
432 cairo_transform (cr, &matrix);
434 switch (view_object->priv->handles_style)
436 case GL_VIEW_OBJECT_HANDLES_BOX:
440 create_handle_path (cr, object, scale, w/2, 0);
443 cairo_new_sub_path (cr);
444 create_handle_path (cr, object, scale, w, 0);
447 cairo_new_sub_path (cr);
448 create_handle_path (cr, object, scale, w, h/2);
451 cairo_new_sub_path (cr);
452 create_handle_path (cr, object, scale, w, h);
455 cairo_new_sub_path (cr);
456 create_handle_path (cr, object, scale, w/2, h);
459 cairo_new_sub_path (cr);
460 create_handle_path (cr, object, scale, 0, h);
463 cairo_new_sub_path (cr);
464 create_handle_path (cr, object, scale, 0, h/2);
467 cairo_new_sub_path (cr);
468 create_handle_path (cr, object, scale, 0, 0);
472 case GL_VIEW_OBJECT_HANDLES_LINE:
475 create_handle_path (cr, object, scale, 0, 0);
478 cairo_new_sub_path (cr);
479 create_handle_path (cr, object, scale, w, h);
484 cairo_set_source_rgba (cr, HANDLE_FILL_RGBA_ARGS);
485 cairo_fill_preserve (cr);
487 cairo_set_line_width (cr, HANDLE_OUTLINE_WIDTH_PIXELS/scale);
488 cairo_set_source_rgba (cr, HANDLE_OUTLINE_RGBA_ARGS);
493 gl_debug (DEBUG_VIEW, "END");
496 /*****************************************************************************/
497 /* Is there an object handle at (x,y). */
498 /*****************************************************************************/
500 gl_view_object_handle_at (glViewObject *view_object,
505 glLabelObject *object = view_object->priv->object;
507 cairo_matrix_t matrix;
510 glViewObjectHandle handle = GL_VIEW_OBJECT_HANDLE_NONE;
512 gl_debug (DEBUG_VIEW, "START");
514 g_return_val_if_fail (view_object && GL_IS_VIEW_OBJECT (view_object), handle);
515 g_return_val_if_fail (object && GL_IS_LABEL_OBJECT (object), handle);
517 scale = view_object->priv->view->home_scale * view_object->priv->view->zoom;
519 gl_label_object_get_position (object, &x0, &y0);
520 gl_label_object_get_matrix (object, &matrix);
522 gl_label_object_get_size (GL_LABEL_OBJECT(object), &w, &h);
526 cairo_translate (cr, x0, y0);
527 cairo_transform (cr, &matrix);
529 cairo_device_to_user (cr, &x, &y);
531 switch (view_object->priv->handles_style)
533 case GL_VIEW_OBJECT_HANDLES_BOX:
536 create_handle_path (cr, object, scale, w, h);
537 if (cairo_in_fill (cr, x, y)) {handle = GL_VIEW_OBJECT_HANDLE_SE; break;}
540 create_handle_path (cr, object, scale, 0, h);
541 if (cairo_in_fill (cr, x, y)) {handle = GL_VIEW_OBJECT_HANDLE_SW; break;}
544 create_handle_path (cr, object, scale, w, 0);
545 if (cairo_in_fill (cr, x, y)) {handle = GL_VIEW_OBJECT_HANDLE_NE; break;}
548 create_handle_path (cr, object, scale, 0, 0);
549 if (cairo_in_fill (cr, x, y)) {handle = GL_VIEW_OBJECT_HANDLE_NW; break;}
552 create_handle_path (cr, object, scale, w, h/2);
553 if (cairo_in_fill (cr, x, y)) {handle = GL_VIEW_OBJECT_HANDLE_E; break;}
556 create_handle_path (cr, object, scale, w/2, h);
557 if (cairo_in_fill (cr, x, y)) {handle = GL_VIEW_OBJECT_HANDLE_S; break;}
560 create_handle_path (cr, object, scale, 0, h/2);
561 if (cairo_in_fill (cr, x, y)) {handle = GL_VIEW_OBJECT_HANDLE_W; break;}
564 create_handle_path (cr, object, scale, w/2, 0);
565 if (cairo_in_fill (cr, x, y)) {handle = GL_VIEW_OBJECT_HANDLE_N; break;}
569 case GL_VIEW_OBJECT_HANDLES_LINE:
571 create_handle_path (cr, object, scale, w, h);
572 if (cairo_in_fill (cr, x, y)) {handle = GL_VIEW_OBJECT_HANDLE_P2; break;}
575 create_handle_path (cr, object, scale, 0, 0);
576 if (cairo_in_fill (cr, x, y)) {handle = GL_VIEW_OBJECT_HANDLE_P1; break;}
587 /*---------------------------------------------------------------------------*/
588 /* PRIVATE. Resize object. */
589 /*---------------------------------------------------------------------------*/
591 gl_view_object_resize_event (glViewObject *view_object,
592 glViewObjectHandle handle,
593 gboolean honor_aspect,
598 glLabelObject *object;
599 cairo_matrix_t matrix;
600 gdouble x0, y0, x1, y1, x2, y2;
604 gl_debug (DEBUG_VIEW, "x,y world = %g, %g", x, y);
606 object = view_object->priv->object;
609 * Change to item relative coordinates
612 gl_label_object_get_position (object, &x0, &y0);
613 cairo_translate (cr, x0, y0);
614 gl_label_object_get_matrix (object, &matrix);
615 cairo_transform (cr, &matrix);
618 * Initialize origin and 2 corners in object relative coordinates.
626 gl_label_object_get_size (object, &x2, &y2);
628 gl_debug (DEBUG_VIEW, "x0,y0 object = %g, %g", x0, y0);
629 gl_debug (DEBUG_VIEW, "x1,y1 object = %g, %g", x1, y1);
630 gl_debug (DEBUG_VIEW, "x2,y2 object = %g, %g", x2, y2);
633 * Translate x,y into object relative coordinates.
635 cairo_device_to_user (cr, &x, &y);
637 gl_debug (DEBUG_VIEW, "x,y object = %g, %g", x, y);
645 case GL_VIEW_OBJECT_HANDLE_NW:
650 case GL_VIEW_OBJECT_HANDLE_N:
655 case GL_VIEW_OBJECT_HANDLE_NE:
660 case GL_VIEW_OBJECT_HANDLE_E:
665 case GL_VIEW_OBJECT_HANDLE_SE:
670 case GL_VIEW_OBJECT_HANDLE_S:
675 case GL_VIEW_OBJECT_HANDLE_SW:
680 case GL_VIEW_OBJECT_HANDLE_W:
684 case GL_VIEW_OBJECT_HANDLE_P1:
693 case GL_VIEW_OBJECT_HANDLE_P2:
701 g_print ("Invalid handle.\n"); /* Should not happen! */
704 if ( (handle != GL_VIEW_OBJECT_HANDLE_P1) && (handle != GL_VIEW_OBJECT_HANDLE_P2) )
708 gl_label_object_set_size_honor_aspect (object, w, h);
712 gl_label_object_set_size (object, w, h);
716 * Query the new size in case it was constrained.
718 gl_label_object_get_size (object, &w, &h);
726 case GL_VIEW_OBJECT_HANDLE_NW:
731 case GL_VIEW_OBJECT_HANDLE_N:
732 case GL_VIEW_OBJECT_HANDLE_NE:
737 case GL_VIEW_OBJECT_HANDLE_E:
738 case GL_VIEW_OBJECT_HANDLE_SE:
739 case GL_VIEW_OBJECT_HANDLE_S:
743 case GL_VIEW_OBJECT_HANDLE_SW:
744 case GL_VIEW_OBJECT_HANDLE_W:
750 g_print ("Invalid handle.\n"); /* Should not happen! */
755 gl_label_object_set_size (object, dx, dy);
759 * Put new origin back into world coordinates and set.
761 cairo_user_to_device (cr, &x0, &y0);
763 cairo_device_to_user (cr, &x0, &y0);
764 gl_label_object_set_position (object, x0, y0);