diff --git a/navit/android.c b/navit/android.c index 214e3171cd..3ec08e1a7b 100644 --- a/navit/android.c +++ b/navit/android.c @@ -21,6 +21,7 @@ #include "search.h" #include "start_real.h" #include "track.h" +#include "gui.h" JNIEnv *jnienv; jobject *android_activity = NULL; @@ -322,7 +323,7 @@ JNIEXPORT jobjectArray JNICALL Java_org_navitproject_navit_NavitGraphics_getAllC JNIEXPORT jstring JNICALL Java_org_navitproject_navit_NavitGraphics_getCoordForPoint( JNIEnv* env, - jobject thiz, jint x, jint y, jboolean absoluteCoord) { + jclass thiz, jint x, jint y, jboolean absoluteCoord) { jstring return_string = NULL; @@ -356,7 +357,6 @@ JNIEXPORT jstring JNICALL Java_org_navitproject_navit_NavitGraphics_getCoordForP return return_string; } - JNIEXPORT jobject JNICALL Java_org_navitproject_navit_NavitCallbackHandler_callbackCmdChannel( JNIEnv* env, jclass thiz, jint command) { @@ -493,29 +493,30 @@ JNIEXPORT jint JNICALL Java_org_navitproject_navit_NavitCallbackHandler_callback dbg(lvl_debug,"Setting destination to %s",coord_str); // start navigation asynchronous navit_set_destination(attr.u.navit, &pc, coord_str, 1); + ret = 1; } break; - case 3: { - // navigate to geo position - char *name; + case 8: /* Show contextual actions for a geo position */ + case 3: { /* Navigate to geo position */ s = (*env)->GetStringUTFChars(env, str, NULL); + char *name; char parse_str[strlen(s) + 1]; strcpy(parse_str, s); (*env)->ReleaseStringUTFChars(env, str, s); dbg(lvl_debug, "*****string=%s", s); - // set destination to (lat#lon#title) + /* Parse coordinates from argument string (lat#lon#title) */ struct coord_geo g; char *p; char *stopstring; - // latitude + // extract latitude p = strtok (parse_str,"#"); g.lat = strtof(p, &stopstring); - // longitude + // extract longitude p = strtok (NULL, "#"); g.lng = strtof(p, &stopstring); - // description/name of the place identified by lat and long + // extract description/name of the place identified by lat and long (if any) name = strtok (NULL, "#"); dbg(lvl_debug, "lat=%f", g.lat); @@ -525,17 +526,28 @@ JNIEXPORT jint JNICALL Java_org_navitproject_navit_NavitCallbackHandler_callback struct coord c; transform_from_geo(projection_mg, &g, &c); - struct pcoord pc; + static struct pcoord pc; pc.x = c.x; pc.y = c.y; pc.pro = projection_mg; char coord_str[32]; - if (!name || *name == '\0') { /* When name is an empty string, use the geo coord instead */ + if (name && *name == '\0') /* Force name to NULL if no str1 has been provided */ + name = NULL; + + if (channel == 8) { + if (gui_show_coord_actions(navit_get_gui(attr.u.navit), NULL, NULL) == -1) { + gui_show_coord_actions(navit_get_gui(attr.u.navit), &pc, name); + break; /* -1 indicates that this feature is supported but coord is NULL (probe mode), which is expected */ + } + /* If previous gui_show_coord_actions() probe failed, then fall back to channel=3 block below */ + dbg(lvl_warning, "No contextual coord actions available, starting default action: navigate to destination"); + } + if (!name) { /* When name is an empty string, use the geo coord instead */ pcoord_format_degree_short(&pc, coord_str, sizeof(coord_str), " "); name = coord_str; } - // start navigation asynchronous navit_set_destination(attr.u.navit, &pc, name, 1); + ret = 1; } break; default: diff --git a/navit/android/src/org/navitproject/navit/Navit.java b/navit/android/src/org/navitproject/navit/Navit.java index 011acd9fe9..17dd7bf68b 100644 --- a/navit/android/src/org/navitproject/navit/Navit.java +++ b/navit/android/src/org/navitproject/navit/Navit.java @@ -373,7 +373,7 @@ private void handleIntent(Intent intent) { } else if (naviScheme.equals("geo") && intent.getAction().equals("android.intent.action.VIEW")) { invokeCallbackOnGeo(intent.getData().getSchemeSpecificPart(), - NavitCallbackHandler.MsgType.CLB_SET_DESTINATION, ""); + NavitCallbackHandler.MsgType.CLB_COORD_ACTIONS, ""); } } } diff --git a/navit/android/src/org/navitproject/navit/NavitCallbackHandler.java b/navit/android/src/org/navitproject/navit/NavitCallbackHandler.java index c3a3b3230a..a0e0b218b6 100644 --- a/navit/android/src/org/navitproject/navit/NavitCallbackHandler.java +++ b/navit/android/src/org/navitproject/navit/NavitCallbackHandler.java @@ -42,7 +42,19 @@ static void sendCommand(CmdType command) { enum MsgType { - CLB_SET_DESTINATION, CLB_SET_DISPLAY_DESTINATION, CLB_CALL_CMD, CLB_LOAD_MAP, CLB_UNLOAD_MAP, + /* Set the current navigation destination to geographical coordinates */ + CLB_SET_DESTINATION, + /* Set current navigation destination to a given position on the current graphical display */ + CLB_SET_DISPLAY_DESTINATION, + /* Open a contextual menu with possible actions related to the provided geographical coordinates */ + CLB_COORD_ACTIONS, + /* Call a custom internal command (like in the GUI scripts) */ + CLB_CALL_CMD, + /* Load a map */ + CLB_LOAD_MAP, + /* Unload a map */ + CLB_UNLOAD_MAP, + /* Unload a map and delete it from the storage */ CLB_DELETE_MAP } @@ -50,12 +62,20 @@ enum MsgType { static class CallBackHandler extends Handler { public void handleMessage(Message msg) { switch (msg_values[msg.what]) { - case CLB_SET_DESTINATION: + case CLB_SET_DESTINATION: { String lat = Float.toString(msg.getData().getFloat("lat")); String lon = Float.toString(msg.getData().getFloat("lon")); String q = msg.getData().getString(("q")); callbackMessageChannel(3, lat + "#" + lon + "#" + q); - break; + } + break; + case CLB_COORD_ACTIONS: { + String lat = Float.toString(msg.getData().getFloat("lat")); + String lon = Float.toString(msg.getData().getFloat("lon")); + String q = msg.getData().getString(("q")); + callbackMessageChannel(8, lat + "#" + lon + "#" + q); + } + break; case CLB_SET_DISPLAY_DESTINATION: int x = msg.arg1; int y = msg.arg2; diff --git a/navit/android/src/org/navitproject/navit/NavitGraphics.java b/navit/android/src/org/navitproject/navit/NavitGraphics.java index 79ee27d81b..a1cf727267 100644 --- a/navit/android/src/org/navitproject/navit/NavitGraphics.java +++ b/navit/android/src/org/navitproject/navit/NavitGraphics.java @@ -646,7 +646,7 @@ private void setmActivity(final Navit navit) { private native void motionCallback(long id, int x, int y); - private native String getCoordForPoint(int x, int y, boolean absoluteCoord); + private static native String getCoordForPoint(int x, int y, boolean absoluteCoord); static native String[][] getAllCountries(); diff --git a/navit/gui.c b/navit/gui.c index 817bac15ec..a0663def44 100644 --- a/navit/gui.c +++ b/navit/gui.c @@ -142,6 +142,17 @@ int gui_add_bookmark(struct gui *gui, struct pcoord *c, char *description) { return ret; } +int gui_show_coord_actions(struct gui *gui, const struct pcoord *c, const char *description) { + int ret; + dbg(lvl_info,"enter"); + if (! gui->meth.show_coord_actions) + return 0; + ret=gui->meth.show_coord_actions(gui->priv, c, description); + + dbg(lvl_info,"ret=%d", ret); + return ret; +} + int gui_set_graphics(struct gui *this_, struct graphics *gra) { if (! this_->meth.set_graphics) { dbg(lvl_error, "cannot set graphics, method 'set_graphics' not available"); diff --git a/navit/gui.h b/navit/gui.h index 5bb936938c..c55acc6561 100644 --- a/navit/gui.h +++ b/navit/gui.h @@ -39,6 +39,7 @@ struct gui_methods { int (*run_main_loop)(struct gui_priv *priv); struct datawindow_priv *(*datawindow_new)(struct gui_priv *priv, const char *name, struct callback *click, struct callback *close, struct datawindow_methods *meth); int (*add_bookmark)(struct gui_priv *priv, struct pcoord *c, char *description); + int (*show_coord_actions)(struct gui_priv *priv, struct pcoord *c, char *description); void (*disable_suspend)(struct gui_priv *priv); int (*get_attr)(struct gui_priv *priv, enum attr_type type, struct attr *attr); int (*add_attr)(struct gui_priv *priv, struct attr *attr); @@ -64,6 +65,19 @@ struct menu *gui_menubar_new(struct gui *gui); struct menu *gui_popup_new(struct gui *gui); struct datawindow *gui_datawindow_new(struct gui *gui, const char *name, struct callback *click, struct callback *close); int gui_add_bookmark(struct gui *gui, struct pcoord *c, char *description); +/** + * @brief Show an action menu related to specific geographical coordinates + * + * @param[in] this_ The gui context + * @param[in] c A pointer to the geographical coordinates data + * @param[in] description An (optional) string to use as a label for the geographical coordinates + * + * @return !=0 if the action menu GUI can be displayed + * + * @warning To probe whether the action menu GUI is supported for the current GUI, just run this function with NULL pointers in c. + * This will not open any GUI menu but rather return -1 if the action menu supported. + */ +int gui_show_coord_actions(struct gui *this_, const struct pcoord *c, const char *description); int gui_set_graphics(struct gui *this_, struct graphics *gra); void gui_disable_suspend(struct gui *this_); int gui_has_main_loop(struct gui *this_); diff --git a/navit/gui/gtk/gui_gtk_window.c b/navit/gui/gtk/gui_gtk_window.c index f0d13528a0..1786e502ef 100644 --- a/navit/gui/gtk/gui_gtk_window.c +++ b/navit/gui/gtk/gui_gtk_window.c @@ -276,12 +276,13 @@ static int gui_gtk_add_bookmark(struct gui_priv *gui, struct pcoord *c, char *de } struct gui_methods gui_gtk_methods = { - NULL, + NULL, // gui_gtk_menubar_new gui_gtk_popup_new, gui_gtk_set_graphics, - NULL, + NULL, // gui_gtk_run_main_loop gui_gtk_datawindow_new, gui_gtk_add_bookmark, + NULL, // gui_gtk_show_coord_actions }; static gboolean gui_gtk_delete(GtkWidget *widget, GdkEvent *event, struct navit *nav) { diff --git a/navit/gui/internal/gui_internal.c b/navit/gui/internal/gui_internal.c index 505432da9a..c654f26b30 100644 --- a/navit/gui/internal/gui_internal.c +++ b/navit/gui/internal/gui_internal.c @@ -1022,6 +1022,8 @@ static void gui_internal_cmd_delete_waypoint(struct gui_priv *this, struct widge * @param wm The widget that points to this function as a callback * @param name The display name for the position * @param flags Flags specifying the operations available from the GUI + * + * @note Position input can be done either using pc_in or g_in (if both are provided, pc_in takes precedence) */ /* meaning of the bits in "flags": * 1: "Streets" @@ -2146,6 +2148,12 @@ void gui_internal_leave(struct gui_priv *this) { graphics_draw_mode(this->gra, draw_mode_end); } +/** + * @brief Update the internal state of the internal GUI to store a specific point clicked on the display + * + * @param[in] this Our gui context + * @param[in] p The position of the point clicked on the display + */ void gui_internal_set_click_coord(struct gui_priv *this, struct point *p) { struct coord c; struct coord_geo g; @@ -2167,6 +2175,11 @@ void gui_internal_set_click_coord(struct gui_priv *this, struct point *p) { } } +/** + * @brief Update the internal state of the internal GUI to store the current vehicle position + * + * @param[in] this Our gui context + */ static void gui_internal_set_position_coord(struct gui_priv *this) { struct transformation *trans; struct attr attr,attrp; @@ -2190,6 +2203,13 @@ void gui_internal_enter_setup(struct gui_priv *this) { gui_internal_set_position_coord(this); } +/** + * @brief Display an internal GUI menu + * + * @param[in] this Our gui context + * @param ignore Whether the current triggering button press should be ignored by subsequent handlers (see navit_ignore_button()) + * @param href The anchor of the HTML menu to display (or NULL to display the main menu) + */ void gui_internal_cmd_menu(struct gui_priv *this, int ignore, char *href) { dbg(lvl_debug,"enter"); gui_internal_enter(this, ignore); @@ -2509,7 +2529,7 @@ static void gui_internal_setup(struct gui_priv *this) { char *gui_file; int size; - if (this->background) + if (this->background) /* When this->background is non NULL, we know we have already been initialized (thus already went through gui_internal_setup() previously) */ return; this->background=graphics_gc_new(gra); this->background2=graphics_gc_new(gra); @@ -2533,6 +2553,10 @@ static void gui_internal_setup(struct gui_priv *this) { g_free(buffer); } g_free(gui_file); + if (this->deferred_exec_at_init) { + event_add_timeout(5, 0, this->deferred_exec_at_init); + this->deferred_exec_at_init = NULL; /* Unregister deferred exec, it will be run as an asynchronous callback */ + } } /** @@ -2896,6 +2920,95 @@ static int gui_internal_set_graphics(struct gui_priv *this, struct graphics *gra return 0; } +/** + * @brief A structure containing the context (arguments) to run gui_internal_show_coord() +**/ +struct gui_internal_show_coord_args { + const char *description; /*!< The label to use for the geographical coordinates (ex: "Map Point") */ + struct pcoord coord; /*!< The geographical coordinates to use */ +}; + +static int gui_internal_show_coord_actions(struct gui_priv *this, const struct pcoord *c, + const char *description); /* Forward declaration */ + +/** + * @brief Takes a context (as a pointer to a gui_internal_show_coord_args structure) and run gui_internal_show_coord_actions() with these arguments + * + * This function is used as a callback to invoke gui_internal_show_coord_actions() asynchronously + * + * @note We will also take care of deallocating all dynamic memory in this context struct) +**/ +static void gui_internal_deferred_show_coord_actions(struct gui_priv *this, + const struct gui_internal_show_coord_args *context) { + if (!context) + return; + + gui_internal_show_coord_actions(this, &(context->coord), context->description); + /* Context is not needed anymore, it is up to us to free all its allocated memory */ + if (context->description) + g_free(context->description); + + g_free(context); +} + +/** + * @brief Display an internal contextual menu for the specified geographical coordinates + * + * @param this The internal GUI instance + * @param[in] c The geographical coordinates to use (or NULL if we just want to probe that this feature is supported without actually displaing the menu) + * @param[in] description A label to use for the geographical coordinates (ex: "Map Point"), or NULL if no specific label has been chosen. In that case, we will use the geographical coordinates as a label + * + * @return 0 on failure, 1 on success, -1 if argument c is NULL + */ +static int gui_internal_show_coord_actions(struct gui_priv *this, const struct pcoord *c, const char *description) { + struct widget w; + + dbg(lvl_debug,"enter"); + + if (!c) { /* Probe mode */ + return -1; + } + + if (!this->background) { + dbg(lvl_warning, "Internal GUI not yet initialized at invokation, actions queued for future execution"); + struct gui_internal_show_coord_args *deferred_show_coord_actions_context = g_malloc(sizeof( + struct gui_internal_show_coord_args)); + if (description) + deferred_show_coord_actions_context->description = g_strdup(description); + else + deferred_show_coord_actions_context->description = NULL; + + deferred_show_coord_actions_context->coord = *c; + + struct callback *gui_internal_show_coord_actions_callback = callback_new_2(callback_cast( + gui_internal_deferred_show_coord_actions), this, deferred_show_coord_actions_context); + this->deferred_exec_at_init = + gui_internal_show_coord_actions_callback; /* Plan execution of this callback when internal GUI will be initialized */ + return 1; + } + + w.text = g_malloc(32); + pcoord_format_degree_short(c, w.text, 32, " "); + + if (description) + w.name = description; + else + w.name = w.text; + + gui_internal_enter(this, 1); + gui_internal_set_click_coord(this, NULL); + gui_internal_enter_setup(this); + + gui_internal_cmd_position_do(this, c, NULL, &w, w.name ? w.name : w.text, 8|16|32|64|128); + + gui_internal_menu_render(this); + gui_internal_leave(this); + + g_free(w.text); + + return 1; +} + static void gui_internal_disable_suspend(struct gui_priv *this) { if (this->win->disable_suspend) this->win->disable_suspend(this->win); @@ -2907,12 +3020,13 @@ static void gui_internal_disable_suspend(struct gui_priv *this) { //# Authors: Martin Schaller (04/2008) //############################################################################################################## struct gui_methods gui_internal_methods = { - NULL, - NULL, + NULL, // gui_internal_menubar_new + NULL, // gui_internal_popup_new gui_internal_set_graphics, - NULL, - NULL, - NULL, + NULL, // gui_internal_run_main_loop + NULL, // gui_internal_datawindow_new + NULL, // gui_internal_add_bookmark + gui_internal_show_coord_actions, gui_internal_disable_suspend, gui_internal_get_attr, gui_internal_add_attr, diff --git a/navit/gui/internal/gui_internal_command.h b/navit/gui/internal/gui_internal_command.h index 206a5c2a0e..eed7e3d4e3 100644 --- a/navit/gui/internal/gui_internal_command.h +++ b/navit/gui/internal/gui_internal_command.h @@ -2,7 +2,6 @@ struct attr; struct gui_priv; struct pcoord; -char *gui_internal_coordinates(struct pcoord *pc, char sep); int gui_internal_cmd2_quit(struct gui_priv *this, char *function, struct attr **in, struct attr ***out); void gui_internal_command_init(struct gui_priv *this, struct attr **attrs); /* end of prototypes */ diff --git a/navit/gui/internal/gui_internal_priv.h b/navit/gui/internal/gui_internal_priv.h index ceb5db9864..438abb8a0d 100644 --- a/navit/gui/internal/gui_internal_priv.h +++ b/navit/gui/internal/gui_internal_priv.h @@ -147,6 +147,7 @@ struct gui_priv { int hide_keys; //Flag to set the keyboard mode 1: hide impossible keys on search; 0: highlight them. int results_map_population; int town_use_postal; + struct callback *deferred_exec_at_init; /*!< A callback to be run when internal GUI has finished initializing */ }; struct menu_data { diff --git a/navit/gui/qt5_qml/gui_qt5_qml.cpp b/navit/gui/qt5_qml/gui_qt5_qml.cpp index caab81709d..330ba2662e 100644 --- a/navit/gui/qt5_qml/gui_qt5_qml.cpp +++ b/navit/gui/qt5_qml/gui_qt5_qml.cpp @@ -258,6 +258,7 @@ struct gui_methods gui_qt5_qml_methods = { NULL, NULL, NULL, + NULL, // gui_qt5_qml_show_coord_actions NULL, gui_qt5_qml_get_attr, NULL, diff --git a/navit/gui/win32/gui_win32.c b/navit/gui/win32/gui_win32.c index 63edd73dff..e99d9f5f49 100644 --- a/navit/gui/win32/gui_win32.c +++ b/navit/gui/win32/gui_win32.c @@ -562,9 +562,10 @@ struct gui_methods win32_gui_methods = { NULL, // win32_gui_menubar_new, win32_gui_popup_new, win32_gui_set_graphics, - NULL, + NULL, // win32_gui_run_main_loop NULL, // win32_gui_datawindow_new, win32_gui_add_bookmark, + NULL, // win32_gui_show_coord_actions };