| 1 | #!/usr/bin/python |
|---|
| 2 | # |
|---|
| 3 | # Urwid Palette Test. Showing off highcolor support |
|---|
| 4 | # Copyright (C) 2004-2009 Ian Ward |
|---|
| 5 | # |
|---|
| 6 | # This library is free software; you can redistribute it and/or |
|---|
| 7 | # modify it under the terms of the GNU Lesser General Public |
|---|
| 8 | # License as published by the Free Software Foundation; either |
|---|
| 9 | # version 2.1 of the License, or (at your option) any later version. |
|---|
| 10 | # |
|---|
| 11 | # This library is distributed in the hope that it will be useful, |
|---|
| 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|---|
| 14 | # Lesser General Public License for more details. |
|---|
| 15 | # |
|---|
| 16 | # You should have received a copy of the GNU Lesser General Public |
|---|
| 17 | # License along with this library; if not, write to the Free Software |
|---|
| 18 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|---|
| 19 | # |
|---|
| 20 | # Urwid web site: http://excess.org/urwid/ |
|---|
| 21 | |
|---|
| 22 | """ |
|---|
| 23 | Palette test. Shows the available foreground and background settings |
|---|
| 24 | in monochrome, 16 color, 88 color and 256 color modes. |
|---|
| 25 | """ |
|---|
| 26 | |
|---|
| 27 | import re |
|---|
| 28 | import sys |
|---|
| 29 | |
|---|
| 30 | import urwid |
|---|
| 31 | import urwid.raw_display |
|---|
| 32 | |
|---|
| 33 | CHART_256 = """ |
|---|
| 34 | brown__ dark_red_ dark_magenta_ dark_blue_ dark_cyan_ dark_green_ |
|---|
| 35 | yellow_ light_red light_magenta light_blue light_cyan light_green |
|---|
| 36 | |
|---|
| 37 | #00f#06f#08f#0af#0df#0ff black_______ dark_gray___ |
|---|
| 38 | #60f#00d#06d#08d#0ad#0dd#0fd light_gray__ white_______ |
|---|
| 39 | #80f#60d#00a#06a#08a#0aa#0da#0fa |
|---|
| 40 | #a0f#80d#60a#008#068#088#0a8#0d8#0f8 |
|---|
| 41 | #d0f#a0d#80d#608#006#066#086#0a6#0d6#0f6 |
|---|
| 42 | #f0f#d0d#a0a#808#606#000#060#080#0a0#0d0#0f0#0f6#0f8#0fa#0fd#0ff |
|---|
| 43 | #f0d#d0a#a08#806#600#660#680#6a0#6d0#6f0#6f6#6f8#6fa#6fd#6ff#0df |
|---|
| 44 | #f0a#d08#a06#800#860#880#8a0#8d0#8f0#8f6#8f8#8fa#8fd#8ff#6df#0af |
|---|
| 45 | #f08#d06#a00#a60#a80#aa0#ad0#af0#af6#af8#afa#afd#aff#8df#6af#08f |
|---|
| 46 | #f06#d00#d60#d80#da0#dd0#df0#df6#df8#dfa#dfd#dff#adf#8af#68f#06f |
|---|
| 47 | #f00#f60#f80#fa0#fd0#ff0#ff6#ff8#ffa#ffd#fff#ddf#aaf#88f#66f#00f |
|---|
| 48 | #fd0#fd6#fd8#fda#fdd#fdf#daf#a8f#86f#60f |
|---|
| 49 | #66d#68d#6ad#6dd #fa0#fa6#fa8#faa#fad#faf#d8f#a6f#80f |
|---|
| 50 | #86d#66a#68a#6aa#6da #f80#f86#f88#f8a#f8d#f8f#d6f#a0f |
|---|
| 51 | #a6d#86a#668#688#6a8#6d8 #f60#f66#f68#f6a#f6d#f6f#d0f |
|---|
| 52 | #d6d#a6a#868#666#686#6a6#6d6#6d8#6da#6dd #f00#f06#f08#f0a#f0d#f0f |
|---|
| 53 | #d6a#a68#866#886#8a6#8d6#8d8#8da#8dd#6ad |
|---|
| 54 | #d68#a66#a86#aa6#ad6#ad8#ada#add#8ad#68d |
|---|
| 55 | #d66#d86#da6#dd6#dd8#dda#ddd#aad#88d#66d g78_g82_g85_g89_g93_g100 |
|---|
| 56 | #da6#da8#daa#dad#a8d#86d g52_g58_g62_g66_g70_g74_ |
|---|
| 57 | #88a#8aa #d86#d88#d8a#d8d#a6d g27_g31_g35_g38_g42_g46_g50_ |
|---|
| 58 | #a8a#888#8a8#8aa #d66#d68#d6a#d6d g0__g3__g7__g11_g15_g19_g23_ |
|---|
| 59 | #a88#aa8#aaa#88a |
|---|
| 60 | #a88#a8a |
|---|
| 61 | """ |
|---|
| 62 | |
|---|
| 63 | CHART_88 = """ |
|---|
| 64 | brown__ dark_red_ dark_magenta_ dark_blue_ dark_cyan_ dark_green_ |
|---|
| 65 | yellow_ light_red light_magenta light_blue light_cyan light_green |
|---|
| 66 | |
|---|
| 67 | #00f#08f#0cf#0ff black_______ dark_gray___ |
|---|
| 68 | #80f#00c#08c#0cc#0fc light_gray__ white_______ |
|---|
| 69 | #c0f#80c#008#088#0c8#0f8 |
|---|
| 70 | #f0f#c0c#808#000#080#0c0#0f0#0f8#0fc#0ff #88c#8cc |
|---|
| 71 | #f0c#c08#800#880#8c0#8f0#8f8#8fc#8ff#0cf #c8c#888#8c8#8cc |
|---|
| 72 | #f08#c00#c80#cc0#cf0#cf8#cfc#cff#8cf#08f #c88#cc8#ccc#88c |
|---|
| 73 | #f00#f80#fc0#ff0#ff8#ffc#fff#ccf#88f#00f #c88#c8c |
|---|
| 74 | #fc0#fc8#fcc#fcf#c8f#80f |
|---|
| 75 | #f80#f88#f8c#f8f#c0f g62_g74_g82_g89_g100 |
|---|
| 76 | #f00#f08#f0c#f0f g0__g19_g35_g46_g52 |
|---|
| 77 | """ |
|---|
| 78 | |
|---|
| 79 | CHART_16 = """ |
|---|
| 80 | brown__ dark_red_ dark_magenta_ dark_blue_ dark_cyan_ dark_green_ |
|---|
| 81 | yellow_ light_red light_magenta light_blue light_cyan light_green |
|---|
| 82 | |
|---|
| 83 | black_______ dark_gray___ light_gray__ white_______ |
|---|
| 84 | """ |
|---|
| 85 | |
|---|
| 86 | ATTR_RE = re.compile("(?P<whitespace>[ \n]*)(?P<entry>[^ \n]+)") |
|---|
| 87 | SHORT_ATTR = 4 # length of short high-colour descriptions which may |
|---|
| 88 | # be packed one after the next |
|---|
| 89 | |
|---|
| 90 | def parse_chart(chart, convert): |
|---|
| 91 | """ |
|---|
| 92 | Convert string chart into text markup with the correct attributes. |
|---|
| 93 | |
|---|
| 94 | chart -- palette chart as a string |
|---|
| 95 | convert -- function that converts a single palette entry to an |
|---|
| 96 | (attr, text) tuple, or None if no match is found |
|---|
| 97 | """ |
|---|
| 98 | out = [] |
|---|
| 99 | for match in re.finditer(ATTR_RE, chart): |
|---|
| 100 | if match.group('whitespace'): |
|---|
| 101 | out.append(match.group('whitespace')) |
|---|
| 102 | entry = match.group('entry') |
|---|
| 103 | entry = entry.replace("_", " ") |
|---|
| 104 | while entry: |
|---|
| 105 | # try the first four characters |
|---|
| 106 | attrtext = convert(entry[:SHORT_ATTR]) |
|---|
| 107 | if attrtext: |
|---|
| 108 | elen = SHORT_ATTR |
|---|
| 109 | entry = entry[SHORT_ATTR:].strip() |
|---|
| 110 | else: # try the whole thing |
|---|
| 111 | attrtext = convert(entry.strip()) |
|---|
| 112 | assert attrtext, "Invalid palette entry: %r" % entry |
|---|
| 113 | elen = len(entry) |
|---|
| 114 | entry = "" |
|---|
| 115 | attr, text = attrtext |
|---|
| 116 | out.append((attr, text.ljust(elen))) |
|---|
| 117 | return out |
|---|
| 118 | |
|---|
| 119 | def foreground_chart(chart, background, colors): |
|---|
| 120 | """ |
|---|
| 121 | Create text markup for a foreground colour chart |
|---|
| 122 | |
|---|
| 123 | chart -- palette chart as string |
|---|
| 124 | background -- colour to use for background of chart |
|---|
| 125 | colors -- number of colors (88 or 256) |
|---|
| 126 | """ |
|---|
| 127 | def convert_foreground(entry): |
|---|
| 128 | try: |
|---|
| 129 | attr = urwid.AttrSpec(entry, background, colors) |
|---|
| 130 | except urwid.AttrSpecError: |
|---|
| 131 | return None |
|---|
| 132 | return attr, entry |
|---|
| 133 | return parse_chart(chart, convert_foreground) |
|---|
| 134 | |
|---|
| 135 | def background_chart(chart, foreground, colors): |
|---|
| 136 | """ |
|---|
| 137 | Create text markup for a background colour chart |
|---|
| 138 | |
|---|
| 139 | chart -- palette chart as string |
|---|
| 140 | foreground -- colour to use for foreground of chart |
|---|
| 141 | colors -- number of colors (88 or 256) |
|---|
| 142 | |
|---|
| 143 | This will remap 8 <= colour < 16 to high-colour versions |
|---|
| 144 | in the hopes of greater compatibility |
|---|
| 145 | """ |
|---|
| 146 | def convert_background(entry): |
|---|
| 147 | try: |
|---|
| 148 | attr = urwid.AttrSpec(foreground, entry, colors) |
|---|
| 149 | except urwid.AttrSpecError: |
|---|
| 150 | return None |
|---|
| 151 | # fix 8 <= colour < 16 |
|---|
| 152 | if colors > 16 and attr.background_basic and \ |
|---|
| 153 | attr.background_number >= 8: |
|---|
| 154 | # use high-colour with same number |
|---|
| 155 | entry = 'h%d'%attr.background_number |
|---|
| 156 | attr = urwid.AttrSpec(foreground, entry, colors) |
|---|
| 157 | return attr, entry |
|---|
| 158 | return parse_chart(chart, convert_background) |
|---|
| 159 | |
|---|
| 160 | |
|---|
| 161 | def main(): |
|---|
| 162 | palette = [ |
|---|
| 163 | ('header', 'black,underline', 'light gray', 'standout,underline', |
|---|
| 164 | 'black,underline', '#88a'), |
|---|
| 165 | ('panel', 'light gray', 'dark blue', '', |
|---|
| 166 | '#ffd', '#00a'), |
|---|
| 167 | ('focus', 'light gray', 'dark cyan', 'standout', |
|---|
| 168 | '#ff8', '#806'), |
|---|
| 169 | ] |
|---|
| 170 | |
|---|
| 171 | screen = urwid.raw_display.Screen() |
|---|
| 172 | screen.register_palette(palette) |
|---|
| 173 | |
|---|
| 174 | lb = urwid.SimpleListWalker([]) |
|---|
| 175 | chart_offset = None # offset of chart in lb list |
|---|
| 176 | |
|---|
| 177 | mode_radio_buttons = [] |
|---|
| 178 | chart_radio_buttons = [] |
|---|
| 179 | |
|---|
| 180 | def fcs(widget): |
|---|
| 181 | # wrap widgets that can take focus |
|---|
| 182 | return urwid.AttrMap(widget, None, 'focus') |
|---|
| 183 | |
|---|
| 184 | def set_mode(colors, is_foreground_chart): |
|---|
| 185 | # set terminal mode and redraw chart |
|---|
| 186 | screen.set_terminal_properties(colors) |
|---|
| 187 | screen.reset_default_terminal_palette() |
|---|
| 188 | |
|---|
| 189 | chart_fn = (background_chart, foreground_chart)[is_foreground_chart] |
|---|
| 190 | if colors == 1: |
|---|
| 191 | lb[chart_offset] = urwid.Divider() |
|---|
| 192 | else: |
|---|
| 193 | chart = {16: CHART_16, 88: CHART_88, 256: CHART_256}[colors] |
|---|
| 194 | txt = chart_fn(chart, 'default', colors) |
|---|
| 195 | lb[chart_offset] = urwid.Text(txt, wrap='clip') |
|---|
| 196 | |
|---|
| 197 | def on_mode_change(rb, state, colors): |
|---|
| 198 | # if this radio button is checked |
|---|
| 199 | if state: |
|---|
| 200 | is_foreground_chart = chart_radio_buttons[0].state |
|---|
| 201 | set_mode(colors, is_foreground_chart) |
|---|
| 202 | |
|---|
| 203 | def mode_rb(text, colors, state=False): |
|---|
| 204 | # mode radio buttons |
|---|
| 205 | rb = urwid.RadioButton(mode_radio_buttons, text, state) |
|---|
| 206 | urwid.connect_signal(rb, 'change', on_mode_change, colors) |
|---|
| 207 | return fcs(rb) |
|---|
| 208 | |
|---|
| 209 | def on_chart_change(rb, state): |
|---|
| 210 | # handle foreground check box state change |
|---|
| 211 | set_mode(screen.colors, state) |
|---|
| 212 | |
|---|
| 213 | def click_exit(button): |
|---|
| 214 | raise urwid.ExitMainLoop() |
|---|
| 215 | |
|---|
| 216 | lb.extend([ |
|---|
| 217 | urwid.AttrMap(urwid.Text("Urwid Palette Test"), 'header'), |
|---|
| 218 | urwid.AttrMap(urwid.Columns([ |
|---|
| 219 | urwid.Pile([ |
|---|
| 220 | mode_rb("Monochrome", 1), |
|---|
| 221 | mode_rb("16-Color", 16, True), |
|---|
| 222 | mode_rb("88-Color", 88), |
|---|
| 223 | mode_rb("256-Color", 256),]), |
|---|
| 224 | urwid.Pile([ |
|---|
| 225 | fcs(urwid.RadioButton(chart_radio_buttons, |
|---|
| 226 | "Foreground Colors", True, on_chart_change)), |
|---|
| 227 | fcs(urwid.RadioButton(chart_radio_buttons, |
|---|
| 228 | "Background Colors")), |
|---|
| 229 | urwid.Divider(), |
|---|
| 230 | fcs(urwid.Button("Exit", click_exit)), |
|---|
| 231 | ]), |
|---|
| 232 | ]),'panel') |
|---|
| 233 | ]) |
|---|
| 234 | |
|---|
| 235 | chart_offset = len(lb) |
|---|
| 236 | lb.extend([ |
|---|
| 237 | urwid.Divider() # placeholder for the chart |
|---|
| 238 | ]) |
|---|
| 239 | |
|---|
| 240 | set_mode(16, True) # displays the chart |
|---|
| 241 | |
|---|
| 242 | def unhandled_input(key): |
|---|
| 243 | if key in ('Q','q','esc'): |
|---|
| 244 | raise urwid.ExitMainLoop() |
|---|
| 245 | |
|---|
| 246 | urwid.MainLoop(urwid.ListBox(lb), screen=screen, |
|---|
| 247 | unhandled_input=unhandled_input).run() |
|---|
| 248 | |
|---|
| 249 | if __name__ == "__main__": |
|---|
| 250 | main() |
|---|
| 251 | |
|---|