revise redo/undo code

This commit is contained in:
ChunEon Park 2014-08-02 16:41:24 +09:00
parent 06695c7c55
commit 950d2943a1
9 changed files with 317 additions and 386 deletions

2
README
View File

@ -57,6 +57,8 @@ Ctrl+Shift+W = Insert Part Template Code: Swallow
Ctrl+A = Select Text All
Ctrl+Double Click = Select a word
Ctrl+Z = Undo Text
Ctrl+R = Redo Text
Ctrl+C = Copy Selected Text
Ctrl+V = Paste Copied Text
Ctrl+X = Cut Selected Text

View File

@ -198,7 +198,6 @@ static void
insert_completed_text(autocomp_data *ad)
{
if (!ad->compset_list) return;
int redoundo_cursor = 0;
Elm_Object_Item *it = elm_list_selected_item_get(ad->list);
comp_set *compset = elm_object_item_data_get(it);
@ -206,7 +205,7 @@ insert_completed_text(autocomp_data *ad)
Evas_Object *entry = edit_entry_get(ad->ed);
int space = edit_cur_indent_depth_get(ad->ed);
redoundo_cursor = elm_entry_cursor_pos_get(entry);
int cursor_pos = elm_entry_cursor_pos_get(entry);
//Insert the first line.
elm_entry_entry_insert(entry, txt[0]+ (ad->queue_pos + 1));
@ -229,17 +228,12 @@ insert_completed_text(autocomp_data *ad)
elm_entry_entry_insert(entry, txt[i]);
}
int cursor_pos = elm_entry_cursor_pos_get(entry);
int cursor_pos2 = elm_entry_cursor_pos_get(entry);
redoundo_data *rd = evas_object_data_get(entry, "redoundo");
redoundo_entry_region_push(rd, cursor_pos, cursor_pos2);
/* undo/redo feture connection */
elm_entry_select_region_set(entry, redoundo_cursor, cursor_pos);
redoundo_node_add(elm_entry_selection_get(entry), redoundo_cursor,
cursor_pos - redoundo_cursor, EINA_TRUE);
elm_entry_select_none(entry);
/*--------------------------------------------------------------*/
cursor_pos -= (compset->cursor_offset + (compset->line_back * space));
elm_entry_cursor_pos_set(entry, cursor_pos);
cursor_pos2 -= (compset->cursor_offset + (compset->line_back * space));
elm_entry_cursor_pos_set(entry, cursor_pos2);
edit_line_increase(ad->ed, (compset->line_cnt - 1));
}

View File

