#!/usr/bin/env python ############################################################################# ## ## Copyright (C) 2013 Riverbank Computing Limited. ## Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ## All rights reserved. ## ## This file is part of the examples of PyQt. ## ## $QT_BEGIN_LICENSE:BSD$ ## You may use this file under the terms of the BSD license as follows: ## ## "Redistribution and use in source and binary forms, with or without ## modification, are permitted provided that the following conditions are ## met: ## * Redistributions of source code must retain the above copyright ## notice, this list of conditions and the following disclaimer. ## * Redistributions in binary form must reproduce the above copyright ## notice, this list of conditions and the following disclaimer in ## the documentation and/or other materials provided with the ## distribution. ## * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor ## the names of its contributors may be used to endorse or promote ## products derived from this software without specific prior written ## permission. ## ## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ## $QT_END_LICENSE$ ## ############################################################################# from PyQt5.QtCore import QRect, QSize, Qt from PyQt5.QtWidgets import (QApplication, QFrame, QLabel, QLayout, QTextBrowser, QWidget, QWidgetItem) class ItemWrapper(object): def __init__(self, i, p): self.item = i self.position = p class BorderLayout(QLayout): West, North, South, East, Center = range(5) MinimumSize, SizeHint = range(2) def __init__(self, parent=None, margin=None, spacing=-1): super(BorderLayout, self).__init__(parent) if margin is not None: self.setContentsMargins(margin, margin, margin, margin) self.setSpacing(spacing) self.list = [] def __del__(self): l = self.takeAt(0) while l is not None: l = self.takeAt(0) def addItem(self, item): self.add(item, self.West) def addWidget(self, widget, position): self.add(QWidgetItem(widget), position) def expandingDirections(self): return Qt.Horizontal | Qt.Vertical def hasHeightForWidth(self): return False def count(self): return len(self.list) def itemAt(self, index): if index < len(self.list): return self.list[index].item return None def minimumSize(self): return self.calculateSize(self.MinimumSize) def setGeometry(self, rect): center = None eastWidth = 0 westWidth = 0 northHeight = 0 southHeight = 0 centerHeight = 0 super(BorderLayout, self).setGeometry(rect) for wrapper in self.list: item = wrapper.item position = wrapper.position if position == self.North: item.setGeometry(QRect(rect.x(), northHeight, rect.width(), item.sizeHint().height())) northHeight += item.geometry().height() + self.spacing() elif position == self.South: item.setGeometry(QRect(item.geometry().x(), item.geometry().y(), rect.width(), item.sizeHint().height())) southHeight += item.geometry().height() + self.spacing() item.setGeometry(QRect(rect.x(), rect.y() + rect.height() - southHeight + self.spacing(), item.geometry().width(), item.geometry().height())) elif position == self.Center: center = wrapper centerHeight = rect.height() - northHeight - southHeight for wrapper in self.list: item = wrapper.item position = wrapper.position if position == self.West: item.setGeometry(QRect(rect.x() + westWidth, northHeight, item.sizeHint().width(), centerHeight)) westWidth += item.geometry().width() + self.spacing() elif position == self.East: item.setGeometry(QRect(item.geometry().x(), item.geometry().y(), item.sizeHint().width(), centerHeight)) eastWidth += item.geometry().width() + self.spacing() item.setGeometry(QRect(rect.x() + rect.width() - eastWidth + self.spacing(), northHeight, item.geometry().width(), item.geometry().height())) if center: center.item.setGeometry(QRect(westWidth, northHeight, rect.width() - eastWidth - westWidth, centerHeight)) def sizeHint(self): return self.calculateSize(self.SizeHint) def takeAt(self, index): if index >= 0 and index < len(self.list): layoutStruct = self.list.pop(index) return layoutStruct.item return None def add(self, item, position): self.list.append(ItemWrapper(item, position)) def calculateSize(self, sizeType): totalSize = QSize() for wrapper in self.list: position = wrapper.position itemSize = QSize() if sizeType == self.MinimumSize: itemSize = wrapper.item.minimumSize() else: # sizeType == self.SizeHint itemSize = wrapper.item.sizeHint() if position in (self.North, self.South, self.Center): totalSize.setHeight(totalSize.height() + itemSize.height()) if position in (self.West, self.East, self.Center): totalSize.setWidth(totalSize.width() + itemSize.width()) return totalSize class Window(QWidget): def __init__(self): super(Window, self).__init__() centralWidget = QTextBrowser() centralWidget.setPlainText("Central widget") layout = BorderLayout() layout.addWidget(centralWidget, BorderLayout.Center) # Because BorderLayout doesn't call its super-class addWidget() it # doesn't take ownership of the widgets until setLayout() is called. # Therefore we keep a local reference to each label to prevent it being # garbage collected too soon. label_n = self.createLabel("North") layout.addWidget(label_n, BorderLayout.North) label_w = self.createLabel("West") layout.addWidget(label_w, BorderLayout.West) label_e1 = self.createLabel("East 1") layout.addWidget(label_e1, BorderLayout.East) label_e2 = self.createLabel("East 2") layout.addWidget(label_e2, BorderLayout.East) label_s = self.createLabel("South") layout.addWidget(label_s, BorderLayout.South) self.setLayout(layout) self.setWindowTitle("Border Layout") def createLabel(self, text): label = QLabel(text) label.setFrameStyle(QFrame.Box | QFrame.Raised) return label if __name__ == '__main__': import sys app = QApplication(sys.argv) window = Window() window.show() sys.exit(app.exec_())