Fix stack-overflow when auto-sizing dropdowns.

Fix combobox button click not closing the popup listbox when clicking the button with a visible popup listbox.
Fix some incorrect size policies in UIFileDialog.
This commit is contained in:
Martín Lucas Golini
2026-08-20 14:01:42 -03:00
parent 503cd890a5
commit f193047f1e
8 changed files with 46 additions and 16 deletions
+2 -2
View File
@@ -21,7 +21,7 @@ class EE_API UIComboBox : public UIWidget {
UIDropDownList* getDropDownList() const { return mDropDownList; } UIDropDownList* getDropDownList() const { return mDropDownList; }
UINode* getButton() const { return mButton; } UIWidget* getButton() const { return mButton; }
const String& getText(); const String& getText();
@@ -38,7 +38,7 @@ class EE_API UIComboBox : public UIWidget {
protected: protected:
UIDropDownList* mDropDownList; UIDropDownList* mDropDownList;
UINode* mButton; UIWidget* mButton;
UIComboBox(); UIComboBox();
+10 -1
View File
@@ -51,15 +51,24 @@ class EE_API UIDropDown : public UITextInput {
const Uint32& propertyIndex = 0 ) const; const Uint32& propertyIndex = 0 ) const;
virtual std::vector<PropertyId> getPropertiesImplemented() const; virtual std::vector<PropertyId> getPropertiesImplemented() const;
void addRelatedWidget( UIWidget* widget ) { mRelatedWidgets.push_back( widget ); }
void removeRelatedWidget( UIWidget* widget ) {
mRelatedWidgets.erase(
std::find( mRelatedWidgets.begin(), mRelatedWidgets.end(), widget ) );
}
protected: protected:
StyleConfig mStyleConfig; StyleConfig mStyleConfig;
UINode* mFriendNode{ nullptr }; UINode* mFriendNode{ nullptr };
Uint64 mLastFocusLoss{ 0 };
std::vector<UIWidget*> mRelatedWidgets;
UIDropDown( const std::string& tag ); UIDropDown( const std::string& tag );
virtual UIWidget* getPopUpWidget() const; virtual UIWidget* getPopUpWidget() const;
void onPopUpFocusLoss( const Event* Event ); virtual void onPopUpFocusLoss();
virtual void onItemSelected( const Event* Event ); virtual void onItemSelected( const Event* Event );
virtual void show(); virtual void show();
+1
View File
@@ -47,6 +47,7 @@ enum UIFlag : Int64 {
UI_HTML_ELEMENT = ( 1ULL << 31 ), UI_HTML_ELEMENT = ( 1ULL << 31 ),
UI_CREATING_NODE = ( 1ULL << 32 ), UI_CREATING_NODE = ( 1ULL << 32 ),
UI_IGNORE_GLOBAL_CSS = ( 1ULL << 33 ), UI_IGNORE_GLOBAL_CSS = ( 1ULL << 33 ),
UI_AUTO_SIZING = ( 1ULL << 34 ),
}; };
enum UINodeType { enum UINodeType {
+1
View File
@@ -24,6 +24,7 @@ UIComboBox::UIComboBox() : UIWidget( "combobox" ), mDropDownList( NULL ), mButto
mButton->setVisible( true ); mButton->setVisible( true );
mButton->setEnabled( true ); mButton->setEnabled( true );
mButton->on( Event::OnSizeChange, [this]( const Event* ) { onSizeChange(); } ); mButton->on( Event::OnSizeChange, [this]( const Event* ) { onSizeChange(); } );
mDropDownList->addRelatedWidget( mButton );
applyDefaultTheme(); applyDefaultTheme();
} }
+17 -4
View File
@@ -75,14 +75,21 @@ void UIDropDown::setFriendNode( UINode* friendNode ) {
} }
void UIDropDown::onAutoSize() { void UIDropDown::onAutoSize() {
if ( mFlags & UI_AUTO_SIZING )
return;
mFlags |= UI_AUTO_SIZING;
Float max = eemax<Float>( PixelDensity::dpToPxI( getSkinSize().getHeight() ), Float max = eemax<Float>( PixelDensity::dpToPxI( getSkinSize().getHeight() ),
mTextCache.getLineSpacing() ); mTextCache.getLineSpacing() );
if ( mHeightPolicy == SizePolicy::WrapContent && mLayoutWeight == 0 ) { if ( mHeightPolicy == SizePolicy::WrapContent ) {
setInternalPixelsHeight( eeceil( max + mPaddingPx.Top + mPaddingPx.Bottom ) ); setInternalPixelsHeight( eeceil( max + mPaddingPx.Top + mPaddingPx.Bottom ) );
} else if ( ( mFlags & UI_AUTO_SIZE ) && 0 == getSize().getHeight() && max > 0 ) { } else if ( ( mFlags & UI_AUTO_SIZE ) && 0 == getSize().getHeight() && max > 0 ) {
setInternalPixelsHeight( eeceil( max ) ); setInternalPixelsHeight( eeceil( max ) );
} }
mFlags &= ~UI_AUTO_SIZING;
} }
UIWidget* UIDropDown::getPopUpWidget() const { UIWidget* UIDropDown::getPopUpWidget() const {
@@ -207,15 +214,21 @@ void UIDropDown::onItemKeyDown( const Event* Event ) {
} }
} }
void UIDropDown::onPopUpFocusLoss( const Event* ) { void UIDropDown::onPopUpFocusLoss() {
if ( NULL == getEventDispatcher() ) if ( NULL == getEventDispatcher() )
return; return;
bool frienIsFocus = NULL != mFriendNode && mFriendNode == getEventDispatcher()->getFocusNode(); bool friendIsFocus = NULL != mFriendNode && mFriendNode == getEventDispatcher()->getFocusNode();
bool isChildFocus = isChild( getEventDispatcher()->getFocusNode() ); bool isChildFocus = isChild( getEventDispatcher()->getFocusNode() );
bool isRelatedWidget =
std::find( mRelatedWidgets.begin(), mRelatedWidgets.end(),
getEventDispatcher()->getFocusNode() ) != mRelatedWidgets.end();
if ( getEventDispatcher()->getFocusNode() != this && !isChildFocus && !frienIsFocus ) { if ( getEventDispatcher()->getFocusNode() != this && !isChildFocus && !friendIsFocus &&
!isRelatedWidget ) {
hide(); hide();
mLastFocusLoss = Sys::getTicks();
} }
} }
+10 -4
View File
@@ -31,7 +31,7 @@ UIDropDownList::UIDropDownList( const std::string& tag ) : UIDropDown( tag ), mL
// This will force to change the parent when shown, and force the CSS style reload. // This will force to change the parent when shown, and force the CSS style reload.
mListBox->setParent( this ); mListBox->setParent( this );
mListBox->on( Event::OnWidgetFocusLoss, [this]( auto event ) { onPopUpFocusLoss( event ); } ); mListBox->on( Event::OnWidgetFocusLoss, [this]( auto event ) { onPopUpFocusLoss(); } );
mListBox->on( Event::OnItemSelected, [this]( auto event ) { onItemSelected( event ); } ); mListBox->on( Event::OnItemSelected, [this]( auto event ) { onItemSelected( event ); } );
mListBox->on( Event::OnItemClicked, [this]( auto event ) { onItemClicked( event ); } ); mListBox->on( Event::OnItemClicked, [this]( auto event ) { onItemClicked( event ); } );
mListBox->on( Event::OnItemKeyDown, [this]( auto event ) { onItemKeyDown( event ); } ); mListBox->on( Event::OnItemKeyDown, [this]( auto event ) { onItemKeyDown( event ); } );
@@ -99,16 +99,22 @@ Uint32 UIDropDownList::onKeyDown( const KeyEvent& Event ) {
} }
void UIDropDownList::onAutoSize() { void UIDropDownList::onAutoSize() {
if ( mFlags & UI_AUTO_SIZING )
return;
UIDropDown::onAutoSize(); UIDropDown::onAutoSize();
Float max = eemax<Float>( PixelDensity::dpToPxI( getSkinSize().getWidth() ), mFlags |= UI_AUTO_SIZING;
getTextWidth() );
if ( mWidthPolicy == SizePolicy::WrapContent && mLayoutWeight == 0 ) { Float max = eemax<Float>( PixelDensity::dpToPxI( getSkinSize().getWidth() ), getTextWidth() );
if ( mWidthPolicy == SizePolicy::WrapContent ) {
setInternalPixelsWidth( eeceil( max + mPaddingPx.Left + mPaddingPx.Right ) ); setInternalPixelsWidth( eeceil( max + mPaddingPx.Left + mPaddingPx.Right ) );
} else if ( ( mFlags & UI_AUTO_SIZE ) && 0 == getSize().getWidth() && max > 0 ) { } else if ( ( mFlags & UI_AUTO_SIZE ) && 0 == getSize().getWidth() && max > 0 ) {
setInternalPixelsWidth( eeceil( max ) ); setInternalPixelsWidth( eeceil( max ) );
} }
mFlags &= ~UI_AUTO_SIZING;
} }
UIDropDownList* UIDropDownList::showList() { UIDropDownList* UIDropDownList::showList() {
+2 -2
View File
@@ -29,7 +29,7 @@ UIDropDownModelList::UIDropDownModelList( const std::string& tag ) :
mListView->setParent( this ); mListView->setParent( this );
mListView->setSingleClickNavigation( true ); mListView->setSingleClickNavigation( true );
mListView->on( Event::OnWidgetFocusLoss, [this]( auto event ) { onPopUpFocusLoss( event ); } ); mListView->on( Event::OnWidgetFocusLoss, [this]( auto event ) { onPopUpFocusLoss(); } );
mListView->on( Event::OnModelEvent, [this]( auto event ) { onItemSelected( event ); } ); mListView->on( Event::OnModelEvent, [this]( auto event ) { onItemSelected( event ); } );
mListView->on( Event::KeyDown, [this]( auto event ) { onItemKeyDown( event ); } ); mListView->on( Event::KeyDown, [this]( auto event ) { onItemKeyDown( event ); } );
mListView->on( Event::OnClear, [this]( auto event ) { onWidgetClear( event ); } ); mListView->on( Event::OnClear, [this]( auto event ) { onWidgetClear( event ); } );
@@ -87,7 +87,7 @@ void UIDropDownModelList::setListView( UIAbstractTableView* listView ) {
mListView->setVisible( false ); mListView->setVisible( false );
mListView->setParent( this ); mListView->setParent( this );
mListView->on( Event::OnWidgetFocusLoss, [this]( auto event ) { onPopUpFocusLoss( event ); } ); mListView->on( Event::OnWidgetFocusLoss, [this]( auto event ) { onPopUpFocusLoss(); } );
mListView->on( Event::OnModelEvent, [this]( auto event ) { onItemSelected( event ); } ); mListView->on( Event::OnModelEvent, [this]( auto event ) { onItemSelected( event ); } );
mListView->on( Event::KeyDown, [this]( auto event ) { onItemKeyDown( event ); } ); mListView->on( Event::KeyDown, [this]( auto event ) { onItemKeyDown( event ); } );
mListView->on( Event::OnClear, [this]( auto event ) { onWidgetClear( event ); } ); mListView->on( Event::OnClear, [this]( auto event ) { onWidgetClear( event ); } );
+3 -3
View File
@@ -110,7 +110,7 @@ UIFileDialog::UIFileDialog( Uint32 dialogFlags, const std::string& defaultFilePa
mPath = UITextInput::New(); mPath = UITextInput::New();
mPath->setText( mCurPath ) mPath->setText( mCurPath )
->setLayoutSizePolicy( SizePolicy::WrapContent, SizePolicy::WrapContent ) ->setLayoutSizePolicy( SizePolicy::Fixed, SizePolicy::WrapContent )
->setLayoutWeight( 1 ) ->setLayoutWeight( 1 )
->setParent( hLayout ); ->setParent( hLayout );
mPath->on( Event::OnPressEnter, [this]( auto event ) { onPressEnter( event ); } ); mPath->on( Event::OnPressEnter, [this]( auto event ) { onPressEnter( event ); } );
@@ -176,7 +176,7 @@ UIFileDialog::UIFileDialog( Uint32 dialogFlags, const std::string& defaultFilePa
mMultiView = UIMultiModelView::New(); mMultiView = UIMultiModelView::New();
mMultiView->setParent( linearLayout ); mMultiView->setParent( linearLayout );
mMultiView->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::WrapContent ) mMultiView->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::Fixed )
->setLayoutWeight( 1 ) ->setLayoutWeight( 1 )
->setLayoutMargin( Rectf( 0, 0, 0, 4 ) ); ->setLayoutMargin( Rectf( 0, 0, 0, 4 ) );
mMultiView->on( Event::KeyDown, [this]( const Event* event ) { mMultiView->on( Event::KeyDown, [this]( const Event* event ) {
@@ -245,7 +245,7 @@ UIFileDialog::UIFileDialog( Uint32 dialogFlags, const std::string& defaultFilePa
->setEnabled( false ); ->setEnabled( false );
mFile = UITextInput::New(); mFile = UITextInput::New();
mFile->setLayoutSizePolicy( SizePolicy::WrapContent, SizePolicy::MatchParent ) mFile->setLayoutSizePolicy( SizePolicy::Fixed, SizePolicy::MatchParent )
->setLayoutWeight( 1 ) ->setLayoutWeight( 1 )
->setParent( hLayout ); ->setParent( hLayout );
mFile->setLayoutMargin( Rectf( 0, 0, 4, 0 ) ); mFile->setLayoutMargin( Rectf( 0, 0, 4, 0 ) );