Exemple #1
0
class Switch(_button):
    """
    Switch([value, [labels, [options]]]) -> Switch widget
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    This is very similar to a button. When clicked, it will cycle through it's
    list of options. The label displayed will be the the item in the labels list
    at the same index as the current option (value) in the options list. The
    labels and options need to be exactly the same size.

    Arguments
    ---------
    value
        Must be an item in the options list.
    labels
        A list of strings that will be used as labels.
    options
        A list of items that are cycled through to determin this widgets value.
    """

    _value = widget.ReplaceableCellDescriptor()
    on_label = widget.ReplaceableCellDescriptor()
    off_label = widget.ReplaceableCellDescriptor()

    def __init__(self,
                 value=False,
                 labels=("Off", "On"),
                 options=(False, True),
                 **params):
        super(Switch, self).__init__(**params)
        self._value = value
        self.labels = list(labels)
        self.options = list(options)
        if len(self.labels) != len(self.options):
            raise ValueError(
                "The number of labels has to equal the number of options!")
        self.set_value(value)

    def set_value(self, v):
        self._value = v
        if v not in self.options:
            error = """Could not find value in options.
"""
            error = error + "Value:" + str(v) + "  Options:" + str(
                self.options)
            raise ValueError(error)
        self.label = self.labels[self.options.index(v)]

    value = property(lambda self: self._value, set_value)

    def click(self):
        i = self.options.index(self.value)
        if i == len(self.options) - 1:
            i = 0
        else:
            i += 1
        self.value = self.options[i]
Exemple #2
0
class Image(widget.Widget):
    """
    Image(value) -> Image widget
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    Basic widget for simply displaying an image. value should be a pygame
    surface.
    """
    value = widget.ReplaceableCellDescriptor()

    def __init__(self, value, **params):
        widget.Widget.__init__(self, **params)
        self.value = value

    def draw_widget(self):
        self.blit(self.value, self.pos, clip_rect=self.value.get_rect())

    def width(self):
        return self.value.get_width()

    width = ComputedCellDescriptor(width)

    def height(self):
        return self.value.get_height()

    height = ComputedCellDescriptor(height)
Exemple #3
0
class _slider(widget.Widget):

    _value = widget.ReplaceableCellDescriptor()
    length = widget.ReplaceableCellDescriptor()
    min_value = widget.ReplaceableCellDescriptor()
    step = widget.ReplaceableCellDescriptor()

    def __init__(self, value=0, min_value=0, length=20, step=True, **params):
        widget.Widget.__init__(self, **params)
        self.step = step
        self.length = length
        self.min_value = min_value
        self.value = value

        # Create the marker widget and link it's values to sliders.
        self.marker = Marker()  #widget.Widget()
        self.marker.parent = self
        self.marker._cells["hovering"] = self._cells["hovering"]
        self.marker._cells["focused"] = self._cells["focused"]
        self.marker._cells["pressing"] = self._cells["pressing"]
        self.marker._cells["disabled"] = self._cells["disabled"]

    def set_value(self, v):
        v = max(v, self.min_value)
        v = min(v, self.min_value + self.length)
        if self.step: v = int(v)
        self._value = v
        self.send(CHANGE)

    value = property(lambda self: self._value, set_value)

    def marker_pos(self):
        w = self.style_option["width"] - self.marker.width
        w = float(self.value - self.min_value) / (self.length) * w

        h = self.style_option["height"] - self.marker.height
        h = float(self.value - self.min_value) / (self.length) * h
        return (int(w), int(h))

    marker_pos = ComputedCellDescriptor(marker_pos)
Exemple #4
0
class _button(widget.Widget):

    _label = widget.ReplaceableCellDescriptor()

    def __init__(self, **params):
        self._label = None
        super(_button, self).__init__(**params)

    def set_label(self, v):
        if hasattr(v, "value"):
            l = label.Label(v.value, parent=self)
            l._cells["value"] = ComputedCell(lambda: str(v.value))
        if type(v) == int:
            v = str(v)
        if type(v) == str or type(v) == unicode:
            l = label.Label(v, parent=self)
        self.send(CHANGE)
        self._label = l
        self._label._cells["hovering"] = self._cells["hovering"]
        self._label._cells["focused"] = self._cells["focused"]
        self._label._cells["pressing"] = self._cells["pressing"]

    label = property(lambda self: self._label, set_label)

    def width(self):
        if not self.label:
            return widget.Widget.width.function(self)
        w = self.label.width + self.style_option[
            "padding-left"] + self.style_option["padding-right"]
        return widget.Widget.width.function(self, w)

    width = ComputedCellDescriptor(width)

    def height(self):
        if not self.label:
            return widget.Widget.height.function(self)
        h = self.label.height + self.style_option[
            "padding-top"] + self.style_option["padding-bottom"]
        return widget.Widget.height.function(self, h)

    height = ComputedCellDescriptor(height)

    def draw_widget(self):
        self.label.dirty = True
        self.label.draw()
