Ignore:
Files:
1 added
23 edited

Legend:

Unmodified
Added
Removed
  • Orange/OrangeCanvas/application/canvasmain.py

    r11399 r11415  
    336336        self.dock_widget.setCollapsedWidget(dock2) 
    337337        self.dock_widget.setExpanded(True) 
     338        self.dock_widget.expandedChanged.connect(self._on_tool_dock_expanded) 
    338339 
    339340        self.addDockWidget(Qt.RightDockWidgetArea, self.dock_widget) 
     
    530531                    ) 
    531532 
     533        self.toggle_tool_dock_expand = \ 
     534            QAction(self.tr("Expand Tool Dock"), self, 
     535                    objectName="toggle-tool-dock-expand", 
     536                    checkable=True, 
     537                    checked=True, 
     538                    shortcut=QKeySequence(Qt.ControlModifier | 
     539                                          Qt.ShiftModifier | Qt.Key_D), 
     540                    triggered=self.set_tool_dock_expanded) 
     541 
    532542        # Gets assigned in setup_ui (the action is defined in CanvasToolDock) 
    533543        # TODO: This is bad (should be moved here). 
     
    597607            QActionGroup(self, objectName="toolbox-menu-group") 
    598608 
    599         a1 = self.toolbox_menu.addAction(self.tr("Tool Box")) 
    600         a2 = self.toolbox_menu.addAction(self.tr("Tool List")) 
    601         self.toolbox_menu_group.addAction(a1) 
    602         self.toolbox_menu_group.addAction(a2) 
    603  
    604         self.view_menu.addMenu(self.toolbox_menu) 
     609        self.view_menu.addAction(self.toggle_tool_dock_expand) 
     610 
    605611        self.view_menu.addSeparator() 
    606612        self.view_menu.addAction(self.toogle_margins_action) 
     
    11111117 
    11121118        dialog.deleteLater() 
     1119        model.deleteLater() 
    11131120 
    11141121        if status == QDialog.Accepted: 
     
    12231230 
    12241231        bottom_row = [self.get_started_action, tutorials_action, 
    1225                    self.documentation_action] 
     1232                      self.documentation_action] 
    12261233 
    12271234        self.new_action.triggered.connect(dialog.accept) 
     
    14471454        """ 
    14481455        self.__update_scheme_margins() 
     1456 
     1457    def set_tool_dock_expanded(self, expanded): 
     1458        """ 
     1459        Set the dock widget expanded state. 
     1460        """ 
     1461        self.dock_widget.setExpanded(expanded) 
     1462 
     1463    def _on_tool_dock_expanded(self, expanded): 
     1464        """ 
     1465        'dock_widget' widget was expanded/collapsed. 
     1466        """ 
     1467        if expanded != self.toggle_tool_dock_expand.isChecked(): 
     1468            self.toggle_tool_dock_expand.setChecked(expanded) 
    14491469 
    14501470    def createPopupMenu(self): 
     
    16641684        self.scheme_widget.setChannelNamesVisible(show_channel_names) 
    16651685 
     1686        node_animations = settings.value("enable-node-animations", 
     1687                                         defaultValue=False, 
     1688                                         type=bool) 
     1689        self.scheme_widget.setNodeAnimationEnabled(node_animations) 
    16661690        settings.endGroup() 
    16671691 
  • Orange/OrangeCanvas/application/settings.py

    r11320 r11416  
    234234        tab.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) 
    235235 
     236        nodes = QWidget(self, objectName="nodes") 
     237        nodes.setLayout(QVBoxLayout()) 
     238        nodes.layout().setContentsMargins(0, 0, 0, 0) 
     239 
     240        cb_anim = QCheckBox( 
     241            self.tr("Enable node animations"), 
     242            objectName="enable-node-animations", 
     243            toolTip=self.tr("Enable shadow and ping animations for node " 
     244                            "items in the scheme.") 
     245        ) 
     246        self.bind(cb_anim, "checked", "schemeedit/enable-node-animations") 
     247        nodes.layout().addWidget(cb_anim) 
     248 
     249        form.addRow(self.tr("Nodes"), nodes) 
     250 
    236251        links = QWidget(self, objectName="links") 
    237252        links.setLayout(QVBoxLayout()) 
     
    245260        ) 
    246261 
    247         cb_state = QCheckBox( 
    248             self.tr("Show link state"), 
    249             objectName="show-link-state", 
    250             toolTip=self.tr("Show link state") 
    251         ) 
    252  
    253262        self.bind(cb_show, "checked", "schemeedit/show-channel-names") 
    254         self.bind(cb_state, "checked", "schemeedit/show-link-state") 
    255263 
    256264        links.layout().addWidget(cb_show) 
    257         links.layout().addWidget(cb_state) 
    258265 
    259266        form.addRow(self.tr("Links"), links) 
     
    313320        toolbox.layout().setContentsMargins(0, 0, 0, 0) 
    314321 
    315         exclusive = QCheckBox(self.tr("Exclusive"), 
    316                               toolTip="Only one tab can be opened at a time.") 
    317  
    318         floatable = QCheckBox(self.tr("Floatable"), 
    319                               toolTip="Toolbox can be undocked.") 
     322        exclusive = QCheckBox(self.tr("Only one tab can be open at a time")) 
    320323 
    321324        self.bind(exclusive, "checked", "mainwindow/toolbox-dock-exclusive") 
    322         self.bind(floatable, "checked", "mainwindow/toolbox-dock-floatable") 
    323325 
    324326        toolbox.layout().addWidget(exclusive) 
    325         toolbox.layout().addWidget(floatable) 
    326327 
    327328        form.addRow(self.tr("Tool box"), toolbox) 
  • Orange/OrangeCanvas/canvas/items/nodeitem.py

    r11369 r11411  
    77 
    88from PyQt4.QtGui import ( 
    9     QGraphicsItem, QGraphicsPathItem, QGraphicsObject, 
    10     QGraphicsTextItem, QGraphicsDropShadowEffect, QGraphicsView, 
     9    QGraphicsItem, QGraphicsObject, QGraphicsTextItem, 
     10    QGraphicsDropShadowEffect, QGraphicsView, 
    1111    QPen, QBrush, QColor, QPalette, QIcon, QStyle, QPainter, 
    1212    QPainterPath, QPainterPathStroker, QApplication 
    1313) 
    1414 
    15 from PyQt4.QtCore import Qt, QPointF, QRectF, QSize, QTimer 
     15from PyQt4.QtCore import Qt, QPointF, QRectF, QSize, QTimer, QPropertyAnimation 
    1616from PyQt4.QtCore import pyqtSignal as Signal 
    1717from PyQt4.QtCore import pyqtProperty as Property 
     
    5656 
    5757 
     58def animation_restart(animation): 
     59    if animation.state() == QPropertyAnimation.Running: 
     60        animation.pause() 
     61    animation.start() 
     62 
     63 
    5864SHADOW_COLOR = "#9CACB4" 
    5965FOCUS_OUTLINE_COLOR = "#609ED7" 
    6066 
    6167 
    62 class NodeBodyItem(QGraphicsPathItem): 
     68class NodeBodyItem(GraphicsPathObject): 
    6369    """ 
    6470    The central part (body) of the `NodeItem`. 
    6571    """ 
    6672    def __init__(self, parent=None): 
    67         QGraphicsPathItem.__init__(self, parent) 
     73        GraphicsPathObject.__init__(self, parent) 
    6874        assert(isinstance(parent, NodeItem)) 
    6975 
    7076        self.__processingState = 0 
    7177        self.__progress = -1 
     78        self.__animationEnabled = False 
    7279        self.__isSelected = False 
    7380        self.__hasFocus = False 
     
    8592 
    8693        self.shadow = QGraphicsDropShadowEffect( 
    87             blurRadius=10, 
     94            blurRadius=3, 
    8895            color=QColor(SHADOW_COLOR), 
    8996            offset=QPointF(0, 0), 
     
    9198 
    9299        self.setGraphicsEffect(self.shadow) 
    93         self.shadow.setEnabled(False) 
     100        self.shadow.setEnabled(True) 
     101 
     102        self.__blurAnimation = QPropertyAnimation(self.shadow, "blurRadius", 
     103                                                  self) 
     104        self.__blurAnimation.setDuration(100) 
     105        self.__blurAnimation.finished.connect(self.__on_finished) 
     106 
     107        self.__pingAnimation = QPropertyAnimation(self, "scale", self) 
     108        self.__pingAnimation.setDuration(250) 
     109        self.__pingAnimation.setKeyValues([(0.0, 1.0), (0.5, 1.1), (1.0, 1.0)]) 
    94110 
    95111    # TODO: The body item should allow the setting of arbitrary painter 
     
    113129        self.__updateBrush() 
    114130 
     131    def setAnimationEnabled(self, enabled): 
     132        """ 
     133        Set the node animation enabled. 
     134        """ 
     135        if self.__animationEnabled != enabled: 
     136            self.__animationEnabled = enabled 
     137 
    115138    def setProcessingState(self, state): 
    116139        """ 
    117140        Set the processing state of the node. 
    118141        """ 
    119         self.__processingState = state 
    120         self.update() 
     142        if self.__processingState != state: 
     143            self.__processingState = state 
     144            if not state and self.__animationEnabled: 
     145                self.ping() 
    121146 
    122147    def setProgress(self, progress): 
     
    128153        self.__progress = progress 
    129154        self.update() 
     155 
     156    def ping(self): 
     157        """ 
     158        Trigger a 'ping' animation. 
     159        """ 
     160        animation_restart(self.__pingAnimation) 
    130161 
    131162    def hoverEnterEvent(self, event): 
    132163        self.__hover = True 
    133164        self.__updateShadowState() 
    134         return QGraphicsPathItem.hoverEnterEvent(self, event) 
     165        return GraphicsPathObject.hoverEnterEvent(self, event) 
    135166 
    136167    def hoverLeaveEvent(self, event): 
    137168        self.__hover = False 
    138169        self.__updateShadowState() 
    139         return QGraphicsPathItem.hoverLeaveEvent(self, event) 
     170        return GraphicsPathObject.hoverLeaveEvent(self, event) 
    140171 
    141172    def paint(self, painter, option, widget): 
     
    147178            # Prevent the default bounding rect selection indicator. 
    148179            option.state = option.state ^ QStyle.State_Selected 
    149         QGraphicsPathItem.paint(self, painter, option, widget) 
     180        GraphicsPathObject.paint(self, painter, option, widget) 
    150181 
    151182        if self.__progress >= 0: 
     
    169200            self.setPen(QPen(Qt.NoPen)) 
    170201 
     202        radius = 3 
    171203        enabled = False 
     204 
    172205        if self.__isSelected: 
    173             self.shadow.setBlurRadius(7) 
    174206            enabled = True 
    175         elif self.__hover: 
    176             self.shadow.setBlurRadius(17) 
     207            radius = 7 
     208 
     209        if self.__hover: 
     210            radius = 17 
    177211            enabled = True 
    178         self.shadow.setEnabled(enabled) 
     212 
     213        if enabled and not self.shadow.isEnabled(): 
     214            self.shadow.setEnabled(enabled) 
     215 
     216        if self.__animationEnabled: 
     217            if self.__blurAnimation.state() == QPropertyAnimation.Running: 
     218                self.__blurAnimation.pause() 
     219 
     220            self.__blurAnimation.setStartValue(self.shadow.blurRadius()) 
     221            self.__blurAnimation.setEndValue(radius) 
     222            self.__blurAnimation.start() 
     223        else: 
     224            self.shadow.setBlurRadius(radius) 
    179225 
    180226    def __updateBrush(self): 
     
    215261        self.__hasFocus = focus 
    216262        self.__updateShadowState() 
     263 
     264    def __on_finished(self): 
     265        if self.shadow.blurRadius() == 0: 
     266            self.shadow.setEnabled(False) 
    217267 
    218268 
     
    692742 
    693743        self.__anchorLayout = None 
     744        self.__animationEnabled = False 
    694745 
    695746        self.setZValue(self.Z_VALUE) 
     
    727778        self.shapeItem = NodeBodyItem(self) 
    728779        self.shapeItem.setShapeRect(shape_rect) 
     780        self.shapeItem.setAnimationEnabled(self.__animationEnabled) 
    729781 
    730782        # Rect for widget's 'ears'. 
     
    855907        return self.captionTextItem.font() 
    856908 
     909    def setAnimationEnabled(self, enabled): 
     910        """ 
     911        Set the node animation enabled state. 
     912        """ 
     913        if self.__animationEnabled != enabled: 
     914            self.__animationEnabled = enabled 
     915            self.shapeItem.setAnimationEnabled(enabled) 
     916 
     917    def animationEnabled(self): 
     918        """ 
     919        Are node animations enabled. 
     920        """ 
     921        return self.__animationEnabled 
     922 
    857923    def setProcessingState(self, state): 
    858924        """ 
     
    867933                # Clear the progress meter. 
    868934                self.setProgress(-1) 
     935                if self.__animationEnabled: 
     936                    self.shapeItem.ping() 
    869937 
    870938    def processingState(self): 
  • Orange/OrangeCanvas/canvas/scene.py

    r11369 r11411  
    100100 
    101101        self.__channel_names_visible = True 
     102        self.__node_animation_enabled = True 
    102103 
    103104        self.user_interaction_handler = None 
     
    217218        return self.__channel_names_visible 
    218219 
     220    def set_node_animation_enabled(self, enabled): 
     221        if self.__node_animation_enabled != enabled: 
     222            self.__node_animation_enabled = enabled 
     223 
     224            for node in self.__node_items: 
     225                node.setAnimationEnabled(enabled) 
     226 
    219227    def add_node_item(self, item): 
    220228        """Add a :class:`NodeItem` instance to the scene. 
     
    301309            item.setWidgetCategory(category_desc) 
    302310 
     311        item.setAnimationEnabled(self.__node_animation_enabled) 
    303312        return item 
    304313 
  • Orange/OrangeCanvas/config.py

    r11388 r11411  
    7979     ("schemeedit/show-link-state", bool, True, 
    8080      "Show link state hints."), 
     81 
     82     ("schemeedit/enable-node-animations", bool, True, 
     83      "Enable node animations."), 
    8184 
    8285     ("schemeedit/freeze-on-load", bool, False, 
  • Orange/OrangeCanvas/document/quickmenu.py

    r11371 r11420  
    4848    A menu page in a :class:`QuickMenu` widget, showing a list of actions. 
    4949    Shown actions can be disabled by setting a filtering function using the 
    50     :ref:`setFilterFunc`. 
     50    :func:`setFilterFunc`. 
    5151 
    5252    """ 
     
    8080        return self.__title 
    8181 
    82     title_ = Property(unicode, fget=title, fset=setTitle) 
     82    title_ = Property(unicode, fget=title, fset=setTitle, 
     83                      doc="Title of the page.") 
    8384 
    8485    def setIcon(self, icon): 
     
    9697        return self.__icon 
    9798 
    98     icon_ = Property(QIcon, fget=icon, fset=setIcon) 
     99    icon_ = Property(QIcon, fget=icon, fset=setIcon, 
     100                     doc="Page icon") 
    99101 
    100102    def setFilterFunc(self, func): 
     
    111113    def setModel(self, model): 
    112114        """ 
    113         Reimplemented from :ref:`ToolTree.setModel`. 
     115        Reimplemented from :func:`ToolTree.setModel`. 
    114116        """ 
    115117        proxyModel = ItemDisableFilter(self) 
     
    119121    def setRootIndex(self, index): 
    120122        """ 
    121         Reimplemented from :ref:`ToolTree.setRootIndex` 
     123        Reimplemented from :func:`ToolTree.setRootIndex` 
    122124        """ 
    123125        proxyModel = self.view().model() 
     
    127129    def rootIndex(self): 
    128130        """ 
    129         Reimplemented from :ref:`ToolTree.rootIndex` 
     131        Reimplemented from :func:`ToolTree.rootIndex` 
    130132        """ 
    131133        proxyModel = self.view().model() 
     
    630632    A quick menu popup for the widgets. 
    631633 
    632     The widgets are set using :ref:`setModel` which must be a 
    633     model as returned by QtWidgetRegistry.model() 
    634  
    635     """ 
    636  
     634    The widgets are set using :func:`QuickMenu.setModel` which must be a 
     635    model as returned by :func:`QtWidgetRegistry.model` 
     636 
     637    """ 
     638 
     639    #: An action has been triggered in the menu. 
    637640    triggered = Signal(QAction) 
     641 
     642    #: An action has been hovered in the menu 
    638643    hovered = Signal(QAction) 
    639644 
     
    723728    def addPage(self, name, page): 
    724729        """ 
    725         Add the page and return it's index. 
     730        Add the `page` (:class:`MenuPage`) with `name` and return it's index. 
     731        The `page.icon()` will be used as the icon in the tab bar. 
     732 
    726733        """ 
    727734        icon = page.icon() 
     
    732739 
    733740        index = self.__pages.addPage(page, name, icon, tip) 
    734         # TODO: get the background. 
    735741 
    736742        # Route the page's signals 
     
    738744        page.hovered.connect(self.hovered) 
    739745 
    740         # Install event filter to process key presses. 
     746        # Install event filter to intercept key presses. 
    741747        page.view().installEventFilter(self) 
    742748 
     
    868874 
    869875    def exec_(self, pos=None): 
     876        """ 
     877        Execute the menu at position `pos` (in global screen coordinates). 
     878        Return the triggered :class:`QAction` or `None` if no action was 
     879        triggered. 
     880 
     881        """ 
    870882        self.popup(pos) 
    871883        self.setFocus(Qt.PopupFocusReason) 
     
    882894 
    883895    def hideEvent(self, event): 
     896        """ 
     897        Reimplemented from :class:`QWidget` 
     898        """ 
    884899        FramelessWindow.hideEvent(self, event) 
    885900        if self.__loop: 
     
    962977 
    963978class ItemViewKeyNavigator(QObject): 
     979    """ 
     980    A event filter class listening to key press events and responding 
     981    by moving 'currentItem` on a :class:`QListView`. 
     982 
     983    """ 
    964984    def __init__(self, parent=None): 
    965985        QObject.__init__(self, parent) 
     
    967987 
    968988    def setView(self, view): 
     989        """ 
     990        Set the QListView. 
     991        """ 
    969992        if self.__view != view: 
    970993            self.__view = view 
    971994 
    972995    def view(self): 
     996        """ 
     997        Return the view 
     998        """ 
    973999        return self.__view 
    9741000 
     
    10211047            curr = self.__view.currentIndex() 
    10221048            if curr.isValid(): 
    1023                 # TODO: Does this work 
     1049                # TODO: Does this work? We are emitting signals that are 
     1050                # defined by a different class. This might break some things. 
     1051                # Should we just send the keyPress events to the view, and let 
     1052                # it handle them. 
    10241053                self.__view.activated.emit(curr) 
    10251054 
     
    10421071    """ 
    10431072    Automatically positioning :class:`QSizeGrip`. 
     1073    The widget automatically maintains its position in the window 
     1074    corner during resize events. 
     1075 
    10441076    """ 
    10451077    def __init__(self, parent): 
     
    10531085    def setCorner(self, corner): 
    10541086        """ 
    1055         Set the corner where the size grip should position itself. 
     1087        Set the corner (:class:`Qt.Corner`) where the size grip should 
     1088        position itself. 
     1089 
    10561090        """ 
    10571091        if corner not in [Qt.TopLeftCorner, Qt.TopRightCorner, 
  • Orange/OrangeCanvas/document/schemeedit.py

    r11390 r11411  
    116116        self.__emptyClickButtons = 0 
    117117        self.__channelNamesVisible = True 
     118        self.__nodeAnimationEnabled = True 
    118119        self.__possibleSelectionHandler = None 
    119120        self.__possibleMouseItemsMove = False 
     
    344345        scene = CanvasScene() 
    345346        scene.set_channel_names_visible(self.__channelNamesVisible) 
     347        scene.set_node_animation_enabled(self.__nodeAnimationEnabled) 
    346348        scene.setFont(self.font()) 
    347349 
     
    469471        """ 
    470472        return self.__channelNamesVisible 
     473 
     474    def setNodeAnimationEnabled(self, enabled): 
     475        """ 
     476        Set the node item animation enabled state. 
     477        """ 
     478        if self.__nodeAnimationEnabled != enabled: 
     479            self.__nodeAnimationEnabled = enabled 
     480            self.__scene.set_node_animation_enabled(enabled) 
     481 
     482    def nodeAnimationEnabled(self): 
     483        """ 
     484        Return the node item animation enabled state. 
     485        """ 
     486        return self.__nodeAnimationEnabled 
    471487 
    472488    def undoStack(self): 
     
    545561            self.__view.setScene(self.__scene) 
    546562            self.__scene.set_channel_names_visible(self.__channelNamesVisible) 
     563            self.__scene.set_node_animation_enabled( 
     564                self.__nodeAnimationEnabled 
     565            ) 
     566 
    547567            self.__scene.setFont(self.font()) 
    548568 
  • Orange/OrangeCanvas/gui/dock.py

    r11366 r11414  
    1616from PyQt4.QtCore import Qt, QEvent 
    1717 
    18 from PyQt4.QtCore import pyqtProperty as Property 
     18from PyQt4.QtCore import pyqtProperty as Property, pyqtSignal as Signal 
    1919 
    2020from .stackedwidget import AnimatedStackedWidget 
     
    3131    and ``setCollapsedWidget``. 
    3232 
    33     .. note:: Do use the base class ``QDockWidget.setWidget`` method to set 
    34               the contents. 
     33    .. note:: Do  not use the base class ``QDockWidget.setWidget`` method 
     34              to set the docks contents. Use set[Expanded|Collapsed]Widget 
     35              instead. 
    3536 
    3637    """ 
     38 
     39    #: Emitted when the dock widget's expanded state changes. 
     40    expandedChanged = Signal(bool) 
     41 
    3742    def __init__(self, *args, **kwargs): 
    3843        QDockWidget.__init__(self, *args, **kwargs) 
     
    98103            self.__fixIcon() 
    99104 
     105            self.expandedChanged.emit(state) 
     106 
    100107    def expanded(self): 
    101108        """ 
    102         Is the dock widget in expanded state. When `True` the 
     109        Is the dock widget in expanded state. If `True` the 
    103110        ``expandedWidget`` will be shown, and ``collapsedWidget`` otherwise. 
    104111 
     
    131138            self.updateGeometry() 
    132139 
    133     def expandedWidet(self): 
     140    def expandedWidget(self): 
    134141        """ 
    135142        Return the widget previously set with ``setExpandedWidget``, 
  • Orange/OrangeCanvas/gui/toolbox.py

    r11366 r11417  
    230230            self.__exclusive = exclusive 
    231231            self.__tabActionGroup.setExclusive(exclusive) 
     232            checked = self.__tabActionGroup.checkedAction() 
     233            # Trigger/toggle remaining open pages 
     234            if exclusive and checked is not None: 
     235                for page in self.__pages: 
     236                    if checked != page.action and page.action.isChecked(): 
     237                        page.action.trigger() 
    232238 
    233239    def exclusive(self): 
  • Orange/OrangeCanvas/preview/previewmodel.py

    r11191 r11413  
    5050            self.insertColumn(0, items) 
    5151 
     52        self.__timer = QTimer(self) 
     53 
    5254    def delayedScanUpdate(self, delay=10): 
    5355        """Run a delayed preview item scan update. 
     
    7173            try: 
    7274                iter_scan.next() 
    73                 QTimer.singleShot(delay, process_one) 
    7475            except StopIteration: 
    75                 pass 
     76                self.__timer.timeout.disconnect(process_one) 
     77                self.__timer.stop() 
    7678 
    77         QTimer.singleShot(delay, process_one) 
     79        self.__timer.timeout.connect(process_one) 
     80        self.__timer.start(delay) 
    7881 
    7982 
  • Orange/OrangeCanvas/registry/__init__.py

    r11368 r11418  
    11""" 
     2======== 
     3Registry 
     4======== 
     5 
    26The registry module implements discovery and description of the widgets 
    37that are available/installed. The :class:`WidgetRegistry` is a repository 
  • Orange/OrangeCanvas/registry/base.py

    r11368 r11418  
    11""" 
    2 WidgetRegistry Base 
     2=============== 
     3Widget Registry 
     4=============== 
    35 
    46""" 
     
    2022    """ 
    2123    A container for widget and category descriptions. 
    22  
    23     This class is most often used with WidgetDiscovery class but can 
    24     be used separately. 
    2524 
    2625    >>> reg = WidgetRegistry() 
     
    3837        If supplied the registry is initialized with the contents of `other`. 
    3938 
     39    See also 
     40    -------- 
     41    WidgetDiscovery 
     42 
    4043    """ 
    4144 
     
    4346        # A list of (category, widgets_list) tuples ordered by priority. 
    4447        self.registry = [] 
     48 
    4549        # tuples from 'registry' indexed by name 
    4650        self._categories_dict = {} 
    47         # WidgetDscriptions by qualified name 
     51 
     52        # WidgetDecriptions by qualified name 
    4853        self._widgets_dict = {} 
    4954 
     
    6065        """ 
    6166        Return a list all top level :class:`CategoryDescription` instances 
    62         ordered by priority. 
     67        ordered by `priority`. 
    6368 
    6469        """ 
     
    6772    def category(self, name): 
    6873        """ 
    69         Find a :class:`CategoryDescription` by its `name`. 
     74        Find and return a :class:`CategoryDescription` by its `name`. 
    7075 
    7176        .. note:: Categories are identified by `name` attribute in contrast 
     
    8287    def has_category(self, name): 
    8388        """ 
    84         Does a category with `name` exist in this registry. 
     89        Return ``True`` if a category with `name` exist in this registry. 
    8590 
    8691        Parameters 
     
    130135            Widget description qualified name 
    131136 
    132         See also 
    133         -------- 
    134         WidgetDescription 
    135  
    136137        """ 
    137138        return self._widgets_dict[qualified_name] 
     
    139140    def has_widget(self, qualified_name): 
    140141        """ 
    141         Does the widget with `qualified_name` exist in this registry. 
     142        Return ``True`` if the widget with `qualified_name` exists in 
     143        this registry. 
     144 
    142145        """ 
    143146        return qualified_name in self._widgets_dict 
  • Orange/OrangeCanvas/registry/description.py

    r11368 r11418  
    5353 
    5454class InputSignal(object): 
    55     """Description of an input channel. 
     55    """ 
     56    Description of an input channel. 
    5657 
    5758    Parameters 
     
    116117 
    117118class OutputSignal(object): 
    118     """Description of an output channel. 
     119    """ 
     120    Description of an output channel. 
    119121 
    120122    Parameters 
     
    182184 
    183185class WidgetDescription(object): 
    184     """Description of a widget. 
     186    """ 
     187    Description of a widget. 
    185188 
    186189    Parameters 
     
    207210    project_name : str, optional 
    208211        The distribution name that provides the widget. 
    209     inputs : list of `InputSignal`, optional 
     212    inputs : list of :class:`InputSignal`, optional 
    210213        A list of input channels provided by the widget. 
    211     outputs : list of `OutputSignal`, optional 
     214    outputs : list of :class:`OutputSignal`, optional 
    212215        A list of output channels provided by the widget. 
    213216    help : str, optional 
     
    285288    @classmethod 
    286289    def from_file(cls, filename, import_name=None): 
    287         """Widget description from old style (2.5 version) widget 
     290        """ 
     291        Widget description from old style (2.5 version) widget 
    288292        descriptions. 
    289293 
     
    355359    @classmethod 
    356360    def from_module(cls, module): 
    357         """Get the widget description from a module. 
     361        """ 
     362        Get the widget description from a module. 
    358363 
    359364        The module is inspected for global variables (upper case versions of 
     
    449454 
    450455class CategoryDescription(object): 
    451     """Description of a widget category. 
     456    """ 
     457    Description of a widget category. 
    452458 
    453459    Parameters 
     
    456462    name : str 
    457463        A human readable name. 
    458     version : str 
    459         Version string (optional). 
    460     description : str 
    461         A short description of the category, suitable for a tool 
    462         tip (optional). 
    463     long_description : str 
     464    version : str, optional 
     465        Version string. 
     466    description : str, optional 
     467        A short description of the category, suitable for a tool tip. 
     468    long_description : str, optional 
    464469        A longer description. 
    465     qualified_name : str 
     470    qualified_name : str, 
    466471        Qualified name 
    467472    project_name : str 
     
    470475        Priority (order in the GUI). 
    471476    icon : str 
    472         An icon filename 
     477        An icon filename (a resource name retrievable using `pkg_resources` 
     478        relative to `qualified_name`). 
    473479    background : str 
    474480        An background color for widgets in this category. 
     
    512518    @classmethod 
    513519    def from_package(cls, package): 
    514         """Get the CategoryDescription from a package. 
     520        """ 
     521        Get the CategoryDescription from a package. 
    515522 
    516523        Parameters 
  • Orange/OrangeCanvas/scheme/__init__.py

    r11367 r11419  
    66The scheme package implements and defines the underlying workflow model. 
    77 
    8 The :class:`Scheme` class represents the workflow and is composed of a set 
    9 of :class:`SchemeNode` connected with :class:`SchemeLink`, defining an 
     8The :class:`.Scheme` class represents the workflow and is composed of a set 
     9of :class:`.SchemeNode` connected with :class:`.SchemeLink`, defining an 
    1010directed acyclic graph (DAG). Additionally instances of 
    11 :class:`SchemeArrowAnnotation` or :class:`SchemeTextAnnotation` can be 
     11:class:`.SchemeArrowAnnotation` or :class:`.SchemeTextAnnotation` can be 
    1212inserted into the scheme. 
    1313 
  • Orange/OrangeCanvas/scheme/link.py

    r11367 r11419  
    7171    """ 
    7272 
     73    #: The link enabled state has changed 
    7374    enabled_changed = Signal(bool) 
     75 
     76    #: The link dynamic enabled state has changed. 
    7477    dynamic_enabled_changed = Signal(bool) 
    7578 
  • Orange/OrangeCanvas/scheme/node.py

    r11367 r11419  
    8080                         (name, self.description.name)) 
    8181 
    82     # The title of the node has changed 
     82    #: The title of the node has changed 
    8383    title_changed = Signal(unicode) 
    8484 
     
    9393    def title(self): 
    9494        """ 
    95         Return the node title. 
     95        The node title. 
    9696        """ 
    9797        return self.__title 
     
    9999    title = Property(unicode, fset=set_title, fget=title) 
    100100 
    101     # Position of the node in the scheme has changed 
     101    #: Position of the node in the scheme has changed 
    102102    position_changed = Signal(tuple) 
    103103 
     
    118118    position = Property(tuple, fset=set_position, fget=position) 
    119119 
    120     # Node's progress value has changed. 
     120    #: Node's progress value has changed. 
    121121    progress_changed = Signal(float) 
    122122 
     
    131131    def progress(self): 
    132132        """ 
    133         Return the current progress value. -1 if progress is not set. 
     133        The current progress value. -1 if progress is not set. 
    134134        """ 
    135135        return self.__progress 
     
    137137    progress = Property(float, fset=set_progress, fget=progress) 
    138138 
    139     # Node's processing state has changed. 
     139    #: Node's processing state has changed. 
    140140    processing_state_changed = Signal(int) 
    141141 
     
    150150    def processing_state(self): 
    151151        """ 
    152         Return the node processing state, 0 for not processing, 1 the 
    153         node is busy. 
    154  
     152        The node processing state, 0 for not processing, 1 the node is busy. 
    155153        """ 
    156154        return self.__processing_state 
  • Orange/OrangeCanvas/scheme/scheme.py

    r11391 r11419  
    3030from .readwrite import scheme_to_ows_stream, parse_scheme 
    3131 
    32 from ..registry import WidgetDescription 
     32from ..registry import WidgetDescription, InputSignal, OutputSignal 
    3333 
    3434log = logging.getLogger(__name__) 
     
    201201        See also 
    202202        -------- 
    203         SchemeNode, Scheme.add_node 
     203        .SchemeNode, Scheme.add_node 
    204204 
    205205        """ 
     
    275275                 sink_node, sink_channel): 
    276276        """ 
    277         Create a new SchemeLink and add it to the scheme. 
    278  
    279         Same as:: 
    280  
    281             scheme.add_link(SchemeLink(source_node, source_channel, 
    282                                        sink_node, sink_channel)) 
     277        Create a new :class:`.SchemeLink` from arguments and add it to 
     278        the scheme. The new link is returned. 
    283279 
    284280        Parameters 
     
    286282        source_node : :class:`.SchemeNode` 
    287283            Source node of the new link. 
    288         source_channel : :class:`OutputSignal` 
     284        source_channel : :class:`.OutputSignal` 
    289285            Source channel of the new node. The instance must be from 
    290             `source_node.output_channels()` 
     286            ``source_node.output_channels()`` 
    291287        sink_node : :class:`.SchemeNode` 
    292288            Sink node of the new link. 
    293         sink_channel : :class:`InputSignal` 
     289        sink_channel : :class:`.InputSignal` 
    294290            Sink channel of the new node. The instance must be from 
    295             `sink_node.input_channels()` 
     291            ``sink_node.input_channels()`` 
    296292 
    297293        See also 
    298294        -------- 
    299         SchemeLink, Scheme.add_link 
     295        .SchemeLink, Scheme.add_link 
    300296 
    301297        """ 
     
    328324    def check_connect(self, link): 
    329325        """ 
    330         Check if the `link` can be added to the scheme. 
     326        Check if the `link` can be added to the scheme and raise an 
     327        appropriate exception. 
    331328 
    332329        Can raise: 
    333330            - :class:`TypeError` if `link` is not an instance of 
    334331              :class:`.SchemeLink` 
    335             - :class:`SchemeCycleError` if the `link` would introduce a cycle 
    336             - :class:`IncompatibleChannelTypeError` if the channel types are 
     332            - :class:`.SchemeCycleError` if the `link` would introduce a cycle 
     333            - :class:`.IncompatibleChannelTypeError` if the channel types are 
    337334              not compatible 
    338             - :class:`SinkChannelError` if a sink channel has a `Single` flag 
     335            - :class:`.SinkChannelError` if a sink channel has a `Single` flag 
    339336              specification and the channel is already connected. 
    340             - :class:`DuplicatedLinkError` if a `link` duplicates an already 
     337            - :class:`.DuplicatedLinkError` if a `link` duplicates an already 
    341338              present link. 
    342339 
     
    375372    def creates_cycle(self, link): 
    376373        """ 
    377         Would the `link` if added to the scheme introduce a cycle. 
     374        Return `True` if `link` would introduce a cycle in the scheme. 
     375 
     376        Parameters 
     377        ---------- 
     378        link : :class:`.SchemeLink` 
     379 
    378380        """ 
    379381        check_type(link, SchemeLink) 
     
    385387    def compatible_channels(self, link): 
    386388        """ 
    387         Do the channels in `link` have compatible types. 
     389        Return `True` if the channels in `link` have compatible types. 
     390 
     391        Parameters 
     392        ---------- 
     393        link : :class:`.SchemeLink` 
     394 
    388395        """ 
    389396        check_type(link, SchemeLink) 
     
    391398 
    392399    def can_connect(self, link): 
     400        """ 
     401        Return `True` if `link` can be added to the scheme. 
     402 
     403        See also 
     404        -------- 
     405        Scheme.check_connect 
     406 
     407        """ 
     408        check_type(link, SchemeLink) 
    393409        try: 
    394410            self.check_connect(link) 
    395411            return True 
    396         except (SchemeCycleError, IncompatibleChannelTypeError): 
     412        except (SchemeCycleError, IncompatibleChannelTypeError, 
     413                SinkChannelError, DuplicatedLinkError): 
    397414            return False 
    398         except Exception: 
    399             raise 
    400415 
    401416    def upstream_nodes(self, start_node): 
    402417        """ 
    403         Return a set of all nodes upstream from `start_node`. 
     418        Return a set of all nodes upstream from `start_node` (i.e. 
     419        all ancestor nodes). 
     420 
     421        Parameters 
     422        ---------- 
     423        start_node : :class:`.SchemeNode` 
     424 
    404425        """ 
    405426        visited = set() 
     
    419440        """ 
    420441        Return a set of all nodes downstream from `start_node`. 
     442 
     443        Parameters 
     444        ---------- 
     445        start_node : :class:`.SchemeNode` 
     446 
    421447        """ 
    422448        visited = set() 
     
    438464        of the child in the workflow). Both nodes must be in the scheme. 
    439465 
     466        Parameters 
     467        ---------- 
     468        node : :class:`.SchemeNode` 
     469        child : :class:`.SchemeNode` 
     470 
    440471        """ 
    441472        return child in self.downstream_nodes(node) 
     
    455486    def input_links(self, node): 
    456487        """ 
    457         Return all input links connected to the `node` instance. 
     488        Return a list of all input links (:class:`.SchemeLink`) connected 
     489        to the `node` instance. 
     490 
    458491        """ 
    459492        return self.find_links(sink_node=node) 
     
    461494    def output_links(self, node): 
    462495        """ 
    463         Return all output links connected to the `node` instance. 
     496        Return a list of all output links (:class:`.SchemeLink`) connected 
     497        to the `node` instance. 
     498 
    464499        """ 
    465500        return self.find_links(source_node=node) 
  • Orange/OrangeCanvas/scheme/widgetsscheme.py

    r11391 r11411  
    5050        self.node_for_widget = {} 
    5151        self.signal_manager = WidgetsSignalManager(self) 
     52        self.signal_manager.processingStarted[SchemeNode].connect( 
     53            self.__on_processing_started 
     54        ) 
     55        self.signal_manager.processingFinished[SchemeNode].connect( 
     56            self.__on_processing_finished 
     57        ) 
    5258 
    5359    def add_node(self, node): 
     
    6470        # widget_for_node, etc. to be up to date. 
    6571        widget = self.create_widget_instance(node) 
    66  
    6772        Scheme.add_node(self, node) 
    6873 
     
    199204            QCoreApplication.sendEvent(self, event) 
    200205 
     206    def __on_processing_started(self, node): 
     207        node.set_processing_state(1) 
     208 
     209    def __on_processing_finished(self, node): 
     210        node.set_processing_state(0) 
     211 
    201212 
    202213class WidgetsSignalManager(SignalManager): 
  • Orange/OrangeCanvas/styles/orange.qss

    r11352 r11412  
    300300 
    301301PreviewDialog PreviewBrowser TextLabel#path-text { 
    302     font-size: 12px; 
     302    font-size: 12px; 
    303303} 
    304304 
    305305PreviewDialog PreviewBrowser QLabel#path-label { 
    306     font-size: 12px; 
     306    font-size: 12px; 
     307} 
     308 
     309PreviewDialog DropShadowFrame { 
     310    qproperty-radius_: 10; 
     311    qproperty-color_: rgb(0, 0, 0, 100); 
    307312} 
    308313 
  • docs/canvas/document.rst

    r11390 r11420  
    99 
    1010   document.schemeedit 
     11   document.quickmenu 
  • docs/canvas/scheme.link.rst

    r11367 r11419  
    1010.. autoclass:: SchemeLink 
    1111   :members: 
     12   :exclude-members: 
     13      enabled_changed, 
     14      dynamic_enabled_changed 
    1215   :member-order: bysource 
    1316   :show-inheritance: 
     17 
     18   .. autoattribute:: enabled_changed(enabled) 
     19 
     20   .. autoattribute:: dynamic_enabled_changed(enabled) 
  • docs/canvas/scheme.node.rst

    r11367 r11419  
    1010.. autoclass:: SchemeNode 
    1111   :members: 
     12   :exclude-members: 
     13      title_changed, 
     14      position_changed, 
     15      progress_changed, 
     16      processing_state_changed 
    1217   :member-order: bysource 
    1318   :show-inheritance: 
     
    1621 
    1722   .. autoattribute:: position_changed((x, y)) 
     23 
     24   .. autoattribute:: progress_changed(progress) 
     25 
     26   .. autoattribute:: processing_state_changed(state) 
  • docs/canvas/scheme.scheme.rst

    r11367 r11419  
    4343 
    4444      Signal emitted when a `annotation` is removed from the scheme. 
     45 
     46 
     47.. autoclass:: SchemeCycleError 
     48   :show-inheritance: 
     49 
     50 
     51.. autoclass:: IncompatibleChannelTypeError 
     52   :show-inheritance: 
     53 
     54 
     55.. autoclass:: SinkChannelError 
     56   :show-inheritance: 
     57 
     58 
     59.. autoclass:: DuplicatedLinkError 
     60   :show-inheritance: 
Note: See TracChangeset for help on using the changeset viewer.