Rectify listview behaviour

This commit is contained in:
Přemysl Eric Janouch 2016-10-03 04:00:56 +02:00
parent 563c278771
commit f0c7092521
Signed by: p
GPG Key ID: B715679E3A361BE6
1 changed files with 105 additions and 71 deletions

176
nncmpp.c
View File

@ -947,66 +947,76 @@ app_redraw (void)
// --- 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
app_scroll_up (int n)
app_fix_view_range (void)
{
struct tab *tab = g_ctx.active_tab;
if (tab->item_top < n)
if (tab->item_top < 0)
{
tab->item_top = 0;
return false;
}
tab->item_top -= n;
return true;
}
/// Scroll down @a n items. Doesn't redraw.
static bool
app_scroll_down (int n)
{
struct tab *tab = g_ctx.active_tab;
// TODO: if (n_items >= lines), don't allow to scroll off past the end
if ((tab->item_top += n) >= (int) tab->item_count)
// If the contents are at least as long as the screen, always fill it
int max_item_top = (int) tab->item_count - app_visible_items ();
// But don't let that suggest a negative offset
max_item_top = MAX (max_item_top, 0);
if (tab->item_top > max_item_top)
{
if (tab->item_count)
tab->item_top = tab->item_count - 1;
else
tab->item_top = 0;
tab->item_top = max_item_top;
return false;
}
return true;
}
/// Moves the selection one item up.
/// Scroll down (positive) or up (negative) @a n items. Doesn't redraw.
static bool
app_one_item_up (void)
app_scroll (int n)
{
struct tab *tab = g_ctx.active_tab;
if (tab->item_selected < 1)
return false;
if (--tab->item_selected < tab->item_top)
app_scroll_up (tab->item_top - tab->item_selected);
app_redraw_view ();
return true;
g_ctx.active_tab->item_top += n;
return app_fix_view_range ();
}
/// Moves the selection one item down.
static bool
app_one_item_down (void)
static void
app_ensure_selection_visible (void)
{
struct tab *tab = g_ctx.active_tab;
if (tab->item_selected + 1 >= (int) tab->item_count)
return false;
if (tab->item_selected < 0)
return;
int n_visible = LINES - g_ctx.top_height;
if (++tab->item_selected >= tab->item_top + n_visible)
app_scroll_down (1);
int too_high = 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 ();
return true;
return result;
}
static bool
@ -1023,25 +1033,6 @@ app_goto_tab (int tab_index)
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 -----------------------------------------------------
enum user_action
@ -1058,6 +1049,11 @@ enum user_action
USER_ACTION_MPD_VOLUME_UP,
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_NEXT,
USER_ACTION_GOTO_PAGE_PREVIOUS,
@ -1081,6 +1077,7 @@ static bool
app_process_user_action (enum user_action action)
{
struct mpd_client *c = &g_ctx.client;
struct tab *tab = g_ctx.active_tab;
switch (action)
{
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:
app_one_item_up ();
app_move_selection (-1);
return true;
case USER_ACTION_GOTO_ITEM_NEXT:
app_one_item_down ();
app_move_selection (1);
return true;
case USER_ACTION_GOTO_PAGE_PREVIOUS:
app_scroll_up (LINES - (int) g_ctx.top_height);
app_redraw_view ();
app_scroll ((int) g_ctx.top_height - LINES);
app_move_selection ((int) g_ctx.top_height - LINES);
return true;
case USER_ACTION_GOTO_PAGE_NEXT:
app_scroll_down (LINES - (int) g_ctx.top_height);
app_redraw_view ();
app_scroll (LINES - (int) g_ctx.top_height);
app_move_selection (LINES - (int) g_ctx.top_height);
return true;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -1240,9 +1265,9 @@ app_process_mouse (termo_key_t *event)
if (button == 1)
app_process_left_mouse_click (line, column);
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)
app_process_user_action (USER_ACTION_GOTO_ITEM_NEXT);
app_process_user_action (USER_ACTION_SCROLL_DOWN);
return true;
}
@ -1259,8 +1284,12 @@ g_default_bindings[] =
{ "Escape", USER_ACTION_QUIT },
{ "C-l", USER_ACTION_REDRAW },
{ "Home", USER_ACTION_GOTO_TOP },
{ "End", USER_ACTION_GOTO_BOTTOM },
{ "Up", USER_ACTION_GOTO_ITEM_PREVIOUS },
{ "Down", USER_ACTION_GOTO_ITEM_NEXT },
{ "k", USER_ACTION_GOTO_ITEM_PREVIOUS },
{ "j", USER_ACTION_GOTO_ITEM_NEXT },
{ "PageUp", USER_ACTION_GOTO_PAGE_PREVIOUS },
{ "PageDown", USER_ACTION_GOTO_PAGE_NEXT },
{ "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
{ "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 },
{ "C-Space", USER_ACTION_MPD_STOP },
{ "Right", USER_ACTION_MPD_NEXT },
{ "M-PageUp", USER_ACTION_MPD_VOLUME_UP },
{ "M-PageDown", USER_ACTION_MPD_VOLUME_DOWN },
{ NULL, USER_ACTION_NONE },
@ -1305,11 +1336,6 @@ app_process_termo_event (termo_key_t *event)
beep ();
return true;
}
if (!event->modifiers)
{
// TODO: normal unmodified keys will have functions as well
ucs4_t c = event->code.codepoint;
}
return true;
}
@ -1740,7 +1766,15 @@ app_on_signal_pipe_readable (const struct pollfd *fd, void *user_data)
if (g_winch_received)
{
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;
}
}