Merge pull request #497 from xsdg/cluster
authorOmari Stephens <xsdg@xsdg.org>
Tue, 11 Jul 2017 17:08:01 +0000 (17:08 +0000)
committerGitHub <noreply@github.com>
Tue, 11 Jul 2017 17:08:01 +0000 (17:08 +0000)
Adds preliminary file clustering capability

src/Makefile.am
src/filecluster.c [new file with mode: 0644]
src/filecluster.h [new file with mode: 0644]
src/typedefs.h
src/ui_tree_edit.c
src/view_file/view_file.c
src/view_file/view_file_icon.c
src/view_file/view_file_list.c

index f01fb19..f4f2f4c 100644 (file)
@@ -144,6 +144,8 @@ geeqie_SOURCES = \
        exiv2.cc        \
        filecache.c     \
        filecache.h     \
+       filecluster.c   \
+       filecluster.h   \
        filedata.c      \
        filedata.h      \
        filefilter.c    \
diff --git a/src/filecluster.c b/src/filecluster.c
new file mode 100644 (file)
index 0000000..7c5d9d0
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2008 - 2016 The Geeqie Team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 "filecluster.h"
+
+#include "filedata.h"
+
+static gboolean check_list_contains_sublist(GList *haystack, GList *needle)
+{
+       // TODO(xsdg): Optimize this!  Sort, then scan?
+       GList *h_work, *n_work;
+       for (n_work = needle; n_work; n_work = n_work->next)
+       {
+               gboolean found = FALSE;
+               for (h_work = haystack; h_work; h_work = h_work->next)
+               {
+                       if (n_work == h_work)
+                               {
+                               found = TRUE;
+                               break;
+                               }
+               }
+
+               if (!found) return FALSE;
+       }
+
+       return TRUE;
+}
+
+static gboolean filecluster_fd_equal(gconstpointer ptr_a, gconstpointer ptr_b)
+{
+       // TODO(xsdg): Is there anything we can/should do to validate inputs?
+       FileData *fd_a = (FileData *)ptr_a;
+       FileData *fd_b = (FileData *)ptr_b;
+       return !filelist_sort_compare_filedata(fd_a, fd_b);
+}
+
+// TODO(xsdg): Move this into filedata.h
+static guint filecluster_fd_hash(gconstpointer ptr)
+{
+       if (!ptr) return 1;
+       FileData *fd = (FileData *)ptr;
+       return 7 * g_str_hash(fd->original_path);
+}
+
+FileClusterList *fileclusterlist_new()
+{
+       FileClusterList *fcl = g_new0(FileClusterList, 1);
+       fcl->clusters = g_hash_table_new(&filecluster_fd_hash, &filecluster_fd_equal);
+       return fcl;
+}
+
+FileCluster *filecluster_new()
+{
+       FileCluster *fc = g_new0(FileCluster, 1);
+       fc->show_children = FALSE;
+       return fc;
+}
+
+void fileclusterlist_free(FileClusterList *fcl)
+{
+       // TODO(xsdg): don't leak stuff
+       // if (fcl->fd_list) g_list_free_full(fcl->fd_list, (GDestroyNotify)&filecluster_free);
+       g_hash_table_destroy(fcl->clusters);
+       g_free(fcl);
+}
+
+void filecluster_free(FileCluster *fc)
+{
+       filelist_free(fc->items);
+       g_free(fc);
+}
+
+gboolean filecluster_toggle_show_children(FileCluster *fc)
+{
+       fc->show_children = !fc->show_children;
+       return fc->show_children;
+}
+
+FileCluster *fileclusterlist_create_cluster(FileClusterList *fcl, GList *fd_items)
+{
+       GList *work;
+
+       // Check preconditions.
+       if (!fd_items) return NULL;
+       for (work = fd_items; work; work = work->next)
+               {
+               FileData *fd = work->data;
+               if (g_hash_table_contains(fcl->clusters, fd))
+                       {
+                       // TODO(xsdg): Show this warning in the UI.
+                       g_warning("Tried to create a cluster with a file that is already clustered.");
+                       return NULL;
+                       }
+               }
+
+       FileCluster *new_fc = filecluster_new();
+       new_fc->items = filelist_copy(fd_items);
+       new_fc->head = new_fc->items;
+
+       for (GList *item = new_fc->items; item; item = item->next)
+               {
+               FileData *fd = item->data;
+               g_hash_table_insert(fcl->clusters, fd, new_fc);
+               }
+
+       return new_fc;
+}
+
+gboolean filecluster_has_head(FileCluster *fc, FileData *fd)
+{
+       if (!fd) return FALSE;
+       return filecluster_fd_equal(fc->head->data, fd);
+}
+
+gboolean filecluster_has_child(FileCluster *fc, FileData *fd)
+{
+       if (!fd) return FALSE;
+       return !filecluster_fd_equal(fc->head->data, fd);
+}
+
+gboolean fileclusterlist_has_head(FileClusterList *fcl, FileData *fd)
+{
+       FileCluster *fc = g_hash_table_lookup(fcl->clusters, fd);
+       if (!fc) return FALSE;
+       return filecluster_has_head(fc, fd);
+}
+
+gboolean fileclusterlist_has_child(FileClusterList *fcl, FileData *fd)
+{
+       FileCluster *fc = g_hash_table_lookup(fcl->clusters, fd);
+       if (!fc) return FALSE;
+       return filecluster_has_child(fc, fd);
+}
+
+static gboolean fileclusterlist_should_hide(FileClusterList *fcl, FileData *fd)
+{
+       FileCluster *fc = g_hash_table_lookup(fcl->clusters, fd);
+       if (!fc) return FALSE;
+       // Only difference vs. fileclusterlist_has_child.  Basically, if the node is a child, but
+       // we're showing children, then don't hide.
+       if (fc->show_children) return FALSE;
+       return filecluster_has_child(fc, fd);
+}
+
+// TODO(xsdg): pick a better name for this function
+GList *fileclusterlist_next_non_child(FileClusterList *fcl, GList *list)
+{
+       // Check for no-ops
+       if (!list || !g_hash_table_size(fcl->clusters)) return list;
+
+       // Clusters are being used, so we have to actually check things.
+       for (; list; list = list->next)
+       {
+               FileData *fd = list->data;
+               if (!fileclusterlist_has_child(fcl, fd)) return list;
+       }
+
+       return NULL;
+}
+
+GList *fileclusterlist_remove_children_from_list(FileClusterList *fcl, GList *list)
+{
+       GList *work = list;
+
+       while (work)
+       {
+               FileData *fd = work->data;
+               GList *link = work;
+               // Advance early in case link needs to be removed/freed.
+               work = work->next;
+
+               if (fileclusterlist_should_hide(fcl, fd))
+               {
+                       list = g_list_remove_link(list, link);
+                       file_data_unref(fd);
+                       g_list_free(link);
+               }
+       }
+
+       return list;
+}
+
+/* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */
diff --git a/src/filecluster.h b/src/filecluster.h
new file mode 100644 (file)
index 0000000..d63ee03
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2008 - 2016 The Geeqie Team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ */
+
+#ifndef FILECLUSTER_H
+#define FILECLUSTER_H
+
+#include "main.h"
+
+// FileCluster methods.
+FileCluster *filecluster_new();  // internal?
+void filecluster_free(FileCluster *fc);
+
+gboolean filecluster_toggle_show_children(FileCluster *fc);
+gboolean filecluster_has_head(FileCluster *fc, FileData *fd);
+gboolean filecluster_has_child(FileCluster *fc, FileData *fd);
+
+
+// FileClusterList methods.
+
+FileClusterList *fileclusterlist_new();
+void fileclusterlist_free(FileClusterList *fcl);
+
+// Creates a cluster with items that must already be in the cluster list.  Will fail (and make no
+// changes) if any of the specified items isn't in the list, or if any of the items is already
+// part of a different cluster.
+FileCluster *fileclusterlist_create_cluster(FileClusterList *fcl, GList *fd_items);
+
+gboolean fileclusterlist_has_head(FileClusterList *fcl, FileData *fd);
+gboolean fileclusterlist_has_child(FileClusterList *fcl, FileData *fd);
+
+GList *fileclusterlist_next_non_child(FileClusterList *fcl, GList *list);
+GList *fileclusterlist_remove_children_from_list(FileClusterList *fcl, GList *list);
+
+#endif  // FILECLUSTER_H
+
+/* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */
index 9d7db51..fcf2d69 100644 (file)
@@ -256,7 +256,9 @@ typedef enum {
        SELECTION_NONE          = 0,
        SELECTION_SELECTED      = 1 << 0,
        SELECTION_PRELIGHT      = 1 << 1,
-       SELECTION_FOCUS         = 1 << 2
+       SELECTION_FOCUS         = 1 << 2,
+       SELECTION_CLUSTER_HEAD  = 1 << 3,
+       SELECTION_CLUSTER_CHILD = 1 << 4
 } SelectionType;
 
 typedef struct _ImageLoader ImageLoader;
