more flexible skins

This commit is contained in:
Eduardo Bart 2011-04-11 17:06:03 -03:00
parent da2993d1f9
commit c3f0ca2b4f
24 changed files with 224 additions and 102 deletions

View File

@ -90,6 +90,7 @@ SET(SOURCES
src/framework/ui/uielement.cpp
src/framework/ui/uielementskin.cpp
src/framework/ui/uibuttonskin.cpp
src/framework/ui/uilabelskin.cpp
src/framework/ui/uicontainer.cpp
src/framework/ui/uiskins.cpp
src/framework/ui/uiloader.cpp

View File

@ -2,6 +2,8 @@ default skin image: tibiaskin.png
buttons:
default:
font: tibia-8px-antialised
text color: [238, 238, 238, 255]
default size: [86, 20]
bordered image:
@ -16,7 +18,7 @@ buttons:
center: [46,139,84,18]
down state:
translate: [1, 1]
text translate: [1, 1]
bordered image:
left border: [45,159,1,18]
right border: [130,159,1,18]
@ -46,11 +48,13 @@ panels:
labels:
default:
# the default label is empty
font: tibia-10px-antialised
text color: [238, 238, 238, 255]
windows:
default:
head:
text color: [143, 143, 143, 255]
height: 17
font: tibia-10px-antialised
bordered image:

View File

@ -133,7 +133,7 @@ void Engine::onClose()
void Engine::onResize(const Size& size)
{
g_graphics.resize(size);
UIContainer::getRootContainer()->setSize(size);
UIContainer::getRootContainer()->setSize(Size(size.width()-1, size.height()-1));
if(m_currentState)
m_currentState->onResize(size);

View File

@ -132,11 +132,12 @@ bool Font::load(const std::string& file)
}
void Font::renderText(const std::string& text,
const Point& startPos)
const Point& startPos,
const Color& color)
{
Size boxSize = g_graphics.getScreenSize() - startPos.toSize();
Rect screenCoords(startPos, boxSize);
Font::renderText(text, screenCoords);
Font::renderText(text, screenCoords, ALIGN_TOP_LEFT, color);
}
void Font::renderText(const std::string& text,
@ -158,7 +159,7 @@ void Font::renderText(const std::string& text,
Point *glyphsPositions = calculateGlyphsPositions(text, align, &textBoxSize);
for(int i = 0; i < textLenght; ++i) {
int glyph = (int)text[i];
int glyph = (uchar)text[i];
// skip invalid glyphs
if(glyph < 32)
@ -253,7 +254,7 @@ Point* Font::calculateGlyphsPositions(const std::string& text, int align, Size *
if((align & ALIGN_RIGHT || align & ALIGN_HORIZONTAL_CENTER) || textBoxSize) {
lineWidths[0] = 0;
for(i = 0; i< numGlyphs; ++i) {
glyph = (int)text[i];
glyph = (uchar)text[i];
if(glyph == (uchar)'\n') {
lineWidths[++lines] = 0;
@ -267,7 +268,7 @@ Point* Font::calculateGlyphsPositions(const std::string& text, int align, Size *
Point virtualPos(0, m_topMargin);
lines = 0;
for(i = 0; i < numGlyphs; ++i) {
glyph = (int)text[i];
glyph = (uchar)text[i];
// store current glyph topLeft
glyphsPositions[i] = virtualPos;

View File

@ -55,7 +55,8 @@ public:
/// Simple text render starting at pos
void renderText(const std::string& text,
const Point& startPos);
const Point& startPos,
const Color& color = Color::white);
/** Advanced text render
* screenCoords is the rect that will be filled on the screen

View File

@ -34,11 +34,9 @@ typedef std::function<void()> Callback;
class UIButton : public UIElement
{
public:
UIButton(const std::string& text = std::string()) : UIElement(UI::Button),
m_text(text),
m_state(UI::ButtonUp) {
UIElement();
}
UIButton() :
UIElement(UI::Button),
m_state(UI::ButtonUp) { }
void onInputEvent(const InputEvent& event);

View File

@ -26,6 +26,27 @@
#include "uibutton.h"
#include "graphics/fonts.h"
void UIButtonSkin::load(const YAML::Node& node)
{
UIElementSkin::load(node);
std::string tmp;
m_buttonDownImage = loadImage(node["down state"]);
if(node["down state"].FindValue("text translate"))
node["down state"]["text translate"] >> m_buttonDownTranslate;
if(node.FindValue("mouse over state"))
m_buttonHoverImage = loadImage(node["mouse over state"]);
node["font"] >> tmp;
m_font = g_fonts.get(tmp);
node["text color"] >> m_textColor;
m_textColor = Color::white;
}
void UIButtonSkin::draw(UIElement *element)
{
UIButton *button = static_cast<UIButton*>(element);
@ -41,21 +62,5 @@ void UIButtonSkin::draw(UIElement *element)
UIElementSkin::draw(element);
}
g_fonts.get("tibia-8px-antialised")->renderText(button->getText(), textRect, ALIGN_CENTER, Color(0xFFEEEEEE));
}
void UIButtonSkin::load(const YAML::Node& node)
{
UIElementSkin::load(node);
if(node.FindValue("down state")) {
m_buttonDownImage = loadImage(node["down state"]);
if(node["down state"].FindValue("translate"))
node["down state"]["translate"] >> m_buttonDownTranslate;
}
if(node.FindValue("mouse over state"))
m_buttonHoverImage = loadImage(node["mouse over state"]);
m_font->renderText(button->getText(), textRect, ALIGN_CENTER, m_textColor);
}

View File

@ -29,6 +29,8 @@
#include "uiconstants.h"
#include "uielementskin.h"
class Font;
class UIButtonSkin : public UIElementSkin
{
public:
@ -42,6 +44,8 @@ private:
ImagePtr m_buttonDownImage;
ImagePtr m_buttonHoverImage;
Point m_buttonDownTranslate;
Font *m_font;
Color m_textColor;
};
#endif // UIBUTTONSKIN_H

View File

@ -34,15 +34,15 @@ public:
UIContainer(UI::EElementType type = UI::Container) : UIElement(type) { }
virtual ~UIContainer() { }
virtual void render();
virtual void onInputEvent(const InputEvent& event);
void addChild(UIElementPtr child);
void removeChild(UIElementPtr child);
UIElementPtr getChildById(const std::string& id);
UIElementPtr recursiveGetChildById(const std::string& id);
virtual void render();
virtual void onInputEvent(const InputEvent& event);
void setFocusedElement(UIElementPtr focusedElement);
UIElementPtr getFocusedElement() const { return m_focusedElement; }
@ -52,7 +52,7 @@ public:
static UIContainerPtr& getRootContainer();
protected:
private:
std::list<UIElementPtr> m_children;
UIElementPtr m_focusedElement;
};

View File

@ -25,6 +25,7 @@
#include "uielement.h"
#include "uiskins.h"
#include "uielementskin.h"
#include <graphics/graphics.h>
UIElement::UIElement(UI::EElementType type) :
UILayout(),
@ -57,6 +58,7 @@ void UIElement::render()
{
if(m_skin)
m_skin->draw(this);
//g_graphics.drawBoundingRect(getRect());
}
UIElementPtr UIElement::backwardsGetElementById(const std::string& id)

View File

@ -55,7 +55,7 @@ public:
void setSkin(UIElementSkin *skin);
UIElementSkin *getSkin() { return m_skin; }
virtual void setParent(UIContainerPtr parent) { m_parent = parent; }
void setParent(UIContainerPtr parent) { m_parent = parent; }
UIContainerPtr getParent() const { return m_parent.lock(); }
void setId(const std::string& id) { m_id = id; }
@ -75,6 +75,8 @@ public:
UIElementPtr asUIElement() { return std::static_pointer_cast<UIElement>(shared_from_this()); }
virtual UIContainerPtr asUIContainer() { return UIContainerPtr(); }
friend class UIContainer;
private:
UI::EElementType m_type;
UIContainerWeakPtr m_parent;

View File

@ -24,25 +24,12 @@
#include "uilabel.h"
#include "graphics/fonts.h"
UILabel::UILabel(const std::string& text, Font* font) :
UIElement(UI::Label),
m_text(text),
m_font(font)
{
if(!font)
m_font = g_fonts.get("tibia-10px-antialised");
setSize(m_font->calculateTextRectSize(text));
}
void UILabel::render()
{
m_font->renderText(m_text, getRect(), ALIGN_LEFT, Color(0xFFBFBFBF));
}
#include "uilabelskin.h"
void UILabel::setText(const std::string& text)
{
setSize(m_font->calculateTextRectSize(text));
UILabelSkin *skin = static_cast<UILabelSkin*>(getSkin());
setSize(skin->getFont()->calculateTextRectSize(text));
m_text = text;
}

View File

@ -33,16 +33,14 @@ class Font;
class UILabel : public UIElement
{
public:
UILabel(const std::string& text = std::string(), Font *font = NULL);
void render();
UILabel() :
UIElement(UI::Label) { }
void setText(const std::string& text);
const std::string& getText() const { return m_text; }
private:
std::string m_text;
Font *m_font;
};
typedef std::shared_ptr<UILabel> UILabelPtr;

View File

@ -0,0 +1,51 @@
/* 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 "uilabelskin.h"
#include "uilabel.h"
#include "graphics/fonts.h"
void UILabelSkin::load(const YAML::Node& node)
{
UIElementSkin::load(node);
std::string tmp;
if(node.FindValue("font")) {
node["font"] >> tmp;
m_font = g_fonts.get(tmp);
} else
m_font = g_fonts.getDefaultFont();
if(node.FindValue("text color"))
node["text color"] >> m_textColor;
else
m_textColor = Color::white;
}
void UILabelSkin::draw(UIElement *element)
{
UILabel *label = static_cast<UILabel*>(element);
m_font->renderText(label->getText(), label->getRect(), ALIGN_TOP_LEFT, m_textColor);
}

View File

@ -0,0 +1,50 @@
/* 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.
*/
#ifndef UILABELSKIN_H
#define UILABELSKIN_H
#include "prerequisites.h"
#include "uiconstants.h"
#include "uielementskin.h"
class Font;
class UILabelSkin : public UIElementSkin
{
public:
UILabelSkin(const std::string& name) :
UIElementSkin(name, UI::Label) { }
void load(const YAML::Node& node);
void draw(UIElement *element);
Font *getFont() const { return m_font; }
private:
Font *m_font;
Color m_textColor;
};
#endif // UILABELSKIN_H

View File

@ -58,7 +58,7 @@ void UILayout::setSize(const Size& size)
m_rect = Rect(0, 0, size);
// rect updated, recalculate itself and anchored elements positions
recalculateAnchors();
recalculateLayout();
}
void UILayout::setRect(const Rect& rect)
@ -66,7 +66,7 @@ void UILayout::setRect(const Rect& rect)
m_rect = rect;
// rect updated, recalculate itself and anchored elements positions
recalculateAnchors();
recalculateLayout();
}
bool UILayout::addAnchor(EAnchorType type, const AnchorLine& anchorLine)
@ -91,7 +91,7 @@ bool UILayout::addAnchor(EAnchorType type, const AnchorLine& anchorLine)
anchorLine.getRelativeElement()->addAnchoredElement(asUILayout());
// recalculate itself and anchored elements
recalculateAnchors();
recalculateLayout();
return true;
}
@ -111,7 +111,7 @@ void UILayout::addAnchoredElement(UILayoutPtr anchoredElement)
m_anchoredElements.push_back(anchoredElement);
}
void UILayout::recalculateAnchors()
void UILayout::recalculateLayout()
{
// recalculate horizontal position
if(m_anchors[ANCHOR_HORIZONTAL_CENTER].isValid()) {
@ -145,6 +145,10 @@ void UILayout::recalculateAnchors()
for(auto it = m_anchoredElements.begin(); it != m_anchoredElements.end(); ++it) {
UILayoutPtr element = (*it).lock();
if(element)
element->recalculateAnchors();
element->recalculateLayout();
}
// fire layotu update event
onLayoutRectChange(m_rect);
}

View File

@ -98,19 +98,22 @@ public:
AnchorLine verticalCenter() { return AnchorLine(asUILayout(), ANCHOR_VERTICAL_CENTER); }
// margins
void setMargin(int top, int left, int bottom, int right) { m_marginLeft = left; m_marginRight = right; m_marginTop = top; m_marginBottom = bottom; recalculateAnchors(); }
void setMargin(int horizontal, int vertical) { m_marginLeft = m_marginRight = horizontal; m_marginTop = m_marginBottom = vertical; recalculateAnchors(); }
void setMargin(int margin) { m_marginLeft = m_marginRight = m_marginTop = m_marginBottom = margin; recalculateAnchors(); }
void setMarginLeft(int margin) { m_marginLeft = margin; recalculateAnchors(); }
void setMarginRight(int margin) { m_marginRight = margin; recalculateAnchors(); }
void setMarginTop(int margin) { m_marginTop = margin; recalculateAnchors(); }
void setMarginBottom(int margin) { m_marginBottom = margin; recalculateAnchors(); }
void setMargin(int top, int left, int bottom, int right) { m_marginLeft = left; m_marginRight = right; m_marginTop = top; m_marginBottom = bottom; recalculateLayout(); }
void setMargin(int horizontal, int vertical) { m_marginLeft = m_marginRight = horizontal; m_marginTop = m_marginBottom = vertical; recalculateLayout(); }
void setMargin(int margin) { m_marginLeft = m_marginRight = m_marginTop = m_marginBottom = margin; recalculateLayout(); }
void setMarginLeft(int margin) { m_marginLeft = margin; recalculateLayout(); }
void setMarginRight(int margin) { m_marginRight = margin; recalculateLayout(); }
void setMarginTop(int margin) { m_marginTop = margin; recalculateLayout(); }
void setMarginBottom(int margin) { m_marginBottom = margin; recalculateLayout(); }
UILayoutPtr asUILayout() { return shared_from_this(); }
protected:
virtual void onLayoutRectChange(const Rect& newRect) { }
private:
/// Recalculate itself and anchored elements positions
void recalculateAnchors();
void recalculateLayout();
void addAnchoredElement(UILayoutPtr anchoredElement);
AnchorLine m_anchors[6];

View File

@ -29,6 +29,7 @@
#include "uibuttonskin.h"
#include "uiwindowskin.h"
#include "uitexteditskin.h"
#include "uilabelskin.h"
UISkins g_uiSkins;
@ -108,12 +109,13 @@ bool UISkins::load(const std::string& file)
std::string name;
it.first() >> name;
UIElementSkin *skin = new UIElementSkin(name, UI::Label);
UIElementSkin *skin = new UILabelSkin(name);
skin->load(it.second());
m_elementSkins.push_back(skin);
}
}
{
const YAML::Node& node = doc["text edits"];
for(auto it = node.begin(); it != node.end(); ++it) {
@ -125,10 +127,8 @@ bool UISkins::load(const std::string& file)
m_elementSkins.push_back(skin);
}
}
} catch (YAML::ParserException& e) {
logError("Malformed font file \"%s\"", file.c_str());
} catch (YAML::Exception& e) {
logError("Malformed skin file \"%s\":\n %s", file.c_str(), e.what());
return false;
}
return true;

View File

@ -102,3 +102,9 @@ void UITextEdit::setCursorPos(uint pos)
m_cursorPos = pos;
}
void UITextEdit::onLayoutRectChange(const Rect& rect)
{
m_textRect = rect;
}

View File

@ -46,11 +46,14 @@ public:
void setCursorPos(uint pos);
uint getCursorPos() { return m_cursorPos; }
void onLayoutRectChange(const Rect& rect);
private:
void appendCharacter(char c);
void removeCharacter(bool right);
void recalculate();
Rect m_textRect;
uint m_cursorPos;
int m_startRenderPos;
std::string m_text;

View File

@ -31,9 +31,8 @@
class UIWindow : public UIContainer
{
public:
UIWindow(const std::string& title = std::string()) :
UIContainer(UI::Window),
m_title(title) { }
UIWindow() :
UIContainer(UI::Window) { }
void setTitle(const std::string& title) { m_title = title; }
const std::string& getTitle() const { return m_title; }

View File

@ -25,6 +25,21 @@
#include "uiwindow.h"
#include "graphics/fonts.h"
void UIWindowSkin::load(const YAML::Node& node)
{
UIElementSkin::load(node);
node["head"]["height"] >> m_headHeight;
m_headImage = loadImage(node["head"]);
m_bodyImage = loadImage(node["body"]);
std::string fontName;
node["head"]["font"] >> fontName;
m_titleFont = g_fonts.get(fontName);
node["head"]["text color"] >> m_headTextColor;
}
void UIWindowSkin::draw(UIElement* element)
{
UIElementSkin::draw(element);
@ -41,20 +56,7 @@ void UIWindowSkin::draw(UIElement* element)
m_titleFont->renderText(window->getTitle(),
headRect,
ALIGN_CENTER,
Color(0xFF8F8F8F));
m_headTextColor);
m_bodyImage->draw(bodyRect);
}
void UIWindowSkin::load(const YAML::Node& node)
{
UIElementSkin::load(node);
node["head"]["height"] >> m_headHeight;
m_headImage = loadImage(node["head"]);
m_bodyImage = loadImage(node["body"]);
std::string fontName;
node["head"]["font"] >> fontName;
m_titleFont = g_fonts.get(fontName);
}

View File

@ -43,6 +43,7 @@ private:
ImagePtr m_bodyImage;
Font *m_titleFont;
int m_headHeight;
Color m_headTextColor;
};
#endif // UIWINDOWSKIN_H

