diff --git a/README.md b/README.md
index 766fc9d..d2c315e 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,3 @@
-# libmangers
+# 大学图书馆管理系统
+## Working in progress
\ No newline at end of file
diff --git a/src/educoder/gui/core/functions.py b/src/educoder/gui/core/functions.py
new file mode 100644
index 0000000..5705a53
--- /dev/null
+++ b/src/educoder/gui/core/functions.py
@@ -0,0 +1,50 @@
+# ///////////////////////////////////////////////////////////////
+#
+# 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 os
+
+# APP FUNCTIONS
+# ///////////////////////////////////////////////////////////////
+class Functions:
+
+ # SET SVG ICON
+ # ///////////////////////////////////////////////////////////////
+ def set_svg_icon(icon_name):
+ app_path = os.path.abspath(os.getcwd())
+ folder = "gui/images/svg_icons/"
+ path = os.path.join(app_path, folder)
+ icon = os.path.normpath(os.path.join(path, icon_name))
+ return icon
+
+ # SET SVG IMAGE
+ # ///////////////////////////////////////////////////////////////
+ def set_svg_image(icon_name):
+ app_path = os.path.abspath(os.getcwd())
+ folder = "gui/images/svg_images/"
+ path = os.path.join(app_path, folder)
+ icon = os.path.normpath(os.path.join(path, icon_name))
+ return icon
+
+ # SET IMAGE
+ # ///////////////////////////////////////////////////////////////
+ def set_image(image_name):
+ app_path = os.path.abspath(os.getcwd())
+ folder = "gui/images/images/"
+ path = os.path.join(app_path, folder)
+ image = os.path.normpath(os.path.join(path, image_name))
+ return image
\ No newline at end of file
diff --git a/src/educoder/gui/core/json_settings.py b/src/educoder/gui/core/json_settings.py
new file mode 100644
index 0000000..d54f6cd
--- /dev/null
+++ b/src/educoder/gui/core/json_settings.py
@@ -0,0 +1,58 @@
+# ///////////////////////////////////////////////////////////////
+#
+# 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 json
+import os
+
+# APP SETTINGS
+# ///////////////////////////////////////////////////////////////
+class Settings(object):
+ # APP PATH
+ # ///////////////////////////////////////////////////////////////
+ json_file = "settings.json"
+ app_path = os.path.abspath(os.getcwd())
+ 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}")
+
+ # INIT SETTINGS
+ # ///////////////////////////////////////////////////////////////
+ def __init__(self):
+ super(Settings, self).__init__()
+
+ # DICTIONARY WITH SETTINGS
+ # Just to have objects references
+ self.items = {}
+
+ # DESERIALIZE
+ self.deserialize()
+
+ # SERIALIZE JSON
+ # ///////////////////////////////////////////////////////////////
+ def serialize(self):
+ # WRITE JSON FILE
+ with open(self.settings_path, "w", encoding='utf-8') as write:
+ json.dump(self.items, write, indent=4)
+
+ # DESERIALIZE JSON
+ # ///////////////////////////////////////////////////////////////
+ def deserialize(self):
+ # READ JSON FILE
+ with open(self.settings_path, "r", encoding='utf-8') as reader:
+ settings = json.loads(reader.read())
+ self.items = settings
\ No newline at end of file
diff --git a/src/educoder/gui/core/json_themes.py b/src/educoder/gui/core/json_themes.py
new file mode 100644
index 0000000..f3044ca
--- /dev/null
+++ b/src/educoder/gui/core/json_themes.py
@@ -0,0 +1,66 @@
+# ///////////////////////////////////////////////////////////////
+#
+# 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 json
+import os
+
+# IMPORT SETTINGS
+# ///////////////////////////////////////////////////////////////
+from src.educoder.gui.core.json_settings import Settings
+
+# APP THEMES
+# ///////////////////////////////////////////////////////////////
+class Themes(object):
+ # LOAD SETTINGS
+ # ///////////////////////////////////////////////////////////////
+ setup_settings = Settings()
+ _settings = setup_settings.items
+
+ # APP PATH
+ # ///////////////////////////////////////////////////////////////
+ json_file = f"gui/themes/{_settings['theme_name']}.json"
+ app_path = os.path.abspath(os.getcwd())
+ settings_path = os.path.normpath(os.path.join(app_path, json_file))
+ if not os.path.isfile(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(Themes, self).__init__()
+
+ # DICTIONARY WITH SETTINGS
+ self.items = {}
+
+ # DESERIALIZE
+ self.deserialize()
+
+ # SERIALIZE JSON
+ # ///////////////////////////////////////////////////////////////
+ def serialize(self):
+ # WRITE JSON FILE
+ with open(self.settings_path, "w", encoding='utf-8') as write:
+ json.dump(self.items, write, indent=4)
+
+ # DESERIALIZE JSON
+ # ///////////////////////////////////////////////////////////////
+ def deserialize(self):
+ # READ JSON FILE
+ with open(self.settings_path, "r", encoding='utf-8') as reader:
+ settings = json.loads(reader.read())
+ self.items = settings
\ No newline at end of file
diff --git a/src/educoder/gui/images/svg_icons/active_menu.svg b/src/educoder/gui/images/svg_icons/active_menu.svg
new file mode 100644
index 0000000..b74309a
--- /dev/null
+++ b/src/educoder/gui/images/svg_icons/active_menu.svg
@@ -0,0 +1,79 @@
+
+
diff --git a/src/educoder/gui/images/svg_icons/icon_add_user.svg b/src/educoder/gui/images/svg_icons/icon_add_user.svg
new file mode 100644
index 0000000..2a51754
--- /dev/null
+++ b/src/educoder/gui/images/svg_icons/icon_add_user.svg
@@ -0,0 +1,61 @@
+
+
diff --git a/src/educoder/gui/images/svg_icons/icon_arrow_left.svg b/src/educoder/gui/images/svg_icons/icon_arrow_left.svg
new file mode 100644
index 0000000..6bc8f9a
--- /dev/null
+++ b/src/educoder/gui/images/svg_icons/icon_arrow_left.svg
@@ -0,0 +1,61 @@
+
+
diff --git a/src/educoder/gui/images/svg_icons/icon_arrow_right.svg b/src/educoder/gui/images/svg_icons/icon_arrow_right.svg
new file mode 100644
index 0000000..4f7bac9
--- /dev/null
+++ b/src/educoder/gui/images/svg_icons/icon_arrow_right.svg
@@ -0,0 +1,61 @@
+
+
diff --git a/src/educoder/gui/images/svg_icons/icon_attachment.svg b/src/educoder/gui/images/svg_icons/icon_attachment.svg
new file mode 100644
index 0000000..51a21f5
--- /dev/null
+++ b/src/educoder/gui/images/svg_icons/icon_attachment.svg
@@ -0,0 +1,78 @@
+
+
diff --git a/src/educoder/gui/images/svg_icons/icon_busy.svg b/src/educoder/gui/images/svg_icons/icon_busy.svg
new file mode 100644
index 0000000..309de02
--- /dev/null
+++ b/src/educoder/gui/images/svg_icons/icon_busy.svg
@@ -0,0 +1,60 @@
+
+
diff --git a/src/educoder/gui/images/svg_icons/icon_close.svg b/src/educoder/gui/images/svg_icons/icon_close.svg
new file mode 100644
index 0000000..56651fa
--- /dev/null
+++ b/src/educoder/gui/images/svg_icons/icon_close.svg
@@ -0,0 +1,61 @@
+
+
diff --git a/src/educoder/gui/images/svg_icons/icon_emoticons.svg b/src/educoder/gui/images/svg_icons/icon_emoticons.svg
new file mode 100644
index 0000000..9b5c4e9
--- /dev/null
+++ b/src/educoder/gui/images/svg_icons/icon_emoticons.svg
@@ -0,0 +1,78 @@
+
+
diff --git a/src/educoder/gui/images/svg_icons/icon_file.svg b/src/educoder/gui/images/svg_icons/icon_file.svg
new file mode 100644
index 0000000..3cd93a9
--- /dev/null
+++ b/src/educoder/gui/images/svg_icons/icon_file.svg
@@ -0,0 +1,63 @@
+
+
diff --git a/src/educoder/gui/images/svg_icons/icon_folder.svg b/src/educoder/gui/images/svg_icons/icon_folder.svg
new file mode 100644
index 0000000..48fe08f
--- /dev/null
+++ b/src/educoder/gui/images/svg_icons/icon_folder.svg
@@ -0,0 +1,62 @@
+
+
diff --git a/src/educoder/gui/images/svg_icons/icon_folder_open.svg b/src/educoder/gui/images/svg_icons/icon_folder_open.svg
new file mode 100644
index 0000000..ec541bc
--- /dev/null
+++ b/src/educoder/gui/images/svg_icons/icon_folder_open.svg
@@ -0,0 +1,63 @@
+
+
diff --git a/src/educoder/gui/images/svg_icons/icon_heart.svg b/src/educoder/gui/images/svg_icons/icon_heart.svg
new file mode 100644
index 0000000..ba64b5c
--- /dev/null
+++ b/src/educoder/gui/images/svg_icons/icon_heart.svg
@@ -0,0 +1,62 @@
+
+
diff --git a/src/educoder/gui/images/svg_icons/icon_home.svg b/src/educoder/gui/images/svg_icons/icon_home.svg
new file mode 100644
index 0000000..c5619cf
--- /dev/null
+++ b/src/educoder/gui/images/svg_icons/icon_home.svg
@@ -0,0 +1,66 @@
+
+
diff --git a/src/educoder/gui/images/svg_icons/icon_idle.svg b/src/educoder/gui/images/svg_icons/icon_idle.svg
new file mode 100644
index 0000000..0997f52
--- /dev/null
+++ b/src/educoder/gui/images/svg_icons/icon_idle.svg
@@ -0,0 +1,60 @@
+
+
diff --git a/src/educoder/gui/images/svg_icons/icon_info.svg b/src/educoder/gui/images/svg_icons/icon_info.svg
new file mode 100644
index 0000000..cf98b18
--- /dev/null
+++ b/src/educoder/gui/images/svg_icons/icon_info.svg
@@ -0,0 +1,78 @@
+
+
diff --git a/src/educoder/gui/images/svg_icons/icon_invisible.svg b/src/educoder/gui/images/svg_icons/icon_invisible.svg
new file mode 100644
index 0000000..cf2bcec
--- /dev/null
+++ b/src/educoder/gui/images/svg_icons/icon_invisible.svg
@@ -0,0 +1,61 @@
+
+
diff --git a/src/educoder/gui/images/svg_icons/icon_maximize.svg b/src/educoder/gui/images/svg_icons/icon_maximize.svg
new file mode 100644
index 0000000..4b15003
--- /dev/null
+++ b/src/educoder/gui/images/svg_icons/icon_maximize.svg
@@ -0,0 +1,61 @@
+
+
diff --git a/src/educoder/gui/images/svg_icons/icon_menu.svg b/src/educoder/gui/images/svg_icons/icon_menu.svg
new file mode 100644
index 0000000..e486198
--- /dev/null
+++ b/src/educoder/gui/images/svg_icons/icon_menu.svg
@@ -0,0 +1,63 @@
+
+
diff --git a/src/educoder/gui/images/svg_icons/icon_menu_close.svg b/src/educoder/gui/images/svg_icons/icon_menu_close.svg
new file mode 100644
index 0000000..699f1f2
--- /dev/null
+++ b/src/educoder/gui/images/svg_icons/icon_menu_close.svg
@@ -0,0 +1,61 @@
+
+
diff --git a/src/educoder/gui/images/svg_icons/icon_minimize.svg b/src/educoder/gui/images/svg_icons/icon_minimize.svg
new file mode 100644
index 0000000..e333b56
--- /dev/null
+++ b/src/educoder/gui/images/svg_icons/icon_minimize.svg
@@ -0,0 +1,61 @@
+
+
diff --git a/src/educoder/gui/images/svg_icons/icon_more_options.svg b/src/educoder/gui/images/svg_icons/icon_more_options.svg
new file mode 100644
index 0000000..689ac36
--- /dev/null
+++ b/src/educoder/gui/images/svg_icons/icon_more_options.svg
@@ -0,0 +1,78 @@
+
+
diff --git a/src/educoder/gui/images/svg_icons/icon_online.svg b/src/educoder/gui/images/svg_icons/icon_online.svg
new file mode 100644
index 0000000..d335a7e
--- /dev/null
+++ b/src/educoder/gui/images/svg_icons/icon_online.svg
@@ -0,0 +1,60 @@
+
+
diff --git a/src/educoder/gui/images/svg_icons/icon_restore.svg b/src/educoder/gui/images/svg_icons/icon_restore.svg
new file mode 100644
index 0000000..18dabdd
--- /dev/null
+++ b/src/educoder/gui/images/svg_icons/icon_restore.svg
@@ -0,0 +1,60 @@
+
+
diff --git a/src/educoder/gui/images/svg_icons/icon_save.svg b/src/educoder/gui/images/svg_icons/icon_save.svg
new file mode 100644
index 0000000..c5074df
--- /dev/null
+++ b/src/educoder/gui/images/svg_icons/icon_save.svg
@@ -0,0 +1,61 @@
+
+
diff --git a/src/educoder/gui/images/svg_icons/icon_search.svg b/src/educoder/gui/images/svg_icons/icon_search.svg
new file mode 100644
index 0000000..a4cc81f
--- /dev/null
+++ b/src/educoder/gui/images/svg_icons/icon_search.svg
@@ -0,0 +1,60 @@
+
+
diff --git a/src/educoder/gui/images/svg_icons/icon_send.svg b/src/educoder/gui/images/svg_icons/icon_send.svg
new file mode 100644
index 0000000..8e75b7f
--- /dev/null
+++ b/src/educoder/gui/images/svg_icons/icon_send.svg
@@ -0,0 +1,78 @@
+
+
diff --git a/src/educoder/gui/images/svg_icons/icon_settings.svg b/src/educoder/gui/images/svg_icons/icon_settings.svg
new file mode 100644
index 0000000..02f1b90
--- /dev/null
+++ b/src/educoder/gui/images/svg_icons/icon_settings.svg
@@ -0,0 +1,78 @@
+
+
diff --git a/src/educoder/gui/images/svg_icons/icon_signal.svg b/src/educoder/gui/images/svg_icons/icon_signal.svg
new file mode 100644
index 0000000..5c1558d
--- /dev/null
+++ b/src/educoder/gui/images/svg_icons/icon_signal.svg
@@ -0,0 +1,78 @@
+
+
diff --git a/src/educoder/gui/images/svg_icons/icon_widgets.svg b/src/educoder/gui/images/svg_icons/icon_widgets.svg
new file mode 100644
index 0000000..d0171c2
--- /dev/null
+++ b/src/educoder/gui/images/svg_icons/icon_widgets.svg
@@ -0,0 +1,101 @@
+
+
diff --git a/src/educoder/gui/images/svg_icons/no_icon.svg b/src/educoder/gui/images/svg_icons/no_icon.svg
new file mode 100644
index 0000000..c61b428
--- /dev/null
+++ b/src/educoder/gui/images/svg_icons/no_icon.svg
@@ -0,0 +1,60 @@
+
+
diff --git a/src/educoder/gui/images/svg_images/logo_home.svg b/src/educoder/gui/images/svg_images/logo_home.svg
new file mode 100644
index 0000000..377a685
--- /dev/null
+++ b/src/educoder/gui/images/svg_images/logo_home.svg
@@ -0,0 +1,158 @@
+
+
diff --git a/src/educoder/gui/images/svg_images/logo_top_100x22.svg b/src/educoder/gui/images/svg_images/logo_top_100x22.svg
new file mode 100644
index 0000000..f1a2c3d
--- /dev/null
+++ b/src/educoder/gui/images/svg_images/logo_top_100x22.svg
@@ -0,0 +1,157 @@
+
+
diff --git a/src/educoder/gui/themes/bright_theme.json b/src/educoder/gui/themes/bright_theme.json
new file mode 100644
index 0000000..1c13669
--- /dev/null
+++ b/src/educoder/gui/themes/bright_theme.json
@@ -0,0 +1,28 @@
+{
+ "theme_name" : "Default",
+ "app_color" : {
+ "dark_one" : "#1b1e23",
+ "dark_two" : "#1e2229",
+ "dark_three" : "#21252d",
+ "dark_four" : "#272c36",
+ "bg_one" : "#D3E0F7",
+ "bg_two" : "#E2E9F7",
+ "bg_three" : "#EFF1F7",
+ "icon_color" : "#6C7C96",
+ "icon_hover" : "#8CB8FF",
+ "icon_pressed" : "#6c99f4",
+ "icon_active" : "#8CB8FF",
+ "context_color" : "#568af2",
+ "context_hover" : "#6c99f4",
+ "context_pressed" : "#4B5469",
+ "text_title" : "#606C85",
+ "text_foreground" : "#6B7894",
+ "text_description" : "#7887A6",
+ "text_active" : "#8797BA",
+ "white" : "#f5f6f9",
+ "pink" : "#ff007f",
+ "green" : "#00ff7f",
+ "red" : "#ff5555",
+ "yellow" : "#f1fa8c"
+ }
+}
\ No newline at end of file
diff --git a/src/educoder/gui/themes/default.json b/src/educoder/gui/themes/default.json
new file mode 100644
index 0000000..e1f86f0
--- /dev/null
+++ b/src/educoder/gui/themes/default.json
@@ -0,0 +1,28 @@
+{
+ "theme_name" : "Default",
+ "app_color" : {
+ "dark_one" : "#1b1e23",
+ "dark_two" : "#1e2229",
+ "dark_three" : "#21252d",
+ "dark_four" : "#272c36",
+ "bg_one" : "#2c313c",
+ "bg_two" : "#343b48",
+ "bg_three" : "#3c4454",
+ "icon_color" : "#c3ccdf",
+ "icon_hover" : "#dce1ec",
+ "icon_pressed" : "#6c99f4",
+ "icon_active" : "#f5f6f9",
+ "context_color" : "#568af2",
+ "context_hover" : "#6c99f4",
+ "context_pressed" : "#3f6fd1",
+ "text_title" : "#dce1ec",
+ "text_foreground" : "#8a95aa",
+ "text_description" : "#4f5b6e",
+ "text_active" : "#dce1ec",
+ "white" : "#f5f6f9",
+ "pink" : "#ff007f",
+ "green" : "#00ff7f",
+ "red" : "#ff5555",
+ "yellow" : "#f1fa8c"
+ }
+}
\ No newline at end of file
diff --git a/src/educoder/gui/themes/dracula.json b/src/educoder/gui/themes/dracula.json
new file mode 100644
index 0000000..2bad4b5
--- /dev/null
+++ b/src/educoder/gui/themes/dracula.json
@@ -0,0 +1,28 @@
+{
+ "theme_name" : "dracula",
+ "app_color" : {
+ "dark_one" : "#282a36",
+ "dark_two" : "#2B2E3B",
+ "dark_three" : "#333645",
+ "dark_four" : "#3C4052",
+ "bg_one" : "#44475a",
+ "bg_two" : "#4D5066",
+ "bg_three" : "#595D75",
+ "icon_color" : "#c3ccdf",
+ "icon_hover" : "#dce1ec",
+ "icon_pressed" : "#ff79c6",
+ "icon_active" : "#f5f6f9",
+ "context_color" : "#ff79c6",
+ "context_hover" : "#FF84D7",
+ "context_pressed" : "#FF90DD",
+ "text_title" : "#dce1ec",
+ "text_foreground" : "#f8f8f2",
+ "text_description" : "#979EC7",
+ "text_active" : "#dce1ec",
+ "white" : "#f5f6f9",
+ "pink" : "#ff79c6",
+ "green" : "#00ff7f",
+ "red" : "#ff5555",
+ "yellow" : "#f1fa8c"
+ }
+}
\ No newline at end of file
diff --git a/src/educoder/gui/uis/columns/left_column.ui b/src/educoder/gui/uis/columns/left_column.ui
new file mode 100644
index 0000000..cd9c761
--- /dev/null
+++ b/src/educoder/gui/uis/columns/left_column.ui
@@ -0,0 +1,271 @@
+
+
+ LeftColumn
+
+
+
+ 0
+ 0
+ 240
+ 600
+
+
+
+ Form
+
+
+
+ 0
+
+
+ 5
+
+
+ 5
+
+
+ 5
+
+
+ 5
+
+ -
+
+
+ 0
+
+
+
+
+ 5
+
+
+ 5
+
+
+ 5
+
+
+ 5
+
+
+ 5
+
+
-
+
+
+
+ 0
+ 40
+
+
+
+
+ 16777215
+ 40
+
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+
+
+ -
+
+
+
+ 0
+ 40
+
+
+
+
+ 16777215
+ 40
+
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+
+
+ -
+
+
+
+ 0
+ 40
+
+
+
+
+ 16777215
+ 40
+
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+
+
+ -
+
+
+
+ 16
+
+
+
+ font-size: 16pt
+
+
+ Menu 1 - Left Menu
+
+
+ Qt::AlignCenter
+
+
+
+
+
+
+
+
+ 5
+
+
+ 5
+
+
+ 5
+
+
+ 5
+
+
+ 5
+
+ -
+
+
+
+ 0
+ 40
+
+
+
+
+ 16777215
+ 40
+
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+
+
+ -
+
+
+
+ 16
+
+
+
+ font-size: 16pt
+
+
+ Menu 2 - Left Menu
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+ 9
+
+
+
+ font-size: 9pt
+
+
+ This is just an example menu.
+Add Qt Widgets or your custom widgets here.
+
+
+ Qt::AlignCenter
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/educoder/gui/uis/columns/right_column.ui b/src/educoder/gui/uis/columns/right_column.ui
new file mode 100644
index 0000000..c25d04d
--- /dev/null
+++ b/src/educoder/gui/uis/columns/right_column.ui
@@ -0,0 +1,117 @@
+
+
+ RightColumn
+
+
+
+ 0
+ 0
+ 240
+ 600
+
+
+
+ Form
+
+
+
+ 0
+
+
+ 5
+
+
+ 5
+
+
+ 5
+
+
+ 5
+
+ -
+
+
+ 0
+
+
+
+
+ 5
+
+
+ 5
+
+
+ 5
+
+
+ 5
+
+
+ 5
+
+
-
+
+
+
+ 16
+
+
+
+ font-size: 16pt
+
+
+ Menu 1 - Right Menu
+
+
+ Qt::AlignCenter
+
+
+
+
+
+
+
+
+ 5
+
+
+ 5
+
+
+ 5
+
+
+ 5
+
+
+ 5
+
+ -
+
+
+
+ 16
+
+
+
+ font-size: 16pt
+
+
+ Menu 2 - Right Menu
+
+
+ Qt::AlignCenter
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/educoder/gui/uis/columns/ui_left_column.py b/src/educoder/gui/uis/columns/ui_left_column.py
new file mode 100644
index 0000000..315b6cc
--- /dev/null
+++ b/src/educoder/gui/uis/columns/ui_left_column.py
@@ -0,0 +1,138 @@
+# ///////////////////////////////////////////////////////////////
+#
+# 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 src.educoder.qt_core import *
+
+class Ui_LeftColumn(object):
+ def setupUi(self, LeftColumn):
+ if not LeftColumn.objectName():
+ LeftColumn.setObjectName(u"LeftColumn")
+ LeftColumn.resize(240, 600)
+ self.main_pages_layout = QVBoxLayout(LeftColumn)
+ self.main_pages_layout.setSpacing(0)
+ self.main_pages_layout.setObjectName(u"main_pages_layout")
+ self.main_pages_layout.setContentsMargins(5, 5, 5, 5)
+ self.menus = QStackedWidget(LeftColumn)
+ self.menus.setObjectName(u"menus")
+ self.menu_1 = QWidget()
+ self.menu_1.setObjectName(u"menu_1")
+ self.verticalLayout = QVBoxLayout(self.menu_1)
+ self.verticalLayout.setSpacing(5)
+ self.verticalLayout.setObjectName(u"verticalLayout")
+ self.verticalLayout.setContentsMargins(5, 5, 5, 5)
+ self.btn_1_widget = QWidget(self.menu_1)
+ self.btn_1_widget.setObjectName(u"btn_1_widget")
+ self.btn_1_widget.setMinimumSize(QSize(0, 40))
+ self.btn_1_widget.setMaximumSize(QSize(16777215, 40))
+ self.btn_1_layout = QVBoxLayout(self.btn_1_widget)
+ self.btn_1_layout.setSpacing(0)
+ self.btn_1_layout.setObjectName(u"btn_1_layout")
+ self.btn_1_layout.setContentsMargins(0, 0, 0, 0)
+
+ self.verticalLayout.addWidget(self.btn_1_widget)
+
+ self.btn_2_widget = QWidget(self.menu_1)
+ self.btn_2_widget.setObjectName(u"btn_2_widget")
+ self.btn_2_widget.setMinimumSize(QSize(0, 40))
+ self.btn_2_widget.setMaximumSize(QSize(16777215, 40))
+ self.btn_2_layout = QVBoxLayout(self.btn_2_widget)
+ self.btn_2_layout.setSpacing(0)
+ self.btn_2_layout.setObjectName(u"btn_2_layout")
+ self.btn_2_layout.setContentsMargins(0, 0, 0, 0)
+
+ self.verticalLayout.addWidget(self.btn_2_widget)
+
+ self.btn_3_widget = QWidget(self.menu_1)
+ self.btn_3_widget.setObjectName(u"btn_3_widget")
+ self.btn_3_widget.setMinimumSize(QSize(0, 40))
+ self.btn_3_widget.setMaximumSize(QSize(16777215, 40))
+ self.btn_3_layout = QVBoxLayout(self.btn_3_widget)
+ self.btn_3_layout.setSpacing(0)
+ self.btn_3_layout.setObjectName(u"btn_3_layout")
+ self.btn_3_layout.setContentsMargins(0, 0, 0, 0)
+
+ self.verticalLayout.addWidget(self.btn_3_widget)
+
+ self.label_1 = QLabel(self.menu_1)
+ self.label_1.setObjectName(u"label_1")
+ font = QFont()
+ font.setPointSize(16)
+ self.label_1.setFont(font)
+ self.label_1.setStyleSheet(u"font-size: 16pt")
+ self.label_1.setAlignment(Qt.AlignCenter)
+
+ self.verticalLayout.addWidget(self.label_1)
+
+ self.menus.addWidget(self.menu_1)
+ self.menu_2 = QWidget()
+ self.menu_2.setObjectName(u"menu_2")
+ self.verticalLayout_2 = QVBoxLayout(self.menu_2)
+ self.verticalLayout_2.setSpacing(5)
+ self.verticalLayout_2.setObjectName(u"verticalLayout_2")
+ self.verticalLayout_2.setContentsMargins(5, 5, 5, 5)
+ self.btn_4_widget = QWidget(self.menu_2)
+ self.btn_4_widget.setObjectName(u"btn_4_widget")
+ self.btn_4_widget.setMinimumSize(QSize(0, 40))
+ self.btn_4_widget.setMaximumSize(QSize(16777215, 40))
+ self.btn_4_layout = QVBoxLayout(self.btn_4_widget)
+ self.btn_4_layout.setSpacing(0)
+ self.btn_4_layout.setObjectName(u"btn_4_layout")
+ self.btn_4_layout.setContentsMargins(0, 0, 0, 0)
+
+ self.verticalLayout_2.addWidget(self.btn_4_widget)
+
+ self.label_2 = QLabel(self.menu_2)
+ self.label_2.setObjectName(u"label_2")
+ self.label_2.setFont(font)
+ self.label_2.setStyleSheet(u"font-size: 16pt")
+ self.label_2.setAlignment(Qt.AlignCenter)
+
+ self.verticalLayout_2.addWidget(self.label_2)
+
+ self.label_3 = QLabel(self.menu_2)
+ self.label_3.setObjectName(u"label_3")
+ font1 = QFont()
+ font1.setPointSize(9)
+ self.label_3.setFont(font1)
+ self.label_3.setStyleSheet(u"font-size: 9pt")
+ self.label_3.setAlignment(Qt.AlignCenter)
+ self.label_3.setWordWrap(True)
+
+ self.verticalLayout_2.addWidget(self.label_3)
+
+ self.menus.addWidget(self.menu_2)
+
+ self.main_pages_layout.addWidget(self.menus)
+
+
+ self.retranslateUi(LeftColumn)
+
+ self.menus.setCurrentIndex(0)
+
+
+ QMetaObject.connectSlotsByName(LeftColumn)
+ # setupUi
+
+ def retranslateUi(self, LeftColumn):
+ LeftColumn.setWindowTitle(QCoreApplication.translate("LeftColumn", u"Form", None))
+ self.label_1.setText(QCoreApplication.translate("LeftColumn", u"Menu 1 - Left Menu", None))
+ self.label_2.setText(QCoreApplication.translate("LeftColumn", u"Menu 2 - Left Menu", None))
+ self.label_3.setText(QCoreApplication.translate("LeftColumn", u"This is just an example menu.\n"
+"Add Qt Widgets or your custom widgets here.", None))
+ # retranslateUi
+
diff --git a/src/educoder/gui/uis/columns/ui_right_column.py b/src/educoder/gui/uis/columns/ui_right_column.py
new file mode 100644
index 0000000..7f9cf91
--- /dev/null
+++ b/src/educoder/gui/uis/columns/ui_right_column.py
@@ -0,0 +1,116 @@
+# ///////////////////////////////////////////////////////////////
+#
+# 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 src.educoder.qt_core import *
+
+class Ui_RightColumn(object):
+ def setupUi(self, RightColumn):
+ if not RightColumn.objectName():
+ RightColumn.setObjectName(u"RightColumn")
+ RightColumn.resize(240, 600)
+ self.main_pages_layout = QVBoxLayout(RightColumn)
+ self.main_pages_layout.setSpacing(0)
+ self.main_pages_layout.setObjectName(u"main_pages_layout")
+ self.main_pages_layout.setContentsMargins(5, 5, 5, 5)
+ self.menus = QStackedWidget(RightColumn)
+ self.menus.setObjectName(u"menus")
+ self.menu_1 = QWidget()
+ self.menu_1.setObjectName(u"menu_1")
+ self.verticalLayout = QVBoxLayout(self.menu_1)
+ self.verticalLayout.setSpacing(5)
+ self.verticalLayout.setObjectName(u"verticalLayout")
+ self.verticalLayout.setContentsMargins(5, 5, 5, 5)
+ self.btn_1_widget = QWidget(self.menu_1)
+ self.btn_1_widget.setObjectName(u"btn_1_widget")
+ self.btn_1_widget.setMinimumSize(QSize(0, 40))
+ self.btn_1_widget.setMaximumSize(QSize(16777215, 40))
+ self.btn_1_layout = QVBoxLayout(self.btn_1_widget)
+ self.btn_1_layout.setSpacing(0)
+ self.btn_1_layout.setObjectName(u"btn_1_layout")
+ self.btn_1_layout.setContentsMargins(0, 0, 0, 0)
+
+ self.verticalLayout.addWidget(self.btn_1_widget)
+
+ self.label_1 = QLabel(self.menu_1)
+ self.label_1.setObjectName(u"label_1")
+ font = QFont()
+ font.setPointSize(16)
+ self.label_1.setFont(font)
+ self.label_1.setStyleSheet(u"font-size: 16pt")
+ self.label_1.setAlignment(Qt.AlignCenter)
+
+ self.verticalLayout.addWidget(self.label_1)
+
+ self.menus.addWidget(self.menu_1)
+ self.menu_2 = QWidget()
+ self.menu_2.setObjectName(u"menu_2")
+ self.verticalLayout_2 = QVBoxLayout(self.menu_2)
+ self.verticalLayout_2.setSpacing(5)
+ self.verticalLayout_2.setObjectName(u"verticalLayout_2")
+ self.verticalLayout_2.setContentsMargins(5, 5, 5, 5)
+ self.btn_2_widget = QWidget(self.menu_2)
+ self.btn_2_widget.setObjectName(u"btn_2_widget")
+ self.btn_2_widget.setMinimumSize(QSize(0, 40))
+ self.btn_2_widget.setMaximumSize(QSize(16777215, 40))
+ self.btn_2_layout = QVBoxLayout(self.btn_2_widget)
+ self.btn_2_layout.setSpacing(0)
+ self.btn_2_layout.setObjectName(u"btn_2_layout")
+ self.btn_2_layout.setContentsMargins(0, 0, 0, 0)
+
+ self.verticalLayout_2.addWidget(self.btn_2_widget)
+
+ self.label_2 = QLabel(self.menu_2)
+ self.label_2.setObjectName(u"label_2")
+ self.label_2.setFont(font)
+ self.label_2.setStyleSheet(u"font-size: 16pt")
+ self.label_2.setAlignment(Qt.AlignCenter)
+
+ self.verticalLayout_2.addWidget(self.label_2)
+
+ self.label_3 = QLabel(self.menu_2)
+ self.label_3.setObjectName(u"label_3")
+ font1 = QFont()
+ font1.setPointSize(9)
+ self.label_3.setFont(font1)
+ self.label_3.setStyleSheet(u"font-size: 9pt")
+ self.label_3.setAlignment(Qt.AlignCenter)
+ self.label_3.setWordWrap(True)
+
+ self.verticalLayout_2.addWidget(self.label_3)
+
+ self.menus.addWidget(self.menu_2)
+
+ self.main_pages_layout.addWidget(self.menus)
+
+
+ self.retranslateUi(RightColumn)
+
+ self.menus.setCurrentIndex(1)
+
+
+ QMetaObject.connectSlotsByName(RightColumn)
+ # setupUi
+
+ def retranslateUi(self, RightColumn):
+ RightColumn.setWindowTitle(QCoreApplication.translate("RightColumn", u"Form", None))
+ self.label_1.setText(QCoreApplication.translate("RightColumn", u"Menu 1 - Right Menu", None))
+ self.label_2.setText(QCoreApplication.translate("RightColumn", u"Menu 2 - Right Menu", None))
+ self.label_3.setText(QCoreApplication.translate("RightColumn", u"This is just an example menu.\n"
+"Add Qt Widgets or your custom widgets here.", None))
+ # retranslateUi
+
diff --git a/src/educoder/gui/uis/pages/main_pages.ui b/src/educoder/gui/uis/pages/main_pages.ui
new file mode 100644
index 0000000..04bce61
--- /dev/null
+++ b/src/educoder/gui/uis/pages/main_pages.ui
@@ -0,0 +1,298 @@
+
+
+ MainPages
+
+
+
+ 0
+ 0
+ 860
+ 600
+
+
+
+ Form
+
+
+
+ 0
+
+
+ 5
+
+
+ 5
+
+
+ 5
+
+
+ 5
+
+ -
+
+
+ 1
+
+
+
+ font-size: 14pt
+
+
+
+ 5
+
+
+ 5
+
+
+ 5
+
+
+ 5
+
+
+ 5
+
+
-
+
+
+
+ 300
+ 150
+
+
+
+
+ 300
+ 150
+
+
+
+ QFrame::NoFrame
+
+
+ QFrame::Raised
+
+
+
+ 10
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+
+ 300
+ 120
+
+
+
+
+ 300
+ 120
+
+
+
+ QFrame::NoFrame
+
+
+ QFrame::Raised
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+
+
+ -
+
+
+ Welcome To PyOneDark GUI
+
+
+ Qt::AlignCenter
+
+
+
+
+
+
+
+
+
+
+
+ 5
+
+
+ 5
+
+
+ 5
+
+
+ 5
+
+
+ 5
+
+ -
+
+
+ background: transparent;
+
+
+ QFrame::NoFrame
+
+
+ Qt::ScrollBarAlwaysOff
+
+
+ Qt::ScrollBarAlwaysOff
+
+
+ true
+
+
+
+
+ 0
+ 0
+ 840
+ 580
+
+
+
+ background: transparent;
+
+
+
+ 15
+
+
+ 5
+
+
+ 5
+
+
+ 5
+
+
+ 5
+
+
-
+
+
+
+ 16777215
+ 40
+
+
+
+
+ 16
+
+
+
+ font-size: 16pt
+
+
+ Custom Widgets Page
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+ Here will be all the custom widgets, they will be added over time on this page.
+I will try to always record a new tutorial when adding a new Widget and updating the project on Patreon before launching on GitHub and GitHub after the public release.
+
+
+ Qt::AlignHCenter|Qt::AlignTop
+
+
+ true
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+
+
+
+
+
+
+ QFrame {
+ font-size: 16pt;
+}
+
+
+ -
+
+
+
+ 16
+
+
+
+ Empty Page
+
+
+ Qt::AlignCenter
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/educoder/gui/uis/pages/ui_main_pages.py b/src/educoder/gui/uis/pages/ui_main_pages.py
new file mode 100644
index 0000000..f7cbd0a
--- /dev/null
+++ b/src/educoder/gui/uis/pages/ui_main_pages.py
@@ -0,0 +1,176 @@
+# ///////////////////////////////////////////////////////////////
+#
+# 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 src.educoder.qt_core import *
+
+class Ui_MainPages(object):
+ def setupUi(self, MainPages):
+ if not MainPages.objectName():
+ MainPages.setObjectName(u"MainPages")
+ MainPages.resize(860, 600)
+ self.main_pages_layout = QVBoxLayout(MainPages)
+ self.main_pages_layout.setSpacing(0)
+ self.main_pages_layout.setObjectName(u"main_pages_layout")
+ self.main_pages_layout.setContentsMargins(5, 5, 5, 5)
+ self.pages = QStackedWidget(MainPages)
+ self.pages.setObjectName(u"pages")
+ self.page_1 = QWidget()
+ self.page_1.setObjectName(u"page_1")
+ self.page_1.setStyleSheet(u"font-size: 14pt")
+ self.page_1_layout = QVBoxLayout(self.page_1)
+ self.page_1_layout.setSpacing(5)
+ self.page_1_layout.setObjectName(u"page_1_layout")
+ self.page_1_layout.setContentsMargins(5, 5, 5, 5)
+ self.welcome_base = QFrame(self.page_1)
+ self.welcome_base.setObjectName(u"welcome_base")
+ self.welcome_base.setMinimumSize(QSize(300, 150))
+ self.welcome_base.setMaximumSize(QSize(300, 150))
+ self.welcome_base.setFrameShape(QFrame.NoFrame)
+ self.welcome_base.setFrameShadow(QFrame.Raised)
+ self.center_page_layout = QVBoxLayout(self.welcome_base)
+ self.center_page_layout.setSpacing(10)
+ self.center_page_layout.setObjectName(u"center_page_layout")
+ self.center_page_layout.setContentsMargins(0, 0, 0, 0)
+ self.logo = QFrame(self.welcome_base)
+ self.logo.setObjectName(u"logo")
+ self.logo.setMinimumSize(QSize(300, 120))
+ self.logo.setMaximumSize(QSize(300, 120))
+ self.logo.setFrameShape(QFrame.NoFrame)
+ self.logo.setFrameShadow(QFrame.Raised)
+ self.logo_layout = QVBoxLayout(self.logo)
+ self.logo_layout.setSpacing(0)
+ self.logo_layout.setObjectName(u"logo_layout")
+ self.logo_layout.setContentsMargins(0, 0, 0, 0)
+
+ self.center_page_layout.addWidget(self.logo)
+
+ self.label = QLabel(self.welcome_base)
+ self.label.setObjectName(u"label")
+ self.label.setAlignment(Qt.AlignCenter)
+
+ self.center_page_layout.addWidget(self.label)
+
+
+ self.page_1_layout.addWidget(self.welcome_base, 0, Qt.AlignHCenter)
+
+ self.pages.addWidget(self.page_1)
+ self.page_2 = QWidget()
+ self.page_2.setObjectName(u"page_2")
+ self.page_2_layout = QVBoxLayout(self.page_2)
+ self.page_2_layout.setSpacing(5)
+ self.page_2_layout.setObjectName(u"page_2_layout")
+ self.page_2_layout.setContentsMargins(5, 5, 5, 5)
+ self.scroll_area = QScrollArea(self.page_2)
+ self.scroll_area.setObjectName(u"scroll_area")
+ self.scroll_area.setStyleSheet(u"background: transparent;")
+ self.scroll_area.setFrameShape(QFrame.NoFrame)
+ self.scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
+ self.scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
+ self.scroll_area.setWidgetResizable(True)
+ self.contents = QWidget()
+ self.contents.setObjectName(u"contents")
+ self.contents.setGeometry(QRect(0, 0, 840, 580))
+ self.contents.setStyleSheet(u"background: transparent;")
+ self.verticalLayout = QVBoxLayout(self.contents)
+ self.verticalLayout.setSpacing(15)
+ self.verticalLayout.setObjectName(u"verticalLayout")
+ self.verticalLayout.setContentsMargins(5, 5, 5, 5)
+ self.title_label = QLabel(self.contents)
+ self.title_label.setObjectName(u"title_label")
+ self.title_label.setMaximumSize(QSize(16777215, 40))
+ font = QFont()
+ font.setPointSize(16)
+ self.title_label.setFont(font)
+ self.title_label.setStyleSheet(u"font-size: 16pt")
+ self.title_label.setAlignment(Qt.AlignCenter)
+
+ self.verticalLayout.addWidget(self.title_label)
+
+ self.description_label = QLabel(self.contents)
+ self.description_label.setObjectName(u"description_label")
+ self.description_label.setAlignment(Qt.AlignHCenter|Qt.AlignTop)
+ self.description_label.setWordWrap(True)
+
+ self.verticalLayout.addWidget(self.description_label)
+
+ self.row_1_layout = QHBoxLayout()
+ self.row_1_layout.setObjectName(u"row_1_layout")
+
+ self.verticalLayout.addLayout(self.row_1_layout)
+
+ self.row_2_layout = QHBoxLayout()
+ self.row_2_layout.setObjectName(u"row_2_layout")
+
+ self.verticalLayout.addLayout(self.row_2_layout)
+
+ self.row_3_layout = QHBoxLayout()
+ self.row_3_layout.setObjectName(u"row_3_layout")
+
+ self.verticalLayout.addLayout(self.row_3_layout)
+
+ self.row_4_layout = QVBoxLayout()
+ self.row_4_layout.setObjectName(u"row_4_layout")
+
+ self.verticalLayout.addLayout(self.row_4_layout)
+
+ self.row_5_layout = QVBoxLayout()
+ self.row_5_layout.setObjectName(u"row_5_layout")
+
+ self.verticalLayout.addLayout(self.row_5_layout)
+
+ self.scroll_area.setWidget(self.contents)
+
+ self.page_2_layout.addWidget(self.scroll_area)
+
+ self.pages.addWidget(self.page_2)
+ self.page_3 = QWidget()
+ self.page_3.setObjectName(u"page_3")
+ self.page_3.setStyleSheet(u"QFrame {\n"
+" font-size: 16pt;\n"
+"}")
+ self.page_3_layout = QVBoxLayout(self.page_3)
+ self.page_3_layout.setObjectName(u"page_3_layout")
+ self.empty_page_label = QLabel(self.page_3)
+ self.empty_page_label.setObjectName(u"empty_page_label")
+ self.empty_page_label.setFont(font)
+ self.empty_page_label.setAlignment(Qt.AlignCenter)
+
+ self.page_3_layout.addWidget(self.empty_page_label)
+
+ self.pages.addWidget(self.page_3)
+
+ self.main_pages_layout.addWidget(self.pages)
+
+
+ self.retranslateUi(MainPages)
+
+ self.pages.setCurrentIndex(0)
+
+
+ QMetaObject.connectSlotsByName(MainPages)
+ # setupUi
+
+ def retranslateUi(self, MainPages):
+ MainPages.setWindowTitle(QCoreApplication.translate("MainPages", u"Form", None))
+ self.label.setText(QCoreApplication.translate("MainPages", u"Welcome To PyOneDark GUI", None))
+ self.title_label.setText(QCoreApplication.translate("MainPages", u"Custom Widgets Page", None))
+ self.description_label.setText(QCoreApplication.translate("MainPages", u"Here will be all the custom widgets, they will be added over time on this page.\n"
+"I will try to always record a new tutorial when adding a new Widget and updating the project on Patreon before launching on GitHub and GitHub after the public release.", None))
+ self.empty_page_label.setText(QCoreApplication.translate("MainPages", u"Empty Page", None))
+ # retranslateUi
+
diff --git a/src/educoder/gui/uis/windows/main_window/__init__.py b/src/educoder/gui/uis/windows/main_window/__init__.py
new file mode 100644
index 0000000..0239ed3
--- /dev/null
+++ b/src/educoder/gui/uis/windows/main_window/__init__.py
@@ -0,0 +1,23 @@
+# ///////////////////////////////////////////////////////////////
+#
+# 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
+#
+# ///////////////////////////////////////////////////////////////
+
+# MAIN WINDOW
+# ///////////////////////////////////////////////////////////////
+from . ui_main import UI_MainWindow
+
+# SETUP MAIN WINDOW
+# ///////////////////////////////////////////////////////////////
+from . setup_main_window import SetupMainWindow
\ No newline at end of file
diff --git a/src/educoder/gui/uis/windows/main_window/functions_main_window.py b/src/educoder/gui/uis/windows/main_window/functions_main_window.py
new file mode 100644
index 0000000..9c55068
--- /dev/null
+++ b/src/educoder/gui/uis/windows/main_window/functions_main_window.py
@@ -0,0 +1,145 @@
+# ///////////////////////////////////////////////////////////////
+#
+# 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 src.educoder.qt_core import *
+
+# LOAD UI MAIN
+# ///////////////////////////////////////////////////////////////
+from . ui_main import *
+
+# FUNCTIONS
+class MainFunctions():
+ def __init__(self):
+ super().__init__()
+ # SETUP MAIN WINDOw
+ # Load widgets from "gui\uis\main_window\ui_main.py"
+ # ///////////////////////////////////////////////////////////////
+ self.ui = UI_MainWindow()
+ self.ui.setup_ui(self)
+
+ # SET MAIN WINDOW PAGES
+ # ///////////////////////////////////////////////////////////////
+ def set_page(self, page):
+ self.ui.load_pages.pages.setCurrentWidget(page)
+
+ # SET LEFT COLUMN PAGES
+ # ///////////////////////////////////////////////////////////////
+ def set_left_column_menu(
+ self,
+ menu,
+ title,
+ icon_path
+ ):
+ self.ui.left_column.menus.menus.setCurrentWidget(menu)
+ self.ui.left_column.title_label.setText(title)
+ self.ui.left_column.icon.set_icon(icon_path)
+
+ # RETURN IF LEFT COLUMN IS VISIBLE
+ # ///////////////////////////////////////////////////////////////
+ def left_column_is_visible(self):
+ width = self.ui.left_column_frame.width()
+ if width == 0:
+ return False
+ else:
+ return True
+
+ # RETURN IF RIGHT COLUMN IS VISIBLE
+ # ///////////////////////////////////////////////////////////////
+ def right_column_is_visible(self):
+ width = self.ui.right_column_frame.width()
+ if width == 0:
+ return False
+ else:
+ return True
+
+ # SET RIGHT COLUMN PAGES
+ # ///////////////////////////////////////////////////////////////
+ def set_right_column_menu(self, menu):
+ self.ui.right_column.menus.setCurrentWidget(menu)
+
+ # GET TITLE BUTTON BY OBJECT NAME
+ # ///////////////////////////////////////////////////////////////
+ def get_title_bar_btn(self, object_name):
+ return self.ui.title_bar_frame.findChild(QPushButton, object_name)
+
+ # GET TITLE BUTTON BY OBJECT NAME
+ # ///////////////////////////////////////////////////////////////
+ def get_left_menu_btn(self, object_name):
+ return self.ui.left_menu.findChild(QPushButton, object_name)
+
+ # LEDT AND RIGHT COLUMNS / SHOW / HIDE
+ # ///////////////////////////////////////////////////////////////
+ def toggle_left_column(self):
+ # GET ACTUAL CLUMNS SIZE
+ width = self.ui.left_column_frame.width()
+ right_column_width = self.ui.right_column_frame.width()
+
+ MainFunctions.start_box_animation(self, width, right_column_width, "left")
+
+ def toggle_right_column(self):
+ # GET ACTUAL CLUMNS SIZE
+ left_column_width = self.ui.left_column_frame.width()
+ width = self.ui.right_column_frame.width()
+
+ MainFunctions.start_box_animation(self, left_column_width, width, "right")
+
+ def start_box_animation(self, left_box_width, right_box_width, direction):
+ right_width = 0
+ left_width = 0
+ time_animation = self.ui.settings["time_animation"]
+ minimum_left = self.ui.settings["left_column_size"]["minimum"]
+ maximum_left = self.ui.settings["left_column_size"]["maximum"]
+ minimum_right = self.ui.settings["right_column_size"]["minimum"]
+ maximum_right = self.ui.settings["right_column_size"]["maximum"]
+
+ # Check Left Values
+ if left_box_width == minimum_left and direction == "left":
+ left_width = maximum_left
+ else:
+ left_width = minimum_left
+
+ # Check Right values
+ if right_box_width == minimum_right and direction == "right":
+ right_width = maximum_right
+ else:
+ right_width = minimum_right
+
+ # ANIMATION LEFT BOX
+ self.left_box = QPropertyAnimation(self.ui.left_column_frame, b"minimumWidth")
+ self.left_box.setDuration(time_animation)
+ self.left_box.setStartValue(left_box_width)
+ self.left_box.setEndValue(left_width)
+ self.left_box.setEasingCurve(QEasingCurve.InOutQuart)
+
+ # ANIMATION RIGHT BOX
+ self.right_box = QPropertyAnimation(self.ui.right_column_frame, b"minimumWidth")
+ self.right_box.setDuration(time_animation)
+ self.right_box.setStartValue(right_box_width)
+ self.right_box.setEndValue(right_width)
+ self.right_box.setEasingCurve(QEasingCurve.InOutQuart)
+
+ # GROUP ANIMATION
+ self.group = QParallelAnimationGroup()
+ self.group.stop()
+ self.group.addAnimation(self.left_box)
+ self.group.addAnimation(self.right_box)
+ self.group.start()
\ No newline at end of file
diff --git a/src/educoder/gui/uis/windows/main_window/setup_main_window.py b/src/educoder/gui/uis/windows/main_window/setup_main_window.py
new file mode 100644
index 0000000..ca1ce38
--- /dev/null
+++ b/src/educoder/gui/uis/windows/main_window/setup_main_window.py
@@ -0,0 +1,600 @@
+# ///////////////////////////////////////////////////////////////
+#
+# 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
+# ///////////////////////////////////////////////////////////////
+from gui.widgets.py_table_widget.py_table_widget import PyTableWidget
+from . functions_main_window import *
+import sys
+import os
+
+# IMPORT QT CORE
+# ///////////////////////////////////////////////////////////////
+from src.educoder.qt_core import *
+
+# IMPORT SETTINGS
+# ///////////////////////////////////////////////////////////////
+from src.educoder.gui.core.json_settings import Settings
+
+# IMPORT THEME COLORS
+# ///////////////////////////////////////////////////////////////
+from src.educoder.gui.core.json_themes import Themes
+
+# IMPORT PY ONE DARK WIDGETS
+# ///////////////////////////////////////////////////////////////
+from src.educoder.gui.widgets import *
+
+# LOAD UI MAIN
+# ///////////////////////////////////////////////////////////////
+from . ui_main import *
+
+# MAIN FUNCTIONS
+# ///////////////////////////////////////////////////////////////
+from . functions_main_window import *
+
+# PY WINDOW
+# ///////////////////////////////////////////////////////////////
+class SetupMainWindow:
+ def __init__(self):
+ super().__init__()
+ # SETUP MAIN WINDOw
+ # Load widgets from "gui\uis\main_window\ui_main.py"
+ # ///////////////////////////////////////////////////////////////
+ self.ui = UI_MainWindow()
+ self.ui.setup_ui(self)
+
+ # ADD LEFT MENUS
+ # ///////////////////////////////////////////////////////////////
+ add_left_menus = [
+ {
+ "btn_icon" : "icon_home.svg",
+ "btn_id" : "btn_home",
+ "btn_text" : "Home",
+ "btn_tooltip" : "Home page",
+ "show_top" : True,
+ "is_active" : True
+ },
+ {
+ "btn_icon" : "icon_widgets.svg",
+ "btn_id" : "btn_widgets",
+ "btn_text" : "Show Custom Widgets",
+ "btn_tooltip" : "Show custom widgets",
+ "show_top" : True,
+ "is_active" : False
+ },
+ {
+ "btn_icon" : "icon_add_user.svg",
+ "btn_id" : "btn_add_user",
+ "btn_text" : "Add Users",
+ "btn_tooltip" : "Add users",
+ "show_top" : True,
+ "is_active" : False
+ },
+ {
+ "btn_icon" : "icon_file.svg",
+ "btn_id" : "btn_new_file",
+ "btn_text" : "New File",
+ "btn_tooltip" : "Create new file",
+ "show_top" : True,
+ "is_active" : False
+ },
+ {
+ "btn_icon" : "icon_folder_open.svg",
+ "btn_id" : "btn_open_file",
+ "btn_text" : "Open File",
+ "btn_tooltip" : "Open file",
+ "show_top" : True,
+ "is_active" : False
+ },
+ {
+ "btn_icon" : "icon_save.svg",
+ "btn_id" : "btn_save",
+ "btn_text" : "Save File",
+ "btn_tooltip" : "Save file",
+ "show_top" : True,
+ "is_active" : False
+ },
+ {
+ "btn_icon" : "icon_info.svg",
+ "btn_id" : "btn_info",
+ "btn_text" : "Information",
+ "btn_tooltip" : "Open informations",
+ "show_top" : False,
+ "is_active" : False
+ },
+ {
+ "btn_icon" : "icon_settings.svg",
+ "btn_id" : "btn_settings",
+ "btn_text" : "Settings",
+ "btn_tooltip" : "Open settings",
+ "show_top" : False,
+ "is_active" : False
+ }
+ ]
+
+ # ADD TITLE BAR MENUS
+ # ///////////////////////////////////////////////////////////////
+ add_title_bar_menus = [
+ {
+ "btn_icon" : "icon_search.svg",
+ "btn_id" : "btn_search",
+ "btn_tooltip" : "Search",
+ "is_active" : False
+ },
+ {
+ "btn_icon" : "icon_settings.svg",
+ "btn_id" : "btn_top_settings",
+ "btn_tooltip" : "Top settings",
+ "is_active" : False
+ }
+ ]
+
+ # SETUP CUSTOM BTNs OF CUSTOM WIDGETS
+ # Get sender() function when btn is clicked
+ # ///////////////////////////////////////////////////////////////
+ def setup_btns(self):
+ if self.ui.title_bar.sender() != None:
+ return self.ui.title_bar.sender()
+ elif self.ui.left_menu.sender() != None:
+ return self.ui.left_menu.sender()
+ elif self.ui.left_column.sender() != None:
+ return self.ui.left_column.sender()
+
+ # SETUP MAIN WINDOW WITH CUSTOM PARAMETERS
+ # ///////////////////////////////////////////////////////////////
+ def setup_gui(self):
+ # APP TITLE
+ # ///////////////////////////////////////////////////////////////
+ self.setWindowTitle(self.settings["app_name"])
+
+ # REMOVE TITLE BAR
+ # ///////////////////////////////////////////////////////////////
+ if self.settings["custom_title_bar"]:
+ self.setWindowFlag(Qt.FramelessWindowHint)
+ self.setAttribute(Qt.WA_TranslucentBackground)
+
+ # ADD GRIPS
+ # ///////////////////////////////////////////////////////////////
+ if self.settings["custom_title_bar"]:
+ self.left_grip = PyGrips(self, "left", self.hide_grips)
+ self.right_grip = PyGrips(self, "right", self.hide_grips)
+ self.top_grip = PyGrips(self, "top", self.hide_grips)
+ self.bottom_grip = PyGrips(self, "bottom", self.hide_grips)
+ self.top_left_grip = PyGrips(self, "top_left", self.hide_grips)
+ self.top_right_grip = PyGrips(self, "top_right", self.hide_grips)
+ self.bottom_left_grip = PyGrips(self, "bottom_left", self.hide_grips)
+ self.bottom_right_grip = PyGrips(self, "bottom_right", self.hide_grips)
+
+ # LEFT MENUS / GET SIGNALS WHEN LEFT MENU BTN IS CLICKED / RELEASED
+ # ///////////////////////////////////////////////////////////////
+ # ADD MENUS
+ self.ui.left_menu.add_menus(SetupMainWindow.add_left_menus)
+
+ # SET SIGNALS
+ self.ui.left_menu.clicked.connect(self.btn_clicked)
+ self.ui.left_menu.released.connect(self.btn_released)
+
+ # TITLE BAR / ADD EXTRA BUTTONS
+ # ///////////////////////////////////////////////////////////////
+ # ADD MENUS
+ self.ui.title_bar.add_menus(SetupMainWindow.add_title_bar_menus)
+
+ # SET SIGNALS
+ self.ui.title_bar.clicked.connect(self.btn_clicked)
+ self.ui.title_bar.released.connect(self.btn_released)
+
+ # ADD Title
+ if self.settings["custom_title_bar"]:
+ self.ui.title_bar.set_title(self.settings["app_name"])
+ else:
+ self.ui.title_bar.set_title("Welcome to PyOneDark")
+
+ # LEFT COLUMN SET SIGNALS
+ # ///////////////////////////////////////////////////////////////
+ self.ui.left_column.clicked.connect(self.btn_clicked)
+ self.ui.left_column.released.connect(self.btn_released)
+
+ # SET INITIAL PAGE / SET LEFT AND RIGHT COLUMN MENUS
+ # ///////////////////////////////////////////////////////////////
+ MainFunctions.set_page(self, self.ui.load_pages.page_1)
+ MainFunctions.set_left_column_menu(
+ self,
+ menu = self.ui.left_column.menus.menu_1,
+ title = "Settings Left Column",
+ icon_path = Functions.set_svg_icon("icon_settings.svg")
+ )
+ MainFunctions.set_right_column_menu(self, self.ui.right_column.menu_1)
+
+ # ///////////////////////////////////////////////////////////////
+ # EXAMPLE CUSTOM WIDGETS
+ # Here are added the custom widgets to pages and columns that
+ # were created using Qt Designer.
+ # This is just an example and should be deleted when creating
+ # your application.
+ #
+ # OBJECTS FOR LOAD PAGES, LEFT AND RIGHT COLUMNS
+ # You can access objects inside Qt Designer projects using
+ # the objects below:
+ #
+ #
+ # LEFT COLUMN: self.ui.left_column.menus
+ # RIGHT COLUMN: self.ui.right_column
+ # LOAD PAGES: self.ui.load_pages
+ #
+ # ///////////////////////////////////////////////////////////////
+
+ # LOAD SETTINGS
+ # ///////////////////////////////////////////////////////////////
+ settings = Settings()
+ self.settings = settings.items
+
+ # LOAD THEME COLOR
+ # ///////////////////////////////////////////////////////////////
+ themes = Themes()
+ self.themes = themes.items
+
+ # LEFT COLUMN
+ # ///////////////////////////////////////////////////////////////
+
+ # BTN 1
+ self.left_btn_1 = PyPushButton(
+ text="Btn 1",
+ radius=8,
+ color=self.themes["app_color"]["text_foreground"],
+ bg_color=self.themes["app_color"]["dark_one"],
+ bg_color_hover=self.themes["app_color"]["dark_three"],
+ bg_color_pressed=self.themes["app_color"]["dark_four"]
+ )
+ self.left_btn_1.setMaximumHeight(40)
+ self.ui.left_column.menus.btn_1_layout.addWidget(self.left_btn_1)
+
+ # BTN 2
+ self.left_btn_2 = PyPushButton(
+ text="Btn With Icon",
+ radius=8,
+ color=self.themes["app_color"]["text_foreground"],
+ bg_color=self.themes["app_color"]["dark_one"],
+ bg_color_hover=self.themes["app_color"]["dark_three"],
+ bg_color_pressed=self.themes["app_color"]["dark_four"]
+ )
+ self.icon = QIcon(Functions.set_svg_icon("icon_settings.svg"))
+ self.left_btn_2.setIcon(self.icon)
+ self.left_btn_2.setMaximumHeight(40)
+ self.ui.left_column.menus.btn_2_layout.addWidget(self.left_btn_2)
+
+ # BTN 3 - Default QPushButton
+ self.left_btn_3 = QPushButton("Default QPushButton")
+ self.left_btn_3.setMaximumHeight(40)
+ self.ui.left_column.menus.btn_3_layout.addWidget(self.left_btn_3)
+
+ # PAGES
+ # ///////////////////////////////////////////////////////////////
+
+ # PAGE 1 - ADD LOGO TO MAIN PAGE
+ self.logo_svg = QSvgWidget(Functions.set_svg_image("logo_home.svg"))
+ self.ui.load_pages.logo_layout.addWidget(self.logo_svg, Qt.AlignCenter, Qt.AlignCenter)
+
+ # PAGE 2
+ # CIRCULAR PROGRESS 1
+ self.circular_progress_1 = PyCircularProgress(
+ value = 80,
+ progress_color = self.themes["app_color"]["context_color"],
+ text_color = self.themes["app_color"]["text_title"],
+ font_size = 14,
+ bg_color = self.themes["app_color"]["dark_four"]
+ )
+ self.circular_progress_1.setFixedSize(200,200)
+
+ # CIRCULAR PROGRESS 2
+ self.circular_progress_2 = PyCircularProgress(
+ value = 45,
+ progress_width = 4,
+ progress_color = self.themes["app_color"]["context_color"],
+ text_color = self.themes["app_color"]["context_color"],
+ font_size = 14,
+ bg_color = self.themes["app_color"]["bg_three"]
+ )
+ self.circular_progress_2.setFixedSize(160,160)
+
+ # CIRCULAR PROGRESS 3
+ self.circular_progress_3 = PyCircularProgress(
+ value = 75,
+ progress_width = 2,
+ progress_color = self.themes["app_color"]["pink"],
+ text_color = self.themes["app_color"]["white"],
+ font_size = 14,
+ bg_color = self.themes["app_color"]["bg_three"]
+ )
+ self.circular_progress_3.setFixedSize(140,140)
+
+ # PY SLIDER 1
+ self.vertical_slider_1 = PySlider(
+ margin=8,
+ bg_size=10,
+ bg_radius=5,
+ handle_margin=-3,
+ handle_size=16,
+ handle_radius=8,
+ bg_color = self.themes["app_color"]["dark_three"],
+ bg_color_hover = self.themes["app_color"]["dark_four"],
+ handle_color = self.themes["app_color"]["context_color"],
+ handle_color_hover = self.themes["app_color"]["context_hover"],
+ handle_color_pressed = self.themes["app_color"]["context_pressed"]
+ )
+ self.vertical_slider_1.setMinimumHeight(100)
+
+ # PY SLIDER 2
+ self.vertical_slider_2 = PySlider(
+ bg_color = self.themes["app_color"]["dark_three"],
+ bg_color_hover = self.themes["app_color"]["dark_three"],
+ handle_color = self.themes["app_color"]["context_color"],
+ handle_color_hover = self.themes["app_color"]["context_hover"],
+ handle_color_pressed = self.themes["app_color"]["context_pressed"]
+ )
+ self.vertical_slider_2.setMinimumHeight(100)
+
+ # PY SLIDER 3
+ self.vertical_slider_3 = PySlider(
+ margin=8,
+ bg_size=10,
+ bg_radius=5,
+ handle_margin=-3,
+ handle_size=16,
+ handle_radius=8,
+ bg_color = self.themes["app_color"]["dark_three"],
+ bg_color_hover = self.themes["app_color"]["dark_four"],
+ handle_color = self.themes["app_color"]["context_color"],
+ handle_color_hover = self.themes["app_color"]["context_hover"],
+ handle_color_pressed = self.themes["app_color"]["context_pressed"]
+ )
+ self.vertical_slider_3.setOrientation(Qt.Horizontal)
+ self.vertical_slider_3.setMaximumWidth(200)
+
+ # PY SLIDER 4
+ self.vertical_slider_4 = PySlider(
+ bg_color = self.themes["app_color"]["dark_three"],
+ bg_color_hover = self.themes["app_color"]["dark_three"],
+ handle_color = self.themes["app_color"]["context_color"],
+ handle_color_hover = self.themes["app_color"]["context_hover"],
+ handle_color_pressed = self.themes["app_color"]["context_pressed"]
+ )
+ self.vertical_slider_4.setOrientation(Qt.Horizontal)
+ self.vertical_slider_4.setMaximumWidth(200)
+
+ # ICON BUTTON 1
+ self.icon_button_1 = PyIconButton(
+ icon_path = Functions.set_svg_icon("icon_heart.svg"),
+ parent = self,
+ app_parent = self.ui.central_widget,
+ tooltip_text = "Icon button - Heart",
+ width = 40,
+ height = 40,
+ radius = 20,
+ dark_one = self.themes["app_color"]["dark_one"],
+ icon_color = self.themes["app_color"]["icon_color"],
+ icon_color_hover = self.themes["app_color"]["icon_hover"],
+ icon_color_pressed = self.themes["app_color"]["icon_active"],
+ icon_color_active = self.themes["app_color"]["icon_active"],
+ bg_color = self.themes["app_color"]["dark_one"],
+ bg_color_hover = self.themes["app_color"]["dark_three"],
+ bg_color_pressed = self.themes["app_color"]["pink"]
+ )
+
+ # ICON BUTTON 2
+ self.icon_button_2 = PyIconButton(
+ icon_path = Functions.set_svg_icon("icon_add_user.svg"),
+ parent = self,
+ app_parent = self.ui.central_widget,
+ tooltip_text = "BTN with tooltip",
+ width = 40,
+ height = 40,
+ radius = 8,
+ dark_one = self.themes["app_color"]["dark_one"],
+ icon_color = self.themes["app_color"]["icon_color"],
+ icon_color_hover = self.themes["app_color"]["icon_hover"],
+ icon_color_pressed = self.themes["app_color"]["white"],
+ icon_color_active = self.themes["app_color"]["icon_active"],
+ bg_color = self.themes["app_color"]["dark_one"],
+ bg_color_hover = self.themes["app_color"]["dark_three"],
+ bg_color_pressed = self.themes["app_color"]["green"],
+ )
+
+ # ICON BUTTON 3
+ self.icon_button_3 = PyIconButton(
+ icon_path = Functions.set_svg_icon("icon_add_user.svg"),
+ parent = self,
+ app_parent = self.ui.central_widget,
+ tooltip_text = "BTN actived! (is_actived = True)",
+ width = 40,
+ height = 40,
+ radius = 8,
+ dark_one = self.themes["app_color"]["dark_one"],
+ icon_color = self.themes["app_color"]["icon_color"],
+ icon_color_hover = self.themes["app_color"]["icon_hover"],
+ icon_color_pressed = self.themes["app_color"]["white"],
+ icon_color_active = self.themes["app_color"]["icon_active"],
+ bg_color = self.themes["app_color"]["dark_one"],
+ bg_color_hover = self.themes["app_color"]["dark_three"],
+ bg_color_pressed = self.themes["app_color"]["context_color"],
+ is_active = True
+ )
+
+ # PUSH BUTTON 1
+ self.push_button_1 = PyPushButton(
+ text = "Button Without Icon",
+ radius =8,
+ color = self.themes["app_color"]["text_foreground"],
+ bg_color = self.themes["app_color"]["dark_one"],
+ bg_color_hover = self.themes["app_color"]["dark_three"],
+ bg_color_pressed = self.themes["app_color"]["dark_four"]
+ )
+ self.push_button_1.setMinimumHeight(40)
+
+ # PUSH BUTTON 2
+ self.push_button_2 = PyPushButton(
+ text = "Button With Icon",
+ radius = 8,
+ color = self.themes["app_color"]["text_foreground"],
+ bg_color = self.themes["app_color"]["dark_one"],
+ bg_color_hover = self.themes["app_color"]["dark_three"],
+ bg_color_pressed = self.themes["app_color"]["dark_four"]
+ )
+ self.icon_2 = QIcon(Functions.set_svg_icon("icon_settings.svg"))
+ self.push_button_2.setMinimumHeight(40)
+ self.push_button_2.setIcon(self.icon_2)
+
+ # PY LINE EDIT
+ self.line_edit = PyLineEdit(
+ text = "",
+ place_holder_text = "Place holder text",
+ radius = 8,
+ border_size = 2,
+ color = self.themes["app_color"]["text_foreground"],
+ selection_color = self.themes["app_color"]["white"],
+ bg_color = self.themes["app_color"]["dark_one"],
+ bg_color_active = self.themes["app_color"]["dark_three"],
+ context_color = self.themes["app_color"]["context_color"]
+ )
+ self.line_edit.setMinimumHeight(30)
+
+ # TOGGLE BUTTON
+ self.toggle_button = PyToggle(
+ width = 50,
+ bg_color = self.themes["app_color"]["dark_two"],
+ circle_color = self.themes["app_color"]["icon_color"],
+ active_color = self.themes["app_color"]["context_color"]
+ )
+
+ # TABLE WIDGETS
+ self.table_widget = PyTableWidget(
+ radius = 8,
+ color = self.themes["app_color"]["text_foreground"],
+ selection_color = self.themes["app_color"]["context_color"],
+ bg_color = self.themes["app_color"]["bg_two"],
+ header_horizontal_color = self.themes["app_color"]["dark_two"],
+ header_vertical_color = self.themes["app_color"]["bg_three"],
+ bottom_line_color = self.themes["app_color"]["bg_three"],
+ grid_line_color = self.themes["app_color"]["bg_one"],
+ scroll_bar_bg_color = self.themes["app_color"]["bg_one"],
+ scroll_bar_btn_color = self.themes["app_color"]["dark_four"],
+ context_color = self.themes["app_color"]["context_color"]
+ )
+ self.table_widget.setColumnCount(3)
+ self.table_widget.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
+ self.table_widget.setSelectionMode(QAbstractItemView.ExtendedSelection)
+ self.table_widget.setSelectionBehavior(QAbstractItemView.SelectRows)
+
+ # Columns / Header
+ self.column_1 = QTableWidgetItem()
+ self.column_1.setTextAlignment(Qt.AlignCenter)
+ self.column_1.setText("NAME")
+
+ self.column_2 = QTableWidgetItem()
+ self.column_2.setTextAlignment(Qt.AlignCenter)
+ self.column_2.setText("NICK")
+
+ self.column_3 = QTableWidgetItem()
+ self.column_3.setTextAlignment(Qt.AlignCenter)
+ self.column_3.setText("PASS")
+
+ # Set column
+ self.table_widget.setHorizontalHeaderItem(0, self.column_1)
+ self.table_widget.setHorizontalHeaderItem(1, self.column_2)
+ self.table_widget.setHorizontalHeaderItem(2, self.column_3)
+
+ for x in range(10):
+ row_number = self.table_widget.rowCount()
+ self.table_widget.insertRow(row_number) # Insert row
+ self.table_widget.setItem(row_number, 0, QTableWidgetItem(str("Wanderson"))) # Add name
+ self.table_widget.setItem(row_number, 1, QTableWidgetItem(str("vfx_on_fire_" + str(x)))) # Add nick
+ self.pass_text = QTableWidgetItem()
+ self.pass_text.setTextAlignment(Qt.AlignCenter)
+ self.pass_text.setText("12345" + str(x))
+ self.table_widget.setItem(row_number, 2, self.pass_text) # Add pass
+ self.table_widget.setRowHeight(row_number, 22)
+
+ # ADD WIDGETS
+ self.ui.load_pages.row_1_layout.addWidget(self.circular_progress_1)
+ self.ui.load_pages.row_1_layout.addWidget(self.circular_progress_2)
+ self.ui.load_pages.row_1_layout.addWidget(self.circular_progress_3)
+ self.ui.load_pages.row_2_layout.addWidget(self.vertical_slider_1)
+ self.ui.load_pages.row_2_layout.addWidget(self.vertical_slider_2)
+ self.ui.load_pages.row_2_layout.addWidget(self.vertical_slider_3)
+ self.ui.load_pages.row_2_layout.addWidget(self.vertical_slider_4)
+ self.ui.load_pages.row_3_layout.addWidget(self.icon_button_1)
+ self.ui.load_pages.row_3_layout.addWidget(self.icon_button_2)
+ self.ui.load_pages.row_3_layout.addWidget(self.icon_button_3)
+ self.ui.load_pages.row_3_layout.addWidget(self.push_button_1)
+ self.ui.load_pages.row_3_layout.addWidget(self.push_button_2)
+ self.ui.load_pages.row_3_layout.addWidget(self.toggle_button)
+ self.ui.load_pages.row_4_layout.addWidget(self.line_edit)
+ self.ui.load_pages.row_5_layout.addWidget(self.table_widget)
+
+ # RIGHT COLUMN
+ # ///////////////////////////////////////////////////////////////
+
+ # BTN 1
+ self.right_btn_1 = PyPushButton(
+ text="Show Menu 2",
+ radius=8,
+ color=self.themes["app_color"]["text_foreground"],
+ bg_color=self.themes["app_color"]["dark_one"],
+ bg_color_hover=self.themes["app_color"]["dark_three"],
+ bg_color_pressed=self.themes["app_color"]["dark_four"]
+ )
+ self.icon_right = QIcon(Functions.set_svg_icon("icon_arrow_right.svg"))
+ self.right_btn_1.setIcon(self.icon_right)
+ self.right_btn_1.setMaximumHeight(40)
+ self.right_btn_1.clicked.connect(lambda: MainFunctions.set_right_column_menu(
+ self,
+ self.ui.right_column.menu_2
+ ))
+ self.ui.right_column.btn_1_layout.addWidget(self.right_btn_1)
+
+ # BTN 2
+ self.right_btn_2 = PyPushButton(
+ text="Show Menu 1",
+ radius=8,
+ color=self.themes["app_color"]["text_foreground"],
+ bg_color=self.themes["app_color"]["dark_one"],
+ bg_color_hover=self.themes["app_color"]["dark_three"],
+ bg_color_pressed=self.themes["app_color"]["dark_four"]
+ )
+ self.icon_left = QIcon(Functions.set_svg_icon("icon_arrow_left.svg"))
+ self.right_btn_2.setIcon(self.icon_left)
+ self.right_btn_2.setMaximumHeight(40)
+ self.right_btn_2.clicked.connect(lambda: MainFunctions.set_right_column_menu(
+ self,
+ self.ui.right_column.menu_1
+ ))
+ self.ui.right_column.btn_2_layout.addWidget(self.right_btn_2)
+
+ # ///////////////////////////////////////////////////////////////
+ # END - EXAMPLE CUSTOM WIDGETS
+ # ///////////////////////////////////////////////////////////////
+
+ # RESIZE GRIPS AND CHANGE POSITION
+ # Resize or change position when window is resized
+ # ///////////////////////////////////////////////////////////////
+ def resize_grips(self):
+ if self.settings["custom_title_bar"]:
+ self.left_grip.setGeometry(5, 10, 10, self.height())
+ self.right_grip.setGeometry(self.width() - 15, 10, 10, self.height())
+ self.top_grip.setGeometry(5, 5, self.width() - 10, 10)
+ self.bottom_grip.setGeometry(5, self.height() - 15, self.width() - 10, 10)
+ self.top_right_grip.setGeometry(self.width() - 20, 5, 15, 15)
+ self.bottom_left_grip.setGeometry(5, self.height() - 20, 15, 15)
+ self.bottom_right_grip.setGeometry(self.width() - 20, self.height() - 20, 15, 15)
\ No newline at end of file
diff --git a/src/educoder/gui/uis/windows/main_window/ui_main.py b/src/educoder/gui/uis/windows/main_window/ui_main.py
new file mode 100644
index 0000000..ddda193
--- /dev/null
+++ b/src/educoder/gui/uis/windows/main_window/ui_main.py
@@ -0,0 +1,305 @@
+# ///////////////////////////////////////////////////////////////
+#
+# 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
+# ///////////////////////////////////////////////////////////////
+from src.educoder.gui.core.functions import Functions
+
+# IMPORT QT CORE
+# ///////////////////////////////////////////////////////////////
+from src.educoder.qt_core import *
+
+# IMPORT SETTINGS
+# ///////////////////////////////////////////////////////////////
+from src.educoder.gui.core.json_settings import Settings
+
+# IMPORT THEME COLORS
+# ///////////////////////////////////////////////////////////////
+from src.educoder.gui.core.json_themes import Themes
+
+# IMPORT PY ONE DARK WIDGETS
+# ///////////////////////////////////////////////////////////////
+from src.educoder.gui.widgets import *
+
+# IMPORT SETUP MAIN WINDOW
+# ///////////////////////////////////////////////////////////////
+from . setup_main_window import *
+
+# IMPORT MAIN WINDOW PAGES / AND SIDE BOXES FOR APP
+# ///////////////////////////////////////////////////////////////
+from gui.uis.pages.ui_main_pages import Ui_MainPages
+
+# RIGHT COLUMN
+# ///////////////////////////////////////////////////////////////
+from gui.uis.columns.ui_right_column import Ui_RightColumn
+
+# CREDITS
+# ///////////////////////////////////////////////////////////////
+from gui.widgets.py_credits_bar.py_credits import PyCredits
+
+# PY WINDOW
+# ///////////////////////////////////////////////////////////////
+class UI_MainWindow(object):
+ def setup_ui(self, parent):
+ if not parent.objectName():
+ parent.setObjectName("MainWindow")
+
+ # LOAD SETTINGS
+ # ///////////////////////////////////////////////////////////////
+ settings = Settings()
+ self.settings = settings.items
+
+ # LOAD THEME COLOR
+ # ///////////////////////////////////////////////////////////////
+ themes = Themes()
+ self.themes = themes.items
+
+ # SET INITIAL PARAMETERS
+ parent.resize(self.settings["startup_size"][0], self.settings["startup_size"][1])
+ parent.setMinimumSize(self.settings["minimum_size"][0], self.settings["minimum_size"][1])
+
+ # SET CENTRAL WIDGET
+ # 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)
+ else:
+ self.central_widget_layout.setContentsMargins(0,0,0,0)
+
+ # LOAD PY WINDOW CUSTOM WIDGET
+ # Add inside PyWindow "layout" all Widgets
+ # ///////////////////////////////////////////////////////////////
+ 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"]
+ )
+
+ # If disable custom title bar
+ if not self.settings["custom_title_bar"]:
+ self.window.set_stylesheet(border_radius = 0, border_size = 0)
+
+ # ADD PY WINDOW TO CENTRAL WIDGET
+ self.central_widget_layout.addWidget(self.window)
+
+ # ADD FRAME LEFT MENU
+ # Add here the custom left menu bar
+ # ///////////////////////////////////////////////////////////////
+ left_menu_margin = self.settings["left_menu_content_margins"]
+ left_menu_minimum = self.settings["lef_menu_size"]["minimum"]
+ self.left_menu_frame = QFrame()
+ self.left_menu_frame.setMaximumSize(left_menu_minimum + (left_menu_margin * 2), 17280)
+ self.left_menu_frame.setMinimumSize(left_menu_minimum + (left_menu_margin * 2), 0)
+
+ # LEFT MENU LAYOUT
+ self.left_menu_layout = QHBoxLayout(self.left_menu_frame)
+ self.left_menu_layout.setContentsMargins(
+ left_menu_margin,
+ left_menu_margin,
+ left_menu_margin,
+ left_menu_margin
+ )
+
+ # ADD LEFT MENU
+ # Add custom left menu here
+ # ///////////////////////////////////////////////////////////////
+ self.left_menu = PyLeftMenu(
+ parent = self.left_menu_frame,
+ app_parent = self.central_widget, # For tooltip parent
+ dark_one = self.themes["app_color"]["dark_one"],
+ dark_three = self.themes["app_color"]["dark_three"],
+ dark_four = self.themes["app_color"]["dark_four"],
+ bg_one = self.themes["app_color"]["bg_one"],
+ icon_color = self.themes["app_color"]["icon_color"],
+ icon_color_hover = self.themes["app_color"]["icon_hover"],
+ icon_color_pressed = self.themes["app_color"]["icon_pressed"],
+ icon_color_active = self.themes["app_color"]["icon_active"],
+ context_color = self.themes["app_color"]["context_color"],
+ text_foreground = self.themes["app_color"]["text_foreground"],
+ text_active = self.themes["app_color"]["text_active"]
+ )
+ self.left_menu_layout.addWidget(self.left_menu)
+
+ # ADD LEFT COLUMN
+ # Add here the left column with Stacked Widgets
+ # ///////////////////////////////////////////////////////////////
+ self.left_column_frame = QFrame()
+ self.left_column_frame.setMaximumWidth(self.settings["left_column_size"]["minimum"])
+ self.left_column_frame.setMinimumWidth(self.settings["left_column_size"]["minimum"])
+ self.left_column_frame.setStyleSheet(f"background: {self.themes['app_color']['bg_two']}")
+
+ # ADD LAYOUT TO LEFT COLUMN
+ self.left_column_layout = QVBoxLayout(self.left_column_frame)
+ self.left_column_layout.setContentsMargins(0,0,0,0)
+
+ # ADD CUSTOM LEFT MENU WIDGET
+ self.left_column = PyLeftColumn(
+ parent,
+ app_parent = self.central_widget,
+ text_title = "Settings Left Frame",
+ text_title_size = self.settings["font"]["title_size"],
+ text_title_color = self.themes['app_color']['text_foreground'],
+ icon_path = Functions.set_svg_icon("icon_settings.svg"),
+ dark_one = self.themes['app_color']['dark_one'],
+ bg_color = self.themes['app_color']['bg_three'],
+ btn_color = self.themes['app_color']['bg_three'],
+ btn_color_hover = self.themes['app_color']['bg_two'],
+ btn_color_pressed = self.themes['app_color']['bg_one'],
+ icon_color = self.themes['app_color']['icon_color'],
+ icon_color_hover = self.themes['app_color']['icon_hover'],
+ context_color = self.themes['app_color']['context_color'],
+ icon_color_pressed = self.themes['app_color']['icon_pressed'],
+ icon_close_path = Functions.set_svg_icon("icon_close.svg")
+ )
+ self.left_column_layout.addWidget(self.left_column)
+
+ # ADD RIGHT WIDGETS
+ # Add here the right widgets
+ # ///////////////////////////////////////////////////////////////
+ self.right_app_frame = QFrame()
+
+ # ADD RIGHT APP LAYOUT
+ self.right_app_layout = QVBoxLayout(self.right_app_frame)
+ self.right_app_layout.setContentsMargins(3,3,3,3)
+ self.right_app_layout.setSpacing(6)
+
+ # ADD TITLE BAR FRAME
+ # ///////////////////////////////////////////////////////////////
+ self.title_bar_frame = QFrame()
+ self.title_bar_frame.setMinimumHeight(40)
+ self.title_bar_frame.setMaximumHeight(40)
+ self.title_bar_layout = QVBoxLayout(self.title_bar_frame)
+ self.title_bar_layout.setContentsMargins(0,0,0,0)
+
+ # ADD CUSTOM TITLE BAR TO LAYOUT
+ self.title_bar = PyTitleBar(
+ parent,
+ logo_width = 100,
+ app_parent = self.central_widget,
+ logo_image = "logo_top_100x22.svg",
+ bg_color = self.themes["app_color"]["bg_two"],
+ div_color = self.themes["app_color"]["bg_three"],
+ btn_bg_color = self.themes["app_color"]["bg_two"],
+ btn_bg_color_hover = self.themes["app_color"]["bg_three"],
+ btn_bg_color_pressed = self.themes["app_color"]["bg_one"],
+ icon_color = self.themes["app_color"]["icon_color"],
+ icon_color_hover = self.themes["app_color"]["icon_hover"],
+ icon_color_pressed = self.themes["app_color"]["icon_pressed"],
+ icon_color_active = self.themes["app_color"]["icon_active"],
+ context_color = self.themes["app_color"]["context_color"],
+ dark_one = self.themes["app_color"]["dark_one"],
+ text_foreground = self.themes["app_color"]["text_foreground"],
+ radius = 8,
+ font_family = self.settings["font"]["family"],
+ title_size = self.settings["font"]["title_size"],
+ is_custom_title_bar = self.settings["custom_title_bar"]
+ )
+ self.title_bar_layout.addWidget(self.title_bar)
+
+ # ADD CONTENT AREA
+ # ///////////////////////////////////////////////////////////////
+ self.content_area_frame = QFrame()
+
+ # CREATE LAYOUT
+ self.content_area_layout = QHBoxLayout(self.content_area_frame)
+ self.content_area_layout.setContentsMargins(0,0,0,0)
+ self.content_area_layout.setSpacing(0)
+
+ # LEFT CONTENT
+ self.content_area_left_frame = QFrame()
+
+ # IMPORT MAIN PAGES TO CONTENT AREA
+ self.load_pages = Ui_MainPages()
+ self.load_pages.setupUi(self.content_area_left_frame)
+
+ # RIGHT BAR
+ self.right_column_frame = QFrame()
+ self.right_column_frame.setMinimumWidth(self.settings["right_column_size"]["minimum"])
+ self.right_column_frame.setMaximumWidth(self.settings["right_column_size"]["minimum"])
+
+ # IMPORT RIGHT COLUMN
+ # ///////////////////////////////////////////////////////////////
+ self.content_area_right_layout = QVBoxLayout(self.right_column_frame)
+ self.content_area_right_layout.setContentsMargins(5,5,5,5)
+ self.content_area_right_layout.setSpacing(0)
+
+ # RIGHT BG
+ self.content_area_right_bg_frame = QFrame()
+ self.content_area_right_bg_frame.setObjectName("content_area_right_bg_frame")
+ self.content_area_right_bg_frame.setStyleSheet(f'''
+ #content_area_right_bg_frame {{
+ border-radius: 8px;
+ background-color: {self.themes["app_color"]["bg_two"]};
+ }}
+ ''')
+
+ # ADD BG
+ self.content_area_right_layout.addWidget(self.content_area_right_bg_frame)
+
+ # ADD RIGHT PAGES TO RIGHT COLUMN
+ self.right_column = Ui_RightColumn()
+ self.right_column.setupUi(self.content_area_right_bg_frame)
+
+ # ADD TO LAYOUTS
+ self.content_area_layout.addWidget(self.content_area_left_frame)
+ self.content_area_layout.addWidget(self.right_column_frame)
+
+ # CREDITS / BOTTOM APP FRAME
+ # ///////////////////////////////////////////////////////////////
+ self.credits_frame = QFrame()
+ self.credits_frame.setMinimumHeight(26)
+ self.credits_frame.setMaximumHeight(26)
+
+ # CREATE LAYOUT
+ self.credits_layout = QVBoxLayout(self.credits_frame)
+ self.credits_layout.setContentsMargins(0,0,0,0)
+
+ # ADD CUSTOM WIDGET CREDITS
+ self.credits = PyCredits(
+ bg_two = self.themes["app_color"]["bg_two"],
+ copyright = self.settings["copyright"],
+ version = self.settings["version"],
+ font_family = self.settings["font"]["family"],
+ text_size = self.settings["font"]["text_size"],
+ text_description_color = self.themes["app_color"]["text_description"]
+ )
+
+ # ADD TO LAYOUT
+ self.credits_layout.addWidget(self.credits)
+
+ # ADD WIDGETS TO RIGHT LAYOUT
+ # ///////////////////////////////////////////////////////////////
+ self.right_app_layout.addWidget(self.title_bar_frame)
+ self.right_app_layout.addWidget(self.content_area_frame)
+ self.right_app_layout.addWidget(self.credits_frame)
+
+ # ADD WIDGETS TO "PyWindow"
+ # Add here your custom widgets or default widgets
+ # ///////////////////////////////////////////////////////////////
+ self.window.layout.addWidget(self.left_menu_frame)
+ self.window.layout.addWidget(self.left_column_frame)
+ self.window.layout.addWidget(self.right_app_frame)
+
+ # ADD CENTRAL WIDGET AND SET CONTENT MARGINS
+ # ///////////////////////////////////////////////////////////////
+ parent.setCentralWidget(self.central_widget)
\ No newline at end of file
diff --git a/src/educoder/gui/widgets/__init__.py b/src/educoder/gui/widgets/__init__.py
new file mode 100644
index 0000000..95bd69e
--- /dev/null
+++ b/src/educoder/gui/widgets/__init__.py
@@ -0,0 +1,71 @@
+# ///////////////////////////////////////////////////////////////
+#
+# 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 WIDGETS
+# ADD here all custom widgets
+# ///////////////////////////////////////////////////////////////
+
+# PY WINDOW
+# ///////////////////////////////////////////////////////////////
+from . py_window import PyWindow
+
+# RESIZE GRIP
+# ///////////////////////////////////////////////////////////////
+from . py_grips import PyGrips
+
+# LEFT MENU
+# ///////////////////////////////////////////////////////////////
+from . py_left_menu import PyLeftMenu
+
+# PY LEFT COLUMN
+# ///////////////////////////////////////////////////////////////
+from . py_left_column import PyLeftColumn
+
+# PY TITLE BAR
+# ///////////////////////////////////////////////////////////////
+from . py_title_bar import PyTitleBar
+
+# PY CREDITS
+# ///////////////////////////////////////////////////////////////
+from . py_credits_bar import PyCredits
+
+# PY PUSH BUTTON
+# ///////////////////////////////////////////////////////////////
+from . py_push_button import PyPushButton
+
+# PY TOGGLE
+# ///////////////////////////////////////////////////////////////
+from . py_toggle import PyToggle
+
+# PY SLIDER
+# ///////////////////////////////////////////////////////////////
+from . py_slider import PySlider
+
+# PY CIRCULAR PROGRESS
+# ///////////////////////////////////////////////////////////////
+from . py_circular_progress import PyCircularProgress
+
+# PY ICON BUTTON
+# ///////////////////////////////////////////////////////////////
+from . py_icon_button import PyIconButton
+
+# PY LINE EDIT
+# ///////////////////////////////////////////////////////////////
+from . py_line_edit import PyLineEdit
+
+# PY TABLE WIDGET
+# ///////////////////////////////////////////////////////////////
+from . py_table_widget import PyTableWidget
\ No newline at end of file
diff --git a/src/educoder/gui/widgets/py_circular_progress/__init__.py b/src/educoder/gui/widgets/py_circular_progress/__init__.py
new file mode 100644
index 0000000..a9b7346
--- /dev/null
+++ b/src/educoder/gui/widgets/py_circular_progress/__init__.py
@@ -0,0 +1,19 @@
+# ///////////////////////////////////////////////////////////////
+#
+# 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
+#
+# ///////////////////////////////////////////////////////////////
+
+# PY TITLE BAR
+# ///////////////////////////////////////////////////////////////
+from . py_circular_progress import PyCircularProgress
\ No newline at end of file
diff --git a/src/educoder/gui/widgets/py_circular_progress/py_circular_progress.py b/src/educoder/gui/widgets/py_circular_progress/py_circular_progress.py
new file mode 100644
index 0000000..f5fd217
--- /dev/null
+++ b/src/educoder/gui/widgets/py_circular_progress/py_circular_progress.py
@@ -0,0 +1,114 @@
+# ///////////////////////////////////////////////////////////////
+#
+# 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 src.educoder.qt_core import *
+
+class PyCircularProgress(QWidget):
+ def __init__(
+ self,
+ value = 0,
+ progress_width = 10,
+ is_rounded = True,
+ max_value = 100,
+ progress_color = "#ff79c6",
+ enable_text = True,
+ font_family = "Segoe UI",
+ font_size = 12,
+ suffix = "%",
+ text_color = "#ff79c6",
+ enable_bg = True,
+ bg_color = "#44475a"
+ ):
+ QWidget.__init__(self)
+
+ # CUSTOM PROPERTIES
+ self.value = value
+ self.progress_width = progress_width
+ self.progress_rounded_cap = is_rounded
+ self.max_value = max_value
+ self.progress_color = progress_color
+ # Text
+ self.enable_text = enable_text
+ self.font_family = font_family
+ self.font_size = font_size
+ self.suffix = suffix
+ self.text_color = text_color
+ # BG
+ self.enable_bg = enable_bg
+ self.bg_color = bg_color
+
+ # ADD DROPSHADOW
+ def add_shadow(self, enable):
+ if enable:
+ self.shadow = QGraphicsDropShadowEffect(self)
+ self.shadow.setBlurRadius(15)
+ self.shadow.setXOffset(0)
+ self.shadow.setYOffset(0)
+ self.shadow.setColor(QColor(0, 0, 0, 80))
+ self.setGraphicsEffect(self.shadow)
+
+ # SET VALUE
+ def set_value(self, value):
+ self.value = value
+ self.repaint() # Render progress bar after change value
+
+
+ # PAINT EVENT (DESIGN YOUR CIRCULAR PROGRESS HERE)
+ def paintEvent(self, e):
+ # SET PROGRESS PARAMETERS
+ width = self.width() - self.progress_width
+ height = self.height() - self.progress_width
+ margin = self.progress_width / 2
+ value = self.value * 360 / self.max_value
+
+ # PAINTER
+ paint = QPainter()
+ paint.begin(self)
+ paint.setRenderHint(QPainter.Antialiasing) # remove pixelated edges
+ paint.setFont(QFont(self.font_family, self.font_size))
+
+ # CREATE RECTANGLE
+ rect = QRect(0, 0, self.width(), self.height())
+ paint.setPen(Qt.NoPen)
+
+ # PEN
+ pen = QPen()
+ pen.setWidth(self.progress_width)
+ # Set Round Cap
+ if self.progress_rounded_cap:
+ pen.setCapStyle(Qt.RoundCap)
+
+ # ENABLE BG
+ if self.enable_bg:
+ pen.setColor(QColor(self.bg_color))
+ paint.setPen(pen)
+ paint.drawArc(margin, margin, width, height, 0, 360 * 16)
+
+ # CREATE ARC / CIRCULAR PROGRESS
+ pen.setColor(QColor(self.progress_color))
+ paint.setPen(pen)
+ paint.drawArc(margin, margin, width, height, -90 * 16, -value * 16)
+
+ # CREATE TEXT
+ if self.enable_text:
+ pen.setColor(QColor(self.text_color))
+ paint.setPen(pen)
+ paint.drawText(rect, Qt.AlignCenter, f"{self.value}{self.suffix}")
+
+ # END
+ paint.end()
\ No newline at end of file
diff --git a/src/educoder/gui/widgets/py_credits_bar/__init__.py b/src/educoder/gui/widgets/py_credits_bar/__init__.py
new file mode 100644
index 0000000..4aa4e8f
--- /dev/null
+++ b/src/educoder/gui/widgets/py_credits_bar/__init__.py
@@ -0,0 +1,19 @@
+# ///////////////////////////////////////////////////////////////
+#
+# 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
+#
+# ///////////////////////////////////////////////////////////////
+
+# PY CREDITS
+# ///////////////////////////////////////////////////////////////
+from . py_credits import PyCredits
\ No newline at end of file
diff --git a/src/educoder/gui/widgets/py_credits_bar/py_credits.py b/src/educoder/gui/widgets/py_credits_bar/py_credits.py
new file mode 100644
index 0000000..4912ae0
--- /dev/null
+++ b/src/educoder/gui/widgets/py_credits_bar/py_credits.py
@@ -0,0 +1,95 @@
+# ///////////////////////////////////////////////////////////////
+#
+# 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 src.educoder.qt_core import *
+
+# PY CREDITS BAR AND VERSION
+# ///////////////////////////////////////////////////////////////
+class PyCredits(QWidget):
+ def __init__(
+ self,
+ copyright,
+ version,
+ bg_two,
+ font_family,
+ text_size,
+ text_description_color,
+ radius = 8,
+ padding = 10
+ ):
+ super().__init__()
+
+ # PROPERTIES
+ self._copyright = copyright
+ self._version = version
+ self._bg_two = bg_two
+ self._font_family = font_family
+ self._text_size = text_size
+ self._text_description_color = text_description_color
+ self._radius = radius
+ self._padding = padding
+
+ # SETUP UI
+ self.setup_ui()
+
+ def setup_ui(self):
+ # ADD LAYOUT
+ self.widget_layout = QHBoxLayout(self)
+ self.widget_layout.setContentsMargins(0,0,0,0)
+
+ # BG STYLE
+ style = f"""
+ #bg_frame {{
+ border-radius: {self._radius}px;
+ background-color: {self._bg_two};
+ }}
+ .QLabel {{
+ font: {self._text_size}pt "{self._font_family}";
+ color: {self._text_description_color};
+ padding-left: {self._padding}px;
+ padding-right: {self._padding}px;
+ }}
+ """
+
+ # BG FRAME
+ self.bg_frame = QFrame()
+ self.bg_frame.setObjectName("bg_frame")
+ self.bg_frame.setStyleSheet(style)
+
+ # ADD TO LAYOUT
+ self.widget_layout.addWidget(self.bg_frame)
+
+ # ADD BG LAYOUT
+ self.bg_layout = QHBoxLayout(self.bg_frame)
+ self.bg_layout.setContentsMargins(0,0,0,0)
+
+ # ADD COPYRIGHT TEXT
+ self.copyright_label = QLabel(self._copyright)
+ self.copyright_label.setAlignment(Qt.AlignVCenter)
+
+ # ADD VERSION TEXT
+ self.version_label = QLabel(self._version)
+ self.version_label.setAlignment(Qt.AlignVCenter)
+
+ # SEPARATOR
+ self.separator = QSpacerItem(20, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
+
+ # ADD TO LAYOUT
+ self.bg_layout.addWidget(self.copyright_label)
+ self.bg_layout.addSpacerItem(self.separator)
+ self.bg_layout.addWidget(self.version_label)
diff --git a/src/educoder/gui/widgets/py_grips/__init__.py b/src/educoder/gui/widgets/py_grips/__init__.py
new file mode 100644
index 0000000..a4fda03
--- /dev/null
+++ b/src/educoder/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/src/educoder/gui/widgets/py_grips/py_grips.py b/src/educoder/gui/widgets/py_grips/py_grips.py
new file mode 100644
index 0000000..a95e8a8
--- /dev/null
+++ b/src/educoder/gui/widgets/py_grips/py_grips.py
@@ -0,0 +1,249 @@
+# ///////////////////////////////////////////////////////////////
+#
+# 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 src.educoder.qt_core import *
+
+# PY GRIPS
+# ///////////////////////////////////////////////////////////////
+class PyGrips(QWidget):
+ def __init__(self, parent, position, disable_color = False):
+
+ # SETUP UI
+ # ///////////////////////////////////////////////////////////////
+ super().__init__()
+ self.parent = parent
+ self.setParent(parent)
+ self.wi = Widgets()
+
+ # SHOW TOP LEFT GRIP
+ # ///////////////////////////////////////////////////////////////
+ if position == "top_left":
+ self.wi.top_left(self)
+ grip = QSizeGrip(self.wi.top_left_grip)
+ grip.setFixedSize(self.wi.top_left_grip.size())
+ self.setGeometry(5, 5, 15, 15)
+
+ # ENABLE COLOR
+ if disable_color:
+ self.wi.top_left_grip.setStyleSheet("background: transparent")
+
+ # SHOW TOP RIGHT GRIP
+ # ///////////////////////////////////////////////////////////////
+ if position == "top_right":
+ self.wi.top_right(self)
+ grip = QSizeGrip(self.wi.top_right_grip)
+ grip.setFixedSize(self.wi.top_right_grip.size())
+ self.setGeometry(self.parent.width() - 20, 5, 15, 15)
+
+ # ENABLE COLOR
+ if disable_color:
+ self.wi.top_right_grip.setStyleSheet("background: transparent")
+
+ # SHOW BOTTOM LEFT GRIP
+ # ///////////////////////////////////////////////////////////////
+ if position == "bottom_left":
+ self.wi.bottom_left(self)
+ grip = QSizeGrip(self.wi.bottom_left_grip)
+ grip.setFixedSize(self.wi.bottom_left_grip.size())
+ self.setGeometry(5, self.parent.height() - 20, 15, 15)
+
+ # ENABLE COLOR
+ if disable_color:
+ self.wi.bottom_left_grip.setStyleSheet("background: transparent")
+
+ # SHOW BOTTOM RIGHT GRIP
+ # ///////////////////////////////////////////////////////////////
+ if position == "bottom_right":
+ self.wi.bottom_right(self)
+ grip = QSizeGrip(self.wi.bottom_right_grip)
+ grip.setFixedSize(self.wi.bottom_right_grip.size())
+ self.setGeometry(self.parent.width() - 20, self.parent.height() - 20, 15, 15)
+
+ # ENABLE COLOR
+ if disable_color:
+ self.wi.bottom_right_grip.setStyleSheet("background: transparent")
+
+ # SHOW TOP GRIP
+ # ///////////////////////////////////////////////////////////////
+ if position == "top":
+ self.wi.top(self)
+ self.setGeometry(0, 5, 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 == "bottom":
+ 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_grip.setStyleSheet("background: transparent")
+
+ # SHOW LEFT GRIP
+ # ///////////////////////////////////////////////////////////////
+ elif position == "left":
+ 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 == "right":
+ 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")
+
+ # MOUSE RELEASE
+ # ///////////////////////////////////////////////////////////////
+ def mouseReleaseEvent(self, event):
+ self.mousePos = None
+
+ # RESIZE EVENT
+ # ///////////////////////////////////////////////////////////////
+ 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)
+
+ elif hasattr(self.wi, 'top_right_grip'):
+ self.wi.top_right_grip.setGeometry(self.width() - 15, 0, 15, 15)
+
+ elif hasattr(self.wi, 'bottom_left_grip'):
+ self.wi.bottom_left_grip.setGeometry(0, self.height() - 15, 15, 15)
+
+ elif hasattr(self.wi, 'bottom_right_grip'):
+ self.wi.bottom_right_grip.setGeometry(self.width() - 15, self.height() - 15, 15, 15)
+
+
+# GRIP WIDGTES
+# ///////////////////////////////////////////////////////////////
+class Widgets(object):
+ def top_left(self, form):
+ self.top_left_grip = QFrame(form)
+ self.top_left_grip.setObjectName(u"top_left_grip")
+ self.top_left_grip.setFixedSize(15, 15)
+ self.top_left_grip.setStyleSheet(u"background-color: #333; border: 2px solid #55FF00;")
+
+ def top_right(self, form):
+ self.top_right_grip = QFrame(form)
+ self.top_right_grip.setObjectName(u"top_right_grip")
+ self.top_right_grip.setFixedSize(15, 15)
+ self.top_right_grip.setStyleSheet(u"background-color: #333; border: 2px solid #55FF00;")
+
+ def bottom_left(self, form):
+ self.bottom_left_grip = QFrame(form)
+ self.bottom_left_grip.setObjectName(u"bottom_left_grip")
+ self.bottom_left_grip.setFixedSize(15, 15)
+ self.bottom_left_grip.setStyleSheet(u"background-color: #333; border: 2px solid #55FF00;")
+
+ def bottom_right(self, form):
+ self.bottom_right_grip = QFrame(form)
+ self.bottom_right_grip.setObjectName(u"bottom_right_grip")
+ self.bottom_right_grip.setFixedSize(15, 15)
+ self.bottom_right_grip.setStyleSheet(u"background-color: #333; border: 2px solid #55FF00;")
+
+ def top(self, 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):
+ 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):
+ 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):
+ 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/src/educoder/gui/widgets/py_icon_button/__init__.py b/src/educoder/gui/widgets/py_icon_button/__init__.py
new file mode 100644
index 0000000..cb6fe88
--- /dev/null
+++ b/src/educoder/gui/widgets/py_icon_button/__init__.py
@@ -0,0 +1,19 @@
+# ///////////////////////////////////////////////////////////////
+#
+# 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
+#
+# ///////////////////////////////////////////////////////////////
+
+# PY ICON BUTTON
+# ///////////////////////////////////////////////////////////////
+from . py_icon_button import PyIconButton
\ No newline at end of file
diff --git a/src/educoder/gui/widgets/py_icon_button/py_icon_button.py b/src/educoder/gui/widgets/py_icon_button/py_icon_button.py
new file mode 100644
index 0000000..ced9744
--- /dev/null
+++ b/src/educoder/gui/widgets/py_icon_button/py_icon_button.py
@@ -0,0 +1,268 @@
+# ///////////////////////////////////////////////////////////////
+#
+# 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 src.educoder.qt_core import *
+
+# PY TITLE BUTTON
+# ///////////////////////////////////////////////////////////////
+class PyIconButton(QPushButton):
+ def __init__(
+ self,
+ icon_path = None,
+ parent = None,
+ app_parent = None,
+ tooltip_text = "",
+ btn_id = None,
+ 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",
+ dark_one = "#1b1e23",
+ text_foreground = "#8a95aa",
+ context_color = "#568af2",
+ top_margin = 40,
+ is_active = False
+ ):
+ super().__init__()
+
+ # SET DEFAULT PARAMETERS
+ self.setFixedSize(width, height)
+ self.setCursor(Qt.PointingHandCursor)
+ self.setObjectName(btn_id)
+
+ # 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
+ self._context_color = context_color
+ self._top_margin = top_margin
+ self._is_active = is_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
+ # Parent
+ self._parent = parent
+ self._app_parent = app_parent
+
+ # TOOLTIP
+ self._tooltip_text = tooltip_text
+ self._tooltip = _ToolTip(
+ app_parent,
+ tooltip_text,
+ dark_one,
+ text_foreground
+ )
+ self._tooltip.hide()
+
+ # SET ACTIVE MENU
+ # ///////////////////////////////////////////////////////////////
+ def set_active(self, is_active):
+ self._is_active = is_active
+ self.repaint()
+
+ # RETURN IF IS ACTIVE MENU
+ # ///////////////////////////////////////////////////////////////
+ def is_active(self):
+ return self._is_active
+
+ # PAINT EVENT
+ # painting the button and the icon
+ # ///////////////////////////////////////////////////////////////
+ def paintEvent(self, event):
+ # PAINTER
+ paint = QPainter()
+ paint.begin(self)
+ paint.setRenderHint(QPainter.RenderHint.Antialiasing)
+
+ if self._is_active:
+ # BRUSH
+ brush = QBrush(QColor(self._context_color))
+ else:
+ # 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)
+ if self._is_active:
+ painter.fillRect(icon.rect(), self._icon_color_active)
+ else:
+ painter.fillRect(icon.rect(), self._set_icon_color)
+ qp.drawPixmap(
+ (rect.width() - icon.width()) / 2,
+ (rect.height() - icon.height()) / 2,
+ icon
+ )
+ painter.end()
+
+ # SET ICON
+ # ///////////////////////////////////////////////////////////////
+ def set_icon(self, icon_path):
+ self._set_icon_path = icon_path
+ self.repaint()
+
+ # MOVE TOOLTIP
+ # ///////////////////////////////////////////////////////////////
+ def move_tooltip(self):
+ # GET MAIN WINDOW PARENT
+ gp = self.mapToGlobal(QPoint(0, 0))
+
+ # SET WIDGET TO GET POSTION
+ # Return absolute position of widget inside app
+ pos = self._parent.mapFromGlobal(gp)
+
+ # FORMAT POSITION
+ # Adjust tooltip position with offset
+ pos_x = (pos.x() - (self._tooltip.width() // 2)) + (self.width() // 2)
+ pos_y = pos.y() - self._top_margin
+
+ # SET POSITION TO WIDGET
+ # Move tooltip position
+ self._tooltip.move(pos_x, pos_y)
+
+# TOOLTIP
+# ///////////////////////////////////////////////////////////////
+class _ToolTip(QLabel):
+ # TOOLTIP / LABEL StyleSheet
+ style_tooltip = """
+ QLabel {{
+ background-color: {_dark_one};
+ color: {_text_foreground};
+ padding-left: 10px;
+ padding-right: 10px;
+ border-radius: 17px;
+ border: 0px solid transparent;
+ font: 800 9pt "Segoe UI";
+ }}
+ """
+ def __init__(
+ self,
+ parent,
+ tooltip,
+ dark_one,
+ text_foreground
+ ):
+ QLabel.__init__(self)
+
+ # LABEL SETUP
+ style = self.style_tooltip.format(
+ _dark_one = dark_one,
+ _text_foreground = text_foreground
+ )
+ self.setObjectName(u"label_tooltip")
+ self.setStyleSheet(style)
+ self.setMinimumHeight(34)
+ self.setParent(parent)
+ self.setText(tooltip)
+ self.adjustSize()
+
+ # SET DROP SHADOW
+ self.shadow = QGraphicsDropShadowEffect(self)
+ self.shadow.setBlurRadius(30)
+ self.shadow.setXOffset(0)
+ self.shadow.setYOffset(0)
+ self.shadow.setColor(QColor(0, 0, 0, 80))
+ self.setGraphicsEffect(self.shadow)
diff --git a/src/educoder/gui/widgets/py_left_column/__init__.py b/src/educoder/gui/widgets/py_left_column/__init__.py
new file mode 100644
index 0000000..d2015d4
--- /dev/null
+++ b/src/educoder/gui/widgets/py_left_column/__init__.py
@@ -0,0 +1,20 @@
+# ///////////////////////////////////////////////////////////////
+#
+# 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
+#
+# ///////////////////////////////////////////////////////////////
+
+# PY LEFT COLUMN
+# Left column with custom widgets
+# ///////////////////////////////////////////////////////////////
+from . py_left_column import PyLeftColumn
\ No newline at end of file
diff --git a/src/educoder/gui/widgets/py_left_column/py_icon.py b/src/educoder/gui/widgets/py_left_column/py_icon.py
new file mode 100644
index 0000000..4d91eae
--- /dev/null
+++ b/src/educoder/gui/widgets/py_left_column/py_icon.py
@@ -0,0 +1,70 @@
+# ///////////////////////////////////////////////////////////////
+#
+# 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 src.educoder.qt_core import *
+
+# PY ICON WITH CUSTOM COLORS
+# ///////////////////////////////////////////////////////////////
+class PyIcon(QWidget):
+ def __init__(
+ self,
+ icon_path,
+ icon_color
+ ):
+ super().__init__()
+
+ # PROPERTIES
+ self._icon_path = icon_path
+ self._icon_color = icon_color
+
+ # SETUP UI
+ self.setup_ui()
+
+ def setup_ui(self):
+ # LAYOUT
+ self.layout = QVBoxLayout(self)
+ self.layout.setContentsMargins(0,0,0,0)
+
+ # LABEL
+ self.icon = QLabel()
+ self.icon.setAlignment(Qt.AlignCenter)
+
+ # PAINTER
+ self.set_icon(self._icon_path, self._icon_color)
+
+ # ADD TO LAYOUT
+ self.layout.addWidget(self.icon)
+
+ def set_icon(self, icon_path, icon_color = None):
+ # GET COLOR
+ color = ""
+ if icon_color != None:
+ color = icon_color
+ else:
+ color = self._icon_color
+
+ # PAINTER / PIXMAP
+ icon = QPixmap(icon_path)
+ painter = QPainter(icon)
+ painter.setCompositionMode(QPainter.CompositionMode_SourceIn)
+ painter.fillRect(icon.rect(), color)
+ painter.end()
+
+ # SET PIXMAP
+ self.icon.setPixmap(icon)
+
diff --git a/src/educoder/gui/widgets/py_left_column/py_left_button.py b/src/educoder/gui/widgets/py_left_column/py_left_button.py
new file mode 100644
index 0000000..3ad9d5c
--- /dev/null
+++ b/src/educoder/gui/widgets/py_left_column/py_left_button.py
@@ -0,0 +1,271 @@
+# ///////////////////////////////////////////////////////////////
+#
+# 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 src.educoder.qt_core import *
+
+# PY TITLE BUTTON
+# ///////////////////////////////////////////////////////////////
+class PyLeftButton(QPushButton):
+ def __init__(
+ self,
+ parent,
+ app_parent = None,
+ tooltip_text = "",
+ btn_id = None,
+ 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",
+ dark_one = "#1b1e23",
+ context_color = "#568af2",
+ text_foreground = "#8a95aa",
+ is_active = False
+ ):
+ super().__init__()
+
+ # SET DEFAULT PARAMETERS
+ self.setFixedSize(width, height)
+ self.setCursor(Qt.PointingHandCursor)
+ self.setObjectName(btn_id)
+
+ # 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
+ self._context_color = context_color
+ self._top_margin = self.height() + 6
+ self._is_active = is_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
+ # Parent
+ self._parent = parent
+ self._app_parent = app_parent
+
+ # TOOLTIP
+ self._tooltip_text = tooltip_text
+ self._tooltip = _ToolTip(
+ app_parent,
+ tooltip_text,
+ dark_one,
+ context_color,
+ text_foreground
+ )
+ self._tooltip.hide()
+
+ # SET ACTIVE MENU
+ # ///////////////////////////////////////////////////////////////
+ def set_active(self, is_active):
+ self._is_active = is_active
+ self.repaint()
+
+ # RETURN IF IS ACTIVE MENU
+ # ///////////////////////////////////////////////////////////////
+ def is_active(self):
+ return self._is_active
+
+ # PAINT EVENT
+ # painting the button and the icon
+ # ///////////////////////////////////////////////////////////////
+ def paintEvent(self, event):
+ # PAINTER
+ paint = QPainter()
+ paint.begin(self)
+ paint.setRenderHint(QPainter.RenderHint.Antialiasing)
+
+ if self._is_active:
+ # BRUSH
+ brush = QBrush(QColor(self._bg_color_pressed))
+ else:
+ # 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)
+ if self._is_active:
+ painter.fillRect(icon.rect(), self._context_color)
+ else:
+ painter.fillRect(icon.rect(), self._set_icon_color)
+ qp.drawPixmap(
+ (rect.width() - icon.width()) / 2,
+ (rect.height() - icon.height()) / 2,
+ icon
+ )
+ painter.end()
+
+ # SET ICON
+ # ///////////////////////////////////////////////////////////////
+ def set_icon(self, icon_path):
+ self._set_icon_path = icon_path
+ self.repaint()
+
+ # MOVE TOOLTIP
+ # ///////////////////////////////////////////////////////////////
+ def move_tooltip(self):
+ # GET MAIN WINDOW PARENT
+ gp = self.mapToGlobal(QPoint(0, 0))
+
+ # SET WIDGET TO GET POSTION
+ # Return absolute position of widget inside app
+ pos = self._parent.mapFromGlobal(gp)
+
+ # FORMAT POSITION
+ # Adjust tooltip position with offset
+ pos_x = (pos.x() - self._tooltip.width()) + self.width() + 5
+ pos_y = pos.y() + self._top_margin
+
+ # SET POSITION TO WIDGET
+ # Move tooltip position
+ self._tooltip.move(pos_x, pos_y)
+
+# TOOLTIP
+# ///////////////////////////////////////////////////////////////
+class _ToolTip(QLabel):
+ # TOOLTIP / LABEL StyleSheet
+ style_tooltip = """
+ QLabel {{
+ background-color: {_dark_one};
+ color: {_text_foreground};
+ padding-left: 10px;
+ padding-right: 10px;
+ border-radius: 17px;
+ border: 0px solid transparent;
+ border-right: 3px solid {_context_color};
+ font: 800 9pt "Segoe UI";
+ }}
+ """
+ def __init__(
+ self,
+ parent,
+ tooltip,
+ dark_one,
+ context_color,
+ text_foreground
+ ):
+ QLabel.__init__(self)
+
+ # LABEL SETUP
+ style = self.style_tooltip.format(
+ _dark_one = dark_one,
+ _context_color = context_color,
+ _text_foreground = text_foreground
+ )
+ self.setObjectName(u"label_tooltip")
+ self.setStyleSheet(style)
+ self.setMinimumHeight(34)
+ self.setParent(parent)
+ self.setText(tooltip)
+ self.adjustSize()
+
+ # SET DROP SHADOW
+ self.shadow = QGraphicsDropShadowEffect(self)
+ self.shadow.setBlurRadius(30)
+ self.shadow.setXOffset(0)
+ self.shadow.setYOffset(0)
+ self.shadow.setColor(QColor(0, 0, 0, 80))
+ self.setGraphicsEffect(self.shadow)
diff --git a/src/educoder/gui/widgets/py_left_column/py_left_column.py b/src/educoder/gui/widgets/py_left_column/py_left_column.py
new file mode 100644
index 0000000..7a880c2
--- /dev/null
+++ b/src/educoder/gui/widgets/py_left_column/py_left_column.py
@@ -0,0 +1,194 @@
+# ///////////////////////////////////////////////////////////////
+#
+# 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 src.educoder.qt_core import *
+
+# IMPORT CLOSE BUTTON
+# ///////////////////////////////////////////////////////////////
+from . py_left_button import *
+
+# IMPORT ICON
+# ///////////////////////////////////////////////////////////////
+from . py_icon import *
+
+# IMPORT LEFT COLUMN
+# ///////////////////////////////////////////////////////////////
+from gui.uis.columns.ui_left_column import Ui_LeftColumn
+
+class PyLeftColumn(QWidget):
+ # SIGNALS
+ clicked = Signal(object)
+ released = Signal(object)
+
+ def __init__(
+ self,
+ parent,
+ app_parent,
+ text_title,
+ text_title_size,
+ text_title_color,
+ dark_one,
+ bg_color,
+ btn_color,
+ btn_color_hover,
+ btn_color_pressed,
+ icon_path,
+ icon_color,
+ icon_color_hover,
+ icon_color_pressed,
+ context_color,
+ icon_close_path,
+ radius = 8
+ ):
+ super().__init__()
+
+ # PARAMETERS
+ self._parent = parent
+ self._app_parent = app_parent
+ self._text_title = text_title
+ self._text_title_size = text_title_size
+ self._text_title_color = text_title_color
+ self._icon_path = icon_path
+ self._dark_one = dark_one
+ self._bg_color = bg_color
+ self._btn_color = btn_color
+ self._btn_color_hover = btn_color_hover
+ self._btn_color_pressed = btn_color_pressed
+ self._icon_color = icon_color
+ self._icon_color_hover = icon_color_hover
+ self._icon_color_pressed = icon_color_pressed
+ self._context_color = context_color
+ self._icon_close_path = icon_close_path
+ self._radius = radius
+
+ # SETUP UI
+ self.setup_ui()
+
+ # ADD LEFT COLUMN TO BG FRAME
+ self.menus = Ui_LeftColumn()
+ self.menus.setupUi(self.content_frame)
+
+ # CONNECT SIGNALS
+ self.btn_close.clicked.connect(self.btn_clicked)
+ self.btn_close.released.connect(self.btn_released)
+
+ # TITLE LEFT COLUMN EMIT SIGNALS
+ # ///////////////////////////////////////////////////////////////
+ def btn_clicked(self):
+ self.clicked.emit(self.btn_close)
+
+ def btn_released(self):
+ self.released.emit(self.btn_close)
+
+ # WIDGETS
+ # ///////////////////////////////////////////////////////////////
+ def setup_ui(self):
+ # BASE LAYOUT
+ self.base_layout = QVBoxLayout(self)
+ self.base_layout.setContentsMargins(0,0,0,0)
+ self.base_layout.setSpacing(0)
+
+ # TITLE FRAME
+ # ///////////////////////////////////////////////////////////////
+ self.title_frame = QFrame()
+ self.title_frame.setMaximumHeight(47)
+ self.title_frame.setMinimumHeight(47)
+
+ # TITLE BASE LAYOUT
+ self.title_base_layout = QVBoxLayout(self.title_frame)
+ self.title_base_layout.setContentsMargins(5,3,5,3)
+
+ # TITLE BG
+ self.title_bg_frame = QFrame()
+ self.title_bg_frame.setObjectName("title_bg_frame")
+ self.title_bg_frame.setStyleSheet(f'''
+ #title_bg_frame {{
+ background-color: {self._bg_color};
+ border-radius: {self._radius}px;
+ }}
+ ''')
+
+ # LAYOUT TITLE BG
+ self.title_bg_layout = QHBoxLayout(self.title_bg_frame)
+ self.title_bg_layout.setContentsMargins(5,5,5,5)
+ self.title_bg_layout.setSpacing(3)
+
+ # ICON
+ self.icon_frame = QFrame()
+ self.icon_frame.setFixedSize(30,30)
+ self.icon_frame.setStyleSheet("background: none;")
+ self.icon_layout = QVBoxLayout(self.icon_frame)
+ self.icon_layout.setContentsMargins(0,0,0,0)
+ self.icon_layout.setSpacing(5)
+ self.icon = PyIcon(self._icon_path, self._icon_color)
+ self.icon_layout.addWidget(self.icon, Qt.AlignCenter, Qt.AlignCenter)
+
+ # LABEL
+ self.title_label = QLabel(self._text_title)
+ self.title_label.setObjectName("title_label")
+ self.title_label.setStyleSheet(f'''
+ #title_label {{
+ font-size: {self._text_title_size}pt;
+ color: {self._text_title_color};
+ padding-bottom: 2px;
+ background: none;
+ }}
+ ''')
+
+ # BTN FRAME
+ self.btn_frame = QFrame()
+ self.btn_frame.setFixedSize(30,30)
+ self.btn_frame.setStyleSheet("background: none;")
+ # CLOSE BUTTON
+ self.btn_close = PyLeftButton(
+ self._parent,
+ self._app_parent,
+ tooltip_text = "Hide",
+ dark_one = self._dark_one,
+ bg_color = self._btn_color,
+ bg_color_hover = self._btn_color_hover,
+ bg_color_pressed = self._btn_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_pressed,
+ context_color = self._context_color,
+ text_foreground = self._text_title_color,
+ icon_path = self._icon_close_path,
+ radius = 6,
+ )
+ self.btn_close.setParent(self.btn_frame)
+ self.btn_close.setObjectName("btn_close_left_column")
+
+ # ADD TO TITLE LAYOUT
+ self.title_bg_layout.addWidget(self.icon_frame)
+ self.title_bg_layout.addWidget(self.title_label)
+ self.title_bg_layout.addWidget(self.btn_frame)
+
+ # ADD TITLE BG TO LAYOUT
+ self.title_base_layout.addWidget(self.title_bg_frame)
+
+ # CONTENT FRAME
+ # ///////////////////////////////////////////////////////////////
+ self.content_frame = QFrame()
+ self.content_frame.setStyleSheet("background: none")
+
+ # ADD TO LAYOUT
+ # ///////////////////////////////////////////////////////////////
+ self.base_layout.addWidget(self.title_frame)
+ self.base_layout.addWidget(self.content_frame)
diff --git a/src/educoder/gui/widgets/py_left_menu/__init__.py b/src/educoder/gui/widgets/py_left_menu/__init__.py
new file mode 100644
index 0000000..5c0ed6e
--- /dev/null
+++ b/src/educoder/gui/widgets/py_left_menu/__init__.py
@@ -0,0 +1,20 @@
+# ///////////////////////////////////////////////////////////////
+#
+# 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
+#
+# ///////////////////////////////////////////////////////////////
+
+# PY LEFT MENU
+# Left menu bar
+# ///////////////////////////////////////////////////////////////
+from . py_left_menu import PyLeftMenu
\ No newline at end of file
diff --git a/src/educoder/gui/widgets/py_left_menu/py_div.py b/src/educoder/gui/widgets/py_left_menu/py_div.py
new file mode 100644
index 0000000..2aa68c1
--- /dev/null
+++ b/src/educoder/gui/widgets/py_left_menu/py_div.py
@@ -0,0 +1,34 @@
+# ///////////////////////////////////////////////////////////////
+#
+# 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 src.educoder.qt_core import *
+
+# CUSTOM LEFT MENU
+# ///////////////////////////////////////////////////////////////
+class PyDiv(QWidget):
+ def __init__(self, color):
+ super().__init__()
+
+ self.layout = QHBoxLayout(self)
+ self.layout.setContentsMargins(5,0,5,0)
+ self.frame_line = QFrame()
+ self.frame_line.setStyleSheet(f"background: {color};")
+ self.frame_line.setMaximumHeight(1)
+ self.frame_line.setMinimumHeight(1)
+ self.layout.addWidget(self.frame_line)
+ self.setMaximumHeight(1)
diff --git a/src/educoder/gui/widgets/py_left_menu/py_left_menu.py b/src/educoder/gui/widgets/py_left_menu/py_left_menu.py
new file mode 100644
index 0000000..30d5db7
--- /dev/null
+++ b/src/educoder/gui/widgets/py_left_menu/py_left_menu.py
@@ -0,0 +1,266 @@
+# ///////////////////////////////////////////////////////////////
+#
+# 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 src.educoder.qt_core import *
+
+# IMPORT BUTTON AND DIV
+# ///////////////////////////////////////////////////////////////
+from . py_left_menu_button import PyLeftMenuButton
+from . py_div import PyDiv
+
+# IMPORT FUNCTIONS
+# ///////////////////////////////////////////////////////////////
+from gui.core.functions import *
+
+# PY LEFT MENU
+# ///////////////////////////////////////////////////////////////
+class PyLeftMenu(QWidget):
+ # SIGNALS
+ clicked = Signal(object)
+ released = Signal(object)
+
+ def __init__(
+ self,
+ parent = None,
+ app_parent = None,
+ dark_one = "#1b1e23",
+ dark_three = "#21252d",
+ dark_four = "#272c36",
+ bg_one = "#2c313c",
+ icon_color = "#c3ccdf",
+ icon_color_hover = "#dce1ec",
+ icon_color_pressed = "#edf0f5",
+ icon_color_active = "#f5f6f9",
+ context_color = "#568af2",
+ text_foreground = "#8a95aa",
+ text_active = "#dce1ec",
+ duration_time = 500,
+ radius = 8,
+ minimum_width = 50,
+ maximum_width = 240,
+ icon_path = "icon_menu.svg",
+ icon_path_close = "icon_menu_close.svg",
+ toggle_text = "Hide Menu",
+ toggle_tooltip = "Show menu"
+ ):
+ super().__init__()
+
+ # PROPERTIES
+ # ///////////////////////////////////////////////////////////////
+ self._dark_one = dark_one
+ self._dark_three = dark_three
+ self._dark_four = dark_four
+ self._bg_one = bg_one
+ 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
+ self._context_color = context_color
+ self._text_foreground = text_foreground
+ self._text_active = text_active
+ self._duration_time = duration_time
+ self._radius = radius
+ self._minimum_width = minimum_width
+ self._maximum_width = maximum_width
+ self._icon_path = Functions.set_svg_icon(icon_path)
+ self._icon_path_close = Functions.set_svg_icon(icon_path_close)
+
+ # SET PARENT
+ self._parent = parent
+ self._app_parent = app_parent
+
+ # SETUP WIDGETS
+ self.setup_ui()
+
+ # SET BG COLOR
+ self.bg.setStyleSheet(f"background: {dark_one}; border-radius: {radius};")
+
+ # TOGGLE BUTTON AND DIV MENUS
+ # ///////////////////////////////////////////////////////////////
+ self.toggle_button = PyLeftMenuButton(
+ app_parent,
+ text = toggle_text,
+ tooltip_text = toggle_tooltip,
+ dark_one = self._dark_one,
+ dark_three = self._dark_three,
+ dark_four = self._dark_four,
+ bg_one = self._bg_one,
+ icon_color = self._icon_color,
+ icon_color_hover = self._icon_color_active,
+ icon_color_pressed = self._icon_color_pressed,
+ icon_color_active = self._icon_color_active,
+ context_color = self._context_color,
+ text_foreground = self._text_foreground,
+ text_active = self._text_active,
+ icon_path = icon_path
+ )
+ self.toggle_button.clicked.connect(self.toggle_animation)
+ self.div_top = PyDiv(dark_four)
+
+ # ADD TO TOP LAYOUT
+ # ///////////////////////////////////////////////////////////////
+ self.top_layout.addWidget(self.toggle_button)
+ self.top_layout.addWidget(self.div_top)
+
+ # ADD TO BOTTOM LAYOUT
+ # ///////////////////////////////////////////////////////////////
+ self.div_bottom = PyDiv(dark_four)
+ self.div_bottom.hide()
+ self.bottom_layout.addWidget(self.div_bottom)
+
+ # ADD BUTTONS TO LEFT MENU
+ # Add btns and emit signals
+ # ///////////////////////////////////////////////////////////////
+ def add_menus(self, parameters):
+ if parameters != None:
+ for parameter in parameters:
+ _btn_icon = parameter['btn_icon']
+ _btn_id = parameter['btn_id']
+ _btn_text = parameter['btn_text']
+ _btn_tooltip = parameter['btn_tooltip']
+ _show_top = parameter['show_top']
+ _is_active = parameter['is_active']
+
+ self.menu = PyLeftMenuButton(
+ self._app_parent,
+ text = _btn_text,
+ btn_id = _btn_id,
+ tooltip_text = _btn_tooltip,
+ dark_one = self._dark_one,
+ dark_three = self._dark_three,
+ dark_four = self._dark_four,
+ bg_one = self._bg_one,
+ icon_color = self._icon_color,
+ icon_color_hover = self._icon_color_active,
+ icon_color_pressed = self._icon_color_pressed,
+ icon_color_active = self._icon_color_active,
+ context_color = self._context_color,
+ text_foreground = self._text_foreground,
+ text_active = self._text_active,
+ icon_path = _btn_icon,
+ is_active = _is_active
+ )
+ self.menu.clicked.connect(self.btn_clicked)
+ self.menu.released.connect(self.btn_released)
+
+ # ADD TO LAYOUT
+ if _show_top:
+ self.top_layout.addWidget(self.menu)
+ else:
+ self.div_bottom.show()
+ self.bottom_layout.addWidget(self.menu)
+
+ # LEFT MENU EMIT SIGNALS
+ # ///////////////////////////////////////////////////////////////
+ def btn_clicked(self):
+ self.clicked.emit(self.menu)
+
+ def btn_released(self):
+ self.released.emit(self.menu)
+
+ # EXPAND / RETRACT LEF MENU
+ # ///////////////////////////////////////////////////////////////
+ def toggle_animation(self):
+ # CREATE ANIMATION
+ self.animation = QPropertyAnimation(self._parent, b"minimumWidth")
+ self.animation.stop()
+ if self.width() == self._minimum_width:
+ self.animation.setStartValue(self.width())
+ self.animation.setEndValue(self._maximum_width)
+ self.toggle_button.set_active_toggle(True)
+ self.toggle_button.set_icon(self._icon_path_close)
+ else:
+ self.animation.setStartValue(self.width())
+ self.animation.setEndValue(self._minimum_width)
+ self.toggle_button.set_active_toggle(False)
+ self.toggle_button.set_icon(self._icon_path)
+ self.animation.setEasingCurve(QEasingCurve.InOutCubic)
+ self.animation.setDuration(self._duration_time)
+ self.animation.start()
+
+ # SELECT ONLY ONE BTN
+ # ///////////////////////////////////////////////////////////////
+ def select_only_one(self, widget: str):
+ for btn in self.findChildren(QPushButton):
+ if btn.objectName() == widget:
+ btn.set_active(True)
+ else:
+ btn.set_active(False)
+
+ # SELECT ONLY ONE TAB BTN
+ # ///////////////////////////////////////////////////////////////
+ def select_only_one_tab(self, widget: str):
+ for btn in self.findChildren(QPushButton):
+ if btn.objectName() == widget:
+ btn.set_active_tab(True)
+ else:
+ btn.set_active_tab(False)
+
+ # DESELECT ALL BTNs
+ # ///////////////////////////////////////////////////////////////
+ def deselect_all(self):
+ for btn in self.findChildren(QPushButton):
+ btn.set_active(False)
+
+ # DESELECT ALL TAB BTNs
+ # ///////////////////////////////////////////////////////////////
+ def deselect_all_tab(self):
+ for btn in self.findChildren(QPushButton):
+ btn.set_active_tab(False)
+
+ # SETUP APP
+ # ///////////////////////////////////////////////////////////////
+ def setup_ui(self):
+ # ADD MENU LAYOUT
+ self.left_menu_layout = QVBoxLayout(self)
+ self.left_menu_layout.setContentsMargins(0,0,0,0)
+
+ # ADD BG
+ self.bg = QFrame()
+
+ # TOP FRAME
+ self.top_frame = QFrame()
+
+ # BOTTOM FRAME
+ self.bottom_frame = QFrame()
+
+ # ADD LAYOUTS
+ self._layout = QVBoxLayout(self.bg)
+ self._layout.setContentsMargins(0,0,0,0)
+
+ # TOP LAYOUT
+ self.top_layout = QVBoxLayout(self.top_frame)
+ self.top_layout.setContentsMargins(0,0,0,0)
+ self.top_layout.setSpacing(1)
+
+ # BOTTOM LAYOUT
+ self.bottom_layout = QVBoxLayout(self.bottom_frame)
+ self.bottom_layout.setContentsMargins(0,0,0,8)
+ self.bottom_layout.setSpacing(1)
+
+ # ADD TOP AND BOTTOM FRAME
+ self._layout.addWidget(self.top_frame, 0, Qt.AlignTop)
+ self._layout.addWidget(self.bottom_frame, 0, Qt.AlignBottom)
+
+ # ADD BG TO LAYOUT
+ self.left_menu_layout.addWidget(self.bg)
+
+
+
+
+
diff --git a/src/educoder/gui/widgets/py_left_menu/py_left_menu_button.py b/src/educoder/gui/widgets/py_left_menu/py_left_menu_button.py
new file mode 100644
index 0000000..f7bc575
--- /dev/null
+++ b/src/educoder/gui/widgets/py_left_menu/py_left_menu_button.py
@@ -0,0 +1,380 @@
+# ///////////////////////////////////////////////////////////////
+#
+# 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 os
+
+# IMPORT QT CORE
+# ///////////////////////////////////////////////////////////////
+from src.educoder.qt_core import *
+
+# IMPORT FUNCTIONS
+# ///////////////////////////////////////////////////////////////
+from src.educoder.gui.core.functions import *
+
+# CUSTOM LEFT MENU
+# ///////////////////////////////////////////////////////////////
+class PyLeftMenuButton(QPushButton):
+ def __init__(
+ self,
+ app_parent,
+ text,
+ btn_id = None,
+ tooltip_text = "",
+ margin = 4,
+ dark_one = "#1b1e23",
+ dark_three = "#21252d",
+ dark_four = "#272c36",
+ bg_one = "#2c313c",
+ icon_color = "#c3ccdf",
+ icon_color_hover = "#dce1ec",
+ icon_color_pressed = "#edf0f5",
+ icon_color_active = "#f5f6f9",
+ context_color = "#568af2",
+ text_foreground = "#8a95aa",
+ text_active = "#dce1ec",
+ icon_path = "icon_add_user.svg",
+ icon_active_menu = "active_menu.svg",
+ is_active = False,
+ is_active_tab = False,
+ is_toggle_active = False
+ ):
+ super().__init__()
+ self.setText(text)
+ self.setCursor(Qt.PointingHandCursor)
+ self.setMaximumHeight(50)
+ self.setMinimumHeight(50)
+ self.setObjectName(btn_id)
+
+ # APP PATH
+ self._icon_path = Functions.set_svg_icon(icon_path)
+ self._icon_active_menu = Functions.set_svg_icon(icon_active_menu)
+
+ # PROPERTIES
+ self._margin = margin
+ self._dark_one = dark_one
+ self._dark_three = dark_three
+ self._dark_four = dark_four
+ self._bg_one = bg_one
+ 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
+ self._set_icon_color = self._icon_color # Set icon color
+ self._set_bg_color = self._dark_one # Set BG color
+ self._set_text_foreground = text_foreground
+ self._set_text_active = text_active
+ self._parent = app_parent
+ self._is_active = is_active
+ self._is_active_tab = is_active_tab
+ self._is_toggle_active = is_toggle_active
+
+ # TOOLTIP
+ self._tooltip_text = tooltip_text
+ self.tooltip = _ToolTip(
+ app_parent,
+ tooltip_text,
+ dark_one,
+ context_color,
+ text_foreground
+ )
+ self.tooltip.hide()
+
+ # PAINT EVENT
+ # ///////////////////////////////////////////////////////////////
+ def paintEvent(self, event):
+ # PAINTER
+ p = QPainter()
+ p.begin(self)
+ p.setRenderHint(QPainter.Antialiasing)
+ p.setPen(Qt.NoPen)
+ p.setFont(self.font())
+
+ # RECTANGLES
+ rect = QRect(4, 5, self.width(), self.height() - 10)
+ rect_inside = QRect(4, 5, self.width() - 8, self.height() - 10)
+ rect_icon = QRect(0, 0, 50, self.height())
+ rect_blue = QRect(4, 5, 20, self.height() - 10)
+ rect_inside_active = QRect(7, 5, self.width(), self.height() - 10)
+ rect_text = QRect(45, 0, self.width() - 50, self.height())
+
+ if self._is_active:
+ # DRAW BG BLUE
+ p.setBrush(QColor(self._context_color))
+ p.drawRoundedRect(rect_blue, 8, 8)
+
+ # BG INSIDE
+ p.setBrush(QColor(self._bg_one))
+ p.drawRoundedRect(rect_inside_active, 8, 8)
+
+ # DRAW ACTIVE
+ icon_path = self._icon_active_menu
+ app_path = os.path.abspath(os.getcwd())
+ icon_path = os.path.normpath(os.path.join(app_path, icon_path))
+ self._set_icon_color = self._icon_color_active
+ self.icon_active(p, icon_path, self.width())
+
+ # DRAW TEXT
+ p.setPen(QColor(self._set_text_active))
+ p.drawText(rect_text, Qt.AlignVCenter, self.text())
+
+ # DRAW ICONS
+ self.icon_paint(p, self._icon_path, rect_icon, self._set_icon_color)
+
+ elif self._is_active_tab:
+ # DRAW BG BLUE
+ p.setBrush(QColor(self._dark_four))
+ p.drawRoundedRect(rect_blue, 8, 8)
+
+ # BG INSIDE
+ p.setBrush(QColor(self._bg_one))
+ p.drawRoundedRect(rect_inside_active, 8, 8)
+
+ # DRAW ACTIVE
+ icon_path = self._icon_active_menu
+ app_path = os.path.abspath(os.getcwd())
+ icon_path = os.path.normpath(os.path.join(app_path, icon_path))
+ self._set_icon_color = self._icon_color_active
+ self.icon_active(p, icon_path, self.width())
+
+ # DRAW TEXT
+ p.setPen(QColor(self._set_text_active))
+ p.drawText(rect_text, Qt.AlignVCenter, self.text())
+
+ # DRAW ICONS
+ self.icon_paint(p, self._icon_path, rect_icon, self._set_icon_color)
+
+ # NORMAL BG
+ else:
+ if self._is_toggle_active:
+ # BG INSIDE
+ p.setBrush(QColor(self._dark_three))
+ p.drawRoundedRect(rect_inside, 8, 8)
+
+ # DRAW TEXT
+ p.setPen(QColor(self._set_text_foreground))
+ p.drawText(rect_text, Qt.AlignVCenter, self.text())
+
+ # DRAW ICONS
+ if self._is_toggle_active:
+ self.icon_paint(p, self._icon_path, rect_icon, self._context_color)
+ else:
+ self.icon_paint(p, self._icon_path, rect_icon, self._set_icon_color)
+ else:
+ # BG INSIDE
+ p.setBrush(QColor(self._set_bg_color))
+ p.drawRoundedRect(rect_inside, 8, 8)
+
+ # DRAW TEXT
+ p.setPen(QColor(self._set_text_foreground))
+ p.drawText(rect_text, Qt.AlignVCenter, self.text())
+
+ # DRAW ICONS
+ self.icon_paint(p, self._icon_path, rect_icon, self._set_icon_color)
+
+ p.end()
+
+ # SET ACTIVE MENU
+ # ///////////////////////////////////////////////////////////////
+ def set_active(self, is_active):
+ self._is_active = is_active
+ if not is_active:
+ self._set_icon_color = self._icon_color
+ self._set_bg_color = self._dark_one
+
+ self.repaint()
+
+ # SET ACTIVE TAB MENU
+ # ///////////////////////////////////////////////////////////////
+ def set_active_tab(self, is_active):
+ self._is_active_tab = is_active
+ if not is_active:
+ self._set_icon_color = self._icon_color
+ self._set_bg_color = self._dark_one
+
+ self.repaint()
+
+ # RETURN IF IS ACTIVE MENU
+ # ///////////////////////////////////////////////////////////////
+ def is_active(self):
+ return self._is_active
+
+ # RETURN IF IS ACTIVE TAB MENU
+ # ///////////////////////////////////////////////////////////////
+ def is_active_tab(self):
+ return self._is_active_tab
+
+ # SET ACTIVE TOGGLE
+ # ///////////////////////////////////////////////////////////////
+ def set_active_toggle(self, is_active):
+ self._is_toggle_active = is_active
+
+ # SET ICON
+ # ///////////////////////////////////////////////////////////////
+ def set_icon(self, icon_path):
+ self._icon_path = icon_path
+ self.repaint()
+
+ # DRAW ICON WITH COLORS
+ # ///////////////////////////////////////////////////////////////
+ def icon_paint(self, qp, image, rect, color):
+ icon = QPixmap(image)
+ painter = QPainter(icon)
+ painter.setCompositionMode(QPainter.CompositionMode_SourceIn)
+ painter.fillRect(icon.rect(), color)
+ qp.drawPixmap(
+ (rect.width() - icon.width()) / 2,
+ (rect.height() - icon.height()) / 2,
+ icon
+ )
+ painter.end()
+
+ # DRAW ACTIVE ICON / RIGHT SIDE
+ # ///////////////////////////////////////////////////////////////
+ def icon_active(self, qp, image, width):
+ icon = QPixmap(image)
+ painter = QPainter(icon)
+ painter.setCompositionMode(QPainter.CompositionMode_SourceIn)
+ painter.fillRect(icon.rect(), self._bg_one)
+ qp.drawPixmap(width - 5, 0, icon)
+ painter.end()
+
+ # CHANGE STYLES
+ # Functions with custom styles
+ # ///////////////////////////////////////////////////////////////
+ def change_style(self, event):
+ if event == QEvent.Enter:
+ if not self._is_active:
+ self._set_icon_color = self._icon_color_hover
+ self._set_bg_color = self._dark_three
+ self.repaint()
+ elif event == QEvent.Leave:
+ if not self._is_active:
+ self._set_icon_color = self._icon_color
+ self._set_bg_color = self._dark_one
+ self.repaint()
+ elif event == QEvent.MouseButtonPress:
+ if not self._is_active:
+ self._set_icon_color = self._context_color
+ self._set_bg_color = self._dark_four
+ self.repaint()
+ elif event == QEvent.MouseButtonRelease:
+ if not self._is_active:
+ self._set_icon_color = self._icon_color_hover
+ self._set_bg_color = self._dark_three
+ self.repaint()
+
+ # MOUSE OVER
+ # Event triggered when the mouse is over the BTN
+ # ///////////////////////////////////////////////////////////////
+ def enterEvent(self, event):
+ self.change_style(QEvent.Enter)
+ if self.width() == 50 and self._tooltip_text:
+ 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.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)
+ self.tooltip.hide()
+ 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)
+ return self.released.emit()
+
+ # MOVE TOOLTIP
+ # ///////////////////////////////////////////////////////////////
+ def move_tooltip(self):
+ # GET MAIN WINDOW PARENT
+ gp = self.mapToGlobal(QPoint(0, 0))
+
+ # SET WIDGET TO GET POSTION
+ # Return absolute position of widget inside app
+ pos = self._parent.mapFromGlobal(gp)
+
+ # FORMAT POSITION
+ # Adjust tooltip position with offset
+ pos_x = pos.x() + self.width() + 5
+ pos_y = pos.y() + (self.width() - self.tooltip.height()) // 2
+
+ # SET POSITION TO WIDGET
+ # Move tooltip position
+ self.tooltip.move(pos_x, pos_y)
+
+class _ToolTip(QLabel):
+ # TOOLTIP / LABEL StyleSheet
+ style_tooltip = """
+ QLabel {{
+ background-color: {_dark_one};
+ color: {_text_foreground};
+ padding-left: 10px;
+ padding-right: 10px;
+ border-radius: 17px;
+ border: 0px solid transparent;
+ border-left: 3px solid {_context_color};
+ font: 800 9pt "Segoe UI";
+ }}
+ """
+
+ def __init__(
+ self,
+ parent,
+ tooltip,
+ dark_one,
+ context_color,
+ text_foreground
+ ):
+ QLabel.__init__(self)
+
+ # LABEL SETUP
+ style = self.style_tooltip.format(
+ _dark_one = dark_one,
+ _context_color = context_color,
+ _text_foreground = text_foreground
+ )
+ self.setObjectName(u"label_tooltip")
+ self.setStyleSheet(style)
+ self.setMinimumHeight(34)
+ self.setParent(parent)
+ self.setText(tooltip)
+ self.adjustSize()
+
+ # SET DROP SHADOW
+ self.shadow = QGraphicsDropShadowEffect(self)
+ self.shadow.setBlurRadius(30)
+ self.shadow.setXOffset(0)
+ self.shadow.setYOffset(0)
+ self.shadow.setColor(QColor(0, 0, 0, 80))
+ self.setGraphicsEffect(self.shadow)
+
+
diff --git a/src/educoder/gui/widgets/py_line_edit/__init__.py b/src/educoder/gui/widgets/py_line_edit/__init__.py
new file mode 100644
index 0000000..cb20e14
--- /dev/null
+++ b/src/educoder/gui/widgets/py_line_edit/__init__.py
@@ -0,0 +1,19 @@
+# ///////////////////////////////////////////////////////////////
+#
+# 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
+#
+# ///////////////////////////////////////////////////////////////
+
+# PY LINE EDIT
+# ///////////////////////////////////////////////////////////////
+from . py_line_edit import PyLineEdit
\ No newline at end of file
diff --git a/src/educoder/gui/widgets/py_line_edit/py_line_edit.py b/src/educoder/gui/widgets/py_line_edit/py_line_edit.py
new file mode 100644
index 0000000..ed8cfd8
--- /dev/null
+++ b/src/educoder/gui/widgets/py_line_edit/py_line_edit.py
@@ -0,0 +1,95 @@
+# ///////////////////////////////////////////////////////////////
+#
+# 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 src.educoder.qt_core import *
+
+# STYLE
+# ///////////////////////////////////////////////////////////////
+style = '''
+QLineEdit {{
+ background-color: {_bg_color};
+ border-radius: {_radius}px;
+ border: {_border_size}px solid transparent;
+ padding-left: 10px;
+ padding-right: 10px;
+ selection-color: {_selection_color};
+ selection-background-color: {_context_color};
+ color: {_color};
+}}
+QLineEdit:focus {{
+ border: {_border_size}px solid {_context_color};
+ background-color: {_bg_color_active};
+}}
+'''
+
+# PY PUSH BUTTON
+# ///////////////////////////////////////////////////////////////
+class PyLineEdit(QLineEdit):
+ def __init__(
+ self,
+ text = "",
+ place_holder_text = "",
+ radius = 8,
+ border_size = 2,
+ color = "#FFF",
+ selection_color = "#FFF",
+ bg_color = "#333",
+ bg_color_active = "#222",
+ context_color = "#00ABE8"
+ ):
+ super().__init__()
+
+ # PARAMETERS
+ if text:
+ self.setText(text)
+ if place_holder_text:
+ self.setPlaceholderText(place_holder_text)
+
+ # SET STYLESHEET
+ self.set_stylesheet(
+ radius,
+ border_size,
+ color,
+ selection_color,
+ bg_color,
+ bg_color_active,
+ context_color
+ )
+
+ # SET STYLESHEET
+ def set_stylesheet(
+ self,
+ radius,
+ border_size,
+ color,
+ selection_color,
+ bg_color,
+ bg_color_active,
+ context_color
+ ):
+ # APPLY STYLESHEET
+ style_format = style.format(
+ _radius = radius,
+ _border_size = border_size,
+ _color = color,
+ _selection_color = selection_color,
+ _bg_color = bg_color,
+ _bg_color_active = bg_color_active,
+ _context_color = context_color
+ )
+ self.setStyleSheet(style_format)
\ No newline at end of file
diff --git a/src/educoder/gui/widgets/py_push_button/__init__.py b/src/educoder/gui/widgets/py_push_button/__init__.py
new file mode 100644
index 0000000..9467b6a
--- /dev/null
+++ b/src/educoder/gui/widgets/py_push_button/__init__.py
@@ -0,0 +1,19 @@
+# ///////////////////////////////////////////////////////////////
+#
+# 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
+#
+# ///////////////////////////////////////////////////////////////
+
+# PY PUSH BUTTON
+# ///////////////////////////////////////////////////////////////
+from . py_push_button import PyPushButton
\ No newline at end of file
diff --git a/src/educoder/gui/widgets/py_push_button/py_push_button.py b/src/educoder/gui/widgets/py_push_button/py_push_button.py
new file mode 100644
index 0000000..0d5b421
--- /dev/null
+++ b/src/educoder/gui/widgets/py_push_button/py_push_button.py
@@ -0,0 +1,71 @@
+# ///////////////////////////////////////////////////////////////
+#
+# 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 src.educoder.qt_core import *
+
+# STYLE
+# ///////////////////////////////////////////////////////////////
+style = '''
+QPushButton {{
+ border: none;
+ padding-left: 10px;
+ padding-right: 5px;
+ color: {_color};
+ border-radius: {_radius};
+ background-color: {_bg_color};
+}}
+QPushButton:hover {{
+ background-color: {_bg_color_hover};
+}}
+QPushButton:pressed {{
+ background-color: {_bg_color_pressed};
+}}
+'''
+
+# PY PUSH BUTTON
+# ///////////////////////////////////////////////////////////////
+class PyPushButton(QPushButton):
+ def __init__(
+ self,
+ text,
+ radius,
+ color,
+ bg_color,
+ bg_color_hover,
+ bg_color_pressed,
+ parent = None,
+ ):
+ super().__init__()
+
+ # SET PARAMETRES
+ self.setText(text)
+ if parent != None:
+ self.setParent(parent)
+ self.setCursor(Qt.PointingHandCursor)
+
+ # SET STYLESHEET
+ custom_style = style.format(
+ _color = color,
+ _radius = radius,
+ _bg_color = bg_color,
+ _bg_color_hover = bg_color_hover,
+ _bg_color_pressed = bg_color_pressed
+ )
+ self.setStyleSheet(custom_style)
+
+
\ No newline at end of file
diff --git a/src/educoder/gui/widgets/py_slider/__init__.py b/src/educoder/gui/widgets/py_slider/__init__.py
new file mode 100644
index 0000000..2ba529d
--- /dev/null
+++ b/src/educoder/gui/widgets/py_slider/__init__.py
@@ -0,0 +1,19 @@
+# ///////////////////////////////////////////////////////////////
+#
+# 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
+#
+# ///////////////////////////////////////////////////////////////
+
+# PY SLIDER
+# ///////////////////////////////////////////////////////////////
+from . py_slider import PySlider
\ No newline at end of file
diff --git a/src/educoder/gui/widgets/py_slider/py_slider.py b/src/educoder/gui/widgets/py_slider/py_slider.py
new file mode 100644
index 0000000..011fb50
--- /dev/null
+++ b/src/educoder/gui/widgets/py_slider/py_slider.py
@@ -0,0 +1,97 @@
+# ///////////////////////////////////////////////////////////////
+#
+# 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 src.educoder.qt_core import *
+
+style = """
+/* HORIZONTAL */
+QSlider {{ margin: {_margin}px; }}
+QSlider::groove:horizontal {{
+ border-radius: {_bg_radius}px;
+ height: {_bg_size}px;
+ margin: 0px;
+ background-color: {_bg_color};
+}}
+QSlider::groove:horizontal:hover {{ background-color: {_bg_color_hover}; }}
+QSlider::handle:horizontal {{
+ border: none;
+ height: {_handle_size}px;
+ width: {_handle_size}px;
+ margin: {_handle_margin}px;
+ border-radius: {_handle_radius}px;
+ background-color: {_handle_color};
+}}
+QSlider::handle:horizontal:hover {{ background-color: {_handle_color_hover}; }}
+QSlider::handle:horizontal:pressed {{ background-color: {_handle_color_pressed}; }}
+
+/* VERTICAL */
+QSlider::groove:vertical {{
+ border-radius: {_bg_radius}px;
+ width: {_bg_size}px;
+ margin: 0px;
+ background-color: {_bg_color};
+}}
+QSlider::groove:vertical:hover {{ background-color: {_bg_color_hover}; }}
+QSlider::handle:vertical {{
+ border: none;
+ height: {_handle_size}px;
+ width: {_handle_size}px;
+ margin: {_handle_margin}px;
+ border-radius: {_handle_radius}px;
+ background-color: {_handle_color};
+}}
+QSlider::handle:vertical:hover {{ background-color: {_handle_color_hover}; }}
+QSlider::handle:vertical:pressed {{ background-color: {_handle_color_pressed}; }}
+"""
+
+class PySlider(QSlider):
+ def __init__(
+ self,
+ margin = 0,
+ bg_size = 20,
+ bg_radius = 10,
+ bg_color = "#1b1e23",
+ bg_color_hover = "#1e2229",
+ handle_margin = 2,
+ handle_size = 16,
+ handle_radius = 8,
+ handle_color = "#568af2",
+ handle_color_hover = "#6c99f4",
+ handle_color_pressed = "#3f6fd1"
+ ):
+ super(PySlider, self).__init__()
+
+ # FORMAT STYLE
+ # ///////////////////////////////////////////////////////////////
+ adjust_style = style.format(
+ _margin = margin,
+ _bg_size = bg_size,
+ _bg_radius = bg_radius,
+ _bg_color = bg_color,
+ _bg_color_hover = bg_color_hover,
+ _handle_margin = handle_margin,
+ _handle_size = handle_size,
+ _handle_radius = handle_radius,
+ _handle_color = handle_color,
+ _handle_color_hover = handle_color_hover,
+ _handle_color_pressed = handle_color_pressed
+ )
+
+ # APPLY CUSTOM STYLE
+ # ///////////////////////////////////////////////////////////////
+ self.setStyleSheet(adjust_style)
\ No newline at end of file
diff --git a/src/educoder/gui/widgets/py_table_widget/__init__.py b/src/educoder/gui/widgets/py_table_widget/__init__.py
new file mode 100644
index 0000000..240646c
--- /dev/null
+++ b/src/educoder/gui/widgets/py_table_widget/__init__.py
@@ -0,0 +1,19 @@
+# ///////////////////////////////////////////////////////////////
+#
+# 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
+#
+# ///////////////////////////////////////////////////////////////
+
+# PY TABLE WIDGET
+# ///////////////////////////////////////////////////////////////
+from . py_table_widget import PyTableWidget
\ No newline at end of file
diff --git a/src/educoder/gui/widgets/py_table_widget/py_table_widget.py b/src/educoder/gui/widgets/py_table_widget/py_table_widget.py
new file mode 100644
index 0000000..f0904bd
--- /dev/null
+++ b/src/educoder/gui/widgets/py_table_widget/py_table_widget.py
@@ -0,0 +1,90 @@
+# ///////////////////////////////////////////////////////////////
+#
+# 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 src.educoder.qt_core import *
+
+# IMPORT STYLE
+# ///////////////////////////////////////////////////////////////
+from . style import *
+
+# PY PUSH BUTTON
+# ///////////////////////////////////////////////////////////////
+class PyTableWidget(QTableWidget):
+ def __init__(
+ self,
+ radius = 8,
+ color = "#FFF",
+ bg_color = "#444",
+ selection_color = "#FFF",
+ header_horizontal_color = "#333",
+ header_vertical_color = "#444",
+ bottom_line_color = "#555",
+ grid_line_color = "#555",
+ scroll_bar_bg_color = "#FFF",
+ scroll_bar_btn_color = "#3333",
+ context_color = "#00ABE8"
+ ):
+ super().__init__()
+
+ # PARAMETERS
+
+ # SET STYLESHEET
+ self.set_stylesheet(
+ radius,
+ color,
+ bg_color,
+ header_horizontal_color,
+ header_vertical_color,
+ selection_color,
+ bottom_line_color,
+ grid_line_color,
+ scroll_bar_bg_color,
+ scroll_bar_btn_color,
+ context_color
+ )
+
+ # SET STYLESHEET
+ def set_stylesheet(
+ self,
+ radius,
+ color,
+ bg_color,
+ header_horizontal_color,
+ header_vertical_color,
+ selection_color,
+ bottom_line_color,
+ grid_line_color,
+ scroll_bar_bg_color,
+ scroll_bar_btn_color,
+ context_color
+ ):
+ # APPLY STYLESHEET
+ style_format = style.format(
+ _radius = radius,
+ _color = color,
+ _bg_color = bg_color,
+ _header_horizontal_color = header_horizontal_color,
+ _header_vertical_color = header_vertical_color,
+ _selection_color = selection_color,
+ _bottom_line_color = bottom_line_color,
+ _grid_line_color = grid_line_color,
+ _scroll_bar_bg_color = scroll_bar_bg_color,
+ _scroll_bar_btn_color = scroll_bar_btn_color,
+ _context_color = context_color
+ )
+ self.setStyleSheet(style_format)
\ No newline at end of file
diff --git a/src/educoder/gui/widgets/py_table_widget/style.py b/src/educoder/gui/widgets/py_table_widget/style.py
new file mode 100644
index 0000000..5c3afc0
--- /dev/null
+++ b/src/educoder/gui/widgets/py_table_widget/style.py
@@ -0,0 +1,135 @@
+# STYLE
+# ///////////////////////////////////////////////////////////////
+style = '''
+/* /////////////////////////////////////////////////////////////////////////////////////////////////
+QTableWidget */
+
+QTableWidget {{
+ background-color: {_bg_color};
+ padding: 5px;
+ border-radius: {_radius}px;
+ gridline-color: {_grid_line_color};
+ color: {_color};
+}}
+QTableWidget::item{{
+ border-color: none;
+ padding-left: 5px;
+ padding-right: 5px;
+ gridline-color: rgb(44, 49, 60);
+ border-bottom: 1px solid {_bottom_line_color};
+}}
+QTableWidget::item:selected{{
+ background-color: {_selection_color};
+}}
+QHeaderView::section{{
+ background-color: rgb(33, 37, 43);
+ max-width: 30px;
+ border: 1px solid rgb(44, 49, 58);
+ border-style: none;
+ border-bottom: 1px solid rgb(44, 49, 60);
+ border-right: 1px solid rgb(44, 49, 60);
+}}
+QTableWidget::horizontalHeader {{
+ background-color: rgb(33, 37, 43);
+}}
+QTableWidget QTableCornerButton::section {{
+ border: none;
+ background-color: {_header_horizontal_color};
+ padding: 3px;
+ border-top-left-radius: {_radius}px;
+}}
+QHeaderView::section:horizontal
+{{
+ border: none;
+ background-color: {_header_horizontal_color};
+ padding: 3px;
+}}
+QHeaderView::section:vertical
+{{
+ border: none;
+ background-color: {_header_vertical_color};
+ padding-left: 5px;
+ padding-right: 5px;
+ border-bottom: 1px solid {_bottom_line_color};
+ margin-bottom: 1px;
+}}
+
+
+/* /////////////////////////////////////////////////////////////////////////////////////////////////
+ScrollBars */
+QScrollBar:horizontal {{
+ border: none;
+ background: {_scroll_bar_bg_color};
+ height: 8px;
+ margin: 0px 21px 0 21px;
+ border-radius: 0px;
+}}
+QScrollBar::handle:horizontal {{
+ background: {_context_color};
+ min-width: 25px;
+ border-radius: 4px
+}}
+QScrollBar::add-line:horizontal {{
+ border: none;
+ background: {_scroll_bar_btn_color};
+ width: 20px;
+ border-top-right-radius: 4px;
+ border-bottom-right-radius: 4px;
+ subcontrol-position: right;
+ subcontrol-origin: margin;
+}}
+QScrollBar::sub-line:horizontal {{
+ border: none;
+ background: {_scroll_bar_btn_color};
+ width: 20px;
+ border-top-left-radius: 4px;
+ border-bottom-left-radius: 4px;
+ subcontrol-position: left;
+ subcontrol-origin: margin;
+}}
+QScrollBar::up-arrow:horizontal, QScrollBar::down-arrow:horizontal
+{{
+ background: none;
+}}
+QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal
+{{
+ background: none;
+}}
+QScrollBar:vertical {{
+ border: none;
+ background: {_scroll_bar_bg_color};
+ width: 8px;
+ margin: 21px 0 21px 0;
+ border-radius: 0px;
+}}
+QScrollBar::handle:vertical {{
+ background: {_context_color};
+ min-height: 25px;
+ border-radius: 4px
+}}
+QScrollBar::add-line:vertical {{
+ border: none;
+ background: {_scroll_bar_btn_color};
+ height: 20px;
+ border-bottom-left-radius: 4px;
+ border-bottom-right-radius: 4px;
+ subcontrol-position: bottom;
+ subcontrol-origin: margin;
+}}
+QScrollBar::sub-line:vertical {{
+ border: none;
+ background: {_scroll_bar_btn_color};
+ height: 20px;
+ border-top-left-radius: 4px;
+ border-top-right-radius: 4px;
+ subcontrol-position: top;
+ subcontrol-origin: margin;
+}}
+QScrollBar::up-arrow:vertical, QScrollBar::down-arrow:vertical {{
+ background: none;
+}}
+
+QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical {{
+ background: none;
+}}
+'''
\ No newline at end of file
diff --git a/src/educoder/gui/widgets/py_title_bar/__init__.py b/src/educoder/gui/widgets/py_title_bar/__init__.py
new file mode 100644
index 0000000..85dcd27
--- /dev/null
+++ b/src/educoder/gui/widgets/py_title_bar/__init__.py
@@ -0,0 +1,21 @@
+# ///////////////////////////////////////////////////////////////
+#
+# 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
+#
+# ///////////////////////////////////////////////////////////////
+
+# PY TITLE BAR
+# Top bar with move application, maximize, restore, minimize,
+# close buttons and extra buttons
+# ///////////////////////////////////////////////////////////////
+from . py_title_bar import PyTitleBar
\ No newline at end of file
diff --git a/src/educoder/gui/widgets/py_title_bar/py_div.py b/src/educoder/gui/widgets/py_title_bar/py_div.py
new file mode 100644
index 0000000..a0a1145
--- /dev/null
+++ b/src/educoder/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 src.educoder.qt_core import *
+
+# CUSTOM LEFT MENU
+# ///////////////////////////////////////////////////////////////
+class PyDiv(QWidget):
+ def __init__(self, color):
+ super().__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/src/educoder/gui/widgets/py_title_bar/py_title_bar.py b/src/educoder/gui/widgets/py_title_bar/py_title_bar.py
new file mode 100644
index 0000000..5f6d83d
--- /dev/null
+++ b/src/educoder/gui/widgets/py_title_bar/py_title_bar.py
@@ -0,0 +1,346 @@
+# ///////////////////////////////////////////////////////////////
+#
+# 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 src.educoder.qt_core import *
+
+# IMPORT FUNCTIONS
+# ///////////////////////////////////////////////////////////////
+from src.educoder.gui.core.functions import *
+
+# IMPORT SETTINGS
+# ///////////////////////////////////////////////////////////////
+from src.educoder.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
+# ///////////////////////////////////////////////////////////////
+class PyTitleBar(QWidget):
+ # SIGNALS
+ clicked = Signal(object)
+ released = Signal(object)
+
+ def __init__(
+ self,
+ parent,
+ app_parent,
+ logo_image = "logo_top_100x22.svg",
+ logo_width = 100,
+ buttons = None,
+ dark_one = "#1b1e23",
+ bg_color = "#343b48",
+ 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",
+ text_foreground = "#8a95aa",
+ radius = 8,
+ font_family = "Segoe UI",
+ title_size = 10,
+ is_custom_title_bar = True,
+ ):
+ super().__init__()
+
+ settings = Settings()
+ self.settings = settings.items
+
+ # PARAMETERS
+ self._logo_image = logo_image
+ self._dark_one = dark_one
+ self._bg_color = bg_color
+ self._div_color = div_color
+ self._parent = parent
+ self._app_parent = app_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
+ self._font_family = font_family
+ self._title_size = title_size
+ self._text_foreground = text_foreground
+ self._is_custom_title_bar = is_custom_title_bar
+
+ # SETUP UI
+ self.setup_ui()
+
+ # ADD BG COLOR
+ self.bg.setStyleSheet(f"background-color: {bg_color}; border-radius: {radius}px;")
+
+ # SET LOGO AND WIDTH
+ self.top_logo.setMinimumWidth(logo_width)
+ self.top_logo.setMaximumWidth(logo_width)
+ #self.top_logo.setPixmap(Functions.set_svg_image(logo_image))
+
+ # MOVE WINDOW / MAXIMIZE / RESTORE
+ # ///////////////////////////////////////////////////////////////
+ def moveWindow(event):
+ # IF MAXIMIZED CHANGE TO NORMAL
+ 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
+ if is_custom_title_bar:
+ self.top_logo.mouseMoveEvent = moveWindow
+ self.div_1.mouseMoveEvent = moveWindow
+ self.title_label.mouseMoveEvent = moveWindow
+ self.div_2.mouseMoveEvent = moveWindow
+ self.div_3.mouseMoveEvent = moveWindow
+
+ # MAXIMIZE / RESTORE
+ if is_custom_title_bar:
+ 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.div_2)
+
+ # ADD BUTTONS BUTTONS
+ # ///////////////////////////////////////////////////////////////
+ # Functions
+ self.minimize_button.released.connect(lambda: parent.showMinimized())
+ self.maximize_restore_button.released.connect(lambda: self.maximize_restore())
+ self.close_button.released.connect(lambda: parent.close())
+
+ # Extra BTNs layout
+ self.bg_layout.addLayout(self.custom_buttons_layout)
+
+ # ADD Buttons
+ if is_custom_title_bar:
+ self.bg_layout.addWidget(self.minimize_button)
+ self.bg_layout.addWidget(self.maximize_restore_button)
+ self.bg_layout.addWidget(self.close_button)
+
+ # ADD BUTTONS TO TITLE BAR
+ # Add btns and emit signals
+ # ///////////////////////////////////////////////////////////////
+ def add_menus(self, parameters):
+ if parameters != None and len(parameters) > 0:
+ for parameter in parameters:
+ _btn_icon = Functions.set_svg_icon(parameter['btn_icon'])
+ _btn_id = parameter['btn_id']
+ _btn_tooltip = parameter['btn_tooltip']
+ _is_active = parameter['is_active']
+
+ self.menu = PyTitleButton(
+ self._parent,
+ self._app_parent,
+ btn_id = _btn_id,
+ tooltip_text = _btn_tooltip,
+ dark_one = self._dark_one,
+ bg_color = self._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_active,
+ icon_color_pressed = self._icon_color_pressed,
+ icon_color_active = self._icon_color_active,
+ context_color = self._context_color,
+ text_foreground = self._text_foreground,
+ icon_path = _btn_icon,
+ is_active = _is_active
+ )
+ self.menu.clicked.connect(self.btn_clicked)
+ self.menu.released.connect(self.btn_released)
+
+ # ADD TO LAYOUT
+ self.custom_buttons_layout.addWidget(self.menu)
+
+ # ADD DIV
+ if self._is_custom_title_bar:
+ self.custom_buttons_layout.addWidget(self.div_3)
+
+ # TITLE BAR MENU EMIT SIGNALS
+ # ///////////////////////////////////////////////////////////////
+ def btn_clicked(self):
+ self.clicked.emit(self.menu)
+
+ def btn_released(self):
+ self.released.emit(self.menu)
+
+ # SET TITLE BAR TEXT
+ # ///////////////////////////////////////////////////////////////
+ def set_title(self, title):
+ self.title_label.setText(title)
+
+ # 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)
+ self.maximize_restore_button.set_icon(
+ Functions.set_svg_icon("icon_restore.svg")
+ )
+ else:
+ self._parent.ui.central_widget_layout.setContentsMargins(10,10,10,10)
+ self._parent.ui.window.set_stylesheet(border_radius = 10, border_size = 2)
+ self.maximize_restore_button.set_icon(
+ Functions.set_svg_icon("icon_maximize.svg")
+ )
+
+ # 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
+ # ///////////////////////////////////////////////////////////////
+ def setup_ui(self):
+ # ADD MENU LAYOUT
+ self.title_bar_layout = QVBoxLayout(self)
+ self.title_bar_layout.setContentsMargins(0,0,0,0)
+
+ # ADD BG
+ self.bg = QFrame()
+
+ # ADD BG LAYOUT
+ self.bg_layout = QHBoxLayout(self.bg)
+ 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)
+ self.div_3 = PyDiv(self._div_color)
+
+ # LEFT FRAME WITH MOVE APP
+ self.top_logo = QLabel()
+ self.top_logo_layout = QVBoxLayout(self.top_logo)
+ self.top_logo_layout.setContentsMargins(0,0,0,0)
+ self.logo_svg = QSvgWidget()
+ self.logo_svg.load(Functions.set_svg_image(self._logo_image))
+ self.top_logo_layout.addWidget(self.logo_svg, Qt.AlignCenter, Qt.AlignCenter)
+
+ # TITLE LABEL
+ self.title_label = QLabel()
+ self.title_label.setAlignment(Qt.AlignVCenter)
+ self.title_label.setStyleSheet(f'font: {self._title_size}pt "{self._font_family}"')
+
+ # CUSTOM BUTTONS LAYOUT
+ self.custom_buttons_layout = QHBoxLayout()
+ self.custom_buttons_layout.setContentsMargins(0,0,0,0)
+ self.custom_buttons_layout.setSpacing(3)
+
+ # MINIMIZE BUTTON
+ self.minimize_button = PyTitleButton(
+ self._parent,
+ self._app_parent,
+ tooltip_text = "Close app",
+ dark_one = self._dark_one,
+ 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,
+ context_color = self._context_color,
+ text_foreground = self._text_foreground,
+ radius = 6,
+ icon_path = Functions.set_svg_icon("icon_minimize.svg")
+ )
+
+ # MAXIMIZE / RESTORE BUTTON
+ self.maximize_restore_button = PyTitleButton(
+ self._parent,
+ self._app_parent,
+ tooltip_text = "Maximize app",
+ dark_one = self._dark_one,
+ 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,
+ context_color = self._context_color,
+ text_foreground = self._text_foreground,
+ radius = 6,
+ icon_path = Functions.set_svg_icon("icon_maximize.svg")
+ )
+
+ # CLOSE BUTTON
+ self.close_button = PyTitleButton(
+ self._parent,
+ self._app_parent,
+ tooltip_text = "Close app",
+ dark_one = self._dark_one,
+ 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_active,
+ icon_color_active = self._icon_color_active,
+ context_color = self._context_color,
+ text_foreground = self._text_foreground,
+ radius = 6,
+ 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/src/educoder/gui/widgets/py_title_bar/py_title_button.py b/src/educoder/gui/widgets/py_title_bar/py_title_button.py
new file mode 100644
index 0000000..cb48660
--- /dev/null
+++ b/src/educoder/gui/widgets/py_title_bar/py_title_button.py
@@ -0,0 +1,271 @@
+# ///////////////////////////////////////////////////////////////
+#
+# 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 src.educoder.qt_core import *
+
+# PY TITLE BUTTON
+# ///////////////////////////////////////////////////////////////
+class PyTitleButton(QPushButton):
+ def __init__(
+ self,
+ parent,
+ app_parent = None,
+ tooltip_text = "",
+ btn_id = None,
+ 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",
+ dark_one = "#1b1e23",
+ context_color = "#568af2",
+ text_foreground = "#8a95aa",
+ is_active = False
+ ):
+ super().__init__()
+
+ # SET DEFAULT PARAMETERS
+ self.setFixedSize(width, height)
+ self.setCursor(Qt.PointingHandCursor)
+ self.setObjectName(btn_id)
+
+ # 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
+ self._context_color = context_color
+ self._top_margin = self.height() + 6
+ self._is_active = is_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
+ # Parent
+ self._parent = parent
+ self._app_parent = app_parent
+
+ # TOOLTIP
+ self._tooltip_text = tooltip_text
+ self._tooltip = _ToolTip(
+ app_parent,
+ tooltip_text,
+ dark_one,
+ context_color,
+ text_foreground
+ )
+ self._tooltip.hide()
+
+ # SET ACTIVE MENU
+ # ///////////////////////////////////////////////////////////////
+ def set_active(self, is_active):
+ self._is_active = is_active
+ self.repaint()
+
+ # RETURN IF IS ACTIVE MENU
+ # ///////////////////////////////////////////////////////////////
+ def is_active(self):
+ return self._is_active
+
+ # PAINT EVENT
+ # painting the button and the icon
+ # ///////////////////////////////////////////////////////////////
+ def paintEvent(self, event):
+ # PAINTER
+ paint = QPainter()
+ paint.begin(self)
+ paint.setRenderHint(QPainter.RenderHint.Antialiasing)
+
+ if self._is_active:
+ # BRUSH
+ brush = QBrush(QColor(self._context_color))
+ else:
+ # 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)
+ if self._is_active:
+ painter.fillRect(icon.rect(), self._icon_color_active)
+ else:
+ painter.fillRect(icon.rect(), self._set_icon_color)
+ qp.drawPixmap(
+ (rect.width() - icon.width()) / 2,
+ (rect.height() - icon.height()) / 2,
+ icon
+ )
+ painter.end()
+
+ # SET ICON
+ # ///////////////////////////////////////////////////////////////
+ def set_icon(self, icon_path):
+ self._set_icon_path = icon_path
+ self.repaint()
+
+ # MOVE TOOLTIP
+ # ///////////////////////////////////////////////////////////////
+ def move_tooltip(self):
+ # GET MAIN WINDOW PARENT
+ gp = self.mapToGlobal(QPoint(0, 0))
+
+ # SET WIDGET TO GET POSTION
+ # Return absolute position of widget inside app
+ pos = self._parent.mapFromGlobal(gp)
+
+ # FORMAT POSITION
+ # Adjust tooltip position with offset
+ pos_x = (pos.x() - self._tooltip.width()) + self.width() + 5
+ pos_y = pos.y() + self._top_margin
+
+ # SET POSITION TO WIDGET
+ # Move tooltip position
+ self._tooltip.move(pos_x, pos_y)
+
+# TOOLTIP
+# ///////////////////////////////////////////////////////////////
+class _ToolTip(QLabel):
+ # TOOLTIP / LABEL StyleSheet
+ style_tooltip = """
+ QLabel {{
+ background-color: {_dark_one};
+ color: {_text_foreground};
+ padding-left: 10px;
+ padding-right: 10px;
+ border-radius: 17px;
+ border: 0px solid transparent;
+ border-right: 3px solid {_context_color};
+ font: 800 9pt "Segoe UI";
+ }}
+ """
+ def __init__(
+ self,
+ parent,
+ tooltip,
+ dark_one,
+ context_color,
+ text_foreground
+ ):
+ QLabel.__init__(self)
+
+ # LABEL SETUP
+ style = self.style_tooltip.format(
+ _dark_one = dark_one,
+ _context_color = context_color,
+ _text_foreground = text_foreground
+ )
+ self.setObjectName(u"label_tooltip")
+ self.setStyleSheet(style)
+ self.setMinimumHeight(34)
+ self.setParent(parent)
+ self.setText(tooltip)
+ self.adjustSize()
+
+ # SET DROP SHADOW
+ self.shadow = QGraphicsDropShadowEffect(self)
+ self.shadow.setBlurRadius(30)
+ self.shadow.setXOffset(0)
+ self.shadow.setYOffset(0)
+ self.shadow.setColor(QColor(0, 0, 0, 80))
+ self.setGraphicsEffect(self.shadow)
diff --git a/src/educoder/gui/widgets/py_toggle/__init__.py b/src/educoder/gui/widgets/py_toggle/__init__.py
new file mode 100644
index 0000000..1f0b5af
--- /dev/null
+++ b/src/educoder/gui/widgets/py_toggle/__init__.py
@@ -0,0 +1,19 @@
+# ///////////////////////////////////////////////////////////////
+#
+# 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
+#
+# ///////////////////////////////////////////////////////////////
+
+# PY PUSH BUTTON
+# ///////////////////////////////////////////////////////////////
+from . py_toggle import PyToggle
\ No newline at end of file
diff --git a/src/educoder/gui/widgets/py_toggle/py_toggle.py b/src/educoder/gui/widgets/py_toggle/py_toggle.py
new file mode 100644
index 0000000..12f9b1c
--- /dev/null
+++ b/src/educoder/gui/widgets/py_toggle/py_toggle.py
@@ -0,0 +1,88 @@
+# ///////////////////////////////////////////////////////////////
+#
+# 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 src.educoder.qt_core import *
+
+class PyToggle(QCheckBox):
+ def __init__(
+ self,
+ width = 50,
+ bg_color = "#777",
+ circle_color = "#DDD",
+ active_color = "#00BCFF",
+ animation_curve = QEasingCurve.OutBounce
+ ):
+ QCheckBox.__init__(self)
+ self.setFixedSize(width, 28)
+ self.setCursor(Qt.PointingHandCursor)
+
+ # COLORS
+ self._bg_color = bg_color
+ self._circle_color = circle_color
+ self._active_color = active_color
+
+ self._position = 3
+ self.animation = QPropertyAnimation(self, b"position")
+ self.animation.setEasingCurve(animation_curve)
+ self.animation.setDuration(500)
+ self.stateChanged.connect(self.setup_animation)
+
+ @Property(float)
+ def position(self):
+ return self._position
+
+ @position.setter
+ def position(self, pos):
+ self._position = pos
+ self.update()
+
+ # START STOP ANIMATION
+ def setup_animation(self, value):
+ self.animation.stop()
+ if value:
+ self.animation.setEndValue(self.width() - 26)
+ else:
+ self.animation.setEndValue(4)
+ self.animation.start()
+
+ def hitButton(self, pos: QPoint):
+ return self.contentsRect().contains(pos)
+
+ def paintEvent(self, e):
+ p = QPainter(self)
+ p.setRenderHint(QPainter.Antialiasing)
+ p.setFont(QFont("Segoe UI", 9))
+
+ # SET PEN
+ p.setPen(Qt.NoPen)
+
+ # DRAW RECT
+ rect = QRect(0, 0, self.width(), self.height())
+
+ if not self.isChecked():
+ p.setBrush(QColor(self._bg_color))
+ p.drawRoundedRect(0,0,rect.width(), 28, 14, 14)
+ p.setBrush(QColor(self._circle_color))
+ p.drawEllipse(self._position, 3, 22, 22)
+ else:
+ p.setBrush(QColor(self._active_color))
+ p.drawRoundedRect(0,0,rect.width(), 28, 14, 14)
+ p.setBrush(QColor(self._circle_color))
+ p.drawEllipse(self._position, 3, 22, 22)
+
+ p.end()
\ No newline at end of file
diff --git a/src/educoder/gui/widgets/py_window/__init__.py b/src/educoder/gui/widgets/py_window/__init__.py
new file mode 100644
index 0000000..43e8283
--- /dev/null
+++ b/src/educoder/gui/widgets/py_window/__init__.py
@@ -0,0 +1,19 @@
+# ///////////////////////////////////////////////////////////////
+#
+# 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 WIDGETS
+# ///////////////////////////////////////////////////////////////
+from . py_window import PyWindow
\ No newline at end of file
diff --git a/src/educoder/gui/widgets/py_window/py_window.py b/src/educoder/gui/widgets/py_window/py_window.py
new file mode 100644
index 0000000..3189935
--- /dev/null
+++ b/src/educoder/gui/widgets/py_window/py_window.py
@@ -0,0 +1,141 @@
+# ///////////////////////////////////////////////////////////////
+#
+# 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 QT CORE
+# ///////////////////////////////////////////////////////////////
+from src.educoder.qt_core import *
+
+# IMPORT SETTINGS
+# ///////////////////////////////////////////////////////////////
+from src.educoder.gui.core.json_settings import Settings
+# IMPORT STYLES
+# ///////////////////////////////////////////////////////////////
+from . styles import Styles
+
+# PY WINDOW
+# ///////////////////////////////////////////////////////////////
+class PyWindow(QFrame):
+ def __init__(
+ self,
+ parent,
+ layout = Qt.Vertical,
+ margin = 0,
+ spacing = 2,
+ bg_color = "#2c313c",
+ text_color = "#fff",
+ text_font = "9pt 'Segoe UI'",
+ border_radius = 10,
+ border_size = 2,
+ border_color = "#343b48",
+ enable_shadow = True
+ ):
+ super().__init__()
+
+ # LOAD SETTINGS
+ # ///////////////////////////////////////////////////////////////
+ settings = Settings()
+ self.settings = settings.items
+
+ # PROPERTIES
+ # ///////////////////////////////////////////////////////////////
+ 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
+
+ # OBJECT NAME
+ # ///////////////////////////////////////////////////////////////
+ self.setObjectName("pod_bg_app")
+
+ # APPLY STYLESHEET
+ # ///////////////////////////////////////////////////////////////
+ self.set_stylesheet()
+
+ # ADD LAYOUT
+ # ///////////////////////////////////////////////////////////////
+ if layout == Qt.Vertical:
+ # VERTICAL LAYOUT
+ self.layout = QHBoxLayout(self)
+ else:
+ # HORIZONTAL LAYOUT
+ self.layout = QHBoxLayout(self)
+ self.layout.setContentsMargins(margin, margin, margin, margin)
+ self.layout.setSpacing(spacing)
+
+ # ADD DROP SHADOW
+ # ///////////////////////////////////////////////////////////////
+ if self.settings["custom_title_bar"]:
+ if enable_shadow:
+ self.shadow = QGraphicsDropShadowEffect()
+ self.shadow.setBlurRadius(20)
+ self.shadow.setXOffset(0)
+ self.shadow.setYOffset(0)
+ self.shadow.setColor(QColor(0, 0, 0, 160))
+ 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 bg_color != 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
+ ))
+
\ No newline at end of file
diff --git a/src/educoder/gui/widgets/py_window/styles.py b/src/educoder/gui/widgets/py_window/styles.py
new file mode 100644
index 0000000..a4e74e9
--- /dev/null
+++ b/src/educoder/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
diff --git a/src/educoder/icon.ico b/src/educoder/icon.ico
new file mode 100644
index 0000000..e8a2df8
Binary files /dev/null and b/src/educoder/icon.ico differ
diff --git a/src/educoder/main.py b/src/educoder/main.py
index cb639c7..9012f11 100644
--- a/src/educoder/main.py
+++ b/src/educoder/main.py
@@ -1,18 +1,224 @@
-from PySide6.QtWidgets import *
-import sqlite3
+# ///////////////////////////////////////////////////////////////
+#
+# 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 Window:
+# IMPORT PACKAGES AND MODULES
+# ///////////////////////////////////////////////////////////////
+from gui.uis.windows.main_window.functions_main_window import *
+import sys
+import os
+
+# IMPORT QT CORE
+# ///////////////////////////////////////////////////////////////
+from qt_core import *
+
+# IMPORT SETTINGS
+# ///////////////////////////////////////////////////////////////
+from gui.core.json_settings import Settings
+
+# IMPORT PY ONE DARK WINDOWS
+# ///////////////////////////////////////////////////////////////
+# MAIN WINDOW
+from gui.uis.windows.main_window import *
+
+# IMPORT PY ONE DARK WIDGETS
+# ///////////////////////////////////////////////////////////////
+from gui.widgets import *
+
+# ADJUST QT FONT DPI FOR HIGHT SCALE AN 4K MONITOR
+# ///////////////////////////////////////////////////////////////
+os.environ["QT_FONT_DPI"] = "96"
+
+
+# IF IS 4K MONITOR ENABLE 'os.environ["QT_SCALE_FACTOR"] = "2"'
+
+# MAIN WINDOW
+# ///////////////////////////////////////////////////////////////
+class MainWindow(QMainWindow):
def __init__(self):
- # 初始化窗口
- self.win = QMainWindow()
- self.win.resize(500, 400)
- self.win.move(700, 210)
- self.win.setWindowTitle("测试窗口")
-
-if __name__ == '__main__':
- conn = sqlite3.connect('../../data/lib_manager.db')
-
- app = QApplication([])
- w = Window()
- w.win.show()
- app.exec()
\ No newline at end of file
+ super().__init__()
+
+ # SETUP MAIN WINDOw
+ # Load widgets from "gui\uis\main_window\ui_main.py"
+ # ///////////////////////////////////////////////////////////////
+ self.ui = UI_MainWindow()
+ self.ui.setup_ui(self)
+
+ # LOAD SETTINGS
+ # ///////////////////////////////////////////////////////////////
+ settings = Settings()
+ self.settings = settings.items
+
+ # SETUP MAIN WINDOW
+ # ///////////////////////////////////////////////////////////////
+ self.hide_grips = True # Show/Hide resize grips
+ SetupMainWindow.setup_gui(self)
+
+ # SHOW MAIN WINDOW
+ # ///////////////////////////////////////////////////////////////
+ self.show()
+
+ # LEFT MENU BTN IS CLICKED
+ # Run function when btn is clicked
+ # Check funtion by object name / btn_id
+ # ///////////////////////////////////////////////////////////////
+ def btn_clicked(self):
+ # GET BT CLICKED
+ btn = SetupMainWindow.setup_btns(self)
+
+ # Remove Selection If Clicked By "btn_close_left_column"
+ if btn.objectName() != "btn_settings":
+ self.ui.left_menu.deselect_all_tab()
+
+ # Get Title Bar Btn And Reset Active
+ top_settings = MainFunctions.get_title_bar_btn(self, "btn_top_settings")
+ top_settings.set_active(False)
+
+ # LEFT MENU
+ # ///////////////////////////////////////////////////////////////
+
+ # HOME BTN
+ if btn.objectName() == "btn_home":
+ # Select Menu
+ self.ui.left_menu.select_only_one(btn.objectName())
+
+ # Load Page 1
+ MainFunctions.set_page(self, self.ui.load_pages.page_1)
+
+ # WIDGETS BTN
+ if btn.objectName() == "btn_widgets":
+ # Select Menu
+ self.ui.left_menu.select_only_one(btn.objectName())
+
+ # Load Page 2
+ MainFunctions.set_page(self, self.ui.load_pages.page_2)
+
+ # LOAD USER PAGE
+ if btn.objectName() == "btn_add_user":
+ # Select Menu
+ self.ui.left_menu.select_only_one(btn.objectName())
+
+ # Load Page 3
+ MainFunctions.set_page(self, self.ui.load_pages.page_3)
+
+ # BOTTOM INFORMATION
+ if btn.objectName() == "btn_info":
+ # CHECK IF LEFT COLUMN IS VISIBLE
+ if not MainFunctions.left_column_is_visible(self):
+ self.ui.left_menu.select_only_one_tab(btn.objectName())
+
+ # Show / Hide
+ MainFunctions.toggle_left_column(self)
+ self.ui.left_menu.select_only_one_tab(btn.objectName())
+ else:
+ if btn.objectName() == "btn_close_left_column":
+ self.ui.left_menu.deselect_all_tab()
+ # Show / Hide
+ MainFunctions.toggle_left_column(self)
+
+ self.ui.left_menu.select_only_one_tab(btn.objectName())
+
+ # Change Left Column Menu
+ if btn.objectName() != "btn_close_left_column":
+ MainFunctions.set_left_column_menu(
+ self,
+ menu=self.ui.left_column.menus.menu_2,
+ title="Info tab",
+ icon_path=Functions.set_svg_icon("icon_info.svg")
+ )
+
+ # SETTINGS LEFT
+ if btn.objectName() == "btn_settings" or btn.objectName() == "btn_close_left_column":
+ # CHECK IF LEFT COLUMN IS VISIBLE
+ if not MainFunctions.left_column_is_visible(self):
+ # Show / Hide
+ MainFunctions.toggle_left_column(self)
+ self.ui.left_menu.select_only_one_tab(btn.objectName())
+ else:
+ if btn.objectName() == "btn_close_left_column":
+ self.ui.left_menu.deselect_all_tab()
+ # Show / Hide
+ MainFunctions.toggle_left_column(self)
+ self.ui.left_menu.select_only_one_tab(btn.objectName())
+
+ # Change Left Column Menu
+ if btn.objectName() != "btn_close_left_column":
+ MainFunctions.set_left_column_menu(
+ self,
+ menu=self.ui.left_column.menus.menu_1,
+ title="Settings Left Column",
+ icon_path=Functions.set_svg_icon("icon_settings.svg")
+ )
+
+ # TITLE BAR MENU
+ # ///////////////////////////////////////////////////////////////
+
+ # SETTINGS TITLE BAR
+ if btn.objectName() == "btn_top_settings":
+ # Toogle Active
+ if not MainFunctions.right_column_is_visible(self):
+ btn.set_active(True)
+
+ # Show / Hide
+ MainFunctions.toggle_right_column(self)
+ else:
+ btn.set_active(False)
+
+ # Show / Hide
+ MainFunctions.toggle_right_column(self)
+
+ # Get Left Menu Btn
+ top_settings = MainFunctions.get_left_menu_btn(self, "btn_settings")
+ top_settings.set_active_tab(False)
+
+ # DEBUG
+ print(f"Button {btn.objectName()}, clicked!")
+
+ # LEFT MENU BTN IS RELEASED
+ # Run function when btn is released
+ # Check funtion by object name / btn_id
+ # ///////////////////////////////////////////////////////////////
+ def btn_released(self):
+ # GET BT CLICKED
+ btn = SetupMainWindow.setup_btns(self)
+
+ # DEBUG
+ print(f"Button {btn.objectName()}, released!")
+
+ # RESIZE EVENT
+ # ///////////////////////////////////////////////////////////////
+ def resizeEvent(self, event):
+ SetupMainWindow.resize_grips(self)
+
+ # MOUSE CLICK EVENTS
+ # ///////////////////////////////////////////////////////////////
+ def mousePressEvent(self, event):
+ # SET DRAG POS WINDOW
+ self.dragPos = event.globalPos()
+
+
+# SETTINGS WHEN TO START
+# Set the initial class and also additional parameters of the "QApplication" class
+# ///////////////////////////////////////////////////////////////
+if __name__ == "__main__":
+ # APPLICATION
+ # ///////////////////////////////////////////////////////////////
+ app = QApplication(sys.argv)
+ app.setWindowIcon(QIcon("icon.ico"))
+ window = MainWindow()
+
+ # EXEC APP
+ # ///////////////////////////////////////////////////////////////
+ sys.exit(app.exec())
\ No newline at end of file
diff --git a/src/educoder/qt_core.py b/src/educoder/qt_core.py
new file mode 100644
index 0000000..ce99700
--- /dev/null
+++ b/src/educoder/qt_core.py
@@ -0,0 +1,4 @@
+from PySide6.QtCore import *
+from PySide6.QtGui import *
+from PySide6.QtWidgets import *
+from PySide6.QtSvgWidgets import *
\ No newline at end of file
diff --git a/src/educoder/settings.json b/src/educoder/settings.json
new file mode 100644
index 0000000..eaa0827
--- /dev/null
+++ b/src/educoder/settings.json
@@ -0,0 +1,35 @@
+{
+ "app_name": "PyOneDark - Modern GUI",
+ "version" : "v1.0.0",
+ "copyright" : "By: Wanderson M. Pimenta",
+ "year" : 2021,
+ "theme_name" : "default",
+ "custom_title_bar": true,
+ "startup_size": [
+ 1400,
+ 720
+ ],
+ "minimum_size": [
+ 960,
+ 540
+ ],
+ "lef_menu_size" : {
+ "minimum" : 50,
+ "maximum" : 240
+ },
+ "left_menu_content_margins" : 3,
+ "left_column_size" : {
+ "minimum" : 0,
+ "maximum" : 240
+ },
+ "right_column_size" : {
+ "minimum" : 0,
+ "maximum" : 240
+ },
+ "time_animation" : 500,
+ "font" : {
+ "family" : "Segoe UI",
+ "title_size" : 10,
+ "text_size" : 9
+ }
+}
\ No newline at end of file