Fixed dnd with scrolled positioning
[tbo.git] / src / ui-toolbar.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <gtk/gtk.h>
4 #include <glib/gi18n.h>
5 #include "ui-menu.h"
6 #include "ui-toolbar.h"
7 #include "config.h"
8 #include "comic-new-dialog.h"
9 #include "comic-saveas-dialog.h"
10 #include "comic-open-dialog.h"
11 #include "tbo-window.h"
12 #include "comic.h"
13 #include "custom-stock.h"
14 #include "ui-drawing.h"
15
16 #include "frame-tool.h"
17 #include "selector-tool.h"
18 #include "doodle-tool.h"
19 #include "text-tool.h"
20
21 static int SELECTED_TOOL = NONE;
22 static GtkActionGroup *ACTION_GROUP = NULL;
23
24 static ToolStruct TOOLS[] =
25 {
26     {FRAME,
27      frame_tool_on_select,
28      frame_tool_on_unselect,
29      frame_tool_on_move,
30      frame_tool_on_click,
31      frame_tool_on_release,
32      frame_tool_on_key,
33      frame_tool_drawing},
34
35     {SELECTOR,
36      selector_tool_on_select,
37      selector_tool_on_unselect,
38      selector_tool_on_move,
39      selector_tool_on_click,
40      selector_tool_on_release,
41      selector_tool_on_key,
42      selector_tool_drawing},
43
44     {DOODLE,
45      doodle_tool_on_select,
46      doodle_tool_on_unselect,
47      doodle_tool_on_move,
48      doodle_tool_on_click,
49      doodle_tool_on_release,
50      doodle_tool_on_key,
51      doodle_tool_drawing},
52
53     {TEXT,
54      text_tool_on_select,
55      text_tool_on_unselect,
56      text_tool_on_move,
57      text_tool_on_click,
58      text_tool_on_release,
59      text_tool_on_key,
60      text_tool_drawing},
61 };
62
63 typedef struct
64 {
65     enum Tool tool;
66     char *action;
67
68 } tool_and_action;
69
70 void unselect (enum Tool tool, TboWindow *tbo);
71 gboolean select_tool (GtkAction *action, TboWindow *tbo);
72 void update_toolbar (TboWindow *tbo);
73
74 enum Tool
75 get_selected_tool ()
76 {
77     return SELECTED_TOOL;
78 }
79
80
81 void
82 set_current_tab_page (TboWindow *tbo, gboolean setit)
83 {
84     int nth;
85
86     nth = tbo_comic_page_index (tbo->comic);
87     if (setit)
88         gtk_notebook_set_current_page (GTK_NOTEBOOK (tbo->notebook), nth);
89     tbo->dw_scroll = gtk_notebook_get_nth_page (GTK_NOTEBOOK (tbo->notebook), nth);
90     tbo->drawing = gtk_bin_get_child (GTK_BIN (tbo->dw_scroll));
91     set_frame_view (NULL);
92     set_selected_tool (NONE, tbo);
93 }
94
95 gboolean
96 notebook_switch_page_cb (GtkNotebook     *notebook,
97                          GtkNotebookPage *page,
98                          guint            page_num,
99                          TboWindow        *tbo)
100 {
101     tbo_comic_set_current_page_nth (tbo->comic, page_num);
102     set_current_tab_page (tbo, FALSE);
103     update_toolbar (tbo);
104     tbo_window_update_status (tbo, 0, 0);
105     return FALSE;
106 }
107
108 void
109 set_selected_tool (enum Tool tool, TboWindow *tbo)
110 {
111     unselect (SELECTED_TOOL, tbo);
112     SELECTED_TOOL = tool;
113
114     tool_signal (tool, TOOL_SELECT, tbo);
115     update_toolbar (tbo);
116 }
117
118 void
119 update_toolbar (TboWindow *tbo)
120 {
121     GtkAction *prev;
122     GtkAction *next;
123     GtkAction *delete;
124
125     GtkAction *doodle;
126     GtkAction *text;
127     GtkAction *new_frame;
128
129     if (!ACTION_GROUP)
130         return;
131
132     // Page next, prev and delete button sensitive
133     prev = gtk_action_group_get_action (ACTION_GROUP, "PrevPage");
134     next = gtk_action_group_get_action (ACTION_GROUP, "NextPage");
135     delete = gtk_action_group_get_action (ACTION_GROUP, "DelPage");
136
137     if (tbo_comic_page_first (tbo->comic))
138         gtk_action_set_sensitive (prev, FALSE);
139     else
140         gtk_action_set_sensitive (prev, TRUE);
141
142     if (tbo_comic_page_last (tbo->comic))
143         gtk_action_set_sensitive (next, FALSE);
144     else
145         gtk_action_set_sensitive (next, TRUE);
146     if (tbo_comic_len (tbo->comic) > 1)
147         gtk_action_set_sensitive (delete, TRUE);
148     else
149         gtk_action_set_sensitive (delete, FALSE);
150
151     // Frame view disabled in page view
152     doodle = gtk_action_group_get_action (ACTION_GROUP, "Doodle");
153     text = gtk_action_group_get_action (ACTION_GROUP, "Text");
154     new_frame = gtk_action_group_get_action (ACTION_GROUP, "NewFrame");
155
156     if (get_frame_view() == NULL)
157     {
158         gtk_action_set_sensitive (doodle, FALSE);
159         gtk_action_set_sensitive (text, FALSE);
160         gtk_action_set_sensitive (new_frame, TRUE);
161     }
162     else
163     {
164         gtk_action_set_sensitive (doodle, TRUE);
165         gtk_action_set_sensitive (text, TRUE);
166         gtk_action_set_sensitive (new_frame, FALSE);
167     }
168 }
169
170 gboolean
171 toolbar_handler (GtkWidget *widget, gpointer data)
172 {
173     return FALSE;
174 }
175
176 gboolean
177 add_new_page (GtkAction *action, TboWindow *tbo)
178 {
179     Page *page = tbo_comic_new_page (tbo->comic);
180     int nth = tbo_comic_page_nth (tbo->comic, page);
181     gtk_notebook_insert_page (GTK_NOTEBOOK (tbo->notebook),
182                               create_darea (tbo),
183                               NULL,
184                               nth);
185     tbo_window_update_status (tbo, 0, 0);
186     update_toolbar (tbo);
187     return FALSE;
188 }
189
190 gboolean
191 del_current_page (GtkAction *action, TboWindow *tbo)
192 {
193     int nth = tbo_comic_page_index (tbo->comic);
194     tbo_comic_del_current_page (tbo->comic);
195     set_current_tab_page (tbo, TRUE);
196     gtk_notebook_remove_page (GTK_NOTEBOOK (tbo->notebook), nth);
197     tbo_window_update_status (tbo, 0, 0);
198     update_toolbar (tbo);
199     return FALSE;
200 }
201
202 gboolean
203 next_page (GtkAction *action, TboWindow *tbo)
204 {
205     tbo_comic_next_page (tbo->comic);
206     set_current_tab_page (tbo, TRUE);
207     update_toolbar (tbo);
208     tbo_window_update_status (tbo, 0, 0);
209
210     return FALSE;
211 }
212
213 gboolean
214 prev_page (GtkAction *action, TboWindow *tbo)
215 {
216     tbo_comic_prev_page (tbo->comic);
217     set_current_tab_page (tbo, TRUE);
218     update_toolbar (tbo);
219     tbo_window_update_status (tbo, 0, 0);
220
221     return FALSE;
222 }
223
224 gboolean
225 zoom_100 (GtkAction *action, TboWindow *tbo)
226 {
227     tbo_drawing_zoom_100 (tbo);
228     return FALSE;
229 }
230
231 gboolean
232 zoom_in (GtkAction *action, TboWindow *tbo)
233 {
234     tbo_drawing_zoom_in (tbo);
235     return FALSE;
236 }
237
238 gboolean
239 zoom_out (GtkAction *action, TboWindow *tbo)
240 {
241     tbo_drawing_zoom_out (tbo);
242     return FALSE;
243 }
244
245 static const GtkActionEntry tbo_tools_entries [] = {
246     { "NewFileTool", GTK_STOCK_NEW, N_("_New"), "<control>N",
247       N_("New Comic"),
248       G_CALLBACK (tbo_comic_new_dialog) },
249
250     { "OpenFileTool", GTK_STOCK_OPEN, N_("_Open"), "<control>O",
251       N_("Open comic"),
252       G_CALLBACK (tbo_comic_open_dialog) },
253
254     { "SaveFileTool", GTK_STOCK_SAVE, N_("_Save"), "<control>S",
255       N_("Save current document"),
256       G_CALLBACK (tbo_comic_save_dialog) },
257
258     // Page tools
259     { "NewPage", GTK_STOCK_ADD, N_("New Page"), "<control>P",
260       N_("New page"),
261       G_CALLBACK (add_new_page) },
262
263     { "DelPage", GTK_STOCK_DELETE, N_("Delete Page"), "",
264       N_("Delete current page"),
265       G_CALLBACK (del_current_page) },
266
267     { "PrevPage", GTK_STOCK_GO_BACK, N_("Prev Page"), "",
268       N_("Prev page"),
269       G_CALLBACK (prev_page) },
270
271     { "NextPage", GTK_STOCK_GO_FORWARD, N_("Next Page"), "",
272       N_("Next page"),
273       G_CALLBACK (next_page) },
274
275     // Zoom tools
276     { "Zoomin", GTK_STOCK_ZOOM_IN, N_("Zoom in"), "",
277       N_("Zoom in"),
278       G_CALLBACK (zoom_in) },
279     { "Zoom100", GTK_STOCK_ZOOM_100, N_("Zoom 1:1"), "",
280       N_("Zoom 1:1"),
281       G_CALLBACK (zoom_100) },
282     { "Zoomout", GTK_STOCK_ZOOM_OUT, N_("Zoom out"), "",
283       N_("Zoom out"),
284       G_CALLBACK (zoom_out) },
285 };
286
287 static const GtkToggleActionEntry tbo_tools_toogle_entries [] = {
288     // Page view tools
289     { "NewFrame", TBO_STOCK_FRAME, N_("New _Frame"), "<control>F",
290       N_("New Frame"),
291       G_CALLBACK (select_tool), FALSE },
292
293     { "Selector", TBO_STOCK_SELECTOR, N_("Selector"), "",
294       N_("Selector"),
295       G_CALLBACK (select_tool), FALSE },
296
297     // Frame view tools
298     { "Doodle", TBO_STOCK_DOODLE, N_("Doodle"), "",
299       N_("Doodle"),
300       G_CALLBACK (select_tool), FALSE },
301     { "Text", TBO_STOCK_TEXT, N_("Text"), "",
302       N_("Text"),
303       G_CALLBACK (select_tool), FALSE },
304 };
305
306 static const tool_and_action tools_actions [] = {
307     {FRAME, "NewFrame"},
308     {SELECTOR, "Selector"},
309     {DOODLE, "Doodle"},
310     {TEXT, "Text"},
311 };
312
313 void
314 set_selected_tool_and_action (enum Tool tool, TboWindow *tbo)
315 {
316     GtkToggleAction *action;
317     enum Tool action_tool;
318     gchar *name;
319
320     int i;
321     GtkToggleActionEntry entry;
322
323     for (i=0; i<G_N_ELEMENTS (tools_actions); i++)
324     {
325         if (tool == tools_actions[i].tool)
326         {
327             name = (gchar *) tools_actions[i].action;
328             break;
329         }
330     }
331
332     action = (GtkToggleAction *) gtk_action_group_get_action (ACTION_GROUP, name);
333     if (gtk_action_is_sensitive (GTK_ACTION (action)))
334         gtk_toggle_action_set_active (action, TRUE);
335 }
336
337 void
338 unselect (enum Tool tool, TboWindow *tbo)
339 {
340     int i;
341     GtkToggleAction *action;
342
343     for (i=0; i<G_N_ELEMENTS (tools_actions); i++)
344     {
345         if (tools_actions[i].tool == tool)
346         {
347             action = (GtkToggleAction *) gtk_action_group_get_action (ACTION_GROUP,
348                     tools_actions[i].action);
349
350             gtk_toggle_action_set_active (action, FALSE);
351             break;
352         }
353     }
354     tool_signal (tool, TOOL_UNSELECT, tbo);
355 }
356
357 gboolean
358 select_tool (GtkAction *action, TboWindow *tbo)
359 {
360     GtkToggleAction *toggle_action;
361     int i;
362     const gchar *name;
363     enum Tool tool;
364
365     toggle_action = (GtkToggleAction *) action;
366     name = gtk_action_get_name (action);
367
368
369     for (i=0; i<G_N_ELEMENTS (tools_actions); i++)
370     {
371         if (strcmp (tools_actions[i].action, name) == 0)
372         {
373             tool = tools_actions[i].tool;
374             break;
375         }
376     }
377
378     if (gtk_toggle_action_get_active (toggle_action))
379         set_selected_tool (tool, tbo);
380     else
381         set_selected_tool (NONE, tbo);
382     tbo_window_update_status (tbo, 0, 0);
383     return FALSE;
384 }
385
386 GtkWidget *generate_toolbar (TboWindow *window){
387     GtkWidget *toolbar;
388     GtkUIManager *manager;
389     GError *error = NULL;
390
391     manager = gtk_ui_manager_new ();
392     gtk_ui_manager_add_ui_from_file (manager, DATA_DIR "/ui/tbo-toolbar-ui.xml", &error);
393     if (error != NULL)
394     {
395         g_warning ("Could not merge tbo-toolbar-ui.xml: %s", error->message);
396         g_error_free (error);
397     }
398
399     ACTION_GROUP = gtk_action_group_new ("ToolsActions");
400     gtk_action_group_set_translation_domain (ACTION_GROUP, NULL);
401     gtk_action_group_add_actions (ACTION_GROUP, tbo_tools_entries,
402                         G_N_ELEMENTS (tbo_tools_entries), window);
403     gtk_action_group_add_toggle_actions (ACTION_GROUP, tbo_tools_toogle_entries,
404                         G_N_ELEMENTS (tbo_tools_toogle_entries), window);
405
406     gtk_ui_manager_insert_action_group (manager, ACTION_GROUP, 0);
407
408     toolbar = gtk_ui_manager_get_widget (manager, "/toolbar");
409
410     update_toolbar (window);
411
412     return toolbar;
413 }
414
415 void
416 tool_signal (enum Tool tool, enum ToolSignal signal, gpointer data)
417 {
418     int i;
419     ToolStruct *toolstruct = NULL;
420     void **pdata;
421
422     for (i=0; i<G_N_ELEMENTS (TOOLS); i++)
423     {
424         if (tool == TOOLS[i].tool)
425         {
426             toolstruct = &TOOLS[i];
427             break;
428         }
429     }
430
431     if (toolstruct)
432     {
433         switch (signal)
434         {
435             case TOOL_SELECT:
436                 toolstruct->tool_on_select(data);
437                 break;
438             case TOOL_UNSELECT:
439                 toolstruct->tool_on_unselect(data);
440                 break;
441             case TOOL_MOVE:
442                 pdata = data;
443                 toolstruct->tool_on_move (pdata[0], pdata[1], pdata[2]);
444                 break;
445             case TOOL_CLICK:
446                 pdata = data;
447                 toolstruct->tool_on_click (pdata[0], pdata[1], pdata[2]);
448                 break;
449             case TOOL_RELEASE:
450                 pdata = data;
451                 toolstruct->tool_on_release (pdata[0], pdata[1], pdata[2]);
452                 break;
453             case TOOL_KEY:
454                 pdata = data;
455                 toolstruct->tool_on_key (pdata[0], pdata[1], pdata[2]);
456                 break;
457             case TOOL_DRAWING:
458                 toolstruct->tool_drawing (data);
459                 break;
460             default:
461                 break;
462         }
463     }
464 }