Skip to content

cellects.gui.custom_widgets

cellects.gui.custom_widgets

This module contains all modified/simplified widgets from PySide6 It is made to be easier to use and to be consistant in terms of colors and sizes.

MainTabsWidget

Bases: QPushButton

A custom QPushButton that mimics an explorer tab appearance.

Features: - Customizable text - Night mode support - Three states: not_in_use (grey border), in_use (black border), not_usable (grey text) - Tooltip support for not_usable state

Source code in src/cellects/gui/custom_widgets.py
class MainTabsWidget(QtWidgets.QPushButton):
    """
    A custom QPushButton that mimics an explorer tab appearance.

    Features:
    - Customizable text
    - Night mode support
    - Three states: not_in_use (grey border), in_use (black border), not_usable (grey text)
    - Tooltip support for not_usable state
    """

    def __init__(self, text="", night_mode=False, parent=None):
        super().__init__()

        self.setText(text)
        self.state = "not_in_use"  # States: "not_in_use", "in_use", "not_usable"
        self.setFont(buttonfont)

        # Set basic properties
        self.setSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed)
        self.setFixedHeight(35)
        self.setCursor(QtCore.Qt.CursorShape.PointingHandCursor)

        self.night_mode_switch(night_mode)


    def night_mode_switch(self, night_mode):
        self._night_mode = night_mode
        self.update_style()

    def update_style(self):
        """Update the widget's stylesheetµ"""

        if self.state == "not_usable":
            tab_text_color = "#888888"
            self.setCursor(QtCore.Qt.CursorShape.ForbiddenCursor)
        else:
            if self._night_mode:
                tab_text_color = night_text_Color
            else:
                tab_text_color = textColor
            if self.state == "not_in_use":
                self.setCursor(QtCore.Qt.CursorShape.PointingHandCursor)
        if self.state == "in_use":
            border_width = 2
            if self._night_mode:
                tab_border = f"{border_width}px solid #adadad"
            else:
                tab_border = f"{border_width}px solid #323241"
        else:
            border_width = 1
            if self._night_mode:
                tab_border = f"{border_width}px solid #323241"
            else:
                tab_border = f"{border_width}px solid #adadad"

        if self._night_mode:
            style = {"buttoncolor": night_button_color, "buttontextColor": tab_text_color, "border": tab_border,
                     "font_family": tabfont, "font_size": "22pt", #"font_weight": "bold",
                     "border-top-color": "#323241", "border-right-color": "#323241", # invisible
                     "border-top-left-radius": "10", "border-bottom-left-radius": "1"}
        else:
            style = {"buttoncolor": buttoncolor, "buttontextColor": tab_text_color, "border": tab_border,
                     "font_family": tabfont, "font_size": "22pt", #"font_weight": "bold",
                     "border-top-color": "#ffffff", "border-right-color": "#ffffff", # invisible
                     "border-top-left-radius": "10", "border-bottom-left-radius": "1"
                     }
        self.setStyleSheet(
            "background-color: %s; color: %s; border: %s; font-family: %s; font-size: %s;  border-top-color: %s; border-right-color: %s; border-top-left-radius: %s; border-bottom-left-radius: %s" % tuple(style.values()))


    def set_in_use(self):
        """Set the tab to 'in_use' state with black border."""
        self.state = "in_use"
        self.setToolTip("")  # Clear any tooltip
        self.update_style()

    def set_not_in_use(self):
        """Set the tab to 'not_in_use' state with grey border."""
        self.state = "not_in_use"
        self.setToolTip("")  # Clear any tooltip
        self.update_style()

    def set_not_usable(self, tooltip_text="This tab is not usable"):
        """
        Set the tab to 'not_usable' state with grey text.

        Args:
            tooltip_text (str): Custom tooltip text to show when hovering
        """
        self.state = "not_usable"
        self.setToolTip(tooltip_text)
        self.update_style()

    def get_state(self):
        """Get the current state of the tab."""
        return self.state

    def is_night_mode(self):
        """Check if night mode is enabled."""
        return self._night_mode

get_state()

Get the current state of the tab.

Source code in src/cellects/gui/custom_widgets.py
def get_state(self):
    """Get the current state of the tab."""
    return self.state

is_night_mode()

Check if night mode is enabled.

Source code in src/cellects/gui/custom_widgets.py
def is_night_mode(self):
    """Check if night mode is enabled."""
    return self._night_mode

set_in_use()

Set the tab to 'in_use' state with black border.

Source code in src/cellects/gui/custom_widgets.py
def set_in_use(self):
    """Set the tab to 'in_use' state with black border."""
    self.state = "in_use"
    self.setToolTip("")  # Clear any tooltip
    self.update_style()

set_not_in_use()

Set the tab to 'not_in_use' state with grey border.

