/* * Copyright (c) 2010-2012 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 "uiwidget.h" #include "uihorizontallayout.h" #include "uiverticallayout.h" #include "uigridlayout.h" #include "uianchorlayout.h" #include "uitranslator.h" #include #include #include void UIWidget::initBaseStyle() { m_backgroundColor = Color::alpha; m_borderColor.set(Color::black); m_iconColor = Color::white; m_color = Color::white; m_opacity = 1.0f; // generate an unique id, this is need because anchored layouts find widgets by id static unsigned long id = 1; m_id = stdext::format("widget %d", id++); } void UIWidget::parseBaseStyle(const OTMLNodePtr& styleNode) { // load styles used by all widgets for(const OTMLNodePtr& node : styleNode->children()) { if(node->tag() == "color") setColor(node->value()); else if(node->tag() == "x") setX(node->value()); else if(node->tag() == "y") setY(node->value()); else if(node->tag() == "pos") setPosition(node->value()); else if(node->tag() == "width") setWidth(node->value()); else if(node->tag() == "height") setHeight(node->value()); else if(node->tag() == "rect") setRect(node->value()); else if(node->tag() == "background") setBackgroundColor(node->value()); else if(node->tag() == "background-color") setBackgroundColor(node->value()); else if(node->tag() == "background-offset-x") setBackgroundOffsetX(node->value()); else if(node->tag() == "background-offset-y") setBackgroundOffsetY(node->value()); else if(node->tag() == "background-offset") setBackgroundOffset(node->value()); else if(node->tag() == "background-width") setBackgroundWidth(node->value()); else if(node->tag() == "background-height") setBackgroundHeight(node->value()); else if(node->tag() == "background-size") setBackgroundSize(node->value()); else if(node->tag() == "background-rect") setBackgroundRect(node->value()); else if(node->tag() == "icon") setIcon(stdext::resolve_path(node->value(), node->source())); else if(node->tag() == "icon-source") setIcon(stdext::resolve_path(node->value(), node->source())); else if(node->tag() == "icon-color") setIconColor(node->value()); else if(node->tag() == "icon-offset-x") setIconOffsetX(node->value()); else if(node->tag() == "icon-offset-y") setIconOffsetY(node->value()); else if(node->tag() == "icon-offset") setIconOffset(node->value()); else if(node->tag() == "icon-width") setIconWidth(node->value()); else if(node->tag() == "icon-height") setIconHeight(node->value()); else if(node->tag() == "icon-size") setIconSize(node->value()); else if(node->tag() == "icon-rect") setIconRect(node->value()); else if(node->tag() == "icon-clip") setIconClip(node->value()); else if(node->tag() == "opacity") setOpacity(node->value()); else if(node->tag() == "enabled") setEnabled(node->value()); else if(node->tag() == "visible") setVisible(node->value()); else if(node->tag() == "checked") setChecked(node->value()); else if(node->tag() == "dragable") setChecked(node->value()); else if(node->tag() == "on") setOn(node->value()); else if(node->tag() == "focusable") setFocusable(node->value()); else if(node->tag() == "phantom") setPhantom(node->value()); else if(node->tag() == "size") setSize(node->value()); else if(node->tag() == "fixed-size") setFixedSize(node->value()); else if(node->tag() == "clipping") setClipping(node->value()); else if(node->tag() == "border") { auto split = stdext::split(node->value(), " "); if(split.size() == 2) { setBorderWidth(stdext::safe_cast(split[0])); setBorderColor(stdext::safe_cast(split[1])); } else throw OTMLException(node, "border param must have its width followed by its color"); } else if(node->tag() == "border-width") setBorderWidth(node->value()); else if(node->tag() == "border-width-top") setBorderWidthTop(node->value()); else if(node->tag() == "border-width-right") setBorderWidthRight(node->value()); else if(node->tag() == "border-width-bottom") setBorderWidthBottom(node->value()); else if(node->tag() == "border-width-left") setBorderWidthLeft(node->value()); else if(node->tag() == "border-color") setBorderColor(node->value()); else if(node->tag() == "border-color-top") setBorderColorTop(node->value()); else if(node->tag() == "border-color-right") setBorderColorRight(node->value()); else if(node->tag() == "border-color-bottom") setBorderColorBottom(node->value()); else if(node->tag() == "border-color-left") setBorderColorLeft(node->value()); else if(node->tag() == "margin-top") setMarginTop(node->value()); else if(node->tag() == "margin-right") setMarginRight(node->value()); else if(node->tag() == "margin-bottom") setMarginBottom(node->value()); else if(node->tag() == "margin-left") setMarginLeft(node->value()); else if(node->tag() == "margin") { std::string marginDesc = node->value(); std::vector split; boost::split(split, marginDesc, boost::is_any_of(std::string(" "))); if(split.size() == 4) { setMarginTop(stdext::safe_cast(split[0])); setMarginRight(stdext::safe_cast(split[1])); setMarginBottom(stdext::safe_cast(split[2])); setMarginLeft(stdext::safe_cast(split[3])); } else if(split.size() == 3) { int marginTop = stdext::safe_cast(split[0]); int marginHorizontal = stdext::safe_cast(split[1]); int marginBottom = stdext::safe_cast(split[2]); setMarginTop(marginTop); setMarginRight(marginHorizontal); setMarginBottom(marginBottom); setMarginLeft(marginHorizontal); } else if(split.size() == 2) { int marginVertical = stdext::safe_cast(split[0]); int marginHorizontal = stdext::safe_cast(split[1]); setMarginTop(marginVertical); setMarginRight(marginHorizontal); setMarginBottom(marginVertical); setMarginLeft(marginHorizontal); } else if(split.size() == 1) { int margin = stdext::safe_cast(split[0]); setMarginTop(margin); setMarginRight(margin); setMarginBottom(margin); setMarginLeft(margin); } } else if(node->tag() == "padding-top") setPaddingTop(node->value()); else if(node->tag() == "padding-right") setPaddingRight(node->value()); else if(node->tag() == "padding-bottom") setPaddingBottom(node->value()); else if(node->tag() == "padding-left") setPaddingLeft(node->value()); else if(node->tag() == "padding") { std::string paddingDesc = node->value(); std::vector split; boost::split(split, paddingDesc, boost::is_any_of(std::string(" "))); if(split.size() == 4) { setPaddingTop(stdext::safe_cast(split[0])); setPaddingRight(stdext::safe_cast(split[1])); setPaddingBottom(stdext::safe_cast(split[2])); setPaddingLeft(stdext::safe_cast(split[3])); } else if(split.size() == 3) { int paddingTop = stdext::safe_cast(split[0]); int paddingHorizontal = stdext::safe_cast(split[1]); int paddingBottom = stdext::safe_cast(split[2]); setPaddingTop(paddingTop); setPaddingRight(paddingHorizontal); setPaddingBottom(paddingBottom); setPaddingLeft(paddingHorizontal); } else if(split.size() == 2) { int paddingVertical = stdext::safe_cast(split[0]); int paddingHorizontal = stdext::safe_cast(split[1]); setPaddingTop(paddingVertical); setPaddingRight(paddingHorizontal); setPaddingBottom(paddingVertical); setPaddingLeft(paddingHorizontal); } else if(split.size() == 1) { int padding = stdext::safe_cast(split[0]); setPaddingTop(padding); setPaddingRight(padding); setPaddingBottom(padding); setPaddingLeft(padding); } } // layouts else if(node->tag() == "layout") { std::string layoutType; if(node->hasValue()) layoutType = node->value(); else layoutType = node->valueAt("type", ""); if(!layoutType.empty()) { UILayoutPtr layout; if(layoutType == "horizontalBox") layout = UIHorizontalLayoutPtr(new UIHorizontalLayout(asUIWidget())); else if(layoutType == "verticalBox") layout = UIVerticalLayoutPtr(new UIVerticalLayout(asUIWidget())); else if(layoutType == "grid") layout = UIGridLayoutPtr(new UIGridLayout(asUIWidget())); else if(layoutType == "anchor") layout = UIAnchorLayoutPtr(new UIAnchorLayout(asUIWidget())); else throw OTMLException(node, "cannot determine layout type"); setLayout(layout); } if(node->hasChildren()) m_layout->applyStyle(node); } // anchors else if(boost::starts_with(node->tag(), "anchors.")) { UIWidgetPtr parent = getParent(); if(!parent) { if(m_firstOnStyle) throw OTMLException(node, "cannot create anchor, there is no parent widget!"); else continue; } UIAnchorLayoutPtr anchorLayout = parent->getLayout()->asUIAnchorLayout(); if(!anchorLayout) throw OTMLException(node, "cannot create anchor, the parent widget doesn't use anchor layout!"); std::string what = node->tag().substr(8); if(what == "fill") { fill(node->value()); } else if(what == "centerIn") { centerIn(node->value()); } else { Fw::AnchorEdge anchoredEdge = Fw::translateAnchorEdge(what); if(node->value() == "none") { removeAnchor(anchoredEdge); } else { std::vector split = stdext::split(node->value(), "."); if(split.size() != 2) throw OTMLException(node, "invalid anchor description"); std::string hookedWidgetId = split[0]; Fw::AnchorEdge hookedEdge = Fw::translateAnchorEdge(split[1]); if(anchoredEdge == Fw::AnchorNone) throw OTMLException(node, "invalid anchor edge"); if(hookedEdge == Fw::AnchorNone) throw OTMLException(node, "invalid anchor target edge"); addAnchor(anchoredEdge, hookedWidgetId, hookedEdge); } } // lua functions } else if(boost::starts_with(node->tag(), "@")) { // load once if(m_firstOnStyle) { std::string funcName = node->tag().substr(1); std::string funcOrigin = "@" + node->source() + "[" + node->tag() + "]"; g_lua.loadFunction(node->value(), funcOrigin); luaSetField(funcName); } // lua fields value } else if(boost::starts_with(node->tag(), "&")) { std::string fieldName = node->tag().substr(1); std::string fieldOrigin = "@" + node->source() + "[" + node->tag() + "]"; g_lua.evaluateExpression(node->value(), fieldOrigin); luaSetField(fieldName); } } } void UIWidget::drawBackground(const Rect& screenCoords) { if(m_backgroundColor.aF() > 0.0f) { Rect drawRect = screenCoords; drawRect.translate(m_backgroundRect.topLeft()); if(m_backgroundRect.isValid()) drawRect.resize(m_backgroundRect.size()); g_painter->setColor(m_backgroundColor); g_painter->drawFilledRect(drawRect); } } void UIWidget::drawBorder(const Rect& screenCoords) { // top if(m_borderWidth.top > 0) { g_painter->setColor(m_borderColor.top); Rect borderRect(screenCoords.topLeft(), screenCoords.width(), m_borderWidth.top); g_painter->drawFilledRect(borderRect); } // right if(m_borderWidth.right > 0) { g_painter->setColor(m_borderColor.right); Rect borderRect(screenCoords.topRight() - Point(m_borderWidth.right - 1, 0), m_borderWidth.right, screenCoords.height()); g_painter->drawFilledRect(borderRect); } // bottom if(m_borderWidth.bottom > 0) { g_painter->setColor(m_borderColor.bottom); Rect borderRect(screenCoords.bottomLeft() - Point(0, m_borderWidth.bottom - 1), screenCoords.width(), m_borderWidth.bottom); g_painter->drawFilledRect(borderRect); } // left if(m_borderWidth.left > 0) { g_painter->setColor(m_borderColor.left); Rect borderRect(screenCoords.topLeft(), m_borderWidth.left, screenCoords.height()); g_painter->drawFilledRect(borderRect); } } void UIWidget::drawIcon(const Rect& screenCoords) { if(m_icon) { Rect drawRect; if(m_iconRect.isValid()) { drawRect = screenCoords; drawRect.translate(m_iconRect.topLeft()); drawRect.resize(m_iconRect.size()); } else { drawRect.resize(m_iconClipRect.size()); drawRect.moveCenter(screenCoords.center()); } g_painter->setColor(m_iconColor); g_painter->drawTexturedRect(drawRect, m_icon, m_iconClipRect); } } void UIWidget::setIcon(const std::string& iconFile) { m_icon = g_textures.getTexture(iconFile); if(!m_iconClipRect.isValid()) m_iconClipRect = Rect(0, 0, m_icon->getSize()); }