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