8000 Goto mode by newsch · Pull Request #93 · olin/collascii · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Goto mode #93

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 5 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension < 8000 label class="SelectMenu-item" role="menuitem"> .c  (2)

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
214 changes: 171 additions & 43 deletions src/fe_modes.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

#include "fe_modes.h"

#include <errno.h>
#include <string.h>

#include <ncurses.h>
Expand All @@ -34,11 +35,15 @@
// #define LOG_KEY_EVENTS // `logd` new mouse and key events

editor_mode_t modes[] = {
{"", "", NULL}, // empty (0)
{"Switcher", "Switch to another mode", mode_picker},
{"GOTO", "", mode_goto},
{"", "", NULL}, // USER_MODES
{"Insert", "Insert characters", mode_insert},
{"Pan", "Pan around the canvas", mode_pan},
{"Free-Line", "Draw a line with your arrow keys", mode_free_line},
{"Brush", "Paint with arrow keys and mouse", mode_brush},
{"", "", NULL}, // END
};

typedef struct {
Expand All @@ -57,6 +62,14 @@ typedef struct {

mode_insert_config_t mode_insert_config = {NULL};

typedef struct {
enum { ENTER_FIRST, ENTER_SECOND } state;
char buffer[8];
int xpos, ypos;
} mode_goto_config_t;

mode_goto_config_t mode_goto_config = {ENTER_FIRST, "", 0, 0};

///////////////////////
// GENERAL FUNCTIONS //
///////////////////////
Expand Down Expand Up @@ -97,6 +110,9 @@ void cmd_trim_canvas(State *state) {
int call_mode(Mode_ID mode, reason_t reason, State *state) {
int res = modes[mode].mode_function(reason, state);
update_info_win_state(state);
if (res & RESP_EXIT) {
switch_mode(state->last_canvas_mode, state);
}
return res;
}

Expand All @@ -112,7 +128,7 @@ inline void update_info_win_state(State *state) {
*
* It sends END to the old mode and then START to the new mode
*/
void switch_mode(Mode_ID new_mode, State *state) {
inline void switch_mode(Mode_ID new_mode, State *state) {
logd("Switching to %s\n", modes[new_mode].name);
call_mode(state->current_mode, END, state);
state->last_canvas_mode = state->current_mode;
Expand All @@ -122,6 +138,32 @@ void switch_mode(Mode_ID new_mode, State *state) {
refresh_screen();
}

// switch from normal mode operation to an overridden mode
void enter_override_mode(Mode_ID override_mode, State *state) {
state->override_mode = override_mode;
call_mode(state->override_mode, START, state);
}

// return control from override mode to normal mode
void exit_override_mode(State *state) {
call_mode(state->override_mode, END, state);
state->override_mode = 0;
// TODO: "redraw" old mode
}

// TODO: better name
void handle_mode(reason_t reason, State *state) {
if (state->override_mode != 0) {
int res = call_mode(state->override_mode, reason, state);
if (res & RESP_EXIT) {
logd("Exiting override mode %s\n", modes[state->override_mode].name);
exit_override_mode(state);
}
} else {
call_mode(state->current_mode, reason, state);
}
}

Mode_ID add_mod_canvas_mode(Mode_ID mode, int n) {
int mode_first = MODE_PICKER + 1; // beginning of selectable modes
int mode_list_end = LAST; // length of total mode list
Expand Down Expand Up @@ -162,31 +204,17 @@ int master_handler(State *state, WINDOW *canvas_win, WINDOW *status_win) {
// https://invisible-island.net/ncurses/man/curs_mouse.3x.html
state->ch_in = c;
state->mevent_in = &event;
call_mode(state->current_mode, NEW_MOUSE, state);
}
} else if (c == KEY_TAB) { // switching modes
if (state->current_mode == MODE_PICKER &&
state->last_canvas_mode != MODE_PICKER) {
state->last_canvas_mode = next_canvas_mode(state->last_canvas_mode);

// update mode_picker() to redraw the highlight
state->ch_in = c;
call_mode(state->current_mode, NEW_KEY, state);
} else {
switch_mode(MODE_PICKER, state);
handle_mode(NEW_MOUSE, state);
}
return 0;
} else if (c == KEY_SHIFT_TAB) {
if (state->current_mode == MODE_PICKER &&
state->last_canvas_mode != MODE_PICKER) {
state->last_canvas_mode = previous_canvas_mode(state->last_canvas_mode);

// update mode_picker() to redraw the highlight
state->ch_in = c;
call_mode(state->current_mode, NEW_KEY, state);
} else {
switch_mode(MODE_PICKER, state);
} else if (c == KEY_TAB) { // switch modes
if (state->override_mode != MODE_PICKER) {
enter_override_mode(MODE_PICKER, state);
return 0;
}
} else if (c == KEY_CTRL('g')) { // goto pos
enter_override_mode(MODE_GOTO, state);
return 0;
} else if (c == KEY_NPAGE || c == KEY_PPAGE || c == KEY_SLEFT ||
c == KEY_SRIGHT) {
// shift view down/up/left/right
Expand Down Expand Up @@ -218,19 +246,22 @@ int master_handler(State *state, WINDOW *canvas_win, WINDOW *status_win) {
state->view->x = new_vx;
redraw_canvas_win();
update_info_win_state(state);
return 0;
} else if (c == KEY_CTRL('r')) {
cmd_read_from_file(state);
print_msg_win("Read from file '%s'\n", state->filepath);
return 0;
} else if (c == KEY_CTRL('s')) {
cmd_write_to_file(state);
print_msg_win("Saved to file '%s'\n", state->filepath);
return 0;
} else if (c == KEY_CTRL('t')) {
cmd_trim_canvas(state);
} else {
// pass character on to mode
state->ch_in = c;
call_mode(state->current_mode, NEW_KEY, state);
return 0;
}
// pass character on to mode
state->ch_in = c;
handle_mode(NEW_KEY, state);

// Move UI cursor to the right place
wmove(canvas_win, cursor_y_to_canvas(state->cursor),
Expand Down Expand Up @@ -296,8 +327,36 @@ int mode_picker(reason_t reason, State *state) {
}

// get bounds of switchable modes in enum array (DON'T include mode_picker)
int mode_first = MODE_PICKER + 1; // beginning of selectable modes
int mode_list_end = LAST; // length of total mode list
int mode_first = USER_MODES + 1; // beginning of selectable modes
int mode_list_end = LAST; // length of total mode list

// INTERPRET KEYS
Mode_ID new_mode = 0;
if (reason == NEW_KEY) {
// only accept characters within the bounds of the list
if (state->ch_in >= '1' &&
state->ch_in < '1' + mode_list_end - mode_first) {
new_mode = mode_first + state->ch_in - '1';
} else if (state->ch_in == KEY_ENTER) {
new_mode = state->last_canvas_mode;
} else if (state->ch_in == KEY_TAB) {
state->last_canvas_mode = next_canvas_mode(state->last_canvas_mode);
} else if (state->ch_in == KEY_SHIFT_TAB) {
state->last_canvas_mode = previous_canvas_mode(state->last_canvas_mode);
}
}

// exit early if switching modes
if (new_mode != 0) {
// this is a little funky. We can't just return from override mode, because
// the new mode isn't initialized, but we can't switch without turning off
// override_mode
exit_override_mode(state);
switch_mode(new_mode, state);
return 0;
}

// DRAW INTERFACE

// BUILD MODE INFO MESSAGE
char msg[128] = "";
Expand Down Expand Up @@ -337,20 +396,6 @@ int mode_picker(reason_t reason, State *state) {
if (selected_num_char != -1) {
highlight_mode_text(selected_x, selected_num_char);
}

// INTERPRET KEYS
if (reason == NEW_KEY) {
// only accept characters within the bounds of the list
if (state->ch_in >= '1' &&
state->ch_in < '1' + mode_list_end - mode_first) {
Mode_ID new_mode = mode_first + state->ch_in - '1';
switch_mode(new_mode, state);
return 0;
} else if (state->ch_in == KEY_ENTER) {
switch_mode(state->last_canvas_mode, state);
return 0;
}
}
return 0;
}

Expand Down Expand Up @@ -533,3 +578,86 @@ int mode_brush(reason_t reason, State *state) {

return 0;
}

int update_pos_value(mode_goto_config_t *mode_cfg) {
int *pos;
switch (mode_cfg->state) {
case ENTER_FIRST:
pos = &(mode_cfg->xpos);
break;
case ENTER_SECOND:
pos = &(mode_cfg->ypos);
}
char *buff = mode_cfg->buffer;
// parse buffer value
errno = 0;
int val = (int)strtol(buff, NULL, 10);
if (errno != 0) {
perror("update_pos_value strtol");
print_mode_win("Invalid number");
return 1;
}
// move relative if sign is present
switch (buff[0]) {
case '-':
case '+':
*pos = *pos + val;
break;
default:
*pos = val;
break;
}
return 0;
}

/* mode_goto
*
* Move the cursor to a position entered on the keyboard.
*/
int mode_goto(reason_t reason, State *state) {
mode_goto_config_t *mode_cfg = &mode_goto_config;
char *buff = mode_cfg->buffer;
if (reason == START) {
// reset mode state
mode_cfg->state = ENTER_FIRST;
mode_cfg->xpos = state->view->x + state->cursor->x;
mode_cfg->ypos = state->view->y + state->cursor->y;
memset(buff, 0, 8);
} else if (reason == NEW_KEY) {
switch (state->ch_in) {
case ',':
// parse, switch to second value
update_pos_value(mode_cfg);
memset(buff, 0, 8); // reset buffer
mode_cfg->state = ENTER_SECOND;
break;
case KEY_ENTER:
// parse, set cursor location and return to last mode
update_pos_value(mode_cfg);
memset(buff, 0, 8); // reset buffer
state->cursor->x = mode_cfg->xpos - state->view->x;
state->cursor->y = mode_cfg->ypos - state->view->y;
// TODO: return somehow
return RESP_EXIT;
case KEY_BACKSPACE: {
// remove last char in buffer
int l = strlen(buff);
if (l > 0) {
buff[l] = '\0';
}
}
default: {
// check if valid and add to buffer
// TODO: check for validity
int l = strlen(buff);
if (l < 8 - 1) {
buff[l] = state->ch_in;
}
break;
}
}
}

print_mode_win("Go to pos: (%i, %i)", mode_cfg->xpos, mode_cfg->ypos);
return 0;
}
7 changes: 7 additions & 0 deletions src/fe_modes.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ int mode_master(State *state, WINDOW *canvas_win, WINDOW *status_win);

typedef enum { START, NEW_KEY, NEW_MOUSE, END } reason_t;

// mode responses
#define RESP_OK 0
#define RESP_EXIT 1
#define RESP_REDRAW 2

// Prototype for mode functions. Note that this is NOT a function pointer type
// (use `mode_function_t*` for that). https://stackoverflow.com/a/5195682
typedef int mode_function_t(reason_t, State *);
Expand All @@ -18,6 +23,8 @@ mode_function_t mode_pan;
mode_function_t mode_free_line;
mode_function_t mode_brush;

mode_function_t mode_goto;

typedef struct {
char *name;
char *description;
Expand Down
3 changes: 2 additions & 1 deletion src/frontend.c
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ void init_state(State *state, const arguments_t *const arguments) {

.last_arrow_direction = KEY_RIGHT,
.last_canvas_mode = MODE_INSERT,
.override_mode = 0,
.view = view,
.last_cursor = cursor_newyx(arguments->y, arguments->x),
.filepath = arguments->filename,
Expand Down Expand Up @@ -733,7 +734,7 @@ void update_info_win(const Mode_ID current_mode, const int x, const int y,

/* Signal handler for exiting
*
* Turns of ncurses, disables mouse moves commands, closes the logfile.
* Turns off ncurses, disables mouse moves commands, closes the logfile.
*
* If sig is 0 or SIGINT, exits normally, otherwise prints the signal
* information to stderr and exits with sig.
Expand Down
4 changes: 3 additions & 1 deletion src/mode_id.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
* This enum is used to index into the modes array.
*/
typedef enum {
MODE_PICKER,
MODE_PICKER = 1,
MODE_GOTO,
USER_MODES, // empty start of user modes
MODE_INSERT,
MODE_PAN,
MODE_FREE_LINE,
Expand Down
1 change: 1 addition & 0 deletions src/state.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ typedef struct {
View *view; // view of the canvas (also holds the canvas)
Mode_ID current_mode; // the current mode of the interface
Mode_ID last_canvas_mode; // the last mode of the interface
Mode_ID override_mode; // any special mode that should be used instead
int last_arrow_direction;
Cursor *last_cursor;
char *filepath; // path of savefile
Expand Down
0