From 548d673e8bf968b6d8d0567e4fe36dab236faab3 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Thu, 11 Feb 2021 13:43:36 +0100 Subject: [PATCH] Add drag and drop support for images and assets (#1497) --- apps/OpenSpace/main.cpp | 12 ++++++ include/openspace/engine/openspaceengine.h | 1 + scripts/drag_drop_handler.lua | 43 ++++++++++++++++++++ src/engine/openspaceengine.cpp | 47 ++++++++++++++++++++++ 4 files changed, 103 insertions(+) create mode 100644 scripts/drag_drop_handler.lua diff --git a/apps/OpenSpace/main.cpp b/apps/OpenSpace/main.cpp index b370da39e6..2efc3e7061 100644 --- a/apps/OpenSpace/main.cpp +++ b/apps/OpenSpace/main.cpp @@ -660,6 +660,17 @@ void mainCharCallback(unsigned int codepoint, int modifiers) { +void mainDropCallback(int amount, const char** paths) { + ghoul_assert(amount > 0, "Expected at least one file path"); + ghoul_assert(paths, "expected non-nullptr"); + + for (int i = 0; i < amount; ++i) { + global::openSpaceEngine->handleDragDrop(paths[i]); + } +} + + + std::vector mainEncodeFun() { ZoneScoped LTRACE("main::mainEncodeFun(begin)"); @@ -1252,6 +1263,7 @@ int main(int argc, char* argv[]) { callbacks.mousePos = mainMousePosCallback; callbacks.mouseScroll = mainMouseScrollCallback; callbacks.character = mainCharCallback; + callbacks.drop = mainDropCallback; callbacks.encode = mainEncodeFun; callbacks.decode = mainDecodeFun; Log::instance().setNotifyLevel(Log::Level::Debug); diff --git a/include/openspace/engine/openspaceengine.h b/include/openspace/engine/openspaceengine.h index 42612a9368..2710a709f3 100644 --- a/include/openspace/engine/openspaceengine.h +++ b/include/openspace/engine/openspaceengine.h @@ -86,6 +86,7 @@ public: void touchDetectionCallback(TouchInput input); void touchUpdateCallback(TouchInput input); void touchExitCallback(TouchInput input); + void handleDragDrop(const std::string& file); std::vector encode(); void decode(std::vector data); diff --git a/scripts/drag_drop_handler.lua b/scripts/drag_drop_handler.lua new file mode 100644 index 0000000000..7042333633 --- /dev/null +++ b/scripts/drag_drop_handler.lua @@ -0,0 +1,43 @@ +-- This script gets two parameters in its global scope: +-- filename: The full path for the file that was dropped on the application. +-- Example: C:/OpenSpace/openspace.cfg +-- basename: Only the name of the actual file with extension, but without the full rest +-- of the path. +-- Example: openspace.cfg +-- extension: The extention of the file +-- Example: .cfg +-- +-- From this script, we need to return the script that we want to be executed in response +-- to the drag event. If we don't want anything to happen, don't return anything or +-- return an empty string + +if filename == nil or filename == "" or + basename == nil or basename == "" or + extension == nil or extension == "" then + do return "" end +end + +-- Lua doesn't enjoy \ that are used by Windows extensively. So we convert all \ into / +filename = filename:gsub("\\", "/") +basename = basename:gsub("\\", "/") +basename_without_extension = basename:sub(0, #basename - extension:len()) + +is_image_file = function(extension) + return extension == ".png" or extension == ".jpg" or extension == ".jpeg" or + extension == ".tif" or extension == ".tga" or extension == ".bmp" or + extension == ".psd" or extension == ".gif" or extension == ".hdr" or + extension == ".pic" or extension == ".pnm" +end + +if is_image_file(extension) then + identifier = basename_without_extension:gsub(" ", "_") + return [[openspace.addScreenSpaceRenderable({ + Identifier = "]] .. identifier .. [[", + Type = "ScreenSpaceImageLocal", + TexturePath = "]] .. filename .. [[" + });]] +elseif extension == ".asset" then + return [[openspace.asset.add("]] .. filename .. [[")]] +elseif extension == ".osrec" or extension == ".osrectxt" then + return [[openspace.sessionRecording.startPlayback("]] .. basename .. [[")]] +end diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index 00c135152d..3d1d6dd868 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -83,6 +83,7 @@ #include #include #include +#include #include #include #include @@ -1444,6 +1445,52 @@ void OpenSpaceEngine::touchExitCallback(TouchInput input) { } } +void OpenSpaceEngine::handleDragDrop(const std::string& file) { + std::filesystem::path f(file); + + ghoul::lua::LuaState s(ghoul::lua::LuaState::IncludeStandardLibrary::Yes); + std::string absolutePath = absPath("${SCRIPTS}/drag_drop_handler.lua"); + int status = luaL_loadfile(s, absolutePath.c_str()); + if (status != LUA_OK) { + std::string error = lua_tostring(s, -1); + LERROR(error); + return; + } + + ghoul::lua::push(s, file); + lua_setglobal(s, "filename"); + + std::string basename = f.filename().string(); + ghoul::lua::push(s, basename); + lua_setglobal(s, "basename"); + + std::string extension = f.extension().string(); + std::transform( + extension.begin(), extension.end(), + extension.begin(), + [](char c) { return static_cast(::tolower(c)); } + ); + ghoul::lua::push(s, extension); + lua_setglobal(s, "extension"); + + status = lua_pcall(s, 0, 1, 0); + if (status != LUA_OK) { + std::string error = lua_tostring(s, -1); + LERROR(error); + return; + } + + if (lua_isnil(s, -1)) { + LWARNING(fmt::format("Unhandled file dropped: {}", file)); + return; + } + + std::string script = ghoul::lua::value(s); + global::scriptEngine->queueScript( + script, + scripting::ScriptEngine::RemoteScripting::Yes + ); +} std::vector OpenSpaceEngine::encode() { ZoneScoped