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;
}
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)
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;
// 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);
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.
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
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;
{
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;
};
void shift_color(GdkColor *src, gshort val, gint direction)
{
gshort cs;
+ static gshort COLOR_MAX = 0xffff;
if (val == -1)
{
{
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);
}
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);
}
}
// 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
{
}
}
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;
{
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 */
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);
}
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());