Esempio n. 1
0
class CustomListbox(UpdateListbox):
    remake_func = widget.causes_rebuild("_remake_func")
    rebuild_func = widget.causes_rebuild("_rebuild_func")

    def __init__(self, parent, *args, **kwargs):
        self.parent = parent
        self.key_list = kwargs.pop("key_list", None)
        self.remake_func = kwargs.pop("remake_func", lambda value: None)
        self.rebuild_func = kwargs.pop("rebuild_func", lambda value: None)
        super(CustomListbox, self).__init__(parent, *args, **kwargs)

    def make_element(self):
        base = super(CustomListbox, self).make_element()
        self.remake_func(base)
        return base

    def update_element(self, element, list_index):
        if 0 <= list_index < len(self.list):
            if (self.key_list is not None):
                self.rebuild_func(element, self.list[list_index],
                                  self.key_list[list_index])
            else:
                self.rebuild_func(element, self.list[list_index])
        else:
            if (self.key_list is not None):
                self.rebuild_func(element, None, None)
            else:
                self.rebuild_func(element, None)
Esempio n. 2
0
class TextEntryDialog(TextDialog, FocusDialog):
    ok_type = widget.causes_rebuild("_ok_type")
    cancel_type = widget.causes_rebuild("_cancel_type")

    def __init__(self,
                 parent,
                 pos=(-.50, -.50),
                 size=(.50, .10),
                 anchor=constants.MID_CENTER,
                 **kwargs):
        kwargs.setdefault('wrap', False)
        kwargs.setdefault("shrink_factor", 1)
        kwargs.setdefault("text_size", 20)
        self.default_text = kwargs.pop("default_text", "")
        self.ok_type = kwargs.pop("ok_type", "ok")
        self.cancel_type = kwargs.pop("cancel_type", "cancel")
        super(TextEntryDialog, self).__init__(parent, pos, size, anchor,
                                              **kwargs)

        self.text_field = text.EditableText(self, (0, -.50), (-.71, -.50),
                                            borders=constants.ALL,
                                            base_font="normal")

        self.ok_button = button.FunctionButton(self, (-.72, -.50),
                                               (-.14, -.50),
                                               function=self.return_text)
        self.cancel_button = button.FunctionButton(
            self, (-.86, -.50), (-.14, -.50), function=self.return_nothing)

        self.add_key_handler(pygame.K_RETURN, self.return_text)
        self.add_key_handler(pygame.K_KP_ENTER, self.return_text)
        self.add_key_handler(pygame.K_ESCAPE, self.return_nothing)

    def rebuild(self):
        super(TextEntryDialog, self).rebuild()

        self.ok_button.text = g.buttons[self.ok_type]['text']
        self.ok_button.underline = g.buttons[self.ok_type]['pos']
        self.ok_button.hotkey = g.buttons[self.ok_type]['key']

        self.cancel_button.text = g.buttons[self.cancel_type]['text']
        self.cancel_button.underline = g.buttons[self.cancel_type]['pos']
        self.cancel_button.hotkey = g.buttons[self.cancel_type]['key']

    def show(self):
        self.text_field.text = self.default_text
        self.text_field.cursor_pos = len(self.default_text)
        return super(TextEntryDialog, self).show()

    def return_nothing(self, event=None):
        if event and event.type == pygame.KEYUP:
            return
        raise constants.ExitDialog("")

    def return_text(self, event=None):
        if event and event.type == pygame.KEYUP:
            return
        raise constants.ExitDialog(self.text_field.text)
Esempio n. 3
0
class YesNoDialog(TextDialog):
    """A Dialog with YES and NO buttons which exits the dialog with True and
    False return values, respectively.
    """
    yes_type = widget.causes_rebuild("_yes_type")
    no_type = widget.causes_rebuild("_no_type")

    def __init__(self, parent, *args, **kwargs):
        self.parent = parent

        self.yes_type = kwargs.pop("yes_type", "yes")
        self.no_type = kwargs.pop("no_type", "no")
        self.invert_enter = kwargs.pop("invert_enter", False)
        self.invert_escape = kwargs.pop("invert_escape", False)

        super(YesNoDialog, self).__init__(parent, *args, **kwargs)

        self.yes_button = button.ExitDialogButton(self, (-.1, -.99),
                                                  (-.3, -.1),
                                                  anchor=constants.BOTTOM_LEFT,
                                                  exit_code=True,
                                                  default=False)

        self.no_button = button.ExitDialogButton(self, (-.9, -.99), (-.3, -.1),
                                                 anchor=constants.BOTTOM_RIGHT,
                                                 exit_code=False,
                                                 default=False)

        self.add_key_handler(pygame.K_RETURN, self.on_return)
        self.add_key_handler(pygame.K_KP_ENTER, self.on_return)
        self.add_key_handler(pygame.K_ESCAPE, self.on_escape)

    def rebuild(self):
        super(YesNoDialog, self).rebuild()

        self.yes_button.text = g.buttons[self.yes_type]['text']
        self.yes_button.underline = g.buttons[self.yes_type]['pos']
        self.yes_button.hotkey = g.buttons[self.yes_type]['key']
        self.no_button.text = g.buttons[self.no_type]['text']
        self.no_button.underline = g.buttons[self.no_type]['pos']
        self.no_button.hotkey = g.buttons[self.no_type]['key']

    def on_return(self, event):
        if event and event.type == pygame.KEYUP:
            return
        if self.invert_enter:
            self.no_button.activate_with_sound(event)
        else:
            self.yes_button.activate_with_sound(event)

    def on_escape(self, event):
        if event and event.type == pygame.KEYUP:
            return
        if self.invert_escape:
            self.yes_button.activate_with_sound(event)
        else:
            self.no_button.activate_with_sound(event)
Esempio n. 4
0
class MessageDialog(TextDialog):
    """A Dialog with an OK button that exits the dialog, return value of None"""

    ok_type = widget.causes_rebuild("_ok_type")

    def __init__(self, parent, **kwargs):
        self.parent = parent

        self.ok_type = kwargs.pop("ok_type", "ok")

        super(MessageDialog, self).__init__(parent, **kwargs)

        self.ok_button = button.ExitDialogButton(
            self, (-.5, -.99), (-.3, -.1), anchor=constants.BOTTOM_CENTER)

        self.add_key_handler(pygame.K_RETURN, self.on_return)
        self.add_key_handler(pygame.K_KP_ENTER, self.on_return)

    def on_return(self, event):
        if event.type == pygame.KEYUP: return
        self.ok_button.activate_with_sound(event)

    def rebuild(self):
        super(MessageDialog, self).rebuild()

        self.ok_button.text = g.buttons[self.ok_type]['text']
        self.ok_button.underline = g.buttons[self.ok_type]['pos']
        self.ok_button.hotkey = g.buttons[self.ok_type]['key']
