diff --git a/field.c b/field.c index 09c0537..1aa1ca5 100644 --- a/field.c +++ b/field.c @@ -17,6 +17,8 @@ void field_init_fill(Field* f, Usz height, Usz width, Glyph fill_char) { f->width = (U16)width; } +void field_deinit(Field* f) { free(f->buffer); } + void field_resize_raw(Field* f, Usz height, Usz width) { assert(height <= ORCA_Y_MAX && width <= ORCA_X_MAX); Usz cells = height * width; @@ -31,8 +33,6 @@ void field_resize_raw_if_necessary(Field* field, Usz height, Usz width) { } } -void field_deinit(Field* f) { free(f->buffer); } - void field_copy(Field* src, Field* dest) { field_resize_raw_if_necessary(dest, src->height, src->width); gbuffer_copy_subrect(src->buffer, dest->buffer, src->height, src->width, @@ -40,6 +40,22 @@ void field_copy(Field* src, Field* dest) { src->width); } +void field_resize_filled(Field* field, Usz height, Usz width, Glyph fill_char) { + assert(height <= ORCA_Y_MAX && width <= ORCA_X_MAX); + Usz old_height = field->height; + Usz old_width = field->width; + if (old_height == height && old_width == width) + return; + Usz old_cells = old_height * old_width; + Usz new_cells = height * width; + field->buffer = realloc(field->buffer, new_cells * sizeof(Glyph)); + if (old_cells < new_cells) { + memset(field->buffer + old_cells, fill_char, (new_cells - old_cells) * sizeof(Glyph)); + } + field->height = (U16)height; + field->width = (U16)width; +} + static inline bool glyph_char_is_valid(char c) { return c >= '!' && c <= '~'; } void field_fput(Field* f, FILE* stream) { diff --git a/field.h b/field.h index aa84080..ded6eac 100644 --- a/field.h +++ b/field.h @@ -3,9 +3,10 @@ void field_init(Field* field); void field_init_fill(Field* field, Usz height, Usz width, Glyph fill_char); +void field_deinit(Field* field); void field_resize_raw(Field* field, Usz height, Usz width); void field_resize_raw_if_necessary(Field* field, Usz height, Usz width); -void field_deinit(Field* field); +void field_resize_filled(Field* field, Usz height, Usz width, Glyph fill_char); void field_copy(Field* src, Field* dest); void field_fput(Field* field, FILE* stream); diff --git a/gbuffer.c b/gbuffer.c index 82d50b5..43344c7 100644 --- a/gbuffer.c +++ b/gbuffer.c @@ -26,16 +26,16 @@ void gbuffer_copy_subrect(Glyph* src, Glyph* dest, Usz src_height, Usz copy_bytes = row_copy * sizeof(Glyph); Glyph* src_p = src + src_y * src_width + src_x; Glyph* dest_p = dest + dest_y * dest_width + dest_x; - Usz src_stride; - Usz dest_stride; + Isz src_stride; + Isz dest_stride; if (src_y >= dest_y) { - src_stride = src_width; - dest_stride = dest_width; + src_stride = (Isz)src_width; + dest_stride = (Isz)dest_width; } else { src_p += (ny - 1) * src_width; dest_p += (ny - 1) * dest_width; - src_stride = -src_width; - dest_stride = -dest_width; + src_stride = -(Isz)src_width; + dest_stride = -(Isz)dest_width; } Usz iy = 0; for (;;) { diff --git a/tui_main.c b/tui_main.c index d251446..55a0982 100644 --- a/tui_main.c +++ b/tui_main.c @@ -296,13 +296,21 @@ void draw_field(WINDOW* win, int term_h, int term_w, int pos_y, int pos_x, (void)term_w; if (field_w > Bufcount) return; + if (pos_y >= term_h || pos_x >= term_w) + return; + Usz num_y = (Usz)term_h - (Usz)pos_y; + Usz num_x = (Usz)term_w - (Usz)pos_x; + if (field_h < num_y) + num_y = field_h; + if (field_w < num_x) + num_x = field_w; chtype buffer[Bufcount]; bool use_rulers = ruler_spacing_y != 0 && ruler_spacing_x != 0; - for (Usz y = 0; y < field_h; ++y) { + for (Usz y = 0; y < num_y; ++y) { Glyph const* gline = gbuffer + y * field_w; Mark const* mline = mbuffer + y * field_w; bool use_y_ruler = use_rulers && y % ruler_spacing_y == 0; - for (Usz x = 0; x < field_w; ++x) { + for (Usz x = 0; x < num_x; ++x) { Glyph g = gline[x]; Mark m = mline[x]; if (g == '.') { @@ -312,10 +320,43 @@ void draw_field(WINDOW* win, int term_h, int term_w, int pos_y, int pos_x, buffer[x] = chtype_of_cell(g, m); } wmove(win, pos_y + (int)y, pos_x); - waddchnstr(win, buffer, (int)field_w); + waddchnstr(win, buffer, (int)num_x); + // Trying to clear to eol with 0 chars remaining on line will clear whole + // line from start + if (pos_x + (int)num_x != term_w) { + wmove(win, pos_y + (int)y, pos_x + (int)num_x); + wclrtoeol(win); + } } } +void tui_cursor_confine(Tui_cursor* tc, Usz height, Usz width) { + if (height == 0 || width == 0) + return; + if (tc->y >= height) + tc->y = height - 1; + if (tc->x >= width) + tc->x = width - 1; +} + +void tui_resize_grid(Field* field, Markmap_reusable* markmap, + Field* scratch_field, Isz delta_h, Isz delta_w, + Tui_cursor* tui_cursor, bool* needs_remarking) { + Isz new_height = (Isz)field->height + delta_h; + Isz new_width = (Isz)field->width + delta_w; + if (new_height < 1 || new_width < 1) + return; + field_copy(field, scratch_field); + field_resize_filled(field, (Usz)new_height, (Usz)new_width, '.'); + gbuffer_copy_subrect(scratch_field->buffer, field->buffer, + scratch_field->height, scratch_field->width, + field->height, field->width, 0, 0, 0, 0, + scratch_field->height, scratch_field->width); + tui_cursor_confine(tui_cursor, (Usz)new_height, (Usz)new_width); + markmap_reusable_ensure_size(markmap, (Usz)new_height, (Usz)new_width); + *needs_remarking = true; +} + int main(int argc, char** argv) { static struct option tui_options[] = {{"help", no_argument, 0, 'h'}, {NULL, 0, NULL, 0}}; @@ -527,6 +568,22 @@ int main(int argc, char** argv) { if (ruler_spacing_y < 16) ++ruler_spacing_y; break; + case '(': + tui_resize_grid(&field, &markmap_r, &scratch_field, 0, -1, &tui_cursor, + &needs_remarking); + break; + case ')': + tui_resize_grid(&field, &markmap_r, &scratch_field, 0, 1, &tui_cursor, + &needs_remarking); + break; + case '_': + tui_resize_grid(&field, &markmap_r, &scratch_field, -1, 0, &tui_cursor, + &needs_remarking); + break; + case '+': + tui_resize_grid(&field, &markmap_r, &scratch_field, 1, 0, &tui_cursor, + &needs_remarking); + break; case ' ': undo_history_push(&undo_hist, &field, tick_num); orca_run(field.buffer, markmap_r.buffer, field.height, field.width,