tuikit/menu.py
author Radek Brich <radek.brich@devl.cz>
Sat, 19 Jan 2013 13:05:21 +0100
changeset 63 2a0e04091898
parent 62 2f61931520c9
permissions -rw-r--r--
Rework MenuBar. Add MenuButton. Add mouse event cascading to floaters. LinearLayout: spacing now applies to all children, not just those with expand. Fix Window resize request inside layouts. UnicodeGraphics: prepare for styling/theming.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
0
Radek Brich <radek.brich@devl.cz>
parents:
diff changeset
     1
# -*- coding: utf-8 -*-
Radek Brich <radek.brich@devl.cz>
parents:
diff changeset
     2
18
e6c3a5ee91aa Eliminate relative imports.
Radek Brich <radek.brich@devl.cz>
parents: 10
diff changeset
     3
from tuikit.widget import Widget
43
369c8ef5070a Rename emitter module to events.
Radek Brich <radek.brich@devl.cz>
parents: 41
diff changeset
     4
from tuikit.events import GenericEvent
62
2f61931520c9 Rework layouts: Layout is now normal Container which places its children upon resize event.
Radek Brich <radek.brich@devl.cz>
parents: 45
diff changeset
     5
import logging
0
Radek Brich <radek.brich@devl.cz>
parents:
diff changeset
     6
Radek Brich <radek.brich@devl.cz>
parents:
diff changeset
     7
Radek Brich <radek.brich@devl.cz>
parents:
diff changeset
     8
class Menu(Widget):
Radek Brich <radek.brich@devl.cz>
parents:
diff changeset
     9
    def __init__(self, items=[]):
Radek Brich <radek.brich@devl.cz>
parents:
diff changeset
    10
        Widget.__init__(self)
62
2f61931520c9 Rework layouts: Layout is now normal Container which places its children upon resize event.
Radek Brich <radek.brich@devl.cz>
parents: 45
diff changeset
    11
        w = max([len(x[0]) for x in items if x is not None]) + 4
2f61931520c9 Rework layouts: Layout is now normal Container which places its children upon resize event.
Radek Brich <radek.brich@devl.cz>
parents: 45
diff changeset
    12
        h = len(items) + 2
2f61931520c9 Rework layouts: Layout is now normal Container which places its children upon resize event.
Radek Brich <radek.brich@devl.cz>
parents: 45
diff changeset
    13
        self._default_size.update(w, h)
0
Radek Brich <radek.brich@devl.cz>
parents:
diff changeset
    14
34
e3beacd5e536 Update event propagation, keypress event, focusing.
Radek Brich <radek.brich@devl.cz>
parents: 32
diff changeset
    15
        self.allow_focus = True
e3beacd5e536 Update event propagation, keypress event, focusing.
Radek Brich <radek.brich@devl.cz>
parents: 32
diff changeset
    16
7
d4a291b31cbb New color management - named colors.
Radek Brich <radek.brich@devl.cz>
parents: 2
diff changeset
    17
        self.bg = 'menu'
d4a291b31cbb New color management - named colors.
Radek Brich <radek.brich@devl.cz>
parents: 2
diff changeset
    18
        self.highlight = 'menu-active'
0
Radek Brich <radek.brich@devl.cz>
parents:
diff changeset
    19
        self.items = items
1
69318aba22bf Menu development. New focus. Easier imports from tuikit package.
Radek Brich <radek.brich@devl.cz>
parents: 0
diff changeset
    20
        self.selected = items[0]
0
Radek Brich <radek.brich@devl.cz>
parents:
diff changeset
    21
41
37b7dfc3eae6 Update Emitter: All event handlers now have exactly one argument: object inherited from Event class, which carries any data.
Radek Brich <radek.brich@devl.cz>
parents: 40
diff changeset
    22
        self.add_events('activate', GenericEvent)
0
Radek Brich <radek.brich@devl.cz>
parents:
diff changeset
    23
