Add Theme, Button.
--- a/demos/03_application.py Tue Mar 18 22:39:21 2014 +0100
+++ b/demos/03_application.py Wed Mar 19 00:32:38 2014 +0100
@@ -5,10 +5,15 @@
from tuikit.core.application import Application
from tuikit.widgets.label import Label
+from tuikit.widgets.button import Button
label = Label('Hello there!')
label.pos.update(20, 10)
+button = Button()
+button.pos.update(20, 20)
+
app = Application()
app.root_window.add(label)
+app.root_window.add(button)
app.start()
--- a/tuikit/core/application.py Tue Mar 18 22:39:21 2014 +0100
+++ b/tuikit/core/application.py Wed Mar 19 00:32:38 2014 +0100
@@ -1,4 +1,5 @@
from tuikit.core.window import WindowManager, Window
+from tuikit.core.theme import default_theme
import logging
@@ -24,10 +25,11 @@
self._started = False
self._quit = False
# find and initialize driver
- self.use_driver(driver)
+ self.set_driver(driver)
+ self.set_theme(default_theme)
self.window_manager.add(self.root_window)
- def use_driver(self, driver_name):
+ def set_driver(self, driver_name):
"""Select driver to be used for rendering and input.
`driver_name` should be one of: 'base', 'curses', 'sdl'
@@ -38,6 +40,9 @@
module = __import__('tuikit.driver.' + driver_name, fromlist=['driver_class'])
self.driver = module.driver_class()
+ def set_theme(self, theme):
+ self.window_manager.set_theme(theme)
+
def start(self):
"""Start application. Runs main loop."""
self.log.info('=== start ===')
--- a/tuikit/core/buffer.py Tue Mar 18 22:39:21 2014 +0100
+++ b/tuikit/core/buffer.py Wed Mar 19 00:32:38 2014 +0100
@@ -1,6 +1,8 @@
from tuikit.core.signal import Signal
from tuikit.core.coords import Size
-from tuikit.core.unigraph import unigraph_default
+from tuikit.core.theme import default_theme
+
+from contextlib import contextmanager
class Cell:
@@ -58,7 +60,7 @@
for i in range(h):
self.hline(x, y + i, w, c)
- def frame(self, x=0, y=0, w=0, h=0, style=unigraph_default):
+ def frame(self, x=0, y=0, w=0, h=0, theme=default_theme):
"""Draw rectangular frame.
Frame whole buffer if width or height is not specified (zero).
@@ -67,14 +69,22 @@
"""
w = self.size.w if not w else w
h = self.size.h if not h else h
- self.putch(x, y, style.frame_ulcorner)
- self.putch(x+w-1, y, style.frame_urcorner)
- self.putch(x, y+h-1, style.frame_llcorner)
- self.putch(x+w-1, y+h-1, style.frame_lrcorner)
- self.hline(x+1, y, w-2, style.frame_hline)
- self.hline(x+1, y+h-1, w-2, style.frame_hline)
- self.vline(x, y+1, h-2, style.frame_vline)
- self.vline(x+w-1, y+1, h-2, style.frame_vline)
+ self.putch(x, y, theme.frame_ulcorner)
+ self.putch(x+w-1, y, theme.frame_urcorner)
+ self.putch(x, y+h-1, theme.frame_llcorner)
+ self.putch(x+w-1, y+h-1, theme.frame_lrcorner)
+ self.hline(x+1, y, w-2, theme.frame_hline)
+ self.hline(x+1, y+h-1, w-2, theme.frame_hline)
+ self.vline(x, y+1, h-2, theme.frame_vline)
+ self.vline(x+w-1, y+1, h-2, theme.frame_vline)
+
+ @contextmanager
+ def attr(self, attr_desc):
+ """Set attribute for block of commands, then restore previous attribute."""
+ original_attr = self.getattr()
+ self.setattr(attr_desc)
+ yield
+ self.setattr(original_attr)
class Buffer(BufferOperationsMixin):
@@ -118,6 +128,10 @@
cell = self._data[y * self._size.w + x]
return cell.char, self._attr_descs[cell.attr]
+ def getattr(self):
+ """Get current attribute."""
+ return self._attr_descs[self._current_attr]
+
def setattr(self, attr_desc):
"""Set attribute to be used for subsequent draw operations."""
if attr_desc in self._attr_map:
@@ -159,6 +173,10 @@
"""Get cell data at `x`, `y` coords."""
return self.target.get(x, y)
+ def getattr(self):
+ """Get current attribute."""
+ return self.target.getattr()
+
def setattr(self, attr_desc):
"""Set attribute to be used for subsequent draw operations."""
self.target.setattr(attr_desc)
--- a/tuikit/core/container.py Tue Mar 18 22:39:21 2014 +0100
+++ b/tuikit/core/container.py Wed Mar 19 00:32:38 2014 +0100
@@ -1,3 +1,6 @@
+from tuikit.core.theme import default_theme
+
+
class Container:
"""Container for widgets."""
@@ -5,12 +8,19 @@
def __init__(self):
#: List of child widgets.
self.children = []
+ self.theme = default_theme
def add(self, widget, **kwargs):
"""Add widget into container."""
self.children.append(widget)
widget.parent = self
widget.window = self.window if hasattr(self, 'window') else self
+ widget.set_theme(self.theme)
+
+ def set_theme(self, theme):
+ self.theme = theme
+ for child in self.children:
+ child.set_theme(theme)
def draw(self, buffer, x=0, y=0):
"""Draw child widgets."""
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tuikit/core/theme.py Wed Mar 19 00:32:38 2014 +0100
@@ -0,0 +1,43 @@
+from tuikit.core.unigraph import unigraph_default as unigraph
+
+
+class ColorTheme:
+
+ """Default color style"""
+
+ normal = 'lightgray'
+ button = 'black on lightgray'
+ button_active = 'black on cyan'
+
+
+class GraphicalTheme:
+
+ """Default graphical symbols"""
+
+ # Frame
+ frame_hline = unigraph.HLINE
+ frame_vline = unigraph.VLINE
+ frame_ulcorner = unigraph.ULCORNER
+ frame_urcorner = unigraph.URCORNER
+ frame_llcorner = unigraph.LLCORNER
+ frame_lrcorner = unigraph.LRCORNER
+ frame_ltee = unigraph.LTEE
+ frame_rtee = unigraph.RTEE
+
+ # Scrollbar
+ sb_thumb = unigraph.CIRCLE
+ sb_htrack = unigraph.DOTTED_HLINE
+ sb_vtrack = unigraph.DOTTED_VLINE
+ sb_left = unigraph.LEFT_ARROW
+ sb_right = unigraph.RIGHT_ARROW
+ sb_up = unigraph.UP_ARROW
+ sb_down = unigraph.DOWN_ARROW
+
+
+class Theme(ColorTheme, GraphicalTheme):
+
+ def __getitem__(self, name):
+ return getattr(self, name)
+
+
+default_theme = Theme()
--- a/tuikit/core/unigraph.py Tue Mar 18 22:39:21 2014 +0100
+++ b/tuikit/core/unigraph.py Wed Mar 19 00:32:38 2014 +0100
@@ -47,25 +47,6 @@
ROUND_LLCORNER = '╰'
ROUND_LRCORNER = '╯'
- ### Default style
- # frame
- frame_hline = HLINE
- frame_vline = VLINE
- frame_ulcorner = ULCORNER
- frame_urcorner = URCORNER
- frame_llcorner = LLCORNER
- frame_lrcorner = LRCORNER
- frame_ltee = LTEE
- frame_rtee = RTEE
- # scrollbar
- sb_thumb = CIRCLE
- sb_htrack = DOTTED_HLINE
- sb_vtrack = DOTTED_VLINE
- sb_left = LEFT_ARROW
- sb_right = RIGHT_ARROW
- sb_up = UP_ARROW
- sb_down = DOWN_ARROW
-
def __getitem__(self, name):
return getattr(self, name)
--- a/tuikit/core/widget.py Tue Mar 18 22:39:21 2014 +0100
+++ b/tuikit/core/widget.py Wed Mar 19 00:32:38 2014 +0100
@@ -1,4 +1,5 @@
from tuikit.core.coords import Point, Size
+from tuikit.core.theme import default_theme
class Widget:
@@ -18,6 +19,8 @@
self.parent = None
#: Window owning this Widget
self.window = None
+ #: Theme
+ self.theme = default_theme
### placing and size
#: Position inside parent widget. Modified by layout manager.
@@ -54,3 +57,6 @@
def draw(self, buffer, x, y):
pass
+
+ def set_theme(self, theme):
+ self.theme = theme
--- a/tuikit/core/window.py Tue Mar 18 22:39:21 2014 +0100
+++ b/tuikit/core/window.py Wed Mar 19 00:32:38 2014 +0100
@@ -2,6 +2,7 @@
from tuikit.core.signal import Signal
from tuikit.core.container import Container
from tuikit.core.coords import Point
+from tuikit.core.theme import default_theme
class Window(Container):
@@ -64,11 +65,18 @@
class WindowManager:
- def __init__(self):
+ def __init__(self, theme=default_theme):
self.windows = []
+ self.theme = theme
def add(self, window):
self.windows.append(window)
+ window.set_theme(self.theme)
+
+ def set_theme(self, theme):
+ self.theme = theme
+ for window in self.windows:
+ window.set_theme(theme)
def resize(self, w, h):
self.windows[0].resize(w, h)
@@ -79,6 +87,8 @@
x + window.x,
y + window.y)
+# def keypress(self, keyname, char, mod=0):
+
def handle_event(self, event_name, *args):
"""Handle input event to managed windows."""
handler = getattr(self, event_name, None)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tuikit/widgets/button.py Wed Mar 19 00:32:38 2014 +0100
@@ -0,0 +1,97 @@
+from tuikit.core.widget import Widget
+from tuikit.core.signal import Signal
+
+
+class Button(Widget):
+
+ """Clickable button."""
+
+ def __init__(self, label='btn'):
+ """Create button with given label, size according to label."""
+ Widget.__init__(self)
+
+ #: Button label.
+ self._label = ''
+ #: Text or graphics to be added before label
+ self.prefix = '['
+ #: Text or graphics to be added after label
+ self.suffix = ']'
+ #: How should label be aligned if button has excess space - center | left | right
+ self.align = 'center'
+ #: Padding between prefix/suffix and label
+ self.padding = 1
+
+ self.allow_focus = True
+
+ self.color = 'default'
+ self.color_highlighted = 'default on red'
+ self.highlight = False
+
+ self.sig_clicked = Signal()
+
+ self.label = label
+
+ @property
+ def label(self):
+ """Button label."""
+ return self._label
+
+ @label.setter
+ def label(self, value):
+ self._label = value
+ w = len(value) + len(self.prefix) + len(self.suffix) + 2 * self.padding
+ self.sizereq.update(w, 1)
+
+ def set_theme(self, theme):
+ self.color = theme.button
+ self.color_highlighted = theme.button_active
+
+ def _get_color(self):
+ if self.highlight: # or self.has_focus():
+ return self.color_highlighted
+ return self.color
+
+ def draw(self, buffer, x, y):
+ pad = self.width - len(self.label) - len(self.prefix) - len(self.suffix)
+ lpad, rpad = self._divide_padding(pad)
+ with buffer.attr(self._get_color()):
+ # prefix
+ buffer.puts(x, y, self.prefix)
+ pos = len(self.prefix)
+ # left pad
+ buffer.puts(x + pos, y, ' ' * lpad)
+ pos += lpad
+ # label
+ buffer.puts(x + pos, y, self.label)
+ pos += len(self.label)
+ # right pad
+ buffer.puts(x + pos, y, ' ' * rpad)
+ pos += rpad
+ # suffix
+ buffer.puts(x + pos, y, self.suffix)
+
+ def on_mousedown(self, ev):
+ self.highlight = True
+ self.redraw()
+
+ def on_mouseup(self, ev):
+ self.highlight = False
+ self.redraw()
+
+ if self.enclose(ev.px, ev.py):
+ self.emit('click')
+
+ def on_keypress(self, ev):
+ if ev.keyname == 'enter':
+ self.emit('click')
+
+ def _divide_padding(self, pad):
+ # default is 'left'
+ lpad, rpad = 0, pad
+ if self.align == 'center':
+ lpad = pad // 2
+ rpad = pad - lpad
+ elif self.align == 'right':
+ lpad, rpad = pad, 0
+ return lpad, rpad
+
--- a/tuikit/widgets/label.py Tue Mar 18 22:39:21 2014 +0100
+++ b/tuikit/widgets/label.py Wed Mar 19 00:32:38 2014 +0100
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
from tuikit.core.widget import Widget
@@ -9,8 +7,11 @@
Widget.__init__(self)
self.sizereq.update(len(label), 1)
self.label = label
- #self.color = 'normal'
+ self.color = 'default'
+
+ def set_theme(self, theme):
+ self.color = self.theme.normal
def draw(self, buffer, x, y):
- #ev.driver.pushcolor(self.color)
- buffer.puts(x, y, self.label)
+ with buffer.attr(self.color):
+ buffer.puts(x, y, self.label)