add ieee for object inspection

This commit is contained in:
Green Sky 2024-04-30 19:44:06 +02:00
parent 2b6f4f1267
commit c533b2626d
No known key found for this signature in database
8 changed files with 388 additions and 25 deletions

View File

@ -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

View File

@ -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;
};

View 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.

View File

@ -66,7 +66,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()) {

View File

@ -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);
@ -205,6 +204,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

View File

@ -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
View 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
View 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);
};