kmicl
-m
\ No newline at end of file
+m
#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(),
}
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"))
{
#include <stdlib.h> /* for free() */
#include <stdint.h> /* for uint16_t */
#include <string.h> /* for strlen() */
-#include <ncurses.h> /* for mvwaddch() */
-#include "windows.h" /* for structs Win, Frame, for draw_scroll_hint() */
-#include "misc.h" /* for center_offset(), try_malloc() */
+#include <ncurses.h> /* 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". */
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);
+ }
+}
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;
}
}
}
-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
{
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);
}
}
}
-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)
}
}
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))
{
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;
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);
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;
}
{
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);
}
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;
}
#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()
/* 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;
#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;
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;
-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);
-}
#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 */
};
* 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);
/* 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);
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);
}
}
{
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;
}
}
#include <stdint.h> /* 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;
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 */
-/* 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.
*/
#include "windows.h"
#include <stdint.h> /* for uint8_t, uint16_t, uint32_t, UINT16_MAX */
#include <ncurses.h> /* 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 <stdlib.h> /* for malloc(), free() */
#include <string.h> /* 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() */
-/* 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);
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);
/* 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)
{
}
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
-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;
}
}
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;
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);
}
extern uint8_t suspend_win(struct WinMeta * wmeta, struct Win * w)
{
- destroy_win(w);
-
if (wmeta->chain_start != w)
{
w->prev->next = w->next;
-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;
-}
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;
* 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,
-/* 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);
-/* 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);