From 4680b3a4063a0c73c05c353def799b1c996aa6c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Lucas=20Golini?= Date: Mon, 18 Jul 2022 01:44:34 -0300 Subject: [PATCH] Added UIClip and ClipType. New clipping options for UINode. CSS property "clip" now allows: "none", "padding-box", "content-box" and "border-box". Allowing more precise clipping for each UINode. Replaced all clipEnable and clipDisable calls in favor of setClipType. UINode::draw now does not call drawBackground and drawSkin. Both functions now are called separately before the draw call. Input: fixed WindowClose and Quit event report (Quit won't trigger onClose). ecode: Code clean up, added TerminalManager. Fixed some minor bugs. --- docs/articles/cssspecification.md | 9 +- include/eepp/ui/uiborderdrawable.hpp | 2 + include/eepp/ui/uiclip.hpp | 31 ++ include/eepp/ui/uinode.hpp | 16 + projects/linux/ee.creator.user | 5 +- projects/linux/ee.files | 4 + src/eepp/ui/abstract/uiabstracttableview.cpp | 2 +- src/eepp/ui/css/stylesheetspecification.cpp | 2 +- src/eepp/ui/uiborderdrawable.cpp | 24 ++ src/eepp/ui/uiclip.cpp | 43 +++ src/eepp/ui/uicodeeditor.cpp | 2 +- src/eepp/ui/uiconsole.cpp | 2 +- src/eepp/ui/uidropdownlist.cpp | 2 +- src/eepp/ui/uilinearlayout.cpp | 4 +- src/eepp/ui/uilistbox.cpp | 2 +- src/eepp/ui/uimessagebox.cpp | 8 +- src/eepp/ui/uinode.cpp | 87 ++++- src/eepp/ui/uiscrollview.cpp | 2 +- src/eepp/ui/uitableview.cpp | 2 +- src/eepp/ui/uitabwidget.cpp | 2 +- src/eepp/ui/uitextedit.cpp | 2 +- src/eepp/ui/uitextinput.cpp | 36 +- src/eepp/ui/uitextview.cpp | 4 +- src/eepp/ui/uitreeview.cpp | 4 +- src/eepp/ui/uiviewpager.cpp | 2 +- src/eepp/ui/uiwidget.cpp | 13 +- src/eepp/ui/uiwidgettable.cpp | 4 +- src/eepp/ui/uiwindow.cpp | 46 ++- src/eepp/window/input.cpp | 4 - src/tools/ecode/appconfig.cpp | 4 +- src/tools/ecode/ecode.cpp | 293 ++-------------- src/tools/ecode/ecode.hpp | 65 ++-- src/tools/ecode/terminalmanager.cpp | 343 +++++++++++++++++++ src/tools/ecode/terminalmanager.hpp | 56 +++ 34 files changed, 761 insertions(+), 366 deletions(-) create mode 100644 include/eepp/ui/uiclip.hpp create mode 100644 src/eepp/ui/uiclip.cpp create mode 100644 src/tools/ecode/terminalmanager.cpp create mode 100644 src/tools/ecode/terminalmanager.hpp diff --git a/docs/articles/cssspecification.md b/docs/articles/cssspecification.md index c2bb2f382..a8d08b585 100644 --- a/docs/articles/cssspecification.md +++ b/docs/articles/cssspecification.md @@ -433,10 +433,15 @@ element. ### clip -Enables/disables clipping to the element box. +Specifies how the clipping is applied to the element if clip is enabled. * Applicable to: Any element -* Data Type: [boolean](#boolean-data-type) +* Data Type: [string-list](#string-list-data-type) +* Value List: + * `none`: No clipping is applied. + * `content-box`: Clips the content box of the element (means the whole box). + * `padding-box`: Clips the padding box of the element (the whole box minus the padding). + * `border-box`: Clips the border box of the element (the content box plus the border). * Default Value: Varies for each widget/element. --- diff --git a/include/eepp/ui/uiborderdrawable.hpp b/include/eepp/ui/uiborderdrawable.hpp index 64df1a8ac..042f16b1d 100644 --- a/include/eepp/ui/uiborderdrawable.hpp +++ b/include/eepp/ui/uiborderdrawable.hpp @@ -78,6 +78,8 @@ class EE_API UIBorderDrawable : public Drawable { const Borders& getBorders() const; + Rectf getBorderBoxDiff() const; + protected: const UINode* mOwner; VertexBuffer* mVertexBuffer; diff --git a/include/eepp/ui/uiclip.hpp b/include/eepp/ui/uiclip.hpp new file mode 100644 index 000000000..b89f40467 --- /dev/null +++ b/include/eepp/ui/uiclip.hpp @@ -0,0 +1,31 @@ +#ifndef EE_UI_UICLIP_HPP +#define EE_UI_UICLIP_HPP + +#include +#include + +namespace EE { namespace UI { + +enum class ClipType : Uint32 { None, ContentBox, PaddingBox, BorderBox }; + +class UIClip { + public: + UIClip(); + + UIClip( const ClipType& clipType ); + + static ClipType fromString( std::string str ); + + static std::string toString( const ClipType& clipType ); + + const ClipType& getClipType() const; + + void setClipType( const ClipType& clipType ); + + protected: + ClipType mClipType{ ClipType::None }; +}; + +}} // namespace EE::UI + +#endif // EE_UI_UICLIP_HPP diff --git a/include/eepp/ui/uinode.hpp b/include/eepp/ui/uinode.hpp index 2236a5371..131abc01a 100644 --- a/include/eepp/ui/uinode.hpp +++ b/include/eepp/ui/uinode.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -267,6 +268,14 @@ class EE_API UINode : public Node { void clearBackground(); + const ClipType& getClipType() const; + + UINode* setClipType( const ClipType& clipType ); + + bool hasBorder() const; + + virtual const Rectf& getPixelsPadding() const; + protected: Vector2f mDpPos; Sizef mDpSize; @@ -281,6 +290,9 @@ class EE_API UINode : public Node { Uint32 mDragButton; Color mSkinColor; UISceneNode* mUISceneNode; + Rectf mPadding; + Rectf mPaddingPx; + UIClip mClip; virtual Uint32 onMouseDown( const Vector2i& position, const Uint32& flags ); @@ -358,6 +370,10 @@ class EE_API UINode : public Node { void setInternalPixelsHeight( const Float& height ); virtual void updateOriginPoint(); + + void smartClipStart( const ClipType& reqClipType ); + + void smartClipEnd( const ClipType& reqClipType ); }; }} // namespace EE::UI diff --git a/projects/linux/ee.creator.user b/projects/linux/ee.creator.user index 94f75dac1..b915e5c3f 100644 --- a/projects/linux/ee.creator.user +++ b/projects/linux/ee.creator.user @@ -1,6 +1,6 @@ - + EnvironmentId @@ -109,7 +109,7 @@ {388e5431-b31b-42b3-b9ad-9002d279d75d} 10 0 - 16 + 19 ../../make/linux @@ -1203,7 +1203,6 @@ ecode-debug ProjectExplorer.CustomExecutableRunConfiguration - /home/programming/nume/nume-api/ true false false diff --git a/projects/linux/ee.files b/projects/linux/ee.files index 9a682f348..2e45c8477 100644 --- a/projects/linux/ee.files +++ b/projects/linux/ee.files @@ -356,6 +356,7 @@ ../../include/eepp/ui/uibackgrounddrawable.hpp ../../include/eepp/ui/uiborderdrawable.hpp ../../include/eepp/ui/uicheckbox.hpp +../../include/eepp/ui/uiclip.hpp ../../include/eepp/ui/uicodeeditor.hpp ../../include/eepp/ui/uicombobox.hpp ../../include/eepp/ui/uiconsole.hpp @@ -837,6 +838,7 @@ ../../src/eepp/ui/uibackgrounddrawable.cpp ../../src/eepp/ui/uiborderdrawable.cpp ../../src/eepp/ui/uicheckbox.cpp +../../src/eepp/ui/uiclip.cpp ../../src/eepp/ui/uicodeeditor.cpp ../../src/eepp/ui/uicombobox.cpp ../../src/eepp/ui/uiconsole.cpp @@ -1155,6 +1157,8 @@ ../../src/tools/ecode/projectsearch.cpp ../../src/tools/ecode/projectsearch.hpp ../../src/tools/ecode/scopedop.hpp +../../src/tools/ecode/terminalmanager.cpp +../../src/tools/ecode/terminalmanager.hpp ../../src/tools/ecode/uicodeeditorsplitter.cpp ../../src/tools/ecode/uicodeeditorsplitter.hpp ../../src/tools/ecode/uitreeviewglobalsearch.cpp diff --git a/src/eepp/ui/abstract/uiabstracttableview.cpp b/src/eepp/ui/abstract/uiabstracttableview.cpp index feecda8e9..2056c195b 100644 --- a/src/eepp/ui/abstract/uiabstracttableview.cpp +++ b/src/eepp/ui/abstract/uiabstracttableview.cpp @@ -409,7 +409,7 @@ UIWidget* UIAbstractTableView::createCell( UIWidget* rowWidget, const ModelIndex UITableCell* widget = UITableCell::New( mTag + "::cell" ); widget->setParent( rowWidget ); widget->unsetFlags( UI_AUTO_SIZE ); - widget->clipEnable(); + widget->setClipType( ClipType::ContentBox ); widget->setLayoutSizePolicy( SizePolicy::Fixed, SizePolicy::Fixed ); widget->setTextAlign( UI_HALIGN_LEFT ); widget->setCurIndex( index ); diff --git a/src/eepp/ui/css/stylesheetspecification.cpp b/src/eepp/ui/css/stylesheetspecification.cpp index 0cb460282..65176a1ee 100644 --- a/src/eepp/ui/css/stylesheetspecification.cpp +++ b/src/eepp/ui/css/stylesheetspecification.cpp @@ -154,7 +154,7 @@ void StyleSheetSpecification::registerDefaultProperties() { registerProperty( "layout-to-right-of", "" ).addAlias( "layout_to_right_of" ); registerProperty( "layout-to-top-of", "" ).addAlias( "layout_to_top_of" ); registerProperty( "layout-to-bottom-of", "" ).addAlias( "layout_to_bottom_of" ); - registerProperty( "clip", "" ).setType( PropertyType::Bool ); + registerProperty( "clip", "" ).setType( PropertyType::String ); registerProperty( "rotation", "" ).setType( PropertyType::NumberFloat ); registerProperty( "scale", "" ).setType( PropertyType::Vector2 ); registerProperty( "rotation-origin-point-x", "50%" ) diff --git a/src/eepp/ui/uiborderdrawable.cpp b/src/eepp/ui/uiborderdrawable.cpp index f9a3d69f3..5f1899d08 100644 --- a/src/eepp/ui/uiborderdrawable.cpp +++ b/src/eepp/ui/uiborderdrawable.cpp @@ -239,6 +239,30 @@ void UIBorderDrawable::onPositionChange() { mNeedsUpdate = true; } +Rectf UIBorderDrawable::getBorderBoxDiff() const { + Rectf bd; + switch ( mBorderType ) { + case BorderType::Outside: { + bd.Left = -mBorders.left.width; + bd.Right = mBorders.right.width; + bd.Top = -mBorders.top.width; + bd.Bottom = mBorders.bottom.width; + break; + } + case BorderType::Outline: { + bd.Left = -( mBorders.left.width * 0.5f ); + bd.Right = mBorders.right.width * 0.5f; + bd.Top = -( mBorders.top.width * 0.5f ); + bd.Bottom = mBorders.bottom.width * 0.5f; + break; + } + case BorderType::Inside: { + break; + } + } + return bd; +} + void UIBorderDrawable::update() { updateBorders(); diff --git a/src/eepp/ui/uiclip.cpp b/src/eepp/ui/uiclip.cpp new file mode 100644 index 000000000..e6d668255 --- /dev/null +++ b/src/eepp/ui/uiclip.cpp @@ -0,0 +1,43 @@ +#include +#include + +namespace EE { namespace UI { + +ClipType UIClip::fromString( std::string str ) { + String::toLowerInPlace( str ); + if ( str == "content-box" || str == "true" || str == "1" || str == "t" || str == "y" ) + return ClipType::ContentBox; + else if ( str == "padding-box" ) + return ClipType::PaddingBox; + else if ( str == "content-box" ) + return ClipType::BorderBox; + return ClipType::None; +} + +std::string UIClip::toString( const ClipType& clipType ) { + switch ( clipType ) { + case ClipType::ContentBox: + return "content-box"; + case ClipType::PaddingBox: + return "padding-box"; + case ClipType::BorderBox: + return "border-box"; + case ClipType::None: + return "none"; + } + return "none"; +} + +UIClip::UIClip() {} + +UIClip::UIClip( const ClipType& clipType ) : mClipType( clipType ) {} + +const ClipType& UIClip::getClipType() const { + return mClipType; +} + +void UIClip::setClipType( const ClipType& clipType ) { + mClipType = clipType; +} + +}} // namespace EE::UI diff --git a/src/eepp/ui/uicodeeditor.cpp b/src/eepp/ui/uicodeeditor.cpp index f6e3b03ba..7359bb166 100644 --- a/src/eepp/ui/uicodeeditor.cpp +++ b/src/eepp/ui/uicodeeditor.cpp @@ -142,7 +142,7 @@ UICodeEditor::UICodeEditor( const std::string& elementTag, const bool& autoRegis setFontSize( getUISceneNode()->getUIThemeManager()->getDefaultFontSize() ); - clipEnable(); + setClipType( ClipType::ContentBox ); mDoc->registerClient( this ); subscribeScheduledUpdate(); diff --git a/src/eepp/ui/uiconsole.cpp b/src/eepp/ui/uiconsole.cpp index 2c7fe0139..1e9de6bfd 100644 --- a/src/eepp/ui/uiconsole.cpp +++ b/src/eepp/ui/uiconsole.cpp @@ -40,7 +40,7 @@ UIConsole::UIConsole( Font* font, const bool& makeDefaultCommands, const bool& a UIWidget( "console" ), mKeyBindings( getUISceneNode()->getWindow()->getInput() ) { setFlags( UI_AUTO_PADDING ); mFlags |= UI_TAB_STOP; - clipEnable(); + setClipType( ClipType::ContentBox ); setBackgroundColor( 0x201F1FEE ); diff --git a/src/eepp/ui/uidropdownlist.cpp b/src/eepp/ui/uidropdownlist.cpp index b0ac15195..4f02b6737 100644 --- a/src/eepp/ui/uidropdownlist.cpp +++ b/src/eepp/ui/uidropdownlist.cpp @@ -19,7 +19,7 @@ UIDropDownList* UIDropDownList::New() { UIDropDownList::UIDropDownList( const std::string& tag ) : UITextInput( tag ), mListBox( NULL ), mFriendNode( NULL ) { - clipEnable(); + setClipType( ClipType::ContentBox ); setFlags( UI_AUTO_SIZE | UI_AUTO_PADDING ); unsetFlags( UI_TEXT_SELECTION_ENABLED ); diff --git a/src/eepp/ui/uilinearlayout.cpp b/src/eepp/ui/uilinearlayout.cpp index f0045f560..3798375b3 100644 --- a/src/eepp/ui/uilinearlayout.cpp +++ b/src/eepp/ui/uilinearlayout.cpp @@ -24,13 +24,13 @@ UILinearLayout* UILinearLayout::NewHorizontal() { UILinearLayout::UILinearLayout() : UILayout( "linearlayout" ), mOrientation( UIOrientation::Vertical ) { mFlags |= UI_OWNS_CHILDS_POSITION; - clipEnable(); + setClipType( ClipType::ContentBox ); } UILinearLayout::UILinearLayout( const std::string& tag, const UIOrientation& orientation ) : UILayout( tag ), mOrientation( orientation ) { mFlags |= UI_OWNS_CHILDS_POSITION; - clipEnable(); + setClipType( ClipType::ContentBox ); } Uint32 UILinearLayout::getType() const { diff --git a/src/eepp/ui/uilistbox.cpp b/src/eepp/ui/uilistbox.cpp index 1cc8f6227..ba8917708 100644 --- a/src/eepp/ui/uilistbox.cpp +++ b/src/eepp/ui/uilistbox.cpp @@ -48,7 +48,7 @@ UIListBox::UIListBox( const std::string& tag ) : mContainer->setEnabled( true ); mContainer->setFlags( mFlags ); mContainer->setPosition( 0, 0 ); - mContainer->clipEnable(); + mContainer->setClipType( ClipType::ContentBox ); mVScrollBar = UIScrollBar::NewVertical(); mVScrollBar->setParent( this ); diff --git a/src/eepp/ui/uimessagebox.cpp b/src/eepp/ui/uimessagebox.cpp index 8faead483..7cc5e9025 100644 --- a/src/eepp/ui/uimessagebox.cpp +++ b/src/eepp/ui/uimessagebox.cpp @@ -24,8 +24,8 @@ UIMessageBox::UIMessageBox( const Type& type, const String& message, const Uint3 UILinearLayout* vlay = UILinearLayout::NewVertical(); vlay->setLayoutSizePolicy( SizePolicy::WrapContent, SizePolicy::WrapContent ) ->setLayoutMargin( Rectf( 8, 8, 8, 8 ) ) - ->setParent( mLayoutCont ) - ->clipDisable(); + ->setClipType( ClipType::None ) + ->setParent( mLayoutCont ); mTextBox = UITextView::New(); mTextBox->setText( message ) @@ -46,8 +46,8 @@ UIMessageBox::UIMessageBox( const Type& type, const String& message, const Uint3 hlay->setLayoutMargin( Rectf( 0, 8, 0, 0 ) ) ->setLayoutSizePolicy( SizePolicy::WrapContent, SizePolicy::WrapContent ) ->setLayoutGravity( UI_HALIGN_RIGHT | UI_VALIGN_CENTER ) - ->setParent( vlay ) - ->clipDisable(); + ->setClipType( ClipType::None ) + ->setParent( vlay ); mButtonOK = UIPushButton::New(); mButtonOK->setSize( 90, 0 )->setParent( hlay ); diff --git a/src/eepp/ui/uinode.cpp b/src/eepp/ui/uinode.cpp index f57e9375e..db1296b24 100644 --- a/src/eepp/ui/uinode.cpp +++ b/src/eepp/ui/uinode.cpp @@ -426,13 +426,7 @@ void UINode::drawSkin() { } } -void UINode::draw() { - if ( 0.f != mAlpha ) { - drawBackground(); - - drawSkin(); - } -} +void UINode::draw() {} Uint32 UINode::onMouseDown( const Vector2i& position, const Uint32& flags ) { if ( NULL != getEventDispatcher() && !getEventDispatcher()->isNodeDragging() && @@ -762,6 +756,42 @@ void UINode::drawBorder() { } } +void UINode::smartClipStart( const ClipType& reqClipType ) { + if ( mClip.getClipType() != reqClipType ) + return; + switch ( mClip.getClipType() ) { + case ClipType::PaddingBox: { + const Rectf& pd = getPixelsPadding(); + clipSmartEnable( mScreenPos.x + pd.Left, mScreenPos.y + pd.Top, + mSize.getWidth() - pd.Left - pd.Right, + mSize.getHeight() - pd.Top - pd.Bottom ); + break; + } + case ClipType::ContentBox: { + clipSmartEnable( mScreenPos.x, mScreenPos.y, mSize.getWidth(), mSize.getHeight() ); + break; + } + case ClipType::BorderBox: { + Rectf borderDiff; + if ( mBorder ) + borderDiff = mBorder->getBorderBoxDiff(); + clipSmartEnable( mScreenPos.x + borderDiff.Left, mScreenPos.y + borderDiff.Top, + mSize.getWidth() + borderDiff.Right, + mSize.getHeight() + borderDiff.Bottom ); + break; + } + case ClipType::None: { + break; + } + } +} + +void UINode::smartClipEnd( const ClipType& reqClipType ) { + if ( mVisible && isClipped() && mClip.getClipType() == reqClipType ) { + clipEnd(); + } +} + void UINode::nodeDraw() { if ( mVisible ) { if ( mNodeFlags & NODE_FLAG_POSITION_DIRTY ) @@ -772,17 +802,29 @@ void UINode::nodeDraw() { matrixSet(); + smartClipStart( ClipType::BorderBox ); + if ( mWorldBounds.intersect( mSceneNode->getWorldBounds() ) ) { - clipStart(); + smartClipStart( ClipType::ContentBox ); + + if ( 0.f != mAlpha ) { + drawBackground(); + + drawSkin(); + } + + smartClipStart( ClipType::PaddingBox ); draw(); drawChilds(); + smartClipEnd( ClipType::PaddingBox ); + if ( 0.f != mAlpha ) drawForeground(); - clipEnd(); + smartClipEnd( ClipType::ContentBox ); } else if ( !isClipped() ) { drawChilds(); } @@ -800,6 +842,8 @@ void UINode::nodeDraw() { drawBox(); + smartClipEnd( ClipType::BorderBox ); + matrixUnset(); } } @@ -812,6 +856,31 @@ void UINode::clearBackground() { eeSAFE_DELETE( mBackground ); } +const ClipType& UINode::getClipType() const { + return mClip.getClipType(); +} + +UINode* UINode::setClipType( const ClipType& clipType ) { + if ( mClip.getClipType() != clipType ) { + mClip.setClipType( clipType ); + if ( mClip.getClipType() != ClipType::None ) { + clipEnable(); + } else { + clipDisable(); + } + } + return this; +} + +bool UINode::hasBorder() const { + return ( mFlags & UI_BORDER ) != 0; +} + +const Rectf& UINode::getPixelsPadding() const { + static const Rectf Zero{}; + return Zero; +} + UINodeDrawable* UINode::getBackground() const { if ( NULL == mBackground ) { mBackground = UINodeDrawable::New( const_cast( this ) ); diff --git a/src/eepp/ui/uiscrollview.cpp b/src/eepp/ui/uiscrollview.cpp index 9bff8e074..b8ce93763 100644 --- a/src/eepp/ui/uiscrollview.cpp +++ b/src/eepp/ui/uiscrollview.cpp @@ -25,7 +25,7 @@ UIScrollView::UIScrollView() : mVScroll->setParent( this ); mHScroll->setParent( this ); mContainer->setParent( this ); - mContainer->clipEnable(); + mContainer->setClipType( ClipType::ContentBox ); mContainer->setFlags( UI_OWNS_CHILDS_POSITION ); mContainer->enableReportSizeChangeToChilds(); diff --git a/src/eepp/ui/uitableview.cpp b/src/eepp/ui/uitableview.cpp index dd8c6f75d..722004d0b 100644 --- a/src/eepp/ui/uitableview.cpp +++ b/src/eepp/ui/uitableview.cpp @@ -11,7 +11,7 @@ UITableView* UITableView::New() { } UITableView::UITableView( const std::string& tag ) : UIAbstractTableView( tag ) { - clipEnable(); + setClipType( ClipType::ContentBox ); } UITableView::UITableView() : UITableView( "tableview" ) {} diff --git a/src/eepp/ui/uitabwidget.cpp b/src/eepp/ui/uitabwidget.cpp index fb71fae9c..890b1bd19 100644 --- a/src/eepp/ui/uitabwidget.cpp +++ b/src/eepp/ui/uitabwidget.cpp @@ -25,7 +25,7 @@ UITabWidget::UITabWidget() : mAllowDragAndDropTabs( false ), mTabVerticalDragResistance( PixelDensity::dpToPx( 64 ) ) { setHorizontalAlign( UI_HALIGN_CENTER ); - clipEnable(); + setClipType( ClipType::ContentBox ); mTabBar = UIWidget::NewWithTag( "tabwidget::tabbar" ); mTabBar->setPixelsSize( mSize.getWidth(), mStyleConfig.TabHeight ) diff --git a/src/eepp/ui/uitextedit.cpp b/src/eepp/ui/uitextedit.cpp index 8b3980806..3985b3af2 100644 --- a/src/eepp/ui/uitextedit.cpp +++ b/src/eepp/ui/uitextedit.cpp @@ -15,7 +15,7 @@ UITextEdit* UITextEdit::New() { UITextEdit::UITextEdit() : UICodeEditor( "textedit", true, true ) { setFlags( UI_AUTO_PADDING ); - clipEnable(); + setClipType( ClipType::ContentBox ); mFont = NULL; mHorizontalScrollBarEnabled = true; diff --git a/src/eepp/ui/uitextinput.cpp b/src/eepp/ui/uitextinput.cpp index b8322a7d6..6d04f38a5 100644 --- a/src/eepp/ui/uitextinput.cpp +++ b/src/eepp/ui/uitextinput.cpp @@ -59,7 +59,7 @@ UITextInput::UITextInput( const std::string& tag ) : subscribeScheduledUpdate(); setFlags( UI_AUTO_PADDING | UI_AUTO_SIZE | UI_TEXT_SELECTION_ENABLED ); - clipEnable(); + setClipType( ClipType::ContentBox ); mDoc.registerClient( this ); registerCommands(); @@ -133,11 +133,12 @@ void UITextInput::draw() { if ( mTextCache->getTextWidth() ) { drawSelection( mTextCache ); - if ( isClipped() ) { - clipSmartEnable( mScreenPos.x + mPaddingPx.Left, mScreenPos.y + mPaddingPx.Top, - mSize.getWidth() - mPaddingPx.Left - mPaddingPx.Right, - mSize.getHeight() - mPaddingPx.Top - mPaddingPx.Bottom ); - } + // if ( getClipType() == ClipType::PaddingBox ) { + // clipSmartEnable( mScreenPos.x + mPaddingPx.Left, mScreenPos.y + + //mPaddingPx.Top, mSize.getWidth() - mPaddingPx.Left - mPaddingPx.Right, + // mSize.getHeight() - mPaddingPx.Top - mPaddingPx.Bottom + //); + // } mTextCache->setAlign( getFlags() ); mTextCache->draw( (Float)mScreenPosi.x + (int)mRealAlignOffset.x + (int)mPaddingPx.Left, @@ -145,24 +146,25 @@ void UITextInput::draw() { (int)mPaddingPx.Top, Vector2f::One, 0.f, getBlendMode() ); - if ( isClipped() ) { - clipSmartDisable(); - } + // if ( getClipType() == ClipType::PaddingBox ) { + // clipSmartDisable(); + // } } else if ( !mHintCache->getString().empty() ) { - if ( isClipped() ) { - clipSmartEnable( mScreenPos.x + mPaddingPx.Left, mScreenPos.y + mPaddingPx.Top, - mSize.getWidth() - mPaddingPx.Left - mPaddingPx.Right, - mSize.getHeight() - mPaddingPx.Top - mPaddingPx.Bottom ); - } + // if ( getClipType() == ClipType::PaddingBox ) { + // clipSmartEnable( mScreenPos.x + mPaddingPx.Left, mScreenPos.y + + //mPaddingPx.Top, mSize.getWidth() - mPaddingPx.Left - mPaddingPx.Right, + // mSize.getHeight() - mPaddingPx.Top - mPaddingPx.Bottom + //); + // } mHintCache->draw( (Float)mScreenPosi.x + (int)mRealAlignOffset.x + (int)mPaddingPx.Left, mFontLineCenter + (Float)mScreenPosi.y + (int)mRealAlignOffset.y + (int)mPaddingPx.Top, Vector2f::One, 0.f, getBlendMode() ); - if ( isClipped() ) { - clipSmartDisable(); - } + // if ( getClipType() == ClipType::PaddingBox ) { + // clipSmartDisable(); + // } } } diff --git a/src/eepp/ui/uitextview.cpp b/src/eepp/ui/uitextview.cpp index 937bd186c..b36f266f9 100644 --- a/src/eepp/ui/uitextview.cpp +++ b/src/eepp/ui/uitextview.cpp @@ -291,7 +291,7 @@ void UITextView::onAutoSize() { Float oldW = totW; totW = eemin( totW, getMaxSize().getWidth() ); if ( oldW != totW ) - clipEnable(); + setClipType( ClipType::ContentBox ); } setInternalPixelsWidth( totW ); } @@ -302,7 +302,7 @@ void UITextView::onAutoSize() { Float oldH = totH; totH = eemin( totH, getMaxSize().getHeight() ); if ( oldH != totH ) - clipEnable(); + setClipType( ClipType::ContentBox ); } setInternalPixelsHeight( totH ); } diff --git a/src/eepp/ui/uitreeview.cpp b/src/eepp/ui/uitreeview.cpp index 2ab473aad..897ea504b 100644 --- a/src/eepp/ui/uitreeview.cpp +++ b/src/eepp/ui/uitreeview.cpp @@ -17,7 +17,7 @@ UITreeView::UITreeView() : UIAbstractTableView( "treeview" ), mIndentWidth( PixelDensity::dpToPx( 12 ) ), mExpanderIconSize( PixelDensity::dpToPxI( 12 ) ) { - clipEnable(); + setClipType( ClipType::ContentBox ); mExpandIcon = getUISceneNode()->findIcon( "tree-expanded" ); mContractIcon = getUISceneNode()->findIcon( "tree-contracted" ); } @@ -144,7 +144,7 @@ UIWidget* UITreeView::setupCell( UITableCell* widget, UIWidget* rowWidget, const ModelIndex& index ) { widget->setParent( rowWidget ); widget->unsetFlags( UI_AUTO_SIZE ); - widget->clipEnable(); + widget->setClipType( ClipType::ContentBox ); widget->setLayoutSizePolicy( SizePolicy::Fixed, SizePolicy::Fixed ); widget->setTextAlign( UI_HALIGN_LEFT ); widget->setCurIndex( index ); diff --git a/src/eepp/ui/uiviewpager.cpp b/src/eepp/ui/uiviewpager.cpp index 79f79894b..69b0cc4aa 100644 --- a/src/eepp/ui/uiviewpager.cpp +++ b/src/eepp/ui/uiviewpager.cpp @@ -33,7 +33,7 @@ UIViewPager::UIViewPager() : mContainer = UIWidget::New(); mContainer->setParent( this ); mContainer->setFlags( UI_OWNS_CHILDS_POSITION ); - clipEnable(); + setClipType( ClipType::ContentBox ); } UIViewPager::~UIViewPager() { diff --git a/src/eepp/ui/uiwidget.cpp b/src/eepp/ui/uiwidget.cpp index bf22065ad..c5dbaf522 100644 --- a/src/eepp/ui/uiwidget.cpp +++ b/src/eepp/ui/uiwidget.cpp @@ -605,10 +605,6 @@ void UIWidget::notifyLayoutAttrChangeParent() { } void UIWidget::updateAnchors( const Vector2f& sizeChange ) { - if ( hasClass( "doc_alert" ) ) { - clipDisable(); - } - if ( !( mFlags & ( UI_ANCHOR_LEFT | UI_ANCHOR_TOP | UI_ANCHOR_RIGHT | UI_ANCHOR_BOTTOM ) ) ) return; @@ -1362,7 +1358,7 @@ std::string UIWidget::getPropertyString( const PropertyDefinition* propertyDef, case PropertyId::LayoutHeight: return getLayoutHeightPolicyString(); case PropertyId::Clip: - return isClipped() ? "true" : "false"; + return UIClip::toString( mClip.getClipType() ); case PropertyId::BackgroundPositionX: return getBackground()->getLayer( propertyIndex )->getPositionX(); case PropertyId::BackgroundPositionY: @@ -1569,7 +1565,7 @@ bool UIWidget::applyProperty( const StyleSheetProperty& attribute ) { setFlags( UI_AUTO_SIZE ); notifyLayoutAttrChange(); } else if ( "clip" == cur ) { - clipEnable(); + setClipType( ClipType::ContentBox ); } else if ( "multiselect" == cur ) { setFlags( UI_MULTI_SELECT ); } else if ( "auto_padding" == cur || "autopadding" == cur ) { @@ -1706,10 +1702,7 @@ bool UIWidget::applyProperty( const StyleSheetProperty& attribute ) { break; } case PropertyId::Clip: - if ( attribute.asBool() ) - clipEnable(); - else - clipDisable(); + setClipType( UIClip::fromString( attribute.asString() ) ); break; case PropertyId::Rotation: setRotation( attribute.asFloat() ); diff --git a/src/eepp/ui/uiwidgettable.cpp b/src/eepp/ui/uiwidgettable.cpp index 4a7399776..23d894c41 100644 --- a/src/eepp/ui/uiwidgettable.cpp +++ b/src/eepp/ui/uiwidgettable.cpp @@ -619,9 +619,9 @@ UIWidgetTable* UIWidgetTable::setSmoothScroll( bool smoothScroll ) { mSmoothScroll = smoothScroll; if ( mSmoothScroll ) { - mContainer->clipEnable(); + mContainer->setClipType( ClipType::ContentBox ); } else { - mContainer->clipDisable(); + mContainer->setClipType( ClipType::None ); } return this; diff --git a/src/eepp/ui/uiwindow.cpp b/src/eepp/ui/uiwindow.cpp index 7de2b793d..ed468952c 100644 --- a/src/eepp/ui/uiwindow.cpp +++ b/src/eepp/ui/uiwindow.cpp @@ -72,10 +72,12 @@ UIWindow::UIWindow( UIWindow::WindowBaseContainerType type, const StyleConfig& w break; } + setId( "window" ); + mContainer->setLayoutSizePolicy( SizePolicy::Fixed, SizePolicy::Fixed ); mContainer->writeNodeFlag( NODE_FLAG_OWNED_BY_NODE, 1 ); mContainer->setParent( this ); - mContainer->clipEnable(); + mContainer->setClipType( ClipType::ContentBox ); mContainer->enableReportSizeChangeToChilds(); mContainer->addEventListener( Event::OnPositionChange, cb::Make1( this, &UIWindow::onContainerPositionChange ) ); @@ -1173,7 +1175,7 @@ void UIWindow::setTitle( const String& text ) { mTitle->setHorizontalAlign( getHorizontalAlign() ); mTitle->setVerticalAlign( getVerticalAlign() ); mTitle->setEnabled( false ); - mTitle->clipEnable(); + mTitle->setClipType( ClipType::ContentBox ); mTitle->setVisible( !( mStyleConfig.WinFlags & UI_WIN_NO_DECORATION ) ); } @@ -1233,7 +1235,11 @@ Uint32 UIWindow::onMouseDoubleClick( const Vector2i&, const Uint32& Flags ) { void UIWindow::nodeDraw() { if ( mVisible && 0 != mAlpha ) { - updateScreenPos(); + if ( mNodeFlags & NODE_FLAG_POSITION_DIRTY ) + updateScreenPos(); + + if ( mNodeFlags & NODE_FLAG_POLYGON_DIRTY ) + updateWorldPolygon(); preDraw(); @@ -1248,17 +1254,47 @@ void UIWindow::nodeDraw() { matrixSet(); + smartClipStart( ClipType::BorderBox ); + if ( !ownsFrameBuffer() || ( NULL != mSceneNode && !mSceneNode->usesInvalidation() ) || invalidated() ) { - clipStart(); + smartClipStart( ClipType::ContentBox ); + + if ( 0.f != mAlpha ) { + drawBackground(); + + drawSkin(); + } + + smartClipStart( ClipType::PaddingBox ); draw(); drawChilds(); - clipEnd(); + smartClipEnd( ClipType::PaddingBox ); + + if ( 0.f != mAlpha ) + drawForeground(); + + smartClipEnd( ClipType::ContentBox ); } + drawBorder(); + + if ( mNodeFlags & NODE_FLAG_DROPPABLE_HOVERING ) + drawDroppableHovering(); + + drawHighlightFocus(); + + drawOverNode(); + + updateDebugData(); + + drawBox(); + + smartClipEnd( ClipType::BorderBox ); + matrixUnset(); if ( !clips.empty() ) diff --git a/src/eepp/window/input.cpp b/src/eepp/window/input.cpp index 8e3682a68..2040637dd 100644 --- a/src/eepp/window/input.cpp +++ b/src/eepp/window/input.cpp @@ -208,10 +208,6 @@ void Input::processEvent( InputEvent* Event ) { break; } case InputEvent::Quit: { - if ( Engine::isEngineRunning() ) { - Engine::instance()->forEachWindow( - [&]( EE::Window::Window* win ) { win->onCloseRequest(); } ); - } break; } } diff --git a/src/tools/ecode/appconfig.cpp b/src/tools/ecode/appconfig.cpp index a93610f67..064043edb 100644 --- a/src/tools/ecode/appconfig.cpp +++ b/src/tools/ecode/appconfig.cpp @@ -331,8 +331,8 @@ static void loadDocuments( UICodeEditorSplitter* editorSplitter, std::shared_ptr }, curTabWidget ); } else if ( file["type"] == "terminal" ) { - app->createNewTerminal( file.contains( "title" ) ? file["title"] : "", - curTabWidget ); + app->getTerminalManager()->createNewTerminal( + file.contains( "title" ) ? file["title"] : "", curTabWidget ); if ( curTabWidget->getTabCount() == totalToLoad ) curTabWidget->setTabSelected( diff --git a/src/tools/ecode/ecode.cpp b/src/tools/ecode/ecode.cpp index 4a378f1ef..1e5dc5041 100644 --- a/src/tools/ecode/ecode.cpp +++ b/src/tools/ecode/ecode.cpp @@ -26,6 +26,7 @@ bool App::onCloseRequestCallback( EE::Window::Window* ) { msgBox->addEventListener( Event::MsgBoxConfirmClick, [&]( const Event* ) { if ( !mCurrentProject.empty() ) mConfig.saveProject( mCurrentProject, mSplitter, mConfigPath, mProjectDocConfig ); + saveConfig(); mWindow->close(); } ); msgBox->addEventListener( Event::OnClose, [&]( const Event* ) { msgBox = nullptr; } ); @@ -37,6 +38,7 @@ bool App::onCloseRequestCallback( EE::Window::Window* ) { } else { if ( !mCurrentProject.empty() ) mConfig.saveProject( mCurrentProject, mSplitter, mConfigPath, mProjectDocConfig ); + saveConfig(); return true; } } @@ -334,8 +336,9 @@ void App::loadConfig() { FileSystem::dirAddSlashAtEnd( mConfigPath ); mPluginsPath = mConfigPath + "plugins"; mColorSchemesPath = mConfigPath + "colorschemes"; - mTerminalColorSchemesPath = - mConfigPath + "terminal" + FileSystem::getOSSlash() + "colorschemes"; + mTerminalManager = std::make_unique( this ); + mTerminalManager->setTerminalColorSchemesPath( mConfigPath + "terminal" + + FileSystem::getOSSlash() + "colorschemes" ); if ( !FileSystem::fileExists( mPluginsPath ) ) FileSystem::makeDir( mPluginsPath ); FileSystem::dirAddSlashAtEnd( mPluginsPath ); @@ -415,7 +418,7 @@ void App::mainLoop() { SceneManager::instance()->draw(); mWindow->display(); if ( firstFrame ) { - Log::info( "First frame took: %.2fms", globalClock.getElapsed().asMilliseconds() ); + Log::info( "First frame took: %.2f ms", globalClock.getElapsed().asMilliseconds() ); firstFrame = false; } } else { @@ -468,7 +471,6 @@ App::~App() { delete mFileWatcher; if ( mFileSystemListener ) delete mFileSystemListener; - saveConfig(); eeSAFE_DELETE( mSplitter ); eeSAFE_DELETE( mAutoCompletePlugin ); eeSAFE_DELETE( mLinterPlugin ); @@ -1908,19 +1910,10 @@ const CodeEditorConfig& App::getCodeEditorConfig() const { return mConfig.editor; } -std::map App::getTerminalKeybindings() { - return { - { { KEY_T, KeyMod::getDefaultModifier() | KEYMOD_SHIFT }, "create-new-terminal" }, - { { KEY_E, KEYMOD_CTRL | KEYMOD_LALT | KEYMOD_SHIFT }, - UITerminal::getExclusiveModeToggleCommandName() }, - { { KEY_S, KEYMOD_LALT | KEYMOD_CTRL }, "terminal-rename" }, - }; -} - std::map App::getDefaultKeybindings() { auto bindings = UICodeEditorSplitter::getDefaultKeybindings(); auto local = getLocalKeybindings(); - auto app = getTerminalKeybindings(); + auto app = TerminalManager::getTerminalKeybindings(); local.insert( bindings.begin(), bindings.end() ); local.insert( app.begin(), app.end() ); return local; @@ -2136,248 +2129,10 @@ void App::fullscreenToggle() { ->setActive( !mWindow->isWindowed() ); } -void App::loadTerminalColorSchemes() { - auto colorSchemes = - TerminalColorScheme::loadFromFile( mResPath + "colorschemes/terminalcolorschemes.conf" ); - if ( colorSchemes.empty() ) - colorSchemes.emplace_back( TerminalColorScheme::getDefault() ); - if ( FileSystem::isDirectory( mTerminalColorSchemesPath ) ) { - auto colorSchemesFiles = FileSystem::filesGetInPath( mTerminalColorSchemesPath ); - for ( auto& file : colorSchemesFiles ) { - auto colorSchemesInFile = TerminalColorScheme::loadFromFile( file ); - for ( auto& coloScheme : colorSchemesInFile ) - colorSchemes.emplace_back( coloScheme ); - } - } - for ( const auto& colorScheme : colorSchemes ) - mTerminalColorSchemes.insert( { colorScheme.getName(), colorScheme } ); - mTerminalCurrentColorScheme = mConfig.term.colorScheme; - if ( mTerminalColorSchemes.find( mTerminalCurrentColorScheme ) == mTerminalColorSchemes.end() ) - mTerminalCurrentColorScheme = mTerminalColorSchemes.begin()->first; -} - void App::showGlobalSearch() { mGlobalSearchController->showGlobalSearch(); } -UITerminal* App::createNewTerminal( const std::string& title, UITabWidget* inTabWidget, - const std::string& workingDir ) { -#if EE_PLATFORM == EE_PLATFORM_EMSCRIPTEN - UIMessageBox* msgBox = UIMessageBox::New( - UIMessageBox::OK, - i18n( "feature_not_supported_in_emscripten", - "This feature is only supported in the desktop version of ecode." ) ); - msgBox->showWhenReady(); - return nullptr; -#else - if ( mTerminalColorSchemes.empty() ) - loadTerminalColorSchemes(); - UITabWidget* tabWidget = nullptr; - - if ( !inTabWidget ) { - UIWidget* curWidget = mSplitter->getCurWidget(); - if ( !curWidget ) - return nullptr; - tabWidget = mSplitter->tabWidgetFromWidget( curWidget ); - } else { - tabWidget = inTabWidget; - } - - if ( !tabWidget ) { - if ( !mSplitter->getTabWidgets().empty() ) { - tabWidget = mSplitter->getTabWidgets()[0]; - } else { - return nullptr; - } - } - UITerminal* term = UITerminal::New( - mFontMonoNerdFont ? mFontMonoNerdFont : mFontMono, - mConfig.term.fontSize.asPixels( 0, Sizef(), mDisplayDPI ), Sizef( 16, 16 ), "", {}, - !workingDir.empty() ? workingDir : ( !mCurrentProject.empty() ? mCurrentProject : "" ) ); - auto ret = mSplitter->createWidgetInTabWidget( - tabWidget, term, title.empty() ? i18n( "shell", "Shell" ).toUtf8() : title, true ); - mSplitter->removeUnusedTab( tabWidget ); - ret.first->setIcon( findIcon( "filetype-bash" ) ); - term->setTitle( title ); - auto csIt = mTerminalColorSchemes.find( mTerminalCurrentColorScheme ); - term->setColorScheme( csIt != mTerminalColorSchemes.end() - ? mTerminalColorSchemes.at( mTerminalCurrentColorScheme ) - : TerminalColorScheme::getDefault() ); - term->addEventListener( Event::OnTitleChange, [&]( const Event* event ) { - if ( event->getNode() != mSplitter->getCurWidget() ) - return; - setAppTitle( event->getNode()->asType()->getTitle() ); - } ); - term->addKeyBinds( getLocalKeybindings() ); - term->addKeyBinds( UICodeEditorSplitter::getLocalDefaultKeybindings() ); - term->addKeyBinds( getTerminalKeybindings() ); - // Remove the keybinds that are problematic for a terminal - term->getKeyBindings().removeCommandsKeybind( - { "open-file", "download-file-web", "open-folder", "debug-draw-highlight-toggle", - "debug-draw-boxes-toggle", "debug-draw-debug-data", "debug-widget-tree-view", - "open-locatebar", "open-global-search", "menu-toggle", "console-toggle", "go-to-line" } ); - term->setCommand( "switch-side-panel", [&] { switchSidePanel(); } ); - term->setCommand( "fullscreen-toggle", [&]() { fullscreenToggle(); } ); - for ( int i = 1; i <= 10; i++ ) - term->setCommand( String::format( "switch-to-tab-%d", i ), - [&, i] { mSplitter->switchToTab( i - 1 ); } ); - term->setCommand( "switch-to-first-tab", [&] { - UITabWidget* tabWidget = mSplitter->tabWidgetFromWidget( mSplitter->getCurWidget() ); - if ( tabWidget && tabWidget->getTabCount() ) { - mSplitter->switchToTab( 0 ); - } - } ); - term->setCommand( "switch-to-last-tab", [&] { - UITabWidget* tabWidget = mSplitter->tabWidgetFromWidget( mSplitter->getCurWidget() ); - if ( tabWidget && tabWidget->getTabCount() ) { - mSplitter->switchToTab( tabWidget->getTabCount() - 1 ); - } - } ); - term->setCommand( "switch-to-previous-split", - [&] { mSplitter->switchPreviousSplit( mSplitter->getCurWidget() ); } ); - term->setCommand( "switch-to-next-split", - [&] { mSplitter->switchNextSplit( mSplitter->getCurWidget() ); } ); - term->setCommand( "close-tab", [&] { mSplitter->tryTabClose( mSplitter->getCurWidget() ); } ); - term->setCommand( "create-new", [&] { - auto d = mSplitter->createCodeEditorInTabWidget( - mSplitter->tabWidgetFromWidget( mSplitter->getCurWidget() ) ); - d.first->getTabWidget()->setTabSelected( d.first ); - } ); - term->setCommand( "next-tab", [&] { - UITabWidget* tabWidget = mSplitter->tabWidgetFromWidget( mSplitter->getCurWidget() ); - if ( tabWidget && tabWidget->getTabCount() > 1 ) { - UITab* tab = (UITab*)mSplitter->getCurWidget()->getData(); - Uint32 tabIndex = tabWidget->getTabIndex( tab ); - mSplitter->switchToTab( ( tabIndex + 1 ) % tabWidget->getTabCount() ); - } - } ); - term->setCommand( "previous-tab", [&] { - UITabWidget* tabWidget = mSplitter->tabWidgetFromWidget( mSplitter->getCurWidget() ); - if ( tabWidget && tabWidget->getTabCount() > 1 ) { - UITab* tab = (UITab*)mSplitter->getCurWidget()->getData(); - Uint32 tabIndex = tabWidget->getTabIndex( tab ); - Int32 newTabIndex = (Int32)tabIndex - 1; - mSplitter->switchToTab( newTabIndex < 0 ? tabWidget->getTabCount() - newTabIndex - : newTabIndex ); - } - } ); - term->setCommand( "split-right", [&] { - mSplitter->split( UICodeEditorSplitter::SplitDirection::Right, mSplitter->getCurWidget(), - mSplitter->curEditorExistsAndFocused() ); - } ); - term->setCommand( "split-bottom", [&] { - mSplitter->split( UICodeEditorSplitter::SplitDirection::Bottom, mSplitter->getCurWidget(), - mSplitter->curEditorExistsAndFocused() ); - } ); - term->setCommand( "split-left", [&] { - mSplitter->split( UICodeEditorSplitter::SplitDirection::Left, mSplitter->getCurWidget(), - mSplitter->curEditorExistsAndFocused() ); - } ); - term->setCommand( "split-top", [&] { - mSplitter->split( UICodeEditorSplitter::SplitDirection::Top, mSplitter->getCurWidget(), - mSplitter->curEditorExistsAndFocused() ); - } ); - term->setCommand( "split-swap", [&] { - if ( UISplitter* splitter = mSplitter->splitterFromWidget( mSplitter->getCurWidget() ) ) - splitter->swap(); - } ); - term->setCommand( "terminal-split-right", [&, term] { - mSplitter->split( UICodeEditorSplitter::SplitDirection::Right, mSplitter->getCurWidget(), - false ); - term->execute( "create-new-terminal" ); - } ); - term->setCommand( "terminal-split-bottom", [&, term] { - mSplitter->split( UICodeEditorSplitter::SplitDirection::Bottom, mSplitter->getCurWidget(), - false ); - term->execute( "create-new-terminal" ); - } ); - term->setCommand( "terminal-split-left", [&, term] { - mSplitter->split( UICodeEditorSplitter::SplitDirection::Left, mSplitter->getCurWidget(), - false ); - term->execute( "create-new-terminal" ); - } ); - term->setCommand( "terminal-split-top", [&, term] { - mSplitter->split( UICodeEditorSplitter::SplitDirection::Top, mSplitter->getCurWidget(), - false ); - term->execute( "create-new-terminal" ); - } ); - term->setCommand( "split-swap", [&] { - if ( UISplitter* splitter = mSplitter->splitterFromWidget( mSplitter->getCurWidget() ) ) - splitter->swap(); - } ); - term->setCommand( UITerminal::getExclusiveModeToggleCommandName(), - [term] { term->setExclusiveMode( !term->getExclusiveMode() ); } ); - term->setCommand( "create-new-terminal", [&] { createNewTerminal(); } ); - term->setCommand( "terminal-rename", [&, term] { - UIMessageBox* msgBox = UIMessageBox::New( - UIMessageBox::INPUT, i18n( "new_terminal_name", "New terminal name:" ) ); - msgBox->setTitle( "ecode" ); - msgBox->getTextInput()->setHint( i18n( "any_name", "Any name..." ) ); - msgBox->setCloseShortcut( { KEY_ESCAPE, KEYMOD_NONE } ); - msgBox->showWhenReady(); - msgBox->addEventListener( Event::MsgBoxConfirmClick, [&, msgBox, term]( const Event* ) { - std::string title( msgBox->getTextInput()->getText().toUtf8() ); - term->setTitle( title ); - msgBox->close(); - term->setFocus(); - } ); - } ); - term->setCommand( "move-panel-left", [&] { panelPosition( PanelPosition::Left ); } ); - term->setCommand( "move-panel-right", [&] { panelPosition( PanelPosition::Right ); } ); - term->setCommand( "close-app", [&] { closeApp(); } ); - term->setCommand( "open-file", [&] { openFileDialog(); } ); - term->setCommand( "open-folder", [&] { openFolderDialog(); } ); - term->setCommand( "console-toggle", [&] { consoleToggle(); } ); - term->setCommand( "menu-toggle", [&] { toggleSettingsMenu(); } ); - term->setCommand( "open-global-search", [&] { showGlobalSearch(); } ); - term->setCommand( "open-locatebar", [&] { mFileLocator->showLocateBar(); } ); - term->setCommand( "download-file-web", [&] { downloadFileWebDialog(); } ); - - term->setCommand( "switch-to-previous-colorscheme", [&] { - auto it = mTerminalColorSchemes.find( mTerminalCurrentColorScheme ); - auto prev = std::prev( it, 1 ); - if ( prev != mTerminalColorSchemes.end() ) { - setTerminalColorScheme( prev->first ); - } else { - setTerminalColorScheme( mTerminalColorSchemes.rbegin()->first ); - } - } ); - term->setCommand( "switch-to-next-colorscheme", [&] { - auto it = mTerminalColorSchemes.find( mTerminalCurrentColorScheme ); - setTerminalColorScheme( ++it != mTerminalColorSchemes.end() - ? it->first - : mTerminalColorSchemes.begin()->first ); - } ); - // debug-draw-highlight-toggle - // debug-draw-boxes-toggle - // debug-draw-debug-data - // debug-widget-tree-view - term->setFocus(); - return term; -#endif -} - -void App::applyTerminalColorScheme( const TerminalColorScheme& colorScheme ) { - mSplitter->forEachWidget( [colorScheme]( UIWidget* widget ) { - if ( widget->isType( UI_TYPE_TERMINAL ) ) - widget->asType()->setColorScheme( colorScheme ); - } ); -} - -void App::setTerminalColorScheme( const std::string& name ) { - if ( name != mTerminalCurrentColorScheme ) { - mTerminalCurrentColorScheme = name; - mConfig.term.colorScheme = name; - auto csIt = mTerminalColorSchemes.find( mTerminalCurrentColorScheme ); - applyTerminalColorScheme( csIt != mTerminalColorSchemes.end() - ? mTerminalColorSchemes.at( mTerminalCurrentColorScheme ) - : TerminalColorScheme::getDefault() ); - mNotificationCenter->addNotification( String::format( - i18n( "terminal_color_scheme_set", "Terminal color scheme: %s" ).toUtf8().c_str(), - mTerminalCurrentColorScheme.c_str() ) ); - } -} - void App::showFindView() { mDocSearchController->showFindView(); } @@ -2474,7 +2229,7 @@ void App::onCodeEditorCreated( UICodeEditor* editor, TextDocument& doc ) { doc.setCommand( "download-file-web", [&] { downloadFileWebDialog(); } ); doc.setCommand( "move-panel-left", [&] { panelPosition( PanelPosition::Left ); } ); doc.setCommand( "move-panel-right", [&] { panelPosition( PanelPosition::Right ); } ); - doc.setCommand( "create-new-terminal", [&] { createNewTerminal(); } ); + doc.setCommand( "create-new-terminal", [&] { mTerminalManager->createNewTerminal(); } ); doc.setCommand( "terminal-split-right", [&] { mSplitter->split( UICodeEditorSplitter::SplitDirection::Right, mSplitter->getCurWidget(), false ); @@ -2708,6 +2463,7 @@ void App::toggleSettingsMenu() { } void App::createSettingsMenu() { + Clock clock; mSettingsMenu = UIPopUpMenu::New(); mSettingsMenu->setId( "settings_menu" ); mSettingsMenu @@ -2775,6 +2531,14 @@ void App::createSettingsMenu() { colorSchemeMenu->setSubMenu( newMenu ); } } ); +#if EE_PLATFORM != EE_PLATFORM_EMSCRIPTEN + UIMenuSubMenu* termColorSchemeMenu = + mSettingsMenu->addSubMenu( i18n( "terminal_color_scheme", "Terminal Color Scheme" ), + nullptr, mTerminalManager->createColorSchemeMenu() ); + colorSchemeMenu->addEventListener( Event::OnMenuShow, [&, termColorSchemeMenu]( const Event* ) { + mTerminalManager->updateMenuColorScheme( termColorSchemeMenu ); + } ); +#endif mSettingsMenu->addSubMenu( i18n( "document", "Document" ), nullptr, createDocumentMenu() ) ->setId( "doc-menu" ); mSettingsMenu->addSubMenu( i18n( "edit", "Edit" ), nullptr, createEditMenu() ); @@ -2804,10 +2568,11 @@ void App::createSettingsMenu() { } ); updateRecentFiles(); updateRecentFolders(); + Log::info( "Settings Menu took: %.2f ms", clock.getElapsedTime().asMilliseconds() ); } void App::updateColorSchemeMenu() { - for ( UIPopUpMenu* menu : mFileTypeMenues ) { + for ( UIPopUpMenu* menu : mColorSchemeMenues ) { for ( size_t i = 0; i < menu->getCount(); i++ ) { UIWidget* widget = menu->getItem( i ); if ( widget->isType( UI_TYPE_MENURADIOBUTTON ) ) { @@ -3068,7 +2833,7 @@ void App::createProjectTreeMenu() { } else if ( "open_folder" == id ) { Engine::instance()->openURI( mCurrentProject ); } else if ( "execute_dir_in_terminal" == id ) { - createNewTerminal( "", nullptr, mCurrentProject ); + mTerminalManager->createNewTerminal( "", nullptr, mCurrentProject ); } else if ( "show_hidden_files" == id ) { toggleHiddenFiles(); } else if ( "collapse-all" == id ) { @@ -3246,12 +3011,13 @@ void App::createProjectTreeMenu( const FileInfo& file ) { } else if ( "show_hidden_files" == id ) { toggleHiddenFiles(); } else if ( "execute_in_terminal" == id ) { - UITerminal* term = createNewTerminal( "", nullptr, file.getDirectoryPath() ); + UITerminal* term = + mTerminalManager->createNewTerminal( "", nullptr, file.getDirectoryPath() ); if ( !term ) return; term->executeFile( file.getFilepath() ); } else if ( "execute_dir_in_terminal" == id ) { - createNewTerminal( "", nullptr, file.getDirectoryPath() ); + mTerminalManager->createNewTerminal( "", nullptr, file.getDirectoryPath() ); } else if ( "collapse-all" == id ) { mProjectTreeView->collapseAll(); } else if ( "expand-all" == id ) { @@ -3478,7 +3244,7 @@ void App::init( std::string file, const Float& pidelDensity, const std::string& ecode::Version::getCodename().c_str() ); if ( mWindow->isOpen() ) { - Log::info( "Window creation took: %.2fms", globalClock.getElapsedTime().asMilliseconds() ); + Log::info( "Window creation took: %.2f ms", globalClock.getElapsedTime().asMilliseconds() ); if ( mConfig.window.position != Vector2i( -1, -1 ) && mConfig.window.displayIndex < displayManager->getDisplayCount() ) { @@ -3882,10 +3648,13 @@ void App::init( std::string file, const Float& pidelDensity, const std::string& colorSchemes.emplace_back( coloScheme ); } } + + mTerminalManager->loadTerminalColorSchemes(); + mSplitter = UICodeEditorSplitter::New( this, mUISceneNode, colorSchemes, mInitColorScheme ); mSplitter->setHideTabBarOnSingleTab( mConfig.editor.hideTabBarOnSingleTab ); - Log::info( "Base UI took: %.2fms", globalClock.getElapsedTime().asMilliseconds() ); + Log::info( "Base UI took: %.2f ms", globalClock.getElapsedTime().asMilliseconds() ); #if EE_PLATFORM != EE_PLATFORM_EMSCRIPTEN mFileWatcher = new efsw::FileWatcher(); @@ -3920,7 +3689,7 @@ void App::init( std::string file, const Float& pidelDensity, const std::string& mConsole->setQuakeMode( true ); mConsole->setVisible( false ); - Log::info( "Complete UI took: %.2fms", globalClock.getElapsedTime().asMilliseconds() ); + Log::info( "Complete UI took: %.2f ms", globalClock.getElapsedTime().asMilliseconds() ); #if EE_PLATFORM == EE_PLATFORM_EMSCRIPTEN if ( file == "./this.program" ) @@ -3929,12 +3698,12 @@ void App::init( std::string file, const Float& pidelDensity, const std::string& if ( terminal && file.empty() ) { showSidePanel( false ); - createNewTerminal(); + mTerminalManager->createNewTerminal(); } else { initProjectTreeView( file ); } - Log::info( "Init ProjectTreeView took: %.2fms", + Log::info( "Init ProjectTreeView took: %.2f ms", globalClock.getElapsedTime().asMilliseconds() ); #if EE_PLATFORM == EE_PLATFORM_EMSCRIPTEN diff --git a/src/tools/ecode/ecode.hpp b/src/tools/ecode/ecode.hpp index 48adbc7ab..04c5486f5 100644 --- a/src/tools/ecode/ecode.hpp +++ b/src/tools/ecode/ecode.hpp @@ -9,6 +9,7 @@ #include "notificationcenter.hpp" #include "projectdirectorytree.hpp" #include "projectsearch.hpp" +#include "terminalmanager.hpp" #include "uitreeviewglobalsearch.hpp" #include "widgetcommandexecuter.hpp" #include @@ -84,12 +85,6 @@ class App : public UICodeEditorSplitter::Client { NotificationCenter* getNotificationCenter() const; - UITerminal* createNewTerminal( const std::string& title = "", - UITabWidget* inTabWidget = nullptr, - const std::string& workingDir = "" ); - - std::map getTerminalKeybindings(); - void fullscreenToggle(); void downloadFileWebDialog(); @@ -108,6 +103,40 @@ class App : public UICodeEditorSplitter::Client { void consoleToggle(); + String i18n( const std::string& key, const String& def ); + + UICodeEditorSplitter* getSplitter() const { return mSplitter; } + + TerminalConfig& termConfig() { return mConfig.term; } + + const std::string& resPath() const { return mResPath; } + + Font* getFontMonoNerdFont() const { return mFontMonoNerdFont; } + + Font* getFontMono() const { return mFontMono; } + + const Float& getDisplayDPI() const { return mDisplayDPI; } + + const std::string& getCurrentProject() const { return mCurrentProject; } + + Drawable* findIcon( const std::string& name ); + + std::map getDefaultKeybindings(); + + std::map getLocalKeybindings(); + + void switchSidePanel(); + + void panelPosition( const PanelPosition& panelPosition ); + + void toggleSettingsMenu(); + + FileLocator* getFileLocator() const { return mFileLocator.get(); } + + TerminalManager* getTerminalManager() const { return mTerminalManager.get(); } + + UISceneNode* uiSceneNode() const { return mUISceneNode; } + protected: EE::Window::Window* mWindow{ nullptr }; UISceneNode* mUISceneNode{ nullptr }; @@ -144,7 +173,6 @@ class App : public UICodeEditorSplitter::Client { std::string mConfigPath; std::string mPluginsPath; std::string mColorSchemesPath; - std::string mTerminalColorSchemesPath; std::string mKeybindingsPath; Float mDisplayDPI{ 96 }; std::string mResPath; @@ -175,12 +203,7 @@ class App : public UICodeEditorSplitter::Client { std::unique_ptr mNotificationCenter; std::string mLastFileFolder; ColorSchemePreference mUIColorScheme; - std::map mTerminalColorSchemes; - std::string mTerminalCurrentColorScheme; - - void applyTerminalColorScheme( const TerminalColorScheme& colorScheme ); - - void setTerminalColorScheme( const std::string& name ); + std::unique_ptr mTerminalManager; void saveAllProcess(); @@ -236,10 +259,6 @@ class App : public UICodeEditorSplitter::Client { UIMenu* createHelpMenu(); - Drawable* findIcon( const std::string& name ); - - String i18n( const std::string& key, const String& def ); - void updateProjectSettingsMenu(); UIMenu* createDocumentMenu(); @@ -248,10 +267,6 @@ class App : public UICodeEditorSplitter::Client { void loadKeybindings(); - std::map getDefaultKeybindings(); - - std::map getLocalKeybindings(); - void onDocumentStateChanged( UICodeEditor*, TextDocument& ); void onDocumentModified( UICodeEditor* editor, TextDocument& ); @@ -288,8 +303,6 @@ class App : public UICodeEditorSplitter::Client { void loadCurrentDirectory(); - void toggleSettingsMenu(); - FontTrueType* loadFont( const std::string& name, std::string fontPath, const std::string& fallback = "" ); @@ -297,10 +310,6 @@ class App : public UICodeEditorSplitter::Client { void closeEditors(); - void switchSidePanel(); - - void panelPosition( const PanelPosition& panelPosition ); - void removeFolderWatches(); void createDocAlert( UICodeEditor* editor ); @@ -318,8 +327,6 @@ class App : public UICodeEditorSplitter::Client { UIMessageBox* fileAlreadyExistsMsgBox(); void renameFile( const FileInfo& file ); - - void loadTerminalColorSchemes(); }; } // namespace ecode diff --git a/src/tools/ecode/terminalmanager.cpp b/src/tools/ecode/terminalmanager.cpp new file mode 100644 index 000000000..c05183010 --- /dev/null +++ b/src/tools/ecode/terminalmanager.cpp @@ -0,0 +1,343 @@ +#include "terminalmanager.hpp" +#include "ecode.hpp" +#include + +namespace ecode { + +TerminalManager::TerminalManager( App* app ) : mApp( app ) {} + +void TerminalManager::applyTerminalColorScheme( const TerminalColorScheme& colorScheme ) { + mApp->getSplitter()->forEachWidget( [colorScheme]( UIWidget* widget ) { + if ( widget->isType( UI_TYPE_TERMINAL ) ) + widget->asType()->setColorScheme( colorScheme ); + } ); +} + +void TerminalManager::setTerminalColorScheme( const std::string& name ) { + if ( name != mTerminalCurrentColorScheme ) { + mTerminalCurrentColorScheme = name; + mApp->termConfig().colorScheme = name; + auto csIt = mTerminalColorSchemes.find( mTerminalCurrentColorScheme ); + applyTerminalColorScheme( csIt != mTerminalColorSchemes.end() + ? mTerminalColorSchemes.at( mTerminalCurrentColorScheme ) + : TerminalColorScheme::getDefault() ); + mApp->getNotificationCenter()->addNotification( String::format( + mApp->i18n( "terminal_color_scheme_set", "Terminal color scheme: %s" ).toUtf8().c_str(), + mTerminalCurrentColorScheme.c_str() ) ); + + updateColorSchemeMenu(); + } +} + +void TerminalManager::loadTerminalColorSchemes() { + auto colorSchemes = TerminalColorScheme::loadFromFile( + mApp->resPath() + "colorschemes/terminalcolorschemes.conf" ); + if ( colorSchemes.empty() ) + colorSchemes.emplace_back( TerminalColorScheme::getDefault() ); + if ( FileSystem::isDirectory( mTerminalColorSchemesPath ) ) { + auto colorSchemesFiles = FileSystem::filesGetInPath( mTerminalColorSchemesPath ); + for ( auto& file : colorSchemesFiles ) { + auto colorSchemesInFile = TerminalColorScheme::loadFromFile( file ); + for ( auto& coloScheme : colorSchemesInFile ) + colorSchemes.emplace_back( coloScheme ); + } + } + for ( const auto& colorScheme : colorSchemes ) + mTerminalColorSchemes.insert( { colorScheme.getName(), colorScheme } ); + mTerminalCurrentColorScheme = mApp->termConfig().colorScheme; + if ( mTerminalColorSchemes.find( mTerminalCurrentColorScheme ) == mTerminalColorSchemes.end() ) + mTerminalCurrentColorScheme = mTerminalColorSchemes.begin()->first; +} + +std::map TerminalManager::getTerminalKeybindings() { + return { + { { KEY_T, KeyMod::getDefaultModifier() | KEYMOD_SHIFT }, "create-new-terminal" }, + { { KEY_E, KEYMOD_CTRL | KEYMOD_LALT | KEYMOD_SHIFT }, + UITerminal::getExclusiveModeToggleCommandName() }, + { { KEY_S, KEYMOD_LALT | KEYMOD_CTRL }, "terminal-rename" }, + }; +} + +const std::string& TerminalManager::getTerminalColorSchemesPath() const { + return mTerminalColorSchemesPath; +} + +void TerminalManager::setTerminalColorSchemesPath( const std::string& terminalColorSchemesPath ) { + mTerminalColorSchemesPath = terminalColorSchemesPath; +} + +void TerminalManager::updateColorSchemeMenu() { + for ( UIPopUpMenu* menu : mColorSchemeMenues ) { + for ( size_t i = 0; i < menu->getCount(); i++ ) { + UIWidget* widget = menu->getItem( i ); + if ( widget->isType( UI_TYPE_MENURADIOBUTTON ) ) { + auto* menuItem = widget->asType(); + menuItem->setActive( mTerminalCurrentColorScheme == menuItem->getText() ); + } + } + } +} + +UIMenu* TerminalManager::createColorSchemeMenu() { + mColorSchemeMenuesCreatedWithHeight = mApp->uiSceneNode()->getPixelsSize().getHeight(); + size_t maxItems = 19; + auto cb = [&]( const Event* event ) { + UIMenuItem* item = event->getNode()->asType(); + const String& name = item->getText(); + setTerminalColorScheme( name ); + }; + + UIPopUpMenu* menu = UIPopUpMenu::New(); + menu->addEventListener( Event::OnItemClicked, cb ); + mColorSchemeMenues.push_back( menu ); + size_t total = 0; + const auto& colorSchemes = mTerminalColorSchemes; + + for ( auto& colorScheme : colorSchemes ) { + menu->addRadioButton( colorScheme.first, mTerminalCurrentColorScheme == colorScheme.first ); + + if ( mColorSchemeMenues.size() == 1 && menu->getCount() == 1 ) { + menu->reloadStyle( true, true ); + Float height = menu->getPixelsSize().getHeight(); + Float tHeight = mApp->uiSceneNode()->getPixelsSize().getHeight(); + maxItems = (int)eeceil( tHeight / height ) - 2; + } + + total++; + + if ( menu->getCount() == maxItems && colorSchemes.size() - total > 1 ) { + UIPopUpMenu* newMenu = UIPopUpMenu::New(); + menu->addSubMenu( mApp->i18n( "more...", "More..." ), nullptr, newMenu ); + newMenu->addEventListener( Event::OnItemClicked, cb ); + mColorSchemeMenues.push_back( newMenu ); + menu = newMenu; + } + } + + return mColorSchemeMenues[0]; +} + +void TerminalManager::updateMenuColorScheme( UIMenuSubMenu* colorSchemeMenu ) { + if ( mColorSchemeMenuesCreatedWithHeight != mApp->uiSceneNode()->getPixelsSize().getHeight() ) { + for ( UIPopUpMenu* menu : mColorSchemeMenues ) + menu->close(); + mColorSchemeMenues.clear(); + auto* newMenu = createColorSchemeMenu(); + newMenu->reloadStyle( true, true ); + colorSchemeMenu->setSubMenu( newMenu ); + } +} + +UITerminal* TerminalManager::createNewTerminal( const std::string& title, UITabWidget* inTabWidget, + const std::string& workingDir ) { +#if EE_PLATFORM == EE_PLATFORM_EMSCRIPTEN + UIMessageBox* msgBox = UIMessageBox::New( + UIMessageBox::OK, + i18n( "feature_not_supported_in_emscripten", + "This feature is only supported in the desktop version of ecode." ) ); + msgBox->showWhenReady(); + return nullptr; +#else + UITabWidget* tabWidget = nullptr; + + if ( !inTabWidget ) { + UIWidget* curWidget = mApp->getSplitter()->getCurWidget(); + if ( !curWidget ) + return nullptr; + tabWidget = mApp->getSplitter()->tabWidgetFromWidget( curWidget ); + } else { + tabWidget = inTabWidget; + } + + if ( !tabWidget ) { + if ( !mApp->getSplitter()->getTabWidgets().empty() ) { + tabWidget = mApp->getSplitter()->getTabWidgets()[0]; + } else { + return nullptr; + } + } + UITerminal* term = UITerminal::New( + mApp->getFontMonoNerdFont() ? mApp->getFontMonoNerdFont() : mApp->getFontMono(), + mApp->termConfig().fontSize.asPixels( 0, Sizef(), mApp->getDisplayDPI() ), Sizef( 16, 16 ), + "", {}, + !workingDir.empty() + ? workingDir + : ( !mApp->getCurrentProject().empty() ? mApp->getCurrentProject() : "" ) ); + auto ret = mApp->getSplitter()->createWidgetInTabWidget( + tabWidget, term, title.empty() ? mApp->i18n( "shell", "Shell" ).toUtf8() : title, true ); + mApp->getSplitter()->removeUnusedTab( tabWidget ); + ret.first->setIcon( mApp->findIcon( "filetype-bash" ) ); + term->setTitle( title ); + auto csIt = mTerminalColorSchemes.find( mTerminalCurrentColorScheme ); + term->setColorScheme( csIt != mTerminalColorSchemes.end() + ? mTerminalColorSchemes.at( mTerminalCurrentColorScheme ) + : TerminalColorScheme::getDefault() ); + term->addEventListener( Event::OnTitleChange, [&]( const Event* event ) { + if ( event->getNode() != mApp->getSplitter()->getCurWidget() ) + return; + mApp->setAppTitle( event->getNode()->asType()->getTitle() ); + } ); + term->addKeyBinds( mApp->getLocalKeybindings() ); + term->addKeyBinds( UICodeEditorSplitter::getLocalDefaultKeybindings() ); + term->addKeyBinds( getTerminalKeybindings() ); + // Remove the keybinds that are problematic for a terminal + term->getKeyBindings().removeCommandsKeybind( + { "open-file", "download-file-web", "open-folder", "debug-draw-highlight-toggle", + "debug-draw-boxes-toggle", "debug-draw-debug-data", "debug-widget-tree-view", + "open-locatebar", "open-global-search", "menu-toggle", "console-toggle", "go-to-line" } ); + term->setCommand( "switch-side-panel", [&] { mApp->switchSidePanel(); } ); + term->setCommand( "fullscreen-toggle", [&]() { mApp->fullscreenToggle(); } ); + for ( int i = 1; i <= 10; i++ ) + term->setCommand( String::format( "switch-to-tab-%d", i ), + [&, i] { mApp->getSplitter()->switchToTab( i - 1 ); } ); + term->setCommand( "switch-to-first-tab", [&] { + UITabWidget* tabWidget = + mApp->getSplitter()->tabWidgetFromWidget( mApp->getSplitter()->getCurWidget() ); + if ( tabWidget && tabWidget->getTabCount() ) { + mApp->getSplitter()->switchToTab( 0 ); + } + } ); + term->setCommand( "switch-to-last-tab", [&] { + UITabWidget* tabWidget = + mApp->getSplitter()->tabWidgetFromWidget( mApp->getSplitter()->getCurWidget() ); + if ( tabWidget && tabWidget->getTabCount() ) { + mApp->getSplitter()->switchToTab( tabWidget->getTabCount() - 1 ); + } + } ); + term->setCommand( "switch-to-previous-split", [&] { + mApp->getSplitter()->switchPreviousSplit( mApp->getSplitter()->getCurWidget() ); + } ); + term->setCommand( "switch-to-next-split", [&] { + mApp->getSplitter()->switchNextSplit( mApp->getSplitter()->getCurWidget() ); + } ); + term->setCommand( "close-tab", [&] { + mApp->getSplitter()->tryTabClose( mApp->getSplitter()->getCurWidget() ); + } ); + term->setCommand( "create-new", [&] { + auto d = mApp->getSplitter()->createCodeEditorInTabWidget( + mApp->getSplitter()->tabWidgetFromWidget( mApp->getSplitter()->getCurWidget() ) ); + d.first->getTabWidget()->setTabSelected( d.first ); + } ); + term->setCommand( "next-tab", [&] { + UITabWidget* tabWidget = + mApp->getSplitter()->tabWidgetFromWidget( mApp->getSplitter()->getCurWidget() ); + if ( tabWidget && tabWidget->getTabCount() > 1 ) { + UITab* tab = (UITab*)mApp->getSplitter()->getCurWidget()->getData(); + Uint32 tabIndex = tabWidget->getTabIndex( tab ); + mApp->getSplitter()->switchToTab( ( tabIndex + 1 ) % tabWidget->getTabCount() ); + } + } ); + term->setCommand( "previous-tab", [&] { + UITabWidget* tabWidget = + mApp->getSplitter()->tabWidgetFromWidget( mApp->getSplitter()->getCurWidget() ); + if ( tabWidget && tabWidget->getTabCount() > 1 ) { + UITab* tab = (UITab*)mApp->getSplitter()->getCurWidget()->getData(); + Uint32 tabIndex = tabWidget->getTabIndex( tab ); + Int32 newTabIndex = (Int32)tabIndex - 1; + mApp->getSplitter()->switchToTab( + newTabIndex < 0 ? tabWidget->getTabCount() - newTabIndex : newTabIndex ); + } + } ); + term->setCommand( "split-right", [&] { + mApp->getSplitter()->split( UICodeEditorSplitter::SplitDirection::Right, + mApp->getSplitter()->getCurWidget(), + mApp->getSplitter()->curEditorExistsAndFocused() ); + } ); + term->setCommand( "split-bottom", [&] { + mApp->getSplitter()->split( UICodeEditorSplitter::SplitDirection::Bottom, + mApp->getSplitter()->getCurWidget(), + mApp->getSplitter()->curEditorExistsAndFocused() ); + } ); + term->setCommand( "split-left", [&] { + mApp->getSplitter()->split( UICodeEditorSplitter::SplitDirection::Left, + mApp->getSplitter()->getCurWidget(), + mApp->getSplitter()->curEditorExistsAndFocused() ); + } ); + term->setCommand( "split-top", [&] { + mApp->getSplitter()->split( UICodeEditorSplitter::SplitDirection::Top, + mApp->getSplitter()->getCurWidget(), + mApp->getSplitter()->curEditorExistsAndFocused() ); + } ); + term->setCommand( "split-swap", [&] { + if ( UISplitter* splitter = + mApp->getSplitter()->splitterFromWidget( mApp->getSplitter()->getCurWidget() ) ) + splitter->swap(); + } ); + term->setCommand( "terminal-split-right", [&, term] { + mApp->getSplitter()->split( UICodeEditorSplitter::SplitDirection::Right, + mApp->getSplitter()->getCurWidget(), false ); + term->execute( "create-new-terminal" ); + } ); + term->setCommand( "terminal-split-bottom", [&, term] { + mApp->getSplitter()->split( UICodeEditorSplitter::SplitDirection::Bottom, + mApp->getSplitter()->getCurWidget(), false ); + term->execute( "create-new-terminal" ); + } ); + term->setCommand( "terminal-split-left", [&, term] { + mApp->getSplitter()->split( UICodeEditorSplitter::SplitDirection::Left, + mApp->getSplitter()->getCurWidget(), false ); + term->execute( "create-new-terminal" ); + } ); + term->setCommand( "terminal-split-top", [&, term] { + mApp->getSplitter()->split( UICodeEditorSplitter::SplitDirection::Top, + mApp->getSplitter()->getCurWidget(), false ); + term->execute( "create-new-terminal" ); + } ); + term->setCommand( "split-swap", [&] { + if ( UISplitter* splitter = + mApp->getSplitter()->splitterFromWidget( mApp->getSplitter()->getCurWidget() ) ) + splitter->swap(); + } ); + term->setCommand( UITerminal::getExclusiveModeToggleCommandName(), + [term] { term->setExclusiveMode( !term->getExclusiveMode() ); } ); + term->setCommand( "create-new-terminal", [&] { createNewTerminal(); } ); + term->setCommand( "terminal-rename", [&, term] { + UIMessageBox* msgBox = UIMessageBox::New( + UIMessageBox::INPUT, mApp->i18n( "new_terminal_name", "New terminal name:" ) ); + msgBox->setTitle( "ecode" ); + msgBox->getTextInput()->setHint( mApp->i18n( "any_name", "Any name..." ) ); + msgBox->setCloseShortcut( { KEY_ESCAPE, KEYMOD_NONE } ); + msgBox->showWhenReady(); + msgBox->addEventListener( Event::MsgBoxConfirmClick, [&, msgBox, term]( const Event* ) { + std::string title( msgBox->getTextInput()->getText().toUtf8() ); + term->setTitle( title ); + msgBox->close(); + term->setFocus(); + } ); + } ); + term->setCommand( "move-panel-left", [&] { mApp->panelPosition( PanelPosition::Left ); } ); + term->setCommand( "move-panel-right", [&] { mApp->panelPosition( PanelPosition::Right ); } ); + term->setCommand( "close-app", [&] { mApp->closeApp(); } ); + term->setCommand( "open-file", [&] { mApp->openFileDialog(); } ); + term->setCommand( "open-folder", [&] { mApp->openFolderDialog(); } ); + term->setCommand( "console-toggle", [&] { mApp->consoleToggle(); } ); + term->setCommand( "menu-toggle", [&] { mApp->toggleSettingsMenu(); } ); + term->setCommand( "open-global-search", [&] { mApp->showGlobalSearch(); } ); + term->setCommand( "open-locatebar", [&] { mApp->getFileLocator()->showLocateBar(); } ); + term->setCommand( "download-file-web", [&] { mApp->downloadFileWebDialog(); } ); + + term->setCommand( "switch-to-previous-colorscheme", [&] { + auto it = mTerminalColorSchemes.find( mTerminalCurrentColorScheme ); + auto prev = std::prev( it, 1 ); + if ( prev != mTerminalColorSchemes.end() ) { + setTerminalColorScheme( prev->first ); + } else { + setTerminalColorScheme( mTerminalColorSchemes.rbegin()->first ); + } + } ); + term->setCommand( "switch-to-next-colorscheme", [&] { + auto it = mTerminalColorSchemes.find( mTerminalCurrentColorScheme ); + setTerminalColorScheme( ++it != mTerminalColorSchemes.end() + ? it->first + : mTerminalColorSchemes.begin()->first ); + } ); + // debug-draw-highlight-toggle + // debug-draw-boxes-toggle + // debug-draw-debug-data + // debug-widget-tree-view + term->setFocus(); + return term; +#endif +} + +} // namespace ecode diff --git a/src/tools/ecode/terminalmanager.hpp b/src/tools/ecode/terminalmanager.hpp new file mode 100644 index 000000000..1782a5764 --- /dev/null +++ b/src/tools/ecode/terminalmanager.hpp @@ -0,0 +1,56 @@ +#ifndef ECODE_TERMINALMANAGER_HPP +#define ECODE_TERMINALMANAGER_HPP + +#include +#include + +using namespace eterm::UI; +using namespace EE::UI; + +namespace ecode { + +class App; + +class TerminalManager { + public: + TerminalManager( App* app ); + + UITerminal* createNewTerminal( const std::string& title = "", + UITabWidget* inTabWidget = nullptr, + const std::string& workingDir = "" ); + + void applyTerminalColorScheme( const TerminalColorScheme& colorScheme ); + + void setTerminalColorScheme( const std::string& name ); + + void loadTerminalColorSchemes(); + + static std::map getTerminalKeybindings(); + + const std::string& getTerminalColorSchemesPath() const; + + void setTerminalColorSchemesPath( const std::string& terminalColorSchemesPath ); + + UIMenu* createColorSchemeMenu(); + + void updateMenuColorScheme( UIMenuSubMenu* colorSchemeMenu ); + + const std::map& getTerminalColorSchemes() const { + return mTerminalColorSchemes; + } + + void updateColorSchemeMenu(); + + protected: + App* mApp; + std::string mTerminalColorSchemesPath; + std::map mTerminalColorSchemes; + std::string mTerminalCurrentColorScheme; + + Float mColorSchemeMenuesCreatedWithHeight{ 0 }; + std::vector mColorSchemeMenues; +}; + +} // namespace ecode + +#endif // ECODE_TERMINALMANAGER_HPP