Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a Menu Bar to Tesseratos #1235

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Raycasting, collisions between rays and box/capsule colliders (#225, **@diogomsmiranda**).
- Change speed of the debug-camera using Tab and LShift, positive and negative respectively (#1159, **@diogomsmiranda**)
- Console plugin (#875, **@Scarface1809**).
- Menu Bar to Tesseratos (#1234, **@RiscadoA**).

### Changed

Expand Down
3 changes: 3 additions & 0 deletions tools/tesseratos/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@

set(TESSERATOS_SOURCE
"src/tesseratos/main.cpp"
"src/tesseratos/menu_bar/plugin.cpp"
"src/tesseratos/menu_bar/item.cpp"
"src/tesseratos/menu_bar/selected.cpp"
"src/tesseratos/asset_explorer/plugin.cpp"
"src/tesseratos/asset_explorer/popup.cpp"
"src/tesseratos/settings_inspector/plugin.cpp"
Expand Down
18 changes: 18 additions & 0 deletions tools/tesseratos/src/tesseratos/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <cubos/engine/input/plugin.hpp>
#include <cubos/engine/settings/plugin.hpp>
#include <cubos/engine/settings/settings.hpp>
#include <cubos/engine/transform/child_of.hpp>
#include <cubos/engine/utils/free_camera/plugin.hpp>

#include "asset_explorer/plugin.hpp"
Expand All @@ -13,6 +14,7 @@
#include "ecs_statistics/plugin.hpp"
#include "entity_inspector/plugin.hpp"
#include "entity_selector/plugin.hpp"
#include "menu_bar/plugin.hpp"
#include "metrics_panel/plugin.hpp"
#include "play_pause/plugin.hpp"
#include "scene_editor/plugin.hpp"
Expand Down Expand Up @@ -41,6 +43,7 @@ int main(int argc, char** argv)

cubos.plugin(toolboxPlugin);
cubos.plugin(entitySelectorPlugin);
cubos.plugin(menuBarPlugin);

cubos.plugin(assetExplorerPlugin);
cubos.plugin(entityInspectorPlugin);
Expand Down Expand Up @@ -68,5 +71,20 @@ int main(int argc, char** argv)
input.bind(*bindings);
});

cubos.startupSystem("add some menu items just for testing purposes").call([](Commands cmds) {
RiscadoA marked this conversation as resolved.
Show resolved Hide resolved
auto project = cmds.create().add(MenuBarItem{"Project", 0}).entity();
auto view = cmds.create().add(MenuBarItem{"View", 1}).entity();
cmds.create().add(MenuBarItem{"Help", 2});

cmds.create().add(MenuBarItem{"New", 0}).relatedTo(project, ChildOf{});
cmds.create().add(MenuBarItem{"Open", 1}).relatedTo(project, ChildOf{});
cmds.create().add(MenuBarItem{"Save", 2}).relatedTo(project, ChildOf{});

cmds.create().add(MenuBarItem{"Console", 0}).relatedTo(view, ChildOf{});
cmds.create().add(MenuBarItem{"Assets Explorer", 1}).relatedTo(view, ChildOf{});
cmds.create().add(MenuBarItem{"Entity Inspector", 2}).relatedTo(view, ChildOf{});
cmds.create().add(MenuBarItem{"World Inspector", 3}).relatedTo(view, ChildOf{});
});

cubos.run();
}
13 changes: 13 additions & 0 deletions tools/tesseratos/src/tesseratos/menu_bar/item.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#include "item.hpp"

#include <cubos/core/ecs/reflection.hpp>
#include <cubos/core/reflection/external/primitives.hpp>
#include <cubos/core/reflection/external/string.hpp>

CUBOS_REFLECT_IMPL(tesseratos::MenuBarItem)
{
return cubos::core::ecs::TypeBuilder<MenuBarItem>("tesseratos::MenuBarItem")
.withField("name", &MenuBarItem::name)
.withField("order", &MenuBarItem::order)
.build();
}
30 changes: 30 additions & 0 deletions tools/tesseratos/src/tesseratos/menu_bar/item.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/// @file
/// @brief Component @ref tesseratos::MenuBarItem.
/// @ingroup tesseratos-menu-bar-plugin

#pragma once

#include <string>

#include <cubos/core/reflection/reflect.hpp>

namespace tesseratos
{
/// @brief Component representing a menu bar item.
///
/// Adds an item to the menu bar at the top of the screen.
///
/// @ingroup tesseratos-menu-bar-plugin
struct MenuBarItem
{
CUBOS_REFLECT;

/// @brief Item name.
std::string name{"unnamed"};

/// @brief Item order priority, lower values are displayed first.
///
/// Ties are broken by the item's alphabetical order.
int order{0};
};
} // namespace tesseratos
102 changes: 102 additions & 0 deletions tools/tesseratos/src/tesseratos/menu_bar/plugin.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
#include "plugin.hpp"
#include <algorithm>

#include <imgui.h>

#include <cubos/engine/imgui/plugin.hpp>
#include <cubos/engine/transform/plugin.hpp>

using cubos::core::ecs::Traversal;
using namespace cubos::engine;
using namespace tesseratos;

namespace
{
struct Item
{
Entity entity;
MenuBarItem item;
std::vector<Item> items;
};
} // namespace

static void getChildItems(Item& parent, Query<Entity, const MenuBarItem&> childOf)
{
for (auto [entity, item] : childOf.pin(1, parent.entity))
{
Item child{entity, item, {}};
getChildItems(child, childOf);
parent.items.emplace_back(child);
}

std::sort(parent.items.begin(), parent.items.end(), [](const Item& a, const Item& b) {
return a.item.order < b.item.order || (a.item.order == b.item.order && a.item.name < b.item.name);
});
}

static void showItem(Commands& cmds, const Item& item)
{
if (item.items.empty())
{
if (ImGui::MenuItem(item.item.name.c_str()))
{
// Trigger any observers of the selected item.
cmds.add(item.entity, MenuBarSelected{});
cmds.remove<MenuBarSelected>(item.entity);
}
}
else
{
if (ImGui::BeginMenu(item.item.name.c_str()))
{
for (const auto& child : item.items)
{
showItem(cmds, child);
}
ImGui::EndMenu();
}
}
}

void tesseratos::menuBarPlugin(Cubos& cubos)
{
cubos.depends(imguiPlugin);
cubos.depends(transformPlugin);

cubos.component<MenuBarItem>();
cubos.component<MenuBarSelected>();

cubos.system("draw MenuBar")
.tagged(imguiTag)
.with<MenuBarItem>()
.related<ChildOf>()
.call([](Commands cmds, Query<Entity, const MenuBarItem&> childOf, Query<Entity, const MenuBarItem&> items) {
if (!ImGui::BeginMainMenuBar())
{
return;
}

// Extract item tree from the queries, sorted by the order and name item fields.
std::vector<Item> processed{};
for (auto [entity, item] : items)
{
if (childOf.pin(0, entity).empty())
{
Item root{entity, item, {}};
getChildItems(root, childOf);
processed.push_back(root);
}
}
std::sort(processed.begin(), processed.end(), [](const Item& a, const Item& b) {
return a.item.order < b.item.order || (a.item.order == b.item.order && a.item.name < b.item.name);
});

// Show the menu bar.
for (const auto& item : processed)
{
showItem(cmds, item);
}

ImGui::EndMainMenuBar();
});
}
25 changes: 25 additions & 0 deletions tools/tesseratos/src/tesseratos/menu_bar/plugin.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/// @dir
/// @brief @ref tesseratos-menu-bar-plugin plugin directory.

/// @file
/// @brief Plugin entry point.
/// @ingroup tesseratos-menu-bar-plugin

#pragma once

#include <cubos/engine/prelude.hpp>

#include "item.hpp"
#include "selected.hpp"

namespace tesseratos
{
/// @defgroup tesseratos-menu-bar-plugin Menu Bar
/// @ingroup tesseratos
/// @brief Adds the @ref MenuBarItem and @ref MenuBarSelected components.

/// @brief Plugin entry function.
/// @param cubos @b Cubos main class
/// @ingroup tesseratos-game-plugin
void menuBarPlugin(cubos::engine::Cubos& cubos);
} // namespace tesseratos
8 changes: 8 additions & 0 deletions tools/tesseratos/src/tesseratos/menu_bar/selected.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#include "selected.hpp"

#include <cubos/core/ecs/reflection.hpp>

CUBOS_REFLECT_IMPL(tesseratos::MenuBarSelected)
{
return cubos::core::ecs::TypeBuilder<MenuBarSelected>("tesseratos::MenuBarSelected").build();
}
17 changes: 17 additions & 0 deletions tools/tesseratos/src/tesseratos/menu_bar/selected.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/// @file
/// @brief Component @ref tesseratos::MenuBarSelected.
/// @ingroup tesseratos-menu-bar-plugin

#pragma once

#include <cubos/core/reflection/reflect.hpp>

namespace tesseratos
{
/// @brief Component added to menu bar items when they are selected.
/// @ingroup tesseratos-menu-bar-plugin
struct MenuBarSelected
{
CUBOS_REFLECT;
};
} // namespace tesseratos
Loading