+ {
+ unit = "columns";
+ }
+ struct yx_uint16 start = w->start;
+ scroll_hint(wm, &w->frame, dir, dist, unit, start);
+}
+
+
+
+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)
+ {
+ return draw_wins(wm, w->next);
+ }
+ return 0;
+}
+
+
+
+static void draw_win_borderlines(struct Win * w, char active, WINDOW * pad)
+{
+ /* Draw vertical and horizontal border lines. */
+ uint16_t y, x;
+ for (y = w->start.y; y <= w->start.y + w->frame.size.y; y++)
+ {
+ mvwaddch(pad, y, w->start.x - 1, '|');
+ mvwaddch(pad, y, w->start.x + w->frame.size.x, '|');
+ }
+ for (x = w->start.x; x <= w->start.x + w->frame.size.x; x++)
+ {
+ mvwaddch(pad, w->start.y - 1, x, '-');
+ mvwaddch(pad, w->start.y + w->frame.size.y, x, '-');
+ }
+
+ /* Draw as much as possible of the title into center of top border line. */
+ char min_title_length_visible = 3; /* min. 1 char + 2 padding/decoration */
+ if (w->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 padding/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(pad, w->start.y - 1, w->start.x + title_offset, title);
+ }
+}
+
+
+
+static void draw_wins_borderlines(struct Win * w, struct Win * w_active,
+ WINDOW * pad)
+{
+ char active = 0;
+ if (w == w_active)
+ {
+ active = 1;
+ }
+ draw_win_borderlines(w, active, pad);
+ if (0 != w->next)
+ {
+ draw_wins_borderlines(w->next, w_active, pad);
+ }
+}
+
+
+
+static void draw_wins_bordercorners(struct Win * w, WINDOW * pad)
+{
+ mvwaddch(pad, w->start.y - 1, w->start.x - 1, '+');
+ mvwaddch(pad, w->start.y - 1, w->start.x + w->frame.size.x, '+');
+ mvwaddch(pad, w->start.y + w->frame.size.y, w->start.x - 1, '+');
+ mvwaddch(pad,
+ w->start.y + w->frame.size.y, w->start.x + w->frame.size.x, '+');
+ if (0 != w->next)
+ {
+ draw_wins_bordercorners(w->next, pad);
+ }
+}
+
+
+
+static void shift_win_forward(struct WinMeta * wmeta)
+{
+ if (wmeta->active == wmeta->chain_end)
+ {
+ wmeta->chain_end = wmeta->active->prev;
+ wmeta->chain_end->next = 0;
+ wmeta->active->next = wmeta->chain_start;
+ wmeta->active->next->prev = wmeta->active;
+ wmeta->chain_start = wmeta->active;
+ wmeta->chain_start->prev = 0;
+ }
+ else
+ {
+ struct Win * old_prev = wmeta->active->prev;
+ struct Win * old_next = wmeta->active->next;
+ if (wmeta->chain_end == wmeta->active->next)
+ {
+ wmeta->chain_end = wmeta->active;
+ wmeta->active->next = 0;
+ }
+ else
+ {
+ wmeta->active->next = old_next->next;
+ wmeta->active->next->prev = wmeta->active;
+ }
+ if (wmeta->chain_start == wmeta->active)
+ {
+ wmeta->chain_start = old_next;
+ }
+ else
+ {
+ old_prev->next = old_next;
+ }
+ old_next->prev = old_prev;
+ old_next->next = wmeta->active;
+ wmeta->active->prev = old_next;
+ }
+}
+
+
+
+static void shift_win_backward(struct WinMeta * wmeta)
+{
+ if (wmeta->active == wmeta->chain_start)
+ {
+ wmeta->chain_start = wmeta->active->next;
+ wmeta->chain_start->prev = 0;
+ wmeta->active->prev = wmeta->chain_end;
+ wmeta->active->prev->next = wmeta->active;
+ wmeta->chain_end = wmeta->active;
+ wmeta->chain_end->next = 0;
+ }
+ else
+ {
+ struct Win * old_prev = wmeta->active->prev;
+ struct Win * old_next = wmeta->active->next;
+ if (wmeta->chain_start == wmeta->active->prev)
+ {
+ wmeta->chain_start = wmeta->active;
+ wmeta->active->prev = 0;
+ }
+ else
+ {
+ wmeta->active->prev = old_prev->prev;
+ wmeta->active->prev->next = wmeta->active;
+ }
+ if (wmeta->chain_end == wmeta->active)
+ {
+ wmeta->chain_end = old_prev;
+ }
+ else
+ {
+ old_next->prev = old_prev;
+ }
+ old_prev->next = old_next;
+ old_prev->prev = wmeta->active;
+ wmeta->active->next = old_prev;
+ }
+}
+
+
+
+extern uint8_t init_win_meta(WINDOW * screen, struct WinMeta ** wmp)
+{
+ struct WinMeta * wmeta = malloc(sizeof(struct WinMeta));
+ wmeta->screen = screen;
+ uint32_t maxy_test = getmaxy(screen);
+ uint32_t maxx_test = getmaxx(screen);
+ if (maxy_test > UINT16_MAX || maxx_test > UINT16_MAX)
+ {
+ return 2;
+ }
+ wmeta->padframe.size.y = maxy_test;
+ wmeta->padframe.size.x = maxx_test;
+ wmeta->chain_start = 0;
+ wmeta->chain_end = 0;
+ wmeta->pad_offset = 0;
+ WINDOW * pad_test = newpad(wmeta->padframe.size.y, 1);
+ if (NULL == pad_test)
+ {
+ return 1;
+ }
+ wmeta->padframe.curses_win = pad_test;
+ wmeta->active = 0;
+ *wmp = wmeta;
+ return 0;
+}
+
+
+
+extern uint8_t init_win(struct WinMeta * wmeta, struct Win ** wp, char * title,
+ int16_t height, int16_t width,
+ void * data, void * func)
+{
+ struct Win * w = malloc(sizeof(struct Win));
+ if (NULL == w)
+ {
+ return 1;
+ }
+ w->prev = 0;
+ w->next = 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->draw = func;
+ w->center.y = 0;
+ w->center.x = 0;
+ if (0 < width)
+ {
+ w->frame.size.x = width;
+ }
+ else if (0 >= width)
+ {
+ w->frame.size.x = wmeta->padframe.size.x + width;
+ }
+ if (0 < height && height <= wmeta->padframe.size.y - 1)
+ {
+ w->frame.size.y = height;
+ }
+ else if (0 >= height && wmeta->padframe.size.y + (height - 1) > 0)
+ {
+ w->frame.size.y = wmeta->padframe.size.y + (height - 1);
+ }
+ *wp = w;
+ return 0;
+}
+
+
+
+extern void free_winmeta(struct WinMeta * wmeta)
+{
+ delwin(wmeta->padframe.curses_win);
+ free(wmeta);
+}
+
+
+
+extern void free_win(struct Win * win)
+{
+ delwin(win->frame.curses_win);
+ free(win->title);
+ free(win);
+}
+
+
+
+extern uint8_t append_win(struct WinMeta * wmeta, struct Win * w)
+{
+ if (0 != wmeta->chain_start)
+ {
+ w->prev = wmeta->chain_end;
+ wmeta->chain_end->next = w;
+ }