src/eric7/EricWidgets/EricMapWidget.py

branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9473
3f23dbf37dbe
equal deleted inserted replaced
9220:e9e7eca7efee 9221:bf71ee032bb4
14 14
15 class EricMapWidget(QWidget): 15 class EricMapWidget(QWidget):
16 """ 16 """
17 Class implementing a base class for showing a document map. 17 Class implementing a base class for showing a document map.
18 """ 18 """
19
19 def __init__(self, parent=None): 20 def __init__(self, parent=None):
20 """ 21 """
21 Constructor 22 Constructor
22 23
23 @param parent reference to the parent widget (QWidget) 24 @param parent reference to the parent widget (QWidget)
24 """ 25 """
25 super().__init__(parent) 26 super().__init__(parent)
26 self.setAttribute(Qt.WidgetAttribute.WA_OpaquePaintEvent) 27 self.setAttribute(Qt.WidgetAttribute.WA_OpaquePaintEvent)
27 28
28 self.__width = 14 29 self.__width = 14
29 self.__lineBorder = 1 30 self.__lineBorder = 1
30 self.__lineHeight = 2 31 self.__lineHeight = 2
31 self.__backgroundColor = QColor("#e7e7e7") 32 self.__backgroundColor = QColor("#e7e7e7")
32 self.__setSliderColor() 33 self.__setSliderColor()
33 34
34 self._master = None 35 self._master = None
35 self.__enabled = False 36 self.__enabled = False
36 self.__rightSide = True 37 self.__rightSide = True
37 38
38 if parent is not None and isinstance(parent, QAbstractScrollArea): 39 if parent is not None and isinstance(parent, QAbstractScrollArea):
39 self.setMaster(parent) 40 self.setMaster(parent)
40 41
41 def __setSliderColor(self): 42 def __setSliderColor(self):
42 """ 43 """
43 Private method to set the slider color depending upon the background 44 Private method to set the slider color depending upon the background
44 color. 45 color.
45 """ 46 """
47 # dark background, use white slider 48 # dark background, use white slider
48 self.__sliderColor = Qt.GlobalColor.white 49 self.__sliderColor = Qt.GlobalColor.white
49 else: 50 else:
50 # light background, use black slider 51 # light background, use black slider
51 self.__sliderColor = Qt.GlobalColor.black 52 self.__sliderColor = Qt.GlobalColor.black
52 53
53 def __updateMasterViewportWidth(self): 54 def __updateMasterViewportWidth(self):
54 """ 55 """
55 Private method to update the master's viewport width. 56 Private method to update the master's viewport width.
56 """ 57 """
57 if self._master: 58 if self._master:
61 width = 0 62 width = 0
62 if self.__rightSide: 63 if self.__rightSide:
63 self._master.setViewportMargins(0, 0, width, 0) 64 self._master.setViewportMargins(0, 0, width, 0)
64 else: 65 else:
65 self._master.setViewportMargins(width, 0, 0, 0) 66 self._master.setViewportMargins(width, 0, 0, 0)
66 67
67 def setMaster(self, master): 68 def setMaster(self, master):
68 """ 69 """
69 Public method to set the map master widget. 70 Public method to set the map master widget.
70 71
71 @param master map master widget (QAbstractScrollArea) 72 @param master map master widget (QAbstractScrollArea)
72 """ 73 """
73 self._master = master 74 self._master = master
74 self._master.setVerticalScrollBarPolicy( 75 self._master.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOn)
75 Qt.ScrollBarPolicy.ScrollBarAlwaysOn)
76 self._master.verticalScrollBar().valueChanged.connect(self.update) 76 self._master.verticalScrollBar().valueChanged.connect(self.update)
77 self._master.verticalScrollBar().rangeChanged.connect(self.update) 77 self._master.verticalScrollBar().rangeChanged.connect(self.update)
78 self.__updateMasterViewportWidth() 78 self.__updateMasterViewportWidth()
79 79
80 def setWidth(self, width): 80 def setWidth(self, width):
81 """ 81 """
82 Public method to set the widget width. 82 Public method to set the widget width.
83 83
84 @param width widget width (integer) 84 @param width widget width (integer)
85 """ 85 """
86 if width != self.__width: 86 if width != self.__width:
87 self.__width = max(6, width) # minimum width 6 pixels 87 self.__width = max(6, width) # minimum width 6 pixels
88 self.__updateMasterViewportWidth() 88 self.__updateMasterViewportWidth()
89 self.update() 89 self.update()
90 90
91 def width(self): 91 def width(self):
92 """ 92 """
93 Public method to get the widget's width. 93 Public method to get the widget's width.
94 94
95 @return widget width (integer) 95 @return widget width (integer)
96 """ 96 """
97 return self.__width 97 return self.__width
98 98
99 def setMapPosition(self, onRight): 99 def setMapPosition(self, onRight):
100 """ 100 """
101 Public method to set, whether the map should be shown to the right or 101 Public method to set, whether the map should be shown to the right or
102 left of the master widget. 102 left of the master widget.
103 103
104 @param onRight flag indicating to show the map on the right side of 104 @param onRight flag indicating to show the map on the right side of
105 the master widget 105 the master widget
106 @type bool 106 @type bool
107 """ 107 """
108 if onRight != self.__rightSide: 108 if onRight != self.__rightSide:
109 self.__rightSide = onRight 109 self.__rightSide = onRight
110 self.__updateMasterViewportWidth() 110 self.__updateMasterViewportWidth()
111 self.update() 111 self.update()
112 112
113 def isOnRightSide(self): 113 def isOnRightSide(self):
114 """ 114 """
115 Public method to test, if the map is shown on the right side of the 115 Public method to test, if the map is shown on the right side of the
116 master widget. 116 master widget.
117 117
118 @return flag indicating that the map is to the right of the master 118 @return flag indicating that the map is to the right of the master
119 widget 119 widget
120 @rtype bool 120 @rtype bool
121 """ 121 """
122 return self.__rightSide 122 return self.__rightSide
123 123
124 def setLineDimensions(self, border, height): 124 def setLineDimensions(self, border, height):
125 """ 125 """
126 Public method to set the line (indicator) dimensions. 126 Public method to set the line (indicator) dimensions.
127 127
128 @param border border width on each side in x-direction (integer) 128 @param border border width on each side in x-direction (integer)
129 @param height height of the line in pixels (integer) 129 @param height height of the line in pixels (integer)
130 """ 130 """
131 if border != self.__lineBorder or height != self.__lineHeight: 131 if border != self.__lineBorder or height != self.__lineHeight:
132 self.__lineBorder = max(1, border) # min border 1 pixel 132 self.__lineBorder = max(1, border) # min border 1 pixel
133 self.__lineHeight = max(1, height) # min height 1 pixel 133 self.__lineHeight = max(1, height) # min height 1 pixel
134 self.update() 134 self.update()
135 135
136 def lineDimensions(self): 136 def lineDimensions(self):
137 """ 137 """
138 Public method to get the line (indicator) dimensions. 138 Public method to get the line (indicator) dimensions.
139 139
140 @return tuple with border width (integer) and line height (integer) 140 @return tuple with border width (integer) and line height (integer)
141 """ 141 """
142 return self.__lineBorder, self.__lineHeight 142 return self.__lineBorder, self.__lineHeight
143 143
144 def setEnabled(self, enable): 144 def setEnabled(self, enable):
145 """ 145 """
146 Public method to set the enabled state. 146 Public method to set the enabled state.
147 147
148 @param enable flag indicating the enabled state (boolean) 148 @param enable flag indicating the enabled state (boolean)
149 """ 149 """
150 if enable != self.__enabled: 150 if enable != self.__enabled:
151 self.__enabled = enable 151 self.__enabled = enable
152 self.setVisible(enable) 152 self.setVisible(enable)
153 self.__updateMasterViewportWidth() 153 self.__updateMasterViewportWidth()
154 154
155 def isEnabled(self): 155 def isEnabled(self):
156 """ 156 """
157 Public method to check the enabled state. 157 Public method to check the enabled state.
158 158
159 @return flag indicating the enabled state (boolean) 159 @return flag indicating the enabled state (boolean)
160 """ 160 """
161 return self.__enabled 161 return self.__enabled
162 162
163 def setBackgroundColor(self, color): 163 def setBackgroundColor(self, color):
164 """ 164 """
165 Public method to set the widget background color. 165 Public method to set the widget background color.
166 166
167 @param color color for the background (QColor) 167 @param color color for the background (QColor)
168 """ 168 """
169 if color != self.__backgroundColor: 169 if color != self.__backgroundColor:
170 self.__backgroundColor = color 170 self.__backgroundColor = color
171 self.__setSliderColor() 171 self.__setSliderColor()
172 self.update() 172 self.update()
173 173
174 def backgroundColor(self): 174 def backgroundColor(self):
175 """ 175 """
176 Public method to get the background color. 176 Public method to get the background color.
177 177
178 @return background color (QColor) 178 @return background color (QColor)
179 """ 179 """
180 return QColor(self.__backgroundColor) 180 return QColor(self.__backgroundColor)
181 181
182 def sizeHint(self): 182 def sizeHint(self):
183 """ 183 """
184 Public method to give an indication about the preferred size. 184 Public method to give an indication about the preferred size.
185 185
186 @return preferred size (QSize) 186 @return preferred size (QSize)
187 """ 187 """
188 return QSize(self.__width, 0) 188 return QSize(self.__width, 0)
189 189
190 def paintEvent(self, event): 190 def paintEvent(self, event):
191 """ 191 """
192 Protected method to handle a paint event. 192 Protected method to handle a paint event.
193 193
194 @param event paint event (QPaintEvent) 194 @param event paint event (QPaintEvent)
195 """ 195 """
196 # step 1: fill the whole painting area 196 # step 1: fill the whole painting area
197 painter = QPainter(self) 197 painter = QPainter(self)
198 painter.fillRect(event.rect(), self.__backgroundColor) 198 painter.fillRect(event.rect(), self.__backgroundColor)
199 199
200 # step 2: paint the indicators 200 # step 2: paint the indicators
201 self._paintIt(painter) 201 self._paintIt(painter)
202 202
203 # step 3: paint the slider 203 # step 3: paint the slider
204 if self._master: 204 if self._master:
205 penColor = self.__sliderColor 205 penColor = self.__sliderColor
206 painter.setPen(penColor) 206 painter.setPen(penColor)
207 brushColor = Qt.GlobalColor.transparent 207 brushColor = Qt.GlobalColor.transparent
208 painter.setBrush(QBrush(brushColor)) 208 painter.setBrush(QBrush(brushColor))
209 painter.drawRect(self.__generateSliderRange( 209 painter.drawRect(
210 self._master.verticalScrollBar())) 210 self.__generateSliderRange(self._master.verticalScrollBar())
211 211 )
212
212 def _paintIt(self, painter): 213 def _paintIt(self, painter):
213 """ 214 """
214 Protected method for painting the widget's indicators. 215 Protected method for painting the widget's indicators.
215 216
216 Note: This method should be implemented by subclasses. 217 Note: This method should be implemented by subclasses.
217 218
218 @param painter reference to the painter object (QPainter) 219 @param painter reference to the painter object (QPainter)
219 """ 220 """
220 pass 221 pass
221 222
222 def mousePressEvent(self, event): 223 def mousePressEvent(self, event):
223 """ 224 """
224 Protected method to handle a mouse button press. 225 Protected method to handle a mouse button press.
225 226
226 @param event reference to the mouse event (QMouseEvent) 227 @param event reference to the mouse event (QMouseEvent)
227 """ 228 """
228 if event.button() == Qt.MouseButton.LeftButton and self._master: 229 if event.button() == Qt.MouseButton.LeftButton and self._master:
229 vsb = self._master.verticalScrollBar() 230 vsb = self._master.verticalScrollBar()
230 value = self.position2Value(event.position().toPoint().y() - 1) 231 value = self.position2Value(event.position().toPoint().y() - 1)
231 vsb.setValue(int(value - 0.5 * vsb.pageStep())) # center on page 232 vsb.setValue(int(value - 0.5 * vsb.pageStep())) # center on page
232 self.__mousePressPos = None 233 self.__mousePressPos = None
233 234
234 def mouseMoveEvent(self, event): 235 def mouseMoveEvent(self, event):
235 """ 236 """
236 Protected method to handle a mouse moves. 237 Protected method to handle a mouse moves.
237 238
238 @param event reference to the mouse event (QMouseEvent) 239 @param event reference to the mouse event (QMouseEvent)
239 """ 240 """
240 if event.buttons() & Qt.MouseButton.LeftButton and self._master: 241 if event.buttons() & Qt.MouseButton.LeftButton and self._master:
241 vsb = self._master.verticalScrollBar() 242 vsb = self._master.verticalScrollBar()
242 value = self.position2Value(event.position().toPoint().y() - 1) 243 value = self.position2Value(event.position().toPoint().y() - 1)
243 vsb.setValue(int(value - 0.5 * vsb.pageStep())) # center on page 244 vsb.setValue(int(value - 0.5 * vsb.pageStep())) # center on page
244 245
245 def wheelEvent(self, event): 246 def wheelEvent(self, event):
246 """ 247 """
247 Protected slot handling mouse wheel events. 248 Protected slot handling mouse wheel events.
248 249
249 @param event reference to the wheel event (QWheelEvent) 250 @param event reference to the wheel event (QWheelEvent)
250 """ 251 """
251 isVertical = event.angleDelta().x() == 0 252 isVertical = event.angleDelta().x() == 0
252 if ( 253 if (
253 self._master and 254 self._master
254 event.modifiers() == Qt.KeyboardModifier.NoModifier and 255 and event.modifiers() == Qt.KeyboardModifier.NoModifier
255 isVertical 256 and isVertical
256 ): 257 ):
257 QCoreApplication.sendEvent(self._master.verticalScrollBar(), event) 258 QCoreApplication.sendEvent(self._master.verticalScrollBar(), event)
258 259
259 def calculateGeometry(self): 260 def calculateGeometry(self):
260 """ 261 """
261 Public method to recalculate the map widget's geometry. 262 Public method to recalculate the map widget's geometry.
262 """ 263 """
263 if self._master: 264 if self._master:
270 margins = self._master.contentsMargins() 271 margins = self._master.contentsMargins()
271 if margins.right() > vsbw: 272 if margins.right() > vsbw:
272 vsbw = 0 273 vsbw = 0
273 if self.__rightSide: 274 if self.__rightSide:
274 self.setGeometry( 275 self.setGeometry(
275 QRect(cr.right() - self.__width - vsbw, cr.top(), 276 QRect(
276 self.__width, cr.height())) 277 cr.right() - self.__width - vsbw,
278 cr.top(),
279 self.__width,
280 cr.height(),
281 )
282 )
277 else: 283 else:
278 self.setGeometry( 284 self.setGeometry(QRect(0, cr.top(), self.__width, cr.height()))
279 QRect(0, cr.top(), self.__width, cr.height())) 285 self.update()
280 self.update() 286
281
282 def scaleFactor(self, slider=False): 287 def scaleFactor(self, slider=False):
283 """ 288 """
284 Public method to determine the scrollbar's scale factor. 289 Public method to determine the scrollbar's scale factor.
285 290
286 @param slider flag indicating to calculate the result for the slider 291 @param slider flag indicating to calculate the result for the slider
287 (boolean) 292 (boolean)
288 @return scale factor (float) 293 @return scale factor (float)
289 """ 294 """
290 if self._master: 295 if self._master:
293 posHeight = vsb.height() - delta - 1 298 posHeight = vsb.height() - delta - 1
294 valHeight = vsb.maximum() - vsb.minimum() + vsb.pageStep() 299 valHeight = vsb.maximum() - vsb.minimum() + vsb.pageStep()
295 return float(posHeight) / valHeight 300 return float(posHeight) / valHeight
296 else: 301 else:
297 return 1.0 302 return 1.0
298 303
299 def value2Position(self, value, slider=False): 304 def value2Position(self, value, slider=False):
300 """ 305 """
301 Public method to convert a scrollbar value into a position. 306 Public method to convert a scrollbar value into a position.
302 307
303 @param value value to convert (integer) 308 @param value value to convert (integer)
304 @param slider flag indicating to calculate the result for the slider 309 @param slider flag indicating to calculate the result for the slider
305 (boolean) 310 (boolean)
306 @return position (integer) 311 @return position (integer)
307 """ 312 """
308 if self._master: 313 if self._master:
309 offset = 0 if slider else 1 314 offset = 0 if slider else 1
310 vsb = self._master.verticalScrollBar() 315 vsb = self._master.verticalScrollBar()
311 return int((value - vsb.minimum()) * self.scaleFactor(slider) + 316 return int((value - vsb.minimum()) * self.scaleFactor(slider) + offset)
312 offset)
313 else: 317 else:
314 return value 318 return value
315 319
316 def position2Value(self, position, slider=False): 320 def position2Value(self, position, slider=False):
317 """ 321 """
318 Public method to convert a position into a scrollbar value. 322 Public method to convert a position into a scrollbar value.
319 323
320 @param position scrollbar position to convert (integer) 324 @param position scrollbar position to convert (integer)
321 @param slider flag indicating to calculate the result for the slider 325 @param slider flag indicating to calculate the result for the slider
322 (boolean) 326 (boolean)
323 @return scrollbar value (integer) 327 @return scrollbar value (integer)
324 """ 328 """
325 if self._master: 329 if self._master:
326 offset = 0 if slider else 1 330 offset = 0 if slider else 1
327 vsb = self._master.verticalScrollBar() 331 vsb = self._master.verticalScrollBar()
328 return vsb.minimum() + max( 332 return vsb.minimum() + max(
329 0, (position - offset) / self.scaleFactor(slider)) 333 0, (position - offset) / self.scaleFactor(slider)
334 )
330 else: 335 else:
331 return position 336 return position
332 337
333 def generateIndicatorRect(self, position): 338 def generateIndicatorRect(self, position):
334 """ 339 """
335 Public method to generate an indicator rectangle. 340 Public method to generate an indicator rectangle.
336 341
337 @param position indicator position (integer) 342 @param position indicator position (integer)
338 @return indicator rectangle (QRect) 343 @return indicator rectangle (QRect)
339 """ 344 """
340 return QRect(self.__lineBorder, position - self.__lineHeight // 2, 345 return QRect(
341 self.__width - self.__lineBorder, self.__lineHeight) 346 self.__lineBorder,
342 347 position - self.__lineHeight // 2,
348 self.__width - self.__lineBorder,
349 self.__lineHeight,
350 )
351
343 def __generateSliderRange(self, scrollbar): 352 def __generateSliderRange(self, scrollbar):
344 """ 353 """
345 Private method to generate the slider rectangle. 354 Private method to generate the slider rectangle.
346 355
347 @param scrollbar reference to the vertical scrollbar (QScrollBar) 356 @param scrollbar reference to the vertical scrollbar (QScrollBar)
348 @return slider rectangle (QRect) 357 @return slider rectangle (QRect)
349 """ 358 """
350 pos1 = self.value2Position(scrollbar.value(), slider=True) 359 pos1 = self.value2Position(scrollbar.value(), slider=True)
351 pos2 = self.value2Position(scrollbar.value() + scrollbar.pageStep(), 360 pos2 = self.value2Position(
352 slider=True) 361 scrollbar.value() + scrollbar.pageStep(), slider=True
362 )
353 return QRect(0, pos1, self.__width - 1, pos2 - pos1) 363 return QRect(0, pos1, self.__width - 1, pos2 - pos1)

eric ide

mercurial