Example #1
0
 def __init__(self, widgets, position='top'):
     self.widgets = widgets
     self.position = position
     self.bounds = None
     self.window = None
     self.redraw = Event('bar.redraw')
     self.redraw.listen(self.expose)
Example #2
0
 def __init__(self):
     self.topbars = []
     self.bottombars = []
     self.leftslices = []
     self.rightslices = []
     self.updated = Event('screen.updated')
     self.bars_visible = True
     self.group_hooks = []
Example #3
0
 def __init__(self, max_lines=10):
     self.window = None
     self.max_lines = max_lines
     self.redraw = Event('menu.redraw')
     self.redraw.listen(self._redraw)
     self.submit_ev = Event('menu.submit')
     self.submit_ev.listen(self._submit)
     self.complete = Event('menu.complete')
     self.complete.listen(self._complete)
     self.close = Event('menu.close')
     self.close.listen(self._close)
Example #4
0
 def __init__(self, screen, width, groups, states):
     self.screen = screen
     self.width = width
     self._cairo = None
     self._img = None
     self.redraw = Event('leftbar.redraw')
     self.redraw.listen(self._redraw)
     self.repaint = Event('leftbar.repaint')
     self.repaint.listen(self._paint)
     self.screen.add_group_hook(self._group_hook)
     self.visible = False
     self.groups = groups
     self.states = states
     self._drawn_group = None
Example #5
0
 def __init__(self, screen, width, groups, states):
     self.screen = screen
     self.width = width
     self._cairo = None
     self._img = None
     self.redraw = Event('leftbar.redraw')
     self.redraw.listen(self._redraw)
     self.repaint = Event('leftbar.repaint')
     self.repaint.listen(self._paint)
     self.screen.add_group_hook(self._group_hook)
     self.visible = False
     self.groups = groups
     self.states = states
     self._drawn_group = None
Example #6
0
 def __init__(self, widgets, position='top'):
     self.widgets = widgets
     self.position = position
     self.bounds = None
     self.window = None
     self.redraw = Event('bar.redraw')
     self.redraw.listen(self.expose)
Example #7
0
 def __init__(self):
     self.topbars = []
     self.bottombars = []
     self.leftslices = []
     self.rightslices = []
     self.updated = Event('screen.updated')
     self.bars_visible = True
     self.group_hooks = []
Example #8
0
 def __init__(self, max_lines=10):
     self.window = None
     self.max_lines = max_lines
     self.redraw = Event('menu.redraw')
     self.redraw.listen(self._redraw)
     self.submit_ev = Event('menu.submit')
     self.submit_ev.listen(self._submit)
     self.complete = Event('menu.complete')
     self.complete.listen(self._complete)
     self.close = Event('menu.close')
     self.close.listen(self._close)
Example #9
0
class Layout(metaclass=LayoutMeta):

    def __init__(self):
        self.visible = False
        self.relayout = Event('layout.relayout')
        self.relayout.listen(self.check_relayout)

    def check_relayout(self):
        if self.visible:
            self.layout()
            self.group.check_focus()

    @classmethod
    def get_defined_classes(cls, base):
        res = OrderedDict()
        for k in cls.fields:
            v = getattr(cls, k)
            if isinstance(v, type) and issubclass(v, base):
                res[k] = v
        return res

    def dirty(self):
        self.relayout.emit()

    def all_visible_windows(self):
        for i in getattr(self, 'visible_windows', ()):
            yield i
        sub = getattr(self, 'sublayouts', None)
        if sub:
            for s in sub():
                for i in s.visible_windows:
                    yield i

    def hide(self):
        self.visible = False
        for i in self.all_visible_windows():
            i.hide()

    def show(self):
        self.visible = True
        for i in self.all_visible_windows():
            i.show()
Example #10
0
class Layout(metaclass=LayoutMeta):
    def __init__(self):
        self.visible = False
        self.relayout = Event('layout.relayout')
        self.relayout.listen(self.check_relayout)

    def check_relayout(self):
        if self.visible:
            self.layout()
            self.group.check_focus()

    @classmethod
    def get_defined_classes(cls, base):
        res = OrderedDict()
        for k in cls.fields:
            v = getattr(cls, k)
            if isinstance(v, type) and issubclass(v, base):
                res[k] = v
        return res

    def dirty(self):
        self.relayout.emit()

    def all_visible_windows(self):
        for i in getattr(self, 'visible_windows', ()):
            yield i
        sub = getattr(self, 'sublayouts', None)
        if sub:
            for s in sub():
                for i in s.visible_windows:
                    yield i

    def hide(self):
        self.visible = False
        for i in self.all_visible_windows():
            i.hide()

    def show(self):
        self.visible = True
        for i in self.all_visible_windows():
            i.show()
