VALIGN_BOTTOM = -1 HALIGN_LEFT = -1 HALIGN_CENTER = 0 ANCHOR_CENTER = (VALIGN_CENTER, HALIGN_CENTER) def GetRelativePoint(parent, parent_anchor, child, child_anchor, offset):
    valign, halign = parent_anchor or ANCHOR_CENTER

    if valign == VALIGN_TOP:
        y = parent.y + parent.height
    elif valign == VALIGN_CENTER:
        y = parent.y + parent.height // 2
    else:  # VALIGN_BOTTOM
        y = parent.y

    if halign == HALIGN_LEFT:
        x = parent.x
    elif halign == HALIGN_CENTER:
        x = parent.x + parent.width // 2
    else:  # HALIGN_RIGHT
        x = parent.x + parent.width

    valign, halign = child_anchor or (valign, halign)
    offset_x, offset_y = offset

    if valign == VALIGN_TOP:
        y += offset_y - child.height
    elif valign == VALIGN_CENTER:
        y += offset_y - child.height // 2
    else:  # VALIGN_BOTTOM
        y += offset_y

    if halign == HALIGN_LEFT:
        x += offset_x
    elif halign == HALIGN_CENTER:
        x += offset_x - child.width // 2
    else:  # HALIGN_RIGHT
        x += offset_x - child.width

    return x, y class Rectangle(object):
    def __init__(self, x=0, y=0, width=0, height=0):
        self._x = x
        self._y = y
        self.width = width
        self.height = height

    @property
    def x(self):
        return self._x

    @property
    def y(self):
        return self._y

    @x.setter
    def x(self, value):
        self._x = value

    @y.setter
    def y(self, value):
        self._y = value

    def set_position(self, x, y):
        self._x = x
        self._y = y

    def is_inside(self, x, y):
        return self.x <= x < self.x + self.width and self.y <= y < self.y + self.height class Viewer(Rectangle, Managed):
    def __init__(self, width=0, height=0):
        super(Managed, self).__init__()
        self._parent = None
        self._is_loaded = False

        Rectangle.__init__(self, 0, 0, width, height)

    @property
    def parent(self):
        return self._parent

    @parent.setter
    def parent(self, widget):
        self._parent = widget

    @property
    def is_loaded(self):
        return self._is_loaded

    def is_expandable(self):
        return False

    def set_position(self, x, y):
        super(Viewer, self).set_position(x, y)
        self.layout()

    def get_path(self):
        raise NotImplementedError

    def load(self):
        assert not self._is_loaded
        self._is_loaded = True
        self.load_graphics()

    def unload(self):
        assert self._is_loaded
        self._is_loaded = False
        self.unload_graphics()

    def reload(self):
        self.unload()
        self.load()

    def load_graphics(self):
        pass

    def unload_graphics(self):
        pass

    def layout(self):
        pass

    def compute_size(self):
        return self.width, self.height

    def reset_size(self, reset_parent=True):
        width, height = self.compute_size()

        # if out size changes
        if self.width != width or self.height != height:
            self.width, self.height = width, height

            # This will eventually call our layout
            if reset_parent:
                self.parent.reset_size(reset_parent)
        # else, the parent is never affected and thus we layout.
        else:
            self.layout()

    def delete(self):
        if self.is_loaded:
            self.unload()
        self.parent = None
        Managed.delete(self) class TwoStateController(Controller):
class ContinuousStateController(Controller):
class Option(Controller):
class Selector:
    def __init__(self, is_pressed=False, on_press=None):
    def is_pressed(self):
    def change_state(self):
    def __init__(self, value=0.0, min_value=0.0, max_value=1.0, on_set=None):
    def set_value(self, value):
    def value(self):
    def __init__(self, name, parent):
    def select(self):
    def __init__(self, options, labels=None, on_select=None, selected=None):
    def _make_options(self, options, labels):
    def select(self, option_name):
    def deselect(self): class HorizontalContainer(Container):
    def __init__(self, content, align=VALIGN_CENTER, padding=5):
        assert align in (HALIGN_CENTER, HALIGN_LEFT, HALIGN_RIGHT)
        super(HorizontalContainer, self).__init__(content)
        self.align = align
        self.padding = padding
        self._expandable = []

    def is_expandable(self):
        # True if we contain expandable content.
        return len(self._expandable) > 0

    def expand(self, width, height):
        """
        Expands to fill available horizontal space.  We split available space
        equally between all spacers.
        """
        available = int((width - self.width) / len(self._expandable))
        remainder = height - self.height - len(self._expandable) * available
        for item in self._expandable:
            if remainder > 0:
                item.expand(item.width + available + 1, item.height)
                remainder -= 1
            else:
                item.expand(item.width + available, item.height)
        self.width = width

    def layout(self):
        # Expand any expandable content to our height
        for item in self._content:
            if item.is_expandable() and item.height < self.height:
                item.expand(item.width, self.height)

        left = self.x
        if self.align == VALIGN_TOP:
            for item in self._content:
                item.set_position(left, self.y + self.height - item.height)
                left += item.width + self.padding
        elif self.align == VALIGN_CENTER:
            for item in self._content:
                item.set_position(left, self.y + self.height / 2 - item.height / 2)
                left += item.width + self.padding
        else:  # VALIGN_BOTTOM
            for item in self._content:
                item.set_position(left, self.y)
                left += item.width + self.padding

    def compute_size(self):
        height = 0
        if len(self._content) < 2:
            width = 0
        else:
            width = -self.padding
        for item in self._content:
            item.compute_size()
            height = max(height, item.height)
            width += item.width + self.padding
        self._expandable = [x for x in self._content if x.is_expandable()]

        return width, height class VerticalContainer(Container):
    def __init__(self, content, align=HALIGN_CENTER, padding=5):
        assert align in (HALIGN_CENTER, HALIGN_LEFT, HALIGN_RIGHT)
        super(VerticalContainer, self).__init__(content)
        self.align = align
        self.padding = padding
        self._expandable = []

    def expand(self, width, height):
        """
        Expands to fill available vertical space.  We split available space
        equally between all spacers.
        """
        available = int((height - self.height) / len(self._expandable))
        remainder = height - self.height - len(self._expandable) * available
        for item in self._expandable:
            if remainder > 0:
                item.expand(item.width, item.height + available + 1)
                remainder -= 1
            else:
                item.expand(item.width, item.height + available)
        self.height = height
        self.width = width

    def is_expandable(self):
        # True if we contain an expandable content.
        return len(self._expandable) > 0

    def layout(self):
        # Expand any expandable content to our width
        for item in self._content:
            if item.is_expandable() and item.width < self.width:
                item.expand(self.width, item.height)

        top = self.y + self.height
        if self.align == HALIGN_RIGHT:
            for item in self._content:
                item.set_position(self.x + self.width - item.width, top - item.height)
                top -= item.height + self.padding
        elif self.align == HALIGN_CENTER:
            for item in self._content:
                item.set_position(self.x + self.width / 2 - item.width / 2, top - item.height)
                top -= item.height + self.padding
        else:  # HALIGN_LEFT
            for item in self._content:
                item.set_position(self.x, top - item.height)
                top -= item.height + self.padding

    def compute_size(self):
        if len(self._content) < 2:
            height = 0
        else:
            height = -self.padding
        width = 0
        for item in self._content:
            height += item.height + self.padding
            width = max(width, item.width)
        self._expandable = [x for x in self._content if x.is_expandable()]

        return width, height class Wrapper(Container):
    """
    A Viewer that wraps another widget.
    """
    def __init__(self, content, is_expandable=False, anchor=ANCHOR_CENTER, offset=(0, 0)):
        assert isinstance(content, Viewer)
        Container.__init__(self, [content])

        self.expandable = is_expandable
        self._anchor = anchor
        self.content_offset = offset

    @property
    def anchor(self):
        return self._anchor

    @anchor.setter
    def anchor(self, anchor):
        self._anchor = anchor

    @property
    def content(self):
        return self._content[0]

    @content.setter
    def content(self, content):
        assert isinstance(content, Viewer)
        self.content.delete()

        self._content[0] = content
        self.content.set_manager(self._manager)
        self.content.parent = self
        self.content.load()
        self.reset_size()

    def expand(self, width, height):
        if self.content.is_expandable():
            self.content.expand(width, height)
        self.width = width
        self.height = height

    def is_expandable(self):
        return self.expandable

    def compute_size(self):
        return self.content.width, self.content.height

    def layout(self):
        x, y = GetRelativePoint(self, self.anchor, self.content, self.anchor, self.content_offset)
        self.content.set_position(x, y) class Button(TwoStateController, Viewer):
    def __init__(self, label="", is_pressed=False, on_press=None):
        TwoStateController.__init__(self, is_pressed=is_pressed, on_press=on_press)
        Viewer.__init__(self)

        self.label = label

        # graphics
        self._label = None
        self._button = None

    def change_state(self):
        self._is_pressed = not self._is_pressed
        self.reload()
        self.reset_size()
        self._on_press(self._is_pressed)

    def hit_test(self, x, y):
        return self.is_inside(x, y)

    def on_mouse_press(self, x, y, button, modifiers):
        self.change_state()

    def get_path(self):
        path = ['button']
        if self.is_pressed:
            path.append('down')
        else:
            path.append('up')
        return path

    def load_graphics(self):
        theme = self.theme[self.get_path()]

        self._button = theme['image'].generate(theme['gui_color'], **self.get_batch('background'))

        self._label = Label(self.label,
                            font_name=theme['font'],
                            font_size=theme['font_size'],
                            color=theme['text_color'],
                            **self.get_batch('foreground'))

    def unload_graphics(self):
        self._button.unload()
        self._label.unload()

    def compute_size(self):
        # Treat the height of the label as ascent + descent
        font = self._label.document.get_font()
        height = font.ascent - font.descent

        return self._button.get_needed_size(self._label.content_width, height)

    def layout(self):
        self._button.update(self.x, self.y, self.width, self.height)

        # centers the label on the middle of the button
        x, y, width, height = self._button.get_content_region()

        font = self._label.document.get_font()
        self._label.x = x + width/2 - self._label.content_width/2
        self._label.y = y + height/2 - font.ascent/2 - font.descent
        self._label.update()

    def delete(self):
        TwoStateController.delete(self)
        Viewer.delete(self) class FocusButton(Button, FocusMixin):
    """
    Button that is focusable and thus can be selected with TAB.
    """
    def __init__(self, label="", is_pressed=False, on_press=None):
        Button.__init__(self, label, is_pressed, on_press)
        FocusMixin.__init__(self)

    def on_key_press(self, symbol, modifiers):
        if symbol == pyglet.window.key.ENTER:
            self.change_state() class Manager(ViewerManager, ControllerManager):
    def __init__(self,
                 content,
                 theme,
                 window=None,
                 batch=None,
                 group=None,
                 is_movable=True,
                 anchor=ANCHOR_CENTER,
                 offset=(0, 0)):
        ControllerManager.__init__(self)
        ViewerManager.__init__(self, content, theme, window, batch, group, anchor, offset)

        self.is_movable = is_movable
        self._is_dragging = False

    def hit_test(self, x, y):
        return self.is_inside(x, y)

    def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers):
        if not ControllerManager.on_mouse_drag(self, x, y, dx, dy, buttons, modifiers):
            if self.is_movable and self._is_dragging:
                x, y = self._offset
                self._offset = (int(x + dx), int(y + dy))
                self.set_position(*self.get_position())
                return True

    def on_mouse_motion(self, x, y, dx, dy):
        ControllerManager.on_mouse_motion(self, x, y, dx, dy)
        if self.hit_test(x, y):
            if not self._root_group.is_on_top():
                self.pop_to_top()
            return True

    def on_mouse_press(self, x, y, button, modifiers):
        retval = ControllerManager.on_mouse_press(self, x, y, button, modifiers)
        if self.hit_test(x, y):
            if not retval:
                self._is_dragging = True
                retval = True
        return retval

    def on_mouse_release(self, x, y, button, modifiers):
        self._is_dragging = False
        return ControllerManager.on_mouse_release(self, x, y, button, modifiers)

    def on_resize(self, width, height):
        """
        Update our knowledge of the window's width and height.
        """
        if self.screen.width != width or self.screen.height != height:
            self.screen.width, self.screen.height = width, height
            self.set_position(*self.get_position())

    def delete(self):
        ViewerManager.delete(self)
        ControllerManager.delete(self)
