Skip to content
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

fix writing canvas past bounds #34

Merged
merged 12 commits into from
May 5, 2019
7 changes: 6 additions & 1 deletion src/canvas.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* TODO: assert get/set positions are within canvas sizes?
*/
#include "canvas.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Expand Down Expand Up @@ -81,7 +82,11 @@ void canvas_schari(Canvas *canvas, int i, char c) {
/* Get the character at position (x, y)
*
*/
char canvas_gcharyx(Canvas *canvas, int y, int x) { return canvas->rows[y][x]; }
char canvas_gcharyx(Canvas *canvas, int y, int x) {
assert(x <= canvas->num_cols);
assert(y <= canvas->num_rows);
return canvas->rows[y][x];
}

/* Get the character at index i
*
Expand Down
12 changes: 10 additions & 2 deletions src/cursor.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@ void cursor_move_up(Cursor *cursor, View *view) {
}

void cursor_move_down(Cursor *cursor, View *view) {
if (cursor->y == view_max_y) {
if (cursor->y + 1 >= view->canvas->num_rows - view->y) {
cursor->y = view->canvas->num_rows - view->y - 1;
return;
}
if (cursor->y + 1 >= view_max_y) {
view_move_down(view);
return;
}
Expand All @@ -39,7 +43,11 @@ void cursor_move_left(Cursor *cursor, View *view) {
}

void cursor_move_right(Cursor *cursor, View *view) {
if (cursor->x == view_max_x) {
if (cursor->x >= view->canvas->num_cols - view->x - 1) {
cursor->x = view->canvas->num_cols - view->x - 1;
return;
}
if (cursor->x + 1 >= view_max_x) {
view_move_right(view);
return;
}
Expand Down
88 changes: 84 additions & 4 deletions src/fe_modes.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ int (*mode_functions[])(State *, WINDOW *, WINDOW *) = {
mode_picker,
mode_insert,
mode_pan,
mode_free_line,
};

//////////////////////////////
Expand All @@ -38,6 +39,50 @@ Mode_ID return_to_canvas(int input_ch) { // State?
return LAST;
}

////////////////////////////
// SPECIFC MODE FUNCTIONS //
////////////////////////////

/* free_line_arrows_to_char
*
* Takes the current and previous arrow directions, and returns the
* appropriate character, including diagonals.
*
* NOTE: Assumes that the input character is an arrow key
*
* Reference table:
* ^ v > < (current)
*
* ^ | | / \
* v | | \ /
* > \ / - -
* < / \ - -
* (last)
*/
int free_line_arrows_to_char(int last_arrow, int current_arrow) {
char horizontal = '-';
char vertical = '|';
char diag_up = '/';
char diag_down = '\\';

if ((last_arrow == KEY_UP || current_arrow == KEY_DOWN) &&
(last_arrow == KEY_DOWN || current_arrow == KEY_UP)) {
// arrows are vertically parallel (top left quarter of truth table)
return vertical;
} else if ((last_arrow == KEY_LEFT || current_arrow == KEY_RIGHT) &&
(last_arrow == KEY_RIGHT || current_arrow == KEY_LEFT)) {
// arrows are horizontally parallel (bottom right quarter of truth table)
return horizontal;
} else if ((last_arrow == KEY_UP && current_arrow == KEY_RIGHT) ||
(last_arrow == KEY_DOWN && current_arrow == KEY_LEFT) ||
(last_arrow == KEY_LEFT && current_arrow == KEY_DOWN) ||
(last_arrow == KEY_RIGHT && current_arrow == KEY_UP)) {
return diag_up;
} else {
return diag_down;
}
}

////////////////////
// MODE FUNCTIONS //
////////////////////
Expand Down Expand Up @@ -114,7 +159,6 @@ int mode_pan(State *state, WINDOW *canvas_win, WINDOW *status_win) {
state->current_mode = MODE_PICKER;
return 0;
}

if ((state->ch_in == KEY_LEFT) || (state->ch_in == KEY_RIGHT) ||
(state->ch_in == KEY_UP) || (state->ch_in == KEY_DOWN)) {
view_pan_ch(state->ch_in, state->view);
Expand All @@ -123,6 +167,42 @@ int mode_pan(State *state, WINDOW *canvas_win, WINDOW *status_win) {
return 0;
}

////////////////////////////
// SPECIFC MODE FUNCTIONS //
////////////////////////////
/* mode_free_line
*
* Move with arrows and insert character with keyboard.
*/
int mode_free_line(State *state, WINDOW *canvas_win, WINDOW *status_win) {
// handle mode changing
if (state->ch_in == KEY_TAB) {
// Clean up code
state->last_canvas_mode = MODE_INSERT;

state->current_mode = MODE_PICKER;
return 0;
}

// free line behavior
if ((state->ch_in == KEY_LEFT) || (state->ch_in == KEY_RIGHT) ||
(state->ch_in == KEY_UP) || (state->ch_in == KEY_DOWN)) {
int current_arrow = state->ch_in;
int last_arrow = state->last_arrow_direction;

front_setcharcursor(free_line_arrows_to_char(last_arrow, current_arrow));

state->last_cursor->x = state->cursor->x;
state->last_cursor->y = state->cursor->y;

cursor_key_to_move(current_arrow, state->cursor, state->view);

state->last_arrow_direction = state->ch_in;
} else if (state->ch_in == KEY_BACKSPACE) {
cursor_key_to_move(cursor_opposite_dir(state->last_arrow_direction),
state->cursor, state->view);
front_setcharcursor(' ');
}

wmove(canvas_win, cursor_y_to_canvas(state->cursor),
cursor_x_to_canvas(state->cursor));

return 0;
}
1 change: 1 addition & 0 deletions src/fe_modes.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
int mode_picker(State *state, WINDOW *canvas_win, WINDOW *status_win);
int mode_insert(State *state, WINDOW *canvas_win, WINDOW *status_win);
int mode_pan(State *state, WINDOW *canvas_win, WINDOW *status_win);
int mode_free_line(State *state, WINDOW *canvas_win, WINDOW *status_win);

extern int (*mode_functions[])(State *, WINDOW *, WINDOW *);

Expand Down
77 changes: 67 additions & 10 deletions src/frontend.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,24 @@
#include "frontend.h"
#include "mode_id.h"
#include "state.h"
#include "util.h"

#include <stdio.h>
#include <unistd.h>

WINDOW *canvas_win, *status_win;
Cursor *cursor;
View *view;

#ifdef DEBUG
#define LOG_TO_FILE
#endif

#ifdef LOG_TO_FILE
char *logfile_path = "out.txt";
FILE *logfile = NULL;
#endif

/* Layout
* ___________________________________________
* | 0 -- X, COLS | canvas window
Expand All @@ -30,6 +43,19 @@ View *view;
*/

int main(int argc, char *argv[]) {
#ifdef LOG_TO_FILE
logfile = fopen(logfile_path, "a");
if (logfile == NULL) {
perror("logfile fopen:");
exit(1);
}
if (-1 == dup2(fileno(logfile), fileno(stderr))) {
perror("stderr dup2:");
exit(1);
}
#endif
logd("Starting frontend\n");

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

(void)signal(SIGINT, finish); /* arrange interrupts to terminate */
Expand All @@ -41,7 +67,7 @@ int main(int argc, char *argv[]) {
(void)noecho(); /* don't print on getch() */
curs_set(2);

define_key("\r", KEY_ENTER); // Bind the <Enter> key properly
define_key("\r", KEY_ENTER); // Bind the <Enter> key properly

if (has_colors()) {
setup_colors();
Expand All @@ -51,6 +77,7 @@ int main(int argc, char *argv[]) {
status_win = create_status_win();

cursor = cursor_new();
Cursor *last_cursor = cursor_new();
Canvas *canvas = canvas_new_blank(1000, 1000);

view = view_new_startpos(canvas, 300, 300);
Expand All @@ -59,22 +86,28 @@ int main(int argc, char *argv[]) {
keypad(canvas_win, TRUE);
keypad(status_win, TRUE);

// update the screen size first. This clears the status window on any changes
// (including the first time it's run), so refreshing after updating the
// status will clear it otherwise
update_screen_size();

char test_msg[] = "Test mode";
print_status(test_msg, status_win);

// Move cursor to starting location and redraw
wmove(canvas_win, cursor_y_to_canvas(cursor), cursor_x_to_canvas(cursor));
wrefresh(status_win);
wrefresh(canvas_win); // Refresh Canvas last so it gets the cursor
// Move cursor to starting location and redraw canvases
refresh_screen();

//// Main loop
State new_state = {
.ch_in = 0,
.cursor = cursor,
.current_mode = MODE_INSERT,
// .current_mode = MODE_FREE_LINE,

.last_arrow_direction = KEY_RIGHT,
.last_canvas_mode = MODE_INSERT,
.view = view,
.last_cursor = last_cursor,
};
State *state = &new_state;

Expand All @@ -83,8 +116,6 @@ int main(int argc, char *argv[]) {

mode_functions[state->current_mode](state, canvas_win, status_win);

update_screen_size(canvas_win, status_win, cursor);

refresh_screen();
}

Expand Down Expand Up @@ -115,12 +146,34 @@ void front_setcharcursor(char ch) {
}

void redraw_canvas_win() {
for (int x = 0; x < view_max_x; x++) {
for (int y = 0; y < view_max_y; y++) {
// find max ranges to draw canvas
int max_x = view_max_x;
newsch marked this conversation as resolved.
Show resolved Hide resolved
int max_y = view_max_y;

if (max_x >= view->canvas->num_cols - view->x)
(max_x = view->canvas->num_cols - view->x);
if (max_y >= view->canvas->num_rows - view->y)
(max_y = view->canvas->num_rows - view->y);

// draw canvas onto window
for (int x = 0; x < max_x; x++) {
for (int y = 0; y < max_y; y++) {
mvwaddch(canvas_win, y + 1, x + 1,
canvas_gcharyx(view->canvas, y + view->y, x + view->x));
}
}

// 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++) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be:

Suggested change
for (int y = 0; y < view_max_y; y++) {
for (int y = max_y; y < view_max_y; y++) {

mvwaddch(canvas_win, y + 1, x + 1, 'X');
}
}
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');
}
}
}

void refresh_screen() {
Expand Down Expand Up @@ -218,6 +271,10 @@ void finish(int sig) {
endwin();

/* do your non-curses wrapup here */

#ifdef LOG_TO_FILE
if (logfile != NULL) {
fclose(logfile);
}
#endif
exit(0);
}
1 change: 1 addition & 0 deletions src/frontend.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#define KEY_TAB '\t'
#define KEY_SHIFT_TAB KEY_BTAB
// TODO: Understand delete/backspace on mac

void finish(int sig);
void setup_colors();
Expand Down
1 change: 1 addition & 0 deletions src/mode_id.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ typedef enum {
MODE_PICKER,
MODE_INSERT,
MODE_PAN,
MODE_FREE_LINE,

// ^ add your mode above
LAST, // used to get number of elements
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 {
Mode_ID last_canvas_mode;
int last_arrow_direction;
View *view;
Cursor *last_cursor;
} State;

#endif
17 changes: 17 additions & 0 deletions src/util.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#ifndef util_h
#define util_h

#include <stdio.h>

// printf to stderr
#define eprintf(...) fprintf(stderr, __VA_ARGS__)

#ifdef DEBUG
// log to stderr if DEBUG is defined
#define logd(...) eprintf(__VA_ARGS__)
#else
// do nothing
#define logd(...)
#endif

#endif
4 changes: 2 additions & 2 deletions src/view.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ void view_move_up(View *view) {
}

void view_move_down(View *view) {
if (view->y - view_max_y == view->canvas->num_rows) {
if (view->y + view_max_y > view->canvas->num_rows) {
return;
}
view->y++;
Expand All @@ -37,7 +37,7 @@ void view_move_left(View *view) {
}

void view_move_right(View *view) {
if (view->x + view_max_x == view->canvas->num_cols) {
if (view->x + view_max_x > view->canvas->num_cols) {
return;
}
view->x++;
Expand Down
4 changes: 2 additions & 2 deletions src/view.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
#include "canvas.h"

#define STATUS_HEIGHT 2 // not including borders
#define view_max_x (COLS - 3)
#define view_max_y (LINES - 4 - STATUS_HEIGHT)
#define view_max_x (COLS - 2)
#define view_max_y (LINES - 3 - STATUS_HEIGHT)

typedef struct {
int x, y;
Expand Down