class HorizontalImageScrollArea(QScrollArea): def __init__(self, parent=None): super(HorizontalImageScrollArea, self).__init__(parent) self.setWidgetResizable(True) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn) self.setFrameShape(QFrame.NoFrame) self.layout = QHBoxLayout() scroll = QWidget() scroll.setLayout(self.layout) self.setWidget(scroll) def eventFilter(self, obj, event): if obj == self.widget() and event.type() == QEvent.Resize: self.widget().resize(self.calcNewSize()) return True return super(HorizontalImageScrollArea, self).eventFilter(obj, event) def calcNewSize(self): height = self.viewport().height() layoutMargins = self.layout.contentsMargins() heightForCalc = height - layoutMargins.top() - layoutMargins.bottom() width = self.calcWidthForHeight(heightForCalc) return QSize(width, height) def calcWidthForHeight(self, height): width = 0 for wgt in range(self.layout.count()): width += self.layout.itemAt(wgt).widget().widthForHeight(height) if self.layout.count() > 1: width += self.layout.spacing() * (self.layout.count() - 1) return width
class E5LineEdit(QLineEdit): """ Class implementing a line edit widget showing some inactive text. """ LeftSide = 0 RightSide = 1 def __init__(self, parent=None, inactiveText=""): """ Constructor @param parent reference to the parent widget (QWidget) @param inactiveText text to be shown on inactivity (string) """ super(E5LineEdit, self).__init__(parent) self.setMinimumHeight(22) if qVersion() < "4.7.0": self.__inactiveText = inactiveText else: self.setPlaceholderText(inactiveText) self.__mainLayout = QHBoxLayout(self) self.__mainLayout.setContentsMargins(0, 0, 0, 0) self.__mainLayout.setSpacing(0) self.__leftMargin = 0 self.__leftWidget = E5LineEditSideWidget(self) self.__leftWidget.resize(0, 0) self.__leftLayout = QHBoxLayout(self.__leftWidget) self.__leftLayout.setContentsMargins(0, 0, 2, 0) if QApplication.isRightToLeft(): self.__leftLayout.setDirection(QBoxLayout.RightToLeft) else: self.__leftLayout.setDirection(QBoxLayout.LeftToRight) self.__leftLayout.setSizeConstraint(QLayout.SetFixedSize) self.__rightWidget = E5LineEditSideWidget(self) self.__rightWidget.resize(0, 0) self.__rightLayout = QHBoxLayout(self.__rightWidget) self.__rightLayout.setContentsMargins(0, 0, 2, 0) if self.isRightToLeft(): self.__rightLayout.setDirection(QBoxLayout.RightToLeft) else: self.__rightLayout.setDirection(QBoxLayout.LeftToRight) horizontalSpacer = QSpacerItem( 0, 0, QSizePolicy.Expanding, QSizePolicy.Minimum) self.__mainLayout.addWidget( self.__leftWidget, 0, Qt.AlignVCenter | Qt.AlignLeft) self.__mainLayout.addItem(horizontalSpacer) self.__mainLayout.addWidget( self.__rightWidget, 0, Qt.AlignVCenter | Qt.AlignRight) if self.isRightToLeft(): self.__mainLayout.setDirection(QBoxLayout.RightToLeft) else: self.__mainLayout.setDirection(QBoxLayout.LeftToRight) self.setWidgetSpacing(3) self.__leftWidget.sizeHintChanged.connect(self._updateTextMargins) self.__rightWidget.sizeHintChanged.connect(self._updateTextMargins) def setLeftMargin(self, margin): """ Public method to set the left margin. @param margin left margin in pixel (integer) """ self.__leftMargin = margin def leftMargin(self): """ Public method to get the size of the left margin. @return left margin in pixel (integer) """ return self.__leftMargin def event(self, evt): """ Public method to handle events. @param evt reference to the event (QEvent) @return flag indicating, whether the event was recognized (boolean) """ if evt.type() == QEvent.LayoutDirectionChange: if self.isRightToLeft(): self.__mainLayout.setDirection(QBoxLayout.RightToLeft) self.__leftLayout.setDirection(QBoxLayout.RightToLeft) self.__rightLayout.setDirection(QBoxLayout.RightToLeft) else: self.__mainLayout.setDirection(QBoxLayout.LeftToRight) self.__leftLayout.setDirection(QBoxLayout.LeftToRight) self.__rightLayout.setDirection(QBoxLayout.LeftToRight) return QLineEdit.event(self, evt) def paintEvent(self, evt): """ Protected method handling a paint event. @param evt reference to the paint event (QPaintEvent) """ super(E5LineEdit, self).paintEvent(evt) if qVersion() < "4.7.0": if not self.text() and \ self.__inactiveText and \ not self.hasFocus(): panel = QStyleOptionFrame() self.initStyleOption(panel) textRect = self.style().subElementRect( QStyle.SE_LineEditContents, panel, self) textRect.adjust(2, 0, 0, 0) left = self.textMargin(self.LeftSide) right = self.textMargin(self.RightSide) textRect.adjust(left, 0, -right, 0) painter = QPainter(self) painter.setPen(self.palette().brush( QPalette.Disabled, QPalette.Text).color()) painter.drawText( textRect, Qt.AlignLeft | Qt.AlignVCenter, self.__inactiveText) def _updateTextMargins(self): """ Protected slot to update the text margins. """ if self.__leftMargin == 0: left = self.__leftWidget.sizeHint().width() else: left = self.__leftMargin right = self.__rightWidget.sizeHint().width() top = 0 bottom = 0 self.setTextMargins(left, top, right, bottom) def addWidget(self, widget, position): """ Public method to add a widget to a side. @param widget reference to the widget to add (QWidget) @param position position to add to (E5LineEdit.LeftSide, E5LineEdit.RightSide) """ if widget is None: return if self.isRightToLeft(): if position == self.LeftSide: position = self.RightSide else: position = self.LeftSide if position == self.LeftSide: self.__leftLayout.addWidget(widget) else: self.__rightLayout.insertWidget(1, widget) def removeWidget(self, widget): """ Public method to remove a widget from a side. @param widget reference to the widget to remove (QWidget) """ if widget is None: return self.__leftLayout.removeWidget(widget) self.__rightLayout.removeWidget(widget) widget.hide() def widgetSpacing(self): """ Public method to get the side widget spacing. @return side widget spacing (integer) """ return self.__leftLayout.spacing() def setWidgetSpacing(self, spacing): """ Public method to set the side widget spacing. @param spacing side widget spacing (integer) """ self.__leftLayout.setSpacing(spacing) self.__rightLayout.setSpacing(spacing) self._updateTextMargins() def textMargin(self, position): """ Public method to get the text margin for a side. @param position side to get margin for (E5LineEdit.LeftSide, E5LineEdit.RightSide) @return text margin (integer) """ spacing = self.__rightLayout.spacing() w = 0 if position == self.LeftSide: w = self.__leftWidget.sizeHint().width() else: w = self.__rightWidget.sizeHint().width() if w == 0: return 0 return w + spacing * 2 def inactiveText(self): """ Public method to get the inactive text. @return inactive text (string) """ if qVersion() < "4.7.0": return self.__inactiveText else: return self.placeholderText() def setInactiveText(self, inactiveText): """ Public method to set the inactive text. @param inactiveText text to be shown on inactivity (string) """ if qVersion() < "4.7.0": self.__inactiveText = inactiveText self.update() else: self.setPlaceholderText(inactiveText)
class LineEdit(QLineEdit): inactiveText = QtDynamicProperty('inactiveText', unicode) widgetSpacing = QtDynamicProperty('widgetSpacing', int) def __init__(self, parent=None, contents=u""): super(LineEdit, self).__init__(contents, parent) box_direction = QBoxLayout.RightToLeft if self.isRightToLeft() else QBoxLayout.LeftToRight self.inactiveText = u"" self.left_widget = SideWidget(self) self.left_widget.resize(0, 0) self.left_layout = QHBoxLayout(self.left_widget) self.left_layout.setContentsMargins(0, 0, 0, 0) self.left_layout.setDirection(box_direction) self.left_layout.setSizeConstraint(QLayout.SetFixedSize) self.right_widget = SideWidget(self) self.right_widget.resize(0, 0) self.right_layout = QHBoxLayout(self.right_widget) self.right_layout.setContentsMargins(0, 0, 0, 0) self.right_layout.setDirection(box_direction) self.right_layout.addItem(QSpacerItem(0, 0, QSizePolicy.Expanding, QSizePolicy.Minimum)) self.widgetSpacing = 2 self.left_widget.sizeHintChanged.connect(self._update_text_margins) self.right_widget.sizeHintChanged.connect(self._update_text_margins) @property def left_margin(self): return self.left_widget.sizeHint().width() + 2*self.left_layout.spacing() @property def right_margin(self): return self.right_widget.sizeHint().width() + 2*self.right_layout.spacing() def _update_text_margins(self): self.setTextMargins(self.left_margin, 0, self.right_margin, 0) self._update_side_widget_locations() def _update_side_widget_locations(self): option = QStyleOptionFrame() self.initStyleOption(option) spacing = self.right_layout.spacing() text_rect = self.style().subElementRect(QStyle.SE_LineEditContents, option, self) text_rect.adjust(spacing, 0, -spacing, 0) mid_height = text_rect.center().y() + 1 - (text_rect.height() % 2) # need -1 correction for odd heights -Dan if self.left_layout.count() > 0: left_height = mid_height - self.left_widget.height()/2 left_width = self.left_widget.width() if left_width == 0: left_height = mid_height - self.left_widget.sizeHint().height()/2 self.left_widget.move(text_rect.x(), left_height) text_rect.setX(self.left_margin) text_rect.setY(mid_height - self.right_widget.sizeHint().height()/2.0) text_rect.setHeight(self.right_widget.sizeHint().height()) self.right_widget.setGeometry(text_rect) def event(self, event): event_type = event.type() if event_type == QEvent.LayoutDirectionChange: box_direction = QBoxLayout.RightToLeft if self.isRightToLeft() else QBoxLayout.LeftToRight self.left_layout.setDirection(box_direction) self.right_layout.setDirection(box_direction) elif event_type == QEvent.DynamicPropertyChange: property_name = event.propertyName() if property_name == 'widgetSpacing': self.left_layout.setSpacing(self.widgetSpacing) self.right_layout.setSpacing(self.widgetSpacing) self._update_text_margins() elif property_name == 'inactiveText': self.update() return QLineEdit.event(self, event) def resizeEvent(self, event): self._update_side_widget_locations() QLineEdit.resizeEvent(self, event) def paintEvent(self, event): QLineEdit.paintEvent(self, event) if not self.hasFocus() and not self.text() and self.inactiveText: options = QStyleOptionFrame() self.initStyleOption(options) text_rect = self.style().subElementRect(QStyle.SE_LineEditContents, options, self) text_rect.adjust(self.left_margin+2, 0, -self.right_margin, 0) painter = QPainter(self) painter.setPen(self.palette().brush(QPalette.Disabled, QPalette.Text).color()) painter.drawText(text_rect, Qt.AlignLeft | Qt.AlignVCenter, self.inactiveText) def addHeadWidget(self, widget): if self.isRightToLeft(): self.right_layout.insertWidget(1, widget) else: self.left_layout.addWidget(widget) def addTailWidget(self, widget): if self.isRightToLeft(): self.left_layout.addWidget(widget) else: self.right_layout.insertWidget(1, widget) def removeWidget(self, widget): self.left_layout.removeWidget(widget) self.right_layout.removeWidget(widget) widget.hide()
class E5LineEdit(QLineEdit): """ Class implementing a line edit widget showing some inactive text. """ LeftSide = 0 RightSide = 1 def __init__(self, parent=None, inactiveText=""): """ Constructor @param parent reference to the parent widget (QWidget) @param inactiveText text to be shown on inactivity (string) """ super(E5LineEdit, self).__init__(parent) self.setMinimumHeight(22) self.setPlaceholderText(inactiveText) self.__mainLayout = QHBoxLayout(self) self.__mainLayout.setContentsMargins(0, 0, 0, 0) self.__mainLayout.setSpacing(0) self.__leftMargin = 0 self.__leftWidget = E5LineEditSideWidget(self) self.__leftWidget.resize(0, 0) self.__leftLayout = QHBoxLayout(self.__leftWidget) self.__leftLayout.setContentsMargins(0, 0, 2, 0) if QApplication.isRightToLeft(): self.__leftLayout.setDirection(QBoxLayout.RightToLeft) else: self.__leftLayout.setDirection(QBoxLayout.LeftToRight) self.__leftLayout.setSizeConstraint(QLayout.SetFixedSize) self.__rightWidget = E5LineEditSideWidget(self) self.__rightWidget.resize(0, 0) self.__rightLayout = QHBoxLayout(self.__rightWidget) self.__rightLayout.setContentsMargins(0, 0, 2, 0) if self.isRightToLeft(): self.__rightLayout.setDirection(QBoxLayout.RightToLeft) else: self.__rightLayout.setDirection(QBoxLayout.LeftToRight) horizontalSpacer = QSpacerItem(0, 0, QSizePolicy.Expanding, QSizePolicy.Minimum) self.__mainLayout.addWidget(self.__leftWidget, 0, Qt.AlignVCenter | Qt.AlignLeft) self.__mainLayout.addItem(horizontalSpacer) self.__mainLayout.addWidget(self.__rightWidget, 0, Qt.AlignVCenter | Qt.AlignRight) if self.isRightToLeft(): self.__mainLayout.setDirection(QBoxLayout.RightToLeft) else: self.__mainLayout.setDirection(QBoxLayout.LeftToRight) self.setWidgetSpacing(3) self.__leftWidget.sizeHintChanged.connect(self._updateTextMargins) self.__rightWidget.sizeHintChanged.connect(self._updateTextMargins) def setLeftMargin(self, margin): """ Public method to set the left margin. @param margin left margin in pixel (integer) """ self.__leftMargin = margin def leftMargin(self): """ Public method to get the size of the left margin. @return left margin in pixel (integer) """ return self.__leftMargin def event(self, evt): """ Public method to handle events. @param evt reference to the event (QEvent) @return flag indicating, whether the event was recognized (boolean) """ if evt.type() == QEvent.LayoutDirectionChange: if self.isRightToLeft(): self.__mainLayout.setDirection(QBoxLayout.RightToLeft) self.__leftLayout.setDirection(QBoxLayout.RightToLeft) self.__rightLayout.setDirection(QBoxLayout.RightToLeft) else: self.__mainLayout.setDirection(QBoxLayout.LeftToRight) self.__leftLayout.setDirection(QBoxLayout.LeftToRight) self.__rightLayout.setDirection(QBoxLayout.LeftToRight) return QLineEdit.event(self, evt) def paintEvent(self, evt): """ Protected method handling a paint event. @param evt reference to the paint event (QPaintEvent) """ super(E5LineEdit, self).paintEvent(evt) def _updateTextMargins(self): """ Protected slot to update the text margins. """ if self.__leftMargin == 0: left = self.__leftWidget.sizeHint().width() else: left = self.__leftMargin right = self.__rightWidget.sizeHint().width() top = 0 bottom = 0 self.setTextMargins(left, top, right, bottom) def addWidget(self, widget, position): """ Public method to add a widget to a side. @param widget reference to the widget to add (QWidget) @param position position to add to (E5LineEdit.LeftSide, E5LineEdit.RightSide) """ if widget is None: return if self.isRightToLeft(): if position == self.LeftSide: position = self.RightSide else: position = self.LeftSide if position == self.LeftSide: self.__leftLayout.addWidget(widget) else: self.__rightLayout.insertWidget(1, widget) def removeWidget(self, widget): """ Public method to remove a widget from a side. @param widget reference to the widget to remove (QWidget) """ if widget is None: return self.__leftLayout.removeWidget(widget) self.__rightLayout.removeWidget(widget) widget.hide() def widgetSpacing(self): """ Public method to get the side widget spacing. @return side widget spacing (integer) """ return self.__leftLayout.spacing() def setWidgetSpacing(self, spacing): """ Public method to set the side widget spacing. @param spacing side widget spacing (integer) """ self.__leftLayout.setSpacing(spacing) self.__rightLayout.setSpacing(spacing) self._updateTextMargins() def textMargin(self, position): """ Public method to get the text margin for a side. @param position side to get margin for (E5LineEdit.LeftSide, E5LineEdit.RightSide) @return text margin (integer) """ spacing = self.__rightLayout.spacing() w = 0 if position == self.LeftSide: w = self.__leftWidget.sizeHint().width() else: w = self.__rightWidget.sizeHint().width() if w == 0: return 0 return w + spacing * 2 def inactiveText(self): """ Public method to get the inactive text. @return inactive text (string) """ if qVersionTuple() < (4, 7, 0): return self.__inactiveText else: return self.placeholderText() def setInactiveText(self, inactiveText): """ Public method to set the inactive text. @param inactiveText text to be shown on inactivity (string) """ self.setPlaceholderText(inactiveText)
class LineEdit(QLineEdit): inactiveText = QtDynamicProperty('inactiveText', str) widgetSpacing = QtDynamicProperty('widgetSpacing', int) def __init__(self, parent=None, contents=""): super(LineEdit, self).__init__(contents, parent) box_direction = QBoxLayout.RightToLeft if self.isRightToLeft( ) else QBoxLayout.LeftToRight self.inactiveText = "" self.left_widget = SideWidget(self) self.left_widget.resize(0, 0) self.left_layout = QHBoxLayout(self.left_widget) self.left_layout.setContentsMargins(0, 0, 0, 0) self.left_layout.setDirection(box_direction) self.left_layout.setSizeConstraint(QLayout.SetFixedSize) self.right_widget = SideWidget(self) self.right_widget.resize(0, 0) self.right_layout = QHBoxLayout(self.right_widget) self.right_layout.setContentsMargins(0, 0, 0, 0) self.right_layout.setDirection(box_direction) self.right_layout.addItem( QSpacerItem(0, 0, QSizePolicy.Expanding, QSizePolicy.Minimum)) self.widgetSpacing = 2 self.left_widget.sizeHintChanged.connect(self._update_text_margins) self.right_widget.sizeHintChanged.connect(self._update_text_margins) @property def left_margin(self): return self.left_widget.sizeHint().width( ) + 2 * self.left_layout.spacing() @property def right_margin(self): return self.right_widget.sizeHint().width( ) + 2 * self.right_layout.spacing() def _update_text_margins(self): self.setTextMargins(self.left_margin, 0, self.right_margin, 0) self._update_side_widget_locations() def _update_side_widget_locations(self): option = QStyleOptionFrame() self.initStyleOption(option) spacing = self.right_layout.spacing() text_rect = self.style().subElementRect(QStyle.SE_LineEditContents, option, self) text_rect.adjust(spacing, 0, -spacing, 0) mid_height = text_rect.center().y() + 1 - ( text_rect.height() % 2) # need -1 correction for odd heights -Dan if self.left_layout.count() > 0: left_height = int(mid_height - self.left_widget.height() / 2) left_width = self.left_widget.width() if left_width == 0: left_height = int(mid_height - self.left_widget.sizeHint().height() / 2) self.left_widget.move(text_rect.x(), left_height) text_rect.setX(self.left_margin) text_rect.setY( int(mid_height - self.right_widget.sizeHint().height() / 2.0)) text_rect.setHeight(self.right_widget.sizeHint().height()) self.right_widget.setGeometry(text_rect) def event(self, event): event_type = event.type() if event_type == QEvent.LayoutDirectionChange: box_direction = QBoxLayout.RightToLeft if self.isRightToLeft( ) else QBoxLayout.LeftToRight self.left_layout.setDirection(box_direction) self.right_layout.setDirection(box_direction) elif event_type == QEvent.DynamicPropertyChange: property_name = event.propertyName() if property_name == 'widgetSpacing': self.left_layout.setSpacing(self.widgetSpacing) self.right_layout.setSpacing(self.widgetSpacing) self._update_text_margins() elif property_name == 'inactiveText': self.update() return QLineEdit.event(self, event) def resizeEvent(self, event): self._update_side_widget_locations() QLineEdit.resizeEvent(self, event) def paintEvent(self, event): QLineEdit.paintEvent(self, event) if not self.hasFocus() and not self.text() and self.inactiveText: options = QStyleOptionFrame() self.initStyleOption(options) text_rect = self.style().subElementRect(QStyle.SE_LineEditContents, options, self) text_rect.adjust(self.left_margin + 2, 0, -self.right_margin, 0) painter = QPainter(self) painter.setPen(self.palette().brush(QPalette.Disabled, QPalette.Text).color()) painter.drawText(text_rect, Qt.AlignLeft | Qt.AlignVCenter, self.inactiveText) def addHeadWidget(self, widget): if self.isRightToLeft(): self.right_layout.insertWidget(1, widget) else: self.left_layout.addWidget(widget) def addTailWidget(self, widget): if self.isRightToLeft(): self.left_layout.addWidget(widget) else: self.right_layout.insertWidget(1, widget) def removeWidget(self, widget): self.left_layout.removeWidget(widget) self.right_layout.removeWidget(widget) widget.hide()