mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-08-11 17:17:42 +03:00
1471 lines
41 KiB
C++
1471 lines
41 KiB
C++
#include <eepp/ui/uiwidget.hpp>
|
|
#include <eepp/ui/uithememanager.hpp>
|
|
#include <eepp/ui/uistyle.hpp>
|
|
#include <eepp/ui/uitooltip.hpp>
|
|
#include <eepp/ui/uiscenenode.hpp>
|
|
#include <eepp/ui/uinodedrawable.hpp>
|
|
#include <eepp/ui/css/transitiondefinition.hpp>
|
|
#include <eepp/ui/css/stylesheetproperty.hpp>
|
|
#include <eepp/ui/css/stylesheetselector.hpp>
|
|
#include <eepp/graphics/drawablesearcher.hpp>
|
|
#include <eepp/graphics/rectangledrawable.hpp>
|
|
#include <eepp/scene/actions/actions.hpp>
|
|
#include <eepp/system/functionstring.hpp>
|
|
#include <eepp/window/window.hpp>
|
|
#include <eepp/window/engine.hpp>
|
|
#include <pugixml/pugixml.hpp>
|
|
#include <algorithm>
|
|
#include <eepp/ui/css/shorthanddefinition.hpp>
|
|
#include <eepp/ui/css/stylesheetspecification.hpp>
|
|
|
|
using namespace EE::Window;
|
|
|
|
namespace EE { namespace UI {
|
|
|
|
UIWidget * UIWidget::New() {
|
|
return eeNew( UIWidget, () );
|
|
}
|
|
|
|
UIWidget * UIWidget::NewWithTag( const std::string& tag ) {
|
|
return eeNew( UIWidget, ( tag ) );
|
|
}
|
|
|
|
UIWidget::UIWidget( const std::string & tag ) :
|
|
UINode(),
|
|
mTag( tag ),
|
|
mTheme( NULL ),
|
|
mStyle( NULL ),
|
|
mTooltip( NULL ),
|
|
mMinControlSize(),
|
|
mLayoutWeight(0),
|
|
mLayoutGravity(0),
|
|
mLayoutWidthRules(WRAP_CONTENT),
|
|
mLayoutHeightRules(WRAP_CONTENT),
|
|
mLayoutPositionRule(NONE),
|
|
mLayoutPositionRuleWidget(NULL),
|
|
mAttributesTransactionCount(0)
|
|
{
|
|
mNodeFlags |= NODE_FLAG_WIDGET;
|
|
|
|
updateAnchorsDistances();
|
|
}
|
|
|
|
UIWidget::UIWidget() :
|
|
UIWidget( "widget" )
|
|
{
|
|
}
|
|
|
|
UIWidget::~UIWidget() {
|
|
eeSAFE_DELETE( mStyle );
|
|
eeSAFE_DELETE( mTooltip );
|
|
}
|
|
|
|
Uint32 UIWidget::getType() const {
|
|
return UI_TYPE_WIDGET;
|
|
}
|
|
|
|
bool UIWidget::isType( const Uint32& type ) const {
|
|
return UIWidget::getType() == type ? true : UINode::isType( type );
|
|
}
|
|
|
|
void UIWidget::updateAnchorsDistances() {
|
|
if ( NULL != mParentCtrl ) {
|
|
mDistToBorder = Rect( mPosition.x, mPosition.y, mParentCtrl->getPixelsSize().x - ( mPosition.x + mSize.x ), mParentCtrl->getPixelsSize().y - ( mPosition.y + mSize.y ) );
|
|
}
|
|
}
|
|
|
|
Rect UIWidget::getLayoutMargin() const {
|
|
return mLayoutMargin;
|
|
}
|
|
|
|
UIWidget * UIWidget::setLayoutMargin(const Rect & margin) {
|
|
if ( mLayoutMargin != margin ) {
|
|
mLayoutMargin = margin;
|
|
notifyLayoutAttrChange();
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
UIWidget * UIWidget::setLayoutMarginLeft(const Float& marginLeft) {
|
|
if ( mLayoutMargin.Left != marginLeft ) {
|
|
mLayoutMargin.Left = marginLeft;
|
|
notifyLayoutAttrChange();
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
UIWidget * UIWidget::setLayoutMarginRight(const Float& marginRight) {
|
|
if ( mLayoutMargin.Right != marginRight ) {
|
|
mLayoutMargin.Right = marginRight;
|
|
notifyLayoutAttrChange();
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
UIWidget * UIWidget::setLayoutMarginTop(const Float& marginTop) {
|
|
if ( mLayoutMargin.Top != marginTop ) {
|
|
mLayoutMargin.Top = marginTop;
|
|
notifyLayoutAttrChange();
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
UIWidget * UIWidget::setLayoutMarginBottom(const Float& marginBottom) {
|
|
if ( mLayoutMargin.Bottom != marginBottom ) {
|
|
mLayoutMargin.Bottom = marginBottom;
|
|
notifyLayoutAttrChange();
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
Float UIWidget::getLayoutWeight() const {
|
|
return mLayoutWeight;
|
|
}
|
|
|
|
UIWidget * UIWidget::setLayoutWeight(const Float & weight) {
|
|
if ( mLayoutWeight != weight ) {
|
|
mLayoutWeight = weight;
|
|
notifyLayoutAttrChange();
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
Uint32 UIWidget::getLayoutGravity() const {
|
|
return mLayoutGravity;
|
|
}
|
|
|
|
UIWidget * UIWidget::setLayoutGravity(const Uint32 & layoutGravity) {
|
|
if ( mLayoutGravity != layoutGravity ) {
|
|
mLayoutGravity = layoutGravity;
|
|
notifyLayoutAttrChange();
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
LayoutSizeRules UIWidget::getLayoutWidthRules() const {
|
|
return mLayoutWidthRules;
|
|
}
|
|
|
|
UIWidget * UIWidget::setLayoutWidthRules(const LayoutSizeRules & layoutWidthRules) {
|
|
if ( mLayoutWidthRules != layoutWidthRules ) {
|
|
mLayoutWidthRules = layoutWidthRules;
|
|
notifyLayoutAttrChange();
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
LayoutSizeRules UIWidget::getLayoutHeightRules() const {
|
|
return mLayoutHeightRules;
|
|
}
|
|
|
|
UIWidget * UIWidget::setLayoutHeightRules(const LayoutSizeRules & layoutHeightRules) {
|
|
if ( mLayoutHeightRules != layoutHeightRules ) {
|
|
mLayoutHeightRules = layoutHeightRules;
|
|
notifyLayoutAttrChange();
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
UIWidget * UIWidget::setLayoutSizeRules(const LayoutSizeRules & layoutWidthRules, const LayoutSizeRules & layoutHeightRules) {
|
|
if ( mLayoutWidthRules != layoutWidthRules || mLayoutHeightRules != layoutHeightRules ) {
|
|
mLayoutWidthRules = layoutWidthRules;
|
|
mLayoutHeightRules = layoutHeightRules;
|
|
notifyLayoutAttrChange();
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
UIWidget * UIWidget::setLayoutPositionRule(const LayoutPositionRules & layoutPositionRule, UIWidget * of) {
|
|
if ( mLayoutPositionRule != layoutPositionRule || mLayoutPositionRuleWidget != of ) {
|
|
mLayoutPositionRule = layoutPositionRule;
|
|
mLayoutPositionRuleWidget = of;
|
|
notifyLayoutAttrChange();
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
UIWidget * UIWidget::getLayoutPositionRuleWidget() const {
|
|
return mLayoutPositionRuleWidget;
|
|
}
|
|
|
|
LayoutPositionRules UIWidget::getLayoutPositionRule() const {
|
|
return mLayoutPositionRule;
|
|
}
|
|
|
|
void UIWidget::createTooltip() {
|
|
if ( NULL != mTooltip )
|
|
return;
|
|
|
|
mTooltip = UITooltip::New();
|
|
mTooltip->setVisible( false )->setEnabled( false );
|
|
mTooltip->setTooltipOf( this );
|
|
}
|
|
|
|
Uint32 UIWidget::onMouseMove( const Vector2i & Pos, const Uint32& Flags ) {
|
|
if ( mVisible && NULL != mTooltip && !mTooltip->getText().empty() ) {
|
|
EventDispatcher * eventDispatcher = getEventDispatcher();
|
|
|
|
if ( NULL == eventDispatcher )
|
|
return 1;
|
|
|
|
UIThemeManager * themeManager = UIThemeManager::instance();
|
|
|
|
Vector2f Pos = eventDispatcher->getMousePosf();
|
|
Pos.x += themeManager->getCursorSize().x;
|
|
Pos.y += themeManager->getCursorSize().y;
|
|
|
|
if ( Pos.x + mTooltip->getPixelsSize().getWidth() > eventDispatcher->getSceneNode()->getPixelsSize().getWidth() ) {
|
|
Pos.x = eventDispatcher->getMousePos().x - mTooltip->getPixelsSize().getWidth();
|
|
}
|
|
|
|
if ( Pos.y + mTooltip->getPixelsSize().getHeight() > eventDispatcher->getSceneNode()->getPixelsSize().getHeight() ) {
|
|
Pos.y = eventDispatcher->getMousePos().y - mTooltip->getPixelsSize().getHeight();
|
|
}
|
|
|
|
if ( Time::Zero == themeManager->getTooltipTimeToShow() ) {
|
|
if ( !mTooltip->isVisible() || themeManager->getTooltipFollowMouse() )
|
|
mTooltip->setPosition( PixelDensity::pxToDp( Pos ) );
|
|
|
|
mTooltip->show();
|
|
} else {
|
|
if ( -1.f != mTooltip->getTooltipTime().asMilliseconds() ) {
|
|
mTooltip->addTooltipTime( mSceneNode->getElapsed() );
|
|
}
|
|
|
|
if ( mTooltip->getTooltipTime() >= themeManager->getTooltipTimeToShow() ) {
|
|
if ( mTooltip->getTooltipTime().asMilliseconds() != -1.f ) {
|
|
mTooltip->setPixelsPosition( Pos );
|
|
|
|
mTooltip->show();
|
|
|
|
mTooltip->setTooltipTime( Milliseconds( -1.f ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( themeManager->getTooltipFollowMouse() ) {
|
|
mTooltip->setPixelsPosition( Pos );
|
|
}
|
|
}
|
|
|
|
return UINode::onMouseMove( Pos, Flags );
|
|
}
|
|
|
|
Uint32 UIWidget::onMouseLeave( const Vector2i & Pos, const Uint32& Flags ) {
|
|
if ( mVisible && NULL != mTooltip && !mTooltip->getText().empty() ) {
|
|
mTooltip->setTooltipTime( Milliseconds( 0.f ) );
|
|
|
|
if ( mTooltip->isVisible() )
|
|
mTooltip->hide();
|
|
}
|
|
|
|
return UINode::onMouseLeave( Pos, Flags );
|
|
}
|
|
|
|
UIWidget * UIWidget::setTooltipText( const String& Text ) {
|
|
if ( NULL == mTooltip ) { // If the tooltip wasn't created it will avoid to create a new one if the string is ""
|
|
if ( Text.size() ) {
|
|
createTooltip();
|
|
|
|
mTooltip->setText( Text );
|
|
}
|
|
} else { // but if it's created, i will allow it
|
|
mTooltip->setText( Text );
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
String UIWidget::getTooltipText() {
|
|
if ( NULL != mTooltip )
|
|
return mTooltip->getText();
|
|
|
|
return String();
|
|
}
|
|
|
|
void UIWidget::tooltipRemove() {
|
|
mTooltip = NULL;
|
|
}
|
|
|
|
Node * UIWidget::setSize( const Sizef& size ) {
|
|
Sizef s( size );
|
|
|
|
if ( s.x < mMinControlSize.x )
|
|
s.x = mMinControlSize.x;
|
|
|
|
if ( s.y < mMinControlSize.y )
|
|
s.y = mMinControlSize.y;
|
|
|
|
return UINode::setSize( s );
|
|
}
|
|
|
|
UINode * UIWidget::setFlags(const Uint32 & flags) {
|
|
if ( flags & ( UI_ANCHOR_LEFT | UI_ANCHOR_TOP | UI_ANCHOR_RIGHT | UI_ANCHOR_BOTTOM ) ) {
|
|
updateAnchorsDistances();
|
|
}
|
|
|
|
if ( !( mFlags & UI_AUTO_SIZE ) && ( flags & UI_AUTO_SIZE ) ) {
|
|
onAutoSize();
|
|
}
|
|
|
|
return UINode::setFlags( flags );
|
|
}
|
|
|
|
UINode * UIWidget::unsetFlags(const Uint32 & flags) {
|
|
if ( flags & ( UI_ANCHOR_LEFT | UI_ANCHOR_TOP | UI_ANCHOR_RIGHT | UI_ANCHOR_BOTTOM ) ) {
|
|
updateAnchorsDistances();
|
|
}
|
|
|
|
return UINode::unsetFlags( flags );
|
|
}
|
|
|
|
UIWidget * UIWidget::setAnchors(const Uint32 & flags) {
|
|
mFlags &= ~(UI_ANCHOR_LEFT | UI_ANCHOR_TOP | UI_ANCHOR_RIGHT | UI_ANCHOR_BOTTOM);
|
|
mFlags |= flags;
|
|
updateAnchorsDistances();
|
|
return this;
|
|
}
|
|
|
|
void UIWidget::setTheme( UITheme * Theme ) {
|
|
mTheme = Theme;
|
|
invalidateDraw();
|
|
}
|
|
|
|
UINode * UIWidget::setThemeSkin( const std::string& skinName ) {
|
|
return setThemeSkin( NULL != mTheme ? mTheme : UIThemeManager::instance()->getDefaultTheme(), skinName );
|
|
}
|
|
|
|
UINode * UIWidget::setThemeSkin( UITheme * Theme, const std::string& skinName ) {
|
|
return UINode::setThemeSkin( Theme, skinName );
|
|
}
|
|
|
|
Node * UIWidget::setSize( const Float& Width, const Float& Height ) {
|
|
return UINode::setSize( Width, Height );
|
|
}
|
|
|
|
Node * UIWidget::setId( const std::string& id ) {
|
|
Node::setId( id );
|
|
|
|
reloadStyle( true );
|
|
|
|
return this;
|
|
}
|
|
|
|
const Sizef& UIWidget::getSize() const {
|
|
return UINode::getSize();
|
|
}
|
|
|
|
UITooltip * UIWidget::getTooltip() {
|
|
return mTooltip;
|
|
}
|
|
|
|
void UIWidget::onParentSizeChange( const Vector2f& SizeChange ) {
|
|
updateAnchors( SizeChange );
|
|
UINode::onParentSizeChange( SizeChange );
|
|
}
|
|
|
|
void UIWidget::onPositionChange() {
|
|
updateAnchorsDistances();
|
|
UINode::onPositionChange();
|
|
}
|
|
|
|
void UIWidget::onVisibilityChange() {
|
|
updateAnchorsDistances();
|
|
notifyLayoutAttrChange();
|
|
UINode::onVisibilityChange();
|
|
}
|
|
|
|
void UIWidget::onSizeChange() {
|
|
UINode::onSizeChange();
|
|
notifyLayoutAttrChange();
|
|
}
|
|
|
|
void UIWidget::onAutoSize() {
|
|
}
|
|
|
|
void UIWidget::onWidgetCreated() {
|
|
}
|
|
|
|
void UIWidget::notifyLayoutAttrChange() {
|
|
if ( 0 == mAttributesTransactionCount ) {
|
|
NodeMessage msg( this, NodeMessage::LayoutAttributeChange );
|
|
messagePost( &msg );
|
|
}
|
|
}
|
|
|
|
void UIWidget::notifyLayoutAttrChangeParent() {
|
|
if ( 0 == mAttributesTransactionCount && NULL != mParentCtrl ) {
|
|
NodeMessage msg( this, NodeMessage::LayoutAttributeChange );
|
|
mParentCtrl->messagePost( &msg );
|
|
}
|
|
}
|
|
|
|
void UIWidget::updateAnchors( const Vector2f& SizeChange ) {
|
|
if ( !( mFlags & ( UI_ANCHOR_LEFT | UI_ANCHOR_TOP | UI_ANCHOR_RIGHT | UI_ANCHOR_BOTTOM ) ) )
|
|
return;
|
|
|
|
Sizef newSize( getSize() );
|
|
|
|
if ( !( mFlags & UI_ANCHOR_LEFT ) ) {
|
|
setInternalPosition( Vector2f( mDpPos.x += SizeChange.x, mDpPos.y ) );
|
|
}
|
|
|
|
if ( mFlags & UI_ANCHOR_RIGHT ) {
|
|
if ( NULL != mParentCtrl ) {
|
|
newSize.x = mParentCtrl->getSize().getWidth() - mDpPos.x - PixelDensity::pxToDpI( mDistToBorder.Right );
|
|
|
|
if ( newSize.x < mMinControlSize.getWidth() )
|
|
newSize.x = mMinControlSize.getWidth();
|
|
}
|
|
}
|
|
|
|
if ( !( mFlags & UI_ANCHOR_TOP ) ) {
|
|
setInternalPosition( Vector2f( mDpPos.x, mDpPos.y += SizeChange.y ) );
|
|
}
|
|
|
|
if ( mFlags & UI_ANCHOR_BOTTOM ) {
|
|
if ( NULL != mParentCtrl ) {
|
|
newSize.y = mParentCtrl->getSize().y - mDpPos.y - PixelDensity::pxToDpI( mDistToBorder.Bottom );
|
|
|
|
if ( newSize.y < mMinControlSize.getHeight() )
|
|
newSize.y = mMinControlSize.getHeight();
|
|
}
|
|
}
|
|
|
|
if ( newSize != getSize() )
|
|
setSize( newSize );
|
|
}
|
|
|
|
void UIWidget::alignAgainstLayout() {
|
|
Vector2f pos = mDpPos;
|
|
|
|
switch ( fontHAlignGet( mLayoutGravity ) ) {
|
|
case UI_HALIGN_CENTER:
|
|
pos.x = ( getParent()->getSize().getWidth() - getSize().getWidth() ) / 2;
|
|
break;
|
|
case UI_HALIGN_RIGHT:
|
|
pos.x = getParent()->getSize().getWidth() - mLayoutMargin.Right;
|
|
break;
|
|
case UI_HALIGN_LEFT:
|
|
pos.x = mLayoutMargin.Left;
|
|
break;
|
|
}
|
|
|
|
switch ( fontVAlignGet( mLayoutGravity ) ) {
|
|
case UI_VALIGN_CENTER:
|
|
pos.y = ( getParent()->getSize().getHeight() - getSize().getHeight() ) / 2;
|
|
break;
|
|
case UI_VALIGN_BOTTOM:
|
|
pos.y = getParent()->getSize().getHeight() - mLayoutMargin.Bottom;
|
|
break;
|
|
case UI_VALIGN_TOP:
|
|
pos.y = mLayoutMargin.Top;
|
|
break;
|
|
}
|
|
|
|
setPosition( pos );
|
|
}
|
|
|
|
void UIWidget::reportStyleStateChange() {
|
|
if ( NULL != mStyle && !mStyle->isChangingState() )
|
|
mStyle->onStateChange();
|
|
}
|
|
|
|
bool UIWidget::isSceneNodeLoading() const {
|
|
return getSceneNode()->isUISceneNode() ? static_cast<UISceneNode*>( getSceneNode() )->isLoading() : false;
|
|
}
|
|
|
|
const Rectf& UIWidget::getPadding() const {
|
|
return mPadding;
|
|
}
|
|
|
|
UIWidget * UIWidget::setPadding(const Rectf& padding) {
|
|
if ( padding != mPadding ) {
|
|
mPadding = padding;
|
|
mRealPadding = PixelDensity::dpToPx( mPadding );
|
|
onAutoSize();
|
|
onPaddingChange();
|
|
notifyLayoutAttrChange();
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
UIWidget * UIWidget::setPaddingLeft(const Float& paddingLeft) {
|
|
if ( paddingLeft != mPadding.Left ) {
|
|
mPadding.Left = paddingLeft;
|
|
mRealPadding.Left = PixelDensity::dpToPx( mPadding.Left );
|
|
onAutoSize();
|
|
onPaddingChange();
|
|
notifyLayoutAttrChange();
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
UIWidget * UIWidget::setPaddingRight(const Float& paddingRight) {
|
|
if ( paddingRight != mPadding.Right ) {
|
|
mPadding.Right = paddingRight;
|
|
mRealPadding.Right = PixelDensity::dpToPx( mPadding.Right );
|
|
onAutoSize();
|
|
onPaddingChange();
|
|
notifyLayoutAttrChange();
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
UIWidget * UIWidget::setPaddingTop(const Float& paddingTop) {
|
|
if ( paddingTop != mPadding.Top ) {
|
|
mPadding.Top = paddingTop;
|
|
mRealPadding.Top = PixelDensity::dpToPx( mPadding.Top );
|
|
onAutoSize();
|
|
onPaddingChange();
|
|
notifyLayoutAttrChange();
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
UIWidget * UIWidget::setPaddingBottom(const Float& paddingBottom) {
|
|
if ( paddingBottom != mPadding.Bottom ) {
|
|
mPadding.Bottom = paddingBottom;
|
|
mRealPadding.Bottom = PixelDensity::dpToPx( mPadding.Bottom );
|
|
onAutoSize();
|
|
onPaddingChange();
|
|
notifyLayoutAttrChange();
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
const std::string &UIWidget::getStyleSheetId() const {
|
|
return mId;
|
|
}
|
|
|
|
const std::string& UIWidget::getStyleSheetTag() const {
|
|
return mTag;
|
|
}
|
|
|
|
const std::vector<std::string> &UIWidget::getStyleSheetClasses() const {
|
|
return mClasses;
|
|
}
|
|
|
|
CSS::StyleSheetElement * UIWidget::getStyleSheetParentElement() const {
|
|
return NULL != mParentCtrl && mParentCtrl->isWidget() ? dynamic_cast<CSS::StyleSheetElement*>( mParentCtrl ) : NULL;
|
|
}
|
|
|
|
CSS::StyleSheetElement * UIWidget::getStyleSheetPreviousSiblingElement() const {
|
|
return NULL != mPrev && mPrev->isWidget() ? dynamic_cast<CSS::StyleSheetElement*>( mPrev ) : NULL;
|
|
}
|
|
|
|
CSS::StyleSheetElement * UIWidget::getStyleSheetNextSiblingElement() const {
|
|
return NULL != mNext && mNext->isWidget() ? dynamic_cast<CSS::StyleSheetElement*>( mNext ) : NULL;
|
|
}
|
|
|
|
const std::vector<std::string> &UIWidget::getStyleSheetPseudoClasses() const {
|
|
return mPseudoClasses;
|
|
}
|
|
|
|
void UIWidget::updatePseudoClasses() {
|
|
mPseudoClasses.clear();
|
|
|
|
if ( mState & UIState::StateFlagHover )
|
|
mPseudoClasses.push_back( "hover" );
|
|
|
|
if ( mState & UIState::StateFlagFocus )
|
|
mPseudoClasses.push_back( "focus" );
|
|
|
|
if ( mState & UIState::StateFlagSelected )
|
|
mPseudoClasses.push_back( "selected" );
|
|
|
|
if ( mState & UIState::StateFlagPressed )
|
|
mPseudoClasses.push_back( "pressed" );
|
|
|
|
if ( mState & UIState::StateFlagDisabled )
|
|
mPseudoClasses.push_back( "disabled" );
|
|
|
|
invalidateDraw();
|
|
}
|
|
|
|
void UIWidget::addClass( const std::string& cls ) {
|
|
if ( !cls.empty() && !containsClass( cls ) ) {
|
|
mClasses.push_back( cls );
|
|
|
|
reloadStyle( true );
|
|
}
|
|
}
|
|
|
|
void UIWidget::addClasses( const std::vector<std::string>& classes ) {
|
|
if ( !classes.empty() ) {
|
|
for ( auto cit = classes.begin(); cit != classes.end(); ++cit ) {
|
|
const std::string& cls = *cit;
|
|
|
|
if ( !cls.empty() && !containsClass( cls ) ) {
|
|
mClasses.push_back( cls );
|
|
}
|
|
}
|
|
|
|
reloadStyle( true );
|
|
}
|
|
}
|
|
|
|
void UIWidget::removeClass( const std::string& cls ) {
|
|
if ( containsClass( cls ) ) {
|
|
mClasses.erase( std::find( mClasses.begin(), mClasses.end(), cls ) );
|
|
|
|
reloadStyle( true );
|
|
}
|
|
}
|
|
|
|
void UIWidget::removeClasses( const std::vector<std::string>& classes ) {
|
|
if ( !classes.empty() ) {
|
|
for ( auto cit = classes.begin(); cit != classes.end(); ++cit ) {
|
|
const std::string& cls = *cit;
|
|
|
|
if ( !cls.empty() ) {
|
|
auto found = std::find( mClasses.begin(), mClasses.end(), cls );
|
|
|
|
if ( found != mClasses.end() ) {
|
|
mClasses.erase(found);
|
|
}
|
|
}
|
|
}
|
|
|
|
reloadStyle( true );
|
|
}
|
|
}
|
|
|
|
bool UIWidget::containsClass( const std::string& cls ) const {
|
|
return std::find( mClasses.begin(), mClasses.end(), cls ) != mClasses.end();
|
|
}
|
|
|
|
void UIWidget::setElementTag( const std::string& tag ) {
|
|
if ( mTag != tag ) {
|
|
mTag = tag;
|
|
|
|
reloadStyle( true );
|
|
}
|
|
}
|
|
|
|
const std::string& UIWidget::getElementTag() const {
|
|
return mTag;
|
|
}
|
|
|
|
void UIWidget::pushState( const Uint32& State, bool emitEvent ) {
|
|
if ( !( mState & ( 1 << State ) ) ) {
|
|
mState |= 1 << State;
|
|
|
|
if ( NULL != mSkinState )
|
|
mSkinState->pushState( State );
|
|
|
|
if ( NULL != mStyle ) {
|
|
updatePseudoClasses();
|
|
mStyle->pushState( State );
|
|
}
|
|
|
|
if ( emitEvent ) {
|
|
onStateChange();
|
|
} else {
|
|
invalidateDraw();
|
|
}
|
|
}
|
|
}
|
|
|
|
void UIWidget::popState( const Uint32& State, bool emitEvent ) {
|
|
if ( mState & ( 1 << State ) ) {
|
|
mState &= ~( 1 << State );
|
|
|
|
if ( NULL != mSkinState )
|
|
mSkinState->popState( State );
|
|
|
|
if ( NULL != mStyle ) {
|
|
updatePseudoClasses();
|
|
mStyle->popState( State );
|
|
}
|
|
|
|
if ( emitEvent ) {
|
|
onStateChange();
|
|
} else {
|
|
invalidateDraw();
|
|
}
|
|
}
|
|
}
|
|
|
|
UIStyle * UIWidget::getUIStyle() const {
|
|
return mStyle;
|
|
}
|
|
|
|
void UIWidget::reloadStyle( const bool& reloadChilds ) {
|
|
if ( NULL == mStyle && getSceneNode()->isUISceneNode() && static_cast<UISceneNode*>( getSceneNode() )->hasStyleSheet() ) {
|
|
mStyle = UIStyle::New( this );
|
|
mStyle->setState( mState );
|
|
}
|
|
|
|
if ( NULL != mStyle ) {
|
|
mStyle->load();
|
|
reportStyleStateChange();
|
|
|
|
if ( NULL != mChild && reloadChilds ) {
|
|
Node * ChildLoop = mChild;
|
|
|
|
while ( NULL != ChildLoop ) {
|
|
if ( ChildLoop->isWidget() )
|
|
static_cast<UIWidget*>( ChildLoop )->reloadStyle( reloadChilds );
|
|
|
|
ChildLoop = ChildLoop->getNextNode();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void UIWidget::onPaddingChange() {
|
|
sendCommonEvent( Event::OnPaddingChange );
|
|
invalidateDraw();
|
|
}
|
|
|
|
void UIWidget::onThemeLoaded() {
|
|
reportStyleStateChange();
|
|
}
|
|
|
|
void UIWidget::onParentChange() {
|
|
reloadStyle( true );
|
|
}
|
|
|
|
void UIWidget::beginAttributesTransaction() {
|
|
mAttributesTransactionCount++;
|
|
}
|
|
|
|
void UIWidget::endAttributesTransaction() {
|
|
mAttributesTransactionCount--;
|
|
|
|
if ( 0 == mAttributesTransactionCount ) {
|
|
notifyLayoutAttrChange();
|
|
}
|
|
}
|
|
|
|
const Uint32& UIWidget::getStyleState() const {
|
|
return NULL != mStyle ? mStyle->getCurrentState() : mState;
|
|
}
|
|
|
|
const Uint32& UIWidget::getStylePreviousState() const {
|
|
return NULL != mStyle ? mStyle->getPreviousState() : mState;
|
|
}
|
|
|
|
std::vector<UIWidget*> UIWidget::findAllByClass( const std::string& className ) {
|
|
std::vector<UIWidget*> widgets;
|
|
|
|
if ( containsClass( className ) ) {
|
|
widgets.push_back( this );
|
|
}
|
|
|
|
Node * child = mChild;
|
|
|
|
while ( NULL != child ) {
|
|
if ( child->isWidget() ) {
|
|
std::vector<UIWidget*> foundWidgets = child->asType<UIWidget>()->findAllByClass( className );
|
|
|
|
if ( !foundWidgets.empty() )
|
|
widgets.insert( widgets.end(), foundWidgets.begin(), foundWidgets.end() );
|
|
}
|
|
|
|
child = child->getNextNode();
|
|
}
|
|
|
|
return widgets;
|
|
}
|
|
|
|
std::vector<UIWidget*> UIWidget::findAllByTag( const std::string& tag ) {
|
|
std::vector<UIWidget*> widgets;
|
|
|
|
if ( getElementTag() == tag ) {
|
|
widgets.push_back( this );
|
|
}
|
|
|
|
Node * child = mChild;
|
|
|
|
while ( NULL != child ) {
|
|
if ( child->isWidget() ) {
|
|
std::vector<UIWidget*> foundWidgets = child->asType<UIWidget>()->findAllByTag( tag );
|
|
|
|
if ( !foundWidgets.empty() )
|
|
widgets.insert( widgets.end(), foundWidgets.begin(), foundWidgets.end() );
|
|
}
|
|
|
|
child = child->getNextNode();
|
|
}
|
|
|
|
return widgets;
|
|
}
|
|
|
|
UIWidget* UIWidget::findByClass( const std::string& className ) {
|
|
if ( containsClass( className ) ) {
|
|
return this;
|
|
} else {
|
|
Node * child = mChild;
|
|
|
|
while ( NULL != child ) {
|
|
if ( child->isWidget() ) {
|
|
UIWidget * foundWidget = child->asType<UIWidget>()->findByClass( className );
|
|
|
|
if ( NULL != foundWidget )
|
|
return foundWidget;
|
|
}
|
|
|
|
child = child->getNextNode();
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
UIWidget* UIWidget::findByTag( const std::string& tag ) {
|
|
if ( getElementTag() == tag ) {
|
|
return this;
|
|
} else {
|
|
Node * child = mChild;
|
|
|
|
while ( NULL != child ) {
|
|
if ( child->isWidget() ) {
|
|
UIWidget * foundWidget = child->asType<UIWidget>()->findByTag( tag );
|
|
|
|
if ( NULL != foundWidget )
|
|
return foundWidget;
|
|
}
|
|
|
|
child = child->getNextNode();
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
UIWidget* UIWidget::querySelector( const CSS::StyleSheetSelector& selector ) {
|
|
if ( selector.select( this ) ) {
|
|
return this;
|
|
} else {
|
|
Node * child = mChild;
|
|
|
|
while ( NULL != child ) {
|
|
if ( child->isWidget() ) {
|
|
UIWidget * foundWidget = child->asType<UIWidget>()->querySelector( selector );
|
|
|
|
if ( NULL != foundWidget )
|
|
return foundWidget;
|
|
}
|
|
|
|
child = child->getNextNode();
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
std::vector<UIWidget*> UIWidget::querySelectorAll( const CSS::StyleSheetSelector& selector ) {
|
|
std::vector<UIWidget*> widgets;
|
|
|
|
if ( selector.select( this ) ) {
|
|
widgets.push_back( this );
|
|
}
|
|
|
|
Node * child = mChild;
|
|
|
|
while ( NULL != child ) {
|
|
if ( child->isWidget() ) {
|
|
std::vector<UIWidget*> foundWidgets = child->asType<UIWidget>()->querySelectorAll( selector );
|
|
|
|
if ( !foundWidgets.empty() )
|
|
widgets.insert( widgets.end(), foundWidgets.begin(), foundWidgets.end() );
|
|
}
|
|
|
|
child = child->getNextNode();
|
|
}
|
|
|
|
return widgets;
|
|
}
|
|
|
|
bool UIWidget::checkPropertyDefinition( const StyleSheetProperty& property ) {
|
|
if ( property.getPropertyDefinition() == NULL ) {
|
|
eePRINTL( "applyProperty: Property %s not defined!", property.getName().c_str() );
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
UIWidget* UIWidget::querySelector( const std::string& selector ) {
|
|
return querySelector( CSS::StyleSheetSelector( selector ) );
|
|
}
|
|
|
|
std::vector<UIWidget*> UIWidget::querySelectorAll( const std::string& selector ) {
|
|
return querySelectorAll( CSS::StyleSheetSelector( selector ) );
|
|
}
|
|
|
|
std::string UIWidget::getPropertyString( const std::string& property ) {
|
|
return getPropertyString( StyleSheetSpecification::instance()->getProperty( property ) );
|
|
}
|
|
|
|
std::string UIWidget::getPropertyString( const PropertyDefinition* propertyDef ) {
|
|
if ( NULL == propertyDef ) return "";
|
|
|
|
switch ( propertyDef->getPropertyId() ) {
|
|
case PropertyId::X:
|
|
return String::format( "%.2fdp", getPosition().x );
|
|
case PropertyId::Y:
|
|
return String::format( "%.2fdp", getPosition().y );
|
|
case PropertyId::Width:
|
|
return String::format( "%.2fdp", getSize().getWidth() );
|
|
case PropertyId::Height:
|
|
return String::format( "%.2fdp", getSize().getHeight() );
|
|
case PropertyId::MarginLeft:
|
|
return String::format( "%ddp", getLayoutMargin().Left );
|
|
case PropertyId::MarginTop:
|
|
return String::format( "%ddp", getLayoutMargin().Top );
|
|
case PropertyId::MarginRight:
|
|
return String::format( "%ddp", getLayoutMargin().Right );
|
|
case PropertyId::MarginBottom:
|
|
return String::format( "%ddp", getLayoutMargin().Bottom );
|
|
case PropertyId::PaddingLeft:
|
|
return String::format( "%.2fdp", getPadding().Left );
|
|
case PropertyId::PaddingTop:
|
|
return String::format( "%.2fdp", getPadding().Top );
|
|
case PropertyId::PaddingRight:
|
|
return String::format( "%.2fdp", getPadding().Right );
|
|
case PropertyId::PaddingBottom:
|
|
return String::format( "%.2fdp", getPadding().Bottom );
|
|
case PropertyId::BackgroundColor:
|
|
return getBackgroundColor().toHexString();
|
|
case PropertyId::ForegroundColor:
|
|
return getForegroundColor().toHexString();
|
|
case PropertyId::BorderColor:
|
|
return getBorderColor().toHexString();
|
|
case PropertyId::BorderRadius:
|
|
return String::format( "%u", getBorderRadius() );
|
|
case PropertyId::SkinColor:
|
|
return getSkinColor().toHexString();
|
|
case PropertyId::Rotation:
|
|
return String::format( "%f", getRotation() );
|
|
case PropertyId::Scale:
|
|
return String::format( "%f, %f", getScale().x, getScale().y );
|
|
case PropertyId::Opacity:
|
|
return String::format( "%f", getAlpha() );
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return "";
|
|
}
|
|
|
|
void UIWidget::setStyleSheetProperty( const std::string& name, const std::string& value, const Uint32& specificity ) {
|
|
if ( mStyle != NULL )
|
|
mStyle->setStyleSheetProperty( CSS::StyleSheetProperty( name, value, specificity ) );
|
|
}
|
|
/*
|
|
#define SAVE_NORMAL_STATE_ATTR( ATTR_FORMATED ) \
|
|
if ( state != UIState::StateFlagNormal || ( state == UIState::StateFlagNormal && attribute.isVolatile() ) ) { \
|
|
CSS::StyleSheetProperty oldAttribute = mStyle->getStatelessStyleSheetProperty( attribute.getName() ); \
|
|
if ( oldAttribute.isEmpty() && mStyle->getPreviousState() == UIState::StateFlagNormal ) { \
|
|
mStyle->setStyleSheetProperty( CSS::StyleSheetProperty( attribute.getName(), ATTR_FORMATED ) ); \
|
|
} \
|
|
}
|
|
*/
|
|
#define SAVE_NORMAL_STATE_ATTR( ATTR_FORMATED );
|
|
|
|
bool UIWidget::applyProperty( const StyleSheetProperty& attribute, const Uint32& state ) {
|
|
if ( !checkPropertyDefinition( attribute ) ) return false;
|
|
bool attributeSet = true;
|
|
|
|
switch ( static_cast<PropertyId>( attribute.getPropertyDefinition()->getId() ) ) {
|
|
case PropertyId::Id:
|
|
setId( attribute.value() );
|
|
break;
|
|
case PropertyId::Class:
|
|
addClasses( String::split( attribute.getValue(), ' ' ) );
|
|
break;
|
|
case PropertyId::X:
|
|
SAVE_NORMAL_STATE_ATTR( String::format( "%.2f", getSize().getWidth() ) );
|
|
setLayoutWidthRules( FIXED );
|
|
setInternalPosition( Vector2f( attribute.asDpDimension(), mDpPos.y ) );
|
|
notifyLayoutAttrChange();
|
|
break;
|
|
case PropertyId::Y:
|
|
SAVE_NORMAL_STATE_ATTR( String::format( "%.2f", getSize().getHeight() ) );
|
|
setLayoutWidthRules( FIXED );
|
|
setInternalPosition( Vector2f( mDpPos.x, attribute.asDpDimensionI() ) );
|
|
notifyLayoutAttrChange();
|
|
break;
|
|
case PropertyId::Width:
|
|
SAVE_NORMAL_STATE_ATTR( String::format( "%.2f", getSize().getWidth() ) );
|
|
setLayoutWidthRules( FIXED );
|
|
setInternalWidth( attribute.asDpDimensionI() );
|
|
notifyLayoutAttrChange();
|
|
break;
|
|
case PropertyId::Height:
|
|
SAVE_NORMAL_STATE_ATTR( String::format( "%.2f", getSize().getHeight() ) );
|
|
setLayoutHeightRules( FIXED );
|
|
setInternalHeight( attribute.asDpDimensionI() );
|
|
notifyLayoutAttrChange();
|
|
break;
|
|
case PropertyId::BackgroundColor:
|
|
SAVE_NORMAL_STATE_ATTR( getBackgroundColor().toHexString() );
|
|
setBackgroundColor( attribute.asColor() );
|
|
break;
|
|
case PropertyId::BackgroundImage:
|
|
drawablePropertySet( "background", attribute.getValue(), [&] ( Drawable * drawable, bool ownIt, int index ) {
|
|
setBackgroundDrawable( drawable, ownIt, index );
|
|
} );
|
|
break;
|
|
case PropertyId::BackgroundRepeat:
|
|
setBackgroundRepeat( attribute.value(), 0 );
|
|
break;
|
|
case PropertyId::BackgroundSize:
|
|
SAVE_NORMAL_STATE_ATTR( getBackground()->getLayer(0)->getSizeEq() );
|
|
setBackgroundSize( attribute.value(), 0 );
|
|
break;
|
|
case PropertyId::ForegroundColor:
|
|
SAVE_NORMAL_STATE_ATTR( getForegroundColor().toHexString() );
|
|
setForegroundColor( attribute.asColor() );
|
|
break;
|
|
case PropertyId::ForegroundImage:
|
|
drawablePropertySet( "foreground", attribute.getValue(), [&] ( Drawable * drawable, bool ownIt, int index ) {
|
|
setForegroundDrawable( drawable, ownIt, index );
|
|
} );
|
|
break;
|
|
case PropertyId::ForegroundRadius:
|
|
SAVE_NORMAL_STATE_ATTR( String::toStr( getForegroundRadius() ) );
|
|
setForegroundRadius( attribute.asUint() );
|
|
break;
|
|
case PropertyId::ForegroundSize:
|
|
setForegroundSize( attribute.value(), 0 );
|
|
break;
|
|
case PropertyId::BorderColor:
|
|
SAVE_NORMAL_STATE_ATTR( getBorderColor().toHexString() )
|
|
setBorderColor( attribute.asColor() );
|
|
break;
|
|
case PropertyId::BorderWidth:
|
|
SAVE_NORMAL_STATE_ATTR( String::toStr( getBorderWidth() ) );
|
|
setBorderWidth( attribute.asDpDimensionI("1") );
|
|
break;
|
|
case PropertyId::BorderRadius:
|
|
SAVE_NORMAL_STATE_ATTR( String::format( "%d", getBorderRadius() ) );
|
|
setBorderRadius( PixelDensity::dpToPxI( attribute.asDpDimensionUint() ));
|
|
break;
|
|
case PropertyId::Visible:
|
|
SAVE_NORMAL_STATE_ATTR( isVisible() ? "true" : "false" );
|
|
setVisible( attribute.asBool() );
|
|
break;
|
|
case PropertyId::Enabled:
|
|
SAVE_NORMAL_STATE_ATTR( isEnabled() ? "true" : "false" );
|
|
setEnabled( attribute.asBool() );
|
|
break;
|
|
case PropertyId::Theme:
|
|
if ( NULL != mTheme ) SAVE_NORMAL_STATE_ATTR( mTheme->getName() );
|
|
setThemeByName( attribute.asString() );
|
|
if ( !mSkinName.empty() ) setThemeSkin( mSkinName );
|
|
break;
|
|
case PropertyId::Skin:
|
|
SAVE_NORMAL_STATE_ATTR( mSkinName );
|
|
mSkinName = attribute.asString();
|
|
setThemeSkin( mSkinName );
|
|
break;
|
|
case PropertyId::SkinColor:
|
|
SAVE_NORMAL_STATE_ATTR( getSkinColor().toHexString() );
|
|
setSkinColor( attribute.asColor() );
|
|
break;
|
|
case PropertyId::Gravity:
|
|
{
|
|
std::string gravity = attribute.asString();
|
|
String::toLowerInPlace( gravity );
|
|
std::vector<std::string> strings = String::split( gravity, '|' );
|
|
|
|
if ( strings.size() ) {
|
|
for ( std::size_t i = 0; i < strings.size(); i++ ) {
|
|
std::string cur = strings[i];
|
|
String::toLowerInPlace( cur );
|
|
|
|
if ( "left" == cur )
|
|
setHorizontalAlign( UI_HALIGN_LEFT );
|
|
else if ( "right" == cur )
|
|
setHorizontalAlign( UI_HALIGN_RIGHT );
|
|
else if ( "center_horizontal" == cur )
|
|
setHorizontalAlign( UI_HALIGN_CENTER );
|
|
else if ( "top" == cur )
|
|
setVerticalAlign( UI_VALIGN_TOP );
|
|
else if ( "bottom" == cur )
|
|
setVerticalAlign( UI_VALIGN_BOTTOM );
|
|
else if ( "center_vertical" == cur ) {
|
|
setVerticalAlign( UI_VALIGN_CENTER );
|
|
} else if ( "center" == cur ) {
|
|
setHorizontalAlign( UI_HALIGN_CENTER );
|
|
setVerticalAlign( UI_VALIGN_CENTER );
|
|
}
|
|
}
|
|
|
|
notifyLayoutAttrChange();
|
|
}
|
|
break;
|
|
}
|
|
case PropertyId::Flags:
|
|
{
|
|
SAVE_NORMAL_STATE_ATTR( getFlagsString() );
|
|
|
|
std::string flags = attribute.asString();
|
|
String::toLowerInPlace( flags );
|
|
std::vector<std::string> strings = String::split( flags, '|' );
|
|
|
|
if ( strings.size() ) {
|
|
for ( std::size_t i = 0; i < strings.size(); i++ ) {
|
|
std::string cur = strings[i];
|
|
String::toLowerInPlace( cur );
|
|
|
|
if ( "auto_size" == cur || "autosize" == cur ) {
|
|
setFlags( UI_AUTO_SIZE );
|
|
notifyLayoutAttrChange();
|
|
} else if ( "clip" == cur ) {
|
|
clipEnable();
|
|
} else if ( "multi" == cur ) {
|
|
setFlags( UI_MULTI_SELECT );
|
|
} else if ( "auto_padding" == cur || "autopadding" == cur ) {
|
|
setFlags( UI_AUTO_PADDING );
|
|
notifyLayoutAttrChange();
|
|
} else if ( "reportsizechangetochilds" == cur || "report_size_change_to_childs" == cur ) {
|
|
enableReportSizeChangeToChilds();
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case PropertyId::MarginLeft:
|
|
SAVE_NORMAL_STATE_ATTR( String::format( "%d", mLayoutMargin.Left ) );
|
|
setLayoutMarginLeft( attribute.asDpDimensionI() );
|
|
break;
|
|
case PropertyId::MarginRight:
|
|
SAVE_NORMAL_STATE_ATTR( String::format( "%d", mLayoutMargin.Right ) );
|
|
setLayoutMarginRight( attribute.asDpDimensionI() );
|
|
break;
|
|
case PropertyId::MarginTop:
|
|
SAVE_NORMAL_STATE_ATTR( String::format( "%d", mLayoutMargin.Top ) );
|
|
setLayoutMarginTop( attribute.asDpDimensionI() );
|
|
break;
|
|
case PropertyId::MarginBottom:
|
|
SAVE_NORMAL_STATE_ATTR( String::format( "%d", mLayoutMargin.Bottom ) );
|
|
setLayoutMarginBottom( attribute.asDpDimensionI() );
|
|
break;
|
|
case PropertyId::Tooltip:
|
|
setTooltipText( attribute.asString() );
|
|
break;
|
|
case PropertyId::LayoutWeight:
|
|
SAVE_NORMAL_STATE_ATTR( String::toStr( getLayoutWeight() ) );
|
|
setLayoutWeight( attribute.asFloat() );
|
|
break;
|
|
case PropertyId::LayoutGravity:
|
|
{
|
|
SAVE_NORMAL_STATE_ATTR( getLayoutGravityString() );
|
|
std::string gravityStr = attribute.asString();
|
|
String::toLowerInPlace( gravityStr );
|
|
std::vector<std::string> strings = String::split( gravityStr, '|' );
|
|
Uint32 gravity = 0;
|
|
if ( strings.size() ) {
|
|
for ( std::size_t i = 0; i < strings.size(); i++ ) {
|
|
std::string cur = strings[i];
|
|
String::toLowerInPlace( cur );
|
|
|
|
if ( "left" == cur )
|
|
gravity |= UI_HALIGN_LEFT;
|
|
else if ( "right" == cur )
|
|
gravity |= UI_HALIGN_RIGHT;
|
|
else if ( "center_horizontal" == cur )
|
|
gravity |= UI_HALIGN_CENTER;
|
|
else if ( "top" == cur )
|
|
gravity |= UI_VALIGN_TOP;
|
|
else if ( "bottom" == cur )
|
|
gravity |= UI_VALIGN_BOTTOM;
|
|
else if ( "center_vertical" == cur ) {
|
|
gravity |= UI_VALIGN_CENTER;
|
|
} else if ( "center" == cur ) {
|
|
gravity |= UI_VALIGN_CENTER | UI_HALIGN_CENTER;
|
|
}
|
|
}
|
|
|
|
setLayoutGravity( gravity );
|
|
}
|
|
break;
|
|
}
|
|
case PropertyId::LayoutWidth:
|
|
{
|
|
SAVE_NORMAL_STATE_ATTR( getLayoutWidthRulesString() );
|
|
|
|
std::string val = attribute.asString();
|
|
String::toLowerInPlace( val );
|
|
|
|
if ( "match_parent" == val || "match-parent" == val ) {
|
|
setLayoutWidthRules( MATCH_PARENT );
|
|
} else if ( "wrap_content" == val || "wrap-content" == val ) {
|
|
setLayoutWidthRules( WRAP_CONTENT );
|
|
} else if ( "fixed" == val ) {
|
|
setLayoutWidthRules( FIXED );
|
|
unsetFlags( UI_AUTO_SIZE );
|
|
} else {
|
|
unsetFlags( UI_AUTO_SIZE );
|
|
setLayoutWidthRules( FIXED );
|
|
setInternalWidth( PixelDensity::toDpFromStringI( val ) );
|
|
onSizeChange();
|
|
}
|
|
break;
|
|
}
|
|
case PropertyId::LayoutHeight:
|
|
{
|
|
SAVE_NORMAL_STATE_ATTR( getLayoutHeightRulesString() );
|
|
|
|
std::string val = attribute.asString();
|
|
String::toLowerInPlace( val );
|
|
|
|
if ( "match_parent" == val ) {
|
|
setLayoutHeightRules( MATCH_PARENT );
|
|
} else if ( "wrap_content" == val ) {
|
|
setLayoutHeightRules( WRAP_CONTENT );
|
|
} else if ( "fixed" == val ) {
|
|
setLayoutHeightRules( FIXED );
|
|
unsetFlags( UI_AUTO_SIZE );
|
|
} else {
|
|
unsetFlags( UI_AUTO_SIZE );
|
|
setLayoutHeightRules( FIXED );
|
|
setInternalHeight( PixelDensity::toDpFromStringI( val ) );
|
|
onSizeChange();
|
|
}
|
|
break;
|
|
}
|
|
case PropertyId::LayoutToBottomOf:
|
|
case PropertyId::LayoutToLeftOf:
|
|
case PropertyId::LayoutToRightOf:
|
|
case PropertyId::LayoutToTopOf:
|
|
{
|
|
LayoutPositionRules rule = NONE;
|
|
PropertyId layoutId = static_cast<PropertyId>( attribute.getPropertyDefinition()->getId() );
|
|
if ( layoutId == PropertyId::LayoutToLeftOf ) rule = LEFT_OF;
|
|
else if ( layoutId == PropertyId::LayoutToRightOf ) rule = RIGHT_OF;
|
|
else if ( layoutId == PropertyId::LayoutToTopOf ) rule = TOP_OF;
|
|
else if ( layoutId == PropertyId::LayoutToBottomOf ) rule = BOTTOM_OF;
|
|
std::string id = attribute.asString();
|
|
Node * control = getParent()->find( id );
|
|
if ( NULL != control && control->isWidget() ) {
|
|
UIWidget * widget = static_cast<UIWidget*>( control );
|
|
setLayoutPositionRule( rule, widget );
|
|
}
|
|
break;
|
|
}
|
|
case PropertyId::Clip:
|
|
SAVE_NORMAL_STATE_ATTR( isClipped() ? "true" : "false" );
|
|
if ( attribute.asBool() ) clipEnable();
|
|
else clipDisable();
|
|
break;
|
|
case PropertyId::Rotation:
|
|
SAVE_NORMAL_STATE_ATTR( String::format( "%2.f", mRotation ) )
|
|
setRotation( attribute.asFloat() );
|
|
break;
|
|
case PropertyId::Scale:
|
|
SAVE_NORMAL_STATE_ATTR( String::format( "%2.f, %2.f", mScale.x, mScale.y ) )
|
|
setScale( attribute.asVector2f() );
|
|
break;
|
|
case PropertyId::BlendMode:
|
|
// TODO: SAVE_NORMAL_STATE_ATTR
|
|
setBlendMode( attribute.asBlendMode() );
|
|
break;
|
|
case PropertyId::PaddingLeft:
|
|
SAVE_NORMAL_STATE_ATTR( String::format( "%2.f", mPadding.Left ) );
|
|
setPaddingLeft( attribute.asDpDimension() );
|
|
break;
|
|
case PropertyId::PaddingRight:
|
|
SAVE_NORMAL_STATE_ATTR( String::format( "%2.f", mPadding.Right ) );
|
|
setPaddingRight( attribute.asDpDimension() );
|
|
break;
|
|
case PropertyId::PaddingTop:
|
|
SAVE_NORMAL_STATE_ATTR( String::format( "%2.f", mPadding.Top ) );
|
|
setPaddingTop( attribute.asDpDimension() );
|
|
break;
|
|
case PropertyId::PaddingBottom:
|
|
SAVE_NORMAL_STATE_ATTR( String::format( "%2.f", mPadding.Bottom ) );
|
|
setPaddingBottom( attribute.asDpDimension() );
|
|
break;
|
|
case PropertyId::Opacity:
|
|
{
|
|
SAVE_NORMAL_STATE_ATTR( String::format( "%2.f", mAlpha ) )
|
|
Float alpha = eemin( attribute.asFloat() * 255.f, 255.f );
|
|
setAlpha( alpha );
|
|
setChildsAlpha( alpha );
|
|
break;
|
|
}
|
|
case PropertyId::Cursor:
|
|
SAVE_NORMAL_STATE_ATTR( "arrow" );
|
|
mSceneNode->setCursor( Cursor::fromName( attribute.getValue() ) );
|
|
break;
|
|
case PropertyId::BackgroundPosition:
|
|
SAVE_NORMAL_STATE_ATTR( getBackground()->getLayer(0)->getPositionEq() );
|
|
setBackgroundPosition( attribute.value(), 0 );
|
|
break;
|
|
case PropertyId::ForegroundPosition:
|
|
SAVE_NORMAL_STATE_ATTR( getForeground()->getLayer(0)->getPositionEq() );
|
|
setForegroundPosition( attribute.value(), 0 );
|
|
break;
|
|
case PropertyId::RotationOriginPoint:
|
|
SAVE_NORMAL_STATE_ATTR( getRotationOriginPoint().toString() );
|
|
setRotationOriginPoint( attribute.asOriginPoint() );
|
|
break;
|
|
case PropertyId::ScaleOriginPoint:
|
|
SAVE_NORMAL_STATE_ATTR( getScaleOriginPoint().toString() );
|
|
setScaleOriginPoint( attribute.asOriginPoint() );
|
|
break;
|
|
default:
|
|
attributeSet = false;
|
|
break;
|
|
}
|
|
|
|
return attributeSet;
|
|
}
|
|
|
|
void UIWidget::loadFromXmlNode( const pugi::xml_node& node ) {
|
|
beginAttributesTransaction();
|
|
|
|
for (pugi::xml_attribute_iterator ait = node.attributes_begin(); ait != node.attributes_end(); ++ait) {
|
|
StyleSheetProperty prop( ait->name(), ait->value() );
|
|
|
|
if ( prop.getShorthandDefinition() != NULL ) {
|
|
auto properties = ShorthandDefinition::parseShorthand( prop.getShorthandDefinition(), ait->value() );
|
|
|
|
for ( auto& property : properties )
|
|
applyProperty( property );
|
|
} else {
|
|
applyProperty( prop );
|
|
}
|
|
}
|
|
|
|
endAttributesTransaction();
|
|
}
|
|
|
|
std::string UIWidget::getLayoutWidthRulesString() const {
|
|
LayoutSizeRules rules = getLayoutWidthRules();
|
|
|
|
if ( rules == LayoutSizeRules::MATCH_PARENT ) return "match_parent";
|
|
else if ( rules == LayoutSizeRules::WRAP_CONTENT ) return "wrap_content";
|
|
return String::toStr( getSize().getHeight() ) + "dp";
|
|
}
|
|
|
|
std::string UIWidget::getLayoutHeightRulesString() const {
|
|
LayoutSizeRules rules = getLayoutHeightRules();
|
|
|
|
if ( rules == LayoutSizeRules::MATCH_PARENT ) return "match_parent";
|
|
else if ( rules == LayoutSizeRules::WRAP_CONTENT ) return "wrap_content";
|
|
return String::toStr( getSize().getHeight() ) + "dp";
|
|
}
|
|
|
|
static std::string getGravityStringFromUint( const Uint32& gravity ) {
|
|
std::vector<std::string> gravec;
|
|
|
|
if ( HAlignGet( gravity ) == UI_HALIGN_RIGHT ) {
|
|
gravec.push_back( "right" );
|
|
} else if ( HAlignGet( gravity ) == UI_HALIGN_CENTER ) {
|
|
gravec.push_back( "center_horizontal" );
|
|
} else {
|
|
gravec.push_back( "left" );
|
|
}
|
|
|
|
if ( VAlignGet( gravity ) == UI_VALIGN_BOTTOM ) {
|
|
gravec.push_back( "bottom" );
|
|
} else if ( VAlignGet( gravity ) == UI_VALIGN_CENTER ) {
|
|
gravec.push_back( "center_vertical" );
|
|
} else {
|
|
gravec.push_back( "top" );
|
|
}
|
|
|
|
return String::join( gravec, '|' );
|
|
}
|
|
|
|
std::string UIWidget::getLayoutGravityString() const {
|
|
return getGravityStringFromUint( getLayoutGravity() );
|
|
}
|
|
|
|
std::string UIWidget::getGravityString() const {
|
|
return getGravityStringFromUint( getHorizontalAlign() | getVerticalAlign() );
|
|
}
|
|
|
|
std::string UIWidget::getFlagsString() const {
|
|
std::vector<std::string> flagvec;
|
|
|
|
if ( mFlags & UI_AUTO_SIZE ) flagvec.push_back( "autosize" );
|
|
if ( mFlags & UI_MULTI_SELECT ) flagvec.push_back( "multi" );
|
|
if ( mFlags & UI_AUTO_PADDING ) flagvec.push_back( "autopadding" );
|
|
if ( reportSizeChangeToChilds() ) flagvec.push_back( "reportsizechangetochilds" );
|
|
if ( isClipped() ) flagvec.push_back( "clip" );
|
|
|
|
return String::join( flagvec, '|' );
|
|
}
|
|
|
|
bool UIWidget::drawablePropertySet(const std::string& propertyName, const std::string& value, std::function<void (Drawable*, bool, int)> funcSet) {
|
|
FunctionString functionType = FunctionString::parse( value );
|
|
Drawable * res = NULL;
|
|
int index = 0;
|
|
bool attributeSet = true;
|
|
|
|
if ( !functionType.isEmpty() ) {
|
|
if ( functionType.getName() == "linear-gradient" && functionType.getParameters().size() >= 2 ) {
|
|
RectangleDrawable * drawable = RectangleDrawable::New();
|
|
RectColors rectColors;
|
|
|
|
const std::vector<std::string>& params( functionType.getParameters() );
|
|
|
|
if ( Color::isColorString( params.at(0) ) && params.size() >= 2 ) {
|
|
rectColors.TopLeft = rectColors.TopRight = Color::fromString( params.at(0) );
|
|
rectColors.BottomLeft = rectColors.BottomRight = Color::fromString( params.at(1) );
|
|
} else if ( params.size() >= 3 ) {
|
|
std::string direction = params.at(0);
|
|
String::toLowerInPlace( direction );
|
|
|
|
if ( direction == "to bottom" ) {
|
|
rectColors.TopLeft = rectColors.TopRight = Color::fromString( params.at(1) );
|
|
rectColors.BottomLeft = rectColors.BottomRight = Color::fromString( params.at(2) );
|
|
} else if ( direction == "to left" ) {
|
|
rectColors.TopLeft = rectColors.BottomLeft = Color::fromString( params.at(2) );
|
|
rectColors.TopRight = rectColors.BottomRight = Color::fromString( params.at(1) );
|
|
} else if ( direction == "to right" ) {
|
|
rectColors.TopLeft = rectColors.BottomLeft = Color::fromString( params.at(1) );
|
|
rectColors.TopRight = rectColors.BottomRight = Color::fromString( params.at(2) );
|
|
} else if ( direction == "to top" ) {
|
|
rectColors.TopLeft = rectColors.TopRight = Color::fromString( params.at(2) );
|
|
rectColors.BottomLeft = rectColors.BottomRight = Color::fromString( params.at(1) );
|
|
} else {
|
|
rectColors.TopLeft = rectColors.TopRight = Color::fromString( params.at(1) );
|
|
rectColors.BottomLeft = rectColors.BottomRight = Color::fromString( params.at(2) );
|
|
}
|
|
} else {
|
|
return applyProperty( StyleSheetProperty( propertyName + "-color", params.at(0) ) );
|
|
}
|
|
|
|
drawable->setRectColors( rectColors );
|
|
|
|
funcSet( drawable, true, index );
|
|
} else if ( functionType.getName() == "url" && functionType.getParameters().size() >= 1 ) {
|
|
if ( NULL != ( res = DrawableSearcher::searchByName( functionType.getParameters().at(0) ) ) ) {
|
|
funcSet( res, res->getDrawableType() == Drawable::SPRITE, index );
|
|
}
|
|
}
|
|
} else if ( NULL != ( res = DrawableSearcher::searchByName( value ) ) ) {
|
|
funcSet( res, res->getDrawableType() == Drawable::SPRITE, index );
|
|
} else {
|
|
attributeSet = false;
|
|
}
|
|
|
|
return attributeSet;
|
|
}
|
|
|
|
}}
|