From ac91cedf9cf82379fc878e32b796e888d0915148 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Lucas=20Golini?= Date: Sun, 11 Jan 2026 13:32:48 -0300 Subject: [PATCH] Added support for maximizing the current tab widget (commands: `maximize-tab-widget` and `restore-maximized-tab-widget`), it can also be triggered right clicking a tab -> `Maximize Tab Widget` (SpartanJ/ecode#651). Added UINodeLink, this is a very simple node that lets you set a link to another node. Improved focus control in the status bar panels and windows. It's possible now in UICodeEditorSplitter to cancel a split request with a custom function checker. When downloading a file that it's not a supported format, it will try to open with the default external program set in the host OS. --- include/eepp/core/string.hpp | 2 +- include/eepp/ui.hpp | 1 + .../eepp/ui/tools/uicodeeditorsplitter.hpp | 6 + include/eepp/ui/uihelper.hpp | 1 + include/eepp/ui/uinodelink.hpp | 29 ++++ include/eepp/ui/uiproperty.hpp | 2 +- include/eepp/ui/uiwindow.hpp | 4 + src/eepp/core/string.cpp | 2 +- src/eepp/ui/doc/textdocument.cpp | 4 +- src/eepp/ui/tools/uicodeeditorsplitter.cpp | 13 +- src/eepp/ui/tools/uiwidgetinspector.cpp | 5 +- src/eepp/ui/uinodelink.cpp | 34 +++++ src/eepp/ui/uiwidgetcreator.cpp | 2 + src/eepp/ui/uiwindow.cpp | 13 +- .../eterm/include/eterm/system/ipipe.hpp | 2 +- .../eterm/include/eterm/system/pipe.hpp | 2 +- .../include/eterm/terminal/pseudoterminal.hpp | 5 +- .../src/eterm/terminal/pseudoterminal.cpp | 5 +- .../src/eepp/ui/doc/languages/qb64.cpp | 2 +- .../src/eepp/ui/doc/languages/smallbasic.cpp | 2 +- .../ui/doc/languagessyntaxhighlighting.cpp | 4 +- src/tools/ecode/appconfig.cpp | 3 + src/tools/ecode/applayout.xml.hpp | 8 ++ src/tools/ecode/ecode.cpp | 135 +++++++++++++++++- src/tools/ecode/ecode.hpp | 9 ++ src/tools/ecode/featureshealth.cpp | 1 + src/tools/ecode/ignorematcher.cpp | 8 +- src/tools/ecode/ignorematcher.hpp | 4 +- .../ecode/plugins/aiassistant/chatui.cpp | 1 + .../debugger/debuggerclientlistener.cpp | 1 + .../debugger/statusdebuggercontroller.cpp | 8 ++ src/tools/ecode/plugins/pluginmanager.cpp | 1 + src/tools/ecode/settingsactions.cpp | 2 +- src/tools/ecode/statusappoutputcontroller.cpp | 9 ++ .../ecode/statusbuildoutputcontroller.cpp | 36 +++-- src/tools/ecode/widgetcommandexecuter.hpp | 14 +- 36 files changed, 333 insertions(+), 47 deletions(-) create mode 100644 include/eepp/ui/uinodelink.hpp create mode 100644 src/eepp/ui/uinodelink.cpp diff --git a/include/eepp/core/string.hpp b/include/eepp/core/string.hpp index c7db0ef75..136374c53 100644 --- a/include/eepp/core/string.hpp +++ b/include/eepp/core/string.hpp @@ -678,7 +678,7 @@ class EE_API String { **/ String& operator=( const String& right ); - String& operator=( String&& right ); + String& operator=( String&& right ) noexcept; String& operator=( const StringBaseType& right ); diff --git a/include/eepp/ui.hpp b/include/eepp/ui.hpp index 18a7c1f98..a35f8d276 100644 --- a/include/eepp/ui.hpp +++ b/include/eepp/ui.hpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include diff --git a/include/eepp/ui/tools/uicodeeditorsplitter.hpp b/include/eepp/ui/tools/uicodeeditorsplitter.hpp index 3f25f451b..70351c6f7 100644 --- a/include/eepp/ui/tools/uicodeeditorsplitter.hpp +++ b/include/eepp/ui/tools/uicodeeditorsplitter.hpp @@ -389,6 +389,11 @@ class EE_API UICodeEditorSplitter { UITabWidget* getPreferredTabWidget() const; + UITabWidget* getCurTabWidget() const; + + void + setCanCreateSplitFn( std::function fn ); + protected: UISceneNode* mUISceneNode{ nullptr }; std::shared_ptr mThreadPool; @@ -417,6 +422,7 @@ class EE_API UICodeEditorSplitter { std::function mOnTabWidgetCreateCb; Float mVisualSplitEdgePercent{ 0.1 }; TabTryCloseCallback mTabTryCloseCb; + std::function mCanCreateSplitFn; UICodeEditorSplitter( UICodeEditorSplitter::Client* client, UISceneNode* sceneNode, std::shared_ptr threadPool, diff --git a/include/eepp/ui/uihelper.hpp b/include/eepp/ui/uihelper.hpp index 35c48abbd..0f21eea54 100644 --- a/include/eepp/ui/uihelper.hpp +++ b/include/eepp/ui/uihelper.hpp @@ -106,6 +106,7 @@ enum UINodeType { UI_TYPE_STACK_WIDGET, UI_TYPE_IMAGE_VIEWER, UI_TYPE_AUDIO_PLAYER, + UI_TYPE_NODELINK, UI_TYPE_MODULES = 10000, UI_TYPE_TERMINAL = 10001, UI_TYPE_USER = 200000, diff --git a/include/eepp/ui/uinodelink.hpp b/include/eepp/ui/uinodelink.hpp new file mode 100644 index 000000000..ce941c0f6 --- /dev/null +++ b/include/eepp/ui/uinodelink.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include + +namespace EE::UI { + +class EE_API UINodeLink : public UIWidget { + public: + static UINodeLink* New(); + + static UINodeLink* NewLink( UIWidget* link ); + + virtual Uint32 getType() const; + + virtual bool isType( const Uint32& type ) const; + + UINodeLink* setNodeLink( UIWidget* link ); + + UIWidget* getNodeLink() const; + + protected: + UINodeLink(); + + UINodeLink( UIWidget* link ); + + UIWidget* mNodeLink{ nullptr }; +}; + +} // namespace EE::UI diff --git a/include/eepp/ui/uiproperty.hpp b/include/eepp/ui/uiproperty.hpp index 60862635c..c7aa2c526 100644 --- a/include/eepp/ui/uiproperty.hpp +++ b/include/eepp/ui/uiproperty.hpp @@ -38,7 +38,7 @@ template class UIProperty { void operator=( const T& newVal ) { mBindedData.set( newVal ); } - void operator=( T&& newVal ) { mBindedData.set( std::move( newVal ) ); } + void operator=( T&& newVal ) noexcept { mBindedData.set( std::move( newVal ) ); } const T& value() const { return mBindedData.get(); } diff --git a/include/eepp/ui/uiwindow.hpp b/include/eepp/ui/uiwindow.hpp index bfa47e29a..2497aa459 100644 --- a/include/eepp/ui/uiwindow.hpp +++ b/include/eepp/ui/uiwindow.hpp @@ -204,6 +204,8 @@ class EE_API UIWindow : public UIWidget { bool stealsFocusOnShow() const; + void setCheckEphemeralCloseFn( std::function fn ); + protected: enum UI_RESIZE_TYPE { RESIZE_NONE, @@ -242,9 +244,11 @@ class EE_API UIWindow : public UIWidget { bool mShowWhenReady{ false }; bool mStealFocusOnShow{ true }; bool mClosing{ false }; + bool mLoadedFromXML{ false }; KeyBindings mKeyBindings; std::map mKeyBindingCommands; + std::function mCheckEphemeralCloseFn; virtual void onSizeChange(); diff --git a/src/eepp/core/string.cpp b/src/eepp/core/string.cpp index 4bd9d20e4..599735218 100644 --- a/src/eepp/core/string.cpp +++ b/src/eepp/core/string.cpp @@ -1906,7 +1906,7 @@ String& String::operator=( const String& right ) { return *this; } -String& String::operator=( String&& right ) { +String& String::operator=( String&& right ) noexcept { mString = std::move( right.mString ); return *this; } diff --git a/src/eepp/ui/doc/textdocument.cpp b/src/eepp/ui/doc/textdocument.cpp index bbbbf91c2..c18637ebc 100644 --- a/src/eepp/ui/doc/textdocument.cpp +++ b/src/eepp/ui/doc/textdocument.cpp @@ -4596,8 +4596,8 @@ void TextDocument::convertIndentationToSpaces() { } void TextDocument::initializeCommands() { - mCommands["reset"] = [this] { reset(); }; - mCommands["save"] = [this] { save(); }; + mCommands["reset-document"] = [this] { reset(); }; + mCommands["save-doc"] = [this] { save(); }; mCommands["delete-to-previous-word"] = [this] { deleteToPreviousWord(); }; mCommands["delete-to-previous-char"] = [this] { deleteToPreviousChar(); }; mCommands["delete-to-next-word"] = [this] { deleteToNextWord(); }; diff --git a/src/eepp/ui/tools/uicodeeditorsplitter.cpp b/src/eepp/ui/tools/uicodeeditorsplitter.cpp index 1659cac61..ae5657a46 100644 --- a/src/eepp/ui/tools/uicodeeditorsplitter.cpp +++ b/src/eepp/ui/tools/uicodeeditorsplitter.cpp @@ -338,6 +338,10 @@ UITabWidget* UICodeEditorSplitter::getPreferredTabWidget() const { return mOpenDocumentsInMainSplit ? getFirstTabWidget() : tabWidgetFromWidget( mCurWidget ); } +UITabWidget* UICodeEditorSplitter::getCurTabWidget() const { + return getCurWidget() ? tabWidgetFromWidget( getCurWidget() ) : nullptr; +} + std::pair UICodeEditorSplitter::createEditorInNewTab() { auto d = createCodeEditorInTabWidget( getPreferredTabWidget() ); if ( d.first == nullptr || d.second == nullptr ) { @@ -1243,7 +1247,7 @@ bool UICodeEditorSplitter::curEditorExistsAndFocused() const { UISplitter* UICodeEditorSplitter::split( const SplitDirection& direction, UIWidget* widget, bool openCurEditor ) { - if ( !widget ) + if ( !widget || ( mCanCreateSplitFn && !mCanCreateSplitFn( direction, widget ) ) ) return nullptr; UIOrientation orientation = direction == SplitDirection::Left || direction == SplitDirection::Right @@ -1289,9 +1293,14 @@ UISplitter* UICodeEditorSplitter::split( const SplitDirection& direction, UIWidg return splitter; } +void UICodeEditorSplitter::setCanCreateSplitFn( + std::function fn ) { + mCanCreateSplitFn = fn; +} + UITabWidget* UICodeEditorSplitter::splitTabWidget( SplitDirection direction, UITabWidget* tabWidget ) { - if ( !tabWidget ) + if ( !tabWidget || ( mCanCreateSplitFn && !mCanCreateSplitFn( direction, tabWidget ) ) ) return nullptr; UIOrientation orientation = direction == SplitDirection::Left || direction == SplitDirection::Right diff --git a/src/eepp/ui/tools/uiwidgetinspector.cpp b/src/eepp/ui/tools/uiwidgetinspector.cpp index 213aa9fec..003de0a80 100644 --- a/src/eepp/ui/tools/uiwidgetinspector.cpp +++ b/src/eepp/ui/tools/uiwidgetinspector.cpp @@ -21,8 +21,11 @@ UIWindow* UIWidgetInspector::create( UISceneNode* sceneNode, const Float& menuIc std::function drawBoxesToggle, std::function drawDebugDataToggle ) { static ModelIndex lastModelIndex = {}; - if ( sceneNode->getRoot()->hasChild( "widget-tree-view" ) ) + auto wtv = sceneNode->getRoot()->hasChild( "widget-tree-view" ); + if ( wtv ) { + wtv->toFront(); return nullptr; + } UIWindow* uiWin = UIWindow::New(); uiWin->setId( "widget-tree-view" ); uiWin->setMinWindowSize( 600, 400 ); diff --git a/src/eepp/ui/uinodelink.cpp b/src/eepp/ui/uinodelink.cpp new file mode 100644 index 000000000..3559b49f0 --- /dev/null +++ b/src/eepp/ui/uinodelink.cpp @@ -0,0 +1,34 @@ +#include + +namespace EE::UI { + +UINodeLink* UINodeLink::New() { + return eeNew( UINodeLink, () ); +} + +UINodeLink* UINodeLink::NewLink( UIWidget* link ) { + return eeNew( UINodeLink, ( link ) ); +} + +UINodeLink::UINodeLink() : UIWidget( "nodelink" ) {} + +UINodeLink::UINodeLink( UIWidget* link ) : UIWidget( "nodelink" ), mNodeLink( link ) {} + +Uint32 UINodeLink::getType() const { + return UI_TYPE_NODELINK; +} + +bool UINodeLink::isType( const Uint32& type ) const { + return UINodeLink::getType() == type ? true : UIWidget::isType( type ); +} + +UINodeLink* UINodeLink::setNodeLink( UIWidget* link ) { + mNodeLink = link; + return this; +} + +UIWidget* UINodeLink::getNodeLink() const { + return mNodeLink; +} + +} // namespace EE::UI diff --git a/src/eepp/ui/uiwidgetcreator.cpp b/src/eepp/ui/uiwidgetcreator.cpp index cf0f2d991..84b9ac81c 100644 --- a/src/eepp/ui/uiwidgetcreator.cpp +++ b/src/eepp/ui/uiwidgetcreator.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -102,6 +103,7 @@ void UIWidgetCreator::createBaseWidgetList() { registeredWidget["menuradiobutton"] = UIMenuRadioButton::New; registeredWidget["menuseparator"] = UIMenuSeparator::New; registeredWidget["anchor"] = UIAnchor::New; + registeredWidget["nodelink"] = UINodeLink::New; registeredWidget["textureviewer"] = Tools::UITextureViewer::New; registeredWidget["imageviewer"] = Tools::UIImageViewer::New; diff --git a/src/eepp/ui/uiwindow.cpp b/src/eepp/ui/uiwindow.cpp index 1ba1987cc..815dfc294 100644 --- a/src/eepp/ui/uiwindow.cpp +++ b/src/eepp/ui/uiwindow.cpp @@ -1680,7 +1680,10 @@ bool UIWindow::applyProperty( const StyleSheetProperty& attribute ) { } if ( winflags != mStyleConfig.WinFlags ) { - mStyleConfig.WinFlags = winflags; + if ( mLoadedFromXML ) + mStyleConfig.WinFlags = winflags; + else + mStyleConfig.WinFlags |= winflags; updateWinFlags(); } } @@ -1724,6 +1727,7 @@ bool UIWindow::applyProperty( const StyleSheetProperty& attribute ) { void UIWindow::loadFromXmlNode( const pugi::xml_node& node ) { UIWidget::loadFromXmlNode( node ); + mLoadedFromXML = true; setStealFocusOnShow( false ); showWhenReady(); } @@ -1794,7 +1798,8 @@ void UIWindow::sendWindowToFront() { void UIWindow::checkEphemeralClose() { Node* focusNode = getUISceneNode()->getUIEventDispatcher()->getFocusNode(); if ( !mShowWhenReady && ( mStyleConfig.WinFlags & UI_WIN_EPHEMERAL ) && focusNode != this && - !inParentTreeOf( focusNode ) ) + !inParentTreeOf( focusNode ) && + ( !mCheckEphemeralCloseFn || mCheckEphemeralCloseFn( focusNode ) ) ) closeWindow(); } @@ -1806,4 +1811,8 @@ bool UIWindow::stealsFocusOnShow() const { return mStealFocusOnShow; } +void UIWindow::setCheckEphemeralCloseFn( std::function fn ) { + mCheckEphemeralCloseFn = fn; +} + }} // namespace EE::UI diff --git a/src/modules/eterm/include/eterm/system/ipipe.hpp b/src/modules/eterm/include/eterm/system/ipipe.hpp index fd3a22f38..842b3ca61 100644 --- a/src/modules/eterm/include/eterm/system/ipipe.hpp +++ b/src/modules/eterm/include/eterm/system/ipipe.hpp @@ -47,6 +47,6 @@ class IPipe { virtual int read( char* buf, size_t n, bool block = false ) = 0; }; -}} // namespace EE::System +}} // namespace eterm::System #endif diff --git a/src/modules/eterm/include/eterm/system/pipe.hpp b/src/modules/eterm/include/eterm/system/pipe.hpp index 6be432d39..b742fac7e 100644 --- a/src/modules/eterm/include/eterm/system/pipe.hpp +++ b/src/modules/eterm/include/eterm/system/pipe.hpp @@ -61,6 +61,6 @@ class Pipe : public IPipe { #endif }; -}} // namespace EE::System +}} // namespace eterm::System #endif diff --git a/src/modules/eterm/include/eterm/terminal/pseudoterminal.hpp b/src/modules/eterm/include/eterm/terminal/pseudoterminal.hpp index 88785b77a..ad001c4c4 100644 --- a/src/modules/eterm/include/eterm/terminal/pseudoterminal.hpp +++ b/src/modules/eterm/include/eterm/terminal/pseudoterminal.hpp @@ -72,7 +72,8 @@ class PseudoTerminal final : public IPseudoTerminal { bool mAttached; - PseudoTerminal( int columns, int rows, AutoHandle&& hInput, AutoHandle&& hOutput, void* hPC ); + PseudoTerminal( int columns, int rows, AutoHandle&& hInput, AutoHandle&& hOutput, + void* hPC ) noexcept; #else int mColumns; int mRows; @@ -82,7 +83,7 @@ class PseudoTerminal final : public IPseudoTerminal { std::string mWriteBuffer; - PseudoTerminal( int columns, int rows, AutoHandle&& master, AutoHandle&& slave ); + PseudoTerminal( int columns, int rows, AutoHandle&& master, AutoHandle&& slave ) noexcept; #endif }; } // namespace Terminal diff --git a/src/modules/eterm/src/eterm/terminal/pseudoterminal.cpp b/src/modules/eterm/src/eterm/terminal/pseudoterminal.cpp index 3589be0a6..f5dec27d1 100644 --- a/src/modules/eterm/src/eterm/terminal/pseudoterminal.cpp +++ b/src/modules/eterm/src/eterm/terminal/pseudoterminal.cpp @@ -96,7 +96,8 @@ fail: PseudoTerminal::~PseudoTerminal() {} -PseudoTerminal::PseudoTerminal( int columns, int rows, AutoHandle&& master, AutoHandle&& slave ) : +PseudoTerminal::PseudoTerminal( int columns, int rows, AutoHandle&& master, + AutoHandle&& slave ) noexcept : mColumns( columns ), mRows( rows ), mMaster( std::move( master ) ), @@ -264,7 +265,7 @@ PseudoTerminal::~PseudoTerminal() { } PseudoTerminal::PseudoTerminal( int columns, int rows, AutoHandle&& hInput, AutoHandle&& hOutput, - void* hPC ) : + void* hPC ) noexcept : mInputHandle( std::move( hInput ) ), mOutputHandle( std::move( hOutput ) ), mPHPC( hPC ), diff --git a/src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/qb64.cpp b/src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/qb64.cpp index a58bb42aa..6953ece7c 100644 --- a/src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/qb64.cpp +++ b/src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/qb64.cpp @@ -8,7 +8,7 @@ SyntaxDefinition& addQB64() { auto& sd = SyntaxDefinitionManager::instance()->add( { "QB64", - { "%.bas$", "%.bi$", "%.bm$" }, + { "%.bas$", "%.bi$", "%.bm$", "%.inc$" }, { { { "'.*" }, "comment" }, { { "rem%s.*" }, "comment" }, diff --git a/src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/smallbasic.cpp b/src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/smallbasic.cpp index 69bc4da86..0c7e75145 100644 --- a/src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/smallbasic.cpp +++ b/src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/smallbasic.cpp @@ -9,7 +9,7 @@ SyntaxDefinition& addSmallBASIC() { ->add( { "SmallBASIC", - { "%.bas$" }, + { "%.bas$", "%.sb$" }, { { { "'.*" }, "comment" }, { { "REM%s.*" }, "comment" }, diff --git a/src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languagessyntaxhighlighting.cpp b/src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languagessyntaxhighlighting.cpp index afa5f7af2..5f03e21df 100644 --- a/src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languagessyntaxhighlighting.cpp +++ b/src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languagessyntaxhighlighting.cpp @@ -624,7 +624,7 @@ static void preDefinitionLangsChunk2( SyntaxDefinitionManager* sdm ) { sdm->addPreDefinition( { "QB64", []() -> SyntaxDefinition& { return addQB64(); }, - { "%.bas$", "%.bi$", "%.bm$" }, + { "%.bas$", "%.bi$", "%.bm$", "%.inc$" }, } ); sdm->addPreDefinition( { @@ -708,7 +708,7 @@ static void preDefinitionLangsChunk2( SyntaxDefinitionManager* sdm ) { sdm->addPreDefinition( { "SmallBASIC", []() -> SyntaxDefinition& { return addSmallBASIC(); }, - { "%.bas$" }, + { "%.bas$", "%.sb$" }, } ); sdm->addPreDefinition( { diff --git a/src/tools/ecode/appconfig.cpp b/src/tools/ecode/appconfig.cpp index 5ae086b65..71e919c95 100644 --- a/src/tools/ecode/appconfig.cpp +++ b/src/tools/ecode/appconfig.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -477,6 +478,8 @@ json AppConfig::saveNode( Node* node ) { splitter->getOrientation() == UIOrientation::Horizontal ? "horizontal" : "vertical"; res["first"] = saveNode( splitter->getFirstWidget() ); res["last"] = saveNode( splitter->getLastWidget() ); + } else if ( node->isType( UI_TYPE_NODELINK ) && node->asType()->getNodeLink() ) { + return saveNode( node->asType()->getNodeLink() ); } else if ( node->isType( UI_TYPE_TABWIDGET ) ) { UITabWidget* tabWidget = node->asType(); std::vector files; diff --git a/src/tools/ecode/applayout.xml.hpp b/src/tools/ecode/applayout.xml.hpp index cc92b5b70..4dc28df22 100644 --- a/src/tools/ecode/applayout.xml.hpp +++ b/src/tools/ecode/applayout.xml.hpp @@ -544,6 +544,14 @@ TabWidget::container > ImageViewer > TextView { .audio_player { layout-width: 300dp; } +.pseudo_anchor { + tint: var(--floating-icon); + cursor: arrow; +} +.pseudo_anchor:hover { + tint: var(--primary); + cursor: hand; +} @media (prefers-color-scheme: light) { diff --git a/src/tools/ecode/ecode.cpp b/src/tools/ecode/ecode.cpp index 25edfcdf6..056c7b0e7 100644 --- a/src/tools/ecode/ecode.cpp +++ b/src/tools/ecode/ecode.cpp @@ -173,7 +173,8 @@ void App::saveAllProcess() { } ); dialog->on( Event::OnWindowClose, [this, editor]( const Event* ) { mTmpDocs.erase( &editor->getDocument() ); - if ( !SceneManager::instance()->isShuttingDown() && !mTmpDocs.empty() ) + if ( App::instance() && !SceneManager::instance()->isShuttingDown() && + !mTmpDocs.empty() ) saveAllProcess(); } ); return true; @@ -372,7 +373,8 @@ void App::openFileDialog() { } } ); dialog->on( Event::OnWindowClose, [this]( const Event* ) { - if ( mSplitter && mSplitter->getCurWidget() && !SceneManager::instance()->isShuttingDown() ) + if ( App::instance() && mSplitter && mSplitter->getCurWidget() && + !SceneManager::instance()->isShuttingDown() ) mSplitter->getCurWidget()->setFocus(); } ); dialog->center(); @@ -424,7 +426,8 @@ void App::openFolderDialog() { loadFolder( path ); } ); dialog->on( Event::OnWindowClose, [this]( const Event* ) { - if ( mSplitter && mSplitter->getCurWidget() && !SceneManager::instance()->isShuttingDown() ) + if ( App::instance() && mSplitter && mSplitter->getCurWidget() && + !SceneManager::instance()->isShuttingDown() ) mSplitter->getCurWidget()->setFocus(); } ); dialog->center(); @@ -453,7 +456,7 @@ void App::openFontDialog( std::string& fontPath, bool loadingMonoFont, bool term dialog->setCloseShortcut( KEY_ESCAPE ); dialog->setSingleClickNavigation( mConfig.editor.singleClickNavigation ); dialog->on( Event::OnWindowClose, [this]( const Event* ) { - if ( mSplitter && mSplitter->getCurWidget() && + if ( App::instance() && mSplitter && mSplitter->getCurWidget() && !SceneManager::instance()->isShuttingDown() ) { mSplitter->getCurWidget()->setFocus(); } @@ -563,6 +566,108 @@ void App::downloadFileWeb( const std::string& url ) { UIDownloadWindow::downloadFileWeb( url ); } +void App::maximizeTabWidget() { + UITabWidget* curTabWidget = mSplitter->getCurTabWidget(); + if ( !curTabWidget || mUISceneNode->getRoot()->hasChild( "detached_tab_widget_win" ) ) + return; + + UIWindow::StyleConfig winCfg; + winCfg.WinFlags = UI_WIN_SHADOW | UI_WIN_MODAL | UI_WIN_EPHEMERAL | UI_WIN_NO_DECORATION; + UIWindow* win = UIWindow::NewOpt( UIWindow::SIMPLE_LAYOUT, winCfg ); + win->setPixelsSize( getUISceneNode()->getPixelsSize() - PixelDensity::dpToPx( 64 ) ); + win->setId( "detached_tab_widget_win" ); + win->addClass( "tab_widget_cont" ); + win->getModalWidget()->addClass( "shadowbg" ); + win->getModalWidget()->onClick( [this]( auto ) { + if ( App::instance() ) + restoreMaximizedTabWidget(); + } ); + win->setAnchors( UI_ANCHOR_TOP | UI_ANCHOR_LEFT | UI_ANCHOR_BOTTOM | UI_ANCHOR_RIGHT ); + win->toFront(); + win->center(); + win->setKeyBindingCommand( "close-maximized-tab-widget", [this] { + if ( App::instance() ) + restoreMaximizedTabWidget(); + } ); + win->getKeyBindings().addKeybind( { KEY_ESCAPE }, "close-maximized-tab-widget" ); + win->setCheckEphemeralCloseFn( []( Node* focusNode ) { + if ( focusNode->isType( UI_TYPE_POPUPMENU ) && focusNode->getId() != "settings_menu" ) + return false; + if ( focusNode->getSceneNode()->isUISceneNode() ) { + UISceneNode* sceneNode = static_cast( focusNode->getSceneNode() ); + auto wtv = sceneNode->getRoot()->hasChild( "widget-tree-view" ); + if ( wtv && ( focusNode == wtv || wtv->inParentTreeOf( focusNode ) ) ) + return false; + } + return true; + } ); + auto tabWidgetParent = curTabWidget->getParent(); + bool wasFirstSplit = tabWidgetParent->isType( UI_TYPE_SPLITTER ) && + tabWidgetParent->asType()->getFirstWidget() == curTabWidget; + auto nodeLink = UINodeLink::NewLink( curTabWidget ); + if ( wasFirstSplit ) + nodeLink->setClass( "was_first_split" ); + curTabWidget->setParent( win ); + curTabWidget->setId( "detached_tab_widget" ); + curTabWidget->setPixelsPosition( Vector2f::Zero ); + curTabWidget->setPixelsSize( win->getContainer()->getPixelsSize() ); + curTabWidget->setAnchors( UI_ANCHOR_TOP | UI_ANCHOR_LEFT | UI_ANCHOR_BOTTOM | UI_ANCHOR_RIGHT ); + if ( !curTabWidget->inParentTreeOf( getUISceneNode()->getEventDispatcher()->getFocusNode() ) ) + curTabWidget->getTabSelected()->getOwnedWidget()->setFocus(); + win->on( Event::OnWindowClose, [this]( auto ) { + if ( App::instance() ) + restoreMaximizedTabWidget(); + } ); + nodeLink->setParent( tabWidgetParent ); + nodeLink->setId( "nodelink_tab_widget" ); + if ( wasFirstSplit && tabWidgetParent->isType( UI_TYPE_SPLITTER ) ) + tabWidgetParent->asType()->swap(); + + UIImage* fullscreenImg = UIImage::New(); + fullscreenImg->unsetFlags( UI_AUTO_SIZE ); + fullscreenImg->setLayoutSizePolicy( SizePolicy::Fixed, SizePolicy::Fixed ); + fullscreenImg->setParent( win ); + fullscreenImg->setSize( { 24, curTabWidget->getTabBar()->getSize().getHeight() } ); + fullscreenImg->setPosition( { curTabWidget->getSize().getWidth() - 24, 0 } ); + fullscreenImg->setAnchors( UI_ANCHOR_TOP | UI_ANCHOR_RIGHT ); + fullscreenImg->setDrawable( findIcon( "fullscreen", PixelDensity::dpToPx( 16 ) ) ); + fullscreenImg->setVerticalAlign( UI_VALIGN_CENTER ); + fullscreenImg->setHorizontalAlign( UI_HALIGN_CENTER ); + fullscreenImg->addClass( "pseudo_anchor" ); + fullscreenImg->toFront(); + fullscreenImg->onClick( [this]( auto ) { + restoreMaximizedTabWidget(); + getUISceneNode()->getWindow()->getCursorManager()->set( Cursor::SysType::SysArrow ); + } ); +} + +void App::restoreMaximizedTabWidget() { + if ( !App::instance() || !SceneManager::isActive() ) + return; + auto sceneNode = appInstance->getUISceneNode(); + if ( !sceneNode ) + return; + auto nodeLink = sceneNode->getRoot()->find( "nodelink_tab_widget" ); + if ( !nodeLink ) + return; + auto splitterParent = nodeLink->getParent(); + nodeLink->setParent( sceneNode ); + auto curTabWidget = sceneNode->getRoot()->find( "detached_tab_widget" ); + if ( !curTabWidget ) + return; + curTabWidget->setParent( splitterParent ); + curTabWidget->setAnchors( 0 ); + curTabWidget->setId( "" ); + if ( nodeLink->asType()->hasClass( "was_first_split" ) && + splitterParent->isType( UI_TYPE_SPLITTER ) ) { + splitterParent->asType()->swap(); + } + nodeLink->close(); + auto win = mUISceneNode->find( "detached_tab_widget_win" ); + if ( win ) + win->close(); +} + UIFileDialog* App::saveFileDialog( UICodeEditor* editor, bool focusOnClose ) { if ( !editor ) return nullptr; @@ -611,7 +716,7 @@ UIFileDialog* App::saveFileDialog( UICodeEditor* editor, bool focusOnClose ) { } ); if ( focusOnClose ) { dialog->on( Event::OnWindowClose, [editor]( const Event* ) { - if ( editor && !SceneManager::instance()->isShuttingDown() ) + if ( editor && App::instance() && !SceneManager::instance()->isShuttingDown() ) editor->setFocus(); } ); } @@ -1629,6 +1734,15 @@ void App::onTabCreated( UITab* tab, UIWidget* ) { "clone-document-buffer" ); } + menu->addSeparator(); + if ( mUISceneNode->getRoot()->hasChild( "detached_tab_widget_win" ) ) { + menuAdd( "restore_maximized_tab_widget", "Restore Maximized Tab Widget", "fullscreen", + "restore-maximized-tab-widget" ); + } else { + menuAdd( "maximize_tab_widget", "Maximize Tab Widget", "fullscreen", + "maximize-tab-widget" ); + } + menu->on( Event::OnItemClicked, [tab, this]( const Event* event ) { if ( !event->getNode()->isType( UI_TYPE_MENUITEM ) ) return; @@ -2080,6 +2194,8 @@ std::vector App::getUnlockedCommands() { "create-new-window", "reset-global-language-extensions-priorities", "reset-project-language-extensions-priorities", + "maximize-tab-widget", + "restore-maximized-tab-widget", }; } @@ -2482,6 +2598,9 @@ bool App::loadFileFromPath( loadAudioFromPath( path ); } else if ( !openBinaryAsDocument && PathHelper::isOpenExternalExtension( ext ) ) { Engine::instance()->openURI( path ); + } else if ( tryFindMimeType && TextDocument::fileMightBeBinary( path ) ) { + // Trigger the warning message box with the message "File looks like a binary file" + openFileFromPath( path ); } else { UITab* tab = mSplitter->isDocumentOpen( path ); @@ -3563,6 +3682,8 @@ void App::loadFolder( std::string path, bool forceNewWindow ) { return; } + restoreMaximizedTabWidget(); + Clock dirTreeClock; if ( FileSystem::fileExtension( path ) == "lnk" ) { @@ -4403,6 +4524,10 @@ void App::init( InitParameters& params ) { } return true; } ); + mSplitter->setCanCreateSplitFn( [this]( auto, auto ) { + restoreMaximizedTabWidget(); + return true; + } ); mPluginManager->setSplitter( mSplitter ); Log::info( "Base UI took: %.2f ms", globalClock.getElapsedTime().asMilliseconds() ); diff --git a/src/tools/ecode/ecode.hpp b/src/tools/ecode/ecode.hpp index e2035e289..e277be107 100644 --- a/src/tools/ecode/ecode.hpp +++ b/src/tools/ecode/ecode.hpp @@ -19,6 +19,7 @@ #include "uistatusbar.hpp" #include "universallocator.hpp" #include +#include #include #include #include @@ -438,8 +439,16 @@ class App : public UICodeEditorSplitter::Client, public PluginContextProvider { i18n( "no_project_loaded", "No project loaded" ) ); } } ); + + t.setCommand( "maximize-tab-widget", [this] { maximizeTabWidget(); } ); + + t.setCommand( "restore-maximized-tab-widget", [this] { restoreMaximizedTabWidget(); } ); } + void maximizeTabWidget(); + + void restoreMaximizedTabWidget(); + PluginManager* getPluginManager() const; void diff --git a/src/tools/ecode/featureshealth.cpp b/src/tools/ecode/featureshealth.cpp index 2fb6b3742..2706d7d7a 100644 --- a/src/tools/ecode/featureshealth.cpp +++ b/src/tools/ecode/featureshealth.cpp @@ -592,6 +592,7 @@ void FeaturesHealth::displayHealth( PluginManager* pluginManager, UISceneNode* s win->setKeyBindingCommand( "close-window", [win]() { win->closeWindow(); } ); win->addKeyBinding( { KEY_ESCAPE }, "close-window" ); + win->on( Event::OnWindowReady, [table]( auto ) { table->setFocus(); } ); win->showWhenReady(); win->center(); } diff --git a/src/tools/ecode/ignorematcher.cpp b/src/tools/ecode/ignorematcher.cpp index 27e9a44d1..dc1a955ce 100644 --- a/src/tools/ecode/ignorematcher.cpp +++ b/src/tools/ecode/ignorematcher.cpp @@ -95,8 +95,8 @@ std::string GitIgnoreMatcher::findRepositoryRootPath() const { return FileSystem::fileExists( rootPath + ".git" ) ? rootPath : ""; } -IgnoreMatcherManager::IgnoreMatcherManager( IgnoreMatcherManager&& ignoreMatcher ) : - mMatchers( ignoreMatcher.mMatchers ) { +IgnoreMatcherManager::IgnoreMatcherManager( IgnoreMatcherManager&& ignoreMatcher ) noexcept : + mMatchers( std::move( ignoreMatcher.mMatchers ) ) { ignoreMatcher.mMatchers.clear(); } @@ -108,8 +108,8 @@ IgnoreMatcherManager::IgnoreMatcherManager( std::string rootPath ) { mMatchers.emplace_back( eeNew( GitIgnoreMatcher, ( rootPath ) ) ); } -IgnoreMatcherManager& IgnoreMatcherManager::operator=( IgnoreMatcherManager&& other ) { - mMatchers = other.mMatchers; +IgnoreMatcherManager& IgnoreMatcherManager::operator=( IgnoreMatcherManager&& other ) noexcept { + mMatchers = std::move( other.mMatchers ); other.mMatchers.clear(); return *this; } diff --git a/src/tools/ecode/ignorematcher.hpp b/src/tools/ecode/ignorematcher.hpp index a150bf650..f7b0e2d98 100644 --- a/src/tools/ecode/ignorematcher.hpp +++ b/src/tools/ecode/ignorematcher.hpp @@ -61,11 +61,11 @@ class GitIgnoreMatcher : public IgnoreMatcher { class IgnoreMatcherManager { public: - IgnoreMatcherManager( IgnoreMatcherManager&& ignoreMatcher ); + IgnoreMatcherManager( IgnoreMatcherManager&& ignoreMatcher ) noexcept; IgnoreMatcherManager( std::string rootPath ); - IgnoreMatcherManager& operator=( IgnoreMatcherManager&& other ); + IgnoreMatcherManager& operator=( IgnoreMatcherManager&& other ) noexcept; virtual ~IgnoreMatcherManager(); diff --git a/src/tools/ecode/plugins/aiassistant/chatui.cpp b/src/tools/ecode/plugins/aiassistant/chatui.cpp index 736714cb1..dc63afb09 100644 --- a/src/tools/ecode/plugins/aiassistant/chatui.cpp +++ b/src/tools/ecode/plugins/aiassistant/chatui.cpp @@ -687,6 +687,7 @@ void LLMChatUI::showChatHistory() { win->center(); win->getModalWidget()->addClass( "shadowbg" ); win->setId( UUID().toString() ); + win->on( Event::OnWindowReady, [win]( auto ) { win->setFocus(); } ); loader->center(); diff --git a/src/tools/ecode/plugins/debugger/debuggerclientlistener.cpp b/src/tools/ecode/plugins/debugger/debuggerclientlistener.cpp index 58596dfff..6db2c81e4 100644 --- a/src/tools/ecode/plugins/debugger/debuggerclientlistener.cpp +++ b/src/tools/ecode/plugins/debugger/debuggerclientlistener.cpp @@ -111,6 +111,7 @@ void DebuggerClientListener::createAndShowVariableMenu( ModelIndex idx ) { UITextEdit* input = win->find( "value_input" )->asType(); input->setText( var.value ); win->center(); + win->on( Event::OnWindowReady, [input]( auto ) { input->setFocus(); } ); win->showWhenReady(); } } ); diff --git a/src/tools/ecode/plugins/debugger/statusdebuggercontroller.cpp b/src/tools/ecode/plugins/debugger/statusdebuggercontroller.cpp index 620f9da28..91a8d3e3d 100644 --- a/src/tools/ecode/plugins/debugger/statusdebuggercontroller.cpp +++ b/src/tools/ecode/plugins/debugger/statusdebuggercontroller.cpp @@ -279,6 +279,14 @@ void StatusDebuggerController::createContainer() { } ); } + mContainer->on( Event::KeyDown, [this]( const Event* event ) { + auto ke = event->asKeyEvent(); + if ( ke->getSanitizedMod() == 0 && ke->getKeyCode() == EE::Window::KEY_ESCAPE && + mSplitter->getCurEditor() ) { + mSplitter->getCurEditor()->setFocus(); + } + } ); + mContainer->getKeyBindings().addKeybinds( getLocalDefaultKeybindings() ); setDebuggingState( State::NotStarted ); diff --git a/src/tools/ecode/plugins/pluginmanager.cpp b/src/tools/ecode/plugins/pluginmanager.cpp index 13078117b..a4890186f 100644 --- a/src/tools/ecode/plugins/pluginmanager.cpp +++ b/src/tools/ecode/plugins/pluginmanager.cpp @@ -545,6 +545,7 @@ UIWindow* UIPluginManager::New( UISceneNode* sceneNode, PluginManager* manager, win->close(); } ); win->center(); + win->on( Event::OnWindowReady, [close]( auto ) { close->setFocus(); } ); return win; } diff --git a/src/tools/ecode/settingsactions.cpp b/src/tools/ecode/settingsactions.cpp index ffec1cd85..71ba55d9c 100644 --- a/src/tools/ecode/settingsactions.cpp +++ b/src/tools/ecode/settingsactions.cpp @@ -101,7 +101,7 @@ void SettingsActions::checkForUpdatesResponse( Http::Response&& response, bool f void SettingsActions::checkForUpdates( bool fromStartup ) { Http::getAsync( [this, fromStartup]( const Http&, Http::Request&, Http::Response& response ) { - if ( !SceneManager::existsSingleton() || SceneManager::instance()->isShuttingDown() ) + if ( !SceneManager::isActive() ) return; mApp->getUISceneNode()->runOnMainThread( [this, res = response, fromStartup]() mutable { checkForUpdatesResponse( std::move( res ), fromStartup ); diff --git a/src/tools/ecode/statusappoutputcontroller.cpp b/src/tools/ecode/statusappoutputcontroller.cpp index 37658edb6..9b2760e13 100644 --- a/src/tools/ecode/statusappoutputcontroller.cpp +++ b/src/tools/ecode/statusappoutputcontroller.cpp @@ -182,6 +182,7 @@ void StatusAppOutputController::createContainer() { mContext->getStatusBar()->registerStatusBarPanel( mContainer, mContainer ); auto editor = mContainer->find( "app_output_output" ); + mContainer->getKeyBindings().addKeybindsStringUnordered( mContext->getStatusBarKeybindings() ); editor->getKeyBindings().addKeybindsStringUnordered( mContext->getStatusBarKeybindings() ); editor->setLocked( true ); @@ -195,6 +196,14 @@ void StatusAppOutputController::createContainer() { mScrollLocked = mAppOutput->getMaxScroll().y == mAppOutput->getScroll().y; } ); mContainer->setVisible( false ); + mContainer->on( Event::OnFocus, [this]( auto ) { mAppOutput->setFocus(); } ); + mContainer->on( Event::KeyDown, [this]( const Event* event ) { + auto ke = event->asKeyEvent(); + if ( ke->getSanitizedMod() == 0 && ke->getKeyCode() == EE::Window::KEY_ESCAPE && + mSplitter->getCurEditor() ) { + mSplitter->getCurEditor()->setFocus(); + } + } ); mContainer->bind( "app_output_clear", mClearButton ); mContainer->bind( "app_output_run", mRunButton ); diff --git a/src/tools/ecode/statusbuildoutputcontroller.cpp b/src/tools/ecode/statusbuildoutputcontroller.cpp index 6c3f6afb7..7e920f835 100644 --- a/src/tools/ecode/statusbuildoutputcontroller.cpp +++ b/src/tools/ecode/statusbuildoutputcontroller.cpp @@ -455,12 +455,22 @@ void StatusBuildOutputController::createContainer() { mContainer = mContext->getUISceneNode() ->loadLayoutFromString( XML, mMainSplitter ) ->asType(); + + mContainer->on( Event::KeyDown, [this]( const Event* event ) { + auto ke = event->asKeyEvent(); + if ( ke->getSanitizedMod() == 0 && ke->getKeyCode() == EE::Window::KEY_ESCAPE && + mSplitter->getCurEditor() ) { + mSplitter->getCurEditor()->setFocus(); + } + } ); + mRelLayCE = mContainer->find( "build_output_command_executer" ) ->asType(); mContext->getStatusBar()->registerStatusBarPanel( mContainer, mContainer ); auto editor = mContainer->find( "build_output_output" ); + mContainer->getKeyBindings().addKeybindsStringUnordered( mContext->getStatusBarKeybindings() ); editor->getKeyBindings().addKeybindsStringUnordered( mContext->getStatusBarKeybindings() ); editor->setLocked( true ); @@ -571,18 +581,28 @@ void StatusBuildOutputController::createContainer() { mScrollLocked = mBuildOutput->getMaxScroll().y == mBuildOutput->getScroll().y; } ); mContainer->setVisible( false ); - mRelLayCE->setCommand( "build-output-show-build-output", [this]() { showBuildOutput(); } ); - mRelLayCE->setCommand( "build-output-show-build-issues", [this]() { showIssues(); } ); - mRelLayCE->getKeyBindings().addKeybind( { KEY_1, KeyMod::getDefaultModifier() }, - "build-output-show-build-output" ); - mRelLayCE->getKeyBindings().addKeybind( { KEY_2, KeyMod::getDefaultModifier() }, - "build-output-show-build-issues" ); + + mContainer->setCommand( "build-output-show-build-output", [this]() { showBuildOutput(); } ); + mContainer->setCommand( "build-output-show-build-issues", [this]() { showIssues(); } ); + mContainer->getKeyBindings().addKeybind( { KEY_1, KeyMod::getDefaultModifier() }, + "build-output-show-build-output" ); + mContainer->getKeyBindings().addKeybind( { KEY_2, KeyMod::getDefaultModifier() }, + "build-output-show-build-issues" ); + + mBuildOutput->getDocument().setCommand( "build-output-show-build-output", + [this]() { showBuildOutput(); } ); + mBuildOutput->getDocument().setCommand( "build-output-show-build-issues", + [this]() { showIssues(); } ); + mBuildOutput->getKeyBindings().addKeybind( { KEY_1, KeyMod::getDefaultModifier() }, + "build-output-show-build-output" ); + mBuildOutput->getKeyBindings().addKeybind( { KEY_2, KeyMod::getDefaultModifier() }, + "build-output-show-build-issues" ); mButOutput->onClick( [this]( auto ) { showBuildOutput(); } ); mButIssues->onClick( [this]( auto ) { showIssues(); } ); mButOutput->setTooltipText( - mRelLayCE->getKeyBindings().getCommandKeybindString( "build-output-show-build-output" ) ); + mContainer->getKeyBindings().getCommandKeybindString( "build-output-show-build-output" ) ); mButIssues->setTooltipText( - mRelLayCE->getKeyBindings().getCommandKeybindString( "build-output-show-build-issues" ) ); + mContainer->getKeyBindings().getCommandKeybindString( "build-output-show-build-issues" ) ); mContainer->bind( "build_output_clear", mClearButton ); mContainer->bind( "build_output_build", mBuildButton ); diff --git a/src/tools/ecode/widgetcommandexecuter.hpp b/src/tools/ecode/widgetcommandexecuter.hpp index cc87cca02..9d2fbe60c 100644 --- a/src/tools/ecode/widgetcommandexecuter.hpp +++ b/src/tools/ecode/widgetcommandexecuter.hpp @@ -14,7 +14,7 @@ class UISearchBar : public UILinearLayout, public WidgetCommandExecuter { WidgetCommandExecuter( getInput() ) {} virtual Uint32 onKeyDown( const KeyEvent& event ) { - return WidgetCommandExecuter::onKeyDown( event ); + return WidgetCommandExecuter::onKeyDown( event ) || UILinearLayout::onKeyDown( event ); } }; @@ -26,7 +26,7 @@ class UILocateBar : public UILinearLayout, public WidgetCommandExecuter { WidgetCommandExecuter( getInput() ) {} virtual Uint32 onKeyDown( const KeyEvent& event ) { - return WidgetCommandExecuter::onKeyDown( event ); + return WidgetCommandExecuter::onKeyDown( event ) || UILinearLayout::onKeyDown( event ); } }; @@ -39,7 +39,7 @@ class UIGlobalSearchBar : public UILinearLayout, public WidgetCommandExecuter { WidgetCommandExecuter( getInput() ) {} virtual Uint32 onKeyDown( const KeyEvent& event ) { - return WidgetCommandExecuter::onKeyDown( event ); + return WidgetCommandExecuter::onKeyDown( event ) || UILinearLayout::onKeyDown( event ); } }; @@ -50,7 +50,7 @@ class UIMainLayout : public UIRelativeLayout, public WidgetCommandExecuter { UIMainLayout() : UIRelativeLayout( "mainlayout" ), WidgetCommandExecuter( getInput() ) {} virtual Uint32 onKeyDown( const KeyEvent& event ) { - return WidgetCommandExecuter::onKeyDown( event ); + return WidgetCommandExecuter::onKeyDown( event ) || UIRelativeLayout::onKeyDown( event ); } }; @@ -64,7 +64,7 @@ class UIRelativeLayoutCommandExecuter : public UIRelativeLayout, public WidgetCo UIRelativeLayout( "rellayce" ), WidgetCommandExecuter( getInput() ) {} virtual Uint32 onKeyDown( const KeyEvent& event ) { - return WidgetCommandExecuter::onKeyDown( event ); + return WidgetCommandExecuter::onKeyDown( event ) || UIRelativeLayout::onKeyDown( event ); } }; @@ -79,7 +79,7 @@ class UIHLinearLayoutCommandExecuter : public UILinearLayout, public WidgetComma WidgetCommandExecuter( getInput() ) {} virtual Uint32 onKeyDown( const KeyEvent& event ) { - return WidgetCommandExecuter::onKeyDown( event ); + return WidgetCommandExecuter::onKeyDown( event ) || UILinearLayout::onKeyDown( event ); } }; @@ -93,7 +93,7 @@ class UIVLinearLayoutCommandExecuter : public UILinearLayout, public WidgetComma UILinearLayout( "vboxce", UIOrientation::Vertical ), WidgetCommandExecuter( getInput() ) {} virtual Uint32 onKeyDown( const KeyEvent& event ) { - return WidgetCommandExecuter::onKeyDown( event ); + return WidgetCommandExecuter::onKeyDown( event ) || UILinearLayout::onKeyDown( event ); } };