@@ -271,6 +273,9 @@ typedef struct _CollectWindow CollectWindow;
 
 typedef struct _ImageWindow ImageWindow;
 
+typedef struct _FileCluster FileCluster;
+typedef struct _FileClusterList FileClusterList;
+
 typedef struct _FileData FileData;
 typedef struct _FileDataChangeInfo FileDataChangeInfo;
 
@@ -529,6 +534,20 @@ struct _ImageWindow
        gboolean mouse_wheel_mode;
 };
 
+// A FileCluster is a GList with HashTable access to each node (to perform contains() checks quickly).
+struct _FileCluster
+{
+       GList *head;
+       GList *items;
+       gboolean show_children;
+};
+
+struct _FileClusterList
+{
+       // A map from any clustered FileData to the FileCluster object that describes the cluster.
+       GHashTable *clusters;
+};
+
 #define FILEDATA_MARKS_SIZE 6
 
 struct _FileDataChangeInfo {
@@ -843,6 +862,7 @@ struct _ViewFile
 
        FileData *dir_fd;
        GList *list;
+       FileClusterList *cluster_list;
 
        SortType sort_method;
        gboolean sort_ascend;
index 0fe4b23..464a0ad 100644 (file)
@@ -496,6 +496,7 @@ gint tree_path_to_row(GtkTreePath *tpath)
 void shift_color(GdkColor *src, gshort val, gint direction)
 {
        gshort cs;
+       static gshort COLOR_MAX = 0xffff;
 
        if (val == -1)
                {
@@ -505,11 +506,11 @@ void shift_color(GdkColor *src, gshort val, gint direction)
                {
                val = CLAMP(val, 1, 100);
                }
-       cs = 0xffff / 100 * val;
+       cs = COLOR_MAX / 100 * val;
 
        /* up or down ? */
        if (direction < 0 ||
-           (direction == 0 &&((gint)src->red + (gint)src->green + (gint)src->blue) / 3 > 0xffff / 2))
+           (direction == 0 &&((gint)src->red + (gint)src->green + (gint)src->blue) / 3 > COLOR_MAX / 2))
                {
                src->red = MAX(0 , src->red - cs);
                src->green = MAX(0 , src->green - cs);
@@ -517,9 +518,9 @@ void shift_color(GdkColor *src, gshort val, gint direction)
                }
        else
                {
-               src->red = MIN(0xffff, src->red + cs);
-               src->green = MIN(0xffff, src->green + cs);
-               src->blue = MIN(0xffff, src->blue + cs);
+               src->red = MIN(COLOR_MAX, src->red + cs);
+               src->green = MIN(COLOR_MAX, src->green + cs);
+               src->blue = MIN(COLOR_MAX, src->blue + cs);
                }
 }
 
index c9dbdef..97fafae 100644 (file)
@@ -25,6 +25,7 @@
 #include "collect.h"
 #include "collect-table.h"
 #include "editors.h"
+#include "filecluster.h"
 #include "layout.h"
 #include "menu.h"
 #include "thumb.h"
@@ -673,6 +674,7 @@ static void vf_destroy_cb(GtkWidget *widget, gpointer data)
                gtk_widget_destroy(vf->popup);
                }
 