Example #11
0
class Select(GadgetBase):

    commander = dependency(CommandDispatcher, 'commander')
    dispatcher = dependency(EventDispatcher, 'event-dispatcher')

    def __init__(self, max_lines=10):
        self.window = None
        self.max_lines = max_lines
        self.redraw = Event('menu.redraw')
        self.redraw.listen(self._redraw)
        self.submit_ev = Event('menu.submit')
        self.submit_ev.listen(self._submit)
        self.complete = Event('menu.complete')
        self.complete.listen(self._complete)
        self.close = Event('menu.close')
        self.close.listen(self._close)

    def __zorro_di_done__(self):
        self.line_height = self.theme.menu.line_height

    def cmd_show(self):
        if self.window:
            self.cmd_hide()
        self._current_items = self.items()
        show_lines = min(len(self._current_items) + 1, self.max_lines)
        h = self.theme.menu.line_height
        self.height = h * self.max_lines
        bounds = self.commander['screen'].bounds._replace(height=h)
        self._img = self.xcore.pixbuf(bounds.width, h)
        wid = self.xcore.create_toplevel(
            bounds,
            klass=self.xcore.WindowClass.InputOutput,
            params={
                self.xcore.CW.BackPixel:
                self.theme.menu.background,
                self.xcore.CW.OverrideRedirect:
                True,
                self.xcore.CW.EventMask:
                self.xcore.EventMask.FocusChange
                | self.xcore.EventMask.EnterWindow
                | self.xcore.EventMask.LeaveWindow
                | self.xcore.EventMask.KeymapState
                | self.xcore.EventMask.KeyPress,
            })
        self.window = di(self).inject(
            DisplayWindow(wid, self.draw, focus_out=self._close))
        self.dispatcher.all_windows[wid] = self.window
        self.dispatcher.frames[wid] = self.window  # dirty hack
        self.window.show()
        self.window.focus()
        self.text_field = di(self).inject(
            TextField(self.theme.menu,
                      events={
                          'draw': self.redraw,
                          'submit': self.submit_ev,
                          'complete': self.complete,
                          'close': self.close,
                      }))
        self.dispatcher.active_field = self.text_field
        self._redraw()

    def cmd_hide(self):
        self._close()

    def draw(self, rect=None):
        self._img.draw(self.window)

    def match_lines(self, value):
        matched = set()
        for line, res in self._current_items:
            if line in matched: continue
            if line.startswith(value):
                matched.add(line)
                yield (line, [(1, line[:len(value)]),
                              (0, line[len(value):])], res)
        ncval = value.lower()
        for line, res in self._current_items:
            if line in matched: continue
            if line.lower().startswith(value):
                matched.add(line)
                yield (line, [(1, line[:len(value)]),
                              (0, line[len(value):])], res)
        for line, res in self._current_items:
            if line in matched: continue
            if ncval in line.lower():
                matched.add(line)
                opcodes = []
                for pt in re.compile('((?i)' + re.escape(value) +
                                     ')').split(line):
                    opcodes.append((pt.lower() == ncval, pt))
                yield (line, opcodes, res)

    def _redraw(self):
        if not self.window and not self.text_field:
            return
        lines = list(
            islice(self.match_lines(self.text_field.value), self.max_lines))
        newh = (len(lines) + 1) * self.line_height
        if newh != self.height:
            # don't need to render, need resize
            self.height = newh
            bounds = self.commander['screen'].bounds._replace(height=newh)
            self._img = self.xcore.pixbuf(bounds.width, newh)
            self.window.set_bounds(bounds)
        ctx = self._img.context()
        ctx.set_source(self.theme.menu.background_pat)
        ctx.rectangle(0, 0, self._img.width, self._img.height)
        ctx.fill()
        sx, sy, _, _, ax, ay = ctx.text_extents(self.text_field.value)
        self.text_field.draw(ctx)
        th = self.theme.menu
        pad = th.padding
        y = self.line_height
        for text, opcodes, value in lines:
            ctx.move_to(pad.left, y + self.line_height - pad.bottom)
            for op, tx in opcodes:
                ctx.set_source(th.highlight_pat if op else th.text_pat)
                ctx.show_text(tx)
            y += self.line_height
        self.draw()

    def _submit(self):
        input = self.text_field.value
        matched = None
        value = None
        for matched, opcodes, value in self.match_lines(input):
            break
        self.submit(input, matched, value)
        self._close()

    def _close(self):
        if self.window:
            self.window.destroy()
            self.window = None
        if self.dispatcher.active_field == self.text_field:
            self.dispatcher.active_field = None
        self.text_field = None

    def _complete(self):
        text, _, val = next(iter(self.match_lines(self.text_field.value)))
        self.text_field.value = text
        self.text_field.sel_start = len(text)
        self.text_field.sel_width = 0
        self.redraw.emit()
