示例#1
0
    def create_layout(self):
        '''
        Creates the complete layout including all controls
        '''
        self.title_label = ElidingLabel(text=self.dock_widget.windowTitle())
        self.title_label.set_elide_mode(Qt.ElideRight)
        self.title_label.setObjectName("dockWidgetTabLabel")
        self.title_label.setAlignment(Qt.AlignCenter)
        self.close_button = QPushButton()
        self.close_button.setObjectName("tabCloseButton")

        set_button_icon(self.public.style(), self.close_button,
                        QStyle.SP_TitleBarCloseButton)

        self.close_button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        self.close_button.setVisible(False)
        self.close_button.setToolTip("Close Tab")
        self.close_button.clicked.connect(self.public.close_requested)

        fm = QFontMetrics(self.title_label.font())
        spacing = round(fm.height() / 4.0)

        # Fill the layout
        layout = QBoxLayout(QBoxLayout.LeftToRight)
        layout.setContentsMargins(2 * spacing, 0, 0, 0)
        layout.setSpacing(0)
        self.public.setLayout(layout)
        layout.addWidget(self.title_label, 1)
        layout.addSpacing(spacing)
        layout.addWidget(self.close_button)
        layout.addSpacing(round(spacing * 4.0 / 3.0))
        layout.setAlignment(Qt.AlignCenter)
        self.title_label.setVisible(True)
    def __init__(self, *, dock_area: 'DockAreaWidget' = None,
                 dock_widget: 'DockWidget' = None,
                 dock_manager: 'DockManager' = None):
        '''
        Parameters
        ----------
        dock_manager : DockManager

        dock_area : DockAreaWidget
            Create floating widget with the given dock area
        '''
        if dock_manager is None:
            if dock_area is not None:
                dock_manager = dock_area.dock_manager()
            elif dock_widget is not None:
                dock_manager = dock_widget.dock_manager()

        if dock_manager is None:
            raise ValueError('Must pass in either dock_area, dock_widget, or dock_manager')

        super().__init__(dock_manager)
        self.d = FloatingDockContainerPrivate(self)
        self.d.dock_manager = dock_manager
        dock_container = DockContainerWidget(dock_manager, self)
        self.d.dock_container = dock_container
        dock_container.destroyed.connect(self._destroyed)
        dock_container.dock_areas_added.connect(self.on_dock_areas_added_or_removed)
        dock_container.dock_areas_removed.connect(self.on_dock_areas_added_or_removed)

        if LINUX:
            self.d.title_bar = FloatingWidgetTitleBar(self)
            self.setWindowFlags(super().windowFlags() | Qt.Tool)
            self.setWidget(self.d.dock_container)
            self.setFloating(True)
            self.setFeatures(QDockWidget.AllDockWidgetFeatures)
            self.setTitleBarWidget(self.d.title_bar)
            self.d.title_bar.close_requested.connect(self.close)
        else:
            self.setWindowFlags(Qt.Window | Qt.WindowMaximizeButtonHint | Qt.WindowCloseButtonHint)
            layout = QBoxLayout(QBoxLayout.TopToBottom)
            layout.setContentsMargins(0, 0, 0, 0)
            layout.setSpacing(0)
            self.setLayout(layout)
            layout.addWidget(dock_container)

        dock_manager.register_floating_widget(self)

        # We install an event filter to detect mouse release events because we
        # do not receive mouse release event if the floating widget is behind
        # the drop overlay cross
        qapp = QApplication.instance()
        qapp.installEventFilter(self)
        if dock_area is not None:
            dock_container.add_dock_area(dock_area)
        elif dock_widget is not None:
            dock_container.add_dock_widget(
                DockWidgetArea.center, dock_widget)
        if (dock_area or dock_widget) and LINUX:
            self.d.title_bar.enable_close_button(self.is_closable())
