Rectify listview behaviour
This commit is contained in:
parent
563c278771
commit
f0c7092521
182
nncmpp.c
182
nncmpp.c
|
@ -947,66 +947,76 @@ app_redraw (void)
|
||||||
|
|
||||||
// --- Actions -----------------------------------------------------------------
|
// --- Actions -----------------------------------------------------------------
|
||||||
|
|
||||||
/// Scroll up @a n items. Doesn't redraw.
|
static int
|
||||||
|
app_visible_items (void)
|
||||||
|
{
|
||||||
|
// This may eventually include a header bar and/or a status bar
|
||||||
|
return MAX (0, LINES - g_ctx.top_height);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks what items that are visible and returns if fixes were needed
|
||||||
static bool
|
static bool
|
||||||
app_scroll_up (int n)
|
app_fix_view_range (void)
|
||||||
{
|
{
|
||||||
struct tab *tab = g_ctx.active_tab;
|
struct tab *tab = g_ctx.active_tab;
|
||||||
if (tab->item_top < n)
|
if (tab->item_top < 0)
|
||||||
{
|
{
|
||||||
tab->item_top = 0;
|
tab->item_top = 0;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
tab->item_top -= n;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Scroll down @a n items. Doesn't redraw.
|
// If the contents are at least as long as the screen, always fill it
|
||||||
static bool
|
int max_item_top = (int) tab->item_count - app_visible_items ();
|
||||||
app_scroll_down (int n)
|
// But don't let that suggest a negative offset
|
||||||
|
max_item_top = MAX (max_item_top, 0);
|
||||||
|
|
||||||
|
if (tab->item_top > max_item_top)
|
||||||
{
|
{
|
||||||
struct tab *tab = g_ctx.active_tab;
|
tab->item_top = max_item_top;
|
||||||
// TODO: if (n_items >= lines), don't allow to scroll off past the end
|
|
||||||
if ((tab->item_top += n) >= (int) tab->item_count)
|
|
||||||
{
|
|
||||||
if (tab->item_count)
|
|
||||||
tab->item_top = tab->item_count - 1;
|
|
||||||
else
|
|
||||||
tab->item_top = 0;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Moves the selection one item up.
|
/// Scroll down (positive) or up (negative) @a n items. Doesn't redraw.
|
||||||
static bool
|
static bool
|
||||||
app_one_item_up (void)
|
app_scroll (int n)
|
||||||
|
{
|
||||||
|
g_ctx.active_tab->item_top += n;
|
||||||
|
return app_fix_view_range ();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
app_ensure_selection_visible (void)
|
||||||
{
|
{
|
||||||
struct tab *tab = g_ctx.active_tab;
|
struct tab *tab = g_ctx.active_tab;
|
||||||
if (tab->item_selected < 1)
|
if (tab->item_selected < 0)
|
||||||
return false;
|
return;
|
||||||
|
|
||||||
if (--tab->item_selected < tab->item_top)
|
int too_high = tab->item_top - tab->item_selected;
|
||||||
app_scroll_up (tab->item_top - tab->item_selected);
|
if (too_high > 0)
|
||||||
|
app_scroll (-too_high);
|
||||||
|
|
||||||
|
int too_low = tab->item_selected
|
||||||
|
- (tab->item_top + app_visible_items () - 1);
|
||||||
|
if (too_low > 0)
|
||||||
|
app_scroll (too_low);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
app_move_selection (int diff)
|
||||||
|
{
|
||||||
|
struct tab *tab = g_ctx.active_tab;
|
||||||
|
int fixed = tab->item_selected += diff;
|
||||||
|
fixed = MAX (fixed, 0);
|
||||||
|
fixed = MIN (fixed, (int) tab->item_count - 1);
|
||||||
|
|
||||||
|
bool result = tab->item_selected != fixed;
|
||||||
|
tab->item_selected = fixed;
|
||||||
|
|
||||||
|
app_ensure_selection_visible ();
|
||||||
app_redraw_view ();
|
app_redraw_view ();
|
||||||
return true;
|
return result;
|
||||||
}
|
|
||||||
|
|
||||||
/// Moves the selection one item down.
|
|
||||||
static bool
|
|
||||||
app_one_item_down (void)
|
|
||||||
{
|
|
||||||
struct tab *tab = g_ctx.active_tab;
|
|
||||||
if (tab->item_selected + 1 >= (int) tab->item_count)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
int n_visible = LINES - g_ctx.top_height;
|
|
||||||
if (++tab->item_selected >= tab->item_top + n_visible)
|
|
||||||
app_scroll_down (1);
|
|
||||||
|
|
||||||
app_redraw_view ();
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
@ -1023,25 +1033,6 @@ app_goto_tab (int tab_index)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
app_process_resize (void)
|
|
||||||
{
|
|
||||||
struct tab *tab = g_ctx.active_tab;
|
|
||||||
if (tab->item_selected < 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
int n_visible = LINES - g_ctx.top_height;
|
|
||||||
if (n_visible < 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Scroll up as needed to keep the selection visible
|
|
||||||
int selected_offset = tab->item_selected - tab->item_top;
|
|
||||||
if (selected_offset >= n_visible)
|
|
||||||
app_scroll_up (selected_offset - n_visible + 1);
|
|
||||||
|
|
||||||
app_redraw ();
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- User input handling -----------------------------------------------------
|
// --- User input handling -----------------------------------------------------
|
||||||
|
|
||||||
enum user_action
|
enum user_action
|
||||||
|
@ -1058,6 +1049,11 @@ enum user_action
|
||||||
USER_ACTION_MPD_VOLUME_UP,
|
USER_ACTION_MPD_VOLUME_UP,
|
||||||
USER_ACTION_MPD_VOLUME_DOWN,
|
USER_ACTION_MPD_VOLUME_DOWN,
|
||||||
|
|
||||||
|
USER_ACTION_SCROLL_UP,
|
||||||
|
USER_ACTION_SCROLL_DOWN,
|
||||||
|
|
||||||
|
USER_ACTION_GOTO_TOP,
|
||||||
|
USER_ACTION_GOTO_BOTTOM,
|
||||||
USER_ACTION_GOTO_ITEM_PREVIOUS,
|
USER_ACTION_GOTO_ITEM_PREVIOUS,
|
||||||
USER_ACTION_GOTO_ITEM_NEXT,
|
USER_ACTION_GOTO_ITEM_NEXT,
|
||||||
USER_ACTION_GOTO_PAGE_PREVIOUS,
|
USER_ACTION_GOTO_PAGE_PREVIOUS,
|
||||||
|
@ -1081,6 +1077,7 @@ static bool
|
||||||
app_process_user_action (enum user_action action)
|
app_process_user_action (enum user_action action)
|
||||||
{
|
{
|
||||||
struct mpd_client *c = &g_ctx.client;
|
struct mpd_client *c = &g_ctx.client;
|
||||||
|
struct tab *tab = g_ctx.active_tab;
|
||||||
switch (action)
|
switch (action)
|
||||||
{
|
{
|
||||||
case USER_ACTION_QUIT:
|
case USER_ACTION_QUIT:
|
||||||
|
@ -1131,20 +1128,48 @@ app_process_user_action (enum user_action action)
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
// XXX: these should rather be parametrized
|
||||||
|
case USER_ACTION_SCROLL_UP:
|
||||||
|
app_scroll (-3);
|
||||||
|
app_redraw_view ();
|
||||||
|
return true;
|
||||||
|
case USER_ACTION_SCROLL_DOWN:
|
||||||
|
app_scroll (3);
|
||||||
|
app_redraw_view ();
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case USER_ACTION_GOTO_TOP:
|
||||||
|
if (tab->item_count)
|
||||||
|
{
|
||||||
|
g_ctx.active_tab->item_selected = 0;
|
||||||
|
app_ensure_selection_visible ();
|
||||||
|
app_redraw_view ();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
case USER_ACTION_GOTO_BOTTOM:
|
||||||
|
if (tab->item_count)
|
||||||
|
{
|
||||||
|
g_ctx.active_tab->item_selected =
|
||||||
|
(int) g_ctx.active_tab->item_count - 1;
|
||||||
|
app_ensure_selection_visible ();
|
||||||
|
app_redraw_view ();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
case USER_ACTION_GOTO_ITEM_PREVIOUS:
|
case USER_ACTION_GOTO_ITEM_PREVIOUS:
|
||||||
app_one_item_up ();
|
app_move_selection (-1);
|
||||||
return true;
|
return true;
|
||||||
case USER_ACTION_GOTO_ITEM_NEXT:
|
case USER_ACTION_GOTO_ITEM_NEXT:
|
||||||
app_one_item_down ();
|
app_move_selection (1);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case USER_ACTION_GOTO_PAGE_PREVIOUS:
|
case USER_ACTION_GOTO_PAGE_PREVIOUS:
|
||||||
app_scroll_up (LINES - (int) g_ctx.top_height);
|
app_scroll ((int) g_ctx.top_height - LINES);
|
||||||
app_redraw_view ();
|
app_move_selection ((int) g_ctx.top_height - LINES);
|
||||||
return true;
|
return true;
|
||||||
case USER_ACTION_GOTO_PAGE_NEXT:
|
case USER_ACTION_GOTO_PAGE_NEXT:
|
||||||
app_scroll_down (LINES - (int) g_ctx.top_height);
|
app_scroll (LINES - (int) g_ctx.top_height);
|
||||||
app_redraw_view ();
|
app_move_selection (LINES - (int) g_ctx.top_height);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -1240,9 +1265,9 @@ app_process_mouse (termo_key_t *event)
|
||||||
if (button == 1)
|
if (button == 1)
|
||||||
app_process_left_mouse_click (line, column);
|
app_process_left_mouse_click (line, column);
|
||||||
else if (button == 4)
|
else if (button == 4)
|
||||||
app_process_user_action (USER_ACTION_GOTO_ITEM_PREVIOUS);
|
app_process_user_action (USER_ACTION_SCROLL_UP);
|
||||||
else if (button == 5)
|
else if (button == 5)
|
||||||
app_process_user_action (USER_ACTION_GOTO_ITEM_NEXT);
|
app_process_user_action (USER_ACTION_SCROLL_DOWN);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1259,8 +1284,12 @@ g_default_bindings[] =
|
||||||
{ "Escape", USER_ACTION_QUIT },
|
{ "Escape", USER_ACTION_QUIT },
|
||||||
{ "C-l", USER_ACTION_REDRAW },
|
{ "C-l", USER_ACTION_REDRAW },
|
||||||
|
|
||||||
|
{ "Home", USER_ACTION_GOTO_TOP },
|
||||||
|
{ "End", USER_ACTION_GOTO_BOTTOM },
|
||||||
{ "Up", USER_ACTION_GOTO_ITEM_PREVIOUS },
|
{ "Up", USER_ACTION_GOTO_ITEM_PREVIOUS },
|
||||||
{ "Down", USER_ACTION_GOTO_ITEM_NEXT },
|
{ "Down", USER_ACTION_GOTO_ITEM_NEXT },
|
||||||
|
{ "k", USER_ACTION_GOTO_ITEM_PREVIOUS },
|
||||||
|
{ "j", USER_ACTION_GOTO_ITEM_NEXT },
|
||||||
{ "PageUp", USER_ACTION_GOTO_PAGE_PREVIOUS },
|
{ "PageUp", USER_ACTION_GOTO_PAGE_PREVIOUS },
|
||||||
{ "PageDown", USER_ACTION_GOTO_PAGE_NEXT },
|
{ "PageDown", USER_ACTION_GOTO_PAGE_NEXT },
|
||||||
{ "C-p", USER_ACTION_GOTO_ITEM_PREVIOUS },
|
{ "C-p", USER_ACTION_GOTO_ITEM_PREVIOUS },
|
||||||
|
@ -1270,9 +1299,11 @@ g_default_bindings[] =
|
||||||
|
|
||||||
// Not sure how to set these up, they're pretty arbitrary so far
|
// Not sure how to set these up, they're pretty arbitrary so far
|
||||||
{ "Left", USER_ACTION_MPD_PREVIOUS },
|
{ "Left", USER_ACTION_MPD_PREVIOUS },
|
||||||
|
{ "Right", USER_ACTION_MPD_NEXT },
|
||||||
|
{ "h", USER_ACTION_MPD_PREVIOUS },
|
||||||
|
{ "l", USER_ACTION_MPD_NEXT },
|
||||||
{ "Space", USER_ACTION_MPD_TOGGLE },
|
{ "Space", USER_ACTION_MPD_TOGGLE },
|
||||||
{ "C-Space", USER_ACTION_MPD_STOP },
|
{ "C-Space", USER_ACTION_MPD_STOP },
|
||||||
{ "Right", USER_ACTION_MPD_NEXT },
|
|
||||||
{ "M-PageUp", USER_ACTION_MPD_VOLUME_UP },
|
{ "M-PageUp", USER_ACTION_MPD_VOLUME_UP },
|
||||||
{ "M-PageDown", USER_ACTION_MPD_VOLUME_DOWN },
|
{ "M-PageDown", USER_ACTION_MPD_VOLUME_DOWN },
|
||||||
{ NULL, USER_ACTION_NONE },
|
{ NULL, USER_ACTION_NONE },
|
||||||
|
@ -1305,11 +1336,6 @@ app_process_termo_event (termo_key_t *event)
|
||||||
beep ();
|
beep ();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!event->modifiers)
|
|
||||||
{
|
|
||||||
// TODO: normal unmodified keys will have functions as well
|
|
||||||
ucs4_t c = event->code.codepoint;
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1740,7 +1766,15 @@ app_on_signal_pipe_readable (const struct pollfd *fd, void *user_data)
|
||||||
if (g_winch_received)
|
if (g_winch_received)
|
||||||
{
|
{
|
||||||
update_curses_terminal_size ();
|
update_curses_terminal_size ();
|
||||||
app_process_resize ();
|
app_redraw_top ();
|
||||||
|
|
||||||
|
app_fix_view_range ();
|
||||||
|
#if SELECTION_SHOULD_BE_VISIBLE_AFTER_RESIZE
|
||||||
|
// First we had to make the assumptions of this valid
|
||||||
|
app_ensure_selection_visible ();
|
||||||
|
#endif
|
||||||
|
app_redraw_view ();
|
||||||
|
|
||||||
g_winch_received = false;
|
g_winch_received = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue