132 lines
4.9 KiB
Python
132 lines
4.9 KiB
Python
|
|
from LUIObject import LUIObject
|
|
from LUISprite import LUISprite
|
|
from LUIInitialState import LUIInitialState
|
|
from LUILayouts import LUIHorizontalStretchedLayout
|
|
|
|
class LUISlider(LUIObject):
|
|
|
|
""" Slider which can be used to control values """
|
|
|
|
def __init__(self, parent=None, filled=True, min_value=0.0, max_value=1.0, width=100.0, value=None, **kwargs):
|
|
""" Constructs a new slider. If filled is True, the part behind the knob
|
|
will be solid """
|
|
LUIObject.__init__(self, x=0, y=0, solid=True)
|
|
self.set_width(width)
|
|
self._knob = LUISprite(self, "SliderKnob", "skin")
|
|
self._knob.z_offset = 2
|
|
self._knob.solid = True
|
|
|
|
# Construct the background
|
|
self._slider_bg = LUIHorizontalStretchedLayout(parent=self, prefix="SliderBg", center_vertical=True, width="100%", margin=(-1, 0, 0, 0))
|
|
|
|
self._filled = filled
|
|
self._min_value = min_value
|
|
self._max_value = max_value
|
|
|
|
self._side_margin = self._knob.width / 4
|
|
self._effective_width = self.width - 2 * self._side_margin
|
|
|
|
if self._filled:
|
|
self._slider_fill = LUIObject(self)
|
|
self._fill_left = LUISprite(self._slider_fill, "SliderBgFill_Left", "skin")
|
|
self._fill_mid = LUISprite(self._slider_fill, "SliderBgFill", "skin")
|
|
self._fill_mid.left = self._fill_left.width
|
|
self._slider_fill.z_offset = 1
|
|
self._slider_fill.center_vertical = True
|
|
|
|
if parent is not None:
|
|
self.parent = parent
|
|
|
|
# Handle various events
|
|
self._knob.bind("mousedown", self._start_drag)
|
|
self._knob.bind("mousemove", self._update_drag)
|
|
self._knob.bind("mouseup", self._stop_drag)
|
|
self._knob.bind("keydown", self._on_keydown)
|
|
self._knob.bind("blur", self._stop_drag)
|
|
self._knob.bind("keyrepeat", self._on_keydown)
|
|
|
|
self._drag_start_pos = None
|
|
self._dragging = False
|
|
self._drag_start_val = 0
|
|
self.current_val = 10
|
|
|
|
# Set initial value
|
|
if value is None:
|
|
self.set_value( (self._min_value + self._max_value) / 2.0 )
|
|
else:
|
|
self.set_value(value)
|
|
|
|
self._update_knob()
|
|
|
|
LUIInitialState.init(self, kwargs)
|
|
|
|
def on_click(self, event):
|
|
""" Internal on click handler """
|
|
# I don't like this behaviour
|
|
# relative_pos = self.get_relative_pos(event.coordinates)
|
|
# if not self._dragging:
|
|
# self._set_current_val(relative_pos.x)
|
|
|
|
def _update_knob(self):
|
|
""" Internal method to update the slider knob """
|
|
self._knob.left = self.current_val - (self._knob.width / 2) + self._side_margin
|
|
if self._filled:
|
|
self._fill_mid.width = self.current_val - self._fill_left.width + self._side_margin
|
|
|
|
def _set_current_val(self, pixels):
|
|
""" Internal method to set the current value in pixels """
|
|
pixels = max(0, min(self._effective_width, pixels))
|
|
self.current_val = pixels
|
|
self.trigger_event("changed")
|
|
self._update_knob()
|
|
|
|
def _start_drag(self, event):
|
|
""" Internal drag start handler """
|
|
self._knob.request_focus()
|
|
if not self._dragging:
|
|
self._drag_start_pos = event.coordinates
|
|
self._dragging = True
|
|
self._drag_start_val = self.current_val
|
|
self._knob.color = (0.8,0.8,0.8,1.0)
|
|
|
|
def set_value(self, value):
|
|
""" Sets the value of the slider, should be between minimum and maximum. """
|
|
scaled = (float(value) - float(self._min_value)) \
|
|
/ (float(self._max_value) - float(self._min_value)) \
|
|
* self._effective_width
|
|
self._set_current_val(scaled)
|
|
|
|
def get_value(self):
|
|
""" Returns the current value of the slider """
|
|
return (self.current_val / float(self._effective_width)) \
|
|
* (float(self._max_value) - float(self._min_value)) \
|
|
+ self._min_value
|
|
|
|
value = property(get_value, set_value)
|
|
|
|
def _on_keydown(self, event):
|
|
""" Internal keydown handler """
|
|
if event.message == "arrow_right":
|
|
self._set_current_val(self.current_val + 2)
|
|
elif event.message == "arrow_left":
|
|
self._set_current_val(self.current_val - 2)
|
|
elif event.message == "escape":
|
|
self.current_val = self._drag_start_val
|
|
self._stop_drag(event)
|
|
self._update_knob()
|
|
|
|
def _update_drag(self, event):
|
|
""" Internal drag handler """
|
|
if self._dragging:
|
|
dragOffset = event.coordinates.x - self._drag_start_pos.x
|
|
finalValue = self._drag_start_val + dragOffset
|
|
self._set_current_val(finalValue)
|
|
|
|
def _stop_drag(self, event):
|
|
""" Internal drag stop handelr """
|
|
self._drag_start_pos = None
|
|
self._dragging = False
|
|
self._drag_start_val = self.current_val
|
|
self._knob.color = (1,1,1,1)
|