Exemple #5
0
class _box(container.Container):

    expand = widget.ReplaceableCellDescriptor()

    def __init__(self, expand=True, **params):
        container.Container.__init__(self, **params)

        self.expand = expand

    def add(self, *widgets):
        super(_box, self).add(*widgets)
        self.position_widgets()

    def remove(self, widgets):
        container.Container.remove(self, widgets)
        self.position_widgets()

    def draw(self, drawbg=True):
        self.dirty = True
        container.Container.draw(self, drawbg)
Exemple #6
0
class Button(_button):
    """
    Button([value]) -> Button widget
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    A widget resembling a button.

    Arguments
    ---------
    value
        The text or widget to be displayed on the button.
    """

    _value = widget.ReplaceableCellDescriptor()

    def __init__(self, value=" ", **params):
        super(Button, self).__init__(**params)
        self._value = None
        self.value = value

    def set_value(self, v):
        self._value = v
        self.label = v

    value = property(lambda self: self._value, set_value)
class SelectBox(box.VBox):
    """
    SelectBox([multiple, [expand]]) -> SelectBox widget
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    Subclasses from VBox. Like a html select box.

    You can access SelectBox.values to get a set of all selected values.

    Arguments
    ---------
    multiple
        If set to True, multiple options can be selected.

    expand
        If set to True (default) all widgets will expand to be the same width.
    """

    multiple = widget.ReplaceableCellDescriptor()

    def __init__(self, multiple=False, **params):
        box.VBox.__init__(self, **params)
        self.selected = set()  #CellSet()
        self.options = CellDict()
        self.multiple = multiple

    def get_values(self):
        vs = set()
        for v in self.selected:
            vs.add(self.options[v])
        return vs

    values = property(get_values)

    def get_label(self, v):
        if hasattr(v, "value"):
            l = label.Label(v.value, parent=self, container=self)
            l._cells["value"] = ComputedCell(lambda: str(v.value))
        if type(v) == int:
            v = str(v)
        if type(v) == str or type(v) == unicode:
            l = label.Label(v, parent=self)
        return l

    def add(self, label, value):
        """
        SelectBox.add(label, value) -> Option widget
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        Add an option to SelectBox.

        Arguments
        ---------
        label
            The text or widget to be displayed as the option.

        value
            The value of the option (not displayed).
        """
        label = self.get_label(label)
        label._cells["disabled"] = self._cells["disabled"]
        box.VBox.add(self, label)
        self.options[label] = value
        self.send(CHANGE)

        def click():
            if label in self.selected:
                self.selected.remove(label)
                label.selected = False
            else:
                self.selected.add(label)
                label.selected = True

            if not self.multiple:
                for l in self.options.keys():
                    if l != label:
                        l.selected = False
                self.selected = set((label, ))  #CellSet((label,))

        label.click = click

        return label

    def remove(self, option):
        """
        SelectBox.remove(option) -> None
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        Remove option from SelectBox.

        Arguments
        ---------
        option
            Can ether be a string representing an option's value or the option
            widget.

        """
        if type(option) == str:
            for k, v in self.options.items():
                if v == option:
                    box.VBox.remove(self, self.options[k])
                    del self.options[k]
        else:
            box.VBox.remove(self, option)
            del self.options[option]
        self.send(CHANGE)

    def clear(self):
        """
        SelectBox.clear() -> None
        ^^^^^^^^^^^^^^^^^^^^^^^^^
        clears all options from SelectBox.
        """
        rops = set()
        for v in self.options.keys():
            rops.add(v)
        for v in rops:
            self.remove(v)
