Fix #712: ability to return to previous image if home/end was pressed occasionally
authorColin Clark <colin.clark@cclark.uk>
Thu, 26 Sep 2019 10:21:35 +0000 (11:21 +0100)
committerColin Clark <colin.clark@cclark.uk>
Thu, 26 Sep 2019 10:21:35 +0000 (11:21 +0100)
https://github.com/BestImageViewer/geeqie/issues/712

Additional Go menu items - Image Back, Image Forward

Remove key bindings for multi-page navigation - they conflict with other
usage. The user can set their own key bindings.

Remove enable/disable multi-page navigation items. The parameter
fd->page_total is set in another thread which causes problems. It is
easiest to leave them always enabled.

doc/docbook/GuideMainWindowMenus.xml
src/history_list.c
src/history_list.h
src/image.c
src/layout_image.c
src/layout_util.c
src/toolbar.c

index 3f1f93b..07e9b1d 100644 (file)
           <para>Goes to the last image</para>\r
         </listitem>\r
       </varlistentry>\r
+      <varlistentry>\r
+        <term>\r
+          <menuchoice>\r
+            <guimenu>Image Back</guimenu>\r
+          </menuchoice>\r
+        </term>\r
+        <listitem>\r
+          <para>Each image you view is appended to a chain. You may traverse forwards and backwards through this chain using this and the following key. Move to the previous image in the chain.</para>\r
+        </listitem>\r
+      </varlistentry>\r
+      <varlistentry>\r
+        <term>\r
+          <menuchoice>\r
+            <guimenu>Image Forward</guimenu>\r
+          </menuchoice>\r
+        </term>\r
+        <listitem>\r
+          <para>Move to the next image in the chain.</para>\r
+        </listitem>\r
+      </varlistentry>\r
       <varlistentry>\r
         <term>\r
           <menuchoice>\r
index e1fafbf..d03ee05 100644 (file)
@@ -98,6 +98,79 @@ void history_chain_append_end(const gchar *path)
                }
 }
 
+/*
+ *-----------------------------------------------------------------------------
+ * Implements an image history chain. Whenever an image is displayed it is
+ * appended to a chain.
+ * Pressing the Image Back and Image Forward buttons moves along the chain,
+ * but does not make additions to the chain.
+ * The chain always increases and is deleted at the end of the session
+ *-----------------------------------------------------------------------------
+ */
+static GList *image_chain = NULL;
+static guint image_chain_index = G_MAXUINT;
+static gboolean image_nav_button = FALSE; /** Used to prevent the nav buttons making entries to the chain **/
+const gchar *image_chain_back()
+{
+       image_nav_button = TRUE;
+
+       image_chain_index = image_chain_index > 0 ? image_chain_index - 1 : 0;
+
+       return g_list_nth_data(image_chain, image_chain_index);
+}
+
+const gchar *image_chain_forward()
+{
+       image_nav_button= TRUE;
+       guint last = g_list_length(image_chain) - 1;
+
+       image_chain_index = image_chain_index < last ? image_chain_index + 1 : last;
+
+       return g_list_nth_data(image_chain, image_chain_index);
+}
+
+/**
+ * @brief Appends a path to the image history chain
+ * @param path Image path selected
+ * 
+ * Each time the user selects a new image it is appended to the chain
+ * except when it is identical to the current last entry
+ * The pointer is always moved to the end of the chain
+ */
+void image_chain_append_end(const gchar *path)
+{
+       GList *work;
+
+       if (!image_nav_button)
+               {
+               if(image_chain_index == G_MAXUINT)
+                       {
+                       image_chain = g_list_append(image_chain, g_strdup(path));
+                       image_chain_index = 0;
+                       }
+               else
+                       {
+                       work = g_list_last(image_chain);
+                       gchar *tmp;
+                       tmp = work->data;
+                       if (g_strcmp0(work->data , path) != 0)
+                               {
+                               image_chain = g_list_append(image_chain, g_strdup(path));
+                               image_chain_index = g_list_length(image_chain) - 1;
+                               DEBUG_3("%d %s", image_chain_index, path);
+                               }
+                       else
+                               {
+                               image_chain_index = g_list_length(image_chain) - 1;
+                               }
+                       }
+               }
+       else
+               {
+               image_nav_button = FALSE;
+               }
+}
+
 /*
  *-----------------------------------------------------------------------------
  * history lists
index da10b8e..f9040de 100644 (file)
@@ -40,6 +40,10 @@ const gchar *history_chain_back();
 const gchar *history_chain_forward();
 void history_chain_append_end(const gchar *path);
 
+const gchar *image_chain_back();
+const gchar *image_chain_forward();
+void image_chain_append_end(const gchar *path);
+
 /* the returned GList is internal, don't free it */
 GList *history_list_get_by_key(const gchar *key);
 
index 23d2a20..a36f21d 100644 (file)
@@ -29,6 +29,7 @@
 #include "exif.h"
 #include "metadata.h"
 #include "histogram.h"
