[gegl] bin: add a thumbbar as part of overlay image controls



commit e525efa8bf9cf4f079579c7c427e0208a3414ac3
Author: Øyvind Kolås <pippin gimp org>
Date:   Sun Jan 27 03:20:13 2019 +0100

    bin: add a thumbbar as part of overlay image controls

 bin/ui.c                 | 332 +++++++++++++++++++++++++++++++++++++++++++----
 operations/common/save.c |   4 +-
 2 files changed, 309 insertions(+), 27 deletions(-)
---
diff --git a/bin/ui.c b/bin/ui.c
index c225b4dc9..615078756 100644
--- a/bin/ui.c
+++ b/bin/ui.c
@@ -253,8 +253,6 @@ struct _State {
   char           new_opname[1024];
   int            rev;
 
-  int            concurrent_thumbnailers;
-
   float          u, v;
   float          scale;
   float          dir_scale;
@@ -266,6 +264,13 @@ struct _State {
   int            show_graph;
   float          graph_scale;
 
+  float          thumbbar_pan_x;
+  float          thumbbar_pan_y;
+  int            show_thumbbar;
+  float          thumbbar_scale;
+  float          thumbbar_opacity;
+  int            thumbbar_timeout;
+
   int            show_controls;
   int            controls_timeout;
   int            frame_no;
@@ -322,23 +327,20 @@ Setting settings[]=
   STRING_PROP_RO(save_path, "save path, might be different from path if current path is an immutable source 
image itself"),
   STRING_PROP_RO(src_path, "source path the immutable source image currently being edited"),
 
-  FLOAT_PROP(u, "horizontal coordinate of top-left in display/scaled by scale factor coordinates"),
-  FLOAT_PROP(v, "vertical coordinate of top-left in display/scaled by scale factor coordinates"),
-  FLOAT_PROP(render_quality, "1.0 = normal 2.0 = render at 2.0 zoom factor 4.0 render at 25%"),
-  FLOAT_PROP(preview_quality, "preview quality for use during some interactions, same scale as 
render-quality"),
+//  FLOAT_PROP(u, "horizontal coordinate of top-left in display/scaled by scale factor coordinates"),
+//  FLOAT_PROP(v, "vertical coordinate of top-left in display/scaled by scale factor coordinates"),
+//  FLOAT_PROP(render_quality, "1.0 = normal 2.0 = render at 2.0 zoom factor 4.0 render at 25%"),
+//  FLOAT_PROP(preview_quality, "preview quality for use during some interactions, same scale as 
render-quality"),
   INT_PROP(show_graph, "show the graph (and commandline)"),
+  INT_PROP(show_thumbbar, "show the thumbbar"),
   INT_PROP(show_controls, "show image viewer controls (maybe merge with show-graph and give better name)"),
   INT_PROP(slide_enabled, "slide show going"),
   INT_PROP_RO(is_video, ""),
   INT_PROP(color_manage_display, "perform ICC color management and convert output to display ICC profile 
instead of passing out sRGB, passing out sRGB is faster."),
   INT_PROP(playing, "wheter we are playing or not set to 0 for pause 1 for playing"),
-  INT_PROP(concurrent_thumbnailers, "number of child processes spawned at the same time doing thumbnailing"),
   INT_PROP(frame_no, "current frame number in video/animation"),
   FLOAT_PROP(scale, "display scale factor"),
   INT_PROP(show_bindings, "show currently valid keybindings"),
-  FLOAT_PROP(graph_pan_x, "vertical scroll offset of graph"),
-  FLOAT_PROP(graph_pan_y, "horizontal scroll offset of graph"),
-  FLOAT_PROP(graph_scale, "graph scale factor"),
 
 };
 
@@ -627,13 +629,13 @@ static gboolean renderer_task (gpointer data)
       if (thumb_queue)
       {
         static GPid thumbnailer_pid = 0;
-#define THUMB_BATCH_SIZE    32
+#define THUMB_BATCH_SIZE    10
         char *argv[THUMB_BATCH_SIZE]={"gegl","--thumbgen", NULL};
         int count = 2;
         MrgList *to_remove = NULL;
 
         for (MrgList *iter = thumb_queue;
-             iter && count < THUMB_BATCH_SIZE-2;
+             iter && count < THUMB_BATCH_SIZE-3;
              iter=iter->next)
         {
           ThumbQueueItem *item = iter->data;
@@ -695,12 +697,14 @@ static void init_state (State *o)
   const char *renderer_env = g_getenv ("GEGL_RENDERER");
   o->scale           = 1.0;
   o->graph_scale     = 1.0;
+  o->thumbbar_scale  = 1.0;
+  o->thumbbar_opacity = 1.0;
+  o->show_thumbbar = 1.0;
   o->render_quality  = 1.0;
   o->preview_quality = 1.0;
   //o->preview_quality = 2.0;
   o->slide_pause     = 5.0;
   o->slide_enabled   = 0;
-  o->concurrent_thumbnailers = 2;
   o->show_bindings   = 0;
   o->ui_consumer = g_hash_table_new (g_direct_hash, g_direct_equal);
 
@@ -733,7 +737,7 @@ int mrg_ui_main (int argc, char **argv, char **ops)
   State *o = &state;
   global_state = o;
 
-
+  mrg_set_image_cache_mb (mrg, 1024);
   mrg_set_title (mrg, "GEGL");
 
   gegl_init (&argc, &argv);
@@ -878,6 +882,14 @@ static int hide_controls_cb (Mrg *mrg, void *data)
   return 0;
 }
 
+static int fade_thumbbar_cb (Mrg *mrg, void *data)
+{
+  State *o = data;
+  o->show_thumbbar = 1;
+  mrg_queue_draw (o->mrg, NULL);
+  return 0;
+}
+
 static void on_viewer_motion (MrgEvent *e, void *data1, void *data2)
 {
   State *o = data1;
@@ -892,7 +904,22 @@ static void on_viewer_motion (MrgEvent *e, void *data1, void *data2)
       mrg_remove_idle (o->mrg, o->controls_timeout);
       o->controls_timeout = 0;
     }
-    o->controls_timeout = mrg_add_timeout (o->mrg, 1000, hide_controls_cb, o);
+    o->controls_timeout = mrg_add_timeout (o->mrg, 2000, hide_controls_cb, o);
+  }
+}
+
+static void on_thumbbar_motion (MrgEvent *e, void *data1, void *data2)
+{
+  State *o = data1;
+  on_viewer_motion (e, data1, NULL);
+  {
+    o->show_thumbbar = 2;
+    if (o->thumbbar_timeout)
+    {
+      mrg_remove_idle (o->mrg, o->thumbbar_timeout);
+      o->thumbbar_timeout = 0;
+    }
+    o->thumbbar_timeout = mrg_add_timeout (o->mrg, 4000, fade_thumbbar_cb, o);
   }
 }
 
@@ -1117,6 +1144,7 @@ static void on_dir_drag (MrgEvent *e, void *data1, void *data2)
   if (e->type == MRG_DRAG_RELEASE)
   {
     zoom_pinch = 0;
+    mrg_queue_draw (e->mrg, NULL);
   } else if (e->type == MRG_DRAG_PRESS)
   {
     if (e->device_no == 5)
@@ -1182,6 +1210,8 @@ static void on_dir_drag (MrgEvent *e, void *data1, void *data2)
 }
 
 
+
+
 static GeglNode *add_output (State *o, GeglNode *active, const char *optype);
 static GeglNode *add_aux (State *o, GeglNode *active, const char *optype);
 static GeglNode *add_input (State *o, GeglNode *active, const char *optype);
@@ -1372,9 +1402,14 @@ static void entry_select (MrgEvent *event, void *data1, void *data2)
 static void entry_load (MrgEvent *event, void *data1, void *data2)
 {
   State *o = data1;
+
+  if (o->rev)
+    argvs_eval ("save");
+
   g_free (o->path);
   o->path = g_strdup (data2);
   load_path (o);
+  mrg_event_stop_propagate (event);
   mrg_queue_draw (event->mrg, NULL);
 }
 
@@ -1414,7 +1449,6 @@ static void ui_dir_viewer (State *o)
   mrg_listen (mrg, MRG_MOTION, on_viewer_motion, o, NULL);
   cairo_new_path (cr);
 
-//  mrg_set_edge_right (mrg, 4095);
   cairo_save (cr);
   cairo_translate (cr, 0, -(int)o->v);
   {
@@ -1445,7 +1479,7 @@ static void ui_dir_viewer (State *o)
       float y = dim * (no/cols);
       int is_dir = 0;
 
-      if (y < -dim || y > mrg_height (mrg) + o->v)
+      if (y < -dim + o->v || y > mrg_height (mrg) + o->v)
         continue;
 
       lstat (path, &stat_buf);
@@ -1591,6 +1625,165 @@ static void draw_edit (Mrg *mrg, float x, float y, float w, float h)
   cairo_new_path (cr);
   cairo_arc (cr, x+0.5*w, y+0.5*h, h * .4, 0.0, G_PI * 2);
 }
+static void on_thumbbar_drag (MrgEvent *e, void *data1, void *data2);
+
+
+static void on_thumbbar_visible (MrgEvent *event, void *data1, void *data2)
+{
+}
+
+static void on_thumbbar_scroll (MrgEvent *event, void *data1, void *data2)
+{
+  State *o = data1;
+  on_viewer_motion (event, data1, NULL);
+  switch (event->scroll_direction)
+  {
+     case MRG_SCROLL_DIRECTION_DOWN:
+       o->thumbbar_scale /= 1.1;
+       if (o->thumbbar_scale < 0.2)
+         o->thumbbar_scale = 0.2;
+       break;
+     case MRG_SCROLL_DIRECTION_UP:
+       o->thumbbar_scale *= 1.1;
+       if (o->thumbbar_scale > 3)
+         o->thumbbar_scale = 3;
+       break;
+     default:
+       break;
+  }
+  mrg_queue_draw (event->mrg, NULL);
+  mrg_event_stop_propagate (event);
+}
+
+static void draw_thumb_bar (State *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);
+  float dim = height * 0.15 * o->thumbbar_scale;
+  float padding = .025;
+  float opacity;
+
+  cairo_save (cr);
+
+  if (o->show_thumbbar > 1)
+  {
+     opacity = o->thumbbar_opacity * (1.0 - 0.09) + 0.09 * 1.0;
+     if (opacity < 0.99)
+       mrg_queue_draw (o->mrg, NULL);
+  }
+  else
+  {
+     opacity = o->thumbbar_opacity * (1.0 - 0.09) + 0.09 * 0.05;
+     if (opacity > 0.06)
+       mrg_queue_draw (o->mrg, NULL);
+  }
+  o->thumbbar_opacity = opacity;
+
+  //cairo_translate (mrg_cr (mrg), - o->thumbbar_pan_x, -o->thumbbar_pan_y);
+  //cairo_scale (mrg_cr (mrg), o->thumbbar_scale, o->thumbbar_scale);
+
+  cairo_rectangle (cr, 0, height-dim, width, dim);
+  mrg_listen (mrg, MRG_DRAG, on_thumbbar_drag, o, NULL);
+  mrg_listen (mrg, MRG_SCROLL, on_thumbbar_scroll, o, NULL);
+  mrg_listen (mrg, MRG_DRAG, on_thumbbar_motion, o, NULL);
+  mrg_listen (mrg, MRG_MOTION, on_thumbbar_motion, o, NULL);
+  mrg_listen (mrg, MRG_SCROLL, on_thumbbar_motion, o, NULL);
+  cairo_new_path (cr);
+
+  if (curr && opacity > 0.06)
+  {
+    GList *iter = curr;
+    float x = mrg_width(mrg)/2-dim/2 - o->thumbbar_pan_x;
+
+
+    for (iter = curr; iter && x < width; iter = iter->next)
+    {
+      char *path = suffix_path (iter->data);
+      char *thumbpath = get_thumb_path (path);
+      int w, h;
+
+      if (
+         access (thumbpath, F_OK) == 0 &&
+         mrg_query_image (mrg, thumbpath, &w, &h))
+      {
+
+        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 (iter == curr)
+          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));
+          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);
+        }
+      }
+      else
+      {
+         if (access (thumbpath, F_OK) != 0) // only queue if does not exist,
+                                            // mrg/stb_image seem to suffer on some of our pngs
+         {
+           queue_thumb (iter->data, thumbpath);
+         }
+      }
+      x += dim;
+      g_free (thumbpath);
+      g_free (path);
+    }
+    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)
+    {
+      char *path = suffix_path (iter->data);
+      char *thumbpath = get_thumb_path (path);
+      int w, h;
+
+      if (
+         access (thumbpath, F_OK) == 0 &&
+         mrg_query_image (mrg, thumbpath, &w, &h))
+      {
+
+        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);
+          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));
+          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);
+        }
+      }
+      else
+      {
+         if (access (thumbpath, F_OK) != 0) // only queue if does not exist,
+                                            // mrg/stb_image seem to suffer on some of our pngs
+         {
+           queue_thumb (iter->data, thumbpath);
+         }
+      }
+      x -= dim;
+      g_free (thumbpath);
+      g_free (path);
+    }
+
+  }
+
+  cairo_restore (cr);
+}
 
 static void ui_viewer (State *o)
 {
@@ -1601,12 +1794,12 @@ static void ui_viewer (State *o)
   cairo_save (cr);
   cairo_rectangle (cr, 0,0, width, height);
 
-  draw_grid (mrg, height * 0.1/3, height * 0.1/3, height * 0.12, height * 0.12);
+  draw_grid (mrg, height * 0.1/4, height * 0.1/4, height * 0.10, height * 0.10);
   if (o->show_controls)
     contrasty_stroke (cr);
   else
     cairo_new_path (cr);
-  cairo_rectangle (cr, 0, 0, height * 0.2, height * 0.2);
+  cairo_rectangle (cr, 0, 0, height * 0.15, height * 0.15);
   if (o->show_controls)
   {
     cairo_set_source_rgba (cr, 1,1,1,.1);
@@ -1614,13 +1807,13 @@ static void ui_viewer (State *o)
   }
   mrg_listen (mrg, MRG_PRESS, run_command, "parent", NULL);
 
-  draw_back (mrg, height * .1 / 3, height * .5, height * .1, height *.1);
+  draw_back (mrg, height * .1 / 4, height * .5, height * .1, height *.1);
   cairo_close_path (cr);
   if (o->show_controls)
     contrasty_stroke (cr);
   else
     cairo_new_path (cr);
-  cairo_rectangle (cr, 0, height * .3, height * .2, height *.7);
+  cairo_rectangle (cr, 0, height * .3, height * .15, height *.7);
   if (o->show_controls)
   {
     cairo_set_source_rgba (cr, 1,1,1,.1);
@@ -1629,13 +1822,13 @@ static void ui_viewer (State *o)
   mrg_listen (mrg, MRG_TAP, run_command, "prev", NULL);
   cairo_new_path (cr);
 
-  draw_forward (mrg, width - height * .15, height * .5, height * .1, height *.1);
+  draw_forward (mrg, width - height * .12, height * .5, height * .1, height *.1);
   cairo_close_path (cr);
   if (o->show_controls)
     contrasty_stroke (cr);
   else
     cairo_new_path (cr);
-  cairo_rectangle (cr, width - height * .2, height * .3, height * .2, height *.7);
+  cairo_rectangle (cr, width - height * .15, height * .3, height * .15, height *.7);
 
   if (o->show_controls)
   {
@@ -1643,13 +1836,13 @@ static void ui_viewer (State *o)
     cairo_fill_preserve (cr);
   }
   mrg_listen (mrg, MRG_TAP, run_command, "next", NULL);
-  draw_edit (mrg, width - height * .2, height * .0, height * .2, height *.2);
+  draw_edit (mrg, width - height * .15, height * .0, height * .15, height *.15);
 
   if (o->show_controls)
     contrasty_stroke (cr);
   else
     cairo_new_path (cr);
-  cairo_rectangle (cr, width - height * .2, height * .0, height * .2, height *.2);
+  cairo_rectangle (cr, width - height * .15, height * .0, height * .15, height *.15);
   if (o->show_controls)
   {
     cairo_set_source_rgba (cr, 1,1,1,.1);
@@ -1658,6 +1851,8 @@ static void ui_viewer (State *o)
   mrg_listen (mrg, MRG_PRESS, run_command, "toggle editing", NULL);
   cairo_new_path (cr);
 
+  if (o->show_thumbbar)
+    draw_thumb_bar (o);
 
   if (o->slide_enabled && o->slide_timeout == 0)
   {
@@ -1706,6 +1901,8 @@ static void dir_scroll_cb (MrgEvent *event, void *data1, void *data2)
   }
 }
 
+
+
 static void dir_touch_handling (Mrg *mrg, State *o)
 {
   cairo_new_path (mrg_cr (mrg));
@@ -2918,6 +3115,90 @@ static void on_graph_drag (MrgEvent *e, void *data1, void *data2)
   drag_preview (e);
 }
 
+
+static void on_thumbbar_drag (MrgEvent *e, void *data1, void *data2)
+{
+  static float pinch_coord[4][2] = {0,};
+  static int   pinch = 0;
+  static float orig_zoom = 1.0;
+
+  State *o = data1;
+  //GeglNode *node = data2;
+
+  on_viewer_motion (e, data1, data2);
+  if (e->type == MRG_DRAG_RELEASE)
+  {
+    pinch = 0;
+  } else if (e->type == MRG_DRAG_PRESS)
+  {
+    if (e->device_no == 5) /* 5 is second finger/touch point */
+    {
+      pinch_coord[1][0] = e->device_x;
+      pinch_coord[1][1] = e->device_y;
+      pinch_coord[2][0] = pinch_coord[0][0];
+      pinch_coord[2][1] = pinch_coord[0][1];
+      pinch_coord[3][0] = pinch_coord[1][0];
+      pinch_coord[3][1] = pinch_coord[1][1];
+      pinch = 1;
+      orig_zoom = o->graph_scale;
+    }
+    else if (e->device_no == 1 || e->device_no == 4) /* 1 is mouse pointer 4 is first finger */
+    {
+      pinch_coord[0][0] = e->device_x;
+      pinch_coord[0][1] = e->device_y;
+    }
+  } else if (e->type == MRG_DRAG_MOTION)
+  {
+    if (e->device_no == 1 || e->device_no == 4) /* 1 is mouse pointer 4 is first finger */
+    {
+      pinch_coord[0][0] = e->device_x;
+      pinch_coord[0][1] = e->device_y;
+    }
+    if (e->device_no == 5)
+    {
+      pinch_coord[1][0] = e->device_x;
+      pinch_coord[1][1] = e->device_y;
+    }
+
+    if (pinch)
+    {
+      float orig_dist = hypotf ( pinch_coord[2][0]- pinch_coord[3][0],
+                                 pinch_coord[2][1]- pinch_coord[3][1]);
+      float dist = hypotf (pinch_coord[0][0] - pinch_coord[1][0],
+                           pinch_coord[0][1] - pinch_coord[1][1]);
+    {
+      float x, y;
+      float screen_cx = (pinch_coord[0][0] + pinch_coord[1][0])/2;
+      float screen_cy = (pinch_coord[0][1] + pinch_coord[1][1])/2;
+      //get_coords_graph (o, screen_cx, screen_cy, &x, &y);
+
+      x = (o->thumbbar_pan_x + screen_cx) / o->thumbbar_scale;
+      y = (o->thumbbar_pan_y + screen_cy) / o->thumbbar_scale;
+
+      o->thumbbar_scale = orig_zoom * (dist / orig_dist);
+
+      o->thumbbar_pan_x = x * o->thumbbar_scale - screen_cx;
+      o->thumbbar_pan_y = y * o->thumbbar_scale - screen_cy;
+
+      o->thumbbar_pan_x -= (e->delta_x )/2; /* doing half contribution of motion per finger */
+      o->thumbbar_pan_y -= (e->delta_y )/2; /* is simple and roughly right */
+    }
+
+    }
+    else
+    {
+      if (e->device_no == 1 || e->device_no == 4)
+      {
+        o->thumbbar_pan_x -= (e->delta_x );
+        o->thumbbar_pan_y -= (e->delta_y );
+      }
+    }
+    mrg_queue_draw (e->mrg, NULL);
+  }
+  mrg_event_stop_propagate (e);
+}
+
+
 static void on_active_node_drag (MrgEvent *e, void *data1, void *data2, int is_aux)
 {
   State *o = data1;
@@ -4906,6 +5187,7 @@ static void load_path_inner (State *o,
   o->is_video = 0;
   o->frame_no = -1;
   o->prev_frame_played = 0;
+  o->thumbbar_pan_x = 0;
 
   if (g_str_has_suffix (path, ".gif"))
   {
diff --git a/operations/common/save.c b/operations/common/save.c
index 55ea8bf1b..4780c8fa9 100644
--- a/operations/common/save.c
+++ b/operations/common/save.c
@@ -61,9 +61,9 @@ gegl_save_set_saver (GeglOperation *operation)
   const gchar *extension, *handler;
 
   /* If prepare has already been invoked, bail out early */
-  if (self->cached_path && !strcmp (o->path, self->cached_path))
+  if (self->cached_path && o->path && !strcmp (o->path, self->cached_path))
       return;
-  if (*o->path == '\0')
+  if (o->path == NULL || *o->path == '\0')
     return;
   g_free (self->cached_path);
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]