Skip to content

Commit

Permalink
Merge pull request #73 from olin/papercuts
Browse files Browse the repository at this point in the history
Papercuts and other small, aggravating injuries
  • Loading branch information
newsch authored May 23, 2019
2 parents a65ab68 + a585df6 commit c10f66c
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 55 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ deploy:
api_key:
secure: A3IZutdvZovr1s7efh66o96sGdY49b4tPg57usx/YyTGgF2LqIUY5M5wfrKRmCuey69v++8WFuODH9djr3y9JI0CI6pem/alFByp9AoL9gdZVeTWcl1k5PCSxux15xMcvd7PSO8UGhVCHq1A6XcBWjyHWDlE1zLAI+tVI6NrWd5clIPe3L+HyREkpK4tXQROD+dQ+htsAdr+6uY5ajcFdfqBM6ORHy4JB78/FO3cTj7Z702EWSwPfuUCSvWt2eEbbIyx8MH1XXczfqKKoSf7fGD60Ykr0hhOJXqbgeXBoHw/nooqxLTepI/nCWpfXU2ThzZV2Qmc86X2rTnja404mKzFxtIL+zJEj243PsCjbIXImiJNVyVP/J3rI0zYcr34pEwWd2cC+2AMf2NK50uh1GpRDtKmb5EmgD6nhnKKoU76mcmAuOJqzwaGLBazEWMjN/7K9Ny1iLb2PYDWPPRjLW06KO+vuZYthJtwH80DZ0JMZR5pbEe1he0kUciBGECLQPoJ+EDMS2eje5m2aOrfMJbd8ItEP4jjXzHd2WWsnbo8QYxU6Mf+yJp5EJzBu/dAmh0wTiI12JgPhKviIYrCmcYV8s+eW107uvj9QBd0J9JXJa5xdSUySdEl5dffIat5k5lJcmUh1X6/dgSfVR5mEiWqajQFXtk0vMMEFWIWhas=
on:
repo: olin/SoftSysCollascii
repo: olin/collascii
tags: true # build on tagged releases only
branch: master
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# COLLASCII

