Ignore:
Timestamp:
11/07/12 18:30:30 (18 months ago)
Author:
Ales Erjavec <ales.erjavec@…>
Branch:
default
Message:

Cleanup of the ToolGrid code and interface.

Moved the add/remove action code to actionEvent handler, also added
more tests.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • Orange/OrangeCanvas/gui/toolgrid.py

    r11176 r11177  
    22Tool Grid Widget. 
    33================ 
     4 
     5A Widget containing a grid of clickable actions/buttons. 
    46 
    57""" 
     
    9799 
    98100    def paintEvent(self, event): 
    99         try: 
    100             p = QStylePainter(self) 
    101             opt = QStyleOptionToolButton() 
    102             self.initStyleOption(opt) 
    103             if self.__text: 
    104                 # Replace the text 
    105                 opt.text = self.__text 
    106             p.drawComplexControl(QStyle.CC_ToolButton, opt) 
    107         except Exception, ex: 
    108             print ex 
     101        p = QStylePainter(self) 
     102        opt = QStyleOptionToolButton() 
     103        self.initStyleOption(opt) 
     104        if self.__text: 
     105            # Replace the text 
     106            opt.text = self.__text 
     107        p.drawComplexControl(QStyle.CC_ToolButton, opt) 
    109108        p.end() 
    110109 
     
    112111class ToolGrid(QWidget): 
    113112    """A widget containing a grid of actions/buttons. 
     113 
     114    Actions can be added using standard QWidget addAction and insertAction 
     115    methods. 
     116 
    114117    """ 
    115118    actionTriggered = Signal(QAction) 
     
    119122                 iconSize=None, toolButtonStyle=Qt.ToolButtonTextUnderIcon): 
    120123        QWidget.__init__(self, parent) 
    121         self.columns = columns 
    122         self.buttonSize = buttonSize or QSize(50, 50) 
    123         self.iconSize = iconSize or QSize(26, 26) 
    124         self.toolButtonStyle = toolButtonStyle 
    125         self._gridSlots = [] 
    126  
    127         self._buttonListener = ToolButtonEventListener(self) 
    128         self._buttonListener.buttonRightClicked.connect( 
    129                 self._onButtonRightClick) 
    130  
    131         self._buttonListener.buttonEnter.connect( 
    132                 self._onButtonEnter) 
     124 
     125        if buttonSize is not None: 
     126            buttonSize = QSize(buttonSize) 
     127 
     128        if iconSize is not None: 
     129            iconSize = QSize(iconSize) 
     130 
     131        self.__columns = columns 
     132        self.__buttonSize = buttonSize or QSize(50, 50) 
     133        self.__iconSize = iconSize or QSize(26, 26) 
     134        self.__toolButtonStyle = toolButtonStyle 
     135 
     136        self.__gridSlots = [] 
     137 
     138        self.__buttonListener = ToolButtonEventListener(self) 
     139        self.__buttonListener.buttonRightClicked.connect( 
     140                self.__onButtonRightClick) 
     141 
     142        self.__buttonListener.buttonEnter.connect( 
     143                self.__onButtonEnter) 
    133144 
    134145        self.__mapper = QSignalMapper() 
    135146        self.__mapper.mapped[QObject].connect(self.__onClicked) 
    136147 
    137         self.setupUi() 
    138  
    139     def setupUi(self): 
     148        self.__setupUi() 
     149 
     150    def __setupUi(self): 
    140151        layout = QGridLayout() 
    141152        layout.setContentsMargins(0, 0, 0, 0) 
     
    148159        """Set the button size. 
    149160        """ 
    150         for slot in self._gridSlots: 
    151             slot.button.setFixedSize(size) 
    152         self.buttonSize = size 
     161        if self.__buttonSize != size: 
     162            self.__buttonSize = size 
     163            for slot in self.__gridSlots: 
     164                slot.button.setFixedSize(size) 
     165 
     166    def buttonSize(self): 
     167        return QSize(self.__buttonSize) 
    153168 
    154169    def setIconSize(self, size): 
    155170        """Set the button icon size. 
    156171        """ 
    157         for slot in self._gridSlots: 
    158             slot.button.setIconSize(size) 
    159         self.iconSize = size 
     172        if self.__iconSize != size: 
     173            self.__iconSize = size 
     174            for slot in self.__gridSlots: 
     175                slot.button.setIconSize(size) 
     176 
     177    def iconSize(self): 
     178        return QSize(self.__iconSize) 
    160179 
    161180    def setToolButtonStyle(self, style): 
    162181        """Set the tool button style. 
    163182        """ 
    164         for slot in self._gridSlots: 
    165             slot.button.setToolButtonStyle(style) 
    166  
    167         self.toolButtonStyle = style 
     183        if self.__toolButtonStyle != style: 
     184            self.__toolButtonStyle = style 
     185            for slot in self.__gridSlots: 
     186                slot.button.setToolButtonStyle(style) 
     187 
     188    def toolButtonStyle(self): 
     189        return self.__toolButtonStyle 
    168190 
    169191    def setColumnCount(self, columns): 
    170192        """Set the number of button/action columns. 
    171193        """ 
    172         if self.columns != columns: 
    173             self.columns = columns 
    174             self._relayout() 
     194        if self.__columns != columns: 
     195            self.__columns = columns 
     196            self.__relayout() 
     197 
     198    def columns(self): 
     199        return self.__columns 
    175200 
    176201    def clear(self): 
    177202        """Clear all actions. 
    178203        """ 
    179         layout = self.layout() 
    180         for slot in self._gridSlots: 
     204        for slot in reversed(list(self.__gridSlots)): 
    181205            self.removeAction(slot.action) 
    182             index = layout.indexOf(slot.button) 
    183             layout.takeAt(index) 
    184             slot.button.deleteLater() 
    185  
    186         self._gridSlots = [] 
    187  
    188     # TODO: Move the add/insert/remove code in actionEvent, preserve the 
    189     # default Qt widget action interface. 
    190  
    191     def addAction(self, action): 
    192         """Append a new action to the ToolGrid. 
    193         """ 
    194         self.insertAction(len(self._gridSlots), action) 
    195  
    196     def insertAction(self, index, action): 
    197         """Insert a new action at index. 
    198         """ 
    199         self._shiftGrid(index, 1) 
     206        self.__gridSlots = [] 
     207 
     208    def insertAction(self, before, action): 
     209        """Insert a new action at the position currently occupied 
     210        by `before` (can also be an index). 
     211 
     212        """ 
     213        if isinstance(before, int): 
     214            actions = list(self.actions()) 
     215            if len(actions) == 0 or before >= len(actions): 
     216                # Insert as the first action of the last action. 
     217                return self.addAction(action) 
     218 
     219            before = actions[before] 
     220 
     221        return QWidget.insertAction(self, before, action) 
     222 
     223    def setActions(self, actions): 
     224        """Clear the grid and add actions. 
     225        """ 
     226        self.clear() 
     227 
     228        for action in actions: 
     229            self.addAction(action) 
     230 
     231    def buttonForAction(self, action): 
     232        """Return the `QToolButton` instance button for `action`. 
     233        """ 
     234        actions = [slot.action for slot in self.__gridSlots] 
     235        index = actions.index(action) 
     236        return self.__gridSlots[index].button 
     237 
     238    def createButtonForAction(self, action): 
     239        """Create and return a QToolButton for action. 
     240        """ 
     241        button = _ToolGridButton(self) 
     242        button.setDefaultAction(action) 
     243 
     244        if self.__buttonSize.isValid(): 
     245            button.setFixedSize(self.__buttonSize) 
     246        if self.__iconSize.isValid(): 
     247            button.setIconSize(self.__iconSize) 
     248 
     249        button.setToolButtonStyle(self.__toolButtonStyle) 
     250        button.setProperty("tool-grid-button", QVariant(True)) 
     251        return button 
     252 
     253    def count(self): 
     254        return len(self.__gridSlots) 
     255 
     256    def actionEvent(self, event): 
     257        QWidget.actionEvent(self, event) 
     258 
     259        if event.type() == QEvent.ActionAdded: 
     260            # Note: the action is already in the self.actions() list. 
     261            actions = list(self.actions()) 
     262            index = actions.index(event.action()) 
     263            self.__insertActionButton(index, event.action()) 
     264 
     265        elif event.type() == QEvent.ActionRemoved: 
     266            self.__removeActionButton(event.action()) 
     267 
     268    def __insertActionButton(self, index, action): 
     269        """Create a button for the action and add it to the layout 
     270        at index. 
     271 
     272        """ 
     273        self.__shiftGrid(index, 1) 
    200274        button = self.createButtonForAction(action) 
    201         row = index / self.columns 
    202         column = index % self.columns 
     275 
     276        row = index / self.__columns 
     277        column = index % self.__columns 
     278 
    203279        self.layout().addWidget( 
    204280            button, row, column, 
    205281            Qt.AlignLeft | Qt.AlignTop 
    206282        ) 
    207         self._gridSlots.insert( 
     283 
     284        self.__gridSlots.insert( 
    208285            index, _ToolGridSlot(button, action, row, column) 
    209286        ) 
     
    211288        self.__mapper.setMapping(button, action) 
    212289        button.clicked.connect(self.__mapper.map) 
    213         button.installEventFilter(self._buttonListener) 
     290        button.installEventFilter(self.__buttonListener) 
    214291        button.installEventFilter(self) 
    215292 
    216     def setActions(self, actions): 
    217         """Clear the grid and add actions. 
    218         """ 
    219         self.clear() 
    220  
    221         for action in actions: 
    222             self.addAction(action) 
    223  
    224     def removeAction(self, action): 
    225         """Remove action from the widget. 
    226         """ 
    227         actions = [slot.action for slot in self._gridSlots] 
     293    def __removeActionButton(self, action): 
     294        """Remove the button for the action from the layout and delete it. 
     295        """ 
     296        actions = [slot.action for slot in self.__gridSlots] 
    228297        index = actions.index(action) 
    229         slot = self._gridSlots.pop(index) 
    230  
    231         slot.button.removeEventFilter(self._buttonListener) 
     298        slot = self.__gridSlots.pop(index) 
     299 
     300        slot.button.removeEventFilter(self.__buttonListener) 
     301        slot.button.removeEventFilter(self) 
    232302        self.__mapper.removeMappings(slot.button) 
    233303 
    234304        self.layout().removeWidget(slot.button) 
    235         self._shiftGrid(index + 1, -1) 
     305        self.__shiftGrid(index + 1, -1) 
    236306 
    237307        slot.button.deleteLater() 
    238308 
    239     def buttonForAction(self, action): 
    240         """Return the `QToolButton` instance button for `action`. 
    241         """ 
    242         actions = [slot.action for slot in self._gridSlots] 
    243         index = actions.index(action) 
    244         return self._gridSlots[index].button 
    245  
    246     def createButtonForAction(self, action): 
    247         """Create and return a QToolButton for action. 
    248         """ 
    249 #        button = QToolButton(self) 
    250         button = _ToolGridButton(self) 
    251         button.setDefaultAction(action) 
    252 #        button.setText(action.text()) 
    253 #        button.setIcon(action.icon()) 
    254  
    255         if self.buttonSize.isValid(): 
    256             button.setFixedSize(self.buttonSize) 
    257         if self.iconSize.isValid(): 
    258             button.setIconSize(self.iconSize) 
    259  
    260         button.setToolButtonStyle(self.toolButtonStyle) 
    261         button.setProperty("tool-grid-button", QVariant(True)) 
    262         return button 
    263  
    264     def count(self): 
    265         return len(self._gridSlots) 
    266  
    267     def _shiftGrid(self, start, count=1): 
     309    def __shiftGrid(self, start, count=1): 
    268310        """Shift all buttons starting at index `start` by `count` cells. 
    269311        """ 
     
    276318 
    277319        for index in range(start, end, -direction): 
    278             item = self.layout().itemAtPosition(index / self.columns, 
    279                                                 index % self.columns) 
     320            item = self.layout().itemAtPosition(index / self.__columns, 
     321                                                index % self.__columns) 
    280322            if item: 
    281323                button = item.widget() 
    282324                new_index = index + count 
    283                 self.layout().addWidget(button, new_index / self.columns, 
    284                                         new_index % self.columns, 
     325                self.layout().addWidget(button, new_index / self.__columns, 
     326                                        new_index % self.__columns, 
    285327                                        Qt.AlignLeft | Qt.AlignTop) 
    286328 
    287     def _relayout(self): 
     329    def __relayout(self): 
    288330        """Relayout the buttons. 
    289331        """ 
     
    291333            self.layout().takeAt(i) 
    292334 
    293         self._gridSlots = [_ToolGridSlot(slot.button, slot.action, 
    294                                          i / self.columns, i % self.columns) 
    295                            for i, slot in enumerate(self._gridSlots)] 
    296  
    297         for slot in self._gridSlots: 
     335        self.__gridSlots = [_ToolGridSlot(slot.button, slot.action, 
     336                                          i / self.__columns, 
     337                                          i % self.__columns) 
     338                            for i, slot in enumerate(self.__gridSlots)] 
     339 
     340        for slot in self.__gridSlots: 
    298341            self.layout().addWidget(slot.button, slot.row, slot.column, 
    299342                                    Qt.AlignLeft | Qt.AlignTop) 
    300343 
    301     def _indexOf(self, button): 
     344    def __indexOf(self, button): 
    302345        """Return the index of button widget. 
    303346        """ 
    304         buttons = [slot.button for slot in self._gridSlots] 
     347        buttons = [slot.button for slot in self.__gridSlots] 
    305348        return buttons.index(button) 
    306349 
    307     def _onButtonRightClick(self, button): 
     350    def __onButtonRightClick(self, button): 
    308351        print button 
    309352 
    310     def _onButtonEnter(self, button): 
     353    def __onButtonEnter(self, button): 
    311354        action = button.defaultAction() 
    312355        self.actionHovered.emit(action) 
     
    332375        assert(focus is self.focusWidget()) 
    333376        try: 
    334             index = self._indexOf(focus) 
     377            index = self.__indexOf(focus) 
    335378        except IndexError: 
    336379            return False 
    337380 
    338381        if key == Qt.Key_Down: 
    339             index += self.columns 
     382            index += self.__columns 
    340383        elif key == Qt.Key_Up: 
    341             index -= self.columns 
     384            index -= self.__columns 
    342385        elif key == Qt.Key_Left: 
    343386            index -= 1 
     
    346389 
    347390        if index >= 0 and index < self.count(): 
    348             button = self._gridSlots[index].button 
     391            button = self.__gridSlots[index].button 
    349392            button.setFocus(Qt.TabFocusReason) 
    350393            return True 
Note: See TracChangeset for help on using the changeset viewer.