raster pushed a commit to branch master.

http://git.enlightenment.org/core/enlightenment.git/commit/?id=3bfb56367910811a2a84d25bd5a7a1357ee6e135

commit 3bfb56367910811a2a84d25bd5a7a1357ee6e135
Author: Carsten Haitzler <[email protected]>
Date:   Mon Nov 1 12:49:59 2021 +0000

    paledit - add undo/redo with escape as undo
    
    now you can rescue yourself from badness...
---
 src/bin/tools/paledit/colsel.c    |   5 +
 src/bin/tools/paledit/main.c      |  19 +++
 src/bin/tools/paledit/main.h      |  20 +++
 src/bin/tools/paledit/meson.build |   3 +-
 src/bin/tools/paledit/palcols.c   |  45 ++++-
 src/bin/tools/paledit/undoredo.c  | 337 ++++++++++++++++++++++++++++++++++++++
 6 files changed, 427 insertions(+), 2 deletions(-)

diff --git a/src/bin/tools/paledit/colsel.c b/src/bin/tools/paledit/colsel.c
index af5ecaba5..2ee92c45d 100644
--- a/src/bin/tools/paledit/colsel.c
+++ b/src/bin/tools/paledit/colsel.c
@@ -12,6 +12,11 @@ _spinner_to_rect(Evas_Object *win)
      {
         Elm_Palette_Color *col = elm_object_item_data_get(it);
         Elm_Palette *pal = evas_object_data_get(win, "pal");
+
+        undoredo_op_col_change(win, col->name,
+                               col->r, col->g, col->b, col->a,
+                               r, g, b, a);
+        elm_config_palette_color_set(pal, col->name, r, g, b, a);
         col->r = r;
         col->g = g;
         col->b = b;
diff --git a/src/bin/tools/paledit/main.c b/src/bin/tools/paledit/main.c
index 0ddc07353..d06139e4d 100644
--- a/src/bin/tools/paledit/main.c
+++ b/src/bin/tools/paledit/main.c
@@ -19,6 +19,7 @@ pal_load(Evas_Object *win)
    if (!palname) return;
    Elm_Palette *pal = elm_config_palette_load(palname);
    if (!pal) return;
+   undoredo_reset(win);
    evas_object_data_set(win, "pal", pal);
    palcols_fill(win);
    palimg_update(evas_object_data_get(win, "pal_image"), pal);
@@ -32,6 +33,19 @@ _cb_close_click(void *data, Evas_Object *obj EINA_UNUSED, 
void *event_info EINA_
    evas_object_del(data);
 }
 
+static void
+_cb_key_down(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj EINA_UNUSED, 
void *event_info)
+{
+   Evas_Object *win = data;
+   Evas_Event_Key_Down *ev = event_info;
+
+   if (!strcmp(ev->key, "Escape"))
+     {
+        underedo_undo(win);
+     }
+}
+
+
 EAPI_MAIN int
 elm_main(int argc, char **argv)
 {
@@ -42,6 +56,11 @@ elm_main(int argc, char **argv)
    win = elm_win_util_standard_add("e_paledit", "Palette Editor");
    elm_win_autodel_set(win, EINA_TRUE);
 
+   o = evas_object_rectangle_add(evas_object_evas_get(win));
+   if (!evas_object_key_grab(o, "Escape", 0, 0, EINA_FALSE)) printf("Can't 
grab...\n");
+   evas_object_event_callback_add(o, EVAS_CALLBACK_KEY_DOWN,
+                                  _cb_key_down, win);
+
    fr = o = elm_frame_add(win);
    elm_object_style_set(o, "pad_medium");
    evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
diff --git a/src/bin/tools/paledit/main.h b/src/bin/tools/paledit/main.h
index 1578aa8ea..1b0d98b87 100644
--- a/src/bin/tools/paledit/main.h
+++ b/src/bin/tools/paledit/main.h
@@ -17,4 +17,24 @@ Evas_Object *colsel_add(Evas_Object *win);
 void         pal_load(Evas_Object *win);
 void         pal_save(Evas_Object *win);
 
+void
+undoredo_op_col_add(Evas_Object *win,
+                    const char *col,
+                    int r, int g, int b, int a);
+void
+undoredo_op_col_del(Evas_Object *win,
+                    const char *col,
+                    int r, int g, int b, int a);
+void
+undoredo_op_col_change(Evas_Object *win,
+                       const char *col,
+                       int r_from, int g_from, int b_from, int a_from,
+                       int r_to, int g_to, int b_to, int a_to);
+void
+undoredo_reset(Evas_Object *win);
+void
+underedo_undo(Evas_Object *win);
+void
+underedo_redo(Evas_Object *win);
+
 #endif
diff --git a/src/bin/tools/paledit/meson.build 
b/src/bin/tools/paledit/meson.build
index 6f74ac8cc..3ea1a9795 100644
--- a/src/bin/tools/paledit/meson.build
+++ b/src/bin/tools/paledit/meson.build
@@ -4,7 +4,8 @@ executable('enlightenment_paledit',
              'colsel.c',
              'palcols.c',
              'palimg.c',
-             'palsel.c'
+             'palsel.c',
+             'undoredo.c'
            ],
            include_directories: include_directories('.'),
            dependencies       : [ dep_elementary, deps ],
diff --git a/src/bin/tools/paledit/palcols.c b/src/bin/tools/paledit/palcols.c
index 5b2415380..93bcf1e79 100644
--- a/src/bin/tools/paledit/palcols.c
+++ b/src/bin/tools/paledit/palcols.c
@@ -121,6 +121,7 @@ _pal_color_add(Evas_Object *win)
                        if (!strcmp(col->name, plain)) goto exists;
                     }
                   elm_colorselector_color_get(evas_object_data_get(win, 
"pal_colorsel"), &r, &g, &b, &a);
+                  undoredo_op_col_add(win, plain, r, g, b, a);
                   elm_config_palette_color_set(pal, plain, r, g, b, a);
                   EINA_LIST_FOREACH(pal->colors, l, col)
                     {
@@ -157,6 +158,7 @@ _pal_color_del(Evas_Object *win)
      {
         Elm_Palette *pal = evas_object_data_get(win, "pal");
         Elm_Palette_Color *col = elm_object_item_data_get(it);
+        undoredo_op_col_del(win, col->name, col->r, col->g, col->b, col->a);
         if (col->name) elm_config_palette_color_unset(pal, col->name);
         it_sel = elm_genlist_item_next_get(it);
         if (!it_sel) it_sel = elm_genlist_item_prev_get(it);
@@ -490,6 +492,22 @@ _pal_hover_add(Evas_Object *win, Evas_Object *button)
 //   elm_theme_color_class_list_free(ccs);
 }
 
+static void
+_cb_undo_click(void *data, Evas_Object *obj EINA_UNUSED, void *event_info 
EINA_UNUSED)
+{
+   Evas_Object *win = data;
+
+   underedo_undo(win);
+}
+
+static void
+_cb_redo_click(void *data, Evas_Object *obj EINA_UNUSED, void *event_info 
EINA_UNUSED)
+{
+   Evas_Object *win = data;
+
+   underedo_redo(win);
+}
+
 static void
 _cb_modify_click(void *data, Evas_Object *obj EINA_UNUSED, void *event_info 
EINA_UNUSED)
 {
@@ -550,6 +568,32 @@ palcols_add(Evas_Object *win)
    evas_object_show(o);
    evas_object_data_set(win, "pal_image", o);
 
+   btn = o = elm_button_add(win);
+   evas_object_size_hint_weight_set(o, 0.0, 0.0);
+   evas_object_size_hint_fill_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL);
+   evas_object_smart_callback_add(o, "clicked", _cb_undo_click, win);
+   elm_box_pack_end(bxh, o);
+   evas_object_show(o);
+   elm_object_tooltip_text_set(o, "Undo");
+
+   o = elm_icon_add(win);
+   elm_icon_standard_set(o, "edit-undo");
+   elm_object_content_set(btn, o);
+   evas_object_show(o);
+
+   btn = o = elm_button_add(win);
+   evas_object_size_hint_weight_set(o, 0.0, 0.0);
+   evas_object_size_hint_fill_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL);
+   evas_object_smart_callback_add(o, "clicked", _cb_redo_click, win);
+   elm_box_pack_end(bxh, o);
+   evas_object_show(o);
+   elm_object_tooltip_text_set(o, "Redo");
+
+   o = elm_icon_add(win);
+   elm_icon_standard_set(o, "edit-redo");
+   elm_object_content_set(btn, o);
+   evas_object_show(o);
+
    o = elm_genlist_add(win);
    evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
    evas_object_size_hint_fill_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL);
@@ -559,7 +603,6 @@ palcols_add(Evas_Object *win)
    elm_object_tooltip_text_set(o, "Colors listed in this palette");
 
    btn = o = elm_button_add(win);
-   evas_object_size_hint_weight_set(o, 1.0, 0.0);
    evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, 0.0);
    evas_object_size_hint_fill_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL);
    evas_object_smart_callback_add(o, "clicked", _cb_modify_click, win);
