Merge pull request #385 from ihabunek/colors-settings
Read TUI colors from settings
This commit is contained in:
commit
5e8a7bb415
5 changed files with 105 additions and 84 deletions
|
@ -50,3 +50,62 @@ sensitive = true
|
||||||
visibility = "unlisted"
|
visibility = "unlisted"
|
||||||
scheduled_in = "30 minutes"
|
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"]
|
||||||
|
```
|
||||||
|
|
|
@ -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"
|
|
|
@ -3,12 +3,12 @@ import urwid
|
||||||
|
|
||||||
from concurrent.futures import ThreadPoolExecutor
|
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.console import get_default_visibility
|
||||||
from toot.exceptions import ApiError
|
from toot.exceptions import ApiError
|
||||||
|
|
||||||
from .compose import StatusComposer
|
from .compose import StatusComposer
|
||||||
from .constants import PALETTE, MONO_PALETTE
|
from .constants import PALETTE
|
||||||
from .entities import Status
|
from .entities import Status
|
||||||
from .overlays import ExceptionStackTrace, GotoMenu, Help, StatusSource, StatusLinks, StatusZoom
|
from .overlays import ExceptionStackTrace, GotoMenu, Help, StatusSource, StatusLinks, StatusZoom
|
||||||
from .overlays import StatusDeleteConfirmation, Account
|
from .overlays import StatusDeleteConfirmation, Account
|
||||||
|
@ -78,19 +78,20 @@ class TUI(urwid.Frame):
|
||||||
loop: urwid.MainLoop
|
loop: urwid.MainLoop
|
||||||
screen: urwid.BaseScreen
|
screen: urwid.BaseScreen
|
||||||
|
|
||||||
@classmethod
|
@staticmethod
|
||||||
def create(cls, app, user, args):
|
def create(app, user, args):
|
||||||
"""Factory method, sets up TUI and an event loop."""
|
"""Factory method, sets up TUI and an event loop."""
|
||||||
screen = urwid.raw_display.Screen()
|
screen = TUI.create_screen(args)
|
||||||
tui = cls(app, user, screen, args)
|
tui = TUI(app, user, screen, args)
|
||||||
|
|
||||||
if args.no_color:
|
palette = PALETTE.copy()
|
||||||
screen.set_terminal_properties(1)
|
overrides = settings.get_setting("tui.palette", dict, {})
|
||||||
screen.reset_default_terminal_palette()
|
for name, styles in overrides.items():
|
||||||
|
palette.append(tuple([name] + styles))
|
||||||
|
|
||||||
loop = urwid.MainLoop(
|
loop = urwid.MainLoop(
|
||||||
tui,
|
tui,
|
||||||
palette=MONO_PALETTE if args.no_color else PALETTE,
|
palette=palette,
|
||||||
event_loop=urwid.AsyncioEventLoop(),
|
event_loop=urwid.AsyncioEventLoop(),
|
||||||
unhandled_input=tui.unhandled_input,
|
unhandled_input=tui.unhandled_input,
|
||||||
screen=screen,
|
screen=screen,
|
||||||
|
@ -99,6 +100,18 @@ class TUI(urwid.Frame):
|
||||||
|
|
||||||
return tui
|
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):
|
def __init__(self, app, user, screen, args):
|
||||||
self.app = app
|
self.app = app
|
||||||
self.user = user
|
self.user = user
|
||||||
|
|
|
@ -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 = [
|
PALETTE = [
|
||||||
# Components
|
# Components
|
||||||
('button', 'white', 'black'),
|
('button', 'white', 'black'),
|
||||||
('button_focused', 'light gray', 'dark magenta'),
|
('button_focused', 'light gray', 'dark magenta', 'bold,underline'),
|
||||||
('card_author', 'yellow', ''),
|
('card_author', 'yellow', ''),
|
||||||
('card_title', 'dark green', ''),
|
('card_title', 'dark green', ''),
|
||||||
('columns_divider', 'white', 'dark blue'),
|
('columns_divider', 'white', 'dark blue'),
|
||||||
|
@ -14,7 +25,7 @@ PALETTE = [
|
||||||
('footer_status', 'white', 'dark blue'),
|
('footer_status', 'white', 'dark blue'),
|
||||||
('footer_status_bold', 'white, bold', 'dark blue'),
|
('footer_status_bold', 'white, bold', 'dark blue'),
|
||||||
('header', 'white', 'dark blue'),
|
('header', 'white', 'dark blue'),
|
||||||
('header_bold', 'white,bold', 'dark blue'),
|
('header_bold', 'white,bold', 'dark blue', 'bold'),
|
||||||
('intro_bigtext', 'yellow', ''),
|
('intro_bigtext', 'yellow', ''),
|
||||||
('intro_smalltext', 'light blue', ''),
|
('intro_smalltext', 'light blue', ''),
|
||||||
('poll_bar', 'white', 'dark blue'),
|
('poll_bar', 'white', 'dark blue'),
|
||||||
|
@ -22,16 +33,17 @@ PALETTE = [
|
||||||
('status_detail_bookmarked', 'light red', ''),
|
('status_detail_bookmarked', 'light red', ''),
|
||||||
('status_detail_timestamp', 'light blue', ''),
|
('status_detail_timestamp', 'light blue', ''),
|
||||||
('status_list_account', 'dark green', ''),
|
('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', ''),
|
('status_list_timestamp', 'light blue', ''),
|
||||||
|
|
||||||
# Functional
|
# Functional
|
||||||
('hashtag', 'light cyan,bold', ''),
|
('account', 'dark green', ''),
|
||||||
('hashtag_followed', 'yellow,bold', ''),
|
('hashtag', 'light cyan,bold', '', 'bold'),
|
||||||
('link', ',italics', ''),
|
('hashtag_followed', 'yellow,bold', '', 'bold'),
|
||||||
('link_focused', ',italics', 'dark magenta'),
|
('link', ',italics', '', ',italics'),
|
||||||
|
('link_focused', ',italics', 'dark magenta', "underline,italics"),
|
||||||
('shortcut', 'light blue', ''),
|
('shortcut', 'light blue', ''),
|
||||||
('shortcut_highlight', 'white,bold', ''),
|
('shortcut_highlight', 'white,bold', '', 'bold'),
|
||||||
('warning', 'light red', ''),
|
('warning', 'light red', ''),
|
||||||
|
|
||||||
# Visiblity
|
# Visiblity
|
||||||
|
@ -47,54 +59,6 @@ PALETTE = [
|
||||||
('success', 'dark green', ''),
|
('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
|
|
||||||
('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 = [
|
VISIBILITY_OPTIONS = [
|
||||||
("public", "Public", "Post to public timelines"),
|
("public", "Public", "Post to public timelines"),
|
||||||
("unlisted", "Unlisted", "Do not post to public timelines"),
|
("unlisted", "Unlisted", "Do not post to public timelines"),
|
||||||
|
|
|
@ -326,9 +326,9 @@ class StatusDetails(urwid.Pile):
|
||||||
yield ("pack", urwid.AttrMap(urwid.Divider("-"), "dim"))
|
yield ("pack", urwid.AttrMap(urwid.Divider("-"), "dim"))
|
||||||
|
|
||||||
if status.author.display_name:
|
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.Text((account_color, status.author.account)))
|
||||||
yield ("pack", urwid.Divider())
|
yield ("pack", urwid.Divider())
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue