From 94b4b3519706a490741ee255f5539f364c7fd3d4 Mon Sep 17 00:00:00 2001 From: Ivan Habunek Date: Sat, 8 Jul 2023 08:49:50 +0200 Subject: [PATCH 1/5] Tweak colors --- toot/tui/constants.py | 2 ++ toot/tui/timeline.py | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/toot/tui/constants.py b/toot/tui/constants.py index e672947..8e2bddf 100644 --- a/toot/tui/constants.py +++ b/toot/tui/constants.py @@ -26,6 +26,7 @@ PALETTE = [ ('status_list_timestamp', 'light blue', ''), # Functional + ('account', 'dark green', ''), ('hashtag', 'light cyan,bold', ''), ('hashtag_followed', 'yellow,bold', ''), ('link', ',italics', ''), @@ -75,6 +76,7 @@ MONO_PALETTE = [ ('warning', 'white,bold', 'black'), # Functional + ('account', 'white', ''), ('hashtag_followed', 'white,bold', ''), ('hashtag', 'white,bold', ''), ('link', ',italics', ''), diff --git a/toot/tui/timeline.py b/toot/tui/timeline.py index 8c46a00..13b867f 100644 --- a/toot/tui/timeline.py +++ b/toot/tui/timeline.py @@ -326,9 +326,9 @@ class StatusDetails(urwid.Pile): yield ("pack", urwid.AttrMap(urwid.Divider("-"), "dim")) if status.author.display_name: - yield ("pack", urwid.Text(("status_detail_author", status.author.display_name))) + yield ("pack", urwid.Text(("bold", status.author.display_name))) - account_color = "highlight" if status.author.account in self.followed_accounts else "dim" + account_color = "highlight" if status.author.account in self.followed_accounts else "account" yield ("pack", urwid.Text((account_color, status.author.account))) yield ("pack", urwid.Divider()) From 740f7fafd445883db089bab37f4e9dbb6334d489 Mon Sep 17 00:00:00 2001 From: Ivan Habunek Date: Fri, 7 Jul 2023 14:24:16 +0200 Subject: [PATCH 2/5] Read TUI palette overrides from settings --- toot/tui/app.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/toot/tui/app.py b/toot/tui/app.py index cac8454..cef1e85 100644 --- a/toot/tui/app.py +++ b/toot/tui/app.py @@ -3,7 +3,7 @@ import urwid from concurrent.futures import ThreadPoolExecutor -from toot import api, config, __version__ +from toot import api, config, __version__, settings from toot.console import get_default_visibility from toot.exceptions import ApiError @@ -88,9 +88,14 @@ class TUI(urwid.Frame): screen.set_terminal_properties(1) screen.reset_default_terminal_palette() + palette = MONO_PALETTE if args.no_color else PALETTE + overrides = settings.get_setting("tui.palette", dict, {}) + for name, styles in overrides.items(): + palette.append(tuple([name] + styles)) + loop = urwid.MainLoop( tui, - palette=MONO_PALETTE if args.no_color else PALETTE, + palette=palette, event_loop=urwid.AsyncioEventLoop(), unhandled_input=tui.unhandled_input, screen=screen, From 0903dae8d35d624d4edc44a6c3c1c8b3ff07afc1 Mon Sep 17 00:00:00 2001 From: Ivan Habunek Date: Sat, 8 Jul 2023 11:35:41 +0200 Subject: [PATCH 3/5] Read TUI colors from settings --- toot/tui/app.py | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/toot/tui/app.py b/toot/tui/app.py index cef1e85..833cb0b 100644 --- a/toot/tui/app.py +++ b/toot/tui/app.py @@ -78,15 +78,11 @@ class TUI(urwid.Frame): loop: urwid.MainLoop screen: urwid.BaseScreen - @classmethod - def create(cls, app, user, args): + @staticmethod + def create(app, user, args): """Factory method, sets up TUI and an event loop.""" - screen = urwid.raw_display.Screen() - tui = cls(app, user, screen, args) - - if args.no_color: - screen.set_terminal_properties(1) - screen.reset_default_terminal_palette() + screen = TUI.create_screen(args) + tui = TUI(app, user, screen, args) palette = MONO_PALETTE if args.no_color else PALETTE overrides = settings.get_setting("tui.palette", dict, {}) @@ -104,6 +100,18 @@ class TUI(urwid.Frame): return tui + @staticmethod + def create_screen(args): + screen = urwid.raw_display.Screen() + + # Determine how many colors to use + default_colors = 1 if args.no_color else 16 + colors = settings.get_setting("tui.colors", int, default_colors) + logger.debug(f"Setting colors to {colors}") + screen.set_terminal_properties(colors) + + return screen + def __init__(self, app, user, screen, args): self.app = app self.user = user From 0c0f889e3fbb4a44bb8c657956c660a908b74e25 Mon Sep 17 00:00:00 2001 From: Ivan Habunek Date: Sat, 8 Jul 2023 09:04:38 +0200 Subject: [PATCH 4/5] Add docs for overriding palette --- docs/settings.md | 59 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/docs/settings.md b/docs/settings.md index f128b7b..9d0fcd8 100644 --- a/docs/settings.md +++ b/docs/settings.md @@ -50,3 +50,62 @@ sensitive = true visibility = "unlisted" scheduled_in = "30 minutes" ``` + +## TUI color palette + +TUI uses Urwid which provides several color modes. See +[Urwid documentation](https://urwid.org/manual/displayattributes.html) +for more details. + +By default, TUI operates in 16-color mode which can be changed by setting the +`color` setting in the `[tui]` section to one of the following values: + +* `1` (monochrome) +* `16` (default) +* `88` +* `256` +* `16777216` (24 bit) + +TUI defines a list of colors which can be customized, currently they can be seen +[in the source code](https://github.com/ihabunek/toot/blob/master/toot/tui/constants.py). They can be overriden in the `[tui.palette]` section. + +Each color is defined as a list of upto 5 values: + +* foreground color (16 color mode) +* background color (16 color mode) +* monochrome color (monochrome mode) +* foreground color (high-color mode) +* background color (high-color mode) + +Any colors which are not used by your desired color mode can be skipped or set +to an empty string. + +For example, to change the button colors in 16 color mode: + +```toml +[tui.palette] +button = ["dark red,bold", ""] +button_focused = ["light gray", "green"] +``` + +In monochrome mode: + +```toml +[tui] +colors = 1 + +[tui.palette] +button = ["", "", "bold"] +button_focused = ["", "", "italics"] +``` + +In 256 color mode: + +```toml +[tui] +colors = 256 + +[tui.palette] +button = ["", "", "", "#aaa", "#bbb"] +button_focused = ["", "", "", "#aaa", "#bbb"] +``` From afd349f1aba0f3d10f300dab6bd4733da82e4db8 Mon Sep 17 00:00:00 2001 From: Ivan Habunek Date: Sat, 8 Jul 2023 12:30:49 +0200 Subject: [PATCH 5/5] Remove the monochrome palette Monochrome colors should be defined as the third color in each tuple instead. In monochrome mode it's not possible to set the background so all highlights can only be done using bold, italics, underline... --- tests/test_constants.py | 15 -------- toot/tui/app.py | 4 +-- toot/tui/constants.py | 78 +++++++++++------------------------------ 3 files changed, 22 insertions(+), 75 deletions(-) delete mode 100644 tests/test_constants.py diff --git a/tests/test_constants.py b/tests/test_constants.py deleted file mode 100644 index 60a15cf..0000000 --- a/tests/test_constants.py +++ /dev/null @@ -1,15 +0,0 @@ -from toot.tui.constants import PALETTE, MONO_PALETTE - - -def test_palette(): - # for every entry in PALETTE, there must be - # a corresponding entry in MONO_PALETTE - for pal in PALETTE: - matches = [item for item in MONO_PALETTE if item[0] == pal[0]] - assert len(matches) > 0, f"{pal}, present in PALETTE, missing from MONO_PALETTE" - - # for every entry in MONO_PALETTE, there must be - # a corresponding entry in PALETTE - for pal in MONO_PALETTE: - matches = [item for item in PALETTE if item[0] == pal[0]] - assert len(matches) > 0, f"{pal}, present in MONO_PALETTE, missing from PALETTE" diff --git a/toot/tui/app.py b/toot/tui/app.py index 833cb0b..9d78b12 100644 --- a/toot/tui/app.py +++ b/toot/tui/app.py @@ -8,7 +8,7 @@ from toot.console import get_default_visibility from toot.exceptions import ApiError from .compose import StatusComposer -from .constants import PALETTE, MONO_PALETTE +from .constants import PALETTE from .entities import Status from .overlays import ExceptionStackTrace, GotoMenu, Help, StatusSource, StatusLinks, StatusZoom from .overlays import StatusDeleteConfirmation, Account @@ -84,7 +84,7 @@ class TUI(urwid.Frame): screen = TUI.create_screen(args) tui = TUI(app, user, screen, args) - palette = MONO_PALETTE if args.no_color else PALETTE + palette = PALETTE.copy() overrides = settings.get_setting("tui.palette", dict, {}) for name, styles in overrides.items(): palette.append(tuple([name] + styles)) diff --git a/toot/tui/constants.py b/toot/tui/constants.py index 8e2bddf..91bb3b7 100644 --- a/toot/tui/constants.py +++ b/toot/tui/constants.py @@ -1,8 +1,19 @@ -# name, fg, bg, mono, fg_h, bg_h +# Color definitions are tuples of: +# - name +# - foreground (normal mode) +# - background (normal mode) +# - foreground (monochrome mode) +# - foreground (high color mode) +# - background (high color mode) +# +# See: +# http://urwid.org/tutorial/index.html#display-attributes +# http://urwid.org/manual/displayattributes.html#using-display-attributes + PALETTE = [ # Components ('button', 'white', 'black'), - ('button_focused', 'light gray', 'dark magenta'), + ('button_focused', 'light gray', 'dark magenta', 'bold,underline'), ('card_author', 'yellow', ''), ('card_title', 'dark green', ''), ('columns_divider', 'white', 'dark blue'), @@ -14,7 +25,7 @@ PALETTE = [ ('footer_status', 'white', 'dark blue'), ('footer_status_bold', 'white, bold', 'dark blue'), ('header', 'white', 'dark blue'), - ('header_bold', 'white,bold', 'dark blue'), + ('header_bold', 'white,bold', 'dark blue', 'bold'), ('intro_bigtext', 'yellow', ''), ('intro_smalltext', 'light blue', ''), ('poll_bar', 'white', 'dark blue'), @@ -22,17 +33,17 @@ PALETTE = [ ('status_detail_bookmarked', 'light red', ''), ('status_detail_timestamp', 'light blue', ''), ('status_list_account', 'dark green', ''), - ('status_list_selected', 'white,bold', 'dark green'), + ('status_list_selected', 'white,bold', 'dark green', 'bold,underline'), ('status_list_timestamp', 'light blue', ''), # Functional ('account', 'dark green', ''), - ('hashtag', 'light cyan,bold', ''), - ('hashtag_followed', 'yellow,bold', ''), - ('link', ',italics', ''), - ('link_focused', ',italics', 'dark magenta'), + ('hashtag', 'light cyan,bold', '', 'bold'), + ('hashtag_followed', 'yellow,bold', '', 'bold'), + ('link', ',italics', '', ',italics'), + ('link_focused', ',italics', 'dark magenta', "underline,italics"), ('shortcut', 'light blue', ''), - ('shortcut_highlight', 'white,bold', ''), + ('shortcut_highlight', 'white,bold', '', 'bold'), ('warning', 'light red', ''), # Visiblity @@ -48,55 +59,6 @@ PALETTE = [ ('success', 'dark green', ''), ] -MONO_PALETTE = [ - # Components - ('button', 'white', 'black'), - ('button_focused', 'black', 'white'), - ('card_author', 'white', ''), - ('card_title', 'white, bold', ''), - ('columns_divider', 'white', 'black'), - ('content_warning', 'white', 'black'), - ('editbox', 'white', 'black'), - ('editbox_focused', 'black', 'white'), - ('footer_message', 'white', 'black'), - ('footer_message_error', 'white,bold', 'black'), - ('footer_status', 'black', 'white'), - ('footer_status_bold', 'black,bold', 'white'), - ('header', 'black', 'white'), - ('header_bold', 'black,bold', 'white'), - ('intro_bigtext', 'white', 'black'), - ('intro_smalltext', 'white', 'black'), - ('poll_bar', 'black', 'white'), - ('status_detail_account', 'white', ''), - ('status_detail_bookmarked', 'white', ''), - ('status_detail_timestamp', 'white', ''), - ('status_list_account', 'white', ''), - ('status_list_selected', 'white,bold', ''), - ('status_list_timestamp', 'white', ''), - ('warning', 'white,bold', 'black'), - - # Functional - ('account', 'white', ''), - ('hashtag_followed', 'white,bold', ''), - ('hashtag', 'white,bold', ''), - ('link', ',italics', ''), - ('link_focused', ',bold,italics', ''), - ('shortcut', 'white', ''), - ('shortcut_highlight', 'white,bold', ''), - - # Visiblity - ('visibility_public', 'white', ''), - ('visibility_unlisted', 'white', ''), - ('visibility_private', 'white', ''), - ('visibility_direct', 'white', ''), - - # Styles - ('bold', ',bold', ''), - ('dim', 'light gray', ''), - ('highlight', ',bold', ''), - ('success', '', ''), -] - VISIBILITY_OPTIONS = [ ("public", "Public", "Post to public timelines"), ("unlisted", "Unlisted", "Do not post to public timelines"),