E5Gui/E5MapWidget.py

changeset 3327
1338767b5315
child 3329
1ee38e29ed4f
equal deleted inserted replaced
3326:b4868bd56338 3327:1338767b5315
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2014 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing a base class for showing a document map.
8 """
9
10 from PyQt4.QtCore import Qt, QSize, QRect
11 from PyQt4.QtGui import QWidget, QAbstractScrollArea, QColor, QBrush, QPainter
12
13
14 class E5MapWidget(QWidget):
15 """
16 Class implementing a base class for showing a document map.
17 """
18 def __init__(self, parent=None):
19 """
20 Constructor
21
22 @param parent reference to the parent widget (QWidget)
23 """
24 super().__init__(parent)
25 self.setAttribute(Qt.WA_OpaquePaintEvent)
26
27 self.__width = 12
28 self.__lineBorder = 2
29 self.__lineHeight = 2
30 self.__backgroundColor = QColor(Qt.lightGray).lighter(120)
31 self.__sliderBorderColor = QColor(Qt.black)
32 self.__sliderBackgroundColor = QColor(Qt.white)
33
34 self.__master = None
35 self.__enabled = False
36
37 if parent is not None and isinstance(parent, QAbstractScrollArea):
38 self.setMaster(parent)
39
40 def __updateMasterViewportWidth(self):
41 """
42 Private method to update the master's viewport width.
43 """
44 if self.__master:
45 if self.__enabled:
46 width = self.__width
47 else:
48 width = 0
49 self.__master.setViewportMargins(0, 0, width, 0)
50
51 def setMaster(self, master):
52 """
53 Public method to set the map master widget.
54
55 @param master map master widget (QAbstractScrollArea)
56 """
57 self.__master = master
58 self.__master.verticalScrollBar().valueChanged.connect(self.repaint)
59 self.__updateMasterViewportWidth()
60
61 def setWidth(self, width):
62 """
63 Public method to set the widget width.
64
65 @param width widget width (integer)
66 """
67 self.__width = width
68
69 def width(self):
70 """
71 Public method to get the widget's width.
72
73 @return widget width (integer)
74 """
75 return self.__width
76
77 def setLineDimensions(self, border, height):
78 """
79 Public method to set the line (indicator) dimensions.
80
81 @param border border width on each side in x-direction (integer)
82 @param height height of the line in pixels (integer)
83 """
84 self.__lineBorder = border
85 self.__lineHeight = max(2, height) # min height is 2 pixels
86
87 def lineDimensions(self):
88 """
89 Public method to get the line (indicator) dimensions.
90
91 @return tuple with border width (integer) and line height (integer)
92 """
93 return self.__lineBorder, self.__lineHeight
94
95 def setEnabled(self, enable):
96 """
97 Public method to set the enabled state.
98
99 @param enable flag indicating the enabled state (boolean)
100 """
101 self.__enabled = enable
102 self.setVisible(enable)
103 self.__updateMasterViewportWidth()
104
105 def isEnabled(self):
106 """
107 Public method to check the enabled state.
108
109 @return flag indicating the enabled state (boolean)
110 """
111 return self.__enabled
112
113 def setBackgroundColor(self, color):
114 """
115 Public method to set the widget background color.
116
117 @param color color for the background (QColor)
118 """
119 self.__backgroundColor = color
120
121 def backgroundColor(self):
122 """
123 Public method to get the background color.
124
125 @return background color (QColor)
126 """
127 return QColor(self.__backgroundColor)
128
129 def setSliderColors(self, border, background):
130 """
131 Public method to set the slider colors.
132
133 @param border border color (QColor)
134 @param background background color (QColor)
135 """
136 self.__sliderBorderColor = border
137 self.__sliderBackgroundColor = background
138
139 def sliderColors(self):
140 """
141 Public method to get the slider colors.
142
143 @return tuple with the slider's border color (QColor) and
144 background color (QColor)
145 """
146 return (QColor(self.__sliderBorderColor),
147 QColor(self.__sliderBackgroundColor))
148
149 def sizeHint(self):
150 """
151 Public method to give an indication about the preferred size.
152
153 @return preferred size (QSize)
154 """
155 return QSize(self.__width, 0)
156
157 def paintEvent(self, event):
158 """
159 Protected method to handle a paint event.
160
161 @param event paint event (QPaintEvent)
162 """
163 # step 1: fill the whole painting area
164 painter = QPainter(self)
165 painter.fillRect(event.rect(), self.__backgroundColor)
166
167 # step 2: paint the indicators
168 self._paintIt(painter)
169
170 # step 3: paint the slider
171 if self.__master:
172 penColor = self.__sliderBorderColor
173 penColor.setAlphaF(0.8)
174 painter.setPen(penColor)
175 brushColor = self.__sliderBackgroundColor
176 brushColor.setAlphaF(0.5)
177 painter.setBrush(QBrush(brushColor))
178 painter.drawRect(self.__generateSliderRange(
179 self.__master.verticalScrollBar()))
180
181 def _paintIt(self, painter):
182 """
183 Protected method for painting the widget's indicators.
184
185 Note: This method should be implemented by subclasses.
186
187 @param painter reference to the painter object (QPainter)
188 """
189 pass
190
191 def mousePressEvent(self, event):
192 """
193 Protected method to handle a mouse button press.
194
195 @param event mouse event (QMouseEvent)
196 """
197 if event.button() == Qt.LeftButton and self.__master:
198 vsb = self.__master.verticalScrollBar()
199 value = self.position2Value(event.pos().y() - 1)
200 vsb.setValue(value - 0.5 * vsb.pageStep()) # center on page
201
202 def calculateGeometry(self):
203 """
204 Public method to recalculate the map widget's geometry.
205 """
206 if self.__master:
207 cr = self.__master.contentsRect()
208 vsb = self.__master.verticalScrollBar()
209 if vsb.isVisible():
210 vsbw = vsb.contentsRect().width()
211 else:
212 vsbw = 0
213 left, top, right, bottom = self.__master.getContentsMargins()
214 if right > vsbw:
215 vsbw = 0
216 self.setGeometry(QRect(cr.right() - self.__width - vsbw, cr.top(),
217 self.__width, cr.height()))
218
219 def scaleFactor(self, slider=False):
220 """
221 Public method to determine the scrollbar's scale factor.
222
223 @param slider flag indicating to calculate the result for the slider
224 (boolean)
225 @return scale factor (float)
226 """
227 if self.__master:
228 delta = 0 if slider else 2
229 vsb = self.__master.verticalScrollBar()
230 posHeight = vsb.height() - delta - 1
231 valHeight = vsb.maximum() - vsb.minimum() + vsb.pageStep()
232 return posHeight / valHeight
233 else:
234 return 1.0
235
236 def value2Position(self, value, slider=False):
237 """
238 Public method to convert a scrollbar value into a position.
239
240 @param value value to convert (integer)
241 @param slider flag indicating to calculate the result for the slider
242 (boolean)
243 @return position (integer)
244 """
245 if self.__master:
246 offset = 0 if slider else 1
247 vsb = self.__master.verticalScrollBar()
248 return (value - vsb.minimum()) * self.scaleFactor(slider) + offset
249 else:
250 return value
251
252 def position2Value(self, position, slider=False):
253 """
254 Public method to convert a position into a scrollbar value.
255
256 @param position scrollbar position to convert (integer)
257 @param slider flag indicating to calculate the result for the slider
258 (boolean)
259 @return scrollbar value (integer)
260 """
261 if self.__master:
262 offset = 0 if slider else 1
263 vsb = self.__master.verticalScrollBar()
264 return vsb.minimum() + max(
265 0, (position - offset) / self.scaleFactor(slider))
266 else:
267 return position
268
269 def generateIndicatorRect(self, position):
270 """
271 Public method to generate an indicator rectangle.
272
273 @param position indicator position (integer)
274 @return indicator rectangle (QRect)
275 """
276 return QRect(self.__lineBorder, position - self.__lineHeight // 2,
277 self.__width - self.__lineBorder, self.__lineHeight)
278
279 def __generateSliderRange(self, scrollbar):
280 """
281 Private method to generate the slider rectangle.
282
283 @param scrollbar reference to the vertical scrollbar (QScrollBar)
284 @return slider rectangle (QRect)
285 """
286 pos1 = self.value2Position(scrollbar.value(), slider=True)
287 pos2 = self.value2Position(scrollbar.value() + scrollbar.pageStep(),
288 slider=True)
289 return QRect(1, pos1, self.__width - 2, pos2 - pos1 + 1)
290 # TODO: check slider appearance and adjust to self.__width

eric ide

mercurial