Commit c45b6837 authored by Gauthier Quesnel's avatar Gauthier Quesnel
Browse files

gui: add a group/ungroup mode

parent f9d78d8d
......@@ -2,7 +2,8 @@ cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
project(irritator-gui VERSION 0.1.0 LANGUAGES CXX)
set(gui_sources
dialog-file.cpp imnodes.cpp imnodes.hpp window-logger.cpp node-editor.cpp
dialog-file.cpp gui.hpp imnodes.cpp imnodes.hpp window-logger.cpp
node-editor.hpp node-editor.cpp
${PROJECT_SOURCE_DIR}/../../external/imgui/imgui.cpp
${PROJECT_SOURCE_DIR}/../../external/imgui/imgui.h
${PROJECT_SOURCE_DIR}/../../external/imgui/imgui_demo.cpp
......
......@@ -3,6 +3,7 @@
// http://www.boost.org/LICENSE_1_0.txt)
#include "gui.hpp"
#include "node-editor.hpp"
#include <fmt/format.h>
......
......@@ -5,21 +5,10 @@
#ifndef ORG_VLEPROJECT_IRRITATOR_APP_GUI_2020
#define ORG_VLEPROJECT_IRRITATOR_APP_GUI_2020
#include <imgui.h>
#include <filesystem>
#include <string>
namespace irt {
enum class simulation_status
{
success,
running,
uninitialized,
internal_error,
};
void
node_editor_initialize();
......@@ -29,22 +18,6 @@ node_editor_show();
void
node_editor_shutdown();
struct window_logger
{
ImGuiTextBuffer buffer;
ImGuiTextFilter filter;
ImVector<int> line_offsets;
bool auto_scroll = true;
bool scroll_to_bottom = false;
window_logger() = default;
void clear() noexcept;
void log(const int level, const char* fmt, ...) IM_FMTARGS(3);
void log(const int level, const char* fmt, va_list args) IM_FMTLIST(3);
void show(bool* is_show);
};
/* Filesytem dialog box */
bool
......
......@@ -1942,6 +1942,35 @@ SetNodeGridSpacePos(int node_id, const ImVec2& grid_pos)
node.origin = grid_pos;
}
ImVec2
GetNodeScreenSpacePos(int node_id)
{
// Remember to call Initialize() before using any other functions!
assert(initialized);
EditorContext& editor = editor_context_get();
NodeData& node = editor.nodes.find_or_create_new(node_id);
return grid_space_to_editor_space(node.origin);
}
ImVec2
GetNodeGridSpacePos(int node_id)
{
// Remember to call Initialize() before using any other functions!
assert(initialized);
EditorContext& editor = editor_context_get();
NodeData& node = editor.nodes.find_or_create_new(node_id);
return node.origin;
}
void
ClearSelectedNodesAndLinks()
{
assert(initialized);
EditorContext& editor = editor_context_get();
editor.selected_link_indices.clear();
editor.selected_node_indices.clear();
}
void
SetNodeDraggable(int node_id, const bool draggable)
{
......
......@@ -272,6 +272,12 @@ void
SetNodeScreenSpacePos(int node_id, const ImVec2& screen_space_pos);
void
SetNodeGridSpacePos(int node_id, const ImVec2& grid_pos);
ImVec2
GetNodeScreenSpacePos(int node_id);
ImVec2
GetNodeGridSpacePos(int node_id);
// Enable or disable the ability to click and drag a specific node.
void
SetNodeDraggable(int node_id, const bool draggable);
......@@ -304,6 +310,9 @@ GetSelectedNodes(int* node_ids);
void
GetSelectedLinks(int* link_ids);
void
ClearSelectedNodesAndLinks();
// Was the previous attribute active? This will continuously return true while
// the left mouse button is being pressed over the UI content of the attribute.
bool
......
This diff is collapsed.
// Copyright (c) 2020 INRA Distributed under the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef ORG_VLEPROJECT_IRRITATOR_APP_NODE_EDITOR_2020
#define ORG_VLEPROJECT_IRRITATOR_APP_NODE_EDITOR_2020
#include <irritator/core.hpp>
#include <filesystem>
#include <fstream>
#include <thread>
#include <unordered_map>
#include <variant>
#include <vector>
#include "imnodes.hpp"
#include <imgui.h>
namespace irt {
template<typename Identifier>
constexpr Identifier
undefined() noexcept
{
static_assert(
std::is_enum<Identifier>::value,
"Identifier must be a enumeration: enum class id : unsigned {};");
return static_cast<Identifier>(0);
}
enum class editor_id : u64;
enum class cluster_id : u64;
using child_id = std::variant<model_id, cluster_id>;
enum class simulation_status
{
success,
running,
uninitialized,
internal_error,
};
static inline constexpr int not_found = -1;
struct top_cluster
{
std::vector<child_id> children;
std::vector<int> nodes;
int next_node_id = 0;
static inline constexpr int not_found = -1;
int get_index(const child_id id) const noexcept
{
auto it = std::find(std::begin(children), std::end(children), id);
if (it == std::end(children))
return not_found;
return static_cast<int>(std::distance(std::begin(children), it));
}
int get_index(const int node) const noexcept
{
auto it = std::find(std::begin(nodes), std::end(nodes), node);
if (it == std::end(nodes))
return not_found;
return static_cast<int>(std::distance(std::begin(nodes), it));
}
//const child_id get_child(const int node) const noexcept
//{
// if (auto found = get_index(node); found != not_found)
// return children[found];
// return undefined<child_id>();
//}
//const int get_node(const child_id id) const noexcept
//{
// if (auto found = get_index(id); found != not_found)
// return nodes[found];
// return not_found;
//}
void clear() noexcept
{
children.clear();
nodes.clear();
}
void pop(const int index) noexcept
{
std::swap(children[index], children.back());
children.pop_back();
std::swap(nodes[index], nodes.back());
nodes.pop_back();
}
void emplace_back(const child_id id)
{
children.emplace_back(id);
nodes.emplace_back(next_node_id);
++next_node_id;
}
};
struct cluster
{
cluster() = default;
small_string<16> name;
std::vector<child_id> children;
std::vector<input_port_id> input_ports;
std::vector<output_port_id> output_ports;
int get(const child_id id) const noexcept
{
for (size_t i = 0, e = children.size(); i != e; ++i)
if (id == children[i])
return static_cast<int>(i);
return not_found;
}
};
struct window_logger
{
ImGuiTextBuffer buffer;
ImGuiTextFilter filter;
ImVector<int> line_offsets;
bool auto_scroll = true;
bool scroll_to_bottom = false;
window_logger() = default;
void clear() noexcept;
void log(const int level, const char* fmt, ...) IM_FMTARGS(3);
void log(const int level, const char* fmt, va_list args) IM_FMTLIST(3);
void show(bool* is_show);
};
struct observation_output
{
enum class type
{
none,
plot,
file,
both
};
observation_output() = default;
observation_output(const char* name_)
: name(name_)
{}
std::ofstream ofs;
const char* name = nullptr;
array<float> data;
double tl = 0.0;
float min = -1.f;
float max = +1.f;
int id = 0;
type observation_type = type::none;
};
struct editor
{
small_string<16> name;
std::filesystem::path path;
imnodes::EditorContext* context = nullptr;
bool initialized = false;
bool show = true;
simulation sim;
double simulation_begin = 0.0;
double simulation_end = 10.0;
double simulation_current = 10.0;
std::thread simulation_thread;
simulation_status st = simulation_status::uninitialized;
bool simulation_show_value = false;
bool stop = false;
vector<observation_output> observation_outputs;
array<observation_output::type> observation_types;
std::filesystem::path observation_directory;
data_array<cluster, cluster_id> clusters;
array<cluster_id> clusters_mapper; /* group per cluster_id */
array<cluster_id> models_mapper; /* group per model_id */
top_cluster top;
status initialize(u32 id) noexcept;
void clear() noexcept;
void reorder() noexcept;
void group(const ImVector<int>& nodes) noexcept;
void ungroup(const int node) noexcept;
void free_group(cluster& group) noexcept;
void free_children(const ImVector<int>& nodes) noexcept;
void copy_group(const child_id* sources,
const size_t size,
child_id* destination) noexcept;
void reorder_subgroup(const size_t from,
const size_t length,
ImVec2 click_pos) noexcept;
cluster_id parent(cluster_id child) const noexcept
{
return clusters_mapper[get_index(child)];
}
cluster_id parent(model_id child) const noexcept
{
return models_mapper[get_index(child)];
}
void parent(const cluster_id child, const cluster_id parent) noexcept
{
clusters_mapper[get_index(child)] = parent;
}
void parent(const model_id child, const cluster_id parent) noexcept
{
models_mapper[get_index(child)] = parent;
}
int get_in(input_port_id id) const noexcept
{
return static_cast<int>(get_index(id));
}
input_port_id get_in(int index) const noexcept
{
auto* port = sim.input_ports.try_to_get(static_cast<u32>(index));
return port ? sim.input_ports.get_id(port) : undefined<input_port_id>();
}
int get_out(output_port_id id) const noexcept
{
constexpr u32 is_output = 1 << 31;
u32 index = get_index(id);
index |= is_output;
return static_cast<int>(index);
}
output_port_id get_out(int index) const noexcept
{
constexpr u32 mask = ~(1 << 31); /* remove the first bit */
index &= mask;
auto* port = sim.output_ports.try_to_get(static_cast<u32>(index));
return port ? sim.output_ports.get_id(port)
: undefined<output_port_id>();
}
status add_lotka_volterra() noexcept;
status add_izhikevitch() noexcept;
void show_connections() noexcept;
void show_model_dynamics(model& mdl) noexcept;
void show_model_cluster(cluster& mdl) noexcept;
void show_top() noexcept;
bool show_editor() noexcept;
};
} // namespace irt
#endif
\ No newline at end of file
......@@ -2,7 +2,7 @@
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include "gui.hpp"
#include "node-editor.hpp"
namespace irt {
......
......@@ -4411,6 +4411,48 @@ struct simulation
});
}
template<typename Function>
void for_all_input_port(const model& mdl, Function f)
{
dispatch(
mdl.type,
[ this, &f, dyn_id = mdl.id ]<typename DynamicsM>(DynamicsM &
dyn_models)
{
using Dynamics = typename DynamicsM::value_type;
if constexpr (is_detected_v<has_input_port_t, Dynamics>) {
if (auto* dyn = dyn_models.try_to_get(dyn_id); dyn)
for (size_t i = 0, e = std::size(dyn->x); i != e; ++i)
if (auto* port = input_ports.try_to_get(dyn->x[i]);
port)
f(*port);
}
return status::success;
});
}
template<typename Function>
void for_all_output_port(const model& mdl, Function f)
{
dispatch(
mdl.type,
[ this, &f, dyn_id = mdl.id ]<typename DynamicsM>(DynamicsM &
dyn_models) {
using Dynamics = typename DynamicsM::value_type;
if constexpr (is_detected_v<has_output_port_t, Dynamics>) {
if (auto* dyn = dyn_models.try_to_get(dyn_id); dyn)
for (size_t i = 0, e = std::size(dyn->y); i != e; ++i)
if (auto* port = output_ports.try_to_get(dyn->y[i]);
port)
f(*port);
}
return status::success;
});
}
status get_input_port_index(const model& mdl,
const input_port_id port,
int* index) const noexcept
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment