mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-05-29 09:36:29 +03:00
1873 lines
50 KiB
C++
1873 lines
50 KiB
C++
#include <eepp/graphics/font.hpp>
|
|
#include <eepp/graphics/globalbatchrenderer.hpp>
|
|
#include <eepp/graphics/primitives.hpp>
|
|
#include <eepp/graphics/renderer/renderer.hpp>
|
|
#include <eepp/graphics/textureregion.hpp>
|
|
#include <eepp/scene/action.hpp>
|
|
#include <eepp/scene/actionmanager.hpp>
|
|
#include <eepp/scene/actions/fade.hpp>
|
|
#include <eepp/scene/actions/move.hpp>
|
|
#include <eepp/scene/actions/rotate.hpp>
|
|
#include <eepp/scene/actions/scale.hpp>
|
|
#include <eepp/scene/scenemanager.hpp>
|
|
#include <eepp/scene/scenenode.hpp>
|
|
#include <eepp/ui/css/stylesheetspecification.hpp>
|
|
#include <eepp/ui/uiborderdrawable.hpp>
|
|
#include <eepp/ui/uinode.hpp>
|
|
#include <eepp/ui/uinodedrawable.hpp>
|
|
#include <eepp/ui/uiscenenode.hpp>
|
|
#include <eepp/ui/uiskin.hpp>
|
|
#include <eepp/ui/uiskinstate.hpp>
|
|
#include <eepp/ui/uistate.hpp>
|
|
#include <eepp/ui/uitheme.hpp>
|
|
#include <eepp/ui/uithememanager.hpp>
|
|
#include <eepp/ui/uiwindow.hpp>
|
|
#include <eepp/window/engine.hpp>
|
|
|
|
namespace EE { namespace UI {
|
|
|
|
UINode* UINode::New() {
|
|
return eeNew( UINode, () );
|
|
}
|
|
|
|
UINode::UINode() :
|
|
Node(),
|
|
mFlags( UI_NODE_DEFAULT_FLAGS ),
|
|
mState( UIState::StateFlagNormal ),
|
|
mSkinState( NULL ),
|
|
mBackground( NULL ),
|
|
mForeground( NULL ),
|
|
mBorder( NULL ),
|
|
mDragButton( EE_BUTTON_LMASK ),
|
|
mSkinColor( Color::White ),
|
|
mUISceneNode( SceneManager::instance()->getUISceneNode() ) {
|
|
mNodeFlags |= NODE_FLAG_UINODE | NODE_FLAG_OVER_FIND_ALLOWED;
|
|
|
|
if ( NULL != mUISceneNode )
|
|
setParent( (Node*)mUISceneNode->getRoot() );
|
|
}
|
|
|
|
UINode::~UINode() {
|
|
removeSkin();
|
|
|
|
eeSAFE_DELETE( mBackground );
|
|
eeSAFE_DELETE( mForeground );
|
|
eeSAFE_DELETE( mBorder );
|
|
|
|
if ( isDragging() && getEventDispatcher() )
|
|
getEventDispatcher()->setNodeDragging( NULL );
|
|
}
|
|
|
|
void UINode::worldToNodeTranslation( Vector2f& Pos ) const {
|
|
Node* ParentLoop = mParentNode;
|
|
|
|
Pos -= mPosition;
|
|
|
|
while ( NULL != ParentLoop ) {
|
|
const Vector2f& ParentPos = ParentLoop->isUINode()
|
|
? ParentLoop->asType<UINode>()->getPixelsPosition()
|
|
: ParentLoop->getPosition();
|
|
|
|
Pos -= ParentPos;
|
|
|
|
ParentLoop = ParentLoop->getParent();
|
|
}
|
|
}
|
|
|
|
void UINode::nodeToWorldTranslation( Vector2f& Pos ) const {
|
|
Node* ParentLoop = mParentNode;
|
|
|
|
while ( NULL != ParentLoop ) {
|
|
const Vector2f& ParentPos = ParentLoop->isUINode()
|
|
? ParentLoop->asType<UINode>()->getPixelsPosition()
|
|
: ParentLoop->getPosition();
|
|
|
|
Pos += ParentPos;
|
|
|
|
ParentLoop = ParentLoop->getParent();
|
|
}
|
|
}
|
|
|
|
Uint32 UINode::getType() const {
|
|
return UI_TYPE_UINODE;
|
|
}
|
|
|
|
bool UINode::isType( const Uint32& type ) const {
|
|
return UINode::getType() == type || Node::isType( type );
|
|
}
|
|
|
|
void UINode::setInternalPosition( const Vector2f& Pos ) {
|
|
mDpPos = Pos;
|
|
Transformable::setPosition( PixelDensity::dpToPx( Pos ) );
|
|
setDirty();
|
|
}
|
|
|
|
void UINode::setPosition( const Vector2f& Pos ) {
|
|
if ( Pos != mDpPos ) {
|
|
setInternalPosition( Pos );
|
|
onPositionChange();
|
|
}
|
|
}
|
|
|
|
Node* UINode::setPosition( const Float& x, const Float& y ) {
|
|
setPosition( Vector2f( x, y ) );
|
|
return this;
|
|
}
|
|
|
|
UINode* UINode::setPixelsPosition( const Vector2f& Pos ) {
|
|
if ( mPosition != Pos ) {
|
|
mDpPos = PixelDensity::pxToDp( Pos );
|
|
Transformable::setPosition( Pos );
|
|
setDirty();
|
|
onPositionChange();
|
|
}
|
|
return this;
|
|
}
|
|
|
|
UINode* UINode::setPixelsPosition( const Float& x, const Float& y ) {
|
|
setPixelsPosition( Vector2f( x, y ) );
|
|
return this;
|
|
}
|
|
|
|
const Vector2f& UINode::getPosition() const {
|
|
return mDpPos;
|
|
}
|
|
|
|
const Vector2f& UINode::getPixelsPosition() const {
|
|
return mPosition;
|
|
}
|
|
|
|
void UINode::setInternalSize( const Sizef& size ) {
|
|
Sizef s( fitMinMaxSizeDp( size ) );
|
|
|
|
if ( s != mDpSize ) {
|
|
mDpSize = s;
|
|
mSize = PixelDensity::dpToPx( s );
|
|
mNodeFlags |= NODE_FLAG_POLYGON_DIRTY;
|
|
updateCenter();
|
|
onSizeChange();
|
|
sendCommonEvent( Event::OnSizeChange );
|
|
invalidateDraw();
|
|
}
|
|
}
|
|
|
|
void UINode::setInternalPixelsSize( const Sizef& size ) {
|
|
Sizef s( fitMinMaxSizePx( size ) );
|
|
|
|
if ( s != mSize ) {
|
|
mDpSize = PixelDensity::pxToDp( s ).ceil();
|
|
mSize = s;
|
|
mNodeFlags |= NODE_FLAG_POLYGON_DIRTY;
|
|
updateCenter();
|
|
onSizeChange();
|
|
sendCommonEvent( Event::OnSizeChange );
|
|
invalidateDraw();
|
|
}
|
|
}
|
|
|
|
Node* UINode::setSize( const Sizef& size ) {
|
|
Sizef s( fitMinMaxSizeDp( size ) );
|
|
|
|
if ( s != mDpSize ) {
|
|
Vector2f sizeChange( s.x - mDpSize.x, s.y - mDpSize.y );
|
|
|
|
setInternalSize( s );
|
|
|
|
if ( reportSizeChangeToChildren() ) {
|
|
sendParentSizeChange( sizeChange );
|
|
}
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
Node* UINode::setSize( const Float& Width, const Float& Height ) {
|
|
return setSize( Vector2f( Width, Height ) );
|
|
}
|
|
|
|
UINode* UINode::setPixelsSize( const Sizef& size ) {
|
|
Sizef s( fitMinMaxSizePx( size ) );
|
|
Sizef pMinSize( PixelDensity::dpToPx( mMinSize ) );
|
|
|
|
if ( s.x < pMinSize.x )
|
|
s.x = pMinSize.x;
|
|
|
|
if ( s.y < pMinSize.y )
|
|
s.y = pMinSize.y;
|
|
|
|
if ( s != mSize ) {
|
|
Vector2f sizeChange( s.x - mSize.x, s.y - mSize.y );
|
|
|
|
setInternalPixelsSize( s );
|
|
|
|
if ( reportSizeChangeToChildren() ) {
|
|
sendParentSizeChange( PixelDensity::pxToDp( sizeChange ) );
|
|
}
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
UINode* UINode::setPixelsSize( const Float& x, const Float& y ) {
|
|
return setPixelsSize( Sizef( x, y ) );
|
|
}
|
|
|
|
void UINode::setInternalPixelsWidth( const Float& width ) {
|
|
setInternalPixelsSize( Sizef( width, mSize.y ) );
|
|
}
|
|
|
|
void UINode::setInternalPixelsHeight( const Float& height ) {
|
|
setInternalPixelsSize( Sizef( mSize.x, height ) );
|
|
}
|
|
|
|
void UINode::setMinSize( const Sizef& size ) {
|
|
if ( size != mMinSize ) {
|
|
mMinSize = size;
|
|
setSize( getSize() );
|
|
}
|
|
}
|
|
|
|
void UINode::setMinWidth( const Float& width ) {
|
|
if ( width != mMinSize.x ) {
|
|
mMinSize.x = width;
|
|
setSize( getSize() );
|
|
}
|
|
}
|
|
|
|
void UINode::setMinHeight( const Float& height ) {
|
|
if ( height != mMinSize.y ) {
|
|
mMinSize.y = height;
|
|
setSize( getSize() );
|
|
}
|
|
}
|
|
|
|
const Sizef& UINode::getCurMinSize() const {
|
|
return mMinSize;
|
|
}
|
|
|
|
const std::string& UINode::getMinWidthEq() const {
|
|
return mMinWidthEq;
|
|
}
|
|
|
|
void UINode::setMinSizeEq( const std::string& minWidthEq, const std::string& minHeightEq ) {
|
|
if ( mMinWidthEq != minWidthEq || mMinHeightEq != minHeightEq ) {
|
|
mMinWidthEq = minWidthEq;
|
|
mMinHeightEq = minHeightEq;
|
|
|
|
if ( !mMinWidthEq.empty() ) {
|
|
mMinSize.x =
|
|
lengthFromValueAsDp( mMinWidthEq, PropertyRelativeTarget::ContainingBlockWidth );
|
|
}
|
|
|
|
if ( !mMinHeightEq.empty() ) {
|
|
mMinSize.y =
|
|
lengthFromValueAsDp( mMinHeightEq, PropertyRelativeTarget::ContainingBlockHeight );
|
|
}
|
|
|
|
setSize( mDpSize );
|
|
}
|
|
}
|
|
|
|
void UINode::setMinWidthEq( const std::string& minWidthEq ) {
|
|
if ( mMinWidthEq != minWidthEq ) {
|
|
mMinWidthEq = minWidthEq;
|
|
|
|
if ( !mMinWidthEq.empty() ) {
|
|
mMinSize.x =
|
|
lengthFromValueAsDp( mMinWidthEq, PropertyRelativeTarget::ContainingBlockWidth );
|
|
}
|
|
|
|
setSize( mDpSize );
|
|
}
|
|
}
|
|
|
|
const std::string& UINode::getMinHeightEq() const {
|
|
return mMinHeightEq;
|
|
}
|
|
|
|
void UINode::setMinHeightEq( const std::string& minHeightEq ) {
|
|
if ( mMinHeightEq != minHeightEq ) {
|
|
mMinHeightEq = minHeightEq;
|
|
|
|
if ( !mMinHeightEq.empty() ) {
|
|
mMinSize.y =
|
|
lengthFromValueAsDp( mMinHeightEq, PropertyRelativeTarget::ContainingBlockHeight );
|
|
}
|
|
|
|
setSize( mDpSize );
|
|
}
|
|
}
|
|
|
|
const std::string& UINode::getMaxWidthEq() const {
|
|
return mMaxWidthEq;
|
|
}
|
|
|
|
void UINode::setMaxSizeEq( const std::string& maxWidthEq, const std::string& maxHeightEq ) {
|
|
if ( mMaxWidthEq != maxWidthEq || mMaxHeightEq != maxHeightEq ) {
|
|
mMaxWidthEq = maxWidthEq;
|
|
mMaxHeightEq = maxHeightEq;
|
|
if ( mMaxWidthEq == "none" )
|
|
mMaxWidthEq.clear();
|
|
if ( mMaxHeightEq == "none" )
|
|
mMaxHeightEq.clear();
|
|
setSize( mDpSize );
|
|
}
|
|
}
|
|
|
|
void UINode::setMaxWidthEq( const std::string& maxWidthEq ) {
|
|
if ( mMaxWidthEq != maxWidthEq ) {
|
|
mMaxWidthEq = maxWidthEq;
|
|
if ( mMaxWidthEq == "none" )
|
|
mMaxWidthEq.clear();
|
|
onSizeChange();
|
|
}
|
|
}
|
|
|
|
const std::string& UINode::getMaxHeightEq() const {
|
|
return mMaxHeightEq;
|
|
}
|
|
|
|
void UINode::setMaxHeightEq( const std::string& maxHeightEq ) {
|
|
if ( mMaxHeightEq != maxHeightEq ) {
|
|
mMaxHeightEq = maxHeightEq;
|
|
if ( mMaxHeightEq == "none" )
|
|
mMaxHeightEq.clear();
|
|
onSizeChange();
|
|
}
|
|
}
|
|
|
|
Sizef UINode::getMaxSize() const {
|
|
Sizef s;
|
|
|
|
if ( !mMaxWidthEq.empty() ) {
|
|
Float length =
|
|
lengthFromValueAsDp( mMaxWidthEq, PropertyRelativeTarget::ContainingBlockWidth );
|
|
s.x = eemax( s.x, length );
|
|
}
|
|
|
|
if ( !mMaxHeightEq.empty() ) {
|
|
Float length =
|
|
lengthFromValueAsDp( mMaxHeightEq, PropertyRelativeTarget::ContainingBlockHeight );
|
|
s.y = eemax( s.y, length );
|
|
}
|
|
|
|
return s;
|
|
}
|
|
|
|
Sizef UINode::getMaxSizePx() const {
|
|
Sizef s;
|
|
|
|
if ( !mMaxWidthEq.empty() ) {
|
|
Float length = lengthFromValue( mMaxWidthEq, PropertyRelativeTarget::ContainingBlockWidth );
|
|
s.x = eemax( s.x, length );
|
|
}
|
|
|
|
if ( !mMaxHeightEq.empty() ) {
|
|
Float length =
|
|
lengthFromValue( mMaxHeightEq, PropertyRelativeTarget::ContainingBlockHeight );
|
|
s.y = eemax( s.y, length );
|
|
}
|
|
|
|
return s;
|
|
}
|
|
|
|
Sizef UINode::getMinSize() const {
|
|
Sizef s;
|
|
|
|
if ( !mMinWidthEq.empty() ) {
|
|
Float length =
|
|
lengthFromValueAsDp( mMinWidthEq, PropertyRelativeTarget::ContainingBlockWidth );
|
|
s.x = eemax( s.x, length );
|
|
}
|
|
|
|
if ( !mMinHeightEq.empty() ) {
|
|
Float length =
|
|
lengthFromValueAsDp( mMinHeightEq, PropertyRelativeTarget::ContainingBlockHeight );
|
|
s.y = eemax( s.y, length );
|
|
}
|
|
|
|
return s;
|
|
}
|
|
|
|
Sizef UINode::getMinSizePx() const {
|
|
Sizef s;
|
|
|
|
if ( !mMinWidthEq.empty() ) {
|
|
Float length = lengthFromValue( mMinWidthEq, PropertyRelativeTarget::ContainingBlockWidth );
|
|
s.x = eemax( s.x, length );
|
|
}
|
|
|
|
if ( !mMinHeightEq.empty() ) {
|
|
Float length =
|
|
lengthFromValue( mMinHeightEq, PropertyRelativeTarget::ContainingBlockHeight );
|
|
s.y = eemax( s.y, length );
|
|
}
|
|
|
|
return s;
|
|
}
|
|
|
|
Sizef UINode::fitMinMaxSizePx( const Sizef& size ) const {
|
|
Sizef s( size );
|
|
|
|
if ( mMinSize.x != 0.f )
|
|
s.x = std::max( s.x, PixelDensity::dpToPx( mMinSize.x ) );
|
|
|
|
if ( mMinSize.y != 0.f )
|
|
s.y = std::max( s.y, PixelDensity::dpToPx( mMinSize.y ) );
|
|
|
|
if ( !mMinWidthEq.empty() ) {
|
|
Float length = lengthFromValue( mMinWidthEq, PropertyRelativeTarget::ContainingBlockWidth );
|
|
s.x = eemax( s.x, length );
|
|
}
|
|
|
|
if ( !mMinHeightEq.empty() ) {
|
|
Float length =
|
|
lengthFromValue( mMinHeightEq, PropertyRelativeTarget::ContainingBlockHeight );
|
|
s.y = eemax( s.y, length );
|
|
}
|
|
|
|
if ( !mMaxWidthEq.empty() ) {
|
|
Float length = lengthFromValue( mMaxWidthEq, PropertyRelativeTarget::ContainingBlockWidth );
|
|
s.x = eemin( s.x, length );
|
|
}
|
|
|
|
if ( !mMaxHeightEq.empty() ) {
|
|
Float length =
|
|
lengthFromValue( mMaxHeightEq, PropertyRelativeTarget::ContainingBlockHeight );
|
|
s.y = eemin( s.y, length );
|
|
}
|
|
|
|
return s;
|
|
}
|
|
|
|
bool UINode::isScrollable() const {
|
|
return 0 != ( mFlags & UI_SCROLLABLE );
|
|
}
|
|
|
|
Sizef UINode::fitMinMaxSizeDp( const Sizef& size ) const {
|
|
Sizef s( size );
|
|
|
|
s.x = std::max( s.x, mMinSize.x );
|
|
s.y = std::max( s.y, mMinSize.y );
|
|
|
|
if ( !mMinWidthEq.empty() ) {
|
|
Float length =
|
|
lengthFromValueAsDp( mMinWidthEq, PropertyRelativeTarget::ContainingBlockWidth );
|
|
s.x = eemax( s.x, length );
|
|
}
|
|
|
|
if ( !mMinHeightEq.empty() ) {
|
|
Float length =
|
|
lengthFromValueAsDp( mMinHeightEq, PropertyRelativeTarget::ContainingBlockHeight );
|
|
s.y = eemax( s.y, length );
|
|
}
|
|
|
|
if ( !mMaxWidthEq.empty() ) {
|
|
Float length =
|
|
lengthFromValueAsDp( mMaxWidthEq, PropertyRelativeTarget::ContainingBlockWidth );
|
|
s.x = eemin( s.x, length );
|
|
}
|
|
|
|
if ( !mMaxHeightEq.empty() ) {
|
|
Float length =
|
|
lengthFromValueAsDp( mMaxHeightEq, PropertyRelativeTarget::ContainingBlockHeight );
|
|
s.y = eemin( s.y, length );
|
|
}
|
|
|
|
return s;
|
|
}
|
|
|
|
void UINode::updateOriginPoint() {
|
|
Node::updateOriginPoint();
|
|
|
|
if ( mRotationOriginPoint.OriginType == OriginPoint::OriginEquation ) {
|
|
if ( !mRotationOriginPoint.getXEq().empty() ) {
|
|
mRotationOriginPoint.x = lengthFromValue( mRotationOriginPoint.getXEq(),
|
|
PropertyRelativeTarget::LocalBlockWidth );
|
|
}
|
|
|
|
if ( !mRotationOriginPoint.getYEq().empty() ) {
|
|
mRotationOriginPoint.y = lengthFromValue( mRotationOriginPoint.getYEq(),
|
|
PropertyRelativeTarget::LocalBlockHeight );
|
|
}
|
|
|
|
Transformable::setRotationOrigin( getRotationOriginPoint().x, getRotationOriginPoint().y );
|
|
}
|
|
|
|
if ( mScaleOriginPoint.OriginType == OriginPoint::OriginEquation ) {
|
|
if ( !mScaleOriginPoint.getXEq().empty() ) {
|
|
mScaleOriginPoint.x = lengthFromValue( mScaleOriginPoint.getXEq(),
|
|
PropertyRelativeTarget::LocalBlockWidth );
|
|
}
|
|
|
|
if ( !mScaleOriginPoint.getYEq().empty() ) {
|
|
mScaleOriginPoint.y = lengthFromValue( mScaleOriginPoint.getYEq(),
|
|
PropertyRelativeTarget::LocalBlockHeight );
|
|
}
|
|
|
|
Transformable::setScaleOrigin( getScaleOriginPoint().x, getScaleOriginPoint().y );
|
|
}
|
|
}
|
|
|
|
Rect UINode::getRect() const {
|
|
return Rect( Vector2i( mDpPos.x, mDpPos.y ), Sizei( mDpSize.x, mDpSize.y ) );
|
|
}
|
|
|
|
Rectf UINode::getRectBox() const {
|
|
return Rectf( mPosition, mSize );
|
|
}
|
|
|
|
const Sizef& UINode::getSize() const {
|
|
return mDpSize;
|
|
}
|
|
|
|
void UINode::drawHighlightFocus() {
|
|
if ( ( mFlags & UI_HIGHLIGHT ) ||
|
|
( NULL != getEventDispatcher() && mSceneNode->getHighlightFocus() &&
|
|
getEventDispatcher()->getFocusNode() == this ) ) {
|
|
Primitives P;
|
|
P.setFillMode( DRAW_LINE );
|
|
P.setBlendMode( getBlendMode() );
|
|
P.setColor( mSceneNode->getHighlightFocusColor() );
|
|
P.setLineWidth( PixelDensity::dpToPxI( 1 ) );
|
|
P.drawRectangle( getScreenBounds() );
|
|
}
|
|
}
|
|
|
|
void UINode::drawOverNode() {
|
|
if ( NULL != getEventDispatcher() && mSceneNode->getHighlightOver() &&
|
|
getEventDispatcher()->getMouseOverNode() == this ) {
|
|
Primitives P;
|
|
P.setFillMode( DRAW_LINE );
|
|
P.setBlendMode( getBlendMode() );
|
|
P.setColor( mSceneNode->getHighlightOverColor() );
|
|
P.setLineWidth( PixelDensity::dpToPxI( 1 ) );
|
|
P.drawRectangle( getScreenBounds() );
|
|
}
|
|
}
|
|
|
|
void UINode::drawDroppableHovering() {
|
|
Primitives P;
|
|
P.setFillMode( DRAW_FILL );
|
|
P.setBlendMode( getBlendMode() );
|
|
P.setColor( getDroppableHoveringColor() );
|
|
P.setLineWidth( PixelDensity::dpToPxI( 1 ) );
|
|
P.drawRectangle( getScreenBounds() );
|
|
}
|
|
|
|
void UINode::updateDebugData() {
|
|
if ( NULL != mSceneNode && mSceneNode->getDrawDebugData() && isWidget() &&
|
|
NULL != getEventDispatcher() && getEventDispatcher()->getMouseOverNode() == this ) {
|
|
UIWidget* widget = asType<UIWidget>();
|
|
|
|
String text = "Tag: " + String::fromUtf8( widget->getStyleSheetTag() ) + "\n";
|
|
|
|
if ( !mId.empty() ) {
|
|
text += "ID: " + mId + "\n";
|
|
}
|
|
|
|
if ( !widget->getStyleSheetClasses().empty() ) {
|
|
text += "Classes: " + String::join( widget->getStyleSheetClasses(), ' ' ) + "\n";
|
|
}
|
|
|
|
if ( widget->getStyleSheetPseudoClasses() ) {
|
|
text += "Pseudo Classes: " +
|
|
String::join( widget->getStyleSheetPseudoClassesStrings(), ' ' ) + "\n";
|
|
}
|
|
|
|
text += String::format(
|
|
"X: %.2fpx (%.2fdp) Y: %.2fpx (%.2fdp)\nW: %.2fpx (%.2fdp) H: %.2fpx (%.2fdp)",
|
|
mPosition.x, mDpPos.x, mPosition.y, mDpPos.y, mSize.x, mDpSize.x, mSize.y, mDpSize.y );
|
|
|
|
if ( widget->getPadding() != Rectf( 0, 0, 0, 0 ) ) {
|
|
Rectf p( widget->getPadding() );
|
|
text += String::format( "\npadding: %.2f %.2f %.2f %.2f", p.Top, p.Right, p.Bottom,
|
|
p.Left );
|
|
}
|
|
|
|
if ( widget->getLayoutMargin() != Rectf( 0, 0, 0, 0 ) ) {
|
|
Rectf m( widget->getLayoutMargin() );
|
|
text +=
|
|
String::format( "\nmargin: %.2f %.2f %.2f %.2f", m.Top, m.Right, m.Bottom, m.Left );
|
|
}
|
|
|
|
widget->setTooltipText( text );
|
|
}
|
|
}
|
|
|
|
void UINode::drawBox() {
|
|
if ( NULL != mSceneNode && mSceneNode->getDrawBoxes() ) {
|
|
Primitives P;
|
|
P.setFillMode( DRAW_LINE );
|
|
P.setBlendMode( getBlendMode() );
|
|
P.setColor( Color::fromPointer( this ) );
|
|
P.setLineWidth( PixelDensity::dpToPxI( 1 ) );
|
|
P.drawRectangle( getScreenBounds() );
|
|
}
|
|
}
|
|
|
|
void UINode::drawSkin() {
|
|
if ( NULL != mSkinState ) {
|
|
mSkinState->setStateColor( mSkinState->getCurrentState(), mSkinColor );
|
|
|
|
if ( mFlags & UI_SKIN_KEEP_SIZE_ON_DRAW ) {
|
|
Sizef rSize =
|
|
PixelDensity::dpToPx( getSkinSize( getSkin(), mSkinState->getCurrentState() ) );
|
|
Sizef diff = ( mSize - rSize ) * 0.5f;
|
|
|
|
mSkinState->draw( std::trunc( mScreenPos.x ) + eefloor( diff.x ),
|
|
std::trunc( mScreenPos.y ) + eefloor( diff.y ),
|
|
eefloor( rSize.getWidth() ), eefloor( rSize.getHeight() ),
|
|
(Uint32)mAlpha );
|
|
} else {
|
|
mSkinState->draw( std::trunc( mScreenPos.x ), std::trunc( mScreenPos.y ),
|
|
eefloor( mSize.getWidth() ), eefloor( mSize.getHeight() ),
|
|
(Uint32)mAlpha );
|
|
}
|
|
}
|
|
}
|
|
|
|
void UINode::draw() {}
|
|
|
|
Uint32 UINode::onMouseDown( const Vector2i& position, const Uint32& flags ) {
|
|
if ( NULL != getEventDispatcher() && !getEventDispatcher()->isNodeDragging() &&
|
|
!( getEventDispatcher()->getLastPressTrigger() & mDragButton ) &&
|
|
( flags & mDragButton ) && isDragEnabled() && !isDragging() ) {
|
|
startDragging( position.asFloat() );
|
|
}
|
|
|
|
pushState( UIState::StatePressed );
|
|
|
|
return Node::onMouseDown( position, flags );
|
|
}
|
|
|
|
Uint32 UINode::onMouseUp( const Vector2i& Pos, const Uint32& Flags ) {
|
|
if ( isDragEnabled() && isDragging() && ( Flags & mDragButton ) ) {
|
|
setDragging( false );
|
|
|
|
if ( NULL != getEventDispatcher() )
|
|
getEventDispatcher()->setNodeDragging( NULL );
|
|
}
|
|
|
|
popState( UIState::StatePressed );
|
|
|
|
return Node::onMouseUp( Pos, Flags );
|
|
}
|
|
|
|
Uint32 UINode::onCalculateDrag( const Vector2f& position, const Uint32& flags ) {
|
|
if ( isDragEnabled() && isDragging() && NULL != getEventDispatcher() ) {
|
|
EventDispatcher* eventDispatcher = getEventDispatcher();
|
|
|
|
if ( !( flags /*press trigger*/ & mDragButton ) ) {
|
|
setDragging( false );
|
|
eventDispatcher->setNodeDragging( NULL );
|
|
return 1;
|
|
}
|
|
|
|
Vector2f pos( eefloor( position.x ), eefloor( position.y ) );
|
|
if ( mDragPoint != pos && ( std::abs( mDragPoint.x - pos.x ) > 1.f ||
|
|
std::abs( mDragPoint.y - pos.y ) > 1.f ) ) {
|
|
Sizef dragDiff;
|
|
dragDiff.x = ( mFlags & UI_DRAG_HORIZONTAL ) ? (Float)( mDragPoint.x - pos.x ) : 0;
|
|
dragDiff.y = ( mFlags & UI_DRAG_VERTICAL ) ? (Float)( mDragPoint.y - pos.y ) : 0;
|
|
|
|
if ( onDrag( pos, flags, dragDiff ) ) {
|
|
setPixelsPosition( mPosition - dragDiff );
|
|
mDragPoint = pos;
|
|
eventDispatcher->setNodeDragging( this );
|
|
}
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
Uint32 UINode::onValueChange() {
|
|
sendCommonEvent( Event::OnValueChange );
|
|
invalidateDraw();
|
|
return 1;
|
|
}
|
|
|
|
Uint32 UINode::getHorizontalAlign() const {
|
|
return mFlags & UI_HALIGN_MASK;
|
|
}
|
|
|
|
UINode* UINode::setHorizontalAlign( Uint32 halign ) {
|
|
mFlags &= ~UI_HALIGN_MASK;
|
|
mFlags |= halign & UI_HALIGN_MASK;
|
|
|
|
onAlignChange();
|
|
return this;
|
|
}
|
|
|
|
Uint32 UINode::getVerticalAlign() const {
|
|
return mFlags & UI_VALIGN_MASK;
|
|
}
|
|
|
|
UINode* UINode::setVerticalAlign( Uint32 valign ) {
|
|
mFlags &= ~UI_VALIGN_MASK;
|
|
mFlags |= valign & UI_VALIGN_MASK;
|
|
|
|
onAlignChange();
|
|
return this;
|
|
}
|
|
|
|
UINode* UINode::setGravity( Uint32 hvalign ) {
|
|
mFlags &= ~( UI_VALIGN_MASK | UI_HALIGN_MASK );
|
|
mFlags |= ( hvalign & ( UI_VALIGN_MASK | UI_HALIGN_MASK ) );
|
|
|
|
onAlignChange();
|
|
return this;
|
|
}
|
|
|
|
UINodeDrawable* UINode::setBackgroundFillEnabled( bool enabled ) {
|
|
writeFlag( UI_FILL_BACKGROUND, enabled ? 1 : 0 );
|
|
|
|
if ( enabled && NULL == mBackground ) {
|
|
getBackground();
|
|
}
|
|
|
|
invalidateDraw();
|
|
|
|
return mBackground;
|
|
}
|
|
|
|
UINode* UINode::setBackgroundDrawable( Drawable* drawable, bool ownIt, int index ) {
|
|
setBackgroundFillEnabled( true )->setDrawable( index, drawable, ownIt );
|
|
return this;
|
|
}
|
|
|
|
UINode* UINode::setBackgroundDrawable( const std::string& drawable, int index ) {
|
|
setBackgroundFillEnabled( true )->setDrawable( index, drawable );
|
|
return this;
|
|
}
|
|
|
|
UINode* UINode::setBackgroundColor( const Color& color ) {
|
|
setBackgroundFillEnabled( true )->setBackgroundColor( color );
|
|
return this;
|
|
}
|
|
|
|
UINode* UINode::setBackgroundTint( const Color& color, int index ) {
|
|
setBackgroundFillEnabled( true )->setDrawableColor( index, color );
|
|
return this;
|
|
}
|
|
|
|
UINode* UINode::setBackgroundPositionX( const std::string& positionX, int index ) {
|
|
setBackgroundFillEnabled( true )->setDrawablePositionX( index, positionX );
|
|
return this;
|
|
}
|
|
|
|
UINode* UINode::setBackgroundPositionY( const std::string& positionY, int index ) {
|
|
setBackgroundFillEnabled( true )->setDrawablePositionY( index, positionY );
|
|
return this;
|
|
}
|
|
|
|
UINode* UINode::setBackgroundRepeat( const std::string& repeatRule, int index ) {
|
|
setBackgroundFillEnabled( true )->setDrawableRepeat( index, repeatRule );
|
|
return this;
|
|
}
|
|
|
|
UINode* UINode::setBackgroundSize( const std::string& size, int index ) {
|
|
setBackgroundFillEnabled( true )->setDrawableSize( index, size );
|
|
return this;
|
|
}
|
|
|
|
UINode* UINode::setBackgroundOrigin( const std::string& origin, int index ) {
|
|
setBackgroundFillEnabled( true )->setDrawableOrigin( index, origin );
|
|
return this;
|
|
}
|
|
|
|
UINode* UINode::setBackgroundClip( const std::string& clip, int index ) {
|
|
setBackgroundFillEnabled( true )->setDrawableClip( index, clip );
|
|
return this;
|
|
}
|
|
|
|
UINode* UINode::setBackgroundAttachment( const std::string& attachment, int index ) {
|
|
setBackgroundFillEnabled( true )->setDrawableAttachment( index, attachment );
|
|
return this;
|
|
}
|
|
|
|
Color UINode::getBackgroundColor() const {
|
|
return NULL != mBackground ? mBackground->getBackgroundColor() : Color::Transparent;
|
|
}
|
|
|
|
Color UINode::getBackgroundTint( int index ) const {
|
|
return mBackground ? mBackground->getLayer( index )->getColor() : Color::White;
|
|
}
|
|
|
|
UINode* UINode::setBorderRadius( const unsigned int& corners ) {
|
|
setBorderEnabled( true )->setRadius( corners );
|
|
setBackgroundFillEnabled( true )->setBorderRadius( corners );
|
|
return this;
|
|
}
|
|
|
|
UINode* UINode::setTopLeftRadius( const std::string& radius ) {
|
|
setBorderEnabled( true )->setTopLeftRadius( radius );
|
|
setBackgroundFillEnabled( true )->getBackgroundDrawable().setTopLeftRadius( radius );
|
|
return this;
|
|
}
|
|
|
|
UINode* UINode::setTopRightRadius( const std::string& radius ) {
|
|
setBorderEnabled( true )->setTopRightRadius( radius );
|
|
setBackgroundFillEnabled( true )->getBackgroundDrawable().setTopRightRadius( radius );
|
|
return this;
|
|
}
|
|
|
|
UINode* UINode::setBottomLeftRadius( const std::string& radius ) {
|
|
setBorderEnabled( true )->setBottomLeftRadius( radius );
|
|
setBackgroundFillEnabled( true )->getBackgroundDrawable().setBottomLeftRadius( radius );
|
|
return this;
|
|
}
|
|
|
|
UINode* UINode::setBottomRightRadius( const std::string& radius ) {
|
|
setBorderEnabled( true )->setBottomRightRadius( radius );
|
|
setBackgroundFillEnabled( true )->getBackgroundDrawable().setBottomRightRadius( radius );
|
|
return this;
|
|
}
|
|
|
|
Uint32 UINode::getBorderRadius() const {
|
|
return NULL != mBorder ? mBorder->getRadius() : 0;
|
|
}
|
|
|
|
UINodeDrawable* UINode::setForegroundFillEnabled( bool enabled ) {
|
|
writeFlag( UI_FILL_FOREGROUND, enabled ? 1 : 0 );
|
|
|
|
if ( enabled && NULL == mForeground ) {
|
|
getForeground();
|
|
}
|
|
|
|
invalidateDraw();
|
|
|
|
return mForeground;
|
|
}
|
|
|
|
UINode* UINode::setForegroundDrawable( Drawable* drawable, bool ownIt, int index ) {
|
|
setForegroundFillEnabled( true )->setDrawable( index, drawable, ownIt );
|
|
return this;
|
|
}
|
|
|
|
UINode* UINode::setForegroundDrawable( const std::string& drawable, int index ) {
|
|
setForegroundFillEnabled( true )->setDrawable( index, drawable );
|
|
return this;
|
|
}
|
|
|
|
Color UINode::getForegroundColor() const {
|
|
return NULL != mForeground ? mForeground->getBackgroundColor() : Color::Transparent;
|
|
}
|
|
|
|
Color UINode::getForegroundTint( int index ) const {
|
|
return mForeground ? mForeground->getLayer( index )->getColor() : Color::White;
|
|
}
|
|
|
|
UINode* UINode::setForegroundColor( const Color& color ) {
|
|
setForegroundFillEnabled( true )->setBackgroundColor( color );
|
|
return this;
|
|
}
|
|
|
|
UINode* UINode::setForegroundTint( const Color& color, int index ) {
|
|
setForegroundFillEnabled( true )->setDrawableColor( index, color );
|
|
return this;
|
|
}
|
|
|
|
UINode* UINode::setForegroundPositionX( const std::string& positionX, int index ) {
|
|
setForegroundFillEnabled( true )->setDrawablePositionX( index, positionX );
|
|
return this;
|
|
}
|
|
|
|
UINode* UINode::setForegroundPositionY( const std::string& positionY, int index ) {
|
|
setForegroundFillEnabled( true )->setDrawablePositionY( index, positionY );
|
|
return this;
|
|
}
|
|
|
|
UINode* UINode::setForegroundRepeat( const std::string& repeatRule, int index ) {
|
|
setForegroundFillEnabled( true )->setDrawableRepeat( index, repeatRule );
|
|
return this;
|
|
}
|
|
|
|
UINode* UINode::setForegroundSize( const std::string& size, int index ) {
|
|
setForegroundFillEnabled( true )->setDrawableSize( index, size );
|
|
return this;
|
|
}
|
|
|
|
UINode* UINode::setForegroundRadius( const unsigned int& corners ) {
|
|
setForegroundFillEnabled( true )->setBorderRadius( corners );
|
|
return this;
|
|
}
|
|
|
|
Uint32 UINode::getForegroundRadius() const {
|
|
return NULL != mForeground ? mForeground->getBorderRadius() : 0;
|
|
}
|
|
|
|
UINode* UINode::setForegroundTopLeftRadius( const std::string& radius ) {
|
|
setForegroundFillEnabled( true )->getBackgroundDrawable().setTopLeftRadius( radius );
|
|
return this;
|
|
}
|
|
|
|
UINode* UINode::setForegroundTopRightRadius( const std::string& radius ) {
|
|
setForegroundFillEnabled( true )->getBackgroundDrawable().setTopRightRadius( radius );
|
|
return this;
|
|
}
|
|
|
|
UINode* UINode::setForegroundBottomLeftRadius( const std::string& radius ) {
|
|
setForegroundFillEnabled( true )->getBackgroundDrawable().setBottomLeftRadius( radius );
|
|
return this;
|
|
}
|
|
|
|
UINode* UINode::setForegroundBottomRightRadius( const std::string& radius ) {
|
|
setForegroundFillEnabled( true )->getBackgroundDrawable().setBottomRightRadius( radius );
|
|
return this;
|
|
}
|
|
|
|
const Sizef& UINode::getForegroundTopLeftRadius() const {
|
|
static const Sizef zero;
|
|
if ( NULL != mForeground )
|
|
return mForeground->getBackgroundDrawable().getRadiuses().topLeft;
|
|
return zero;
|
|
}
|
|
|
|
const Sizef& UINode::getForegroundTopRightRadius() const {
|
|
static const Sizef zero;
|
|
if ( NULL != mForeground )
|
|
return mForeground->getBackgroundDrawable().getRadiuses().topRight;
|
|
return zero;
|
|
}
|
|
|
|
const Sizef& UINode::getForegroundBottomLeftRadius() const {
|
|
static const Sizef zero;
|
|
if ( NULL != mForeground )
|
|
return mForeground->getBackgroundDrawable().getRadiuses().bottomLeft;
|
|
return zero;
|
|
}
|
|
|
|
const Sizef& UINode::getForegroundBottomRightRadius() const {
|
|
static const Sizef zero;
|
|
if ( NULL != mForeground )
|
|
return mForeground->getBackgroundDrawable().getRadiuses().bottomRight;
|
|
return zero;
|
|
}
|
|
|
|
UIBorderDrawable* UINode::setBorderEnabled( bool enabled ) const {
|
|
const_cast<UINode*>( this )->writeFlag( UI_BORDER, enabled ? 1 : 0 );
|
|
|
|
if ( enabled && NULL == mBorder ) {
|
|
getBorder();
|
|
|
|
if ( NULL == mBackground ) {
|
|
getBackground();
|
|
}
|
|
}
|
|
|
|
const_cast<UINode*>( this )->invalidateDraw();
|
|
|
|
return NULL != mBorder ? mBorder : NULL;
|
|
}
|
|
|
|
UINode* UINode::setBorderColor( const Color& color ) {
|
|
setBorderEnabled( true )->setColor( color );
|
|
return this;
|
|
}
|
|
|
|
Color UINode::getBorderColor() {
|
|
return setBorderEnabled( true )->getColor();
|
|
}
|
|
|
|
UINode* UINode::setBorderWidth( const unsigned int& width ) {
|
|
setBorderEnabled( true )->setLineWidth( width );
|
|
return this;
|
|
}
|
|
|
|
Float UINode::getBorderWidth() const {
|
|
return NULL != mBorder ? mBorder->getLineWidth() : 1.f;
|
|
}
|
|
|
|
const Uint32& UINode::getFlags() const {
|
|
return mFlags;
|
|
}
|
|
|
|
UINode* UINode::setFlags( const Uint32& flags ) {
|
|
if ( NULL == mBackground && ( flags & UI_FILL_BACKGROUND ) )
|
|
setBackgroundFillEnabled( true );
|
|
|
|
if ( NULL == mForeground && ( flags & UI_FILL_FOREGROUND ) )
|
|
setForegroundFillEnabled( true );
|
|
|
|
if ( NULL == mBorder && ( flags & UI_BORDER ) )
|
|
setBorderEnabled( true );
|
|
|
|
mFlags |= flags;
|
|
|
|
if ( Font::getHorizontalAlign( flags ) || Font::getVerticalAlign( flags ) ) {
|
|
onAlignChange();
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
UINode* UINode::unsetFlags( const Uint32& flags ) {
|
|
if ( mFlags & flags )
|
|
mFlags &= ~flags;
|
|
|
|
if ( Font::getHorizontalAlign( flags ) || Font::getVerticalAlign( flags ) ) {
|
|
onAlignChange();
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
UINode* UINode::resetFlags( Uint32 newFlags ) {
|
|
mFlags = newFlags;
|
|
return this;
|
|
}
|
|
|
|
void UINode::drawBackground() {
|
|
if ( ( mFlags & UI_FILL_BACKGROUND ) && NULL != mBackground ) {
|
|
mBackground->draw( mScreenPos.trunc(), mSize.floor(), mAlpha );
|
|
}
|
|
}
|
|
|
|
void UINode::drawForeground() {
|
|
if ( ( mFlags & UI_FILL_FOREGROUND ) && NULL != mForeground ) {
|
|
mForeground->draw( mScreenPos.trunc(), mSize.floor(), (Uint32)mAlpha );
|
|
}
|
|
}
|
|
|
|
void UINode::drawBorder() {
|
|
if ( ( mFlags & UI_BORDER ) && NULL != mBorder ) {
|
|
mBorder->setAlpha( mAlpha );
|
|
mBorder->draw( mScreenPos.trunc(), mSize.floor() );
|
|
}
|
|
}
|
|
|
|
void UINode::smartClipStart( const ClipType& reqClipType, bool needsClipPlanes ) {
|
|
if ( mClip.getClipType() != reqClipType )
|
|
return;
|
|
switch ( mClip.getClipType() ) {
|
|
case ClipType::PaddingBox: {
|
|
const Rectf& pd = getPixelsPadding();
|
|
clipSmartEnable( mScreenPos.x + pd.Left, mScreenPos.y + pd.Top,
|
|
mSize.getWidth() - pd.Left - pd.Right,
|
|
mSize.getHeight() - pd.Top - pd.Bottom, needsClipPlanes );
|
|
break;
|
|
}
|
|
case ClipType::ContentBox: {
|
|
clipSmartEnable( mScreenPos.x, mScreenPos.y, mSize.getWidth(), mSize.getHeight(),
|
|
needsClipPlanes );
|
|
break;
|
|
}
|
|
case ClipType::BorderBox: {
|
|
Rectf borderDiff;
|
|
if ( mBorder )
|
|
borderDiff = mBorder->getBorderBoxDiff();
|
|
clipSmartEnable( mScreenPos.x + borderDiff.Left, mScreenPos.y + borderDiff.Top,
|
|
mSize.getWidth() + borderDiff.Right,
|
|
mSize.getHeight() + borderDiff.Bottom, needsClipPlanes );
|
|
break;
|
|
}
|
|
case ClipType::None: {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void UINode::smartClipEnd( const ClipType& reqClipType, bool needsClipPlanes ) {
|
|
if ( mVisible && isClipped() && mClip.getClipType() == reqClipType ) {
|
|
clipEnd( needsClipPlanes );
|
|
}
|
|
}
|
|
|
|
void UINode::smartClipStart( const ClipType& reqClipType ) {
|
|
smartClipStart( reqClipType, isMeOrParentTreeScaledOrRotatedOrFrameBuffer() );
|
|
}
|
|
|
|
void UINode::smartClipEnd( const ClipType& reqClipType ) {
|
|
smartClipEnd( reqClipType, isMeOrParentTreeScaledOrRotatedOrFrameBuffer() );
|
|
}
|
|
|
|
Color UINode::getDroppableHoveringColor() {
|
|
const PropertyDefinition* def =
|
|
StyleSheetSpecification::instance()->getProperty( "droppable-hovering-color" );
|
|
Color color = Color::fromString( def->getDefaultValue() );
|
|
if ( isWidget() ) {
|
|
UIWidget* widget = asType<UIWidget>();
|
|
std::string colorString = widget->getPropertyString( def );
|
|
if ( !colorString.empty() ) {
|
|
color = Color::fromString( colorString );
|
|
} else {
|
|
colorString = mUISceneNode->getRoot()->getPropertyString( def );
|
|
if ( !colorString.empty() )
|
|
color = Color::fromString( colorString );
|
|
}
|
|
}
|
|
return color;
|
|
}
|
|
|
|
void UINode::nodeDraw() {
|
|
if ( mVisible ) {
|
|
if ( mNodeFlags & NODE_FLAG_POSITION_DIRTY )
|
|
updateScreenPos();
|
|
|
|
if ( mNodeFlags & NODE_FLAG_POLYGON_DIRTY )
|
|
updateWorldPolygon();
|
|
|
|
matrixSet();
|
|
|
|
bool needsClipPlanes =
|
|
mClip.getClipType() != ClipType::None && isMeOrParentTreeScaledOrRotatedOrFrameBuffer();
|
|
|
|
smartClipStart( ClipType::BorderBox, needsClipPlanes );
|
|
|
|
bool intersected = mWorldBounds.intersect( mSceneNode->getWorldBounds() );
|
|
|
|
if ( intersected ) {
|
|
smartClipStart( ClipType::ContentBox, needsClipPlanes );
|
|
|
|
if ( 0.f != mAlpha ) {
|
|
drawBackground();
|
|
|
|
drawSkin();
|
|
}
|
|
|
|
smartClipStart( ClipType::PaddingBox, needsClipPlanes );
|
|
|
|
draw();
|
|
|
|
drawChildren();
|
|
|
|
smartClipEnd( ClipType::PaddingBox, needsClipPlanes );
|
|
|
|
if ( 0.f != mAlpha )
|
|
drawForeground();
|
|
|
|
smartClipEnd( ClipType::ContentBox, needsClipPlanes );
|
|
} else if ( !isClipped() ) {
|
|
drawChildren();
|
|
}
|
|
|
|
if ( intersected )
|
|
drawBorder();
|
|
|
|
if ( mNodeFlags & NODE_FLAG_DROPPABLE_HOVERING )
|
|
drawDroppableHovering();
|
|
|
|
if ( intersected ) {
|
|
drawHighlightFocus();
|
|
|
|
drawOverNode();
|
|
|
|
updateDebugData();
|
|
|
|
drawBox();
|
|
}
|
|
|
|
smartClipEnd( ClipType::BorderBox, needsClipPlanes );
|
|
|
|
matrixUnset();
|
|
}
|
|
}
|
|
|
|
void UINode::clearForeground() {
|
|
eeSAFE_DELETE( mForeground );
|
|
}
|
|
|
|
void UINode::clearBackground() {
|
|
eeSAFE_DELETE( mBackground );
|
|
}
|
|
|
|
const ClipType& UINode::getClipType() const {
|
|
return mClip.getClipType();
|
|
}
|
|
|
|
UINode* UINode::setClipType( const ClipType& clipType ) {
|
|
if ( mClip.getClipType() != clipType ) {
|
|
mClip.setClipType( clipType );
|
|
if ( mClip.getClipType() != ClipType::None ) {
|
|
clipEnable();
|
|
} else {
|
|
clipDisable();
|
|
}
|
|
}
|
|
return this;
|
|
}
|
|
|
|
bool UINode::hasBorder() const {
|
|
return ( mFlags & UI_BORDER ) != 0;
|
|
}
|
|
|
|
const Rectf& UINode::getPixelsPadding() const {
|
|
static const Rectf Zero{};
|
|
return Zero;
|
|
}
|
|
|
|
UINodeDrawable* UINode::getBackground() const {
|
|
if ( NULL == mBackground ) {
|
|
mBackground = UINodeDrawable::New( const_cast<UINode*>( this ) );
|
|
if ( mFlags & UI_HTML_ELEMENT )
|
|
mBackground->setBackgroundMode( BackgroundMode::Html );
|
|
}
|
|
|
|
return mBackground;
|
|
}
|
|
|
|
bool UINode::hasBackground() const {
|
|
return mBackground != nullptr;
|
|
}
|
|
|
|
UINodeDrawable* UINode::getForeground() const {
|
|
if ( NULL == mForeground ) {
|
|
mForeground = UINodeDrawable::New( const_cast<UINode*>( this ) );
|
|
}
|
|
|
|
return mForeground;
|
|
}
|
|
|
|
bool UINode::hasForeground() const {
|
|
return mForeground != nullptr;
|
|
}
|
|
|
|
UIBorderDrawable* UINode::getBorder() const {
|
|
if ( NULL == mBorder ) {
|
|
mBorder = UIBorderDrawable::New( this );
|
|
mBorder->setColor( Color::Transparent );
|
|
// mBorder->setLineWidth( PixelDensity::dpToPx( 1 ) );
|
|
}
|
|
|
|
return mBorder;
|
|
}
|
|
|
|
void UINode::setThemeByName( const std::string& Theme ) {
|
|
setTheme( getUISceneNode()->getUIThemeManager()->getByName( Theme ) );
|
|
}
|
|
|
|
void UINode::setTheme( UITheme* Theme ) {
|
|
setThemeSkin( Theme, "widget" );
|
|
}
|
|
|
|
UINode* UINode::setThemeSkin( const std::string& skinName ) {
|
|
return setThemeSkin( getUISceneNode()->getUIThemeManager()->getDefaultTheme(), skinName );
|
|
}
|
|
|
|
UINode* UINode::setThemeSkin( UITheme* Theme, const std::string& skinName ) {
|
|
if ( NULL != Theme ) {
|
|
setSkin( Theme->getSkin( skinName ) );
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
UINode* UINode::setSkin( const UISkin& Skin ) {
|
|
removeSkin();
|
|
|
|
writeNodeFlag( NODE_FLAG_SKIN_OWNER, 1 );
|
|
|
|
UISkin* SkinCopy = const_cast<UISkin*>( &Skin )->clone();
|
|
|
|
mSkinState = UISkinState::New( SkinCopy );
|
|
|
|
onThemeLoaded();
|
|
|
|
return this;
|
|
}
|
|
|
|
UINode* UINode::setSkin( UISkin* skin ) {
|
|
if ( NULL != skin ) {
|
|
if ( NULL != mSkinState && mSkinState->getSkin() == skin )
|
|
return this;
|
|
|
|
Uint32 InitialState = UIState::StateFlagNormal;
|
|
|
|
if ( NULL != mSkinState ) {
|
|
InitialState = mSkinState->getState();
|
|
}
|
|
|
|
removeSkin();
|
|
|
|
mSkinState = UISkinState::New( skin );
|
|
mSkinState->setState( InitialState );
|
|
|
|
onThemeLoaded();
|
|
} else {
|
|
removeSkin();
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
UINode* UINode::setSkinColor( const Color& color ) {
|
|
if ( color != mSkinColor ) {
|
|
mSkinColor = color;
|
|
invalidateDraw();
|
|
}
|
|
return this;
|
|
}
|
|
|
|
const Color& UINode::getSkinColor() const {
|
|
return mSkinColor;
|
|
}
|
|
|
|
void UINode::removeSkin() {
|
|
if ( NULL != mSkinState && ( mNodeFlags & NODE_FLAG_SKIN_OWNER ) ) {
|
|
UISkin* tSkin = mSkinState->getSkin();
|
|
|
|
eeSAFE_DELETE( tSkin );
|
|
}
|
|
|
|
eeSAFE_DELETE( mSkinState );
|
|
}
|
|
|
|
void UINode::onStateChange() {
|
|
invalidateDraw();
|
|
}
|
|
|
|
void UINode::onEnabledChange() {
|
|
if ( !mEnabled ) {
|
|
pushState( UIState::StateDisabled );
|
|
} else {
|
|
popState( UIState::StateDisabled );
|
|
}
|
|
|
|
Node::onEnabledChange();
|
|
}
|
|
|
|
void UINode::onAlignChange() {
|
|
invalidateDraw();
|
|
}
|
|
|
|
void UINode::pushState( const Uint32& State, bool emitEvent ) {
|
|
if ( !( mState & ( 1 << State ) ) ) {
|
|
mState |= 1 << State;
|
|
|
|
if ( NULL != mSkinState )
|
|
mSkinState->pushState( State );
|
|
|
|
if ( emitEvent ) {
|
|
onStateChange();
|
|
} else {
|
|
invalidateDraw();
|
|
}
|
|
}
|
|
}
|
|
|
|
void UINode::popState( const Uint32& State, bool emitEvent ) {
|
|
if ( mState & ( 1 << State ) ) {
|
|
mState &= ~( 1 << State );
|
|
|
|
if ( NULL != mSkinState )
|
|
mSkinState->popState( State );
|
|
|
|
if ( emitEvent ) {
|
|
onStateChange();
|
|
} else {
|
|
invalidateDraw();
|
|
}
|
|
}
|
|
}
|
|
|
|
void UINode::setThemeToChildren( UITheme* Theme ) {
|
|
Node* ChildLoop = mChild;
|
|
|
|
while ( NULL != ChildLoop ) {
|
|
if ( ChildLoop->isUINode() ) {
|
|
UINode* node = static_cast<UINode*>( ChildLoop );
|
|
node->setThemeToChildren( Theme );
|
|
node->setTheme( Theme ); // First set the theme to children to let the father override
|
|
// the children forced themes
|
|
}
|
|
|
|
ChildLoop = ChildLoop->getNextNode();
|
|
}
|
|
}
|
|
|
|
UISkin* UINode::getSkin() const {
|
|
if ( NULL != mSkinState )
|
|
return mSkinState->getSkin();
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void UINode::writeFlag( const Uint32& Flag, const Uint32& Val ) {
|
|
if ( Val )
|
|
mFlags |= Flag;
|
|
else {
|
|
if ( mFlags & Flag )
|
|
mFlags &= ~Flag;
|
|
}
|
|
}
|
|
|
|
void UINode::applyDefaultTheme() {
|
|
getUISceneNode()->getUIThemeManager()->applyDefaultTheme( this );
|
|
}
|
|
|
|
Rectf UINode::makePadding( bool PadLeft, bool PadRight, bool PadTop, bool PadBottom,
|
|
bool SkipFlags ) const {
|
|
Rectf tPadding( 0, 0, 0, 0 );
|
|
|
|
if ( mFlags & UI_AUTO_PADDING || SkipFlags ) {
|
|
if ( NULL != mSkinState && NULL != mSkinState->getSkin() ) {
|
|
Rectf rPadding = mSkinState->getSkin()->getBorderSize();
|
|
|
|
if ( PadLeft ) {
|
|
tPadding.Left = rPadding.Left;
|
|
}
|
|
|
|
if ( PadRight ) {
|
|
tPadding.Right = rPadding.Right;
|
|
}
|
|
|
|
if ( PadTop ) {
|
|
tPadding.Top = rPadding.Top;
|
|
}
|
|
|
|
if ( PadBottom ) {
|
|
tPadding.Bottom = rPadding.Bottom;
|
|
}
|
|
}
|
|
}
|
|
|
|
return PixelDensity::pxToDp( tPadding );
|
|
}
|
|
|
|
Sizef UINode::getSkinSize( UISkin* Skin, const Uint32& State ) const {
|
|
if ( NULL != Skin ) {
|
|
return Skin->getSize( State );
|
|
}
|
|
|
|
return Sizef::Zero;
|
|
}
|
|
|
|
Sizef UINode::getSkinSize( const Uint32& state ) const {
|
|
if ( NULL != getSkin() ) {
|
|
return getSkin()->getSize( state );
|
|
}
|
|
|
|
return Sizef::Zero;
|
|
}
|
|
|
|
void UINode::onThemeLoaded() {
|
|
invalidateDraw();
|
|
}
|
|
|
|
void UINode::onChildCountChange( Node* child, const bool& removed ) {
|
|
Node::onChildCountChange( child, removed );
|
|
}
|
|
|
|
void UINode::worldToNode( Vector2i& pos ) const {
|
|
Vector2f toPos( convertToNodeSpace( Vector2f( pos.x, pos.y ) ) );
|
|
pos = Vector2i( toPos.x / PixelDensity::getPixelDensity(),
|
|
toPos.y / PixelDensity::getPixelDensity() );
|
|
}
|
|
|
|
void UINode::nodeToWorld( Vector2i& pos ) const {
|
|
Vector2f toPos( convertToWorldSpace( Vector2f( pos.x * PixelDensity::getPixelDensity(),
|
|
pos.y * PixelDensity::getPixelDensity() ) ) );
|
|
pos = Vector2i( toPos.x, toPos.y );
|
|
}
|
|
|
|
void UINode::worldToNode( Vector2f& pos ) const {
|
|
Vector2f toPos( convertToNodeSpace( pos ) );
|
|
pos = Vector2f( toPos.x / PixelDensity::getPixelDensity(),
|
|
toPos.y / PixelDensity::getPixelDensity() );
|
|
}
|
|
|
|
void UINode::nodeToWorld( Vector2f& pos ) const {
|
|
Vector2f toPos( convertToWorldSpace( Vector2f( pos.x * PixelDensity::getPixelDensity(),
|
|
pos.y * PixelDensity::getPixelDensity() ) ) );
|
|
pos = Vector2f( toPos.x, toPos.y );
|
|
}
|
|
|
|
Node* UINode::getWindowContainer() const {
|
|
const Node* node = this;
|
|
|
|
while ( node != NULL ) {
|
|
if ( node->isType( UI_TYPE_WINDOW ) ) {
|
|
return static_cast<const UIWindow*>( node )->getContainer();
|
|
} else if ( mSceneNode == node ) {
|
|
if ( mSceneNode->isUISceneNode() ) {
|
|
return static_cast<UISceneNode*>( mSceneNode )->getRoot();
|
|
} else {
|
|
return mSceneNode;
|
|
}
|
|
}
|
|
|
|
node = node->getParent();
|
|
}
|
|
|
|
return mSceneNode;
|
|
}
|
|
|
|
bool UINode::isTabFocusable() const {
|
|
return 0 != ( mFlags & UI_TAB_FOCUSABLE );
|
|
}
|
|
|
|
const Vector2f& UINode::getDragPoint() const {
|
|
return mDragPoint;
|
|
}
|
|
|
|
void UINode::setDragPoint( const Vector2f& Point ) {
|
|
mDragPoint = Point;
|
|
}
|
|
|
|
Uint32 UINode::onDrag( const Vector2f&, const Uint32&, const Sizef& ) {
|
|
return 1;
|
|
}
|
|
|
|
Uint32 UINode::onDragStart( const Vector2i& pos, const Uint32& flags ) {
|
|
sendMouseEvent( Event::OnDragStart, pos, flags );
|
|
return 1;
|
|
}
|
|
|
|
Uint32 UINode::onDragStop( const Vector2i& pos, const Uint32& flags ) {
|
|
sendMouseEvent( Event::OnDragStop, pos, flags );
|
|
return 1;
|
|
}
|
|
|
|
Uint32 UINode::onDrop( UINode* widget ) {
|
|
DropEvent event( this, widget, Event::OnNodeDropped );
|
|
sendEvent( &event );
|
|
return 1;
|
|
}
|
|
|
|
Uint32 UINode::onMouseOver( const Vector2i& position, const Uint32& flags ) {
|
|
Node::onMouseOver( position, flags );
|
|
|
|
pushState( UIState::StateHover );
|
|
|
|
return 1;
|
|
}
|
|
|
|
Uint32 UINode::onMouseLeave( const Vector2i& position, const Uint32& flags ) {
|
|
Node::onMouseLeave( position, flags );
|
|
|
|
popState( UIState::StateHover );
|
|
popState( UIState::StatePressed );
|
|
|
|
return 1;
|
|
}
|
|
|
|
bool UINode::isDragEnabled() const {
|
|
return 0 != ( mFlags & UI_DRAG_ENABLE );
|
|
}
|
|
|
|
void UINode::setDragEnabled( const bool& enable ) {
|
|
writeFlag( UI_DRAG_ENABLE, true == enable );
|
|
}
|
|
|
|
bool UINode::isDragging() const {
|
|
return 0 != ( mNodeFlags & NODE_FLAG_DRAGGING );
|
|
}
|
|
|
|
void UINode::setDragging( bool dragging, bool emitDropEvent ) {
|
|
if ( NULL == getEventDispatcher() )
|
|
return;
|
|
|
|
writeNodeFlag( NODE_FLAG_DRAGGING, dragging );
|
|
|
|
if ( dragging ) {
|
|
NodeMessage tMsg( this, NodeMessage::DragStart, getEventDispatcher()->getPressTrigger() );
|
|
messagePost( &tMsg );
|
|
|
|
onDragStart( getEventDispatcher()->getMousePos(), getEventDispatcher()->getPressTrigger() );
|
|
} else {
|
|
NodeMessage tMsg( this, NodeMessage::DragStop, getEventDispatcher()->getPressTrigger() );
|
|
messagePost( &tMsg );
|
|
|
|
onDragStop( getEventDispatcher()->getMousePos(), getEventDispatcher()->getPressTrigger() );
|
|
|
|
if ( emitDropEvent ) {
|
|
bool enabled = isEnabled();
|
|
mEnabled = false;
|
|
Node* found = getUISceneNode()->overFind( getEventDispatcher()->getMousePosf() );
|
|
if ( found && found->isUINode() ) {
|
|
NodeDropMessage msg( found, NodeMessage::Drop, this );
|
|
found->messagePost( &msg );
|
|
found->asType<UINode>()->onDrop( this );
|
|
}
|
|
mEnabled = enabled;
|
|
}
|
|
}
|
|
}
|
|
|
|
void UINode::startDragging( const Vector2f& position ) {
|
|
setDragging( true );
|
|
|
|
if ( NULL != getEventDispatcher() )
|
|
getEventDispatcher()->setNodeDragging( this );
|
|
|
|
mDragPoint = position;
|
|
}
|
|
|
|
bool UINode::ownsChildPosition() const {
|
|
return 0 != ( mFlags & UI_OWNS_CHILDREN_POSITION );
|
|
}
|
|
|
|
void UINode::setDragButton( const Uint32& Button ) {
|
|
mDragButton = Button;
|
|
}
|
|
|
|
const Uint32& UINode::getDragButton() const {
|
|
return mDragButton;
|
|
}
|
|
|
|
void UINode::onWidgetFocusLoss() {
|
|
sendCommonEvent( Event::OnWidgetFocusLoss );
|
|
invalidateDraw();
|
|
}
|
|
|
|
Node* UINode::setFocus( NodeFocusReason reason ) {
|
|
if ( NULL != getEventDispatcher() )
|
|
getEventDispatcher()->setFocusNode( this, reason );
|
|
return this;
|
|
}
|
|
|
|
Float UINode::getPropertyRelativeTargetContainerLength(
|
|
const PropertyRelativeTarget& relativeTarget, const Float& defaultValue,
|
|
const Uint32& propertyIndex ) const {
|
|
Float containerLength = defaultValue;
|
|
switch ( relativeTarget ) {
|
|
case PropertyRelativeTarget::ContainingBlockWidth: {
|
|
Node* parent = getParent(); // Text spans cannot be considered containing blocks
|
|
while ( parent->isType( UI_TYPE_TEXTSPAN ) )
|
|
parent = parent->getParent();
|
|
containerLength = parent ? parent->getPixelsSize().getWidth() : 0;
|
|
break;
|
|
}
|
|
case PropertyRelativeTarget::ContainingBlockHeight: {
|
|
Node* parent = getParent(); // Text spans cannot be considered containing blocks
|
|
while ( parent->isType( UI_TYPE_TEXTSPAN ) )
|
|
parent = parent->getParent();
|
|
containerLength = parent ? parent->getPixelsSize().getHeight() : 0;
|
|
break;
|
|
}
|
|
case PropertyRelativeTarget::LocalBlockWidth:
|
|
containerLength = getPixelsSize().getWidth();
|
|
break;
|
|
case PropertyRelativeTarget::LocalBlockHeight:
|
|
containerLength = getPixelsSize().getHeight();
|
|
break;
|
|
case PropertyRelativeTarget::BackgroundWidth:
|
|
containerLength =
|
|
getPixelsSize().getWidth() -
|
|
getBackground()->getLayer( propertyIndex )->getDrawableSize().getWidth();
|
|
break;
|
|
case PropertyRelativeTarget::BackgroundHeight:
|
|
containerLength =
|
|
getPixelsSize().getHeight() -
|
|
getBackground()->getLayer( propertyIndex )->getDrawableSize().getHeight();
|
|
break;
|
|
case PropertyRelativeTarget::ForegroundWidth:
|
|
containerLength =
|
|
getPixelsSize().getWidth() -
|
|
getForeground()->getLayer( propertyIndex )->getDrawableSize().getWidth();
|
|
break;
|
|
case PropertyRelativeTarget::ForegroundHeight:
|
|
containerLength =
|
|
getPixelsSize().getHeight() -
|
|
getForeground()->getLayer( propertyIndex )->getDrawableSize().getHeight();
|
|
break;
|
|
case PropertyRelativeTarget::LocalBlockRadiusWidth:
|
|
containerLength = getPixelsSize().getWidth() * 0.5f;
|
|
break;
|
|
case PropertyRelativeTarget::LocalBlockRadiusHeight:
|
|
containerLength = getPixelsSize().getHeight() * 0.5f;
|
|
break;
|
|
case PropertyRelativeTarget::None:
|
|
default:
|
|
break;
|
|
}
|
|
return containerLength;
|
|
}
|
|
|
|
Float UINode::lengthFromValue( const std::string& value,
|
|
const PropertyRelativeTarget& relativeTarget,
|
|
const Float& defaultValue, const Uint32& propertyIndex ) const {
|
|
Float containerLength =
|
|
getPropertyRelativeTargetContainerLength( relativeTarget, defaultValue, propertyIndex );
|
|
return convertLength( StyleSheetLength::fromString( value, defaultValue ), containerLength );
|
|
}
|
|
|
|
Float UINode::lengthFromValue( const StyleSheetProperty& property,
|
|
const Float& defaultValue ) const {
|
|
if ( property.getPropertyDefinition() &&
|
|
property.getPropertyDefinition()->getPropertyId() == PropertyId::FontSize ) {
|
|
StyleSheetLength length( property.value() );
|
|
if ( length.getUnit() == StyleSheetLength::Unit::Percentage ) {
|
|
length.setValue( length.getValue() / 100.f, StyleSheetLength::Unit::Em );
|
|
return convertLength( length, 0 );
|
|
}
|
|
|
|
static constexpr std::string_view FontSizeNames[] = {
|
|
"xx-small", "x-small", "small", "medium", "large",
|
|
"x-large", "xx-large", "xxx-large", "smaller", "larger" };
|
|
|
|
auto it = std::find( std::begin( FontSizeNames ), std::end( FontSizeNames ),
|
|
property.getValue() );
|
|
|
|
if ( it != std::end( FontSizeNames ) ) {
|
|
std::string_view keyword = *it;
|
|
StyleSheetLength res;
|
|
if ( keyword == "xx-small" ) {
|
|
res.setValue( 0.6f, StyleSheetLength::Unit::Rem );
|
|
} else if ( keyword == "x-small" ) {
|
|
res.setValue( 0.75f, StyleSheetLength::Unit::Rem );
|
|
} else if ( keyword == "small" ) {
|
|
res.setValue( 0.89f, StyleSheetLength::Unit::Rem );
|
|
} else if ( keyword == "medium" ) {
|
|
res.setValue( 1.0f, StyleSheetLength::Unit::Rem );
|
|
} else if ( keyword == "large" ) {
|
|
res.setValue( 1.2f, StyleSheetLength::Unit::Rem );
|
|
} else if ( keyword == "x-large" ) {
|
|
res.setValue( 1.5f, StyleSheetLength::Unit::Rem );
|
|
} else if ( keyword == "xx-large" ) {
|
|
res.setValue( 2.0f, StyleSheetLength::Unit::Rem );
|
|
} else if ( keyword == "xxx-large" ) {
|
|
res.setValue( 3.0f, StyleSheetLength::Unit::Rem );
|
|
} else if ( keyword == "smaller" ) {
|
|
res.setValue( 0.85f, StyleSheetLength::Unit::Em );
|
|
} else if ( keyword == "larger" ) {
|
|
res.setValue( 1.2f, StyleSheetLength::Unit::Em );
|
|
}
|
|
return convertLength( res, 0 );
|
|
} else if ( property.getValue() == "inherit" ) {
|
|
Node* parentNode = getParent();
|
|
if ( parentNode && parentNode->isWidget() ) {
|
|
Float parentPxSize = getAbsoluteFontSize( parentNode->asType<UIWidget>() );
|
|
StyleSheetLength res;
|
|
res.setValue( PixelDensity::pxToDp( parentPxSize ), StyleSheetLength::Unit::Dp );
|
|
return convertLength( res, 0 );
|
|
}
|
|
StyleSheetLength res;
|
|
res.setValue( 12, StyleSheetLength::Unit::Dp );
|
|
return convertLength( res, 0 );
|
|
}
|
|
}
|
|
return lengthFromValue( property.getValue(),
|
|
property.getPropertyDefinition()->getRelativeTarget(), defaultValue,
|
|
property.getIndex() );
|
|
}
|
|
|
|
Float UINode::lengthFromValueAsDp( const std::string& value,
|
|
const PropertyRelativeTarget& relativeTarget,
|
|
const Float& defaultValue, const Uint32& propertyIndex ) const {
|
|
Float containerLength =
|
|
getPropertyRelativeTargetContainerLength( relativeTarget, defaultValue, propertyIndex );
|
|
return convertLengthAsDp( StyleSheetLength::fromString( value, defaultValue ),
|
|
containerLength );
|
|
}
|
|
|
|
Float UINode::lengthFromValueAsDp( const StyleSheetProperty& property,
|
|
const Float& defaultValue ) const {
|
|
return lengthFromValueAsDp( property.getValue(),
|
|
property.getPropertyDefinition()->getRelativeTarget(), defaultValue,
|
|
property.getIndex() );
|
|
}
|
|
|
|
Uint32 UINode::onFocus( NodeFocusReason reason ) {
|
|
pushState( UIState::StateFocus );
|
|
|
|
return Node::onFocus( reason );
|
|
}
|
|
|
|
Uint32 UINode::onFocusLoss() {
|
|
popState( UIState::StateFocus );
|
|
|
|
return Node::onFocusLoss();
|
|
}
|
|
|
|
void UINode::onSceneChange() {
|
|
Node::onSceneChange();
|
|
if ( NULL != mSceneNode && mSceneNode->isUISceneNode() ) {
|
|
mUISceneNode = static_cast<UISceneNode*>( mSceneNode );
|
|
}
|
|
}
|
|
|
|
Float UINode::convertLength( const CSS::StyleSheetLength& length,
|
|
const Float& containerLength ) const {
|
|
Float rootFontSize = 12.f * PixelDensity::getPixelDensity();
|
|
Float elFontSize = rootFontSize;
|
|
|
|
if ( length.getUnit() == StyleSheetLength::Unit::Rem && getUISceneNode() ) {
|
|
UIWidget* docRoot = isWidget() ? const_cast<UINode*>( this )->asType<UIWidget>() : nullptr;
|
|
if ( docRoot ) {
|
|
while ( docRoot->getParent() && docRoot->getParent()->isWidget() ) {
|
|
if ( docRoot->getElementTag() == "html" )
|
|
break;
|
|
docRoot = docRoot->getParent()->asType<UIWidget>();
|
|
}
|
|
rootFontSize = getAbsoluteFontSize( docRoot );
|
|
} else {
|
|
rootFontSize = getAbsoluteFontSize( getUISceneNode()->getRoot() );
|
|
}
|
|
} else if ( ( length.getUnit() == StyleSheetLength::Unit::Em ||
|
|
length.getUnit() == StyleSheetLength::Unit::Ex ||
|
|
length.getUnit() == StyleSheetLength::Unit::Ch ) &&
|
|
isWidget() ) {
|
|
elFontSize = getAbsoluteFontSize( asConstType<UIWidget>() );
|
|
}
|
|
|
|
Graphics::Font* font = nullptr;
|
|
if ( getUISceneNode() && getUISceneNode()->getUIThemeManager() )
|
|
font = getUISceneNode()->getUIThemeManager()->getDefaultFont();
|
|
|
|
auto ret = length.asPixels( containerLength, getSceneNode()->getPixelsSize(),
|
|
getSceneNode()->getDPI(), elFontSize, rootFontSize, font );
|
|
|
|
if ( ( mFlags & UI_HTML_ELEMENT ) && length.getUnit() == StyleSheetLength::Unit::Px )
|
|
ret = PixelDensity::dpToPx( ret ); // scale px as if where dp in HTML elements
|
|
|
|
return ret;
|
|
}
|
|
|
|
Float UINode::convertLengthAsDp( const StyleSheetLength& length,
|
|
const Float& containerLength ) const {
|
|
return PixelDensity::pxToDp( convertLength( length, containerLength ) );
|
|
}
|
|
|
|
UISceneNode* UINode::getUISceneNode() const {
|
|
return mUISceneNode;
|
|
}
|
|
|
|
Input* UINode::getInput() const {
|
|
return mUISceneNode->getWindow()->getInput();
|
|
}
|
|
|
|
Rectf UINode::getLocalDpBounds() const {
|
|
return Rectf( 0, 0, mDpSize.getWidth(), mDpSize.getHeight() );
|
|
}
|
|
|
|
Float UINode::getAbsoluteFontSize( const UIWidget* widget ) const {
|
|
std::string pxStr = widget->getPropertyString(
|
|
StyleSheetSpecification::instance()->getProperty( PropertyId::FontSize ) );
|
|
if ( pxStr.empty() )
|
|
return 12.f * PixelDensity::getPixelDensity();
|
|
StyleSheetLength len( pxStr );
|
|
if ( len.getUnit() == StyleSheetLength::Unit::Rem ) {
|
|
Float rootFontSize = 12.f * PixelDensity::getPixelDensity();
|
|
if ( widget->getUISceneNode() ) {
|
|
UIWidget* docRoot = const_cast<UIWidget*>( widget );
|
|
while ( docRoot->getParent() && docRoot->getParent()->isWidget() ) {
|
|
if ( docRoot->getElementTag() == "html" )
|
|
break;
|
|
docRoot = docRoot->getParent()->asType<UIWidget>();
|
|
}
|
|
rootFontSize = getAbsoluteFontSize( docRoot );
|
|
}
|
|
return len.getValue() * rootFontSize;
|
|
} else if ( len.getUnit() == StyleSheetLength::Unit::Em ||
|
|
len.getUnit() == StyleSheetLength::Unit::Percentage ) {
|
|
Float parentFontSize = 12.f;
|
|
Node* pNode = widget->getParent();
|
|
while ( pNode ) {
|
|
if ( pNode->isWidget() ) {
|
|
parentFontSize = getAbsoluteFontSize( pNode->asType<UIWidget>() );
|
|
break;
|
|
}
|
|
pNode = pNode->getParent();
|
|
}
|
|
if ( len.getUnit() == StyleSheetLength::Unit::Em )
|
|
return len.getValue() * parentFontSize;
|
|
return ( len.getValue() / 100.f ) * parentFontSize;
|
|
}
|
|
return widget->convertLength( len, 0 );
|
|
}
|
|
|
|
}} // namespace EE::UI
|