2 * Navit, a modular navigation system.
3 * Copyright (C) 2005-2008 Navit Team
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * version 2 as published by the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
23 #include <gdk/gdkkeysyms.h>
24 #if !defined(GDK_Book) || !defined(GDK_Calendar)
25 #include <X11/XF86keysym.h>
38 #include "transform.h"
45 #include "navit_nls.h"
48 #include "hildon/hildon-defines.h
49 #define KEY_ZOOM_IN HILDON_HARDKEY_INCREASE
50 #define KEY_ZOOM_OUT HILDON_HARDKEY_DECREASE
51 #define KEY_UP HILDON_HARDKEY_UP
52 #define KEY_DOWN HILDON_HARDKEY_DOWN
53 #define KEY_LEFT HILDON_HARDKEY_LEFT
54 #define KEY_RIGHT HILDON_HARDKEY_RIGHT
57 #define GDK_Book XF86XK_Book
60 #define GDK_Calendar XF86XK_Calendar
62 #define KEY_ZOOM_IN GDK_Book
63 #define KEY_ZOOM_OUT GDK_Calendar
65 #define KEY_DOWN GDK_Down
66 #define KEY_LEFT GDK_Left
67 #define KEY_RIGHT GDK_Right
71 keypress(GtkWidget *widget, GdkEventKey *event, struct gui_priv *this)
75 GtkToggleAction *action;
79 if (event->type != GDK_KEY_PRESS)
81 dbg(1,"keypress 0x%x\n", event->keyval);
82 transform_get_size(navit_get_trans(this->nav), &w, &h);
83 switch (event->keyval) {
85 gtk_menu_shell_select_first(GTK_MENU_SHELL(this->menubar), TRUE);
90 navit_set_center_screen(this->nav, &p);
95 navit_set_center_screen(this->nav, &p);
100 navit_set_center_screen(this->nav, &p);
105 navit_set_center_screen(this->nav, &p);
108 navit_zoom_in(this->nav, 2, NULL);
111 navit_zoom_out(this->nav, 2, NULL);
114 case HILDON_HARDKEY_FULLSCREEN:
115 action = GTK_TOGGLE_ACTION (gtk_action_group_get_action (this->base_group, "FullscreenAction"));
117 if ( gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action)))
123 gtk_toggle_action_set_active (action, fullscreen);
133 gui_gtk_set_graphics(struct gui_priv *this, struct graphics *gra)
137 graphics=graphics_get_data(gra, "gtk_widget");
140 GTK_WIDGET_SET_FLAGS (graphics, GTK_CAN_FOCUS);
141 gtk_widget_set_sensitive(graphics, TRUE);
142 g_signal_connect(G_OBJECT(graphics), "key-press-event", G_CALLBACK(keypress), this);
143 gtk_box_pack_end(GTK_BOX(this->vbox), graphics, TRUE, TRUE, 0);
144 gtk_widget_show_all(graphics);
145 gtk_widget_grab_focus(graphics);
151 gui_gtk_add_bookmark_do(struct gui_priv *gui)
153 navit_add_bookmark(gui->nav, &gui->dialog_coord, gtk_entry_get_text(GTK_ENTRY(gui->dialog_entry)));
154 gtk_widget_destroy(gui->dialog_win);
158 gui_gtk_add_bookmark(struct gui_priv *gui, struct pcoord *c, char *description)
160 GtkWidget *button_ok,*button_cancel,*label,*vbox,*hbox;
162 gui->dialog_coord=*c;
163 gui->dialog_win=gtk_window_new(GTK_WINDOW_TOPLEVEL);
164 vbox=gtk_vbox_new(FALSE, 0);
165 gtk_container_add (GTK_CONTAINER (gui->dialog_win), vbox);
166 gtk_window_set_title(GTK_WINDOW(gui->dialog_win),_("Add Bookmark"));
167 gtk_window_set_wmclass (GTK_WINDOW (gui->dialog_win), "navit", "Navit");
168 gtk_window_set_transient_for(GTK_WINDOW(gui->dialog_win), GTK_WINDOW(gui->win));
169 gtk_window_set_modal(GTK_WINDOW(gui->dialog_win), TRUE);
170 label=gtk_label_new(_("Name"));
171 gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
172 gui->dialog_entry=gtk_entry_new();
173 gtk_entry_set_text(GTK_ENTRY(gui->dialog_entry), description);
174 gtk_box_pack_start(GTK_BOX(vbox), gui->dialog_entry, TRUE, TRUE, 0);
175 hbox=gtk_hbox_new(FALSE, 0);
176 button_ok = gtk_button_new_from_stock (GTK_STOCK_OK);
177 gtk_box_pack_start(GTK_BOX(hbox), button_ok, TRUE, TRUE, 10);
178 button_cancel = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
179 gtk_box_pack_start(GTK_BOX(hbox), button_cancel, TRUE, TRUE, 10);
180 gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 10);
181 gtk_widget_show_all(gui->dialog_win);
182 GTK_WIDGET_SET_FLAGS (button_ok, GTK_CAN_DEFAULT);
183 gtk_widget_grab_default(button_ok);
184 g_signal_connect_swapped (G_OBJECT (button_cancel), "clicked", G_CALLBACK (gtk_widget_destroy), G_OBJECT (gui->dialog_win));
185 g_signal_connect_swapped (G_OBJECT (gui->dialog_entry), "activate", G_CALLBACK (gui_gtk_add_bookmark_do), gui);
187 g_signal_connect_swapped(G_OBJECT (button_ok), "clicked", G_CALLBACK (gui_gtk_add_bookmark_do), gui);
192 struct gui_methods gui_gtk_methods = {
195 gui_gtk_set_graphics,
197 gui_gtk_datawindow_new,
198 gui_gtk_add_bookmark,
202 gui_gtk_delete(GtkWidget *widget, GdkEvent *event, struct navit *nav)
204 /* FIXME remove attr_navit callback */
211 gui_gtk_toggle_init(struct gui_priv *this)
214 GtkToggleAction *toggle_action;
216 if (navit_get_attr(this->nav, attr_cursor, &attr, NULL)) {
217 toggle_action = GTK_TOGGLE_ACTION(gtk_action_group_get_action(this->base_group, "CursorAction"));
218 gtk_toggle_action_set_active(toggle_action, attr.u.num);
220 dbg(0, "Unable to locate CursorAction\n");
222 if (navit_get_attr(this->nav, attr_orientation, &attr, NULL)) {
223 toggle_action = GTK_TOGGLE_ACTION(gtk_action_group_get_action(this->base_group, "OrientationAction"));
224 gtk_toggle_action_set_active(toggle_action, attr.u.num != -1);
226 dbg(0, "Unable to locate OrientationAction\n");
228 if (navit_get_attr(this->nav, attr_tracking, &attr, NULL)) {
229 toggle_action = GTK_TOGGLE_ACTION(gtk_action_group_get_action(this->base_group, "TrackingAction"));
230 gtk_toggle_action_set_active(toggle_action, attr.u.num);
232 dbg(0, "Unable to locate TrackingAction\n");
236 struct action_cb_data {
237 struct gui_priv *gui;
242 gui_gtk_action_activate(GtkAction *action, struct action_cb_data *data)
244 if(data->attr.type == attr_destination) {
246 g_object_get(G_OBJECT(action), "label", &label,NULL);
247 navit_set_destination(data->gui->nav, data->attr.u.pcoord, label);
252 struct gui_menu_info {
258 gui_gtk_del_menu(struct gui_priv *this, struct gui_menu_info *meninfo)
260 gtk_action_group_remove_action(this->dyn_group, meninfo->action);
261 gtk_ui_manager_remove_ui(this->ui_manager, meninfo->merge_id);
264 static struct gui_menu_info
265 gui_gtk_add_menu(struct gui_priv *this, char *name, char *label, char *path, int submenu, struct action_cb_data *data)
267 struct gui_menu_info meninfo;
271 action=gtk_action_new(name, label, NULL, NULL);
272 meninfo.action = action;
274 g_signal_connect(action, "activate", G_CALLBACK(gui_gtk_action_activate), data);
275 gtk_action_group_add_action(this->dyn_group, action);
276 merge_id =gtk_ui_manager_new_merge_id(this->ui_manager);
277 meninfo.merge_id = merge_id;
278 gtk_ui_manager_add_ui(this->ui_manager, merge_id, path, name, name, submenu ? GTK_UI_MANAGER_MENU : GTK_UI_MANAGER_MENUITEM, FALSE);
284 gui_gtk_action_toggled(GtkToggleAction *action, struct action_cb_data *data)
287 active.type=attr_active;
288 active.u.num=gtk_toggle_action_get_active(action);
289 map_set_attr(data->attr.u.map, &active);
290 navit_draw(data->gui->nav);
294 gui_gtk_add_toggle_menu(struct gui_priv *this, char *name, char *label, char *path, struct action_cb_data *data, gboolean active)
296 GtkToggleAction *toggle_action;
299 toggle_action=gtk_toggle_action_new(name, label, NULL, NULL);
300 gtk_toggle_action_set_active(toggle_action, active);
301 g_signal_connect(GTK_ACTION(toggle_action), "toggled", G_CALLBACK(gui_gtk_action_toggled), data);
302 gtk_action_group_add_action(this->dyn_group, GTK_ACTION(toggle_action));
303 merge_id=gtk_ui_manager_new_merge_id(this->ui_manager);
304 gtk_ui_manager_add_ui(this->ui_manager, merge_id, path, name, name, GTK_UI_MANAGER_MENUITEM, FALSE);
308 gui_gtk_action_changed(GtkRadioAction *action, GtkRadioAction *current, struct action_cb_data *data)
310 if (action == current) {
311 navit_set_attr(data->gui->nav, &data->attr);
316 gui_gtk_add_radio_menu(struct gui_priv *this, char *name, char *label, char *path, struct action_cb_data *data, GSList **g)
318 GtkRadioAction *radio_action;
321 radio_action=gtk_radio_action_new(name, label, NULL, NULL, 0);
322 gtk_radio_action_set_group(radio_action, *g);
323 *g=gtk_radio_action_get_group(radio_action);
324 g_signal_connect(GTK_ACTION(radio_action), "changed", G_CALLBACK(gui_gtk_action_changed), data);
325 gtk_action_group_add_action(this->dyn_group, GTK_ACTION(radio_action));
326 merge_id=gtk_ui_manager_new_merge_id(this->ui_manager);
327 gtk_ui_manager_add_ui(this->ui_manager, merge_id, path, name, name, GTK_UI_MANAGER_MENUITEM, FALSE);
331 gui_gtk_layouts_init(struct gui_priv *this)
333 struct attr_iter *iter;
335 struct action_cb_data *data;
339 iter=navit_attr_iter_new();
340 while(navit_get_attr(this->nav, attr_layout, &attr, iter)) {
341 name=g_strdup_printf("Layout %d", count++);
342 data=g_new(struct action_cb_data, 1);
344 data->attr.type=attr_layout;
345 data->attr.u.layout=attr.u.layout;
346 gui_gtk_add_radio_menu(this, name, attr.u.layout->name, "/ui/MenuBar/Map/Layout/LayoutMenuAdditions", data, &this->layout_group);
349 navit_attr_iter_destroy(iter);
353 gui_gtk_projections_init(struct gui_priv *this)
355 struct action_cb_data *data;
357 data=g_new(struct action_cb_data, 1);
359 data->attr.type=attr_projection;
360 data->attr.u.projection=projection_mg;
361 gui_gtk_add_radio_menu(this, "Projection mg", "Map & Guide", "/ui/MenuBar/Map/Projection/ProjectionMenuAdditions", data, &this->projection_group);
363 data=g_new(struct action_cb_data, 1);
365 data->attr.type=attr_projection;
366 data->attr.u.projection=projection_garmin;
367 gui_gtk_add_radio_menu(this, "Projection garmin", "Garmin", "/ui/MenuBar/Map/Projection/ProjectionMenuAdditions", data, &this->projection_group);
371 gui_gtk_vehicles_init(struct gui_priv *this)
373 struct attr_iter *iter;
374 struct attr attr,vattr;
375 struct action_cb_data *data;
379 iter=navit_attr_iter_new();
380 while(navit_get_attr(this->nav, attr_vehicle, &attr, iter)) {
381 vehicle_get_attr(attr.u.vehicle, attr_name, &vattr, NULL);
382 name=g_strdup_printf("Vehicle %d", count++);
383 data=g_new(struct action_cb_data, 1);
385 data->attr.type=attr_vehicle;
386 data->attr.u.vehicle=attr.u.vehicle;
387 gui_gtk_add_radio_menu(this, name, vattr.u.str, "/ui/MenuBar/Map/Vehicle/VehicleMenuAdditions", data, &this->vehicle_group);
390 navit_attr_iter_destroy(iter);
394 gui_gtk_maps_init(struct gui_priv *this)
396 struct attr_iter *iter;
397 struct attr attr,active,type,data;
398 struct action_cb_data *cb_data;
402 iter=navit_attr_iter_new();
403 while(navit_get_attr(this->nav, attr_map, &attr, iter)) {
404 name=g_strdup_printf("Map %d", count++);
405 if (! map_get_attr(attr.u.map, attr_type, &type, NULL))
407 if (! map_get_attr(attr.u.map, attr_data, &data, NULL))
409 label=g_strdup_printf("%s:%s", type.u.str, data.u.str);
410 cb_data=g_new(struct action_cb_data, 1);
412 cb_data->attr.type=attr_map;
413 cb_data->attr.u.map=attr.u.map;
414 if (! map_get_attr(attr.u.map, attr_active, &active, NULL))
416 gui_gtk_add_toggle_menu(this, name, label, "/ui/MenuBar/Map/MapMenuAdditions", cb_data, active.u.num);
420 navit_attr_iter_destroy(iter);
425 gui_gtk_destinations_update(struct gui_priv *this)
429 struct action_cb_data *data;
430 struct map_rect *mr=NULL;
432 struct gui_menu_info *meninfo;
437 curr = g_list_first(this->dest_menuitems);
440 gui_gtk_del_menu(this, (struct gui_menu_info *)curr->data);
441 g_free((struct gui_menu_info *)curr->data);
442 curr = g_list_next(curr);
445 g_list_free(this->dest_menuitems);
446 this->dest_menuitems = NULL;
448 if(navit_get_attr(this->nav, attr_former_destination_map, &attr, NULL) && attr.u.map && (mr=map_rect_new(attr.u.map, NULL))) {
449 while ((item=map_rect_get_item(mr))) {
450 if (item->type != type_former_destination) continue;
451 name=g_strdup_printf("Destination %d", count++);
452 item_attr_get(item, attr_label, &attr);
454 item_coord_get(item, &c, 1);
455 data=g_new(struct action_cb_data, 1);
457 data->attr.type=attr_destination;
458 data->attr.u.pcoord=g_new(struct pcoord, 1);
459 data->attr.u.pcoord->pro=projection_mg;
460 data->attr.u.pcoord->x=c.x;
461 data->attr.u.pcoord->y=c.y;
463 meninfo = g_new(struct gui_menu_info, 1);
464 *meninfo = gui_gtk_add_menu(this, name, label, "/ui/MenuBar/Route/FormerDestinations/FormerDestinationMenuAdditions",0,data);
465 this->dest_menuitems = g_list_prepend(this->dest_menuitems, meninfo);
468 map_rect_destroy(mr);
473 gui_gtk_destinations_init(struct gui_priv *this)
475 navit_add_callback(this->nav, callback_new_attr_1(callback_cast(gui_gtk_destinations_update), attr_destination, this));
476 gui_gtk_destinations_update(this);
480 gui_gtk_bookmarks_update(struct gui_priv *this)
484 struct action_cb_data *data;
485 struct map_rect *mr=NULL;
486 struct gui_menu_info *meninfo;
490 char *parent, *name, *label, *label_full, *menu_label, *tmp_parent, *s;
493 curr = g_list_first(this->bookmarks_menuitems);
496 gui_gtk_del_menu(this, (struct gui_menu_info *)curr->data);
497 g_free((struct gui_menu_info *)curr->data);
498 curr = g_list_next(curr);
501 g_list_free(this->bookmarks_menuitems);
502 this->bookmarks_menuitems = NULL;
504 if(navit_get_attr(this->nav, attr_bookmark_map, &attr, NULL) && attr.u.map && (mr=map_rect_new(attr.u.map, NULL))) {
505 hash=g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
506 while ((item=map_rect_get_item(mr))) {
507 if (item->type != type_bookmark) continue;
508 item_attr_get(item, attr_label, &attr);
509 label_full=attr.u.str;
510 item_coord_get(item, &c, 1);
511 menu_label=g_malloc(strlen(label_full)+1);
513 parent=g_strdup("/ui/MenuBar/Route/Bookmarks/BookmarkMenuAdditions");
514 while ((s=strchr(label, '/'))) {
515 strcpy(menu_label, label_full);
516 menu_label[s-label_full]='\0';
517 if ((tmp_parent=g_hash_table_lookup(hash, menu_label))) {
518 tmp_parent=g_strdup(tmp_parent);
520 name=g_strdup_printf("Bookmark %d", count++);
521 meninfo = g_new(struct gui_menu_info, 1);
522 *meninfo = gui_gtk_add_menu(this, name, menu_label+(label-label_full),parent,1,NULL);
523 this->bookmarks_menuitems = g_list_prepend(this->bookmarks_menuitems, meninfo);
524 tmp_parent=g_strdup_printf("%s/%s", parent, name);
525 g_hash_table_insert(hash, g_strdup(menu_label), g_strdup(tmp_parent));
533 data=g_new(struct action_cb_data, 1);
535 data->attr.type=attr_destination;
536 data->attr.u.pcoord=g_new(struct pcoord, 1);
537 data->attr.u.pcoord->pro=projection_mg;
538 data->attr.u.pcoord->x=c.x;
539 data->attr.u.pcoord->y=c.y;
540 name=g_strdup_printf("Bookmark %d", count++);
541 meninfo = g_new(struct gui_menu_info, 1);
542 *meninfo = gui_gtk_add_menu(this, name, label, parent,0,data);
543 this->bookmarks_menuitems = g_list_prepend(this->bookmarks_menuitems, meninfo);
547 g_hash_table_destroy(hash);
552 gui_gtk_bookmarks_init(struct gui_priv *this)
554 navit_add_callback(this->nav, callback_new_attr_1(callback_cast(gui_gtk_bookmarks_update), attr_bookmark_map, this));
555 gui_gtk_bookmarks_update(this);
559 gui_gtk_init(struct gui_priv *this, struct navit *nav)
563 gui_gtk_toggle_init(this);
564 gui_gtk_layouts_init(this);
565 gui_gtk_projections_init(this);
566 gui_gtk_vehicles_init(this);
567 gui_gtk_maps_init(this);
568 gui_gtk_destinations_init(this);
569 gui_gtk_bookmarks_init(this);
572 static struct gui_priv *
573 gui_gtk_new(struct navit *nav, struct gui_methods *meth, struct attr **attrs)
575 struct gui_priv *this;
577 char *cp = getenv("NAVIT_XID");
583 xid = strtol(cp, NULL, 0);
586 this=g_new0(struct gui_priv, 1);
589 attr = attr_search(attrs, NULL, attr_menubar);
591 this->menubar_enable=attr->u.num;
593 this->menubar_enable=1;
595 attr=attr_search(attrs, NULL, attr_toolbar);
597 this->toolbar_enable=attr->u.num;
599 this->toolbar_enable=1;
601 attr=attr_search(attrs, NULL, attr_statusbar);
603 this->statusbar_enable=attr->u.num;
605 this->statusbar_enable=1;
608 *meth=gui_gtk_methods;
611 this->win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
613 this->win = gtk_plug_new(xid);
615 g_signal_connect(G_OBJECT(this->win), "delete-event", G_CALLBACK(gui_gtk_delete), nav);
616 this->vbox = gtk_vbox_new(FALSE, 0);
617 gtk_window_set_default_size(GTK_WINDOW(this->win), w, h);
618 gtk_window_set_title(GTK_WINDOW(this->win), "Navit");
619 gtk_window_set_wmclass (GTK_WINDOW (this->win), "navit", "Navit");
620 gtk_widget_realize(this->win);
621 gui_gtk_ui_init(this);
622 if (this->menubar_enable) {
623 widget=gtk_ui_manager_get_widget(this->ui_manager, "/ui/MenuBar");
624 GTK_WIDGET_UNSET_FLAGS (widget, GTK_CAN_FOCUS);
625 gtk_box_pack_start (GTK_BOX(this->vbox), widget, FALSE, FALSE, 0);
626 gtk_widget_show (widget);
627 this->menubar=widget;
629 if (this->toolbar_enable) {
630 widget=gtk_ui_manager_get_widget(this->ui_manager, "/ui/ToolBar");
631 GTK_WIDGET_UNSET_FLAGS (widget, GTK_CAN_FOCUS);
632 gtk_box_pack_start (GTK_BOX(this->vbox), widget, FALSE, FALSE, 0);
633 gtk_widget_show (widget);
635 if (this->statusbar_enable) {
636 this->statusbar=gui_gtk_statusbar_new(this);
638 gtk_container_add(GTK_CONTAINER(this->win), this->vbox);
639 gtk_widget_show_all(this->win);
642 navit_add_callback(nav, callback_new_attr_1(callback_cast(gui_gtk_init), attr_navit, this));
647 static char **gtk_argv={NULL};
652 gtk_init(>k_argc, >k_argv);
656 plugin_register_gui_type("gtk", gui_gtk_new);