@ -25,6 +25,7 @@ struct editor_s
syntax_helper *sh;
parser_data *pd;
redoundo_data *rd;
int cur_line;
int line_max;
@ -334,7 +335,7 @@ ctxpopup_candidate_selected_cb(void *data, Evas_Object *obj, void *event_info)
{
edit_data *ed = data;
const char *text = event_info;
redoundo_candidate_add(text, elm_entry_cursor_pos_get(ed->en_edit));
redoundo_text_relative_push(ed->rd, text);
elm_entry_entry_insert(ed->en_edit, text);
elm_ctxpopup_dismiss(obj);
edit_changed_set(ed, EINA_TRUE);
@ -445,6 +446,9 @@ edit_template_insert(edit_data *ed)
elm_entry_entry_insert(ed->en_edit, p);
elm_entry_entry_insert(ed->en_edit, t[i]);
int cursor_pos2 = elm_entry_cursor_pos_get(ed->en_edit);
redoundo_entry_region_push(ed->rd, cursor_pos, cursor_pos2);
elm_entry_cursor_pos_set(ed->en_edit, cursor_pos);
syntax_color_partial_update(ed, 0);
@ -519,7 +523,6 @@ edit_template_part_insert(edit_data *ed, Edje_Part_Type type)
break;
}
int redoundo_cursor = 0;
int i;
for (i = 0; i < (line_cnt - 1); i++)
{
@ -532,11 +535,8 @@ edit_template_part_insert(edit_data *ed, Edje_Part_Type type)
elm_entry_entry_insert(ed->en_edit, p);
elm_entry_entry_insert(ed->en_edit, t[i]);
redoundo_cursor = elm_entry_cursor_pos_get(ed->en_edit);
elm_entry_select_region_set(ed->en_edit, cursor_pos, redoundo_cursor);
redoundo_node_add(elm_entry_selection_get(ed->en_edit), cursor_pos,
redoundo_cursor - cursor_pos, EINA_TRUE);
elm_entry_select_none(ed->en_edit);
int cursor_pos2 = elm_entry_cursor_pos_get(ed->en_edit);
redoundo_entry_region_push(ed->rd, cursor_pos, cursor_pos2);
elm_entry_cursor_pos_set(ed->en_edit, cursor_pos);
@ -834,7 +834,8 @@ edit_line_delete(edit_data *ed)
//only one line remain. clear it.
if (ed->line_max == 1)
{
redoundo_node_add(elm_entry_entry_get(ed->en_edit), 0, 0, EINA_FALSE);
redoundo_text_push(ed->rd, elm_entry_entry_get(ed->en_edit), 0, 0,
EINA_FALSE);
elm_entry_entry_set(ed->en_edit, "");
line_init(ed);
return;
@ -857,15 +858,31 @@ edit_line_delete(edit_data *ed)
evas_textblock_cursor_range_delete(cur1, cur2);
evas_textblock_cursor_free(cur1);
evas_textblock_cursor_free(cur2);
redoundo_node_add(content, cur1_pos, abs(cur2_pos - cur1_pos), EINA_FALSE);
redoundo_text_push(ed->rd, content, cur1_pos, abs(cur2_pos - cur1_pos),
EINA_FALSE);
elm_entry_calc_force(ed->en_edit);
edit_line_decrease(ed, 1);
cur_line_pos_set(ed, EINA_TRUE);
edit_changed_set(ed, EINA_TRUE);
}
static void
edit_redoundo(edit_data *ed, Eina_Bool undo)
{
int lines;
Eina_Bool changed;
if (undo) lines = redoundo_undo(ed->rd, &changed);
else lines = redoundo_redo(ed->rd, &changed);
if (!changed) return;
if (lines > 0) edit_line_increase(ed, lines);
else edit_line_decrease(ed, abs(lines));
edit_changed_set(ed, EINA_TRUE);
syntax_color_full_update(ed, EINA_TRUE);
}
static Eina_Bool
@ -876,7 +893,26 @@ key_down_cb(void *data, int type EINA_UNUSED, void *ev)
//Control Key
if (!strcmp("Control_L", event->key))
ed->ctrl_pressed = EINA_TRUE;
{
ed->ctrl_pressed = EINA_TRUE;
return ECORE_CALLBACK_PASS_ON;
}
if (ed->ctrl_pressed)
{
//Undo
if (!strcmp(event->key, "z") || !strcmp(event->key, "Z"))
{
edit_redoundo(ed, EINA_TRUE);
return ECORE_CALLBACK_DONE;
}
//Redo
if (!strcmp(event->key, "r") || !strcmp(event->key, "R"))
{
edit_redoundo(ed, EINA_FALSE);
return ECORE_CALLBACK_DONE;
}
}
return ECORE_CALLBACK_PASS_ON;
}
@ -1019,7 +1055,8 @@ edit_init(Evas_Object *parent)
edit_line_number_toggle(ed);
edit_font_size_update(ed, EINA_FALSE, EINA_FALSE);
redoundo_init(en_edit);
ed->rd = redoundo_init(en_edit);
evas_object_data_set(ed->en_edit, "redoundo", ed->rd);
return ed;
}
@ -1044,13 +1081,13 @@ edit_term(edit_data *ed)
syntax_helper *sh = ed->sh;
parser_data *pd = ed->pd;
redoundo_term(ed->rd);
ecore_thread_cancel(ed->syntax_color_thread);
ecore_timer_del(ed->syntax_color_timer);
free(ed);
syntax_term(sh);
parser_term(pd);
redoundo_term();
}
void
@ -1202,6 +1239,7 @@ edit_edc_reload(edit_data *ed, const char *edc_path)
edit_new(ed);
edj_mgr_reload_need_set(EINA_TRUE);
config_apply();
redoundo_clear(ed->rd);
}
Eina_Stringshare *

