Change between tools with keys
[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->drawing = gtk_bin_get_child (GTK_BIN (gtk_notebook_get_nth_page (GTK_NOTEBOOK (tbo->notebook), nth)));
90     set_frame_view (NULL);
91     set_selected_tool (NONE, tbo);
92 }
93
94 gboolean
95 notebook_switch_page_cb (GtkNotebook     *notebook,
96                          GtkNotebookPage *page,
97                          guint            page_num,
98                          TboWindow        *tbo)
99 {
100     tbo_comic_set_current_page_nth (tbo->comic, page_num);
101     set_current_tab_page (tbo, FALSE);
102     update_toolbar (tbo);
103     tbo_window_update_status (tbo, 0, 0);
104     return FALSE;
105 }
106
107 void
108 set_selected_tool (enum Tool tool, TboWindow *tbo)
109 {
110     unselect (SELECTED_TOOL, tbo);
111     SELECTED_TOOL = tool;
112
113     tool_signal (tool, TOOL_SELECT, tbo);
114     update_toolbar (tbo);
115 }
116
117 void
118 update_toolbar (TboWindow *tbo)
119 {
120     GtkAction *prev;
121     GtkAction *next;
122     GtkAction *delete;
123
124     GtkAction *doodle;
125     GtkAction *text;
126     GtkAction *new_frame;
127
128     if (!ACTION_GROUP)
129         return;
130
131     // Page next, prev and delete button sensitive
132     prev = gtk_action_group_get_action (ACTION_GROUP, "PrevPage");
133     next = gtk_action_group_get_action (ACTION_GROUP, "NextPage");
134     delete = gtk_action_group_get_action (ACTION_GROUP, "DelPage");
135
136     if (tbo_comic_page_first (tbo->comic))
137         gtk_action_set_sensitive (prev, FALSE);
138     else
139         gtk_action_set_sensitive (prev, TRUE);
140
141     if (tbo_comic_page_last (tbo->comic))
142         gtk_action_set_sensitive (next, FALSE);
143     else
144         gtk_action_set_sensitive (next, TRUE);
145     if (tbo_comic_len (tbo->comic) > 1)
146         gtk_action_set_sensitive (delete, TRUE);
147     else
148         gtk_action_set_sensitive (delete, FALSE);
149
150     // Frame view disabled in page view
151     doodle = gtk_action_group_get_action (ACTION_GROUP, "Doodle");
152     text = gtk_action_group_get_action (ACTION_GROUP, "Text");
153     new_frame = gtk_action_group_get_action (ACTION_GROUP, "NewFrame");
154
155     if (get_frame_view() == NULL)
156     {
157         gtk_action_set_sensitive (doodle, FALSE);
158         gtk_action_set_sensitive (text, FALSE);
159         gtk_action_set_sensitive (new_frame, TRUE);
160     }
161     else
162     {
163         gtk_action_set_sensitive (doodle, TRUE);
164         gtk_action_set_sensitive (text, TRUE);
165         gtk_action_set_sensitive (new_frame, FALSE);
166     }
167 }
168
169 gboolean
170 toolbar_handler (GtkWidget *widget, gpointer data)
171 {
172     return FALSE;
173 }
174
175 gboolean
176 add_new_page (GtkAction *action, TboWindow *tbo)
177 {
178     Page *page = tbo_comic_new_page (tbo->comic);
179     int nth = tbo_comic_page_nth (tbo->comic, page);
180     gtk_notebook_insert_page (GTK_NOTEBOOK (tbo->notebook),
181                               create_darea (tbo),
182                               NULL,
183                               nth);
184     tbo_window_update_status (tbo, 0, 0);
185     update_toolbar (tbo);
186     return FALSE;
187 }
188
189 gboolean
190 del_current_page (GtkAction *action, TboWindow *tbo)
191 {
192     int nth = tbo_comic_page_index (tbo->comic);
193     tbo_comic_del_current_page (tbo->comic);
194     set_current_tab_page (tbo, TRUE);
195     gtk_notebook_remove_page (GTK_NOTEBOOK (tbo->notebook), nth);
196     tbo_window_update_status (tbo, 0, 0);
197     update_toolbar (tbo);
198     return FALSE;
199 }
200
201 gboolean
202 next_page (GtkAction *action, TboWindow *tbo)
203 {
204     tbo_comic_next_page (tbo->comic);
205     set_current_tab_page (tbo, TRUE);
206     update_toolbar (tbo);
207     tbo_window_update_status (tbo, 0, 0);
208
209     return FALSE;
210 }
211
212 gboolean
213 prev_page (GtkAction *action, TboWindow *tbo)
214 {
215     tbo_comic_prev_page (tbo->comic);
216     set_current_tab_page (tbo, TRUE);
217     update_toolbar (tbo);
218     tbo_window_update_status (tbo, 0, 0);
219
220     return FALSE;
221 }
222
223 gboolean
224 zoom_100 (GtkAction *action, TboWindow *tbo)
225 {
226     tbo_drawing_zoom_100 (tbo);
227     return FALSE;
228 }
229
230 gboolean
231 zoom_in (GtkAction *action, TboWindow *tbo)
232 {
233     tbo_drawing_zoom_in (tbo);
234     return FALSE;
235 }
236
237 gboolean
238 zoom_out (GtkAction *action, TboWindow *tbo)
239 {
240     tbo_drawing_zoom_out (tbo);
241     return FALSE;
242 }
243
244 static const GtkActionEntry tbo_tools_entries [] = {
245     { "NewFileTool", GTK_STOCK_NEW, N_("_New"), "<control>N",
246       N_("New Comic"),
247       G_CALLBACK (tbo_comic_new_dialog) },
248
249     { "OpenFileTool", GTK_STOCK_OPEN, N_("_Open"), "<control>O",
250       N_("Open comic"),
251       G_CALLBACK (tbo_comic_open_dialog) },
252
253     { "SaveFileTool", GTK_STOCK_SAVE, N_("_Save"), "<control>S",
254       N_("Save current document"),
255       G_CALLBACK (tbo_comic_save_dialog) },
256
257     // Page tools
258     { "NewPage", GTK_STOCK_ADD, N_("New Page"), "<control>P",
259       N_("New page"),
260       G_CALLBACK (add_new_page) },
261
262     { "DelPage", GTK_STOCK_DELETE, N_("Delete Page"), "",
263       N_("Delete current page"),
264       G_CALLBACK (del_current_page) },
265
266     { "PrevPage", GTK_STOCK_GO_BACK, N_("Prev Page"), "",
267       N_("Prev page"),
268       G_CALLBACK (prev_page) },
269
270     { "NextPage", GTK_STOCK_GO_FORWARD, N_("Next Page"), "",
271       N_("Next page"),
272       G_CALLBACK (next_page) },
273
274     // Zoom tools
275     { "Zoomin", GTK_STOCK_ZOOM_IN, N_("Zoom in"), "",
276       N_("Zoom in"),
277       G_CALLBACK (zoom_in) },
278     { "Zoom100", GTK_STOCK_ZOOM_100, N_("Zoom 1:1"), "",
279       N_("Zoom 1:1"),
280       G_CALLBACK (zoom_100) },
281     { "Zoomout", GTK_STOCK_ZOOM_OUT, N_("Zoom out"), "",
282       N_("Zoom out"),
283       G_CALLBACK (zoom_out) },
284 };
285
286 static const GtkToggleActionEntry tbo_tools_toogle_entries [] = {
287     // Page view tools
288     { "NewFrame", TBO_STOCK_FRAME, N_("New _Frame"), "<control>F",
289       N_("New Frame"),
290       G_CALLBACK (select_tool), FALSE },
291
292     { "Selector", TBO_STOCK_SELECTOR, N_("Selector"), "",
293       N_("Selector"),
294       G_CALLBACK (select_tool), FALSE },
295
296     // Frame view tools
297     { "Doodle", TBO_STOCK_DOODLE, N_("Doodle"), "",
298       N_("Doodle"),
299       G_CALLBACK (select_tool), FALSE },
300     { "Text", TBO_STOCK_TEXT, N_("Text"), "",
301       N_("Text"),
302       G_CALLBACK (select_tool), FALSE },
303 };
304
305 static const tool_and_action tools_actions [] = {
306     {FRAME, "NewFrame"},
307     {SELECTOR, "Selector"},
308     {DOODLE, "Doodle"},
309     {TEXT, "Text"},
310 };
311
312 void
313 set_selected_tool_and_action (enum Tool tool, TboWindow *tbo)
314 {
315     GtkToggleAction *action;
316     enum Tool action_tool;
317     gchar *name;
318
319     int i;
320     GtkToggleActionEntry entry;
321
322     for (i=0; i<G_N_ELEMENTS (tools_actions); i++)
323     {
324         if (tool == tools_actions[i].tool)
325         {
326             name = (gchar *) tools_actions[i].action;
327             break;
328         }
329     }
330
331     action = (GtkToggleAction *) gtk_action_group_get_action (ACTION_GROUP, name);
332     if (gtk_action_is_sensitive (GTK_ACTION (action)))
333         gtk_toggle_action_set_active (action, TRUE);
334 }
335
336 void
337 unselect (enum Tool tool, TboWindow *tbo)
338 {
339     int i;
340     GtkToggleAction *action;
341
342     for (i=0; i<G_N_ELEMENTS (tools_actions); i++)
343     {
344         if (tools_actions[i].tool == tool)
345         {
346             action = (GtkToggleAction *) gtk_action_group_get_action (ACTION_GROUP,
347                     tools_actions[i].action);
348
349             gtk_toggle_action_set_active (action, FALSE);
350             break;
351         }
352     }
353     tool_signal (tool, TOOL_UNSELECT, tbo);
354 }
355
356 gboolean
357 select_tool (GtkAction *action, TboWindow *tbo)
358 {
359     GtkToggleAction *toggle_action;
360     int i;
361     const gchar *name;
362     enum Tool tool;
363
364     toggle_action = (GtkToggleAction *) action;
365     name = gtk_action_get_name (action);
366
367
368     for (i=0; i<G_N_ELEMENTS (tools_actions); i++)
369     {
370         if (strcmp (tools_actions[i].action, name) == 0)
371         {
372             tool = tools_actions[i].tool;
373             break;
374         }
375     }
376
377     if (gtk_toggle_action_get_active (toggle_action))
378         set_selected_tool (tool, tbo);
379     else
380         set_selected_tool (NONE, tbo);
381     tbo_window_update_status (tbo, 0, 0);
382     return FALSE;
383 }
384
385 GtkWidget *generate_toolbar (TboWindow *window){
386     GtkWidget *toolbar;
387     GtkUIManager *manager;
388     GError *error = NULL;
389
390     manager = gtk_ui_manager_new ();
391     gtk_ui_manager_add_ui_from_file (manager, DATA_DIR "/ui/tbo-toolbar-ui.xml", &error);
392     if (error != NULL)
393     {
394         g_warning ("Could not merge tbo-toolbar-ui.xml: %s", error->message);
395         g_error_free (error);
396     }
397
398     ACTION_GROUP = gtk_action_group_new ("ToolsActions");
399     gtk_action_group_set_translation_domain (ACTION_GROUP, NULL);
400     gtk_action_group_add_actions (ACTION_GROUP, tbo_tools_entries,
401                         G_N_ELEMENTS (tbo_tools_entries), window);
402     gtk_action_group_add_toggle_actions (ACTION_GROUP, tbo_tools_toogle_entries,
403                         G_N_ELEMENTS (tbo_tools_toogle_entries), window);
404
405     gtk_ui_manager_insert_action_group (manager, ACTION_GROUP, 0);
406
407     toolbar = gtk_ui_manager_get_widget (manager, "/toolbar");
408
409     update_toolbar (window);
410
411     return toolbar;
412 }
413
414 void
415 tool_signal (enum Tool tool, enum ToolSignal signal, gpointer data)
416 {
417     int i;
418     ToolStruct *toolstruct = NULL;
419     void **pdata;
420
421     for (i=0; i<G_N_ELEMENTS (TOOLS); i++)
422     {
423         if (tool == TOOLS[i].tool)
424         {
425             toolstruct = &TOOLS[i];
426             break;
427         }
428     }
429
430     if (toolstruct)
431     {
432         switch (signal)
433         {
434             case TOOL_SELECT:
435                 toolstruct->tool_on_select(data);
436                 break;
437             case TOOL_UNSELECT:
438                 toolstruct->tool_on_unselect(data);
439                 break;
440             case TOOL_MOVE:
441                 pdata = data;
442                 toolstruct->tool_on_move (pdata[0], pdata[1], pdata[2]);
443                 break;
444             case TOOL_CLICK:
445                 pdata = data;
446                 toolstruct->tool_on_click (pdata[0], pdata[1], pdata[2]);
447                 break;
448             case TOOL_RELEASE:
449                 pdata = data;
450                 toolstruct->tool_on_release (pdata[0], pdata[1], pdata[2]);
451                 break;
452             case TOOL_KEY:
453                 pdata = data;
454                 toolstruct->tool_on_key (pdata[0], pdata[1], pdata[2]);
455                 break;
456             case TOOL_DRAWING:
457                 toolstruct->tool_drawing (data);
458                 break;
459             default:
460                 break;
461         }
462     }
463 }