Source code in src/cellects/gui/custom_widgets.py
def set_not_in_use(self):
    """Set the tab to 'not_in_use' state with grey border."""
    self.state = "not_in_use"
    self.setToolTip("")  # Clear any tooltip
    self.update_style()

set_not_usable(tooltip_text='This tab is not usable')

Set the tab to 'not_usable' state with grey text.

Args: tooltip_text (str): Custom tooltip text to show when hovering

Source code in src/cellects/gui/custom_widgets.py
def set_not_usable(self, tooltip_text="This tab is not usable"):
    """
    Set the tab to 'not_usable' state with grey text.

    Args:
        tooltip_text (str): Custom tooltip text to show when hovering
    """
    self.state = "not_usable"
    self.setToolTip(tooltip_text)
    self.update_style()

update_style()

Update the widget's stylesheetµ

Source code in src/cellects/gui/custom_widgets.py
def update_style(self):
    """Update the widget's stylesheetµ"""

    if self.state == "not_usable":
        tab_text_color = "#888888"
        self.setCursor(QtCore.Qt.CursorShape.ForbiddenCursor)
    else:
        if self._night_mode:
            tab_text_color = night_text_Color
        else:
            tab_text_color = textColor
        if self.state == "not_in_use":
            self.setCursor(QtCore.Qt.CursorShape.PointingHandCursor)
    if self.state == "in_use":
        border_width = 2
        if self._night_mode:
            tab_border = f"{border_width}px solid #adadad"
        else:
            tab_border = f"{border_width}px solid #323241"
    else:
        border_width = 1
        if self._night_mode:
            tab_border = f"{border_width}px solid #323241"
        else:
            tab_border = f"{border_width}px solid #adadad"

    if self._night_mode:
        style = {"buttoncolor": night_button_color, "buttontextColor": tab_text_color, "border": tab_border,
                 "font_family": tabfont, "font_size": "22pt", #"font_weight": "bold",
                 "border-top-color": "#323241", "border-right-color": "#323241", # invisible
                 "border-top-left-radius": "10", "border-bottom-left-radius": "1"}
    else:
        style = {"buttoncolor": buttoncolor, "buttontextColor": tab_text_color, "border": tab_border,
                 "font_family": tabfont, "font_size": "22pt", #"font_weight": "bold",
                 "border-top-color": "#ffffff", "border-right-color": "#ffffff", # invisible
                 "border-top-left-radius": "10", "border-bottom-left-radius": "1"
                 }
    self.setStyleSheet(
        "background-color: %s; color: %s; border: %s; font-family: %s; font-size: %s;  border-top-color: %s; border-right-color: %s; border-top-left-radius: %s; border-bottom-left-radius: %s" % tuple(style.values()))

PButton

Bases: QPushButton

Source code in src/cellects/gui/custom_widgets.py
class PButton(QtWidgets.QPushButton):
    def __init__(self, text, fade=True, tip=None, night_mode=False):
        """

        self.setStyleSheet("background-color: rgb(107, 145, 202);\n"
                                "border-color: rgb(255, 255, 255);\n"
                                "color: rgb(0, 0, 0);\n"
                                "font: 17pt \"Britannic Bold\";")
        :param text:
        """
        super().__init__()
        self.setText(text)
        self.setToolTip(tip)
        self.night_mode_switch(night_mode)
        self.setFont(buttonfont)
        self.setSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
        self.setFixedWidth(len(text)*15 + 25)
        self.setCursor(QtCore.Qt.CursorShape.PointingHandCursor)

    def night_mode_switch(self, night_mode):
        if night_mode:
            self.style = {"buttoncolor": night_button_color, "buttontextColor": night_text_Color, "buttonborder": night_button_border,
                          "buttonangles": buttonangles}
        else:
            self.style = {"buttoncolor": buttoncolor, "buttontextColor": textColor, "buttonborder": buttonborder,
                          "buttonangles": buttonangles}
        self.update_style()

    def event_filter(self, event):
        if event.type() == QtCore.QEvent.MouseMove:
            if event.buttons() == QtCore.Qt.NoButton:
                self.fade()
            else:
                self.unfade()

    def update_style(self):
        self.setStyleSheet(
            "background-color: %s; color: %s; border: %s; border-radius: %s" % tuple(self.style.values()))

    def color(self, color):
        self.style["buttoncolor"] = color
        self.update_style()

    def textcolor(self, textcolor):
        self.style["buttontextColor"] = textcolor
        self.update_style()

    def border(self, border):
        self.style["buttonborder"] = border
        self.update_style()

    def angles(self, angles):
        self.style["buttonangles"] = angles
        self.update_style()

    def fade(self):
        self.setWindowOpacity(0.5)
        self.setStyleSheet("background-color: %s; color: %s; border: %s; border-radius: %s" % (buttonclickedcolor, textColor, buttonborder, buttonangles))
        QtCore.QTimer.singleShot(300, self.unfade)

    def unfade(self):
        self.setWindowOpacity(1)
        self.setStyleSheet("background-color: %s; color: %s; border: %s; border-radius: %s" % (buttoncolor, textColor, buttonborder, buttonangles))