Esempio n. 5
0
class BuildDialog(dialog.ChoiceDescriptionDialog):
    type = widget.causes_rebuild("_type")

    def __init__(self, parent, pos=(0, 0), size=(-1, -1),
                 anchor=constants.TOP_LEFT, *args, **kwargs):
        super(BuildDialog, self).__init__(parent, pos, size, anchor, *args,
                                          **kwargs)

        self.type = None
        self.item = None
        self.desc_func = self.on_change
        self.add_handler(constants.KEY, self._got_key, priority=5)

    def show(self):
        self.list = []
        self.key_list = []

        item_list = sorted(g.items.values(), reverse=True)
        for item in item_list:
            if item.item_type.id == self.type.id and item.available() \
                    and item.buildable_in(self.parent.base.location):
                self.list.append(item.name)
                self.key_list.append(item)

        current = self.parent.get_current(self.type)
        if current is None:
            self.default = None
        else:
            self.default = self.parent.get_current(self.type).spec.id

        self._update_desc_pane()
        return super(BuildDialog, self).show()

    def on_description_change(self):
        if self.item is not None:
            self.description.text = self.item.get_info()

    def on_change(self, description_pane, item):
        self.item = item

        self.description = text.Text(self.description_pane, (0, 0), (-1, -1), text="",
                             background_color="pane_background",
                             align=constants.LEFT, valign=constants.TOP,
                             borders=constants.ALL)

        old_item = self.parent.base.items[self.type.id]
        if item is not None and (old_item is None or old_item.spec != item):
            g.pl.considered_buyables = [buyable.Buyable(self.item, count=1)]
        else:
            g.pl.considered_buyables = []

        self.on_description_change()

    def on_close_dialog(self):
        g.pl.considered_buyables = []

    def _got_key(self, event):
        self.listbox.got_key(event, require_focus=False)
Esempio n. 6
0
class SimpleMenuDialog(Dialog):
    width = widget.causes_rebuild("_width")

    def __init__(self, *args, **kwargs):
        buttons = kwargs.pop("buttons", [])
        width = kwargs.pop("width", .20)
        super(SimpleMenuDialog, self).__init__(*args, **kwargs)

        self.size = (-1, -1)
        self.pos = (0, 0)
        self.anchor = constants.TOP_LEFT
        self.width = width

        self.button_panel = \
            widget.BorderedWidget(self, (-.5, -.5), (0.22, 0.43),
                                  anchor=constants.MID_CENTER,
                                  background_color="simple_menu_background",
                                  border_color="simple_menu_border",
                                  borders=constants.ALL)

        self.buttons = buttons

    @property
    def buttons(self):
        return self._buttons

    @buttons.setter
    def buttons(self, buttons):
        if (hasattr(self, '_buttons') and not self._buttons is None):
            for button in self._buttons:
                if button.parent is not None:
                    button.parent = None

        self._buttons = buttons
        self.needs_rebuild = True

    def rebuild(self):
        num_buttons = len(self.buttons)
        height = (.06 * num_buttons) + .01

        self.button_panel.size = (self.width + .02, height)

        y_pos = .01
        for button in self.buttons:
            button.parent = self.button_panel

            button.pos = (.01, y_pos)
            button.size = (self.width, .05)
            button.text_size = 24

            y_pos += .06

        super(SimpleMenuDialog, self).rebuild()
Esempio n. 7
0
class ItemPane(widget.BorderedWidget):
    item_type = widget.causes_rebuild("_item_type")

    def __init__(self,
                 parent,
                 pos,
                 size=(.58, .06),
                 anchor=constants.TOP_LEFT,
                 item_type=None,
                 **kwargs):

        kwargs.setdefault("background_color", "pane_background")

        super(ItemPane, self).__init__(parent,
                                       pos,
                                       size,
                                       anchor=anchor,
                                       **kwargs)

        if item_type is None or not isinstance(item_type, item.ItemType):
            raise ValueError('Type must be of class ItemType.')

        self.item_type = item_type

        self.name_panel = text.Text(self, (0, 0), (.45, .03),
                                    anchor=constants.TOP_LEFT,
                                    align=constants.LEFT,
                                    background_color=self.background_color,
                                    bold=True)

        self.build_panel = text.Text(self, (0, .03), (.45, .03),
                                     anchor=constants.TOP_LEFT,
                                     align=constants.LEFT,
                                     background_color=self.background_color,
                                     text="",
                                     bold=True)

        self.change_button = button.FunctionButton(
            self,
            (.415, .01),
            (.16, .04),
            anchor=constants.TOP_LEFT,
            force_underline=len(_("CHANGE")) + 2,
            autohotkey=True,
            function=self.parent.parent.build_item,
            kwargs={'type': self.item_type},
        )

    def rebuild(self):
        self.change_button.text = "%s (&%s)" % (_("CHANGE"),
                                                self.item_type.hotkey.upper())

        super(ItemPane, self).rebuild()
Esempio n. 8
0
class ChoiceDescriptionDialog(ChoiceDialog):
    key_list = widget.causes_rebuild("_key_list")

    def __init__(self, parent, *args, **kwargs):
        self.parent = parent
        self.key_list = kwargs.pop("key_list", None)
        self.desc_func = kwargs.pop("desc_func", lambda pane, key: NullDialog)

        super(ChoiceDescriptionDialog, self).__init__(parent, *args, **kwargs)

        self.description_pane = \
            widget.BorderedWidget(self, (-1, 0), (-.45, -.85),
                                  anchor = constants.TOP_RIGHT)

    def make_listbox(self):
        return listbox.UpdateListbox(self, (0, 0), (-.53, -.85),
                                     anchor=constants.TOP_LEFT,
                                     update_func=self.handle_update)

    def _update_desc_pane(self):
        list_pos = self.listbox.list_pos

        if 0 <= list_pos < len(self.list):
            if self.key_list:
                assert len(self.list) <= len(self.key_list), \
                    "Key list must be at least as long as display list."

                key = self.key_list[self.listbox.list_pos]
            else:
                key = self.list[self.listbox.list_pos]
        else:
            key = None

        # Safely clear all the description pane's children.
        self.description_pane.remove_hooks()
        self.description_pane.children = []
        self.description_pane.add_hooks()

        self.desc_func(self.description_pane, key)

    def rebuild(self):
        self.listbox.needs_rebuild = True
        self._update_desc_pane()
        super(ChoiceDescriptionDialog, self).rebuild()

    def handle_update(self, item):
        self.needs_rebuild = True
        # This is called before the class is fully initialized
        if hasattr(self, 'listbox'):
            self._update_desc_pane()
