home · contact · privacy
Restructured source tree. Code moves to src/, object files to build/.
authorChristian Heller <c.heller@plomlompom.de>
Wed, 19 Jun 2013 03:22:21 +0000 (05:22 +0200)
committerChristian Heller <c.heller@plomlompom.de>
Wed, 19 Jun 2013 03:22:21 +0000 (05:22 +0200)
21 files changed:
Makefile
draw_wins.c [deleted file]
draw_wins.h [deleted file]
keybindings.c [deleted file]
keybindings.h [deleted file]
readwrite.c [deleted file]
readwrite.h [deleted file]
roguelike.c [deleted file]
roguelike.h [deleted file]
src/draw_wins.c [new file with mode: 0644]
src/draw_wins.h [new file with mode: 0644]
src/keybindings.c [new file with mode: 0644]
src/keybindings.h [new file with mode: 0644]
src/readwrite.c [new file with mode: 0644]
src/readwrite.h [new file with mode: 0644]
src/roguelike.c [new file with mode: 0644]
src/roguelike.h [new file with mode: 0644]
src/windows.c [new file with mode: 0644]
src/windows.h [new file with mode: 0644]
windows.c [deleted file]
windows.h [deleted file]

index bedecc0347db339e26f8f7a35a48db37bf3a1fc9..69eb0a95ccde9d7698faaa99a7e196cdcb0971e0 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,15 +1,19 @@
 CC=cc
 CFLAGS=-Wall -g
 TARGET=roguelike
-SOURCES=$(shell find . -type f -name \*.c)
-OBJECTS=$(SOURCES:.c=.o)
+SRCDIR=src
+BUILDDIR=build
+SOURCES=$(shell find $(SRCDIR)/ -type f -name \*.c)
+OBJECTS=$(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES:.c=.o))
 
 roguelike: $(OBJECTS)
        $(CC) $(CFLAGS) -o roguelike $(OBJECTS) -lncurses
 
-%.o: %.c
-       $(CC) $(CFLAGS) -c $< -o $@
+$(BUILDDIR)/%.o: $(SRCDIR)/%.c
+       mkdir -p $(BUILDDIR); $(CC) $(CFLAGS) -c $< -o $@
 
 .PHONY: clean
 clean:
