class ButtonBase(Control):
    align = 'c'
    action = None
    rightClickAction = None
    default_choice_color = ThemeProperty('default_choice_color')
    default_choice_bg_color = ThemeProperty('default_choice_bg_color')

    def mouse_down(self, event):
        button = event.button
        if self.enabled and button == 1:
            self._highlighted = True

    def mouse_drag(self, event):
        state = event in self
        if event.buttons[0] == 1 and state != self._highlighted:
            self._highlighted = state
            self.invalidate()

    def mouse_up(self, event):
        button = event.button
        if event in self and button == 1:
            if self is event.clicked_widget or (
                    event.clicked_widget
                    and self in event.clicked_widget.all_parents()):
                self._highlighted = False
                if self.enabled:
                    self.call_handler('action')
        if event in self and button == 3 and self.enabled:
            if self is event.clicked_widget or (
                    event.clicked_widget
                    and self in event.clicked_widget.all_parents()):
                self.call_handler('rightClickAction')
        self.get_root().fix_sticky_ctrl()
Exemple #2
0
class ButtonBase(Control):

    align = 'c'
    action = None
    default_choice_color = ThemeProperty('default_choice_color')
    default_choice_bg_color = ThemeProperty('default_choice_bg_color')

    def mouse_down(self, event):
        if self.enabled:
            self._highlighted = True

    def mouse_drag(self, event):
        state = event in self
        if state != self._highlighted:
            self._highlighted = state
            self.invalidate()

    def mouse_up(self, event):
        if event in self:
            if self is event.clicked_widget or (
                    event.clicked_widget
                    and self in event.clicked_widget.all_parents()):
                self._highlighted = False
                if self.enabled:
                    self.call_handler('action')
Exemple #3
0
class CheckWidget(Widget):
    default_size = (16, 16)
    margin = 4
    border_width = 1
    check_mark_tweak = 2

    if __builtins__.get("mcenf_tab_to_next"):
        tab_stop = True
        highlight_color = ThemeProperty('highlight_color')

    smooth = ThemeProperty('smooth')

    def __init__(self, **kwds):
        Widget.__init__(self, Rect((0, 0), self.default_size), **kwds)

    def draw(self, surf):
        if self.highlighted:
            r = self.get_margin_rect()
            fg = self.fg_color
            d = self.check_mark_tweak
            p1 = (r.left, r.centery - d)
            p2 = (r.centerx - d, r.bottom)
            p3 = (r.right, r.top - d)
            if self.smooth:
                draw.aalines(surf, fg, False, [p1, p2, p3])
            else:
                draw.lines(surf, fg, False, [p1, p2, p3])
Exemple #4
0
class Multichoice(PaletteView, Control):

    highlight_color = ThemeProperty('highlight_color')
    cell_margin = ThemeProperty('cell_margin')

    #highlight_style = 'frame'
    align = 'c'
    tab_stop = True

    def __init__(self, cell_size, values, **kwds):
        PaletteView.__init__(self, cell_size, 1, len(values), **kwds)
        self.values = values

    def num_items(self):
        return len(self.values)

    def item_is_selected(self, n):
        return self.get_value() == self.values[n]

    def click_item(self, n, e):
        if self.tab_stop:
            self.focus()
        self.set_value(self.values[n])

    def draw(self, surf):
        if self.has_focus():
            surf.fill(self.highlight_color)
        PaletteView.draw(self, surf)

    def key_down(self, e):
        k = e.key
        if k == K_LEFT:
            self.change_value(-1)
        elif k == K_RIGHT:
            self.change_value(1)
        else:
            PaletteView.key_down(self, e)

    def change_value(self, d):
        values = self.values
        if values:
            n = len(values)
            value = self.get_value()
            try:
                i = values.index(value)
            except ValueError:
                if d < 0:
                    i = 0
                else:
                    i = n - 1
            else:
                i = max(0, min(n - 1, i + d))
            self.set_value(values[i])
class Image(Widget):
    #  image   Image to display

    highlight_color = ThemeProperty('highlight_color')

    image = overridable_property('image')

    highlighted = False

    def __init__(self, image=None, rect=None, **kwds):
        Widget.__init__(self, rect, **kwds)
        if image:
            if isinstance(image, basestring):
                image = resource.get_image(image)
            w, h = image.get_size()
            d = 2 * self.margin
            self.size = w + d, h + d
            self._image = image

    def get_image(self):
        return self._image

    def set_image(self, x):
        self._image = x

    def draw(self, surf):
        frame = surf.get_rect()
        if self.highlighted:
            surf.fill(self.highlight_color)
        image = self.image
        r = image.get_rect()
        r.center = frame.center
        surf.blit(image, r)
Exemple #6
0
class ProgressBar(Control, Widget):
    bc = ThemeProperty('sel_color')
    center = 0
    border_width = 1

    def __init__(self, width=100, center=0, **kwds):
        Widget.__init__(self, Rect((0, 0), (width, 16)), **kwds)
        if (center > width):
            center = width / 2
        self.center = center

    def draw(self, surf):
        frame = surf.get_rect()
        print self.value
        rect = Rect((self.center, 0), (self.value, frame.height))
        draw.rect(surf, self.bc, rect, 0)
class TabPanel(Widget):
    #  pages         [Widget]
    #  current_page  Widget

    tab_font = FontProperty('tab_font')
    tab_height = ThemeProperty('tab_height')
    tab_border_width = ThemeProperty('tab_border_width')
    tab_spacing = ThemeProperty('tab_spacing')
    tab_margin = ThemeProperty('tab_margin')
    tab_fg_color = ThemeProperty('tab_fg_color')
    default_tab_bg_color = ThemeProperty('default_tab_bg_color')
    tab_area_bg_color = ThemeProperty('tab_area_bg_color')
    tab_dimming = ThemeProperty('tab_dimming')
    tab_titles = None

    #use_page_bg_color_for_tabs = ThemeProperty('use_page_bg_color_for_tabs')

    def __init__(self, pages=None, **kwds):
        Widget.__init__(self, **kwds)
        self.pages = []
        self.current_page = None
        if pages:
            w = h = 0
            for title, page in pages:
                w = max(w, page.width)
                h = max(h, page.height)
                self._add_page(title, page)
            self.size = (w, h)
            self.show_page(pages[0][1])

    def content_size(self):
        return self.width, self.height - self.tab_height

    def content_rect(self):
        return Rect((0, self.tab_height), self.content_size())

    def page_height(self):
        return self.height - self.tab_height

    def add_page(self, title, page):
        self._add_page(title, page)
        if not self.current_page:
            self.show_page(page)

    def _add_page(self, title, page):
        page.tab_title = _(title)
        page.anchor = 'ltrb'
        self.pages.append(page)

    def remove_page(self, page):
        try:
            i = self.pages.index(page)
            del self.pages[i]
        except IndexError:
            pass
        if page is self.current_page:
            self.show_page(None)

    def show_page(self, page):
        if self.current_page:
            self.remove(self.current_page)
        self.current_page = page
        if page:
            th = self.tab_height
            page.rect = Rect(0, th, self.width, self.height - th)
            self.add(page)
            page.focus()

    def draw(self, surf):
        self.draw_tab_area_bg(surf)
        self.draw_tabs(surf)

    def draw_tab_area_bg(self, surf):
        bg = self.tab_area_bg_color
        if bg:
            surf.fill(bg, (0, 0, self.width, self.tab_height))

    def draw_tabs(self, surf):
        font = self.tab_font
        fg = self.tab_fg_color
        b = self.tab_border_width
        if b:
            surf.fill(fg, (0, self.tab_height - b, self.width, b))
        for i, title, page, selected, rect in self.iter_tabs():
            x0 = rect.left
            w = rect.width
            h = rect.height
            r = rect
            if not selected:
                r = Rect(r)
                r.bottom -= b
            self.draw_tab_bg(surf, page, selected, r)
            if b:
                surf.fill(fg, (x0, 0, b, h))
                surf.fill(fg, (x0 + b, 0, w - 2 * b, b))
                surf.fill(fg, (x0 + w - b, 0, b, h))
            buf = font.render(title, True, page.fg_color or fg)
            r = buf.get_rect()
            r.center = (x0 + w // 2, h // 2)
            surf.blit(buf, r)

    def iter_tabs(self):
        pages = self.pages
        current_page = self.current_page
        n = len(pages)
        b = self.tab_border_width
        s = self.tab_spacing
        h = self.tab_height
        m = self.tab_margin
        width = self.width - 2 * m + s - b
        x0 = m
        for i, page in enumerate(pages):
            x1 = m + (i + 1) * width // n  # self.tab_boundary(i + 1)
            selected = page is current_page
            yield i, page.tab_title, page, selected, Rect(
                x0, 0, x1 - x0 - s + b, h)
            x0 = x1

    def draw_tab_bg(self, surf, page, selected, rect):
        bg = self.tab_bg_color_for_page(page)
        if not selected:
            bg = brighten(bg, self.tab_dimming)
        surf.fill(bg, rect)

    def tab_bg_color_for_page(self, page):
        return getattr(page, 'tab_bg_color', None) \
               or page.bg_color \
               or self.default_tab_bg_color

    def mouse_down(self, e):
        x, y = e.local
        if y < self.tab_height:
            i = self.tab_number_containing_x(x)
            if i is not None:
                self.show_page(self.pages[i])

    def tab_number_containing_x(self, x):
        n = len(self.pages)
        m = self.tab_margin
        width = self.width - 2 * m + self.tab_spacing - self.tab_border_width
        i = (x - m) * n // width
        if 0 <= i < n:
            return i

    def gl_draw_self(self, root, offset):
        self.gl_draw(root, offset)

    def gl_draw(self, root, offset):
        pages = self.pages

        if len(pages) > 1:
            tlcorner = (offset[0] + self.bottomleft[0],
                        offset[1] + self.bottomleft[1])
            pageTabContents = []
            current_page = self.current_page
            n = len(pages)
            b = self.tab_border_width
            s = self.tab_spacing
            h = self.tab_height
            m = self.tab_margin
            tabWidth = (self.size[0] - (s * n) - (2 * m)) / n
            width = self.width - 2 * m + s - b
            x0 = m + tlcorner[0]

            font = self.tab_font
            fg = self.tab_fg_color
            surface = Surface(self.size, SRCALPHA)

            glEnable(GL_BLEND)

            for i, page in enumerate(pages):
                x1 = x0 + tabWidth
                selected = page is current_page
                if selected:
                    glColor(1.0, 1.0, 1.0, 0.5)
                else:
                    glColor(0.5, 0.5, 0.5, 0.5)
                glRectf(x0, tlcorner[1] - (m + b), x1, tlcorner[1] - (h))
                buf = font.render(self.pages[i].tab_title, True, self.fg_color
                                  or fg)
                r = buf.get_rect()

                offs = ((tabWidth - r.size[0]) / 2) + m + ((s + tabWidth) * i)

                surface.blit(buf, (offs, m))
                x0 = x1 + s

            data = image.tostring(surface, 'RGBA', 1)
            rect = self.rect.move(offset)
            w, h = root.size
            glViewport(0, 0, w, h)
            glMatrixMode(GL_PROJECTION)
            glLoadIdentity()
            gluOrtho2D(0, w, 0, h)
            glMatrixMode(GL_MODELVIEW)
            glLoadIdentity()
            glRasterPos2i(rect.left, h - rect.bottom)
            glPushAttrib(GL_COLOR_BUFFER_BIT)
            glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
            glDrawPixels(self.width, self.height, GL_RGBA, GL_UNSIGNED_BYTE,
                         fromstring(data, dtype='uint8'))
            glPopAttrib()
            glFlush()

            glDisable(GL_BLEND)
Exemple #8
0
class Tree(Column):
    """..."""
    rows = []
    row_margin = 2
    column_margin = 2
    bullet_size = ThemeProperty('bullet_size')
    bullet_color_active = ThemeProperty('bullet_color_active')
    bullet_color_inactive = ThemeProperty('bullet_color_inactive')

    def __init__(self, *args, **kwargs):
        self.menu = [("Add", "add_item"),
                     ("Delete", "delete_item"),
                     ("New child", "add_child"),
                     ("Rename", "rename_item"),
                     ("", ""),
                     ("Cut", "cut_item"),
                     ("Copy", "copy_item"),
                     ("Paste", "paste_item"),
                     ("Paste as child", "paste_child"),
                     ]
        if not hasattr(self, 'map_types_item'):
            global map_types_item
            self.map_types_item = setup_map_types_item()
        self.selected_item_index = None
        self.selected_item = None
        self.clicked_item = None
        self.copyBuffer = kwargs.pop('copyBuffer', None)
        self._parent = kwargs.pop('_parent', None)
        self.styles = kwargs.pop('styles', {})
        self.compound_types = [dict,] + kwargs.pop('compound_types', [])
        self.item_types = self.compound_types + kwargs.pop('item_types', [a[0] for a in self.map_types_item.values()] or [int, float, unicode, bool])
        for t in self.item_types:
            if 'create_%s'%t.__name__ in globals().keys():
                setattr(self, 'create_%s'%t.__name__, globals()['create_%s'%t.__name__])
        self.show_fields = kwargs.pop('show_fields', False)
        self.deployed = []
        self.data = data = kwargs.pop("data", {})
        self.draw_zebra = draw_zebra = kwargs.pop('draw_zebra', True)
#        self.inner_width = kwargs.pop('inner_width', 'auto')
        self.inner_width = kwargs.pop('inner_width', 500)
        self.__num_rows = len(data.keys())
        self.build_layout()
#        row_height = self.font.size(' ')[1]
        row_height = self.font.get_linesize()
        self.treeRow = treeRow = TreeRow((self.inner_width, row_height), 10, draw_zebra=draw_zebra)
        Column.__init__(self, [treeRow,], **kwargs)

    def dispatch_key(self, name, evt):
        if not hasattr(evt, 'key'):
            return
        if name == "key_down":
            keyname = self.root.getKey(evt)
            if keyname == "Up" and self.selected_item_index > 0:
                if self.selected_item_index == None:
                    self.selected_item_index = -1
                self.selected_item_index = max(self.selected_item_index - 1, 0)

            elif keyname == "Down" and self.selected_item_index < len(self.rows) - 1:
                if self.selected_item_index == None:
                    self.selected_item_index = -1
                self.selected_item_index += 1
            elif keyname == 'Page down':
                if self.selected_item_index == None:
                    self.selected_item_index = -1
                self.selected_item_index = min(len(self.rows) - 1, self.selected_item_index + self.treeRow.num_rows())
            elif keyname == 'Page up':
                if self.selected_item_index == None:
                    self.selected_item_index = -1
                self.selected_item_index = max(0, self.selected_item_index - self.treeRow.num_rows())
            if self.treeRow.cell_to_item_no(0, 0) != None and (self.treeRow.cell_to_item_no(0, 0) + self.treeRow.num_rows() -1 > self.selected_item_index or self.treeRow.cell_to_item_no(0, 0) + self.treeRow.num_rows() -1 < self.selected_item_index):
                self.treeRow.scroll_to_item(self.selected_item_index)

            if keyname == 'Return' and self.selected_item_index != None:
                self.select_item(self.selected_item_index)
                if self.selected_item[7] in self.compound_types:
                    self.deploy(self.selected_item[6])

    def cut_item(self):
        self.copyBuffer = ([] + self.selected_item, 1)
        self.delete_item()

    def copy_item(self):
        self.copyBuffer = ([] + self.selected_item, 0)

    def paste_item(self):
        parent = self.get_item_parent(self.selected_item)
        name = self.copyBuffer[0][3]
        old_name = u"%s"%self.copyBuffer[0][3]
        if self.copyBuffer[1] == 0:
            name = input_text_buttons("Choose a name", 300, self.copyBuffer[0][3])
        else:
            old_name = ""
        if name and type(name) in (str, unicode) and name != old_name:
            new_item = copy.deepcopy(self.copyBuffer[0][9])
            if hasattr(new_item, 'name'):
                new_item.name = name
            self.add_item_to(parent, (name, new_item))

    def paste_child(self):
        name = self.copyBuffer[0][3]
        old_name = u"%s"%self.copyBuffer[0][3]
        names = []
        children = self.get_item_children(self.selected_item)
        if children:
            names = [a[3] for a in children]
        if name in names:
            name = input_text_buttons("Choose a name", 300, self.copyBuffer[0][3])
        else:
            old_name = ""
        if name and type(name) in (str, unicode) and name != old_name:
            new_item = copy.deepcopy(self.copyBuffer[0][9])
            if hasattr(new_item, 'name'):
                new_item.name = name
            self.add_item_to(self.selected_item, (name, new_item))

    @staticmethod
    def add_item_to_dict(parent, name, item):
        parent[name] = item

    def add_item_to(self, parent, (name, item)):
        if parent is None:
            tp = 'dict'
            parent = self.data
        else:
            tp = parent[7].__name__
            parent = parent[9]
        if not name:
            i = 0
            name = 'Item %03d'%i
            while name in self.data.keys():
                i += 1
                name = 'Item %03d'%i
        meth = getattr(self, 'add_item_to_%s'%tp, None)
        if meth:
            meth(parent, name, item)
            self.build_layout()
        else:
            alert(_("No function implemented to add items to %s type.")%type(parent).__name__, doNotTranslate=True)
Exemple #9
0
class Widget(gvent.GventReceiver):
    logger = logging.getLogger("GyUI.Widget")

    font = FontProperty('font')
    fg_color = ThemeProperty('fg_color')
    bg_color = ThemeProperty('bg_color')
    bg_image = ThemeProperty('bg_image')
    scale_bg = ThemeProperty('scale_bg')
    border_width = ThemeProperty('border_width')
    border_color = ThemeProperty('border_color')
    sel_color = ThemeProperty('sel_color')
    margin = ThemeProperty('margin')
    menu_bar = overridable_property('menu_bar')
    is_gl_container = overridable_property('is_gl_container')

    # rect properties accesses
    left = rect_property('left')
    right = rect_property('right')
    top = rect_property('top')
    bottom = rect_property('bottom')
    width = rect_property('width')
    height = rect_property('height')
    size = rect_property('size')
    topleft = rect_property('topleft')
    topright = rect_property('topright')
    bottomleft = rect_property('bottomleft')
    bottomright = rect_property('bottomright')
    midleft = rect_property('midleft')
    midright = rect_property('midright')
    midtop = rect_property('midtop')
    midbottom = rect_property('midbottom')
    center = rect_property('center')
    centerx = rect_property('centerx')
    centery = rect_property('centery')

    # local_rect properties accesses
    local_left = local_rect_property('left')
    local_right = local_rect_property('right')
    local_top = local_rect_property('top')
    local_bottom = local_rect_property('bottom')
    local_width = local_rect_property('width')
    local_height = local_rect_property('height')
    local_size = local_rect_property('size')
    local_topleft = local_rect_property('topleft')
    local_topright = local_rect_property('topright')
    local_bottomleft = local_rect_property('bottomleft')
    local_bottomright = local_rect_property('bottomright')
    local_midleft = local_rect_property('midleft')
    local_midright = local_rect_property('midright')
    local_midtop = local_rect_property('midtop')
    local_midbottom = local_rect_property('midbottom')
    local_center = local_rect_property('center')
    local_centerx = local_rect_property('centerx')
    local_centery = local_rect_property('centery')

    def __init__(self, rect=None):
        '''
        Constructor for Widget
        '''
        gvent.GventReceiver.__init__(self)

        self.dirty = 1
        self.parent = None
        if rect is None:
            self._rect = pygame.Rect((0, 0), (100, 100))
        elif rect:
            self._rect = pygame.Rect(rect)


#            self._rect = rect
        self._local_rect = pygame.Rect((0, 0), (100, 100))

    def get_rect(self):
        '''
        Getter for rect property
        '''
        return self._rect

    def set_rect(self, rect):
        '''
        Setter for rect property
        '''
        old_rect = self._rect
        self._rect = pygame.Rect(rect)
        self._rect_global_to_local()
        self._moved(old_rect.topleft)
        self._resized(old_rect.size)

    rect = property(get_rect, set_rect)

    def get_local_rect(self):
        '''
        Getter for local_rect property
        '''
        return self._local_rect

    def set_local_rect(self, rect):
        '''
        Setter for local_rect property
        '''
        old_rect = self._local_rect
        self._local_rect = pygame.Rect(rect)
        self._rect_local_to_global()
        self._moved(old_rect.topleft)
        self._resized(old_rect.size)

    local_rect = property(get_local_rect, set_local_rect)

    def _rect_global_to_local(self):
        '''
        Set local rect from global rect
        '''
        if self.parent:
            move_by = (self.parent.left * -1, self.parent.top * -1)
            self._local_rect = self._rect.move(move_by)
        else:
            self._local_rect = self._rect
        print self, "new local_rect:", self._local_rect

    def _rect_local_to_global(self):
        '''
        Set global rect from local rect
        '''
        if self.parent:
            self._rect = self._local_rect.move(self.parent.topleft)
        else:
            self._rect = self._local_rect

    def _resized(self, old_size):
        '''
        Inform widget that it's size has changed
        '''
        if self._rect.size != tuple(old_size):
            # new size is different
            pass

    def _moved(self, old_pos):
        if self._rect.topleft != tuple(old_pos):
            # new pos is actually different
            self.set_dirty()

    def _parent_moved(self, old_pos):
        # recalculate local rect with new parent position
        self._rect_local_to_global()

    def _set_parent(self, parent):
        self.parent = parent
        #        self._parent_resized(None)
        self._parent_moved(None)

    def get_widget_at(self, pos):
        '''
        Get widged at that (global) position
        
        This is mainly useful as recursion end from Bin widgets 
        '''
        return self

    def _draw(self, surface):
        '''
        Execute actual draw of this very widget
        '''
        pygame.draw.rect(surface, (0xff, 0, 0), self.rect)

    def draw(self, surface):
        '''
        '''
        self._draw(surface)

    def set_dirty(self):
        '''
        Set this widget to be redrawn next draw
        '''
        if not self.dirty:
            self.dirty = 1

    def set_dirty_all(self):
        self.set_dirty()
class Label(Widget):
    text = overridable_property('text')
    align = overridable_property('align')

    hover_color = ThemeProperty('hover_color')
    highlight_color = ThemeProperty('highlight_color')
    disabled_color = ThemeProperty('disabled_color')
    highlight_bg_color = ThemeProperty('highlight_bg_color')
    hover_bg_color = ThemeProperty('hover_bg_color')
    enabled_bg_color = ThemeProperty('enabled_bg_color')
    disabled_bg_color = ThemeProperty('disabled_bg_color')

    enabled = True
    highlighted = False
    _align = 'l'

    def __init__(self, text, width=None, base_text=None, **kwds):
        #-# Translation live update preparation
        # base_text: to be used each time a widget takes a formated string
        #            defaults to 'text'.
        Widget.__init__(self, **kwds)
        #-# Translation live update preparation
        self.fixed_width = width
        self.base_text = base_text or text
        self.previous_translation = _(text,
                                      doNotTranslate=kwds.get(
                                          'doNotTranslate', False))
        #-#
        self._text = _(text, doNotTranslate=kwds.get('doNotTranslate', False))
        #-#
        self.calc_size()
        #-#

    #-# Translation live update preparation
    def calc_size(self):
        lines = self._text.split("\n")
        tw, th = 0, 0
        for i in range(len(lines)):
            line = lines[i]
            if i == len(lines) - 1:
                w, h = self.font.size(line)
            else:
                w, h = self.font.size(line)[0], self.font.get_linesize()
            tw = max(tw, w)
            th += h
        if self.fixed_width is not None:
            tw = self.fixed_width
        else:
            tw = max(1, tw)
        d = 2 * self.margin
        self.size = (tw + d, th + d)

    def get_update_translation(self):
        return Widget.update_translation(self)

    def set_update_ui(self, v):
        self.text = self.base_text
        self.set_text(self.base_text)
        self.calc_size()
        Widget.set_update_ui(self, v)

    #-#

    def __repr__(self):
        return "Label {0}, child of {1}".format(self.text, self.parent)

    def get_text(self):
        return self._text

    def set_text(self, x, doNotTranslate=False):
        self._text = _(x, doNotTranslate=doNotTranslate or self.doNotTranslate)
        self.calc_size()

    def get_align(self):
        return self._align

    def set_align(self, x):
        self._align = x

    def draw(self, surface):
        if not self.enabled:
            fg = self.disabled_color
            bg = self.disabled_bg_color
        else:
            fg = self.fg_color
            bg = self.enabled_bg_color
            if self.is_default:
                fg = self.default_choice_color or fg
                bg = self.default_choice_bg_color or bg
            if self.is_hover:
                fg = self.hover_color or fg
                bg = self.hover_bg_color or bg
            if self.highlighted:
                fg = self.highlight_color or fg
                bg = self.highlight_bg_color or bg

        self.draw_with(surface, fg, bg)

    is_default = False

    def draw_with(self, surface, fg, bg=None):
        if bg:
            r = surface.get_rect()
            b = self.border_width
            if b:
                e = -2 * b
                r.inflate_ip(e, e)
            surface.fill(bg, r)
        m = self.margin
        align = self.align
        width = surface.get_width()
        y = m
        lines = self.text.split("\n")
        font = self.font
        dy = font.get_linesize()
        for line in lines:
            if len(line):
                size = font.size(line)
                if size[0] == 0:
                    continue

                image = font.render(line, True, fg)
                r = image.get_rect()
                r.top = y
                if align == 'l':
                    r.left = m
                elif align == 'r':
                    r.right = width - m
                else:
                    r.centerx = width // 2
                surface.blit(image, r)
            y += dy
class PaletteView(GridView):
    # nrows   int   No. of displayed rows
    #  ncols   int   No. of displayed columns
    #
    #  Abstract methods:
    #
    #    num_items()  -->  no. of items
    #    draw_item(surface, item_no, rect)
    #    click_item(item_no, event)
    #    item_is_selected(item_no)  -->  bool

    sel_width = ThemeProperty('sel_width')
    zebra_color = ThemeProperty('zebra_color')
    scroll_button_size = ThemeProperty('scroll_button_size')
    scroll_button_color = ThemeProperty('scroll_button_color')
    highlight_style = ThemeProperty('highlight_style')
    # 'frame' or 'fill' or 'reverse' or None

    def __init__(self, cell_size, nrows, ncols, scrolling=False, **kwds):
        GridView.__init__(self, cell_size, nrows, ncols, **kwds)
        self.scrolling = scrolling
        if scrolling:
            d = self.scroll_button_size
            #l = self.width
            #b = self.height
            self.width += d
            #self.scroll_up_rect = Rect(l, 0, d, d).inflate(-4, -4)
            #self.scroll_down_rect = Rect(l, b - d, d, d).inflate(-4, -4)
        self.scroll = 0
        self.dragging_hover = False
        self.scroll_rel = 0

    def scroll_up_rect(self):
        d = self.scroll_button_size
        r = Rect(0, 0, d, d)
        m = self.margin
        r.top = m
        r.right = self.width - m
        r.inflate_ip(-4, -4)
        return r

    def scroll_down_rect(self):
        d = self.scroll_button_size
        r = Rect(0, 0, d, d)
        m = self.margin
        r.bottom = self.height - m
        r.right = self.width - m
        r.inflate_ip(-4, -4)
        return r

    def draw(self, surface):

        GridView.draw(self, surface)
        u = False
        d = False
        if self.can_scroll_up():
            u = True
            self.draw_scroll_up_button(surface)
        if self.can_scroll_down():
            d = True
            self.draw_scroll_down_button(surface)

        if u or d:
            self.draw_scrollbar(surface)

    def draw_scroll_up_button(self, surface):
        r = self.scroll_up_rect()
        c = self.scroll_button_color
        draw.polygon(surface, c, [r.bottomleft, r.midtop, r.bottomright])

    def draw_scroll_down_button(self, surface):
        r = self.scroll_down_rect()
        c = self.scroll_button_color
        draw.polygon(surface, c, [r.topleft, r.midbottom, r.topright])

    def draw_cell(self, surface, row, col, rect):
        i = self.cell_to_item_no(row, col)
        if i is not None:
            highlight = self.item_is_selected(i)
            self.draw_item_and_highlight(surface, i, rect, highlight)

    def draw_item_and_highlight(self, surface, i, rect, highlight):
        if not i % 2 and "Header" not in str(type(self)):
            surface.fill(self.zebra_color, rect)
        if highlight:
            self.draw_prehighlight(surface, i, rect)
        if highlight and self.highlight_style == 'reverse':
            fg = self.inherited('bg_color') or self.sel_color
        else:
            fg = self.fg_color
        self.draw_item_with(surface, i, rect, fg)
        if highlight:
            self.draw_posthighlight(surface, i, rect)

    def draw_item_with(self, surface, i, rect, fg):
        old_fg = self.fg_color
        self.fg_color = fg
        try:
            self.draw_item(surface, i, rect)
        finally:
            self.fg_color = old_fg

    def draw_prehighlight(self, surface, i, rect):
        if self.highlight_style == 'reverse':
            color = self.fg_color
        else:
            color = self.sel_color
        self.draw_prehighlight_with(surface, i, rect, color)

    def draw_prehighlight_with(self, surface, i, rect, color):
        style = self.highlight_style
        if style == 'frame':
            frame_rect(surface, color, rect, self.sel_width)
        elif style == 'fill' or style == 'reverse':
            surface.fill(color, rect)

    def draw_posthighlight(self, surface, i, rect):
        pass

    def mouse_down(self, event):
        if event.button == 1:
            if self.scrolling:
                p = event.local
                if self.scrollbar_rect().collidepoint(p):
                    self.dragging_hover = True
                    return
                elif self.scroll_up_rect().collidepoint(p):
                    self.scroll_up()
                    return
                elif self.scroll_down_rect().collidepoint(p):
                    self.scroll_down()
                    return
        if event.button == 4:
            self.scroll_up()
        if event.button == 5:
            self.scroll_down()

        GridView.mouse_down(self, event)

    def mouse_drag(self, event):
        if self.dragging_hover:
            self.scroll_rel += event.rel[1]
            sub = self.scroll_up_rect().bottom
            t = self.scroll_down_rect().top
            d = t - sub
            # Get the total row number (n).
            n = self.num_items() / getattr(getattr(self, 'parent', None), 'num_cols', lambda: 1)()
            # Get the displayed row number (v)
            s = float(d) / n
            if abs(self.scroll_rel) >= s:
                if self.scroll_rel > 0:
                    self.scroll_down(delta=int(abs(self.scroll_rel) / s))
                else:
                    self.scroll_up(delta=int(abs(self.scroll_rel) / s))
                self.scroll_rel = 0

    def mouse_up(self, event):
        if event.button == 1:
            if self.dragging_hover:
                self.dragging_hover = False
                self.scroll_rel = 0

    def scroll_up(self, delta=1):
        if self.can_scroll_up():
            self.scroll -= delta

    def scroll_down(self, delta=1):
        if self.can_scroll_down():
            self.scroll += delta

    def scroll_to_item(self, n):
        i = max(0, min(n, self.num_items() - 1))
        p = self.items_per_page()
        self.scroll = p * (i // p)

    def can_scroll_up(self):
        return self.scrolling and self.scroll > 0

    def can_scroll_down(self):
        return self.scrolling and self.scroll + self.items_per_page() < self.num_items()

    def items_per_page(self):
        return self.num_rows() * self.num_cols()

    def click_cell(self, row, col, event):
        i = self.cell_to_item_no(row, col)
        if i is not None:
            self.click_item(i, event)

    def cell_to_item_no(self, row, col):
        i = self.scroll + row * self.num_cols() + col
        if 0 <= i < self.num_items():
            return i
        else:
            return None

    def num_rows(self):
        ch = self.cell_size[1]
        if ch:
            return self.height // ch
        else:
            return 0

    def num_cols(self):
        width = self.width
        if self.scrolling:
            width -= self.scroll_button_size
        cw = self.cell_size[0]
        if cw:
            return width // cw
        else:
            return 0

    def item_is_selected(self, n):
        return False

    def click_item(self, n, e):
        pass

    def scrollbar_rect(self):
        # Get the distance between the scroll buttons (d)
        sub = self.scroll_up_rect().bottom
        t = self.scroll_down_rect().top
        d = t - sub
        # Get the total row number (n).
        n = self.num_items() / getattr(getattr(self, 'parent', None), 'num_cols', lambda: 1)()
        # Get the displayed row number (v)
        v = self.num_rows()
        if n:
            s = float(d) / n
        else:
            s = 0
        h = s * v
        if type(h) == float:
            if h - int(h) > 0:
                h += 1

        top = max(sub, sub + (s * self.scroll) + self.scroll_rel)
        r = Rect(0, top, self.scroll_button_size, h)
        m = self.margin
        r.right = self.width - m
        r.bottom = min(r.bottom, t)
        r.inflate_ip(-4, -4)
        if r.h < 1:
            r.h = int(h)
        return r

    def draw_scrollbar(self, surface):
        r = self.scrollbar_rect()
        c = map(lambda x: min(255, max(0, x + 10)), self.scroll_button_color)
        draw.rect(surface, c, r)
Exemple #12
0
class Menu(Dialog):
    disabled_color = ThemeProperty('disabled_color')
    click_outside_response = -1
    scroll_button_size = ThemeProperty('scroll_button_size')
    scroll_button_color = ThemeProperty('scroll_button_color')
    scroll = 0

    def __init__(self,
                 title,
                 items,
                 scrolling=False,
                 scroll_items=30,
                 scroll_page=5,
                 **kwds):
        self.title = _(title)
        self.items = items
        self._items = [MenuItem(*item) for item in items]
        self.scrolling = scrolling and len(self._items) > scroll_items
        self.scroll_items = scroll_items
        self.scroll_page = scroll_page
        Dialog.__init__(self, **kwds)

        h = self.font.get_linesize()
        if self.scrolling:
            self.height = h * self.scroll_items + h
        else:
            self.height = h * len(self._items) + h

    def present(self, client, pos):
        client = client or get_root()
        self.topleft = client.local_to_global(pos)
        focus = get_focus()
        font = self.font
        h = font.get_linesize()
        items = self._items
        margin = self.margin
        if self.scrolling:
            height = h * self.scroll_items + h
        else:
            height = h * len(items) + h
        w1 = w2 = 0
        for item in items:
            item.enabled = self.command_is_enabled(item, focus)
            w1 = max(w1, font.size(item.text)[0])
            w2 = max(w2, font.size(item.keyname)[0])
        width = w1 + 2 * margin
        self._key_margin = width
        if w2 > 0:
            width += w2 + margin
        if self.scrolling:
            width += self.scroll_button_size
        self.size = (width, height)
        self._hilited = None

        root = get_root()
        self.rect.clamp_ip(root.rect)

        return Dialog.present(self, centered=False)

    def command_is_enabled(self, item, focus):
        cmd = item.command
        if cmd:
            enabler_name = cmd + '_enabled'
            handler = focus
            while handler:
                enabler = getattr(handler, enabler_name, None)
                if enabler:
                    return enabler()
                handler = handler.next_handler()
        return True

    def scroll_up_rect(self):
        d = self.scroll_button_size
        r = Rect(0, 0, d, d)
        m = self.margin
        r.top = m
        r.right = self.width - m
        r.inflate_ip(-4, -4)
        return r

    def scroll_down_rect(self):
        d = self.scroll_button_size
        r = Rect(0, 0, d, d)
        m = self.margin
        r.bottom = self.height - m
        r.right = self.width - m
        r.inflate_ip(-4, -4)
        return r

    def draw(self, surf):
        font = self.font
        h = font.get_linesize()
        sep = surf.get_rect()
        sep.height = 1
        if self.scrolling:
            sep.width -= self.margin + self.scroll_button_size
        colors = [self.disabled_color, self.fg_color]
        bg = self.bg_color
        xt = self.margin
        xk = self._key_margin
        y = h // 2
        hilited = self._hilited
        if self.scrolling:
            items = self._items[self.scroll:self.scroll + self.scroll_items]
        else:
            items = self._items
        for item in items:
            text = item.text
            if not text:
                sep.top = y + h // 2
                surf.fill(colors[0], sep)
            else:
                if item is hilited:
                    rect = surf.get_rect()
                    rect.top = y
                    rect.height = h
                    if self.scrolling:
                        rect.width -= xt + self.scroll_button_size
                    surf.fill(colors[1], rect)
                    color = bg
                else:
                    color = colors[item.enabled]
                buf = font.render(item.text, True, color)
                surf.blit(buf, (xt, y))
                keyname = item.keyname
                if keyname:
                    buf = font.render(keyname, True, color)
                    surf.blit(buf, (xk, y))
            y += h
        if self.scrolling:
            if self.can_scroll_up():
                self.draw_scroll_up_button(surf)
            if self.can_scroll_down():
                self.draw_scroll_down_button(surf)

    def draw_scroll_up_button(self, surface):
        r = self.scroll_up_rect()
        c = self.scroll_button_color
        draw.polygon(surface, c, [r.bottomleft, r.midtop, r.bottomright])

    def draw_scroll_down_button(self, surface):
        r = self.scroll_down_rect()
        c = self.scroll_button_color
        draw.polygon(surface, c, [r.topleft, r.midbottom, r.topright])

    def mouse_move(self, e):
        self.mouse_drag(e)

    def mouse_drag(self, e):
        item = self.find_enabled_item(e)
        if item is not self._hilited:
            self._hilited = item
            self.invalidate()

    def mouse_up(self, e):
        if 1 <= e.button <= 3:
            item = self.find_enabled_item(e)
            if item:
                self.dismiss(self._items.index(item))

    def find_enabled_item(self, e):
        x, y = e.local
        if 0 <= x < (self.width - self.margin - self.scroll_button_size
                     if self.scrolling else self.width):
            h = self.font.get_linesize()
            i = (y - h // 2) // h + self.scroll
            items = self._items
            if 0 <= i < len(items):
                item = items[i]
                if item.enabled:
                    return item

    def mouse_down(self, event):
        if event.button == 1:
            if self.scrolling:
                p = event.local
                if self.scroll_up_rect().collidepoint(p):
                    self.scroll_up()
                    return
                elif self.scroll_down_rect().collidepoint(p):
                    self.scroll_down()
                    return
        if event.button == 4:
            self.scroll_up()
        if event.button == 5:
            self.scroll_down()

        Dialog.mouse_down(self, event)

    def scroll_up(self):
        if self.can_scroll_up():
            self.scroll = max(self.scroll - self.scroll_page, 0)

    def scroll_down(self):
        if self.can_scroll_down():
            self.scroll = min(self.scroll + self.scroll_page,
                              len(self._items) - self.scroll_items)

    def can_scroll_up(self):
        return self.scrolling and self.scroll > 0

    def can_scroll_down(self):
        return (self.scrolling
                and self.scroll + self.scroll_items < len(self._items))

    def find_item_for_key(self, e):
        for item in self._items:
            if item.keycode == e.key \
                    and item.shift == e.shift and item.alt == e.alt:
                focus = get_focus()
                if self.command_is_enabled(item, focus):
                    return self._items.index(item)
                else:
                    return -1
        return -1

    def get_command(self, i):
        if i >= 0:
            item = self._items[i]
            cmd = item.command
            if cmd:
                return cmd + '_cmd'

    def invoke_item(self, i):
        cmd = self.get_command(i)
        if cmd:
            get_focus().handle_command(cmd)
Exemple #13
0
class Menu(Dialog):
    disabled_color = ThemeProperty('disabled_color')
    click_outside_response = -1
    scroll_button_size = ThemeProperty('scroll_button_size')
    scroll_button_color = ThemeProperty('scroll_button_color')
    scroll = 0

    def __init__(self,
                 title,
                 items,
                 scrolling=False,
                 scroll_items=30,
                 scroll_page=5,
                 handler=None,
                 **kwds):
        self.handler = handler
        self.title = _(title, doNotTranslate=kwds.get('doNotTranslate', False))
        self.items = items
        self._items = [
            MenuItem(*item, doNotTranslate=kwds.get('doNotTranslate', False))
            for item in items
        ]
        self.scrolling = scrolling and len(self._items) > scroll_items
        self.scroll_items = scroll_items
        self.scroll_page = scroll_page

        if __builtins__.get("mcenf_tab_to_next"):
            self._selected_item_index = 0
            self._hilited = self._items[self._selected_item_index]

        Dialog.__init__(self, **kwds)

        self.root = self.get_root()
        self.calc_size()

    #&#
    def set_items(self, items):
        self.items = items
        self._items = [
            MenuItem(*item, doNotTranslate=self.doNotTranslate)
            for item in items
        ]

    def set_scroll_items(self, scroll_items):
        if scroll_items < len(self.items):
            self.scroll_items = scroll_items
        else:
            self.scroll_items = len(self.items)
        self.calc_size()

    #&#

    def calc_size(self):
        h = self.font.get_linesize()
        if self.scrolling:
            self.height = h * self.scroll_items + h
        else:
            self.height = h * len(self._items) + h

    def set_update_ui(self, v):
        if v:
            self._items = [
                MenuItem(*item, doNotTranslate=self.doNotTranslate)
                for item in self.items
            ]
        Dialog.set_update_ui(self, v)

    def present(self, client, pos):
        client = client or self.root
        self.topleft = client.local_to_global(pos)
        focus = self.handler or get_focus()
        font = self.font
        h = font.get_linesize()
        items = self._items
        margin = self.margin
        if self.scrolling:
            height = h * self.scroll_items + h
        else:
            height = h * len(items) + h
        w1 = w2 = 0
        for item in items:
            item.enabled = self.command_is_enabled(item, focus)
            w1 = max(w1, font.size(item.text)[0])
            w2 = max(w2, font.size(item.keyname)[0])
        width = w1 + 2 * margin
        self._key_margin = width
        if w2 > 0:
            width += w2 + margin
        if self.scrolling:
            width += self.scroll_button_size
        self.size = (width, height)
        if not __builtins__.get("mcenf_tab_to_next"):
            self._hilited = None

        self.rect.clamp_ip(self.root.rect)

        return Dialog.present(self, centered=False)

    @staticmethod
    def command_is_enabled(item, focus):
        cmd = item.command
        if cmd:
            enabler_name = cmd + '_enabled'
            handler = focus
            while handler:
                enabler = getattr(handler, enabler_name, None)
                if enabler:
                    return enabler()
                handler = handler.next_handler()
        return True

    def scroll_up_rect(self):
        d = self.scroll_button_size
        r = Rect(0, 0, d, d)
        m = self.margin
        r.top = m
        r.right = self.width - m
        r.inflate_ip(-4, -4)
        return r

    def scroll_down_rect(self):
        d = self.scroll_button_size
        r = Rect(0, 0, d, d)
        m = self.margin
        r.bottom = self.height - m
        r.right = self.width - m
        r.inflate_ip(-4, -4)
        return r

    def draw(self, surf):
        font = self.font
        h = font.get_linesize()
        sep = surf.get_rect()
        sep.height = 1
        if self.scrolling:
            sep.width -= self.margin + self.scroll_button_size
        colors = [self.disabled_color, self.fg_color]
        bg = self.bg_color
        xt = self.margin
        xk = self._key_margin
        y = h // 2
        hilited = self._hilited
        if self.scrolling:
            items = self._items[self.scroll:self.scroll + self.scroll_items]
        else:
            items = self._items
        for item in items:
            text = item.text
            if not text:
                sep.top = y + h // 2
                surf.fill(colors[0], sep)
            else:
                if item is hilited:
                    rect = surf.get_rect()
                    rect.top = y
                    rect.height = h
                    if self.scrolling:
                        rect.width -= xt + self.scroll_button_size
                    surf.fill(colors[1], rect)
                    color = bg
                else:
                    color = colors[item.enabled]
                buf = font.render(item.text, True, color)
                surf.blit(buf, (xt, y))
                keyname = item.keyname
                if keyname:
                    buf = font.render(keyname, True, color)
                    surf.blit(buf, (xk, y))
            y += h
        if self.scrolling:
            if self.can_scroll_up():
                self.draw_scroll_up_button(surf)
            if self.can_scroll_down():
                self.draw_scroll_down_button(surf)

    def draw_scroll_up_button(self, surface):
        r = self.scroll_up_rect()
        c = self.scroll_button_color
        draw.polygon(surface, c, [r.bottomleft, r.midtop, r.bottomright])

    def draw_scroll_down_button(self, surface):
        r = self.scroll_down_rect()
        c = self.scroll_button_color
        draw.polygon(surface, c, [r.topleft, r.midbottom, r.topright])

    def mouse_move(self, e):
        self.mouse_drag(e)

    def mouse_drag(self, e):
        item = self.find_enabled_item(e)
        if item is not self._hilited:
            self._hilited = item
            self.invalidate()

            if __builtins__.get("mcenf_tab_to_next"):
                if item:
                    self._selected_item_index = self._items.index(item)

    def mouse_up(self, e):
        if 1 <= e.button <= 3:
            item = self.find_enabled_item(e)
            if item:
                self.dismiss(self._items.index(item))

    def find_enabled_item(self, e):
        x, y = e.local
        if 0 <= x < (self.width - self.margin - self.scroll_button_size
                     if self.scrolling else self.width):
            h = self.font.get_linesize()
            i = (y - h // 2) // h + self.scroll
            items = self._items
            if 0 <= i < len(items):
                item = items[i]
                if item.enabled:
                    return item

    def mouse_down(self, event):
        if event.button == 1:
            if self.scrolling:
                p = event.local
                if self.scroll_up_rect().collidepoint(p):
                    self.scroll_up()
                    return
                elif self.scroll_down_rect().collidepoint(p):
                    self.scroll_down()
                    return
        if event.button == 4:
            self.scroll_up()
        if event.button == 5:
            self.scroll_down()

        Dialog.mouse_down(self, event)

    def scroll_up(self):
        if self.can_scroll_up():
            self.scroll = max(self.scroll - self.scroll_page, 0)

    def scroll_down(self):
        if self.can_scroll_down():
            self.scroll = min(self.scroll + self.scroll_page,
                              len(self._items) - self.scroll_items)

    def can_scroll_up(self):
        return self.scrolling and self.scroll > 0

    def can_scroll_down(self):
        return (self.scrolling
                and self.scroll + self.scroll_items < len(self._items))

    def find_item_for_key(self, e):
        for item in self._items:
            if item.keycode == e.key \
                    and item.shift == e.shift and item.alt == e.alt:
                focus = get_focus()
                if self.command_is_enabled(item, focus):
                    return self._items.index(item)
                else:
                    return -1
        return -1

    def get_command(self, i):
        if i >= 0:
            item = self._items[i]
            cmd = item.command
            if cmd:
                return cmd + '_cmd'

    def invoke_item(self, i):
        cmd = self.get_command(i)
        if cmd:
            get_focus().handle_command(cmd)

    if __builtins__.get("mcenf_tab_to_next"):

        def key_down(self, event):
            """Handles key presses to select and activate menu items or dismiss it.
            :param event: object: The event to be processed."""
            key = self.root.getKey(event)
            last_index = len(self._items) - 1

            # Just define a dummy method when scrolling is not necessary.
            def _x(*args, **kwargs):
                """..."""
                pass

            def page_up_down(*args, **kwargs):
                """Triggers scroll alignment to see the selected item on page up/down event."""
                self.scroll = min(self._selected_item_index,
                                  last_index - self.scroll_items + 1)

            view_meth = _x
            if key == "Up":
                if self._selected_item_index == 0:
                    self._selected_item_index = last_index
                    self.scroll = last_index - self.scroll_items + 1
                else:
                    self._selected_item_index -= 1
                    view_meth = self.scroll_up
            elif key == "Down":
                if self._selected_item_index == last_index:
                    self._selected_item_index = 0
                    self.scroll = 0
                else:
                    self._selected_item_index += 1
                    view_meth = self.scroll_down
            elif key == "Page up":
                self._selected_item_index = max(
                    0, self._selected_item_index - self.scroll_items)
                view_meth = page_up_down
            elif key == "Page down":
                self._selected_item_index = min(
                    last_index, self._selected_item_index + self.scroll_items)
                view_meth = page_up_down
            elif key in ("Return", "Enter", "Space"):
                self.dismiss(self._selected_item_index)
            elif key == "Escape":
                self.dismiss(False)
            else:
                Dialog.key_down(self, event)

            self._hilited = self._items[self._selected_item_index]

            # Ensure the selected item is visible by scrollign accordingly
            if self._hilited not in self._items[self.scroll:self.scroll +
                                                self.scroll_items]:
                view_meth()
Exemple #14
0
class PaletteView(GridView):
    # nrows   int   No. of displayed rows
    #  ncols   int   No. of displayed columns
    #
    #  Abstract methods:
    #
    #    num_items()  -->  no. of items
    #    draw_item(surface, item_no, rect)
    #    click_item(item_no, event)
    #    item_is_selected(item_no)  -->  bool

    sel_width = ThemeProperty('sel_width')
    zebra_color = ThemeProperty('zebra_color')
    scroll_button_size = ThemeProperty('scroll_button_size')
    scroll_button_color = ThemeProperty('scroll_button_color')
    highlight_style = ThemeProperty('highlight_style')

    # 'frame' or 'fill' or 'reverse' or None

    def __init__(self, cell_size, nrows, ncols, scrolling=False, **kwds):
        GridView.__init__(self, cell_size, nrows, ncols, **kwds)
        self.scrolling = scrolling
        if scrolling:
            d = self.scroll_button_size
            #l = self.width
            #b = self.height
            self.width += d
            #self.scroll_up_rect = Rect(l, 0, d, d).inflate(-4, -4)
            #self.scroll_down_rect = Rect(l, b - d, d, d).inflate(-4, -4)
        self.scroll = 0

    def scroll_up_rect(self):
        d = self.scroll_button_size
        r = Rect(0, 0, d, d)
        m = self.margin
        r.top = m
        r.right = self.width - m
        r.inflate_ip(-4, -4)
        return r

    def scroll_down_rect(self):
        d = self.scroll_button_size
        r = Rect(0, 0, d, d)
        m = self.margin
        r.bottom = self.height - m
        r.right = self.width - m
        r.inflate_ip(-4, -4)
        return r

    def draw(self, surface):

        GridView.draw(self, surface)
        if self.can_scroll_up():
            self.draw_scroll_up_button(surface)
        if self.can_scroll_down():
            self.draw_scroll_down_button(surface)

    def draw_scroll_up_button(self, surface):
        r = self.scroll_up_rect()
        c = self.scroll_button_color
        draw.polygon(surface, c, [r.bottomleft, r.midtop, r.bottomright])

    def draw_scroll_down_button(self, surface):
        r = self.scroll_down_rect()
        c = self.scroll_button_color
        draw.polygon(surface, c, [r.topleft, r.midbottom, r.topright])

    def draw_cell(self, surface, row, col, rect):
        i = self.cell_to_item_no(row, col)
        if i is not None:
            highlight = self.item_is_selected(i)
            self.draw_item_and_highlight(surface, i, rect, highlight)

    def draw_item_and_highlight(self, surface, i, rect, highlight):
        if i % 2:
            surface.fill(self.zebra_color, rect)
        if highlight:
            self.draw_prehighlight(surface, i, rect)
        if highlight and self.highlight_style == 'reverse':
            fg = self.inherited('bg_color') or self.sel_color
        else:
            fg = self.fg_color
        self.draw_item_with(surface, i, rect, fg)
        if highlight:
            self.draw_posthighlight(surface, i, rect)

    def draw_item_with(self, surface, i, rect, fg):
        old_fg = self.fg_color
        self.fg_color = fg
        try:
            self.draw_item(surface, i, rect)
        finally:
            self.fg_color = old_fg

    def draw_prehighlight(self, surface, i, rect):
        if self.highlight_style == 'reverse':
            color = self.fg_color
        else:
            color = self.sel_color
        self.draw_prehighlight_with(surface, i, rect, color)

    def draw_prehighlight_with(self, surface, i, rect, color):
        style = self.highlight_style
        if style == 'frame':
            frame_rect(surface, color, rect, self.sel_width)
        elif style == 'fill' or style == 'reverse':
            surface.fill(color, rect)

    def draw_posthighlight(self, surface, i, rect):
        pass

    def mouse_down(self, event):
        if event.button == 1:
            if self.scrolling:
                p = event.local
                if self.scroll_up_rect().collidepoint(p):
                    self.scroll_up()
                    return
                elif self.scroll_down_rect().collidepoint(p):
                    self.scroll_down()
                    return
        if event.button == 4:
            self.scroll_up()
        if event.button == 5:
            self.scroll_down()

        GridView.mouse_down(self, event)

    def scroll_up(self):
        if self.can_scroll_up():
            self.scroll -= self.items_per_page() / 2

    def scroll_down(self):
        if self.can_scroll_down():
            self.scroll += self.items_per_page() / 2

    def scroll_to_item(self, n):
        i = max(0, min(n, self.num_items() - 1))
        p = self.items_per_page()
        self.scroll = p * (i // p)

    def can_scroll_up(self):
        return self.scrolling and self.scroll > 0

    def can_scroll_down(self):
        return self.scrolling and self.scroll + self.items_per_page(
        ) < self.num_items()

    def items_per_page(self):
        return self.num_rows() * self.num_cols()

    def click_cell(self, row, col, event):
        i = self.cell_to_item_no(row, col)
        if i is not None:
            self.click_item(i, event)

    def cell_to_item_no(self, row, col):
        i = self.scroll + row * self.num_cols() + col
        if 0 <= i < self.num_items():
            return i
        else:
            return None

    def num_rows(self):
        ch = self.cell_size[1]
        if ch:
            return self.height // ch
        else:
            return 0

    def num_cols(self):
        width = self.width
        if self.scrolling:
            width -= self.scroll_button_size
        cw = self.cell_size[0]
        if cw:
            return width // cw
        else:
            return 0

    def item_is_selected(self, n):
        return False

    def click_item(self, n, e):
        pass
class Label(Widget):
    text = overridable_property('text')
    align = overridable_property('align')

    hover_color = ThemeProperty('hover_color')
    highlight_color = ThemeProperty('highlight_color')
    disabled_color = ThemeProperty('disabled_color')
    highlight_bg_color = ThemeProperty('highlight_bg_color')
    hover_bg_color = ThemeProperty('hover_bg_color')
    enabled_bg_color = ThemeProperty('enabled_bg_color')
    disabled_bg_color = ThemeProperty('disabled_bg_color')

    enabled = True
    highlighted = False
    _align = 'l'

    def __init__(self, text, width=None, **kwds):
        Widget.__init__(self, **kwds)
        font = self.font
        text = _(text, doNotTranslate=kwds.get('doNotTranslate', False))
        lines = text.split("\n")
        tw, th = 0, 0
        for line in lines:
            w, h = font.size(line)
            tw = max(tw, w)
            th += h
        if width is not None:
            tw = width
        else:
            tw = max(1, tw)
        d = 2 * self.margin
        self.size = (tw + d, th + d)
        self._text = text

    def __repr__(self):
        return "Label {0}, child of {1}".format(self.text, self.parent)

    def get_text(self):
        return self._text

    def set_text(self, x):
        self._text = _(x)

    def get_align(self):
        return self._align

    def set_align(self, x):
        self._align = x

    def draw(self, surface):
        if not self.enabled:
            fg = self.disabled_color
            bg = self.disabled_bg_color
        else:
            fg = self.fg_color
            bg = self.enabled_bg_color
            if self.is_default:
                fg = self.default_choice_color or fg
                bg = self.default_choice_bg_color or bg
            if self.is_hover:
                fg = self.hover_color or fg
                bg = self.hover_bg_color or bg
            if self.highlighted:
                fg = self.highlight_color or fg
                bg = self.highlight_bg_color or bg

        self.draw_with(surface, fg, bg)

    is_default = False

    def draw_with(self, surface, fg, bg=None):
        if bg:
            r = surface.get_rect()
            b = self.border_width
            if b:
                e = -2 * b
                r.inflate_ip(e, e)
            surface.fill(bg, r)
        m = self.margin
        align = self.align
        width = surface.get_width()
        y = m
        lines = self.text.split("\n")
        font = self.font
        dy = font.get_linesize()
        for line in lines:
            if len(line):
                size = font.size(line)
                if size[0] == 0:
                    continue

                image = font.render(line, True, fg)
                r = image.get_rect()
                r.top = y
                if align == 'l':
                    r.left = m
                elif align == 'r':
                    r.right = width - m
                else:
                    r.centerx = width // 2
                surface.blit(image, r)
            y += dy
Exemple #16
0
class Label(Widget):
    text = overridable_property('text')
    align = overridable_property('align')

    highlight_color = ThemeProperty('highlight_color')
    disabled_color = ThemeProperty('disabled_color')
    highlight_bg_color = ThemeProperty('highlight_bg_color')
    enabled_bg_color = ThemeProperty('enabled_bg_color')
    disabled_bg_color = ThemeProperty('disabled_bg_color')
    
    enabled = True
    highlighted = False
    _align = 'l'
    
    def __init__(self, text, width = None, **kwds):
        Widget.__init__(self, **kwds)
        font = self.font
        self.set_text(text)
        return
    
        lines = text.split("\n")
        tw, th = 0, 0
        for line in lines:
            w, h = font.size(line)
            tw = max(tw, w)
            th += h
        if width is not None:
            tw = width
        else:
            tw = max(1, tw)
        d = 2 * self.margin
        self.size = (tw + d, th + d)
        self._text = text
    
    
    def get_text(self):
        return self._text
    
    def _render_image(self):
        '''
        Render image to be blited on draw
        '''
        line_height = self.font.get_linesize()
        lines = self._text.split("\n")
        fg = self.fg_color
        bg = self.bg_color
        line_images = []
        line_width = 0
        for line in lines:
            print bg
            img = self.font.render(line, True, fg)
            line_width = max(line_width, img.get_width())
            line_images.append(img)
        space = self.border_width + self.margin
        self.width = 2*space + line_width
        self.height = 2*space + len(line_images)*line_height
        self._image = pygame.Surface(self.size)
        if bg:
            self._image.fill()
        dest = pygame.Rect((0,0),(self.width,line_height))
        for img in line_images:
            dest.width = img.get_width()
            if self.align=='c':
                dest.centerx = self.width/2
            elif self.align=='r':
                dest.right = self.width
#            else:
#                dest.left = 0
            # blit it
            self._image.blit(img, dest)
            dest.top += dest.height
            
            
    
    def set_text(self, text):
        self._text = text
        self._render_image()
    
    
    def get_align(self):
        return self._align
    
    def set_align(self, x):
        self._align = x
        self._render_image()

    def draw(self, surface):
        surface.blit(self._image, self.rect)


    def draw_with(self, surface, fg, bg = None):
        if bg:
            r = surface.get_rect()
            b = self.border_width
            if b:
                e = - 2 * b
                r.inflate_ip(e, e)
            surface.fill(bg, r)
        m = self.margin
        align = self.align
        width = surface.get_width()
        y = m
        lines = self.text.split("\n")
        font = self.font
        dy = font.get_linesize()
        for line in lines:
            image = font.render(line, True, fg)
            r = image.get_rect()
            r.top = y
            if align == 'l':
                r.left = m
            elif align == 'r':
                r.right = width - m
            else:
                r.centerx = width // 2
            surface.blit(image, r)
            y += dy
Exemple #17
0
class Label(Widget):

	text = overridable_property('text')
	align = overridable_property('align')

	highlight_color = ThemeProperty('highlight_color')
	disabled_color = ThemeProperty('disabled_color')
	highlight_bg_color = ThemeProperty('highlight_bg_color')
	enabled_bg_color = ThemeProperty('enabled_bg_color')
	disabled_bg_color = ThemeProperty('disabled_bg_color')
	
	enabled = True
	highlighted = False
	_align = 'l'
	
	def __init__(self, text, width = None, **kwds):
		Widget.__init__(self, **kwds)
		font = self.font
		lines = text.split("\n")
		tw, th = 0, 0
		for line in lines:
			w, h = font.size(line)
			tw = max(tw, w)
			th += h
		if width is not None:
			tw = width
		else:
			tw = max(1, tw)
		d = 2 * self.margin
		self.size = (tw + d, th + d)
		self._text = text
	
	def get_text(self):
		return self._text
	
	def set_text(self, x):
		self._text = x
	
	def get_align(self):
		return self._align
	
	def set_align(self, x):
		self._align = x

	def draw(self, surface):
		if not self.enabled:
			fg = self.disabled_color
			bg = self.disabled_bg_color
		elif self.highlighted:
			fg = self.highlight_color
			bg = self.highlight_bg_color
		else:
			fg = self.fg_color
			bg = self.enabled_bg_color
		self.draw_with(surface, fg, bg)

	def draw_with(self, surface, fg, bg = None):
		if bg:
			r = surface.get_rect()
			b = self.border_width
			if b:
				e = - 2 * b
				r.inflate_ip(e, e)
			surface.fill(bg, r)
		m = self.margin
		align = self.align
		width = surface.get_width()
		y = m
		lines = self.text.split("\n")
		font = self.font
		dy = font.get_linesize()
		for line in lines:
			image = font.render(line, True, fg)
			r = image.get_rect()
			r.top = y
			if align == 'l':
				r.left = m
			elif align == 'r':
				r.right = width - m
			else:
				r.centerx = width // 2
			surface.blit(image, r)
			y += dy
Exemple #18
0
class Menu(Dialog):

    disabled_color = ThemeProperty('disabled_color')
    click_outside_response = -1

    def __init__(self, title, items, **kwds):
        self.title = title
        self.items = items
        self._items = [MenuItem(*item) for item in items]
        Dialog.__init__(self, **kwds)

    def present(self, client, pos):
        client = client or get_root()
        self.topleft = client.local_to_global(pos)
        focus = get_focus()
        font = self.font
        h = font.get_linesize()
        items = self._items
        margin = self.margin
        height = h * len(items) + h
        w1 = w2 = 0
        for item in items:
            item.enabled = self.command_is_enabled(item, focus)
            w1 = max(w1, font.size(item.text)[0])
            w2 = max(w2, font.size(item.keyname)[0])
        width = w1 + 2 * margin
        self._key_margin = width
        if w2 > 0:
            width += w2 + margin
        self.size = (width, height)
        self._hilited = None
        return Dialog.present(self, centered=False)

    def command_is_enabled(self, item, focus):
        cmd = item.command
        if cmd:
            enabler_name = cmd + '_enabled'
            handler = focus
            while handler:
                enabler = getattr(handler, enabler_name, None)
                if enabler:
                    return enabler()
                handler = handler.next_handler()
        return True

    def draw(self, surf):
        font = self.font
        h = font.get_linesize()
        sep = surf.get_rect()
        sep.height = 1
        colors = [self.disabled_color, self.fg_color]
        bg = self.bg_color
        xt = self.margin
        xk = self._key_margin
        y = h // 2
        hilited = self._hilited
        for item in self._items:
            text = item.text
            if not text:
                sep.top = y + h // 2
                surf.fill(colors[0], sep)
            else:
                if item is hilited:
                    rect = surf.get_rect()
                    rect.top = y
                    rect.height = h
                    surf.fill(colors[1], rect)
                    color = bg
                else:
                    color = colors[item.enabled]
                buf = font.render(item.text, True, color)
                surf.blit(buf, (xt, y))
                keyname = item.keyname
                if keyname:
                    buf = font.render(keyname, True, color)
                    surf.blit(buf, (xk, y))
            y += h

    def mouse_move(self, e):
        self.mouse_drag(e)

    def mouse_drag(self, e):
        item = self.find_enabled_item(e)
        if item is not self._hilited:
            self._hilited = item
            self.invalidate()

    def mouse_up(self, e):
        item = self.find_enabled_item(e)
        if item:
            self.dismiss(self._items.index(item))

    def find_enabled_item(self, e):
        x, y = e.local
        if 0 <= x < self.width:
            h = self.font.get_linesize()
            i = (y - h // 2) // h
            items = self._items
            if 0 <= i < len(items):
                item = items[i]
                if item.enabled:
                    return item

    def find_item_for_key(self, e):
        for item in self._items:
            if item.keycode == e.key \
             and item.shift == e.shift and item.alt == e.alt:
                focus = get_focus()
                if self.command_is_enabled(item, focus):
                    return self._items.index(item)
                else:
                    return -1
        return -1

    def get_command(self, i):
        if i >= 0:
            item = self._items[i]
            cmd = item.command
            if cmd:
                return cmd + '_cmd'

    def invoke_item(self, i):
        cmd = self.get_command(i)
        if cmd:
            get_focus().handle_command(cmd)
Exemple #19
0
class Tree(Column):
    """..."""
    rows = []
    row_margin = 2
    column_margin = 2
    bullet_size = ThemeProperty('bullet_size')
    bullet_color_active = ThemeProperty('bullet_color_active')
    bullet_color_inactive = ThemeProperty('bullet_color_inactive')

    def __init__(self, *args, **kwargs):
        self.menu = [("Add", "add_item"),
                     ("Delete", "delete_item"),
                     ("New child", "add_child"),
                     ("Rename", "rename_item"),
                     ]
        self.selected_item_index = None
        self.selected_item = None
        self._parent = kwargs.pop('_parent', None)
        self.styles = kwargs.pop('styles', {})
        self.compound_types = [dict,] + kwargs.pop('compound_types', [])
        self.show_fields = kwargs.pop('show_fields', False)
        self.deployed = []
        self.data = data = kwargs.pop("data", {})
        self.draw_zebra = draw_zebra = kwargs.pop('draw_zebra', True)
#        self.inner_width = kwargs.pop('inner_width', 'auto')
        self.inner_width = kwargs.pop('inner_width', 500)
        self.__num_rows = len(data.keys())
        self.build_layout()
        row_height = self.font.size(' ')[1]
        self.treeRow = treeRow = TreeRow((self.inner_width, row_height), 10, draw_zebra=draw_zebra)
        Column.__init__(self, [treeRow,], **kwargs)

    def add_item(self):
        print "add_item"

    def add_child(self):
        print "add_child"

    def delete_item(self):
        print "delete_item"

    def rename_item(self):
        print "rename_item"

    def show_menu(self, pos):
        if self.menu and self.selected_item_index:
            m = Menu("Menu", self.menu)
            i = m.present(self, pos)
            if i > -1:
                meth = getattr(self, self.menu[i][1], None)
                if meth:
                    meth()

    def build_layout(self):
        data = self.data
        parent = 0
        children = []
        keys = data.keys()
        keys.sort()
        items = [[0, a, data[a], parent, children, keys.index(a) + 1] for a in keys]
        rows = []
        w = 50
        aId = len(items) + 1
        while items:
            lvl, k, v, p, c, id = items.pop(0)
            _c = False
            fields = []
            if type(v) in self.compound_types:
                meth = getattr(self, 'parse_%s'%v.__class__.__name__, None)
                if meth is not None:
                    v = meth(k, v)
                ks = v.keys()
                ks.sort()
                ks.reverse()
                for a in ks:
                    b = v[a]
                    if id in self.deployed:
                        itm = [lvl + 1, a, b, id, [], aId]
                        items.insert(0, itm)
                        c.append(aId)
                    _c = True
                    aId += 1
            else:
                if type(v) in (list, tuple):
                    fields = v
                elif type(v) not in self.compound_types or hasattr(self._parent, 'build_%s'%k.lower()):
                    fields = [v,]
            head = Surface((self.bullet_size * (lvl + 1) + self.font.size(k)[0], self.bullet_size), SRCALPHA)
            if _c:
                meth = getattr(self, 'draw_%s_bullet'%{False: 'closed', True: 'opened'}[id in self.deployed])
            else:
                meth = getattr(self, 'draw_%s_bullet'%v.__class__.__name__, None)
                if not meth:
                    meth = self.draw_deadend_bullet
            bg, fg, shape, text = self.styles.get(type(v),
                                                  ({True: self.bullet_color_active, False: self.bullet_color_inactive}[_c],
                                                   self.fg_color, 'square', ''),
                                                 )
            meth(head, bg, fg, shape, text, k, lvl)
            rows.append([head, fields, [w] * len(fields), k, p, c, id, type(v), lvl])
        self.rows = rows

    def deploy(self, id):
            if id in self.deployed:
                self.deployed.remove(id)
            else:
                self.deployed.append(id)
            self.build_layout()

    def click_item(self, n, pos):
        """..."""
        row = self.rows[n]
        r = self.get_bullet_rect(row[0], row[8])
        x = pos[0]
        if self.margin + r.left - self.treeRow.hscroll <= x <= self.margin + self.treeRow.margin + r.right - self.treeRow.hscroll:
            id = row[6]
            self.deploy(id)
        else:
            self.select_item(n)

    def select_item(self, n):
        self.selected_item_index = n
        self.selected_item = self.rows[n]

    def get_bullet_rect(self, surf, lvl):
        r = Rect(0, 0, self.bullet_size, self.bullet_size)
        r.left = self.bullet_size * lvl
        r.inflate_ip(-4, -4)
        return r

    def draw_item_text(self, surf, r, text):
        buf = self.font.render(unicode(text), True, self.fg_color)
        blit_in_rect(surf, buf, Rect(r.right, r.top, surf.get_width() - r.right, r.height), 'c')

    def draw_deadend_bullet(self, surf, bg, fg, shape, text, item_text, lvl):
        r = self.get_bullet_rect(surf, lvl)
        draw.polygon(surf, bg, [r.midtop, r.midright, r.midbottom, r.midleft])
        self.draw_item_text(surf, r, item_text)

    def draw_closed_bullet(self, surf, bg, fg, shape, text, item_text, lvl):
        r = self.get_bullet_rect(surf, lvl)
        draw.polygon(surf, bg, [r.topleft, r.midright, r.bottomleft])
        self.draw_item_text(surf, r, item_text)

    def draw_opened_bullet(self, surf, bg, fg, shape, text, item_text, lvl):
        r = self.get_bullet_rect(surf, lvl)
        draw.polygon(surf, bg, [r.topleft, r.midbottom, r.topright])
        self.draw_item_text(surf, r, item_text)

    def draw_tree_cell(self, surf, i, data, cell_rect, column):
        """..."""
        if type(data) in (str, unicode):
            self.draw_text_cell(surf, i, data, cell_rect, 'l', self.font)
        else:
            self.draw_image_cell(surf, i, data, cell_rect, column)

    @staticmethod
    def draw_image_cell(surf, i, data, cell_rect, column):
        """..."""
        blit_in_rect(surf, data, cell_rect, 'l')

    def draw_text_cell(self, surf, i, data, cell_rect, align, font):
        buf = font.render(unicode(data), True, self.fg_color)
        blit_in_rect(surf, buf, cell_rect, align)

    def num_rows(self):
        return len(self.rows)

    def row_data(self, row):
        return self.rows[row]

    def column_info(self, row_data):
        m = self.column_margin
        d = 2 * m
        x = 0
        for i in range(0,2):
            if i < 1:
                width = self.width
                data = row_data[i]
                yield i, x + m, width - d, None, data
                x += width
        if self.show_fields:
            for i in range(len(row_data[2])):
                width = 50 * (i + 1)
                data = row_data[2][i]
                if type(data) != (str, unicode):
                    data = repr(data)
                yield i, x + m, width - d, None, data
                x += width
Exemple #20
0
class Widget(object):
    #  rect            Rect       bounds in parent's coordinates
    #  parent          Widget     containing widget
    #  subwidgets      [Widget]   contained widgets
    #  focus_switch    Widget     subwidget to receive key events
    #  fg_color        color      or None to inherit from parent
    #  bg_color        color      to fill background, or None
    #  visible         boolean
    #  border_width    int        width of border to draw around widget, or None
    #  border_color    color      or None to use widget foreground color
    #  tab_stop        boolean    stop on this widget when tabbing
    #  anchor          string     of 'ltrb'

    font = FontProperty('font')
    fg_color = ThemeProperty('fg_color')
    bg_color = ThemeProperty('bg_color')
    bg_image = ThemeProperty('bg_image')
    scale_bg = ThemeProperty('scale_bg')
    border_width = ThemeProperty('border_width')
    border_color = ThemeProperty('border_color')
    sel_color = ThemeProperty('sel_color')
    margin = ThemeProperty('margin')
    menu_bar = overridable_property('menu_bar')
    is_gl_container = overridable_property('is_gl_container')

    tab_stop = False
    enter_response = None
    cancel_response = None
    anchor = 'ltwh'
    debug_resize = False
    _menubar = None
    _visible = True
    _is_gl_container = False
    redraw_every_event = True

    tooltip = None
    tooltipText = None
    doNotTranslate = False

    def __init__(self, rect=None, **kwds):
        if rect and not isinstance(rect, Rect):
            raise TypeError("Widget rect not a pygame.Rect")
        self._rect = Rect(rect or (0, 0, 100, 100))
        self.parent = None
        self.subwidgets = []
        self.focus_switch = None
        self.is_modal = False
        self.set(**kwds)
        self.root = self.get_root()

    def set(self, **kwds):
        for name, value in kwds.iteritems():
            if not hasattr(self, name):
                raise TypeError("Unexpected keyword argument '%s'" % name)
            setattr(self, name, value)

    def get_rect(self):
        return self._rect

    def set_rect(self, x):
        old_size = self._rect.size
        self._rect = Rect(x)
        self._resized(old_size)

    #    def get_anchor(self):
    #        if self.hstretch:
    #            chars ='lr'
    #        elif self.hmove:
    #            chars = 'r'
    #        else:
    #            chars = 'l'
    #        if self.vstretch:
    #            chars += 'tb'
    #        elif self.vmove:
    #            chars += 'b'
    #        else:
    #            chars += 't'
    #        return chars
    #
    #    def set_anchor(self, chars):
    #        self.hmove = 'r' in chars and not 'l' in chars
    #        self.vmove = 'b' in chars and not 't' in chars
    #        self.hstretch = 'r' in chars and 'l' in chars
    #        self.vstretch = 'b' in chars and 't' in chars
    #
    #    anchor = property(get_anchor, set_anchor)

    resizing_axes = {'h': 'lr', 'v': 'tb'}
    resizing_values = {'': [0], 'm': [1], 's': [0, 1]}

    def set_resizing(self, axis, value):
        chars = self.resizing_axes[axis]
        anchor = self.anchor
        for c in chars:
            anchor = anchor.replace(c, '')
        for i in self.resizing_values[value]:
            anchor += chars[i]
        self.anchor = anchor + value

    def _resized(self, (old_width, old_height)):
        new_width, new_height = self._rect.size
        dw = new_width - old_width
        dh = new_height - old_height
        if dw or dh:
            self.resized(dw, dh)
Exemple #21
0
class TabPanel(Widget):
    #  pages         [Widget]
    #  current_page  Widget

    tab_font = FontProperty('tab_font')
    tab_height = ThemeProperty('tab_height')
    tab_border_width = ThemeProperty('tab_border_width')
    tab_spacing = ThemeProperty('tab_spacing')
    tab_margin = ThemeProperty('tab_margin')
    tab_fg_color = ThemeProperty('tab_fg_color')
    default_tab_bg_color = ThemeProperty('default_tab_bg_color')
    tab_area_bg_color = ThemeProperty('tab_area_bg_color')
    tab_dimming = ThemeProperty('tab_dimming')

    #use_page_bg_color_for_tabs = ThemeProperty('use_page_bg_color_for_tabs')

    def __init__(self, pages=None, **kwds):
        Widget.__init__(self, **kwds)
        self.pages = []
        self.current_page = None
        if pages:
            w = h = 0
            for title, page in pages:
                w = max(w, page.width)
                h = max(h, page.height)
                self._add_page(title, page)
            self.size = (w, h)
            self.show_page(pages[0][1])

    def content_size(self):
        return (self.width, self.height - self.tab_height)

    def content_rect(self):
        return Rect((0, self.tab_height), self.content_size())

    def page_height(self):
        return self.height - self.tab_height

    def add_page(self, title, page):
        self._add_page(title, page)
        if not self.current_page:
            self.show_page(page)

    def _add_page(self, title, page):
        page.tab_title = title
        page.anchor = 'ltrb'
        self.pages.append(page)

    def remove_page(self, page):
        try:
            i = self.pages.index(page)
            del self.pages[i]
        except IndexError:
            pass
        if page is self.current_page:
            self.show_page(None)

    def show_page(self, page):
        if self.current_page:
            self.remove(self.current_page)
        self.current_page = page
        if page:
            th = self.tab_height
            page.rect = Rect(0, th, self.width, self.height - th)
            self.add(page)
            page.focus()

    def draw(self, surf):
        self.draw_tab_area_bg(surf)
        self.draw_tabs(surf)

    def draw_tab_area_bg(self, surf):
        bg = self.tab_area_bg_color
        if bg:
            surf.fill(bg, (0, 0, self.width, self.tab_height))

    def draw_tabs(self, surf):
        font = self.tab_font
        fg = self.tab_fg_color
        b = self.tab_border_width
        if b:
            surf.fill(fg, (0, self.tab_height - b, self.width, b))
        for i, title, page, selected, rect in self.iter_tabs():
            x0 = rect.left
            w = rect.width
            h = rect.height
            r = rect
            if not selected:
                r = Rect(r)
                r.bottom -= b
            self.draw_tab_bg(surf, page, selected, r)
            if b:
                surf.fill(fg, (x0, 0, b, h))
                surf.fill(fg, (x0 + b, 0, w - 2 * b, b))
                surf.fill(fg, (x0 + w - b, 0, b, h))
            buf = font.render(title, True, page.fg_color or fg)
            r = buf.get_rect()
            r.center = (x0 + w // 2, h // 2)
            surf.blit(buf, r)

    def iter_tabs(self):
        pages = self.pages
        current_page = self.current_page
        n = len(pages)
        b = self.tab_border_width
        s = self.tab_spacing
        h = self.tab_height
        m = self.tab_margin
        width = self.width - 2 * m + s - b
        x0 = m
        for i, page in enumerate(pages):
            x1 = m + (i + 1) * width // n  #self.tab_boundary(i + 1)
            selected = page is current_page
            yield i, page.tab_title, page, selected, Rect(
                x0, 0, x1 - x0 - s + b, h)
            x0 = x1

    def draw_tab_bg(self, surf, page, selected, rect):
        bg = self.tab_bg_color_for_page(page)
        if not selected:
            bg = brighten(bg, self.tab_dimming)
        surf.fill(bg, rect)

    def tab_bg_color_for_page(self, page):
        return getattr(page, 'tab_bg_color', None) \
         or page.bg_color \
         or self.default_tab_bg_color

    def mouse_down(self, e):
        x, y = e.local
        if y < self.tab_height:
            i = self.tab_number_containing_x(x)
            if i is not None:
                self.show_page(self.pages[i])

    def tab_number_containing_x(self, x):
        n = len(self.pages)
        m = self.tab_margin
        width = self.width - 2 * m + self.tab_spacing - self.tab_border_width
        i = (x - m) * n // width
        if 0 <= i < n:
            return i