+ {
+ 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)
+{
+ if (0 != wmeta->active /* No shifting with less */
+ && wmeta->chain_start != wmeta->chain_end /* than one window visible. */
+ && (dir == 'f' || dir == 'b'))
+ {
+ struct Win * w_shift = wmeta->active, * w_p, * w_p_next;
+
+ /* Check if shifting will lead to wrapping. */
+ char wrap = 0;
+ if ( (dir == 'f' && w_shift == wmeta->chain_end)
+ || (dir == 'b' && w_shift == wmeta->chain_start))
+ {
+ wrap = 1;
+ }
+
+ /* Suspend all visible windows. */
+ 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;
+ }
+
+ /* Re-append all previously visible windows in the new order. */
+ 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; /* TODO: Is this necessary? If so, why? */
+ }
+}
+
+
+
+extern void draw_all_wins(struct WinMeta * wmeta)
+{
+ /* Empty everything before filling it a-new. */
+ erase();
+ wnoutrefresh(wmeta->screen);
+ werase(wmeta->pad.curses_win);
+ if (wmeta->chain_start)
+ {
+
+ /* Only draw the windows' *contents* first. */
+ draw_wins (wmeta->chain_start);
+
+ /* Draw windows' borders. Lines first, then line crossings / corners. */
+ 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_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);
+
+ /* Draw virtual screen scroll hints. */
+ 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), '>');
+ }
+
+ /* Write virtual screen segment to be shown on physical screen into */
+ /* ncurses screen buffer. */
+ pnoutrefresh(wmeta->pad.curses_win, 0, wmeta->pad_offset, 0, 0,
+ wmeta->pad.size.y, wmeta->pad.size.x-1);
+ }
+
+ /* Only at the end write accumulated changes to the physical screen. */
+ doupdate();
+}
+
+
+
+extern void draw_scroll_hint(struct Frame * frame, uint16_t pos, uint32_t dist,
+ char dir)
+{
+ /* Decide on alignment (vertical/horizontal?), thereby scroll hint text. */
+ char * more = "more";
+ char * unit_cols = "columns";
+ char * unit_rows = "lines";
+ uint16_t dsc_space = frame->size.x;
+ char * unit = unit_rows;
+ if ('<' == dir || '>' == dir)
+ {
+ dsc_space = frame->size.y;
+ unit = unit_cols;
+ }
+ char * scrolldsc = malloc((4 * sizeof(char)) + strlen(more) + strlen(unit)
+ + 10); /* 10 = uint32 max strlen */
+ sprintf(scrolldsc, " %d %s %s ", dist, more, unit);
+
+ /* Decide on offset of the description text inside the scroll hint line. */
+ char offset = 1, q;
+ if (dsc_space > strlen(scrolldsc) + 1)
+ {
+ offset = (dsc_space - strlen(scrolldsc)) / 2;
+ }
+
+ /* Draw scroll hint line as dir symbols bracketing description text. */
+ chtype symbol;
+ for (q = 0; q < dsc_space; q++)
+ {
+ if (q >= offset && q < strlen(scrolldsc) + offset)
+ {
+ symbol = scrolldsc[q - offset] | A_REVERSE;
+ }
+ else
+ {
+ symbol = dir | A_REVERSE;
+ }
+ if ('<' == dir || '>' == dir)
+ {
+ mvwaddch(frame->curses_win, q, pos, symbol);
+ }
+ else
+ {
+ mvwaddch(frame->curses_win, pos, q, symbol);
+ }
+ }
+
+ free(scrolldsc);
+}