Example #12
0
 def __init__(self):
     self.visible = False
     self.relayout = Event('layout.relayout')
     self.relayout.listen(self.check_relayout)
Example #13
0
 def __init__(self):
     self.visible = False
     self.relayout = Event('layout.relayout')
     self.relayout.listen(self.check_relayout)
Example #14
0
class Screen(object):
    def __init__(self):
        self.topbars = []
        self.bottombars = []
        self.leftslices = []
        self.rightslices = []
        self.updated = Event('screen.updated')
        self.bars_visible = True
        self.group_hooks = []

    def add_group_hook(self, fun):
        self.group_hooks.append(fun)

    def remove_group_hook(self, fun):
        self.group_hooks.remove(fun)

    def set_group(self, group):
        self.group = group
        for h in self.group_hooks:
            h()

    def cmd_focus(self):
        self.group.focus()

    def set_bounds(self, rect):
        self.bounds = rect
        x, y, w, h = rect
        if self.bars_visible:
            for bar in self.topbars:
                bar.set_bounds(Rectangle(x, y, w, bar.height))
                y += bar.height
                h -= bar.height
            for bar in self.bottombars:
                h -= bar.height
                bar.set_bounds(Rectangle(x, y + h, w, bar.height))
            for gadget in self.leftslices:
                gadget.set_bounds(Rectangle(x, y, gadget.width, h))
                x += gadget.width
                w -= gadget.width
            for gadget in self.rightslices:
                w -= gadget.width
                gadget.set_bounds(Rectangle(x + w, y, gadget.width, h))
        self.inner_bounds = Rectangle(x, y, w, h)
        self.updated.emit()

    def all_bars(self):
        for bar in self.topbars:
            yield bar
        for bar in self.bottombars:
            yield bar

    def add_top_bar(self, bar):
        if bar not in self.topbars:
            self.topbars.append(bar)
        self.set_bounds(self.bounds)

    def add_bottom_bar(self, bar):
        if bar not in self.bottombars:
            self.bottombars.append(bar)
        self.set_bounds(self.bounds)

    def slice_left(self, obj):
        if obj not in self.leftslices:
            self.leftslices.append(obj)
        self.set_bounds(self.bounds)

    def unslice_left(self, obj):
        if obj in self.leftslices:
            self.leftslices.remove(obj)
        self.set_bounds(self.bounds)

    def slice_right(self, obj):
        if obj not in self.rightslices:
            self.rightslices.append(obj)
        self.set_bounds(self.bounds)

    def unslice_right(self, obj):
        if obj in self.rightslices:
            self.leftslices.remove(obj)
        self.set_bounds(self.bounds)

    def cmd_toggle_bars(self):
        if self.bars_visible:
            self.cmd_hide_bars()
        else:
            self.cmd_show_bars()

    def cmd_hide_bars(self):
        for bar in self.all_bars():
            bar.window.hide()
        self.bars_visible = False
        self.inner_bounds = self.bounds
        self.updated.emit()

    def cmd_show_bars(self):
        for bar in self.all_bars():
            bar.window.show()
        self.bars_visible = True
        self.set_bounds(self.bounds)