Exemple #8
0
class TextBlock(widget.Widget):
    """
    TextBlock(value) -> TextBlock widget
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    Basic widget for wrapping and displaying some text. Supports line breaks
    (ether \\n or <br>)
    """
    value = widget.ReplaceableCellDescriptor(restriction=StringRestriction())

    def __init__(self, value, **params):
        widget.Widget.__init__(self, **params)

        self.value = value

    def font(self):
        """
        Label.font -> pygame.Font
        ^^^^^^^^^^^^^^^^^^^^^^^^^
        The font that this label is using.
        """
        f = self.get_font(self.style_option["font-family"], self.style_option["font-size"])
        if self.style_option["font-weight"] == "bold":
            f.set_bold(True)
        return f
    font = ComputedCellDescriptor(font)

    def font_x(self):
        x,_ = self.pos
        return x + self.style_option["padding-left"]
    font_x = ComputedCellDescriptor(font_x)

    def font_y(self):
        _,y = self.pos
        return y + self.style_option["padding-top"]
    font_y = ComputedCellDescriptor(font_y)

    def lines(self):
        # First we need to wrap the text (split it into lines).
        char_w,line_h = self.font.size("e")
        max_chars = self.style_option["width"]/char_w
        line_w,_ = self.font.size(max_chars*"e")
        value = self.value.replace("\n", "<br>")
        value = value.replace("<br>", " <br> ")
        words = value.split(" ")
        lines = []
        line_data = ""
        for word in words:
            if word != "<br>" and self.font.size(line_data +" "+ word)[0] < line_w:
                # We can fit this word onto this line.
                line_data = line_data+" "+word
            else:
                # Flush old line and start a new one.
                lines.append(line_data.strip())
                if word != "<br>":
                    line_data = word
                else:
                    line_data = ""
        lines.append(line_data.strip())
        return lines
    lines = ComputedCellDescriptor(lines)

    def height(self):
        _,line_h = self.font.size("e")
        h = line_h*len(self.lines) + self.style_option["padding-bottom"]+\
                self.style_option["padding-top"]
        return widget.Widget.height.function(self, h)
    height = ComputedCellDescriptor(height)

    def draw_widget(self):
        linenum = 0
        _,line_h = self.font.size("e")
        for line in self.lines:
            x = self.font_x
            y = self.font_y + line_h*linenum
            self.blit(self.font.render(line, self.style_option["antialias"],
                      self.style_option["color"]), (x,y))
            linenum += 1
Exemple #9
0
class Label(widget.Widget):
    """
    Label(value) -> Label widget
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    Basic widget for simply displaying some text. Not really much to
    it, you can pass it a value which it will display.
    """
    value = widget.ReplaceableCellDescriptor(restriction=StringRestriction())

    def __init__(self, value, **params):
        super(Label, self).__init__(self, **params)

        self.value = value

    def font(self):
        """
        Label.font -> pygame.Font
        ^^^^^^^^^^^^^^^^^^^^^^^^^
        The font that this label is using.
        """
        f = self.get_font(self.style_option["font-family"],
                          self.style_option["font-size"])
        if self.style_option["font-weight"] == "bold":
            f.set_bold(True)
        return f

    font = ComputedCellDescriptor(font)

    def width(self):
        w = self.font.size(self.value)[0]
        return widget.Widget.width.function(self, w)

    width = ComputedCellDescriptor(width)

    def height(self):
        h = self.font.size(self.value)[1]
        return widget.Widget.height.function(self, h)

    height = ComputedCellDescriptor(height)

    def font_x(self):
        x, _ = self.pos
        return x + self.style_option["padding-left"]

    font_x = ComputedCellDescriptor(font_x)

    def font_y(self):
        _, y = self.pos
        return y + self.style_option["padding-top"]

    font_y = ComputedCellDescriptor(font_y)

    #def clip_rect(self):
    #return pygame.Rect(0,0,
    #self.width-(self.style_option["padding-left"]+\
    #self.style_option["padding-right"]),
    #self.height-(self.style_option["padding-top"]+\
    #self.style_option["padding-bottom"]))
    #clip_rect = ComputedCellDescriptor(clip_rect)

    def font_value(self):
        return self.font.render(self.value, self.style_option["antialias"],
                                self.style_option["color"])

    font_value = ComputedCellDescriptor(font_value)

    def draw_widget(self):
        # We do this incase we are trying to blit the text into a space smaller
        # than it can fit into.

        self.blit(self.font_value, (self.font_x, self.font_y),
                  clip_rect=self.clip_rect)
