Modularized vehicle
[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         { "VisibleRouteGraphAction", 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                                 <menuitem name=\"Visible Routegraph\" action=\"VisibleRouteGraphAction\" />\
375                                 <placeholder name=\"DataMenuAdditions\" />\
376                         </menu>\
377                         <menu name=\"Route\" action=\"RouteMenuAction\">\
378                                 <menuitem name=\"Refresh\" action=\"RefreshAction\" />\
379                                 <menuitem name=\"Destination\" action=\"DestinationAction\" />\
380                                 <menuitem name=\"Clear\" action=\"RouteClearAction\" />\
381                                 <placeholder name=\"RouteMenuAdditions\" />\
382                         </menu>\
383                 </menubar>\
384                 <toolbar name=\"ToolBar\" action=\"BaseToolbar\" action=\"BaseToolbarAction\">\
385                         <placeholder name=\"ToolItems\">\
386                                 <separator/>\
387                                 <toolitem name=\"Zoom in\" action=\"ZoomInAction\"/>\
388                                 <toolitem name=\"Zoom out\" action=\"ZoomOutAction\"/>\
389                                 <toolitem name=\"Refresh\" action=\"RefreshAction\"/>\
390                                 <toolitem name=\"Cursor\" action=\"CursorAction\"/>\
391                                 <toolitem name=\"Orientation\" action=\"OrientationAction\"/>\
392                                 <toolitem name=\"Destination\" action=\"DestinationAction\"/>\
393                                 <!-- <toolitem name=\"Info\" action=\"InfoAction\"/> -->\
394                                 <toolitem name=\"Roadbook\" action=\"RoadbookAction\"/>\
395                                 <toolitem name=\"Quit\" action=\"QuitAction\"/>\
396                                 <separator/>\
397                         </placeholder>\
398                 </toolbar>\
399                 <popup name=\"PopUp\">\
400                 </popup>\
401         </ui>";
402         
403
404 static void
405 activate(void *dummy, struct menu_priv *menu)
406 {
407         if (menu->cb)
408                 callback_call_0(menu->cb);
409 }       
410
411 static struct menu_methods menu_methods;
412
413 static struct menu_priv *
414 add_menu(struct menu_priv *menu, struct menu_methods *meth, char *name, enum menu_type type, struct callback *cb)
415 {
416         struct menu_priv *ret;
417         char *dynname;
418
419         ret=g_new0(struct menu_priv, 1);
420         *meth=menu_methods;
421         if (! strcmp(menu->path, "/ui/MenuBar") && !strcmp(name,"Route")) {
422                 dynname=g_strdup("Route");
423         } else if (! strcmp(menu->path, "/ui/MenuBar") && !strcmp(name,"Data")) {
424                 dynname=g_strdup("Data");
425         } else {
426                 dynname=g_strdup_printf("%d", menu->gui->dyn_counter++);
427                 if (type == menu_type_toggle)
428                         ret->action=GTK_ACTION(gtk_toggle_action_new(dynname, name, NULL, NULL));
429                 else
430                         ret->action=gtk_action_new(dynname, name, NULL, NULL);
431                 if (cb) 
432                         ret->handler_id=g_signal_connect(ret->action, "activate", G_CALLBACK(activate), ret);
433                 gtk_action_group_add_action(menu->gui->dyn_group, ret->action);
434                 ret->merge_id=gtk_ui_manager_new_merge_id(menu->gui->menu_manager);
435                 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);
436         }
437         ret->gui=menu->gui;
438         ret->path=g_strdup_printf("%s/%s", menu->path, dynname);
439         ret->type=type;
440         ret->cb=cb;
441         ret->sibling=menu->child;
442         menu->child=ret;
443         g_free(dynname);
444         return ret;
445                 
446 }
447
448 static void
449 remove_menu(struct menu_priv *item, int recursive)
450 {
451
452         if (recursive) {
453                 struct menu_priv *next,*child=item->child;
454                 while (child) {
455                         next=child->sibling;
456                         remove_menu(child, recursive);
457                         child=next;
458                 }
459         }
460         if (item->action) {
461                 gtk_ui_manager_remove_ui(item->gui->menu_manager, item->merge_id);
462                 gtk_action_group_remove_action(item->gui->dyn_group, item->action);
463 #if 0
464                 if (item->callback)
465                         g_signal_handler_disconnect(item->action, item->handler_id);
466 #endif
467                 g_object_unref(item->action);
468         }
469         g_free(item->path);
470         g_free(item);
471 }
472
473 static void
474 set_toggle(struct menu_priv *menu, int active)
475 {
476         gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(menu->action), active);
477 }
478
479 static  int
480 get_toggle(struct menu_priv *menu)
481 {
482         return gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(menu->action));
483 }
484
485 static struct menu_methods menu_methods = {
486         add_menu,
487         set_toggle,
488         get_toggle,
489 };
490
491
492 static void
493 popup_deactivate(GtkWidget *widget, struct menu_priv *menu)
494 {
495         g_signal_handler_disconnect(widget, menu->handler_id);
496         remove_menu(menu, 1);
497 }       
498
499 static struct menu_priv *
500 gui_gtk_ui_new (struct gui_priv *this, struct menu_methods *meth, char *path, int popup, GtkWidget **widget_ret)
501 {
502         struct menu_priv *ret;
503         GError *error;
504         GtkWidget *widget;
505
506         *meth=menu_methods;
507         ret=g_new0(struct menu_priv, 1);
508         ret->path=g_strdup(path);
509         ret->gui=this;
510         if (! this->menu_manager) {
511                 this->base_group = gtk_action_group_new ("BaseActions");
512                 this->debug_group = gtk_action_group_new ("DebugActions");
513                 this->dyn_group = gtk_action_group_new ("DynamicActions");
514                 register_my_stock_icons();
515                 this->menu_manager = gtk_ui_manager_new ();
516                 gtk_action_group_set_translation_domain(this->base_group,"navit");
517                 gtk_action_group_set_translation_domain(this->debug_group,"navit");
518                 gtk_action_group_set_translation_domain(this->dyn_group,"navit");
519                 gtk_action_group_add_actions (this->base_group, entries, n_entries, this);
520                 gtk_action_group_add_toggle_actions (this->base_group, toggleentries, n_toggleentries, this);
521                 gtk_ui_manager_insert_action_group (this->menu_manager, this->base_group, 0);
522                 gtk_action_group_add_actions (this->debug_group, debug_entries, n_debug_entries, this);
523                 gtk_ui_manager_insert_action_group (this->menu_manager, this->debug_group, 0);
524                 gtk_ui_manager_add_ui_from_string (this->menu_manager, layout, strlen(layout), &error);
525                 gtk_ui_manager_insert_action_group (this->menu_manager, this->dyn_group, 0);
526                 error=NULL;
527                 if (error) {
528                         g_message ("building menus failed: %s", error->message);
529                         g_error_free (error);
530                 }
531         }
532         widget=gtk_ui_manager_get_widget(this->menu_manager, path);
533         GTK_WIDGET_UNSET_FLAGS (widget, GTK_CAN_FOCUS);
534         if (widget_ret)
535                 *widget_ret=widget;
536         if (! popup) {
537                 gtk_box_pack_start (GTK_BOX(this->vbox), widget, FALSE, FALSE, 0);
538                 gtk_widget_show (widget);
539         } else {
540                 gtk_menu_popup(GTK_MENU(widget), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time ());
541                 ret->handler_id=g_signal_connect(widget, "selection-done", G_CALLBACK(popup_deactivate), ret);
542         }
543         return ret;
544 }
545
546 struct menu_priv *
547 gui_gtk_toolbar_new(struct gui_priv *this, struct menu_methods *meth)
548 {
549         return gui_gtk_ui_new(this, meth, "/ui/ToolBar", 0, NULL);
550 }
551
552 struct menu_priv *
553 gui_gtk_menubar_new(struct gui_priv *this, struct menu_methods *meth)
554 {
555         return gui_gtk_ui_new(this, meth, "/ui/MenuBar", 0, &this->menubar);
556 }
557
558 struct menu_priv *
559 gui_gtk_popup_new(struct gui_priv *this, struct menu_methods *meth)
560 {
561         return gui_gtk_ui_new(this, meth, "/ui/PopUp", 1, NULL);
562 }