diff --git a/flask/Pipfile b/flask/Pipfile index a40b724b..09122eaa 100644 --- a/flask/Pipfile +++ b/flask/Pipfile @@ -6,6 +6,8 @@ name = "pypi" [packages] flask = "*" flask-cors = "*" +ttkbootstrap = "*" +customtkinter = "*" [dev-packages] diff --git a/flask/Pipfile.lock b/flask/Pipfile.lock index bb6ea092..05f185ac 100644 --- a/flask/Pipfile.lock +++ b/flask/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "08e5722aa464adfe98b1eb46c2dc84865e3893dab6eb4d729e43cb720724521c" + "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,97 @@ "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", + "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..57289584 100644 --- a/home/homeScreenGui.py +++ b/home/homeScreenGui.py @@ -1,39 +1,112 @@ import tkinter as tk -from tkinter import Canvas, Frame, Scrollbar, Label +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): + 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 on_enter(e, widget): + widget.config(highlightbackground='yellow', highlightthickness=2) + +def on_leave(e, widget): + widget.config(highlightbackground='grey', highlightthickness=1) + +def render_top_frame(root): + 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): + # 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 + 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) -#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) + 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 + 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) - # Set the highlightthickness for normal state so that the change is visible on hover - new_game_frame.config(highlightbackground='grey', highlightthickness=1) + # 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=10, pady=10) - # 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)) + 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(event): + +# 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) @@ -47,198 +120,168 @@ 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() - # 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') + # 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') + 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 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) + # 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, 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) 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) - + 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", - 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)) + 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) - # 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 = 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 - 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='#33363e') initial_render(root) root.mainloop() -display_home_screen() - - - - - - +display_home_screen()