+#include "history_list.h"
 #include "image-load.h"
 #include "image-overlay.h"
 #include "layout.h"
@@ -1384,6 +1385,11 @@ void image_change_from_collection(ImageWindow *imd, CollectionData *cd, CollectI
                collection_table_unselect_all(cw->table);
                collection_table_select(cw->table,info);
                }
+
+       if (info->fd)
+               {
+               image_chain_append_end(info->fd->path);
+               }
 }
 
 CollectionData *image_get_collection(ImageWindow *imd, CollectInfo **info)
index ee26fd4..a87e9f8 100644 (file)
@@ -1400,6 +1400,11 @@ void layout_image_set_fd(LayoutWindow *lw, FileData *fd)
        layout_image_slideshow_continue_check(lw);
        layout_bars_new_image(lw);
        layout_image_animate_new_file(lw);
+
+       if (fd)
+               {
+               image_chain_append_end(fd->path);
+               }
 }
 
 void layout_image_set_with_ahead(LayoutWindow *lw, FileData *fd, FileData *read_ahead_fd)
index 83db36c..40a3253 100644 (file)
@@ -1546,7 +1546,10 @@ static void layout_menu_page_first_cb(GtkAction *action, gpointer data)
        LayoutWindow *lw = data;
        FileData *fd = layout_image_get_fd(lw);
 
-       file_data_set_page_num(fd, 1);
+       if (fd->page_total > 0)
+               {
+               file_data_set_page_num(fd, 1);
+               }
 }
 
 static void layout_menu_page_last_cb(GtkAction *action, gpointer data)
@@ -1554,7 +1557,10 @@ static void layout_menu_page_last_cb(GtkAction *action, gpointer data)
        LayoutWindow *lw = data;
        FileData *fd = layout_image_get_fd(lw);
 
-       file_data_set_page_num(fd, -1);
+       if (fd->page_total > 0)
+               {
+               file_data_set_page_num(fd, -1);
+               }
 }
 
 static void layout_menu_page_next_cb(GtkAction *action, gpointer data)
@@ -1562,7 +1568,10 @@ static void layout_menu_page_next_cb(GtkAction *action, gpointer data)
        LayoutWindow *lw = data;
        FileData *fd = layout_image_get_fd(lw);
 
-       file_data_inc_page_num(fd);
+       if (fd->page_total > 0)
+               {
+               file_data_inc_page_num(fd);
+               }
 }
 
 static void layout_menu_page_previous_cb(GtkAction *action, gpointer data)
@@ -1570,7 +1579,28 @@ static void layout_menu_page_previous_cb(GtkAction *action, gpointer data)
        LayoutWindow *lw = data;
        FileData *fd = layout_image_get_fd(lw);
 
-       file_data_dec_page_num(fd);
+       if (fd->page_total > 0)
+               {
+               file_data_dec_page_num(fd);
+               }
+}
+
+static void layout_menu_image_forward_cb(GtkAction *action, gpointer data)
+{
+       LayoutWindow *lw = data;
+       FileData *dir_fd;
+
+       /* Obtain next image */
+       layout_set_path(lw, image_chain_forward());
+}
+
+static void layout_menu_image_back_cb(GtkAction *action, gpointer data)
+{
+       LayoutWindow *lw = data;
+       FileData *dir_fd;
+
+       /* Obtain previous image */
+       layout_set_path(lw, image_chain_back());
 }
 
 static void layout_menu_split_pane_next_cb(GtkAction *action, gpointer data)
