From 7e12b8c2685ded22d0b420b6d4e0c96d87e8f880 Mon Sep 17 00:00:00 2001 From: pelya Date: Sun, 1 Dec 2013 00:48:59 +0200 Subject: [PATCH 1/4] Guichan-xml: example how to use absolute touch coordinates instead of emulated mouse events in Guichan --- .../commandergenius/commandergenius | 2 +- .../guichan-xml/AndroidAppSettings.cfg | 15 +- .../application/guichan-xml/sdlguiexample.cpp | 476 +++-- .../jni/application/guichan-xml/xmlgui.cpp | 1730 ++++++++--------- project/jni/application/guichan-xml/xmlgui.h | 306 +-- 5 files changed, 1298 insertions(+), 1231 deletions(-) diff --git a/project/jni/application/commandergenius/commandergenius b/project/jni/application/commandergenius/commandergenius index 8e8424dbb..1bcbadd1e 160000 --- a/project/jni/application/commandergenius/commandergenius +++ b/project/jni/application/commandergenius/commandergenius @@ -1 +1 @@ -Subproject commit 8e8424dbb390713ba3fde3e1622c6d6046602002 +Subproject commit 1bcbadd1eadd735235288463239c348f5b58f845 diff --git a/project/jni/application/guichan-xml/AndroidAppSettings.cfg b/project/jni/application/guichan-xml/AndroidAppSettings.cfg index f047d26ff..92e723b31 100644 --- a/project/jni/application/guichan-xml/AndroidAppSettings.cfg +++ b/project/jni/application/guichan-xml/AndroidAppSettings.cfg @@ -75,6 +75,10 @@ CompatibilityHacksSlowCompatibleEventQueue=n # Save and restore OpenGL state when drawing on-screen keyboard for apps that use SDL_OPENGL CompatibilityHacksTouchscreenKeyboardSaveRestoreOpenGLState= +# Application uses SDL_UpdateRects() properly, and does not draw in any region outside those rects. +# This improves drawing speed, but I know only one application that does that, and it's written by me (y)/(n) +CompatibilityHacksProperUsageOfSDL_UpdateRects= + # Application uses mouse (y) or (n), this will show mouse emulation dialog to the user AppUsesMouse=y @@ -82,10 +86,13 @@ AppUsesMouse=y AppNeedsTwoButtonMouse=y # Show SDL mouse cursor, for applications that do not draw cursor at all (y) or (n) -ShowMouseCursor=n +ShowMouseCursor=y + +# Generate more touch events, by default SDL generates one event per one video frame, this is useful for drawing apps (y) or (n) +GenerateSubframeTouchEvents= # Force relative (laptop) mouse movement mode, useful when both on-screen keyboard and mouse are needed (y) or (n) -ForceRelativeMouseMode=n +ForceRelativeMouseMode=y # Application needs arrow keys (y) or (n), will show on-screen dpad/joystick (y) or (n) AppNeedsArrowKeys=n @@ -106,7 +113,7 @@ AppUsesAccelerometer=n AppUsesGyroscope=n # Application uses multitouch (y) or (n), multitouch events are passed as SDL_JOYBALLMOTION events for the joystick 0 -AppUsesMultitouch=n +AppUsesMultitouch=y # Application records audio (it will use any available source, such a s microphone) # API is defined in file SDL_android.h: int SDL_ANDROID_OpenAudioRecording(SDL_AudioSpec *spec); void SDL_ANDROID_CloseAudioRecording(void); @@ -179,7 +186,7 @@ AppVersionName="1.01" ResetSdlConfigForThisVersion=n # Delete application data files when upgrading (specify file/dir paths separated by spaces) -DeleteFilesOnUpgrade="" +DeleteFilesOnUpgrade="%" # Optional shared libraries to compile - removing some of them will save space # MP3 support by libMAD is encumbered by patents and libMAD is GPL-ed diff --git a/project/jni/application/guichan-xml/sdlguiexample.cpp b/project/jni/application/guichan-xml/sdlguiexample.cpp index db984a42b..90bc244dc 100644 --- a/project/jni/application/guichan-xml/sdlguiexample.cpp +++ b/project/jni/application/guichan-xml/sdlguiexample.cpp @@ -1,208 +1,268 @@ -/** - * SDL Hello World example for Guichan. - */ - -// Include all necessary headers. -#include -#include -#include -#include -#include "xmlgui.h" -/* - * Common stuff we need - */ -bool running = true; - -/* - * SDL Stuff we need - */ -SDL_Surface* screen; -SDL_Event event; - -/* - * Guichan SDL stuff we need - */ -gcn::SDLInput* input; // Input driver -gcn::SDLGraphics* graphics; // Graphics driver -gcn::SDLImageLoader* imageLoader; // For loading images - -/* - * Guichan stuff we need - */ -gcn::Gui* gui; // A Gui object - binds it all together -gcn::Container* top; // A top container -gcn::ImageFont* font; // A font - -//XmlGui stuff -XmlGui *xmlgui = new XmlGui(); - -/** - * Initializes the Hello World - */ -void init() -{ - /* - * Here we initialize SDL as we would do with any SDL application. - */ - SDL_Init(SDL_INIT_VIDEO); - screen = SDL_SetVideoMode(640, 480, 32, SDL_HWSURFACE); - // We want unicode - SDL_EnableUNICODE(1); - // We want to enable key repeat - SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); - - /* - * Now it's time for Guichan SDL stuff - */ - imageLoader = new gcn::SDLImageLoader(); - // The ImageLoader in use is static and must be set to be - // able to load images - gcn::Image::setImageLoader(imageLoader); - graphics = new gcn::SDLGraphics(); - // Set the target for the graphics object to be the screen. - // In other words, we will draw to the screen. - // Note, any surface will do, it doesn't have to be the screen. - graphics->setTarget(screen); - input = new gcn::SDLInput(); - - /* - * Last but not least it's time to initialize and create the gui - * with Guichan stuff. - */ - gui = new gcn::Gui(); - // Set gui to use the SDLGraphics object. - gui->setGraphics(graphics); - // Set gui to use the SDLInput object - gui->setInput(input); - // Set the top container - gui->setTop(top); - // Load the image font. - font = new gcn::ImageFont("fixedfont.bmp", " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"); - // The global font is static and must be set. - gcn::Widget::setGlobalFont(font); - - xmlgui = new XmlGui(); - xmlgui->parse("gui.xml"); - gui->setTop(xmlgui->getWidget("top")); -} - -/** - * Halts the application - */ -void halt() -{ - /* - * Destroy Guichan stuff - */ - delete xmlgui; - delete font; - delete top; - delete gui; - - /* - * Destroy Guichan SDL stuff - */ - delete input; - delete graphics; - delete imageLoader; - - /* - * Destroy SDL stuff - */ - SDL_Quit(); -} - -/** - * Checks input. On escape halt the application. - */ -void checkInput() -{ - /* - * Poll SDL events - */ - while(SDL_PollEvent(&event)) - { - if (event.type == SDL_KEYDOWN) - { - if (event.key.keysym.sym == SDLK_ESCAPE) - { - running = false; - } - if (event.key.keysym.sym == SDLK_f) - { - if (event.key.keysym.mod & KMOD_CTRL) - { - // Works with X11 only - SDL_WM_ToggleFullScreen(screen); - } - } - } - else if(event.type == SDL_QUIT) - { - running = false; - } - - /* - * Now that we are done polling and using SDL events we pass - * the leftovers to the SDLInput object to later be handled by - * the Gui. (This example doesn't require us to do this 'cause a - * label doesn't use input. But will do it anyway to show how to - * set up an SDL application with Guichan.) - */ - input->pushInput(event); - } -} - -/** - * Runs the application - */ -void run() -{ - while(running) - { - // Poll input - checkInput(); - // Let the gui perform it's logic (like handle input) - gui->logic(); - // Draw the gui - gui->draw(); - // Update the screen - SDL_Flip(screen); - } -} - -int main(int argc, char **argv) -{ - try - { - init(); - run(); - halt(); - } - /* - * Catch all Guichan exceptions - */ - catch (gcn::Exception e) - { - std::cerr << e.getMessage() << std::endl; - return 1; - } - /* - * Catch all Std exceptions - */ - catch (std::exception e) - { - std::cerr << "Std exception: " << e.what() << std::endl; - return 1; - } - /* - * Catch all Unknown exceptions - */ - catch (...) - { - std::cerr << "Unknown exception" << std::endl; - return 1; - } - - return 0; -} +/** + * SDL Hello World example for Guichan. + */ + +// Include all necessary headers. +#include +#include +#include +#include +//#include +#include "xmlgui.h" + +/* + * Common stuff we need + */ +bool running = true; + +/* + * SDL Stuff we need + */ +SDL_Surface* screen; +SDL_Event event; + +/* + * Guichan SDL stuff we need + */ +gcn::SDLInput* input; // Input driver +gcn::SDLGraphics* graphics; // Graphics driver +gcn::SDLImageLoader* imageLoader; // For loading images + +/* + * Guichan stuff we need + */ +gcn::Gui* gui; // A Gui object - binds it all together +gcn::Container* top; // A top container +gcn::ImageFont* font; // A font + +//XmlGui stuff +XmlGui *xmlgui = new XmlGui(); + +/** + * Initializes the Hello World + */ +void init() +{ + /* + * Here we initialize SDL as we would do with any SDL application. + */ + SDL_Init(SDL_INIT_VIDEO); + screen = SDL_SetVideoMode(640, 480, 32, SDL_HWSURFACE); + // We want unicode + SDL_EnableUNICODE(1); + // We want to enable key repeat + SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); + // Enable Android multitouch + SDL_InitSubSystem(SDL_INIT_JOYSTICK); + SDL_JoystickOpen(0); + + /* + * Now it's time for Guichan SDL stuff + */ + imageLoader = new gcn::SDLImageLoader(); + // The ImageLoader in use is static and must be set to be + // able to load images + gcn::Image::setImageLoader(imageLoader); + graphics = new gcn::SDLGraphics(); + // Set the target for the graphics object to be the screen. + // In other words, we will draw to the screen. + // Note, any surface will do, it doesn't have to be the screen. + graphics->setTarget(screen); + input = new gcn::SDLInput(); + + /* + * Last but not least it's time to initialize and create the gui + * with Guichan stuff. + */ + gui = new gcn::Gui(); + // Set gui to use the SDLGraphics object. + gui->setGraphics(graphics); + // Set gui to use the SDLInput object + gui->setInput(input); + // Set the top container + gui->setTop(top); + // Load the image font. + font = new gcn::ImageFont("fixedfont.bmp", " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"); + // The global font is static and must be set. + gcn::Widget::setGlobalFont(font); + + xmlgui = new XmlGui(); + xmlgui->parse("gui.xml"); + gui->setTop(xmlgui->getWidget("top")); +} + +/** + * Halts the application + */ +void halt() +{ + /* + * Destroy Guichan stuff + */ + delete xmlgui; + delete font; + delete top; + delete gui; + + /* + * Destroy Guichan SDL stuff + */ + delete input; + delete graphics; + delete imageLoader; + + /* + * Destroy SDL stuff + */ + SDL_Quit(); +} + +/** + * Checks input. On escape halt the application. + */ +void checkInput() +{ + /* + * Poll SDL events + */ + while(SDL_PollEvent(&event)) + { + if (event.type == SDL_KEYDOWN) + { + if (event.key.keysym.sym == SDLK_ESCAPE) + { + running = false; + } + if (event.key.keysym.sym == SDLK_f) + { + if (event.key.keysym.mod & KMOD_CTRL) + { + // Works with X11 only + SDL_WM_ToggleFullScreen(screen); + } + } + } + else if(event.type == SDL_QUIT) + { + running = false; + } + + /* + * Now that we are done polling and using SDL events we pass + * the leftovers to the SDLInput object to later be handled by + * the Gui. (This example doesn't require us to do this 'cause a + * label doesn't use input. But will do it anyway to show how to + * set up an SDL application with Guichan.) + */ + if (event.type == SDL_MOUSEMOTION || + event.type == SDL_MOUSEBUTTONDOWN || + event.type == SDL_MOUSEBUTTONUP) + { + // Filter emulated mouse events for Guichan, we wand absolute input + } + else + { + // Convert multitouch event to SDL mouse event + static int x = 0, y = 0, buttons = 0; + SDL_Event event2; + memcpy(&event2, &event, sizeof(event)); + if (event.type == SDL_JOYBALLMOTION && + event.jball.which == 0 && + event.jball.ball == 0) + { + event2.type = SDL_MOUSEMOTION; + event2.motion.which = 0; + event2.motion.state = buttons; + event2.motion.xrel = event.jball.xrel - x; + event2.motion.yrel = event.jball.yrel - y; + x = event.jball.xrel; + y = event.jball.yrel; + event2.motion.x = x; + event2.motion.y = y; + //__android_log_print(ANDROID_LOG_INFO, "GUICHAN","Mouse motion %d %d btns %d", x, y, buttons); + if (buttons == 0) + { + // Push mouse motion event first, then button down event + input->pushInput(event2); + buttons = SDL_BUTTON_LMASK; + event2.type = SDL_MOUSEBUTTONDOWN; + event2.button.which = 0; + event2.button.button = SDL_BUTTON_LEFT; + event2.button.state = SDL_PRESSED; + event2.button.x = x; + event2.button.y = y; + //__android_log_print(ANDROID_LOG_INFO, "GUICHAN","Mouse button %d coords %d %d", buttons, x, y); + } + } + if (event.type == SDL_JOYBUTTONUP && + event.jbutton.which == 0 && + event.jbutton.button == 0) + { + // Do not push button down event here, because we need mouse motion event first + buttons = 0; + event2.type = SDL_MOUSEBUTTONUP; + event2.button.which = 0; + event2.button.button = SDL_BUTTON_LEFT; + event2.button.state = SDL_RELEASED; + event2.button.x = x; + event2.button.y = y; + //__android_log_print(ANDROID_LOG_INFO, "GUICHAN","Mouse button %d coords %d %d", buttons, x, y); + } + input->pushInput(event2); + } + } +} + +/** + * Runs the application + */ +void run() +{ + while(running) + { + // Poll input + checkInput(); + // Let the gui perform it's logic (like handle input) + gui->logic(); + // Draw the gui + gui->draw(); + // Update the screen + SDL_Flip(screen); + } +} + +int main(int argc, char **argv) +{ + try + { + init(); + run(); + halt(); + } + /* + * Catch all Guichan exceptions + */ + catch (gcn::Exception e) + { + std::cerr << e.getMessage() << std::endl; + return 1; + } + /* + * Catch all Std exceptions + */ + catch (std::exception e) + { + std::cerr << "Std exception: " << e.what() << std::endl; + return 1; + } + /* + * Catch all Unknown exceptions + */ + catch (...) + { + std::cerr << "Unknown exception" << std::endl; + return 1; + } + + return 0; +} diff --git a/project/jni/application/guichan-xml/xmlgui.cpp b/project/jni/application/guichan-xml/xmlgui.cpp index 3deb9273b..3fc066b60 100644 --- a/project/jni/application/guichan-xml/xmlgui.cpp +++ b/project/jni/application/guichan-xml/xmlgui.cpp @@ -1,865 +1,865 @@ -#include "xmlgui.h" -#include -#include - -XmlGui::XmlGui() -{ - -} - -bool XmlGui::parse(const std::string &filename) -{ - TiXmlElement *element = NULL; - TiXmlNode *node = NULL; - - doc = new TiXmlDocument(filename.c_str()); - - bool loadOkay = doc->LoadFile(); - - if ( !loadOkay ) - { - throw GCN_EXCEPTION("Error parsing xml file."); - } - node = doc->FirstChild(); - - if(node == NULL) - { - throw GCN_EXCEPTION("Xml document is null or has errors."); - } - - while(node!=NULL) - { - element = node->ToElement(); - parseWidgets(element,NULL); - node = doc->IterateChildren(node); - } - - return true; -} - -void XmlGui::addToParent(gcn::Widget *widget,gcn::Widget *parent) -{ - if(!parent) return; - - gcn::Container* top = dynamic_cast(parent); - - if(top) - { - top->add(widget); - } - else - { - gcn::Window* window = dynamic_cast(parent); - - if(window) -// window->setContent(widget); - window->add(widget); - else - { - gcn::ScrollArea* scrollarea = dynamic_cast(parent); - scrollarea->setContent(widget); - } - } - -} - -void XmlGui::parseWidgets(TiXmlElement *element, gcn::Widget *parent) -{ - if(!element) return; - - std::string value = element->Value(); - - if(value == "container") - parseContainer(element,parent); - if(value == "label") - parseLabel(element,parent); - else if(value == "radiobutton") - parseRadioButton(element,parent); - else if(value == "button") - parseButton(element,parent); - else if(value == "checkbox") - parseCheckBox(element,parent); - else if(value == "icon") - parseIcon(element,parent); - else if(value == "textbox") - parseTextBox(element,parent); - else if(value == "textfield") - parseTextField(element,parent); - else if(value == "slider") - parseSlider(element,parent); - else if(value == "window") - parseWindow(element,parent); - else if(value == "scrollarea") - parseScrollArea(element,parent); - else if(value == "dropdown") - parseDropdown(element,parent); - else if(value == "listbox") - parseListbox(element,parent); -} - -void XmlGui::parseDefaults(TiXmlElement *element, gcn::Widget *widget) -{ - if(!element) return; - - - if(element->Attribute("x")) - { - int x = atoi(element->Attribute("x")->c_str()); - widget->setX(x); - } - - - if(element->Attribute("y")) - { - int y = atoi(element->Attribute("y")->c_str()); - widget->setY(y); - } - - - if(element->Attribute("width")) - { - int w = atoi(element->Attribute("width")->c_str()); - widget->setWidth(w); - } - - if(element->Attribute("height")) - { - int h = atoi(element->Attribute("height")->c_str()); - widget->setHeight(h); - } - - if(element->Attribute("basecolor")) - { - int color; - sscanf(element->Attribute("basecolor")->c_str(),"%x",&color); - widget->setBaseColor(gcn::Color(color)); - } - - if(element->Attribute("foregroundcolor")) - { - int color; - sscanf(element->Attribute("foregroundcolor")->c_str(),"%x",&color); - widget->setForegroundColor(gcn::Color(color)); - } - - if(element->Attribute("backgroundcolor")) - { - int color; - sscanf(element->Attribute("backgroundcolor")->c_str(),"%x",&color); - widget->setBackgroundColor(gcn::Color(color)); - } - - - if(element->Attribute("frame")) - { - int b = atoi(element->Attribute("framesize")->c_str()); - widget->setFrameSize(b); - } - - if(element->Attribute("font")) - { - if(fonts[*element->Attribute("font")]) - widget->setFont(fonts[*element->Attribute("visible")]); - } - - if(element->Attribute("visible")) - widget->setVisible(checkBool(*element->Attribute("visible"))); - - if(element->Attribute("focusable")) - widget->setFocusable(checkBool(*element->Attribute("focusable"))); - - if(element->Attribute("enabled")) - widget->setEnabled(checkBool(*element->Attribute("enabled"))); - - if(element->Attribute("tabin")) - widget->setTabInEnabled(checkBool(*element->Attribute("tabin"))); - - if(element->Attribute("tabout")) - widget->setTabOutEnabled(checkBool(*element->Attribute("tabout"))); - - if(element->Attribute("eventId")) - widget->setActionEventId(*element->Attribute("eventId")); - - if(element->Attribute("actionListener")) - widget->addActionListener(actions[*element->Attribute("actionListener")]); -} - -void XmlGui::parseContainer(TiXmlElement *element, gcn::Widget *parent) -{ - - std::string name; - if(element->Attribute("name")) - { - name = element->Attribute("name")->c_str(); - }else - { - throw GCN_EXCEPTION("Container Widget must have a unique name"); - } - - gcn::Container *c = new gcn::Container(); - - - if(element->Attribute("opaque")) - c->setOpaque(checkBool(*element->Attribute("opaque"))); - - - parseDefaults(element,c); - - //parsing child elements - TiXmlNode *child = element->FirstChild(); - - if(child) - { - while(child) - { - TiXmlElement *e = child->ToElement(); - - parseWidgets(e,c); - - child = doc->IterateChildren(child); - } - } - - addToParent(c,parent); - widgets[name] = c; -} - -void XmlGui::parseLabel(TiXmlElement *element,gcn::Widget *parent) -{ - if(!element) - return; - - - std::string name; - - if(element->Attribute("name")) - { - name = *element->Attribute("name"); - }else - { - throw GCN_EXCEPTION("Label Widget must have a unique name"); - } - - - gcn::Label *label = new gcn::Label; - - - if(element->Attribute("caption")) - { - label->setCaption(*element->Attribute("caption")); - } - - label->adjustSize(); - - if(element->Attribute("align")) - { - if(*element->Attribute("align") == "center" || *element->Attribute("align") == "CENTER") - { - label->setAlignment(gcn::Graphics::CENTER); - }else if(*element->Attribute("align") == "left" || *element->Attribute("align") == "LEFT") - { - label->setAlignment(gcn::Graphics::LEFT); - }else - { - label->setAlignment(gcn::Graphics::RIGHT); - } - } - - parseDefaults(element,label); - - addToParent(label,parent); - widgets[name] = label; -} - -void XmlGui::parseButton(TiXmlElement *element,gcn::Widget *parent) -{ - if(!element) - return; - - - std::string name; - if(element->Attribute("name")) - { - name = element->Attribute("name")->c_str(); - }else - { - throw GCN_EXCEPTION("Button Widget must have a unique name"); - } - - gcn::Button *button = new gcn::Button; - - - if(element->Attribute("caption")) - { - button->setCaption(*element->Attribute("caption")); - } - - if(element->Attribute("align")) - { - if(*element->Attribute("align") == "center" || *element->Attribute("align") == "CENTER") - { - button->setAlignment(gcn::Graphics::CENTER); - }else if(*element->Attribute("align") == "left" || *element->Attribute("align") == "LEFT") - { - button->setAlignment(gcn::Graphics::LEFT); - }else - { - button->setAlignment(gcn::Graphics::RIGHT); - } - } - - button->adjustSize(); - - parseDefaults(element,button); - -// button->lostFocus(); //fix: this call must't exists -//????? - - addToParent(button,parent); - - widgets[name] = button; -} - -void XmlGui::parseCheckBox(TiXmlElement *element,gcn::Widget *parent) -{ - if(!element) - return; - - std::string name; - if(element->Attribute("name")) - { - name = element->Attribute("name")->c_str(); - }else - { - throw GCN_EXCEPTION("Checkbox Widget must have a unique name"); - } - - gcn::CheckBox *checkbox = new gcn::CheckBox; - - - if(element->Attribute("caption")) - { - checkbox->setCaption(*element->Attribute("caption")); - } - - checkbox->adjustSize(); - - - if(element->Attribute("selected")) - checkbox->setSelected(checkBool(*element->Attribute("selected"))); - - parseDefaults(element,checkbox); - - - addToParent(checkbox,parent); - - widgets[name] = checkbox; -} - - -void XmlGui::parseRadioButton(TiXmlElement *element,gcn::Widget *parent) -{ - if(!element) - return; - - - std::string name; - if(element->Attribute("name")) - { - name = element->Attribute("name")->c_str(); - }else - { - throw GCN_EXCEPTION("RadioButton Widget must have a unique name"); - } - - gcn::RadioButton *radio = new gcn::RadioButton; - - if(element->Attribute("caption")) - { - radio->setCaption(*element->Attribute("caption")); - } - - radio->adjustSize(); - - - if(element->Attribute("selected")) - radio->setSelected(checkBool(*element->Attribute("selected"))); - - if(element->Attribute("group")) - radio->setGroup(*element->Attribute("group")); - - parseDefaults(element,radio); - - addToParent(radio,parent); - - widgets[name] = radio; -} - -void XmlGui::parseIcon(TiXmlElement *element,gcn::Widget *parent) -{ - if(!element) - return; - - - std::string name; - if(element->Attribute("name")) - { - name = element->Attribute("name")->c_str(); - }else - { - throw GCN_EXCEPTION("Icon Widget must have a unique name"); - } - - gcn::Icon *icon; - - gcn::Image *image; - - if(element->Attribute("image")) - { -// image = new gcn::Image(*element->Attribute("image")); - image = gcn::Image::load(*element->Attribute("image")); - } - - if(image) - { - icon = new gcn::Icon(image); - } - - parseDefaults(element,icon); - - addToParent(icon,parent); - widgets[name] = icon; -} - - -void XmlGui::parseTextBox(TiXmlElement *element,gcn::Widget *parent) -{ - if(!element) - return; - - - std::string name; - if(element->Attribute("name")) - { - name = element->Attribute("name")->c_str(); - }else - { - throw GCN_EXCEPTION("TextBox Widget must have a unique name"); - } - - gcn::TextBox *textbox = new gcn::TextBox; - - if(element->Attribute("editable")) - textbox->setEditable(checkBool(*element->Attribute("editable"))); - - if(element->Attribute("text")) - { - textbox->setText(*element->Attribute("text")); - } - - if(element->Attribute("opaque")) - textbox->setOpaque(checkBool(*element->Attribute("opaque"))); - - parseDefaults(element,textbox); - - addToParent(textbox,parent); - - widgets[name] = textbox; -} - -void XmlGui::parseTextField(TiXmlElement *element,gcn::Widget *parent) -{ - if(!element) - return; - - - std::string name; - if(element->Attribute("name")) - { - name = element->Attribute("name")->c_str(); - }else - { - throw GCN_EXCEPTION("TextField Widget must have a unique name"); - } - - gcn::TextField *textfield = new gcn::TextField; - - if(element->Attribute("text")) - { - textfield->setText(*element->Attribute("text")); - } - - parseDefaults(element,textfield); - - addToParent(textfield,parent); - - widgets[name] = textfield; -} - -void XmlGui::parseSlider(TiXmlElement *element,gcn::Widget *parent) -{ - if(!element) - return; - - - std::string name; - if(element->Attribute("name")) - { - name = element->Attribute("name")->c_str(); - }else - { - throw GCN_EXCEPTION("Slider Widget must have a unique name"); - } - - gcn::Slider *slider = new gcn::Slider; - - if(element->Attribute("start")) - { - int start = atoi(element->Attribute("start")->c_str()); - - slider->setScaleStart(start); - } - - if(element->Attribute("end")) - { - int end = atoi(element->Attribute("end")->c_str()); - slider->setScaleEnd(end); - } - - if(element->Attribute("value")) - { - int value = atoi(element->Attribute("value")->c_str()); - slider->setValue(value); - } - - if(element->Attribute("markerLength")) - { - int l = atoi(element->Attribute("markerLength")->c_str()); - slider->setMarkerLength(l); - } - - if(element->Attribute("stepLength")) - { - int l = atoi(element->Attribute("stepLength")->c_str()); - slider->setStepLength(l); - } - - if(element->Attribute("orientation")) - { - if(*element->Attribute("orientation") == "HORIZONTAL" || *element->Attribute("orientation") == "horizontal") - slider->setOrientation(gcn::Slider::HORIZONTAL); - else slider->setOrientation(gcn::Slider::VERTICAL); - } - - - - parseDefaults(element,slider); - - addToParent(slider,parent); - - widgets[name] = slider; -} - -void XmlGui::parseWindow(TiXmlElement *element,gcn::Widget *parent) -{ - if(!element) - return; - - - std::string name; - if(element->Attribute("name")) - { - name = *element->Attribute("name"); - }else - { - throw GCN_EXCEPTION("Window Widget must have a unique name"); - } - - gcn::Window *window = new gcn::Window; - - - if(element->Attribute("caption")) - { - window->setCaption(*element->Attribute("caption")); - } - - if(element->Attribute("tabbing")) - { - window->setPadding(checkBool(*element->Attribute("tabbing"))); - } - - if(element->Attribute("movable")) - { - window->setMovable(checkBool(*element->Attribute("movable"))); - } - - if(element->Attribute("titleBarHeight")) - { - int h = atoi(element->Attribute("titleBarHeight")->c_str()); - window->setTitleBarHeight(h); - } - - - if(element->Attribute("opaque")) - window->setOpaque(checkBool(*element->Attribute("opaque"))); - - - parseDefaults(element,window); - - //parsing child elements - TiXmlNode *child = element->FirstChild(); - - if(child) - { - while(child) - { - TiXmlElement *e = child->ToElement(); - parseWidgets(e,window); - child = doc->IterateChildren(child); - } - } - - - window->resizeToContent(); - - addToParent(window,parent); - - widgets[name] = window; -} - - -void XmlGui::parseScrollArea(TiXmlElement *element,gcn::Widget *parent) -{ - if(!element) - return; - - - std::string name; - if(element->Attribute("name")) - { - name = element->Attribute("name")->c_str(); - }else - { - throw GCN_EXCEPTION("ScrollArea Widget must have a unique name"); - } - - gcn::ScrollArea *scroll = new gcn::ScrollArea; - - - if(element->Attribute("hPolicy")) - { - if(*element->Attribute("hPolicy") == "ALWAYS" || *element->Attribute("hPolicy") == "always") - scroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_ALWAYS); - else if(*element->Attribute("hPolicy") == "NEVER" || *element->Attribute("hPolicy") == "never") - scroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); - } - - if(element->Attribute("vPolicy")) - { - if(*element->Attribute("vPolicy") == "ALWAYS" || *element->Attribute("vPolicy") == "always") - scroll->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_ALWAYS); - else if(*element->Attribute("vPolicy") == "NEVER" || *element->Attribute("vPolicy") == "never") - scroll->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); - } - - if(element->Attribute("vScrollAmount")) - { - int h; - sscanf(element->Attribute("vScrollAmount")->c_str(),"%d",&h); - scroll->setVerticalScrollAmount(h); - } - - if(element->Attribute("hScrollAmount")) - { - int h = atoi(element->Attribute("hScrollAmount")->c_str()); - scroll->setHorizontalScrollAmount(h); - } - - if(element->Attribute("scrollBarWidth")) - { - int w = atoi(element->Attribute("scrollbarWidth")->c_str()); - scroll->setScrollbarWidth(w); - } - - if(element->Attribute("content")) - { - gcn::Widget *content = getWidget(*element->Attribute("content")); - if(content) - { - scroll->setContent(content); - } - } - - parseDefaults(element,scroll); - - if(!scroll->getContent()) - { - - //parsing child elements - TiXmlNode *child = element->FirstChild(); - - if(child) - { - while(child) - { - TiXmlElement *e = child->ToElement(); - - parseWidgets(e,scroll); - - child = doc->IterateChildren(child); - } - } - } - - - addToParent(scroll,parent); - - widgets[name] = scroll; -} - -void XmlGui::parseDropdown(TiXmlElement *element,gcn::Widget *parent) -{ - if(!element) - return; - - - std::string name; - if(element->Attribute("name")) - { - name = element->Attribute("name")->c_str(); - }else - { - throw GCN_EXCEPTION("DropDown Widget must have a unique name"); - } - - gcn::DropDown *dropdown = new gcn::DropDown; - - - parseDefaults(element,dropdown); - - XmlListModel *listmodel; - //parsing child elements - TiXmlNode *child = element->FirstChild(); - - if(child) - { - - listmodel = new XmlListModel; - - while(child) - { - TiXmlElement *e = child->ToElement(); - if(e->Value() == "li") - { - listmodel->items.push_back(e->FirstChild()->Value()); - } - child = doc->IterateChildren(child); - } - } - - if(listmodel) - dropdown->setListModel(listmodel); - - if(element->Attribute("selected")) - { - int s = atoi(element->Attribute("selected")->c_str()); - dropdown->setSelected(s); - } - - addToParent(dropdown,parent); - widgets[name] = dropdown; -} - -void XmlGui::parseListbox(TiXmlElement *element,gcn::Widget *parent) -{ - if(!element) - return; - - - std::string name; - if(element->Attribute("name")) - { - name = element->Attribute("name")->c_str(); - }else - { - throw GCN_EXCEPTION("ListBox Widget must have a unique name"); - } - - gcn::ListBox *listbox = new gcn::ListBox; - - - parseDefaults(element,listbox); - - XmlListModel *listmodel; - //parsing child elements - TiXmlNode *child = element->FirstChild(); - - if(child) - { - - listmodel = new XmlListModel; - - while(child) - { - TiXmlElement *e = child->ToElement(); - if(e->Value() == "li") - { - listmodel->items.push_back(e->FirstChild()->Value()); - } - child = doc->IterateChildren(child); - } - } - - if(listmodel) - listbox->setListModel(listmodel); - - if(element->Attribute("selected")) - { - int s = atoi(element->Attribute("selected")->c_str()); - listbox->setSelected(s); - } - - addToParent(listbox,parent); - widgets[name] = listbox; -} - - -gcn::Widget *XmlGui::getWidget(const std::string &name) -{ - - std::map::iterator it = widgets.find(name); - if(it == widgets.end()) { - return NULL; - } - - return widgets[name]; -} - -bool XmlGui::checkBool(const std::string &value) -{ - return (value == "1" || value == "true" || value == "True"); -} - -void XmlGui::addActionListener(const std::string &name, gcn::ActionListener *al) -{ - if(al) - actions[name] = al; -} - -void XmlGui::addFont(const std::string &name, gcn::Font *font) -{ - if(font) - fonts[name] = font; -} - - -int XmlListModel::getNumberOfElements() -{ - return items.size(); -} - -std::string XmlListModel::getElementAt(int i) -{ - return items[i]; -} - +#include "xmlgui.h" +#include +#include + +XmlGui::XmlGui() +{ + +} + +bool XmlGui::parse(const std::string &filename) +{ + TiXmlElement *element = NULL; + TiXmlNode *node = NULL; + + doc = new TiXmlDocument(filename.c_str()); + + bool loadOkay = doc->LoadFile(); + + if ( !loadOkay ) + { + throw GCN_EXCEPTION("Error parsing xml file."); + } + node = doc->FirstChild(); + + if(node == NULL) + { + throw GCN_EXCEPTION("Xml document is null or has errors."); + } + + while(node!=NULL) + { + element = node->ToElement(); + parseWidgets(element,NULL); + node = doc->IterateChildren(node); + } + + return true; +} + +void XmlGui::addToParent(gcn::Widget *widget,gcn::Widget *parent) +{ + if(!parent) return; + + gcn::Container* top = dynamic_cast(parent); + + if(top) + { + top->add(widget); + } + else + { + gcn::Window* window = dynamic_cast(parent); + + if(window) +// window->setContent(widget); + window->add(widget); + else + { + gcn::ScrollArea* scrollarea = dynamic_cast(parent); + scrollarea->setContent(widget); + } + } + +} + +void XmlGui::parseWidgets(TiXmlElement *element, gcn::Widget *parent) +{ + if(!element) return; + + std::string value = element->Value(); + + if(value == "container") + parseContainer(element,parent); + if(value == "label") + parseLabel(element,parent); + else if(value == "radiobutton") + parseRadioButton(element,parent); + else if(value == "button") + parseButton(element,parent); + else if(value == "checkbox") + parseCheckBox(element,parent); + else if(value == "icon") + parseIcon(element,parent); + else if(value == "textbox") + parseTextBox(element,parent); + else if(value == "textfield") + parseTextField(element,parent); + else if(value == "slider") + parseSlider(element,parent); + else if(value == "window") + parseWindow(element,parent); + else if(value == "scrollarea") + parseScrollArea(element,parent); + else if(value == "dropdown") + parseDropdown(element,parent); + else if(value == "listbox") + parseListbox(element,parent); +} + +void XmlGui::parseDefaults(TiXmlElement *element, gcn::Widget *widget) +{ + if(!element) return; + + + if(element->Attribute("x")) + { + int x = atoi(element->Attribute("x")->c_str()); + widget->setX(x); + } + + + if(element->Attribute("y")) + { + int y = atoi(element->Attribute("y")->c_str()); + widget->setY(y); + } + + + if(element->Attribute("width")) + { + int w = atoi(element->Attribute("width")->c_str()); + widget->setWidth(w); + } + + if(element->Attribute("height")) + { + int h = atoi(element->Attribute("height")->c_str()); + widget->setHeight(h); + } + + if(element->Attribute("basecolor")) + { + int color; + sscanf(element->Attribute("basecolor")->c_str(),"%x",&color); + widget->setBaseColor(gcn::Color(color)); + } + + if(element->Attribute("foregroundcolor")) + { + int color; + sscanf(element->Attribute("foregroundcolor")->c_str(),"%x",&color); + widget->setForegroundColor(gcn::Color(color)); + } + + if(element->Attribute("backgroundcolor")) + { + int color; + sscanf(element->Attribute("backgroundcolor")->c_str(),"%x",&color); + widget->setBackgroundColor(gcn::Color(color)); + } + + + if(element->Attribute("frame")) + { + int b = atoi(element->Attribute("framesize")->c_str()); + widget->setFrameSize(b); + } + + if(element->Attribute("font")) + { + if(fonts[*element->Attribute("font")]) + widget->setFont(fonts[*element->Attribute("visible")]); + } + + if(element->Attribute("visible")) + widget->setVisible(checkBool(*element->Attribute("visible"))); + + if(element->Attribute("focusable")) + widget->setFocusable(checkBool(*element->Attribute("focusable"))); + + if(element->Attribute("enabled")) + widget->setEnabled(checkBool(*element->Attribute("enabled"))); + + if(element->Attribute("tabin")) + widget->setTabInEnabled(checkBool(*element->Attribute("tabin"))); + + if(element->Attribute("tabout")) + widget->setTabOutEnabled(checkBool(*element->Attribute("tabout"))); + + if(element->Attribute("eventId")) + widget->setActionEventId(*element->Attribute("eventId")); + + if(element->Attribute("actionListener")) + widget->addActionListener(actions[*element->Attribute("actionListener")]); +} + +void XmlGui::parseContainer(TiXmlElement *element, gcn::Widget *parent) +{ + + std::string name; + if(element->Attribute("name")) + { + name = element->Attribute("name")->c_str(); + }else + { + throw GCN_EXCEPTION("Container Widget must have a unique name"); + } + + gcn::Container *c = new gcn::Container(); + + + if(element->Attribute("opaque")) + c->setOpaque(checkBool(*element->Attribute("opaque"))); + + + parseDefaults(element,c); + + //parsing child elements + TiXmlNode *child = element->FirstChild(); + + if(child) + { + while(child) + { + TiXmlElement *e = child->ToElement(); + + parseWidgets(e,c); + + child = doc->IterateChildren(child); + } + } + + addToParent(c,parent); + widgets[name] = c; +} + +void XmlGui::parseLabel(TiXmlElement *element,gcn::Widget *parent) +{ + if(!element) + return; + + + std::string name; + + if(element->Attribute("name")) + { + name = *element->Attribute("name"); + }else + { + throw GCN_EXCEPTION("Label Widget must have a unique name"); + } + + + gcn::Label *label = new gcn::Label; + + + if(element->Attribute("caption")) + { + label->setCaption(*element->Attribute("caption")); + } + + label->adjustSize(); + + if(element->Attribute("align")) + { + if(*element->Attribute("align") == "center" || *element->Attribute("align") == "CENTER") + { + label->setAlignment(gcn::Graphics::CENTER); + }else if(*element->Attribute("align") == "left" || *element->Attribute("align") == "LEFT") + { + label->setAlignment(gcn::Graphics::LEFT); + }else + { + label->setAlignment(gcn::Graphics::RIGHT); + } + } + + parseDefaults(element,label); + + addToParent(label,parent); + widgets[name] = label; +} + +void XmlGui::parseButton(TiXmlElement *element,gcn::Widget *parent) +{ + if(!element) + return; + + + std::string name; + if(element->Attribute("name")) + { + name = element->Attribute("name")->c_str(); + }else + { + throw GCN_EXCEPTION("Button Widget must have a unique name"); + } + + gcn::Button *button = new gcn::Button; + + + if(element->Attribute("caption")) + { + button->setCaption(*element->Attribute("caption")); + } + + if(element->Attribute("align")) + { + if(*element->Attribute("align") == "center" || *element->Attribute("align") == "CENTER") + { + button->setAlignment(gcn::Graphics::CENTER); + }else if(*element->Attribute("align") == "left" || *element->Attribute("align") == "LEFT") + { + button->setAlignment(gcn::Graphics::LEFT); + }else + { + button->setAlignment(gcn::Graphics::RIGHT); + } + } + + button->adjustSize(); + + parseDefaults(element,button); + +// button->lostFocus(); //fix: this call must't exists +//????? + + addToParent(button,parent); + + widgets[name] = button; +} + +void XmlGui::parseCheckBox(TiXmlElement *element,gcn::Widget *parent) +{ + if(!element) + return; + + std::string name; + if(element->Attribute("name")) + { + name = element->Attribute("name")->c_str(); + }else + { + throw GCN_EXCEPTION("Checkbox Widget must have a unique name"); + } + + gcn::CheckBox *checkbox = new gcn::CheckBox; + + + if(element->Attribute("caption")) + { + checkbox->setCaption(*element->Attribute("caption")); + } + + checkbox->adjustSize(); + + + if(element->Attribute("selected")) + checkbox->setSelected(checkBool(*element->Attribute("selected"))); + + parseDefaults(element,checkbox); + + + addToParent(checkbox,parent); + + widgets[name] = checkbox; +} + + +void XmlGui::parseRadioButton(TiXmlElement *element,gcn::Widget *parent) +{ + if(!element) + return; + + + std::string name; + if(element->Attribute("name")) + { + name = element->Attribute("name")->c_str(); + }else + { + throw GCN_EXCEPTION("RadioButton Widget must have a unique name"); + } + + gcn::RadioButton *radio = new gcn::RadioButton; + + if(element->Attribute("caption")) + { + radio->setCaption(*element->Attribute("caption")); + } + + radio->adjustSize(); + + + if(element->Attribute("selected")) + radio->setSelected(checkBool(*element->Attribute("selected"))); + + if(element->Attribute("group")) + radio->setGroup(*element->Attribute("group")); + + parseDefaults(element,radio); + + addToParent(radio,parent); + + widgets[name] = radio; +} + +void XmlGui::parseIcon(TiXmlElement *element,gcn::Widget *parent) +{ + if(!element) + return; + + + std::string name; + if(element->Attribute("name")) + { + name = element->Attribute("name")->c_str(); + }else + { + throw GCN_EXCEPTION("Icon Widget must have a unique name"); + } + + gcn::Icon *icon; + + gcn::Image *image; + + if(element->Attribute("image")) + { +// image = new gcn::Image(*element->Attribute("image")); + image = gcn::Image::load(*element->Attribute("image")); + } + + if(image) + { + icon = new gcn::Icon(image); + } + + parseDefaults(element,icon); + + addToParent(icon,parent); + widgets[name] = icon; +} + + +void XmlGui::parseTextBox(TiXmlElement *element,gcn::Widget *parent) +{ + if(!element) + return; + + + std::string name; + if(element->Attribute("name")) + { + name = element->Attribute("name")->c_str(); + }else + { + throw GCN_EXCEPTION("TextBox Widget must have a unique name"); + } + + gcn::TextBox *textbox = new gcn::TextBox; + + if(element->Attribute("editable")) + textbox->setEditable(checkBool(*element->Attribute("editable"))); + + if(element->Attribute("text")) + { + textbox->setText(*element->Attribute("text")); + } + + if(element->Attribute("opaque")) + textbox->setOpaque(checkBool(*element->Attribute("opaque"))); + + parseDefaults(element,textbox); + + addToParent(textbox,parent); + + widgets[name] = textbox; +} + +void XmlGui::parseTextField(TiXmlElement *element,gcn::Widget *parent) +{ + if(!element) + return; + + + std::string name; + if(element->Attribute("name")) + { + name = element->Attribute("name")->c_str(); + }else + { + throw GCN_EXCEPTION("TextField Widget must have a unique name"); + } + + gcn::TextField *textfield = new gcn::TextField; + + if(element->Attribute("text")) + { + textfield->setText(*element->Attribute("text")); + } + + parseDefaults(element,textfield); + + addToParent(textfield,parent); + + widgets[name] = textfield; +} + +void XmlGui::parseSlider(TiXmlElement *element,gcn::Widget *parent) +{ + if(!element) + return; + + + std::string name; + if(element->Attribute("name")) + { + name = element->Attribute("name")->c_str(); + }else + { + throw GCN_EXCEPTION("Slider Widget must have a unique name"); + } + + gcn::Slider *slider = new gcn::Slider; + + if(element->Attribute("start")) + { + int start = atoi(element->Attribute("start")->c_str()); + + slider->setScaleStart(start); + } + + if(element->Attribute("end")) + { + int end = atoi(element->Attribute("end")->c_str()); + slider->setScaleEnd(end); + } + + if(element->Attribute("value")) + { + int value = atoi(element->Attribute("value")->c_str()); + slider->setValue(value); + } + + if(element->Attribute("markerLength")) + { + int l = atoi(element->Attribute("markerLength")->c_str()); + slider->setMarkerLength(l); + } + + if(element->Attribute("stepLength")) + { + int l = atoi(element->Attribute("stepLength")->c_str()); + slider->setStepLength(l); + } + + if(element->Attribute("orientation")) + { + if(*element->Attribute("orientation") == "HORIZONTAL" || *element->Attribute("orientation") == "horizontal") + slider->setOrientation(gcn::Slider::HORIZONTAL); + else slider->setOrientation(gcn::Slider::VERTICAL); + } + + + + parseDefaults(element,slider); + + addToParent(slider,parent); + + widgets[name] = slider; +} + +void XmlGui::parseWindow(TiXmlElement *element,gcn::Widget *parent) +{ + if(!element) + return; + + + std::string name; + if(element->Attribute("name")) + { + name = *element->Attribute("name"); + }else + { + throw GCN_EXCEPTION("Window Widget must have a unique name"); + } + + gcn::Window *window = new gcn::Window; + + + if(element->Attribute("caption")) + { + window->setCaption(*element->Attribute("caption")); + } + + if(element->Attribute("tabbing")) + { + window->setPadding(checkBool(*element->Attribute("tabbing"))); + } + + if(element->Attribute("movable")) + { + window->setMovable(checkBool(*element->Attribute("movable"))); + } + + if(element->Attribute("titleBarHeight")) + { + int h = atoi(element->Attribute("titleBarHeight")->c_str()); + window->setTitleBarHeight(h); + } + + + if(element->Attribute("opaque")) + window->setOpaque(checkBool(*element->Attribute("opaque"))); + + + parseDefaults(element,window); + + //parsing child elements + TiXmlNode *child = element->FirstChild(); + + if(child) + { + while(child) + { + TiXmlElement *e = child->ToElement(); + parseWidgets(e,window); + child = doc->IterateChildren(child); + } + } + + + window->resizeToContent(); + + addToParent(window,parent); + + widgets[name] = window; +} + + +void XmlGui::parseScrollArea(TiXmlElement *element,gcn::Widget *parent) +{ + if(!element) + return; + + + std::string name; + if(element->Attribute("name")) + { + name = element->Attribute("name")->c_str(); + }else + { + throw GCN_EXCEPTION("ScrollArea Widget must have a unique name"); + } + + gcn::ScrollArea *scroll = new gcn::ScrollArea; + + + if(element->Attribute("hPolicy")) + { + if(*element->Attribute("hPolicy") == "ALWAYS" || *element->Attribute("hPolicy") == "always") + scroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_ALWAYS); + else if(*element->Attribute("hPolicy") == "NEVER" || *element->Attribute("hPolicy") == "never") + scroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + } + + if(element->Attribute("vPolicy")) + { + if(*element->Attribute("vPolicy") == "ALWAYS" || *element->Attribute("vPolicy") == "always") + scroll->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_ALWAYS); + else if(*element->Attribute("vPolicy") == "NEVER" || *element->Attribute("vPolicy") == "never") + scroll->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + } + + if(element->Attribute("vScrollAmount")) + { + int h; + sscanf(element->Attribute("vScrollAmount")->c_str(),"%d",&h); + scroll->setVerticalScrollAmount(h); + } + + if(element->Attribute("hScrollAmount")) + { + int h = atoi(element->Attribute("hScrollAmount")->c_str()); + scroll->setHorizontalScrollAmount(h); + } + + if(element->Attribute("scrollBarWidth")) + { + int w = atoi(element->Attribute("scrollbarWidth")->c_str()); + scroll->setScrollbarWidth(w); + } + + if(element->Attribute("content")) + { + gcn::Widget *content = getWidget(*element->Attribute("content")); + if(content) + { + scroll->setContent(content); + } + } + + parseDefaults(element,scroll); + + if(!scroll->getContent()) + { + + //parsing child elements + TiXmlNode *child = element->FirstChild(); + + if(child) + { + while(child) + { + TiXmlElement *e = child->ToElement(); + + parseWidgets(e,scroll); + + child = doc->IterateChildren(child); + } + } + } + + + addToParent(scroll,parent); + + widgets[name] = scroll; +} + +void XmlGui::parseDropdown(TiXmlElement *element,gcn::Widget *parent) +{ + if(!element) + return; + + + std::string name; + if(element->Attribute("name")) + { + name = element->Attribute("name")->c_str(); + }else + { + throw GCN_EXCEPTION("DropDown Widget must have a unique name"); + } + + gcn::DropDown *dropdown = new gcn::DropDown; + + + parseDefaults(element,dropdown); + + XmlListModel *listmodel; + //parsing child elements + TiXmlNode *child = element->FirstChild(); + + if(child) + { + + listmodel = new XmlListModel; + + while(child) + { + TiXmlElement *e = child->ToElement(); + if(e->Value() == "li") + { + listmodel->items.push_back(e->FirstChild()->Value()); + } + child = doc->IterateChildren(child); + } + } + + if(listmodel) + dropdown->setListModel(listmodel); + + if(element->Attribute("selected")) + { + int s = atoi(element->Attribute("selected")->c_str()); + dropdown->setSelected(s); + } + + addToParent(dropdown,parent); + widgets[name] = dropdown; +} + +void XmlGui::parseListbox(TiXmlElement *element,gcn::Widget *parent) +{ + if(!element) + return; + + + std::string name; + if(element->Attribute("name")) + { + name = element->Attribute("name")->c_str(); + }else + { + throw GCN_EXCEPTION("ListBox Widget must have a unique name"); + } + + gcn::ListBox *listbox = new gcn::ListBox; + + + parseDefaults(element,listbox); + + XmlListModel *listmodel; + //parsing child elements + TiXmlNode *child = element->FirstChild(); + + if(child) + { + + listmodel = new XmlListModel; + + while(child) + { + TiXmlElement *e = child->ToElement(); + if(e->Value() == "li") + { + listmodel->items.push_back(e->FirstChild()->Value()); + } + child = doc->IterateChildren(child); + } + } + + if(listmodel) + listbox->setListModel(listmodel); + + if(element->Attribute("selected")) + { + int s = atoi(element->Attribute("selected")->c_str()); + listbox->setSelected(s); + } + + addToParent(listbox,parent); + widgets[name] = listbox; +} + + +gcn::Widget *XmlGui::getWidget(const std::string &name) +{ + + std::map::iterator it = widgets.find(name); + if(it == widgets.end()) { + return NULL; + } + + return widgets[name]; +} + +bool XmlGui::checkBool(const std::string &value) +{ + return (value == "1" || value == "true" || value == "True"); +} + +void XmlGui::addActionListener(const std::string &name, gcn::ActionListener *al) +{ + if(al) + actions[name] = al; +} + +void XmlGui::addFont(const std::string &name, gcn::Font *font) +{ + if(font) + fonts[name] = font; +} + + +int XmlListModel::getNumberOfElements() +{ + return items.size(); +} + +std::string XmlListModel::getElementAt(int i) +{ + return items[i]; +} + diff --git a/project/jni/application/guichan-xml/xmlgui.h b/project/jni/application/guichan-xml/xmlgui.h index 8d22509a5..80e55d5c9 100644 --- a/project/jni/application/guichan-xml/xmlgui.h +++ b/project/jni/application/guichan-xml/xmlgui.h @@ -1,155 +1,155 @@ -/* XmlGui - xml parsing class for guichan (http://guichan.sourceforge.net) - * author - quard (quard8@gmail.com) - * Changes: - * v. 0.4 - fixed bug in Visual Studio .NET 2003, when compiler option /GR is not enabled; - fixed widget allocation, when attribute "name" is't exists - deleted all "return false" after GCN_EXCEPTION, because they not used ever - * v. 0.3.5 - fixed stupid bug, when widgets not parsed if parent widget is NULL - * v. 0.3 - added parsing method for widget, - * now checking widget node is in one function - * v. 0.2 - small bug fix - * - added parsing widgets under 'container' - * - changed sscanf to atoi - * v. 0.1 - first public release -*/ - - -#ifndef XML_GUI_H -#define XML_GUI_H - -#include -#include "tinyxml.h" -#include - -//!XmlGui class for loading gui widget from xml file -class XmlGui -{ -public: - //!constructor - XmlGui(); - //!parse xml file - //@param filename the file name to parse - //@return true if loaded ok - bool parse(const std::string &filename); - - //@param name th widget name - //@return widget by name - gcn::Widget *getWidget(const std::string &name); - - //!parse default parameters for all widgets - //@param element the xml element - //@param widget the current widget - void parseDefaults(TiXmlElement *element, gcn::Widget *widget); - - //!parse container widget - //@param element the xml element - //@param widget the current widget - void parseContainer(TiXmlElement *element, gcn::Widget *parent); - - //!parse label widget - //@param element the xml element - //@param widget the current widget - void parseLabel(TiXmlElement *element, gcn::Widget *parent); - - //!parse button widget - //@param element the xml element - //@param widget the current widget - void parseButton(TiXmlElement *element, gcn::Widget *parent); - - //!parse checkbox widget - //@param element the xml element - //@param widget the current widget - void parseCheckBox(TiXmlElement *element, gcn::Widget *parent); - - //!parse radiobutton widget - //@param element the xml element - //@param widget the current widget - void parseRadioButton(TiXmlElement *element, gcn::Widget *parent); - - //!parse icon widget - //@param element the xml element - //@param widget the current widget - void parseIcon(TiXmlElement *element, gcn::Widget *parent); - - //!parse textbox widget - //@param element the xml element - //@param widget the current widget - void parseTextBox(TiXmlElement *element, gcn::Widget *parent); - - //!parse textfield widget - //@param element the xml element - //@param widget the current widget - void parseTextField(TiXmlElement *element, gcn::Widget *parent); - - //!parse slider widget - //@param element the xml element - //@param widget the current widget - void parseSlider(TiXmlElement *element, gcn::Widget *parent); - - //!parse window widget - //@param element the xml element - //@param widget the current widget - void parseWindow(TiXmlElement *element, gcn::Widget *parent); - - //!parse scrollarea widget - //@param element the xml element - //@param widget the current widget - void parseScrollArea(TiXmlElement *element,gcn::Widget *parent); - - //!parse dropdown widget - //@param element the xml element - //@param widget the current widget - void parseDropdown(TiXmlElement *element,gcn::Widget *parent); - - //!parse listbox widget - //@param element the xml element - //@param widget the current widget - void parseListbox(TiXmlElement *element,gcn::Widget *parent); - - //!add actionlistener to array - //@param name the actionlistener name - //@param al the pointer to actionlistener class - void addActionListener(const std::string &name,gcn::ActionListener *al); - - //!add font - //@param name the font name - //@param al the pointer to font class - void addFont(const std::string &name,gcn::Font *font); - - -private: - //!parse xml node - //@param element - xml element - //@param parent - the parent widget - void parseWidgets(TiXmlElement *element, gcn::Widget *parent); - - //!adding widget to parent - //!parent widget can be Container,ScrollArea,Window. this function get class and set widget or add widget (for Container) - //@param widget our widget - //@param parent the parent widget - void addToParent(gcn::Widget *widget, gcn::Widget *parent); - - //!check string value for boolean value - //@param value the string value - //@return true if value are "1" or "true" - bool checkBool(const std::string &value); - - - std::map widgets; - std::map actions; - std::map fonts; - - //temporary xml document (need by some functions) - TiXmlDocument *doc; -}; - -class XmlListModel : public gcn::ListModel -{ -public: - virtual int getNumberOfElements(); - virtual std::string getElementAt(int i); - std::vector items; -}; - +/* XmlGui - xml parsing class for guichan (http://guichan.sourceforge.net) + * author - quard (quard8@gmail.com) + * Changes: + * v. 0.4 - fixed bug in Visual Studio .NET 2003, when compiler option /GR is not enabled; + fixed widget allocation, when attribute "name" is't exists + deleted all "return false" after GCN_EXCEPTION, because they not used ever + * v. 0.3.5 - fixed stupid bug, when widgets not parsed if parent widget is NULL + * v. 0.3 - added parsing method for widget, + * now checking widget node is in one function + * v. 0.2 - small bug fix + * - added parsing widgets under 'container' + * - changed sscanf to atoi + * v. 0.1 - first public release +*/ + + +#ifndef XML_GUI_H +#define XML_GUI_H + +#include +#include "tinyxml.h" +#include + +//!XmlGui class for loading gui widget from xml file +class XmlGui +{ +public: + //!constructor + XmlGui(); + //!parse xml file + //@param filename the file name to parse + //@return true if loaded ok + bool parse(const std::string &filename); + + //@param name th widget name + //@return widget by name + gcn::Widget *getWidget(const std::string &name); + + //!parse default parameters for all widgets + //@param element the xml element + //@param widget the current widget + void parseDefaults(TiXmlElement *element, gcn::Widget *widget); + + //!parse container widget + //@param element the xml element + //@param widget the current widget + void parseContainer(TiXmlElement *element, gcn::Widget *parent); + + //!parse label widget + //@param element the xml element + //@param widget the current widget + void parseLabel(TiXmlElement *element, gcn::Widget *parent); + + //!parse button widget + //@param element the xml element + //@param widget the current widget + void parseButton(TiXmlElement *element, gcn::Widget *parent); + + //!parse checkbox widget + //@param element the xml element + //@param widget the current widget + void parseCheckBox(TiXmlElement *element, gcn::Widget *parent); + + //!parse radiobutton widget + //@param element the xml element + //@param widget the current widget + void parseRadioButton(TiXmlElement *element, gcn::Widget *parent); + + //!parse icon widget + //@param element the xml element + //@param widget the current widget + void parseIcon(TiXmlElement *element, gcn::Widget *parent); + + //!parse textbox widget + //@param element the xml element + //@param widget the current widget + void parseTextBox(TiXmlElement *element, gcn::Widget *parent); + + //!parse textfield widget + //@param element the xml element + //@param widget the current widget + void parseTextField(TiXmlElement *element, gcn::Widget *parent); + + //!parse slider widget + //@param element the xml element + //@param widget the current widget + void parseSlider(TiXmlElement *element, gcn::Widget *parent); + + //!parse window widget + //@param element the xml element + //@param widget the current widget + void parseWindow(TiXmlElement *element, gcn::Widget *parent); + + //!parse scrollarea widget + //@param element the xml element + //@param widget the current widget + void parseScrollArea(TiXmlElement *element,gcn::Widget *parent); + + //!parse dropdown widget + //@param element the xml element + //@param widget the current widget + void parseDropdown(TiXmlElement *element,gcn::Widget *parent); + + //!parse listbox widget + //@param element the xml element + //@param widget the current widget + void parseListbox(TiXmlElement *element,gcn::Widget *parent); + + //!add actionlistener to array + //@param name the actionlistener name + //@param al the pointer to actionlistener class + void addActionListener(const std::string &name,gcn::ActionListener *al); + + //!add font + //@param name the font name + //@param al the pointer to font class + void addFont(const std::string &name,gcn::Font *font); + + +private: + //!parse xml node + //@param element - xml element + //@param parent - the parent widget + void parseWidgets(TiXmlElement *element, gcn::Widget *parent); + + //!adding widget to parent + //!parent widget can be Container,ScrollArea,Window. this function get class and set widget or add widget (for Container) + //@param widget our widget + //@param parent the parent widget + void addToParent(gcn::Widget *widget, gcn::Widget *parent); + + //!check string value for boolean value + //@param value the string value + //@return true if value are "1" or "true" + bool checkBool(const std::string &value); + + + std::map widgets; + std::map actions; + std::map fonts; + + //temporary xml document (need by some functions) + TiXmlDocument *doc; +}; + +class XmlListModel : public gcn::ListModel +{ +public: + virtual int getNumberOfElements(); + virtual std::string getElementAt(int i); + std::vector items; +}; + #endif From 96d2e43bfb8e22bef74181b69979d42b4fc2421e Mon Sep 17 00:00:00 2001 From: pelya Date: Tue, 3 Dec 2013 20:45:00 +0200 Subject: [PATCH 2/4] Fix for MTK tablets with broken touch input --- project/java/Video.java | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/project/java/Video.java b/project/java/Video.java index 904b77536..c9c526f37 100644 --- a/project/java/Video.java +++ b/project/java/Video.java @@ -109,13 +109,18 @@ abstract class DifferentTouchInput multiTouchAvailable2 = true; } try { + Log.i("SDL", "Device: " + android.os.Build.DEVICE); + Log.i("SDL", "Device name: " + android.os.Build.DISPLAY); Log.i("SDL", "Device model: " + android.os.Build.MODEL); + Log.i("SDL", "Device board: " + android.os.Build.BOARD); if( android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH ) { if ( Globals.GenerateSubframeTouchEvents ) return IcsTouchInputWithHistory.Holder.sInstance; if( DetectCrappyDragonRiseDatexGamepad() ) return CrappyDragonRiseDatexGamepadInputWhichNeedsItsOwnHandlerBecauseImTooCheapAndStupidToBuyProperGamepad.Holder.sInstance; + if( (android.os.Build.BOARD.contains("bird")) + return CrappyMtkTabletWithBrokenTouchDrivers.Holder.sInstance return IcsTouchInput.Holder.sInstance; } if( android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.GINGERBREAD ) @@ -468,6 +473,23 @@ abstract class DifferentTouchInput return false; } } + private static class CrappyMtkTabletWithBrokenTouchDrivers extends IcsTouchInput + { + private static class Holder + { + private static final CrappyMtkTabletWithBrokenTouchDrivers sInstance = new CrappyMtkTabletWithBrokenTouchDrivers(); + } + public void process(final MotionEvent event) + { + if( event.getX() != 0.0f && event.getY() != 0.0f ) // Ignore event when it has zero coordinates + super.process(event); + } + public void processGenericEvent(final MotionEvent event) + { + if( event.getX() != 0.0f && event.getY() != 0.0f ) // Ignore event when it has zero coordinates + super.processGenericEvent(event); + } + } } From 41825b30e4157a96d5e88cd8dc2afbaed8db6ebb Mon Sep 17 00:00:00 2001 From: pelya Date: Tue, 3 Dec 2013 20:55:10 +0200 Subject: [PATCH 3/4] Oops, compilation error --- project/java/Video.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/project/java/Video.java b/project/java/Video.java index c9c526f37..d0cfbc57a 100644 --- a/project/java/Video.java +++ b/project/java/Video.java @@ -119,8 +119,8 @@ abstract class DifferentTouchInput return IcsTouchInputWithHistory.Holder.sInstance; if( DetectCrappyDragonRiseDatexGamepad() ) return CrappyDragonRiseDatexGamepadInputWhichNeedsItsOwnHandlerBecauseImTooCheapAndStupidToBuyProperGamepad.Holder.sInstance; - if( (android.os.Build.BOARD.contains("bird")) - return CrappyMtkTabletWithBrokenTouchDrivers.Holder.sInstance + if( android.os.Build.BOARD.contains("bird") ) + return CrappyMtkTabletWithBrokenTouchDrivers.Holder.sInstance; return IcsTouchInput.Holder.sInstance; } if( android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.GINGERBREAD ) From 7f0c344e5aea4c40a113dfaa3e298420f83084fd Mon Sep 17 00:00:00 2001 From: pelya Date: Tue, 3 Dec 2013 22:20:34 +0200 Subject: [PATCH 4/4] Added TTF support to Guichan library --- project/jni/guichan/Android.mk | 4 +- .../guichan/contrib/sdl/sdltruetypefont.hpp | 156 ++++++++++++++++ .../src/contrib/sdl/sdltruetypefont.cpp | 171 ++++++++++++++++++ 3 files changed, 329 insertions(+), 2 deletions(-) create mode 100644 project/jni/guichan/include/guichan/contrib/sdl/sdltruetypefont.hpp create mode 100644 project/jni/guichan/src/contrib/sdl/sdltruetypefont.cpp diff --git a/project/jni/guichan/Android.mk b/project/jni/guichan/Android.mk index a1400424b..30dedb31e 100644 --- a/project/jni/guichan/Android.mk +++ b/project/jni/guichan/Android.mk @@ -7,7 +7,7 @@ LOCAL_MODULE := guichan APP_SUBDIRS := $(patsubst $(LOCAL_PATH)/%, %, $(shell find $(LOCAL_PATH)/src -type d)) LOCAL_C_INCLUDES := $(LOCAL_PATH) $(LOCAL_PATH)/../sdl-$(SDL_VERSION)/include $(LOCAL_PATH)/include \ - $(LOCAL_PATH)/../sdl_image/include + $(LOCAL_PATH)/../sdl_image/include $(LOCAL_PATH)/../sdl_ttf/include LOCAL_CFLAGS := -DHAVE_CONFIG_H -D_GNU_SOURCE=1 -D_REENTRANT -fexceptions -frtti LOCAL_CPP_EXTENSION := .cpp @@ -16,7 +16,7 @@ LOCAL_SRC_FILES := $(foreach F, $(APP_SUBDIRS), $(addprefix $(F)/,$(notdir $(wil LOCAL_SRC_FILES += $(foreach F, $(APP_SUBDIRS), $(addprefix $(F)/,$(notdir $(wildcard $(LOCAL_PATH)/$(F)/*.c)))) LOCAL_SHARED_LIBRARIES := sdl-$(SDL_VERSION) -LOCAL_SHARED_LIBRARIES += sdl_image +LOCAL_SHARED_LIBRARIES += sdl_image sdl_ttf LOCAL_STATIC_LIBRARIES := diff --git a/project/jni/guichan/include/guichan/contrib/sdl/sdltruetypefont.hpp b/project/jni/guichan/include/guichan/contrib/sdl/sdltruetypefont.hpp new file mode 100644 index 000000000..34bf8a59c --- /dev/null +++ b/project/jni/guichan/include/guichan/contrib/sdl/sdltruetypefont.hpp @@ -0,0 +1,156 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GCN_CONTRIB_SDLTRUETYPEFONT_HPP +#define GCN_CONTRIB_SDLTRUETYPEFONT_HPP + +#include +#include + +#include + +#include "guichan/font.hpp" +#include "guichan/platform.hpp" + +namespace gcn +{ + class Graphics; + namespace contrib + { + + /** + * SDL True Type Font implementation of Font. It uses the SDL_ttf library + * to display True Type Fonts with SDL. + * + * NOTE: You must initialize the SDL_ttf library before using this + * class. Also, remember to call the SDL_ttf libraries quit + * function. + * + * @author Walluce Pinkham + * @author Olof Naessén + */ + class GCN_EXTENSION_DECLSPEC SDLTrueTypeFont: public Font + { + public: + + /** + * Constructor. + * + * @param filename the filename of the True Type Font. + * @param size the size the font should be in. + */ + SDLTrueTypeFont (const std::string& filename, int size); + + /** + * Destructor. + */ + virtual ~SDLTrueTypeFont(); + + /** + * Sets the spacing between rows in pixels. Default is 0 pixels. + * The spacing can be negative. + * + * @param spacing the spacing in pixels. + */ + virtual void setRowSpacing (int spacing); + + /** + * Gets the spacing between rows in pixels. + * + * @return the spacing. + */ + virtual int getRowSpacing(); + + /** + * Sets the spacing between letters in pixels. Default is 0 pixels. + * The spacing can be negative. + * + * @param spacing the spacing in pixels. + */ + virtual void setGlyphSpacing(int spacing); + + /** + * Gets the spacing between letters in pixels. + * + * @return the spacing. + */ + virtual int getGlyphSpacing(); + + /** + * Sets the use of anti aliasing.. + * + * @param antaAlias true for use of antia aliasing. + */ + virtual void setAntiAlias(bool antiAlias); + + /** + * Checks if anti aliasing is used. + * + * @return true if anti aliasing is used. + */ + virtual bool isAntiAlias(); + + + // Inherited from Font + + virtual int getWidth(const std::string& text) const; + + virtual int getHeight() const; + + virtual void drawString(Graphics* graphics, const std::string& text, int x, int y); + + protected: + TTF_Font *mFont; + + int mHeight; + int mGlyphSpacing; + int mRowSpacing; + + std::string mFilename; + bool mAntiAlias; + }; + } +} + +#endif + diff --git a/project/jni/guichan/src/contrib/sdl/sdltruetypefont.cpp b/project/jni/guichan/src/contrib/sdl/sdltruetypefont.cpp new file mode 100644 index 000000000..1fc11ed99 --- /dev/null +++ b/project/jni/guichan/src/contrib/sdl/sdltruetypefont.cpp @@ -0,0 +1,171 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * For comments regarding functions please see the header file. + */ + +#include "guichan/contrib/sdl/sdltruetypefont.hpp" + +#include "guichan/exception.hpp" +#include "guichan/image.hpp" +#include "guichan/graphics.hpp" +#include "guichan/sdl/sdlgraphics.hpp" + +namespace gcn +{ + namespace contrib + { + SDLTrueTypeFont::SDLTrueTypeFont (const std::string& filename, int size) + { + mRowSpacing = 0; + mGlyphSpacing = 0; + mAntiAlias = true; + mFilename = filename; + mFont = NULL; + + mFont = TTF_OpenFont(filename.c_str(), size); + + if (mFont == NULL) + { + throw GCN_EXCEPTION("SDLTrueTypeFont::SDLTrueTypeFont. "+std::string(TTF_GetError())); + } + } + + SDLTrueTypeFont::~SDLTrueTypeFont() + { + TTF_CloseFont(mFont); + } + + int SDLTrueTypeFont::getWidth(const std::string& text) const + { + int w, h; + TTF_SizeText(mFont, text.c_str(), &w, &h); + + return w; + } + + int SDLTrueTypeFont::getHeight() const + { + return TTF_FontHeight(mFont) + mRowSpacing; + } + + void SDLTrueTypeFont::drawString(gcn::Graphics* graphics, const std::string& text, const int x, const int y) + { + if (text == "") + { + return; + } + + gcn::SDLGraphics *sdlGraphics = dynamic_cast(graphics); + + if (sdlGraphics == NULL) + { + throw GCN_EXCEPTION("SDLTrueTypeFont::drawString. Graphics object not an SDL graphics object!"); + return; + } + + // This is needed for drawing the Glyph in the middle if we have spacing + int yoffset = getRowSpacing() / 2; + + Color col = sdlGraphics->getColor(); + + SDL_Color sdlCol; + sdlCol.b = col.b; + sdlCol.r = col.r; + sdlCol.g = col.g; + + SDL_Surface *textSurface; + if (mAntiAlias) + { + textSurface = TTF_RenderText_Blended(mFont, text.c_str(), sdlCol); + } + else + { + textSurface = TTF_RenderText_Solid(mFont, text.c_str(), sdlCol); + } + + SDL_Rect dst, src; + dst.x = x; + dst.y = y + yoffset; + src.w = textSurface->w; + src.h = textSurface->h; + src.x = 0; + src.y = 0; + + sdlGraphics->drawSDLSurface(textSurface, src, dst); + SDL_FreeSurface(textSurface); + } + + void SDLTrueTypeFont::setRowSpacing(int spacing) + { + mRowSpacing = spacing; + } + + int SDLTrueTypeFont::getRowSpacing() + { + return mRowSpacing; + } + + void SDLTrueTypeFont::setGlyphSpacing(int spacing) + { + mGlyphSpacing = spacing; + } + + int SDLTrueTypeFont::getGlyphSpacing() + { + return mGlyphSpacing; + } + + void SDLTrueTypeFont::setAntiAlias(bool antiAlias) + { + mAntiAlias = antiAlias; + } + + bool SDLTrueTypeFont::isAntiAlias() + { + return mAntiAlias; + } + } +} +