647e9b98ae6d1494b99a52feb90b434f9e5558fa
[navit-package] / src / gui / gtk / gui_gtk_action.c
1 #include <string.h>
2 #include <gtk/gtk.h>
3 #include "navit.h"
4 #include "gui_gtk.h"
5 #include "menu.h"
6 #include "coord.h"
7 #include "callback.h"
8 #include "debug.h"
9 #include "destination.h"
10
11 #define gettext_noop(String) String
12 #define _(STRING)    gettext(STRING)
13 #define _n(STRING)    gettext_noop(STRING)
14
15 struct menu_priv {
16         char *path;     
17         GtkAction *action;
18         struct gui_priv *gui;
19         enum menu_type type;
20         struct callback *cb;
21         struct menu_priv *child;
22         struct menu_priv *sibling;
23         gulong handler_id;
24         guint merge_id;
25 };
26
27 /* Create callbacks that implement our Actions */
28
29 static void
30 zoom_in_action(GtkWidget *w, struct gui_priv *gui, void *dummy)
31 {
32         navit_zoom_in(gui->nav, 2, NULL);
33 }
34
35 static void
36 zoom_out_action(GtkWidget *w, struct gui_priv *gui, void *dummy)
37 {
38         navit_zoom_out(gui->nav, 2, NULL);
39 }
40
41 static void
42 refresh_action(GtkWidget *w, struct gui_priv *gui, void *dummy)
43 {
44         navit_draw(gui->nav);
45 }
46
47 static void
48 roadbook_action(GtkWidget *w, struct gui_priv *gui, void *dummy)
49 {
50         navit_window_roadbook_new(gui->nav);
51 }
52
53 static void
54 cursor_action(GtkWidget *w, struct gui_priv *gui, void *dummy)
55 {
56         navit_toggle_cursor(gui->nav);
57 }
58
59 static void
60 tracking_action(GtkWidget *w, struct gui_priv *gui, void *dummy)
61 {
62         navit_toggle_tracking(gui->nav);
63 }
64
65 static void
66 orient_north_action(GtkWidget *w, struct gui_priv *gui, void *dummy)
67 {
68         navit_toggle_orient_north(gui->nav);
69 }
70
71 static void
72 window_fullscreen_action(GtkWidget *w, struct gui_priv *gui, void *dummy)
73 {
74         if(gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(w)))
75                 gtk_window_fullscreen(GTK_WINDOW(gui->win));
76         else
77                 gtk_window_unfullscreen(GTK_WINDOW(gui->win));
78 }
79
80 #include <stdlib.h>
81 #include "point.h"
82 #include "transform.h"
83
84 static void
85 info_action(GtkWidget *w, struct gui_priv *gui, void *dummy)
86 {
87         char buffer[512];
88         int mw,mh;
89         struct coord lt, rb;
90         struct point p;
91         struct transformation *t;
92
93         t=navit_get_trans(gui->nav);
94         transform_get_size(t, &mw, &mh);
95         p.x=0;
96         p.y=0;
97         transform_reverse(t, &p, &lt);
98         p.x=mw;
99         p.y=mh;
100         transform_reverse(t, &p, &rb);
101
102         sprintf(buffer,"./info.sh %d,%d 0x%x,0x%x 0x%x,0x%x", mw, mh, lt.x, lt.y, rb.x, rb.y);
103         system(buffer);
104
105 }
106
107
108 static void
109 route_clear_action(GtkWidget *w, struct gui_priv *gui, void *dummy)
110 {
111         navit_set_destination(gui->nav, NULL, NULL);
112 }
113
114 static void
115 destination_action(GtkWidget *w, struct gui_priv *gui, void *dummy)
116 {
117         destination_address(gui->nav);
118 }
119
120
121 static void     
122 quit_action (GtkWidget *w, struct gui_priv *gui, void *dummy)
123 {
124         navit_destroy(gui->nav);
125 }
126
127 static void
128 visible_blocks_action(GtkWidget *w, struct container *co)
129 {
130 #if 0
131         co->data_window[data_window_type_block]=data_window("Visible Blocks",co->win,NULL);
132         graphics_redraw(co);
133 #endif
134 }
135
136 static void
137 visible_towns_action(GtkWidget *w, struct container *co)
138 {
139 #if 0
140         co->data_window[data_window_type_town]=data_window("Visible Towns",co->win,NULL);
141         graphics_redraw(co);
142 #endif
143 }
144
145 static void
146 visible_polys_action(GtkWidget *w, struct container *co)
147 {
148 #if 0
149         co->data_window[data_window_type_street]=data_window("Visible Polys",co->win,NULL);
150         graphics_redraw(co);
151 #endif
152 }
153
154 static void
155 visible_streets_action(GtkWidget *w, struct container *co)
156 {
157 #if 0
158         co->data_window[data_window_type_street]=data_window("Visible Streets",co->win,NULL);
159         graphics_redraw(co);
160 #endif
161 }
162
163 static void
164 visible_points_action(GtkWidget *w, struct container *co)
165 {
166 #if 0
167         co->data_window[data_window_type_point]=data_window("Visible Points",co->win,NULL);
168         graphics_redraw(co);
169 #endif
170 }
171
172 static void
173 visible_routegraph_action(GtkWidget *w, struct gui_priv *gui, void *dummy)
174 {
175         navit_toggle_routegraph_display(gui->nav);
176 }
177
178
179
180 static GtkActionEntry entries[] = 
181 {
182         { "DisplayMenuAction", NULL, gettext_noop("Display") },
183         { "RouteMenuAction", NULL, _n("Route") },
184         { "Map", NULL, _n("Map") },
185         { "LayoutMenuAction", NULL, _n("Layout") },
186         { "ZoomOutAction", GTK_STOCK_ZOOM_OUT, _n("ZoomOut"), NULL, NULL, G_CALLBACK(zoom_out_action) },
187         { "ZoomInAction", GTK_STOCK_ZOOM_IN, _n("ZoomIn"), NULL, NULL, G_CALLBACK(zoom_in_action) },
188         { "RefreshAction", GTK_STOCK_REFRESH, _n("Refresh"), NULL, NULL, G_CALLBACK(refresh_action) },
189         { "RoadbookAction", GTK_STOCK_JUSTIFY_FILL, _n("Roadbook"), NULL, NULL, G_CALLBACK(roadbook_action) },
190 #ifdef GTK_STOCK_INFO
191         { "InfoAction", GTK_STOCK_INFO, _n("Info"), NULL, NULL, G_CALLBACK(info_action) },
192 #else
193         { "InfoAction", NULL, _n("Info"), NULL, NULL, G_CALLBACK(info_action) },
194 #endif /*GTK_STOCK_INFO*/
195         { "DestinationAction", "flag_icon", _n("Destination"), NULL, NULL, G_CALLBACK(destination_action) },
196         { "RouteClearAction", NULL, _n("Clear"), NULL, NULL, G_CALLBACK(route_clear_action) },
197         { "Test", NULL, _n("Test"), NULL, NULL, G_CALLBACK(destination_action) },
198         { "QuitAction", GTK_STOCK_QUIT, _n("_Quit"), "<control>Q",NULL, G_CALLBACK (quit_action) }
199 };
200
201 static guint n_entries = G_N_ELEMENTS (entries);
202
203 static GtkToggleActionEntry toggleentries[] = 
204 {
205         { "CursorAction", "cursor_icon",_n("Cursor"), NULL, NULL, G_CALLBACK(cursor_action),TRUE },
206         { "TrackingAction", NULL ,_n("Tracking"), NULL, NULL, G_CALLBACK(tracking_action),TRUE },
207         { "OrientationAction", "orientation_icon", _n("Orientation"), NULL, NULL, G_CALLBACK(orient_north_action),FALSE },
208 #ifdef GTK_STOCK_FULLSCREEN
209         { "FullscreenAction",GTK_STOCK_FULLSCREEN, _n("Fullscreen"), NULL, NULL, G_CALLBACK(window_fullscreen_action), FALSE }
210 #else
211         { "FullscreenAction", NULL, _n("Fullscreen"), NULL, NULL, G_CALLBACK(window_fullscreen_action), FALSE }
212 #endif /*GTK_STOCK_FULLSCREEN*/
213 };
214
215 static guint n_toggleentries = G_N_ELEMENTS (toggleentries);
216
217 static GtkActionEntry debug_entries[] = 
218 {
219         { "DataMenuAction", NULL, _n("Data") },
220         { "VisibleBlocksAction", NULL, _n("VisibleBlocks"), NULL, NULL, G_CALLBACK(visible_blocks_action) },
221         { "VisibleTownsAction", NULL, _n("VisibleTowns"), NULL, NULL, G_CALLBACK(visible_towns_action) },
222         { "VisiblePolysAction", NULL, _n("VisiblePolys"), NULL, NULL, G_CALLBACK(visible_polys_action) },
223         { "VisibleStreetsAction", NULL, _n("VisibleStreets"), NULL, NULL, G_CALLBACK(visible_streets_action) },
224         { "VisiblePointsAction", NULL, _n("VisiblePoints"), NULL, NULL, G_CALLBACK(visible_points_action) },
225         { "VisiblePointsAction", NULL, _n("RouteGraph"), NULL, NULL, G_CALLBACK(visible_routegraph_action) }
226 };
227
228 static guint n_debug_entries = G_N_ELEMENTS (debug_entries);
229
230
231 static const char * cursor_xpm[] = {
232 "22 22 2 1",
233 "       c None",
234 ".      c #0000FF",
235 "                      ",
236 "                      ",
237 "                      ",
238 "          ..          ",
239 "        ..  ..        ",
240 "      ..      ..      ",
241 "     .          .     ",
242 "     .          .     ",
243 "    .        ... .    ",
244 "    .     ... .  .    ",
245 "   .   ...   .    .   ",
246 "   . ..     .     .   ",
247 "    .      .     .    ",
248 "    .     .      .    ",
249 "     .   .      .     ",
250 "     .  .       .     ",
251 "      ..      ..      ",
252 "        ..  ..        ",
253 "          ..          ",
254 "                      ",
255 "                      ",
256 "                      "};
257
258
259 static const char * north_xpm[] = {
260 "22 22 2 1",
261 "       c None",
262 ".      c #000000",
263 "                      ",
264 "                      ",
265 "           .          ",
266 "          ...         ",
267 "         . . .        ",
268 "        .  .  .       ",
269 "           .          ",
270 "     ....  .  ....    ",
271 "     ....  .  ....    ",
272 "      .... .   ..     ",
273 "      .. ..    ..     ",
274 "      ..  ..   ..     ",
275 "      ..   ..  ..     ",
276 "      ..    .. ..     ",
277 "      ..   . ....     ",
278 "     ....  .  ....    ",
279 "     ....  .  ....    ",
280 "           .          ",
281 "           .          ",
282 "           .          ",
283 "                      ",
284 "                      "};
285
286
287 static const char * flag_xpm[] = {
288 "22 22 2 1",
289 "       c None",
290 "+      c #000000",
291 "+++++++               ",
292 "+   +++++++++         ",
293 "+   +++   +++++++++   ",
294 "+   +++   +++   +++   ",
295 "++++      +++   +++   ",
296 "++++   +++      +++   ",
297 "++++   +++   +++  +   ",
298 "+   ++++++   +++  +   ",
299 "+   +++   ++++++  +   ",
300 "+   +++   +++   +++   ",
301 "++++      +++   +++   ",
302 "++++   +++      +++   ",
303 "++++++++++   +++  +   ",
304 "+      +++++++++  +   ",
305 "+            ++++++   ",
306 "+                     ",
307 "+                     ",
308 "+                     ",
309 "+                     ",
310 "+                     ",
311 "+                     ",
312 "+                     "};
313
314
315
316 static struct {
317         gchar *stockid;
318         const char **icon_xpm;
319 } stock_icons[] = {
320         {"cursor_icon", cursor_xpm },
321         {"orientation_icon", north_xpm },
322         {"flag_icon", flag_xpm }
323 };
324
325
326 static gint n_stock_icons = G_N_ELEMENTS (stock_icons);
327
328
329 static void
330 register_my_stock_icons (void)
331 {
332         GtkIconFactory *icon_factory;
333         GtkIconSet *icon_set; 
334         GdkPixbuf *pixbuf;
335         gint i;
336
337         icon_factory = gtk_icon_factory_new ();
338
339         for (i = 0; i < n_stock_icons; i++) 
340         {
341                 pixbuf = gdk_pixbuf_new_from_xpm_data(stock_icons[i].icon_xpm);
342                 icon_set = gtk_icon_set_new_from_pixbuf (pixbuf);
343                 g_object_unref(pixbuf);
344                 gtk_icon_factory_add (icon_factory, stock_icons[i].stockid, icon_set);
345                 gtk_icon_set_unref (icon_set);
346         }
347
348         gtk_icon_factory_add_default(icon_factory); 
349
350         g_object_unref(icon_factory);
351 }
352
353
354 static char layout[] =
355         "<ui>\
356                 <menubar name=\"MenuBar\">\
357                         <menu name=\"Display\" action=\"DisplayMenuAction\">\
358                                 <menuitem name=\"Zoom in\" action=\"ZoomInAction\" />\
359                                 <menuitem name=\"Zoom out\" action=\"ZoomOutAction\" />\
360                                 <menuitem name=\"Cursor\" action=\"CursorAction\"/>\
361                                 <menuitem name=\"Tracking\" action=\"TrackingAction\"/>\
362                                 <menuitem name=\"Orientation\" action=\"OrientationAction\"/>\
363                                 <menuitem name=\"Roadbook\" action=\"RoadbookAction\"/>\
364                                 <menuitem name=\"Fullscreen\" action=\"FullscreenAction\"/>\
365                                 <menuitem name=\"Quit\" action=\"QuitAction\" />\
366                                 <placeholder name=\"RouteMenuAdditions\" />\
367                         </menu>\
368                         <menu name=\"Data\" action=\"DataMenuAction\">\
369                                 <menuitem name=\"Visible Blocks\" action=\"VisibleBlocksAction\" />\
370                                 <menuitem name=\"Visible Towns\" action=\"VisibleTownsAction\" />\
371                                 <menuitem name=\"Visible Polys\" action=\"VisiblePolysAction\" />\
372                                 <menuitem name=\"Visible Streets\" action=\"VisibleStreetsAction\" />\
373                                 <menuitem name=\"Visible Points\" action=\"VisiblePointsAction\" />\
374                                 <placeholder name=\"DataMenuAdditions\" />\
375                         </menu>\
376                         <menu name=\"Route\" action=\"RouteMenuAction\">\
377                                 <menuitem name=\"Refresh\" action=\"RefreshAction\" />\
378                                 <menuitem name=\"Destination\" action=\"DestinationAction\" />\
379                                 <menuitem name=\"Clear\" action=\"RouteClearAction\" />\
380                                 <placeholder name=\"RouteMenuAdditions\" />\
381                         </menu>\
382                 </menubar>\
383                 <toolbar name=\"ToolBar\" action=\"BaseToolbar\" action=\"BaseToolbarAction\">\
384                         <placeholder name=\"ToolItems\">\
385                                 <separator/>\
386                                 <toolitem name=\"Zoom in\" action=\"ZoomInAction\"/>\
387                                 <toolitem name=\"Zoom out\" action=\"ZoomOutAction\"/>\
388                                 <toolitem name=\"Refresh\" action=\"RefreshAction\"/>\
389                                 <toolitem name=\"Cursor\" action=\"CursorAction\"/>\
390                                 <toolitem name=\"Orientation\" action=\"OrientationAction\"/>\
391                                 <toolitem name=\"Destination\" action=\"DestinationAction\"/>\
392                                 <!-- <toolitem name=\"Info\" action=\"InfoAction\"/> -->\
393                                 <toolitem name=\"Roadbook\" action=\"RoadbookAction\"/>\
394                                 <toolitem name=\"Quit\" action=\"QuitAction\"/>\
395                                 <separator/>\
396                         </placeholder>\
397                 </toolbar>\
398                 <popup name=\"PopUp\">\
399                 </popup>\
400         </ui>";
401         
402
403 static void
404 activate(void *dummy, struct menu_priv *menu)
405 {
406         if (menu->cb)
407                 callback_call_0(menu->cb);
408 }       
409
410 static struct menu_methods menu_methods;
411
412 static struct menu_priv *
413 add_menu(struct menu_priv *menu, struct menu_methods *meth, char *name, enum menu_type type, struct callback *cb)
414 {
415         struct menu_priv *ret;
416         char *dynname;
417
418         ret=g_new0(struct menu_priv, 1);
419         *meth=menu_methods;
420         if (! strcmp(menu->path, "/ui/MenuBar") && !strcmp(name,"Route")) {
421                 dynname=g_strdup("Route");
422         } else if (! strcmp(menu->path, "/ui/MenuBar") && !strcmp(name,"Data")) {
423                 dynname=g_strdup("Data");
424         } else {
425                 dynname=g_strdup_printf("%d", menu->gui->dyn_counter++);
426                 if (type == menu_type_toggle)
427                         ret->action=GTK_ACTION(gtk_toggle_action_new(dynname, name, NULL, NULL));
428                 else
429                         ret->action=gtk_action_new(dynname, name, NULL, NULL);
430                 if (cb) 
431                         ret->handler_id=g_signal_connect(ret->action, "activate", G_CALLBACK(activate), ret);
432                 gtk_action_group_add_action(menu->gui->dyn_group, ret->action);
433                 ret->merge_id=gtk_ui_manager_new_merge_id(menu->gui->menu_manager);
434                 gtk_ui_manager_add_ui( menu->gui->menu_manager, ret->merge_id, menu->path, dynname, dynname, type == menu_type_submenu ? GTK_UI_MANAGER_MENU : GTK_UI_MANAGER_MENUITEM, FALSE);
435         }
436         ret->gui=menu->gui;
437         ret->path=g_strdup_printf("%s/%s", menu->path, dynname);
438         ret->type=type;
439         ret->cb=cb;
440         ret->sibling=menu->child;
441         menu->child=ret;
442         g_free(dynname);
443         return ret;
444                 
445 }
446
447 static void
448 remove_menu(struct menu_priv *item, int recursive)
449 {
450
451         if (recursive) {
452                 struct menu_priv *next,*child=item->child;
453                 while (child) {
454                         next=child->sibling;
455                         remove_menu(child, recursive);
456                         child=next;
457                 }
458         }
459         if (item->action) {
460                 gtk_ui_manager_remove_ui(item->gui->menu_manager, item->merge_id);
461                 gtk_action_group_remove_action(item->gui->dyn_group, item->action);
462 #if 0
463                 if (item->callback)
464                         g_signal_handler_disconnect(item->action, item->handler_id);
465 #endif
466                 g_object_unref(item->action);
467         }
468         g_free(item->path);
469         g_free(item);
470 }
471
472 static void
473 set_toggle(struct menu_priv *menu, int active)
474 {
475         gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(menu->action), active);
476 }
477
478 static  int
479 get_toggle(struct menu_priv *menu)
480 {
481         return gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(menu->action));
482 }
483
484 static struct menu_methods menu_methods = {
485         add_menu,
486         set_toggle,
487         get_toggle,
488 };
489
490
491 static void
492 popup_deactivate(GtkWidget *widget, struct menu_priv *menu)
493 {
494         g_signal_handler_disconnect(widget, menu->handler_id);
495         remove_menu(menu, 1);
496 }       
497
498 static struct menu_priv *
499 gui_gtk_ui_new (struct gui_priv *this, struct menu_methods *meth, char *path, int popup, GtkWidget **widget_ret)
500 {
501         struct menu_priv *ret;
502         GError *error;
503         GtkWidget *widget;
504
505         *meth=menu_methods;
506         ret=g_new0(struct menu_priv, 1);
507         ret->path=g_strdup(path);
508         ret->gui=this;
509         if (! this->menu_manager) {
510                 this->base_group = gtk_action_group_new ("BaseActions");
511                 this->debug_group = gtk_action_group_new ("DebugActions");
512                 this->dyn_group = gtk_action_group_new ("DynamicActions");
513                 register_my_stock_icons();
514                 this->menu_manager = gtk_ui_manager_new ();
515                 gtk_action_group_set_translation_domain(this->base_group,"navit");
516                 gtk_action_group_set_translation_domain(this->debug_group,"navit");
517                 gtk_action_group_set_translation_domain(this->dyn_group,"navit");
518                 gtk_action_group_add_actions (this->base_group, entries, n_entries, this);
519                 gtk_action_group_add_toggle_actions (this->base_group, toggleentries, n_toggleentries, this);
520                 gtk_ui_manager_insert_action_group (this->menu_manager, this->base_group, 0);
521                 gtk_action_group_add_actions (this->debug_group, debug_entries, n_debug_entries, this);
522                 gtk_ui_manager_insert_action_group (this->menu_manager, this->debug_group, 0);
523                 gtk_ui_manager_add_ui_from_string (this->menu_manager, layout, strlen(layout), &error);
524                 gtk_ui_manager_insert_action_group (this->menu_manager, this->dyn_group, 0);
525                 error=NULL;
526                 if (error) {
527                         g_message ("building menus failed: %s", error->message);
528                         g_error_free (error);
529                 }
530         }
531         widget=gtk_ui_manager_get_widget(this->menu_manager, path);
532         GTK_WIDGET_UNSET_FLAGS (widget, GTK_CAN_FOCUS);
533         if (widget_ret)
534                 *widget_ret=widget;
535         if (! popup) {
536                 gtk_box_pack_start (GTK_BOX(this->vbox), widget, FALSE, FALSE, 0);
537                 gtk_widget_show (widget);
538         } else {
539                 gtk_menu_popup(GTK_MENU(widget), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time ());
540                 ret->handler_id=g_signal_connect(widget, "selection-done", G_CALLBACK(popup_deactivate), ret);
541         }
542         return ret;
543 }
544
545 struct menu_priv *
546 gui_gtk_toolbar_new(struct gui_priv *this, struct menu_methods *meth)
547 {
548         return gui_gtk_ui_new(this, meth, "/ui/ToolBar", 0, NULL);
549 }
550
551 struct menu_priv *
552 gui_gtk_menubar_new(struct gui_priv *this, struct menu_methods *meth)
553 {
554         return gui_gtk_ui_new(this, meth, "/ui/MenuBar", 0, &this->menubar);
555 }
556
557 struct menu_priv *
558 gui_gtk_popup_new(struct gui_priv *this, struct menu_methods *meth)
559 {
560         return gui_gtk_ui_new(this, meth, "/ui/PopUp", 1, NULL);
561 }