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