Uses custom hash/equals functions so that we can actually fetch equivalent FileDatas...
authorOmari Stephens <xsdg@google.com>
Sun, 9 Jul 2017 01:40:49 +0000 (01:40 +0000)
committerOmari Stephens <xsdg@google.com>
Mon, 10 Jul 2017 08:00:55 +0000 (08:00 +0000)
src/filecluster.c
src/filecluster.h
src/typedefs.h
src/ui_tree_edit.c
src/view_file/view_file_icon.c
src/view_file/view_file_list.c

index a8cb22d..2b7ebcc 100644 (file)
@@ -42,37 +42,60 @@ static gboolean check_list_contains_sublist(GList *haystack, GList *needle)
        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(&g_direct_hash, &g_direct_equal);
+       fcl->clusters = g_hash_table_new(&filecluster_fd_hash, &filecluster_fd_equal);
 }
 
 FileCluster *filecluster_new()
 {
        FileCluster *fc = g_new0(FileCluster, 1);
+       fc->show_children = FALSE;
 }
 
 void fileclusterlist_free(FileClusterList *fcl)
 {
-       if (fcl->fd_list) g_list_free_full(fcl->fd_list, (GDestroyNotify)&filecluster_free);
+       // 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;
-       // TODO(xsdg): Is this actually necessary?
-       // if (!check_list_contains_sublist(fcl->fd_list, fd_items)) return NULL;
        for (work = fd_items; work; work = work->next)
                {
                FileData *fd = work->data;
@@ -85,7 +108,7 @@ FileCluster *fileclusterlist_create_cluster(FileClusterList *fcl, GList *fd_item
                }
 
        FileCluster *new_fc = filecluster_new();
-       new_fc->items = g_list_copy(fd_items);
+       new_fc->items = filelist_copy(fd_items);
        new_fc->head = new_fc->items;
 
        for (GList *item = new_fc->items; item; item = item->next)
@@ -111,7 +134,31 @@ gboolean fileclusterlist_has_child(FileClusterList *fcl, FileData *fd)
        return fc->head->data != fd;
 }
 
-GList *filecluster_remove_children_from_list(FileClusterList *fcl, GList *list)
+static gboolean fileclusterlist_should_hide(FileClusterList *fcl, FileData *fd)
+{
+       FileCluster *fc = g_hash_table_lookup(fcl->clusters, fd);
+       if (!fc) return FALSE;
+       if (fc->show_children) return FALSE;  // TODO(xsdg): new function "should_show"
+       return fc->head->data != 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;
 
@@ -122,7 +169,7 @@ GList *filecluster_remove_children_from_list(FileClusterList *fcl, GList *list)
                // Advance early in case link needs to be removed/freed.
                work = work->next;
 
-               if (fileclusterlist_has_child(fcl, fd))
+               if (fileclusterlist_should_hide(fcl, fd))
                {
                        list = g_list_remove_link(list, link);
                        file_data_unref(fd);
index 3b2956d..660f5eb 100644 (file)
@@ -26,6 +26,8 @@ FileCluster *filecluster_new();  // internal?
 void fileclusterlist_free(FileClusterList *fcl);
 void filecluster_free(FileCluster *fc);
 
+gboolean filecluster_toggle_show_children(FileCluster *fc);
+
 // 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.
@@ -34,6 +36,7 @@ FileCluster *fileclusterlist_create_cluster(FileClusterList *fcl, GList *fd_item
 gboolean fileclusterlist_has_head(FileClusterList *fcl, FileData *fd);
 gboolean fileclusterlist_has_child(FileClusterList *fcl, FileData *fd);
 
-GList *filecluster_remove_children_from_list(FileClusterList *fcl, GList *list);
+GList *fileclusterlist_next_non_child(FileClusterList *fcl, GList *list);
+GList *fileclusterlist_remove_children_from_list(FileClusterList *fcl, GList *list);
 
 #endif  // FILECLUSTER_H
index cbaf56d..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;
@@ -537,13 +539,11 @@ struct _FileCluster
 {
        GList *head;
        GList *items;
+       gboolean show_children;
 };
 
 struct _FileClusterList
 {
-       // All of the elements in the list, regardless of whether they're part of a cluster or not.
-       GList *fd_list;
-
        // A map from any clustered FileData to the FileCluster object that describes the cluster.
        GHashTable *clusters;
 };
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 e3ab038..c2a423b 100644 (file)
@@ -1261,9 +1261,16 @@ gboolean vficon_press_key_cb(GtkWidget *widget, GdkEventKey *event, gpointer dat
                                // 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!");
-                                       fileclusterlist_create_cluster(vf->cluster_list, VFICON(vf)->selection);
+                                       fc = fileclusterlist_create_cluster(vf->cluster_list, VFICON(vf)->selection);
+                                       if (fc)
+                                               {
+                                               // TODO(xsdg): set CLUSTER_CHILD
+                                               vficon_selection_add(vf, VFICON(vf)->selection->data, SELECTION_CLUSTER_HEAD, NULL);
+                                               vf_refresh(vf);
+                                               }
                                        }
                                else
                                        {
@@ -1278,6 +1285,19 @@ gboolean vficon_press_key_cb(GtkWidget *widget, GdkEventKey *event, gpointer dat
                                        }
                                }
                        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)
+                                       {
+                                       filecluster_toggle_show_children(fc);
+                                       vf_refresh(vf);
+                                       }
+                               }
+                       break;
                default:
                        stop_signal = FALSE;
                        break;
@@ -1824,7 +1844,7 @@ 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 = filecluster_remove_children_from_list(vf->cluster_list, new_filelist);
+               new_filelist = fileclusterlist_remove_children_from_list(vf->cluster_list, new_filelist);
                }
 
        /* the list might not be sorted if there were renames */
@@ -2002,6 +2022,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 15a71c5..86cb612 100644 (file)
@@ -1669,7 +1669,7 @@ gboolean vflist_refresh(ViewFile *vf)
                        }
 
                vf->list = file_data_filter_marks_list(vf->list, vf_marks_get_filter(vf));
-               vf->list = filecluster_remove_children_from_list(vf->cluster_list, vf->list);
+               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());