New color management - named colors.
authorRadek Brich <radek.brich@devl.cz>
Wed, 13 Apr 2011 01:33:27 +0200
changeset 7 d4a291b31cbb
parent 6 d4ee152d7d07
child 8 fcaabd817774
New color management - named colors.
docs/colors.rst
docs/index.rst
tuikit/application.py
tuikit/backend_curses.py
tuikit/button.py
tuikit/label.py
tuikit/menu.py
tuikit/menubar.py
tuikit/window.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/colors.rst	Wed Apr 13 01:33:27 2011 +0200
@@ -0,0 +1,25 @@
+Colors
+======
+
+backend.setcolor(name, description)
+
+  This will parse description, prepare attributes and save them under 'name'.
+  Description is in format <foreground> "on" <background> "," <attributes>.
+  For example:
+    "black on cyan"
+    "white on cyan" or "gray on cyan, standout" (equivalent)
+    "yellow on red, underline, blink"
+
+backend.pushcolor(name)
+
+backend.popcolor()
+
+
+Default theme
+-------------
+
+menu-normal - black on cyan
+menu-highlight - white on cyan
+
+window-normal - gray on blue
+window-highlight - white on blue
--- a/docs/index.rst	Sun Apr 10 22:56:13 2011 +0200
+++ b/docs/index.rst	Wed Apr 13 01:33:27 2011 +0200
@@ -9,5 +9,5 @@
    widget
    focus
    redraw
+   colors
 
-
--- a/tuikit/application.py	Sun Apr 10 22:56:13 2011 +0200
+++ b/tuikit/application.py	Wed Apr 13 01:33:27 2011 +0200
@@ -92,6 +92,7 @@
 
     def mainloop(self, screen):
         self.screen = BackendCurses(screen)
+        self.applytheme()
         self.top.width, self.top.height = self.screen.width, self.screen.height
         self.top.emit('resize')
 
@@ -114,3 +115,14 @@
             if self.quit:
                 break
 
+
+    def applytheme(self):
+        screen = self.screen
+        screen.setcolor('normal',                  'white on blue')
+        screen.setcolor('window',                  'white on blue')
+        screen.setcolor('window-controls',         'white on blue, bold')
+        screen.setcolor('window-controls-active',  'cyan on blue, bold')
+        screen.setcolor('button',                  'black on white')
+        screen.setcolor('button-active',           'black on cyan')
+        screen.setcolor('menu',                    'black on cyan')
+        screen.setcolor('menu-active',             'white on cyan, bold')
--- a/tuikit/backend_curses.py	Sun Apr 10 22:56:13 2011 +0200
+++ b/tuikit/backend_curses.py	Wed Apr 13 01:33:27 2011 +0200
@@ -69,13 +69,28 @@
         (0x1b,0x5b,0x5b,0x45,       'f5'            ),  # linux
     )
 
+    color_names = {
+        'black'   : curses.COLOR_BLACK,
+        'blue'    : curses.COLOR_BLUE,
+        'cyan'    : curses.COLOR_CYAN,
+        'green'   : curses.COLOR_GREEN,
+        'magenta' : curses.COLOR_MAGENTA,
+        'red'     : curses.COLOR_RED,
+        'white'   : curses.COLOR_WHITE,
+        'yellow'  : curses.COLOR_YELLOW,
+    }
+
     def __init__(self, screen):
         self.screen = screen
         self.height, self.width = screen.getmaxyx()
 
         self.cursor = None
         self.clipstack = []
-        self.colorstack = []
+
+        self.colors = {}     # maps names to curses attributes
+        self.colorpairs = {} # maps tuple (fg,bg) to curses color_pair
+        self.colorstack = [] # pushcolor/popcolor puts or gets attributes from this
+
         self.inputqueue = []
         self.mbtnstack = []
 
@@ -89,16 +104,6 @@
         screen.immedok(0)
         screen.keypad(0)
 
-        curses.init_pair(1, curses.COLOR_WHITE, curses.COLOR_BLACK)
-        curses.init_pair(2, curses.COLOR_BLACK, curses.COLOR_CYAN)
-        curses.init_pair(3, curses.COLOR_WHITE, curses.COLOR_CYAN)
-        curses.init_pair(4, curses.COLOR_WHITE, curses.COLOR_BLUE)
-        curses.init_pair(5, curses.COLOR_CYAN, curses.COLOR_BLUE)
-
-        self.BOLD = curses.A_BOLD
-        self.BLINK = curses.A_BLINK
-        self.UNDERLINE = curses.A_UNDERLINE
-
         # http://en.wikipedia.org/wiki/List_of_Unicode_characters#Geometric_shapes
         self.UP_ARROW = '▲' #curses.ACS_UARROW
         self.DOWN_ARROW = '▼' #curses.ACS_DARROW
@@ -171,22 +176,60 @@
 
     ## attributes ##
 
