summaryrefslogtreecommitdiff
path: root/silx/gui/icons.py
diff options
context:
space:
mode:
Diffstat (limited to 'silx/gui/icons.py')
-rw-r--r--silx/gui/icons.py360
1 files changed, 360 insertions, 0 deletions
diff --git a/silx/gui/icons.py b/silx/gui/icons.py
new file mode 100644
index 0000000..eaf83b8
--- /dev/null
+++ b/silx/gui/icons.py
@@ -0,0 +1,360 @@
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 2016 European Synchrotron Radiation Facility
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# ###########################################################################*/
+"""Set of icons for buttons.
+
+Use :func:`getQIcon` to create Qt QIcon from the name identifying an icon.
+"""
+
+__authors__ = ["T. Vincent"]
+__license__ = "MIT"
+__date__ = "25/04/2017"
+
+
+import logging
+import weakref
+from . import qt
+from silx.resources import resource_filename
+from silx.utils import weakref as silxweakref
+from silx.utils.decorators import deprecated
+
+
+_logger = logging.getLogger(__name__)
+"""Module logger"""
+
+
+_cached_icons = weakref.WeakValueDictionary()
+"""Cache loaded icons in a weak structure"""
+
+
+_supported_formats = None
+"""Order of file format extension to check"""
+
+
+class AbstractAnimatedIcon(qt.QObject):
+ """Store an animated icon.
+
+ It provides an event containing the new icon everytime it is updated."""
+
+ def __init__(self, parent=None):
+ """Constructor
+
+ :param qt.QObject parent: Parent of the QObject
+ :raises: ValueError when name is not known
+ """
+ qt.QObject.__init__(self, parent)
+
+ self.__targets = silxweakref.WeakList()
+ self.__currentIcon = None
+
+ iconChanged = qt.Signal(qt.QIcon)
+ """Signal sent with a QIcon everytime the animation changed."""
+
+ def register(self, obj):
+ """Register an object to the AnimatedIcon.
+ If no object are registred, the animation is paused.
+ Object are stored in a weaked list.
+
+ :param object obj: An object
+ """
+ if obj not in self.__targets:
+ self.__targets.append(obj)
+ self._updateState()
+
+ def unregister(self, obj):
+ """Remove the object from the registration.
+ If no object are registred the animation is paused.
+
+ :param object obj: A registered object
+ """
+ if obj in self.__targets:
+ self.__targets.remove(obj)
+ self._updateState()
+
+ def hasRegistredObjects(self):
+ """Returns true if any object is registred.
+
+ :rtype: bool
+ """
+ return len(self.__targets)
+
+ def isRegistered(self, obj):
+ """Returns true if the object is registred in the AnimatedIcon.
+
+ :param object obj: An object
+ :rtype: bool
+ """
+ return obj in self.__targets
+
+ def currentIcon(self):
+ """Returns the icon of the current frame.
+
+ :rtype: qt.QIcon
+ """
+ return self.__currentIcon
+
+ def _updateState(self):
+ """Update the object according to the connected objects."""
+ pass
+
+ def _setCurrentIcon(self, icon):
+ """Store the current icon and emit a `iconChanged` event.
+
+ :param qt.QIcon icon: The current icon
+ """
+ self.__currentIcon = icon
+ self.iconChanged.emit(self.__currentIcon)
+
+
+class MovieAnimatedIcon(AbstractAnimatedIcon):
+ """Store a looping QMovie to provide icons for each frames.
+ Provides an event with the new icon everytime the movie frame
+ is updated."""
+
+ def __init__(self, filename, parent=None):
+ """Constructor
+
+ :param str filename: An icon name to an animated format
+ :param qt.QObject parent: Parent of the QObject
+ :raises: ValueError when name is not known
+ """
+ AbstractAnimatedIcon.__init__(self, parent)
+
+ qfile = getQFile(filename)
+ self.__movie = qt.QMovie(qfile.fileName(), qt.QByteArray(), parent)
+ self.__movie.setCacheMode(qt.QMovie.CacheAll)
+ self.__movie.frameChanged.connect(self.__frameChanged)
+ self.__cacheIcons = {}
+
+ self.__movie.jumpToFrame(0)
+ self.__updateIconAtFrame(0)
+
+ def __frameChanged(self, frameId):
+ """Callback everytime the QMovie frame change
+ :param int frameId: Current frame id
+ """
+ self.__updateIconAtFrame(frameId)
+
+ def __updateIconAtFrame(self, frameId):
+ """
+ Update the current stored QIcon
+
+ :param int frameId: Current frame id
+ """
+ if frameId in self.__cacheIcons:
+ icon = self.__cacheIcons[frameId]
+ else:
+ icon = qt.QIcon(self.__movie.currentPixmap())
+ self.__cacheIcons[frameId] = icon
+ self._setCurrentIcon(icon)
+
+ def _updateState(self):
+ """Update the movie play according to internal stat of the
+ AnimatedIcon."""
+ self.__movie.setPaused(not self.hasRegistredObjects())
+
+
+class MultiImageAnimatedIcon(AbstractAnimatedIcon):
+ """Store a looping QMovie to provide icons for each frames.
+ Provides an event with the new icon everytime the movie frame
+ is updated."""
+
+ def __init__(self, filename, parent=None):
+ """Constructor
+
+ :param str filename: An icon name to an animated format
+ :param qt.QObject parent: Parent of the QObject
+ :raises: ValueError when name is not known
+ """
+ AbstractAnimatedIcon.__init__(self, parent)
+
+ self.__frames = []
+ for i in range(100):
+ try:
+ pixmap = getQPixmap("animated/%s-%02d" % (filename, i))
+ except ValueError:
+ break
+ icon = qt.QIcon(pixmap)
+ self.__frames.append(icon)
+
+ if len(self.__frames) == 0:
+ raise ValueError("Animated icon '%s' do not exists" % filename)
+
+ self.__frameId = -1
+ self.__timer = qt.QTimer(self)
+ self.__timer.timeout.connect(self.__increaseFrame)
+ self.__updateIconAtFrame(0)
+
+ def __increaseFrame(self):
+ """Callback called every timer timeout to change the current frame of
+ the animation
+ """
+ frameId = (self.__frameId + 1) % len(self.__frames)
+ self.__updateIconAtFrame(frameId)
+
+ def __updateIconAtFrame(self, frameId):
+ """
+ Update the current stored QIcon
+
+ :param int frameId: Current frame id
+ """
+ self.__frameId = frameId
+ icon = self.__frames[frameId]
+ self._setCurrentIcon(icon)
+
+ def _updateState(self):
+ """Update the object to wake up or sleep it according to its use."""
+ if self.hasRegistredObjects():
+ if not self.__timer.isActive():
+ self.__timer.start(100)
+ else:
+ if self.__timer.isActive():
+ self.__timer.stop()
+
+
+class AnimatedIcon(MovieAnimatedIcon):
+ """Store a looping QMovie to provide icons for each frames.
+ Provides an event with the new icon everytime the movie frame
+ is updated.
+
+ It may not be available anymore for the silx release 0.6.
+
+ .. deprecated:: 0.5
+ Use :class:`MovieAnimatedIcon` instead.
+ """
+
+ @deprecated
+ def __init__(self, filename, parent=None):
+ MovieAnimatedIcon.__init__(self, filename, parent=parent)
+
+
+def getWaitIcon():
+ """Returns a cached version of the waiting AbstractAnimatedIcon.
+
+ :rtype: AbstractAnimatedIcon
+ """
+ return getAnimatedIcon("process-working")
+
+
+def getAnimatedIcon(name):
+ """Create an AbstractAnimatedIcon from a name.
+
+ Try to load a mng or a gif file, then try to load a multi-image animated
+ icon.
+
+ In Qt5 mng or gif are not used. It does not take care very well of the
+ transparency.
+
+ :param str name: Name of the icon, in one of the defined icons
+ in this module.
+ :return: Corresponding AbstractAnimatedIcon
+ :raises: ValueError when name is not known
+ """
+ key = name + "__anim"
+ if key not in _cached_icons:
+
+ qtMajorVersion = int(qt.qVersion().split(".")[0])
+ icon = None
+
+ # ignore mng and gif in Qt5
+ if qtMajorVersion != 5:
+ try:
+ icon = MovieAnimatedIcon(name)
+ except ValueError:
+ icon = None
+
+ if icon is None:
+ try:
+ icon = MultiImageAnimatedIcon(name)
+ except ValueError:
+ icon = None
+
+ if icon is None:
+ raise ValueError("Not an animated icon name: %s", name)
+
+ _cached_icons[key] = icon
+ else:
+ icon = _cached_icons[key]
+ return icon
+
+
+def getQIcon(name):
+ """Create a QIcon from its name.
+
+ :param str name: Name of the icon, in one of the defined icons
+ in this module.
+ :return: Corresponding QIcon
+ :raises: ValueError when name is not known
+ """
+ if name not in _cached_icons:
+ qfile = getQFile(name)
+ icon = qt.QIcon(qfile.fileName())
+ _cached_icons[name] = icon
+ else:
+ icon = _cached_icons[name]
+ return icon
+
+
+def getQPixmap(name):
+ """Create a QPixmap from its name.
+
+ :param str name: Name of the icon, in one of the defined icons
+ in this module.
+ :return: Corresponding QPixmap
+ :raises: ValueError when name is not known
+ """
+ qfile = getQFile(name)
+ return qt.QPixmap(qfile.fileName())
+
+
+def getQFile(name):
+ """Create a QFile from an icon name. Filename is found
+ according to supported Qt formats.
+
+ :param str name: Name of the icon, in one of the defined icons
+ in this module.
+ :return: Corresponding QFile
+ :rtype: qt.QFile
+ :raises: ValueError when name is not known
+ """
+ global _supported_formats
+ if _supported_formats is None:
+ _supported_formats = []
+ supported_formats = qt.supportedImageFormats()
+ order = ["mng", "gif", "svg", "png", "jpg"]
+ for format_ in order:
+ if format_ in supported_formats:
+ _supported_formats.append(format_)
+ if len(_supported_formats) == 0:
+ _logger.error("No format supported for icons")
+ else:
+ _logger.debug("Format %s supported", ", ".join(_supported_formats))
+
+ for format_ in _supported_formats:
+ format_ = str(format_)
+ filename = resource_filename('gui/icons/%s.%s' % (name, format_))
+ qfile = qt.QFile(filename)
+ if qfile.exists():
+ return qfile
+ raise ValueError('Not an icon name: %s' % name)