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