Browse Source

Add re-layout of Qnav blocks on terminal resize

Previously, the Qnav blocks (the menu panels) would have their position
determined once when they're first created, and then never updated. The
positioning of Qnav blocks is determined by some code that may cause the
blocks to wrap or be positioned differently depending on how much screen
space is available. For example, if you open a nested menu that's three
blocks/panels deep, and the third panel doesn't have enough room on the
right in the terminal, it may be shown below the second panel instead of
to the right.

This had a flaw. If the user resized their terminal after the menus were
already open, the positions of the menu panels wouldn't be adjusted to
accommodate the new screen size. There wasn't a way to trigger a full
re-layout of all the menu items when the terminal was resized.

This commit adds qnav_adjust_term_size(), which is called from
tui_main.c when the terminal is resized. This function will re-layout
the menu panels.
master
cancel 4 years ago
parent
commit
acac9a5ac6
  1. 52
      term_util.c
  2. 1
      term_util.h
  3. 1
      tui_main.c

52
term_util.c

@ -70,18 +70,22 @@ void qnav_deinit() {
while (qnav_stack.top) while (qnav_stack.top)
qnav_stack_pop(); qnav_stack_pop();
} }
static ORCA_NOINLINE void qnav_stack_push(Qblock *qb, int height, int width) { // Set new y and x coordinates for the top and left of a Qblock based on the
#ifndef NDEBUG // position of the Qblock "below" it in the stack. (Below meaning its order in
for (Qblock *i = qnav_stack.top; i; i = i->down) { // the stack, not vertical position on a Y axis.) The target Qblock should
assert(i != qb); // already be inserted into the stack somewhere, so don't call this before
} // you've finished doing the rest of the setup on the Qblock. The y and x
#endif // fields can be junk, though, since this function writes to them without
// reading them.
static ORCA_NOINLINE void qnav_reposition_block(Qblock *qb) {
int top = 0, left = 0; int top = 0, left = 0;
int total_h = height + 2, total_w = width + 2; Qblock *prev = qb->down;
if (qnav_stack.top) { if (!prev)
WINDOW *w = qnav_stack.top->outer_window; goto done;
int prev_y, prev_x, prev_h, prev_w; int total_h, total_w;
getbegyx(w, prev_y, prev_x); getmaxyx(qb->outer_window, total_h, total_w);
WINDOW *w = prev->outer_window;
int prev_y = prev->y, prev_x = prev->x, prev_h, prev_w;
getmaxyx(w, prev_h, prev_w); getmaxyx(w, prev_h, prev_w);
// Start by trying to position the item to the right of the previous item. // Start by trying to position the item to the right of the previous item.
left = prev_x + prev_w + 0; left = prev_x + prev_w + 0;
@ -106,10 +110,21 @@ static ORCA_NOINLINE void qnav_stack_push(Qblock *qb, int height, int width) {
left = 0; left = 0;
} }
} }
done:
qb->y = top;
qb->x = left;
}
static ORCA_NOINLINE void qnav_stack_push(Qblock *qb, int height, int width) {
#ifndef NDEBUG
for (Qblock *i = qnav_stack.top; i; i = i->down) {
assert(i != qb);
}
#endif
int total_h = height + 2, total_w = width + 2;
if (qnav_stack.top)
qnav_stack.top->up = qb; qnav_stack.top->up = qb;
} else { else
qnav_stack.bottom = qb; qnav_stack.bottom = qb;
}
qb->down = qnav_stack.top; qb->down = qnav_stack.top;
qnav_stack.top = qb; qnav_stack.top = qb;
qb->outer_window = newpad(total_h, total_w); qb->outer_window = newpad(total_h, total_w);
@ -117,8 +132,7 @@ static ORCA_NOINLINE void qnav_stack_push(Qblock *qb, int height, int width) {
// if we should use derwin or subpad now. subpad is probably more compatible. // if we should use derwin or subpad now. subpad is probably more compatible.
// ncurses docs state that it handles it correctly, unlike some others? // ncurses docs state that it handles it correctly, unlike some others?
qb->content_window = subpad(qb->outer_window, height, width, 1, 1); qb->content_window = subpad(qb->outer_window, height, width, 1, 1);
qb->y = top; qnav_reposition_block(qb);
qb->x = left;
qnav_stack.occlusion_dirty = true; qnav_stack.occlusion_dirty = true;
} }
@ -216,6 +230,14 @@ done:
return drew_any; return drew_any;
} }
void qnav_adjust_term_size(void) {
if (!qnav_stack.bottom)
return;
for (Qblock *qb = qnav_stack.bottom; qb; qb = qb->up)
qnav_reposition_block(qb);
qnav_stack.occlusion_dirty = true;
}
void qblock_print_border(Qblock *qb, unsigned int attr) { void qblock_print_border(Qblock *qb, unsigned int attr) {
wborder(qb->outer_window, ACS_VLINE | attr, ACS_VLINE | attr, wborder(qb->outer_window, ACS_VLINE | attr, ACS_VLINE | attr,
ACS_HLINE | attr, ACS_HLINE | attr, ACS_ULCORNER | attr, ACS_HLINE | attr, ACS_HLINE | attr, ACS_ULCORNER | attr,

1
term_util.h

@ -120,6 +120,7 @@ void qnav_deinit(void);
Qblock *qnav_top_block(void); Qblock *qnav_top_block(void);
void qnav_stack_pop(void); void qnav_stack_pop(void);
bool qnav_draw(void); // also clear qnav_stack.occlusion_dirty bool qnav_draw(void); // also clear qnav_stack.occlusion_dirty
void qnav_adjust_term_size(void);
void qblock_print_frame(Qblock *qb, bool active); void qblock_print_frame(Qblock *qb, bool active);
void qblock_set_title(Qblock *qb, char const *title); void qblock_set_title(Qblock *qb, char const *title);

1
tui_main.c

@ -3523,6 +3523,7 @@ event_loop:;
} }
case KEY_RESIZE: case KEY_RESIZE:
tui_adjust_term_size(&t, &cont_window); tui_adjust_term_size(&t, &cont_window);
qnav_adjust_term_size();
goto event_loop; goto event_loop;
#ifndef FEAT_NOMOUSE #ifndef FEAT_NOMOUSE
case KEY_MOUSE: { case KEY_MOUSE: {

Loading…
Cancel
Save