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