@@ -1922,10 +1952,13 @@ static GtkActionEntry menu_entries[] = {
   { "NextImage",       GTK_STOCK_GO_DOWN,      N_("_Next Image"),                      "space",                N_("Next Image"),                       CB(layout_menu_image_next_cb) },
   { "NextImageAlt1",   GTK_STOCK_GO_DOWN,      N_("_Next Image"),                      "Page_Down",            N_("Next Image"),                       CB(layout_menu_image_next_cb) },
 
-  { "FirstPage",       GTK_STOCK_MEDIA_PREVIOUS,       N_("_First Page"),      "<control>Home",        N_( "First Page"),      CB(layout_menu_page_first_cb) },
-  { "LastPage",        GTK_STOCK_MEDIA_NEXT,   N_("_Last Page"),       "<control>End",         N_("Last Page"),        CB(layout_menu_page_last_cb) },
-  { "NextPage",        GTK_STOCK_MEDIA_FORWARD,        N_("_Next Page"),                       "<control>Page_Down",   N_("Next Page"),        CB(layout_menu_page_next_cb) },
-  { "PrevPage",        GTK_STOCK_MEDIA_REWIND, N_("_Previous Page"),   "<control>Page_Up",             N_("Previous Page"),    CB(layout_menu_page_previous_cb) },
+  { "ImageForward",    GTK_STOCK_GOTO_LAST,    N_("Image Forward"),    NULL,           N_("Image Forward"),    CB(layout_menu_image_forward_cb) },
+  { "ImageBack",       GTK_STOCK_GOTO_FIRST,   N_("Image Back"),               NULL,           N_("Image Back"),               CB(layout_menu_image_back_cb) },
+
+  { "FirstPage",       GTK_STOCK_MEDIA_PREVIOUS,       N_("_First Page"),      NULL,   N_( "First Page"),      CB(layout_menu_page_first_cb) },
+  { "LastPage",        GTK_STOCK_MEDIA_NEXT,   N_("_Last Page"),       NULL,           N_("Last Page"),        CB(layout_menu_page_last_cb) },
+  { "NextPage",        GTK_STOCK_MEDIA_FORWARD,        N_("_Next Page"),                       NULL,   N_("Next Page"),        CB(layout_menu_page_next_cb) },
+  { "PrevPage",        GTK_STOCK_MEDIA_REWIND, N_("_Previous Page"),   NULL,           N_("Previous Page"),    CB(layout_menu_page_previous_cb) },
 
 
   { "NextImageAlt2",   GTK_STOCK_GO_DOWN,      N_("_Next Image"),                      "KP_Page_Down",         N_("Next Image"),                       CB(layout_menu_image_next_cb) },
@@ -2154,6 +2187,8 @@ static const gchar *menu_ui_description =
 "      <menuitem action='PrevImage'/>"
 "      <menuitem action='NextImage'/>"
 "      <menuitem action='LastImage'/>"
+"      <menuitem action='ImageBack'/>"
+"      <menuitem action='ImageForward'/>"
 "      <separator/>"
 "      <menuitem action='Back'/>"
 "      <menuitem action='Forward'/>"
@@ -2641,39 +2676,6 @@ static void layout_actions_setup_editors(LayoutWindow *lw)
        g_list_free(editors_list);
 }
 
-static gboolean go_menu_select(GtkWidget *widget, gpointer data)
-{
-       GtkAction *action;
-       LayoutWindow *lw = data;
-
-       action = gtk_action_group_get_action(lw->action_group, "FirstPage");
-       gtk_action_set_sensitive(action, FALSE);
-       action = gtk_action_group_get_action(lw->action_group, "PrevPage");
-       gtk_action_set_sensitive(action, FALSE);
-       action = gtk_action_group_get_action(lw->action_group, "LastPage");
-       gtk_action_set_sensitive(action, FALSE);
-       action = gtk_action_group_get_action(lw->action_group, "NextPage");
-       gtk_action_set_sensitive(action, FALSE);
-
-       if (lw->image && lw->image->image_fd && lw->image->image_fd->page_total > 0)
-               {
-               if (lw->image->image_fd->page_num > 0)
-                       {
-                       action = gtk_action_group_get_action(lw->action_group, "FirstPage");
-                       gtk_action_set_sensitive(action, TRUE);
-                       action = gtk_action_group_get_action(lw->action_group, "PrevPage");
-                       gtk_action_set_sensitive(action, TRUE);
-                       }
-               if (lw->image->image_fd->page_num < (lw->image->image_fd->page_total - 1))
-                       {
-                       action = gtk_action_group_get_action(lw->action_group, "LastPage");
-                       gtk_action_set_sensitive(action, TRUE);
-                       action = gtk_action_group_get_action(lw->action_group, "NextPage");
-                       gtk_action_set_sensitive(action, TRUE);
-                       }
-               }
-}
-
 void layout_actions_setup(LayoutWindow *lw)
 {
        GError *error;
@@ -2688,10 +2690,6 @@ void layout_actions_setup(LayoutWindow *lw)
 
        gtk_action_group_add_actions(lw->action_group,
                                     menu_entries, G_N_ELEMENTS(menu_entries), lw);
-
-       action = gtk_action_group_get_action(lw->action_group, "GoMenu");
-       g_signal_connect(G_OBJECT(action), "activate", G_CALLBACK(go_menu_select), lw);
-
        gtk_action_group_add_toggle_actions(lw->action_group,
                                            menu_toggle_entries, G_N_ELEMENTS(menu_toggle_entries), lw);
        gtk_action_group_add_radio_actions(lw->action_group,
index e77b51a..472429d 100644 (file)
@@ -83,6 +83,8 @@ static const UseableToolbarItems useable_toolbar_items[] = {
        {"LastPage",    N_("Last Page"), GTK_STOCK_MEDIA_NEXT},
        {"NextPage",    N_("Next page"), GTK_STOCK_MEDIA_FORWARD},
        {"PrevPage",    N_("Previous Page"), GTK_STOCK_MEDIA_REWIND},
+       {"ImageForward",        N_("Image Forward"), GTK_STOCK_GOTO_LAST},
+       {"ImageBack",   N_("Image Back"), GTK_STOCK_GOTO_FIRST},
        {"NewWindow",   N_("New _window"), GTK_STOCK_NEW},
        {"NewCollection",       N_("New collection"), GTK_STOCK_INDEX},
        {"OpenCollection",      N_("Open collection"), GTK_STOCK_OPEN},