Menu development. New focus. Easier imports from tuikit package.
authorRadek Brich <radek.brich@devl.cz>
Thu, 17 Feb 2011 23:35:05 +0100
changeset 1 69318aba22bf
parent 0 a35731b5e31a
child 2 684cdc352562
Menu development. New focus. Easier imports from tuikit package.
docs/focus.rst
example.py
tuikit/__init__.py
tuikit/application.py
tuikit/container.py
tuikit/menu.py
tuikit/menubar.py
tuikit/widget.py
--- a/docs/focus.rst	Wed Feb 16 23:51:30 2011 +0100
+++ b/docs/focus.rst	Thu Feb 17 23:35:05 2011 +0100
@@ -1,14 +1,16 @@
 Focus
 =====
 
-Only one non-container widget can have focus at the time.
-All parent containers also have focus.
+Only one widget can have focus at the time.
+Top widget has link to currently focused widget in 'focuswidget'.
 
 Events emitted on change: focus, unfocus
 
-mousedown - focus widget under mouse or its parent if canfocus() == false
+mousedown - focus widget under mouse
 
-tab - focus next child in container
+tab - focus next child in container (depends on canfocus())
 shift-tab - previous child
 
 hide() -> unfocus
+
+tab/shift-tab into / out off containers?
--- a/example.py	Wed Feb 16 23:51:30 2011 +0100
+++ b/example.py	Thu Feb 17 23:35:05 2011 +0100
@@ -4,17 +4,7 @@
 import locale
 locale.setlocale(locale.LC_ALL, '')
 
-import os
-
-from tuikit.application import Application
-from tuikit.editfield import EditField
-from tuikit.window import Window
-from tuikit.button import Button
-from tuikit.scrollbar import VScrollbar
-from tuikit.textedit import TextEdit
-from tuikit.menubar import MenuBar
-from tuikit.menu import Menu
-from tuikit.layout import VerticalLayout
+from tuikit import *
 
 
 class MyApplication(Application):
@@ -25,34 +15,39 @@
         menubar = MenuBar()
         self.top.add(menubar)
 
-        filemenu = Menu(['New', '-', 'Open', 'Save', '-', 'Quit'])
+        win = Window()
+        self.top.add(win)
+        win.x = 10
+        win.y = 5
+        win.allowlayout = False
+
+
+        filemenu = Menu([
+            ('New', None),
+            None,
+            ('Open', None),
+            ('Save', None),
+            None,
+            ('Quit', self.terminate),
+            ])
         self.top.add(filemenu)
-        filemenu.allowlayout = False
-        filemenu.hidden = True
 
-        editmenu = Menu(['Copy', 'Paste'])
+        editmenu = Menu([('Copy', None), ('Paste', None)])
+        helpmenu = Menu([('About', None)])
+
         self.top.add(editmenu)
-        editmenu.allowlayout = False
-        editmenu.hidden = True
-
-        helpmenu = Menu(['About'])
         self.top.add(helpmenu)
-        helpmenu.allowlayout = False
-        helpmenu.hidden = True
 
         menubar.setitems([
             ('File', filemenu),
             ('Edit', editmenu),
-            ('Help', helpmenu)
+            ('Help', helpmenu),
             ])
 
         vert = VerticalLayout()
         self.top.layout(vert)
 
 
-        #win = Window()
-        #self.top.add(win)
-
         #button = Button('click!')
         #win.add(button)
         #button.x = 10
--- a/tuikit/__init__.py	Wed Feb 16 23:51:30 2011 +0100
+++ b/tuikit/__init__.py	Thu Feb 17 23:35:05 2011 +0100
@@ -0,0 +1,15 @@
+# -*- coding: utf-8 -*-
+
+from tuikit.application import Application
+from tuikit.button import Button
+from tuikit.common import Rect
+from tuikit.container import Container
+from tuikit.editbox import EditBox
+from tuikit.editfield import EditField
+from tuikit.layout import VerticalLayout
+from tuikit.menu import Menu
+from tuikit.menubar import MenuBar
+from tuikit.scrollbar import VScrollbar
+from tuikit.textedit import TextEdit
+from tuikit.widget import Widget
+from tuikit.window import Window
--- a/tuikit/application.py	Wed Feb 16 23:51:30 2011 +0100
+++ b/tuikit/application.py	Thu Feb 17 23:35:05 2011 +0100
@@ -14,6 +14,8 @@
     def __init__(self):
         Container.__init__(self)
 
+        self.focuswidget = None
+
         self.top = self
 
         self.timeout = []
@@ -21,6 +23,11 @@
 
         self.connect('draw', self.on_draw)
 
+    def keypress(self, keyname, char):
+        if self.focuswidget and self.focuswidget != self:
+            self.focuswidget.emit('keypress', keyname, char)
+        self.handle('keypress', keyname, char)
+
 
     def on_draw(self, screen, x, y):
         screen.erase()
