Brought the UIStack over from the previous game to use here.
This commit is contained in:
parent
25e3935170
commit
6aa1a877c9
7 changed files with 241 additions and 0 deletions
123
demos/multiscreen.cpp
Normal file
123
demos/multiscreen.cpp
Normal file
|
|
@ -0,0 +1,123 @@
|
||||||
|
#include "guecs/sfml/backend.hpp"
|
||||||
|
#include "guecs/sfml/components.hpp"
|
||||||
|
#include "guecs/uistack.hpp"
|
||||||
|
#include "guecs/ui.hpp"
|
||||||
|
#include <iostream>
|
||||||
|
#include <chrono>
|
||||||
|
#include <thread>
|
||||||
|
#include <flat_map>
|
||||||
|
#include <fmt/core.h>
|
||||||
|
|
||||||
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
|
struct TestScreen {
|
||||||
|
guecs::UI $gui{};
|
||||||
|
|
||||||
|
TestScreen(const std::string &layout) {
|
||||||
|
init(layout);
|
||||||
|
}
|
||||||
|
|
||||||
|
void init(const std::string& layout) {
|
||||||
|
$gui.position(0, 0, 1280, 720);
|
||||||
|
$gui.layout(layout);
|
||||||
|
|
||||||
|
for(auto& [name, cell] : $gui.cells()) {
|
||||||
|
auto gui_id = $gui.entity(name);
|
||||||
|
$gui.set<guecs::Rectangle>(gui_id, {});
|
||||||
|
$gui.set<guecs::Effect>(gui_id, {});
|
||||||
|
$gui.set<guecs::Text>(gui_id, {guecs::to_wstring(name)});
|
||||||
|
$gui.set<guecs::Clickable>(gui_id, {
|
||||||
|
[&, gui_id, name](auto) { fmt::println("click! {}={}", name, gui_id); }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$gui.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
void render(sf::RenderTarget& target) {
|
||||||
|
$gui.render(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mouse(float x, float y, guecs::Modifiers mods) {
|
||||||
|
return $gui.mouse(x, y, mods);
|
||||||
|
}
|
||||||
|
|
||||||
|
void update() {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
try {
|
||||||
|
sfml::Backend backend;
|
||||||
|
guecs::init(&backend);
|
||||||
|
|
||||||
|
sf::RenderWindow window(sf::VideoMode({1280, 720}), "Multi-Screen Tester");
|
||||||
|
window.setVerticalSyncEnabled(true);
|
||||||
|
window.setFramerateLimit(60);
|
||||||
|
window.setPosition({0,0});
|
||||||
|
|
||||||
|
gui::UIStack<TestScreen> stack;
|
||||||
|
auto test2 = std::make_shared<TestScreen>("[test2|sonice]");
|
||||||
|
auto test3 = std::make_shared<TestScreen>("[test3|pointer]");
|
||||||
|
|
||||||
|
{
|
||||||
|
stack.add("test1", std::make_shared<TestScreen>("[test1|hello]"));
|
||||||
|
stack.add("test2", test2);
|
||||||
|
stack.add("test3", test3);
|
||||||
|
}
|
||||||
|
|
||||||
|
stack.set_active("test1");
|
||||||
|
|
||||||
|
while(window.isOpen()) {
|
||||||
|
while (const auto event = window.pollEvent()) {
|
||||||
|
if(event->is<sf::Event::Closed>()) {
|
||||||
|
window.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(const auto* mouse = event->getIf<sf::Event::MouseButtonPressed>()) {
|
||||||
|
if(mouse->button == sf::Mouse::Button::Left) {
|
||||||
|
sf::Vector2f pos = window.mapPixelToCoords(mouse->position);
|
||||||
|
stack.mouse(pos.x, pos.y, false);
|
||||||
|
}
|
||||||
|
} else if(const auto* key = event->getIf<sf::Event::KeyPressed>()) {
|
||||||
|
using KEY = sf::Keyboard::Scan;
|
||||||
|
|
||||||
|
switch(key->scancode) {
|
||||||
|
case KEY::Q:
|
||||||
|
return 0;
|
||||||
|
case KEY::N: {
|
||||||
|
bool good = stack.next();
|
||||||
|
fmt::println("showing {} is {}", stack.active_name(), good);
|
||||||
|
} break;
|
||||||
|
case KEY::P: {
|
||||||
|
bool good = stack.prev();
|
||||||
|
fmt::println("showing {} is {}", stack.active_name(), good);
|
||||||
|
} break;
|
||||||
|
case KEY::F:
|
||||||
|
stack.first();
|
||||||
|
break;
|
||||||
|
case KEY::L:
|
||||||
|
stack.last();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stack.update();
|
||||||
|
stack.render(window);
|
||||||
|
window.display();
|
||||||
|
|
||||||
|
std::this_thread::sleep_for(100ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch(const std::system_error& e) {
|
||||||
|
std::cout << "WARNING: On OSX you'll get this error on shutdown.\n";
|
||||||
|
std::cout << "Caught system_error with code "
|
||||||
|
"[" << e.code() << "] meaning "
|
||||||
|
"[" << e.what() << "]\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -52,6 +52,7 @@ namespace guecs {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Rectangle {
|
struct Rectangle {
|
||||||
|
// BUG: confirm that padding is being used correctly here
|
||||||
int padding = THEME.PADDING;
|
int padding = THEME.PADDING;
|
||||||
sf::Color color = THEME.FILL_COLOR;
|
sf::Color color = THEME.FILL_COLOR;
|
||||||
sf::Color border_color = THEME.BORDER_COLOR;
|
sf::Color border_color = THEME.BORDER_COLOR;
|
||||||
|
|
@ -62,6 +63,9 @@ namespace guecs {
|
||||||
void render(sf::RenderTarget& window, sf::Shader *shader_ptr);
|
void render(sf::RenderTarget& window, sf::Shader *shader_ptr);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// BUG: meter needs a backing rectangle of one color for the full bar, then
|
||||||
|
// another rectangle for the current setting.
|
||||||
|
// BUG: the meter will be past the end, probably a floating point error
|
||||||
struct Meter {
|
struct Meter {
|
||||||
float percent = 1.0f;
|
float percent = 1.0f;
|
||||||
sf::Color color = THEME.BG_COLOR_DARK;
|
sf::Color color = THEME.BG_COLOR_DARK;
|
||||||
|
|
@ -95,6 +99,7 @@ namespace guecs {
|
||||||
void stop(bool hover);
|
void stop(bool hover);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// BUG: it should be _way_ easier to set the background and change it
|
||||||
struct Background {
|
struct Background {
|
||||||
float x = 0.0f;
|
float x = 0.0f;
|
||||||
float y = 0.0f;
|
float y = 0.0f;
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,9 @@ namespace guecs {
|
||||||
shared_ptr<sf::Font> $font = nullptr;
|
shared_ptr<sf::Font> $font = nullptr;
|
||||||
lel::Parser $parser;
|
lel::Parser $parser;
|
||||||
string $grid = "";
|
string $grid = "";
|
||||||
|
// BUG: check for this to prevent bugs, or find a way to shape the API so you
|
||||||
|
// simply can't get it wrong
|
||||||
|
bool initialized = false;
|
||||||
|
|
||||||
UI();
|
UI();
|
||||||
|
|
||||||
|
|
|
||||||
97
include/guecs/uistack.hpp
Normal file
97
include/guecs/uistack.hpp
Normal file
|
|
@ -0,0 +1,97 @@
|
||||||
|
#include <guecs/ui.hpp>
|
||||||
|
#include <flat_map>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
namespace gui {
|
||||||
|
template<typename SCREEN_TYPE>
|
||||||
|
struct UIStack {
|
||||||
|
using UIStackMap = std::flat_map<std::string, std::shared_ptr<SCREEN_TYPE>>;
|
||||||
|
|
||||||
|
UIStackMap screens{};
|
||||||
|
bool visible = false;
|
||||||
|
|
||||||
|
UIStackMap::iterator $current{screens.begin()};
|
||||||
|
SCREEN_TYPE* $active = nullptr;
|
||||||
|
|
||||||
|
void add(const std::string& name, std::shared_ptr<SCREEN_TYPE> screen) {
|
||||||
|
screens.insert_or_assign(name, screen);
|
||||||
|
update_active(screens.begin());
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_active(const UIStackMap::iterator& itr) {
|
||||||
|
$current = itr;
|
||||||
|
$active = (*$current).second.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_active(const std::string& name) {
|
||||||
|
assert(screens.contains(name) && "no screen with that name");
|
||||||
|
update_active(screens.find(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_visible(bool new_value) {
|
||||||
|
visible = new_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_visible() {
|
||||||
|
return visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
void render(sf::RenderTarget& target) {
|
||||||
|
assert($active != nullptr && "you didn't set active");
|
||||||
|
$active->render(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
void update() {
|
||||||
|
assert($active != nullptr && "you didn't set active");
|
||||||
|
$active->update();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mouse(float x, float y, guecs::Modifiers mods = guecs::NO_MODS) {
|
||||||
|
assert($active != nullptr && "you didn't set active");
|
||||||
|
return $active->mouse(x, y, mods);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool move(const UIStackMap::iterator& itr, const UIStackMap::iterator& avoid, const UIStackMap::iterator& result) {
|
||||||
|
if(itr != avoid) {
|
||||||
|
update_active(result);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool next() {
|
||||||
|
return move($current + 1, screens.end(), $current + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool prev() {
|
||||||
|
return move($current, screens.begin(), $current - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void first() {
|
||||||
|
update_active(screens.begin());
|
||||||
|
}
|
||||||
|
|
||||||
|
void last() {
|
||||||
|
update_active(screens.end() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& active_name() {
|
||||||
|
assert($active != nullptr && "you didn't set active");
|
||||||
|
return (*$current).first;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<SCREEN_TYPE> active_ui() {
|
||||||
|
assert($active != nullptr && "you didn't set active");
|
||||||
|
return (*$current).second;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<SCREEN_TYPE> at(const std::string& name) {
|
||||||
|
return screens.at(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
const UIStackMap::key_container_type& names() {
|
||||||
|
return screens.keys();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
10
meson.build
10
meson.build
|
|
@ -144,3 +144,13 @@ executable('calc', [
|
||||||
include_directories: lel_guecs_inc,
|
include_directories: lel_guecs_inc,
|
||||||
link_with: [lel_guecs_lib, lel_guecs_sfml_lib],
|
link_with: [lel_guecs_lib, lel_guecs_sfml_lib],
|
||||||
dependencies: dependencies)
|
dependencies: dependencies)
|
||||||
|
|
||||||
|
executable('multiscreen', [
|
||||||
|
'demos/multiscreen.cpp',
|
||||||
|
],
|
||||||
|
cpp_args: cpp_args,
|
||||||
|
link_args: link_args,
|
||||||
|
override_options: exe_defaults,
|
||||||
|
include_directories: lel_guecs_inc,
|
||||||
|
link_with: [lel_guecs_lib, lel_guecs_sfml_lib],
|
||||||
|
dependencies: dependencies)
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
namespace guecs {
|
namespace guecs {
|
||||||
using std::make_shared;
|
using std::make_shared;
|
||||||
|
|
||||||
|
// BUG: this seems to center things wrong in lel layouts
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void sfml_center_helper(T& obj, lel::Cell& cell, int padding) {
|
void sfml_center_helper(T& obj, lel::Cell& cell, int padding) {
|
||||||
sf::Vector2f position{float(cell.x + padding), float(cell.y + padding)};
|
sf::Vector2f position{float(cell.x + padding), float(cell.y + padding)};
|
||||||
|
|
|
||||||
|
|
@ -118,6 +118,8 @@ namespace guecs {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BUG: either render detects that the things are initialized or there's
|
||||||
|
// another validator function I can call in debug modes to confirm they are
|
||||||
void UI::render(sf::RenderTarget& window) {
|
void UI::render(sf::RenderTarget& window) {
|
||||||
if(auto bg = get_if<Background>(MAIN)) {
|
if(auto bg = get_if<Background>(MAIN)) {
|
||||||
bg->render(window);
|
bg->render(window);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue