add ieee for object inspection
This commit is contained in:
parent
b8132afabb
commit
471fac409e
@ -63,6 +63,10 @@ add_executable(tomato
|
||||
./chat_gui/settings_window.hpp
|
||||
./chat_gui/settings_window.cpp
|
||||
|
||||
./imgui_entt_entity_editor.hpp
|
||||
./object_store_ui.hpp
|
||||
./object_store_ui.cpp
|
||||
|
||||
./tox_ui_utils.hpp
|
||||
./tox_ui_utils.cpp
|
||||
|
||||
|
@ -1,28 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <entt/entity/registry.hpp>
|
||||
#include <entt/entity/handle.hpp>
|
||||
#include <entt/container/dense_set.hpp>
|
||||
|
||||
#include <solanaceae/object_store/object_store.hpp>
|
||||
#include <solanaceae/contact/contact_model3.hpp>
|
||||
#include <solanaceae/message3/registry_message_model.hpp>
|
||||
|
||||
#include <solanaceae/file/file2.hpp>
|
||||
|
||||
enum class Content : uint32_t {};
|
||||
using ContentRegistry = entt::basic_registry<Content>;
|
||||
using ContentHandle = entt::basic_handle<ContentRegistry>;
|
||||
|
||||
struct ContentStore {
|
||||
static constexpr const char* version {"1"};
|
||||
|
||||
ContentRegistry _reg;
|
||||
|
||||
ContentRegistry& registry(void);
|
||||
ContentHandle objectHandle(const Content e);
|
||||
|
||||
};
|
||||
|
||||
namespace Content1::Components {
|
||||
|
||||
// TODO: design it as a tree?
|
||||
@ -33,7 +18,7 @@ namespace Content1::Components {
|
||||
struct TagVideoStream {};
|
||||
|
||||
struct TimingTiedTo {
|
||||
entt::dense_set<ContentHandle> ties;
|
||||
entt::dense_set<ObjectHandle> ties;
|
||||
};
|
||||
|
||||
// the associated messages, if any
|
||||
@ -59,6 +44,6 @@ namespace Content1::Components {
|
||||
|
||||
// TODO: i have no idea
|
||||
struct RawFile2ReadFromContentFactoryI {
|
||||
virtual std::shared_ptr<File2I> open(ContentHandle h) = 0;
|
||||
virtual std::shared_ptr<File2I> open(ObjectHandle h) = 0;
|
||||
};
|
||||
|
||||
|
319
src/imgui_entt_entity_editor.hpp
Normal file
319
src/imgui_entt_entity_editor.hpp
Normal file
@ -0,0 +1,319 @@
|
||||
// for the license, see the end of the file
|
||||
#pragma once
|
||||
|
||||
#include "entt/entity/fwd.hpp"
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
#include <entt/entt.hpp>
|
||||
#include <imgui.h>
|
||||
|
||||
#ifndef MM_IEEE_ASSERT
|
||||
#define MM_IEEE_ASSERT(x) assert(x)
|
||||
#endif
|
||||
|
||||
#define MM_IEEE_IMGUI_PAYLOAD_TYPE_ENTITY "MM_IEEE_ENTITY"
|
||||
|
||||
#ifndef MM_IEEE_ENTITY_WIDGET
|
||||
#define MM_IEEE_ENTITY_WIDGET ::MM::EntityWidget
|
||||
#endif
|
||||
|
||||
namespace MM {
|
||||
|
||||
template <class EntityType>
|
||||
inline void EntityWidget(EntityType& e, entt::basic_registry<EntityType>& reg, bool dropTarget = false)
|
||||
{
|
||||
ImGui::PushID(static_cast<int>(entt::to_integral(e)));
|
||||
|
||||
if (reg.valid(e)) {
|
||||
ImGui::Text("ID: %d", entt::to_integral(e));
|
||||
} else {
|
||||
ImGui::Text("Invalid Entity");
|
||||
}
|
||||
|
||||
if (reg.valid(e)) {
|
||||
if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_SourceAllowNullID)) {
|
||||
ImGui::SetDragDropPayload(MM_IEEE_IMGUI_PAYLOAD_TYPE_ENTITY, &e, sizeof(e));
|
||||
ImGui::Text("ID: %d", entt::to_integral(e));
|
||||
ImGui::EndDragDropSource();
|
||||
}
|
||||
}
|
||||
|
||||
if (dropTarget && ImGui::BeginDragDropTarget()) {
|
||||
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(MM_IEEE_IMGUI_PAYLOAD_TYPE_ENTITY)) {
|
||||
e = *(EntityType*)payload->Data;
|
||||
}
|
||||
|
||||
ImGui::EndDragDropTarget();
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
template <class Component, class EntityType>
|
||||
void ComponentEditorWidget([[maybe_unused]] entt::basic_registry<EntityType>& registry, [[maybe_unused]] EntityType entity) {}
|
||||
|
||||
template <class Component, class EntityType>
|
||||
void ComponentAddAction(entt::basic_registry<EntityType>& registry, EntityType entity)
|
||||
{
|
||||
registry.template emplace<Component>(entity);
|
||||
}
|
||||
|
||||
template <class Component, class EntityType>
|
||||
void ComponentRemoveAction(entt::basic_registry<EntityType>& registry, EntityType entity)
|
||||
{
|
||||
registry.template remove<Component>(entity);
|
||||
}
|
||||
|
||||
template <class EntityType>
|
||||
class EntityEditor {
|
||||
public:
|
||||
using Registry = entt::basic_registry<EntityType>;
|
||||
using ComponentTypeID = entt::id_type;
|
||||
|
||||
struct ComponentInfo {
|
||||
using Callback = std::function<void(Registry&, EntityType)>;
|
||||
std::string name;
|
||||
Callback widget, create, destroy;
|
||||
};
|
||||
|
||||
bool show_window = true;
|
||||
|
||||
private:
|
||||
std::map<ComponentTypeID, ComponentInfo> component_infos;
|
||||
|
||||
bool entityHasComponent(Registry& registry, EntityType& entity, ComponentTypeID type_id)
|
||||
{
|
||||
const auto* storage_ptr = registry.storage(type_id);
|
||||
return storage_ptr != nullptr && storage_ptr->contains(entity);
|
||||
}
|
||||
|
||||
public:
|
||||
template <class Component>
|
||||
ComponentInfo& registerComponent(const ComponentInfo& component_info)
|
||||
{
|
||||
auto index = entt::type_hash<Component>::value();
|
||||
auto insert_info = component_infos.insert_or_assign(index, component_info);
|
||||
MM_IEEE_ASSERT(insert_info.second);
|
||||
return std::get<ComponentInfo>(*insert_info.first);
|
||||
}
|
||||
|
||||
template <class Component>
|
||||
ComponentInfo& registerComponent(const std::string& name, typename ComponentInfo::Callback widget)
|
||||
{
|
||||
return registerComponent<Component>(ComponentInfo{
|
||||
name,
|
||||
widget,
|
||||
ComponentAddAction<Component, EntityType>,
|
||||
ComponentRemoveAction<Component, EntityType>,
|
||||
});
|
||||
}
|
||||
|
||||
template <class Component>
|
||||
ComponentInfo& registerComponent(const std::string& name)
|
||||
{
|
||||
return registerComponent<Component>(name, ComponentEditorWidget<Component, EntityType>);
|
||||
}
|
||||
|
||||
void renderEditor(Registry& registry, EntityType& e)
|
||||
{
|
||||
ImGui::TextUnformatted("Editing:");
|
||||
ImGui::SameLine();
|
||||
|
||||
MM_IEEE_ENTITY_WIDGET(e, registry, true);
|
||||
|
||||
if (ImGui::Button("New")) {
|
||||
e = registry.create();
|
||||
}
|
||||
if (registry.valid(e)) {
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Button("Clone")) {
|
||||
auto old_e = e;
|
||||
e = registry.create();
|
||||
|
||||
// create a copy of an entity component by component
|
||||
for (auto &&curr: registry.storage()) {
|
||||
if (auto &storage = curr.second; storage.contains(old_e)) {
|
||||
// TODO: do something with the return value. returns false on failure.
|
||||
storage.push(e, storage.value(old_e));
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui::SameLine();
|
||||
|
||||
ImGui::Dummy({10, 0}); // space destroy a bit, to not accidentally click it
|
||||
ImGui::SameLine();
|
||||
|
||||
// red button
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.65f, 0.15f, 0.15f, 1.f));
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.8f, 0.3f, 0.3f, 1.f));
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(1.f, 0.2f, 0.2f, 1.f));
|
||||
if (ImGui::Button("Destroy")) {
|
||||
registry.destroy(e);
|
||||
e = entt::null;
|
||||
}
|
||||
ImGui::PopStyleColor(3);
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
if (registry.valid(e)) {
|
||||
ImGui::PushID(static_cast<int>(entt::to_integral(e)));
|
||||
std::map<ComponentTypeID, ComponentInfo> has_not;
|
||||
for (auto& [component_type_id, ci] : component_infos) {
|
||||
if (entityHasComponent(registry, e, component_type_id)) {
|
||||
ImGui::PushID(component_type_id);
|
||||
if (ImGui::Button("-")) {
|
||||
ci.destroy(registry, e);
|
||||
ImGui::PopID();
|
||||
continue; // early out to prevent access to deleted data
|
||||
} else {
|
||||
ImGui::SameLine();
|
||||
}
|
||||
|
||||
if (ImGui::CollapsingHeader(ci.name.c_str())) {
|
||||
ImGui::Indent(30.f);
|
||||
ImGui::PushID("Widget");
|
||||
ci.widget(registry, e);
|
||||
ImGui::PopID();
|
||||
ImGui::Unindent(30.f);
|
||||
}
|
||||
ImGui::PopID();
|
||||
} else {
|
||||
has_not[component_type_id] = ci;
|
||||
}
|
||||
}
|
||||
|
||||
if (!has_not.empty()) {
|
||||
if (ImGui::Button("+ Add Component")) {
|
||||
ImGui::OpenPopup("Add Component");
|
||||
}
|
||||
|
||||
if (ImGui::BeginPopup("Add Component")) {
|
||||
ImGui::TextUnformatted("Available:");
|
||||
ImGui::Separator();
|
||||
|
||||
for (auto& [component_type_id, ci] : has_not) {
|
||||
ImGui::PushID(component_type_id);
|
||||
if (ImGui::Selectable(ci.name.c_str())) {
|
||||
ci.create(registry, e);
|
||||
}
|
||||
ImGui::PopID();
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
ImGui::PopID();
|
||||
}
|
||||
}
|
||||
|
||||
void renderEntityList(Registry& registry, std::set<ComponentTypeID>& comp_list)
|
||||
{
|
||||
ImGui::Text("Components Filter:");
|
||||
ImGui::SameLine();
|
||||
if (ImGui::SmallButton("clear")) {
|
||||
comp_list.clear();
|
||||
}
|
||||
|
||||
ImGui::Indent();
|
||||
|
||||
for (const auto& [component_type_id, ci] : component_infos) {
|
||||
bool is_in_list = comp_list.count(component_type_id);
|
||||
bool active = is_in_list;
|
||||
|
||||
ImGui::Checkbox(ci.name.c_str(), &active);
|
||||
|
||||
if (is_in_list && !active) { // remove
|
||||
comp_list.erase(component_type_id);
|
||||
} else if (!is_in_list && active) { // add
|
||||
comp_list.emplace(component_type_id);
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::Unindent();
|
||||
ImGui::Separator();
|
||||
|
||||
if (comp_list.empty()) {
|
||||
ImGui::Text("Orphans:");
|
||||
for (EntityType e : registry.template storage<EntityType>()) {
|
||||
if (registry.orphan(e)) {
|
||||
MM_IEEE_ENTITY_WIDGET(e, registry, false);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
entt::basic_runtime_view<entt::basic_sparse_set<EntityType>> view{};
|
||||
for (const auto type : comp_list) {
|
||||
auto* storage_ptr = registry.storage(type);
|
||||
if (storage_ptr != nullptr) {
|
||||
view.iterate(*storage_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: add support for exclude
|
||||
|
||||
ImGui::Text("%lu Entities Matching:", view.size_hint());
|
||||
|
||||
if (ImGui::BeginChild("entity list")) {
|
||||
for (auto e : view) {
|
||||
MM_IEEE_ENTITY_WIDGET(e, registry, false);
|
||||
}
|
||||
}
|
||||
ImGui::EndChild();
|
||||
}
|
||||
}
|
||||
|
||||
// displays both, editor and list
|
||||
// uses static internally, use only as a quick way to get going!
|
||||
void renderSimpleCombo(Registry& registry, EntityType& e)
|
||||
{
|
||||
if (show_window) {
|
||||
ImGui::SetNextWindowSize(ImVec2(550, 400), ImGuiCond_FirstUseEver);
|
||||
if (ImGui::Begin("Entity Editor", &show_window)) {
|
||||
if (ImGui::BeginChild("list", {200, 0}, true)) {
|
||||
static std::set<ComponentTypeID> comp_list;
|
||||
renderEntityList(registry, comp_list);
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::BeginChild("editor")) {
|
||||
renderEditor(registry, e);
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // MM
|
||||
|
||||
// MIT License
|
||||
|
||||
// Copyright (c) 2019-2022 Erik Scholz
|
||||
// Copyright (c) 2020 Gnik Droy
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
@ -68,7 +68,7 @@ int main(int argc, char** argv) {
|
||||
} else { // HACK
|
||||
SDLVideoCameraContent vcc;
|
||||
auto* reader = vcc.aquireReader();
|
||||
for (size_t i = 0; i < 200; i++) {
|
||||
for (size_t i = 0; i < 20; i++) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
auto new_frame_opt = reader->getNext();
|
||||
if (new_frame_opt.has_value()) {
|
||||
|
@ -34,6 +34,7 @@ MainScreen::MainScreen(SDL_Renderer* renderer_, Theme& theme_, std::string save_
|
||||
msg_tc(mil, sdlrtu),
|
||||
cg(conf, rmm, cr, sdlrtu, contact_tc, msg_tc, theme),
|
||||
sw(conf),
|
||||
osui(os),
|
||||
tuiu(tc, conf),
|
||||
tdch(tpi)
|
||||
{
|
||||
@ -65,8 +66,6 @@ MainScreen::MainScreen(SDL_Renderer* renderer_, Theme& theme_, std::string save_
|
||||
g_provideInstance<RegistryMessageModel>("RegistryMessageModel", "host", &rmm);
|
||||
g_provideInstance<MessageSerializerNJ>("MessageSerializerNJ", "host", &msnj);
|
||||
|
||||
g_provideInstance<ContentStore>("ContentStore", "host", &cs);
|
||||
|
||||
g_provideInstance<ToxI>("ToxI", "host", &tc);
|
||||
g_provideInstance<ToxPrivateI>("ToxPrivateI", "host", &tpi);
|
||||
g_provideInstance<ToxEventProviderI>("ToxEventProviderI", "host", &tc);
|
||||
@ -246,6 +245,7 @@ Screen* MainScreen::render(float time_delta, bool&) {
|
||||
|
||||
const float cg_interval = cg.render(time_delta); // render
|
||||
sw.render(); // render
|
||||
osui.render();
|
||||
tuiu.render(); // render
|
||||
tdch.render(); // render
|
||||
|
||||
|
@ -12,8 +12,6 @@
|
||||
#include <solanaceae/toxcore/tox_event_logger.hpp>
|
||||
#include "./tox_private_impl.hpp"
|
||||
|
||||
#include "./content/content.hpp"
|
||||
|
||||
#include <solanaceae/tox_contacts/tox_contact_model2.hpp>
|
||||
#include <solanaceae/tox_messages/tox_message_manager.hpp>
|
||||
#include <solanaceae/tox_messages/tox_transfer_manager.hpp>
|
||||
@ -31,6 +29,7 @@
|
||||
|
||||
#include "./chat_gui4.hpp"
|
||||
#include "./chat_gui/settings_window.hpp"
|
||||
#include "./object_store_ui.hpp"
|
||||
#include "./tox_ui_utils.hpp"
|
||||
#include "./tox_dht_cap_histo.hpp"
|
||||
#include "./tox_friend_faux_offline_messaging.hpp"
|
||||
@ -55,8 +54,6 @@ struct MainScreen final : public Screen {
|
||||
MessageSerializerNJ msnj;
|
||||
MessageTimeSort mts;
|
||||
|
||||
ContentStore cs;
|
||||
|
||||
ToxEventLogger tel{std::cout};
|
||||
ToxClient tc;
|
||||
ToxPrivateImpl tpi;
|
||||
@ -81,6 +78,7 @@ struct MainScreen final : public Screen {
|
||||
|
||||
ChatGui4 cg;
|
||||
SettingsWindow sw;
|
||||
ObjectStoreUI osui;
|
||||
ToxUIUtils tuiu;
|
||||
ToxDHTCapHisto tdch;
|
||||
|
||||
|
38
src/object_store_ui.cpp
Normal file
38
src/object_store_ui.cpp
Normal file
@ -0,0 +1,38 @@
|
||||
#include "./object_store_ui.hpp"
|
||||
|
||||
#include <solanaceae/object_store/meta_components.hpp>
|
||||
|
||||
#include <imgui/imgui.h>
|
||||
|
||||
ObjectStoreUI::ObjectStoreUI(
|
||||
ObjectStore2& os
|
||||
) : _os(os) {
|
||||
_ee.show_window = false;
|
||||
|
||||
_ee.registerComponent<ObjectStore::Components::ID>("ID");
|
||||
_ee.registerComponent<ObjectStore::Components::DataCompressionType>("DataCompressionType");
|
||||
}
|
||||
|
||||
void ObjectStoreUI::render(void) {
|
||||
{ // main window menubar injection
|
||||
// assumes the window "tomato" was rendered already by cg
|
||||
if (ImGui::Begin("tomato")) {
|
||||
if (ImGui::BeginMenuBar()) {
|
||||
ImGui::Separator();
|
||||
if (ImGui::BeginMenu("ObjectStore")) {
|
||||
if (ImGui::MenuItem("Inspector")) {
|
||||
//_show_add_friend_window = true;
|
||||
_ee.show_window = true;
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
ImGui::EndMenuBar();
|
||||
}
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
static Object selected_ent {entt::null};
|
||||
_ee.renderSimpleCombo(_os.registry(), selected_ent);
|
||||
}
|
||||
|
19
src/object_store_ui.hpp
Normal file
19
src/object_store_ui.hpp
Normal file
@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <solanaceae/object_store/object_store.hpp>
|
||||
|
||||
#include "./imgui_entt_entity_editor.hpp"
|
||||
|
||||
class ObjectStoreUI {
|
||||
ObjectStore2& _os;
|
||||
|
||||
MM::EntityEditor<Object> _ee;
|
||||
|
||||
public:
|
||||
ObjectStoreUI(
|
||||
ObjectStore2& os
|
||||
);
|
||||
|
||||
void render(void);
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user