45
43b2279b06e1 Clean up Emitter class, simplify event handling. Fix Container.focusnext() method. Add events test (handler auto-registration, order).
Radek Brich <radek.brich@devl.cz>
parents: 43
diff changeset
    24
    def on_draw(self, ev):
63
2a0e04091898 Rework MenuBar. Add MenuButton. Add mouse event cascading to floaters.
Radek Brich <radek.brich@devl.cz>
parents: 62
diff changeset
    25
        #logging.getLogger('tuikit').info('menu draw %s %s %s', ev, ev.x, ev.y)
41
37b7dfc3eae6 Update Emitter: All event handlers now have exactly one argument: object inherited from Event class, which carries any data.
Radek Brich <radek.brich@devl.cz>
parents: 40
diff changeset
    26
        ev.driver.pushcolor(self.bg)
37b7dfc3eae6 Update Emitter: All event handlers now have exactly one argument: object inherited from Event class, which carries any data.
Radek Brich <radek.brich@devl.cz>
parents: 40
diff changeset
    27
        ev.driver.frame(ev.x, ev.y, self.width, self.height)
0
Radek Brich <radek.brich@devl.cz>
parents:
diff changeset
    28
        i = 1
Radek Brich <radek.brich@devl.cz>
parents:
diff changeset
    29
        for item in self.items:
1
69318aba22bf Menu development. New focus. Easier imports from tuikit package.
Radek Brich <radek.brich@devl.cz>
parents: 0
diff changeset
    30
            if item is None:
41
37b7dfc3eae6 Update Emitter: All event handlers now have exactly one argument: object inherited from Event class, which carries any data.
Radek Brich <radek.brich@devl.cz>
parents: 40
diff changeset
    31
                ev.driver.puts(ev.x, ev.y + i, ev.driver.unigraph.LTEE + \
37b7dfc3eae6 Update Emitter: All event handlers now have exactly one argument: object inherited from Event class, which carries any data.
Radek Brich <radek.brich@devl.cz>
parents: 40
diff changeset
    32
                    ev.driver.unigraph.HLINE * (self.width - 2) + ev.driver.unigraph.RTEE)
0
Radek Brich <radek.brich@devl.cz>
parents:
diff changeset
    33
            else:
1
69318aba22bf Menu development. New focus. Easier imports from tuikit package.
Radek Brich <radek.brich@devl.cz>
parents: 0
diff changeset
    34
                if self.selected == item:
41
37b7dfc3eae6 Update Emitter: All event handlers now have exactly one argument: object inherited from Event class, which carries any data.
Radek Brich <radek.brich@devl.cz>
parents: 40
diff changeset
    35
                    ev.driver.pushcolor(self.highlight)
37b7dfc3eae6 Update Emitter: All event handlers now have exactly one argument: object inherited from Event class, which carries any data.
Radek Brich <radek.brich@devl.cz>
parents: 40
diff changeset
    36
                    ev.driver.puts(ev.x + 1, ev.y + i,
37b7dfc3eae6 Update Emitter: All event handlers now have exactly one argument: object inherited from Event class, which carries any data.
Radek Brich <radek.brich@devl.cz>
parents: 40
diff changeset
    37
                        ' ' + item[0] + ' ' * (self.width - 3 - len(item[0])))
37b7dfc3eae6 Update Emitter: All event handlers now have exactly one argument: object inherited from Event class, which carries any data.
Radek Brich <radek.brich@devl.cz>
parents: 40
diff changeset
    38
                    ev.driver.popcolor()
1
69318aba22bf Menu development. New focus. Easier imports from tuikit package.
Radek Brich <radek.brich@devl.cz>
parents: 0
diff changeset
    39
                else:
