summaryrefslogtreecommitdiff
path: root/src/python/widget/slider.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/python/widget/slider.py')
-rw-r--r--src/python/widget/slider.py371
1 files changed, 371 insertions, 0 deletions
diff --git a/src/python/widget/slider.py b/src/python/widget/slider.py
new file mode 100644
index 0000000..1e63f0a
--- /dev/null
+++ b/src/python/widget/slider.py
@@ -0,0 +1,371 @@
+# -*- coding: utf-8 -*-
+# libavg - Media Playback Engine.
+# Copyright (C) 2003-2014 Ulrich von Zadow
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# Current versions can be found at www.libavg.de
+
+from libavg import avg, gesture
+from base import SwitchNode, HStretchNode, VStretchNode, Orientation
+from . import skin
+
+import math
+
+
+class ScrollBarTrack(SwitchNode):
+
+ def __init__(self, bmp, endsExtent, disabledBmp, orientation=Orientation.HORIZONTAL,
+ **kwargs):
+
+ super(ScrollBarTrack, self).__init__(nodeMap=None, **kwargs)
+ if orientation == Orientation.HORIZONTAL:
+ StretchNode = HStretchNode
+ else:
+ StretchNode = VStretchNode
+ self.__enabledNode = StretchNode(src=bmp, endsExtent=endsExtent, parent=self)
+ self.__disabledNode = StretchNode(src=disabledBmp, endsExtent=endsExtent,
+ parent=self)
+
+ self.setNodeMap({
+ "ENABLED": self.__enabledNode,
+ "DISABLED": self.__disabledNode
+ })
+ self.visibleid = "ENABLED"
+
+
+class ScrollBarThumb(SwitchNode):
+
+ def __init__(self, upBmp, downBmp, disabledBmp, endsExtent,
+ orientation=Orientation.HORIZONTAL, minExtent=-1,
+ **kwargs):
+
+ super(ScrollBarThumb, self).__init__(nodeMap=None, **kwargs)
+
+ if orientation == Orientation.HORIZONTAL:
+ StretchNode = HStretchNode
+ else:
+ StretchNode = VStretchNode
+ self.__upNode = StretchNode(src=upBmp, endsExtent=endsExtent, minExtent=minExtent)
+ self.__downNode = StretchNode(src=downBmp, endsExtent=endsExtent,
+ minExtent=minExtent)
+ self.__disabledNode = StretchNode(src=disabledBmp, endsExtent=endsExtent,
+ minExtent=minExtent)
+
+ self.setNodeMap({
+ "UP": self.__upNode,
+ "DOWN": self.__downNode,
+ "DISABLED": self.__disabledNode
+ })
+ self.visibleid = "UP"
+
+
+class SliderThumb(SwitchNode):
+
+ def __init__(self, upBmp, downBmp, disabledBmp, **kwargs):
+ upNode = avg.ImageNode()
+ upNode.setBitmap(upBmp)
+ downNode = avg.ImageNode()
+ downNode.setBitmap(downBmp)
+ disabledNode = avg.ImageNode()
+ disabledNode.setBitmap(disabledBmp)
+ nodeMap = {"UP": upNode, "DOWN": downNode, "DISABLED": disabledNode}
+ super(SliderThumb, self).__init__(nodeMap=nodeMap, visibleid="UP", **kwargs)
+
+
+class ProgressBar(avg.DivNode):
+
+ def __init__(self, orientation, skinObj=skin.Skin.default, height=0, width=0,
+ range=(0.,1.), value=0.0, parent=None, **kwargs):
+ super(ProgressBar, self).__init__(**kwargs)
+ self.registerInstance(self, parent)
+ if orientation == Orientation.HORIZONTAL:
+ cfg = skinObj.defaultProgressBarCfg["horizontal"]
+ else:
+ cfg = skinObj.defaultProgressBarCfg["vertical"]
+
+ self._orientation = orientation
+
+ trackBmp = cfg["trackBmp"]
+ self._trackNode = ScrollBarTrack(bmp=trackBmp, disabledBmp=trackBmp,
+ endsExtent=cfg["trackEndsExtent"], orientation=self._orientation)
+ self.appendChild(self._trackNode)
+
+ thumbUpBmp = cfg["thumbUpBmp"]
+ endsExtent=cfg["thumbEndsExtent"]
+
+ self.__thumbNode = ScrollBarThumb(orientation=self._orientation,
+ upBmp=thumbUpBmp, downBmp=thumbUpBmp, disabledBmp=thumbUpBmp,
+ endsExtent=endsExtent)
+ self.appendChild(self.__thumbNode)
+
+ self.__range = range
+ self.__value = value
+
+ if orientation == Orientation.HORIZONTAL:
+ self.size = (width, trackBmp.getSize().y)
+ else:
+ self.size = (trackBmp.getSize().x, height)
+ self._positionNodes()
+
+ def getRange(self):
+ return self.__range
+
+ def setRange(self, range):
+ self.__range = (float(range[0]), float(range[1]))
+ self._positionNodes()
+ range = property(getRange, setRange)
+
+ def getValue(self):
+ return self.__value
+
+ def setValue(self, value):
+ self._positionNodes(value)
+ value = property(getValue, setValue)
+
+ def _positionNodes(self, newValue=None):
+ if newValue is not None:
+ self.__value = float(newValue)
+ if self.__value < self.__range[0]:
+ self.__value = self.__range[0]
+ if self.__value > self.__range[1]:
+ self.__value = self.__range[1]
+ self._trackNode.size = self.size
+
+ effectiveRange = math.fabs(self.__range[1] - self.__range[0])
+ normValue = ((self.__value-self.__range[0])/effectiveRange)
+ if self._orientation == Orientation.HORIZONTAL:
+ self.__thumbNode.width = normValue*self.size.x
+ else:
+ self.__thumbNode.height = normValue*self.size.y
+
+
+class SliderBase(avg.DivNode):
+
+ THUMB_POS_CHANGED = avg.Publisher.genMessageID()
+ PRESSED = avg.Publisher.genMessageID()
+ RELEASED = avg.Publisher.genMessageID()
+
+ def __init__(self, orientation, cfg, enabled=True, height=0, width=0, range=(0.,1.),
+ thumbPos=0.0, parent=None, **kwargs):
+ super(SliderBase, self).__init__(**kwargs)
+ self.registerInstance(self, parent)
+
+ self.publish(SliderBase.THUMB_POS_CHANGED)
+ self.publish(SliderBase.PRESSED)
+ self.publish(SliderBase.RELEASED)
+
+ self._orientation = orientation
+
+ trackBmp = cfg["trackBmp"]
+ trackDisabledBmp = cfg["trackDisabledBmp"]
+ self._trackNode = ScrollBarTrack(bmp=trackBmp, disabledBmp=trackDisabledBmp,
+ endsExtent=cfg["trackEndsExtent"], orientation=self._orientation)
+ self.appendChild(self._trackNode)
+
+ self._initThumb(cfg)
+
+ self._range = range
+ self._thumbPos = thumbPos
+
+ self.subscribe(self.SIZE_CHANGED, lambda newSize: self._positionNodes())
+ if orientation == Orientation.HORIZONTAL:
+ self.size = (width, trackBmp.getSize().y)
+ else:
+ self.size = (trackBmp.getSize().x, height)
+ if not(enabled):
+ self.setEnabled(False)
+
+ self.__recognizer = gesture.DragRecognizer(self._thumbNode, friction=-1,
+ detectedHandler=self.__onDragStart, moveHandler=self.__onDrag,
+ upHandler=self.__onUp)
+
+ def getRange(self):
+ return self._range
+
+ def setRange(self, range):
+ self._range = (float(range[0]), float(range[1]))
+ self._positionNodes()
+
+ # range[1] > range[0]: Reversed scrollbar.
+ range = property(getRange, setRange)
+
+ def getThumbPos(self):
+ return self._thumbPos
+
+ def setThumbPos(self, thumbPos):
+ self._positionNodes(thumbPos)
+
+ thumbPos = property(getThumbPos, setThumbPos)
+
+ def getEnabled(self):
+ return self._trackNode.visibleid != "DISABLED"
+
+ def setEnabled(self, enabled):
+ if enabled:
+ if self._trackNode.visibleid == "DISABLED":
+ self._trackNode.visibleid = "ENABLED"
+ self._thumbNode.visibleid = "UP"
+ self.__recognizer.enable(True)
+ else:
+ if self._trackNode.visibleid != "DISABLED":
+ self._trackNode.visibleid = "DISABLED"
+ self._thumbNode.visibleid = "DISABLED"
+ self.__recognizer.enable(False)
+
+ enabled = property(getEnabled, setEnabled)
+
+ def _positionNodes(self, newSliderPos=None):
+ if newSliderPos is not None:
+ self._thumbPos = float(newSliderPos)
+ self._trackNode.size = self.size
+
+ self._constrainSliderPos()
+
+ pixelRange = self._getScrollRangeInPixels()
+ if self._getSliderRange() == 0:
+ thumbPixelPos = 0
+ else:
+ thumbPixelPos = (((self._thumbPos-self._range[0])/self._getSliderRange())*
+ pixelRange)
+ if self._orientation == Orientation.HORIZONTAL:
+ self._thumbNode.x = thumbPixelPos
+ else:
+ self._thumbNode.y = thumbPixelPos
+
+ def __onDragStart(self):
+ self._thumbNode.visibleid = "DOWN"
+ self.__dragStartPos = self._thumbPos
+ self.notifySubscribers(Slider.PRESSED, [])
+
+ def __onDrag(self, offset):
+ pixelRange = self._getScrollRangeInPixels()
+ if pixelRange == 0:
+ normalizedOffset = 0
+ else:
+ if self._orientation == Orientation.HORIZONTAL:
+ normalizedOffset = offset.x/pixelRange
+ else:
+ normalizedOffset = offset.y/pixelRange
+ oldThumbPos = self._thumbPos
+ self._positionNodes(self.__dragStartPos + normalizedOffset*self._getSliderRange())
+ if self._thumbPos != oldThumbPos:
+ self.notifySubscribers(Slider.THUMB_POS_CHANGED, [self._thumbPos])
+
+ def __onUp(self, offset):
+ self.__onDrag(offset)
+ self._thumbNode.visibleid = "UP"
+ self.notifySubscribers(Slider.RELEASED, [])
+
+
+class Slider(SliderBase):
+
+ def __init__(self, orientation=Orientation.HORIZONTAL, skinObj=skin.Skin.default,
+ **kwargs):
+ if orientation == Orientation.HORIZONTAL:
+ cfg = skinObj.defaultSliderCfg["horizontal"]
+ else:
+ cfg = skinObj.defaultSliderCfg["vertical"]
+ super(Slider, self).__init__(orientation, cfg, **kwargs)
+
+ def _initThumb(self, cfg):
+ thumbUpBmp = cfg["thumbUpBmp"]
+ thumbDownBmp = skin.getBmpFromCfg(cfg, "thumbDownBmp", "thumbUpBmp")
+ thumbDisabledBmp = skin.getBmpFromCfg(cfg, "thumbDisabledBmp", "thumbUpBmp")
+ self._thumbNode = SliderThumb(upBmp=thumbUpBmp, downBmp=thumbDownBmp,
+ disabledBmp=thumbDisabledBmp)
+ self.appendChild(self._thumbNode)
+
+ def _getScrollRangeInPixels(self):
+ if self._orientation == Orientation.HORIZONTAL:
+ return self.size.x - self._thumbNode.size.x
+ else:
+ return self.size.y - self._thumbNode.size.y
+
+ def _getSliderRange(self):
+ return self._range[1] - self._range[0]
+
+ def _constrainSliderPos(self):
+ rangeMin = min(self._range[0], self._range[1])
+ rangeMax = max(self._range[0], self._range[1])
+ self._thumbPos = max(rangeMin, self._thumbPos)
+ self._thumbPos = min(rangeMax, self._thumbPos)
+
+
+class ScrollBar(SliderBase):
+
+ def __init__(self, orientation=Orientation.HORIZONTAL, skinObj=skin.Skin.default,
+ thumbExtent=0.1, **kwargs):
+ self.__thumbExtent = thumbExtent
+ if orientation == Orientation.HORIZONTAL:
+ cfg = skinObj.defaultScrollBarCfg["horizontal"]
+ else:
+ cfg = skinObj.defaultScrollBarCfg["vertical"]
+ super(ScrollBar, self).__init__(orientation=orientation, cfg=cfg, **kwargs)
+
+ def _initThumb(self, cfg):
+ thumbUpBmp = cfg["thumbUpBmp"]
+ thumbDownBmp = skin.getBmpFromCfg(cfg, "thumbDownBmp", "thumbUpBmp")
+ thumbDisabledBmp = skin.getBmpFromCfg(cfg, "thumbDisabledBmp", "thumbUpBmp")
+ endsExtent=cfg["thumbEndsExtent"]
+
+ self._thumbNode = ScrollBarThumb(orientation=self._orientation,
+ upBmp=thumbUpBmp, downBmp=thumbDownBmp,
+ disabledBmp=thumbDisabledBmp, endsExtent=endsExtent)
+ self.appendChild(self._thumbNode)
+
+ def getThumbExtent(self):
+ return self.__thumbExtent
+
+ def setThumbExtent(self, thumbExtent):
+ self.__thumbExtent = float(thumbExtent)
+ self._positionNodes()
+
+ thumbExtent = property(getThumbExtent, setThumbExtent)
+
+ def _getScrollRangeInPixels(self):
+ if self._orientation == Orientation.HORIZONTAL:
+ return self.size.x - self._thumbNode.width
+ else:
+ return self.size.y - self._thumbNode.height
+
+ def _positionNodes(self, newSliderPos=None):
+ effectiveRange = math.fabs(self._range[1] - self._range[0])
+ if self._orientation == Orientation.HORIZONTAL:
+ thumbExtent = (self.__thumbExtent/effectiveRange)*self.size.x
+ self._thumbNode.width = thumbExtent
+ else:
+ thumbExtent = (self.__thumbExtent/effectiveRange)*self.size.y
+ self._thumbNode.height = thumbExtent
+ super(ScrollBar, self)._positionNodes(newSliderPos)
+ if self._range[1] < self._range[0]:
+ # Reversed (upside-down) scrollbar
+ if self._orientation == Orientation.HORIZONTAL:
+ self._thumbNode.x -= thumbExtent
+ else:
+ self._thumbNode.y -= thumbExtent
+
+ def _getSliderRange(self):
+ if self._range[1] > self._range[0]:
+ return self._range[1] - self._range[0] - self.__thumbExtent
+ else:
+ return self._range[1] - self._range[0] + self.__thumbExtent
+
+ def _constrainSliderPos(self):
+ rangeMin = min(self._range[0], self._range[1])
+ rangeMax = max(self._range[0], self._range[1])
+ self._thumbPos = max(rangeMin, self._thumbPos)
+ self._thumbPos = min(rangeMax-self.__thumbExtent, self._thumbPos)
+