Commit 7f03786d authored by Gauthier Quesnel's avatar Gauthier Quesnel
Browse files

gui: use tab to merge editor and source windows

parent 0af000cf
Pipeline #34738 passed with stage
in 1 minute and 25 seconds
......@@ -105,7 +105,7 @@ application::show()
editor* ed = nullptr;
while (editors.next(ed)) {
if (ed->show) {
if (!ed->show_editor()) {
if (!ed->show_window()) {
editor* next = ed;
editors.next(next);
free_editor(*ed);
......
......@@ -265,9 +265,6 @@ struct editor
file_discrete_outs;
std::vector<observation_output> observation_outputs;
void show_sources_window(bool* is_show);
void show_menu_sources(const char* title, source& src);
template<typename Function, typename... Args>
constexpr void observation_dispatch(const u32 index,
Function&& f,
......@@ -328,7 +325,6 @@ struct editor
bool show_save_file_dialog = false;
bool show_select_directory_dialog = false;
bool show_settings = false;
bool show_sources = false;
struct settings_manager
{
......@@ -432,8 +428,11 @@ struct editor
void show_model_dynamics(model& mdl) noexcept;
void show_model_cluster(cluster& mdl) noexcept;
void show_top() noexcept;
void show_sources() noexcept;
void show_editor() noexcept;
void show_menu_sources(const char* title, source& src);
bool show_editor() noexcept;
bool show_window() noexcept;
};
struct window_logger
......
......@@ -2583,273 +2583,9 @@ add_popup_menuitem(editor& ed, dynamics_type type, model_id* new_model)
return status::success;
}
bool
void
editor::show_editor() noexcept
{
ImNodes::EditorContextSet(context);
ImGuiWindowFlags windows_flags = 0;
windows_flags |= ImGuiWindowFlags_MenuBar;
ImGui::SetNextWindowPos(ImVec2(500, 50), ImGuiCond_FirstUseEver);
ImGui::SetNextWindowSize(ImVec2(800, 700), ImGuiCond_Once);
if (!ImGui::Begin(name.c_str(), &show, windows_flags)) {
ImGui::End();
return true;
}
if (ImGui::BeginMenuBar()) {
if (ImGui::BeginMenu("File")) {
if (ImGui::MenuItem("Open"))
show_load_file_dialog = true;
if (!path.empty() && ImGui::MenuItem("Save")) {
log_w.log(3,
"Write into file %s\n",
(const char*)path.u8string().c_str());
if (auto os = std::ofstream(path); os.is_open()) {
writer w(os);
auto ret = w(sim, srcs);
if (is_success(ret))
log_w.log(5, "success\n");
else
log_w.log(4, "error writing\n");
}
}
if (ImGui::MenuItem("Save as..."))
show_save_file_dialog = true;
if (ImGui::MenuItem("Close")) {
ImGui::EndMenu();
ImGui::EndMenuBar();
ImGui::End();
return false;
}
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Edition")) {
ImGui::MenuItem("Show minimap", nullptr, &show_minimap);
ImGui::MenuItem("Show parameter in models",
nullptr,
&settings.show_dynamics_inputs_in_editor);
ImGui::Separator();
if (ImGui::MenuItem("Clear"))
clear();
ImGui::Separator();
if (ImGui::MenuItem("Grid Reorder"))
compute_grid_layout();
if (ImGui::MenuItem("Automatic Layout"))
compute_automatic_layout();
ImGui::Separator();
if (ImGui::MenuItem("External sources"))
show_sources = true;
if (ImGui::MenuItem("Settings"))
show_settings = true;
ImGui::EndMenu();
}
auto empty_fun = [this](irt::model_id id) {
this->top.emplace_back(id);
parent(id, undefined<cluster_id>());
};
if (ImGui::BeginMenu("Examples")) {
if (ImGui::MenuItem("Insert example AQSS lotka_volterra"))
if (auto ret = add_lotka_volterra(); is_bad(ret))
log_w.log(3,
"Fail to initialize a Lotka Volterra "
"model (%s)\n",
status_string(ret));
if (ImGui::MenuItem("Insert Izhikevitch model"))
if (auto ret = add_izhikevitch(); is_bad(ret))
log_w.log(3,
"Fail to initialize an Izhikevitch "
"model (%s)\n",
status_string(ret));
if (ImGui::MenuItem("Insert example QSS1 lotka_volterra"))
if (auto ret = example_qss_lotka_volterra<1>(sim, empty_fun);
is_bad(ret))
log_w.log(3,
"Fail to initialize "
"example_qss_lotka_volterra<1>: %s\n",
status_string(ret));
if (ImGui::MenuItem("Insert example QSS1 negative_lif"))
if (auto ret = example_qss_negative_lif<1>(sim, empty_fun);
is_bad(ret))
log_w.log(3,
"Fail to initialize "
"example_qss_negative_lif<1>: %s\n",
status_string(ret));
if (ImGui::MenuItem("Insert example QSS1 lif"))
if (auto ret = example_qss_lif<1>(sim, empty_fun); is_bad(ret))
log_w.log(3,
"Fail to initialize example_qss_lif<1>: %s\n",
status_string(ret));
if (ImGui::MenuItem("Insert example QSS1 van_der_pol"))
if (auto ret = example_qss_van_der_pol<1>(sim, empty_fun);
is_bad(ret))
log_w.log(
3,
"Fail to initialize example_qss_van_der_pol<1>: %s\n",
status_string(ret));
if (ImGui::MenuItem("Insert example QSS1 izhikevich"))
if (auto ret = example_qss_izhikevich<1>(sim, empty_fun);
is_bad(ret))
log_w.log(
3,
"Fail to initialize example_qss_izhikevich<1>: %s\n",
status_string(ret));
if (ImGui::MenuItem("Insert example QSS2 lotka_volterra"))
if (auto ret = example_qss_lotka_volterra<2>(sim, empty_fun);
is_bad(ret))
log_w.log(3,
"Fail to initialize "
"example_qss_lotka_volterra<2>: %s\n",
status_string(ret));
if (ImGui::MenuItem("Insert example QSS2 negative_lif"))
if (auto ret = example_qss_negative_lif<2>(sim, empty_fun);
is_bad(ret))
log_w.log(3,
"Fail to initialize "
"example_qss_negative_lif<2>: %s\n",
status_string(ret));
if (ImGui::MenuItem("Insert example QSS2 lif"))
if (auto ret = example_qss_lif<2>(sim, empty_fun); is_bad(ret))
log_w.log(3,
"Fail to initialize example_qss_lif<2>: %s\n",
status_string(ret));
if (ImGui::MenuItem("Insert example QSS2 van_der_pol"))
if (auto ret = example_qss_van_der_pol<2>(sim, empty_fun);
is_bad(ret))
log_w.log(
3,
"Fail to initialize example_qss_van_der_pol<2>: %s\n",
status_string(ret));
if (ImGui::MenuItem("Insert example QSS2 izhikevich"))
if (auto ret = example_qss_izhikevich<2>(sim, empty_fun);
is_bad(ret))
log_w.log(
3,
"Fail to initialize example_qss_izhikevich<2>: %s\n",
status_string(ret));
if (ImGui::MenuItem("Insert example QSS3 lotka_volterra"))
if (auto ret = example_qss_lotka_volterra<3>(sim, empty_fun);
is_bad(ret))
log_w.log(3,
"Fail to initialize "
"example_qss_lotka_volterra<3>: %s\n",
status_string(ret));
if (ImGui::MenuItem("Insert example QSS3 negative_lif"))
if (auto ret = example_qss_negative_lif<3>(sim, empty_fun);
is_bad(ret))
log_w.log(3,
"Fail to initialize "
"example_qss_negative_lif<3>: %s\n",
status_string(ret));
if (ImGui::MenuItem("Insert example QSS3 lif"))
if (auto ret = example_qss_lif<3>(sim, empty_fun); is_bad(ret))
log_w.log(3,
"Fail to initialize example_qss_lif<3>: %s\n",
status_string(ret));
if (ImGui::MenuItem("Insert example QSS3 van_der_pol"))
if (auto ret = example_qss_van_der_pol<3>(sim, empty_fun);
is_bad(ret))
log_w.log(
3,
"Fail to initialize example_qss_van_der_pol<3>: %s\n",
status_string(ret));
if (ImGui::MenuItem("Insert example QSS3 izhikevich"))
if (auto ret = example_qss_izhikevich<3>(sim, empty_fun);
is_bad(ret))
log_w.log(
3,
"Fail to initialize example_qss_izhikevich<3>: %s\n",
status_string(ret));
ImGui::EndMenu();
}
ImGui::EndMenuBar();
}
if (show_select_directory_dialog) {
ImGui::OpenPopup("Select directory");
if (select_directory_dialog(observation_directory)) {
show_select_directory_dialog = false;
log_w.log(
5, "Output directory: %s", (const char*)path.u8string().c_str());
}
}
if (show_load_file_dialog) {
const char* title = "Select file path to load";
const char8_t* filters[] = { u8".irt", nullptr };
ImGui::OpenPopup(title);
if (load_file_dialog(path, title, filters)) {
show_load_file_dialog = false;
log_w.log(
5, "Load file from %s: ", (const char*)path.u8string().c_str());
if (auto is = std::ifstream(path); is.is_open()) {
reader r(is);
auto ret = r(sim, srcs, [&r, this](model_id id) {
parent(id, undefined<cluster_id>());
const auto index = get_index(id);
const auto new_id = top.emplace_back(id);
const auto pos = r.get_position(index);
ImNodes::SetNodeEditorSpacePos(new_id, ImVec2(pos.x, pos.y));
});
if (is_success(ret))
log_w.log(5, "success\n");
else
log_w.log(4, "fail\n");
}
}
}
if (show_save_file_dialog) {
if (sim.models.size()) {
const char* title = "Select file path to save";
const char8_t* filters[] = { u8".irt", nullptr };
ImGui::OpenPopup(title);
if (save_file_dialog(path, title, filters)) {
show_save_file_dialog = false;
log_w.log(
5, "Save file to %s\n", (const char*)path.u8string().c_str());
log_w.log(3,
"Write into file %s\n",
(const char*)path.u8string().c_str());
if (auto os = std::ofstream(path); os.is_open()) {
writer w(os);
auto ret = w(sim, srcs, [](model_id mdl_id, float& x, float& y) {
const auto index = irt::get_index(mdl_id);
const auto pos = ImNodes::GetNodeEditorSpacePos(static_cast<int>(index));
x = pos.x;
y = pos.y;
});
if (is_success(ret))
log_w.log(5, "success\n");
else
log_w.log(4, "error writing\n");
}
}
}
}
ImGui::Text("X -- delete selected nodes and/or connections / "
"D -- duplicate selected nodes / "
......@@ -2862,6 +2598,8 @@ editor::show_editor() noexcept
ImGuiTableFlags_BordersV;
if (ImGui::BeginTable("Editor", 2, flags)) {
ImNodes::EditorContextSet(context);
ImGui::TableNextRow();
ImGui::TableSetColumnIndex(0);
......@@ -2874,13 +2612,14 @@ editor::show_editor() noexcept
ImGui::IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows) &&
ImNodes::IsEditorHovered() && ImGui::IsMouseClicked(1);
model_id new_model = undefined<model_id>();
const auto click_pos = ImGui::GetMousePosOnOpeningCurrentPopup();
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(8.f, 8.f));
if (!ImGui::IsAnyItemHovered() && open_popup)
ImGui::OpenPopup("Context menu");
if (ImGui::BeginPopup("Context menu")) {
model_id new_model = undefined<model_id>();
const auto click_pos = ImGui::GetMousePosOnOpeningCurrentPopup();
if (ImGui::BeginMenu("QSS1")) {
auto i = static_cast<int>(dynamics_type::qss1_integrator);
......@@ -2938,13 +2677,8 @@ editor::show_editor() noexcept
add_popup_menuitem(*this, dynamics_type::flow, &new_model);
ImGui::EndPopup();
if (new_model != undefined<model_id>()) {
parent(new_model, undefined<cluster_id>());
ImNodes::SetNodeScreenSpacePos(top.emplace_back(new_model),
click_pos);
}
}
ImGui::PopStyleVar();
if (show_minimap)
......@@ -2952,6 +2686,12 @@ editor::show_editor() noexcept
ImNodes::EndNodeEditor();
if (new_model != undefined<model_id>()) {
parent(new_model, undefined<cluster_id>());
ImNodes::SetNodeScreenSpacePos(top.emplace_back(new_model),
click_pos);
}
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(8.f, 8.f));
int node_id;
......@@ -3078,151 +2818,429 @@ editor::show_editor() noexcept
selected_links.resize(0);
}
ImGui::TableSetColumnIndex(1);
ImGui::TableSetColumnIndex(1);
if (ImGui::CollapsingHeader("Selected Models",
ImGuiTreeNodeFlags_CollapsingHeader |
ImGuiTreeNodeFlags_DefaultOpen) &&
num_selected_nodes) {
selected_nodes.resize(num_selected_nodes, -1);
ImNodes::GetSelectedNodes(selected_nodes.begin());
static std::vector<std::string> names;
names.clear();
names.resize(selected_nodes.size());
for (int i = 0, e = selected_nodes.size(); i != e; ++i)
names[i] = fmt::format("{}", selected_nodes[i]);
for (int i = 0, e = selected_nodes.size(); i != e; ++i) {
const auto index = top.get_index(selected_nodes[i]);
if (index == not_found)
continue;
const auto& child = top.children[index];
if (child.first.index())
continue;
const auto id = std::get<model_id>(child.first);
model* mdl = sim.models.try_to_get(id);
if (!mdl)
continue;
if (ImGui::TreeNodeEx(names[i].c_str(),
ImGuiTreeNodeFlags_DefaultOpen)) {
const auto index = get_index(id);
auto out = observation_outputs[index];
auto old_choose = static_cast<int>(out.index());
auto choose = old_choose;
ImGui::Text(
"%s", dynamics_type_names[static_cast<int>(mdl->type)]);
const char* items[] = {
"none", "plot", "file", "file dt "
};
ImGui::Combo("type", &choose, items, IM_ARRAYSIZE(items));
if (choose == 1) {
if (old_choose == 2 || old_choose == 3) {
sim.observers.free(mdl->obs_id);
observation_outputs_free(index);
}
plot_output* plot;
if (old_choose != 1) {
plot_output& tf = plot_outs.alloc(names[i].c_str());
plot = &tf;
tf.ed = this;
observation_outputs[index] = plot_outs.get_id(tf);
auto& o = sim.observers.alloc(names[i].c_str(), tf);
sim.observe(*mdl, o);
} else {
plot = plot_outs.try_to_get(
std::get<plot_output_id>(out));
irt_assert(plot);
}
ImGui::InputText("name##plot",
plot->name.begin(),
plot->name.capacity());
ImGui::InputDouble(
"dt##plot", &plot->time_step, 0.001, 1.0, "%.8f");
} else if (choose == 2) {
if (old_choose == 1 || old_choose == 3) {
sim.observers.free(mdl->obs_id);
observation_outputs_free(index);
}
file_output* file;
if (old_choose != 2) {
file_output& tf = file_outs.alloc(names[i].c_str());
file = &tf;
tf.ed = this;
observation_outputs[index] = file_outs.get_id(tf);
auto& o = sim.observers.alloc(names[i].c_str(), tf);
sim.observe(*mdl, o);
} else {
file = file_outs.try_to_get(
std::get<file_output_id>(out));
irt_assert(file);
}
ImGui::InputText("name##file",
file->name.begin(),
file->name.capacity());
} else if (choose == 3) {
if (old_choose == 1 || old_choose == 2) {
sim.observers.free(mdl->obs_id);
observation_outputs_free(index);
}
file_discrete_output* file;
if (old_choose != 3) {
file_discrete_output& tf =
file_discrete_outs.alloc(names[i].c_str());
file = &tf;
tf.ed = this;
observation_outputs[index] =
file_discrete_outs.get_id(tf);
auto& o = sim.observers.alloc(names[i].c_str(), tf);
sim.observe(*mdl, o);
} else {
file = file_discrete_outs.try_to_get(
std::get<file_discrete_output_id>(out));
irt_assert(file);
}
ImGui::InputText("name##filedt",
file->name.begin(),
file->name.capacity());
ImGui::InputDouble(
"dt##filedt", &file->time_step, 0.001, 1.0, "%.8f");
} else if (old_choose != choose) {
sim.observers.free(mdl->obs_id);
observation_outputs_free(index);
}
sim.dispatch(*mdl,
[this]<typename Dynamics>(Dynamics& dyn) {
ImGui::Spacing();
show_dynamics_inputs(*this, dyn);
});
ImGui::TreePop();
}
}
}
ImGui::EndTable();
}
}
bool
editor::show_window() noexcept
{
ImGuiWindowFlags windows_flags = 0;
windows_flags |= ImGuiWindowFlags_MenuBar;
ImGui::SetNextWindowPos(ImVec2(500, 50), ImGuiCond_FirstUseEver);
ImGui::SetNextWindowSize(ImVec2(800, 700), ImGuiCond_Once);
if (!ImGui::Begin(name.c_str(), &show, windows_flags)) {
ImGui::End();
return true;
}
if (ImGui::BeginMenuBar()) {
if (ImGui::BeginMenu("File")) {
if (ImGui::MenuItem("Open"))
show_load_file_dialog = true;
if (!path.empty() && ImGui::MenuItem("Save")) {
log_w.log(3,
"Write into file %s\n",
(const char*)path.u8string().c_str());
if (auto os = std::ofstream(path); os.is_open()) {
writer w(os);
auto ret = w(sim, srcs);
if (is_success(ret))
log_w.log(5, "success\n");
else
log_w.log(4, "error writing\n");
}
}
if (ImGui::MenuItem("Save as..."))
show_save_file_dialog = true;
if (ImGui::MenuItem("Close")) {
ImGui::EndMenu();
ImGui::EndMenuBar();
ImGui::End();
return false;
}
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Edition")) {
ImGui::MenuItem("Show minimap", nullptr, &show_minimap);
ImGui::MenuItem("Show parameter in models",
nullptr,
&settings.show_dynamics_inputs_in_editor);
ImGui::Separator();
if (ImGui::MenuItem("Clear"))
clear();
ImGui::Separator();
if (ImGui::MenuItem("Grid Reorder"))
compute_grid_layout();
if (ImGui::MenuItem("Automatic Layout"))
compute_automatic_layout();
ImGui::Separator();
if (ImGui::MenuItem("Settings"))
show_settings = true;
ImGui::EndMenu();
}
auto empty_fun = [this](irt::model_id id) {
this->top.emplace_back(id);
parent(id, undefined<cluster_id>());
};
if (ImGui::BeginMenu("Examples")) {
if (ImGui::MenuItem("Insert example AQSS lotka_volterra"))
if (auto ret = add_lotka_volterra(); is_bad(ret))
log_w.log(3,
"Fail to initialize a Lotka Volterra "
"model (%s)\n",
status_string(ret));
if (ImGui::MenuItem("Insert Izhikevitch model"))
if (auto ret = add_izhikevitch(); is_bad(ret))
log_w.log(3,
"Fail to initialize an Izhikevitch "
"model (%s)\n",
status_string(ret));
if (ImGui::MenuItem("Insert example QSS1 lotka_volterra"))