home · contact · privacy
Overhauled large parts of window system to universalize scroll hints.
authorChristian Heller <c.heller@plomlompom.de>
Mon, 21 Oct 2013 01:57:15 +0000 (03:57 +0200)
committerChristian Heller <c.heller@plomlompom.de>
Mon, 21 Oct 2013 01:57:15 +0000 (03:57 +0200)
config/windows/toggle_order_and_active
src/control.c
src/draw_wins.c
src/main.c
src/map.c
src/map.h
src/map_object_actions.h
src/wincontrol.c
src/wincontrol.h
src/windows.c
src/windows.h

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