Added eterm::UITerminal.

Many changes over ecode. Working on adding terminal support in ecode. Basic support is working, may contain some bugs.
This commit is contained in:
Martín Lucas Golini
2022-07-05 22:34:48 -03:00
parent c06eaa8d78
commit 00c5515fd0
34 changed files with 772 additions and 198 deletions

View File

@@ -12,12 +12,14 @@ namespace EE {
class EE_API AllocatedPointer {
public:
AllocatedPointer( void* Data, const std::string& File, int Line, size_t Memory );
AllocatedPointer( void* data, const std::string& File, int Line, size_t memory,
bool track = false );
std::string mFile;
int mLine;
size_t mMemory;
void* mData;
bool mTrack;
};
typedef std::map<void*, AllocatedPointer> AllocatedPointerMap;
@@ -27,31 +29,31 @@ class EE_API MemoryManager {
public:
static void* addPointer( const AllocatedPointer& aAllocatedPointer );
static void* addPointerInPlace( void* Place, const AllocatedPointer& aAllocatedPointer );
static void* addPointerInPlace( void* place, const AllocatedPointer& aAllocatedPointer );
static bool removePointer( void* Data );
static bool removePointer( void* data, const char* file, const size_t& line );
static void showResults();
template <class T> static T* deletePtr( T* Data ) {
delete Data;
return Data;
template <class T> static T* deletePtr( T* data ) {
delete data;
return data;
}
template <class T> static T* deleteArrayPtr( T* Data ) {
delete[] Data;
return Data;
template <class T> static T* deleteArrayPtr( T* data ) {
delete[] data;
return data;
}
template <class T> static T* free( T* Data ) {
::free( Data );
template <class T> static T* free( T* data ) {
::free( data );
#if defined( __GNUC__ ) && __GNUC__ >= 12
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wuse-after-free"
return Data;
return data;
#pragma GCC diagnostic pop
#else
return Data;
return data;
#endif
}
@@ -67,6 +69,10 @@ class EE_API MemoryManager {
};
#ifdef EE_MEMORY_MANAGER
#define eeNewTracked( classType, constructor ) \
(classType*)EE::MemoryManager::addPointer( EE::AllocatedPointer( \
new classType constructor, __FILE__, __LINE__, sizeof( classType ), true ) )
#define eeNew( classType, constructor ) \
(classType*)EE::MemoryManager::addPointer( EE::AllocatedPointer( \
new classType constructor, __FILE__, __LINE__, sizeof( classType ) ) )
@@ -84,25 +90,30 @@ class EE_API MemoryManager {
EE::MemoryManager::addPointer( EE::AllocatedPointer( EE::MemoryManager::allocate( amount ), \
__FILE__, __LINE__, amount ) )
#define eeDelete( data ) \
{ \
if ( EE::MemoryManager::removePointer( EE::MemoryManager::deletePtr( data ) ) == false ) \
printf( "Deleting at '%s' %d\n", __FILE__, __LINE__ ); \
#define eeDelete( data ) \
{ \
if ( EE::MemoryManager::removePointer( EE::MemoryManager::deletePtr( data ), __FILE__, \
__LINE__ ) == false ) \
printf( "Deleting at '%s' %d\n", __FILE__, __LINE__ ); \
}
#define eeDeleteArray( data ) \
{ \
if ( EE::MemoryManager::removePointer( EE::MemoryManager::deleteArrayPtr( data ) ) == \
false ) \
printf( "Deleting at '%s' %d\n", __FILE__, __LINE__ ); \
#define eeDeleteArray( data ) \
{ \
if ( EE::MemoryManager::removePointer( EE::MemoryManager::deleteArrayPtr( data ), \
__FILE__, __LINE__ ) == false ) \
printf( "Deleting at '%s' %d\n", __FILE__, __LINE__ ); \
}
#define eeFree( data ) \
{ \
if ( EE::MemoryManager::removePointer( EE::MemoryManager::free( data ) ) == false ) \
printf( "Deleting at '%s' %d\n", __FILE__, __LINE__ ); \
#define eeFree( data ) \
{ \
if ( EE::MemoryManager::removePointer( EE::MemoryManager::free( data ), __FILE__, \
__LINE__ ) == false ) \
printf( "Deleting at '%s' %d\n", __FILE__, __LINE__ ); \
}
#else
#define eeNewTracked( classType, constructor ) new classType constructor
#define eeNew( classType, constructor ) new classType constructor
#define eeNewInPlace( place, classType, constructor ) new place classType constructor

View File

@@ -2,6 +2,7 @@
#define EE_UICUIEVENT_HPP
#include <eepp/config.hpp>
#include <string>
namespace EE { namespace Scene {
@@ -85,6 +86,7 @@ class EE_API Event {
OnMenuShow,
OnMenuHide,
OnEditorTabReady,
OnTitleChange,
NoEvent = eeINDEX_NOT_FOUND
};
@@ -115,6 +117,17 @@ class EE_API DropEvent : public Event {
Node* droppedNode;
};
class EE_API TextEvent : public Event {
public:
TextEvent( Node* node, const Uint32& eventType, const std::string& txt ) :
Event( node, eventType ), text( txt ) {}
const std::string& getText() const { return text; }
protected:
std::string text;
};
}} // namespace EE::Scene
#endif

View File

@@ -217,6 +217,8 @@ class EE_API Node : public Transformable {
void sendCommonEvent( const Uint32& Event );
void sendTextEvent( const Uint32& event, const std::string& text );
void childsCloseAll();
const std::string& getId() const;

View File

@@ -123,6 +123,10 @@ class EE_API IniFile {
int getValueI( std::string const keyname, std::string const valuename,
int const defValue = 0 ) const;
/** Gets the value as an unsigned long */
unsigned long getValueU( std::string const keyname, std::string const valuename,
unsigned long const defValue = 0 ) const;
/** Gets the value as boolean */
bool getValueB( std::string const keyname, std::string const valuename,
bool const defValue = false ) const;
@@ -164,6 +168,15 @@ class EE_API IniFile {
bool setValueI( std::string const keyname, std::string const valuename, int const value,
bool create = true );
/** Sets a unsigned long value from a keyname and a valuename
* @param keyname The key name
* @param valuename The value name
* @param value The value to assign
* @param create If true it will create the keyname if doesn't exists
*/
bool setValueU( std::string const keyname, std::string const valuename,
unsigned long const value, bool create = true );
/** Sets a boolean value from a keyname and a valuename
* @param keyname The key name
* @param valuename The value name

View File

@@ -284,6 +284,8 @@ class EE_API TextDocument {
void execute( const std::string& command );
void setCommands( const std::map<std::string, DocumentCommand>& cmds );
void setCommand( const std::string& command, DocumentCommand func );
bool hasCommand( const std::string& command );

View File

@@ -26,6 +26,8 @@ class EE_API UICodeEditorSplitter {
virtual void onCodeEditorFocusChange( UICodeEditor* editor ) = 0;
virtual void onWidgetFocusChange( UIWidget* widget ) = 0;
virtual void onDocumentStateChanged( UICodeEditor* editor, TextDocument& doc ) = 0;
virtual void onDocumentModified( UICodeEditor* editor, TextDocument& doc ) = 0;
@@ -39,18 +41,20 @@ class EE_API UICodeEditorSplitter {
virtual void onDocumentLoaded( UICodeEditor* codeEditor, const std::string& path ) = 0;
};
static std::vector<std::string> getUnlockedCommands();
static UICodeEditorSplitter* New( UICodeEditorSplitter::Client* client, UISceneNode* sceneNode,
const std::vector<SyntaxColorScheme>& colorSchemes = {},
const std::string& initColorScheme = "" );
virtual ~UICodeEditorSplitter();
virtual bool tryTabClose( UICodeEditor* editor );
virtual bool tryTabClose(UIWidget* widget );
void closeEditorTab( UICodeEditor* editor );
void closeTab( UIWidget* widget );
UISplitter* splitEditor( const SplitDirection& direction, UICodeEditor* editor,
bool openCurEditor = true );
UISplitter* split( const SplitDirection& direction, UIWidget* editor,
bool openCurEditor = true );
void switchToTab( Int32 index );
@@ -66,10 +70,18 @@ class EE_API UICodeEditorSplitter {
UITabWidget* tabWidgetFromEditor( UICodeEditor* editor ) const;
UITabWidget* tabWidgetFromWidget( UIWidget* widget ) const;
UISplitter* splitterFromEditor( UICodeEditor* editor ) const;
UISplitter* splitterFromWidget( UIWidget* widget ) const;
std::pair<UITab*, UICodeEditor*> createCodeEditorInTabWidget( UITabWidget* tabWidget );
std::pair<UITab*, UIWidget*> createWidgetInTabWidget( UITabWidget* tabWidget, UIWidget* widget,
const std::string& tabName,
bool focus = true );
UICodeEditor* createCodeEditor();
void focusSomeEditor( Node* searchFrom = nullptr );
@@ -101,6 +113,8 @@ class EE_API UICodeEditorSplitter {
void applyColorScheme( const SyntaxColorScheme& colorScheme );
void forEachWidgetStoppable( std::function<bool( UIWidget* )> run ) const;
void forEachEditor( std::function<void( UICodeEditor* )> run ) const;
void forEachDoc( std::function<void( TextDocument& doc )> run ) const;
@@ -149,9 +163,16 @@ class EE_API UICodeEditorSplitter {
Node* getBaseLayout() const;
UIWidget* getCurWidget() const;
void setCurentWidget( UIWidget* curWidget );
bool curWidgetExists() const;
protected:
UISceneNode* mUISceneNode{ nullptr };
UICodeEditor* mCurEditor{ nullptr };
UIWidget* mCurWidget{ nullptr };
std::map<std::string, SyntaxColorScheme> mColorSchemes;
std::string mCurrentColorScheme;
std::vector<UITabWidget*> mTabWidgets;

View File

@@ -99,7 +99,9 @@ enum UINodeType {
UI_TYPE_TABLEVIEW,
UI_TYPE_TABLECELL,
UI_TYPE_LISTVIEW,
UI_TYPE_USER = 10000
UI_TYPE_MODULES = 10000,
UI_TYPE_TERMINAL = 10001,
UI_TYPE_USER = 100000
};
enum class ScrollBarMode : Uint32 { Auto, AlwaysOn, AlwaysOff };

View File

@@ -54,6 +54,8 @@ class EE_API UITabWidget : public UIWidget {
UITabWidget* add( UITab* tab );
UITab* getTabFromOwnedWidget( const UIWidget* widget );
UITab* getTab( const Uint32& index );
UITab* getTab( const String& text );

View File

@@ -348,7 +348,7 @@ function build_base_cpp_configuration( package_name )
set_xcode_config()
configuration "debug"
defines { "DEBUG" }
defines { "DEBUG", "EE_DEBUG", "EE_MEMORY_MANAGER" }
flags { "Symbols" }
if not is_vs() then
buildoptions{ "-Wall" }
@@ -1179,16 +1179,20 @@ solution "eepp"
set_kind()
language "C++"
files { "src/tools/ecode/**.cpp" }
includedirs { "src/thirdparty/efsw/include", "src/thirdparty" }
links { "efsw-static" }
includedirs { "src/thirdparty/efsw/include", "src/thirdparty", "src/modules/eterm/include/" }
links { "efsw-static", "eterm-static" }
if not os.is("windows") and not os.is("haiku") then
links { "pthread" }
end
if os.is("macosx") then
links { "CoreFoundation.framework", "CoreServices.framework" }
end
if os.is_real("linux") then
links { "util" }
end
if os.is("haiku") then
links { "bsd" }
end
build_link_configuration( "ecode", true )
project "eterm"

View File

@@ -195,7 +195,7 @@ function build_base_cpp_configuration( package_name )
buildoptions { "-Wall" }
filter "configurations:debug*"
defines { "DEBUG" }
defines { "DEBUG", "EE_DEBUG", "EE_MEMORY_MANAGER" }
symbols "On"
targetname ( package_name .. "-debug" )
@@ -926,13 +926,17 @@ workspace "eepp"
set_kind()
language "C++"
files { "src/tools/ecode/**.cpp" }
incdirs { "src/thirdparty/efsw/include", "src/thirdparty" }
links { "efsw-static" }
incdirs { "src/thirdparty/efsw/include", "src/thirdparty", "src/modules/eterm/include/" }
links { "efsw-static", "eterm-static" }
build_link_configuration( "ecode", true )
filter "system:macosx"
links { "CoreFoundation.framework", "CoreServices.framework" }
filter { "system:not windows", "system:not haiku" }
links { "pthread" }
filter "system:linux"
links { "util" }
filter "system:haiku"
links { "bsd" }
project "eterm"
set_kind()

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 7.0.2, 2022-07-03T19:41:27. -->
<!-- Written by QtCreator 7.0.2, 2022-07-04T12:05:43. -->
<qtcreator>
<data>
<variable>EnvironmentId</variable>
@@ -107,7 +107,7 @@
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{388e5431-b31b-42b3-b9ad-9002d279d75d}</value>
<value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">12</value>
<value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">10</value>
<value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">19</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">

View File

@@ -1013,6 +1013,7 @@
../../src/modules/eterm/include/eterm/terminal/terminaldisplay.hpp
../../src/modules/eterm/include/eterm/terminal/terminalemulator.hpp
../../src/modules/eterm/include/eterm/terminal/terminaltypes.hpp
../../src/modules/eterm/include/eterm/ui/uiterminal.hpp
../../src/modules/eterm/src/eterm/system/autohandle.cpp
../../src/modules/eterm/src/eterm/system/pipe.cpp
../../src/modules/eterm/src/eterm/system/process.cpp
@@ -1026,6 +1027,7 @@
../../src/modules/eterm/src/eterm/terminal/types.hpp
../../src/modules/eterm/src/eterm/terminal/wide.hpp
../../src/modules/eterm/src/eterm/terminal/windowserrors.hpp
../../src/modules/eterm/src/eterm/ui/uiterminal.cpp
../../src/test/eetest.cpp
../../src/tests/test_all/test.cpp
../../src/tests/test_all/test.hpp

View File

@@ -10,3 +10,5 @@
/usr/lib64/gcc/x86_64-suse-linux/10/include
../../src/modules/eterm/src/
../../src/modules/eterm/include/
../../src/modules/eterm/include/eterm/ui
../../src/modules/eterm/src/eterm/ui

View File

@@ -19,18 +19,20 @@ static size_t sPeakMemoryUsage = 0;
static AllocatedPointer sBiggestAllocation = AllocatedPointer( NULL, "", 0, 0 );
static Mutex sAlloMutex;
AllocatedPointer::AllocatedPointer( void* Data, const std::string& File, int Line, size_t Memory ) {
mData = Data;
mFile = File;
mLine = Line;
mMemory = Memory;
AllocatedPointer::AllocatedPointer( void* data, const std::string& file, int line, size_t memory,
bool track ) {
mData = data;
mFile = file;
mLine = line;
mMemory = memory;
mTrack = track;
}
void* MemoryManager::addPointerInPlace( void* Place, const AllocatedPointer& aAllocatedPointer ) {
AllocatedPointerMapIt it = sMapPointers.find( Place );
void* MemoryManager::addPointerInPlace( void* place, const AllocatedPointer& aAllocatedPointer ) {
AllocatedPointerMapIt it = sMapPointers.find( place );
if ( it != sMapPointers.end() ) {
removePointer( Place );
removePointer( place, aAllocatedPointer.mFile.c_str(), aAllocatedPointer.mLine );
}
return addPointer( aAllocatedPointer );
@@ -52,16 +54,23 @@ void* MemoryManager::addPointer( const AllocatedPointer& aAllocatedPointer ) {
sBiggestAllocation = aAllocatedPointer;
}
if ( aAllocatedPointer.mTrack )
eePRINTL( "Allocating pointer %p at '%s' %d", aAllocatedPointer.mData,
aAllocatedPointer.mFile.c_str(), aAllocatedPointer.mLine );
return aAllocatedPointer.mData;
}
bool MemoryManager::removePointer( void* Data ) {
bool MemoryManager::removePointer( void* data, const char* file, const size_t& line ) {
Lock l( sAlloMutex );
AllocatedPointerMapIt it = sMapPointers.find( Data );
AllocatedPointerMapIt it = sMapPointers.find( data );
if ( it->second.mTrack )
eePRINTL( "Deleting pointer %p at '%s' %d", data, file, line );
if ( it == sMapPointers.end() ) {
eePRINTL( "Trying to delete pointer %p created that does not exist!", Data );
eePRINTL( "Trying to delete pointer %p created that does not exist!", data );
return false;
}

View File

@@ -303,6 +303,11 @@ void Node::sendCommonEvent( const Uint32& event ) {
sendEvent( &CommonEvent );
}
void Node::sendTextEvent( const Uint32& event, const std::string& text ) {
TextEvent tevent( this, event, text );
sendEvent( &tevent );
}
Uint32 Node::onTextInput( const TextInputEvent& event ) {
sendEvent( &event );
return 0;

View File

@@ -305,6 +305,14 @@ bool IniFile::setValueI( std::string const keyname, std::string const valuename,
return setValue( keyname, valuename, svalue, create );
}
bool IniFile::setValueU( const std::string keyname, const std::string valuename,
const unsigned long value, bool create ) {
char svalue[MAX_VALUEDATA];
String::formatBuffer( svalue, MAX_VALUEDATA, "%u", value );
return setValue( keyname, valuename, svalue, create );
}
bool IniFile::setValueF( std::string const keyname, std::string const valuename, double const value,
bool create ) {
char svalue[MAX_VALUEDATA];
@@ -356,6 +364,14 @@ int IniFile::getValueI( std::string const keyname, std::string const valuename,
return atoi( getValue( keyname, valuename, svalue ).c_str() );
}
unsigned long IniFile::getValueU( const std::string keyname, const std::string valuename,
const unsigned long defValue ) const {
char svalue[MAX_VALUEDATA];
String::formatBuffer( svalue, MAX_VALUEDATA, "%u", defValue );
return atoi( getValue( keyname, valuename, svalue ).c_str() );
}
bool IniFile::getValueB( const std::string keyname, const std::string valuename,
const bool defValue ) const {
std::string val = getValue( keyname, valuename, defValue ? "1" : "0" );

View File

@@ -1445,6 +1445,10 @@ void TextDocument::execute( const std::string& command ) {
}
}
void TextDocument::setCommands( const std::map<std::string, DocumentCommand>& cmds ) {
mCommands.insert( cmds.begin(), cmds.end() );
}
void TextDocument::setCommand( const std::string& command, TextDocument::DocumentCommand func ) {
mCommands[command] = func;
}

View File

@@ -22,7 +22,7 @@ UICodeEditorSplitter::getLocalDefaultKeybindings() {
{ { KEY_S, KeyMod::getDefaultModifier() }, "save-doc" },
{ { KEY_L, KeyMod::getDefaultModifier() | KEYMOD_SHIFT }, "lock-toggle" },
{ { KEY_T, KeyMod::getDefaultModifier() }, "create-new" },
{ { KEY_W, KeyMod::getDefaultModifier() }, "close-doc" },
{ { KEY_W, KeyMod::getDefaultModifier() }, "close-tab" },
{ { KEY_TAB, KeyMod::getDefaultModifier() }, "next-doc" },
{ { KEY_TAB, KeyMod::getDefaultModifier() | KEYMOD_SHIFT }, "previous-doc" },
{ { KEY_J, KEYMOD_LALT | KEYMOD_SHIFT }, "split-left" },
@@ -57,6 +57,24 @@ UICodeEditorSplitter::getLocalDefaultKeybindings() {
};
}
std::vector<std::string> UICodeEditorSplitter::getUnlockedCommands() {
const std::vector<std::string> unlockedCmds{ "lock-toggle",
"create-new",
"close-tab",
"next-doc",
"previous-doc",
"split-left",
"split-right",
"split-top",
"split-bottom",
"split-swap",
"switch-to-previous-split",
"switch-to-next-split",
"switch-to-previous-colorscheme",
"switch-to-next-colorscheme" };
return unlockedCmds;
}
UICodeEditorSplitter* UICodeEditorSplitter::New( UICodeEditorSplitter::Client* client,
UISceneNode* sceneNode,
const std::vector<SyntaxColorScheme>& colorSchemes,
@@ -89,12 +107,26 @@ UITabWidget* UICodeEditorSplitter::tabWidgetFromEditor( UICodeEditor* editor ) c
return nullptr;
}
UITabWidget* UICodeEditorSplitter::tabWidgetFromWidget( UIWidget* widget ) const {
if ( widget )
return ( (UITab*)widget->getData() )->getTabWidget();
return nullptr;
}
UISplitter* UICodeEditorSplitter::splitterFromEditor( UICodeEditor* editor ) const {
if ( editor && editor->getParent()->getParent()->getParent()->isType( UI_TYPE_SPLITTER ) )
return editor->getParent()->getParent()->getParent()->asType<UISplitter>();
return nullptr;
}
UISplitter* UICodeEditorSplitter::splitterFromWidget( UIWidget* widget ) const {
if ( widget && widget->getParent() && widget->getParent()->getParent() &&
widget->getParent()->getParent()->getParent() &&
widget->getParent()->getParent()->getParent()->isType( UI_TYPE_SPLITTER ) )
return widget->getParent()->getParent()->getParent()->asType<UISplitter>();
return nullptr;
}
UICodeEditor* UICodeEditorSplitter::createCodeEditor() {
UICodeEditor* editor = UICodeEditor::NewOpt( false, true );
TextDocument& doc = editor->getDocument();
@@ -187,7 +219,7 @@ UICodeEditor* UICodeEditorSplitter::createCodeEditor() {
} );
doc.setCommand( "switch-to-previous-split", [&] { switchPreviousSplit( mCurEditor ); } );
doc.setCommand( "switch-to-next-split", [&] { switchNextSplit( mCurEditor ); } );
doc.setCommand( "close-doc", [&] { tryTabClose( mCurEditor ); } );
doc.setCommand( "close-tab", [&] { tryTabClose( mCurEditor ); } );
doc.setCommand( "create-new", [&] {
auto d = createCodeEditorInTabWidget( tabWidgetFromEditor( mCurEditor ) );
d.first->getTabWidget()->setTabSelected( d.first );
@@ -223,12 +255,12 @@ UICodeEditor* UICodeEditorSplitter::createCodeEditor() {
switchToTab( tabWidget->getTabCount() - 1 );
}
} );
doc.setCommand( "split-right", [&] { splitEditor( SplitDirection::Right, mCurEditor ); } );
doc.setCommand( "split-bottom", [&] { splitEditor( SplitDirection::Bottom, mCurEditor ); } );
doc.setCommand( "split-left", [&] { splitEditor( SplitDirection::Left, mCurEditor ); } );
doc.setCommand( "split-top", [&] { splitEditor( SplitDirection::Top, mCurEditor ); } );
doc.setCommand( "split-right", [&] { split( SplitDirection::Right, mCurWidget ); } );
doc.setCommand( "split-bottom", [&] { split( SplitDirection::Bottom, mCurWidget ); } );
doc.setCommand( "split-left", [&] { split( SplitDirection::Left, mCurWidget ); } );
doc.setCommand( "split-top", [&] { split( SplitDirection::Top, mCurWidget ); } );
doc.setCommand( "split-swap", [&] {
if ( UISplitter* splitter = splitterFromEditor( mCurEditor ) )
if ( UISplitter* splitter = splitterFromWidget( mCurWidget ) )
splitter->swap();
} );
doc.setCommand( "open-containing-folder", [&] {
@@ -257,11 +289,7 @@ UICodeEditor* UICodeEditorSplitter::createCodeEditor() {
event->getNode()->asType<UICodeEditor>()->getDocument() );
} );
editor->addKeyBinds( getLocalDefaultKeybindings() );
editor->addUnlockedCommands( { "lock-toggle", "create-new", "close-doc", "next-doc",
"previous-doc", "split-left", "split-right", "split-top",
"split-bottom", "split-swap", "switch-to-previous-split",
"switch-to-next-split", "switch-to-previous-colorscheme",
"switch-to-next-colorscheme" } );
editor->addUnlockedCommands( getUnlockedCommands() );
if ( nullptr == mCurEditor ) {
mAboutToAddEditor = editor;
@@ -386,16 +414,31 @@ void UICodeEditorSplitter::loadAsyncFileFromPathInNewTab(
void UICodeEditorSplitter::setCurrentEditor( UICodeEditor* editor ) {
eeASSERT( checkEditorExists( editor ) );
bool isNew = mCurEditor != editor;
bool isNewW = mCurWidget != editor;
mCurEditor = editor;
mCurWidget = editor;
if ( isNewW )
mClient->onWidgetFocusChange( editor );
if ( isNew )
mClient->onCodeEditorFocusChange( editor );
if ( editor )
mClient->onDocumentStateChanged( editor, editor->getDocument() );
}
void UICodeEditorSplitter::setCurentWidget( UIWidget* curWidget ) {
if ( curWidget->isType( UI_TYPE_CODEEDITOR ) ) {
setCurrentEditor( curWidget->asType<UICodeEditor>() );
return;
}
bool isNewW = mCurWidget != curWidget;
mCurWidget = curWidget;
if ( isNewW )
mClient->onWidgetFocusChange( curWidget );
}
std::pair<UITab*, UICodeEditor*>
UICodeEditorSplitter::createCodeEditorInTabWidget( UITabWidget* tabWidget ) {
eeASSERT( curEditorExists() );
eeASSERT( curWidgetExists() );
if ( nullptr == tabWidget )
return std::make_pair( (UITab*)nullptr, (UICodeEditor*)nullptr );
UICodeEditor* editor = createCodeEditor();
@@ -413,8 +456,34 @@ UICodeEditorSplitter::createCodeEditorInTabWidget( UITabWidget* tabWidget ) {
return std::make_pair( tab, editor );
}
std::pair<UITab*, UIWidget*>
UICodeEditorSplitter::createWidgetInTabWidget( UITabWidget* tabWidget, UIWidget* widget,
const std::string& tabName, bool focus ) {
eeASSERT( curWidgetExists() );
if ( nullptr == tabWidget )
return std::make_pair( (UITab*)nullptr, (UIWidget*)nullptr );
UITab* tab = tabWidget->add( tabName, widget );
widget->setData( (UintPtr)tab );
widget->addEventListener( Event::OnFocus, [&]( const Event* event ) {
setCurentWidget( event->getNode()->asType<UIWidget>() );
} );
widget->addEventListener( Event::OnTitleChange, [&]( const Event* event ) {
const TextEvent* tevent = static_cast<const TextEvent*>( event );
UIWidget* widget = event->getNode()->asType<UIWidget>();
UITabWidget* tabWidget = tabWidgetFromWidget( widget );
UITab* tab = tabWidget->getTabFromOwnedWidget( widget );
if ( !tab )
return;
tab->setText( tevent->getText() );
} );
if ( focus )
tabWidget->setTabSelected( tab );
return std::make_pair( tab, widget );
}
void UICodeEditorSplitter::removeUnusedTab( UITabWidget* tabWidget ) {
if ( tabWidget && tabWidget->getTabCount() >= 2 &&
tabWidget->getTab( 0 )->getOwnedWidget()->isType( UI_TYPE_CODEEDITOR ) &&
tabWidget->getTab( 0 )
->getOwnedWidget()
->asType<UICodeEditor>()
@@ -425,7 +494,7 @@ void UICodeEditorSplitter::removeUnusedTab( UITabWidget* tabWidget ) {
}
UITabWidget* UICodeEditorSplitter::createEditorWithTabWidget( Node* parent, bool openCurEditor ) {
eeASSERT( curEditorExists() );
eeASSERT( curWidgetExists() );
if ( nullptr == mBaseLayout )
mBaseLayout = parent;
UICodeEditor* prevCurEditor = mCurEditor;
@@ -439,11 +508,19 @@ UITabWidget* UICodeEditorSplitter::createEditorWithTabWidget( Node* parent, bool
tabWidget->setAllowSwitchTabsInEmptySpaces( true );
tabWidget->addEventListener( Event::OnTabSelected, [&]( const Event* event ) {
UITabWidget* tabWidget = event->getNode()->asType<UITabWidget>();
setCurrentEditor( tabWidget->getTabSelected()->getOwnedWidget()->asType<UICodeEditor>() );
if ( tabWidget->getTabSelected()->getOwnedWidget()->isType( UI_TYPE_CODEEDITOR ) ) {
setCurrentEditor(
tabWidget->getTabSelected()->getOwnedWidget()->asType<UICodeEditor>() );
} else {
setCurentWidget( tabWidget->getTabSelected()->getOwnedWidget()->asType<UIWidget>() );
}
} );
tabWidget->setTabTryCloseCallback( [&]( UITab* tab ) -> bool {
tryTabClose( tab->getOwnedWidget()->asType<UICodeEditor>() );
return false;
if ( tab->getOwnedWidget()->isType( UI_TYPE_CODEEDITOR ) ) {
tryTabClose( tab->getOwnedWidget()->asType<UICodeEditor>() );
return false;
}
return true;
} );
tabWidget->addEventListener( Event::OnTabClosed, [&]( const Event* event ) {
onTabClosed( static_cast<const TabEvent*>( event ) );
@@ -467,6 +544,8 @@ UITab* UICodeEditorSplitter::isDocumentOpen( const std::string& path,
return nullptr;
for ( size_t i = 0; i < tabWidget->getTabCount(); i++ ) {
UITab* tab = tabWidget->getTab( i );
if ( !tab->getOwnedWidget()->isType( UI_TYPE_CODEEDITOR ) )
continue;
UICodeEditor* editor = tab->getOwnedWidget()->asType<UICodeEditor>();
if ( editor->getDocument().getFilePath() == path ) {
@@ -477,6 +556,8 @@ UITab* UICodeEditorSplitter::isDocumentOpen( const std::string& path,
for ( auto tabWidget : mTabWidgets ) {
for ( size_t i = 0; i < tabWidget->getTabCount(); i++ ) {
UITab* tab = tabWidget->getTab( i );
if ( !tab->getOwnedWidget()->isType( UI_TYPE_CODEEDITOR ) )
continue;
UICodeEditor* editor = tab->getOwnedWidget()->asType<UICodeEditor>();
if ( editor->getDocument().getFilePath() == path ) {
@@ -496,8 +577,10 @@ void UICodeEditorSplitter::applyColorScheme( const SyntaxColorScheme& colorSchem
void UICodeEditorSplitter::forEachEditor( std::function<void( UICodeEditor* )> run ) const {
for ( auto tabWidget : mTabWidgets )
for ( size_t i = 0; i < tabWidget->getTabCount(); i++ )
run( tabWidget->getTab( i )->getOwnedWidget()->asType<UICodeEditor>() );
for ( size_t i = 0; i < tabWidget->getTabCount(); i++ ) {
if ( tabWidget->getTab( i )->getOwnedWidget()->isType( UI_TYPE_CODEEDITOR ) )
run( tabWidget->getTab( i )->getOwnedWidget()->asType<UICodeEditor>() );
}
}
void UICodeEditorSplitter::forEachDoc( std::function<void( TextDocument& )> run ) const {
@@ -516,7 +599,19 @@ void UICodeEditorSplitter::forEachEditorStoppable(
std::function<bool( UICodeEditor* )> run ) const {
for ( auto tabWidget : mTabWidgets ) {
for ( size_t i = 0; i < tabWidget->getTabCount(); i++ ) {
if ( run( tabWidget->getTab( i )->getOwnedWidget()->asType<UICodeEditor>() ) ) {
if ( tabWidget->getTab( i )->getOwnedWidget()->isType( UI_TYPE_CODEEDITOR ) &&
run( tabWidget->getTab( i )->getOwnedWidget()->asType<UICodeEditor>() ) ) {
return;
}
}
}
}
void UICodeEditorSplitter::forEachWidgetStoppable( std::function<bool( UIWidget* )> run ) const {
for ( auto tabWidget : mTabWidgets ) {
for ( size_t i = 0; i < tabWidget->getTabCount(); i++ ) {
if ( tabWidget->getTab( i )->getOwnedWidget()->isWidget() &&
run( tabWidget->getTab( i )->getOwnedWidget()->asType<UIWidget>() ) ) {
return;
}
}
@@ -526,7 +621,8 @@ void UICodeEditorSplitter::forEachEditorStoppable(
void UICodeEditorSplitter::forEachDocStoppable( std::function<bool( TextDocument& )> run ) const {
for ( auto tabWidget : mTabWidgets ) {
for ( size_t i = 0; i < tabWidget->getTabCount(); i++ ) {
if ( run( *tabWidget->getTab( i )
if ( tabWidget->getTab( i )->getOwnedWidget()->isType( UI_TYPE_CODEEDITOR ) &&
run( *tabWidget->getTab( i )
->getOwnedWidget()
->asType<UICodeEditor>()
->getDocumentRef()
@@ -568,6 +664,10 @@ Node* UICodeEditorSplitter::getBaseLayout() const {
return mBaseLayout;
}
UIWidget* UICodeEditorSplitter::getCurWidget() const {
return mCurWidget;
}
std::vector<UICodeEditor*> UICodeEditorSplitter::getAllEditors() {
std::vector<UICodeEditor*> editors;
forEachEditor( [&]( UICodeEditor* editor ) { editors.push_back( editor ); } );
@@ -598,50 +698,65 @@ void UICodeEditorSplitter::zoomReset() {
forEachEditor( []( UICodeEditor* editor ) { editor->fontSizeReset(); } );
}
bool UICodeEditorSplitter::tryTabClose( UICodeEditor* editor ) {
if ( nullptr != editor && editor->isDirty() ) {
UIMessageBox* msgBox =
UIMessageBox::New( UIMessageBox::OK_CANCEL,
"Do you really want to close this tab?\nAll changes will be lost." );
msgBox->addEventListener( Event::MsgBoxConfirmClick,
[&, editor]( const Event* ) { closeEditorTab( editor ); } );
msgBox->addEventListener( Event::OnClose, [&]( const Event* ) {
msgBox = nullptr;
if ( mCurEditor )
mCurEditor->setFocus();
} );
msgBox->setTitle( "Close Tab?" );
msgBox->center();
msgBox->show();
bool UICodeEditorSplitter::tryTabClose( UIWidget* widget ) {
if ( !widget )
return false;
if ( widget->isType( UI_TYPE_CODEEDITOR ) ) {
UICodeEditor* editor = widget->asType<UICodeEditor>();
if ( nullptr != editor && editor->isDirty() ) {
UIMessageBox* msgBox = UIMessageBox::New(
UIMessageBox::OK_CANCEL,
"Do you really want to close this tab?\nAll changes will be lost." );
msgBox->addEventListener( Event::MsgBoxConfirmClick,
[&, editor]( const Event* ) { closeTab( editor ); } );
msgBox->addEventListener( Event::OnClose, [&]( const Event* ) {
msgBox = nullptr;
if ( mCurEditor )
mCurEditor->setFocus();
} );
msgBox->setTitle( "Close Tab?" );
msgBox->center();
msgBox->show();
return false;
} else {
closeTab( editor );
return true;
}
} else {
closeEditorTab( editor );
closeTab( widget );
return true;
}
}
void UICodeEditorSplitter::closeEditorTab( UICodeEditor* editor ) {
if ( editor ) {
UITabWidget* tabWidget = tabWidgetFromEditor( editor );
if ( tabWidget ) {
if ( !( editor->getDocument().isEmpty() &&
!tabWidget->getParent()->isType( UI_TYPE_SPLITTER ) &&
tabWidget->getTabCount() == 1 ) ) {
tabWidget->removeTab( (UITab*)editor->getData() );
void UICodeEditorSplitter::closeTab( UIWidget* widget ) {
if ( widget ) {
if ( widget->isType( UI_TYPE_CODEEDITOR ) ) {
UICodeEditor* editor = widget->asType<UICodeEditor>();
UITabWidget* tabWidget = tabWidgetFromEditor( editor );
if ( tabWidget ) {
if ( !( editor->getDocument().isEmpty() &&
!tabWidget->getParent()->isType( UI_TYPE_SPLITTER ) &&
tabWidget->getTabCount() == 1 ) ) {
tabWidget->removeTab( (UITab*)editor->getData() );
}
}
} else {
UITabWidget* tabWidget = tabWidgetFromWidget( widget );
tabWidget->removeTab( (UITab*)widget->getData() );
}
}
}
UISplitter* UICodeEditorSplitter::splitEditor( const SplitDirection& direction,
UICodeEditor* editor, bool openCurEditor ) {
if ( !editor )
UISplitter* UICodeEditorSplitter::split( const SplitDirection& direction, UIWidget* widget,
bool openCurEditor ) {
if ( !widget )
return nullptr;
UIOrientation orientation =
direction == SplitDirection::Left || direction == SplitDirection::Right
? UIOrientation::Horizontal
: UIOrientation::Vertical;
UITabWidget* tabWidget = tabWidgetFromEditor( editor );
UITabWidget* tabWidget = tabWidgetFromWidget( widget );
if ( !tabWidget )
return nullptr;
Node* parent = tabWidget->getParent();
@@ -750,15 +865,14 @@ void UICodeEditorSplitter::switchNextSplit( UICodeEditor* editor ) {
void UICodeEditorSplitter::focusSomeEditor( Node* searchFrom ) {
UICodeEditor* editor =
searchFrom ? searchFrom->findByType<UICodeEditor>( UI_TYPE_CODEEDITOR )
: mUISceneNode->getRoot()->findByType<UICodeEditor>( UI_TYPE_CODEEDITOR );
searchFrom && searchFrom->isType( UI_TYPE_CODEEDITOR )
? searchFrom->findByType<UICodeEditor>( UI_TYPE_CODEEDITOR )
: ( mBaseLayout ? mBaseLayout->findByType<UICodeEditor>( UI_TYPE_CODEEDITOR )
: nullptr );
if ( searchFrom && !editor )
editor = mUISceneNode->getRoot()->findByType<UICodeEditor>( UI_TYPE_CODEEDITOR );
if ( editor && tabWidgetFromEditor( editor ) && !tabWidgetFromEditor( editor )->isClosing() &&
tabWidgetFromEditor( editor )->getTabCount() > 1 ) {
UITabWidget* tabW = tabWidgetFromEditor( editor );
UITabWidget* tabW = nullptr;
if ( editor && ( tabW = tabWidgetFromEditor( editor ) ) && !tabW->isClosing() &&
tabW->getTabCount() > 1 ) {
if ( tabW && tabW->getTabSelected()->getOwnedWidget() != editor ) {
tabW->setTabSelected( tabW->getTabSelected() );
return;
@@ -782,10 +896,6 @@ void UICodeEditorSplitter::focusSomeEditor( Node* searchFrom ) {
return;
}
}
UITabWidget* tabW = mUISceneNode->getRoot()->findByType<UITabWidget>( UI_TYPE_TABWIDGET );
if ( tabW && tabW->getTabCount() > 0 )
tabW->setTabSelected( tabW->getTabSelected() );
}
void UICodeEditorSplitter::closeTabWidgets( UISplitter* splitter ) {
@@ -828,6 +938,18 @@ bool UICodeEditorSplitter::curEditorExists() const {
return found || mCurEditor == nullptr || mAboutToAddEditor == mCurEditor || mFirstCodeEditor;
}
bool UICodeEditorSplitter::curWidgetExists() const {
bool found = false;
forEachWidgetStoppable( [&]( UIWidget* widget ) {
if ( widget == mCurWidget ) {
found = true;
return true;
}
return false;
} );
return found || mCurWidget == nullptr;
}
UICodeEditor* UICodeEditorSplitter::getCurEditor() const {
eeASSERT( curEditorExists() );
return mCurEditor;
@@ -855,10 +977,10 @@ void UICodeEditorSplitter::closeSplitter( UISplitter* splitter ) {
}
void UICodeEditorSplitter::onTabClosed( const TabEvent* tabEvent ) {
UICodeEditor* editor = tabEvent->getTab()->getOwnedWidget()->asType<UICodeEditor>();
UIWidget* widget = tabEvent->getTab()->getOwnedWidget()->asType<UIWidget>();
UITabWidget* tabWidget = tabEvent->getTab()->getTabWidget();
if ( tabWidget->getTabCount() == 0 ) {
UISplitter* splitter = splitterFromEditor( editor );
UISplitter* splitter = splitterFromWidget( widget );
if ( splitter ) {
if ( splitter->isFull() ) {
tabWidget->close();
@@ -903,6 +1025,7 @@ void UICodeEditorSplitter::onTabClosed( const TabEvent* tabEvent ) {
}
}
mCurEditor = nullptr;
mCurWidget = nullptr;
auto d = createCodeEditorInTabWidget( tabWidget );
d.first->getTabWidget()->setTabSelected( d.first );
} else {
@@ -912,7 +1035,7 @@ void UICodeEditorSplitter::onTabClosed( const TabEvent* tabEvent ) {
}
if ( tabEvent->getTab()->getOwnedWidget() == mCurEditor )
focusSomeEditor( nullptr );
eeASSERT( curEditorExists() );
eeASSERT( curWidgetExists() );
}
}}} // namespace EE::UI::Tools

View File

@@ -216,6 +216,8 @@ UIPushButton* UITab::setText( const String& text ) {
tTabW->orderTabs();
}
sendTextEvent( Event::OnTitleChange, mText.toUtf8() );
}
return this;
}

View File

@@ -466,6 +466,18 @@ UITabWidget* UITabWidget::add( UITab* tab ) {
return this;
}
UITab* UITabWidget::getTabFromOwnedWidget( const UIWidget* widget ) {
for ( Uint32 i = 0; i < mTabs.size(); i++ ) {
if ( mTabs[i]->isType( UI_TYPE_TAB ) ) {
UITab* tTab = mTabs[i]->asType<UITab>();
if ( tTab->getOwnedWidget() == widget )
return tTab;
}
}
return nullptr;
}
UITab* UITabWidget::getTab( const Uint32& index ) {
eeASSERT( index < mTabs.size() );
return mTabs[index];

View File

@@ -7,6 +7,7 @@
#include <eepp/ui/css/stylesheetspecification.hpp>
#include <eepp/ui/css/transitiondefinition.hpp>
#include <eepp/ui/uiborderdrawable.hpp>
#include <eepp/ui/uieventdispatcher.hpp>
#include <eepp/ui/uinodedrawable.hpp>
#include <eepp/ui/uiscenenode.hpp>
#include <eepp/ui/uistyle.hpp>
@@ -56,6 +57,10 @@ UIWidget::UIWidget( const std::string& tag ) :
UIWidget::UIWidget() : UIWidget( "widget" ) {}
UIWidget::~UIWidget() {
if ( mUISceneNode && mUISceneNode->getUIEventDispatcher() &&
mUISceneNode->getUIEventDispatcher()->getNodeDragging() == this )
mUISceneNode->getUIEventDispatcher()->setNodeDragging( nullptr );
if ( !SceneManager::instance()->isShootingDown() && NULL != mUISceneNode )
mUISceneNode->onWidgetDelete( this );
eeSAFE_DELETE( mStyle );

View File

@@ -1162,6 +1162,9 @@ const Uint8& UIWindow::getBaseAlpha() const {
}
void UIWindow::setTitle( const String& text ) {
if ( mTitle && text == mTitle->getText() )
return;
if ( NULL == mTitle ) {
mTitle = UITextView::NewWithTag( "window::title" );
mTitle->setLayoutSizePolicy( SizePolicy::Fixed, SizePolicy::Fixed );
@@ -1177,6 +1180,7 @@ void UIWindow::setTitle( const String& text ) {
fixTitleSize();
mTitle->setText( text );
sendTextEvent( Event::OnTitleChange, text.toUtf8() );
}
void UIWindow::fixTitleSize() {

View File

@@ -178,7 +178,7 @@ class TerminalDisplay : public ITerminalDisplay {
virtual void onMouseDoubleClick( const Vector2i& pos, const Uint32& flags );
virtual void onMouseMotion( const Vector2i& pos, const Uint32& flags );
virtual void onMouseMove( const Vector2i& pos, const Uint32& flags );
virtual void onMouseDown( const Vector2i& pos, const Uint32& flags );

View File

@@ -0,0 +1,72 @@
#ifndef ETERM_UI_UITERMINAL_HPP
#define ETERM_UI_UITERMINAL_HPP
#include <eepp/ui/uiwidget.hpp>
#include <eterm/terminal/terminaldisplay.hpp>
using namespace EE::UI;
using namespace eterm::Terminal;
namespace eterm { namespace UI {
class EE_API UITerminal : public UIWidget {
public:
static UITerminal* New( Font* font, const Float& fontSize, const Sizef& pixelsSize,
std::string program = "", const std::vector<std::string>& args = {},
const std::string& workingDir = "", const size_t& historySize = 10000,
IProcessFactory* processFactory = nullptr,
const bool& useFrameBuffer = false );
static UITerminal* New( const std::shared_ptr<TerminalDisplay>& terminalDisplay );
virtual ~UITerminal();
virtual Uint32 getType() const;
virtual bool isType( const Uint32& type ) const;
virtual void draw();
const std::shared_ptr<TerminalDisplay>& getTerm() const;
virtual void scheduledUpdate( const Time& time );
const std::string& getTitle() const;
void setTitle( const std::string& title );
protected:
std::string mTitle;
bool mIsCustomTitle{ false };
bool mDraggingSel{ false };
UITerminal( const std::shared_ptr<TerminalDisplay>& terminalDisplay );
std::shared_ptr<TerminalDisplay> mTerm;
virtual Uint32 onTextInput( const TextInputEvent& event );
virtual Uint32 onKeyDown( const KeyEvent& event );
virtual Uint32 onKeyUp( const KeyEvent& event );
virtual Uint32 onMouseMove( const Vector2i& position, const Uint32& flags );
virtual Uint32 onMouseDown( const Vector2i& position, const Uint32& flags );
virtual Uint32 onMouseDoubleClick( const Vector2i& position, const Uint32& flags );
virtual Uint32 onMouseUp( const Vector2i& position, const Uint32& flags );
virtual void onPositionChange();
virtual void onSizeChange();
virtual Uint32 onFocus();
virtual Uint32 onFocusLoss();
};
}} // namespace eterm::UI
#endif

View File

@@ -695,7 +695,7 @@ void TerminalDisplay::onMouseDoubleClick( const Vector2i& pos, const Uint32& fla
}
}
void TerminalDisplay::onMouseMotion( const Vector2i& pos, const Uint32& flags ) {
void TerminalDisplay::onMouseMove( const Vector2i& pos, const Uint32& flags ) {
if ( ( flags & EE_BUTTON_LMASK ) &&
( mTerminal->getSelectionMode() == TerminalSelectionMode::SEL_EMPTY ||
mTerminal->getSelectionMode() == TerminalSelectionMode::SEL_READY ) ) {
@@ -712,6 +712,28 @@ void TerminalDisplay::onMouseMotion( const Vector2i& pos, const Uint32& flags )
void TerminalDisplay::onMouseDown( const Vector2i& pos, const Uint32& flags ) {
auto gridPos{ positionToGrid( pos ) };
if ( ( flags & EE_BUTTON_LMASK ) &&
mLastDoubleClick.getElapsedTime() < Milliseconds( 300.f ) ) {
mTerminal->selstart( gridPos.x, gridPos.y, SNAP_LINE );
} else if ( flags & EE_BUTTON_LMASK ) {
if ( mTerminal->getSelectionMode() == TerminalSelectionMode::SEL_IDLE ) {
mTerminal->selstart( gridPos.x, gridPos.y, 0 );
invalidateLines();
} else if ( mTerminal->getSelectionMode() == TerminalSelectionMode::SEL_READY ) {
mTerminal->selclear();
}
} else if ( flags & EE_BUTTON_MMASK ) {
auto selection = mTerminal->getSelection();
if ( !selection.empty() ) {
for ( auto& chr : selection )
onTextInput( chr );
}
}
mTerminal->mousereport( TerminalMouseEventType::MouseButtonDown, positionToGrid( pos ), flags,
mWindow->getInput()->getModState() );
}
void TerminalDisplay::onMouseUp( const Vector2i& pos, const Uint32& flags ) {
Uint32 smod = sanitizeMod( mWindow->getInput()->getModState() );
auto scIt = terminalKeyMap.MouseShortcuts().find( flags );
@@ -738,29 +760,6 @@ void TerminalDisplay::onMouseDown( const Vector2i& pos, const Uint32& flags ) {
}
}
if ( ( flags & EE_BUTTON_LMASK ) &&
mLastDoubleClick.getElapsedTime() < Milliseconds( 300.f ) ) {
mTerminal->selstart( gridPos.x, gridPos.y, SNAP_LINE );
} else if ( flags & EE_BUTTON_LMASK ) {
if ( mTerminal->getSelectionMode() == TerminalSelectionMode::SEL_IDLE ) {
auto gridPos{ positionToGrid( pos ) };
mTerminal->selstart( gridPos.x, gridPos.y, 0 );
invalidateLines();
} else if ( mTerminal->getSelectionMode() == TerminalSelectionMode::SEL_READY ) {
mTerminal->selclear();
}
} else if ( flags & EE_BUTTON_MMASK ) {
auto selection = mTerminal->getSelection();
if ( !selection.empty() ) {
for ( auto& chr : selection )
onTextInput( chr );
}
}
mTerminal->mousereport( TerminalMouseEventType::MouseButtonDown, positionToGrid( pos ), flags,
mWindow->getInput()->getModState() );
}
void TerminalDisplay::onMouseUp( const Vector2i& pos, const Uint32& flags ) {
if ( ( flags & EE_BUTTON_LMASK ) ) {
auto selection = mTerminal->getSelection();
if ( !selection.empty() && selection != "\n" )
@@ -1089,7 +1088,8 @@ void TerminalDisplay::drawGrid( const Vector2f& pos ) {
y += lineHeight;
}
if ( !mEmulator->isScrolling() && !IS_SET( MODE_HIDE ) && mDirtyCursor ) {
if ( !mEmulator->isScrolling() && !IS_SET( MODE_HIDE ) &&
( !mUseFrameBuffer || mDirtyCursor ) ) {
mDirtyCursor = false;
Color drawcol;
if ( IS_SET( MODE_REVERSE ) ) {
@@ -1172,7 +1172,7 @@ void TerminalDisplay::draw( const Vector2f& pos ) {
Primitives p;
p.setForceDraw( false );
p.setColor( defaultBg );
p.drawRectangle( Rectf( mPosition.asFloat(), mSize.asFloat() ) );
p.drawRectangle( Rectf( mPosition.floor().asFloat(), mSize.asFloat() ) );
if ( !mFrameBuffer || mDirty )
drawGrid( pos );

View File

@@ -0,0 +1,140 @@
#include <eepp/scene/scenemanager.hpp>
#include <eepp/ui/uiscenenode.hpp>
#include <eepp/ui/uitabwidget.hpp>
#include <eterm/ui/uiterminal.hpp>
using namespace EE::Scene;
namespace eterm { namespace UI {
UITerminal* UITerminal::New( Font* font, const Float& fontSize, const Sizef& pixelsSize,
std::string program, const std::vector<std::string>& args,
const std::string& workingDir, const size_t& historySize,
IProcessFactory* processFactory, const bool& useFrameBuffer ) {
auto win = SceneManager::instance()->getUISceneNode()->getWindow();
auto terminal =
TerminalDisplay::create( win, font, fontSize, pixelsSize, program, args, workingDir,
historySize, processFactory, useFrameBuffer );
return UITerminal::New( terminal );
}
UITerminal* UITerminal::New( const std::shared_ptr<TerminalDisplay>& terminalDisplay ) {
return eeNew( UITerminal, ( terminalDisplay ) );
}
UITerminal::~UITerminal() {}
Uint32 UITerminal::getType() const {
return UI_TYPE_TERMINAL;
}
bool UITerminal::isType( const Uint32& type ) const {
return getType() == type || UIWidget::isType( type );
}
void UITerminal::draw() {
mTerm->setPosition( mScreenPosi.asFloat() );
mTerm->draw();
}
UITerminal::UITerminal( const std::shared_ptr<TerminalDisplay>& terminalDisplay ) :
UIWidget( "terminal" ), mTerm( terminalDisplay ) {
mFlags |= UI_TAB_STOP;
mTerm->pushEventCallback( [&]( const TerminalDisplay::Event& event ) {
if ( event.type == TerminalDisplay::EventType::TITLE && getParent() ) {
if ( !mIsCustomTitle && mTitle != event.eventData ) {
mTitle = event.eventData;
sendTextEvent( Event::OnTitleChange, mTitle );
}
}
} );
subscribeScheduledUpdate();
}
const std::shared_ptr<TerminalDisplay>& UITerminal::getTerm() const {
return mTerm;
}
void UITerminal::scheduledUpdate( const Time& ) {
mTerm->update();
if ( mTerm->isDirty() )
invalidateDraw();
}
const std::string& UITerminal::getTitle() const {
return mTitle;
}
void UITerminal::setTitle( const std::string& title ) {
if ( title != mTitle ) {
mTitle = title;
mIsCustomTitle = true;
sendTextEvent( Event::OnTitleChange, title );
}
}
Uint32 UITerminal::onTextInput( const TextInputEvent& event ) {
mTerm->onTextInput( event.getChar() );
return 1;
}
Uint32 UITerminal::onKeyDown( const KeyEvent& event ) {
mTerm->onKeyDown( event.getKeyCode(), event.getChar(), event.getMod(), event.getScancode() );
return 1;
}
Uint32 UITerminal::onKeyUp( const KeyEvent& ) {
return 1;
}
Uint32 UITerminal::onMouseMove( const Vector2i& position, const Uint32& flags ) {
mTerm->onMouseMove( position, flags );
return 1;
}
Uint32 UITerminal::onMouseDown( const Vector2i& position, const Uint32& flags ) {
if ( ( flags & EE_BUTTON_LMASK ) &&
mTerm->getTerminal()->getSelectionMode() == TerminalSelectionMode::SEL_IDLE ) {
mDraggingSel = true;
} else if ( ( flags & EE_BUTTON_LMASK ) && mDraggingSel ) {
return 1;
}
mTerm->onMouseDown( position, flags );
return 1;
}
Uint32 UITerminal::onMouseDoubleClick( const Vector2i& position, const Uint32& flags ) {
mTerm->onMouseDoubleClick( position, flags );
return 1;
}
Uint32 UITerminal::onMouseUp( const Vector2i& position, const Uint32& flags ) {
if ( ( flags & EE_BUTTON_LMASK ) && mDraggingSel )
mDraggingSel = false;
mTerm->onMouseUp( position, flags );
return 1;
}
void UITerminal::onPositionChange() {
mTerm->setPosition( mScreenPosi.asFloat() );
UIWidget::onPositionChange();
}
void UITerminal::onSizeChange() {
mTerm->setSize( getPixelsSize() );
UIWidget::onSizeChange();
}
Uint32 UITerminal::onFocus() {
mTerm->setFocus( true );
invalidateDraw();
return UIWidget::onFocus();
}
Uint32 UITerminal::onFocusLoss() {
mTerm->setFocus( false );
invalidateDraw();
return UIWidget::onFocusLoss();
}
}} // namespace eterm::UI

View File

@@ -229,7 +229,7 @@ json saveNode( Node* node ) {
res["type"] = "splitter";
res["split"] = splitter->getSplitPartition().toString();
res["orientation"] =
splitter->getOrientation() == UIOrientation::Horizontal ? "horizontal" : "vertial";
splitter->getOrientation() == UIOrientation::Horizontal ? "horizontal" : "vertical";
res["first"] = saveNode( splitter->getFirstWidget() );
res["last"] = saveNode( splitter->getLastWidget() );
} else if ( node->isType( UI_TYPE_TABWIDGET ) ) {
@@ -309,7 +309,7 @@ static void loadDocuments( UICodeEditorSplitter* editorSplitter, std::shared_ptr
curTabWidget );
}
} else if ( j["type"] == "splitter" ) {
UISplitter* splitter = editorSplitter->splitEditor(
UISplitter* splitter = editorSplitter->split(
j["orientation"] == "horizontal" ? UICodeEditorSplitter::SplitDirection::Right
: UICodeEditorSplitter::SplitDirection::Bottom,
curTabWidget->getTabSelected()->getOwnedWidget()->asType<UICodeEditor>(), false );
@@ -392,4 +392,4 @@ void AppConfig::loadProject( std::string projectFolder, UICodeEditorSplitter* ed
}
}
}
} // namespace ecode

View File

@@ -28,7 +28,7 @@ void DocSearchController::initSearchBar(
auto& kbind = mSearchBarLayout->getKeyBindings();
kbind.addKeybindsString( {
{ mApp->getKeybind( "repeat-find" ), "repeat-find" },
{ mApp->getKeybind( "find-prev" ), "find-prev" },
{ mApp->getKeybind( "find-prev" ), "find-prev" }
} );
kbind.addKeybindsStringUnordered( keybindings );
@@ -104,8 +104,8 @@ void DocSearchController::initSearchBar(
} );
mSearchBarLayout->addCommand( "close-searchbar", [&] {
hideSearchBar();
if ( mEditorSplitter->getCurEditor() )
mEditorSplitter->getCurEditor()->setFocus();
if ( mEditorSplitter->getCurWidget() )
mEditorSplitter->getCurWidget()->setFocus();
if ( mSearchState.editor ) {
if ( mEditorSplitter->editorExists( mSearchState.editor ) ) {
mSearchState.editor->setHighlightWord( "" );

View File

@@ -17,8 +17,7 @@ void appLoop() {
}
bool App::onCloseRequestCallback( EE::Window::Window* ) {
if ( nullptr != mEditorSplitter->getCurEditor() &&
mEditorSplitter->getCurEditor()->isDirty() ) {
if ( mEditorSplitter->isAnyEditorDirty() ) {
UIMessageBox* msgBox = UIMessageBox::New(
UIMessageBox::OK_CANCEL,
i18n( "confirm_ecode_exit",
@@ -152,9 +151,9 @@ void App::openFileDialog() {
loadFileFromPath( file );
} );
dialog->addEventListener( Event::OnWindowClose, [&]( const Event* ) {
if ( mEditorSplitter && mEditorSplitter->getCurEditor() &&
if ( mEditorSplitter && mEditorSplitter->getCurWidget() &&
!SceneManager::instance()->isShootingDown() )
mEditorSplitter->getCurEditor()->setFocus();
mEditorSplitter->getCurWidget()->setFocus();
} );
dialog->center();
dialog->show();
@@ -174,9 +173,9 @@ void App::openFolderDialog() {
loadFolder( path );
} );
dialog->addEventListener( Event::OnWindowClose, [&]( const Event* ) {
if ( mEditorSplitter && mEditorSplitter->getCurEditor() &&
if ( mEditorSplitter && mEditorSplitter->getCurWidget() &&
!SceneManager::instance()->isShootingDown() )
mEditorSplitter->getCurEditor()->setFocus();
mEditorSplitter->getCurWidget()->setFocus();
} );
dialog->center();
dialog->show();
@@ -198,9 +197,9 @@ void App::openFontDialog( std::string& fontPath, bool loadingMonoFont ) {
dialog->setTitle( "Select Font File" );
dialog->setCloseShortcut( KEY_ESCAPE );
dialog->addEventListener( Event::OnWindowClose, [&]( const Event* ) {
if ( mEditorSplitter && mEditorSplitter->getCurEditor() &&
if ( mEditorSplitter && mEditorSplitter->getCurWidget() &&
!SceneManager::instance()->isShootingDown() )
mEditorSplitter->getCurEditor()->setFocus();
mEditorSplitter->getCurWidget()->setFocus();
} );
dialog->addEventListener( Event::OpenFile, [&, loadingMonoFont]( const Event* event ) {
auto newPath = event->getNode()->asType<UIFileDialog>()->getFullPath();
@@ -658,8 +657,8 @@ UIMenu* App::createWindowMenu() {
"New UI scale factor assigned.\nPlease restart the application." );
msg->show();
setFocusEditorOnClose( msg );
} else if ( mEditorSplitter && mEditorSplitter->getCurEditor() ) {
mEditorSplitter->getCurEditor()->setFocus();
} else if ( mEditorSplitter && mEditorSplitter->getCurWidget() ) {
mEditorSplitter->getCurWidget()->setFocus();
}
} else {
UIMessageBox* msg = UIMessageBox::New( UIMessageBox::OK, "Invalid value!" );
@@ -865,8 +864,8 @@ UIMenu* App::createViewMenu() {
void App::setFocusEditorOnClose( UIMessageBox* msgBox ) {
msgBox->addEventListener( Event::OnClose, [&]( const Event* ) {
if ( mEditorSplitter && mEditorSplitter->getCurEditor() )
mEditorSplitter->getCurEditor()->setFocus();
if ( mEditorSplitter && mEditorSplitter->getCurWidget() )
mEditorSplitter->getCurWidget()->setFocus();
} );
}
@@ -1482,8 +1481,13 @@ void App::updateProjectSettingsMenu() {
}
void App::updateDocumentMenu() {
if ( !mEditorSplitter->getCurEditor() )
if ( !mEditorSplitter->getCurWidget() ||
!mEditorSplitter->getCurWidget()->isType( UI_TYPE_CODEEDITOR ) ) {
mSettingsMenu->getItemId( "doc-menu" )->setEnabled( false );
return;
}
mSettingsMenu->getItemId( "doc-menu" )->setEnabled( true );
const TextDocument& doc = mEditorSplitter->getCurEditor()->getDocument();
@@ -1534,10 +1538,10 @@ void App::updateDocumentMenu() {
->setActive( mEditorSplitter->getCurEditor()->isLocked() );
}
static void
updateKeybindings( IniFile& ini, const std::string& group, Input* input,
std::unordered_map<std::string, std::string>& keybindings,
const std::unordered_map<std::string, std::string>& defKeybindings ) {
static void updateKeybindings( IniFile& ini, const std::string& group, Input* input,
std::unordered_map<std::string, std::string>& keybindings,
const std::unordered_map<std::string, std::string>& defKeybindings,
bool forceRebind = false ) {
KeyBindings bindings( input );
bool added = false;
@@ -1552,7 +1556,7 @@ updateKeybindings( IniFile& ini, const std::string& group, Input* input,
for ( const auto& key : keybindings )
invertedKeybindings[key.second] = key.first;
if ( defKeybindings.size() != keybindings.size() ) {
if ( defKeybindings.size() != keybindings.size() || forceRebind ) {
for ( const auto& key : defKeybindings ) {
auto foundCmd = invertedKeybindings.find( key.second );
auto& shortcutStr = key.first;
@@ -1562,6 +1566,22 @@ updateKeybindings( IniFile& ini, const std::string& group, Input* input,
invertedKeybindings[key.second] = shortcutStr;
ini.setValue( group, shortcutStr, key.second );
added = true;
} else if ( foundCmd == invertedKeybindings.end() ) {
// Override the shortcut if the command that holds that
// shortcut does not exists anymore
auto kb = keybindings.find( shortcutStr );
if ( kb != keybindings.end() ) {
bool found = false;
for ( const auto& val : defKeybindings )
if ( val.second == kb->second )
found = true;
if ( !found ) {
keybindings[shortcutStr] = key.second;
invertedKeybindings[key.second] = shortcutStr;
ini.setValue( group, shortcutStr, key.second );
added = true;
}
}
}
}
}
@@ -1569,11 +1589,11 @@ updateKeybindings( IniFile& ini, const std::string& group, Input* input,
ini.writeFile();
}
static void
updateKeybindings( IniFile& ini, const std::string& group, Input* input,
std::unordered_map<std::string, std::string>& keybindings,
std::unordered_map<std::string, std::string>& invertedKeybindings,
const std::map<KeyBindings::Shortcut, std::string>& defKeybindings ) {
static void updateKeybindings( IniFile& ini, const std::string& group, Input* input,
std::unordered_map<std::string, std::string>& keybindings,
std::unordered_map<std::string, std::string>& invertedKeybindings,
const std::map<KeyBindings::Shortcut, std::string>& defKeybindings,
bool forceRebind = false ) {
KeyBindings bindings( input );
bool added = false;
@@ -1587,7 +1607,7 @@ updateKeybindings( IniFile& ini, const std::string& group, Input* input,
for ( const auto& key : keybindings )
invertedKeybindings[key.second] = key.first;
if ( defKeybindings.size() != keybindings.size() ) {
if ( defKeybindings.size() != keybindings.size() || forceRebind ) {
for ( const auto& key : defKeybindings ) {
auto foundCmd = invertedKeybindings.find( key.second );
auto shortcutStr = bindings.getShortcutString( key.first );
@@ -1597,6 +1617,22 @@ updateKeybindings( IniFile& ini, const std::string& group, Input* input,
invertedKeybindings[key.second] = shortcutStr;
ini.setValue( group, shortcutStr, key.second );
added = true;
} else if ( foundCmd == invertedKeybindings.end() ) {
// Override the shortcut if the command that holds that
// shortcut does not exists anymore
auto kb = keybindings.find( shortcutStr );
if ( kb != keybindings.end() ) {
bool found = false;
for ( const auto& val : defKeybindings )
if ( val.second == kb->second )
found = true;
if ( !found ) {
keybindings[shortcutStr] = key.second;
invertedKeybindings[key.second] = shortcutStr;
ini.setValue( group, shortcutStr, key.second );
added = true;
}
}
}
}
}
@@ -1616,18 +1652,26 @@ void App::loadKeybindings() {
ini.writeFile();
}
bool forceRebind = false;
auto version = ini.getValueU( "version", "version", 0 );
if ( version != ecode::Version::getVersionNum() ) {
ini.setValueU( "version", "version", ecode::Version::getVersionNum() );
ini.writeFile();
forceRebind = true;
}
Uint32 defModKeyCode = KeyMod::getKeyMod( defMod );
if ( 0 != defModKeyCode )
if ( KEYMOD_NONE != defModKeyCode )
KeyMod::setDefaultModifier( defModKeyCode );
updateKeybindings( ini, "editor", mWindow->getInput(), mKeybindings, mKeybindingsInvert,
getDefaultKeybindings() );
getDefaultKeybindings(), forceRebind );
updateKeybindings( ini, "global_search", mWindow->getInput(), mGlobalSearchKeybindings,
GlobalSearchController::getDefaultKeybindings() );
GlobalSearchController::getDefaultKeybindings(), forceRebind );
updateKeybindings( ini, "document_search", mWindow->getInput(), mDocumentSearchKeybindings,
DocSearchController::getDefaultKeybindings() );
DocSearchController::getDefaultKeybindings(), forceRebind );
}
}
@@ -1644,7 +1688,9 @@ void App::onDocumentCursorPosChange( UICodeEditor*, TextDocument& doc ) {
}
void App::updateDocInfo( TextDocument& doc ) {
if ( mConfig.editor.showDocInfo && mDocInfoText && mEditorSplitter->getCurEditor() ) {
if ( mConfig.editor.showDocInfo && mDocInfoText && mEditorSplitter->getCurEditor() &&
mEditorSplitter->getCurEditor()->isType( UI_TYPE_CODEEDITOR ) ) {
mDocInfoText->setVisible( true );
mDocInfoText->setText( String::format(
"line: %lld / %lu col: %lld %s", doc.getSelection().start().line() + 1,
doc.linesCount(), mEditorSplitter->getCurEditor()->getCurrentColumnCount(),
@@ -1665,9 +1711,19 @@ void App::syncProjectTreeWithEditor( UICodeEditor* editor ) {
}
}
void App::onWidgetFocusChange( UIWidget* widget ) {
if ( mConfig.editor.showDocInfo && mDocInfoText ) {
mDocInfoText->setVisible( widget && widget->isType( UI_TYPE_CODEEDITOR ) );
}
updateDocumentMenu();
if ( widget && !widget->isType( UI_TYPE_CODEEDITOR ) ) {
if ( widget->isType( UI_TYPE_TERMINAL ) )
setAppTitle( widget->asType<UITerminal>()->getTitle() );
}
}
void App::onCodeEditorFocusChange( UICodeEditor* editor ) {
updateDocInfo( editor->getDocument() );
updateDocumentMenu();
mDocSearchController->onCodeEditorFocusChange( editor );
syncProjectTreeWithEditor( editor );
}
@@ -1907,6 +1963,33 @@ NotificationCenter* App::getNotificationCenter() const {
return mNotificationCenter.get();
}
void App::createNewTerminal() {
UIWidget* curWidget = mEditorSplitter->getCurWidget();
if ( !curWidget )
return;
UITabWidget* tabWidget = mEditorSplitter->tabWidgetFromWidget( curWidget );
if ( !tabWidget ) {
if ( !mEditorSplitter->getTabWidgets().empty() ) {
tabWidget = mEditorSplitter->getTabWidgets()[0];
} else {
return;
}
}
UITerminal* term = UITerminal::New( mFontMono, PixelDensity::dpToPx( 11 ), Sizef( 16, 16 ) );
mEditorSplitter->createWidgetInTabWidget( tabWidget, term, "Shell", true );
term->addEventListener( Event::OnTitleChange, [&]( const Event* event ) {
if ( event->getNode() != mEditorSplitter->getCurWidget() )
return;
setAppTitle( event->getNode()->asType<UITerminal>()->getTitle() );
} );
}
std::map<std::string, std::function<void()>> App::getGlobalCommands() {
std::map<std::string, std::function<void()>> cmds;
return cmds;
}
void App::onCodeEditorCreated( UICodeEditor* editor, TextDocument& doc ) {
const CodeEditorConfig& config = mConfig.editor;
const DocumentConfig& docc = !mCurrentProject.empty() && !mProjectDocConfig.useGlobalSettings
@@ -1947,10 +2030,7 @@ void App::onCodeEditorCreated( UICodeEditor* editor, TextDocument& doc ) {
doc.setCommand( "save-as-doc", [&] { saveFileDialog( mEditorSplitter->getCurEditor() ); } );
doc.setCommand( "save-all", [&] { saveAll(); } );
doc.setCommand( "find-replace", [&] { mDocSearchController->showFindView(); } );
doc.setCommand( "open-global-search", [&] {
mGlobalSearchController->showGlobalSearch(
mGlobalSearchController->isUsingSearchReplaceTree() );
} );
doc.setCommand( "open-global-search", [&] { mGlobalSearchController->showGlobalSearch(); } );
doc.setCommand( "open-locatebar", [&] { mFileLocator->showLocateBar(); } );
doc.setCommand( "repeat-find", [&] {
mDocSearchController->findNextText( mDocSearchController->getSearchState() );
@@ -2013,18 +2093,20 @@ void App::onCodeEditorCreated( UICodeEditor* editor, TextDocument& doc ) {
msgBox->setTitle( mWindowTitle );
msgBox->getTextInput()->setHint( "Any https or http URL" );
msgBox->setCloseShortcut( { KEY_ESCAPE, 0 } );
msgBox->setCloseShortcut( { KEY_ESCAPE, KEYMOD_NONE } );
msgBox->showWhenReady();
msgBox->addEventListener( Event::MsgBoxConfirmClick, [&, msgBox]( const Event* ) {
std::string url( msgBox->getTextInput()->getText().toUtf8() );
downloadFileWeb( url );
if ( mEditorSplitter->getCurEditor() )
mEditorSplitter->getCurEditor()->setFocus();
if ( mEditorSplitter->getCurWidget() )
mEditorSplitter->getCurWidget()->setFocus();
msgBox->closeWindow();
} );
} );
doc.setCommand( "move-panel-left", [&] { panelPosition( PanelPosition::Left ); } );
doc.setCommand( "move-panel-right", [&] { panelPosition( PanelPosition::Right ); } );
doc.setCommand( "create-new-terminal", [&] { createNewTerminal(); } );
editor->addUnlockedCommand( "create-new-terminal" );
editor->addEventListener( Event::OnDocumentSave, [&]( const Event* event ) {
UICodeEditor* editor = event->getNode()->asType<UICodeEditor>();
@@ -2204,7 +2286,7 @@ UIPopUpMenu* App::createToolsMenu() {
if ( txt == "Locate..." ) {
mFileLocator->showLocateBar();
} else if ( txt == "Project Find..." ) {
mGlobalSearchController->showGlobalSearch();
mGlobalSearchController->showGlobalSearch( false );
} else if ( txt == "Go to line..." ) {
mFileLocator->goToLine();
} else if ( txt == "Load current document directory as folder" ) {
@@ -2231,6 +2313,8 @@ void App::createSettingsMenu() {
mSettingsMenu = UIPopUpMenu::New();
mSettingsMenu->setId( "settings_menu" );
mSettingsMenu->add( "New", findIcon( "document-new" ), getKeybind( "create-new" ) );
mSettingsMenu->add( "New Terminal", findIcon( "terminal" ),
getKeybind( "create-new-terminal" ) );
mSettingsMenu->add( "Open File...", findIcon( "document-open" ), getKeybind( "open-file" ) );
mSettingsMenu->add( "Open Folder...", findIcon( "document-open" ),
getKeybind( "open-folder" ) );
@@ -2268,14 +2352,14 @@ void App::createSettingsMenu() {
fileTypeMenu->setSubMenu( newMenu );
}
} );
mSettingsMenu->addSubMenu( "Document", nullptr, createDocumentMenu() );
mSettingsMenu->addSubMenu( "Document", nullptr, createDocumentMenu() )->setId( "doc-menu" );
mSettingsMenu->addSubMenu( "Edit", nullptr, createEditMenu() );
mSettingsMenu->addSubMenu( "View", nullptr, createViewMenu() );
mSettingsMenu->addSubMenu( "Tools", nullptr, createToolsMenu() );
mSettingsMenu->addSubMenu( "Window", nullptr, createWindowMenu() );
mSettingsMenu->addSubMenu( "Help", findIcon( "help" ), createHelpMenu() );
mSettingsMenu->addSeparator();
mSettingsMenu->add( "Close", findIcon( "document-close" ), getKeybind( "close-doc" ) );
mSettingsMenu->add( "Close", findIcon( "document-close" ), getKeybind( "close-tab" ) );
mSettingsMenu->add( "Close Folder", findIcon( "document-close" ),
getKeybind( "close-folder" ) );
mSettingsMenu->addSeparator();
@@ -2289,6 +2373,8 @@ void App::createSettingsMenu() {
const String& name = event->getNode()->asType<UIMenuItem>()->getText();
if ( name == "New" ) {
runCommand( "create-new" );
} else if ( name == "New Terminal" ) {
runCommand( "create-new-terminal" );
} else if ( name == "Open File..." ) {
runCommand( "open-file" );
} else if ( name == "Open Folder..." ) {
@@ -2302,7 +2388,7 @@ void App::createSettingsMenu() {
} else if ( name == "Save All" ) {
runCommand( "save-all" );
} else if ( name == "Close" ) {
runCommand( "close-doc" );
runCommand( "close-tab" );
} else if ( name == "Close Folder" ) {
runCommand( "close-folder" );
} else if ( name == "Quit" ) {
@@ -2761,8 +2847,8 @@ void App::loadFolder( const std::string& path ) {
updateRecentFolders();
updateProjectSettingsMenu();
if ( mEditorSplitter->getCurEditor() )
mEditorSplitter->getCurEditor()->setFocus();
if ( mEditorSplitter->getCurWidget() )
mEditorSplitter->getCurWidget()->setFocus();
}
FontTrueType* App::loadFont( const std::string& name, std::string fontPath,
@@ -3157,6 +3243,7 @@ void App::init( std::string file, const Float& pidelDensity, const std::string&
{ "global-settings", 0xedcf },
{ "folder-user", 0xed84 },
{ "help", 0xf045 },
{ "terminal", 0xf1f6 },
};
for ( const auto& icon : icons )
iconTheme->add( UIGlyphIcon::New( icon.first, iconFont, icon.second ) );

View File

@@ -13,6 +13,9 @@
#include "widgetcommandexecuter.hpp"
#include <eepp/ee.hpp>
#include <efsw/efsw.hpp>
#include <eterm/ui/uiterminal.hpp>
using namespace eterm::UI;
namespace ecode {
@@ -77,6 +80,10 @@ class App : public UICodeEditorSplitter::Client {
NotificationCenter* getNotificationCenter() const;
void createNewTerminal();
std::map<std::string, std::function<void()>> getGlobalCommands();
protected:
EE::Window::Window* mWindow{ nullptr };
UISceneNode* mUISceneNode{ nullptr };
@@ -230,6 +237,8 @@ class App : public UICodeEditorSplitter::Client {
void onDocumentCursorPosChange( UICodeEditor* editor, TextDocument& );
void onWidgetFocusChange( UIWidget* widget );
void onCodeEditorFocusChange( UICodeEditor* editor );
bool setAutoComplete( bool enable );

View File

@@ -61,7 +61,8 @@ void FileLocator::initLocateBar( UILocateBar* locateBar, UITextInput* locateInpu
String number( mLocateInput->getText().substr( 2 ) );
Int64 val;
if ( String::fromString( val, number ) && val - 1 >= 0 ) {
mEditorSplitter->getCurEditor()->goToLine( { val - 1, 0 } );
if ( mEditorSplitter->getCurEditor() )
mEditorSplitter->getCurEditor()->goToLine( { val - 1, 0 } );
mLocateTable->setVisible( false );
}
} else {
@@ -84,7 +85,8 @@ void FileLocator::initLocateBar( UILocateBar* locateBar, UITextInput* locateInpu
} );
mLocateBarLayout->addCommand( "close-locatebar", [&] {
hideLocateBar();
mEditorSplitter->getCurEditor()->setFocus();
if ( mEditorSplitter->getCurWidget() )
mEditorSplitter->getCurWidget()->setFocus();
} );
mLocateBarLayout->getKeyBindings().addKeybindsString( {
{ "escape", "close-locatebar" },

View File

@@ -47,6 +47,10 @@ size_t GlobalSearchController::replaceInFiles( const std::string& replaceText,
return count;
}
void GlobalSearchController::showGlobalSearch() {
showGlobalSearch( isUsingSearchReplaceTree() );
}
void GlobalSearchController::initGlobalSearchBar(
UIGlobalSearchBar* globalSearchBar, const GlobalSearchBarConfig& globalSearchBarConfig,
std::unordered_map<std::string, std::string> keybindings ) {
@@ -132,8 +136,8 @@ void GlobalSearchController::initGlobalSearchBar(
} );
mGlobalSearchBarLayout->addCommand( "close-global-searchbar", [&] {
hideGlobalSearchBar();
if ( mEditorSplitter->getCurEditor() )
mEditorSplitter->getCurEditor()->setFocus();
if ( mEditorSplitter->getCurWidget() )
mEditorSplitter->getCurWidget()->setFocus();
} );
mGlobalSearchBarLayout->addCommand( "expand-all", [&] {
mGlobalSearchTree->expandAll();

View File

@@ -50,7 +50,9 @@ class GlobalSearchController {
size_t replaceInFiles( const std::string& replaceText,
std::shared_ptr<ProjectSearch::ResultModel> model );
void showGlobalSearch( bool searchAndReplace = false );
void showGlobalSearch();
void showGlobalSearch( bool searchAndReplace );
void updateColorScheme( const SyntaxColorScheme& colorScheme );

View File

@@ -10,7 +10,7 @@ void inputCallback( InputEvent* event ) {
switch ( event->Type ) {
case InputEvent::MouseMotion: {
terminal->onMouseMotion( win->getInput()->getMousePos(),
terminal->onMouseMove( win->getInput()->getMousePos(),
win->getInput()->getPressTrigger() );
break;
}