Source code for openalea.oalab.gui.menu
# -*- python -*-
#
#       Main Menu class
#
#       OpenAlea.OALab: Multi-Paradigm GUI
#
#       Copyright 2013 INRIA - CIRAD - INRA
#
#       File author(s): Julien Coste <julien.coste@inria.fr>
#
#       File contributor(s):
#
#       Distributed under the Cecill-C License.
#       See accompanying file LICENSE.txt or copy at
#           http://www.cecill.info/licences/Licence_CeCILL-C_V1-en.html
#
#       OpenAlea WebSite : http://openalea.gforge.inria.fr
#
###############################################################################
"""
Full example:
.. code-block:: python
    from openalea.vpltk.qt import QtGui
    from openalea.oalab.gui.menu import PanedMenu
    # Create ribbon bar
    menu = PanedMenu()
    # Create Qt QAction
    act1 = QtGui.QAction(u'act 1', menu)
    act2 = QtGui.QAction(u'act 2', menu)
    # Add actions to ribbon bar
    menu.addBtnByAction('Panel', 'group', act1, PanedMenu.BigButton)
    menu.addBtnByAction('Panel', 'group', act2, PanedMenu.SmallButton)
"""
__revision__ = ""
from openalea.vpltk.qt import QtGui, QtCore
"""
# To generate images
from openalea.lpy.gui.compile_ui import check_rc_generation
check_rc_generation('resources.qrc')
"""
size_policy_small = QtGui.QSizePolicy(QtGui.QSizePolicy.Maximum, QtGui.QSizePolicy.Maximum)
big_btn_size = QtCore.QSize(25, 25)
small_btn_size = QtCore.QSize(100, 16)
big_icon_size = QtCore.QSize(24, 24)
small_icon_size = QtCore.QSize(16, 16)
toolbutton_style = """
    QToolButton {
         background-color: transparent;
         min-width: 80px;
     }
    QToolButton:hover {
        border: 1px solid rgb(200, 200, 200);
        border-radius: 2px;
    }
    QToolButton:pressed {
        background-color: rgba(0, 0, 0, 50);
        border: 1px solid rgb(175, 175, 175);
        border-radius: 2px;
    }
"""
[docs]class PanedMenu(QtGui.QTabWidget):
    """
    A widget that tries to mimic menu of Microsoft Office 2010.
    Cf. Ribbon Bar.
    >>> from openalea.oalab.gui.menu import PanedMenu
    >>> menu = PanedMenu()
    """
    BigButton = 0
    SmallButton = 1
    BigWidget = 'bigwidget'
    SmallWidget = 'smallwidget'
    def __init__(self, parent=None):
        super(PanedMenu, self).__init__()
        self.setAccessibleName("Menu")
        self.setContentsMargins(0, 0, 0, 0)
        size_policy = QtGui.QSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Maximum)
        self.setSizePolicy(size_policy)
        self.tab_name = list()
[docs]    def addSpecialTab(self, label, widget=None):
        widget = Pane()
        self.tab_name.append(label)
        self.addTab(widget, label)
[docs]    def addBtn(self, pane_name, group_name, btn_name, btn_icon, btn_type=0):
        """
        :param pane_name: name of pane. type:String.
        :param group_name: name of group inside the pane. type:String.
        :param btn_name: name of button inside the group. type:String.
        :param btn_icon: icon of button. type:QtGui.QIcon.
        :param btn_type: type of button to add. 0 = Big Button. 1 = Small Button, smallwidget = Small Widget, bigwidget = Big Widget. Default=0.
        :return: created button. type:QToolButton
        """
        # Check if pane exist, else create it
        if pane_name not in self.tab_name:
            self.addSpecialTab(pane_name)
        # Get Pane
        index = self.tab_name.index(pane_name)
        pane = self.widget(index)
        # Check if group exist, else create it
        if group_name not in pane.group_name:
            pane.addGroup(group_name)
        # Get group
        index = pane.group_name.index(group_name) + 1
        grp = pane.layout.itemAtPosition(0, index).widget()
        # Add Btn
        return grp.addBtn(btn_name, btn_icon, btn_type)
