From: Christian Heller Date: Sat, 25 Jan 2014 06:13:21 +0000 (+0100) Subject: Merged Win and WinConf structs, windows.h and wincontrol.h. Also lots of refactoring... X-Git-Tag: tce~867 X-Git-Url: https://plomlompom.com/repos/%7B%7B%20web_path%20%7D%7D/decks/%7B%7Bprefix%7D%7D/add_structured?a=commitdiff_plain;h=024b404c0db59dc6651b1c8f3d379c2797654fdf;p=plomrogue Merged Win and WinConf structs, windows.h and wincontrol.h. Also lots of refactoring on the way. --- diff --git a/src/client/control.c b/src/client/control.c index 6059096..538f52c 100644 --- a/src/client/control.c +++ b/src/client/control.c @@ -12,11 +12,10 @@ #include "misc.h" /* reload_interface_conf(), save_interface_conf(), * nav_inventory() */ -#include "wincontrol.h" /* struct WinConf, toggle_window(), toggle_winconfig(), - * scroll_pad(), get_winconf_by_win(), - * growshrink_active_window(), toggle_win_size_type() - */ -#include "windows.h" /* for cycle_active_win(), shift_active_win() */ +#include "windows.h" /* get_win_byid(), shift_active_win(), resize_active_win(), + * toggle_win_size_type(), toggle_window(), + * cycle_active_win(), scroll_v_screen() + */ #include "world.h" /* for global world */ @@ -90,8 +89,8 @@ static uint8_t try_client_commands(struct Command * command) || try_1args(command, "inv_d", nav_inventory, 'd') || try_1args(command, "cyc_win_f", cycle_active_win, 'f') || try_1args(command, "cyc_win_b", cycle_active_win, 'b') - || try_1args(command, "scrl_r", scroll_pad, '+') - || try_1args(command, "scrl_l", scroll_pad, '-') + || try_1args(command, "scrl_r", scroll_v_screen, '+') + || try_1args(command, "scrl_l", scroll_v_screen, '-') || try_1args(command, "to_a_keywin", toggle_window, 'k') || try_1args(command, "to_g_keywin", toggle_window, '0') || try_1args(command, "to_wg_keywin", toggle_window, '1') @@ -101,10 +100,10 @@ static uint8_t try_client_commands(struct Command * command) || try_1args(command, "to_inv", toggle_window, 'c') || try_1args(command, "to_logwin", toggle_window, 'l') || try_0args(command, "winconf", toggle_winconfig) - || try_1args(command, "grow_h", growshrink_active_window, '*') - || try_1args(command, "shri_h", growshrink_active_window, '_') - || try_1args(command, "grow_v", growshrink_active_window, '+') - || try_1args(command, "shri_v", growshrink_active_window, '-') + || try_1args(command, "grow_h", resize_active_win, '*') + || try_1args(command, "shri_h", resize_active_win, '_') + || try_1args(command, "grow_v", resize_active_win, '+') + || try_1args(command, "shri_v", resize_active_win, '-') || try_1args(command, "to_height_t", toggle_win_size_type, 'y') || try_1args(command, "to_width_t", toggle_win_size_type, 'x') || try_1args(command, "shift_f", shift_active_win, 'f') @@ -151,18 +150,18 @@ static uint8_t try_server_commands(struct Command * command) extern uint8_t try_key(uint16_t key) { struct Command * command = get_command_to_keycode(world.kb_global.kbs, key); - if (!command && world.wins.win_active) + if (!command && world.windb.active) { - struct WinConf * wc = get_winconf_by_win(world.wins.win_active); - if (0 == wc->view) + struct Win * w = get_win_by_id(world.windb.active); + if (0 == w->view) { - command = get_command_to_keycode(wc->kb.kbs, key); + command = get_command_to_keycode(w->kb.kbs, key); } - else if (1 == wc->view) + else if (1 == w->view) { command = get_command_to_keycode(world.kb_wingeom.kbs, key); } - else if (2 == wc->view) + else if (2 == w->view) { command = get_command_to_keycode(world.kb_winkeys.kbs, key); } diff --git a/src/client/draw_wins.c b/src/client/draw_wins.c index 8e792ca..9fd78fc 100644 --- a/src/client/draw_wins.c +++ b/src/client/draw_wins.c @@ -9,8 +9,7 @@ #include /* strlen(), strtok() */ #include "../common/try_malloc.h" /* try_malloc() */ #include "keybindings.h" /* struct KeyBinding, get_keyname_to_keycode() */ -#include "wincontrol.h" /* struct WinConf, get_winconf_by_win() */ -#include "windows.h" /* struct Win */ +#include "windows.h" /* struct Win, get_win_by_id() */ #include "world.h" /* global world */ @@ -58,17 +57,17 @@ static uint16_t draw_titled_keybinding_list(char * title, struct Win * w, static void try_resize_winmap(struct Win * w, int new_size_y, int new_size_x) { char * f_name = "try_resize_winmap()"; - if (w->winmapsize.y >= new_size_y && w->winmapsize.x >= new_size_x) + if (w->winmap_size.y >= new_size_y && w->winmap_size.x >= new_size_x) { return; } - if (w->winmapsize.y > new_size_y) + if (w->winmap_size.y > new_size_y) { - new_size_y = w->winmapsize.y; + new_size_y = w->winmap_size.y; } - else if (w->winmapsize.x > new_size_x) + else if (w->winmap_size.x > new_size_x) { - new_size_x = w->winmapsize.x; + new_size_x = w->winmap_size.x; } chtype * old_winmap = w->winmap; uint32_t new_size = sizeof(chtype) * new_size_y * new_size_x; @@ -76,9 +75,9 @@ static void try_resize_winmap(struct Win * w, int new_size_y, int new_size_x) uint16_t y, x; for (y = 0; y < new_size_y; y++) { - for (x = 0; y < w->winmapsize.y && x < w->winmapsize.x; x++) + for (x = 0; y < w->winmap_size.y && x < w->winmap_size.x; x++) { - chtype ch = old_winmap[(y * w->winmapsize.x) + x]; + chtype ch = old_winmap[(y * w->winmap_size.x) + x]; w->winmap[(y * new_size_x) + x] = ch; } for (; x < new_size_x; x++) @@ -87,15 +86,15 @@ static void try_resize_winmap(struct Win * w, int new_size_y, int new_size_x) } } free(old_winmap); - w->winmapsize.y = new_size_y; - w->winmapsize.x = new_size_x; + w->winmap_size.y = new_size_y; + w->winmap_size.x = new_size_x; } static void set_ch_on_yx(struct Win * w, int y, int x, chtype ch) { - w->winmap[(y * w->winmapsize.x) + x] = ch; + w->winmap[(y * w->winmap_size.x) + x] = ch; } @@ -104,10 +103,10 @@ static void add_text_with_linebreaks(struct Win * win, char * text) { uint16_t x, y; int16_t z = -1; - for (y = win->winmapsize.y; ; y++) + for (y = win->winmap_size.y; ; y++) { - try_resize_winmap(win, y + 1, win->framesize.x); - for (x = 0; x < win->framesize.x; x++) + try_resize_winmap(win, y + 1, win->frame_size.x); + for (x = 0; x < win->frame_size.x; x++) { z++; if ('\n' == text[z]) @@ -139,12 +138,12 @@ static void add_text_with_linebreaks(struct Win * win, char * text) static void add_line(struct Win * w, char * line, attr_t attri) { - uint16_t y = w->winmapsize.y; + uint16_t y = w->winmap_size.y; uint16_t len_line = strlen(line); if (attri - && w->winmapsize.x < w->framesize.x && w->framesize.x > len_line) + && w->winmap_size.x < w->frame_size.x && w->frame_size.x > len_line) { - try_resize_winmap(w, y + 1, w->framesize.x); + try_resize_winmap(w, y + 1, w->frame_size.x); } else { @@ -157,7 +156,7 @@ static void add_line(struct Win * w, char * line, attr_t attri) } if (attri) { - for (; x < w->framesize.x; x++) + for (; x < w->frame_size.x; x++) { set_ch_on_yx(w, y, x, ' ' | attri); } @@ -177,7 +176,7 @@ static void draw_text_from_bottom(struct Win * win, char * text) int16_t z = -1; for (y = 0; 0 == toggle; y++) { - for (x = 0; x < win->framesize.x; x++) + for (x = 0; x < win->frame_size.x; x++) { z++; if ('\n' == text[z]) @@ -200,16 +199,16 @@ static void draw_text_from_bottom(struct Win * win, char * text) /* Depending on what's bigger, determine start point in window or text. */ uint16_t start_y = 0; - if (y < win->framesize.y) + if (y < win->frame_size.y) { - start_y = win->framesize.y - y; + start_y = win->frame_size.y - y; } - else if (y > win->framesize.y) + else if (y > win->frame_size.y) { - uint16_t offset = y - win->framesize.y; + uint16_t offset = y - win->frame_size.y; for (y = 0; y < offset; y++) { - for (x = 0; x < win->framesize.x; x++) + for (x = 0; x < win->frame_size.x; x++) { z++; if ('\n' == text[z]) @@ -385,16 +384,16 @@ extern void draw_win_available_keybindings(struct Win * win) { char * title = "Active window's keybindings:"; struct KeyBinding * kb_p; - struct WinConf * wc = get_winconf_by_win(world.wins.win_active); - if (0 == wc->view) + struct Win * w = get_win_by_id(world.windb.active); + if (0 == w->view) { - kb_p = wc->kb.kbs; + kb_p = w->kb.kbs; } - else if (1 == wc->view) + else if (1 == w->view) { kb_p = world.kb_wingeom.kbs; } - else if (2 == wc->view) + else if (2 == w->view) { kb_p = world.kb_winkeys.kbs; } @@ -432,19 +431,17 @@ extern void draw_win_keybindings_winconf_keybindings(struct Win * win) extern void draw_winconf_keybindings(struct Win * win) { - struct WinConf * wc = get_winconf_by_win(win); char * title = "Window's keybindings:"; add_line(win, title, 0); add_line(win, " ", 0); - draw_keybinding_config(win, &wc->kb, 2); - win->center.y = wc->kb.select + 2; + draw_keybinding_config(win, &win->kb, 2); + win->center.y = win->kb.select + 2; } extern void draw_winconf_geometry(struct Win * win) { - struct WinConf * wcp = get_winconf_by_win(win); char * title = "Window's geometry:\n"; char * h_d = "\nHeight to save: "; char * h_pos = " (width in cells)"; @@ -454,11 +451,11 @@ extern void draw_winconf_geometry(struct Win * win) char * w_neg = " (negative diff: cells to screen height)"; char * h_t = h_pos; char * w_t = w_pos; - if (1 == wcp->height_type) + if (1 == win->target_height_type) { h_t = h_neg; } - if (1 == wcp->width_type) + if (1 == win->target_width_type) { w_t = w_neg; } @@ -466,7 +463,7 @@ extern void draw_winconf_geometry(struct Win * win) + strlen(h_t) + strlen(h_d) + 6 /* 6 = n of chars to */ + strlen(w_t) + strlen(w_d) + 6 + 1; /* write max int16_t */ char text[maxl + 1]; - sprintf(text, "%s%s%d%s%s%d%s", title, h_d, wcp->height, h_t, - w_d, wcp->width, w_t); + sprintf(text, "%s%s%d%s%s%d%s", title, h_d, win->target_height, h_t, + w_d, win->target_width, w_t); add_text_with_linebreaks(win, text); } diff --git a/src/client/io.c b/src/client/io.c index 998691c..095577d 100644 --- a/src/client/io.c +++ b/src/client/io.c @@ -17,9 +17,9 @@ * try_fgetc() */ #include "control.h" /* try_key() */ -#include "map_window.h" /* for map_center() */ +#include "map_window.h" /* map_center() */ #include "misc.h" /* reset_windows() */ -#include "windows.h" /* draw_all_wins() */ +#include "windows.h" /* reset_windows_on_winch(), draw_all_wins() */ #include "world.h" /* world global */ @@ -260,7 +260,7 @@ extern char * io_loop() { if (world.winch) { - reset_windows(); + reset_windows_on_winch(); world.winch = 0; change_in_client++; } diff --git a/src/client/keybindings.c b/src/client/keybindings.c index 7207641..fd62dda 100644 --- a/src/client/keybindings.c +++ b/src/client/keybindings.c @@ -9,7 +9,6 @@ #include /* strlen(), strchr(), strcmp() */ #include "../common/readwrite.h" /* textfile_sizes(), try_fgets(),try_fwrite()*/ #include "../common/try_malloc.h" /* try_malloc() */ -#include "wincontrol.h" /* get_winconf_by_win() */ #include "windows.h" /* draw_all_wins() */ #include "world.h" /* global world */ @@ -82,8 +81,8 @@ static struct KeyBindingDB * char_selected_kb_db(char c) } else if ('w' == c) { - struct WinConf * wc = get_winconf_by_win(world.wins.win_active); - kbd = &wc->kb; + struct Win * w = get_win_by_id(world.windb.active); + kbd = &w->kb; } return kbd; } diff --git a/src/client/main.c b/src/client/main.c index 61c53b8..3e3bbdd 100644 --- a/src/client/main.c +++ b/src/client/main.c @@ -9,6 +9,7 @@ #include "command_db.h" /* init_command_db() */ #include "io.h" /* io_loop(), try_send() */ #include "misc.h" /* load_interface_conf(), winch_called() */ +#include "windows.h" /* struct Win, winch_called() */ #include "world.h" /* struct World */ @@ -32,11 +33,11 @@ int main(int argc, char * argv[]) set_cleanup_func(cleanup); /* Initialize the whole interface. */ - world.wins.screen = initscr(); + world.windb.t_screen = initscr(); set_cleanup_flag(CLEANUP_NCURSES); noecho(); curs_set(0); - keypad(world.wins.screen, TRUE); + keypad(world.windb.t_screen, TRUE); init_command_db(); /* The command DB needs to be initialized before */ load_interface_conf(); /* the interface, whose keybindings depend on it. */ diff --git a/src/client/map_window.c b/src/client/map_window.c index aace59c..e9f7ced 100644 --- a/src/client/map_window.c +++ b/src/client/map_window.c @@ -3,8 +3,7 @@ #include "map_window.h" #include /* uint16_t */ #include "misc.h" /* center_offset() */ -#include "wincontrol.h" /* get_win_by_id() */ -#include "windows.h" /* struct Win */ +#include "windows.h" /* struct Win, get_win_by_id() */ #include "world.h" /* for global world */ @@ -13,11 +12,11 @@ extern void map_scroll(char d) { struct Win * win = get_win_by_id('m'); uint16_t offset; - if (('N' == d || 'S' == d) && world.map.size.y > win->framesize.y) + if (('N' == d || 'S' == d) && world.map.size.y > win->frame_size.y) { offset = center_offset(win->center.y, - world.map.size.y, win->framesize.y); - win->center.y = offset + (win->framesize.y / 2); + world.map.size.y, win->frame_size.y); + win->center.y = offset + (win->frame_size.y / 2); if ('S' == d && win->center.y < world.map.size.y - 1) { win->center.y++; @@ -25,11 +24,11 @@ extern void map_scroll(char d) } win->center.y = win->center.y - ('N' == d && win->center.y > 0); } - else if (('W' == d || 'E' == d) && world.map.size.x > win->framesize.x) + else if (('W' == d || 'E' == d) && world.map.size.x > win->frame_size.x) { offset = center_offset(win->center.x, - world.map.size.x, win->framesize.x); - win->center.x = offset + (win->framesize.x / 2); + world.map.size.x, win->frame_size.x); + win->center.x = offset + (win->frame_size.x / 2); if ('E' == d && win->center.x < world.map.size.x - 1) { win->center.x++; diff --git a/src/client/map_window.h b/src/client/map_window.h index 46ca435..39b0e6d 100644 --- a/src/client/map_window.h +++ b/src/client/map_window.h @@ -6,8 +6,6 @@ #ifndef MAP_WINDOW_H #define MAP_WINDOW_H -#include "../common/yx_uint16.h" /* for yx_uint16 */ - /* Try changing map window's focus into direction "d" (north = "N" etc.). */ diff --git a/src/client/misc.c b/src/client/misc.c index a37155b..ca8e829 100644 --- a/src/client/misc.c +++ b/src/client/misc.c @@ -1,28 +1,25 @@ /* src/client/misc.c */ #include "misc.h" -#include /* delwin(), endwin(), refresh() */ -#include /* uint8_t, uint16_t */ +#include /* exit() */ +#include /* delwin() */ +#include /* NULL */ +#include /* uint8_t, uint32_t */ #include /* sprintf() */ -#include /* exit(), free() */ -#include /* memset(), strlen() */ +#include /* strlen() */ #include /* global optarg, getopt() */ -#include "../common/readwrite.h" /* try_fopen(), try_fclose(), +#include "../common/readwrite.h" /* try_fopen(), try_fclose(), textfile_sizes(), * try_fclose_unlink_rename(), */ -#include "cleanup.h" /* for set_cleanup_flag() */ +#include "cleanup.h" /* set_cleanup_flag() */ #include "keybindings.h" /* free_keybindings(), read_keybindings_from_file(), * write_keybindings_to_file() */ -#include "map_window.h" /* for map_center() */ -#include "wincontrol.h" /* struct WinConf, init_wins(), get_winconf_by_win(), - * sorted_win_toggle_and_activate(), get_win_by_id(), - * toggle_window(), write_winconf_of_id_to_file(), - * read_winconf_from_file(), get_next_winconf_id(), - * read_order_wins_visible_active(), - * write_order_wins_visible_active() - */ -#include "windows.h" /* struct Win, make_pad(), suspend_win(), free_win() */ +#include "map_window.h" /* map_center() */ +#include "windows.h" /* for free_windb(), make_v_screen_and_init_win_sizes(), + * read_winconf_from_file(), write_winconf_of_id_to_file(), + * toggle_window() + */ #include "world.h" /* global world */ @@ -58,9 +55,9 @@ extern void save_interface_conf() write_keybindings_to_file(file, &world.kb_winkeys, delim); write_order_wins_visible_active(file, delim); uint8_t i; - for (i = 0; i < strlen(world.wins.ids); i++) + for (i = 0; i < strlen(world.windb.ids); i++) { - write_winconf_of_id_to_file(file, world.wins.ids[i], delim); + write_winconf_of_id_to_file(file, world.windb.ids[i], delim); } try_fclose_unlink_rename(file, path_tmp, path, f_name); } @@ -83,9 +80,14 @@ extern void load_interface_conf() try_fclose(file, f_name); /* Build windows as defined by read interface data and toggle them on. */ - make_pad(); - init_wins(); - sorted_win_toggle_and_activate(); + make_v_screen_and_init_win_sizes(); + uint8_t i; + char tmp_active = world.windb.active; + char tmp_order[strlen(world.windb.order) + 1]; + sprintf(tmp_order, "%s", world.windb.order); + world.windb.order[0] = '\0'; + for (i = 0; i < strlen(tmp_order); toggle_window(tmp_order[i]), i++); + world.windb.active = tmp_active; /* So that the interface config data and the window structs get freed. */ set_cleanup_flag(CLEANUP_INTERFACE); @@ -101,66 +103,12 @@ extern void unload_interface_conf() world.kb_wingeom.kbs = NULL; free_keybindings(world.kb_winkeys.kbs); world.kb_winkeys.kbs = NULL; - while (0 != world.wins.win_active) - { - suspend_win(world.wins.win_active); - } - free_winconfs(); - delwin(world.wins.pad); -} - - - -extern void winch_called(int signal) -{ - world.winch = 1; -} - - - -extern void reset_windows() -{ - endwin(); /* "[S]tandard way" to recalibrate ncurses post SIGWINCH, says */ - refresh(); /* . */ - struct Win * w_p = world.wins.chain_start; - char win_ids[strlen(world.wins.ids) + 1]; - memset(win_ids, '\0', strlen(world.wins.ids) + 1); - uint8_t i = 0; - char active = '\0'; - for (; NULL != w_p; w_p = w_p->next, i++) - { - struct WinConf * wc_p = get_winconf_by_win(w_p); - win_ids[i] = wc_p->id; - if (w_p == world.wins.win_active) - { - active = wc_p->id; - } - } - while (0 != world.wins.win_active) - { - w_p = world.wins.win_active; - suspend_win(w_p); - } - char id; - while (0 != (id = get_next_winconf_id())) + while ('\0' != world.windb.active) { - free_win(get_win_by_id(id)); - } - delwin(world.wins.pad); - make_pad(); - init_wins(); - if (strlen(win_ids) < 1) - { - return; - } - for (i = 0; i < strlen(win_ids); i++) - { - toggle_window(win_ids[i]); - if (active == win_ids[i]) - { - world.wins.win_active = get_win_by_id(win_ids[i]); - } + toggle_window(world.windb.active); } + free_windb(); + delwin(world.windb.v_screen); } @@ -174,29 +122,6 @@ extern void reload_interface_conf() -extern uint16_t center_offset(uint16_t position, uint16_t mapsize, - uint16_t framesize) -{ - uint16_t offset = 0; - if (mapsize > framesize) - { - if (position > framesize / 2) - { - if (position < mapsize - (framesize / 2)) - { - offset = position - (framesize / 2); - } - else - { - offset = mapsize - framesize; - } - } - } - return offset; -} - - - extern void nav_inventory(char dir) { if ('u' == dir) @@ -214,4 +139,3 @@ extern void nav_inventory(char dir) world.player_inventory_select = world.player_inventory_select + (world.player_inventory_select < n_elems); } - diff --git a/src/client/misc.h b/src/client/misc.h index 01e2488..5fb3e71 100644 --- a/src/client/misc.h +++ b/src/client/misc.h @@ -7,8 +7,6 @@ #ifndef MISC_H #define MISC_H -#include /* for uint16_t */ - /* Parses command line argument -i into client configuration. */ @@ -25,17 +23,6 @@ extern void load_interface_conf(); extern void unload_interface_conf(); extern void reload_interface_conf(); -/* The SIGWINCH handler winch_called() merely sets world.winch to 1. This info - * is used by io_loop() to call reset_windows(), which adapts the currently - * loaded interface configuration to the new screen size. - */ -extern void winch_called(); -extern void reset_windows(); - -/* Return offset into center map of "mapsize" on "position" in "framesize". */ -extern uint16_t center_offset(uint16_t position, - uint16_t mapsize, uint16_t framesize); - /* Move world.inventory_sel up ("dir"="u") or down (else) as far as possible. */ extern void nav_inventory(char dir); diff --git a/src/client/wincontrol.c b/src/client/wincontrol.c deleted file mode 100644 index 5b82053..0000000 --- a/src/client/wincontrol.c +++ /dev/null @@ -1,459 +0,0 @@ -/* src/client/wincontrol.c */ - -#include "wincontrol.h" -#include /* global errno */ -#include /* NULL */ -#include /* uint8_t, uint16_t, uint32_t */ -#include /* FILE, sprintf() */ -#include /* free(), atoi() */ -#include /* strlen(), strchr(), memcpy() */ -#include "../common/readwrite.h" /* try_fgets(), try_fwrite(), try_fgetc(), - * try_fputc() - */ -#include "../common/rexit.h" /* exit_err(), exit_trouble() */ -#include "../common/try_malloc.h" /* try_malloc() */ -#include "../common/yx_uint16.h" /* struct yx_uint16 */ -#include "draw_wins.h" /* draw_win_map(), draw_win_info(), draw_win_log(), - * draw_win_available_keybindings(), - * draw_win_inventory(), draw_win_keybindings_global(), - * draw_win_keybindings_winconf_geometry(), - * draw_win_keybindings_winconf_keybindings(), - * draw_winconf_geometry(), draw_winconf_keybindings() - */ -#include "keybindings.h" /* struct KeyBinding, free_keybindings() */ -#include "windows.h" /* struct Win, resize_active_win(), reset_pad_offset(), - * append_win(), suspend_win(), init_win(), free_win() - */ -#include "world.h" /* global world */ - - - -/* Wrapper around init_win() called with values from Winconf of "id". */ -static void init_win_from_winconf(char id); - -/* Free data pointed to inside individual WinConf struct of "id". */ -static void free_winconf_data(char id); - -/* Write geometry of a window to its WinConf, as positive or negative values - * (dependent on state ofWinConf->height_type / WinConf->width_type). - */ -static void set_winconf_geometry(char id); - -/* Get WinConf by "id". */ -static struct WinConf * get_winconf_by_id(char id); - -/* Get (Win->draw) function identified by "c"; NULL if c not mapped to one. */ -static void * get_drawfunc_by_char(char c); - - - -static void free_winconf_data(char id) -{ - struct WinConf * wc = get_winconf_by_id(id); - free(wc->title); - free_keybindings(wc->kb.kbs); - free_win(wc->win); -} - - - -static void set_winconf_geometry(char id) -{ - struct WinConf * wcp = get_winconf_by_id(id); - if (0 == wcp->height_type) - { - wcp->height = wcp->win->framesize.y; - } - else if (1 == wcp->height_type) - { - wcp->height = wcp->win->framesize.y - world.wins.padsize.y + 1; - } - if (0 == wcp->width_type) - { - wcp->width = wcp->win->framesize.x; - } - else if (1 == wcp->width_type) - { - wcp->width = wcp->win->framesize.x - world.wins.padsize.x; - } -} - - - -static void * get_drawfunc_by_char(char c) -{ - - if ('c' == c) - { - return draw_win_inventory; - } - else if ('i' == c) - { - return draw_win_info; - } - else if ('l' == c) - { - return draw_win_log; - } - else if ('k' == c) - { - return draw_win_available_keybindings; - } - else if ('m' == c) - { - return draw_win_map; - } - else if ('0' == c) - { - return draw_win_keybindings_global; - } - else if ('1' == c) - { - return draw_win_keybindings_winconf_geometry; - } - else if ('2' == c) - { - return draw_win_keybindings_winconf_keybindings; - } - return NULL; -} - - - -extern void init_win_from_winconf(char id) -{ - char * err = "get_drawfunc_by_char() returns NULL to init_win_from_file()."; - struct WinConf * winconf = get_winconf_by_id(id); - void * f = get_drawfunc_by_char(winconf->id); - exit_err(NULL == f, err); - init_win(&winconf->win, winconf->title, winconf->height, winconf->width, f); -} - - - -static struct WinConf * get_winconf_by_id(char id) -{ - uint8_t i = 0; - while (1) - { - if (id == world.wins.winconfs[i].id) - { - return &world.wins.winconfs[i]; - } - i++; - } -} - - - -extern struct WinConf * get_winconf_by_win(struct Win * win) -{ - uint8_t i = 0; - while (1) - { - if (win == world.wins.winconfs[i].win) - { - return &world.wins.winconfs[i]; - } - i++; - } -} - - - -extern struct Win * get_win_by_id(char id) -{ - struct WinConf * wc = get_winconf_by_id(id); - return wc->win; -} - - - -extern uint8_t read_winconf_from_file(char * line, uint32_t linemax, - FILE * file) -{ - char * f_name = "read_winconf_from_file()"; - int test = try_fgetc(file, f_name); - if (EOF == test) - { - return 0; - } - struct WinConf winconf; - winconf.id = (char) test; - try_fgetc(file, f_name); - try_fgets(line, linemax + 1, file, f_name); - winconf.title = try_malloc(strlen(line), f_name); - memcpy(winconf.title, line, strlen(line) - 1); /* Eliminate newline char */ - winconf.title[strlen(line) - 1] = '\0'; /* char at end of string. */ - try_fgets(line, linemax + 1, file, f_name); - winconf.height = atoi(line); - winconf.height_type = (0 >= winconf.height); - try_fgets(line, linemax + 1, file, f_name); - winconf.width = atoi(line); - winconf.width_type = (0 >= winconf.width); - read_keybindings_from_file(line, linemax, file, &winconf.kb); - winconf.win = NULL; - winconf.view = 0; - winconf.center.y = 0; - winconf.center.x = 0; - if (world.wins.ids) - { - uint8_t old_ids_size = strlen(world.wins.ids); - char * new_ids = try_malloc(old_ids_size + 1 + 1, f_name); - sprintf(new_ids, "%s%c", world.wins.ids, winconf.id); - free(world.wins.ids); - world.wins.ids = new_ids; - uint16_t old_winconfs_size = old_ids_size * sizeof(struct WinConf); - uint16_t new_winconfs_size = old_winconfs_size + sizeof(struct WinConf); - struct WinConf * new_winconfs = try_malloc(new_winconfs_size, f_name); - memcpy(new_winconfs, world.wins.winconfs, old_winconfs_size); - new_winconfs[old_ids_size] = winconf; - free(world.wins.winconfs); - world.wins.winconfs = new_winconfs; - } - else - { - world.wins.ids = try_malloc(2, f_name); - sprintf(world.wins.ids, "%c", winconf.id); - world.wins.winconfs = try_malloc(sizeof(struct WinConf), f_name); - *world.wins.winconfs = winconf; - } - return 1; -} - - - -extern void write_winconf_of_id_to_file(FILE * file, char c, char * delim) -{ - char * f_name = "write_winconf_of_id_to_file()"; - struct WinConf * wc = get_winconf_by_id(c); - uint8_t size = strlen(wc->title) + 2; - if (size < 7) /* Ensure that at least 5 + 2 char fit into line so that */ - { /* the digit representation of any uint16_t may be stored. */ - size = 7; - } - char line[size]; - sprintf(line, "%c\n", wc->id); - try_fwrite(line, sizeof(char), strlen(line), file, f_name); - sprintf(line, "%s\n", wc->title); - try_fwrite(line, sizeof(char), strlen(line), file, f_name); - sprintf(line, "%d\n", wc->height); - try_fwrite(line, sizeof(char), strlen(line), file, f_name); - sprintf(line, "%d\n", wc->width); - try_fwrite(line, sizeof(char), strlen(line), file, f_name); - write_keybindings_to_file(file, &wc->kb, delim); -} - - - -extern void read_order_wins_visible_active(char * line, uint32_t linemax, - FILE * file) -{ - char * f_name = "read_order_wins_visible_active()"; - char win_order[linemax + 1]; - try_fgets(win_order, linemax + 1, file, f_name); - world.wins.order = try_malloc(linemax, f_name); - win_order[strlen(win_order) - 1] = '\0'; - sprintf(world.wins.order, "%s", win_order); - int char_or_eof = try_fgetc(file, f_name); - char * err_eof = "fgetc() unexpectedly hitting EOF"; - exit_trouble(EOF == char_or_eof, f_name, err_eof); - world.wins.id_active = (uint8_t) char_or_eof; - exit_trouble(EOF == try_fgetc(file, f_name), f_name, err_eof); - try_fgets(line, linemax + 1, file, f_name); -} - - - -extern void write_order_wins_visible_active(FILE * file, char * delim) -{ - char * f_name = "write_order_wins_visible_active()"; - char line[strlen(world.wins.ids) + 2]; - struct Win * w_p = world.wins.chain_start; - char active = ' '; - uint8_t i; - for (; NULL != w_p; w_p = w_p->next, i++) - { - struct WinConf * wc_p = get_winconf_by_win(w_p); - line[i] = wc_p->id; - if (w_p == world.wins.win_active) - { - active = wc_p->id; - } - } - line[i] = '\n'; - line[i + 1] = '\0'; - try_fwrite(line, sizeof(char), strlen(line), file, f_name); - try_fputc(active, file, f_name); - try_fputc('\n', file, f_name); - try_fwrite(delim, strlen(delim), 1, file, f_name); -} - - - -extern void free_winconfs() -{ - char id; - while (0 != (id = get_next_winconf_id())) - { - free_winconf_data(id); - } - free(world.wins.ids); - world.wins.ids = NULL; - free(world.wins.winconfs); - world.wins.winconfs = NULL; - free(world.wins.order); - world.wins.order = NULL; -} - - - -extern void init_wins() -{ - char id; - while (0 != (id = get_next_winconf_id())) - { - init_win_from_winconf(id); - } -} - - - -extern void sorted_win_toggle_and_activate() -{ - uint8_t i = 0; - for (; i < strlen(world.wins.order); i++) - { - if (NULL == strchr(world.wins.ids, world.wins.order[i])) - { - continue; - } - toggle_window(world.wins.order[i]); - if (world.wins.id_active == (uint8_t) world.wins.order[i]) - { - world.wins.win_active = get_win_by_id(world.wins.order[i]); - } - } -} - - -extern char get_next_winconf_id() -{ - static uint8_t i = 0; - char c = world.wins.ids[i]; - if (0 == c) - { - i = 0; - return c; - } - i++; - return c; -} - - - -extern void toggle_window(char id) -{ - struct Win * win = get_win_by_id(id); - if (0 == win->prev && world.wins.chain_start != win) /* Win struct is */ - { /* outside chain? */ - append_win(win); - } - else - { - suspend_win(win); - } -} - - - -extern void toggle_winconfig() -{ - struct Win * win = world.wins.win_active; - struct WinConf * wcp = get_winconf_by_win(win); - if (0 == wcp->view) - { - wcp->view = 1; - win->draw = draw_winconf_geometry; - wcp->center = win->center; - win->center.y = 0; - win->center.x = 0; - } - else if (1 == wcp->view) - { - wcp->view = 2; - win->draw = draw_winconf_keybindings; - win->center.x = 0; - } - else - { - wcp->view = 0; - win->draw = get_drawfunc_by_char(wcp->id); - win->center = wcp->center; - } -} - - - -extern void toggle_win_size_type(char axis) -{ - struct Win * win = world.wins.win_active; - struct WinConf * wcp = get_winconf_by_win(win); - if ('y' == axis) - { - wcp->height_type = (0 == wcp->height_type); - set_winconf_geometry(wcp->id); - return; - } - wcp->width_type = ( 0 == wcp->width_type - && win->framesize.x <= world.wins.padsize.x); - set_winconf_geometry(wcp->id); -} - - - -extern void scroll_pad(char dir) -{ - if ('+' == dir) - { - reset_pad_offset(world.wins.pad_offset + 1); - } - else if ('-' == dir) - { - reset_pad_offset(world.wins.pad_offset - 1); - } -} - - - -extern void growshrink_active_window(char change) -{ - if (0 != world.wins.win_active) - { - struct yx_uint16 size = world.wins.win_active->framesize; - if (change == '-') - { - size.y--; - } - else if (change == '+') - { - size.y++; - } - else if (change == '_') - { - size.x--; - } - else if (change == '*') - { - size.x++; - } - resize_active_win(size); - struct WinConf * wcp = get_winconf_by_win(world.wins.win_active); - if ( 1 == wcp->width_type - && world.wins.win_active->framesize.x > world.wins.padsize.x) - { - wcp->width_type = 0; - } - set_winconf_geometry(wcp->id); - } -} diff --git a/src/client/wincontrol.h b/src/client/wincontrol.h deleted file mode 100644 index 9e7de86..0000000 --- a/src/client/wincontrol.h +++ /dev/null @@ -1,107 +0,0 @@ -/* src/client/wincontrol.h - * - * Routines that build on top of the windows library to provide a simple window - * management API to the game. Also helps managing window-specific keybindings. - */ - -#ifndef WINCONTROL_H -#define WINCONTROL_H - -#include /* uint8_t, int16_t */ -#include "keybindings.h" /* struct KeyBindingDB */ -#include "../common/yx_uint16.h" /* yx_uint16 struct */ -struct Win; - -#include - - -struct WinConfDB -{ - WINDOW * screen; /* ncurses' pointer to the terminal screen */ - WINDOW * pad; /* ncurses pad of virtual screen */ - struct WinConf * winconfs; - struct Win * chain_start; /* first Win in chain; its .prev == 0 */ - struct Win * chain_end; /* last Win in chain; its .next == 0 */ - struct Win * win_active; /* Win highlighted / selected for manipulation */ - struct yx_uint16 padsize; /* virtual screen size */ - char * ids; /* all windows' ids */ - char * order; /* order of visible windows (identified by IDs) */ - uint16_t pad_offset; /* number of cells view is moved to the right */ - char id_active; /* id of window selected as active */ -}; - -/* Window's configuration (like geometry, keybindings) and the Win itself. */ -struct WinConf -{ - struct Win * win; /* Window / Win struct configured by this WinConf. */ - struct KeyBindingDB kb; /* Window-specific keybindings. */ - struct yx_uint16 center; /* Designated Win.center. */ - int16_t height; /* Designated height to pass to init_win(). */ - int16_t width; /* Designated width to pass to init_win(). */ - uint8_t height_type; /* 0: read .height/.width as size in positive cells; */ - uint8_t width_type; /* 1: as negative diff in cells to the screen size. */ - uint8_t view; /* 0: use .draw as Win.draw; 1/2: use draw_winconf()_(1/2). */ - char id; /* Identifier of WinConf, also identifies Win.draw function. */ - char * title; /* Designated title to pass to init_win(). */ -}; - - - -/* Get WinConf fathering "win" / get Win of WinConf of "id". */ -extern struct WinConf * get_winconf_by_win(struct Win * win); -extern struct Win * get_win_by_id(char id); - -/* Free all WinConf DB data. */ -extern void free_winconfs(); - -/* Initialize Win structs for WinConfs in WinConf database. */ -extern void init_wins(); - -/* Toggle windows in order set by world.win_order. Point active window selection - * to window identified by world.wins.win_active. - */ -extern void sorted_win_toggle_and_activate(); - -/* Read/write world.win_order and world.wins.win_active from/to "file". */ -extern void read_order_wins_visible_active(char * line, uint32_t linemax, - FILE * file); -extern void write_order_wins_visible_active(FILE * file, char * delim); - -/* Iterate over chars of world.wins.winconf_ids array. Restart after \0.*/ -extern char get_next_winconf_id(); - -/* Read/write individual WinConf (identified by "c") from/to file. */ -extern uint8_t read_winconf_from_file(char * line, uint32_t linemax, - FILE * file); -extern void write_winconf_of_id_to_file(FILE * file, char c, char * delim); - -/* Toggle "window configuration" view for active window. Sets sensible - * Win.center values for the various configuration views (for winconf_geometry: - * y=0, x=0; for winconf_keys: x=0 (y is set by draw_winconf_keybindings()). - */ -extern void toggle_winconfig(); - -/* Toggle WinConf.(height/width)_type ("axis" = "y": height; else: width). Avoid - * positive diff to screen width (value would be wrongly read as a non-diff), - * width_type toggles to 1 only if world.wins.screen's width >= WinConf.width. - */ -extern void toggle_win_size_type(char axis); - -/* Toggle display of a window identified by "id". */ - extern void toggle_window(char id); - -/* Try scrolling virtual screen left ("dir" = "-") or right ("dir" = "+") to the - * degree allowed by the window manager's reset_pad_offset(). - */ -extern void scroll_pad(char dir); - -/* Try to grow or shrink the active window horizontally ("change" = "*"/"_") or - * vertically ("change = "+"/"-") by one cell size to the degree allowed by the - * window manager's resize_active_win(). If a new window width would surpass - * that of the terminal screen, set WinConf.width_type to 0. - */ -extern void growshrink_active_window(char change); - - - -#endif diff --git a/src/client/windows.c b/src/client/windows.c index c69ee7d..2d5dd3a 100644 --- a/src/client/windows.c +++ b/src/client/windows.c @@ -1,26 +1,66 @@ /* src/client/windows.c */ #include "windows.h" +#include /* chtype, getmaxx(), getmaxy(), erase(), werase(), + * endwin(), delwin(), wnoutrefresh(), pnoutrefresh(), + * doupdate(), refresh(), delwin(), newpad(), mvwaddch(), + * mvwaddstr(), wresize() + */ #include /* NULL */ +#include /* free(), atoi() */ #include /* uint8_t, uint16_t, uint32_t, UINT16_MAX */ #include /* sprintf() */ -#include /* free() */ -#include /* strlen(), memcpy(), strnlen() */ -#include /* chtype, pnoutrefresh(), doupdate(), werase(), erase(), - * wnoutrefresh(), getmaxx(), getmaxy(), mvwaddstr(), - * mvwaddch(), mvwaddstr(), wresize() - */ -#include "../common/rexit.h" /* for exit_err() */ -#include "../common/try_malloc.h" /* for try_malloc() */ -#include "../common/yx_uint16.h" /* for struct yx_uint16 */ -#include "misc.h" /* for center_offset() */ -#include "world.h" /* for world global */ +#include /* memcpy(), strlen(), strnlen(), strchr() */ +#include "../common/rexit.h" /* exit_trouble(), exit_err() */ +#include "../common/readwrite.h" /* try_fputc(), try_write(), try_fgets(), + * try_fgetc() + */ +#include "../common/try_malloc.h" /* try_malloc() */ +#include "../common/yx_uint16.h" /* struct yx_uint16 */ +#include "draw_wins.h" /* draw_winconf_geometry(), draw_winconf_keybindings(), + * draw_win_inventory(), draw_win_info(), draw_win_log(), + * draw_win_available_keybindings(), draw_win_map(), + * draw_win_keybindings_winconf_keybindings(), + * draw_win_keybindings_winconf_geometry(), + * draw_win_keybindings_global() + */ +#include "keybindings.h" /* free_keybindings(), write_keybidings_to_file(), + * read_keybindings_from_file() + */ +#include "world.h" /* global world */ + + + +/* Get position of id "c" in world.windb.order or return Win before/after (or + * NULL if there is no window before/after). + */ +static uint8_t get_pos_in_order(char c); +static struct Win * get_win_after(char c); +static struct Win * get_win_before(char c); + +/* Calculate "id"'s window's size from v_screen size and .target_(height/width). + * A .target_width == 0 makes the window as wide as .t_screen. .target_height == + * 0 sets the maximum allowed height: one cell smaller than that of .v_screen. + * Negative values make width/height so many cells smaller than what 0 would + * set. Values that would reduce the window height or width to less than 1 cell + * according to the aforementioned rules set the height/width as if they were 0. + */ +static void init_win_size_from_winconf_and_v_screen_size(char id); +/* Get (Win->draw) function identified by "c"; NULL if c not mapped to one. + * match_func() is just a little helper to it. + */ +static uint8_t match_func(char c, void (** f) (), char c_m, void (* f_m) ()); +static void * get_drawfunc_by_char(char c); +/* Write "win"'s size back to .target_(height/width) as per .target_*_type. */ +static void set_win_target_size(struct Win * win); +/* Iterate over chars of world.windb.ids array / string. Restart after \0.*/ +static char get_next_win_id(); -/* Make virtual screen just wide enough to contain all visible windows. */ -static void refit_pad(); +/* Make .v_screen just wide enough to contain all visible windows. */ +static void refit_v_screen(); /* Update geometry (sizes, positions) of window "w" and its successors in the * window chain. Use place_win() for the positioning algorithm. @@ -29,23 +69,19 @@ static void update_wins(struct Win * w); static void place_win(struct Win * w); /* Draw scroll hint (a line saying that there are "dist" more elements of "unit" - * further into the direction symbolized by "dir") into virtual screen, onto an - * appropriate edge of a window or the screen; the left/right edge if "dir" is - * "<"/">", or the top/bottom edge if it is "^"/"v". "start" be either the start - * coordinate of a window's frame, or .y=0, .x=wm->pad_offset for the virtual - * screen. winscroll_hint() and padscroll_hint() are wrappers to both cases. + * further into the direction symbolized by "dir") into .v_screen, onto an + * appropriate edge of a window or .v_screen; the left/right edge if "dir" is + * "<"/">", or the top/bottom edge if it is "^"/"v". Use "start" as the start + * coordinate of the frame that is to contain the scroll hints. winscroll_hint() + * is a wrapper that uses the border of window "w" as this frame. */ static void scroll_hint(struct yx_uint16 fsize, char dir, uint16_t dist, char * unit, struct yx_uint16 start); static void winscroll_hint(struct Win * w, char dir, uint16_t dist); -static void padscroll_hint(char dir, uint16_t dist); - -/* Draw contents of all windows in window chain from window "w" onwards. */ -static void draw_wins(struct Win * w); /* draw_win_borderlines() draws vertical/horizontal borders of window "w" sans - * corners into the virtual screen. It draws the top border line as the windows' - * title bar (highlighted if the window is selected as active). It is called + * corners into .v_screen. It draws the top border line as the windows' title + * bar (highlighted if the window is selected as active). It is called * recursively by draw_wins_borderlines() on all windows from "w" on. * draw_wins_bordercorners() draws the border corners of "w" and its successors. */ @@ -53,34 +89,166 @@ static void draw_win_borderlines(struct Win * w); static void draw_wins_borderlines(struct Win * w); static void draw_wins_bordercorners(struct Win * w); -/* Shift active window forwards / backwards in window chain. */ -static void shift_win_forward(); -static void shift_win_backward(); +/* Draw contents of all windows in window chain from window "w" onwards. */ +static void draw_wins(struct Win * w); + +/* Append/suspend window "w" to/from chain of visible windows. Appended windows + * will become active. Suspended active windows will move the active window + * selection to their successor in the window chain or, failing that, their + * predecessor, or, failing that, to 0 (no window active). + */ +static void append_win(struct Win * w); +static void suspend_win(struct Win * w); + +/* Copy Win content pointed to by "win" into appendend world.windb.wins area. */ +static void add_win_to_windb(struct Win * win); + + + +static uint8_t get_pos_in_order(char c) +{ + uint8_t i; + for (i = 0; c != world.windb.order[i]; i++); + return i; +} + + +static struct Win * get_win_after(char c) +{ + return get_win_by_id(world.windb.order[get_pos_in_order(c) + 1]); +} -static void refit_pad() + +static struct Win * get_win_before(char c) +{ + uint8_t i = get_pos_in_order(c); + if (i > 0) + { + return get_win_by_id(world.windb.order[i - 1]); + } + return NULL; +} + + + +static void init_win_size_from_winconf_and_v_screen_size(char id) +{ + struct Win * w = get_win_by_id(id); + w->frame_size.y = world.windb.v_screen_size.y - 1; + if ( 0 < w->target_height + && w->target_height <= world.windb.v_screen_size.y - 1) + { + w->frame_size.y = w->target_height; + } + else if ( 0 > w->target_height + && world.windb.v_screen_size.y + (w->target_height - 1) > 0) + { + w->frame_size.y = world.windb.v_screen_size.y + (w->target_height - 1); + } + w->frame_size.x = world.windb.v_screen_size.x; + if (0 < w->target_width) + { + w->frame_size.x = w->target_width; + } + else if ( 0 > w->target_width + && world.windb.v_screen_size.x + w->target_width > 0) + { + w->frame_size.x = world.windb.v_screen_size.x + w->target_width; + } +} + + + +static uint8_t match_func(char c, void (** f) (), char c_m, void (* f_m) ()) +{ + if (c == c_m) + { + * f = f_m; + return 1; + } + return 0; +} + + + +static void * get_drawfunc_by_char(char c) +{ + void (* f) (struct Win *) = NULL; + if ( match_func(c, &f, 'c', draw_win_inventory) + || match_func(c, &f, 'i', draw_win_info) + || match_func(c, &f, 'l', draw_win_log) + || match_func(c, &f, 'k', draw_win_available_keybindings) + || match_func(c, &f, 'm', draw_win_map) + || match_func(c, &f, '0', draw_win_keybindings_global) + || match_func(c, &f, '1', draw_win_keybindings_winconf_geometry) + || match_func(c, &f, '2', draw_win_keybindings_winconf_keybindings)); + return f; +} + + + +static void set_win_target_size(struct Win * wcp) +{ + if (0 == wcp->target_height_type) + { + wcp->target_height = wcp->frame_size.y; + } + else if (1 == wcp->target_height_type) + { + wcp->target_height = wcp->frame_size.y - world.windb.v_screen_size.y +1; + } + if (0 == wcp->target_width_type) + { + wcp->target_width = wcp->frame_size.x; + } + else if (1 == wcp->target_width_type) + { + wcp->target_width = wcp->frame_size.x - world.windb.v_screen_size.x; + } +} + + + +static char get_next_win_id() +{ + static uint8_t i = 0; + char c = world.windb.ids[i]; + if (0 == c) + { + i = 0; + return c; + } + i++; + return c; +} + + + +static void refit_v_screen() { /* Determine rightmost window column. */ uint32_t lastwcol = 0; - struct Win * wp = world.wins.chain_start; + struct Win * wp = get_win_by_id(world.windb.order[0]); while (wp != 0) { - if ((uint32_t) wp->start.x + (uint32_t) wp->framesize.x > lastwcol + 1) + if ((uint32_t) wp->start.x + (uint32_t) wp->frame_size.x > lastwcol + 1) { - lastwcol = (uint32_t) wp->start.x + (uint32_t) wp->framesize.x - 1; + lastwcol = (uint32_t) wp->start.x + (uint32_t) wp->frame_size.x - 1; } - wp = wp->next; + wp = get_win_after(wp->id); } - /* Only resize the pad if the rightmost window column has changed. */ - char * err_s = "refit_pad() extends virtual screen beyond legal sizes."; - char * err_m = "refit_pad() triggers memory alloc error via wresize()."; - if (getmaxx(world.wins.pad) + 1 != lastwcol) + /* Only resize .v_screen if the rightmost window column has changed. */ + char * err_s = "refit_v_screen() grows virtual screen beyond legal sizes."; + char * err_m = "refit_v_screen() triggers memory alloc error in wresize()."; + if (getmaxx(world.windb.v_screen) + 1 != lastwcol) { uint8_t t = (lastwcol + 2 > UINT16_MAX); exit_err(t, err_s); - t = wresize(world.wins.pad, getmaxy(world.wins.pad), lastwcol + 2); + t = wresize(world.windb.v_screen, getmaxy(world.windb.v_screen), + lastwcol + 2); exit_err(t, err_m); } } @@ -90,10 +258,11 @@ static void refit_pad() static void update_wins(struct Win * w) { place_win(w); - refit_pad(); - if (0 != w->next) + refit_v_screen(); + struct Win * next = get_win_after(w->id); + if (next) { - update_wins(w->next); + update_wins(next); } } @@ -104,24 +273,25 @@ static void place_win(struct Win * w) /* If w is first window, it goes into the top left corner. */ w->start.x = 0; w->start.y = 1; /* Leave space for title bar. */ - if (0 != w->prev) + struct Win * w_prev = get_win_before(w->id); + if (w_prev) { /* If not, fit w's top left to top right of last top predecessor. */ - struct Win * w_top = w->prev; - while (w_top->start.y != 1) - { - w_top = w_top->prev; - } - w->start.x = w_top->start.x + w_top->framesize.x + 1; + struct Win * w_top = w_prev; + for (; + w_top->start.y != 1; + w_top = get_win_before(w_top->id)); + w->start.x = w_top->start.x + w_top->frame_size.x + 1; /* Fit w's top left to bottom left of its ->prev if enough space. */ - uint16_t w_prev_maxy = w->prev->start.y + w->prev->framesize.y; - if ( w->framesize.x <= w->prev->framesize.x - && w->framesize.y < world.wins.padsize.y - w_prev_maxy) + 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 < world.windb.v_screen_size.y - w_prev_maxy) { - w->start.x = w->prev->start.x; + w->start.x = w_prev->start.x; w->start.y = w_prev_maxy + 1; + return; } /* Failing that, try to fit w' top left to the top right of the last @@ -130,26 +300,24 @@ static void place_win(struct Win * w) * until the bottom right of w_thr directly throning over it 3) and with * this same space extending far enough to the bottom for fitting in w. */ - else + struct Win * w_test = w_prev; + struct Win * w_thr; + while (w_test != w_top) { - struct Win * w_test = w->prev; - struct Win * w_thr; - while (w_test != w_top) + for (w_thr = get_win_before(w_test->id); + w_test->start.y <= w_thr->start.y; + w_thr = get_win_before(w_thr->id)); + uint16_t w_thr_bottom = w_thr->start.y + w_thr->frame_size.y; + uint16_t free_width = (w_thr->start.x + w_thr->frame_size.x) + - (w_test->start.x + w_test->frame_size.x); + if ( w->frame_size.y < world.windb.v_screen_size.y - w_thr_bottom + && w->frame_size.x < free_width) { - w_thr = w_test->prev; - for (; w_test->start.y <= w_thr->start.y; w_thr = w_thr->prev); - uint16_t w_thr_bottom = w_thr->start.y + w_thr->framesize.y; - uint16_t free_width = (w_thr->start.x + w_thr->framesize.x) - - (w_test->start.x + w_test->framesize.x); - if ( w->framesize.y < world.wins.padsize.y - w_thr_bottom - && w->framesize.x < free_width) - { - w->start.x = w_test->start.x + w_test->framesize.x + 1; - w->start.y = w_thr_bottom + 1; - break; - } - w_test = w_thr; + w->start.x = w_test->start.x + w_test->frame_size.x + 1; + w->start.y = w_thr_bottom + 1; + break; } + w_test = w_thr; } } } @@ -196,23 +364,14 @@ static void scroll_hint(struct yx_uint16 fsize, char dir, uint16_t dist, } if ('<' == dir || '>' == dir) { - mvwaddch(world.wins.pad, start.y + q, start.x + draw_offset, c); + mvwaddch(world.windb.v_screen, start.y+q, start.x+draw_offset, c); continue; } - mvwaddch(world.wins.pad, start.y + draw_offset, start.x + q, c); + mvwaddch(world.windb.v_screen, start.y + draw_offset, start.x + q, c); } } -static void padscroll_hint(char dir, uint16_t dist) -{ - struct yx_uint16 start; - start.y = 0; - start.x = world.wins.pad_offset; - scroll_hint(world.wins.padsize, dir, dist, "columns", start); -} - - static void winscroll_hint(struct Win * w, char dir, uint16_t dist) { @@ -222,52 +381,7 @@ static void winscroll_hint(struct Win * w, char dir, uint16_t dist) unit = "columns"; } struct yx_uint16 start = w->start; - scroll_hint(w->framesize, dir, dist, unit, start); -} - - - -static void draw_wins(struct Win * w) -{ - w->draw(w); - uint16_t size_y = w->winmapsize.y; - uint16_t size_x = w->winmapsize.x; - uint16_t offset_y = center_offset(w->center.y, size_y, w->framesize.y); - uint16_t offset_x = center_offset(w->center.x, size_x, w->framesize.x); - uint16_t y, x; - for (y = offset_y; y < w->framesize.y + offset_y && y < size_y; y++) - { - for (x = offset_x; x < w->framesize.x + offset_x && x < size_x; x++) - { - chtype ch = w->winmap[(y * w->winmapsize.x) + x]; - mvwaddch(world.wins.pad, w->start.y + (y - offset_y), - w->start.x + (x - offset_x), ch); - } - } - free(w->winmap); - w->winmap = NULL; - w->winmapsize.y = 0; - w->winmapsize.x = 0; - if (offset_y > 0) - { - winscroll_hint(w, '^', offset_y + 1); - } - if (size_y > offset_y + w->framesize.y) - { - winscroll_hint(w, 'v', size_y - ((offset_y + w->framesize.y) - 1)); - } - if (offset_x > 0) - { - winscroll_hint(w, '<', offset_x + 1); - } - if (size_x > offset_x + w->framesize.x) - { - winscroll_hint(w, '>', size_x - ((offset_x + w->framesize.x) - 1)); - } - if (0 != w->next) - { - return draw_wins(w->next); - } + scroll_hint(w->frame_size, dir, dist, unit, start); } @@ -276,38 +390,37 @@ static void draw_win_borderlines(struct Win * w) { /* Draw vertical and horizontal border lines. */ uint16_t y, x; - for (y = w->start.y; y <= w->start.y + w->framesize.y; y++) + for (y = w->start.y; y <= w->start.y + w->frame_size.y; y++) { - mvwaddch(world.wins.pad, y, w->start.x - 1, '|'); - mvwaddch(world.wins.pad, y, w->start.x + w->framesize.x, '|'); + mvwaddch(world.windb.v_screen, y, w->start.x - 1, '|'); + mvwaddch(world.windb.v_screen, y, w->start.x + w->frame_size.x, '|'); } - for (x = w->start.x; x <= w->start.x + w->framesize.x; x++) + for (x = w->start.x; x <= w->start.x + w->frame_size.x; x++) { - mvwaddch(world.wins.pad, w->start.y - 1, x, '-'); - mvwaddch(world.wins.pad, w->start.y + w->framesize.y, x, '-'); + mvwaddch(world.windb.v_screen, w->start.y - 1, x, '-'); + mvwaddch(world.windb.v_screen, w->start.y + w->frame_size.y, x, '-'); } /* Draw as much as possible of the title into center of top border line. */ - char min_title_length_visible = 3; /* min. 1 char + 2 padding/decoration */ - if (w->framesize.x >= min_title_length_visible) + uint8_t min_title_length_visible = 3;/* min. 1 char +2 padding/decoration*/ + if (w->frame_size.x >= min_title_length_visible) { - uint16_t title_offset = 0; - if (w->framesize.x > strlen(w->title) + 2) + uint16_t offset = 0; + if (w->frame_size.x > strlen(w->title) + 2) { - title_offset = (w->framesize.x - (strlen(w->title) + 2)) / 2; + offset = (w->frame_size.x - (strlen(w->title) + 2)) / 2; } /* +2 is for padding/decoration */ - uint16_t length_visible = strnlen(w->title, w->framesize.x - 2); + uint16_t length_visible = strnlen(w->title, w->frame_size.x - 2); char title[length_visible + 3]; char decoration = ' '; - if (w == world.wins.win_active) + if (w->id == world.windb.active) { decoration = '$'; } memcpy(title + 1, w->title, length_visible); title[0] = title[length_visible + 1] = decoration; title[length_visible + 2] = '\0'; - mvwaddstr(world.wins.pad, - w->start.y - 1, w->start.x + title_offset, title); + mvwaddstr(world.windb.v_screen, w->start.y-1, w->start.x+offset, title); } } @@ -316,9 +429,10 @@ static void draw_win_borderlines(struct Win * w) static void draw_wins_borderlines(struct Win * w) { draw_win_borderlines(w); - if (0 != w->next) + struct Win * next = get_win_after(w->id); + if (next) { - draw_wins_borderlines(w->next); + draw_wins_borderlines(next); } } @@ -326,324 +440,556 @@ static void draw_wins_borderlines(struct Win * w) static void draw_wins_bordercorners(struct Win * w) { - mvwaddch(world.wins.pad, w->start.y - 1, w->start.x - 1, '+'); - mvwaddch(world.wins.pad, w->start.y - 1, w->start.x + w->framesize.x, '+'); - mvwaddch(world.wins.pad, w->start.y + w->framesize.y, w->start.x - 1, '+'); - mvwaddch(world.wins.pad, w->start.y + w->framesize.y, - w->start.x + w->framesize.x, '+'); - if (0 != w->next) - { - draw_wins_bordercorners(w->next); + mvwaddch(world.windb.v_screen, + w->start.y - 1, w->start.x - 1, '+'); + mvwaddch(world.windb.v_screen, + w->start.y - 1, w->start.x + w->frame_size.x, '+'); + mvwaddch(world.windb.v_screen, + w->start.y + w->frame_size.y, w->start.x - 1, '+'); + mvwaddch(world.windb.v_screen, w->start.y + w->frame_size.y, + w->start.x + w->frame_size.x, '+'); + struct Win * next = get_win_after(w->id); + if (next) + { + draw_wins_bordercorners(next); } } -static void shift_win_forward() +static void draw_wins(struct Win * w) { - if (world.wins.win_active == world.wins.chain_end) + void (* drawfunc) (struct Win *) = get_drawfunc_by_char(w->id); + if (1 == w->view) { - world.wins.chain_end = world.wins.win_active->prev; - world.wins.chain_end->next = 0; - world.wins.win_active->next = world.wins.chain_start; - world.wins.win_active->next->prev = world.wins.win_active; - world.wins.chain_start = world.wins.win_active; - world.wins.chain_start->prev = 0; + drawfunc = draw_winconf_geometry; } - else + else if (2 == w->view) { - struct Win * old_prev = world.wins.win_active->prev; - struct Win * old_next = world.wins.win_active->next; - if (world.wins.chain_end == world.wins.win_active->next) - { - world.wins.chain_end = world.wins.win_active; - world.wins.win_active->next = 0; - } - else - { - world.wins.win_active->next = old_next->next; - world.wins.win_active->next->prev = world.wins.win_active; - } - if (world.wins.chain_start == world.wins.win_active) - { - world.wins.chain_start = old_next; - } - else + drawfunc = draw_winconf_keybindings; + } + drawfunc(w); + uint16_t size_y = w->winmap_size.y; + uint16_t size_x = w->winmap_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); + uint16_t y, 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++) { - old_prev->next = old_next; + chtype ch = w->winmap[(y * w->winmap_size.x) + x]; + mvwaddch(world.windb.v_screen, w->start.y + (y - offset_y), + w->start.x + (x - offset_x), ch); } - old_next->prev = old_prev; - old_next->next = world.wins.win_active; - world.wins.win_active->prev = old_next; + } + free(w->winmap); + w->winmap = NULL; + w->winmap_size.y = 0; + w->winmap_size.x = 0; + if (offset_y > 0) + { + winscroll_hint(w, '^', offset_y + 1); + } + if (size_y > offset_y + w->frame_size.y) + { + winscroll_hint(w, 'v', size_y - ((offset_y + w->frame_size.y) - 1)); + } + if (offset_x > 0) + { + winscroll_hint(w, '<', offset_x + 1); + } + if (size_x > offset_x + w->frame_size.x) + { + winscroll_hint(w, '>', size_x - ((offset_x + w->frame_size.x) - 1)); + } + struct Win * next = get_win_after(w->id); + if (next) + { + return draw_wins(next); } } -static void shift_win_backward() +static void append_win(struct Win * w) { - if (world.wins.win_active == world.wins.chain_start) - { - world.wins.chain_start = world.wins.win_active->next; - world.wins.chain_start->prev = 0; - world.wins.win_active->prev = world.wins.chain_end; - world.wins.win_active->prev->next = world.wins.win_active; - world.wins.chain_end = world.wins.win_active; - world.wins.chain_end->next = 0; + char * f_name = "append_win()"; + uint8_t old_size = strlen(world.windb.order) + 1; + char * new_order = try_malloc(old_size + 1, f_name); + memcpy(new_order, world.windb.order, old_size - 1); + new_order[old_size - 1] = w->id; + new_order[old_size] = '\0'; + free(world.windb.order); + world.windb.order = new_order; + world.windb.active = w->id; + update_wins(w); +} + + + +static void suspend_win(struct Win * w) +{ + char * f_name = "suspend_win()"; + uint8_t new_size = strlen(world.windb.order); + char * new_order = try_malloc(new_size, f_name); + uint8_t i = get_pos_in_order(w->id); + char next_char = world.windb.order[i + 1]; + world.windb.order[i] = '\0'; + char * second_part = &world.windb.order[i + 1]; + sprintf(new_order, "%s%s", world.windb.order, second_part); + free(world.windb.order); + world.windb.order = new_order; + world.windb.active = world.windb.order[i]; + if (!world.windb.order[i] && 0 < i) + { + world.windb.active = world.windb.order[i - 1]; + } + if (world.windb.order[i]) + { + update_wins(get_win_by_id(next_char)); /* Already calls */ + return; /* refit_v_screen(), so leave. */ + } + refit_v_screen(); +} + + + +static void add_win_to_windb(struct Win * win) +{ + char * f_name = "add_win_to_windb()"; + if (world.windb.ids) + { + uint8_t old_ids_size = strlen(world.windb.ids); + char * new_ids = try_malloc(old_ids_size + 1 + 1, f_name); + sprintf(new_ids, "%s%c", world.windb.ids, win->id); + free(world.windb.ids); + world.windb.ids = new_ids; + uint16_t old_wins_size = old_ids_size * sizeof(struct Win); + uint16_t new_wins_size = old_wins_size + sizeof(struct Win); + struct Win * new_wins = try_malloc(new_wins_size, f_name); + memcpy(new_wins, world.windb.wins, old_wins_size); + new_wins[old_ids_size] = *win; + free(world.windb.wins); + world.windb.wins = new_wins; + return; } - else + world.windb.ids = try_malloc(2, f_name); + sprintf(world.windb.ids, "%c", win->id); + world.windb.wins = try_malloc(sizeof(struct Win), f_name); + world.windb.wins[0] = *win; +} + + + +extern uint16_t center_offset(uint16_t position, uint16_t mapsize, + uint16_t frame_size) +{ + uint16_t offset = 0; + if (mapsize > frame_size) { - struct Win * old_prev = world.wins.win_active->prev; - struct Win * old_next = world.wins.win_active->next; - if (world.wins.chain_start == world.wins.win_active->prev) - { - world.wins.chain_start = world.wins.win_active; - world.wins.win_active->prev = 0; - } - else - { - world.wins.win_active->prev = old_prev->prev; - world.wins.win_active->prev->next = world.wins.win_active; - } - if (world.wins.chain_end == world.wins.win_active) + if (position > frame_size / 2) { - world.wins.chain_end = old_prev; + if (position < mapsize - (frame_size / 2)) + { + offset = position - (frame_size / 2); + } + else + { + offset = mapsize - frame_size; + } } - else + } + return offset; +} + + + +extern struct Win * get_win_by_id(char id) +{ + uint8_t i = 0; + while ('\0' != world.windb.ids[i]) + { + if (id == world.windb.ids[i]) { - old_next->prev = old_prev; + return &world.windb.wins[i]; } - old_prev->next = old_next; - old_prev->prev = world.wins.win_active; - world.wins.win_active->next = old_prev; + i++; } + return NULL; } -extern void make_pad() +extern uint8_t read_winconf_from_file(char * line, uint32_t linemax, + FILE * file) { - char * err_s = "make_pad() creates an illegaly large virtual screen."; - char * err_m = "make_pad() triggers memory allocation error via newpad()."; - uint32_t maxy_test = getmaxy(world.wins.screen); - uint32_t maxx_test = getmaxx(world.wins.screen); - exit_err(maxy_test > UINT16_MAX || maxx_test > UINT16_MAX, err_s); - world.wins.padsize.y = maxy_test; - world.wins.padsize.x = maxx_test; - world.wins.pad = newpad(world.wins.padsize.y, 1); - exit_err(NULL == world.wins.pad, err_m); + char * f_name = "read_winconf_from_file()"; + int test = try_fgetc(file, f_name); + if (EOF == test) + { + return 0; + } + struct Win win; + win.id = (char) test; + try_fgetc(file, f_name); + try_fgets(line, linemax + 1, file, f_name); + win.title = try_malloc(strlen(line), f_name); + memcpy(win.title, line, strlen(line) - 1); /* Eliminate newline char */ + win.title[strlen(line) - 1] = '\0'; /* char at end of string. */ + try_fgets(line, linemax + 1, file, f_name); + win.target_height = atoi(line); + win.target_height_type = (0 >= win.target_height); + try_fgets(line, linemax + 1, file, f_name); + win.target_width = atoi(line); + win.target_width_type = (0 >= win.target_width); + read_keybindings_from_file(line, linemax, file, &win.kb); + win.view = 0; + win.target_center.y = 0; + win.target_center.x = 0; + win.winmap_size.y = 0; + win.winmap_size.x = 0; + win.winmap = NULL; + win.center.y = 0; + win.center.x = 0; + add_win_to_windb(&win); + return 1; } -extern void init_win(struct Win ** wp, char * title, int16_t height, - int16_t width, void * func) +extern void write_winconf_of_id_to_file(FILE * file, char c, char * delim) { - char * f_name = "init_win()"; - struct Win * w = try_malloc(sizeof(struct Win), f_name); - w->prev = 0; - w->next = 0; - w->winmapsize.y = 0; - w->winmapsize.x = 0; - w->winmap = NULL; - w->title = try_malloc(strlen(title) + 1, f_name); - sprintf(w->title, "%s", title); - w->draw = func; - w->center.y = 0; - w->center.x = 0; - w->framesize.y = world.wins.padsize.y - 1; - if (0 < height && height <= world.wins.padsize.y - 1) - { - w->framesize.y = height; - } - else if (0 > height && world.wins.padsize.y + (height - 1) > 0) - { - w->framesize.y = world.wins.padsize.y + (height - 1); - } - w->framesize.x = world.wins.padsize.x; - if (0 < width) - { - w->framesize.x = width; - } - else if (0 > width && world.wins.padsize.x + width > 0) - { - w->framesize.x = world.wins.padsize.x + width; - } - *wp = w; + char * f_name = "write_winconf_of_id_to_file()"; + struct Win * wc = get_win_by_id(c); + uint8_t size = strlen(wc->title) + 2; + if (size < 7) /* Ensure that at least 5 + 2 char fit into line so that */ + { /* the digit representation of any uint16_t may be stored. */ + size = 7; + } + char line[size]; + sprintf(line, "%c\n", wc->id); + try_fwrite(line, sizeof(char), strlen(line), file, f_name); + sprintf(line, "%s\n", wc->title); + try_fwrite(line, sizeof(char), strlen(line), file, f_name); + sprintf(line, "%d\n", wc->target_height); + try_fwrite(line, sizeof(char), strlen(line), file, f_name); + sprintf(line, "%d\n", wc->target_width); + try_fwrite(line, sizeof(char), strlen(line), file, f_name); + write_keybindings_to_file(file, &wc->kb, delim); } -extern void free_win(struct Win * win) +extern void read_order_wins_visible_active(char * line, uint32_t linemax, + FILE * file) { - free(win->title); - free(win); + char * f_name = "read_order_wins_visible_active()"; + char win_order[linemax + 1]; + try_fgets(win_order, linemax + 1, file, f_name); + win_order[strlen(win_order) - 1] = '\0'; + world.windb.order = try_malloc(strlen(win_order) + 1, f_name); + sprintf(world.windb.order, "%s", win_order); + int char_or_eof = try_fgetc(file, f_name); + char * err_eof = "fgetc() unexpectedly hitting EOF"; + exit_trouble(EOF == char_or_eof, f_name, err_eof); + world.windb.active = (uint8_t) char_or_eof; + exit_trouble(EOF == try_fgetc(file, f_name), f_name, err_eof); + try_fgets(line, linemax + 1, file, f_name); } -extern void append_win(struct Win * w) +extern void write_order_wins_visible_active(FILE * file, char * delim) { - if (0 != world.wins.chain_start) - { - w->prev = world.wins.chain_end; - world.wins.chain_end->next = w; + char * f_name = "write_order_wins_visible_active()"; + try_fwrite(world.windb.order, strlen(world.windb.order), 1, file, f_name); + try_fputc('\n', file, f_name); + try_fputc(world.windb.active, file, f_name); + try_fputc('\n', file, f_name); + try_fwrite(delim, strlen(delim), 1, file, f_name); +} + + + +extern void make_v_screen_and_init_win_sizes() +{ + char * f_name = "make_v_screen_and_init_win_sizes()"; + char * err_s = "creating an illegaly large virtual screen"; + char * err_m = "triggering a memory allocation error via newpad()"; + uint32_t maxy_test = getmaxy(world.windb.t_screen); + uint32_t maxx_test = getmaxx(world.windb.t_screen); + exit_trouble(maxy_test>UINT16_MAX || maxx_test>UINT16_MAX, f_name, err_s); + world.windb.v_screen_size.y = maxy_test; + world.windb.v_screen_size.x = maxx_test; + world.windb.v_screen = newpad(world.windb.v_screen_size.y, 1); + exit_trouble(NULL == world.windb.v_screen, f_name, err_m); + char id; + while (0 != (id = get_next_win_id())) + { + init_win_size_from_winconf_and_v_screen_size(id); } - else - { - world.wins.win_active = w; - world.wins.chain_start = w; +} + + + +extern void free_windb() +{ + char id; + while (0 != (id = get_next_win_id())) + { + struct Win * wc = get_win_by_id(id); + free(wc->title); + free_keybindings(wc->kb.kbs); + } + free(world.windb.ids); + world.windb.ids = NULL; + free(world.windb.wins); + world.windb.wins = NULL; + free(world.windb.order); + world.windb.order = NULL; +} + + + +extern void winch_called(int signal) +{ + world.winch = 1; +} + + + +extern void reset_windows_on_winch() +{ + endwin(); /* "[S]tandard way" to recalibrate ncurses post SIGWINCH, says */ + refresh(); /* . */ + char tmp_order[strlen(world.windb.order) + 1]; + sprintf(tmp_order, "%s", world.windb.order); + uint8_t i; + char tmp_active = world.windb.active; + for (i = 0; i < strlen(tmp_order); toggle_window(tmp_order[i]), i++); + delwin(world.windb.v_screen); + make_v_screen_and_init_win_sizes(); + for (i = 0; i < strlen(tmp_order); toggle_window(tmp_order[i]), i++); + world.windb.active = tmp_active; +} + + + +extern void draw_all_wins() +{ + /* Empty everything before filling it a-new. */ + erase(); + wnoutrefresh(world.windb.t_screen); + werase(world.windb.v_screen); + if (world.windb.active) + { + + /* Draw borders, wins. Order matters: corners should overwrite lines. */ + draw_wins_borderlines(get_win_by_id(world.windb.order[0])); + draw_wins_bordercorners(get_win_by_id(world.windb.order[0])); + draw_wins(get_win_by_id(world.windb.order[0])); + + /* Draw .v_screen scroll hints. */ + struct yx_uint16 start; + start.y = 0; + start.x = world.windb.v_screen_offset; + char * cols_string = "columns"; + if (world.windb.v_screen_offset > 0) + { + scroll_hint(world.windb.v_screen_size, '<', + world.windb.v_screen_offset + 1, cols_string, start); + } + uint16_t size_x = getmaxx(world.windb.v_screen); + uint16_t right_edge = world.windb.v_screen_offset + + world.windb.v_screen_size.x; + if (right_edge < size_x - 1) + { + scroll_hint(world.windb.v_screen_size, '>', + size_x - right_edge, cols_string, start); + } + + /* Put .v_screen segment to be shown on .t_screen to .t_screen buffer.*/ + pnoutrefresh(world.windb.v_screen, 0, world.windb.v_screen_offset, 0, 0, + world.windb.v_screen_size.y, + world.windb.v_screen_size.x - 1); } - world.wins.chain_end = w; - update_wins(w); + + /* Only at the end write accumulated changes to .t_screen. */ + doupdate(); } -extern void suspend_win(struct Win * w) +extern void toggle_window(char id) { - if (world.wins.chain_start != w) + struct Win * win = get_win_by_id(id); + if (NULL == strchr(world.windb.order, id)) { - w->prev->next = w->next; + append_win(win); + return; } - else + suspend_win(win); +} + + + +extern void toggle_winconfig() +{ + if (!world.windb.active) { - world.wins.chain_start = w->next; + return; } - uint8_t pad_refitted = 0; - if (world.wins.chain_end != w) + struct Win * w = get_win_by_id(world.windb.active); + if (0 == w->view) { - w->next->prev = w->prev; - if (world.wins.win_active == w) - { - world.wins.win_active = w->next; - } - update_wins(w->next); /* Positioning of successor windows may be */ - pad_refitted = 1; /* affected / need correction. Note that */ - } /* update_wins() already refits the pad, */ - else /* voiding later need for that. */ - { - world.wins.chain_end = w->prev; - if (world.wins.win_active == w) - { - world.wins.win_active = w->prev; - } + w->view = 1; + w->target_center = w->center; + w->center.y = 0; + w->center.x = 0; + return; } - w->prev = 0; - w->next = 0; - if (0 == pad_refitted) + else if (1 == w->view) { - refit_pad(); + w->view = 2; + w->center.x = 0; + return; } + w->view = 0; + w->center = w->target_center; } -extern void reset_pad_offset(uint16_t new_offset) +extern void toggle_win_size_type(char axis) { - if (new_offset >= 0 - && (new_offset < world.wins.pad_offset - || new_offset + world.wins.padsize.x < getmaxx(world.wins.pad))) + struct Win * w = get_win_by_id(world.windb.active); + if ('y' == axis) { - world.wins.pad_offset = new_offset; + w->target_height_type = (0 == w->target_height_type); + set_win_target_size(w); + return; } + w->target_width_type = ( 0 == w->target_width_type + && w->frame_size.x <= world.windb.v_screen_size.x); + set_win_target_size(w); } -extern void resize_active_win(struct yx_uint16 size) +extern void resize_active_win(char change) { - if (0 != world.wins.win_active - && size.x > 0 && size.y > 0 && size.y < world.wins.padsize.y) + if (world.windb.active) { - world.wins.win_active->framesize = size; - update_wins(world.wins.win_active); /* Positioning of following */ - } /* windows may be affected. */ + struct Win * w = get_win_by_id(world.windb.active); + if (change == '-' && w->frame_size.y > 1) + { + w->frame_size.y--; + } + else if (change == '_' && w->frame_size.y > 1) + { + w->frame_size.x--; + } + else if ( change == '+' + && w->frame_size.y < world.windb.v_screen_size.y - 1) + { + w->frame_size.y++; + } + else if (change == '*' && w->frame_size.y < UINT16_MAX) + { + w->frame_size.x++; + } + if ( 1 == w->target_width_type + && w->frame_size.x > world.windb.v_screen_size.x) + { + w->target_width_type = 0; + } + set_win_target_size(w); + update_wins(w); + } } -extern void cycle_active_win(char dir) +extern void shift_active_win(char dir) { - if (0 != world.wins.win_active) + uint8_t len_order = strlen(world.windb.order); + if (1 < len_order) { + char tmp[len_order + 1]; + tmp[len_order] = '\0'; + uint8_t pos = get_pos_in_order(world.windb.active); if ('f' == dir) { - if (world.wins.win_active->next != 0) + if (pos == len_order - 1) { - world.wins.win_active = world.wins.win_active->next; + memcpy(tmp + 1, world.windb.order, len_order - 1); + tmp[0] = world.windb.active; + memcpy(world.windb.order, tmp, len_order + 1); } else { - world.wins.win_active = world.wins.chain_start; + world.windb.order[pos] = world.windb.order[pos + 1]; + world.windb.order[pos + 1] = world.windb.active; } } else { - if (world.wins.win_active->prev != 0) + if (pos == 0) { - world.wins.win_active = world.wins.win_active->prev; + memcpy(tmp, world.windb.order + 1, len_order - 1); + tmp[len_order - 1] = world.windb.active; + memcpy(world.windb.order, tmp, len_order + 1); } else { - world.wins.win_active = world.wins.chain_end; + world.windb.order[pos] = world.windb.order[pos - 1]; + world.windb.order[pos - 1] = world.windb.active; } } + update_wins(get_win_by_id(world.windb.order[0])); } } -extern void shift_active_win(char dir) +extern void scroll_v_screen(char dir) { - if ( 0 == world.wins.win_active /* No shifting with <2 windows visible. */ - || world.wins.chain_start == world.wins.chain_end) + if ( '+' == dir + && world.windb.v_screen_offset + world.windb.v_screen_size.x + 1 + < getmaxx(world.windb.v_screen)) { - return; + world.windb.v_screen_offset++; } - if ('f' == dir) + else if ( '-' == dir + && world.windb.v_screen_offset > 0) { - shift_win_forward(); - update_wins(world.wins.chain_start); - return; + world.windb.v_screen_offset--; } - shift_win_backward(); - update_wins(world.wins.chain_start); } -extern void draw_all_wins() +extern void cycle_active_win(char dir) { - /* Empty everything before filling it a-new. */ - erase(); - wnoutrefresh(world.wins.screen); - werase(world.wins.pad); - if (world.wins.chain_start) + uint8_t len_order = strlen(world.windb.order); + if (1 < len_order) { - - /* Draw windows' borders first, then windows. */ - draw_wins_borderlines(world.wins.chain_start); - draw_wins_bordercorners(world.wins.chain_start); - draw_wins(world.wins.chain_start); - - /* Draw virtual screen scroll hints. */ - if (world.wins.pad_offset > 0) + uint8_t pos = get_pos_in_order(world.windb.active); + if ('f' == dir) { - padscroll_hint('<', world.wins.pad_offset + 1); + world.windb.active = world.windb.order[pos + 1]; + if ('\0' == world.windb.active) + { + world.windb.active = world.windb.order[0]; + } + return; } - uint16_t size_x = getmaxx(world.wins.pad); - uint16_t right_edge = world.wins.pad_offset + world.wins.padsize.x; - if (right_edge < size_x - 1) + if (pos > 0) { - padscroll_hint('>', size_x - right_edge); + world.windb.active = world.windb.order[pos - 1]; + return; } - - /* Write pad segment to be shown on physical screen to screen buffer. */ - pnoutrefresh(world.wins.pad, 0, world.wins.pad_offset, 0, 0, - world.wins.padsize.y, world.wins.padsize.x - 1); + world.windb.active = world.windb.order[len_order - 1]; } - - /* Only at the end write accumulated changes to the physical screen. */ - doupdate(); } diff --git a/src/client/windows.h b/src/client/windows.h index 2f82667..d8da5be 100644 --- a/src/client/windows.h +++ b/src/client/windows.h @@ -24,91 +24,123 @@ #ifndef WINDOWS_H #define WINDOWS_H -#include /* chtype */ -#include /* uint16_t, int16_t */ +#include /* WINDOW, chtype */ +#include /* uint8_t, int16_t, uint16_t */ +#include "keybindings.h" /* struct KeyBindingDB */ #include "../common/yx_uint16.h" /* yx_uint16 struct */ -/* "Win" structs describe windows as frames located inside the virtual screen - * pad through which "winmaps" are visible, 2-dimensional maps of ncurses - * chtypes. If a winmap is bigger than its frame, scrolling hints will appear at - * the proper edges. Win structs are chained into a linked list of all the - * windows visible on the virtual screen and also contain pointers to what - * content is to be drawn inside the window, and by use of what method. - */ -struct Win +struct WinDB { - 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 framesize; /* window frame size to see winmap through */ - struct yx_uint16 start; /* upper left corner of window in pad */ - struct yx_uint16 center; /* winmap cell to center frame on if smaller*/ - char * title; /* title to be used in window title bar */ - void (* draw) (struct Win *); /* function that draws/updates the winmap */ - chtype * winmap; /* sequence of cells, sorted into lines ... */ - struct yx_uint16 winmapsize; /* ... with these geometry infos */ + WINDOW * t_screen; /* ncurses' pointer to the terminal screen */ + WINDOW * v_screen; /* virtual screen (ncurses pad) */ + struct Win * wins; /* array of windows */ + struct yx_uint16 v_screen_size; /* virtual screen size */ + char * ids; /* all windows' ids, followed by \0 */ + char * order; /* visible windows' id's order, followed by \0 */ + uint16_t v_screen_offset; /* how many cells v_screen view moved rightwards*/ + char active; /* id of window selected as active */ }; +struct Win +{ + struct KeyBindingDB kb; /* window-specific keybindings */ + char * title; /* title to be used in window title bar */ + struct yx_uint16 target_center; /* saves .center when toggling .view */ + struct yx_uint16 frame_size; /* size of window/frame to see winmap through*/ + struct yx_uint16 start; /* upper left corner of window in v_screen */ + struct yx_uint16 center; /* winnap cell to center frame on if < winmap */ + struct yx_uint16 winmap_size; /* delimits .winmap, sorts it into lines */ + chtype * winmap; /* window content in sequence of chtype's to write */ + int16_t target_height; /* window size / .frame_size description in config */ + int16_t target_width; /* file format, i.e. values <= 0 may be used */ + char id; /* Win identifier; also maps to default window drawing function. */ + uint8_t target_height_type; /* 0: read .height/.width as positive size; */ + uint8_t target_width_type; /* 1: as negative diff to v_screen size */ + uint8_t view; /* winde view mode: 0: use default draw function set by .id */ +}; /* 1/2: use one of the two config view draw function */ + + + +/* Return yx offset to focus map of "mapsize" on "position" in "frame_size". */ +extern uint16_t center_offset(uint16_t position, + uint16_t mapsize, uint16_t frame_size); + +/* Get Win of "id". */ +extern struct Win * get_win_by_id(char id); + +/* Read/write individual Win (identified by "c") and world.windb.order / + * world.windb.active from/to "file". Follow writing with "delim" delimiter. + * Use "line" and "linemax" as expected by try_fgets(). + */ +extern uint8_t read_winconf_from_file(char * line, uint32_t linemax, + FILE * file); +extern void write_winconf_of_id_to_file(FILE * file, char c, char * delim); +extern void read_order_wins_visible_active(char * line, uint32_t linemax, + FILE * file); +extern void write_order_wins_visible_active(FILE * file, char * delim); + +/* Builds virtual sreen from .t_screen's size, fits win's sizes to them.*/ +extern void make_v_screen_and_init_win_sizes(); + +/* Free all WinDB data. */ +extern void free_windb(); + +/* The SIGWINCH handler winch_called() merely sets world.winch to 1. This info + * is used by io_loop() to call reset_windows_on_winch(), which adapts the + * currently loaded interface configuration to the new .t_screen size. + */ +extern void winch_called(); +extern void reset_windows_on_winch(); +/* Draw .v_screen and its windows. Add scroll hints where edges of .t_screen hit + * .non-edges inside the virtual screen. Then update .t_screen. + */ +extern void draw_all_wins(); -/* Builds world.wins.pad from the sizes of the current terminal screen. */ -extern void make_pad(); +/* Toggle display of a window of "id". */ +extern void toggle_window(char id); -/* Initialize a Win at "wp" to "title", "height" and "width" and appoint - * "func"() as its .draw. Initialize other members to 0. - * - * Pass 0 for "width" to make the window as wide as the terminal screen. Pass 0 - * for "height" for the maximum allowed height: one cell smaller than that of - * the terminal screen. Pass negative values for either of them to make the - * window width/height so many cells smaller than what 0 would set. Values that - * that would reduce the window height or width to less than 1 cell according to - * the aforementioned rules set the height/width as if they were set to 0. +/* Toggle "window configuration" view for active window. Sets sensible .center + * values for each configuration view (for winconf_geometry: y=0, x=0; for + * winconf_keys: x=0 (y is set by draw_winconf_keybindings()); stores default + * view's .center in .target_center to return to it when toggling back. */ -extern void init_win(struct Win ** wp, char * title, int16_t height, - int16_t width, void * func); +extern void toggle_winconfig(); -/* Free memory initianized Win structs. */ -extern void free_win(struct Win * win); +/* Toggle active window's .target_(height/width)_type ("axis" = "y": height; + * else: width). Don't toggle to .target_width_type of 1 (saving the width as a + * diff to the .t_screen's width) if window's width is larger than .t_screen's + * width, for such width is better saved directly with .target_width_type of 0. + */ +extern void toggle_win_size_type(char axis); -/* Append/suspend window "w" to/from chain of visible windows. Appended windows - * will become active. Suspended active windows will move the active window - * selection to their successor in the window chain or, failing that, their - * predecessor, or, failing that, to 0 (no window active). +/* Grow or shrink active window horizontally ("change" = "*"/"_") or vertically + * ("change" = "+"/"-") if the new size was at least 1x1, the height at least + * one cell smaller than .v_screen's vertical hight (to provide space for the + * title bar) and the width max. (2^16) - 1 cells. If a new window width would + * surpass that of .t_screen, set active window's .target_width_type to 0. */ -extern void append_win(struct Win * w); -extern void suspend_win(struct Win * w); +extern void resize_active_win(char c); -/* Apply scrolling offset "new_offset" to virtual screen if it is equal/greater - * 0 and does not push the view (further) beyond the virtual screen's border. If - * the view is already beyond the virtual screen's border due to it having - * shrunk after suspension of windows, only allow screen scrolling leftwards. +/* Move active window forwards ("dir" == "f") or backwards (any other "dir") in + * window chain. Wrap around in the window chain if start / end of it is met. */ -extern void reset_pad_offset(uint16_t new_offset); +extern void shift_active_win(char dir); -/* Apply "size" to the active window if it provides a minimum size of 1x1 cells - * and is in height at least one cell smaller than the screen's vertical height - * (to provide space for the title bar). Does nothing if no window is active. +/* Sroll .v_screen one cell to the left if "dir" is "-" and .v_screen_offset is + * more than 1, or to the right if "dir" is "+" and .v_screen's right edge would + * not move (further, if suspension of windows has moved it to the left already) + * leftwards to .t_screen's right edge. */ -extern void resize_active_win(struct yx_uint16 size); +extern void scroll_v_screen(char dir); /* Cycle active window selection forwards ("dir" == "f") or backwards (any * other "dir"). Wrap around in the windows chain if start / end of it is met. - * Does nothing if no window is active. */ extern void cycle_active_win(char dir); -/* Move active window forwards ("dir" == "f") or backwards (any other "dir") in - * the window chain. Wrap around in the window chain if start / end of it is - * met. Does nothing if no window is active. - */ -extern void shift_active_win(char dir); - -/* Draw virtual screen and its windows. Add scroll hints where edges of terminal - * screen hit non-edges inside the virtual screen. Then update terminal screen. - */ -extern void draw_all_wins(); - #endif diff --git a/src/client/world.h b/src/client/world.h index fb8ae4d..9e07efa 100644 --- a/src/client/world.h +++ b/src/client/world.h @@ -12,13 +12,13 @@ #include "../common/yx_uint16.h" /* struct yx_uint16 */ #include "keybindings.h" /* stuct KeyBindingDB */ #include "command_db.h" /* struct CommandDB */ -#include "wincontrol.h" /* WinConfDB */ +#include "windows.h" /* WinDB */ struct World { - struct WinConfDB wins; + struct WinDB windb; struct CommandDB cmd_db; /* Command database. */ struct KeyBindingDB kb_global; /* Global keybindings. */ struct KeyBindingDB kb_wingeom; /* Window geometry config keybindings. */