From 5d7bd05a0af626f3a959da7a59dfb0637ab54a1c Mon Sep 17 00:00:00 2001 From: Ibrahim Date: Sun, 12 Mar 2023 05:53:50 +0530 Subject: [PATCH 1/2] Add an automated beautiful GUI Menu --- gui/circle_switch_off.png | Bin 0 -> 159 bytes gui/circle_switch_on.png | Bin 0 -> 870 bytes gui/dark_blue_gray_panel.png | 1 + gui/gui_view.py | 342 ++++++++++++++++++++++++++++------- main.py | 6 +- 5 files changed, 279 insertions(+), 70 deletions(-) create mode 100644 gui/circle_switch_off.png create mode 100644 gui/circle_switch_on.png create mode 100644 gui/dark_blue_gray_panel.png diff --git a/gui/circle_switch_off.png b/gui/circle_switch_off.png new file mode 100644 index 0000000000000000000000000000000000000000..3bd05f251018b5b7f454849e0368aa1adc1255df GIT binary patch literal 159 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*_=1|;R|J2nC-mSQK*5Dp-y;YjHK^20n`978f1 z-=1&eWKa}1u;Kgn`#)ox3_Oe-cc-Q8WB;?A*)P-Oa>p`3U*%bDCcPO_7flus7Px71 Xge76Zjps5z8yGxY{an^LB{Ts5)9o}l literal 0 HcmV?d00001 diff --git a/gui/circle_switch_on.png b/gui/circle_switch_on.png new file mode 100644 index 0000000000000000000000000000000000000000..dd9d40a8ed7eaa177ec57da40635865db2ac2cea GIT binary patch literal 870 zcmV-s1DX7ZP);0l z4+gk7SoZdv8{z6c=-=usizkuUpK$gm#3ud^Wme;?Oq$zuaYXg?VzSD`4MY3R9A zSP3h77#{aSceDMrj^>f6A96VrQvx8l4AF0*uWko5{RwHfD zM9f@Plp@>fr47nGVxCYlmldT*cT)k<}%CIYrKNLW^G7Q8D}0G|8hPr-&Yg%X`xY@+p{C zPHmGsDs0O^25=}Q-_3p&f?djpLWb?q;}m6lyDFWGX1EP;I63=cLLA9*fw~2N3@bRY>*G z&q8)lir6OBWrYY*gG%8|D*GW)v}J{CtP4FG$jF%M9T8;IvX>41c20>Gdb0Uv=`Ak* wof4R(H!Ev;F*GQY|2O+uV_hU@tcwJVKXJAW=A`WG9smFU07*qoM6N<$f*LN2b^rhX literal 0 HcmV?d00001 diff --git a/gui/dark_blue_gray_panel.png b/gui/dark_blue_gray_panel.png new file mode 100644 index 0000000..41c284d --- /dev/null +++ b/gui/dark_blue_gray_panel.png @@ -0,0 +1 @@ +file:///home/ibrahim/PycharmProjects/arcade/arcade/arcade/resources/gui_basic_assets/window/dark_blue_gray_panel.png \ No newline at end of file diff --git a/gui/gui_view.py b/gui/gui_view.py index 12ffdc2..81a9151 100644 --- a/gui/gui_view.py +++ b/gui/gui_view.py @@ -4,6 +4,7 @@ """ import arcade import arcade.gui + from base_view import BaseView @@ -11,86 +12,293 @@ class GuiView(BaseView): def __init__(self, time_on_screen): super().__init__(time_on_screen) - - # --- Required for all code that uses UI element, - # a UIManager to handle the UI. + + self.count = 0 self.manager = arcade.gui.UIManager() - self.manager.enable() - - # Set background color - arcade.set_background_color(arcade.color.DARK_BLUE_GRAY) - - # Create a vertical BoxGroup to align buttons - self.v_box = arcade.gui.UIBoxLayout() - - # Create a text label - ui_text_label = arcade.gui.UITextArea(text="This is a Text Widget", - width=500, - height=40, - font_size=24, - font_name="Kenney Future") - self.v_box.add(ui_text_label.with_space_around(bottom=0)) - - text = "The real danger is not that computers will begin to think like people, " \ - "but that people will begin " \ - "to think like computers. - Sydney Harris (Journalist)" - ui_text_label = arcade.gui.UITextArea(text=text, - width=500, - height=60, - font_size=12, - font_name="Arial") - self.v_box.add(ui_text_label.with_space_around(bottom=0)) - - # Create a UIFlatButton - ui_flatbutton = arcade.gui.UIFlatButton(text="Instructions", width=200) - self.v_box.add(ui_flatbutton.with_space_around(bottom=20)) - - # Create a UIFlatButton - ui_flatbutton = arcade.gui.UIFlatButton(text="Start Game", width=200) - self.v_box.add(ui_flatbutton.with_space_around(bottom=20)) - - # Create a UIFlatButton - ui_flatbutton = arcade.gui.UIFlatButton(text="Exit", width=200) - self.v_box.add(ui_flatbutton.with_space_around(bottom=20)) - - # Handle Clicks - @ui_flatbutton.event("on_click") - def on_click_flatbutton(event): - print("UIFlatButton pressed", event) - - # Create a UITextureButton - texture = arcade.load_texture(":resources:onscreen_controls/flat_dark/play.png") - ui_texture_button = arcade.gui.UITextureButton(texture=texture) - - # Handle Clicks - @ui_texture_button.event("on_click") - def on_click_texture_button(event): - print("UITextureButton pressed", event) - - self.v_box.add(ui_texture_button.with_space_around(bottom=20)) - - # Create a widget to hold the v_box widget, that will center the buttons - self.manager.add( - arcade.gui.UIAnchorWidget( - anchor_x="center_x", - anchor_y="bottom", - child=self.v_box) + + self.resume_button = arcade.gui.UIFlatButton(text="Resume", width=150) + start_new_game_button = arcade.gui.UIFlatButton(text="Start New Game", width=150) + volume_button = arcade.gui.UIFlatButton(text="Volume", width=150) + self.options_button = arcade.gui.UIFlatButton(text="Options", width=150) + self.options_menu = None + + exit_button = arcade.gui.UIFlatButton(text="Exit", width=320) + + # Initialise a grid in which widgets can be arranged. + self.grid = arcade.gui.UIGridLayout(column_count=2, row_count=3, horizontal_spacing=20, vertical_spacing=20) + + # Adding the buttons to the layout. + self.grid.add(self.resume_button, col_num=0, row_num=0) + self.grid.add(start_new_game_button, col_num=1, row_num=0) + self.grid.add(volume_button, col_num=0, row_num=1) + self.grid.add(self.options_button, col_num=1, row_num=1) + self.grid.add(exit_button, col_num=0, row_num=2, col_span=2) + + self.anchor = self.manager.add(arcade.gui.UIAnchorLayout()) + + self.anchor.add( + anchor_x="center_x", + anchor_y="center_y", + child=self.grid, ) + @volume_button.event("on_click") + def on_click_volume_button(event): + self.volume_menu = SubMenu( + "Volume Menu", "How do you like your volume?", "Enable Sound", + ["Play: Rock", "Play: Punk", "Play: Pop"], + "Adjust Volume", + ) + self.manager.add( + self.volume_menu, + layer=1 + ) + + @self.options_button.event("on_click") + def on_click_options_button(event): + self.options_menu = SubMenu( + "Funny Menu", "Too much fun here", "Fun?", + ["Make Fun", "Enjoy Fun", "Like Fun"], + "Adjust Fun" + ) + self.manager.add( + self.options_menu, + layer=1 + ) + def on_click_start(self, event): print("Start:", event) def on_draw(self): - arcade.start_render() + self.clear() + self.draw_line_one("GUI Menu") self.manager.draw() - self.draw_line_one("GUI Controls") def on_update(self, delta_time): self.total_time += delta_time if self.total_time > self.time_on_screen: if not self.window.view_list: - self.window.create_views() + self.window.create_views(13) new_view = self.window.view_list.pop(0) - self.window.show_view(new_view) \ No newline at end of file + self.window.show_view(new_view) + elif self.total_time > 0.3 and self.count == 0: + self.options_button.hovered = True + self.count += 1 + elif self.total_time > 0.35 and self.count == 1: + self.options_button.hovered = False + self.options_button.pressed = True + self.count += 1 + elif self.total_time > 0.4 and self.count == 2: + self.options_button.pressed = False + self.options_button.dispatch_event( + "on_click", + arcade.gui.UIOnClickEvent(self.options_button, self.options_button.x, self.options_button.y) + ) + self.count += 1 + elif self.total_time > 4.95 and self.count == 21: + self.resume_button.pressed = True + + if not hasattr(self.options_menu, "dispatch_event"): + return + + if self.total_time > 0.75 and self.count == 3: + self.options_menu.dispatch_event("on_update", 1) + self.count += 1 + elif self.total_time > 0.85 and self.count == 4: + self.options_menu.dispatch_event("on_update", 2) + self.count += 1 + elif self.total_time > 1 and self.count == 5: + self.options_menu.dispatch_event("on_update", 2) + self.count += 1 + elif self.total_time > 1.25 and self.count == 6: + self.options_menu.dispatch_event("on_update", 3) + self.count += 1 + elif self.total_time > 2 and self.count == 7: + self.options_menu.dispatch_event("on_update", 3) + self.count += 1 + elif self.total_time > 2.25 and self.count == 8: + self.options_menu.dispatch_event("on_update", 4) + self.count += 1 + elif self.total_time > 2.85 and self.count == 9: + self.options_menu.dispatch_event("on_update", 12) + self.count += 1 + elif self.total_time > 3.0 and self.count == 10: + self.options_menu.dispatch_event("on_update", 5) + self.count += 1 + elif self.total_time > 3.25 and self.count == 11: + self.options_menu.dispatch_event("on_update", 6) + self.count += 1 + elif self.total_time > 3.35 and self.count == 12: + self.options_menu.dispatch_event("on_update", 6) + self.count += 1 + elif self.total_time > 3.45 and self.count == 13: + self.options_menu.dispatch_event("on_update", 6) + self.count += 1 + elif self.total_time > 3.55 and self.count == 14: + self.options_menu.dispatch_event("on_update", 7) + self.count += 1 + elif self.total_time > 3.65 and self.count == 15: + self.options_menu.dispatch_event("on_update", 7) + self.count += 1 + elif self.total_time > 3.75 and self.count == 16: + self.options_menu.dispatch_event("on_update", 7) + self.count += 1 + elif self.total_time > 3.85 and self.count == 17: + self.options_menu.dispatch_event("on_update", 8) + self.count += 1 + elif self.total_time > 4.2 and self.count == 18: + self.options_menu.dispatch_event("on_update", 9) + self.count += 1 + elif self.total_time > 4.5 and self.count == 19: + self.options_menu.dispatch_event("on_update", 10) + self.count += 1 + elif self.total_time > 4.75 and self.count == 20: + self.options_menu.dispatch_event("on_update", 11) + self.count += 1 + + + +class SubMenu(arcade.gui.UIMouseFilterMixin, arcade.gui.UIAnchorLayout): + """Acts like a fake view/window.""" + + def __init__(self, + title: str, + input_text: str, + toggle_label: str, + dropdown_options: list[str], + slider_label: str, + **kwargs + ): + super().__init__(size_hint=(1, 1), **kwargs) + + # Setup frame which will act like the window. + frame = self.add(arcade.gui.UIAnchorLayout(width=300, height=getattr(kwargs, "height", 400), size_hint=None)) + frame.with_padding(all=20) + + # Add a background to the window. + # Nine patch smoothes the edges. + frame.with_background(texture=arcade.gui.NinePatchTexture( + left=7, + right=7, + bottom=7, + top=7, + texture=arcade.load_texture( + "dark_blue_gray_panel.png" + ) + )) + + self.back_button = arcade.gui.UIFlatButton(text="Back", width=250) + # The type of event listener we used earlier for the button will not work here. + self.back_button.on_click = self.on_click_back_button + + title_label = arcade.gui.UILabel(text=title, align="center", font_size=20, multiline=False) + # Adding some extra space around the title. + title_label_space = arcade.gui.UISpace(height=30, color=arcade.color.DARK_BLUE_GRAY) + + self.input_text = arcade.gui.UIInputText(text=input_text, width=250).with_border() + + # Load the on-off textures. + on_texture = arcade.load_texture("circle_switch_on.png") + off_texture = arcade.load_texture("circle_switch_off.png") + + # Create the on-off toggle and a label + toggle_label = arcade.gui.UILabel(text=toggle_label) + self.toggle = arcade.gui.UITextureToggle( + on_texture=on_texture, + off_texture=off_texture, + width=20, + height=20 + ) + + # Align toggle and label horizontally next to each other + toggle_group = arcade.gui.UIBoxLayout(vertical=False, space_between=5) + toggle_group.add(self.toggle) + toggle_group.add(toggle_label) + + # Create dropdown with a specified default. + self.dropdown = arcade.gui.UIDropdown(default=dropdown_options[0], options=dropdown_options, height=20, width=250) + + slider_label = arcade.gui.UILabel(text=slider_label) + pressed_style = arcade.gui.UISlider.UIStyle(filled_bar=arcade.color.GREEN, unfilled_bar=arcade.color.RED) + default_style = arcade.gui.UISlider.UIStyle() + style_dict = {"press": pressed_style, "normal": default_style, "hover": default_style, "disabled": default_style} + # Configuring the styles is optional. + self.slider = arcade.gui.UISlider(value=50, width=250, style=style_dict) + + widget_layout = arcade.gui.UIBoxLayout(align="left", space_between=10) + widget_layout.add(title_label) + widget_layout.add(title_label_space) + widget_layout.add(self.input_text) + widget_layout.add(toggle_group) + widget_layout.add(self.dropdown) + widget_layout.add(slider_label) + widget_layout.add(self.slider) + + widget_layout.add(self.back_button) + + frame.add(child=widget_layout, anchor_x="center_x", anchor_y="top") + + def on_click_back_button(self, event): + # Removes the widget from the manager. + # After this the manager will respond to its events like it previously did. + self.parent.remove(self) + + + def on_update(self, event_number): + match event_number: + case 1: + self.input_text.dispatch_event( + "on_event", + arcade.gui.UIMousePressEvent( + self.input_text, + self.input_text.x + 1, + self.input_text.y + 1, + 0, + 0, + ) + ) + case 2: + self.input_text.dispatch_event( + "on_event", + arcade.gui.UITextEvent( + self.input_text, + "?", + ) + ) + case 3: + self.toggle.value = not self.toggle.value + case 4: + self.dropdown._show_overlay() + case 5: + child = self.dropdown._layout._children[1].child + child.dispatch_event( + "on_click", + arcade.gui.UIOnClickEvent(child, child.x, child.y) + ) + case 6: + self.slider.pressed = True + self.slider.dispatch_event( + "on_event", + arcade.gui.UIMouseDragEvent(self.slider, self.slider.value_x + 20, 0, 0, 0, 0, 0) + ) + case 7: + self.slider.pressed = True + self.slider.dispatch_event( + "on_event", + arcade.gui.UIMouseDragEvent(self.slider, self.slider.value_x - 25, 0, 0, 0, 0, 0) + ) + case 8: + self.slider.pressed = False + case 9: + self.back_button.hovered = True + case 10: + self.back_button.hovered = False + self.back_button.pressed = True + case 11: + self.back_button.pressed = False + self.on_click_back_button(arcade.gui.UIOnClickEvent(self.back_button, 0, 0)) + case 12: + child = self.dropdown._layout._children[1].child + child.pressed = True diff --git a/main.py b/main.py index f132608..4efe6d2 100644 --- a/main.py +++ b/main.py @@ -118,9 +118,9 @@ def create_views(self, count): elif count == 12 and not prototype: self.loading_view.line_two_text = "Tiled map" - # from gui.gui_view import GuiView - # view = GuiView(4.0) - # self.view_list.append(view) + from gui.gui_view import GuiView + view = GuiView(5.0) + self.view_list.append(view) elif count == 13 and not prototype: from tiled_map.tiled_map import TiledMap From 31aa6c7a55241ed76c2eddeb7348172d3e32209d Mon Sep 17 00:00:00 2001 From: Ibrahim Date: Sun, 12 Mar 2023 05:55:17 +0530 Subject: [PATCH 2/2] Revert added config for easy testing --- gui/gui_view.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gui/gui_view.py b/gui/gui_view.py index 81a9151..c8a6b4e 100644 --- a/gui/gui_view.py +++ b/gui/gui_view.py @@ -79,7 +79,7 @@ def on_update(self, delta_time): if self.total_time > self.time_on_screen: if not self.window.view_list: - self.window.create_views(13) + self.window.create_views() new_view = self.window.view_list.pop(0) self.window.show_view(new_view)