[docs]    def addBtnByAction(self, pane_name, group_name, action, btn_type=0):
        """
        :param pane_name: name of pane. type:String.
        :param group_name: name of group inside the pane. type:String.
        :param action: to add (with a name and an icon)
        :param btn_type: type of button to add. 0 = Big Button. 1 = Small Button, smallwidget = Small Widget, bigwidget = Big Widget. Default=0.
        :return: created button. type:QToolButton
        """
        # Check if pane exist, else create it
        if pane_name not in self.tab_name:
            self.addSpecialTab(pane_name)
        # Get Pane
        index = self.tab_name.index(pane_name)
        pane = self.widget(index)
        # Check if group exist, else create it
        if group_name not in pane.group_name:
            pane.addGroup(group_name)
        # Get group
        index = pane.group_name.index(group_name) + 1
        grp = pane.layout.itemAtPosition(0, index).widget()
        # Add Btn
        return grp.addBtnByAction(action, btn_type)
[docs]    def showPane(self, pane_name):
        # Find tab named 'name'
        try:
            index = self.tab_name.index(pane_name)
        except ValueError:
            pass
        else:
            self.setCurrentIndex(index)
[docs]class Pane(QtGui.QWidget):
    def __init__(self, parent=None):
        # TODO : scroll doesn't work yet
        super(Pane, self).__init__()
#         self.setWidgetResizable(False)
#         self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        # ScrollBarAsNeeded
        # ScrollBarAlwaysOn
        # ScrollBarAlwaysOff
#         self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
        self.group_name = list()
        self.layout = QtGui.QGridLayout()
        self.layout.setContentsMargins(0, 0, 0, 0)
        self.layout.setSpacing(0)
        self.layout.setAlignment(QtCore.Qt.AlignLeft)
        self.setLayout(self.layout)
        self.setSizePolicy(size_policy_small)
[docs]    def addGroup(self, name):
        grp = Group(name)
        column = self.layout.columnCount()
        self.layout.addWidget(grp, 0, column, QtCore.Qt.AlignHCenter)
        self.group_name.append(name)
[docs]class Group(QtGui.QWidget):
    def __init__(self, name):
        super(Group, self).__init__()
        self.setToolTip(name)
        self.name = name
        self.layout = QtGui.QHBoxLayout()
        self.layout.setContentsMargins(0, 0, 0, 0)
        self.layout.setSpacing(0)
        self.layout.setAlignment(QtCore.Qt.AlignLeft)
        self.setLayout(self.layout)
        self.layout.addWidget(SubGroupH())
        self.layout.addWidget(SubGroupGrid())
#         self.setSizePolicy(size_policy_small)
[docs]    def addBtnByAction(self, action, style=PanedMenu.BigButton):
        if style == PanedMenu.BigButton:
            return self.addBigToolButton(action)
        elif style == PanedMenu.SmallButton:
            return self.addSmallToolButton(action)
        elif style == PanedMenu.SmallWidget:
            return self.addWidget(action, "small")
        elif style == PanedMenu.BigWidget:
            return self.addWidget(action, "big")
[docs]    def addWidget(self, widget, style="big"):
        """
        Permit to add small widget like if it was a small button
        """
        btn = widget
        if style == "small":
            layout = self.layout.itemAt(1).widget().layout
            self.check_unicity_group(layout, btn.accessibleName())
            column = layout.columnCount()
            row = layout.rowCount()
            nb = layout.count()
            new_row = nb - nb / 3 * 3
            # If not a new column
            if new_row > 0:
                layout.addWidget(btn, new_row + 1, column - 1)
            # If new column
            else:
                layout.addWidget(btn, 1, column)
        elif style == "big":
            layout = self.layout.itemAt(0).widget().layout
            self.check_unicity_box(layout, btn.accessibleName())
            layout.addWidget(btn)
        return btn
[docs]    def addBigBtn(self, name, icon):
        btn = BigToolButton(name, icon)
        layout = self.layout.itemAt(0).widget().layout
        self.check_unicity_box(layout, name)
        layout.addWidget(btn)
        return btn
[docs]    def addSmallBtn(self, name, icon):
        btn = SmallToolButton(name, icon)
        layout = self.layout.itemAt(1).widget().layout
        self.check_unicity_group(layout, name)
        column = layout.columnCount()
        row = layout.rowCount()
        nb = layout.count()
        new_row = nb - nb / 3 * 3
        # If not a new column
        if new_row > 0:
            layout.addWidget(btn, new_row + 1, column - 1)
        # If new column
        else:
            layout.addWidget(btn, 1, column)
        return btn
[docs]    def addBigToolButton(self, action):
        btn = BigToolButton(action)
        layout = self.layout.itemAt(0).widget().layout
        self.check_unicity_box(layout, btn.defaultAction().iconText())
        layout.addWidget(btn)
        return btn
