diff --git a/subiquity/core.py b/subiquity/core.py index 61edbc4e..e8640eba 100644 --- a/subiquity/core.py +++ b/subiquity/core.py @@ -24,7 +24,7 @@ log = logging.getLogger('console_conf.core') class Subiquity(Application): - from subiquity.palette import PALETTE, STYLES, STYLES_MONO + from subiquity.palette import COLORS, STYLES, STYLES_MONO project = "subiquity" diff --git a/subiquity/palette.py b/subiquity/palette.py index 05af92b8..4f44a799 100644 --- a/subiquity/palette.py +++ b/subiquity/palette.py @@ -15,61 +15,18 @@ """ Palette definitions """ -black = 'black' # index 0 -dark_red = 'dark red' # index 1 -dark_green = 'dark green' # index 2 -brown = 'brown' # index 3 -dark_blue = 'dark blue' # index 4 # This is overwritten to ubuntu orange at startup -dark_magenta = 'dark magenta' # index 5 -dark_cyan = 'dark cyan' # index 6 -light_gray = 'light gray' # index 7 -dark_gray = 'dark gray' # index 8 -light_red = 'light red' # index 9 -light_green = 'light green' # index 10 -yellow = 'yellow' # index 11 -light_blue = 'light blue' # index 12 -light_magenta = 'light magenta' # index 13 -light_cyan = 'light cyan' # index 14 -white = 'white' # index 15 - -URWID_16_NAMES = [ - 'black', - 'dark red', - 'dark green', - 'brown', - 'dark blue', - 'dark magenta', - 'dark cyan', - 'light gray', +COLORS = [ + ("bg", (0x00, 0x00, 0x00)), + ("orange", (0xe9, 0x54, 0x20)), + ("danger", (0xff, 0x00, 0x00)), + ("good", (0x00, 0xff, 0x00)), + ("neutral", (0x00, 0xff, 0xff)), + ("gray", (0x7f, 0x7f, 0x7f)), + ("aubergine", (0x77, 0x21, 0x6f)), + ("fg", (0xff, 0xff, 0xff)), ] -URWID16 = {} -URWID256 = {} - -PALETTE = bytearray(8*3) - -colors = { - 0: ("bg", (0x00, 0x00, 0x00)), - 1: ("orange", (0xe9, 0x54, 0x20)), - 2: ("danger", (0xff, 0x00, 0x00)), - 3: ("good", (0x00, 0xff, 0x00)), - 4: ("neutral", (0x00, 0xff, 0xff)), - 5: ("gray", (0x7f, 0x7f, 0x7f)), - 6: ("aubergine", (0x77, 0x21, 0x6f)), - 7: ("fg", (0xff, 0xff, 0xff)), -} - -for i, (c, (r, g, b)) in colors.items(): - URWID16[c] = URWID_16_NAMES[i] - PALETTE[i*3+0] = r - PALETTE[i*3+1] = g - PALETTE[i*3+2] = b - URWID256[c] = 'h' + str(i+16) - -orange = "#e51" -warm_gray = "g15" - STYLES = [ ('frame_header', 'fg', 'orange'), ('frame_footer', 'fg', 'gray'), @@ -102,22 +59,20 @@ focus_styles = set([ for i in range(len(STYLES)): name, fg, bg = STYLES[i] - STYLES[i] = (name, URWID16[fg], URWID16[bg], '', URWID256[fg], URWID256[bg]) if name in focus_styles: - STYLES.append( - (name + ' focus', URWID16[bg], URWID16[fg], '', URWID256[bg], URWID256[fg])) + STYLES.append((name + ' focus', bg, fg)) STYLES_MONO = [ - ('frame_header', white, black, '', '', ''), - ('frame_footer', white, black, '', '', ''), - ('body', white, black, '', '', ''), - ('info_minor', white, black, '', '', ''), - ('menu_button', '', '', '', white, ''), - ('menu_button focus', '', '', '', white, ''), - ('button', white, black, '', '', ''), - ('button focus', white, black, '', '', ''), - ('string_input', '', '', '', white, ''), - ('string_input focus', '', '', '', white, ''), - ('progress_incomplete', '', '', '', '', black), - ('progress_complete', '', '', '', '', white), + ('frame_header', 'white', 'black'), + ('frame_footer', 'white', 'black'), + ('body', 'white', 'black'), + ('info_minor', 'white', 'black'), + ('menu_button', '', ''), + ('menu_button focus', '', ''), + ('button', 'white', 'black'), + ('button focus', 'white', 'black'), + ('string_input', '', ''), + ('string_input focus', '', ''), + ('progress_incomplete', '', ''), + ('progress_complete', '', ''), ] diff --git a/subiquitycore/core.py b/subiquitycore/core.py index 9e688618..d4dd5130 100644 --- a/subiquitycore/core.py +++ b/subiquitycore/core.py @@ -17,7 +17,6 @@ from concurrent import futures import fcntl import logging import sys -import os import urwid import yaml @@ -42,21 +41,19 @@ PIO_CMAP = 0x4B71 # sets colour palette on VGA+ UO_R, UO_G, UO_B = 0xe9, 0x54, 0x20 -def setup_ubuntu_orange(pal, additional_opts): - """Overwrite color 4 (usually "dark blue") to Ubuntu orange.""" - if is_linux_tty(): - curpal = bytearray(16*3) - fcntl.ioctl(sys.stdout.fileno(), GIO_CMAP, curpal) - curpal[:8] = pal - fcntl.ioctl(sys.stdout.fileno(), PIO_CMAP, curpal) - elif os.environ['TERM'] == 'fbterm': - print('\033[3;4;%i;%i;%i}' % (UO_R, UO_G, UO_B), flush=True) - else: - additional_opts['screen'].set_terminal_properties(colors=256) - entries = [] - for i in range(8): - entries.append((i+16, pal[i*3+0], pal[i*3+1], pal[i*3+2])) - additional_opts['screen'].modify_terminal_palette(entries) +class ISO_8613_3_Screen(urwid.raw_display.Screen): + + def __init__(self, _urwid_name_to_rgb): + self._fg_to_rgb = _urwid_name_to_rgb.copy() + self._fg_to_rgb['default'] = _urwid_name_to_rgb['light gray'] + self._bg_to_rgb = _urwid_name_to_rgb.copy() + self._bg_to_rgb['default'] = _urwid_name_to_rgb['black'] + super().__init__() + + def _attrspec_to_escape(self, a): + f_r, f_g, f_b = self._fg_to_rgb[a.foreground] + b_r, b_g, b_b = self._bg_to_rgb[a.background] + return "\x1b[38;2;{};{};{};48;2;{};{};{}m".format(f_r, f_g, f_b, b_r, b_g, b_b) def is_linux_tty(): @@ -69,6 +66,56 @@ def is_linux_tty(): return r == b'\x02' + +def setup_screen(colors, styles): + """Return a palette and screen to be passed to MainLoop. + + colors is a list of exactly 8 tuples (name, (r, g, b)) + + styles is a list of tuples (stylename, fg_color, bg_color) where + fg_color and bg_color are defined in 'colors' + """ + # The part that makes this "fun" is that urwid insists on referring + # to the basic colors by their "standard" names but we overwrite + # these colors to mean different things. So we convert styles into + # an urwid palette by mapping the names in colors to the standard + # name, and then either overwrite the first 8 colors to be the + # colors from 'colors' (on the linux vt) or use a custom screen + # class that displays maps the standard color name to the value + # specified in colors using 24-bit control codes. + if len(colors) != 8: + raise Exception("setup_screen must be passed a list of exactly 8 colors") + urwid_8_names = ( + 'black', + 'dark red', + 'dark green', + 'brown', + 'dark blue', + 'dark magenta', + 'dark cyan', + 'light gray', + ) + urwid_name = dict(zip([c[0] for c in colors], urwid_8_names)) + + urwid_palette = [] + for name, fg, bg in styles: + urwid_palette.append((name, urwid_name[fg], urwid_name[bg])) + + if is_linux_tty(): + curpal = bytearray(16*3) + fcntl.ioctl(sys.stdout.fileno(), GIO_CMAP, curpal) + for i in range(8): + for j in range(3): + curpal[i*3+j] = colors[i][1][j] + fcntl.ioctl(sys.stdout.fileno(), PIO_CMAP, curpal) + return urwid.raw_display.Screen(), urwid_palette + else: + _urwid_name_to_rgb = {} + for i, n in enumerate(urwid_8_names): + _urwid_name_to_rgb[n] = colors[i][1] + return ISO_8613_3_Screen(_urwid_name_to_rgb), urwid_palette + + class Application: # A concrete subclass must set project and controllers attributes, e.g.: @@ -167,25 +214,17 @@ class Application: def exit(self): raise urwid.ExitMainLoop() - def header_hotkeys(self, key): - return False - def run(self): if not hasattr(self, 'loop'): - palette = self.STYLES - additional_opts = { - 'screen': urwid.raw_display.Screen(), - 'unhandled_input': self.header_hotkeys, - 'handle_mouse': False, - 'pop_ups': True, - } if self.common['opts'].run_on_serial: palette = self.STYLES_MONO + screen = urwid.raw_display.Screen() else: - setup_ubuntu_orange(self.PALETTE, additional_opts) + screen, palette = setup_screen(self.COLORS, self.STYLES) self.common['loop'] = urwid.MainLoop( - self.common['ui'], palette, **additional_opts) + self.common['ui'], palette=palette, screen=screen, + handle_mouse=False, pop_ups=True) log.debug("Running event loop: {}".format( self.common['loop'].event_loop))