Commits

Henning Schröder committed 36d2cad

huge refactorings. tgui is now a package

Comments (0)

Files changed (17)

cursesengine.py

-# -*_ coding: utf-8 -*-
-# http://gnosis.cx/publish/programming/charming_python_6.html
-import sys
-import curses
-
-from keymap import keymap
-from palette import ColorScheme
-
-
-def debug(*args):
-    s = " ".join(str(a) for a in args)
-    open("/tmp/debug.log", "a").write("%s\n" % s)
-
-
-    
-class BasePaintEngine(object):
-    
-
-    def rectangle(self, x1, y1, x2, y2):
-        self.engine.text(x1, y1, "+")                 # top-left
-        self.engine.text(x2, y1, "+")                 # top-right
-        self.engine.text(x1 + 1, y1, "-" * (width-2)) # top line
-        self.engine.text(x1, y2, "+")                 # bottomleft
-        self.engine.text(x2, y2, "+")                 # bottomright
-        self.engine.text(x1+1, y2, "-" * (width-2))   # bottom line
-        for y in range(y1+1, y2):                     # side lines
-            self.engine.text(x1, y, "|")              #  (left)
-            self.engine.text(x2, y, "|")              #  (right)
-
-
-
-
-class PaintEngine(BasePaintEngine):
-    instance = None
-    
-
-    def __init__(self):
-        if PaintEngine.instance:
-            raise RuntimeError("Only one console instance allowed")
-        PaintEngine.instance = self
-        sys.excepthook = self.excepthook
-        self.window = curses.initscr()
-        #if curses.has_colors():
-        curses.start_color()
-        curses.noecho()
-        #curses.cbreak()    
-        curses.raw() # intercept everything
-        # In keypad mode, escape sequences for special keys
-        # (like the cursor keys) will be interpreted and
-        # a special value like curses.KEY_LEFT will be returned
-        self.window.keypad(1)
-
-        
-        # Frame the interface area at fixed VT100 size
-        self.width = 80
-        self.height= 25
-        self.screen = self.window.subwin(self.height, self.width, 0, 0)
-        #self.screen.box()
-        #self.screen.hline(2, 1, curses.ACS_HLINE, 77)
-        self.screen.refresh()
-    
-
-        
-    def excepthook(self, *args):
-        self.close()
-        sys.__excepthook__(*args)
-        sys.exit(1)
-
-
-    def __del__(self):
-        self.close()
-        
-
-    def close(self):
-        if self.window:
-            self.window.keypad(0)
-        curses.echo()
-        #curses.nocbreak()
-        curses.endwin()
-
-
-    def getchar(self, wait=False):
-        if not wait:
-            self.screen.nodelay(1)
-            while 1:
-                try:
-                    curses.cbreak()
-                    break
-                except _curses.error:
-                    pass
-        return self.screen.getch()
-    
-    
-    def readkeys(self):
-        l = []
-        while True:
-            key = self.getchar()
-            if key == -1:
-                break
-            l.append(chr(key))
-        return "".join(l)
-
-        
-    def xreadkeys(self):
-        umlauts = {
-            '\xc3\xa4': u'ä',
-            '\xc3\x84': u'Ä',
-            '\xc3\xb6': u'ö',
-            '\xc3\x96': u'Ö',
-            '\xc3\xbc': u'ü',
-            '\xc3\x9c': u'Ü',
-            '\xc3\x9f': u'ß',
-            }
-
-        keys = self.readkeys()
-        
-        if keys in umlauts:
-            return False, umlauts[keys]
-        if keys == "\x7f":
-            return True, "backspace"
-        if keys.startswith(chr(27)):
-            xkeys = keymap.get(keys[1:], None)
-            if xkeys:
-                return True, xkeys
-            elif len(keys) == 2:
-                return True, "meta %s" % keys[1]
-        elif len(keys) ==  1:
-            code = ord(keys[0]) 
-            if code < 32 and code not in (9,10):
-                return True, "ctrl %s" % chr(ord('A') + code - 1) + str(code)
-        return False, keys
-        
-
-    def refresh(self):
-        self.screen.refresh()
-    
-    
-    def text(self, column, line, string, style=curses.A_NORMAL):
-        if isinstance(style, ColorScheme):
-            style = style.color_pair()
-        self.screen.addstr(line, column, string, style)
-
-
-    def page(self):
-        self.window.erase()
-        
-
-    def gotoxy(self, x, y):
-        self.window.move(x, y)
-        self.text(x,y, "")
-
-        
-    def show_cursor(self):
-        curses.curs_set(2)
-
-
-    def hide_cursor(self):
-        curses.curs_set(0)
-
-
-    def rectangle(self, ulx, uly, lrx, lry, style=curses.A_NORMAL):
-        if isinstance(style, ColorScheme):
-            style = style.color_pair()
-        # taken from curses.textpad
-        self.window.vline(uly+1, ulx, curses.ACS_VLINE, lry - uly - 1, style)
-        self.window.hline(uly, ulx+1, curses.ACS_HLINE, lrx - ulx - 1, style)
-        self.window.hline(lry, ulx+1, curses.ACS_HLINE, lrx - ulx - 1, style)
-        self.window.vline(uly+1, lrx, curses.ACS_VLINE, lry - uly - 1, style)
-        self.window.addch(uly, ulx, curses.ACS_ULCORNER, style)
-        self.window.addch(uly, lrx, curses.ACS_URCORNER, style)
-        self.window.addch(lry, lrx, curses.ACS_LRCORNER, style)
-        self.window.addch(lry, ulx, curses.ACS_LLCORNER, style)
-
-
-
-
-if __name__=='__main__':
-    c = PaintEngine()
-    c.text(1,1, "hello, world!")
-    i = 0
-    while True:
-        extended, keys = c.xreadkeys()
-        if keys or extended:
-            i += 1
-            c.text(1, i, "%r  %s   " % (keys, extended))
-    c.close()
-

generate_keymap.py

-# -*- coding: utf-8 -*-
-
-def escape_modifier( digit ):
-    mode = ord(digit) - ord("1")
-    return "shift "*(mode&1) + "meta "*((mode&2)/2) + "ctrl "*((mode&4)/4)
-
-
-keys = [('[A','up'),('[B','down'),('[C','right'),('[D','left'),
-    ('[E','5'),('[F','end'),('[G','5'),('[H','home'),
-    ('[1~','home'),('[2~','insert'),('[3~','delete'),('[4~','end'),
-    ('[5~','page up'),('[6~','page down'),
-    ('[7~','home'),('[8~','end'),
-    
-    ('[[A','f1'),('[[B','f2'),('[[C','f3'),('[[D','f4'),('[[E','f5'),
-    
-    ('[11~','f1'),('[12~','f2'),('[13~','f3'),('[14~','f4'),
-    ('[15~','f5'),('[17~','f6'),('[18~','f7'),('[19~','f8'),
-    ('[20~','f9'),('[21~','f10'),('[23~','f11'),('[24~','f12'),
-    ('[25~','f13'),('[26~','f14'),('[28~','f15'),('[29~','f16'),
-    ('[31~','f17'),('[32~','f18'),('[33~','f19'),('[34~','f20'),
-    
-    ('OA','up'),('OB','down'),('OC','right'),('OD','left'),
-    ('OH','home'),('OF','end'),
-    ('OP','f1'),('OQ','f2'),('OR','f3'),('OS','f4'),
-    ('Oo','/'),('Oj','*'),('Om','-'),('Ok','+'),
-    
-    ('[Z','shift tab')
-    ] + [
-    #('%s' % chr(i) , 'ctrl %s' % chr(ord('A') + i)) for i in range(27)
-    ] + [
-    # modified cursor keys + home, end, 5 -- [#X and [1;#X forms
-    (prefix+digit+letter, escape_modifier(digit) + key)
-       for prefix in "[","[1;"
-         for digit in "12345678"
-           for letter,key in zip("ABCDEFGH",
-              ('up','down','right','left','5','end','5','home'))
-    ] + [ 
-    # modified F1-F4 keys -- O#X form
-    ("O"+digit+letter, escape_modifier(digit) + key)
-      for digit in "12345678"
-        for letter,key in zip("PQRS",('f1','f2','f3','f4'))
-    ] + [ 
-    # modified F1-F13 keys -- [XX;#~ form
-    ("["+str(num)+";"+digit+"~", escape_modifier(digit) + key)
-    for digit in "12345678"
-    for num,key in zip(
-    (11,12,13,14,15,17,18,19,20,21,23,24,25,26,28,29,31,32,33,34),
-    ('f1','f2','f3','f4','f5','f6','f7','f8','f9','f10','f11',
-    'f12','f13','f14','f15','f16','f17','f18','f19','f20'))
-    ] 
-
-    
-	
-if __name__ == "__main__":
-    f = open("keymap.py", "w")
-    print >>f, "# -*- coding: utf-8 -*-"
-    print >>f, "keymap = {"
-    for chars, name in keys:
-        print >>f, "    %r: %r," % (chars, name)
-    print >>f, "}"
-    f.close()

