diff --git a/docs/articles/cssspecification.md b/docs/articles/cssspecification.md index e5e87f680..d00588385 100644 --- a/docs/articles/cssspecification.md +++ b/docs/articles/cssspecification.md @@ -1748,6 +1748,23 @@ Sets the text stroke (also known as text outline) width/thickness. --- +### text-transform + +The text-transform CSS property specifies how to capitalize an element's text. It can be used to +make text appear in all-uppercase or all-lowercase, or with each word capitalized. + +* Applicable to: EE::UI::UITextView (TextView) and any element that holds inside or extends from a + TextView, EE::UI::UITooltip (Tooltip). +* Data Type: [string-list](#string-list-data-type) +* Value List: + * `lowercase` + * `uppercase` + * `capitalize` + * `none` +* Default value: `none` + +--- + ### theme Sets a theme to the element. Changing the theme will not have any effect unless [skin](#skin) is also set. diff --git a/include/eepp/core/string.hpp b/include/eepp/core/string.hpp index 15e1675f7..2f4e53b7c 100644 --- a/include/eepp/core/string.hpp +++ b/include/eepp/core/string.hpp @@ -165,15 +165,24 @@ class EE_API String { /** Convert the reference of a string into lower case string */ static void toLowerInPlace( std::string& str ); + /** Capitalizes the reference of a string */ + static void capitalizeInPlace( std::string& str ); + /** Convert a string to lower case */ static std::string toLower( std::string str ); + /** Catitalize a string */ + static std::string capitalize( std::string str ); + /** Convert a string to lower case */ static String toUpper( const String& str ); /** Convert a string to lower case */ static String toLower( const String& str ); + /** Capitalizes a string */ + static String capitalize( const String& str ); + /** Convert the string to an std::vector */ static std::vector stringToUint8( const std::string& str ); @@ -791,6 +800,8 @@ class EE_API String { String& toUpper(); + String& capitalize(); + String& escape(); String& unescape(); diff --git a/include/eepp/graphics/text.hpp b/include/eepp/graphics/text.hpp index 15ca46b43..db3886ee8 100644 --- a/include/eepp/graphics/text.hpp +++ b/include/eepp/graphics/text.hpp @@ -3,6 +3,7 @@ #include #include +#include namespace EE { namespace Graphics { @@ -56,6 +57,8 @@ class EE_API Text { void setOutlineThickness( Float thickness ); + void transformText( const TextTransform::Value& transform ); + String& getString(); Font* getFont() const; diff --git a/include/eepp/graphics/texttransform.hpp b/include/eepp/graphics/texttransform.hpp new file mode 100644 index 000000000..7fc0dcffd --- /dev/null +++ b/include/eepp/graphics/texttransform.hpp @@ -0,0 +1,40 @@ +#ifndef EE_GRAPHICS_TEXTTRANSFORM_HPP +#define EE_GRAPHICS_TEXTTRANSFORM_HPP + +#include + +namespace EE { namespace Graphics { + +class TextTransform { + public: + enum Value { LowerCase, UpperCase, Capitalize, None }; + + static TextTransform::Value fromString( std::string str ) { + String::toLowerInPlace( str ); + if ( str == "lowercase" ) + return LowerCase; + else if ( str == "uppercase" ) + return UpperCase; + else if ( str == "capitalize" ) + return Capitalize; + return None; + } + + static std::string toString( const TextTransform::Value& val ) { + switch ( val ) { + case LowerCase: + return "lowercase"; + case UpperCase: + return "uppercase"; + case Capitalize: + return "capitalize"; + case None: + return "none"; + } + return "none"; + } +}; + +}} // namespace EE::Graphics + +#endif // EE_GRAPHICS_TEXTTRANSFORM_HPP diff --git a/include/eepp/ui/css/propertydefinition.hpp b/include/eepp/ui/css/propertydefinition.hpp index fb75d4784..a2c71028a 100644 --- a/include/eepp/ui/css/propertydefinition.hpp +++ b/include/eepp/ui/css/propertydefinition.hpp @@ -63,6 +63,7 @@ enum class PropertyId : Uint32 { Opacity = String::hash( "opacity" ), Cursor = String::hash( "cursor" ), Text = String::hash( "text" ), + TextTransform = String::hash( "text-transform" ), Color = String::hash( "color" ), ShadowColor = String::hash( "shadow-color" ), SelectionColor = String::hash( "selection-color" ), diff --git a/include/eepp/ui/uitextview.hpp b/include/eepp/ui/uitextview.hpp index e450459b7..14346bcf6 100644 --- a/include/eepp/ui/uitextview.hpp +++ b/include/eepp/ui/uitextview.hpp @@ -1,5 +1,5 @@ -#ifndef EE_UICUITEXTBOX_H -#define EE_UICUITEXTBOX_H +#ifndef EE_UI_UITEXTVIEW_HPP +#define EE_UI_UITEXTVIEW_HPP #include #include @@ -96,6 +96,10 @@ class EE_API UITextView : public UIWidget { const Vector2f& getRealAlignOffset() const; + const TextTransform::Value& getTextTransform() const; + + void setTextTransform( const TextTransform::Value& textTransform ); + protected: Text* mTextCache; String mString; @@ -114,6 +118,7 @@ class EE_API UITextView : public UIWidget { Int32 mLastSelCurEnd; Int32 mFontLineCenter; bool mSelecting; + TextTransform::Value mTextTransform{ TextTransform::None }; virtual void drawSelection( Text* textCache ); @@ -155,6 +160,8 @@ class EE_API UITextView : public UIWidget { const Int32& getFontLineCenter(); + void transformText(); + void recalculate(); void resetSelCache(); diff --git a/include/eepp/ui/uitooltip.hpp b/include/eepp/ui/uitooltip.hpp index 37879e0cd..543feb425 100644 --- a/include/eepp/ui/uitooltip.hpp +++ b/include/eepp/ui/uitooltip.hpp @@ -1,6 +1,7 @@ #ifndef EE_UICUITOOLTIP_HPP #define EE_UICUITOOLTIP_HPP +#include #include #include @@ -100,6 +101,10 @@ class EE_API UITooltip : public UIWidget { void setDontAutoHideOnMouseMove( bool dontAutoHideOnMouseMove ); + const TextTransform::Value& getTextTransform() const; + + void setTextTransform( const TextTransform::Value& textTransform ); + protected: Text* mTextCache; UIFontStyleConfig mStyleConfig; @@ -107,6 +112,7 @@ class EE_API UITooltip : public UIWidget { Time mTooltipTime; UINode* mTooltipOf; String mStringBuffer; + TextTransform::Value mTextTransform{ TextTransform::None }; bool mDontAutoHideOnMouseMove{ false }; virtual void onAlphaChange(); @@ -118,6 +124,8 @@ class EE_API UITooltip : public UIWidget { virtual void autoAlign(); virtual void autoPadding(); + + void transformText(); }; }} // namespace EE::UI diff --git a/src/eepp/core/string.cpp b/src/eepp/core/string.cpp index 2e3e71d0d..9c812ec41 100644 --- a/src/eepp/core/string.cpp +++ b/src/eepp/core/string.cpp @@ -520,12 +520,31 @@ void String::toLowerInPlace( std::string& str ) { std::transform( str.begin(), str.end(), str.begin(), (int ( * )( int ))std::tolower ); } +void String::capitalizeInPlace( std::string& str ) { + char last = ' '; + for ( std::string::iterator i = str.begin(); i != str.end(); ++i ) { + if ( isspace( last ) || last == '.' ) + *i = toupper( *i ); + last = *i; + } +} + std::string String::toLower( std::string str ) { for ( std::string::iterator i = str.begin(); i != str.end(); ++i ) *i = static_cast( std::tolower( *i ) ); return str; } +std::string String::capitalize( std::string str ) { + char last = ' '; + for ( std::string::iterator i = str.begin(); i != str.end(); ++i ) { + if ( isspace( last ) || last == '.' ) + *i = toupper( *i ); + last = *i; + } + return str; +} + String String::toUpper( const String& str ) { String cpy( str ); cpy.toUpper(); @@ -538,6 +557,12 @@ String String::toLower( const String& str ) { return cpy; } +String String::capitalize( const String& str ) { + String cpy( str ); + cpy.capitalize(); + return cpy; +} + String& String::toLower() { for ( StringType::iterator i = mString.begin(); i != mString.end(); ++i ) *i = static_cast( std::tolower( *i ) ); @@ -550,6 +575,16 @@ String& String::toUpper() { return *this; } +String& String::capitalize() { + String::StringBaseType last = ' '; + for ( StringType::iterator i = mString.begin(); i != mString.end(); ++i ) { + if ( isspace( last ) || last == '.' ) + *i = toupper( *i ); + last = *i; + } + return *this; +} + String& String::escape() { this->assign( String::escape( *this ) ); return *this; diff --git a/src/eepp/graphics/text.cpp b/src/eepp/graphics/text.cpp index 0a4da7029..a62e30b9b 100644 --- a/src/eepp/graphics/text.cpp +++ b/src/eepp/graphics/text.cpp @@ -250,6 +250,22 @@ void Text::setOutlineThickness( Float thickness ) { } } +void Text::transformText( const TextTransform::Value& transform ) { + switch ( transform ) { + case TextTransform::LowerCase: + setString( String::toLower( mString ) ); + break; + case TextTransform::UpperCase: + setString( String::toUpper( mString ) ); + break; + case TextTransform::Capitalize: + setString( String::capitalize( mString ) ); + break; + default: + break; + } +} + String& Text::getString() { return mString; } diff --git a/src/eepp/ui/css/stylesheetspecification.cpp b/src/eepp/ui/css/stylesheetspecification.cpp index b317a3d34..e5da93438 100644 --- a/src/eepp/ui/css/stylesheetspecification.cpp +++ b/src/eepp/ui/css/stylesheetspecification.cpp @@ -190,6 +190,7 @@ void StyleSheetSpecification::registerDefaultProperties() { registerProperty( "opacity", "" ).setType( PropertyType::NumberFloat ); registerProperty( "cursor", "arrow" ); registerProperty( "text", "" ).setType( PropertyType::String ); + registerProperty( "text-transform", "" ).setType( PropertyType::String ); registerProperty( "color", "" ) .setType( PropertyType::Color ) .addAlias( "text-color" ) diff --git a/src/eepp/ui/uipushbutton.cpp b/src/eepp/ui/uipushbutton.cpp index 3f2e0a878..11ab91592 100644 --- a/src/eepp/ui/uipushbutton.cpp +++ b/src/eepp/ui/uipushbutton.cpp @@ -463,6 +463,7 @@ std::string UIPushButton::getPropertyString( const PropertyDefinition* propertyD case PropertyId::TextStrokeWidth: case PropertyId::TextStrokeColor: case PropertyId::TextSelection: + case PropertyId::TextTransform: return mTextBox->getPropertyString( propertyDef, propertyIndex ); default: return UIWidget::getPropertyString( propertyDef, propertyIndex ); @@ -529,6 +530,7 @@ bool UIPushButton::applyProperty( const StyleSheetProperty& attribute ) { case PropertyId::TextStrokeWidth: case PropertyId::TextStrokeColor: case PropertyId::TextSelection: + case PropertyId::TextTransform: attributeSet = mTextBox->applyProperty( attribute ); break; default: diff --git a/src/eepp/ui/uitextview.cpp b/src/eepp/ui/uitextview.cpp index b36f266f9..d19d2e666 100644 --- a/src/eepp/ui/uitextview.cpp +++ b/src/eepp/ui/uitextview.cpp @@ -235,6 +235,23 @@ const Vector2f& UITextView::getRealAlignOffset() const { return mRealAlignOffset; } +const TextTransform::Value& UITextView::getTextTransform() const { + return mTextTransform; +} + +void UITextView::transformText() { + mTextCache->setString( mString ); + mTextCache->transformText( mTextTransform ); +} + +void UITextView::setTextTransform( const TextTransform::Value& textTransform ) { + if ( textTransform != mTextTransform ) { + mTextTransform = textTransform; + transformText(); + recalculate(); + } +} + const Color& UITextView::getFontShadowColor() const { return mFontStyleConfig.ShadowColor; } @@ -281,8 +298,11 @@ void UITextView::wrapText( const Uint32& maxWidth ) { } void UITextView::onAutoSize() { + bool sizeChanged = false; + if ( ( mFlags & UI_AUTO_SIZE && 0 == getSize().getWidth() ) ) { setInternalPixelsSize( Sizef( mTextCache->getTextWidth(), mTextCache->getTextHeight() ) ); + sizeChanged = true; } if ( mWidthPolicy == SizePolicy::WrapContent ) { @@ -293,7 +313,10 @@ void UITextView::onAutoSize() { if ( oldW != totW ) setClipType( ClipType::ContentBox ); } - setInternalPixelsWidth( totW ); + if ( mSize.x != totW ) { + setInternalPixelsWidth( totW ); + sizeChanged = true; + } } if ( mHeightPolicy == SizePolicy::WrapContent ) { @@ -304,8 +327,14 @@ void UITextView::onAutoSize() { if ( oldH != totH ) setClipType( ClipType::ContentBox ); } - setInternalPixelsHeight( totH ); + if ( mSize.y != totH ) { + setInternalPixelsHeight( totH ); + sizeChanged = true; + } } + + if ( sizeChanged ) + notifyLayoutAttrChange(); } void UITextView::alignFix() { @@ -624,6 +653,9 @@ bool UITextView::applyProperty( const StyleSheetProperty& attribute ) { case PropertyId::Text: setText( getTranslatorString( attribute.asString() ) ); break; + case PropertyId::TextTransform: + setTextTransform( TextTransform::fromString( attribute.asString() ) ); + break; case PropertyId::Color: setFontColor( attribute.asColor() ); break; @@ -700,6 +732,8 @@ std::string UITextView::getPropertyString( const PropertyDefinition* propertyDef switch ( propertyDef->getPropertyId() ) { case PropertyId::Text: return getText().toUtf8(); + case PropertyId::TextTransform: + return TextTransform::toString( getTextTransform() ); case PropertyId::Color: return getFontColor().toHexString(); case PropertyId::ShadowColor: diff --git a/src/eepp/ui/uitooltip.cpp b/src/eepp/ui/uitooltip.cpp index 0bf7ee03d..c09a38a42 100644 --- a/src/eepp/ui/uitooltip.cpp +++ b/src/eepp/ui/uitooltip.cpp @@ -341,6 +341,8 @@ std::string UITooltip::getPropertyString( const PropertyDefinition* propertyDef, return ""; switch ( propertyDef->getPropertyId() ) { + case PropertyId::TextTransform: + return TextTransform::toString( getTextTransform() ); case PropertyId::Color: return getFontColor().toHexString(); case PropertyId::ShadowColor: @@ -385,11 +387,28 @@ void UITooltip::setDontAutoHideOnMouseMove( bool dontAutoHideOnMouseMove ) { mDontAutoHideOnMouseMove = dontAutoHideOnMouseMove; } +void UITooltip::transformText() { + mTextCache->transformText( mTextTransform ); +} + +const TextTransform::Value& UITooltip::getTextTransform() const { + return mTextTransform; +} + +void UITooltip::setTextTransform( const TextTransform::Value& textTransform ) { + if ( textTransform != mTextTransform ) { + mTextTransform = textTransform; + transformText(); + } +} + bool UITooltip::applyProperty( const StyleSheetProperty& attribute ) { if ( !checkPropertyDefinition( attribute ) ) return false; switch ( attribute.getPropertyDefinition()->getPropertyId() ) { + case PropertyId::TextTransform: + setTextTransform( TextTransform::fromString( attribute.asString() ) ); case PropertyId::Color: setFontColor( attribute.asColor() ); break;