123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208 |
- from LUIObject import LUIObject
- from LUISprite import LUISprite
- from LUILabel import LUILabel
- from LUILayouts import LUICornerLayout, LUIHorizontalStretchedLayout
- from LUIInitialState import LUIInitialState
- from functools import partial
- __all__ = ["LUISelectbox"]
- class LUISelectbox(LUIObject):
- """ Selectbox widget, showing several options whereas the user can select
- only one. """
- def __init__(self, width=200, options=None, selected_option=None, **kwargs):
- """ Constructs a new selectbox with a given width """
- LUIObject.__init__(self, x=0, y=0, w=width+4, solid=True)
- LUIInitialState.init(self, kwargs)
- # The selectbox has a small border, to correct this we move it
- self.margin.left = -2
- self._bg_layout = LUIHorizontalStretchedLayout(parent=self, prefix="Selectbox", width="100%")
- self._label_container = LUIObject(self, x=10, y=0)
- self._label_container.set_size("100%", "100%")
- self._label_container.clip_bounds = (0,0,0,0)
- self._label = LUILabel(parent=self._label_container, text=u"Select an option ..")
- self._label.center_vertical = True
- self._drop_menu = LUISelectdrop(parent=self, width=width)
- self._drop_menu.top = self._bg_layout._sprite_right.height - 7
- self._drop_menu.topmost = True
- self._drop_open = False
- self._drop_menu.hide()
- self._options = []
- self._current_option_id = None
- if options is not None:
- self._options = options
- self._select_option(selected_option)
- def get_selected_option(self):
- """ Returns the selected option """
- return self._current_option_id
- def set_selected_option(self, option_id):
- """ Sets the selected option """
- raise NotImplementedError()
- selected_option = property(get_selected_option, set_selected_option)
- def _render_options(self):
- """ Internal method to render all available options """
- self._drop_menu._render_options(self._options)
- def get_options(self):
- """ Returns the list of options """
- return self._options
- def set_options(self, options):
- """ Sets the list of options, options should be a list containing entries
- whereas each entry is a tuple in the format (option_id, option_label).
- The option ID can be an arbitrary object, and will not get modified. """
- self._options = options
- self._current_option_id = None
- self._render_options()
- options = property(get_options, set_options)
- def _select_option(self, opt_id):
- """ Internal method to select an option """
- self._label.alpha = 1.0
- for elem_opt_id, opt_val in self._options:
- if opt_id == elem_opt_id:
- self._label.text = opt_val
- self._current_option_id = opt_id
- return
- self._label.alpha = 0.3
- # def on_mouseover(self, event):
- # """ Internal handle when the select-knob was hovered """
- # self._bg_layout.color = (0.9,0.9,0.9,1.0)
- # def on_mouseout(self, event):
- # """ Internal handle when the select-knob was no longer hovered """
- # self._bg_layout.color = (1,1,1,1.0)
- def on_click(self, event):
- """ On-Click handler """
- self.request_focus()
- if self._drop_open:
- self._close_drop()
- else:
- self._open_drop()
- def on_mousedown(self, event):
- """ Mousedown handler """
- self._bg_layout.alpha = 0.9
- def on_mouseup(self, event):
- """ Mouseup handler """
- self._bg_layout.alpha = 1
- def on_blur(self, event):
- """ Internal handler when the selectbox lost focus """
- if not self._drop_menu.focused:
- self._close_drop()
- def _open_drop(self):
- """ Internal method to show the dropdown menu """
- if not self._drop_open:
- self._render_options()
- self._drop_menu.show()
- self.request_focus()
- self._drop_open = True
- def _close_drop(self):
- """ Internal method to close the dropdown menu """
- if self._drop_open:
- self._drop_menu.hide()
- self._drop_open = False
- def _on_option_selected(self, opt_id):
- """ Internal method when an option got selected """
- self._select_option(opt_id)
- self._close_drop()
- class LUISelectdrop(LUIObject):
- """ Internal class used by the selectbox, representing the dropdown menu """
- def __init__(self, parent, width=200):
- LUIObject.__init__(self, x=0, y=0, w=width, h=1, solid=True)
- self._layout = LUICornerLayout(parent=self, image_prefix="Selectdrop_",
- width=width + 10, height=100)
- self._layout.margin.left = -3
- self._opener = LUISprite(self, "SelectboxOpen_Right", "skin")
- self._opener.right = -4
- self._opener.top = -25
- self._opener.z_offset = 3
- self._container = LUIObject(self._layout, 0, 0, 0, 0)
- self._container.width = self.width
- self._container.clip_bounds = (0,0,0,0)
- self._container.left = 5
- self._container.solid = True
- self._container.bind("mousedown", lambda *args: self.request_focus())
- self._selectbox = parent
- self._option_focus = False
- self.parent = self._selectbox
- def _on_opt_over(self, event):
- """ Inernal handler when an option got hovered """
- event.sender.color = (0,0,0,0.1)
- def _on_opt_out(self, event):
- """ Inernal handler when an option got no longer hovered """
- event.sender.color = (0,0,0,0)
- def _on_opt_click(self, opt_id, event):
- """ Internal handler when an option got clicked """
- self._selectbox._on_option_selected(opt_id)
- def _render_options(self, options):
- """ Internal method to update the options """
- num_visible_options = min(30, len(options))
- offset_top = 6
- self._layout.height = num_visible_options * 30 + offset_top + 11
- self._container.height = num_visible_options * 30 + offset_top + 1
- self._container.remove_all_children()
- current_y = offset_top
- for opt_id, opt_val in options:
- opt_container = LUIObject(self._container, x=0, y=current_y, w=self._container.width - 30, h=30)
- opt_bg = LUISprite(opt_container, "blank", "skin")
- opt_bg.width = self._container.width
- opt_bg.height = opt_container.height
- opt_bg.color = (0,0,0,0)
- opt_bg.bind("mouseover", self._on_opt_over)
- opt_bg.bind("mouseout", self._on_opt_out)
- opt_bg.bind("mousedown", lambda *args: self.request_focus())
- opt_bg.bind("click", partial(self._on_opt_click, opt_id))
- opt_bg.solid = True
- opt_label = LUILabel(parent=opt_container, text=opt_val.encode('utf-8'))
- opt_label.top = 8
- opt_label.left = 8
- if opt_id == self._selectbox.selected_option:
- opt_label.color = (0.6, 0.9, 0.4, 1.0)
- divider = LUISprite(opt_container, "SelectdropDivider", "skin")
- divider.top = 30 - divider.height / 2
- divider.width = self._container.width
- current_y += 30
|