diff --git a/gui/core/json_settings.py b/gui/core/json_settings.py index ae68034..bdd795f 100644 --- a/gui/core/json_settings.py +++ b/gui/core/json_settings.py @@ -26,7 +26,7 @@ class Settings(object): # /////////////////////////////////////////////////////////////// json_file = "settings.json" app_path = os.path.abspath(os.getcwd()) - settings_path = os.path.join(app_path, json_file) + settings_path = os.path.normpath(os.path.join(app_path, json_file)) if not os.path.isfile(settings_path): print(f"WARNING: \"settings.json\" not found! check in the folder {settings_path}") diff --git a/gui/core/json_themes.py b/gui/core/json_themes.py index c5b6535..6875ca1 100644 --- a/gui/core/json_themes.py +++ b/gui/core/json_themes.py @@ -19,29 +19,52 @@ import json import os +# IMPORT SETTINGS +# /////////////////////////////////////////////////////////////// +from gui.core.json_settings import Settings + # APP THEMES # /////////////////////////////////////////////////////////////// -class Settings(object): +class Themes(object): + # LOAD SETTINGS + # /////////////////////////////////////////////////////////////// + setup_settings = Settings() + _settings = setup_settings.items + # APP PATH # /////////////////////////////////////////////////////////////// - json_file = "settings.json" + json_file = f"gui/themes/{_settings['theme_name']}.json" app_path = os.path.abspath(os.getcwd()) - settings_path = os.path.join(app_path, json_file) + settings_path = os.path.normpath(os.path.join(app_path, json_file)) if not os.path.isfile(settings_path): - print(f"WARNING: \"settings.json\" not found! check in the folder {settings_path}") - + print(f"WARNING: \"gui/themes/{_settings['theme_name']}.json\" not found! check in the folder {settings_path}") + # INIT SETTINGS # /////////////////////////////////////////////////////////////// def __init__(self): - super(Settings, self).__init__() + super(Themes, self).__init__() # DICTIONARY WITH SETTINGS self.items = { - "app_name" : "", - "custom_title_bar" : True, - "startup_size" : [], - "minimum_size" : [], - "theme_name" : "" + "theme_name" : "", + "app_color" : { + "dark_one" : "", + "dark_two" : "", + "dark_three" : "", + "dark_four" : "", + "bg_one" : "", + "bg_two" : "", + "icon_normal" : "", + "icon_hover" : "", + "icon_pressed" : "", + "icon_active" : "", + "context_color" : "", + "context_hover" : "", + "context_pressed" : "", + "text_title" : "", + "text_foreground" : "", + "text_description" : "" + } } # DESERIALIZE diff --git a/gui/themes/default.json b/gui/themes/default.json new file mode 100644 index 0000000..38d332b --- /dev/null +++ b/gui/themes/default.json @@ -0,0 +1,21 @@ +{ + "theme_name" : "Default", + "app_color" : { + "dark_one" : "#1b1e23", + "dark_two" : "#1e2229", + "dark_three" : "#21252d", + "dark_four" : "#272c36", + "bg_one" : "#2c313c", + "bg_two" : "#343b48", + "icon_normal" : "#c3ccdf", + "icon_hover" : "#dce1ec", + "icon_pressed" : "#edf0f5", + "icon_active" : "#f5f6f9", + "context_color" : "#568af2", + "context_hover" : "#6c99f4", + "context_pressed" : "#3f6fd1", + "text_title" : "#dce1ec", + "text_foreground" : "#8a95aa", + "text_description" : "#6c7b95" + } +} \ No newline at end of file diff --git a/gui/uis/windows/main_window/ui_main.py b/gui/uis/windows/main_window/ui_main.py index fc55860..416b801 100644 --- a/gui/uis/windows/main_window/ui_main.py +++ b/gui/uis/windows/main_window/ui_main.py @@ -26,6 +26,10 @@ from qt_core import * # /////////////////////////////////////////////////////////////// from gui.core.json_settings import Settings +# IMPORT THEME COLORS +# /////////////////////////////////////////////////////////////// +from gui.core.json_themes import Themes + # IMPORT PY ONE DARK WIDGETS # /////////////////////////////////////////////////////////////// from gui.widgets import * @@ -42,15 +46,30 @@ class UI_MainWindow(object): settings = Settings() self.settings = settings.items + # LOAD THEME COLOR + # /////////////////////////////////////////////////////////////// + themes = Themes() + self.themes = themes.items + # SET INITIAL PARAMETERS parent.setMinimumSize(self.settings["startup_size"][0], self.settings["startup_size"][1]) # LOAD PY WINDOW CUSTOM WIDGET + # Add inside PyWindow "layout" all Widgets # /////////////////////////////////////////////////////////////// - self.window = PyWindow(parent) - - # TEXT - self.label = QLabel(self.settings["app_name"], self.window) + self.window = PyWindow( + parent, + bg_color = self.themes["app_color"]["bg_one"], + border_color = self.themes["app_color"]["bg_two"], + text_color = self.themes["app_color"]["text_foreground"] + ) + + # ADD WIDGETS TO "PyWindow" + # Add here your custom widgets or default widgets + # /////////////////////////////////////////////////////////////// + self.window.layout.addWidget(QLabel(self.settings["app_name"])) + self.window.layout.addWidget(QLabel(self.settings["app_name"])) # ADD CENTRAL WIDGET - parent.setCentralWidget(self.window) \ No newline at end of file + parent.setCentralWidget(self.window) + parent.setContentsMargins(10,10,10,10) \ No newline at end of file diff --git a/gui/widgets/__init__.py b/gui/widgets/__init__.py index 1aa46af..4df82f7 100644 --- a/gui/widgets/__init__.py +++ b/gui/widgets/__init__.py @@ -20,4 +20,8 @@ # PY WINDOW # /////////////////////////////////////////////////////////////// -from . py_window import PyWindow \ No newline at end of file +from . py_window import PyWindow + +# RESIZE GRIP +# /////////////////////////////////////////////////////////////// +from . py_grips import PyGrips \ No newline at end of file diff --git a/gui/widgets/py_grips/__init__.py b/gui/widgets/py_grips/__init__.py new file mode 100644 index 0000000..a4fda03 --- /dev/null +++ b/gui/widgets/py_grips/__init__.py @@ -0,0 +1,17 @@ +# /////////////////////////////////////////////////////////////// +# +# BY: WANDERSON M.PIMENTA +# PROJECT MADE WITH: Qt Designer and PySide6 +# V: 1.0.0 +# +# This project can be used freely for all uses, as long as they maintain the +# respective credits only in the Python scripts, any information in the visual +# interface (GUI) can be modified without any implication. +# +# There are limitations on Qt licenses if you want to use your products +# commercially, I recommend reading them on the official website: +# https://doc.qt.io/qtforpython/licenses.html +# +# /////////////////////////////////////////////////////////////// + +from . py_grips import PyGrips diff --git a/gui/widgets/py_grips/py_grips.py b/gui/widgets/py_grips/py_grips.py new file mode 100644 index 0000000..6fd9624 --- /dev/null +++ b/gui/widgets/py_grips/py_grips.py @@ -0,0 +1,163 @@ +# /////////////////////////////////////////////////////////////// +# +# BY: WANDERSON M.PIMENTA +# PROJECT MADE WITH: Qt Designer and PySide6 +# V: 1.0.0 +# +# This project can be used freely for all uses, as long as they maintain the +# respective credits only in the Python scripts, any information in the visual +# interface (GUI) can be modified without any implication. +# +# There are limitations on Qt licenses if you want to use your products +# commercially, I recommend reading them on the official website: +# https://doc.qt.io/qtforpython/licenses.html +# +# /////////////////////////////////////////////////////////////// + +# IMPORT PACKAGES AND MODULES +# /////////////////////////////////////////////////////////////// +import sys + +# IMPORT QT CORE +# /////////////////////////////////////////////////////////////// +from qt_core import * + +class PyGrips(QWidget): + def __init__(self, parent, position, disable_color = False): + + # SETUP UI + QWidget.__init__(self) + self.parent = parent + self.setParent(parent) + self.wi = Widgets() + + # SHOW TOP GRIP + if position == Qt.TopEdge: + self.wi.top(self) + self.setGeometry(0, 0, self.parent.width(), 10) + self.setMaximumHeight(10) + + # RESIZE TOP + def resize_top(event): + delta = event.pos() + height = max(self.parent.minimumHeight(), self.parent.height() - delta.y()) + geo = self.parent.geometry() + geo.setTop(geo.bottom() - height) + self.parent.setGeometry(geo) + event.accept() + self.wi.top_grip.mouseMoveEvent = resize_top + + # ENABLE COLOR + if disable_color: + self.wi.top_grip.setStyleSheet("background: transparent") + + # SHOW BOTTOM GRIP + elif position == Qt.BottomEdge: + self.wi.bottom(self) + self.setGeometry(0, self.parent.height() - 10, self.parent.width(), 10) + self.setMaximumHeight(10) + + # RESIZE BOTTOM + def resize_bottom(event): + delta = event.pos() + height = max(self.parent.minimumHeight(), self.parent.height() + delta.y()) + self.parent.resize(self.parent.width(), height) + event.accept() + self.wi.bottom_grip.mouseMoveEvent = resize_bottom + + # ENABLE COLOR + if disable_color: + self.wi.bottom.setStyleSheet("background: transparent") + + # SHOW LEFT GRIP + elif position == Qt.LeftEdge: + self.wi.left(self) + self.setGeometry(0, 10, 10, self.parent.height()) + self.setMaximumWidth(10) + + # RESIZE LEFT + def resize_left(event): + delta = event.pos() + width = max(self.parent.minimumWidth(), self.parent.width() - delta.x()) + geo = self.parent.geometry() + geo.setLeft(geo.right() - width) + self.parent.setGeometry(geo) + event.accept() + self.wi.left_grip.mouseMoveEvent = resize_left + + # ENABLE COLOR + if disable_color: + self.wi.left_grip.setStyleSheet("background: transparent") + + # RESIZE RIGHT + elif position == Qt.RightEdge: + self.wi.right(self) + self.setGeometry(self.parent.width() - 10, 10, 10, self.parent.height()) + self.setMaximumWidth(10) + + def resize_right(event): + delta = event.pos() + width = max(self.parent.minimumWidth(), self.parent.width() + delta.x()) + self.parent.resize(width, self.parent.height()) + event.accept() + self.wi.right_grip.mouseMoveEvent = resize_right + + # ENABLE COLOR + if disable_color: + self.wi.right_grip.setStyleSheet("background: transparent") + + + def mouseReleaseEvent(self, event): + self.mousePos = None + + def resizeEvent(self, event): + if hasattr(self.wi, 'top_grip'): + self.wi.top_grip.setGeometry(0, 0, self.width(), 10) + + elif hasattr(self.wi, 'bottom_grip'): + self.wi.bottom_grip.setGeometry(0, 0, self.width(), 10) + + elif hasattr(self.wi, 'left_grip'): + self.wi.left_grip.setGeometry(0, 0, 10, self.height() - 20) + + elif hasattr(self.wi, 'right_grip'): + self.wi.right_grip.setGeometry(0, 0, 10, self.height() - 20) + +class Widgets(object): + def top(self, Form): + if not Form.objectName(): + Form.setObjectName(u"Form") + self.top_grip = QFrame(Form) + self.top_grip.setObjectName(u"top_grip") + self.top_grip.setGeometry(QRect(0, 0, 500, 10)) + self.top_grip.setStyleSheet(u"background-color: rgb(85, 255, 255);") + self.top_grip.setCursor(QCursor(Qt.SizeVerCursor)) + + def bottom(self, Form): + if not Form.objectName(): + Form.setObjectName(u"Form") + self.bottom_grip = QFrame(Form) + self.bottom_grip.setObjectName(u"bottom_grip") + self.bottom_grip.setGeometry(QRect(0, 0, 500, 10)) + self.bottom_grip.setStyleSheet(u"background-color: rgb(85, 170, 0);") + self.bottom_grip.setCursor(QCursor(Qt.SizeVerCursor)) + + def left(self, Form): + if not Form.objectName(): + Form.setObjectName(u"Form") + self.left_grip = QFrame(Form) + self.left_grip.setObjectName(u"left") + self.left_grip.setGeometry(QRect(0, 10, 10, 480)) + self.left_grip.setMinimumSize(QSize(10, 0)) + self.left_grip.setCursor(QCursor(Qt.SizeHorCursor)) + self.left_grip.setStyleSheet(u"background-color: rgb(255, 121, 198);") + + def right(self, Form): + if not Form.objectName(): + Form.setObjectName(u"Form") + self.right_grip = QFrame(Form) + self.right_grip.setObjectName(u"right") + self.right_grip.setGeometry(QRect(0, 0, 10, 500)) + self.right_grip.setMinimumSize(QSize(10, 0)) + self.right_grip.setCursor(QCursor(Qt.SizeHorCursor)) + self.right_grip.setStyleSheet(u"background-color: rgb(255, 0, 127);") diff --git a/gui/widgets/py_window/py_window.py b/gui/widgets/py_window/py_window.py index 40f15db..3792a41 100644 --- a/gui/widgets/py_window/py_window.py +++ b/gui/widgets/py_window/py_window.py @@ -26,10 +26,30 @@ from qt_core import * # /////////////////////////////////////////////////////////////// from gui.core.json_settings import Settings +# IMPORT PY GRIP +# /////////////////////////////////////////////////////////////// +from gui.widgets.py_grips import PyGrips + +# IMPORT STYLES +# /////////////////////////////////////////////////////////////// +from . styles import Styles + # PY WINDOW # /////////////////////////////////////////////////////////////// -class PyWindow(QWidget): - def __init__(self, parent): +class PyWindow(QFrame): + def __init__( + self, + parent, + layout = Qt.Vertical, + margin = 10, + bg_color = "#2c313c", + text_color = "#fff", + text_font = "9pt 'Segoe UI'", + border_radius = 10, + border_size = 2, + border_color = "#343b48", + enable_shadow = True + ): super(PyWindow, self).__init__() # LOAD SETTINGS @@ -37,20 +57,109 @@ class PyWindow(QWidget): settings = Settings() self.settings = settings.items - # APP MARGINS LAYOUT + # PROPERTIES # /////////////////////////////////////////////////////////////// - self.app_margins_layout = QVBoxLayout(self) - self.app_margins_layout.setContentsMargins(0,0,0,0) - self.app_margins_layout.setObjectName("app_margins_layout") + self.parent = parent + self.layout = layout + self.margin = margin + self.bg_color = bg_color + self.text_color = text_color + self.text_font = text_font + self.border_radius = border_radius + self.border_size = border_size + self.border_color = border_color + self.enable_shadow = enable_shadow - # BG APP - # /////////////////////////////////////////////////////////////// - self.bg_app = QFrame(self) - self.bg_app.setStyleSheet("background: #333") - self.bg_app.setObjectName("bg_app") + # OBJECT NAME + # /////////////////////////////////////////////////////////////// + self.setObjectName("pod_bg_app") - # ADD WIDGETS TO APP MARGINS LAUOUT + # APPLY STYLESHEET + # /////////////////////////////////////////////////////////////// + self.set_stylesheet() + + # ADD LAYOUT # /////////////////////////////////////////////////////////////// - self.app_margins_layout.addWidget(self.bg_app) - + if layout == Qt.Vertical: + # VERTICAL LAYOUT + self.layout = QVBoxLayout(self) + else: + # HORIZONTAL LAYOUT + self.layout = QHBoxLayout(self) + self.layout.setContentsMargins(margin, margin, margin, margin) + + # ADD GRIPS + # /////////////////////////////////////////////////////////////// + if self.settings["custom_title_bar"]: + self.left_grip = PyGrips(parent, Qt.LeftEdge) + self.right_grip = PyGrips(parent, Qt.RightEdge) + self.top_grip = PyGrips(parent, Qt.TopEdge) + self.bottom_grip = PyGrips(parent, Qt.BottomEdge) + # UPDATE WHEN RESIZE + parent.resizeEvent = self._resize_grips + + # ADD DROP SHADOW + # /////////////////////////////////////////////////////////////// + if self.settings["custom_title_bar"]: + if enable_shadow: + self.shadow = QGraphicsDropShadowEffect() + self.shadow.setBlurRadius(25) + self.shadow.setXOffset(0) + self.shadow.setYOffset(0) + self.shadow.setColor(QColor(0, 0, 0, 120)) + self.setGraphicsEffect(self.shadow) + + # APPLY AND UPDATE STYLESHEET + # /////////////////////////////////////////////////////////////// + def set_stylesheet( + self, + bg_color = None, + border_radius = None, + border_size = None, + border_color = None, + text_color = None, + text_font = None + ): + # CHECK BG COLOR + if border_radius != None: internal_bg_color = bg_color + else: internal_bg_color = self.bg_color + + # CHECK BORDER RADIUS + if border_radius != None: internal_border_radius = border_radius + else: internal_border_radius = self.border_radius + + # CHECK BORDER SIZE + if border_size != None: internal_border_size = border_size + else: internal_border_size = self.border_size + + # CHECK BORDER COLOR + if text_color != None: internal_text_color = text_color + else: internal_text_color = self.text_color + + # CHECK TEXT COLOR + if border_color != None: internal_border_color = border_color + else: internal_border_color = self.border_color + + # CHECK TEXT COLOR + if text_font != None: internal_text_font = text_font + else: internal_text_font = self.text_font + + self.setStyleSheet(Styles.bg_style.format( + _bg_color = internal_bg_color, + _border_radius = internal_border_radius, + _border_size = internal_border_size, + _border_color = internal_border_color, + _text_color = internal_text_color, + _text_font = internal_text_font + )) + + # RESIZE GRIPS AND CHANGE POSITION + # Resize or change position when window is resized + # /////////////////////////////////////////////////////////////// + def _resize_grips(self, event): + if self.settings["custom_title_bar"]: + self.left_grip.setGeometry(0, 10, 10, self.parent.height()) + self.right_grip.setGeometry(self.parent.width() - 10, 10, 10, self.parent.height()) + self.top_grip.setGeometry(0, 0, self.parent.width(), 10) + self.bottom_grip.setGeometry(0, self.parent.height() - 10, self.parent.width(), 10) \ No newline at end of file diff --git a/gui/widgets/py_window/styles.py b/gui/widgets/py_window/styles.py new file mode 100644 index 0000000..a4e74e9 --- /dev/null +++ b/gui/widgets/py_window/styles.py @@ -0,0 +1,28 @@ +# /////////////////////////////////////////////////////////////// +# +# BY: WANDERSON M.PIMENTA +# PROJECT MADE WITH: Qt Designer and PySide6 +# V: 1.0.0 +# +# This project can be used freely for all uses, as long as they maintain the +# respective credits only in the Python scripts, any information in the visual +# interface (GUI) can be modified without any implication. +# +# There are limitations on Qt licenses if you want to use your products +# commercially, I recommend reading them on the official website: +# https://doc.qt.io/qtforpython/licenses.html +# +# /////////////////////////////////////////////////////////////// + +class Styles(object): + bg_style = """ + #pod_bg_app {{ + background-color: {_bg_color}; + border-radius: {_border_radius}; + border: {_border_size}px solid {_border_color}; + }} + QFrame {{ + color: {_text_color}; + font: {_text_font}; + }} + """ \ No newline at end of file