diff --git a/src/bin/tools/paledit/undoredo.c b/src/bin/tools/paledit/undoredo.c
new file mode 100644
index 000000000..4ef1f5ed7
--- /dev/null
+++ b/src/bin/tools/paledit/undoredo.c
@@ -0,0 +1,337 @@
+#include "main.h"
+
+typedef enum
+{
+   ENTRY_NONE,
+   ENTRY_CHANGE,
+   ENTRY_ADD,
+   ENTRY_DEL
+} Entry_Type;
+
+typedef struct
+{
+   double tim;
+   const char *name;
+   Entry_Type type;
+   unsigned char r, g, b, a;
+   unsigned char r2, g2, b2, a2;
+} Entry;
+
+static Eina_List *undo = NULL;
+static Eina_List *list = NULL;
+static int ignore = 0;
+
+/*
+static void
+_dump(void)
+{
+   Entry *en;
+   Eina_List *l;
+
+   printf("--------------------------------------------------\n");
+   EINA_LIST_FOREACH(list, l, en)
+     {
+        if (l == undo) printf("* ");
+        else printf("  ");
+        switch (en->type)
+          {
+           case ENTRY_NONE:
+             printf("UNDO: none\n");
+             break;
+           case ENTRY_CHANGE:
+             printf("UNDO: change %5.2f [%s] %3i %3i %3i %3i -> %3i %3i %3i 
%3i\n",
+                    en->tim,
+                    en->name,
+                    en->r, en->g, en->b, en->a,
+                    en->r2, en->g2, en->b2, en->a2
+                   );
+             break;
+           case ENTRY_ADD:
+             printf("UNDO: add    %5.2f [%s] %3i %3i %3i %3i\n",
+                    en->tim,
+                    en->name,
+                    en->r, en->g, en->b, en->a
+                   );
+             break;
+           case ENTRY_DEL:
+             printf("UNDO: del    %5.2f [%s] %3i %3i %3i %3i\n",
+                    en->tim,
+                    en->name,
+                    en->r, en->g, en->b, en->a
+                   );
+             break;
+           default:
+             break;
+          }
+     }
+}
+*/
+
+static void
+_undo_init(void)
+{
+   Entry *en;
+
+   if (list) return;
+   en = calloc(1, sizeof(Entry));
+   if (!en) return;
+   en->name = eina_stringshare_add("");
+   en->tim = 0.0;
+   en->type = ENTRY_NONE;
+   list = eina_list_append(list, en);
+   undo = list;
+}
+
+static void
+_undo_remove(void)
+{
+   Entry *en;
+   Eina_List *l, *ll;
+
+   if (!undo) return;
+   EINA_LIST_REVERSE_FOREACH_SAFE(list, l, ll, en)
+     {
+        if (l == undo) break;
+        if (en->type == ENTRY_NONE) break;
+        eina_stringshare_del(en->name);
+        free(en);
+        list = eina_list_remove_list(list, l);
+     }
+   undo = NULL;
+}
+
+static void
+_undo_apply(Evas_Object *win, Entry *en)
+{
+   Elm_Palette *pal = evas_object_data_get(win, "pal");
+
+   ignore++;
+   switch (en->type)
+     {
+      case ENTRY_CHANGE:
+        elm_config_palette_color_set(pal, en->name,
+                                     en->r2, en->g2, en->b2, en->a2);
+        palcols_fill(win);
+        // XXX: update colorsel
+        break;
+      case ENTRY_ADD:
+        elm_config_palette_color_unset(pal, en->name);
+        palcols_fill(win);
+        break;
+      case ENTRY_DEL:
+        elm_config_palette_color_set(pal, en->name,
+                                     en->r, en->g, en->b, en->a);
+        palcols_fill(win);
+        break;
+      default:
+        break;
+     }
+   ignore--;
+}
+
+static void
+_redo_apply(Evas_Object *win, Entry *en)
+{
+   Elm_Palette *pal = evas_object_data_get(win, "pal");
+
+   ignore++;
+   switch (en->type)
+     {
+      case ENTRY_CHANGE:
+        elm_config_palette_color_set(pal, en->name,
+                                     en->r2, en->g2, en->b2, en->a2);
+        palcols_fill(win);
+        // XXX: update colorsel
+        break;
+      case ENTRY_ADD:
+        elm_config_palette_color_set(pal, en->name,
+                                     en->r, en->g, en->b, en->a);
+        palcols_fill(win);
+        break;
+      case ENTRY_DEL:
+        elm_config_palette_color_unset(pal, en->name);
+        palcols_fill(win);
+        break;
+      default:
+        break;
+     }
+   ignore--;
+}
+
+void
+undoredo_op_col_add(Evas_Object *win EINA_UNUSED,
+                    const char *col,
+                    int r, int g, int b, int a)
+{
+   Entry *en;
+   double t;
+
+   if (ignore) return;
+   if (!col) return;
+   t = ecore_time_get();
+   _undo_remove();
+   en = calloc(1, sizeof(Entry));
+   if (!en) return;
+   en->name = eina_stringshare_add(col);
+   en->tim = t;
+   en->type = ENTRY_ADD;
+   en->r = r;
+   en->g = g;
+   en->b = b;
+   en->a = a;
+   _undo_init();
+   list = eina_list_append(list, en);
+   undo = NULL;
+//   _dump();
+}
+
+void
+undoredo_op_col_del(Evas_Object *win EINA_UNUSED,
+                    const char *col,
+                    int r, int g, int b, int a)
+{
+   Entry *en;
+   double t;
+
+   if (ignore) return;
+   if (!col) return;
+   t = ecore_time_get();
+   _undo_remove();
+   en = calloc(1, sizeof(Entry));
+   if (!en) return;
+   en->name = eina_stringshare_add(col);
+   en->tim = t;
+   en->type = ENTRY_DEL;
+   en->r = r;
+   en->g = g;
+   en->b = b;
+   en->a = a;
+   _undo_init();
+   list = eina_list_append(list, en);
+   undo = NULL;
+//   _dump();
+}
+
+void
+undoredo_op_col_change(Evas_Object *win EINA_UNUSED,
+                       const char *col,
+                       int r_from, int g_from, int b_from, int a_from,
+                       int r_to, int g_to, int b_to, int a_to)
+{
+   Entry *en, *en_last = NULL;
+   Eina_List *l;
+   double t;
+
+   if (ignore) return;
+   if (!col) return;
+   if ((r_from == r_to) && (g_from == g_to) &&
+       (b_from == b_to) && (a_from == a_to)) return;
+   t = ecore_time_get();
+   _undo_remove();
+   l = eina_list_last(list);
+   if (l)
+     {
+        en = l->data;
+        if ((en->type == ENTRY_CHANGE) &&
+            (!strcmp(col, en->name)) &&
+            ((t - en->tim) < 0.5))
+          {
+             en->tim = t;
+             en->r2 = r_to;
+             en->g2 = g_to;
+             en->b2 = b_to;
+             en->a2 = a_to;
+//             _dump();
+             return;
+          }
+     }
+   EINA_LIST_REVERSE_FOREACH(list, l, en)
+     {
+        if (en->type == ENTRY_CHANGE)
+          {
+             if (!strcmp(en->name, col)) en_last = en;
+          }
+        else break;
+     }
+   _undo_init();
+   if (!en_last)
+     {
+        en = calloc(1, sizeof(Entry));
+        if (!en) return;
+        en->name = eina_stringshare_add(col);
+        en->tim = t - 1.0;
+        en->type = ENTRY_CHANGE;
+        en->r = r_from;
+        en->g = g_from;
+        en->b = b_from;
+        en->a = a_from;
+        en->r2 = r_from;
+        en->g2 = g_from;
+        en->b2 = b_from;
+        en->a2 = a_from;
+        list = eina_list_append(list, en);
+     }
+   en = calloc(1, sizeof(Entry));
+   if (!en) return;
+   en->name = eina_stringshare_add(col);
+   en->tim = t;
+   en->type = ENTRY_CHANGE;
+   en->r = r_from;
+   en->g = g_from;
+   en->b = b_from;
+   en->a = a_from;
+   en->r2 = r_to;
+   en->g2 = g_to;
+   en->b2 = b_to;
+   en->a2 = a_to;
+   _undo_init();
+   list = eina_list_append(list, en);
+   undo = NULL;
+//   _dump();
+}
+
+void
+undoredo_reset(Evas_Object *win EINA_UNUSED)
+{
+   Entry *en;
+
+   EINA_LIST_FREE(list, en)
+     {
+        eina_stringshare_del(en->name);
+        free(en);
+     }
+   undo = NULL;
+}
+
+void
+underedo_undo(Evas_Object *win)
+{
+   Entry *en;
+
+   if (undo)
+     {
+        en = undo->data;
+        if (en->type == ENTRY_NONE) return;
+        undo = undo->prev;
+     }
+   else undo = eina_list_last(list);
+   if (!undo) return;
+
+   en = undo->data;
+   if (en->type == ENTRY_NONE) return;
+   _undo_apply(win, en);
+//   _dump();
+}
+
+void
+underedo_redo(Evas_Object *win)
+{
+   Entry *en;
+
+   if (!undo) return;
+   undo = undo->next;
+   if (!undo) return;
+   en = undo->data;
+   _redo_apply(win, en);
+//   _dump();
+}

-- 


Reply via email to