Angel 3.2
A 2D Game Prototyping Engine
UserInterface.cpp
1 
2 // Copyright (C) 2008-2013, Shane Liesegang
3 // All rights reserved.
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright
11 // notice, this list of conditions and the following disclaimer in the
12 // documentation and/or other materials provided with the distribution.
13 // * Neither the name of the copyright holder nor the names of any
14 // contributors may be used to endorse or promote products derived from
15 // this software without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 // POSSIBILITY OF SUCH DAMAGE.
29 
30 #include "stdafx.h"
31 #include "../UI/UserInterface.h"
32 
33 #include "Gwen/Gwen.h"
34 #include "Gwen/Controls/Canvas.h"
35 #include "Gwen/Controls/Button.h"
36 #include "Gwen/Controls/GroupBox.h"
37 #include "Gwen/Controls/WindowControl.h"
38 
39 #if defined(__APPLE__)
40  // included files from gwen trigger Clang/GCC warnings
41  #pragma GCC diagnostic push
42  #pragma GCC diagnostic ignored "-Wdangling-else"
43  #pragma GCC diagnostic ignored "-Wunused-variable"
44 #endif
45  #include "Gwen/Skins/TexturedBase.h"
46 #if defined(__APPLE__)
47  #pragma GCC diagnostic pop
48 #endif
49 
50 #include "../UI/GwenRenderer.h"
51 #include "../Infrastructure/Log.h"
52 #include "../Infrastructure/Camera.h"
53 #include "../Infrastructure/World.h"
54 
55 
56 typedef std::map<AngelUIHandle, void (*)()> ButtonMapping;
57 typedef std::map<AngelUIHandle, void (*)(int)> ChoiceMapping;
58 
59 class EventHandler : public Gwen::Event::Handler
60 {
61 public:
62  void AddButtonCallback(Gwen::Controls::Base* control, void (*callback)())
63  {
64  _buttonCallbacks[control] = callback;
65  }
66 
67  void AddChoiceCallback(Gwen::Controls::Base* control, void (*callback)(int))
68  {
69  _choiceCallbacks[control] = callback;
70  }
71 
72 
73  void OnPress(Gwen::Controls::Base* control)
74  {
75  Check(control);
76  }
77 
78 private:
79  void Check(Gwen::Controls::Base* control)
80  {
81  ButtonMapping::iterator buttonIt = _buttonCallbacks.find(control);
82  if (buttonIt != _buttonCallbacks.end())
83  {
84  if (buttonIt->second != NULL)
85  {
86  buttonIt->second();
87  }
88  return;
89  }
90 
91  ChoiceMapping::iterator choiceIt = _choiceCallbacks.find(control->GetParent());
92  if (choiceIt != _choiceCallbacks.end())
93  {
94  int button = -1;
95  Gwen::Controls::Base::List buttons = ((Gwen::Controls::Base*)choiceIt->first)->GetChildren();
96  Gwen::Controls::Base::List::iterator butIt = buttons.begin();
97  int count = 0;
98  while (butIt != buttons.end())
99  {
100  if (*butIt == control)
101  {
102  button = count;
103  break;
104  }
105  butIt++;
106  count++;
107  }
108 
109  if (choiceIt->second != NULL)
110  {
111  choiceIt->second(button);
112  }
113  theUI.RemoveUIElement(choiceIt->first);
114  return;
115  }
116  }
117 
118  ButtonMapping _buttonCallbacks;
119  ChoiceMapping _choiceCallbacks;
120 };
121 
122 
123 namespace
124 {
125  Gwen::Controls::Canvas* AngelCanvas;
126  Gwen::Skin::Base* AngelSkin;
127 
128  EventHandler handler;
129 }
130 
131 UserInterface* UserInterface::s_UserInterface = NULL;
132 
134 {
135  if (s_UserInterface == NULL)
136  {
137  s_UserInterface = new UserInterface();
138  }
139  return *s_UserInterface;
140 }
141 
142 UserInterface::UserInterface()
143 {
144  #if !ANGEL_MOBILE
145  double mpos_x, mpos_y;
146  glfwGetCursorPos(theWorld.GetMainWindow(), &mpos_x, &mpos_y);
147  _mousePosition.X = (float)mpos_x;
148  _mousePosition.Y = (float)mpos_y;
149  #else
150  _mousePosition.X = _mousePosition.Y = 0;
151  #endif
152 
153  const String skinTexture = "Resources/Images/DefaultSkin.png";
154 
155  _renderer = new GwenRenderer(skinTexture);
156 
157  AngelSkin = new Gwen::Skin::TexturedBase(_renderer);
158  ((Gwen::Skin::TexturedBase*)AngelSkin)->Init(skinTexture);
159  AngelSkin->SetDefaultFont(Gwen::Utility::StringToUnicode("Resources/Fonts/Inconsolata.otf"), 20);
160 
161  _renderer->FinishInit();
162 
163  AngelCanvas = new Gwen::Controls::Canvas(AngelSkin);
164  AngelCanvas->SetSize(theCamera.GetWindowWidth(), theCamera.GetWindowHeight()); // should be size of window (update when change)
165 
166  _locked = false;
167 }
168 
169 UserInterface::~UserInterface()
170 {
171 
172 }
173 
175 {
176  delete AngelCanvas;
177  delete AngelSkin;
178 
179  delete _renderer;
180 }
181 
183 {
184  for (unsigned int i=0; i < _deferredRemoves.size(); i++)
185  {
186  RemoveUIElement(_deferredRemoves[i]);
187  }
188  _deferredRemoves.clear();
189 
190  _locked = true;
191  AngelCanvas->DoThink();
192  AngelCanvas->RenderCanvas();
193  _locked = false;
194 }
195 
196 #if ANGEL_MOBILE
197  void UserInterface::TouchMotionEvent(Touch* movedTouch)
198  {
199  Vec2i translatedPoint(movedTouch->CurrentPoint.X * 2, movedTouch->CurrentPoint.Y * 2);
200  int deltaX = _mousePosition.X - translatedPoint.X;
201  int deltaY = _mousePosition.Y - translatedPoint.Y;
202  _mousePosition.X = translatedPoint.X;
203  _mousePosition.Y = translatedPoint.Y;
204  AngelCanvas->InputMouseMoved(translatedPoint.X, translatedPoint.Y, deltaX, deltaY);
205  }
206 
207  void UserInterface::TouchEndEvent(Touch* endedTouch)
208  {
209  _locked = true;
210  TouchMotionEvent(endedTouch);
211  AngelCanvas->InputMouseButton(0, false); // 0 = left button
212  _locked = false;
213  }
214 
215  void UserInterface::TouchStartEvent(Touch* startedTouch)
216  {
217  _locked = true;
218  TouchMotionEvent(startedTouch);
219  AngelCanvas->InputMouseButton(0, true); // 0 = left button
220  _locked = false;
221  }
222 
223 #else //ANGEL_MOBILE
224  void UserInterface::MouseMotionEvent(Vec2i screenCoordinates)
225  {
226  if (theWorld.GetConsole()->IsEnabled())
227  {
228  return;
229  }
230 
231  _locked = true;
232  int deltaX = _mousePosition.X - screenCoordinates.X;
233  int deltaY = _mousePosition.Y - screenCoordinates.Y;
234  _mousePosition.X = screenCoordinates.X;
235  _mousePosition.Y = screenCoordinates.Y;
236  AngelCanvas->InputMouseMoved(screenCoordinates.X, screenCoordinates.Y, deltaX, deltaY);
237  _locked = false;
238  }
239 
240  void UserInterface::MouseDownEvent(Vec2i screenCoordinates, MouseButtonInput button)
241  {
242  if (theWorld.GetConsole()->IsEnabled())
243  {
244  return;
245  }
246 
247  _locked = true;
248  AngelCanvas->InputMouseButton(button, true);
249  _locked = false;
250  }
251 
252  void UserInterface::MouseUpEvent(Vec2i screenCoordinates, MouseButtonInput button)
253  {
254  if (theWorld.GetConsole()->IsEnabled())
255  {
256  return;
257  }
258 
259  _locked = true;
260  AngelCanvas->InputMouseButton(button, false);
261  _locked = false;
262  }
263 
265  {
266  if (theWorld.GetConsole()->IsEnabled())
267  {
268  return;
269  }
270 
271  _locked = true;
272  AngelCanvas->InputMouseWheel(position.Y);
273  _locked = false;
274  }
275 #endif //ANGEL_MOBILE
276 
277 void UserInterface::RemoveUIElement(AngelUIHandle element)
278 {
279  if (_locked)
280  {
281  _deferredRemoves.push_back(element);
282  return;
283  }
284  std::set<AngelUIHandle>::iterator it = _elements.find(element);
285  if (it != _elements.end())
286  {
287  delete (Gwen::Controls::Base*)(*it);
288  _elements.erase(it);
289  }
290 }
291 
292 AngelUIHandle UserInterface::AddButton(const String& label, Vec2i position, void (*callback)(), bool center, const String& font, Vec2i padding)
293 {
294  Gwen::Controls::Button* button = new Gwen::Controls::Button(AngelCanvas);
295  if (font != "")
296  {
297  button->SetFont(Gwen::Utility::StringToUnicode(font), 20, false);
298  }
299  button->SetText(label);
300  button->SetPadding(Gwen::Padding(padding.X, padding.Y, padding.X, padding.Y));
301  button->SizeToContents();
302  if (center)
303  {
304  Gwen::Point size = button->GetSize();
305  button->SetPos(position.X - (size.x / 2), position.Y - (size.y / 2));
306  }
307  else
308  {
309  button->SetPos(position.X, position.Y);
310  }
311 
312  button->onPress.Add(&handler, &EventHandler::OnPress);
313  handler.AddButtonCallback(button, callback);
314 
315  _elements.insert(button);
316 
317  return button;
318 }
319 
320 AngelUIHandle UserInterface::ShowChoiceBox(const String& choiceLabel, const StringList& labels, void (*callback)(int), const String& font, Vec2i padding, bool modal)
321 {
322  Gwen::Controls::WindowControl* box = new Gwen::Controls::WindowControl(AngelCanvas);
323 
324  box->SetTitle(choiceLabel);
325 
326  Gwen::TextObject fontTextObject = Gwen::Utility::StringToUnicode(font);
327 
328  Vec2i maxSize;
329  std::vector<Gwen::Controls::Button*> buttons;
330 
331  for (unsigned int i=0; i < labels.size(); i++)
332  {
333  Gwen::Controls::Button* button = new Gwen::Controls::Button(box);
334  buttons.push_back(button);
335  if (font != "")
336  {
337  button->SetFont(fontTextObject, 20, false);
338  }
339  button->SetText(labels[i]);
340  button->SetPadding(Gwen::Padding(padding.X, padding.Y, padding.X, padding.Y));
341  button->SizeToContents();
342  Gwen::Point size = button->GetSize();
343  if (maxSize.X < size.x)
344  {
345  maxSize.X = size.x;
346  }
347  if (maxSize.Y < size.y)
348  {
349  maxSize.Y = size.y;
350  }
351 
352  button->onPress.Add(&handler, &EventHandler::OnPress);
353  }
354 
355  for (unsigned int i=0; i < buttons.size(); i++)
356  {
357  buttons[i]->SetPos(maxSize.X / 2 - (buttons[i]->GetSize().x / 2), i * (maxSize.Y + padding.Y));
358  }
359 
360  box->SetSize(maxSize.X + (padding.X * 2), buttons.size() * (maxSize.Y + padding.Y) + (padding.Y * 3));
361  box->SetPos((AngelCanvas->GetSize().x / 2) - (box->GetSize().x / 2), (AngelCanvas->GetSize().y / 2) - (box->GetSize().y / 2));
362 
363  if (modal)
364  {
365  box->MakeModal();
366  }
367  box->SetDeleteOnClose(true);
368  box->SetClosable(false);
369 
370  handler.AddChoiceCallback(box, callback);
371 
372  _elements.insert(box);
373 
374  return box;
375 }