6 from PyQt4 import QtGui
7 from PyQt4 import QtCore
10 from util import misc as misc_utils
12 class misc_utils(object):
15 def log_exception(logger):
22 _moduleLogger = logging.getLogger(__name__)
28 def _radius_at(center, pos):
33 radius = math.sqrt(xDelta ** 2 + yDelta ** 2)
37 def _angle_at(center, pos):
42 radius = math.sqrt(xDelta ** 2 + yDelta ** 2)
43 angle = math.acos(xDelta / radius)
45 angle = _TWOPI - angle
50 class QActionPieItem(object):
52 def __init__(self, action, weight = 1):
59 def setWeight(self, weight):
65 def setEnabled(self, enabled = True):
66 self._action.setEnabled(enabled)
69 return self._action.isEnabled()
72 class PieFiling(object):
74 INNER_RADIUS_DEFAULT = 32
75 OUTER_RADIUS_DEFAULT = 128
80 NULL_CENTER = QActionPieItem(QtGui.QAction(None))
83 self._innerRadius = self.INNER_RADIUS_DEFAULT
84 self._outerRadius = self.OUTER_RADIUS_DEFAULT
86 self._center = self.NULL_CENTER
88 self._cacheIndexToAngle = {}
89 self._cacheTotalWeight = 0
91 def insertItem(self, item, index = -1):
92 self._children.insert(index, item)
93 self._invalidate_cache()
95 def removeItemAt(self, index):
96 item = self._children.pop(index)
97 self._invalidate_cache()
99 def set_center(self, item):
101 item = self.NULL_CENTER
108 del self._children[:]
109 self._center = self.NULL_CENTER
110 self._invalidate_cache()
112 def itemAt(self, index):
113 return self._children[index]
115 def indexAt(self, center, point):
116 return self._angle_to_index(_angle_at(center, point))
118 def innerRadius(self):
119 return self._innerRadius
121 def setInnerRadius(self, radius):
122 self._innerRadius = radius
124 def outerRadius(self):
125 return self._outerRadius
127 def setOuterRadius(self, radius):
128 self._outerRadius = radius
131 return iter(self._children)
134 return len(self._children)
136 def __getitem__(self, index):
137 return self._children[index]
139 def _invalidate_cache(self):
140 self._cacheIndexToAngle.clear()
141 self._cacheTotalWeight = sum(child.weight() for child in self._children)
142 if self._cacheTotalWeight == 0:
143 self._cacheTotalWeight = 1
145 def _index_to_angle(self, index, isShifted):
146 key = index, isShifted
147 if key in self._cacheIndexToAngle:
148 return self._cacheIndexToAngle[key]
149 index = index % len(self._children)
151 baseAngle = _TWOPI / self._cacheTotalWeight
156 angle -= (self._children[0].weight() * baseAngle) / 2
158 angle -= baseAngle / 2
162 for i, child in enumerate(self._children):
165 angle += child.weight() * baseAngle
166 while _TWOPI < angle:
169 self._cacheIndexToAngle[key] = angle
172 def _angle_to_index(self, angle):
173 numChildren = len(self._children)
175 return self.SELECTION_CENTER
177 baseAngle = _TWOPI / self._cacheTotalWeight
179 iterAngle = math.pi / 2 - (self.itemAt(0).weight() * baseAngle) / 2
183 oldIterAngle = iterAngle
184 for index, child in enumerate(self._children):
185 iterAngle += child.weight() * baseAngle
186 if oldIterAngle < angle and angle <= iterAngle:
187 return index - 1 if index != 0 else numChildren - 1
188 elif oldIterAngle < (angle + _TWOPI) and (angle + _TWOPI <= iterAngle):
189 return index - 1 if index != 0 else numChildren - 1
190 oldIterAngle = iterAngle
193 class PieArtist(object):
195 ICON_SIZE_DEFAULT = 32
197 def __init__(self, filing):
198 # @bug Plus it would be a good idea to fill in the icon body's
199 # @bug Maybe even make the icons glow?
200 self._filing = filing
202 self._cachedOuterRadius = self._filing.outerRadius()
203 self._cachedInnerRadius = self._filing.innerRadius()
204 canvasSize = self._cachedOuterRadius * 2 + 1
205 self._canvas = QtGui.QPixmap(canvasSize, canvasSize)
210 diameter = self._filing.outerRadius() * 2 + 1
211 return QtCore.QSize(diameter, diameter)
213 def centerSize(self):
214 painter = QtGui.QPainter(self._canvas)
215 text = self._filing.center().action().text()
216 fontMetrics = painter.fontMetrics()
218 textBoundingRect = fontMetrics.boundingRect(text)
220 textBoundingRect = QtCore.QRect()
221 textWidth = textBoundingRect.width()
222 textHeight = textBoundingRect.height()
225 textWidth + self.ICON_SIZE_DEFAULT,
226 max(textHeight, self.ICON_SIZE_DEFAULT),
229 def show(self, palette):
230 self.palette = palette
233 self._cachedOuterRadius != self._filing.outerRadius() or
234 self._cachedInnerRadius != self._filing.innerRadius()
236 self._cachedOuterRadius = self._filing.outerRadius()
237 self._cachedInnerRadius = self._filing.innerRadius()
238 self._canvas = self._canvas.scaled(self.pieSize())
240 if self._mask is None:
241 self._mask = QtGui.QBitmap(self._canvas.size())
242 self._mask.fill(QtCore.Qt.color0)
243 self._generate_mask(self._mask)
244 self._canvas.setMask(self._mask)
250 def paint(self, selectionIndex):
251 painter = QtGui.QPainter(self._canvas)
252 painter.setRenderHint(QtGui.QPainter.Antialiasing, True)
254 adjustmentRect = self._canvas.rect().adjusted(0, 0, -1, -1)
256 numChildren = len(self._filing)
258 if selectionIndex == PieFiling.SELECTION_CENTER and self._filing.center().isEnabled():
259 painter.setBrush(self.palette.highlight())
261 painter.setBrush(self.palette.window())
262 painter.setPen(self.palette.mid().color())
264 painter.drawRect(self._canvas.rect())
265 self._paint_center_foreground(painter, selectionIndex)
267 elif numChildren == 1:
268 if selectionIndex == 0 and self._filing[0].isEnabled():
269 painter.setBrush(self.palette.highlight())
271 painter.setBrush(self.palette.window())
273 painter.fillRect(self._canvas.rect(), painter.brush())
275 for i in xrange(len(self._filing)):
276 self._paint_slice_background(painter, adjustmentRect, i, selectionIndex)
278 self._paint_center_background(painter, adjustmentRect, selectionIndex)
279 self._paint_center_foreground(painter, selectionIndex)
281 for i in xrange(len(self._filing)):
282 self._paint_slice_foreground(painter, i, selectionIndex)
286 def _generate_mask(self, mask):
288 Specifies on the mask the shape of the pie menu
290 painter = QtGui.QPainter(mask)
291 painter.setPen(QtCore.Qt.color1)
292 painter.setBrush(QtCore.Qt.color1)
293 painter.drawEllipse(mask.rect().adjusted(0, 0, -1, -1))
295 def _paint_slice_background(self, painter, adjustmentRect, i, selectionIndex):
296 if i == selectionIndex and self._filing[i].isEnabled():
297 painter.setBrush(self.palette.highlight())
299 painter.setBrush(self.palette.window())
300 painter.setPen(self.palette.mid().color())
302 a = self._filing._index_to_angle(i, True)
303 b = self._filing._index_to_angle(i + 1, True)
310 startAngleInDeg = (a * 360 * 16) / _TWOPI
311 sizeInDeg = (size * 360 * 16) / _TWOPI
312 painter.drawPie(adjustmentRect, int(startAngleInDeg), int(sizeInDeg))
314 def _paint_slice_foreground(self, painter, i, selectionIndex):
315 child = self._filing[i]
317 a = self._filing._index_to_angle(i, True)
318 b = self._filing._index_to_angle(i + 1, True)
321 middleAngle = (a + b) / 2
322 averageRadius = (self._cachedInnerRadius + self._cachedOuterRadius) / 2
324 sliceX = averageRadius * math.cos(middleAngle)
325 sliceY = - averageRadius * math.sin(middleAngle)
327 piePos = self._canvas.rect().center()
331 painter, child.action(), i == selectionIndex, pieX+sliceX, pieY+sliceY
334 def _paint_label(self, painter, action, isSelected, x, y):
336 fontMetrics = painter.fontMetrics()
338 textBoundingRect = fontMetrics.boundingRect(text)
340 textBoundingRect = QtCore.QRect()
341 textWidth = textBoundingRect.width()
342 textHeight = textBoundingRect.height()
344 icon = action.icon().pixmap(
345 QtCore.QSize(self.ICON_SIZE_DEFAULT, self.ICON_SIZE_DEFAULT),
349 iconWidth = icon.width()
350 iconHeight = icon.width()
351 averageWidth = (iconWidth + textWidth)/2
352 if not icon.isNull():
353 iconRect = QtCore.QRect(
360 painter.drawPixmap(iconRect, icon)
364 if action.isEnabled():
365 pen = self.palette.highlightedText()
366 brush = self.palette.highlight()
368 pen = self.palette.mid()
369 brush = self.palette.window()
371 if action.isEnabled():
372 pen = self.palette.windowText()
374 pen = self.palette.mid()
375 brush = self.palette.window()
377 leftX = x - averageWidth + iconWidth
378 topY = y + textHeight/2
379 painter.setPen(pen.color())
380 painter.setBrush(brush)
381 painter.drawText(leftX, topY, text)
383 def _paint_center_background(self, painter, adjustmentRect, selectionIndex):
384 dark = self.palette.dark().color()
385 light = self.palette.light().color()
386 if selectionIndex == PieFiling.SELECTION_CENTER and self._filing.center().isEnabled():
387 background = self.palette.highlight().color()
389 background = self.palette.window().color()
391 innerRadius = self._cachedInnerRadius
392 adjustmentCenterPos = adjustmentRect.center()
393 innerRect = QtCore.QRect(
394 adjustmentCenterPos.x() - innerRadius,
395 adjustmentCenterPos.y() - innerRadius,
400 painter.setPen(QtCore.Qt.NoPen)
401 painter.setBrush(background)
402 painter.drawPie(innerRect, 0, 360 * 16)
404 painter.setPen(QtGui.QPen(dark, 1))
405 painter.setBrush(QtCore.Qt.NoBrush)
406 painter.drawEllipse(innerRect)
408 painter.setPen(QtGui.QPen(dark, 1))
409 painter.setBrush(QtCore.Qt.NoBrush)
410 painter.drawEllipse(adjustmentRect)
412 r = QtCore.QRect(innerRect)
413 innerCenter = r.center()
414 innerRect.setLeft(innerCenter.x() + ((r.left() - innerCenter.x()) / 3) * 1)
415 innerRect.setRight(innerCenter.x() + ((r.right() - innerCenter.x()) / 3) * 1)
416 innerRect.setTop(innerCenter.y() + ((r.top() - innerCenter.y()) / 3) * 1)
417 innerRect.setBottom(innerCenter.y() + ((r.bottom() - innerCenter.y()) / 3) * 1)
419 def _paint_center_foreground(self, painter, selectionIndex):
420 centerPos = self._canvas.rect().center()
429 self._filing.center().action(),
430 selectionIndex == PieFiling.SELECTION_CENTER,
435 class QPieDisplay(QtGui.QWidget):
437 def __init__(self, filing, parent = None, flags = QtCore.Qt.Window):
438 QtGui.QWidget.__init__(self, parent, flags)
439 self._filing = filing
440 self._artist = PieArtist(self._filing)
441 self._selectionIndex = PieFiling.SELECTION_NONE
443 def popup(self, pos):
444 self._update_selection(pos)
448 return self._artist.pieSize()
450 @misc_utils.log_exception(_moduleLogger)
451 def showEvent(self, showEvent):
452 mask = self._artist.show(self.palette())
455 QtGui.QWidget.showEvent(self, showEvent)
457 @misc_utils.log_exception(_moduleLogger)
458 def hideEvent(self, hideEvent):
460 self._selectionIndex = PieFiling.SELECTION_NONE
461 QtGui.QWidget.hideEvent(self, hideEvent)
463 @misc_utils.log_exception(_moduleLogger)
464 def paintEvent(self, paintEvent):
465 canvas = self._artist.paint(self._selectionIndex)
467 screen = QtGui.QPainter(self)
468 screen.drawPixmap(QtCore.QPoint(0, 0), canvas)
470 QtGui.QWidget.paintEvent(self, paintEvent)
472 def selectAt(self, index):
473 oldIndex = self._selectionIndex
474 self._selectionIndex = index
479 class QPieButton(QtGui.QWidget):
481 activated = QtCore.pyqtSignal(int)
482 highlighted = QtCore.pyqtSignal(int)
483 canceled = QtCore.pyqtSignal()
484 aboutToShow = QtCore.pyqtSignal()
485 aboutToHide = QtCore.pyqtSignal()
490 def __init__(self, buttonSlice, parent = None):
491 # @bug Artifacts on Maemo 5 due to window 3D effects, find way to disable them for just these?
492 # @bug The pie's are being pushed back on screen on Maemo, leading to coordinate issues
493 QtGui.QWidget.__init__(self, parent)
494 self._cachedCenterPosition = self.rect().center()
496 self._filing = PieFiling()
497 self._display = QPieDisplay(self._filing, None, QtCore.Qt.SplashScreen)
498 self._selectionIndex = PieFiling.SELECTION_NONE
500 self._buttonFiling = PieFiling()
501 self._buttonFiling.set_center(buttonSlice)
502 # @todo Figure out how to make the button auto-fill to content
503 self._buttonFiling.setOuterRadius(self.BUTTON_RADIUS)
504 self._buttonArtist = PieArtist(self._buttonFiling)
505 self._poppedUp = False
507 self._delayPopupTimer = QtCore.QTimer()
508 self._delayPopupTimer.setInterval(self.DELAY)
509 self._delayPopupTimer.setSingleShot(True)
510 self._delayPopupTimer.timeout.connect(self._on_delayed_popup)
511 self._popupLocation = None
513 self._mousePosition = None
514 self.setFocusPolicy(QtCore.Qt.StrongFocus)
516 def insertItem(self, item, index = -1):
517 self._filing.insertItem(item, index)
519 def removeItemAt(self, index):
520 self._filing.removeItemAt(index)
522 def set_center(self, item):
523 self._filing.set_center(item)
525 def set_button(self, item):
531 def itemAt(self, index):
532 return self._filing.itemAt(index)
534 def indexAt(self, point):
535 return self._filing.indexAt(self._cachedCenterPosition, point)
537 def innerRadius(self):
538 return self._filing.innerRadius()
540 def setInnerRadius(self, radius):
541 self._filing.setInnerRadius(radius)
543 def outerRadius(self):
544 return self._filing.outerRadius()
546 def setOuterRadius(self, radius):
547 self._filing.setOuterRadius(radius)
549 def buttonRadius(self):
550 return self._buttonFiling.outerRadius()
552 def setButtonRadius(self, radius):
553 self._buttonFiling.setOuterRadius(radius)
556 return self._buttonArtist.pieSize()
558 @misc_utils.log_exception(_moduleLogger)
559 def mousePressEvent(self, mouseEvent):
560 lastSelection = self._selectionIndex
562 lastMousePos = mouseEvent.pos()
563 self._mousePosition = lastMousePos
564 self._update_selection(self._cachedCenterPosition)
566 self.highlighted.emit(self._selectionIndex)
568 self._display.selectAt(self._selectionIndex)
569 self._popupLocation = mouseEvent.globalPos()
570 self._delayPopupTimer.start()
572 @misc_utils.log_exception(_moduleLogger)
573 def _on_delayed_popup(self):
574 assert self._popupLocation is not None
575 self._popup_child(self._popupLocation)
577 @misc_utils.log_exception(_moduleLogger)
578 def mouseMoveEvent(self, mouseEvent):
579 lastSelection = self._selectionIndex
581 lastMousePos = mouseEvent.pos()
582 if self._mousePosition is None:
584 self._update_selection(lastMousePos)
587 self._update_selection(self._cachedCenterPosition + (lastMousePos - self._mousePosition))
589 if lastSelection != self._selectionIndex:
590 self.highlighted.emit(self._selectionIndex)
591 self._display.selectAt(self._selectionIndex)
593 if self._selectionIndex != PieFiling.SELECTION_CENTER and self._delayPopupTimer.isActive():
594 self._on_delayed_popup()
596 @misc_utils.log_exception(_moduleLogger)
597 def mouseReleaseEvent(self, mouseEvent):
598 self._delayPopupTimer.stop()
599 self._popupLocation = None
601 lastSelection = self._selectionIndex
603 lastMousePos = mouseEvent.pos()
604 if self._mousePosition is None:
606 self._update_selection(lastMousePos)
609 self._update_selection(self._cachedCenterPosition + (lastMousePos - self._mousePosition))
610 self._mousePosition = None
612 self._activate_at(self._selectionIndex)
615 @misc_utils.log_exception(_moduleLogger)
616 def keyPressEvent(self, keyEvent):
617 if keyEvent.key() in [QtCore.Qt.Key_Right, QtCore.Qt.Key_Down, QtCore.Qt.Key_Tab]:
618 self._popup_child(QtGui.QCursor.pos())
619 if self._selectionIndex != len(self._filing) - 1:
620 nextSelection = self._selectionIndex + 1
623 self._select_at(nextSelection)
624 self._display.selectAt(self._selectionIndex)
625 elif keyEvent.key() in [QtCore.Qt.Key_Left, QtCore.Qt.Key_Up, QtCore.Qt.Key_Backtab]:
626 self._popup_child(QtGui.QCursor.pos())
627 if 0 < self._selectionIndex:
628 nextSelection = self._selectionIndex - 1
630 nextSelection = len(self._filing) - 1
631 self._select_at(nextSelection)
632 self._display.selectAt(self._selectionIndex)
633 elif keyEvent.key() in [QtCore.Qt.Key_Space]:
634 self._popup_child(QtGui.QCursor.pos())
635 self._select_at(PieFiling.SELECTION_CENTER)
636 self._display.selectAt(self._selectionIndex)
637 elif keyEvent.key() in [QtCore.Qt.Key_Return, QtCore.Qt.Key_Enter, QtCore.Qt.Key_Space]:
638 self._delayPopupTimer.stop()
639 self._popupLocation = None
640 self._activate_at(self._selectionIndex)
642 elif keyEvent.key() in [QtCore.Qt.Key_Escape, QtCore.Qt.Key_Backspace]:
643 self._delayPopupTimer.stop()
644 self._popupLocation = None
645 self._activate_at(PieFiling.SELECTION_NONE)
648 QtGui.QWidget.keyPressEvent(self, keyEvent)
650 @misc_utils.log_exception(_moduleLogger)
651 def showEvent(self, showEvent):
652 self._buttonArtist.show(self.palette())
653 self._cachedCenterPosition = self.rect().center()
655 QtGui.QWidget.showEvent(self, showEvent)
657 @misc_utils.log_exception(_moduleLogger)
658 def hideEvent(self, hideEvent):
660 self._select_at(PieFiling.SELECTION_NONE)
661 QtGui.QWidget.hideEvent(self, hideEvent)
663 @misc_utils.log_exception(_moduleLogger)
664 def paintEvent(self, paintEvent):
666 canvas = self._buttonArtist.paint(PieFiling.SELECTION_CENTER)
668 canvas = self._buttonArtist.paint(PieFiling.SELECTION_NONE)
670 screen = QtGui.QPainter(self)
671 screen.drawPixmap(QtCore.QPoint(0, 0), canvas)
673 QtGui.QWidget.paintEvent(self, paintEvent)
676 return iter(self._filing)
679 return len(self._filing)
681 def _popup_child(self, position):
682 self._poppedUp = True
683 self.aboutToShow.emit()
685 self._delayPopupTimer.stop()
686 self._popupLocation = None
688 position = position - QtCore.QPoint(self._filing.outerRadius(), self._filing.outerRadius())
689 self._display.move(position)
694 def _hide_child(self):
695 self._poppedUp = False
696 self.aboutToHide.emit()
700 def _select_at(self, index):
701 self._selectionIndex = index
703 def _update_selection(self, lastMousePos):
704 radius = _radius_at(self._cachedCenterPosition, lastMousePos)
705 if radius < self._filing.innerRadius():
706 self._select_at(PieFiling.SELECTION_CENTER)
707 elif radius <= self._filing.outerRadius():
708 self._select_at(self.indexAt(lastMousePos))
710 self._select_at(PieFiling.SELECTION_NONE)
712 def _activate_at(self, index):
713 if index == PieFiling.SELECTION_NONE:
716 elif index == PieFiling.SELECTION_CENTER:
717 child = self._filing.center()
719 child = self.itemAt(index)
721 if child.action().isEnabled():
722 child.action().trigger()
723 self.activated.emit(index)
728 class QPieMenu(QtGui.QWidget):
730 activated = QtCore.pyqtSignal(int)
731 highlighted = QtCore.pyqtSignal(int)
732 canceled = QtCore.pyqtSignal()
733 aboutToShow = QtCore.pyqtSignal()
734 aboutToHide = QtCore.pyqtSignal()
736 def __init__(self, parent = None):
737 QtGui.QWidget.__init__(self, parent)
738 self._cachedCenterPosition = self.rect().center()
740 self._filing = PieFiling()
741 self._artist = PieArtist(self._filing)
742 self._selectionIndex = PieFiling.SELECTION_NONE
744 self._mousePosition = ()
745 self.setFocusPolicy(QtCore.Qt.StrongFocus)
747 def popup(self, pos):
748 self._update_selection(pos)
751 def insertItem(self, item, index = -1):
752 self._filing.insertItem(item, index)
755 def removeItemAt(self, index):
756 self._filing.removeItemAt(index)
759 def set_center(self, item):
760 self._filing.set_center(item)
767 def itemAt(self, index):
768 return self._filing.itemAt(index)
770 def indexAt(self, point):
771 return self._filing.indexAt(self._cachedCenterPosition, point)
773 def innerRadius(self):
774 return self._filing.innerRadius()
776 def setInnerRadius(self, radius):
777 self._filing.setInnerRadius(radius)
780 def outerRadius(self):
781 return self._filing.outerRadius()
783 def setOuterRadius(self, radius):
784 self._filing.setOuterRadius(radius)
788 return self._artist.pieSize()
790 @misc_utils.log_exception(_moduleLogger)
791 def mousePressEvent(self, mouseEvent):
792 lastSelection = self._selectionIndex
794 lastMousePos = mouseEvent.pos()
795 self._update_selection(lastMousePos)
796 self._mousePosition = lastMousePos
798 if lastSelection != self._selectionIndex:
799 self.highlighted.emit(self._selectionIndex)
802 @misc_utils.log_exception(_moduleLogger)
803 def mouseMoveEvent(self, mouseEvent):
804 lastSelection = self._selectionIndex
806 lastMousePos = mouseEvent.pos()
807 self._update_selection(lastMousePos)
809 if lastSelection != self._selectionIndex:
810 self.highlighted.emit(self._selectionIndex)
813 @misc_utils.log_exception(_moduleLogger)
814 def mouseReleaseEvent(self, mouseEvent):
815 lastSelection = self._selectionIndex
817 lastMousePos = mouseEvent.pos()
818 self._update_selection(lastMousePos)
819 self._mousePosition = ()
821 self._activate_at(self._selectionIndex)
824 @misc_utils.log_exception(_moduleLogger)
825 def keyPressEvent(self, keyEvent):
826 if keyEvent.key() in [QtCore.Qt.Key_Right, QtCore.Qt.Key_Down, QtCore.Qt.Key_Tab]:
827 if self._selectionIndex != len(self._filing) - 1:
828 nextSelection = self._selectionIndex + 1
831 self._select_at(nextSelection)
833 elif keyEvent.key() in [QtCore.Qt.Key_Left, QtCore.Qt.Key_Up, QtCore.Qt.Key_Backtab]:
834 if 0 < self._selectionIndex:
835 nextSelection = self._selectionIndex - 1
837 nextSelection = len(self._filing) - 1
838 self._select_at(nextSelection)
840 elif keyEvent.key() in [QtCore.Qt.Key_Return, QtCore.Qt.Key_Enter, QtCore.Qt.Key_Space]:
841 self._activate_at(self._selectionIndex)
842 elif keyEvent.key() in [QtCore.Qt.Key_Escape, QtCore.Qt.Key_Backspace]:
843 self._activate_at(PieFiling.SELECTION_NONE)
845 QtGui.QWidget.keyPressEvent(self, keyEvent)
847 @misc_utils.log_exception(_moduleLogger)
848 def showEvent(self, showEvent):
849 self.aboutToShow.emit()
850 self._cachedCenterPosition = self.rect().center()
852 mask = self._artist.show(self.palette())
855 lastMousePos = self.mapFromGlobal(QtGui.QCursor.pos())
856 self._update_selection(lastMousePos)
858 QtGui.QWidget.showEvent(self, showEvent)
860 @misc_utils.log_exception(_moduleLogger)
861 def hideEvent(self, hideEvent):
863 self._selectionIndex = PieFiling.SELECTION_NONE
864 QtGui.QWidget.hideEvent(self, hideEvent)
866 @misc_utils.log_exception(_moduleLogger)
867 def paintEvent(self, paintEvent):
868 canvas = self._artist.paint(self._selectionIndex)
870 screen = QtGui.QPainter(self)
871 screen.drawPixmap(QtCore.QPoint(0, 0), canvas)
873 QtGui.QWidget.paintEvent(self, paintEvent)
876 return iter(self._filing)
879 return len(self._filing)
881 def _select_at(self, index):
882 self._selectionIndex = index
884 def _update_selection(self, lastMousePos):
885 radius = _radius_at(self._cachedCenterPosition, lastMousePos)
886 if radius < self._filing.innerRadius():
887 self._selectionIndex = PieFiling.SELECTION_CENTER
888 elif radius <= self._filing.outerRadius():
889 self._select_at(self.indexAt(lastMousePos))
891 self._selectionIndex = PieFiling.SELECTION_NONE
893 def _activate_at(self, index):
894 if index == PieFiling.SELECTION_NONE:
896 self.aboutToHide.emit()
899 elif index == PieFiling.SELECTION_CENTER:
900 child = self._filing.center()
902 child = self.itemAt(index)
904 if child.isEnabled():
905 child.action().trigger()
906 self.activated.emit(index)
909 self.aboutToHide.emit()
914 PieFiling.NULL_CENTER.setEnabled(False)
921 def _on_about_to_hide(app):
925 if __name__ == "__main__":
926 app = QtGui.QApplication([])
934 singleAction = QtGui.QAction(None)
935 singleAction.setText("Boo")
936 singleItem = QActionPieItem(singleAction)
938 spie.insertItem(singleItem)
942 oneAction = QtGui.QAction(None)
943 oneAction.setText("Chew")
944 oneItem = QActionPieItem(oneAction)
945 twoAction = QtGui.QAction(None)
946 twoAction.setText("Foo")
947 twoItem = QActionPieItem(twoAction)
948 iconTextAction = QtGui.QAction(None)
949 iconTextAction.setText("Icon")
950 iconTextAction.setIcon(QtGui.QIcon.fromTheme("gtk-close"))
951 iconTextItem = QActionPieItem(iconTextAction)
953 mpie.insertItem(oneItem)
954 mpie.insertItem(twoItem)
955 mpie.insertItem(oneItem)
956 mpie.insertItem(iconTextItem)
960 oneAction = QtGui.QAction(None)
961 oneAction.setText("Chew")
962 oneAction.triggered.connect(lambda: _print("Chew"))
963 oneItem = QActionPieItem(oneAction)
964 twoAction = QtGui.QAction(None)
965 twoAction.setText("Foo")
966 twoAction.triggered.connect(lambda: _print("Foo"))
967 twoItem = QActionPieItem(twoAction)
968 iconAction = QtGui.QAction(None)
969 iconAction.setIcon(QtGui.QIcon.fromTheme("gtk-open"))
970 iconAction.triggered.connect(lambda: _print("Icon"))
971 iconItem = QActionPieItem(iconAction)
972 iconTextAction = QtGui.QAction(None)
973 iconTextAction.setText("Icon")
974 iconTextAction.setIcon(QtGui.QIcon.fromTheme("gtk-close"))
975 iconTextAction.triggered.connect(lambda: _print("Icon and text"))
976 iconTextItem = QActionPieItem(iconTextAction)
978 mpie.set_center(iconItem)
979 mpie.insertItem(oneItem)
980 mpie.insertItem(twoItem)
981 mpie.insertItem(oneItem)
982 mpie.insertItem(iconTextItem)
984 mpie.aboutToHide.connect(lambda: _on_about_to_hide(app))
985 mpie.canceled.connect(lambda: _print("Canceled"))
988 oneAction = QtGui.QAction(None)
989 oneAction.setText("Chew")
990 oneAction.triggered.connect(lambda: _print("Chew"))
991 oneItem = QActionPieItem(oneAction)
992 twoAction = QtGui.QAction(None)
993 twoAction.setText("Foo")
994 twoAction.triggered.connect(lambda: _print("Foo"))
995 twoItem = QActionPieItem(twoAction)
996 iconAction = QtGui.QAction(None)
997 iconAction.setIcon(QtGui.QIcon.fromTheme("gtk-open"))
998 iconAction.triggered.connect(lambda: _print("Icon"))
999 iconItem = QActionPieItem(iconAction)
1000 iconTextAction = QtGui.QAction(None)
1001 iconTextAction.setText("Icon")
1002 iconTextAction.setIcon(QtGui.QIcon.fromTheme("gtk-close"))
1003 iconTextAction.triggered.connect(lambda: _print("Icon and text"))
1004 iconTextItem = QActionPieItem(iconTextAction)
1005 pieFiling = PieFiling()
1006 pieFiling.set_center(iconItem)
1007 pieFiling.insertItem(oneItem)
1008 pieFiling.insertItem(twoItem)
1009 pieFiling.insertItem(oneItem)
1010 pieFiling.insertItem(iconTextItem)
1011 mpie = QPieDisplay(pieFiling)
1015 oneAction = QtGui.QAction(None)
1016 oneAction.setText("Chew")
1017 oneAction.triggered.connect(lambda: _print("Chew"))
1018 oneItem = QActionPieItem(oneAction)
1019 twoAction = QtGui.QAction(None)
1020 twoAction.setText("Foo")
1021 twoAction.triggered.connect(lambda: _print("Foo"))
1022 twoItem = QActionPieItem(twoAction)
1023 iconAction = QtGui.QAction(None)
1024 iconAction.setIcon(QtGui.QIcon.fromTheme("gtk-open"))
1025 iconAction.triggered.connect(lambda: _print("Icon"))
1026 iconItem = QActionPieItem(iconAction)
1027 iconTextAction = QtGui.QAction(None)
1028 iconTextAction.setText("Icon")
1029 iconTextAction.setIcon(QtGui.QIcon.fromTheme("gtk-close"))
1030 iconTextAction.triggered.connect(lambda: _print("Icon and text"))
1031 iconTextItem = QActionPieItem(iconTextAction)
1032 mpie = QPieButton(iconItem)
1033 mpie.set_center(iconItem)
1034 mpie.insertItem(oneItem)
1035 mpie.insertItem(twoItem)
1036 mpie.insertItem(oneItem)
1037 mpie.insertItem(iconTextItem)
1039 mpie.aboutToHide.connect(lambda: _on_about_to_hide(app))
1040 mpie.canceled.connect(lambda: _print("Canceled"))