Example #15
0
class Select(GadgetBase):

    commander = dependency(CommandDispatcher, 'commander')
    dispatcher = dependency(EventDispatcher, 'event-dispatcher')

    def __init__(self, max_lines=10):
        self.window = None
        self.max_lines = max_lines
        self.redraw = Event('menu.redraw')
        self.redraw.listen(self._redraw)
        self.submit_ev = Event('menu.submit')
        self.submit_ev.listen(self._submit)
        self.complete = Event('menu.complete')
        self.complete.listen(self._complete)
        self.close = Event('menu.close')
        self.close.listen(self._close)

    def __zorro_di_done__(self):
        self.line_height = self.theme.menu.line_height

    def cmd_show(self):
        if self.window:
            self.cmd_hide()
        self._current_items = self.items()
        show_lines = min(len(self._current_items) + 1, self.max_lines)
        h = self.theme.menu.line_height
        self.height = h*self.max_lines
        bounds = self.commander['screen'].bounds._replace(height=h)
        self._img = self.xcore.pixbuf(bounds.width, h)
        wid = self.xcore.create_toplevel(bounds,
            klass=self.xcore.WindowClass.InputOutput,
            params={
                self.xcore.CW.BackPixel: self.theme.menu.background,
                self.xcore.CW.OverrideRedirect: True,
                self.xcore.CW.EventMask:
                    self.xcore.EventMask.FocusChange
                    | self.xcore.EventMask.EnterWindow
                    | self.xcore.EventMask.LeaveWindow
                    | self.xcore.EventMask.KeymapState
                    | self.xcore.EventMask.KeyPress,
            })
        self.window = di(self).inject(DisplayWindow(wid, self.draw,
            focus_out=self._close))
        self.dispatcher.all_windows[wid] = self.window
        self.dispatcher.frames[wid] = self.window  # dirty hack
        self.window.show()
        self.window.focus()
        self.text_field = di(self).inject(TextField(self.theme.menu, events={
            'draw': self.redraw,
            'submit': self.submit_ev,
            'complete': self.complete,
            'close': self.close,
            }))
        self.dispatcher.active_field = self.text_field
        self._redraw()

    def cmd_hide(self):
        self._close()

    def draw(self, rect=None):
        self._img.draw(self.window)

    def match_lines(self, value):
        matched = set()
        for line, res in self._current_items:
            if line in matched: continue
            if line.startswith(value):
                matched.add(line)
                yield (line,
                       [(1, line[:len(value)]), (0, line[len(value):])],
                       res)
        ncval = value.lower()
        for line, res in self._current_items:
            if line in matched: continue
            if line.lower().startswith(value):
                matched.add(line)
                yield (line,
                       [(1, line[:len(value)]), (0, line[len(value):])],
                       res)
        for line, res in self._current_items:
            if line in matched: continue
            if ncval in line.lower():
                matched.add(line)
                opcodes = []
                for pt in re.compile('((?i)'+re.escape(value)+')').split(line):
                    opcodes.append((pt.lower() == ncval, pt))
                yield (line, opcodes, res)

    def _redraw(self):
        if not self.window and not self.text_field:
            return
        lines = list(islice(self.match_lines(self.text_field.value),
                            self.max_lines))
        newh = (len(lines)+1)*self.line_height
        if newh != self.height:
            # don't need to render, need resize
            self.height = newh
            bounds = self.commander['screen'].bounds._replace(height=newh)
            self._img = self.xcore.pixbuf(bounds.width, newh)
            self.window.set_bounds(bounds)
        ctx = self._img.context()
        ctx.set_source(self.theme.menu.background_pat)
        ctx.rectangle(0, 0, self._img.width, self._img.height)
        ctx.fill()
        sx, sy, _, _, ax, ay = ctx.text_extents(self.text_field.value)
        self.text_field.draw(ctx)
        th = self.theme.menu
        pad = th.padding
        y = self.line_height
        for text, opcodes, value in lines:
            ctx.move_to(pad.left, y + self.line_height - pad.bottom)
            for op, tx in opcodes:
                ctx.set_source(th.highlight_pat if op else th.text_pat)
                ctx.show_text(tx)
            y += self.line_height
        self.draw()

    def _submit(self):
        input = self.text_field.value
        matched = None
        value = None
        for matched, opcodes, value in self.match_lines(input):
            break
        self.submit(input, matched, value)
        self._close()

    def _close(self):
        if self.window:
            self.window.destroy()
            self.window = None
        if self.dispatcher.active_field == self.text_field:
            self.dispatcher.active_field = None
        self.text_field = None

    def _complete(self):
        text, _, val = next(iter(self.match_lines(self.text_field.value)))
        self.text_field.value = text
        self.text_field.sel_start = len(text)
        self.text_field.sel_width = 0
        self.redraw.emit()
Example #16
0
class Bar(object):

    xcore = dependency(Core, 'xcore')
    dispatcher = dependency(EventDispatcher, 'event-dispatcher')
    theme = dependency(Theme, 'theme')

    def __init__(self, widgets, position='top'):
        self.widgets = widgets
        self.position = position
        self.bounds = None
        self.window = None
        self.redraw = Event('bar.redraw')
        self.redraw.listen(self.expose)

    def __zorro_di_done__(self):
        bar = self.theme.bar
        self.height = bar.height
        self.background = bar.background_pat
        inj = di(self).clone()
        inj['bar'] = self
        for w in self.widgets:
            w.height = self.height
            inj.inject(w)

    def set_bounds(self, rect):
        self.bounds = rect
        self.width = rect.width
        stride = self.xcore.bitmap_stride
        self.img = self.xcore.pixbuf(self.width, self.height)
        self.cairo = self.img.context()
        if self.window and not self.window.set_bounds(rect):
            self.redraw.emit()

    def create_window(self):
        EM = self.xcore.EventMask
        CW = self.xcore.CW
        self.window = DisplayWindow(
            self.xcore.create_toplevel(
                self.bounds,
                klass=self.xcore.WindowClass.InputOutput,
                params={
                    CW.EventMask: EM.Exposure | EM.SubstructureNotify,
                    CW.OverrideRedirect: True,
                }), self.expose)
        self.window.want.size = self.bounds
        di(self).inject(self.window)
        self.dispatcher.register_window(self.window)
        self.window.show()

    def expose(self, rect=None):
        # TODO(tailhook) set clip region to specified rectangle
        self.cairo.set_source(self.background)
        self.cairo.rectangle(0, 0, self.width, self.height)
        self.cairo.fill()
        l = 0
        r = self.width
        for i in self.widgets:
            self.cairo.save()
            self.cairo.rectangle(l, 0, r - l, self.height)
            self.cairo.clip()
            l, r = i.draw(self.cairo, l, r)
            self.cairo.restore()
        self.img.draw(self.window)
Example #17
0
class Screen(object):

    def __init__(self):
        self.topbars = []
        self.bottombars = []
        self.leftslices = []
        self.rightslices = []
        self.updated = Event('screen.updated')
        self.bars_visible = True
        self.group_hooks = []

    def add_group_hook(self, fun):
        self.group_hooks.append(fun)

    def remove_group_hook(self, fun):
        self.group_hooks.remove(fun)

    def set_group(self, group):
        self.group = group
        for h in self.group_hooks:
            h()

    def cmd_focus(self):
        self.group.focus()

    def set_bounds(self, rect):
        self.bounds = rect
        x, y, w, h = rect
        if self.bars_visible:
            for bar in self.topbars:
                bar.set_bounds(Rectangle(x, y, w, bar.height))
                y += bar.height
                h -= bar.height
            for bar in self.bottombars:
                h -= bar.height
                bar.set_bounds(Rectangle(x, y+h, w, bar.height))
            for gadget in self.leftslices:
                gadget.set_bounds(Rectangle(x, y, gadget.width, h))
                x += gadget.width
                w -= gadget.width
            for gadget in self.rightslices:
                w -= gadget.width
                gadget.set_bounds(Rectangle(x+w, y, gadget.width, h))
        self.inner_bounds = Rectangle(x, y, w, h)
        self.updated.emit()

    def all_bars(self):
        for bar in self.topbars:
            yield bar
        for bar in self.bottombars:
            yield bar

    def add_top_bar(self, bar):
        if bar not in self.topbars:
            self.topbars.append(bar)
        self.set_bounds(self.bounds)

    def add_bottom_bar(self, bar):
        if bar not in self.bottombars:
            self.bottombars.append(bar)
        self.set_bounds(self.bounds)

    def slice_left(self, obj):
        if obj not in self.leftslices:
            self.leftslices.append(obj)
        self.set_bounds(self.bounds)

    def unslice_left(self, obj):
        if obj in self.leftslices:
            self.leftslices.remove(obj)
        self.set_bounds(self.bounds)

    def slice_right(self, obj):
        if obj not in self.rightslices:
            self.rightslices.append(obj)
        self.set_bounds(self.bounds)

    def unslice_right(self, obj):
        if obj in self.rightslices:
            self.leftslices.remove(obj)
        self.set_bounds(self.bounds)

    def cmd_toggle_bars(self):
        if self.bars_visible:
            self.cmd_hide_bars()
        else:
            self.cmd_show_bars()

    def cmd_hide_bars(self):
        for bar in self.all_bars():
            bar.window.hide()
        self.bars_visible = False
        self.inner_bounds = self.bounds
        self.updated.emit()

    def cmd_show_bars(self):
        for bar in self.all_bars():
            bar.window.show()
        self.bars_visible = True
        self.set_bounds(self.bounds)
Example #18
0
class Bar(object):

    xcore = dependency(Core, 'xcore')
    dispatcher = dependency(EventDispatcher, 'event-dispatcher')
    theme = dependency(Theme, 'theme')


    def __init__(self, widgets, position='top'):
        self.widgets = widgets
        self.position = position
        self.bounds = None
        self.window = None
        self.redraw = Event('bar.redraw')
        self.redraw.listen(self.expose)

    def __zorro_di_done__(self):
        bar = self.theme.bar
        self.height = bar.height
        self.background = bar.background_pat
        inj = di(self).clone()
        inj['bar'] = self
        for w in self.widgets:
            w.height = self.height
            inj.inject(w)

    def set_bounds(self, rect):
        self.bounds = rect
        self.width = rect.width
        stride = self.xcore.bitmap_stride
        self.img = self.xcore.pixbuf(self.width, self.height)
        self.cairo = self.img.context()
        if self.window and not self.window.set_bounds(rect):
            self.redraw.emit()

    def create_window(self):
        EM = self.xcore.EventMask
        CW = self.xcore.CW
        self.window = DisplayWindow(self.xcore.create_toplevel(self.bounds,
            klass=self.xcore.WindowClass.InputOutput,
            params={
                CW.EventMask: EM.Exposure | EM.SubstructureNotify,
                CW.OverrideRedirect: True,
            }), self.expose)
        self.window.want.size = self.bounds
        di(self).inject(self.window)
        self.dispatcher.register_window(self.window)
        self.window.show()

    def expose(self, rect=None):
        # TODO(tailhook) set clip region to specified rectangle
        self.cairo.set_source(self.background)
        self.cairo.rectangle(0, 0, self.width, self.height)
        self.cairo.fill()
        l = 0
        r = self.width
        for i in self.widgets:
            self.cairo.save()
            self.cairo.rectangle(l, 0, r-l, self.height)
            self.cairo.clip()
            l, r = i.draw(self.cairo, l, r)
            self.cairo.restore()
        self.img.draw(self.window)