-       rm $(OBJECTS); rm roguelike
+       rm $(OBJECTS)
+       rmdir $(BUILDDIR)
+       rm $(TARGET)
diff --git a/draw_wins.c b/draw_wins.c
deleted file mode 100644 (file)
index 818037a..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-#include <stdlib.h>
-#include <stdint.h>
-#include <ncurses.h>
-#include <string.h>
-#include "windows.h"
-#include "draw_wins.h"
-#include "roguelike.h"
-#include "keybindings.h"
-
-void draw_with_linebreaks (struct Win * win, char * text, uint16_t start_y) {
-// Write text into window content space. Start on row start_y. Fill unused rows with whitespace.
-  uint16_t x, y;
-  char toggle;
-  char fin = 0;
-  int16_t z = -1;
-  for (y = start_y; y < win->frame.size.y; y++) {
-    if (0 == fin)
-      toggle = 0;
-    for (x = 0; x < win->frame.size.x; x++) {
-       if (0 == toggle) {
-         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; } } } } }
-
-void draw_text_from_bottom (struct Win * win, char * text) {
-// Draw text from end/bottom to the top.
-  char toggle = 0;
-  uint16_t x, y, offset;
-  int16_t z = -1;
-  for (y = 0; 0 == toggle; y++)                           // Determine number of lines text would have in
-    for (x = 0; x < win->frame.size.x; x++) {             // a window of available width, but infinite height.
-      z++;
-      if ('\n' == text[z])            // Treat \n and \0 as control characters for incrementing y and stopping
-        break;                        // the loop. Make sure they don't count as cell space themselves.
-      if ('\n' == text[z+1]) {
-        z++;
-        break; }
-      else if (0 == text[z+1]) {
-        toggle = 1;
-        break; } }
-  z = -1;
-  uint16_t start_y = 0;
-  if (y < win->frame.size.y)       // Depending on what is bigger, determine start point in window or in text.
-    start_y = win->frame.size.y - y;
-  else if (y > win->frame.size.y) {
-    offset = y - win->frame.size.y;
-    for (y = 0; y < offset; y++)
-      for (x = 0; x < win->frame.size.x; x++) {
-        z++;
-        if ('\n' == text[z])
-          break;
-        if ('\n' == text[z+1]) {
-          z++;
-          break; } }
-    text = text + (sizeof(char) * (z + 1)); }
-  draw_with_linebreaks(win, text, start_y); }
-
-void draw_log_win (struct Win * win) {
-// Draw log text from world struct in win->data from bottom to top.
-  struct World * world = (struct World *) win->data;
-  draw_text_from_bottom(win, world->log); }
-
-void draw_map_win (struct Win * win) {
-// Draw map determined by win->data Map struct into window. Respect offset.
-  struct World * world = (struct World *) win->data;
-  struct Map * map = world->map;
-  struct Player * player = world->player;
-  struct Monster * monster = world->monster;
-  char * cells = map->cells;
-  uint16_t width_map_av = map->width - map->offset_x;
-  uint16_t height_map_av = map->height - map->offset_y;
-  uint16_t x, y, z;
-  for (y = 0; y < win->frame.size.y; y++) {
-    z = map->offset_x + (map->offset_y + y) * (map->width);
-    for (x = 0; x < win->frame.size.x; x++) {
-      if (y < height_map_av && x < width_map_av) {
-        if (z == (map->width * player->y) + player->x)
-          mvwaddch(win->frame.curses_win, y, x, '@');
-        else if (z == (map->width * monster->y) + monster->x)
-          mvwaddch(win->frame.curses_win, y, x, 'M');
-        else
-          mvwaddch(win->frame.curses_win, y, x, cells[z]);
-        z++; } } } }
-
-void draw_info_win (struct Win * win) {
-// Draw info window by appending win->data integer value to "Turn: " display.
-  struct World * world = (struct World *) win->data;
-  uint16_t count = world->turn;
-  char text[100];
-  snprintf(text, 100, "Turn: %d", count);
-  draw_with_linebreaks(win, text, 0); }
-
-void draw_keys_win (struct Win * win) {
-// Draw keybindings window.
-  struct World * world = (struct World *) win->data;
-  uint16_t offset = 0, y, x;
-  if (world->keyswindata->max >= win->frame.size.y) {
-    if (world->keyswindata->select > win->frame.size.y / 2) {
-      if (world->keyswindata->select < (world->keyswindata->max - (win->frame.size.y / 2)))
-        offset = world->keyswindata->select - (win->frame.size.y / 2);
-      else
-        offset = world->keyswindata->max - win->frame.size.y + 1; } }
-  uint8_t keydescwidth = 9 + 1; // max length assured by get_keyname() + \0
-  char * keydesc = malloc(keydescwidth), * keyname;
-  attr_t attri;
-  for (y = 0; y <= world->keyswindata->max && y < win->frame.size.y; y++) {
-    if (0 == y && offset > 0) {
-      draw_scroll_hint(&win->frame, y, offset + 1, '^');
-      continue; }
-    else if (win->frame.size.y == y + 1 && 0 < world->keyswindata->max - (win->frame.size.y + offset - 1)) {
-      draw_scroll_hint(&win->frame, y, world->keyswindata->max - (offset + win->frame.size.y) + 2, 'v');
-      continue; }
-    attri = 0;
-    if (y == world->keyswindata->select - offset) {
-      attri = A_REVERSE;
-      if (1 == world->keyswindata->edit)
-        attri = attri | A_BLINK; }
-    keyname = get_keyname(world->keybindings[y + offset].key);
-    snprintf(keydesc, keydescwidth, "%-9s", keyname);
-    free(keyname);
-    for (x = 0; x < win->frame.size.x; x++)
-      if (x < strlen(keydesc))
-        mvwaddch(win->frame.curses_win, y, x, keydesc[x] | attri);
-      else if (strlen(keydesc) < x && x < strlen(world->keybindings[y + offset].name) + strlen(keydesc) + 1)
-        mvwaddch(win->frame.curses_win, y, x,
-                 world->keybindings[y + offset].name[x - strlen(keydesc) - 1] | attri);
-      else
-        mvwaddch(win->frame.curses_win, y, x, ' ' | attri); }
-  free(keydesc); }
diff --git a/draw_wins.h b/draw_wins.h
deleted file mode 100644 (file)
index 64f332c..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-void draw_with_linebreaks (struct Win *, char *, uint16_t);
-void draw_text_from_bottom (struct Win *, char *);
-void draw_log_win (struct Win *);
-void draw_map_win (struct Win *);
-void draw_info_win (struct Win *);
-void draw_keys_win (struct Win *);
diff --git a/keybindings.c b/keybindings.c
deleted file mode 100644 (file)
index b6ff412..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-#include <stdlib.h>
-#include <stdint.h>
-#include <ncurses.h>
-#include <string.h>
-#include "windows.h"
-#include "roguelike.h"
-#include "keybindings.h"
-
-void init_keybindings(struct World * world) {
-// Initialize keybindings from file "keybindings".
-  FILE * file = fopen("keybindings", "r");
-  uint16_t lines = 0;
-  int c = 0;
-  uint16_t linemax = 0;
-  uint16_t c_count = 0;
-  while (EOF != c) {
-    c_count++;
-    c = getc(file);
-    if ('\n' == c) {
-      if (c_count > linemax)
-        linemax = c_count + 1;
-      c_count = 0;
-      lines++; } }
-  struct KeyBinding * keybindings = malloc(lines * sizeof(struct KeyBinding));
-  fseek(file, 0, SEEK_SET);
-  char * command = malloc(linemax);
-  uint16_t commcount = 0;
-  char * cmdptr;
-  while (fgets(command, linemax, file)) {
-    keybindings[commcount].key = atoi(command);
-    cmdptr = strchr(command, ' ') + 1;
-    keybindings[commcount].name = malloc(strlen(cmdptr));
-    memcpy(keybindings[commcount].name, cmdptr, strlen(cmdptr) - 1);
-    keybindings[commcount].name[strlen(cmdptr) - 1] = '\0';
-    commcount++; }
-  free(command);
-  fclose(file);
-  struct KeysWinData * keyswindata = malloc(sizeof(struct KeysWinData));
-  keyswindata->max = lines - 1;
-  keyswindata->select = 0;
-  keyswindata->edit = 0;
-  world->keybindings = keybindings;
-  world->keyswindata = keyswindata; }
-
-void save_keybindings(struct World * world) {
-// Write keybindings to keybindings file.
-  struct KeysWinData * keyswindata = (struct KeysWinData *) world->keyswindata;
-  struct KeyBinding * keybindings = world->keybindings;
-  FILE * file = fopen("keybindings", "w");
-  uint16_t linemax = 0;
-  uint16_t i;
-  for (i = 0; i <= keyswindata->max; i++)
-    if (strlen(keybindings[i].name) > linemax)
-      linemax = strlen(keybindings[i].name);
-  linemax = linemax + 6;                                // + 6 = + 3 digits + whitespace + newline + null byte
-  char * line = malloc(linemax);
-  for (i = 0; i <= keyswindata->max; i++) {
-    snprintf(line, linemax, "%d %s\n", keybindings[i].key, keybindings[i].name);
-    fwrite(line, sizeof(char), strlen(line), file); }
-  free(line);
-  fclose(file); }
-
-uint16_t get_action_key (struct KeyBinding * keybindings, char * name) {
-// Return key matching name in keybindings.
-  uint16_t i = 0;
-  while (strcmp(keybindings[i].name, name) )
-    i++;
-  return keybindings[i].key; }
-
-char * get_keyname(uint16_t keycode) {
-// Translate some keycodes to readable names of max 9 chars.
-  char * keyname;
-  keyname = malloc(15);
-  if (32 < keycode && keycode < 127)
-    sprintf(keyname, "%c", keycode);
-  else if (keycode == 9)
-    sprintf(keyname, "TAB");
-  else if (keycode == 10)
-    sprintf(keyname, "RETURN");
-  else if (keycode == 27)
-    sprintf(keyname, "ESCAPE");
-  else if (keycode == 32)
-    sprintf(keyname, "SPACE");
-  else if (keycode == KEY_UP)
-    sprintf(keyname, "UP");
-  else if (keycode == KEY_DOWN)
-    sprintf(keyname, "DOWN");
-  else if (keycode == KEY_LEFT)
-    sprintf(keyname, "LEFT");
-  else if (keycode == KEY_RIGHT)
-    sprintf(keyname, "RIGHT");
-  else if (keycode == KEY_HOME)
-    sprintf(keyname, "HOME");
-  else if (keycode == KEY_BACKSPACE)
-    sprintf(keyname, "BACKSPACE");
-  else if (keycode >= KEY_F0 && keycode <= KEY_F(63)) {
-    uint16_t f = keycode - KEY_F0;
-    sprintf(keyname, "F%d", f); }
-  else if (keycode == KEY_DC)
-    sprintf(keyname, "DELETE");
-  else if (keycode == KEY_IC)
-    sprintf(keyname, "INSERT");
-  else if (keycode == KEY_NPAGE)
-    sprintf(keyname, "NEXT PAGE");
-  else if (keycode == KEY_PPAGE)
-    sprintf(keyname, "PREV PAGE");
-  else if (keycode == KEY_END)
-    sprintf(keyname, "END");
-  else
-    sprintf(keyname, "(unknown)");
-  return keyname;  }
-
-void keyswin_mod_key (struct World * world, struct WinMeta * win_meta) {
-// In keybindings window, mark selection modifiable, modify key. Ensure max of three digits in key code field.
-  world->keyswindata->edit = 1;
-  draw_all_wins (win_meta);
-  int key = getch();
-  if (key < 1000)
-    world->keybindings[world->keyswindata->select].key = key;
-  world->keyswindata->edit = 0; }
-
-void keyswin_move_selection (struct World * world, char dir) {
-// In keybindings window, move selection upwards or downwards (if within limits of list length).
-  if ('u' == dir && world->keyswindata->select > 0)
-    world->keyswindata->select--;
-  else if ('d' == dir && world->keyswindata->select < world->keyswindata->max)
-    world->keyswindata->select++; }
diff --git a/keybindings.h b/keybindings.h
deleted file mode 100644 (file)
index b0ff912..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-struct KeyBinding {
-  char * name;
-  uint16_t key; };
-
-struct KeysWinData {
-  uint16_t max;
-  char edit;
-  uint16_t select; };
-
-void init_keybindings(struct World *);
-void save_keybindings(struct World *);
-uint16_t get_action_key (struct KeyBinding *, char *);
-char * get_keyname(uint16_t);
-void keyswin_mod_key (struct World *, struct WinMeta *);
-void keyswin_move_selection (struct World *, char);
diff --git a/readwrite.c b/readwrite.c
deleted file mode 100644 (file)
index ed5a3a3..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-#include <stdio.h>
-#include <limits.h>
-#include <stdint.h>
-
-uint16_t read_uint16_bigendian(FILE * file) {
-// Read uint16 from file in big-endian order.
-  const uint16_t nchar = UCHAR_MAX + 1;
-  unsigned char a = fgetc(file);
-  unsigned char b = fgetc(file);
-  return (a * nchar) + b; }
-
-void write_uint16_bigendian(uint16_t x, FILE * file) {
-// Write uint16 to file in beg-endian order.
-  const uint16_t nchar = UCHAR_MAX + 1;
-  unsigned char a = x / nchar;
-  unsigned char b = x % nchar;
-  fputc(a, file);
-  fputc(b, file); }
-
-uint32_t read_uint32_bigendian(FILE * file) {
-// Read uint32 from file in big-endian order.
-  const uint16_t nchar = UCHAR_MAX + 1;
-  unsigned char a = fgetc(file);
-  unsigned char b = fgetc(file);
-  unsigned char c = fgetc(file);
-  unsigned char d = fgetc(file);
-  return (a * nchar * nchar * nchar) + (b * nchar * nchar) + (c * nchar) + d; }
-
-void write_uint32_bigendian(uint32_t x, FILE * file) {
-// Write uint32 to file in beg-endian order.
-  const uint16_t nchar = UCHAR_MAX + 1;
-  unsigned char a = x / (nchar * nchar * nchar);
-  unsigned char b = (x - (a * nchar * nchar * nchar)) / (nchar * nchar);
-  unsigned char c = (x - ((a * nchar * nchar * nchar) + (b * nchar * nchar))) / nchar;
-  unsigned char d = x % nchar;
-  fputc(a, file);
-  fputc(b, file);
-  fputc(c, file);
-  fputc(d, file); }
-
diff --git a/readwrite.h b/readwrite.h
deleted file mode 100644 (file)
index 28bc3ab..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-uint16_t read_uint16_bigendian(FILE * file);
-void write_uint16_bigendian(uint16_t x, FILE * file);
-uint32_t read_uint32_bigendian(FILE * file);
-void write_uint32_bigendian(uint32_t x, FILE * file);
-
diff --git a/roguelike.c b/roguelike.c
deleted file mode 100644 (file)
index f0057e2..0000000
+++ /dev/null
@@ -1,383 +0,0 @@
-#include <stdlib.h>
-#include <stdint.h>
-#include <ncurses.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-#include "windows.h"
-#include "draw_wins.h"
-#include "roguelike.h"
-#include "keybindings.h"
-#include "readwrite.h"
-
-uint16_t rrand(char use_seed, uint32_t new_seed) {
-// Pseudo-random number generator (LGC algorithm). Use instead of rand() to ensure portable predictability.
-  static uint32_t seed;
-  if (0 != use_seed)
-    seed = new_seed;
-  seed = ((seed * 1103515245) + 12345) % 2147483648;   // Values as recommended by POSIX.1-2001 (see rand(3)).
-  return (seed / 65536); }                         // Ignore least significant 16 bits (they are less random).
-
-void save_game(struct World * world) {
-// Save game data to game file.
-  FILE * file = fopen("savefile", "w");
-  write_uint32_bigendian(world->seed, file);
-  write_uint32_bigendian(world->turn, file);
-  write_uint16_bigendian(world->player->y, file);
-  write_uint16_bigendian(world->player->x, file);
-  write_uint16_bigendian(world->monster->y, file);
-  write_uint16_bigendian(world->monster->x, file);
-  fclose(file); }
-
-void toggle_window (struct WinMeta * win_meta, struct Win * win) {
-// Toggle display of window win.
-  if (0 != win->frame.curses_win)
-    suspend_win(win_meta, win);
-  else
-    append_win(win_meta, win); }
-
-void scroll_pad (struct WinMeta * win_meta, char dir) {
-// Try to scroll pad left or right.
-  if      ('+' == dir)
-    reset_pad_offset(win_meta, win_meta->pad_offset + 1);
-  else if ('-' == dir)
-    reset_pad_offset(win_meta, win_meta->pad_offset - 1); }
-
-void growshrink_active_window (struct WinMeta * win_meta, char change) {
-// Grow or shrink active window horizontally or vertically by one cell size.
-  if (0 != win_meta->active) {
-    uint16_t height = win_meta->active->frame.size.y;
-    uint16_t width = win_meta->active->frame.size.x;
-    if      (change == '-')
-      height--;
-    else if (change == '+')
-      height++;
-    else if (change == '_')
-      width--;
-    else if (change == '*')
-      width++;
-    resize_active_win (win_meta, height, width); } }
-
-struct Map init_map () {
-// Initialize map with some experimental start values.
-  struct Map map;
-  map.width = 64;
-  map.height = 64;
-  map.offset_x = 0;
-  map.offset_y = 0;
-  uint32_t size = map.width * map.height;
-  map.cells = malloc(size);
-  uint16_t y, x;
-  for (y = 0; y < map.height; y++)
-    for (x = 0; x < map.width; x++)
-      map.cells[(y * map.width) + x] = '~';
-  map.cells[size / 2 + (map.width / 2)] = '.';
-  uint32_t repeats, root, curpos;
-  for (root = 0; root * root * root < size; root++);
-  for (repeats = 0; repeats < size * root; repeats++) {
-    y = rrand(0, 0) % map.height;
-    x = rrand(0, 0) % map.width;
-    curpos = y * map.width + x;
-    if ('~' == map.cells[curpos] &&
-        (   (curpos >= map.width && '.' == map.cells[curpos - map.width])
-         || (curpos < map.width * (map.height-1) && '.' == map.cells[curpos + map.width])
-         || (curpos > 0 && curpos % map.width != 0 && '.' == map.cells[curpos-1])
-         || (curpos < (map.width * map.height) && (curpos+1) % map.width != 0 && '.' == map.cells[curpos+1])))
-      map.cells[y * map.width + x] = '.'; }
-  return map; }
-
-void map_scroll (struct Map * map, char dir) {
-// Scroll map into direction dir if possible by changing the offset.
-  if      ('n' == dir && map->offset_y > 0)
-    map->offset_y--;
-  else if ('s' == dir)
-    map->offset_y++;
-  else if ('w' == dir && map->offset_x > 0)
-    map->offset_x--;
-  else if ('e' == dir)
-    map->offset_x++; }
-
-void next_turn (struct World * world) {
-// Increment turn and move enemy.
-  world->turn++;
-  rrand(1, world->seed * world->turn);
-  char d = rrand(0, 0) % 5;
-  uint16_t ty = world->monster->y;
-  uint16_t tx = world->monster->x;
-  if (1 == d)
-    ty++;
-  else if (2 == d)
-    ty--;
-  else if (3 == d)
-    tx++;
-  else if (4 == d)
-    tx--;
-  if (tx == world->player->x && ty == world->player->y)
-    update_log(world, "\nThe monster hits you.");
-  else if (is_passable(world->map, ty, tx)) {
-    world->monster->y = ty;
-    world->monster->x = tx; } }
-
-void update_log (struct World * world, char * text) {
-// Update log with new text to be appended.
-  char * new_text;
-  uint16_t len_old = strlen(world->log);
-  uint16_t len_new = strlen(text);
-  uint16_t len_whole = len_old + len_new + 1;
-  new_text = calloc(len_whole, sizeof(char));
-  memcpy(new_text, world->log, len_old);
-  memcpy(new_text + len_old, text, len_new);
-  free(world->log);
-  world->log = new_text; }
-
-char is_passable (struct Map * map, uint16_t y, uint16_t x) {
-// Check if coordinate on (or beyond) map is accessible to movement.
-  char passable = 0;
-  if (0 <= x && x < map->width && 0 <= y && y < map->height)
-    if ('.' == map->cells[y * map->width + x])
-      passable = 1;
-  return passable; }
-
-void record_action (char action) {
-// Append action to game record file.
-  FILE * file = fopen("record", "a");
-  fputc(action, file);
-  fclose(file); }
-
-void move_player (struct World * world, char d) {
-// Move player in direction d, increment turn counter and update log.
-  static char prev = 0;
-  char success = 0;
-  char * dir;
-  uint16_t ty = world->player->y;
-  uint16_t tx = world->player->x;
-  if ('s' == d) {
-    dir = "south";
-    ty++; }
-  if ('n' == d) {
-    dir = "north";
-    ty--; }
-  if ('w' == d) {
-    dir = "west";
-    tx--; }
-  if ('e' == d) {
-    dir = "east";
-    tx++; }
-  if (ty == world->monster->y && tx == world->monster->x)
-    success = 2;
-  else if (is_passable(world->map, ty, tx)) {
-    success = 1;
-    world->player->y = ty;
-    world->player->x = tx; }
-  if (success * d == prev)
-    update_log (world, ".");
-  else {
-    if (2 == success)
-      update_log (world, "\nYou hit the monster.");
-    else {
-      char * msg = calloc(25, sizeof(char));
-      char * msg_content = "You fail to move";
-      if (1 == success)
-        msg_content = "You move";
-      sprintf(msg, "\n%s %s.", msg_content, dir);
-      update_log (world, msg);
-      free(msg); } }
-  prev = success * d;
-  if (1 == world->interactive)
-    record_action(d);
-  next_turn (world); }
-
-void player_wait (struct World * world) {
-// Make player wait one turn.
-  if (1 == world->interactive)
-    record_action(0);
-  next_turn (world);
-  update_log (world, "\nYou wait."); }
-
-unsigned char meta_keys(int key, struct World * world, struct WinMeta * win_meta, struct Win * win_keys,
-                        struct Win * win_map, struct Win * win_info, struct Win * win_log) {
-// Call some meta program / window management actions dependent on key. Return 1 to signal quitting.
-  if (key == get_action_key(world->keybindings, "quit"))
-    return 1;
-  else if (key == get_action_key(world->keybindings, "scroll pad right"))
-    scroll_pad (win_meta, '+');
-  else if (key == get_action_key(world->keybindings, "scroll pad left"))
-    scroll_pad (win_meta, '-');
-  else if (key == get_action_key(world->keybindings, "toggle keys window"))
-    toggle_window(win_meta, win_keys);
-  else if (key == get_action_key(world->keybindings, "toggle map window"))
-    toggle_window(win_meta, win_map);
-  else if (key == get_action_key(world->keybindings, "toggle info window"))
-    toggle_window(win_meta, win_info);
-  else if (key == get_action_key(world->keybindings, "toggle log window"))
-    toggle_window(win_meta, win_log);
-  else if (key == get_action_key(world->keybindings, "cycle forwards"))
-    cycle_active_win(win_meta, 'n');
-  else if (key == get_action_key(world->keybindings, "cycle backwards"))
-    cycle_active_win(win_meta, 'p');
-  else if (key == get_action_key(world->keybindings, "shift forwards"))
-    shift_active_win(win_meta, 'f');
-  else if (key == get_action_key(world->keybindings, "shift backwards"))
-    shift_active_win(win_meta, 'b');
-  else if (key == get_action_key(world->keybindings, "grow horizontally"))
-    growshrink_active_window(win_meta, '*');
-  else if (key == get_action_key(world->keybindings, "shrink horizontally"))
-    growshrink_active_window(win_meta, '_');
-  else if (key == get_action_key(world->keybindings, "grow vertically"))
-    growshrink_active_window(win_meta, '+');
-  else if (key == get_action_key(world->keybindings, "shrink vertically"))
-    growshrink_active_window(win_meta, '-');
-  else if (key == get_action_key(world->keybindings, "save keys"))
-    save_keybindings(world);
-  else if (key == get_action_key(world->keybindings, "keys nav up"))
-    keyswin_move_selection (world, 'u');
-  else if (key == get_action_key(world->keybindings, "keys nav down"))
-    keyswin_move_selection (world, 'd');
-  else if (key == get_action_key(world->keybindings, "keys mod"))
-    keyswin_mod_key (world, win_meta);
-  else if (key == get_action_key(world->keybindings, "map up"))
-    map_scroll (world->map, 'n');
-  else if (key == get_action_key(world->keybindings, "map down"))
-    map_scroll (world->map, 's');
-  else if (key == get_action_key(world->keybindings, "map right"))
-    map_scroll (world->map, 'e');
-  else if (key == get_action_key(world->keybindings, "map left"))
-    map_scroll (world->map, 'w');
-  return 0; }
-
-int main (int argc, char *argv[]) {
-  struct World world;
-  world.interactive = 1;
-  int opt;
-  uint32_t start_turn;
-  while ((opt = getopt(argc, argv, "s::")) != -1) {
-    switch (opt) {
-      case 's':
-        world.interactive = 0;
-        start_turn = 0;
-        if (optarg)
-          start_turn = atoi(optarg);
-        break;
-      default:
-        exit(EXIT_FAILURE); } }
-
-  world.log = calloc(1, sizeof(char));
-  update_log (&world, " ");
-  struct Player player;
-  world.player = &player;
-  struct Monster monster;
-  world.monster = &monster;
-  FILE * file;
-  if (1 == world.interactive && 0 == access("savefile", F_OK)) {
-    file = fopen("savefile", "r");
-    world.seed = read_uint32_bigendian(file);
-    world.turn = read_uint32_bigendian(file);
-    player.y = read_uint16_bigendian(file);
-    player.x = read_uint16_bigendian(file);
-    monster.y = read_uint16_bigendian(file);
-    monster.x = read_uint16_bigendian(file);
-    fclose(file); }
-  else {
-    world.turn = 1;
-    if (0 == world.interactive) {
-      file = fopen("record", "r");
-      world.seed = read_uint32_bigendian(file); }
-    else {
-      file = fopen("record", "w");
-      world.seed = time(NULL);
-      write_uint32_bigendian(world.seed, file);
-      fclose(file); } }
-  rrand(1, world.seed);
-  struct Map map = init_map();
-  world.map = &map;
-  if (1 == world.turn) {
-    for (player.y = player.x = 0; 0 == is_passable(&map, player.y, player.x);) {
-      player.y = rrand(0, 0) % map.height;
-      player.x = rrand(0, 0) % map.width; }
-    for (monster.y = monster.x = 0; 0 == is_passable(&map, monster.y, monster.x);) {
-      monster.y = rrand(0, 0) % map.height;
-      monster.x = rrand(0, 0) % map.width; } }
-
-  WINDOW * screen = initscr();
-  noecho();
-  curs_set(0);
-  keypad(screen, TRUE);
-  raw();
-  init_keybindings(&world);
-  struct WinMeta win_meta = init_win_meta(screen);
-  struct Win win_keys = init_win(&win_meta, "Keys", &world, draw_keys_win);
-  struct Win win_map = init_win(&win_meta, "Map", &world, draw_map_win);
-  struct Win win_info = init_win(&win_meta, "Info", &world, draw_info_win);
-  struct Win win_log = init_win(&win_meta, "Log", &world, draw_log_win);
-  win_keys.frame.size.x = 29;
-  win_map.frame.size.x = win_meta.pad.size.x - win_keys.frame.size.x - win_log.frame.size.x - 2;
-  win_info.frame.size.y = 1;
-  win_log.frame.size.y = win_meta.pad.size.y - 3;
-  toggle_window(&win_meta, &win_keys);
-  toggle_window(&win_meta, &win_map);
-  toggle_window(&win_meta, &win_info);
-  toggle_window(&win_meta, &win_log);
-
-  int key;
-  unsigned char quit_called = 0;
-  if (0 == world.interactive) {
-    unsigned char still_reading_file = 1;
-    int action;
-    while (1) {
-      if (start_turn == world.turn)
-        start_turn = 0;
-      if (0 == start_turn) {
-        draw_all_wins (&win_meta);
-        key = getch(); }
-      if (1 == still_reading_file &&
-          (world.turn < start_turn || key == get_action_key(world.keybindings, "wait / next turn")) ) {
-        action = getc(file);
-        if (EOF == action) {
-          start_turn = 0;
-          still_reading_file = 0; }
-        else if (0 == action)
-          player_wait (&world);
-        else if ('s' == action)
-          move_player(&world, 's');
-        else if ('n' == action)
-          move_player(&world, 'n');
-        else if ('e' == action)
-          move_player(&world, 'e');
-        else if ('w' == action)
-          move_player(&world, 'w'); }
-      else
-        quit_called = meta_keys(key, &world, &win_meta, &win_keys, &win_map, &win_info, &win_log);
-        if (1 == quit_called)
-          break; } }
-  else {
-    uint32_t last_turn = 0;
-    while (1) {
-      if (last_turn != world.turn) {
-        save_game(&world);
-        last_turn = world.turn; }
-      draw_all_wins (&win_meta);
-      key = getch();
-      if      (key == get_action_key(world.keybindings, "player down"))
-        move_player(&world, 's');
-      else if (key == get_action_key(world.keybindings, "player up"))
-        move_player(&world, 'n');
-      else if (key == get_action_key(world.keybindings, "player right"))
-        move_player(&world, 'e');
-      else if (key == get_action_key(world.keybindings, "player left"))
-        move_player(&world, 'w');
-      else if (key == get_action_key(world.keybindings, "wait / next turn"))
-        player_wait (&world);
-      else
-        quit_called = meta_keys(key, &world, &win_meta, &win_keys, &win_map, &win_info, &win_log);
-        if (1 == quit_called)
-          break; } }
-
-  free(map.cells);
-  for (key = 0; key <= world.keyswindata->max; key++)
-    free(world.keybindings[key].name);
-  free(world.keybindings);
-  free(world.keyswindata);
-  free(world.log);
-
-  endwin();
-  return 0; }
diff --git a/roguelike.h b/roguelike.h
deleted file mode 100644 (file)
index d82313e..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-struct World {
-  char interactive;
-  struct KeyBinding * keybindings;
-  struct KeysWinData * keyswindata;
-  uint32_t seed;
-  uint32_t turn;
-  char * log;
-  struct Map * map;
-  struct Monster * monster;
-  struct Player * player; };
-
-struct Map {
-  uint16_t width;
-  uint16_t height;
-  uint16_t offset_x;
-  uint16_t offset_y;
-  char * cells; };
-
-struct Player {
-  uint16_t y;
-  uint16_t x; };
-
-struct Monster {
-  uint16_t y;
-  uint16_t x; };
-
-uint16_t rrand(char, uint32_t);
-void save_game(struct World *);
-void toggle_window (struct WinMeta *, struct Win *);
-void scroll_pad (struct WinMeta *, char);
-void growshrink_active_window (struct WinMeta *, char);
-struct Map init_map ();
-void map_scroll (struct Map *, char);
-void next_turn (struct World *);
-void update_log (struct World *, char *);
-char is_passable (struct Map *, uint16_t, uint16_t);
-void record_action (char);
-void move_player (struct World *, char);
-void player_wait(struct World *);
-unsigned char meta_keys(int, struct World *, struct WinMeta *, struct Win *, struct Win *, struct Win *, struct Win *);
diff --git a/src/draw_wins.c b/src/draw_wins.c
new file mode 100644 (file)
index 0000000..818037a
--- /dev/null
@@ -0,0 +1,138 @@
+#include <stdlib.h>
+#include <stdint.h>
+#include <ncurses.h>
+#include <string.h>
+#include "windows.h"
+#include "draw_wins.h"
+#include "roguelike.h"
+#include "keybindings.h"
+
+void draw_with_linebreaks (struct Win * win, char * text, uint16_t start_y) {
+// Write text into window content space. Start on row start_y. Fill unused rows with whitespace.
+  uint16_t x, y;
+  char toggle;
+  char fin = 0;
+  int16_t z = -1;
+  for (y = start_y; y < win->frame.size.y; y++) {
+    if (0 == fin)
+      toggle = 0;
+    for (x = 0; x < win->frame.size.x; x++) {
+       if (0 == toggle) {
+         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; } } } } }
+
+void draw_text_from_bottom (struct Win * win, char * text) {
+// Draw text from end/bottom to the top.
+  char toggle = 0;
+  uint16_t x, y, offset;
+  int16_t z = -1;
+  for (y = 0; 0 == toggle; y++)                           // Determine number of lines text would have in
+    for (x = 0; x < win->frame.size.x; x++) {             // a window of available width, but infinite height.
+      z++;
+      if ('\n' == text[z])            // Treat \n and \0 as control characters for incrementing y and stopping
+        break;                        // the loop. Make sure they don't count as cell space themselves.
+      if ('\n' == text[z+1]) {
+        z++;
+        break; }
+      else if (0 == text[z+1]) {
+        toggle = 1;
+        break; } }
+  z = -1;
+  uint16_t start_y = 0;
+  if (y < win->frame.size.y)       // Depending on what is bigger, determine start point in window or in text.
+    start_y = win->frame.size.y - y;
+  else if (y > win->frame.size.y) {
+    offset = y - win->frame.size.y;
+    for (y = 0; y < offset; y++)
+      for (x = 0; x < win->frame.size.x; x++) {
+        z++;
+        if ('\n' == text[z])
+          break;
+        if ('\n' == text[z+1]) {
+          z++;
+          break; } }
+    text = text + (sizeof(char) * (z + 1)); }
+  draw_with_linebreaks(win, text, start_y); }
+
+void draw_log_win (struct Win * win) {
+// Draw log text from world struct in win->data from bottom to top.
+  struct World * world = (struct World *) win->data;
+  draw_text_from_bottom(win, world->log); }
+
+void draw_map_win (struct Win * win) {
+// Draw map determined by win->data Map struct into window. Respect offset.
+  struct World * world = (struct World *) win->data;
+  struct Map * map = world->map;
+  struct Player * player = world->player;
+  struct Monster * monster = world->monster;
+  char * cells = map->cells;
+  uint16_t width_map_av = map->width - map->offset_x;
+  uint16_t height_map_av = map->height - map->offset_y;
+  uint16_t x, y, z;
+  for (y = 0; y < win->frame.size.y; y++) {
+    z = map->offset_x + (map->offset_y + y) * (map->width);
+    for (x = 0; x < win->frame.size.x; x++) {
+      if (y < height_map_av && x < width_map_av) {
+        if (z == (map->width * player->y) + player->x)
+          mvwaddch(win->frame.curses_win, y, x, '@');
+        else if (z == (map->width * monster->y) + monster->x)
+          mvwaddch(win->frame.curses_win, y, x, 'M');
+        else
+          mvwaddch(win->frame.curses_win, y, x, cells[z]);
+        z++; } } } }
+
+void draw_info_win (struct Win * win) {
+// Draw info window by appending win->data integer value to "Turn: " display.
+  struct World * world = (struct World *) win->data;
+  uint16_t count = world->turn;
+  char text[100];
+  snprintf(text, 100, "Turn: %d", count);
+  draw_with_linebreaks(win, text, 0); }
+
+void draw_keys_win (struct Win * win) {
+// Draw keybindings window.
+  struct World * world = (struct World *) win->data;
+  uint16_t offset = 0, y, x;
+  if (world->keyswindata->max >= win->frame.size.y) {
+    if (world->keyswindata->select > win->frame.size.y / 2) {
+      if (world->keyswindata->select < (world->keyswindata->max - (win->frame.size.y / 2)))
+        offset = world->keyswindata->select - (win->frame.size.y / 2);
+      else
+        offset = world->keyswindata->max - win->frame.size.y + 1; } }
+  uint8_t keydescwidth = 9 + 1; // max length assured by get_keyname() + \0
+  char * keydesc = malloc(keydescwidth), * keyname;
+  attr_t attri;
+  for (y = 0; y <= world->keyswindata->max && y < win->frame.size.y; y++) {
+    if (0 == y && offset > 0) {
+      draw_scroll_hint(&win->frame, y, offset + 1, '^');
+      continue; }
+    else if (win->frame.size.y == y + 1 && 0 < world->keyswindata->max - (win->frame.size.y + offset - 1)) {
+      draw_scroll_hint(&win->frame, y, world->keyswindata->max - (offset + win->frame.size.y) + 2, 'v');
+      continue; }
+    attri = 0;
+    if (y == world->keyswindata->select - offset) {
+      attri = A_REVERSE;
+      if (1 == world->keyswindata->edit)
+        attri = attri | A_BLINK; }
+    keyname = get_keyname(world->keybindings[y + offset].key);
+    snprintf(keydesc, keydescwidth, "%-9s", keyname);
+    free(keyname);
+    for (x = 0; x < win->frame.size.x; x++)
+      if (x < strlen(keydesc))
+        mvwaddch(win->frame.curses_win, y, x, keydesc[x] | attri);
+      else if (strlen(keydesc) < x && x < strlen(world->keybindings[y + offset].name) + strlen(keydesc) + 1)
+        mvwaddch(win->frame.curses_win, y, x,
+                 world->keybindings[y + offset].name[x - strlen(keydesc) - 1] | attri);
+      else
+        mvwaddch(win->frame.curses_win, y, x, ' ' | attri); }
+  free(keydesc); }
diff --git a/src/draw_wins.h b/src/draw_wins.h
new file mode 100644 (file)
index 0000000..64f332c
--- /dev/null
@@ -0,0 +1,6 @@
+void draw_with_linebreaks (struct Win *, char *, uint16_t);
+void draw_text_from_bottom (struct Win *, char *);
+void draw_log_win (struct Win *);
+void draw_map_win (struct Win *);
+void draw_info_win (struct Win *);
+void draw_keys_win (struct Win *);
diff --git a/src/keybindings.c b/src/keybindings.c
new file mode 100644 (file)
index 0000000..b6ff412
--- /dev/null
@@ -0,0 +1,127 @@
+#include <stdlib.h>
+#include <stdint.h>
+#include <ncurses.h>
+#include <string.h>
+#include "windows.h"
+#include "roguelike.h"
+#include "keybindings.h"
+
+void init_keybindings(struct World * world) {
+// Initialize keybindings from file "keybindings".
+  FILE * file = fopen("keybindings", "r");
+  uint16_t lines = 0;
+  int c = 0;
+  uint16_t linemax = 0;
+  uint16_t c_count = 0;
+  while (EOF != c) {
+    c_count++;
+    c = getc(file);
+    if ('\n' == c) {
+      if (c_count > linemax)
+        linemax = c_count + 1;
+      c_count = 0;
+      lines++; } }
+  struct KeyBinding * keybindings = malloc(lines * sizeof(struct KeyBinding));
+  fseek(file, 0, SEEK_SET);
+  char * command = malloc(linemax);
+  uint16_t commcount = 0;
+  char * cmdptr;
+  while (fgets(command, linemax, file)) {
+    keybindings[commcount].key = atoi(command);
+    cmdptr = strchr(command, ' ') + 1;
+    keybindings[commcount].name = malloc(strlen(cmdptr));
+    memcpy(keybindings[commcount].name, cmdptr, strlen(cmdptr) - 1);
+    keybindings[commcount].name[strlen(cmdptr) - 1] = '\0';
+    commcount++; }
+  free(command);
+  fclose(file);
+  struct KeysWinData * keyswindata = malloc(sizeof(struct KeysWinData));
+  keyswindata->max = lines - 1;
+  keyswindata->select = 0;
+  keyswindata->edit = 0;
+  world->keybindings = keybindings;
+  world->keyswindata = keyswindata; }
+
+void save_keybindings(struct World * world) {
+// Write keybindings to keybindings file.
+  struct KeysWinData * keyswindata = (struct KeysWinData *) world->keyswindata;
+  struct KeyBinding * keybindings = world->keybindings;
+  FILE * file = fopen("keybindings", "w");
+  uint16_t linemax = 0;
+  uint16_t i;
+  for (i = 0; i <= keyswindata->max; i++)
+    if (strlen(keybindings[i].name) > linemax)
+      linemax = strlen(keybindings[i].name);
+  linemax = linemax + 6;                                // + 6 = + 3 digits + whitespace + newline + null byte
+  char * line = malloc(linemax);
+  for (i = 0; i <= keyswindata->max; i++) {
+    snprintf(line, linemax, "%d %s\n", keybindings[i].key, keybindings[i].name);
+    fwrite(line, sizeof(char), strlen(line), file); }
+  free(line);
+  fclose(file); }
+
+uint16_t get_action_key (struct KeyBinding * keybindings, char * name) {
+// Return key matching name in keybindings.
+  uint16_t i = 0;
+  while (strcmp(keybindings[i].name, name) )
+    i++;
+  return keybindings[i].key; }
+
+char * get_keyname(uint16_t keycode) {
+// Translate some keycodes to readable names of max 9 chars.
+  char * keyname;
+  keyname = malloc(15);
+  if (32 < keycode && keycode < 127)
+    sprintf(keyname, "%c", keycode);
+  else if (keycode == 9)
+    sprintf(keyname, "TAB");
+  else if (keycode == 10)
+    sprintf(keyname, "RETURN");
+  else if (keycode == 27)
+    sprintf(keyname, "ESCAPE");
+  else if (keycode == 32)
+    sprintf(keyname, "SPACE");
+  else if (keycode == KEY_UP)
+    sprintf(keyname, "UP");
+  else if (keycode == KEY_DOWN)
+    sprintf(keyname, "DOWN");
+  else if (keycode == KEY_LEFT)
+    sprintf(keyname, "LEFT");
+  else if (keycode == KEY_RIGHT)
+    sprintf(keyname, "RIGHT");
+  else if (keycode == KEY_HOME)
+    sprintf(keyname, "HOME");
+  else if (keycode == KEY_BACKSPACE)
+    sprintf(keyname, "BACKSPACE");
+  else if (keycode >= KEY_F0 && keycode <= KEY_F(63)) {
+    uint16_t f = keycode - KEY_F0;
+    sprintf(keyname, "F%d", f); }
+  else if (keycode == KEY_DC)
+    sprintf(keyname, "DELETE");
+  else if (keycode == KEY_IC)
+    sprintf(keyname, "INSERT");
+  else if (keycode == KEY_NPAGE)
+    sprintf(keyname, "NEXT PAGE");
+  else if (keycode == KEY_PPAGE)
+    sprintf(keyname, "PREV PAGE");
+  else if (keycode == KEY_END)
+    sprintf(keyname, "END");
+  else
+    sprintf(keyname, "(unknown)");
+  return keyname;  }
+
+void keyswin_mod_key (struct World * world, struct WinMeta * win_meta) {
+// In keybindings window, mark selection modifiable, modify key. Ensure max of three digits in key code field.
+  world->keyswindata->edit = 1;
+  draw_all_wins (win_meta);
+  int key = getch();
+  if (key < 1000)
+    world->keybindings[world->keyswindata->select].key = key;
+  world->keyswindata->edit = 0; }
+
+void keyswin_move_selection (struct World * world, char dir) {
+// In keybindings window, move selection upwards or downwards (if within limits of list length).
+  if ('u' == dir && world->keyswindata->select > 0)
+    world->keyswindata->select--;
+  else if ('d' == dir && world->keyswindata->select < world->keyswindata->max)
+    world->keyswindata->select++; }
diff --git a/src/keybindings.h b/src/keybindings.h
new file mode 100644 (file)
index 0000000..b0ff912
--- /dev/null
@@ -0,0 +1,15 @@
+struct KeyBinding {
+  char * name;
+  uint16_t key; };
+
+struct KeysWinData {
+  uint16_t max;
+  char edit;
+  uint16_t select; };
+
+void init_keybindings(struct World *);
+void save_keybindings(struct World *);
+uint16_t get_action_key (struct KeyBinding *, char *);
+char * get_keyname(uint16_t);
+void keyswin_mod_key (struct World *, struct WinMeta *);
+void keyswin_move_selection (struct World *, char);
diff --git a/src/readwrite.c b/src/readwrite.c
new file mode 100644 (file)
index 0000000..ed5a3a3
--- /dev/null
@@ -0,0 +1,40 @@
+#include <stdio.h>
+#include <limits.h>
+#include <stdint.h>
+
+uint16_t read_uint16_bigendian(FILE * file) {
+// Read uint16 from file in big-endian order.
+  const uint16_t nchar = UCHAR_MAX + 1;
+  unsigned char a = fgetc(file);
+  unsigned char b = fgetc(file);
+  return (a * nchar) + b; }
+
+void write_uint16_bigendian(uint16_t x, FILE * file) {
+// Write uint16 to file in beg-endian order.
+  const uint16_t nchar = UCHAR_MAX + 1;
+  unsigned char a = x / nchar;
+  unsigned char b = x % nchar;
+  fputc(a, file);
+  fputc(b, file); }
+
+uint32_t read_uint32_bigendian(FILE * file) {
+// Read uint32 from file in big-endian order.
+  const uint16_t nchar = UCHAR_MAX + 1;
+  unsigned char a = fgetc(file);
+  unsigned char b = fgetc(file);
+  unsigned char c = fgetc(file);
+  unsigned char d = fgetc(file);
+  return (a * nchar * nchar * nchar) + (b * nchar * nchar) + (c * nchar) + d; }
+
+void write_uint32_bigendian(uint32_t x, FILE * file) {
+// Write uint32 to file in beg-endian order.
+  const uint16_t nchar = UCHAR_MAX + 1;
+  unsigned char a = x / (nchar * nchar * nchar);
+  unsigned char b = (x - (a * nchar * nchar * nchar)) / (nchar * nchar);
+  unsigned char c = (x - ((a * nchar * nchar * nchar) + (b * nchar * nchar))) / nchar;
+  unsigned char d = x % nchar;
+  fputc(a, file);
+  fputc(b, file);
+  fputc(c, file);
+  fputc(d, file); }
+
diff --git a/src/readwrite.h b/src/readwrite.h
new file mode 100644 (file)
index 0000000..28bc3ab
--- /dev/null
@@ -0,0 +1,5 @@
+uint16_t read_uint16_bigendian(FILE * file);
+void write_uint16_bigendian(uint16_t x, FILE * file);
+uint32_t read_uint32_bigendian(FILE * file);
+void write_uint32_bigendian(uint32_t x, FILE * file);
+
diff --git a/src/roguelike.c b/src/roguelike.c
new file mode 100644 (file)
index 0000000..f0057e2
--- /dev/null
@@ -0,0 +1,383 @@
+#include <stdlib.h>
+#include <stdint.h>
+#include <ncurses.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include "windows.h"
+#include "draw_wins.h"
+#include "roguelike.h"
+#include "keybindings.h"
+#include "readwrite.h"
+
+uint16_t rrand(char use_seed, uint32_t new_seed) {
+// Pseudo-random number generator (LGC algorithm). Use instead of rand() to ensure portable predictability.
+  static uint32_t seed;
+  if (0 != use_seed)
+    seed = new_seed;
+  seed = ((seed * 1103515245) + 12345) % 2147483648;   // Values as recommended by POSIX.1-2001 (see rand(3)).
+  return (seed / 65536); }                         // Ignore least significant 16 bits (they are less random).
+
+void save_game(struct World * world) {
+// Save game data to game file.
+  FILE * file = fopen("savefile", "w");
+  write_uint32_bigendian(world->seed, file);
+  write_uint32_bigendian(world->turn, file);
+  write_uint16_bigendian(world->player->y, file);
+  write_uint16_bigendian(world->player->x, file);
+  write_uint16_bigendian(world->monster->y, file);
+  write_uint16_bigendian(world->monster->x, file);
+  fclose(file); }
+
+void toggle_window (struct WinMeta * win_meta, struct Win * win) {
+// Toggle display of window win.
+  if (0 != win->frame.curses_win)
+    suspend_win(win_meta, win);
+  else
+    append_win(win_meta, win); }
+
+void scroll_pad (struct WinMeta * win_meta, char dir) {
+// Try to scroll pad left or right.
+  if      ('+' == dir)
+    reset_pad_offset(win_meta, win_meta->pad_offset + 1);
+  else if ('-' == dir)
+    reset_pad_offset(win_meta, win_meta->pad_offset - 1); }
+
+void growshrink_active_window (struct WinMeta * win_meta, char change) {
+// Grow or shrink active window horizontally or vertically by one cell size.
+  if (0 != win_meta->active) {
+    uint16_t height = win_meta->active->frame.size.y;
+    uint16_t width = win_meta->active->frame.size.x;
+    if      (change == '-')
+      height--;
+    else if (change == '+')
+      height++;
+    else if (change == '_')
+      width--;
+    else if (change == '*')
+      width++;
+    resize_active_win (win_meta, height, width); } }
+
+struct Map init_map () {
+// Initialize map with some experimental start values.
+  struct Map map;
+  map.width = 64;
+  map.height = 64;
+  map.offset_x = 0;
+  map.offset_y = 0;
+  uint32_t size = map.width * map.height;
+  map.cells = malloc(size);
+  uint16_t y, x;
+  for (y = 0; y < map.height; y++)
+    for (x = 0; x < map.width; x++)
+      map.cells[(y * map.width) + x] = '~';
+  map.cells[size / 2 + (map.width / 2)] = '.';
+  uint32_t repeats, root, curpos;
+  for (root = 0; root * root * root < size; root++);
+  for (repeats = 0; repeats < size * root; repeats++) {
+    y = rrand(0, 0) % map.height;
+    x = rrand(0, 0) % map.width;
+    curpos = y * map.width + x;
+    if ('~' == map.cells[curpos] &&
+        (   (curpos >= map.width && '.' == map.cells[curpos - map.width])
+         || (curpos < map.width * (map.height-1) && '.' == map.cells[curpos + map.width])
+         || (curpos > 0 && curpos % map.width != 0 && '.' == map.cells[curpos-1])
+         || (curpos < (map.width * map.height) && (curpos+1) % map.width != 0 && '.' == map.cells[curpos+1])))
+      map.cells[y * map.width + x] = '.'; }
+  return map; }
+
+void map_scroll (struct Map * map, char dir) {
+// Scroll map into direction dir if possible by changing the offset.
+  if      ('n' == dir && map->offset_y > 0)
+    map->offset_y--;
+  else if ('s' == dir)
+    map->offset_y++;
+  else if ('w' == dir && map->offset_x > 0)
+    map->offset_x--;
+  else if ('e' == dir)
+    map->offset_x++; }
+
+void next_turn (struct World * world) {
+// Increment turn and move enemy.
+  world->turn++;
+  rrand(1, world->seed * world->turn);
+  char d = rrand(0, 0) % 5;
+  uint16_t ty = world->monster->y;
+  uint16_t tx = world->monster->x;
+  if (1 == d)
+    ty++;
+  else if (2 == d)
+    ty--;
+  else if (3 == d)
+    tx++;
+  else if (4 == d)
+    tx--;
+  if (tx == world->player->x && ty == world->player->y)
+    update_log(world, "\nThe monster hits you.");
+  else if (is_passable(world->map, ty, tx)) {
+    world->monster->y = ty;
+    world->monster->x = tx; } }
+
+void update_log (struct World * world, char * text) {
+// Update log with new text to be appended.
+  char * new_text;
+  uint16_t len_old = strlen(world->log);
+  uint16_t len_new = strlen(text);
+  uint16_t len_whole = len_old + len_new + 1;
+  new_text = calloc(len_whole, sizeof(char));
+  memcpy(new_text, world->log, len_old);
+  memcpy(new_text + len_old, text, len_new);
+  free(world->log);
+  world->log = new_text; }
+
+char is_passable (struct Map * map, uint16_t y, uint16_t x) {
+// Check if coordinate on (or beyond) map is accessible to movement.
+  char passable = 0;
+  if (0 <= x && x < map->width && 0 <= y && y < map->height)
+    if ('.' == map->cells[y * map->width + x])
+      passable = 1;
+  return passable; }
+
+void record_action (char action) {
+// Append action to game record file.
+  FILE * file = fopen("record", "a");
+  fputc(action, file);
+  fclose(file); }
+
+void move_player (struct World * world, char d) {
+// Move player in direction d, increment turn counter and update log.
+  static char prev = 0;
+  char success = 0;
+  char * dir;
+  uint16_t ty = world->player->y;
+  uint16_t tx = world->player->x;
+  if ('s' == d) {
+    dir = "south";
+    ty++; }
+  if ('n' == d) {
+    dir = "north";
+    ty--; }
+  if ('w' == d) {
+    dir = "west";
+    tx--; }
+  if ('e' == d) {
+    dir = "east";
+    tx++; }
+  if (ty == world->monster->y && tx == world->monster->x)
+    success = 2;
+  else if (is_passable(world->map, ty, tx)) {
+    success = 1;
+    world->player->y = ty;
+    world->player->x = tx; }
+  if (success * d == prev)
+    update_log (world, ".");
+  else {
+    if (2 == success)
+      update_log (world, "\nYou hit the monster.");
+    else {
+      char * msg = calloc(25, sizeof(char));
+      char * msg_content = "You fail to move";
+      if (1 == success)
+        msg_content = "You move";
+      sprintf(msg, "\n%s %s.", msg_content, dir);
+      update_log (world, msg);
+      free(msg); } }
+  prev = success * d;
+  if (1 == world->interactive)
+    record_action(d);
+  next_turn (world); }
+
+void player_wait (struct World * world) {
+// Make player wait one turn.
+  if (1 == world->interactive)
+    record_action(0);
+  next_turn (world);
+  update_log (world, "\nYou wait."); }
+
+unsigned char meta_keys(int key, struct World * world, struct WinMeta * win_meta, struct Win * win_keys,
+                        struct Win * win_map, struct Win * win_info, struct Win * win_log) {
+// Call some meta program / window management actions dependent on key. Return 1 to signal quitting.
+  if (key == get_action_key(world->keybindings, "quit"))
+    return 1;
+  else if (key == get_action_key(world->keybindings, "scroll pad right"))
+    scroll_pad (win_meta, '+');
+  else if (key == get_action_key(world->keybindings, "scroll pad left"))
+    scroll_pad (win_meta, '-');
+  else if (key == get_action_key(world->keybindings, "toggle keys window"))
+    toggle_window(win_meta, win_keys);
+  else if (key == get_action_key(world->keybindings, "toggle map window"))
+    toggle_window(win_meta, win_map);
+  else if (key == get_action_key(world->keybindings, "toggle info window"))
+    toggle_window(win_meta, win_info);
+  else if (key == get_action_key(world->keybindings, "toggle log window"))
+    toggle_window(win_meta, win_log);
+  else if (key == get_action_key(world->keybindings, "cycle forwards"))
+    cycle_active_win(win_meta, 'n');
+  else if (key == get_action_key(world->keybindings, "cycle backwards"))
+    cycle_active_win(win_meta, 'p');
+  else if (key == get_action_key(world->keybindings, "shift forwards"))
+    shift_active_win(win_meta, 'f');
+  else if (key == get_action_key(world->keybindings, "shift backwards"))
+    shift_active_win(win_meta, 'b');
+  else if (key == get_action_key(world->keybindings, "grow horizontally"))
+    growshrink_active_window(win_meta, '*');
+  else if (key == get_action_key(world->keybindings, "shrink horizontally"))
+    growshrink_active_window(win_meta, '_');
+  else if (key == get_action_key(world->keybindings, "grow vertically"))
+    growshrink_active_window(win_meta, '+');
+  else if (key == get_action_key(world->keybindings, "shrink vertically"))
+    growshrink_active_window(win_meta, '-');
+  else if (key == get_action_key(world->keybindings, "save keys"))
+    save_keybindings(world);
+  else if (key == get_action_key(world->keybindings, "keys nav up"))
+    keyswin_move_selection (world, 'u');
+  else if (key == get_action_key(world->keybindings, "keys nav down"))
+    keyswin_move_selection (world, 'd');
+  else if (key == get_action_key(world->keybindings, "keys mod"))
+    keyswin_mod_key (world, win_meta);
+  else if (key == get_action_key(world->keybindings, "map up"))
+    map_scroll (world->map, 'n');
+  else if (key == get_action_key(world->keybindings, "map down"))
+    map_scroll (world->map, 's');
+  else if (key == get_action_key(world->keybindings, "map right"))
+    map_scroll (world->map, 'e');
+  else if (key == get_action_key(world->keybindings, "map left"))
+    map_scroll (world->map, 'w');
+  return 0; }
+
+int main (int argc, char *argv[]) {
+  struct World world;
+  world.interactive = 1;
+  int opt;
+  uint32_t start_turn;
+  while ((opt = getopt(argc, argv, "s::")) != -1) {
+    switch (opt) {
+      case 's':
+        world.interactive = 0;
+        start_turn = 0;
+        if (optarg)
+          start_turn = atoi(optarg);
+        break;
+      default:
+        exit(EXIT_FAILURE); } }
+
+  world.log = calloc(1, sizeof(char));
+  update_log (&world, " ");
+  struct Player player;
+  world.player = &player;
+  struct Monster monster;
+  world.monster = &monster;
+  FILE * file;
+  if (1 == world.interactive && 0 == access("savefile", F_OK)) {
+    file = fopen("savefile", "r");
+    world.seed = read_uint32_bigendian(file);
+    world.turn = read_uint32_bigendian(file);
+    player.y = read_uint16_bigendian(file);
+    player.x = read_uint16_bigendian(file);
+    monster.y = read_uint16_bigendian(file);
+    monster.x = read_uint16_bigendian(file);
+    fclose(file); }
+  else {
+    world.turn = 1;
+    if (0 == world.interactive) {
+      file = fopen("record", "r");
+      world.seed = read_uint32_bigendian(file); }
+    else {
+      file = fopen("record", "w");
+      world.seed = time(NULL);
+      write_uint32_bigendian(world.seed, file);
+      fclose(file); } }
+  rrand(1, world.seed);
+  struct Map map = init_map();
+  world.map = &map;
+  if (1 == world.turn) {
+    for (player.y = player.x = 0; 0 == is_passable(&map, player.y, player.x);) {
+      player.y = rrand(0, 0) % map.height;
+      player.x = rrand(0, 0) % map.width; }
+    for (monster.y = monster.x = 0; 0 == is_passable(&map, monster.y, monster.x);) {
+      monster.y = rrand(0, 0) % map.height;
+      monster.x = rrand(0, 0) % map.width; } }
+
+  WINDOW * screen = initscr();
+  noecho();
+  curs_set(0);
+  keypad(screen, TRUE);
+  raw();
+  init_keybindings(&world);
+  struct WinMeta win_meta = init_win_meta(screen);
+  struct Win win_keys = init_win(&win_meta, "Keys", &world, draw_keys_win);
+  struct Win win_map = init_win(&win_meta, "Map", &world, draw_map_win);
+  struct Win win_info = init_win(&win_meta, "Info", &world, draw_info_win);
+  struct Win win_log = init_win(&win_meta, "Log", &world, draw_log_win);
+  win_keys.frame.size.x = 29;
+  win_map.frame.size.x = win_meta.pad.size.x - win_keys.frame.size.x - win_log.frame.size.x - 2;
+  win_info.frame.size.y = 1;
+  win_log.frame.size.y = win_meta.pad.size.y - 3;
+  toggle_window(&win_meta, &win_keys);
+  toggle_window(&win_meta, &win_map);
+  toggle_window(&win_meta, &win_info);
+  toggle_window(&win_meta, &win_log);
+
+  int key;
+  unsigned char quit_called = 0;
+  if (0 == world.interactive) {
+    unsigned char still_reading_file = 1;
+    int action;
+    while (1) {
+      if (start_turn == world.turn)
+        start_turn = 0;
+      if (0 == start_turn) {
+        draw_all_wins (&win_meta);
+        key = getch(); }
+      if (1 == still_reading_file &&
+          (world.turn < start_turn || key == get_action_key(world.keybindings, "wait / next turn")) ) {
+        action = getc(file);
+        if (EOF == action) {
+          start_turn = 0;
+          still_reading_file = 0; }
+        else if (0 == action)
+          player_wait (&world);
+        else if ('s' == action)
+          move_player(&world, 's');
+        else if ('n' == action)
+          move_player(&world, 'n');
+        else if ('e' == action)
+          move_player(&world, 'e');
+        else if ('w' == action)
+          move_player(&world, 'w'); }
+      else
+        quit_called = meta_keys(key, &world, &win_meta, &win_keys, &win_map, &win_info, &win_log);
+        if (1 == quit_called)
+          break; } }
+  else {
+    uint32_t last_turn = 0;
+    while (1) {
+      if (last_turn != world.turn) {
+        save_game(&world);
+        last_turn = world.turn; }
+      draw_all_wins (&win_meta);
+      key = getch();
+      if      (key == get_action_key(world.keybindings, "player down"))
+        move_player(&world, 's');
+      else if (key == get_action_key(world.keybindings, "player up"))
+        move_player(&world, 'n');
+      else if (key == get_action_key(world.keybindings, "player right"))
+        move_player(&world, 'e');
+      else if (key == get_action_key(world.keybindings, "player left"))
+        move_player(&world, 'w');
+      else if (key == get_action_key(world.keybindings, "wait / next turn"))
+        player_wait (&world);
+      else
+        quit_called = meta_keys(key, &world, &win_meta, &win_keys, &win_map, &win_info, &win_log);
+        if (1 == quit_called)
+          break; } }
+
+  free(map.cells);
+  for (key = 0; key <= world.keyswindata->max; key++)
+    free(world.keybindings[key].name);
+  free(world.keybindings);
+  free(world.keyswindata);
+  free(world.log);
+
+  endwin();
+  return 0; }
diff --git a/src/roguelike.h b/src/roguelike.h
new file mode 100644 (file)
index 0000000..d82313e
--- /dev/null
@@ -0,0 +1,40 @@
+struct World {
+  char interactive;
+  struct KeyBinding * keybindings;
+  struct KeysWinData * keyswindata;
+  uint32_t seed;
+  uint32_t turn;
+  char * log;
+  struct Map * map;
+  struct Monster * monster;
+  struct Player * player; };
+
+struct Map {
+  uint16_t width;
+  uint16_t height;
+  uint16_t offset_x;
+  uint16_t offset_y;
+  char * cells; };
+
+struct Player {
+  uint16_t y;
+  uint16_t x; };
+
+struct Monster {
+  uint16_t y;
+  uint16_t x; };
+
+uint16_t rrand(char, uint32_t);
+void save_game(struct World *);
+void toggle_window (struct WinMeta *, struct Win *);
+void scroll_pad (struct WinMeta *, char);
+void growshrink_active_window (struct WinMeta *, char);
+struct Map init_map ();
+void map_scroll (struct Map *, char);
+void next_turn (struct World *);
+void update_log (struct World *, char *);
+char is_passable (struct Map *, uint16_t, uint16_t);
+void record_action (char);
+void move_player (struct World *, char);
+void player_wait(struct World *);
+unsigned char meta_keys(int, struct World *, struct WinMeta *, struct Win *, struct Win *, struct Win *, struct Win *);
diff --git a/src/windows.c b/src/windows.c
new file mode 100644 (file)
index 0000000..98c8cf8
--- /dev/null
@@ -0,0 +1,300 @@
+#include <stdlib.h>
+#include <stdint.h>
+#include <ncurses.h>
+#include <string.h>
+#include "windows.h"
+
+struct Corners {
+  struct yx_uint16 tl;
+  struct yx_uint16 tr;
+  struct yx_uint16 bl;
+  struct yx_uint16 br; };
+
+static void refit_pad (struct WinMeta *);
+static void place_win (struct WinMeta *, struct Win *);
+static void update_wins (struct WinMeta *, struct Win *);
+static void destroy_win (struct Win *);
+static void draw_wins_borders (struct Win *, struct Win *, struct Corners *, uint16_t);
+static void draw_win_borders (struct Win *, char);
+static void draw_wins (struct Win *);
+
+extern struct WinMeta init_win_meta (WINDOW * screen) {
+// Create and populate WinMeta struct with sane default values.
+  struct WinMeta wmeta;
+  wmeta.screen = screen;
+  wmeta.pad.size.y = getmaxy(screen);
+  wmeta.pad.size.x = getmaxx(screen);
+  wmeta.chain_start = 0;
+  wmeta.chain_end = 0;
+  wmeta.pad_offset = 0;
+  wmeta.pad.curses_win = newpad(wmeta.pad.size.y, 1);
+  wmeta.active = 0;
+  return wmeta; }
+
+extern struct Win init_win (struct WinMeta * wmeta, char * title, void * data, void * func) {
+// Create and populate Win struct with sane default values.
+  struct Win w;
+  w.prev = 0;
+  w.next = 0;
+  w.frame.curses_win = 0;
+  w.title = title;
+  w.frame.size.x = 20;
+  w.frame.size.y = wmeta->pad.size.y - 1;
+  w.data = data;
+  w.draw = func;
+  return w; }
+
+extern void append_win (struct WinMeta * wmeta, struct Win * w) {
+// Append win to window chain. Set active, if first window. Update geometry of windows from new window on.
+  if (0 != wmeta->chain_start) {
+    w->prev = wmeta->chain_end;
+    wmeta->chain_end->next = w; }
+  else {
+    wmeta->active = w;
+    wmeta->chain_start = w; }
+  wmeta->chain_end = w;
+  update_wins(wmeta, w); }
+
+static void refit_pad (struct WinMeta * wmeta) {
+// Fit pad width to minimum width demanded by current windows' geometries.
+  uint16_t lastwincol = 0;
+  struct Win * w_p = wmeta->chain_start;
+  while (w_p != 0) {
+    if (w_p->start.x + w_p->frame.size.x > lastwincol + 1)
+      lastwincol = w_p->start.x + w_p->frame.size.x - 1;
+    w_p = w_p->next; }
+  if (getmaxx(wmeta->pad.curses_win) != lastwincol)
+    wresize(wmeta->pad.curses_win, getmaxy(wmeta->pad.curses_win), lastwincol + 2); }
+
+extern void suspend_win (struct WinMeta * wmeta, struct Win * w) {
+// Destroy win, suspend from chain. Update geometry of following rows and pad, as well as activity selection.
+  destroy_win(w);
+  if (wmeta->chain_start != w)         // Give win's position in the chain to element next to it in the chain.
+    w->prev->next = w->next;
+  else
+    wmeta->chain_start = w->next;
+  char pad_refitted = 0;
+  if (wmeta->chain_end != w) {                      // Let chain element next to win know its new predecessor.
+    w->next->prev = w->prev;
+    if (wmeta->active == w)                               // If win was active, shift active window pointer to
+      wmeta->active = w->next;                            // the next chain element, if that is a window ...
+    update_wins(wmeta, w->next);
+    pad_refitted = 1; }
+  else {
+    wmeta->chain_end = w->prev;
+    if (wmeta->active == w)                                            // ... or else to the previous element.
+      wmeta->active = w->prev; }
+  w->prev = 0;
+  w->next = 0;
+  if (0 == pad_refitted)                                                            // Refit pad if necessary.
+    refit_pad(wmeta); }
+
+static void place_win (struct WinMeta * wmeta, struct Win * w) {
+// Based on position and sizes of previous window, find fitting place for current window.
+  w->start.x = 0;                                  // if window is first in chain, place it on top-left corner
+  w->start.y = 1;
+  if (0 != w->prev) {
+    struct Win * w_top = w->prev;
+    while (w_top->start.y != 1)
+      w_top = w_top->prev;                                       // else, default to placing window in new top
+    w->start.x = w_top->start.x + w_top->frame.size.x + 1;       // column to the right of the last one
+    uint16_t w_prev_maxy = w->prev->start.y + getmaxy(w->prev->frame.curses_win);
+    if (w->frame.size.x <= w->prev->frame.size.x && w->frame.size.y < wmeta->pad.size.y - w_prev_maxy) {
+      w->start.x = w->prev->start.x;                       // place window below previous window if it fits
+      w->start.y = w_prev_maxy + 1; }                      // vertically and is not wider than its predecessor
+    else {
+      struct Win * w_up = w->prev;
+      struct Win * w_upup = w_up;
+      uint16_t widthdiff;
+      while (w_up != w_top) {
+        w_upup = w_up->prev;
+        while (1) {
+          if (w_up->start.y != w_upup->start.y)
+            break;
+          w_upup = w_upup->prev; }
+        w_prev_maxy = w_upup->start.y + getmaxy(w_upup->frame.curses_win);
+        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->pad.size.y - w_prev_maxy && w->frame.size.x < widthdiff) {
+          w->start.x = w_up->start.x + w_up->frame.size.x + 1 ; // else try to open new sub column under
+          w->start.y = w_prev_maxy + 1;                        // last window below which enough space remains
+          break; }
+        w_up = w_upup; } } } }
+
+static void update_wins (struct WinMeta * wmeta, struct Win * w) {
+// Update geometry of win and its next of kin. Destroy (if visible), (re-)build window. If need, resize pad.
+  if (0 != w->frame.curses_win)
+    destroy_win (w);
+  place_win(wmeta, w);
+  refit_pad(wmeta);
+  w->frame.curses_win=subpad(wmeta->pad.curses_win, w->frame.size.y, w->frame.size.x, w->start.y, w->start.x);
+  if (0 != w->next)
+    update_wins (wmeta, w->next); }
+
+static void destroy_win (struct Win * w) {
+// Delete window.
+  delwin(w->frame.curses_win);
+  w->frame.curses_win = 0; }
+
+static void draw_win_borders (struct Win * w, char active) {
+// Draw borders of window win, including title. Decorate in a special way if window is marked as active.
+  uint16_t y, x;
+  for (y = w->start.y; y <= w->start.y + w->frame.size.y; y++) {
+    mvwaddch(wgetparent(w->frame.curses_win), y, w->start.x - 1, '|');
+    mvwaddch(wgetparent(w->frame.curses_win), y, w->start.x + w->frame.size.x, '|'); }
+  for (x = w->start.x; x <= w->start.x + w->frame.size.x; x++) {
+    mvwaddch(wgetparent(w->frame.curses_win), w->start.y - 1, x, '-');
+    mvwaddch(wgetparent(w->frame.curses_win), w->start.y + w->frame.size.y, x, '-'); }
+  char min_title_length_visible = 3;        // 1 char minimal, plus 2 chars for decoration left/right of title
+  if (w->frame.size.x >= min_title_length_visible) {
+    uint16_t title_offset = 0;
+    if (w->frame.size.x > strlen(w->title) + 2)
+      title_offset = (w->frame.size.x - (strlen(w->title) + 2)) / 2;                  // + 2 is for decoration
+    uint16_t length_visible = strnlen(w->title, w->frame.size.x - 2);
+    char title[length_visible + 3];
+    char decoration = ' ';
+    if (1 == active)
+      decoration = '$';
+    memcpy(title + 1, w->title, length_visible);
+    title[0] = title[length_visible + 1] = decoration;
+    title[length_visible + 2] = '\0';
+    mvwaddstr(wgetparent(w->frame.curses_win), w->start.y - 1, w->start.x + title_offset, title); } }
+
+static void draw_wins_borders (struct Win * w, struct Win * w_active, struct Corners * corners, uint16_t i) {
+// Call draw_win_borders() for all windows in chain from win on. Save current window's border corners.
+  char active = 0;
+  if (w == w_active)
+    active = 1;
+  draw_win_borders(w, active);
+  corners[i].tl.y = w->start.y - 1;
+  corners[i].tl.x = w->start.x - 1;
+  corners[i].tr.y = w->start.y - 1;
+  corners[i].tr.x = w->start.x + w->frame.size.x;
+  corners[i].bl.y = w->start.y + w->frame.size.y;
+  corners[i].bl.x = w->start.x - 1;
+  corners[i].br.y = w->start.y + w->frame.size.y;
+  corners[i].br.x = w->start.x + w->frame.size.x;
+  if (0 != w->next) {
+    draw_wins_borders (w->next, w_active, corners, i + 1); } }
+
+static void draw_wins (struct Win * w) {
+// Draw contents of all windows in window chain from win on.
+  w->draw(w);
+  if (0 != w->next) {
+    draw_wins (w->next); } }
+
+extern void draw_scroll_hint (struct Frame * frame, uint16_t pos, uint32_t dist, char dir) {
+// Draw scroll hint into frame at pos (row or col dependend on dir), mark distance of dist cells into dir.
+  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
+  sprintf(scrolldsc, " %d %s %s ", dist, more, unit);
+  char offset = 1, q;
+  if (dsc_space > strlen(scrolldsc) + 1)
+    offset = (dsc_space - strlen(scrolldsc)) / 2;
+  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); }
+
+extern void draw_all_wins (struct WinMeta * wmeta) {
+// Draw pad with all windows and their borders, plus scrolling hints.
+  erase();
+  wnoutrefresh(wmeta->screen);
+  werase(wmeta->pad.curses_win);
+  if (wmeta->chain_start) {
+    uint16_t n_wins = 1, i;
+    struct Win * win_p = wmeta->chain_start;
+    while (0 != win_p->next) {
+      win_p = win_p->next;
+      n_wins++; }
+    struct Corners * all_corners = malloc(sizeof(struct Corners) * n_wins);
+    draw_wins (wmeta->chain_start);
+    draw_wins_borders (wmeta->chain_start, wmeta->active, all_corners, 0);
+    for (i = 0; i < n_wins; i++) {
+      mvwaddch(wmeta->pad.curses_win, all_corners[i].tl.y, all_corners[i].tl.x, '+');
+      mvwaddch(wmeta->pad.curses_win, all_corners[i].tr.y, all_corners[i].tr.x, '+');
+      mvwaddch(wmeta->pad.curses_win, all_corners[i].bl.y, all_corners[i].bl.x, '+');
+      mvwaddch(wmeta->pad.curses_win, all_corners[i].br.y, all_corners[i].br.x, '+'); }
+    free(all_corners);
+    if (wmeta->pad_offset > 0)
+      draw_scroll_hint(&wmeta->pad, wmeta->pad_offset, wmeta->pad_offset + 1, '<');
+    if (wmeta->pad_offset + wmeta->pad.size.x < getmaxx(wmeta->pad.curses_win) - 1)
+      draw_scroll_hint(&wmeta->pad, wmeta->pad_offset + wmeta->pad.size.x - 1,
+                       getmaxx(wmeta->pad.curses_win) - (wmeta->pad_offset + wmeta->pad.size.x), '>');
+    pnoutrefresh(wmeta->pad.curses_win, 0, wmeta->pad_offset, 0, 0, wmeta->pad.size.y, wmeta->pad.size.x-1); }
+  doupdate(); }
+
+extern void resize_active_win (struct WinMeta * wmeta, uint16_t height, uint16_t width) {
+// Grow or shrink currently active window. Correct its geometry and that of its followers.
+  if (0 != wmeta->active && width > 0 && height > 0 && height < wmeta->pad.size.y) {
+    wmeta->active->frame.size.y = height;
+    wmeta->active->frame.size.x = width;
+    update_wins(wmeta, wmeta->chain_start); } }
+
+extern void cycle_active_win (struct WinMeta * wmeta, char dir) {
+// Cycle active window selection forwards (dir = 'n') or backwards.
+  if (0 != wmeta->active) {
+    if ('n' == dir) {
+      if (wmeta->active->next != 0)
+        wmeta->active = wmeta->active->next;
+      else
+        wmeta->active = wmeta->chain_start; }
+    else {
+      if (wmeta->active->prev != 0)
+        wmeta->active = wmeta->active->prev;
+      else
+        wmeta->active = wmeta->chain_end; } } }
+
+extern void shift_active_win (struct WinMeta * wmeta, char dir) {
+// Move active window forward/backward in window chain. If jumping beyond start/end, move to other chain end.
+  if (0 != wmeta->active && wmeta->chain_start != wmeta->chain_end && (dir == 'f' || dir == 'b')) {
+    struct Win * w_shift = wmeta->active, * w_p, * w_p_next;
+    char wrap = 0;
+    if ((dir == 'f' && w_shift == wmeta->chain_end) || (dir == 'b' && w_shift == wmeta->chain_start))
+      wrap = 1;
+    uint16_t i, i_max;
+    for (i_max = 1, w_p = wmeta->chain_start; w_p != wmeta->chain_end; i_max++)
+      w_p = w_p->next;
+    struct Win ** wins = malloc(i_max * sizeof(struct Win *));
+    for (i = 0, w_p = wmeta->chain_start; i < i_max; i++) {
+      w_p_next = w_p->next;
+      suspend_win(wmeta, w_p);
+      wins[i] = w_p;
+      w_p = w_p_next; }
+    if (wrap)
+      if (dir == 'f') {
+        append_win(wmeta, w_shift);
+        for (i = 0; i < i_max - 1; i++)
+          append_win(wmeta, wins[i]); }
+      else {
+        for (i = 1; i < i_max; i++)
+          append_win(wmeta, wins[i]);
+        append_win(wmeta, w_shift); }
+    else
+      for (i = 0; i < i_max; i++)
+        if ((dir == 'f' && w_shift == wins[i]) || (dir == 'b' && w_shift == wins[i+1])) {
+          append_win(wmeta, wins[i+1]);
+          append_win(wmeta, wins[i]);
+          i++; }
+        else
+          append_win(wmeta, wins[i]);
+    free(wins);
+    wmeta->active = w_shift; } }
+
+extern void reset_pad_offset(struct WinMeta * wmeta, uint16_t new_offset) {
+// Apply new_offset to windows pad, if it proves to be sane.
+  if (new_offset >= 0 && new_offset + wmeta->pad.size.x < getmaxx(wmeta->pad.curses_win))
+    wmeta->pad_offset = new_offset; }
diff --git a/src/windows.h b/src/windows.h
new file mode 100644 (file)
index 0000000..c194907
--- /dev/null
@@ -0,0 +1,35 @@
+struct yx_uint16 {
+  uint16_t y;
+  uint16_t x; };
+
+struct Frame {
+  WINDOW * curses_win;
+  struct yx_uint16 size; };
+
+struct WinMeta {
+  WINDOW * screen;
+  uint16_t pad_offset;
+  struct Frame pad;
+  struct Win * chain_start;
+  struct Win * chain_end;
+  struct Win * active; };
+
+struct Win {
+  struct Win * prev;
+  struct Win * next;
+  struct yx_uint16 start;
+  struct Frame frame;
+  char * title;
+  void (* draw) (struct Win *);
+  void * data; };
+
+extern struct WinMeta init_win_meta (WINDOW *);
+extern struct Win init_win (struct WinMeta *, char *, void *, void *);
+extern void append_win (struct WinMeta *, struct Win *);
+extern void suspend_win (struct WinMeta *, struct Win *);
+extern void draw_scroll_hint (struct Frame *, uint16_t, uint32_t, char);
+extern void draw_all_wins (struct WinMeta *);
+extern void resize_active_win (struct WinMeta *, uint16_t, uint16_t);
+extern void cycle_active_win (struct WinMeta *, char);
+extern void shift_active_win (struct WinMeta *, char);
+extern void reset_pad_offset (struct WinMeta *, uint16_t);
diff --git a/windows.c b/windows.c
deleted file mode 100644 (file)
index 98c8cf8..0000000
--- a/windows.c
+++ /dev/null
@@ -1,300 +0,0 @@
-#include <stdlib.h>
-#include <stdint.h>
-#include <ncurses.h>
-#include <string.h>
-#include "windows.h"
-
-struct Corners {
-  struct yx_uint16 tl;
-  struct yx_uint16 tr;
-  struct yx_uint16 bl;
-  struct yx_uint16 br; };
-
-static void refit_pad (struct WinMeta *);
-static void place_win (struct WinMeta *, struct Win *);
-static void update_wins (struct WinMeta *, struct Win *);
-static void destroy_win (struct Win *);
-static void draw_wins_borders (struct Win *, struct Win *, struct Corners *, uint16_t);
-static void draw_win_borders (struct Win *, char);
-static void draw_wins (struct Win *);
-
-extern struct WinMeta init_win_meta (WINDOW * screen) {
-// Create and populate WinMeta struct with sane default values.
-  struct WinMeta wmeta;
-  wmeta.screen = screen;
-  wmeta.pad.size.y = getmaxy(screen);
-  wmeta.pad.size.x = getmaxx(screen);
-  wmeta.chain_start = 0;
-  wmeta.chain_end = 0;
-  wmeta.pad_offset = 0;
-  wmeta.pad.curses_win = newpad(wmeta.pad.size.y, 1);
-  wmeta.active = 0;
-  return wmeta; }
-
-extern struct Win init_win (struct WinMeta * wmeta, char * title, void * data, void * func) {
-// Create and populate Win struct with sane default values.
-  struct Win w;
-  w.prev = 0;
-  w.next = 0;
-  w.frame.curses_win = 0;
-  w.title = title;
-  w.frame.size.x = 20;
-  w.frame.size.y = wmeta->pad.size.y - 1;
-  w.data = data;
-  w.draw = func;
-  return w; }
-
-extern void append_win (struct WinMeta * wmeta, struct Win * w) {
-// Append win to window chain. Set active, if first window. Update geometry of windows from new window on.
-  if (0 != wmeta->chain_start) {
-    w->prev = wmeta->chain_end;
-    wmeta->chain_end->next = w; }
-  else {
-    wmeta->active = w;
-    wmeta->chain_start = w; }
-  wmeta->chain_end = w;
-  update_wins(wmeta, w); }
-
-static void refit_pad (struct WinMeta * wmeta) {
-// Fit pad width to minimum width demanded by current windows' geometries.
-  uint16_t lastwincol = 0;
-  struct Win * w_p = wmeta->chain_start;
-  while (w_p != 0) {
-    if (w_p->start.x + w_p->frame.size.x > lastwincol + 1)
-      lastwincol = w_p->start.x + w_p->frame.size.x - 1;
-    w_p = w_p->next; }
-  if (getmaxx(wmeta->pad.curses_win) != lastwincol)
-    wresize(wmeta->pad.curses_win, getmaxy(wmeta->pad.curses_win), lastwincol + 2); }
-
-extern void suspend_win (struct WinMeta * wmeta, struct Win * w) {
-// Destroy win, suspend from chain. Update geometry of following rows and pad, as well as activity selection.
-  destroy_win(w);
-  if (wmeta->chain_start != w)         // Give win's position in the chain to element next to it in the chain.
-    w->prev->next = w->next;
-  else
-    wmeta->chain_start = w->next;
-  char pad_refitted = 0;
-  if (wmeta->chain_end != w) {                      // Let chain element next to win know its new predecessor.
-    w->next->prev = w->prev;
-    if (wmeta->active == w)                               // If win was active, shift active window pointer to
-      wmeta->active = w->next;                            // the next chain element, if that is a window ...
-    update_wins(wmeta, w->next);
-    pad_refitted = 1; }
-  else {
-    wmeta->chain_end = w->prev;
-    if (wmeta->active == w)                                            // ... or else to the previous element.
-      wmeta->active = w->prev; }
-  w->prev = 0;
-  w->next = 0;
-  if (0 == pad_refitted)                                                            // Refit pad if necessary.
-    refit_pad(wmeta); }
-
-static void place_win (struct WinMeta * wmeta, struct Win * w) {
-// Based on position and sizes of previous window, find fitting place for current window.
-  w->start.x = 0;                                  // if window is first in chain, place it on top-left corner
-  w->start.y = 1;
-  if (0 != w->prev) {
-    struct Win * w_top = w->prev;
-    while (w_top->start.y != 1)
-      w_top = w_top->prev;                                       // else, default to placing window in new top
-    w->start.x = w_top->start.x + w_top->frame.size.x + 1;       // column to the right of the last one
-    uint16_t w_prev_maxy = w->prev->start.y + getmaxy(w->prev->frame.curses_win);
-    if (w->frame.size.x <= w->prev->frame.size.x && w->frame.size.y < wmeta->pad.size.y - w_prev_maxy) {
-      w->start.x = w->prev->start.x;                       // place window below previous window if it fits
-      w->start.y = w_prev_maxy + 1; }                      // vertically and is not wider than its predecessor
-    else {
-      struct Win * w_up = w->prev;
-      struct Win * w_upup = w_up;
-      uint16_t widthdiff;
-      while (w_up != w_top) {
-        w_upup = w_up->prev;
-        while (1) {
-          if (w_up->start.y != w_upup->start.y)
-            break;
-          w_upup = w_upup->prev; }
-        w_prev_maxy = w_upup->start.y + getmaxy(w_upup->frame.curses_win);
-        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->pad.size.y - w_prev_maxy && w->frame.size.x < widthdiff) {
-          w->start.x = w_up->start.x + w_up->frame.size.x + 1 ; // else try to open new sub column under
-          w->start.y = w_prev_maxy + 1;                        // last window below which enough space remains
-          break; }
-        w_up = w_upup; } } } }
-
-static void update_wins (struct WinMeta * wmeta, struct Win * w) {
-// Update geometry of win and its next of kin. Destroy (if visible), (re-)build window. If need, resize pad.
-  if (0 != w->frame.curses_win)
-    destroy_win (w);
-  place_win(wmeta, w);
-  refit_pad(wmeta);
-  w->frame.curses_win=subpad(wmeta->pad.curses_win, w->frame.size.y, w->frame.size.x, w->start.y, w->start.x);
-  if (0 != w->next)
-    update_wins (wmeta, w->next); }
-
-static void destroy_win (struct Win * w) {
-// Delete window.
-  delwin(w->frame.curses_win);
-  w->frame.curses_win = 0; }
-
-static void draw_win_borders (struct Win * w, char active) {
-// Draw borders of window win, including title. Decorate in a special way if window is marked as active.
-  uint16_t y, x;
-  for (y = w->start.y; y <= w->start.y + w->frame.size.y; y++) {
-    mvwaddch(wgetparent(w->frame.curses_win), y, w->start.x - 1, '|');
-    mvwaddch(wgetparent(w->frame.curses_win), y, w->start.x + w->frame.size.x, '|'); }
-  for (x = w->start.x; x <= w->start.x + w->frame.size.x; x++) {
-    mvwaddch(wgetparent(w->frame.curses_win), w->start.y - 1, x, '-');
-    mvwaddch(wgetparent(w->frame.curses_win), w->start.y + w->frame.size.y, x, '-'); }
-  char min_title_length_visible = 3;        // 1 char minimal, plus 2 chars for decoration left/right of title
-  if (w->frame.size.x >= min_title_length_visible) {
-    uint16_t title_offset = 0;
-    if (w->frame.size.x > strlen(w->title) + 2)
-      title_offset = (w->frame.size.x - (strlen(w->title) + 2)) / 2;                  // + 2 is for decoration
-    uint16_t length_visible = strnlen(w->title, w->frame.size.x - 2);
-    char title[length_visible + 3];
-    char decoration = ' ';
-    if (1 == active)
-      decoration = '$';
-    memcpy(title + 1, w->title, length_visible);
-    title[0] = title[length_visible + 1] = decoration;
-    title[length_visible + 2] = '\0';
-    mvwaddstr(wgetparent(w->frame.curses_win), w->start.y - 1, w->start.x + title_offset, title); } }
-
-static void draw_wins_borders (struct Win * w, struct Win * w_active, struct Corners * corners, uint16_t i) {
-// Call draw_win_borders() for all windows in chain from win on. Save current window's border corners.
-  char active = 0;
-  if (w == w_active)
-    active = 1;
-  draw_win_borders(w, active);
-  corners[i].tl.y = w->start.y - 1;
-  corners[i].tl.x = w->start.x - 1;
-  corners[i].tr.y = w->start.y - 1;
-  corners[i].tr.x = w->start.x + w->frame.size.x;
-  corners[i].bl.y = w->start.y + w->frame.size.y;
-  corners[i].bl.x = w->start.x - 1;
-  corners[i].br.y = w->start.y + w->frame.size.y;
-  corners[i].br.x = w->start.x + w->frame.size.x;
-  if (0 != w->next) {
-    draw_wins_borders (w->next, w_active, corners, i + 1); } }
-
-static void draw_wins (struct Win * w) {
-// Draw contents of all windows in window chain from win on.
-  w->draw(w);
-  if (0 != w->next) {
-    draw_wins (w->next); } }
-
-extern void draw_scroll_hint (struct Frame * frame, uint16_t pos, uint32_t dist, char dir) {
-// Draw scroll hint into frame at pos (row or col dependend on dir), mark distance of dist cells into dir.
-  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
-  sprintf(scrolldsc, " %d %s %s ", dist, more, unit);
-  char offset = 1, q;
-  if (dsc_space > strlen(scrolldsc) + 1)
-    offset = (dsc_space - strlen(scrolldsc)) / 2;
-  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); }
-
-extern void draw_all_wins (struct WinMeta * wmeta) {
-// Draw pad with all windows and their borders, plus scrolling hints.
-  erase();
-  wnoutrefresh(wmeta->screen);
-  werase(wmeta->pad.curses_win);
-  if (wmeta->chain_start) {
-    uint16_t n_wins = 1, i;
-    struct Win * win_p = wmeta->chain_start;
-    while (0 != win_p->next) {
-      win_p = win_p->next;
-      n_wins++; }
-    struct Corners * all_corners = malloc(sizeof(struct Corners) * n_wins);
-    draw_wins (wmeta->chain_start);
-    draw_wins_borders (wmeta->chain_start, wmeta->active, all_corners, 0);
-    for (i = 0; i < n_wins; i++) {
-      mvwaddch(wmeta->pad.curses_win, all_corners[i].tl.y, all_corners[i].tl.x, '+');
-      mvwaddch(wmeta->pad.curses_win, all_corners[i].tr.y, all_corners[i].tr.x, '+');
-      mvwaddch(wmeta->pad.curses_win, all_corners[i].bl.y, all_corners[i].bl.x, '+');
-      mvwaddch(wmeta->pad.curses_win, all_corners[i].br.y, all_corners[i].br.x, '+'); }
-    free(all_corners);
-    if (wmeta->pad_offset > 0)
-      draw_scroll_hint(&wmeta->pad, wmeta->pad_offset, wmeta->pad_offset + 1, '<');
-    if (wmeta->pad_offset + wmeta->pad.size.x < getmaxx(wmeta->pad.curses_win) - 1)
-      draw_scroll_hint(&wmeta->pad, wmeta->pad_offset + wmeta->pad.size.x - 1,
-                       getmaxx(wmeta->pad.curses_win) - (wmeta->pad_offset + wmeta->pad.size.x), '>');
-    pnoutrefresh(wmeta->pad.curses_win, 0, wmeta->pad_offset, 0, 0, wmeta->pad.size.y, wmeta->pad.size.x-1); }
-  doupdate(); }
-
-extern void resize_active_win (struct WinMeta * wmeta, uint16_t height, uint16_t width) {
-// Grow or shrink currently active window. Correct its geometry and that of its followers.
-  if (0 != wmeta->active && width > 0 && height > 0 && height < wmeta->pad.size.y) {
-    wmeta->active->frame.size.y = height;
-    wmeta->active->frame.size.x = width;
-    update_wins(wmeta, wmeta->chain_start); } }
-
-extern void cycle_active_win (struct WinMeta * wmeta, char dir) {
-// Cycle active window selection forwards (dir = 'n') or backwards.
-  if (0 != wmeta->active) {
-    if ('n' == dir) {
-      if (wmeta->active->next != 0)
-        wmeta->active = wmeta->active->next;
-      else
-        wmeta->active = wmeta->chain_start; }
-    else {
-      if (wmeta->active->prev != 0)
-        wmeta->active = wmeta->active->prev;
-      else
-        wmeta->active = wmeta->chain_end; } } }
-
-extern void shift_active_win (struct WinMeta * wmeta, char dir) {
-// Move active window forward/backward in window chain. If jumping beyond start/end, move to other chain end.
-  if (0 != wmeta->active && wmeta->chain_start != wmeta->chain_end && (dir == 'f' || dir == 'b')) {
-    struct Win * w_shift = wmeta->active, * w_p, * w_p_next;
-    char wrap = 0;
-    if ((dir == 'f' && w_shift == wmeta->chain_end) || (dir == 'b' && w_shift == wmeta->chain_start))
-      wrap = 1;
-    uint16_t i, i_max;
-    for (i_max = 1, w_p = wmeta->chain_start; w_p != wmeta->chain_end; i_max++)
-      w_p = w_p->next;
-    struct Win ** wins = malloc(i_max * sizeof(struct Win *));
-    for (i = 0, w_p = wmeta->chain_start; i < i_max; i++) {
-      w_p_next = w_p->next;
-      suspend_win(wmeta, w_p);
-      wins[i] = w_p;
-      w_p = w_p_next; }
-    if (wrap)
-      if (dir == 'f') {
-        append_win(wmeta, w_shift);
-        for (i = 0; i < i_max - 1; i++)
-          append_win(wmeta, wins[i]); }
-      else {
-        for (i = 1; i < i_max; i++)
-          append_win(wmeta, wins[i]);
-        append_win(wmeta, w_shift); }
-    else
-      for (i = 0; i < i_max; i++)
-        if ((dir == 'f' && w_shift == wins[i]) || (dir == 'b' && w_shift == wins[i+1])) {
-          append_win(wmeta, wins[i+1]);
-          append_win(wmeta, wins[i]);
-          i++; }
-        else
-          append_win(wmeta, wins[i]);
-    free(wins);
-    wmeta->active = w_shift; } }
-
-extern void reset_pad_offset(struct WinMeta * wmeta, uint16_t new_offset) {
-// Apply new_offset to windows pad, if it proves to be sane.
-  if (new_offset >= 0 && new_offset + wmeta->pad.size.x < getmaxx(wmeta->pad.curses_win))
-    wmeta->pad_offset = new_offset; }
diff --git a/windows.h b/windows.h
deleted file mode 100644 (file)
index c194907..0000000
--- a/windows.h
+++ /dev/null
@@ -1,35 +0,0 @@
-struct yx_uint16 {
-  uint16_t y;
-  uint16_t x; };
-
-struct Frame {
-  WINDOW * curses_win;
-  struct yx_uint16 size; };
-
-struct WinMeta {
-  WINDOW * screen;
-  uint16_t pad_offset;
-  struct Frame pad;
-  struct Win * chain_start;
-  struct Win * chain_end;
-  struct Win * active; };
-
-struct Win {
-  struct Win * prev;
-  struct Win * next;
-  struct yx_uint16 start;
-  struct Frame frame;
-  char * title;
-  void (* draw) (struct Win *);
-  void * data; };
-
-extern struct WinMeta init_win_meta (WINDOW *);
-extern struct Win init_win (struct WinMeta *, char *, void *, void *);
-extern void append_win (struct WinMeta *, struct Win *);
-extern void suspend_win (struct WinMeta *, struct Win *);
-extern void draw_scroll_hint (struct Frame *, uint16_t, uint32_t, char);
-extern void draw_all_wins (struct WinMeta *);
-extern void resize_active_win (struct WinMeta *, uint16_t, uint16_t);
-extern void cycle_active_win (struct WinMeta *, char);
-extern void shift_active_win (struct WinMeta *, char);
-extern void reset_pad_offset (struct WinMeta *, uint16_t);