@@ -87,7 +94,6 @@
         self.screen = BackendCurses(screen)
         self.top.width, self.top.height = self.screen.width, self.screen.height
         self.top.emit('resize')
-        self.top.setfocus()
 
         while True:
             self.top.draw(self.screen)
--- a/tuikit/container.py	Wed Feb 16 23:51:30 2011 +0100
+++ b/tuikit/container.py	Thu Feb 17 23:35:05 2011 +0100
@@ -8,7 +8,6 @@
         Widget.__init__(self, width, height)
 
         self.children = []
-        self.focuschild = None
         self.mousechild = None
 
         self.borders = (0, 0, 0, 0) # left, top, right, bottom
@@ -34,34 +33,6 @@
             child.settop(top)
 
 
-    ### focus
-
-
-    def canfocus(self):
-        return True
-
-
-    def setfocus(self):
-        self.focus = True
-        if self.focuschild is None and len(self.children) > 0:
-            for child in self.children:
-                if self.focuschild is None:
-                    if child.canfocus():
-                        self.focuschild = child
-                        child.setfocus()
-                else:
-                    if child.focus:
-                        child.unfocus()
-
-    def unfocus(self):
-        self.focus = False
-        for child in self.children:
-            child.unfocus()
-
-
-    ###
-
-
     def draw(self, screen, x=0, y=0):
         #if self._redraw:
             #self.fill(screen, self.y, self.x, self.height, self.width)
@@ -80,14 +51,6 @@
         #self._redraw = False
 
 
-    def keypress(self, keyname, char):
-        # always relay key event to some child
-        if self.focus:
-            self.handle('keypress', keyname, char)
-            if self.focuschild:
-                self.focuschild.keypress(keyname, char)
-
-
     def mousedown(self, ev):
         handled = False
         for child in reversed(self.children):
@@ -98,6 +61,7 @@
                 handled = True
                 break
         if not handled:
+            self.setfocus()
             self.handle('mousedown', ev)
 
 
--- a/tuikit/menu.py	Wed Feb 16 23:51:30 2011 +0100
+++ b/tuikit/menu.py	Thu Feb 17 23:35:05 2011 +0100
@@ -6,14 +6,19 @@
 class Menu(Widget):
     def __init__(self, items=[]):
         Widget.__init__(self)
-        self.width = max([len(x) for x in items]) + 4
+        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.items = items
+        self.selected = items[0]
 
         self.connect('draw', self.on_draw)
         self.connect('keypress', self.on_keypress)
+        self.connect('mousedown', self.on_mousedown)
+        self.connect('mousemove', self.on_mousemove)
+        self.connect('mouseup', self.on_mouseup)
 
 
     def on_draw(self, screen, x, y):
@@ -21,14 +26,71 @@
         screen.frame(x, y, self.width, self.height)
         i = 1
         for item in self.items:
-            if item == '-':
+            if item is None:
                 screen.puts(x, y + i, screen.LTEE + screen.HLINE * (self.width - 2) + screen.RTEE)
             else:
-                screen.puts(x + 1, y + i, ' ' + item + ' ' * (self.width - 3 - len(item)))
+                if self.selected == item:
+                    screen.pushcolor(self.highlight, screen.BOLD)
+                    screen.puts(x + 1, y + i, ' ' + item[0] + ' ' * (self.width - 3 - len(item[0])))
+                    screen.popcolor()
+                else:
+                    screen.puts(x + 1, y + i, ' ' + item[0] + ' ' * (self.width - 3 - len(item[0])))
             i += 1
         screen.popcolor()
 
 
     def on_keypress(self, keyname, char):
+        if keyname == 'up':
+            self.move_selected(-1)
+        if keyname == 'down':
+            self.move_selected(+1)
+        if keyname == 'enter':
+            self.run_selected()
         self.redraw()
 
+
+    def on_mousedown(self, ev):
+        self.select_at_pos(ev.wy - 1)
+        self.run_selected()
+
+
+    def on_mousemove(self, ev):
+        self.select_at_pos(ev.wy - 1)
+
+
+    def on_mouseup(self, ev):
+        ok = self.select_at_pos(ev.wy - 1)
+        if ok:
+            self.run_selected()
+
+
+    def select_at_pos(self, pos):
+        if pos < 0:
+            return False
+        try:
+            item = self.items[pos]
+        except IndexError:
+            return False
+        if item is None:
+            return False
+        self.selected = item
+        self.redraw()
+        return True
+
+
+    def move_selected(self, offset):
+        if self.selected:
+            i = self.items.index(self.selected)
+            i += offset
+            item = self.items[i % len(self.items)]
+            if item is None:
+                i += offset
+                item = self.items[i % len(self.items)]
+            self.selected = item
+        self.redraw()
+
+
+    def run_selected(self):
+        if self.selected and self.selected[1] is not None:
+            self.selected[1]()
+
--- a/tuikit/menubar.py	Wed Feb 16 23:51:30 2011 +0100
+++ b/tuikit/menubar.py	Thu Feb 17 23:35:05 2011 +0100
@@ -1,6 +1,7 @@
 # -*- coding: utf-8 -*-
 
 from .widget import Widget
