From e0d9e383b04c443c9c48e8dcc8fc03416a76c9d2 Mon Sep 17 00:00:00 2001 From: GhostofCookie Date: Wed, 26 Feb 2025 10:05:10 -0500 Subject: [PATCH 1/3] Removed submodules and added flow editor into this repo instead. --- .gitmodules | 20 ---- CMakeLists.txt | 64 ++++++----- cmake/CPM.cmake | 24 ++++ cmake/add_libs.cmake | 29 +---- include/flow/ui/windows/PropertyWindow.hpp | 34 ++++++ programs/editor/CMakeLists.txt | 40 +++++++ programs/editor/src/main.cpp | 127 +++++++++++++++++++++ src/Editor.cpp | 12 +- src/EditorNodes.hpp | 110 ++++++++++++++++++ src/FileExplorer.cpp | 1 - src/widgets/PropertyTree.cpp | 3 +- src/windows/GraphWindow.cpp | 6 +- src/windows/PropertyWindow.cpp | 106 +++++++++++++++++ third_party/CMakeLists.txt | 19 --- third_party/flow-core | 1 - third_party/hello_imgui | 1 - third_party/imgui | 1 - third_party/imgui-node-editor | 1 - third_party/nfd | 1 - third_party/spdlog | 1 - 20 files changed, 494 insertions(+), 107 deletions(-) delete mode 100644 .gitmodules create mode 100644 cmake/CPM.cmake create mode 100644 include/flow/ui/windows/PropertyWindow.hpp create mode 100644 programs/editor/CMakeLists.txt create mode 100644 programs/editor/src/main.cpp create mode 100644 src/windows/PropertyWindow.cpp delete mode 100644 third_party/CMakeLists.txt delete mode 160000 third_party/flow-core delete mode 160000 third_party/hello_imgui delete mode 160000 third_party/imgui delete mode 160000 third_party/imgui-node-editor delete mode 160000 third_party/nfd delete mode 160000 third_party/spdlog diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 6ab78f9..0000000 --- a/.gitmodules +++ /dev/null @@ -1,20 +0,0 @@ -[submodule "third_party/nfd"] - path = third_party/nfd - url = https://github.com/btzy/nativefiledialog-extended.git -[submodule "third_party/flow-core"] - path = third_party/flow-core - url = https://github.com/InFlowStructure/flow-core.git -[submodule "third_party/spdlog"] - path = third_party/spdlog - url = https://github.com/gabime/spdlog.git -[submodule "third_party/hello_imgui"] - path = third_party/hello_imgui - url = https://github.com/pthom/hello_imgui.git -[submodule "third_party/imgui-node-editor"] - path = third_party/imgui-node-editor - url = https://github.com/pthom/imgui-node-editor.git - branch = imgui_bundle -[submodule "third_party/imgui"] - path = third_party/imgui - url = https://github.com/pthom/imgui.git - branch = imgui_bundle diff --git a/CMakeLists.txt b/CMakeLists.txt index 336a364..fbef805 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,41 +15,50 @@ elseif(MSVC) add_compile_definitions(_CRT_SECURE_NO_WARNINGS) endif() -# ----------------------------------------------------------------------------- -# Options -# ----------------------------------------------------------------------------- - -option(flow-ui_USE_EXTERNAL_FLOW_CORE "Use an external Flow Core library" OFF) - # ----------------------------------------------------------------------------- # Dependencies # ----------------------------------------------------------------------------- -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake") - -find_package(nlohmann_json CONFIG QUIET) -if (NOT nlohmann_json_FOUND) - include(FetchContent) - FetchContent_Declare( - nlohmann_json OVERRIDE_FIND_PACKAGE - URL https://github.com/nlohmann/json/releases/download/v3.11.3/json.tar.xz - ) - FetchContent_MakeAvailable(nlohmann_json) -endif() - -if (flow-ui_USE_EXTERNAL_FLOW_CORE) - find_package(flow-core REQUIRED) -endif() - if(flow-ui_INSTALL) - if (NOT flow-ui_USE_EXTERNAL_FLOW_CORE) - set(flow-core_INSTALL ON CACHE BOOL "" FORCE) - endif() + set(flow-core_INSTALL ON CACHE BOOL "" FORCE) set(SPDLOG_INSTALL ON CACHE BOOL "" FORCE) set(NFD_INSTALL ON CACHE BOOL "" FORCE) endif() -add_subdirectory(third_party) +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake") + +include(cmake/CPM.cmake) + +CPMAddPackage("gh:InFlowStructure/flow-core#ae2f12e") +CPMAddPackage("gh:gabime/spdlog@1.15.1") +CPMAddPackage("gh:btzy/nativefiledialog-extended@1.2.1") + +FetchContent_Declare( + imgui + GIT_REPOSITORY https://github.com/pthom/imgui.git + GIT_TAG imgui_bundle +) +FetchContent_Declare( + imgui_node_editor + GIT_REPOSITORY https://github.com/pthom/imgui-node-editor.git + GIT_TAG imgui_bundle +) +FetchContent_MakeAvailable(imgui imgui_node_editor) + + +set(HELLOIMGUI_DOWNLOAD_FREETYPE_IF_NEEDED OFF CACHE BOOL "") +set(HELLOIMGUI_USE_FREETYPE OFF CACHE BOOL "") +set(HELLOIMGUI_USE_EXTERNAL_JSON ON CACHE BOOL "") +set(HELLOIMGUI_BUILD_IMGUI OFF CACHE BOOL "" FORCE) +set(HELLOIMGUI_IMGUI_SOURCE_DIR ${imgui_SOURCE_DIR} CACHE STRING "" FORCE) +CPMAddPackage("gh:GhostofCookie/hello_imgui#bb61203") + +include(FetchContent) +include(cmake/add_libs.cmake) +include(${hello_imgui_SOURCE_DIR}/hello_imgui_cmake/msvc/msvc_target_group.cmake) + +add_imgui(${imgui_SOURCE_DIR}) +add_simple_external_library_with_sources(imgui_node_editor ${imgui_node_editor_SOURCE_DIR}) # ----------------------------------------------------------------------------- # Library @@ -93,6 +102,7 @@ add_library(${PROJECT_NAME} SHARED src/windows/GraphWindow.cpp src/windows/ModuleManagerWindow.cpp src/windows/NodeExplorerWindow.cpp + src/windows/PropertyWindow.cpp src/windows/ShortcutsWindow.cpp # Widget source files @@ -143,6 +153,8 @@ target_link_libraries(${PROJECT_NAME} PRIVATE ) target_compile_definitions(${PROJECT_NAME} PUBLIC IMGUI_DEFINE_MATH_OPERATORS) +add_subdirectory(programs/editor) + # ----------------------------------------------------------------------------- # Install # ----------------------------------------------------------------------------- diff --git a/cmake/CPM.cmake b/cmake/CPM.cmake new file mode 100644 index 0000000..47e2e87 --- /dev/null +++ b/cmake/CPM.cmake @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: MIT +# +# SPDX-FileCopyrightText: Copyright (c) 2019-2023 Lars Melchior and contributors + +set(CPM_DOWNLOAD_VERSION 0.40.5) +set(CPM_HASH_SUM "c46b876ae3b9f994b4f05a4c15553e0485636862064f1fcc9d8b4f832086bc5d") + +if(CPM_SOURCE_CACHE) + set(CPM_DOWNLOAD_LOCATION "${CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake") +elseif(DEFINED ENV{CPM_SOURCE_CACHE}) + set(CPM_DOWNLOAD_LOCATION "$ENV{CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake") +else() + set(CPM_DOWNLOAD_LOCATION "${CMAKE_BINARY_DIR}/cmake/CPM_${CPM_DOWNLOAD_VERSION}.cmake") +endif() + +# Expand relative path. This is important if the provided path contains a tilde (~) +get_filename_component(CPM_DOWNLOAD_LOCATION ${CPM_DOWNLOAD_LOCATION} ABSOLUTE) + +file(DOWNLOAD + https://github.com/cpm-cmake/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake + ${CPM_DOWNLOAD_LOCATION} EXPECTED_HASH SHA256=${CPM_HASH_SUM} +) + +include(${CPM_DOWNLOAD_LOCATION}) diff --git a/cmake/add_libs.cmake b/cmake/add_libs.cmake index 09f51e5..3708bbb 100644 --- a/cmake/add_libs.cmake +++ b/cmake/add_libs.cmake @@ -19,41 +19,14 @@ function(add_imgui imgui_dir) target_compile_options(imgui PRIVATE "/wd4297") endif() - if(PROJECT_IS_TOP_LEVEL AND NOT SKBUILD) - install(TARGETS imgui DESTINATION ./lib/) - endif() - - if(IMGUI_BUNDLE_BUILD_PYTHON) - target_compile_definitions(imgui PUBLIC ImTextureID=int) - endif() - if (UNIX) target_compile_options(imgui PUBLIC -fPIC) endif() - hello_imgui_msvc_target_group_sources(imgui) - endif() -endfunction() -function (add_hello_imgui) - if (UNIX) - add_compile_options(-fPIC) - endif() - - set(BUILD_SHARED_LIBS OFF) - set(imgui_dir ${CMAKE_CURRENT_LIST_DIR}/imgui) - add_imgui(${imgui_dir}) - - set(HELLOIMGUI_BUILD_IMGUI OFF CACHE BOOL "" FORCE) - set(HELLOIMGUI_IMGUI_SOURCE_DIR ${imgui_dir} CACHE STRING "" FORCE) - - add_subdirectory(hello_imgui) - - if (WIN32) - set_target_properties(hello_imgui PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON) + hello_imgui_msvc_target_group_sources(imgui) endif() endfunction() - function(add_simple_external_library_with_sources lib_target_name lib_folder) file(GLOB lib_sources ${lib_folder}/*.cpp ${lib_folder}/*.h) diff --git a/include/flow/ui/windows/PropertyWindow.hpp b/include/flow/ui/windows/PropertyWindow.hpp new file mode 100644 index 0000000..7594e24 --- /dev/null +++ b/include/flow/ui/windows/PropertyWindow.hpp @@ -0,0 +1,34 @@ +// Copyright (c) 2024, Cisco Systems, Inc. +// All rights reserved. + +#pragma once + +#include "flow/ui/Core.hpp" +#include "flow/ui/Window.hpp" + +#include +#include + +#include +#include + +FLOW_UI_NAMESPACE_START + +class PropertyWindow : public Window +{ + public: + PropertyWindow(std::shared_ptr env); + virtual ~PropertyWindow() = default; + + virtual void Draw() override; + + void SetCurrentGraph(std::shared_ptr graph) { _graph = graph; } + + static inline const std::string Name = "Properties"; + + private: + std::weak_ptr _env; + std::weak_ptr _graph; +}; + +FLOW_UI_NAMESPACE_END diff --git a/programs/editor/CMakeLists.txt b/programs/editor/CMakeLists.txt new file mode 100644 index 0000000..7bbbd4e --- /dev/null +++ b/programs/editor/CMakeLists.txt @@ -0,0 +1,40 @@ +cmake_minimum_required(VERSION 3.10) + +project(FlowEditor VERSION 1.0.1 LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# ----------------------------------------------------------------------------- +# Dependencies +# ----------------------------------------------------------------------------- + +CPMAddPackage("gh:jarro2783/cxxopts@3.2.0") + +# ----------------------------------------------------------------------------- +# Executable +# ----------------------------------------------------------------------------- + +if(MSVC) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /utf-8") +endif() + +hello_imgui_add_app(${PROJECT_NAME} + src/main.cpp + + ASSETS_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/assets/ +) +target_link_libraries(${PROJECT_NAME} PUBLIC + flow-ui::flow-ui + cxxopts + imgui_node_editor +) + +if(MSVC) + add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + $ + $ + COMMAND_EXPAND_LISTS + ) +endif() diff --git a/programs/editor/src/main.cpp b/programs/editor/src/main.cpp new file mode 100644 index 0000000..c007f35 --- /dev/null +++ b/programs/editor/src/main.cpp @@ -0,0 +1,127 @@ +#include +#include +#include +#include + +#include +#include +#include +#include + +int main(int argc, char** argv) +{ + std::string filename; + +#ifndef FLOW_WINDOWS + // clang-format off + cxxopts::Options options("FlowEditor"); + options.add_options() + ("f,flow", "Flow file to open", cxxopts::value()) + ("l,log_level", "Logging level [trace = 0, debug = 1, info = 2, warn = 3, err = 4, critical = 5, off = 6]", cxxopts::value()) + ("h,help", "Print usage"); + // clang-format on + + cxxopts::ParseResult result; + + try + { + result = options.parse(argc, argv); + } + catch (const cxxopts::exceptions::exception& e) + { + std::cerr << "Caught exception while parsing arguments: " << e.what() << std::endl; + return EXIT_FAILURE; + } + + if (result.count("help")) + { + std::cerr << options.help() << std::endl; + return EXIT_SUCCESS; + } + + if (result.count("flow")) + { + filename = result["flow"].as(); + } + + if (result.count("log_level")) + { + spdlog::set_level(static_cast(result["log_level"].as())); + } +#endif + + flow::ui::Editor app(filename); + + app.LoadFonts = [](flow::ui::Config& config) { + config.DefaultFont = flow::ui::LoadFont("fonts/DroidSans.ttf", 18.f); + config.NodeHeaderFont = flow::ui::LoadFont("fonts/DroidSans.ttf", 20.f); + config.IconFont = flow::ui::LoadFont("fonts/fontawesome-webfont.ttf", 18.f); + }; + + app.SetupStyle = [](flow::ui::Style& style) { + style.WindowBorderSize = 5.f; + style.FrameBorderSize = 2.f; + style.TabRounding = 8.f; + style.TabBarBorderSize = 0.f; + style.CellPadding = {.Width = 7.f, .Height = 7.f}; + + auto& imgui_colours = style.Colours.BaseColours; + using BaseColour = flow::ui::Style::BaseColour; + + imgui_colours[BaseColour::WindowBg] = flow::ui::Colour(21, 21, 21); + imgui_colours[BaseColour::PopupBg] = flow::ui::Colour(15, 15, 15, 175); + imgui_colours[BaseColour::Border] = flow::ui::Colour(15, 15, 15); + imgui_colours[BaseColour::PopupBg] = imgui_colours[BaseColour::WindowBg]; + imgui_colours[BaseColour::FrameBg] = flow::ui::Colour(15, 15, 15); + imgui_colours[BaseColour::MenuBarBg] = flow::ui::Colour(21, 21, 21); + imgui_colours[BaseColour::TitleBg] = flow::ui::Colour(21, 21, 21); + imgui_colours[BaseColour::TitleBgActive] = imgui_colours[BaseColour::TitleBg]; + imgui_colours[BaseColour::Tab] = flow::ui::Colour(21, 21, 21); + imgui_colours[BaseColour::TabDimmed] = flow::ui::Colour(21, 21, 21); + imgui_colours[BaseColour::TabHovered] = flow::ui::Colour(47, 47, 47); + imgui_colours[BaseColour::TabSelected] = flow::ui::Colour(3, 98, 195); + imgui_colours[BaseColour::TabDimmedSelected] = imgui_colours[BaseColour::TabSelected]; + imgui_colours[BaseColour::Button] = flow::ui::Colour(32, 32, 32); + imgui_colours[BaseColour::ButtonHovered] = flow::ui::Colour(3, 98, 195); + imgui_colours[BaseColour::ButtonActive] = flow::ui::Colour(13, 39, 77); + imgui_colours[BaseColour::ScrollbarBg] = flow::ui::Colour(21, 21, 21); + imgui_colours[BaseColour::ScrollbarGrab] = flow::ui::Colour(86, 86, 86); + imgui_colours[BaseColour::TableBorderLight] = flow::ui::Colour(21, 21, 21); + imgui_colours[BaseColour::TableBorderStrong] = flow::ui::Colour(21, 21, 21); + imgui_colours[BaseColour::TableRowBg] = flow::ui::Colour(36, 36, 36); + imgui_colours[BaseColour::TableRowBgAlt] = flow::ui::Colour(36, 36, 36); + imgui_colours[BaseColour::Header] = flow::ui::Colour(47, 47, 47); + imgui_colours[BaseColour::HeaderHovered] = flow::ui::Colour(50, 50, 50); + imgui_colours[BaseColour::CheckMark] = flow::ui::Colour(3, 98, 195); + + auto& colours = style.Colours.EditorColours; + using EditorColour = flow::ui::Style::EditorColour; + + colours[EditorColour::Bg] = flow::ui::Colour(38, 38, 38); + colours[EditorColour::Grid] = flow::ui::Colour(52, 52, 52); + colours[EditorColour::NodeBg] = flow::ui::Colour(15, 17, 15, 240); + colours[EditorColour::NodeBorder] = flow::ui::Colour(0, 0, 0); + colours[EditorColour::SelNodeBorder] = flow::ui::Colour(255, 255, 255); + colours[EditorColour::Flow] = flow::ui::Colour(32, 191, 85); + colours[EditorColour::FlowMarker] = flow::ui::Colour(32, 191, 85); + colours[EditorColour::HighlightLinkBorder] = flow::ui::Colour(0, 188, 235); + colours[EditorColour::SelLinkBorder] = flow::ui::Colour(0, 188, 235); + }; + + try + { + app.Run(); + } + catch (const std::exception& e) + { + SPDLOG_CRITICAL("Exiting with error: {0}", e.what()); + return EXIT_FAILURE; + } + catch (...) + { + SPDLOG_CRITICAL("Exiting with unknown error"); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/src/Editor.cpp b/src/Editor.cpp index 489f315..1f600e5 100644 --- a/src/Editor.cpp +++ b/src/Editor.cpp @@ -10,6 +10,7 @@ #include "utilities/Conversions.hpp" #include "windows/ModuleManagerWindow.hpp" #include "windows/NodeExplorerWindow.hpp" +#include "windows/PropertyWindow.hpp" #include "windows/ShortcutsWindow.hpp" #include @@ -40,7 +41,7 @@ HelloImGui::RunnerParams _params; Editor::Editor(const std::string& initial_file) { - _params.appWindowParams.windowTitle = "Flow Code"; + _params.appWindowParams.windowTitle = "Flow Editor"; _params.appWindowParams.borderless = false; _params.appWindowParams.restorePreviousGeometry = true; _params.iniFolderType = HelloImGui::IniFolderType::TempFolder; @@ -123,7 +124,7 @@ void Editor::Init(const std::string& initial_file) } }); - _env->GetFactory()->RegisterNodeClass("Editor", "Preview"); + _factory->RegisterNodeClass("Editor", "Preview"); _factory->RegisterNodeView(); _factory->RegisterInputType(false); @@ -153,7 +154,13 @@ void Editor::Init(const std::string& initial_file) AddDockspace(PropertyDockspace, DefaultDockspace, 0.25f, DockspaceSplitDirection::Left); AddDockspace("PropertySubSpace", PropertyDockspace, 0.5f, DockspaceSplitDirection::Down); + AddDockspace("MiscSpace", DefaultDockspace, 0.25f, DockspaceSplitDirection::Down); + auto property_window = std::make_shared(_env); + OnActiveGraphChanged.Bind(flow::IndexableName{property_window->GetName()}, + [=](const auto& g) { property_window->SetCurrentGraph(g); }); + + AddWindow(std::move(property_window), PropertyDockspace); AddWindow(std::move(node_explorer), "PropertySubSpace"); AddWindow(std::make_shared(_env, default_modules_path), "PropertySubSpace", false); AddWindow(std::make_shared(), PropertyDockspace, false); @@ -288,6 +295,7 @@ void Editor::DrawMainMenuBar() { std::filesystem::create_directory(default_modules_path); std::filesystem::copy_file(filename, new_module_file, std::filesystem::copy_options::skip_existing); + _env->LoadModule(new_module_file); } catch (const std::exception& e) { diff --git a/src/EditorNodes.hpp b/src/EditorNodes.hpp index f6d3e89..caf1aff 100644 --- a/src/EditorNodes.hpp +++ b/src/EditorNodes.hpp @@ -98,6 +98,116 @@ struct PreviewNodeView : NodeView } }; +template +struct FunctionTraits; + +template +struct FunctionTraits +{ + using ReturnType = std::invoke_result_t; + using ArgTypes = std::tuple; +}; + +template Func> +class FunctionWrapperNode : public Node +{ + protected: + using FuncTraits = FunctionTraits; + using OutputType = typename FuncTraits::ReturnType; + + private: + template + void AddInputs(std::integer_sequence) + { + (AddInput>( + {input_names[Idx] = "in" + std::to_string(Idx)}, ""), + ...); + } + + template + auto GetInputs(std::integer_sequence) + { + return std::make_tuple( + GetInputData>(IndexableName{input_names[Idx]})...); + } + + template + json SaveInputs(std::integer_sequence) const + { + json inputs_json; + ( + [&, this] { + const auto& key = input_names[Idx]; + if (auto x = GetInputData>(IndexableName{key})) + { + inputs_json[key] = x->Get(); + } + }(), + ...); + + return inputs_json; + } + + template + void RestoreInputs(json& j, std::integer_sequence) + { + ( + [&, this] { + const auto& key = input_names[Idx]; + if (!j.contains(key)) + { + return; + } + + SetInputData(IndexableName{key}, + MakeNodeData>(j[key]), false); + }(), + ...); + } + + public: + explicit FunctionWrapperNode(const std::string& uuid_str, const std::string& name, std::shared_ptr env) + : Node(uuid_str, TypeName_v>, name, std::move(env)), _func{Func} + { + AddInputs(std::make_integer_sequence>{}); + + AddOutput("result", "result"); + } + + virtual ~FunctionWrapperNode() = default; + + protected: + void Compute() override + { + auto inputs = GetInputs(std::make_integer_sequence>{}); + + if (std::apply([](auto&&... args) { return (!args || ...); }, inputs)) return; + + auto result = std::apply([&](auto&&... args) { return _func(args->Get()...); }, inputs); + this->SetOutputData("result", MakeNodeData(std::move(result))); + } + + json SaveInputs() const override + { + return SaveInputs(std::make_integer_sequence>{}); + } + + void RestoreInputs(const json& j) override + { + RestoreInputs(const_cast(j), std::make_integer_sequence>{}); + } + + private: + std::add_pointer_t _func; + std::array> input_names{""}; +}; + +#ifndef FLOW_WINDOWS +#define WRAP_FUNCTION_IN_NODE_TYPE(func, ...) FunctionWrapperNode +#else +#define WRAP_FUNCTION_IN_NODE_TYPE(func, ...) FunctionWrapperNode +#endif + FLOW_UI_NAMESPACE_END struct PreviewNode : public flow::Node diff --git a/src/FileExplorer.cpp b/src/FileExplorer.cpp index b2474aa..fdf8a62 100644 --- a/src/FileExplorer.cpp +++ b/src/FileExplorer.cpp @@ -90,7 +90,6 @@ std::filesystem::path FileExplorer::Save(std::filesystem::path save_path, std::s std::filesystem::path FileExplorer::GetHomePath() { - #ifdef FLOW_WINDOWS const char* dir = std::getenv("USERPROFILE"); #else diff --git a/src/widgets/PropertyTree.cpp b/src/widgets/PropertyTree.cpp index cdadb5f..6079cc1 100644 --- a/src/widgets/PropertyTree.cpp +++ b/src/widgets/PropertyTree.cpp @@ -65,7 +65,8 @@ void PropertyTree::operator()() noexcept continue; } - auto property_table = Table(category_name + "##table", _columns, ImGui::GetItemRectSize().x + 1.f); + auto property_table = + Table(category_name + "##table", _columns, static_cast(ImGui::GetItemRectSize().x + 1.f)); for (const auto& widget : widgets) { property_table.AddEntry(widget); diff --git a/src/windows/GraphWindow.cpp b/src/windows/GraphWindow.cpp index 9a8122f..963b359 100644 --- a/src/windows/GraphWindow.cpp +++ b/src/windows/GraphWindow.cpp @@ -237,10 +237,6 @@ GraphWindow::GraphWindow(std::shared_ptr graph) _editor_ctx = std::unique_ptr(std::bit_cast(ed::CreateEditor(&config))); - auto& canvas_view = const_cast(GetEditorDetailContext(_editor_ctx)->GetView()); - canvas_view.Origin = {0, 0}; - canvas_view.InvScale = 75; - auto& ed_style = GetEditorDetailContext(GetEditorContext())->GetStyle(); ed_style.NodeBorderWidth = 0.5f; ed_style.FlowDuration = 1.f; @@ -371,6 +367,7 @@ try } ImGui::SetCursorScreenPos(cursorTopLeft); + ed::Suspend(); static ed::NodeId context_node_id = 0; @@ -390,6 +387,7 @@ try _get_popup_location = true; _new_node_link_pin = nullptr; } + ed::Resume(); if (_get_popup_location) diff --git a/src/windows/PropertyWindow.cpp b/src/windows/PropertyWindow.cpp new file mode 100644 index 0000000..5c54b29 --- /dev/null +++ b/src/windows/PropertyWindow.cpp @@ -0,0 +1,106 @@ +// Copyright (c) 2024, Cisco Systems, Inc. +// All rights reserved. + +#include "PropertyWindow.hpp" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +FLOW_UI_NAMESPACE_START + +using namespace ax; +namespace ed = ax::NodeEditor; + +constexpr Colour empty_property_text_colour = Colour(175, 175, 175); + +struct CentredText : public widgets::Text +{ + CentredText(const std::string& text, const Colour& c) + : Text(text, c, {widgets::Text::HorizontalAlignment::Centre, widgets::Text::VerticalAlignment::Centre}) + { + } + + virtual ~CentredText() = default; +}; + +PropertyWindow::PropertyWindow(std::shared_ptr env) : Window(PropertyWindow::Name), _env{env} {} + +struct NodeProperty +{ + std::string Name; + flow::SharedNode Node; +}; + +void PropertyWindow::Draw() +{ + auto env = _env.lock(); + if (!env) return; + + auto graph = _graph.lock(); + if (!GetEditorContext() || !graph) + { + CentredText("Nothing to show", empty_property_text_colour)(); + return; + } + + ed::SetCurrentEditor(std::bit_cast(GetEditorContext().get())); + + std::array selected_ids; + auto result = ed::GetSelectedNodes(selected_ids.data(), 256); + + if (result == 0) + { + CentredText("Select one or more nodes", empty_property_text_colour)(); + return; + } + + std::set ids(selected_ids.begin(), std::next(selected_ids.begin(), result)); + + std::vector nodes; + nodes.reserve(result); + + graph->Visit([&](auto& node) { + if (!ids.contains(std::hash{}(node->ID()))) return; + nodes.emplace_back(node); + }); + + for (auto& node : nodes) + { + + std::string c_name = node->GetName() + "##" + std::to_string(std::hash{}(node->ID())); + widgets::PropertyTree properties(c_name, 2); + + const auto make_port_data_property = [&](const auto& port) -> std::vector> { + return { + std::make_shared("Type"), + std::make_shared(std::string{port->GetDataType()}), + std::make_shared("Value"), + std::make_shared(port->GetData() ? port->GetData()->ToString() : "None"), + }; + }; + + for (const auto& [key, input] : node->GetInputPorts()) + { + const std::string key_name{std::string_view(key)}; + properties.AddProperty(key_name, make_port_data_property(input), "Inputs"); + } + + for (const auto& [key, output] : node->GetOutputPorts()) + { + const std::string key_name{std::string_view(key)}; + properties.AddProperty(key_name, make_port_data_property(output), "Outputs"); + } + + properties(); + } +} + +FLOW_UI_NAMESPACE_END diff --git a/third_party/CMakeLists.txt b/third_party/CMakeLists.txt deleted file mode 100644 index 0b7d213..0000000 --- a/third_party/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ -if (NOT flow-ui_USE_EXTERNAL_FLOW_CORE) - set(flow-core_USE_EXTERNAL_JSON ON CACHE BOOL "") - add_subdirectory(flow-core) -endif() - -set(HELLOIMGUI_DOWNLOAD_FREETYPE_IF_NEEDED OFF CACHE BOOL "") -set(HELLOIMGUI_USE_FREETYPE OFF CACHE BOOL "") - -include(add_libs) -include(hello_imgui/hello_imgui_cmake/hello_imgui_add_app.cmake) -include(hello_imgui/hello_imgui_cmake/msvc/msvc_target_group.cmake) - -add_hello_imgui() -add_simple_external_library_with_sources(imgui_node_editor ${CMAKE_CURRENT_SOURCE_DIR}/imgui-node-editor) - -add_subdirectory(nfd) - -set(CMAKE_POSITION_INDEPENDENT_CODE ON) -add_subdirectory(spdlog) diff --git a/third_party/flow-core b/third_party/flow-core deleted file mode 160000 index 460adfa..0000000 --- a/third_party/flow-core +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 460adfac699d63c2533441f8e2dc810762e85d23 diff --git a/third_party/hello_imgui b/third_party/hello_imgui deleted file mode 160000 index 7b8657c..0000000 --- a/third_party/hello_imgui +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 7b8657c4b2c2d57f0a7db6049f181d8718f8720f diff --git a/third_party/imgui b/third_party/imgui deleted file mode 160000 index df2b6d6..0000000 --- a/third_party/imgui +++ /dev/null @@ -1 +0,0 @@ -Subproject commit df2b6d6b68ad0151eb76780fead73fa7053d401d diff --git a/third_party/imgui-node-editor b/third_party/imgui-node-editor deleted file mode 160000 index 3966e21..0000000 --- a/third_party/imgui-node-editor +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 3966e21ac9d43b159e6d19493e20ab5e2e8465ec diff --git a/third_party/nfd b/third_party/nfd deleted file mode 160000 index 29e3bcb..0000000 --- a/third_party/nfd +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 29e3bcb578345b9fa345d1d7683f00c150565ca3 diff --git a/third_party/spdlog b/third_party/spdlog deleted file mode 160000 index 96a8f62..0000000 --- a/third_party/spdlog +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 96a8f6250cbf4e8c76387c614f666710a2fa9bad From 64744d345e9df6b3e9393edb965fce74a1ee3a17 Mon Sep 17 00:00:00 2001 From: GhostofCookie Date: Wed, 26 Feb 2025 10:21:08 -0500 Subject: [PATCH 2/3] Fix mac and linux builds. Trying to fix linux build for spdlog. Ading position independent code for hello_imgui as well. Explicitly add fPIC to compile options. --- CMakeLists.txt | 10 ++++++++-- src/EditorNodes.hpp | 9 +++++---- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fbef805..f065ac7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,7 +30,6 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake") include(cmake/CPM.cmake) CPMAddPackage("gh:InFlowStructure/flow-core#ae2f12e") -CPMAddPackage("gh:gabime/spdlog@1.15.1") CPMAddPackage("gh:btzy/nativefiledialog-extended@1.2.1") FetchContent_Declare( @@ -45,12 +44,16 @@ FetchContent_Declare( ) FetchContent_MakeAvailable(imgui imgui_node_editor) - set(HELLOIMGUI_DOWNLOAD_FREETYPE_IF_NEEDED OFF CACHE BOOL "") set(HELLOIMGUI_USE_FREETYPE OFF CACHE BOOL "") set(HELLOIMGUI_USE_EXTERNAL_JSON ON CACHE BOOL "") set(HELLOIMGUI_BUILD_IMGUI OFF CACHE BOOL "" FORCE) set(HELLOIMGUI_IMGUI_SOURCE_DIR ${imgui_SOURCE_DIR} CACHE STRING "" FORCE) + +if (UNIX) + add_compile_options(-fPIC) +endif() + CPMAddPackage("gh:GhostofCookie/hello_imgui#bb61203") include(FetchContent) @@ -60,6 +63,9 @@ include(${hello_imgui_SOURCE_DIR}/hello_imgui_cmake/msvc/msvc_target_group.cmake add_imgui(${imgui_SOURCE_DIR}) add_simple_external_library_with_sources(imgui_node_editor ${imgui_node_editor_SOURCE_DIR}) +set(CMAKE_POSITION_INDEPENDENT_CODE ON) +CPMAddPackage("gh:gabime/spdlog@1.15.1") + # ----------------------------------------------------------------------------- # Library # ----------------------------------------------------------------------------- diff --git a/src/EditorNodes.hpp b/src/EditorNodes.hpp index caf1aff..2df8bab 100644 --- a/src/EditorNodes.hpp +++ b/src/EditorNodes.hpp @@ -169,7 +169,7 @@ class FunctionWrapperNode : public Node explicit FunctionWrapperNode(const std::string& uuid_str, const std::string& name, std::shared_ptr env) : Node(uuid_str, TypeName_v>, name, std::move(env)), _func{Func} { - AddInputs(std::make_integer_sequence>{}); + AddInputs(std::make_integer_sequence>{}); AddOutput("result", "result"); } @@ -179,7 +179,7 @@ class FunctionWrapperNode : public Node protected: void Compute() override { - auto inputs = GetInputs(std::make_integer_sequence>{}); + auto inputs = GetInputs(std::make_integer_sequence>{}); if (std::apply([](auto&&... args) { return (!args || ...); }, inputs)) return; @@ -189,12 +189,13 @@ class FunctionWrapperNode : public Node json SaveInputs() const override { - return SaveInputs(std::make_integer_sequence>{}); + return SaveInputs(std::make_integer_sequence>{}); } void RestoreInputs(const json& j) override { - RestoreInputs(const_cast(j), std::make_integer_sequence>{}); + RestoreInputs(const_cast(j), + std::make_integer_sequence>{}); } private: From fd87a8f045b846309330a7b453e9e2a3d9fac942 Mon Sep 17 00:00:00 2001 From: GhostofCookie Date: Wed, 26 Feb 2025 12:29:14 -0500 Subject: [PATCH 3/3] Updating flow core version. --- CMakeLists.txt | 4 ++-- src/windows/GraphWindow.cpp | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f065ac7..71a054e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,7 +29,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake") include(cmake/CPM.cmake) -CPMAddPackage("gh:InFlowStructure/flow-core#ae2f12e") +CPMAddPackage("gh:InFlowStructure/flow-core@1.2.0") CPMAddPackage("gh:btzy/nativefiledialog-extended@1.2.1") FetchContent_Declare( @@ -54,7 +54,7 @@ if (UNIX) add_compile_options(-fPIC) endif() -CPMAddPackage("gh:GhostofCookie/hello_imgui#bb61203") +CPMAddPackage("gh:GhostofCookie/hello_imgui#0e0adb7") include(FetchContent) include(cmake/add_libs.cmake) diff --git a/src/windows/GraphWindow.cpp b/src/windows/GraphWindow.cpp index 963b359..a3edf50 100644 --- a/src/windows/GraphWindow.cpp +++ b/src/windows/GraphWindow.cpp @@ -776,9 +776,9 @@ void GraphWindow::OnLoadNode(const flow::SharedNode& node, const json& position_ { auto view_factory = std::dynamic_pointer_cast(GetEnv()->GetFactory()); node_view = view_factory->CreateNodeView(node); - node_view->Node->OnSetOutput.Bind("ShowLinkFlowing", [=, this, node_id = node->ID()](const IndexableName& key) { - ShowLinkFlowing(node_id, key); - }); + node_view->Node->OnSetOutput.Bind( + "ShowLinkFlowing", + [=, this, node_id = node->ID()](const IndexableName& key, auto) { ShowLinkFlowing(node_id, key); }); _item_views.emplace(node_view->ID(), node_view); } @@ -812,7 +812,7 @@ flow::SharedNode GraphWindow::CreateNode(const std::string& class_name, const st throw std::runtime_error("Failed to create node: " + display_name); } - new_node->OnSetOutput.Bind("ShowLinkFlowing", [=, this, node_id = new_node->ID()](const IndexableName& key) { + new_node->OnSetOutput.Bind("ShowLinkFlowing", [=, this, node_id = new_node->ID()](const IndexableName& key, auto) { ShowLinkFlowing(node_id, key); }); @@ -973,7 +973,7 @@ void GraphWindow::CreateNodesAction(const json& SPDLOG_json) auto node_view = factory->CreateNodeView(node); node->OnSetOutput.Bind("ShowLinkFlowing", - [=, this, id = node->ID()](const auto& key) { ShowLinkFlowing(id, key); }); + [=, this, id = node->ID()](const auto& key, auto) { ShowLinkFlowing(id, key); }); const ImVec2 pos = position_json; const ImVec2 new_pos = ImGui::GetMousePos() + (pos - first_pos);