keymap.py

-# -*- coding: utf-8 -*-
-keymap = {
-    '[A': 'up',
-    '[B': 'down',
-    '[C': 'right',
-    '[D': 'left',
-    '[E': '5',
-    '[F': 'end',
-    '[G': '5',
-    '[H': 'home',
-    '[1~': 'home',
-    '[2~': 'insert',
-    '[3~': 'delete',
-    '[4~': 'end',
-    '[5~': 'page up',
-    '[6~': 'page down',
-    '[7~': 'home',
-    '[8~': 'end',
-    '[[A': 'f1',
-    '[[B': 'f2',
-    '[[C': 'f3',
-    '[[D': 'f4',
-    '[[E': 'f5',
-    '[11~': 'f1',
-    '[12~': 'f2',
-    '[13~': 'f3',
-    '[14~': 'f4',
-    '[15~': 'f5',
-    '[17~': 'f6',
-    '[18~': 'f7',
-    '[19~': 'f8',
-    '[20~': 'f9',
-    '[21~': 'f10',
-    '[23~': 'f11',
-    '[24~': 'f12',
-    '[25~': 'f13',
-    '[26~': 'f14',
-    '[28~': 'f15',
-    '[29~': 'f16',
-    '[31~': 'f17',
-    '[32~': 'f18',
-    '[33~': 'f19',
-    '[34~': 'f20',
-    'OA': 'up',
-    'OB': 'down',
-    'OC': 'right',
-    'OD': 'left',
-    'OH': 'home',
-    'OF': 'end',
-    'OP': 'f1',
-    'OQ': 'f2',
-    'OR': 'f3',
-    'OS': 'f4',
-    'Oo': '/',
-    'Oj': '*',
-    'Om': '-',
-    'Ok': '+',
-    '[Z': 'shift tab',
-    '[1A': 'up',
-    '[1B': 'down',
-    '[1C': 'right',
-    '[1D': 'left',
-    '[1E': '5',
-    '[1F': 'end',
-    '[1G': '5',
-    '[1H': 'home',
-    '[2A': 'shift up',
-    '[2B': 'shift down',
-    '[2C': 'shift right',
-    '[2D': 'shift left',
-    '[2E': 'shift 5',
-    '[2F': 'shift end',
-    '[2G': 'shift 5',
-    '[2H': 'shift home',
-    '[3A': 'meta up',
-    '[3B': 'meta down',
-    '[3C': 'meta right',
-    '[3D': 'meta left',
-    '[3E': 'meta 5',
-    '[3F': 'meta end',
-    '[3G': 'meta 5',
-    '[3H': 'meta home',
-    '[4A': 'shift meta up',
-    '[4B': 'shift meta down',
-    '[4C': 'shift meta right',
-    '[4D': 'shift meta left',
-    '[4E': 'shift meta 5',
-    '[4F': 'shift meta end',
-    '[4G': 'shift meta 5',
-    '[4H': 'shift meta home',
-    '[5A': 'ctrl up',
-    '[5B': 'ctrl down',
-    '[5C': 'ctrl right',
-    '[5D': 'ctrl left',
-    '[5E': 'ctrl 5',
-    '[5F': 'ctrl end',
-    '[5G': 'ctrl 5',
-    '[5H': 'ctrl home',
-    '[6A': 'shift ctrl up',
-    '[6B': 'shift ctrl down',
-    '[6C': 'shift ctrl right',
-    '[6D': 'shift ctrl left',
-    '[6E': 'shift ctrl 5',
-    '[6F': 'shift ctrl end',
-    '[6G': 'shift ctrl 5',
-    '[6H': 'shift ctrl home',
-    '[7A': 'meta ctrl up',
-    '[7B': 'meta ctrl down',
-    '[7C': 'meta ctrl right',
-    '[7D': 'meta ctrl left',
-    '[7E': 'meta ctrl 5',
-    '[7F': 'meta ctrl end',
-    '[7G': 'meta ctrl 5',
-    '[7H': 'meta ctrl home',
-    '[8A': 'shift meta ctrl up',
-    '[8B': 'shift meta ctrl down',
-    '[8C': 'shift meta ctrl right',
-    '[8D': 'shift meta ctrl left',
-    '[8E': 'shift meta ctrl 5',
-    '[8F': 'shift meta ctrl end',
-    '[8G': 'shift meta ctrl 5',
-    '[8H': 'shift meta ctrl home',
-    '[1;1A': 'up',
-    '[1;1B': 'down',
-    '[1;1C': 'right',
-    '[1;1D': 'left',
-    '[1;1E': '5',
-    '[1;1F': 'end',
-    '[1;1G': '5',
-    '[1;1H': 'home',
-    '[1;2A': 'shift up',
-    '[1;2B': 'shift down',
-    '[1;2C': 'shift right',
-    '[1;2D': 'shift left',
-    '[1;2E': 'shift 5',
-    '[1;2F': 'shift end',
-    '[1;2G': 'shift 5',
-    '[1;2H': 'shift home',
-    '[1;3A': 'meta up',
-    '[1;3B': 'meta down',
-    '[1;3C': 'meta right',
-    '[1;3D': 'meta left',
-    '[1;3E': 'meta 5',
-    '[1;3F': 'meta end',
-    '[1;3G': 'meta 5',
-    '[1;3H': 'meta home',
-    '[1;4A': 'shift meta up',
-    '[1;4B': 'shift meta down',
-    '[1;4C': 'shift meta right',
-    '[1;4D': 'shift meta left',
-    '[1;4E': 'shift meta 5',
-    '[1;4F': 'shift meta end',
-    '[1;4G': 'shift meta 5',
-    '[1;4H': 'shift meta home',
-    '[1;5A': 'ctrl up',
-    '[1;5B': 'ctrl down',
-    '[1;5C': 'ctrl right',
-    '[1;5D': 'ctrl left',
-    '[1;5E': 'ctrl 5',
-    '[1;5F': 'ctrl end',
-    '[1;5G': 'ctrl 5',
-    '[1;5H': 'ctrl home',
-    '[1;6A': 'shift ctrl up',
-    '[1;6B': 'shift ctrl down',
-    '[1;6C': 'shift ctrl right',
-    '[1;6D': 'shift ctrl left',
-    '[1;6E': 'shift ctrl 5',
-    '[1;6F': 'shift ctrl end',
-    '[1;6G': 'shift ctrl 5',
-    '[1;6H': 'shift ctrl home',
-    '[1;7A': 'meta ctrl up',
-    '[1;7B': 'meta ctrl down',
-    '[1;7C': 'meta ctrl right',
-    '[1;7D': 'meta ctrl left',
-    '[1;7E': 'meta ctrl 5',
-    '[1;7F': 'meta ctrl end',
-    '[1;7G': 'meta ctrl 5',
-    '[1;7H': 'meta ctrl home',
-    '[1;8A': 'shift meta ctrl up',
-    '[1;8B': 'shift meta ctrl down',
-    '[1;8C': 'shift meta ctrl right',
-    '[1;8D': 'shift meta ctrl left',
-    '[1;8E': 'shift meta ctrl 5',
-    '[1;8F': 'shift meta ctrl end',
-    '[1;8G': 'shift meta ctrl 5',
-    '[1;8H': 'shift meta ctrl home',
-    'O1P': 'f1',
-    'O1Q': 'f2',
-    'O1R': 'f3',
-    'O1S': 'f4',
-    'O2P': 'shift f1',
-    'O2Q': 'shift f2',
-    'O2R': 'shift f3',
-    'O2S': 'shift f4',
-    'O3P': 'meta f1',
-    'O3Q': 'meta f2',
-    'O3R': 'meta f3',
-    'O3S': 'meta f4',
-    'O4P': 'shift meta f1',
-    'O4Q': 'shift meta f2',
-    'O4R': 'shift meta f3',
-    'O4S': 'shift meta f4',
-    'O5P': 'ctrl f1',
-    'O5Q': 'ctrl f2',
-    'O5R': 'ctrl f3',
-    'O5S': 'ctrl f4',
-    'O6P': 'shift ctrl f1',
-    'O6Q': 'shift ctrl f2',
-    'O6R': 'shift ctrl f3',
-    'O6S': 'shift ctrl f4',
-    'O7P': 'meta ctrl f1',
-    'O7Q': 'meta ctrl f2',
-    'O7R': 'meta ctrl f3',
-    'O7S': 'meta ctrl f4',
-    'O8P': 'shift meta ctrl f1',
-    'O8Q': 'shift meta ctrl f2',
-    'O8R': 'shift meta ctrl f3',
-    'O8S': 'shift meta ctrl f4',
-    '[11;1~': 'f1',
-    '[12;1~': 'f2',
-    '[13;1~': 'f3',
-    '[14;1~': 'f4',
-    '[15;1~': 'f5',
-    '[17;1~': 'f6',
-    '[18;1~': 'f7',
-    '[19;1~': 'f8',
-    '[20;1~': 'f9',
-    '[21;1~': 'f10',
-    '[23;1~': 'f11',
-    '[24;1~': 'f12',
-    '[25;1~': 'f13',
-    '[26;1~': 'f14',
-    '[28;1~': 'f15',
-    '[29;1~': 'f16',
-    '[31;1~': 'f17',
-    '[32;1~': 'f18',
-    '[33;1~': 'f19',
-    '[34;1~': 'f20',
-    '[11;2~': 'shift f1',
-    '[12;2~': 'shift f2',
-    '[13;2~': 'shift f3',
-    '[14;2~': 'shift f4',
-    '[15;2~': 'shift f5',
-    '[17;2~': 'shift f6',
-    '[18;2~': 'shift f7',
-    '[19;2~': 'shift f8',
-    '[20;2~': 'shift f9',
-    '[21;2~': 'shift f10',
-    '[23;2~': 'shift f11',
-    '[24;2~': 'shift f12',
-    '[25;2~': 'shift f13',
-    '[26;2~': 'shift f14',
-    '[28;2~': 'shift f15',
-    '[29;2~': 'shift f16',
-    '[31;2~': 'shift f17',
-    '[32;2~': 'shift f18',
-    '[33;2~': 'shift f19',
-    '[34;2~': 'shift f20',
-    '[11;3~': 'meta f1',
-    '[12;3~': 'meta f2',
-    '[13;3~': 'meta f3',
-    '[14;3~': 'meta f4',
-    '[15;3~': 'meta f5',
-    '[17;3~': 'meta f6',
-    '[18;3~': 'meta f7',
-    '[19;3~': 'meta f8',
-    '[20;3~': 'meta f9',
-    '[21;3~': 'meta f10',
-    '[23;3~': 'meta f11',
-    '[24;3~': 'meta f12',
-    '[25;3~': 'meta f13',
-    '[26;3~': 'meta f14',
-    '[28;3~': 'meta f15',
-    '[29;3~': 'meta f16',
-    '[31;3~': 'meta f17',
-    '[32;3~': 'meta f18',
-    '[33;3~': 'meta f19',
-    '[34;3~': 'meta f20',
-    '[11;4~': 'shift meta f1',
-    '[12;4~': 'shift meta f2',
-    '[13;4~': 'shift meta f3',
-    '[14;4~': 'shift meta f4',
-    '[15;4~': 'shift meta f5',
-    '[17;4~': 'shift meta f6',
-    '[18;4~': 'shift meta f7',
-    '[19;4~': 'shift meta f8',
-    '[20;4~': 'shift meta f9',
-    '[21;4~': 'shift meta f10',
-    '[23;4~': 'shift meta f11',
-    '[24;4~': 'shift meta f12',
-    '[25;4~': 'shift meta f13',
-    '[26;4~': 'shift meta f14',
-    '[28;4~': 'shift meta f15',
-    '[29;4~': 'shift meta f16',
-    '[31;4~': 'shift meta f17',
-    '[32;4~': 'shift meta f18',
-    '[33;4~': 'shift meta f19',
-    '[34;4~': 'shift meta f20',
-    '[11;5~': 'ctrl f1',
-    '[12;5~': 'ctrl f2',
-    '[13;5~': 'ctrl f3',
-    '[14;5~': 'ctrl f4',
-    '[15;5~': 'ctrl f5',
-    '[17;5~': 'ctrl f6',
-    '[18;5~': 'ctrl f7',
-    '[19;5~': 'ctrl f8',
-    '[20;5~': 'ctrl f9',
-    '[21;5~': 'ctrl f10',
-    '[23;5~': 'ctrl f11',
-    '[24;5~': 'ctrl f12',
-    '[25;5~': 'ctrl f13',
-    '[26;5~': 'ctrl f14',
-    '[28;5~': 'ctrl f15',
-    '[29;5~': 'ctrl f16',
-    '[31;5~': 'ctrl f17',
-    '[32;5~': 'ctrl f18',
-    '[33;5~': 'ctrl f19',
-    '[34;5~': 'ctrl f20',
-    '[11;6~': 'shift ctrl f1',
-    '[12;6~': 'shift ctrl f2',
-    '[13;6~': 'shift ctrl f3',
-    '[14;6~': 'shift ctrl f4',
-    '[15;6~': 'shift ctrl f5',
-    '[17;6~': 'shift ctrl f6',
-    '[18;6~': 'shift ctrl f7',
-    '[19;6~': 'shift ctrl f8',
-    '[20;6~': 'shift ctrl f9',
-    '[21;6~': 'shift ctrl f10',
-    '[23;6~': 'shift ctrl f11',
-    '[24;6~': 'shift ctrl f12',
-    '[25;6~': 'shift ctrl f13',
-    '[26;6~': 'shift ctrl f14',
-    '[28;6~': 'shift ctrl f15',
-    '[29;6~': 'shift ctrl f16',
-    '[31;6~': 'shift ctrl f17',
-    '[32;6~': 'shift ctrl f18',
-    '[33;6~': 'shift ctrl f19',
-    '[34;6~': 'shift ctrl f20',
-    '[11;7~': 'meta ctrl f1',
-    '[12;7~': 'meta ctrl f2',
-    '[13;7~': 'meta ctrl f3',
-    '[14;7~': 'meta ctrl f4',
-    '[15;7~': 'meta ctrl f5',
-    '[17;7~': 'meta ctrl f6',
-    '[18;7~': 'meta ctrl f7',
-    '[19;7~': 'meta ctrl f8',
-    '[20;7~': 'meta ctrl f9',
-    '[21;7~': 'meta ctrl f10',
-    '[23;7~': 'meta ctrl f11',
-    '[24;7~': 'meta ctrl f12',
-    '[25;7~': 'meta ctrl f13',
-    '[26;7~': 'meta ctrl f14',
-    '[28;7~': 'meta ctrl f15',
-    '[29;7~': 'meta ctrl f16',
-    '[31;7~': 'meta ctrl f17',
-    '[32;7~': 'meta ctrl f18',
-    '[33;7~': 'meta ctrl f19',
-    '[34;7~': 'meta ctrl f20',
-    '[11;8~': 'shift meta ctrl f1',
-    '[12;8~': 'shift meta ctrl f2',
-    '[13;8~': 'shift meta ctrl f3',
-    '[14;8~': 'shift meta ctrl f4',
-    '[15;8~': 'shift meta ctrl f5',
-    '[17;8~': 'shift meta ctrl f6',
-    '[18;8~': 'shift meta ctrl f7',
-    '[19;8~': 'shift meta ctrl f8',
-    '[20;8~': 'shift meta ctrl f9',
-    '[21;8~': 'shift meta ctrl f10',
-    '[23;8~': 'shift meta ctrl f11',
-    '[24;8~': 'shift meta ctrl f12',
-    '[25;8~': 'shift meta ctrl f13',
-    '[26;8~': 'shift meta ctrl f14',
-    '[28;8~': 'shift meta ctrl f15',
-    '[29;8~': 'shift meta ctrl f16',
-    '[31;8~': 'shift meta ctrl f17',
-    '[32;8~': 'shift meta ctrl f18',
-    '[33;8~': 'shift meta ctrl f19',
-    '[34;8~': 'shift meta ctrl f20',
-}