__init__(text, fade=True, tip=None, night_mode=False)

    self.setStyleSheet("background-color: rgb(107, 145, 202);

" "border-color: rgb(255, 255, 255); " "color: rgb(0, 0, 0); " "font: 17pt "Britannic Bold";") :param text:

Source code in src/cellects/gui/custom_widgets.py
def __init__(self, text, fade=True, tip=None, night_mode=False):
    """

    self.setStyleSheet("background-color: rgb(107, 145, 202);\n"
                            "border-color: rgb(255, 255, 255);\n"
                            "color: rgb(0, 0, 0);\n"
                            "font: 17pt \"Britannic Bold\";")
    :param text:
    """
    super().__init__()
    self.setText(text)
    self.setToolTip(tip)
    self.night_mode_switch(night_mode)
    self.setFont(buttonfont)
    self.setSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
    self.setFixedWidth(len(text)*15 + 25)
    self.setCursor(QtCore.Qt.CursorShape.PointingHandCursor)

WindowType

Bases: QWidget

Source code in src/cellects/gui/custom_widgets.py
class WindowType(QtWidgets.QWidget):
    resized = QtCore.Signal()
    def __init__(self, parent, night_mode=False):
        super().__init__()

        self.thread_dict = {}
        self.setVisible(False)
        self.setParent(parent)
        self.frame = QtWidgets.QFrame(self)
        self.frame.setGeometry(QtCore.QRect(0, 0, self.parent().screen_width, self.parent().screen_height))
        self.display_image = None
        self.setFont(QFont(textfont, textsize, QFont.Medium))
        self.night_mode = night_mode
        self.night_mode_switch(night_mode)

    def resizeEvent(self, event):
        '''
        # Use this signal to detect a resize event and call center window function
        :param event:
        :return:
        '''
        self.resized.emit()
        self.night_mode_switch(self.night_mode)
        if self.display_image is not None:
            win_width, win_height = self.size().width(), self.size().height()
            self.display_image.max_width = win_width - self.parent().image_window_width_diff
            self.display_image.max_height = win_height - self.parent().image_window_height_diff
            if self.display_image.max_width * self.display_image.height_width_ratio < self.display_image.max_height:
                self.display_image.scaled_shape = [round(self.display_image.max_width * self.display_image.height_width_ratio), self.display_image.max_width]
            else:
                self.display_image.scaled_shape = [self.display_image.max_height, np.round(self.display_image.max_height / self.display_image.height_width_ratio)]

            self.display_image.setMaximumHeight(self.display_image.scaled_shape[0])
            self.display_image.setMaximumWidth(self.display_image.scaled_shape[1])
        return super(WindowType, self).resizeEvent(event)

    def center_window(self):
        self.parent().center()

    def night_mode_switch(self, night_mode):
        if night_mode:
            self.setStyleSheet(
                "background-color: %s; color: %s; font: %s; selection-color: %s; selection-background-color: %s" % (
                night_background_color, night_text_Color, f"{textsize}pt {textfont};",
                night_selection_color, night_selection_background_color))
        else:
            self.setStyleSheet(
                "background-color: %s; color: %s; font: %s; selection-color: %s; selection-background-color: %s" % (
                backgroundcolor, textColor, f"{textsize}pt {textfont};", selectioncolor,
                selectionbackgroundcolor))

resizeEvent(event)

Use this signal to detect a resize event and call center window function

:param event: :return:

Source code in src/cellects/gui/custom_widgets.py
def resizeEvent(self, event):
    '''
    # Use this signal to detect a resize event and call center window function
    :param event:
    :return:
    '''
    self.resized.emit()
    self.night_mode_switch(self.night_mode)
    if self.display_image is not None:
        win_width, win_height = self.size().width(), self.size().height()
        self.display_image.max_width = win_width - self.parent().image_window_width_diff
        self.display_image.max_height = win_height - self.parent().image_window_height_diff
        if self.display_image.max_width * self.display_image.height_width_ratio < self.display_image.max_height:
            self.display_image.scaled_shape = [round(self.display_image.max_width * self.display_image.height_width_ratio), self.display_image.max_width]
        else:
            self.display_image.scaled_shape = [self.display_image.max_height, np.round(self.display_image.max_height / self.display_image.height_width_ratio)]

        self.display_image.setMaximumHeight(self.display_image.scaled_shape[0])
        self.display_image.setMaximumWidth(self.display_image.scaled_shape[1])
    return super(WindowType, self).resizeEvent(event)