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(); +}