forked from enlightenment/enventor
revise redo/undo code
This commit is contained in:
parent
06695c7c55
commit
950d2943a1
2
README
2
README
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
@ -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 *
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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__ */
|
||||
|
|
Loading…
Reference in New Issue