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 self._filing = filing
200 self._cachedOuterRadius = self._filing.outerRadius()
201 self._cachedInnerRadius = self._filing.innerRadius()
202 canvasSize = self._cachedOuterRadius * 2 + 1
203 self._canvas = QtGui.QPixmap(canvasSize, canvasSize)
208 diameter = self._filing.outerRadius() * 2 + 1
209 return QtCore.QSize(diameter, diameter)
211 def centerSize(self):
212 painter = QtGui.QPainter(self._canvas)
213 text = self._filing.center().action().text()
214 fontMetrics = painter.fontMetrics()
216 textBoundingRect = fontMetrics.boundingRect(text)
218 textBoundingRect = QtCore.QRect()
219 textWidth = textBoundingRect.width()
220 textHeight = textBoundingRect.height()
223 textWidth + self.ICON_SIZE_DEFAULT,
224 max(textHeight, self.ICON_SIZE_DEFAULT),
227 def show(self, palette):
228 self.palette = palette
231 self._cachedOuterRadius != self._filing.outerRadius() or
232 self._cachedInnerRadius != self._filing.innerRadius()
234 self._cachedOuterRadius = self._filing.outerRadius()
235 self._cachedInnerRadius = self._filing.innerRadius()
236 self._canvas = self._canvas.scaled(self.pieSize())
238 if self._mask is None:
239 self._mask = QtGui.QBitmap(self._canvas.size())
240 self._mask.fill(QtCore.Qt.color0)
241 self._generate_mask(self._mask)
242 self._canvas.setMask(self._mask)
248 def paint(self, selectionIndex):
249 painter = QtGui.QPainter(self._canvas)
250 painter.setRenderHint(QtGui.QPainter.Antialiasing, True)
252 adjustmentRect = self._canvas.rect().adjusted(0, 0, -1, -1)
254 numChildren = len(self._filing)
256 if selectionIndex == PieFiling.SELECTION_CENTER and self._filing.center().isEnabled():
257 painter.setBrush(self.palette.highlight())
259 painter.setBrush(self.palette.background())
260 painter.setPen(self.palette.mid().color())
262 painter.drawRect(self._canvas.rect())
263 self._paint_center_foreground(painter, selectionIndex)
265 elif numChildren == 1:
266 if selectionIndex == 0 and self._filing[0].isEnabled():
267 painter.setBrush(self.palette.highlight())
269 painter.setBrush(self.palette.background())
271 painter.fillRect(self._canvas.rect(), painter.brush())
273 for i in xrange(len(self._filing)):
274 self._paint_slice_background(painter, adjustmentRect, i, selectionIndex)
276 self._paint_center_background(painter, adjustmentRect, selectionIndex)
277 self._paint_center_foreground(painter, selectionIndex)
279 for i in xrange(len(self._filing)):
280 self._paint_slice_foreground(painter, i, selectionIndex)
284 def _generate_mask(self, mask):
286 Specifies on the mask the shape of the pie menu
288 painter = QtGui.QPainter(mask)
289 painter.setPen(QtCore.Qt.color1)
290 painter.setBrush(QtCore.Qt.color1)
291 painter.drawEllipse(mask.rect().adjusted(0, 0, -1, -1))
293 def _paint_slice_background(self, painter, adjustmentRect, i, selectionIndex):
294 if i == selectionIndex and self._filing[i].isEnabled():
295 painter.setBrush(self.palette.highlight())
297 painter.setBrush(self.palette.background())
298 painter.setPen(self.palette.mid().color())
300 a = self._filing._index_to_angle(i, True)
301 b = self._filing._index_to_angle(i + 1, True)
308 startAngleInDeg = (a * 360 * 16) / _TWOPI
309 sizeInDeg = (size * 360 * 16) / _TWOPI
310 painter.drawPie(adjustmentRect, int(startAngleInDeg), int(sizeInDeg))
312 def _paint_slice_foreground(self, painter, i, selectionIndex):
313 child = self._filing[i]
315 a = self._filing._index_to_angle(i, True)
316 b = self._filing._index_to_angle(i + 1, True)
319 middleAngle = (a + b) / 2
320 averageRadius = (self._cachedInnerRadius + self._cachedOuterRadius) / 2
322 sliceX = averageRadius * math.cos(middleAngle)
323 sliceY = - averageRadius * math.sin(middleAngle)
325 piePos = self._canvas.rect().center()
329 painter, child.action(), i == selectionIndex, pieX+sliceX, pieY+sliceY
332 def _paint_label(self, painter, action, isSelected, x, y):
334 fontMetrics = painter.fontMetrics()
336 textBoundingRect = fontMetrics.boundingRect(text)
338 textBoundingRect = QtCore.QRect()
339 textWidth = textBoundingRect.width()
340 textHeight = textBoundingRect.height()
342 icon = action.icon().pixmap(
343 QtCore.QSize(self.ICON_SIZE_DEFAULT, self.ICON_SIZE_DEFAULT),
347 iconWidth = icon.width()
348 iconHeight = icon.width()
349 averageWidth = (iconWidth + textWidth)/2
350 if not icon.isNull():
351 iconRect = QtCore.QRect(
358 painter.drawPixmap(iconRect, icon)
362 if action.isEnabled():
363 pen = self.palette.highlightedText()
364 brush = self.palette.highlight()
366 pen = self.palette.mid()
367 brush = self.palette.background()
369 if action.isEnabled():
370 pen = self.palette.text()
372 pen = self.palette.mid()
373 brush = self.palette.background()
375 leftX = x - averageWidth + iconWidth
376 topY = y + textHeight/2
377 painter.setPen(pen.color())
378 painter.setBrush(brush)
379 painter.drawText(leftX, topY, text)
381 def _paint_center_background(self, painter, adjustmentRect, selectionIndex):
382 dark = self.palette.dark().color()
383 light = self.palette.light().color()
384 if selectionIndex == PieFiling.SELECTION_CENTER and self._filing.center().isEnabled():
385 background = self.palette.highlight().color()
387 background = self.palette.background().color()
389 innerRadius = self._cachedInnerRadius
390 adjustmentCenterPos = adjustmentRect.center()
391 innerRect = QtCore.QRect(
392 adjustmentCenterPos.x() - innerRadius,
393 adjustmentCenterPos.y() - innerRadius,
398 painter.setPen(QtCore.Qt.NoPen)
399 painter.setBrush(background)
400 painter.drawPie(innerRect, 0, 360 * 16)
402 painter.setPen(QtGui.QPen(dark, 1))
403 painter.setBrush(QtCore.Qt.NoBrush)
404 painter.drawEllipse(innerRect)
406 painter.setPen(QtGui.QPen(dark, 1))
407 painter.setBrush(QtCore.Qt.NoBrush)
408 painter.drawEllipse(adjustmentRect)
410 r = QtCore.QRect(innerRect)
411 innerCenter = r.center()
412 innerRect.setLeft(innerCenter.x() + ((r.left() - innerCenter.x()) / 3) * 1)
413 innerRect.setRight(innerCenter.x() + ((r.right() - innerCenter.x()) / 3) * 1)
414 innerRect.setTop(innerCenter.y() + ((r.top() - innerCenter.y()) / 3) * 1)
415 innerRect.setBottom(innerCenter.y() + ((r.bottom() - innerCenter.y()) / 3) * 1)
417 def _paint_center_foreground(self, painter, selectionIndex):
418 centerPos = self._canvas.rect().center()
427 self._filing.center().action(),
428 selectionIndex == PieFiling.SELECTION_CENTER,
433 class QPieDisplay(QtGui.QWidget):
435 def __init__(self, filing, parent = None, flags = QtCore.Qt.Window):
436 QtGui.QWidget.__init__(self, parent, flags)
437 self._filing = filing
438 self._artist = PieArtist(self._filing)
439 self._selectionIndex = PieFiling.SELECTION_NONE
441 def popup(self, pos):
442 self._update_selection(pos)
446 return self._artist.pieSize()
448 @misc_utils.log_exception(_moduleLogger)
449 def showEvent(self, showEvent):
450 mask = self._artist.show(self.palette())
453 QtGui.QWidget.showEvent(self, showEvent)
455 @misc_utils.log_exception(_moduleLogger)
456 def hideEvent(self, hideEvent):
458 self._selectionIndex = PieFiling.SELECTION_NONE
459 QtGui.QWidget.hideEvent(self, hideEvent)
461 @misc_utils.log_exception(_moduleLogger)
462 def paintEvent(self, paintEvent):
463 canvas = self._artist.paint(self._selectionIndex)
465 screen = QtGui.QPainter(self)
466 screen.drawPixmap(QtCore.QPoint(0, 0), canvas)
468 QtGui.QWidget.paintEvent(self, paintEvent)
470 def selectAt(self, index):
471 oldIndex = self._selectionIndex
472 self._selectionIndex = index
477 class QPieButton(QtGui.QWidget):
479 activated = QtCore.pyqtSignal(int)
480 highlighted = QtCore.pyqtSignal(int)
481 canceled = QtCore.pyqtSignal()
482 aboutToShow = QtCore.pyqtSignal()
483 aboutToHide = QtCore.pyqtSignal()
488 def __init__(self, buttonSlice, parent = None):
489 QtGui.QWidget.__init__(self, parent)
490 self._cachedCenterPosition = self.rect().center()
492 self._filing = PieFiling()
493 self._display = QPieDisplay(self._filing, None, QtCore.Qt.SplashScreen)
494 self._selectionIndex = PieFiling.SELECTION_NONE
496 self._buttonFiling = PieFiling()
497 self._buttonFiling.set_center(buttonSlice)
498 # @todo Figure out how to make the button auto-fill to content
499 self._buttonFiling.setOuterRadius(self.BUTTON_RADIUS)
500 self._buttonArtist = PieArtist(self._buttonFiling)
501 self._poppedUp = False
503 self._delayPopupTimer = QtCore.QTimer()
504 self._delayPopupTimer.setInterval(self.DELAY)
505 self._delayPopupTimer.setSingleShot(True)
506 self._delayPopupTimer.timeout.connect(self._on_delayed_popup)
507 self._popupLocation = None
509 self._mousePosition = None
510 self.setFocusPolicy(QtCore.Qt.StrongFocus)
512 def insertItem(self, item, index = -1):
513 self._filing.insertItem(item, index)
515 def removeItemAt(self, index):
516 self._filing.removeItemAt(index)
518 def set_center(self, item):
519 self._filing.set_center(item)
521 def set_button(self, item):
527 def itemAt(self, index):
528 return self._filing.itemAt(index)
530 def indexAt(self, point):
531 return self._filing.indexAt(self._cachedCenterPosition, point)
533 def innerRadius(self):
534 return self._filing.innerRadius()
536 def setInnerRadius(self, radius):
537 self._filing.setInnerRadius(radius)
539 def outerRadius(self):
540 return self._filing.outerRadius()
542 def setOuterRadius(self, radius):
543 self._filing.setOuterRadius(radius)
545 def buttonRadius(self):
546 return self._buttonFiling.outerRadius()
548 def setButtonRadius(self, radius):
549 self._buttonFiling.setOuterRadius(radius)
552 return self._buttonArtist.pieSize()
554 @misc_utils.log_exception(_moduleLogger)
555 def mousePressEvent(self, mouseEvent):
556 lastSelection = self._selectionIndex
558 lastMousePos = mouseEvent.pos()
559 self._mousePosition = lastMousePos
560 self._update_selection(self._cachedCenterPosition)
562 self.highlighted.emit(self._selectionIndex)
564 self._display.selectAt(self._selectionIndex)
565 self._popupLocation = mouseEvent.globalPos()
566 self._delayPopupTimer.start()
568 @misc_utils.log_exception(_moduleLogger)
569 def _on_delayed_popup(self):
570 assert self._popupLocation is not None
571 self._popup_child(self._popupLocation)
573 @misc_utils.log_exception(_moduleLogger)
574 def mouseMoveEvent(self, mouseEvent):
575 lastSelection = self._selectionIndex
577 lastMousePos = mouseEvent.pos()
578 if self._mousePosition is None:
580 self._update_selection(lastMousePos)
583 self._update_selection(self._cachedCenterPosition + (lastMousePos - self._mousePosition))
585 if lastSelection != self._selectionIndex:
586 self.highlighted.emit(self._selectionIndex)
587 self._display.selectAt(self._selectionIndex)
589 if self._selectionIndex != PieFiling.SELECTION_CENTER and self._delayPopupTimer.isActive():
590 self._on_delayed_popup()
592 @misc_utils.log_exception(_moduleLogger)
593 def mouseReleaseEvent(self, mouseEvent):
594 self._delayPopupTimer.stop()
595 self._popupLocation = None
597 lastSelection = self._selectionIndex
599 lastMousePos = mouseEvent.pos()
600 if self._mousePosition is None:
602 self._update_selection(lastMousePos)
605 self._update_selection(self._cachedCenterPosition + (lastMousePos - self._mousePosition))
606 self._mousePosition = None
608 self._activate_at(self._selectionIndex)
611 @misc_utils.log_exception(_moduleLogger)
612 def keyPressEvent(self, keyEvent):
613 if keyEvent.key() in [QtCore.Qt.Key_Right, QtCore.Qt.Key_Down, QtCore.Qt.Key_Tab]:
614 self._popup_child(QtGui.QCursor.pos())
615 if self._selectionIndex != len(self._filing) - 1:
616 nextSelection = self._selectionIndex + 1
619 self._select_at(nextSelection)
620 self._display.selectAt(self._selectionIndex)
621 elif keyEvent.key() in [QtCore.Qt.Key_Left, QtCore.Qt.Key_Up, QtCore.Qt.Key_Backtab]:
622 self._popup_child(QtGui.QCursor.pos())
623 if 0 < self._selectionIndex:
624 nextSelection = self._selectionIndex - 1
626 nextSelection = len(self._filing) - 1
627 self._select_at(nextSelection)
628 self._display.selectAt(self._selectionIndex)
629 elif keyEvent.key() in [QtCore.Qt.Key_Space]:
630 self._popup_child(QtGui.QCursor.pos())
631 self._select_at(PieFiling.SELECTION_CENTER)
632 self._display.selectAt(self._selectionIndex)
633 elif keyEvent.key() in [QtCore.Qt.Key_Return, QtCore.Qt.Key_Enter, QtCore.Qt.Key_Space]:
634 self._delayPopupTimer.stop()
635 self._popupLocation = None
636 self._activate_at(self._selectionIndex)
638 elif keyEvent.key() in [QtCore.Qt.Key_Escape, QtCore.Qt.Key_Backspace]:
639 self._delayPopupTimer.stop()
640 self._popupLocation = None
641 self._activate_at(PieFiling.SELECTION_NONE)
644 QtGui.QWidget.keyPressEvent(self, keyEvent)
646 @misc_utils.log_exception(_moduleLogger)
647 def showEvent(self, showEvent):
648 self._buttonArtist.show(self.palette())
649 self._cachedCenterPosition = self.rect().center()
651 QtGui.QWidget.showEvent(self, showEvent)
653 @misc_utils.log_exception(_moduleLogger)
654 def hideEvent(self, hideEvent):
656 self._select_at(PieFiling.SELECTION_NONE)
657 QtGui.QWidget.hideEvent(self, hideEvent)
659 @misc_utils.log_exception(_moduleLogger)
660 def paintEvent(self, paintEvent):
662 canvas = self._buttonArtist.paint(PieFiling.SELECTION_CENTER)
664 canvas = self._buttonArtist.paint(PieFiling.SELECTION_NONE)
666 screen = QtGui.QPainter(self)
667 screen.drawPixmap(QtCore.QPoint(0, 0), canvas)
669 QtGui.QWidget.paintEvent(self, paintEvent)
672 return iter(self._filing)
675 return len(self._filing)
677 def _popup_child(self, position):
678 self._poppedUp = True
679 self.aboutToShow.emit()
681 self._delayPopupTimer.stop()
682 self._popupLocation = None
684 position = position - QtCore.QPoint(self._filing.outerRadius(), self._filing.outerRadius())
685 self._display.move(position)
690 def _hide_child(self):
691 self._poppedUp = False
692 self.aboutToHide.emit()
696 def _select_at(self, index):
697 self._selectionIndex = index
699 def _update_selection(self, lastMousePos):
700 radius = _radius_at(self._cachedCenterPosition, lastMousePos)
701 if radius < self._filing.innerRadius():
702 self._select_at(PieFiling.SELECTION_CENTER)
703 elif radius <= self._filing.outerRadius():
704 self._select_at(self.indexAt(lastMousePos))
706 self._select_at(PieFiling.SELECTION_NONE)
708 def _activate_at(self, index):
709 if index == PieFiling.SELECTION_NONE:
712 elif index == PieFiling.SELECTION_CENTER:
713 child = self._filing.center()
715 child = self.itemAt(index)
717 if child.action().isEnabled():
718 child.action().trigger()
719 self.activated.emit(index)
724 class QPieMenu(QtGui.QWidget):
726 activated = QtCore.pyqtSignal(int)
727 highlighted = QtCore.pyqtSignal(int)
728 canceled = QtCore.pyqtSignal()
729 aboutToShow = QtCore.pyqtSignal()
730 aboutToHide = QtCore.pyqtSignal()
732 def __init__(self, parent = None):
733 QtGui.QWidget.__init__(self, parent)
734 self._cachedCenterPosition = self.rect().center()
736 self._filing = PieFiling()
737 self._artist = PieArtist(self._filing)
738 self._selectionIndex = PieFiling.SELECTION_NONE
740 self._mousePosition = ()
741 self.setFocusPolicy(QtCore.Qt.StrongFocus)
743 def popup(self, pos):
744 self._update_selection(pos)
747 def insertItem(self, item, index = -1):
748 self._filing.insertItem(item, index)
751 def removeItemAt(self, index):
752 self._filing.removeItemAt(index)
755 def set_center(self, item):
756 self._filing.set_center(item)
763 def itemAt(self, index):
764 return self._filing.itemAt(index)
766 def indexAt(self, point):
767 return self._filing.indexAt(self._cachedCenterPosition, point)
769 def innerRadius(self):
770 return self._filing.innerRadius()
772 def setInnerRadius(self, radius):
773 self._filing.setInnerRadius(radius)
776 def outerRadius(self):
777 return self._filing.outerRadius()
779 def setOuterRadius(self, radius):
780 self._filing.setOuterRadius(radius)
784 return self._artist.pieSize()
786 @misc_utils.log_exception(_moduleLogger)
787 def mousePressEvent(self, mouseEvent):
788 lastSelection = self._selectionIndex
790 lastMousePos = mouseEvent.pos()
791 self._update_selection(lastMousePos)
792 self._mousePosition = lastMousePos
794 if lastSelection != self._selectionIndex:
795 self.highlighted.emit(self._selectionIndex)
798 @misc_utils.log_exception(_moduleLogger)
799 def mouseMoveEvent(self, mouseEvent):
800 lastSelection = self._selectionIndex
802 lastMousePos = mouseEvent.pos()
803 self._update_selection(lastMousePos)
805 if lastSelection != self._selectionIndex:
806 self.highlighted.emit(self._selectionIndex)
809 @misc_utils.log_exception(_moduleLogger)
810 def mouseReleaseEvent(self, mouseEvent):
811 lastSelection = self._selectionIndex
813 lastMousePos = mouseEvent.pos()
814 self._update_selection(lastMousePos)
815 self._mousePosition = ()
817 self._activate_at(self._selectionIndex)
820 @misc_utils.log_exception(_moduleLogger)
821 def keyPressEvent(self, keyEvent):
822 if keyEvent.key() in [QtCore.Qt.Key_Right, QtCore.Qt.Key_Down, QtCore.Qt.Key_Tab]:
823 if self._selectionIndex != len(self._filing) - 1:
824 nextSelection = self._selectionIndex + 1
827 self._select_at(nextSelection)
829 elif keyEvent.key() in [QtCore.Qt.Key_Left, QtCore.Qt.Key_Up, QtCore.Qt.Key_Backtab]:
830 if 0 < self._selectionIndex:
831 nextSelection = self._selectionIndex - 1
833 nextSelection = len(self._filing) - 1
834 self._select_at(nextSelection)
836 elif keyEvent.key() in [QtCore.Qt.Key_Return, QtCore.Qt.Key_Enter, QtCore.Qt.Key_Space]:
837 self._activate_at(self._selectionIndex)
838 elif keyEvent.key() in [QtCore.Qt.Key_Escape, QtCore.Qt.Key_Backspace]:
839 self._activate_at(PieFiling.SELECTION_NONE)
841 QtGui.QWidget.keyPressEvent(self, keyEvent)
843 @misc_utils.log_exception(_moduleLogger)
844 def showEvent(self, showEvent):
845 self.aboutToShow.emit()
846 self._cachedCenterPosition = self.rect().center()
848 mask = self._artist.show(self.palette())
851 lastMousePos = self.mapFromGlobal(QtGui.QCursor.pos())
852 self._update_selection(lastMousePos)
854 QtGui.QWidget.showEvent(self, showEvent)
856 @misc_utils.log_exception(_moduleLogger)
857 def hideEvent(self, hideEvent):
859 self._selectionIndex = PieFiling.SELECTION_NONE
860 QtGui.QWidget.hideEvent(self, hideEvent)
862 @misc_utils.log_exception(_moduleLogger)
863 def paintEvent(self, paintEvent):
864 canvas = self._artist.paint(self._selectionIndex)
866 screen = QtGui.QPainter(self)
867 screen.drawPixmap(QtCore.QPoint(0, 0), canvas)
869 QtGui.QWidget.paintEvent(self, paintEvent)
872 return iter(self._filing)
875 return len(self._filing)
877 def _select_at(self, index):
878 self._selectionIndex = index
880 def _update_selection(self, lastMousePos):
881 radius = _radius_at(self._cachedCenterPosition, lastMousePos)
882 if radius < self._filing.innerRadius():
883 self._selectionIndex = PieFiling.SELECTION_CENTER
884 elif radius <= self._filing.outerRadius():
885 self._select_at(self.indexAt(lastMousePos))
887 self._selectionIndex = PieFiling.SELECTION_NONE
889 def _activate_at(self, index):
890 if index == PieFiling.SELECTION_NONE:
892 self.aboutToHide.emit()
895 elif index == PieFiling.SELECTION_CENTER:
896 child = self._filing.center()
898 child = self.itemAt(index)
900 if child.isEnabled():
901 child.action().trigger()
902 self.activated.emit(index)
905 self.aboutToHide.emit()
910 PieFiling.NULL_CENTER.setEnabled(False)
917 def _on_about_to_hide(app):
921 if __name__ == "__main__":
922 app = QtGui.QApplication([])
930 singleAction = QtGui.QAction(None)
931 singleAction.setText("Boo")
932 singleItem = QActionPieItem(singleAction)
934 spie.insertItem(singleItem)
938 oneAction = QtGui.QAction(None)
939 oneAction.setText("Chew")
940 oneItem = QActionPieItem(oneAction)
941 twoAction = QtGui.QAction(None)
942 twoAction.setText("Foo")
943 twoItem = QActionPieItem(twoAction)
944 iconTextAction = QtGui.QAction(None)
945 iconTextAction.setText("Icon")
946 iconTextAction.setIcon(QtGui.QIcon.fromTheme("gtk-close"))
947 iconTextItem = QActionPieItem(iconTextAction)
949 mpie.insertItem(oneItem)
950 mpie.insertItem(twoItem)
951 mpie.insertItem(oneItem)
952 mpie.insertItem(iconTextItem)
956 oneAction = QtGui.QAction(None)
957 oneAction.setText("Chew")
958 oneAction.triggered.connect(lambda: _print("Chew"))
959 oneItem = QActionPieItem(oneAction)
960 twoAction = QtGui.QAction(None)
961 twoAction.setText("Foo")
962 twoAction.triggered.connect(lambda: _print("Foo"))
963 twoItem = QActionPieItem(twoAction)
964 iconAction = QtGui.QAction(None)
965 iconAction.setIcon(QtGui.QIcon.fromTheme("gtk-open"))
966 iconAction.triggered.connect(lambda: _print("Icon"))
967 iconItem = QActionPieItem(iconAction)
968 iconTextAction = QtGui.QAction(None)
969 iconTextAction.setText("Icon")
970 iconTextAction.setIcon(QtGui.QIcon.fromTheme("gtk-close"))
971 iconTextAction.triggered.connect(lambda: _print("Icon and text"))
972 iconTextItem = QActionPieItem(iconTextAction)
974 mpie.set_center(iconItem)
975 mpie.insertItem(oneItem)
976 mpie.insertItem(twoItem)
977 mpie.insertItem(oneItem)
978 mpie.insertItem(iconTextItem)
980 mpie.aboutToHide.connect(lambda: _on_about_to_hide(app))
981 mpie.canceled.connect(lambda: _print("Canceled"))
984 oneAction = QtGui.QAction(None)
985 oneAction.setText("Chew")
986 oneAction.triggered.connect(lambda: _print("Chew"))
987 oneItem = QActionPieItem(oneAction)
988 twoAction = QtGui.QAction(None)
989 twoAction.setText("Foo")
990 twoAction.triggered.connect(lambda: _print("Foo"))
991 twoItem = QActionPieItem(twoAction)
992 iconAction = QtGui.QAction(None)
993 iconAction.setIcon(QtGui.QIcon.fromTheme("gtk-open"))
994 iconAction.triggered.connect(lambda: _print("Icon"))
995 iconItem = QActionPieItem(iconAction)
996 iconTextAction = QtGui.QAction(None)
997 iconTextAction.setText("Icon")
998 iconTextAction.setIcon(QtGui.QIcon.fromTheme("gtk-close"))
999 iconTextAction.triggered.connect(lambda: _print("Icon and text"))
1000 iconTextItem = QActionPieItem(iconTextAction)
1001 pieFiling = PieFiling()
1002 pieFiling.set_center(iconItem)
1003 pieFiling.insertItem(oneItem)
1004 pieFiling.insertItem(twoItem)
1005 pieFiling.insertItem(oneItem)
1006 pieFiling.insertItem(iconTextItem)
1007 mpie = QPieDisplay(pieFiling)
1011 oneAction = QtGui.QAction(None)
1012 oneAction.setText("Chew")
1013 oneAction.triggered.connect(lambda: _print("Chew"))
1014 oneItem = QActionPieItem(oneAction)
1015 twoAction = QtGui.QAction(None)
1016 twoAction.setText("Foo")
1017 twoAction.triggered.connect(lambda: _print("Foo"))
1018 twoItem = QActionPieItem(twoAction)
1019 iconAction = QtGui.QAction(None)
1020 iconAction.setIcon(QtGui.QIcon.fromTheme("gtk-open"))
1021 iconAction.triggered.connect(lambda: _print("Icon"))
1022 iconItem = QActionPieItem(iconAction)
1023 iconTextAction = QtGui.QAction(None)
1024 iconTextAction.setText("Icon")
1025 iconTextAction.setIcon(QtGui.QIcon.fromTheme("gtk-close"))
1026 iconTextAction.triggered.connect(lambda: _print("Icon and text"))
1027 iconTextItem = QActionPieItem(iconTextAction)
1028 mpie = QPieButton(iconItem)
1029 mpie.set_center(iconItem)
1030 mpie.insertItem(oneItem)
1031 mpie.insertItem(twoItem)
1032 mpie.insertItem(oneItem)
1033 mpie.insertItem(iconTextItem)
1035 mpie.aboutToHide.connect(lambda: _on_about_to_hide(app))
1036 mpie.canceled.connect(lambda: _print("Canceled"))