Package libxyz :: Package ui :: Module colors |
[hide private]
[frames] | no frames]

# Source Code for Module libxyz.ui.colors

      1  #-*- coding: utf8 -*
      2  #
      3  # Max E. Kuznecov ~syhpoon <syhpoon@syhpoon.name> 2008
      4  #
      5  # This file is part of XYZCommander.
      6  # XYZCommander is free software: you can redistribute it and/or modify
      7  # it under the terms of the GNU Lesser Public License as published by
      8  # the Free Software Foundation, either version 3 of the License, or
      9  # (at your option) any later version.
     10  # XYZCommander is distributed in the hope that it will be useful,
     11  # but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
     13  # GNU Lesser Public License for more details.
     14  # You should have received a copy of the GNU Lesser Public License
     15  # along with XYZCommander. If not, see <http://www.gnu.org/licenses/>.
     16
     17  import copy
     18  import re
     19
     20  from libxyz import const
     21  from libxyz.exceptions import XYZValueError
     22  from libxyz.ui.display import is_lowui_ge_0_9_9
     23
     24 -class Color(object):
     25      """
     26      Base color
     27      """
     28
     29      colors = {}
     30      ctype = u"base"
     31
     32 -    def __init__(self, color):
     33          if not self.is_color_valid(color):
     34              raise XYZValueError(_(u"Invalid %s color: %s" % \
     35                                    (self.ctype, str(color))))
     36
     37          self.color = None
     38          self._set_color(color)
     39
     40      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     41
     42 -    def is_color_valid(self, color):
     43          """
     44          Check if color is valid
     45          """
     46
     47          return color in self.colors
     48
     49      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     50
     51 -    def _set_color(self, color):
     52          self.color = self.colors[color]
     53
     54      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     55
     56 -    def __str__(self):
     57          return u"<%s color: %s>" % (self.ctype, str(self.color))
     58
     59      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     60
     61 -    def __repr__(self):
     62          return self.__str__()
     63
     64  #++++++++++++++++++++++++++++++++++++++++++++++++
     65
     66 -class Foreground(Color):
     67      """
     68      Foreground color
     69      """
     70
     71      colors = {
     72                u"BLACK": u"black",
     73                u"BROWN": u"brown",
     74                u"YELLOW": u"yellow",
     75                u"WHITE": u"white",
     76                u"DEFAULT": u"default",
     77
     78                u"DARK_BLUE": u"dark blue",
     79                u"DARK_MAGENTA": u"dark magenta",
     80                u"DARK_CYAN": u"dark cyan",
     81                u"DARK_RED": u"dark red",
     82                u"DARK_GREEN": u"dark green",
     83                u"DARK_GRAY": u"dark gray",
     84
     85                u"LIGHT_GRAY": u"light gray",
     86                u"LIGHT_RED": u"light red",
     87                u"LIGHT_GREEN": u"light green",
     88                u"LIGHT_BLUE": u"light blue",
     89                u"LIGHT_MAGENTA": u"light magenta",
     90                u"LIGHT_CYAN": u"light cyan",
     91                }
     92
     93      ctype = u"foreground"
     94
     95  #++++++++++++++++++++++++++++++++++++++++++++++++
     96
     97 -class Background(Color):
     98      """
     99      Background color
    100      """
    101
    102      colors = {
    103          u"BLACK": u"black",
    104          u"BROWN": u"brown",
    105          u"DEFAULT": u"default",
    106
    107          u"DARK_RED": u"dark red",
    108          u"DARK_GREEN": u"dark green",
    109          u"DARK_BLUE": u"dark blue",
    110          u"DARK_MAGENTA": u"dark magenta",
    111          u"DARK_CYAN": u"dark cyan",
    112
    113          u"LIGHT_GRAY": u"light gray",
    114          u"DARK_GRAY": u"dark gray"
    115          }
    116
    117      ctype = u"background"
    118
    119  #++++++++++++++++++++++++++++++++++++++++++++++++
    120
    121 -class Attribute(Color):
    122      """
    123      Terminal attributes
    124      """
    125
    126      colors = {
    127          u"BOLD": u"bold",
    128          u"UNDERLINE": u"underline",
    129          u"BLINK": u"blink",
    130          u"STANDOUT": u"standout",
    131          }
    132
    133      ctype = u"attribute"
    134
    135  #++++++++++++++++++++++++++++++++++++++++++++++++
    136
    137 -class BaseHighColor(Color):
    138      """
    139      High color can contain value of form:
    140
    141      #009 (0% red, 0% green, 60% red, like HTML colors)
    142      #fcc (100% red, 80% green, 80% blue)
    143      g40 (40% gray, decimal), 'g#cc' (80% gray, hex),
    144      #000, 'g0', 'g#00' (black),
    145      #fff, 'g100', 'g#ff' (white)
    146      h8 (color number 8), 'h255' (color number 255)
    147      """
    148
    149 -    def is_color_valid(self, color):
    150          # Regular color is also valid
    151          if color in self.colors:
    152              return True
    153
    154          # Else check for high color
    155          hexre = r"(?:\d|[a-fA-F])"
    156          hicolorre = re.compile(r"^((?:#%(hexre)s{3})|(?:g\d{1,3})|"\
    157                                 r"(?:g#%(hexre)s{1,2})|(?:h\d{1,3}))$" %
    158                                 locals())
    159
    160          if hicolorre.match(color) is None:
    161              return False
    162          else:
    163              return True
    164
    165      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    166
    167 -    def _set_color(self, color):
    168          if color in self.colors:
    169              self.color = self.colors[color]
    170          else:
    171              self.color = color
    172
    173  #++++++++++++++++++++++++++++++++++++++++++++++++
    174
    175 -class ForegroundHigh(BaseHighColor):
    176      colors = Foreground.colors
    177
    178  #++++++++++++++++++++++++++++++++++++++++++++++++
    179
    180 -class BackgroundHigh(BaseHighColor):
    181      colors = Background.colors
    182
    183  #++++++++++++++++++++++++++++++++++++++++++++++++
    184
    185 -class Palette(object):
    186      """
    187      Palette abstraction
    188      """
    189
    190      @classmethod
    191 -    def convert(cls, config):
    192          """
    193          Convert config text colors to tuple of instances
    194          """
    195
    196          fg = config.get("foreground", None)
    197
    198          if fg is not None:
    199              fg = Foreground(fg)
    200
    201          bg = config.get("background", None)
    202
    203          if bg is not None:
    204              bg = Background(bg)
    205
    206          fg_attrs = [Attribute(x) for x in
    207                      config.get("fg_attributes", [])] or None
    208
    209          mono = [Attribute(x) for x in config.get("mono", [])] or None
    210
    211          fg_high = config.get("foreground_high", None)
    212
    213          if fg_high is not None:
    214              fg_high = ForegroundHigh(fg_high)
    215
    216          bg_high = config.get("background_high", None)
    217
    218          if bg_high is not None:
    219              bg_high = BackgroundHigh(bg_high)
    220
    221          return (fg, bg, fg_attrs, mono, fg_high, bg_high)
    222
    223      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    224
    225 -    def __init__(self, name, fg, bg, fg_attrs=None, mono=None,
    226                   fg_high=None, bg_high=None):
    227          """
    228          Init palette.
    229
    230          @param name: Palette name
    231          """
    232
    233          self.name = name
    234
    235          self._fg = None
    236          self._bg = None
    237          self._fg_attrs = None
    238          self._mono = None
    239          self._fg_high = None
    240          self._bg_high = None
    241
    242          self.fg = fg
    243          self.bg = bg
    244          self.fg_attrs = fg_attrs
    245          self.mono = mono
    246          self.fg_high = fg_high
    247          self.bg_high = bg_high
    248
    249      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    250
    251 -    def _fg_get(self):
    252          return self._fg
    253
    254 -    def _fg_set(self, fg):
    255          if fg is not None and not isinstance(fg, Foreground):
    256              raise XYZValueError(_(u"Invalid argument type %s, "\
    257                                    u"libxyz.ui.color.Foreground instance "\
    258                                    u"expected." % type(fg)))
    259          else:
    260              self._fg = fg
    261
    262      fg = property(_fg_get, _fg_set)
    263
    264      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    265
    266 -    def _bg_get(self):
    267          return self._bg
    268
    269 -    def _bg_set(self, bg):
    270          if bg is not None and not isinstance(bg, Background):
    271              raise XYZValueError(_(u"Invalid argument type %s, "\
    272                                    u"libxyz.ui.color.Background or instance "\
    273                                    u"expected." % type(bg)))
    274
    275          self._bg = bg
    276
    277      bg = property(_bg_get, _bg_set)
    278
    279      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    280
    281 -    def _fg_attrs_get(self):
    282          return self._fg_attrs
    283
    284 -    def _fg_attrs_set(self, attrs):
    285          if attrs is not None:
    286              for attr in attrs:
    287                  if not isinstance(attr, Attribute):
    288                      raise XYZValueError(_(u"Invalid argument type %s, "\
    289                                            u"libxyz.ui.color.Attribute "\
    290                                            u"instance expected." % type(attr)))
    291
    292          self._fg_attrs = attrs
    293
    294      fg_attrs = property(_fg_attrs_get, _fg_attrs_set)
    295
    296      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    297
    298 -    def _mono_get(self):
    299          return self._mono
    300
    301 -    def _mono_set(self, mono):
    302          if mono is not None:
    303              for attr in mono:
    304                  if not isinstance(attr, Attribute):
    305                      raise XYZValueError(_(u"Invalid argument type %s, "\
    306                                            u"libxyz.ui.color.Attribute "\
    307                                            u"instance expected." % type(mono)))
    308
    309          self._mono = mono
    310
    311      mono = property(_mono_get, _mono_set)
    312
    313      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    314
    315 -    def _fg_high_get(self):
    316          return self._fg_high
    317
    318 -    def _fg_high_set(self, fg_high):
    319          if fg_high is not None and not isinstance(fg_high, ForegroundHigh):
    320              raise XYZValueError(_(u"Invalid argument type %s, "\
    321                                    u"libxyz.ui.color.ForegroundHigh instance "\
    322                                    u"expected." % type(fg_high)))
    323          else:
    324              self._fg_high = fg_high
    325
    326      fg_high = property(_fg_high_get, _fg_high_set)
    327
    328      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    329
    330 -    def _bg_high_get(self):
    331          return self._bg_high
    332
    333 -    def _bg_high_set(self, bg_high):
    334          if bg_high is not None and not isinstance(bg_high, BackgroundHigh):
    335              raise XYZValueError(_(u"Invalid argument type %s, "\
    336                                    u"libxyz.ui.color.BackgroundHigh instance "\
    337                                    u"expected." % type(bg_high)))
    338          else:
    339              self._bg_high = bg_high
    340
    341      bg_high = property(_bg_high_get, _bg_high_set)
    342
    343      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    344
    345 -    def get_palette(self, display=const.DEFAULT_DISPLAY_DRIVER):
    346          """
    347          Return urwid-compatible palette tuple
    348          """
    349
    350          raw = display == "raw"
    351
    352          fg = self.fg.color
    353          fg_attrs = self.fg_attrs
    354
    355          # Append attributes to foreground color
    356          if fg_attrs is not None and is_lowui_ge_0_9_9() and raw:
    357              fg = ",".join([fg] + [x.color for x in fg_attrs])
    358
    359          bg = self.bg.color
    360          mono = self.mono
    361
    362          if mono is not None:
    363              mono = ",".join([x.color for x in mono])
    364
    365          fg_high = self.fg_high
    366
    367          if fg_high is not None:
    368              fg_high = fg_high.color
    369
    370              if fg_attrs is not None and is_lowui_ge_0_9_9() and raw:
    371                  fg_high = ",".join([fg_high] + [x.color for x in fg_attrs])
    372
    373          bg_high = self.bg_high
    374
    375          if bg_high is not None:
    376              bg_high = bg_high.color
    377
    378          result = (self.name, fg, bg, mono)
    379
    380          if is_lowui_ge_0_9_9() and raw:
    381              result += (fg_high, bg_high)
    382
    383          return result
    384
    385      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    386
    387 -    def set_fg(self, fg):
    388          """
    389          Set foreground color
    390          """
    391
    392          self.fg = fg
    393
    394      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    395
    396 -    def set_bg(self, bg):
    397          """
    398          Set background color
    399          """
    400
    401          self.bg = bg
    402
    403      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    404
    405 -    def copy(self):
    406          """
    407          Return copy of Palette instance
    408          """
    409
    410          return copy.deepcopy(self)
    411
    412      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    413
    414 -    def __call__(self, config):
    415          new = self.copy()
    416
    417          fg, bg, fg_attrs, mono, fg_high, bg_high = self.convert(config)
    418
    419          if fg:
    420              new.fg = fg
    421          if bg:
    422              new.bg = bg
    423          if fg_attrs:
    424              new.fg_attrs = fg_attrs
    425          if mono:
    426              new.mono = mono
    427          if fg_high:
    428              new.fg_high = fg_high
    429          if bg_high:
    430              new.bg_high = bg_high
    431
    432          return new
    433