palette.py

-# -*- coding: utf-8 -*-
-import curses
-
-colors = {
-    'default':        -1,
-    'black':          curses.COLOR_BLACK,  
-    'dark red':       curses.COLOR_RED,    
-    'dark green':     curses.COLOR_GREEN,  
-    'brown':          curses.COLOR_YELLOW, 
-    'dark blue':      curses.COLOR_BLUE,   
-    'dark magenta':   curses.COLOR_MAGENTA,
-    'dark cyan':      curses.COLOR_CYAN,   
-    'light gray':     curses.COLOR_WHITE,  
-    'dark gray':      curses.COLOR_BLACK,  
-    'light red':      curses.COLOR_RED,    
-    'light green':    curses.COLOR_GREEN,  
-    'yellow':         curses.COLOR_YELLOW, 
-    'light blue':     curses.COLOR_BLUE,   
-    'light magenta':  curses.COLOR_MAGENTA,
-    'light cyan':     curses.COLOR_CYAN,   
-    'white':          curses.COLOR_WHITE,  
-    }
-                                                                    
-
-
-class ColorScheme(object):
-    registered = {}
-
-
-    def __init__(self, foreground, background):
-        key = (foreground, background)
-        found = self.registered.get(key, None)
-        if not found:
-            self.num = len(self.registered) + 1
-            curses.start_color()
-            curses.init_pair(self.num, colors[foreground], colors[background])
-            self.registered[key] = self.num
-        else:
-            self.num = found
-
-        
-    def color_pair(self):
-        return curses.color_pair(self.num)
-
-
 import sys
 from weakref import WeakSet
 
