def show_resource_menu(self, slot, entry): position = self.widgets.index(entry) if self.resource_menu_shown: self.hide_resource_menu() self.resource_menu_shown = True vbox = self._gui.findChild(name="resources") lbl = widgets.Label(name="select_res_label", text=_("Select a resource:")) vbox.addChild(lbl) scrollarea = widgets.ScrollArea(name="resources_scrollarea") res_box = widgets.VBox() scrollarea.addChild(res_box) vbox.addChild(scrollarea) # TODO: use create_resource_selection_dialog from util/gui.py # hardcoded for 5 works better than vbox.width / button_width amount_per_line = 5 current_hbox = widgets.HBox(max_size="326,46") index = 1 settlement = entry.settlement() inventory = settlement.get_component(StorageComponent).inventory if settlement else None from horizons.gui.widgets.imagefillstatusbutton import ImageFillStatusButton for res_id in sorted(self.icon_for_resource): if ( res_id in self.instance.route.waypoints[position]["resource_list"] and slot.findChild(name="button").up_image.source is not self.icon_for_resource[res_id] ): continue cb = Callback(self.add_resource, slot, res_id, entry) if res_id == 0 or inventory is None: # no fillbar e.g. on dead settlement (shouldn't happen) or dummy slot button = ImageButton(size=(46, 46)) icon = self.icon_for_resource[res_id] button.up_image, button.down_image, button.hover_image = icon, icon, icon button.capture(cb) else: # button with fillbar amount = inventory[res_id] filled = int(float(inventory[res_id]) / float(inventory.get_limit(res_id)) * 100.0) button = ImageFillStatusButton.init_for_res( self.session.db, res_id, amount=amount, filled=filled, use_inactive_icon=False ) button.button.capture(cb) current_hbox.addChild(button) if index >= amount_per_line: index -= amount_per_line res_box.addChild(current_hbox) current_hbox = widgets.HBox(max_size="326,26") index += 1 current_hbox.addSpacer(widgets.Spacer()) # TODO this spacer does absolutely nothing. res_box.addChild(current_hbox) self._gui.adaptLayout() self._resource_selection_area_layout_hack_fix()
def create_resource_selection_dialog( on_click, inventory, db, widget="select_trade_resource.xml", res_filter=None, amount_per_line=None ): """Returns a container containing resource icons. @param on_click: called with resource id as parameter on clicks @param inventory: to determine fill status of resource slots @param db: main db instance @param widget: which xml file to use as a template. Default: tabwidget. Required since the resource bar also uses this code (no tabs there though). @param res_filter: callback to decide which icons to use. Default: show all @param amount_per_line: how many resource icons per line. Default: try to fit layout """ from horizons.gui.widgets.imagefillstatusbutton import ImageFillStatusButton dummy_icon_path = "content/gui/icons/resources/none_gray.png" dlg = load_uh_widget(widget) button_width = ImageFillStatusButton.CELL_SIZE[0] # used for dummy button vbox = dlg.findChild(name="resources") amount_per_line = amount_per_line or vbox.width // button_width # Add the zero element to the beginning that allows to remove the currently # sold/bought resource: resources = [0] + db.get_res(only_tradeable=True) current_hbox = HBox(name="hbox_0", padding=0) index = 1 for res_id in resources: # don't show resources that are already in the list if res_filter is not None and not res_filter(res_id): continue # create button (dummy one or real one) if res_id == 0 or inventory is None: button = ImageButton(size=(button_width, button_width), name="resource_icon_00") button.up_image, button.down_image, button.hover_image = (dummy_icon_path,) * 3 else: amount = inventory[res_id] filled = int(float(inventory[res_id]) / float(inventory.get_limit(res_id)) * 100.0) button = ImageFillStatusButton.init_for_res( db, res_id, amount=amount, filled=filled, uncached=True, use_inactive_icon=False ) # on click: add this res cb = Callback(on_click, res_id) if hasattr(button, "button"): # for imagefillstatusbuttons button.button.capture(cb) button.button.name = "resource_%d" % res_id else: button.capture(cb) button.name = "resource_%d" % res_id current_hbox.addChild(button) if index % amount_per_line == 0: vbox.addChild(current_hbox) box_id = index // amount_per_line current_hbox = HBox(name="hbox_%s" % box_id, padding=0) index += 1 vbox.addChild(current_hbox) vbox.adaptLayout() return dlg
def create_resource_selection_dialog(on_click, inventory, db, widget="select_trade_resource.xml", res_filter=None): """Returns a container containing resource icons @param on_click: called with resource id as parameter on clicks @param inventory: to determine fill status of resource slots @param db: main db instance @param widget: which xml file to use as a template. Default: tabwidget. Required since the resource bar also uses this code (no tabs there though). @param res_filter: callback to decide which icons to use. Default: show all """ from horizons.gui.widgets.imagefillstatusbutton import ImageFillStatusButton from fife.extensions.pychan.widgets import ImageButton dummy_icon_path = "content/gui/icons/resources/none_gray.png" dlg = load_uh_widget(widget) button_width = ImageFillStatusButton.DEFAULT_BUTTON_SIZE[0] # used for dummy button vbox = dlg.findChild(name="resources") amount_per_line = vbox.width / button_width current_hbox = pychan.widgets.HBox(name="hbox_0", padding=0) index = 1 resources = db.get_res(True) # Add the zero element to the beginning that allows to remove the currently # sold/bought resource for res_id in [0] + list(resources): # don't show resources that are already in the list if res_filter is not None and not res_filter(res_id): continue # create button (dummy one or real one) if res_id == 0: button = ImageButton(size=(button_width, button_width), name="resource_icon_00") button.up_image, button.down_image, button.hover_image = (dummy_icon_path,) * 3 else: amount = inventory[res_id] filled = int(float(inventory[res_id]) / float(inventory.get_limit(res_id)) * 100.0) button = ImageFillStatusButton.init_for_res( db, res_id, amount=amount, filled=filled, use_inactive_icon=False ) # on click: add this res cb = Callback(on_click, res_id) if hasattr(button, "button"): # for imagefillstatusbuttons button.button.capture(cb) else: button.capture(cb) current_hbox.addChild(button) if index % amount_per_line == 0 and index is not 0: vbox.addChild(current_hbox) current_hbox = pychan.widgets.HBox(name="hbox_%s" % (index / amount_per_line), padding=0) index += 1 # current_hbox.addSpacer(pychan.widgets.layout.Spacer) #TODO: proper alignment vbox.addChild(current_hbox) vbox.adaptLayout() return dlg
def _create_build_buttons(self, building_id, container): # {{mode}} in double braces because it is replaced as a second step path = "content/gui/icons/buildmenu/{id:03d}{{mode}}.png".format(id=building_id) helptext = self.instance.session.db.get_building_tooltip(building_id) build_button = ImageButton(name="build{id}".format(id=building_id), helptext=helptext) build_button.up_image = path.format(mode='') build_button.down_image = build_button.hover_image = path.format(mode='_h') build_button.capture(Callback(self.build_related, building_id)) return build_button
def create_resource_selection_dialog(on_click, inventory, db, widget='select_trade_resource.xml', res_filter=None, amount_per_line=None): """Returns a container containing resource icons. @param on_click: called with resource id as parameter on clicks @param inventory: to determine fill status of resource slots @param db: main db instance @param widget: which xml file to use as a template. Default: tabwidget. Required since the resource bar also uses this code (no tabs there though). @param res_filter: callback to decide which icons to use. Default: show all @param amount_per_line: how many resource icons per line. Default: try to fit layout """ from horizons.gui.widgets.imagefillstatusbutton import ImageFillStatusButton dummy_icon_path = "content/gui/icons/resources/none_gray.png" dlg = load_uh_widget(widget) button_width = ImageFillStatusButton.CELL_SIZE[0] # used for dummy button vbox = dlg.findChild(name="resources") amount_per_line = amount_per_line or vbox.width // button_width # Add the zero element to the beginning that allows to remove the currently # sold/bought resource: resources = [0] + db.get_res(only_tradeable=True) current_hbox = HBox(name="hbox_0", padding=0) index = 1 for res_id in resources: # don't show resources that are already in the list if res_filter is not None and not res_filter(res_id): continue # create button (dummy one or real one) if res_id == 0 or inventory is None: button = ImageButton( size=(button_width, button_width), name="resource_icon_00") button.up_image, button.down_image, button.hover_image = (dummy_icon_path,)*3 else: amount = inventory[res_id] filled = int(float(inventory[res_id]) / float(inventory.get_limit(res_id)) * 100.0) button = ImageFillStatusButton.init_for_res(db, res_id, amount=amount, filled=filled, uncached=True, use_inactive_icon=False) # on click: add this res cb = Callback(on_click, res_id) if hasattr(button, "button"): # for imagefillstatusbuttons button.button.capture( cb ) else: button.capture( cb ) current_hbox.addChild(button) if index % amount_per_line == 0: vbox.addChild(current_hbox) box_id = index // amount_per_line current_hbox = HBox(name="hbox_%s" % box_id, padding=0) index += 1 vbox.addChild(current_hbox) vbox.adaptLayout() return dlg
def __init__(self): self.page_widgets = {} self.dict_lt = {} self.dict_rt = {} self.widget = load_uh_widget(self.widget_xml, style=self.style) self.pickbelts_container_lt = self.widget.findChild(name="left_pickbelts") self.pickbelts_container_rt = self.widget.findChild(name="right_pickbelts") for i in range(len(self.sections)): self.page_widgets[i] = self.widget.findChild(name=self.sections[i][0]) # Create the required pickbelts for side in ('lt', 'rt'): for i in range(len(self.sections)): pickbelt = ImageButton(is_focusable=False) pickbelt.name = self.sections[i][0] + '_' + side pickbelt.text = self.sections[i][1] pickbelt.font = "small_tooltip" pickbelt.position = (self.pickbelt_start_pos[0]+5*i, self.pickbelt_start_pos[1]+70*i) pickbelt.capture(Callback(self.update_view, i), event_name="mouseClicked") if side == 'lt': pickbelt.up_image='content/gui/images/background/pickbelt_l.png' self.pickbelts_container_lt.addChild(pickbelt) self.dict_lt[i] = pickbelt else: pickbelt.up_image='content/gui/images/background/pickbelt_r.png' self.pickbelts_container_rt.addChild(pickbelt) self.dict_rt[i] = pickbelt self.widget.show() # Hack to initially setup the pickbelts properly self.update_view() self.widget.hide() # Hack to initially setup the pickbelts properly
def _create_build_buttons(self, building_id, container): # {{mode}} in double braces because it is replaced as a second step path = "content/gui/icons/buildmenu/{id:03d}{{mode}}.png".format( id=building_id) helptext = self.instance.session.db.get_building_tooltip(building_id) build_button = ImageButton(name="build{id}".format(id=building_id), helptext=helptext) build_button.up_image = path.format(mode='') build_button.down_image = build_button.hover_image = path.format( mode='_h') build_button.capture(Callback(self.build_related, building_id)) return build_button
def _add_line_to_gui(self, ship, sequence_number): sequence_number_label = widgets.Label(name = 'sequence_number_%d' % ship.worldid) sequence_number_label.text = unicode(sequence_number) sequence_number_label.min_size = sequence_number_label.max_size = (15, 20) ship_name = widgets.Label(name = 'ship_name_%d' % ship.worldid) ship_name.text = ship.get_component(NamedComponent).name ship_name.min_size = ship_name.max_size = (100, 20) rename_icon = ImageButton(name = 'rename_%d' % ship.worldid) rename_icon.up_image = "content/gui/images/background/rename_feather_20.png" rename_icon.hover_image = "content/gui/images/background/rename_feather_20_h.png" rename_icon.helptext = _("Click to change the name of this ship") rename_icon.max_size = (20, 20) # (width, height) ship_type = widgets.Label(name = 'ship_type_%d' % ship.worldid) ship_type.text = ship.classname ship_type.min_size = ship_type.max_size = (60, 20) weapons = widgets.Label(name = 'weapons_%d' % ship.worldid) if isinstance(ship, FightingShip): weapon_list = [] for weapon_id, amount in sorted(ship.get_weapon_storage()): weapon_list.append('%d %s' % (amount, self.session.db.get_res_name(weapon_id))) if weapon_list: weapons.text = u', '.join(weapon_list) else: #i18n There are no weapons equipped at the moment. weapons.text = _('None') else: weapons.text = _('N/A') weapons.min_size = weapons.max_size = (60, 20) health = widgets.Label(name = 'health_%d' % ship.worldid) health_component = ship.get_component(HealthComponent) health.text = u'%d/%d' % (health_component.health, health_component.max_health) health.min_size = health.max_size = (65, 20) status = widgets.Label(name = 'status_%d' % ship.worldid) status.text, status_position = ship.get_status() status.min_size = status.max_size = (320, 20) hbox = widgets.HBox() hbox.addChild(sequence_number_label) hbox.addChild(ship_name) hbox.addChild(rename_icon) hbox.addChild(ship_type) hbox.addChild(weapons) hbox.addChild(health) hbox.addChild(status) self._content_vbox.addChild(hbox) return (ship_name, rename_icon, status, status_position)
def __init__( self, items=None, default_item_n=0, circular=True, min_size=(50, 14), max_size=(50, 14), font=None, background_color=None, **kwargs ): self._current_index = 0 self._items = map(unicode, items) if items is not None else [] self._default_item_n = default_item_n self._min_size = min_size self.circular = circular padding = 1 self.text_field = TextField(background_color=background_color) self.decrease_button = ImageButton( up_image="gui/buttons/left_arrow_up.png", down_image="gui/buttons/left_arrow_down.png", hover_image="gui/buttons/left_arrow_hover.png", ) # FIXME Technomage 2011-03-05: This is a hack to prevent the button # from expanding width-wise and skewing the TextField orientation. # Max size shouldn't be hard-coded like this though... self.decrease_button.max_size = (12, 12) self.decrease_button.capture(self.previousItem) self.increase_button = ImageButton( up_image="gui/buttons/right_arrow_up.png", down_image="gui/buttons/right_arrow_down.png", hover_image="gui/buttons/right_arrow_hover.png", ) self.increase_button.capture(self.nextItem) increase_button_width, increase_button_height = self.increase_button.size decrease_button_width, decrease_button_height = self.decrease_button.size self.text_field = TextField(font=font) text_field_width = min_size[0] - (2 * padding) - (increase_button_width + decrease_button_width) self.text_field.min_width = text_field_width self.text_field.max_width = text_field_width self.text_field.min_height = min_size[1] self.text_field.text = self.items[default_item_n] if len(self.items) > 0 else u"" HBox.__init__(self, **kwargs) self.opaque = 0 self.padding = padding self.margins = (0, 0) self.addChildren(self.decrease_button, self.text_field, self.increase_button)
def __init__(self): self.page_widgets = {} self.widget = load_uh_widget(self.widget_xml, center_widget=True) # Lists holding pickbelt ImageButtons, placed to the left/right of the book self.buttons = {'left': [], 'right': []} for i, (name, text) in enumerate(self.sections): self.page_widgets[i] = self.widget.findChild(name=name) # Create the required pickbelts for i, (name, text) in enumerate(self.sections): for side in self.buttons: pickbelt = ImageButton(is_focusable=False, text=text) pickbelt.name = name + '_' + side pickbelt.up_image = 'content/gui/images/background/pickbelt_%s.png' % side pickbelt.font = "small_tooltip" pickbelt.capture(Callback(self.update_view, i), event_name="mouseClicked") start_x, start_y = self.pickbelt_start_pos pickbelt.position = (start_x + 5*i, start_y + 70*i) container = self.widget.findChild(name="%s_pickbelts" % side) container.addChild(pickbelt) self.buttons[side].append(pickbelt) self.widget.show() # Hack to initially setup the pickbelts properly self.update_view() self.widget.hide() # Hack to initially setup the pickbelts properly
def _add_line_to_gui(self, settlement, sequence_number): sequence_number_label = widgets.Label(name = 'sequence_number_%d' % settlement.worldid) sequence_number_label.text = unicode(sequence_number) sequence_number_label.min_size = sequence_number_label.max_size = (15, 20) name = widgets.Label(name = 'name_%d' % settlement.worldid) name.text = settlement.get_component(NamedComponent).name name.min_size = name.max_size = (175, 20) rename_icon = ImageButton(name = 'rename_%d' % settlement.worldid) rename_icon.up_image = "content/gui/images/background/rename_feather_20.png" rename_icon.hover_image = "content/gui/images/background/rename_feather_20_h.png" rename_icon.helptext = _("Click to change the name of your settlement") rename_icon.max_size = (20, 20) # (width, height) self._add_generic_line_to_gui(settlement.worldid, [sequence_number_label, name, rename_icon], settlement.inhabitants, settlement.cumulative_taxes, settlement.cumulative_running_costs) return name, rename_icon
def _create_build_buttons(self, building_id, container): level = Entities.buildings[building_id].settler_level # Check if the level of the building is lower or same as the settler level if level <= self.instance.owner.settler_level: # {{mode}} in double braces because it is replaced as a second step path = "content/gui/icons/buildmenu/{id:03d}{{mode}}.png".format(id=building_id) helptext = self.instance.session.db.get_building_tooltip(building_id) build_button = ImageButton(name="build{id}".format(id=building_id), \ helptext=helptext) build_button.up_image = path.format(mode='') build_button.down_image = path.format(mode='_h') build_button.hover_image = path.format(mode='_h') build_button.capture(Callback(self.buildField, building_id)) container.findChild(name="build_button_container").addChild(build_button) build_button_bg = Icon(image="content/gui/images/buttons/buildmenu_button_bg.png") container.findChild(name="build_button_bg_container").addChild(build_button_bg) return True else: # No button built return False
def draw_widget(self): """ Updates whole messagewidget (all messages): draw icons. Inactive messages need their icon hovered to display their text again """ button_space = self.widget.findChild(name="button_space") button_space.removeAllChildren() # Remove old buttons for index, message in enumerate(self.active_messages): if (self.item + index) >= len(self.active_messages): # Only display most recent notifications continue button = ImageButton() button.name = str(index) button.up_image = message.up_image button.hover_image = message.hover_image button.down_image = message.down_image button.is_focusable = False # show text on hover events = { button.name + "/mouseEntered": Callback(self.show_text, index), button.name + "/mouseExited": self.hide_text, } # init callback to something callable to improve robustness callback = Callback(lambda: None) if message.x is not None and message.y is not None: # move camera to source of event on click, if there is a source callback = Callback.ChainedCallbacks( callback, # this makes it so the order of callback assignment doesn't matter Callback(self.session.view.center, message.x, message.y), Callback(self.session.ingame_gui.minimap.highlight, (message.x, message.y))) if message.type == "logbook": # open logbook to relevant page callback = Callback.ChainedCallbacks( callback, # this makes it so the order of callback assignment doesn't matter Callback(self.session.ingame_gui.logbook.show, message.created)) if callback: events[button.name] = callback button.mapEvents(events) button_space.addChild(button) button_space.resizeToContent() self.widget.size = button_space.size
def _init_tabs(self): """Add enough tabbuttons for all widgets.""" def on_tab_removal(tabwidget): # called when a tab is being removed (via weakref since tabs shouldn't have references to the parent tabwidget) # If one tab is removed, the whole tabwidget will die.. # This is easy usually the desired behaviour. if tabwidget(): tabwidget().on_remove() # Load buttons for index, tab in enumerate(self._tabs): # don't add a reference to the tab.add_remove_listener(Callback(on_tab_removal, weakref.ref(self))) container = Container(name="container_%s" % index) background = Icon(name="bg_%s" % index) button = ImageButton(name=str(index)) if self.current_tab is tab: background.image = tab.button_background_image_active button.up_image = tab.button_active_image else: background.image = tab.button_background_image button.up_image = tab.button_up_image button.down_image = tab.button_down_image button.hover_image = tab.button_hover_image button.is_focusable = False button.size = (50, 50) button.capture(Callback(self._show_tab, index)) if hasattr(tab, 'helptext') and tab.helptext is not None: button.helptext = tab.helptext container.size = background.size container.addChild(background) container.addChild(button) self.content.addChild(container) self.widget.size = (50, 55*len(self._tabs)) self.widget.adaptLayout() self._apply_layout_hack()
def __init__(self): self.page_widgets = {} self.dict_lt = {} self.dict_rt = {} self.widget = load_uh_widget(self.widget_xml, style=self.style) self.pickbelts_container_lt = self.widget.findChild( name="left_pickbelts") self.pickbelts_container_rt = self.widget.findChild( name="right_pickbelts") for i in range(len(self.sections)): self.page_widgets[i] = self.widget.findChild( name=self.sections[i][0]) # Create the required pickbelts for side in ('lt', 'rt'): for i in range(len(self.sections)): pickbelt = ImageButton(is_focusable=False) pickbelt.name = self.sections[i][0] + '_' + side pickbelt.text = self.sections[i][1] pickbelt.font = "small_tooltip" pickbelt.position = (self.pickbelt_start_pos[0] + 5 * i, self.pickbelt_start_pos[1] + 70 * i) pickbelt.capture(Callback(self.update_view, i), event_name="mouseClicked") if side == 'lt': pickbelt.up_image = 'content/gui/images/background/pickbelt_l.png' self.pickbelts_container_lt.addChild(pickbelt) self.dict_lt[i] = pickbelt else: pickbelt.up_image = 'content/gui/images/background/pickbelt_r.png' self.pickbelts_container_rt.addChild(pickbelt) self.dict_rt[i] = pickbelt self.widget.show() # Hack to initially setup the pickbelts properly self.update_view() self.widget.hide() # Hack to initially setup the pickbelts properly
def draw_widget(self): """ Updates whole messagewidget (all messages): draw icons. Inactive messages need their icon hovered to display their text again """ button_space = self.widget.findChild(name="button_space") button_space.removeAllChildren() # Remove old buttons for index, message in enumerate(self.active_messages): if (self.item + index) >= len(self.active_messages): # Only display most recent notifications continue button = ImageButton() button.name = str(index) button.up_image = message.up_image button.hover_image = message.hover_image button.down_image = message.down_image button.is_focusable = False # show text on hover events = { button.name + "/mouseEntered": Callback(self.show_text, index), button.name + "/mouseExited": self.hide_text, } # init callback to something callable to improve robustness callback = Callback(lambda: None) if message.x is not None and message.y is not None: # move camera to source of event on click, if there is a source callback = Callback.ChainedCallbacks( callback, # this makes it so the order of callback assignment doesn't matter Callback(self.session.view.center, message.x, message.y), Callback(self.session.ingame_gui.minimap.highlight, (message.x, message.y) ) ) if message.type == "logbook": # open logbook to relevant page callback = Callback.ChainedCallbacks( callback, # this makes it so the order of callback assignment doesn't matter Callback(self.session.ingame_gui.logbook.show, message.created) ) if callback: events[button.name] = callback button.mapEvents(events) button_space.addChild(button) button_space.resizeToContent() self.widget.size = button_space.size
def _init_tabs(self): """Add enough tabbuttons for all widgets.""" def on_tab_removal(tabwidget): # called when a tab is being removed (via weakref since tabs shouldn't have references to the parent tabwidget) # If one tab is removed, the whole tabwidget will die.. # This is easy usually the desired behaviour. if tabwidget(): tabwidget().on_remove() # Load buttons for index, tab in enumerate(self._tabs): # don't add a reference to the tab.add_remove_listener(Callback(on_tab_removal, weakref.ref(self))) container = Container(name="container_%s" % index) background = Icon(name="bg_%s" % index) button = ImageButton(name=str(index)) if self.current_tab is tab: background.image = tab.button_background_image_active button.up_image = tab.button_active_image else: background.image = tab.button_background_image button.up_image = tab.button_up_image button.down_image = tab.button_down_image button.hover_image = tab.button_hover_image button.is_focusable = False button.size = (50, 50) button.capture(Callback(self._show_tab, index)) if hasattr(tab, 'helptext') and tab.helptext is not None: button.helptext = tab.helptext container.size = background.size container.addChild(background) container.addChild(button) self.content.addChild(container) self.widget.size = (50, 55 * len(self._tabs)) self.widget.adaptLayout() self._apply_layout_hack()
class Spinner(HBox): ATTRIBUTES = HBox.ATTRIBUTES + [ListAttr("items"), IntAttr("default_item_n"), BoolAttr("circular")] def default_item_n(): def fget(self): return self._default_item_n def fset(self, index): if len(self.items) - 1 >= index: self._default_item_n = index self.text_field.text = self.items[index] else: error_message = "default_item_n exceeds number of items in spinner" raise ValueError(error_message) return locals() default_item_n = property(**default_item_n()) def items(): def fget(self): return self._items def fset(self, items): self._items = map(unicode, items) if self.default_item_n > len(items) - 1: self.default_item_n = 0 self.text_field.text = self.items[self.default_item_n] if len(self.items) > 0 else u"" return locals() items = property(**items()) def background_color(): def fget(self): return self.text_field.background_color def fset(self, background_color): self.text_field.background_color = background_color return locals() background_color = property(**background_color()) def font(): def fget(self): return self.text_field.font def fset(self, font): self.text_field.font = font return locals() font = property(**font()) def background_color(): def fget(self): return self.text_field.background_color def fset(self, background_color): self.text_field.background_color = background_color return locals() background_color = property(**background_color()) def min_size(): def fget(self): return self._min_size def fset(self, min_size): self._min_size = min_size self.decrease_button.capture(self.previousItem) increase_button_width, increase_button_height = self.increase_button.size decrease_button_width, decrease_button_height = self.decrease_button.size text_field_width = min_size[0] - (2 * self.padding) - (increase_button_width + decrease_button_width) self.text_field.min_width = text_field_width self.text_field.max_width = text_field_width self.text_field.min_height = min_size[1] return locals() min_size = property(**min_size()) def max_size(): def fget(self): return self._max_size def fset(self, max_size): self._max_size = max_size self.decrease_button.capture(self.previousItem) increase_button_width, increase_button_height = self.increase_button.size decrease_button_width, decrease_button_height = self.decrease_button.size text_field_width = max_size[0] - (2 * self.padding) - (increase_button_width + decrease_button_width) self.text_field.max_width = text_field_width self.text_field.max_height = max_size[1] return locals() max_size = property(**max_size()) def __init__( self, items=None, default_item_n=0, circular=True, min_size=(50, 14), max_size=(50, 14), font=None, background_color=None, **kwargs ): self._current_index = 0 self._items = map(unicode, items) if items is not None else [] self._default_item_n = default_item_n self._min_size = min_size self.circular = circular padding = 1 self.text_field = TextField(background_color=background_color) self.decrease_button = ImageButton( up_image="gui/buttons/left_arrow_up.png", down_image="gui/buttons/left_arrow_down.png", hover_image="gui/buttons/left_arrow_hover.png", ) # FIXME Technomage 2011-03-05: This is a hack to prevent the button # from expanding width-wise and skewing the TextField orientation. # Max size shouldn't be hard-coded like this though... self.decrease_button.max_size = (12, 12) self.decrease_button.capture(self.previousItem) self.increase_button = ImageButton( up_image="gui/buttons/right_arrow_up.png", down_image="gui/buttons/right_arrow_down.png", hover_image="gui/buttons/right_arrow_hover.png", ) self.increase_button.capture(self.nextItem) increase_button_width, increase_button_height = self.increase_button.size decrease_button_width, decrease_button_height = self.decrease_button.size self.text_field = TextField(font=font) text_field_width = min_size[0] - (2 * padding) - (increase_button_width + decrease_button_width) self.text_field.min_width = text_field_width self.text_field.max_width = text_field_width self.text_field.min_height = min_size[1] self.text_field.text = self.items[default_item_n] if len(self.items) > 0 else u"" HBox.__init__(self, **kwargs) self.opaque = 0 self.padding = padding self.margins = (0, 0) self.addChildren(self.decrease_button, self.text_field, self.increase_button) def nextItem(self, event, widget): if self.circular: if self._current_index < len(self.items) - 1: self._current_index += 1 else: self._current_index = 0 self.text_field.text = self.items[self._current_index] elif self._current_index < len(self.items) - 1: self._current_index += 1 self.text_field.text = self.items[self._current_index] def previousItem(self, event, widget): if self.circular: if self._current_index > 0: self._current_index -= 1 else: self._current_index = len(self.items) - 1 self.text_field.text = self.items[self._current_index] elif self._current_index > 0: self._current_index -= 1 self.text_field.text = self.items[self._current_index]