Bring in the components into separate files so I can start to see how to make them generic. Then make the calculator kind of work but not yet.

main
Zed A. Shaw 11 months ago
parent 313a9aec83
commit 4b07ecac45
  1. 75
      demos/calc.cpp
  2. 136
      sfml/components.cpp
  3. 120
      sfml/components.hpp

@ -4,17 +4,31 @@
#include "sfml/textures.hpp"
#include "guecs.hpp"
#include "constants.hpp"
#include <fmt/xchar.h>
constexpr const int WINDOW_WIDTH=300;
constexpr const int WINDOW_HEIGHT=400;
using std::string, std::wstring;
const std::unordered_map<string, wstring> LABELS {
{"readout", L""}, {"clear", L"CLR"}, {"btn0", L"0"}, {"btn1", L"1"},
{"btn2", L"2"}, {"btn3", L"3"}, {"btn4", L"4"},
{"btn5", L"5"}, {"btn6", L"6"}, {"btn7", L"7"},
{"btn8", L"8"}, {"btn9", L"9"}, {"mult", L"*"},
{"minus", L"-"}, {"plus", L"+"}, {"neg", L"!"},
{"dot", L"."}, {"eq", L"="}
};
struct Calculator {
guecs::UI $gui;
wstring $input;
double $value = 0.0;
Calculator() {
$gui.position(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
$gui.layout(
"[readout]"
"[*%(400)readout|_|_|_|clear]"
"[btn7|btn8|btn9|mult]"
"[btn4|btn5|btn6|minus]"
"[btn1|btn2|btn3|plus]"
@ -26,13 +40,20 @@ struct Calculator {
for(auto& [name, cell] : $gui.cells()) {
auto id = $gui.entity(name);
auto& label = LABELS.at(name);
$gui.set<guecs::Rectangle>(id, {});
$gui.set<guecs::Effect>(id, {});
$gui.set<guecs::Label>(id, {guecs::to_wstring(name)});
if(name == "readout") {
$gui.set<guecs::Textual>(id, {L"", 40});
} else {
$gui.set<guecs::Label>(id, { label });
$gui.set<guecs::Clickable>(id, {
[=](auto, auto) { fmt::println("clicked {}", name); }
[&, name](auto, auto) { handle_button(label[0]); }
});
}
}
$gui.init();
}
@ -45,9 +66,57 @@ struct Calculator {
void mouse(float x, float y, bool hover) {
$gui.mouse(x, y, hover);
}
void handle_button(wchar_t op) {
switch(op) {
case L'0':
case L'1':
case L'2':
case L'3':
case L'4':
case L'5':
case L'6':
case L'7':
case L'8':
case L'9':
case L'.':
if($input.size() <= 10) {
$input += op;
}
break;
case L'*':
$value = $value * std::stof($input);
$input = L"";
break;
case L'-':
$value = $value - std::stof($input);
$input = L"";
break;
case L'+':
$value = $value + std::stof($input);
$input = L"";
break;
case L'!':
$value = $value * -1.0;
$input = L"";
break;
case L'=':
$input = fmt::format(L"{}", $value);
$value = 0.0;
break;
case L'C':
$input = L"";
break;
}
auto readout = $gui.entity("readout");
auto& label = $gui.get<guecs::Textual>(readout);
label.update($input);
}
};
int main() {
sound::init();
shaders::init();

@ -0,0 +1,136 @@
#include "guecs.hpp"
#include "sfml/shaders.hpp"
#include "sfml/sound.hpp"
#include "sfml/textures.hpp"
namespace guecs {
using std::make_shared;
void Textual::init(lel::Cell &cell, shared_ptr<sf::Font> font_ptr) {
dbc::check(font_ptr != nullptr, "you failed to initialize this WideText");
if(font == nullptr) font = font_ptr;
if(text == nullptr) text = make_shared<sf::Text>(*font, content, size);
text->setFillColor(color);
if(centered) {
auto bounds = text->getLocalBounds();
auto text_cell = lel::center(bounds.size.x, bounds.size.y, cell);
// this stupid / 2 is because SFML renders from baseline rather than from the claimed bounding box
text->setPosition({float(text_cell.x), float(text_cell.y) - text_cell.h / 2});
} else {
text->setPosition({float(cell.x + padding * 2), float(cell.y + padding * 2)});
}
text->setCharacterSize(size);
}
void Textual::update(const wstring& new_content) {
content = new_content;
text->setString(content);
}
void Sprite::update(const string& new_name) {
if(new_name != name) {
name = new_name;
auto sprite_texture = textures::get(name);
sprite->setTexture(*sprite_texture.texture);
sprite->setTextureRect(sprite_texture.sprite->getTextureRect());
}
}
void Sprite::init(lel::Cell &cell) {
auto sprite_texture = textures::get(name);
sprite = make_shared<sf::Sprite>(
*sprite_texture.texture,
sprite_texture.sprite->getTextureRect());
sprite->setPosition({
float(cell.x + padding),
float(cell.y + padding)});
auto bounds = sprite->getLocalBounds();
sprite->setScale({
float(cell.w - padding * 2) / bounds.size.x,
float(cell.h - padding * 2) / bounds.size.y});
}
void Rectangle::init(lel::Cell& cell) {
sf::Vector2f size{float(cell.w) - padding * 2, float(cell.h) - padding * 2};
if(shape == nullptr) shape = make_shared<sf::RectangleShape>(size);
shape->setPosition({float(cell.x + padding), float(cell.y + padding)});
shape->setFillColor(color);
shape->setOutlineColor(border_color);
shape->setOutlineThickness(border_px);
}
void Meter::init(lel::Cell& cell) {
bar.init(cell);
}
void Meter::render(lel::Cell& cell) {
float level = std::clamp(percent, 0.0f, 1.0f) * float(cell.w);
// ZED: this 6 is a border width, make it a thing
bar.shape->setSize({std::max(level, 0.0f), float(cell.h - 6)});
}
void Sound::play(bool hover) {
if(!hover) {
sound::play(on_click);
}
}
void Sound::stop(bool hover) {
if(!hover) {
sound::stop(on_click);
}
}
void Background::init() {
sf::Vector2f size{float(w), float(h)};
if(shape == nullptr) shape = make_shared<sf::RectangleShape>(size);
shape->setPosition({float(x), float(y)});
shape->setFillColor(color);
}
void Effect::init(lel::Cell &cell) {
$shader_version = shaders::version();
$shader = shaders::get(name);
$shader->setUniform("u_resolution", sf::Vector2f({float(cell.w), float(cell.h)}));
$clock = std::make_shared<sf::Clock>();
}
void Effect::step() {
sf::Time cur_time = $clock->getElapsedTime();
float u_time = cur_time.asSeconds();
if(u_time < $u_time_end) {
$shader->setUniform("u_duration", duration);
$shader->setUniform("u_time_end", $u_time_end);
$shader->setUniform("u_time", u_time);
} else {
$active = false;
}
}
void Effect::run() {
$active = true;
sf::Time u_time = $clock->getElapsedTime();
$u_time_end = u_time.asSeconds() + duration;
}
shared_ptr<sf::Shader> Effect::checkout_ptr() {
if(shaders::updated($shader_version)) {
$shader = shaders::get(name);
$shader_version = shaders::version();
}
return $shader;
}
void Effect::stop() {
$active = false;
}
}

@ -0,0 +1,120 @@
#pragma once
#include "dbc.hpp"
#include "sfml/color.hpp"
#include "lel.hpp"
#include <string>
#include <memory>
#include <SFML/Graphics.hpp>
#include <functional>
#include <any>
namespace guecs {
using std::shared_ptr, std::wstring, std::string;
constexpr const int PADDING = 3;
constexpr const int BORDER_PX = 1;
constexpr const int TEXT_SIZE = 30;
constexpr const int LABEL_SIZE = 20;
constexpr const sf::Color FILL_COLOR = ColorValue::DARK_MID;
constexpr const sf::Color TEXT_COLOR = ColorValue::LIGHT_LIGHT;
constexpr const sf::Color BG_COLOR = ColorValue::MID;
constexpr const sf::Color BORDER_COLOR = ColorValue::MID;
constexpr const char *FONT_FILE_NAME="assets/text.otf";
struct Textual {
std::wstring content;
unsigned int size = TEXT_SIZE;
sf::Color color = TEXT_COLOR;
int padding = PADDING;
bool centered = false;
shared_ptr<sf::Font> font = nullptr;
shared_ptr<sf::Text> text = nullptr;
void init(lel::Cell &cell, shared_ptr<sf::Font> font_ptr);
void update(const std::wstring& new_content);
};
struct Label : public Textual {
template<typename... Args>
Label(Args... args) : Textual(args...)
{
centered = true;
size = LABEL_SIZE;
}
Label() {
centered = true;
};
};
struct Sprite {
string name;
int padding = PADDING;
std::shared_ptr<sf::Sprite> sprite = nullptr;
void init(lel::Cell &cell);
void update(const string& new_name);
};
struct Rectangle {
int padding = PADDING;
sf::Color color = FILL_COLOR;
sf::Color border_color = BORDER_COLOR;
int border_px = BORDER_PX;
shared_ptr<sf::RectangleShape> shape = nullptr;
void init(lel::Cell& cell);
};
struct Meter {
float percent = 1.0f;
sf::Color color = ColorValue::BLACK;
Rectangle bar;
void init(lel::Cell& cell);
void render(lel::Cell& cell);
};
struct Effect {
float duration = 0.1f;
string name{"ui_shader"};
float $u_time_end = 0.0;
bool $active = false;
std::shared_ptr<sf::Clock> $clock = nullptr;
std::shared_ptr<sf::Shader> $shader = nullptr;
int $shader_version = 0;
void init(lel::Cell &cell);
void run();
void stop();
void step();
shared_ptr<sf::Shader> checkout_ptr();
};
struct Sound {
string on_click{"ui_click"};
void play(bool hover);
void stop(bool hover);
};
struct Background {
float x = 0.0f;
float y = 0.0f;
float w = 0.0f;
float h = 0.0f;
sf::Color color = BG_COLOR;
shared_ptr<sf::RectangleShape> shape = nullptr;
Background(lel::Parser& parser, sf::Color bg_color=BG_COLOR) :
x(parser.grid_x),
y(parser.grid_y),
w(parser.grid_w),
h(parser.grid_h),
color(bg_color)
{}
Background() {}
void init();
};
}