41
37b7dfc3eae6 Update Emitter: All event handlers now have exactly one argument: object inherited from Event class, which carries any data.
Radek Brich <radek.brich@devl.cz>
parents: 40
diff changeset
    40
                    ev.driver.puts(ev.x + 1, ev.y + i,
37b7dfc3eae6 Update Emitter: All event handlers now have exactly one argument: object inherited from Event class, which carries any data.
Radek Brich <radek.brich@devl.cz>
parents: 40
diff changeset
    41
                        ' ' + item[0] + ' ' * (self.width - 3 - len(item[0])))
0
Radek Brich <radek.brich@devl.cz>
parents:
diff changeset
    42
            i += 1
41
37b7dfc3eae6 Update Emitter: All event handlers now have exactly one argument: object inherited from Event class, which carries any data.
Radek Brich <radek.brich@devl.cz>
parents: 40
diff changeset
    43
        ev.driver.popcolor()
0
Radek Brich <radek.brich@devl.cz>
parents:
diff changeset
    44
45
43b2279b06e1 Clean up Emitter class, simplify event handling. Fix Container.focusnext() method. Add events test (handler auto-registration, order).
Radek Brich <radek.brich@devl.cz>
parents: 43
diff changeset
    45
    def on_keypress(self, ev):
41
37b7dfc3eae6 Update Emitter: All event handlers now have exactly one argument: object inherited from Event class, which carries any data.
Radek Brich <radek.brich@devl.cz>
parents: 40
diff changeset
    46
        if ev.keyname == 'up':
1
69318aba22bf Menu development. New focus. Easier imports from tuikit package.
Radek Brich <radek.brich@devl.cz>
parents: 0
diff changeset
    47
            self.move_selected(-1)
63
2a0e04091898 Rework MenuBar. Add MenuButton. Add mouse event cascading to floaters.
Radek Brich <radek.brich@devl.cz>
parents: 62
diff changeset
    48
            return True
2a0e04091898 Rework MenuBar. Add MenuButton. Add mouse event cascading to floaters.
Radek Brich <radek.brich@devl.cz>
parents: 62
diff changeset
    49
        if ev.keyname in ('down', 'tab'):
1
69318aba22bf Menu development. New focus. Easier imports from tuikit package.
Radek Brich <radek.brich@devl.cz>
parents: 0
diff changeset
    50
            self.move_selected(+1)
63
2a0e04091898 Rework MenuBar. Add MenuButton. Add mouse event cascading to floaters.
Radek Brich <radek.brich@devl.cz>
parents: 62
diff changeset
    51
            return True
41
37b7dfc3eae6 Update Emitter: All event handlers now have exactly one argument: object inherited from Event class, which carries any data.
Radek Brich <radek.brich@devl.cz>
parents: 40
diff changeset
    52
        if ev.keyname == 'enter':
1
69318aba22bf Menu development. New focus. Easier imports from tuikit package.
Radek Brich <radek.brich@devl.cz>
parents: 0
diff changeset
    53
            self.run_selected()
63
2a0e04091898 Rework MenuBar. Add MenuButton. Add mouse event cascading to floaters.
Radek Brich <radek.brich@devl.cz>
parents: 62
diff changeset
    54
            return True
0
Radek Brich <radek.brich@devl.cz>
parents:
diff changeset
    55
        self.redraw()
Radek Brich <radek.brich@devl.cz>
parents:
diff changeset
    56
45
43b2279b06e1 Clean up Emitter class, simplify event handling. Fix Container.focusnext() method. Add events test (handler auto-registration, order).
Radek Brich <radek.brich@devl.cz>
parents: 43
diff changeset
    57
    def on_mousedown(self, ev):
1
69318aba22bf Menu development. New focus. Easier imports from tuikit package.
Radek Brich <radek.brich@devl.cz>
parents: 0
diff changeset
    58
        self.select_at_pos(ev.wy - 1)
69318aba22bf Menu development. New focus. Easier imports from tuikit package.
Radek Brich <radek.brich@devl.cz>
parents: 0
diff changeset
    59