Example #19
0
class LeftBar(object):

    xcore = dependency(XCore, 'xcore')
    theme = dependency(Theme, 'theme')
    dispatcher = dependency(EventDispatcher, 'event-dispatcher')
    commander = dependency(CommandDispatcher, 'commander')

    def __init__(self, screen, width, groups, states):
        self.screen = screen
        self.width = width
        self._cairo = None
        self._img = None
        self.redraw = Event('leftbar.redraw')
        self.redraw.listen(self._redraw)
        self.repaint = Event('leftbar.repaint')
        self.repaint.listen(self._paint)
        self.screen.add_group_hook(self._group_hook)
        self.visible = False
        self.groups = groups
        self.states = states
        self._drawn_group = None

    def __zorro_di_done__(self):
        wid = self.xcore.create_toplevel(Rectangle(0, 0, 1, 1),
            klass=self.xcore.WindowClass.InputOutput,
            params={
                self.xcore.CW.BackPixel: self.theme.menu.background,
                self.xcore.CW.OverrideRedirect: True,
                self.xcore.CW.EventMask: self.xcore.EventMask.Exposure,
            })
        self.window = di(self).inject(DisplayWindow(wid, self.paint))
        self.dispatcher.all_windows[wid] = self.window
        self.window.show()
        if self.screen.group:
            self._group_hook()
        self.commander.events['window'].listen(self._check_redraw)
        Window.any_window_changed.listen(self._check_redraw)

    def paint(self, rect):
        self.repaint.emit()

    def _check_redraw(self):
        st  = self.states.get(self.screen.group)
        if st is None or st.dirty:
            self.redraw.emit()

    def set_bounds(self, rect):
        self.bounds = rect
        self.window.set_bounds(rect)
        self._cairo = None
        self._img = None

    def _draw_section(self, title, y):
        ctx = self._cairo
        theme = self.theme.tabs
        ctx.set_source(theme.section_color_pat)
        sx, sy, tw, th, ax, ay = ctx.text_extents(title)
        y += theme.section_padding.top + th
        x = self.width - theme.section_padding.right - tw
        ctx.move_to(x, y)
        ctx.show_text(title)
        y += theme.section_padding.bottom
        return y

    def _draw_win(self, win, y):
        ctx = self._cairo
        theme = self.theme.tabs
        sx, sy, tw, th, ax, ay = ctx.text_extents(win.title)
        fh = th + theme.padding.top + theme.padding.bottom
        # Background
        if win.active:
            ctx.set_source(theme.active_bg_pat)
        elif win.urgent:
            ctx.set_source(theme.urgent_bg_pat)
        else:
            ctx.set_source(theme.inactive_bg_pat)
        ctx.move_to(self.width, y)
        ctx.line_to(theme.margin.left + theme.border_radius, y)
        ctx.curve_to(theme.margin.left + theme.border_radius/3, y,
            theme.margin.left, y + theme.border_radius/3,
            theme.margin.left, y + theme.border_radius)
        ctx.line_to(theme.margin.left, y + fh - theme.border_radius)
        ctx.curve_to(theme.margin.left, y + fh - theme.border_radius/3,
            theme.margin.left + theme.border_radius/3, y + fh,
            theme.margin.left + theme.border_radius, y + fh)
        ctx.line_to(self.width, y + fh)
        ctx.close_path()
        ctx.fill()
        # Icon
        if hasattr(win.win, 'icons'):
            win.win.draw_icon(ctx,
                theme.margin.left + theme.padding.left,
                y + (th + theme.padding.top + theme.padding.bottom
                     - theme.icon_size)//2,
                theme.icon_size)
        # Title
        if win.active:
            ctx.set_source(theme.active_title_pat)
        elif win.urgent:
            ctx.set_source(theme.urgent_title_pat)
        else:
            ctx.set_source(theme.inactive_title_pat)
        x = theme.margin.left + theme.padding.left
        x += theme.icon_size + theme.icon_spacing
        ctx.move_to(x, y + theme.padding.top + th)
        y += th + theme.spacing + theme.padding.top + theme.padding.bottom
        ctx.show_text(win.title)
        ctx.fill()
        return y

    def _paint(self):
        if self._img:
            self._img.draw(self.window)

    def _redraw(self):
        if not self.visible:
            return
        gr = self.screen.group
        st = self.states.get(gr)
        if st is None:
            st = self.states[gr] = di(self).inject(State(gr))
        if not st.update() and self._img and self._drawn_group == gr:
            return
        if self._img is None:
            self._img = self.xcore.pixbuf(self.width, self.bounds.height)
            self._cairo = self._img.context()
        theme = self.theme.tabs
        ctx = self._cairo
        ctx.set_source(theme.background_pat)
        ctx.rectangle(0, 0, self._img.width, self._img.height)
        ctx.fill()
        theme.font.apply(ctx)
        y = theme.margin.top
        for sec in st.sections:
            for win in sec:
                if isinstance(win, str):
                    if len(st.sections) > 1:
                        y = self._draw_section(win, y)
                else:
                    y = self._draw_win(win, y)
        self._drawn_group = gr
        self.repaint.emit()

    def _group_hook(self):
        ngr = self.screen.group
        if ngr.name in self.groups:
            self.show()
        else:
            self.hide()
        self.redraw.emit()

    def show(self):
        if not self.visible:
            self.visible = True
            self.window.show()
            self.screen.slice_left(self)

    def hide(self):
        if self.visible:
            self.visible = False
            self.screen.unslice_left(self)
            self.window.hide()
            self._cairo = None
            self._img = None
