LUISlider.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. from LUIObject import LUIObject
  2. from LUISprite import LUISprite
  3. from LUIInitialState import LUIInitialState
  4. from LUILayouts import LUIHorizontalStretchedLayout
  5. class LUISlider(LUIObject):
  6. """ Slider which can be used to control values """
  7. def __init__(self, parent=None, filled=True, min_value=0.0, max_value=1.0, width=100.0, value=None, **kwargs):
  8. """ Constructs a new slider. If filled is True, the part behind the knob
  9. will be solid """
  10. LUIObject.__init__(self, x=0, y=0, solid=True)
  11. self.set_width(width)
  12. self._knob = LUISprite(self, "SliderKnob", "skin")
  13. self._knob.z_offset = 2
  14. self._knob.solid = True
  15. # Construct the background
  16. self._slider_bg = LUIHorizontalStretchedLayout(parent=self, prefix="SliderBg", center_vertical=True, width="100%", margin=(-1, 0, 0, 0))
  17. self._filled = filled
  18. self._min_value = min_value
  19. self._max_value = max_value
  20. self._side_margin = self._knob.width / 4
  21. self._effective_width = self.width - 2 * self._side_margin
  22. if self._filled:
  23. self._slider_fill = LUIObject(self)
  24. self._fill_left = LUISprite(self._slider_fill, "SliderBgFill_Left", "skin")
  25. self._fill_mid = LUISprite(self._slider_fill, "SliderBgFill", "skin")
  26. self._fill_mid.left = self._fill_left.width
  27. self._slider_fill.z_offset = 1
  28. self._slider_fill.center_vertical = True
  29. if parent is not None:
  30. self.parent = parent
  31. # Handle various events
  32. self._knob.bind("mousedown", self._start_drag)
  33. self._knob.bind("mousemove", self._update_drag)
  34. self._knob.bind("mouseup", self._stop_drag)
  35. self._knob.bind("keydown", self._on_keydown)
  36. self._knob.bind("blur", self._stop_drag)
  37. self._knob.bind("keyrepeat", self._on_keydown)
  38. self._drag_start_pos = None
  39. self._dragging = False
  40. self._drag_start_val = 0
  41. self.current_val = 10
  42. # Set initial value
  43. if value is None:
  44. self.set_value( (self._min_value + self._max_value) / 2.0 )
  45. else:
  46. self.set_value(value)
  47. self._update_knob()
  48. LUIInitialState.init(self, kwargs)
  49. def on_click(self, event):
  50. """ Internal on click handler """
  51. # I don't like this behaviour
  52. # relative_pos = self.get_relative_pos(event.coordinates)
  53. # if not self._dragging:
  54. # self._set_current_val(relative_pos.x)
  55. def _update_knob(self):
  56. """ Internal method to update the slider knob """
  57. self._knob.left = self.current_val - (self._knob.width / 2) + self._side_margin
  58. if self._filled:
  59. self._fill_mid.width = self.current_val - self._fill_left.width + self._side_margin
  60. def _set_current_val(self, pixels):
  61. """ Internal method to set the current value in pixels """
  62. pixels = max(0, min(self._effective_width, pixels))
  63. self.current_val = pixels
  64. self.trigger_event("changed")
  65. self._update_knob()
  66. def _start_drag(self, event):
  67. """ Internal drag start handler """
  68. self._knob.request_focus()
  69. if not self._dragging:
  70. self._drag_start_pos = event.coordinates
  71. self._dragging = True
  72. self._drag_start_val = self.current_val
  73. self._knob.color = (0.8,0.8,0.8,1.0)
  74. def set_value(self, value):
  75. """ Sets the value of the slider, should be between minimum and maximum. """
  76. scaled = (float(value) - float(self._min_value)) \
  77. / (float(self._max_value) - float(self._min_value)) \
  78. * self._effective_width
  79. self._set_current_val(scaled)
  80. def get_value(self):
  81. """ Returns the current value of the slider """
  82. return (self.current_val / float(self._effective_width)) \
  83. * (float(self._max_value) - float(self._min_value)) \
  84. + self._min_value
  85. value = property(get_value, set_value)
  86. def _on_keydown(self, event):
  87. """ Internal keydown handler """
  88. if event.message == "arrow_right":
  89. self._set_current_val(self.current_val + 2)
  90. elif event.message == "arrow_left":
  91. self._set_current_val(self.current_val - 2)
  92. elif event.message == "escape":
  93. self.current_val = self._drag_start_val
  94. self._stop_drag(event)
  95. self._update_knob()
  96. def _update_drag(self, event):
  97. """ Internal drag handler """
  98. if self._dragging:
  99. dragOffset = event.coordinates.x - self._drag_start_pos.x
  100. finalValue = self._drag_start_val + dragOffset
  101. self._set_current_val(finalValue)
  102. def _stop_drag(self, event):
  103. """ Internal drag stop handelr """
  104. self._drag_start_pos = None
  105. self._dragging = False
  106. self._drag_start_val = self.current_val
  107. self._knob.color = (1,1,1,1)