45
43b2279b06e1 Clean up Emitter class, simplify event handling. Fix Container.focusnext() method. Add events test (handler auto-registration, order).
Radek Brich <radek.brich@devl.cz>
parents: 43
diff changeset
    60
    def on_mousemove(self, ev):
1
69318aba22bf Menu development. New focus. Easier imports from tuikit package.
Radek Brich <radek.brich@devl.cz>
parents: 0
diff changeset
    61
        self.select_at_pos(ev.wy - 1)
69318aba22bf Menu development. New focus. Easier imports from tuikit package.
Radek Brich <radek.brich@devl.cz>
parents: 0
diff changeset
    62
45
43b2279b06e1 Clean up Emitter class, simplify event handling. Fix Container.focusnext() method. Add events test (handler auto-registration, order).
Radek Brich <radek.brich@devl.cz>
parents: 43
diff changeset
    63
    def on_mouseup(self, ev):
1
69318aba22bf Menu development. New focus. Easier imports from tuikit package.
Radek Brich <radek.brich@devl.cz>
parents: 0
diff changeset
    64
        ok = self.select_at_pos(ev.wy - 1)
69318aba22bf Menu development. New focus. Easier imports from tuikit package.
Radek Brich <radek.brich@devl.cz>
parents: 0
diff changeset
    65
        if ok:
69318aba22bf Menu development. New focus. Easier imports from tuikit package.
Radek Brich <radek.brich@devl.cz>
parents: 0
diff changeset
    66
            self.run_selected()
69318aba22bf Menu development. New focus. Easier imports from tuikit package.
Radek Brich <radek.brich@devl.cz>
parents: 0
diff changeset
    67
69318aba22bf Menu development. New focus. Easier imports from tuikit package.
Radek Brich <radek.brich@devl.cz>
parents: 0
diff changeset
    68
    def select_at_pos(self, pos):
69318aba22bf Menu development. New focus. Easier imports from tuikit package.
Radek Brich <radek.brich@devl.cz>
parents: 0
diff changeset
    69
        if pos < 0:
69318aba22bf Menu development. New focus. Easier imports from tuikit package.
Radek Brich <radek.brich@devl.cz>
parents: 0
diff changeset
    70
            return False
69318aba22bf Menu development. New focus. Easier imports from tuikit package.
Radek Brich <radek.brich@devl.cz>
parents: 0
diff changeset
    71
        try:
69318aba22bf Menu development. New focus. Easier imports from tuikit package.
Radek Brich <radek.brich@devl.cz>
parents: 0
diff changeset
    72
            item = self.items[pos]
69318aba22bf Menu development. New focus. Easier imports from tuikit package.
Radek Brich <radek.brich@devl.cz>
parents: 0
diff changeset
    73
        except IndexError:
69318aba22bf Menu development. New focus. Easier imports from tuikit package.
Radek Brich <radek.brich@devl.cz>
parents: 0
diff changeset
    74
            return False
69318aba22bf Menu development. New focus. Easier imports from tuikit package.
Radek Brich <radek.brich@devl.cz>
parents: 0
diff changeset
    75
        if item is None:
69318aba22bf Menu development. New focus. Easier imports from tuikit package.
Radek Brich <radek.brich@devl.cz>
parents: 0
diff changeset
    76
            return False
69318aba22bf Menu development. New focus. Easier imports from tuikit package.
Radek Brich <radek.brich@devl.cz>
parents: 0
diff changeset
    77
        self.selected = item
69318aba22bf Menu development. New focus. Easier imports from tuikit package.
Radek Brich <radek.brich@devl.cz>
parents: 0
diff changeset
    78
        self.redraw()
69318aba22bf Menu development. New focus. Easier imports from tuikit package.
Radek Brich <radek.brich@devl.cz>
parents: 0
diff changeset
    79
        return True
69318aba22bf Menu development. New focus. Easier imports from tuikit package.
Radek Brich <radek.brich@devl.cz>
parents: 0
diff changeset
    80
