1 ///////////////////////////////////////////////////////////////////////////////
2 // Copyright (C) 2004-2011 by The Allacrost Project
3 // Copyright (C) 2012-2016 by Bertram (Valyria Tear)
4 // All Rights Reserved
5 //
6 // This code is licensed under the GNU GPL version 2. It is free software
7 // and you may modify it and/or redistribute it under the terms of this license.
8 // See http://www.gnu.org/copyleft/gpl.html for details.
9 ///////////////////////////////////////////////////////////////////////////////
10
11 /** ****************************************************************************
12 *** \file menu_window.h
13 *** \author Raj Sharma, roos@allacrost.org
14 *** \author Yohann Ferreira, yohann ferreira orange fr
15 *** \brief Header file for menu window class
16 *** ***************************************************************************/
17
18 #include "menu_window.h"
19
20 #include "engine/video/video.h"
21
22 #include "utils/utils_common.h"
23
24 using namespace vt_utils;
25 using namespace vt_video;
26 using namespace vt_video::private_video;
27 using namespace vt_gui::private_gui;
28
29 namespace vt_gui
30 {
31
MenuWindow()32 MenuWindow::MenuWindow() :
33 _window_state(VIDEO_MENU_STATE_HIDDEN)
34 {
35 _skin = GUIManager->_GetDefaultMenuSkin();
36 }
37
38
39
Create(const std::string & skin_name,float w,float h,int32_t visible_flags,int32_t shared_flags)40 bool MenuWindow::Create(const std::string &skin_name, float w, float h, int32_t visible_flags, int32_t shared_flags)
41 {
42 _skin = GUIManager->_GetMenuSkin(skin_name);
43 if(_skin == nullptr) {
44 IF_PRINT_WARNING(VIDEO_DEBUG) << "the requested menu skin was not found: " << skin_name << std::endl;
45 return false;
46 }
47
48 return Create(w, h, visible_flags, shared_flags);
49 }
50
51
52
Create(float w,float h,int32_t visible_flags,int32_t shared_flags)53 bool MenuWindow::Create(float w, float h, int32_t visible_flags, int32_t shared_flags)
54 {
55 if(w <= 0 || h <= 0) {
56 IF_PRINT_WARNING(VIDEO_DEBUG) << "width and/or height argument was invalid: "
57 << "(width = " << w << ", height = " << h << ")" << std::endl;
58 return false;
59 }
60
61 _width = w;
62 _height = h;
63 _edge_visible_flags = visible_flags;
64 _edge_shared_flags = shared_flags;
65
66 if(_skin == nullptr)
67 _skin = GUIManager->_GetDefaultMenuSkin();
68
69 if(_skin == nullptr) {
70 IF_PRINT_WARNING(VIDEO_DEBUG) << "a default menu skin was unavailable (no skins were loaded)" << std::endl;
71 return false;
72 }
73
74 if(_RecreateImage() == false)
75 return false;
76
77 // Add the new menu window to the menu map
78 GUIManager->_AddMenuWindow(this);
79 return true;
80 }
81
82
83
Destroy()84 void MenuWindow::Destroy()
85 {
86 _skin = nullptr;
87 GUIManager->_RemoveMenuWindow(this);
88 }
89
Draw(const Color & color)90 void MenuWindow::Draw(const Color& color)
91 {
92 if(_window_state == VIDEO_MENU_STATE_HIDDEN)
93 return;
94
95 VideoManager->PushState();
96 VideoManager->SetDrawFlags(_xalign, _yalign, VIDEO_BLEND, 0);
97
98 VideoManager->Move(_position.x, _position.y);
99 _menu_image.Draw(color);
100
101 if(GUIManager->DEBUG_DrawOutlines()) {
102 _DEBUG_DrawOutline();
103 }
104
105 VideoManager->PopState();
106 return;
107 } // void MenuWindow::Draw()
108
SetDimensions(float w,float h)109 void MenuWindow::SetDimensions(float w, float h)
110 {
111 if(w <= 0.0f) {
112 IF_PRINT_WARNING(VIDEO_DEBUG) << "invalid width argument: " << w << std::endl;
113 return;
114 }
115
116 if(h <= 0.0f) {
117 IF_PRINT_WARNING(VIDEO_DEBUG) << "invalid height argument: " << h << std::endl;
118 return;
119 }
120
121 _width = w;
122 _height = h;
123 _RecreateImage();
124 }
125
126
127
SetMenuSkin(const std::string & skin_name)128 void MenuWindow::SetMenuSkin(const std::string &skin_name)
129 {
130 MenuSkin *new_skin = GUIManager->_GetMenuSkin(skin_name);
131 if(new_skin == nullptr) {
132 IF_PRINT_WARNING(VIDEO_DEBUG) << "the skin_name \"" << skin_name << "\" was invalid" << std::endl;
133 return;
134 }
135
136 _skin = new_skin;
137 _RecreateImage();
138 }
139
_RecreateImage()140 bool MenuWindow::_RecreateImage()
141 {
142 if(_skin == nullptr) {
143 IF_PRINT_WARNING(VIDEO_DEBUG) << "no menu skin set when function was invoked" << std::endl;
144 return false;
145 }
146
147 _menu_image.Clear();
148
149 // Get information about the border sizes
150 float left_border_size = _skin->borders[1][0].GetWidth();
151 float right_border_size = _skin->borders[1][2].GetWidth();
152 float top_border_size = _skin->borders[2][1].GetHeight();
153 float bottom_border_size = _skin->borders[0][1].GetHeight();
154
155 float horizontal_border_size = left_border_size + right_border_size;
156 float vertical_border_size = top_border_size + bottom_border_size;
157
158 float top_width = _skin->borders[2][1].GetWidth();
159 float left_height = _skin->borders[1][0].GetHeight();
160
161 // Calculate how many times the top/bottom images have to be tiled in order to make up the width of the window
162 _inner_width = _width - horizontal_border_size;
163 _inner_height = _height - vertical_border_size;
164
165 if(_inner_width < 0.0f) {
166 IF_PRINT_WARNING(VIDEO_DEBUG) << "_inner_width was computed as negative" << std::endl;
167 return false;
168 }
169
170 if(_inner_height < 0.0f) {
171 IF_PRINT_WARNING(VIDEO_DEBUG) << "_inner_height was computed as negative" << std::endl;
172 return false;
173 }
174
175 // Will be true if there is a background image for the menu skin being used
176 bool background_loaded = _skin->background.GetWidth();
177
178 // Find how many times we have to tile the border images to fit the dimensions given
179 float num_x_tiles = _inner_width / top_width;
180 float num_y_tiles = _inner_height / left_height;
181
182 int32_t inum_x_tiles = static_cast<int32_t>(num_x_tiles);
183 int32_t inum_y_tiles = static_cast<int32_t>(num_y_tiles);
184
185 // Ideally, the border sizes should evenly divide into the window sizes but the person who
186 // created the window might have passed in a width and height that is not a multiple of
187 // the border sizes. If this is the case, we have to extend the dimensions a little bit.
188 float dnum_x_tiles = num_x_tiles - inum_x_tiles;
189 float dnum_y_tiles = num_y_tiles - inum_y_tiles;
190
191 if(dnum_x_tiles > 0.001f) {
192 float width_adjust = (1.0f - dnum_x_tiles) * top_width;
193 _width += width_adjust;
194 _inner_width += width_adjust;
195 ++inum_x_tiles;
196 }
197
198 if(dnum_y_tiles > 0.001f) {
199 float height_adjust = (1.0f - dnum_y_tiles) * top_width;
200 _height += height_adjust;
201 _inner_height += height_adjust;
202 ++inum_y_tiles;
203 }
204
205 // Now we have all the information we need to create the window.
206 // Begin by re-creating the overlay at the correct width and height
207 Color c[4];
208 _skin->borders[1][1].GetVertexColor(c[0], 0);
209 _skin->borders[1][1].GetVertexColor(c[1], 1);
210 _skin->borders[1][1].GetVertexColor(c[2], 2);
211 _skin->borders[1][1].GetVertexColor(c[3], 3);
212
213 _skin->borders[1][1].SetDimensions(left_border_size, top_border_size);
214 _skin->borders[1][1].SetVertexColors(c[0], c[1], c[2], c[3]);
215
216 // If a valid background image is loaded, then tile the interior of the window with it
217 if(background_loaded) {
218 _skin->background.SetVertexColors(c[0], c[1], c[2], c[3]);
219
220 float width = _skin->background.GetWidth();
221 float height = _skin->background.GetHeight();
222
223 float min_x = 0;
224 float min_y = 0;
225
226 float max_x = _inner_width + horizontal_border_size;
227 float max_y = _inner_height + vertical_border_size;
228
229 if(_edge_visible_flags & VIDEO_MENU_EDGE_TOP)
230 max_y -= (top_border_size / 2);
231 if(_edge_visible_flags & VIDEO_MENU_EDGE_BOTTOM)
232 min_y += (bottom_border_size / 2);
233 if(_edge_visible_flags & VIDEO_MENU_EDGE_LEFT)
234 min_x += (left_border_size / 2);
235 if(_edge_visible_flags & VIDEO_MENU_EDGE_RIGHT)
236 max_x -= (right_border_size / 2);
237
238 for(float y = min_y ; y < max_y; y += height) {
239 for(float x = min_x; x < max_x; x += width) {
240 float u = 1.0, v = 1.0;
241
242 if(x + width > max_x)
243 u = (max_x - x) / width;
244 if(y + height > max_y)
245 v = (max_y - y) / height;
246
247 _menu_image.AddImage(_skin->background, x, y, 0.0f, 0.0f, u, v);
248 }
249 }
250 } else {
251 // Otherwise re-create the overlay at the correct width and height
252 _skin->borders[1][1].SetDimensions(_inner_width, _inner_height);
253 _skin->borders[1][1].SetVertexColors(c[0], c[1], c[2], c[3]);
254 _menu_image.AddImage(_skin->borders[1][1], left_border_size, bottom_border_size);
255 }
256
257 // First create the corners of the image
258 float max_x = left_border_size + inum_x_tiles * top_width;
259 float max_y = bottom_border_size + inum_y_tiles * left_height;
260 float min_x = 0.0f;
261 float min_y = 0.0f;
262
263 // Bottom left
264 if(_edge_visible_flags & VIDEO_MENU_EDGE_LEFT && _edge_visible_flags & VIDEO_MENU_EDGE_BOTTOM) {
265 if(_edge_shared_flags & VIDEO_MENU_EDGE_LEFT && _edge_shared_flags & VIDEO_MENU_EDGE_BOTTOM)
266 _menu_image.AddImage(_skin->connectors[4], min_x, min_y);
267 else if(_edge_shared_flags & VIDEO_MENU_EDGE_LEFT)
268 _menu_image.AddImage(_skin->connectors[1], min_x, min_y);
269 else if(_edge_shared_flags & VIDEO_MENU_EDGE_BOTTOM)
270 _menu_image.AddImage(_skin->connectors[2], min_x, min_y);
271 else
272 _menu_image.AddImage(_skin->borders[2][0], min_x, min_y);
273 } else if(_edge_visible_flags & VIDEO_MENU_EDGE_LEFT)
274 _menu_image.AddImage(_skin->borders[1][0], min_x, min_y);
275 else if(_edge_visible_flags & VIDEO_MENU_EDGE_BOTTOM)
276 _menu_image.AddImage(_skin->borders[0][1], min_x, min_y);
277 else if(!background_loaded)
278 _menu_image.AddImage(_skin->borders[1][1], min_x, min_y);
279
280 // Bottom right
281 if(_edge_visible_flags & VIDEO_MENU_EDGE_RIGHT && _edge_visible_flags & VIDEO_MENU_EDGE_BOTTOM) {
282 if(_edge_shared_flags & VIDEO_MENU_EDGE_RIGHT && _edge_shared_flags & VIDEO_MENU_EDGE_BOTTOM)
283 _menu_image.AddImage(_skin->connectors[4], max_x, min_y);
284 else if(_edge_shared_flags & VIDEO_MENU_EDGE_RIGHT)
285 _menu_image.AddImage(_skin->connectors[1], max_x, min_y);
286 else if(_edge_shared_flags & VIDEO_MENU_EDGE_BOTTOM)
287 _menu_image.AddImage(_skin->connectors[3], max_x, min_y);
288 else
289 _menu_image.AddImage(_skin->borders[2][2], max_x, min_y);
290 } else if(_edge_visible_flags & VIDEO_MENU_EDGE_RIGHT)
291 _menu_image.AddImage(_skin->borders[1][2], max_x, min_y);
292 else if(_edge_visible_flags & VIDEO_MENU_EDGE_BOTTOM)
293 _menu_image.AddImage(_skin->borders[2][1], max_x, min_y);
294 else if(!background_loaded)
295 _menu_image.AddImage(_skin->borders[1][1], max_x, min_y);
296
297 // Top left
298 if(_edge_visible_flags & VIDEO_MENU_EDGE_LEFT && _edge_visible_flags & VIDEO_MENU_EDGE_TOP) {
299 if(_edge_shared_flags & VIDEO_MENU_EDGE_LEFT && _edge_shared_flags & VIDEO_MENU_EDGE_TOP)
300 _menu_image.AddImage(_skin->connectors[4], min_x, max_y);
301 else if(_edge_shared_flags & VIDEO_MENU_EDGE_LEFT)
302 _menu_image.AddImage(_skin->connectors[0], min_x, max_y);
303 else if(_edge_shared_flags & VIDEO_MENU_EDGE_TOP)
304 _menu_image.AddImage(_skin->connectors[2], min_x, max_y);
305 else
306 _menu_image.AddImage(_skin->borders[0][0], min_x, max_y);
307 } else if(_edge_visible_flags & VIDEO_MENU_EDGE_LEFT)
308 _menu_image.AddImage(_skin->borders[1][0], min_x, max_y);
309 else if(_edge_visible_flags & VIDEO_MENU_EDGE_TOP)
310 _menu_image.AddImage(_skin->borders[0][1], min_x, max_y);
311 else if(!background_loaded)
312 _menu_image.AddImage(_skin->borders[1][1], min_x, max_y);
313
314 // Top right
315 if(_edge_visible_flags & VIDEO_MENU_EDGE_TOP && _edge_visible_flags & VIDEO_MENU_EDGE_RIGHT) {
316 if(_edge_shared_flags & VIDEO_MENU_EDGE_RIGHT && _edge_shared_flags & VIDEO_MENU_EDGE_TOP)
317 _menu_image.AddImage(_skin->connectors[4], max_x, max_y);
318 else if(_edge_shared_flags & VIDEO_MENU_EDGE_RIGHT)
319 _menu_image.AddImage(_skin->connectors[0], max_x, max_y);
320 else if(_edge_shared_flags & VIDEO_MENU_EDGE_TOP)
321 _menu_image.AddImage(_skin->connectors[3], max_x, max_y);
322 else
323 _menu_image.AddImage(_skin->borders[0][2], max_x, max_y);
324 } else if(_edge_visible_flags & VIDEO_MENU_EDGE_TOP)
325 _menu_image.AddImage(_skin->borders[0][1], max_x, max_y);
326 else if(_edge_visible_flags & VIDEO_MENU_EDGE_RIGHT)
327 _menu_image.AddImage(_skin->borders[1][2], max_x, max_y);
328 else if(!background_loaded)
329 _menu_image.AddImage(_skin->borders[1][1], max_x, max_y);
330
331 // Iterate from left to right and fill in the horizontal borders
332 for(int32_t tile_x = 0; tile_x < inum_x_tiles; ++tile_x) {
333 if(_edge_visible_flags & VIDEO_MENU_EDGE_TOP)
334 _menu_image.AddImage(_skin->borders[0][1], left_border_size + top_width * tile_x, max_y);
335 else if(!background_loaded)
336 _menu_image.AddImage(_skin->borders[1][1], left_border_size + top_width * tile_x, max_y);
337
338 if(_edge_visible_flags & VIDEO_MENU_EDGE_BOTTOM)
339 _menu_image.AddImage(_skin->borders[2][1], left_border_size + top_width * tile_x, 0.0f);
340 else if(!background_loaded)
341 _menu_image.AddImage(_skin->borders[1][1], left_border_size + top_width * tile_x, 0.0f);
342 }
343
344 // Iterate from bottom to top and fill in the vertical borders
345 for(int32_t tile_y = 0; tile_y < inum_y_tiles; ++tile_y) {
346 if(_edge_visible_flags & VIDEO_MENU_EDGE_LEFT)
347 _menu_image.AddImage(_skin->borders[1][0], 0.0f, bottom_border_size + left_height * tile_y);
348 else if(!background_loaded)
349 _menu_image.AddImage(_skin->borders[1][1], 0.0f, bottom_border_size + left_height * tile_y);
350
351 if(_edge_visible_flags & VIDEO_MENU_EDGE_RIGHT)
352 _menu_image.AddImage(_skin->borders[1][2], max_x, bottom_border_size + left_height * tile_y);
353 else if(!background_loaded)
354 _menu_image.AddImage(_skin->borders[1][1], max_x, bottom_border_size + left_height * tile_y);
355 }
356
357 return true;
358 }
359
360 } // namespace vt_gui
361