import pyglet.text
from pyglet_gui.constants import VALIGN_BOTTOM, HALIGN_LEFT, HALIGN_CENTER, ANCHOR_CENTER, GetRelativePoint
from pyglet_gui.core import Rectangle, Viewer
from pyglet_gui.controllers import Controller
from pyglet_gui.containers import HorizontalContainer, VerticalContainer, Wrapper
from pyglet_gui.buttons import Button, FocusButton
from pyglet_gui.manager import Manager
    def expand(self, width, height):
        if self.content.is_expandable():
            content_width, content_height = self._frame.get_content_size(width, height)
            self.content.expand(content_width, content_height)
        self.width, self.height = width, height

    def layout(self):
        self._frame.update(self.x, self.y, self.width, self.height)

        # we create a rectangle with the interior for using in GetRelativePoint
        x, y, width, height = self._frame.get_content_region()
        interior = Rectangle(x, y, width, height)
        x, y = GetRelativePoint(interior, self.anchor, self.content, self.anchor, self.content_offset)
        self.content.set_position(x, y)

    def compute_size(self):
        self.content.compute_size()
        return self._frame.get_needed_size(self.content.width, self.content.height)


class TitleFrame(VerticalContainer):
    def __init__(self, title, content):
        VerticalContainer.__init__(self, content=[
            HorizontalContainer([Graphic(path=["titlebar", "left"], is_expandable=True),
                                 Frame(Label(title, path=["titlebar"]),
                                       path=["titlebar", "center"]),
                                 Graphic(path=["titlebar", "right"], is_expandable=True),
                                 ], align=VALIGN_BOTTOM, padding=0),
            Frame(content, path=["titlebar", "frame"], is_expandable=True),
            ], padding=0)