-    def pushcolor(self, col, attr=0):
-        if type(col) is tuple:
-            col, attr = col
-        if attr == 'bold':
-            attr = self.BOLD
-        self.screen.attrset(curses.color_pair(col) | attr)
-        self.colorstack.append((col, attr))
+    def _parsecolor(self, name):
+        name = name.lower().strip()
+        return self.color_names[name]
+
+
+    def _getcolorpair(self, fg, bg):
+        pair = (fg, bg)
+        if pair in self.colorpairs:
+            return self.colorpairs[pair]
+        num = len(self.colorpairs) + 1
+        curses.init_pair(num, fg, bg)
+        self.colorpairs[pair] = num
+        return num
+
+
+    def _parseattrs(self, attrs):
+        res = 0
+        for a in attrs:
+            a = a.lower().strip()
+            trans = {
+                'blink'     : curses.A_BLINK,
+                'bold'      : curses.A_BOLD,
+                'dim'       : curses.A_DIM,
+                'standout'  : curses.A_STANDOUT,
+                'underline' : curses.A_UNDERLINE,
+            }
+            res = res | trans[a]
+        return res
+
+
+    def setcolor(self, name, desc):
+        parts = desc.split(',')
+        fg, bg = parts[0].split(' on ')
+        attrs = parts[1:]
+        fg = self._parsecolor(fg)
+        bg = self._parsecolor(bg)
+        col = self._getcolorpair(fg, bg)
+        attr = self._parseattrs(attrs)
+        self.colors[name] = curses.color_pair(col) | attr
+
+
+    def pushcolor(self, name):
+        attr = self.colors[name]
+        self.screen.attrset(attr)
+        self.colorstack.append(attr)
 
 
     def popcolor(self):
         self.colorstack.pop()
         if len(self.colorstack):
-            col, attr = self.colorstack[-1]
+            attr = self.colorstack[-1]
         else:
-            col, attr = 0, 0
-        self.screen.attrset(curses.color_pair(col) | attr)
+            attr = 0
+        self.screen.attrset(attr)
 
 
     ## drawing ##
@@ -257,8 +300,8 @@
         if not self.testclip(x, y):
             return
         self.cursor = (y, x)
-    
-        
+
+
     def hidecursor(self):
         curses.curs_set(False)
         self.cursor = None
--- a/tuikit/button.py	Sun Apr 10 22:56:13 2011 +0200
+++ b/tuikit/button.py	Wed Apr 13 01:33:27 2011 +0200
@@ -11,8 +11,8 @@
         Widget.__init__(self, len(label) + 4, 1)
 
         self.label = label
-        self.bg = 1
-        self.bghi = 2
+        self.bg = 'button'
+        self.bghi = 'button-active'
         self.highlight = False
 
         self.lbracket = '<'
--- a/tuikit/label.py	Sun Apr 10 22:56:13 2011 +0200
+++ b/tuikit/label.py	Wed Apr 13 01:33:27 2011 +0200
@@ -12,6 +12,8 @@
 
 
     def on_draw(self, screen, x, y):
+        screen.pushcolor('normal')
         screen.puts(x, y, self.label)
+        screen.popcolor()
 
 
--- a/tuikit/menu.py	Sun Apr 10 22:56:13 2011 +0200
+++ b/tuikit/menu.py	Wed Apr 13 01:33:27 2011 +0200
@@ -9,8 +9,8 @@
         self.width = max([len(x[0]) for x in items if x is not None]) + 4
         self.height = len(items) + 2
 
-        self.bg = 2
-        self.highlight = 3
+        self.bg = 'menu'
+        self.highlight = 'menu-active'
         self.items = items
         self.selected = items[0]
         self.menubar = None
@@ -31,7 +31,7 @@
                 screen.puts(x, y + i, screen.LTEE + screen.HLINE * (self.width - 2) + screen.RTEE)
             else:
                 if self.selected == item:
-                    screen.pushcolor(self.highlight, screen.BOLD)
+                    screen.pushcolor(self.highlight)
                     screen.puts(x + 1, y + i, ' ' + item[0] + ' ' * (self.width - 3 - len(item[0])))
                     screen.popcolor()
                 else:
--- a/tuikit/menubar.py	Sun Apr 10 22:56:13 2011 +0200
+++ b/tuikit/menubar.py	Wed Apr 13 01:33:27 2011 +0200
@@ -8,8 +8,8 @@
     def __init__(self, items = []):
         Widget.__init__(self, 0, 1)
 
-        self.bg = 2
-        self.highlight = 3
+        self.bg = 'menu'
+        self.highlight = 'menu-active'
 
         self.setitems(items)
         self.selected = None
@@ -41,7 +41,7 @@
         i = 0
         for item in self.items:
             if self.selected == item:
-                screen.pushcolor(self.highlight, screen.BOLD)
+                screen.pushcolor(self.highlight)
                 screen.puts(x + i, y, '  ' + item[0] + '  ')
                 screen.popcolor()
             else:
--- a/tuikit/window.py	Sun Apr 10 22:56:13 2011 +0200
+++ b/tuikit/window.py	Wed Apr 13 01:33:27 2011 +0200
@@ -27,10 +27,10 @@
         self.closebtn.x = self.width - 5
         self.closebtn.width = 3
         self.closebtn.connect('click', self.on_closebtn)
-        self.closebtn.bg = (4, 'bold')
-        self.closebtn.bghi = (5, 'bold')
+        self.closebtn.bg = 'window-controls'
+        self.closebtn.bghi = 'window-controls-active'
         self.add(self.closebtn)
-        
+
         self.borders = (1, 1, 1, 1)
 
 
@@ -45,14 +45,14 @@
 
 
     def on_draw(self, screen, x, y):
-        screen.pushcolor(4)
+        screen.pushcolor('window')
         screen.frame(x, y, self.width, self.height)
 
         if self.resizable:
             if self.resizing:
-                screen.pushcolor(5, 'bold')
+                screen.pushcolor('window-controls-active')
             else:
-                screen.pushcolor(4, 'bold')
+                screen.pushcolor('window-controls')
             screen.puts(x + self.width - 2, y + self.height - 1, '─┘') # '━┛'
             screen.popcolor()