--- trunk/src/main.c 2008/12/10 00:00:05 2 +++ trunk/src/main.c 2009/04/01 12:47:35 156 @@ -1,4 +1,6 @@ /* + * Copyright (C) 2008 Till Harbaum . + * * This file is part of OSM2Go. * * OSM2Go is free software: you can redistribute it and/or modify @@ -19,12 +21,15 @@ #include #include +#include #include "appdata.h" +#include "banner.h" /* disable/enable main screen control dependant on presence of open project */ -static void main_project_loaded(appdata_t *appdata) { - gboolean loaded = (appdata->project != NULL); +static void main_ui_enable(appdata_t *appdata) { + gboolean project_valid = (appdata->project != NULL); + gboolean osm_valid = (appdata->osm != NULL); /* cancel any action in progress */ if(GTK_WIDGET_FLAGS(appdata->iconbar->cancel) & GTK_SENSITIVE) @@ -33,7 +38,7 @@ /* ---- set project name as window title ----- */ #ifndef USE_HILDON char *str = NULL; - if(loaded) + if(project_valid) str = g_strdup_printf("OSM2Go - %s", appdata->project->name); else str = g_strdup_printf("OSM2Go"); @@ -41,92 +46,82 @@ gtk_window_set_title(GTK_WINDOW(appdata->window), str); g_free(str); #else - if(loaded) + if(project_valid) gtk_window_set_title(GTK_WINDOW(appdata->window), appdata->project->name); else gtk_window_set_title(GTK_WINDOW(appdata->window), ""); #endif if(appdata->iconbar && appdata->iconbar->toolbar) - gtk_widget_set_sensitive(appdata->iconbar->toolbar, loaded); + gtk_widget_set_sensitive(appdata->iconbar->toolbar, osm_valid); /* disable all menu entries related to map */ - gtk_widget_set_sensitive(appdata->track.menu_track, loaded); - gtk_widget_set_sensitive(appdata->menu_view, loaded); - gtk_widget_set_sensitive(appdata->menu_osm, loaded); - gtk_widget_set_sensitive(appdata->menu_wms, loaded); - gtk_widget_set_sensitive(appdata->menu_map, loaded); - gtk_widget_set_sensitive(appdata->menu_item_project_close, loaded); + gtk_widget_set_sensitive(appdata->menu_osm, project_valid); + gtk_widget_set_sensitive(appdata->menu_item_osm_upload, osm_valid); + if(appdata->menu_item_osm_undo) + gtk_widget_set_sensitive(appdata->menu_item_osm_undo, osm_valid); + gtk_widget_set_sensitive(appdata->menu_item_osm_save_changes, osm_valid); + gtk_widget_set_sensitive(appdata->menu_item_osm_undo_changes, osm_valid); + gtk_widget_set_sensitive(appdata->track.menu_track, osm_valid); + gtk_widget_set_sensitive(appdata->menu_view, osm_valid); + gtk_widget_set_sensitive(appdata->menu_wms, osm_valid); + gtk_widget_set_sensitive(appdata->menu_map, osm_valid); + gtk_widget_set_sensitive(appdata->menu_item_project_close, project_valid); - if(!loaded) - statusbar_set(appdata, _("Plase load or create a project"), FALSE); + if(!project_valid) + statusbar_set(appdata, _("Please load or create a project"), FALSE); } /******************** begin of menu *********************/ -#if 0 // simplify menu -static struct { - enum { MENU_END, MENU_ITEM, MENU_SUB, MENU_SUB_END, MENU_SEP } type; - - char *title; - GCallback c_handler; -} menu[] = { - { MENU_SUB, "OSM", NULL }, - - { MENU_END, NULL, NULL }, -}; -#endif - static void -cb_menu_project_open(GtkWidget *window, gpointer data) { +cb_menu_project_open(GtkMenuItem *item, gpointer data) { appdata_t *appdata = (appdata_t*)data; project_load(appdata, NULL); - main_project_loaded(appdata); + main_ui_enable(appdata); } static void -cb_menu_project_close(GtkWidget *window, gpointer data) { +cb_menu_project_close(GtkMenuItem *item, gpointer data) { appdata_t *appdata = (appdata_t*)data; project_close(appdata); - main_project_loaded(appdata); + main_ui_enable(appdata); } static void -cb_menu_about(GtkWidget *window, gpointer data) { - GtkAboutDialog *about = GTK_ABOUT_DIALOG(gtk_about_dialog_new()); - - gtk_about_dialog_set_name(about, "OSM2Go"); - gtk_about_dialog_set_version(about, VERSION); - gtk_about_dialog_set_copyright(about, _("Copyright 2008")); +cb_menu_about(GtkMenuItem *item, gpointer data) { + appdata_t *appdata = (appdata_t*)data; const gchar *authors[] = { "Till Harbaum ", - "Andrew Chadwick", + "Andrew Chadwick ", NULL }; - gtk_about_dialog_set_authors(about, authors); - - gtk_about_dialog_set_website(about, - _("http://www.harbaum.org/till/maemo")); - - gtk_about_dialog_set_comments(about, - _("Mobile OSM Editor")); + const gchar *artists[] = { + "Andrew Zhilin ", + NULL }; - gtk_widget_show_all(GTK_WIDGET(about)); - gtk_dialog_run(GTK_DIALOG(about)); - gtk_widget_destroy(GTK_WIDGET(about)); + gtk_show_about_dialog(GTK_WINDOW(appdata->window), + "name", "OSM2Go", + "version", VERSION, + "copyright", _("Copyright 2008-2009"), + "authors", authors, + "artists", artists, + "website", _("http://www.harbaum.org/till/maemo"), + "comments", _("Mobile OSM Editor"), + NULL); } void on_window_destroy (GtkWidget *widget, gpointer data); static void -cb_menu_quit(GtkWidget *window, gpointer data) { +cb_menu_quit(GtkMenuItem *item, gpointer data) { appdata_t *appdata = (appdata_t*)data; gtk_widget_destroy(GTK_WIDGET(appdata->window)); } static void -cb_menu_upload(GtkWidget *window, gpointer data) { +cb_menu_upload(GtkMenuItem *item, gpointer data) { appdata_t *appdata = (appdata_t*)data; if(!appdata->osm || !appdata->project) return; @@ -134,37 +129,46 @@ } static void -cb_menu_download(GtkWidget *window, gpointer data) { +cb_menu_download(GtkMenuItem *item, gpointer data) { appdata_t *appdata = (appdata_t*)data; - if(!appdata->osm || !appdata->project) return; + if(!appdata->project) return; - /* redraw the entire map by destroying all map items and redrawing them */ - diff_save(appdata->project, appdata->osm); - map_clear(appdata, MAP_LAYER_OBJECTS_ONLY); - osm_free(&appdata->icon, appdata->osm); + /* if we have valid osm data loaded: save state first */ + if(appdata->osm) { + /* redraw the entire map by destroying all map items and redrawing them */ + diff_save(appdata->project, appdata->osm); + map_clear(appdata, MAP_LAYER_OBJECTS_ONLY); + osm_free(&appdata->icon, appdata->osm); + + appdata->osm = NULL; + } // download - osm_download(GTK_WIDGET(appdata->window), appdata->project); + if(osm_download(GTK_WIDGET(appdata->window), appdata->project)) { + banner_busy_start(appdata, 1, "Redrawing..."); + appdata->osm = osm_parse(appdata->project->osm); + diff_restore(appdata, appdata->project, appdata->osm); + map_paint(appdata); + banner_busy_stop(appdata); //"Redrawing..." + } - appdata->osm = osm_parse(appdata->project->osm); - diff_restore(appdata, appdata->project, appdata->osm); - map_paint(appdata); + main_ui_enable(appdata); } static void -cb_menu_wms_import(GtkWidget *window, gpointer data) { +cb_menu_wms_import(GtkMenuItem *item, gpointer data) { appdata_t *appdata = (appdata_t*)data; wms_import(appdata); } static void -cb_menu_wms_clear(GtkWidget *window, gpointer data) { +cb_menu_wms_clear(GtkMenuItem *item, gpointer data) { appdata_t *appdata = (appdata_t*)data; wms_remove(appdata); } static void -cb_menu_wms_adjust(GtkWidget *window, gpointer data) { +cb_menu_wms_adjust(GtkMenuItem *item, gpointer data) { appdata_t *appdata = (appdata_t*)data; map_action_set(appdata, MAP_ACTION_BG_ADJUST); } @@ -172,25 +176,26 @@ /* ----------- hide objects for performance reasons ----------- */ static void -cb_menu_map_hide_sel(GtkWidget *window, gpointer data) { +cb_menu_map_hide_sel(GtkMenuItem *item, gpointer data) { appdata_t *appdata = (appdata_t*)data; map_hide_selected(appdata); } static void -cb_menu_map_show_all(GtkWidget *window, gpointer data) { +cb_menu_map_show_all(GtkMenuItem *item, gpointer data) { appdata_t *appdata = (appdata_t*)data; map_show_all(appdata); } -/* ----------------------------------------------- ----------- */ +/* ---------------------------------------------------------- */ #if 1 // mainly for testing static void -cb_menu_redraw(GtkWidget *window, gpointer data) { +cb_menu_redraw(GtkMenuItem *item, gpointer data) { appdata_t *appdata = (appdata_t*)data; /* redraw the entire map by destroying all map items and redrawing them */ + banner_busy_start(appdata, 1, "Redrawing..."); track_save(appdata->project, appdata->track.track); diff_save(appdata->project, appdata->osm); map_clear(appdata, MAP_LAYER_ALL); @@ -205,39 +210,94 @@ map_track_draw(appdata->map, appdata->track.track); wms_load(appdata); + banner_busy_stop(appdata); //"Redrawing..." } #endif static void -cb_menu_style(GtkWidget *window, gpointer data) { +cb_menu_style(GtkMenuItem *item, gpointer data) { appdata_t *appdata = (appdata_t*)data; style_select(GTK_WIDGET(appdata->window), appdata); } static void -cb_menu_save_changes(GtkWidget *window, gpointer data) { +cb_menu_map_no_icons(GtkCheckMenuItem *item, gpointer data) { + appdata_t *appdata = (appdata_t*)data; + + banner_busy_start(appdata, 1, "Redrawing..."); + map_clear(appdata, MAP_LAYER_OBJECTS_ONLY); + appdata->settings->no_icons = gtk_check_menu_item_get_active(item); + map_paint(appdata); + banner_busy_stop(appdata); //"Redrawing..." +} + +static void +cb_menu_map_no_antialias(GtkCheckMenuItem *item, gpointer data) { + appdata_t *appdata = (appdata_t*)data; + + banner_busy_start(appdata, 1, "Redrawing..."); + map_clear(appdata, MAP_LAYER_OBJECTS_ONLY); + appdata->settings->no_antialias = gtk_check_menu_item_get_active(item); + map_paint(appdata); + banner_busy_stop(appdata); //"Redrawing..." +} + +static void +cb_menu_undo(GtkMenuItem *item, gpointer data) { + appdata_t *appdata = (appdata_t*)data; + + undo(appdata); + + // the banner will be displayed from within undo with more details +} + +static void +cb_menu_save_changes(GtkMenuItem *item, gpointer data) { appdata_t *appdata = (appdata_t*)data; diff_save(appdata->project, appdata->osm); - statusbar_set(appdata, _("Saved all changes in projects diff file"), FALSE); + banner_show_info(appdata, _("Saved local changes")); } +static void +cb_menu_undo_changes(GtkMenuItem *item, gpointer data) { + appdata_t *appdata = (appdata_t*)data; + + if(!yes_no_f(GTK_WIDGET(appdata->window), NULL, 0, 0, + _("Discard local changes?"), + _("Throw away all the changes you've not " + "uploaded yet? This can't be undone."))) + return; + + banner_busy_start(appdata, 1, _("Redrawing...")); + map_clear(appdata, MAP_LAYER_OBJECTS_ONLY); + osm_free(&appdata->icon, appdata->osm); + diff_remove(appdata->project); + appdata->osm = osm_parse(appdata->project->osm); + map_paint(appdata); + banner_busy_stop(appdata); //"Redrawing..." + + banner_show_info(appdata, _("Discarded local changes")); +} -#ifdef USE_HILDON static void -cb_menu_fullscreen(GtkWidget *widget, gpointer data) { +cb_menu_osm_relations(GtkMenuItem *item, gpointer data) { + relation_list((appdata_t*)data); +} + +static void +cb_menu_fullscreen(GtkCheckMenuItem *item, gpointer data) { appdata_t *appdata = (appdata_t *)data; - if(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) + if(gtk_check_menu_item_get_active(item)) gtk_window_fullscreen(GTK_WINDOW(appdata->window)); else gtk_window_unfullscreen(GTK_WINDOW(appdata->window)); } -#endif static void -cb_menu_zoomin(GtkWidget *widget, appdata_t *appdata) { +cb_menu_zoomin(GtkMenuItem *item, appdata_t *appdata) { if(!appdata || !appdata->map) return; map_set_zoom(appdata->map, appdata->map->state->zoom*ZOOM_FACTOR_MENU, TRUE); @@ -245,7 +305,7 @@ } static void -cb_menu_zoomout(GtkWidget *widget, appdata_t *appdata) { +cb_menu_zoomout(GtkMenuItem *item, appdata_t *appdata) { if(!appdata || !appdata->map) return; map_set_zoom(appdata->map, appdata->map->state->zoom/ZOOM_FACTOR_MENU, TRUE); @@ -253,7 +313,8 @@ } static void -cb_menu_track_import(GtkWidget *window, appdata_t *appdata) { +cb_menu_track_import(GtkMenuItem *item, appdata_t *appdata) { + g_assert(appdata->settings); /* open a file selector */ GtkWidget *dialog; @@ -270,30 +331,35 @@ NULL); #endif - /* use path if one is present */ - if(appdata->track.import_path) - gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), - appdata->track.import_path); - + if(appdata->settings->track_path) { + if(!g_file_test(appdata->settings->track_path, G_FILE_TEST_EXISTS)) { + char *last_sep = strrchr(appdata->settings->track_path, '/'); + if(last_sep) { + *last_sep = 0; // seperate path from file + + /* the user just created a new document */ + gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), + appdata->settings->track_path); + gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), + last_sep+1); + + /* restore full filename */ + *last_sep = '/'; + } + } else + gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), + appdata->settings->track_path); + } + gtk_widget_show_all (GTK_WIDGET(dialog)); if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_FM_OK) { char *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); /* load a track */ - track_do(appdata, TRACK_IMPORT, filename); + appdata->track.track = track_import(appdata, filename); if(appdata->track.track) { - - /* save path if gpx was successfully loaded */ - char *r = strrchr(filename, '/'); - - /* there is a delimiter, use everything left of it as path */ - if(r) { - *r = 0; - if(appdata->track.import_path) g_free(appdata->track.import_path); - appdata->track.import_path = g_strdup(filename); - /* restore path ... just in case ... */ - *r = '/'; - } + if(appdata->settings->track_path) g_free(appdata->settings->track_path); + appdata->settings->track_path = g_strdup(filename); } g_free (filename); } @@ -302,210 +368,475 @@ } static void -cb_menu_track_gps(GtkWidget *window, gpointer data) { +cb_menu_track_enable_gps(GtkMenuItem *item, gpointer data) { appdata_t *appdata = (appdata_t*)data; if(gtk_check_menu_item_get_active( - GTK_CHECK_MENU_ITEM(appdata->track.menu_item_gps))) { - track_do(appdata, TRACK_GPS, NULL); - } else { - track_do(appdata, TRACK_NONE, NULL); - } + GTK_CHECK_MENU_ITEM(appdata->track.menu_item_enable_gps))) { + track_enable_gps(appdata, TRUE); + } else + track_enable_gps(appdata, FALSE); } + static void -cb_menu_track_export(GtkWidget *window, gpointer data) { +cb_menu_track_follow_gps(GtkMenuItem *item, gpointer data) { appdata_t *appdata = (appdata_t*)data; - messagef(GTK_WIDGET(appdata->window), _("NIY"), - _("Track export is not yet supported.")); + + if(gtk_check_menu_item_get_active( + GTK_CHECK_MENU_ITEM(appdata->track.menu_item_follow_gps))) { + appdata->settings->follow_gps = TRUE; + } else + appdata->settings->follow_gps = FALSE; } + static void -cb_menu_track_clear(GtkWidget *window, gpointer data) { +cb_menu_track_export(GtkMenuItem *item, appdata_t *appdata) { + g_assert(appdata->settings); + + /* open a file selector */ + GtkWidget *dialog; + +#ifdef USE_HILDON + dialog = hildon_file_chooser_dialog_new(GTK_WINDOW(appdata->window), + GTK_FILE_CHOOSER_ACTION_SAVE); +#else + dialog = gtk_file_chooser_dialog_new(_("Export track file"), + GTK_WINDOW(appdata->window), + GTK_FILE_CHOOSER_ACTION_SAVE, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, + NULL); +#endif + + printf("set filename <%s>\n", appdata->settings->track_path); + + if(appdata->settings->track_path) { + if(!g_file_test(appdata->settings->track_path, G_FILE_TEST_EXISTS)) { + char *last_sep = strrchr(appdata->settings->track_path, '/'); + if(last_sep) { + *last_sep = 0; // seperate path from file + + /* the user just created a new document */ + gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), + appdata->settings->track_path); + gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), + last_sep+1); + + /* restore full filename */ + *last_sep = '/'; + } + } else + gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), + appdata->settings->track_path); + } + + if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_FM_OK) { + gchar *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); + if(filename) { + printf("export to %s\n", filename); + + if(!g_file_test(filename, G_FILE_TEST_EXISTS) || + yes_no_f(dialog, appdata, MISC_AGAIN_ID_EXPORT_OVERWRITE, + MISC_AGAIN_FLAG_DONT_SAVE_NO, + "Overwrite existing file", + "The file already exists. " + "Do you really want to replace it?")) { + if(appdata->settings->track_path) + g_free(appdata->settings->track_path); + appdata->settings->track_path = g_strdup(filename); + + track_export(appdata, filename); + } + } + } + + gtk_widget_destroy (dialog); +} + + +static void +cb_menu_track_clear(GtkMenuItem *item, gpointer data) { appdata_t *appdata = (appdata_t*)data; - track_do(appdata, TRACK_NONE, NULL); + track_clear(appdata, appdata->track.track); + appdata->track.track = NULL; +} + + + + +/* + * Platform-specific UI tweaks. + */ + + +#ifndef USE_HILDON +#ifdef PORTRAIT + +// Portrait mode, for openmoko-like systems +#define uispecific_main_menu_new gtk_menu_new + +#else + +// Regular desktop builds +#define uispecific_main_menu_new gtk_menu_bar_new +#define UISPECIFIC_MAIN_MENU_IS_MENU_BAR +#define UISPECIFIC_MENU_HAS_ICONS +#define UISPECIFIC_MENU_HAS_ACCELS + +#endif //PORTRAIT +#else//USE_HILDON + +// Maemo/Hildon builds +#define uispecific_main_menu_new gtk_menu_new + +#endif + + + +// Half-arsed slapdash common menu item constructor. Let's use GtkBuilder +// instead so we have some flexibility. + +static GtkWidget * +menu_append_new_item(appdata_t *appdata, + GtkWidget *menu_shell, + GtkSignalFunc activate_cb, + char *label, + const gchar *icon_name, // stock id or name for icon_load + // overridden by label, accels, icon_name + const gchar *accel_path, + guint accel_key, // from gdk/gdkkeysyms.h + GdkModifierType accel_mods, // e.g. GDK_CONTROL_MASK + gboolean enabled, + gboolean is_check, gboolean check_status) +{ + GtkWidget *item = NULL; + GtkWidget *image = NULL; + + gboolean stock_item_known = FALSE; + GtkStockItem stock_item; + if (icon_name != NULL) { + stock_item_known = gtk_stock_lookup(icon_name, &stock_item); + } + + // Icons +#ifndef UISPECIFIC_MENU_HAS_ICONS + item = is_check ? gtk_check_menu_item_new_with_mnemonic (label) + : gtk_menu_item_new_with_mnemonic (label); +#else + if (is_check) { + item = gtk_check_menu_item_new_with_mnemonic (label); + } + else if (!stock_item_known) { + GdkPixbuf *pbuf = icon_load(&appdata->icon, icon_name); + if (pbuf) { + image = gtk_image_new_from_pixbuf(pbuf); + } + if (image) { + item = gtk_image_menu_item_new_with_mnemonic(label); + gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), image); + } + else { + item = gtk_menu_item_new_with_mnemonic(label); + } + } + else { + item = gtk_image_menu_item_new_with_mnemonic(label); + image = gtk_image_new_from_stock(icon_name, GTK_ICON_SIZE_MENU); + gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), image); + } +#endif + +#ifdef UISPECIFIC_MENU_HAS_ACCELS + // Accelerators + // Default + if (accel_path != NULL) { + gtk_menu_item_set_accel_path(GTK_MENU_ITEM(item), accel_path); + if (accel_key != 0) { + gtk_accel_map_add_entry( accel_path, accel_key, accel_mods ); + } + else if (stock_item_known) { + gtk_accel_map_add_entry( accel_path, stock_item.keyval, + stock_item.modifier ); + } + } +#endif + + gtk_menu_shell_append(GTK_MENU_SHELL(menu_shell), GTK_WIDGET(item)); + gtk_widget_set_sensitive(GTK_WIDGET(item), enabled); + if (is_check) + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), check_status); + + g_signal_connect(item, "activate", GTK_SIGNAL_FUNC(activate_cb), + appdata); + return item; } + void menu_create(appdata_t *appdata) { GtkWidget *menu, *item, *submenu; - menu = gtk_menu_new(); + GtkWidget *about_quit_items_menu; + if (g_module_supported()) { + printf("*** can use GModule: consider using GtkUIManager / GtkBuilder\n"); + } + + menu = uispecific_main_menu_new(); + about_quit_items_menu = menu; /* -------------------- Project submenu -------------------- */ - item = gtk_menu_item_new_with_label( _("Project") ); - gtk_menu_append(GTK_MENU_SHELL(menu), item); + GtkAccelGroup *accel_grp = gtk_accel_group_new(); + item = gtk_menu_item_new_with_mnemonic( _("_Project") ); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); submenu = gtk_menu_new(); + gtk_menu_set_accel_group(GTK_MENU(submenu), accel_grp); gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu); +#ifdef UISPECIFIC_MAIN_MENU_IS_MENU_BAR + about_quit_items_menu = submenu; +#endif - item = gtk_menu_item_new_with_label( _("Open...") ); - gtk_menu_append(GTK_MENU_SHELL(submenu), item); - g_signal_connect(item, "activate", GTK_SIGNAL_FUNC(cb_menu_project_open), - appdata); - - appdata->menu_item_project_close = item = - gtk_menu_item_new_with_label( _("Close") ); - gtk_menu_append(GTK_MENU_SHELL(submenu), item); - g_signal_connect(item, "activate", GTK_SIGNAL_FUNC(cb_menu_project_close), - appdata); + menu_append_new_item( + appdata, submenu, GTK_SIGNAL_FUNC(cb_menu_project_open), _("_Open..."), + GTK_STOCK_OPEN, "/Project/Open", + 0, 0, TRUE, FALSE, FALSE + ); + + appdata->menu_item_project_close = menu_append_new_item( + appdata, submenu, GTK_SIGNAL_FUNC(cb_menu_project_close), _("_Close"), + GTK_STOCK_CLOSE, "/Project/Close", + 0, 0, TRUE, FALSE, FALSE + ); /* --------------- view menu ------------------- */ - gtk_menu_append(GTK_MENU_SHELL(menu), gtk_separator_menu_item_new()); +#ifndef UISPECIFIC_MAIN_MENU_IS_MENU_BAR + gtk_menu_shell_append(GTK_MENU_SHELL(menu), gtk_separator_menu_item_new()); +#endif - appdata->menu_view = item = - gtk_menu_item_new_with_label( _("View") ); - gtk_menu_append(GTK_MENU_SHELL(menu), item); + appdata->menu_view = item = gtk_menu_item_new_with_mnemonic( _("_View") ); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); submenu = gtk_menu_new(); + gtk_menu_set_accel_group(GTK_MENU(submenu), accel_grp); gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu); -#ifdef USE_HILDON - appdata->fullscreen_menu_item = - item = gtk_check_menu_item_new_with_label( _("Fullscreen") ); - gtk_menu_append(GTK_MENU_SHELL(submenu), item); - g_signal_connect(item, "activate", GTK_SIGNAL_FUNC(cb_menu_fullscreen), - appdata); -#endif - - item = gtk_menu_item_new_with_label( _("Zoom +" )); - gtk_menu_append(GTK_MENU_SHELL(submenu), item); - g_signal_connect(item, "activate", GTK_SIGNAL_FUNC(cb_menu_zoomin), appdata); - - item = gtk_menu_item_new_with_label( _("Zoom -") ); - gtk_menu_append(GTK_MENU_SHELL(submenu), item); - g_signal_connect(item, "activate", GTK_SIGNAL_FUNC(cb_menu_zoomout), appdata); + appdata->menu_item_view_fullscreen = menu_append_new_item( + appdata, submenu, GTK_SIGNAL_FUNC(cb_menu_fullscreen), _("_Fullscreen"), + GTK_STOCK_FULLSCREEN, "/View/Fullscreen", + 0, 0, TRUE, TRUE, FALSE + ); + + menu_append_new_item( + appdata, submenu, GTK_SIGNAL_FUNC(cb_menu_zoomin), _("Zoom _in"), + GTK_STOCK_ZOOM_IN, "/View/ZoomIn", + GDK_comma, GDK_CONTROL_MASK, TRUE, FALSE, FALSE + ); + + menu_append_new_item( + appdata, submenu, GTK_SIGNAL_FUNC(cb_menu_zoomout), _("Zoom _out"), + GTK_STOCK_ZOOM_OUT, "/View/ZoomOut", + GDK_period, GDK_CONTROL_MASK, TRUE, FALSE, FALSE + ); /* -------------------- OSM submenu -------------------- */ - appdata->menu_osm = item = gtk_menu_item_new_with_label( _("OSM") ); - gtk_menu_append(GTK_MENU_SHELL(menu), item); + appdata->menu_osm = item = gtk_menu_item_new_with_mnemonic( _("_OSM") ); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); submenu = gtk_menu_new(); + gtk_menu_set_accel_group(GTK_MENU(submenu), accel_grp); gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu); - item = gtk_menu_item_new_with_label( _("Upload...") ); - gtk_menu_append(GTK_MENU_SHELL(submenu), item); - g_signal_connect(item, "activate", GTK_SIGNAL_FUNC(cb_menu_upload), appdata); - - item = gtk_menu_item_new_with_label( _("Download...") ); - gtk_menu_append(GTK_MENU_SHELL(submenu), item); - g_signal_connect(item, "activate", GTK_SIGNAL_FUNC(cb_menu_download), appdata); - - gtk_menu_append(GTK_MENU_SHELL(submenu), gtk_separator_menu_item_new()); - - item = gtk_menu_item_new_with_label( _("Save diff file") ); - gtk_menu_append(GTK_MENU_SHELL(submenu), item); - g_signal_connect(item, "activate", GTK_SIGNAL_FUNC(cb_menu_save_changes), - appdata); + appdata->menu_item_osm_upload = menu_append_new_item( + appdata, submenu, GTK_SIGNAL_FUNC(cb_menu_upload), _("_Upload..."), + "upload.16", "/OSM/Upload", + GDK_u, GDK_SHIFT_MASK|GDK_CONTROL_MASK, TRUE, FALSE, FALSE + ); + + menu_append_new_item( + appdata, submenu, GTK_SIGNAL_FUNC(cb_menu_download), _("_Download..."), + "download.16", "/OSM/Download", + GDK_d, GDK_SHIFT_MASK|GDK_CONTROL_MASK, TRUE, FALSE, FALSE + ); + + gtk_menu_shell_append(GTK_MENU_SHELL(submenu), gtk_separator_menu_item_new()); + + if(getenv("OSM2GO_UNDO_TEST")) { + appdata->menu_item_osm_undo = menu_append_new_item( + appdata, submenu, GTK_SIGNAL_FUNC(cb_menu_undo), _("_Undo"), + GTK_STOCK_UNDO, "/OSM/Undo", + GDK_z, GDK_CONTROL_MASK, TRUE, FALSE, FALSE + ); + } else + printf("set environment variable OSM2GO_UNDO_TEST to enable undo framework tests\n"); + + appdata->menu_item_osm_save_changes = menu_append_new_item( + appdata, submenu, GTK_SIGNAL_FUNC(cb_menu_save_changes), _("_Save local changes"), + GTK_STOCK_SAVE, "/OSM/SaveChanges", + GDK_s, GDK_SHIFT_MASK|GDK_CONTROL_MASK, TRUE, FALSE, FALSE + ); + + appdata->menu_item_osm_undo_changes = menu_append_new_item( + appdata, submenu, GTK_SIGNAL_FUNC(cb_menu_undo_changes), _("Disca_rd local changes..."), + GTK_STOCK_DELETE, "/OSM/DiscardChanges", + 0, 0, TRUE, FALSE, FALSE + ); + + gtk_menu_shell_append(GTK_MENU_SHELL(submenu), gtk_separator_menu_item_new()); + appdata->menu_item_osm_relations = menu_append_new_item( + appdata, submenu, GTK_SIGNAL_FUNC(cb_menu_osm_relations), _("_Relations..."), + NULL, "/OSM/Relations", + GDK_r, GDK_SHIFT_MASK|GDK_CONTROL_MASK, TRUE, FALSE, FALSE + ); /* -------------------- wms submenu -------------------- */ - appdata->menu_wms = item = gtk_menu_item_new_with_label( _("WMS") ); - gtk_menu_append(GTK_MENU_SHELL(menu), item); + appdata->menu_wms = item = gtk_menu_item_new_with_mnemonic( _("_WMS") ); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); submenu = gtk_menu_new(); + gtk_menu_set_accel_group(GTK_MENU(submenu), accel_grp); gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu); - item = gtk_menu_item_new_with_label( _("Import...") ); - gtk_menu_append(GTK_MENU_SHELL(submenu), item); - g_signal_connect(item, "activate", GTK_SIGNAL_FUNC(cb_menu_wms_import), - appdata); - - appdata->menu_item_wms_clear = item = - gtk_menu_item_new_with_label( _("Clear") ); - gtk_menu_append(GTK_MENU_SHELL(submenu), item); - gtk_widget_set_sensitive(item, FALSE); - g_signal_connect(item, "activate", GTK_SIGNAL_FUNC(cb_menu_wms_clear), - appdata); - - appdata->menu_item_wms_adjust = item = - gtk_menu_item_new_with_label( _("Adjust") ); - gtk_menu_append(GTK_MENU_SHELL(submenu), item); - gtk_widget_set_sensitive(item, FALSE); - g_signal_connect(item, "activate", GTK_SIGNAL_FUNC(cb_menu_wms_adjust), - appdata); + menu_append_new_item( + appdata, submenu, GTK_SIGNAL_FUNC(cb_menu_wms_import), _("_Import..."), + GTK_STOCK_INDEX, "/WMS/Import", + 0, 0, TRUE, FALSE, FALSE + ); + + appdata->menu_item_wms_clear = menu_append_new_item( + appdata, submenu, GTK_SIGNAL_FUNC(cb_menu_wms_clear), _("_Clear"), + GTK_STOCK_CLEAR, "/WMS/Clear", + 0, 0, TRUE, FALSE, FALSE + ); + gtk_widget_set_sensitive(appdata->menu_item_wms_clear, FALSE); + + appdata->menu_item_wms_adjust = menu_append_new_item( + appdata, submenu, GTK_SIGNAL_FUNC(cb_menu_wms_adjust), _("_Adjust"), + NULL, "/WMS/Adjust", + 0, 0, TRUE, FALSE, FALSE + ); + gtk_widget_set_sensitive(appdata->menu_item_wms_adjust, FALSE); /* -------------------- map submenu -------------------- */ - appdata->menu_map = item = gtk_menu_item_new_with_label( _("Map") ); - gtk_menu_append(GTK_MENU_SHELL(menu), item); + appdata->menu_map = item = gtk_menu_item_new_with_mnemonic( _("_Map") ); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); submenu = gtk_menu_new(); + gtk_menu_set_accel_group(GTK_MENU(submenu), accel_grp); gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu); - appdata->menu_item_map_hide_sel = item = - gtk_menu_item_new_with_label( _("Hide selected") ); - gtk_menu_append(GTK_MENU_SHELL(submenu), item); - gtk_widget_set_sensitive(item, FALSE); - g_signal_connect(item, "activate", GTK_SIGNAL_FUNC(cb_menu_map_hide_sel), - appdata); - - appdata->menu_item_map_show_all = item = - gtk_menu_item_new_with_label( _("Show all") ); - gtk_menu_append(GTK_MENU_SHELL(submenu), item); - gtk_widget_set_sensitive(item, FALSE); - g_signal_connect(item, "activate", GTK_SIGNAL_FUNC(cb_menu_map_show_all), - appdata); - - gtk_menu_append(GTK_MENU_SHELL(submenu), gtk_separator_menu_item_new()); - - item = gtk_menu_item_new_with_label( _("Redraw") ); - gtk_menu_append(GTK_MENU_SHELL(submenu), item); - g_signal_connect(item, "activate", GTK_SIGNAL_FUNC(cb_menu_redraw), appdata); - - gtk_menu_append(GTK_MENU_SHELL(submenu), gtk_separator_menu_item_new()); - - item = gtk_menu_item_new_with_label( _("Style...") ); - gtk_menu_append(GTK_MENU_SHELL(submenu), item); - g_signal_connect(item, "activate", GTK_SIGNAL_FUNC(cb_menu_style), appdata); + appdata->menu_item_map_hide_sel = menu_append_new_item( + appdata, submenu, GTK_SIGNAL_FUNC(cb_menu_map_hide_sel), _("_Hide selected"), + GTK_STOCK_REMOVE, "/Map/HideSelected", + 0, 0, TRUE, FALSE, FALSE + ); + gtk_widget_set_sensitive(appdata->menu_item_map_hide_sel, FALSE); + + appdata->menu_item_map_show_all = menu_append_new_item( + appdata, submenu, GTK_SIGNAL_FUNC(cb_menu_map_show_all), _("_Show all"), + GTK_STOCK_ADD, "/Map/ShowAll", + 0, 0, TRUE, FALSE, FALSE + ); + gtk_widget_set_sensitive(appdata->menu_item_map_show_all, FALSE); + + gtk_menu_shell_append(GTK_MENU_SHELL(submenu), gtk_separator_menu_item_new()); + + menu_append_new_item( + appdata, submenu, GTK_SIGNAL_FUNC(cb_menu_style), _("St_yle..."), + GTK_STOCK_SELECT_COLOR, "/Map/Style", + 0, 0, TRUE, FALSE, FALSE + ); + + gtk_menu_shell_append(GTK_MENU_SHELL(submenu), gtk_separator_menu_item_new()); + + /* switches mainly intended for testing/debugging */ + menu_append_new_item( + appdata, submenu, GTK_SIGNAL_FUNC(cb_menu_redraw), _("_Redraw"), + NULL, "/Map/Redraw", + GDK_r, GDK_CONTROL_MASK, TRUE, FALSE, FALSE + ); + + appdata->menu_item_map_no_icons = menu_append_new_item( + appdata, submenu, GTK_SIGNAL_FUNC(cb_menu_map_no_icons), _("No _icons"), + NULL, "/Map/NoIcons", + 0, 0, TRUE, TRUE, appdata->settings->no_icons + ); + + appdata->menu_item_map_no_antialias = menu_append_new_item( + appdata, submenu, GTK_SIGNAL_FUNC(cb_menu_map_no_antialias), + _("No _antialias"), + NULL, "/Map/NoAntialias", + 0, 0, TRUE, TRUE, appdata->settings->no_antialias + ); /* -------------------- track submenu -------------------- */ - appdata->track.menu_track = item = gtk_menu_item_new_with_label(_("Track")); - gtk_menu_append(GTK_MENU_SHELL(menu), item); + appdata->track.menu_track = item = gtk_menu_item_new_with_mnemonic(_("_Track")); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); submenu = gtk_menu_new(); + gtk_menu_set_accel_group(GTK_MENU(submenu), accel_grp); gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu); - appdata->track.menu_item_import = - item = gtk_menu_item_new_with_label( _("Import...") ); - gtk_menu_append(GTK_MENU_SHELL(submenu), item); - g_signal_connect(item, "activate", GTK_SIGNAL_FUNC(cb_menu_track_import), - appdata); - - appdata->track.menu_item_export = - item = gtk_menu_item_new_with_label( _("Export...") ); - gtk_menu_append(GTK_MENU_SHELL(submenu), item); - g_signal_connect(item, "activate", GTK_SIGNAL_FUNC(cb_menu_track_export), - appdata); - - appdata->track.menu_item_clear = - item = gtk_menu_item_new_with_label( _("Clear") ); - gtk_menu_append(GTK_MENU_SHELL(submenu), item); - g_signal_connect(item, "activate", GTK_SIGNAL_FUNC(cb_menu_track_clear), - appdata); - - appdata->track.menu_item_gps = - item = gtk_check_menu_item_new_with_label( _("GPS") ); - gtk_menu_append(GTK_MENU_SHELL(submenu), item); - g_signal_connect(item, "activate", GTK_SIGNAL_FUNC(cb_menu_track_gps), - appdata); + appdata->track.menu_item_import = menu_append_new_item( + appdata, submenu, GTK_SIGNAL_FUNC(cb_menu_track_import), _("_Import..."), + NULL, "/Track/Import", + 0, 0, TRUE, FALSE, FALSE + ); + + appdata->track.menu_item_export = menu_append_new_item( + appdata, submenu, GTK_SIGNAL_FUNC(cb_menu_track_export), _("_Export..."), + NULL, "/Track/Export", + 0, 0, FALSE, FALSE, FALSE + ); + + appdata->track.menu_item_clear = menu_append_new_item( + appdata, submenu, GTK_SIGNAL_FUNC(cb_menu_track_clear), _("_Clear"), + GTK_STOCK_CLEAR, "/Track/Clear", + 0, 0, FALSE, FALSE, FALSE + ); + + + appdata->track.menu_item_enable_gps = menu_append_new_item( + appdata, submenu, GTK_SIGNAL_FUNC(cb_menu_track_enable_gps),_("_GPS enable"), + NULL, "/Track/GPS", + GDK_g, GDK_CONTROL_MASK|GDK_SHIFT_MASK, TRUE, TRUE, + appdata->settings->enable_gps + ); + + appdata->track.menu_item_follow_gps = menu_append_new_item( + appdata, submenu, GTK_SIGNAL_FUNC(cb_menu_track_follow_gps), _("GPS follow"), + NULL, "/Track/Follow", + 0, 0, appdata->settings->enable_gps, TRUE, + appdata->settings->follow_gps + ); /* ------------------------------------------------------- */ - gtk_menu_append(GTK_MENU_SHELL(menu), gtk_separator_menu_item_new()); + gtk_menu_shell_append(GTK_MENU_SHELL(about_quit_items_menu), + gtk_separator_menu_item_new()); + menu_append_new_item( + appdata, about_quit_items_menu, GTK_SIGNAL_FUNC(cb_menu_about), _("_About..."), + GTK_STOCK_ABOUT, "/About", + 0, 0, TRUE, FALSE, FALSE + ); + + menu_append_new_item( + appdata, about_quit_items_menu, GTK_SIGNAL_FUNC(cb_menu_quit), _("_Quit"), + GTK_STOCK_QUIT, "/Quit", + 0, 0, TRUE, FALSE, FALSE + ); - item = gtk_menu_item_new_with_label( _("About...") ); - gtk_menu_append(GTK_MENU_SHELL(menu), item); - g_signal_connect(item, "activate", GTK_SIGNAL_FUNC(cb_menu_about), appdata); - - - item = gtk_menu_item_new_with_label( _("Quit") ); - gtk_menu_append(GTK_MENU_SHELL(menu), item); - g_signal_connect(item, "activate", GTK_SIGNAL_FUNC(cb_menu_quit), appdata); + gtk_window_add_accel_group(GTK_WINDOW(appdata->window), accel_grp); #ifdef USE_HILDON hildon_window_set_menu(appdata->window, GTK_MENU(menu)); #else - /* attach ordinary gtk menu */ - GtkWidget *menu_bar = gtk_menu_bar_new(); + GtkWidget *menu_bar = menu; + +#ifndef UISPECIFIC_MAIN_MENU_IS_MENU_BAR + // we need to make one first + menu_bar = gtk_menu_bar_new(); GtkWidget *root_menu = gtk_menu_item_new_with_label (_("Menu")); gtk_widget_show(root_menu); @@ -514,14 +845,40 @@ gtk_menu_item_set_submenu(GTK_MENU_ITEM (root_menu), menu); gtk_widget_show(menu_bar); +#endif //UISPECIFIC_MAIN_MENU_IS_MENU_BAR + gtk_box_pack_start(GTK_BOX(appdata->vbox), menu_bar, 0, 0, 0); -#endif + +#endif //USE_HILDON } /********************* end of menu **********************/ +#ifdef UISPECIFIC_MENU_HAS_ACCELS +#define ACCELS_FILE "accels" + +static void menu_accels_load(appdata_t *appdata) { + char *accels_file = g_strdup_printf("%s/" ACCELS_FILE, + appdata->settings->base_path); + gtk_accel_map_load(accels_file); + g_free(accels_file); +} + +static void menu_accels_save(appdata_t *appdata) { + char *accels_file = g_strdup_printf("%s" ACCELS_FILE, + appdata->settings->base_path); + gtk_accel_map_save(accels_file); + g_free(accels_file); +} + +#endif + void cleanup(appdata_t *appdata) { +#ifdef UISPECIFIC_MENU_HAS_ACCELS + menu_accels_save(appdata); +#endif + settings_save(appdata->settings); #ifdef USE_HILDON @@ -565,6 +922,9 @@ project_free(appdata->project); + if(appdata->menu_item_osm_undo) + undo_free(appdata->undo.state); + puts("everything is gone"); } @@ -580,34 +940,28 @@ appdata_t *appdata = (appdata_t*)data; int handled = FALSE; - // printf("key event %d\n", event->keyval); - // the map handles some keys on its own ... switch(event->keyval) { -#ifdef USE_HILDON -#if 0 - case HILDON_HARDKEY_SELECT: - handled = TRUE; - break; -#endif - +#ifdef USE_HILDON + /* this is in fact a mapping to GDK_F6 */ case HILDON_HARDKEY_FULLSCREEN: - { - gboolean fullscreen = !gtk_check_menu_item_get_active( - GTK_CHECK_MENU_ITEM(appdata->fullscreen_menu_item)); +#else + case GDK_F11: +#endif + if(!gtk_check_menu_item_get_active( + GTK_CHECK_MENU_ITEM(appdata->menu_item_view_fullscreen))) { + gtk_window_fullscreen(GTK_WINDOW(appdata->window)); gtk_check_menu_item_set_active( - GTK_CHECK_MENU_ITEM(appdata->fullscreen_menu_item), fullscreen); - - if(fullscreen) - gtk_window_fullscreen(GTK_WINDOW(appdata->window)); - else + GTK_CHECK_MENU_ITEM(appdata->menu_item_view_fullscreen), TRUE); + } else { gtk_window_unfullscreen(GTK_WINDOW(appdata->window)); - - handled = TRUE; - } + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(appdata->menu_item_view_fullscreen), FALSE); + } + + handled = TRUE; break; -#endif } /* forward unprocessed key presses to map */ @@ -635,10 +989,10 @@ g_thread_init(NULL); - gps_init(&appdata); - gtk_init (&argc, &argv); + gps_init(&appdata); + #ifdef USE_HILDON printf("Installing osso context for \"org.harbaum." PACKAGE "\"\n"); appdata.osso_context = osso_initialize("org.harbaum."PACKAGE, @@ -674,12 +1028,15 @@ g_signal_connect(G_OBJECT(appdata.window), "key_press_event", G_CALLBACK(on_window_key_press), &appdata); - appdata.vbox = gtk_vbox_new(FALSE,0); - menu_create(&appdata); - /* user specific init */ appdata.settings = settings_load(); + appdata.vbox = gtk_vbox_new(FALSE,0); + menu_create(&appdata); +#ifdef UISPECIFIC_MENU_HAS_ACCELS + menu_accels_load(&appdata); +#endif + /* ----------------------- setup main window ---------------- */ GtkWidget *hbox = gtk_hbox_new(FALSE,0); @@ -688,7 +1045,15 @@ #ifdef PORTRAIT gtk_box_pack_start(GTK_BOX(vbox), iconbar_new(&appdata), FALSE, FALSE, 0); #endif - gtk_box_pack_start(GTK_BOX(vbox), map_new(&appdata), TRUE, TRUE, 0); + + /* generate main map view */ + GtkWidget *map = map_new(&appdata); + if(!map) { + cleanup(&appdata); + return -1; + } + + gtk_box_pack_start(GTK_BOX(vbox), map, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(vbox), statusbar_new(&appdata), FALSE, FALSE, 0); #ifndef PORTRAIT @@ -716,13 +1081,21 @@ if(appdata.settings->project) project_load(&appdata, appdata.settings->project); - main_project_loaded(&appdata); + main_ui_enable(&appdata); + + /* start GPS if enabled by config */ + if(appdata.settings && appdata.settings->enable_gps) + track_enable_gps(&appdata, TRUE); /* ------------ jump into main loop ---------------- */ gtk_main(); + puts("gtk_main() left"); + track_save(appdata.project, appdata.track.track); + track_clear(&appdata, appdata.track.track); + appdata.track.track = NULL; /* save a diff if there are dirty entries */ diff_save(appdata.project, appdata.osm); @@ -731,3 +1104,5 @@ return 0; } + +// vim:et:ts=8:sw=2:sts=2:ai