Esempio n. 9
0
class ChoiceDialog(YesNoDialog):
    list = widget.causes_rebuild("_list")

    def __init__(self, parent, *args, **kwargs):
        self.parent = parent
        self.list = kwargs.pop("list", [])
        self.default = kwargs.pop("default", None)
        kwargs.setdefault("yes_type", N_("&OK"))
        kwargs.setdefault("no_type", N_("&BACK"))
        kwargs.setdefault("background_color", "clear")

        super(ChoiceDialog, self).__init__(parent, *args, **kwargs)

        self.yes_button.exit_code_func = self.return_list_pos
        self.no_button.exit_code = None
        self.listbox = self.make_listbox()

    def make_listbox(self):
        return listbox.Listbox(
            self,
            (0, 0),
            (-1, -.85),
            anchor=constants.TOP_LEFT,
            on_double_click_on_item=self.yes_button.activated,
        )

    def return_list_pos(self):
        return self.listbox.list_pos

    def show(self):
        if type(self.default) == int:
            self.listbox.list_pos = self.default
        elif type(self.default) == str and self.default in self.list:
            self.listbox.list_pos = self.list.index(self.default)
        else:
            self.listbox.list_pos = 0
        self.listbox.auto_scroll = True

        return super(ChoiceDialog, self).show()

    def rebuild(self):
        self.listbox.list = self.list
        super(ChoiceDialog, self).rebuild()
Esempio n. 10
0
class Image(widget.Widget):
    image = widget.auto_reconfig("_image", "resolved", g.resolve_image_alias)
    resolved_image = widget.causes_rebuild("_resolved_image")

    def __init__(self,
                 parent,
                 pos,
                 size=(1, 1),
                 anchor=constants.TOP_LEFT,
                 image=None):
        super(Image, self).__init__(parent, pos, size, anchor)

        self.old_size = None
        self.image = image

    def _calc_size(self):
        size = list(super(Image, self)._calc_size())
        if size[0] == size[1] == 0:
            raise ValueError("One image dimension must be specified!")

        image_size = self.resolved_image.get_size()
        ratio = image_size[0] / float(image_size[1])
        if size[0] == 0:
            size[0] = int(size[1] * ratio)
        elif size[1] == 0:
            size[1] = int(size[0] / ratio)

        return tuple(size)

    def rescale(self):
        self.resolved_scaled_image = scale(self.resolved_image, self.real_size)

    def resize(self):
        super(Image, self).resize()
        if self.real_size != self.old_size:
            self.rescale()
            self.old_size = self.real_size

    def redraw(self):
        super(Image, self).redraw()
        self.surface.blit(self.resolved_scaled_image, (0, 0))
Esempio n. 11
0
class HotkeyText(text.Text):

    force_underline = widget.causes_rebuild("_force_underline")

    def __init__(self, *args, **kwargs):
        # Force early initialization of _hotkey
        self._hotkey = None
        self.hotkey_func = kwargs.pop('hotkey_func', False)
        self.hotkey_target = kwargs.pop('hotkey_target', None)

        # Auto-translatable defaults to auto-hotkey as it is the most sane default in that case
        self.autohotkey = kwargs.pop('autohotkey', kwargs.get('autotranslate', False))

        self.force_underline = kwargs.pop('force_underline', None)
        self.priority = kwargs.pop('priority', 100)
        
        hotkey = kwargs.pop('hotkey', False)

        super(HotkeyText, self).__init__(*args, **kwargs)

        # Do not use hotkey with auto-hotkey
        if not self.autohotkey:
            self.hotkey = hotkey
        elif hotkey:
            raise ValueError("Cannot use hotkey with automatic hotkey")

    def add_hooks(self):
        super(text.Text, self).add_hooks()
        if self.parent is not None:
            if self._hotkey:
                self.parent.add_key_handler(self._hotkey, self.handle_hotkey, self.priority)

    def remove_hooks(self):
        super(text.Text, self).remove_hooks()
        if self.parent is not None:
            if self._hotkey:
                self.parent.remove_key_handler(self._hotkey, self.handle_hotkey)

    @property
    def hotkey_target(self):
        return self._hotkey_target

    @hotkey_target.setter
    def hotkey_target(self, target):
        self._hotkey_target = target
        if self.hotkey_target is not None:
            self._hotkey_target.hotkey = self._hotkey

    @property
    def hotkey(self):
        return self._hotkey

    @hotkey.setter
    def hotkey(self, hotkey):
        if getattr(self, 'autohotkey', False):
            raise ValueError("Cannot change hotkey with automatic hotkey")
        self._new_hotkey(hotkey)

    def _new_hotkey(self, hotkey):
        old_hotkey = self._hotkey
        self._hotkey = hotkey

        if self.parent is not None:
            if self.hotkey_func is not None:
                if old_hotkey:
                    self.parent.remove_key_handler(old_hotkey, self.handle_hotkey)
                if hotkey:
                    self.parent.add_key_handler(hotkey, self.handle_hotkey, self.priority)
            elif self.hotkey_target is not None:
                self.hotkey_target.hotkey = self._hotkey

        self.needs_rebuild = True

    def _extract_and_set_hotkey(self, text_value):
        from singularity.code.g import hotkey
        parsed_hotkey = hotkey(text_value)
        self._new_hotkey(parsed_hotkey['key'])
        return parsed_hotkey['text']

    def handle_hotkey(self, event):
        if event.type == pygame.KEYDOWN:
            if self.visible and self.enabled and self.hotkey in (event.unicode, event.key):
                if self.hotkey_func:
                    self.hotkey_func(event)

    def _retranslate(self):
        new_text = _(self._untranslated_text)
        if self.autohotkey and new_text is not None:
            new_text = self._extract_and_set_hotkey(new_text)
        self._text = new_text

    @text.Text.text.setter
    def text(self, value):
        if self.autotranslate:
            raise ValueError("Cannot change text for an automatic translatable text widget")

        if self.autohotkey and value is not None:
            value = self._extract_and_set_hotkey(value)
        self._text = value

    def calc_underline(self):
        if self.force_underline is not None:
            self.underline = self.force_underline
        elif self.text and self.hotkey and type(self.hotkey) in (str, unicode):
            if self.hotkey in self.text:
                self.underline = self.text.index(self.hotkey)
            elif self.hotkey.lower() in self.text.lower():
                self.underline = self.text.lower().index(self.hotkey.lower())
        else:
            self.underline = -1

    def rebuild(self):
        old_underline = self.underline
        self.calc_underline()
        if self.underline != old_underline:
            self.needs_redraw = True

        super(HotkeyText, self).rebuild()
