Commits

Henning Schröder  committed 573b43e

changed focus works, added simple signal implementation

  • Participants
  • Parent commits cb9f23f

Comments (0)

Files changed (5)

         if curses.has_colors():
             curses.start_color()
         curses.noecho()
-        curses.cbreak()    
-        #curses.raw() # intercept everything
+        #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)
+        self.window.keypad(1)
 
         
         # Frame the interface area at fixed VT100 size
 
         
     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()
-        xkeys = keymap.get(keys, None)
-        if xkeys:
-            return True, xkeys
+        
+        if keys in umlauts:
+            return False, umlauts[keys]
+
+        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 gotoxy(self, x, y):
         self.window.move(x, y)
+        self.text(x,y, "")
 
         
     def show_cursor(self):

File generate_keymap.py

     
     ('[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;"
     (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")
 # -*- coding: utf-8 -*-
 import sys
+from weakref import WeakSet
 
 from console import debug
 from collections import namedtuple
         return False
 
 
+    
+
+
+    
+
+
+class ObjectSignal(object):
+
+
+    def __init__(self, sender):
+        self.sender = sender
+        self.slots = WeakSet()
+        
+        
+    def connect(self, slot):
+        self.slots.add(slot)
+        
+        
+    def emit(self, *args):
+        if self.sender.signalsBlocked():
+            return
+        TObject._sender = self.sender
+        for ref in self.slots:
+            slot = ref()
+            if slot:
+                slot(*args)
+        # Object.sender = None
+
+
+
+class Signal(object):
+    
+
+    def __get__(self, obj, cls):
+        signals = obj.__dict__.setdefault("__signals__", {})
+        objsig = signals.get(self)
+        if not objsig:
+            objsig = ObjectSignal(obj)
+            signals[self] = objsig
+        return objsig
+
+
+
+
 
 class TObject(object):
+    _object_instances = WeakSet()
+    
+    _sender = None
+
+
+    destroyed = Signal()
+
+
+
+    def __init__(self, parent=None):
+        TObject._object_instances.add(self)
+        self._children = set()
+        self._parent = None
+        self._event_filters = set()
+        self._signals_blocked = False
+    
+        if parent:
+            self.setParent(parent)        
+    
+            
+
+    @classmethod
+    def sender(cls):
+        return cls._sender
+    
 
     
-    def __init__(self, parent=None):
-        self._children = set()
-        self._parent = parent
-        self._event_filters = set()
-        if parent:
-            parent._children.add(self)
+    def signalsBlocked(self):
+        return self._signals_blocked
+    
+    
+    def blockSignals(self, flag):
+        self._signals_blcoked = flag
 
+
+    def delete(self):
+        self.setParent(None)
+        for child in self.children():
+            child.delete()
+        self.destoyed.emit(self)            
+        TObject._object_instances.remove(self)
+        
+        
+    __del__ = delete
+
+
+    def _add_child(self, child):
+        old_parent = child.parent()
+        if old_parent:
+            old_parent._remove_child(child)
+        self._children.add(child)
+        child._parent = self
+        
+        
+    def _remove_child(self, child):
+        self._children.remove(child)
+        child._parent = None
+        
             
     def setParent(self, new_parent):
-        parent = self.parent()
-        if parent:
-            parent._children.remove(self)
-        self._parent = new_parent
-        if new_parent:
-            new_parent._children.add(self)
+        if not new_parent:
+            old_parent = self.parent()
+            if old_parent:
+                old_parent._remove_child(self)
+        else:
+            new_parent._add_child(self)
 
             
     def children(self):
     
 
 
-
-
-
-
     
 if __name__ == "__main__":
     @dispatch(int)
         
 
     test(1)
-    test(1.0)
+    test(1.0)
+    
+    
+    
+    
+    
+    
-from tgui import TApplication, TWidget, TLabel, TPoint, TSize, TPushButton
+from tgui import TApplication, TWidget, TLabel, TPoint, TSize, TPushButton, TCheckBox
+
+
+def test():
+	l.setText("clicked!")
+
+
+def exit():
+	app.quit()
 
 
 app = TApplication()
 app.desktop().show()
 win = TWidget()
-win.move(TPoint(5, 5))
-win.resize(TSize(60, 15))
+win.move(5,5)
+win.resize(60,15)
+
+
+c = TCheckBox(win)
+c.setText("Is this working?")
+c.move(2,3)
+c.resize(10,10)
+
+
 l = TLabel(win)
 l.setText("Hello, world")
 l.move(TPoint(2,2))
+
 b = TPushButton(win, "OK")
-b.move(TPoint(4,4))
+b.move(4,4)
+b.clicked.connect(test)
+
+
+q = TPushButton(win, "Quit")
+q.move(20, 4)
+q.clicked.connect(exit)
+
 win.show()
 
 app.run()
-##while app.event_loop.processEvent():
-##    pass
-##app.desktop().console.getchar(wait=True)
-#app.desktop().console.close()
 # -*- coding: utf-8 -*-
+import sys
+
 from console import Console, debug
-from tcore import TSize, TPoint, TRect, TEvent, TEventLoop, TObject, dispatch
+from tcore import TSize, TPoint, TRect, TEvent, TEventLoop, TObject, dispatch, Signal
 
 
 class TFocusPolicy:
 
 
 class TKey:
-    pass
+    Key_Tab = "\t"
+    Key_Return = "\n"
+    Key_Enter = "\n"
+    Key_Space = " "
 
 
 
         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.GREY = TColor(7)
+TColor.BLACK = TColor(0)
+TColor.WHITE = TColor(15)
+TColor.RED = TColor(4)
+        
+
+class TPalette(object):
+    
+    
+    
+    def base(self):
+        return TColor.GREY
+    
+    window = base
+
+
+    def text(self):
+        return TColor.BLACK    
+
+    windowText = text
+    
 
         
 class TPainter(object):
     def __init__(self, obj=None):
         self.stack = []
         if obj:
-            self.stack.append(obj)
-        self.obj = obj
+            self.begin(obj)
         self.engine = Console.instance
+        self.engine.hide_cursor()
 
 
     def begin(self, obj):
     
 
 
-class TInputHook(object):
+class TInputContext(TObject):
 
 
-    def __init__(self):
+    def __init__(self, parent=None):
+        super(TInputContext, self).__init__(parent)
         self.xreadkeys = Console.instance.xreadkeys
-    
+        
 
     def poll(self):
         extended, keys = self.xreadkeys()
         if keys:
-            Console.instance.text(1,1, "poll %r    " % keys)
-            return TKeyEvent(keys)
+            #Console.instance.text(1,1, "poll %r    " % keys)
+            self.focusWidget().postEvent(TKeyEvent(keys))
+
+    
+    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._focus_widget = None
-        self._top_level_widgets = set()
+        self._active_window = None
         self.event_loop = TEventLoop.instance()
         TApplication.instance = self
         self._desktop = TDesktopWidget()
-        self.input_hook = TInputHook()
+        self.input_context = TInputContext()
 
-        #self.focusChanged = Signal()
 
+    def quit(self, exitcode=0):
+        Console.instance.close()
+        sys.exit(exitcode)
+        
 
     @classmethod
     def desktop(cls):
     
     @classmethod
     def activeWindow(cls):
-        return cls.focusWidget().window()
+        if cls.instance._active_window:
+            return cls.instance._active_window
 
 
     @classmethod
-    def setActiveWindow(cls, window):
-        cls.setFocusWidget(window.focusNextChild())
+    def setActiveWindow(cls, widget):
+        window = widget.window()
+        if cls.instance._active_window != window:
+            cls.instance._active_window = window
 
     
     @classmethod
                     found.append(child)
         return found
 
-    
-    @classmethod
-    def _registerTopLevelWidget(cls, widget):
-        if not cls.focusWidget():
-            cls.setFocusWidget(widget)
-        cls.instance._top_level_widgets.add(widget)
-
-        
-    @classmethod
-    def _unregisterTopLevelWidget(cls, widget):
-        cls.instance._top_level_widgets.remove(widget)
-
 
     @classmethod
     def topLevelWidgets(cls):
-        return list(cls.instance._top_level_widgets)
+        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._focus_widget
+        return cls.instance.activeWindow().focusWidget()
     
-    
-    @classmethod
-    def setFocusWidget(cls, widget):
-        old_focus_widget = cls.instance._focus_widget
-        if widget != old_focus_widget:
-            cls.instance._focus_widget = widget
-            if old_focus_widget:
-                cls.instance.postEvent(old_focus_widget, TFocusEvent(TEventTypes.FocusOut))
-            cls.instance.postEvent(widget, TFocusEvent(TEventTypes.FocusIn))
-
 
     def postEvent(self, receiver_object, event):
         self.event_loop.postEvent(receiver_object, event)
         while True:
             if self.processEvent():
                 Console.instance.refresh()
-            event = self.input_hook.poll()
-            if event:
-                self.postEvent(self.focusWidget(), event)
+            self.input_context.poll()
 
             
 
         self._focus_policy = TFocusPolicy.TabFocus
         self._update_geom(TPoint(0,0), self.sizeHint(), silent=True)
         self._visible = True
+        self._focus_widget = None
+        self._palette = TPalette()
         if not parent:
-            TApplication._registerTopLevelWidget(self)
+            self.activateWindow()
+        self._contents_margins = TMargins(0, 0, 0, 0)
+        
+        
+    @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 _find_focusNextChild(self):
-        focus_widget = TApplication.focusWidget()
-        found = False
-        for child in self.children():
+        
+    def _focusable_widgets(self):
+        l = []
+        for child in self.window().children():
             if not isinstance(child, TWidget):
                 continue
-            if child == focus_widget:
-                found = True
-                continue
-            if found or not focus_widget:
-                return child
-    
+            if child.children():
+                l.extend(child._focusable_widget())
+            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._find_focusNextChild()
+        widget = self.window().nextInFocusChain()
         if widget:
             widget.setFocus()
+            return True
+        return False
 
     
-    def _find_focusPreviousChild(self):
-        focus_widget = TApplication.focusWidget()
-        previous = None
-        for child in self.children():
-            if child == focus_widget:
-                return previous
-            if isinstance(child, TWidget):
-                if not focus_widget:
-                    return child
-                previous = child
+    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._find_focusPreviousChild()
+        widget = self.window().previousInFocusChain()
         if widget:
             widet.setFocus()
+            return True
+        return False
 
 
     def setFocusPolicy(self, policy):
 
         
     def focusPolicy(self):
-        return self,_focus_policy
+        return self._focus_policy
 
         
     def setFocus(self, reason=None):
         if self._focus_policy == TFocusPolicy.NoFocus:
             return
-        TApplication.setFocusWidget(self)
+        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):
             obj = parent
             parent = obj.parent()
         return obj
-
-
-    def __del__(self):
-        TApplication._unregisterTopLevelWidget(self)
     
 
     def close(self):
         else:
             return False
 
- 
-       
+        
     def show(self):
         self.setVisible(True)
         
         for child in self.children():
             child.setVisible(flag)
 
+            
+    def isVisible(self):
+        return self._visible
+
 
     def _update_geom(self, pos, size, silent=False):
         x1 = pos.x
         
 
     def focusInEvent(self, event):
-        pass
-            
+        pos = self.mapToGlobal(self.pos())
+        Console.instance.gotoxy(pos.x, pos.y)
+        Console.instance.show_cursor()
+
     
     def focusOutEvent(self, event):
         pass
 
 
     def keyPressEvent(self, event):
-        if event.key == Key_Tab:
-            widget = self.parent().focusNextChild()
+        if event.key == TKey.Key_Tab:
+            widget = self.nextInFocusChain()
             widget.setFocus()
             event.accept()
 
             rect = self.geometry()
             painter.drawRect(rect)
             painter.fillRect(rect.inner(), " ")
+        for child in self.children():
+            if isinstance(child, TWidget) and child.isVisible():
+                child.postEvent(event)
 
 
     def resizeEvent(self, event):
         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):
 
 
 
