guichanmanager.cpp

00001 /***************************************************************************
00002  *   Copyright (C) 2005-2011 by the FIFE team                              *
00003  *   http://www.fifengine.net                                              *
00004  *   This file is part of FIFE.                                            *
00005  *                                                                         *
00006  *   FIFE is free software; you can redistribute it and/or                 *
00007  *   modify it under the terms of the GNU Lesser General Public            *
00008  *   License as published by the Free Software Foundation; either          *
00009  *   version 2.1 of the License, or (at your option) any later version.    *
00010  *                                                                         *
00011  *   This library is distributed in the hope that it will be useful,       *
00012  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00013  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
00014  *   Lesser General Public License for more details.                       *
00015  *                                                                         *
00016  *   You should have received a copy of the GNU Lesser General Public      *
00017  *   License along with this library; if not, write to the                 *
00018  *   Free Software Foundation, Inc.,                                       *
00019  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA          *
00020  ***************************************************************************/
00021 
00022 // Standard C++ library includes
00023 
00024 // 3rd party library includes
00025 #include <guichan/sdl/sdlinput.hpp>
00026 #include <guichan/key.hpp>
00027 #include <guichan/focushandler.hpp>
00028 #include <guichan.hpp>
00029 
00030 // FIFE includes
00031 // These includes are split up in two parts, separated by one empty line
00032 // First block: files included from the FIFE root src directory
00033 // Second block: files included from the same folder
00034 #ifdef HAVE_OPENGL
00035 #include "gui/guichan/base/opengl/opengl_gui_graphics.h"
00036 #include "gui/guichan/base/opengle/opengle_gui_graphics.h"
00037 #endif
00038 #include "gui/guichan/base/sdl/sdl_gui_graphics.h"
00039 #include "util/base/exception.h"
00040 #include "util/log/logger.h"
00041 #include "video/renderbackend.h"
00042 #include "gui/guichan/base/gui_imageloader.h"
00043 #include "gui/guichan/base/gui_font.h"
00044 #include "gui/guichan/console/console.h"
00045 #include "video/fonts/fontbase.h"
00046 #include "video/fonts/truetypefont.h"
00047 #include "video/fonts/subimagefont.h"
00048 #include "eventchannel/key/ec_key.h"
00049 #include "eventchannel/key/ec_keyevent.h"
00050 #include "eventchannel/mouse/ec_mouseevent.h"
00051 #include "vfs/fife_boost_filesystem.h"
00052 
00053 #include "guichanmanager.h"
00054 
00055 namespace FIFE {
00056     static Logger _log(LM_GUI);
00057 
00058     GUIChanManager::GUIChanManager() :
00059         m_gcn_gui(new gcn::Gui()),
00060         m_focushandler(0),
00061         m_gcn_topcontainer(new gcn::Container()),
00062         m_imgloader(new GuiImageLoader()) ,
00063         m_input(new gcn::SDLInput()),
00064         m_console(0),
00065         m_defaultfont(0),
00066         m_fonts(),
00067         m_logic_executed(false) {
00068 
00069         m_gcn_gui->setInput(m_input);
00070         gcn::Image::setImageLoader(m_imgloader);
00071 
00072         m_gcn_gui->setTop(m_gcn_topcontainer);
00073         m_focushandler = m_gcn_topcontainer->_getFocusHandler();
00074 
00075         m_gcn_topcontainer->setOpaque(false);
00076         m_gcn_topcontainer->setFocusable(false);
00077         m_had_mouse = false;
00078         m_had_widget = false;
00079     }
00080 
00081     GUIChanManager::~GUIChanManager() {
00082         delete m_console;
00083         delete m_gcn_topcontainer;
00084         delete m_imgloader;
00085         delete m_input;
00086         delete m_gcn_gui;
00087         delete m_gui_graphics;
00088         std::vector<GuiFont*>::iterator i = m_fonts.begin();
00089         while (i != m_fonts.end()) {
00090             delete *i;
00091             ++i;
00092         }
00093     }
00094 
00095     bool GUIChanManager::onSdlEvent(SDL_Event& evt) {
00096         if (!m_input) {
00097             FL_WARN(_log, "GUIChanManager, GuichanGUI->getInput == 0 ... discarding events!");
00098             return false;
00099         }
00100 
00101         bool overWidget = m_gcn_topcontainer->getWidgetAt(evt.button.x,evt.button.y) != 0;
00102 
00103         switch(evt.type) {
00104             case SDL_MOUSEBUTTONDOWN:
00105                 m_had_widget = overWidget;
00106             case SDL_MOUSEBUTTONUP:
00107                 // Always send the button up/down events to guichan
00108                 m_input->pushInput(evt);
00109 
00110                 // Button was pressed over a widget and still is over a widget
00111                 // so we mark the event as processed.
00112                 if( m_had_widget && overWidget ) {
00113                     return true;
00114                 }
00115 
00116                 // Button wasn't pressed over a widget so we want to release focus
00117                 // no matter what.
00118                 if (!m_had_widget) {
00119                     m_focushandler->focusNone();
00120                 }
00121 
00122                 // Button up was processed by guichan but there was no widget under
00123                 // the mouse at the time.  Don't mark it as processed here so the
00124                 // other listeners have a chance to process the event.
00125                 return false;
00126 
00127             case SDL_MOUSEMOTION:
00128                 if( m_gcn_topcontainer->getWidgetAt(evt.button.x,evt.button.y) ) {
00129                     m_had_mouse = true;
00130                     m_input->pushInput(evt);
00131                     return true;
00132                 }
00133                 if( m_had_mouse ) {
00134                     // We only keep the mouse if a widget/window has requested
00135                     // dragging.
00136                     m_had_mouse = m_focushandler->getDraggedWidget() != 0;
00137                     m_input->pushInput(evt);
00138                     return true;
00139                 }
00140                 return false;
00141 
00142             case SDL_KEYDOWN:
00143             case SDL_KEYUP:
00144                 if(m_focushandler->getFocused()) {
00145                     m_input->pushInput(evt);
00146                     return true;
00147                 }
00148                 return false;
00149 
00150             case SDL_ACTIVEEVENT:
00151                 // Actually Guichan doesn't care (it should!)
00152                 // so at least don't swallow mouse_focus events up.
00153                 return false;
00154 
00155             default:
00156                 return false;
00157         }
00158     }
00159 
00160     void GUIChanManager::resizeTopContainer(uint32_t x, uint32_t y, uint32_t width, uint32_t height) {
00161         m_gcn_topcontainer->setDimension(gcn::Rectangle(x, y, width, height));
00162         this->invalidateFonts();
00163         this->m_console->reLayout();
00164     }
00165 
00166     gcn::Gui* GUIChanManager::getGuichanGUI() const {
00167         return m_gcn_gui;
00168     }
00169 
00170     void GUIChanManager::add(gcn::Widget* widget) {
00171         if( !m_widgets.count(widget) ) {
00172             m_gcn_topcontainer->add(widget);
00173             m_widgets.insert(widget);
00174         }
00175     }
00176 
00177     void GUIChanManager::remove(gcn::Widget* widget) {
00178         if( m_widgets.count(widget) ) {
00179             m_widgets.erase(widget);
00180             m_gcn_topcontainer->remove(widget);
00181         }
00182     }
00183 
00184     void GUIChanManager::init(const std::string& backend, int32_t screenWidth, int32_t screenHeight) {
00185         if( backend == "SDL" ) {
00186             m_gui_graphics = new SdlGuiGraphics();
00187         }
00188 #ifdef HAVE_OPENGL
00189         else if (backend == "OpenGL") {
00190             m_gui_graphics = new OpenGLGuiGraphics();
00191         }
00192         else if (backend == "OpenGLe") {
00193             m_gui_graphics = new OpenGLeGuiGraphics();
00194         } 
00195 #endif
00196         else {
00197             //should never get here
00198             assert(0);
00199         }
00200 
00201         m_gcn_gui->setGraphics(m_gui_graphics);
00202         m_console = new Console();
00203 
00204         resizeTopContainer(0, 0, screenWidth, screenHeight);
00205     }
00206 
00207     GuiFont* GUIChanManager::createFont(const std::string& path, uint32_t size, const std::string& glyphs) {
00208         std::string fontpath = path;
00209         std::string fontglyphs = glyphs;
00210         int32_t fontsize = size;
00211 
00212         // Set default settings if necessary
00213         if(fontpath == "") {
00214             fontpath = m_fontpath;
00215         }
00216         if(fontsize == 0) {
00217             fontsize = m_fontsize;
00218         }
00219         if(fontglyphs == "") {
00220             fontglyphs = m_fontglyphs;
00221         }
00222 
00223         IFont* font = NULL;
00224         GuiFont* guifont = NULL;
00225         if( bfs::extension(fontpath) == ".ttf" || bfs::extension(fontpath) == ".ttc" ) {
00226             font = new TrueTypeFont(fontpath, fontsize);
00227         } else {
00228             font = new SubImageFont(fontpath, fontglyphs);
00229         }
00230         guifont = new GuiFont(font);
00231 
00232         m_fonts.push_back(guifont);
00233         return guifont;
00234     }
00235 
00236     void GUIChanManager::releaseFont(GuiFont* font) {
00237         std::vector<GuiFont*>::iterator i = m_fonts.begin();
00238         while (i != m_fonts.end()) {
00239             if ((*i) == font) {
00240                 m_fonts.erase(i);
00241                 delete font;
00242                 return;
00243             }
00244             ++i;
00245         }
00246     }
00247 
00248     void GUIChanManager::invalidateFonts() {
00249         std::vector<GuiFont*>::iterator it = m_fonts.begin();
00250         while (it != m_fonts.end()) {
00251             (*it)->invalidate();
00252             ++it;
00253         }
00254     }
00255 
00256     GuiFont* GUIChanManager::setDefaultFont(const std::string& path, uint32_t size, const std::string& glyphs) {
00257         m_fontpath = path;
00258         m_fontsize = size;
00259         m_fontglyphs = glyphs;
00260 
00261         m_defaultfont = createFont();
00262         gcn::Widget::setGlobalFont(m_defaultfont);
00263         if (m_console) {
00264             m_console->reLayout();
00265         }
00266 
00267         return m_defaultfont;
00268     }
00269 
00270     void GUIChanManager::turn() {
00271         if (!m_logic_executed)
00272             m_gcn_gui->logic();
00273         m_logic_executed = false;
00274         m_gcn_gui->draw();
00275     }
00276 
00277     KeyEvent GUIChanManager::translateKeyEvent(const gcn::KeyEvent& gcnevt) {
00278         KeyEvent keyevt;
00279         if(gcnevt.getType() == gcn::KeyEvent::PRESSED)
00280             keyevt.setType(KeyEvent::PRESSED);
00281         else if(gcnevt.getType() == gcn::KeyEvent::RELEASED)
00282             keyevt.setType(KeyEvent::RELEASED);
00283         else {
00284             FL_WARN(_log, LMsg("GUIChanManager::translateKeyEvent() - ") << "Unknown event type: " << gcnevt.getType());
00285             keyevt.setType(KeyEvent::UNKNOWN);
00286         }
00287         keyevt.setShiftPressed(gcnevt.isShiftPressed());
00288         keyevt.setControlPressed(gcnevt.isControlPressed());
00289         keyevt.setAltPressed(gcnevt.isAltPressed());
00290         keyevt.setMetaPressed(gcnevt.isMetaPressed());
00291         keyevt.setNumericPad(gcnevt.isNumericPad());
00292 
00293         // Convert from guichan keyval to FIFE keyval
00294         int32_t keyval = gcnevt.getKey().getValue();
00295         keyval = convertGuichanKeyToFifeKey(keyval);
00296 
00297         keyevt.setKey(Key(static_cast<Key::KeyType>(keyval), keyval));
00298 
00299         return keyevt;
00300     }
00301 
00302     MouseEvent GUIChanManager::translateMouseEvent(const gcn::MouseEvent& gcnevt) {
00303         MouseEvent mouseevt;
00304         mouseevt.setShiftPressed(gcnevt.isShiftPressed());
00305         mouseevt.setControlPressed(gcnevt.isControlPressed());
00306         mouseevt.setAltPressed(gcnevt.isAltPressed());
00307         mouseevt.setMetaPressed(gcnevt.isMetaPressed());
00308         mouseevt.setX(gcnevt.getX());
00309         mouseevt.setY(gcnevt.getY());
00310 
00311         switch(gcnevt.getType()) {
00312             case gcn::MouseEvent::PRESSED:
00313                 mouseevt.setType(MouseEvent::PRESSED);
00314                 break;
00315             case gcn::MouseEvent::RELEASED:
00316                 mouseevt.setType(MouseEvent::RELEASED);
00317                 break;
00318             case gcn::MouseEvent::MOVED:
00319                 mouseevt.setType(MouseEvent::MOVED);
00320                 break;
00321             case gcn::MouseEvent::CLICKED:
00322                 mouseevt.setType(MouseEvent::CLICKED);
00323                 break;
00324             case gcn::MouseEvent::ENTERED:
00325                 mouseevt.setType(MouseEvent::ENTERED);
00326                 break;
00327             case gcn::MouseEvent::EXITED:
00328                 mouseevt.setType(MouseEvent::EXITED);
00329                 break;
00330             case gcn::MouseEvent::DRAGGED:
00331                 mouseevt.setType(MouseEvent::DRAGGED);
00332                 break;
00333             case gcn::MouseEvent::WHEEL_MOVED_DOWN:
00334                 mouseevt.setType(MouseEvent::WHEEL_MOVED_DOWN);
00335                 break;
00336             case gcn::MouseEvent::WHEEL_MOVED_UP:
00337                 mouseevt.setType(MouseEvent::WHEEL_MOVED_UP);
00338                 break;
00339             default:
00340                 mouseevt.setType(MouseEvent::UNKNOWN_EVENT);
00341         }
00342 
00343         switch(gcnevt.getButton()) {
00344             case gcn::MouseInput::LEFT:
00345                 mouseevt.setButton(MouseEvent::LEFT);
00346                 break;
00347             case gcn::MouseInput::RIGHT:
00348                 mouseevt.setButton(MouseEvent::RIGHT);
00349                 break;
00350             case gcn::MouseInput::MIDDLE:
00351                 mouseevt.setButton(MouseEvent::MIDDLE);
00352                 break;
00353             default:
00354                 mouseevt.setButton(MouseEvent::UNKNOWN_BUTTON);
00355                 break;
00356         }
00357         return mouseevt;
00358     }
00359 
00360 
00361     int32_t GUIChanManager::convertGuichanKeyToFifeKey(int32_t value) {
00362 
00363         switch (value) {
00364             case gcn::Key::TAB:
00365                 value = Key::TAB;
00366                 break;
00367             case gcn::Key::LEFT_ALT:
00368                 value = Key::LEFT_ALT;
00369                 break;
00370             case gcn::Key::RIGHT_ALT:
00371                 value = Key::RIGHT_ALT;
00372                 break;
00373             case gcn::Key::LEFT_SHIFT:
00374                 value = Key::LEFT_SHIFT;
00375                 break;
00376             case gcn::Key::RIGHT_SHIFT:
00377                 value = Key::RIGHT_SHIFT;
00378                 break;
00379             case gcn::Key::LEFT_CONTROL:
00380                 value = Key::LEFT_CONTROL;
00381                 break;
00382             case gcn::Key::RIGHT_CONTROL:
00383                 value = Key::RIGHT_CONTROL;
00384                 break;
00385             case gcn::Key::BACKSPACE:
00386                 value = Key::BACKSPACE;
00387                 break;
00388             case gcn::Key::PAUSE:
00389                 value = Key::PAUSE;
00390                 break;
00391             case gcn::Key::SPACE:
00392                 value = Key::SPACE;
00393                 break;
00394             case gcn::Key::ESCAPE:
00395                 value = Key::ESCAPE;
00396                 break;
00397             case gcn::Key::DELETE:
00398                 value = Key::DELETE;
00399                 break;
00400             case gcn::Key::INSERT:
00401                 value = Key::INSERT;
00402                 break;
00403             case gcn::Key::HOME:
00404                 value = Key::HOME;
00405                 break;
00406             case gcn::Key::END:
00407                 value = Key::END;
00408                 break;
00409             case gcn::Key::PAGE_UP:
00410                 value = Key::PAGE_UP;
00411                 break;
00412             case gcn::Key::PRINT_SCREEN:
00413                 value = Key::PRINT_SCREEN;
00414                 break;
00415             case gcn::Key::PAGE_DOWN:
00416                 value = Key::PAGE_DOWN;
00417                 break;
00418             case gcn::Key::F1:
00419                 value = Key::F1;
00420                 break;
00421             case gcn::Key::F2:
00422                 value = Key::F2;
00423                 break;
00424             case gcn::Key::F3:
00425                 value = Key::F3;
00426                 break;
00427             case gcn::Key::F4:
00428                 value = Key::F4;
00429                 break;
00430             case gcn::Key::F5:
00431                 value = Key::F5;
00432                 break;
00433             case gcn::Key::F6:
00434                 value = Key::F6;
00435                 break;
00436             case gcn::Key::F7:
00437                 value = Key::F7;
00438                 break;
00439             case gcn::Key::F8:
00440                 value = Key::F8;
00441                 break;
00442             case gcn::Key::F9:
00443                 value = Key::F9;
00444                 break;
00445             case gcn::Key::F10:
00446                 value = Key::F10;
00447                 break;
00448             case gcn::Key::F11:
00449                 value = Key::F11;
00450                 break;
00451             case gcn::Key::F12:
00452                 value = Key::F12;
00453                 break;
00454             case gcn::Key::F13:
00455                 value = Key::F13;
00456                 break;
00457             case gcn::Key::F14:
00458                 value = Key::F14;
00459                 break;
00460             case gcn::Key::F15:
00461                 value = Key::F15;
00462                 break;
00463             case gcn::Key::NUM_LOCK:
00464                 value = Key::NUM_LOCK;
00465                 break;
00466             case gcn::Key::CAPS_LOCK:
00467                 value = Key::CAPS_LOCK;
00468                 break;
00469             case gcn::Key::SCROLL_LOCK:
00470                 value = Key::SCROLL_LOCK;
00471                 break;
00472             case gcn::Key::RIGHT_META:
00473                 value = Key::RIGHT_META;
00474                 break;
00475             case gcn::Key::LEFT_META:
00476                 value = Key::LEFT_META;
00477                 break;
00478             case gcn::Key::LEFT_SUPER:
00479                 value = Key::LEFT_SUPER;
00480                 break;
00481             case gcn::Key::RIGHT_SUPER:
00482                 value = Key::RIGHT_SUPER;
00483                 break;
00484             case gcn::Key::ALT_GR:
00485                 value = Key::ALT_GR;
00486                 break;
00487             case gcn::Key::UP:
00488                 value = Key::UP;
00489                 break;
00490             case gcn::Key::DOWN:
00491                 value = Key::DOWN;
00492                 break;
00493             case gcn::Key::LEFT:
00494                 value = Key::LEFT;
00495                 break;
00496             case gcn::Key::RIGHT:
00497                 value = Key::RIGHT;
00498                 break;
00499             case gcn::Key::ENTER:
00500                 value = Key::ENTER;
00501                 break;
00502 
00503             default:
00504                 // Convert from unicode to lowercase letters
00505                 if (value >= 1 && value <= 26) {
00506                     // Control characters
00507                     value = value - 1 + 'a';
00508                 } else if (value >= 'A' && value <= 'Z') {
00509                     value = value - 'A' + 'a';
00510                 }
00511 
00512                 // FIXME: Accented characters (รก) will not get converted properly.
00513                 break;
00514         }
00515 
00516         return value;
00517     }
00518 }