[gegl] bin: add support for custom collection order and per file key/values
- From: Øyvind "pippin" Kolås <ok src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl] bin: add support for custom collection order and per file key/values
- Date: Wed, 10 Apr 2019 12:35:33 +0000 (UTC)
commit b4d2fa11a7a0d470b54e4ff88fdc34074ed31a54
Author: Øyvind Kolås <pippin gimp org>
Date: Sat Apr 6 05:35:36 2019 +0200
bin: add support for custom collection order and per file key/values
Add a filesystem based key/value store, and custom folder ordering that exist
in the per folder .gegl subfolder, which already contains the thumbnails.
For now there is no UI that permits creating a custom order, but creating
a file .gegl/index and having the filenames in the desired order, with
possible duplicates - will make gegl use the order provided in the file.
bin/lua/init.lua | 2 +
bin/ui-collection.c | 36 ++-
bin/ui-core.c | 809 ++++++++++++++++++++++++++++++++++++++++++++++++++--
bin/ui-viewer.c | 66 +++--
bin/ui.h | 148 ++++++++--
5 files changed, 987 insertions(+), 74 deletions(-)
---
diff --git a/bin/lua/init.lua b/bin/lua/init.lua
index 50a5dee05..1c1a9cc9c 100644
--- a/bin/lua/init.lua
+++ b/bin/lua/init.lua
@@ -30,6 +30,8 @@ struct _GeState {
the file that is written to on save. This differs depending
on type of input file.
*/
+ GList *index;
+ int index_dirty;
GList *paths; /* list of full paths to entries in collection/path/containing path,
XXX: could be replaced with URIs, and each
element should perhaps contain more internal info
diff --git a/bin/ui-collection.c b/bin/ui-collection.c
index 8fd545f3d..7ab72ea4f 100644
--- a/bin/ui-collection.c
+++ b/bin/ui-collection.c
@@ -93,6 +93,10 @@ static void entry_load (MrgEvent *event, void *data1, void *data2)
g_free (o->path);
o->path = g_strdup (data2);
ui_load_path (o);
+
+ //
+
+
mrg_event_stop_propagate (event);
mrg_queue_draw (event->mrg, NULL);
}
@@ -172,8 +176,9 @@ static void on_dir_drag (MrgEvent *e, void *data1, void *data2)
}
}
+ /* auto-center */
{
- int count = g_list_length (o->paths);
+ int count = g_list_length (o->paths) + g_list_length (o->index);
if (o->v < 0)
o->v = 0;
if (o->v > count/hack_cols * hack_dim - mrg_height(e->mrg)/2)
@@ -228,7 +233,7 @@ static void on_dir_scroll_drag (MrgEvent *e, void *data1, void *data2)
break;
case MRG_DRAG_MOTION:
{
- int count = g_list_length (o->paths);
+ int count = g_list_length (o->paths) + g_list_length (o->index);
float height = mrg_height (e->mrg);
#if 0
y = height * ( o->v / (count/hack_cols * hack_dim) )
@@ -256,7 +261,6 @@ void ui_collection (GeState *o)
{
Mrg *mrg = o->mrg;
cairo_t *cr = mrg_cr (mrg);
- GList *iter;
float dim;
int cols;
int no = 0;
@@ -269,8 +273,7 @@ void ui_collection (GeState *o)
cols = hack_cols;
dim = hack_dim;
- count = g_list_length (o->paths);
-
+ count = g_list_length (o->paths) + g_list_length (o->index);
cairo_save (cr);
cairo_translate (cr, 0, -(int)o->v);
@@ -306,18 +309,23 @@ void ui_collection (GeState *o)
no++;
}
- for (iter = o->paths; iter; iter=iter->next, no++)
+ for (int idx = 0; idx < count; idx ++, no++)
{
+ char *basename = meta_get_child (o, o->path, idx);
struct stat stat_buf;
int w, h;
- gchar *path = iter->data;
+ gchar *path = g_strdup_printf ("%s/%s", o->path, basename);
char *lastslash = strrchr (path, '/');
float x = dim * (no%cols);
float y = dim * (no/cols);
int is_dir = 0;
+ g_free (basename);
if (y < -dim * 4 + o->v || y > mrg_height (mrg) + dim * 1.5 + o->v)
+ {
+ g_free (path);
continue;
+ }
lstat (path, &stat_buf);
@@ -394,7 +402,7 @@ void ui_collection (GeState *o)
cairo_fill_preserve (mrg_cr (mrg));
}
- mrg_listen (mrg, MRG_TAP, entry_load, o, (void*)g_intern_string (iter->data));
+ mrg_listen (mrg, MRG_TAP, entry_load, o, (void*)g_intern_string (path));
cairo_new_path (mrg_cr (mrg));
if (w!=0 && h!=0)
@@ -430,10 +438,11 @@ void ui_collection (GeState *o)
cairo_stroke_preserve (mrg_cr(mrg));
#endif
if (no == o->entry_no + 1)
- mrg_listen_full (mrg, MRG_TAP, entry_load, o, path, NULL, NULL);
+ mrg_listen_full (mrg, MRG_TAP, entry_load, o, (void*)g_intern_string (path), NULL, NULL);
else
mrg_listen_full (mrg, MRG_TAP, entry_select, o, GINT_TO_POINTER(no-1), NULL, NULL);
cairo_new_path (mrg_cr(mrg));
+ g_free (path);
}
cairo_restore (cr);
@@ -503,7 +512,7 @@ int cmd_collection (COMMAND_ARGS); /* "collection", -1, "<up|left|right|down|fir
}
else if (!strcmp(argv[1], "last"))
{
- o->entry_no = g_list_length (o->paths)-1;
+ o->entry_no = g_list_length (o->paths) + g_list_length (o->index)-1;
}
else if (!strcmp(argv[1], "right"))
{
@@ -525,9 +534,8 @@ int cmd_collection (COMMAND_ARGS); /* "collection", -1, "<up|left|right|down|fir
if (o->entry_no < -1)
o->entry_no = -1;
- if (o->entry_no >= (int)g_list_length (o->paths))
- o->entry_no = g_list_length (o->paths)-1;
-
+ if (o->entry_no >= (int)(g_list_length (o->paths) + g_list_length (o->index)))
+ o->entry_no = g_list_length (o->paths) + g_list_length (o->index)-1;
ui_center_active_entry (o);
@@ -549,5 +557,3 @@ void ui_center_active_entry (GeState *o)
pos < o->v)
o->v = hack_dim * (row) - mrg_height (o->mrg)/2 + hack_dim;
}
-
-
diff --git a/bin/ui-core.c b/bin/ui-core.c
index d6ec0a3b5..90a22f548 100644
--- a/bin/ui-core.c
+++ b/bin/ui-core.c
@@ -502,6 +502,28 @@ gchar *ui_get_thumb_path (const char *path)
return ret;
}
+gchar *ui_get_metadata_path (const char *path);
+gchar *
+ui_get_metadata_path (const char *path)
+{
+ gchar *ret;
+ gchar *basename = g_path_get_basename (path);
+ gchar *dirname = g_path_get_dirname (path);
+ ret = g_strdup_printf ("%s/.gegl/%s/metadata", dirname, basename);
+ g_free (basename);
+ g_free (dirname);
+ return ret;
+}
+
+gchar *ui_get_index_path (const char *path);
+gchar *
+ui_get_index_path (const char *path)
+{
+ gchar *ret;
+ ret = g_strdup_printf ("%s/.gegl/index", path);
+ return ret;
+}
+
static void get_coords (GeState *o, float screen_x, float screen_y,
@@ -523,6 +545,9 @@ static int str_has_visual_suffix (char *path)
return gegl_str_has_image_suffix (path) || gegl_str_has_video_suffix (path);
}
+static int
+index_contains (GeState *state,
+ const char *name);
static void populate_path_list (GeState *o)
{
@@ -554,7 +579,7 @@ static void populate_path_list (GeState *o)
for (i = 0; i < n; i++)
{
- if (namelist[i]->d_name[0] != '.')
+ if (namelist[i]->d_name[0] != '.' && !index_contains (o, namelist[i]->d_name))
{
gchar *fpath = g_strdup_printf ("%s/%s", path, namelist[i]->d_name);
lstat (fpath, &stat_buf);
@@ -570,6 +595,7 @@ static void populate_path_list (GeState *o)
for (i = 0; i < n; i++)
{
if (namelist[i]->d_name[0] != '.' &&
+ !index_contains (o, namelist[i]->d_name) &&
str_has_visual_suffix (namelist[i]->d_name))
{
gchar *fpath = g_strdup_printf ("%s/%s", path, namelist[i]->d_name);
@@ -649,6 +675,10 @@ static char *sh_esc (const char *input)
}
#endif
+static void
+load_index (GeState *state, const char *path);
+static void
+store_index (GeState *state, const char *path);
static void load_path_inner (GeState *o, char *path);
@@ -790,8 +820,10 @@ static gpointer renderer_thread (gpointer data)
static char *binary_relative_data_dir = NULL;
+#ifdef HAVE_LUA
static char *
resolve_lua_file (const char *basename);
+#endif
int mrg_ui_main (int argc, char **argv, char **ops)
{
@@ -883,6 +915,28 @@ int mrg_ui_main (int argc, char **argv, char **ops)
#endif
ui_load_path (o);
+
+ {
+ int no = 0;
+ char *basename = g_path_get_basename (o->path);
+ o->entry_no = 0;
+ for (GList *iter = o->index; iter && !o->entry_no; iter = iter->next, no++)
+ {
+ IndexItem *item = iter->data;
+ if (!strcmp (item->name, basename))
+ o->entry_no = no;
+ }
+ for (GList *iter = o->paths; iter && !o->entry_no; iter = iter->next, no++)
+ {
+ if (!strcmp (iter->data, o->path))
+ o->entry_no = no;
+ }
+ g_free (basename);
+
+
+ }
+
+
mrg_set_ui (mrg, gegl_ui, o);
on_viewer_motion (NULL, o, NULL);
@@ -933,7 +987,7 @@ cmd_thumb (COMMAND_ARGS)
/* protect against some possible repeated requests to generate the same thumb
*/
if (g_file_test (thumbpath, G_FILE_TEST_EXISTS))
- return -1;
+ return 0;
{
char *dirname = g_path_get_dirname (thumbpath);
@@ -1891,12 +1945,14 @@ static void update_string (const char *new_text, void *data)
strcpy (str, new_text);
}
+#ifdef HAVE_LUA
static void update_string2 (const char *new_text, void *data)
{
char **str = data;
g_free (*str);
*str = g_strdup (new_text);
}
+#endif
static void
draw_property_int (GeState *o, Mrg *mrg, GeglNode *node, const GParamSpec *pspec)
@@ -3926,9 +3982,14 @@ static void do_commandline_run (MrgEvent *event, void *data1, void *data2)
}
else
{
- g_free (o->path);
- o->path = g_strdup (g_list_nth_data (o->paths, o->entry_no));
+ char *basedir = o->path;
+ char *basename = meta_get_child (o, basedir, o->entry_no);
+ o->path = g_strdup_printf ("%s/%s", basedir, basename);
+ g_free (basedir);
+ g_free (basename);
ui_load_path (o);
+ if (g_file_test (o->path, G_FILE_TEST_IS_DIR))
+ o->entry_no = 0;
}
}
else
@@ -4623,7 +4684,7 @@ static cairo_matrix_t node_get_relative_transform (GeglNode *node_view,
/* given a basename return fully qualified path, searching through
* posisble locations, return NULL if not found.
*/
-
+#ifdef HAVE_LUA
static char *
resolve_lua_file2 (const char *basepath, gboolean add_gegl, const char *basename)
{
@@ -4642,7 +4703,8 @@ resolve_lua_file2 (const char *basepath, gboolean add_gegl, const char *basename
g_free (path);
return NULL;
}
-
+#endif
+#ifdef HAVE_LUA
static char *
resolve_lua_file (const char *basename)
{
@@ -4665,6 +4727,7 @@ resolve_lua_file (const char *basename)
return ret;
}
+#endif
static gboolean run_lua_file (const char *basename)
@@ -5175,6 +5238,13 @@ static void load_path_inner (GeState *o,
char *path)
{
char *meta;
+ if (o->save_path)
+ {
+ if (o->index_dirty)
+ store_index (o, o->save_path);
+ }
+
+
if (o->src_path)
{
if (lui_contents)
@@ -5223,6 +5293,7 @@ static void load_path_inner (GeState *o,
o->src_path = g_strdup (path);
}
}
+ load_index (o, o->path);
if (access (o->save_path, F_OK) != -1)
{
@@ -5402,10 +5473,10 @@ void ui_load_path (GeState *o)
thumb_queue_item_free (item);
}
- populate_path_list (o);
o->playing = 0;
load_path_inner (o, o->path);
+ populate_path_list (o);
{
struct stat stat_buf;
@@ -5417,9 +5488,12 @@ void ui_load_path (GeState *o)
else
zoom_to_fit (o);
}
+ //if (S_ISDIR (stat_buf.st_mode))
+ //{
+ // o->entry_no = -1;
+ //}
}
- o->entry_no = -1;
o->scale = 1.0;
o->u = 0;
o->v = 0;
@@ -6371,20 +6445,27 @@ int cmd_discard (COMMAND_ARGS) /* "discard", 0, "", "moves the current image to
char *old_path;
char *tmp;
char *lastslash;
- char *path = o->path;
if (o->is_dir)
{
- path = g_list_nth_data (o->paths, o->entry_no);
+ char *basedir = o->path;
+ char *basename = meta_get_child (o, basedir, o->entry_no);
+ g_free (o->path);
+ old_path = g_strdup_printf ("%s/%s", basedir, basename);
+ g_free (basename);
}
+ else
+ old_path = g_strdup (o->path);
- old_path = g_strdup (path);
if (!o->is_dir)
{
- argvs_eval ("next");
- if (!strcmp (old_path, o->path))
+ if (o->entry_no == g_list_length (o->index) + g_list_length(o->paths)-1)
{
argvs_eval ("prev");
}
+ else
+ {
+ argvs_eval ("next");
+ }
}
tmp = g_strdup (old_path);
lastslash = strrchr (tmp, '/');
@@ -6714,20 +6795,23 @@ cmd_clear (COMMAND_ARGS)
int cmd_next (COMMAND_ARGS) /* "next", 0, "", "next sibling element in current collection/folder"*/
{
GeState *o = global_state;
- GList *curr = g_list_find_custom (o->paths, o->path, (void*)g_strcmp0);
if (o->rev)
argvs_eval ("save");
- if (curr && curr->next)
+ if (o->entry_no >= (int)(g_list_length(o->index)+g_list_length(o->paths))-1)
+ return 0;
+ o->entry_no ++;
+ //o->entry_no = 0;
+
{
+ char *new_path = meta_child_no_path (o, NULL, o->entry_no);
g_free (o->path);
- o->path = g_strdup (curr->next->data);
+ o->path = new_path;
ui_load_path (o);
mrg_queue_draw (o->mrg, NULL);
}
activate_sink_producer (o);
-
return 0;
}
@@ -6736,6 +6820,7 @@ int cmd_parent (COMMAND_ARGS) /* "parent", 0, "", "enter parent collection (swit
{
GeState *o = global_state;
char *prev_path = g_strdup (o->path);
+ char *prev_basename = g_path_get_basename (o->path);
char *lastslash = strrchr (o->path, '/');
int entry_no = 0;
@@ -6750,17 +6835,29 @@ int cmd_parent (COMMAND_ARGS) /* "parent", 0, "", "enter parent collection (swit
lastslash[0] = '\0';
ui_load_path (o);
-
+ if (g_file_test (prev_path, G_FILE_TEST_IS_DIR))
{
int no = 0;
+ for (GList *i = o->index; i; i=i->next, no++)
+ {
+ IndexItem *item = i->data;
+ if (!strcmp (item->name, prev_basename))
+ {
+ entry_no = no;
+ goto yep;
+ }
+ }
for (GList *i = o->paths; i; i=i->next, no++)
{
if (!strcmp (i->data, prev_path))
{
entry_no = no;
- break;
+ goto yep;
}
}
+
+ yep:
+ do{}while(0);
}
if (entry_no)
@@ -6772,6 +6869,7 @@ int cmd_parent (COMMAND_ARGS) /* "parent", 0, "", "enter parent collection (swit
mrg_queue_draw (o->mrg, NULL);
}
g_free (prev_path);
+ g_free (prev_basename);
o->active = NULL;
return 0;
}
@@ -6780,14 +6878,17 @@ int cmd_parent (COMMAND_ARGS) /* "parent", 0, "", "enter parent collection (swit
int cmd_prev (COMMAND_ARGS) /* "prev", 0, "", "previous sibling element in current collection/folder"*/
{
GeState *o = global_state;
- GList *curr = g_list_find_custom (o->paths, o->path, (void*)g_strcmp0);
+ //GList *curr = g_list_find_custom (o->paths, o->path, (void*)g_strcmp0);
if (o->rev)
argvs_eval ("save");
- if (curr && curr->prev)
+ if (o->entry_no>0)
+ o->entry_no--;
+
{
+ char *new_path = meta_child_no_path (o, NULL, o->entry_no);
g_free (o->path);
- o->path = g_strdup (curr->prev->data);
+ o->path = new_path;
ui_load_path (o);
mrg_queue_draw (o->mrg, NULL);
}
@@ -7329,4 +7430,668 @@ int ge_state_get_n_paths (GeState *state)
{
return g_list_length (state->paths);
}
+
+void
+meta_set_key (GeState *state,const char *path, const char *key, const char *value)
+{
+ gchar *metadata_path = ui_get_metadata_path (path);
+ gchar *contents = NULL;
+ char *alloc_value = NULL;
+ if (strchr (value, '\n'))
+ {
+ const char *src;
+ char *dst = alloc_value;
+ alloc_value = g_malloc (strlen (value) * 2 + 1);
+ for (src = value; *src; src++)
+ {
+ if (*src == '\n')
+ {
+ *dst = '\\';
+ dst++;
+ *dst = 'n';
+ dst++;
+ }
+ else
+ {
+ *dst = *src;
+ dst++;
+ }
+ }
+ *dst = 0;
+ value = alloc_value;
+ }
+
+ g_file_get_contents (metadata_path, &contents, NULL, NULL);
+ if (contents)
+ {
+ char *line = contents;
+
+ while (*line)
+ {
+ if (0==memcmp (line, key, strlen (key)) &&
+ line[strlen(key)]=='=')
+ {
+ char *start = &line[strlen(key)+1];
+ char *end = start;
+
+ for (end = start; *end != '\n' && *end != '\0'; end++);
+ if (*end == 0)
+ {
+ *line = 0;
+ }
+ else
+ {
+ memmove (line, end + 1, strlen (end));
+ }
+ goto prepped;
+ }
+
+ while (*line && *line != '\n')
+ {
+ line++;
+ }
+ if (*line == '\n')
+ line++;
+ }
+
+ prepped:
+ {
+ char *str = g_strdup_printf ("%s%s=%s\n", contents, key, value);
+ g_file_set_contents (metadata_path, str, -1, NULL);
+ g_free (str);
+ }
+
+ g_free (contents);
+ }
+ else
+ {
+ char *str = g_strdup_printf ("%s=%s\n", key, value);
+ char *dirname = g_path_get_dirname (metadata_path);
+ g_mkdir_with_parents (dirname, 0777);
+ g_free (dirname);
+
+
+ fprintf (stderr, "%s!%s!!!\n\n", metadata_path, str);
+ g_file_set_contents (metadata_path, str, -1, NULL);
+ g_free (str);
+ }
+
+ g_free (metadata_path);
+ if (alloc_value)
+ g_free (alloc_value);
+}
+
+static IndexItem *
+index_item_new (void)
+{
+ return g_malloc0 (sizeof (IndexItem));
+}
+
+static void
+index_item_destroy (IndexItem *item)
+{
+ g_free (item->name);
+ for (int i = 0; i < INDEX_MAX_ATTRIBUTES; i++)
+ {
+ if (item->attribute[i])
+ g_free (item->attribute[i]);
+ if (item->detail[i])
+ g_free (item->detail[i]);
+ }
+}
+
+static void
+store_index (GeState *state, const char *path)
+{
+ GString *str;
+
+ struct stat stat_buf;
+ char *dirname;
+ char *index_path = NULL;
+ lstat (path, &stat_buf);
+ if (S_ISREG (stat_buf.st_mode))
+ {
+ dirname = g_path_get_dirname (path);
+ }
+ else if (S_ISDIR (stat_buf.st_mode))
+ {
+ dirname = g_strdup (path);
+ }
+ else
+ {
+ return;
+ }
+ str = g_string_new ("");
+ index_path = ui_get_index_path (dirname);
+
+ for (GList *iter = state->index; iter; iter=iter->next)
+ {
+ IndexItem *item = iter->data;
+ g_string_append_printf (str, "%s\n", item->name);
+ for (int i = 0; i < INDEX_MAX_ATTRIBUTES; i++)
+ {
+ if (item->attribute[i])
+ {
+ g_string_append_printf (str, "\t%s\n", item->attribute[i]);
+ if (item->detail[i])
+ {
+ g_string_append_printf (str, "\t\t%s\n", item->detail[i]);
+ }
+ }
+ }
+ }
+ g_file_set_contents (index_path, str->str, -1, NULL);
+
+ g_free (dirname);
+ g_free (index_path);
+ g_string_free (str, TRUE);
+}
+
+static void
+load_index (GeState *state, const char *path)
+{
+ /* if path is not a folder load its parent */
+ struct stat stat_buf;
+ char *index_path = NULL;
+ gchar *contents = NULL;
+ gchar *dirname = NULL;
+
+ while (state->index)
+ {
+ index_item_destroy (state->index->data);
+ state->index = g_list_remove (state->index, state->index->data);
+ }
+
+ lstat (path, &stat_buf);
+ if (S_ISREG (stat_buf.st_mode))
+ {
+ dirname = g_path_get_dirname (path);
+ }
+ else if (S_ISDIR (stat_buf.st_mode))
+ {
+ dirname = g_strdup (path);
+ }
+ else
+ {
+ return;
+ }
+ index_path = ui_get_index_path (dirname);
+
+ g_file_get_contents (index_path, &contents, NULL, NULL);
+ if (contents)
+ {
+ char *line = contents;
+
+ int child_no = -1;
+ char *name = NULL;
+ char *attribute = NULL;
+ char *detail = NULL;
+ while (*line)
+ {
+ char *nextline = line;
+ /* skip to next line */
+ while (*nextline && *nextline != '\n')
+ nextline++;
+ if (*nextline == '\n')
+ nextline++;
+
+ if (line[0] != '\t') /* name */
+ {
+ char *end;
+ name = line;
+ for (end = name; *end && *end != '\n'; end++);
+ *end = 0;
+ child_no ++;
+ meta_insert_child (state, dirname, child_no, name);
+ }
+ else /* key or value*/
+ {
+ if (line[1] != '\t') /* attribute */
+ {
+ char *end;
+ attribute = &line[1];
+ for (end = attribute; *end && *end != '\n'; end++);
+ *end = 0;
+ }
+ else /* detail */
+ {
+ char *end;
+ detail = &line[2];
+ for (end = detail; *end && *end != '\n'; end++);
+ *end = 0;
+ meta_set_attribute (state, dirname, child_no, attribute, detail);
+ }
+ }
+ line = nextline;
+ }
+ g_free (contents);
+ }
+ g_free (dirname);
+ if (index_path)
+ g_free (index_path);
+ state->index_dirty = 0;
+}
+
+
+
+const char *
+meta_get_key (GeState *state, const char *path, const char *key)
+{
+ const char *ret = NULL;
+ gchar *metadata_path = ui_get_metadata_path (path);
+ gchar *contents = NULL;
+ g_file_get_contents (metadata_path, &contents, NULL, NULL);
+ if (contents)
+ {
+ char *line = contents;
+ while (*line)
+ {
+
+ if (0==memcmp (line, key, strlen (key)) &&
+ line[strlen(key)]=='=')
+ {
+ char *start = &line[strlen(key)+1];
+ char *end = start;
+ for (end = start; *end != '\n' && *end != '\0'; end++);
+ *end = 0;
+
+ for (char *p = start; *p && p != end && *p != '\n'; p++)
+ {
+ if (p[0] == '\\' && p[1]=='n')
+ {
+ p[0] = '\n';
+ memmove (line, end + 1, strlen (end));
+ }
+ }
+
+ ret = g_intern_string (start);
+
+ g_free (contents);
+ return ret;
+ }
+
+ while (*line && *line != '\n')
+ {
+ line++;
+ }
+ if (*line == '\n')
+ line++;
+ }
+ g_free (contents);
+ }
+ return NULL;
+}
+
+
+void
+meta_insert_child (GeState *state,const char *path,
+ int value_no,
+ const char *child_name)
+{
+ IndexItem *item = index_item_new ();
+ item->name = g_strdup (child_name);
+ state->index = g_list_insert (state->index, item, value_no);
+ state->index_dirty ++;
+}
+
+int
+meta_remove_child (GeState *state,const char *path,
+ int value_no, /* or -1 to remove first match
+ or -2 to remove all matching child_name,
+ or specific number >=0 to remove specific */
+ const char *child_name)
+{
+ int no;
+ int ret = -1;
+ GList *iter;
+
+ again:
+ for (iter = state->index, no=0; iter;iter=iter->next, no++)
+ {
+ IndexItem *item = iter->data;
+ if (child_name)
+ {
+ if (!strcmp (child_name, item->name))
+ {
+ if (value_no == -1)
+ {
+ state->index = g_list_remove (state->index, item);
+ index_item_destroy (item);
+ state->index_dirty++;
+ return no;
+ }
+ else if (value_no == -2)
+ {
+ state->index = g_list_remove (state->index, item);
+ index_item_destroy (item);
+ ret = no;
+ state->index_dirty++;
+ goto again;
+ }
+ else if (value_no == no)
+ {
+ state->index = g_list_remove (state->index, item);
+ index_item_destroy (item);
+ state->index_dirty++;
+ return no;
+ }
+ else
+ {
+ g_assert (0);
+ }
+ }
+ }
+ else
+ {
+ g_assert (value_no>=0);
+ if (value_no == no)
+ {
+ state->index = g_list_remove (state->index, item);
+ index_item_destroy (item);
+ return no;
+ }
+ }
+ }
+
+ return ret;
+}
+
+void
+meta_replace_child (GeState *state,const char *path,
+ int old_value_no, /* or -1 for first matching old_child_name */
+ const char *old_child_name, /* NULL to use >=0 old_value_no or a string */
+ const char *new_child_name)
+{
+ int old_val_no = meta_remove_child (state, path, old_value_no, old_child_name);
+ meta_insert_child (state, path, old_val_no, new_child_name);
+}
+
+void
+meta_swap_children (GeState *state,const char *path,
+ int value_no1, /* -1 to use only name */
+ const char *child_name1, /* or NULL to use no1 (which cannot be -1) */
+ int value_no2,
+ const char *child_name2)
+{
+ fprintf (stderr, "%s NYI\n", __FUNCTION__);
+}
+
+void
+meta_set_attribute (GeState *state,
+ const char *path,
+ int value_no,
+ // also have child name
+ const char *attribute,
+ const char *detail)
+{
+ GList *iter;
+ int no;
+ fprintf (stderr, "----%s %i %s %s\n", path, value_no, attribute, detail);
+ for (iter = state->index, no = 0; iter; iter=iter->next, no++)
+ {
+ IndexItem *item = iter->data;
+ if (no == value_no)
+ {
+ for (int ano = 0; ano < INDEX_MAX_ATTRIBUTES; ano++)
+ {
+ if (item->attribute[ano] && !strcmp (item->attribute[ano], attribute))
+ {
+ if (item->detail[ano])
+ {
+ g_free (item->detail[ano]);
+ item->detail[ano] = NULL;
+ }
+ if (detail)
+ {
+ item->detail[ano] = g_strdup (detail);
+ }
+ state->index_dirty ++;
+ return;
+ }
+ }
+
+ for (int ano = 0; ano < INDEX_MAX_ATTRIBUTES; ano++)
+ {
+ if (item->attribute[ano] == NULL)
+ {
+ if (item->detail[ano])
+ {
+ g_free (item->detail[ano]);
+ item->detail[ano] = NULL;
+ }
+ if (detail)
+ {
+ item->detail[ano] = g_strdup (detail);
+ }
+ item->attribute[ano] = g_strdup (attribute);
+ state->index_dirty ++;
+ return;
+ }
+ }
+ }
+ }
+}
+
+const char *
+meta_get_attribute (GeState *state,
+ const char *path,
+ int value_no,
+ const char *attribute)
+{
+ GList *iter;
+ int no;
+ for (iter = state->index, no = 0; iter; iter=iter->next, no++)
+ {
+ IndexItem *item = iter->data;
+ if (no == value_no)
+ {
+ for (int ano = 0; ano < INDEX_MAX_ATTRIBUTES; ano++)
+ {
+ if (item->attribute[ano] && !strcmp (item->attribute[ano], attribute))
+ {
+ return item->detail[ano];
+ }
+ }
+ }
+ }
+
+ /* XXX; fall back to loading key/value ? */
+
+ return NULL;
+}
+
+int
+meta_has_attribute (GeState *state,
+ const char *path,
+ int value_no,
+ const char *attribute)
+{
+ GList *iter;
+ int no;
+ for (iter = state->index, no = 0; iter; iter=iter->next, no++)
+ {
+ IndexItem *item = iter->data;
+ if (no == value_no)
+ {
+ for (int ano = 0; ano < INDEX_MAX_ATTRIBUTES; ano++)
+ {
+ if (item->attribute[ano] && !strcmp (item->attribute[ano], attribute))
+ {
+ return 1;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+void
+meta_unset_attribute (GeState *state,
+ const char *path,
+ int value_no,
+ const char *attribute)
+{
+ GList *iter;
+ int no;
+ for (iter = state->index, no = 0; iter; iter=iter->next, no++)
+ {
+ IndexItem *item = iter->data;
+ if (no == value_no)
+ {
+ for (int ano = 0; ano < INDEX_MAX_ATTRIBUTES; ano++)
+ {
+ if (item->attribute[ano] && !strcmp (item->attribute[ano], attribute))
+ {
+ g_free (item->attribute[ano]);
+ item->attribute[ano] = NULL;
+ if (item->detail[ano])
+ g_free (item->detail[ano]);
+ item->detail[ano] = NULL;
+ state->index_dirty ++;
+ }
+ }
+ }
+ }
+}
+
+#if 1
+static int
+index_contains (GeState *state,
+ const char *name)
+{
+ for (GList *iter = state->index; iter; iter = iter->next)
+ {
+ IndexItem *item = iter->data;
+ if (!strcmp (item->name, name))
+ return 1;
+ }
+ return 0;
+}
+#endif
+
+char *
+meta_get_child (GeState *state,
+ const char *path,
+ int child_no)
+{
+ int items = g_list_length (state->index);
+ GList *iter;
+ int no = 0;
+ if (child_no >= 0 && child_no < items) {
+ IndexItem *item = g_list_nth_data (state->index, child_no);
+ return g_strdup (item->name);
+ }
+ no = items;
+ for (iter = state->paths; iter; iter=iter->next)
+ {
+ char *basename = g_path_get_basename (iter->data);
+// if (!index_contains (state, basename))
+ {
+ if (no == child_no)
+ {
+ return basename;
+ }
+ no++;
+ }
+ g_free (basename);
+ }
+ return NULL;
+}
+
+/* integer/float abstraction for path key/values */
+
+void
+meta_set_key_int (GeState *state,
+ const char *path,
+ const char *key,
+ int value)
+{
+ char *buf = g_strdup_printf ("%i", value);
+ meta_set_key (state, path, key, buf);
+ g_free (buf);
+}
+
+int
+meta_get_key_int (GeState *state,
+ const char *path,
+ const char *key)
+{
+ const char *value = meta_get_key (state, path, key);
+ if (!value)
+ return -999999;
+ return atoi (value);
+}
+
+int
+meta_get_attribute_int (GeState *state,
+ const char *path,
+ int value_no,
+ const char *attribute)
+{
+ const char *value = meta_get_attribute (state, path, value_no, attribute);
+ if (!value)
+ return -999999;
+ return atoi (value);
+}
+
+float
+meta_get_attribute_float (GeState *state,
+ const char *path,
+ int value_no,
+ const char *attribute)
+{
+ const char *value = meta_get_attribute (state, path, value_no, attribute);
+ if (!value)
+ return -999999.99999;
+ return g_ascii_strtod (value, NULL);
+}
+
+void
+meta_set_key_float (GeState *state,
+ const char *path,
+ const char *key,
+ float value)
+{
+ char buf[G_ASCII_DTOSTR_BUF_SIZE];
+ g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE, value);
+ meta_set_key (state, path, key, buf);
+}
+
+void
+meta_set_attribute_float (GeState *state,
+ const char *path,
+ int value_no,
+ // also have child name
+ const char *attribute,
+ float detail)
+{
+ char buf[G_ASCII_DTOSTR_BUF_SIZE];
+ g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE, detail);
+ meta_set_attribute (state, path, value_no, attribute, buf);
+}
+
+void
+meta_set_attribute_int (GeState *state,
+ const char *path,
+ int value_no,
+ // also have child name
+ const char *attribute,
+ int detail)
+{
+ char buf[G_ASCII_DTOSTR_BUF_SIZE];
+ sprintf (buf, "%d", detail);
+ meta_set_attribute (state, path, value_no, attribute, buf);
+}
+
+float
+meta_get_key_float (GeState *state,
+ const char *path,
+ const char *key)
+{
+ const char *value = meta_get_key (state, path, key);
+ if (!value)
+ return -999999.99999;
+ return g_ascii_strtod (value, NULL);
+}
+
#endif
diff --git a/bin/ui-viewer.c b/bin/ui-viewer.c
index f3b98d3f3..210b77690 100644
--- a/bin/ui-viewer.c
+++ b/bin/ui-viewer.c
@@ -38,18 +38,19 @@
static void entry_load (MrgEvent *event, void *data1, void *data2)
{
GeState *o = data1;
-
+ char *newpath;
if (o->rev)
argvs_eval ("save");
+ o->entry_no = GPOINTER_TO_INT(data2);
+ newpath = meta_child_no_path (o, NULL, o->entry_no);
g_free (o->path);
- o->path = g_strdup (data2);
+ o->path = newpath;
ui_load_path (o);
mrg_event_stop_propagate (event);
mrg_queue_draw (event->mrg, NULL);
}
-
static void on_viewer_motion (MrgEvent *e, void *data1, void *data2)
{
GeState *o = data1;
@@ -246,13 +247,32 @@ static void on_thumbbar_scroll (MrgEvent *event, void *data1, void *data2)
mrg_event_stop_propagate (event);
}
+char *meta_child_no_path (GeState *o, const char *path, int child_no)
+{
+ char *basename = meta_get_child (o, path, child_no);
+ char *ret;
+ if (o->is_dir)
+ ret = g_strdup_printf ("%s/%s", o->path, basename);
+ else
+ {
+ char *dirname = g_path_get_dirname (o->path);
+ ret = g_strdup_printf ("%s/%s", dirname, basename);
+ g_free (dirname);
+ }
+ g_free (basename);
+ return ret;
+}
+
static void draw_thumb_bar (GeState *o)
{
Mrg *mrg = o->mrg;
float width = mrg_width(mrg);
float height = mrg_height(mrg);
cairo_t *cr = mrg_cr (mrg);
- GList *curr = g_list_find_custom (o->paths, o->path, (void*)g_strcmp0);
+
+ //fprintf (stderr, "... %i ...\n", o->entry_no);
+
+ //GList *curr = g_list_find_custom (o->paths, o->path, (void*)g_strcmp0);
float dim = height * 0.15 * o->thumbbar_scale;
float padding = .025;
float opacity;
@@ -281,15 +301,18 @@ static void draw_thumb_bar (GeState *o)
mrg_listen (mrg, MRG_SCROLL, on_thumbbar_motion, o, NULL);
cairo_new_path (cr);
- if (curr && opacity > 0.01)
+ if (opacity > 0.01)
{
- GList *iter = curr;
+ //GList *iter = curr;
float x = mrg_width(mrg)/2-dim/2 - o->thumbbar_pan_x;
+ int entry_no = o->entry_no;
+ int entries = g_list_length (o->index) + g_list_length (o->paths);
-
- for (iter = curr; iter && x < width; iter = iter->next)
+ //for (iter = curr; iter && x < width; iter = iter->next)
+ while (x < width && entry_no < entries)
{
- char *path = ui_suffix_path (iter->data);
+ char *upath = meta_child_no_path (o, NULL, entry_no);
+ char *path = ui_suffix_path (upath);
char *thumbpath = ui_get_thumb_path (path);
int w, h;
@@ -305,11 +328,11 @@ static void draw_thumb_bar (GeState *o)
if (w!=0 && h!=0)
{
cairo_rectangle (mrg_cr (mrg), x, height-dim, wdim, hdim);
- if (iter == curr)
+ if (entry_no == o->entry_no)
cairo_set_source_rgba (mrg_cr (mrg), 1,1,0,.7 * opacity);
else
cairo_set_source_rgba (mrg_cr (mrg), 1,1,1,.1 * opacity);
- mrg_listen (mrg, MRG_TAP, entry_load, o, (void*)g_intern_string (iter->data));
+ mrg_listen (mrg, MRG_TAP, entry_load, o, GINT_TO_POINTER(entry_no));
cairo_fill (mrg_cr (mrg));
mrg_image (mrg, x + dim * padding, height-dim*(1.0-padding),
wdim * (1.0-padding*2), hdim *(1.0-padding*2), opacity, thumbpath, NULL, NULL);
@@ -320,20 +343,23 @@ static void draw_thumb_bar (GeState *o)
if (access (thumbpath, F_OK) != 0) // only queue if does not exist,
// mrg/stb_image seem to suffer on some of our pngs
{
- ui_queue_thumb (iter->data);
+ ui_queue_thumb (upath);
}
}
x += dim;
g_free (thumbpath);
g_free (path);
+ g_free (upath);
+ entry_no ++;
}
x = mrg_width(mrg)/2-dim/2 - o->thumbbar_pan_x;
dim = height * 0.15 * o->thumbbar_scale;
x -= dim;
-
- for (iter = curr->prev; iter && x > -dim; iter = iter->prev)
+ entry_no = o->entry_no-1;
+ while (x > -dim && entry_no >= 0)
{
- char *path = ui_suffix_path (iter->data);
+ char *upath = meta_child_no_path (o, NULL, entry_no);
+ char *path = ui_suffix_path (upath);
char *thumbpath = ui_get_thumb_path (path);
int w, h;
@@ -345,11 +371,15 @@ static void draw_thumb_bar (GeState *o)
float wdim = dim, hdim = dim;
if (w > h) hdim = dim / (1.0 * w / h);
else wdim = dim * (1.0 * w / h);
+
if (w!=0 && h!=0)
{
cairo_rectangle (mrg_cr (mrg), x, height-dim, wdim, hdim);
+ if (entry_no == o->entry_no)
+ cairo_set_source_rgba (mrg_cr (mrg), 1,1,0,.7 * opacity);
+ else
cairo_set_source_rgba (mrg_cr (mrg), 1,1,1,.1 * opacity);
- mrg_listen (mrg, MRG_TAP, entry_load, o, (void*)g_intern_string (iter->data));
+ mrg_listen (mrg, MRG_TAP, entry_load, o, GINT_TO_POINTER(entry_no));
cairo_fill (mrg_cr (mrg));
mrg_image (mrg, x + dim * padding, height-dim*(1.0-padding),
wdim * (1.0-padding*2), hdim *(1.0-padding*2), opacity, thumbpath, NULL, NULL);
@@ -360,12 +390,14 @@ static void draw_thumb_bar (GeState *o)
if (access (thumbpath, F_OK) != 0) // only queue if does not exist,
// mrg/stb_image seem to suffer on some of our pngs
{
- ui_queue_thumb (iter->data);
+ ui_queue_thumb (upath);
}
}
x -= dim;
g_free (thumbpath);
g_free (path);
+ g_free (upath);
+ entry_no --;
}
}
diff --git a/bin/ui.h b/bin/ui.h
index 79d2a7302..9445e03a5 100644
--- a/bin/ui.h
+++ b/bin/ui.h
@@ -29,6 +29,19 @@ typedef struct _GeStateClass GeStateClass;
*
*/
+typedef struct _IndexItem IndexItem;
+
+#define INDEX_MAX_ATTRIBUTES 8
+
+struct _IndexItem {
+ char *name;
+ char *attribute[INDEX_MAX_ATTRIBUTES];
+ char *detail[INDEX_MAX_ATTRIBUTES];
+
+ /* we could cache item meta data for reading here */
+ //char *key[INDEX_MAX_ATTRIBUTES];
+ //char *value[INDEX_MAX_ATTRIBUTES];
+};
struct _GeState {
GObject parent;
@@ -42,6 +55,8 @@ struct _GeState {
the file that is written to on save. This differs depending
on type of input file.
*/
+ GList *index; /* dictates manual order and attribute/details for entries */
+ int index_dirty;
GList *paths; /* list of full paths to entries in collection/path/containing path,
XXX: could be replaced with URIs, and each
element should perhaps contain more internal info
@@ -130,32 +145,125 @@ struct _GeStateClass {
GObjectClass parent;
};
-GType ge_state_get_type (void) G_GNUC_CONST;
-GeState* ge_state_new (void);
-
-const char *ge_state_get_path (GeState *state, int no);
-int ge_state_get_n_paths (GeState *state);
-void ui_load_path (GeState *o);
-void ui_center_active_entry (GeState *o);
-
-
-void path_set_key (const char *path, const char *key, const char *value);
-const char *path_get_key (const char *path, const char *key);
+GType ge_state_get_type (void) G_GNUC_CONST;
+GeState* ge_state_new (void);
+const char *ge_state_get_path (GeState *state, int no);
+int ge_state_get_n_paths (GeState *state);
+void ui_load_path (GeState *o);
+void ui_center_active_entry (GeState *o);
+
+
+
+
+void meta_set_key (GeState *state,
+ const char *path,
+ const char *key,
+ const char *value);
+
+const char *meta_get_key (GeState *state, const char *path, const char *key);
+
+void meta_set_key_int (GeState *state, const char *path, const char *key, int value);
+int meta_get_key_int (GeState *state, const char *path, const char *key);
+void meta_set_key_float (GeState *state, const char *path, const char *key, float value);
+float meta_get_key_float (GeState *state, const char *path, const char *key);
+
+int
+meta_get_attribute_int (GeState *state,
+ const char *path,
+ int child_no,
+ // also have child name
+ const char *attribute);
+
+float
+meta_get_attribute_float (GeState *state,
+ const char *path,
+ int child_no,
+ // also have child name
+ const char *attribute);
+
+void
+meta_set_attribute_float (GeState *state,
+ const char *path,
+ int child_no,
+ // also have child name
+ const char *attribute,
+ float detail);
+
+void
+meta_set_attribute_int (GeState *state,
+ const char *path,
+ int child_no,
+ // also have child name
+ const char *attribute,
+ int detail);
/* --- the display order is overrides, then dirlist.. this
* should be configurable
*
- * the display order should be a second list of
+ * the display order should be a second list of
*/
-
-
-
-
-void ui_viewer (GeState *o);
-void ui_collection (GeState *o);
-char *ui_suffix_path (const char *path);
-char *ui_unsuffix_path (const char *path);
+void
+meta_set_attribute (GeState *state,
+ const char *path,
+ int child_no,
+ const char *attribute,
+ const char *detail);
+const char *
+meta_get_attribute (GeState *state,
+ const char *path,
+ int child_no,
+ const char *attribute);
+int
+meta_has_attribute (GeState *state,
+ const char *path,
+ int child_no,
+ const char *attribute);
+void
+meta_unset_attribute (GeState *state,
+ const char *path,
+ int child_no,
+ const char *attribute);
+
+/* for now - not supporting multivalue on attribute/details */
+
+char *
+meta_get_child (GeState *state,
+ const char *path,
+ int child_no);
+
+void
+meta_insert_child (GeState *state,
+ const char *path,
+ int child_no,
+ const char *child_name);
+int
+meta_remove_child (GeState *state,
+ const char *path,
+ int child_no,
+ const char *child_name);
+
+void
+meta_replace_child (GeState *state,
+ const char *path,
+ int old_child_no,
+ const char *old_child_name,
+ const char *new_child_name);
+
+void
+meta_swap_children (GeState *state,
+ const char *path,
+ int child_no1,
+ const char *child_name1,
+ int child_no2,
+ const char *child_name2);
+
+char *meta_child_no_path (GeState *o, const char *path, int child_no);
+
+void ui_viewer (GeState *o);
+void ui_collection (GeState *o);
+char *ui_suffix_path (const char *path);
+char *ui_unsuffix_path (const char *path);
int ui_hide_controls_cb (Mrg *mrg, void *data);
gchar *ui_get_thumb_path (const char *path);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]