diff --git a/LICENSE b/LICENSE index 44aed90..1d6387b 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2016 - 2017, Přemysl Janouch +Copyright (c) 2016 - 2018, Přemysl Janouch Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. diff --git a/nncmpp.c b/nncmpp.c index 6d6bde4..cb4f091 100644 --- a/nncmpp.c +++ b/nncmpp.c @@ -1,7 +1,7 @@ /* * nncmpp -- the MPD client you never knew you needed * - * Copyright (c) 2016 - 2017, Přemysl Janouch + * Copyright (c) 2016 - 2018, Přemysl Janouch * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted. @@ -66,6 +66,7 @@ enum #include "liberty/liberty.c" #include "liberty/liberty-tui.c" +#include #include #include #ifndef TIOCGWINSZ @@ -1171,6 +1172,29 @@ app_visible_items (void) return MAX (0, app_fitting_items ()); } +struct scrollbar { long length, start; } +app_compute_scrollbar (long top, long total, long visible) +{ + if (total < visible) + return (struct scrollbar) { 0, 0 }; + if (visible == 1) + return (struct scrollbar) { 1, 0 }; + if (visible == 2) + return (struct scrollbar) { 1, top >= total / 2 }; + + // Only be at the top or bottom when the top or bottom item can be seen. + // The algorithm isn't optimal but it's a bitch to get right. + double lenf = 1. + (visible - 2.) * visible / total, length = 0.; + long offset = 1. + (visible - 2.) * top / total + modf (lenf, &length); + + if (top == 0) + return (struct scrollbar) { length, 0 }; + if (top + visible >= total) + return (struct scrollbar) { length, visible - length }; + + return (struct scrollbar) { length, offset }; +} + static void app_draw_scrollbar (void) { @@ -1183,18 +1207,15 @@ app_draw_scrollbar (void) struct tab *tab = g.active_tab; int visible_items = app_visible_items (); + hard_assert (tab->item_count != 0); if (!g.use_partial_boxes) { - // Apparently here we don't want the 0.5 rounding constant - int length = (float) visible_items / (int) tab->item_count - * (visible_items - 1); - int start = (float) tab->item_top / (int) tab->item_count - * (visible_items - 1); - + struct scrollbar bar = app_compute_scrollbar + (tab->item_top, tab->item_count, visible_items); for (int row = 0; row < visible_items; row++) { move (g.header_height + row, COLS - 1); - if (row < start || row > start + length + 1) + if (row < bar.start || row >= bar.start + bar.length) addch (' ' | APP_ATTR (SCROLLBAR)); else addch (' ' | APP_ATTR (SCROLLBAR) | A_REVERSE);