class SectionHeader(HorizontalContainer):
    def __init__(self, title, align=HALIGN_CENTER):
        if align == HALIGN_LEFT:
            left_expand = False
            right_expand = True
        elif align == HALIGN_CENTER:
            left_expand = True
            right_expand = True
        else:  # HALIGN_RIGHT
            left_expand = True
            right_expand = False

        HorizontalContainer.__init__(self, content=[
            Graphic(path=["section", "left"], is_expandable=left_expand),
            Frame(Label(title, path=["section"]), path=['section', 'center']),
            Graphic(path=["section", "right"], is_expandable=right_expand),
            ], align=VALIGN_BOTTOM, padding=0)


class FoldingSection(VerticalContainer, Controller):
    def __init__(self, title, content=None, is_open=True, align=HALIGN_CENTER):
        Controller.__init__(self)
        if align == HALIGN_LEFT:
            left_expand = False
            right_expand = True
        elif align == HALIGN_CENTER:
            left_expand = True
            right_expand = True
        else:  # HALIGN_RIGHT
            left_expand = True
            right_expand = False

        self.is_open = is_open
        self.folding_content = content
        self.book = Graphic(self._get_image_path())

        self.header = HorizontalContainer([Graphic(path=["section", "left"], is_expandable=left_expand),
                                           Frame(HorizontalContainer([
                                               self.book,
                                               Label(title, path=["section"]),
                                               ]), path=["section", "center"]),
                                           Graphic(path=["section", "right"], is_expandable=right_expand),
                                           ], align=VALIGN_BOTTOM, padding=0)
        layout = [self.header]
        if self.is_open:
            layout.append(self.folding_content)

        VerticalContainer.__init__(self, content=layout, align=align)

    def set_manager(self, manager):
        Controller.set_manager(self, manager)

        self.header.set_manager(manager)
        self.header.parent = self

        for item in self._content:
            if item == self.header:
                continue
            item.set_manager(self._manager)
            item.parent = self

    def _get_image_path(self):
        if self.is_open:
            return ["section", "opened"]
        else:
            return ["section", "closed"]

    def hit_test(self, x, y):
        return self.header.is_inside(x, y)

    def on_mouse_press(self, x, y, button, modifiers):
        self.is_open = not self.is_open

        self.book._path = self._get_image_path()
        self.book.reload()

        if self.is_open:
            self.add(self.folding_content)
        else:
            self.remove(self.folding_content)

    def delete(self):
        if not self.is_open:
            self.folding_content.delete()
        self.folding_content = None
        VerticalContainer.delete(self)



class PopupMessage(Manager):