Exemple #10
0
class Input(widget.Widget):
    """
    Input([value, [max_length, [disallowed_chars]]]) - Input widget
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    Creates an HTML like input field.

    Arguments
    ---------
    value
        The initial value of the input (defaults to ""). Note that due to the
        nature of the value, you cannot link to it (but you can from it). If
        you really want to link it's value you can do so it _value, but it may
        not always work like you expect!

    max_length
        The maximum number of character that can be put into the Input.

    disallowed_chars
        A list of characters that are disallowed to enter.
    """

    _value = widget.ReplaceableCellDescriptor()
    cur_pos = widget.ReplaceableCellDescriptor()
    max_length = widget.ReplaceableCellDescriptor()

    def __init__(self, value="", max_length=None, disallowed_chars=[], **params):
        widget.Widget.__init__(self, **params)
        self._value = u""
        self.cur_pos = 0
        self.max_length = max_length
        self.value = value
        self.disallowed_chars = disallowed_chars
        self.last_press = {K_BACKSPACE:0, K_LEFT:0, K_RIGHT:0, K_DELETE:0}


    def font(self):
        """
        Input.font -> pygame.Font
        ^^^^^^^^^^^^^^^^^^^^^^^^^
        The font that this input is using.
        """
        f = self.get_font(self.style_option["font-family"], self.style_option["font-size"])
        if self.style_option["font-weight"] == "bold":
            f.set_bold(True)
        return f
    font = ComputedCellDescriptor(font)

    def set_value(self,v):
        if v == None: v = ''
        v = unicode(v)
        if self.max_length and len(v) > self.max_length:
            v = v[0:self.max_length-1]
        self._value = v
        if self.cur_pos-1 > len(v):
            #print self.cur_pos-1, len(v)
            self.cur_pos = len(v)
        self.send(CHANGE)
    value = property(lambda self: self._value, set_value)

    def size(self):
        s,_ = self.font.size("e")
        num = self.style_option["width"]/s
        return self.font.size("e"*num)
    size = ComputedCellDescriptor(size)

    def width(self):
        w = self.size[0] + self.style_option["padding-left"]+\
                self.style_option["padding-right"]
        return widget.Widget.width.function(self, w)
    width = ComputedCellDescriptor(width)

    def height(self):
        h = self.size[1] + self.style_option["padding-top"]+\
                self.style_option["padding-bottom"]
        return widget.Widget.height.function(self, h)
    height = ComputedCellDescriptor(height)

    def font_clip_rect(self):
        vx = max(self.font.size(self.value)[0] - self.size[0], 0)
        return pygame.Rect((vx, 0), self.size)
    font_clip_rect = ComputedCellDescriptor(font_clip_rect)

    def font_x(self):
        x,_ = self.pos
        return x + self.style_option["padding-left"]
    font_x = ComputedCellDescriptor(font_x)

    def font_y(self):
        _,y = self.pos
        return y + self.style_option["padding-top"]
    font_y = ComputedCellDescriptor(font_y)

    def draw_widget(self):
        self.blit(self.font.render(self.value, self.style_option["antialias"],
                                   self.style_option["color"]),
                  (self.font_x,self.font_y),
                  clip_rect=self.font_clip_rect)

        if self.focused:
            w,h = self.font.size(self.value[0:self.cur_pos])
            r = pygame.Surface((2,self.size[1]))
            r.fill(self.style_option["color"])
            x = min(w, self.size[0])
            self.blit(r, (self.font_x+x, self.font_y))

    def repetitive_events(self):
        # Key repeating. Better way to do this?
        k = pygame.key.get_pressed()
        if k[K_BACKSPACE] and pygame.time.get_ticks()-self.last_press[K_BACKSPACE] > 300:
            self.value = self.value[:self.cur_pos-1] + self.value[self.cur_pos:]
            if self.cur_pos > 0:
                self.cur_pos -= 1
        elif k[K_DELETE] and pygame.time.get_ticks()-self.last_press[K_DELETE] > 300:
            if len(self.value) > self.cur_pos:
                self.value = self.value[:self.cur_pos] + self.value[self.cur_pos+1:]
        elif k[K_LEFT] and pygame.time.get_ticks()-self.last_press[K_LEFT] > 300:
            if self.cur_pos > 0: self.cur_pos -= 1
        elif k[K_RIGHT] and pygame.time.get_ticks()-self.last_press[K_RIGHT] > 300:
            if self.cur_pos < len(self.value): self.cur_pos += 1



    def event(self,e):
        widget.Widget.event(self, e)
        if e.type == KEYDOWN:
            if e.key == K_BACKSPACE:
                if self.cur_pos:
                    self.value = self.value[:self.cur_pos-1] + self.value[self.cur_pos:]
                    if self.cur_pos > 0:
                        self.cur_pos -= 1
                    self.last_press[K_BACKSPACE] = pygame.time.get_ticks()
            elif e.key == K_DELETE:
                if len(self.value) > self.cur_pos:
                    self.value = self.value[:self.cur_pos] + self.value[self.cur_pos+1:]
                self.last_press[K_DELETE] = pygame.time.get_ticks()
            elif e.key == K_HOME:
                self.cur_pos = 0
            elif e.key == K_END:
                self.cur_pos = len(self.value)
            elif e.key == K_LEFT:
                if self.cur_pos > 0: self.cur_pos -= 1
                self.last_press[K_LEFT] = pygame.time.get_ticks()
            elif e.key == K_RIGHT:
                if self.cur_pos < len(self.value): self.cur_pos += 1
                self.last_press[K_RIGHT] = pygame.time.get_ticks()
            elif e.key == K_ESCAPE: pass
            elif e.key == K_RETURN:
                self.next()
            else:
                if self.max_length:
                    if len(self.value) == self.max_length:
                        return
                c = e.unicode
                #c = (e.unicode).encode('latin-1')
                if c and c not in self.disallowed_chars:
                    self.value = unicode(self.value)[:self.cur_pos] + c +\
                        unicode(self.value)[self.cur_pos:]
                    self.cur_pos += 1