View File

@ -95,9 +95,10 @@ indent_insert_br_case(indent_data *id, Evas_Object *entry)
memset(p, ' ', space);
p[space] = '\0';
redoundo_node_add(p, elm_entry_cursor_pos_get(entry), 0, EINA_TRUE);
elm_entry_entry_insert(entry, p);
redoundo_data *rd = evas_object_data_get(entry, "redoundo");
redoundo_text_push(rd, p, elm_entry_cursor_pos_get(entry), 0, EINA_TRUE);
elm_entry_entry_insert(entry, p);
}
static void

View File

@ -177,18 +177,6 @@ ctrl_func(app_data *ad, const char *key)
autocomp_toggle();
return ECORE_CALLBACK_DONE;
}
//Undo
if (!strcmp(key, "z") || !strcmp(key, "Z"))
{
undo(ad->ed);
return ECORE_CALLBACK_DONE;
}
//Redo
if (!strcmp(key, "y") || !strcmp(key, "Y"))
{
redo(ad->ed);
return ECORE_CALLBACK_DONE;
}
return ECORE_CALLBACK_PASS_ON;
}

View File

@ -171,7 +171,6 @@ newfile_open(menu_data *md)
md->newfile_layout = layout;
menu_activate_request();
redoundo_clear();
}
static void
@ -580,7 +579,6 @@ edc_file_load(menu_data *md)
elm_object_focus_set(fs, EINA_TRUE);
md->fileselector_layout = layout;
redoundo_clear();
}
static void

View File

