From d4ec180134a1fa47b394b10ac5370b1d017a14fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Lucas=20Golini?= Date: Fri, 3 Apr 2026 18:21:44 -0300 Subject: [PATCH] ecode: allow configuring the default working directory of a new terminal (SpartanJ/ecode#857). Fix border of app_hint. eepp: UIHTMLTable column width calculation improvements. --- .../assets/html/hn_thread_test.html | 10 --- src/eepp/ui/uihtmltable.cpp | 89 ++++++++++++++----- src/tools/ecode/applayout.xml.hpp | 1 + src/tools/ecode/ecode.cpp | 13 +++ src/tools/ecode/ecode.hpp | 2 + .../ecode/plugins/plugincontextprovider.hpp | 2 + src/tools/ecode/terminalmanager.cpp | 20 ++--- 7 files changed, 92 insertions(+), 45 deletions(-) diff --git a/bin/unit_tests/assets/html/hn_thread_test.html b/bin/unit_tests/assets/html/hn_thread_test.html index d2544b057..8369a0e4a 100644 --- a/bin/unit_tests/assets/html/hn_thread_test.html +++ b/bin/unit_tests/assets/html/hn_thread_test.html @@ -1,15 +1,7 @@ - - - - - - - $500 GPU outperforms Claude Sonnet on coding benchmarks | Hacker News - @@ -181,6 +173,4 @@ - - diff --git a/src/eepp/ui/uihtmltable.cpp b/src/eepp/ui/uihtmltable.cpp index 28160c52b..80daf9e0b 100644 --- a/src/eepp/ui/uihtmltable.cpp +++ b/src/eepp/ui/uihtmltable.cpp @@ -133,9 +133,9 @@ void UIHTMLTable::computeIntrinsicWidths() const { cell->mWidthPolicy = SizePolicy::WrapContent; Float cellMin = cell->getMinIntrinsicWidth(); Float cellMax = cell->getMaxIntrinsicWidth(); - Float cellSpecified = std::max( cell->getPropertyWidth(), - getRecursiveSpecifiedWidth( - getRecursiveSpecifiedWidth, cell ) ); + Float cellSpecified = + std::max( cell->getPropertyWidth(), + getRecursiveSpecifiedWidth( getRecursiveSpecifiedWidth, cell ) ); cell->mWidthPolicy = widthPolicy; Uint32 colspan = cell->getColspan(); @@ -164,9 +164,9 @@ void UIHTMLTable::computeIntrinsicWidths() const { cell->mWidthPolicy = SizePolicy::WrapContent; Float cellMin = cell->getMinIntrinsicWidth(); Float cellMax = cell->getMaxIntrinsicWidth(); - Float cellSpecified = std::max( cell->getPropertyWidth(), - getRecursiveSpecifiedWidth( - getRecursiveSpecifiedWidth, cell ) ); + Float cellSpecified = + std::max( cell->getPropertyWidth(), + getRecursiveSpecifiedWidth( getRecursiveSpecifiedWidth, cell ) ); cell->mWidthPolicy = widthPolicy; Uint32 colspan = cell->getColspan(); @@ -220,8 +220,10 @@ void UIHTMLTable::computeIntrinsicWidths() const { totalMax += mColMaxWidths[i]; } - mMinIntrinsicWidth = totalMin + mPaddingPx.Left + mPaddingPx.Right + ( maxCols + 1 ) * mCellspacing; - mMaxIntrinsicWidth = totalMax + mPaddingPx.Left + mPaddingPx.Right + ( maxCols + 1 ) * mCellspacing; + mMinIntrinsicWidth = + totalMin + mPaddingPx.Left + mPaddingPx.Right + ( maxCols + 1 ) * mCellspacing; + mMaxIntrinsicWidth = + totalMax + mPaddingPx.Left + mPaddingPx.Right + ( maxCols + 1 ) * mCellspacing; mIntrinsicWidthsDirty = false; } @@ -266,24 +268,25 @@ void UIHTMLTable::updateLayout() { mPacking = false; return; } - Float totalMin = 0.f; - // Float totalMax = 0.f; + Float totalMax = 0.f; // Make sure this is uncommented for ( size_t i = 0; i < maxCols; ++i ) { totalMin += mColMinWidths[i]; - // totalMax += mColMaxWidths[i]; + totalMax += mColMaxWidths[i]; // Accumulate max widths } Float tableUsedWidth = availableWidth; // always try to fill the container // Assign column widths if ( tableUsedWidth <= totalMin + 0.001f ) { - // 1. Too narrow → scale down proportionally - Float scale = tableUsedWidth / totalMin; + // 1. Too narrow → scale down proportionally to min widths + Float scale = totalMin > 0.001f ? ( tableUsedWidth / totalMin ) : 0.f; for ( size_t i = 0; i < maxCols; ++i ) mColWidths[i] = mColMinWidths[i] * scale; - } else { - // 2. Extra space → distribute extra by flexibility + + } else if ( tableUsedWidth <= totalMax + 0.001f ) { + // 2. Partial flex → space is between min and max. Distribute extra by flexibility (text + // wrapping) Float extraSpace = tableUsedWidth - totalMin; Float totalFlex = 0.f; @@ -303,17 +306,55 @@ void UIHTMLTable::updateLayout() { mColWidths[i] = mColMinWidths[i] + added; } } else { - // No flexibility (all rigid) → stretch proportionally to min widths - if ( totalMin > 0.001f ) { - Float scale = tableUsedWidth / totalMin; - for ( size_t i = 0; i < maxCols; ++i ) - mColWidths[i] = mColMinWidths[i] * scale; - } else { - Float w = tableUsedWidth / static_cast( maxCols ); - for ( size_t i = 0; i < maxCols; ++i ) - mColWidths[i] = w; + // Fallback if no flex exists + Float scale = totalMin > 0.001f ? ( tableUsedWidth / totalMin ) : 0.f; + for ( size_t i = 0; i < maxCols; ++i ) + mColWidths[i] = mColMinWidths[i] * scale; + } + + } else { + // 3. Abundant space → table is wider than all max widths combined. + // Give everyone their max width, then distribute the leftover space. + Float leftOver = tableUsedWidth - totalMax; + + Float totalMaxUnspecified = 0.f; + size_t unspecifiedCount = 0; + + for ( size_t i = 0; i < maxCols; ++i ) { + if ( mColSpecifiedWidths[i] <= 0.f ) { + totalMaxUnspecified += mColMaxWidths[i]; + unspecifiedCount++; } } + + if ( unspecifiedCount > 0 ) { + // Distribute leftover space proportionally to max-widths for a balanced look + if ( totalMaxUnspecified > 0.001f ) { + for ( size_t i = 0; i < maxCols; ++i ) { + if ( mColSpecifiedWidths[i] <= 0.f ) { + Float scale = mColMaxWidths[i] / totalMaxUnspecified; + mColWidths[i] = mColMaxWidths[i] + ( leftOver * scale ); + } else { + mColWidths[i] = mColMaxWidths[i]; // Rigid explicit column stays rigid + } + } + } else { + // Fallback to strict even split if max widths are 0 + Float share = leftOver / static_cast( unspecifiedCount ); + for ( size_t i = 0; i < maxCols; ++i ) { + if ( mColSpecifiedWidths[i] <= 0.f ) { + mColWidths[i] = mColMaxWidths[i] + share; + } else { + mColWidths[i] = mColMaxWidths[i]; + } + } + } + } else { + // Absolute fallback: All columns explicitly specified, but space remains. Scale up. + Float scale = totalMax > 0.001f ? ( tableUsedWidth / totalMax ) : 0.f; + for ( size_t i = 0; i < maxCols; ++i ) + mColWidths[i] = mColMaxWidths[i] * scale; + } } // Safety fallback (should never trigger now) diff --git a/src/tools/ecode/applayout.xml.hpp b/src/tools/ecode/applayout.xml.hpp index 7b6964c74..b8d9b4718 100644 --- a/src/tools/ecode/applayout.xml.hpp +++ b/src/tools/ecode/applayout.xml.hpp @@ -531,6 +531,7 @@ Anchor.error:hover { border-top-color: var(--button-border); padding: 4dp 16dp 4dp 16dp; border-top-left-radius: 12dp; + border-width: 1dp; margin-bottom: 16dp; margin-right: 2dp; font-style: shadow; diff --git a/src/tools/ecode/ecode.cpp b/src/tools/ecode/ecode.cpp index 1a7113743..00e73d12d 100644 --- a/src/tools/ecode/ecode.cpp +++ b/src/tools/ecode/ecode.cpp @@ -1423,6 +1423,19 @@ std::string App::getCurrentWorkingDir() const { return ""; } +std::string App::getCurrentFileDir() const { + if ( mSplitter && mSplitter->curEditorIsNotNull() && mSplitter->curEditorExists() && + mSplitter->getCurEditor()->hasDocument() && + mSplitter->getCurEditor()->getDocument().hasFilepath() ) { + return mSplitter->getCurEditor()->getDocument().getFileInfo().getDirectoryPath(); + } + + if ( !mCurrentProject.empty() && mCurrentProject != mPlaygroundPath ) + return mCurrentProject; + + return ""; +} + std::vector> App::makeAutoClosePairs( const std::string& strPairs ) { auto curPairs = String::split( strPairs, ',' ); diff --git a/src/tools/ecode/ecode.hpp b/src/tools/ecode/ecode.hpp index d841ee29f..471216e6c 100644 --- a/src/tools/ecode/ecode.hpp +++ b/src/tools/ecode/ecode.hpp @@ -162,6 +162,8 @@ class App : public UICodeEditorSplitter::Client, public PluginContextProvider { std::string getCurrentWorkingDir() const; + std::string getCurrentFileDir() const; + Drawable* findIcon( const std::string& name ); Drawable* findIcon( const std::string& name, const size_t iconSize ); diff --git a/src/tools/ecode/plugins/plugincontextprovider.hpp b/src/tools/ecode/plugins/plugincontextprovider.hpp index 9b54b5c95..3f63463eb 100644 --- a/src/tools/ecode/plugins/plugincontextprovider.hpp +++ b/src/tools/ecode/plugins/plugincontextprovider.hpp @@ -125,6 +125,8 @@ class PluginContextProvider { virtual std::string getCurrentWorkingDir() const = 0; + virtual std::string getCurrentFileDir() const = 0; + virtual void focusOrLoadFile( const std::string& path, const TextRange& range = {}, bool searchInSameContext = false ) = 0; diff --git a/src/tools/ecode/terminalmanager.cpp b/src/tools/ecode/terminalmanager.cpp index 54be52774..9baa26c21 100644 --- a/src/tools/ecode/terminalmanager.cpp +++ b/src/tools/ecode/terminalmanager.cpp @@ -265,10 +265,11 @@ void TerminalManager::configureTerminalScrollback() { void TerminalManager::configureTerminalWorkingDir() { static const auto layout( R"xml( - + - + @@ -278,10 +279,10 @@ void TerminalManager::configureTerminalWorkingDir() { - + )xml" ); UIWindow* window = mApp->getUISceneNode()->loadLayoutFromString( layout )->asType(); - UIComboBox* workingDirCombo = window->find( "working_dir_combo" ); + UIDropDownList* workingDirCombo = window->find( "working_dir_combo" ); UIWidget* otherDirContainer = window->find( "other_dir_container" ); UITextInput* otherDirInput = window->find( "other_dir_input" ); UIPushButton* otherDirBrowse = window->find( "other_dir_browse" ); @@ -292,8 +293,7 @@ void TerminalManager::configureTerminalWorkingDir() { mApp->i18n( "project_root_directory", "Project Root Directory" ), mApp->i18n( "current_file_directory", "Current File Directory" ), mApp->i18n( "user_home_directory", "User Home" ), - mApp->i18n( "other_directory", "Other" ) - }; + mApp->i18n( "other_directory", "Other" ) }; workingDirCombo->getListBox()->addListBoxItems( options ); workingDirCombo->getListBox()->setSelected( @@ -306,14 +306,13 @@ void TerminalManager::configureTerminalWorkingDir() { updateOtherVisible( mApp->getConfig().term.workingDir ); - workingDirCombo->on( Event::OnItemSelected, [updateOtherVisible, workingDirCombo]( auto ) { + workingDirCombo->on( Event::OnValueChange, [updateOtherVisible, workingDirCombo]( auto ) { updateOtherVisible( static_cast( workingDirCombo->getListBox()->getItemSelectedIndex() ) ); } ); otherDirBrowse->onClick( [this, otherDirInput]( auto ) { - UIFileDialog* dialog = mApp->openFileDialog(); - dialog->setWindowFlags( UI_WIN_DEFAULT_FLAGS | UI_WIN_MODAL ); + UIFileDialog* dialog = mApp->openFileDialog( false ); dialog->setTitle( mApp->i18n( "select_working_directory", "Select Working Directory" ) ); dialog->addFilePattern( "*", true ); dialog->setAllowFolderSelect( true ); @@ -330,7 +329,6 @@ void TerminalManager::configureTerminalWorkingDir() { window->closeWindow(); } ); - cancel->onClick( [window]( auto ) { window->closeWindow(); } ); window->on( Event::KeyDown, [window]( const Event* event ) { @@ -349,7 +347,7 @@ std::string TerminalManager::getSelectedWorkingDir() const { return !mApp->getCurrentProject().empty() ? mApp->getCurrentProject() : mApp->getCurrentWorkingDir(); case TerminalWorkingDir::CurrentFileDir: - return mApp->getCurrentWorkingDir(); + return mApp->getCurrentFileDir(); case TerminalWorkingDir::UserHome: return Sys::getUserDirectory(); case TerminalWorkingDir::Other: