Improve context menu in tab widget.

This commit is contained in:
Martín Lucas Golini
2024-01-07 21:22:16 -03:00
parent 74e3dee369
commit 82b13329fd
3 changed files with 240 additions and 45 deletions

View File

@@ -53,7 +53,21 @@ class EE_API UICodeEditorSplitter {
virtual ~UICodeEditorSplitter();
virtual bool tryTabClose( UIWidget* widget, UITabWidget::FocusTabBehavior focusTabBehavior );
virtual bool tryTabClose( UIWidget* widget, UITabWidget::FocusTabBehavior focusTabBehavior,
std::function<void()> onMsgBoxCloseCb = {} );
virtual bool tryCloseAllTabs( UIWidget* widget,
UITabWidget::FocusTabBehavior focusTabBehavior );
virtual bool tryCloseOtherTabs( UIWidget* widget,
UITabWidget::FocusTabBehavior focusTabBehavior );
virtual bool tryCloseCleanTabs( UIWidget* widget,
UITabWidget::FocusTabBehavior focusTabBehavior );
virtual bool tryCloseTabsToDirection( UIWidget* widget,
UITabWidget::FocusTabBehavior focusTabBehavior,
bool toTheRight );
void closeTab( UIWidget* widget, UITabWidget::FocusTabBehavior focusTabBehavior );
@@ -223,6 +237,21 @@ class EE_API UICodeEditorSplitter {
t.setCommand( "close-tab", [this] {
tryTabClose( mCurWidget, UITabWidget::FocusTabBehavior::Default );
} );
t.setCommand( "close-other-tabs", [this] {
tryCloseOtherTabs( mCurWidget, UITabWidget::FocusTabBehavior::Default );
} );
t.setCommand( "close-all-tabs", [this] {
tryCloseAllTabs( mCurWidget, UITabWidget::FocusTabBehavior::Default );
} );
t.setCommand( "close-clean-tabs", [this] {
tryCloseCleanTabs( mCurWidget, UITabWidget::FocusTabBehavior::Default );
} );
t.setCommand( "close-tabs-to-the-left", [this] {
tryCloseTabsToDirection( mCurWidget, UITabWidget::FocusTabBehavior::Default, false );
} );
t.setCommand( "close-tabs-to-the-right", [this] {
tryCloseTabsToDirection( mCurWidget, UITabWidget::FocusTabBehavior::Default, true );
} );
t.setCommand( "create-new", [this] {
auto d = createCodeEditorInTabWidget( tabWidgetFromWidget( mCurWidget ) );
if ( d.first != nullptr && d.second != nullptr ) {
@@ -308,6 +337,10 @@ class EE_API UICodeEditorSplitter {
void setThreadPool( const std::shared_ptr<ThreadPool>& threadPool );
bool checkEditorExists( UICodeEditor* ) const;
bool checkWidgetExists( UIWidget* ) const;
protected:
UISceneNode* mUISceneNode{ nullptr };
std::shared_ptr<ThreadPool> mThreadPool;
@@ -336,9 +369,9 @@ class EE_API UICodeEditorSplitter {
const std::vector<SyntaxColorScheme>& colorSchemes,
const std::string& initColorScheme );
bool checkEditorExists( UICodeEditor* ) const;
virtual void onTabClosed( const TabEvent* tabEvent );
void closeAllTabs( std::vector<UITab*> tabs, UITabWidget::FocusTabBehavior focusTabBehavior );
};
}}} // namespace EE::UI::Tools

View File

@@ -63,7 +63,12 @@ std::vector<std::string> UICodeEditorSplitter::getUnlockedCommands() {
"switch-to-previous-split",
"switch-to-next-split",
"switch-to-previous-colorscheme",
"switch-to-next-colorscheme" };
"switch-to-next-colorscheme",
"close-other-tabs",
"close-all-tabs",
"close-clean-tabs",
"close-tabs-to-the-left",
"close-tabs-to-the-right" };
return unlockedCmds;
}
@@ -920,7 +925,8 @@ void UICodeEditorSplitter::zoomReset() {
}
bool UICodeEditorSplitter::tryTabClose( UIWidget* widget,
UITabWidget::FocusTabBehavior focusTabBehavior ) {
UITabWidget::FocusTabBehavior focusTabBehavior,
std::function<void()> onMsgBoxCloseCb ) {
if ( !widget )
return false;
@@ -932,17 +938,24 @@ bool UICodeEditorSplitter::tryTabClose( UIWidget* widget,
return false;
mTryCloseMsgBox = UIMessageBox::New(
UIMessageBox::OK_CANCEL,
widget->getUISceneNode()->getTranslatorString(
"@string/confirm_close_tab",
"Do you really want to close this tab?\nAll changes will be lost." ) );
mTryCloseMsgBox->addEventListener( Event::OnConfirm, [&, editor]( const Event* ) {
closeTab( editor, focusTabBehavior );
} );
mTryCloseMsgBox->addEventListener( Event::OnClose, [this]( const Event* ) {
mTryCloseMsgBox = nullptr;
if ( mCurEditor )
mCurEditor->setFocus();
} );
String::format( widget->getUISceneNode()
->i18n( "@string/confirm_close_tab",
"Do you really want to close this tab?\nAll changes in "
"\"%s\" will be lost." )
.toUtf8(),
editor->getDocument().getFilename() ) );
mTryCloseMsgBox->addEventListener( Event::OnConfirm,
[this, editor, focusTabBehavior]( const Event* ) {
closeTab( editor, focusTabBehavior );
} );
mTryCloseMsgBox->addEventListener( Event::OnClose,
[this, onMsgBoxCloseCb]( const Event* ) {
mTryCloseMsgBox = nullptr;
if ( mCurEditor )
mCurEditor->setFocus();
if ( onMsgBoxCloseCb )
onMsgBoxCloseCb();
} );
mTryCloseMsgBox->setTitle( widget->getUISceneNode()->getTranslatorString(
"@string/ask_close_tab", "Close Tab?" ) );
mTryCloseMsgBox->center();
@@ -958,6 +971,108 @@ bool UICodeEditorSplitter::tryTabClose( UIWidget* widget,
}
}
void UICodeEditorSplitter::closeAllTabs( std::vector<UITab*> tabs,
UITabWidget::FocusTabBehavior focusTabBehavior ) {
while ( !tabs.empty() ) {
UITab* tab = tabs.back();
if ( tab && !tryTabClose( tab->getOwnedWidget()->asType<UIWidget>(), focusTabBehavior,
[this, tabs, focusTabBehavior]() mutable {
tabs.pop_back();
closeAllTabs( tabs, focusTabBehavior );
} ) ) {
return;
} else {
tabs.pop_back();
}
}
}
bool UICodeEditorSplitter::tryCloseAllTabs( UIWidget* widget,
UITabWidget::FocusTabBehavior focusTabBehavior ) {
UITabWidget* tabW = tabWidgetFromWidget( widget );
if ( !tabW )
return false;
size_t tabCount = tabW->getTabCount();
std::vector<UITab*> tabs;
for ( size_t i = 0; i < tabCount; i++ )
tabs.push_back( tabW->getTab( i ) );
closeAllTabs( tabs, focusTabBehavior );
return true;
}
bool UICodeEditorSplitter::tryCloseOtherTabs( UIWidget* widget,
UITabWidget::FocusTabBehavior focusTabBehavior ) {
UITabWidget* tabW = tabWidgetFromWidget( widget );
if ( !tabW )
return false;
size_t tabCount = tabW->getTabCount();
std::vector<UITab*> tabs;
for ( size_t i = 0; i < tabCount; i++ ) {
if ( tabW->getTab( i )->getOwnedWidget() != widget )
tabs.push_back( tabW->getTab( i ) );
}
closeAllTabs( tabs, focusTabBehavior );
return true;
}
bool UICodeEditorSplitter::tryCloseCleanTabs( UIWidget* widget,
UITabWidget::FocusTabBehavior focusTabBehavior ) {
UITabWidget* tabW = tabWidgetFromWidget( widget );
if ( !tabW )
return false;
size_t tabCount = tabW->getTabCount();
std::vector<UITab*> tabs;
for ( size_t i = 0; i < tabCount; i++ ) {
UITab* tab = tabW->getTab( i );
UIWidget* widget =
tab->getOwnedWidget()->isWidget() ? tab->getOwnedWidget()->asType<UIWidget>() : nullptr;
if ( widget && widget->isType( UI_TYPE_CODEEDITOR ) &&
!widget->asType<UICodeEditor>()->isDirty() )
tabs.push_back( tabW->getTab( i ) );
}
closeAllTabs( tabs, focusTabBehavior );
return true;
}
bool UICodeEditorSplitter::tryCloseTabsToDirection( UIWidget* widget,
UITabWidget::FocusTabBehavior focusTabBehavior,
bool toTheRight ) {
UITabWidget* tabW = tabWidgetFromWidget( widget );
if ( !tabW )
return false;
UITab* tab = tabW->getTabFromOwnedWidget( widget );
if ( !tab )
return false;
size_t tabIndex = tabW->getTabIndex( tab );
if ( tabIndex == eeINDEX_NOT_FOUND )
return false;
size_t tabCount = tabW->getTabCount();
std::vector<UITab*> tabs;
if ( toTheRight ) {
for ( size_t i = tabIndex + 1; i < tabCount; i++ )
tabs.push_back( tabW->getTab( i ) );
} else {
for ( size_t i = 0; i < tabIndex; i++ )
tabs.push_back( tabW->getTab( i ) );
}
closeAllTabs( tabs, focusTabBehavior );
return true;
}
void UICodeEditorSplitter::closeTab( UIWidget* widget,
UITabWidget::FocusTabBehavior focusTabBehavior ) {
if ( widget ) {
@@ -1158,6 +1273,18 @@ void UICodeEditorSplitter::closeTabWidgets( UISplitter* splitter ) {
}
}
bool UICodeEditorSplitter::checkWidgetExists( UIWidget* checkWidget ) const {
bool found = false;
forEachWidgetStoppable( [&]( UIWidget* widget ) {
if ( widget == checkWidget ) {
found = true;
return true;
}
return false;
} );
return found || checkWidget == nullptr;
}
bool UICodeEditorSplitter::checkEditorExists( UICodeEditor* checkEditor ) const {
bool found = false;
forEachEditorStoppable( [&found, checkEditor]( UICodeEditor* editor ) {

View File

@@ -1183,6 +1183,8 @@ Drawable* App::findIcon( const std::string& name ) {
}
Drawable* App::findIcon( const std::string& name, const size_t iconSize ) {
if ( name.empty() )
return nullptr;
UIIcon* icon = mUISceneNode->findIcon( name );
if ( icon )
return icon->getSize( iconSize );
@@ -1659,39 +1661,72 @@ void App::onTabCreated( UITab* tab, UIWidget* ) {
UITab* tab = event->getNode()->asType<UITab>();
if ( !tab->getTabWidget() )
return;
menu->add( i18n( "editor_tab_menu_close_tab", "Close Tab" ) )->setId( "close-tab" );
menu->add( i18n( "editor_tab_menu_close_other_tabs", "Close Other Tabs" ) )
->setId( "close-other-tabs" );
menu->add( i18n( "editor_tab_menu_close_all_tabs", "Close All Tabs" ) )
->setId( "close-all-tabs" );
const auto menuAdd = [menu, this]( const std::string& translateKey,
const String& translateString, const std::string& icon,
const std::string& cmd ) {
UIMenuItem* menuItem = menu->add( i18n( translateKey, translateString ),
findIcon( icon ), getKeybind( cmd ) );
menuItem->setId( cmd );
return menuItem;
};
menuAdd( "editor_tab_menu_close_tab", "Close Tab", "document-close", "close-tab" );
menuAdd( "editor_tab_menu_close_other_tabs", "Close Other Tabs", "", "close-other-tabs" );
menuAdd( "editor_tab_menu_close_clean_tabs", "Close Clean Tabs", "", "close-clean-tabs" );
menuAdd( "editor_tab_menu_close_all_tabs", "Close All Tabs", "", "close-all-tabs" );
menuAdd( "editor_tab_menu_close_tabs_to_the_left", "Close Tabs To The Left", "",
"close-tabs-to-the-left" );
menuAdd( "editor_tab_menu_close_tabs_to_the_right", "Close Tabs To The Right", "",
"close-tabs-to-the-right" );
if ( tab->getOwnedWidget()->isType( UI_TYPE_CODEEDITOR ) ) {
menu->addSeparator();
menuAdd( "split_left", "Split Left", "split-horizontal", "split-left" );
menuAdd( "split_right", "Split Right", "split-horizontal", "split-right" );
menuAdd( "split_top", "Split Top", "split-vertical", "split-top" );
menuAdd( "split_bottom", "Split Bottom", "split-vertical", "split-bottom" );
menu->addSeparator();
menuAdd( "open_containing_folder", "Open Containing Folder...", "folder-open",
"open-containing-folder" );
menuAdd( "copy_containing_folder_path", "Copy Containing Folder Path...", "copy",
"copy-containing-folder-path" );
menuAdd( "copy_file_path", "Copy File Path", "copy", "copy-file-path" );
menuAdd( "copy_file_path_and_position", "Copy File Path and Position", "copy",
"copy-file-path-and-position" );
}
menu->addEventListener( Event::OnItemClicked, [tab, this]( const Event* event ) {
if ( !event->getNode()->isType( UI_TYPE_MENUITEM ) )
return;
UIMenuItem* item = event->getNode()->asType<UIMenuItem>();
UITabWidget* tabW = tab->getTabWidget();
if ( "close-tab" == item->getId() ) {
mSplitter->closeTab( tab->getOwnedWidget()->asType<UIWidget>(),
UITabWidget::FocusTabBehavior::Closest );
} else if ( "close-other-tabs" == item->getId() ) {
size_t tabCount = tabW->getTabCount();
std::vector<UITab*> tabs;
for ( size_t i = 0; i < tabCount; i++ ) {
if ( tabW->getTab( i ) != tab )
tabs.push_back( tabW->getTab( i ) );
}
for ( auto* tab : tabs ) {
mSplitter->closeTab( tab->getOwnedWidget()->asType<UIWidget>(),
UITabWidget::FocusTabBehavior::Closest );
}
} else if ( "close-all-tabs" == item->getId() ) {
size_t tabCount = tabW->getTabCount();
std::vector<UITab*> tabs;
for ( size_t i = 0; i < tabCount; i++ )
tabs.push_back( tabW->getTab( i ) );
for ( auto* tab : tabs ) {
mSplitter->closeTab( tab->getOwnedWidget()->asType<UIWidget>(),
UITabWidget::FocusTabBehavior::Closest );
}
UICodeEditor* nce = nullptr;
UICodeEditor* ce = nullptr;
UIWidget* ncw = nullptr;
UIWidget* cw = nullptr;
if ( tab->getOwnedWidget()->isType( UI_TYPE_CODEEDITOR ) ) {
nce = tab->getOwnedWidget()->asType<UICodeEditor>();
ce = mSplitter->getCurEditor();
if ( nce != ce )
mSplitter->setCurrentEditor( nce );
} else {
ncw = tab->getOwnedWidget()->asType<UIWidget>();
cw = mSplitter->getCurWidget();
if ( ncw != cw )
mSplitter->setCurrentWidget( ncw );
}
runCommand( item->getId() );
if ( tab->getOwnedWidget()->isType( UI_TYPE_CODEEDITOR ) ) {
if ( nce != ce && mSplitter->checkEditorExists( ce ) )
mSplitter->setCurrentEditor( ce );
} else {
if ( ncw != cw && mSplitter->checkWidgetExists( cw ) )
mSplitter->setCurrentWidget( cw );
}
} );
} );