3 * Copyright (C) 2001-2009 Jim Evins <evins@snaught.com>.
5 * This file is part of gLabels.
7 * gLabels is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
12 * gLabels is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with gLabels. If not, see <http://www.gnu.org/licenses/>.
21 #include "view-object.h"
28 /*========================================================*/
29 /* Private constants and macros. */
30 /*========================================================*/
32 #define HANDLE_FILL_RGBA_ARGS 0.0, 0.75, 0.0, 0.4
33 #define HANDLE_OUTLINE_RGBA_ARGS 0.0, 0.0, 0.0, 0.8
35 #define HANDLE_OUTLINE_WIDTH_PIXELS 1.0
36 #define HANDLE_PIXELS 7
39 /*========================================================*/
41 /*========================================================*/
43 struct _glViewObjectPrivate {
45 glLabelObject *object;
48 glViewObjectHandlesStyle handles_style;
50 GtkWidget *property_editor;
54 /*========================================================*/
55 /* Private globals. */
56 /*========================================================*/
59 /*========================================================*/
60 /* Private function prototypes. */
61 /*========================================================*/
63 static void gl_view_object_finalize (GObject *object);
65 static void object_removed_cb (glViewObject *view_object,
66 glLabelObject *object);
68 static void object_top_cb (glViewObject *view_object,
69 glLabelObject *object);
71 static void object_bottom_cb (glViewObject *view_object,
72 glLabelObject *object);
75 /*****************************************************************************/
76 /* Boilerplate object stuff. */
77 /*****************************************************************************/
78 G_DEFINE_TYPE (glViewObject, gl_view_object, G_TYPE_OBJECT);
82 gl_view_object_class_init (glViewObjectClass *class)
84 GObjectClass *object_class = G_OBJECT_CLASS (class);
86 gl_debug (DEBUG_VIEW, "START");
88 gl_view_object_parent_class = g_type_class_peek_parent (class);
90 object_class->finalize = gl_view_object_finalize;
92 gl_debug (DEBUG_VIEW, "END");
97 gl_view_object_init (glViewObject *view_object)
99 gl_debug (DEBUG_VIEW, "START");
101 view_object->priv = g_new0 (glViewObjectPrivate, 1);
103 gl_debug (DEBUG_VIEW, "END");
108 gl_view_object_finalize (GObject *object)
110 glViewObject *view_object = GL_VIEW_OBJECT (object);
113 gl_debug (DEBUG_VIEW, "START");
115 g_return_if_fail (object && GL_IS_VIEW_OBJECT (object));
117 view = view_object->priv->view;
118 view->object_list = g_list_remove (view->object_list, object);
119 view->selected_object_list =
120 g_list_remove (view->selected_object_list, object);
122 g_object_unref (view_object->priv->object);
123 if (view_object->priv->property_editor) {
124 gl_debug (DEBUG_VIEW, "Destroy editor");
125 g_object_unref (G_OBJECT(view_object->priv->property_editor));
127 g_free (view_object->priv);
129 G_OBJECT_CLASS (gl_view_object_parent_class)->finalize (object);
131 gl_debug (DEBUG_VIEW, "END");
135 /*****************************************************************************/
136 /* NEW object view. */
137 /*****************************************************************************/
139 gl_view_object_new (void)
141 glViewObject *view_object;
143 gl_debug (DEBUG_VIEW, "START");
145 view_object = g_object_new (gl_view_object_get_type(), NULL);
147 gl_debug (DEBUG_VIEW, "END");
149 return G_OBJECT (view_object);
153 /*****************************************************************************/
154 /* Set parent view to which this object view belongs. */
155 /*****************************************************************************/
157 gl_view_object_set_view (glViewObject *view_object,
160 gl_debug (DEBUG_VIEW, "START");
162 g_return_if_fail (view_object && GL_IS_VIEW_OBJECT (view_object));
163 g_return_if_fail (view && GL_IS_VIEW (view));
165 view_object->priv->view = view;
167 view->object_list = g_list_append (view->object_list, view_object);
169 g_signal_connect_swapped (G_OBJECT (view_object->priv->object), "changed",
170 G_CALLBACK (gl_view_update), view);
171 g_signal_connect_swapped (G_OBJECT (view_object->priv->object), "moved",
172 G_CALLBACK (gl_view_update), view);
174 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");
205 /*---------------------------------------------------------------------------*/
206 /* PRIVATE. Handle object "removed" signal. */
207 /*---------------------------------------------------------------------------*/
209 object_removed_cb (glViewObject *view_object,
210 glLabelObject *object)
213 gl_debug (DEBUG_VIEW, "START");
215 g_return_if_fail (view_object && GL_IS_VIEW_OBJECT (view_object));
216 g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
218 view = gl_view_object_get_view (view_object);
219 view->object_list = g_list_remove (view->object_list, view_object);
220 g_object_unref (G_OBJECT (view_object));
222 gl_debug (DEBUG_VIEW, "END");
226 /*---------------------------------------------------------------------------*/
227 /* PRIVATE. Handle object "top" signal. */
228 /*---------------------------------------------------------------------------*/
230 object_top_cb (glViewObject *view_object,
231 glLabelObject *object)
234 gl_debug (DEBUG_VIEW, "START");
236 g_return_if_fail (view_object && GL_IS_VIEW_OBJECT (view_object));
237 g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
239 view = gl_view_object_get_view (view_object);
241 /* Move to end of list, representing front most object */
242 view->object_list = g_list_remove (view->object_list, view_object);
243 view->object_list = g_list_append (view->object_list, view_object);
245 gl_debug (DEBUG_VIEW, "END");
249 /*---------------------------------------------------------------------------*/
250 /* PRIVATE. Handle object "removed" signal. */
251 /*---------------------------------------------------------------------------*/
253 object_bottom_cb (glViewObject *view_object,
254 glLabelObject *object)
257 gl_debug (DEBUG_VIEW, "START");
259 g_return_if_fail (view_object && GL_IS_VIEW_OBJECT (view_object));
260 g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
262 view = gl_view_object_get_view (view_object);
264 /* Move to front of list, representing rear most object */
265 view->object_list = g_list_remove (view->object_list, view_object);
266 view->object_list = g_list_prepend (view->object_list, view_object);
268 gl_debug (DEBUG_VIEW, "END");
272 /*****************************************************************************/
273 /* Return parent view associated with this view. */
274 /*****************************************************************************/
276 gl_view_object_get_view (glViewObject *view_object)
278 gl_debug (DEBUG_VIEW, "START");
280 g_return_val_if_fail (view_object && GL_IS_VIEW_OBJECT (view_object), NULL);
282 gl_debug (DEBUG_VIEW, "END");
284 return view_object->priv->view;
288 /*****************************************************************************/
289 /* Return label object that we are following. */
290 /*****************************************************************************/
292 gl_view_object_get_object (glViewObject *view_object)
294 gl_debug (DEBUG_VIEW, "START");
296 g_return_val_if_fail (view_object && GL_IS_VIEW_OBJECT (view_object), NULL);
298 gl_debug (DEBUG_VIEW, "END");
300 return view_object->priv->object;
304 /*****************************************************************************/
305 /* Get property editor. */
306 /*****************************************************************************/
308 gl_view_object_get_editor (glViewObject *view_object)
310 gl_debug (DEBUG_VIEW, "START");
312 g_return_val_if_fail (view_object && GL_IS_VIEW_OBJECT (view_object), NULL);
314 if ( GL_VIEW_OBJECT_GET_CLASS(view_object)->construct_editor != NULL ) {
316 if (view_object->priv->property_editor == NULL) {
317 view_object->priv->property_editor =
318 GL_VIEW_OBJECT_GET_CLASS(view_object)->construct_editor (view_object);
320 g_signal_connect (G_OBJECT (view_object->priv->property_editor),
322 G_CALLBACK (gtk_widget_destroyed),
323 &view_object->priv->property_editor);
325 gtk_widget_show (view_object->priv->property_editor);
330 gl_debug (DEBUG_VIEW, "END");
332 return view_object->priv->property_editor;
336 /*****************************************************************************/
338 /*****************************************************************************/
340 gl_view_object_select (glViewObject *view_object)
342 gl_debug (DEBUG_VIEW, "START");
344 gl_view_select_object(view_object->priv->view, view_object);
346 gl_debug (DEBUG_VIEW, "END");
350 /*****************************************************************************/
351 /* Is object at (x,y)? */
352 /*****************************************************************************/
354 gl_view_object_at (glViewObject *view_object,
359 glLabelObject *object = view_object->priv->object;
361 cairo_matrix_t matrix;
362 gboolean return_val = FALSE;
364 gl_debug (DEBUG_VIEW, "START");
366 g_return_val_if_fail (view_object && GL_IS_VIEW_OBJECT (view_object), FALSE);
367 g_return_val_if_fail (object && GL_IS_LABEL_OBJECT (object), FALSE);
369 gl_label_object_get_position (object, &x0, &y0);
370 gl_label_object_get_matrix (object, &matrix);
373 cairo_translate (cr, x0, y0);
374 cairo_transform (cr, &matrix);
376 cairo_device_to_user (cr, &x, &y);
378 if ( GL_VIEW_OBJECT_GET_CLASS(view_object)->object_at != NULL ) {
380 return_val = GL_VIEW_OBJECT_GET_CLASS(view_object)->object_at (view_object, cr, x, y);
388 gl_debug (DEBUG_VIEW, "END");
392 /*--------------------------------------------------------------------------*/
393 /* Create handle path */
394 /*--------------------------------------------------------------------------*/
396 create_handle_path (cairo_t *cr,
397 glLabelObject *object,
402 gl_debug (DEBUG_VIEW, "START");
405 x_handle - HANDLE_PIXELS/scale/2, y_handle - HANDLE_PIXELS/scale/2,
406 HANDLE_PIXELS/scale, HANDLE_PIXELS/scale);
408 gl_debug (DEBUG_VIEW, "END");
412 /*****************************************************************************/
413 /* Draw object handles */
414 /*****************************************************************************/
416 gl_view_object_draw_handles (glViewObject *view_object,
419 glLabelObject *object = view_object->priv->object;
421 cairo_matrix_t matrix;
425 gl_debug (DEBUG_VIEW, "START");
427 g_return_if_fail (view_object && GL_IS_VIEW_OBJECT (view_object));
428 g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
430 scale = view_object->priv->view->home_scale * view_object->priv->view->zoom;
432 gl_label_object_get_position (object, &x0, &y0);
433 gl_label_object_get_matrix (object, &matrix);
435 gl_label_object_get_size (GL_LABEL_OBJECT(object), &w, &h);
439 cairo_translate (cr, x0, y0);
440 cairo_transform (cr, &matrix);
442 switch (view_object->priv->handles_style)
444 case GL_VIEW_OBJECT_HANDLES_BOX:
448 create_handle_path (cr, object, scale, w/2, 0);
451 cairo_new_sub_path (cr);
452 create_handle_path (cr, object, scale, w, 0);
455 cairo_new_sub_path (cr);
456 create_handle_path (cr, object, scale, w, h/2);
459 cairo_new_sub_path (cr);
460 create_handle_path (cr, object, scale, w, h);
463 cairo_new_sub_path (cr);
464 create_handle_path (cr, object, scale, w/2, h);
467 cairo_new_sub_path (cr);
468 create_handle_path (cr, object, scale, 0, h);
471 cairo_new_sub_path (cr);
472 create_handle_path (cr, object, scale, 0, h/2);
475 cairo_new_sub_path (cr);
476 create_handle_path (cr, object, scale, 0, 0);
480 case GL_VIEW_OBJECT_HANDLES_LINE:
483 create_handle_path (cr, object, scale, 0, 0);
486 cairo_new_sub_path (cr);
487 create_handle_path (cr, object, scale, w, h);
492 cairo_set_source_rgba (cr, HANDLE_FILL_RGBA_ARGS);
493 cairo_fill_preserve (cr);
495 cairo_set_line_width (cr, HANDLE_OUTLINE_WIDTH_PIXELS/scale);
496 cairo_set_source_rgba (cr, HANDLE_OUTLINE_RGBA_ARGS);
501 gl_debug (DEBUG_VIEW, "END");
505 /*****************************************************************************/
506 /* Is there an object handle at (x,y). */
507 /*****************************************************************************/
509 gl_view_object_handle_at (glViewObject *view_object,
514 glLabelObject *object = view_object->priv->object;
516 cairo_matrix_t matrix;
519 glViewObjectHandle handle = GL_VIEW_OBJECT_HANDLE_NONE;
521 gl_debug (DEBUG_VIEW, "START");
523 g_return_val_if_fail (view_object && GL_IS_VIEW_OBJECT (view_object), handle);
524 g_return_val_if_fail (object && GL_IS_LABEL_OBJECT (object), handle);
526 scale = view_object->priv->view->home_scale * view_object->priv->view->zoom;
528 gl_label_object_get_position (object, &x0, &y0);
529 gl_label_object_get_matrix (object, &matrix);
531 gl_label_object_get_size (GL_LABEL_OBJECT(object), &w, &h);
535 cairo_translate (cr, x0, y0);
536 cairo_transform (cr, &matrix);
538 cairo_device_to_user (cr, &x, &y);
540 switch (view_object->priv->handles_style)
542 case GL_VIEW_OBJECT_HANDLES_BOX:
545 create_handle_path (cr, object, scale, w, h);
546 if (cairo_in_fill (cr, x, y)) {handle = GL_VIEW_OBJECT_HANDLE_SE; break;}
549 create_handle_path (cr, object, scale, 0, h);
550 if (cairo_in_fill (cr, x, y)) {handle = GL_VIEW_OBJECT_HANDLE_SW; break;}
553 create_handle_path (cr, object, scale, w, 0);
554 if (cairo_in_fill (cr, x, y)) {handle = GL_VIEW_OBJECT_HANDLE_NE; break;}
557 create_handle_path (cr, object, scale, 0, 0);
558 if (cairo_in_fill (cr, x, y)) {handle = GL_VIEW_OBJECT_HANDLE_NW; break;}
561 create_handle_path (cr, object, scale, w, h/2);
562 if (cairo_in_fill (cr, x, y)) {handle = GL_VIEW_OBJECT_HANDLE_E; break;}
565 create_handle_path (cr, object, scale, w/2, h);
566 if (cairo_in_fill (cr, x, y)) {handle = GL_VIEW_OBJECT_HANDLE_S; break;}
569 create_handle_path (cr, object, scale, 0, h/2);
570 if (cairo_in_fill (cr, x, y)) {handle = GL_VIEW_OBJECT_HANDLE_W; break;}
573 create_handle_path (cr, object, scale, w/2, 0);
574 if (cairo_in_fill (cr, x, y)) {handle = GL_VIEW_OBJECT_HANDLE_N; break;}
578 case GL_VIEW_OBJECT_HANDLES_LINE:
580 create_handle_path (cr, object, scale, w, h);
581 if (cairo_in_fill (cr, x, y)) {handle = GL_VIEW_OBJECT_HANDLE_P2; break;}
584 create_handle_path (cr, object, scale, 0, 0);
585 if (cairo_in_fill (cr, x, y)) {handle = GL_VIEW_OBJECT_HANDLE_P1; break;}
597 /*---------------------------------------------------------------------------*/
598 /* PRIVATE. Resize object. */
599 /*---------------------------------------------------------------------------*/
601 gl_view_object_resize_event (glViewObject *view_object,
602 glViewObjectHandle handle,
603 gboolean honor_aspect,
608 glLabelObject *object;
609 cairo_matrix_t matrix;
610 gdouble x0, y0, x1, y1, x2, y2;
614 gl_debug (DEBUG_VIEW, "x,y world = %g, %g", x, y);
616 object = view_object->priv->object;
619 * Change to item relative coordinates
622 gl_label_object_get_position (object, &x0, &y0);
623 cairo_translate (cr, x0, y0);
624 gl_label_object_get_matrix (object, &matrix);
625 cairo_transform (cr, &matrix);
628 * Initialize origin and 2 corners in object relative coordinates.
636 gl_label_object_get_size (object, &x2, &y2);
638 gl_debug (DEBUG_VIEW, "x0,y0 object = %g, %g", x0, y0);
639 gl_debug (DEBUG_VIEW, "x1,y1 object = %g, %g", x1, y1);
640 gl_debug (DEBUG_VIEW, "x2,y2 object = %g, %g", x2, y2);
643 * Translate x,y into object relative coordinates.
645 cairo_device_to_user (cr, &x, &y);
647 gl_debug (DEBUG_VIEW, "x,y object = %g, %g", x, y);
655 case GL_VIEW_OBJECT_HANDLE_NW:
660 case GL_VIEW_OBJECT_HANDLE_N:
665 case GL_VIEW_OBJECT_HANDLE_NE:
670 case GL_VIEW_OBJECT_HANDLE_E:
675 case GL_VIEW_OBJECT_HANDLE_SE:
680 case GL_VIEW_OBJECT_HANDLE_S:
685 case GL_VIEW_OBJECT_HANDLE_SW:
690 case GL_VIEW_OBJECT_HANDLE_W:
694 case GL_VIEW_OBJECT_HANDLE_P1:
703 case GL_VIEW_OBJECT_HANDLE_P2:
711 g_print ("Invalid handle.\n"); /* Should not happen! */
714 if ( (handle != GL_VIEW_OBJECT_HANDLE_P1) && (handle != GL_VIEW_OBJECT_HANDLE_P2) )
718 gl_label_object_set_size_honor_aspect (object, w, h);
722 gl_label_object_set_size (object, w, h);
726 * Query the new size in case it was constrained.
728 gl_label_object_get_size (object, &w, &h);
736 case GL_VIEW_OBJECT_HANDLE_NW:
741 case GL_VIEW_OBJECT_HANDLE_N:
742 case GL_VIEW_OBJECT_HANDLE_NE:
747 case GL_VIEW_OBJECT_HANDLE_E:
748 case GL_VIEW_OBJECT_HANDLE_SE:
749 case GL_VIEW_OBJECT_HANDLE_S:
753 case GL_VIEW_OBJECT_HANDLE_SW:
754 case GL_VIEW_OBJECT_HANDLE_W:
760 g_print ("Invalid handle.\n"); /* Should not happen! */
765 gl_label_object_set_size (object, dx, dy);
769 * Put new origin back into world coordinates and set.
771 cairo_user_to_device (cr, &x0, &y0);
773 cairo_device_to_user (cr, &x0, &y0);
774 gl_label_object_set_position (object, x0, y0);
780 * Local Variables: -- emacs
782 * c-basic-offset: 8 -- emacs
783 * tab-width: 8 -- emacs
784 * indent-tabs-mode: nil -- emacs