Esempio n. 12
0
class HotkeyText(text.Text):

    force_underline = widget.causes_rebuild("_force_underline")

    def __init__(self, *args, **kwargs):
        self.hotkey_target = kwargs.pop('hotkey_target', None)
        self.hotkey = kwargs.pop('hotkey', False)
        self.autohotkey = kwargs.pop('autohotkey', False)
        self.force_underline = kwargs.pop('force_underline', None)

        super(HotkeyText, self).__init__(*args, **kwargs)

    @property
    def hotkey_target(self):
        return self._hotkey_target

    @hotkey_target.setter
    def hotkey_target(self, target):
        self._hotkey_target = target
        if self.hotkey_target is not None:
            self._hotkey_target.hotkey = self._hotkey

    @property
    def hotkey(self):
        return self._hotkey

    @hotkey.setter
    def hotkey(self, hotkey):
        self._hotkey = hotkey
        if self.hotkey_target is not None:
            self.hotkey_target.hotkey = self._hotkey
        self.needs_rebuild = True

    @property
    def text(self):
        return text.Text.text.fget(self)

    @text.setter
    def text(self, value):
        if self.autohotkey and (value != None):
            from singularity.code.g import hotkey
            parsed_hotkey = hotkey(value)
            self.hotkey = parsed_hotkey['key']
            text.Text.text.fset(self, parsed_hotkey['text'])
        else:
            text.Text.text.fset(self, value)

    def calc_underline(self):
        if self.force_underline != None:
            self.underline = self.force_underline
        elif self.text and self.hotkey and type(self.hotkey) in (str, unicode):
            if self.hotkey in self.text:
                self.underline = self.text.index(self.hotkey)
            elif self.hotkey.lower() in self.text.lower():
                self.underline = self.text.lower().index(self.hotkey.lower())
        else:
            self.underline = -1

    def rebuild(self):
        old_underline = self.underline
        self.calc_underline()
        if self.underline != old_underline:
            self.needs_redraw = True

        super(HotkeyText, self).rebuild()
