1 #include "menu.h"
2
3 extern bool g_exit;
4 extern Mouse g_mouse;
5
MenuitemOption(const string name,const string value)6 MenuitemOption::MenuitemOption(const string name, const string value) :
7 m_name(name),m_value(value)
8 {}
9
option_id(const menuoptions_t & options,const string & name)10 int MenuitemOption::option_id(const menuoptions_t& options,const string &name)
11 {
12 for(unsigned int i=0;i<options.size();++i) {
13 if (options[i].m_name == name)
14 return i;
15 }
16
17 return -1;
18 }
19
20
Menuitem(const string & name,const string & text,const string & action,const string & submenu,menuoptions_t options,int selected_option)21 Menuitem::Menuitem(const string &name,const string &text,const string &action,const string &submenu,
22 menuoptions_t options,int selected_option) :
23 m_name(name),m_text(text),m_action(action),m_submenu(submenu),m_options(options),m_selected_option(selected_option)
24 {}
25
Menu(menuitems_t & items,const string & parent)26 Menu::Menu(menuitems_t &items,const string &parent) :
27 m_items(items),m_selected(0),m_parent(parent)
28 {}
29
~Menu()30 Menu::~Menu()
31 {}
32
add_item(Menuitem item)33 void Menu::add_item(Menuitem item)
34 {
35 m_items.push_back(item);
36 }
37
next_item(void)38 void Menu::next_item(void)
39 {
40 m_selected++;
41 if (m_selected>=(int)m_items.size())
42 m_selected = 0;
43 }
44
prev_item(void)45 void Menu::prev_item(void)
46 {
47 m_selected--;
48 if (m_selected<0)
49 m_selected = (m_items.size()-1);
50 }
51
selected_item_next_option(void)52 void Menu::selected_item_next_option(void)
53 {
54 Menuitem &item = m_items[m_selected];
55 if (item.m_options.empty()) // item does not have options
56 return;
57
58 item.m_selected_option++;
59 if (item.m_selected_option>=(int)item.m_options.size())
60 item.m_selected_option = 0;
61
62 if (!item.m_action.empty()) // if options have action set, set it every time the selected option changes
63 add_action(item.m_action, item.m_options[item.m_selected_option].m_value );
64 }
65
selected_item_prev_option(void)66 void Menu::selected_item_prev_option(void)
67 {
68 Menuitem &item = m_items[m_selected];
69 if (item.m_options.empty()) // item does not have options
70 return;
71
72 item.m_selected_option--;
73
74 if (item.m_selected_option<0)
75 item.m_selected_option = item.m_options.size() - 1;
76
77 if (!item.m_action.empty()) // if options have action set, set it every time the selected option changes
78 add_action(item.m_action, item.m_options[item.m_selected_option].m_value );
79 }
80
add_action(const string & action_name,const string & action_value)81 void Menu::add_action(const string &action_name, const string &action_value)
82 {
83 m_pending_actions.push_back(make_pair(action_name,action_value));
84 }
85
get_pending_actions(void)86 vec_str_pair_t Menu::get_pending_actions(void)
87 {
88 vec_str_pair_t actions = m_pending_actions;
89 m_pending_actions.clear();
90 return actions;
91 }
92
93
collect_options(void)94 map_str_str_t Menu::collect_options(void)
95 {
96 map_str_str_t opts;
97
98 for (menuitems_t::const_iterator it=m_items.begin(),end=m_items.end();it!=end;++it) {
99 Menuitem mi = *it;
100 if (mi.m_options.empty()) continue;
101 if (mi.m_name.empty()) continue;
102
103 opts[mi.m_name] = mi.m_options[mi.m_selected_option].m_value;
104 }
105 return opts;
106 }
107
activate_item(void)108 string Menu::activate_item(void)
109 {
110 Menuitem &item = m_items[m_selected];
111
112 if (!item.m_options.empty()) { // item does have options
113 selected_item_next_option();
114 } else if (!item.m_action.empty()) { // action
115 if (item.m_action == ":disabled")
116 return "";
117
118 add_action(item.m_action, "");
119
120 } else if (!item.m_submenu.empty()) {
121 if (item.m_submenu==":up_level")
122 return m_parent;
123 else
124 return item.m_submenu;
125 }
126
127 return "";
128 }
129
switch_to_item(int item)130 void Menu::switch_to_item(int item)
131 {
132 item = clamp<int>(item, 0, m_items.size());
133 m_selected = item;
134 }
135
136
GraphicMenu(menuitems_t & items,MFont * font,float font_size,vec4 color,vec4 color_hi)137 GraphicMenu::GraphicMenu(menuitems_t &items,MFont *font,float font_size,vec4 color,vec4 color_hi) :
138 Menu(items),m_font(font),m_font_size(font_size),m_color(color),m_color_hi(color_hi),m_bboxes()
139 {
140 }
141
draw(vec2 pos,bool centered)142 void GraphicMenu::draw(vec2 pos, bool centered)
143 {
144 m_font->setup_drawing();
145
146 glPushMatrix();
147 glTranslate(vec3(pos));
148
149 m_bboxes.clear();
150
151 for(int i=0;i<(int)m_items.size();++i) {
152 Menuitem &item = m_items[i];
153 float ypos = m_font->line_sep() * i * m_font_size;
154 float xpos = 0.0;
155 vec4 color;
156 if (m_selected == i)
157 color = m_color_hi;
158 else
159 color = m_color;
160
161 string text;
162 if (!item.m_options.empty()) {
163 if (m_selected == i) {
164 text = item.m_text + ": <" + item.m_options[item.m_selected_option].m_name + ">";
165 xpos += (m_font->size_of_text("<>",m_font_size))/2.0f;
166 } else {
167 text = item.m_text + ": " + item.m_options[item.m_selected_option].m_name;
168 }
169 } else {
170 text = item.m_text;
171 }
172
173 if (m_selected == i) {
174 m_font->print_text_with_shadow(text.c_str(),vec2(xpos,ypos),m_font_size,centered,color);
175 } else {
176 m_font->print_text(text.c_str(),vec2(xpos,ypos),m_font_size,centered,color);
177 }
178
179 AABB bb = m_font->bbox(text.c_str(),m_font_size,vec2(xpos,ypos)+pos,centered);
180 m_bboxes.push_back(bb);
181 }
182 glPopMatrix();
183
184 m_font->finish_drawing();
185 }
186
mouse_moved_to(const vec2 p)187 void GraphicMenu::mouse_moved_to(const vec2 p)
188 {
189 for (unsigned int i=0;i<m_bboxes.size();++i) {
190 if (m_bboxes[i].contains_point(p)) { // return on first match
191 m_selected = i;
192 return;
193 }
194 }
195 }
196
MenuSystem()197 MenuSystem::MenuSystem() :
198 m_current_menu(NULL)
199 {}
200
add_menu(const string & menu_name,Menu * menu)201 void MenuSystem::add_menu(const string &menu_name, Menu *menu)
202 {
203 m_menus[menu_name] = menu;
204 if (menu_name == "main")
205 m_current_menu = menu;
206 }
207
switch_to_menu(const string & menu_name)208 void MenuSystem::switch_to_menu(const string &menu_name)
209 {
210 m_current_menu = m_menus[menu_name];
211 }
212
switch_to_item(int item)213 void MenuSystem::switch_to_item(int item)
214 {
215 if (m_current_menu)
216 m_current_menu->switch_to_item(item);
217 }
218
draw(vec2 pos,bool centered)219 void MenuSystem::draw(vec2 pos, bool centered)
220 {
221 if (m_current_menu)
222 m_current_menu->draw(pos,centered);
223 }
224
get_pending_actions(void)225 vec_str_pair_t MenuSystem::get_pending_actions(void)
226 {
227 vec_str_pair_t actions;
228 for(menustore_t::const_iterator it=m_menus.begin();it!=m_menus.end();++it) {
229 vec_str_pair_t a = (*it).second->get_pending_actions();
230 copy(a.begin(),a.end(),back_inserter(actions));
231 }
232 return actions;
233 }
234
up_level(void)235 bool MenuSystem::up_level(void)
236 {
237 if (!m_current_menu->m_parent.empty()) {
238 m_current_menu = m_menus[m_current_menu->m_parent];
239 return true;
240 } else {
241 return false;
242 }
243 }
244
activate(void)245 void MenuSystem::activate(void)
246 {
247 string new_menu = m_current_menu->activate_item();
248 if (!new_menu.empty()) {
249 if (m_current_menu->m_parent != new_menu) {
250 m_menus[new_menu]->m_selected = 0; // reset the index unless returning
251 m_menus[new_menu]->m_parent = menup_to_str(m_current_menu);
252 }
253 m_current_menu = m_menus[new_menu];
254 }
255 }
256
key_action(int key)257 bool MenuSystem::key_action(int key)
258 {
259 switch(key) {
260 case GLFW_KEY_UP: if (m_current_menu) m_current_menu->prev_item(); break;
261 case GLFW_KEY_DOWN: if (m_current_menu) m_current_menu->next_item(); break;
262 case GLFW_KEY_LEFT: if (m_current_menu) m_current_menu->selected_item_prev_option(); break;
263 case GLFW_KEY_RIGHT: if (m_current_menu) m_current_menu->selected_item_next_option(); break;
264
265 case GLFW_KEY_ENTER:
266 case GLFW_KEY_KP_ENTER:
267 activate();
268 break;
269 case GLFW_KEY_ESC:
270 if (!up_level())
271 return true; // top exit
272 break;
273 }
274
275 return false;
276 }
277
mouse_action(int button)278 bool MenuSystem::mouse_action(int button)
279 {
280 if (button==GLFW_MOUSE_BUTTON_LEFT) {
281 activate();
282 }
283
284 return false;
285 }
286
mouse_moved(void)287 void MenuSystem::mouse_moved(void)
288 {
289 if (m_current_menu) {
290 vec2 pos = g_mouse.get_pos();
291 m_current_menu->mouse_moved_to(pos);
292 }
293 }
294
mouse_wheel(int dir)295 void MenuSystem::mouse_wheel(int dir)
296 {
297 if (m_current_menu) {
298 if (dir<0)
299 m_current_menu->prev_item();
300 else if (dir>0)
301 m_current_menu->next_item();
302 }
303 }
304
305
menup_to_str(Menu * menu)306 string MenuSystem::menup_to_str(Menu *menu)
307 {
308 for(menustore_t::const_iterator it=m_menus.begin();it!=m_menus.end();++it) {
309 if ((*it).second == menu)
310 return ((*it).first);
311 }
312 return "";
313 }
314
str_to_menup(const string & str)315 Menu *MenuSystem::str_to_menup(const string &str)
316 {
317 return m_menus[str];
318 }
319