Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • Orange/OrangeCanvas/document/quickmenu.py

    r11462 r11494  
    2121    QStandardItemModel, QSortFilterProxyModel, QStyleOptionToolButton, 
    2222    QStylePainter, QStyle, QApplication, QStyledItemDelegate, 
    23     QStyleOptionViewItemV4, QSizeGrip, QKeySequence 
     23    QStyleOptionViewItemV4, QSizeGrip 
    2424) 
    2525 
     
    3535from ..gui.lineedit import LineEdit 
    3636from ..gui.tooltree import ToolTree, FlattenedTreeItemModel 
     37from ..gui.toolgrid import ToolButtonEventListener 
     38from ..gui.toolbox import create_tab_gradient 
    3739from ..gui.utils import StyledWidget_paintEvent 
    3840 
     
    4244 
    4345log = logging.getLogger(__name__) 
     46 
     47 
     48class _MenuItemDelegate(QStyledItemDelegate): 
     49    def __init__(self, parent=None): 
     50        QStyledItemDelegate.__init__(self, parent) 
     51 
     52    def sizeHint(self, option, index): 
     53        option = QStyleOptionViewItemV4(option) 
     54        self.initStyleOption(option, index) 
     55        size = QStyledItemDelegate.sizeHint(self, option, index) 
     56 
     57        # TODO: get the default QMenu item height from the current style. 
     58        size.setHeight(max(size.height(), 25)) 
     59        return size 
    4460 
    4561 
     
    6379        self.__icon = icon 
    6480 
     81        self.view().setItemDelegate(_MenuItemDelegate(self.view())) 
    6582        # Make sure the initial model is wrapped in a ItemDisableFilter. 
    6683        self.setModel(self.model()) 
     
    133150        proxyModel = self.view().model() 
    134151        return proxyModel.mapToSource(ToolTree.rootIndex(self)) 
     152 
     153    def sizeHint(self): 
     154        view = self.view() 
     155        hint = view.sizeHint() 
     156        model = view.model() 
     157 
     158        # This will not work for nested items (tree). 
     159        count = model.rowCount(view.rootIndex()) 
     160 
     161        width = view.sizeHintForColumn(0) 
     162 
     163        if count: 
     164            height = view.sizeHintForRow(0) 
     165            height = height * count 
     166        else: 
     167            height = hint.height() 
     168        return QSize(max(width, hint.width()), max(height, hint.height())) 
    135169 
    136170 
     
    293327        widget_hints = [default_size] 
    294328        for i in range(self.count()): 
    295             w = self.widget(i) 
    296             if isinstance(w, ToolTree): 
    297                 hint = self.__sizeHintForTreeView(w.view()) 
    298             else: 
    299                 hint = w.sizeHint() 
     329            hint = self.widget(i).sizeHint() 
    300330            widget_hints.append(hint) 
     331 
    301332        width = max([s.width() for s in widget_hints]) 
    302333        # Take the median for the height 
     
    341372 
    342373    def paintEvent(self, event): 
     374        opt = QStyleOptionToolButton() 
     375        self.initStyleOption(opt) 
     376        opt.features |= QStyleOptionToolButton.HasMenu 
    343377        if self.__flat: 
    344378            # Use default widget background/border styling. 
    345379            StyledWidget_paintEvent(self, event) 
    346380 
    347             opt = QStyleOptionToolButton() 
    348             self.initStyleOption(opt) 
    349381            p = QStylePainter(self) 
    350382            p.drawControl(QStyle.CE_ToolButtonLabel, opt) 
    351383        else: 
    352             QToolButton.paintEvent(self, event) 
    353  
     384            p = QStylePainter(self) 
     385            p.drawComplexControl(QStyle.CC_ToolButton, opt) 
     386 
     387    def sizeHint(self): 
     388        opt = QStyleOptionToolButton() 
     389        self.initStyleOption(opt) 
     390        opt.features |= QStyleOptionToolButton.HasMenu 
     391        style = self.style() 
     392 
     393        hint = style.sizeFromContents(QStyle.CT_ToolButton, opt, 
     394                                      opt.iconSize, self) 
     395        return hint 
    354396 
    355397_Tab = \ 
     
    364406 
    365407 
    366 # TODO: ..application.canvastooldock.QuickCategoryToolbar is very similar, 
    367 #       to TobBarWidget. Maybe common functionality could factored our. 
    368  
    369408class TabBarWidget(QWidget): 
    370409    """ 
     
    377416    def __init__(self, parent=None, **kwargs): 
    378417        QWidget.__init__(self, parent, **kwargs) 
    379         layout = QHBoxLayout() 
     418        layout = QVBoxLayout() 
    380419        layout.setContentsMargins(0, 0, 0, 0) 
    381420        layout.setSpacing(0) 
    382421        self.setLayout(layout) 
    383422 
    384         self.setSizePolicy(QSizePolicy.Expanding, 
    385                            QSizePolicy.Fixed) 
     423        self.setSizePolicy(QSizePolicy.Fixed, 
     424                           QSizePolicy.Expanding) 
    386425        self.__tabs = [] 
     426 
    387427        self.__currentIndex = -1 
     428        self.__changeOnHover = False 
     429 
     430        self.__iconSize = QSize(26, 26) 
     431 
    388432        self.__group = QButtonGroup(self, exclusive=True) 
    389433        self.__group.buttonPressed[QAbstractButton].connect( 
     
    391435        ) 
    392436 
     437        self.__hoverListener = ToolButtonEventListener(self) 
     438 
     439    def setChangeOnHover(self, changeOnHover): 
     440        """ 
     441        If set to ``True`` the tab widget will change the current index when 
     442        the mouse hovers over a tab button. 
     443 
     444        """ 
     445        if self.__changeOnHover != changeOnHover: 
     446            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                ) 
     456 
     457    def changeOnHover(self): 
     458        """ 
     459        Does the current tab index follow the mouse cursor. 
     460        """ 
     461        return self.__changeOnHover 
     462 
    393463    def count(self): 
    394464        """ 
     
    410480        button.setSizePolicy(QSizePolicy.Expanding, 
    411481                             QSizePolicy.Expanding) 
     482        button.setIconSize(self.__iconSize) 
    412483 
    413484        self.__group.addButton(button) 
     485 
     486        button.installEventFilter(self.__hoverListener) 
     487 
    414488        tab = _Tab(text, icon, toolTip, button, None, None) 
    415489        self.layout().insertWidget(index, button) 
     
    430504            tab = self.__tabs.pop(index) 
    431505            self.__group.removeButton(tab.button) 
     506 
     507            tab.button.removeEventFilter(self.__hoverListener) 
     508 
    432509            tab.button.deleteLater() 
    433510 
     
    490567        return self.__tabs[index].button 
    491568 
     569    def setIconSize(self, size): 
     570        if self.__iconSize != size: 
     571            self.__iconSize = size 
     572            for tab in self.__tabs: 
     573                tab.button.setIconSize(self.__iconSize) 
     574 
    492575    def __updateTab(self, index): 
    493576        """ 
     
    515598                break 
    516599 
     600    def __onButtonEnter(self, button): 
     601        if self.__changeOnHover: 
     602            button.click() 
     603 
    517604 
    518605class PagedMenu(QWidget): 
     
    531618        self.__currentIndex = -1 
    532619 
    533         layout = QVBoxLayout() 
     620        layout = QHBoxLayout() 
    534621        layout.setContentsMargins(0, 0, 0, 0) 
    535622        layout.setSpacing(0) 
    536623 
    537624        self.__tab = TabBarWidget(self) 
    538         self.__tab.setFixedHeight(25) 
    539625        self.__tab.currentChanged.connect(self.setCurrentIndex) 
     626        self.__tab.setChangeOnHover(True) 
    540627 
    541628        self.__stack = MenuStackWidget(self) 
    542629 
    543         layout.addWidget(self.__tab) 
     630        layout.addWidget(self.__tab, alignment=Qt.AlignTop) 
    544631        layout.addWidget(self.__stack) 
    545632 
     
    659746        self.layout().setContentsMargins(6, 6, 6, 6) 
    660747 
     748        self.__search = SearchWidget(self, objectName="search-line") 
     749 
     750        self.__search.setPlaceholderText( 
     751            self.tr("Search for widget or select from the list.") 
     752        ) 
     753 
     754        self.layout().addWidget(self.__search) 
     755 
    661756        self.__frame = QFrame(self, objectName="menu-frame") 
    662757        layout = QVBoxLayout() 
    663         layout.setContentsMargins(1, 1, 1, 1) 
     758        layout.setContentsMargins(0, 0, 0, 0) 
    664759        layout.setSpacing(2) 
    665760        self.__frame.setLayout(layout) 
     
    674769        self.__frame.layout().addWidget(self.__pages) 
    675770 
    676         self.__search = SearchWidget(self, objectName="search-line") 
    677  
    678         self.__search.setPlaceholderText( 
    679             self.tr("Search for widget or select from the list.") 
    680         ) 
    681  
    682         self.layout().addWidget(self.__search) 
    683771        self.setSizePolicy(QSizePolicy.Fixed, 
    684772                           QSizePolicy.Expanding) 
     
    691779            view = self.__suggestPage.view() 
    692780            view.verticalScrollBar().setAttribute(Qt.WA_MacMiniSize, True) 
    693             # Don't show the focus frame because it expands into the tab 
    694             # bar at the top. 
     781            # Don't show the focus frame because it expands into the tab bar. 
    695782            view.setAttribute(Qt.WA_MacShowFocusRect, False) 
    696783 
    697         self.addPage(self.tr("Quick Search"), self.__suggestPage) 
     784        i = self.addPage(self.tr("Quick Search"), self.__suggestPage) 
     785        button = self.__pages.tabButton(i) 
     786        button.setObjectName("search-tab-button") 
     787        button.setStyleSheet( 
     788            "TabButton {\n" 
     789            "    qproperty-flat_: false;\n" 
     790            "    border: none;" 
     791            "}\n") 
    698792 
    699793        self.__search.textEdited.connect(self.__on_textEdited) 
     
    756850        """ 
    757851        page = MenuPage(self) 
    758         view = page.view() 
    759         delegate = WidgetItemDelegate(view) 
    760         view.setItemDelegate(delegate) 
    761852 
    762853        page.setModel(index.model()) 
     
    797888            if brush.isValid(): 
    798889                brush = brush.toPyObject() 
     890                base_color = brush.color() 
    799891                button = self.__pages.tabButton(i) 
    800                 palette = button.palette() 
    801892                button.setStyleSheet( 
    802893                    "TabButton {\n" 
    803894                    "    qproperty-flat_: false;\n" 
    804                     "    background-color: %s;\n" 
     895                    "    background: %s;\n" 
    805896                    "    border: none;\n" 
     897                    "    border-bottom: 1px solid palette(dark);\n" 
    806898                    "}\n" 
    807899                    "TabButton:checked {\n" 
    808                     "    border: 1px solid %s;\n" 
    809                     "}" % (brush.color().name(), 
    810                            palette.color(palette.Mid).name()) 
     900                    "    background: %s\n" 
     901                    "}" % (create_css_gradient(base_color), 
     902                           create_css_gradient(base_color.darker(110))) 
    811903                ) 
    812904 
     
    823915                self.__pages.page(i).setFilterFunc(func) 
    824916 
    825     def popup(self, pos=None): 
    826         """ 
    827         Popup the menu at `pos` (in screen coordinates). 
     917    def popup(self, pos=None, searchText=""): 
     918        """ 
     919        Popup the menu at `pos` (in screen coordinates). 'Search' text field 
     920        is initialized with `searchText` if provided. 
    828921        """ 
    829922        if pos is None: 
    830923            pos = QPoint() 
    831924 
    832         self.__search.setText("") 
    833         self.__suggestPage.setFilterFixedString("") 
     925        self.__search.setText(searchText) 
     926        self.__suggestPage.setFilterFixedString(searchText) 
    834927 
    835928        self.ensurePolished() 
     
    873966        self.show() 
    874967 
    875     def exec_(self, pos=None): 
     968        if searchText: 
     969            self.setFocusProxy(self.__search) 
     970        else: 
     971            self.setFocusProxy(None) 
     972 
     973    def exec_(self, pos=None, searchText=""): 
    876974        """ 
    877975        Execute the menu at position `pos` (in global screen coordinates). 
    878976        Return the triggered :class:`QAction` or `None` if no action was 
    879         triggered. 
    880  
    881         """ 
    882         self.popup(pos) 
     977        triggered. 'Search' text field is initialized with `searchText` if 
     978        provided. 
     979 
     980        """ 
     981        self.popup(pos, searchText) 
    883982        self.setFocus(Qt.PopupFocusReason) 
    884983 
     
    9691068 
    9701069        return FramelessWindow.eventFilter(self, obj, event) 
    971  
    972  
    973 class WidgetItemDelegate(QStyledItemDelegate): 
    974     def __init__(self, parent=None): 
    975         QStyledItemDelegate.__init__(self, parent) 
    976  
    977     def sizeHint(self, option, index): 
    978         option = QStyleOptionViewItemV4(option) 
    979         self.initStyleOption(option, index) 
    980         size = QStyledItemDelegate.sizeHint(self, option, index) 
    981         size.setHeight(max(size.height(), 25)) 
    982         return size 
    9831070 
    9841071 
     
    11471234 
    11481235        self.move(x, y) 
     1236 
     1237 
     1238def create_css_gradient(base_color): 
     1239    """ 
     1240    Create a Qt css linear gradient fragment based on the `base_color`. 
     1241    """ 
     1242    grad = create_tab_gradient(base_color) 
     1243    stops = grad.stops() 
     1244    stops = "\n".join("    stop: {0:f} {1}".format(stop, color.name()) 
     1245                      for stop, color in stops) 
     1246    return ("qlineargradient(\n" 
     1247            "    x1: 0, y1: 0, x2: 0, y2: 1,\n" 
     1248            "{0})").format(stops) 
Note: See TracChangeset for help on using the changeset viewer.