diff options
| -rw-r--r-- | nncmpp.c | 168 | 
1 files changed, 101 insertions, 67 deletions
| @@ -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) +{ +	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; -	if (tab->item_selected < 1) -		return false; +	if (tab->item_selected < 0) +		return; -	if (--tab->item_selected < tab->item_top) -		app_scroll_up (tab->item_top - tab->item_selected); +	int too_high = tab->item_top - tab->item_selected; +	if (too_high > 0) +		app_scroll (-too_high); -	app_redraw_view (); -	return true; +	int too_low = tab->item_selected +		- (tab->item_top + app_visible_items () - 1); +	if (too_low > 0) +		app_scroll (too_low);  } -/// Moves the selection one item down.  static bool -app_one_item_down (void) +app_move_selection (int diff)  {  	struct tab *tab = g_ctx.active_tab; -	if (tab->item_selected + 1 >= (int) tab->item_count) -		return false; +	int fixed = tab->item_selected += diff; +	fixed = MAX (fixed, 0); +	fixed = MIN (fixed, (int) tab->item_count - 1); -	int n_visible = LINES - g_ctx.top_height; -	if (++tab->item_selected >= tab->item_top + n_visible) -		app_scroll_down (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;  	}  } | 