[docs]    def addSmallToolButton(self, action):
        btn = SmallToolButton(action)
        layout = self.layout.itemAt(1).widget().layout
        self.check_unicity_group(layout, btn.defaultAction().iconText())
        column = layout.columnCount()
        row = layout.rowCount()
        nb = layout.count()
        new_row = nb - nb / 3 * 3
        # If not a new column
        if new_row > 0:
            layout.addWidget(btn, new_row + 1, column - 1)
        # If new column
        else:
            layout.addWidget(btn, 1, column)
        return btn
[docs]    def check_unicity_group(self, layout, name):
        """
        Hide old button if a new is added with the same name.
        Works with groupLayout
        """
        column = layout.columnCount()
        row = layout.rowCount()
        for y in range(column):
            for x in range(row):
                try:
                    widget = layout.itemAtPosition(x, y).widget()
                    if str(widget.text()) == str(name):
                        widget.hide()
                except:
                    pass
[docs]    def check_unicity_box(self, layout, name):
        """
        Hide old button if a new is added with the same name
        Works with hbox and vbox layout
        """
        for i in range(layout.count()):
            widget = layout.itemAt(i).widget()
            if str(widget.text()) == str(name):
                widget.hide()
[docs]class SubGroupH(QtGui.QWidget):
    def __init__(self):
        super(SubGroupH, self).__init__()
        self.layout = QtGui.QHBoxLayout()
        self.layout.setContentsMargins(0, 0, 0, 0)
        self.layout.setSpacing(0)
        self.layout.setAlignment(QtCore.Qt.AlignLeft)
        self.setLayout(self.layout)
        self.setSizePolicy(size_policy_small)
[docs]class SubGroupV(QtGui.QWidget):
    def __init__(self):
        super(SubGroupV, self).__init__()
        self.layout = QtGui.QVBoxLayout()
        self.layout.setContentsMargins(0, 0, 0, 0)
        self.layout.setSpacing(0)
        self.layout.setAlignment(QtCore.Qt.AlignTop)
        self.setLayout(self.layout)
[docs]class SubGroupGrid(QtGui.QWidget):
    def __init__(self):
        super(SubGroupGrid, self).__init__()
        self.layout = QtGui.QGridLayout()
        self.layout.setContentsMargins(0, 0, 0, 0)
        self.layout.setSpacing(0)
        self.layout.setAlignment(QtCore.Qt.AlignLeft)
        self.setLayout(self.layout)
[docs]class ToolButton(QtGui.QToolButton):
    def __init__(self, action, icon=None):
        super(ToolButton, self).__init__()
        self.setAutoRaise(True)
        if isinstance(action, QtGui.QAction):
            self.setDefaultAction(action)
        else:
            self.setText(str(action))
            if isinstance(icon, QtGui.QIcon):
                self.setIcon(icon)
        self.setStyleSheet(toolbutton_style)
        self.setSizePolicy(size_policy_small)
        self.setContentsMargins(0, 0, 0, 0)
[docs]class BigToolButton(ToolButton):
    def __init__(self, action, icon=None):
        super(BigToolButton, self).__init__(action, icon)
        self.setToolButtonStyle(QtCore.Qt.ToolButtonIconOnly)
        self.setIconSize(big_icon_size)
        self.setMinimumSize(big_btn_size)
        self.setMaximumSize(big_btn_size)
[docs]class SmallToolButton(ToolButton):
    def __init__(self, action, icon=None):
        super(SmallToolButton, self).__init__(action, icon)
        self.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon)
        self.setIconSize(small_icon_size)
        self.setMinimumSize(small_btn_size)
        self.setMaximumSize(small_btn_size)
if __name__ == '__main__':
    import sys
    from openalea.vpltk.qt import QtGui
    instance = QtGui.QApplication.instance()
    if instance is None:
        qapp = QtGui.QApplication(sys.argv)
    else:
        qapp = instance
    # Example: create a panel with one group containing 1 big and 3 small buttons
    menu = PanedMenu()
    act0 = QtGui.QAction(u'Action', menu)
    act1 = QtGui.QAction(u'act 1', menu)
    act2 = QtGui.QAction(u'act 2', menu)
    act3 = QtGui.QAction(u'act 3', menu)
    menu.addBtnByAction('Panel', 'group', act0, PanedMenu.BigButton)
    menu.addBtnByAction('Panel', 'group', act1, PanedMenu.SmallButton)
    menu.addBtnByAction('Panel', 'group', act2, PanedMenu.SmallButton)
    menu.addBtnByAction('Panel', 'group', act3, PanedMenu.SmallButton)
    menu.show()
    if instance is None:
        qapp.exec_()