+       fileclusterlist_free(vf->cluster_list);
        file_data_unref(vf->dir_fd);
        g_free(vf->info);
        g_free(vf);
@@ -729,6 +731,7 @@ ViewFile *vf_new(FileViewType type, FileData *dir_fd)
        gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(vf->scrolled),
                                       GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
 
+       vf->cluster_list = fileclusterlist_new();
        vf->filter = vf_marks_filter_init(vf);
 
        vf->widget = gtk_vbox_new(FALSE, 0);
index b60074c..cd5d05c 100644 (file)
@@ -30,6 +30,7 @@
 #include "dnd.h"
 #include "editors.h"
 #include "img-view.h"
+#include "filecluster.h"
 #include "filedata.h"
 #include "layout.h"
 #include "layout_image.h"
@@ -1250,6 +1251,63 @@ gboolean vficon_press_key_cb(GtkWidget *widget, GdkEventKey *event, gpointer dat
                        vf->popup = vf_pop_menu(vf);
                        gtk_menu_popup(GTK_MENU(vf->popup), NULL, NULL, vfi_menu_position_cb, vf, 0, GDK_CURRENT_TIME);
                        break;
+               case GDK_KEY_Insert:
+                       // DO NOT SUBMIT
+                       // TODO(xsdg): make an actual UX for this.
+                       g_warning("Starting a cluster!");
+                       fd = vficon_find_data(vf, VFICON(vf)->focus_row, VFICON(vf)->focus_column, NULL);
+                       if (fd)
+                               {
+                               // Make a cluster out of the entire selection
+                               if (VFICON(vf)->selection && VFICON(vf)->selection->next)
+                                       {
+                                       FileCluster *fc;
+                                       // At least two items selected; go for it.
+                                       g_warning("Had requisite number of selection items; going for it!");
+                                       fc = fileclusterlist_create_cluster(vf->cluster_list, VFICON(vf)->selection);
+                                       if (fc)
+                                               {
+                                               vficon_selection_add(vf, VFICON(vf)->selection->data, SELECTION_CLUSTER_HEAD, NULL);
+                                               vf_refresh(vf);
+                                               }
+                                       }
+                               else
+                                       {
+                                       if (VFICON(vf)->selection)
+                                               {
+                                               g_warning("Only one item selected; need at least two.");
+                                               }
+                                       else
+                                               {
+                                               g_warning("No items selected; need at least two.");
+                                               }
+                                       }
+                               }
+                       break;
+               case GDK_KEY_F2:
+                       g_warning("Flipping show_children!");
+                       fd = vficon_find_data(vf, VFICON(vf)->focus_row, VFICON(vf)->focus_column, NULL);
+                       if (fd)
+                               {
+                               FileCluster *fc = g_hash_table_lookup(vf->cluster_list->clusters, fd);
+                               if (fc)
+                                       {
+                                       if (filecluster_toggle_show_children(fc))
+                                               {
+                                               for (GList *work = fc->items; work; work = work->next)
+                                                       {
+                                                       // TODO(xsdg): This is broken because the FileData pointer stored in the
+                                                       // cluster is different from the one just added to vf->list, even though
+                                                       // they are equivalent.
+                                                       FileData *fd = work->data;
+                                                       if (work == fc->head) continue;
+                                                       vficon_selection_add(vf, fd, SELECTION_CLUSTER_CHILD, NULL);
+                                                       }
+                                               }
+                                       vf_refresh(vf);
+                                       }
+                               }
+                       break;
                default:
                        stop_signal = FALSE;
                        break;
@@ -1796,9 +1854,11 @@ static gboolean vficon_refresh_real(ViewFile *vf, gboolean keep_position)
                {
                ret = filelist_read(vf->dir_fd, &new_filelist, NULL);
                new_filelist = file_data_filter_marks_list(new_filelist, vf_marks_get_filter(vf));
+               new_filelist = fileclusterlist_remove_children_from_list(vf->cluster_list, new_filelist);
                }
 
-       vf->list = filelist_sort(vf->list, vf->sort_method, vf->sort_ascend); /* the list might not be sorted if there were renames */
+       /* the list might not be sorted if there were renames */
+       vf->list = filelist_sort(vf->list, vf->sort_method, vf->sort_ascend);
        new_filelist = filelist_sort(new_filelist, vf->sort_method, vf->sort_ascend);
 
        if (VFICON(vf)->selection)
@@ -1972,6 +2032,21 @@ static void vficon_cell_data_cb(GtkTreeViewColumn *tree_column, GtkCellRenderer
                memcpy(&color_fg, &style->text[state], sizeof(color_fg));
                memcpy(&color_bg, &style->base[state], sizeof(color_bg));
 
+               if (fd->selected & SELECTION_CLUSTER_HEAD)
+                       {
+                       // TODO(xsdg): Cluster coloration should be part of the style.
+                       color_bg.blue = 0x4000;
+                       color_bg.green = 0x4000;
+                       color_bg.red = 0xFFFF;
+                       }
+               else if (fd->selected & SELECTION_CLUSTER_CHILD)
+                       {
+                       // TODO(xsdg): Cluster coloration should be part of the style.
+                       color_bg.blue = 0x8000;
+                       color_bg.green = 0x8000;
+                       color_bg.red = 0xFFFF;
+                       }
+
                if (fd->selected & SELECTION_PRELIGHT)
                        {
                        shift_color(&color_bg, -1, 0);
index b56a025..5e02c39 100644 (file)
@@ -27,6 +27,7 @@
 #include "dnd.h"
 #include "editors.h"
 #include "img-view.h"
+#include "filecluster.h"
 #include "layout.h"
 #include "layout_image.h"
 #include "menu.h"
@@ -497,6 +498,77 @@ gboolean vflist_press_key_cb(GtkWidget *widget, GdkEventKey *event, gpointer dat
        ViewFile *vf = data;
        GtkTreePath *tpath;
 
+       // DO NOT SUBMIT
+       // TODO(xsdg): these key combos should be handled by the standard, configurable mechanism.
+
+       if (event->keyval == GDK_KEY_Insert || event->keyval == GDK_KEY_F2)
+               {
+               // First off, get the selected FDs
+               GList *selected_fds = NULL;
+                       {
+                       GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
+                       if (event->keyval == GDK_KEY_Insert)
+                               {
+                               if (gtk_tree_selection_count_selected_rows(selection) < 2)
+                                       {
+                                       g_warning("Need at least two items selected to create a cluster.");
+                                       return TRUE;
+                                       }
+                               }
+                       else
+                               {
+                               if (gtk_tree_selection_count_selected_rows(selection) < 1)
+                                       {
+                                       g_warning("Must have a node selected to flip show_children.");
+                                       return TRUE;
+                                       }
+                               }
+
+                       // List of GtkTreePath
+                       GList *selected_rows = gtk_tree_selection_get_selected_rows(selection, NULL);
+                       GtkTreeModel *store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
+                       GtkTreeIter iter;
+                       for (GList *work = selected_rows; work; work = work->next)
+                               {
+                               FileData *fd;
+                               GtkTreePath *select_path = work->data;
+                               gtk_tree_model_get_iter(store, &iter, select_path);
+                               gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
+                               selected_fds = g_list_prepend(selected_fds, file_data_ref(fd));
+                               }
+
+                       selected_fds = g_list_reverse(selected_fds);
+                       g_list_free_full(selected_rows, (GDestroyNotify)gtk_tree_path_free);
+                       }
+
+               if (event->keyval == GDK_KEY_Insert)
+                       {
+                       g_warning("Starting a cluster!");
+                       FileCluster *fc = fileclusterlist_create_cluster(vf->cluster_list, selected_fds);
+                       if (fc)
+                               {
+                               // TODO(xsdg): mark as in a cluster somehow?
+                               vf_refresh(vf);
+                               }
+                       }
+               else if (event->keyval == GDK_KEY_F2)
+                       {
+                       FileData *fd = selected_fds->data;
+                       if (fd)
+                               {
+                               g_warning("Flipping show_children!");
+                               FileCluster *fc = g_hash_table_lookup(vf->cluster_list->clusters, fd);
+                               if (fc)
+                                       {
+                                       filecluster_toggle_show_children(fc);
+                                       vf_refresh(vf);
+                                       }
+                               }
+                       }
+
+               return TRUE;  // Handled event; stop propagating.
+               }
+
        if (event->keyval != GDK_KEY_Menu) return FALSE;
 
        gtk_tree_view_get_cursor(GTK_TREE_VIEW(vf->listview), &tpath, NULL);
@@ -909,9 +981,14 @@ static void vflist_setup_iter_recursive(ViewFile *vf, GtkTreeStore *store, GtkTr
                                else
                                        {
                                        if (parent_iter)
-                                               match = filelist_sort_compare_filedata_full(fd, old_fd, SORT_NAME, TRUE); /* always sort sidecars by name */
+                                               {
+                                               /* always sort sidecars by name */
+                                               match = filelist_sort_compare_filedata_full(fd, old_fd, SORT_NAME, TRUE);
+                                               }
                                        else
+                                               {
                                                match = filelist_sort_compare_filedata_full(fd, old_fd, vf->sort_method, vf->sort_ascend);
+                                               }
 
                                        if (match == 0) g_warning("multiple fd for the same path");
                                        }
@@ -1668,6 +1745,7 @@ gboolean vflist_refresh(ViewFile *vf)
                        }
 
                vf->list = file_data_filter_marks_list(vf->list, vf_marks_get_filter(vf));
+               vf->list = fileclusterlist_remove_children_from_list(vf->cluster_list, vf->list);
                file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
 
                DEBUG_1("%s vflist_refresh: sort", get_exec_time());
@@ -1729,8 +1807,43 @@ static void vflist_listview_color_cb(GtkTreeViewColumn *tree_column, GtkCellRend
 {
        ViewFile *vf = data;
        gboolean set;
+       FileData *fd;
 
        gtk_tree_model_get(tree_model, iter, FILE_COLUMN_COLOR, &set, -1);
+       gtk_tree_model_get(tree_model, iter, FILE_COLUMN_POINTER, &fd, -1);
+       // TODO(xsdg): optimize!
+       if (fd)
+               {
+               FileCluster *fc = g_hash_table_lookup(vf->cluster_list->clusters, fd);
+               if (fc)
+                       {
+                       if (filecluster_has_head(fc, fd))
+                               {
+                               GdkColor *color_bg = g_new0(GdkColor, 1);
+                               color_bg->blue = 0x4000;
+                               color_bg->green = 0x4000;
+                               color_bg->red = 0xFFFF;
+
+                               g_object_set(G_OBJECT(cell),
+                                                "cell-background-gdk", color_bg,
+                                                "cell-background-set", TRUE, NULL);
+                               return;
+                               }
+                       else if (filecluster_has_child(fc, fd))
+                               {
+                               GdkColor *color_bg = g_new0(GdkColor, 1);
+                               color_bg->blue = 0x8000;
+                               color_bg->green = 0x8000;
+                               color_bg->red = 0xFFFF;
+
+                               g_object_set(G_OBJECT(cell),
+                                                "cell-background-gdk", color_bg,
+                                                "cell-background-set", TRUE, NULL);
+                               return;
+                               }
+                       }
+               }
+
        g_object_set(G_OBJECT(cell),
                     "cell-background-gdk", vflist_listview_color_shifted(vf->listview),
                     "cell-background-set", set, NULL);