1 /***************************************************************************
2  *   Copyright (C) 2005-2019 by the FIFE team                              *
3  *   http://www.fifengine.net                                              *
4  *   This file is part of FIFE.                                            *
5  *                                                                         *
6  *   FIFE is free software; you can redistribute it and/or                 *
7  *   modify it under the terms of the GNU Lesser General Public            *
8  *   License as published by the Free Software Foundation; either          *
9  *   version 2.1 of the License, or (at your option) any later version.    *
10  *                                                                         *
11  *   This library is distributed in the hope that it will be useful,       *
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
14  *   Lesser General Public License for more details.                       *
15  *                                                                         *
16  *   You should have received a copy of the GNU Lesser General Public      *
17  *   License along with this library; if not, write to the                 *
18  *   Free Software Foundation, Inc.,                                       *
19  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA          *
20  ***************************************************************************/
21 
22 // Standard C++ library includes
23 
24 // 3rd party library includes
25 #include <fifechan/sdl/sdlinput.hpp>
26 #include <fifechan/key.hpp>
27 #include <fifechan/focushandler.hpp>
28 #include <fifechan.hpp>
29 
30 // FIFE includes
31 // These includes are split up in two parts, separated by one empty line
32 // First block: files included from the FIFE root src directory
33 // Second block: files included from the same folder
34 #ifdef HAVE_OPENGL
35 #include "gui/fifechan/base/opengl/opengl_gui_graphics.h"
36 #endif
37 #include "gui/fifechan/base/sdl/sdl_gui_graphics.h"
38 #include "util/base/exception.h"
39 #include "util/log/logger.h"
40 #include "video/renderbackend.h"
41 #include "gui/fifechan/base/gui_imageloader.h"
42 #include "gui/fifechan/base/gui_font.h"
43 #include "gui/fifechan/console/console.h"
44 #include "video/fonts/fontbase.h"
45 #include "video/fonts/truetypefont.h"
46 #include "video/fonts/subimagefont.h"
47 #include "eventchannel/key/key.h"
48 #include "eventchannel/key/keyevent.h"
49 #include "eventchannel/mouse/mouseevent.h"
50 #include "vfs/fife_boost_filesystem.h"
51 
52 #include "fifechanmanager.h"
53 
54 namespace FIFE {
55 	static Logger _log(LM_GUI);
56 
FifechanManager()57 	FifechanManager::FifechanManager() :
58 		m_fcn_gui(new fcn::Gui()),
59 		m_focushandler(0),
60 		m_fcn_topcontainer(new fcn::Container()),
61 		m_imgloader(new GuiImageLoader()) ,
62 		m_input(new fcn::SDLInput()),
63 		m_console(0),
64 		m_cursor(0),
65 		m_defaultfont(0),
66 		m_fonts(),
67 		m_logic_executed(false),
68 		m_enabled_console(true),
69 		m_backend("") {
70 
71 		m_fcn_gui->setInput(m_input);
72 		fcn::Image::setImageLoader(m_imgloader);
73 
74 		m_fcn_gui->setTop(m_fcn_topcontainer);
75 		m_focushandler = m_fcn_topcontainer->_getFocusHandler();
76 
77 		m_fcn_topcontainer->setOpaque(false);
78 		m_fcn_topcontainer->setFocusable(false);
79 		m_had_mouse = false;
80 		m_had_widget = false;
81 		m_lastMotionX = 0;
82 		m_lastMotionY = 0;
83 	}
84 
~FifechanManager()85 	FifechanManager::~FifechanManager() {
86 		delete m_console;
87 		delete m_fcn_topcontainer;
88 		delete m_imgloader;
89 		delete m_input;
90 		delete m_fcn_gui;
91 		delete m_gui_graphics;
92 		std::vector<GuiFont*>::iterator i = m_fonts.begin();
93 		while (i != m_fonts.end()) {
94 			delete *i;
95 			++i;
96 		}
97 	}
98 
onSdlEvent(SDL_Event & evt)99 	bool FifechanManager::onSdlEvent(SDL_Event& evt) {
100 		if (!m_input) {
101 			FL_WARN(_log, "FifechanManager, FifechanGUI->getInput == 0 ... discarding events!");
102 			return false;
103 		}
104 
105 		bool overWidget = m_fcn_topcontainer->getWidgetAt(m_lastMotionX, m_lastMotionY) != 0;
106 
107 		switch(evt.type) {
108 			case SDL_MOUSEWHEEL:
109 			case SDL_MOUSEBUTTONDOWN:
110 				m_had_widget = overWidget;
111 			case SDL_MOUSEBUTTONUP:
112 				// Always send the button up/down events to fifechan
113 				m_input->pushInput(evt);
114 
115 				// Button was pressed over a widget and still is over a widget
116 				// so we mark the event as processed.
117 				if( m_had_widget && overWidget ) {
118 					return true;
119 				}
120 
121 				// Button wasn't pressed over a widget so we want to release focus
122 				// no matter what.
123 				if (!m_had_widget) {
124 					m_focushandler->focusNone();
125 				}
126 
127 				// Button up was processed by fifechan but there was no widget under
128 				// the mouse at the time.  Don't mark it as processed here so the
129 				// other listeners have a chance to process the event.
130 				return false;
131 
132 			case SDL_MOUSEMOTION:
133 				m_lastMotionX = evt.motion.x;
134 				m_lastMotionY = evt.motion.y;
135 				if (m_fcn_topcontainer->getWidgetAt(evt.motion.x,evt.motion.y)) {
136 					m_had_mouse = true;
137 					m_input->pushInput(evt);
138 					return true;
139 				}
140 				if( m_had_mouse ) {
141 					// We only keep the mouse if a widget/window has requested
142 					// dragging.
143 					m_had_mouse = m_focushandler->getDraggedWidget() != 0;
144 					m_input->pushInput(evt);
145 					return true;
146 				}
147 				return false;
148 
149 			case SDL_KEYDOWN:
150 			case SDL_KEYUP:
151 				if(m_focushandler->getFocused()) {
152 					m_input->pushInput(evt);
153 					return true;
154 				}
155 				return false;
156 
157 			case SDL_TEXTINPUT:
158 				// don't consume TEXTINPUT
159 				m_input->pushInput(evt);
160 				return false;
161 
162 			case SDL_WINDOWEVENT:
163 				// don't consume WINDOWEVENTS
164 				m_input->pushInput(evt);
165 				return false;
166 
167 			default:
168 				return false;
169 		}
170 	}
171 
resizeTopContainer(uint32_t x,uint32_t y,uint32_t width,uint32_t height)172 	void FifechanManager::resizeTopContainer(uint32_t x, uint32_t y, uint32_t width, uint32_t height) {
173 		if (m_backend == "SDL") {
174 			static_cast<SdlGuiGraphics*>(m_gui_graphics)->updateTarget();
175 		} else {
176 			static_cast<OpenGLGuiGraphics*>(m_gui_graphics)->updateTarget();
177 		}
178 		m_fcn_topcontainer->setDimension(fcn::Rectangle(x, y, width, height));
179 		invalidateFonts();
180 		if (m_console) {
181 			m_console->reLayout();
182 		}
183 	}
184 
getFifechanGUI() const185 	fcn::Gui* FifechanManager::getFifechanGUI() const {
186 		return m_fcn_gui;
187 	}
188 
add(fcn::Widget * widget)189 	void FifechanManager::add(fcn::Widget* widget) {
190 		if( !m_widgets.count(widget) ) {
191 			m_fcn_topcontainer->add(widget);
192 			m_widgets.insert(widget);
193 		}
194 	}
195 
remove(fcn::Widget * widget)196 	void FifechanManager::remove(fcn::Widget* widget) {
197 		if( m_widgets.count(widget) ) {
198 			m_widgets.erase(widget);
199 			m_fcn_topcontainer->remove(widget);
200 		}
201 	}
202 
setConsoleEnabled(bool console)203 	void FifechanManager::setConsoleEnabled(bool console) {
204 		m_enabled_console = console;
205 	}
206 
isConsoleEnabled() const207 	bool FifechanManager::isConsoleEnabled() const {
208 		return m_enabled_console;
209 	}
210 
init(const std::string & backend,int32_t screenWidth,int32_t screenHeight)211 	void FifechanManager::init(const std::string& backend, int32_t screenWidth, int32_t screenHeight) {
212 		if( backend == "SDL" ) {
213 			m_gui_graphics = new SdlGuiGraphics();
214 		}
215 #ifdef HAVE_OPENGL
216 		else if (backend == "OpenGL") {
217 			m_gui_graphics = new OpenGLGuiGraphics();
218 		}
219 #endif
220         else {
221 			//should never get here
222 			assert(0);
223 		}
224 		m_backend = backend;
225 
226 		m_fcn_gui->setGraphics(m_gui_graphics);
227 		if (m_enabled_console) {
228 			m_console = new Console();
229 		}
230 
231 		resizeTopContainer(0, 0, screenWidth, screenHeight);
232 	}
233 
createFont(const std::string & path,uint32_t size,const std::string & glyphs)234 	GuiFont* FifechanManager::createFont(const std::string& path, uint32_t size, const std::string& glyphs) {
235 		std::string fontpath = path;
236 		std::string fontglyphs = glyphs;
237 		int32_t fontsize = size;
238 
239 		// Set default settings if necessary
240 		if(fontpath == "") {
241 			fontpath = m_fontpath;
242 		}
243 		if(fontsize == 0) {
244 			fontsize = m_fontsize;
245 		}
246 		if(fontglyphs == "") {
247 			fontglyphs = m_fontglyphs;
248 		}
249 
250 		IFont* font = NULL;
251 		GuiFont* guifont = NULL;
252 		if( bfs::extension(fontpath) == ".ttf" || bfs::extension(fontpath) == ".ttc" ) {
253 			font = new TrueTypeFont(fontpath, fontsize);
254 		} else {
255 			font = new SubImageFont(fontpath, fontglyphs);
256 		}
257 		guifont = new GuiFont(font);
258 
259 		m_fonts.push_back(guifont);
260 		return guifont;
261 	}
262 
releaseFont(GuiFont * font)263 	void FifechanManager::releaseFont(GuiFont* font) {
264 		std::vector<GuiFont*>::iterator i = m_fonts.begin();
265 		while (i != m_fonts.end()) {
266 			if ((*i) == font) {
267 				m_fonts.erase(i);
268 				delete font;
269 				return;
270 			}
271 			++i;
272 		}
273 	}
274 
invalidateFonts()275 	void FifechanManager::invalidateFonts() {
276 		std::vector<GuiFont*>::iterator it = m_fonts.begin();
277 		while (it != m_fonts.end()) {
278 			(*it)->invalidate();
279 			++it;
280 		}
281 	}
282 
setDefaultFont(const std::string & path,uint32_t size,const std::string & glyphs)283 	GuiFont* FifechanManager::setDefaultFont(const std::string& path, uint32_t size, const std::string& glyphs) {
284 		m_fontpath = path;
285 		m_fontsize = size;
286 		m_fontglyphs = glyphs;
287 
288 		m_defaultfont = createFont();
289 		fcn::Widget::setGlobalFont(m_defaultfont);
290 		if (m_console) {
291 			m_console->reLayout();
292 		}
293 
294 		return m_defaultfont;
295 	}
296 
turn()297 	void FifechanManager::turn() {
298 		if (!m_logic_executed)
299 			m_fcn_gui->logic();
300 		m_logic_executed = false;
301 		m_fcn_gui->draw();
302 	}
303 
translateKeyEvent(const fcn::KeyEvent & fcnevt)304 	KeyEvent FifechanManager::translateKeyEvent(const fcn::KeyEvent& fcnevt) {
305 		KeyEvent keyevt;
306 		if(fcnevt.getType() == fcn::KeyEvent::Pressed)
307 			keyevt.setType(KeyEvent::PRESSED);
308 		else if(fcnevt.getType() == fcn::KeyEvent::Released)
309 			keyevt.setType(KeyEvent::RELEASED);
310 		else {
311 			FL_WARN(_log, LMsg("FifechanManager::translateKeyEvent() - ") << "Unknown event type: " << fcnevt.getType());
312 			keyevt.setType(KeyEvent::UNKNOWN);
313 		}
314 		keyevt.setShiftPressed(fcnevt.isShiftPressed());
315 		keyevt.setControlPressed(fcnevt.isControlPressed());
316 		keyevt.setAltPressed(fcnevt.isAltPressed());
317 		keyevt.setMetaPressed(fcnevt.isMetaPressed());
318 		keyevt.setNumericPad(fcnevt.isNumericPad());
319 
320 		// Convert from fifechan keyval to FIFE keyval
321 		int32_t keyval = fcnevt.getKey().getValue();
322 		keyval = convertFifechanKeyToFifeKey(keyval);
323 
324 		keyevt.setKey(Key(static_cast<Key::KeyType>(keyval)));
325 
326 		return keyevt;
327 	}
328 
translateMouseEvent(const fcn::MouseEvent & fcnevt)329 	MouseEvent FifechanManager::translateMouseEvent(const fcn::MouseEvent& fcnevt) {
330 		MouseEvent mouseevt;
331 		mouseevt.setShiftPressed(fcnevt.isShiftPressed());
332 		mouseevt.setControlPressed(fcnevt.isControlPressed());
333 		mouseevt.setAltPressed(fcnevt.isAltPressed());
334 		mouseevt.setMetaPressed(fcnevt.isMetaPressed());
335 		mouseevt.setX(fcnevt.getX());
336 		mouseevt.setY(fcnevt.getY());
337 
338 		switch(fcnevt.getType()) {
339 			case fcn::MouseEvent::Pressed:
340 				mouseevt.setType(MouseEvent::PRESSED);
341 				break;
342 			case fcn::MouseEvent::Released:
343 				mouseevt.setType(MouseEvent::RELEASED);
344 				break;
345 			case fcn::MouseEvent::Moved:
346 				mouseevt.setType(MouseEvent::MOVED);
347 				break;
348 			case fcn::MouseEvent::Clicked:
349 				mouseevt.setType(MouseEvent::CLICKED);
350 				break;
351 			case fcn::MouseEvent::Entered:
352 				mouseevt.setType(MouseEvent::ENTERED);
353 				break;
354 			case fcn::MouseEvent::Exited:
355 				mouseevt.setType(MouseEvent::EXITED);
356 				break;
357 			case fcn::MouseEvent::Dragged:
358 				mouseevt.setType(MouseEvent::DRAGGED);
359 				break;
360 			case fcn::MouseEvent::WheelMovedDown:
361 				mouseevt.setType(MouseEvent::WHEEL_MOVED_DOWN);
362 				break;
363 			case fcn::MouseEvent::WheelMovedUp:
364 				mouseevt.setType(MouseEvent::WHEEL_MOVED_UP);
365 				break;
366 			default:
367 				mouseevt.setType(MouseEvent::UNKNOWN_EVENT);
368 		}
369 
370 		switch(fcnevt.getButton()) {
371 			case fcn::MouseInput::Left:
372 				mouseevt.setButton(MouseEvent::LEFT);
373 				break;
374 			case fcn::MouseInput::Right:
375 				mouseevt.setButton(MouseEvent::RIGHT);
376 				break;
377 			case fcn::MouseInput::Middle:
378 				mouseevt.setButton(MouseEvent::MIDDLE);
379 				break;
380 			case fcn::MouseInput::X1:
381 				mouseevt.setButton(MouseEvent::X1);
382 				break;
383 			case fcn::MouseInput::X2:
384 				mouseevt.setButton(MouseEvent::X2);
385 				break;
386 			default:
387 				mouseevt.setButton(MouseEvent::UNKNOWN_BUTTON);
388 				break;
389 		}
390 		return mouseevt;
391 	}
392 
setTabbingEnabled(bool tabbing)393 	void FifechanManager::setTabbingEnabled(bool tabbing) {
394 		m_fcn_gui->setTabbingEnabled(tabbing);
395 	}
396 
isTabbingEnabled() const397 	bool FifechanManager::isTabbingEnabled() const {
398 		return m_fcn_gui->isTabbingEnabled();
399 	}
400 
convertFifechanKeyToFifeKey(int32_t value)401 	int32_t FifechanManager::convertFifechanKeyToFifeKey(int32_t value) {
402 
403 		switch (value) {
404 			case fcn::Key::Tab:
405 				value = Key::TAB;
406 				break;
407 			case fcn::Key::LeftAlt:
408 				value = Key::LEFT_ALT;
409 				break;
410 			case fcn::Key::RightAlt:
411 				value = Key::RIGHT_ALT;
412 				break;
413 			case fcn::Key::LeftShift:
414 				value = Key::LEFT_SHIFT;
415 				break;
416 			case fcn::Key::RightShift:
417 				value = Key::RIGHT_SHIFT;
418 				break;
419 			case fcn::Key::LeftControl:
420 				value = Key::LEFT_CONTROL;
421 				break;
422 			case fcn::Key::RightControl:
423 				value = Key::RIGHT_CONTROL;
424 				break;
425 			case fcn::Key::Backspace:
426 				value = Key::BACKSPACE;
427 				break;
428 			case fcn::Key::Pause:
429 				value = Key::PAUSE;
430 				break;
431 			case fcn::Key::Space:
432 				value = Key::SPACE;
433 				break;
434 			case fcn::Key::Escape:
435 				value = Key::ESCAPE;
436 				break;
437 			case fcn::Key::Delete:
438 				value = Key::DELETE;
439 				break;
440 			case fcn::Key::Insert:
441 				value = Key::INSERT;
442 				break;
443 			case fcn::Key::Home:
444 				value = Key::HOME;
445 				break;
446 			case fcn::Key::End:
447 				value = Key::END;
448 				break;
449 			case fcn::Key::PageUp:
450 				value = Key::PAGE_UP;
451 				break;
452 			case fcn::Key::PrintScreen:
453 				value = Key::PRINT_SCREEN;
454 				break;
455 			case fcn::Key::PageDown:
456 				value = Key::PAGE_DOWN;
457 				break;
458 			case fcn::Key::F1:
459 				value = Key::F1;
460 				break;
461 			case fcn::Key::F2:
462 				value = Key::F2;
463 				break;
464 			case fcn::Key::F3:
465 				value = Key::F3;
466 				break;
467 			case fcn::Key::F4:
468 				value = Key::F4;
469 				break;
470 			case fcn::Key::F5:
471 				value = Key::F5;
472 				break;
473 			case fcn::Key::F6:
474 				value = Key::F6;
475 				break;
476 			case fcn::Key::F7:
477 				value = Key::F7;
478 				break;
479 			case fcn::Key::F8:
480 				value = Key::F8;
481 				break;
482 			case fcn::Key::F9:
483 				value = Key::F9;
484 				break;
485 			case fcn::Key::F10:
486 				value = Key::F10;
487 				break;
488 			case fcn::Key::F11:
489 				value = Key::F11;
490 				break;
491 			case fcn::Key::F12:
492 				value = Key::F12;
493 				break;
494 			case fcn::Key::F13:
495 				value = Key::F13;
496 				break;
497 			case fcn::Key::F14:
498 				value = Key::F14;
499 				break;
500 			case fcn::Key::F15:
501 				value = Key::F15;
502 				break;
503 			case fcn::Key::NumLock:
504 				value = Key::NUM_LOCK;
505 				break;
506 			case fcn::Key::CapsLock:
507 				value = Key::CAPS_LOCK;
508 				break;
509 			case fcn::Key::ScrollLock:
510 				value = Key::SCROLL_LOCK;
511 				break;
512 			case fcn::Key::LeftSuper:
513 				value = Key::LEFT_SUPER;
514 				break;
515 			case fcn::Key::RightSuper:
516 				value = Key::RIGHT_SUPER;
517 				break;
518 			case fcn::Key::AltGr:
519 				value = Key::ALT_GR;
520 				break;
521 			case fcn::Key::Up:
522 				value = Key::UP;
523 				break;
524 			case fcn::Key::Down:
525 				value = Key::DOWN;
526 				break;
527 			case fcn::Key::Left:
528 				value = Key::LEFT;
529 				break;
530 			case fcn::Key::Right:
531 				value = Key::RIGHT;
532 				break;
533 			case fcn::Key::Enter:
534 				value = Key::ENTER;
535 				break;
536 
537 			default:
538 				// Convert from unicode to lowercase letters
539 				if (value >= 1 && value <= 26) {
540 					// Control characters
541 					value = value - 1 + 'a';
542 				} else if (value >= 'A' && value <= 'Z') {
543 					value = value - 'A' + 'a';
544 				}
545 
546 				// FIXME: Accented characters (á) will not get converted properly.
547 				break;
548 		}
549 
550 		return value;
551 	}
552 }
553