diff --git a/docs/articles/cssspecification.md b/docs/articles/cssspecification.md index cfd51e4a8..d2158424d 100644 --- a/docs/articles/cssspecification.md +++ b/docs/articles/cssspecification.md @@ -1279,6 +1279,22 @@ Sets the maximum visible items for the list shown by a drop down list or combo b --- +### menu-width-mode + +Sets how is the dropdown-menu width calculated. + +* Applicable to: EE::UI::UIDropDownList (DropDownList), EE::UI::UIComboBox (ComboBox) +* Data Type: [string-list](#string-list-data-type) +* Value List: + * `dropdown`: Same width as the dropdown button. + * `contents`: The length of its contents. + * `contents-center`: The length of its contents but centered against the dropdown button. + * `expand-if-needed`: Same width as the dropdown button unless its contents are larger than the dropdown button, in that case it will expand to its contents. + * `expand-if-needed-center`: Same as `expand-if-needed` but centered against the dropdown button. +* Default value: `dropdown` + +--- + ### min-height Read [min-height](https://developer.mozilla.org/en-US/docs/Web/CSS/min-height) documentation. diff --git a/include/eepp/ui/css/propertydefinition.hpp b/include/eepp/ui/css/propertydefinition.hpp index 14780c951..e2e3a3e71 100644 --- a/include/eepp/ui/css/propertydefinition.hpp +++ b/include/eepp/ui/css/propertydefinition.hpp @@ -225,6 +225,7 @@ enum class PropertyId : Uint32 { LineWrapMode = String::hash( "line-wrap-mode" ), LineWrapType = String::hash( "line-wrap-type" ), DisplayOptions = String::hash( "display-options" ), + MenuWidthMode = String::hash( "menu-width-mode" ), }; enum class PropertyType : Uint32 { diff --git a/include/eepp/ui/uidropdownlist.hpp b/include/eepp/ui/uidropdownlist.hpp index 8f28f123e..d8ada4edd 100644 --- a/include/eepp/ui/uidropdownlist.hpp +++ b/include/eepp/ui/uidropdownlist.hpp @@ -8,10 +8,23 @@ namespace EE { namespace UI { class EE_API UIDropDownList : public UITextInput { public: + enum class MenuWidthMode { + DropDown, + Contents, + ContentsCentered, + ExpandIfNeeded, + ExpandIfNeededCentered + }; + + static MenuWidthMode menuWidthModeFromString( std::string_view str ); + + static std::string menuWidthModeToString( MenuWidthMode rule ); + class StyleConfig { public: Uint32 MaxNumVisibleItems = 10; bool PopUpToRoot = false; + MenuWidthMode menuWidthRule{ MenuWidthMode::DropDown }; }; static UIDropDownList* NewWithTag( const std::string& tag ); @@ -30,19 +43,19 @@ class EE_API UIDropDownList : public UITextInput { UIListBox* getListBox() const; - void showList(); + UIDropDownList* showList(); bool getPopUpToRoot() const; - void setPopUpToRoot( bool popUpToRoot ); + UIDropDownList* setPopUpToRoot( bool popUpToRoot ); Uint32 getMaxNumVisibleItems() const; - void setMaxNumVisibleItems( const Uint32& maxNumVisibleItems ); + UIDropDownList* setMaxNumVisibleItems( const Uint32& maxNumVisibleItems ); const StyleConfig& getStyleConfig() const; - void setStyleConfig( const StyleConfig& styleConfig ); + UIDropDownList* setStyleConfig( const StyleConfig& styleConfig ); virtual bool applyProperty( const StyleSheetProperty& attribute ); @@ -53,6 +66,10 @@ class EE_API UIDropDownList : public UITextInput { virtual void loadFromXmlNode( const pugi::xml_node& node ); + UIDropDownList* setMenuWidthMode( MenuWidthMode rule ); + + MenuWidthMode getMenuWidthMode() const; + protected: friend class UIComboBox; diff --git a/include/eepp/ui/uilistbox.hpp b/include/eepp/ui/uilistbox.hpp index fb499ffc5..b6903ce0c 100644 --- a/include/eepp/ui/uilistbox.hpp +++ b/include/eepp/ui/uilistbox.hpp @@ -116,6 +116,8 @@ class EE_API UIListBox : public UITouchDraggableWidget { void setItemText( const Uint32& index, const String& newText ); + UIListBoxItem* getReferenceItem() const { return mDummyItem; } + protected: friend class UIListBoxItem; friend class UIItemContainer; diff --git a/src/eepp/ui/css/stylesheetspecification.cpp b/src/eepp/ui/css/stylesheetspecification.cpp index 71490209b..c87240b98 100644 --- a/src/eepp/ui/css/stylesheetspecification.cpp +++ b/src/eepp/ui/css/stylesheetspecification.cpp @@ -421,6 +421,7 @@ void StyleSheetSpecification::registerDefaultProperties() { registerProperty( "line-wrap-type", "viewport" ).setType( PropertyType::String ); registerProperty( "display-options", "" ).setType( PropertyType::String ); + registerProperty( "menu-width-mode", "" ).setType( PropertyType::String ); // Shorthands registerShorthand( "margin", { "margin-top", "margin-right", "margin-bottom", "margin-left" }, diff --git a/src/eepp/ui/uicombobox.cpp b/src/eepp/ui/uicombobox.cpp index b6815b11b..1117ccd30 100644 --- a/src/eepp/ui/uicombobox.cpp +++ b/src/eepp/ui/uicombobox.cpp @@ -179,6 +179,7 @@ bool UIComboBox::applyProperty( const StyleSheetProperty& attribute ) { case PropertyId::RowHeight: case PropertyId::VScrollMode: case PropertyId::HScrollMode: + case PropertyId::MenuWidthMode: return mDropDownList->applyProperty( attribute ); default: return UIWidget::applyProperty( attribute ); @@ -229,6 +230,7 @@ std::string UIComboBox::getPropertyString( const PropertyDefinition* propertyDef case PropertyId::RowHeight: case PropertyId::VScrollMode: case PropertyId::HScrollMode: + case PropertyId::MenuWidthMode: return mDropDownList->getPropertyString( propertyDef, propertyIndex ); default: return UIWidget::getPropertyString( propertyDef, propertyIndex ); @@ -274,6 +276,7 @@ std::vector UIComboBox::getPropertiesImplemented() const { PropertyId::RowHeight, PropertyId::VScrollMode, PropertyId::HScrollMode, + PropertyId::MenuWidthMode, }; props.insert( props.end(), local.begin(), local.end() ); return props; diff --git a/src/eepp/ui/uidropdownlist.cpp b/src/eepp/ui/uidropdownlist.cpp index 875eb28a4..314b94bd5 100644 --- a/src/eepp/ui/uidropdownlist.cpp +++ b/src/eepp/ui/uidropdownlist.cpp @@ -10,6 +10,35 @@ namespace EE { namespace UI { +UIDropDownList::MenuWidthMode +UIDropDownList::menuWidthModeFromString( std::string_view str ) { + if ( "contents" == str || "fit-to-contents" == str ) + return MenuWidthMode::Contents; + if ( "contents-centered" == str || "fit-to-contents-centered" == str ) + return MenuWidthMode::ContentsCentered; + if ( "expand-if-needed" == str || "fit-to-drop-down-expand-if-needed" == str ) + return MenuWidthMode::ExpandIfNeeded; + if ( "expand-if-needed-centered" == str || "fit-to-drop-down-expand-if-needed-centered" == str ) + return MenuWidthMode::ExpandIfNeededCentered; + return MenuWidthMode::DropDown; // "dropdown" +} + +std::string UIDropDownList::menuWidthModeToString( MenuWidthMode rule ) { + switch ( rule ) { + case MenuWidthMode::DropDown: + return "dropdown"; + case MenuWidthMode::Contents: + return "contents"; + case MenuWidthMode::ContentsCentered: + return "contents-centered"; + case MenuWidthMode::ExpandIfNeeded: + return "expand-if-needed"; + case MenuWidthMode::ExpandIfNeededCentered: + return "expand-if-needed-centered"; + } + return "dropdown"; +} + UIDropDownList* UIDropDownList::NewWithTag( const std::string& tag ) { return eeNew( UIDropDownList, ( tag ) ); } @@ -138,9 +167,9 @@ Uint32 UIDropDownList::onMouseClick( const Vector2i& Pos, const Uint32& Flags ) return 1; } -void UIDropDownList::showList() { +UIDropDownList* UIDropDownList::showList() { if ( NULL == mListBox ) - return; + return this; if ( !mListBox->isVisible() ) { if ( mListBox->getCount() ) { @@ -151,6 +180,36 @@ void UIDropDownList::showList() { Float width = NULL != mFriendNode ? mFriendNode->getSize().getWidth() : getSize().getWidth(); + bool center = + mStyleConfig.menuWidthRule == MenuWidthMode::ContentsCentered || + mStyleConfig.menuWidthRule == + MenuWidthMode::ExpandIfNeededCentered; + + Float contentsWidth = 0; + if ( mStyleConfig.menuWidthRule == MenuWidthMode::Contents || + mStyleConfig.menuWidthRule == MenuWidthMode::ContentsCentered || + mStyleConfig.menuWidthRule == MenuWidthMode::ExpandIfNeeded || + mStyleConfig.menuWidthRule == + MenuWidthMode::ExpandIfNeededCentered ) { + contentsWidth = eeceil( PixelDensity::pxToDp( + mListBox->getMaxTextWidth() + + PixelDensity::dpToPx( mListBox->getContainerPadding().getWidth() ) + + mListBox->getReferenceItem()->getPixelsPadding().getWidth() + + mListBox->getVerticalScrollBar()->getPixelsSize().getWidth() ) ); + } + + if ( mStyleConfig.menuWidthRule == MenuWidthMode::Contents || + mStyleConfig.menuWidthRule == MenuWidthMode::ContentsCentered ) { + width = contentsWidth; + } + + if ( ( mStyleConfig.menuWidthRule == MenuWidthMode::ExpandIfNeeded || + mStyleConfig.menuWidthRule == + MenuWidthMode::ExpandIfNeededCentered ) && + contentsWidth > width ) { + width = contentsWidth; + } + mListBox->setSize( width, (Int32)( eemin( mListBox->getCount(), mStyleConfig.MaxNumVisibleItems ) * mListBox->getRowHeight() ) + @@ -170,13 +229,15 @@ void UIDropDownList::showList() { mListBox->toFront(); - Vector2f pos( mDpPos.x, mDpPos.y + getSize().getHeight() ); + Float offsetX = center ? eefloor( ( getSize().getWidth() - width ) * 0.5f ) : 0; + + Vector2f pos( mDpPos.x + offsetX, mDpPos.y + getSize().getHeight() ); Vector2f posCpy( pos ); nodeToWorld( posCpy ); if ( !getUISceneNode()->getWorldBounds().contains( Rectf( posCpy, mListBox->getSize() ) ) ) { - pos = Vector2f( mDpPos.x, mDpPos.y - mListBox->getSize().getHeight() ); + pos = Vector2f( mDpPos.x + offsetX, mDpPos.y - mListBox->getSize().getHeight() ); } if ( mStyleConfig.PopUpToRoot ) { @@ -200,21 +261,23 @@ void UIDropDownList::showList() { } else { hide(); } + return this; } bool UIDropDownList::getPopUpToRoot() const { return mStyleConfig.PopUpToRoot; } -void UIDropDownList::setPopUpToRoot( bool popUpToRoot ) { +UIDropDownList* UIDropDownList::setPopUpToRoot( bool popUpToRoot ) { mStyleConfig.PopUpToRoot = popUpToRoot; + return this; } Uint32 UIDropDownList::getMaxNumVisibleItems() const { return mStyleConfig.MaxNumVisibleItems; } -void UIDropDownList::setMaxNumVisibleItems( const Uint32& maxNumVisibleItems ) { +UIDropDownList* UIDropDownList::setMaxNumVisibleItems( const Uint32& maxNumVisibleItems ) { if ( maxNumVisibleItems != mStyleConfig.MaxNumVisibleItems ) { mStyleConfig.MaxNumVisibleItems = maxNumVisibleItems; @@ -223,17 +286,20 @@ void UIDropDownList::setMaxNumVisibleItems( const Uint32& maxNumVisibleItems ) { getListBox()->getCount() ) * mListBox->getRowHeight() ); } + return this; } const UIDropDownList::StyleConfig& UIDropDownList::getStyleConfig() const { return mStyleConfig; } -void UIDropDownList::setStyleConfig( const StyleConfig& styleConfig ) { +UIDropDownList* UIDropDownList::setStyleConfig( const StyleConfig& styleConfig ) { mStyleConfig = styleConfig; setMaxNumVisibleItems( mStyleConfig.MaxNumVisibleItems ); setPopUpToRoot( mStyleConfig.PopUpToRoot ); + setMenuWidthMode( mStyleConfig.menuWidthRule ); + return this; } void UIDropDownList::onWidgetClear( const Event* ) { @@ -352,6 +418,9 @@ bool UIDropDownList::applyProperty( const StyleSheetProperty& attribute ) { case PropertyId::MaxVisibleItems: setMaxNumVisibleItems( attribute.asUint() ); break; + case PropertyId::MenuWidthMode: + setMenuWidthMode( menuWidthModeFromString( attribute.getValue() ) ); + break; case PropertyId::SelectedIndex: case PropertyId::SelectedText: case PropertyId::ScrollBarStyle: @@ -379,6 +448,8 @@ std::string UIDropDownList::getPropertyString( const PropertyDefinition* propert return mStyleConfig.PopUpToRoot ? "true" : "false"; case PropertyId::MaxVisibleItems: return String::toString( mStyleConfig.MaxNumVisibleItems ); + case PropertyId::MenuWidthMode: + return menuWidthModeToString( mStyleConfig.menuWidthRule ); case PropertyId::SelectedIndex: case PropertyId::SelectedText: case PropertyId::ScrollBarStyle: @@ -398,7 +469,7 @@ std::vector UIDropDownList::getPropertiesImplemented() const { auto props = UITextInput::getPropertiesImplemented(); auto local = { PropertyId::PopUpToRoot, PropertyId::MaxVisibleItems, PropertyId::SelectedIndex, PropertyId::SelectedText, PropertyId::ScrollBarStyle, PropertyId::RowHeight, - PropertyId::VScrollMode, PropertyId::HScrollMode }; + PropertyId::VScrollMode, PropertyId::HScrollMode, PropertyId::MenuWidthMode }; props.insert( props.end(), local.begin(), local.end() ); return props; } @@ -419,4 +490,13 @@ void UIDropDownList::onClassChange() { mListBox->setClasses( getClasses() ); } +UIDropDownList* UIDropDownList::setMenuWidthMode( MenuWidthMode rule ) { + mStyleConfig.menuWidthRule = rule; + return this; +} + +UIDropDownList::MenuWidthMode UIDropDownList::getMenuWidthMode() const { + return mStyleConfig.menuWidthRule; +} + }} // namespace EE::UI diff --git a/src/eepp/ui/uilistbox.cpp b/src/eepp/ui/uilistbox.cpp index b4c76265b..24ef94b93 100644 --- a/src/eepp/ui/uilistbox.cpp +++ b/src/eepp/ui/uilistbox.cpp @@ -132,22 +132,23 @@ void UIListBox::addListBoxItems( std::vector texts ) { mItems.push_back( NULL ); } + findMaxWidth(); updatePageStep(); updateScroll(); } -Uint32 UIListBox::addListBoxItem( UIListBoxItem* Item ) { - mItems.push_back( Item ); - mTexts.push_back( Item->getText() ); +Uint32 UIListBox::addListBoxItem( UIListBoxItem* item ) { + mItems.push_back( item ); + mTexts.push_back( item->getText() ); - if ( Item->getParent() != mContainer ) - Item->setParent( mContainer ); + if ( item->getParent() != mContainer ) + item->setParent( mContainer ); updateScroll(); Uint32 tMaxTextWidth = mMaxTextWidth; - itemUpdateSize( Item ); + itemUpdateSize( item ); if ( tMaxTextWidth != mMaxTextWidth ) { updateListBoxItemsSize(); @@ -249,11 +250,11 @@ Uint32 UIListBox::getListBoxItemIndex( const String& Name ) { return eeINDEX_NOT_FOUND; } -Uint32 UIListBox::getListBoxItemIndex( UIListBoxItem* Item ) { +Uint32 UIListBox::getListBoxItemIndex( UIListBoxItem* item ) { Uint32 size = (Uint32)mItems.size(); for ( Uint32 i = 0; i < size; i++ ) { - if ( Item == mItems[i] ) + if ( item == mItems[i] ) return i; } @@ -357,9 +358,7 @@ void UIListBox::findMaxWidth() { return; Uint32 size = (Uint32)mItems.size(); - Int32 width; - Text textCache; - textCache.setStyleConfig( fontStyleConfig ); + Float width; mMaxTextWidth = 0; @@ -367,11 +366,10 @@ void UIListBox::findMaxWidth() { if ( NULL != mItems[i] ) { width = (Int32)mItems[i]->getTextWidth(); } else { - textCache.setString( mTexts[i] ); - width = textCache.getTextWidth(); + width = Text::getTextWidth( mTexts[i], fontStyleConfig ); } - if ( width > (Int32)mMaxTextWidth ) + if ( width > (Float)mMaxTextWidth ) mMaxTextWidth = width; } } @@ -383,27 +381,28 @@ void UIListBox::updateListBoxItemsSize() { itemUpdateSize( mItems[i] ); } -void UIListBox::itemUpdateSize( UIListBoxItem* Item ) { - if ( NULL != Item ) { - Int32 width = (Int32)Item->getTextWidth(); +void UIListBox::itemUpdateSize( UIListBoxItem* item ) { + if ( NULL == item ) + return; - if ( width > (Int32)mMaxTextWidth ) { - mMaxTextWidth = width; - } + Float width = eeceil( item->getTextWidth() ); - if ( !mHScrollBar->isVisible() ) { - if ( width < mContainer->getSize().getWidth() ) - width = mContainer->getSize().getWidth(); - - if ( ( mItemsNotVisible > 0 && ScrollBarMode::Auto == mVScrollMode ) || - ScrollBarMode::AlwaysOn == mVScrollMode ) - width -= mVScrollBar->getSize().getWidth(); - } else { - width = mMaxTextWidth; - } - - Item->setSize( width, mRowHeight ); + if ( width > (Float)mMaxTextWidth ) { + mMaxTextWidth = width; } + + if ( !mHScrollBar->isVisible() ) { + if ( width < mContainer->getPixelsSize().getWidth() ) + width = mContainer->getPixelsSize().getWidth(); + + if ( ( mItemsNotVisible > 0 && ScrollBarMode::Auto == mVScrollMode ) || + ScrollBarMode::AlwaysOn == mVScrollMode ) + width -= mVScrollBar->getPixelsSize().getWidth(); + } else { + width = mMaxTextWidth; + } + + item->setPixelsSize( width, PixelDensity::dpToPx( mRowHeight ) ); } void UIListBox::containerResize() { diff --git a/src/tools/ecode/plugins/aiassistant/chatui.cpp b/src/tools/ecode/plugins/aiassistant/chatui.cpp index 0ebbc0b69..1f0d0472b 100644 --- a/src/tools/ecode/plugins/aiassistant/chatui.cpp +++ b/src/tools/ecode/plugins/aiassistant/chatui.cpp @@ -166,7 +166,7 @@ DropDownList.role_ui { - + diff --git a/src/tools/ecode/projectbuild.cpp b/src/tools/ecode/projectbuild.cpp index 1a94d50cd..8d2fe4016 100644 --- a/src/tools/ecode/projectbuild.cpp +++ b/src/tools/ecode/projectbuild.cpp @@ -1179,16 +1179,16 @@ void ProjectBuildManager::buildSidePanelTab() { - + - + - +