From: Christian Heller Date: Mon, 21 Oct 2013 01:57:15 +0000 (+0200) Subject: Overhauled large parts of window system to universalize scroll hints. X-Git-Tag: tce~942 X-Git-Url: https://plomlompom.com/repos/%7B%7Bdb.prefix%7D%7D/todo?a=commitdiff_plain;h=e31f0c764131a28ac50c6f9c35e0a190f4bc95e4;p=plomrogue Overhauled large parts of window system to universalize scroll hints. --- diff --git a/config/windows/toggle_order_and_active b/config/windows/toggle_order_and_active index f188d83..2ae7c2c 100644 --- a/config/windows/toggle_order_and_active +++ b/config/windows/toggle_order_and_active @@ -1,2 +1,2 @@ kmicl -m \ No newline at end of file +m diff --git a/src/control.c b/src/control.c index c590539..504b0f5 100644 --- a/src/control.c +++ b/src/control.c @@ -8,7 +8,7 @@ #include "keybindings.h" /* for get_keycode_to_action(), mod_selected_keyb(), * move_keyb_mod_selection() */ -#include "map.h" /* for map_scroll(), map_center_object() */ +#include "map.h" /* for map_scroll() */ #include "main.h" /* for World struct */ #include "rexit.h" /* for exit_err() */ #include "wincontrol.h" /* for scroll_pad(), toggle_window(), @@ -306,23 +306,24 @@ extern uint8_t meta_control(int key, struct World * world) } else if (key == get_available_keycode_to_action(world, "map_u")) { - map_scroll(world->map, NORTH, win_map->frame.size); - } + map_scroll(win_map, world->map->size, NORTH); + } else if (key == get_available_keycode_to_action(world, "map_d")) { - map_scroll(world->map, SOUTH, win_map->frame.size); + map_scroll(win_map, world->map->size, SOUTH); } else if (key == get_available_keycode_to_action(world, "map_r")) { - map_scroll(world->map, EAST, win_map->frame.size); + map_scroll(win_map, world->map->size, EAST); } else if (key == get_available_keycode_to_action(world, "map_l")) { - map_scroll(world->map, WEST, win_map->frame.size); + map_scroll(win_map, world->map->size, WEST); } else if (key == get_available_keycode_to_action(world, "map_c")) { - map_center_object(world->map, get_player(world), win_map->frame.size); + struct MapObj * player = get_player(world); + win_map->center = player->pos; } else if (key == get_available_keycode_to_action(world, "inv_u")) { diff --git a/src/draw_wins.c b/src/draw_wins.c index 74b6c45..f86971c 100644 --- a/src/draw_wins.c +++ b/src/draw_wins.c @@ -4,35 +4,40 @@ #include /* for free() */ #include /* for uint16_t */ #include /* for strlen() */ -#include /* for mvwaddch() */ -#include "windows.h" /* for structs Win, Frame, for draw_scroll_hint() */ -#include "misc.h" /* for center_offset(), try_malloc() */ +#include /* for attri_t, chtype, mvwaddch(), wresize() */ +#include "windows.h" /* for struct Win */ +#include "misc.h" /* for try_malloc() */ #include "keybindings.h" /* for struct KeyBinding, for get_name_to_keycode() */ #include "map_objects.h" /* for structs MapObj, get_map_object_def(), * get_player() */ #include "map.h" /* for Map struct */ #include "main.h" /* for World struct */ -#include "rexit.h" /* for err_exit() */ #include "command_db.h" /* for get_command_longdesc() */ #include "wincontrol.h" /* for WinConf struct, get_winconf_by_win() */ -/* Write "text" into window "win" as far as possible. Start on row "start_y". - * Break lines at newlines. +/* Widen the ncurses window below "win" to "minx" if it is below that. */ +static void rewiden_if_less_than(struct Win * win, uint16_t minx); + +/* Write "text" into window "win". Start on row "start_y". Break text at + * right window edge. Also break at newlines. */ static void draw_with_linebreaks(struct Win * win, char * text, uint16_t start_y); -/* Write "line" into window "win" at line "y" as far as it fits into it; apply - * ncurses attribute "attri" to all characters drawn; if "fill" is non-zero, - * fill the entire line with empty characters ("attri" also applied on these). +/* Write "line" into window "w" at line "y"; apply ncurses attribute + * "attri" to all characters drawn; if "fill" is non-zero, fill the + * entire line until the right window edge with empty characters + * ("attri" also applied on these). */ -static void draw_line(struct Win * win, uint16_t y, char * line, attr_t attri, +static void draw_line(struct Win * w, uint16_t y, char * line, attr_t attri, uint8_t fill); -/* Write "text" not starting from the top but from the bottom of "win". */ +/* Write "text" with draw_with_linebreaks() as not starting from the top + * but from the bottom of "win". + */ static void draw_text_from_bottom(struct Win * win, char * text); /* Draw onto "map" in "win" the objects in the chain at "start". */ @@ -43,30 +48,26 @@ static void draw_map_objects(struct World * world, struct MapObj * start, static char * get_kb_line_and_iterate(struct World * world, struct KeyBinding ** kb_pp); -/* Draw horizontal scroll hints in "frame" at the end line or a start line of y - * value "start" if the current "y" fits one of these lines and the number of - * lines "n_owned" and the "offset" make it appropriate. - * - * Return 1 if a scroll hint was drawn, else 0. - */ -static uint8_t scroll_hint_helper(struct World * world, uint16_t start, - uint16_t y, uint16_t offset, uint16_t n_owned, - struct Frame * frame, char * f_name); - /* Draw from line "start" on config view for keybindings defined at "kb". */ -static void draw_kb_view(struct World * world, struct Win * win, - char * f_name, struct KeyBiData * kb, uint8_t start); +static void draw_kb_view(struct World * world, struct Win * w, + struct KeyBiData * kb, uint8_t start); -/* Draw into window "win" from line "start" on a "title" followed by an empty +/* Draw into window "w" from line "start" on a "title" followed by an empty * line followed by a list of all keybindings starting at kb_p. */ -static uint16_t draw_titled_keybinding_list(struct World * world, - struct Win * win, uint16_t start, - char * title, +static uint16_t draw_titled_keybinding_list(struct World * world, char * title, + struct Win * w, uint16_t start, struct KeyBinding * kb_p); +static void rewiden_if_less_than(struct Win * win, uint16_t minx) +{ + if (minx > getmaxx(win->frame.curses_win)) + { + wresize(win->frame.curses_win, getmaxy(win->frame.curses_win), minx); + } +} @@ -74,39 +75,30 @@ static void draw_with_linebreaks(struct Win * win, char * text, uint16_t start_y) { uint16_t x, y; - char toggle; - char fin = 0; int16_t z = -1; - for (y = start_y; y < win->frame.size.y; y++) + rewiden_if_less_than(win, win->frame.size.x); + for (y = start_y; ; y++) { - if (0 == fin) - { - toggle = 0; - } + wresize(win->frame.curses_win, y + 1, getmaxx(win->frame.curses_win)); for (x = 0; x < win->frame.size.x; x++) { - if (0 == toggle) + z++; + if ('\n' == text[z]) + { + break; + } + else + { + mvwaddch(win->frame.curses_win, y, x, text[z]); + } + if ('\n' == text[z+1]) { z++; - if ('\n' == text[z]) - { - toggle = 1; - continue; - } - else - { - mvwaddch(win->frame.curses_win, y, x, text[z]); - } - if ('\n' == text[z+1]) - { - z++; - toggle = 1; - } - else if (0 == text[z+1]) - { - toggle = 1; - fin = 1; - } + break; + } + else if (0 == text[z+1]) + { + return; } } } @@ -114,26 +106,28 @@ static void draw_with_linebreaks(struct Win * win, char * text, -static void draw_line(struct Win * win, uint16_t y, char * line, attr_t attri, +static void draw_line(struct Win * w, uint16_t y, char * line, attr_t attri, uint8_t fill) { uint16_t x = 0; - for (; x < win->frame.size.x && x < strlen(line); x++) + for (; x < strlen(line); x++) { - mvwaddch(win->frame.curses_win, y, x, line[x] | attri); + rewiden_if_less_than(w, x + 1); + mvwaddch(w->frame.curses_win, y, x, line[x] | attri); } if (0 != fill) { - for (; x < win->frame.size.x; x++) + for (; x < w->frame.size.x; x++) { - mvwaddch(win->frame.curses_win, y, x, ' ' | attri); + rewiden_if_less_than(w, x + 1); + mvwaddch(w->frame.curses_win, y, x, ' ' | attri); } } } -static void draw_text_from_bottom (struct Win * win, char * text) +static void draw_text_from_bottom(struct Win * win, char * text) { /* Determine number of lines text would have in a window of win's width, * but infinite height. Treat \n and \0 as control chars for incrementing @@ -209,17 +203,12 @@ static void draw_map_objects(struct World * world, struct MapObj * start, { for (o = start; o != 0; o = o->next) { - if ( ( (0 == i && 0 == o->lifepoints) /* Draw in-animate */ - || (1 == i && 0 < o->lifepoints)) /* objects first. */ - && o->pos.y >= map->offset.y - && o->pos.y < map->offset.y + win->frame.size.y - && o->pos.x >= map->offset.x - && o->pos.x < map->offset.x + win->frame.size.x) + if (( (0 == i && 0 == o->lifepoints) /* Draw in-animate */ + || (1 == i && 0 < o->lifepoints))) /* objects first. */ { d = get_map_object_def(world, o->type); c = d->char_on_map; - mvwaddch(win->frame.curses_win, - o->pos.y - map->offset.y, o->pos.x - map->offset.x, c); + mvwaddch(win->frame.curses_win, o->pos.y, o->pos.x, c); } } } @@ -244,54 +233,22 @@ static char * get_kb_line_and_iterate(struct World * world, -static uint8_t scroll_hint_helper(struct World * world, uint16_t start, - uint16_t y, uint16_t offset, uint16_t n_owned, - struct Frame * frame, char * f_name) -{ - uint8_t ret = 0; - char * err_hint = trouble_msg(world, f_name, "draw_scroll_hint()"); - if (start == y && offset > 0) - { - uint8_t test = draw_scroll_hint(frame, y, offset + 1, '^'); - exit_err(test, world, err_hint); - ret = 1; - } - else if ( frame->size.y == y + 1 - && n_owned > frame->size.y + offset - 1 - start) - { - uint8_t pos = n_owned - (offset + frame->size.y) + 2 + start; - uint8_t test = draw_scroll_hint(frame, y, pos, 'v'); - exit_err(test, world, err_hint); - ret = 1; - } - free(err_hint); - return ret; -} - - - -static void draw_kb_view(struct World * world, struct Win * win, - char * f_name, struct KeyBiData * kb, uint8_t start) +static void draw_kb_view(struct World * world, struct Win * w, + struct KeyBiData * kb, uint8_t start) { if (0 == kb->kbs) { - draw_line(win, start, "(none)", 0, 0); + wresize(w->frame.curses_win, start + 1, getmaxx(w->frame.curses_win)); + draw_line(w, start, "(none)", 0, 0); return; } - uint16_t kb_max = get_n_of_keybs(kb->kbs) - 1; - uint16_t offset; - offset = center_offset(kb->select, kb_max, win->frame.size.y - 1 - start); - struct KeyBinding * kb_p = get_keyb_of_n(kb->kbs, offset + (offset > 0)); + struct KeyBinding * kb_p = kb->kbs; uint16_t y; - for (y = start; 0 != kb_p && y < win->frame.size.y; y++) + for (y = start; 0 != kb_p; y++) { - if (scroll_hint_helper(world, start, y, offset, kb_max, &win->frame, - f_name)) - { - continue; - } + wresize(w->frame.curses_win, y + 1, getmaxx(w->frame.curses_win)); attr_t attri = 0; - if (y - start == kb->select - offset) + if (y - start == kb->select) { attri = A_REVERSE; if (1 == kb->edit) @@ -300,27 +257,26 @@ static void draw_kb_view(struct World * world, struct Win * win, } } char * kb_line = get_kb_line_and_iterate(world, &kb_p); - draw_line(win, y, kb_line, attri, 1); - + draw_line(w, y, kb_line, attri, 1); free(kb_line); } } -static uint16_t draw_titled_keybinding_list(struct World * world, - struct Win * win, uint16_t start, - char * title, +static uint16_t draw_titled_keybinding_list(struct World * world, char * title, + struct Win * w, uint16_t start, struct KeyBinding * kb_p) { uint16_t x, y; uint16_t i = 0; uint8_t state = 0; - for (y = start; y < win->frame.size.y && (0 == state || 0 != kb_p); y++) + for (y = start; (0 == state || 0 != kb_p); y++) { + wresize(w->frame.curses_win, y + 1, getmaxx(w->frame.curses_win)); if (0 == state) { - for (x = 0; x < win->frame.size.x; x++) + for (x = 0; ; x++) { if (i == strlen(title)) { @@ -329,18 +285,32 @@ static uint16_t draw_titled_keybinding_list(struct World * world, i = 0; break; } - mvwaddch(win->frame.curses_win, y, x, title[i]); + rewiden_if_less_than(w, x + 1); + mvwaddch(w->frame.curses_win, y, x, title[i]); i++; } continue; } char * kb_line = get_kb_line_and_iterate(world, &kb_p); - draw_line(win, y, kb_line, 0, 0); + if (strlen(kb_line) > getmaxx(w->frame.curses_win)) + { + wresize(w->frame.curses_win, y + 1, strlen(kb_line)); + } + draw_line(w, y, kb_line, 0, 0); free(kb_line); } if (2 == state) { - draw_line(win, y, "(none)", 0, 0); + char * none = "(none)"; + if (strlen(none) > getmaxx(w->frame.curses_win)) + { + wresize(w->frame.curses_win, y + 1, strlen(none)); + } + else + { + wresize(w->frame.curses_win, y + 1, getmaxx(w->frame.curses_win)); + } + draw_line(w, y, none, 0, 0); y++; } return y; @@ -361,19 +331,14 @@ extern void draw_win_map(struct Win * win) struct World * world = (struct World *) win->data; struct Map * map = world->map; char * cells = map->cells; - uint16_t width_map_av = map->size.x - map->offset.x; - uint16_t height_map_av = map->size.y - map->offset.y; + wresize(win->frame.curses_win, map->size.y, map->size.x); uint16_t x, y, z; - for (y = 0; y < win->frame.size.y; y++) + for (y = 0; y < map->size.y; y++) { - z = map->offset.x + (map->offset.y + y) * (map->size.x); - for (x = 0; x < win->frame.size.x; x++) + for (x = 0; x < map->size.x; x++) { - if (y < height_map_av && x < width_map_av) - { - mvwaddch(win->frame.curses_win, y, x, cells[z]); - z++; - } + mvwaddch(win->frame.curses_win, y, x, cells[z]); + z++; } } draw_map_objects(world, world->map_objs, map, win); @@ -406,28 +371,17 @@ extern void draw_win_inventory(struct Win * win) struct MapObj * player = get_player(world); if (NULL == player->owns) { - mvwaddstr(win->frame.curses_win, 0, 0, "(empty)"); + draw_line(win, 0, "(none)", 0, 0); return; } - char * f_name = "draw_win_inventory()"; + win->center.y = world->inventory_select; struct MapObj * owned = player->owns; - uint8_t n_owned; - for (n_owned = 0; NULL != owned->next; owned = owned->next, n_owned++); - uint8_t offset = center_offset(world->inventory_select, n_owned, - win->frame.size.y - 1); - uint8_t i; - for (i = 0, owned = player->owns; i < offset + (offset > 0); - i++, owned = owned->next); uint8_t y; - for (y = 0; NULL != owned && y < win->frame.size.y; y++) + for (y = 0; NULL != owned; y++) { - if (scroll_hint_helper(world, 0, y, offset, n_owned, &win->frame, - f_name)) - { - continue; - } + wresize(win->frame.curses_win, y + 1, getmaxx(win->frame.curses_win)); attr_t attri = 0; - if (y == world->inventory_select - offset) + if (y == world->inventory_select) { attri = A_REVERSE; } @@ -457,8 +411,8 @@ extern void draw_win_available_keybindings(struct Win * win) { kb_p = world->kb_winkeys.kbs; } - uint16_t offset = draw_titled_keybinding_list(world, win, 0, title, kb_p); - draw_titled_keybinding_list(world, win, offset + 1, "Global keybindings:", + uint16_t offset = draw_titled_keybinding_list(world, title, win, 0, kb_p); + draw_titled_keybinding_list(world, "Global keybindings", win, offset + 1, world->kb_global.kbs); } @@ -466,40 +420,39 @@ extern void draw_win_available_keybindings(struct Win * win) extern void draw_win_keybindings_global(struct Win * win) { - char * f_name = "draw_win_keybindings_global()"; struct World * world = (struct World *) win->data; - draw_kb_view(world, win, f_name, &world->kb_global, 0); + win->center.y = world->kb_global.select; + draw_kb_view(world, win, &world->kb_global, 0); } extern void draw_win_keybindings_winconf_geometry(struct Win * win) { - char * f_name = "draw_win_keybindings_winconf_geometry()"; struct World * world = (struct World *) win->data; - draw_kb_view(world, win, f_name, &world->kb_wingeom, 0); + win->center.y = world->kb_wingeom.select; + draw_kb_view(world, win, &world->kb_wingeom, 0); } extern void draw_win_keybindings_winconf_keybindings(struct Win * win) { - char * f_name = "draw_win_keybindings_winconf_keybindings()"; struct World * world = (struct World *) win->data; - draw_kb_view(world, win, f_name, &world->kb_winkeys, 0); + win->center.y = world->kb_winkeys.select; + draw_kb_view(world, win, &world->kb_winkeys, 0); } extern void draw_winconf_keybindings(struct Win * win) { - char * f_name = "draw_winconf_keybindings()"; struct World * world = (struct World *) win->data; struct WinConf * wc = get_winconf_by_win(world, win); char * title = "Window's keybindings:"; - uint8_t title_space = strlen(title) / win->frame.size.x + 2; - mvwaddstr(win->frame.curses_win, 0, 0, title); - draw_kb_view(world, win, f_name, &wc->kb, title_space); + draw_line(win, 0, title, 0, 0); + draw_kb_view(world, win, &wc->kb, 2); + win->center.y = wc->kb.select + 2; } diff --git a/src/main.c b/src/main.c index 90aa9dd..bb2ef43 100644 --- a/src/main.c +++ b/src/main.c @@ -17,7 +17,7 @@ #include "map_objects.h" /* for structs MapObj, init_map_object_defs(), * build_map_objects(), get_player() */ -#include "map.h" /* for struct Map, init_map(), map_center_object() */ +#include "map.h" /* for struct Map, init_map() */ #include "misc.h" /* for update_log(), find_passable_pos(), save_game(), * try_calloc(), check_tempfile(), check_xor_files(), * load_interface_conf(), load_game() @@ -162,7 +162,7 @@ int main(int argc, char *argv[]) /* Focus map on player. */ struct MapObj * player = get_player(&world); struct Win * win_map = get_win_by_id(&world, 'm'); - map_center_object(&map, player, win_map->frame.size); + win_map->center = player->pos; /* Initialize player's inventory selection index to start position. */ world.inventory_select = 0; diff --git a/src/map.c b/src/map.c index 368c0e2..16b2782 100644 --- a/src/map.c +++ b/src/map.c @@ -4,6 +4,7 @@ #include "map_objects.h" /* for Player struct */ #include "yx_uint16.h" /* for yx_uint16 and dir enums */ #include "rrand.h" /* for rrand() */ +#include "windows.h" /* for struct Win */ struct World; @@ -14,8 +15,6 @@ struct Map init_map(struct World * world) struct Map map; map.size.x = 64; map.size.y = 64; - map.offset.x = 0; - map.offset.y = 0; uint32_t size = map.size.x * map.size.y; map.cells = try_malloc(size, world, f_name); uint16_t y, x; @@ -55,31 +54,33 @@ struct Map init_map(struct World * world) -void map_scroll (struct Map * map, enum dir d, struct yx_uint16 win_size) +void map_scroll(struct Win * win, struct yx_uint16 map_size, enum dir d) { - if (NORTH == d && map->offset.y > 0) + uint16_t offset; + if ((NORTH == d || SOUTH == d) && map_size.y > win->frame.size.y) { - map->offset.y--; - } - else if (WEST == d && map->offset.x > 0) - { - map->offset.x--; - } - else if (SOUTH == d && map->offset.y + win_size.y < map->size.y) - { - map->offset.y++; + offset = center_offset(win->center.y, map_size.y, win->frame.size.y); + win->center.y = offset + (win->frame.size.y / 2); + if (NORTH == d && win->center.y > 0) + { + win->center.y--; + } + else if (SOUTH == d && win->center.y < map_size.y - 1) + { + win->center.y++; + } } - else if (EAST == d && map->offset.x + win_size.x < map->size.x) + else if ((WEST == d || EAST == d) && map_size.x > win->frame.size.x) { - map->offset.x++; + offset = center_offset(win->center.x, map_size.x, win->frame.size.x); + win->center.x = offset + (win->frame.size.x / 2); + if (WEST == d && win->center.x > 0) + { + win->center.x--; + } + else if (EAST == d && win->center.x < map_size.x - 1) + { + win->center.x++; + } } } - - - -void map_center_object(struct Map * map, struct MapObj * object, - struct yx_uint16 win_size) -{ - map->offset.y = center_offset(object->pos.y, map->size.y, win_size.y); - map->offset.x = center_offset(object->pos.x, map->size.x, win_size.x); -} diff --git a/src/map.h b/src/map.h index 73825c0..8dfe446 100644 --- a/src/map.h +++ b/src/map.h @@ -10,12 +10,13 @@ #include "yx_uint16.h" /* for yx_uint16 and dir enums */ struct MapObj; +struct Win; + struct Map { struct yx_uint16 size; /* map's height/width in number of cells */ - struct yx_uint16 offset; /* the map scroll offset */ char * cells; /* sequence of bytes encoding map cells */ }; @@ -27,21 +28,14 @@ struct Map * into a cycle of repeatedly selecting a random cell on the map and * transforming it into a land cell if it is horizontally or vertically neighbor * to one; the cycle ends when a land cell is due to be created right at the - * border of the map. The map scroll offset is initialized to 0,0. + * border of the map. */ extern struct Map init_map(); -/* Scroll map into direction "dir" by changing the scroll offset if that does - * not push the map view beyond the size of the map window as described by - * "win_size". - */ -extern void map_scroll(struct Map * map, enum dir d, struct yx_uint16 win_size); -/* Scroll map to center on the "object" by changing the scroll offset following - * (and constrained by) the window size as described by "win_size". - */ -extern void map_center_object(struct Map * map, struct MapObj * object, - struct yx_uint16 win_size); + +/* Try to change the view center of map "win" of "map_size" into dir "d". */ +void map_scroll(struct Win * win, struct yx_uint16 map_size, enum dir d); diff --git a/src/map_object_actions.h b/src/map_object_actions.h index 30bbae3..b144f29 100644 --- a/src/map_object_actions.h +++ b/src/map_object_actions.h @@ -16,9 +16,9 @@ struct MapObj; /* Try to move "actor" one step in direction "d" and handle the consequences: - * either the move succeeds, or another actor is encountered and hit (which leads - * to its lifepoint decreasing by one and potentially its death), or the target - * square is not passable and the move fails. + * either the move succeeds, or another actor is encountered and hit (which + * leads to its lifepoint decreasing by one and potentially its death), or the + * target square is not passable and the move fails. */ extern uint8_t move_actor(struct World * world, struct MapObj * actor, enum dir d); diff --git a/src/wincontrol.c b/src/wincontrol.c index 3d03078..d444623 100644 --- a/src/wincontrol.c +++ b/src/wincontrol.c @@ -504,13 +504,13 @@ extern void save_win_configs(struct World * world) extern uint8_t toggle_window(struct WinMeta * win_meta, struct Win * win) { - if (0 != win->frame.curses_win) + if (0 == win->prev && win_meta->chain_start != win) /* Win outside chain. */ { - return suspend_win(win_meta, win); + return append_win(win_meta, win); } else { - return append_win(win_meta, win); + return suspend_win(win_meta, win); } } @@ -523,15 +523,20 @@ extern void toggle_winconfig(struct World * world, struct Win * win) { win->draw = draw_winconf_geometry; wcp->view = 1; + wcp->center = win->center; + win->center.y = 0; + win->center.x = 0; } else if (1 == wcp->view) { win->draw = draw_winconf_keybindings; wcp->view = 2; + win->center.x = 0; } else { win->draw = get_drawfunc_by_char(wcp->draw); + win->center = wcp->center; wcp->view = 0; } } diff --git a/src/wincontrol.h b/src/wincontrol.h index 416cc91..a422f5f 100644 --- a/src/wincontrol.h +++ b/src/wincontrol.h @@ -11,6 +11,7 @@ #include /* for uint8_t, int16_t */ #include "keybindings.h" /* for KeyBiData struct */ +#include "yx_uint16.h" /* for yx_uint16 struct */ struct Win; struct WinMeta; struct World; @@ -28,9 +29,11 @@ struct WinConf char * title; /* designated title as passed to init_win() */ int16_t height; /* designated height as interpreted by init_win()*/ int16_t width; /* designated width as interpreted by init_win() */ - char draw; /* identifier of designated Win->_draw; to be returned to */ + char draw; /* identifier of designated Win->draw; to be returned to */ /* after toggling window configuration view */ - uint8_t view; /* 0: use ->draw as Win->_draw; 1: use draw_winconf()*/ + struct yx_uint16 center; /* designated center for Win->draw view; to be */ + /* returned to after toggling winconf view */ + uint8_t view; /* 0: use ->draw as Win->_draw; 1, 2: use draw_winconf()_* */ uint8_t height_type; /* both: 0: interpret ->height/->width as size in */ uint8_t width_type; /* positive cells; 1: as negative diff to max width */ struct KeyBiData kb; /* the window's specific keybindings */ @@ -68,9 +71,14 @@ extern void save_win_configs(struct World * world); -/* Toggle "window configuration" view for "win". */ +/* Toggle "window configuration" view for "win". This also sets sensible values + * for win->center for the various configuration views (y=0, x=0 for + * winconf_geometry and x= for winconf_keys). + */ extern void toggle_winconfig(struct World * world, struct Win * win); + + /* Toggle interpretation type for Win's width/height of Win in WinConf. Width * only toggles to 1 if terminal window is at least as wide as WinConf->width. */ diff --git a/src/windows.c b/src/windows.c index df96743..069e08f 100644 --- a/src/windows.c +++ b/src/windows.c @@ -3,12 +3,13 @@ #include "windows.h" #include /* for uint8_t, uint16_t, uint32_t, UINT16_MAX */ #include /* for typedefs WINDOW, chtype, wresize(), getmaxx(), */ - /* getmaxy(), supbad(), delwin(), mvwaddch(), */ - /* mvwaddstr(), newpad(), wnoutrefres(), erase(), */ - /* werase(), pnoutrefresh(), doupdate() */ + /* getmaxy(), delwin(), mvwaddch(), mvwaddstr(), */ + /* newpad(), wnoutrefres(), erase(), werase(), */ + /* pnoutrefresh(), doupdate(), getmaxyx() */ #include /* for malloc(), free() */ #include /* for strlen(), strnlen(), memcpy() */ -#include "yx_uint16.h" /* for yx_uint16 coordinates */ +#include "yx_uint16.h" /* for struct yx_uint16 */ +#include "misc.h" /* for center_offset() */ @@ -27,13 +28,24 @@ static void place_win(struct WinMeta * wmeta, struct Win * w); -/* Destroy window "w"'s ncurses WINDOW (and set w.Frame.curses_win to 0). */ -static void destroy_win(struct Win * w); +/* Draw scroll hint (a line stating that there are "dist" more elements of + * "unit" further into the direction symbolized by the "dir" char) into virtual + * screen pad, onto an appropriate edge of "frame": the left or right edge if + * "dir" is "<" or ">", or the upper or lower edge if it is "^" or "v". "start" + * should be either the start coordinate of "frame" if it describes a window or + * .y=, .x=wm->pad_offset if it describes the virtual screen. winscroll_hint() + * and padscroll_hint() are wrappers to simplify the use of scroll_hint(). + */ +static void scroll_hint(struct WinMeta * wm, struct Frame * frame, char dir, + uint16_t dist, char * unit, struct yx_uint16 start); +static void winscroll_hint(struct WinMeta * wm, struct Win * w, char dir, + uint16_t dist); +static void padscroll_hint(struct WinMeta * wm, char dir, uint16_t dist); /* Draw contents of all windows in window chain from window "w" onwards. */ -static void draw_wins(struct Win * w); +static uint8_t draw_wins(struct WinMeta * wm, struct Win * w); @@ -96,24 +108,12 @@ static uint8_t refit_pad(struct WinMeta * wmeta) static uint8_t update_wins(struct WinMeta * wmeta, struct Win * w) { - if (0 != w->frame.curses_win) - { - destroy_win(w); - } place_win(wmeta, w); uint8_t test_refit = refit_pad(wmeta); if (0 != test_refit) { return test_refit; } - WINDOW * subpad_test = subpad(wmeta->padframe.curses_win, - w->frame.size.y, w->frame.size.x, - w->start.y, w->start.x); - if (NULL == subpad_test) - { - return 1; - } - w->frame.curses_win = subpad_test; if (0 != w->next) { return update_wins(wmeta, w->next); @@ -142,8 +142,7 @@ static void place_win(struct WinMeta * wmeta, struct Win * w) /* Fit window below its predecessor if that one directly thrones over * empty space wide and high enough. */ - uint16_t w_prev_maxy = w->prev->start.y - + getmaxy(w->prev->frame.curses_win); + uint16_t w_prev_maxy = w->prev->start.y + w->prev->frame.size.y; if ( w->frame.size.x <= w->prev->frame.size.x && w->frame.size.y < wmeta->padframe.size.y - w_prev_maxy) { @@ -170,8 +169,7 @@ static void place_win(struct WinMeta * wmeta, struct Win * w) } w_upup = w_upup->prev; } - w_prev_maxy = w_upup->start.y - + getmaxy(w_upup->frame.curses_win); + w_prev_maxy = w_upup->start.y + w_upup->frame.size.y; widthdiff = (w_upup->start.x + w_upup->frame.size.x) - (w_up->start.x + w_up->frame.size.x); if ( w->frame.size.y < wmeta->padframe.size.y - w_prev_maxy @@ -189,21 +187,123 @@ static void place_win(struct WinMeta * wmeta, struct Win * w) -static void destroy_win(struct Win * w) +static void scroll_hint(struct WinMeta * wm, struct Frame * frame, char dir, + uint16_t dist, char * unit, struct yx_uint16 start) +{ + /* Decide on alignment (vertical/horizontal?), thereby hint text space. */ + char * more = "more"; + uint16_t dsc_space = frame->size.x; + if ('<' == dir || '>' == dir) + { + dsc_space = frame->size.y; + } /* vv-- 10 = max strlen for uint16_t */ + char scrolldsc[1 + strlen(more) + 1 + 10 + 1 + strlen(unit) + 1 + 1]; + sprintf(scrolldsc, " %d %s %s ", dist, more, unit); + + /* Decide on offset of the description text inside the scroll hint line. */ + uint16_t dsc_offset = 1; + if (dsc_space > strlen(scrolldsc) + 1) + { + dsc_offset = (dsc_space - strlen(scrolldsc)) / 2; + } + + /* Draw scroll hint line as dir symbols bracketing description text. */ + uint16_t draw_offset = 0; + if ('>' == dir) + { + draw_offset = frame->size.x - 1; + } + else if ('v' == dir) + { + draw_offset = frame->size.y - 1; + } + uint16_t q = 0; + for (; q < dsc_space; q++) + { + chtype symbol = dir | A_REVERSE; + if (q >= dsc_offset && q < strlen(scrolldsc) + dsc_offset) + { + symbol = scrolldsc[q - dsc_offset] | A_REVERSE; + } + if ('<' == dir || '>' == dir) + { + mvwaddch(wm->padframe.curses_win, + start.y + q, start.x + draw_offset, symbol); + } + else + { + mvwaddch(wm->padframe.curses_win, + start.y + draw_offset, start.x + q, symbol); + } + } +} + + +static void padscroll_hint(struct WinMeta * wm, char dir, uint16_t dist) +{ + struct yx_uint16 start; + start.y = 0; + start.x = wm->pad_offset; + scroll_hint(wm, &wm->padframe, dir, dist, "columns", start); +} + + + +static void winscroll_hint(struct WinMeta * wm, struct Win * w, char dir, + uint16_t dist) { - delwin(w->frame.curses_win); - w->frame.curses_win = 0; + char * unit = "lines"; + if ('<' == dir || '>' == dir) + { + unit = "columns"; + } + struct yx_uint16 start = w->start; + scroll_hint(wm, &w->frame, dir, dist, unit, start); } -static void draw_wins(struct Win * w) +static uint8_t draw_wins(struct WinMeta * wm, struct Win * w) { + if (ERR == wresize(w->frame.curses_win, 1, 1)) + { + return 1; + } w->draw(w); + uint16_t y, x, size_y, size_x; + getmaxyx(w->frame.curses_win, size_y, size_x); + uint16_t offset_y = center_offset(w->center.y, size_y, w->frame.size.y); + uint16_t offset_x = center_offset(w->center.x, size_x, w->frame.size.x); + for (y = offset_y; y < w->frame.size.y + offset_y && y < size_y; y++) + { + for (x = offset_x; x < w->frame.size.x + offset_x && x < size_x; x++) + { + chtype ch = mvwinch(w->frame.curses_win, y, x); + mvwaddch(wm->padframe.curses_win, w->start.y + (y - offset_y), + w->start.x + (x - offset_x), ch); + } + } + if (offset_y > 0) + { + winscroll_hint(wm, w, '^', offset_y + 1); + } + if (size_y > offset_y + w->frame.size.y) + { + winscroll_hint(wm, w, 'v', size_y - ((offset_y + w->frame.size.y) - 1)); + } + if (offset_x > 0) + { + winscroll_hint(wm, w, '<', offset_x + 1); + } + if (size_x > offset_x + w->frame.size.x) + { + winscroll_hint(wm, w, '>', size_x - ((offset_x + w->frame.size.x) - 1)); + } if (0 != w->next) { - draw_wins(w->next); + return draw_wins(wm, w->next); } + return 0; } @@ -401,15 +501,21 @@ extern uint8_t init_win(struct WinMeta * wmeta, struct Win ** wp, char * title, } w->prev = 0; w->next = 0; - w->frame.curses_win = 0; + w->frame.curses_win = newpad(1, 1); + if (NULL == w->frame.curses_win) + { + return 1; + } w->title = malloc(strlen(title) + 1); if (NULL == w->title) { return 1; } sprintf(w->title, "%s", title); - w->data = data; + w->data = data; w->draw = func; + w->center.y = 0; + w->center.x = 0; if (0 < width) { w->frame.size.x = width; @@ -442,10 +548,7 @@ extern void free_winmeta(struct WinMeta * wmeta) extern void free_win(struct Win * win) { - if (0 != win->frame.curses_win) - { - delwin(win->frame.curses_win); - } + delwin(win->frame.curses_win); free(win->title); free(win); } @@ -472,8 +575,6 @@ extern uint8_t append_win(struct WinMeta * wmeta, struct Win * w) extern uint8_t suspend_win(struct WinMeta * wmeta, struct Win * w) { - destroy_win(w); - if (wmeta->chain_start != w) { w->prev->next = w->next; @@ -596,107 +697,43 @@ extern uint8_t shift_active_win(struct WinMeta * wmeta, char dir) -extern uint8_t draw_all_wins(struct WinMeta * wmeta) +extern uint8_t draw_all_wins(struct WinMeta * wm) { /* Empty everything before filling it a-new. */ erase(); - wnoutrefresh(wmeta->screen); - werase(wmeta->padframe.curses_win); - if (wmeta->chain_start) + wnoutrefresh(wm->screen); + werase(wm->padframe.curses_win); + if (wm->chain_start) { - /* Draw windows' contents first, then their borders. */ - draw_wins(wmeta->chain_start); - draw_wins_borderlines(wmeta->chain_start, wmeta->active, - wmeta->padframe.curses_win); - draw_wins_bordercorners(wmeta->chain_start,wmeta->padframe.curses_win); + /* Draw windows' borders first, then windows. */ + draw_wins_borderlines(wm->chain_start, wm->active, + wm->padframe.curses_win); + draw_wins_bordercorners(wm->chain_start, wm->padframe.curses_win); + + if (1 == draw_wins(wm, wm->chain_start)) + { + return 1; + } /* Draw virtual screen scroll hints. */ - if (wmeta->pad_offset > 0) + if (wm->pad_offset > 0) { - if (draw_scroll_hint(&wmeta->padframe, - wmeta->pad_offset, wmeta->pad_offset + 1, '<')) - { - return 1; - } + padscroll_hint(wm, '<', wm->pad_offset + 1); } - if (wmeta->pad_offset + wmeta->padframe.size.x - < getmaxx(wmeta->padframe.curses_win) - 1) + uint16_t size_x = getmaxx(wm->padframe.curses_win); + uint16_t right_edge = wm->pad_offset + wm->padframe.size.x; + if (right_edge < size_x - 1) { - if (draw_scroll_hint(&wmeta->padframe, - wmeta->pad_offset + wmeta->padframe.size.x - 1, - getmaxx(wmeta->padframe.curses_win) - - (wmeta->pad_offset + wmeta->padframe.size.x), - '>')) - { - return 1; - } + padscroll_hint(wm, '>', size_x - right_edge); } - /* Write virtual screen segment to be shown on physical screen into */ - /* ncurses screen buffer. */ - pnoutrefresh(wmeta->padframe.curses_win, 0, wmeta->pad_offset, 0, 0, - wmeta->padframe.size.y, wmeta->padframe.size.x-1); + /* Write pad segment to be shown on physical screen to screen buffer. */ + pnoutrefresh(wm->padframe.curses_win, 0, wm->pad_offset, 0, 0, + wm->padframe.size.y, wm->padframe.size.x - 1); } /* Only at the end write accumulated changes to the physical screen. */ doupdate(); return 0; } - - - -extern uint8_t draw_scroll_hint(struct Frame * frame, uint16_t pos, - uint32_t dist, char dir) -{ - /* Decide on alignment (vertical/horizontal?), thereby scroll hint text. */ - char * more = "more"; - char * unit_cols = "columns"; - char * unit_rows = "lines"; - uint16_t dsc_space = frame->size.x; - char * unit = unit_rows; - if ('<' == dir || '>' == dir) - { - dsc_space = frame->size.y; - unit = unit_cols; - } - char * scrolldsc = malloc((4 * sizeof(char)) + strlen(more) + strlen(unit) - + 10); /* 10 = uint32 max strlen */ - if (NULL == scrolldsc) - { - return 1; - } - sprintf(scrolldsc, " %d %s %s ", dist, more, unit); - - /* Decide on offset of the description text inside the scroll hint line. */ - char offset = 1, q; - if (dsc_space > strlen(scrolldsc) + 1) - { - offset = (dsc_space - strlen(scrolldsc)) / 2; - } - - /* Draw scroll hint line as dir symbols bracketing description text. */ - chtype symbol; - for (q = 0; q < dsc_space; q++) - { - if (q >= offset && q < strlen(scrolldsc) + offset) - { - symbol = scrolldsc[q - offset] | A_REVERSE; - } - else - { - symbol = dir | A_REVERSE; - } - if ('<' == dir || '>' == dir) - { - mvwaddch(frame->curses_win, q, pos, symbol); - } - else - { - mvwaddch(frame->curses_win, pos, q, symbol); - } - } - - free(scrolldsc); - return 0; -} diff --git a/src/windows.h b/src/windows.h index 9f1b02b..eed33ff 100644 --- a/src/windows.h +++ b/src/windows.h @@ -61,6 +61,7 @@ struct Win struct Win * prev; /* chain pointers; if 0, they mark the start or end */ struct Win * next; /* of the chain; if both are 0, Win is outside chain */ struct yx_uint16 start; /* upper left corner of "frame" WINDOW */ + struct yx_uint16 center; /* window content center to focus window on */ char * title; /* title to be used in window title bar */ void (* draw) (struct Win *); /* how to draw window content ("data") */ struct Frame frame; @@ -106,6 +107,7 @@ extern uint8_t init_win_meta(WINDOW * screen, struct WinMeta ** wmeta); * values that exceed it or negative values that would reduce the window height * < 1 cell. * + * The Win frame's curses window is initialized to a pad of size 1x1 cells. * Other members of the Win struct are initialized to 0. */ extern uint8_t init_win(struct WinMeta * wmeta, struct Win ** w, char * title, @@ -114,7 +116,7 @@ extern uint8_t init_win(struct WinMeta * wmeta, struct Win ** w, char * title, -/* Free allocated memory for an initialized Win / WinMeta struct. */ +/* Free allocated memory for an initialized Win / WinMeta structs. */ extern void free_winmeta(struct WinMeta * wmeta); extern void free_win(struct Win * win); @@ -165,23 +167,11 @@ extern uint8_t shift_active_win(struct WinMeta * wmeta, char dir); -/* Draw virtual screen including all windows. Also add scroll hints (see comment - * on draw_scroll_hint()) for where the edges of the terminal screen hit - * non-edges of and inside the virtual screen. Then update the terminal screen. +/* Draw virtual screen including all windows. Also add scroll hints for where + * the edges of the terminal screen hit non-edges of and inside the virtual + * screen. Then update the terminal screen. */ -extern uint8_t draw_all_wins(struct WinMeta * wmeta); - - - -/* Draw scroll hint (a line stating that there is more to see on scrolling - * further into a certain direction) into "frame" at position "pos" (describing - * a column or a row dependent on "dir" being *either* "<"/">" *or* something - * else). It will consist of a line of "dir" symbols bracketing a descriptive - * text stating "dist" as the number of rows/columns further available beyond - * the hint. - */ -extern uint8_t draw_scroll_hint(struct Frame * frame, uint16_t pos, - uint32_t dist, char dir); +extern uint8_t draw_all_wins(struct WinMeta * wm);