class FormWidget(QFrame, object): accepted = Signal(object) stateChanged = Signal() validated = Signal() def __init__(self, *args, **kwargs): super(FormWidget, self).__init__(*args, **kwargs) self._schema = dict() self._widgets = list() self._validator = None main_layout = layouts.VerticalLayout(spacing=0, margins=(0, 0, 0, 0)) self.setLayout(main_layout) self._fields_frame = QFrame(self) self._fields_frame.setObjectName('fieldsFrame') options_layout = layouts.VerticalLayout(spacing=0, margins=(0, 0, 0, 0)) self._fields_frame.setLayout(options_layout) self._title_widget = buttons.BaseButton(parent=self) self._title_widget.setCheckable(True) self._title_widget.setObjectName('titleWidget') self._title_widget.toggled.connect(self._on_title_clicked) self._title_widget.hide() main_layout.addWidget(self._title_widget) main_layout.addWidget(self._fields_frame) # ================================================================================================================= # OVERRIDES # ================================================================================================================= def closeEvent(self, event): self.save_persistent_values() super(FormWidget, self).closeEvent(event) # ================================================================================================================= # BASE # ================================================================================================================= def title_widget(self): """ Returns the title widget :return: QWidget """ return self._title_widget def set_title(self, title): """ Sets the title text :param title: str """ self.title_widget().setText(title) def is_expanded(self): """ Returns whether the item is expanded or not :return: bool """ return self._title_widget.isChecked() def set_expanded(self, flag): """ Expands the options if True, otherwise collapses the options :param flag: bool """ with qt_contexts.block_signals(self._title_widget): self._title_widget.setChecked(flag) self._fields_frame.setVisible(flag) def set_title_visible(self, flag): """ Sets whether the title widget is visible or not :param flag: bool """ self.title_widget().setVisible(flag) def widget(self, name): """ Returns the widget for the given widget name :param name: str :return: FieldWidget """ for widget in self._widgets: if widget.data().get('name') == name: return widget def value(self, name): """ Returns the value for the given widget name :param name: str :return: object """ widget = self.widget(name) return widget.value() def set_value(self, name, value): """ Sets the value for the given field name :param name: str :param value: variant """ widget = self.widget(name) widget.set_value(value) def values(self): """ Returns all the field values indexed by the field name :return: dict """ values = dict() for widget in self._widgets: name = widget.data().get('name') if name: values[name] = widget.value() return values def set_values(self, values): """ Sets the field values for the current form :param values: dict """ state = list() for name in values: state.append({'name': name, 'value': values[name]}) self._set_state(state) def default_values(self): """ Returns all teh default field values indexed by the field name :return: dict """ values = dict() for widget in self._widgets: name = widget.data().get('name') if name: values[name] = widget.default() return values def set_data(self, name, data): """ Sets the data for the given field name :param name: str :param data: dict """ widget = self.widget(name) if not widget: return widget.set_data(data) def fields(self): """ Returns fields data for the form :return: list(dict) """ options = list() for widget in self._widgets: options.append(widget.data()) return options def field_widgets(self): """ Returns all field widgets :return: list(FieleWidget) """ return self._widgets def state(self): """ Returns the current state :return: dict """ fields = list() for widget in self._widgets: fields.append(widget.state()) state = {'fields': fields, 'expanded': self.is_expanded()} return state def set_state(self, state): """ Sets the current state :param state: dict """ expanded = state.get('expanded') if expanded is not None: self.set_expanded(expanded) fields = state.get('fields') if fields is not None: self._set_state(fields) self.validate() def schema(self): """ Returns form's schema :return: dict """ return self._schema def set_schema(self, schema, layout=None, errors_visible=False): """ Sets the schema for the widget :param schema: list(dict) :param layout: str :param errors_visible: str """ self._schema = self._sort_schema(schema) for field in schema: cls = formfields.FIELD_WIDGET_REGISTRY.get( field.get('type', 'label')) if not cls: LOGGER.warning('Cannot find widget for {}'.format(field)) continue if layout and not field.get('layout'): field['layout'] = layout error_visible = field.get('errorVisible') field[ 'errorVisible'] = error_visible if error_visible is not None else errors_visible widget = cls(data=field, parent=self._fields_frame, form_widget=self) data = widget.default_data() data.update(field) widget.set_data(data) value = field.get('value') default = field.get('default') if value is None and default is not None: widget.set_value(default) self._widgets.append(widget) callback = partial(self._on_field_changed, widget) widget.valueChanged.connect(callback) self._fields_frame.layout().addWidget(widget) self.load_persistent_values() def validator(self): """ Returns the validator for the form :return: fn """ return self._validator def set_validator(self, validator): """ Sets the validator for the options :param validator: fn """ self._validator = validator def reset(self): """ Reset all option widget back to the ir default values """ for widget in self._widgets: widget.reset() self.validate() def validate(self, widget=None): """ Validates the current options using the validator """ if not self._validator: return values = dict() for name, value in self.values().items(): data = self.widget(name).data() if data.get('validate', True): values[name] = value if widget: values['fieldChanged'] = widget.name() fields = self._validator(**values) if fields is not None: self._set_state(fields) self.validated.emit() def errors(self): """ Returns all form errors :return: list(str) """ errors = list() for widget in self._widgets: error = widget.data().get('error') if error: errors.append(error) return errors def has_errors(self): """ Returns whether the form contains any error :return: bool """ return bool(self.errors()) def save_persistent_values(self): """ Saves form widget values Triggered when the user changes field values """ data = dict() for widget in self._widgets: name = widget.data().get('name') if name and widget.data().get('persistent'): key = self.objectName() or 'FormWidget' key = widget.data().get('persistentKey', key) data.setdefault(key, dict()) data[key][name] = widget.value() for key in data: settings.set(key, data[key]) def load_persistent_values(self): """ Returns the options from the user settings :return: dict """ values = dict() default_values = self.default_values() for field in self.schema(): name = field.get('name') persistent = field.get('persistent') if persistent: key = self.objectName() or 'FormWidget' key = field.get('persistentKey', key) value = settings.get(key, dict()).get(name) else: value = default_values.get(name) if value is not None: values[name] = value self.set_values(values) # ============================================================================================================ # INTERNAL # ============================================================================================================ def _sort_schema(self, schema): """ Internal function that sorts the schema depending on the group order :param schema: list(dict) :return: list(dict) """ def _key(field): return field['order'] order = 0 for i, field in enumerate(schema): if field.get('type') == 'group': order = field.get('order', order) field['order'] = order return sorted(schema, key=_key) def _set_state(self, fields): """ Internal function that sets fields state :param fields: list(dict) """ for widget in self._widgets: widget.blockSignals(True) try: for widget in self._widgets: widget.set_error('') for field in fields: if field.get('name') == widget.data().get('name'): widget.set_data(field) finally: for widget in self._widgets: widget.blockSignals(False) self.stateChanged.emit() # ============================================================================================================ # CALLBACKS # ============================================================================================================ def _on_title_clicked(self, toggle): """ Internal callback function that is triggered when the user clicks in the title widget """ self.set_expanded(toggle) self.stateChanged.emit() def _on_field_changed(self, widget): """ Internal callback function triggered when the given option widget changes its value :param widget: FieldWidget """ self.validate(widget=widget)
def ui(self): super(LoadWidget, self).ui() tabs_widget = tabs.BaseTabWidget(parent=self) info_widget = QWidget() info_layout = layouts.VerticalLayout(spacing=0, margins=(0, 0, 0, 0)) info_widget.setLayout(info_layout) if self.OPTIONS_WIDGET: self._options_widget = self.OPTIONS_WIDGET(parent=self) title_layout = layouts.HorizontalLayout(spacing=1, margins=(1, 1, 0, 0)) self._icon_lbl = label.BaseLabel('', parent=self) self._icon_lbl.setMaximumSize(QSize(14, 14)) self._icon_lbl.setMinimumSize(QSize(14, 14)) self._icon_lbl.setScaledContents(True) self._title_lbl = label.BaseLabel('Title', parent=self) title_layout.addWidget(self._icon_lbl) title_layout.addWidget(self._title_lbl) icon_toggle_box = QFrame() icon_toggle_box.setFrameShape(QFrame.NoFrame) icon_toggle_box.setFrameShadow(QFrame.Plain) icon_toggle_box_lyt = layouts.VerticalLayout(spacing=1, margins=(0, 1, 0, 0)) icon_toggle_box.setLayout(icon_toggle_box_lyt) icon_toggle_box_header = QFrame() icon_toggle_box_header.setFrameShape(QFrame.NoFrame) icon_toggle_box_header.setFrameShadow(QFrame.Plain) icon_toggle_box_header_lyt = layouts.VerticalLayout(spacing=0, margins=(0, 0, 0, 0)) icon_toggle_box_header.setLayout(icon_toggle_box_header_lyt) self._icon_toggle_box_btn = buttons.BaseButton('ICON', parent=self) self._icon_toggle_box_btn.setObjectName('iconButton') self._icon_toggle_box_btn.setCheckable(True) self._icon_toggle_box_btn.setChecked(True) icon_toggle_box_header_lyt.addWidget(self._icon_toggle_box_btn) self._icon_toggle_box_frame = QFrame() self._icon_toggle_box_frame.setFrameShape(QFrame.NoFrame) self._icon_toggle_box_frame.setFrameShadow(QFrame.Plain) icon_toggle_box_frame_lyt = layouts.VerticalLayout(spacing=1, margins=(0, 1, 0, 0)) self._icon_toggle_box_frame.setLayout(icon_toggle_box_frame_lyt) thumbnail_layout = layouts.HorizontalLayout(spacing=0, margins=(0, 0, 0, 0)) icon_toggle_box_frame_lyt.addLayout(thumbnail_layout) thumbnail_frame_layout = layouts.VerticalLayout(spacing=0, margins=(0, 0, 0, 0)) self._thumbnail_frame = QFrame() self._thumbnail_frame.setFrameShape(QFrame.NoFrame) self._thumbnail_frame.setFrameShadow(QFrame.Plain) self._thumbnail_frame.setLayout(thumbnail_frame_layout) thumbnail_layout.addWidget(self._thumbnail_frame) self._thumbnail_btn = QToolButton() self._thumbnail_btn.setObjectName('thumbnailButton') self._thumbnail_btn.setMinimumSize(QSize(0, 0)) self._thumbnail_btn.setMaximumSize(QSize(150, 150)) self._thumbnail_btn.setStyleSheet( 'color: rgb(40, 40, 40);\nborder: 1px solid rgb(0, 0, 0, 0);\nbackground-color: rgb(254, 255, 230, 0);' ) self._thumbnail_btn.setLayoutDirection(Qt.LeftToRight) self._thumbnail_btn.setText('Snapshot') self._thumbnail_btn.setIcon(resources.icon('thumbnail')) thumbnail_frame_layout.addWidget(self._thumbnail_btn) icon_toggle_box_lyt.addWidget(icon_toggle_box_header) icon_toggle_box_lyt.addWidget(self._icon_toggle_box_frame) info_toggle_box = QFrame() info_toggle_box.setFrameShape(QFrame.NoFrame) info_toggle_box.setFrameShadow(QFrame.Plain) info_toggle_box_lyt = layouts.VerticalLayout(spacing=0, margins=(0, 0, 0, 0)) info_toggle_box.setLayout(info_toggle_box_lyt) info_toggle_box_header = QFrame() info_toggle_box_header.setFrameShape(QFrame.NoFrame) info_toggle_box_header.setFrameShadow(QFrame.Plain) info_toggle_box_header_lyt = layouts.VerticalLayout(spacing=0, margins=(0, 0, 0, 0)) info_toggle_box_header.setLayout(info_toggle_box_header_lyt) self._info_toggle_box_btn = buttons.BaseButton('INFO', parent=self) self._info_toggle_box_btn.setObjectName('infoButton') self._info_toggle_box_btn.setCheckable(True) self._info_toggle_box_btn.setChecked(True) info_toggle_box_header_lyt.addWidget(self._info_toggle_box_btn) self._info_toggle_box_frame = QFrame() self._info_toggle_box_frame.setFrameShape(QFrame.NoFrame) self._info_toggle_box_frame.setFrameShadow(QFrame.Plain) info_toggle_box_frame_lyt = layouts.VerticalLayout(spacing=1, margins=(0, 1, 0, 0)) self._info_toggle_box_frame.setLayout(info_toggle_box_frame_lyt) self._info_frame = QFrame() self._info_frame.setFrameShape(QFrame.NoFrame) self._info_frame.setFrameShadow(QFrame.Plain) info_frame_lyt = layouts.VerticalLayout(spacing=0, margins=(0, 0, 0, 0)) self._info_frame.setLayout(info_frame_lyt) info_toggle_box_frame_lyt.addWidget(self._info_frame) info_toggle_box_lyt.addWidget(info_toggle_box_header) info_toggle_box_lyt.addWidget(self._info_toggle_box_frame) version_toggle_box = QFrame() version_toggle_box.setFrameShape(QFrame.NoFrame) version_toggle_box.setFrameShadow(QFrame.Plain) version_toggle_box_lyt = layouts.VerticalLayout(spacing=0, margins=(0, 0, 0, 0)) version_toggle_box.setLayout(version_toggle_box_lyt) version_toggle_box_header = QFrame() version_toggle_box_header.setFrameShape(QFrame.NoFrame) version_toggle_box_header.setFrameShadow(QFrame.Plain) version_toggle_box_header_lyt = layouts.VerticalLayout(spacing=0, margins=(0, 0, 0, 0)) version_toggle_box_header.setLayout(version_toggle_box_header_lyt) self._version_toggle_box_btn = buttons.BaseButton('VERSION', parent=self) self._version_toggle_box_btn.setObjectName('versionButton') self._version_toggle_box_btn.setCheckable(True) self._version_toggle_box_btn.setChecked(True) version_toggle_box_header_lyt.addWidget(self._version_toggle_box_btn) self._version_toggle_box_frame = QFrame() self._version_toggle_box_frame.setFrameShape(QFrame.NoFrame) self._version_toggle_box_frame.setFrameShadow(QFrame.Plain) version_toggle_box_frame_lyt = layouts.VerticalLayout(spacing=1, margins=(0, 1, 0, 0)) self._version_toggle_box_frame.setLayout(version_toggle_box_frame_lyt) self._version_frame = QFrame() self._version_frame.setFrameShape(QFrame.NoFrame) self._version_frame.setFrameShadow(QFrame.Plain) version_frame_lyt = layouts.VerticalLayout(spacing=0, margins=(0, 0, 0, 0)) self._version_frame.setLayout(version_frame_lyt) version_toggle_box_frame_lyt.addWidget(self._version_frame) self._history_widget = self.HISTORY_WIDGET() version_frame_lyt.addWidget(self._history_widget) version_toggle_box_lyt.addWidget(version_toggle_box_header) version_toggle_box_lyt.addWidget(self._version_toggle_box_frame) preview_buttons_frame = QFrame() preview_buttons_frame.setObjectName('previewButtons') preview_buttons_frame.setFrameShape(QFrame.NoFrame) preview_buttons_frame.setFrameShadow(QFrame.Plain) self._preview_buttons_frame_lyt = layouts.VerticalLayout(spacing=0, margins=(2, 2, 2, 2)) self._preview_buttons_lyt = layouts.HorizontalLayout(spacing=2, margins=(0, 0, 0, 0)) self._load_btn = buttons.BaseButton('Load', parent=self) self._load_btn.setObjectName('loadButton') self._load_btn.setMinimumSize(QSize(60, 35)) self._load_btn.setMaximumSize(QSize(125, 35)) self._preview_buttons_frame_lyt.addStretch() self._preview_buttons_frame_lyt.addLayout(self._preview_buttons_lyt) self._preview_buttons_frame_lyt.addStretch() self._preview_buttons_lyt.addWidget(self._load_btn) preview_buttons_frame.setLayout(self._preview_buttons_frame_lyt) info_layout.addLayout(title_layout) info_layout.addWidget(icon_toggle_box) info_layout.addWidget(info_toggle_box) info_layout.addWidget(version_toggle_box) tabs_widget.addTab(info_widget, 'Info') if self._options_widget: tabs_widget.addTab(self._options_widget, 'Options') self.main_layout.addWidget(tabs_widget) self.main_layout.addWidget(dividers.Divider()) self.main_layout.addWidget(preview_buttons_frame) self.main_layout.addItem( QSpacerItem(0, 250, QSizePolicy.Preferred, QSizePolicy.Expanding))
class GroupBoxWidget(base.BaseFrame): toggled = Signal(bool) def __init__(self, title, widget, persistent=False, settings=None, *args, **kwargs): self._title = title self._widget = None self._persistent = None self._settings = settings super(GroupBoxWidget, self).__init__(*args, **kwargs) if widget: self.set_widget(widget) # We force the update of the check status to make sure that the wrapped widget visibility is updated self.set_checked(self.is_checked()) self.set_persistent(persistent) # ============================================================================================================ # OVERRIDES # ============================================================================================================ def get_main_layout(self): return layouts.VerticalLayout(spacing=0, margins=(0, 0, 0, 0)) def ui(self): super(GroupBoxWidget, self).ui() self._title_widget = buttons.BaseButton(self._title, parent=self) self._title_widget.setCheckable(True) self._on_icon = resources.icon('down_button') self._off_icon = resources.icon('right_button') self._title_widget.setIcon(self._off_icon) self._widget_frame = QFrame(self) self._widget_frame.setObjectName('contentsWidget') widget_frame_layout = layouts.VerticalLayout(spacing=2, margins=(0, 0, 0, 0)) self._widget_frame.setLayout(widget_frame_layout) self.main_layout.addWidget(self._title_widget) self.main_layout.addWidget(self._widget_frame) def setup_signals(self): self._title_widget.toggled.connect(self._on_toggled_title) # ============================================================================================================ # BASE # ============================================================================================================ def is_checked(self): """ Returns whether or not group box is checked :return: bool """ return self._title_widget.isChecked() def set_checked(self, flag): """ Sets the check statue of the group box :param flag: bool """ self._title_widget.setChecked(flag) self._title_widget.setIcon(self._on_icon if flag else self._off_icon) self._widget_frame.setVisible(flag) if self._widget: self._widget.setVisible(flag) def is_persistent(self): """ Returns whether or not widget state is stored in settings :return: bool """ return self._persistent def set_persistent(self, flag): """ Sets whether or not widget state is stored in settings :param flag: bool """ self._persistent = flag self.load_settings() def title(self): """ Returns group box title :return: str """ return self._title_widget.text() def set_widget(self, widget): """ Sets the widget to hide when the user clicks the title :param widget: QWidget """ self._widget = widget self._widget.setParent(self._widget_frame) self._widget_frame.layout().addWidget(self._widget) # ============================================================================================================ # SETTINGS # ============================================================================================================ def load_settings(self): """ Loads widget state from given settings """ if not self._settings or not self._persistent: return if not self.objectName(): raise NameError( 'Impossible to save "{}" widget state because no objectName is defined!' .format(self)) data = {self.objectName(): {'checked': self.is_checked()}} self._settings.save(data) def save_settings(self): """ Saves current widget state into settings """ if not self._settings or not self._persistent: return if not self.objectName(): raise NameError( 'Impossible to load "{}" widget state because no objectName is defined!' .format(self)) data = self._settings.read() data = data.get(self.objectName(), dict()) if data and isinstance(data, dict): checked = data.get('checked', True) self.set_checked(checked) # ============================================================================================================ # CALLBACKS # ============================================================================================================ def _on_toggled_title(self, flag): """ Internal callback function that is called each time title group widget is toggled :param flag: bool """ self.save_settings() self.set_checked(flag) self.toggled.emit(flag)
class MessageBox(QDialog, object): MAX_WIDTH = 320 MAX_HEIGHT = 220 @staticmethod def input(parent, title, text, input_text='', width=None, height=None, buttons=None, header_pixmap=None, header_color=None, theme_to_apply=None): """ Helper dialog function to get a single text value from the user :param parent: QWidget :param title: str :param text: str :param input_text: str :param width: int :param height: int :param buttons: list(QDialogButtonBox.StandardButton) :param header_pixmap: QPixmap :param header_color: str :param theme_to_apply: Theme :return: QMessageBox.StandardButton """ buttons = buttons or QDialogButtonBox.Ok | QDialogButtonBox.Cancel dialog = create_message_box(parent=parent, title=title, text=text, width=width, height=height, buttons=buttons, header_pixmap=header_pixmap, header_color=header_color, enable_input_edit=True, theme_to_apply=theme_to_apply) dialog.set_input_text(input_text) dialog.exec_() clicked_btn = dialog.clicked_standard_button() return dialog.input_text(), clicked_btn @staticmethod def question(parent, title, text, width=None, height=None, buttons=None, header_pixmap=None, header_color=None, enable_dont_show_checkbox=False, theme_to_apply=None): """ Helper dialog function to get a single text value from the user :param parent: QWidget :param title: str :param text: str :param width: int :param height: int :param buttons: list(QDialogButtonBox.StandardButton) :param header_pixmap: QPixmap :param header_color: str :param enable_dont_show_checkbox: bool :param theme_to_apply: Theme :return: QDialogButtonBox.StandardButton """ buttons = buttons or QDialogButtonBox.Yes | QDialogButtonBox.No | QDialogButtonBox.Cancel clicked_btn = show_message_box(parent=parent, title=title, text=text, width=width, height=height, buttons=buttons, header_pixmap=header_pixmap, header_color=header_color, enable_dont_show_checkbox=enable_dont_show_checkbox, theme_to_apply=theme_to_apply) return clicked_btn @staticmethod def warning(parent, title, text, width=None, height=None, buttons=None, header_pixmap=None, header_color='rgb(250, 160, 0)', enable_dont_show_checkbox=False, force=False): """ Helper dialog function to open a warning message box with the given options :param parent: QWidget :param title: str :param text: str :param width: int :param height: int :param buttons: list(QDialogButtonBox.StandardButton) :param header_pixmap: QPixmap :param header_color: str :param enable_dont_show_checkbox: bool :param force: bool :return: QDialogButtonBox.StandardButton """ buttons = buttons or QDialogButtonBox.Yes | QDialogButtonBox.No clicked_btn = show_message_box(parent=parent, title=title, text=text, width=width, height=height, buttons=buttons, header_pixmap=header_pixmap, header_color=header_color, enable_dont_show_checkbox=enable_dont_show_checkbox, force=force) return clicked_btn @staticmethod def critical(parent, title, text, width=None, height=None, buttons=None, header_pixmap=None, header_color='rgb(230, 80, 80)'): """ Helper dialog function to open a critical/error message box with the given options :param parent: QWidget :param title: str :param text: str :param width: int :param height: int :param buttons: list(QDialogButtonBox.StandardButton) :param header_pixmap: QPixmap :param header_color: str :return: QDialogButtonBox.StandardButton """ buttons = buttons or QDialogButtonBox.Ok | QDialogButtonBox.Cancel clicked_btn = show_message_box(parent=parent, title=title, text=text, width=width, height=height, buttons=buttons, header_pixmap=header_pixmap, header_color=header_color) return clicked_btn def __init__(self, name='messageBox', width=None, height=None, enable_input_edit=False, enable_dont_show_checkbox=False, parent=None): super(MessageBox, self).__init__(parent=parent) self._frame = None self._animation = None self._dont_show_checkbox = False self._clicked_button = None self._clicked_standard_button = None self.setMinimumWidth(width or self.MAX_WIDTH) self.setMinimumHeight(height or self.MAX_HEIGHT) self.setObjectName(name) self.setWindowFlags(self.windowFlags() | Qt.FramelessWindowHint) # self.setAttribute(Qt.WA_TranslucentBackground) # self.setStyleSheet('background-color: rgb(68, 68, 68, 255);') parent = self.parent() self._frame = None if parent and parent != dcc.get_main_window(): parent.installEventFilter(self) self._frame = QFrame(parent) self._frame.setStyleSheet('background-color: rgba(25, 25, 25, 150);') self._frame.setObjectName('messageBoxFrame') self._frame.show() self.setParent(self._frame) self.main_layout = layouts.VerticalLayout(spacing=0, margins=(0, 0, 0, 0)) self.setLayout(self.main_layout) self._header = QFrame(self) self._header.setFixedHeight(46) self._header.setObjectName('messageBoxHeaderFrame') self._header.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self._icon = label.BaseLabel(parent=self._header) self._icon.hide() self._icon.setFixedHeight(32) self._icon.setFixedHeight(32) self._icon.setScaledContents(True) self._icon.setAlignment(Qt.AlignTop) self._icon.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) self._title = label.BaseLabel(parent=self._header) self._title.setObjectName('messageBoxHeaderLabel') self._title.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) hlayout = layouts.HorizontalLayout(spacing=10, margins=(15, 7, 15, 10)) hlayout.addWidget(self._icon) hlayout.addWidget(self._title) self._header.setLayout(hlayout) body_layout = layouts.VerticalLayout() self._body = QFrame(self) self._body.setObjectName('messageBoxBody') self._body.setLayout(body_layout) self._message = label.BaseLabel(parent=self._body) self._message.setWordWrap(True) self._message.setMinimumHeight(15) self._message.setAlignment(Qt.AlignLeft) self._message.setTextInteractionFlags(Qt.TextSelectableByMouse) self._message.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) body_layout.addWidget(self._message) body_layout.setContentsMargins(15, 15, 15, 15) if enable_input_edit: self._input_edit = lineedit.BaseLineEdit(parent=self._body) self._input_edit.setObjectName('messageBoxInputEdit') self._input_edit.setMinimumHeight(32) self._input_edit.setFocus() body_layout.addStretch(1) body_layout.addWidget(self._input_edit) body_layout.addStretch(10) if enable_dont_show_checkbox: msg = 'Do not show this message again' self._dont_show_checkbox = checkbox.BaseCheckBox(msg, parent=self._body) body_layout.addStretch(10) body_layout.addWidget(self._dont_show_checkbox) body_layout.addStretch(2) self._button_box = QDialogButtonBox(None, Qt.Horizontal, self) self._button_box.clicked.connect(self._on_clicked) self._button_box.accepted.connect(self._on_accept) self._button_box.rejected.connect(self._on_reject) self.main_layout.addWidget(self._header) self.main_layout.addWidget(self._body) body_layout.addWidget(self._button_box) self.updateGeometry() def eventFilter(self, object, event): """ Overrides base QDialog eventFilter function Updates the geometry when the parnet widget changes size :param object: QWidget :param event: QEvent """ if event.type() == QEvent.Resize: self.updateGeometry() return super(MessageBox, self).eventFilter(object, event) def showEvent(self, event): """ Overrides base QDialog showEvent function Fade in hte dialog on show :param event: QEvent """ self.updateGeometry() self._fade_in() def keyPressEvent(self, event): if event.key() != Qt.Key_Escape: super(MessageBox, self).keyPressEvent(event) def updateGeometry(self): """ Overrides base QDialog updateGeometry function Updates the geometry to be in the center of it's parent """ frame = self._frame if frame: frame.setGeometry(self._frame.parent().geometry()) frame.move(0, 0) geometry = self.geometry() center_point = frame.geometry().center() geometry.moveCenter(center_point) geometry.setY(geometry.y() - 50) self.move(geometry.topLeft()) def exec_(self): """ Overrides base QDialog exec_ function Shows the dialog as a modal dialog :return: variant, int or None """ super(MessageBox, self).exec_() return self.clicked_index() def button_box(self): """ Returns the button box widget for the dialog :return: QDialogButtonBox """ return self._button_box def header(self): """ Returns the header frame :return: QFrame """ return self._header def set_header_color(self, color): """ Sets the header color for the message box :param color: str """ self.header().setStyleSheet('background-color: {}'.format(color)) def set_title_text(self, text): """ Sets the title text to be displayed :param text: str """ self._title.setText(text) def set_text(self, text): """ Sets the text message to be displayed :param text: str """ self._message.setText(str(text)) def input_text(self): """ Returns the text that the user has given in the input edit :return: str """ return self._input_edit.text() def set_input_text(self, text): """ Sets the input text :param text: str """ self._input_edit.setText(text) if text: self._input_edit.selectAll() def add_button(self, *args): """ Adds a new upsh button with the given text and roled """ self.button_box().addButton(*args) def set_buttons(self, buttons): """ Sets the buttons to be displayed in message box :param buttons: QMessageBox.StandardButton """ self.button_box().setStandardButtons(buttons) def set_pixmap(self, pixmap): """ Sets the pixmap for the message box :param pixmap: QPixmap """ self._icon.setPixmap(pixmap) self._icon.show() def clicked_button(self): """ Returns the button that was clicked :return: variant, QPushButton or None """ return self._clicked_button def clicked_index(self): """ Returns the button that was clicked by its index :return: variant, int or None """ for i, btn in enumerate(self.button_box().buttons()): if btn == self.clicked_button(): return i def clicked_standard_button(self): """ Returns the button that was clicked by the user :return: variant, QMessageBox.StandardButton or None """ return self._clicked_standard_button def is_dont_show_checkbox_checked(self): """ Returns the checked state of the dont show again checkbox :return: bool """ if self._dont_show_checkbox: return self._dont_show_checkbox.isChecked() else: return False def _fade_in(self, duration=200): """ Internal function that fade in the dialog using opacity effect :param duration: int :return: QPropertyAnimation """ if self._frame: self._animation = animation.fade_in_widget(self._frame, duration=duration) return self._animation def _fade_out(self, duration=200): """ Internal function that fade out the dialog using opacity effect :param duration: int :return: QPropertyAnimation """ if self._frame: self._animation = animation.fade_out_widget(self._frame, duration=duration) return self._animation def _on_clicked(self, button): """ Internal callback function triggered when the user clicks a button :param button: QPushButton """ self._clicked_button = button self._clicked_standard_button = self.button_box().standardButton(button) def _on_accept(self): """ Internal callback function triggered when the DialogButtonBox has been accepted """ anim = self._fade_out() if anim: anim.finished.connect(self._on_accept_animation_finished) else: self._on_accept_animation_finished() def _on_reject(self): """ Internal callback function triggered when the DialogButtonBox has been rejected """ anim = self._fade_out() if anim: anim.finished.connect(self._on_reject_animation_finished) else: self._on_reject_animation_finished() def _on_accept_animation_finished(self): """ Internal callback function triggered when the animation has finished on accepted """ parent = self._frame or self parent.close() self.accept() def _on_reject_animation_finished(self): parent = self._frame or self parent.close() self.reject()