diff --git a/include/eepp/ui/uitabwidget.hpp b/include/eepp/ui/uitabwidget.hpp index f00535ff3..854e079c5 100644 --- a/include/eepp/ui/uitabwidget.hpp +++ b/include/eepp/ui/uitabwidget.hpp @@ -4,6 +4,7 @@ #include #include #include +#include namespace EE { namespace UI { @@ -25,6 +26,8 @@ class EE_API TabEvent : public Event { class EE_API UITabWidget : public UIWidget { public: + enum class FocusTabBehavior { Closest, FocusOrder }; + class StyleConfig { public: Float TabSeparation = 0; @@ -166,6 +169,9 @@ class EE_API UITabWidget : public UIWidget { void setDroppableHoveringColor( const Color& droppableHoveringColor ); + FocusTabBehavior getFocusTabBehavior() const; + void setFocusTabBehavior( FocusTabBehavior focusTabBehavior ); + protected: friend class UITab; @@ -184,6 +190,8 @@ class EE_API UITabWidget : public UIWidget { bool mDroppableHoveringColorWasSet{ false }; Float mTabVerticalDragResistance; Color mDroppableHoveringColor{ Color::Transparent }; + FocusTabBehavior mFocusTabBehavior{ FocusTabBehavior::Closest }; + std::deque mFocusHistory; void onThemeLoaded(); @@ -223,6 +231,12 @@ class EE_API UITabWidget : public UIWidget { void updateScrollBar(); void updateScroll(); + + void updateTabSelected( FocusTabBehavior tabBehavior ); + + void insertFocusHistory( UITab* tab ); + + void eraseFocusHistory( UITab* tab ); }; }} // namespace EE::UI diff --git a/src/eepp/ui/tools/uicodeeditorsplitter.cpp b/src/eepp/ui/tools/uicodeeditorsplitter.cpp index 9f3e4ace9..2e2413203 100644 --- a/src/eepp/ui/tools/uicodeeditorsplitter.cpp +++ b/src/eepp/ui/tools/uicodeeditorsplitter.cpp @@ -574,6 +574,7 @@ UITabWidget* UICodeEditorSplitter::createEditorWithTabWidget( Node* parent, bool tabWidget->setAllowRearrangeTabs( true ); tabWidget->setAllowDragAndDropTabs( true ); tabWidget->setAllowSwitchTabsInEmptySpaces( true ); + tabWidget->setFocusTabBehavior( UITabWidget::FocusTabBehavior::FocusOrder ); tabWidget->addEventListener( Event::OnTabSelected, [&]( const Event* event ) { UITabWidget* tabWidget = event->getNode()->asType(); if ( tabWidget->getTabSelected()->getOwnedWidget()->isType( UI_TYPE_CODEEDITOR ) ) { diff --git a/src/eepp/ui/uitabwidget.cpp b/src/eepp/ui/uitabwidget.cpp index 6ec4abbb5..64afd5847 100644 --- a/src/eepp/ui/uitabwidget.cpp +++ b/src/eepp/ui/uitabwidget.cpp @@ -26,7 +26,7 @@ UITabWidget::UITabWidget() : mAllowSwitchTabsInEmptySpaces( false ), mDroppableHoveringColorWasSet( false ), mTabVerticalDragResistance( PixelDensity::dpToPx( 64 ) ) { - mFlags |= UI_SCROLLABLE; + mFlags |= UI_SCROLLABLE; setHorizontalAlign( UI_HALIGN_CENTER ); setClipType( ClipType::ContentBox ); @@ -541,12 +541,61 @@ void UITabWidget::removeTab( const Uint32& index, bool destroyOwnedNode, bool im removeTab( index, destroyOwnedNode, true, immediateClose ); } +void UITabWidget::updateTabSelected( FocusTabBehavior tabBehavior ) { + if ( tabBehavior == FocusTabBehavior::Closest ) { + if ( !mTabs.empty() ) { + if ( mTabSelectedIndex < mTabs.size() ) { + setTabSelected( mTabs[mTabSelectedIndex] ); + } else { + if ( mTabSelectedIndex > 0 && mTabSelectedIndex - 1 < mTabs.size() ) { + setTabSelected( mTabs[mTabSelectedIndex - 1] ); + } else { + setTabSelected( mTabs[0] ); + } + } + } else { + mTabSelected = NULL; + mTabSelectedIndex = eeINDEX_NOT_FOUND; + } + } else { + if ( !mFocusHistory.empty() ) { + do { + auto tab = mFocusHistory.back(); + mFocusHistory.pop_back(); + if ( eeINDEX_NOT_FOUND != getTabIndex( tab ) ) { + setTabSelected( tab ); + return; + } + } while ( !mFocusHistory.empty() ); + return ( updateTabSelected( FocusTabBehavior::Closest ) ); + } + mTabSelected = NULL; + mTabSelectedIndex = eeINDEX_NOT_FOUND; + } +} + +void UITabWidget::insertFocusHistory( UITab* tab ) { + eraseFocusHistory( tab ); + mFocusHistory.push_back( tab ); +} + +void UITabWidget::eraseFocusHistory( UITab* tab ) { + auto it = std::find( mFocusHistory.begin(), mFocusHistory.end(), tab ); + while ( it != mFocusHistory.end() ) { + if ( it != mFocusHistory.end() ) + mFocusHistory.erase( it ); + it = std::find( mFocusHistory.begin(), mFocusHistory.end(), tab ); + }; +} + void UITabWidget::removeTab( const Uint32& index, bool destroyOwnedNode, bool destroyTab, bool immediateClose ) { eeASSERT( index < mTabs.size() ); UITab* tab = mTabs[index]; + eraseFocusHistory( tab ); + if ( destroyTab && !immediateClose ) { tab->close(); tab->setVisible( false ); @@ -562,20 +611,7 @@ void UITabWidget::removeTab( const Uint32& index, bool destroyOwnedNode, bool de mTabs.erase( mTabs.begin() + index ); if ( index == mTabSelectedIndex ) { - if ( !mTabs.empty() ) { - if ( mTabSelectedIndex < mTabs.size() ) { - setTabSelected( mTabs[mTabSelectedIndex] ); - } else { - if ( mTabSelectedIndex > 0 && mTabSelectedIndex - 1 < mTabs.size() ) { - setTabSelected( mTabs[mTabSelectedIndex - 1] ); - } else { - setTabSelected( mTabs[0] ); - } - } - } else { - mTabSelected = NULL; - mTabSelectedIndex = eeINDEX_NOT_FOUND; - } + updateTabSelected( mFocusTabBehavior ); } else { mTabSelectedIndex = getTabIndex( mTabSelected ); } @@ -641,6 +677,7 @@ void UITabWidget::removeAllTabs( bool destroyOwnedNode, bool immediateClose ) { mTabSelected = NULL; mTabSelectedIndex = eeINDEX_NOT_FOUND; + mFocusHistory.clear(); orderTabs(); @@ -693,6 +730,8 @@ UITab* UITabWidget::setTabSelected( UITab* tab ) { } tab->select(); + insertFocusHistory( tab ); + if ( tab->getOwnedWidget() ) tab->getOwnedWidget()->setFocus(); @@ -789,6 +828,14 @@ void UITabWidget::setDroppableHoveringColor( const Color& droppableHoveringColor mDroppableHoveringColorWasSet = true; } +UITabWidget::FocusTabBehavior UITabWidget::getFocusTabBehavior() const { + return mFocusTabBehavior; +} + +void UITabWidget::setFocusTabBehavior( UITabWidget::FocusTabBehavior focusTabBehavior ) { + mFocusTabBehavior = focusTabBehavior; +} + void UITabWidget::refreshOwnedWidget( UITab* tab ) { if ( NULL != tab && NULL != tab->getOwnedWidget() ) { tab->getOwnedWidget()->setParent( mNodeContainer ); diff --git a/src/tools/ecode/ecode.cpp b/src/tools/ecode/ecode.cpp index 24388f644..3b88f4bb2 100644 --- a/src/tools/ecode/ecode.cpp +++ b/src/tools/ecode/ecode.cpp @@ -799,6 +799,7 @@ void App::switchStatusBar() { mSettings->getWindowMenu()->getItemId( "toggle-status-bar" )->asType(); if ( chk->isActive() != mConfig.ui.showStatusBar ) chk->setActive( mConfig.ui.showStatusBar ); + updateDocInfoLocation(); showStatusBar( mConfig.ui.showStatusBar ); } @@ -831,7 +832,7 @@ EE::Window::Window* App::getWindow() const { return mWindow; } -UILinearLayout* App::getDocInfo() const { +UITextView* App::getDocInfo() const { return mDocInfo; } @@ -1507,11 +1508,25 @@ void App::onDocumentCursorPosChange( UICodeEditor*, TextDocument& doc ) { updateDocInfo( doc ); } +void App::updateDocInfoLocation() { + if ( !mDocInfo ) + return; + if ( mConfig.ui.showStatusBar ) { + if ( mStatusBar != mDocInfo->getParent() ) { + mDocInfo->setParent( mStatusBar ); + mDocInfo->setEnabled( true ); + } + } else if ( mStatusBar == mDocInfo->getParent() ) { + mDocInfo->setParent( mMainSplitter->find( "main_splitter_cont" ) ); + mDocInfo->setEnabled( false ); + } +} + void App::updateDocInfo( TextDocument& doc ) { - if ( mConfig.editor.showDocInfo && mDocInfoText && mSplitter->curEditorExistsAndFocused() ) { - if ( mDocInfo ) - mDocInfo->setVisible( true ); - mDocInfoText->setText( String::format( + if ( mConfig.editor.showDocInfo && mDocInfo && mSplitter->curEditorExistsAndFocused() ) { + mDocInfo->setVisible( true ); + updateDocInfoLocation(); + mDocInfo->setText( String::format( "%s: %lld / %lu %s: %lld %s", i18n( "line_abbr", "line" ).toUtf8().c_str(), doc.getSelection().start().line() + 1, doc.linesCount(), i18n( "col_abbr", "col" ).toUtf8().c_str(), @@ -1536,7 +1551,7 @@ void App::syncProjectTreeWithEditor( UICodeEditor* editor ) { } void App::onWidgetFocusChange( UIWidget* widget ) { - if ( mConfig.editor.showDocInfo && mDocInfoText ) + if ( mConfig.editor.showDocInfo && mDocInfo ) mDocInfo->setVisible( widget && widget->isType( UI_TYPE_CODEEDITOR ) ); mSettings->updateDocumentMenu(); @@ -3193,15 +3208,26 @@ TextInput.small_input, #settings:hover { color: var(--primary); } -#doc_info { +RelativeLayout > #doc_info { background-color: var(--back); margin-bottom: 22dp; margin-right: 22dp; border-radius: 8dp; padding: 6dp; opacity: 0.8; + layout-gravity: bottom|right; } -#doc_info > TextView { +StatusBar > #doc_info { + background-color: transparent; + margin-bottom: 0dp; + margin-right: 0dp; + border-radius: 0dp; + border: 0dp solid transparent; + padding: 0dp 4dp 0dp 4dp; + opacity: 1; + layout-gravity: center; +} +#doc_info { color: var(--font); } #search_find.error, @@ -3291,7 +3317,7 @@ TableView#locate_bar_table > tableview::row:selected > tableview::cell:nth-child padding-top: 1dp; padding-bottom: 1dp; } -#status_bar > * { +#status_bar > .status_but { padding: 0dp 5dp 0dp 4dp; background-color: var(--list-back); border-radius: 0dp; @@ -3301,10 +3327,10 @@ TableView#locate_bar_table > tableview::row:selected > tableview::cell:nth-child border-right-color: var(--tab-line); font-size: 10dp; } -#status_bar > *:hover { +#status_bar > .status_but:hover { background-color: var(--item-hover); } -#status_bar > *.selected { +#status_bar > .status_but.selected { background-color: var(--primary); } #panel > tabwidget::container > * { @@ -3529,11 +3555,9 @@ Anchor.error:hover { - + - - - + @@ -3608,7 +3632,7 @@ Anchor.error:hover { - + @@ -3844,7 +3868,6 @@ Anchor.error:hover { mUISceneNode->bind( "code_container", mBaseLayout ); mUISceneNode->bind( "image_container", mImageLayout ); mUISceneNode->bind( "doc_info", mDocInfo ); - mUISceneNode->bind( "doc_info_text", mDocInfoText ); mUISceneNode->bind( "panel", mSidePanel ); mUISceneNode->bind( "project_splitter", mProjectSplitter ); mUISceneNode->addEventListener( Event::KeyDown, [&]( const Event* event ) { diff --git a/src/tools/ecode/ecode.hpp b/src/tools/ecode/ecode.hpp index 7b3eab602..ce668b300 100644 --- a/src/tools/ecode/ecode.hpp +++ b/src/tools/ecode/ecode.hpp @@ -321,7 +321,7 @@ class App : public UICodeEditorSplitter::Client { EE::Window::Window* getWindow() const; - UILinearLayout* getDocInfo() const; + UITextView* getDocInfo() const; UITreeView* getProjectTreeView() const; @@ -403,7 +403,7 @@ class App : public UICodeEditorSplitter::Client { const std::map& getRealTerminalKeybindings() const; - protected: + protected: std::vector mArgs; EE::Window::Window* mWindow{ nullptr }; UISceneNode* mUISceneNode{ nullptr }; @@ -412,8 +412,7 @@ class App : public UICodeEditorSplitter::Client { UIMainLayout* mMainLayout{ nullptr }; UILayout* mBaseLayout{ nullptr }; UILayout* mImageLayout{ nullptr }; - UILinearLayout* mDocInfo{ nullptr }; - UITextView* mDocInfoText{ nullptr }; + UITextView* mDocInfo{ nullptr }; std::vector mRecentFiles; std::stack mRecentClosedFiles; std::vector mRecentFolders; @@ -566,6 +565,8 @@ class App : public UICodeEditorSplitter::Client { void cleanUpRecentFiles(); void updateOpenRecentFolderBtn(); + + void updateDocInfoLocation(); }; } // namespace ecode diff --git a/src/tools/ecode/statusbuildoutputcontroller.cpp b/src/tools/ecode/statusbuildoutputcontroller.cpp index 6d37aa4e5..254e6d7a8 100644 --- a/src/tools/ecode/statusbuildoutputcontroller.cpp +++ b/src/tools/ecode/statusbuildoutputcontroller.cpp @@ -116,7 +116,9 @@ bool StatusBuildOutputController::searchFindAndAddStatusResult( status.message = subtxt.substr( 0, nl ); } } else if ( pattern.config.patternOrder.file == i ) { - status.file = FileSystem::getRealPath( cmd->workingDir + subtxt ); + status.file = !subtxt.empty() && subtxt[0] == '.' + ? FileSystem::getRealPath( cmd->workingDir + subtxt ) + : FileSystem::getRealPath( subtxt ); status.fileName = FileSystem::fileNameFromPath( status.file ); } else if ( pattern.config.patternOrder.line == i ) { int l;