diff --git a/include/eepp/ui/uiwidget.hpp b/include/eepp/ui/uiwidget.hpp index 002d99949..1416bad91 100644 --- a/include/eepp/ui/uiwidget.hpp +++ b/include/eepp/ui/uiwidget.hpp @@ -625,6 +625,9 @@ class EE_API UIWidget : public UINode { */ virtual bool applyProperty( const StyleSheetProperty& attribute ); + /** @return The cursor resolved from this widget's current style. */ + Cursor::Type getCursor() const; + void propagateInheritedProperty( const CSS::StyleSheetProperty& property ); /** @@ -1518,6 +1521,7 @@ class EE_API UIWidget : public UINode { mutable Float mMinIntrinsicWidth{ 0 }; mutable Float mMaxIntrinsicWidth{ 0 }; mutable bool mIntrinsicWidthsDirty{ true }; + Uint8 mCursor{ static_cast( Cursor::Arrow ) }; Uint8 mMarginAuto{ 0 }; void calculateAutoMargin(); diff --git a/include/eepp/window/cursor.hpp b/include/eepp/window/cursor.hpp index f8b99cb06..bf3867526 100644 --- a/include/eepp/window/cursor.hpp +++ b/include/eepp/window/cursor.hpp @@ -36,6 +36,8 @@ class EE_API Cursor { static Cursor::Type fromName( std::string name ); + static const char* toName( Cursor::Type cursor ); + /** @enum SysType list the system cursors that can be used */ enum SysType { SysArrow = 0, /**< Arrow */ diff --git a/src/eepp/ui/css/stylesheetspecification.cpp b/src/eepp/ui/css/stylesheetspecification.cpp index dc218d6f3..89a817e38 100644 --- a/src/eepp/ui/css/stylesheetspecification.cpp +++ b/src/eepp/ui/css/stylesheetspecification.cpp @@ -212,7 +212,7 @@ void StyleSheetSpecification::registerDefaultProperties() { .setType( PropertyType::NumberLength ) .setRelativeTarget( PropertyRelativeTarget::ContainingBlockHeight ); registerProperty( "opacity", "" ).setType( PropertyType::NumberFloat ); - registerProperty( "cursor", "arrow" ); + registerProperty( "cursor", "arrow", true ); registerProperty( "text", "" ).setType( PropertyType::String ); registerProperty( "text-transform", "", true ).setType( PropertyType::String ); registerProperty( "color", "", true ) diff --git a/src/eepp/ui/uiwidget.cpp b/src/eepp/ui/uiwidget.cpp index 0c16ec591..5c25a2ada 100644 --- a/src/eepp/ui/uiwidget.cpp +++ b/src/eepp/ui/uiwidget.cpp @@ -509,7 +509,10 @@ Uint32 UIWidget::onMouseOver( const Vector2i& position, const Uint32& flags ) { } } - return UINode::onMouseOver( position, flags ); + Uint32 result = UINode::onMouseOver( position, flags ); + if ( mSceneNode ) + mSceneNode->setCursor( getCursor() ); + return result; } Uint32 UIWidget::onMouseLeave( const Vector2i& Pos, const Uint32& Flags ) { @@ -519,6 +522,8 @@ Uint32 UIWidget::onMouseLeave( const Vector2i& Pos, const Uint32& Flags ) { NULL != mTooltip && !mTooltip->dontAutoHideOnMouseMove() ) { mTooltip->hide(); } + if ( NULL != eventDispatcher && eventDispatcher->getMouseOverNode() == nullptr && mSceneNode ) + mSceneNode->setCursor( Cursor::Arrow ); return UINode::onMouseLeave( Pos, Flags ); } @@ -1691,6 +1696,10 @@ std::vector UIWidget::querySelectorAll( const std::string& selector ) return querySelectorAll( CSS::StyleSheetSelector( selector ) ); } +Cursor::Type UIWidget::getCursor() const { + return static_cast( mCursor ); +} + std::vector UIWidget::getPropertiesImplemented() const { return { PropertyId::X, PropertyId::Y, @@ -1832,7 +1841,7 @@ std::string UIWidget::getPropertyString( const PropertyDefinition* propertyDef, case PropertyId::Opacity: return String::fromFloat( getAlpha() / 255.f ); case PropertyId::Cursor: - return "arrow"; + return Cursor::toName( getCursor() ); case PropertyId::Visible: return isVisible() ? "true" : "false"; case PropertyId::Enabled: @@ -2410,7 +2419,10 @@ bool UIWidget::applyProperty( const StyleSheetProperty& attribute ) { break; } case PropertyId::Cursor: - mSceneNode->setCursor( Cursor::fromName( attribute.getValue() ) ); + mCursor = static_cast( Cursor::fromName( attribute.getValue() ) ); + if ( mSceneNode && getEventDispatcher() && + getEventDispatcher()->getMouseOverNode() == this ) + mSceneNode->setCursor( getCursor() ); break; case PropertyId::BackgroundPositionX: setBackgroundPositionX( attribute.value(), attribute.getIndex() ); diff --git a/src/eepp/window/cursor.cpp b/src/eepp/window/cursor.cpp index f3711bf7d..1f32a5ff3 100644 --- a/src/eepp/window/cursor.cpp +++ b/src/eepp/window/cursor.cpp @@ -88,6 +88,37 @@ Cursor::Type Cursor::fromName( std::string name ) { return Arrow; } +const char* Cursor::toName( Cursor::Type cursor ) { + switch ( cursor ) { + case Hand: + return "hand"; + case IBeam: + return "ibeam"; + case Wait: + return "wait"; + case Crosshair: + return "crosshair"; + case WaitArrow: + return "waitarrow"; + case SizeNWSE: + return "sizenwse"; + case SizeNESW: + return "sizenesw"; + case SizeWE: + return "sizewe"; + case SizeNS: + return "sizens"; + case SizeAll: + return "sizeall"; + case NoCursor: + return "nocursor"; + case Arrow: + case CursorCount: + return "arrow"; + } + return "arrow"; +} + const String::HashType& Cursor::getId() const { return mId; } diff --git a/src/tests/unit_tests/uihtml_float_tests.cpp b/src/tests/unit_tests/uihtml_float_tests.cpp index 8eb8405ba..ad1cdf699 100644 --- a/src/tests/unit_tests/uihtml_float_tests.cpp +++ b/src/tests/unit_tests/uihtml_float_tests.cpp @@ -650,6 +650,8 @@ UTEST( UIHTMLFloat, ss64BlockAnchorsAndSvgAtPixelDensity2 ) { ASSERT_TRUE( input != nullptr ); ASSERT_TRUE( searchButton != nullptr ); ASSERT_TRUE( svg != nullptr ); + EXPECT_EQ( searchButton->getCursor(), Cursor::Hand ); + EXPECT_EQ( svg->getCursor(), Cursor::Hand ); EXPECT_NEAR( input->getPixelsSize().getHeight(), 74.5f, 1.f ); EXPECT_NEAR( searchButton->getPixelsSize().getHeight(), 69.f, 1.f ); EXPECT_LE( searchButton->getPixelsPosition().y + searchButton->getPixelsSize().getHeight(), diff --git a/src/tests/unit_tests/uiscenenode_tests.cpp b/src/tests/unit_tests/uiscenenode_tests.cpp index aaf144b92..d3ceb0963 100644 --- a/src/tests/unit_tests/uiscenenode_tests.cpp +++ b/src/tests/unit_tests/uiscenenode_tests.cpp @@ -23,6 +23,8 @@ using namespace EE::UI; UTEST( UISceneNode, CssPointerCursorUsesHandCursor ) { EXPECT_EQ( Cursor::fromName( "pointer" ), Cursor::Hand ); EXPECT_EQ( Cursor::fromName( "POINTER" ), Cursor::Hand ); + EXPECT_STREQ( Cursor::toName( Cursor::Hand ), "hand" ); + EXPECT_STREQ( Cursor::toName( Cursor::Arrow ), "arrow" ); } static UISceneNode* init_test_scene_node() {