Several fixes for UIViewPager.

Added min-width and max-width CSS properties (still needs testing).
Fixed CSS animations with multiple steps.
Fixed menu sub-menues not appearing.
This commit is contained in:
Martín Lucas Golini
2020-02-28 04:40:32 -03:00
parent 8c108c5ed9
commit cd34f7f4e4
19 changed files with 239 additions and 53 deletions

View File

@@ -466,6 +466,12 @@ TabWidget {
animation-play-state: running;
}
#test_8 Widget {
max-width: 64dp;
background-color: #323232;
margin-right: 8dp;
}
@media screen and (max-width: 1024px) {
#lvbox {

View File

@@ -93,6 +93,14 @@
<Image src="file://assets/sprites/3.png" scale-type="expand" />
<Image src="file://assets/sprites/4.png" scale-type="expand" />
</ViewPager>
<ViewPager id="test_8" layout_width="match_parent" layout_height="match_parent">
<hbox>
<Widget layout_width="match_parent" layout_height="match_parent" />
<Widget layout_width="match_parent" layout_height="match_parent" />
<Widget layout_width="match_parent" layout_height="match_parent" />
<Widget layout_width="match_parent" layout_height="match_parent" />
</hbox>
</ViewPager>
<Tab name="Padding Test" owns="test_1" />
<Tab name="Tabs Test" owns="test_2" />
<Tab name="Cascade Test" owns="test_3" />
@@ -100,5 +108,6 @@
<Tab name="Scroll Test" owns="test_5" />
<Tab name="Grid Test" owns="test_6" />
<Tab name="View Pager Test" owns="test_7" />
<Tab name="MinMax Size Test" owns="test_8" />
</TabWidget>
</vbox>

View File

@@ -135,6 +135,9 @@ enum class PropertyId : Uint32 {
AnimationSpeed = String::hash( "animation-speed" ),
ArcStartAngle = String::hash( "arc-start-angle" ),
MinWidth = String::hash( "min-width" ),
MinHeight = String::hash( "min-height" ),
MaxWidth = String::hash( "max-width" ),
MaxHeight = String::hash( "max-height" ),
MinMarginRight = String::hash( "min-margin-right" ),
MinIconSpace = String::hash( "min-icon-space" ),
TotalSteps = String::hash( "total-steps" ),

View File

@@ -35,7 +35,8 @@ enum UIFlag {
UI_TOUCH_DRAG_ENABLED = ( 1 << 18 ),
UI_TEXT_SELECTION_ENABLED = ( 1 << 19 ),
UI_ATTRIBUTE_CHANGED = ( 1 << 20 ),
UI_CHECKED = ( 1 << 21 )
UI_CHECKED = ( 1 << 21 ),
UI_OWNS_CHILDS_POSITION = ( 1 << 22 )
};
enum UINodeType {

View File

@@ -32,6 +32,8 @@ class EE_API UILinearLayout : public UILayout {
protected:
UIOrientation mOrientation;
bool mHPacking;
bool mVPacking;
virtual Uint32 onMessage( const NodeMessage* Msg );
@@ -39,7 +41,7 @@ class EE_API UILinearLayout : public UILayout {
virtual void onParentSizeChange( const Vector2f& SizeChange );
virtual void onChildCountChange( Node * child, const bool& removed );
virtual void onChildCountChange( Node* child, const bool& removed );
void pack();

View File

@@ -31,22 +31,22 @@ class EE_API UIMenuSubMenu : public UIMenuItem {
virtual bool inheritsFrom( const Uint32 getType );
Float getMouseOverTimeShowMenu() const;
const Time& getMouseOverTimeShowMenu() const;
void setMouseOverTimeShowMenu( const Float& maxTime );
void setMouseOverTimeShowMenu( const Time& maxTime );
protected:
UIMenu* mSubMenu;
UINode* mArrow;
Float mTimeOver;
Float mMaxTime;
Time mMaxTime;
Uint32 mCbId;
Uint32 mCbId2;
Action* mCurWait;
virtual Uint32 onMouseOver( const Vector2i& position, const Uint32& flags );
virtual Uint32 onMouseLeave( const Vector2i& position, const Uint32& flags );
virtual Uint32 onMouseMove( const Vector2i& position, const Uint32& flags );
virtual void onStateChange();
virtual void onSizeChange();

View File

@@ -192,6 +192,8 @@ class EE_API UINode : public Node {
void setDragging( const bool& dragging );
bool ownsChildPosition() const;
const Vector2f& getDragPoint() const;
void setDragPoint( const Vector2f& Point );

View File

@@ -227,6 +227,22 @@ class EE_API UIWidget : public UINode {
Float lengthFromValueAsDp( const StyleSheetProperty& property, const Float& defaultValue = 0,
const Float& defaultContainerValue = 0 );
const std::string& getMinWidthEq() const;
void setMinWidthEq( const std::string& minWidthEq );
const std::string& getMinHeightEq() const;
void setMinHeightEq( const std::string& minHeightEq );
const std::string& getMaxWidthEq() const;
void setMaxWidthEq( const std::string& maxWidthEq );
const std::string& getMaxHeightEq() const;
void setMaxHeightEq( const std::string& maxHeightEq );
protected:
friend class UIManager;
friend class UISceneNode;
@@ -250,6 +266,10 @@ class EE_API UIWidget : public UINode {
std::string mSkinName;
std::vector<std::string> mClasses;
std::vector<std::string> mPseudoClasses;
std::string mMinWidthEq;
std::string mMinHeightEq;
std::string mMaxWidthEq;
std::string mMaxHeightEq;
explicit UIWidget( const std::string& tag );

View File

@@ -138,8 +138,6 @@ void Node::scheduledUpdate( const Time& ) {}
Node* Node::setSize( const Sizef& Size ) {
if ( Size != mSize ) {
Vector2f sizeChange( Size.x - mSize.x, Size.y - mSize.y );
setInternalSize( Size );
onSizeChange();

View File

@@ -308,15 +308,18 @@ void StyleSheetPropertyAnimation::onUpdate( const Time& time ) {
Float normalizedProgress = getCurrentProgress();
for ( size_t i = 1; i < mAnimationStepsTime.size(); i++ ) {
if ( normalizedProgress < mAnimationStepsTime[i] ) {
if ( normalizedProgress >= mAnimationStepsTime[i - 1] &&
normalizedProgress <= mAnimationStepsTime[i] ) {
curPos = i;
} else {
break;
}
}
if ( curPos - 1 >= 0 && curPos < static_cast<Int32>( mStates.size() ) ) {
tweenProperty( widget, normalizedProgress, mPropertyDef, mStates[curPos - 1],
Float relTime = mAnimationStepsTime[curPos] - mAnimationStepsTime[curPos - 1];
Float curTime = normalizedProgress - mAnimationStepsTime[curPos - 1];
Float relativeProgress = curTime / relTime;
tweenProperty( widget, relativeProgress, mPropertyDef, mStates[curPos - 1],
mStates[curPos], mAnimation.getTimingFunction(), mPropertyIndex,
isDone() );
}

View File

@@ -236,7 +236,20 @@ void StyleSheetSpecification::registerDefaultProperties() {
registerProperty( "outline-thickness", "" ).setType( PropertyType::NumberLength );
registerProperty( "animation-speed", "" ).setType( PropertyType::Vector2 );
registerProperty( "arc-start-angle", "" ).setType( PropertyType::NumberFloat );
registerProperty( "min-width", "" ).setType( PropertyType::NumberLength );
registerProperty( "min-width", "" )
.setType( PropertyType::NumberLength )
.setRelativeTarget( PropertyRelativeTarget::ContainingBlockWidth );
registerProperty( "min-height", "" )
.setType( PropertyType::NumberLength )
.setRelativeTarget( PropertyRelativeTarget::ContainingBlockHeight );
registerProperty( "max-width", "" )
.setType( PropertyType::NumberLength )
.setRelativeTarget( PropertyRelativeTarget::ContainingBlockWidth );
registerProperty( "max-height", "" )
.setType( PropertyType::NumberLength )
.setRelativeTarget( PropertyRelativeTarget::ContainingBlockHeight );
registerProperty( "min-margin-right", "" ).setType( PropertyType::NumberLength );
registerProperty( "min-icon-space", "" ).setType( PropertyType::NumberLength );
@@ -329,7 +342,6 @@ void StyleSheetSpecification::registerDefaultProperties() {
registerProperty( "max-edge-resistance", "0" ).setType( PropertyType::NumberFloat );
registerProperty( "timing-function", "linear" ).setType( PropertyType::String );
// Shorthands
registerShorthand( "margin", {"margin-top", "margin-right", "margin-bottom", "margin-left"},
ShorthandType::Box );

View File

@@ -16,7 +16,10 @@ UILinearLayout* UILinearLayout::NewHorizontal() {
}
UILinearLayout::UILinearLayout() :
UILayout( "linearlayout" ), mOrientation( UIOrientation::Vertical ) {
UILayout( "linearlayout" ),
mOrientation( UIOrientation::Vertical ),
mHPacking( false ),
mVPacking( false ) {
clipEnable();
}
@@ -65,6 +68,9 @@ void UILinearLayout::pack() {
}
void UILinearLayout::packVertical() {
if ( mVPacking )
return;
mVPacking = true;
bool sizeChanged = false;
Sizef size( getSize() );
@@ -224,15 +230,22 @@ void UILinearLayout::packVertical() {
getParent()->asType<UILinearLayout>()->getOrientation() ==
UIOrientation::Horizontal ) ) {
setInternalWidth( maxX );
mVPacking = false;
packVertical();
notifyLayoutAttrChangeParent();
}
}
alignAgainstLayout();
if ( getParent()->isUINode() && !getParent()->asType<UINode>()->ownsChildPosition() ) {
alignAgainstLayout();
}
mVPacking = false;
}
void UILinearLayout::packHorizontal() {
if ( mHPacking )
return;
mHPacking = true;
bool sizeChanged = false;
Sizef size( getSize() );
@@ -268,7 +281,6 @@ void UILinearLayout::packHorizontal() {
if ( sizeChanged ) {
setInternalSize( size );
;
}
Node* ChildLoop = mChild;
@@ -304,11 +316,11 @@ void UILinearLayout::packHorizontal() {
widget->getLayoutWeight() == 0 &&
widget->getSize().getWidth() !=
getSize().getWidth() - widget->getLayoutMargin().Left -
widget->getLayoutMargin().Top - mPadding.Left - mPadding.Right ) {
widget->setSize( getSize().getWidth(), widget->getSize().getWidth() -
widget->getLayoutMargin().Left -
widget->getLayoutMargin().Top -
mPadding.Left - mPadding.Right );
widget->getLayoutMargin().Right - mPadding.Left - mPadding.Right ) {
widget->setSize( getSize().getWidth() - widget->getLayoutMargin().Left -
widget->getLayoutMargin().Right - mPadding.Left -
mPadding.Right,
widget->getSize().getHeight() );
}
}
@@ -392,12 +404,16 @@ void UILinearLayout::packHorizontal() {
getParent()->asType<UILinearLayout>()->getOrientation() ==
UIOrientation::Vertical ) ) {
setInternalHeight( maxY );
mHPacking = false;
packHorizontal();
notifyLayoutAttrChangeParent();
}
}
alignAgainstLayout();
if ( getParent()->isUINode() && !getParent()->asType<UINode>()->ownsChildPosition() ) {
alignAgainstLayout();
}
mHPacking = false;
}
Sizei UILinearLayout::getTotalUsedSize() {

View File

@@ -681,6 +681,7 @@ void UIMenu::fixMenuPos( Vector2f& Pos, UIMenu* Menu, UIMenu* Parent, UIMenuSubM
qPos.Right = qPos.Left + Menu->getPixelsSize().getWidth();
qPos.Top = Pos.y;
qPos.Bottom = qPos.Top + Menu->getPixelsSize().getHeight();
Vector2f oriPos( Pos );
if ( !qScreen.contains( qPos ) ) {
Pos.y =
@@ -701,6 +702,10 @@ void UIMenu::fixMenuPos( Vector2f& Pos, UIMenu* Menu, UIMenu* Parent, UIMenuSubM
Menu->getPixelsSize().getHeight();
qPos.Top = Pos.y;
qPos.Bottom = qPos.Top + Menu->getPixelsSize().getHeight();
if ( !qScreen.contains( qPos ) ) {
Pos = oriPos;
}
}
}
}

View File

@@ -12,10 +12,10 @@ UIMenuSubMenu::UIMenuSubMenu() :
UIMenuItem( "menu::submenu" ),
mSubMenu( NULL ),
mArrow( NULL ),
mTimeOver( 0.f ),
mMaxTime( 200.f ),
mMaxTime( Milliseconds( 200.f ) ),
mCbId( 0 ),
mCbId2( 0 ) {
mCbId2( 0 ),
mCurWait( NULL ) {
mArrow = UINode::New();
mArrow->setParent( this );
mArrow->setFlags( UI_AUTO_SIZE );
@@ -89,20 +89,6 @@ UIMenu* UIMenuSubMenu::getSubMenu() const {
return mSubMenu;
}
Uint32 UIMenuSubMenu::onMouseMove( const Vector2i& Pos, const Uint32& Flags ) {
UIMenuItem::onMouseMove( Pos, Flags );
if ( NULL != mSceneNode && NULL != mSubMenu && !mSubMenu->isVisible() ) {
mTimeOver += mSceneNode->getElapsed().asMilliseconds();
if ( mTimeOver >= mMaxTime ) {
showSubMenu();
}
}
return 1;
}
void UIMenuSubMenu::showSubMenu() {
mSubMenu->setParent( getParent()->getParent() );
@@ -120,12 +106,26 @@ void UIMenuSubMenu::showSubMenu() {
}
}
Uint32 UIMenuSubMenu::onMouseOver( const Vector2i& position, const Uint32& flags ) {
Action* openMenu = Actions::Runnable::New(
[&] {
if ( isMouseOver() )
showSubMenu();
mCurWait = NULL;
},
mMaxTime );
runAction( openMenu );
return UIMenuItem::onMouseOver( position, flags );
}
Uint32 UIMenuSubMenu::onMouseLeave( const Vector2i& Pos, const Uint32& Flags ) {
UIMenuItem::onMouseLeave( Pos, Flags );
mTimeOver = 0;
return 1;
if ( NULL != mCurWait ) {
removeAction( mCurWait );
mCurWait = NULL;
}
return UIMenuItem::onMouseLeave( Pos, Flags );
}
UINode* UIMenuSubMenu::getArrow() const {
@@ -170,11 +170,11 @@ bool UIMenuSubMenu::inheritsFrom( const Uint32 Type ) {
return false;
}
Float UIMenuSubMenu::getMouseOverTimeShowMenu() const {
const Time& UIMenuSubMenu::getMouseOverTimeShowMenu() const {
return mMaxTime;
}
void UIMenuSubMenu::setMouseOverTimeShowMenu( const Float& maxTime ) {
void UIMenuSubMenu::setMouseOverTimeShowMenu( const Time& maxTime ) {
mMaxTime = maxTime;
}

View File

@@ -595,8 +595,8 @@ void UINode::drawBackground() {
void UINode::drawForeground() {
if ( ( mFlags & UI_FILL_FOREGROUND ) && NULL != mForeground ) {
mForeground->draw( Vector2f( mScreenPosi.x, mScreenPosi.y ),
Sizef( eefloor( mSize.getWidth() ), eefloor( mSize.getHeight() ) ),
(Uint32)mAlpha );
Sizef( eefloor( mSize.getWidth() ), eefloor( mSize.getHeight() ) ),
(Uint32)mAlpha );
}
}
@@ -1006,6 +1006,10 @@ void UINode::setDragging( const bool& dragging ) {
}
}
bool UINode::ownsChildPosition() const {
return 0 != ( mFlags & UI_OWNS_CHILDS_POSITION );
}
void UINode::setDragButton( const Uint32& Button ) {
mDragButton = Button;
}
@@ -1037,6 +1041,7 @@ Uint32 UINode::onFocusLoss() {
}
Float UINode::convertLength( const CSS::StyleSheetLength& length, const Float& containerLength ) {
// TODO: Fix asPixels parameters
return length.asPixels( containerLength, getSceneNode()->getPixelsSize(),
getSceneNode()->getDPI(), 12, 12 );
}

View File

@@ -36,7 +36,9 @@ void UIRelativeLayout::onParentSizeChange( const Vector2f& ) {
}
void UIRelativeLayout::fixChilds() {
setInternalPosition( Vector2f( mLayoutMargin.Left, mLayoutMargin.Top ) );
if ( getParent()->isUINode() && !getParent()->asType<UINode>()->ownsChildPosition() ) {
setInternalPosition( Vector2f( mLayoutMargin.Left, mLayoutMargin.Top ) );
}
if ( getLayoutWidthRule() == LayoutSizeRule::MatchParent ) {
Rectf padding = Rectf();

View File

@@ -19,12 +19,14 @@ UIScrollView::UIScrollView() :
mScrollView( NULL ),
mSizeChangeCb( 0 ),
mPosChangeCb( 0 ) {
mFlags |= UI_OWNS_CHILDS_POSITION;
enableReportSizeChangeToChilds();
mVScroll->setParent( this );
mHScroll->setParent( this );
mContainer->setParent( this );
mContainer->clipEnable();
mContainer->setFlags( UI_OWNS_CHILDS_POSITION );
mContainer->enableReportSizeChangeToChilds();
mVScroll->addEventListener( Event::OnValueChange,

View File

@@ -28,8 +28,10 @@ UIViewPager::UIViewPager() :
mCurrentPage( 0 ),
mTotalPages( 0 ),
mTimingFunction( Ease::Interpolation::SineIn ) {
mFlags |= UI_OWNS_CHILDS_POSITION;
mContainer = UIWidget::New();
mContainer->setParent( this );
mContainer->setFlags( UI_OWNS_CHILDS_POSITION );
}
UIViewPager::~UIViewPager() {
@@ -49,8 +51,17 @@ void UIViewPager::onChildCountChange( Node* child, const bool& removed ) {
if ( !removed && child != mContainer ) {
child->setParent( mContainer );
}
updateChilds();
mTotalPages = mContainer->getChildCount();
if ( child != mContainer ) {
mTotalPages = mContainer->getChildCount();
updateChilds();
}
if ( !removed && child != mContainer ) {
child->addEventListener( Event::OnPositionChange,
[&]( const Event* event ) { updateChilds(); } );
}
UIWidget::onChildCountChange( child, removed );
}
@@ -172,8 +183,9 @@ void UIViewPager::limitDisplacement() {
void UIViewPager::setDisplacement( const Float& val ) {
mDisplacement = val;
Float normalizedDisplacement = mDisplacement - mCurrentPage * getLength();
if ( eeabs( mDisplacement ) > mDragResistance ) {
if ( eeabs( normalizedDisplacement ) > mDragResistance ) {
if ( mOrientation == UIOrientation::Horizontal ) {
mContainer->setPixelsPosition(
Vector2f( -mDisplacement, mContainer->getPixelsPosition().y ) );

View File

@@ -311,6 +311,30 @@ Node* UIWidget::setSize( const Sizef& size ) {
if ( s.y < mMinControlSize.y )
s.y = mMinControlSize.y;
if ( !mMinWidthEq.empty() ) {
Float length =
lengthFromValue( mMinWidthEq, CSS::PropertyRelativeTarget::ContainingBlockWidth );
s.x = eemax( s.x, length );
}
if ( !mMinHeightEq.empty() ) {
Float length =
lengthFromValue( mMinHeightEq, CSS::PropertyRelativeTarget::ContainingBlockHeight );
s.y = eemax( s.y, length );
}
if ( !mMaxWidthEq.empty() ) {
Float length =
lengthFromValue( mMaxWidthEq, CSS::PropertyRelativeTarget::ContainingBlockWidth );
s.x = eemin( s.x, length );
}
if ( !mMaxHeightEq.empty() ) {
Float length =
lengthFromValue( mMaxWidthEq, CSS::PropertyRelativeTarget::ContainingBlockHeight );
s.y = eemin( s.y, length );
}
return UINode::setSize( s );
}
@@ -577,6 +601,50 @@ Float UIWidget::lengthFromValueAsDp( const StyleSheetProperty& property, const F
defaultContainerValue, property.getIndex() );
}
const std::string& UIWidget::getMinWidthEq() const {
return mMinWidthEq;
}
void UIWidget::setMinWidthEq( const std::string& minWidthEq ) {
if ( mMinWidthEq != minWidthEq ) {
mMinWidthEq = minWidthEq;
setSize( mSize );
}
}
const std::string& UIWidget::getMinHeightEq() const {
return mMinHeightEq;
}
void UIWidget::setMinHeightEq( const std::string& minHeightEq ) {
if ( mMinHeightEq != minHeightEq ) {
mMinHeightEq = minHeightEq;
setSize( mSize );
}
}
const std::string& UIWidget::getMaxWidthEq() const {
return mMaxWidthEq;
}
void UIWidget::setMaxWidthEq( const std::string& maxWidthEq ) {
if ( mMaxWidthEq != maxWidthEq ) {
mMaxWidthEq = maxWidthEq;
setSize( mSize );
}
}
const std::string& UIWidget::getMaxHeightEq() const {
return mMaxHeightEq;
}
void UIWidget::setMaxHeightEq( const std::string& maxHeightEq ) {
if ( mMaxHeightEq != maxHeightEq ) {
mMaxHeightEq = maxHeightEq;
setSize( mSize );
}
}
const Rectf& UIWidget::getPadding() const {
return mPadding;
}
@@ -1105,6 +1173,14 @@ std::string UIWidget::getPropertyString( const PropertyDefinition* propertyDef,
return getScaleOriginPoint().toString();
case PropertyId::BlendMode:
return "";
case PropertyId::MinWidth:
return mMinWidthEq;
case PropertyId::MaxWidth:
return mMaxWidthEq;
case PropertyId::MinHeight:
return mMinHeightEq;
case PropertyId::MaxHeight:
return mMaxHeightEq;
default:
break;
}
@@ -1438,6 +1514,18 @@ bool UIWidget::applyProperty( const StyleSheetProperty& attribute ) {
case PropertyId::ScaleOriginPoint:
setScaleOriginPoint( attribute.asOriginPoint() );
break;
case PropertyId::MinWidth:
setMinWidthEq( attribute.getValue() );
break;
case PropertyId::MaxWidth:
setMaxWidthEq( attribute.getValue() );
break;
case PropertyId::MinHeight:
setMinHeightEq( attribute.getValue() );
break;
case PropertyId::MaxHeight:
setMaxHeightEq( attribute.getValue() );
break;
default:
attributeSet = false;
break;