Ignore:
Location:
Orange/OrangeCanvas
Files:
4 edited

Legend:

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

    r11496 r11502  
    1717    QFileDialog, QMessageBox, QVBoxLayout, QSizePolicy, QColor, QKeySequence, 
    1818    QIcon, QToolBar, QToolButton, QDockWidget, QDesktopServices, QApplication, 
    19     QCursor 
    2019) 
    2120 
     
    4241 
    4342from .canvastooldock import CanvasToolDock, QuickCategoryToolbar, \ 
    44                             CategoryPopupMenu 
     43                            CategoryPopupMenu, popup_position_from_source 
    4544from .aboutdialog import AboutDialog 
    4645from .schemeinfo import SchemeInfoDialog 
     
    773772        if self.use_popover: 
    774773            # Show a popup menu with the widgets in the category 
    775             m = CategoryPopupMenu(self.quick_category) 
     774            popup = CategoryPopupMenu(self.quick_category) 
    776775            reg = self.widget_registry.model() 
    777776            i = index(self.widget_registry.categories(), category, 
    778777                      predicate=lambda name, cat: cat.name == name) 
    779778            if i != -1: 
    780                 m.setCategoryItem(reg.item(i)) 
    781                 action = m.exec_(QCursor.pos()) 
     779                popup.setCategoryItem(reg.item(i)) 
     780                button = self.quick_category.buttonForAction(action) 
     781                pos = popup_position_from_source(popup, button) 
     782                action = popup.exec_(pos) 
    782783                if action is not None: 
    783784                    self.on_tool_box_widget_activated(action) 
  • Orange/OrangeCanvas/application/canvastooldock.py

    r11495 r11502  
    1111 
    1212from PyQt4.QtCore import ( 
    13     Qt, QSize, QObject, QPropertyAnimation, QEvent, QRect, 
     13    Qt, QSize, QObject, QPropertyAnimation, QEvent, QRect, QPoint, 
    1414    QModelIndex, QPersistentModelIndex, QEventLoop, QMimeData 
    1515) 
     
    536536 
    537537    return geom 
     538 
     539 
     540def popup_position_from_source(popup, source, orientation=Qt.Vertical): 
     541    popup.ensurePolished() 
     542    source.ensurePolished() 
     543 
     544    if popup.testAttribute(Qt.WA_Resized): 
     545        size = popup.size() 
     546    else: 
     547        size = popup.sizeHint() 
     548 
     549    desktop = QApplication.desktop() 
     550    screen_geom = desktop.availableGeometry(source) 
     551    source_rect = QRect(source.mapToGlobal(QPoint(0, 0)), source.size()) 
     552 
     553    if orientation == Qt.Vertical: 
     554        if source_rect.right() + size.width() < screen_geom.width(): 
     555            x = source_rect.right() 
     556        else: 
     557            x = source_rect.left() - size.width() 
     558 
     559        # bottom overflow 
     560        dy = source_rect.top() + size.height() - screen_geom.height() 
     561        if dy < 0: 
     562            y = source_rect.top() 
     563        else: 
     564            y = source_rect.top() - dy 
     565    else: 
     566        # right overflow 
     567        dx = source_rect.left() + size.width() - screen_geom.width() 
     568        if dx < 0: 
     569            x = source_rect.left() 
     570        else: 
     571            x = source_rect.left() - dx 
     572 
     573        if source_rect.bottom() + size.height() < screen_geom.height(): 
     574            y = source_rect.bottom() 
     575        else: 
     576            y = source_rect.top() - size.height() 
     577 
     578    return QPoint(x, y) 
  • Orange/OrangeCanvas/document/quickmenu.py

    r11494 r11501  
    2121    QStandardItemModel, QSortFilterProxyModel, QStyleOptionToolButton, 
    2222    QStylePainter, QStyle, QApplication, QStyledItemDelegate, 
    23     QStyleOptionViewItemV4, QSizeGrip 
     23    QStyleOptionViewItemV4, QSizeGrip, QCursor, QPolygon, QRegion 
    2424) 
    2525 
     
    2828 
    2929from PyQt4.QtCore import ( 
    30     Qt, QObject, QPoint, QSize, QRect, QEventLoop, QEvent, QModelIndex 
     30    Qt, QObject, QPoint, QSize, QRect, QEventLoop, QEvent, QModelIndex, 
     31    QTimer 
    3132) 
    3233 
     
    153154    def sizeHint(self): 
    154155        view = self.view() 
    155         hint = view.sizeHint() 
    156156        model = view.model() 
    157157 
     
    165165            height = height * count 
    166166        else: 
    167             height = hint.height() 
    168         return QSize(max(width, hint.width()), max(height, hint.height())) 
     167            height = 0 
     168        return QSize(width, height) 
    169169 
    170170 
     
    359359 
    360360        self.__flat = True 
     361        self.__showMenuIndicator = False 
    361362 
    362363    def setFlat(self, flat): 
     
    371372                     designable=True) 
    372373 
     374    def setShownMenuIndicator(self, show): 
     375        if self.__showMenuIndicator != show: 
     376            self.__showMenuIndicator = show 
     377            self.update() 
     378 
     379    def showMenuIndicator(self): 
     380        return self.__showMenuIndicator 
     381 
     382    showMenuIndicator_ = Property(bool, fget=showMenuIndicator, 
     383                                  fset=setShownMenuIndicator, 
     384                                  designable=True) 
     385 
    373386    def paintEvent(self, event): 
    374387        opt = QStyleOptionToolButton() 
    375388        self.initStyleOption(opt) 
    376         opt.features |= QStyleOptionToolButton.HasMenu 
     389        if self.__showMenuIndicator and self.isChecked(): 
     390            opt.features |= QStyleOptionToolButton.HasMenu 
    377391        if self.__flat: 
    378392            # Use default widget background/border styling. 
     
    388402        opt = QStyleOptionToolButton() 
    389403        self.initStyleOption(opt) 
    390         opt.features |= QStyleOptionToolButton.HasMenu 
     404        if self.__showMenuIndicator and self.isChecked(): 
     405            opt.features |= QStyleOptionToolButton.HasMenu 
    391406        style = self.style() 
    392407 
     
    434449            self.__onButtonPressed 
    435450        ) 
    436  
    437         self.__hoverListener = ToolButtonEventListener(self) 
     451        self.setMouseTracking(True) 
     452 
     453        self.__sloppyButton = None 
     454        self.__sloppyRegion = QRegion() 
     455        self.__sloppyTimer = QTimer(self, singleShot=True) 
     456        self.__sloppyTimer.timeout.connect(self.__onSloppyTimeout) 
    438457 
    439458    def setChangeOnHover(self, changeOnHover): 
     
    445464        if self.__changeOnHover != changeOnHover: 
    446465            self.__changeOnHover = changeOnHover 
    447  
    448             if changeOnHover: 
    449                 self.__hoverListener.buttonEnter.connect( 
    450                     self.__onButtonEnter 
    451                 ) 
    452             else: 
    453                 self.__hoverListener.buttonEnter.disconnect( 
    454                     self.__onButtonEnter 
    455                 ) 
    456466 
    457467    def changeOnHover(self): 
     
    481491                             QSizePolicy.Expanding) 
    482492        button.setIconSize(self.__iconSize) 
     493        button.setMouseTracking(True) 
    483494 
    484495        self.__group.addButton(button) 
    485496 
    486         button.installEventFilter(self.__hoverListener) 
     497        button.installEventFilter(self) 
    487498 
    488499        tab = _Tab(text, icon, toolTip, button, None, None) 
     
    505516            self.__group.removeButton(tab.button) 
    506517 
    507             tab.button.removeEventFilter(self.__hoverListener) 
     518            tab.button.removeEventFilter(self) 
     519 
     520            if tab.button is self.__sloppyButton: 
     521                self.__sloppyButton = None 
     522                self.__sloppyRegion = QRegion() 
    508523 
    509524            tab.button.deleteLater() 
     
    550565            self.__currentIndex = index 
    551566 
     567            self.__sloppyRegion = QRegion() 
     568            self.__sloppyButton = None 
     569 
    552570            if index != -1: 
    553571                self.__tabs[index].button.setChecked(True) 
     
    586604            b.setIcon(tab.icon) 
    587605 
    588         if tab.toolTip: 
    589             b.setToolTip(tab.toolTip) 
    590  
    591606        if tab.palette: 
    592607            b.setPalette(tab.palette) 
     
    598613                break 
    599614 
    600     def __onButtonEnter(self, button): 
    601         if self.__changeOnHover: 
    602             button.click() 
     615    def __calcSloppyRegion(self, current): 
     616        """ 
     617        Given a current mouse cursor position return a region of the widget 
     618        where hover/move events should change the current tab only on a 
     619        timeout. 
     620 
     621        """ 
     622        p1 = current + QPoint(0, 2) 
     623        p2 = current + QPoint(0, -2) 
     624        p3 = self.pos() + QPoint(self.width(), 0) 
     625        p4 = self.pos() + QPoint(self.width(), self.height()) 
     626        return QRegion(QPolygon([p1, p2, p3, p4])) 
     627 
     628    def __setSloppyButton(self, button): 
     629        """ 
     630        Set the current sloppy button (a tab button inside sloppy region) 
     631        and reset the sloppy timeout. 
     632 
     633        """ 
     634        self.__sloppyButton = button 
     635        delay = self.style().styleHint(QStyle.SH_Menu_SubMenuPopupDelay, None) 
     636        # The delay timeout is the same as used by Qt in the QMenu. 
     637        self.__sloppyTimer.start(delay * 6) 
     638 
     639    def __onSloppyTimeout(self): 
     640        if self.__sloppyButton is not None: 
     641            button = self.__sloppyButton 
     642            self.__sloppyButton = None 
     643            if not button.isChecked(): 
     644                index = [tab.button for tab in self.__tabs].index(button) 
     645                self.setCurrentIndex(index) 
     646 
     647                # Update the sloppy region from the current cursor position. 
     648                current = self.mapFromGlobal(QCursor.pos()) 
     649                if self.contentsRect().contains(current): 
     650                    self.__sloppyRegion = self.__calcSloppyRegion(current) 
     651 
     652    def eventFilter(self, receiver, event): 
     653        if event.type() == QEvent.MouseMove and \ 
     654                isinstance(receiver, TabButton): 
     655            pos = receiver.mapTo(self, event.pos()) 
     656            if self.__sloppyRegion.contains(pos): 
     657                self.__setSloppyButton(receiver) 
     658            else: 
     659                if not receiver.isChecked(): 
     660                    index = [tab.button for tab in self.__tabs].index(receiver) 
     661                    self.setCurrentIndex(index) 
     662                    self.__sloppyRegion = self.__calcSloppyRegion(pos) 
     663 
     664        return QWidget.eventFilter(self, receiver, event) 
     665 
     666    def leaveEvent(self, event): 
     667        self.__sloppyButton = None 
     668        self.__sloppyRegion = QRegion() 
     669 
     670        return QWidget.leaveEvent(self, event) 
    603671 
    604672 
     
    620688        layout = QHBoxLayout() 
    621689        layout.setContentsMargins(0, 0, 0, 0) 
    622         layout.setSpacing(0) 
     690        layout.setSpacing(6) 
    623691 
    624692        self.__tab = TabBarWidget(self) 
     
    713781        """ 
    714782        return self.__tab.button(index) 
     783 
     784 
     785TAB_BUTTON_STYLE_TEMPLATE = """\ 
     786TabButton { 
     787    qproperty-flat_: false; 
     788    background: %s; 
     789    border: none; 
     790    border-bottom: 1px solid palette(dark); 
     791} 
     792 
     793TabButton:checked { 
     794    background: %s; 
     795    border: none; 
     796    border-top: 1px solid #609ED7; 
     797    border-bottom: 1px solid #609ED7; 
     798} 
     799""" 
    715800 
    716801 
     
    891976                button = self.__pages.tabButton(i) 
    892977                button.setStyleSheet( 
    893                     "TabButton {\n" 
    894                     "    qproperty-flat_: false;\n" 
    895                     "    background: %s;\n" 
    896                     "    border: none;\n" 
    897                     "    border-bottom: 1px solid palette(dark);\n" 
    898                     "}\n" 
    899                     "TabButton:checked {\n" 
    900                     "    background: %s\n" 
    901                     "}" % (create_css_gradient(base_color), 
    902                            create_css_gradient(base_color.darker(110))) 
     978                    TAB_BUTTON_STYLE_TEMPLATE % 
     979                    (create_css_gradient(base_color), 
     980                     create_css_gradient(base_color.darker(120))) 
    903981                ) 
    904982 
  • Orange/OrangeCanvas/styles/orange.qss

    r11495 r11500  
    375375 
    376376QuickMenu ToolTree QTreeView::item { 
    377     height: 25px; 
    378377    border-bottom: 1px solid #e9eff2; 
    379378} 
     
    395394 
    396395QuickMenu TabBarWidget QToolButton { 
    397     width: 33px; 
    398396    height: 25px; 
    399397    border-bottom: 1px solid palette(dark); 
    400398    padding-right: 5px; 
     399    padding-left: 5px; 
     400    qproperty-showMenuIndicator_: true; 
    401401} 
    402402 
Note: See TracChangeset for help on using the changeset viewer.