Example #20
0
class LeftBar(object):

    xcore = dependency(XCore, 'xcore')
    theme = dependency(Theme, 'theme')
    dispatcher = dependency(EventDispatcher, 'event-dispatcher')
    commander = dependency(CommandDispatcher, 'commander')

    def __init__(self, screen, width, groups, states):
        self.screen = screen
        self.width = width
        self._cairo = None
        self._img = None
        self.redraw = Event('leftbar.redraw')
        self.redraw.listen(self._redraw)
        self.repaint = Event('leftbar.repaint')
        self.repaint.listen(self._paint)
        self.screen.add_group_hook(self._group_hook)
        self.visible = False
        self.groups = groups
        self.states = states
        self._drawn_group = None

    def __zorro_di_done__(self):
        wid = self.xcore.create_toplevel(
            Rectangle(0, 0, 1, 1),
            klass=self.xcore.WindowClass.InputOutput,
            params={
                self.xcore.CW.BackPixel: self.theme.menu.background,
                self.xcore.CW.OverrideRedirect: True,
                self.xcore.CW.EventMask: self.xcore.EventMask.Exposure,
            })
        self.window = di(self).inject(DisplayWindow(wid, self.paint))
        self.dispatcher.all_windows[wid] = self.window
        self.window.show()
        if self.screen.group:
            self._group_hook()
        self.commander.events['window'].listen(self._check_redraw)
        Window.any_window_changed.listen(self._check_redraw)

    def paint(self, rect):
        self.repaint.emit()

    def _check_redraw(self):
        st = self.states.get(self.screen.group)
        if st is None or st.dirty:
            self.redraw.emit()

    def set_bounds(self, rect):
        self.bounds = rect
        self.window.set_bounds(rect)
        self._cairo = None
        self._img = None

    def _draw_section(self, title, y):
        ctx = self._cairo
        theme = self.theme.tabs
        ctx.set_source(theme.section_color_pat)
        sx, sy, tw, th, ax, ay = ctx.text_extents(title)
        y += theme.section_padding.top + th
        x = self.width - theme.section_padding.right - tw
        ctx.move_to(x, y)
        ctx.show_text(title)
        y += theme.section_padding.bottom
        return y

    def _draw_win(self, win, y):
        ctx = self._cairo
        theme = self.theme.tabs
        sx, sy, tw, th, ax, ay = ctx.text_extents(win.title)
        fh = th + theme.padding.top + theme.padding.bottom
        # Background
        if win.active:
            ctx.set_source(theme.active_bg_pat)
        elif win.urgent:
            ctx.set_source(theme.urgent_bg_pat)
        else:
            ctx.set_source(theme.inactive_bg_pat)
        ctx.move_to(self.width, y)
        ctx.line_to(theme.margin.left + theme.border_radius, y)
        ctx.curve_to(theme.margin.left + theme.border_radius / 3, y,
                     theme.margin.left, y + theme.border_radius / 3,
                     theme.margin.left, y + theme.border_radius)
        ctx.line_to(theme.margin.left, y + fh - theme.border_radius)
        ctx.curve_to(theme.margin.left, y + fh - theme.border_radius / 3,
                     theme.margin.left + theme.border_radius / 3, y + fh,
                     theme.margin.left + theme.border_radius, y + fh)
        ctx.line_to(self.width, y + fh)
        ctx.close_path()
        ctx.fill()
        # Icon
        if hasattr(win.win, 'icons'):
            win.win.draw_icon(
                ctx, theme.margin.left + theme.padding.left,
                y + (th + theme.padding.top + theme.padding.bottom -
                     theme.icon_size) // 2, theme.icon_size)
        # Title
        if win.active:
            ctx.set_source(theme.active_title_pat)
        elif win.urgent:
            ctx.set_source(theme.urgent_title_pat)
        else:
            ctx.set_source(theme.inactive_title_pat)
        x = theme.margin.left + theme.padding.left
        x += theme.icon_size + theme.icon_spacing
        ctx.move_to(x, y + theme.padding.top + th)
        y += th + theme.spacing + theme.padding.top + theme.padding.bottom
        ctx.show_text(win.title)
        ctx.fill()
        return y

    def _paint(self):
        if self._img:
            self._img.draw(self.window)

    def _redraw(self):
        if not self.visible:
            return
        gr = self.screen.group
        st = self.states.get(gr)
        if st is None:
            st = self.states[gr] = di(self).inject(State(gr))
        if not st.update() and self._img and self._drawn_group == gr:
            return
        if self._img is None:
            self._img = self.xcore.pixbuf(self.width, self.bounds.height)
            self._cairo = self._img.context()
        theme = self.theme.tabs
        ctx = self._cairo
        ctx.set_source(theme.background_pat)
        ctx.rectangle(0, 0, self._img.width, self._img.height)
        ctx.fill()
        theme.font.apply(ctx)
        y = theme.margin.top
        for sec in st.sections:
            for win in sec:
                if isinstance(win, str):
                    if len(st.sections) > 1:
                        y = self._draw_section(win, y)
                else:
                    y = self._draw_win(win, y)
        self._drawn_group = gr
        self.repaint.emit()

    def _group_hook(self):
        ngr = self.screen.group
        if ngr.name in self.groups:
            self.show()
        else:
            self.hide()
        self.redraw.emit()

    def show(self):
        if not self.visible:
            self.visible = True
            self.window.show()
            self.screen.slice_left(self)

    def hide(self):
        if self.visible:
            self.visible = False
            self.screen.unslice_left(self)
            self.window.hide()
            self._cairo = None
            self._img = None