From 07ffb403f548c95e54e660283f13f81622112f41 Mon Sep 17 00:00:00 2001 From: Andrew Hamilton Date: Tue, 17 Jul 2018 08:58:29 +1000 Subject: [PATCH] Made scrollbars more accurate. - Used unicode characters to have fractional lengthed bars. - Don't allow specifing a scrollbar character anymore. You can give the bar's color and background color. --- tests/fill3_test.py | 44 +++++++++++++++++++++++++-------------- vigil/fill3.py | 50 ++++++++++++++++++++++++++++++++++----------- 2 files changed, 67 insertions(+), 27 deletions(-) diff --git a/tests/fill3_test.py b/tests/fill3_test.py index f165edc..767199d 100755 --- a/tests/fill3_test.py +++ b/tests/fill3_test.py @@ -7,6 +7,7 @@ import unittest import vigil.fill3 as fill3 +import vigil.termstr as termstr class WidgetTests(unittest.TestCase): @@ -70,30 +71,43 @@ class WidgetTests(unittest.TestCase): placeholder.widget = self.TEXT_B self.assert_string(placeholder.appearance_min(), "B") + def assert_string2(self, appearance, expected_string): + self.assertEqual( + ("\n".join(line.data for line in appearance), + "".join("i" if style.fg_color==termstr.Color.black else " " + for line in appearance for style in line.style)), + expected_string) + def test_scroll_bar(self): - scroll_bar = fill3.ScrollBar(is_horizontal=True, bar_char="#") + scroll_bar = fill3.ScrollBar(is_horizontal=True) self.assertEqual(scroll_bar.interval, (0, 0)) - self.assert_string(scroll_bar.appearance((1, 1)), "#") + self.assert_string2(scroll_bar.appearance((1, 1)), (" ", "i")) scroll_bar.interval = (0, 0.5) - self.assert_string(scroll_bar.appearance((2, 1)), "# ") + self.assert_string2(scroll_bar.appearance((2, 1)), (" ", "i ")) scroll_bar.interval = (0, 0.1) - self.assert_string(scroll_bar.appearance((2, 1)), "# ") + self.assert_string2(scroll_bar.appearance((2, 1)), (" ", "i ")) scroll_bar.interval = (0.25, 0.75) - self.assert_string(scroll_bar.appearance((4, 1)), " ## ") - scroll_bar = fill3.ScrollBar(is_horizontal=False, bar_char="#") + self.assert_string2(scroll_bar.appearance((4, 1)), (" █ ", " i ")) + scroll_bar.interval = (0, 0.75) + self.assert_string2(scroll_bar.appearance((2, 1)), (" ▌", "i ")) + + scroll_bar = fill3.ScrollBar(is_horizontal=False) self.assertEqual(scroll_bar.interval, (0, 0)) - self.assert_string(scroll_bar.appearance((1, 1)), "#") + self.assert_string2(scroll_bar.appearance((1, 1)), ("█", " ")) scroll_bar.interval = (0, 0.5) - self.assert_string(scroll_bar.appearance((1, 2)), "#\n" - " ") + self.assert_string2(scroll_bar.appearance((1, 2)), ("█\n" + "█", " i")) scroll_bar.interval = (0, 0.1) - self.assert_string(scroll_bar.appearance((1, 2)), "#\n" - " ") + self.assert_string2(scroll_bar.appearance((1, 2)), ("█\n" + "█", " i")) scroll_bar.interval = (0.25, 0.75) - self.assert_string(scroll_bar.appearance((1, 4)), " \n" - "#\n" - "#\n" - " ") + self.assert_string2(scroll_bar.appearance((1, 4)), (" \n" + "█\n" + "█\n" + "█", " i")) + scroll_bar.interval = (0, 0.75) + self.assert_string2(scroll_bar.appearance((1, 2)), ("█\n" + "▄", " i")) def test_table_widget(self): table = fill3.Table([]) diff --git a/vigil/fill3.py b/vigil/fill3.py index 59e1b06..a9f10a1 100644 --- a/vigil/fill3.py +++ b/vigil/fill3.py @@ -179,15 +179,30 @@ class Filler: class ScrollBar: - _GREY_BACKGROUND_STYLE = termstr.CharStyle(bg_color=termstr.Color.grey_100) - _GREY_BLOCK = termstr.TermStr(" ", _GREY_BACKGROUND_STYLE) + _HORIZONTAL_CHARS = [" ", "▏", "▎", "▍", "▌", "▋", "▊", "▉"] + _VERTICAL_CHARS = ["█", "▇", "▆", "▅", "▄", "▃", "▂", "▁"] - def __init__(self, is_horizontal, interval=(0, 0), bar_char=_GREY_BLOCK, - background_char=" "): + def __init__(self, is_horizontal, interval=(0, 0), + bar_color=termstr.Color.grey_100, + background_color=termstr.Color.black): self._is_horizontal = is_horizontal self.interval = interval - self.bar_char = bar_char - self.background_char = background_char + self.bar_color = bar_color + self.background_color = background_color + self.bar_char = termstr.TermStr("█").fg_color(bar_color) + self.background_char = termstr.TermStr(" ").bg_color(background_color) + self.start_h_chars = [termstr.TermStr(char).fg_color( + self.background_color).bg_color(self.bar_color) + for char in self._HORIZONTAL_CHARS] + self.end_h_chars = [termstr.TermStr(char).fg_color( + self.bar_color).bg_color(self.background_color) + for char in self._HORIZONTAL_CHARS] + self.start_v_chars = [termstr.TermStr(char).fg_color( + self.bar_color).bg_color(self.background_color) + for char in self._VERTICAL_CHARS] + self.end_v_chars = [termstr.TermStr(char).fg_color( + self.background_color).bg_color(self.bar_color) + for char in self._VERTICAL_CHARS] def appearance(self, dimensions): width, height = dimensions @@ -195,13 +210,24 @@ class ScrollBar: length = width if self._is_horizontal else height assert all(0 <= fraction <= 1 for fraction in self.interval), \ self.interval - start_index, end_index = [int(fraction * length) - for fraction in self.interval] - if start_index == end_index and end_index < length: - end_index += 1 + (start_index, start_remainder), (end_index, end_remainder) = \ + [divmod(fraction * length * 8, 8) for fraction in self.interval] + start_index, end_index = int(start_index), int(end_index) + start_remainder, end_remainder = \ + int(start_remainder), int(end_remainder) + if start_index == end_index: + end_index, end_remainder = start_index + 1, start_remainder + elif end_index == start_index + 1: + end_remainder = max(start_remainder, end_remainder) + start_chars, end_chars = ((self.start_h_chars, self.end_h_chars) + if self._is_horizontal + else (self.start_v_chars, self.end_v_chars)) bar = (self.background_char * start_index + - self.bar_char * (end_index - start_index) + - self.background_char * (length - end_index)) + start_chars[start_remainder] + + self.bar_char * (end_index - start_index - 1) + + end_chars[end_remainder] + + self.background_char * (length - end_index - 1)) + bar = bar[:length] return [bar] if self._is_horizontal else [char for char in bar]