diff --git a/include/eepp/scene/action.hpp b/include/eepp/scene/action.hpp index ef7e182ad..6d9202cf3 100644 --- a/include/eepp/scene/action.hpp +++ b/include/eepp/scene/action.hpp @@ -52,7 +52,7 @@ class EE_API Action { void setFlags( const Uint32& flags ); /** @return The action tag. */ - Uint32 getTag() const; + String::HashType getTag() const; /** Sets a tag to identify and filter actions. */ void setTag( const Uint32& tag ); @@ -94,7 +94,7 @@ class EE_API Action { Node* mNode; Uint32 mFlags; - Uint32 mTag; + String::HashType mTag; Uint32 mNumCallBacks; Uint32 mId; ActionCallbackMap mCallbacks; diff --git a/include/eepp/scene/actionmanager.hpp b/include/eepp/scene/actionmanager.hpp index 488f88763..b4ae5e912 100644 --- a/include/eepp/scene/actionmanager.hpp +++ b/include/eepp/scene/actionmanager.hpp @@ -32,11 +32,11 @@ class EE_API ActionManager { void removeAllActionsFromTarget( Node* target ); - void removeActionsByTagFromTarget( Node* target, const Uint32& tag ); + void removeActionsByTagFromTarget( Node* target, const String::HashType& tag ); std::vector getActionsFromTarget( Node* target ); - std::vector getActionsByTagFromTarget( Node* target, const Uint32& tag ); + std::vector getActionsByTagFromTarget( Node* target, const String::HashType& tag ); void update( const Time& time ); diff --git a/include/eepp/scene/event.hpp b/include/eepp/scene/event.hpp index e70ef5a48..bb3411b3e 100644 --- a/include/eepp/scene/event.hpp +++ b/include/eepp/scene/event.hpp @@ -35,6 +35,7 @@ class EE_API Event { OnDocumentChanged, OnDocumentClosed, OnDocumentSyntaxDefinitionChange, + OnDocumentDirtyOnFileSysten, OnFontStyleChanged, OnPressEnter, OnValueChange, @@ -72,7 +73,7 @@ class EE_API Event { OnLayoutUpdate, OnSelectionChanged, OnNodeDropped, - OnSave, + OnDocumentSave, OnModelEvent, OnResourceChange, OnActiveWidgetChange, diff --git a/include/eepp/scene/node.hpp b/include/eepp/scene/node.hpp index 56d873c6a..5dc7ae7f1 100644 --- a/include/eepp/scene/node.hpp +++ b/include/eepp/scene/node.hpp @@ -302,7 +302,7 @@ class EE_API Node : public Transformable { void removeActions( const std::vector& actions ); - void removeActionsByTag( const Uint32& tag ); + void removeActionsByTag( const String::HashType& tag ); std::vector getActions(); @@ -373,7 +373,7 @@ class EE_API Node : public Transformable { Uint32 getNodeOfTypeIndex() const; void runOnMainThread( Actions::Runnable::RunnableFunc runnable, - const Time& delay = Seconds( 0 ) ); + const Time& delay = Seconds( 0 ), const Uint32& tag = 0 ); bool isChild( Node* child ) const; @@ -510,7 +510,7 @@ class EE_API Node : public Transformable { void checkClose(); - void sendParentSizeChange( const Vector2f& SizeChange ); + void sendParentSizeChange( const Vector2f& sizeChange ); void childDeleteAll(); diff --git a/include/eepp/system/fileinfo.hpp b/include/eepp/system/fileinfo.hpp index 3a8fe8fe5..5a8a6c296 100644 --- a/include/eepp/system/fileinfo.hpp +++ b/include/eepp/system/fileinfo.hpp @@ -66,14 +66,16 @@ class EE_API FileInfo { const Uint64& getInode() const; + bool isUninitialized() const; + protected: mutable std::string mFilepath; - Uint64 mModificationTime{0}; - Uint64 mSize{0}; - Uint32 mOwnerId{0}; - Uint32 mGroupId{0}; - Uint32 mPermissions{0}; - Uint64 mInode{0}; + Uint64 mModificationTime{ 0 }; + Uint64 mSize{ 0 }; + Uint32 mOwnerId{ 0 }; + Uint32 mGroupId{ 0 }; + Uint32 mPermissions{ 0 }; + Uint64 mInode{ 0 }; }; typedef std::map FileInfoMap; diff --git a/include/eepp/ui/doc/textdocument.hpp b/include/eepp/ui/doc/textdocument.hpp index 78da95bed..e82e638c4 100644 --- a/include/eepp/ui/doc/textdocument.hpp +++ b/include/eepp/ui/doc/textdocument.hpp @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -40,8 +41,9 @@ class EE_API TextDocument { virtual void onDocumentLineCountChange( const size_t& lastCount, const size_t& newCount ) = 0; virtual void onDocumentLineChanged( const Int64& lineIndex ) = 0; - virtual void onDocumentSaved() = 0; + virtual void onDocumentSaved( TextDocument* ) = 0; virtual void onDocumentClosed( TextDocument* ) {} + virtual void onDocumentDirtyOnFileSystem( TextDocument* ) {} }; TextDocument( bool verbose = true ); @@ -64,6 +66,8 @@ class EE_API TextDocument { bool loadFromPack( Pack* pack, std::string filePackPath ); + bool reload(); + bool save(); bool save( const std::string& path ); @@ -243,16 +247,16 @@ class EE_API TextDocument { void setCommand( const std::string& command, DocumentCommand func ); - TextPosition find( String text, TextPosition from = {0, 0}, const bool& caseSensitive = true, + TextPosition find( String text, TextPosition from = { 0, 0 }, const bool& caseSensitive = true, TextRange restrictRange = TextRange() ); - TextPosition findLast( String text, TextPosition from = {0, 0}, + TextPosition findLast( String text, TextPosition from = { 0, 0 }, const bool& caseSensitive = true, TextRange restrictRange = TextRange() ); TextPosition replaceSelection( const String& replace ); - TextPosition replace( String search, const String& replace, TextPosition from = {0, 0}, + TextPosition replace( String search, const String& replace, TextPosition from = { 0, 0 }, const bool& caseSensitive = true, TextRange restrictRange = TextRange() ); String getIndentString(); @@ -279,6 +283,8 @@ class EE_API TextDocument { const std::string& getFilePath() const; + const FileInfo& getFileInfo() const; + bool isDirty() const; const Uint32& getPageSize() const; @@ -338,31 +344,40 @@ class EE_API TextDocument { const std::vector>& autoCloseBracketsPairs ); + bool isDirtyOnFileSystem() const; + + void setDirtyOnFileSystem( bool dirtyOnFileSystem ); + + bool isSaving() const; + protected: friend class UndoStack; UndoStack mUndoStack; std::string mFilePath; + FileInfo mFileRealPath; std::vector mLines; TextRange mSelection; std::unordered_set mClients; - LineEnding mLineEnding{LineEnding::LF}; - bool mIsBOM{false}; - bool mAutoDetectIndentType{true}; - bool mForceNewLineAtEndOfFile{false}; - bool mTrimTrailingWhitespaces{false}; - bool mVerbose{false}; - bool mAutoCloseBrackets{false}; + LineEnding mLineEnding{ LineEnding::LF }; + bool mIsBOM{ false }; + bool mAutoDetectIndentType{ true }; + bool mForceNewLineAtEndOfFile{ false }; + bool mTrimTrailingWhitespaces{ false }; + bool mVerbose{ false }; + bool mAutoCloseBrackets{ false }; + bool mDirtyOnFileSystem{ false }; + bool mSaving{ false }; std::vector> mAutoCloseBracketsPairs; - Uint32 mIndentWidth{4}; - IndentType mIndentType{IndentType::IndentTabs}; + Uint32 mIndentWidth{ 4 }; + IndentType mIndentType{ IndentType::IndentTabs }; Clock mTimer; SyntaxDefinition mSyntaxDefinition; std::string mDefaultFileName; Uint64 mCleanChangeId; - Uint32 mPageSize{10}; + Uint32 mPageSize{ 10 }; std::map mCommands; String mNonWordChars; - Client* mActiveClient{nullptr}; + Client* mActiveClient{ nullptr }; void initializeCommands(); @@ -384,6 +399,8 @@ class EE_API TextDocument { void notifyUndoRedo( const UndoRedo& eventType ); + void notifyDirtyOnFileSystem(); + void insertAtStartOfSelectedLines( const String& text, bool skipEmpty ); void removeFromStartOfSelectedLines( const String& text, bool skipEmpty ); @@ -397,7 +414,7 @@ class EE_API TextDocument { void guessIndentType(); - bool loadFromStream( IOStream& file, std::string path ); + bool loadFromStream( IOStream& file, std::string path, bool callReset ); }; }}} // namespace EE::UI::Doc diff --git a/include/eepp/ui/models/sortingproxymodel.hpp b/include/eepp/ui/models/sortingproxymodel.hpp index eb00e7d14..7be3ed818 100644 --- a/include/eepp/ui/models/sortingproxymodel.hpp +++ b/include/eepp/ui/models/sortingproxymodel.hpp @@ -88,7 +88,6 @@ class EE_API SortingProxyModel final : public Model, private Model::Client { SortOrder mSortOrder{ SortOrder::Ascending }; Role mSortRole{ Role::Sort }; bool mSortingCaseSensitive{ false }; - bool mSorting{ false }; }; }}} // namespace EE::UI::Models diff --git a/include/eepp/ui/tools/uicodeeditorsplitter.hpp b/include/eepp/ui/tools/uicodeeditorsplitter.hpp index 0c9b008cb..bf19c5e97 100644 --- a/include/eepp/ui/tools/uicodeeditorsplitter.hpp +++ b/include/eepp/ui/tools/uicodeeditorsplitter.hpp @@ -87,6 +87,8 @@ class EE_API UICodeEditorSplitter { void forEachEditor( std::function run ); + void forEachDoc( std::function run ); + void zoomIn(); void zoomOut(); @@ -117,6 +119,8 @@ class EE_API UICodeEditorSplitter { std::vector getAllEditors(); + void forEachDocStoppable( std::function run ); + protected: UISceneNode* mUISceneNode{ nullptr }; UICodeEditor* mCurEditor{ nullptr }; diff --git a/include/eepp/ui/uicodeeditor.hpp b/include/eepp/ui/uicodeeditor.hpp index b8e62ba0a..f6c1409ff 100644 --- a/include/eepp/ui/uicodeeditor.hpp +++ b/include/eepp/ui/uicodeeditor.hpp @@ -485,10 +485,12 @@ class EE_API UICodeEditor : public UIWidget, public TextDocument::Client { virtual void onDocumentUndoRedo( const TextDocument::UndoRedo& ); - virtual void onDocumentSaved(); + virtual void onDocumentSaved( TextDocument* ); virtual void onDocumentClosed( TextDocument* doc ); + virtual void onDocumentDirtyOnFileSystem( TextDocument* doc ); + std::pair getVisibleLineRange(); int getVisibleLinesCount(); diff --git a/include/eepp/ui/uitextinput.hpp b/include/eepp/ui/uitextinput.hpp index b12d193e6..fa17dd7fa 100644 --- a/include/eepp/ui/uitextinput.hpp +++ b/include/eepp/ui/uitextinput.hpp @@ -175,7 +175,7 @@ class EE_API UITextInput : public UITextView, public TextDocument::Client { virtual void onDocumentUndoRedo( const TextDocument::UndoRedo& ); - virtual void onDocumentSaved(); + virtual void onDocumentSaved( TextDocument* ); void registerKeybindings(); diff --git a/include/eepp/ui/uiwidget.hpp b/include/eepp/ui/uiwidget.hpp index 9238816b9..f10ec1616 100644 --- a/include/eepp/ui/uiwidget.hpp +++ b/include/eepp/ui/uiwidget.hpp @@ -282,7 +282,7 @@ class EE_API UIWidget : public UINode { virtual Uint32 onMouseLeave( const Vector2i& Pos, const Uint32& Flags ); - virtual void onParentSizeChange( const Vector2f& SizeChange ); + virtual void onParentSizeChange( const Vector2f& sizeChange ); virtual void onPositionChange(); @@ -308,7 +308,7 @@ class EE_API UIWidget : public UINode { virtual void onTabPress(); - void updateAnchors( const Vector2f& SizeChange ); + void updateAnchors( const Vector2f& sizeChange ); void alignAgainstLayout(); diff --git a/premake4.lua b/premake4.lua index 882235adc..e5fbbc261 100644 --- a/premake4.lua +++ b/premake4.lua @@ -1,1122 +1,1128 @@ -function newplatform(plf) - local name = plf.name - local description = plf.description - - -- Register new platform - premake.platforms[name] = { - cfgsuffix = "_"..name, - iscrosscompiler = true - } - - -- Allow use of new platform in --platfroms - table.insert(premake.option.list["platform"].allowed, { name, description }) - table.insert(premake.fields.platforms.allowed, name) - - -- Add compiler support - premake.gcc.platforms[name] = plf.gcc -end - -function newgcctoolchain(toolchain) - newplatform { - name = toolchain.name, - description = toolchain.description, - gcc = { - cc = toolchain.prefix .. "gcc", - cxx = toolchain.prefix .. "g++", - ar = toolchain.prefix .. "ar", - cppflags = "-MMD " .. toolchain.cppflags - } - } -end - -function newclangtoolchain(toolchain) - newplatform { - name = toolchain.name, - description = toolchain.description, - gcc = { - cc = toolchain.prefix .. "clang", - cxx = toolchain.prefix .. "clang++", - ar = toolchain.prefix .. "ar", - cppflags = "-MMD " .. toolchain.cppflags - } - } -end - -newplatform { - name = "clang", - description = "Clang", - gcc = { - cc = "clang", - cxx = "clang++", - ar = "ar", - cppflags = "-MMD " - } -} - -newplatform { - name = "clang-static-analyze", - description = "Clang static analysis build", - gcc = { - cc = "clang --analyze", - cxx = "clang++ --analyze", - ar = "ar", - cppflags = "-MMD" - } -} - -newplatform { - name = "emscripten", - description = "Emscripten", - gcc = { - cc = "emcc", - cxx = "em++", - ar = "emar", - cppflags = "-MMD -D__emscripten__" - } -} - -newgcctoolchain { - name = "mingw32", - description = "Mingw32 to cross-compile windows binaries from *nix", - prefix = "i686-w64-mingw32-", - cppflags = "" -} - -newgcctoolchain { - name ="android-arm7", - description = "Android ARMv7 (not implemented)", - prefix = iif( os.getenv("ANDROID_NDK"), os.getenv("ANDROID_NDK"), "" ) .. "arm-linux-androideabi-", - cppflags = "-MMD -arch=armv7 -march=armv7 -marm -mcpu=cortex-a8" -} - -toolchain_path = os.getenv("TOOLCHAINPATH") - -if not toolchain_path then - toolchain_path = "" -end - --- cross compiling from linux, totally experimental, using: http://code.google.com/p/ios-toolchain-based-on-clang-for-linux/ -newplatform { - name = "ios-cross-arm7", - description = "iOS ARMv7 ( cross-compiling )", - gcc = { - cc = "ios-clang", - cxx = "ios-clang++", - ar = "arm-apple-darwin11-ar", - cppflags = "-MMD -march=armv7 -marm -mcpu=cortex-a8" - } -} - -newplatform { - name = "ios-cross-x86", - description = "iOS x86 ( cross-compiling )", - gcc = { - cc = "ios-clang", - cxx = "ios-clang++", - ar = "arm-apple-darwin11-ar", - cppflags = "-MMD -march=i386 -m32" - } -} - -newclangtoolchain { - name ="ios-arm64", - description = "iOS ARM64", - prefix = iif( os.getenv("TOOLCHAINPATH"), os.getenv("TOOLCHAINPATH"), "" ), - cppflags = "-arch arm64" -} - -newclangtoolchain { - name ="ios-x86", - description = "iOS x86", - prefix = iif( os.getenv("TOOLCHAINPATH"), os.getenv("TOOLCHAINPATH"), "" ), - cppflags = "-m32 -arch i386" -} - -newclangtoolchain { - name ="ios-x86_64", - description = "iOS x86_64", - prefix = iif( os.getenv("TOOLCHAINPATH"), os.getenv("TOOLCHAINPATH"), "" ), - cppflags = "-m64 -arch x86_64" -} - -if _OPTIONS.platform then - -- overwrite the native platform with the options::platform - premake.gcc.platforms['Native'] = premake.gcc.platforms[_OPTIONS.platform] -end - -newoption { trigger = "with-openssl", description = "Enables OpenSSL support ( and disables mbedtls backend )." } -newoption { trigger = "with-dynamic-freetype", description = "Dynamic link against freetype." } -newoption { trigger = "with-static-eepp", description = "Force to build the demos and tests with eepp compiled statically" } -newoption { trigger = "with-static-backend", description = "It will try to compile the library with a static backend (only for gcc and mingw).\n\t\t\t\tThe backend should be placed in libs/your_platform/libYourBackend.a" } -newoption { trigger = "with-gles2", description = "Compile with GLES2 support" } -newoption { trigger = "with-gles1", description = "Compile with GLES1 support" } -newoption { trigger = "with-mojoal", description = "Compile with mojoAL as OpenAL implementation instead of using openal-soft (requires SDL2 backend)" } -newoption { trigger = "use-frameworks", description = "In macOS it will try to link the external libraries from its frameworks. For example, instead of linking against SDL2 it will link agains SDL2.framework." } -newoption { trigger = "with-emscripten-pthreads", description = "Enables emscripten build to use posix threads" } -newoption { - trigger = "with-backend", - description = "Select the backend to use for window and input handling.\n\t\t\tIf no backend is selected or if the selected is not installed the script will search for a backend present in the system, and will use it.", - allowed = { - { "SDL2", "SDL2" } - } -} - -function explode(div,str) - if (div=='') then return false end - local pos,arr = 0,{} - for st,sp in function() return string.find(str,div,pos,true) end do - table.insert(arr,string.sub(str,pos,st-1)) - pos = sp + 1 - end - table.insert(arr,string.sub(str,pos)) - return arr -end - -function os.get_real() - if _OPTIONS.platform == "ios-arm64" or - _OPTIONS.platform == "ios-x86" or - _OPTIONS.platform == "ios-x86_64" or - _OPTIONS.platform == "ios-cross-arm7" or - _OPTIONS.platform == "ios-cross-x86" then - return "ios" - end - - if _OPTIONS.platform == "android-arm7" then - return "android" - end - - if _OPTIONS.platform == "mingw32" then - return _OPTIONS.platform - end - - if _OPTIONS.platform == "emscripten" then - return _OPTIONS.platform - end - - return os.get() -end - -function os.is_real( os_name ) - return os.get_real() == os_name -end - -if os.is_real("haiku") and not os.is64bit() then - premake.gcc.cc = "gcc-x86" - premake.gcc.cxx = "g++-x86" - premake.gcc.ar = "ar-x86" -end - -function print_table( table_ref ) - for _, value in pairs( table_ref ) do - print(value) - end -end - -function table_length(T) - local count = 0 - for _ in pairs(T) do count = count + 1 end - return count -end - -function args_contains( element ) - return table.contains( _ARGS, element ) -end - -function multiple_insert( parent_table, insert_table ) - for _, value in pairs( insert_table ) do - table.insert( parent_table, value ) - end -end - -function get_ios_arch() - local archs = explode( "-", _OPTIONS.platform ) - return archs[ table_length( archs ) ] -end - -function os_findlib( name ) - if os.is_real("macosx") and ( is_xcode() or _OPTIONS["use-frameworks"] ) then - local path = "/Library/Frameworks/" .. name .. ".framework" - - if os.isdir( path ) then - return path - end - end - - return os.findlib( name ) -end - -function get_backend_link_name( name ) - if os.is_real("macosx") and ( is_xcode() or _OPTIONS["use-frameworks"] ) then - local fname = name .. ".framework" - - if os_findlib( name ) then -- Search for the framework - return fname - end - end - - return name -end - -function string.starts(String,Start) - if ( _ACTION ) then - return string.sub(String,1,string.len(Start))==Start - end - - return false -end - -function is_vs() - return ( string.starts(_ACTION,"vs") ) -end - -function is_xcode() - return ( string.starts(_ACTION,"xcode") ) -end - -function set_kind() - if os.is_real("macosx") then - kind("ConsoleApp") - else - kind("WindowedApp") - end -end - -link_list = { } -os_links = { } -backends = { } -static_backends = { } -backend_selected = false -remote_sdl2_version = "SDL2-2.0.10" - -function build_base_configuration( package_name ) - includedirs { "src/thirdparty/zlib" } - - if not os.is("windows") and not os.is_real("emscripten") then - buildoptions{ "-fPIC" } - end - - if is_vs() then - includedirs { "src/thirdparty/libzip/vs" } - end - - set_ios_config() - set_xcode_config() - - configuration "debug" - defines { "DEBUG" } - flags { "Symbols" } - if not is_vs() then - buildoptions{ "-Wall", "-std=gnu99" } - end - targetname ( package_name .. "-debug" ) - - configuration "release" - defines { "NDEBUG" } - flags { "OptimizeSpeed" } - if not is_vs() then - buildoptions{ "-Wall", "-std=gnu99" } - end - targetname ( package_name ) - - configuration "emscripten" - buildoptions { "-O3 -s USE_SDL=2 -s PRECISE_F32=1 -s ENVIRONMENT=worker,web" } - if _OPTIONS["with-emscripten-pthreads"] then - buildoptions { "-s USE_PTHREADS=1" } - end -end - -function build_base_cpp_configuration( package_name ) - if not os.is("windows") and not os.is_real("emscripten") then - buildoptions{ "-fPIC" } - end - - set_ios_config() - set_xcode_config() - - configuration "debug" - defines { "DEBUG" } - flags { "Symbols" } - if not is_vs() then - buildoptions{ "-Wall" } - end - targetname ( package_name .. "-debug" ) - - configuration "release" - defines { "NDEBUG" } - flags { "OptimizeSpeed" } - if not is_vs() then - buildoptions{ "-Wall" } - end - targetname ( package_name ) - - configuration "emscripten" - buildoptions { "-O3 -s USE_SDL=2 -s PRECISE_F32=1 -s ENVIRONMENT=worker,web" } - if _OPTIONS["with-emscripten-pthreads"] then - buildoptions { "-s USE_PTHREADS=1" } - end -end - -function add_cross_config_links() - if not is_vs() then - if os.is_real("mingw32") or os.is_real("windows") or os.is_real("ios") then -- if is crosscompiling from *nix - linkoptions { "-static-libgcc", "-static-libstdc++" } - end - - if os.is_real("mingw32") then - linkoptions { "-Wl,-Bstatic -lstdc++ -lpthread -Wl,-Bdynamic" } - end - end -end - -function fix_shared_lib_linking_path( package_name, libname ) - if ( "4.4-beta5" == _PREMAKE_VERSION or "HEAD" == _PREMAKE_VERSION ) and not _OPTIONS["with-static-eepp"] and package_name == "eepp" then - if os.is("macosx") then - linkoptions { "-install_name " .. libname .. ".dylib" } - elseif os.is("linux") or os.is("freebsd") then - linkoptions { "-Wl,-soname=\"" .. libname .. "\"" } - elseif os.is("haiku") then - linkoptions { "-Wl,-soname=\"" .. libname .. ".so" .. "\"" } - end - end -end - -function build_link_configuration( package_name, use_ee_icon ) - includedirs { "include" } - - local extension = ""; - - if package_name == "eepp" then - defines { "EE_EXPORTS" } - elseif package_name == "eepp-static" then - defines { "EE_STATIC" } - end - - if not is_vs() then - buildoptions{ "-std=c++14" } - end - - if package_name ~= "eepp" and package_name ~= "eepp-static" then - if not _OPTIONS["with-static-eepp"] then - links { "eepp-shared" } - else - links { "eepp-static" } - defines { "EE_STATIC" } - add_static_links() - links { link_list } - end - - if os.is("windows") and not is_vs() then - if ( true == use_ee_icon ) then - linkoptions { "../../bin/assets/icon/ee.res" } - end - end - - if os.is_real("emscripten") then - extension = ".html" - - if ( package_name ~= "eeew" and - package_name ~= "eees" and - package_name ~= "eehttp-request" and - package_name ~= "eephysics" and - package_name ~= "eevbo-fbo-batch" - ) then - linkoptions { "--preload-file assets/" } - end - end - - if _OPTIONS.platform == "ios-cross-arm7" then - extension = ".ios" - end - - if _OPTIONS.platform == "ios-cross-x86" then - extension = ".x86.ios" - end - - if _OPTIONS.platform == "ios-cross-x86_64" then - extension = ".x86_64.ios" - end - end - - configuration "debug" - defines { "DEBUG", "EE_DEBUG", "EE_MEMORY_MANAGER" } - flags { "Symbols" } - - if not is_vs() and not os.is_real("emscripten") then - buildoptions{ "-Wall -Wno-long-long" } - end - - fix_shared_lib_linking_path( package_name, "libeepp-debug" ) - - if not os.is_real("emscripten") then - targetname ( package_name .. "-debug" .. extension ) - else - targetname ( package_name .. extension ) - end - - configuration "release" - defines { "NDEBUG" } - flags { "OptimizeSpeed" } - - if not is_vs() and not os.is_real("emscripten") then - buildoptions { "-fno-strict-aliasing -ffast-math" } - end - - if not is_vs() and not os.is_real("emscripten") and not os.is_real("macosx") then - buildoptions { "-s" } - end - - fix_shared_lib_linking_path( package_name, "libeepp" ) - - targetname ( package_name .. extension ) - - configuration "windows" - add_cross_config_links() - - configuration "emscripten" - linkoptions { "-O3 -s TOTAL_MEMORY=67108864" } - linkoptions { "-s USE_SDL=2" } - buildoptions { "-O3 -s USE_SDL=2 -s PRECISE_F32=1 -s ENVIRONMENT=worker,web" } - - if _OPTIONS["with-emscripten-pthreads"] then - buildoptions { "-s USE_PTHREADS=1" } - linkoptions { "-s USE_PTHREADS=1" } - end - - if _OPTIONS["with-gles1"] and ( not _OPTIONS["with-gles2"] or _OPTIONS["force-gles1"] ) then - linkoptions{ "-s LEGACY_GL_EMULATION=1" } - end - - if _OPTIONS["with-gles2"] and not _OPTIONS["force-gles1"] then - linkoptions{ "-s FULL_ES2=1" } - end - - set_ios_config() - set_xcode_config() -end - -function generate_os_links() - if os.is_real("linux") then - multiple_insert( os_links, { "rt", "pthread", "X11", "openal", "GL", "Xcursor" } ) - - if _OPTIONS["with-static-eepp"] then - table.insert( os_links, "dl" ) - end - elseif os.is_real("windows") then - multiple_insert( os_links, { "opengl32", "glu32", "gdi32", "ws2_32", "winmm", "ole32" } ) - elseif os.is_real("mingw32") then - multiple_insert( os_links, { "opengl32", "glu32", "gdi32", "ws2_32", "winmm", "ole32" } ) - elseif os.is_real("macosx") then - multiple_insert( os_links, { "OpenGL.framework", "CoreFoundation.framework" } ) - elseif os.is_real("freebsd") then - multiple_insert( os_links, { "rt", "pthread", "X11", "GL", "Xcursor" } ) - elseif os.is_real("haiku") then - multiple_insert( os_links, { "GL", "network" } ) - elseif os.is_real("ios") then - multiple_insert( os_links, { "OpenGLES.framework", "AudioToolbox.framework", "CoreAudio.framework", "Foundation.framework", "CoreFoundation.framework", "UIKit.framework", "QuartzCore.framework", "CoreGraphics.framework", "CoreMotion.framework", "AVFoundation.framework", "GameController.framework" } ) - end - - if not _OPTIONS["with-mojoal"] then - if os.is_real("linux") or os.is_real("freebsd") or os.is_real("haiku") or os.is_real("emscripten") then - multiple_insert( os_links, { "openal" } ) - elseif os.is_real("windows") or os.is_real("mingw32") then - multiple_insert( os_links, { "OpenAL32" } ) - elseif os.is_real("macosx") or os.is_real("ios") then - multiple_insert( os_links, { "OpenAL.framework" } ) - end - end -end - -function parse_args() - if _OPTIONS["with-gles2"] then - defines { "EE_GLES2", "SOIL_GLES2" } - end - - if _OPTIONS["with-gles1"] then - defines { "EE_GLES1", "SOIL_GLES1" } - end -end - -function add_static_links() - -- The linking order DOES matter - -- Expose the symbols that need one static library AFTER adding that static lib - - -- Add static backends - if next(static_backends) ~= nil then - for _, value in pairs( static_backends ) do - linkoptions { value } - end - end - - if not _OPTIONS["with-dynamic-freetype"] then - links { "freetype-static" } - end - - links { "SOIL2-static", - "chipmunk-static", - "libzip-static", - "jpeg-compressor-static", - "zlib-static", - "imageresampler-static", - "pugixml-static", - "vorbis-static" - } - - if _OPTIONS["with-mojoal"] then - links { "mojoal-static"} - end - - if not _OPTIONS["with-openssl"] then - links { "mbedtls-static" } - end - - if not os.is_real("haiku") and not os.is_real("ios") and not os.is_real("android") and not os.is_real("emscripten") then - links{ "glew-static" } - end -end - -function can_add_static_backend( name ) - if _OPTIONS["with-static-backend"] then - local path = "libs/" .. os.get_real() .. "/lib" .. name .. ".a" - return os.isfile(path) - end -end - -function insert_static_backend( name ) - table.insert( static_backends, path.getrelative( "libs/" .. os.get_real(), "./" ) .. "/libs/" .. os.get_real() .. "/lib" .. name .. ".a" ) -end - -function add_sdl2() - print("Using SDL2 backend"); - files { "src/eepp/window/backend/SDL2/*.cpp" } - defines { "EE_BACKEND_SDL_ACTIVE", "EE_SDL_VERSION_2" } - - if not can_add_static_backend("SDL2") then - if not os.is_real("emscripten") then - table.insert( link_list, get_backend_link_name( "SDL2" ) ) - end - else - insert_static_backend( "SDL2" ) - end -end - -function set_xcode_config() - if is_xcode() or _OPTIONS["use-frameworks"] then - linkoptions { "-F/Library/Frameworks" } - includedirs { "/Library/Frameworks/SDL2.framework/Headers" } - defines { "EE_SDL2_FROM_ROOTPATH" } - end -end - -function set_ios_config() - if _OPTIONS.platform == "ios-arm64" or _OPTIONS.platform == "ios-x86" or _OPTIONS.platform == "ios-x86_64" then - local err = false - - if nil == os.getenv("TOOLCHAINPATH") then - print("You must set TOOLCHAINPATH enviroment variable.") - print("\tExample: /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/") - err = true - end - - if nil == os.getenv("SYSROOTPATH") then - print("You must set SYSROOTPATH enviroment variable.") - print("\tExample: /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS12.1.sdk") - err = true - end - - if nil == os.getenv("IOSVERSION") then - print("You must set IOSVERSION enviroment variable.") - print("\tExample: 12.1") - err = true - end - - if err then - os.exit(1) - end - - local sysroot_path = os.getenv("SYSROOTPATH") - local framework_path = sysroot_path .. "/System/Library/Frameworks" - local framework_libs_path = framework_path .. "/usr/lib" - local sysroot_ver = " -miphoneos-version-min=9.0 -isysroot " .. sysroot_path - - buildoptions { sysroot_ver .. " -I" .. sysroot_path .. "/usr/include" } - linkoptions { sysroot_ver } - libdirs { framework_libs_path } - linkoptions { " -F" .. framework_path .. " -L" .. framework_libs_path .. " -isysroot " .. sysroot_path } - includedirs { "src/thirdparty/" .. remote_sdl2_version .. "/include" } - end - - if _OPTIONS.platform == "ios-cross-arm7" or _OPTIONS.platform == "ios-cross-x86" then - includedirs { "src/thirdparty/" .. remote_sdl2_version .. "/include" } - end -end - -function backend_is( name, libname ) - if not _OPTIONS["with-backend"] then - _OPTIONS["with-backend"] = "SDL2" - end - - if next(backends) == nil then - backends = string.explode(_OPTIONS["with-backend"],",") - end - - local backend_sel = table.contains( backends, name ) - - local ret_val = os_findlib( libname ) and backend_sel - - if os.is_real("mingw32") or os.is_real("emscripten") then - ret_val = backend_sel - end - - if ret_val then - backend_selected = true - end - - return ret_val -end - -function select_backend() - if backend_is("SDL2", "SDL2") then - print("Selected SDL2") - add_sdl2() - end - - -- If the selected backend is not present, try to find one present - if not backend_selected then - if os_findlib("SDL2", "SDL2") then - add_sdl2() - else - print("ERROR: Couldnt find any backend. Forced SDL2.") - add_sdl2( true ) - end - end -end - -function check_ssl_support() - if _OPTIONS["with-openssl"] then - if os.is("windows") then - table.insert( link_list, get_backend_link_name( "libssl" ) ) - table.insert( link_list, get_backend_link_name( "libcrypto" ) ) - else - table.insert( link_list, get_backend_link_name( "ssl" ) ) - table.insert( link_list, get_backend_link_name( "crypto" ) ) - end - - files { "src/eepp/network/ssl/backend/openssl/*.cpp" } - - defines { "EE_OPENSSL" } - else - files { "src/eepp/network/ssl/backend/mbedtls/*.cpp" } - - defines { "EE_MBEDTLS" } - end - - defines { "EE_SSL_SUPPORT" } -end - -function set_macos_and_ios_config() - if os.is_real("macosx") and ( is_xcode() or _OPTIONS["use-frameworks"] ) then - libdirs { "/System/Library/Frameworks", "/Library/Frameworks" } - end - - if _OPTIONS["use-frameworks"] then - defines { "EE_USE_FRAMEWORKS" } - end -end - -function build_eepp( build_name ) - includedirs { "include", "src", "src/thirdparty", "include/eepp/thirdparty", "src/thirdparty/freetype2/include", "src/thirdparty/zlib", "src/thirdparty/libogg/include", "src/thirdparty/libvorbis/include", "src/thirdparty/mbedtls/include" } - - if _OPTIONS["with-mojoal"] then - defines( "AL_LIBTYPE_STATIC" ) - includedirs { "src/thirdparty/mojoAL" } - end - - set_macos_and_ios_config() - set_ios_config() - set_xcode_config() - - add_static_links() - - if is_vs() then - includedirs { "src/thirdparty/libzip/vs" } - end - - if not is_vs() then - buildoptions{ "-std=c++14" } - end - - if os.is("windows") then - files { "src/eepp/system/platform/win/*.cpp" } - files { "src/eepp/network/platform/win/*.cpp" } - else - files { "src/eepp/system/platform/posix/*.cpp" } - files { "src/eepp/network/platform/unix/*.cpp" } - end - - files { "src/eepp/core/*.cpp", - "src/eepp/math/*.cpp", - "src/eepp/system/*.cpp", - "src/eepp/audio/*.cpp", - "src/eepp/graphics/*.cpp", - "src/eepp/graphics/renderer/*.cpp", - "src/eepp/window/*.cpp", - "src/eepp/network/*.cpp", - "src/eepp/network/ssl/*.cpp", - "src/eepp/network/http/*.cpp", - "src/eepp/scene/*.cpp", - "src/eepp/scene/actions/*.cpp", - "src/eepp/ui/*.cpp", - "src/eepp/ui/abstract/*.cpp", - "src/eepp/ui/models/*.cpp", - "src/eepp/ui/css/*.cpp", - "src/eepp/ui/doc/*.cpp", - "src/eepp/ui/tools/*.cpp", - "src/eepp/physics/*.cpp", - "src/eepp/physics/constraints/*.cpp", - "src/eepp/maps/*.cpp", - "src/eepp/maps/mapeditor/*.cpp" - } - - check_ssl_support() - - select_backend() - - if _OPTIONS["with-dynamic-freetype"] and os_findlib("freetype") then - table.insert( link_list, get_backend_link_name( "freetype" ) ) - end - - multiple_insert( link_list, os_links ) - - links { link_list } - - build_link_configuration( build_name ) - - configuration "emscripten" - if _OPTIONS["force-gles1"] then - defines{ "EE_GLES1_DEFAULT" } - end -end - -function set_targetdir( dir ) - if os.is_real("ios") then - targetdir(dir .. get_ios_arch() .. "/" ) - else - targetdir(dir) - end -end - -solution "eepp" - - targetdir("./bin/") - configurations { "debug", "release" } - - if os.is_real("ios") then - location("./make/" .. _OPTIONS.platform .. "/" ) - objdir("obj/" .. os.get_real() .. "/" .. get_ios_arch() .. "/" ) - else - location("./make/" .. os.get_real() .. "/") - objdir("obj/" .. os.get_real() .. "/") - end - - generate_os_links() - parse_args() - - if os.is_real("macosx") then - defines { "GL_SILENCE_DEPRECATION" } - end - - project "SOIL2-static" - kind "StaticLib" - language "C" - set_targetdir("libs/" .. os.get_real() .. "/thirdparty/") - files { "src/thirdparty/SOIL2/src/SOIL2/*.c" } - includedirs { "src/thirdparty/SOIL2" } - build_base_configuration( "SOIL2" ) - - if not os.is_real("haiku") and not os.is_real("ios") and not os.is_real("android") and not os.is_real("emscripten") then - project "glew-static" - kind "StaticLib" - language "C" - defines { "GLEW_NO_GLU", "GLEW_STATIC" } - set_targetdir("libs/" .. os.get_real() .. "/thirdparty/") - files { "src/thirdparty/glew/*.c" } - includedirs { "include/thirdparty/glew" } - build_base_configuration( "glew" ) - end - - if not _OPTIONS["with-openssl"] then - project "mbedtls-static" - kind "StaticLib" - language "C" - set_targetdir("libs/" .. os.get_real() .. "/thirdparty/") - includedirs { "src/thirdparty/mbedtls/include/" } - files { "src/thirdparty/mbedtls/library/*.c" } - build_base_cpp_configuration( "mbedtls" ) - end - - project "vorbis-static" - kind "StaticLib" - language "C" - set_targetdir("libs/" .. os.get_real() .. "/thirdparty/") - includedirs { "src/thirdparty/libvorbis/lib/", "src/thirdparty/libogg/include", "src/thirdparty/libvorbis/include" } - files { "src/thirdparty/libogg/**.c", "src/thirdparty/libvorbis/**.c" } - build_base_cpp_configuration( "vorbis" ) - - project "pugixml-static" - kind "StaticLib" - language "C++" - set_targetdir("libs/" .. os.get_real() .. "/thirdparty/") - files { "src/thirdparty/pugixml/*.cpp" } - build_base_cpp_configuration( "pugixml" ) - - project "zlib-static" - kind "StaticLib" - language "C" - set_targetdir("libs/" .. os.get_real() .. "/thirdparty/") - files { "src/thirdparty/zlib/*.c" } - build_base_configuration( "zlib" ) - - project "libzip-static" - kind "StaticLib" - language "C" - set_targetdir("libs/" .. os.get_real() .. "/thirdparty/") - files { "src/thirdparty/libzip/*.c" } - includedirs { "src/thirdparty/zlib" } - build_base_configuration( "libzip" ) - - project "freetype-static" - kind "StaticLib" - language "C" - set_targetdir("libs/" .. os.get_real() .. "/thirdparty/") - defines { "FT2_BUILD_LIBRARY" } - files { "src/thirdparty/freetype2/src/**.c" } - includedirs { "src/thirdparty/freetype2/include" } - build_base_configuration( "freetype" ) - - project "chipmunk-static" - kind "StaticLib" - - if is_vs() then - language "C++" - buildoptions { "/TP" } - else - language "C" - end - - set_targetdir("libs/" .. os.get_real() .. "/thirdparty/") - files { "src/thirdparty/chipmunk/*.c", "src/thirdparty/chipmunk/constraints/*.c" } - includedirs { "include/eepp/thirdparty/chipmunk" } - build_base_configuration( "chipmunk" ) - - project "jpeg-compressor-static" - kind "StaticLib" - language "C++" - set_targetdir("libs/" .. os.get_real() .. "/thirdparty/") - files { "src/thirdparty/jpeg-compressor/*.cpp" } - build_base_cpp_configuration( "jpeg-compressor" ) - - project "imageresampler-static" - kind "StaticLib" - language "C++" - set_targetdir("libs/" .. os.get_real() .. "/thirdparty/") - files { "src/thirdparty/imageresampler/*.cpp" } - build_base_cpp_configuration( "imageresampler" ) - - if _OPTIONS["with-mojoal"] then - project "mojoal-static" - kind "StaticLib" - language "C" - defines( "AL_LIBTYPE_STATIC" ) - set_targetdir("libs/" .. os.get_real() .. "/thirdparty/") - includedirs { "include/eepp/thirdparty/mojoAL" } - files { "src/thirdparty/mojoAL/*.c" } - build_base_cpp_configuration( "mojoal" ) - end - - project "efsw-static" - kind "StaticLib" - language "C++" - set_targetdir("libs/" .. os.get_real() .. "/thirdparty/") - includedirs { "src/thirdparty/efsw/include", "src/thirdparty/efsw/src" } - - if os.is("windows") then - osfiles = "src/thirdparty/efsw/src/efsw/platform/win/*.cpp" - else - osfiles = "src/thirdparty/efsw/src/efsw/platform/posix/*.cpp" - end - - files { "src/thirdparty/efsw/src/efsw/*.cpp", osfiles } - - if os.is("windows") then - excludes { - "src/thirdparty/efsw/src/efsw/WatcherKqueue.cpp", - "src/thirdparty/efsw/src/efsw/WatcherFSEvents.cpp", - "src/thirdparty/efsw/src/efsw/WatcherInotify.cpp", - "src/thirdparty/efsw/src/efsw/FileWatcherKqueue.cpp", - "src/thirdparty/efsw/src/efsw/FileWatcherInotify.cpp", - "src/thirdparty/efsw/src/efsw/FileWatcherFSEvents.cpp" - } - elseif os.is("linux") then - excludes { - "src/thirdparty/efsw/src/efsw/WatcherKqueue.cpp", - "src/thirdparty/efsw/src/efsw/WatcherFSEvents.cpp", - "src/thirdparty/efsw/src/efsw/WatcherWin32.cpp", - "src/thirdparty/efsw/src/efsw/FileWatcherKqueue.cpp", - "src/thirdparty/efsw/src/efsw/FileWatcherWin32.cpp", - "src/thirdparty/efsw/src/efsw/FileWatcherFSEvents.cpp" - } - elseif os.is("macosx") then - excludes { - "src/thirdparty/efsw/src/efsw/WatcherInotify.cpp", - "src/thirdparty/efsw/src/efsw/WatcherWin32.cpp", - "src/thirdparty/efsw/src/efsw/FileWatcherInotify.cpp", - "src/thirdparty/efsw/src/efsw/FileWatcherWin32.cpp" - } - elseif os.is("freebsd") then - excludes { - "src/thirdparty/efsw/src/efsw/WatcherInotify.cpp", - "src/thirdparty/efsw/src/efsw/WatcherWin32.cpp", - "src/thirdparty/efsw/src/efsw/WatcherFSEvents.cpp", - "src/thirdparty/efsw/src/efsw/FileWatcherInotify.cpp", - "src/thirdparty/efsw/src/efsw/FileWatcherWin32.cpp", - "src/thirdparty/efsw/src/efsw/FileWatcherFSEvents.cpp" - } - end - - build_base_cpp_configuration( "efsw" ) - - -- Library - project "eepp-main" - kind "StaticLib" - language "C++" - set_targetdir("libs/" .. os.get_real() .. "/") - files { "src/eepp/main/eepp_main.cpp" } - - project "eepp-static" - kind "StaticLib" - language "C++" - set_targetdir("libs/" .. os.get_real() .. "/") - build_eepp( "eepp-static" ) - - project "eepp-shared" - kind "SharedLib" - language "C++" - set_targetdir("libs/" .. os.get_real() .. "/") - build_eepp( "eepp" ) - - -- Examples - project "eepp-external-shader" - set_kind() - language "C++" - files { "src/examples/external_shader/*.cpp" } - build_link_configuration( "eepp-external-shader", true ) - - project "eepp-empty-window" - set_kind() - language "C++" - files { "src/examples/empty_window/*.cpp" } - build_link_configuration( "eepp-empty-window", true ) - - project "eepp-sound" - kind "ConsoleApp" - language "C++" - files { "src/examples/sound/*.cpp" } - build_link_configuration( "eepp-sound", true ) - - project "eepp-sprites" - set_kind() - language "C++" - files { "src/examples/sprites/*.cpp" } - build_link_configuration( "eepp-sprites", true ) - - project "eepp-fonts" - set_kind() - language "C++" - files { "src/examples/fonts/*.cpp" } - build_link_configuration( "eepp-fonts", true ) - - project "eepp-vbo-fbo-batch" - set_kind() - language "C++" - files { "src/examples/vbo_fbo_batch/*.cpp" } - build_link_configuration( "eepp-vbo-fbo-batch", true ) - - project "eepp-physics" - set_kind() - language "C++" - files { "src/examples/physics/*.cpp" } - build_link_configuration( "eepp-physics", true ) - - project "eepp-http-request" - kind "ConsoleApp" - language "C++" - files { "src/examples/http_request/*.cpp" } - includedirs { "src/thirdparty" } - build_link_configuration( "eepp-http-request", true ) - - project "eepp-ui-hello-world" - set_kind() - language "C++" - files { "src/examples/ui_hello_world/*.cpp" } - includedirs { "src/thirdparty" } - build_link_configuration( "eepp-ui-hello-world", true ) - - -- Tools - project "eepp-textureatlaseditor" - set_kind() - language "C++" - files { "src/tools/textureatlaseditor/*.cpp" } - build_link_configuration( "eepp-TextureAtlasEditor", true ) - - project "eepp-mapeditor" - set_kind() - language "C++" - files { "src/tools/mapeditor/*.cpp" } - build_link_configuration( "eepp-MapEditor", true ) - - project "eepp-uieditor" - set_kind() - language "C++" - includedirs { "src/thirdparty/efsw/include", "src/thirdparty" } - - if not os.is("windows") and not os.is("haiku") then - links { "pthread" } - elseif os.is("macosx") then - links { "CoreFoundation.framework", "CoreServices.framework" } - end - - links { "efsw-static", "pugixml-static" } - files { "src/tools/uieditor/*.cpp" } - build_link_configuration( "eepp-UIEditor", true ) - - project "ecode" - set_kind() - language "C++" - files { "src/tools/codeeditor/*.cpp" } - includedirs { "src/thirdparty" } - build_link_configuration( "ecode", true ) - - project "eepp-texturepacker" - kind "ConsoleApp" - language "C++" - includedirs { "src/thirdparty" } - files { "src/tools/texturepacker/*.cpp" } - build_link_configuration( "eepp-TexturePacker", true ) - - -- Tests - project "eepp-test" - set_kind() - language "C++" - files { "src/tests/test_all/*.cpp" } - build_link_configuration( "eepp-test", true ) - - project "eepp-ui-perf-test" - set_kind() - language "C++" - files { "src/tests/ui_perf_test/*.cpp" } - includedirs { "src/thirdparty" } - build_link_configuration( "eepp-ui-perf-test", true ) - -if os.isfile("external_projects.lua") then - dofile("external_projects.lua") -end +function newplatform(plf) + local name = plf.name + local description = plf.description + + -- Register new platform + premake.platforms[name] = { + cfgsuffix = "_"..name, + iscrosscompiler = true + } + + -- Allow use of new platform in --platfroms + table.insert(premake.option.list["platform"].allowed, { name, description }) + table.insert(premake.fields.platforms.allowed, name) + + -- Add compiler support + premake.gcc.platforms[name] = plf.gcc +end + +function newgcctoolchain(toolchain) + newplatform { + name = toolchain.name, + description = toolchain.description, + gcc = { + cc = toolchain.prefix .. "gcc", + cxx = toolchain.prefix .. "g++", + ar = toolchain.prefix .. "ar", + cppflags = "-MMD " .. toolchain.cppflags + } + } +end + +function newclangtoolchain(toolchain) + newplatform { + name = toolchain.name, + description = toolchain.description, + gcc = { + cc = toolchain.prefix .. "clang", + cxx = toolchain.prefix .. "clang++", + ar = toolchain.prefix .. "ar", + cppflags = "-MMD " .. toolchain.cppflags + } + } +end + +newplatform { + name = "clang", + description = "Clang", + gcc = { + cc = "clang", + cxx = "clang++", + ar = "ar", + cppflags = "-MMD " + } +} + +newplatform { + name = "clang-static-analyze", + description = "Clang static analysis build", + gcc = { + cc = "clang --analyze", + cxx = "clang++ --analyze", + ar = "ar", + cppflags = "-MMD" + } +} + +newplatform { + name = "emscripten", + description = "Emscripten", + gcc = { + cc = "emcc", + cxx = "em++", + ar = "emar", + cppflags = "-MMD -D__emscripten__" + } +} + +newgcctoolchain { + name = "mingw32", + description = "Mingw32 to cross-compile windows binaries from *nix", + prefix = "i686-w64-mingw32-", + cppflags = "" +} + +newgcctoolchain { + name ="android-arm7", + description = "Android ARMv7 (not implemented)", + prefix = iif( os.getenv("ANDROID_NDK"), os.getenv("ANDROID_NDK"), "" ) .. "arm-linux-androideabi-", + cppflags = "-MMD -arch=armv7 -march=armv7 -marm -mcpu=cortex-a8" +} + +toolchain_path = os.getenv("TOOLCHAINPATH") + +if not toolchain_path then + toolchain_path = "" +end + +-- cross compiling from linux, totally experimental, using: http://code.google.com/p/ios-toolchain-based-on-clang-for-linux/ +newplatform { + name = "ios-cross-arm7", + description = "iOS ARMv7 ( cross-compiling )", + gcc = { + cc = "ios-clang", + cxx = "ios-clang++", + ar = "arm-apple-darwin11-ar", + cppflags = "-MMD -march=armv7 -marm -mcpu=cortex-a8" + } +} + +newplatform { + name = "ios-cross-x86", + description = "iOS x86 ( cross-compiling )", + gcc = { + cc = "ios-clang", + cxx = "ios-clang++", + ar = "arm-apple-darwin11-ar", + cppflags = "-MMD -march=i386 -m32" + } +} + +newclangtoolchain { + name ="ios-arm64", + description = "iOS ARM64", + prefix = iif( os.getenv("TOOLCHAINPATH"), os.getenv("TOOLCHAINPATH"), "" ), + cppflags = "-arch arm64" +} + +newclangtoolchain { + name ="ios-x86", + description = "iOS x86", + prefix = iif( os.getenv("TOOLCHAINPATH"), os.getenv("TOOLCHAINPATH"), "" ), + cppflags = "-m32 -arch i386" +} + +newclangtoolchain { + name ="ios-x86_64", + description = "iOS x86_64", + prefix = iif( os.getenv("TOOLCHAINPATH"), os.getenv("TOOLCHAINPATH"), "" ), + cppflags = "-m64 -arch x86_64" +} + +if _OPTIONS.platform then + -- overwrite the native platform with the options::platform + premake.gcc.platforms['Native'] = premake.gcc.platforms[_OPTIONS.platform] +end + +newoption { trigger = "with-openssl", description = "Enables OpenSSL support ( and disables mbedtls backend )." } +newoption { trigger = "with-dynamic-freetype", description = "Dynamic link against freetype." } +newoption { trigger = "with-static-eepp", description = "Force to build the demos and tests with eepp compiled statically" } +newoption { trigger = "with-static-backend", description = "It will try to compile the library with a static backend (only for gcc and mingw).\n\t\t\t\tThe backend should be placed in libs/your_platform/libYourBackend.a" } +newoption { trigger = "with-gles2", description = "Compile with GLES2 support" } +newoption { trigger = "with-gles1", description = "Compile with GLES1 support" } +newoption { trigger = "with-mojoal", description = "Compile with mojoAL as OpenAL implementation instead of using openal-soft (requires SDL2 backend)" } +newoption { trigger = "use-frameworks", description = "In macOS it will try to link the external libraries from its frameworks. For example, instead of linking against SDL2 it will link agains SDL2.framework." } +newoption { trigger = "with-emscripten-pthreads", description = "Enables emscripten build to use posix threads" } +newoption { + trigger = "with-backend", + description = "Select the backend to use for window and input handling.\n\t\t\tIf no backend is selected or if the selected is not installed the script will search for a backend present in the system, and will use it.", + allowed = { + { "SDL2", "SDL2" } + } +} + +function explode(div,str) + if (div=='') then return false end + local pos,arr = 0,{} + for st,sp in function() return string.find(str,div,pos,true) end do + table.insert(arr,string.sub(str,pos,st-1)) + pos = sp + 1 + end + table.insert(arr,string.sub(str,pos)) + return arr +end + +function os.get_real() + if _OPTIONS.platform == "ios-arm64" or + _OPTIONS.platform == "ios-x86" or + _OPTIONS.platform == "ios-x86_64" or + _OPTIONS.platform == "ios-cross-arm7" or + _OPTIONS.platform == "ios-cross-x86" then + return "ios" + end + + if _OPTIONS.platform == "android-arm7" then + return "android" + end + + if _OPTIONS.platform == "mingw32" then + return _OPTIONS.platform + end + + if _OPTIONS.platform == "emscripten" then + return _OPTIONS.platform + end + + return os.get() +end + +function os.is_real( os_name ) + return os.get_real() == os_name +end + +if os.is_real("haiku") and not os.is64bit() then + premake.gcc.cc = "gcc-x86" + premake.gcc.cxx = "g++-x86" + premake.gcc.ar = "ar-x86" +end + +function print_table( table_ref ) + for _, value in pairs( table_ref ) do + print(value) + end +end + +function table_length(T) + local count = 0 + for _ in pairs(T) do count = count + 1 end + return count +end + +function args_contains( element ) + return table.contains( _ARGS, element ) +end + +function multiple_insert( parent_table, insert_table ) + for _, value in pairs( insert_table ) do + table.insert( parent_table, value ) + end +end + +function get_ios_arch() + local archs = explode( "-", _OPTIONS.platform ) + return archs[ table_length( archs ) ] +end + +function os_findlib( name ) + if os.is_real("macosx") and ( is_xcode() or _OPTIONS["use-frameworks"] ) then + local path = "/Library/Frameworks/" .. name .. ".framework" + + if os.isdir( path ) then + return path + end + end + + return os.findlib( name ) +end + +function get_backend_link_name( name ) + if os.is_real("macosx") and ( is_xcode() or _OPTIONS["use-frameworks"] ) then + local fname = name .. ".framework" + + if os_findlib( name ) then -- Search for the framework + return fname + end + end + + return name +end + +function string.starts(String,Start) + if ( _ACTION ) then + return string.sub(String,1,string.len(Start))==Start + end + + return false +end + +function is_vs() + return ( string.starts(_ACTION,"vs") ) +end + +function is_xcode() + return ( string.starts(_ACTION,"xcode") ) +end + +function set_kind() + if os.is_real("macosx") then + kind("ConsoleApp") + else + kind("WindowedApp") + end +end + +link_list = { } +os_links = { } +backends = { } +static_backends = { } +backend_selected = false +remote_sdl2_version = "SDL2-2.0.10" + +function build_base_configuration( package_name ) + includedirs { "src/thirdparty/zlib" } + + if not os.is("windows") and not os.is_real("emscripten") then + buildoptions{ "-fPIC" } + end + + if is_vs() then + includedirs { "src/thirdparty/libzip/vs" } + end + + set_ios_config() + set_xcode_config() + + configuration "debug" + defines { "DEBUG" } + flags { "Symbols" } + if not is_vs() then + buildoptions{ "-Wall", "-std=gnu99" } + end + targetname ( package_name .. "-debug" ) + + configuration "release" + defines { "NDEBUG" } + flags { "OptimizeSpeed" } + if not is_vs() then + buildoptions{ "-Wall", "-std=gnu99" } + end + targetname ( package_name ) + + configuration "emscripten" + buildoptions { "-O3 -s USE_SDL=2 -s PRECISE_F32=1 -s ENVIRONMENT=worker,web" } + if _OPTIONS["with-emscripten-pthreads"] then + buildoptions { "-s USE_PTHREADS=1" } + end +end + +function build_base_cpp_configuration( package_name ) + if not os.is("windows") and not os.is_real("emscripten") then + buildoptions{ "-fPIC" } + end + + set_ios_config() + set_xcode_config() + + configuration "debug" + defines { "DEBUG" } + flags { "Symbols" } + if not is_vs() then + buildoptions{ "-Wall" } + end + targetname ( package_name .. "-debug" ) + + configuration "release" + defines { "NDEBUG" } + flags { "OptimizeSpeed" } + if not is_vs() then + buildoptions{ "-Wall" } + end + targetname ( package_name ) + + configuration "emscripten" + buildoptions { "-O3 -s USE_SDL=2 -s PRECISE_F32=1 -s ENVIRONMENT=worker,web" } + if _OPTIONS["with-emscripten-pthreads"] then + buildoptions { "-s USE_PTHREADS=1" } + end +end + +function add_cross_config_links() + if not is_vs() then + if os.is_real("mingw32") or os.is_real("windows") or os.is_real("ios") then -- if is crosscompiling from *nix + linkoptions { "-static-libgcc", "-static-libstdc++" } + end + + if os.is_real("mingw32") then + linkoptions { "-Wl,-Bstatic -lstdc++ -lpthread -Wl,-Bdynamic" } + end + end +end + +function fix_shared_lib_linking_path( package_name, libname ) + if ( "4.4-beta5" == _PREMAKE_VERSION or "HEAD" == _PREMAKE_VERSION ) and not _OPTIONS["with-static-eepp"] and package_name == "eepp" then + if os.is("macosx") then + linkoptions { "-install_name " .. libname .. ".dylib" } + elseif os.is("linux") or os.is("freebsd") then + linkoptions { "-Wl,-soname=\"" .. libname .. "\"" } + elseif os.is("haiku") then + linkoptions { "-Wl,-soname=\"" .. libname .. ".so" .. "\"" } + end + end +end + +function build_link_configuration( package_name, use_ee_icon ) + includedirs { "include" } + + local extension = ""; + + if package_name == "eepp" then + defines { "EE_EXPORTS" } + elseif package_name == "eepp-static" then + defines { "EE_STATIC" } + end + + if not is_vs() then + buildoptions{ "-std=c++14" } + end + + if package_name ~= "eepp" and package_name ~= "eepp-static" then + if not _OPTIONS["with-static-eepp"] then + links { "eepp-shared" } + else + links { "eepp-static" } + defines { "EE_STATIC" } + add_static_links() + links { link_list } + end + + if os.is("windows") and not is_vs() then + if ( true == use_ee_icon ) then + linkoptions { "../../bin/assets/icon/ee.res" } + end + end + + if os.is_real("emscripten") then + extension = ".html" + + if ( package_name ~= "eeew" and + package_name ~= "eees" and + package_name ~= "eehttp-request" and + package_name ~= "eephysics" and + package_name ~= "eevbo-fbo-batch" + ) then + linkoptions { "--preload-file assets/" } + end + end + + if _OPTIONS.platform == "ios-cross-arm7" then + extension = ".ios" + end + + if _OPTIONS.platform == "ios-cross-x86" then + extension = ".x86.ios" + end + + if _OPTIONS.platform == "ios-cross-x86_64" then + extension = ".x86_64.ios" + end + end + + configuration "debug" + defines { "DEBUG", "EE_DEBUG", "EE_MEMORY_MANAGER" } + flags { "Symbols" } + + if not is_vs() and not os.is_real("emscripten") then + buildoptions{ "-Wall -Wno-long-long" } + end + + fix_shared_lib_linking_path( package_name, "libeepp-debug" ) + + if not os.is_real("emscripten") then + targetname ( package_name .. "-debug" .. extension ) + else + targetname ( package_name .. extension ) + end + + configuration "release" + defines { "NDEBUG" } + flags { "OptimizeSpeed" } + + if not is_vs() and not os.is_real("emscripten") then + buildoptions { "-fno-strict-aliasing -ffast-math" } + end + + if not is_vs() and not os.is_real("emscripten") and not os.is_real("macosx") then + buildoptions { "-s" } + end + + fix_shared_lib_linking_path( package_name, "libeepp" ) + + targetname ( package_name .. extension ) + + configuration "windows" + add_cross_config_links() + + configuration "emscripten" + linkoptions { "-O3 -s TOTAL_MEMORY=67108864" } + linkoptions { "-s USE_SDL=2" } + buildoptions { "-O3 -s USE_SDL=2 -s PRECISE_F32=1 -s ENVIRONMENT=worker,web" } + + if _OPTIONS["with-emscripten-pthreads"] then + buildoptions { "-s USE_PTHREADS=1" } + linkoptions { "-s USE_PTHREADS=1" } + end + + if _OPTIONS["with-gles1"] and ( not _OPTIONS["with-gles2"] or _OPTIONS["force-gles1"] ) then + linkoptions{ "-s LEGACY_GL_EMULATION=1" } + end + + if _OPTIONS["with-gles2"] and not _OPTIONS["force-gles1"] then + linkoptions{ "-s FULL_ES2=1" } + end + + set_ios_config() + set_xcode_config() +end + +function generate_os_links() + if os.is_real("linux") then + multiple_insert( os_links, { "rt", "pthread", "X11", "openal", "GL", "Xcursor" } ) + + if _OPTIONS["with-static-eepp"] then + table.insert( os_links, "dl" ) + end + elseif os.is_real("windows") then + multiple_insert( os_links, { "opengl32", "glu32", "gdi32", "ws2_32", "winmm", "ole32" } ) + elseif os.is_real("mingw32") then + multiple_insert( os_links, { "opengl32", "glu32", "gdi32", "ws2_32", "winmm", "ole32" } ) + elseif os.is_real("macosx") then + multiple_insert( os_links, { "OpenGL.framework", "CoreFoundation.framework" } ) + elseif os.is_real("freebsd") then + multiple_insert( os_links, { "rt", "pthread", "X11", "GL", "Xcursor" } ) + elseif os.is_real("haiku") then + multiple_insert( os_links, { "GL", "network" } ) + elseif os.is_real("ios") then + multiple_insert( os_links, { "OpenGLES.framework", "AudioToolbox.framework", "CoreAudio.framework", "Foundation.framework", "CoreFoundation.framework", "UIKit.framework", "QuartzCore.framework", "CoreGraphics.framework", "CoreMotion.framework", "AVFoundation.framework", "GameController.framework" } ) + end + + if not _OPTIONS["with-mojoal"] then + if os.is_real("linux") or os.is_real("freebsd") or os.is_real("haiku") or os.is_real("emscripten") then + multiple_insert( os_links, { "openal" } ) + elseif os.is_real("windows") or os.is_real("mingw32") then + multiple_insert( os_links, { "OpenAL32" } ) + elseif os.is_real("macosx") or os.is_real("ios") then + multiple_insert( os_links, { "OpenAL.framework" } ) + end + end +end + +function parse_args() + if _OPTIONS["with-gles2"] then + defines { "EE_GLES2", "SOIL_GLES2" } + end + + if _OPTIONS["with-gles1"] then + defines { "EE_GLES1", "SOIL_GLES1" } + end +end + +function add_static_links() + -- The linking order DOES matter + -- Expose the symbols that need one static library AFTER adding that static lib + + -- Add static backends + if next(static_backends) ~= nil then + for _, value in pairs( static_backends ) do + linkoptions { value } + end + end + + if not _OPTIONS["with-dynamic-freetype"] then + links { "freetype-static" } + end + + links { "SOIL2-static", + "chipmunk-static", + "libzip-static", + "jpeg-compressor-static", + "zlib-static", + "imageresampler-static", + "pugixml-static", + "vorbis-static" + } + + if _OPTIONS["with-mojoal"] then + links { "mojoal-static"} + end + + if not _OPTIONS["with-openssl"] then + links { "mbedtls-static" } + end + + if not os.is_real("haiku") and not os.is_real("ios") and not os.is_real("android") and not os.is_real("emscripten") then + links{ "glew-static" } + end +end + +function can_add_static_backend( name ) + if _OPTIONS["with-static-backend"] then + local path = "libs/" .. os.get_real() .. "/lib" .. name .. ".a" + return os.isfile(path) + end +end + +function insert_static_backend( name ) + table.insert( static_backends, path.getrelative( "libs/" .. os.get_real(), "./" ) .. "/libs/" .. os.get_real() .. "/lib" .. name .. ".a" ) +end + +function add_sdl2() + print("Using SDL2 backend"); + files { "src/eepp/window/backend/SDL2/*.cpp" } + defines { "EE_BACKEND_SDL_ACTIVE", "EE_SDL_VERSION_2" } + + if not can_add_static_backend("SDL2") then + if not os.is_real("emscripten") then + table.insert( link_list, get_backend_link_name( "SDL2" ) ) + end + else + insert_static_backend( "SDL2" ) + end +end + +function set_xcode_config() + if is_xcode() or _OPTIONS["use-frameworks"] then + linkoptions { "-F/Library/Frameworks" } + includedirs { "/Library/Frameworks/SDL2.framework/Headers" } + defines { "EE_SDL2_FROM_ROOTPATH" } + end +end + +function set_ios_config() + if _OPTIONS.platform == "ios-arm64" or _OPTIONS.platform == "ios-x86" or _OPTIONS.platform == "ios-x86_64" then + local err = false + + if nil == os.getenv("TOOLCHAINPATH") then + print("You must set TOOLCHAINPATH enviroment variable.") + print("\tExample: /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/") + err = true + end + + if nil == os.getenv("SYSROOTPATH") then + print("You must set SYSROOTPATH enviroment variable.") + print("\tExample: /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS12.1.sdk") + err = true + end + + if nil == os.getenv("IOSVERSION") then + print("You must set IOSVERSION enviroment variable.") + print("\tExample: 12.1") + err = true + end + + if err then + os.exit(1) + end + + local sysroot_path = os.getenv("SYSROOTPATH") + local framework_path = sysroot_path .. "/System/Library/Frameworks" + local framework_libs_path = framework_path .. "/usr/lib" + local sysroot_ver = " -miphoneos-version-min=9.0 -isysroot " .. sysroot_path + + buildoptions { sysroot_ver .. " -I" .. sysroot_path .. "/usr/include" } + linkoptions { sysroot_ver } + libdirs { framework_libs_path } + linkoptions { " -F" .. framework_path .. " -L" .. framework_libs_path .. " -isysroot " .. sysroot_path } + includedirs { "src/thirdparty/" .. remote_sdl2_version .. "/include" } + end + + if _OPTIONS.platform == "ios-cross-arm7" or _OPTIONS.platform == "ios-cross-x86" then + includedirs { "src/thirdparty/" .. remote_sdl2_version .. "/include" } + end +end + +function backend_is( name, libname ) + if not _OPTIONS["with-backend"] then + _OPTIONS["with-backend"] = "SDL2" + end + + if next(backends) == nil then + backends = string.explode(_OPTIONS["with-backend"],",") + end + + local backend_sel = table.contains( backends, name ) + + local ret_val = os_findlib( libname ) and backend_sel + + if os.is_real("mingw32") or os.is_real("emscripten") then + ret_val = backend_sel + end + + if ret_val then + backend_selected = true + end + + return ret_val +end + +function select_backend() + if backend_is("SDL2", "SDL2") then + print("Selected SDL2") + add_sdl2() + end + + -- If the selected backend is not present, try to find one present + if not backend_selected then + if os_findlib("SDL2", "SDL2") then + add_sdl2() + else + print("ERROR: Couldnt find any backend. Forced SDL2.") + add_sdl2( true ) + end + end +end + +function check_ssl_support() + if _OPTIONS["with-openssl"] then + if os.is("windows") then + table.insert( link_list, get_backend_link_name( "libssl" ) ) + table.insert( link_list, get_backend_link_name( "libcrypto" ) ) + else + table.insert( link_list, get_backend_link_name( "ssl" ) ) + table.insert( link_list, get_backend_link_name( "crypto" ) ) + end + + files { "src/eepp/network/ssl/backend/openssl/*.cpp" } + + defines { "EE_OPENSSL" } + else + files { "src/eepp/network/ssl/backend/mbedtls/*.cpp" } + + defines { "EE_MBEDTLS" } + end + + defines { "EE_SSL_SUPPORT" } +end + +function set_macos_and_ios_config() + if os.is_real("macosx") and ( is_xcode() or _OPTIONS["use-frameworks"] ) then + libdirs { "/System/Library/Frameworks", "/Library/Frameworks" } + end + + if _OPTIONS["use-frameworks"] then + defines { "EE_USE_FRAMEWORKS" } + end +end + +function build_eepp( build_name ) + includedirs { "include", "src", "src/thirdparty", "include/eepp/thirdparty", "src/thirdparty/freetype2/include", "src/thirdparty/zlib", "src/thirdparty/libogg/include", "src/thirdparty/libvorbis/include", "src/thirdparty/mbedtls/include" } + + if _OPTIONS["with-mojoal"] then + defines( "AL_LIBTYPE_STATIC" ) + includedirs { "src/thirdparty/mojoAL" } + end + + set_macos_and_ios_config() + set_ios_config() + set_xcode_config() + + add_static_links() + + if is_vs() then + includedirs { "src/thirdparty/libzip/vs" } + end + + if not is_vs() then + buildoptions{ "-std=c++14" } + end + + if os.is("windows") then + files { "src/eepp/system/platform/win/*.cpp" } + files { "src/eepp/network/platform/win/*.cpp" } + else + files { "src/eepp/system/platform/posix/*.cpp" } + files { "src/eepp/network/platform/unix/*.cpp" } + end + + files { "src/eepp/core/*.cpp", + "src/eepp/math/*.cpp", + "src/eepp/system/*.cpp", + "src/eepp/audio/*.cpp", + "src/eepp/graphics/*.cpp", + "src/eepp/graphics/renderer/*.cpp", + "src/eepp/window/*.cpp", + "src/eepp/network/*.cpp", + "src/eepp/network/ssl/*.cpp", + "src/eepp/network/http/*.cpp", + "src/eepp/scene/*.cpp", + "src/eepp/scene/actions/*.cpp", + "src/eepp/ui/*.cpp", + "src/eepp/ui/abstract/*.cpp", + "src/eepp/ui/models/*.cpp", + "src/eepp/ui/css/*.cpp", + "src/eepp/ui/doc/*.cpp", + "src/eepp/ui/tools/*.cpp", + "src/eepp/physics/*.cpp", + "src/eepp/physics/constraints/*.cpp", + "src/eepp/maps/*.cpp", + "src/eepp/maps/mapeditor/*.cpp" + } + + check_ssl_support() + + select_backend() + + if _OPTIONS["with-dynamic-freetype"] and os_findlib("freetype") then + table.insert( link_list, get_backend_link_name( "freetype" ) ) + end + + multiple_insert( link_list, os_links ) + + links { link_list } + + build_link_configuration( build_name ) + + configuration "emscripten" + if _OPTIONS["force-gles1"] then + defines{ "EE_GLES1_DEFAULT" } + end +end + +function set_targetdir( dir ) + if os.is_real("ios") then + targetdir(dir .. get_ios_arch() .. "/" ) + else + targetdir(dir) + end +end + +solution "eepp" + + targetdir("./bin/") + configurations { "debug", "release" } + + if os.is_real("ios") then + location("./make/" .. _OPTIONS.platform .. "/" ) + objdir("obj/" .. os.get_real() .. "/" .. get_ios_arch() .. "/" ) + else + location("./make/" .. os.get_real() .. "/") + objdir("obj/" .. os.get_real() .. "/") + end + + generate_os_links() + parse_args() + + if os.is_real("macosx") then + defines { "GL_SILENCE_DEPRECATION" } + end + + project "SOIL2-static" + kind "StaticLib" + language "C" + set_targetdir("libs/" .. os.get_real() .. "/thirdparty/") + files { "src/thirdparty/SOIL2/src/SOIL2/*.c" } + includedirs { "src/thirdparty/SOIL2" } + build_base_configuration( "SOIL2" ) + + if not os.is_real("haiku") and not os.is_real("ios") and not os.is_real("android") and not os.is_real("emscripten") then + project "glew-static" + kind "StaticLib" + language "C" + defines { "GLEW_NO_GLU", "GLEW_STATIC" } + set_targetdir("libs/" .. os.get_real() .. "/thirdparty/") + files { "src/thirdparty/glew/*.c" } + includedirs { "include/thirdparty/glew" } + build_base_configuration( "glew" ) + end + + if not _OPTIONS["with-openssl"] then + project "mbedtls-static" + kind "StaticLib" + language "C" + set_targetdir("libs/" .. os.get_real() .. "/thirdparty/") + includedirs { "src/thirdparty/mbedtls/include/" } + files { "src/thirdparty/mbedtls/library/*.c" } + build_base_cpp_configuration( "mbedtls" ) + end + + project "vorbis-static" + kind "StaticLib" + language "C" + set_targetdir("libs/" .. os.get_real() .. "/thirdparty/") + includedirs { "src/thirdparty/libvorbis/lib/", "src/thirdparty/libogg/include", "src/thirdparty/libvorbis/include" } + files { "src/thirdparty/libogg/**.c", "src/thirdparty/libvorbis/**.c" } + build_base_cpp_configuration( "vorbis" ) + + project "pugixml-static" + kind "StaticLib" + language "C++" + set_targetdir("libs/" .. os.get_real() .. "/thirdparty/") + files { "src/thirdparty/pugixml/*.cpp" } + build_base_cpp_configuration( "pugixml" ) + + project "zlib-static" + kind "StaticLib" + language "C" + set_targetdir("libs/" .. os.get_real() .. "/thirdparty/") + files { "src/thirdparty/zlib/*.c" } + build_base_configuration( "zlib" ) + + project "libzip-static" + kind "StaticLib" + language "C" + set_targetdir("libs/" .. os.get_real() .. "/thirdparty/") + files { "src/thirdparty/libzip/*.c" } + includedirs { "src/thirdparty/zlib" } + build_base_configuration( "libzip" ) + + project "freetype-static" + kind "StaticLib" + language "C" + set_targetdir("libs/" .. os.get_real() .. "/thirdparty/") + defines { "FT2_BUILD_LIBRARY" } + files { "src/thirdparty/freetype2/src/**.c" } + includedirs { "src/thirdparty/freetype2/include" } + build_base_configuration( "freetype" ) + + project "chipmunk-static" + kind "StaticLib" + + if is_vs() then + language "C++" + buildoptions { "/TP" } + else + language "C" + end + + set_targetdir("libs/" .. os.get_real() .. "/thirdparty/") + files { "src/thirdparty/chipmunk/*.c", "src/thirdparty/chipmunk/constraints/*.c" } + includedirs { "include/eepp/thirdparty/chipmunk" } + build_base_configuration( "chipmunk" ) + + project "jpeg-compressor-static" + kind "StaticLib" + language "C++" + set_targetdir("libs/" .. os.get_real() .. "/thirdparty/") + files { "src/thirdparty/jpeg-compressor/*.cpp" } + build_base_cpp_configuration( "jpeg-compressor" ) + + project "imageresampler-static" + kind "StaticLib" + language "C++" + set_targetdir("libs/" .. os.get_real() .. "/thirdparty/") + files { "src/thirdparty/imageresampler/*.cpp" } + build_base_cpp_configuration( "imageresampler" ) + + if _OPTIONS["with-mojoal"] then + project "mojoal-static" + kind "StaticLib" + language "C" + defines( "AL_LIBTYPE_STATIC" ) + set_targetdir("libs/" .. os.get_real() .. "/thirdparty/") + includedirs { "include/eepp/thirdparty/mojoAL" } + files { "src/thirdparty/mojoAL/*.c" } + build_base_cpp_configuration( "mojoal" ) + end + + project "efsw-static" + kind "StaticLib" + language "C++" + set_targetdir("libs/" .. os.get_real() .. "/thirdparty/") + includedirs { "src/thirdparty/efsw/include", "src/thirdparty/efsw/src" } + + if os.is("windows") then + osfiles = "src/thirdparty/efsw/src/efsw/platform/win/*.cpp" + else + osfiles = "src/thirdparty/efsw/src/efsw/platform/posix/*.cpp" + end + + files { "src/thirdparty/efsw/src/efsw/*.cpp", osfiles } + + if os.is("windows") then + excludes { + "src/thirdparty/efsw/src/efsw/WatcherKqueue.cpp", + "src/thirdparty/efsw/src/efsw/WatcherFSEvents.cpp", + "src/thirdparty/efsw/src/efsw/WatcherInotify.cpp", + "src/thirdparty/efsw/src/efsw/FileWatcherKqueue.cpp", + "src/thirdparty/efsw/src/efsw/FileWatcherInotify.cpp", + "src/thirdparty/efsw/src/efsw/FileWatcherFSEvents.cpp" + } + elseif os.is("linux") then + excludes { + "src/thirdparty/efsw/src/efsw/WatcherKqueue.cpp", + "src/thirdparty/efsw/src/efsw/WatcherFSEvents.cpp", + "src/thirdparty/efsw/src/efsw/WatcherWin32.cpp", + "src/thirdparty/efsw/src/efsw/FileWatcherKqueue.cpp", + "src/thirdparty/efsw/src/efsw/FileWatcherWin32.cpp", + "src/thirdparty/efsw/src/efsw/FileWatcherFSEvents.cpp" + } + elseif os.is("macosx") then + excludes { + "src/thirdparty/efsw/src/efsw/WatcherInotify.cpp", + "src/thirdparty/efsw/src/efsw/WatcherWin32.cpp", + "src/thirdparty/efsw/src/efsw/FileWatcherInotify.cpp", + "src/thirdparty/efsw/src/efsw/FileWatcherWin32.cpp" + } + elseif os.is("freebsd") then + excludes { + "src/thirdparty/efsw/src/efsw/WatcherInotify.cpp", + "src/thirdparty/efsw/src/efsw/WatcherWin32.cpp", + "src/thirdparty/efsw/src/efsw/WatcherFSEvents.cpp", + "src/thirdparty/efsw/src/efsw/FileWatcherInotify.cpp", + "src/thirdparty/efsw/src/efsw/FileWatcherWin32.cpp", + "src/thirdparty/efsw/src/efsw/FileWatcherFSEvents.cpp" + } + end + + build_base_cpp_configuration( "efsw" ) + + -- Library + project "eepp-main" + kind "StaticLib" + language "C++" + set_targetdir("libs/" .. os.get_real() .. "/") + files { "src/eepp/main/eepp_main.cpp" } + + project "eepp-static" + kind "StaticLib" + language "C++" + set_targetdir("libs/" .. os.get_real() .. "/") + build_eepp( "eepp-static" ) + + project "eepp-shared" + kind "SharedLib" + language "C++" + set_targetdir("libs/" .. os.get_real() .. "/") + build_eepp( "eepp" ) + + -- Examples + project "eepp-external-shader" + set_kind() + language "C++" + files { "src/examples/external_shader/*.cpp" } + build_link_configuration( "eepp-external-shader", true ) + + project "eepp-empty-window" + set_kind() + language "C++" + files { "src/examples/empty_window/*.cpp" } + build_link_configuration( "eepp-empty-window", true ) + + project "eepp-sound" + kind "ConsoleApp" + language "C++" + files { "src/examples/sound/*.cpp" } + build_link_configuration( "eepp-sound", true ) + + project "eepp-sprites" + set_kind() + language "C++" + files { "src/examples/sprites/*.cpp" } + build_link_configuration( "eepp-sprites", true ) + + project "eepp-fonts" + set_kind() + language "C++" + files { "src/examples/fonts/*.cpp" } + build_link_configuration( "eepp-fonts", true ) + + project "eepp-vbo-fbo-batch" + set_kind() + language "C++" + files { "src/examples/vbo_fbo_batch/*.cpp" } + build_link_configuration( "eepp-vbo-fbo-batch", true ) + + project "eepp-physics" + set_kind() + language "C++" + files { "src/examples/physics/*.cpp" } + build_link_configuration( "eepp-physics", true ) + + project "eepp-http-request" + kind "ConsoleApp" + language "C++" + files { "src/examples/http_request/*.cpp" } + includedirs { "src/thirdparty" } + build_link_configuration( "eepp-http-request", true ) + + project "eepp-ui-hello-world" + set_kind() + language "C++" + files { "src/examples/ui_hello_world/*.cpp" } + includedirs { "src/thirdparty" } + build_link_configuration( "eepp-ui-hello-world", true ) + + -- Tools + project "eepp-textureatlaseditor" + set_kind() + language "C++" + files { "src/tools/textureatlaseditor/*.cpp" } + build_link_configuration( "eepp-TextureAtlasEditor", true ) + + project "eepp-mapeditor" + set_kind() + language "C++" + files { "src/tools/mapeditor/*.cpp" } + build_link_configuration( "eepp-MapEditor", true ) + + project "eepp-uieditor" + set_kind() + language "C++" + includedirs { "src/thirdparty/efsw/include", "src/thirdparty" } + + if not os.is("windows") and not os.is("haiku") then + links { "pthread" } + elseif os.is("macosx") then + links { "CoreFoundation.framework", "CoreServices.framework" } + end + + links { "efsw-static", "pugixml-static" } + files { "src/tools/uieditor/*.cpp" } + build_link_configuration( "eepp-UIEditor", true ) + + project "ecode" + set_kind() + language "C++" + files { "src/tools/codeeditor/*.cpp" } + includedirs { "src/thirdparty/efsw/include", "src/thirdparty" } + links { "efsw-static" } + if not os.is("windows") and not os.is("haiku") then + links { "pthread" } + elseif os.is("macosx") then + links { "CoreFoundation.framework", "CoreServices.framework" } + end + build_link_configuration( "ecode", true ) + + project "eepp-texturepacker" + kind "ConsoleApp" + language "C++" + includedirs { "src/thirdparty" } + files { "src/tools/texturepacker/*.cpp" } + build_link_configuration( "eepp-TexturePacker", true ) + + -- Tests + project "eepp-test" + set_kind() + language "C++" + files { "src/tests/test_all/*.cpp" } + build_link_configuration( "eepp-test", true ) + + project "eepp-ui-perf-test" + set_kind() + language "C++" + files { "src/tests/ui_perf_test/*.cpp" } + includedirs { "src/thirdparty" } + build_link_configuration( "eepp-ui-perf-test", true ) + +if os.isfile("external_projects.lua") then + dofile("external_projects.lua") +end diff --git a/premake5.lua b/premake5.lua index fb762eb1c..b101f8625 100644 --- a/premake5.lua +++ b/premake5.lua @@ -845,8 +845,13 @@ workspace "eepp" set_kind() language "C++" files { "src/tools/codeeditor/*.cpp" } - incdirs { "src/thirdparty" } + incdirs { "src/thirdparty/efsw/include", "src/thirdparty" } + links { "efsw-static" } build_link_configuration( "ecode", true ) + filter "system:macosx" + links { "CoreFoundation.framework", "CoreServices.framework" } + filter { "system:not windows", "system:not haiku" } + links { "pthread" } project "eepp-texturepacker" kind "ConsoleApp" diff --git a/projects/linux/ee.creator.user b/projects/linux/ee.creator.user index dfc88af2e..a23376646 100644 --- a/projects/linux/ee.creator.user +++ b/projects/linux/ee.creator.user @@ -1,6 +1,6 @@ - + EnvironmentId diff --git a/projects/linux/ee.files b/projects/linux/ee.files index 61e4df193..2bd4ca5b6 100644 --- a/projects/linux/ee.files +++ b/projects/linux/ee.files @@ -1023,6 +1023,8 @@ ../../src/tools/codeeditor/autocompletemodule.hpp ../../src/tools/codeeditor/codeeditor.cpp ../../src/tools/codeeditor/codeeditor.hpp +../../src/tools/codeeditor/filesystemlistener.cpp +../../src/tools/codeeditor/filesystemlistener.hpp ../../src/tools/codeeditor/ignorematcher.cpp ../../src/tools/codeeditor/ignorematcher.hpp ../../src/tools/codeeditor/projectdirectorytree.cpp diff --git a/src/eepp/scene/action.cpp b/src/eepp/scene/action.cpp index e85cfb4b5..717d390d7 100644 --- a/src/eepp/scene/action.cpp +++ b/src/eepp/scene/action.cpp @@ -17,7 +17,7 @@ void Action::setFlags( const Uint32& flags ) { mFlags = flags; } -Uint32 Action::getTag() const { +String::HashType Action::getTag() const { return mTag; } diff --git a/src/eepp/scene/actionmanager.cpp b/src/eepp/scene/actionmanager.cpp index c93b99fe5..466f251aa 100644 --- a/src/eepp/scene/actionmanager.cpp +++ b/src/eepp/scene/actionmanager.cpp @@ -48,7 +48,8 @@ std::vector ActionManager::getActionsFromTarget( Node* target ) { return actions; } -std::vector ActionManager::getActionsByTagFromTarget( Node* target, const Uint32& tag ) { +std::vector ActionManager::getActionsByTagFromTarget( Node* target, + const String::HashType& tag ) { std::vector actions; for ( auto it = mActions.begin(); it != mActions.end(); ++it ) { @@ -65,7 +66,7 @@ void ActionManager::removeActionByTag( const Uint32& tag ) { removeAction( getActionByTag( tag ) ); } -void ActionManager::removeActionsByTagFromTarget( Node* target, const Uint32& tag ) { +void ActionManager::removeActionsByTagFromTarget( Node* target, const String::HashType& tag ) { std::vector removeList; for ( auto it = mActions.begin(); it != mActions.end(); ++it ) { diff --git a/src/eepp/scene/node.cpp b/src/eepp/scene/node.cpp index aecbaecab..a3d6aaef8 100644 --- a/src/eepp/scene/node.cpp +++ b/src/eepp/scene/node.cpp @@ -1442,7 +1442,7 @@ void Node::removeActions( const std::vector& actions ) { getActionManager()->removeActions( actions ); } -void Node::removeActionsByTag( const Uint32& tag ) { +void Node::removeActionsByTag( const String::HashType& tag ) { getActionManager()->removeActionsByTagFromTarget( this, tag ); } @@ -1458,8 +1458,11 @@ void Node::clearActions() { getActionManager()->removeAllActionsFromTarget( this ); } -void Node::runOnMainThread( Actions::Runnable::RunnableFunc runnable, const Time& delay ) { - runAction( Actions::Runnable::New( runnable, delay ) ); +void Node::runOnMainThread( Actions::Runnable::RunnableFunc runnable, const Time& delay, + const Uint32& tag ) { + Action* action = Actions::Runnable::New( runnable, delay ); + action->setTag( tag ); + runAction( action ); } Transform Node::getLocalTransform() const { @@ -1554,12 +1557,12 @@ Node* Node::getParentWidget() const { return NULL; } -void Node::sendParentSizeChange( const Vector2f& SizeChange ) { +void Node::sendParentSizeChange( const Vector2f& sizeChange ) { if ( reportSizeChangeToChilds() ) { Node* child = mChild; while ( NULL != child ) { - child->onParentSizeChange( SizeChange ); + child->onParentSizeChange( sizeChange ); child = child->getNextNode(); } } diff --git a/src/eepp/system/fileinfo.cpp b/src/eepp/system/fileinfo.cpp index 0eb42e9e9..74996e3e9 100644 --- a/src/eepp/system/fileinfo.cpp +++ b/src/eepp/system/fileinfo.cpp @@ -172,6 +172,10 @@ const Uint64& FileInfo::getInode() const { return mInode; } +bool FileInfo::isUninitialized() const { + return mModificationTime == 0; +} + bool FileInfo::operator==( const FileInfo& Other ) const { return ( mModificationTime == Other.mModificationTime && mSize == Other.mSize && mOwnerId == Other.mOwnerId && mGroupId == Other.mGroupId && diff --git a/src/eepp/ui/doc/textdocument.cpp b/src/eepp/ui/doc/textdocument.cpp index 154f58bcc..328d7342e 100644 --- a/src/eepp/ui/doc/textdocument.cpp +++ b/src/eepp/ui/doc/textdocument.cpp @@ -27,7 +27,7 @@ TextDocument::TextDocument( bool verbose ) : mUndoStack( this ), mVerbose( verbose ), mAutoCloseBracketsPairs( - {{'(', ')'}, {'[', ']'}, {'{', '}'}, {'\'', '\''}, {'"', '"'}, {'`', '`'}} ), + { { '(', ')' }, { '[', ']' }, { '{', '}' }, { '\'', '\'' }, { '"', '"' }, { '`', '`' } } ), mDefaultFileName( "untitled" ), mCleanChangeId( 0 ), mNonWordChars( DEFAULT_NON_WORD_CHARS ) { @@ -49,7 +49,8 @@ bool TextDocument::isEmpty() { void TextDocument::reset() { mFilePath = mDefaultFileName; - mSelection.set( {0, 0}, {0, 0} ); + mFileRealPath = FileInfo(); + mSelection.set( { 0, 0 }, { 0, 0 } ); mLines.clear(); mLines.emplace_back( String( "\n" ) ); mSyntaxDefinition = SyntaxDefinitionManager::instance()->getPlainStyle(); @@ -70,12 +71,13 @@ static String ptrGetLine( char* data, const size_t& size, size_t& position ) { } bool TextDocument::loadFromStream( IOStream& file ) { - return loadFromStream( file, "untitled" ); + return loadFromStream( file, "untitled", true ); } -bool TextDocument::loadFromStream( IOStream& file, std::string path ) { +bool TextDocument::loadFromStream( IOStream& file, std::string path, bool callReset ) { Clock clock; - reset(); + if ( callReset ) + reset(); mLines.clear(); if ( file.isOpen() ) { const size_t BLOCK_SIZE = EE_1MB; @@ -199,7 +201,7 @@ void TextDocument::guessIndentType() { } void TextDocument::resetSyntax() { - String header( getText( {{0, 0}, positionOffset( {0, 0}, 128 )} ) ); + String header( getText( { { 0, 0 }, positionOffset( { 0, 0 }, 128 ) } ) ); mSyntaxDefinition = SyntaxDefinitionManager::instance()->find( mFilePath, header ); } @@ -257,20 +259,23 @@ bool TextDocument::loadFromFile( const std::string& path ) { Pack* pack = PackManager::instance()->exists( pathFix ); if ( NULL != pack ) { mFilePath = pathFix; + mFileRealPath = FileInfo(); return loadFromPack( pack, pathFix ); } } IOStreamFile file( path, "rb" ); - bool ret = loadFromStream( file, path ); + bool ret = loadFromStream( file, path, true ); mFilePath = path; + mFileRealPath = FileInfo::isLink( mFilePath ) ? FileInfo( FileInfo( mFilePath ).linksTo() ) + : FileInfo( mFilePath ); resetSyntax(); return ret; } bool TextDocument::loadFromMemory( const Uint8* data, const Uint32& size ) { IOStreamMemory stream( (const char*)data, size ); - return loadFromStream( stream, mFilePath ); + return loadFromStream( stream, mFilePath, true ); } bool TextDocument::loadFromPack( Pack* pack, std::string filePackPath ) { @@ -284,18 +289,42 @@ bool TextDocument::loadFromPack( Pack* pack, std::string filePackPath ) { return ret; } +bool TextDocument::reload() { + bool ret = false; + std::string path( mFilePath ); + if ( mFileRealPath.exists() ) { + auto selection = mSelection; + mUndoStack.clear(); + cleanChangeId(); + IOStreamFile file( path, "rb" ); + ret = loadFromStream( file, path, false ); + mFileRealPath = FileInfo::isLink( mFilePath ) ? FileInfo( FileInfo( mFilePath ).linksTo() ) + : FileInfo( mFilePath ); + resetSyntax(); + notifyTextChanged(); + setSelection( selection.start() ); + } + return ret; +} + bool TextDocument::save( const std::string& path ) { if ( path.empty() || mDefaultFileName == path ) return false; if ( FileSystem::fileCanWrite( FileSystem::fileRemoveFileName( path ) ) ) { IOStreamFile file( path, "wb" ); mFilePath = path; + mSaving = true; if ( save( file ) ) { file.close(); + mFileRealPath = + FileInfo::isLink( mFilePath ) ? FileInfo( mFilePath ).linksTo() : mFilePath; + mSaving = false; notifyDocumentSaved(); return true; } else { mFilePath.clear(); + mFileRealPath = FileInfo(); + mSaving = false; } } return false; @@ -307,7 +336,7 @@ bool TextDocument::save( IOStream& stream ) { const std::string whitespaces( " \t\f\v\n\r" ); char nl = '\n'; if ( mIsBOM ) { - unsigned char bom[] = {0xEF, 0xBB, 0xBF}; + unsigned char bom[] = { 0xEF, 0xBB, 0xBF }; stream.write( (char*)bom, sizeof( bom ) ); } size_t lastLine = mLines.size() - 1; @@ -428,7 +457,7 @@ String TextDocument::getText( const TextRange& range ) const { return mLines[nrange.start().line()].substr( nrange.start().column(), nrange.end().column() - nrange.start().column() ); } - std::vector lines = {mLines[nrange.start().line()].substr( nrange.start().column() )}; + std::vector lines = { mLines[nrange.start().line()].substr( nrange.start().column() ) }; for ( auto i = nrange.start().line() + 1; i <= nrange.end().line() - 1; i++ ) { lines.emplace_back( mLines[i].getText() ); } @@ -478,7 +507,7 @@ TextPosition TextDocument::insert( TextPosition position, const String& text, TextPosition cursor = positionOffset( position, text.size() ); mUndoStack.pushSelection( undoStack, getSelection(), time ); - mUndoStack.pushRemove( undoStack, {position, cursor}, time ); + mUndoStack.pushRemove( undoStack, { position, cursor }, time ); notifyTextChanged(); @@ -671,7 +700,7 @@ TextPosition TextDocument::startOfContent( TextPosition start ) { break; } } - return {start.line(), indent}; + return { start.line(), indent }; } TextPosition TextDocument::startOfDoc() const { @@ -683,7 +712,7 @@ TextPosition TextDocument::endOfDoc() const { } TextRange TextDocument::getDocRange() const { - return {startOfDoc(), endOfDoc()}; + return { startOfDoc(), endOfDoc() }; } void TextDocument::deleteTo( int offset ) { @@ -847,8 +876,9 @@ void TextDocument::moveToStartOfContent() { void TextDocument::selectToStartOfContent() { TextPosition start = getSelection().start(); TextPosition indented = startOfContent( getSelection().start() ); - setSelection( {indented.column() == start.column() ? TextPosition( start.line(), 0 ) : indented, - getSelection().end()} ); + setSelection( + { indented.column() == start.column() ? TextPosition( start.line(), 0 ) : indented, + getSelection().end() } ); } void TextDocument::moveToStartOfLine() { @@ -881,12 +911,12 @@ void TextDocument::deleteCurrentLine() { return; } if ( getSelection().start().line() + 1 >= (Int64)linesCount() ) { - remove( {startOfLine( getSelection().start() ), - startOfLine( {getSelection().start().line() - 1, 0} )} ); + remove( { startOfLine( getSelection().start() ), + startOfLine( { getSelection().start().line() - 1, 0 } ) } ); setSelection( startOfLine( getSelection().start() ) ); } else { - remove( {startOfLine( getSelection().start() ), - startOfLine( {getSelection().start().line() + 1, 0} )} ); + remove( { startOfLine( getSelection().start() ), + startOfLine( { getSelection().start().line() + 1, 0 } ) } ); setSelection( startOfLine( getSelection().start() ) ); } } @@ -900,25 +930,25 @@ void TextDocument::selectToNextChar() { } void TextDocument::selectToPreviousWord() { - setSelection( {previousWordBoundary( getSelection().start() ), getSelection().end()} ); + setSelection( { previousWordBoundary( getSelection().start() ), getSelection().end() } ); } void TextDocument::selectToNextWord() { - setSelection( {nextWordBoundary( getSelection().start() ), getSelection().end()} ); + setSelection( { nextWordBoundary( getSelection().start() ), getSelection().end() } ); } void TextDocument::selectWord() { - setSelection( {nextWordBoundary( getSelection().start() ), - previousWordBoundary( getSelection().start() )} ); + setSelection( { nextWordBoundary( getSelection().start() ), + previousWordBoundary( getSelection().start() ) } ); } void TextDocument::selectLine() { if ( getSelection().start().line() + 1 < (Int64)linesCount() ) { setSelection( - {{getSelection().start().line() + 1, 0}, {getSelection().start().line(), 0}} ); + { { getSelection().start().line() + 1, 0 }, { getSelection().start().line(), 0 } } ); } else { - setSelection( - {{getSelection().start().line(), (Int64)line( getSelection().start().line() ).size()}, - {getSelection().start().line(), 0}} ); + setSelection( { { getSelection().start().line(), + (Int64)line( getSelection().start().line() ).size() }, + { getSelection().start().line(), 0 } } ); } } @@ -981,8 +1011,8 @@ void TextDocument::newLineAbove() { TextPosition indent = startOfContent( getSelection().start() ); if ( indent.column() != 0 ) input.insert( 0, line( start.line() ).getText().substr( 0, indent.column() ) ); - insert( {start.line(), 0}, input ); - setSelection( {start.line(), (Int64)input.size()} ); + insert( { start.line(), 0 }, input ); + setSelection( { start.line(), (Int64)input.size() } ); } void TextDocument::insertAtStartOfSelectedLines( const String& text, bool skipEmpty ) { @@ -992,7 +1022,7 @@ void TextDocument::insertAtStartOfSelectedLines( const String& text, bool skipEm for ( auto i = range.start().line(); i <= range.end().line(); i++ ) { const String& line = this->line( i ).getText(); if ( !skipEmpty || line.length() != 1 ) { - insert( {i, 0}, text ); + insert( { i, 0 }, text ); } } setSelection( TextPosition( range.start().line(), range.start().column() + text.size() ), @@ -1009,7 +1039,7 @@ void TextDocument::removeFromStartOfSelectedLines( const String& text, bool skip const String& line = this->line( i ).getText(); if ( !skipEmpty || line.length() != 1 ) { if ( line.substr( 0, text.length() ) == text ) { - remove( {{i, 0}, {i, static_cast( text.length() )}} ); + remove( { { i, 0 }, { i, static_cast( text.length() ) } } ); if ( i == range.start().line() ) { startRemoved = text.size(); } else if ( i == range.end().line() ) { @@ -1040,10 +1070,10 @@ void TextDocument::moveLinesUp() { appendLineIfLastLine( range.end().line() ); if ( range.start().line() > 0 ) { auto& text = line( range.start().line() - 1 ); - insert( {range.end().line() + 1, 0}, text.getText() ); - remove( {{range.start().line() - 1, 0}, {range.start().line(), 0}} ); - setSelection( {range.start().line() - 1, range.start().column()}, - {range.end().line() - 1, range.end().column()}, swap ); + insert( { range.end().line() + 1, 0 }, text.getText() ); + remove( { { range.start().line() - 1, 0 }, { range.start().line(), 0 } } ); + setSelection( { range.start().line() - 1, range.start().column() }, + { range.end().line() - 1, range.end().column() }, swap ); } } @@ -1053,10 +1083,10 @@ void TextDocument::moveLinesDown() { appendLineIfLastLine( range.end().line() + 1 ); if ( range.end().line() < (Int64)mLines.size() - 1 ) { auto text = line( range.end().line() + 1 ); - remove( {{range.end().line() + 1, 0}, {range.end().line() + 2, 0}} ); - insert( {range.start().line(), 0}, text.getText() ); - setSelection( {range.start().line() + 1, range.start().column()}, - {range.end().line() + 1, range.end().column()}, swap ); + remove( { { range.end().line() + 1, 0 }, { range.end().line() + 2, 0 } } ); + insert( { range.start().line(), 0 }, text.getText() ); + setSelection( { range.start().line() + 1, range.start().column() }, + { range.end().line() + 1, range.end().column() }, swap ); } } @@ -1100,7 +1130,7 @@ void TextDocument::print() const { } TextRange TextDocument::sanitizeRange( const TextRange& range ) const { - return {sanitizePosition( range.start() ), sanitizePosition( range.end() )}; + return { sanitizePosition( range.start() ), sanitizePosition( range.end() ) }; } bool TextDocument::getAutoCloseBrackets() const { @@ -1122,11 +1152,25 @@ void TextDocument::setAutoCloseBracketsPairs( mAutoCloseBracketsPairs = autoCloseBracketsPairs; } +bool TextDocument::isDirtyOnFileSystem() const { + return mDirtyOnFileSystem; +} + +void TextDocument::setDirtyOnFileSystem( bool dirtyOnFileSystem ) { + mDirtyOnFileSystem = dirtyOnFileSystem; + if ( mDirtyOnFileSystem ) + notifyDirtyOnFileSystem(); +} + +bool TextDocument::isSaving() const { + return mSaving; +} + TextPosition TextDocument::sanitizePosition( const TextPosition& position ) const { Int64 line = eeclamp( position.line(), 0UL, mLines.size() - 1 ); Int64 col = eeclamp( position.column(), 0UL, eemax( 0, mLines[line].size() - 1 ) ); - return {line, col}; + return { line, col }; } const TextDocument::IndentType& TextDocument::getIndentType() const { @@ -1171,6 +1215,10 @@ const std::string& TextDocument::getFilePath() const { return mFilePath; } +const FileInfo& TextDocument::getFileInfo() const { + return mFileRealPath; +} + bool TextDocument::isDirty() const { return mCleanChangeId != getCurrentChangeId(); } @@ -1221,7 +1269,7 @@ TextPosition TextDocument::find( String text, TextPosition from, const bool& cas : String::toLower( line( i ).getText() ).find( text ); } if ( String::StringType::npos != col ) { - return {(Int64)i, (Int64)col}; + return { (Int64)i, (Int64)col }; } } return TextPosition(); @@ -1261,7 +1309,7 @@ TextPosition TextDocument::findLast( String text, TextPosition from, const bool& : String::toLower( line( i ).getText() ).rfind( text ); } if ( String::StringType::npos != col ) { - return {(Int64)i, (Int64)col}; + return { (Int64)i, (Int64)col }; } } return TextPosition(); @@ -1281,7 +1329,7 @@ TextPosition TextDocument::replace( String search, const String& replace, TextPo if ( start.isValid() ) { TextPosition end = positionOffset( start, search.size() ); if ( end.isValid() ) { - setSelection( {start, end} ); + setSelection( { start, end } ); deleteTo( 0 ); textInput( replace ); return end; @@ -1318,7 +1366,7 @@ TextPosition TextDocument::findOpenBracket( TextPosition startPosition, } else if ( string[i] == openBracket ) { count--; if ( 0 == count ) { - return {line, i}; + return { line, i }; } } } @@ -1343,7 +1391,7 @@ TextPosition TextDocument::findCloseBracket( TextPosition startPosition, } else if ( string[i] == closeBracket ) { count--; if ( 0 == count ) { - return {line, i}; + return { line, i }; } } } @@ -1400,7 +1448,7 @@ void TextDocument::notifySelectionChanged() { void TextDocument::notifyDocumentSaved() { for ( auto& client : mClients ) { - client->onDocumentSaved(); + client->onDocumentSaved( this ); } } @@ -1428,6 +1476,12 @@ void TextDocument::notifyUndoRedo( const TextDocument::UndoRedo& eventType ) { } } +void TextDocument::notifyDirtyOnFileSystem() { + for ( auto& client : mClients ) { + client->onDocumentDirtyOnFileSystem( this ); + } +} + void TextDocument::initializeCommands() { mCommands["reset"] = [&] { reset(); }; mCommands["save"] = [&] { save(); }; diff --git a/src/eepp/ui/tools/uicodeeditorsplitter.cpp b/src/eepp/ui/tools/uicodeeditorsplitter.cpp index 61359073a..25f35b969 100644 --- a/src/eepp/ui/tools/uicodeeditorsplitter.cpp +++ b/src/eepp/ui/tools/uicodeeditorsplitter.cpp @@ -401,6 +401,13 @@ void UICodeEditorSplitter::forEachEditor( std::function r run( tabWidget->getTab( i )->getOwnedWidget()->asType() ); } +void UICodeEditorSplitter::forEachDoc( std::function run ) { + std::unordered_set docs; + forEachEditor( [&]( UICodeEditor* editor ) { docs.insert( editor->getDocumentRef().get() ); } ); + for ( auto doc : docs ) + run( *doc ); +} + void UICodeEditorSplitter::forEachEditorStoppable( std::function run ) { for ( auto tabWidget : mTabWidgets ) { for ( size_t i = 0; i < tabWidget->getTabCount(); i++ ) { @@ -411,6 +418,20 @@ void UICodeEditorSplitter::forEachEditorStoppable( std::function run ) { + for ( auto tabWidget : mTabWidgets ) { + for ( size_t i = 0; i < tabWidget->getTabCount(); i++ ) { + if ( run( *tabWidget->getTab( i ) + ->getOwnedWidget() + ->asType() + ->getDocumentRef() + .get() ) ) { + return; + } + } + } +} + std::vector UICodeEditorSplitter::getAllEditors() { std::vector editors; forEachEditor( [&]( UICodeEditor* editor ) { editors.push_back( editor ); } ); diff --git a/src/eepp/ui/uicodeeditor.cpp b/src/eepp/ui/uicodeeditor.cpp index a8e4fd9d6..0b80c61cf 100644 --- a/src/eepp/ui/uicodeeditor.cpp +++ b/src/eepp/ui/uicodeeditor.cpp @@ -832,7 +832,8 @@ Uint32 UICodeEditor::onMouseOver( const Vector2i& position, const Uint32& flags for ( auto& module : mModules ) if ( module->onMouseOver( this, position, flags ) ) return UIWidget::onMouseOver( position, flags ); - getUISceneNode()->setCursor( !mLocked ? Cursor::IBeam : Cursor::Arrow ); + if ( getEventDispatcher()->getMouseOverNode() == this ) + getUISceneNode()->setCursor( !mLocked ? Cursor::IBeam : Cursor::Arrow ); return UIWidget::onMouseOver( position, flags ); } @@ -1010,8 +1011,9 @@ void UICodeEditor::onDocumentUndoRedo( const TextDocument::UndoRedo& ) { onDocumentSelectionChange( {} ); } -void UICodeEditor::onDocumentSaved() { - sendCommonEvent( Event::OnSave ); +void UICodeEditor::onDocumentSaved( TextDocument* doc ) { + DocEvent event( this, doc, Event::OnDocumentSave ); + sendEvent( &event ); } void UICodeEditor::onDocumentClosed( TextDocument* doc ) { @@ -1019,6 +1021,11 @@ void UICodeEditor::onDocumentClosed( TextDocument* doc ) { sendEvent( &event ); } +void UICodeEditor::onDocumentDirtyOnFileSystem( TextDocument* doc ) { + DocEvent event( this, doc, Event::OnDocumentDirtyOnFileSysten ); + sendEvent( &event ); +} + std::pair UICodeEditor::getVisibleLineRange() { Float lineHeight = getLineHeight(); Float minLine = eemax( 0.f, eefloor( mScroll.y / lineHeight ) ); @@ -1781,6 +1788,7 @@ void UICodeEditor::drawLineText( const Int64& index, Vector2f position, const Fl if ( position.x + textWidth >= mScreenPos.x && position.x <= mScreenPos.x + mSize.getWidth() ) { Text line( "", mFont, fontSize ); + line.setTabWidth( mTabWidth ); const SyntaxColorScheme::Style& style = mColorScheme.getSyntaxStyle( token.type ); line.setStyleConfig( mFontStyleConfig ); if ( style.style ) diff --git a/src/eepp/ui/uilayout.cpp b/src/eepp/ui/uilayout.cpp index 4f4bd9b65..5b45edc3e 100644 --- a/src/eepp/ui/uilayout.cpp +++ b/src/eepp/ui/uilayout.cpp @@ -43,8 +43,8 @@ void UILayout::onPaddingChange() { tryUpdateLayout(); } -void UILayout::onParentSizeChange( const Vector2f& ) { - UIWidget::onParentChange(); +void UILayout::onParentSizeChange( const Vector2f& sizeChange ) { + UIWidget::onParentSizeChange( sizeChange ); if ( !getParent()->isLayout() ) { mPacking = false; tryUpdateLayout(); diff --git a/src/eepp/ui/uitextinput.cpp b/src/eepp/ui/uitextinput.cpp index 1ecdf870b..081a8b7d6 100644 --- a/src/eepp/ui/uitextinput.cpp +++ b/src/eepp/ui/uitextinput.cpp @@ -428,7 +428,7 @@ void UITextInput::onDocumentUndoRedo( const TextDocument::UndoRedo& ) { onSelectionChange(); } -void UITextInput::onDocumentSaved() {} +void UITextInput::onDocumentSaved( TextDocument* ) {} UITextInput* UITextInput::setMaxLength( const Uint32& maxLength ) { mMaxLength = maxLength; diff --git a/src/eepp/ui/uiwidget.cpp b/src/eepp/ui/uiwidget.cpp index 0aed5e2d5..17c06f905 100644 --- a/src/eepp/ui/uiwidget.cpp +++ b/src/eepp/ui/uiwidget.cpp @@ -522,9 +522,9 @@ UITooltip* UIWidget::getTooltip() { return mTooltip; } -void UIWidget::onParentSizeChange( const Vector2f& SizeChange ) { - updateAnchors( SizeChange ); - UINode::onParentSizeChange( SizeChange ); +void UIWidget::onParentSizeChange( const Vector2f& sizeChange ) { + updateAnchors( sizeChange ); + UINode::onParentSizeChange( sizeChange ); } void UIWidget::onPositionChange() { @@ -574,14 +574,18 @@ void UIWidget::notifyLayoutAttrChangeParent() { } } -void UIWidget::updateAnchors( const Vector2f& SizeChange ) { +void UIWidget::updateAnchors( const Vector2f& sizeChange ) { + if ( hasClass( "doc_alert" ) ) { + clipDisable(); + } + if ( !( mFlags & ( UI_ANCHOR_LEFT | UI_ANCHOR_TOP | UI_ANCHOR_RIGHT | UI_ANCHOR_BOTTOM ) ) ) return; Sizef newSize( getSize() ); if ( !( mFlags & UI_ANCHOR_LEFT ) ) { - setInternalPosition( Vector2f( mDpPos.x += SizeChange.x, mDpPos.y ) ); + setInternalPosition( Vector2f( mDpPos.x += sizeChange.x, mDpPos.y ) ); } if ( mFlags & UI_ANCHOR_RIGHT ) { @@ -595,7 +599,7 @@ void UIWidget::updateAnchors( const Vector2f& SizeChange ) { } if ( !( mFlags & UI_ANCHOR_TOP ) ) { - setInternalPosition( Vector2f( mDpPos.x, mDpPos.y += SizeChange.y ) ); + setInternalPosition( Vector2f( mDpPos.x, mDpPos.y += sizeChange.y ) ); } if ( mFlags & UI_ANCHOR_BOTTOM ) { @@ -620,7 +624,7 @@ void UIWidget::alignAgainstLayout() { pos.x = ( getParent()->getSize().getWidth() - getSize().getWidth() ) / 2; break; case UI_HALIGN_RIGHT: - pos.x = getParent()->getSize().getWidth() - mLayoutMargin.Right; + pos.x = getParent()->getSize().getWidth() - getSize().getWidth() - mLayoutMargin.Right; break; case UI_HALIGN_LEFT: pos.x = mLayoutMargin.Left; @@ -632,7 +636,8 @@ void UIWidget::alignAgainstLayout() { pos.y = ( getParent()->getSize().getHeight() - getSize().getHeight() ) / 2; break; case UI_VALIGN_BOTTOM: - pos.y = getParent()->getSize().getHeight() - mLayoutMargin.Bottom; + pos.y = + getParent()->getSize().getHeight() - getSize().getHeight() - mLayoutMargin.Bottom; break; case UI_VALIGN_TOP: pos.y = mLayoutMargin.Top; diff --git a/src/tools/codeeditor/codeeditor.cpp b/src/tools/codeeditor/codeeditor.cpp index 6d3721493..041665711 100644 --- a/src/tools/codeeditor/codeeditor.cpp +++ b/src/tools/codeeditor/codeeditor.cpp @@ -946,6 +946,10 @@ App::~App() { eeSAFE_DELETE( mEditorSplitter ); eeSAFE_DELETE( mAutoCompleteModule ); eeSAFE_DELETE( mConsole ); + if ( mFileWatcher ) + delete mFileWatcher; + if ( mFileSystemListener ) + delete mFileSystemListener; } void App::updateRecentFiles() { @@ -1627,6 +1631,14 @@ void App::onDocumentLoaded( UICodeEditor* editor, const std::string& path ) { UITab* tab = reinterpret_cast( editor->getData() ); tab->setTooltipText( path ); } + + TextDocument& doc = editor->getDocument(); + + if ( mFileWatcher && doc.hasFilepath() && + ( !mDirTree || !mDirTree->isDirInTree( doc.getFileInfo().getFilepath() ) ) ) { + std::string dir( FileSystem::fileRemoveFileName( doc.getFileInfo().getFilepath() ) ); + mFilesFolderWatches[dir] = mFileWatcher->addWatch( dir, mFileSystemListener ); + } } const CodeEditorConfig& App::getCodeEditorConfig() const { @@ -1666,6 +1678,7 @@ std::vector App::getUnlockedCommands() { } void App::closeEditors() { + removeFolderWatches(); mConfig.saveProject( mCurrentProject, mEditorSplitter, mConfigPath ); std::vector editors = mEditorSplitter->getAllEditors(); for ( auto editor : editors ) { @@ -1694,6 +1707,62 @@ void App::closeFolder() { } } +void App::createDocAlert( UICodeEditor* editor ) { + UILinearLayout* docAlert = editor->findByClass( "doc_alert" ); + + if ( docAlert ) + return; + + const std::string& msg = R"xml( + + + + + + + )xml"; + docAlert = static_cast( mUISceneNode->loadLayoutFromString( msg, editor ) ); + + editor->enableReportSizeChangeToChilds(); + + docAlert->find( "file_reload" ) + ->addEventListener( Event::MouseClick, [editor, docAlert]( const Event* event ) { + const MouseEvent* mouseEvent = static_cast( event ); + if ( mouseEvent->getFlags() & EE_BUTTON_LMASK ) { + editor->getDocument().reload(); + editor->disableReportSizeChangeToChilds(); + docAlert->close(); + editor->setFocus(); + } + } ); + + docAlert->find( "file_overwrite" ) + ->addEventListener( Event::MouseClick, [editor, docAlert]( const Event* event ) { + const MouseEvent* mouseEvent = static_cast( event ); + if ( mouseEvent->getFlags() & EE_BUTTON_LMASK ) { + editor->getDocument().save(); + editor->disableReportSizeChangeToChilds(); + docAlert->close(); + editor->setFocus(); + } + } ); + + docAlert->find( "file_ignore" ) + ->addEventListener( Event::MouseClick, [docAlert, editor]( const Event* event ) { + const MouseEvent* mouseEvent = static_cast( event ); + if ( mouseEvent->getFlags() & EE_BUTTON_LMASK ) { + editor->disableReportSizeChangeToChilds(); + docAlert->close(); + editor->setFocus(); + } + } ); +} + void App::onCodeEditorCreated( UICodeEditor* editor, TextDocument& doc ) { const CodeEditorConfig& config = mConfig.editor; editor->setFontSize( config.fontSize.asDp( 0, Sizef(), mUISceneNode->getDPI() ) ); @@ -1780,8 +1849,12 @@ void App::onCodeEditorCreated( UICodeEditor* editor, TextDocument& doc ) { doc.setCommand( "load-current-dir", [&] { loadCurrentDirectory(); } ); doc.setCommand( "menu-toggle", [&] { toggleSettingsMenu(); } ); doc.setCommand( "switch-side-panel", [&] { switchSidePanel(); } ); - editor->addEventListener( Event::OnSave, [&]( const Event* event ) { + + editor->addEventListener( Event::OnDocumentSave, [&]( const Event* event ) { UICodeEditor* editor = event->getNode()->asType(); + updateEditorTabTitle( editor ); + if ( mEditorSplitter->getCurEditor() == editor ) + editor->setFocus(); if ( editor->getDocument().getFilePath() == mKeybindingsPath ) { mKeybindings.clear(); mKeybindingsInvert.clear(); @@ -1793,11 +1866,41 @@ void App::onCodeEditorCreated( UICodeEditor* editor, TextDocument& doc ) { } } ); + editor->addEventListener( + Event::OnDocumentDirtyOnFileSysten, [&, editor]( const Event* event ) { + const DocEvent* docEvent = static_cast( event ); + FileInfo file( docEvent->getDoc()->getFileInfo().getFilepath() ); + TextDocument* doc = docEvent->getDoc(); + if ( doc->getFileInfo() != file ) { + if ( doc->isDirty() ) { + editor->runOnMainThread( [&, editor]() { createDocAlert( editor ); } ); + } else { + auto hash = String::hash( docEvent->getDoc()->getFilePath() ); + editor->removeActionsByTag( hash ); + editor->runOnMainThread( [doc]() { doc->reload(); }, Seconds( 0.5f ), hash ); + } + } + } ); + if ( !mKeybindings.empty() ) { editor->getKeyBindings().reset(); editor->getKeyBindings().addKeybindsString( mKeybindings ); } + editor->addEventListener( Event::OnDocumentClosed, [&]( const Event* event ) { + if ( !appInstance ) + return; + const DocEvent* docEvent = static_cast( event ); + std::string dir( FileSystem::fileRemoveFileName( docEvent->getDoc()->getFilePath() ) ); + auto itWatch = mFilesFolderWatches.find( dir ); + if ( mFileWatcher && itWatch != mFilesFolderWatches.end() ) { + if ( !mDirTree || !mDirTree->isDirInTree( dir ) ) { + mFileWatcher->removeWatch( itWatch->second ); + } + mFilesFolderWatches.erase( itWatch ); + } + } ); + if ( config.autoComplete && !mAutoCompleteModule ) setAutoComplete( config.autoComplete ); @@ -1988,6 +2091,18 @@ void App::updateEditorState() { } } +void App::removeFolderWatches() { + if ( mFileWatcher ) { + for ( auto dir : mFolderWatches ) + mFileWatcher->removeWatch( dir ); + mFolderWatches.clear(); + + for ( auto fileFolder : mFilesFolderWatches ) + mFileWatcher->removeWatch( fileFolder.second ); + mFilesFolderWatches.clear(); + } +} + void App::loadDirTree( const std::string& path ) { Clock* clock = eeNew( Clock, () ); mDirTree = std::make_unique( path, mThreadPool ); @@ -1999,6 +2114,12 @@ void App::loadDirTree( const std::string& path ) { eeDelete( clock ); mDirTreeReady = true; mUISceneNode->runOnMainThread( [&] { updateLocateTable(); } ); + if ( mFileWatcher ) { + removeFolderWatches(); + auto newDirs = dirTree.getDirectories(); + for ( auto dir : newDirs ) + mFolderWatches.insert( mFileWatcher->addWatch( dir, mFileSystemListener ) ); + } }, SyntaxDefinitionManager::instance()->getExtensionsPatternsSupported() ); } @@ -2252,6 +2373,16 @@ void App::init( const std::string& file, const Float& pidelDensity ) { padding-top: 0dp; padding-bottom: 0dp; } + .doc_alert { + padding: 16dp; + border-width: 2dp; + border-radius: 4dp; + border-color: var(--primary); + background-color: var(--back); + margin-right: 24dp; + margin-top: 24dp; + cursor: arrow; + } @@ -2262,7 +2393,7 @@ void App::init( const std::string& file, const Float& pidelDensity ) { - + @@ -2393,6 +2524,12 @@ void App::init( const std::string& file, const Float& pidelDensity ) { SyntaxColorScheme::loadFromFile( mResPath + "assets/colorschemes/colorschemes.conf" ), mInitColorScheme ); +#if EE_PLATFORM != EE_PLATFORM_EMSCRIPTEN + mFileWatcher = new efsw::FileWatcher(); + mFileSystemListener = new FileSystemListener( mEditorSplitter ); + mFileWatcher->watch(); +#endif + initSearchBar(); initGlobalSearchBar(); diff --git a/src/tools/codeeditor/codeeditor.hpp b/src/tools/codeeditor/codeeditor.hpp index 736da6f63..b9ca5bbc0 100644 --- a/src/tools/codeeditor/codeeditor.hpp +++ b/src/tools/codeeditor/codeeditor.hpp @@ -2,10 +2,12 @@ #define EE_TOOLS_CODEEDITOR_HPP #include "appconfig.hpp" +#include "filesystemlistener.hpp" #include "projectdirectorytree.hpp" #include "projectsearch.hpp" #include "uitreeviewglobalsearch.hpp" #include +#include class WidgetCommandExecuter { public: @@ -196,6 +198,10 @@ class App : public UICodeEditorSplitter::Client { std::string mCurrentProject; FontTrueType* mFont{ nullptr }; FontTrueType* mFontMono{ nullptr }; + efsw::FileWatcher* mFileWatcher{ nullptr }; + FileSystemListener* mFileSystemListener{ nullptr }; + std::unordered_set mFolderWatches; + std::unordered_map mFilesFolderWatches; void saveAllProcess(); @@ -322,6 +328,10 @@ class App : public UICodeEditorSplitter::Client { std::shared_ptr model ); void switchSidePanel(); + + void removeFolderWatches(); + + void createDocAlert( UICodeEditor* editor ); }; #endif // EE_TOOLS_CODEEDITOR_HPP diff --git a/src/tools/codeeditor/filesystemlistener.cpp b/src/tools/codeeditor/filesystemlistener.cpp new file mode 100644 index 000000000..e693df122 --- /dev/null +++ b/src/tools/codeeditor/filesystemlistener.cpp @@ -0,0 +1,36 @@ +#include "filesystemlistener.hpp" + +FileSystemListener::FileSystemListener( UICodeEditorSplitter* splitter ) : mSplitter( splitter ) {} + +void FileSystemListener::handleFileAction( efsw::WatchID, const std::string& dir, + const std::string& filename, efsw::Action action, + std::string ) { + if ( action == efsw::Actions::Modified ) { + FileInfo file( dir + filename ); + if ( file.isLink() ) + file = FileInfo( file.linksTo() ); + if ( isFileOpen( file ) ) + notifyChange( file ); + } +} + +bool FileSystemListener::isFileOpen( const FileInfo& file ) { + bool found = false; + mSplitter->forEachDocStoppable( [&]( TextDocument& doc ) { + if ( file.getFilepath() == doc.getFileInfo().getFilepath() ) { + found = true; + return true; + } + return false; + } ); + return found; +} + +void FileSystemListener::notifyChange( const FileInfo& file ) { + mSplitter->forEachDoc( [&]( TextDocument& doc ) { + if ( file.getFilepath() == doc.getFileInfo().getFilepath() && + file.getModificationTime() != doc.getFileInfo().getModificationTime() && + !doc.isSaving() ) + doc.setDirtyOnFileSystem( true ); + } ); +} diff --git a/src/tools/codeeditor/filesystemlistener.hpp b/src/tools/codeeditor/filesystemlistener.hpp new file mode 100644 index 000000000..7f64c5996 --- /dev/null +++ b/src/tools/codeeditor/filesystemlistener.hpp @@ -0,0 +1,30 @@ +#ifndef FILESYSTEMLISTENER_HPP +#define FILESYSTEMLISTENER_HPP + +#include +#include +#include +#include + +using namespace EE::System; +using namespace EE::UI; +using namespace EE::UI::Tools; + +class FileSystemListener : public efsw::FileWatchListener { + public: + FileSystemListener( UICodeEditorSplitter* codeSplitter ); + + virtual ~FileSystemListener() {} + + void handleFileAction( efsw::WatchID, const std::string& dir, const std::string& filename, + efsw::Action action, std::string ); + + protected: + UICodeEditorSplitter* mSplitter; + + bool isFileOpen( const FileInfo& file ); + + void notifyChange( const FileInfo& file ); +}; + +#endif // FILESYSTEMLISTENER_HPP diff --git a/src/tools/codeeditor/projectdirectorytree.cpp b/src/tools/codeeditor/projectdirectorytree.cpp index b889ea34e..4fed68d7c 100644 --- a/src/tools/codeeditor/projectdirectorytree.cpp +++ b/src/tools/codeeditor/projectdirectorytree.cpp @@ -1,4 +1,5 @@ #include "projectdirectorytree.hpp" +#include #include #include @@ -16,6 +17,7 @@ void ProjectDirectoryTree::scan( const ProjectDirectoryTree::ScanCompleteEvent& [&, acceptedPattern, ignoreHidden] { #endif Lock l( mFilesMutex ); + mDirectories.push_back( mPath ); if ( !acceptedPattern.empty() ) { std::vector files; std::vector names; @@ -63,7 +65,7 @@ std::shared_ptr ProjectDirectoryTree::fuzzyMatchTree( const std:: std::vector files; std::vector names; for ( size_t i = 0; i < mNames.size(); i++ ) - matchesMap.insert( {String::fuzzyMatch( mNames[i], match ), i} ); + matchesMap.insert( { String::fuzzyMatch( mNames[i], match ), i } ); for ( auto& res : matchesMap ) { if ( names.size() < max ) { names.emplace_back( mNames[res.second] ); @@ -121,6 +123,20 @@ const std::vector& ProjectDirectoryTree::getFiles() const { return mFiles; } +const std::vector& ProjectDirectoryTree::getDirectories() const { + return mDirectories; +} + +bool ProjectDirectoryTree::isFileInTree( const std::string& filePath ) const { + return std::find( mFiles.begin(), mFiles.end(), filePath ) != mFiles.end(); +} + +bool ProjectDirectoryTree::isDirInTree( const std::string& dirTree ) const { + std::string dir( FileSystem::fileRemoveFileName( dirTree ) ); + FileSystem::dirAddSlashAtEnd( dir ); + return std::find( mDirectories.begin(), mDirectories.end(), dirTree ) != mDirectories.end(); +} + void ProjectDirectoryTree::getDirectoryFiles( std::vector& files, std::vector& names, std::string directory, @@ -145,6 +161,9 @@ void ProjectDirectoryTree::getDirectoryFiles( std::vector& files, FileSystem::dirAddSlashAtEnd( fullpath ); if ( currentDirs.find( fullpath ) == currentDirs.end() ) continue; + mDirectories.push_back( fullpath ); + } else { + mDirectories.push_back( fullpath ); } IgnoreMatcherManager dirMatcher( fullpath ); getDirectoryFiles( files, names, fullpath, currentDirs, ignoreHidden, diff --git a/src/tools/codeeditor/projectdirectorytree.hpp b/src/tools/codeeditor/projectdirectorytree.hpp index 573ea4686..e1281bc76 100644 --- a/src/tools/codeeditor/projectdirectorytree.hpp +++ b/src/tools/codeeditor/projectdirectorytree.hpp @@ -70,11 +70,18 @@ class ProjectDirectoryTree { const std::vector& getFiles() const; + const std::vector& getDirectories() const; + + bool isFileInTree( const std::string& filePath ) const; + + bool isDirInTree( const std::string& dirTree ) const; + protected: std::string mPath; std::shared_ptr mPool; std::vector mFiles; std::vector mNames; + std::vector mDirectories; bool mIsReady; Mutex mFilesMutex; IgnoreMatcherManager mIgnoreMatcher;