View File

@ -33,22 +33,22 @@ class Color
{
public:
inline Color() : color(0) { }
inline Color(uint8 r, uint8 g, uint8 b, uint8 a = 0xFF) : color(((r & 0xff)<<24) | ((g & 0xff)<<16) | ((b & 0xff)<<8) | (a & 0xff)) { }
inline Color(uint8 r, uint8 g, uint8 b, uint8 a = 0xFF) : color(((a & 0xff)<<24) | ((b & 0xff)<<16) | ((g & 0xff)<<8) | (r & 0xff)) { }
inline Color(const Color& other) : color(other.color) { }
inline Color(RGBA rgba) : color(rgba) { }
inline uint8 r() const { return (color >> 24) & 0xFF; }
inline uint8 g() const { return (color >> 16) & 0xFF; }
inline uint8 b() const { return (color >> 8) & 0xFF; }
inline uint8 a() const { return color & 0xFF; }
inline uint8 a() const { return (color >> 24) & 0xFF; }
inline uint8 b() const { return (color >> 16) & 0xFF; }
inline uint8 g() const { return (color >> 8) & 0xFF; }
inline uint8 r() const { return color & 0xFF; }
inline RGBA rgba() const { return color; }
inline const uint8* rgbaPtr() const { return (const uint8*)&color; }
inline void setRed(uint8 r) { color = ((r & 0xff)<<24) | (color & 0x00ffffff); }
inline void setGreen(uint8 g) { color = ((g & 0xff)<<16) | (color & 0xff00ffff); }
inline void setBlue(uint8 b) { color = ((b & 0xff)<<8) | (color & 0xffff00ff); }
inline void setAlpha(uint8 a) { color = (a & 0xff) | (color & 0xffffff00); }
inline void setRGBA(uint8 r, uint8 g, uint8 b, uint8 a = 0xFF) { color = ((r & 0xff)<<24) | ((g & 0xff)<<16) | ((b & 0xff)<<8) | (a & 0xff); }
inline void setAlpha(uint8 a) { color = ((a & 0xff)<<24) | (color & 0x00ffffff); }
inline void setBlue(uint8 b) { color = ((b & 0xff)<<16) | (color & 0xff00ffff); }
inline void setGreen(uint8 g) { color = ((g & 0xff)<<8) | (color & 0xffff00ff); }
inline void setRed(uint8 r) { color = (r & 0xff) | (color & 0xffffff00); }
inline void setRGBA(uint8 r, uint8 g, uint8 b, uint8 a = 0xFF) { color = ((a & 0xff)<<24) | ((b & 0xff)<<16) | ((g & 0xff)<<8) | (r & 0xff); }
inline void setRGBA(uint32 rgba) { color = rgba; }
inline Color& operator=(const Color& other) { color = other.color; return *this; }