208 lines
7.2 KiB
Python
208 lines
7.2 KiB
Python
|
|
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)
|
|
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
|