From a75a226613bc0a074aa0802d5c0997596b817854 Mon Sep 17 00:00:00 2001 From: Jeffin Johnykutty Date: Wed, 20 Mar 2024 12:57:38 -0400 Subject: [PATCH 1/4] Edit Homescreen GUI to match figma concept. --- flask/Pipfile | 1 + flask/Pipfile.lock | 85 +++++++++++- home/homeScreenGui.py | 299 ++++++++++++++++++++---------------------- 3 files changed, 228 insertions(+), 157 deletions(-) diff --git a/flask/Pipfile b/flask/Pipfile index a40b724b..390ff2cd 100644 --- a/flask/Pipfile +++ b/flask/Pipfile @@ -6,6 +6,7 @@ name = "pypi" [packages] flask = "*" flask-cors = "*" +ttkbootstrap = "*" [dev-packages] diff --git a/flask/Pipfile.lock b/flask/Pipfile.lock index bb6ea092..78f854a4 100644 --- a/flask/Pipfile.lock +++ b/flask/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "08e5722aa464adfe98b1eb46c2dc84865e3893dab6eb4d729e43cb720724521c" + "sha256": "5e505c84607b03e50b01c099000da2963fa54bbc7eecd3c71c0dbb7f9c9151e2" }, "pipfile-spec": 6, "requires": { @@ -139,6 +139,89 @@ "markers": "python_version >= '3.7'", "version": "==2.1.5" }, + "pillow": { + "hashes": [ + "sha256:0304004f8067386b477d20a518b50f3fa658a28d44e4116970abfcd94fac34a8", + "sha256:0689b5a8c5288bc0504d9fcee48f61a6a586b9b98514d7d29b840143d6734f39", + "sha256:0eae2073305f451d8ecacb5474997c08569fb4eb4ac231ffa4ad7d342fdc25ac", + "sha256:0fb3e7fc88a14eacd303e90481ad983fd5b69c761e9e6ef94c983f91025da869", + "sha256:11fa2e5984b949b0dd6d7a94d967743d87c577ff0b83392f17cb3990d0d2fd6e", + "sha256:127cee571038f252a552760076407f9cff79761c3d436a12af6000cd182a9d04", + "sha256:154e939c5f0053a383de4fd3d3da48d9427a7e985f58af8e94d0b3c9fcfcf4f9", + "sha256:15587643b9e5eb26c48e49a7b33659790d28f190fc514a322d55da2fb5c2950e", + "sha256:170aeb00224ab3dc54230c797f8404507240dd868cf52066f66a41b33169bdbe", + "sha256:1b5e1b74d1bd1b78bc3477528919414874748dd363e6272efd5abf7654e68bef", + "sha256:1da3b2703afd040cf65ec97efea81cfba59cdbed9c11d8efc5ab09df9509fc56", + "sha256:1e23412b5c41e58cec602f1135c57dfcf15482013ce6e5f093a86db69646a5aa", + "sha256:2247178effb34a77c11c0e8ac355c7a741ceca0a732b27bf11e747bbc950722f", + "sha256:257d8788df5ca62c980314053197f4d46eefedf4e6175bc9412f14412ec4ea2f", + "sha256:3031709084b6e7852d00479fd1d310b07d0ba82765f973b543c8af5061cf990e", + "sha256:322209c642aabdd6207517e9739c704dc9f9db943015535783239022002f054a", + "sha256:322bdf3c9b556e9ffb18f93462e5f749d3444ce081290352c6070d014c93feb2", + "sha256:33870dc4653c5017bf4c8873e5488d8f8d5f8935e2f1fb9a2208c47cdd66efd2", + "sha256:35bb52c37f256f662abdfa49d2dfa6ce5d93281d323a9af377a120e89a9eafb5", + "sha256:3c31822339516fb3c82d03f30e22b1d038da87ef27b6a78c9549888f8ceda39a", + "sha256:3eedd52442c0a5ff4f887fab0c1c0bb164d8635b32c894bc1faf4c618dd89df2", + "sha256:3ff074fc97dd4e80543a3e91f69d58889baf2002b6be64347ea8cf5533188213", + "sha256:47c0995fc4e7f79b5cfcab1fc437ff2890b770440f7696a3ba065ee0fd496563", + "sha256:49d9ba1ed0ef3e061088cd1e7538a0759aab559e2e0a80a36f9fd9d8c0c21591", + "sha256:51f1a1bffc50e2e9492e87d8e09a17c5eea8409cda8d3f277eb6edc82813c17c", + "sha256:52a50aa3fb3acb9cf7213573ef55d31d6eca37f5709c69e6858fe3bc04a5c2a2", + "sha256:54f1852cd531aa981bc0965b7d609f5f6cc8ce8c41b1139f6ed6b3c54ab82bfb", + "sha256:609448742444d9290fd687940ac0b57fb35e6fd92bdb65386e08e99af60bf757", + "sha256:69ffdd6120a4737710a9eee73e1d2e37db89b620f702754b8f6e62594471dee0", + "sha256:6fad5ff2f13d69b7e74ce5b4ecd12cc0ec530fcee76356cac6742785ff71c452", + "sha256:7049e301399273a0136ff39b84c3678e314f2158f50f517bc50285fb5ec847ad", + "sha256:70c61d4c475835a19b3a5aa42492409878bbca7438554a1f89d20d58a7c75c01", + "sha256:716d30ed977be8b37d3ef185fecb9e5a1d62d110dfbdcd1e2a122ab46fddb03f", + "sha256:753cd8f2086b2b80180d9b3010dd4ed147efc167c90d3bf593fe2af21265e5a5", + "sha256:773efe0603db30c281521a7c0214cad7836c03b8ccff897beae9b47c0b657d61", + "sha256:7823bdd049099efa16e4246bdf15e5a13dbb18a51b68fa06d6c1d4d8b99a796e", + "sha256:7c8f97e8e7a9009bcacbe3766a36175056c12f9a44e6e6f2d5caad06dcfbf03b", + "sha256:823ef7a27cf86df6597fa0671066c1b596f69eba53efa3d1e1cb8b30f3533068", + "sha256:8373c6c251f7ef8bda6675dd6d2b3a0fcc31edf1201266b5cf608b62a37407f9", + "sha256:83b2021f2ade7d1ed556bc50a399127d7fb245e725aa0113ebd05cfe88aaf588", + "sha256:870ea1ada0899fd0b79643990809323b389d4d1d46c192f97342eeb6ee0b8483", + "sha256:8d12251f02d69d8310b046e82572ed486685c38f02176bd08baf216746eb947f", + "sha256:9c23f307202661071d94b5e384e1e1dc7dfb972a28a2310e4ee16103e66ddb67", + "sha256:9d189550615b4948f45252d7f005e53c2040cea1af5b60d6f79491a6e147eef7", + "sha256:a086c2af425c5f62a65e12fbf385f7c9fcb8f107d0849dba5839461a129cf311", + "sha256:a2b56ba36e05f973d450582fb015594aaa78834fefe8dfb8fcd79b93e64ba4c6", + "sha256:aebb6044806f2e16ecc07b2a2637ee1ef67a11840a66752751714a0d924adf72", + "sha256:b1b3020d90c2d8e1dae29cf3ce54f8094f7938460fb5ce8bc5c01450b01fbaf6", + "sha256:b4b6b1e20608493548b1f32bce8cca185bf0480983890403d3b8753e44077129", + "sha256:b6f491cdf80ae540738859d9766783e3b3c8e5bd37f5dfa0b76abdecc5081f13", + "sha256:b792a349405fbc0163190fde0dc7b3fef3c9268292586cf5645598b48e63dc67", + "sha256:b7c2286c23cd350b80d2fc9d424fc797575fb16f854b831d16fd47ceec078f2c", + "sha256:babf5acfede515f176833ed6028754cbcd0d206f7f614ea3447d67c33be12516", + "sha256:c365fd1703040de1ec284b176d6af5abe21b427cb3a5ff68e0759e1e313a5e7e", + "sha256:c4225f5220f46b2fde568c74fca27ae9771536c2e29d7c04f4fb62c83275ac4e", + "sha256:c570f24be1e468e3f0ce7ef56a89a60f0e05b30a3669a459e419c6eac2c35364", + "sha256:c6dafac9e0f2b3c78df97e79af707cdc5ef8e88208d686a4847bab8266870023", + "sha256:c8de2789052ed501dd829e9cae8d3dcce7acb4777ea4a479c14521c942d395b1", + "sha256:cb28c753fd5eb3dd859b4ee95de66cc62af91bcff5db5f2571d32a520baf1f04", + "sha256:cb4c38abeef13c61d6916f264d4845fab99d7b711be96c326b84df9e3e0ff62d", + "sha256:d1b35bcd6c5543b9cb547dee3150c93008f8dd0f1fef78fc0cd2b141c5baf58a", + "sha256:d8e6aeb9201e655354b3ad049cb77d19813ad4ece0df1249d3c793de3774f8c7", + "sha256:d8ecd059fdaf60c1963c58ceb8997b32e9dc1b911f5da5307aab614f1ce5c2fb", + "sha256:da2b52b37dad6d9ec64e653637a096905b258d2fc2b984c41ae7d08b938a67e4", + "sha256:e87f0b2c78157e12d7686b27d63c070fd65d994e8ddae6f328e0dcf4a0cd007e", + "sha256:edca80cbfb2b68d7b56930b84a0e45ae1694aeba0541f798e908a49d66b837f1", + "sha256:f379abd2f1e3dddb2b61bc67977a6b5a0a3f7485538bcc6f39ec76163891ee48", + "sha256:fe4c15f6c9285dc54ce6553a3ce908ed37c8f3825b5a51a15c91442bb955b868" + ], + "markers": "python_version >= '3.8'", + "version": "==10.2.0" + }, + "ttkbootstrap": { + "hashes": [ + "sha256:53925525c4104f9e345627500dced2d0392ad74324b2a81467aaee3ffbe1a474", + "sha256:c6a10ee5ea64051a0f8b75c20ef8e5f2417c62b4d0858c831683d4f2135aa573" + ], + "index": "pypi", + "markers": "python_version >= '3.7'", + "version": "==1.10.1" + }, "werkzeug": { "hashes": [ "sha256:507e811ecea72b18a404947aded4b3390e1db8f826b494d76550ef45bb3b1dcc", diff --git a/home/homeScreenGui.py b/home/homeScreenGui.py index e5231b9f..271fdad8 100644 --- a/home/homeScreenGui.py +++ b/home/homeScreenGui.py @@ -1,39 +1,85 @@ import tkinter as tk -from tkinter import Canvas, Frame, Scrollbar, Label +from tkinter import Canvas, Frame, Scrollbar, Label, ttk import webbrowser +from PIL import Image, ImageTk -#Add new game icon in scrollable list -def render_new_game_icon(game_list_frame): - box_width = 125 - box_height = 125 - - # Create a game frame with the specified size - new_game_frame = tk.Frame(game_list_frame, width=box_width, height=box_height, bg='#51535B') - new_game_frame.pack_propagate(False) # Prevents child widgets from altering the frame's size - new_game_frame.pack(side=tk.LEFT, padx=20, pady=20) - - # Create a label with the game name and size, and ensure it's centered - game_label = tk.Label(new_game_frame, text=f"+\n", - fg='#FFFFFF', bg='#51535B', font=('Helvetica', 20)) - game_label.pack(expand=True) # This will center the text in the frame - game_label.bind("", open_code_editor_new_game_page) +# Methods to test if cliking widgets are responsive +def home_button_clicked_event(event=None): + print("Home button clicked!") + +def community_hub_clicked_event(event=None): + print("Community Hub button clicked!") + +def classroom_clicked_event(event=None): + print("Classroom button clicked!") +def settings_clicked_event(event=None): + print("Settings button clicked!") - # Set the highlightthickness for normal state so that the change is visible on hover - new_game_frame.config(highlightbackground='grey', highlightthickness=1) - # Bind enter and leave events to the game frame to show mous hovering effects - new_game_frame.bind("", lambda e, widget=new_game_frame: on_enter(e, widget)) - new_game_frame.bind("", lambda e, widget=new_game_frame: on_leave(e, widget)) +def on_enter(e, widget): + widget.config(highlightbackground='yellow', highlightthickness=2) + +def on_leave(e, widget): + widget.config(highlightbackground='grey', highlightthickness=1) -#Function where it opens a new web browser tab that shows a new game page -def open_code_editor_new_game_page(event): +def render_top_frame(root): + top_frame = tk.Frame(root, bg='#2D3039') + top_frame.pack(side=tk.TOP, fill='x', anchor='n') + + def create_top_button(frame, image_path, command, desired_width, desired_height): + # Open the image file with PIL + pil_img = Image.open(image_path) + # Resize the image to the desired dimensions + pil_img = pil_img.resize((desired_width, desired_height), Image.LANCZOS) + + # Create a PhotoImage object from the resized PIL image + img = ImageTk.PhotoImage(pil_img) + + # Create a Tkinter button with this image + button = tk.Button(frame, image=img, command=command, bd= 0, highlightthickness=0) + button.image = img # Keep a reference to the image + button.pack(side=tk.LEFT, padx=10, pady=10) + return button + + home_img_path = 'home\\guiImages\\homeIcon.png' + community_img_path = 'home\\guiImages\\communityHubIcon.png' + classroom_img_path = 'home\\guiImages\\classroomIcon.png' + settings_img_path = 'home\\guiImages\\settingsIcon.png' + + # Create buttons with images + buttonWidth = 75 + buttonHeight = 75 + home_button = create_top_button(top_frame, home_img_path, home_button_clicked_event, buttonWidth, buttonHeight) + community_button = create_top_button(top_frame, community_img_path, community_hub_clicked_event, buttonWidth, buttonHeight) + classroom_button = create_top_button(top_frame, classroom_img_path, classroom_clicked_event, buttonWidth, buttonHeight) + settings_button = create_top_button(top_frame, settings_img_path, settings_clicked_event, buttonWidth, buttonHeight) + +def render_new_game_icon(game_list_frame, button_width, button_height): + # Open the image file with PIL and resize it + pil_img = Image.open('home\\guiImages\\newGameIcon.png') + pil_img = pil_img.resize((button_width, button_height), Image.LANCZOS) + + # Create a PhotoImage object from the resized PIL image + photo = ImageTk.PhotoImage(pil_img) + + # Create a Tkinter button with this image + img_button = tk.Button(game_list_frame, image=photo, command=open_code_editor_new_game_page, borderwidth=0, highlightthickness=0) + img_button.image = photo # Keep a reference to the image + img_button.pack(side=tk.LEFT, padx=20, pady=20) + + img_button.bind("", lambda e, widget=img_button: on_enter(e, widget)) + img_button.bind("", lambda e, widget=img_button: on_leave(e, widget)) + + +# Function where it opens a new web browser tab that shows a new game page +def open_code_editor_new_game_page(): print("New Game Icon button clicked!") link = 'http://localhost:5000/?load=filename.json' webbrowser.open(link) -#Opening an instance of the code editor +# Opening an instance of the code editor def open_code_editor(): link = 'http://localhost:5000' webbrowser.open(link) @@ -52,193 +98,134 @@ def display_game_info(game_info_container, game_name): for widget in game_info_container.winfo_children(): widget.destroy() - # Create a frame for the text information - text_info_frame = tk.Frame(game_info_container) + # Style update: Game information container background color + game_info_container.config(bg='#23252C') + + # Create a frame for the text information with padding and background color + text_info_frame = tk.Frame(game_info_container, padx=10, pady=10, bg='#23252C') text_info_frame.pack(side=tk.LEFT, fill=tk.X, expand=True) - # Create labels inside the text information frame - tk.Label(text_info_frame, text=game_name, font=("Helvetica", 16), anchor='w').pack(fill='x') - tk.Label(text_info_frame, text="Author: You", anchor='w').pack(fill='x') - tk.Label(text_info_frame, text="Last Updated: 2/13/2024", anchor='w').pack(fill='x') + # Update label styles with font size and foreground color + tk.Label(text_info_frame, text=game_name, font=("Helvetica", 16), anchor='w', fg='#FFFFFF', bg='#23252C').pack(fill='x') + tk.Label(text_info_frame, text="Author: You", anchor='w', fg='#FFFFFF', bg='#23252C').pack(fill='x') + tk.Label(text_info_frame, text="Last Updated: 2/13/2024", anchor='w', fg='#FFFFFF', bg='#23252C').pack(fill='x') + + # Style update for button frame + button_frame = tk.Frame(game_info_container, bg='#23252C') + button_frame.pack(side=tk.RIGHT, padx=10, pady=10) - # Create a frame for the buttons - button_frame = tk.Frame(game_info_container) - button_frame.pack(side=tk.RIGHT) + def create_button(frame, image_path, command, desired_width, desired_height): + # Open the image file with PIL + pil_img = Image.open(image_path) + # Resize the image to the desired dimensions + pil_img = pil_img.resize((desired_width, desired_height), Image.LANCZOS) + # Create a PhotoImage object from the resized PIL image + img = ImageTk.PhotoImage(pil_img) + + # Create a Tkinter button with this image + button = tk.Button(frame, image=img, command=command, bd= 0, highlightthickness=0) + button.image = img # Keep a reference to the image + button.pack(side=tk.LEFT, padx=5, pady=5) + return button - # Create buttons inside the button frame with equal width and height - play_button = tk.Button(button_frame, text="Play", bg="red", fg="white") - play_button.pack(side=tk.LEFT, padx=5, pady=5, ipadx=20, ipady=20) # ipadx and ipady add internal padding to make the button square - play_button.bind("", lambda e, widget=play_button: on_enter(e, widget)) - play_button.bind("", lambda e, widget=play_button: on_leave(e, widget)) + play_button_img_path = 'home\\guiImages\\playButtonIcon.png' + edit_button_img_path = 'home\\guiImages\\editIcon.png' + upload_buton_img_path = 'home\\guiImages\\uploadIcon.png' - edit_button = tk.Button(button_frame, text="Edit", bg="blue", fg="white", command=open_code_editor) # When clicked, a new code editor istance is made in a new web browser tab. - edit_button.pack(side=tk.LEFT, padx=5, pady=5, ipadx=20, ipady=20) # Same internal padding for square shape - edit_button.bind("", lambda e, widget=edit_button: on_enter(e, widget)) - edit_button.bind("", lambda e, widget=edit_button: on_leave(e, widget)) + buttonWidth = 90 + buttonHeight = 90 - upload_button = tk.Button(button_frame, text="Upload", bg="green", fg="white") - upload_button.pack(side=tk.LEFT, padx=5, pady=5, ipadx=20, ipady=20) # Same internal padding for square shape - upload_button.bind("", lambda e, widget=upload_button: on_enter(e, widget)) - upload_button.bind("", lambda e, widget=upload_button: on_leave(e, widget)) + # Create buttons with new styling + play_button = create_button(button_frame, play_button_img_path, None, buttonWidth, buttonHeight) + edit_button = create_button(button_frame, edit_button_img_path, open_code_editor, buttonWidth, buttonHeight) + upload_button = create_button(button_frame, upload_buton_img_path, None, buttonWidth, buttonHeight) def render_game_library(main_container, game_info_container): - # Create a container frame with a border - container = tk.Frame(main_container, bd=2, relief='groove') + # Update the container frame with a background color + container = tk.Frame(main_container, bg='#23252C') container.pack(side=tk.TOP, fill='both', expand=True, padx=10, pady=10) - - canvas = tk.Canvas(container, highlightthickness=0) - - # Create a frame for the scrollbar to ensure it's at the bottom of the container - scrollbar_frame = tk.Frame(container) - scrollbar_frame.pack(side=tk.BOTTOM, fill='x', expand=False) - - # Create a scrollbar within the scrollbar frame - scrollbar = tk.Scrollbar(scrollbar_frame, orient="horizontal", command=canvas.xview) - scrollbar.pack(side=tk.BOTTOM, fill='x', expand=False) - - # Pack the canvas after the scrollbar frame to fill the remaining space + + canvas = tk.Canvas(container, bg='#23252C', highlightthickness=0) + canvas.pack(side=tk.TOP, fill='both', expand=True) - - # Configure the canvas - canvas.configure(xscrollcommand=scrollbar.set) - - # Create a frame inside the canvas for the list of games - game_list_frame = tk.Frame(canvas) - - # Add the game list frame to a window in the canvas + + # Style the game list frame with a background color + game_list_frame = tk.Frame(canvas, bg='#23252C') canvas.create_window((0, 0), window=game_list_frame, anchor='nw') - - # Define a function to update the canvas's scrollregion + def on_frame_configure(canvas): canvas.configure(scrollregion=canvas.bbox('all')) - - # Bind the Frame's configuration event to update the canvas's scrollregion + game_list_frame.bind('', lambda event, canvas=canvas: on_frame_configure(canvas)) - + + # dimensions for new game icon and games in game library + game_lib_button_width = 125 + game_lib_button_height = 125 + + # Invoke new game button function + render_new_game_icon(game_list_frame, game_lib_button_width, game_lib_button_height) + # Example list of games to populate the frame - games = ["T T T", "Game 2", "Game 3", "Game 4", "Game 5", "Game 6", "Game 7"] - - #Invoke new gam button function - render_new_game_icon(game_list_frame) + games = ["Game 1", "Game 2", "Game 3", "Game 4", "Game 5", "Game 6", "Game 7"] # Add games to the frame for game in games: - box_width = 125 - box_height = 125 - + box_width = 125 + box_height = 125 + # Create a game frame with the specified size game_frame = tk.Frame(game_list_frame, width=box_width, height=box_height, bg='#51535B') game_frame.pack_propagate(False) # Prevents child widgets from altering the frame's size game_frame.pack(side=tk.LEFT, padx=20, pady=20) - + # Create a label with the game name and size, and ensure it's centered game_label = tk.Label(game_frame, text=f"{game}\n", - fg='#FFFFFF', bg='#51535B', font=('Helvetica', 20)) + fg='#FFFFFF', bg='#51535B', font=('Helvetica', 20)) game_label.pack(expand=True) # This will center the text in the frame game_label.bind("", lambda event, name=game: display_game_info(game_info_container, name)) # Set the highlightthickness for normal state so that the change is visible on hover game_frame.config(highlightbackground='grey', highlightthickness=1) - # Bind enter and leave events to the game frame to show mous hovering effects + # Bind enter and leave events to the game frame to show mouse hovering effects game_frame.bind("", lambda e, widget=game_frame: on_enter(e, widget)) game_frame.bind("", lambda e, widget=game_frame: on_leave(e, widget)) - - # Update the scrollregion after the UI has been drawn + game_list_frame.update_idletasks() on_frame_configure(canvas) - + # Bind mousewheel scrolling to the canvas def on_mousewheel(event): - canvas.xview_scroll(int(-1*(event.delta/120)), "units") + canvas.xview_scroll(int(-1 * (event.delta/120)), "units") canvas.bind_all("", on_mousewheel) -# Methods to test if cliking widgets are responsive -def home_button_clicked_event(event=None): - print("Home button clicked!") - -def community_hub_clicked_event(event=None): - print("Community Hub button clicked!") - -def classroom_clicked_event(event=None): - print("Classroom button clicked!") - -def settings_clicked_event(event=None): - print("Settings button clicked!") - -def render_top_frame(root): - top_frame = tk.Frame(root) - top_frame.pack(side=tk.TOP, anchor=tk.NW) - - # Add home button - home_canvas = tk.Canvas(top_frame, width=100, height=100) - home_canvas.pack(side=tk.LEFT, padx=10, pady=10) - home_canvas.create_rectangle(0, 0, 100, 100, fill="#51535B") - home_canvas.create_text(50, 50, text="Home", fill="#FFFFFF") - home_canvas.bind("", home_button_clicked_event) - home_canvas.bind("", lambda e, widget=home_canvas: on_enter(e, widget)) - home_canvas.bind("", lambda e, widget=home_canvas: on_leave(e, widget)) - - - # Add Community Hub button - community_canvas = tk.Canvas(top_frame, width=100, height=100) - community_canvas.pack(side=tk.LEFT, padx=10, pady=10) - community_canvas.create_rectangle(0, 0, 100, 100, fill="#51535B") - community_canvas.create_text(50, 50, text="CH", fill="#FFFFFF") - community_canvas.bind("", community_hub_clicked_event) - community_canvas.bind("", lambda e, widget=community_canvas: on_enter(e, widget)) - community_canvas.bind("", lambda e, widget=community_canvas: on_leave(e, widget)) - - - # Add Classroom button - classroom_canvas = tk.Canvas(top_frame, width=100, height=100) - classroom_canvas.pack(side=tk.LEFT, padx=10, pady=10) - classroom_canvas.create_rectangle(0, 0, 100, 100, fill="#51535B") - classroom_canvas.create_text(50, 50, text="Classroom", fill="#FFFFFF") - classroom_canvas.bind("", classroom_clicked_event) - classroom_canvas.bind("", lambda e, widget=classroom_canvas: on_enter(e, widget)) - classroom_canvas.bind("", lambda e, widget=classroom_canvas: on_leave(e, widget)) - - - # Add Settings Button - settings_canvas = tk.Canvas(top_frame, width=100, height=100) - settings_canvas.pack(side=tk.LEFT, padx=10, pady=10) - settings_canvas.create_rectangle(0, 0, 100, 100, fill="#51535B") - settings_canvas.create_text(50, 50, text="Settings", fill="#FFFFFF") - settings_canvas.bind("", settings_clicked_event) - settings_canvas.bind("", lambda e, widget=settings_canvas: on_enter(e, widget)) - settings_canvas.bind("", lambda e, widget=settings_canvas: on_leave(e, widget)) - - def initial_render(root): - render_top_frame(root) + top_container = tk.Frame(root, bg='#424347') + top_container.pack(side=tk.TOP, fill='both', expand=True, padx=4, pady=4) + render_top_frame(top_container) # Main container frame for both the games list and game information - main_container = tk.Frame(root) - main_container.pack(side=tk.TOP, fill='both', expand=True) + main_container = tk.Frame(root, bg='#23252C') + main_container.pack(side=tk.TOP, fill='both', expand=True, padx=10, pady=10) + # Create the game information container and pack it at the bottom of the main container - game_info_container = tk.Frame(main_container, bd=2, relief='groove') - game_info_container.pack(side=tk.BOTTOM, fill='x', padx=10, pady=10) + game_info_container = tk.Frame(main_container, bd=0, relief='groove') + game_info_container.pack(side=tk.BOTTOM, fill='x', padx=20, pady=20) render_game_library(main_container, game_info_container) def display_home_screen(): root = tk.Tk() root.geometry("800x450") + root.configure(bg='#2D3039') initial_render(root) root.mainloop() -display_home_screen() - - - - - - +display_home_screen() From e2785ad5af522701092cb1e0ada579064d840e79 Mon Sep 17 00:00:00 2001 From: Jeffin Johnykutty Date: Wed, 20 Mar 2024 21:19:05 -0400 Subject: [PATCH 2/4] Added battery & wifi icons to homescreen. --- home/homeScreenGui.py | 41 +++++++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/home/homeScreenGui.py b/home/homeScreenGui.py index 271fdad8..4425d835 100644 --- a/home/homeScreenGui.py +++ b/home/homeScreenGui.py @@ -24,7 +24,7 @@ def on_leave(e, widget): widget.config(highlightbackground='grey', highlightthickness=1) def render_top_frame(root): - top_frame = tk.Frame(root, bg='#2D3039') + top_frame = tk.Frame(root, bg='#33363e') top_frame.pack(side=tk.TOP, fill='x', anchor='n') def create_top_button(frame, image_path, command, desired_width, desired_height): @@ -48,12 +48,37 @@ def create_top_button(frame, image_path, command, desired_width, desired_height) settings_img_path = 'home\\guiImages\\settingsIcon.png' # Create buttons with images - buttonWidth = 75 - buttonHeight = 75 - home_button = create_top_button(top_frame, home_img_path, home_button_clicked_event, buttonWidth, buttonHeight) - community_button = create_top_button(top_frame, community_img_path, community_hub_clicked_event, buttonWidth, buttonHeight) - classroom_button = create_top_button(top_frame, classroom_img_path, classroom_clicked_event, buttonWidth, buttonHeight) - settings_button = create_top_button(top_frame, settings_img_path, settings_clicked_event, buttonWidth, buttonHeight) + button_width = 75 + button_height = 75 + home_button = create_top_button(top_frame, home_img_path, home_button_clicked_event, button_width, button_height) + community_button = create_top_button(top_frame, community_img_path, community_hub_clicked_event, button_width, button_height) + classroom_button = create_top_button(top_frame, classroom_img_path, classroom_clicked_event, button_width, button_height) + settings_button = create_top_button(top_frame, settings_img_path, settings_clicked_event, button_width, button_height) + + # Add battery and wifi icons + def add_icon(frame, image_path, desired_width, desired_height): + # Open the image file with PIL + pil_img = Image.open(image_path) + # Resize the image to the desired dimensions + pil_img = pil_img.resize((desired_width, desired_height), Image.LANCZOS) + + # Create a PhotoImage object from the resized PIL image + img = ImageTk.PhotoImage(pil_img) + + # Create a label within the frame to display the image + image_label = tk.Label(frame, image=img, bd=0, highlightthickness=0) + image_label.image = img # Keep a reference to prevent garbage collection + image_label.pack(side=tk.LEFT, padx=10, pady=10) + + + battery_img_path = 'home\\guiImages\\batteryIcon.png' + wifi_img_path = 'home\\guiImages\\wifiIcon.png' + + battery_icon = add_icon(top_frame, battery_img_path, 75, 75) + wifi_icon = add_icon(top_frame, wifi_img_path, 75, 75) + + + def render_new_game_icon(game_list_frame, button_width, button_height): # Open the image file with PIL and resize it @@ -221,7 +246,7 @@ def initial_render(root): def display_home_screen(): root = tk.Tk() root.geometry("800x450") - root.configure(bg='#2D3039') + root.configure(bg='#33363e') initial_render(root) root.mainloop() From 016660db8faf7b8694db7e4082c516ca5d2820b4 Mon Sep 17 00:00:00 2001 From: Jeffin Johnykutty Date: Thu, 21 Mar 2024 01:45:43 -0400 Subject: [PATCH 3/4] -Add bolding to game info text -Added rounded corners to main container (insdie of root container which holds the game library and game info containers). -Added new python file that can test out methods that might be good for the gui later on. --- flask/Pipfile | 1 + flask/Pipfile.lock | 27 ++++++++++++++++++++++++++- home/homeScreenGui.py | 19 +++++++++---------- 3 files changed, 36 insertions(+), 11 deletions(-) diff --git a/flask/Pipfile b/flask/Pipfile index 390ff2cd..09122eaa 100644 --- a/flask/Pipfile +++ b/flask/Pipfile @@ -7,6 +7,7 @@ name = "pypi" flask = "*" flask-cors = "*" ttkbootstrap = "*" +customtkinter = "*" [dev-packages] diff --git a/flask/Pipfile.lock b/flask/Pipfile.lock index 78f854a4..05f185ac 100644 --- a/flask/Pipfile.lock +++ b/flask/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "5e505c84607b03e50b01c099000da2963fa54bbc7eecd3c71c0dbb7f9c9151e2" + "sha256": "d6995e9273d650b4bda1294c46f67825da8886e07ebf5e5c144212278b7772ef" }, "pipfile-spec": 6, "requires": { @@ -40,6 +40,23 @@ "markers": "platform_system == 'Windows'", "version": "==0.4.6" }, + "customtkinter": { + "hashes": [ + "sha256:14ad3e7cd3cb3b9eb642b9d4e8711ae80d3f79fb82545ad11258eeffb2e6b37c", + "sha256:fd8db3bafa961c982ee6030dba80b4c2e25858630756b513986db19113d8d207" + ], + "index": "pypi", + "markers": "python_version >= '3.7'", + "version": "==5.2.2" + }, + "darkdetect": { + "hashes": [ + "sha256:a7509ccf517eaad92b31c214f593dbcf138ea8a43b2935406bbd565e15527a85", + "sha256:b5428e1170263eb5dea44c25dc3895edd75e6f52300986353cd63533fe7df8b1" + ], + "markers": "python_version >= '3.6'", + "version": "==0.8.0" + }, "flask": { "hashes": [ "sha256:3232e0e9c850d781933cf0207523d1ece087eb8d87b23777ae38456e2fbe7c6e", @@ -139,6 +156,14 @@ "markers": "python_version >= '3.7'", "version": "==2.1.5" }, + "packaging": { + "hashes": [ + "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5", + "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9" + ], + "markers": "python_version >= '3.7'", + "version": "==24.0" + }, "pillow": { "hashes": [ "sha256:0304004f8067386b477d20a518b50f3fa658a28d44e4116970abfcd94fac34a8", diff --git a/home/homeScreenGui.py b/home/homeScreenGui.py index 4425d835..119a6de3 100644 --- a/home/homeScreenGui.py +++ b/home/homeScreenGui.py @@ -1,5 +1,6 @@ import tkinter as tk from tkinter import Canvas, Frame, Scrollbar, Label, ttk +import customtkinter as ctk import webbrowser from PIL import Image, ImageTk @@ -78,8 +79,6 @@ def add_icon(frame, image_path, desired_width, desired_height): wifi_icon = add_icon(top_frame, wifi_img_path, 75, 75) - - def render_new_game_icon(game_list_frame, button_width, button_height): # Open the image file with PIL and resize it pil_img = Image.open('home\\guiImages\\newGameIcon.png') @@ -91,7 +90,7 @@ def render_new_game_icon(game_list_frame, button_width, button_height): # Create a Tkinter button with this image img_button = tk.Button(game_list_frame, image=photo, command=open_code_editor_new_game_page, borderwidth=0, highlightthickness=0) img_button.image = photo # Keep a reference to the image - img_button.pack(side=tk.LEFT, padx=20, pady=20) + img_button.pack(side=tk.LEFT, padx=10, pady=10) img_button.bind("", lambda e, widget=img_button: on_enter(e, widget)) img_button.bind("", lambda e, widget=img_button: on_leave(e, widget)) @@ -130,10 +129,10 @@ def display_game_info(game_info_container, game_name): text_info_frame = tk.Frame(game_info_container, padx=10, pady=10, bg='#23252C') text_info_frame.pack(side=tk.LEFT, fill=tk.X, expand=True) - # Update label styles with font size and foreground color - tk.Label(text_info_frame, text=game_name, font=("Helvetica", 16), anchor='w', fg='#FFFFFF', bg='#23252C').pack(fill='x') - tk.Label(text_info_frame, text="Author: You", anchor='w', fg='#FFFFFF', bg='#23252C').pack(fill='x') - tk.Label(text_info_frame, text="Last Updated: 2/13/2024", anchor='w', fg='#FFFFFF', bg='#23252C').pack(fill='x') + # Add text into gme info frame + ctk.CTkLabel(text_info_frame, text=game_name, font=("Helvetica", 40, "bold"), anchor='w', text_color='#FFFFFF', fg_color='#23252C').pack(fill='x') + ctk.CTkLabel(text_info_frame, text="Author: You", font=("Helvetica", 20, "bold") ,anchor='w', text_color='#FFFFFF', fg_color='#23252C').pack(fill='x') + ctk.CTkLabel(text_info_frame, text="Last Updated: 2/13/2024", font=("Helvetica", 20, "bold") ,anchor='w', text_color='#FFFFFF', fg_color='#23252C').pack(fill='x') # Style update for button frame button_frame = tk.Frame(game_info_container, bg='#23252C') @@ -203,7 +202,7 @@ def on_frame_configure(canvas): # Create a game frame with the specified size game_frame = tk.Frame(game_list_frame, width=box_width, height=box_height, bg='#51535B') game_frame.pack_propagate(False) # Prevents child widgets from altering the frame's size - game_frame.pack(side=tk.LEFT, padx=20, pady=20) + game_frame.pack(side=tk.LEFT, padx=10, pady=10) # Create a label with the game name and size, and ensure it's centered game_label = tk.Label(game_frame, text=f"{game}\n", @@ -233,8 +232,8 @@ def initial_render(root): render_top_frame(top_container) # Main container frame for both the games list and game information - main_container = tk.Frame(root, bg='#23252C') - main_container.pack(side=tk.TOP, fill='both', expand=True, padx=10, pady=10) + main_container = ctk.CTkFrame(master=root, corner_radius=20, fg_color='#23252C') + main_container.pack(side=tk.TOP, fill='both', expand=True, padx=20, pady=10) # Create the game information container and pack it at the bottom of the main container From 630cdaf5058eb6a50cff010fbb8d539778af528f Mon Sep 17 00:00:00 2001 From: Jeffin Johnykutty Date: Thu, 21 Mar 2024 13:36:08 -0400 Subject: [PATCH 4/4] Enhanced functionality in `display_game_library()` to enable the play button feature. Now, when the play button is clicked, the compiler script is triggered. I've configured it to use the 'Multiplayer Tetris' JSON file as the default game. This means that whenever a user clicks the play button for any game frame (e.g., game 1, game 2, etc.), the compiler will compile the Multiplayer Tetris game. To ensure smooth operation, I added a print statement in the compiler code to verify the existence of the game JSON file path. If the file path doesn't exist, an error message is displayed. However, it appears that the `compile.js` script is unable to locate the specified file. I suspect there might be an issue within the `compile.js` script itself, as the GUI side seems to be functioning correctly. I recommend the team member assigned to the script review it for any potential errors. --- home/homeScreenGui.py | 40 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/home/homeScreenGui.py b/home/homeScreenGui.py index 119a6de3..57289584 100644 --- a/home/homeScreenGui.py +++ b/home/homeScreenGui.py @@ -1,8 +1,11 @@ import tkinter as tk -from tkinter import Canvas, Frame, Scrollbar, Label, ttk +from tkinter import Canvas, Frame, Scrollbar, Label, ttk, filedialog import customtkinter as ctk import webbrowser from PIL import Image, ImageTk +import os + + # Methods to test if cliking widgets are responsive def home_button_clicked_event(event=None): @@ -117,7 +120,7 @@ def on_leave(e, widget): widget.config(highlightbackground='grey', highlightthickness=1) -def display_game_info(game_info_container, game_name): +def display_game_info(game_info_container, game_name, game_json_path): # Clear any existing widgets in the game information container for widget in game_info_container.winfo_children(): widget.destroy() @@ -138,6 +141,34 @@ def display_game_info(game_info_container, game_name): button_frame = tk.Frame(game_info_container, bg='#23252C') button_frame.pack(side=tk.RIGHT, padx=10, pady=10) + def compile_game(json_file_path): + # Path to the compiler script + compiler_script_path = os.path.join(".", "blockly", "compile.js") + + # Check if the JSON file exists + if not os.path.exists(json_file_path): + print(f"Error: JSON file '{json_file_path}' not found.") + return + + # Construct the command to run, enclosing json_file_path in quotes + command = f"node {compiler_script_path} \"{json_file_path}\"" + + # Call the compiler script using os.system() + return_code = os.system(command) + + if return_code == 0: + # Compilation succeeded + print("Game compiled successfully!") + else: + # Compilation failed + print("Compilation failed.") + + def on_compile_click(game_json_path): + # Set the path to the game JSON file + # json_file_path = os.path.join(".", "flask", "saved", "Multiplayer Tetris.json") + compile_game(game_json_path) + + def create_button(frame, image_path, command, desired_width, desired_height): # Open the image file with PIL pil_img = Image.open(image_path) @@ -161,7 +192,8 @@ def create_button(frame, image_path, command, desired_width, desired_height): buttonHeight = 90 # Create buttons with new styling - play_button = create_button(button_frame, play_button_img_path, None, buttonWidth, buttonHeight) + # play_button = create_button(button_frame, play_button_img_path, on_compile_click, buttonWidth, buttonHeight) + play_button = create_button(button_frame, play_button_img_path, lambda: on_compile_click(game_json_path), buttonWidth, buttonHeight) edit_button = create_button(button_frame, edit_button_img_path, open_code_editor, buttonWidth, buttonHeight) upload_button = create_button(button_frame, upload_buton_img_path, None, buttonWidth, buttonHeight) @@ -208,7 +240,7 @@ def on_frame_configure(canvas): game_label = tk.Label(game_frame, text=f"{game}\n", fg='#FFFFFF', bg='#51535B', font=('Helvetica', 20)) game_label.pack(expand=True) # This will center the text in the frame - game_label.bind("", lambda event, name=game: display_game_info(game_info_container, name)) + game_label.bind("", lambda event, name=game: display_game_info(game_info_container, name, os.path.join(".", "flask", "saved", "Multiplayer Tetris.json"))) # Set the highlightthickness for normal state so that the change is visible on hover game_frame.config(highlightbackground='grey', highlightthickness=1)