ref: 6489ad6faa5679bfd5847c65ba3d2077d5491c11
parent: 6d7bb8930001936708e7cb47abfaa130c8e87dfc
author: cancel <cancel@cancel.fm>
date: Sun Dec 2 14:15:19 EST 2018
Add undo to tui
--- a/tui_main.c
+++ b/tui_main.c
@@ -185,6 +185,96 @@
waddchnstr(win, &ch, 1);
}
+typedef struct Field_pool_node {
+ Field field;
+ struct Field_pool_node* next;
+} Field_pool_node;
+
+typedef struct {
+ Field_pool_node* head;
+ Usz count;
+} Field_pool;
+
+void field_pool_take(Field_pool* pool, Field* out) {
+ (void)pool;
+ (void)out;
+}
+void field_pool_give(Field_pool* pool, Field* given) {
+ (void)pool;
+ (void)given;
+}
+
+typedef struct Undo_node {
+ Field field;
+ Usz tick_num;
+ struct Undo_node* prev;
+ struct Undo_node* next;
+} Undo_node;
+
+typedef struct {
+ Undo_node* first;
+ Undo_node* last;
+ Usz count;
+} Undo_history;
+
+void undo_history_init(Undo_history* hist) {
+ hist->first = NULL;
+ hist->last = NULL;
+}
+void undo_history_deinit(Undo_history* hist) {
+ Undo_node* a = hist->first;
+ while (a) {
+ Undo_node* b = a->next;
+ field_deinit(&a->field);
+ free(a);
+ a = b;
+ }
+}
+
+void undo_history_push(Undo_history* hist, Field* field, Usz tick_num) {
+ Undo_node* new_node = malloc(sizeof(Undo_node));
+ field_init(&new_node->field);
+ field_resize_raw(&new_node->field, field->height, field->width);
+ field_copy_subrect(field, &new_node->field, 0, 0, 0, 0, field->height,
+ field->width);
+ new_node->tick_num = tick_num;
+ if (hist->last) {
+ hist->last->next = new_node;
+ new_node->prev = hist->last;
+ } else {
+ hist->first = new_node;
+ hist->last = new_node;
+ new_node->prev = NULL;
+ }
+ new_node->next = NULL;
+ hist->last = new_node;
+}
+
+void undo_history_pop(Undo_history* hist, Field* out_field, Usz* out_tick_num) {
+ Undo_node* last = hist->last;
+ if (!last)
+ return;
+ Usz height = last->field.height;
+ Usz width = last->field.width;
+ if (out_field->height != height || out_field->width != width) {
+ field_resize_raw(out_field, height, width);
+ }
+ field_copy_subrect(&last->field, out_field, 0, 0, 0, 0, height, width);
+ *out_tick_num = last->tick_num;
+ if (hist->first == last) {
+ hist->first = NULL;
+ hist->last = NULL;
+ } else {
+ Undo_node* new_last = last->prev;
+ new_last->next = NULL;
+ hist->last = new_last;
+ }
+ field_deinit(&last->field);
+ free(last);
+}
+
+bool undo_history_count(Undo_history* hist) { return hist->count; }
+
void draw_ui_bar(WINDOW* win, int win_y, int win_x, const char* filename,
Usz tick_num) {
wmove(win, win_y, win_x);
@@ -287,6 +377,8 @@
mbuffer_clear(markmap_r.buffer, field.height, field.width);
Bank bank;
bank_init(&bank);
+ Undo_history undo_hist;
+ undo_history_init(&undo_hist);
// Enable UTF-8 by explicitly initializing our locale before initializing
// ncurses.
@@ -382,18 +474,26 @@
case KEY_RIGHT:
tui_cursor_move_relative(&tui_cursor, field.height, field.width, 0, 1);
break;
+ case AND_CTRL('u'):
+ if (undo_history_count(&undo_hist) > 0) {
+ undo_history_pop(&undo_hist, &field, &tick_num);
+ }
+ break;
case ' ':
+ undo_history_push(&undo_hist, &field, tick_num);
orca_run(field.buffer, markmap_r.buffer, field.height, field.width,
tick_num, &bank);
++tick_num;
break;
+ default:
+ if (key >= '!' && key <= '~') {
+ undo_history_push(&undo_hist, &field, tick_num);
+ gbuffer_poke(field.buffer, field.height, field.width, tui_cursor.y,
+ tui_cursor.x, (char)key);
+ }
+ break;
}
- if (key >= '!' && key <= '~') {
- gbuffer_poke(field.buffer, field.height, field.width, tui_cursor.y,
- tui_cursor.x, (char)key);
- }
-
// ncurses gives us the special value KEY_RESIZE if the user didn't
// actually type anything, but the terminal resized.
// bool ignored_input = ch < CHAR_MIN || ch > CHAR_MAX || ch == KEY_RESIZE;
@@ -403,5 +503,6 @@
markmap_reusable_deinit(&markmap_r);
bank_deinit(&bank);
field_deinit(&field);
+ undo_history_deinit(&undo_hist);
return 0;
}