示例#3
0
    def create_layout(self):
        '''
        Creates the complete layout including all controls
        '''
        self.title_label = ElidingLabel()
        self.title_label.set_elide_mode(Qt.ElideRight)
        self.title_label.setText("DockWidget->windowTitle()")
        self.title_label.setObjectName("floatingTitleLabel")
        self.title_label.setAlignment(Qt.AlignLeft)

        self.close_button = QPushButton()
        self.close_button.setObjectName("floatingTitleCloseButton")
        self.close_button.setFlat(True)

        # self.close_button.setAutoRaise(True)
        set_button_icon(self.public.style(), self.close_button,
                        QStyle.SP_TitleBarCloseButton)

        self.close_button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        self.close_button.setVisible(True)
        self.close_button.setFocusPolicy(Qt.NoFocus)
        self.close_button.clicked.connect(self.public.close_requested)

        fm = QFontMetrics(self.title_label.font())
        spacing = round(fm.height() / 4.0)

        # Fill the layout
        layout = QBoxLayout(QBoxLayout.LeftToRight)
        layout.setContentsMargins(6, 0, 0, 0)
        layout.setSpacing(0)
        self.public.setLayout(layout)
        layout.addWidget(self.title_label, 1)
        layout.addSpacing(spacing)
        layout.addWidget(self.close_button)
        layout.setAlignment(Qt.AlignCenter)
        self.title_label.setVisible(True)
class ExtendedTabBar(QFrame):
    '''
    A tab bar that has QToolBars to the left, right, and floating at the end of the tabs.

    Note that although this class inherits from QFrame, __getattr__() trickery is used to "inherit"
    the attributes of an internal object that inherits from QTabBar. This is done because it allows
    the actual tab bar object to be placed in a layout with other widgets, while allowing this class
    to be treated as the tab bar itself.
    '''
    RoundedNorth = QTabBar.RoundedNorth
    RoundedSouth = QTabBar.RoundedSouth
    RoundedWest = QTabBar.RoundedWest
    RoundedEast = QTabBar.RoundedEast
    TriangularNorth = QTabBar.TriangularNorth
    TriangularSouth = QTabBar.TriangularSouth
    TriangularWest = QTabBar.TriangularWest
    TriangularEast = QTabBar.TriangularEast

    def __init__(self):
        super(ExtendedTabBar, self).__init__()

        self._tab_bar = _NoMinimumWidthTabBar()

        self._left_toolbar = QToolBar()
        self._floating_toolbar = QToolBar()
        self._right_toolbar = QToolBar()

        # Setup the layout.
        self._main_layout = QBoxLayout(QBoxLayout.LeftToRight)
        self._main_layout.setContentsMargins(0, 0, 0, 0)
        self._main_layout.setSpacing(0)

        self._main_layout.addWidget(self._left_toolbar)
        self._main_layout.addWidget(self._tab_bar)
        self._main_layout.addWidget(self._floating_toolbar)
        self._main_layout.addStretch()
        self._main_layout.addWidget(self._right_toolbar)

        self.setLayout(self._main_layout)

    def __getattr__(self, name):
        '''
        Return the internal tab bar object's attributes if this class does not have the given
        attribute.
        '''
        return self.__dict__.get(name, getattr(self._tab_bar, name))

    def minimumSizeHint(self):
        '''
        Add on any margins to the minimum size hint. Keeps the widget from getting sized so that the
        tab tops are cut off.
        '''
        margins = self._main_layout.contentsMargins()
        minimum_size_hint = self._tab_bar.minimumSizeHint()

        if self.shape() in {
                QTabBar.RoundedNorth, QTabBar.RoundedSouth,
                QTabBar.TriangularNorth, QTabBar.TriangularSouth
        }:
            return minimum_size_hint + QSize(0,
                                             margins.top() + margins.bottom())
        else:
            return minimum_size_hint + QSize(margins.left() + margins.right(),
                                             0)

    def setShape(self, shape):
        '''
        Sets the tab shapes.

        shape
            One of:
                ExtendedTabBar.RoundedNorth
                ExtendedTabBar.RoundedSouth
                ExtendedTabBar.RoundedWest
                ExtendedTabBar.RoundedEast
                ExtendedTabBar.TriangularNorth
                ExtendedTabBar.TriangularSouth
                ExtendedTabBar.TriangularWest
                ExtendedTabBar.TriangularEast
        '''
        self._tab_bar.setShape(shape)

        if shape in {
                QTabBar.RoundedNorth, QTabBar.RoundedSouth,
                QTabBar.TriangularNorth, QTabBar.TriangularSouth
        }:
            direction = QBoxLayout.LeftToRight
            orientation = Qt.Horizontal
        else:
            direction = QBoxLayout.TopToBottom
            orientation = Qt.Vertical

        self._main_layout.setDirection(direction)
        self._left_toolbar.setOrientation(orientation)
        self._floating_toolbar.setOrientation(orientation)
        self._right_toolbar.setOrientation(orientation)

    @property
    def left_toolbar(self):
        '''
        Returns the QToolBar to the left (top) of the tabs.
        '''
        return self._left_toolbar

    @property
    def floating_toolbar(self):
        '''
        Returns the QToolBar floating to the right (bottom) of the tabs.
        '''
        return self._floating_toolbar

    @property
    def right_toolbar(self):
        '''
        Returns the QToolBar to the right (bottom) of the tabs.
        '''
        return self._right_toolbar
