diff --git a/gui/images/svg_icons/no_icon.svg b/gui/images/svg_icons/no_icon.svg new file mode 100644 index 0000000..c61b428 --- /dev/null +++ b/gui/images/svg_icons/no_icon.svg @@ -0,0 +1,60 @@ + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/gui/themes/default.json b/gui/themes/default.json index 67ed005..3363093 100644 --- a/gui/themes/default.json +++ b/gui/themes/default.json @@ -7,6 +7,7 @@ "dark_four" : "#272c36", "bg_one" : "#2c313c", "bg_two" : "#343b48", + "bg_three" : "#3c4454", "icon_color" : "#c3ccdf", "icon_hover" : "#dce1ec", "icon_pressed" : "#edf0f5", diff --git a/gui/uis/windows/main_window/ui_main.py b/gui/uis/windows/main_window/ui_main.py index 59ed864..c84acd6 100644 --- a/gui/uis/windows/main_window/ui_main.py +++ b/gui/uis/windows/main_window/ui_main.py @@ -66,6 +66,10 @@ class UI_MainWindow(object): # Add central widget to app # /////////////////////////////////////////////////////////////// self.central_widget = QWidget() + self.central_widget.setStyleSheet(f''' + font: {self.settings["font"]["text_size"]}pt "{self.settings["font"]["family"]}"; + color: {self.themes["app_color"]["text_foreground"]}; + ''') self.central_widget_layout = QVBoxLayout(self.central_widget) if self.settings["custom_title_bar"]: self.central_widget_layout.setContentsMargins(10,10,10,10) @@ -81,6 +85,7 @@ class UI_MainWindow(object): border_color = self.themes["app_color"]["bg_two"], text_color = self.themes["app_color"]["text_foreground"] ) + # If disable custom title bar if not self.settings["custom_title_bar"]: @@ -156,7 +161,11 @@ class UI_MainWindow(object): # ADD CUSTOM TITLE BAR TO LAYOUT self.title_bar = PyTitleBar( - parent + parent, + bg_color = self.themes["app_color"]["bg_two"], + div_color = self.themes["app_color"]["bg_three"], + font_family = self.settings["font"]["family"], + title_size = self.settings["font"]["title_size"] ) self.title_bar_layout.addWidget(self.title_bar) diff --git a/gui/widgets/py_left_menu/py_div.py b/gui/widgets/py_left_menu/py_div.py index ec970dd..4976760 100644 --- a/gui/widgets/py_left_menu/py_div.py +++ b/gui/widgets/py_left_menu/py_div.py @@ -14,10 +14,6 @@ # # /////////////////////////////////////////////////////////////// -# IMPORT PACKAGES AND MODULES -# /////////////////////////////////////////////////////////////// -import os - # IMPORT QT CORE # /////////////////////////////////////////////////////////////// from qt_core import * @@ -28,7 +24,7 @@ class PyDiv(QWidget): def __init__(self, color): super(PyDiv, self).__init__() - self.layout = QVBoxLayout(self) + self.layout = QHBoxLayout(self) self.layout.setContentsMargins(5,0,5,0) self.frame_line = QFrame() self.frame_line.setStyleSheet(f"background: {color};") diff --git a/gui/widgets/py_left_menu/py_left_menu_button.py b/gui/widgets/py_left_menu/py_left_menu_button.py index a653c11..73ac1e4 100644 --- a/gui/widgets/py_left_menu/py_left_menu_button.py +++ b/gui/widgets/py_left_menu/py_left_menu_button.py @@ -260,7 +260,7 @@ class PyLeftMenuButton(QPushButton): if event.button() == Qt.LeftButton: self.change_style(QEvent.MouseButtonPress) self.tooltip.hide() - return self.clicked.emit() + return self.clicked.emit() # MOUSE RELEASED # Event triggered after the mouse button is released @@ -268,7 +268,7 @@ class PyLeftMenuButton(QPushButton): def mouseReleaseEvent(self, event): if event.button() == Qt.LeftButton: self.change_style(QEvent.MouseButtonRelease) - return self.released.emit() + return self.released.emit() # MOVE TOOLTIP # /////////////////////////////////////////////////////////////// diff --git a/gui/widgets/py_title_bar/py_div.py b/gui/widgets/py_title_bar/py_div.py new file mode 100644 index 0000000..c450a9b --- /dev/null +++ b/gui/widgets/py_title_bar/py_div.py @@ -0,0 +1,35 @@ +# /////////////////////////////////////////////////////////////// +# +# 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 QT CORE +# /////////////////////////////////////////////////////////////// +from qt_core import * + +# CUSTOM LEFT MENU +# /////////////////////////////////////////////////////////////// +class PyDiv(QWidget): + def __init__(self, color): + super(PyDiv, self).__init__() + + self.layout = QHBoxLayout(self) + self.layout.setContentsMargins(0,5,0,5) + self.frame_line = QFrame() + self.frame_line.setStyleSheet(f"background: {color};") + self.frame_line.setMaximumWidth(1) + self.frame_line.setMinimumWidth(1) + self.layout.addWidget(self.frame_line) + self.setMaximumWidth(20) + self.setMinimumWidth(20) diff --git a/gui/widgets/py_title_bar/py_title_bar.py b/gui/widgets/py_title_bar/py_title_bar.py index a5dc259..c5a8ae4 100644 --- a/gui/widgets/py_title_bar/py_title_bar.py +++ b/gui/widgets/py_title_bar/py_title_bar.py @@ -26,6 +26,19 @@ from gui.core.functions import * # /////////////////////////////////////////////////////////////// from gui.core.json_settings import Settings +# IMPORT DIV +# /////////////////////////////////////////////////////////////// +from . py_div import PyDiv + +# IMPORT BUTTON +# /////////////////////////////////////////////////////////////// +from . py_title_button import PyTitleButton + +# GLOBALS +# /////////////////////////////////////////////////////////////// +_is_maximized = False +_old_size = QSize() + # PY TITLE BAR # Top bar with move application, maximize, restore, minimize, # close buttons and extra buttons @@ -38,13 +51,39 @@ class PyTitleBar(QWidget): logo_width = 100, buttons = None, bg_color = "#343b48", - radius = 8 + div_color = "#3c4454", + btn_bg_color = "#343b48", + btn_bg_color_hover = "#3c4454", + btn_bg_color_pressed = "#2c313c", + icon_color = "#c3ccdf", + icon_color_hover = "#dce1ec", + icon_color_pressed = "#edf0f5", + icon_color_active = "#f5f6f9", + context_color = "#6c99f4", + radius = 8, + font_family = "Segoe UI", + title_size = 10 ): super(PyTitleBar, self).__init__() settings = Settings() self.settings = settings.items + # PARAMETERS + self._bg_color = bg_color + self._div_color = div_color + self._font_family = font_family + self._title_size = title_size + self._parent = parent + self._btn_bg_color = btn_bg_color + self._btn_bg_color_hover = btn_bg_color_hover + self._btn_bg_color_pressed = btn_bg_color_pressed + self._context_color = context_color + self._icon_color = icon_color + self._icon_color_hover = icon_color_hover + self._icon_color_pressed = icon_color_pressed + self._icon_color_active = icon_color_active + # SETUP UI self.setup_ui() @@ -60,26 +99,77 @@ class PyTitleBar(QWidget): self.title_label.setText(self.settings["app_name"]) # MOVE WINDOW / MAXIMIZE / RESTORE + # /////////////////////////////////////////////////////////////// def moveWindow(event): # IF MAXIMIZED CHANGE TO NORMAL - # if self.isMaximized(): - # UiFunctions.maximize_restore(self) - # self.resize(_old_size) - # curso_x = self.pos().x() - # curso_y = event.globalPos().y() - QCursor.pos().y() - # self.move(curso_x, curso_y) + if parent.isMaximized(): + self.maximize_restore() + #self.resize(_old_size) + curso_x = parent.pos().x() + curso_y = event.globalPos().y() - QCursor.pos().y() + parent.move(curso_x, curso_y) # MOVE WINDOW if event.buttons() == Qt.LeftButton: parent.move(parent.pos() + event.globalPos() - parent.dragPos) parent.dragPos = event.globalPos() event.accept() + + # MOVE APP WIDGETS self.top_logo.mouseMoveEvent = moveWindow + self.div_1.mouseMoveEvent = moveWindow self.title_label.mouseMoveEvent = moveWindow + self.div_2.mouseMoveEvent = moveWindow + + # MAXIMIZE / RESTORE + self.top_logo.mouseDoubleClickEvent = self.maximize_restore + self.div_1.mouseDoubleClickEvent = self.maximize_restore + self.title_label.mouseDoubleClickEvent = self.maximize_restore + self.div_2.mouseDoubleClickEvent = self.maximize_restore # ADD WIDGETS TO TITLE BAR + # /////////////////////////////////////////////////////////////// self.bg_layout.addWidget(self.top_logo) + self.bg_layout.addWidget(self.div_1) self.bg_layout.addWidget(self.title_label) - self.bg_layout.addWidget(self.right_frame) + self.bg_layout.addWidget(self.div_2) + + # ADD BUTTONS BUTTONS + # /////////////////////////////////////////////////////////////// + # Functions + self.minimize_button.clicked.connect(lambda: parent.showMinimized()) + self.maximize_restore_button.clicked.connect(lambda: self.maximize_restore()) + self.close_button.clicked.connect(lambda: parent.close()) + # ADD Buttons + self.bg_layout.addWidget(self.minimize_button) + self.bg_layout.addWidget(self.maximize_restore_button) + self.bg_layout.addWidget(self.close_button) + + # MAXIMIZE / RESTORE + # maximize and restore parent window + # /////////////////////////////////////////////////////////////// + def maximize_restore(self, e = None): + global _is_maximized + global _old_size + + # CHANGE UI AND RESIZE GRIP + def change_ui(): + if _is_maximized: + self._parent.ui.central_widget_layout.setContentsMargins(0,0,0,0) + self._parent.ui.window.set_stylesheet(border_radius = 0, border_size = 0) + else: + self._parent.ui.central_widget_layout.setContentsMargins(10,10,10,10) + self._parent.ui.window.set_stylesheet(border_radius = 10, border_size = 2) + + # CHECK EVENT + if self._parent.isMaximized(): + _is_maximized = False + self._parent.showNormal() + change_ui() + else: + _is_maximized = True + _old_size = QSize(self._parent.width(), self._parent.height()) + self._parent.showMaximized() + change_ui() # SETUP APP # /////////////////////////////////////////////////////////////// @@ -93,21 +183,59 @@ class PyTitleBar(QWidget): # ADD BG LAYOUT self.bg_layout = QHBoxLayout(self.bg) - self.bg_layout.setContentsMargins(10,0,0,0) + self.bg_layout.setContentsMargins(10,0,5,0) self.bg_layout.setSpacing(0) + # DIVS + self.div_1 = PyDiv(self._div_color) + self.div_2 = PyDiv(self._div_color) + # LEFT FRAME WITH MOVE APP self.top_logo = QLabel() # TITLE LABEL self.title_label = QLabel() self.title_label.setAlignment(Qt.AlignVCenter) - self.title_label.setStyleSheet("padding-left: 10px; font-size: 10pt") + self.title_label.setStyleSheet(f'font: {self._title_size}pt "{self._font_family}"') - # RIGHT FRAME WITH BUTTONS - self.right_frame = QFrame() - self.right_frame.setMinimumWidth(100) - self.right_frame.setStyleSheet("background: #CCC") + # MINIMIZE BUTTON + self.minimize_button = PyTitleButton( + tooltip_text = "Close app", + bg_color = self._btn_bg_color, + bg_color_hover = self._btn_bg_color_hover, + bg_color_pressed = self._btn_bg_color_pressed, + icon_color = self._icon_color, + icon_color_hover = self._icon_color_hover, + icon_color_pressed = self._icon_color_pressed, + icon_color_active = self._icon_color_active, + icon_path = Functions.set_svg_icon("icon_minimize.svg") + ) + + # MAXIMIZE / RESTORE BUTTON + self.maximize_restore_button = PyTitleButton( + tooltip_text = "Maximize app", + bg_color = self._btn_bg_color, + bg_color_hover = self._btn_bg_color_hover, + bg_color_pressed = self._btn_bg_color_pressed, + icon_color = self._icon_color, + icon_color_hover = self._icon_color_hover, + icon_color_pressed = self._icon_color_pressed, + icon_color_active = self._icon_color_active, + icon_path = Functions.set_svg_icon("icon_maximize.svg") + ) + + # CLOSE BUTTON + self.close_button = PyTitleButton( + tooltip_text = "Close app", + bg_color = self._btn_bg_color, + bg_color_hover = self._btn_bg_color_hover, + bg_color_pressed = self._context_color, + icon_color = self._icon_color, + icon_color_hover = self._icon_color_hover, + icon_color_pressed = self._icon_color_pressed, + icon_color_active = self._icon_color_active, + icon_path = Functions.set_svg_icon("icon_close.svg") + ) # ADD TO LAYOUT self.title_bar_layout.addWidget(self.bg) \ No newline at end of file diff --git a/gui/widgets/py_title_bar/py_title_button.py b/gui/widgets/py_title_bar/py_title_button.py new file mode 100644 index 0000000..65785d2 --- /dev/null +++ b/gui/widgets/py_title_bar/py_title_button.py @@ -0,0 +1,152 @@ +# /////////////////////////////////////////////////////////////// +# +# 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 QT CORE +# /////////////////////////////////////////////////////////////// +from qt_core import * + +# PY TITLE BUTTON +# /////////////////////////////////////////////////////////////// +class PyTitleButton(QPushButton): + def __init__( + self, + tooltip_text = "", + width = 30, + height = 30, + radius = 8, + bg_color = "#343b48", + bg_color_hover = "#3c4454", + bg_color_pressed = "#2c313c", + icon_color = "#c3ccdf", + icon_color_hover = "#dce1ec", + icon_color_pressed = "#edf0f5", + icon_color_active = "#f5f6f9", + icon_path = "no_icon.svg", + is_active = False + ): + super(PyTitleButton, self).__init__() + + # SET DEFAULT PARAMETERS + self.setFixedSize(width, height) + self.setCursor(Qt.PointingHandCursor) + + # PROPERTIES + self._bg_color = bg_color + self._bg_color_hover = bg_color_hover + self._bg_color_pressed = bg_color_pressed + self._icon_color = icon_color + self._icon_color_hover = icon_color_hover + self._icon_color_pressed = icon_color_pressed + self._icon_color_active = icon_color_active + # Set Parameters + self._set_bg_color = bg_color + self._set_icon_path = icon_path + self._set_icon_color = icon_color + self._set_border_radius = radius + + # PAINT EVENT + # painting the button and the icon + # /////////////////////////////////////////////////////////////// + def paintEvent(self, event): + # PAINTER + paint = QPainter() + paint.begin(self) + paint.setRenderHint(QPainter.RenderHint.Antialiasing) + + # BRUSH + brush = QBrush(QColor(self._set_bg_color)) + + # CREATE RECTANGLE + rect = QRect(0, 0, self.width(), self.height()) + paint.setPen(Qt.NoPen) + paint.setBrush(brush) + paint.drawRoundedRect( + rect, + self._set_border_radius, + self._set_border_radius + ) + + # DRAW ICONS + self.icon_paint(paint, self._set_icon_path, rect) + + # END PAINTER + paint.end() + + # CHANGE STYLES + # Functions with custom styles + def change_style(self, event): + if event == QEvent.Enter: + self._set_bg_color = self._bg_color_hover + self._set_icon_color = self._icon_color_hover + self.repaint() + elif event == QEvent.Leave: + self._set_bg_color = self._bg_color + self._set_icon_color = self._icon_color + self.repaint() + elif event == QEvent.MouseButtonPress: + self._set_bg_color = self._bg_color_pressed + self._set_icon_color = self._icon_color_pressed + self.repaint() + elif event == QEvent.MouseButtonRelease: + self._set_bg_color = self._bg_color_hover + self._set_icon_color = self._icon_color_hover + self.repaint() + + # MOUSE OVER + # Event triggered when the mouse is over the BTN + def enterEvent(self, event): + self.change_style(QEvent.Enter) + #self.move_tooltip() + #self.tooltip.show() + + # MOUSE LEAVE + # Event fired when the mouse leaves the BTN + def leaveEvent(self, event): + self.change_style(QEvent.Leave) + #self.move_tooltip() + #self.tooltip.hide() + + # MOUSE PRESS + # Event triggered when the left button is pressed + def mousePressEvent(self, event): + if event.button() == Qt.LeftButton: + self.change_style(QEvent.MouseButtonPress) + # SET FOCUS + self.setFocus() + # EMIT SIGNAL + return self.clicked.emit() + + # MOUSE RELEASED + # Event triggered after the mouse button is released + def mouseReleaseEvent(self, event): + if event.button() == Qt.LeftButton: + self.change_style(QEvent.MouseButtonRelease) + # EMIT SIGNAL + return self.released.emit() + + # DRAW ICON WITH COLORS + # /////////////////////////////////////////////////////////////// + def icon_paint(self, qp, image, rect): + icon = QPixmap(image) + painter = QPainter(icon) + painter.setCompositionMode(QPainter.CompositionMode_SourceIn) + painter.fillRect(icon.rect(), self._set_icon_color) + qp.drawPixmap( + (rect.width() - icon.width()) / 2, + (rect.height() - icon.height()) / 2, + icon + ) + painter.end() diff --git a/gui/widgets/py_window/py_window.py b/gui/widgets/py_window/py_window.py index f00a471..8d0ab17 100644 --- a/gui/widgets/py_window/py_window.py +++ b/gui/widgets/py_window/py_window.py @@ -25,10 +25,6 @@ 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 diff --git a/settings.json b/settings.json index dd84267..f8e31bc 100644 --- a/settings.json +++ b/settings.json @@ -18,5 +18,10 @@ "minimum" : 240, "maximum" : 240 }, - "theme_name": "default" + "theme_name" : "default", + "font" : { + "family" : "Segoe UI", + "title_size" : 10, + "text_size" : 9 + } } \ No newline at end of file