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