From 3cf446a467f38d660bb385b817855dc12867d8c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Lucas=20Golini?= Date: Sat, 16 Jul 2022 19:30:50 -0300 Subject: [PATCH] Implemented UIConsole. Some various minor fixes. --- LICENSE | 2 +- bin/assets/ui/breeze.css | 13 + include/eepp/graphics/console.hpp | 102 +- include/eepp/graphics/fontstyleconfig.hpp | 9 - include/eepp/scene/actions/runnable.hpp | 3 + include/eepp/ui.hpp | 1 + include/eepp/ui/doc/textdocument.hpp | 4 + include/eepp/ui/doc/textdocumentline.hpp | 2 + include/eepp/ui/uiconsole.hpp | 289 ++++ include/eepp/ui/uihelper.hpp | 1 + include/eepp/ui/uitextinput.hpp | 1 - projects/linux/ee.creator.user | 4 +- projects/linux/ee.files | 3 + src/eepp/graphics/console.cpp | 200 +-- src/eepp/scene/actions/runnable.cpp | 9 +- src/eepp/scene/node.cpp | 8 +- src/eepp/ui/doc/textdocument.cpp | 8 + src/eepp/ui/tools/uicolorpicker.cpp | 1 + src/eepp/ui/uiconsole.cpp | 1250 +++++++++++++++++ src/eepp/ui/uitextinput.cpp | 1 + src/eepp/ui/uiwidgetcreator.cpp | 2 + src/tools/ecode/ecode.cpp | 27 +- src/tools/ecode/ecode.hpp | 4 +- src/tools/mapeditor/mapeditor.cpp | 10 +- .../textureatlaseditor/textureatlaseditor.cpp | 9 +- 25 files changed, 1722 insertions(+), 241 deletions(-) create mode 100644 include/eepp/ui/uiconsole.hpp create mode 100644 src/eepp/ui/uiconsole.cpp diff --git a/LICENSE b/LICENSE index b39d117b6..3ac7e0327 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2020 Martín Lucas Golini +Copyright (c) 2022 Martín Lucas Golini Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/bin/assets/ui/breeze.css b/bin/assets/ui/breeze.css index e76e911f7..e8f2a40c2 100644 --- a/bin/assets/ui/breeze.css +++ b/bin/assets/ui/breeze.css @@ -38,6 +38,8 @@ --menu-font-disabled: #6e7275; --win-icon: #dbdbdd; --floating-icon: #eff0f188; + --term-back-color: #1e2127; + --term-font-color: #abb2bf; droppable-hovering-color: #FFFFFF20; } @@ -963,6 +965,15 @@ tab:not(:selected):hover > tab::icon { tint: var(--menu-font-active); } +console { + background-color: var(--term-back-color); + color: var(--term-font-color); + padding: 2dp; + font-size: 11dp; + border-bottom-color: var(--separator); + border-bottom-width: var(--border-width); +} + @media (prefers-color-scheme: light) { :root { @@ -1004,6 +1015,8 @@ tab:not(:selected):hover > tab::icon { --menu-font-disabled: #a8a9aa; --win-icon: #232627; --floating-icon: #cbcdcd; + --term-back-color: #eff0f1; + --term-font-color: #232627; droppable-hovering-color: #00000020; } diff --git a/include/eepp/graphics/console.hpp b/include/eepp/graphics/console.hpp index cbdc0d8f5..d0a0a0540 100644 --- a/include/eepp/graphics/console.hpp +++ b/include/eepp/graphics/console.hpp @@ -28,8 +28,8 @@ class EE_API Console : protected LogReaderInterface { Console( EE::Window::Window* window = NULL ); /** Creates the console */ - Console( Font* Font, const bool& MakeDefaultCommands = true, const bool& AttachToLog = true, - const unsigned int& MaxLogLines = 1024, const Uint32& textureId = 0, + Console( Font* Font, const bool& makeDefaultCommands = true, const bool& attachToLog = true, + const unsigned int& maxLogLines = 1024, const Uint32& textureId = 0, EE::Window::Window* window = NULL ); virtual ~Console(); @@ -103,8 +103,8 @@ class EE_API Console : protected LogReaderInterface { * @param MaxLogLines Maximum number of lines stored on the console * @param textureId Background texture id ( 0 for no texture ) */ - void create( Font* Font, const bool& MakeDefaultCommands = true, const bool& AttachToLog = true, - const unsigned int& MaxLogLines = 1024, const Uint32& textureId = 0 ); + void create( Font* Font, const bool& makeDefaultCommands = true, const bool& attachToLog = true, + const unsigned int& maxLogLines = 1024, const Uint32& textureId = 0 ); /** Add Text to Console */ void pushText( const String& str ); @@ -146,71 +146,68 @@ class EE_API Console : protected LogReaderInterface { std::deque mCmdLog; std::deque mLastCommands; - EE::Window::Window* mWindow; + EE::Window::Window* mWindow{ nullptr }; - Color mConColor; - Color mConLineColor; - Color mFontLineColor; + Color mConColor{ 0x201F1FEE }; + Color mConLineColor{ 0x666666EE }; + Color mFontLineColor{ 255, 255, 255, 230 }; - Float mWidth; - Float mHeight; - Float mHeightMin; - Float mCurHeight; - Float mY; - Float mA; - Float mMaxAlpha; - Float mTempY; - Float mFontSize; - Time mFadeSpeed; + Sizef mSize; +#if EE_PLATFORM == EE_PLATFORM_ANDROID || EE_PLATFORM == EE_PLATFORM_IOS + Float mHeightMin{ 0.5f }; +#else + Float mHeightMin{ 0.6f }; +#endif + Float mCurHeight{ 0.f }; + Float mY{ 0.f }; + Float mA{ 0.f }; + Float mMaxAlpha{ 255.f }; + Float mTempY{ 0.f }; + Float mFontSize{ 12.f }; + Time mFadeSpeed{ Milliseconds( 250.f ) }; - Uint32 mMyCallback; - Uint32 mVidCb; - Uint32 mEx; - Uint32 mMaxLogLines; - int mLastLogPos; + Uint32 mMyCallback{ 0 }; + Uint32 mVidCb{ 0 }; + Uint32 mEx{ 0 }; + Uint32 mMaxLogLines{ 1024 }; + int mLastLogPos{ 0 }; - InputTextBuffer* mTBuf; + InputTextBuffer* mTBuf{ nullptr }; Primitives mPri; - Uint32 mTexId; + Uint32 mTexId{ 0 }; struct sCon { - int ConMin; - int ConMax; - int ConModif; + int ConMin{ 0 }; + int ConMax{ 0 }; + int ConModif{ 0 }; }; sCon mCon; - Float mCurAlpha; + Float mCurAlpha{ 0.f }; std::vector mTextCache; FontStyleConfig mFontStyleConfig; - bool mEnabled; - bool mVisible; - bool mFadeIn; - bool mFadeOut; - bool mExpand; - bool mFading; - bool mShowFps; - bool mCurSide; + bool mEnabled{ false }; + bool mVisible{ false }; + bool mFadeIn{ false }; + bool mFadeOut{ false }; + bool mExpand{ false }; + bool mFading{ false }; + bool mShowFps{ false }; + bool mCurSide{ false }; void createDefaultCommands(); void fade( const Time& elapsedTime ); - /** Internal Callback for default command ( clear ) */ - void cmdClear( const std::vector& params ); - /** Internal Callback for default command ( maximize ) */ - void cmdMaximize( const std::vector& params ); + void cmdMaximize(); /** Internal Callback for default command ( minimize ) */ - void cmdMinimize( const std::vector& params ); - - /** Internal Callback for default command ( quit ) */ - void cmdQuit( const std::vector& params ); + void cmdMinimize(); /** Internal Callback for default command ( cmdlist ) */ - void cmdCmdList( const std::vector& params ); + void cmdCmdList(); /** Internal Callback for default command ( showcursor ) */ void cmdShowCursor( const std::vector& params ); @@ -218,18 +215,12 @@ class EE_API Console : protected LogReaderInterface { /** Internal Callback for default command ( setfpslimit ) */ void cmdFrameLimit( const std::vector& params ); - /** Internal Callback for default command ( getlog ) */ - void cmdGetLog( const std::vector& params ); - /** Internal Callback for default command ( setgamma ) */ void cmdSetGamma( const std::vector& params ); /** Internal Callback for default command ( setvolume ) */ void cmdSetVolume( const std::vector& params ); - /** Internal Callback for default command ( getgpuextensions ) */ - void cmdGetGpuExtensions( const std::vector& params ); - /** Internal Callback for default command ( dir and ls ) */ void cmdDir( const std::vector& params ); @@ -237,10 +228,7 @@ class EE_API Console : protected LogReaderInterface { void cmdShowFps( const std::vector& params ); /** Internal Callback for default command ( gettexturememory ) */ - void cmdGetTextureMemory( const std::vector& params ); - - /** Internal Callback for default command ( hide ) */ - void cmdHideConsole( const std::vector& params ); + void cmdGetTextureMemory(); /** The Default Commands Callbacks for the Console ( don't call it ) */ void privInputCallback( InputEvent* Event ); @@ -261,7 +249,7 @@ class EE_API Console : protected LogReaderInterface { void printCommandsStartingWith( const String& start ); - void privVideoResize( EE::Window::Window* win ); + void privVideoResize( EE::Window::Window* ); void writeLog( const std::string& Text ); diff --git a/include/eepp/graphics/fontstyleconfig.hpp b/include/eepp/graphics/fontstyleconfig.hpp index 89a4a4e8e..973edcffb 100644 --- a/include/eepp/graphics/fontstyleconfig.hpp +++ b/include/eepp/graphics/fontstyleconfig.hpp @@ -27,15 +27,6 @@ class FontStyleConfig { FontStyleConfig() {} - FontStyleConfig( const FontStyleConfig& fontStyleConfig ) : - Font( fontStyleConfig.Font ), - CharacterSize( fontStyleConfig.CharacterSize ), - Style( fontStyleConfig.Style ), - FontColor( fontStyleConfig.FontColor ), - ShadowColor( fontStyleConfig.ShadowColor ), - OutlineThickness( fontStyleConfig.OutlineThickness ), - OutlineColor( fontStyleConfig.OutlineColor ) {} - virtual void updateFontStyleConfig( const FontStyleConfig& fontStyleConfig ) { Font = fontStyleConfig.Font; Style = fontStyleConfig.Style; diff --git a/include/eepp/scene/actions/runnable.hpp b/include/eepp/scene/actions/runnable.hpp index 94790a4af..b359aff20 100644 --- a/include/eepp/scene/actions/runnable.hpp +++ b/include/eepp/scene/actions/runnable.hpp @@ -14,12 +14,15 @@ class EE_API Runnable : public Delay { void update( const Time& time ) override; + bool isDone() override; + Action* clone() const override; Action* reverse() const override; protected: RunnableFunc mCallback; + bool mCalled{ false }; explicit Runnable( RunnableFunc callback, const Time& time = Seconds( 0 ) ); diff --git a/include/eepp/ui.hpp b/include/eepp/ui.hpp index 6f735db10..bc7370a21 100644 --- a/include/eepp/ui.hpp +++ b/include/eepp/ui.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include diff --git a/include/eepp/ui/doc/textdocument.hpp b/include/eepp/ui/doc/textdocument.hpp index d592989b1..af3889368 100644 --- a/include/eepp/ui/doc/textdocument.hpp +++ b/include/eepp/ui/doc/textdocument.hpp @@ -121,6 +121,8 @@ class EE_API TextDocument { size_t linesCount() const; + const TextDocumentLine& getCurrentLine() const; + std::vector& lines(); bool hasSelection() const; @@ -143,6 +145,8 @@ class EE_API TextDocument { bool replaceLine( const Int64& lineNum, const String& text ); + bool replaceCurrentLine( const String& text ); + void print() const; // Translations diff --git a/include/eepp/ui/doc/textdocumentline.hpp b/include/eepp/ui/doc/textdocumentline.hpp index 83912871f..5dd1ca0f0 100644 --- a/include/eepp/ui/doc/textdocumentline.hpp +++ b/include/eepp/ui/doc/textdocumentline.hpp @@ -16,6 +16,8 @@ class EE_API TextDocumentLine { const String& getText() const { return mText; } + String getTextWithoutNewLine() const { return mText.substr( 0, mText.size() - 1 ); } + void operator=( const std::string& right ) { setText( right ); } String::StringBaseType operator[]( std::size_t index ) const { return mText[index]; } diff --git a/include/eepp/ui/uiconsole.hpp b/include/eepp/ui/uiconsole.hpp new file mode 100644 index 000000000..b8ff66da5 --- /dev/null +++ b/include/eepp/ui/uiconsole.hpp @@ -0,0 +1,289 @@ +#ifndef EE_UI_UICONSOLE_HPP +#define EE_UI_UICONSOLE_HPP + +#include +#include +#include +#include +#include +#include +#include + +using namespace EE::Graphics; +using namespace EE::System; +using namespace EE::UI::Doc; + +namespace EE { namespace UI { + +class EE_API UIConsole : public UIWidget, + protected LogReaderInterface, + public TextDocument::Client { + public: + //! The Console Callback return a vector of parameters ( String ) + typedef std::function& )> ConsoleCallback; + + static UIConsole* New(); + + static UIConsole* NewOpt( Font* font, const bool& makeDefaultCommands = true, + const bool& attachToLog = true, + const unsigned int& maxLogLines = 1024 ); + + virtual ~UIConsole(); + + virtual Uint32 getType() const; + + virtual bool isType( const Uint32& type ) const; + + virtual void setTheme( UITheme* Theme ); + + Font* getFont() const; + + const UIFontStyleConfig& getFontStyleConfig() const; + + UIConsole* setFont( Font* font ); + + UIConsole* setFontSize( const Float& dpSize ); + + const Float& getFontSize() const; + + UIConsole* setFontColor( const Color& color ); + + const Color& getFontColor() const; + + UIConsole* setFontSelectedColor( const Color& color ); + + const Color& getFontSelectedColor() const; + + UIConsole* setFontSelectionBackColor( const Color& color ); + + const Color& getFontSelectionBackColor() const; + + UIConsole* setFontShadowColor( const Color& color ); + + const Color& getFontShadowColor() const; + + UIConsole* setFontStyle( const Uint32& fontStyle ); + + UIConsole* setFontOutlineThickness( const Float& outlineThickness ); + + const Float& getFontOutlineThickness() const; + + UIConsole* setFontOutlineColor( const Color& outlineColor ); + + const Color& getFontOutlineColor() const; + + void addCommand( const std::string& command, const ConsoleCallback& cb ); + + const Uint32& getMaxLogLines() const; + + void setMaxLogLines( const Uint32& maxLogLines ); + + Int32 linesOnScreen(); + + virtual void draw(); + + /** @return If the console is rendering the FPS count. */ + const bool& isShowingFps() const; + + /** Activate/Deactive fps rendering */ + void showFps( const bool& show ); + + bool getEscapePastedText() const; + + void setEscapePastedText( bool escapePastedText ); + + bool isTextSelectionEnabled() const; + + /** Add Text to Console */ + void pushText( const String& str ); + + /** Add formated Text to console */ + void pushText( const char* format, ... ); + + Float getLineHeight() const; + + bool getQuakeMode() const; + + void setQuakeMode( bool quakeMode ); + + void show(); + + void hide(); + + void toggle(); + + bool isActive() const; + + Float getQuakeModeHeightPercent() const; + + void setQuakeModeHeightPercent( const Float& quakeModeHeightPercent ); + + virtual void scheduledUpdate( const Time& time ); + + const Time& getBlinkTime() const; + + void setBlinkTime( const Time& blinkTime ); + + protected: + Mutex mMutex; + std::map mCallbacks; + std::deque mCmdLog; + std::deque mLastCommands; + std::vector mTextCache; + UIFontStyleConfig mFontStyleConfig; + Uint32 mMaxLogLines{ 8192 }; + TextDocument mDoc; + KeyBindings mKeyBindings; + + struct sCon { + int min{ 0 }; + int max{ 0 }; + int modif{ 0 }; + }; + sCon mCon; + + bool mShowFps{ false }; + bool mEscapePastedText{ false }; + bool mMouseDown{ false }; + bool mQuakeMode{ false }; + bool mShowing{ false }; + bool mHiding{ false }; + bool mFading{ false }; + Clock mBlinkTimer; + Time mBlinkTime{ Seconds( 0.f ) }; + bool mCursorVisible{ true }; + int mLastLogPos{ 0 }; +#if EE_PLATFORM == EE_PLATFORM_ANDROID || EE_PLATFORM == EE_PLATFORM_IOS + Float mQuakeModeHeightPercent{ 0.5f }; +#else + Float mQuakeModeHeightPercent{ 0.6f }; +#endif + + UIConsole( Font* Font, const bool& makeDefaultCommands = true, const bool& attachToLog = true, + const unsigned int& maxLogLines = 1024 ); + + virtual bool applyProperty( const StyleSheetProperty& attribute ); + + virtual std::string getPropertyString( const PropertyDefinition* propertyDef, + const Uint32& propertyIndex = 0 ) const; + + void updateCacheSize(); + + virtual Uint32 onPressEnter(); + + virtual void onFontChanged(); + + virtual void onFontStyleChanged(); + + virtual Uint32 onMouseDown( const Vector2i& position, const Uint32& flags ); + + virtual Uint32 onMouseUp( const Vector2i& position, const Uint32& flags ); + + virtual Uint32 onMouseClick( const Vector2i& position, const Uint32& flags ); + + virtual Uint32 onMouseDoubleClick( const Vector2i& position, const Uint32& flags ); + + virtual Uint32 onMouseOver( const Vector2i& position, const Uint32& flags ); + + virtual Uint32 onMouseLeave( const Vector2i& position, const Uint32& flags ); + + virtual Uint32 onFocus(); + + virtual Uint32 onFocusLoss(); + + virtual void onDocumentTextChanged(); + + virtual void onDocumentCursorChange( const TextPosition& ); + + virtual void onDocumentSelectionChange( const TextRange& ); + + virtual void onDocumentLineCountChange( const size_t& lastCount, const size_t& newCount ); + + virtual void onDocumentLineChanged( const Int64& lineIndex ); + + virtual void onDocumentUndoRedo( const TextDocument::UndoRedo& ); + + virtual void onDocumentSaved( TextDocument* ); + + virtual void onDocumentMoved( TextDocument* ); + + void onDocumentClosed( TextDocument* ){}; + + void onDocumentDirtyOnFileSystem( TextDocument* ){}; + + virtual Uint32 onKeyDown( const KeyEvent& event ); + + virtual Uint32 onTextInput( const TextInputEvent& event ); + + virtual void onSelectionChange(); + + virtual void onSizeChange(); + + void registerKeybindings(); + + void registerCommands(); + + void copy(); + + void cut(); + + void paste(); + + void createDefaultCommands(); + + /** Internal Callback for default command ( cmdlist ) */ + void cmdCmdList(); + + /** Internal Callback for default command ( showcursor ) */ + void cmdShowCursor( const std::vector& params ); + + /** Internal Callback for default command ( setfpslimit ) */ + void cmdFrameLimit( const std::vector& params ); + + /** Internal Callback for default command ( setgamma ) */ + void cmdSetGamma( const std::vector& params ); + + /** Internal Callback for default command ( setvolume ) */ + void cmdSetVolume( const std::vector& params ); + + /** Internal Callback for default command ( dir and ls ) */ + void cmdDir( const std::vector& params ); + + /** Internal Callback for default command ( showfps ) */ + void cmdShowFps( const std::vector& params ); + + /** Internal Callback for default command ( gettexturememory ) */ + void cmdGetTextureMemory(); + + /** The Default Commands Callbacks for the Console ( don't call it ) */ + void privInputCallback( InputEvent* Event ); + + /** Clear the Console */ + void cmdClear(); + + /** Add the current log to the console */ + void cmdGetLog(); + + /** Add the GPU Extensions supported to the console */ + void cmdGetGpuExtensions(); + + void privPushText( const String& str ); + + void writeLog( const std::string& text ); + + void resetCursor(); + + void getFilesFrom( std::string txt, const Uint32& curPos ); + + void printCommandsStartingWith( const String& start ); + + String getLastCommonSubStr( std::list& cmds ); + + void processLine(); + + Int32 maxLinesOnScreen(); +}; + +}} // namespace EE::UI + +#endif diff --git a/include/eepp/ui/uihelper.hpp b/include/eepp/ui/uihelper.hpp index 5e4210bf8..973ec90e9 100644 --- a/include/eepp/ui/uihelper.hpp +++ b/include/eepp/ui/uihelper.hpp @@ -99,6 +99,7 @@ enum UINodeType { UI_TYPE_TABLEVIEW, UI_TYPE_TABLECELL, UI_TYPE_LISTVIEW, + UI_TYPE_CONSOLE, UI_TYPE_MODULES = 10000, UI_TYPE_TERMINAL = 10001, UI_TYPE_USER = 100000 diff --git a/include/eepp/ui/uitextinput.hpp b/include/eepp/ui/uitextinput.hpp index 11397fccc..52d5e6b4e 100644 --- a/include/eepp/ui/uitextinput.hpp +++ b/include/eepp/ui/uitextinput.hpp @@ -5,7 +5,6 @@ #include #include #include -#include using namespace EE::UI::Doc; diff --git a/projects/linux/ee.creator.user b/projects/linux/ee.creator.user index 8e592c3ed..e949a7bb3 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 - 20 + 16 ../../make/linux diff --git a/projects/linux/ee.files b/projects/linux/ee.files index 775048b41..9315dd437 100644 --- a/projects/linux/ee.files +++ b/projects/linux/ee.files @@ -1,6 +1,7 @@ ../../README.md ../../TODO.md ../../bin/assets/colorschemes/colorschemes.conf +../../bin/assets/colorschemes/terminalcolorschemes.conf ../../bin/assets/ee.ini ../../bin/assets/plugins/formatters.json ../../bin/assets/plugins/linters.json @@ -358,6 +359,7 @@ ../../include/eepp/ui/uicheckbox.hpp ../../include/eepp/ui/uicodeeditor.hpp ../../include/eepp/ui/uicombobox.hpp +../../include/eepp/ui/uiconsole.hpp ../../include/eepp/ui/uidropdownlist.hpp ../../include/eepp/ui/uieventdispatcher.hpp ../../include/eepp/ui/uifiledialog.hpp @@ -840,6 +842,7 @@ ../../src/eepp/ui/uicheckbox.cpp ../../src/eepp/ui/uicodeeditor.cpp ../../src/eepp/ui/uicombobox.cpp +../../src/eepp/ui/uiconsole.cpp ../../src/eepp/ui/uidropdownlist.cpp ../../src/eepp/ui/uieventdispatcher.cpp ../../src/eepp/ui/uifiledialog.cpp diff --git a/src/eepp/graphics/console.cpp b/src/eepp/graphics/console.cpp index fbf6aa306..c9b0d8099 100755 --- a/src/eepp/graphics/console.cpp +++ b/src/eepp/graphics/console.cpp @@ -16,81 +16,23 @@ using namespace EE::Window; namespace EE { namespace Graphics { Console::Console( EE::Window::Window* window ) : - mWindow( window ), - mConColor( 0x201F1FEE ), - mConLineColor( 0x666666EE ), - mFontLineColor( 255, 255, 255, 230 ), - mWidth( 0 ), - mHeight( 0 ), -#if EE_PLATFORM == EE_PLATFORM_ANDROID || EE_PLATFORM == EE_PLATFORM_IOS - mHeightMin( 0.5f ), -#else - mHeightMin( 0.6f ), -#endif - mY( 0.0f ), - mA( 0.0f ), - mFadeSpeed( Milliseconds( 250.f ) ), - mMyCallback( 0 ), - mVidCb( 0 ), - mMaxLogLines( 1024 ), - mLastLogPos( 0 ), - mTBuf( InputTextBuffer::New() ), - mTexId( 0 ), - mCurAlpha( 0 ), - mEnabled( false ), - mVisible( false ), - mFadeIn( false ), - mFadeOut( false ), - mExpand( false ), - mFading( false ), - mShowFps( false ), - mCurSide( false ) { + mWindow( window ), mTBuf( InputTextBuffer::New() ) { mFontStyleConfig.FontColor = Color( 0xCFCFCFFF ); - if ( NULL == mWindow ) { + if ( NULL == mWindow ) mWindow = Engine::instance()->getCurrentWindow(); - } } -Console::Console( Font* font, const bool& MakeDefaultCommands, const bool& AttachToLog, - const unsigned int& MaxLogLines, const Uint32& TextureId, +Console::Console( Font* font, const bool& makeDefaultCommands, const bool& attachToLog, + const unsigned int& maxLogLines, const Uint32& textureId, EE::Window::Window* window ) : - mWindow( window ), - mConColor( 0x201F1FEE ), - mConLineColor( 0x666666EE ), - mFontLineColor( 255, 255, 255, 230 ), - mWidth( 0 ), - mHeight( 0 ), -#if EE_PLATFORM == EE_PLATFORM_ANDROID || EE_PLATFORM == EE_PLATFORM_IOS - mHeightMin( 0.5f ), -#else - mHeightMin( 0.6f ), -#endif - mY( 0.0f ), - mA( 0.0f ), - mFadeSpeed( Milliseconds( 250.f ) ), - mMyCallback( 0 ), - mVidCb( 0 ), - mMaxLogLines( 1024 ), - mLastLogPos( 0 ), - mTBuf( InputTextBuffer::New() ), - mTexId( 0 ), - mCurAlpha( 0 ), - mEnabled( false ), - mVisible( false ), - mFadeIn( false ), - mFadeOut( false ), - mExpand( false ), - mFading( false ), - mShowFps( false ), - mCurSide( false ) { + mWindow( window ), mTBuf( InputTextBuffer::New() ) { mFontStyleConfig.FontColor = Color( 0xCFCFCFFF ); - if ( NULL == mWindow ) { + if ( NULL == mWindow ) mWindow = Engine::instance()->getCurrentWindow(); - } - create( font, MakeDefaultCommands, AttachToLog, MaxLogLines, TextureId ); + create( font, makeDefaultCommands, attachToLog, maxLogLines, textureId ); } Console::~Console() { @@ -102,9 +44,8 @@ Console::~Console() { eeSAFE_DELETE( mTBuf ); - if ( Log::existsSingleton() ) { + if ( Log::existsSingleton() ) Log::instance()->removeLogReader( this ); - } } void Console::setConsoleMinimizedHeight( const EE::Float& MinHeight ) { @@ -133,7 +74,7 @@ void Console::setBackgroundColor( const Color& BackColor ) { void Console::setCharacterSize( const EE::Uint32& characterSize ) { mFontStyleConfig.CharacterSize = characterSize; - mFontSize = ( Float )( mFontStyleConfig.Font->getFontHeight( + mFontSize = (Float)( mFontStyleConfig.Font->getFontHeight( PixelDensity::dpToPxI( mFontStyleConfig.CharacterSize ) ) ); } @@ -165,29 +106,28 @@ const Color& Console::getFontLineColor() const { return mFontLineColor; } -void Console::create( Font* Font, const bool& MakeDefaultCommands, const bool& AttachToLog, - const unsigned int& MaxLogLines, const Uint32& TextureId ) { - if ( NULL == mWindow ) { +void Console::create( Font* Font, const bool& makeDefaultCommands, const bool& attachToLog, + const unsigned int& maxLogLines, const Uint32& textureId ) { + if ( NULL == mWindow ) mWindow = Engine::instance()->getCurrentWindow(); - } mFontStyleConfig.Font = Font; - mFontSize = ( Float )( mFontStyleConfig.Font->getFontHeight( + mFontSize = (Float)( mFontStyleConfig.Font->getFontHeight( PixelDensity::dpToPxI( mFontStyleConfig.CharacterSize ) ) ); - if ( TextureId > 0 ) - mTexId = TextureId; + if ( textureId > 0 ) + mTexId = textureId; - mMaxLogLines = MaxLogLines; + mMaxLogLines = maxLogLines; mMaxAlpha = (Float)mConColor.a; mEnabled = true; - if ( MakeDefaultCommands ) + if ( makeDefaultCommands ) createDefaultCommands(); - mWidth = (Float)mWindow->getWidth(); - mHeight = (Float)mWindow->getHeight(); + mSize.x = (Float)mWindow->getWidth(); + mSize.y = (Float)mWindow->getHeight(); mTextCache.resize( maxLinesOnScreen() ); @@ -207,9 +147,8 @@ void Console::create( Font* Font, const bool& MakeDefaultCommands, const bool& A cmdGetLog(); - if ( AttachToLog ) { + if ( attachToLog ) Log::instance()->addLogReader( this ); - } } void Console::addCommand( const String& Command, ConsoleCallback CB ) { @@ -226,24 +165,24 @@ void Console::draw( const Time& elapsedTime ) { if ( mTexId == 0 ) { mPri.setColor( Color( mConColor.r, mConColor.g, mConColor.b, static_cast( mA ) ) ); - mPri.drawRectangle( Rectf( Vector2f( 0.0f, 0.0f ), Sizef( mWidth, mY ) ) ); + mPri.drawRectangle( Rectf( Vector2f( 0.0f, 0.0f ), Sizef( mSize.x, mY ) ) ); } else { Color C( mConColor.r, mConColor.g, mConColor.b, static_cast( mA ) ); Texture* Tex = TextureFactory::instance()->getTexture( mTexId ); if ( NULL != Tex ) - Tex->drawEx( 0.0f, 0.0f, mWidth, mY, 0.0f, Vector2f::One, C, C, C, C ); + Tex->drawEx( 0.0f, 0.0f, mSize.x, mY, 0.0f, Vector2f::One, C, C, C, C ); } mPri.setColor( Color( mConLineColor.r, mConLineColor.g, mConLineColor.b, static_cast( mA ) ) ); mPri.drawRectangle( - Rectf( Vector2f( 0.0f, mY ), Sizef( mWidth, PixelDensity::dpToPx( 2.0f ) ) ) ); + Rectf( Vector2f( 0.0f, mY ), Sizef( mSize.x, PixelDensity::dpToPx( 2.0f ) ) ) ); Int32 linesInScreen = this->linesOnScreen(); if ( static_cast( mCmdLog.size() ) > linesInScreen ) - mEx = ( Uint32 )( mCmdLog.size() - linesInScreen ); + mEx = (Uint32)( mCmdLog.size() - linesInScreen ); else mEx = 0; mTempY = -mCurHeight; @@ -365,7 +304,7 @@ const Time& Console::getFadeSpeed() const { return mFadeSpeed; } -static std::vector SplitCommandParams( String str ) { +static std::vector splitCommandParams( String str ) { std::vector params = String::split( str, ' ' ); std::vector rparams; String tstr; @@ -399,7 +338,7 @@ static std::vector SplitCommandParams( String str ) { void Console::processLine() { String str = mTBuf->getBuffer(); - std::vector params = SplitCommandParams( str ); + std::vector params = splitCommandParams( str ); mLastCommands.push_back( str ); mLastLogPos = (int)mLastCommands.size(); @@ -492,9 +431,9 @@ void Console::fade( const Time& elapsedTime ) { } if ( mExpand ) - mCurHeight = mHeight; + mCurHeight = mSize.y; else - mCurHeight = eefloor( mHeightMin * mHeight ); + mCurHeight = eefloor( mHeightMin * mSize.y ); if ( mFadeIn ) { mFadeOut = false; @@ -594,16 +533,16 @@ void Console::printCommandsStartingWith( const String& start ) { } } -void Console::privVideoResize( EE::Window::Window* win ) { - mWidth = (Float)mWindow->getWidth(); - mHeight = (Float)mWindow->getHeight(); +void Console::privVideoResize( EE::Window::Window* ) { + mSize.x = (Float)mWindow->getWidth(); + mSize.y = (Float)mWindow->getHeight(); mTextCache.resize( maxLinesOnScreen() ); if ( mVisible ) { if ( mExpand ) - mCurHeight = mHeight; + mCurHeight = mSize.y; else - mCurHeight = eefloor( mHeightMin * mHeight ); + mCurHeight = eefloor( mHeightMin * mSize.y ); mY = mCurHeight; } @@ -699,7 +638,7 @@ Int32 Console::linesOnScreen() { } Int32 Console::maxLinesOnScreen() { - return static_cast( ( mHeight / mFontSize ) + 3 ); + return static_cast( ( mSize.y / mFontSize ) + 3 ); } void Console::privInputCallback( InputEvent* Event ) { @@ -797,63 +736,55 @@ void Console::privInputCallback( InputEvent* Event ) { } void Console::createDefaultCommands() { - addCommand( "clear", cb::Make1( this, &Console::cmdClear ) ); - addCommand( "quit", cb::Make1( this, &Console::cmdQuit ) ); - addCommand( "maximize", cb::Make1( this, &Console::cmdMaximize ) ); - addCommand( "minimize", cb::Make1( this, &Console::cmdMinimize ) ); - addCommand( "cmdlist", cb::Make1( this, &Console::cmdCmdList ) ); - addCommand( "help", cb::Make1( this, &Console::cmdCmdList ) ); - addCommand( "showcursor", cb::Make1( this, &Console::cmdShowCursor ) ); - addCommand( "setfpslimit", cb::Make1( this, &Console::cmdFrameLimit ) ); - addCommand( "getlog", cb::Make1( this, &Console::cmdGetLog ) ); - addCommand( "setgamma", cb::Make1( this, &Console::cmdSetGamma ) ); - addCommand( "setvolume", cb::Make1( this, &Console::cmdSetVolume ) ); - addCommand( "getgpuextensions", cb::Make1( this, &Console::cmdGetGpuExtensions ) ); - addCommand( "dir", cb::Make1( this, &Console::cmdDir ) ); - addCommand( "ls", cb::Make1( this, &Console::cmdDir ) ); - addCommand( "showfps", cb::Make1( this, &Console::cmdShowFps ) ); - addCommand( "gettexturememory", cb::Make1( this, &Console::cmdGetTextureMemory ) ); - addCommand( "hide", cb::Make1( this, &Console::cmdHideConsole ) ); + addCommand( "clear", [&]( const auto& ) { cmdClear(); } ); + addCommand( "quit", [&]( const auto& ) { mWindow->close(); } ); + addCommand( "maximize", [&]( const auto& ) { cmdMaximize(); } ); + addCommand( "minimize", [&]( const auto& ) { cmdMinimize(); } ); + addCommand( "cmdlist", [&]( const auto& ) { cmdCmdList(); } ); + addCommand( "help", [&]( const auto& ) { cmdCmdList(); } ); + addCommand( "showcursor", [&]( const auto& params ) { cmdShowCursor( params ); } ); + addCommand( "setfpslimit", [&]( const auto& params ) { cmdFrameLimit( params ); } ); + addCommand( "getlog", [&]( const auto& ) { cmdGetLog(); } ); + addCommand( "setgamma", [&]( const auto& params ) { cmdSetGamma( params ); } ); + addCommand( "setvolume", [&]( const auto& params ) { cmdSetVolume( params ); } ); + addCommand( "getgpuextensions", [&]( const auto& ) { cmdGetGpuExtensions(); } ); + addCommand( "dir", [&]( const auto& params ) { cmdDir( params ); } ); + addCommand( "ls", [&]( const auto& params ) { cmdDir( params ); } ); + addCommand( "showfps", [&]( const auto& params ) { cmdShowFps( params ); } ); + addCommand( "gettexturememory", [&]( const auto& ) { cmdGetTextureMemory(); } ); + addCommand( "hide", [&]( const auto& ) { fadeOut(); } ); } void Console::cmdClear() { Uint16 CutLines; if ( mExpand ) { - CutLines = ( Uint16 )( mHeight / mFontSize ); + CutLines = (Uint16)( mSize.y / mFontSize ); } else { - CutLines = ( Uint16 )( ( mHeightMin * mHeight ) / mFontSize ); + CutLines = (Uint16)( ( mHeightMin * mSize.y ) / mFontSize ); } for ( Uint16 i = 0; i < CutLines; i++ ) privPushText( "" ); } -void Console::cmdClear( const std::vector& params ) { - cmdClear(); -} - -void Console::cmdMaximize( const std::vector& params ) { +void Console::cmdMaximize() { mExpand = true; - mY = mHeight; + mY = mSize.y; privPushText( "Console Maximized" ); } -void Console::cmdMinimize( const std::vector& params ) { +void Console::cmdMinimize() { mExpand = false; - mY = eefloor( mHeightMin * mHeight ); + mY = eefloor( mHeightMin * mSize.y ); privPushText( "Console Minimized" ); } -void Console::cmdQuit( const std::vector& params ) { - mWindow->close(); -} - -void Console::cmdGetTextureMemory( const std::vector& params ) { +void Console::cmdGetTextureMemory() { privPushText( "Total texture memory used: " + FileSystem::sizeToString( TextureFactory::instance()->getTextureMemorySize() ) ); } -void Console::cmdCmdList( const std::vector& params ) { +void Console::cmdCmdList() { std::map::iterator itr; for ( itr = mCallbacks.begin(); itr != mCallbacks.end(); ++itr ) { privPushText( "\t" + itr->first ); @@ -899,10 +830,6 @@ void Console::cmdGetLog() { } } -void Console::cmdGetLog( const std::vector& params ) { - cmdGetLog(); -} - void Console::cmdGetGpuExtensions() { std::vector tvec = String::split( String( GLi->getExtensions() ), ' ' ); if ( tvec.size() > 0 ) { @@ -911,14 +838,9 @@ void Console::cmdGetGpuExtensions() { } } -void Console::cmdGetGpuExtensions( const std::vector& params ) { - cmdGetGpuExtensions(); -} - void Console::cmdSetGamma( const std::vector& params ) { if ( params.size() >= 2 ) { Float tFloat = 0.f; - bool Res = String::fromString( tFloat, params[1] ); if ( Res && ( tFloat > 0.1f && tFloat <= 10.0f ) ) { @@ -1018,10 +940,6 @@ void Console::cmdShowFps( const std::vector& params ) { privPushText( "Valid parameters are 0 ( hide ) or 1 ( show )." ); } -void Console::cmdHideConsole( const std::vector& params ) { - fadeOut(); -} - void Console::ignoreCharOnPrompt( const Uint32& ch ) { mTBuf->pushIgnoredChar( ch ); } diff --git a/src/eepp/scene/actions/runnable.cpp b/src/eepp/scene/actions/runnable.cpp index 40c29ba64..4bde166b2 100644 --- a/src/eepp/scene/actions/runnable.cpp +++ b/src/eepp/scene/actions/runnable.cpp @@ -10,11 +10,18 @@ Runnable::Runnable( Runnable::RunnableFunc callback, const Time& time ) : Delay( time ), mCallback( callback ) {} void Runnable::update( const Time& ) { - if ( mCallback && isDone() ) { + if ( mCallback && Delay::isDone() && !mCalled ) { mCallback(); + mCalled = true; + } else if ( !mCallback ) { + mCalled = true; } } +bool Runnable::isDone() { + return Delay::isDone() && mCalled; +} + Action* Runnable::clone() const { return New( mCallback, mTime ); } diff --git a/src/eepp/scene/node.cpp b/src/eepp/scene/node.cpp index d2cbb110a..01cef843e 100644 --- a/src/eepp/scene/node.cpp +++ b/src/eepp/scene/node.cpp @@ -283,11 +283,11 @@ void Node::close() { void Node::draw() {} void Node::update( const Time& time ) { - Node* ChildLoop = mChild; + Node* childLoop = mChild; - while ( NULL != ChildLoop ) { - ChildLoop->update( time ); - ChildLoop = ChildLoop->mNext; + while ( NULL != childLoop ) { + childLoop->update( time ); + childLoop = childLoop->mNext; } writeNodeFlag( NODE_FLAG_MOUSEOVER_ME_OR_CHILD, 0 ); diff --git a/src/eepp/ui/doc/textdocument.cpp b/src/eepp/ui/doc/textdocument.cpp index c2f59138e..d3706158c 100644 --- a/src/eepp/ui/doc/textdocument.cpp +++ b/src/eepp/ui/doc/textdocument.cpp @@ -605,6 +605,10 @@ size_t TextDocument::linesCount() const { return mLines.size(); } +const TextDocumentLine& TextDocument::getCurrentLine() const { + return mLines[mSelection.start().line()]; +} + std::vector& TextDocument::lines() { return mLines; } @@ -789,6 +793,10 @@ bool TextDocument::replaceLine( const Int64& lineNum, const String& text ) { return false; } +bool TextDocument::replaceCurrentLine( const String& text ) { + return replaceLine( getSelection().start().line(), text ); +} + TextPosition TextDocument::nextChar( TextPosition position ) const { return positionOffset( position, TextPosition( 0, 1 ) ); } diff --git a/src/eepp/ui/tools/uicolorpicker.cpp b/src/eepp/ui/tools/uicolorpicker.cpp index e2cf647ca..1a8fe9b29 100644 --- a/src/eepp/ui/tools/uicolorpicker.cpp +++ b/src/eepp/ui/tools/uicolorpicker.cpp @@ -11,6 +11,7 @@ #include #include #include +#include namespace EE { namespace UI { namespace Tools { diff --git a/src/eepp/ui/uiconsole.cpp b/src/eepp/ui/uiconsole.cpp new file mode 100644 index 000000000..6dffface9 --- /dev/null +++ b/src/eepp/ui/uiconsole.cpp @@ -0,0 +1,1250 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace EE::Window; +using namespace EE::Scene; + +namespace EE { namespace UI { + +UIConsole* UIConsole::New() { + return eeNew( UIConsole, ( nullptr, true, false, 8192 ) ); +} + +UIConsole* UIConsole::NewOpt( Font* font, const bool& makeDefaultCommands, const bool& attachToLog, + const unsigned int& maxLogLines ) { + return eeNew( UIConsole, ( font, makeDefaultCommands, attachToLog, maxLogLines ) ); +} + +UIConsole::UIConsole( Font* font, const bool& makeDefaultCommands, const bool& attachToLog, + const unsigned int& maxLogLines ) : + UIWidget( "console" ), mKeyBindings( getUISceneNode()->getWindow()->getInput() ) { + setFlags( UI_AUTO_PADDING ); + mFlags |= UI_TAB_STOP; + clipEnable(); + + setBackgroundColor( 0x201F1FEE ); + + mDoc.registerClient( this ); + registerCommands(); + registerKeybindings(); + + mFontStyleConfig.Font = font; + if ( nullptr == font ) + mFontStyleConfig.Font = FontManager::instance()->getByName( "monospace" ); + + mMaxLogLines = maxLogLines; + + if ( nullptr == mFontStyleConfig.Font ) + Log::error( "A monospace font must be loaded to be able to use the console.\nTry loading " + "a font with the name \"monospace\"" ); + + if ( makeDefaultCommands ) + createDefaultCommands(); + + mTextCache.resize( maxLinesOnScreen() ); + + cmdGetLog(); + + if ( attachToLog ) + Log::instance()->addLogReader( this ); + + applyDefaultTheme(); + + subscribeScheduledUpdate(); +} + +UIConsole::~UIConsole() { + if ( Log::existsSingleton() ) + Log::instance()->removeLogReader( this ); +} + +Uint32 UIConsole::getType() const { + return UI_TYPE_CONSOLE; +} + +bool UIConsole::isType( const Uint32& type ) const { + return UIConsole::getType() == type ? true : UIWidget::isType( type ); +} + +void UIConsole::setTheme( UITheme* Theme ) { + UIWidget::setTheme( Theme ); + + setThemeSkin( Theme, "console" ); + + onThemeLoaded(); +} + +void UIConsole::scheduledUpdate( const Time& ) { + if ( hasFocus() && getUISceneNode()->getWindow()->hasFocus() ) { + if ( mBlinkTime != Time::Zero && mBlinkTimer.getElapsedTime() > mBlinkTime ) { + mCursorVisible = !mCursorVisible; + mBlinkTimer.restart(); + invalidateDraw(); + } + } +} + +const Time& UIConsole::getBlinkTime() const { + return mBlinkTime; +} + +void UIConsole::setBlinkTime( const Time& blinkTime ) { + if ( blinkTime != mBlinkTime ) { + mBlinkTime = blinkTime; + resetCursor(); + if ( mBlinkTime == Time::Zero ) + mCursorVisible = true; + } +} + +Font* UIConsole::getFont() const { + return mFontStyleConfig.Font; +} + +const UIFontStyleConfig& UIConsole::getFontStyleConfig() const { + return mFontStyleConfig; +} + +UIConsole* UIConsole::setFont( Font* font ) { + if ( mFontStyleConfig.Font != font ) { + mFontStyleConfig.Font = font; + invalidateDraw(); + onFontChanged(); + } + return this; +} + +bool UIConsole::applyProperty( const StyleSheetProperty& attribute ) { + if ( !checkPropertyDefinition( attribute ) ) + return false; + + switch ( attribute.getPropertyDefinition()->getPropertyId() ) { + case PropertyId::Color: + setFontColor( attribute.asColor() ); + break; + case PropertyId::ShadowColor: + setFontShadowColor( attribute.asColor() ); + break; + case PropertyId::SelectionColor: + mFontStyleConfig.FontSelectedColor = attribute.asColor(); + break; + case PropertyId::SelectionBackColor: + setFontSelectionBackColor( attribute.asColor() ); + break; + case PropertyId::FontFamily: { + Font* font = FontManager::instance()->getByName( attribute.asString() ); + + if ( NULL != font && font->loaded() ) { + setFont( font ); + } + break; + } + case PropertyId::FontSize: + setFontSize( lengthFromValueAsDp( attribute ) ); + break; + case PropertyId::FontStyle: { + setFontStyle( attribute.asFontStyle() ); + break; + } + case PropertyId::TextStrokeWidth: + setFontOutlineThickness( lengthFromValue( attribute ) ); + break; + case PropertyId::TextStrokeColor: + setFontOutlineColor( attribute.asColor() ); + break; + default: + return UIWidget::applyProperty( attribute ); + } + + return true; +} + +std::string UIConsole::getPropertyString( const PropertyDefinition* propertyDef, + const Uint32& propertyIndex ) const { + if ( NULL == propertyDef ) + return ""; + + switch ( propertyDef->getPropertyId() ) { + case PropertyId::Color: + return getFontColor().toHexString(); + case PropertyId::ShadowColor: + return getFontShadowColor().toHexString(); + case PropertyId::SelectionColor: + return getFontSelectedColor().toHexString(); + case PropertyId::SelectionBackColor: + return getFontSelectionBackColor().toHexString(); + case PropertyId::FontFamily: + return NULL != getFont() ? getFont()->getName() : ""; + case PropertyId::FontSize: + return String::format( "%.2fdp", getFontSize() ); + case PropertyId::FontStyle: + return Text::styleFlagToString( getFontStyleConfig().getFontStyle() ); + case PropertyId::TextStrokeWidth: + return String::toString( PixelDensity::dpToPx( getFontOutlineThickness() ) ); + case PropertyId::TextStrokeColor: + return getFontOutlineColor().toHexString(); + default: + return UIWidget::getPropertyString( propertyDef, propertyIndex ); + } +} + +UIConsole* UIConsole::setFontSize( const Float& dpSize ) { + if ( mFontStyleConfig.CharacterSize != dpSize ) { + mFontStyleConfig.CharacterSize = + eeabs( dpSize - (int)dpSize ) == 0.5f || (int)dpSize == dpSize ? dpSize + : eefloor( dpSize ); + mFontStyleConfig.CharacterSize = mFontStyleConfig.CharacterSize; + invalidateDraw(); + onFontChanged(); + } + return this; +} + +const Float& UIConsole::getFontSize() const { + return mFontStyleConfig.getFontCharacterSize(); +} + +UIConsole* UIConsole::setFontColor( const Color& color ) { + if ( mFontStyleConfig.getFontColor() != color ) { + mFontStyleConfig.FontColor = color; + invalidateDraw(); + onFontStyleChanged(); + } + return this; +} + +const Color& UIConsole::getFontColor() const { + return mFontStyleConfig.getFontColor(); +} + +const Color& UIConsole::getFontSelectedColor() const { + return mFontStyleConfig.getFontSelectedColor(); +} + +UIConsole* UIConsole::setFontSelectedColor( const Color& color ) { + if ( mFontStyleConfig.getFontSelectedColor() != color ) { + mFontStyleConfig.FontSelectedColor = color; + invalidateDraw(); + onFontStyleChanged(); + } + return this; +} + +UIConsole* UIConsole::setFontSelectionBackColor( const Color& color ) { + if ( mFontStyleConfig.getFontSelectionBackColor() != color ) { + mFontStyleConfig.FontSelectionBackColor = color; + invalidateDraw(); + onFontStyleChanged(); + } + return this; +} + +const Color& UIConsole::getFontSelectionBackColor() const { + return mFontStyleConfig.getFontSelectionBackColor(); +} + +UIConsole* UIConsole::setFontOutlineThickness( const Float& outlineThickness ) { + if ( mFontStyleConfig.OutlineThickness != outlineThickness ) { + mFontStyleConfig.OutlineThickness = outlineThickness; + onFontStyleChanged(); + } + return this; +} + +const Float& UIConsole::getFontOutlineThickness() const { + return mFontStyleConfig.OutlineThickness; +} + +UIConsole* UIConsole::setFontOutlineColor( const Color& outlineColor ) { + if ( mFontStyleConfig.OutlineColor != outlineColor ) { + mFontStyleConfig.OutlineColor = outlineColor; + onFontStyleChanged(); + } + return this; +} + +const Color& UIConsole::getFontOutlineColor() const { + return mFontStyleConfig.OutlineColor; +} + +void UIConsole::onFontChanged() { + updateCacheSize(); +} + +void UIConsole::onFontStyleChanged() { + onFontChanged(); +} + +void UIConsole::addCommand( const std::string& command, const ConsoleCallback& cb ) { + if ( !( mCallbacks.count( command ) > 0 ) ) + mCallbacks[command] = cb; +} + +const Uint32& UIConsole::getMaxLogLines() const { + return mMaxLogLines; +} + +void UIConsole::setMaxLogLines( const Uint32& maxLogLines ) { + mMaxLogLines = maxLogLines; +} + +void UIConsole::privPushText( const String& str ) { + Lock l( mMutex ); + mCmdLog.push_back( str ); + invalidateDraw(); + if ( mCmdLog.size() >= mMaxLogLines ) + mCmdLog.pop_front(); +} + +Int32 UIConsole::linesOnScreen() { + return static_cast( + ( ( getPixelsSize().getHeight() - mPaddingPx.Top - mPaddingPx.Bottom ) / getLineHeight() ) - + 1 ); +} + +Int32 UIConsole::maxLinesOnScreen() { + return static_cast( + ( ( getPixelsSize().getHeight() - mPaddingPx.Top - mPaddingPx.Bottom ) / getLineHeight() ) + + 3 ); +} + +void UIConsole::draw() { + if ( !mVisible || NULL == mFontStyleConfig.Font ) + return; + + Lock l( mMutex ); + Int32 linesInScreen = linesOnScreen(); + size_t pos = 0; + Float curY; + Float lineHeight = getLineHeight(); + + mCon.min = eemax( 0, (Int32)mCmdLog.size() - linesInScreen ); + mCon.max = (int)mCmdLog.size() - 1; + + UIWidget::draw(); + + Color fontColor( Color( mFontStyleConfig.FontColor.r, mFontStyleConfig.FontColor.g, + mFontStyleConfig.FontColor.b ) + .blendAlpha( (Uint8)mAlpha ) ); + + for ( int i = mCon.max - mCon.modif; i >= mCon.min - mCon.modif; i-- ) { + if ( i < (int)mCmdLog.size() && i >= 0 ) { + curY = mScreenPos.y + getPixelsSize().getHeight() - mPaddingPx.Bottom - + pos * lineHeight - lineHeight * 2 - 1; + Text& text = mTextCache[pos]; + text.setStyleConfig( mFontStyleConfig ); + text.setFillColor( fontColor ); + text.setString( mCmdLog[i] ); + text.draw( mScreenPos.x + mPaddingPx.Left, curY ); + pos++; + } + } + + curY = mScreenPos.y + getPixelsSize().getHeight() - mPaddingPx.Bottom - lineHeight - 1; + + Text& text = mTextCache[mTextCache.size() - 1]; + text.setStyleConfig( mFontStyleConfig ); + text.setFillColor( fontColor ); + text.setString( "> " + mDoc.getCurrentLine().getTextWithoutNewLine() ); + text.draw( mScreenPos.x + mPaddingPx.Left, curY ); + + Text& text2 = mTextCache[mTextCache.size() - 2]; + text2.setStyleConfig( mFontStyleConfig ); + text2.setFillColor( fontColor ); + + if ( mCursorVisible ) { + if ( (unsigned int)mDoc.getSelection().start().column() == + mDoc.getCurrentLine().size() - 1 ) { + Uint32 width = text.getTextWidth(); + text2.setString( "_" ); + text2.draw( mScreenPos.x + mPaddingPx.Left + width, curY ); + } else { + text2.setString( "> " + mDoc.getCurrentLine().getText().substr( + 0, mDoc.getSelection().start().column() ) ); + Uint32 width = mPaddingPx.Left + text2.getTextWidth(); + text2.setString( "_" ); + text2.draw( mScreenPos.x + width, curY ); + } + } + + if ( mShowFps ) { + Float cw = + mFontStyleConfig.Font->getGlyph( '_', mFontStyleConfig.CharacterSize, false ).advance; + Text& text = mTextCache[mTextCache.size() - 3]; + Color OldColor1( text.getColor() ); + text.setStyleConfig( mFontStyleConfig ); + text.setFillColor( fontColor ); + text.setString( "FPS: " + String::toString( getUISceneNode()->getWindow()->getFPS() ) ); + text.draw( mScreenPos.x + getPixelsSize().getWidth() - text.getTextWidth() - cw - + mPaddingPx.Right, + mScreenPos.y + mPaddingPx.Top + eefloor( lineHeight / 2 ) ); + text.setFillColor( OldColor1 ); + } +} + +// CMDS +void UIConsole::createDefaultCommands() { + addCommand( "clear", [&]( const auto& ) { cmdClear(); } ); + addCommand( "quit", [&]( const auto& ) { getUISceneNode()->getWindow()->close(); } ); + addCommand( "cmdlist", [&]( const auto& ) { cmdCmdList(); } ); + addCommand( "help", [&]( const auto& ) { cmdCmdList(); } ); + addCommand( "showcursor", [&]( const auto& params ) { cmdShowCursor( params ); } ); + addCommand( "setfpslimit", [&]( const auto& params ) { cmdFrameLimit( params ); } ); + addCommand( "getlog", [&]( const auto& ) { cmdGetLog(); } ); + addCommand( "setgamma", [&]( const auto& params ) { cmdSetGamma( params ); } ); + addCommand( "setvolume", [&]( const auto& params ) { cmdSetVolume( params ); } ); + addCommand( "getgpuextensions", [&]( const auto& ) { cmdGetGpuExtensions(); } ); + addCommand( "dir", [&]( const auto& params ) { cmdDir( params ); } ); + addCommand( "ls", [&]( const auto& params ) { cmdDir( params ); } ); + addCommand( "showfps", [&]( const auto& params ) { cmdShowFps( params ); } ); + addCommand( "gettexturememory", [&]( const auto& ) { cmdGetTextureMemory(); } ); +} + +void UIConsole::cmdClear() { + size_t cutLines = getPixelsSize().getHeight() / mFontStyleConfig.CharacterSize; + for ( size_t i = 0; i < cutLines; i++ ) + privPushText( "" ); +} + +void UIConsole::cmdGetTextureMemory() { + privPushText( "Total texture memory used: " + + FileSystem::sizeToString( TextureFactory::instance()->getTextureMemorySize() ) ); +} + +void UIConsole::cmdCmdList() { + for ( auto itr = mCallbacks.begin(); itr != mCallbacks.end(); ++itr ) + privPushText( "\t" + itr->first ); +} + +void UIConsole::cmdShowCursor( const std::vector& params ) { + if ( params.size() >= 2 ) { + Int32 tInt = 0; + + bool Res = String::fromString( tInt, params[1] ); + + if ( Res && ( tInt == 0 || tInt == 1 ) ) { + getUISceneNode()->getWindow()->getCursorManager()->setVisible( 0 != tInt ); + } else + privPushText( "Valid parameters are 0 or 1." ); + } else { + privPushText( "No parameters. Valid parameters are 0 ( hide ) or 1 ( show )." ); + } +} + +void UIConsole::cmdFrameLimit( const std::vector& params ) { + if ( params.size() >= 2 ) { + Int32 tInt = 0; + + bool Res = String::fromString( tInt, params[1] ); + + if ( Res && ( tInt >= 0 && tInt <= 10000 ) ) { + getUISceneNode()->getWindow()->setFrameRateLimit( tInt ); + return; + } + } + + privPushText( "Valid parameters are between 0 and 10000 (0 = no limit)." ); +} + +void UIConsole::cmdGetLog() { + std::vector tvec = + String::split( String( String::toString( Log::instance()->getBuffer() ) ) ); + if ( tvec.size() > 0 ) { + for ( unsigned int i = 0; i < tvec.size(); i++ ) + privPushText( tvec[i] ); + } +} + +void UIConsole::cmdGetGpuExtensions() { + std::vector tvec = String::split( String( GLi->getExtensions() ), ' ' ); + if ( tvec.size() > 0 ) { + for ( unsigned int i = 0; i < tvec.size(); i++ ) + privPushText( tvec[i] ); + } +} + +void UIConsole::cmdSetGamma( const std::vector& params ) { + if ( params.size() >= 2 ) { + Float tFloat = 0.f; + bool Res = String::fromString( tFloat, params[1] ); + + if ( Res && ( tFloat > 0.1f && tFloat <= 10.0f ) ) { + getUISceneNode()->getWindow()->setGamma( tFloat, tFloat, tFloat ); + return; + } + } + + privPushText( "Valid parameters are between 0.1 and 10." ); +} + +void UIConsole::cmdSetVolume( const std::vector& params ) { + if ( params.size() >= 2 ) { + Float tFloat = 0.f; + + bool Res = String::fromString( tFloat, params[1] ); + + if ( Res && ( tFloat >= 0.0f && tFloat <= 100.0f ) ) { + EE::Audio::Listener::setGlobalVolume( tFloat ); + return; + } + } + + privPushText( "Valid parameters are between 0 and 100." ); +} + +void UIConsole::cmdDir( const std::vector& params ) { + if ( params.size() >= 2 ) { + String Slash( FileSystem::getOSSlash() ); + String myPath = params[1]; + String myOrder; + + if ( params.size() > 2 ) { + myOrder = params[2]; + } + + if ( FileSystem::isDirectory( myPath ) ) { + unsigned int i; + + std::vector mFiles = FileSystem::filesGetInPath( myPath ); + std::sort( mFiles.begin(), mFiles.end() ); + + privPushText( "Directory: " + myPath ); + + if ( myOrder == "ff" ) { + std::vector mFolders; + std::vector mFile; + + for ( i = 0; i < mFiles.size(); i++ ) { + if ( FileSystem::isDirectory( myPath + Slash + mFiles[i] ) ) { + mFolders.push_back( mFiles[i] ); + } else { + mFile.push_back( mFiles[i] ); + } + } + + if ( mFolders.size() ) + privPushText( "Folders: " ); + + for ( i = 0; i < mFolders.size(); i++ ) + privPushText( " " + mFolders[i] ); + + if ( mFolders.size() ) + privPushText( "Files: " ); + + for ( i = 0; i < mFile.size(); i++ ) + privPushText( " " + mFile[i] ); + + } else { + for ( i = 0; i < mFiles.size(); i++ ) + privPushText( " " + mFiles[i] ); + } + } else { + if ( myPath == "help" ) + privPushText( + "You can use a third parameter to show folders first, the parameter is ff." ); + else + privPushText( "Path \"" + myPath + "\" is not a directory." ); + } + } else { + privPushText( "Expected a path to list. Example of usage: ls /home" ); + } +} + +void UIConsole::cmdShowFps( const std::vector& params ) { + if ( params.size() >= 2 ) { + Int32 tInt = 0; + + bool res = String::fromString( tInt, params[1] ); + + if ( res && ( tInt == 0 || tInt == 1 ) ) { + mShowFps = 0 != tInt; + return; + } + } + + privPushText( "Valid parameters are 0 ( hide ) or 1 ( show )." ); +} + +void UIConsole::writeLog( const std::string& text ) { + std::vector strings = String::split( String( text ) ); + for ( size_t i = 0; i < strings.size(); i++ ) + privPushText( strings[i] ); +} + +const bool& UIConsole::isShowingFps() const { + return mShowFps; +} + +void UIConsole::showFps( const bool& show ) { + mShowFps = show; +} + +void UIConsole::copy() { + getUISceneNode()->getWindow()->getClipboard()->setText( mDoc.getSelectedText().toUtf8() ); +} + +void UIConsole::cut() { + getUISceneNode()->getWindow()->getClipboard()->setText( mDoc.getSelectedText().toUtf8() ); + mDoc.deleteSelection(); +} + +bool UIConsole::getEscapePastedText() const { + return mEscapePastedText; +} + +void UIConsole::setEscapePastedText( bool escapePastedText ) { + mEscapePastedText = escapePastedText; +} + +void UIConsole::paste() { + String pasted( getUISceneNode()->getWindow()->getClipboard()->getText() ); + if ( mEscapePastedText ) { + pasted.escape(); + } else { + String::replaceAll( pasted, "\n", "" ); + } + mDoc.textInput( pasted ); + sendCommonEvent( Event::OnTextPasted ); +} + +Uint32 UIConsole::onKeyDown( const KeyEvent& event ) { + if ( ( event.getKeyCode() == KEY_TAB ) && + mDoc.getSelection().start().column() == (Int64)mDoc.getCurrentLine().size() - 1 ) { + printCommandsStartingWith( mDoc.getCurrentLine().getTextWithoutNewLine() ); + getFilesFrom( mDoc.getCurrentLine().getTextWithoutNewLine().toUtf8(), + mDoc.getSelection().start().column() ); + return 1; + } + + if ( event.getMod() & KEYMOD_SHIFT ) { + if ( event.getKeyCode() == KEY_UP && mCon.min - mCon.modif > 0 ) { + mCon.modif++; + invalidateDraw(); + return 1; + } + + if ( event.getKeyCode() == KEY_DOWN && mCon.modif > 0 ) { + mCon.modif--; + invalidateDraw(); + return 1; + } + + if ( event.getKeyCode() == KEY_HOME ) { + size_t size; + { + Lock l( mMutex ); + size = mCmdLog.size(); + } + if ( static_cast( size ) > linesOnScreen() ) { + mCon.modif = mCon.min; + invalidateDraw(); + return 1; + } + } + + if ( event.getKeyCode() == KEY_END ) { + mCon.modif = 0; + invalidateDraw(); + return 1; + } + + if ( event.getKeyCode() == KEY_PAGEUP ) { + if ( mCon.min - mCon.modif - linesOnScreen() / 2 > 0 ) + mCon.modif += linesOnScreen() / 2; + else + mCon.modif = mCon.min; + invalidateDraw(); + return 1; + } + + if ( event.getKeyCode() == KEY_PAGEDOWN ) { + if ( mCon.modif - linesOnScreen() / 2 > 0 ) + mCon.modif -= linesOnScreen() / 2; + else + mCon.modif = 0; + invalidateDraw(); + return 1; + } + } else { + if ( mLastCommands.size() > 0 ) { + if ( event.getKeyCode() == KEY_UP && mLastLogPos > 0 ) { + mLastLogPos--; + } + + if ( event.getKeyCode() == KEY_DOWN && + mLastLogPos < static_cast( mLastCommands.size() ) ) { + mLastLogPos++; + } + + if ( event.getKeyCode() == KEY_UP || event.getKeyCode() == KEY_DOWN ) { + if ( mLastLogPos == static_cast( mLastCommands.size() ) ) { + mDoc.replaceCurrentLine( "" ); + } else { + mDoc.replaceCurrentLine( mLastCommands[mLastLogPos] ); + mDoc.moveToEndOfLine(); + } + invalidateDraw(); + return 1; + } + } + } + + std::string cmd = mKeyBindings.getCommandFromKeyBind( { event.getKeyCode(), event.getMod() } ); + if ( !cmd.empty() ) { + mDoc.execute( cmd ); + return 1; + } + return UIWidget::onKeyDown( event ); +} + +Uint32 UIConsole::onTextInput( const TextInputEvent& event ) { + Input* input = getUISceneNode()->getWindow()->getInput(); + + if ( ( input->isLeftAltPressed() && !event.getText().empty() && event.getText()[0] == '\t' ) || + input->isControlPressed() || input->isMetaPressed() || input->isLeftAltPressed() ) + return 0; + + const String& text = event.getText(); + + for ( size_t i = 0; i < text.size(); i++ ) { + if ( text[i] == '\n' ) + return 0; + } + + mDoc.textInput( text ); + invalidateDraw(); + return 1; +} +Uint32 UIConsole::onPressEnter() { + processLine(); + sendCommonEvent( Event::OnPressEnter ); + invalidateDraw(); + return 0; +} +void UIConsole::registerCommands() { + mDoc.setCommand( "copy", [&] { copy(); } ); + mDoc.setCommand( "cut", [&] { cut(); } ); + mDoc.setCommand( "paste", [&] { paste(); } ); + mDoc.setCommand( "press-enter", [&] { onPressEnter(); } ); +} + +void UIConsole::registerKeybindings() { + mKeyBindings.addKeybinds( { + { { KEY_BACKSPACE, KeyMod::getDefaultModifier() }, "delete-to-previous-word" }, + { { KEY_BACKSPACE, KEYMOD_SHIFT }, "delete-to-previous-char" }, + { { KEY_BACKSPACE, 0 }, "delete-to-previous-char" }, + { { KEY_DELETE, KeyMod::getDefaultModifier() }, "delete-to-next-word" }, + { { KEY_DELETE, 0 }, "delete-to-next-char" }, + { { KEY_KP_ENTER, 0 }, "press-enter" }, + { { KEY_RETURN, 0 }, "press-enter" }, + { { KEY_LEFT, KeyMod::getDefaultModifier() | KEYMOD_SHIFT }, "select-to-previous-word" }, + { { KEY_LEFT, KeyMod::getDefaultModifier() }, "move-to-previous-word" }, + { { KEY_LEFT, KEYMOD_SHIFT }, "select-to-previous-char" }, + { { KEY_LEFT, 0 }, "move-to-previous-char" }, + { { KEY_RIGHT, KeyMod::getDefaultModifier() | KEYMOD_SHIFT }, "select-to-next-word" }, + { { KEY_RIGHT, KeyMod::getDefaultModifier() }, "move-to-next-word" }, + { { KEY_RIGHT, KEYMOD_SHIFT }, "select-to-next-char" }, + { { KEY_RIGHT, 0 }, "move-to-next-char" }, + { { KEY_Z, KeyMod::getDefaultModifier() | KEYMOD_SHIFT }, "redo" }, + { { KEY_HOME, KeyMod::getDefaultModifier() | KEYMOD_SHIFT }, "select-to-start-of-doc" }, + { { KEY_HOME, KEYMOD_SHIFT }, "select-to-start-of-content" }, + { { KEY_HOME, KeyMod::getDefaultModifier() }, "move-to-start-of-doc" }, + { { KEY_HOME, 0 }, "move-to-start-of-content" }, + { { KEY_END, KeyMod::getDefaultModifier() | KEYMOD_SHIFT }, "select-to-end-of-doc" }, + { { KEY_END, KEYMOD_SHIFT }, "select-to-end-of-line" }, + { { KEY_END, KeyMod::getDefaultModifier() }, "move-to-end-of-doc" }, + { { KEY_END, 0 }, "move-to-end-of-line" }, + { { KEY_Y, KeyMod::getDefaultModifier() }, "redo" }, + { { KEY_Z, KeyMod::getDefaultModifier() }, "undo" }, + { { KEY_C, KeyMod::getDefaultModifier() }, "copy" }, + { { KEY_X, KeyMod::getDefaultModifier() }, "cut" }, + { { KEY_V, KeyMod::getDefaultModifier() }, "paste" }, + { { KEY_A, KeyMod::getDefaultModifier() }, "select-all" }, + } ); +} + +void UIConsole::resetCursor() { + mCursorVisible = true; + mBlinkTimer.restart(); +} + +Uint32 UIConsole::onFocus() { + UINode::onFocus(); + + resetCursor(); + + getSceneNode()->getWindow()->startTextInput(); + + return 1; +} + +Uint32 UIConsole::onFocusLoss() { + getSceneNode()->getWindow()->stopTextInput(); + mCursorVisible = false; + invalidateDraw(); + return UIWidget::onFocusLoss(); +} + +bool UIConsole::isTextSelectionEnabled() const { + return 0 != ( mFlags & UI_TEXT_SELECTION_ENABLED ); +} + +Uint32 UIConsole::onMouseDown( const Vector2i& position, const Uint32& flags ) { + UIWidget::onMouseDown( position, flags ); + + if ( NULL != getEventDispatcher() && isTextSelectionEnabled() && ( flags & EE_BUTTON_LMASK ) && + getEventDispatcher()->getMouseDownNode() == this ) { + getUISceneNode()->getWindow()->getInput()->captureMouse( true ); + mMouseDown = true; + } + + return 1; +} + +Uint32 UIConsole::onMouseUp( const Vector2i& position, const Uint32& flags ) { + if ( flags == EE_BUTTON_WUMASK ) { + if ( mCon.min - mCon.modif - 6 > 0 ) { + mCon.modif += 6; + } else { + mCon.modif = mCon.min; + } + } else if ( flags == EE_BUTTON_WDMASK ) { + if ( mCon.modif - 6 > 0 ) { + mCon.modif -= 6; + } else { + mCon.modif = 0; + } + } else if ( flags & EE_BUTTON_LMASK ) { + if ( mMouseDown ) { + mMouseDown = false; + getUISceneNode()->getWindow()->getInput()->captureMouse( false ); + } + } else if ( ( flags & EE_BUTTON_RMASK ) ) { + // onCreateContextMenu( position, flags ); + } + return UIWidget::onMouseUp( position, flags ); +} + +Uint32 UIConsole::onMouseClick( const Vector2i& position, const Uint32& flags ) { + return UIWidget::onMouseClick( position, flags ); +} + +Uint32 UIConsole::onMouseDoubleClick( const Vector2i& Pos, const Uint32& Flags ) { + return UIWidget::onMouseDoubleClick( Pos, Flags ); +} + +Uint32 UIConsole::onMouseOver( const Vector2i& position, const Uint32& flags ) { + return UIWidget::onMouseOver( position, flags ); +} + +Uint32 UIConsole::onMouseLeave( const Vector2i& Pos, const Uint32& Flags ) { + return UIWidget::onMouseLeave( Pos, Flags ); +} + +void UIConsole::onDocumentTextChanged() { + resetCursor(); + + invalidateDraw(); + + sendCommonEvent( Event::OnBufferChange ); +} + +void UIConsole::onDocumentCursorChange( const TextPosition& ) { + resetCursor(); + invalidateDraw(); +} + +void UIConsole::onDocumentSelectionChange( const TextRange& ) { + onSelectionChange(); +} + +void UIConsole::onDocumentLineCountChange( const size_t&, const size_t& ) { + invalidateDraw(); +} + +void UIConsole::onDocumentLineChanged( const Int64& ) { + invalidateDraw(); +} + +void UIConsole::onDocumentUndoRedo( const TextDocument::UndoRedo& ) { + onSelectionChange(); +} + +void UIConsole::onDocumentSaved( TextDocument* ) {} + +void UIConsole::onDocumentMoved( TextDocument* ) {} + +void UIConsole::onSelectionChange() { + invalidateDraw(); +} + +String UIConsole::getLastCommonSubStr( std::list& cmds ) { + String lastCommon( mDoc.getCurrentLine().getTextWithoutNewLine() ); + String strTry( lastCommon ); + + std::list::iterator ite; + + bool found = false; + + do { + found = false; + + bool allEqual = true; + + String strBeg( ( *cmds.begin() ) ); + + if ( strTry.size() + 1 <= strBeg.size() ) { + strTry = String( strBeg.substr( 0, strTry.size() + 1 ) ); + + for ( ite = ++cmds.begin(); ite != cmds.end(); ++ite ) { + String& strCur = ( *ite ); + + if ( !( strTry.size() <= strCur.size() && + strTry == strCur.substr( 0, strTry.size() ) ) ) { + allEqual = false; + } + } + + if ( allEqual ) { + lastCommon = strTry; + + found = true; + } + } + } while ( found ); + + return lastCommon; +} + +void UIConsole::printCommandsStartingWith( const String& start ) { + std::list cmds; + + for ( auto it = mCallbacks.begin(); it != mCallbacks.end(); ++it ) { + if ( String::startsWith( it->first, start ) ) { + cmds.push_back( it->first ); + } + } + + if ( cmds.size() > 1 ) { + privPushText( "> " + mDoc.getCurrentLine().getTextWithoutNewLine() ); + + std::list::iterator ite; + + for ( ite = cmds.begin(); ite != cmds.end(); ++ite ) + privPushText( ( *ite ) ); + + String newStr( getLastCommonSubStr( cmds ) ); + + if ( newStr != mDoc.getCurrentLine().getTextWithoutNewLine() ) { + mDoc.replaceCurrentLine( newStr ); + mDoc.moveToEndOfLine(); + } + } else if ( cmds.size() ) { + mDoc.replaceCurrentLine( cmds.front() ); + mDoc.moveToEndOfLine(); + } +} + +void UIConsole::updateCacheSize() { + Int32 maxLines = maxLinesOnScreen(); + if ( maxLines > (Int64)mTextCache.size() ) + mTextCache.resize( maxLines ); +} + +void UIConsole::onSizeChange() { + updateCacheSize(); + return UIWidget::onSizeChange(); +} + +void UIConsole::getFilesFrom( std::string txt, const Uint32& curPos ) { + static char OSSlash = FileSystem::getOSSlash().at( 0 ); + size_t pos; + + if ( std::string::npos != ( pos = txt.find_last_of( OSSlash ) ) && pos <= curPos ) { + size_t fpos = txt.find_first_of( OSSlash ); + + std::string dir( txt.substr( fpos, pos - fpos + 1 ) ); + std::string file( txt.substr( pos + 1 ) ); + + if ( FileSystem::isDirectory( dir ) ) { + size_t count = 0, lasti = 0; + std::vector files = FileSystem::filesGetInPath( dir, true, true ); + String res; + bool again = false; + + do { + std::vector foundFiles; + res = ""; + count = 0; + again = false; + + for ( size_t i = 0; i < files.size(); i++ ) { + if ( !file.size() || String::startsWith( files[i], file ) ) { + res += "\t" + files[i] + "\n"; + count++; + lasti = i; + foundFiles.push_back( files[i] ); + } + } + + if ( count > 1 ) { + bool allBigger = true; + bool allStartsWith = true; + + do { + allBigger = true; + + for ( size_t i = 0; i < foundFiles.size(); i++ ) { + if ( foundFiles[i].size() < file.size() + 1 ) { + allBigger = false; + break; + } + } + + if ( allBigger ) { + std::string tfile = foundFiles[0].substr( 0, file.size() + 1 ); + allStartsWith = true; + + for ( size_t i = 0; i < foundFiles.size(); i++ ) { + if ( !String::startsWith( foundFiles[i], tfile ) ) { + allStartsWith = false; + break; + } + } + + if ( allStartsWith ) { + file = tfile; + again = true; + } + } + } while ( allBigger && allStartsWith ); + } + } while ( again ); + + if ( count == 1 ) { + std::string slash = ""; + + if ( FileSystem::isDirectory( dir + files[lasti] ) ) { + slash = FileSystem::getOSSlash(); + } + + mDoc.replaceCurrentLine( mDoc.getCurrentLine().getText().substr( 0, pos + 1 ) + + files[lasti] + slash ); + } else if ( count > 1 ) { + privPushText( "Directory file list:" ); + pushText( res ); + mDoc.replaceCurrentLine( mDoc.getCurrentLine().getText().substr( 0, pos + 1 ) + + file ); + } + mDoc.moveToEndOfLine(); + invalidateDraw(); + } + } +} + +void UIConsole::pushText( const String& str ) { + if ( std::string::npos != str.find_first_of( '\n' ) ) { + std::vector Strings = String::split( String( str ) ); + + for ( Uint32 i = 0; i < Strings.size(); i++ ) { + privPushText( Strings[i] ); + } + } else { + privPushText( str ); + } +} + +void UIConsole::pushText( const char* format, ... ) { + int n, size = 256; + std::string tstr( size, '\0' ); + + va_list args; + + while ( 1 ) { + va_start( args, format ); + + n = vsnprintf( &tstr[0], size, format, args ); + + if ( n > -1 && n < size ) { + tstr.resize( n ); + + pushText( tstr ); + + va_end( args ); + + return; + } + + if ( n > -1 ) // glibc 2.1 + size = n + 1; // precisely what is needed + else // glibc 2.0 + size *= 2; // twice the old size + + tstr.resize( size ); + } +} + +Float UIConsole::getLineHeight() const { + return mFontStyleConfig.Font->getFontHeight( + PixelDensity::dpToPx( mFontStyleConfig.CharacterSize ) ); +} + +bool UIConsole::getQuakeMode() const { + return mQuakeMode; +} + +void UIConsole::setQuakeMode( bool quakeMode ) { + if ( mQuakeMode != quakeMode ) { + mQuakeMode = quakeMode; + + if ( mQuakeMode ) { + setParent( mUISceneNode->getRoot() ); + Sizef ps( mUISceneNode->getRoot()->getPixelsSize() ); + setPixelsSize( { ps.getWidth(), eefloor( ps.getHeight() * mQuakeModeHeightPercent ) } ); + setPosition( { 0, 0 } ); + } + } +} + +void UIConsole::show() { + if ( !mQuakeMode ) { + setVisible( true ); + setEnabled( true ); + return; + } + if ( mHiding ) + return; + + setVisible( true ); + setEnabled( true ); + toFront(); + mFading = true; + auto* spawn = Actions::Spawn::New( + { Actions::FadeIn::New( Seconds( .25f ) ), + Actions::Move::New( { 0, -getSize().getHeight() }, { 0, 0 }, Seconds( .25f ) ) } ); + runAction( Actions::Sequence::New( { spawn, Actions::Runnable::New( [&] { + setVisible( true ); + setEnabled( true ); + mFading = false; + setFocus(); + } ) } ) ); +} + +void UIConsole::hide() { + if ( !mQuakeMode ) { + setVisible( false ); + setEnabled( false ); + return; + } + if ( mFading ) + return; + + mHiding = true; + setVisible( true ); + setEnabled( true ); + auto* spawn = Actions::Spawn::New( + { Actions::FadeOut::New( Seconds( .25f ) ), + Actions::Move::New( { 0, 0 }, { 0, -getSize().getHeight() }, Seconds( .25f ) ) } ); + runAction( Actions::Sequence::New( { spawn, Actions::Runnable::New( [&] { + setVisible( false ); + setEnabled( false ); + mHiding = false; + } ) } ) ); +} + +void UIConsole::toggle() { + if ( isVisible() ) { + hide(); + } else { + show(); + } +} + +bool UIConsole::isActive() const { + return isVisible() && !mHiding; +} + +Float UIConsole::getQuakeModeHeightPercent() const { + return mQuakeModeHeightPercent; +} + +void UIConsole::setQuakeModeHeightPercent( const Float& quakeModeHeightPercent ) { + mQuakeModeHeightPercent = quakeModeHeightPercent; +} + +static std::vector splitCommandParams( String str ) { + std::vector params = String::split( str, ' ' ); + std::vector rparams; + String tstr; + + for ( size_t i = 0; i < params.size(); i++ ) { + String tparam = params[i]; + + if ( !tparam.empty() ) { + if ( '"' == tparam[0] ) { + tstr += tparam; + } else if ( '"' == tparam[tparam.size() - 1] ) { + tstr += " " + tparam; + + rparams.push_back( String::trim( tstr, '"' ) ); + + tstr = ""; + } else if ( !tstr.empty() ) { + tstr += " " + tparam; + } else { + rparams.push_back( tparam ); + } + } + } + + if ( !tstr.empty() ) { + rparams.push_back( String::trim( tstr, '"' ) ); + } + + return rparams; +} + +void UIConsole::processLine() { + String str( mDoc.getCurrentLine().getTextWithoutNewLine() ); + std::vector params = splitCommandParams( str ); + + mLastCommands.push_back( str ); + mLastLogPos = (int)mLastCommands.size(); + + if ( mLastCommands.size() > 20 ) + mLastCommands.pop_front(); + + if ( str.size() > 0 ) { + privPushText( "> " + str ); + + if ( mCallbacks.find( params[0] ) != mCallbacks.end() ) { + mCallbacks[params[0]]( params ); + } else { + privPushText( "Unknown Command: '" + params[0] + "'" ); + } + } + mDoc.replaceCurrentLine( "" ); + invalidateDraw(); +} + +}} // namespace EE::UI diff --git a/src/eepp/ui/uitextinput.cpp b/src/eepp/ui/uitextinput.cpp index 0de6b020e..b8322a7d6 100644 --- a/src/eepp/ui/uitextinput.cpp +++ b/src/eepp/ui/uitextinput.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include namespace EE { namespace UI { diff --git a/src/eepp/ui/uiwidgetcreator.cpp b/src/eepp/ui/uiwidgetcreator.cpp index 61d7f4539..1a5955e0a 100644 --- a/src/eepp/ui/uiwidgetcreator.cpp +++ b/src/eepp/ui/uiwidgetcreator.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -88,6 +89,7 @@ void UIWidgetCreator::createBaseWidgetList() { registeredWidget["tableview"] = UITableView::New; registeredWidget["listview"] = UIListView::New; registeredWidget["stackwidget"] = UIStackWidget::New; + registeredWidget["console"] = UIConsole::New; registeredWidget["hbox"] = UILinearLayout::NewHorizontal; registeredWidget["vbox"] = UILinearLayout::NewVertical; diff --git a/src/tools/ecode/ecode.cpp b/src/tools/ecode/ecode.cpp index a11070a2e..608bc0f87 100644 --- a/src/tools/ecode/ecode.cpp +++ b/src/tools/ecode/ecode.cpp @@ -408,14 +408,11 @@ void App::closeApp() { void App::mainLoop() { mWindow->getInput()->update(); - Time elapsed = SceneManager::instance()->getElapsed(); SceneManager::instance()->update(); - if ( SceneManager::instance()->getUISceneNode()->invalidated() || mConsole->isActive() || - mConsole->isFading() ) { + if ( SceneManager::instance()->getUISceneNode()->invalidated() ) { mWindow->clear(); SceneManager::instance()->draw(); - mConsole->draw( elapsed ); mWindow->display(); if ( firstFrame ) { Log::info( "First frame took: %.2fms", globalClock.getElapsed().asMilliseconds() ); @@ -2330,11 +2327,7 @@ UITerminal* App::createNewTerminal( const std::string& title, UITabWidget* inTab term->setCommand( "close-app", [&] { closeApp(); } ); term->setCommand( "open-file", [&] { openFileDialog(); } ); term->setCommand( "open-folder", [&] { openFolderDialog(); } ); - term->setCommand( "console-toggle", [&] { - mConsole->toggle(); - bool lock = mConsole->isActive(); - mSplitter->forEachEditor( [lock]( UICodeEditor* editor ) { editor->setLocked( lock ); } ); - } ); + term->setCommand( "console-toggle", [&] { consoleToggle(); } ); term->setCommand( "menu-toggle", [&] { toggleSettingsMenu(); } ); term->setCommand( "open-global-search", [&] { showGlobalSearch(); } ); term->setCommand( "open-locatebar", [&] { mFileLocator->showLocateBar(); } ); @@ -2445,11 +2438,7 @@ void App::onCodeEditorCreated( UICodeEditor* editor, TextDocument& doc ) { doc.setCommand( "fullscreen-toggle", [&]() { fullscreenToggle(); } ); doc.setCommand( "open-file", [&] { openFileDialog(); } ); doc.setCommand( "open-folder", [&] { openFolderDialog(); } ); - doc.setCommand( "console-toggle", [&] { - mConsole->toggle(); - bool lock = mConsole->isActive(); - mSplitter->forEachEditor( [lock]( UICodeEditor* editor ) { editor->setLocked( lock ); } ); - } ); + doc.setCommand( "console-toggle", [&] { consoleToggle(); } ); doc.setCommand( "lock", [&] { if ( mSplitter->curEditorExistsAndFocused() ) { mSplitter->getCurEditor()->setLocked( true ); @@ -3130,6 +3119,12 @@ void App::newFolder( const FileInfo& file ) { } ); } +void App::consoleToggle() { + mConsole->toggle(); + bool lock = mConsole->isActive(); + mSplitter->forEachEditor( [lock]( UICodeEditor* editor ) { editor->setLocked( lock ); } ); +} + void App::createProjectTreeMenu( const FileInfo& file ) { if ( mProjectTreeMenu && mProjectTreeMenu->isVisible() ) mProjectTreeMenu->close(); @@ -3921,7 +3916,9 @@ void App::init( std::string file, const Float& pidelDensity, const std::string& mSplitter->createEditorWithTabWidget( mBaseLayout ); - mConsole = eeNew( Console, ( mFontMono, true, true, 1024 * 1000, 0, mWindow ) ); + mConsole = UIConsole::NewOpt( mFontMono, true, true, 1024 * 10 ); + mConsole->setQuakeMode( true ); + mConsole->setVisible( false ); Log::info( "Complete UI took: %.2fms", globalClock.getElapsedTime().asMilliseconds() ); diff --git a/src/tools/ecode/ecode.hpp b/src/tools/ecode/ecode.hpp index e49685e78..48adbc7ab 100644 --- a/src/tools/ecode/ecode.hpp +++ b/src/tools/ecode/ecode.hpp @@ -106,10 +106,12 @@ class App : public UICodeEditorSplitter::Client { void newFolder( const FileInfo& file ); + void consoleToggle(); + protected: EE::Window::Window* mWindow{ nullptr }; UISceneNode* mUISceneNode{ nullptr }; - Console* mConsole{ nullptr }; + UIConsole* mConsole{ nullptr }; std::string mWindowTitle{ "ecode" }; UILayout* mMainLayout{ nullptr }; UILayout* mBaseLayout{ nullptr }; diff --git a/src/tools/mapeditor/mapeditor.cpp b/src/tools/mapeditor/mapeditor.cpp index 5d1c40d51..cd681c5f1 100644 --- a/src/tools/mapeditor/mapeditor.cpp +++ b/src/tools/mapeditor/mapeditor.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include using namespace EE; @@ -20,14 +21,13 @@ EE::Window::Window* win = NULL; UIMessageBox* MsgBox = NULL; MapEditor* Editor = NULL; -bool onCloseRequestCallback( EE::Window::Window* w ) { +bool onCloseRequestCallback( EE::Window::Window* ) { if ( NULL != Editor ) { MsgBox = UIMessageBox::New( UIMessageBox::OK_CANCEL, "Do you really want to close the current map?\nAll changes will be lost." ); - MsgBox->addEventListener( Event::MsgBoxConfirmClick, - []( const Event* event ) { win->close(); } ); - MsgBox->addEventListener( Event::OnClose, []( const Event* event ) { MsgBox = NULL; } ); + MsgBox->addEventListener( Event::MsgBoxConfirmClick, []( const Event* ) { win->close(); } ); + MsgBox->addEventListener( Event::OnClose, []( const Event* ) { MsgBox = NULL; } ); MsgBox->setTitle( "Close Map?" ); MsgBox->center(); MsgBox->show(); @@ -73,7 +73,7 @@ void mainLoop() { } } -EE_MAIN_FUNC int main( int argc, char* argv[] ) { +EE_MAIN_FUNC int main( int, char*[] ) { DisplayManager* displayManager = Engine::instance()->getDisplayManager(); displayManager->enableScreenSaver(); displayManager->enableMouseFocusClickThrough(); diff --git a/src/tools/textureatlaseditor/textureatlaseditor.cpp b/src/tools/textureatlaseditor/textureatlaseditor.cpp index e213e449e..a3516dce7 100644 --- a/src/tools/textureatlaseditor/textureatlaseditor.cpp +++ b/src/tools/textureatlaseditor/textureatlaseditor.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include using namespace EE; @@ -19,14 +20,14 @@ EE::Window::Window* win = NULL; UIMessageBox* MsgBox = NULL; TextureAtlasEditor* Editor = NULL; -bool onCloseRequestCallback( EE::Window::Window* w ) { +bool onCloseRequestCallback( EE::Window::Window* ) { if ( NULL != Editor && Editor->isEdited() ) { MsgBox = UIMessageBox::New( UIMessageBox::OK_CANCEL, "Do you really want to close the texture atlas editor?\nAll changes will be lost." ); MsgBox->addEventListener( Event::MsgBoxConfirmClick, - []( const Event* event ) { win->close(); } ); - MsgBox->addEventListener( Event::OnClose, []( const Event* event ) { MsgBox = NULL; } ); + []( const Event* ) { win->close(); } ); + MsgBox->addEventListener( Event::OnClose, []( const Event* ) { MsgBox = NULL; } ); MsgBox->setTitle( "Close Texture Atlas Editor?" ); MsgBox->center(); MsgBox->show(); @@ -72,7 +73,7 @@ void mainLoop() { } } -EE_MAIN_FUNC int main( int argc, char* argv[] ) { +EE_MAIN_FUNC int main( int, char*[] ) { DisplayManager* displayManager = Engine::instance()->getDisplayManager(); displayManager->enableScreenSaver(); displayManager->enableMouseFocusClickThrough();