+import logging
 
 
 class MenuBar(Widget):
@@ -16,11 +17,23 @@
         self.connect('draw', self.on_draw)
         self.connect('keypress', self.on_keypress)
         self.connect('mousedown', self.on_mousedown)
+        self.connect('mousemove', self.on_mousemove)
+        self.connect('unfocus', self.on_unfocus)
 
 
     def setitems(self, items):
         self.items = items
 
+        i = 0
+        for item in self.items:
+            if isinstance(item[1], Widget):
+                item[1].x = i
+                item[1].y = self.y + 1
+                item[1].allowlayout = False
+                item[1].hidden = True
+                item[1].connect('focus', self.on_submenu_focus)
+            i += len(item[0]) + 4
+
 
     def on_draw(self, screen, x, y):
         screen.pushcolor(self.bg)
@@ -39,23 +52,60 @@
 
 
     def on_keypress(self, keyname, char):
+        if keyname == 'left':
+            self.move_selected(-1)
+        elif keyname == 'right':
+            self.move_selected(+1)
+        else:
+            if self.selected:
+                if isinstance(self.selected[1], Widget):
+                    self.selected[1].emit('keypress', keyname, char)
+
+
+    def move_selected(self, offset):
+        if self.selected:
+            i = self.items.index(self.selected)
+            item = self.items[(i + offset) % len(self.items)]
+            self.unselect()
+            self.select(item)
         self.redraw()
 
 
     def on_mousedown(self, ev):
         i = 0
+        self.unselect()
+        for item in self.items:
+            w = len(item[0]) + 4
+            if ev.wx >= i and ev.wx < i + w:
+                self.select(item)
+            i += w
+
+
+    def on_mousemove(self, ev):
+        self.on_mousedown(ev)
+
+
+    def on_unfocus(self, newfocus):
+        #logging.getLogger('tuikit').debug('unfocus')
+        if self.selected and newfocus == self.selected[1]:
+            return
+        self.unselect()
+
+
+    def on_submenu_focus(self):
+        self.setfocus()
+
+
+    def select(self, item):
+        self.selected = item
+        if isinstance(item[1], Widget):
+            item[1].hidden = False
+            item[1].redraw()
+
+
+    def unselect(self):
         if self.selected:
             if isinstance(self.selected[1], Widget):
                 self.selected[1].hidden = True
             self.selected = None
-        for item in self.items:
-            w = len(item[0]) + 4
-            if ev.wx >= i and ev.wx < i + w:
-                self.selected = item
-                if isinstance(item[1], Widget):
-                    item[1].x = i
-                    item[1].y = self.y + 1
-                    item[1].hidden = False
-                    item[1].redraw()
-            i += w
 
--- a/tuikit/widget.py	Wed Feb 16 23:51:30 2011 +0100
+++ b/tuikit/widget.py	Thu Feb 17 23:35:05 2011 +0100
@@ -16,17 +16,19 @@
         self.allowlayout = True
         # redraw request
         self._redraw = True
-        self.focus = False
         self.hidden = False
         # event handlers
         self.event = {
             'resize' : [],
             'draw' : [],
+            'focus' : [],
+            'unfocus' : [],
             'keypress' : [],
             'mousedown' : [],
             'mouseup' : [],
             'mousemove' : [],
-            'mousewheel' : []}
+            'mousewheel' : [],
+            }
 
 
     def settop(self, top):
@@ -85,27 +87,42 @@
 
 
     def setfocus(self):
-        self.focus = True
+        if self.hasfocus():
+            return
+        if self.top.focuswidget:
+            self.top.focuswidget.unfocus(self)
+        self.top.focuswidget = self
+        self.emit('focus')
 
 
     def unfocus(self):
-        self.focus = False
+        if self.top.focuswidget != self:
+            return
+        self.top.focuswidget = None
+        self.emit('unfocus')
 
 
-    def grabfocus(self):
-        if not self.focus:
-            self.parent.grabfocus(self) # grab focus for me
+    def hasfocus(self):
+        return self.top.focuswidget == self
+
+
+    def focus(self):
+        self.handle('focus')
+
+
+    def unfocus(self, newfocus=None):
+        self.handle('unfocus', newfocus)
 
 
     ###
 
 
     def keypress(self, keyname, char):
-        if self.focus:
-            self.handle('keypress', keyname, char)
+        self.handle('keypress', keyname, char)
 
 
     def mousedown(self, ev):
+        self.setfocus()
         self.handle('mousedown', ev)
 
 
@@ -142,3 +159,4 @@
             y,x = self.parent.screenyx()
             return self.y + y, self.x + x
         return self.y, self.x
+