diff --git a/CMakeLists.txt b/CMakeLists.txt index 88c27925..11e99543 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,7 +52,7 @@ IF(CMAKE_BUILD_TYPE STREQUAL "Debug") ADD_DEFINITIONS(-D_DEBUG) ENDIF(CMAKE_BUILD_TYPE STREQUAL "Debug") -SET(SOURCES src/framework/ui/uilinedecorationskin.cpp src/framework/ui/uicheckboxskin.cpp src/framework/ui/uilinedecoration.cpp src/framework/ui/uicheckbox.cpp +SET(SOURCES # game sources src/main.cpp src/menustate.cpp @@ -79,11 +79,11 @@ SET(SOURCES src/framework/ui/uilinedecorationskin.cpp src/framework/ui/uicheckbo src/framework/graphics/framebuffer.cpp src/framework/graphics/font.cpp src/framework/graphics/fonts.cpp - src/framework/graphics/fonttext.cpp src/framework/graphics/textureloader.cpp src/framework/graphics/texture.cpp src/framework/graphics/textures.cpp src/framework/graphics/graphics.cpp + src/framework/graphics/textarea.cpp # framework ui src/framework/ui/uilayout.cpp @@ -101,6 +101,10 @@ SET(SOURCES src/framework/ui/uilinedecorationskin.cpp src/framework/ui/uicheckbo src/framework/ui/uiwindowskin.cpp src/framework/ui/uitextedit.cpp src/framework/ui/uitexteditskin.cpp + src/framework/ui/uilinedecorationskin.cpp + src/framework/ui/uicheckboxskin.cpp + src/framework/ui/uilinedecoration.cpp + src/framework/ui/uicheckbox.cpp # framework net src/framework/net/connection.cpp diff --git a/data/skins/tibiaskin.yml b/data/skins/tibiaskin.yml index 66339f84..9d1da26f 100644 --- a/data/skins/tibiaskin.yml +++ b/data/skins/tibiaskin.yml @@ -84,7 +84,7 @@ text edits: default: default size: [86, 16] font: tibia-10px-antialised - text margin: 2 + text margin: 3 bordered image: left border: [308,97,1,1] right border: [319,97,1,10] diff --git a/src/framework/core/dispatcher.cpp b/src/framework/core/dispatcher.cpp index b2364670..26e767a0 100644 --- a/src/framework/core/dispatcher.cpp +++ b/src/framework/core/dispatcher.cpp @@ -24,14 +24,15 @@ #include "dispatcher.h" #include "platform.h" +#include "engine.h" Dispatcher g_dispatcher; -void Dispatcher::poll(int ticks) +void Dispatcher::poll() { while(!m_taskList.empty()) { Task *task = m_taskList.top(); - if(ticks < task->ticks) + if(g_engine.getLastFrameTicks() < task->ticks) break; task->callback(); diff --git a/src/framework/core/dispatcher.h b/src/framework/core/dispatcher.h index 7be2ff9f..9070e924 100644 --- a/src/framework/core/dispatcher.h +++ b/src/framework/core/dispatcher.h @@ -49,7 +49,7 @@ public: Dispatcher() { } /// Execute scheduled events - void poll(int ticks); + void poll(); /// Add an event void addTask(const Callback& callback); diff --git a/src/framework/core/engine.cpp b/src/framework/core/engine.cpp index b320b7d3..f528b61c 100644 --- a/src/framework/core/engine.cpp +++ b/src/framework/core/engine.cpp @@ -53,8 +53,8 @@ void Engine::terminate() void Engine::run() { Font *defaultFont = g_fonts.getDefaultFont(); - int ticks = Platform::getTicks(); - int lastFpsTicks = ticks; + m_lastFrameTicks = Platform::getTicks(); + int lastFpsTicks = m_lastFrameTicks; int frameCount = 0; int fps = 0; m_running = true; @@ -66,18 +66,18 @@ void Engine::run() // poll network events g_connections.poll(); - ticks = Platform::getTicks(); + m_lastFrameTicks = Platform::getTicks(); // poll diaptcher tasks - g_dispatcher.poll(ticks); + g_dispatcher.poll(); // render only when visible if(Platform::isWindowVisible()) { // calculate and fps if(m_calculateFps) { frameCount++; - if(ticks - lastFpsTicks >= 1000) { - lastFpsTicks = ticks; + if(m_lastFrameTicks - lastFpsTicks >= 1000) { + lastFpsTicks = m_lastFrameTicks; fps = frameCount; frameCount = 0; } diff --git a/src/framework/core/engine.h b/src/framework/core/engine.h index f0762569..804aa4b0 100644 --- a/src/framework/core/engine.h +++ b/src/framework/core/engine.h @@ -61,6 +61,8 @@ public: /// Enable FPS counter on screen void enableFpsCounter(bool enable = true) { m_calculateFps = enable; }; + int getLastFrameTicks() const { return m_lastFrameTicks; } + private: /// Called to render every frame void render(); @@ -70,6 +72,7 @@ private: bool m_calculateFps; GameState *m_currentState; + int m_lastFrameTicks; }; extern Engine g_engine; diff --git a/src/framework/graphics/font.cpp b/src/framework/graphics/font.cpp index 8cb6dec2..617b9051 100644 --- a/src/framework/graphics/font.cpp +++ b/src/framework/graphics/font.cpp @@ -26,6 +26,7 @@ #include "core/resources.h" #include "textures.h" #include "graphics.h" +#include "textarea.h" void Font::calculateGlyphsWidthsAutomatically(const Size& glyphSize) { @@ -138,116 +139,32 @@ void Font::renderText(const std::string& text, Font::renderText(text, screenCoords, ALIGN_TOP_LEFT, color); } + void Font::renderText(const std::string& text, const Rect& screenCoords, int align, - const Color& color, - const Point& startInternalPos, - int cursorPos, - const Color& cursorColor) + const Color& color) { - // prevent glitches from invalid rects - if(!screenCoords.isValid()) - return; - - int textLenght = text.length(); - - // map glyphs positions - Size textBoxSize; - Point *glyphsPositions = calculateGlyphsPositions(text, align, &textBoxSize); - - for(int i = 0; i < textLenght; ++i) { - int glyph = (uchar)text[i]; - - // skip invalid glyphs - if(glyph < 32) - continue; - - // calculate initial glyph rect and texture coords - Rect glyphScreenCoords(glyphsPositions[i], m_glyphsSize[glyph]); - Rect glyphTextureCoords = m_glyphsTextureCoords[glyph]; - - // first translate to align position - if(align & ALIGN_BOTTOM) { - glyphScreenCoords.translate(0, screenCoords.height() - textBoxSize.height()); - } else if(align & ALIGN_VERTICAL_CENTER) { - glyphScreenCoords.translate(0, (screenCoords.height() - textBoxSize.height()) / 2); - } else { // ALIGN_TOP - // nothing to do - } - - if(align & ALIGN_RIGHT) { - glyphScreenCoords.translate(screenCoords.width() - textBoxSize.width(), 0); - } else if(align & ALIGN_HORIZONTAL_CENTER) { - glyphScreenCoords.translate((screenCoords.width() - textBoxSize.width()) / 2, 0); - } else { // ALIGN_TOP - // nothing to do - } - - // only render glyphs that are after startRenderPosition - if(glyphScreenCoords.bottom() < startInternalPos.y || glyphScreenCoords.right() < startInternalPos.x) - continue; - - // bound glyph topLeft to startRenderPosition - if(glyphScreenCoords.top() < startInternalPos.y) { - glyphTextureCoords.setTop(glyphTextureCoords.top() + (startInternalPos.y - glyphScreenCoords.top())); - glyphScreenCoords.setTop(startInternalPos.y); - } - if(glyphScreenCoords.left() < startInternalPos.x) { - glyphTextureCoords.setLeft(glyphTextureCoords.left() + (startInternalPos.x - glyphScreenCoords.left())); - glyphScreenCoords.setLeft(startInternalPos.x); - } - - // subtract startInternalPos - glyphScreenCoords.translate(-startInternalPos); - - // translate rect to screen coords - glyphScreenCoords.translate(screenCoords.topLeft()); - - // only render if glyph rect is visible on screenCoords - if(!screenCoords.intersects(glyphScreenCoords)) - continue; - - // bound glyph bottomRight to screenCoords bottomRight - if(glyphScreenCoords.bottom() > screenCoords.bottom()) { - glyphTextureCoords.setBottom(glyphTextureCoords.bottom() + (screenCoords.bottom() - glyphScreenCoords.bottom())); - glyphScreenCoords.setBottom(screenCoords.bottom()); - } - if(glyphScreenCoords.right() > screenCoords.right()) { - glyphTextureCoords.setRight(glyphTextureCoords.right() + (screenCoords.right() - glyphScreenCoords.right())); - glyphScreenCoords.setRight(screenCoords.right()); - } - - // render glyph - g_graphics.drawTexturedRect(glyphScreenCoords, m_texture, glyphTextureCoords, color); - - // render cursor - if(i == cursorPos) { - Rect cursorRect(glyphScreenCoords.left()-1, glyphScreenCoords.top(), 1, m_glyphHeight); - g_graphics.drawFilledRect(cursorRect, cursorColor); - } - // render cursor after last element - else if(cursorPos == textLenght && i == textLenght - 1) { - Rect cursorRect(glyphScreenCoords.right()+1, glyphScreenCoords.top(), 1, m_glyphHeight); - g_graphics.drawFilledRect(cursorRect, cursorColor); - } - } + TextArea textArea(this, text, screenCoords, align, color); + textArea.draw(); } -Point* Font::calculateGlyphsPositions(const std::string& text, int align, Size *textBoxSize) +std::vector Font::calculateGlyphsPositions(const std::string& text, int align, Size *textBoxSize) { - static Point glyphsPositions[8192]; - static int lineWidths[512]; + int numGlyphs = text.length(); + std::vector glyphsPositions(numGlyphs); + if(numGlyphs == 0) { + if(textBoxSize) + textBoxSize->setSize(0,0); + return glyphsPositions; + } + + std::vector lineWidths(numGlyphs); int maxLineWidth = 0; int lines = 0; int glyph; int i; - // protect buffer overflow on glyphsPostions - int numGlyphs = text.length(); - if(numGlyphs > 8192) - logFatal("could not calculate glyphs positions, text length is > 8192!"); - // calculate lines width if((align & ALIGN_RIGHT || align & ALIGN_HORIZONTAL_CENTER) || textBoxSize) { lineWidths[0] = 0; @@ -299,13 +216,13 @@ Point* Font::calculateGlyphsPositions(const std::string& text, int align, Size * textBoxSize->setHeight(virtualPos.y + m_glyphHeight); } - return (Point *)glyphsPositions; + return glyphsPositions; } - Size Font::calculateTextRectSize(const std::string& text) { Size size; calculateGlyphsPositions(text, ALIGN_TOP_LEFT, &size); return size; } + diff --git a/src/framework/graphics/font.h b/src/framework/graphics/font.h index 4e691d46..c518b8d3 100644 --- a/src/framework/graphics/font.h +++ b/src/framework/graphics/font.h @@ -42,6 +42,8 @@ enum EAlign { ALIGN_BOTTOM_LEFT = ALIGN_BOTTOM | ALIGN_LEFT }; +class TextArea; + class Font { public: @@ -65,21 +67,21 @@ public: void renderText(const std::string& text, const Rect& screenCoords, int align = ALIGN_TOP_LEFT, - const Color& color = Color::white, - const Point& startInternalPos = Point(), - int cursorPos = -1, - const Color& cursorColor = Color::white); - + const Color& color = Color::white); /// Calculate glyphs positions to use on render, also calculates textBoxSize if wanted - Point *calculateGlyphsPositions(const std::string& text, int align = ALIGN_TOP_LEFT, Size *textBoxSize = NULL); + std::vector calculateGlyphsPositions(const std::string& text, int align = ALIGN_TOP_LEFT, Size *textBoxSize = NULL); /// Simulate render and calculate text size Size calculateTextRectSize(const std::string& text); const std::string& getName() const { return m_name; } int getGlyphHeight() const { return m_glyphHeight; } - + const Rect *getGlyphsTextureCoords() const { return m_glyphsTextureCoords; } + const Size *getGlyphsSize() const { return m_glyphsSize; } + const TexturePtr& getTexture() const { return m_texture; } + int getTopMargin() const { return m_topMargin; } + private: void calculateGlyphsWidthsAutomatically(const Size& glyphSize); diff --git a/src/framework/graphics/fonttext.cpp b/src/framework/graphics/fonttext.cpp deleted file mode 100644 index dae0aa61..00000000 --- a/src/framework/graphics/fonttext.cpp +++ /dev/null @@ -1,26 +0,0 @@ -/* The MIT License - * - * Copyright (c) 2010 OTClient, https://github.com/edubart/otclient - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - - -#include "fonttext.h" - diff --git a/src/framework/graphics/textarea.cpp b/src/framework/graphics/textarea.cpp new file mode 100644 index 00000000..61cc6825 --- /dev/null +++ b/src/framework/graphics/textarea.cpp @@ -0,0 +1,256 @@ +/* The MIT License + * + * Copyright (c) 2010 OTClient, https://github.com/edubart/otclient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +#include "textarea.h" +#include "graphics.h" +#include "core/engine.h" + +TextArea::TextArea() : + m_font(0), + m_align(ALIGN_TOP_LEFT), + m_color(Color::white), + m_cursorPos(-1), + m_cursorVisible(false) +{ +} + +TextArea::TextArea(Font* font, + const std::string& text, + const Rect& screenCoords, + int align, + const Color& color) : + m_font(font), + m_text(text), + m_screenCoords(screenCoords), + m_align(align), + m_color(color), + m_cursorPos(-1), + m_cursorVisible(false) +{ + recalculate(); +} + +void TextArea::draw() +{ + int numGlyphs = m_text.length(); + const TexturePtr& texture = m_font->getTexture(); + for(int i=0;i= 0 && m_cursorPos <= numGlyphs) { + const int delay = 500; + int ticks = g_engine.getLastFrameTicks(); + // draw every 500ms + if(ticks - m_cursorTicks <= delay) { + Rect cursorRect; + if(m_cursorPos == 0) + cursorRect = Rect(m_drawArea.left()-1, m_drawArea.top(), 1, m_font->getGlyphHeight()); + else if(m_cursorPos == numGlyphs) + cursorRect = Rect(m_glyphsCoords[m_cursorPos-1].right(), m_glyphsCoords[m_cursorPos-1].top(), 1, m_font->getGlyphHeight()); + else + cursorRect = Rect(m_glyphsCoords[m_cursorPos-1].right(), m_glyphsCoords[m_cursorPos-1].top(), 1, m_font->getGlyphHeight()); + g_graphics.drawFilledRect(cursorRect, m_color); + } else if(ticks - m_cursorTicks >= 2*delay) { + m_cursorTicks = g_engine.getLastFrameTicks(); + } + } +} + +void TextArea::recalculate() +{ + // prevent glitches from invalid rects + if(!m_screenCoords.isValid()) + return; + + int textLenght = m_text.length(); + + m_glyphsCoords.clear(); + m_glyphsTexCoords.clear(); + + m_glyphsCoords.resize(textLenght); + m_glyphsTexCoords.resize(textLenght); + + // map glyphs positions + Size textBoxSize; + std::vector glyphsPositions = m_font->calculateGlyphsPositions(m_text, m_align, &textBoxSize); + const Rect *glyphsTextureCoords = m_font->getGlyphsTextureCoords(); + const Size *glyphsSize = m_font->getGlyphsSize(); + + m_drawArea.setLeft(m_screenCoords.left()); + m_drawArea.setTop(m_screenCoords.top()+m_font->getTopMargin()); + m_drawArea.setRight(m_screenCoords.right()); + m_drawArea.setBottom(m_screenCoords.bottom()); + + for(int i = 0; i < textLenght; ++i) { + int glyph = (uchar)m_text[i]; + + // skip invalid glyphs + if(glyph < 32) + continue; + + // calculate initial glyph rect and texture coords + Rect glyphScreenCoords(glyphsPositions[i], glyphsSize[glyph]); + Rect glyphTextureCoords = glyphsTextureCoords[glyph]; + + // first translate to align position + if(m_align & ALIGN_BOTTOM) { + glyphScreenCoords.translate(0, m_screenCoords.height() - textBoxSize.height()); + } else if(m_align & ALIGN_VERTICAL_CENTER) { + glyphScreenCoords.translate(0, (m_screenCoords.height() - textBoxSize.height()) / 2); + } else { // ALIGN_TOP + // nothing to do + } + + if(m_align & ALIGN_RIGHT) { + glyphScreenCoords.translate(m_screenCoords.width() - textBoxSize.width(), 0); + } else if(m_align & ALIGN_HORIZONTAL_CENTER) { + glyphScreenCoords.translate((m_screenCoords.width() - textBoxSize.width()) / 2, 0); + } else { // ALIGN_TOP + // nothing to do + } + + // only render glyphs that are after startRenderPosition + if(glyphScreenCoords.bottom() < m_startInternalPos.y || glyphScreenCoords.right() < m_startInternalPos.x) + continue; + + // bound glyph topLeft to startRenderPosition + if(glyphScreenCoords.top() < m_startInternalPos.y) { + glyphTextureCoords.setTop(glyphTextureCoords.top() + (m_startInternalPos.y - glyphScreenCoords.top())); + glyphScreenCoords.setTop(m_startInternalPos.y); + } + if(glyphScreenCoords.left() < m_startInternalPos.x) { + glyphTextureCoords.setLeft(glyphTextureCoords.left() + (m_startInternalPos.x - glyphScreenCoords.left())); + glyphScreenCoords.setLeft(m_startInternalPos.x); + } + + // subtract startInternalPos + glyphScreenCoords.translate(-m_startInternalPos); + + // translate rect to screen coords + glyphScreenCoords.translate(m_screenCoords.topLeft()); + + // only render if glyph rect is visible on screenCoords + if(!m_screenCoords.intersects(glyphScreenCoords)) + continue; + + // bound glyph bottomRight to screenCoords bottomRight + if(glyphScreenCoords.bottom() > m_screenCoords.bottom()) { + glyphTextureCoords.setBottom(glyphTextureCoords.bottom() + (m_screenCoords.bottom() - glyphScreenCoords.bottom())); + glyphScreenCoords.setBottom(m_screenCoords.bottom()); + } + if(glyphScreenCoords.right() > m_screenCoords.right()) { + glyphTextureCoords.setRight(glyphTextureCoords.right() + (m_screenCoords.right() - glyphScreenCoords.right())); + glyphScreenCoords.setRight(m_screenCoords.right()); + } + + // render glyph + m_glyphsCoords[i] = glyphScreenCoords; + m_glyphsTexCoords[i] = glyphTextureCoords; + } +} + +void TextArea::setFont(Font* font) +{ + m_font = font; + recalculate(); +} + +void TextArea::setText(const std::string& text) +{ + m_text = text; + if(m_cursorPos >= 0) { + m_cursorPos = 0; + m_cursorTicks = g_engine.getLastFrameTicks(); + } + recalculate(); +} + +void TextArea::setScreenCoords(Rect screenCoords) +{ + m_screenCoords = screenCoords; + recalculate(); +} + +void TextArea::setAlign(int align) +{ + m_align = align; + recalculate(); +} + +void TextArea::setStartInternalPos(Point startPos) +{ + m_startInternalPos = startPos; + recalculate(); +} + +void TextArea::enableCursor(bool enable) +{ + if(enable) { + m_cursorPos = 0; + m_cursorTicks = g_engine.getLastFrameTicks(); + } else + m_cursorPos = -1; +} + +void TextArea::appendCharacter(char c) +{ + if(m_cursorPos >= 0) { + std::string tmp; + tmp = c; + m_text.insert(m_cursorPos, tmp); + m_cursorPos++; + m_cursorTicks = g_engine.getLastFrameTicks(); + recalculate(); + } +} + +void TextArea::removeCharacter(bool right) +{ + if(m_cursorPos >= 0) { + if(right && (uint)m_cursorPos < m_text.length()) + m_text.erase(m_text.begin() + m_cursorPos); + else if((uint)m_cursorPos <= m_text.length() && m_cursorPos > 0) { + m_text.erase(m_text.begin() + (--m_cursorPos)); + m_cursorTicks = g_engine.getLastFrameTicks(); + } + recalculate(); + } +} + +void TextArea::moveCursor(bool right) +{ + if(right) { + if((uint)m_cursorPos+1 <= m_text.length()) { + m_cursorPos++; + m_cursorTicks = g_engine.getLastFrameTicks(); + } + } else { + if(m_cursorPos-1 >= 0) { + m_cursorPos--; + m_cursorTicks = g_engine.getLastFrameTicks(); + } + } +} diff --git a/src/framework/graphics/fonttext.h b/src/framework/graphics/textarea.h similarity index 55% rename from src/framework/graphics/fonttext.h rename to src/framework/graphics/textarea.h index edb7f41d..1536a625 100644 --- a/src/framework/graphics/fonttext.h +++ b/src/framework/graphics/textarea.h @@ -22,32 +22,55 @@ */ -#ifndef FONTTEXT_H -#define FONTTEXT_H +#ifndef TEXTAREA_H +#define TEXTAREA_H #include "prerequisites.h" #include "font.h" -class FontText +class TextArea { public: - FontText() { } + TextArea(); + TextArea(Font *font, + const std::string& text, + const Rect& screenCoords, + int align = ALIGN_TOP_LEFT, + const Color& color = Color::white); + void draw(); + + void setFont(Font *font); + void setText(const std::string& text); + void setScreenCoords(Rect screenCoords); + void setAlign(int align); + void setColor(const Color& color) { m_color = color; } + void setStartInternalPos(Point startPos); + void enableCursor(bool enable = true); + void setCursorVisible(bool visible = true) { m_cursorVisible = visible; } + + void moveCursor(bool right); void appendCharacter(char c); - void appendText(const std::string &text); - void erase(bool left); + void removeCharacter(bool right); - void setText(const std::string &text); - void setCursorPos(int pos); - void setSelection(int start, int end); - void setColor(const Color& color); - void setSize(const Size& size); - void setStartPos(); + const std::string& getText() const { return m_text; } private: - int m_cursorPos; - std::string m_text; + void recalculate(); + Font *m_font; + std::string m_text; + Rect m_screenCoords; + Rect m_drawArea; + int m_align; + Color m_color; + Point m_startInternalPos; + int m_cursorPos; + int m_cursorTicks; + bool m_cursorVisible; + + std::vector m_glyphsCoords; + std::vector m_glyphsTexCoords; }; -#endif // FONTTEXT_H +#endif // TEXTAREA_H diff --git a/src/framework/ui/uicontainer.cpp b/src/framework/ui/uicontainer.cpp index 4b4e93c4..9b30765e 100644 --- a/src/framework/ui/uicontainer.cpp +++ b/src/framework/ui/uicontainer.cpp @@ -111,7 +111,7 @@ void UIContainer::onInputEvent(const InputEvent& event) } // mouse events } else if(event.type & EV_MOUSE) { - // mouse down and weel events only go to elements that contains the mouse position + // mouse down and wheel events only go to elements that contains the mouse position if(event.type & EV_DOWN || event.type & EV_MOUSE_WHEEL) { if(child->getRect().contains(event.mousePos)) { // focus it @@ -134,7 +134,11 @@ void UIContainer::onInputEvent(const InputEvent& event) void UIContainer::setFocusedElement(UIElementPtr focusedElement) { - if(m_focusedElement) + if(m_focusedElement) { m_focusedElement->setFocused(false); + m_focusedElement->onFocusChange(); + } m_focusedElement = focusedElement; + m_focusedElement->setFocused(true); + m_focusedElement->onFocusChange(); } diff --git a/src/framework/ui/uielement.h b/src/framework/ui/uielement.h index 9f415868..6d40d237 100644 --- a/src/framework/ui/uielement.h +++ b/src/framework/ui/uielement.h @@ -48,6 +48,7 @@ public: virtual void render(); virtual void onInputEvent(const InputEvent& event) { } + virtual void onFocusChange() { } UIElementPtr backwardsGetElementById(const std::string& id); diff --git a/src/framework/ui/uitextedit.cpp b/src/framework/ui/uitextedit.cpp index f35c01ea..fb80a563 100644 --- a/src/framework/ui/uitextedit.cpp +++ b/src/framework/ui/uitextedit.cpp @@ -23,74 +23,45 @@ #include "uitextedit.h" +#include "uitexteditskin.h" #include "graphics/fonts.h" UITextEdit::UITextEdit() : - UIElement(UI::TextEdit), - m_cursorPos(0), - m_startRenderPos(0) + UIElement(UI::TextEdit) { - + UITextEditSkin *skin = static_cast(getSkin()); + m_textArea.setFont(skin->getFont()); + m_textArea.enableCursor(); } void UITextEdit::onInputEvent(const InputEvent& event) { if(event.type == EV_TEXT_ENTER) { - appendCharacter(event.keychar); + m_textArea.appendCharacter(event.keychar); } else if(event.type == EV_KEY_DOWN) { if(event.keycode == KC_DELETE) - removeCharacter(true); + m_textArea.removeCharacter(true); else if(event.keycode == KC_BACK) - removeCharacter(false); - else if(event.keycode == KC_RIGHT) { - if(m_cursorPos < m_text.length()) - m_cursorPos++; - } else if(event.keycode == KC_LEFT) { - if(m_cursorPos > 0) - m_cursorPos--; - } + m_textArea.removeCharacter(false); + else if(event.keycode == KC_RIGHT) + m_textArea.moveCursor(true); + else if(event.keycode == KC_LEFT) + m_textArea.moveCursor(false); } } -void UITextEdit::clearText() -{ - m_text = ""; - m_cursorPos = 0; -} - -void UITextEdit::setText(const std::string& text) -{ - m_text = text; - m_cursorPos = 0; -} - -void UITextEdit::appendCharacter(char c) -{ - std::string tmp; - tmp = c; - m_text.insert(m_cursorPos, tmp); - m_cursorPos++; -} - -void UITextEdit::removeCharacter(bool right) -{ - if(right && m_cursorPos < m_text.length()) - m_text.erase(m_text.begin() + m_cursorPos); - else if(m_text.length() >= m_cursorPos && m_cursorPos > 0) - m_text.erase(m_text.begin() + (--m_cursorPos)); -} - -void UITextEdit::setCursorPos(uint pos) +void UITextEdit::onLayoutRectChange(const Rect& rect) { - if(pos > m_text.length()) - m_cursorPos = m_text.length(); - else - m_cursorPos = pos; + UITextEditSkin *skin = static_cast(getSkin()); + Rect textRect = rect; + int margin = skin->getTextMargin(); + textRect.setLeft(textRect.left()+margin); + textRect.setRight(textRect.right()-margin); + m_textArea.setScreenCoords(textRect); } -void UITextEdit::onLayoutRectChange(const Rect& rect) +void UITextEdit::onFocusChange() { - m_textRect = rect; + m_textArea.setCursorVisible(isFocused()); } - diff --git a/src/framework/ui/uitextedit.h b/src/framework/ui/uitextedit.h index 45c504f1..c194d70a 100644 --- a/src/framework/ui/uitextedit.h +++ b/src/framework/ui/uitextedit.h @@ -27,6 +27,7 @@ #include "prerequisites.h" #include "uielement.h" +#include "graphics/textarea.h" class Font; @@ -37,24 +38,16 @@ public: void onInputEvent(const InputEvent& event); - void clearText(); void setText(const std::string& text); - const std::string& getText() const { return m_text; } + const std::string& getText() const { return m_textArea.getText(); } - void setCursorPos(uint pos); - uint getCursorPos() { return m_cursorPos; } + TextArea& getTextArea() { return m_textArea; } void onLayoutRectChange(const Rect& rect); + void onFocusChange(); private: - void appendCharacter(char c); - void removeCharacter(bool right); - void recalculate(); - - Rect m_textRect; - uint m_cursorPos; - int m_startRenderPos; - std::string m_text; + TextArea m_textArea; }; typedef boost::shared_ptr UITextEditPtr; diff --git a/src/framework/ui/uitexteditskin.cpp b/src/framework/ui/uitexteditskin.cpp index f5180f23..342bf2b2 100644 --- a/src/framework/ui/uitexteditskin.cpp +++ b/src/framework/ui/uitexteditskin.cpp @@ -51,5 +51,5 @@ void UITextEditSkin::draw(UIElement* element) UIElementSkin::draw(element); UITextEdit *textEdit = static_cast(element); - m_font->renderText(textEdit->getText(), textEdit->getRect(), ALIGN_TOP_LEFT, m_textColor); + textEdit->getTextArea().draw(); }