07539d73051b24759a63f69754d7aed829049a65
[tbo.git] / src / ui-drawing.c
1 #include <stdio.h>
2 #include <cairo.h>
3 #include <gtk/gtk.h>
4 #include <gdk/gdkkeysyms.h>
5 #include <stdlib.h>
6 #include <glib/gi18n.h>
7 #include <math.h>
8
9 #include "ui-toolbar.h"
10
11 #include "tbo-window.h"
12 #include "ui-drawing.h"
13
14 #include "comic.h"
15 #include "page.h"
16 #include "frame.h"
17
18 #include "frame-tool.h"
19 #include "selector-tool.h"
20 #include "doodle-tool.h"
21 #include "dnd.h"
22
23 #include "tbo-tooltip.h"
24
25
26 Frame *FRAME_VIEW = NULL;
27 float ZOOM_STEP = 0.05;
28 float ZOOM = 1;
29 gboolean KEY_BINDER = TRUE;
30
31 void
32 tbo_drawing_draw_page (cairo_t *cr, Page *page, int w, int h)
33 {
34     Frame *frame;
35     GList *frame_list;
36
37     // white background
38     cairo_set_source_rgb(cr, 1, 1, 1);
39     cairo_rectangle(cr, 0, 0, w, h);
40     cairo_fill(cr);
41
42     for (frame_list = tbo_page_get_frames (page); frame_list; frame_list = frame_list->next)
43     {
44         // draw each frame
45         frame = (Frame *)frame_list->data;
46         tbo_frame_draw (frame, cr);
47     }
48 }
49
50 void
51 tbo_drawing_draw (cairo_t *cr, TboWindow *tbo)
52 {
53     Frame *frame;
54     GList *frame_list;
55     Page *page;
56
57     int w, h;
58
59     w = tbo->comic->width;
60     h = tbo->comic->height;
61     // white background
62     cairo_set_source_rgb(cr, 1, 1, 1);
63     cairo_rectangle(cr, 0, 0, w*ZOOM, h*ZOOM);
64     cairo_fill(cr);
65
66     cairo_scale (cr, ZOOM, ZOOM);
67
68     page = tbo_comic_get_current_page (tbo->comic);
69
70     if (!FRAME_VIEW)
71     {
72         for (frame_list = tbo_page_get_frames (page); frame_list; frame_list = frame_list->next)
73         {
74             // draw each frame
75             frame = (Frame *)frame_list->data;
76             tbo_frame_draw (frame, cr);
77         }
78     }
79     else
80     {
81         tbo_frame_draw_scaled (FRAME_VIEW, cr, w, h);
82     }
83 }
84
85 gboolean
86 on_key_cb (GtkWidget    *widget,
87            GdkEventKey  *event,
88            TboWindow    *tbo)
89 {
90     enum Tool tool;
91     void **data = malloc (sizeof(void *)*3);
92     data[0] = widget;
93     data[1] = event;
94     data[2] = tbo;
95
96     tool = get_selected_tool ();
97     tool_signal (tool, TOOL_KEY, data);
98     free (data);
99
100     update_drawing (tbo);
101     tbo_window_update_status (tbo, 0, 0);
102
103     if (KEY_BINDER)
104     {
105         switch (event->keyval)
106         {
107             case GDK_plus:
108                 tbo_drawing_zoom_in (tbo);
109                 break;
110             case GDK_minus:
111                 tbo_drawing_zoom_out (tbo);
112                 break;
113             case GDK_1:
114                 tbo_drawing_zoom_100 (tbo);
115                 break;
116             case GDK_2:
117                 tbo_drawing_zoom_fit (tbo);
118                 break;
119             case GDK_s:
120                 set_selected_tool_and_action (SELECTOR, tbo);
121                 break;
122             case GDK_t:
123                 set_selected_tool_and_action (TEXT, tbo);
124                 break;
125             case GDK_d:
126                 set_selected_tool_and_action (DOODLE, tbo);
127                 break;
128             case GDK_f:
129                 set_selected_tool_and_action (FRAME, tbo);
130                 break;
131             default:
132                 break;
133         }
134     }
135     return FALSE;
136 }
137
138 gboolean
139 on_expose_cb (GtkWidget      *widget,
140               GdkEventExpose *event,
141               TboWindow       *tbo)
142 {
143     cairo_t *cr;
144     enum Tool tool;
145     GdkWindow *window;
146
147     cr = gdk_cairo_create(GTK_LAYOUT (widget)->bin_window);
148
149     cairo_set_source_rgb (cr, 0, 0, 0);
150     cairo_rectangle (cr, 0, 0, widget->allocation.width,
151                                widget->allocation.height);
152     cairo_fill (cr);
153
154     tbo_drawing_draw (cr, tbo);
155
156     tbo_tooltip_draw (cr);
157
158     // Update drawing helpers
159     tool = get_selected_tool ();
160     tool_signal (tool, TOOL_DRAWING, cr);
161
162     cairo_destroy(cr);
163
164     return FALSE;
165 }
166
167 gboolean
168 on_move_cb (GtkWidget     *widget,
169            GdkEventMotion *event,
170            TboWindow      *tbo)
171 {
172
173     enum Tool tool;
174     void **data = malloc (sizeof(void *)*3);
175     data[0] = widget;
176     event->x = event->x / ZOOM;
177     event->y = event->y / ZOOM;
178     data[1] = event;
179     data[2] = tbo;
180
181     tool = get_selected_tool ();
182     tool_signal (tool, TOOL_MOVE, data);
183     free (data);
184
185     update_drawing (tbo);
186     tbo_window_update_status (tbo, (int)event->x, (int)event->y);
187
188     return FALSE;
189 }
190
191 gboolean
192 on_click_cb (GtkWidget    *widget,
193            GdkEventButton *event,
194            TboWindow      *tbo)
195 {
196     enum Tool tool;
197     void **data = malloc (sizeof(void *)*3);
198     data[0] = widget;
199     event->x = event->x / ZOOM;
200     event->y = event->y / ZOOM;
201     data[1] = event;
202     data[2] = tbo;
203
204     tool = get_selected_tool ();
205     tool_signal (tool, TOOL_CLICK, data);
206     free (data);
207
208     update_drawing (tbo);
209     tbo_window_update_status (tbo, (int)event->x, (int)event->y);
210     return FALSE;
211 }
212
213 gboolean
214 on_release_cb (GtkWidget    *widget,
215            GdkEventButton   *event,
216            TboWindow        *tbo)
217 {
218     enum Tool tool;
219     void **data = malloc (sizeof(void *)*3);
220     data[0] = widget;
221     event->x = event->x / ZOOM;
222     event->y = event->y / ZOOM;
223
224     data[1] = event;
225     data[2] = tbo;
226
227     tool = get_selected_tool ();
228     tool_signal (tool, TOOL_RELEASE, data);
229     free (data);
230
231     update_drawing (tbo);
232     tbo_window_update_status (tbo, (int)event->x, (int)event->y);
233     return FALSE;
234 }
235
236 GtkWidget *
237 get_drawing_area (int width, int height)
238 {
239
240     GtkWidget *drawing;
241
242     drawing = gtk_layout_new(NULL, NULL);
243     gtk_layout_set_size (GTK_LAYOUT (drawing), width+2, height+2);
244
245     return drawing;
246 }
247
248 void
249 darea_connect_signals (TboWindow *tbo, GtkWidget *drawing)
250 {
251     gtk_widget_add_events (drawing, GDK_BUTTON_PRESS_MASK |
252                                     GDK_BUTTON_RELEASE_MASK |
253                                     GDK_POINTER_MOTION_MASK);
254
255     g_signal_connect(drawing, "expose-event",
256             G_CALLBACK (on_expose_cb), tbo);
257
258     g_signal_connect (drawing, "button_press_event",
259             G_CALLBACK (on_click_cb), tbo);
260
261     g_signal_connect (drawing, "button_release_event",
262             G_CALLBACK (on_release_cb), tbo);
263
264     g_signal_connect (drawing, "motion_notify_event",
265             G_CALLBACK (on_move_cb), tbo);
266
267     // drag & drop
268     gtk_drag_dest_set (drawing, GTK_DEST_DEFAULT_ALL, TARGET_LIST, N_TARGETS, GDK_ACTION_COPY);
269     g_signal_connect (drawing, "drag-data-received", G_CALLBACK(drag_data_received_handl), tbo);
270 }
271
272 void
273 darea_disconnect_signals (TboWindow *tbo, GtkWidget *drawing)
274 {
275     g_signal_handlers_disconnect_by_func (drawing, G_CALLBACK (on_expose_cb), tbo);
276     g_signal_handlers_disconnect_by_func (drawing, G_CALLBACK (on_click_cb), tbo);
277     g_signal_handlers_disconnect_by_func (drawing, G_CALLBACK (on_release_cb), tbo);
278     g_signal_handlers_disconnect_by_func (drawing, G_CALLBACK (on_move_cb), tbo);
279     g_signal_handlers_disconnect_by_func (drawing, G_CALLBACK(drag_data_received_handl), tbo);
280 }
281
282 void
283 update_drawing (TboWindow *tbo)
284 {
285     gtk_widget_queue_draw_area (tbo->drawing,
286             0, 0,
287             tbo->drawing->allocation.width,
288             tbo->drawing->allocation.height);
289 }
290
291 void
292 set_frame_view (Frame *frame)
293 {
294     FRAME_VIEW = frame;
295 }
296
297 Frame *
298 get_frame_view ()
299 {
300     return FRAME_VIEW;
301 }
302
303 void tbo_drawing_zoom_in (TboWindow *tbo)
304 {
305     ZOOM += ZOOM_STEP;
306     gtk_layout_set_size (GTK_LAYOUT (tbo->drawing), tbo->comic->width*ZOOM, tbo->comic->height*ZOOM);
307     update_drawing (tbo);
308 }
309
310 void tbo_drawing_zoom_out (TboWindow *tbo)
311 {
312     ZOOM -= ZOOM_STEP;
313     gtk_layout_set_size (GTK_LAYOUT (tbo->drawing), tbo->comic->width*ZOOM, tbo->comic->height*ZOOM);
314     update_drawing (tbo);
315 }
316
317 void tbo_drawing_zoom_100 (TboWindow *tbo)
318 {
319     ZOOM = 1;
320     gtk_layout_set_size (GTK_LAYOUT (tbo->drawing), tbo->comic->width*ZOOM, tbo->comic->height*ZOOM);
321     update_drawing (tbo);
322 }
323
324 void tbo_drawing_zoom_fit (TboWindow *tbo)
325 {
326     float z1, z2;
327     int w, h;
328     w = tbo->drawing->allocation.width;
329     h = tbo->drawing->allocation.height;
330
331     z1 = fabs ((float)w / (float)tbo->comic->width);
332     z2 = fabs ((float)h / (float)tbo->comic->height);
333     ZOOM = z1 < z2 ? z1 : z2;
334
335     gtk_layout_set_size (GTK_LAYOUT (tbo->drawing), tbo->comic->width*ZOOM, tbo->comic->height*ZOOM);
336     update_drawing (tbo);
337 }
338
339 float
340 tbo_drawing_get_zoom ()
341 {
342     return ZOOM;
343 }
344
345 void
346 set_key_binder (gboolean binder)
347 {
348     KEY_BINDER = binder;
349 }
350
351 void
352 tbo_drawing_adjust_scroll (TboWindow *tbo)
353 {
354     gtk_layout_set_size (GTK_LAYOUT (tbo->drawing), tbo->comic->width*ZOOM, tbo->comic->height*ZOOM);
355     update_drawing (tbo);
356 }