From 42660d82962c3ccac0813487e187537f17ca5a24 Mon Sep 17 00:00:00 2001 From: Peng_Lx Date: Wed, 31 May 2023 02:18:26 +0800 Subject: [PATCH] Update --- {src/educoder/core => core}/__init__.py | 0 core/usermanager.py | 170 +++++ .../core/permission => database}/__init__.py | 0 database/database.py | 97 +++ gui/AddBook.py | 40 ++ gui/AddBookInformation.py | 64 ++ gui/AddUser.py | 40 ++ gui/BorrowBook.py | 27 + gui/LibrarySystemUI.py | 111 ++++ gui/LoginDialog.py | 44 ++ gui/RemoveBook.py | 28 + gui/RemoveBookInformation.py | 28 + gui/RemoveUser.py | 28 + gui/ReturnBook.py | 27 + data/lib_manager.db => gui/__init__.py | 0 library.db | Bin 0 -> 49152 bytes src/educoder/core/permission/permission.py | 8 - src/educoder/database/database.py | 39 -- src/educoder/database/database_sqlite.py | 10 - src/educoder/gui/core/functions.py | 50 -- src/educoder/gui/core/json_settings.py | 58 -- src/educoder/gui/core/json_themes.py | 66 -- .../gui/images/svg_icons/active_menu.svg | 79 --- .../gui/images/svg_icons/icon_add_user.svg | 61 -- .../gui/images/svg_icons/icon_arrow_left.svg | 61 -- .../gui/images/svg_icons/icon_arrow_right.svg | 61 -- .../gui/images/svg_icons/icon_attachment.svg | 78 --- .../gui/images/svg_icons/icon_busy.svg | 60 -- .../gui/images/svg_icons/icon_close.svg | 61 -- .../gui/images/svg_icons/icon_emoticons.svg | 78 --- .../gui/images/svg_icons/icon_file.svg | 63 -- .../gui/images/svg_icons/icon_folder.svg | 62 -- .../gui/images/svg_icons/icon_folder_open.svg | 63 -- .../gui/images/svg_icons/icon_heart.svg | 62 -- .../gui/images/svg_icons/icon_home.svg | 66 -- .../gui/images/svg_icons/icon_idle.svg | 60 -- .../gui/images/svg_icons/icon_info.svg | 78 --- .../gui/images/svg_icons/icon_invisible.svg | 61 -- .../gui/images/svg_icons/icon_maximize.svg | 61 -- .../gui/images/svg_icons/icon_menu.svg | 63 -- .../gui/images/svg_icons/icon_menu_close.svg | 61 -- .../gui/images/svg_icons/icon_minimize.svg | 61 -- .../images/svg_icons/icon_more_options.svg | 78 --- .../gui/images/svg_icons/icon_online.svg | 60 -- .../gui/images/svg_icons/icon_restore.svg | 60 -- .../gui/images/svg_icons/icon_save.svg | 61 -- .../gui/images/svg_icons/icon_search.svg | 60 -- .../gui/images/svg_icons/icon_send.svg | 78 --- .../gui/images/svg_icons/icon_settings.svg | 78 --- .../gui/images/svg_icons/icon_signal.svg | 78 --- .../gui/images/svg_icons/icon_widgets.svg | 101 --- src/educoder/gui/images/svg_icons/no_icon.svg | 60 -- .../gui/images/svg_images/logo_home.svg | 158 ----- .../gui/images/svg_images/logo_top_100x22.svg | 157 ----- src/educoder/gui/themes/bright_theme.json | 28 - src/educoder/gui/themes/default.json | 28 - src/educoder/gui/themes/dracula.json | 28 - src/educoder/gui/uis/columns/left_column.ui | 271 -------- src/educoder/gui/uis/columns/right_column.ui | 117 ---- .../gui/uis/columns/ui_left_column.py | 138 ---- .../gui/uis/columns/ui_right_column.py | 116 ---- src/educoder/gui/uis/pages/main_pages.ui | 298 --------- src/educoder/gui/uis/pages/ui_main_pages.py | 176 ----- .../gui/uis/windows/main_window/__init__.py | 23 - .../main_window/functions_main_window.py | 145 ----- .../windows/main_window/setup_main_window.py | 600 ------------------ .../gui/uis/windows/main_window/ui_main.py | 305 --------- src/educoder/gui/widgets/__init__.py | 71 --- .../widgets/py_circular_progress/__init__.py | 19 - .../py_circular_progress.py | 114 ---- .../gui/widgets/py_credits_bar/__init__.py | 19 - .../gui/widgets/py_credits_bar/py_credits.py | 95 --- src/educoder/gui/widgets/py_grips/__init__.py | 17 - src/educoder/gui/widgets/py_grips/py_grips.py | 249 -------- .../gui/widgets/py_icon_button/__init__.py | 19 - .../widgets/py_icon_button/py_icon_button.py | 268 -------- .../gui/widgets/py_left_column/__init__.py | 20 - .../gui/widgets/py_left_column/py_icon.py | 70 -- .../widgets/py_left_column/py_left_button.py | 271 -------- .../widgets/py_left_column/py_left_column.py | 194 ------ .../gui/widgets/py_left_menu/__init__.py | 20 - .../gui/widgets/py_left_menu/py_div.py | 34 - .../gui/widgets/py_left_menu/py_left_menu.py | 266 -------- .../py_left_menu/py_left_menu_button.py | 380 ----------- .../gui/widgets/py_line_edit/__init__.py | 19 - .../gui/widgets/py_line_edit/py_line_edit.py | 95 --- .../gui/widgets/py_push_button/__init__.py | 19 - .../widgets/py_push_button/py_push_button.py | 71 --- .../gui/widgets/py_slider/__init__.py | 19 - .../gui/widgets/py_slider/py_slider.py | 97 --- .../gui/widgets/py_table_widget/__init__.py | 19 - .../py_table_widget/py_table_widget.py | 90 --- .../gui/widgets/py_table_widget/style.py | 135 ---- .../gui/widgets/py_title_bar/__init__.py | 21 - .../gui/widgets/py_title_bar/py_div.py | 35 - .../gui/widgets/py_title_bar/py_title_bar.py | 346 ---------- .../widgets/py_title_bar/py_title_button.py | 271 -------- .../gui/widgets/py_toggle/__init__.py | 19 - .../gui/widgets/py_toggle/py_toggle.py | 88 --- .../gui/widgets/py_window/__init__.py | 19 - .../gui/widgets/py_window/py_window.py | 141 ---- src/educoder/gui/widgets/py_window/styles.py | 28 - src/educoder/icon.ico | Bin 202993 -> 0 bytes src/educoder/main.py | 224 ------- src/educoder/qt_core.py | 4 - src/educoder/settings.json | 35 - 106 files changed, 704 insertions(+), 8754 deletions(-) rename {src/educoder/core => core}/__init__.py (100%) create mode 100644 core/usermanager.py rename {src/educoder/core/permission => database}/__init__.py (100%) create mode 100644 database/database.py create mode 100644 gui/AddBook.py create mode 100644 gui/AddBookInformation.py create mode 100644 gui/AddUser.py create mode 100644 gui/BorrowBook.py create mode 100644 gui/LibrarySystemUI.py create mode 100644 gui/LoginDialog.py create mode 100644 gui/RemoveBook.py create mode 100644 gui/RemoveBookInformation.py create mode 100644 gui/RemoveUser.py create mode 100644 gui/ReturnBook.py rename data/lib_manager.db => gui/__init__.py (100%) create mode 100644 library.db delete mode 100644 src/educoder/core/permission/permission.py delete mode 100644 src/educoder/database/database.py delete mode 100644 src/educoder/database/database_sqlite.py delete mode 100644 src/educoder/gui/core/functions.py delete mode 100644 src/educoder/gui/core/json_settings.py delete mode 100644 src/educoder/gui/core/json_themes.py delete mode 100644 src/educoder/gui/images/svg_icons/active_menu.svg delete mode 100644 src/educoder/gui/images/svg_icons/icon_add_user.svg delete mode 100644 src/educoder/gui/images/svg_icons/icon_arrow_left.svg delete mode 100644 src/educoder/gui/images/svg_icons/icon_arrow_right.svg delete mode 100644 src/educoder/gui/images/svg_icons/icon_attachment.svg delete mode 100644 src/educoder/gui/images/svg_icons/icon_busy.svg delete mode 100644 src/educoder/gui/images/svg_icons/icon_close.svg delete mode 100644 src/educoder/gui/images/svg_icons/icon_emoticons.svg delete mode 100644 src/educoder/gui/images/svg_icons/icon_file.svg delete mode 100644 src/educoder/gui/images/svg_icons/icon_folder.svg delete mode 100644 src/educoder/gui/images/svg_icons/icon_folder_open.svg delete mode 100644 src/educoder/gui/images/svg_icons/icon_heart.svg delete mode 100644 src/educoder/gui/images/svg_icons/icon_home.svg delete mode 100644 src/educoder/gui/images/svg_icons/icon_idle.svg delete mode 100644 src/educoder/gui/images/svg_icons/icon_info.svg delete mode 100644 src/educoder/gui/images/svg_icons/icon_invisible.svg delete mode 100644 src/educoder/gui/images/svg_icons/icon_maximize.svg delete mode 100644 src/educoder/gui/images/svg_icons/icon_menu.svg delete mode 100644 src/educoder/gui/images/svg_icons/icon_menu_close.svg delete mode 100644 src/educoder/gui/images/svg_icons/icon_minimize.svg delete mode 100644 src/educoder/gui/images/svg_icons/icon_more_options.svg delete mode 100644 src/educoder/gui/images/svg_icons/icon_online.svg delete mode 100644 src/educoder/gui/images/svg_icons/icon_restore.svg delete mode 100644 src/educoder/gui/images/svg_icons/icon_save.svg delete mode 100644 src/educoder/gui/images/svg_icons/icon_search.svg delete mode 100644 src/educoder/gui/images/svg_icons/icon_send.svg delete mode 100644 src/educoder/gui/images/svg_icons/icon_settings.svg delete mode 100644 src/educoder/gui/images/svg_icons/icon_signal.svg delete mode 100644 src/educoder/gui/images/svg_icons/icon_widgets.svg delete mode 100644 src/educoder/gui/images/svg_icons/no_icon.svg delete mode 100644 src/educoder/gui/images/svg_images/logo_home.svg delete mode 100644 src/educoder/gui/images/svg_images/logo_top_100x22.svg delete mode 100644 src/educoder/gui/themes/bright_theme.json delete mode 100644 src/educoder/gui/themes/default.json delete mode 100644 src/educoder/gui/themes/dracula.json delete mode 100644 src/educoder/gui/uis/columns/left_column.ui delete mode 100644 src/educoder/gui/uis/columns/right_column.ui delete mode 100644 src/educoder/gui/uis/columns/ui_left_column.py delete mode 100644 src/educoder/gui/uis/columns/ui_right_column.py delete mode 100644 src/educoder/gui/uis/pages/main_pages.ui delete mode 100644 src/educoder/gui/uis/pages/ui_main_pages.py delete mode 100644 src/educoder/gui/uis/windows/main_window/__init__.py delete mode 100644 src/educoder/gui/uis/windows/main_window/functions_main_window.py delete mode 100644 src/educoder/gui/uis/windows/main_window/setup_main_window.py delete mode 100644 src/educoder/gui/uis/windows/main_window/ui_main.py delete mode 100644 src/educoder/gui/widgets/__init__.py delete mode 100644 src/educoder/gui/widgets/py_circular_progress/__init__.py delete mode 100644 src/educoder/gui/widgets/py_circular_progress/py_circular_progress.py delete mode 100644 src/educoder/gui/widgets/py_credits_bar/__init__.py delete mode 100644 src/educoder/gui/widgets/py_credits_bar/py_credits.py delete mode 100644 src/educoder/gui/widgets/py_grips/__init__.py delete mode 100644 src/educoder/gui/widgets/py_grips/py_grips.py delete mode 100644 src/educoder/gui/widgets/py_icon_button/__init__.py delete mode 100644 src/educoder/gui/widgets/py_icon_button/py_icon_button.py delete mode 100644 src/educoder/gui/widgets/py_left_column/__init__.py delete mode 100644 src/educoder/gui/widgets/py_left_column/py_icon.py delete mode 100644 src/educoder/gui/widgets/py_left_column/py_left_button.py delete mode 100644 src/educoder/gui/widgets/py_left_column/py_left_column.py delete mode 100644 src/educoder/gui/widgets/py_left_menu/__init__.py delete mode 100644 src/educoder/gui/widgets/py_left_menu/py_div.py delete mode 100644 src/educoder/gui/widgets/py_left_menu/py_left_menu.py delete mode 100644 src/educoder/gui/widgets/py_left_menu/py_left_menu_button.py delete mode 100644 src/educoder/gui/widgets/py_line_edit/__init__.py delete mode 100644 src/educoder/gui/widgets/py_line_edit/py_line_edit.py delete mode 100644 src/educoder/gui/widgets/py_push_button/__init__.py delete mode 100644 src/educoder/gui/widgets/py_push_button/py_push_button.py delete mode 100644 src/educoder/gui/widgets/py_slider/__init__.py delete mode 100644 src/educoder/gui/widgets/py_slider/py_slider.py delete mode 100644 src/educoder/gui/widgets/py_table_widget/__init__.py delete mode 100644 src/educoder/gui/widgets/py_table_widget/py_table_widget.py delete mode 100644 src/educoder/gui/widgets/py_table_widget/style.py delete mode 100644 src/educoder/gui/widgets/py_title_bar/__init__.py delete mode 100644 src/educoder/gui/widgets/py_title_bar/py_div.py delete mode 100644 src/educoder/gui/widgets/py_title_bar/py_title_bar.py delete mode 100644 src/educoder/gui/widgets/py_title_bar/py_title_button.py delete mode 100644 src/educoder/gui/widgets/py_toggle/__init__.py delete mode 100644 src/educoder/gui/widgets/py_toggle/py_toggle.py delete mode 100644 src/educoder/gui/widgets/py_window/__init__.py delete mode 100644 src/educoder/gui/widgets/py_window/py_window.py delete mode 100644 src/educoder/gui/widgets/py_window/styles.py delete mode 100644 src/educoder/icon.ico delete mode 100644 src/educoder/main.py delete mode 100644 src/educoder/qt_core.py delete mode 100644 src/educoder/settings.json diff --git a/src/educoder/core/__init__.py b/core/__init__.py similarity index 100% rename from src/educoder/core/__init__.py rename to core/__init__.py diff --git a/core/usermanager.py b/core/usermanager.py new file mode 100644 index 0000000..92dee01 --- /dev/null +++ b/core/usermanager.py @@ -0,0 +1,170 @@ +import hashlib + +class UserManager: + def __init__(self, db_connection): + self.db_connection = db_connection + self.logged_in_user = None + self.create_default_admin() + + def create_default_admin(self): + cur = self.db_connection.cursor() + cur.execute('SELECT * FROM Account WHERE userID="admin"') + admin_account = cur.fetchone() + if not admin_account: + default_password = "admin" # 默认密码是admin,实际情况下应该设置更复杂的密码 + passwordHash = hashlib.sha256(default_password.encode()).hexdigest() # 使用SHA-256算法对密码进行哈希 + cur.execute('INSERT INTO Account(userID, passwordHash, permission) VALUES(?, ?, ?)', + ("admin", passwordHash, "Admin")) + self.db_connection.commit() + + def login(self, userID, password): + cur = self.db_connection.cursor() + passwordHash = hashlib.sha256(password.encode()).hexdigest() + cur.execute('SELECT * FROM Account WHERE userID=? AND passwordHash=?', (userID, passwordHash)) + user = cur.fetchone() + if user: + self.logged_in_user = user + print("Login successful") + return True + else: + print("Login failed") + return False + + def logout(self): + self.logged_in_user = None + + def add_user(self, userID, password, permission): + if self.logged_in_user and self.logged_in_user[2] == 'Admin': + cur = self.db_connection.cursor() + passwordHash = hashlib.sha256(password.encode()).hexdigest() + cur.execute('INSERT INTO Account(userID, passwordHash, permission) VALUES(?, ?, ?)', (userID, passwordHash, permission)) + self.db_connection.commit() + else: + print("Permission denied") + + def add_book_info(self,ISBN, author, summary, price, publicationDate, category): + if self.logged_in_user and self.logged_in_user[2] == 'Admin': # 检查当前登录的用户是否有Admin权限 + cur = self.db_connection.cursor() + cur.execute(''' + INSERT INTO BookInfo(ISBN, author, summary, price, publicationDate, category) VALUES(?, ?, ?, ?, ?, ?) + ''', (ISBN, author, summary, price, publicationDate, category)) + self.db_connection.commit() + else: + print("Only Admin can add books.") + + def add_book(self, bookId, ISBN, location): + if self.logged_in_user and self.logged_in_user[2] == 'Admin': # 检查当前登录的用户是否有Admin权限 + cur = self.db_connection.cursor() + cur.execute('''INSERT INTO MainBook(bookID, ISBN, borrowStatus) VALUES(?, ?, 'borrowed')''', bookId, ISBN) + cur.execute('''INSERT INTO BookLocation(bookID, location) VALUES(?, ?)''', bookId, location) + self.db_connection.commit() + else: + print("Only Admin can add books.") + + def delete_book(self, bookID): + if self.logged_in_user and self.logged_in_user[2] == 'Admin': # 检查当前登录的用户是否有Admin权限 + cur = self.db_connection.cursor() + cur.execute('DELETE FROM MainBook WHERE bookID=?', (bookID,)) + cur.execute('DELETE FROM BookLocation WHERE bookID=?', (bookID,)) + cur.execute('DELETE FROM BorrowRecord WHERE bookID=?', (bookID,)) + cur.execute('DELETE FROM BookInfo WHERE ISBN=(SELECT ISBN FROM MainBook WHERE bookID=?)', (bookID,)) + self.db_connection.commit() + else: + print("Only Admin can delete books.") + + def change_book_location(self, bookID, new_location): + if self.logged_in_user and self.logged_in_user[2] == 'Admin': # 检查当前登录的用户是否有Admin权限 + cur = self.db_connection.cursor() + cur.execute('UPDATE BookLocation SET location=? WHERE bookID=?', (new_location, bookID)) + self.db_connection.commit() + else: + print("Only Admin can change book location.") + + def check_borrower(self, bookID): + if self.logged_in_user and self.logged_in_user[2] == 'Admin': # 检查当前登录的用户是否有Admin权限 + cur = self.db_connection.cursor() + cur.execute('SELECT borrowingUser FROM BorrowRecord WHERE bookID=? AND actualReturnTime IS NULL', (bookID,)) + borrower = cur.fetchone() + if borrower: + print(f"The book {bookID} is currently borrowed by {borrower[0]}") + else: + print(f"The book {bookID} is currently not borrowed.") + else: + print("Only Admin can check borrower.") + + def check_borrow_record(self, bookID): + if self.logged_in_user and self.logged_in_user[2] == 'Admin': # 检查当前登录的用户是否有Admin权限 + cur = self.db_connection.cursor() + cur.execute('SELECT * FROM BorrowRecord WHERE bookID=?', (bookID,)) + records = cur.fetchall() + for record in records: + print(record) + else: + print("Only Admin can check borrow record.") + + def change_user_permission(self, userID, new_permission): + if self.logged_in_user and self.logged_in_user[2] == 'Admin': # 检查当前登录的用户是否有Admin权限 + cur = self.db_connection.cursor() + cur.execute('UPDATE Account SET permission=? WHERE userID=?', (new_permission, userID)) + self.db_connection.commit() + else: + print("Only Admin can change user permission.") + + def borrow_book(self, bookID, expectedReturnTime): + if self.logged_in_user and self.logged_in_user[2] == 'User': # 检查当前登录的用户是否有User权限 + cur = self.db_connection.cursor() + # 检查该图书是否可用 + cur.execute('SELECT borrowStatus FROM MainBook WHERE bookID=?', (bookID,)) + borrowStatus = cur.fetchone()[0] + if borrowStatus == 'available': + # 更新图书的借阅状态 + cur.execute('UPDATE MainBook SET borrowStatus=? WHERE bookID=?', ('borrowed', bookID)) + # 添加一条新的借阅记录 + cur.execute(''' + INSERT INTO BorrowRecord(bookID, borrowTime, expectedReturnTime, borrowingUser) + VALUES(?, datetime("now"), ?, ?) + ''', (bookID, expectedReturnTime, self.logged_in_user[0])) + self.db_connection.commit() + print("You have successfully borrowed the book.") + else: + print("The book is currently not available.") + else: + print("Only User can borrow books.") + + def return_book(self, bookID): + if self.logged_in_user and self.logged_in_user[2] == 'User': # 检查当前登录的用户是否有User权限 + cur = self.db_connection.cursor() + # 检查该用户是否真的借阅了这本图书 + cur.execute('SELECT * FROM BorrowRecord WHERE bookID=? AND borrowingUser=? AND actualReturnTime IS NULL', + (bookID, self.logged_in_user[0])) + if cur.fetchone(): + # 更新图书的借阅状态 + cur.execute('UPDATE MainBook SET borrowStatus=? WHERE bookID=?', ('available', bookID)) + # 更新借阅记录中的实际归还时间 + cur.execute( + 'UPDATE BorrowRecord SET actualReturnTime=datetime("now") WHERE bookID=? AND borrowingUser=? AND actualReturnTime IS NULL', + (bookID, self.logged_in_user[0])) + self.db_connection.commit() + print("You have successfully returned the book.") + else: + print("You didn't borrow this book.") + else: + print("Only User can return books.") + + def find_book(self, bookID): + # 检查用户是否有权限查找书籍 + if self.logged_in_user and self.logged_in_user[2] in ['Admin', 'User']: + # 在数据库中查找书籍 + cur = self.db_connection.cursor() + cur.execute(''' + SELECT * FROM MainBook WHERE bookID = ? + ''', (bookID,)) + book = cur.fetchone() + if book is not None: + return book + else: + print("Book not found.") + return None + else: + print("Permission Denied: You do not have the required permissions to find books.") + return None \ No newline at end of file diff --git a/src/educoder/core/permission/__init__.py b/database/__init__.py similarity index 100% rename from src/educoder/core/permission/__init__.py rename to database/__init__.py diff --git a/database/database.py b/database/database.py new file mode 100644 index 0000000..47e4a6a --- /dev/null +++ b/database/database.py @@ -0,0 +1,97 @@ + + +class Database: + def __init__(self, db_connection): + self.db_connection = db_connection + + def init(self): + cur = self.db_connection.cursor() + tables = [ + ("Account", ''' + CREATE TABLE Account( + userID TEXT PRIMARY KEY, + passwordHash TEXT, + permission TEXT CHECK(permission IN ('Admin', 'User', 'Ban')) + ) + '''), + + ("MainBook", ''' + CREATE TABLE MainBook( + bookID TEXT PRIMARY KEY, + ISBN TEXT, + borrowStatus TEXT CHECK(borrowStatus IN ('borrowed', 'available')) + ) + '''), + + ("BookLocation", ''' + CREATE TABLE BookLocation( + bookID TEXT PRIMARY KEY, + location TEXT + ) + '''), + + ("BorrowRecord", ''' + CREATE TABLE BorrowRecord( + bookID TEXT, + borrowTime TEXT, + actualReturnTime TEXT, + expectedReturnTime TEXT, + borrowingUser TEXT + ) + '''), + + ("BookInfo", ''' + CREATE TABLE BookInfo( + ISBN TEXT PRIMARY KEY, + author TEXT, + summary TEXT, + price REAL, + publicationDate TEXT, + category TEXT + ) + '''), + + ("BookCategory", ''' + CREATE TABLE BookCategory( + category TEXT PRIMARY KEY + ) + ''') + ] + + # 创建表,只有当表不存在时才创建 + for table_name, table_query in tables: + cur.execute(f"SELECT name FROM sqlite_master WHERE type='table' AND name='{table_name}'") + if not cur.fetchone(): + cur.execute(table_query) + + # 添加默认的图书类别 + categories = [ + '马克思主义、列宁主义、毛泽东思想、邓小平理论', + '哲学、宗教', + '社会科学总论', + '政治、法律', + '军事', + '经济', + '文化、科学、教育、体育', + '语言、文字', + '文学', + '艺术', + '历史、地理', + '自然科学总论', + '数理科学和化学', + '天文学、地球科学', + '生物科学', + '医学、卫生', + '农业科学', + '工业科学', + '交通运输', + '航空、航天', + '环境科学、劳动保护科学(安全科学)', + '综合性图书' + ] + + for category in categories: + cur.execute('SELECT * FROM BookCategory WHERE category="category"') + print(category) + if not cur.fetchone(): + cur.execute('INSERT INTO BookCategory(category) VALUES(?)', (category,)) diff --git a/gui/AddBook.py b/gui/AddBook.py new file mode 100644 index 0000000..a2e961f --- /dev/null +++ b/gui/AddBook.py @@ -0,0 +1,40 @@ +from PySide6.QtWidgets import QDialog, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QPushButton + +from core.usermanager import UserManager + + +class AddBook(QDialog): + def __init__(self, user_manager: UserManager): + super().__init__() + self.user_manager = user_manager + + self.layout = QVBoxLayout() + + self.setWindowTitle("添加图书") + + self.isbn = QHBoxLayout() + self.isbn.addWidget(QLabel("ISBN")) + self.isbn_line_edit = QLineEdit() + self.isbn.addWidget(self.isbn_line_edit) + self.layout.addLayout(self.isbn) + + self.book_id = QHBoxLayout() + self.book_id.addWidget(QLabel("BookID")) + self.book_id_line_edit = QLineEdit() + self.book_id.addWidget(self.book_id_line_edit) + self.layout.addLayout(self.book_id) + + self.location = QHBoxLayout() + self.location.addWidget(QLabel("图书位置")) + self.location_line_edit = QLineEdit() + self.location.addWidget(self.location_line_edit) + self.layout.addLayout(self.location) + + self.add_button = QPushButton("添加图书") + self.add_button.clicked.connect(self.add) + self.layout.addWidget(self.add_button) + + self.setLayout(self.layout) + + def add(self): + self.user_manager.add_book(self.book_id_line_edit.text(), self.isbn_line_edit.text(), self.location_line_edit.text()) \ No newline at end of file diff --git a/gui/AddBookInformation.py b/gui/AddBookInformation.py new file mode 100644 index 0000000..c81f4ab --- /dev/null +++ b/gui/AddBookInformation.py @@ -0,0 +1,64 @@ +from PySide6.QtCore import QRegularExpression +from PySide6.QtGui import QRegularExpressionValidator +from PySide6.QtWidgets import QDialog, QVBoxLayout, QLineEdit, QHBoxLayout, QLabel, QPushButton + +from core.usermanager import UserManager + + +class AddBookInformation(QDialog): + def __init__(self, user_manager: UserManager): + super().__init__() + self.user_manager = user_manager + + self.layout = QVBoxLayout() + + self.setWindowTitle("添加图书信息") + + self.isbn = QHBoxLayout() + self.isbn.addWidget(QLabel("ISBN")) + self.isbn_line_edit = QLineEdit() + self.isbn.addWidget(self.isbn_line_edit) + self.layout.addLayout(self.isbn) + + self.author_line_edit = QLineEdit() + self.author = QHBoxLayout() + self.author.addWidget(QLabel("作者")) + self.author.addWidget(self.author_line_edit) + self.layout.addLayout(self.author) + + self.summary_line_edit = QLineEdit() + self.summary = QHBoxLayout() + self.summary.addWidget(QLabel("书名")) + self.summary.addWidget(self.summary_line_edit) + self.layout.addLayout(self.summary) + + self.price_line_edit = QLineEdit() + reg = QRegularExpression('^[1-9]\d*\.\d+$|^0\.\d+$|^[1-9]\d*$|^0$') + validator = QRegularExpressionValidator(self) + validator.setRegularExpression(reg) + self.price_line_edit.setValidator(validator) + self.price = QHBoxLayout() + self.price.addWidget(QLabel("价格")) + self.price.addWidget(self.price_line_edit) + self.layout.addLayout(self.price) + + self.date_line_edit = QLineEdit() + self.date = QHBoxLayout() + self.date.addWidget(QLabel("成书日期")) + self.date.addWidget(self.date_line_edit) + self.layout.addLayout(self.date) + + self.category_line_edit = QLineEdit() + self.category = QHBoxLayout() + self.category.addWidget(QLabel("分类")) + self.category.addWidget(self.category_line_edit) + self.layout.addLayout(self.category) + + self.add_button = QPushButton("添加图书") + self.add_button.clicked.connect(self.add) + self.layout.addWidget(self.add_button) + + self.setLayout(self.layout) + + def add(self): + self.user_manager.add_book_info(self.isbn_line_edit.text(), self.author_line_edit.text(), self.summary_line_edit.text(), self.price_line_edit.text(), self.date_line_edit.text(), self.category_line_edit.text()) \ No newline at end of file diff --git a/gui/AddUser.py b/gui/AddUser.py new file mode 100644 index 0000000..539d533 --- /dev/null +++ b/gui/AddUser.py @@ -0,0 +1,40 @@ +from PySide6.QtWidgets import QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QDialog, QPushButton + +from core.usermanager import UserManager + + +class AddUser(QDialog): + def __init__(self, user_manager: UserManager): + super().__init__() + self.user_manager = user_manager + + self.layout = QVBoxLayout() + + self.setWindowTitle("添加用户") + + self.user = QHBoxLayout() + self.user.addWidget(QLabel("账户")) + self.user_line_edit = QLineEdit() + self.user.addWidget(self.user_line_edit) + self.layout.addLayout(self.user) + + self.password_line_edit = QLineEdit() + self.password = QHBoxLayout() + self.password.addWidget(QLabel("密码")) + self.password.addWidget(self.password_line_edit) + self.layout.addLayout(self.password) + + self.permission_line_edit = QLineEdit() + self.permission = QHBoxLayout() + self.permission.addWidget(QLabel("权限")) + self.permission.addWidget(self.permission_line_edit) + self.layout.addLayout(self.permission) + + self.add_button = QPushButton("添加用户") + self.add_button.clicked.connect(self.add) + self.layout.addWidget(self.add_button) + + self.setLayout(self.layout) + + def add(self): + self.user_manager.add_user(self.user_line_edit.text(), self.password_line_edit.text(), self.permission_line_edit.text()) diff --git a/gui/BorrowBook.py b/gui/BorrowBook.py new file mode 100644 index 0000000..8edfbb5 --- /dev/null +++ b/gui/BorrowBook.py @@ -0,0 +1,27 @@ +from PySide6.QtWidgets import QDialog, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QPushButton + + +class BorrowBook(QDialog): + def __init__(self, user_manager): + super().__init__() + + self.user_manager = user_manager + + self.layout = QVBoxLayout() + + self.setWindowTitle("借阅图书") + + self.book_id = QHBoxLayout() + self.book_id.addWidget(QLabel("BookID")) + self.book_id_line_edit = QLineEdit() + self.book_id.addWidget(self.book_id_line_edit) + self.layout.addLayout(self.book_id) + + self.borrow_button = QPushButton("借阅") + self.borrow_button.clicked.connect(self.borrow) + self.layout.addWidget(self.borrow_button) + + self.setLayout(self.layout) + + def borrow(self): + pass \ No newline at end of file diff --git a/gui/LibrarySystemUI.py b/gui/LibrarySystemUI.py new file mode 100644 index 0000000..c009aa3 --- /dev/null +++ b/gui/LibrarySystemUI.py @@ -0,0 +1,111 @@ +from PySide6.QtGui import QPixmap, QAction +from PySide6.QtWidgets import QApplication, QMainWindow, QPushButton, QVBoxLayout, QWidget, QLabel, QLineEdit, \ + QGridLayout, QGroupBox, QMessageBox, QListView, QAbstractItemView, QListWidgetItem, QHBoxLayout, QToolBar, \ + QStatusBar, QTableView, QMenuBar, QMenu +from PySide6.QtCore import Qt + +from core.usermanager import UserManager +from gui.AddBook import AddBook +from gui.AddBookInformation import AddBookInformation +from gui.AddUser import AddUser +from gui.BorrowBook import BorrowBook +from gui.RemoveBook import RemoveBook +from gui.RemoveBookInformation import RemoveBookInformation +from gui.RemoveUser import RemoveUser +from gui.ReturnBook import ReturnBook + + +class LibrarySystemUI(QMainWindow): + def __init__(self, user_manager: UserManager): + super().__init__() + + self.user_manager = user_manager + + self.setWindowTitle("图书信息管理系统") + + self.tool_bar = QToolBar(self) + self.addToolBar(Qt.TopToolBarArea, self.tool_bar) + if user_manager.logged_in_user[2] == "Admin": + # 创建工具栏 + self.add_info_action = QAction("添加图书信息", self) + self.tool_bar.addAction(self.add_info_action) + + self.delete_info_action = QAction("删除图书信息", self) + self.tool_bar.addAction(self.delete_info_action) + + self.add_action = QAction("添加图书", self) + self.tool_bar.addAction(self.add_action) + + self.delete_action = QAction("删除图书", self) + self.tool_bar.addAction(self.delete_action) + + self.add_user_action = QAction("添加用户", self) + self.tool_bar.addAction(self.add_user_action) + + self.delete_user_action = QAction("移除用户", self) + self.tool_bar.addAction(self.delete_user_action) + + self.book_status_action = QAction("查询图书状态", self) + self.tool_bar.addAction(self.book_status_action) + + # 连接动作 + self.add_info_action.triggered.connect(self.add_info_book) + self.delete_info_action.triggered.connect(self.delete_info_book) + self.add_action.triggered.connect(self.add_book) + self.delete_action.triggered.connect(self.remove_book) + self.add_user_action.triggered.connect(self.add_user) + self.delete_user_action.triggered.connect(self.delete_user) + self.book_status_action.triggered.connect(self.book_status) + else: + self.borrow_action = QAction("借阅图书", self) + self.tool_bar.addAction(self.borrow_action) + + self.return_action = QAction("归还图书", self) + self.tool_bar.addAction(self.return_action) + + #链接动作 + self.borrow_action.triggered.connect(self.borrow_book) + self.return_action.triggered.connect(self.return_book) + + # 创建状态栏 + self.status_bar = QStatusBar(self) + self.setStatusBar(self.status_bar) + + # 创建中心区域 + self.table_view = QTableView(self) + self.setCentralWidget(self.table_view) + + def add_info_book(self): + self.add_book_information = AddBookInformation(self.user_manager) + self.add_book_information.show() + + def delete_info_book(self): + self.remove_book_information = RemoveBookInformation(self.user_manager) + self.remove_book_information.show() + + def add_book(self): + self.add_book = AddBook(self.user_manager) + self.add_book.show() + + def remove_book(self): + self.remove_book = RemoveBook(self.user_manager) + self.remove_book.show() + + def add_user(self): + self.addUser = AddUser(self.user_manager) + self.addUser.show() + + def delete_user(self): + self.removeUser = RemoveUser(self.user_manager) + self.removeUser.show() + + def borrow_book(self): + self.borrow_book = BorrowBook(self.user_manager) + self.borrow_book.show() + + def return_book(self): + self.return_book = ReturnBook(self.user_manager) + self.return_book.show() + + def book_status(self): + pass \ No newline at end of file diff --git a/gui/LoginDialog.py b/gui/LoginDialog.py new file mode 100644 index 0000000..4411ad8 --- /dev/null +++ b/gui/LoginDialog.py @@ -0,0 +1,44 @@ +from PySide6.QtWidgets import QApplication, QDialog, QVBoxLayout, QLabel, QLineEdit, QPushButton, QHBoxLayout, QTextEdit + +from gui.LibrarySystemUI import LibrarySystemUI + + +class LoginDialog(QDialog): + def __init__(self, user_manager): + super().__init__() + + self.user_manager = user_manager + + self.layout = QVBoxLayout() + + self.setWindowTitle("请登录") + + self.label = QLabel("请输入您的用户名称和密码") + self.layout.addWidget(self.label) + + self.userID_line_edit = QLineEdit() + self.userID = QHBoxLayout() + self.userID.addWidget(QLabel("账户")) + self.userID.addWidget(self.userID_line_edit) + self.layout.addLayout(self.userID) + + self.password_line_edit = QLineEdit() + self.password = QHBoxLayout() + self.password.addWidget(QLabel("密码")) + self.password.addWidget(self.password_line_edit) + self.layout.addLayout(self.password) + + self.login_button = QPushButton("登录") + self.login_button.clicked.connect(self.login) + self.layout.addWidget(self.login_button) + + self.setLayout(self.layout) + + def login(self): + userID = self.userID_line_edit.text() + password = self.password_line_edit.text() + login = self.user_manager.login(userID, password) + if login: + self.hide() + self.lsu = LibrarySystemUI(self.user_manager) + self.lsu.show() \ No newline at end of file diff --git a/gui/RemoveBook.py b/gui/RemoveBook.py new file mode 100644 index 0000000..254d6c7 --- /dev/null +++ b/gui/RemoveBook.py @@ -0,0 +1,28 @@ +from PySide6.QtWidgets import QDialog, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QPushButton + +from core.usermanager import UserManager + + +class RemoveBook(QDialog): + def __init__(self, user_manager: UserManager): + super().__init__() + self.user_manager = user_manager + + self.layout = QVBoxLayout() + + self.setWindowTitle("移除图书") + + self.book_id = QHBoxLayout() + self.book_id.addWidget(QLabel("BookID")) + self.book_id_line_edit = QLineEdit() + self.book_id.addWidget(self.book_id_line_edit) + self.layout.addLayout(self.book_id) + + self.remove_button = QPushButton("移除图书") + self.remove_button.clicked.connect(self.remove) + self.layout.addWidget(self.remove_button) + + self.setLayout(self.layout) + + def remove(self): + pass diff --git a/gui/RemoveBookInformation.py b/gui/RemoveBookInformation.py new file mode 100644 index 0000000..bc0ceec --- /dev/null +++ b/gui/RemoveBookInformation.py @@ -0,0 +1,28 @@ +from PySide6.QtWidgets import QDialog, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QPushButton + +from core.usermanager import UserManager + + +class RemoveBookInformation(QDialog): + def __init__(self, user_manager: UserManager): + super().__init__() + self.user_manager = user_manager + + self.layout = QVBoxLayout() + + self.setWindowTitle("移除图书信息") + + self.isbn = QHBoxLayout() + self.isbn.addWidget(QLabel("ISBN")) + self.isbn_line_edit = QLineEdit() + self.isbn.addWidget(self.isbn_line_edit) + self.layout.addLayout(self.isbn) + + self.remove_button = QPushButton("移除图书") + self.remove_button.clicked.connect(self.remove) + self.layout.addWidget(self.remove_button) + + self.setLayout(self.layout) + + def remove(self): + pass \ No newline at end of file diff --git a/gui/RemoveUser.py b/gui/RemoveUser.py new file mode 100644 index 0000000..2c57c54 --- /dev/null +++ b/gui/RemoveUser.py @@ -0,0 +1,28 @@ +from PySide6.QtWidgets import QDialog, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QPushButton + +from core.usermanager import UserManager + + +class RemoveUser(QDialog): + def __init__(self, user_manager: UserManager): + super().__init__() + self.user_manager = user_manager + + self.layout = QVBoxLayout() + + self.setWindowTitle("移除用户") + + self.user = QHBoxLayout() + self.user.addWidget(QLabel("账户")) + self.user_line_edit = QLineEdit() + self.user.addWidget(self.user_line_edit) + self.layout.addLayout(self.user) + + self.remove_button = QPushButton("移除用户") + self.remove_button.clicked.connect(self.remove) + self.layout.addWidget(self.remove_button) + + self.setLayout(self.layout) + + def remove(self): + pass \ No newline at end of file diff --git a/gui/ReturnBook.py b/gui/ReturnBook.py new file mode 100644 index 0000000..0397ed0 --- /dev/null +++ b/gui/ReturnBook.py @@ -0,0 +1,27 @@ +from PySide6.QtWidgets import QDialog, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QPushButton + + +class ReturnBook(QDialog): + def __init__(self, user_manager): + super().__init__() + + self.user_manager = user_manager + + self.layout = QVBoxLayout() + + self.setWindowTitle("归还图书") + + self.book_id = QHBoxLayout() + self.book_id.addWidget(QLabel("BookID")) + self.book_id_line_edit = QLineEdit() + self.book_id.addWidget(self.book_id_line_edit) + self.layout.addLayout(self.book_id) + + self.return_button = QPushButton("归还") + self.return_button.clicked.connect(self.return_book) + self.layout.addWidget(self.return_button) + + self.setLayout(self.layout) + + def return_book(self): + pass \ No newline at end of file diff --git a/data/lib_manager.db b/gui/__init__.py similarity index 100% rename from data/lib_manager.db rename to gui/__init__.py diff --git a/library.db b/library.db new file mode 100644 index 0000000000000000000000000000000000000000..6165af9d237cc61fd41bd2ac1d3410ac3c245321 GIT binary patch literal 49152 zcmeI)&2QUe90zbaX`3c#7J7gvs>&>(s;#uLIC0|SM%o3fwA&yJf*l}w>^QAO5(md& z-HEv!h=~I)Lqgi%!UZA0hSbZt2_YeI-~fLD7n+tzoPi^c?W9eYG%YWh)bO>E`0?Y% zFTc<8JXY){%F+vqs-bX2O)nFJi!qNeEXzE@aSX%w>3f8}ThlO2473*LoNY@Vmh>}E zzw}(dmt*|iTg<7SgFghmJN4DbcHoBpNAE4)m{0eAbl9fIhX4d1009U<00RFvfj51g z(8L65rVS#Mlvz!CZH^eqvZh~cPy6SxnRG70<?2Zw~)EqQF>bR4}}&cSVpZBl-1hnCHg%vPwIwdFX!72mFL@+M*QD1Plm?F+3T-6Iy)dior-vUR-e1$5S+XkbT#tApd*?Z|+$(4z8+B63Dn?ze z98pwRttzsi6pmHcIk;L`ezB%F72GLma)UO^ntQL!Eox3xS*@~_9(o97f6b9F?OmyR z^C&eBXghYEqBwL^Z)=^UQ}L}OkGbNu`_uYUc5D}jTCrkk%?A#|)XM!2;@Rtb-NSXN zWyv5$y=I5Z&7IH8EleHApTEdWO*%PBVe$+&N!}o8$-3T6PEU6logL`aFJqN}7H(P^rRURG;0 zdbMchY0I^7(uJ~Gv1F{)ZOvy%rK`=1YbcZ+JM5y-j4sbN6K;C7urC<_ns5bQWrBC< z2POzW00Izz00bZa0SG_<0uX=z1pa}*CD&ls3_M;{D$Au+QAx>BQ4(S#l9Ce&Po$JY zVu`3MNkt_dC2>)Ri6Si(m*TuE#NvXGip7%=NfL^JSV&n<04}kEAu|vn)>DC`oJffY zg_aihh``6Cf|80PrGijU6h2-kN_;{jDLE;|in1U{Ns{D?iDHyUf{-LBK50K%@X@GT z!QYtRAM^tg1Rwwb2tWV=5P$##AOHafKmYcW+;Be7o-6iAJKrOmrp|+4=l~#^wX-_y270cZR;a zCn7|gBm^J;0SG_<0uX=z1Rwwb2tWV=#}x3o!(QhRfiwQU$pkl#xhaZ400Izz00bZa z0SG_<0uX=z1R(I}1Tw7K9Nqom%f?&pZeRO!>)wN{%^Sa5GaK)G+_+=zEpFevy}j|x z*1bizfk|9=4)b8eLY literal 0 HcmV?d00001 diff --git a/src/educoder/core/permission/permission.py b/src/educoder/core/permission/permission.py deleted file mode 100644 index 3cc0510..0000000 --- a/src/educoder/core/permission/permission.py +++ /dev/null @@ -1,8 +0,0 @@ -from enum import Enum, unique - - -@unique -class Permission(Enum): - NONE = 0 - USER = 1 - ADMIN = 2 diff --git a/src/educoder/database/database.py b/src/educoder/database/database.py deleted file mode 100644 index ee1aff6..0000000 --- a/src/educoder/database/database.py +++ /dev/null @@ -1,39 +0,0 @@ -from src.educoder.core.permission.permission import Permission - - -class Database(object): - def addBook(self, unique_id, isbn, state): - pass - - def removeBook(self, unique_id): - pass - - def addUser(self, user_id, userpass_word, permission: Permission, nick_name): - pass - - def modifyUserPermission(self, user_id, permission: Permission): - pass - - def removeUser(self, unique_id): - pass - - def addBookInformation(self, isbn, author, description, price, made_time, image, category): - pass - - def removeBookInformation(self, isbn): - pass - - def brownBook(self, unique_id, brownuser): - pass - - def stillBook(self, unique_id): - pass - - def addCategory(self, category): - pass - - def removeCategory(self, category): - pass - - def login(self, user_id, password): - return True diff --git a/src/educoder/database/database_sqlite.py b/src/educoder/database/database_sqlite.py deleted file mode 100644 index 231b093..0000000 --- a/src/educoder/database/database_sqlite.py +++ /dev/null @@ -1,10 +0,0 @@ -import database -import sqlite3 - - -class DatabaseSQLite(database.Database): - conn = sqlite3.connect - - def connection(self): - self.conn = sqlite3.connect("../../../data/lib_manager.db") - diff --git a/src/educoder/gui/core/functions.py b/src/educoder/gui/core/functions.py deleted file mode 100644 index 5705a53..0000000 --- a/src/educoder/gui/core/functions.py +++ /dev/null @@ -1,50 +0,0 @@ -# /////////////////////////////////////////////////////////////// -# -# 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 deleted file mode 100644 index d54f6cd..0000000 --- a/src/educoder/gui/core/json_settings.py +++ /dev/null @@ -1,58 +0,0 @@ -# /////////////////////////////////////////////////////////////// -# -# 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 deleted file mode 100644 index f3044ca..0000000 --- a/src/educoder/gui/core/json_themes.py +++ /dev/null @@ -1,66 +0,0 @@ -# /////////////////////////////////////////////////////////////// -# -# 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 deleted file mode 100644 index b74309a..0000000 --- a/src/educoder/gui/images/svg_icons/active_menu.svg +++ /dev/null @@ -1,79 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - diff --git a/src/educoder/gui/images/svg_icons/icon_add_user.svg b/src/educoder/gui/images/svg_icons/icon_add_user.svg deleted file mode 100644 index 2a51754..0000000 --- a/src/educoder/gui/images/svg_icons/icon_add_user.svg +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - - image/svg+xml - - - - - - - - - diff --git a/src/educoder/gui/images/svg_icons/icon_arrow_left.svg b/src/educoder/gui/images/svg_icons/icon_arrow_left.svg deleted file mode 100644 index 6bc8f9a..0000000 --- a/src/educoder/gui/images/svg_icons/icon_arrow_left.svg +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - - image/svg+xml - - - - - - - - - diff --git a/src/educoder/gui/images/svg_icons/icon_arrow_right.svg b/src/educoder/gui/images/svg_icons/icon_arrow_right.svg deleted file mode 100644 index 4f7bac9..0000000 --- a/src/educoder/gui/images/svg_icons/icon_arrow_right.svg +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - - image/svg+xml - - - - - - - - - diff --git a/src/educoder/gui/images/svg_icons/icon_attachment.svg b/src/educoder/gui/images/svg_icons/icon_attachment.svg deleted file mode 100644 index 51a21f5..0000000 --- a/src/educoder/gui/images/svg_icons/icon_attachment.svg +++ /dev/null @@ -1,78 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - diff --git a/src/educoder/gui/images/svg_icons/icon_busy.svg b/src/educoder/gui/images/svg_icons/icon_busy.svg deleted file mode 100644 index 309de02..0000000 --- a/src/educoder/gui/images/svg_icons/icon_busy.svg +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - - image/svg+xml - - - - - - - - - diff --git a/src/educoder/gui/images/svg_icons/icon_close.svg b/src/educoder/gui/images/svg_icons/icon_close.svg deleted file mode 100644 index 56651fa..0000000 --- a/src/educoder/gui/images/svg_icons/icon_close.svg +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - - image/svg+xml - - - - - - - - - diff --git a/src/educoder/gui/images/svg_icons/icon_emoticons.svg b/src/educoder/gui/images/svg_icons/icon_emoticons.svg deleted file mode 100644 index 9b5c4e9..0000000 --- a/src/educoder/gui/images/svg_icons/icon_emoticons.svg +++ /dev/null @@ -1,78 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - diff --git a/src/educoder/gui/images/svg_icons/icon_file.svg b/src/educoder/gui/images/svg_icons/icon_file.svg deleted file mode 100644 index 3cd93a9..0000000 --- a/src/educoder/gui/images/svg_icons/icon_file.svg +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - - - image/svg+xml - - - - - - - - - diff --git a/src/educoder/gui/images/svg_icons/icon_folder.svg b/src/educoder/gui/images/svg_icons/icon_folder.svg deleted file mode 100644 index 48fe08f..0000000 --- a/src/educoder/gui/images/svg_icons/icon_folder.svg +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - - - image/svg+xml - - - - - - - - - diff --git a/src/educoder/gui/images/svg_icons/icon_folder_open.svg b/src/educoder/gui/images/svg_icons/icon_folder_open.svg deleted file mode 100644 index ec541bc..0000000 --- a/src/educoder/gui/images/svg_icons/icon_folder_open.svg +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - - - image/svg+xml - - - - - - - - - diff --git a/src/educoder/gui/images/svg_icons/icon_heart.svg b/src/educoder/gui/images/svg_icons/icon_heart.svg deleted file mode 100644 index ba64b5c..0000000 --- a/src/educoder/gui/images/svg_icons/icon_heart.svg +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - - - image/svg+xml - - - - - - - - - diff --git a/src/educoder/gui/images/svg_icons/icon_home.svg b/src/educoder/gui/images/svg_icons/icon_home.svg deleted file mode 100644 index c5619cf..0000000 --- a/src/educoder/gui/images/svg_icons/icon_home.svg +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - - - image/svg+xml - - - - - - - - - diff --git a/src/educoder/gui/images/svg_icons/icon_idle.svg b/src/educoder/gui/images/svg_icons/icon_idle.svg deleted file mode 100644 index 0997f52..0000000 --- a/src/educoder/gui/images/svg_icons/icon_idle.svg +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - - image/svg+xml - - - - - - - - - diff --git a/src/educoder/gui/images/svg_icons/icon_info.svg b/src/educoder/gui/images/svg_icons/icon_info.svg deleted file mode 100644 index cf98b18..0000000 --- a/src/educoder/gui/images/svg_icons/icon_info.svg +++ /dev/null @@ -1,78 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - diff --git a/src/educoder/gui/images/svg_icons/icon_invisible.svg b/src/educoder/gui/images/svg_icons/icon_invisible.svg deleted file mode 100644 index cf2bcec..0000000 --- a/src/educoder/gui/images/svg_icons/icon_invisible.svg +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - - image/svg+xml - - - - - - - - - diff --git a/src/educoder/gui/images/svg_icons/icon_maximize.svg b/src/educoder/gui/images/svg_icons/icon_maximize.svg deleted file mode 100644 index 4b15003..0000000 --- a/src/educoder/gui/images/svg_icons/icon_maximize.svg +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - - image/svg+xml - - - - - - - - - diff --git a/src/educoder/gui/images/svg_icons/icon_menu.svg b/src/educoder/gui/images/svg_icons/icon_menu.svg deleted file mode 100644 index e486198..0000000 --- a/src/educoder/gui/images/svg_icons/icon_menu.svg +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - - - image/svg+xml - - - - - - - - - diff --git a/src/educoder/gui/images/svg_icons/icon_menu_close.svg b/src/educoder/gui/images/svg_icons/icon_menu_close.svg deleted file mode 100644 index 699f1f2..0000000 --- a/src/educoder/gui/images/svg_icons/icon_menu_close.svg +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - - image/svg+xml - - - - - - - - - diff --git a/src/educoder/gui/images/svg_icons/icon_minimize.svg b/src/educoder/gui/images/svg_icons/icon_minimize.svg deleted file mode 100644 index e333b56..0000000 --- a/src/educoder/gui/images/svg_icons/icon_minimize.svg +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - - image/svg+xml - - - - - - - - - diff --git a/src/educoder/gui/images/svg_icons/icon_more_options.svg b/src/educoder/gui/images/svg_icons/icon_more_options.svg deleted file mode 100644 index 689ac36..0000000 --- a/src/educoder/gui/images/svg_icons/icon_more_options.svg +++ /dev/null @@ -1,78 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - diff --git a/src/educoder/gui/images/svg_icons/icon_online.svg b/src/educoder/gui/images/svg_icons/icon_online.svg deleted file mode 100644 index d335a7e..0000000 --- a/src/educoder/gui/images/svg_icons/icon_online.svg +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - - image/svg+xml - - - - - - - - - diff --git a/src/educoder/gui/images/svg_icons/icon_restore.svg b/src/educoder/gui/images/svg_icons/icon_restore.svg deleted file mode 100644 index 18dabdd..0000000 --- a/src/educoder/gui/images/svg_icons/icon_restore.svg +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - - image/svg+xml - - - - - - - - - diff --git a/src/educoder/gui/images/svg_icons/icon_save.svg b/src/educoder/gui/images/svg_icons/icon_save.svg deleted file mode 100644 index c5074df..0000000 --- a/src/educoder/gui/images/svg_icons/icon_save.svg +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - - image/svg+xml - - - - - - - - - diff --git a/src/educoder/gui/images/svg_icons/icon_search.svg b/src/educoder/gui/images/svg_icons/icon_search.svg deleted file mode 100644 index a4cc81f..0000000 --- a/src/educoder/gui/images/svg_icons/icon_search.svg +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - - image/svg+xml - - - - - - - - - diff --git a/src/educoder/gui/images/svg_icons/icon_send.svg b/src/educoder/gui/images/svg_icons/icon_send.svg deleted file mode 100644 index 8e75b7f..0000000 --- a/src/educoder/gui/images/svg_icons/icon_send.svg +++ /dev/null @@ -1,78 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - diff --git a/src/educoder/gui/images/svg_icons/icon_settings.svg b/src/educoder/gui/images/svg_icons/icon_settings.svg deleted file mode 100644 index 02f1b90..0000000 --- a/src/educoder/gui/images/svg_icons/icon_settings.svg +++ /dev/null @@ -1,78 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - diff --git a/src/educoder/gui/images/svg_icons/icon_signal.svg b/src/educoder/gui/images/svg_icons/icon_signal.svg deleted file mode 100644 index 5c1558d..0000000 --- a/src/educoder/gui/images/svg_icons/icon_signal.svg +++ /dev/null @@ -1,78 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - diff --git a/src/educoder/gui/images/svg_icons/icon_widgets.svg b/src/educoder/gui/images/svg_icons/icon_widgets.svg deleted file mode 100644 index d0171c2..0000000 --- a/src/educoder/gui/images/svg_icons/icon_widgets.svg +++ /dev/null @@ -1,101 +0,0 @@ - -image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/educoder/gui/images/svg_icons/no_icon.svg b/src/educoder/gui/images/svg_icons/no_icon.svg deleted file mode 100644 index c61b428..0000000 --- a/src/educoder/gui/images/svg_icons/no_icon.svg +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - - image/svg+xml - - - - - - - - - diff --git a/src/educoder/gui/images/svg_images/logo_home.svg b/src/educoder/gui/images/svg_images/logo_home.svg deleted file mode 100644 index 377a685..0000000 --- a/src/educoder/gui/images/svg_images/logo_home.svg +++ /dev/null @@ -1,158 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/educoder/gui/images/svg_images/logo_top_100x22.svg b/src/educoder/gui/images/svg_images/logo_top_100x22.svg deleted file mode 100644 index f1a2c3d..0000000 --- a/src/educoder/gui/images/svg_images/logo_top_100x22.svg +++ /dev/null @@ -1,157 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/educoder/gui/themes/bright_theme.json b/src/educoder/gui/themes/bright_theme.json deleted file mode 100644 index 1c13669..0000000 --- a/src/educoder/gui/themes/bright_theme.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "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 deleted file mode 100644 index e1f86f0..0000000 --- a/src/educoder/gui/themes/default.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "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 deleted file mode 100644 index 2bad4b5..0000000 --- a/src/educoder/gui/themes/dracula.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "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 deleted file mode 100644 index cd9c761..0000000 --- a/src/educoder/gui/uis/columns/left_column.ui +++ /dev/null @@ -1,271 +0,0 @@ - - - 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 deleted file mode 100644 index c25d04d..0000000 --- a/src/educoder/gui/uis/columns/right_column.ui +++ /dev/null @@ -1,117 +0,0 @@ - - - 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 deleted file mode 100644 index 315b6cc..0000000 --- a/src/educoder/gui/uis/columns/ui_left_column.py +++ /dev/null @@ -1,138 +0,0 @@ -# /////////////////////////////////////////////////////////////// -# -# 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 deleted file mode 100644 index 7f9cf91..0000000 --- a/src/educoder/gui/uis/columns/ui_right_column.py +++ /dev/null @@ -1,116 +0,0 @@ -# /////////////////////////////////////////////////////////////// -# -# 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 deleted file mode 100644 index 04bce61..0000000 --- a/src/educoder/gui/uis/pages/main_pages.ui +++ /dev/null @@ -1,298 +0,0 @@ - - - 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 deleted file mode 100644 index f7cbd0a..0000000 --- a/src/educoder/gui/uis/pages/ui_main_pages.py +++ /dev/null @@ -1,176 +0,0 @@ -# /////////////////////////////////////////////////////////////// -# -# 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 deleted file mode 100644 index 0239ed3..0000000 --- a/src/educoder/gui/uis/windows/main_window/__init__.py +++ /dev/null @@ -1,23 +0,0 @@ -# /////////////////////////////////////////////////////////////// -# -# 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 deleted file mode 100644 index 9c55068..0000000 --- a/src/educoder/gui/uis/windows/main_window/functions_main_window.py +++ /dev/null @@ -1,145 +0,0 @@ -# /////////////////////////////////////////////////////////////// -# -# 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 deleted file mode 100644 index ca1ce38..0000000 --- a/src/educoder/gui/uis/windows/main_window/setup_main_window.py +++ /dev/null @@ -1,600 +0,0 @@ -# /////////////////////////////////////////////////////////////// -# -# 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 deleted file mode 100644 index ddda193..0000000 --- a/src/educoder/gui/uis/windows/main_window/ui_main.py +++ /dev/null @@ -1,305 +0,0 @@ -# /////////////////////////////////////////////////////////////// -# -# 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 deleted file mode 100644 index 95bd69e..0000000 --- a/src/educoder/gui/widgets/__init__.py +++ /dev/null @@ -1,71 +0,0 @@ -# /////////////////////////////////////////////////////////////// -# -# 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 deleted file mode 100644 index a9b7346..0000000 --- a/src/educoder/gui/widgets/py_circular_progress/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -# /////////////////////////////////////////////////////////////// -# -# 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 deleted file mode 100644 index f5fd217..0000000 --- a/src/educoder/gui/widgets/py_circular_progress/py_circular_progress.py +++ /dev/null @@ -1,114 +0,0 @@ -# /////////////////////////////////////////////////////////////// -# -# 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 deleted file mode 100644 index 4aa4e8f..0000000 --- a/src/educoder/gui/widgets/py_credits_bar/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -# /////////////////////////////////////////////////////////////// -# -# 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 deleted file mode 100644 index 4912ae0..0000000 --- a/src/educoder/gui/widgets/py_credits_bar/py_credits.py +++ /dev/null @@ -1,95 +0,0 @@ -# /////////////////////////////////////////////////////////////// -# -# 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 deleted file mode 100644 index a4fda03..0000000 --- a/src/educoder/gui/widgets/py_grips/__init__.py +++ /dev/null @@ -1,17 +0,0 @@ -# /////////////////////////////////////////////////////////////// -# -# 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 deleted file mode 100644 index a95e8a8..0000000 --- a/src/educoder/gui/widgets/py_grips/py_grips.py +++ /dev/null @@ -1,249 +0,0 @@ -# /////////////////////////////////////////////////////////////// -# -# 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 deleted file mode 100644 index cb6fe88..0000000 --- a/src/educoder/gui/widgets/py_icon_button/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -# /////////////////////////////////////////////////////////////// -# -# 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 deleted file mode 100644 index ced9744..0000000 --- a/src/educoder/gui/widgets/py_icon_button/py_icon_button.py +++ /dev/null @@ -1,268 +0,0 @@ -# /////////////////////////////////////////////////////////////// -# -# 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 deleted file mode 100644 index d2015d4..0000000 --- a/src/educoder/gui/widgets/py_left_column/__init__.py +++ /dev/null @@ -1,20 +0,0 @@ -# /////////////////////////////////////////////////////////////// -# -# 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 deleted file mode 100644 index 4d91eae..0000000 --- a/src/educoder/gui/widgets/py_left_column/py_icon.py +++ /dev/null @@ -1,70 +0,0 @@ -# /////////////////////////////////////////////////////////////// -# -# 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 deleted file mode 100644 index 3ad9d5c..0000000 --- a/src/educoder/gui/widgets/py_left_column/py_left_button.py +++ /dev/null @@ -1,271 +0,0 @@ -# /////////////////////////////////////////////////////////////// -# -# 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 deleted file mode 100644 index 7a880c2..0000000 --- a/src/educoder/gui/widgets/py_left_column/py_left_column.py +++ /dev/null @@ -1,194 +0,0 @@ -# /////////////////////////////////////////////////////////////// -# -# 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 deleted file mode 100644 index 5c0ed6e..0000000 --- a/src/educoder/gui/widgets/py_left_menu/__init__.py +++ /dev/null @@ -1,20 +0,0 @@ -# /////////////////////////////////////////////////////////////// -# -# 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 deleted file mode 100644 index 2aa68c1..0000000 --- a/src/educoder/gui/widgets/py_left_menu/py_div.py +++ /dev/null @@ -1,34 +0,0 @@ -# /////////////////////////////////////////////////////////////// -# -# 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 deleted file mode 100644 index 30d5db7..0000000 --- a/src/educoder/gui/widgets/py_left_menu/py_left_menu.py +++ /dev/null @@ -1,266 +0,0 @@ -# /////////////////////////////////////////////////////////////// -# -# 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 deleted file mode 100644 index f7bc575..0000000 --- a/src/educoder/gui/widgets/py_left_menu/py_left_menu_button.py +++ /dev/null @@ -1,380 +0,0 @@ -# /////////////////////////////////////////////////////////////// -# -# 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 deleted file mode 100644 index cb20e14..0000000 --- a/src/educoder/gui/widgets/py_line_edit/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -# /////////////////////////////////////////////////////////////// -# -# 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 deleted file mode 100644 index ed8cfd8..0000000 --- a/src/educoder/gui/widgets/py_line_edit/py_line_edit.py +++ /dev/null @@ -1,95 +0,0 @@ -# /////////////////////////////////////////////////////////////// -# -# 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 deleted file mode 100644 index 9467b6a..0000000 --- a/src/educoder/gui/widgets/py_push_button/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -# /////////////////////////////////////////////////////////////// -# -# 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 deleted file mode 100644 index 0d5b421..0000000 --- a/src/educoder/gui/widgets/py_push_button/py_push_button.py +++ /dev/null @@ -1,71 +0,0 @@ -# /////////////////////////////////////////////////////////////// -# -# 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 deleted file mode 100644 index 2ba529d..0000000 --- a/src/educoder/gui/widgets/py_slider/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -# /////////////////////////////////////////////////////////////// -# -# 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 deleted file mode 100644 index 011fb50..0000000 --- a/src/educoder/gui/widgets/py_slider/py_slider.py +++ /dev/null @@ -1,97 +0,0 @@ -# /////////////////////////////////////////////////////////////// -# -# 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 deleted file mode 100644 index 240646c..0000000 --- a/src/educoder/gui/widgets/py_table_widget/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -# /////////////////////////////////////////////////////////////// -# -# 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 deleted file mode 100644 index f0904bd..0000000 --- a/src/educoder/gui/widgets/py_table_widget/py_table_widget.py +++ /dev/null @@ -1,90 +0,0 @@ -# /////////////////////////////////////////////////////////////// -# -# 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 deleted file mode 100644 index 5c3afc0..0000000 --- a/src/educoder/gui/widgets/py_table_widget/style.py +++ /dev/null @@ -1,135 +0,0 @@ -# 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 deleted file mode 100644 index 85dcd27..0000000 --- a/src/educoder/gui/widgets/py_title_bar/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -# /////////////////////////////////////////////////////////////// -# -# 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 deleted file mode 100644 index a0a1145..0000000 --- a/src/educoder/gui/widgets/py_title_bar/py_div.py +++ /dev/null @@ -1,35 +0,0 @@ -# /////////////////////////////////////////////////////////////// -# -# 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 deleted file mode 100644 index 5f6d83d..0000000 --- a/src/educoder/gui/widgets/py_title_bar/py_title_bar.py +++ /dev/null @@ -1,346 +0,0 @@ -# /////////////////////////////////////////////////////////////// -# -# 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 deleted file mode 100644 index cb48660..0000000 --- a/src/educoder/gui/widgets/py_title_bar/py_title_button.py +++ /dev/null @@ -1,271 +0,0 @@ -# /////////////////////////////////////////////////////////////// -# -# 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 deleted file mode 100644 index 1f0b5af..0000000 --- a/src/educoder/gui/widgets/py_toggle/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -# /////////////////////////////////////////////////////////////// -# -# 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 deleted file mode 100644 index 12f9b1c..0000000 --- a/src/educoder/gui/widgets/py_toggle/py_toggle.py +++ /dev/null @@ -1,88 +0,0 @@ -# /////////////////////////////////////////////////////////////// -# -# 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 deleted file mode 100644 index 43e8283..0000000 --- a/src/educoder/gui/widgets/py_window/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -# /////////////////////////////////////////////////////////////// -# -# 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 deleted file mode 100644 index 3189935..0000000 --- a/src/educoder/gui/widgets/py_window/py_window.py +++ /dev/null @@ -1,141 +0,0 @@ -# /////////////////////////////////////////////////////////////// -# -# 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 deleted file mode 100644 index a4e74e9..0000000 --- a/src/educoder/gui/widgets/py_window/styles.py +++ /dev/null @@ -1,28 +0,0 @@ -# /////////////////////////////////////////////////////////////// -# -# 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 deleted file mode 100644 index e8a2df8dc85808d95a8172788ae5b6478fb83614..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 202993 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