summaryrefslogtreecommitdiff
path: root/src/python/widget/button.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/python/widget/button.py')
-rw-r--r--src/python/widget/button.py443
1 files changed, 443 insertions, 0 deletions
diff --git a/src/python/widget/button.py b/src/python/widget/button.py
new file mode 100644
index 0000000..f938e46
--- /dev/null
+++ b/src/python/widget/button.py
@@ -0,0 +1,443 @@
+# -*- 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
+#
+# Original author of this file is Henrik Thoms
+
+from libavg import avg, statemachine, player, gesture
+
+from base import SwitchNode, HVStretchNode
+from . import skin
+
+class _ButtonBase(avg.DivNode):
+
+ PRESSED = avg.Publisher.genMessageID()
+ RELEASED = avg.Publisher.genMessageID()
+
+ def __init__(self, parent=None, **kwargs):
+ super(_ButtonBase, self).__init__(**kwargs)
+ self.registerInstance(self, parent)
+ self.publish(self.PRESSED)
+ self.publish(self.RELEASED)
+
+ def _setActiveArea(self, upNode, activeAreaNode, fatFingerEnlarge):
+ if fatFingerEnlarge:
+ if activeAreaNode:
+ raise(RuntimeError(
+ "Button: Can't specify both fatFingerEnlarge and activeAreaNode"))
+ size = upNode.size
+ minSize = 20*player.getPixelsPerMM()
+ size = avg.Point2D(max(minSize, size.x), max(minSize, size.y))
+ activeAreaNode = avg.RectNode(size=size, opacity=0, parent=self)
+ #Here we need to store a 'hard' reference to the active area node
+ #because the tap recognizer won't keep it
+ self.__activeAreaNode = activeAreaNode
+ else:
+ if activeAreaNode == None:
+ activeAreaNode = self
+ else:
+ self.appendChild(activeAreaNode)
+
+ self._tapRecognizer = gesture.TapRecognizer(activeAreaNode,
+ possibleHandler=self._onDown,
+ detectedHandler=self._onTap,
+ failHandler=self._onTapFail)
+
+
+class Button(_ButtonBase):
+
+ CLICKED = avg.Publisher.genMessageID()
+
+ def __init__(self, upNode, downNode, disabledNode=None, activeAreaNode=None,
+ enabled=True, fatFingerEnlarge=False, **kwargs):
+ super(Button, self).__init__(**kwargs)
+
+ if disabledNode == None:
+ disabledNode = upNode
+
+ nodeMap = {
+ "UP": upNode,
+ "DOWN": downNode,
+ "DISABLED": disabledNode
+ }
+ self.__switchNode = SwitchNode(nodeMap=nodeMap, visibleid="UP", parent=self)
+ self.publish(self.CLICKED)
+
+ self.__stateMachine = statemachine.StateMachine("Button", "UP")
+ self.__stateMachine.addState("UP", ("DOWN", "DISABLED"),
+ enterFunc=self._enterUp, leaveFunc=self._leaveUp)
+ self.__stateMachine.addState("DOWN", ("UP", "DISABLED"),
+ enterFunc=self._enterDown, leaveFunc=self._leaveDown)
+ self.__stateMachine.addState("DISABLED", ("UP",),
+ enterFunc=self._enterDisabled, leaveFunc=self._leaveDisabled)
+
+ self._setActiveArea(upNode, activeAreaNode, fatFingerEnlarge)
+
+ if not(enabled):
+ self.setEnabled(False)
+
+ def getEnabled(self):
+ return self.__stateMachine.state != "DISABLED"
+
+ def setEnabled(self, enabled):
+ if enabled:
+ if self.__stateMachine.state == "DISABLED":
+ self.__stateMachine.changeState("UP")
+ else:
+ if self.__stateMachine.state != "DISABLED":
+ self.__stateMachine.changeState("DISABLED")
+
+ enabled = property(getEnabled, setEnabled)
+
+ def _getState(self):
+ return self.__stateMachine.state
+
+ def _onDown(self):
+ self.__stateMachine.changeState("DOWN")
+ self.notifySubscribers(self.PRESSED, [])
+
+ def _onTap(self):
+ self.__stateMachine.changeState("UP")
+ self.notifySubscribers(self.CLICKED, [])
+ self.notifySubscribers(self.RELEASED, [])
+
+ def _onTapFail(self):
+ self.__stateMachine.changeState("UP")
+ self.notifySubscribers(self.RELEASED, [])
+
+ def _enterUp(self):
+ self.__setActiveNode()
+
+ def _leaveUp(self):
+ pass
+
+ def _enterDown(self):
+ self.__setActiveNode()
+
+ def _leaveDown(self):
+ pass
+
+ def _enterDisabled(self):
+ self.__setActiveNode()
+ self._tapRecognizer.enable(False)
+
+ def _leaveDisabled(self):
+ self._tapRecognizer.enable(True)
+
+ def __setActiveNode(self):
+ self.__switchNode.visibleid = self.__stateMachine.state
+
+
+class BmpButton(Button):
+
+ def __init__(self, upSrc, downSrc, disabledSrc=None, **kwargs):
+ upNode = avg.ImageNode(href=upSrc)
+ downNode = avg.ImageNode(href=downSrc)
+ if disabledSrc != None:
+ disabledNode = avg.ImageNode(href=disabledSrc)
+ else:
+ disabledNode = None
+ super(BmpButton, self).__init__(upNode=upNode, downNode=downNode,
+ disabledNode=disabledNode, **kwargs)
+
+
+class TextButton(Button):
+
+ def __init__(self, text, skinObj=skin.Skin.default, **kwargs):
+ size = avg.Point2D(kwargs["size"])
+ cfg = skinObj.defaultTextButtonCfg
+
+ self.wordsNodes = []
+
+ upNode = self.__createStateNode(size, cfg, "upBmp", text, "font")
+ downNode = self.__createStateNode(size, cfg, "downBmp", text, "downFont")
+ if "disabledBmp" in cfg:
+ disabledNode = self.__createStateNode(size, cfg, "disabledBmp", text,
+ "disabledFont")
+ else:
+ disabledNode = None
+
+ super(TextButton, self).__init__(upNode=upNode, downNode=downNode,
+ disabledNode=disabledNode, **kwargs)
+
+ def __createStateNode(self, size, cfg, bmpName, text, fontStyleName):
+ stateNode = avg.DivNode(size=size)
+ endsExtent = eval(cfg["endsExtent"], {}, {})
+ HVStretchNode(size=size, src=cfg[bmpName], endsExtent=endsExtent,
+ parent=stateNode)
+ words = avg.WordsNode(text=text, fontstyle=cfg[fontStyleName], parent=stateNode)
+ words.pos = (round((size.x-words.size.x)/2), round((size.y-words.size.y)/2))
+ self.wordsNodes.append(words)
+ return stateNode
+
+ def getText(self):
+ return self.wordsNodes[0].text
+
+ def setText(self, text):
+ for node in self.wordsNodes:
+ node.text = text
+ node.pos = (self.size-node.size)/2
+
+ text = property(getText, setText)
+
+
+class ToggleButton(_ButtonBase):
+
+ TOGGLED = avg.Publisher.genMessageID()
+
+ def __init__(self, uncheckedUpNode, uncheckedDownNode, checkedUpNode, checkedDownNode,
+ uncheckedDisabledNode=None, checkedDisabledNode=None, activeAreaNode=None,
+ enabled=True, fatFingerEnlarge=False, checked=False, **kwargs):
+ super(ToggleButton, self).__init__(**kwargs)
+ nodeMap = {
+ "UNCHECKED_UP": uncheckedUpNode,
+ "UNCHECKED_DOWN": uncheckedDownNode,
+ "CHECKED_UP": checkedUpNode,
+ "CHECKED_DOWN": checkedDownNode,
+ "UNCHECKED_DISABLED": uncheckedDisabledNode,
+ "CHECKED_DISABLED": checkedDisabledNode,
+ }
+ if uncheckedDisabledNode == None:
+ nodeMap["UNCHECKED_DISABLED"] = uncheckedUpNode
+ if checkedDisabledNode == None:
+ nodeMap["CHECKED_DISABLED"] = checkedUpNode
+ self.__switchNode = SwitchNode(nodeMap=nodeMap, visibleid="UNCHECKED_UP",
+ parent=self)
+
+ self.publish(ToggleButton.TOGGLED)
+
+ self.__stateMachine = statemachine.StateMachine("ToggleButton", "UNCHECKED_UP")
+ self.__stateMachine.addState("UNCHECKED_UP", ("UNCHECKED_DOWN",
+ "UNCHECKED_DISABLED"), enterFunc=self._enterUncheckedUp,
+ leaveFunc=self._leaveUncheckedUp)
+ self.__stateMachine.addState("UNCHECKED_DOWN", ("UNCHECKED_UP",
+ "UNCHECKED_DISABLED", "CHECKED_UP"), enterFunc=self._enterUncheckedDown,
+ leaveFunc=self._leaveUncheckedDown)
+ self.__stateMachine.addState("CHECKED_UP", ("CHECKED_DOWN", "CHECKED_DISABLED"),
+ enterFunc=self._enterCheckedUp, leaveFunc=self._leaveCheckedUp)
+ self.__stateMachine.addState("CHECKED_DOWN", ("CHECKED_UP", "UNCHECKED_UP",
+ "CHECKED_DISABLED"), enterFunc=self._enterCheckedDown,
+ leaveFunc=self._leaveCheckedDown)
+ self.__stateMachine.addState("UNCHECKED_DISABLED", ("UNCHECKED_UP",),
+ enterFunc=self._enterUncheckedDisabled,
+ leaveFunc=self._leaveUncheckedDisabled)
+ self.__stateMachine.addState("CHECKED_DISABLED", ("CHECKED_UP", ),
+ enterFunc=self._enterCheckedDisabled,
+ leaveFunc=self._leaveCheckedDisabled)
+
+ self._setActiveArea(uncheckedUpNode, activeAreaNode, fatFingerEnlarge)
+
+ if not enabled:
+ self.__stateMachine.changeState("UNCHECKED_DISABLED")
+ if checked:
+ self.setChecked(True)
+
+ def getEnabled(self):
+ return (self.__stateMachine.state != "CHECKED_DISABLED" and
+ self.__stateMachine.state != "UNCHECKED_DISABLED")
+
+ def setEnabled(self, enabled):
+ if enabled:
+ if self.__stateMachine.state == "CHECKED_DISABLED":
+ self.__stateMachine.changeState("CHECKED_UP")
+ elif self.__stateMachine.state == "UNCHECKED_DISABLED":
+ self.__stateMachine.changeState("UNCHECKED_UP")
+ else:
+ if (self.__stateMachine.state == "CHECKED_UP" or
+ self.__stateMachine.state == "CHECKED_DOWN") :
+ self.__stateMachine.changeState("CHECKED_DISABLED")
+ elif (self.__stateMachine.state == "UNCHECKED_UP" or
+ self.__stateMachine.state == "UNCHECKED_DOWN") :
+ self.__stateMachine.changeState("UNCHECKED_DISABLED")
+
+ enabled = property(getEnabled, setEnabled)
+
+ def getChecked(self):
+ return (self.__stateMachine.state != "UNCHECKED_UP" and
+ self.__stateMachine.state != "UNCHECKED_DOWN" and
+ self.__stateMachine.state != "UNCHECKED_DISABLED")
+
+ def setChecked(self, checked):
+ oldEnabled = self.getEnabled()
+ if checked:
+ if self.__stateMachine.state == "UNCHECKED_DISABLED":
+ self.__stateMachine.changeState("UNCHECKED_UP")
+ if self.__stateMachine.state == "UNCHECKED_UP":
+ self.__stateMachine.changeState("UNCHECKED_DOWN")
+ if self.__stateMachine.state != "CHECKED_UP":
+ self.__stateMachine.changeState("CHECKED_UP")
+ if not oldEnabled:
+ self.__stateMachine.changeState("CHECKED_DISABLED")
+ else:
+ if self.__stateMachine.state == "CHECKED_DISABLED":
+ self.__stateMachine.changeState("CHECKED_UP")
+ if self.__stateMachine.state == "CHECKED_UP":
+ self.__stateMachine.changeState("CHECKED_DOWN")
+ if self.__stateMachine.state != "UNCHECKED_UP":
+ self.__stateMachine.changeState("UNCHECKED_UP")
+ if not oldEnabled:
+ self.__stateMachine.changeState("UNCHECKED_DISABLED")
+
+ checked = property(getChecked, setChecked)
+
+ def _getState(self):
+ return self.__stateMachine.state
+
+ def _enterUncheckedUp(self):
+ self.__setActiveNode()
+
+ def _leaveUncheckedUp(self):
+ pass
+
+ def _enterUncheckedDown(self):
+ self.__setActiveNode()
+
+ def _leaveUncheckedDown(self):
+ pass
+
+ def _enterCheckedUp(self):
+ self.__setActiveNode()
+
+ def _leaveCheckedUp(self):
+ pass
+
+ def _enterCheckedDown(self):
+ self.__setActiveNode()
+
+ def _leaveCheckedDown(self):
+ pass
+
+ def _enterUncheckedDisabled(self):
+ self.__setActiveNode()
+ self._tapRecognizer.enable(False)
+
+ def _leaveUncheckedDisabled(self):
+ self._tapRecognizer.enable(True)
+
+ def _enterCheckedDisabled(self):
+ self.__setActiveNode()
+ self._tapRecognizer.enable(False)
+
+ def _leaveCheckedDisabled(self):
+ self._tapRecognizer.enable(True)
+
+ def _onDown(self):
+ if self.__stateMachine.state == "UNCHECKED_UP":
+ self.__stateMachine.changeState("UNCHECKED_DOWN")
+ elif self.__stateMachine.state == "CHECKED_UP":
+ self.__stateMachine.changeState("CHECKED_DOWN")
+ self.notifySubscribers(self.PRESSED, [])
+
+ def _onTap(self):
+ if self.__stateMachine.state == "UNCHECKED_DOWN":
+ self.__stateMachine.changeState("CHECKED_UP")
+ self.notifySubscribers(ToggleButton.TOGGLED, [True])
+ elif self.__stateMachine.state == "CHECKED_DOWN":
+ self.__stateMachine.changeState("UNCHECKED_UP")
+ self.notifySubscribers(ToggleButton.TOGGLED, [False])
+ self.notifySubscribers(self.RELEASED, [])
+
+ def _onTapFail(self):
+ if self.__stateMachine.state == "UNCHECKED_DOWN":
+ self.__stateMachine.changeState("UNCHECKED_UP")
+ elif self.__stateMachine.state == "CHECKED_DOWN":
+ self.__stateMachine.changeState("CHECKED_UP")
+ self.notifySubscribers(self.RELEASED, [])
+
+ def __setActiveNode(self):
+ self.__switchNode.visibleid = self.__stateMachine.state
+
+
+class CheckBox(ToggleButton):
+
+ def __init__(self, text="", skinObj=skin.Skin.default, **kwargs):
+ self.cfg = skinObj.defaultCheckBoxCfg
+
+ uncheckedUpNode = self.__createImageNode(self.cfg["uncheckedUpBmp"])
+ uncheckedDownNode = self.__createImageNode(self.cfg["uncheckedDownBmp"])
+ uncheckedDisabledNode = self.__createImageNode(self.cfg["uncheckedDisabledBmp"])
+ checkedUpNode = self.__createImageNode(self.cfg["checkedUpBmp"])
+ checkedDownNode = self.__createImageNode(self.cfg["checkedDownBmp"])
+ checkedDisabledNode = self.__createImageNode(self.cfg["checkedDisabledBmp"])
+
+ super(CheckBox, self).__init__(uncheckedUpNode=uncheckedUpNode,
+ uncheckedDownNode=uncheckedDownNode,
+ uncheckedDisabledNode=uncheckedDisabledNode,
+ checkedUpNode=checkedUpNode,
+ checkedDownNode=checkedDownNode,
+ checkedDisabledNode=checkedDisabledNode,
+ **kwargs)
+ self.textNode = avg.WordsNode(pos=(20,0), text=text, fontstyle=self.cfg["font"],
+ parent=self)
+
+ def _enterUncheckedUp(self):
+ self.textNode.fontstyle = self.cfg["font"]
+ super(CheckBox, self)._enterUncheckedUp()
+
+ def _enterUncheckedDown(self):
+ self.textNode.fontstyle = self.cfg["downFont"]
+ super(CheckBox, self)._enterUncheckedDown()
+
+ def _enterCheckedUp(self):
+ self.textNode.fontstyle = self.cfg["font"]
+ super(CheckBox, self)._enterCheckedUp()
+
+ def _enterCheckedDown(self):
+ self.textNode.fontstyle = self.cfg["downFont"]
+ super(CheckBox, self)._enterCheckedDown()
+
+ def _enterUncheckedDisabled(self):
+ self.textNode.fontstyle = self.cfg["disabledFont"]
+ super(CheckBox, self)._enterUncheckedDisabled()
+
+ def _enterCheckedDisabled(self):
+ self.textNode.fontstyle = self.cfg["disabledFont"]
+ super(CheckBox, self)._enterCheckedDisabled()
+
+ def __createImageNode(self, bmp):
+ node = avg.ImageNode()
+ node.setBitmap(bmp)
+ return node
+
+
+class BmpToggleButton(ToggleButton):
+ def __init__(self, uncheckedUpSrc, uncheckedDownSrc, checkedUpSrc, checkedDownSrc,
+ uncheckedDisabledSrc=None, checkedDisabledSrc=None, **kwargs):
+ uncheckedUpNode = avg.ImageNode(href=uncheckedUpSrc)
+ uncheckedDownNode = avg.ImageNode(href=uncheckedDownSrc)
+ checkedUpNode = avg.ImageNode(href=checkedUpSrc)
+ checkedDownNode = avg.ImageNode(href=checkedDownSrc)
+
+ if uncheckedDisabledSrc != None:
+ uncheckedDisabledNode = avg.ImageNode(href=uncheckedDisabledSrc)
+ else:
+ uncheckedDisabledNode = None
+ if checkedDisabledSrc != None:
+ checkedDisabledNode = avg.ImageNode(href=checkedDisabledSrc)
+ else:
+ checkedDisabledNode = None
+
+ super(BmpToggleButton, self).__init__(uncheckedUpNode=uncheckedUpNode,
+ uncheckedDownNode=uncheckedDownNode,
+ checkedUpNode=checkedUpNode,
+ checkedDownNode=checkedDownNode,
+ uncheckedDisabledNode=uncheckedDisabledNode,
+ checkedDisabledNode=checkedDisabledNode,
+ **kwargs)
+