Exemple #11
0
class Container(widget.Widget):
    """
    Container([scrollable]) -> Container widget
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    A base container widget for containing other widgets. (gosh that's
    descriptive!) scrollable is for wether or not the container is, well,
    scrollable (this feature isn't complete yet, but still usable)!
    """

    scrollable = widget.ReplaceableCellDescriptor()
    offset_x = widget.ReplaceableCellDescriptor()
    offset_y = widget.ReplaceableCellDescriptor()

    def __init__(self, scrollable=False, **params):
        super(Container, self).__init__(**params)
        self.widgets = CellList()
        self.scrollable = scrollable
        self.offset_x = 0
        self.offset_y = 0

        self.vslider = slider.VSlider(length=self.content_height, step=False,
                active=self.scrollable, height=self.style_option["height"]-\
                self.style_option["padding-top"]-\
                self.style_option["padding-bottom"])
        self.vslider.x = self.width - self.vslider.width-\
                self.style_option["padding-left"]-\
                self.style_option["padding-right"]
        #self.vslider.container = self
        self.vslider.parent = self
        self.offset_y = self.vslider.link("value")
        self.vslider._cells["disabled"] = self._cells["disabled"]
        self.vslider._cells["length"] = self._cells["content_height"]
        self.vslider.connect(CHANGE, self.draw_widget)

    #def width(self, width=0):
    #width = widget.Widget.width.function(self, width)
    #return width+self.vslider.width
    #width = ComputedCellDescriptor(width)

    def content_height(self):
        return 0

    content_height = ComputedCellDescriptor(content_height)

    def draw_widget(self):
        if not self.widgets: return
        for w in self.widgets:
            w.dirty = True
        self.vslider.dirty = True

    def draw(self, drawbg=True):
        if self.dirty: drawbg = False
        else: drawbg = True
        super(Container, self).draw()
        if not self.widgets: return
        for w in self.widgets:
            if w.active:
                w.draw(drawbg)
        if self.scrollable:
            self.vslider.draw(False)

    def exit(self):
        self.hovering = False
        if not self.widgets: return
        for w in self.widgets:
            w.exit()

    def event(self, e):
        widget.Widget.event(self, e)
        if not self.widgets: return
        for w in self.widgets:
            if w.active:
                w._event(e)

        if self.scrollable:
            self.vslider._event(e)

    def add(self, *widgets):
        """
        Container.add(widgets) -> None
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        Add widgets to Container.

        Arguments
        ---------
        widgets
            can ether be a single widget or a list of widgets.
        """

        for w in widgets:
            if type(w) == list:
                raise ValueError(
                    "Got unexpected value. Remember that if you want to add multiple widgets to a container, do c.add(w1,w2,w3)!"
                )
            self.widgets.append(w)
            w.container = self
            w.parent = self
            w.send(OPEN)

    def remove(self, widgets):
        """
        Container.remove(widgets) -> None
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        Remove widgets from Container.

        Arguments
        ---------
        widgets
            can ether be a single widget or a list of widgets.

        """
        try:
            iter(widgets)
        except TypeError:
            widgets = [widgets]

        for w in widgets:
            self.widgets.remove(w)
            w.send(CLOSE)
        self.dirty = True

    def _next(self, orig=None):
        start = 0
        if orig and orig in self.widgets: start = self.widgets.index(orig) + 1
        for w in self.widgets[start:]:
            if not w.disabled and w.focusable:
                if isinstance(w, Container):
                    if w._next():
                        return True
                else:
                    self.focus(w)
                    return True
        return False

    def next(self, w=None):
        if self._next(w): return True
        if self.container: return self.container.next(self)