mirror of
https://github.com/rkd77/elinks.git
synced 2024-12-04 14:46:47 -05:00
Rewrite the better part of scroll_menu so that it is more readable
and wraps properly when the first or last items on a menu are unselectable. Drop search_selectable, which is now unnecessary.
This commit is contained in:
parent
9bc71ec8a9
commit
82850fab29
@ -254,80 +254,57 @@ count_menu_size(struct terminal *term, struct menu *menu)
|
||||
int_bounds(&menu->box.y, 0, height - my);
|
||||
}
|
||||
|
||||
static int
|
||||
search_selectable(struct menu *menu, int pos, int dir)
|
||||
{
|
||||
assert(pos >= 0 && pos < menu->size && (dir == 1 || dir == -1));
|
||||
if_assert_failed return -1;
|
||||
|
||||
while (!mi_is_selectable(&menu->items[pos])) {
|
||||
if (dir > 0 && pos == menu->size - 1)
|
||||
return -1;
|
||||
else if (dir < 0 && pos == 0)
|
||||
return -1;
|
||||
|
||||
pos += dir;
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
static void
|
||||
scroll_menu(struct menu *menu, int steps, int wrap)
|
||||
{
|
||||
int height, scr_i, pos;
|
||||
int height, scr_i, pos, start;
|
||||
int s = steps ? steps/abs(steps) : 1; /* Selectable item search direction. */
|
||||
|
||||
if (menu->size <= 0) {
|
||||
no_item:
|
||||
/* Menu is empty. */
|
||||
menu->selected = -1;
|
||||
menu->first = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Move by required steps and handle wraparound if needed.
|
||||
* A step of zero can be used, indicating we want to select
|
||||
* item corresponding to |menu->selected| value rather than
|
||||
* moving by to a position relative to this value.
|
||||
* We override search direction for selectable items if we encounter
|
||||
* a limit, since it depends in which conditions this limit is
|
||||
* attained. */
|
||||
menu->selected += steps;
|
||||
if (menu->selected >= menu->size) {
|
||||
start = pos = menu->selected;
|
||||
|
||||
if (!steps) steps = 1;
|
||||
|
||||
while (steps) {
|
||||
pos += s, steps -= s;
|
||||
|
||||
while (1) {
|
||||
if (start == pos) {
|
||||
goto select_item;
|
||||
} else if (pos >= menu->size && s == 1) {
|
||||
if (wrap) {
|
||||
menu->selected = 0;
|
||||
s = 1;
|
||||
pos = 0;
|
||||
} else {
|
||||
menu->selected = int_max(0, menu->size - 1);
|
||||
s = -1;
|
||||
pos = menu->size - 1;
|
||||
goto select_item;
|
||||
}
|
||||
} else if (menu->selected < 0) {
|
||||
} else if (pos < 0 && s == -1) {
|
||||
if (wrap) {
|
||||
menu->selected = int_max(0, menu->size - 1);
|
||||
s = -1;
|
||||
pos = menu->size - 1;
|
||||
} else {
|
||||
menu->selected = 0;
|
||||
s = 1;
|
||||
pos = 0;
|
||||
goto select_item;
|
||||
}
|
||||
} else if (!mi_is_selectable(&menu->items[pos])) {
|
||||
pos += s;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
if (start == -1) start = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Current selected item may be an unselectable item, so we need to
|
||||
* find first selectable item near to it.
|
||||
* @s = 1 : ascending search.
|
||||
* @s = -1: descending search. */
|
||||
|
||||
/* Search first selectable item in one direction. */
|
||||
pos = search_selectable(menu, menu->selected, s);
|
||||
if (pos == -1) {
|
||||
/* If not found, invert the search direction and try again. */
|
||||
pos = search_selectable(menu, menu->selected, -s);
|
||||
}
|
||||
|
||||
/* No selectable item found, just return. */
|
||||
if (pos == -1) {
|
||||
menu->selected = -1;
|
||||
menu->first = 0;
|
||||
}
|
||||
select_item:
|
||||
if (!mi_is_selectable(&menu->items[pos]))
|
||||
goto no_item;
|
||||
|
||||
menu->selected = pos;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user