diff --git a/System/config.py b/System/config.py index 81a39f3..7fc6fad 100644 --- a/System/config.py +++ b/System/config.py @@ -63,7 +63,6 @@ def formatDefault() -> None: open("System/config/themes.json", "w").write("{\n \"default\": \"light\"\n}\n") - class FontConfig: """ Font Configuration diff --git a/System/config/themes/light.json b/System/config/themes/light.json index 5c02052..fb6ad93 100644 --- a/System/config/themes/light.json +++ b/System/config/themes/light.json @@ -1,6 +1,6 @@ { "text-color": "#000000", "background-color": "#FFFFFF", - "background-color-2": "#EFEFEF", + "background-color-2": "#F5F5F5", "background-color-3": "#DFDFDF" } \ No newline at end of file diff --git a/System/dialogs.py b/System/dialogs.py index 81e5790..557d333 100644 --- a/System/dialogs.py +++ b/System/dialogs.py @@ -14,117 +14,190 @@ from PyQt6.QtGui import * from PyQt6.QtCore import * from PyQt6.QtWidgets import * -from PyQt6.QtNetwork import * class Preferences(QWidget): """System Preferences Application""" + class Appearance(QWidget): + class ThemeLabel(QLabel): + def __init__(self, parent): + super(Preferences.Appearance.ThemeLabel, self).__init__(parent) + self.setCursor(Qt.CursorShape.PointingHandCursor) + self.index = None + self.setFont(QFont(returnProperties()["font-family"], returnProperties()["font-size"])) + self.setAlignment(Qt.AlignmentFlag.AlignCenter) + + def mousePressEvent(self, event): + self.parent().parent().changeTheme(self.index) + super(Preferences.Appearance.ThemeLabel, self).mousePressEvent(event) + + class Theme(QWidget): + def __init__(self, parent, update_function): + super(Preferences.Appearance.Theme, self).__init__(parent=parent) + self.update_function = update_function + self.layout = QGridLayout() + self.theme, self.font_size, self.font_family = returnProperties()["theme"], returnProperties()["font-size"], returnProperties()["font-family"] + self.top_bar = QGroupBox(self) + self.top_bar.setLayout(QHBoxLayout()) + self.back_button = QPushButton("Back", self.top_bar) + self.back_button.pressed.connect(lambda self=self: self.parent().setCurrentIndex(0)) + self.top_bar.layout().addWidget(self.back_button) + # self.layout.addWidget(self.top_bar, 0, 0) + self.widgets, self.group_box_widgets = { + "top-bar": [self.top_bar, [0, 0]], + "theme-label": [QLabel("Theme"), [3, 0]], + "theme-group-box": [QGroupBox(self), [3, 1]], + "font-size-label": [QLabel("Font Size"), [5, 0]], + "font-size": [Slider(5, 20, int(returnProperties()["font-size"]), self.changeFontSize), [5, 1]], + "reset-font-size": [PushButton("Reset"), [5, 2]], + "font-family-label": [QLabel("Font Family"), [6, 0]], + "font-family": [QComboBox(self), [6, 1]] + }, {} + # Append to self.group_box_widgets + for x, y in zip(Themes.getThemes(), range(1, len(Themes.getThemes().keys()) + 1)): + self.group_box_widgets[x] = [Preferences.Appearance.ThemeLabel(self), [1, y]] + # Specific widget properties + # # Font family properties + self.widgets["font-family"][0].addItems(returnProperties()["fonts"]) + self.widgets["font-family"][0].setStyleSheet(f"QComboBox QAbstractItemView {{ selection-color: {'#AAAAAA' if returnProperties()['theme'] == 'light' else '#555555'}; color: {returnBackgroundProperties()['text-color']}; }};") + self.widgets["font-family"][0].setCurrentIndex(returnProperties()["fonts"].index(self.font_family)) + self.widgets["font-family"][0].currentIndexChanged.connect(self.changeFontFamily) + # # Reset font size properties + self.widgets["reset-font-size"][0].clicked.connect(self.resetFontSize) + # # Label properties + for i in ["theme-label", "font-size-label", "font-family-label"]: + self.widgets[i][0].setStyleSheet(f"color: {returnBackgroundProperties()['text-color']};") + self.widgets[i][0].setFont(QFont(returnProperties()["font-family"], returnProperties()["font-size"])) + # # Theme group box properties + self.widgets["theme-group-box"][0].setStyleSheet("QGroupBox { border: none; }") + self.group_box_layout = QHBoxLayout() + for i in self.group_box_widgets: + self.group_box_layout.addWidget(self.group_box_widgets[i][0]) + self.widgets["theme-group-box"][0].setLayout(self.group_box_layout) + self.widgets["theme-group-box"][0].setFixedSize(540, 100) + self.widgets["theme-group-box"][0].layout().setContentsMargins(30, 30, 30, 30) + # # Theme button properties + for i in self.group_box_widgets.keys(): + self.group_box_widgets[i][0].setText(i.title()) + self.group_box_widgets[i][0].setStyleSheet(f"color: #{str(Themes.getThemes()[i]['text-color'])[1:].lower()}; border: none; background: #{str(Themes.getThemes()[i]['background-color'])[1:].lower()};") + self.group_box_widgets[i][0].index = i + # exec(f"self.group_box_widgets[i][0].pressed.connect(lambda self=self: self.changeTheme('{i}'))", globals(), locals()) + # Add to layout + for i in self.widgets.keys(): + self.layout.addWidget(self.widgets[i][0], self.widgets[i][1][0], self.widgets[i][1][1]) + self.setLayout(self.layout) # Set layout + + def _update(self): + self.setStyleSheet(f"background-color: {returnBackgroundProperties()['background-color-2']}") + for i in ["theme-label", "font-size-label", "font-family-label"]: + self.widgets[i][0].setStyleSheet(f"color: {returnBackgroundProperties()['text-color']}; font-size: {returnProperties()['font-size']}") + self.widgets[i][0].setFont(QFont(returnProperties()["font-family"], returnProperties()["font-size"])) + for i in self.group_box_widgets.keys(): + self.group_box_widgets[i][0].setStyleSheet(f"color: {returnBackgroundProperties()['text-color']}; border: none") + self.group_box_widgets[i][0].setFont(QFont(returnProperties()["font-family"], returnProperties()["font-size"])) + # self.widgets["font-family"][0].setStyleSheet("QComboBox QAbstractItemView {selection-color: #AAAAAA}") + if returnProperties()["theme"] == "light": + self.widgets["font-family"][0].setStyleSheet("QComboBox QAbstractItemView { selection-color: #AAAAAA; color: #000000; };") + else: + self.widgets["font-family"][0].setStyleSheet("QComboBox QAbstractItemView { selection-color: #555555; color: #FFFFFF; };") + self.update_function() + + def resetFontSize(self) -> None: + self.font_size = 12 + self.widgets["font-size"][0].setValue(12) + with open("System/config/font.json") as file: + data = load(file) + data["font-size"] = self.font_size + open("System/config/font.json", "w").write(str(data).replace("'", "\"")) + self._update() + + def changeFontFamily(self) -> None: + self.font_family = self.widgets["font-family"][0].currentText() + with open("System/config/font.json", "r+") as file: + data = load(file) + data["font-family"] = self.font_family + open("System/config/font.json", "w").write(str(data).replace("'", "\"")) + self._update() + + def changeFontSize(self) -> None: + self.font_size = self.widgets["font-size"][0].value() + with open("System/config/font.json", "r+") as file: + data = load(file) + data["font-size"] = self.font_size + open("System/config/font.json", "w").write(str(data).replace("'", "\"")) + self._update() + + def changeTheme(self, theme): + self.theme = theme + with open("System/config/theme.json", "r+") as file: + data = load(file) + data["theme"] = self.theme + open("System/config/theme.json", "w").write(str(data).replace("'", "\"")) + self._update() + self.parent().parent().parent().parent().parent().restartWindow() + + def resizeEvent(self, event) -> None: + self.top_bar.resize(QSize(event.size().width(), self.top_bar.size().height())) + super(Preferences.Appearance.Theme, self).resizeEvent(event) + + class AppearanceWidget(QWidget): + def __init__(self, parent, update_function): + super(Preferences.Appearance.AppearanceWidget, self).__init__(parent) + self.update_function = update_function + self.buttons = [] + self.buttons.append(ActionPushButton(self, "General", lambda: self.parent().setCurrentIndex(1))) + self.buttons.append(ActionPushButton(self, "Windows", lambda: self.parent().setCurrentIndex(1))) + self.buttons.append(ActionPushButton(self, "Dock", lambda: self.parent().setCurrentIndex(1))) + width = self.buttons[0].width() + for i in range(len(self.buttons)): + self.buttons[i].move(QPoint(i * (width + 5), 0)) + + def resizeEvent(self, event) -> None: + single_width, width, y = self.buttons[0].width(), 0, 0 + for i in range(len(self.buttons)): + if (width + 5) >= self.width(): + y += self.buttons[i].height() + 5 + width = 0 + self.buttons[i].move(QPoint(width, y)) + width += single_width + 5 + super(Preferences.Appearance.AppearanceWidget, self).resizeEvent(event) + + def __init__(self, parent, update_function): + super(Preferences.Appearance, self).__init__(parent) + self.update_function = update_function + self.stacked_widgets, self.pages = QStackedWidget(self), {"main": Preferences.Appearance.AppearanceWidget(self, update_function), "theme": Preferences.Appearance.Theme(self, update_function)} + for i in self.pages.values(): + self.stacked_widgets.addWidget(i) + + def resizeEvent(self, event) -> None: + for i in self.pages.values(): + i.resize(event.size()) + super(Preferences.Appearance, self).resizeEvent(event) + def __init__(self, update_function) -> None: super(Preferences, self).__init__() self.setCursor(Qt.CursorShape.ArrowCursor) - self.update_function = update_function - self.layout = QGridLayout() - self.theme, self.font_size, self.font_family = returnProperties()["theme"], returnProperties()["font-size"], returnProperties()["font-family"] - self.widgets, self.group_box_widgets, self.theme_icons = { - "theme-label": [QLabel("Theme"), [3, 1]], - "theme-group-box": [QGroupBox(self), [3, 2]], - "font-size-label": [QLabel("Font Size"), [5, 1]], - "font-size": [Slider(5, 20, int(returnProperties()["font-size"]), self.changeFontSize), [5, 2]], - "reset-font-size": [PushButton("Reset"), [5, 3]], - "font-family-label": [QLabel("Font Family"), [6, 1]], - "font-family": [QComboBox(self), [6, 2]] - }, {}, {} - # Append to self.group_box_widgets - for x, y in zip(Themes.getThemes(), range(1, len(Themes.getThemes().keys()) + 1)): - self.group_box_widgets[x] = [QToolButton(self), [1, y]] - # Specific widget properties - # # Font family properties - self.widgets["font-family"][0].addItems(returnProperties()["fonts"]) - self.widgets["font-family"][0].setStyleSheet(f"QComboBox QAbstractItemView {{ selection-color: {'#AAAAAA' if returnProperties()['theme'] == 'light' else '#555555'}; color: {returnBackgroundProperties()['text-color']}; }};") - self.widgets["font-family"][0].setCurrentIndex(returnProperties()["fonts"].index(self.font_family)) - self.widgets["font-family"][0].currentIndexChanged.connect(self.changeFontFamily) - # # Reset font size properties - self.widgets["reset-font-size"][0].clicked.connect(self.resetFontSize) - # # Label properties - for i in ["theme-label", "font-size-label", "font-family-label"]: - self.widgets[i][0].setStyleSheet(f"color: {returnBackgroundProperties()['text-color']};") - self.widgets[i][0].setFont(QFont(returnProperties()["font-family"], returnProperties()["font-size"])) - # # Theme group box properties - self.widgets["theme-group-box"][0].setStyleSheet("QGroupBox { border: none; }") - self.group_box_layout = QHBoxLayout() - for i in self.group_box_widgets: self.group_box_layout.addWidget(self.group_box_widgets[i][0]) - self.widgets["theme-group-box"][0].setLayout(self.group_box_layout) - self.widgets["theme-group-box"][0].setFixedSize(540, 100) - # # Theme button properties - for i in self.group_box_widgets.keys(): - self.theme_icons[i] = QNetworkAccessManager(self) - exec(f"self.theme_icons[i].finished.connect(lambda reply, self=self: self.setIcon(reply, '{i}'))", globals(), locals()) - self.theme_icons[i].get(QNetworkRequest(QUrl(f"https://htmlcolors.com/color-image/{str(Themes.getThemes()[i]['background-color'])[1:].lower()}.png"))) - self.group_box_widgets[i][0].setText(i.title()) - self.group_box_widgets[i][0].setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextUnderIcon) - self.group_box_widgets[i][0].setCursor(Qt.CursorShape.PointingHandCursor) - self.group_box_widgets[i][0].setStyleSheet(f"color: {returnBackgroundProperties()['text-color']}; border: none") - self.group_box_widgets[i][0].setFont(QFont(returnProperties()["font-family"], returnProperties()["font-size"])) - self.group_box_widgets[i][0].setIconSize(QSize(25, 25)) - exec(f"self.group_box_widgets[i][0].pressed.connect(lambda self=self: self.changeTheme('{i}'))", globals(), locals()) - # Add to layout - for i in self.widgets.keys(): - self.layout.addWidget(self.widgets[i][0], self.widgets[i][1][0], self.widgets[i][1][1]) - self.setLayout(self.layout) # Set layout - - def setIcon(self, reply, icon): - image = QImage() - image.loadFromData(reply.readAll()) - self.group_box_widgets[icon][0].setIcon(QIcon(QPixmap.fromImage(image))) + self.tabs = QScrollArea(self) + self.tabs.setWidgetResizable(True) - def _update(self): - self.setStyleSheet(f"background-color: {returnBackgroundProperties()['background-color-2']}") - for i in ["theme-label", "font-size-label", "font-family-label"]: - self.widgets[i][0].setStyleSheet(f"color: {returnBackgroundProperties()['text-color']}; font-size: {returnProperties()['font-size']}") - self.widgets[i][0].setFont(QFont(returnProperties()["font-family"], returnProperties()["font-size"])) - for i in self.group_box_widgets.keys(): - self.group_box_widgets[i][0].setStyleSheet(f"color: {returnBackgroundProperties()['text-color']}; border: none") - self.group_box_widgets[i][0].setFont(QFont(returnProperties()["font-family"], returnProperties()["font-size"])) - # self.widgets["font-family"][0].setStyleSheet("QComboBox QAbstractItemView {selection-color: #AAAAAA}") - if returnProperties()["theme"] == "light": - self.widgets["font-family"][0].setStyleSheet("QComboBox QAbstractItemView { selection-color: #AAAAAA; color: #000000; };") - else: - self.widgets["font-family"][0].setStyleSheet("QComboBox QAbstractItemView { selection-color: #555555; color: #FFFFFF; };") - self.update_function() - - def resetFontSize(self) -> None: - self.font_size = 12 - self.widgets["font-size"][0].setValue(12) - with open("System/config/font.json") as file: - data = load(file) - data["font-size"] = self.font_size - open("System/config/font.json", "w").write(str(data).replace("'", "\"")) - self._update() + self.tab_widget = QWidget() + self.tabs.setWidget(self.tab_widget) + + self.tab_layout = QVBoxLayout(self.tab_widget) + self.tab_layout.addWidget(TabButton(self.tab_widget, lambda: self.stacked_widgets.setCurrentIndex(0), "Appearance")) + self.tab_layout.addItem(QSpacerItem(100, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)) - def changeFontFamily(self) -> None: - self.font_family = self.widgets["font-family"][0].currentText() - with open("System/config/font.json", "r+") as file: - data = load(file) - data["font-family"] = self.font_family - open("System/config/font.json", "w").write(str(data).replace("'", "\"")) - self._update() + self.tabs.setStyleSheet("border: none; background: #F0F0F0") - def changeFontSize(self) -> None: - self.font_size = self.widgets["font-size"][0].value() - with open("System/config/font.json", "r+") as file: - data = load(file) - data["font-size"] = self.font_size - open("System/config/font.json", "w").write(str(data).replace("'", "\"")) - self._update() + self.stacked_widgets, self.pages = QStackedWidget(self), {"appearance": Preferences.Appearance(self, update_function)} + for i in self.pages.values(): + self.stacked_widgets.addWidget(i) - def changeTheme(self, theme): - self.theme = theme - with open("System/config/theme.json", "r+") as file: - data = load(file) - data["theme"] = self.theme - open("System/config/theme.json", "w").write(str(data).replace("'", "\"")) - self._update() - self.parent().restartWindow() + def resizeEvent(self, event): + self.tabs.resize(QSize(event.size().width() // 5, event.size().height())) + self.stacked_widgets.resize(QSize(event.size().width() // 5 * 4, event.size().height())) + self.stacked_widgets.move(self.tabs.width(), 0) + super(Preferences, self).resizeEvent(event) class ShutDownWindow(QWidget): diff --git a/System/main.py b/System/main.py index bfc25d2..8acfe56 100644 --- a/System/main.py +++ b/System/main.py @@ -26,7 +26,7 @@ applications, config = _applications.returnApplications(), Config() -print("Starting the Mini Operating System...") # Print starting message +print("Starting the Mini Operating System...") # Print starting message (maybe remove?) class Window(QMainWindow): diff --git a/System/widgets/buttons/__init__.py b/System/widgets/buttons/__init__.py index a8acb92..ee6e718 100644 --- a/System/widgets/buttons/__init__.py +++ b/System/widgets/buttons/__init__.py @@ -92,16 +92,20 @@ def leaveEvent(self, event: QEvent) -> None: class PushButton(QPushButton): """Add QPushButton Animation""" - def __init__(self, text="", color="black") -> None: - super().__init__() + def __init__(self, text="", parent=None, color="black", padding="15px", background="#F5F5F5", hover="#E6E6E6") -> None: + if parent is None: + super(PushButton, self).__init__() + else: + super(PushButton, self).__init__(parent) self.color = color + self.padding = padding self.setText(text) self._animation = QVariantAnimation() - self._animation.setStartValue(QColor("black")) - self._animation.setEndValue(QColor("white")) + self._animation.setStartValue(QColor(hover)) + self._animation.setEndValue(QColor(background)) self._animation.valueChanged.connect(self.valueChanged) self._animation.setDuration(200) - self.updateStylesheet(QColor("white")) + self.updateStylesheet(QColor(background)) self.setCursor(QCursor(Qt.CursorShape.PointingHandCursor)) def valueChanged(self, color: QColor) -> None: @@ -110,9 +114,7 @@ def valueChanged(self, color: QColor) -> None: def updateStylesheet(self, background: QColor) -> None: """Update style sheet""" - self.setStyleSheet( - f"QPushButton {{background-color: {background.name()}; color: #888888; padding: 16px 32px; text-align: center; text-decoration: none; font-size: 16px; margin: 4px 2px; border: 2px solid " - f"white;}}") + self.setStyleSheet(f"background-color: {background.name()}; color: {self.color}; border: none; padding: {self.padding};") def enterEvent(self, event: QEvent) -> None: """Display backward color animation on mouse hover""" @@ -134,3 +136,22 @@ def updateColor(self, color="black") -> None: class ToolButton(QToolButton): def __init__(self, parent): super(ToolButton, self).__init__(parent) + + +class TabButton(PushButton): + def __init__(self, parent, action, text=""): + super(TabButton, self).__init__(text, parent, padding="5px") + self.action = action + + def mousePressEvent(self, event): + self.action() + super(TabButton, self).mousePressEvent(event) + + +class ActionPushButton(PushButton): + def __init__(self, parent, text="", action=None): + super(ActionPushButton, self).__init__(text, parent, padding="0px") + self.action = action + self.pressed.connect(lambda self=self: self.action() if self.action is not None else None) + self.setFixedSize(QSize(75, 75)) + \ No newline at end of file