Migrated code from gtk2 to gtk3
[tbo.git] / src / tbo-tool-selector.c
1 /*
2  * This file is part of TBO, a gnome comic editor
3  * Copyright (C) 2010  Daniel Garcia Moreno <dani@danigm.net>
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18
19
20 #include <math.h>
21 #include <glib/gi18n.h>
22 #include <gdk/gdkkeysyms.h>
23 #include <stdlib.h>
24 #include "comic.h"
25 #include "frame.h"
26 #include "page.h"
27 #include "tbo-ui-utils.h"
28 #include "tbo-tool-selector.h"
29 #include "tbo-drawing.h"
30 #include "tbo-object-group.h"
31 #include "ui-menu.h"
32 #include "tbo-tooltip.h"
33
34 G_DEFINE_TYPE (TboToolSelector, tbo_tool_selector, TBO_TYPE_TOOL_BASE);
35
36 /* Headers */
37 static void on_move (TboToolBase *tool, GtkWidget *widget, GdkEventMotion *event);
38 static void on_click (TboToolBase *tool, GtkWidget *widget, GdkEventButton *event);
39 static void on_release (TboToolBase *tool, GtkWidget *widget, GdkEventButton *event);
40 static void on_key (TboToolBase *tool, GtkWidget *widget, GdkEventKey *event);
41 static void drawing (TboToolBase *tool, cairo_t *cr);
42
43 static void frame_view_on_move (TboToolBase *tool, GtkWidget *widget, GdkEventMotion *event);
44 static void page_view_on_move (TboToolBase *tool, GtkWidget *widget, GdkEventMotion *event);
45 static void frame_view_on_click (TboToolBase *tool, GtkWidget *widget, GdkEventButton *event);
46 static void page_view_on_click (TboToolBase *tool, GtkWidget *widget, GdkEventButton *event);
47 static void frame_view_drawing (TboToolBase *tool, cairo_t *cr);
48 static void page_view_drawing (TboToolBase *tool, cairo_t *cr);
49 static void frame_view_on_key (TboToolBase *tool, GtkWidget *widget, GdkEventKey *event);
50
51 /* Definitions */
52
53 /* aux */
54 static gboolean
55 update_selected_cb (GtkSpinButton *widget, TboToolSelector *tool)
56 {
57     TboDrawing *drawing = TBO_DRAWING (TBO_TOOL_BASE (tool)->tbo->drawing);
58     if (tool->resizing || tool->clicked || tool->selected_frame == NULL || tool->spin_x == NULL)
59         return FALSE;
60
61     tool->selected_frame->x = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (tool->spin_x));
62     tool->selected_frame->y = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (tool->spin_y));
63     tool->selected_frame->width = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (tool->spin_w));
64     tool->selected_frame->height = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (tool->spin_h));
65
66     tbo_drawing_update (drawing);
67     return FALSE;
68 }
69
70 static gboolean
71 update_color_cb (GtkColorButton *button, TboToolSelector *tool)
72 {
73     TboDrawing *drawing = TBO_DRAWING (TBO_TOOL_BASE (tool)->tbo->drawing);
74     if (tool->resizing || tool->clicked || tool->selected_frame == NULL)
75         return FALSE;
76
77     GdkColor color = { 0, 0, 0, 0 };
78     gtk_color_button_get_color (button, &color);
79     tbo_frame_set_color (tool->selected_frame, &color);
80     tbo_drawing_update (drawing);
81     return FALSE;
82 }
83
84 static gboolean
85 update_border_cb (GtkToggleButton *button, TboToolSelector *tool)
86 {
87     TboDrawing *drawing = TBO_DRAWING (TBO_TOOL_BASE (tool)->tbo->drawing);
88     if (tool->resizing || tool->clicked || tool->selected_frame == NULL)
89         return FALSE;
90
91     tool->selected_frame->border = !tool->selected_frame->border;
92     tbo_drawing_update (drawing);
93     return FALSE;
94 }
95
96 static void
97 empty_tool_area (TboToolSelector *self)
98 {
99     tbo_empty_tool_area (TBO_TOOL_BASE (self)->tbo);
100     self->spin_x = NULL;
101     self->spin_y = NULL;
102     self->spin_h = NULL;
103     self->spin_w = NULL;
104 }
105
106 static void
107 update_tool_area (TboToolSelector *self)
108 {
109     TboWindow *tbo = TBO_TOOL_BASE (self)->tbo;
110     GtkWidget *toolarea = tbo->toolarea;
111     GtkWidget *hpanel;
112     GtkWidget *label;
113     GtkWidget *color;
114     GtkWidget *border;
115     GdkColor gdk_color = { 0, 0, 0, 0 };
116
117     if (!self->spin_x)
118     {
119         empty_tool_area (self);
120         self->spin_x = add_spin_with_label (toolarea, "x: ", self->selected_frame->x);
121         self->spin_y = add_spin_with_label (toolarea, "y: ", self->selected_frame->y);
122         self->spin_w = add_spin_with_label (toolarea, "w: ", self->selected_frame->width);
123         self->spin_h = add_spin_with_label (toolarea, "h: ", self->selected_frame->height);
124
125         g_signal_connect (self->spin_x, "value-changed", G_CALLBACK (update_selected_cb), self);
126         g_signal_connect (self->spin_y, "value-changed", G_CALLBACK (update_selected_cb), self);
127         g_signal_connect (self->spin_w, "value-changed", G_CALLBACK (update_selected_cb), self);
128         g_signal_connect (self->spin_h, "value-changed", G_CALLBACK (update_selected_cb), self);
129
130         hpanel = gtk_hbox_new (FALSE, 0);
131         label = gtk_label_new (_("Background color: "));
132         gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
133         color = gtk_color_button_new ();
134         gdk_color.red = self->selected_frame->color->r * 65535;
135         gdk_color.green = self->selected_frame->color->g * 65535;
136         gdk_color.blue = self->selected_frame->color->b * 65535;
137         gtk_color_button_set_color (GTK_COLOR_BUTTON (color), &gdk_color);
138
139         gtk_box_pack_start (GTK_BOX (hpanel), label, TRUE, TRUE, 5);
140         gtk_box_pack_start (GTK_BOX (hpanel), color, TRUE, TRUE, 5);
141         gtk_box_pack_start (GTK_BOX (toolarea), hpanel, FALSE, FALSE, 5);
142         g_signal_connect (color, "color-set", G_CALLBACK (update_color_cb), self);
143
144         border = gtk_check_button_new_with_label (_("border"));
145         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (border), self->selected_frame->border);
146         gtk_box_pack_start (GTK_BOX (toolarea), border, FALSE, FALSE, 5);
147         g_signal_connect (border, "toggled", G_CALLBACK (update_border_cb), self);
148
149         gtk_widget_show_all (toolarea);
150     }
151
152     gtk_spin_button_set_value (GTK_SPIN_BUTTON (self->spin_x), self->selected_frame->x);
153     gtk_spin_button_set_value (GTK_SPIN_BUTTON (self->spin_y), self->selected_frame->y);
154     gtk_spin_button_set_value (GTK_SPIN_BUTTON (self->spin_w), self->selected_frame->width);
155     gtk_spin_button_set_value (GTK_SPIN_BUTTON (self->spin_h), self->selected_frame->height);
156 }
157
158 static gboolean
159 over_resizer (TboToolSelector *self, Frame *frame, int x, int y)
160 {
161     int rx, ry;
162     rx = frame->x + frame->width;
163     ry = frame->y + frame->height;
164
165     float r_size;
166     r_size = R_SIZE / tbo_drawing_get_zoom (TBO_DRAWING (TBO_TOOL_BASE (self)->tbo->drawing));
167
168     if (((rx-r_size) < x) &&
169         ((rx+r_size) > x) &&
170         ((ry-r_size) < y) &&
171         ((ry+r_size) > y))
172     {
173         return TRUE;
174     }
175     else
176     {
177         return FALSE;
178     }
179 }
180
181 static gboolean
182 over_resizer_obj (TboToolSelector *self, TboObjectBase *obj, int x, int y)
183 {
184     int rx, ry;
185     int ox, oy, ow, oh;
186     tbo_frame_get_obj_relative (obj, &ox, &oy, &ow, &oh);
187     rx = ox + (ow * cos(obj->angle) - oh * sin(obj->angle));
188     ry = oy + (oh * cos(obj->angle) + ow * sin(obj->angle));
189
190     float r_size;
191     r_size = R_SIZE / tbo_drawing_get_zoom (TBO_DRAWING (TBO_TOOL_BASE (self)->tbo->drawing));
192
193     if (((rx-r_size) < x) &&
194         ((rx+r_size) > x) &&
195         ((ry-r_size) < y) &&
196         ((ry+r_size) > y))
197     {
198         return TRUE;
199     }
200     else
201     {
202         return FALSE;
203     }
204 }
205
206 static gboolean
207 over_rotater_obj (TboToolSelector *self, TboObjectBase *obj, int x, int y)
208 {
209     int rx, ry;
210     int ox, oy, ow, oh;
211     tbo_frame_get_obj_relative (obj, &ox, &oy, &ow, &oh);
212     rx = ox;
213     ry = oy;
214
215     float r_size;
216     r_size = R_SIZE / tbo_drawing_get_zoom (TBO_DRAWING (TBO_TOOL_BASE (self)->tbo->drawing));
217
218     if (((rx-r_size/2.0) < x) &&
219         ((rx+r_size/2.0) > x) &&
220         ((ry-r_size/2.0) < y) &&
221         ((ry+r_size/2.0) > y))
222     {
223         return TRUE;
224     }
225     else
226     {
227         return FALSE;
228     }
229 }
230
231 /* tool signal */
232 static void
233 on_move (TboToolBase *tool, GtkWidget *widget, GdkEventMotion *event)
234 {
235     TboDrawing *drawing = TBO_DRAWING (tool->tbo->drawing);
236     Frame *frame = tbo_drawing_get_current_frame (drawing);
237     if (frame)
238         frame_view_on_move (tool, widget, event);
239     else
240         page_view_on_move (tool, widget, event);
241
242     tbo_drawing_update (drawing);
243 }
244
245 static void
246 on_click (TboToolBase *tool, GtkWidget *widget, GdkEventButton *event)
247 {
248     TboDrawing *drawing = TBO_DRAWING (tool->tbo->drawing);
249     Frame *frame = tbo_drawing_get_current_frame (drawing);
250     if (frame)
251         frame_view_on_click (tool, widget, event);
252     else
253         page_view_on_click (tool, widget, event);
254
255     tbo_drawing_update (drawing);
256 }
257
258 static void
259 on_release (TboToolBase *tool, GtkWidget *widget, GdkEventButton *event)
260 {
261     TboToolSelector *self = TBO_TOOL_SELECTOR (tool);
262     self->start_x = 0;
263     self->start_y = 0;
264     self->clicked = FALSE;
265     self->resizing = FALSE;
266     self->rotating = FALSE;
267 }
268
269 static void
270 on_key (TboToolBase *tool, GtkWidget *widget, GdkEventKey *event)
271 {
272     TboDrawing *drawing = TBO_DRAWING (tool->tbo->drawing);
273     Frame *frame = tbo_drawing_get_current_frame (drawing);
274     if (frame)
275         frame_view_on_key (tool, widget, event);
276 }
277
278 static void
279 drawing (TboToolBase *tool, cairo_t *cr)
280 {
281     TboDrawing *drawing = TBO_DRAWING (tool->tbo->drawing);
282     Frame *frame = tbo_drawing_get_current_frame (drawing);
283     if (frame)
284         frame_view_drawing (tool, cr);
285     else
286         page_view_drawing (tool, cr);
287 }
288
289 /* frame view */
290 static void
291 frame_view_on_move (TboToolBase *tool, GtkWidget *widget, GdkEventMotion *event)
292 {
293     int x, y, offset_x, offset_y;
294     TboToolSelector *self = TBO_TOOL_SELECTOR (tool);
295
296     x = (int)event->x;
297     y = (int)event->y;
298
299     self->x = x;
300     self->y = y;
301
302     if (self->selected_object != NULL)
303     {
304         if (self->clicked)
305         {
306             offset_x = (self->start_x - x) / tbo_frame_get_scale_factor ();
307             offset_y = (self->start_y - y) / tbo_frame_get_scale_factor ();
308
309             // resizing object
310             if (self->resizing)
311             {
312                 self->selected_object->width = self->start_m_w - offset_x;
313                 self->selected_object->height = self->start_m_h - offset_y;
314             }
315             else if (self->rotating)
316             {
317                 self->selected_object->angle = atan2 (offset_y, offset_x);
318             }
319             // moving object
320             else
321             {
322                 self->selected_object->x = self->start_m_x - offset_x;
323                 self->selected_object->y = self->start_m_y - offset_y;
324             }
325         }
326
327         // updating group object
328         if (TBO_IS_OBJECT_GROUP (self->selected_object))
329         {
330             tbo_object_group_update_status (TBO_OBJECT_GROUP (self->selected_object));
331
332             self->start_x = x;
333             self->start_y = y;
334             self->start_m_x = self->selected_object->x;
335             self->start_m_y = self->selected_object->y;
336             self->start_m_w = self->selected_object->width;
337             self->start_m_h = self->selected_object->height;
338         }
339
340         tbo_object_group_set_vars (self->selected_object);
341         // over resizer
342         if (over_resizer_obj (self, self->selected_object, x, y))
343         {
344             self->over_resizer = TRUE;
345         }
346         else
347         {
348             self->over_resizer = FALSE;
349         }
350         // over rotater
351         if (over_rotater_obj (self, self->selected_object, x, y))
352         {
353             self->over_rotater = TRUE;
354         }
355         else
356         {
357             self->over_rotater = FALSE;
358         }
359         tbo_object_group_unset_vars (self->selected_object);
360
361     }
362 }
363
364 static void
365 frame_view_on_click (TboToolBase *tool, GtkWidget *widget, GdkEventButton *event)
366 {
367     TboToolSelector *self = TBO_TOOL_SELECTOR (tool);
368     int x, y;
369     GList *obj_list;
370     Frame *frame;
371     TboObjectBase *obj, *obj2;
372     TboObjectGroup *group;
373     TboDrawing *drawing = TBO_DRAWING (tool->tbo->drawing);
374     gboolean found = FALSE;
375
376     x = (int)event->x;
377     y = (int)event->y;
378
379     // resizing
380     tbo_object_group_set_vars (self->selected_object);
381     if (self->selected_object && over_resizer_obj (self, self->selected_object, x, y))
382     {
383         self->resizing = TRUE;
384     }
385     else if (self->selected_object && over_rotater_obj (self, self->selected_object, x, y))
386     {
387         self->rotating = TRUE;
388     }
389     else
390     {
391         frame = tbo_drawing_get_current_frame (drawing);
392
393         for (obj_list = g_list_first (frame->objects); obj_list; obj_list = obj_list->next)
394         {
395             obj = TBO_OBJECT_BASE (obj_list->data);
396             tbo_object_group_set_vars (obj);
397             if (tbo_frame_point_inside_obj (obj, x, y))
398             {
399                 // Selecting last occurrence.
400                 obj2 = obj;
401                 found = TRUE;
402             }
403             tbo_object_group_unset_vars (obj);
404         }
405
406         if (!found)
407             tbo_tool_selector_set_selected_obj (self, NULL);
408         else
409         {
410             if ((event->state & GDK_SHIFT_MASK) && self->selected_object) {
411                 if (!TBO_IS_OBJECT_GROUP (self->selected_object))
412                 {
413                     group = TBO_OBJECT_GROUP (tbo_object_group_new ());
414                     tbo_frame_add_obj (frame, TBO_OBJECT_BASE (group));
415                     tbo_object_group_add (group, self->selected_object);
416                 }
417                 else
418                     group = TBO_OBJECT_GROUP (self->selected_object);
419
420                 tbo_object_group_add (group, obj2);
421                 obj2 = TBO_OBJECT_BASE (group);
422             }
423             tbo_tool_selector_set_selected_obj (self, obj2);
424         }
425     }
426     tbo_object_group_unset_vars (self->selected_object);
427
428     self->start_x = x;
429     self->start_y = y;
430
431     if (self->selected_object)
432     {
433         self->start_m_x = self->selected_object->x;
434         self->start_m_y = self->selected_object->y;
435         self->start_m_w = self->selected_object->width;
436         self->start_m_h = self->selected_object->height;
437     }
438     self->clicked = TRUE;
439 }
440
441 static void
442 frame_view_drawing (TboToolBase *tool, cairo_t *cr)
443 {
444     const double dashes[] = {5, 5};
445     Color border = {0.9, 0.9, 0};
446     Color white = {1, 1, 1};
447     Color black = {0, 0, 0};
448     Color *resizer_border;
449     Color *resizer_fill;
450     Color *rotater_border;
451     Color *rotater_fill;
452     int x, y;
453     float r_size;
454     TboToolSelector *self = TBO_TOOL_SELECTOR (tool);
455     TboObjectBase *current_obj = self->selected_object;
456     TboDrawing *drawing = TBO_DRAWING (tool->tbo->drawing);
457
458     if (current_obj != NULL)
459     {
460         if (TBO_IS_OBJECT_GROUP (current_obj))
461             tbo_object_group_set_vars (current_obj);
462
463         cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
464         cairo_set_line_width (cr, 1);
465         cairo_set_dash (cr, dashes, G_N_ELEMENTS (dashes), 0);
466         cairo_set_source_rgb (cr, border.r, border.g, border.b);
467         int ox, oy, ow, oh;
468         tbo_frame_get_obj_relative (current_obj, &ox, &oy, &ow, &oh);
469
470         cairo_translate (cr, ox, oy);
471         cairo_rotate (cr, current_obj->angle);
472         cairo_rectangle (cr, 0, 0, ow, oh);
473         cairo_stroke (cr);
474
475         // resizer
476         if (self->over_resizer)
477         {
478             resizer_fill = &black;
479             resizer_border = &white;
480         }
481         else
482         {
483             resizer_fill = &white;
484             resizer_border = &black;
485         }
486
487         // rotater
488         if (self->over_rotater)
489         {
490             rotater_fill = &black;
491             rotater_border = &white;
492         }
493         else
494         {
495             rotater_fill = &white;
496             rotater_border = &black;
497         }
498
499         cairo_set_line_width (cr, 1);
500         cairo_set_dash (cr, dashes, 0, 0);
501
502         x = ow;
503         y = oh;
504
505         r_size = R_SIZE / tbo_drawing_get_zoom (drawing);
506         cairo_set_line_width (cr, 1/tbo_drawing_get_zoom (drawing));
507
508         cairo_rectangle (cr, x, y, r_size, r_size);
509         cairo_set_source_rgb(cr, resizer_fill->r, resizer_fill->g, resizer_fill->b);
510         cairo_fill (cr);
511
512         cairo_set_source_rgb(cr, resizer_border->r, resizer_border->g, resizer_border->b);
513         cairo_rectangle (cr, x, y, r_size, r_size);
514         cairo_stroke (cr);
515
516         // object rotate zone
517         cairo_set_source_rgb(cr, rotater_fill->r, rotater_fill->g, rotater_fill->b);
518         cairo_arc (cr, 0, 0, r_size / 2., 0, 2 * M_PI);
519         cairo_fill (cr);
520         cairo_set_source_rgb(cr, rotater_border->r, rotater_border->g, rotater_border->b);
521         cairo_arc (cr, 0, 0, r_size / 2., 0, 2 * M_PI);
522         cairo_stroke (cr);
523         cairo_set_line_width (cr, tbo_drawing_get_zoom (drawing));
524
525         cairo_rotate (cr, -current_obj->angle);
526         cairo_translate (cr, -ox, -oy);
527
528         cairo_set_antialias (cr, CAIRO_ANTIALIAS_DEFAULT);
529
530         if (self->rotating)
531         {
532             cairo_set_source_rgb(cr, 1, 0, 0);
533             cairo_move_to (cr, ox, oy);
534             cairo_line_to (cr, self->x, self->y);
535             cairo_stroke (cr);
536         }
537
538         if (TBO_IS_OBJECT_GROUP (current_obj))
539             tbo_object_group_unset_vars (current_obj);
540     }
541 }
542
543 static void
544 frame_view_on_key (TboToolBase *tool, GtkWidget *widget, GdkEventKey *event)
545 {
546     TboToolSelector *self = TBO_TOOL_SELECTOR (tool);
547     TboObjectBase *current_obj = self->selected_object;
548     TboDrawing *drawing = TBO_DRAWING (tool->tbo->drawing);
549
550     if (self->selected_frame != NULL && event->keyval == GDK_KEY_Escape)
551     {
552         tbo_tool_selector_set_selected (self, NULL);
553         tbo_drawing_set_current_frame (drawing, NULL);
554         update_menubar (tool->tbo);
555         tbo_toolbar_update (tool->tbo->toolbar);
556     }
557
558     if (current_obj != NULL)
559     {
560         switch (event->keyval)
561         {
562             case GDK_KEY_less:
563                 tbo_object_base_resize (current_obj, RESIZE_LESS);
564                 break;
565             case GDK_KEY_greater:
566                 tbo_object_base_resize (current_obj, RESIZE_GREATER);
567                 break;
568             case GDK_KEY_Up:
569                 tbo_object_base_move (current_obj, MOVE_UP);
570                 break;
571             case GDK_KEY_Down:
572                 tbo_object_base_move (current_obj, MOVE_DOWN);
573                 break;
574             case GDK_KEY_Left:
575                 tbo_object_base_move (current_obj, MOVE_LEFT);
576                 break;
577             case GDK_KEY_Right:
578                 tbo_object_base_move (current_obj, MOVE_RIGHT);
579                 break;
580             default:
581                 break;
582         }
583     }
584     tbo_drawing_update (drawing);
585 }
586
587 static void
588 page_view_drawing (TboToolBase *tool, cairo_t *cr)
589 {
590     const double dashes[] = {5, 5};
591     Color border = {0.9, 0.9, 0};
592     Color white = {1, 1, 1};
593     Color black = {0, 0, 0};
594     Color *resizer_border;
595     Color *resizer_fill;
596     int x, y;
597     float r_size;
598
599     TboToolSelector *self = TBO_TOOL_SELECTOR (tool);
600     Frame *selected = self->selected_frame;
601     TboDrawing *drawing = TBO_DRAWING (tool->tbo->drawing);
602
603     if (selected != NULL)
604     {
605         cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
606         cairo_set_line_width (cr, 1);
607         cairo_set_dash (cr, dashes, G_N_ELEMENTS (dashes), 0);
608         cairo_set_source_rgb (cr, border.r, border.g, border.b);
609         cairo_rectangle (cr, selected->x, selected->y,
610                 selected->width, selected->height);
611         cairo_stroke (cr);
612
613         // resizer
614         if (self->over_resizer)
615         {
616             resizer_fill = &black;
617             resizer_border = &white;
618         }
619         else
620         {
621             resizer_fill = &white;
622             resizer_border = &black;
623         }
624
625         cairo_set_line_width (cr, 1);
626         cairo_set_dash (cr, dashes, 0, 0);
627
628         x = selected->x + selected->width;
629         y = selected->y + selected->height;
630
631         r_size = R_SIZE / tbo_drawing_get_zoom (drawing);
632         cairo_set_line_width (cr, 1 / tbo_drawing_get_zoom (drawing));
633         cairo_rectangle (cr, x, y, r_size, r_size);
634         cairo_set_source_rgb(cr, resizer_fill->r, resizer_fill->g, resizer_fill->b);
635         cairo_fill (cr);
636
637         cairo_set_source_rgb(cr, resizer_border->r, resizer_border->g, resizer_border->b);
638         cairo_rectangle (cr, x, y, r_size, r_size);
639         cairo_stroke (cr);
640         cairo_set_line_width (cr, tbo_drawing_get_zoom (drawing));
641
642         cairo_set_antialias (cr, CAIRO_ANTIALIAS_DEFAULT);
643     }
644 }
645
646 static void
647 page_view_on_click (TboToolBase *tool, GtkWidget *widget, GdkEventButton *event)
648 {
649     int x, y;
650     GList *frame_list;
651     Page *page;
652     Frame *frame;
653     gboolean found = FALSE;
654
655     TboWindow *tbo = tool->tbo;
656     TboToolSelector *self = TBO_TOOL_SELECTOR (tool);
657     Frame *selected;
658     TboDrawing *drawing = TBO_DRAWING (tool->tbo->drawing);
659
660     x = (int)event->x;
661     y = (int)event->y;
662
663
664     page = tbo_comic_get_current_page (tbo->comic);
665     for (frame_list = tbo_page_get_frames (page); frame_list; frame_list = frame_list->next)
666     {
667         frame = (Frame *)frame_list->data;
668         if (tbo_frame_point_inside (frame, x, y))
669         {
670             // Selecting last occurrence.
671             tbo_tool_selector_set_selected (self, frame);
672             found = TRUE;
673         }
674     }
675     selected = self->selected_frame;
676
677     // resizing
678     if (selected && over_resizer (self, selected, x, y))
679     {
680         self->resizing = TRUE;
681     }
682     else if (!found)
683         tbo_tool_selector_set_selected (self, NULL);
684
685     // double click, frame view
686     if (selected && event->type == GDK_2BUTTON_PRESS)
687     {
688         tbo_drawing_set_current_frame (drawing, selected);
689         empty_tool_area (self);
690         tbo_tooltip_set (NULL, 0, 0, tbo);
691         // TODO add tooltip_notify
692         tbo_tooltip_set_center_timeout (_("press esc to go back"), 3000, tbo);
693         update_menubar (tbo);
694         tbo_toolbar_update (tbo->toolbar);
695     }
696
697     self->start_x = x;
698     self->start_y = y;
699
700     if (selected)
701     {
702         self->start_m_x = selected->x;
703         self->start_m_y = selected->y;
704         self->start_m_w = selected->width;
705         self->start_m_h = selected->height;
706         tbo_page_set_current_frame (page, selected);
707     }
708     self->clicked = TRUE;
709 }
710
711 static void
712 page_view_on_move (TboToolBase *tool, GtkWidget *widget, GdkEventMotion *event)
713 {
714     int x, y, offset_x, offset_y;
715     TboWindow *tbo = tool->tbo;
716     TboToolSelector *self = TBO_TOOL_SELECTOR (tool);
717     Frame *selected = self->selected_frame;
718
719     x = (int)event->x;
720     y = (int)event->y;
721
722     if (selected != NULL)
723     {
724         if (self->clicked)
725         {
726             offset_x = (self->start_x - x);
727             offset_y = (self->start_y - y);
728
729             // resizing frame
730             if (self->resizing)
731             {
732                 selected->width = abs (self->start_m_w - offset_x);
733                 selected->height = abs (self->start_m_h - offset_y);
734
735                 update_tool_area (self);
736             }
737             // moving frame
738             else
739             {
740                 selected->x = self->start_m_x - offset_x;
741                 selected->y = self->start_m_y - offset_y;
742
743                 update_tool_area (self);
744             }
745         }
746
747         // over resizer
748         if (over_resizer (self, selected, x, y))
749         {
750             self->over_resizer = TRUE;
751         }
752         else
753         {
754             self->over_resizer = FALSE;
755         }
756     }
757
758     GList *frame_list;
759     Frame *frame;
760     Page *page = tbo_comic_get_current_page (tbo->comic);
761     gboolean found = FALSE;
762     int x1, y1;
763
764     for (frame_list = tbo_page_get_frames (page); frame_list && !found; frame_list = frame_list->next)
765     {
766         if (tbo_frame_point_inside ((Frame*)frame_list->data, x, y))
767         {
768             frame = (Frame*)frame_list->data;
769             x1 = frame->x + (frame->width / 2);
770             y1 = frame->y + (frame->height / 2);
771             tbo_tooltip_set (_("double click here"), x1, y1, tbo);
772             found = TRUE;
773         }
774     }
775     if (!found)
776         tbo_tooltip_set(NULL, 0, 0, tbo);
777 }
778
779 /* init methods */
780
781 static void
782 tbo_tool_selector_init (TboToolSelector *self)
783 {
784     self->x = 0;
785     self->y = 0;
786     self->start_x = 0;
787     self->start_y = 0;
788     self->start_m_x = 0;
789     self->start_m_y = 0;
790     self->start_m_w = 0;
791     self->start_m_h = 0;
792     self->clicked = FALSE;
793     self->over_resizer = FALSE;
794     self->over_rotater = FALSE;
795     self->resizing = FALSE;
796     self->rotating = FALSE;
797     self->spin_w = NULL;
798     self->spin_h = NULL;
799     self->spin_x = NULL;
800     self->spin_y = NULL;
801
802     self->parent_instance.on_move = on_move;
803     self->parent_instance.on_click = on_click;
804     self->parent_instance.on_release = on_release;
805     self->parent_instance.on_key = on_key;
806     self->parent_instance.drawing = drawing;
807 }
808
809 static void
810 tbo_tool_selector_class_init (TboToolSelectorClass *klass)
811 {
812 }
813
814 /* object functions */
815
816 GObject *
817 tbo_tool_selector_new ()
818 {
819     GObject *tbo_tool;
820     tbo_tool = g_object_new (TBO_TYPE_TOOL_SELECTOR, NULL);
821     return tbo_tool;
822 }
823
824 GObject *
825 tbo_tool_selector_new_with_params (TboWindow *tbo)
826 {
827     GObject *tbo_tool;
828     TboToolBase *tbo_tool_base;
829     tbo_tool = g_object_new (TBO_TYPE_TOOL_SELECTOR, NULL);
830     tbo_tool_base = TBO_TOOL_BASE (tbo_tool);
831     tbo_tool_base->tbo = tbo;
832     return tbo_tool;
833 }
834
835 Frame *
836 tbo_tool_selector_get_selected_frame (TboToolSelector *self)
837 {
838     return self->selected_frame;
839 }
840
841 TboObjectBase *
842 tbo_tool_selector_get_selected_obj (TboToolSelector *self)
843 {
844     return self->selected_object;
845 }
846
847 void
848 tbo_tool_selector_set_selected (TboToolSelector *self, Frame *frame)
849 {
850     self->selected_frame = frame;
851     empty_tool_area (self);
852     if (self->selected_frame != NULL)
853         update_tool_area (self);
854     update_menubar (TBO_TOOL_BASE (self)->tbo);
855 }
856
857 void
858 tbo_tool_selector_set_selected_obj (TboToolSelector *self, TboObjectBase *obj)
859 {
860     if (!obj && TBO_IS_OBJECT_GROUP (self->selected_object))
861     {
862         TboDrawing *drawing = TBO_DRAWING (TBO_TOOL_BASE (self)->tbo->drawing);
863         Frame *frame = tbo_drawing_get_current_frame (drawing);
864         tbo_frame_del_obj (frame, self->selected_object);
865     }
866     self->selected_object = obj;
867     update_menubar (TBO_TOOL_BASE (self)->tbo);
868 }
869