Changeset 11180:c0e3d8cdbd08 in orange


Ignore:
Timestamp:
11/12/12 20:04:40 (17 months ago)
Author:
Ales Erjavec <ales.erjavec@…>
Branch:
default
Message:

Added link AnchorLayout class.

Location:
Orange/OrangeCanvas/canvas
Files:
2 added
4 edited

Legend:

Unmodified
Added
Removed
  • Orange/OrangeCanvas/canvas/items/nodeitem.py

    r11153 r11180  
    487487 
    488488def linspace(count): 
    489     return map(float, 
    490                numpy.linspace(0.0, 1.0, count + 2, endpoint=True)[1:-1]) 
     489    return map(float, numpy.linspace(0.0, 1.0, count + 2, endpoint=True)[1:-1]) 
    491490 
    492491 
     
    527526        self.inputAnchorItem = None 
    528527        self.outputAnchorItem = None 
    529  
    530         # round anchor indicators on the anchor path 
    531 #        self.inputAnchors = [] 
    532 #        self.outputAnchors = [] 
    533528 
    534529        # title text item 
  • Orange/OrangeCanvas/canvas/items/utils.py

    r11172 r11180  
    11import numpy 
    22 
    3 from PyQt4.QtGui import QColor, QRadialGradient, QGraphicsItem 
     3import sip 
     4 
     5from PyQt4.QtGui import QColor, QRadialGradient 
     6from PyQt4.QtCore import QObject, QSignalMapper 
     7from PyQt4.QtCore import pyqtSignal as Signal 
    48 
    59 
     
    5458    obj = item.toGraphicsObject() 
    5559    return item if obj is None else obj 
     60 
     61 
     62def typed_signal_mapper(pyType): 
     63    """Create a TypedSignalMapper class supporting signal 
     64    mapping for `pyType` (the default QSigalMapper only supports 
     65    int, string, QObject and QWidget (but not for instance QGraphicsItem). 
     66 
     67    """ 
     68 
     69    def unwrap(obj): 
     70        return sip.unwrapinstance(sip.cast(obj, QObject)) 
     71 
     72    class TypedSignalMapper(QSignalMapper): 
     73        pyMapped = Signal(pyType) 
     74 
     75        def __init__(self, parent=None): 
     76            QSignalMapper.__init__(self, parent) 
     77            self.__mapping = {} 
     78 
     79        def setPyMapping(self, sender, mapped): 
     80            sender_id = unwrap(sender) 
     81            self.__mapping[sender_id] = mapped 
     82            sender.destroyed.connect(self.removePyMappings) 
     83 
     84        def removePyMappings(self, sender): 
     85            sender_id = unwrap(sender) 
     86            del self.__mapping[sender_id] 
     87            sender.destroyed.disconnect(self.removePyMappings) 
     88 
     89        def pyMap(self, sender=None): 
     90            if sender is None: 
     91                sender = self.sender() 
     92 
     93            sender_id = unwrap(sender) 
     94            mapped = self.__mapping[sender_id] 
     95            self.pyMapped.emit(mapped) 
     96 
     97    return TypedSignalMapper 
  • Orange/OrangeCanvas/canvas/scene.py

    r11172 r11180  
    55 
    66import logging 
     7from operator import attrgetter 
    78 
    89from PyQt4.QtGui import QGraphicsScene, QPainter, QBrush, \ 
    910                        QGraphicsItem 
    1011 
    11 from PyQt4.QtCore import Qt, QObject, QPointF, QRectF, QSizeF, QLineF, \ 
    12                          QBuffer, QSignalMapper 
     12from PyQt4.QtCore import Qt, QPointF, QRectF, QSizeF, QLineF, QBuffer 
    1313 
    1414from PyQt4.QtCore import pyqtSignal as Signal 
    1515from PyQt4.QtCore import PYQT_VERSION_STR 
    1616 
    17 import sip 
    1817 
    1918from .. import scheme 
    2019 
    2120from . import items 
    22 from .items.utils import toGraphicsObjectIfPossible 
     21from .layout import AnchorLayout 
     22from .items.utils import toGraphicsObjectIfPossible, typed_signal_mapper 
    2323 
    2424log = logging.getLogger(__name__) 
    25  
    26  
    27 def typed_signal_mapper(pyType): 
    28     """Create a TypedSignalMapper class supporting signal 
    29     mapping for `pyType` (the default QSigalMapper only supports 
    30     int, string, QObject and QWidget (but not for instance QGraphicsItem). 
    31  
    32     """ 
    33  
    34     def unwrap(obj): 
    35         return sip.unwrapinstance(sip.cast(obj, QObject)) 
    36  
    37     class TypedSignalMapper(QSignalMapper): 
    38         pyMapped = Signal(pyType) 
    39  
    40         def __init__(self, parent=None): 
    41             QSignalMapper.__init__(self, parent) 
    42             self.__mapping = {} 
    43  
    44         def setPyMapping(self, sender, mapped): 
    45             sender_id = unwrap(sender) 
    46             self.__mapping[sender_id] = mapped 
    47             sender.destroyed.connect(self.removePyMappings) 
    48  
    49         def removePyMappings(self, sender): 
    50             sender_id = unwrap(sender) 
    51             del self.__mapping[sender_id] 
    52             sender.destroyed.disconnect(self.removePyMappings) 
    53  
    54         def pyMap(self, sender=None): 
    55             if sender is None: 
    56                 sender = self.sender() 
    57  
    58             sender_id = unwrap(sender) 
    59             mapped = self.__mapping[sender_id] 
    60             self.pyMapped.emit(mapped) 
    61  
    62     return TypedSignalMapper 
    6325 
    6426 
     
    12688        self.editable = True 
    12789 
     90        # Anchor Layout 
     91        self.__anchor_layout = AnchorLayout() 
     92        self.addItem(self.__anchor_layout) 
     93 
    12894        self.user_interaction_handler = None 
    12995 
     
    151117        self.__link_items = [] 
    152118        self.__item_for_link = {} 
     119        self.__annotation_items = [] 
     120        self.__item_for_annotation = {} 
     121 
     122        self.__anchor_layout.deleteLater() 
    153123 
    154124        self.user_interaction_handler = None 
     
    219189        self.registry = registry 
    220190 
     191    def set_anchor_layout(self, layout): 
     192        if self.__anchor_layout != layout: 
     193            if self.__anchor_layout: 
     194                self.__anchor_layout.deleteLater() 
     195                self.__anchor_layout = None 
     196 
     197            self.__anchor_layout = layout 
     198 
     199    def anchor_layout(self): 
     200        return self.__anchor_layout 
     201 
    221202    def add_node_item(self, item): 
    222203        """Add a :class:`NodeItem` instance to the scene. 
     
    343324        log.info("Added link %r -> %r to '%s'" % \ 
    344325                 (item.sourceItem.title, item.sinkItem.title, self)) 
     326 
     327        self.__anchor_layout.invalidateLink(item) 
    345328 
    346329        return item 
     
    553536        return [item for item in self.__annotation_items if item.isSelected()] 
    554537 
     538    def node_links(self, node_item): 
     539        """Return all links from the `node_item` (:class:`NodeItem`). 
     540        """ 
     541        return self.node_output_links(node_item) + \ 
     542               self.node_input_links(node_item) 
     543 
     544    def node_output_links(self, node_item): 
     545        """Return a list of all output links from `node_item`. 
     546        """ 
     547        return [link for link in self.__link_items 
     548                if link.sourceItem == node_item] 
     549 
     550    def node_input_links(self, node_item): 
     551        """Return a list of all input links for `node_item`. 
     552        """ 
     553        return [link for link in self.__link_items 
     554                if link.sinkItem == node_item] 
     555 
     556    def neighbor_nodes(self, node_item): 
     557        """Return a list of `node_item`'s (class:`NodeItem`) neighbor nodes. 
     558        """ 
     559        neighbors = map(attrgetter("sourceItem"), 
     560                        self.node_input_links(node_item)) 
     561 
     562        neighbors.extend(map(attrgetter("sinkItem"), 
     563                             self.node_output_links(node_item))) 
     564        return neighbors 
     565 
    555566    def on_widget_state_change(self, widget, state): 
    556567        pass 
     
    563574 
    564575    def _on_position_change(self, item): 
     576        # Invalidate the anchor point layout and schedule a layout. 
     577        self.__anchor_layout.invalidateNode(item) 
     578 
    565579        self.node_item_position_changed.emit(item, item.pos()) 
    566580 
  • Orange/OrangeCanvas/canvas/tests/test_scene.py

    r11138 r11180  
    233233 
    234234        return file_desc, discretize_desc, bayes_desc 
    235  
Note: See TracChangeset for help on using the changeset viewer.