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