-from console import debug
 from collections import namedtuple
 
 
     def processEvent(self):
         if self.queue:
             obj, event = self.queue.pop()
-            debug("processing event", event, "for", obj)
             if obj:
                 obj.event(event)
             return True
-from tgui import TApplication, TWidget, TLabel, TPoint, TSize, TPushButton, TCheckBox, TLineEdit, TMenu
+from tcore import TPoint, TSize
+from tgui import TApplication
+from tgui import TCheckBox, TPushButton
+from tgui import TLabel, TLineEdit, TMenu
+from tgui import TWidget
 
 
 def test():

tgui.py

-# -*- coding: utf-8 -*-
-import sys
-
-from cursesengine import PaintEngine, ColorScheme, debug
-from tcore import TSize, TPoint, TRect, TEvent, TEventLoop, TObject, dispatch, Signal, Property
-
-
-class TFocusPolicy:
-    NoFocus = 0
-    TabFocus = 1
-
-    
-class TEventTypes:
-    KeyPress = 6
-    #KeyRelease = 7
-    FocusIn = 8
-    FocusOut = 9
-    Paint = 12
-    Resize = 14
-    Show = 17
-    Hide = 18
-    Close = 19
-    User = 1000
-
-
-class TKey:
-    Key_Backtab = "shift tab"
-    Key_Tab = "\t"
-    Key_Return = "\n"
-    Key_Enter = "\n"
-    Key_Space = " "
-    Key_Backspace = "backspace"
-    Key_Left = "left"
-    Key_Right = "right"
-    Key_Up = "up"
-    Key_Down = "down"
-    
-
-
-class TKeyEvent(TEvent):
-
-
-    def __init__(self, key, text=None, modifiers=None):
-        super(TKeyEvent, self).__init__(TEventTypes.KeyPress)
-        self.key = key
-        self.text = text
-        self.modifiers = modifiers
-
-
-
-class TPaintEvent(TEvent):
-
-    
-    def __init__(self, rect=None):
-        super(TPaintEvent, self).__init__(TEventTypes.Paint)
-        self.rect = rect
-
-        
-
-class TCloseEvent(TEvent):
-    
-    
-    def __init__(self):
-        super(TCloseEvent, self).__init__(TEventTypes.Close)
-
-
-        
-class THideEvent(TEvent):
-
-    
-    def __init__(self):
-        super(THideEvent, self).__init__(TEventTypes.Hide)
-
-
-
-class TShowEvent(TEvent):
-
-    
-    def __init__(self):
-        super(TShowEvent, self).__init__(TEventTypes.Show)
-
-
-
-class TResizeEvent(TEvent):
-
-    
-    def __init__(self, size):
-        super(TResizeEvent, self).__init__(TEventTypes.Resize)
-        self.size = size
-
-
-
-class TFocusEvent(TEvent):
-
-
-    def __init__(self, kind, reason=None):
-        super(TFocusEvent, self).__init__(kind)
-        self.reason = reason
-
-
-    def gotFocus(self):
-        return self.kind == TEventTypes.FocusIn
-
-
-    def lostFocus(self):
-        return self.kind == TEventTypes.FocusOut
-
-
-    
-class TMargins(object):
-
-    __slots__ = ("top", "left", "right", "bottom")
-
-    
-    def __init__(self, left, top, right, bottom):
-        self.top = top
-        self.left = left
-        self.right = right
-        self.bottom = bottom
-
-
-class TColor:
-    def __init__(self, value):
-        self.value = value
-TColor.GRAY = TColor("light gray")
-TColor.BLACK = TColor("black")
-TColor.WHITE = TColor("white")
-TColor.RED = TColor("dark red")
-TColor.GREEN = TColor("dark green")
-        
-
-class TPalette(object):
-    
-    
-    def base(self):
-        return ColorScheme(TColor.RED.value, TColor.GRAY.value)
-    
-    window = base
-
-
-    def text(self):
-        return ColorScheme(TColor.BLACK.value, TColor.GRAY.value)
-
-    windowText = text
-    
-
-        
-class TPainter(object):
-
-
-    def __init__(self, obj=None):
-        self.stack = []
-        if obj:
-            self.begin(obj)
-        self.engine = PaintEngine.instance
-        #self.engine.hide_cursor()
-
-
-    def begin(self, obj):
-        self.stack.append(obj)
-        self.obj = obj
-        
-
-    def end(self):
-        self.stack.pop()
-        if self.stack:
-            self.obj = self.stack[-1]
-        else:
-            self.obj = None
-            
-            
-    def drawRect(self, rect):
-        pal = self.obj.palette()
-        gpos = self.obj.mapToGlobal(TPoint(0, 0))
-        x1 = gpos.x + rect.topLeft.x
-        y1 = gpos.y + rect.topLeft.y
-        width = rect.size.width
-        height = rect.size.height
-        x2 = x1 + width - 1
-        y2 = y1 + height - 1
-        self.engine.rectangle(x1, y1, x2, y2, pal.window())
-
-
-    
-    def drawLine(self, start_pos, end_pos):
-        x1, y1 = start_pos.x, start_pos.y
-        x2, y2 = end_pos.x, end_pos.y
-        if y1 == y1:
-            width = x2 - x1
-            self.engine.text(x1, y1, "-" * width)
-        elif x1 == x2:
-            for y in range(y1, y2+1):
-                self.engine.text(x1, y, "|")
-        else:
-            raise NotImplementedError("Only horizontal and vertial lines supported right now")
-
-        
-    @dispatch(TPoint, str)
-    def drawText(self, pos, text):
-        gpos = self.obj.mapToGlobal(TPoint(0,0))
-        pal = self.obj.palette()
-        self.engine.text(gpos.x + pos.x, gpos.y + pos.y, text, pal.text())
-        
-
-    @dispatch(int, int, str)
-    def drawText(self, x, y, text):
-        self.drawText(TPoint(x, y), text)
-
-
-    @dispatch(TRect, str)
-    def fillRect(self, rect, char):
-        pal = self.obj.palette()
-        gpos = self.obj.mapToGlobal(TPoint(0, 0))
-        x1 = gpos.x + rect.topLeft.x
-        y1 = gpos.y + rect.topLeft.y
-        width = rect.size.width
-        height = rect.size.height
-        x2 = x1 + width - 1
-        y2 = y1 + height - 1
-        for y in range(y1, y2):
-            self.engine.text(x1, y, char*width, pal.window())
-
-
-class TInputContext(TObject):
-
-
-    def __init__(self, parent=None):
-        super(TInputContext, self).__init__(parent)
-        self.xreadkeys = PaintEngine.instance.xreadkeys
-        
-
-    def poll(self):
-        extended, keys = self.xreadkeys()
-        if keys:
-            if extended:
-                event = TKeyEvent(key=keys)
-            else:
-                event = TKeyEvent(key=keys, text=keys)
-            self.focusWidget().postEvent(event)
-
-    
-    def setFocusWidget(self, widget):
-        old_focus_widget = self.focusWidget()
-        
-        if widget != old_focus_widget:
-            cls.instance._focus_widget = widget
-            if old_focus_widget:
-                old_focus_widget.postEvent(TFocusEvent(TEventTypes.FocusOut))
-            widget.postEvent(TFocusEvent(TEventTypes.FocusIn))
-            widget.activateWindow()
-
-
-    def focusWidget(self):
-        return TApplication.instance.focusWidget()
-
-
-
-
-
-class TApplication(TObject):
-
-    instance = None
-    
-    focusChanged = Signal()
-    
-    
-    def __init__(self):
-        super(TApplication, self).__init__()
-        self._active_window = None
-        self.event_loop = TEventLoop.instance()
-        TApplication.instance = self
-        self._desktop = TDesktopWidget()
-        self.input_context = TInputContext()
-
-
-    def quit(self, exitcode=0):
-        PaintEngine.instance.close()
-        sys.exit(exitcode)
-        
-
-    @classmethod
-    def desktop(cls):
-        return cls.instance._desktop
-
-    
-    @classmethod
-    def activeWindow(cls):
-        if cls.instance._active_window:
-            return cls.instance._active_window
-
-
-    @classmethod
-    def setActiveWindow(cls, widget):
-        window = widget.window()
-        if cls.instance._active_window != window:
-            cls.instance._active_window = window
-
-    
-    @classmethod
-    def allWidgets(cls):
-        found = list(cls.topLevelWidgets())
-        for obj in found:
-            for child in obj.children():
-                if isinstance(child, TWidget) and child not in found:
-                    found.append(child)
-        return found
-
-
-    @classmethod
-    def topLevelWidgets(cls):
-        l = []
-        for ref in TObject._object_instances:
-            obj = ref()
-            if obj is None:
-                continue
-            if isinstance(obj, TWidget) and obj.parent() == None:
-                l.append(obj)
-        return l
-
-    
-    @classmethod
-    def focusWidget(cls):
-        return cls.instance.activeWindow().focusWidget()
-    
-
-    def postEvent(self, receiver_object, event):
-        self.event_loop.postEvent(receiver_object, event)
-
-    
-    def sendEvent(self, receiver_object, event):
-        self.event_loop.sendEvent(receiver_object, event)
-
-    
-    def notify(self, receiver_object, event):
-        self.event_loop.notify(receiver_object, event)
-        
-        
-    def processEvent(self):
-        return self.event_loop.processEvent()
-    
-        
-    def run(self):
-        #self._desktop.show()
-        win = self.activeWindow().focusNextChild()
-        while True:
-            if self.processEvent():
-                PaintEngine.instance.refresh()
-            self.input_context.poll()
-
-
-def elide(text, width):
-    if len(text) > width:
-        text = text[:width-3] + "..."
-    return text
-
-
-
-
-class TAction(TObject):
-
-    changed = Signal()
-    triggered = Signal()
-
-
-    def __init__(self, parent=None, **kwargs):
-        self._text = ""
-        self._checked = False
-        super(TAction, self).__init__(parent, **kwargs)
-
-        
-    def text(self):
-        return self._text
-    
-    
-    def setText(self, text):
-        self._text = text
-        self.changed.emit()
-
-        
-    Text = Property(text, setText)
-
-    
-    def setChecked(self, flag):
-        self._checked = flag
-        self.changed.emit()
-
-        
-    def isChecked(self):
-        return self._checked
-
-    
-    Checked = Property(isChecked, setChecked)
-
-    
-    def trigger(self):
-        self.triggered.emit()
-
-
-class TWidget(TObject):
-
-    
-    def __init__(self, parent=None, **kwargs):
-        self._contents_margins = TMargins(0, 0, 0, 0)
-        self._focus_policy = TFocusPolicy.TabFocus
-        self._geom = (0, 0, 1, 1)
-        self._visible = True
-        self._focus_widget = None
-        self._palette = TPalette()
-        self._windowTitle = ""
-        self._actions = []
-        super(TWidget, self).__init__(parent, **kwargs)
-        if not parent:
-            self.activateWindow()
-
-
-    def actions(self):
-        return self._actions[:]
-            
-        
-    @dispatch(str)
-    def addAction(self, title):
-        return self.addAction(TAction(self, Text=title))
-        
-    
-    @dispatch(TAction)
-    def addAction(self, action):
-        self._actions.append(action)
-        self.update()
-        return action
-
-
-    def windowTitle(self):
-        return self._windowTitle
-
-        
-    def setWindowTitle(self, title):
-        self._windowTitle = title or ""
-        if not self.parent():
-            self.update()
-
-
-    WindowTitle = Property(windowTitle, setWindowTitle)
-    
-
-    @dispatch(int,int,int,int)
-    def setContentsMargins(self, left, top, right, bottom):
-        self.setContentsMargins(TMargins(left, top, right, bottom))
-        
-        
-    @dispatch(TMargins)
-    def setContentsMargins(self, margins):
-        old_margins = self._contents_margins
-        self._contents_margins = margins
-        if old_margins != margins:
-            self.postEvent(TResizeEvent(self.size))
-            self.update()
-
-        
-    def activateWindow(self):
-        TApplication.setActiveWindow(self)
-
-        
-    def _focusable_widgets(self):
-        l = []
-        for child in self.window().children():
-            if not isinstance(child, TWidget):
-                continue
-            if 0: #child.children():
-                pass # XXX: l.extend(child._focusable_widgets())
-            elif child.focusPolicy() != TFocusPolicy.NoFocus:
-                l.append(child)
-        return l
-
-
-    def nextInFocusChain(self):
-        focus_widget = self.focusWidget()
-        widgets = self._focusable_widgets()
-        if widgets:
-            try:
-                idx = widgets.index(focus_widget) + 1
-            except ValueError:
-                idx = 0
-            return widgets[idx % len(widgets)]
-
-            
-    def focusNextChild(self):
-        widget = self.window().nextInFocusChain()
-        if widget:
-            widget.setFocus()
-            return True
-        return False
-
-    
-    def previousInFocusChain(self):
-        focus_widget = self.focusWidget()
-        widgets = self._focusable_widgets()
-        if widgets:
-            try:
-                idx = widgets.index(focus_widget) - 1
-            except ValueError:
-                idx = -1
-            return widgets[idx]
-
-        
-    def setPalette(self, pal):
-        self._palette = pal
-        
-        
-    def palette(self):
-        return self._palette
-    
-
-    def focusWidget(self):
-        if self.parent():
-            return self.window().focusWidget()
-        if self._focus_widget:
-            return self._focus_widget
-
-
-
-    def focusPreviousChild(self):
-        widget = self.window().previousInFocusChain()
-        if widget:
-            widet.setFocus()
-            return True
-        return False
-
-
-    def setFocusPolicy(self, policy):
-        self._focus_policy = policy
-
-        
-    def focusPolicy(self):
-        return self._focus_policy
-
-        
-    def setFocus(self, reason=None):
-        if self._focus_policy == TFocusPolicy.NoFocus:
-            return
-        win = self.window()
-        if win._focus_widget:
-            win._focus_widget.postEvent(TFocusEvent(TEventTypes.FocusOut))
-        win._focus_widget = self
-        self.postEvent(TFocusEvent(TEventTypes.FocusIn))
-
-        
-    def hasFocus(self):
-        return TApplication.focusWidget() == self
-
-
-    def clearFocus(self):
-        if self.hasFocus():
-            self.postEvent(TFocusEvent())
-
-
-    
-    def sizeHint(self):
-        return TSize(1,1)
-
-        
-    def window(self):
-        obj = self
-        parent = obj.parent()
-        while parent:
-            obj = parent
-            parent = obj.parent()
-        return obj
-    
-
-    def close(self):
-        if self.parent() == None:
-            self.postEvent(THideEvent())
-            self.postEvent(TCloseEvent())
-            self.clearFocus()
-            return True
-        else:
-            return False
-
-        
-    def show(self):
-        self.setVisible(True)
-        
-
-    def hide(self):
-        self.setVisible(False)
-
-        
-    def setVisible(self, flag):
-        self._visible = flag
-        self.postEvent(TPaintEvent())
-        if flag:
-            self.postEvent(TShowEvent())
-        else:    
-            self.postEvent(THideEvent())
-        for child in self.children():
-            if isinstance(child, TWidget):
-                child.setVisible(flag)
-
-            
-    def isVisible(self):
-        return self._visible
-
-    Visible = Property(isVisible, setVisible)
-
-
-    def _update_geom(self, pos, size, silent=False):
-        x1 = pos.x
-        y1 = pos.y
-        x2 = x1 + size.width
-        y2 = y1 + size.height
-        self._geom = (x1, y1, x2, y2)
-        if not silent:
-            self.postEvent(TResizeEvent(size))
-
-        
-    def size(self):
-        (x1, y1, x2, y2) = self._geom
-        width, height = x2 - y1, y2 - y1
-        return TSize(width, height)
-    
-    
-    def width(self):
-        return self.size().width
-    
-    
-    def height(self):
-        return self.size().height
-
-    
-    def left(seft):
-        return self.pos().x
-
-    
-    def top(self):
-        return self.pos().y
-    
-
-    @dispatch(TSize)
-    def resize(self, size):
-        (x1, y1, x2, y2) = self._geom
-        width, height = size.width, size.height
-        self._update_geom(TPoint(x1, y1), TSize(width, height))
-
-        
-    @dispatch(int,int)
-    def resize(self, width, height):
-        self.resize(TSize(width, height))
-
-        
-    @dispatch(tuple)
-    def resize(self, (width, height)):
-        self.resize(TSize(width, height))
-        
-        
-    Size = Property(size, resize)
-
-
-    def pos(self):
-        (x1, y1, x2, y2) = self._geom
-        return TPoint(x1, y1)
-
-
-    @dispatch(TPoint)
-    def move(self, pos):
-        self._update_geom(pos, self.size())
-
-
-    
-    @dispatch(int,int)
-    def move(self, x, y):
-        self.move(TPoint(x, y))
-        
-        
-    @dispatch(tuple)
-    def move(self, (x,y)):
-        self.move(TPoint(x,y))
-
-        
-    Pos = Property(pos, move)
-
-
-    def geometry(self):
-        return TRect(self.pos(), self.size())
-
-    
-    @dispatch(TPoint, TSize)
-    def setGeometry(self, pos, size):
-        self._update_geom(pos, size)
-
-
-        
-    @dispatch(int,int,int,int)
-    def setGeometry(self, x1, y1, width, height):
-        self._update_geom(TPoint(x1, y1), TSize(width, height))
-
-        
-    @dispatch(tuple)
-    def setGeometry(self, (x1, y1, width, height)):
-        self._update_geom(TPoint(x1, y1), TSize(width, height))
-
-        
-    @dispatch(TRect)
-    def setGeometry(self, rect):
-        self._update_geom(rect.topLeft, rect.size)
-
-        
-    Geometry = Property(geometry, setGeometry)
-
-    
-    def mapToParent(self, pos):
-        parent = self.parent()
-        if not parent:
-            return TPoint(pos.x, pos.y)
-        else:
-            ppos = parent.pos()
-            return TPoint(ppos.x + pos.x, ppos.y + pos.y)
-
-
-    def mapToGlobal(self, pos):
-        obj = self
-        while obj:
-            pos = obj.mapToParent(pos)
-            obj = obj.parent()
-        return pos
-
-    
-    def event(self, event):
-        super(TWidget, self).event(event)
-        if event.accepted or event.ignored:
-            return
-        if isinstance(event, TPaintEvent):
-            self.paintEvent(event)
-        elif isinstance(event, TKeyEvent):
-            self.keyPressEvent(event)
-        elif isinstance(event, TShowEvent):
-            self.showEvent(event)
-        elif isinstance(event, THideEvent):
-            self.hideEvent(event)
-        elif isinstance(event, TCloseEvent):
-            self.closeEvent(event)
-        elif isinstance(event, TFocusEvent):
-            if event.gotFocus():
-                self.focusInEvent(event)
-            else:
-                self.focusOutEvent(event)
-
-                
-    def showEvent(self, event):
-        if not self.parent():
-            TApplication.setActiveWindow(self)
-        
-
-    def focusInEvent(self, event):
-        pos = self.mapToGlobal(self.pos())
-        PaintEngine.instance.gotoxy(pos.x, pos.y)
-        PaintEngine.instance.show_cursor()
-
-    
-    def focusOutEvent(self, event):
-        pass
-
-
-    def keyPressEvent(self, event):
-        if event.key == TKey.Key_Tab:
-            widget = self.nextInFocusChain()
-            widget.setFocus()
-            event.accept()
-        elif event.key == TKey.Key_Backtab:
-            widget = self.previousInFocusChain()
-            widget.setFocus()
-            event.accept()
-        
-
-
-    def paintEvent(self, event):
-        painter = TPainter(self)
-        if self.parent():
-            painter.fillRect(self.geometry(), " ")
-        else:
-            rect = self.geometry()
-            painter.drawRect(rect)
-            painter.fillRect(rect.inner(), " ")
-            pos = self.pos()
-            painter.drawText(pos.x + self.width() - 4, pos.y, "[*]")
-            painter.drawText(pos.x + 2, pos.y, " %s " % elide(self.windowTitle(), self.width() - 4) )
-        for child in self.children():
-            if isinstance(child, TWidget) and child.isVisible():
-                child.postEvent(event)
-
-
-    def resizeEvent(self, event):
-        pass
-
-    
-    def update(self, rect=None):
-        self.postEvent(TPaintEvent(rect))
-    
-        
-    def repaint(self, rect=None):
-        event = TPaintEvent(rect)
-        self.paintEvent(event)
-
-
-        
-
-
-class TDesktopWidget(TWidget):
-
-
-    def __init__(self):
-        self.engine = PaintEngine()
-        super(TDesktopWidget, self).__init__()
-        self._update_geom(TPoint(0, 0), self.sizeHint())
-
-        
-    def sizeHint(self):
-        return TSize(self.engine.width, self.engine.height)
-
-        
-    def paintEvent(self, event):
-        painter = TPainter(self)
-        painter.fillRect(self.geometry(), " ")
-
-
-    
-        
-class TFrame(TWidget):
-
-    
-    def __init__(self, parent):
-        super(TWidget, self).__init__(parent)
-        self.setContentsMargins(1, 1, -1, -1)
-
-    
-    def paintEvent(self, event):
-        TWidget.paintEvent(event)
-        painter = TPainter(self)
-        rect = self.geometry()
-        painter.drawRect(rect)
-        for child in self.children():
-            child.paintEvent(event)
-
-
-        
-class TDialog(TWidget):
-    
-
-    def __init__(self):
-        super(TWidget, self).__init__()
-        
-    
-
-        
-class AbstractTextWidgetMixin(object):
-
-    
-    def __init__(self, text=""):
-        self._text = text
-
-            
-    def sizeHint(self):
-        return TSize(min(70, len(self._text)), 1)
-
-
-    def setText(self, text):
-        self._text = text
-        self.resize(self.sizeHint())
-        self.update()
-
-
-    def text(self):
-        return self._text
-
-
-    Text = Property(text, setText)
-
-
-
-class TLabel(TWidget, AbstractTextWidgetMixin):
-
-    
-    def __init__(self, parent=None, **kwargs):
-        AbstractTextWidgetMixin.__init__(self)
-        TWidget.__init__(self, parent, **kwargs)
-        self.setFocusPolicy(TFocusPolicy.NoFocus)
-
-
-    def paintEvent(self, event):
-        painter = TPainter(self)
-        painter.drawText(self.pos(), elide(self.text(), self.width()))
-
-
-
-        
-class TAbstractButton(TWidget, AbstractTextWidgetMixin):
-
-    
-    clicked = Signal()
-    
-    
-    def __init__(self, parent=None, text="", checked=False, checkable=False, **kwargs):
-        AbstractTextWidgetMixin.__init__(self, text)
-        self._checked = checked
-        self._checkable = checkable
-        TWidget.__init__(self, parent, **kwargs)
-
-        
-    def setCheckable(self, flag):
-        self._checkable = flag
-        
-        
-    def isCheckable(self):
-        return self._checkable
-
-    Checkable = Property(isCheckable, setCheckable)
-
-    
-    def setChecked(self, flag):
-        self._checked = flag
-        self.update()
-        
-        
-    def isChecked(self):
-        return self._checked
-
-    
-    Checked = Property(isChecked, setChecked)
-
-    
-    def keyPressEvent(self, event):
-        if event.key == TKey.Key_Return:
-            if self.isCheckable():
-                self.setChecked(not self.isChecked())
-                return
-            else:
-                self.clicked.emit()
-        elif event.key == TKey.Key_Space:
-            if self.isCheckable():
-                self.setChecked(not self.isChecked())
-        super(TAbstractButton, self).keyPressEvent(event)
-
-        
-        
-class TCheckBox(TAbstractButton):
-
-    stateChanged = Signal()
-    
-    
-    def __init__(self, parent, **kwargs):
-        super(TCheckBox, self).__init__(parent, checkable=True, **kwargs)
-        
-        
-    def setChecked(self, flag):
-        super(TCheckBox, self).setChecked(flag)
-        self.stateChanged.emit(flag)
-        
-    
-    def paintEvent(self, event):
-        painter = TPainter(self)
-        checked = self._checked and "x" or " "
-        painter.drawText(self.pos(), "[%s] %s" % (checked, self.text()))
-
-        
-
-class TRadioButton(TAbstractButton):
-
-    
-    def __init__(self, parent):
-        super(TRadioButton, self).__init__(self, parent, checkable=True)
-
-    
-    def paintEvent(self, event):
-        painter = TPainter(self)
-        checked = self._checked and "x" or " "
-        painter.drawText(self.pos(), "(%s) %s" % (checked, self.text()))
-
-
-
-        
-class TPushButton(TAbstractButton):
-    
-    
-    def paintEvent(self, event):
-        painter = TPainter(self)
-        painter.drawText(self.pos(), "< %s >" % self.text())
-
-
-        
-class TToolButton(TAbstractButton):
-    pass
-
-
-
-class TLineEdit(TWidget):
-    
-    cursorPositionChanged = Signal()
-    textChanged = Signal()
-
-
-    def __init__(self, parent, **kwargs):
-        self._text = ""
-        self._cursorPosition = 0
-        self._cursor_offset = 0
-        super(TLineEdit, self).__init__(parent, **kwargs)
-        
-        
-    def text(self):
-        return self._text
-    
-    
-    def setText(self, text):
-        old_text = self._text
-        if old_text != text:
-            self._text = text
-            self.update()
-            self.textChanged.emit(text)
-
-    
-    Text = Property(text, setText)
-        
-
-    def cursorPosition(self):
-        return self._cursorPosition
-    
-    
-    def setCursorPosition(self, pos):
-        old_pos = self._cursorPosition
-        if pos != old_pos:
-            self._cursorPosition = pos
-            pos = self.mapToGlobal(self.pos())
-            PaintEngine.instance.gotoxy(pos.x + self.cursorPosition() + 1, pos.y)
-            PaintEngine.instance.show_cursor()
-            self.cursorPositionChanged.emit(old_pos, pos)
-
-
-    CursorPosition = Property(cursorPosition, setCursorPosition)
-
-    
-    def focusInEvent(self, event):
-        pos = self.mapToGlobal(self.pos())
-        PaintEngine.instance.gotoxy(pos.x + self.cursorPosition() + 1, pos.y)
-        PaintEngine.instance.show_cursor()
-        
-    
-    def paintEvent(self, event):
-        painter = TPainter(self)
-        text = self.text()[self._cursor_offset:self._cursor_offset+self.width()]
-        display_text = "[%s]" % text.ljust(self.width(), " ")
-        painter.drawText(self.pos(), display_text)
-
-        
-    def keyPressEvent(self, event):
-        if event.key in (TKey.Key_Tab, TKey.Key_Backtab, 
-                         TKey.Key_Return, TKey.Key_Enter):
-            pass
-        elif event.key or event.text:
-            text = self.text()
-            cpos = self.cursorPosition()
-            tpos = self._cursor_offset + cpos
-            if event.text:
-                new_text = text[:tpos] + event.key + text[tpos:]
-                self.setText(new_text)
-                if cpos == self.width()-2:
-                    self._cursor_offset += 1
-                    self.setCursorPosition(cpos) # XXX
-                else:
-                    self.setCursorPosition(cpos + 1)
-            elif event.key == TKey.Key_Backspace:     
-                new_text = text[:tpos-1] + text[tpos:]
-                self.setText(new_text)
-                if tpos > 0 and cpos == 0:
-                    self._cursor_offset -= 1
-                    self.setCursorPosition(cpos) # XXX
-                elif cpos > 0:
-                    self.setCursorPosition(cpos - 1)
-                else:
-                    self.setCursorPosition(cpos) # XXX
-            elif event.key == TKey.Key_Left:
-                if cpos > 0:
-                    self.setCursorPosition(cpos - 1)
-                elif tpos > 0:
-                    self._cursor_offset -= 1
-                    self.setCursorPosition(cpos) # XXX
-            elif event.key == TKey.Key_Right:
-                if cpos < len(self.text()):
-                    self.setCursorPosition(cpos + 1)
-                elif len(self.text()) > self.width():
-                    self._cursor_offset += 1
-                    self.setCursorPosition(cpos) # XXX
-            #else:
-            #    print repr(event.key)
-
-        super(TLineEdit, self).keyPressEvent(event)
-
-
-        
-class TMenu(TWidget):
-
-
-    def __init__(self, parent, **kwargs):
-        self._actions = []
-        self._current = -1
-        super(TMenu, self).__init__(parent, **kwargs)
-        self._menuAction = TAction(self)
-
-        
-    def menuAction(self):
-        return self._menuAction
-    
-    
-    def setMenuAction(self, action):
-        self._menuAction = action
-    
-        
-    MenuAction = Property(menuAction, setMenuAction)
-
-    
-    def title(self):
-        return self.menuAction().title()
-    
-    
-    def setTitle(self, title):
-        self.menuAction().setText(title)
-        #self.update()        
-
-        
-    Title = Property(title, setTitle)
-        
-
-    def sizeHint(self):
-        w = max(len(action.text()) for action in self.actions())
-        h = len(self._actions)
-        return TSize(min(40, w), min(20, h))
-
-    
-    def actionAction(self):
-        self.actions()[self._current]
-        
-    
-    def setActiveAction(self, action):
-        self._current = self.actions().index(action)
-        self.update()
-
-    
-    def keyPressEvent(self, event):
-        if event.key == TKey.Key_Down:
-            self._current += 1
-            if self._current >= len(self.actions()):
-                self._current = 0
-            self.update()
-        elif event.key == TKey.Key_Up:
-            self._current -= 1
-            if self._current < 0:
-                self._current = len(self.actions()) - 1
-            self.update()
-        elif event.key in (TKey.Key_Return, TKey.Key_Enter):
-            self.activeAction().trigger()
-        else:
-            super(TMenu, self).keyPressEvent(event)
-
-        
-    def paintEvent(self, event):
-        pos = self.mapToParent(self.pos())
-        painter = TPainter(self)
-        painter.drawRect(self.geometry())
-        h = self.height() - 2
-        w = self.width() - 2
-        for i, action in enumerate(self.actions()[:h]):
-            if i == self._current:
-                text = ">%s<" % elide(action.text(), w - 2)
-            else:
-                text = " %s " % elide(action.text(), w - 2)
-            painter.drawText(pos.x+2, pos.y+i + 1, text)
-
-
-
-class TMenuBar(TWidget):
-
-
-    def __init__(self, parent, **kwargs):
-        self._menus = []
-        self._current = -1
-        super(TMenuBar, self).__init__(parent, **kwargs)
-
-        
-    def addMenu(self, menu):
-        self._menus.append(menu)
-        
-        
-    def keyPressEvent(self, event):
-        if event.key == TKey.Key_Right:
-            self._current += 1
-            if self._current >= len(self._menus):
-                self._current = 0
-            self.update()
-        elif event.key == TKey.Key_Left:
-            self._current -= 1
-            if self._current < 0:
-                self._current = len(self._menus) - 1
-            self.update()
-        elif event.key in (TKey.Key_Return, TKey.Key_Enter):
-            self._menus[self._current].show()
-        else:
-            super(TMenuBar, self).keyPressEvent(event)
-
-        
-    def paintEvent(self, event):
-        painter = TPainter(self)
-        pos = self.pos()
-        dx = 0
-        for menu in self._menus:
-            title = " %s " % elide(menu.title(), self.width() - dx)
-            painter.drawText(0, dx, title)
-            dx += len(title) + 2
-            
-            
+# -*- coding: utf-8 -*-
+#from tcore import TSize, TPoint, TRect, TEvent, TEventLoop, TObject, dispatch, Signal, Property
+from tgui.base import (TEventTypes, TKey, TFocusPolicy, TKeyEvent, TPaintEvent, TCloseEvent, THideEvent, TShowEvent,
+                       TResizeEvent, TFocusEvent, TMargins, TColor, TPalette, elide,
+                       TPainter, TPaintEngine, TColorScheme, debug)
+from tgui.tapplication import TInputContext, TApplication, TDesktopWidget
+from tgui.buttons import TAbstractButton, TPushButton, TToolButton, TCheckBox, TRadioButton
+from tgui.widgets import AbstractTextWidgetMixin, TLineEdit, TMenu, TMenuBar, TLabel
+from tgui.twidget import  TAction, TWidget
+
+
+# -*- coding: utf-8 -*-
+from exceptions import NotImplementedError
+
+from tcore import TEvent, TPoint, dispatch, TRect
+from tgui.palette import TColorScheme
+from tgui.cursesengine import TPaintEngine, debug # will be imported from other modules from here
+
+
+class TEventTypes:
+    KeyPress = 6
+    #KeyRelease = 7
+    FocusIn = 8
+    FocusOut = 9
+    Paint = 12
+    Resize = 14
+    Show = 17
+    Hide = 18
+    Close = 19
+    User = 1000
+
+
+class TKey:
+    Key_Backtab = "shift tab"
+    Key_Tab = "\t"
+    Key_Return = "\n"
+    Key_Enter = "\n"
+    Key_Space = " "
+    Key_Backspace = "backspace"
+    Key_Left = "left"
+    Key_Right = "right"
+    Key_Up = "up"
+    Key_Down = "down"
+
+
+class TFocusPolicy:
+    NoFocus = 0
+    TabFocus = 1
+
+
+class TKeyEvent(TEvent):
+
+
+    def __init__(self, key, text=None, modifiers=None):
+        super(TKeyEvent, self).__init__(TEventTypes.KeyPress)
+        self.key = key
+        self.text = text
+        self.modifiers = modifiers
+
+
+class TPaintEvent(TEvent):
+
+
+    def __init__(self, rect=None):
+        super(TPaintEvent, self).__init__(TEventTypes.Paint)
+        self.rect = rect
+
+
+class TCloseEvent(TEvent):
+
+
+    def __init__(self):
+        super(TCloseEvent, self).__init__(TEventTypes.Close)
+
+
+class THideEvent(TEvent):
+
+
+    def __init__(self):
+        super(THideEvent, self).__init__(TEventTypes.Hide)
+
+
+class TShowEvent(TEvent):
+
+
+    def __init__(self):
+        super(TShowEvent, self).__init__(TEventTypes.Show)
+
+
+class TResizeEvent(TEvent):
+
+
+    def __init__(self, size):
+        super(TResizeEvent, self).__init__(TEventTypes.Resize)
+        self.size = size
+
+
+class TFocusEvent(TEvent):
+
+
+    def __init__(self, kind, reason=None):
+        super(TFocusEvent, self).__init__(kind)
+        self.reason = reason
+
+
+    def gotFocus(self):
+        return self.kind == TEventTypes.FocusIn
+
+
+    def lostFocus(self):
+        return self.kind == TEventTypes.FocusOut
+
+
+class TMargins(object):
+
+    __slots__ = ("top", "left", "right", "bottom")
+
+
+    def __init__(self, left, top, right, bottom):
+        self.top = top
+        self.left = left
+        self.right = right
+        self.bottom = bottom
+
+
+class TColor:
+    def __init__(self, value):
+        self.value = value
+
+TColor.GRAY = TColor("light gray")
+TColor.BLACK = TColor("black")
+TColor.WHITE = TColor("white")
+TColor.RED = TColor("dark red")
+TColor.GREEN = TColor("dark green")
+
+
+
+class TPalette(object):
+
+
+    def base(self):
+        return TColorScheme(TColor.RED.value, TColor.GRAY.value)
+
+    window = base
+
+
+    def text(self):
+        return TColorScheme(TColor.BLACK.value, TColor.GRAY.value)
+
+    windowText = text
+
+
+def elide(text, width):
+    if len(text) > width:
+        text = text[:width-3] + "..."
+    return text
+
+
+class TPainter(object):
+
+
+    def __init__(self, obj=None):
+        self.stack = []
+        if obj:
+            self.begin(obj)
+        self.engine = TPaintEngine.instance
+        #self.engine.hide_cursor()
+
+
+    def begin(self, obj):
+        self.stack.append(obj)
+        self.obj = obj
+
+
+    def end(self):
+        self.stack.pop()
+        if self.stack:
+            self.obj = self.stack[-1]
+        else:
+            self.obj = None
+
+
+    def drawRect(self, rect):
+        pal = self.obj.palette()
+        gpos = self.obj.mapToGlobal(TPoint(0, 0))
+        x1 = gpos.x + rect.topLeft.x
+        y1 = gpos.y + rect.topLeft.y
+        width = rect.size.width
+        height = rect.size.height
+        x2 = x1 + width - 1
+        y2 = y1 + height - 1
+        self.engine.rectangle(x1, y1, x2, y2, pal.window())
+
+
+
+    def drawLine(self, start_pos, end_pos):
+        x1, y1 = start_pos.x, start_pos.y
+        x2, y2 = end_pos.x, end_pos.y
+        if y1 == y1:
+            width = x2 - x1
+            self.engine.text(x1, y1, "-" * width)
+        elif x1 == x2:
+            for y in range(y1, y2+1):
+                self.engine.text(x1, y, "|")
+        else:
+            raise NotImplementedError("Only horizontal and vertial lines supported right now")
+
+
+    @dispatch(TPoint, str)
+    def drawText(self, pos, text):
+        gpos = self.obj.mapToGlobal(TPoint(0,0))
+        pal = self.obj.palette()
+        self.engine.text(gpos.x + pos.x, gpos.y + pos.y, text, pal.text())
+
+
+    @dispatch(int, int, str)
+    def drawText(self, x, y, text):
+        self.drawText(TPoint(x, y), text)
+
+
+    @dispatch(TRect, str)
+    def fillRect(self, rect, char):
+        pal = self.obj.palette()
+        gpos = self.obj.mapToGlobal(TPoint(0, 0))
+        x1 = gpos.x + rect.topLeft.x
+        y1 = gpos.y + rect.topLeft.y
+        width = rect.size.width
+        height = rect.size.height
+        x2 = x1 + width - 1
+        y2 = y1 + height - 1
+        for y in range(y1, y2):
+            self.engine.text(x1, y, char*width, pal.window())
+# -*- coding: utf-8 -*-
+from tcore import Signal, Property
+from tgui.base import TKey, TPainter
+from tgui.widgets import AbstractTextWidgetMixin
+from tgui.twidget import TWidget
+
+
+class TAbstractButton(TWidget, AbstractTextWidgetMixin):
+
+
+    clicked = Signal()
+
+
+    def __init__(self, parent=None, text="", checked=False, checkable=False, **kwargs):
+        AbstractTextWidgetMixin.__init__(self, text)
+        self._checked = checked
+        self._checkable = checkable
+        TWidget.__init__(self, parent, **kwargs)
+
+
+    def setCheckable(self, flag):
+        self._checkable = flag
+
+
+    def isCheckable(self):
+        return self._checkable
+
+    Checkable = Property(isCheckable, setCheckable)
+
+
+    def setChecked(self, flag):
+        self._checked = flag
+        self.update()
+
+
+    def isChecked(self):
+        return self._checked
+
+
+    Checked = Property(isChecked, setChecked)
+
+
+    def keyPressEvent(self, event):
+        if event.key == TKey.Key_Return:
+            if self.isCheckable():
+                self.setChecked(not self.isChecked())
+                return
+            else:
+                self.clicked.emit()
+        elif event.key == TKey.Key_Space:
+            if self.isCheckable():
+                self.setChecked(not self.isChecked())
+        super(TAbstractButton, self).keyPressEvent(event)
+
+
+class TCheckBox(TAbstractButton):
+
+    stateChanged = Signal()
+
+
+    def __init__(self, parent, **kwargs):
+        super(TCheckBox, self).__init__(parent, checkable=True, **kwargs)
+
+
+    def setChecked(self, flag):
+        super(TCheckBox, self).setChecked(flag)
+        self.stateChanged.emit(flag)
+
+
+    def paintEvent(self, event):
+        painter = TPainter(self)
+        checked = self._checked and "x" or " "
+        painter.drawText(self.pos(), "[%s] %s" % (checked, self.text()))
+
+
+class TPushButton(TAbstractButton):
+
+
+    def paintEvent(self, event):
+        painter = TPainter(self)
+        painter.drawText(self.pos(), "< %s >" % self.text())
+
+
+class TRadioButton(TAbstractButton):
+
+
+    def __init__(self, parent):
+        super(TRadioButton, self).__init__(self, parent, checkable=True)
+
+
+    def paintEvent(self, event):
+        painter = TPainter(self)
+        checked = self._checked and "x" or " "
+        painter.drawText(self.pos(), "(%s) %s" % (checked, self.text()))
+
+
+class TToolButton(TAbstractButton):
+    pass

tgui/cursesengine.py

+# -*_ coding: utf-8 -*-
+# http://gnosis.cx/publish/programming/charming_python_6.html
+import sys
+import curses
+
+from keymap import keymap
+from palette import TColorScheme
+
+
+def debug(*args):