menu_05.py Full Listing
menu_05.py
1"""
2Menu.
3
4Shows the usage of almost every gui widget, switching views and making a modal.
5"""
6
7from typing import List
8
9import arcade
10import arcade.gui
11
12# Screen title and size
13SCREEN_WIDTH = 800
14SCREEN_HEIGHT = 600
15SCREEN_TITLE = "Making a Menu"
16
17
18class MainView(arcade.View):
19 """This is the class where your normal game would go."""
20
21 def __init__(self):
22 super().__init__()
23
24 self.manager = arcade.gui.UIManager()
25
26 switch_menu_button = arcade.gui.UIFlatButton(text="Pause", width=150)
27
28 # Initialise the button with an on_click event.
29 @switch_menu_button.event("on_click")
30 def on_click_switch_button(event):
31 # Passing the main view into menu view as an argument.
32 menu_view = MenuView(self)
33 self.window.show_view(menu_view)
34
35 # Use the anchor to position the button on the screen.
36 self.anchor = self.manager.add(arcade.gui.UIAnchorLayout())
37
38 self.anchor.add(
39 anchor_x="center_x",
40 anchor_y="center_y",
41 child=switch_menu_button,
42 )
43
44 def on_hide_view(self):
45 # Disable the UIManager when the view is hidden.
46 self.manager.disable()
47
48 def on_show_view(self):
49 """This is run once when we switch to this view"""
50 arcade.set_background_color(arcade.color.DARK_BLUE_GRAY)
51
52 # Enable the UIManager when the view is showm.
53 self.manager.enable()
54
55 def on_draw(self):
56 """Render the screen."""
57 # Clear the screen
58 self.clear()
59
60 # Draw the manager.
61 self.manager.draw()
62
63
64class MenuView(arcade.View):
65 """Main menu view class."""
66
67 def __init__(self, main_view):
68 super().__init__()
69
70 self.manager = arcade.gui.UIManager()
71
72 resume_button = arcade.gui.UIFlatButton(text="Resume", width=150)
73 start_new_game_button = arcade.gui.UIFlatButton(text="Start New Game", width=150)
74 volume_button = arcade.gui.UIFlatButton(text="Volume", width=150)
75 options_button = arcade.gui.UIFlatButton(text="Options", width=150)
76
77 exit_button = arcade.gui.UIFlatButton(text="Exit", width=320)
78
79 # Initialise a grid in which widgets can be arranged.
80 self.grid = arcade.gui.UIGridLayout(
81 column_count=2, row_count=3, horizontal_spacing=20, vertical_spacing=20
82 )
83
84 # Adding the buttons to the layout.
85 self.grid.add(resume_button, column=0, row=0)
86 self.grid.add(start_new_game_button, column=1, row=0)
87 self.grid.add(volume_button, column=0, row=1)
88 self.grid.add(options_button, column=1, row=1)
89 self.grid.add(exit_button, column=0, row=2, column_span=2)
90
91 self.anchor = self.manager.add(arcade.gui.UIAnchorLayout())
92
93 self.anchor.add(
94 anchor_x="center_x",
95 anchor_y="center_y",
96 child=self.grid,
97 )
98
99 self.main_view = main_view
100
101 @resume_button.event("on_click")
102 def on_click_resume_button(event):
103 # Pass already created view because we are resuming.
104 self.window.show_view(self.main_view)
105
106 @start_new_game_button.event("on_click")
107 def on_click_start_new_game_button(event):
108 # Create a new view because we are starting a new game.
109 main_view = MainView()
110 self.window.show_view(main_view)
111
112 @exit_button.event("on_click")
113 def on_click_exit_button(event):
114 arcade.exit()
115
116 @volume_button.event("on_click")
117 def on_click_volume_button(event):
118 volume_menu = SubMenu(
119 "Volume Menu",
120 "How do you like your volume?",
121 "Enable Sound",
122 ["Play: Rock", "Play: Punk", "Play: Pop"],
123 "Adjust Volume",
124 )
125 self.manager.add(volume_menu, layer=1)
126
127 @options_button.event("on_click")
128 def on_click_options_button(event):
129 options_menu = SubMenu(
130 "Funny Menu",
131 "Too much fun here",
132 "Fun?",
133 ["Make Fun", "Enjoy Fun", "Like Fun"],
134 "Adjust Fun",
135 )
136 self.manager.add(options_menu, layer=1)
137
138 def on_hide_view(self):
139 # Disable the UIManager when the view is hidden.
140 self.manager.disable()
141
142 def on_show_view(self):
143 """This is run once when we switch to this view"""
144
145 # Makes the background darker
146 arcade.set_background_color([rgb - 50 for rgb in arcade.color.DARK_BLUE_GRAY])
147
148 # Enable the UIManager when the view is showm.
149 self.manager.enable()
150
151 def on_draw(self):
152 """Render the screen."""
153 # Clear the screen
154 self.clear()
155 self.manager.draw()
156
157
158class SubMenu(arcade.gui.UIMouseFilterMixin, arcade.gui.UIAnchorLayout):
159 """Acts like a fake view/window."""
160
161 def __init__(
162 self,
163 title: str,
164 input_text: str,
165 toggle_label: str,
166 dropdown_options: List[str],
167 slider_label: str,
168 ):
169 super().__init__(size_hint=(1, 1))
170
171 # Setup frame which will act like the window.
172 frame = self.add(arcade.gui.UIAnchorLayout(width=300, height=400, size_hint=None))
173 frame.with_padding(all=20)
174
175 # Add a background to the window.
176 # Nine patch smoothes the edges.
177 frame.with_background(
178 texture=arcade.gui.NinePatchTexture(
179 left=7,
180 right=7,
181 bottom=7,
182 top=7,
183 texture=arcade.load_texture(
184 ":resources:gui_basic_assets/window/dark_blue_gray_panel.png"
185 ),
186 )
187 )
188
189 back_button = arcade.gui.UIFlatButton(text="Back", width=250)
190 # The type of event listener we used earlier for the button will not work here.
191 back_button.on_click = self.on_click_back_button
192
193 title_label = arcade.gui.UILabel(text=title, align="center", font_size=20, multiline=False)
194 # Adding some extra space around the title.
195 title_label_space = arcade.gui.UISpace(height=30, color=arcade.color.DARK_BLUE_GRAY)
196
197 input_text_widget = arcade.gui.UIInputText(text=input_text, width=250).with_border()
198
199 # Load the on-off textures.
200 on_texture = arcade.load_texture(
201 ":resources:gui_basic_assets/simple_checkbox/circle_on.png"
202 )
203 off_texture = arcade.load_texture(
204 ":resources:gui_basic_assets/simple_checkbox/circle_off.png"
205 )
206
207 # Create the on-off toggle and a label
208 toggle_label = arcade.gui.UILabel(text=toggle_label)
209 toggle = arcade.gui.UITextureToggle(
210 on_texture=on_texture, off_texture=off_texture, width=20, height=20
211 )
212
213 # Align toggle and label horizontally next to each other
214 toggle_group = arcade.gui.UIBoxLayout(vertical=False, space_between=5)
215 toggle_group.add(toggle)
216 toggle_group.add(toggle_label)
217
218 # Create dropdown with a specified default.
219 dropdown = arcade.gui.UIDropdown(
220 default=dropdown_options[0], options=dropdown_options, height=20, width=250
221 )
222
223 slider_label = arcade.gui.UILabel(text=slider_label)
224 pressed_style = arcade.gui.UISlider.UIStyle(
225 filled_track=arcade.color.GREEN, unfilled_track=arcade.color.RED
226 )
227 default_style = arcade.gui.UISlider.UIStyle()
228 style_dict = {
229 "press": pressed_style,
230 "normal": default_style,
231 "hover": default_style,
232 "disabled": default_style,
233 }
234 # Configuring the styles is optional.
235 slider = arcade.gui.UISlider(value=50, width=250, style=style_dict)
236
237 widget_layout = arcade.gui.UIBoxLayout(align="left", space_between=10)
238 widget_layout.add(title_label)
239 widget_layout.add(title_label_space)
240 widget_layout.add(input_text_widget)
241 widget_layout.add(toggle_group)
242 widget_layout.add(dropdown)
243 widget_layout.add(slider_label)
244 widget_layout.add(slider)
245
246 widget_layout.add(back_button)
247
248 frame.add(child=widget_layout, anchor_x="center_x", anchor_y="top")
249
250 def on_click_back_button(self, event):
251 # Removes the widget from the manager.
252 # After this the manager will respond to its events like it previously did.
253 self.parent.remove(self)
254
255
256def main():
257 window = arcade.Window(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE, resizable=True)
258 main_view = MainView()
259 window.show_view(main_view)
260 arcade.run()
261
262
263if __name__ == "__main__":
264 main()