class ExtendedTabWidget(QFrame):
    '''
    Like QTabWidget, except the tab bar is located elsewhere. Intended for use with ExtendedTabBar.
    '''
    def __init__(self):
        super(ExtendedTabWidget, self).__init__()

        self._tab_bar = None
        self._stack = QStackedWidget()

        self._main_layout = QBoxLayout(QBoxLayout.LeftToRight)
        self._main_layout.setContentsMargins(0, 0, 0, 0)
        self._main_layout.addWidget(self._stack)
        self.setLayout(self._main_layout)

    def _move_tab(self, from_, to):
        '''
        Handles tab moves so that the tab bar indices stay aligned with the widget stack indices.
        '''
        displaced_widget = self._stack.widget(from_)
        moved_widget = self._stack.widget(to)

        self._stack.removeWidget(moved_widget)
        self._stack.removeWidget(displaced_widget)

        self._stack.insertWidget(to, displaced_widget)
        self._stack.insertWidget(from_, moved_widget)

        self._stack.setCurrentIndex(self._tab_bar.currentIndex())

    def setTabBar(self, tab_bar):
        '''
        Sets the tab bar that will be used to switch between tabs.

        tab_bar
            The tab bar to set as the controller of this widget.
        '''
        if self._tab_bar is not None:
            raise Exception('Tab bar already set.')

        self._tab_bar = tab_bar
        tab_bar.currentChanged.connect(self._stack.setCurrentIndex)
        tab_bar.tabCloseRequested.connect(self.closeTab)
        tab_bar.tabMoved.connect(self._move_tab)

    def closeTab(self, index):
        '''
        Closes a tab, removing from this widget, the tab bar, and deleting its widget.

        index
            Index of the tab to be closed.
        '''
        self._tab_bar.removeTab(index)

        widget = self._stack.widget(index)
        self._stack.removeWidget(widget)

        widget.deleteLater()

        self._stack.setCurrentIndex(self._tab_bar.currentIndex())

    def addTab(self, widget, label):
        '''
        Adds a tab.

        widget
            The widget for the tab contents.

        label
            The name of the tab to show in the tab bar.

        Returns the index of the added tab.
        '''
        index = self._tab_bar.addTab(label)
        self._stack.insertWidget(index, widget)

        return index

    def count(self):
        '''
        Returns the number of widgets.
        '''
        return self._stack.count()

    def widget(self, index):
        '''
        Returns the widget at the given index.
        '''
        return self._stack.widget(index)

    def indexOf(self, widget):
        '''
        Returns the index of the given widget.
        '''
        return self._stack.indexOf(widget)