1# -*- coding: utf-8 -*-
2
3# Copyright (c) 2004 - 2021 Detlev Offenbach <detlev@die-offenbachs.de>
4#
5
6"""
7Module implementing a pixmap cache for icons.
8"""
9
10import os
11
12from PyQt5.QtCore import Qt, QSize
13from PyQt5.QtGui import QPixmap, QIcon, QPainter
14
15
16class PixmapCache:
17    """
18    Class implementing a pixmap cache for icons.
19    """
20    SupportedExtensions = [".svgz", ".svg", ".png"]
21
22    def __init__(self):
23        """
24        Constructor
25        """
26        self.pixmapCache = {}
27        self.searchPath = []
28
29    def getPixmap(self, key, size=None):
30        """
31        Public method to retrieve a pixmap.
32
33        @param key name of the wanted pixmap
34        @type str
35        @param size requested size
36        @type QSize
37        @return the requested pixmap
38        @rtype QPixmap
39        """
40        if key:
41            basename, ext = os.path.splitext(key)
42            if size and not size.isEmpty():
43                key = "{0}_{1}_{2}".format(
44                    basename, size.width(), size.height())
45            else:
46                key = basename
47
48            try:
49                return self.pixmapCache[key]
50            except KeyError:
51                pm = QPixmap()
52                for extension in self.SupportedExtensions:
53                    filename = basename + extension
54                    if not os.path.isabs(filename):
55                        for path in self.searchPath:
56                            pm = QPixmap(path + "/" + filename)
57                            if not pm.isNull():
58                                break
59                    else:
60                        pm = QPixmap(filename)
61                    if not pm.isNull():
62                        if size and not size.isEmpty():
63                            pm = pm.scaled(size)
64                        break
65                else:
66                    pm = QPixmap()
67
68                self.pixmapCache[key] = pm
69                return self.pixmapCache[key]
70
71        return QPixmap()
72
73    def addSearchPath(self, path):
74        """
75        Public method to add a path to the search path.
76
77        @param path path to add
78        @type str
79        """
80        if path not in self.searchPath:
81            self.searchPath.append(path)
82
83    def removeSearchPath(self, path):
84        """
85        Public method to remove a path from the search path.
86
87        @param path path to remove
88        @type str
89        """
90        if path in self.searchPath:
91            self.searchPath.remove(path)
92
93pixCache = PixmapCache()
94
95
96def getPixmap(key, size=None, cache=pixCache):
97    """
98    Module function to retrieve a pixmap.
99
100    @param key name of the wanted pixmap
101    @type str
102    @param size requested size
103    @type QSize
104    @param cache reference to the pixmap cache object
105    @type PixmapCache
106    @return the requested pixmap
107    @rtype QPixmap
108    """
109    return cache.getPixmap(key, size=size)
110
111
112def getIcon(key, size=None, cache=pixCache):
113    """
114    Module function to retrieve an icon.
115
116    @param key name of the wanted pixmap
117    @type str
118    @param size requested size
119    @type QSize
120    @param cache reference to the pixmap cache object
121    @type PixmapCache
122    @return the requested icon
123    @rtype QIcon
124    """
125    return QIcon(cache.getPixmap(key, size=size))
126
127
128def getSymlinkIcon(key, size=None, cache=pixCache):
129    """
130    Module function to retrieve a symbolic link icon.
131
132    @param key name of the wanted pixmap
133    @type str
134    @param size requested size
135    @type QSize
136    @param cache reference to the pixmap cache object
137    @type PixmapCache
138    @return the requested icon
139    @rtype QIcon
140    """
141    pix1 = QPixmap(cache.getPixmap(key, size=size))
142    pix2 = cache.getPixmap("symlink")
143    painter = QPainter(pix1)
144    painter.drawPixmap(0, 10, pix2)
145    painter.end()
146    return QIcon(pix1)
147
148
149def getCombinedIcon(keys, size=None, cache=pixCache):
150    """
151    Module function to retrieve a symbolic link icon.
152
153    @param keys list of names of icons
154    @type list of str
155    @param size requested size of individual icons
156    @type QSize
157    @param cache reference to the pixmap cache object
158    @type PixmapCache
159    @return the requested icon
160    @rtype QIcon
161    """
162    height = width = 0
163    pixmaps = []
164    for key in keys:
165        pix = cache.getPixmap(key, size=size)
166        if not pix.isNull():
167            height = max(height, pix.height())
168            width = max(width, pix.width())
169            pixmaps.append(pix)
170    if pixmaps:
171        pix = QPixmap(len(pixmaps) * width, height)
172        pix.fill(Qt.GlobalColor.transparent)
173        painter = QPainter(pix)
174        x = 0
175        for pixmap in pixmaps:
176            painter.drawPixmap(x, 0, pixmap.scaled(QSize(width, height)))
177            x += width
178        painter.end()
179        icon = QIcon(pix)
180    else:
181        icon = QIcon()
182    return icon
183
184
185def addSearchPath(path, cache=pixCache):
186    """
187    Module function to add a path to the search path.
188
189    @param path path to add
190    @type str
191    @param cache reference to the pixmap cache object
192    @type PixmapCache
193    """
194    cache.addSearchPath(path)
195
196
197def removeSearchPath(path, cache=pixCache):
198    """
199    Public method to remove a path from the search path.
200
201    @param path path to remove
202    @type str
203    @param cache reference to the pixmap cache object
204    @type PixmapCache
205    """
206    cache.removeSearchPath(path)
207