diff --git a/tui.c b/tui.c index 279edf8..927ec4c 100644 --- a/tui.c +++ b/tui.c @@ -22,6 +22,7 @@ enum { }; static Engine *g_engine = NULL; +static DispatchFn g_dispatch = NULL; static int selected_row = 0; static int selected_col = 0; static bool show_help = false; @@ -36,7 +37,6 @@ typedef enum { // Mark storage #define MAX_MARKS 26 // a-z static int marks[MAX_MARKS]; // stores clip_index for each mark -static int mark_selected = -1; // -1 = no mark selected // Visual mode state static int visual_start_row = 0; @@ -109,32 +109,16 @@ static int* get_selected_clips(int *count) { return clips; } -// Get all clip indices in a row -static int* get_row_clips(int row, int *count) { - *count = GRID_COLS; - int *clips = (int *)malloc(*count * sizeof(int)); - if (!clips) { - *count = 0; - return NULL; - } - - for (int c = 0; c < GRID_COLS; c++) { - clips[c] = grid_to_clip_index(row, c); - } - - return clips; -} - -// Delete (reset) clips +// Delete (reset) clips via dispatch static void delete_clips(int *clip_indices, int count) { for (int i = 0; i < count; i++) { - engine_reset_clip(g_engine, clip_indices[i]); + Action action = { .type = ACTION_RESET_CLIP, .data.reset_clip = { .clip_index = clip_indices[i] } }; + g_dispatch(action); } } // Yank clips (store their indices) static void yank_clips(int *clip_indices, int count) { - // Free previous yank buffer if (yank_buffer.clip_indices) { free(yank_buffer.clip_indices); } @@ -146,11 +130,10 @@ static void yank_clips(int *clip_indices, int count) { } } -// Paste clips (trigger them) +// Paste clips (trigger them via dispatch) static void paste_clips(void) { if (!yank_buffer.clip_indices || yank_buffer.count == 0) return; - // Calculate offset from current position to first yanked clip int first_yanked_row = yank_buffer.clip_indices[0] / GRID_COLS; int first_yanked_col = yank_buffer.clip_indices[0] % GRID_COLS; int row_offset = selected_row - first_yanked_row; @@ -163,13 +146,13 @@ static void paste_clips(void) { int new_row = orig_row + row_offset; int new_col = orig_col + col_offset; - // Bounds check if (new_row >= 0 && new_row < GRID_ROWS && new_col >= 0 && new_col < GRID_COLS) { int new_clip_idx = grid_to_clip_index(new_row, new_col); - // Trigger three times to go from empty -> recording -> looping -> stopped - engine_trigger_clip(g_engine, new_clip_idx); - engine_trigger_clip(g_engine, new_clip_idx); - engine_trigger_clip(g_engine, new_clip_idx); + // Trigger three times to cycle: empty -> recording -> looping -> stopped + for (int j = 0; j < 3; j++) { + Action action = { .type = ACTION_TRIGGER_CLIP, .data.trigger_clip = { .clip_index = new_clip_idx } }; + g_dispatch(action); + } } } } @@ -197,48 +180,47 @@ static void go_to_mark(char mark_char) { // Play next scene (next row) static void play_next_scene(void) { int next_row = (selected_row + 1) % GRID_ROWS; - engine_trigger_scene(g_engine, next_row); + Action action = { .type = ACTION_TRIGGER_SCENE, .data.trigger_scene = { .scene_index = next_row } }; + g_dispatch(action); selected_row = next_row; } // Play previous scene (previous row) static void play_prev_scene(void) { int prev_row = (selected_row - 1 + GRID_ROWS) % GRID_ROWS; - engine_trigger_scene(g_engine, prev_row); + Action action = { .type = ACTION_TRIGGER_SCENE, .data.trigger_scene = { .scene_index = prev_row } }; + g_dispatch(action); selected_row = prev_row; } // Draw a single cell static void draw_cell(int row, int col, bool selected) { int clip_idx = grid_to_clip_index(row, col); - Clip *clip = &g_engine->clips[clip_idx]; + AppState state = dispatcher_get_state(); + Clip *clip = &state.clips[clip_idx]; int y = row * CELL_HEIGHT + 1; int x = col * CELL_WIDTH + 1; - int color = state_to_color((ClipState)atomic_load(&clip->state)); + int color = state_to_color(clip->state); if (selected) { color = COLOR_SELECTED; } else if (current_mode == MODE_VISUAL && is_in_visual_selection(row, col)) { - // Use a different highlight for visual selection (invert colors) - color = COLOR_SELECTED; // Same as selected for now + color = COLOR_SELECTED; } attron(COLOR_PAIR(color)); - // Draw cell border for (int dy = 0; dy < CELL_HEIGHT; dy++) { for (int dx = 0; dx < CELL_WIDTH; dx++) { mvaddch(y + dy, x + dx, ' '); } } - // Draw clip number mvprintw(y + 1, x + 1, "%2d", clip_idx); - // Draw state indicator char state_char; - switch ((ClipState)atomic_load(&clip->state)) { + switch (clip->state) { case CLIP_EMPTY: state_char = ' '; break; case CLIP_RECORDING: state_char = 'R'; break; case CLIP_LOOPING: state_char = 'L'; break; @@ -254,12 +236,12 @@ static void draw_cell(int row, int col, bool selected) { static void draw_grid(void) { clear(); - // Draw title attron(A_BOLD); mvprintw(0, 0, "JACK Looper - 8x8 Clip Grid"); attroff(A_BOLD); - // Draw cells + AppState state = dispatcher_get_state(); + for (int row = 0; row < GRID_ROWS; row++) { for (int col = 0; col < GRID_COLS; col++) { bool selected = (row == selected_row && col == selected_col); @@ -267,27 +249,21 @@ static void draw_grid(void) { } } - // Draw status bar int clip_idx = grid_to_clip_index(selected_row, selected_col); - Clip *clip = &g_engine->clips[clip_idx]; + Clip *clip = &state.clips[clip_idx]; mvprintw(GRID_ROWS * CELL_HEIGHT + 1, 0, "Selected: Clip %d | State: %s | Buffer: %zu samples", - clip_idx, clip_state_to_string((ClipState)atomic_load(&clip->state)), - (size_t)atomic_load(&clip->buffer_size)); - - TransportState transport_state = (TransportState)atomic_load(&g_engine->transport->state_atomic); - ClockSource clock_source = (ClockSource)atomic_load(&g_engine->transport->clock_source_atomic); + clip_idx, clip_state_to_string(clip->state), clip->buffer_size); mvprintw(GRID_ROWS * CELL_HEIGHT + 2, 0, "Transport: %s | Clock: %s | BPM: %.1f | Quantize: %s | Threshold: %u", - transport_state_to_string(transport_state), - clock_source_to_string(clock_source), - (double)atomic_load(&g_engine->transport->bpm_atomic_raw) / 100.0, - quantize_mode_to_string((QuantizeMode)atomic_load(&g_engine->quantize_mode_atomic)), - (unsigned int)atomic_load(&g_engine->quantize_threshold_atomic)); + transport_state_to_string(state.transport_state), + clock_source_to_string(state.clock_source), + state.bpm, + quantize_mode_to_string(state.quantize_mode), + (unsigned int)state.quantize_threshold); - // Draw mode indicator const char *mode_str; switch (current_mode) { case MODE_NORMAL: mode_str = "NORMAL"; break; @@ -295,38 +271,23 @@ static void draw_grid(void) { case MODE_MOVE: mode_str = "MOVE"; break; default: mode_str = "?"; break; } - mvprintw(GRID_ROWS * CELL_HEIGHT + 3, 0, - "Mode: %s", mode_str); + mvprintw(GRID_ROWS * CELL_HEIGHT + 3, 0, "Mode: %s", mode_str); - // Draw help if active if (show_help) { attron(COLOR_PAIR(COLOR_HELP)); - mvprintw(GRID_ROWS * CELL_HEIGHT + 4, 0, - "=== Help ==="); - mvprintw(GRID_ROWS * CELL_HEIGHT + 5, 0, - "h/j/k/l - Navigate grid (left/down/up/right)"); - mvprintw(GRID_ROWS * CELL_HEIGHT + 6, 0, - "t - Trigger selected clip"); - mvprintw(GRID_ROWS * CELL_HEIGHT + 7, 0, - "r - Reset selected clip"); - mvprintw(GRID_ROWS * CELL_HEIGHT + 8, 0, - "s - Trigger scene (current row)"); - mvprintw(GRID_ROWS * CELL_HEIGHT + 9, 0, - "Space - Play/Pause transport"); - mvprintw(GRID_ROWS * CELL_HEIGHT + 10, 0, - "S - Stop transport"); - mvprintw(GRID_ROWS * CELL_HEIGHT + 11, 0, - "C - Toggle clock source (Internal/MIDI)"); - mvprintw(GRID_ROWS * CELL_HEIGHT + 12, 0, - "q - Toggle quantize mode (off/beat/bar)"); - mvprintw(GRID_ROWS * CELL_HEIGHT + 13, 0, - "T - Set quantize threshold"); - mvprintw(GRID_ROWS * CELL_HEIGHT + 14, 0, - "x - Reset transport position"); - mvprintw(GRID_ROWS * CELL_HEIGHT + 15, 0, - "? - Toggle help"); - mvprintw(GRID_ROWS * CELL_HEIGHT + 16, 0, - "Esc/q - Quit"); + mvprintw(GRID_ROWS * CELL_HEIGHT + 4, 0, "=== Help ==="); + mvprintw(GRID_ROWS * CELL_HEIGHT + 5, 0, "h/j/k/l - Navigate grid (left/down/up/right)"); + mvprintw(GRID_ROWS * CELL_HEIGHT + 6, 0, "t - Trigger selected clip"); + mvprintw(GRID_ROWS * CELL_HEIGHT + 7, 0, "r - Reset selected clip"); + mvprintw(GRID_ROWS * CELL_HEIGHT + 8, 0, "s - Trigger scene (current row)"); + mvprintw(GRID_ROWS * CELL_HEIGHT + 9, 0, "Space - Play/Pause transport"); + mvprintw(GRID_ROWS * CELL_HEIGHT + 10, 0, "S - Stop transport"); + mvprintw(GRID_ROWS * CELL_HEIGHT + 11, 0, "C - Toggle clock source (Internal/MIDI)"); + mvprintw(GRID_ROWS * CELL_HEIGHT + 12, 0, "q - Toggle quantize mode (off/beat/bar)"); + mvprintw(GRID_ROWS * CELL_HEIGHT + 13, 0, "T - Set quantize threshold"); + mvprintw(GRID_ROWS * CELL_HEIGHT + 14, 0, "x - Reset transport position"); + mvprintw(GRID_ROWS * CELL_HEIGHT + 15, 0, "? - Toggle help"); + mvprintw(GRID_ROWS * CELL_HEIGHT + 16, 0, "Esc/q - Quit"); attroff(COLOR_PAIR(COLOR_HELP)); } @@ -334,42 +295,31 @@ static void draw_grid(void) { } // Handle command mode input (after pressing ':') -// Returns true if the application should quit static bool handle_command_mode(void) { char cmd_buffer[256]; int cmd_pos = 0; memset(cmd_buffer, 0, sizeof(cmd_buffer)); - // Save current nodelay state and force blocking input int prev_nodelay = nodelay(stdscr, FALSE); - // Show command prompt mvprintw(LINES - 1, 0, ":"); clrtoeol(); refresh(); while (1) { int ch = getch(); - // Do NOT break on ERR; getch() will block now if (ch == '\n' || ch == '\r') { - // Execute command cmd_buffer[cmd_pos] = '\0'; - - // Clear command line mvprintw(LINES - 1, 0, " "); refresh(); - // Parse and execute command if (strcmp(cmd_buffer, "q") == 0) { - // Restore previous nodelay state before returning nodelay(stdscr, prev_nodelay); - return true; // Quit + return true; } else if (strncmp(cmd_buffer, "load ", 5) == 0) { - // :load char *rest = cmd_buffer + 5; int clip_idx = atoi(rest); - // Find filename after clip index char *filename = rest; while (*filename && *filename != ' ') filename++; if (*filename) { @@ -377,25 +327,26 @@ static bool handle_command_mode(void) { filename++; while (*filename == ' ') filename++; if (*filename) { - // Submit load request via save/load queue - save_load_queue_push(&g_engine->save_load_queue, REQ_LOAD_CLIP, clip_idx, filename); + Action action = { .type = ACTION_LOAD_CLIP, .data.load_clip = { .clip_index = clip_idx } }; + strncpy(action.data.load_clip.filename, filename, 255); + action.data.load_clip.filename[255] = '\0'; + g_dispatch(action); } } } else if (strncmp(cmd_buffer, "save ", 5) == 0) { - // :save int clip_idx = atoi(cmd_buffer + 5); - save_load_queue_push(&g_engine->save_load_queue, REQ_SAVE_CLIP, clip_idx, ""); + Action action = { .type = ACTION_SAVE_CLIP, .data.save_clip = { .clip_index = clip_idx } }; + g_dispatch(action); } - // Restore previous nodelay state before returning nodelay(stdscr, prev_nodelay); - return false; // Don't quit - } else if (ch == 27) { // Escape - cancel command mode + return false; + } else if (ch == 27) { mvprintw(LINES - 1, 0, " "); refresh(); nodelay(stdscr, prev_nodelay); return false; - } else if (ch == KEY_BACKSPACE || ch == 127) { // Backspace + } else if (ch == KEY_BACKSPACE || ch == 127) { if (cmd_pos > 0) { cmd_pos--; cmd_buffer[cmd_pos] = '\0'; @@ -410,76 +361,59 @@ static bool handle_command_mode(void) { } } - // Should never reach here, but restore just in case nodelay(stdscr, prev_nodelay); return false; } // Handle mouse events static void handle_mouse_event(MEVENT *event) { - // Convert mouse position to grid coordinates - int grid_row = (event->y - 1) / CELL_HEIGHT; // -1 for title row - int grid_col = (event->x - 1) / CELL_WIDTH; // -1 for left margin + int grid_row = (event->y - 1) / CELL_HEIGHT; + int grid_col = (event->x - 1) / CELL_WIDTH; - // Bounds check if (grid_row < 0 || grid_row >= GRID_ROWS || grid_col < 0 || grid_col >= GRID_COLS) { return; } if (event->bstate & BUTTON1_CLICKED) { - // Left click: select and trigger clip selected_row = grid_row; selected_col = grid_col; - int clip_idx = grid_to_clip_index(selected_row, selected_col); - engine_trigger_clip(g_engine, clip_idx); + Action action = { .type = ACTION_TRIGGER_CLIP, .data.trigger_clip = { .clip_index = clip_idx } }; + g_dispatch(action); } else if (event->bstate & BUTTON3_CLICKED) { - // Right click: select and reset clip selected_row = grid_row; selected_col = grid_col; - int clip_idx = grid_to_clip_index(selected_row, selected_col); - engine_reset_clip(g_engine, clip_idx); + Action action = { .type = ACTION_RESET_CLIP, .data.reset_clip = { .clip_index = clip_idx } }; + g_dispatch(action); } else if (event->bstate & BUTTON2_CLICKED) { - // Middle click: select and trigger scene selected_row = grid_row; selected_col = grid_col; - - engine_trigger_scene(g_engine, selected_row); + Action action = { .type = ACTION_TRIGGER_SCENE, .data.trigger_scene = { .scene_index = selected_row } }; + g_dispatch(action); } else if (event->bstate & BUTTON1_DOUBLE_CLICKED) { - // Double left click: select and trigger scene selected_row = grid_row; selected_col = grid_col; - - engine_trigger_scene(g_engine, selected_row); + Action action = { .type = ACTION_TRIGGER_SCENE, .data.trigger_scene = { .scene_index = selected_row } }; + g_dispatch(action); } } -static void handle_sigint(int sig) { - (void)sig; - tui_cleanup(); - _Exit(1); -} - void tui_init(Engine *engine) { g_engine = engine; + g_dispatch = engine->dispatch; - // Initialize ncurses initscr(); cbreak(); noecho(); keypad(stdscr, TRUE); - curs_set(0); // Hide cursor + curs_set(0); - // Enable mouse events mousemask(BUTTON1_CLICKED | BUTTON3_CLICKED | BUTTON2_CLICKED | BUTTON1_DOUBLE_CLICKED, NULL); - mouseinterval(10); // 10ms click interval + mouseinterval(10); - // Initialize colors if (has_colors()) { start_color(); - - // Define color pairs init_pair(COLOR_EMPTY, COLOR_WHITE, COLOR_BLACK); init_pair(COLOR_RECORDING, COLOR_RED, COLOR_BLACK); init_pair(COLOR_LOOPING, COLOR_GREEN, COLOR_BLACK); @@ -493,8 +427,8 @@ void tui_run(Engine *engine) { if (!engine) return; g_engine = engine; + g_dispatch = engine->dispatch; - // Initialize marks for (int i = 0; i < MAX_MARKS; i++) { marks[i] = -1; } @@ -507,7 +441,6 @@ void tui_run(Engine *engine) { break; } - // Handle mouse events if (ch == KEY_MOUSE) { MEVENT event; if (getmouse(&event) == OK) { @@ -517,65 +450,42 @@ void tui_run(Engine *engine) { } } - // Handle mode-specific input if (current_mode == MODE_MOVE) { switch (ch) { - case 'h': - case KEY_LEFT: + case 'h': case KEY_LEFT: selected_col = (selected_col - 1 + GRID_COLS) % GRID_COLS; break; - - case 'j': - case KEY_DOWN: + case 'j': case KEY_DOWN: selected_row = (selected_row + 1) % GRID_ROWS; break; - - case 'k': - case KEY_UP: + case 'k': case KEY_UP: selected_row = (selected_row - 1 + GRID_ROWS) % GRID_ROWS; break; - - case 'l': - case KEY_RIGHT: + case 'l': case KEY_RIGHT: selected_col = (selected_col + 1) % GRID_COLS; break; - - case '\n': - case '\r': - case 27: // Escape + case '\n': case '\r': case 27: current_mode = MODE_NORMAL; break; - - default: - break; } - draw_grid(); continue; } if (current_mode == MODE_VISUAL) { switch (ch) { - case 'h': - case KEY_LEFT: + case 'h': case KEY_LEFT: visual_end_col = (visual_end_col - 1 + GRID_COLS) % GRID_COLS; break; - - case 'j': - case KEY_DOWN: + case 'j': case KEY_DOWN: visual_end_row = (visual_end_row + 1) % GRID_ROWS; break; - - case 'k': - case KEY_UP: + case 'k': case KEY_UP: visual_end_row = (visual_end_row - 1 + GRID_ROWS) % GRID_ROWS; break; - - case 'l': - case KEY_RIGHT: + case 'l': case KEY_RIGHT: visual_end_col = (visual_end_col + 1) % GRID_COLS; break; - case 'd': { int count; int *clips = get_selected_clips(&count); @@ -586,7 +496,6 @@ void tui_run(Engine *engine) { current_mode = MODE_NORMAL; break; } - case 'y': { int count; int *clips = get_selected_clips(&count); @@ -597,135 +506,108 @@ void tui_run(Engine *engine) { current_mode = MODE_NORMAL; break; } - - case 27: // Escape + case 27: current_mode = MODE_NORMAL; break; - - default: - break; } - draw_grid(); continue; } // Normal mode switch (ch) { - case 'h': - case KEY_LEFT: + case 'h': case KEY_LEFT: selected_col = (selected_col - 1 + GRID_COLS) % GRID_COLS; break; - - case 'j': - case KEY_DOWN: + case 'j': case KEY_DOWN: selected_row = (selected_row + 1) % GRID_ROWS; break; - - case 'k': - case KEY_UP: + case 'k': case KEY_UP: selected_row = (selected_row - 1 + GRID_ROWS) % GRID_ROWS; break; - - case 'l': - case KEY_RIGHT: + case 'l': case KEY_RIGHT: selected_col = (selected_col + 1) % GRID_COLS; break; - case 't': { int clip_idx = grid_to_clip_index(selected_row, selected_col); - engine_trigger_clip(engine, clip_idx); + Action action = { .type = ACTION_TRIGGER_CLIP, .data.trigger_clip = { .clip_index = clip_idx } }; + g_dispatch(action); break; } - case 'd': { - // Delete (reset) current clip int clip_idx = grid_to_clip_index(selected_row, selected_col); - engine_reset_clip(engine, clip_idx); + Action action = { .type = ACTION_RESET_CLIP, .data.reset_clip = { .clip_index = clip_idx } }; + g_dispatch(action); break; } - case 'y': { - // Yank current clip int clip_idx = grid_to_clip_index(selected_row, selected_col); yank_clips(&clip_idx, 1); break; } - - case 'p': { - // Paste + case 'p': paste_clips(); break; - } - case 's': { - // Trigger scene for current row - engine_trigger_scene(engine, selected_row); + Action action = { .type = ACTION_TRIGGER_SCENE, .data.trigger_scene = { .scene_index = selected_row } }; + g_dispatch(action); break; } - case 'q': { - // Cycle quantize mode + AppState state = dispatcher_get_state(); QuantizeMode modes[] = {QUANTIZE_OFF, QUANTIZE_BEAT, QUANTIZE_BAR}; int num_modes = sizeof(modes) / sizeof(modes[0]); int current = 0; for (int i = 0; i < num_modes; i++) { - if (engine->quantize_mode == modes[i]) { + if (state.quantize_mode == modes[i]) { current = i; break; } } QuantizeMode next = modes[(current + 1) % num_modes]; - engine_set_quantize_mode(engine, next); + Action action = { .type = ACTION_SET_QUANTIZE_MODE, .data.set_quantize_mode = { .mode = next } }; + g_dispatch(action); break; } - case 'T': { - // Toggle threshold between 0 and 1000 - if (engine->quantize_threshold == 0) { - engine_set_quantize_threshold(engine, 1000); - } else { - engine_set_quantize_threshold(engine, 0); - } + AppState state = dispatcher_get_state(); + jack_nframes_t new_threshold = (state.quantize_threshold == 0) ? 1000 : 0; + Action action = { .type = ACTION_SET_QUANTIZE_THRESHOLD, .data.set_quantize_threshold = { .threshold = new_threshold } }; + g_dispatch(action); break; } - - case ' ': { // Space bar - toggle play/pause - engine_transport_toggle_play(engine); + case ' ': { + Action action = { .type = ACTION_TRANSPORT_TOGGLE_PLAY }; + g_dispatch(action); break; } - - case 'S': { // Shift+S - stop transport - engine_transport_stop(engine); + case 'S': { + Action action = { .type = ACTION_TRANSPORT_STOP }; + g_dispatch(action); break; } - - case 'C': { // Shift+C - toggle clock source - ClockSource current = transport_get_clock_source(engine->transport); - ClockSource next = (current == CLOCK_SOURCE_INTERNAL) ? + case 'C': { + AppState state = dispatcher_get_state(); + ClockSource next = (state.clock_source == CLOCK_SOURCE_INTERNAL) ? CLOCK_SOURCE_MIDI : CLOCK_SOURCE_INTERNAL; - engine_set_clock_source(engine, next); + Action action = { .type = ACTION_SET_CLOCK_SOURCE, .data.set_clock_source = { .source = next } }; + g_dispatch(action); break; } - - case 'x': - engine_transport_stop(engine); + case 'x': { + Action action = { .type = ACTION_RESET_TRANSPORT }; + g_dispatch(action); break; - + } case ':': { bool should_quit = handle_command_mode(); - if (should_quit) { - return; - } + if (should_quit) return; break; } - case '?': show_help = !show_help; break; - case 'v': { - // Enter visual mode current_mode = MODE_VISUAL; visual_start_row = selected_row; visual_start_col = selected_col; @@ -733,9 +615,7 @@ void tui_run(Engine *engine) { visual_end_col = selected_col; break; } - case 'V': { - // Select entire line current_mode = MODE_VISUAL; visual_start_row = selected_row; visual_start_col = 0; @@ -743,62 +623,41 @@ void tui_run(Engine *engine) { visual_end_col = GRID_COLS - 1; break; } - case 'm': { - // Enter move mode current_mode = MODE_MOVE; break; } - - case 'N': { - // Play next scene + case 'N': play_next_scene(); break; - } - - case 'P': { - // Play previous scene + case 'P': play_prev_scene(); break; - } - case '\'': { - // Go to mark - wait for next character nodelay(stdscr, FALSE); int mark_ch = getch(); nodelay(stdscr, TRUE); - if (mark_ch != ERR) { - go_to_mark((char)mark_ch); - } + if (mark_ch != ERR) go_to_mark((char)mark_ch); break; } - case 'u': { - // Undo - engine_undo_action(engine); + Action action = { .type = ACTION_UNDO }; + g_dispatch(action); break; } - - case 18: { // Ctrl+R (18 = 0x12) - // Redo - engine_redo_action(engine); + case 18: { // Ctrl+R + Action action = { .type = ACTION_REDO }; + g_dispatch(action); break; } - - case 27: // Escape key - case 'Q': + case 27: case 'Q': return; - default: - // Check for mark setting (m) if (ch == 'm') { - // Wait for next character nodelay(stdscr, FALSE); int mark_ch = getch(); nodelay(stdscr, TRUE); - if (mark_ch != ERR) { - set_mark((char)mark_ch); - } + if (mark_ch != ERR) set_mark((char)mark_ch); } break; } @@ -808,20 +667,13 @@ void tui_run(Engine *engine) { } void tui_cleanup(void) { - // Free yank buffer if (yank_buffer.clip_indices) { free(yank_buffer.clip_indices); yank_buffer.clip_indices = NULL; yank_buffer.count = 0; } - // Disable mouse mousemask(0, NULL); - - // Restore terminal settings curs_set(1); endwin(); - - // Reset signal handler to default - signal(SIGINT, SIG_DFL); } diff --git a/tui.h b/tui.h index 5ec463d..6c2b49d 100644 --- a/tui.h +++ b/tui.h @@ -2,6 +2,7 @@ #define TUI_H #include "engine.h" +#include "dispatcher.h" // Initialize TUI void tui_init(Engine *engine); @@ -12,7 +13,4 @@ void tui_run(Engine *engine); // Cleanup TUI void tui_cleanup(void); -// Handle command mode input (after pressing ':') -void tui_handle_command_mode(Engine *engine); - #endif // TUI_H