+
 class TLabel(TWidget, AbstractTextWidgetMixin):
 
     
     def __init__(self, parent=None, text=""):
         AbstractTextWidgetMixin.__init__(self, text)
         TWidget.__init__(self, parent)
+        self.setFocusPolicy(TFocusPolicy.NoFocus)
 
-    
 
     def paintEvent(self, event):
         painter = TPainter(self)
 class TAbstractButton(TWidget, AbstractTextWidgetMixin):
 
     
-    def __init__(self, parent=None, text="", checked=False):
+    clicked = Signal()
+    
+    
+    def __init__(self, parent=None, text="", checked=False, checkable=False):
         AbstractTextWidgetMixin.__init__(self, text)
         self._checked = checked
+        self._checkable = checkable
         TWidget.__init__(self, parent)
 
+        
+    def setCheckable(self, flag):
+        self._checkable = flag
+        
+        
+    def isCheckable(self):
+        return self._checkable
+
 
     def setChecked(self, flag):
         self._checked = flag
     def isChecked(self):
         return self._checked
 
+    
+    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):
+        super(TCheckBox, self).__init__(parent, checkable=True)
+        
+        
+    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 " "
         
 
 class TRadioButton(TAbstractButton):
+
     
+    def __init__(self, parent):
+        super(TRadioButton, self).__init__(self, parent, checkable=True)
+
     
     def paintEvent(self, event):
         painter = TPainter(self)
         painter = TPainter(self)
         painter.drawText(self.pos(), "< %s >" % self.text())
 
+
+        
+class TToolButton(TAbstractButton):
+    pass