source: orange/Orange/OrangeCanvas/orngCanvasItems.py @ 10827:8527a7511c4f

Revision 10827:8527a7511c4f, 29.0 KB checked in by mitar, 2 years ago (diff)

Support for widgets loading from modules, registered through entry point.

Line 
1# Author: Gregor Leban (gregor.leban@fri.uni-lj.si)
2# Description:
3#    two main objects that are shown in the canvas; Line and Widget
4#
5from PyQt4.QtCore import *
6from PyQt4.QtGui import *
7import os, sys, math
8ERROR = 0
9WARNING = 1
10
11def getDropShadow(item):
12    if hasattr(item, "graphicsEffect"):
13        return item.graphicsEffect()
14    else:
15        return None
16   
17def setDropShadow(self, offset=QPointF(0.3, 0.5), blur_radius=5):
18    if qVersion() >= "4.6" and self.canvasDlg.settings["enableCanvasDropShadows"]:
19        effect = QGraphicsDropShadowEffect(self.scene())
20        effect.setOffset(offset)
21        effect.setBlurRadius(blur_radius)
22        self.setGraphicsEffect(effect)
23   
24class TempCanvasLine(QGraphicsPathItem):
25    def __init__(self, canvasDlg, canvas):
26        QGraphicsLineItem.__init__(self, None, canvas)
27        self.setZValue(-10)
28        self.canvasDlg = canvasDlg
29        self.startWidget = None
30        self.endWidget = None
31        self.widget = None
32
33        self.setPen(QPen(QColor(180, 180, 180), 3, Qt.SolidLine))
34       
35        self.setDropShadow(offset=QPointF(0.0, 0.0))
36   
37    setDropShadow = setDropShadow
38    getDropShadow = getDropShadow
39   
40    def setStartWidget(self, widget):
41        self.startWidget = widget
42        pos = widget.getRightEdgePoint()
43        endX, endY = startX, startY = pos.x(), pos.y()
44#        self.setLine(pos.x(), pos.y(), pos.x(), pos.y())
45       
46    def setEndWidget(self, widget):
47        self.endWidget = widget
48        pos = widget.getLeftEdgePoint()
49        endX, endY = startX, startY = pos.x(), pos.y()
50#        self.setLine(pos.x(), pos.y(), pos.x(), pos.y())
51       
52    def updateLinePos(self, newPos):
53        if self.startWidget == None and self.endWidget == None:
54            return
55       
56        if self.startWidget != None:
57            func = "getDistToLeftEdgePoint"
58        else:
59            func = "getDistToRightEdgePoint"
60       
61        schema = self.canvasDlg.schema
62        view = schema.canvasView
63       
64        self.widget = None
65        widgets = view.getItemsAtPos(newPos, CanvasWidget)
66        if widgets:
67            self.widget = widgets[0]
68        else:
69            dists = [(getattr(w, func)(newPos), w) for w in schema.widgets]
70            dists.sort()
71            if dists and dists[0][0] < 20:
72                self.widget = dists[0][1]
73       
74        if self.startWidget:
75            pos = self.startWidget.getRightEdgePoint()
76        else:
77            pos = self.endWidget.getLeftEdgePoint()
78
79        if self.widget not in [self.startWidget, self.endWidget]: 
80            if self.startWidget == None and self.widget.widgetInfo.outputs:
81                newPos = self.widget.getRightEdgePoint()
82            elif self.endWidget == None and self.widget.widgetInfo.inputs:
83                newPos = self.widget.getLeftEdgePoint()
84       
85        path = QPainterPath(pos)
86        if self.startWidget != None:
87            path.cubicTo(pos.x()+60, pos.y(), newPos.x()-60, newPos.y(), newPos.x(),newPos.y())
88        else:
89            path.cubicTo(pos.x()-60, pos.y(), newPos.x()+60, newPos.y(), newPos.x(),newPos.y())
90        self.setPath(path)
91#        self.setLine(pos.x(), pos.y(), newPos.x(), newPos.y())
92       
93    def remove(self):
94        self.hide()
95        self.startWidget = None
96        self.endWidget = None
97       
98        self.prepareGeometryChange()
99       
100        if self.getDropShadow():
101            self.setGraphicsEffect(None)
102             
103        for child in self.childItems():
104            child.hide()
105            child.setParentItem(None)
106            self.scene().removeItem(child)
107           
108        self.hide()
109        self.scene().removeItem(self)
110
111# #######################################
112# # CANVAS LINE
113# #######################################
114       
115class CanvasLine(QGraphicsPathItem):
116    def __init__(self, signalManager, canvasDlg, view, outWidget, inWidget, scene, *args):
117        self.outWidget = outWidget
118        self.inWidget = inWidget
119       
120        QGraphicsPathItem.__init__(self, None, None)
121        self.signalManager = signalManager
122        self.canvasDlg = canvasDlg
123        self.view = view
124        self.setZValue(-10)
125       
126        self.caption = ""
127        self.captionItem = QGraphicsTextItem(self)
128        self.captionItem.setDefaultTextColor(QColor(80, 80, 192))
129        self.captionItem.setHtml("<center>%s</center>" % self.caption)
130        self.captionItem.setAcceptHoverEvents(False)
131        self.captionItem.setVisible(bool(self.canvasDlg.settings["showSignalNames"]))
132        self.captionItem.setAcceptedMouseButtons(Qt.NoButton)
133       
134        self.updateTooltip()
135       
136        # this might seem unnecessary, but the pen size 20 is used for collision detection, when we want to see whether to to show the line menu or not
137        self.setPen(QPen(QColor(200, 200, 200), 20, Qt.SolidLine))
138        self.setAcceptHoverEvents(True)
139        self.hoverState = False
140           
141        if scene is not None:
142            scene.addItem(self)
143           
144        self._dyn_enabled = False
145           
146        QObject.connect(self.outWidget.instance, SIGNAL("dynamicLinkEnabledChanged(PyQt_PyObject, bool)"), self.updateDynamicEnableState)
147       
148        self.setDropShadow(offset=QPointF(0.0, 0.0))
149       
150    setDropShadow = setDropShadow
151    getDropShadow = getDropShadow
152   
153    def remove(self):
154        self.hide()
155        self.setToolTip("")
156        self.outWidget = None
157        self.inWidget = None
158       
159        self.prepareGeometryChange()
160       
161        if self.getDropShadow():
162            self.setGraphicsEffect(None)
163           
164        for child in self.childItems():
165            child.hide()
166            child.setParentItem(None)
167            self.scene().removeItem(child)
168           
169        self.hide()
170        self.scene().removeItem(self)
171        QApplication.instance().processEvents(QEventLoop.ExcludeUserInputEvents)
172       
173    def getEnabled(self):
174        signals = self.signalManager.findSignals(self.outWidget.instance, self.inWidget.instance)
175        if not signals: return 0
176        return int(self.signalManager.isSignalEnabled(self.outWidget.instance, self.inWidget.instance, signals[0][0], signals[0][1]))
177
178    def getSignals(self):
179        signals = []
180        for link in self.signalManager.getLinks(self.outWidget.instance, self.inWidget.instance):
181            signals.append((link.signalNameFrom, link.signalNameTo))
182#        for (inWidgetInstance, outName, inName, X) in self.signalManager.links.get(self.outWidget.instance, []):
183#            if inWidgetInstance == self.inWidget.instance:
184#                signals.append((outName, inName))
185        return signals
186   
187    def isDynamic(self):
188        links = self.signalManager.getLinks(self.outWidget.instance, self.inWidget.instance)
189        return any(link.dynamic for link in links)
190   
191    def updateDynamicEnableState(self, link, enabled):
192        """ Call when dynamic signal state changes
193        """
194        links = self.signalManager.getLinks(self.outWidget.instance, self.inWidget.instance)
195        if link not in links:
196            return
197       
198        if self.isDynamic():
199            if enabled:
200                self._dyn_enabled = True
201            else:
202                self._dyn_enabled = False
203        self.update()
204       
205   
206    def updatePainterPath(self):
207        p1 = self.outWidget.getRightEdgePoint()
208        p2 = self.inWidget.getLeftEdgePoint()
209        path = QPainterPath(p1)
210        path.cubicTo(p1.x() + 60, p1.y(), p2.x() - 60, p2.y(), p2.x(), p2.y())
211        self.setPath(path)
212        metrics = QFontMetrics(self.captionItem.font())
213        oddLineOffset = -metrics.lineSpacing() / 2 * (len(self.caption.strip().splitlines()) % 2)
214        mid = self.path().pointAtPercent(0.5)
215        rect = self.captionItem.boundingRect()
216        self.captionItem.setPos(mid + QPointF(-rect.width() / 2.0, -rect.height() / 2.0 + oddLineOffset))
217        self.update()
218       
219    def shape(self):
220        stroke = QPainterPathStroker()
221        stroke.setWidth(6)
222        return stroke.createStroke(self.path())
223   
224    def boundingRect(self):
225        rect = QGraphicsPathItem.boundingRect(self)
226        if self.getDropShadow():
227            textRect = self.captionItem.boundingRect() ## Should work without this but for some reason if using graphics effects the text gets clipped
228            textRect.moveTo(self.captionItem.pos())
229            return rect.united(textRect)
230        else:
231            return rect
232
233    def paint(self, painter, option, widget = None):
234        if self.isDynamic():
235            color2 = QColor(Qt.blue if self._dyn_enabled else Qt.red)
236            color1 = color2.lighter(150)
237        else:
238            color1 = QColor(200, 200, 200)
239            color2 = QColor(160, 160, 160)
240        painter.setPen(QPen(color1, 6 if self.hoverState == True else 4 , self.getEnabled() and Qt.SolidLine or Qt.DashLine, Qt.RoundCap))
241        painter.drawPath(self.path())
242        painter.setPen(QPen(color2, 2 , self.getEnabled() and Qt.SolidLine or Qt.DashLine, Qt.RoundCap))
243        painter.drawPath(self.path())
244
245    def updateTooltip(self):
246        if self.inWidget and self.outWidget:
247            status = self.getEnabled() == 0 and " (Disabled)" or ""
248            string = "<nobr><b>" + self.outWidget.caption + "</b> --> <b>" + self.inWidget.caption + "</b>" + status + "</nobr><hr>Signals:<br>"
249            for (outSignal, inSignal) in self.getSignals():
250                string += "<nobr> &nbsp; &nbsp; - " + outSignal + " --> " + inSignal + "</nobr><br>"
251            string = string[:-4]
252            self.setToolTip(string)
253   
254            # print the text with the signals
255            self.caption = "\n".join([outSignal for (outSignal, inSignal) in self.getSignals()])
256            self.captionItem.setHtml("<center>%s</center>" % self.caption.replace("\n", "<br/>"))
257            self.updatePainterPath()
258
259    def hoverEnterEvent(self, event):
260        self.hoverState = True
261        self.update()
262   
263    def hoverLeaveEvent(self, event):
264        self.hoverState = False
265        self.update()
266       
267
268# #######################################
269# # CANVAS WIDGET
270# #######################################
271class CanvasWidget(QGraphicsRectItem):
272    def __init__(self, signalManager, scene, view, widgetInfo, defaultPic, canvasDlg, widgetSettings = {}):
273        # import widget class and create a class instance
274        if widgetInfo.module:
275            name = "%s.%s" % (widgetInfo.module, widgetInfo.fileName)
276            __import__(name)
277            m = sys.modules[name]
278        else:
279            m = __import__(widgetInfo.fileName)
280        self.instance = m.__dict__[widgetInfo.fileName].__new__(m.__dict__[widgetInfo.fileName], _owInfo=canvasDlg.settings["owInfo"],
281                                                                _owWarning = canvasDlg.settings["owWarning"], _owError=canvasDlg.settings["owError"],
282                                                                _owShowStatus = canvasDlg.settings["owShow"], _useContexts = canvasDlg.settings["useContexts"],
283                                                                _category = widgetInfo.category, _settingsFromSchema = widgetSettings)
284        self.instance.__init__(signalManager=signalManager)
285        self.instance.__dict__["widgetInfo"] = widgetInfo
286        self.isProcessing = 0   # is this widget currently processing signals
287        self.progressBarShown = 0
288        self.progressBarValue = -1
289        self.widgetSize = QSizeF(0, 0)
290        self.widgetState = {}
291        self.caption = widgetInfo.name
292        self.selected = False
293        self.inLines = []               # list of connected lines on input
294        self.outLines = []              # list of connected lines on output
295        self.icon = canvasDlg.getWidgetIcon(widgetInfo)
296       
297        self.instance.setProgressBarHandler(view.progressBarHandler)   # set progress bar event handler
298        self.instance.setProcessingHandler(view.processingHandler)
299        self.instance.setWidgetStateHandler(self.updateWidgetState)
300        self.instance.setEventHandler(canvasDlg.output.widgetEvents)
301        self.instance.setWidgetIcon(canvasDlg.getFullWidgetIconName(widgetInfo))
302        #self.instance.updateStatusBarState()
303
304        QGraphicsRectItem.__init__(self, None, None)
305        self.signalManager = signalManager
306        self.widgetInfo = widgetInfo
307        self.view = view
308        self.canvasDlg = canvasDlg
309        canvasPicsDir  = os.path.join(canvasDlg.canvasDir, "icons")
310        self.imageLeftEdge = QPixmap(os.path.join(canvasPicsDir,"leftEdge.png"))
311        self.imageRightEdge = QPixmap(os.path.join(canvasPicsDir,"rightEdge.png"))
312        self.imageLeftEdgeG = QPixmap(os.path.join(canvasPicsDir,"leftEdgeG.png"))
313        self.imageRightEdgeG = QPixmap(os.path.join(canvasPicsDir,"rightEdgeG.png"))
314        self.imageLeftEdgeR = QPixmap(os.path.join(canvasPicsDir,"leftEdgeR.png"))
315        self.imageRightEdgeR = QPixmap(os.path.join(canvasPicsDir,"rightEdgeR.png"))
316        self.shownLeftEdge, self.shownRightEdge = self.imageLeftEdge, self.imageRightEdge
317        self.imageFrame = QIcon(QPixmap(os.path.join(canvasPicsDir, "frame.png")))
318        self.edgeSize = QSizeF(self.imageLeftEdge.size())
319        self.resetWidgetSize()
320       
321        self.oldPos = self.pos()
322       
323        self.infoIcon = QGraphicsPixmapItem(self.canvasDlg.widgetIcons["Info"], self)
324        self.warningIcon = QGraphicsPixmapItem(self.canvasDlg.widgetIcons["Warning"], self)
325        self.errorIcon = QGraphicsPixmapItem(self.canvasDlg.widgetIcons["Error"], self)
326        self.infoIcon.hide()
327        self.warningIcon.hide()
328        self.errorIcon.hide()
329       
330        self.captionItem = QGraphicsTextItem(self)
331        self.captionItem.setHtml("<center>%s</center>" % self.caption)
332        self.captionItem.document().setTextWidth(min(self.captionItem.document().idealWidth(), 200))
333       
334        self.captionItem.setPos(-self.captionItem.boundingRect().width()/2.0 + self.widgetSize.width() / 2.0, self.widgetSize.height() + 2)
335        self.captionItem.setAcceptHoverEvents(False)
336       
337        # do we want to restore last position and size of the widget
338        if self.canvasDlg.settings["saveWidgetsPosition"]:
339            self.instance.restoreWidgetPosition()
340           
341        self.setAcceptHoverEvents(True)
342        self.hoverState = False
343        self.setFlags(QGraphicsItem.ItemIsSelectable)# | QGraphicsItem.ItemIsMovable)
344       
345        if scene is not None:
346            scene.addItem(self)
347           
348        self.setDropShadow()
349
350    setDropShadow = setDropShadow
351    getDropShadow = getDropShadow
352   
353    def resetWidgetSize(self):
354        size = self.canvasDlg.schemeIconSizeList[self.canvasDlg.settings['schemeIconSize']]
355        self.setRect(0,0, size, size)
356        self.widgetSize = QSizeF(size, size)
357        self.update()
358
359    # get the list of connected signal names
360    def getInConnectedSignalNames(self):
361        signals = []
362        for line in self.inLines:
363            for (outSignal, inSignal) in line.getSignals():
364                if inSignal not in signals: signals.append(inSignal)
365        return signals
366
367    # get the list of connected signal names
368    def getOutConnectedSignalNames(self):
369        signals = []
370        for line in self.outLines:
371            for (outSignal, inSignal) in line.getSignals():
372                if outSignal not in signals: signals.append(outSignal)
373        return signals
374
375    def remove(self):
376        self.hide()
377        self.errorIcon.hide()
378        self.warningIcon.hide()
379        self.infoIcon.hide()
380
381        # save settings
382        if (self.instance != None):
383            if self.canvasDlg.menuSaveSettings == 1 and not self.instance._settingsFromSchema:       
384                # save settings only if checked in the main menu, and the widget settings were not loaded from
385                # a schema file (i.e it is a new widget, this prevents the overriding of the the global .ini file)
386                try:
387                    self.instance.saveSettings()
388                except:
389                    print "Unable to save settings for %s widget" % (self.instance.captionTitle)
390                    type, val, traceback = sys.exc_info()
391                    sys.excepthook(type, val, traceback)  # we pretend that we handled the exception, so that it doesn't crash canvas
392            self.instance.close()
393            self.instance.linksOut.clear()      # this helps python to more quickly delete the unused objects
394            self.instance.linksIn.clear()
395            self.instance.setProgressBarHandler(None)   # set progress bar event handler
396            self.instance.setProcessingHandler(None)
397            self.instance.setWidgetStateHandler(None)
398            self.instance.setEventHandler(None)
399            self.instance.onDeleteWidget()      # this is a cleanup function that can take care of deleting some unused objects
400           
401            # Schedule the widget instance for deletion
402            self.instance.deleteLater()
403            self.instance = None
404           
405        self.prepareGeometryChange()
406       
407        if self.getDropShadow():
408            self.setGraphicsEffect(None)
409       
410        for child in self.childItems():
411            child.hide()
412            child.setParentItem(None)
413            self.scene().removeItem(child)
414       
415        self.hide()
416        self.scene().removeItem(self)
417       
418    def savePosition(self):
419        self.oldPos = self.pos()
420
421    def restorePosition(self):
422        self.setPos(self.oldPos)
423
424    def updateText(self, text):
425        self.caption = str(text)
426        self.prepareGeometryChange()
427        self.captionItem.setHtml("<center>%s</center>" % self.caption)
428        self.captionItem.document().adjustSize()
429        self.captionItem.document().setTextWidth(min(self.captionItem.document().idealWidth(), 200))
430       
431        self.captionItem.setPos(-self.captionItem.boundingRect().width()/2.0 + self.widgetSize.width() / 2.0, self.widgetSize.height() + 2)
432        self.updateTooltip()
433        self.update()
434
435    def updateWidgetState(self):
436        widgetState = self.instance.widgetState
437
438        self.infoIcon.hide()
439        self.warningIcon.hide()
440        self.errorIcon.hide()
441
442        yPos = - 21 - self.progressBarShown * 20
443        iconNum = sum([widgetState.get("Info", {}).values() != [],  widgetState.get("Warning", {}).values() != [], widgetState.get("Error", {}).values() != []])
444
445        if self.canvasDlg.settings["ocShow"]:        # if show icons is enabled in canvas options dialog
446            startX = (self.rect().width()/2) - ((iconNum*(self.canvasDlg.widgetIcons["Info"].width()+2))/2)
447            off  = 0
448            if len(widgetState.get("Info", {}).values()) > 0 and self.canvasDlg.settings["ocInfo"]:
449                off  = self.updateWidgetStateIcon(self.infoIcon, startX, yPos, widgetState["Info"])
450            if len(widgetState.get("Warning", {}).values()) > 0 and self.canvasDlg.settings["ocWarning"]:
451                off += self.updateWidgetStateIcon(self.warningIcon, startX+off, yPos, widgetState["Warning"])
452            if len(widgetState.get("Error", {}).values()) > 0 and self.canvasDlg.settings["ocError"]:
453                off += self.updateWidgetStateIcon(self.errorIcon, startX+off, yPos, widgetState["Error"])
454
455
456    def updateWidgetStateIcon(self, icon, x, y, stateDict):
457        icon.setPos(x,y)
458        icon.show()
459        icon.setToolTip(reduce(lambda x,y: x+'<br>'+y, stateDict.values()))
460        return icon.pixmap().width() + 3
461
462    # set coordinates of the widget
463    def setCoords(self, x, y):
464        if self.canvasDlg.settings["snapToGrid"]:
465            x = round(x/10)*10
466            y = round(y/10)*10
467        self.setPos(x, y)
468        self.updateWidgetState()
469       
470    def setPos(self, *args):
471        QGraphicsRectItem.setPos(self, *args)
472        for line in self.inLines + self.outLines:
473            line.updatePainterPath()
474           
475
476    # we have to increase the default bounding rect so that we also repaint the name of the widget and input/output boxes
477    def boundingRect(self):
478        rect = QRectF(QPointF(0, 0), self.widgetSize).adjusted(-11, -6, 11, 6)#.adjusted(-100, -100, 100, 100) #(-10-width, -4, +10+width, +25)
479        rect.setTop(rect.top() - 20 - 21) ## Room for progress bar and warning, error, info icons
480        if self.getDropShadow():
481            textRect = self.captionItem.boundingRect() ## Should work without this but for some reason if using graphics effects the text gets clipped
482            textRect.moveTo(self.captionItem.pos()) 
483            return rect.united(textRect)
484        else:
485            return rect
486
487    # is mouse position inside the left signal channel
488    def mouseInsideLeftChannel(self, pos):
489        if self.widgetInfo.inputs == []: return False
490
491        boxRect = QRectF(self.x()-self.edgeSize.width(), self.y() + (self.widgetSize.height()-self.edgeSize.height())/2, self.edgeSize.width(), self.edgeSize.height())
492        boxRect.adjust(-10,-10,5,10)       # enlarge the rectangle
493        if isinstance(pos, QPointF) and boxRect.contains(pos): return True
494        elif isinstance(pos, QRectF) and boxRect.intersects(pos): return True
495        else: return False
496
497    # is mouse position inside the right signal channel
498    def mouseInsideRightChannel(self, pos):
499        if self.widgetInfo.outputs == []: return False
500
501        boxRect = QRectF(self.x()+self.widgetSize.width(), self.y() + (self.widgetSize.height()-self.edgeSize.height())/2, self.edgeSize.width(), self.edgeSize.height())
502        boxRect.adjust(-5,-10,10,10)       # enlarge the rectangle
503        if isinstance(pos, QPointF) and boxRect.contains(pos): return True
504        elif isinstance(pos, QRectF) and boxRect.intersects(pos): return True
505        else: return False
506       
507    def canConnect(self, outWidget, inWidget, dynamic=False):
508        if outWidget == inWidget:
509            return
510       
511        canConnect = self.signalManager.canConnect(outWidget.instance, inWidget.instance, dynamic=dynamic)
512       
513#        outputs = [outWidget.instance.getOutputType(output.name) for output in outWidget.widgetInfo.outputs]
514#        inputs = [inWidget.instance.getInputType(input.name) for input in inWidget.widgetInfo.inputs]
515#        canConnect = 0
516#        for outtype in outputs:
517#            if any(issubclass(outtype, intype) for intype in inputs):
518#                canConnect = 1
519#                break
520#            elif dynamic and any(issubclass(intype, outtype) for intype in inputs):
521#                canConnect = 2
522#                break
523
524        if outWidget == self:
525            self.shownRightEdge = canConnect and self.imageRightEdgeG or self.imageRightEdgeR
526        else:
527            self.shownLeftEdge = canConnect and self.imageLeftEdgeG or self.imageLeftEdgeR
528
529    def resetLeftRightEdges(self):
530        self.shownLeftEdge = self.imageLeftEdge
531        self.shownRightEdge = self.imageRightEdge
532   
533   
534    # we know that the mouse was pressed inside a channel box. We only need to find
535    # inside which one it was
536    def getEdgePoint(self, pos):
537        if self.mouseInsideLeftChannel(pos):
538            return self.getLeftEdgePoint()
539        elif self.mouseInsideRightChannel(pos):
540            return self.getRightEdgePoint()
541
542    def getLeftEdgePoint(self):
543        return QPointF(self.x()+2- self.edgeSize.width(), self.y() + self.widgetSize.height()/2)
544
545    def getRightEdgePoint(self):
546        return QPointF(self.x()-2+ self.widgetSize.width() + self.edgeSize.width(), self.y() + self.widgetSize.height()/2)
547
548    def getDistToLeftEdgePoint(self, point):
549        p = self.getLeftEdgePoint()
550        diff = point-p
551        return math.sqrt(diff.x()**2 + diff.y()**2)
552   
553    def getDistToRightEdgePoint(self, point):
554        p = self.getRightEdgePoint()
555        diff = point-p
556        return math.sqrt(diff.x()**2 + diff.y()**2)
557
558
559    # draw the widget
560    def paint(self, painter, option, widget = None):
561        if self.isProcessing or self.isSelected() or getattr(self, "invalidPosition", False):
562            painter.setPen(QPen(QBrush(QColor(125, 162, 206, 192)), 1, Qt.SolidLine, Qt.RoundCap))
563            painter.setBrush(QBrush(QColor(217, 232, 252, 192)))
564            painter.drawRoundedRect(-10, -5, self.widgetSize.width()+20, self.widgetSize.height()+10, 5, 5)
565
566        if self.widgetInfo.inputs != []:
567            painter.drawPixmap(-self.edgeSize.width()+1, (self.widgetSize.height()-self.edgeSize.height())/2, self.shownLeftEdge)
568        if self.widgetInfo.outputs != []:
569            painter.drawPixmap(self.widgetSize.width()-2, (self.widgetSize.height()-self.edgeSize.height())/2, self.shownRightEdge)
570           
571        if self.hoverState:
572            color = QColor(125, 162, 206)
573            painter.setPen(Qt.NoPen)
574            painter.setBrush(color)
575            painter.drawRoundedRect(-2, -2, self.widgetSize.width() + 4, self.widgetSize.height() + 4, 5, 5)
576           
577        painter.drawPixmap(0,0, self.icon.pixmap(self.widgetSize.width(), self.widgetSize.height()))
578       
579        yPos = -22
580        if self.progressBarValue >= 0 and self.progressBarValue <= 100:
581            rect = QRectF(0, yPos, self.widgetSize.width(), 16)
582            painter.setPen(QPen(QColor(0,0,0)))
583            painter.setBrush(QBrush(QColor(255,255,255)))
584            painter.drawRect(rect)
585
586            painter.setBrush(QBrush(QColor(0,128,255)))
587            painter.drawRect(QRectF(0, yPos, self.widgetSize.width()*self.progressBarValue/100., 16))
588            painter.drawText(rect, Qt.AlignCenter, "%d %%" % (self.progressBarValue))
589
590
591    def addOutLine(self, line):
592        self.outLines.append(line)
593
594    def addInLine(self,line):
595        self.inLines.append(line)
596
597    def removeLine(self, line):
598        if line in self.inLines:
599            self.inLines.remove(line)
600        elif line in self.outLines:
601            self.outLines.remove(line)
602        else:
603            print "Orange Canvas: Error. Unable to remove line"
604
605        self.updateTooltip()
606
607
608    def setAllLinesFinished(self, finished):
609        for line in self.inLines: line.finished = finished
610        for line in self.outLines: line.finished = finished
611
612
613    def updateTooltip(self):
614        string = "<nobr><b>" + self.caption + "</b></nobr><hr>Inputs:<br>"
615
616        if self.widgetInfo.inputs == []: string += "&nbsp; &nbsp; None<br>"
617        else:
618            for signal in self.widgetInfo.inputs:
619                widgets = self.signalManager.getLinkWidgetsIn(self.instance, signal.name)
620                if len(widgets) > 0:
621                    string += "<nobr> &nbsp; &nbsp; - <b>" + signal.name + "</b> (from "
622                    for i in range(len(widgets)-1):
623                        string += self.view.doc.getWidgetCaption(widgets[i]) + ", "
624                    string += self.view.doc.getWidgetCaption(widgets[-1]) + ")</nobr><br>"
625                else:
626                    string += "<nobr> &nbsp; &nbsp; - " + signal.name + "</nobr><br>"
627
628        string = string[:-4]
629        string += "<hr>Outputs:<br>"
630        if self.widgetInfo.outputs == []: string += "&nbsp; &nbsp; None<br>"
631        else:
632            for signal in self.widgetInfo.outputs:
633                widgets = self.signalManager.getLinkWidgetsOut(self.instance, signal.name)
634                if len(widgets) > 0:
635                    string += "<nobr> &nbsp; &nbsp; - <b>" + signal.name + "</b> (to "
636                    for i in range(len(widgets)-1):
637                        string += self.view.doc.getWidgetCaption(widgets[i]) + ", "
638                    string += self.view.doc.getWidgetCaption(widgets[-1]) + ")</nobr><br>"
639                else:
640                    string += "<nobr> &nbsp; &nbsp; - " + signal.name + "</nobr><br>"
641        string = string[:-4]
642        self.setToolTip(string)
643
644    def setProgressBarValue(self, value):
645        self.progressBarValue = value
646        if value < 0 or value > 100:
647            self.updateWidgetState()
648        self.update()
649
650    def setProcessing(self, value):
651        self.isProcessing = value
652        self.update()
653
654    def hoverEnterEvent(self, event):
655        self.hoverState = True
656        self.update()
657        return QGraphicsRectItem.hoverEnterEvent(self, event)
658       
659    def hoverLeaveEvent(self, event):
660        self.hoverState = False
661        self.update()
662        return QGraphicsRectItem.hoverLeaveEvent(self, event)       
663
664class MyCanvasText(QGraphicsSimpleTextItem):
665    def __init__(self, canvas, text, x, y, flags=Qt.AlignLeft, bold=0, show=1):
666        QGraphicsSimpleTextItem.__init__(self, text, None, canvas)
667        self.setPos(x,y)
668        self.setPen(QPen(Qt.black))
669        self.flags = flags
670        if bold:
671            font = self.font();
672            font.setBold(1);
673            self.setFont(font)
674        if show:
675            self.show()
676
677    def paint(self, painter, option, widget = None):
678        #painter.resetMatrix()
679        painter.setPen(self.pen())
680        painter.setFont(self.font())
681
682        xOff = 0; yOff = 0
683        rect = painter.boundingRect(QRectF(0,0,2000,2000), self.flags, self.text())
684        if self.flags & Qt.AlignHCenter: xOff = rect.width()/2.
685        elif self.flags & Qt.AlignRight: xOff = rect.width()
686        if self.flags & Qt.AlignVCenter: yOff = rect.height()/2.
687        elif self.flags & Qt.AlignBottom:yOff = rect.height()
688        #painter.drawText(self.pos().x()-xOff, self.pos().y()-yOff, rect.width(), rect.height(), self.flags, self.text())
689        painter.drawText(-xOff, -yOff, rect.width(), rect.height(), self.flags, self.text())
690       
Note: See TracBrowser for help on using the repository browser.