69318aba22bf Menu development. New focus. Easier imports from tuikit package.
Radek Brich <radek.brich@devl.cz>
parents: 0
diff changeset
    81
    def move_selected(self, offset):
69318aba22bf Menu development. New focus. Easier imports from tuikit package.
Radek Brich <radek.brich@devl.cz>
parents: 0
diff changeset
    82
        if self.selected:
69318aba22bf Menu development. New focus. Easier imports from tuikit package.
Radek Brich <radek.brich@devl.cz>
parents: 0
diff changeset
    83
            i = self.items.index(self.selected)
69318aba22bf Menu development. New focus. Easier imports from tuikit package.
Radek Brich <radek.brich@devl.cz>
parents: 0
diff changeset
    84
            i += offset
69318aba22bf Menu development. New focus. Easier imports from tuikit package.
Radek Brich <radek.brich@devl.cz>
parents: 0
diff changeset
    85
            item = self.items[i % len(self.items)]
69318aba22bf Menu development. New focus. Easier imports from tuikit package.
Radek Brich <radek.brich@devl.cz>
parents: 0
diff changeset
    86
            if item is None:
69318aba22bf Menu development. New focus. Easier imports from tuikit package.
Radek Brich <radek.brich@devl.cz>
parents: 0
diff changeset
    87
                i += offset
69318aba22bf Menu development. New focus. Easier imports from tuikit package.
Radek Brich <radek.brich@devl.cz>
parents: 0
diff changeset
    88
                item = self.items[i % len(self.items)]
69318aba22bf Menu development. New focus. Easier imports from tuikit package.
Radek Brich <radek.brich@devl.cz>
parents: 0
diff changeset
    89
            self.selected = item
69318aba22bf Menu development. New focus. Easier imports from tuikit package.
Radek Brich <radek.brich@devl.cz>
parents: 0
diff changeset
    90
        self.redraw()
69318aba22bf Menu development. New focus. Easier imports from tuikit package.
Radek Brich <radek.brich@devl.cz>
parents: 0
diff changeset
    91
69318aba22bf Menu development. New focus. Easier imports from tuikit package.
Radek Brich <radek.brich@devl.cz>
parents: 0
diff changeset
    92
    def run_selected(self):
69318aba22bf Menu development. New focus. Easier imports from tuikit package.
Radek Brich <radek.brich@devl.cz>
parents: 0
diff changeset
    93
        if self.selected and self.selected[1] is not None:
10
ec1d47e6fe09 Use isinstance instead of type.
Radek Brich <radek.brich@devl.cz>
parents: 9
diff changeset
    94
            if isinstance(self.selected[1], str):
34
e3beacd5e536 Update event propagation, keypress event, focusing.
Radek Brich <radek.brich@devl.cz>
parents: 32
diff changeset
    95
                self.emit('activate', self.selected[1])
9
7175ed629a76 Added ComboBox, HorizontalLayout, TreeNode, TreeModel, TreeView. Widget is now descendant of EventSource. Improved color management (color prefixes).
Radek Brich <radek.brich@devl.cz>
parents: 7
diff changeset
    96
            elif isinstance(self.selected[1], Widget):
2
684cdc352562 Menu, Window and other improvements.
Radek Brich <radek.brich@devl.cz>
parents: 1
diff changeset
    97
                self.selected[1].show()
38
c6e170452c7f Documentation, fix names of focus methods.
Radek Brich <radek.brich@devl.cz>
parents: 34
diff changeset
    98
                self.selected[1].set_focus()
2
684cdc352562 Menu, Window and other improvements.
Radek Brich <radek.brich@devl.cz>
parents: 1
diff changeset
    99
            else:
684cdc352562 Menu, Window and other improvements.
Radek Brich <radek.brich@devl.cz>
parents: 1
diff changeset
   100
                self.selected[1]()
1
69318aba22bf Menu development. New focus. Easier imports from tuikit package.
Radek Brich <radek.brich@devl.cz>
parents: 0
diff changeset
   101