[![Build Status](https://travis-ci.com/olin/SoftSysCollascii.svg?branch=master)](https://travis-ci.com/olin/SoftSysCollascii)
[![Build Status](https://travis-ci.com/olin/collascii.svg?branch=master)](https://travis-ci.com/olin/collascii)

_A collaborative ascii canvas_

Expand Down
6 changes: 4 additions & 2 deletions src/canvas.c
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,7 @@ inline Canvas *canvas_trim(Canvas *orig, int right, int bottom, int left,
* Top left of canvas is (0, 0).
*/
void canvas_scharyx(Canvas *canvas, int y, int x, char c) {
assert(canvas_isin_yx(canvas, y, x));
canvas->rows[y][x] = c;
}

Expand All @@ -369,6 +370,7 @@ void canvas_scharyx(Canvas *canvas, int y, int x, char c) {
* Index starts at 0 at position (0, 0) and increments first horizontally.
*/
void canvas_schari(Canvas *canvas, int i, char c) {
assert(canvas_isin_i(canvas, i));
int row = i / canvas->num_cols;
int col = i % canvas->num_cols;
canvas->rows[row][col] = c;
Expand All @@ -378,15 +380,15 @@ void canvas_schari(Canvas *canvas, int i, char c) {
*
*/
char canvas_gcharyx(Canvas *canvas, int y, int x) {
assert(x <= canvas->num_cols);
assert(y <= canvas->num_rows);
assert(canvas_isin_yx(canvas, y, x));
return canvas->rows[y][x];
}

/* Get the character at index i
*
*/
char canvas_gchari(Canvas *canvas, int i) {
assert(canvas_isin_i(canvas, i));
int row = i / canvas->num_cols;
int col = i % canvas->num_cols;
return canvas->rows[row][col];
Expand Down
51 changes: 29 additions & 22 deletions src/fe_modes.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
#include "mode_id.h"
#include "util.h"

// #define LOG_KEY_EVENTS // `logd` new mouse and key events

editor_mode_t modes[] = {
{"Switcher", "Switch to another mode", mode_picker},
{"Insert", "Insert characters", mode_insert},
Expand Down Expand Up @@ -126,10 +128,23 @@ void switch_mode(Mode_ID new_mode, State *state) {
int master_handler(State *state, WINDOW *canvas_win, WINDOW *status_win) {
// catching keypresses
int c = wgetch(canvas_win); // grab from window
#ifdef LOG_KEYS
#ifdef LOG_KEY_EVENTS
logd("New key: '%c' (%d)\n", c, c);
#endif
if (c == KEY_TAB) { // switching modes
if (c == KEY_MOUSE) {
// handle mouse events
MEVENT event;
if (getmouse(&event) == OK) {
#ifdef LOG_KEY_EVENTS
logd("New mouse event: (%i, %i), %li\n", event.x, event.y, event.bstate);
#endif
// TODO: look into mouse_trafo, wmouse_trafo
// 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) {
logd("Reverting to last mode\n");
Expand Down Expand Up @@ -404,7 +419,18 @@ int mode_brush(reason_t reason, State *state) {
mode_cfg->state = PAINT_OFF;
}

if (reason == NEW_KEY) {
if (reason == NEW_MOUSE) {
if (state->mevent_in->bstate & BUTTON1_PRESSED) {
mode_cfg->state = PAINT_ON;
} else if (state->mevent_in->bstate & BUTTON1_RELEASED) {
mode_cfg->state = PAINT_OFF;
}
// only update cursor position on mouse move if we're painting
if (mode_cfg->state == PAINT_ON) {
state->cursor->x = state->mevent_in->x - 1;
state->cursor->y = state->mevent_in->y - 1;
}
} else if (reason == NEW_KEY) {
if ((state->ch_in == KEY_LEFT) || (state->ch_in == KEY_RIGHT) ||
(state->ch_in == KEY_UP) || (state->ch_in == KEY_DOWN)) {
// arrow keys - move cursor
Expand All @@ -419,25 +445,6 @@ int mode_brush(reason_t reason, State *state) {
} else if (mode_cfg->state == PAINT_OFF) {
mode_cfg->state = PAINT_ON;
}
} else if (KEY_MOUSE == state->ch_in) {
// handle mouse events
MEVENT event;
if (getmouse(&event) == OK) {
#ifdef LOG_KEYS
logd("New mouse event: (%i, %i), %li\n", event.x, event.y,
(long int)event.bstate);
#endif
if (event.bstate & BUTTON1_PRESSED) {
mode_cfg->state = PAINT_ON;
} else if (event.bstate & BUTTON1_RELEASED) {
mode_cfg->state = PAINT_OFF;
}
// only update cursor position on mouse move if we're painting
if (mode_cfg->state == PAINT_ON) {
state->cursor->x = event.x - 1;
state->cursor->y = event.y - 1;
}
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/fe_modes.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

int mode_master(State *state, WINDOW *canvas_win, WINDOW *status_win);

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

// Prototype for mode functions. Note that this is NOT a function pointer type
// (use `mode_function_t*` for that). https://stackoverflow.com/a/5195682
Expand Down
83 changes: 61 additions & 22 deletions src/frontend.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* | (_| (_) | |__| |__ / _ \\__ \ (__ | | | |
* \___\___/|____|____/_/ \_\___/\___|___|___|
*
* Yesterdays future, tomorrow!
* Yesterday's future, tomorrow!
*
* A collaborative ASCII editor, in your terminal.
*
Expand Down Expand Up @@ -52,6 +52,17 @@ bool networked = false;

char *DEFAULT_FILEPATH = "art.txt";

// signals to be caught with finish() function
int caught_signals[] = {SIGINT, SIGTERM, SIGKILL, SIGABRT,
SIGSEGV, SIGQUIT, SIGSTOP};

// #define LOG_TO_FILE // redirect stderr to "out.txt"

// mouse movements options (only use one)
// #define ENABLE_MOUSE_MOVEMENT 1003 // all move updates
#define ENABLE_MOUSE_MOVEMENT 1002 // move updates when buttons are pressed
// #define ENABLE_MOUSE_MOVEMENT 0 // don't send any charcodes

#ifdef DEBUG
#define LOG_TO_FILE
#endif
Expand All @@ -62,6 +73,11 @@ FILE *logfile = NULL;
#endif

int main(int argc, char *argv[]) {
// setup finish() signal handler
for (int i = 0; i < sizeof(caught_signals) / sizeof(int); i++) {
signal(caught_signals[i], finish);
}

#ifdef LOG_TO_FILE
logfile = fopen(logfile_path, "a");
if (logfile == NULL) {
Expand Down Expand Up @@ -131,8 +147,6 @@ int main(int argc, char *argv[]) {

/* initialize your non-curses data structures here */

(void)signal(SIGINT, finish); /* arrange interrupts to terminate */

(void)initscr(); /* initialize the curses library */
keypad(stdscr, TRUE); /* enable keyboard mapping */
(void)nonl(); /* tell curses not to do NL->CR/NL on output */
Expand All @@ -148,16 +162,15 @@ int main(int argc, char *argv[]) {

// ENABLE MOUSE INPUT
// grab only mouse movement and left mouse press/release
#ifndef LOG_KEYS
mousemask(REPORT_MOUSE_POSITION | BUTTON1_PRESSED | BUTTON1_RELEASED, NULL);
#endif
#ifdef LOG_KEYS
mmask_t return_mask = mousemask(
REPORT_MOUSE_POSITION | BUTTON1_PRESSED | BUTTON1_RELEASED, NULL);
logd("Returned mouse mask: %li\n", (long int)return_mask);
mmask_t mmask = BUTTON1_PRESSED | BUTTON1_RELEASED;
#ifdef ENABLE_MOUSE_MOVEMENT
mmask |= REPORT_MOUSE_POSITION;
#endif
mmask_t return_mask = mousemask(mmask, NULL);
logd("Returned mouse mask: %li\n", return_mask);
// get mouse updates faster at the expense of not registering "clicks"
mouseinterval(0);
#ifdef ENABLE_MOUSE_MOVEMENT
// Make the terminal report mouse movement events, in a not-great way.
// Printing the escape code should bump it into `1003` mode, where an update
// is sent whenever the mouse moves between cells. Also of note: `1002` only
Expand All @@ -170,9 +183,13 @@ int main(int argc, char *argv[]) {
// https://stackoverflow.com/q/29020638
// https://stackoverflow.com/q/7462850
//
// Disable mouse events is called in finish(), remove it if you change this.
printf("\033[?1003h\n"); // enable events
// printf("\033[?1003l\n"); // disable events
// disabling mouse event charcodes is done in finish()
if (ENABLE_MOUSE_MOVEMENT == 1002) {
printf("\033[?1002h\n");
} else if (ENABLE_MOUSE_MOVEMENT == 1003) {
printf("\033[?1003h\n");
}
#endif

canvas_win = create_canvas_win();
status_interface = create_status_interface();
Expand Down Expand Up @@ -260,8 +277,7 @@ int main(int argc, char *argv[]) {
}
// Cleanup
cursor_free(cursor);
// TODO: destory status_interface
destroy_win(status_interface->status_win);
destroy_status_interface(status_interface);
destroy_win(canvas_win);
finish(0);
}
Expand Down Expand Up @@ -314,12 +330,12 @@ void redraw_canvas_win() {
// draw fill in rest of window
for (int x = max_x; x < view_max_x; x++) {
for (int y = 0; y < view_max_y; y++) {
mvwaddch(canvas_win, y + 1, x + 1, 'X');
mvwaddch(canvas_win, y + 1, x + 1, ACS_CKBOARD);
}
}
for (int y = max_y; y < view_max_y; y++) {
for (int x = 0; x < view_max_x; x++) {
mvwaddch(canvas_win, y + 1, x + 1, 'X');
for (int x = 0; x < max_x; x++) {
mvwaddch(canvas_win, y + 1, x + 1, ACS_CKBOARD);
}
}
}
Expand Down Expand Up @@ -518,17 +534,40 @@ void update_info_win(Mode_ID current_mode, int x, int y) {
waddnstr(mw, buffer, INFO_WIDTH);
}

/* Signal handler for exiting
*
* Turns of 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.
*/
void finish(int sig) {
endwin();

// Disable mouse events
printf("\033[?1003l\n");
// Disable mouse events charcode
#ifdef ENABLE_MOUSE_MOVEMENT
if (ENABLE_MOUSE_MOVEMENT == 1002) {
printf("\033[?1002l\n");
} else if (ENABLE_MOUSE_MOVEMENT == 1003) {
printf("\033[?1003l\n");
}
#endif

/* do your non-curses wrapup here */
#ifdef LOG_TO_FILE
if (logfile != NULL) {
fclose(logfile);
}
#endif
exit(0);
// decide how to exit based on signal
switch (sig) {
case 0: // normal
case SIGINT: // user CTRL-C
eprintf("Exiting\n");
exit(0);
break;
default: // problems
eprintf("Exited with signal %d (%s)\n", sig, strsignal(sig));
exit(sig);
break;
}
}
12 changes: 6 additions & 6 deletions src/state.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@
* Make sure its length is capped.
*/
typedef struct {
int ch_in;
Cursor *cursor;
Mode_ID current_mode;

Mode_ID last_canvas_mode;
int ch_in; // characters read by ncurses
MEVENT *mevent_in; // mouse events read by ncurses
Cursor *cursor; // cursor location on screen, relative to window
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
int last_arrow_direction;
View *view;
Cursor *last_cursor;
char *filepath; // path of savefile
} State;
Expand Down

0 comments on commit c10f66c

Please sign in to comment.