diff options
Diffstat (limited to 'gui/gtk')
-rw-r--r-- | gui/gtk/Makefile.am | 6 | ||||
-rw-r--r-- | gui/gtk/datawindow.c | 214 | ||||
-rw-r--r-- | gui/gtk/destination.c | 539 | ||||
-rw-r--r-- | gui/gtk/gui_gtk.h | 62 | ||||
-rw-r--r-- | gui/gtk/gui_gtk_action.c | 627 | ||||
-rw-r--r-- | gui/gtk/gui_gtk_statusbar.c | 178 | ||||
-rw-r--r-- | gui/gtk/gui_gtk_window.c | 771 |
7 files changed, 2397 insertions, 0 deletions
diff --git a/gui/gtk/Makefile.am b/gui/gtk/Makefile.am new file mode 100644 index 00000000..1588bfe8 --- /dev/null +++ b/gui/gtk/Makefile.am @@ -0,0 +1,6 @@ +include $(top_srcdir)/Makefile.inc +AM_CPPFLAGS = -I$(top_srcdir)/navit @NAVIT_CFLAGS@ @HILDON_CFLAGS@ @GTK2_CFLAGS@ -DMODULE=gui_gtk +modulegui_LTLIBRARIES = libgui_gtk.la +libgui_gtk_la_SOURCES = datawindow.c destination.c gui_gtk_statusbar.c gui_gtk_action.c gui_gtk_window.c gui_gtk.h +libgui_gtk_la_LIBADD = @GTK2_LIBS@ +libgui_gtk_la_LDFLAGS = -module -avoid-version diff --git a/gui/gtk/datawindow.c b/gui/gtk/datawindow.c new file mode 100644 index 00000000..75f43a80 --- /dev/null +++ b/gui/gtk/datawindow.c @@ -0,0 +1,214 @@ +/** + * Navit, a modular navigation system. + * Copyright (C) 2005-2008 Navit Team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <gdk/gdkkeysyms.h> +#include <gtk/gtk.h> +#include "debug.h" +#include "callback.h" +#include "param.h" +#include "data_window.h" +#include "gui_gtk.h" + +struct datawindow_priv { + GtkWidget *window; + GtkWidget *scrolled_window; + GtkWidget *treeview; + GtkWidget *button; + GtkListStore *liststore; + GtkTreeModel *sortmodel; + struct callback *click, *close; + struct gui_priv *gui; +}; + +static GValue value; +static void +select_row(GtkTreeView *tree, GtkTreePath *path, GtkTreeViewColumn *column, struct datawindow_priv *win) +{ + char *cols[20]; + GtkTreeIter iter; + GtkTreeModel *model; + int i; + + dbg(0,"win=%p\n", win); + + model=gtk_tree_view_get_model(tree); + gtk_tree_model_get_iter(model, &iter, path); + + for (i=0;i<gtk_tree_model_get_n_columns(model);i++) { + gtk_tree_model_get_value(model, &iter, i, &value); + cols[i]=g_strdup_value_contents(&value)+1; + cols[i][strlen(cols[i])-1]='\0'; + g_value_unset(&value); + } + callback_call_1(win->click, cols); +} + +static void +gui_gtk_datawindow_add(struct datawindow_priv *win, struct param_list *param, int count) +{ + int i; + GtkCellRenderer *cell; + GtkTreeIter iter; + GType types[count]; + + if (! win->treeview) { + win->treeview=gtk_tree_view_new(); + gtk_tree_view_set_model (GTK_TREE_VIEW (win->treeview), NULL); + gtk_container_add(GTK_CONTAINER(win->scrolled_window), win->treeview); + gtk_widget_show_all(GTK_WIDGET(win->window)); + gtk_widget_grab_focus(GTK_WIDGET(win->treeview)); + + /* add column names to treeview */ + for(i=0;i<count;i++) { + if (param[i].name) { + cell=gtk_cell_renderer_text_new(); + gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (win->treeview),-1,param[i].name, + cell,"text",i, NULL); + } + } +#if 0 + g_signal_connect(G_OBJECT(win->treeview), "click-column", G_CALLBACK(click_column), NULL); +#endif + g_signal_connect(G_OBJECT(win->treeview), "row-activated", G_CALLBACK(select_row), win); + } + + /* find data storage and create a new one if none is there */ + if (gtk_tree_view_get_model(GTK_TREE_VIEW (win->treeview)) == NULL) { + for(i=0;i<count;i++) { + if (param[i].name && !strcmp(param[i].name, "Distance")) + types[i]=G_TYPE_INT; + else + types[i]=G_TYPE_STRING; + } + win->liststore=gtk_list_store_newv(count,types); + if (! strcmp(param[0].name, "Distance")) { + win->sortmodel=gtk_tree_model_sort_new_with_model(GTK_TREE_MODEL(win->liststore)); + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (win->sortmodel), 0, GTK_SORT_ASCENDING); + gtk_tree_view_set_model (GTK_TREE_VIEW (win->treeview), GTK_TREE_MODEL(win->sortmodel)); + } else + gtk_tree_view_set_model (GTK_TREE_VIEW (win->treeview), GTK_TREE_MODEL(win->liststore)); + } + + gtk_list_store_append(win->liststore,&iter); + + /* add data to data storage */ + for(i=0;i<count;i++) { + if (param[i].name && !strcmp(param[i].name, "Distance")) { + gtk_list_store_set(win->liststore,&iter,i,atoi(param[i].value),-1); + } else { + gtk_list_store_set(win->liststore,&iter,i,param[i].value,-1); + } + } +} + +static void +gui_gtk_datawindow_mode(struct datawindow_priv *win, int start) +{ + if (start) { + if (win && win->treeview) { + gtk_tree_view_set_model (GTK_TREE_VIEW (win->treeview), NULL); + } + } +} + +static gboolean +gui_gtk_datawindow_delete(GtkWidget *widget, GdkEvent *event, struct datawindow_priv *win) +{ + callback_call_0(win->close); + + if (win->button) { + gtk_toggle_action_set_active (GTK_TOGGLE_ACTION(win->button), FALSE); + } + + return FALSE; +} + +void +gui_gtk_datawindow_destroy(struct datawindow_priv *win) +{ + if ((!win->gui) || (!win->gui->datawindow)) { + return; + } + + gui_gtk_datawindow_delete(NULL, NULL, win); + gtk_widget_destroy(win->window); + win->gui->datawindow = NULL; + + return; +} + +void +gui_gtk_datawindow_set_button(struct datawindow_priv *this_, GtkWidget *btn) +{ + this_->button = btn; +} + +static gboolean +keypress(GtkWidget *widget, GdkEventKey *event, struct datawindow_priv *win) +{ + if (event->type != GDK_KEY_PRESS) + return FALSE; + if (event->keyval == GDK_Cancel) { + gui_gtk_datawindow_delete(widget, (GdkEvent *)event, win); + gtk_widget_destroy(win->window); + } + return FALSE; +} + + +static struct datawindow_methods gui_gtk_datawindow_meth = { + gui_gtk_datawindow_destroy, + gui_gtk_datawindow_add, + gui_gtk_datawindow_mode, +}; + +struct datawindow_priv * +gui_gtk_datawindow_new(struct gui_priv *gui, char *name, struct callback *click, struct callback *close, struct datawindow_methods *meth) +{ + struct datawindow_priv *win; + + if (!gui) + return NULL; + *meth=gui_gtk_datawindow_meth; + win=g_new0(struct datawindow_priv, 1); + win->window=gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_default_size(GTK_WINDOW(win->window), 320, 200); + gtk_window_set_title(GTK_WINDOW(win->window), name); + gtk_window_set_wmclass (GTK_WINDOW (win->window), "navit", "Navit"); + + win->scrolled_window = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (win->scrolled_window), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_container_add(GTK_CONTAINER(win->window), win->scrolled_window); + g_signal_connect(G_OBJECT(win->window), "key-press-event", G_CALLBACK(keypress), win); + win->treeview=NULL; + win->click=click; + win->close=close; + gtk_window_set_transient_for(GTK_WINDOW((GtkWidget *)(win->window)), GTK_WINDOW(gui->win)); + g_signal_connect(G_OBJECT(win->window), "delete-event", G_CALLBACK(gui_gtk_datawindow_delete), win); + gtk_widget_show_all(win->window); + + win->gui = gui; + gui->datawindow = win; + return win; +} + diff --git a/gui/gtk/destination.c b/gui/gtk/destination.c new file mode 100644 index 00000000..a9c5b2cd --- /dev/null +++ b/gui/gtk/destination.c @@ -0,0 +1,539 @@ +/** + * Navit, a modular navigation system. + * Copyright (C) 2005-2008 Navit Team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <gtk/gtk.h> +#include "debug.h" +#include "destination.h" +#include "navit.h" +#include "item.h" +#include "coord.h" +#include "track.h" +#include "country.h" +#include "search.h" +#include "projection.h" +#include "navit_nls.h" + +#define COL_COUNT 8 + +static struct search_param { + struct navit *nav; + struct mapset *ms; + struct search_list *sl; + struct attr attr; + int partial; + GtkWidget *entry_country, *entry_postal, *entry_city, *entry_district; + GtkWidget *entry_street, *entry_number; + GtkWidget *listbox; + GtkWidget *treeview; + GtkListStore *liststore; + GtkTreeModel *liststore2; +} search_param; + +static void button_map(GtkWidget *widget, struct search_param *search) +{ + GtkTreePath *path; + GtkTreeViewColumn *focus_column; + struct pcoord *c=NULL; + GtkTreeIter iter; + + gtk_tree_view_get_cursor(GTK_TREE_VIEW(search->treeview), &path, &focus_column); + if(!path) + return; + if(!gtk_tree_model_get_iter(search->liststore2, &iter, path)) + return; + gtk_tree_model_get (GTK_TREE_MODEL (search->liststore2), &iter, COL_COUNT, &c, -1); + if (c) { + navit_set_center(search->nav, c, 1); + } +} + +static char *description(struct search_param *search, GtkTreeIter *iter) +{ + char *desc,*car,*postal,*town,*street; + char empty='\0'; + + gtk_tree_model_get (GTK_TREE_MODEL (search->liststore2), iter, 0, &car, -1); + gtk_tree_model_get (GTK_TREE_MODEL (search->liststore2), iter, 1, &postal, -1); + gtk_tree_model_get (GTK_TREE_MODEL (search->liststore2), iter, 2, &town, -1); + gtk_tree_model_get (GTK_TREE_MODEL (search->liststore2), iter, 4, &street, -1); + + /* protect against nulls */ + if (car==0) car=∅ + if (postal==0) postal=∅ + if (town==0) town=∅ + if (street==0) street=∅ + + if (search->attr.type == attr_town_name) + desc=g_strdup_printf("%s-%s %s", car, postal, town); + else + desc=g_strdup_printf("%s-%s %s, %s", car, postal, town, street); + return desc; +} + +static void button_destination(GtkWidget *widget, struct search_param *search) +{ + struct pcoord *c=NULL; + GtkTreeIter iter; + char *desc; + + if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (search->liststore2), &iter)) + return; + gtk_tree_model_get (GTK_TREE_MODEL (search->liststore2), &iter, COL_COUNT, &c, -1); + if (c) { + desc=description(search, &iter); + navit_set_destination(search->nav, c, desc, 1); + g_free(desc); + } +} + +static void button_bookmark(GtkWidget *widget, struct search_param *search) +{ + struct pcoord *c=NULL; + GtkTreeIter iter; + char *desc; + + if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (search->liststore2), &iter)) + return; + gtk_tree_model_get (GTK_TREE_MODEL (search->liststore2), &iter, COL_COUNT, &c, -1); + if (c) { + desc=description(search, &iter); + navit_add_bookmark(search->nav, c, desc); + g_free(desc); + } +} + + +char **columns_text[] = { + (char *[]){_n("Car"),_n("Iso2"),_n("Iso3"),_n("Country"),NULL}, + (char *[]){_n("Car"),_n("Postal"),_n("Town"),_n("District"),NULL}, + (char *[]){_n("Car"),_n("Postal"),_n("Town"),_n("District"),_n("Street"),NULL}, + (char *[]){_n("Car"),_n("Postal"),_n("Town"),_n("District"),_n("Street"),_n("Number"),NULL}, +}; + +static void set_columns(struct search_param *param, int mode) +{ + GList *columns_list,*columns; + char **column_text=columns_text[mode]; + int i=0; + + columns_list=gtk_tree_view_get_columns(GTK_TREE_VIEW(param->treeview)); + columns=columns_list; + while (columns) { + gtk_tree_view_remove_column(GTK_TREE_VIEW(param->treeview), columns->data); + columns=g_list_next(columns); + } + g_list_free(columns_list); + while (*column_text) { + GtkCellRenderer *cell=gtk_cell_renderer_text_new(); + gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (param->treeview),-1, gettext(*column_text), cell, "text", i, NULL); + i++; + column_text++; + } + +} + +static void row_activated(GtkWidget *widget, GtkTreePath *p1, GtkTreeViewColumn *c, struct search_param *search) +{ + GtkTreePath *path; + GtkTreeViewColumn *focus_column; + GtkTreeIter iter; + GtkWidget *entry_widget; + char *str; + int column; + + dbg(0,"enter\n"); + gtk_tree_view_get_cursor(GTK_TREE_VIEW(search->treeview), &path, &focus_column); + if(!path) + return; + if(!gtk_tree_model_get_iter(search->liststore2, &iter, path)) + return; + switch(search->attr.type) { + case attr_country_all: + entry_widget=search->entry_country; + column=3; + break; + case attr_town_name: + entry_widget=search->entry_city; + column=2; + break; + case attr_street_name: + entry_widget=search->entry_street; + column=4; + break; + default: + dbg(0,"Unknown mode\n"); + return; + } + gtk_tree_model_get(search->liststore2, &iter, column, &str, -1); + dbg(0,"str=%s\n", str); + search->partial=0; + gtk_entry_set_text(GTK_ENTRY(entry_widget), str); +} + +static void tree_view_button_release(GtkWidget *widget, GdkEventButton *event, struct search_param *search) +{ + GtkTreePath *path; + GtkTreeViewColumn *column; + gtk_tree_view_get_cursor(GTK_TREE_VIEW(search->treeview), &path, &column); + gtk_tree_view_row_activated(GTK_TREE_VIEW(search->treeview), path, column); + +} +static void +next_focus(struct search_param *search, GtkWidget *widget) +{ + if (widget == search->entry_country) + gtk_widget_grab_focus(search->entry_city); + if (widget == search->entry_city) + gtk_widget_grab_focus(search->entry_street); + if (widget == search->entry_street) + gtk_widget_grab_focus(search->entry_number); + +} + +static void changed(GtkWidget *widget, struct search_param *search) +{ + struct search_list_result *res; + GtkTreeIter iter; + + search->attr.u.str=(char *)gtk_entry_get_text(GTK_ENTRY(widget)); + printf("changed %s partial %d\n", search->attr.u.str, search->partial); + if (widget == search->entry_country) { + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (search->liststore2), 3, GTK_SORT_ASCENDING); + dbg(0,"country\n"); + search->attr.type=attr_country_all; + set_columns(search, 0); + } + if (widget == search->entry_postal) { + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (search->liststore2), 1, GTK_SORT_ASCENDING); + dbg(0,"postal\n"); + search->attr.type=attr_town_postal; + if (strlen(search->attr.u.str) < 2) + return; + set_columns(search, 1); + } + if (widget == search->entry_city) { + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (search->liststore2), 2, GTK_SORT_ASCENDING); + dbg(0,"town\n"); + search->attr.type=attr_town_name; + if (strlen(search->attr.u.str) < 3) + return; + set_columns(search, 1); + } + if (widget == search->entry_street) { + dbg(0,"street\n"); + search->attr.type=attr_street_name; + set_columns(search, 2); + } + + + search_list_search(search->sl, &search->attr, search->partial); + gtk_list_store_clear(search->liststore); + while((res=search_list_get_result(search->sl))) { + gtk_list_store_append(search->liststore,&iter); + gtk_list_store_set(search->liststore,&iter,COL_COUNT,res->c,-1); + if (widget == search->entry_country) { + if (res->country) { + gtk_list_store_set(search->liststore,&iter,0,res->country->car,-1); + gtk_list_store_set(search->liststore,&iter,1,res->country->iso3,-1); + gtk_list_store_set(search->liststore,&iter,2,res->country->iso2,-1); + gtk_list_store_set(search->liststore,&iter,3,res->country->name,-1); + } + } else { + if (res->country) + gtk_list_store_set(search->liststore,&iter,0,res->country->car,-1); + else + gtk_list_store_set(search->liststore,&iter,0,"",-1); + if (res->town) { + gtk_list_store_set(search->liststore,&iter,1,res->town->common.postal,-1); + gtk_list_store_set(search->liststore,&iter,2,res->town->name,-1); + gtk_list_store_set(search->liststore,&iter,3,res->town->district,-1); + } else { + gtk_list_store_set(search->liststore,&iter,1,"",-1); + gtk_list_store_set(search->liststore,&iter,2,"",-1); + gtk_list_store_set(search->liststore,&iter,3,"",-1); + } + if (res->street) + gtk_list_store_set(search->liststore,&iter,4,res->street->name,-1); + else + gtk_list_store_set(search->liststore,&iter,4,"",-1); + + } + } + if (! search->partial) + next_focus(search, widget); + search->partial=1; +} + +/* borrowed from gpe-login */ + + +#define MAX_ARGS 8 + +static void +parse_xkbd_args (const char *cmd, char **argv) +{ + const char *p = cmd; + char buf[strlen (cmd) + 1], *bufp = buf; + int nargs = 0; + int escape = 0, squote = 0, dquote = 0; + + while (*p) + { + if (escape) + { + *bufp++ = *p; + escape = 0; + } + else + { + switch (*p) + { + case '\\': + escape = 1; + break; + case '"': + if (squote) + *bufp++ = *p; + else + dquote = !dquote; + break; + case '\'': + if (dquote) + *bufp++ = *p; + else + squote = !squote; + break; + case ' ': + if (!squote && !dquote) + { + *bufp = 0; + if (nargs < MAX_ARGS) + argv[nargs++] = strdup (buf); + bufp = buf; + break; + } + default: + *bufp++ = *p; + break; + } + } + p++; + } + + if (bufp != buf) + { + *bufp = 0; + if (nargs < MAX_ARGS) + argv[nargs++] = strdup (buf); + } + argv[nargs] = NULL; +} + +int kbd_pid; + +static int +spawn_xkbd (char *xkbd_path, char *xkbd_str) +{ +#ifdef _WIN32 // AF FIXME for WIN32 + #ifndef F_SETFD + #define F_SETFD 2 + #endif +#else + char *xkbd_args[MAX_ARGS + 1]; + int fd[2]; + char buf[256]; + char c; + int a = 0; + size_t n; + + pipe (fd); + kbd_pid = fork (); + if (kbd_pid == 0) + { + close (fd[0]); + if (dup2 (fd[1], 1) < 0) + perror ("dup2"); + close (fd[1]); + if (fcntl (1, F_SETFD, 0)) + perror ("fcntl"); + xkbd_args[0] = (char *)xkbd_path; + xkbd_args[1] = "-xid"; + if (xkbd_str) + parse_xkbd_args (xkbd_str, xkbd_args + 2); + else + xkbd_args[2] = NULL; + execvp (xkbd_path, xkbd_args); + perror (xkbd_path); + _exit (1); + } + close (fd[1]); + do { + n = read (fd[0], &c, 1); + if (n) + { + buf[a++] = c; + } + } while (n && (c != 10) && (a < (sizeof (buf) - 1))); + + if (a) + { + buf[a] = 0; + return atoi (buf); + } +#endif + return 0; +} + +int destination_address(struct navit *nav) +{ + + GtkWidget *window2, *keyboard, *vbox, *table; + GtkWidget *label_country; + GtkWidget *label_postal, *label_city, *label_district; + GtkWidget *label_street, *label_number; + GtkWidget *hseparator1,*hseparator2; + GtkWidget *button1,*button2,*button3; + int i; + struct search_param *search=&search_param; + struct attr search_attr, country_name, *country_attr; + struct tracking *tracking; + struct country_search *cs; + struct item *item; + + + search->nav=nav; + search->ms=navit_get_mapset(nav); + search->sl=search_list_new(search->ms); + + window2 = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_title(GTK_WINDOW(window2),_("Enter Destination")); + gtk_window_set_wmclass (GTK_WINDOW (window2), "navit", "Navit"); + vbox = gtk_vbox_new(FALSE, 0); + table = gtk_table_new(3, 8, FALSE); + + search->entry_country = gtk_entry_new(); + label_country = gtk_label_new(_("Country")); + search->entry_postal = gtk_entry_new(); + gtk_widget_set_sensitive(GTK_WIDGET(search->entry_postal), FALSE); + label_postal = gtk_label_new(_("Zip Code")); + search->entry_city = gtk_entry_new(); + label_city = gtk_label_new(_("City")); + search->entry_district = gtk_entry_new(); + gtk_widget_set_sensitive(GTK_WIDGET(search->entry_district), FALSE); + label_district = gtk_label_new(_("District/Township")); + hseparator1 = gtk_vseparator_new(); + search->entry_street = gtk_entry_new(); + label_street = gtk_label_new(_("Street")); + search->entry_number = gtk_entry_new(); + label_number = gtk_label_new(_("Number")); + search->treeview=gtk_tree_view_new(); + search->listbox = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (search->listbox), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + + gtk_tree_view_set_model (GTK_TREE_VIEW (search->treeview), NULL); + gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(search->listbox),search->treeview); + { + GType types[COL_COUNT+1]; + for(i=0;i<COL_COUNT;i++) + types[i]=G_TYPE_STRING; + types[i]=G_TYPE_POINTER; + search->liststore=gtk_list_store_newv(COL_COUNT+1,types); + search->liststore2=gtk_tree_model_sort_new_with_model(GTK_TREE_MODEL(search->liststore)); + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (search->liststore2), 3, GTK_SORT_ASCENDING); + gtk_tree_view_set_model (GTK_TREE_VIEW (search->treeview), GTK_TREE_MODEL(search->liststore2)); + } + + + + + hseparator2 = gtk_vseparator_new(); + button1 = gtk_button_new_with_label(_("Map")); + button2 = gtk_button_new_with_label(_("Bookmark")); + button3 = gtk_button_new_with_label(_("Destination")); + + gtk_table_attach(GTK_TABLE(table), label_country, 0, 1, 0, 1, 0, GTK_FILL, 0, 0); + gtk_table_attach(GTK_TABLE(table), label_postal, 1, 2, 0, 1, 0, GTK_FILL, 0, 0); + gtk_table_attach(GTK_TABLE(table), label_city, 2, 3, 0, 1, 0, GTK_FILL, 0, 0); + + gtk_table_attach(GTK_TABLE(table), search->entry_country, 0, 1, 1, 2, 0, GTK_FILL, 0, 0); + gtk_table_attach(GTK_TABLE(table), search->entry_postal, 1, 2, 1, 2, 0, GTK_FILL, 0, 0); + gtk_table_attach(GTK_TABLE(table), search->entry_city, 2, 3, 1, 2, 0, GTK_FILL, 0, 0); + + gtk_table_attach(GTK_TABLE(table), label_district, 0, 1, 2, 3, 0, GTK_FILL, 0, 0); + gtk_table_attach(GTK_TABLE(table), label_street, 1, 2, 2, 3, 0, GTK_FILL, 0, 0); + gtk_table_attach(GTK_TABLE(table), label_number, 2, 3, 2, 3, 0, GTK_FILL, 0, 0); + + gtk_table_attach(GTK_TABLE(table), search->entry_district, 0, 1, 3, 4, 0, GTK_FILL, 0, 0); + gtk_table_attach(GTK_TABLE(table), search->entry_street, 1, 2, 3, 4, 0, GTK_FILL, 0, 0); + gtk_table_attach(GTK_TABLE(table), search->entry_number, 2, 3, 3, 4, 0, GTK_FILL, 0, 0); + + gtk_table_attach(GTK_TABLE(table), search->listbox, 0, 3, 4, 5, GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 0, 0); + + gtk_table_attach(GTK_TABLE(table), button1, 0, 1, 5, 6, GTK_FILL, GTK_FILL, 0, 0); + gtk_table_attach(GTK_TABLE(table), button2, 1, 2, 5, 6, GTK_FILL, GTK_FILL, 0, 0); + gtk_table_attach(GTK_TABLE(table), button3, 2, 3, 5, 6, GTK_FILL, GTK_FILL, 0, 0); + + g_signal_connect(G_OBJECT(search->entry_country), "changed", G_CALLBACK(changed), search); + g_signal_connect(G_OBJECT(search->entry_postal), "changed", G_CALLBACK(changed), search); + g_signal_connect(G_OBJECT(search->entry_city), "changed", G_CALLBACK(changed), search); + g_signal_connect(G_OBJECT(search->entry_district), "changed", G_CALLBACK(changed), search); + g_signal_connect(G_OBJECT(search->entry_street), "changed", G_CALLBACK(changed), search); + g_signal_connect(G_OBJECT(search->entry_number), "changed", G_CALLBACK(changed), search); + g_signal_connect(G_OBJECT(button1), "clicked", G_CALLBACK(button_map), search); + g_signal_connect(G_OBJECT(button2), "clicked", G_CALLBACK(button_bookmark), search); + g_signal_connect(G_OBJECT(button3), "clicked", G_CALLBACK(button_destination), search); + g_signal_connect(G_OBJECT(search->treeview), "button-release-event", G_CALLBACK(tree_view_button_release), search); + g_signal_connect(G_OBJECT(search->treeview), "row_activated", G_CALLBACK(row_activated), search); + + gtk_widget_grab_focus(search->entry_city); + + gtk_box_pack_start(GTK_BOX(vbox), table, TRUE, TRUE, 0); + keyboard=gtk_socket_new(); + gtk_box_pack_end(GTK_BOX(vbox), keyboard, FALSE, FALSE, 0); + gtk_container_add(GTK_CONTAINER(window2), vbox); +#if 0 + g_signal_connect(G_OBJECT(listbox), "select-row", G_CALLBACK(select_row), NULL); +#endif + gtk_widget_show_all(window2); + +#ifndef _WIN32 + gtk_socket_steal(GTK_SOCKET(keyboard), spawn_xkbd("xkbd","-geometry 200x100")); +#endif + + country_attr=country_default(); + tracking=navit_get_tracking(nav); + if (tracking && tracking_get_attr(tracking, attr_country_id, &search_attr, NULL)) + country_attr=&search_attr; + if (country_attr) { + cs=country_search_new(country_attr, 0); + item=country_search_get_item(cs); + if (item && item_attr_get(item, attr_country_name, &country_name)) + gtk_entry_set_text(GTK_ENTRY(search->entry_country), country_name.u.str); + country_search_destroy(cs); + } else { + dbg(0,"warning: no default country found\n"); + } + search->partial=1; + return 0; +} diff --git a/gui/gtk/gui_gtk.h b/gui/gtk/gui_gtk.h new file mode 100644 index 00000000..6168b9ae --- /dev/null +++ b/gui/gtk/gui_gtk.h @@ -0,0 +1,62 @@ +/** + * Navit, a modular navigation system. + * Copyright (C) 2005-2008 Navit Team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "coord.h" + +struct menu_methods; +struct datawindow_methods; +struct navit; +struct callback; +struct statusbar_priv; + +struct gui_priv { + struct navit *nav; + GtkWidget *win; + GtkWidget *dialog_win; + GtkWidget *dialog_entry; + struct pcoord dialog_coord; + GtkWidget *vbox; + GtkWidget *menubar; + GtkActionGroup *base_group; + GtkActionGroup *debug_group; + GtkActionGroup *dyn_group; + GtkUIManager *ui_manager; + GSList *layout_group; + GSList *projection_group; + GSList *vehicle_group; + GList *dest_menuitems; + GList *bookmarks_menuitems; + GList *vehicle_menuitems; + GtkUIManager *menu_manager; // old + struct statusbar_priv *statusbar; + int menubar_enable; + int toolbar_enable; + int statusbar_enable; + int dyn_counter; + struct datawindow_priv *datawindow; +}; + +void gui_gtk_ui_init(struct gui_priv *this); +struct menu_priv *gui_gtk_menubar_new(struct gui_priv *gui, struct menu_methods *meth); +struct statusbar_priv *gui_gtk_statusbar_new(struct gui_priv *gui); +struct menu_priv *gui_gtk_popup_new(struct gui_priv *gui, struct menu_methods *meth); +struct datawindow_priv *gui_gtk_datawindow_new(struct gui_priv *gui, char *name, struct callback *click, struct callback *close, struct datawindow_methods *meth); +void gui_gtk_datawindow_destroy(struct datawindow_priv *win); +void gui_gtk_datawindow_set_button(struct datawindow_priv *this_, GtkWidget *btn); + diff --git a/gui/gtk/gui_gtk_action.c b/gui/gtk/gui_gtk_action.c new file mode 100644 index 00000000..144a8270 --- /dev/null +++ b/gui/gtk/gui_gtk_action.c @@ -0,0 +1,627 @@ +/** + * Navit, a modular navigation system. + * Copyright (C) 2005-2008 Navit Team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include <string.h> +#include <gtk/gtk.h> +#include "navit.h" +#include "gui_gtk.h" +#include "menu.h" +#include "coord.h" +#include "item.h" +#include "attr.h" +#include "callback.h" +#include "debug.h" +#include "destination.h" + +#define gettext_noop(String) String +#define _(STRING) gettext(STRING) +#define _n(STRING) gettext_noop(STRING) + +struct menu_priv { + char *path; + GtkAction *action; + struct gui_priv *gui; + enum menu_type type; + struct callback *cb; + struct menu_priv *child; + struct menu_priv *sibling; + gulong handler_id; + guint merge_id; + GtkWidget *widget; +}; + +/* Create callbacks that implement our Actions */ + +static void +zoom_in_action(GtkWidget *w, struct gui_priv *gui, void *dummy) +{ + navit_zoom_in(gui->nav, 2, NULL); +} + +static void +zoom_out_action(GtkWidget *w, struct gui_priv *gui, void *dummy) +{ + navit_zoom_out(gui->nav, 2, NULL); +} + +static void +refresh_action(GtkWidget *w, struct gui_priv *gui, void *dummy) +{ + navit_draw(gui->nav); +} + +// Forward declarations, these should not be visible outside the GUI, so +// they are not in the header files, but here +void gui_gtk_datawindow_set_button(struct datawindow_priv *this_, GtkWidget *btn); +void gui_gtk_datawindow_destroy(struct datawindow_priv *win); + +static void +roadbook_action(GtkWidget *w, struct gui_priv *gui, void *dummy) +{ + + if (! gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(w))) { + gui_gtk_datawindow_destroy(gui->datawindow); + } else { + navit_window_roadbook_new(gui->nav); + if (gui->datawindow) { + gui_gtk_datawindow_set_button(gui->datawindow, w); + } + } +} + +static void +autozoom_action(GtkWidget *w, struct gui_priv *gui, void *dummy) +{ + struct attr autozoom_attr; + + autozoom_attr.type = attr_autozoom_active; + if (! gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(w))) { + autozoom_attr.u.num = 0; + } else { + autozoom_attr.u.num = 1; + } + + navit_set_attr(gui->nav, &autozoom_attr); +} + +static void +cursor_action(GtkWidget *w, struct gui_priv *gui, void *dummy) +{ + struct attr attr; + + attr.type=attr_cursor; + attr.u.num=gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(w)); + if(!navit_set_attr(gui->nav, &attr)) { + dbg(0, "Failed to set attr_cursor\n"); + } +} + +static void +tracking_action(GtkWidget *w, struct gui_priv *gui, void *dummy) +{ + struct attr attr; + + attr.type=attr_tracking; + attr.u.num=gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(w)); + if(!navit_set_attr(gui->nav, &attr)) { + dbg(0, "Failed to set attr_tracking\n"); + } +} + +static void +orient_north_action(GtkWidget *w, struct gui_priv *gui, void *dummy) +{ + struct attr attr; + + attr.type=attr_orientation; + attr.u.num=gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(w)) ? 0:-1; + if(!navit_set_attr(gui->nav, &attr)) { + dbg(0, "Failed to set attr_orientation\n"); + } +} + +static void +window_fullscreen_action(GtkWidget *w, struct gui_priv *gui, void *dummy) +{ + if(gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(w))) + gtk_window_fullscreen(GTK_WINDOW(gui->win)); + else + gtk_window_unfullscreen(GTK_WINDOW(gui->win)); +} + +#include <stdlib.h> +#include "point.h" +#include "transform.h" + +static void +info_action(GtkWidget *w, struct gui_priv *gui, void *dummy) +{ + char buffer[512]; + int mw,mh; + struct coord lt, rb; + struct point p; + struct transformation *t; + + t=navit_get_trans(gui->nav); + transform_get_size(t, &mw, &mh); + p.x=0; + p.y=0; + transform_reverse(t, &p, <); + p.x=mw; + p.y=mh; + transform_reverse(t, &p, &rb); + + sprintf(buffer,"./info.sh %d,%d 0x%x,0x%x 0x%x,0x%x", mw, mh, lt.x, lt.y, rb.x, rb.y); + system(buffer); + +} + + +static void +route_clear_action(GtkWidget *w, struct gui_priv *gui, void *dummy) +{ + navit_set_destination(gui->nav, NULL, NULL, 0); +} + +static void +destination_action(GtkWidget *w, struct gui_priv *gui, void *dummy) +{ + destination_address(gui->nav); +} + +static void +quit_action (GtkWidget *w, struct gui_priv *gui, void *dummy) +{ + navit_destroy(gui->nav); +} + +static GtkActionEntry entries[] = +{ + { "DisplayMenuAction", NULL, _n("Display") }, + { "RouteMenuAction", NULL, _n("Route") }, + { "FormerDestinationMenuAction", NULL, _n("Former Destinations") }, + { "BookmarkMenuAction", NULL, _n("Bookmarks") }, + { "MapMenuAction", NULL, _n("Map") }, + { "LayoutMenuAction", NULL, _n("Layout") }, + { "ProjectionMenuAction", NULL, _n("Projection") }, + { "VehicleMenuAction", NULL, _n("Vehicle") }, + { "ZoomOutAction", GTK_STOCK_ZOOM_OUT, _n("ZoomOut"), NULL, NULL, G_CALLBACK(zoom_out_action) }, + { "ZoomInAction", GTK_STOCK_ZOOM_IN, _n("ZoomIn"), NULL, NULL, G_CALLBACK(zoom_in_action) }, + { "RefreshAction", GTK_STOCK_REFRESH, _n("Recalculate"), NULL, NULL, G_CALLBACK(refresh_action) }, +#ifdef GTK_STOCK_INFO + { "InfoAction", GTK_STOCK_INFO, _n("Info"), NULL, NULL, G_CALLBACK(info_action) }, +#else + { "InfoAction", NULL, _n("Info"), NULL, NULL, G_CALLBACK(info_action) }, +#endif /*GTK_STOCK_INFO*/ + { "DestinationAction", "flag_icon", _n("Destination"), NULL, NULL, G_CALLBACK(destination_action) }, + { "RouteClearAction", NULL, _n("Stop Navigation"), NULL, NULL, G_CALLBACK(route_clear_action) }, + { "Test", NULL, _n("Test"), NULL, NULL, G_CALLBACK(destination_action) }, + { "QuitAction", GTK_STOCK_QUIT, _n("_Quit"), "<control>Q",NULL, G_CALLBACK (quit_action) } +}; + +static guint n_entries = G_N_ELEMENTS (entries); + +static GtkToggleActionEntry toggleentries[] = +{ + { "CursorAction", "cursor_icon",_n("Cursor"), NULL, NULL, G_CALLBACK(cursor_action),TRUE }, + { "TrackingAction", NULL ,_n("Lock on Road"), NULL, NULL, G_CALLBACK(tracking_action),TRUE }, + { "OrientationAction", "orientation_icon", _n("Northing"), NULL, NULL, G_CALLBACK(orient_north_action),FALSE }, + { "RoadbookAction", GTK_STOCK_JUSTIFY_FILL, _n("Roadbook"), NULL, NULL, G_CALLBACK(roadbook_action), FALSE }, + { "AutozoomAction", GTK_STOCK_ZOOM_FIT, _n("Autozoom"), NULL, NULL, G_CALLBACK(autozoom_action), FALSE }, +#ifdef GTK_STOCK_FULLSCREEN + { "FullscreenAction",GTK_STOCK_FULLSCREEN, _n("Fullscreen"), NULL, NULL, G_CALLBACK(window_fullscreen_action), FALSE } +#else + { "FullscreenAction", NULL, _n("Fullscreen"), NULL, NULL, G_CALLBACK(window_fullscreen_action), FALSE } +#endif /*GTK_STOCK_FULLSCREEN*/ +}; + +static guint n_toggleentries = G_N_ELEMENTS (toggleentries); + +static GtkActionEntry debug_entries[] = +{ + { "DataMenuAction", NULL, _n("Data") }, +}; + +static guint n_debug_entries = G_N_ELEMENTS (debug_entries); + + +static const char * cursor_xpm[] = { +"22 22 2 1", +" c None", +". c #0000FF", +" ", +" ", +" ", +" .. ", +" .. .. ", +" .. .. ", +" . . ", +" . . ", +" . ... . ", +" . ... . . ", +" . ... . . ", +" . .. . . ", +" . . . ", +" . . . ", +" . . . ", +" . . . ", +" .. .. ", +" .. .. ", +" .. ", +" ", +" ", +" "}; + + +static const char * north_xpm[] = { +"22 22 2 1", +" c None", +". c #000000", +" ", +" ", +" . ", +" ... ", +" . . . ", +" . . . ", +" . ", +" .... . .... ", +" .... . .... ", +" .... . .. ", +" .. .. .. ", +" .. .. .. ", +" .. .. .. ", +" .. .. .. ", +" .. . .... ", +" .... . .... ", +" .... . .... ", +" . ", +" . ", +" . ", +" ", +" "}; + + +static const char * flag_xpm[] = { +"22 22 2 1", +" c None", +"+ c #000000", +"+++++++ ", +"+ +++++++++ ", +"+ +++ +++++++++ ", +"+ +++ +++ +++ ", +"++++ +++ +++ ", +"++++ +++ +++ ", +"++++ +++ +++ + ", +"+ ++++++ +++ + ", +"+ +++ ++++++ + ", +"+ +++ +++ +++ ", +"++++ +++ +++ ", +"++++ +++ +++ ", +"++++++++++ +++ + ", +"+ +++++++++ + ", +"+ ++++++ ", +"+ ", +"+ ", +"+ ", +"+ ", +"+ ", +"+ ", +"+ "}; + + + +static struct { + gchar *stockid; + const char **icon_xpm; +} stock_icons[] = { + {"cursor_icon", cursor_xpm }, + {"orientation_icon", north_xpm }, + {"flag_icon", flag_xpm } +}; + + +static gint n_stock_icons = G_N_ELEMENTS (stock_icons); + + +static void +register_my_stock_icons (void) +{ + GtkIconFactory *icon_factory; + GtkIconSet *icon_set; + GdkPixbuf *pixbuf; + gint i; + + icon_factory = gtk_icon_factory_new (); + + for (i = 0; i < n_stock_icons; i++) + { + pixbuf = gdk_pixbuf_new_from_xpm_data(stock_icons[i].icon_xpm); + icon_set = gtk_icon_set_new_from_pixbuf (pixbuf); + g_object_unref(pixbuf); + gtk_icon_factory_add (icon_factory, stock_icons[i].stockid, icon_set); + gtk_icon_set_unref (icon_set); + } + + gtk_icon_factory_add_default(icon_factory); + + g_object_unref(icon_factory); +} + + +static char layout[] = + "<ui>\ + <menubar name=\"MenuBar\">\ + <menu name=\"Display\" action=\"DisplayMenuAction\">\ + <menuitem name=\"Zoom in\" action=\"ZoomInAction\" />\ + <menuitem name=\"Zoom out\" action=\"ZoomOutAction\" />\ + <menuitem name=\"Cursor\" action=\"CursorAction\"/>\ + <menuitem name=\"Tracking\" action=\"TrackingAction\"/>\ + <menuitem name=\"Orientation\" action=\"OrientationAction\"/>\ + <menuitem name=\"Roadbook\" action=\"RoadbookAction\"/>\ + <menuitem name=\"Autozoom\" action=\"AutozoomAction\"/>\ + <menuitem name=\"Fullscreen\" action=\"FullscreenAction\"/>\ + <menuitem name=\"Quit\" action=\"QuitAction\" />\ + <placeholder name=\"RouteMenuAdditions\" />\ + </menu>\ + <menu name=\"Data\" action=\"DataMenuAction\">\ + <placeholder name=\"DataMenuAdditions\" />\ + </menu>\ + <menu name=\"Route\" action=\"RouteMenuAction\">\ + <menuitem name=\"Refresh\" action=\"RefreshAction\" />\ + <menuitem name=\"Destination\" action=\"DestinationAction\" />\ + <menuitem name=\"Clear\" action=\"RouteClearAction\" />\ + <menu name=\"FormerDestinations\" action=\"FormerDestinationMenuAction\">\ + <placeholder name=\"FormerDestinationMenuAdditions\" />\ + </menu>\ + <menu name=\"Bookmarks\" action=\"BookmarkMenuAction\">\ + <placeholder name=\"BookmarkMenuAdditions\" />\ + </menu>\ + <placeholder name=\"RouteMenuAdditions\" />\ + </menu>\ + <menu name=\"Map\" action=\"MapMenuAction\">\ + <menu name=\"Layout\" action=\"LayoutMenuAction\">\ + <placeholder name=\"LayoutMenuAdditions\" />\ + </menu>\ + <menu name=\"Projection\" action=\"ProjectionMenuAction\">\ + <placeholder name=\"ProjectionMenuAdditions\" />\ + </menu>\ + <menu name=\"Vehicle\" action=\"VehicleMenuAction\">\ + <placeholder name=\"VehicleMenuAdditions\" />\ + </menu>\ + <placeholder name=\"MapMenuAdditions\" />\ + </menu>\ + </menubar>\ + <toolbar name=\"ToolBar\" action=\"BaseToolbar\" action=\"BaseToolbarAction\">\ + <placeholder name=\"ToolItems\">\ + <separator/>\ + <toolitem name=\"Zoom in\" action=\"ZoomInAction\"/>\ + <toolitem name=\"Zoom out\" action=\"ZoomOutAction\"/>\ + <toolitem name=\"Refresh\" action=\"RefreshAction\"/>\ + <toolitem name=\"Cursor\" action=\"CursorAction\"/>\ + <toolitem name=\"Orientation\" action=\"OrientationAction\"/>\ + <toolitem name=\"Destination\" action=\"DestinationAction\"/>\ + <!-- <toolitem name=\"Info\" action=\"InfoAction\"/> -->\ + <toolitem name=\"Roadbook\" action=\"RoadbookAction\"/>\ + <toolitem name=\"Autozoom\" action=\"AutozoomAction\"/>\ + <toolitem name=\"Quit\" action=\"QuitAction\"/>\ + <separator/>\ + </placeholder>\ + </toolbar>\ + <popup name=\"PopUp\">\ + </popup>\ + </ui>"; + + +static void +activate(void *dummy, struct menu_priv *menu) +{ + if (menu->cb) + callback_call_0(menu->cb); +} + +static struct menu_methods menu_methods; + +static struct menu_priv * +add_menu(struct menu_priv *menu, struct menu_methods *meth, char *name, enum menu_type type, struct callback *cb) +{ + struct menu_priv *ret; + char *dynname; + + ret=g_new0(struct menu_priv, 1); + *meth=menu_methods; + if (! strcmp(menu->path, "/ui/MenuBar") && !strcmp(name,"Route")) { + dynname=g_strdup("Route"); + } else if (! strcmp(menu->path, "/ui/MenuBar") && !strcmp(name,"Data")) { + dynname=g_strdup("Data"); + } else { + dynname=g_strdup_printf("%d", menu->gui->dyn_counter++); + if (type == menu_type_toggle) + ret->action=GTK_ACTION(gtk_toggle_action_new(dynname, name, NULL, NULL)); + else + ret->action=gtk_action_new(dynname, name, NULL, NULL); + if (cb) + ret->handler_id=g_signal_connect(ret->action, "activate", G_CALLBACK(activate), ret); + gtk_action_group_add_action(menu->gui->dyn_group, ret->action); + ret->merge_id=gtk_ui_manager_new_merge_id(menu->gui->ui_manager); + gtk_ui_manager_add_ui( menu->gui->ui_manager, ret->merge_id, menu->path, dynname, dynname, type == menu_type_submenu ? GTK_UI_MANAGER_MENU : GTK_UI_MANAGER_MENUITEM, FALSE); + } + ret->gui=menu->gui; + ret->path=g_strdup_printf("%s/%s", menu->path, dynname); + ret->type=type; + ret->cb=cb; + ret->sibling=menu->child; + menu->child=ret; + g_free(dynname); + return ret; + +} + +static void +remove_menu(struct menu_priv *item, int recursive) +{ + + if (recursive) { + struct menu_priv *next,*child=item->child; + while (child) { + next=child->sibling; + remove_menu(child, recursive); + child=next; + } + } + if (item->action) { + gtk_ui_manager_remove_ui(item->gui->ui_manager, item->merge_id); + gtk_action_group_remove_action(item->gui->dyn_group, item->action); +#if 0 + if (item->callback) + g_signal_handler_disconnect(item->action, item->handler_id); +#endif + g_object_unref(item->action); + } + g_free(item->path); + g_free(item); +} + +static void +set_toggle(struct menu_priv *menu, int active) +{ + gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(menu->action), active); +} + +static int +get_toggle(struct menu_priv *menu) +{ + return gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(menu->action)); +} + +static struct menu_methods menu_methods = { +#if 1 + add_menu, + set_toggle, + get_toggle, +#else + NULL, + NULL, + NULL +#endif +}; + + +static void +popup_deactivate(GtkWidget *widget, struct menu_priv *menu) +{ + g_signal_handler_disconnect(widget, menu->handler_id); + remove_menu(menu, 1); +} + +static void +popup_activate(struct menu_priv *menu) +{ +#ifdef _WIN32 + menu->widget=gtk_ui_manager_get_widget(menu->gui->ui_manager, menu->path ); +#endif + gtk_menu_popup(GTK_MENU(menu->widget), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time ()); + menu->handler_id=g_signal_connect(menu->widget, "selection-done", G_CALLBACK(popup_deactivate), menu); +} + +void +gui_gtk_ui_init(struct gui_priv *this) +{ + GError *error = NULL; + struct attr attr; + GtkToggleAction *toggle_action; + + this->base_group = gtk_action_group_new ("BaseActions"); + this->debug_group = gtk_action_group_new ("DebugActions"); + this->dyn_group = gtk_action_group_new ("DynamicActions"); + register_my_stock_icons(); + this->ui_manager = gtk_ui_manager_new (); + gtk_action_group_set_translation_domain(this->base_group,"navit"); + gtk_action_group_set_translation_domain(this->debug_group,"navit"); + gtk_action_group_set_translation_domain(this->dyn_group,"navit"); + gtk_action_group_add_actions (this->base_group, entries, n_entries, this); + gtk_action_group_add_toggle_actions (this->base_group, toggleentries, n_toggleentries, this); + gtk_ui_manager_insert_action_group (this->ui_manager, this->base_group, 0); + gtk_action_group_add_actions (this->debug_group, debug_entries, n_debug_entries, this); + gtk_ui_manager_insert_action_group (this->ui_manager, this->debug_group, 0); + gtk_ui_manager_add_ui_from_string (this->ui_manager, layout, strlen(layout), &error); + gtk_ui_manager_insert_action_group (this->ui_manager, this->dyn_group, 0); + if (error) { + g_message ("building menus failed: %s", error->message); + g_error_free (error); + } + if (navit_get_attr(this->nav, attr_cursor, &attr, NULL)) { + toggle_action = GTK_TOGGLE_ACTION(gtk_action_group_get_action(this->base_group, "CursorAction")); + gtk_toggle_action_set_active(toggle_action, attr.u.num); + } + if (navit_get_attr(this->nav, attr_orientation, &attr, NULL)) { + toggle_action = GTK_TOGGLE_ACTION(gtk_action_group_get_action(this->base_group, "OrientationAction")); + gtk_toggle_action_set_active(toggle_action, attr.u.num != -1); + } + if (navit_get_attr(this->nav, attr_tracking, &attr, NULL)) { + toggle_action = GTK_TOGGLE_ACTION(gtk_action_group_get_action(this->base_group, "TrackingAction")); + gtk_toggle_action_set_active(toggle_action, attr.u.num); + } + toggle_action = GTK_TOGGLE_ACTION(gtk_action_group_get_action(this->base_group, "RoadbookAction")); + gtk_toggle_action_set_active(toggle_action, 0); + + if (navit_get_attr(this->nav, attr_autozoom_active, &attr, NULL)) { + toggle_action = GTK_TOGGLE_ACTION(gtk_action_group_get_action(this->base_group, "AutozoomAction")); + gtk_toggle_action_set_active(toggle_action, attr.u.num); + } + +} + +static struct menu_priv * +gui_gtk_ui_new (struct gui_priv *this, struct menu_methods *meth, char *path, int popup, GtkWidget **widget_ret) +{ + struct menu_priv *ret; + GtkWidget *widget; + + *meth=menu_methods; + ret=g_new0(struct menu_priv, 1); + ret->path=g_strdup(path); + ret->gui=this; + + widget=gtk_ui_manager_get_widget(this->ui_manager, path); + GTK_WIDGET_UNSET_FLAGS (widget, GTK_CAN_FOCUS); + if (widget_ret) + *widget_ret=widget; + if (! popup) { + gtk_box_pack_start (GTK_BOX(this->vbox), widget, FALSE, FALSE, 0); + gtk_widget_show (widget); + } else { + ret->widget=widget; + meth->popup=popup_activate; + } + return ret; +} + +#if 0 +struct menu_priv * +gui_gtk_menubar_new(struct gui_priv *this, struct menu_methods *meth) +{ + return gui_gtk_ui_new(this, meth, "/ui/MenuBar", 0, &this->menubar); +} +#endif + +struct menu_priv * +gui_gtk_popup_new(struct gui_priv *this, struct menu_methods *meth) +{ + return gui_gtk_ui_new(this, meth, "/ui/PopUp", 1, NULL); +} diff --git a/gui/gtk/gui_gtk_statusbar.c b/gui/gtk/gui_gtk_statusbar.c new file mode 100644 index 00000000..f31cf078 --- /dev/null +++ b/gui/gtk/gui_gtk_statusbar.c @@ -0,0 +1,178 @@ +/** + * Navit, a modular navigation system. + * Copyright (C) 2005-2008 Navit Team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include <stdio.h> +#include <string.h> +#include <time.h> +#include <math.h> +#include <gtk/gtk.h> +#include "item.h" +#include "coord.h" +#include "debug.h" +#include "vehicle.h" +#include "callback.h" +#include "route.h" +#include "transform.h" +#include "navit.h" +#include "map.h" +#include "navigation.h" +#include "gui_gtk.h" +#include "navit_nls.h" + +struct statusbar_priv { + struct gui_priv *gui; + GtkWidget *hbox; + char gps_text[128]; + GtkWidget *gps; + char route_text[128]; + GtkWidget *route; + struct callback *vehicle_cb; +}; + +#if 0 +static void +statusbar_destroy(struct statusbar_priv *this) +{ + g_free(this); +} + +static void +statusbar_gps_update(struct statusbar_priv *this, int sats, int qual, double lng, double lat, double height, double direction, double speed) +{ + char *dirs[]={_("N"),_("NE"),_("E"),_("SE"),_("S"),_("SW"),_("W"),_("NW"),_("N")}; + char *dir; + int dir_idx; + char pos_text[26]; + + coord_format(lat,lng,DEGREES_MINUTES_SECONDS,pos_text,sizeof(pos_text)); + dir=dirs[dir_idx]; + sprintf(this->gps_text, "GPS %02d/%02d %s %4.0fm %3.0f°%-2s %3.0fkm/h", sats, qual, pos_text, height, direction, dir, speed); + gtk_label_set_text(GTK_LABEL(this->gps), this->gps_text); + +} +#endif + +static char *status_fix2str(int type) +{ + switch(type) { + case 0: return _("No"); + case 1: return _("2D"); + case 3: return _("3D"); + default: + return _("OT"); + } +} + +static void +statusbar_route_update(struct statusbar_priv *this, struct navit *navit, struct vehicle *v) +{ + struct navigation *nav=NULL; + struct map *map=NULL; + struct map_rect *mr=NULL; + struct item *item=NULL; + struct attr attr; + double route_len=0; + time_t eta; + struct tm *eta_tm=NULL; + char buffer[128]; + double lng, lat, direction=0, height=0, speed=0, hdop=0; + int sats=0, qual=0; + int status=0; + char *dirs[]={_("N"),_("NE"),_("E"),_("SE"),_("S"),_("SW"),_("W"),_("NW"),_("N")}; + char *dir; + int dir_idx; + + if (navit) + nav=navit_get_navigation(navit); + if (nav) + map=navigation_get_map(nav); + if (map) + mr=map_rect_new(map, NULL); + if (mr) + item=map_rect_get_item(mr); + if (item) { + if (item_attr_get(item, attr_destination_length, &attr)) + route_len=attr.u.num; + if (item_attr_get(item, attr_destination_time, &attr)) { + eta=time(NULL)+attr.u.num/10; + eta_tm=localtime(&eta); + } + } + if (mr) + map_rect_destroy(mr); + sprintf(buffer,_("Route %4.0fkm %02d:%02d ETA" ),route_len/1000, eta_tm ? eta_tm->tm_hour : 0 , eta_tm ? eta_tm->tm_min : 0); + if (strcmp(buffer, this->route_text)) { + strcpy(this->route_text, buffer); + gtk_label_set_text(GTK_LABEL(this->route), this->route_text); + } + if (!vehicle_get_attr(v, attr_position_coord_geo, &attr, NULL)) + return; + lng=attr.u.coord_geo->lng; + lat=attr.u.coord_geo->lat; + if (vehicle_get_attr(v, attr_position_fix_type, &attr, NULL)) + status=attr.u.num; + if (vehicle_get_attr(v, attr_position_direction, &attr, NULL)) + direction=*(attr.u.numd); + direction=fmod(direction,360); + if (direction < 0) + direction+=360; + dir_idx=(direction+22.5)/45; + dir=dirs[dir_idx]; + if (vehicle_get_attr(v, attr_position_height, &attr, NULL)) + height=*(attr.u.numd); + if (vehicle_get_attr(v, attr_position_hdop, &attr, NULL)) + hdop=*(attr.u.numd); + if (vehicle_get_attr(v, attr_position_speed, &attr, NULL)) + speed=*(attr.u.numd); + if (vehicle_get_attr(v, attr_position_sats_used, &attr, NULL)) + sats=attr.u.num; + if (vehicle_get_attr(v, attr_position_qual, &attr, NULL)) + qual=attr.u.num; + coord_format(lat,lng,DEGREES_MINUTES_SECONDS,buffer,sizeof(buffer)); + sprintf(this->gps_text,"GPS:%s %02d/%02d HD:%02.2f %s %4.0fm %3.0f°%-2s %3.0fkm/h", + status_fix2str(status), + sats, qual, hdop, buffer, height, + direction, dir, speed); + gtk_label_set_text(GTK_LABEL(this->gps), this->gps_text); +} + +struct statusbar_priv * +gui_gtk_statusbar_new(struct gui_priv *gui) +{ + struct statusbar_priv *this=g_new0(struct statusbar_priv, 1); + + this->gui=gui; + this->hbox=gtk_hbox_new(FALSE, 1); + this->gps=gtk_label_new( "GPS 00/0 0000.0000N 00000.0000E 0000m 000°NO 000km/h" ); + gtk_label_set_justify(GTK_LABEL(this->gps), GTK_JUSTIFY_LEFT); + this->route=gtk_label_new( _( "Route 0000km 0+00:00 ETA" ) ); + gtk_label_set_justify(GTK_LABEL(this->route), GTK_JUSTIFY_LEFT); + gtk_box_pack_start(GTK_BOX(this->hbox), this->gps, TRUE, TRUE, 2); + gtk_box_pack_start(GTK_BOX(this->hbox), gtk_vseparator_new(), TRUE, TRUE, 2); + gtk_box_pack_start(GTK_BOX(this->hbox), this->route, TRUE, TRUE, 2); + GTK_WIDGET_UNSET_FLAGS (this->hbox, GTK_CAN_FOCUS); + + gtk_box_pack_end(GTK_BOX(gui->vbox), this->hbox, FALSE, FALSE, 0); + gtk_widget_show_all(this->hbox); + /* add a callback for position updates */ + this->vehicle_cb=callback_new_attr_1(callback_cast(statusbar_route_update), attr_position_coord_geo, this); + navit_add_callback(gui->nav, this->vehicle_cb); + return this; +} + diff --git a/gui/gtk/gui_gtk_window.c b/gui/gtk/gui_gtk_window.c new file mode 100644 index 00000000..a95b8e1b --- /dev/null +++ b/gui/gtk/gui_gtk_window.c @@ -0,0 +1,771 @@ +/** + * Navit, a modular navigation system. + * Copyright (C) 2005-2008 Navit Team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <math.h> +#include <gdk/gdkkeysyms.h> +#if !defined(GDK_Book) || !defined(GDK_Calendar) +#include <X11/XF86keysym.h> +#endif +#include <gtk/gtk.h> +#include "config.h" +#include "item.h" +#include "navit.h" +#include "debug.h" +#include "gui.h" +#include "coord.h" +#include "point.h" +#include "plugin.h" +#include "graphics.h" +#include "gui_gtk.h" +#include "transform.h" +#include "config.h" +#include "callback.h" +#include "layout.h" +#include "vehicle.h" +#include "map.h" +#include "coord.h" +#include "event.h" +#include "navit_nls.h" + +#ifdef USE_HILDON +#include "hildon/hildon-defines.h" +#define KEY_ZOOM_IN HILDON_HARDKEY_INCREASE +#define KEY_ZOOM_OUT HILDON_HARDKEY_DECREASE +#define KEY_UP HILDON_HARDKEY_UP +#define KEY_DOWN HILDON_HARDKEY_DOWN +#define KEY_LEFT HILDON_HARDKEY_LEFT +#define KEY_RIGHT HILDON_HARDKEY_RIGHT +#else +#ifndef GDK_Book +#define GDK_Book XF86XK_Book +#endif +#ifndef GDK_Calendar +#define GDK_Calendar XF86XK_Calendar +#endif +#define KEY_ZOOM_IN GDK_Book +#define KEY_ZOOM_OUT GDK_Calendar +#define KEY_UP GDK_Up +#define KEY_DOWN GDK_Down +#define KEY_LEFT GDK_Left +#define KEY_RIGHT GDK_Right +#endif + +static gboolean +keypress(GtkWidget *widget, GdkEventKey *event, struct gui_priv *this) +{ + int w,h; + struct transformation *t; + #ifdef USE_HILDON + GtkToggleAction *action; + gboolean *fullscreen; + #endif /*HILDON*/ + struct point p; + if (event->type != GDK_KEY_PRESS) + return FALSE; + dbg(1,"keypress 0x%x\n", event->keyval); + transform_get_size(navit_get_trans(this->nav), &w, &h); + switch (event->keyval) { + case GDK_KP_Enter: + gtk_menu_shell_select_first(GTK_MENU_SHELL(this->menubar), TRUE); + break; + case KEY_UP: + p.x=w/2; + p.y=0; + navit_set_center_screen(this->nav, &p, 1); + break; + case KEY_DOWN: + p.x=w/2; + p.y=h; + navit_set_center_screen(this->nav, &p, 1); + break; + case KEY_LEFT: + p.x=0; + p.y=h/2; + navit_set_center_screen(this->nav, &p, 1); + break; + case KEY_RIGHT: + p.x=w; + p.y=h/2; + navit_set_center_screen(this->nav, &p, 1); + break; + case KEY_ZOOM_IN: + navit_zoom_in(this->nav, 2, NULL); + break; + case KEY_ZOOM_OUT: + navit_zoom_out(this->nav, 2, NULL); + break; + case 'a': + t=navit_get_trans(this->nav); + transform_set_yaw(t, (transform_get_yaw(t)+15)%360); + navit_draw(this->nav); + break; + case 'd': + t=navit_get_trans(this->nav); + transform_set_yaw(t, (transform_get_yaw(t)-15)%360); + navit_draw(this->nav); + break; + case 'w': + t=navit_get_trans(this->nav); + transform_set_pitch(t, (transform_get_pitch(t)+5)%360); + navit_draw(this->nav); + break; + case 'x': + t=navit_get_trans(this->nav); + transform_set_pitch(t, (transform_get_pitch(t)-5)%360); + navit_draw(this->nav); + break; + case 'r': + t=navit_get_trans(this->nav); + transform_set_distance(t, (transform_get_distance(t)-5)); + navit_draw(this->nav); + break; + case 'f': + t=navit_get_trans(this->nav); + transform_set_distance(t, (transform_get_distance(t)+5)); + navit_draw(this->nav); + break; + case 'z': + t=navit_get_trans(this->nav); + transform_set_hog(t, (transform_get_hog(t)+1)); + navit_draw(this->nav); + break; + case 'h': + t=navit_get_trans(this->nav); + transform_set_hog(t, (transform_get_hog(t)-1)); + navit_draw(this->nav); + break; + case 't': + { + struct coord *p; + struct pcoord pc; + t=navit_get_trans(this->nav); + p=transform_center(t); + pc.pro=projection_mg; + p->y+=50*cos(transform_get_yaw(t)*M_PI/180); + p->x+=50*sin(transform_get_yaw(t)*M_PI/180); + pc.x=p->x; + pc.y=p->y; + navit_set_center(this->nav, &pc, 1); + } + break; + case 'g': + { + struct coord *p; + struct pcoord pc; + t=navit_get_trans(this->nav); + p=transform_center(t); + pc.pro=projection_mg; + p->y-=50*cos(transform_get_yaw(t)*M_PI/180); + p->x-=50*sin(transform_get_yaw(t)*M_PI/180); + pc.x=p->x; + pc.y=p->y; + navit_set_center(this->nav, &pc, 1); + } + break; + #ifdef USE_HILDON + case HILDON_HARDKEY_FULLSCREEN: + action = GTK_TOGGLE_ACTION (gtk_action_group_get_action (this->base_group, "FullscreenAction")); + + if ( gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action))) + { + fullscreen = 0; + } else { + fullscreen = 1; + } + gtk_toggle_action_set_active (action, fullscreen); + break; + #endif /*HILDON*/ + default: + return FALSE; + } + return TRUE; +} + +static int +gui_gtk_set_graphics(struct gui_priv *this, struct graphics *gra) +{ + GtkWidget *graphics; + + graphics=graphics_get_data(gra, "gtk_widget"); + if (! graphics) + return 1; + GTK_WIDGET_SET_FLAGS (graphics, GTK_CAN_FOCUS); + gtk_widget_set_sensitive(graphics, TRUE); + g_signal_connect(G_OBJECT(graphics), "key-press-event", G_CALLBACK(keypress), this); + gtk_box_pack_end(GTK_BOX(this->vbox), graphics, TRUE, TRUE, 0); + gtk_widget_show_all(graphics); + gtk_widget_grab_focus(graphics); + + return 0; +} + +static void +gui_gtk_add_bookmark_do(struct gui_priv *gui) +{ + navit_add_bookmark(gui->nav, &gui->dialog_coord, gtk_entry_get_text(GTK_ENTRY(gui->dialog_entry))); + gtk_widget_destroy(gui->dialog_win); +} + +static int +gui_gtk_add_bookmark(struct gui_priv *gui, struct pcoord *c, char *description) +{ + GtkWidget *button_ok,*button_cancel,*label,*vbox,*hbox; + + gui->dialog_coord=*c; + gui->dialog_win=gtk_window_new(GTK_WINDOW_TOPLEVEL); + vbox=gtk_vbox_new(FALSE, 0); + gtk_container_add (GTK_CONTAINER (gui->dialog_win), vbox); + gtk_window_set_title(GTK_WINDOW(gui->dialog_win),_("Add Bookmark")); + gtk_window_set_wmclass (GTK_WINDOW (gui->dialog_win), "navit", "Navit"); + gtk_window_set_transient_for(GTK_WINDOW(gui->dialog_win), GTK_WINDOW(gui->win)); + gtk_window_set_modal(GTK_WINDOW(gui->dialog_win), TRUE); + label=gtk_label_new(_("Name")); + gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0); + gui->dialog_entry=gtk_entry_new(); + gtk_entry_set_text(GTK_ENTRY(gui->dialog_entry), description); + gtk_box_pack_start(GTK_BOX(vbox), gui->dialog_entry, TRUE, TRUE, 0); + hbox=gtk_hbox_new(FALSE, 0); + button_ok = gtk_button_new_from_stock (GTK_STOCK_OK); + gtk_box_pack_start(GTK_BOX(hbox), button_ok, TRUE, TRUE, 10); + button_cancel = gtk_button_new_from_stock (GTK_STOCK_CANCEL); + gtk_box_pack_start(GTK_BOX(hbox), button_cancel, TRUE, TRUE, 10); + gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 10); + gtk_widget_show_all(gui->dialog_win); + GTK_WIDGET_SET_FLAGS (button_ok, GTK_CAN_DEFAULT); + gtk_widget_grab_default(button_ok); + g_signal_connect_swapped (G_OBJECT (button_cancel), "clicked", G_CALLBACK (gtk_widget_destroy), G_OBJECT (gui->dialog_win)); + g_signal_connect_swapped (G_OBJECT (gui->dialog_entry), "activate", G_CALLBACK (gui_gtk_add_bookmark_do), gui); + + g_signal_connect_swapped(G_OBJECT (button_ok), "clicked", G_CALLBACK (gui_gtk_add_bookmark_do), gui); + + return 1; +} + +struct gui_methods gui_gtk_methods = { + NULL, + gui_gtk_popup_new, + gui_gtk_set_graphics, + NULL, + gui_gtk_datawindow_new, + gui_gtk_add_bookmark, +}; + +static gboolean +gui_gtk_delete(GtkWidget *widget, GdkEvent *event, struct navit *nav) +{ + /* FIXME remove attr_navit callback */ + navit_destroy(nav); + + return TRUE; +} + +static void +gui_gtk_toggle_init(struct gui_priv *this) +{ + struct attr attr; + GtkToggleAction *toggle_action; + + if (navit_get_attr(this->nav, attr_cursor, &attr, NULL)) { + toggle_action = GTK_TOGGLE_ACTION(gtk_action_group_get_action(this->base_group, "CursorAction")); + gtk_toggle_action_set_active(toggle_action, attr.u.num); + } else { + dbg(1, "Unable to locate CursorAction\n"); + } + if (navit_get_attr(this->nav, attr_orientation, &attr, NULL)) { + toggle_action = GTK_TOGGLE_ACTION(gtk_action_group_get_action(this->base_group, "OrientationAction")); + gtk_toggle_action_set_active(toggle_action, attr.u.num != -1); + } else { + dbg(0, "Unable to locate OrientationAction\n"); + } + if (navit_get_attr(this->nav, attr_tracking, &attr, NULL)) { + toggle_action = GTK_TOGGLE_ACTION(gtk_action_group_get_action(this->base_group, "TrackingAction")); + gtk_toggle_action_set_active(toggle_action, attr.u.num); + } else { + dbg(0, "Unable to locate TrackingAction\n"); + } +} + +struct action_cb_data { + struct gui_priv *gui; + struct attr attr; +}; + +static void +gui_gtk_action_activate(GtkAction *action, struct action_cb_data *data) +{ + if(data->attr.type == attr_destination) { + char * label; + g_object_get(G_OBJECT(action), "label", &label,NULL); + navit_set_destination(data->gui->nav, data->attr.u.pcoord, label, 1); + g_free(label); + } +} + +struct gui_menu_info { + guint merge_id; + GtkAction *action; +}; + +static void +gui_gtk_del_menu(struct gui_priv *this, struct gui_menu_info *meninfo) +{ + gtk_action_group_remove_action(this->dyn_group, meninfo->action); + gtk_ui_manager_remove_ui(this->ui_manager, meninfo->merge_id); +} + +static struct gui_menu_info +gui_gtk_add_menu(struct gui_priv *this, char *name, char *label, char *path, int submenu, struct action_cb_data *data) +{ + struct gui_menu_info meninfo; + GtkAction *action; + guint merge_id; + + action=gtk_action_new(name, label, NULL, NULL); + meninfo.action = action; + if (data) + g_signal_connect(action, "activate", G_CALLBACK(gui_gtk_action_activate), data); + gtk_action_group_add_action(this->dyn_group, action); + merge_id =gtk_ui_manager_new_merge_id(this->ui_manager); + meninfo.merge_id = merge_id; + gtk_ui_manager_add_ui(this->ui_manager, merge_id, path, name, name, submenu ? GTK_UI_MANAGER_MENU : GTK_UI_MANAGER_MENUITEM, FALSE); + + return meninfo; +} + +static void +gui_gtk_action_toggled(GtkToggleAction *action, struct action_cb_data *data) +{ + struct attr active; + active.type=attr_active; + active.u.num=gtk_toggle_action_get_active(action); + map_set_attr(data->attr.u.map, &active); + navit_draw(data->gui->nav); +} + +static void +gui_gtk_add_toggle_menu(struct gui_priv *this, char *name, char *label, char *path, struct action_cb_data *data, gboolean active) +{ + GtkToggleAction *toggle_action; + guint merge_id; + + toggle_action=gtk_toggle_action_new(name, label, NULL, NULL); + gtk_toggle_action_set_active(toggle_action, active); + g_signal_connect(GTK_ACTION(toggle_action), "toggled", G_CALLBACK(gui_gtk_action_toggled), data); + gtk_action_group_add_action(this->dyn_group, GTK_ACTION(toggle_action)); + merge_id=gtk_ui_manager_new_merge_id(this->ui_manager); + gtk_ui_manager_add_ui(this->ui_manager, merge_id, path, name, name, GTK_UI_MANAGER_MENUITEM, FALSE); +} + +static void +gui_gtk_action_changed(GtkRadioAction *action, GtkRadioAction *current, struct action_cb_data *data) +{ + if (action == current) { + navit_set_attr(data->gui->nav, &data->attr); + } +} + +static struct gui_menu_info +gui_gtk_add_radio_menu(struct gui_priv *this, char *name, char *label, char *path, struct action_cb_data *data, GSList **g) +{ + struct gui_menu_info meninfo; + GtkRadioAction *radio_action; + guint merge_id; + + radio_action=gtk_radio_action_new(name, label, NULL, NULL, 0); + meninfo.action = (GtkAction *)radio_action; + gtk_radio_action_set_group(radio_action, *g); + *g=gtk_radio_action_get_group(radio_action); + g_signal_connect(GTK_ACTION(radio_action), "changed", G_CALLBACK(gui_gtk_action_changed), data); + gtk_action_group_add_action(this->dyn_group, GTK_ACTION(radio_action)); + merge_id=gtk_ui_manager_new_merge_id(this->ui_manager); + meninfo.merge_id = merge_id; + gtk_ui_manager_add_ui(this->ui_manager, merge_id, path, name, name, GTK_UI_MANAGER_MENUITEM, FALSE); + + return meninfo; +} + +static void +gui_gtk_layouts_init(struct gui_priv *this) +{ + struct attr_iter *iter; + struct attr attr; + struct action_cb_data *data; + int count=0; + char *name; + + iter=navit_attr_iter_new(); + while(navit_get_attr(this->nav, attr_layout, &attr, iter)) { + name=g_strdup_printf("Layout %d", count++); + data=g_new(struct action_cb_data, 1); + data->gui=this; + data->attr.type=attr_layout; + data->attr.u.layout=attr.u.layout; + gui_gtk_add_radio_menu(this, name, attr.u.layout->name, "/ui/MenuBar/Map/Layout/LayoutMenuAdditions", data, &this->layout_group); + g_free(name); + } + navit_attr_iter_destroy(iter); +} + +static void +gui_gtk_projections_init(struct gui_priv *this) +{ + struct action_cb_data *data; + + data=g_new(struct action_cb_data, 1); + data->gui=this; + data->attr.type=attr_projection; + data->attr.u.projection=projection_mg; + gui_gtk_add_radio_menu(this, "Projection mg", "Map & Guide", "/ui/MenuBar/Map/Projection/ProjectionMenuAdditions", data, &this->projection_group); + + data=g_new(struct action_cb_data, 1); + data->gui=this; + data->attr.type=attr_projection; + data->attr.u.projection=projection_garmin; + gui_gtk_add_radio_menu(this, "Projection garmin", "Garmin", "/ui/MenuBar/Map/Projection/ProjectionMenuAdditions", data, &this->projection_group); +} + +static void +gui_gtk_vehicles_update(struct gui_priv *this) +{ + struct attr_iter *iter; + struct attr attr,vattr; + struct action_cb_data *data; + int count=0; + char *name; + GList *curr; + struct gui_menu_info *meninfo; + dbg(1,"enter\n"); + + curr = g_list_first(this->vehicle_menuitems); + + while (curr) { + gui_gtk_del_menu(this, (struct gui_menu_info *)curr->data); + g_free((struct gui_menu_info *)curr->data); + curr = g_list_next(curr); + }; + + g_list_free(this->vehicle_menuitems); + this->vehicle_menuitems = NULL; + + iter=navit_attr_iter_new(); + while(navit_get_attr(this->nav, attr_vehicle, &attr, iter)) { + vehicle_get_attr(attr.u.vehicle, attr_name, &vattr, NULL); + name=g_strdup_printf("Vehicle %d", count++); + data=g_new(struct action_cb_data, 1); + data->gui=this; + data->attr.type=attr_vehicle; + data->attr.u.vehicle=attr.u.vehicle; + meninfo = g_new(struct gui_menu_info, 1); + *meninfo = gui_gtk_add_radio_menu(this, name, vattr.u.str, "/ui/MenuBar/Map/Vehicle/VehicleMenuAdditions", data, &this->vehicle_group); + this->vehicle_menuitems = g_list_prepend(this->vehicle_menuitems, meninfo); + g_free(name); + } + navit_attr_iter_destroy(iter); +} + +static void +gui_gtk_vehicles_init(struct gui_priv *this) +{ + navit_add_callback(this->nav, callback_new_attr_1(callback_cast(gui_gtk_vehicles_update), attr_vehicle, this)); + gui_gtk_vehicles_update(this); +} + +static void +gui_gtk_maps_init(struct gui_priv *this) +{ + struct attr_iter *iter; + struct attr attr,active,type,data; + struct action_cb_data *cb_data; + int count=0; + char *name, *label; + + iter=navit_attr_iter_new(); + while(navit_get_attr(this->nav, attr_map, &attr, iter)) { + name=g_strdup_printf("Map %d", count++); + if (! map_get_attr(attr.u.map, attr_type, &type, NULL)) + type.u.str=""; + if (! map_get_attr(attr.u.map, attr_data, &data, NULL)) + data.u.str=""; + label=g_strdup_printf("%s:%s", type.u.str, data.u.str); + cb_data=g_new(struct action_cb_data, 1); + cb_data->gui=this; + cb_data->attr.type=attr_map; + cb_data->attr.u.map=attr.u.map; + if (! map_get_attr(attr.u.map, attr_active, &active, NULL)) + active.u.num=1; + gui_gtk_add_toggle_menu(this, name, label, "/ui/MenuBar/Map/MapMenuAdditions", cb_data, active.u.num); + g_free(name); + g_free(label); + } + navit_attr_iter_destroy(iter); + +} + +static void +gui_gtk_destinations_update(struct gui_priv *this) +{ + GList *curr; + struct attr attr; + struct action_cb_data *data; + struct map_rect *mr=NULL; + struct item *item; + struct gui_menu_info *meninfo; + struct coord c; + int count=0; + char *name, *label; + + curr = g_list_first(this->dest_menuitems); + + while (curr) { + gui_gtk_del_menu(this, (struct gui_menu_info *)curr->data); + g_free((struct gui_menu_info *)curr->data); + curr = g_list_next(curr); + }; + + g_list_free(this->dest_menuitems); + this->dest_menuitems = NULL; + + if(navit_get_attr(this->nav, attr_former_destination_map, &attr, NULL) && attr.u.map && (mr=map_rect_new(attr.u.map, NULL))) { + while ((item=map_rect_get_item(mr))) { + if (item->type != type_former_destination) continue; + name=g_strdup_printf("Destination %d", count++); + item_attr_get(item, attr_label, &attr); + label=attr.u.str; + item_coord_get(item, &c, 1); + data=g_new(struct action_cb_data, 1); + data->gui=this; + data->attr.type=attr_destination; + data->attr.u.pcoord=g_new(struct pcoord, 1); + data->attr.u.pcoord->pro=projection_mg; + data->attr.u.pcoord->x=c.x; + data->attr.u.pcoord->y=c.y; + + meninfo = g_new(struct gui_menu_info, 1); + *meninfo = gui_gtk_add_menu(this, name, label, "/ui/MenuBar/Route/FormerDestinations/FormerDestinationMenuAdditions",0,data); + this->dest_menuitems = g_list_prepend(this->dest_menuitems, meninfo); + g_free(name); + } + map_rect_destroy(mr); + } +} + +static void +gui_gtk_destinations_init(struct gui_priv *this) +{ + navit_add_callback(this->nav, callback_new_attr_1(callback_cast(gui_gtk_destinations_update), attr_destination, this)); + gui_gtk_destinations_update(this); +} + +static void +gui_gtk_bookmarks_update(struct gui_priv *this) +{ + GList *curr; + struct attr attr; + struct action_cb_data *data; + struct map_rect *mr=NULL; + struct gui_menu_info *meninfo; + struct item *item; + struct coord c; + int count=0; + char *parent, *name, *label, *label_full, *menu_label, *tmp_parent, *s; + GHashTable *hash; + + curr = g_list_first(this->bookmarks_menuitems); + + while (curr) { + gui_gtk_del_menu(this, (struct gui_menu_info *)curr->data); + g_free((struct gui_menu_info *)curr->data); + curr = g_list_next(curr); + }; + + g_list_free(this->bookmarks_menuitems); + this->bookmarks_menuitems = NULL; + + if(navit_get_attr(this->nav, attr_bookmark_map, &attr, NULL) && attr.u.map && (mr=map_rect_new(attr.u.map, NULL))) { + hash=g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); + while ((item=map_rect_get_item(mr))) { + if (item->type != type_bookmark) continue; + item_attr_get(item, attr_label, &attr); + label_full=attr.u.str; + item_coord_get(item, &c, 1); + menu_label=g_malloc(strlen(label_full)+1); + label=label_full; + parent=g_strdup("/ui/MenuBar/Route/Bookmarks/BookmarkMenuAdditions"); + while ((s=strchr(label, '/'))) { + strcpy(menu_label, label_full); + menu_label[s-label_full]='\0'; + if ((tmp_parent=g_hash_table_lookup(hash, menu_label))) { + tmp_parent=g_strdup(tmp_parent); + } else { + name=g_strdup_printf("Bookmark %d", count++); + meninfo = g_new(struct gui_menu_info, 1); + *meninfo = gui_gtk_add_menu(this, name, menu_label+(label-label_full),parent,1,NULL); + this->bookmarks_menuitems = g_list_prepend(this->bookmarks_menuitems, meninfo); + tmp_parent=g_strdup_printf("%s/%s", parent, name); + g_hash_table_insert(hash, g_strdup(menu_label), g_strdup(tmp_parent)); + g_free(name); + } + g_free(parent); + parent=tmp_parent; + label=s+1; + } + g_free(menu_label); + data=g_new(struct action_cb_data, 1); + data->gui=this; + data->attr.type=attr_destination; + data->attr.u.pcoord=g_new(struct pcoord, 1); + data->attr.u.pcoord->pro=projection_mg; + data->attr.u.pcoord->x=c.x; + data->attr.u.pcoord->y=c.y; + name=g_strdup_printf("Bookmark %d", count++); + meninfo = g_new(struct gui_menu_info, 1); + *meninfo = gui_gtk_add_menu(this, name, label, parent,0,data); + this->bookmarks_menuitems = g_list_prepend(this->bookmarks_menuitems, meninfo); + g_free(name); + g_free(parent); + } + g_hash_table_destroy(hash); + } +} + +static void +gui_gtk_bookmarks_init(struct gui_priv *this) +{ + navit_add_callback(this->nav, callback_new_attr_1(callback_cast(gui_gtk_bookmarks_update), attr_bookmark_map, this)); + gui_gtk_bookmarks_update(this); +} + +static void +gui_gtk_init(struct gui_priv *this, struct navit *nav) +{ + + + gui_gtk_toggle_init(this); + gui_gtk_layouts_init(this); + gui_gtk_projections_init(this); + gui_gtk_vehicles_init(this); + gui_gtk_maps_init(this); + gui_gtk_destinations_init(this); + gui_gtk_bookmarks_init(this); +} + +static struct gui_priv * +gui_gtk_new(struct navit *nav, struct gui_methods *meth, struct attr **attrs) +{ + struct gui_priv *this; + int w=792, h=547; + char *cp = getenv("NAVIT_XID"); + unsigned xid = 0; + struct attr *attr; + GtkWidget *widget; + int fullscreen = 0; + + if (! event_request_system("glib","gui_gtk_new")) + return NULL; + + if (cp) { + xid = strtol(cp, NULL, 0); + } + + this=g_new0(struct gui_priv, 1); + this->nav=nav; + + attr = attr_search(attrs, NULL, attr_menubar); + if (attr) { + this->menubar_enable=attr->u.num; + } else { + this->menubar_enable=1; + } + attr=attr_search(attrs, NULL, attr_toolbar); + if (attr) { + this->toolbar_enable=attr->u.num; + } else { + this->toolbar_enable=1; + } + attr=attr_search(attrs, NULL, attr_statusbar); + if (attr) { + this->statusbar_enable=attr->u.num; + } else { + this->statusbar_enable=1; + } + + *meth=gui_gtk_methods; + + if (!xid) + this->win = gtk_window_new(GTK_WINDOW_TOPLEVEL); + else + this->win = gtk_plug_new(xid); + + + g_signal_connect(G_OBJECT(this->win), "delete-event", G_CALLBACK(gui_gtk_delete), nav); + this->vbox = gtk_vbox_new(FALSE, 0); + gtk_window_set_default_size(GTK_WINDOW(this->win), w, h); + gtk_window_set_title(GTK_WINDOW(this->win), "Navit"); + gtk_window_set_wmclass (GTK_WINDOW (this->win), "navit", "Navit"); + gtk_widget_realize(this->win); + gui_gtk_ui_init(this); + if (this->menubar_enable) { + widget=gtk_ui_manager_get_widget(this->ui_manager, "/ui/MenuBar"); + GTK_WIDGET_UNSET_FLAGS (widget, GTK_CAN_FOCUS); + gtk_box_pack_start (GTK_BOX(this->vbox), widget, FALSE, FALSE, 0); + gtk_widget_show (widget); + this->menubar=widget; + } + if (this->toolbar_enable) { + widget=gtk_ui_manager_get_widget(this->ui_manager, "/ui/ToolBar"); + GTK_WIDGET_UNSET_FLAGS (widget, GTK_CAN_FOCUS); + gtk_box_pack_start (GTK_BOX(this->vbox), widget, FALSE, FALSE, 0); + gtk_widget_show (widget); + } + if (this->statusbar_enable) { + this->statusbar=gui_gtk_statusbar_new(this); + } + gtk_container_add(GTK_CONTAINER(this->win), this->vbox); + gtk_widget_show_all(this->win); + + + navit_add_callback(nav, callback_new_attr_1(callback_cast(gui_gtk_init), attr_navit, this)); + + if ((attr=attr_search(attrs, NULL, attr_fullscreen))) + fullscreen=attr->u.num; + + if (fullscreen) { + GtkToggleAction *action; + action = GTK_TOGGLE_ACTION (gtk_action_group_get_action (this->base_group, "FullscreenAction")); + gtk_toggle_action_set_active (action, fullscreen); + } + + return this; +} + +static int gtk_argc; +static char **gtk_argv={NULL}; + +void +plugin_init(void) +{ + gtk_init(>k_argc, >k_argv); + gtk_set_locale(); + + + plugin_register_gui_type("gtk", gui_gtk_new); +} |