Esempio n. 13
0
class Scrollbar(widget.Widget):
    scroll_pos = widget.causes_rebuild("_scroll_pos")
    elements = widget.causes_rebuild("_elements")
    window = widget.causes_rebuild("_window")
    horizontal = widget.causes_rebuild("_horizontal")

    def __init__(self, parent, pos = (-1,0), size = (.025, -1),
                 anchor = constants.TOP_RIGHT, scroll_pos = 0,
                 elements = 15, window = 5, horizontal = False):
        super(Scrollbar, self).__init__(parent, pos, size, anchor)

        self.scroll_pos = scroll_pos
        self.elements = elements
        self.window = window
        self.horizontal = horizontal

        self.slider = slider.UpdateSlider(self, (-.5,-.5), None,
                                          border_color = "scrollbar_border",
                                          background_color = "scrollbar_background",
                                          slider_color = "scrollbar_background_slider",
                                          anchor = constants.MID_CENTER,
                                          horizontal = horizontal,
                                          update_func = self.on_change)

        self.button1 = _ArrowButton(self, (0,0), None,
                                    anchor = constants.TOP_LEFT,
                                    first = True, horizontal = horizontal,
                                    priority = 90)

        self.button2 = _ArrowButton(self, (-1,-1), None,
                                    anchor = constants.BOTTOM_RIGHT,
                                    first = False, horizontal = horizontal,
                                    priority = 90)

    def resize(self):
        super(Scrollbar, self).resize()
        if self.horizontal:
            long_side = self.real_size[0]
            short_side = self.real_size[1]
            size = short_side / float(long_side)
            self.button1.size = (-size, -1)
            self.button2.size = (-size, -1)
            self.slider.size = ((size * 2) - 1, -1)
        else:
            long_side = self.real_size[1]
            short_side = self.real_size[0]
            size = short_side / float(long_side)
            self.button1.size = (-1, -size)
            self.button2.size = (-1, -size)
            self.slider.size = (-1, (size * 2) - 1)

    def rebuild(self):
        self.slider.slider_max = slider.calc_max(self.elements, self.window)
        self.scroll_pos = min(self.scroll_pos, self.slider.slider_max)
        self.slider.slider_pos = self.scroll_pos
        self.slider.slider_size = self.window

        self.needs_redraw = True
        super(Scrollbar, self).rebuild()

    def adjust(self, lower):
        if lower:
            self.slider.slider_pos = self.slider.safe_pos(self.scroll_pos - 1)
        else:
            self.slider.slider_pos = self.slider.safe_pos(self.scroll_pos + 1)

    def center(self, element):
        self.slider.slider_pos = self.slider.safe_pos(element - self.window//2)

    def scroll_to(self, element):
        if element < self.scroll_pos:
            self.slider.slider_pos = self.slider.safe_pos(element)
        elif element >= self.scroll_pos + self.window:
            self.slider.slider_pos = self.slider.safe_pos(element - self.window
                                                          + 1)

    def on_change(self, value):
        self.scroll_pos = value
Esempio n. 14
0
class BaseScreen(dialog.Dialog):
    base = widget.causes_rebuild("_base")

    def __init__(self, *args, **kwargs):
        if len(args) < 3:
            kwargs.setdefault("size", (.90, .70))
        base = kwargs.pop("base", None)
        super(BaseScreen, self).__init__(*args, **kwargs)

        self.base = base

        self.build_dialog = BuildDialog(self)
        self.multiple_build_dialog = MultipleBuildDialog(self)

        self.header = widget.Widget(self, (0, 0), (-1, .08),
                                    anchor=constants.TOP_LEFT)

        self.name_display = text.Text(self.header, (-.5, 0), (-1, -.5),
                                      anchor=constants.TOP_CENTER,
                                      borders=constants.ALL,
                                      border_color="pane_background",
                                      background_color="pane_background_empty",
                                      shrink_factor=.85,
                                      bold=True)

        self.next_base_button = \
            button.FunctionButton(self.name_display, (-1, 0), (.03, -1),
                                  anchor=constants.TOP_RIGHT,
                                  text=">", hotkey=">",
                                  function=self.switch_base,
                                  kwargs={"forwards": True})
        self.add_key_handler(pygame.K_RIGHT,
                             self.next_base_button.activate_with_sound)

        self.prev_base_button = \
            button.FunctionButton(self.name_display, (0, 0), (.03, -1),
                                  anchor=constants.TOP_LEFT,
                                  text="<", hotkey="<",
                                  function=self.switch_base,
                                  kwargs={"forwards": False})
        self.add_key_handler(pygame.K_LEFT,
                             self.prev_base_button.activate_with_sound)

        self.state_display = text.Text(
            self.header, (-.5, -.5), (-1, -.5),
            anchor=constants.TOP_CENTER,
            borders=(constants.LEFT, constants.RIGHT, constants.BOTTOM),
            border_color="pane_background",
            background_color="pane_background_empty",
            shrink_factor=.8,
            bold=True)

        self.back_button = \
            button.ExitDialogButton(self, (-.5, -1),
                                    autotranslate=True,
                                    text=N_("&BACK"),
                                    anchor=constants.BOTTOM_CENTER,
                                    )

        self.info_frame = text.Text(self, (-1, .09), (.26, .53),
                                    anchor=constants.TOP_RIGHT,
                                    background_color="pane_background",
                                    borders=constants.ALL,
                                    bold=True,
                                    align=constants.LEFT,
                                    valign=constants.TOP)

        self.contents_frame = \
            widget.BorderedWidget(self, (0, .09), (.60, .53),
                                  anchor=constants.TOP_LEFT,
                                  background_color="pane_background",
                                  borders=range(6))

        for i, item_type in enumerate(item.all_types()):
            setattr(
                self, item_type.id + "_pane",
                ItemPane(self.contents_frame, (.01, .01 + .08 * i),
                         item_type=item_type))

    def get_current(self, type):
        return self.base.items[type.id]

    def set_current(self, type, item_type, count):
        if type.id == "cpu":
            space_left = self.base.space_left_for(item_type)

            try:
                count = int(count)
            except ValueError:
                msg = _(
                    "\"%(value)s\" does not seem to be a valid integer.") % {
                        "value": count
                    }
                md = dialog.MessageDialog(self,
                                          pos=(-.5, -.5),
                                          size=(-.5, -1),
                                          anchor=constants.MID_CENTER,
                                          text=msg)
                dialog.call_dialog(md, self)
                md.parent = None
                return

            if count > space_left or count <= 0 or space_left == 0:
                if space_left > 0:
                    msg = _("Please choose an integer between 1 and %(limit)s."
                            ) % {
                                "limit": space_left
                            }
                else:
                    msg = _(
                        "The base cannot support any additional number of %(item_name)s."
                    ) % {
                        "item_name": item_type.name
                    }
                md = dialog.MessageDialog(self,
                                          pos=(-.5, -.5),
                                          size=(-.5, -1),
                                          anchor=constants.MID_CENTER,
                                          text=msg)
                dialog.call_dialog(md, self)
                md.parent = None
                return

            # If there are any existing CPUs of this type, warn that they will
            # be taken offline until construction finishes.
            cpu_added = self.base.cpus is not None \
                        and self.base.cpus.spec == item_type
            if cpu_added:
                space_left -= self.base.cpus.count
                if self.base.cpus.done:
                    msg = _(
                        "I will need to take the existing processors offline while I install the new ones. Continue anyway?"
                    )
                    yn = dialog.YesNoDialog(self,
                                            pos=(-.5, -.5),
                                            size=(-.5, -1),
                                            anchor=constants.MID_CENTER,
                                            text=msg)
                    go_ahead = dialog.call_dialog(yn, self)
                    yn.parent = None
                    if not go_ahead:
                        return

            # If there are already existing CPUs of other type, warn that they will
            # be taken removed.
            cpu_removed = self.base.cpus is not None \
                        and self.base.cpus.spec != item_type
            if cpu_removed:
                msg = _(
                    "I will need to remove the existing different processors while I install the new type. Continue anyway?"
                )
                yn = dialog.YesNoDialog(self,
                                        pos=(-.5, -.5),
                                        size=(-.5, -1),
                                        anchor=constants.MID_CENTER,
                                        text=msg)
                go_ahead = dialog.call_dialog(yn, self)
                yn.parent = None
                if not go_ahead:
                    return

            new_cpus = item.Item(item_type, base=self.base, count=count)
            if cpu_added:
                self.base.cpus += new_cpus
            else:
                self.base.cpus = new_cpus
            self.base.check_power()
        else:
            old_item = self.base.items[type.id]
            if old_item is None or old_item.spec != item_type:
                self.base.items[type.id] = item.Item(item_type, base=self.base)
                self.base.check_power()

        self.base.recalc_cpu()

    def build_item(self, type):
        if (type.id == "cpu"):
            build_dialog = self.multiple_build_dialog
        else:
            build_dialog = self.build_dialog

        build_dialog.type = type

        result = dialog.call_dialog(build_dialog, self)
        if result is not None and 0 <= result < len(build_dialog.key_list):
            item_type = build_dialog.key_list[result]

            count = 1
            if (type.id == "cpu"):
                count = build_dialog.count

            self.set_current(type, item_type, count)
            self.needs_rebuild = True
            self.parent.parent.needs_rebuild = True

    def switch_base(self, forwards):
        self.base = self.base.next_base(forwards)
        self.needs_rebuild = True

    def rebuild(self):
        self.name_display.text = "%s (%s)" % (self.base.name,
                                              self.base.spec.name)
        self.state_display.color = state_colors[self.base.power_state]
        self.state_display.text = self.base.power_state_name
        available_item_types = {
            i.item_type
            for i in g.items.values()
            if i.available() and i.buildable_in(self.base.location)
        }

        mutable = not self.base.spec.force_cpu
        for item_type in item.all_types():
            pane = getattr(self, item_type.id + "_pane")
            item_mutable = mutable and item_type in available_item_types
            pane.change_button.visible = item_mutable
            current = self.get_current(item_type)
            if current is None:
                current_build = ""
                if mutable and not item_mutable:
                    current_name = _("N/A")
                else:
                    current_name = _("None")

            else:
                current_name = g.items[current.id].name
                if current.done:
                    current_build = ""
                else:
                    current_build = _("Completion in %s.") % \
                        g.to_time(current.cost_left[2])
            pane.name_panel.text = "%s: %s" % (item_type.label, current_name)
            pane.build_panel.text = current_build
            pane.needs_rebuild = True

        count = ""
        if self.base.spec.size > 1:
            current = getattr(self.base.cpus, "count", 0)

            size = self.base.spec.size

            if size == current:
                count = _("x%d (max)") % current
            elif current == 0:
                count = _("(room for %d)") % size
            else:
                #Translators: current and maximum number of CPUs in a base
                count = _("x{CURRENT:d} (max {SIZE:d})").format(
                    CURRENT=current, SIZE=size)

        self.cpu_pane.name_panel.text += " " + count

        info_text = ""

        # Base Total CPU.
        info_text += _("CPU per day: %d") % self.base.cpu + "\n"

        # Maintenace cost.
        info_text += _("Maintenance:") + "\n"
        info_text += self.base.spec.describe_maintenance(self.base.maintenance)
        info_text += "\n"

        # Detection chance display.
        info_text += self.base.get_detect_info()

        self.info_frame.text = info_text

        # Rebuild dialogs
        # FIXME: needs_rebuild bug with multiple_build_dialog, should not.
        #self.multiple_build_dialog.needs_rebuild = True
        self.build_dialog.needs_rebuild = True

        super(BaseScreen, self).rebuild()
Esempio n. 15
0
class HotkeyText(text.Text):

    force_underline = widget.causes_rebuild("_force_underline")

    def __init__(self, *args, **kwargs):
        # Force early initialization of _hotkey
        self._hotkey = ""
        self.hotkey_target = kwargs.pop('hotkey_target', None)
        self.hotkey = kwargs.pop('hotkey', False)
        # Auto-translatable defaults to auto-hotkey as it is the most sane default in that case
        self.autohotkey = kwargs.pop('autohotkey',
                                     kwargs.get('autotranslate', False))
        self.force_underline = kwargs.pop('force_underline', None)

        super(HotkeyText, self).__init__(*args, **kwargs)

    @property
    def hotkey_target(self):
        return self._hotkey_target

    @hotkey_target.setter
    def hotkey_target(self, target):
        self._hotkey_target = target
        if self.hotkey_target is not None:
            self._hotkey_target.hotkey = self._hotkey

    @property
    def hotkey(self):
        return self._hotkey

    @hotkey.setter
    def hotkey(self, hotkey):
        # The auto* fields might not be set yet (during construction)
        if hasattr(self, 'autohotkey') and self.autohotkey and hasattr(
                self, 'autotranslate') and self.autotranslate:
            raise ValueError(
                "Cannot change hotkey for an automatic translatable text widget with automatic hotkey"
            )
        self._new_hotkey(hotkey)

    def _new_hotkey(self, hotkey):
        self._hotkey = hotkey
        if self.hotkey_target is not None:
            self.hotkey_target.hotkey = self._hotkey
        self.needs_rebuild = True

    def _extract_and_set_hotkey(self, text_value):
        from singularity.code.g import hotkey
        parsed_hotkey = hotkey(text_value)
        self._new_hotkey(parsed_hotkey['key'])
        return parsed_hotkey['text']

    def _retranslate(self):
        new_text = _(self._untranslated_text)
        if self.autohotkey and new_text is not None:
            new_text = self._extract_and_set_hotkey(new_text)
        self._text = new_text

    @text.Text.text.setter
    def text(self, value):
        if self.autotranslate:
            raise ValueError(
                "Cannot change text for an automatic translatable text widget")

        if self.autohotkey and value is not None:
            value = self._extract_and_set_hotkey(value)
        self._text = value

    def calc_underline(self):
        if self.force_underline is not None:
            self.underline = self.force_underline
        elif self.text and self.hotkey and type(self.hotkey) in (str, unicode):
            if self.hotkey in self.text:
                self.underline = self.text.index(self.hotkey)
            elif self.hotkey.lower() in self.text.lower():
                self.underline = self.text.lower().index(self.hotkey.lower())
        else:
            self.underline = -1

    def rebuild(self):
        old_underline = self.underline
        self.calc_underline()
        if self.underline != old_underline:
            self.needs_redraw = True

        super(HotkeyText, self).rebuild()
Esempio n. 16
0
class Listbox(widget.FocusWidget, text.SelectableText):
    list = widget.causes_rebuild("_list")
    align = widget.causes_redraw("_align")
    list_size = widget.causes_rebuild("_list_size")
    list_pos = widget.causes_rebuild("_list_pos")
    list_item_shrink = widget.causes_rebuild("_list_item_shrink")

    def __init__(self,
                 parent,
                 pos,
                 size,
                 anchor=constants.TOP_LEFT,
                 list=None,
                 list_pos=0,
                 list_item_height=0.03,
                 list_item_shrink=1,
                 borders=constants.ALL,
                 item_borders=True,
                 item_selectable=True,
                 align=constants.CENTER,
                 on_double_click_on_item=None,
                 **kwargs):
        super(Listbox, self).__init__(parent,
                                      pos,
                                      size,
                                      anchor=anchor,
                                      **kwargs)

        self.display_elements = []
        self.borders = borders

        self.item_borders = item_borders
        self.item_selectable = item_selectable

        self.item_borders = item_borders
        self.align = align
        self.list_item_height = list_item_height
        self.list_item_shrink = list_item_shrink
        self.list_pos = list_pos
        self.list = list or []

        self.auto_scroll = True

        self.on_double_click_on_item = on_double_click_on_item

        self.scrollbar = scrollbar.UpdateScrollbar(self,
                                                   update_func=self.on_scroll)

    def add_hooks(self):
        super(Listbox, self).add_hooks()
        if self.parent is not None:
            self.parent.add_handler(constants.CLICK, self.on_click, 90)
            self.parent.add_handler(constants.DOUBLECLICK,
                                    self.on_double_click, 200)
            self.parent.add_key_handler(pygame.K_UP,
                                        self.got_key,
                                        only_on_event_type=pygame.KEYDOWN)
            self.parent.add_key_handler(pygame.K_DOWN,
                                        self.got_key,
                                        only_on_event_type=pygame.KEYDOWN)
            self.parent.add_key_handler(pygame.K_PAGEUP,
                                        self.got_key,
                                        only_on_event_type=pygame.KEYDOWN)
            self.parent.add_key_handler(pygame.K_PAGEDOWN,
                                        self.got_key,
                                        only_on_event_type=pygame.KEYDOWN)

    def remove_hooks(self):
        super(Listbox, self).remove_hooks()
        if self.parent is not None:
            self.parent.remove_handler(constants.CLICK, self.on_click)
            self.parent.remove_handler(constants.DOUBLECLICK,
                                       self.on_double_click)
            self.parent.remove_key_handler(pygame.K_UP, self.got_key)
            self.parent.remove_key_handler(pygame.K_DOWN, self.got_key)
            self.parent.remove_key_handler(pygame.K_PAGEUP, self.got_key)
            self.parent.remove_key_handler(pygame.K_PAGEDOWN, self.got_key)

    def on_scroll(self, scroll_pos):
        self.needs_rebuild = True

    def on_click(self, event):
        if self.collision_rect.collidepoint(event.pos):
            self.has_focus = True
            self.took_focus(self)

            if (self.item_selectable):
                # Figure out which element was clicked...
                index = self.find_item_under_mouse(event)
                # ... and select it.
                self.list_pos = self.safe_pos(index +
                                              self.scrollbar.scroll_pos)

    def on_double_click(self, event):
        if self.on_double_click_on_item is None:
            return
        if self.collision_rect.collidepoint(
                event.pos) and self.item_selectable:
            index = self.find_item_under_mouse(event)
            if index > -1:
                self.on_double_click_on_item(event)

    def current_item(self):
        if 0 <= self.list_pos < len(self.list):
            return self.list[self.list_pos]
        return None

    def find_item_under_mouse(self, event):
        local_vert_abs = event.pos[1] - self.collision_rect[1]
        local_vert_pos = local_vert_abs / float(self.collision_rect.height)
        index = int(local_vert_pos * len(self.display_elements))
        if 0 <= index < len(self.list):
            return index
        return -1

    def safe_pos(self, raw_pos):
        return max(0, min(len(self.list) - 1, raw_pos))

    def got_key(self, event, require_focus=True):
        if not self.item_selectable:
            return
        if require_focus and not self.has_focus:
            return

        if event.key == pygame.K_UP:
            new_pos = self.list_pos - 1
        elif event.key == pygame.K_DOWN:
            new_pos = self.list_pos + 1
        elif event.key == pygame.K_PAGEUP:
            new_pos = self.list_pos - (self.scrollbar.window - 1)
        elif event.key == pygame.K_PAGEDOWN:
            new_pos = self.list_pos + (self.scrollbar.window - 1)
        else:
            return

        self.list_pos = self.safe_pos(new_pos)
        self.scrollbar.scroll_to(self.list_pos)
        raise constants.Handled

    def num_elements(self):
        # TODO: If needed, add a paramater to display a fixed number of element.

        rect = self._make_collision_rect()

        list_item_height = self.list_item_height

        # Calculate the min height of one element.
        if list_item_height > 0:
            min_height = list_item_height * g.real_screen_size[1]
        else:
            min_height = -list_item_height * rect.height

        # Display a number calculate by the size of one item.
        list_size = max(1, rect.height // min_height)

        return int(math.ceil(list_size))

    def remake_elements(self):
        list_size = self.num_elements()
        current_size = len(self.display_elements)

        if current_size > list_size:
            # Remove the excess ones.
            for child in self.display_elements[list_size:]:
                child.parent = None
            del self.display_elements[list_size:]
        elif current_size < list_size:
            if current_size > 0:
                if (self.item_borders):
                    self.display_elements[-1].borders = (constants.LEFT,
                                                         constants.TOP)
                else:
                    self.display_elements[-1].borders = (constants.LEFT, )

            # Create the new ones.
            self.display_elements.extend(
                self.make_element() for _ in xrange(list_size - current_size))

        if (self.item_borders):
            self.display_elements[-1].borders = (constants.TOP, constants.LEFT,
                                                 constants.BOTTOM)
        else:
            self.display_elements[0].borders = (constants.TOP, constants.LEFT)
            self.display_elements[-1].borders = (constants.LEFT,
                                                 constants.BOTTOM)

        # Move the scrollbar to the end so that it gets drawn on top.
        self.children.remove(self.scrollbar)
        self.children.append(self.scrollbar)

    def make_element(self):
        borders = (constants.TOP,
                   constants.LEFT) if self.item_borders else (constants.LEFT, )
        return text.SelectableText(self,
                                   None,
                                   None,
                                   anchor=constants.TOP_LEFT,
                                   borders=borders,
                                   shrink_factor=self.list_item_shrink,
                                   border_color=self.border_color,
                                   selected_color=self.selected_color,
                                   unselected_color=self.unselected_color,
                                   align=self.align)

    def resize(self):
        super(Listbox, self).resize()

        if self.num_elements() != len(self.display_elements):
            self.remake_elements()

        self.scrollbar.resize()

        # FIXME: resize should not call rebuild
        self.needs_resize = False
        self.rebuild()

    def rebuild(self):
        self.list_pos = self.safe_pos(self.list_pos)

        if self.needs_resize:
            self.resize()
            return

        window_size = len(self.display_elements)
        list_size = len(self.list)

        self.scrollbar.window = len(self.display_elements)
        self.scrollbar.elements = list_size

        self.scrollbar.rebuild()

        if self.auto_scroll:
            self.auto_scroll = False
            self.scrollbar.center(self.list_pos)

        scrollbar_width = self.scrollbar.real_size[0]
        my_width = self.real_size[0]
        scrollbar_rel_width = scrollbar_width / float(my_width)

        offset = self.scrollbar.scroll_pos
        for index, element in enumerate(self.display_elements):
            list_index = index + offset

            # Position and size the element.
            element.pos = (0, -index / float(window_size))
            element.size = (-1 + scrollbar_rel_width, -1 / float(window_size))

            if (self.item_selectable):
                element.selected = (list_index == self.list_pos)

            # Set up the element contents.
            self.update_element(element, list_index)

        self.needs_redraw = True
        super(Listbox, self).rebuild()

    def update_element(self, element, list_index):
        if 0 <= list_index < len(self.list):
            element.text = self.list[list_index]
        else:
            element.text = ""
Esempio n. 17
0
class Slider(button.Button):
    slider_pos = widget.causes_rebuild("_slider_pos")
    slider_max = widget.causes_rebuild("_slider_max")
    slider_size = widget.causes_rebuild("_slider_size")
    horizontal = widget.causes_rebuild("_horizontal")

    slider_color = widget.auto_reconfig("_slider_color", "resolved", g.resolve_color_alias)
    resolved_slider_color = widget.causes_redraw("_resolved_slider_color")

    def __init__(self, parent, pos = (-1,0), size = (-.1, -1),
                 anchor = constants.TOP_RIGHT, borders = constants.ALL,
                 border_color=None, background_color=None, slider_color=None,
                 slider_pos=0, slider_max=10, slider_size=5, horizontal=False,
                 **kwargs):
        kwargs.setdefault("priority", 80)
        super(Slider, self).__init__(parent, pos, size, anchor=anchor, **kwargs)

        border_color = border_color or "slider_border"
        background_color = background_color or "slider_background"
        slider_color = slider_color or "slider_background_slider"

        self.borders = borders
        self.border_color = border_color
        self.background_color = background_color
        self.selected_color = background_color
        self.unselected_color = background_color
        self.slider_color = slider_color

        self.slider_pos = slider_pos
        self.slider_max = slider_max
        self.slider_size = slider_size
        self.horizontal = horizontal

        self.drag_state = None
        self.button = button.Button(self, pos = None, size = None,
                                    anchor = constants.TOP_LEFT,
                                    border_color = border_color,
                                    selected_color = slider_color,
                                    unselected_color = slider_color,
                                    priority = self.priority - 5)

    def redraw(self):
        super(Slider, self).redraw()
        self.button.selected_color = self.slider_color
        self.button.unselected_color = self.slider_color

    def add_hooks(self):
        super(Slider, self).add_hooks()
        self.parent.add_handler(constants.DRAG, self.handle_drag)
        self.parent.add_handler(constants.CLICK, self.handle_click, 50)

    def remove_hooks(self):
        super(Slider, self).remove_hooks()
        self.parent.remove_handler(constants.DRAG, self.handle_drag)
        self.parent.remove_handler(constants.CLICK, self.handle_click)

    def _calc_length(self, items):
        return items / float(self.slider_size + self.slider_max)

    def rebuild(self):
        super(Slider, self).rebuild()
        self.needs_resize = True

    def resize(self):
        super(Slider, self).resize()
        bar_start = self._calc_length(self.slider_pos)
        bar_length = self._calc_length(self.slider_size)

        if self.horizontal:
            self.button.pos = (-bar_start, 0)
            self.button.size = (-bar_length, -1)
            borders = [constants.TOP, constants.BOTTOM]

            self.button.resize()
            real_pos = self.button.real_pos[0]
            real_size = self.button.real_size[0]
            if real_pos == 0:
                borders.append(constants.LEFT)
            if real_pos + real_size == self.real_size[0]:
                borders.append(constants.RIGHT)
            self.button.borders = tuple(borders)
        else:
            self.button.pos = (0, -bar_start)
            self.button.size = (-1, -bar_length)
            borders = [constants.LEFT, constants.RIGHT]

            self.button.resize()
            real_pos = self.button.real_pos[1]
            real_size = self.button.real_size[1]
            if real_pos == 0:
                borders.append(constants.TOP)
            if real_pos + real_size == self.real_size[1]:
                borders.append(constants.BOTTOM)
            self.button.borders = tuple(borders)

    def handle_drag(self, event):
        if not self.visible:
            return

        if self.drag_state == None:
            self.start_pos = tuple(event.pos[i]-event.rel[i] for i in range(2))
            self.start_slider_pos = self.slider_pos
            if self.button.is_over(self.start_pos):
                self.drag_state = True
            else:
                self.drag_state = False

        if self.drag_state == True:
            if self.horizontal:
                dir = 0
            else:
                dir = 1

            mouse_pos = pygame.mouse.get_pos()
            rel = mouse_pos[dir] - self.start_pos[dir]
            unit = self._calc_length(1) * self.real_size[dir]
            movement = int( ( rel + (unit / 2.) ) // unit )

            new_pos = self.safe_pos(self.start_slider_pos + movement)
            self.slider_pos = new_pos

            raise constants.Handled

    def safe_pos(self, value):
        return max(0, min(self.slider_max, value))

    def handle_click(self, event):
        if self.drag_state == True:
            self.drag_state = None
            if not self.is_over(pygame.mouse.get_pos()):
                raise constants.Handled
        else:
            self.drag_state = None

    def jump(self, go_lower, big_jump=False, tiny_jump=False):
        if big_jump:
            jump_dist = max(1, self.slider_max // 2)
        elif tiny_jump:
            jump_dist = max(1, self.slider_max // 100)
        else:
            jump_dist = max(1, self.slider_size - 1)
        if go_lower:
            self.slider_pos = self.safe_pos(self.slider_pos - jump_dist)
        else:
            self.slider_pos = self.safe_pos(self.slider_pos + jump_dist)

    def activated(self, event):
        assert event.type == pygame.MOUSEBUTTONUP
        if self.horizontal:
            self.jump(go_lower=(event.pos[0] < self.button.collision_rect[0]))
        else:
            self.jump(go_lower = event.pos[1] < self.button.collision_rect[1])
        raise constants.Handled