diff --git a/bin/assets/layouts/test_widgets.xml b/bin/assets/layouts/test_widgets.xml index a1840c0f1..e5d0d0a72 100644 --- a/bin/assets/layouts/test_widgets.xml +++ b/bin/assets/layouts/test_widgets.xml @@ -1,9 +1,9 @@ - - - + + + @@ -11,7 +11,7 @@ Test 2 Test 3 - + Test Test 2 @@ -29,6 +29,7 @@ + @@ -38,7 +39,7 @@ - + @@ -64,4 +65,3 @@ - diff --git a/bin/assets/ui/breeze.css b/bin/assets/ui/breeze.css new file mode 100644 index 000000000..fb329d5f5 --- /dev/null +++ b/bin/assets/ui/breeze.css @@ -0,0 +1,325 @@ + +:root { + --primary: #3daee9; + --back: #31363b; + --font: #eff0f1; + --button-back: #30353a; + --button-border: #6b6f73; + --button-radius: 2dp; + --base-horizontal-padding: 5dp; + --base-vertical-padding: 7dp; + --border-width: 1dp; + --list-back: #232629; + --separator: #383a3d; + --item-hover: #284150; + --scroll-button: #6b6d6f; + --slider-back: #676a6e; + --slider-button: #31363b; + --slider-border: #787b80; + --scrollbar-border: #373a3d; + --scrollbar-button: #4085a9; + --scrollbar-hback-hover: #606365; +} + +* { + color: var(--font); + font-size: 11dp; + selection-back-color: var(--primary); +} + +PushButton, +SelectButton, +DropDownList { + padding-left: var(--base-horizontal-padding); + padding-right: var(--base-horizontal-padding); + padding-top: var(--base-vertical-padding); + padding-bottom: var(--base-vertical-padding); + background-color: var(--button-back); + border-color: var(--button-border); + border-radius: var(--button-radius); + border-width: var(--border-width); + transition: all 0.125s; +} + +PushButton:hover, +DropDownList:hover, +SelectButton:hover { + border-color: var(--primary); +} + +PushButton:pressed, +SelectButton:pressed, +SelectButton:selected, +SelectButton:selectedpressed { + background-color: var(--primary); +} + +CheckBox::active, +CheckBox::inactive { + width: 12dp; + height: 12dp; + border-width: 1dp; + border-radius: var(--button-radius); +} + +CheckBox::inactive { + border-color: var(--button-border); +} + +CheckBox::active { + border-color: var(--primary); + background-image: rectangle(solid, var(--primary)); + background-size: 70% 70%; + background-position: center; +} + +RadioButton::active, +RadioButton::inactive { + width: 12dp; + height: 12dp; + border-width: 1dp; + border-radius: 100%; +} + +RadioButton::inactive { + border-color: var(--button-border); +} + +RadioButton::active { + border-color: var(--primary); + background-image: circle(solid, var(--primary)); + background-size: 8dp 8dp; + background-position: 6dp 6dp; +} + +ListBox, +DropDownList::ListBox { + background-color: var(--list-back); + border-color: var(--button-border); + border-radius: var(--button-radius); + border-width: var(--border-width); + transition: all 0.15; +} + +ListBox::item { + padding-left: 4dp; + background-image: linear-gradient( to right, #232629, #383a3d ), linear-gradient( to right, #383a3d, #232629 ); + background-size: 50% 1dp, 50% 1dp; + background-position: left bottom, right bottom; +} + +ListBox:hover { + border-color: var(--primary); +} + +ListBox::item:hover { + background-color: var(--item-hover); +} + +ListBox::item:selected { + background-color: var(--primary); +} + +DropDownList::ListBox::item { + padding-left: 4dp; +} + +DropDownList::ListBox::item:hover, +DropDownList::ListBox::item:selected { + background-color: var(--primary); +} + +TextInput { + padding-left: var(--base-horizontal-padding); + padding-right: var(--base-horizontal-padding); + padding-top: var(--base-vertical-padding); + padding-bottom: var(--base-vertical-padding); + background-color: var(--list-back); + border-color: var(--button-border); + border-radius: var(--button-radius); + border-width: var(--border-width); + transition: all 0.15; +} + +TextInput:hover, +TextInput:focus, +SpinBox:hover, +SpinBox:focus { + border-color: var(--primary); +} + +SpinBox { + background-color: var(--list-back); + border-color: var(--button-border); + border-radius: var(--button-radius); + border-width: var(--border-width); + transition: all 0.15; +} + +SpinBox::input { + padding-left: var(--base-horizontal-padding); + padding-right: var(--base-horizontal-padding); + padding-top: var(--base-vertical-padding); + padding-bottom: var(--base-vertical-padding); +} + +SpinBox::input, +SpinBox::input::hover, +SpinBox::input::focus { + border-width: 0dp; + border-color: transparent; +} + +SpinBox::btnup, +SpinBox::btndown { + width: 13dp; + height: 13dp; +} + +TextEdit { + background-color: var(--list-back); + border-color: var(--button-border); + border-radius: var(--button-radius); + border-width: var(--border-width); +} + +TextEdit::input { + padding-left: var(--base-horizontal-padding); + padding-right: var(--base-horizontal-padding); + padding-top: var(--base-vertical-padding); + padding-bottom: var(--base-vertical-padding); +} + +Tooltip { + padding-left: var(--base-horizontal-padding); + padding-right: var(--base-horizontal-padding); + padding-top: var(--base-vertical-padding); + padding-bottom: var(--base-vertical-padding); + background-color: var(--button-back); + border-color: var(--button-border); + border-radius: var(--button-radius); + border-width: var(--border-width); + font-style: shadow; +} + +Slider { + min-width: 11dp; + min-height: 11dp; + half-slider: true; +} + +Slider::vback { + background-color: var(--slider-back); + border-radius: 4dp; + min-width: 5dp; + min-height: 64dp; + transition: all 0.15s; +} + +Slider::hback { + background-color: var(--slider-back); + border-radius: 4dp; + min-width: 64dp; + min-height: 5dp; + transition: all 0.15s; +} + +Slider::vbutton, +Slider::hbutton { + background-color: var(--slider-button); + border-color: var(--slider-border); + border-width: 1dp; + border-radius: 100%; + min-width: 11dp; + min-height: 11dp; +} + +Slider::vbutton:hover, +Slider::vbutton:focus, +Slider::hbutton:hover, +Slider::hbutton:focus { + border-color: var(--primary); +} + +ScrollBar { + scrollbar-style: no-buttons; +} + +ScrollBar::hback { + min-height: 6dp; + border-radius: 4dp; + background-color: transparent; +} + +ScrollBar::vback { + min-width: 6dp; + border-radius: 4dp; + background-color: transparent; +} + +ScrollBar::hslider, +ScrollBar::vslider { + border-width: 1dp; + border-color: var(--scrollbar-border); + background-color: var(--list-back); + padding: 4dp; + transition: all 0.15s; +} + +ScrollBar::hbutton { + min-height: 6dp; + background-color: var(--scrollbar-button); + border-radius: 4dp; + border-width: 0dp; + transition: all 0.15s; +} + +ScrollBar::vbutton { + min-width: 6dp; + background-color: var(--scrollbar-button); + border-radius: 4dp; + border-width: 0dp; + transition: all 0.15s; +} + +ScrollBar::hslider:hover ScrollBar::hback, +ScrollBar::vslider:hover ScrollBar::vback { + background-color: var(--scrollbar-hback-hover); +} + +ScrollBar::vslider:hover ScrollBar::vbutton, +ScrollBar::vbutton:hover, +ScrollBar::hslider:hover ScrollBar::hbutton, +ScrollBar::hbutton:hover { + background-color: var(--primary); +} + +ProgressBar { + min-height: 6dp; +} + +ProgressBar::filler { + border-radius: 4dp; + background-color: var(--primary); +} + +TabWidget { + tab-separation: -1dp; +} + +TabWidget::TabContainer { + background-image: rectangle(solid, #2f3030); + background-size: 100% 1dp; + background-position-y: bottom; + min-height: 24dp; +} + +Tab { + background-color: var(--list-back); + min-height: 24dp; +} + +Tab::text { + padding-left: 4dp; + padding-right: 4dp; +} diff --git a/docs/articles/cssspecification.md b/docs/articles/cssspecification.md index 8ab76456b..b8d2c7a0f 100644 --- a/docs/articles/cssspecification.md +++ b/docs/articles/cssspecification.md @@ -1398,11 +1398,11 @@ Defines how the scrollbar should fit inside an scrollable element. --- -### scrollbar-type +### scrollbar-style Sets the scrollbar style (for the moment defines if it contains buttons at its edge or it's simply a bar). -* Applicable to: EE::UI::UIScrollBar (ScrollBar), EE::UI::UIListBox (ListBox), EE::UI::UIDropDownLis +* Applicable to: EE::UI::UIScrollBar (ScrollBar), EE::UI::UIListBox (ListBox), EE::UI::UIDropDownList (DropDownList), EE::UI::UITable (Table), EE::UI::UIScrollView (ScrollView) * Data Type: [string-list](#string-list-data-type) * Value List: diff --git a/include/eepp/core/string.hpp b/include/eepp/core/string.hpp index 08141adad..cd7e27d26 100644 --- a/include/eepp/core/string.hpp +++ b/include/eepp/core/string.hpp @@ -189,6 +189,18 @@ class EE_API String { */ static bool endsWith( const String& haystack, const String& needle ); + /** @return True if a string contains a substring. + * @param haystack The string to search in. + * @param needle The searched string. + */ + static bool contains( const std::string& haystack, const std::string& needle ); + + /** @return True if a string contains a substring. + * @param haystack The string to search in. + * @param needle The searched string. + */ + static bool contains( const String& haystack, const String& needle ); + /** Replace all occurrences of the search string with the replacement string. */ static void replaceAll( std::string& target, const std::string& that, const std::string& with ); diff --git a/include/eepp/graphics/text.hpp b/include/eepp/graphics/text.hpp index db11a20db..b58ca4f01 100644 --- a/include/eepp/graphics/text.hpp +++ b/include/eepp/graphics/text.hpp @@ -118,7 +118,7 @@ class EE_API Text { void setStyleConfig( const FontStyleConfig& styleConfig ); /** Finds the closest cursor position to the point position */ - Int32 findCharacterFromPos( const Vector2i& pos ); + Int32 findCharacterFromPos( const Vector2i& pos, bool returnNearest = true ); /** Simulates a selection request and return the initial and end cursor position when the * selection worked. Otherwise both parameters will be -1. */ diff --git a/include/eepp/math/vector2.hpp b/include/eepp/math/vector2.hpp index 740342336..0291e2705 100644 --- a/include/eepp/math/vector2.hpp +++ b/include/eepp/math/vector2.hpp @@ -23,29 +23,29 @@ template class Vector2 { Vector2 copy(); /** @return The Dot product of the 2D vectors. */ - T dot( const Vector2& V2 ); + T dot( const Vector2& V2 ) const; /** @return The Cross product of the 2D vectors. */ - T cross( const Vector2& V2 ); + T cross( const Vector2& V2 ) const; /** @return The perpendicular vector */ - Vector2 perp(); + Vector2 perp() const; /** @return The reveser perpendicular vector */ - Vector2 rPerp(); + Vector2 rPerp() const; /** Uses complex multiplication to rotate self by vec. Scaling will occur if self is not a unit * vector. */ - Vector2 rotate( const Vector2& V2 ); + Vector2 rotate( const Vector2& V2 ) const; /** Inverse of Vector2::rotate */ - Vector2 unrotate( const Vector2& V2 ); + Vector2 unrotate( const Vector2& V2 ) const; /** @return The vector Length */ - T length(); + T length() const; /** @return The square of the length of the 2D vector. */ - T lengthSq(); + T lengthSq() const; /** Normalize the vector */ void normalize(); @@ -54,7 +54,7 @@ template class Vector2 { void clamp( T len ); /** @return The unit length vector for the given angle (radians) */ - Vector2 forAngle( const T& a ); + Vector2 forAngle( const T& a ) const; /** @return The angular direction vector is pointing in (radians). */ T toAngle(); @@ -66,25 +66,25 @@ template class Vector2 { void rotate( const T& Angle, const Vector2& RotationCenter ); /** @return The distance between two vectors */ - T distance( const Vector2& Vec ); + T distance( const Vector2& Vec ) const; /** @return The square of the distance between two vectors */ - T distanceSq( const Vector2& Vec ); + T distanceSq( const Vector2& Vec ) const; /** @return True if the distance between the two vectors is less than Dist */ - bool nearDist( const Vector2& Vec, T Dist ); + bool nearDist( const Vector2& Vec, T Dist ) const; /** @return The spherical linear interpolation between two 2D vectors. */ - Vector2 sphericalLerp( const Vector2& Vec, T Time ); + Vector2 sphericalLerp( const Vector2& Vec, T Time ) const; /** Spherical linear interpolation between two vectors */ - Vector2 sphericalLerpConst( const Vector2& Vec, T Angle ); + Vector2 sphericalLerpConst( const Vector2& Vec, T Angle ) const; /** Performs a linear interpolation between two 2D vectors. */ - Vector2 lerp( const Vector2& Vec, T Time ); + Vector2 lerp( const Vector2& Vec, T Time ) const; /** @return A vector interpolated from self towards Vec with length Dist. */ - Vector2 lerpConst( const Vector2& Vec, T Dist ); + Vector2 lerpConst( const Vector2& Vec, T Dist ) const; /** Scales the vector position against another vector */ void scale( const Vector2& scale, const Vector2& Center ); @@ -92,15 +92,15 @@ template class Vector2 { /** Scales the vector position against another vector */ void scale( const T& scale, const Vector2& Center ); - Vector2 ceil(); + Vector2 ceil() const; - Vector2 floor(); + Vector2 floor() const; - Vector2 abs(); + Vector2 abs() const; - Vector2 asFloat(); + Vector2 asFloat() const; - Vector2 asInt(); + Vector2 asInt() const; T x; T y; @@ -114,17 +114,17 @@ template const Vector2 Vector2::One = Vector2( 1, 1 ); template const Vector2 Vector2::Zero = Vector2( 0, 0 ); -template Vector2 Vector2::lerp( const Vector2& Vec, T Time ) { +template Vector2 Vector2::lerp( const Vector2& Vec, T Time ) const { return *this * ( 1 - Time ) + Vec * Time; } -template Vector2 Vector2::lerpConst( const Vector2& Vec, T Dist ) { +template Vector2 Vector2::lerpConst( const Vector2& Vec, T Dist ) const { Vector2 t( *this + ( Vec - *this ) ); t.clamp( Dist ); return t; } -template Vector2 Vector2::sphericalLerp( const Vector2& Vec, T Time ) { +template Vector2 Vector2::sphericalLerp( const Vector2& Vec, T Time ) const { T omega = eeacos( dot( Vec ) ); if ( omega ) { @@ -137,7 +137,8 @@ template Vector2 Vector2::sphericalLerp( const Vector2& Ve } } -template Vector2 Vector2::sphericalLerpConst( const Vector2& Vec, T Angle ) { +template +Vector2 Vector2::sphericalLerpConst( const Vector2& Vec, T Angle ) const { T angle = eeacos( dot( Vec ) ); return lerp( Vec, ( ( Angle < angle ) ? Angle : angle ) / angle ); } @@ -305,35 +306,35 @@ template void Vector2::scale( const T& scale, const Vector2& scale( Vector2( scale, scale ), Center ); } -template T Vector2::dot( const Vector2& V2 ) { +template T Vector2::dot( const Vector2& V2 ) const { return x * V2.x + y * V2.y; } -template T Vector2::cross( const Vector2& V2 ) { +template T Vector2::cross( const Vector2& V2 ) const { return x * V2.x - y * V2.y; } -template Vector2 Vector2::perp() { +template Vector2 Vector2::perp() const { return Vector2( -y, x ); } -template Vector2 Vector2::rPerp() { +template Vector2 Vector2::rPerp() const { return Vector2( y, -x ); } -template Vector2 Vector2::rotate( const Vector2& V2 ) { +template Vector2 Vector2::rotate( const Vector2& V2 ) const { return Vector2( x * V2.x - y * V2.y, x * V2.y + y * V2.x ); } -template Vector2 Vector2::unrotate( const Vector2& V2 ) { +template Vector2 Vector2::unrotate( const Vector2& V2 ) const { return Vector2( x * V2.x - y * V2.y, x * V2.x + y * V2.y ); } -template T Vector2::length() { +template T Vector2::length() const { return eesqrt( dot( Vector2( x, y ) ) ); } -template T Vector2::lengthSq() { +template T Vector2::lengthSq() const { return dot( Vector2( x, y ) ); } @@ -348,7 +349,7 @@ template void Vector2::normalize() { } } -template Vector2 Vector2::forAngle( const T& a ) { +template Vector2 Vector2::forAngle( const T& a ) const { return Vector2( eecos( a ), eesin( a ) ); } @@ -356,11 +357,11 @@ template T Vector2::toAngle() { return eeatan2( y, x ); } -template T Vector2::distance( const Vector2& Vec ) { +template T Vector2::distance( const Vector2& Vec ) const { return eesqrt( ( x - Vec.x ) * ( x - Vec.x ) + ( y - Vec.y ) * ( y - Vec.y ) ); } -template T Vector2::distanceSq( const Vector2& Vec ) { +template T Vector2::distanceSq( const Vector2& Vec ) const { return ( *this - Vec ).lengthSq(); } @@ -373,27 +374,27 @@ template void Vector2::clamp( T len ) { } } -template Vector2 Vector2::ceil() { +template Vector2 Vector2::ceil() const { return Vector2( eeceil( x ), eeceil( y ) ); } -template Vector2 Vector2::floor() { +template Vector2 Vector2::floor() const { return Vector2( eefloor( x ), eefloor( y ) ); } -template Vector2 Vector2::abs() { +template Vector2 Vector2::abs() const { return Vector2( eeabs( x ), eeabs( y ) ); } -template Vector2 Vector2::asFloat() { +template Vector2 Vector2::asFloat() const { return Vector2( x, y ); } -template Vector2 Vector2::asInt() { +template Vector2 Vector2::asInt() const { return Vector2( x, y ); } -template bool Vector2::nearDist( const Vector2& Vec, T Dist ) { +template bool Vector2::nearDist( const Vector2& Vec, T Dist ) const { return 0 != ( distanceSq( Vec ) < Dist * Dist ); } diff --git a/include/eepp/ui/uinode.hpp b/include/eepp/ui/uinode.hpp index d11196af7..a698ed763 100644 --- a/include/eepp/ui/uinode.hpp +++ b/include/eepp/ui/uinode.hpp @@ -248,9 +248,19 @@ class EE_API UINode : public Node { UISceneNode* getUISceneNode(); + + void setMinWidth( const Float& width ); + + void setMinHeight( const Float& height ); + + void setMinSize( const Sizef& size ); + + const Sizef& getMinSize() const; + protected: Vector2f mDpPos; Sizef mDpSize; + Sizef mMinSize; Uint32 mFlags; Uint32 mState; UISkinState* mSkinState; diff --git a/include/eepp/ui/uiprogressbar.hpp b/include/eepp/ui/uiprogressbar.hpp index 12933a06f..02f370671 100644 --- a/include/eepp/ui/uiprogressbar.hpp +++ b/include/eepp/ui/uiprogressbar.hpp @@ -7,6 +7,8 @@ namespace EE { namespace UI { +class UIProgressBarFiller; + class EE_API UIProgressBar : public UIWidget { public: class StyleConfig { @@ -36,8 +38,6 @@ class EE_API UIProgressBar : public UIWidget { const Float& getTotalSteps() const; - virtual void draw(); - virtual void scheduledUpdate( const Time& time ); void setMovementSpeed( const Vector2f& Speed ); @@ -62,17 +62,20 @@ class EE_API UIProgressBar : public UIWidget { const StyleConfig& getStyleConfig() const; protected: + friend class UIProgressBarFiller; StyleConfig mStyleConfig; Float mProgress; Float mTotalSteps; UITextView* mTextBox; Vector2f mOffset; - UISkin* mFillerSkin; + UIProgressBarFiller* mFiller; virtual Uint32 onValueChange(); virtual void onSizeChange(); + virtual void onPaddingChange(); + virtual void onThemeLoaded(); void updateTextBox(); diff --git a/include/eepp/ui/uiscrollbar.hpp b/include/eepp/ui/uiscrollbar.hpp index 1f1595a82..1828e6623 100644 --- a/include/eepp/ui/uiscrollbar.hpp +++ b/include/eepp/ui/uiscrollbar.hpp @@ -60,7 +60,7 @@ class EE_API UIScrollBar : public UIWidget { ScrollBarType getScrollBarType() const; - void setScrollBarType( const ScrollBarType& scrollBarType ); + void setScrollBarStyle( const ScrollBarType& scrollBarType ); bool getExpandBackground() const; @@ -72,7 +72,7 @@ class EE_API UIScrollBar : public UIWidget { const Uint32& propertyIndex = 0 ); protected: - ScrollBarType mScrollBarType; + ScrollBarType mScrollBarStyle; UISlider* mSlider; UIWidget* mBtnUp; UIWidget* mBtnDown; @@ -90,6 +90,8 @@ class EE_API UIScrollBar : public UIWidget { virtual Uint32 onMessage( const NodeMessage* Msg ); virtual void onPaddingChange(); + + void updateOrientation(); }; }} // namespace EE::UI diff --git a/include/eepp/ui/uislider.hpp b/include/eepp/ui/uislider.hpp index fa8501659..94856ed3c 100644 --- a/include/eepp/ui/uislider.hpp +++ b/include/eepp/ui/uislider.hpp @@ -76,6 +76,7 @@ class EE_API UISlider : public UIWidget { UIOrientation mOrientation; bool mAllowHalfSliderOut; bool mExpandBackground; + bool mUpdating; UIWidget* mBackSlider; UIWidget* mSlider; Float mMinValue; @@ -103,6 +104,8 @@ class EE_API UISlider : public UIWidget { virtual void onAlphaChange(); virtual Uint32 onMessage( const NodeMessage* Msg ); + + void updateOrientation(); }; }} // namespace EE::UI diff --git a/include/eepp/ui/uispinbox.hpp b/include/eepp/ui/uispinbox.hpp index 02d6a8a93..14de3782c 100644 --- a/include/eepp/ui/uispinbox.hpp +++ b/include/eepp/ui/uispinbox.hpp @@ -61,8 +61,8 @@ class EE_API UISpinBox : public UIWidget { protected: UITextInput* mInput; - UINode* mPushUp; - UINode* mPushDown; + UIWidget* mPushUp; + UIWidget* mPushDown; Float mMinValue; Float mMaxValue; Float mValue; diff --git a/include/eepp/ui/uistyle.hpp b/include/eepp/ui/uistyle.hpp index ca288a9f2..65ab66d99 100644 --- a/include/eepp/ui/uistyle.hpp +++ b/include/eepp/ui/uistyle.hpp @@ -105,6 +105,8 @@ class EE_API UIStyle : public UIState { void removeAnimation( const CSS::PropertyDefinition* propertyDefinition, const Uint32& propertyIndex ); + + std::string varToVal( const std::string& varDef ); }; }} // namespace EE::UI diff --git a/include/eepp/ui/uitextinput.hpp b/include/eepp/ui/uitextinput.hpp index 1fb422f08..b85faf97a 100644 --- a/include/eepp/ui/uitextinput.hpp +++ b/include/eepp/ui/uitextinput.hpp @@ -109,8 +109,6 @@ class EE_API UITextInput : public UITextView { void autoPadding(); - virtual Uint32 onMouseClick( const Vector2i& position, const Uint32& flags ); - virtual Uint32 onMouseDown( const Vector2i& position, const Uint32& flags ); virtual Uint32 onMouseDoubleClick( const Vector2i& position, const Uint32& flags ); diff --git a/include/eepp/ui/uitextview.hpp b/include/eepp/ui/uitextview.hpp index da616e74d..f00f8c2c5 100644 --- a/include/eepp/ui/uitextview.hpp +++ b/include/eepp/ui/uitextview.hpp @@ -69,7 +69,7 @@ class EE_API UITextView : public UIWidget { const int& getNumLines() const; - const Vector2f& getAlignOffset() const; + Vector2f getAlignOffset() const; virtual void shrinkText( const Uint32& MaxWidth ); @@ -88,7 +88,6 @@ class EE_API UITextView : public UIWidget { Text* mTextCache; String mString; UIFontStyleConfig mFontStyleConfig; - Vector2f mAlignOffset; Vector2f mRealAlignOffset; Int32 mSelCurInit; Int32 mSelCurEnd; diff --git a/include/eepp/ui/uiwidget.hpp b/include/eepp/ui/uiwidget.hpp index 5ee6cb6ef..61fb76ab1 100644 --- a/include/eepp/ui/uiwidget.hpp +++ b/include/eepp/ui/uiwidget.hpp @@ -233,7 +233,6 @@ class EE_API UIWidget : public UINode { UITheme* mTheme; UIStyle* mStyle; UITooltip* mTooltip; - Sizef mMinControlSize; Rect mDistToBorder; Rect mLayoutMargin; Rectf mPadding; diff --git a/projects/linux/ee.files b/projects/linux/ee.files index 82c453b32..a4050e235 100644 --- a/projects/linux/ee.files +++ b/projects/linux/ee.files @@ -4,6 +4,7 @@ ../../bin/assets/layouts/test.css ../../bin/assets/layouts/test.xml ../../bin/assets/layouts/test_widgets.xml +../../bin/assets/ui/breeze.css ../../bin/assets/ui/uitheme.css ../../docs/articles/cssspecification.md ../../docs/articles/uiintroduction.md diff --git a/src/eepp/core/string.cpp b/src/eepp/core/string.cpp index 53cc0a16b..589a354f8 100644 --- a/src/eepp/core/string.cpp +++ b/src/eepp/core/string.cpp @@ -281,6 +281,14 @@ bool String::endsWith( const String& haystack, const String& needle ) { haystack.compare( haystack.size() - needle.size(), needle.size(), needle ) == 0; } +bool String::contains( const std::string& haystack, const std::string& needle ) { + return haystack.find( needle ) != std::string::npos; +} + +bool String::contains( const String& haystack, const String& needle ) { + return haystack.find( needle ) != String::InvalidPos; +} + void String::replaceAll( std::string& target, const std::string& that, const std::string& with ) { std::string::size_type pos = 0; diff --git a/src/eepp/graphics/text.cpp b/src/eepp/graphics/text.cpp index 831a48fec..c622b2398 100644 --- a/src/eepp/graphics/text.cpp +++ b/src/eepp/graphics/text.cpp @@ -7,6 +7,7 @@ #include #include #include +#include namespace EE { namespace Graphics { @@ -281,7 +282,7 @@ Vector2f Text::findCharacterPos( std::size_t index ) const { return mGlyphPos[index]; } -Int32 Text::findCharacterFromPos( const Vector2i& pos ) { +Int32 Text::findCharacterFromPos( const Vector2i& pos, bool returnNearest ) { if ( NULL == mFont ) return 0; @@ -289,8 +290,12 @@ Int32 Text::findCharacterFromPos( const Vector2i& pos ) { Float Width = 0, lWidth = 0, Height = vspace, lHeight = 0; Uint32 CharID; Uint32 prevChar = 0; + Int32 nearest = -1; + Int32 minDist = std::numeric_limits::max(); + Int32 curDist = -1; std::size_t tSize = mString.size(); bool bold = ( mStyle & Bold ) != 0; + Vector2f fpos( pos.asFloat() ); Float hspace = static_cast( mFont->getGlyph( L' ', mRealFontSize, bold ).advance ); @@ -318,7 +323,7 @@ Int32 Text::findCharacterFromPos( const Vector2i& pos ) { if ( pos.x <= Width && pos.x >= lWidth && pos.y <= Height && pos.y >= lHeight ) { if ( i + 1 < tSize ) { Int32 curDist = eeabs( pos.x - lWidth ); - Int32 nextDist = eeabs( pos.x - ( lWidth + glyph.advance ) ); + Int32 nextDist = eeabs( pos.x - Width ); if ( nextDist < curDist ) { return i + 1; @@ -328,6 +333,15 @@ Int32 Text::findCharacterFromPos( const Vector2i& pos ) { return i; } + if ( returnNearest ) { + curDist = eeabs( fpos.distance( Vector2f( Width - ( Width - lWidth ) * 0.5f, + Height - ( Height - lHeight ) * 0.5f ) ) ); + if ( curDist < minDist ) { + nearest = i; + minDist = curDist; + } + } + if ( CharID == '\n' ) { lHeight = Height; Height += vspace; @@ -342,7 +356,7 @@ Int32 Text::findCharacterFromPos( const Vector2i& pos ) { return tSize; } - return -1; + return nearest; } static bool isStopSelChar( Uint32 c ) { diff --git a/src/eepp/ui/css/stylesheetproperty.cpp b/src/eepp/ui/css/stylesheetproperty.cpp index c0412bee6..53728784b 100644 --- a/src/eepp/ui/css/stylesheetproperty.cpp +++ b/src/eepp/ui/css/stylesheetproperty.cpp @@ -25,7 +25,7 @@ StyleSheetProperty::StyleSheetProperty( const PropertyDefinition* definition, mIndex( index ), mVolatile( false ), mImportant( false ), - mIsVarValue( String::startsWith( mValue, "var(" ) ), + mIsVarValue( String::contains( mValue, "var(" ) ), mPropertyDefinition( definition ), mShorthandDefinition( NULL ) { cleanValue(); @@ -48,7 +48,7 @@ StyleSheetProperty::StyleSheetProperty( const bool& isVolatile, mIndex( index ), mVolatile( false ), mImportant( false ), - mIsVarValue( String::startsWith( mValue, "var(" ) ), + mIsVarValue( String::contains( mValue, "var(" ) ), mPropertyDefinition( definition ), mShorthandDefinition( NULL ) { cleanValue(); @@ -68,7 +68,7 @@ StyleSheetProperty::StyleSheetProperty( const std::string& name, const std::stri mIndex( 0 ), mVolatile( false ), mImportant( false ), - mIsVarValue( String::startsWith( mValue, "var(" ) ), + mIsVarValue( String::contains( mValue, "var(" ) ), mPropertyDefinition( StyleSheetSpecification::instance()->getProperty( mNameHash ) ), mShorthandDefinition( NULL == mPropertyDefinition ? StyleSheetSpecification::instance()->getShorthand( mNameHash ) @@ -92,7 +92,7 @@ StyleSheetProperty::StyleSheetProperty( const std::string& name, const std::stri mIndex( index ), mVolatile( isVolatile ), mImportant( false ), - mIsVarValue( String::startsWith( mValue, "var(" ) ), + mIsVarValue( String::contains( mValue, "var(" ) ), mPropertyDefinition( StyleSheetSpecification::instance()->getProperty( mNameHash ) ), mShorthandDefinition( NULL == mPropertyDefinition ? StyleSheetSpecification::instance()->getShorthand( mNameHash ) diff --git a/src/eepp/ui/uicheckbox.cpp b/src/eepp/ui/uicheckbox.cpp index 1ea1e00b0..e091fd008 100644 --- a/src/eepp/ui/uicheckbox.cpp +++ b/src/eepp/ui/uicheckbox.cpp @@ -65,7 +65,7 @@ void UICheckBox::onThemeLoaded() { mInactiveButton->centerVertical(); } - mMinControlSize = mActiveButton->getSkinSize(); + mMinSize = mActiveButton->getSkinSize(); onPaddingChange(); @@ -188,8 +188,6 @@ void UICheckBox::alignFix() { mActiveButton->getPixelsSize().getWidth() + PixelDensity::dpToPx( mTextSeparation ); break; } - - mAlignOffset = PixelDensity::pxToDp( mRealAlignOffset ); } UIWidget* UICheckBox::getCheckedButton() const { diff --git a/src/eepp/ui/uidropdownlist.cpp b/src/eepp/ui/uidropdownlist.cpp index 0d2f007ef..1f0b34bf1 100644 --- a/src/eepp/ui/uidropdownlist.cpp +++ b/src/eepp/ui/uidropdownlist.cpp @@ -83,12 +83,12 @@ void UIDropDownList::setFriendControl( UINode* friendCtrl ) { } void UIDropDownList::onAutoSize() { + Float max = eemax( PixelDensity::dpToPxI( getSkinSize().getHeight() ), getTextHeight() ); + if ( mLayoutHeightRule == LayoutSizeRule::WrapContent ) { - setInternalPixelsHeight( PixelDensity::dpToPxI( getSkinSize().getHeight() ) + - mRealPadding.Top + mRealPadding.Bottom ); - } else if ( ( ( mFlags & UI_AUTO_SIZE ) || 0 == getSize().getHeight() ) && - 0 != getSkinSize().getHeight() ) { - setInternalHeight( getSkinSize().getHeight() ); + setInternalPixelsHeight( max + mRealPadding.Top + mRealPadding.Bottom ); + } else if ( ( ( mFlags & UI_AUTO_SIZE ) || 0 == getSize().getHeight() ) && max > 0 ) { + setInternalHeight( max ); } } diff --git a/src/eepp/ui/uilistbox.cpp b/src/eepp/ui/uilistbox.cpp index 4c29a8a70..6fc2a1ca2 100644 --- a/src/eepp/ui/uilistbox.cpp +++ b/src/eepp/ui/uilistbox.cpp @@ -1074,11 +1074,11 @@ bool UIListBox::applyProperty( const StyleSheetProperty& attribute ) { String::toLowerInPlace( val ); if ( "no-buttons" == val || "nobuttons" == val ) { - mVScrollBar->setScrollBarType( UIScrollBar::NoButtons ); - mHScrollBar->setScrollBarType( UIScrollBar::NoButtons ); + mVScrollBar->setScrollBarStyle( UIScrollBar::NoButtons ); + mHScrollBar->setScrollBarStyle( UIScrollBar::NoButtons ); } else if ( "two-buttons" == val || "twobuttons" == val ) { - mVScrollBar->setScrollBarType( UIScrollBar::TwoButtons ); - mHScrollBar->setScrollBarType( UIScrollBar::NoButtons ); + mVScrollBar->setScrollBarStyle( UIScrollBar::TwoButtons ); + mHScrollBar->setScrollBarStyle( UIScrollBar::NoButtons ); } break; } diff --git a/src/eepp/ui/uinode.cpp b/src/eepp/ui/uinode.cpp index 504fb3185..0738a4d5f 100644 --- a/src/eepp/ui/uinode.cpp +++ b/src/eepp/ui/uinode.cpp @@ -135,26 +135,51 @@ const Vector2f& UINode::getPixelsPosition() const { } void UINode::setInternalSize( const Sizef& size ) { + Sizef s( size ); + + if ( s.x < mMinSize.x ) + s.x = mMinSize.x; + + if ( s.y < mMinSize.y ) + s.y = mMinSize.y; + mDpSize = size; - mSize = PixelDensity::dpToPx( size ); + mSize = PixelDensity::dpToPx( s ); updateCenter(); sendCommonEvent( Event::OnSizeChange ); invalidateDraw(); } void UINode::setInternalPixelsSize( const Sizef& size ) { - mDpSize = PixelDensity::pxToDp( size ); - mSize = size; + Sizef s( size ); + Sizef pMinSize( PixelDensity::dpToPx( mMinSize ) ); + + if ( s.x < pMinSize.x ) + s.x = pMinSize.x; + + if ( s.y < pMinSize.y ) + s.y = pMinSize.y; + + mDpSize = PixelDensity::pxToDp( s ); + mSize = s; updateCenter(); sendCommonEvent( Event::OnSizeChange ); invalidateDraw(); } Node* UINode::setSize( const Sizef& Size ) { - if ( Size != mDpSize ) { - Vector2f sizeChange( Size.x - mDpSize.x, Size.y - mDpSize.y ); + Sizef s( Size ); - setInternalSize( Size ); + if ( s.x < mMinSize.x ) + s.x = mMinSize.x; + + if ( s.y < mMinSize.y ) + s.y = mMinSize.y; + + if ( s != mDpSize ) { + Vector2f sizeChange( s.x - mDpSize.x, s.y - mDpSize.y ); + + setInternalSize( s ); onSizeChange(); @@ -198,6 +223,31 @@ 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::getMinSize() const { + return mMinSize; +} + void UINode::updateOriginPoint() { Node::updateOriginPoint(); diff --git a/src/eepp/ui/uiprogressbar.cpp b/src/eepp/ui/uiprogressbar.cpp index 82c13903a..cdac7488d 100644 --- a/src/eepp/ui/uiprogressbar.cpp +++ b/src/eepp/ui/uiprogressbar.cpp @@ -6,16 +6,68 @@ namespace EE { namespace UI { +class UIProgressBarFiller : public UIWidget { + public: + static UIProgressBarFiller* New( UIProgressBar* parent ) { + return eeNew( UIProgressBarFiller, ( parent ) ); + } + + UIProgressBarFiller( UIProgressBar* parent ) : + UIWidget( "progressbar::filler" ), mProgressBar( NULL ), mFillerSkin( NULL ) { + setParent( parent ); + mProgressBar = parent; + } + + void draw() override { + UIWidget::draw(); + + if ( NULL == mFillerSkin ) + return; + + Float Height = (Float)mSize.getHeight(); + + if ( !mProgressBar->getStyleConfig().VerticalExpand ) + Height = (Float)mFillerSkin->getSize().getHeight(); + + if ( Height > mSize.getHeight() ) + Height = mSize.getHeight(); + + Sizef fSize( mSize ); + Sizei rSize( PixelDensity::dpToPxI( mFillerSkin->getSize() ) ); + Sizei numTiles( (Int32)eeceil( (Float)fSize.getWidth() / (Float)rSize.getWidth() + 2 ), + (Int32)eeceil( (Float)fSize.getHeight() / (Float)rSize.getHeight() ) + 2 ); + + clipSmartEnable( mScreenPos.x, mScreenPos.y, fSize.getWidth(), fSize.getHeight() ); + + Vector2f offset( mProgressBar->mOffset ); + + for ( int y = -1; y < numTiles.y; y++ ) { + for ( int x = -1; x < numTiles.x; x++ ) { + mFillerSkin->draw( Vector2f( (Int32)offset.x + mScreenPosi.x + x * rSize.getWidth(), + offset.y + mScreenPosi.y + y * rSize.getHeight() ), + Sizef( rSize.getWidth(), rSize.getHeight() ) ); + } + } + + clipSmartDisable(); + } + + UIProgressBar* mProgressBar; + UISkin* mFillerSkin; +}; + UIProgressBar* UIProgressBar::New() { return eeNew( UIProgressBar, () ); } -UIProgressBar::UIProgressBar() : - UIWidget( "progressbar" ), mProgress( 0.f ), mTotalSteps( 100.f ), mFillerSkin( NULL ) { +UIProgressBar::UIProgressBar() : UIWidget( "progressbar" ), mProgress( 0.f ), mTotalSteps( 100.f ) { subscribeScheduledUpdate(); setFlags( UI_AUTO_PADDING | UI_AUTO_SIZE ); + mFiller = UIProgressBarFiller::New( this ); + mFiller->setEnabled( true ); + mTextBox = UITextView::NewWithTag( "progressbar::text" ); mTextBox->setHorizontalAlign( UI_HALIGN_CENTER ); mTextBox->setParent( this ); @@ -36,52 +88,15 @@ bool UIProgressBar::isType( const Uint32& type ) const { return UIProgressBar::getType() == type ? true : UIWidget::isType( type ); } -void UIProgressBar::draw() { - UINode::draw(); - - if ( NULL == mFillerSkin ) - return; - - Float Height = (Float)mSize.getHeight(); - - if ( !mStyleConfig.VerticalExpand ) - Height = (Float)mFillerSkin->getSize().getHeight(); - - if ( Height > mSize.getHeight() ) - Height = mSize.getHeight(); - - Sizef fSize( ( ( mSize.getWidth() - mRealPadding.Left - mRealPadding.Right ) * mProgress ) / - mTotalSteps, - Height - mRealPadding.Top - mRealPadding.Bottom ); - Sizei rSize( PixelDensity::dpToPxI( mFillerSkin->getSize() ) ); - Sizei numTiles( (Int32)eeceil( (Float)fSize.getWidth() / (Float)rSize.getWidth() + 2 ), - (Int32)eeceil( (Float)fSize.getHeight() / (Float)rSize.getHeight() ) + 2 ); - - clipSmartEnable( mScreenPos.x + mRealPadding.Left, mScreenPos.y + mRealPadding.Top, - fSize.getWidth(), fSize.getHeight() ); - - for ( int y = -1; y < numTiles.y; y++ ) { - for ( int x = -1; x < numTiles.x; x++ ) { - mFillerSkin->draw( - Vector2f( (Int32)mOffset.x + mScreenPosi.x + mRealPadding.Left + - x * rSize.getWidth(), - mOffset.y + mScreenPosi.y + mRealPadding.Top + y * rSize.getHeight() ), - Sizef( rSize.getWidth(), rSize.getHeight() ) ); - } - } - - clipSmartDisable(); -} - void UIProgressBar::scheduledUpdate( const Time& time ) { - if ( NULL == mFillerSkin ) + if ( NULL == mFiller->mFillerSkin ) return; Vector2f offset( mOffset ); mOffset += mStyleConfig.MovementSpeed * ( Float )( time.asSeconds() ); - Sizei rSize( PixelDensity::dpToPxI( mFillerSkin->getSize() ) ); + Sizei rSize( PixelDensity::dpToPxI( mFiller->mFillerSkin->getSize() ) ); if ( mOffset.x > rSize.getWidth() || mOffset.x < -rSize.getWidth() ) mOffset.x = 0.f; @@ -97,14 +112,14 @@ void UIProgressBar::setTheme( UITheme* Theme ) { UIWidget::setTheme( Theme ); setThemeSkin( Theme, "progressbar" ); - mFillerSkin = Theme->getSkin( "progressbar_filler" ); + mFiller->mFillerSkin = Theme->getSkin( "progressbar_filler" ); - if ( mFillerSkin ) { + if ( mFiller->mFillerSkin ) { if ( mFlags & UI_AUTO_PADDING ) { Float meH = (Float)getSkinSize().getHeight(); - Float otH = (Float)mFillerSkin->getSize().getHeight(); + Float otH = (Float)mFiller->mFillerSkin->getSize().getHeight(); Float res = Math::roundUp( ( meH - otH ) * 0.5f ); - setPadding( Rectf( res, res, res, res ) ); + mFiller->setPadding( Rectf( res, res, res, res ) ); } } @@ -112,8 +127,8 @@ void UIProgressBar::setTheme( UITheme* Theme ) { } void UIProgressBar::onThemeLoaded() { - mMinControlSize.x = eemax( mMinControlSize.x, getSkinSize().getWidth() ); - mMinControlSize.y = eemax( mMinControlSize.y, getSkinSize().getHeight() ); + mMinSize.x = eemax( mMinSize.x, getSkinSize().getWidth() ); + mMinSize.y = eemax( mMinSize.y, getSkinSize().getHeight() ); if ( mFlags & UI_AUTO_SIZE ) { setSize( getSize().getWidth(), getSkinSize().getHeight() ); @@ -124,16 +139,24 @@ void UIProgressBar::onThemeLoaded() { Uint32 UIProgressBar::onValueChange() { UINode::onValueChange(); - onSizeChange(); - return 1; } void UIProgressBar::onSizeChange() { + Sizef fSize( ( ( mSize.getWidth() - mRealPadding.Left - mRealPadding.Right ) * getProgress() ) / + getTotalSteps(), + mSize.getHeight() - mRealPadding.Top - mRealPadding.Bottom ); + mFiller->setPixelsSize( fSize ); + mFiller->setPixelsPosition( mRealPadding.Left, mRealPadding.Top ); updateTextBox(); } +void UIProgressBar::onPaddingChange() { + onSizeChange(); + UIWidget::onPaddingChange(); +} + void UIProgressBar::setProgress( Float Val ) { mProgress = Val; diff --git a/src/eepp/ui/uiradiobutton.cpp b/src/eepp/ui/uiradiobutton.cpp index abc2bc5a8..7be08ade6 100644 --- a/src/eepp/ui/uiradiobutton.cpp +++ b/src/eepp/ui/uiradiobutton.cpp @@ -69,7 +69,7 @@ void UIRadioButton::onThemeLoaded() { mInactiveButton->centerVertical(); } - mMinControlSize = mActiveButton->getSkinSize(); + mMinSize = mActiveButton->getSkinSize(); onPaddingChange(); @@ -255,8 +255,6 @@ void UIRadioButton::alignFix() { mActiveButton->getPixelsSize().getWidth() + PixelDensity::dpToPx( mTextSeparation ); break; } - - mAlignOffset = PixelDensity::pxToDp( mRealAlignOffset ); } UIWidget* UIRadioButton::getActiveButton() const { diff --git a/src/eepp/ui/uiscrollbar.cpp b/src/eepp/ui/uiscrollbar.cpp index 3e89c3a6a..b95d26e6d 100644 --- a/src/eepp/ui/uiscrollbar.cpp +++ b/src/eepp/ui/uiscrollbar.cpp @@ -19,9 +19,9 @@ UIScrollBar* UIScrollBar::NewVertical() { UIScrollBar::UIScrollBar( const UIOrientation& orientation ) : UIWidget( "scrollbar" ), #ifdef EE_PLATFORM_TOUCH - mScrollBarType( NoButtons ) + mScrollBarStyle( NoButtons ) #else - mScrollBarType( TwoButtons ) + mScrollBarStyle( TwoButtons ) #endif { mFlags |= UI_AUTO_SIZE; @@ -41,15 +41,23 @@ UIScrollBar::UIScrollBar( const UIOrientation& orientation ) : mBtnDown->setSize( 16, 16 ); mSlider = UISlider::New(); - mSlider->addEventListener( Event::OnValueChange, - cb::Make1( this, &UIScrollBar::onValueChangeCb ) ); - mSlider->setElementTag( "scrollbar::slider" ); mSlider->setOrientation( orientation ); mSlider->setParent( this ); mSlider->setAllowHalfSliderOut( false ); mSlider->setExpandBackground( false ); - mSlider->getSliderButton()->setElementTag( "scrollbar::button" ); - mSlider->getBackSlider()->setElementTag( "scrollbar::back" ); + + if ( orientation == UIOrientation::Vertical ) { + mSlider->setElementTag( "scrollbar::vslider" ); + mSlider->getSliderButton()->setElementTag( "scrollbar::vbutton" ); + mSlider->getBackSlider()->setElementTag( "scrollbar::vback" ); + } else { + mSlider->setElementTag( "scrollbar::hslider" ); + mSlider->getSliderButton()->setElementTag( "scrollbar::hbutton" ); + mSlider->getBackSlider()->setElementTag( "scrollbar::hback" ); + } + + mSlider->addEventListener( Event::OnValueChange, + cb::Make1( this, &UIScrollBar::onValueChangeCb ) ); adjustChilds(); @@ -76,8 +84,6 @@ void UIScrollBar::setTheme( UITheme* Theme ) { mSlider->getSliderButton()->setThemeSkin( Theme, "hscrollbar_button" ); mBtnUp->setThemeSkin( Theme, "hscrollbar_btnup" ); mBtnDown->setThemeSkin( Theme, "hscrollbar_btndown" ); - mBtnDown->setElementTag( "scrollbar::btnleft" ); - mBtnUp->setElementTag( "scrollbar::btnright" ); } else { UINode::setThemeSkin( Theme, "vscrollbar" ); mSlider->setThemeSkin( Theme, "vscrollbar_slider" ); @@ -85,8 +91,6 @@ void UIScrollBar::setTheme( UITheme* Theme ) { mSlider->getSliderButton()->setThemeSkin( Theme, "vscrollbar_button" ); mBtnUp->setThemeSkin( Theme, "vscrollbar_btnup" ); mBtnDown->setThemeSkin( Theme, "vscrollbar_btndown" ); - mBtnDown->setElementTag( "scrollbar::btndown" ); - mBtnUp->setElementTag( "scrollbar::btnup" ); } UISkin* tSkin = mBtnUp->getSkin(); @@ -115,7 +119,7 @@ void UIScrollBar::onAutoSize() { if ( NULL != tSkin ) { size = tSkin->getSize(); - mMinControlSize = PixelDensity::pxToDp( size ); + setMinSize( PixelDensity::pxToDp( size ) ); if ( mFlags & UI_AUTO_SIZE ) { if ( mSlider->isVertical() ) { @@ -132,6 +136,8 @@ void UIScrollBar::onAutoSize() { if ( NULL != tSkin ) { size = tSkin->getSize(); + setMinSize( PixelDensity::pxToDp( size ) ); + if ( mFlags & UI_AUTO_SIZE ) { if ( mSlider->isVertical() ) { setSize( size.getWidth(), getSize().getHeight() ); @@ -144,9 +150,9 @@ void UIScrollBar::onAutoSize() { if ( mLayoutWidthRule == LayoutSizeRule::WrapContent || mLayoutHeightRule == LayoutSizeRule::WrapContent ) { - size = PixelDensity::dpToPx( mSlider->getMinimumSize() ) + mRealPadding; + size = PixelDensity::dpToPx( mSlider->getSize() ) + mRealPadding; - if ( mScrollBarType == TwoButtons ) { + if ( mScrollBarStyle == TwoButtons ) { if ( mSlider->isVertical() ) { size.y += mBtnDown->getPixelsSize().getHeight() + mBtnUp->getPixelsSize().getHeight(); @@ -180,7 +186,7 @@ void UIScrollBar::adjustChilds() { mBtnUp->setPosition( 0, 0 ); - switch ( mScrollBarType ) { + switch ( mScrollBarStyle ) { case NoButtons: { mBtnDown->setVisible( false )->setEnabled( false ); mBtnUp->setVisible( false )->setEnabled( false ); @@ -390,9 +396,9 @@ bool UIScrollBar::applyProperty( const StyleSheetProperty& attribute ) { String::toLowerInPlace( val ); if ( "no-buttons" == val || "nobuttons" == val ) { - setScrollBarType( NoButtons ); + setScrollBarStyle( NoButtons ); } else if ( "two-buttons" == val || "twobuttons" == val ) { - setScrollBarType( TwoButtons ); + setScrollBarStyle( TwoButtons ); } break; } @@ -407,12 +413,12 @@ bool UIScrollBar::applyProperty( const StyleSheetProperty& attribute ) { } UIScrollBar::ScrollBarType UIScrollBar::getScrollBarType() const { - return mScrollBarType; + return mScrollBarStyle; } -void UIScrollBar::setScrollBarType( const ScrollBarType& scrollBarType ) { - if ( mScrollBarType != scrollBarType ) { - mScrollBarType = scrollBarType; +void UIScrollBar::setScrollBarStyle( const ScrollBarType& scrollBarType ) { + if ( mScrollBarStyle != scrollBarType ) { + mScrollBarStyle = scrollBarType; onAutoSize(); @@ -428,6 +434,7 @@ UINode* UIScrollBar::setOrientation( const UIOrientation& orientation ) { if ( mSlider->getOrientation() != orientation ) { mSlider->setOrientation( orientation ); + updateOrientation(); applyDefaultTheme(); } @@ -450,4 +457,20 @@ void UIScrollBar::onPaddingChange() { UIWidget::onPaddingChange(); } +void UIScrollBar::updateOrientation() { + if ( mSlider->getOrientation() == UIOrientation::Vertical ) { + mBtnDown->setElementTag( "scrollbar::btndown" ); + mBtnUp->setElementTag( "scrollbar::btnup" ); + mSlider->setElementTag( "scrollbar::vslider" ); + mSlider->getSliderButton()->setElementTag( "scrollbar::vbutton" ); + mSlider->getBackSlider()->setElementTag( "scrollbar::vback" ); + } else { + mBtnDown->setElementTag( "scrollbar::btnleft" ); + mBtnUp->setElementTag( "scrollbar::btnright" ); + mSlider->setElementTag( "scrollbar::hslider" ); + mSlider->getSliderButton()->setElementTag( "scrollbar::hbutton" ); + mSlider->getBackSlider()->setElementTag( "scrollbar::hback" ); + } +} + }} // namespace EE::UI diff --git a/src/eepp/ui/uiscrollview.cpp b/src/eepp/ui/uiscrollview.cpp index 626897350..44a510389 100644 --- a/src/eepp/ui/uiscrollview.cpp +++ b/src/eepp/ui/uiscrollview.cpp @@ -320,11 +320,11 @@ bool UIScrollView::applyProperty( const StyleSheetProperty& attribute ) { String::toLowerInPlace( val ); if ( "no-buttons" == val || "nobuttons" == val ) { - mVScroll->setScrollBarType( UIScrollBar::NoButtons ); - mHScroll->setScrollBarType( UIScrollBar::NoButtons ); + mVScroll->setScrollBarStyle( UIScrollBar::NoButtons ); + mHScroll->setScrollBarStyle( UIScrollBar::NoButtons ); } else if ( "two-buttons" == val || "twobuttons" == val ) { - mVScroll->setScrollBarType( UIScrollBar::TwoButtons ); - mHScroll->setScrollBarType( UIScrollBar::NoButtons ); + mVScroll->setScrollBarStyle( UIScrollBar::TwoButtons ); + mHScroll->setScrollBarStyle( UIScrollBar::NoButtons ); } break; } diff --git a/src/eepp/ui/uislider.cpp b/src/eepp/ui/uislider.cpp index 9d6223aff..015d64ed4 100644 --- a/src/eepp/ui/uislider.cpp +++ b/src/eepp/ui/uislider.cpp @@ -22,6 +22,7 @@ UISlider::UISlider( const UIOrientation& orientation ) : mOrientation( orientation ), mAllowHalfSliderOut( false ), mExpandBackground( false ), + mUpdating( false ), mBackSlider( NULL ), mSlider( NULL ), mMinValue( 0.f ), @@ -32,24 +33,34 @@ UISlider::UISlider( const UIOrientation& orientation ) : mOnPosChange( false ) { Sizef bgSize; - if ( UIOrientation::Horizontal == mOrientation ) + if ( UIOrientation::Horizontal == mOrientation ) { bgSize = Sizef( getSize().getWidth() - 16, 8 ); - else + + mBackSlider = UIWidget::NewWithTag( "slider::hback" ); + mSlider = UIWidget::NewWithTag( "slider::hbutton" ); + } else { bgSize = Sizef( 8, getSize().getHeight() - 16 ); - mBackSlider = UIWidget::NewWithTag( "slider::back" ); + mBackSlider = UIWidget::NewWithTag( "slider::vback" ); + mSlider = UIWidget::NewWithTag( "slider::hbutton" ); + } + + auto cb = [&]( const Event* event ) { + if ( !mUpdating ) + adjustChilds(); + }; + mBackSlider->setParent( this ); mBackSlider->setVisible( true ); mBackSlider->setEnabled( true ); mBackSlider->setSize( bgSize ); mBackSlider->center(); - mSlider = UIWidget::NewWithTag( "slider::button" ); mSlider->setParent( this ); mSlider->setEnabled( true ); mSlider->setVisible( true ); mSlider->setDragEnabled( true ); - mSlider->setSize( 16, 16 ); + mSlider->setSize( 4, 4 ); mSlider->setPosition( 0, 0 ); mSlider->addEventListener( Event::OnPositionChange, [&]( const Event* event ) { fixSliderPos(); } ); @@ -59,6 +70,9 @@ UISlider::UISlider( const UIOrientation& orientation ) : else mSlider->centerHorizontal(); + mBackSlider->addEventListener( Event::OnSizeChange, cb ); + mSlider->addEventListener( Event::OnSizeChange, cb ); + applyDefaultTheme(); } @@ -105,72 +119,90 @@ void UISlider::onPaddingChange() { } void UISlider::adjustChilds() { + mUpdating = true; + UISkin* tSkin = mSlider->getSkin(); - if ( NULL != tSkin ) { - if ( mPageStep == 0 ) { - mSlider->setSize( tSkin->getSize() ); - } else { - Float percent = ( mPageStep / ( mMaxValue - mMinValue ) ); + if ( NULL != tSkin ) + mSlider->setMinSize( tSkin->getSize() ); - if ( UIOrientation::Horizontal == mOrientation ) { - Float size = - eemax( ( (Float)getSize().getWidth() * percent ), tSkin->getSize().getWidth() ); - - mSlider->setSize( size, tSkin->getSize().getHeight() ); - } else { - Float size = eemax( ( (Float)getSize().getHeight() * percent ), - tSkin->getSize().getHeight() ); - - mSlider->setSize( tSkin->getSize().getWidth(), size ); - } - } + if ( mPageStep == 0 ) { + mSlider->setSize( mSlider->getMinSize() ); + } else { + Float percent = ( mPageStep / ( mMaxValue - mMinValue ) ); if ( UIOrientation::Horizontal == mOrientation ) { - mSlider->centerVertical(); + Float size = eemax( ( (Float)getSize().getWidth() * percent ), + mSlider->getMinSize().getWidth() ); + + mSlider->setSize( size, mSlider->getSize().getHeight() ); } else { - mSlider->centerHorizontal(); + Float size = eemax( ( (Float)getSize().getHeight() * percent ), + mSlider->getMinSize().getHeight() ); + + mSlider->setSize( mSlider->getSize().getWidth(), size ); } } + if ( UIOrientation::Horizontal == mOrientation ) { + if ( mSlider->getSize().getHeight() > getMinSize().getHeight() ) + setMinHeight( mSlider->getSize().getHeight() ); + + mSlider->centerVertical(); + } else { + if ( mSlider->getSize().getWidth() > getMinimumSize().getWidth() ) + setMinWidth( mSlider->getSize().getWidth() ); + + mSlider->centerHorizontal(); + } + tSkin = mBackSlider->getSkin(); - if ( NULL != tSkin ) { - if ( UIOrientation::Horizontal == mOrientation ) { - Float Height; + if ( NULL != tSkin ) + mBackSlider->setMinSize( tSkin->getSize() ); - if ( mExpandBackground ) - Height = getSize().getHeight() - mPadding.Top - mPadding.Bottom; - else - Height = tSkin->getSize().getHeight(); + if ( UIOrientation::Horizontal == mOrientation ) { + Float Height; - if ( mAllowHalfSliderOut ) - mBackSlider->setSize( Sizef( getSize().getWidth() - mSlider->getSize().getWidth() - - mPadding.Left - mPadding.Right, - Height ) ); - else - mBackSlider->setSize( - Sizef( getSize().getWidth() - mPadding.Left - mPadding.Right, Height ) ); - } else { - Float Width; + if ( mExpandBackground ) + Height = getSize().getHeight() - mPadding.Top - mPadding.Bottom; + else + Height = mBackSlider->getMinSize().getHeight(); - if ( mExpandBackground ) - Width = getSize().getWidth() - mPadding.Left - mPadding.Right; - else - Width = tSkin->getSize().getWidth(); + if ( mAllowHalfSliderOut ) + mBackSlider->setSize( Sizef( getSize().getWidth() - mSlider->getSize().getWidth() - + mPadding.Left - mPadding.Right, + Height ) ); + else + mBackSlider->setSize( + Sizef( getSize().getWidth() - mPadding.Left - mPadding.Right, Height ) ); - if ( mAllowHalfSliderOut ) - mBackSlider->setSize( Sizef( Width, getSize().getHeight() - - mSlider->getSize().getHeight() - - mPadding.Top - mPadding.Bottom ) ); - else - mBackSlider->setSize( Sizef( Width, getSize().getHeight() ) ); - } + if ( Height > getMinSize().getHeight() ) + setMinHeight( Height ); + } else { + Float Width; - mBackSlider->center(); + if ( mExpandBackground ) + Width = getSize().getWidth() - mPadding.Left - mPadding.Right; + else + Width = mBackSlider->getMinSize().getWidth(); + + if ( mAllowHalfSliderOut ) + mBackSlider->setSize( Sizef( Width, getSize().getHeight() - + mSlider->getSize().getHeight() - mPadding.Top - + mPadding.Bottom ) ); + else + mBackSlider->setSize( Sizef( Width, getSize().getHeight() ) ); + + if ( Width > getMinimumSize().getWidth() ) + setMinWidth( Width ); } + mBackSlider->center(); + adjustSliderPos(); + + mUpdating = false; } void UISlider::fixSliderPos() { @@ -395,6 +427,7 @@ UISlider* UISlider::setOrientation( const UIOrientation& orientation ) { if ( orientation != mOrientation ) { mOrientation = orientation; + updateOrientation(); applyDefaultTheme(); } @@ -469,6 +502,16 @@ Uint32 UISlider::onMessage( const NodeMessage* Msg ) { return 0; } +void UISlider::updateOrientation() { + if ( UIOrientation::Horizontal == mOrientation ) { + mBackSlider->setElementTag( "slider::hback" ); + mSlider->setElementTag( "slider::hbutton" ); + } else { + mBackSlider->setElementTag( "slider::vback" ); + mSlider->setElementTag( "slider::hbutton" ); + } +} + std::string UISlider::getPropertyString( const PropertyDefinition* propertyDef, const Uint32& propertyIndex ) { if ( NULL == propertyDef ) diff --git a/src/eepp/ui/uispinbox.cpp b/src/eepp/ui/uispinbox.cpp index cbe8bf702..732558654 100644 --- a/src/eepp/ui/uispinbox.cpp +++ b/src/eepp/ui/uispinbox.cpp @@ -25,13 +25,13 @@ UISpinBox::UISpinBox() : mPushUp->setVisible( true ); mPushUp->setEnabled( true ); mPushUp->setParent( this ); - mPushUp->setSize( 16, 16 ); + mPushUp->setSize( 8, 8 ); mPushDown = UIWidget::NewWithTag( "spinbox::btndown" ); mPushDown->setVisible( true ); mPushDown->setEnabled( true ); mPushDown->setParent( this ); - mPushDown->setSize( 16, 16 ); + mPushDown->setSize( 8, 8 ); mInput->getInputTextBuffer()->setAllowOnlyNumbers( true, false ); mInput->addEventListener( Event::OnBufferChange, @@ -312,13 +312,38 @@ bool UISpinBox::applyProperty( const StyleSheetProperty& attribute ) { case PropertyId::ClickStep: setClickStep( attribute.asFloat() ); break; + case PropertyId::Text: + case PropertyId::AllowEditing: + case PropertyId::MaxLength: + case PropertyId::FreeEditing: + case PropertyId::Numeric: + case PropertyId::AllowFloat: + case PropertyId::Hint: + case PropertyId::HintColor: + case PropertyId::HintShadowColor: + case PropertyId::HintFontSize: + case PropertyId::HintFontFamily: + case PropertyId::HintFontStyle: + case PropertyId::HintStrokeWidth: + case PropertyId::HintStrokeColor: + case PropertyId::Color: + case PropertyId::ShadowColor: + case PropertyId::SelectionColor: + case PropertyId::SelectionBackColor: + case PropertyId::FontFamily: + case PropertyId::FontSize: + case PropertyId::FontStyle: + case PropertyId::Wordwrap: + case PropertyId::TextStrokeWidth: + case PropertyId::TextStrokeColor: + case PropertyId::TextSelection: + case PropertyId::TextAlign: + return mInput->applyProperty( attribute ); default: attributeSet = UIWidget::applyProperty( attribute ); break; } - mInput->applyProperty( attribute ); - return attributeSet; } diff --git a/src/eepp/ui/uistyle.cpp b/src/eepp/ui/uistyle.cpp index b5679853a..3d5231e5e 100644 --- a/src/eepp/ui/uistyle.cpp +++ b/src/eepp/ui/uistyle.cpp @@ -194,26 +194,56 @@ void UIStyle::findVariables( const StyleSheetStyle& style ) { } } -void UIStyle::setVariableFromValue( StyleSheetProperty& property, const std::string& value ) { - FunctionString functionType = FunctionString::parse( value ); +std::string UIStyle::varToVal( const std::string& varDef ) { + FunctionString functionType = FunctionString::parse( varDef ); if ( !functionType.getParameters().empty() ) { for ( auto& val : functionType.getParameters() ) { if ( String::startsWith( val, "--" ) ) { StyleSheetVariable variable( getVariable( val ) ); - if ( !variable.isEmpty() ) { - property.setValue( variable.getValue() ); - break; + return variable.getValue(); } } else if ( String::startsWith( val, "var(" ) ) { - return setVariableFromValue( property, val ); + return varToVal( val ); } else { - property.setValue( val ); - break; + return val; } } } + + return ""; +} + +void UIStyle::setVariableFromValue( StyleSheetProperty& property, const std::string& value ) { + std::string::size_type tokenStart = 0; + std::string::size_type tokenEnd = 0; + std::string newValue( value ); + + while ( true ) { + tokenStart = newValue.find( "var(", tokenStart ); + + if ( tokenStart != std::string::npos ) { + tokenEnd = String::findCloseBracket( value, tokenStart, '(', ')' ); + + if ( tokenEnd != std::string::npos ) { + std::string varDef( newValue.substr( tokenStart, tokenEnd + 1 - tokenStart ) ); + + String::replaceAll( newValue, varDef, varToVal( varDef ) ); + } else { + break; + } + } else { + break; + } + }; + + property.setValue( newValue ); + + if ( newValue.empty() ) { + eePRINTL( "Invalid var: \"%s\" for property: %s", value.c_str(), + property.getName().c_str() ); + } } void UIStyle::applyVarValues( StyleSheetStyle& style ) { diff --git a/src/eepp/ui/uitable.cpp b/src/eepp/ui/uitable.cpp index 9d1125f54..a3f4bac82 100644 --- a/src/eepp/ui/uitable.cpp +++ b/src/eepp/ui/uitable.cpp @@ -695,11 +695,11 @@ bool UITable::applyProperty( const StyleSheetProperty& attribute ) { String::toLowerInPlace( val ); if ( "no-buttons" == val || "nobuttons" == val ) { - mVScrollBar->setScrollBarType( UIScrollBar::NoButtons ); - mHScrollBar->setScrollBarType( UIScrollBar::NoButtons ); + mVScrollBar->setScrollBarStyle( UIScrollBar::NoButtons ); + mHScrollBar->setScrollBarStyle( UIScrollBar::NoButtons ); } else if ( "two-buttons" == val || "twobuttons" == val ) { - mVScrollBar->setScrollBarType( UIScrollBar::TwoButtons ); - mHScrollBar->setScrollBarType( UIScrollBar::NoButtons ); + mVScrollBar->setScrollBarStyle( UIScrollBar::TwoButtons ); + mHScrollBar->setScrollBarStyle( UIScrollBar::NoButtons ); } break; } diff --git a/src/eepp/ui/uitextedit.cpp b/src/eepp/ui/uitextedit.cpp index bcf98de2b..eda471b3b 100644 --- a/src/eepp/ui/uitextedit.cpp +++ b/src/eepp/ui/uitextedit.cpp @@ -33,12 +33,15 @@ UITextEdit::UITextEdit() : mTextInput->setEnabled( true ); mTextInput->setSize( getSize() ); - mTextInput->addEventListener( Event::OnSizeChange, - cb::Make1( this, &UITextEdit::onInputSizeChange ) ); - mTextInput->addEventListener( Event::OnTextChanged, - cb::Make1( this, &UITextEdit::onInputSizeChange ) ); - mTextInput->addEventListener( Event::OnPressEnter, - cb::Make1( this, &UITextEdit::onInputSizeChange ) ); + auto cb = [&]( const Event* event ) { + mNodeFlags |= NODE_FLAG_FREE_USE; + onInputSizeChange( event ); + mNodeFlags &= ~NODE_FLAG_FREE_USE; + }; + + mTextInput->addEventListener( Event::OnSizeChange, cb ); + mTextInput->addEventListener( Event::OnTextChanged, cb ); + mTextInput->addEventListener( Event::OnPressEnter, cb ); mTextInput->addEventListener( Event::OnCursorPosChange, cb::Make1( this, &UITextEdit::onCursorPosChange ) ); @@ -295,9 +298,7 @@ void UITextEdit::onInputSizeChange( const Event* Event ) { if ( mTextInput->getTextHeight() > Height ) { Width -= mVScrollBar->getPixelsSize().getWidth(); - mNodeFlags |= NODE_FLAG_FREE_USE; mTextInput->getInputTextBuffer()->setBuffer( text ); - mNodeFlags &= ~NODE_FLAG_FREE_USE; shrinkText( Width ); diff --git a/src/eepp/ui/uitextinput.cpp b/src/eepp/ui/uitextinput.cpp index 6aabc5a88..cb5b63475 100644 --- a/src/eepp/ui/uitextinput.cpp +++ b/src/eepp/ui/uitextinput.cpp @@ -76,8 +76,8 @@ void UITextInput::drawWaitingCursor() { Primitives P; P.setColor( mFontStyleConfig.FontColor ); - Float CurPosX = eefloor( mScreenPos.x + mRealAlignOffset.x + mCurPos.x + - PixelDensity::dpToPx( 1.f ) + mRealPadding.Left ); + Float CurPosX = + eefloor( mScreenPos.x + mRealAlignOffset.x + mCurPos.x + mRealPadding.Left ); Float CurPosY = mScreenPos.y + mRealAlignOffset.y + mCurPos.y + mRealPadding.Top; if ( CurPosX > (Float)mScreenPos.x + (Float)mSize.x ) @@ -189,6 +189,7 @@ void UITextInput::resetWaitCursor() { } void UITextInput::alignFix() { + Vector2f rOffset( mRealAlignOffset ); UITextView::alignFix(); if ( Font::getHorizontalAlign( getFlags() ) == UI_HALIGN_LEFT ) { @@ -201,18 +202,20 @@ void UITextInput::alignFix() { mTextBuffer.getBuffer().substr( NLPos, mTextBuffer.getCursorPosition() - NLPos ) ); Float tW = textCache.getTextWidth(); - Float tX = mRealAlignOffset.x + tW; - mCurPos.x = tW; mCurPos.y = (Float)LineNum * (Float)mTextCache->getFont()->getLineSpacing( mTextCache->getCharacterSizePx() ); - if ( !mTextBuffer.setSupportNewLine() ) { - if ( tX < 0.f ) + if ( !mTextBuffer.setSupportNewLine() && mSize.getWidth() > 0 ) { + mRealAlignOffset.x = rOffset.x; + Float tX = mRealAlignOffset.x + tW; + + if ( tX < 0.f ) { mRealAlignOffset.x = -( mRealAlignOffset.x + ( tW - mRealAlignOffset.x ) ); - else if ( tX > mSize.getWidth() - mRealPadding.Left - mRealPadding.Right ) + } else if ( tX > mSize.getWidth() - mRealPadding.Left - mRealPadding.Right ) { mRealAlignOffset.x = mSize.getWidth() - mRealPadding.Left - mRealPadding.Right - ( mRealAlignOffset.x + ( tW - mRealAlignOffset.x ) ); + } } } } @@ -228,7 +231,7 @@ void UITextInput::setTheme( UITheme* Theme ) { void UITextInput::onThemeLoaded() { UITextView::onThemeLoaded(); - mMinControlSize.y = eemax( mMinControlSize.y, getSkinSize().getHeight() ); + mMinSize.y = eemax( mMinSize.y, getSkinSize().getHeight() ); autoPadding(); onAutoSize(); @@ -298,33 +301,6 @@ void UITextInput::shrinkText( const Uint32& MaxWidth ) { void UITextInput::updateText() {} -Uint32 UITextInput::onMouseClick( const Vector2i& Pos, const Uint32& Flags ) { - UITextView::onMouseClick( Pos, Flags ); - - if ( ( Flags & EE_BUTTON_LMASK ) ) { - if ( selCurInit() == selCurEnd() ) { - Vector2f controlPos( Vector2f( Pos.x, Pos.y ) ); - worldToNode( controlPos ); - controlPos = PixelDensity::dpToPx( controlPos ) - mRealAlignOffset; - - Int32 curPos = - mTextCache->findCharacterFromPos( Vector2i( controlPos.x, controlPos.y ) ); - - if ( -1 != curPos ) { - mTextBuffer.setCursorPosition( curPos ); - onCursorPositionChange(); - resetWaitCursor(); - } - } else { - mTextBuffer.setCursorPosition( selCurEnd() ); - onCursorPositionChange(); - resetWaitCursor(); - } - } - - return 1; -} - Uint32 UITextInput::onMouseDown( const Vector2i& position, const Uint32& flags ) { int endPos = selCurEnd(); @@ -351,7 +327,7 @@ Uint32 UITextInput::onMouseDoubleClick( const Vector2i& Pos, const Uint32& Flags return 1; } -Uint32 UITextInput::onMouseOver(const Vector2i& position, const Uint32& flags) { +Uint32 UITextInput::onMouseOver( const Vector2i& position, const Uint32& flags ) { if ( NULL != mSceneNode ) mSceneNode->setCursor( Cursor::IBeam ); diff --git a/src/eepp/ui/uitextview.cpp b/src/eepp/ui/uitextview.cpp index fc4e10fd9..052f9b88d 100644 --- a/src/eepp/ui/uitextview.cpp +++ b/src/eepp/ui/uitextview.cpp @@ -318,8 +318,6 @@ void UITextView::alignFix() { mRealAlignOffset.y = 0; break; } - - mAlignOffset = PixelDensity::pxToDp( mRealAlignOffset ); } Uint32 UITextView::onFocusLoss() { @@ -386,8 +384,8 @@ const int& UITextView::getNumLines() const { return mTextCache->getNumLines(); } -const Vector2f& UITextView::getAlignOffset() const { - return mAlignOffset; +Vector2f UITextView::getAlignOffset() const { + return PixelDensity::pxToDp( mRealAlignOffset ); } Uint32 UITextView::onMouseDoubleClick( const Vector2i& Pos, const Uint32& Flags ) { @@ -395,8 +393,9 @@ Uint32 UITextView::onMouseDoubleClick( const Vector2i& Pos, const Uint32& Flags Vector2f controlPos( Vector2f( Pos.x, Pos.y ) ); worldToNode( controlPos ); controlPos = PixelDensity::dpToPx( controlPos ) - mRealAlignOffset; + controlPos -= Vector2f( mRealPadding.Left, mRealPadding.Top ); - Int32 curPos = mTextCache->findCharacterFromPos( Vector2i( controlPos.x, controlPos.y ) ); + Int32 curPos = mTextCache->findCharacterFromPos( controlPos.asInt() ); if ( -1 != curPos ) { Int32 tSelCurInit, tSelCurEnd; @@ -433,9 +432,10 @@ Uint32 UITextView::onMouseDown( const Vector2i& Pos, const Uint32& Flags ) { getEventDispatcher()->getDownControl() == this ) { Vector2f controlPos( Vector2f( Pos.x, Pos.y ) ); worldToNode( controlPos ); - controlPos = PixelDensity::dpToPx( controlPos ) - mRealAlignOffset; + controlPos = PixelDensity::dpToPx( controlPos ) - mRealAlignOffset + + Vector2f( mRealPadding.Left, mRealPadding.Top ); - Int32 curPos = mTextCache->findCharacterFromPos( Vector2i( controlPos.x, controlPos.y ) ); + Int32 curPos = mTextCache->findCharacterFromPos( controlPos.asInt() ); if ( -1 != curPos ) { if ( -1 == selCurInit() || !mSelecting ) { diff --git a/src/eepp/ui/uiwidget.cpp b/src/eepp/ui/uiwidget.cpp index 606292a08..af0de5164 100644 --- a/src/eepp/ui/uiwidget.cpp +++ b/src/eepp/ui/uiwidget.cpp @@ -34,7 +34,6 @@ UIWidget::UIWidget( const std::string& tag ) : mTheme( NULL ), mStyle( NULL ), mTooltip( NULL ), - mMinControlSize(), mLayoutWeight( 0 ), mLayoutGravity( 0 ), mLayoutWidthRule( LayoutSizeRule::WrapContent ), @@ -344,11 +343,11 @@ void UIWidget::tooltipRemove() { Node* UIWidget::setSize( const Sizef& size ) { Sizef s( size ); - if ( s.x < mMinControlSize.x ) - s.x = mMinControlSize.x; + if ( s.x < mMinSize.x ) + s.x = mMinSize.x; - if ( s.y < mMinControlSize.y ) - s.y = mMinControlSize.y; + if ( s.y < mMinSize.y ) + s.y = mMinSize.y; if ( !mMinWidthEq.empty() ) { Float length = @@ -505,8 +504,8 @@ void UIWidget::updateAnchors( const Vector2f& SizeChange ) { newSize.x = mParentCtrl->getSize().getWidth() - mDpPos.x - PixelDensity::pxToDpI( mDistToBorder.Right ); - if ( newSize.x < mMinControlSize.getWidth() ) - newSize.x = mMinControlSize.getWidth(); + if ( newSize.x < mMinSize.getWidth() ) + newSize.x = mMinSize.getWidth(); } } @@ -519,8 +518,8 @@ void UIWidget::updateAnchors( const Vector2f& SizeChange ) { newSize.y = mParentCtrl->getSize().y - mDpPos.y - PixelDensity::pxToDpI( mDistToBorder.Bottom ); - if ( newSize.y < mMinControlSize.getHeight() ) - newSize.y = mMinControlSize.getHeight(); + if ( newSize.y < mMinSize.getHeight() ) + newSize.y = mMinSize.getHeight(); } } @@ -577,14 +576,31 @@ void UIWidget::setMinSizeEq( const std::string& minWidthEq, const std::string& m if ( mMinWidthEq != minWidthEq || mMinHeightEq != minHeightEq ) { mMinWidthEq = minWidthEq; mMinHeightEq = minHeightEq; - setSize( mSize ); + + if ( !mMinWidthEq.empty() ) { + mMinSize.x = + lengthFromValue( mMinWidthEq, CSS::PropertyRelativeTarget::ContainingBlockWidth ); + } + + if ( !mMinHeightEq.empty() ) { + mMinSize.y = + lengthFromValue( mMinHeightEq, CSS::PropertyRelativeTarget::ContainingBlockHeight ); + } + + setSize( mDpSize ); } } void UIWidget::setMinWidthEq( const std::string& minWidthEq ) { if ( mMinWidthEq != minWidthEq ) { mMinWidthEq = minWidthEq; - setSize( mSize ); + + if ( !mMinWidthEq.empty() ) { + mMinSize.x = + lengthFromValue( mMinWidthEq, CSS::PropertyRelativeTarget::ContainingBlockWidth ); + } + + setSize( mDpSize ); } } @@ -595,7 +611,13 @@ const std::string& UIWidget::getMinHeightEq() const { void UIWidget::setMinHeightEq( const std::string& minHeightEq ) { if ( mMinHeightEq != minHeightEq ) { mMinHeightEq = minHeightEq; - setSize( mSize ); + + if ( !mMinHeightEq.empty() ) { + mMinSize.y = + lengthFromValue( mMinHeightEq, CSS::PropertyRelativeTarget::ContainingBlockHeight ); + } + + setSize( mDpSize ); } } @@ -607,14 +629,14 @@ void UIWidget::setMaxSizeEq( const std::string& maxWidthEq, const std::string& m if ( mMaxWidthEq != maxWidthEq || mMaxHeightEq != maxHeightEq ) { mMaxWidthEq = maxWidthEq; mMaxHeightEq = maxHeightEq; - setSize( mSize ); + setSize( mDpSize ); } } void UIWidget::setMaxWidthEq( const std::string& maxWidthEq ) { if ( mMaxWidthEq != maxWidthEq ) { mMaxWidthEq = maxWidthEq; - setSize( mSize ); + setSize( mDpSize ); } }