@ -1,93 +1,63 @@
#include <Elementary.h>
#include "common.h"
/**
* @struct _Diff
* The structure, that store one step of changes.
*/
struct _Diff
typedef struct diff_s
{
Eina_Stringshare *diff; /**< The text, that was changed.*/
unsigned int length; /**< Length of changed text. */
unsigned int position; /**< Entry cursor position from that was changed text */
Eina_Bool action; /**< Type of action: EINA_TRUE - text insert,
EINA_FALSE - text delete */
Eina_Bool relative; /**< If this change relative to prevision or next step
this flag will EINA_TRUE*/
};
typedef struct _Diff Diff;
Eina_Stringshare *text;
unsigned int length;
unsigned int cursor_pos;
Eina_Bool action : 1; //EINA_TRUE: insert, EINA_FALSE, delete
Eina_Bool relative : 1; //If this change relative to prevision or next step
} diff_data;
/**
* @struct _redoundo_queue.
* The main structure of Redo/Undo module. Here stored queue of changes and
* support fields to manage this queue.
*/
struct _redoundo_queue
struct redoundo_s
{
Evas_Object *entry; /**< The elm_entry object, that will changed */
Evas_Object *textblock; /**< Textblock from entry, needed for apply changes */
Evas_Textblock_Cursor *cursor; /**< Support cursor, that provide fast access
to navigate in textblock. */
Eina_List *queue; /**< Queue of changes. Here stored
@c _Diff structures.*/
Eina_List *current_node; /**< Support list pointer, that provide
fast management with queue. Pointed to
current change list node*/
Diff *last_diff; /**< @c _Diff pointer to current changes.
Provide quick acces to changes data*/
Eina_Bool internal_change; /**< The flag, that indicates that change in
entry was initiated by Redo/Undo module. */
Evas_Object *entry;
Evas_Object *textblock;
Evas_Textblock_Cursor *cursor;
Eina_List *queue;
Eina_List *current_node;
diff_data *last_diff;
Eina_Bool internal_change : 1; //Entry change by redoundo
};
static queue *g_queue = NULL;
static void
_free_untracked_changes(void)
untracked_diff_free(redoundo_data *rd)
{
if (!g_queue) return;
if (!g_queue->last_diff)
if (!rd->last_diff)
{
redoundo_clear();
redoundo_clear(rd);
return;
}
Eina_List *l = NULL;
Diff *data = NULL;
Eina_List *l;
diff_data *diff;
EINA_LIST_REVERSE_FOREACH(g_queue->queue, l, data)
EINA_LIST_REVERSE_FOREACH(rd->queue, l, diff)
{
if (data == g_queue->last_diff) break;
eina_stringshare_del(data->diff);
free(data);
g_queue->queue = eina_list_remove_list(g_queue->queue, l);
if (diff == rd->last_diff) break;
eina_stringshare_del(diff->text);
free(diff);
rd->queue = eina_list_remove_list(rd->queue, l);
}
return;
}
static void
_changed_user_cb(void *data EINA_UNUSED,
Evas_Object *obj EINA_UNUSED,
const char *emission EINA_UNUSED,
const char *source EINA_UNUSED)
entry_changed_user_cb(void *data, Evas_Object *obj EINA_UNUSED,
const char *emission EINA_UNUSED,
const char *source EINA_UNUSED)
{
Edje_Entry_Change_Info *info = (Edje_Entry_Change_Info *)
edje_object_signal_callback_extra_data_get();
redoundo_data *rd = data;
Edje_Entry_Change_Info *info = edje_object_signal_callback_extra_data_get();
if (!info) return;
Diff *change = NULL;
int length = 0;
if (g_queue->internal_change)
if (rd->internal_change)
{
g_queue->internal_change = EINA_FALSE;
rd->internal_change = EINA_FALSE;
return;
}
change = (Diff *)calloc(1, sizeof(Diff));
if (!change)
diff_data *diff = calloc(1, sizeof(diff_data));
if (!diff)
{
EINA_LOG_ERR("Failed to allocate Memory!");
return;
@ -95,271 +65,286 @@ _changed_user_cb(void *data EINA_UNUSED,
if (info->insert)
{
if (!info->change.insert.plain_length) goto end;
change->diff = eina_stringshare_add(info->change.insert.content);
change->length = strlen(evas_textblock_text_markup_to_utf8(
g_queue->textblock, change->diff));
change->position = info->change.insert.pos;
change->action = EINA_TRUE;
if (info->change.insert.plain_length == 0) goto nochange;
diff->text = eina_stringshare_add(info->change.insert.content);
char *utf8 = evas_textblock_text_markup_to_utf8(NULL, diff->text);
diff->length = strlen(utf8);
diff->cursor_pos = info->change.insert.pos;
diff->action = EINA_TRUE;
free(utf8);
}
else
{
change->diff = eina_stringshare_add(info->change.del.content);
length = info->change.del.end - info->change.del.start;
if (!length) goto end;
int length = (info->change.del.end - info->change.del.start);
if (length == 0) goto nochange;
if (length > 0) change->position = info->change.del.start;
else change->position = info->change.del.end;
change->length = abs(length);
change->action = EINA_FALSE;
diff->text = eina_stringshare_add(info->change.del.content);
if (length > 0) diff->cursor_pos = info->change.del.start;
else diff->cursor_pos = info->change.del.end;
diff->length = abs(length);
diff->action = EINA_FALSE;
}
change->relative = EINA_FALSE;
diff->relative = EINA_FALSE;
_free_untracked_changes();
g_queue->queue = eina_list_append(g_queue->queue, change);
g_queue->last_diff = change;
g_queue->current_node = eina_list_last(g_queue->queue);
untracked_diff_free(rd);
rd->queue = eina_list_append(rd->queue, diff);
rd->last_diff = diff;
rd->current_node = eina_list_last(rd->queue);
return;
end:
free(change);
return;
nochange:
free(diff);
}
Eina_Bool
undo(edit_data *ed)
int
redoundo_undo(redoundo_data *rd, Eina_Bool *changed)
{
if ((!g_queue) || (!g_queue->last_diff))
return EINA_FALSE;
*changed = EINA_FALSE;
int lines = 0;
if (!rd->last_diff) return 0;
elm_entry_cursor_pos_set(g_queue->entry, g_queue->last_diff->position);
g_queue->internal_change = EINA_TRUE;
if (g_queue->last_diff->action)
{ /* Last change was adding new symbol(s), that mean here need delete it */
stats_line_num_update(0, elm_entry_cursor_pos_get(g_queue->entry));
if (g_queue->last_diff->length == 1)
{
evas_textblock_cursor_pos_set(g_queue->cursor,
g_queue->last_diff->position);
evas_textblock_cursor_char_delete(g_queue->cursor);
}
else
{
Evas_Textblock_Cursor *range = evas_object_textblock_cursor_new(
g_queue->textblock);
evas_textblock_cursor_pos_set(g_queue->cursor,
g_queue->last_diff->position);
evas_textblock_cursor_pos_set(range, g_queue->last_diff->position +
g_queue->last_diff->length);
evas_textblock_cursor_range_delete(g_queue->cursor, range);
evas_textblock_cursor_free(range);
}
lines = parser_line_cnt_get(NULL, g_queue->last_diff->diff);
edit_line_decrease(ed, lines);
}
else
{
evas_textblock_cursor_pos_set(g_queue->cursor,
g_queue->last_diff->position);
evas_object_textblock_text_markup_prepend(g_queue->cursor,
g_queue->last_diff->diff);
elm_entry_cursor_pos_set(rd->entry, rd->last_diff->cursor_pos);
rd->internal_change = EINA_TRUE;
lines = parser_line_cnt_get(NULL, g_queue->last_diff->diff);
edit_line_increase(ed, lines);
}
g_queue->internal_change = EINA_FALSE;
g_queue->current_node = eina_list_prev(g_queue->current_node);
g_queue->last_diff = eina_list_data_get(g_queue->current_node);
if ((g_queue->last_diff) && (g_queue->last_diff->relative)) undo(ed);
edit_changed_set(ed, EINA_TRUE);
edit_syntax_color_full_apply(ed, EINA_TRUE);
return EINA_TRUE;
}
Eina_Bool
redo(edit_data *ed)
{
if ((!g_queue) || (!g_queue->queue))
return EINA_FALSE;
Eina_List *next = NULL;
Diff *change = NULL;
int lines;
next = eina_list_next(g_queue->current_node);
change = eina_list_data_get(next);
if ((!next) && (!g_queue->last_diff))
if (rd->last_diff->action)
{
next = g_queue->queue;
change = eina_list_data_get(next);
}
//Last change was adding new symbol(s), that mean here need delete it
//FIXME: cur_line is 0?
stats_line_num_update(0, elm_entry_cursor_pos_get(rd->entry));
if ((!next) || (!change))
{
g_queue->internal_change = EINA_FALSE;
return EINA_FALSE;
}
g_queue->internal_change = EINA_TRUE;
if (change->action)
{
evas_textblock_cursor_pos_set(g_queue->cursor, change->position);
evas_object_textblock_text_markup_prepend(g_queue->cursor, change->diff);
lines = parser_line_cnt_get(NULL, change->diff);
edit_line_increase(ed, lines);
//Undo one character
if (rd->last_diff->length == 1)
{
evas_textblock_cursor_pos_set(rd->cursor,
rd->last_diff->cursor_pos);
evas_textblock_cursor_char_delete(rd->cursor);
}
//Undo String
else
{
Evas_Textblock_Cursor *cursor =
evas_object_textblock_cursor_new( rd->textblock);
evas_textblock_cursor_pos_set(rd->cursor,
rd->last_diff->cursor_pos);
evas_textblock_cursor_pos_set(cursor,
(rd->last_diff->cursor_pos +
rd->last_diff->length));
evas_textblock_cursor_range_delete(rd->cursor, cursor);
evas_textblock_cursor_free(cursor);
}
lines = -parser_line_cnt_get(NULL, rd->last_diff->text);
}
else
{
if (change->length == 1)
evas_textblock_cursor_pos_set(rd->cursor,
rd->last_diff->cursor_pos);
evas_object_textblock_text_markup_prepend(rd->cursor,
rd->last_diff->text);
lines = parser_line_cnt_get(NULL, rd->last_diff->text);
}
rd->internal_change = EINA_FALSE;
rd->current_node = eina_list_prev(rd->current_node);
rd->last_diff = eina_list_data_get(rd->current_node);
if (rd->last_diff && rd->last_diff->relative)
lines += redoundo_undo(rd, changed);
*changed = EINA_TRUE;
return lines;
}
int
redoundo_redo(redoundo_data *rd, Eina_Bool *changed)
{
*changed = EINA_FALSE;
if (!rd->queue) return 0;
Eina_List *next;
diff_data *diff;
int lines;
next = eina_list_next(rd->current_node);
diff = eina_list_data_get(next);
if ((!next) && (!rd->last_diff))
{
next = rd->queue;
diff = eina_list_data_get(next);
}
if (!next || !diff)
{
rd->internal_change = EINA_FALSE;
return 0;
}
rd->internal_change = EINA_TRUE;
//Insert
if (diff->action)
{
evas_textblock_cursor_pos_set(rd->cursor, diff->cursor_pos);
evas_object_textblock_text_markup_prepend(rd->cursor, diff->text);
lines = parser_line_cnt_get(NULL, diff->text);
}
//Remove
else
{
//One Character
if (diff->length == 1)
{
evas_textblock_cursor_pos_set(g_queue->cursor, change->position);
evas_textblock_cursor_char_delete(g_queue->cursor);
evas_textblock_cursor_pos_set(rd->cursor, diff->cursor_pos);
evas_textblock_cursor_char_delete(rd->cursor);
}
//String
else
{
Evas_Textblock_Cursor *range = evas_object_textblock_cursor_new(
g_queue->textblock);
evas_textblock_cursor_pos_set(g_queue->cursor, change->position);
evas_textblock_cursor_pos_set(range, change->position + change->length);
evas_textblock_cursor_range_delete(g_queue->cursor, range);
evas_textblock_cursor_free(range);
Evas_Textblock_Cursor *cursor =
evas_object_textblock_cursor_new(rd->textblock);
evas_textblock_cursor_pos_set(rd->cursor, diff->cursor_pos);
evas_textblock_cursor_pos_set(cursor,
(diff->cursor_pos + diff->length));
evas_textblock_cursor_range_delete(rd->cursor, cursor);
evas_textblock_cursor_free(cursor);
}
lines = parser_line_cnt_get(NULL, change->diff);
edit_line_decrease(ed, lines);
}
g_queue->internal_change = EINA_FALSE;
elm_entry_cursor_pos_set(g_queue->entry, change->position + change->length);
g_queue->last_diff = change;
g_queue->current_node = next;
if (change->relative) redo(ed);
edit_changed_set(ed, EINA_TRUE);
edit_syntax_color_full_apply(ed, EINA_TRUE);
return EINA_TRUE;
}
Eina_Bool
redoundo_candidate_add(const char *content, int pos)
{
if ((!g_queue) || (!content) || (!pos)) return EINA_FALSE;
Diff *change = NULL;
change = (Diff *)calloc(1, sizeof(Diff));
if (!change)
{
EINA_LOG_ERR("Failed to allocate Memory!");
return EINA_FALSE;
lines = -parser_line_cnt_get(NULL, diff->text);
}
change->diff = eina_stringshare_add(content);
change->length = strlen(evas_textblock_text_markup_to_utf8(
g_queue->textblock, change->diff));
change->position = pos;
change->action = EINA_TRUE;
change->relative = EINA_TRUE;
rd->internal_change = EINA_FALSE;
elm_entry_cursor_pos_set(rd->entry, (diff->cursor_pos + diff->length));
_free_untracked_changes();
g_queue->queue = eina_list_append(g_queue->queue, change);
g_queue->last_diff = change;
g_queue->current_node = eina_list_last(g_queue->queue);
rd->last_diff = diff;
rd->current_node = next;
if (diff->relative)
lines += redoundo_redo(rd, changed);
*changed = EINA_TRUE;
return EINA_TRUE;
}
Eina_Bool
redoundo_node_add(const char *content, int pos, int length, Eina_Bool insert)
void
redoundo_text_push(redoundo_data *rd, const char *text, int pos, int length,
Eina_Bool insert)
{
if ((!g_queue) || (!content)) return EINA_FALSE;
Diff *change = NULL;
if (!text) return;
change = (Diff *)calloc(1, sizeof(Diff));
if (!change)
diff_data *diff = calloc(1, sizeof(diff_data));
if (!diff)
{
EINA_LOG_ERR("Failed to allocate Memory!");
return;
}
change->diff = eina_stringshare_add(content);
if (length) change->length = length;
else change->length = strlen(evas_textblock_text_markup_to_utf8(
g_queue->textblock, change->diff));
if (!change->length)
if (length) diff->length = length;
else
{
eina_stringshare_del(change->diff);
free(change);
return;
char *utf8 = evas_textblock_text_markup_to_utf8(NULL, text);
diff->length = strlen(utf8);
free(utf8);
if (!diff->length)
{
free(diff);
return;
}
}
change->position = pos;
change->action = insert;
change->relative = EINA_FALSE;
_free_untracked_changes();
g_queue->queue = eina_list_append(g_queue->queue, change);
g_queue->last_diff = change;
g_queue->current_node = eina_list_last(g_queue->queue);
diff->text = eina_stringshare_add(text);
diff->cursor_pos = pos;
diff->action = insert;
diff->relative = EINA_FALSE;
return EINA_TRUE;
untracked_diff_free(rd);
rd->queue = eina_list_append(rd->queue, diff);
rd->last_diff = diff;
rd->current_node = eina_list_last(rd->queue);
}
queue *
redoundo_data *
redoundo_init(Evas_Object *entry)
{
if (!entry) return NULL;
g_queue = (queue *)calloc(1, sizeof(queue));
if (!g_queue)
redoundo_data *rd = calloc(1, sizeof(redoundo_data));
if (!rd)
{
EINA_LOG_ERR("Failed to allocate Memory!");
return NULL;
}
g_queue->entry = entry;
g_queue->textblock = elm_entry_textblock_get(entry);
g_queue->cursor = evas_object_textblock_cursor_new(g_queue->textblock);
g_queue->internal_change = EINA_FALSE;
rd->entry = entry;
rd->textblock = elm_entry_textblock_get(entry);
rd->cursor = evas_object_textblock_cursor_new(rd->textblock);
//FIXME: Why signal callback? not smart callback?
elm_object_signal_callback_add(entry, "entry,changed,user", "*",
_changed_user_cb, NULL);
return g_queue;
entry_changed_user_cb, rd);
return rd;
}
Eina_Bool
redoundo_clear(void)
void
redoundo_clear(redoundo_data *rd)
{
Diff *data = NULL;
if (!g_queue) return EINA_FALSE;
diff_data *data;
EINA_LIST_FREE(g_queue->queue, data)
EINA_LIST_FREE(rd->queue, data)
{
eina_stringshare_del(data->diff);
eina_stringshare_del(data->text);
free(data);
}
g_queue->internal_change = EINA_FALSE;
return EINA_TRUE;
rd->internal_change = EINA_FALSE;
}
Eina_Bool
redoundo_term(void)
void
redoundo_term(redoundo_data *rd)
{
if (!g_queue) return EINA_FALSE;
g_queue->entry = NULL;
g_queue->textblock = NULL;
evas_textblock_cursor_free(g_queue->cursor);
redoundo_clear();
free(g_queue);
return EINA_TRUE;
redoundo_clear(rd);
evas_textblock_cursor_free(rd->cursor);
free(rd);
}
void
redoundo_entry_region_push(redoundo_data *rd, int cursor_pos, int cursor_pos2)
{
elm_entry_select_region_set(rd->entry, cursor_pos, cursor_pos2);
redoundo_text_push(rd, elm_entry_selection_get(rd->entry), cursor_pos,
(cursor_pos2 - cursor_pos), EINA_TRUE);
elm_entry_select_none(rd->entry);
}
void
redoundo_text_relative_push(redoundo_data *rd, const char *text)
{
if (!text) return;
diff_data *diff = malloc(sizeof(diff_data));
if (!diff)
{
EINA_LOG_ERR("Failed to allocate Memory!");
return;
}
diff->text = eina_stringshare_add(text);
char *utf8 = evas_textblock_text_markup_to_utf8(NULL, diff->text);
diff->length = strlen(utf8);
diff->cursor_pos = elm_entry_cursor_pos_get(rd->entry);
diff->action = EINA_TRUE;
diff->relative = EINA_TRUE;
untracked_diff_free(rd);
rd->queue = eina_list_append(rd->queue, diff);
rd->last_diff = diff;
rd->current_node = eina_list_last(rd->queue);
free(utf8);
}

View File

@ -9,7 +9,7 @@ typedef struct parser_s parser_data;
typedef struct attr_value_s attr_value;
typedef struct syntax_helper_s syntax_helper;
typedef struct indent_s indent_data;
typedef struct _redoundo_queue queue;
typedef struct redoundo_s redoundo_data;
#include "edc_editor.h"
#include "menu.h"

View File

@ -1,84 +1,9 @@
#ifndef __REDOUNDO_H__
#define __REDOUNDO_H__
redoundo_data *redoundo_init(Evas_Object *entry);
void redoundo_term(redoundo_data *rd);
void redoundo_clear(redoundo_data *rd);
void redoundo_text_push(redoundo_data *rd, const char *text, int pos, int length, Eina_Bool insert);
void redoundo_text_relative_push(redoundo_data *rd, const char *text);
void redoundo_entry_region_push(redoundo_data *rd, int cursor_pos, int cursor_pos2);
int redoundo_undo(redoundo_data *rd, Eina_Bool *changed);
int redoundo_redo(redoundo_data *rd, Eina_Bool *changed);
/* FIXME: Change comments! */
/**
* This function undo the last change, that will happen in entry. If there are
* wasn't changes will returned EINA_FALSE;
*
* @param ed The pointer to the editor_s instatns;
*
* @return EINA_TRUE on success or EINA_FALSE in otherwise.
*/
Eina_Bool
undo(edit_data *ed);
/**
* This function redo the previos change, that will happen in entry. If there are
* wasn't changes will returned EINA_FALSE;
*
* @param ed The pointer to the editor_s instatns;
*
* @return EINA_TRUE on success or EINA_FALSE in otherwise.
*/
Eina_Bool
redo(edit_data *ed);
/**
* This function provide add new node into undo/redo stack, that shoud take
* undo or redo action with next(for redo) or prevision(for undo) node from stack.
*
* @param content The pointer to text, which need mark as changed.
* @param pos The position, where text shoud begin in editable area.
*
* @return EINA_TRUE on success or EINA_FALSE in otherwise.
*
*/
Eina_Bool
redoundo_candidate_add(const char *content, int pos);
/**
* This function provide add new node into undo/redo stack.
*
* @param content The pointer to text, which need mark as changed.
* @param pos The position, where text shoud begin in editable area.
* @param length The length of text. If this value equal 0, then length will
* calculate with using eina_stringshare_strlen, after sharing.
* @param insert If EINA_TRUE change will mark as new text append action,
* else change will known as remove action.
*
* @return EINA_TRUE on success or EINA_FALSE in otherwise.
*
* @note This function need to resolve situations, where text is inserted by API,
* and this event doesn't emit signal "entry,changed,user"
*/
Eina_Bool
redoundo_node_add(const char *diff, int pos, int length, Eina_Bool insert);
/**
* Initialize undo/redo module.
*
* @param entry The Evas_Object pointer to elm_entry, that contain chengable text.
* @return @queue structure if success, or NULL in otherwise.
*/
queue *
redoundo_init(Evas_Object *entry);
/**
* Terminating undo/redo submodule;
*
* @return EINA_TRUE on success or EINA_FALSE in otherwise.
*/
Eina_Bool
redoundo_term(void);
/**
* Clear all history of changes;
*
* @return EINA_TRUE on success or EINA_FALSE in otherwise.
*/
Eina_Bool
redoundo_clear(void);
#endif /* __REDOUNDO_H__ */