handle mouse events
Signed-off-by: Peter Siegmund <developer@mars3142.org>
This commit is contained in:
@@ -1,200 +1,264 @@
|
||||
#include "ui/Device.h"
|
||||
|
||||
#include "SDL3_ttf/SDL_ttf.h"
|
||||
#include <hal/u8g2_hal_sdl.h>
|
||||
#include <u8g2.h>
|
||||
|
||||
#include "MenuOptions.h"
|
||||
#include "ui/SplashScreen.h"
|
||||
#include "ui/widgets/Button.h"
|
||||
#include "ui/widgets/D_Pad.h"
|
||||
|
||||
#include <u8g2.h>
|
||||
#include <hal/u8g2_hal_sdl.h>
|
||||
|
||||
#include "ui/SplashScreen.h"
|
||||
#include "MenuOptions.h"
|
||||
|
||||
u8g2_t u8g2;
|
||||
menu_options_t options;
|
||||
|
||||
static void set_pixel_rgba(
|
||||
const SDL_Surface* surface,
|
||||
const int x,
|
||||
const int y,
|
||||
const uint32_t pixel_color) {
|
||||
if(!surface || x < 0 || x >= surface->w || y < 0 || y >= surface->h) {
|
||||
static void set_pixel_rgba(const SDL_Surface *surface, const int x, const int y, const uint32_t pixel_color)
|
||||
{
|
||||
if (!surface || x < 0 || x >= surface->w || y < 0 || y >= surface->h)
|
||||
{
|
||||
return;
|
||||
}
|
||||
const auto p =
|
||||
static_cast<uint8_t*>(surface->pixels) + y * surface->pitch + x * sizeof(uint32_t);
|
||||
*reinterpret_cast<uint32_t*>(p) = pixel_color;
|
||||
const auto p = static_cast<uint8_t *>(surface->pixels) + y * surface->pitch + x * sizeof(uint32_t);
|
||||
*reinterpret_cast<uint32_t *>(p) = pixel_color;
|
||||
}
|
||||
|
||||
Device::Device(void* appstate)
|
||||
: UIWidget(appstate) {
|
||||
m_children.push_back(
|
||||
std::make_shared<Button>(
|
||||
get_context(),
|
||||
U8G2_SCREEN_WIDTH * U8G2_SCREEN_FACTOR + 3 * U8G2_SCREEN_PADDING + DPAD_WIDTH,
|
||||
U8G2_SCREEN_HEIGHT * U8G2_SCREEN_FACTOR + U8G2_SCREEN_PADDING - BUTTON_WIDTH,
|
||||
BUTTON_WIDTH,
|
||||
[]() { pushKey(SDLK_RETURN); }));
|
||||
m_children.push_back(
|
||||
std::make_shared<Button>(
|
||||
get_context(),
|
||||
U8G2_SCREEN_WIDTH * U8G2_SCREEN_FACTOR + 4 * U8G2_SCREEN_PADDING + DPAD_WIDTH +
|
||||
BUTTON_WIDTH,
|
||||
U8G2_SCREEN_HEIGHT * U8G2_SCREEN_FACTOR + U8G2_SCREEN_PADDING - 2 * BUTTON_WIDTH,
|
||||
BUTTON_WIDTH,
|
||||
[]() { pushKey(SDLK_BACKSPACE); }));
|
||||
m_children.push_back(
|
||||
std::make_shared<D_Pad>(
|
||||
get_context(),
|
||||
U8G2_SCREEN_WIDTH * U8G2_SCREEN_FACTOR + 2 * U8G2_SCREEN_PADDING,
|
||||
U8G2_SCREEN_HEIGHT * U8G2_SCREEN_FACTOR + U8G2_SCREEN_PADDING - DPAD_WIDTH,
|
||||
DPAD_WIDTH,
|
||||
[](int d) {}));
|
||||
Device::Device(void *appstate) : UIWidget(appstate)
|
||||
{
|
||||
auto dpad_callback = [](const D_Pad::Direction direction) {
|
||||
SDL_Keycode key = 0;
|
||||
switch (direction)
|
||||
{
|
||||
case D_Pad::Direction::UP:
|
||||
key = SDLK_UP;
|
||||
break;
|
||||
case D_Pad::Direction::DOWN:
|
||||
key = SDLK_DOWN;
|
||||
break;
|
||||
case D_Pad::Direction::LEFT:
|
||||
key = SDLK_LEFT;
|
||||
break;
|
||||
case D_Pad::Direction::RIGHT:
|
||||
key = SDLK_RIGHT;
|
||||
break;
|
||||
case D_Pad::Direction::NONE: // Fallthrough oder keine Aktion
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (key != 0)
|
||||
{
|
||||
PushKey(key);
|
||||
}
|
||||
};
|
||||
|
||||
u8g2_Setup_sh1106_128x64_noname_f(
|
||||
&u8g2, U8G2_R0, u8x8_byte_sdl_hw_spi, u8x8_gpio_and_delay_sdl);
|
||||
m_children.push_back(std::make_shared<Button>(
|
||||
GetContext(), U8G2_SCREEN_WIDTH * U8G2_SCREEN_FACTOR + 3 * U8G2_SCREEN_PADDING + DPAD_WIDTH,
|
||||
U8G2_SCREEN_HEIGHT * U8G2_SCREEN_FACTOR + U8G2_SCREEN_PADDING - BUTTON_WIDTH, BUTTON_WIDTH,
|
||||
[]() {
|
||||
PushKey(SDLK_RETURN);
|
||||
}));
|
||||
m_children.push_back(std::make_shared<Button>(
|
||||
GetContext(), U8G2_SCREEN_WIDTH * U8G2_SCREEN_FACTOR + 4 * U8G2_SCREEN_PADDING + DPAD_WIDTH + BUTTON_WIDTH,
|
||||
U8G2_SCREEN_HEIGHT * U8G2_SCREEN_FACTOR + U8G2_SCREEN_PADDING - 2 * BUTTON_WIDTH, BUTTON_WIDTH,
|
||||
[]() {
|
||||
PushKey(SDLK_BACKSPACE);
|
||||
}));
|
||||
m_children.push_back(std::make_shared<D_Pad>(
|
||||
GetContext(), U8G2_SCREEN_WIDTH * U8G2_SCREEN_FACTOR + 2 * U8G2_SCREEN_PADDING,
|
||||
U8G2_SCREEN_HEIGHT * U8G2_SCREEN_FACTOR + U8G2_SCREEN_PADDING - DPAD_WIDTH, DPAD_WIDTH, dpad_callback));
|
||||
|
||||
u8g2_Setup_sh1106_128x64_noname_f(&u8g2, U8G2_R0, u8x8_byte_sdl_hw_spi, u8x8_gpio_and_delay_sdl);
|
||||
u8x8_InitDisplay(u8g2_GetU8x8(&u8g2));
|
||||
|
||||
options = {
|
||||
.u8g2 = &u8g2,
|
||||
.setScreen = [this](const std::shared_ptr<Widget>& screen) { this->setScreen(screen); },
|
||||
.pushScreen = [this](const std::shared_ptr<Widget>& screen) { this->pushScreen(screen); },
|
||||
.popScreen = [this]() { this->popScreen(); },
|
||||
.setScreen = [this](const std::shared_ptr<Widget> &screen) {
|
||||
this->SetScreen(screen);
|
||||
},
|
||||
.pushScreen = [this](const std::shared_ptr<Widget> &screen) {
|
||||
this->PushScreen(screen);
|
||||
},
|
||||
.popScreen = [this]() {
|
||||
this->PopScreen();
|
||||
},
|
||||
};
|
||||
widget = std::make_shared<SplashScreen>(&options);
|
||||
}
|
||||
|
||||
void Device::setScreen(const std::shared_ptr<Widget>& screen) {
|
||||
if(screen != nullptr) {
|
||||
void Device::SetScreen(const std::shared_ptr<Widget> &screen)
|
||||
{
|
||||
if (screen != nullptr)
|
||||
{
|
||||
widget = screen;
|
||||
history.clear();
|
||||
history.emplace_back(widget);
|
||||
}
|
||||
}
|
||||
|
||||
void Device::pushScreen(const std::shared_ptr<Widget>& screen) {
|
||||
if(screen != nullptr) {
|
||||
void Device::PushScreen(const std::shared_ptr<Widget> &screen)
|
||||
{
|
||||
if (screen != nullptr)
|
||||
{
|
||||
widget = screen;
|
||||
history.emplace_back(widget);
|
||||
}
|
||||
}
|
||||
|
||||
void Device::popScreen() {
|
||||
if(history.size() >= 2) {
|
||||
void Device::PopScreen()
|
||||
{
|
||||
if (history.size() >= 2)
|
||||
{
|
||||
history.pop_back();
|
||||
widget = history.back();
|
||||
}
|
||||
}
|
||||
|
||||
void Device::pushKey(const SDL_Keycode key) {
|
||||
void Device::PushKey(const SDL_Keycode key)
|
||||
{
|
||||
SDL_Event ev;
|
||||
ev.type = SDL_EVENT_KEY_DOWN;
|
||||
ev.key.key = key;
|
||||
SDL_PushEvent(&ev);
|
||||
}
|
||||
|
||||
void Device::render_u8g2() const {
|
||||
SDL_Surface* u8g2_surface = nullptr;
|
||||
SDL_Texture* u8g2_texture = nullptr;
|
||||
void Device::RenderU8G2() const
|
||||
{
|
||||
SDL_Surface *u8g2_surface = nullptr;
|
||||
SDL_Texture *u8g2_texture = nullptr;
|
||||
|
||||
u8g2_surface =
|
||||
SDL_CreateSurface(U8G2_SCREEN_WIDTH, U8G2_SCREEN_HEIGHT, SDL_PIXELFORMAT_RGBA8888);
|
||||
u8g2_surface = SDL_CreateSurface(U8G2_SCREEN_WIDTH, U8G2_SCREEN_HEIGHT, SDL_PIXELFORMAT_RGBA8888);
|
||||
|
||||
if(!u8g2_surface) {
|
||||
if (!u8g2_surface)
|
||||
{
|
||||
SDL_Log("SDL_CreateSurfaceFrom Error: %s\n", SDL_GetError());
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto color_black = SDL_MapSurfaceRGBA(u8g2_surface, 0, 0, 0, 255);
|
||||
const auto color_white = SDL_MapSurfaceRGBA(u8g2_surface, 255, 255, 255, 255);
|
||||
|
||||
if(!SDL_LockSurface(u8g2_surface)) {
|
||||
SDL_Log("SDL_LockSurface Error: %s\n", SDL_GetError());
|
||||
} else {
|
||||
const auto u8g2_buf = u8g2_GetBufferPtr(&u8g2);
|
||||
for(auto y = 0; y < U8G2_SCREEN_HEIGHT; ++y) {
|
||||
for(auto x = 0; x < U8G2_SCREEN_WIDTH; ++x) {
|
||||
const auto page = y / 8;
|
||||
const auto bit_index = y % 8;
|
||||
const auto byte_ptr = u8g2_buf + page * U8G2_SCREEN_WIDTH + x;
|
||||
const auto pixel_is_set = (*byte_ptr >> bit_index) & 0x01;
|
||||
set_pixel_rgba(u8g2_surface, x, y, pixel_is_set ? color_white : color_black);
|
||||
}
|
||||
const auto u8g2_buf = u8g2_GetBufferPtr(&u8g2);
|
||||
for (auto y = 0; y < U8G2_SCREEN_HEIGHT; ++y)
|
||||
{
|
||||
for (auto x = 0; x < U8G2_SCREEN_WIDTH; ++x)
|
||||
{
|
||||
const auto page = y / 8;
|
||||
const auto bit_index = y % 8;
|
||||
const auto byte_ptr = u8g2_buf + page * U8G2_SCREEN_WIDTH + x;
|
||||
const auto pixel_is_set = (*byte_ptr >> bit_index) & 0x01;
|
||||
set_pixel_rgba(u8g2_surface, x, y, pixel_is_set ? color_white : color_black);
|
||||
}
|
||||
SDL_UnlockSurface(u8g2_surface);
|
||||
}
|
||||
|
||||
u8g2_texture = SDL_CreateTextureFromSurface(get_context()->renderer(), u8g2_surface);
|
||||
if(!u8g2_texture) {
|
||||
u8g2_texture = SDL_CreateTextureFromSurface(GetContext()->MainRenderer(), u8g2_surface);
|
||||
if (!u8g2_texture)
|
||||
{
|
||||
SDL_Log("SDL_CreateTextureFromSurface Error: %s\n", SDL_GetError());
|
||||
}
|
||||
if(!SDL_SetTextureScaleMode(u8g2_texture, SDL_SCALEMODE_NEAREST)) {
|
||||
if (!SDL_SetTextureScaleMode(u8g2_texture, SDL_SCALEMODE_NEAREST))
|
||||
{
|
||||
SDL_Log("SDL_SetTextureScaleMode Error: %s\n", SDL_GetError());
|
||||
}
|
||||
SDL_DestroySurface(u8g2_surface);
|
||||
}
|
||||
|
||||
if(u8g2_texture) {
|
||||
if (u8g2_texture)
|
||||
{
|
||||
SDL_FRect destRect;
|
||||
destRect.x = U8G2_SCREEN_PADDING;
|
||||
destRect.y = U8G2_SCREEN_PADDING;
|
||||
destRect.w = U8G2_SCREEN_WIDTH * U8G2_SCREEN_FACTOR;
|
||||
destRect.h = U8G2_SCREEN_HEIGHT * U8G2_SCREEN_FACTOR;
|
||||
|
||||
SDL_RenderTexture(get_context()->renderer(), u8g2_texture, nullptr, &destRect);
|
||||
SDL_RenderTexture(GetContext()->MainRenderer(), u8g2_texture, nullptr, &destRect);
|
||||
SDL_DestroyTexture(u8g2_texture);
|
||||
}
|
||||
}
|
||||
|
||||
void Device::draw_background() const {
|
||||
void Device::DrawBackground() const
|
||||
{
|
||||
int windowWidth = 0;
|
||||
int windowHeight = 0;
|
||||
|
||||
if(!SDL_GetWindowSize(get_context()->window(), &windowWidth, &windowHeight)) {
|
||||
if (!SDL_GetWindowSize(GetContext()->MainWindow(), &windowWidth, &windowHeight))
|
||||
{
|
||||
SDL_Log("SDL_GetWindowSize Error: %s\n", SDL_GetError());
|
||||
}
|
||||
const auto rect =
|
||||
SDL_FRect{0.0f, 0.0f, static_cast<float>(windowWidth), static_cast<float>(windowHeight)};
|
||||
SDL_SetRenderDrawColor(get_context()->renderer(), 193, 46, 31, 255);
|
||||
SDL_RenderFillRect(get_context()->renderer(), &rect);
|
||||
const auto rect = SDL_FRect{0.0f, 0.0f, static_cast<float>(windowWidth), static_cast<float>(windowHeight)};
|
||||
SDL_SetRenderDrawColor(GetContext()->MainRenderer(), 193, 46, 31, 255);
|
||||
SDL_RenderFillRect(GetContext()->MainRenderer(), &rect);
|
||||
}
|
||||
|
||||
void Device::draw_screen() const {
|
||||
void Device::DrawScreen() const
|
||||
{
|
||||
u8g2_ClearBuffer(&u8g2);
|
||||
|
||||
if(widget != nullptr) {
|
||||
if (widget != nullptr)
|
||||
{
|
||||
widget->update(SDL_GetTicks());
|
||||
widget->render();
|
||||
}
|
||||
|
||||
render_u8g2();
|
||||
RenderU8G2();
|
||||
}
|
||||
|
||||
void Device::draw_text() const {
|
||||
constexpr auto color = SDL_Color({0, 255, 200});
|
||||
const auto surface =
|
||||
TTF_RenderText_Blended(get_context()->m_font_default, "HelloWorld SDL3 TTF", 0, color);
|
||||
const auto texture = SDL_CreateTextureFromSurface(get_context()->renderer(), surface);
|
||||
SDL_DestroySurface(surface);
|
||||
const SDL_FRect dstRect{
|
||||
500, 100, static_cast<float>(texture->w), static_cast<float>(texture->h)};
|
||||
SDL_RenderTexture(get_context()->renderer(), texture, nullptr, &dstRect);
|
||||
SDL_DestroyTexture(texture); // ? Is this safe to do here ?
|
||||
}
|
||||
void Device::Render() const
|
||||
{
|
||||
DrawBackground();
|
||||
DrawScreen();
|
||||
|
||||
void Device::render() const {
|
||||
draw_background();
|
||||
draw_screen();
|
||||
// draw_text();
|
||||
|
||||
for(const auto& child : m_children) {
|
||||
child->render();
|
||||
for (const auto &child : m_children)
|
||||
{
|
||||
child->Render();
|
||||
}
|
||||
}
|
||||
|
||||
void Device::hit_test(SDL_MouseMotionEvent* event) const {
|
||||
SDL_Log("x: %f", event->x);
|
||||
void Device::HandleTap(const SDL_MouseButtonEvent *event) const
|
||||
{
|
||||
// SDL_Log("HandleTap: x=%f, y=%f, button=%d", event->x, event->y, event->button);
|
||||
|
||||
for (const auto &child : m_children)
|
||||
{
|
||||
if (child->IsHit(static_cast<int>(event->x), static_cast<int>(event->y)))
|
||||
{
|
||||
child->OnTap(static_cast<int>(event->x), static_cast<int>(event->y));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Device::onButtonClicked(const uint8_t button) const {
|
||||
if(widget != nullptr) {
|
||||
void Device::ReleaseTap(const SDL_MouseButtonEvent *event) const
|
||||
{
|
||||
// SDL_Log("ReleaseTap: x=%f, y=%f, button=%d", event->x, event->y, event->button);
|
||||
|
||||
for (const auto &child : m_children)
|
||||
{
|
||||
if (child->IsHit(static_cast<int>(event->x), static_cast<int>(event->y)))
|
||||
{
|
||||
child->ReleaseTap(static_cast<int>(event->x), static_cast<int>(event->y));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Device::OnButtonClicked(const uint8_t button) const
|
||||
{
|
||||
if (widget != nullptr)
|
||||
{
|
||||
widget->onButtonClicked(button);
|
||||
}
|
||||
}
|
||||
|
||||
bool Device::IsHit(int mouse_x, int mouse_y) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void Device::OnTap(int mouse_x, int mouse_y)
|
||||
{
|
||||
////
|
||||
}
|
||||
|
||||
void Device::ReleaseTap(int mouse_x, int mouse_y)
|
||||
{
|
||||
///
|
||||
}
|
@@ -5,38 +5,44 @@
|
||||
#include <vector>
|
||||
|
||||
#include "UIWidget.h"
|
||||
#include "model/AppContext.h"
|
||||
#include "common/Widget.h"
|
||||
#include "model/AppContext.h"
|
||||
|
||||
class Device final : public UIWidget {
|
||||
public:
|
||||
explicit Device(void* appstate);
|
||||
class Device final : public UIWidget
|
||||
{
|
||||
public:
|
||||
explicit Device(void *appstate);
|
||||
|
||||
void render() const override;
|
||||
void Render() const override;
|
||||
|
||||
void hit_test(SDL_MouseMotionEvent* event) const;
|
||||
void HandleTap(const SDL_MouseButtonEvent *event) const;
|
||||
|
||||
void onButtonClicked(uint8_t button) const;
|
||||
void ReleaseTap(const SDL_MouseButtonEvent *event) const;
|
||||
|
||||
private:
|
||||
void draw_background() const;
|
||||
void OnButtonClicked(uint8_t button) const;
|
||||
|
||||
void draw_screen() const;
|
||||
[[nodiscard]] bool IsHit(int mouse_x, int mouse_y) const override;
|
||||
|
||||
void draw_text() const;
|
||||
void OnTap(int mouse_x, int mouse_y) override;
|
||||
|
||||
void render_u8g2() const;
|
||||
void ReleaseTap(int mouse_x, int mouse_y) override;
|
||||
|
||||
void setScreen(const std::shared_ptr<Widget>& screen);
|
||||
private:
|
||||
void DrawBackground() const;
|
||||
|
||||
void pushScreen(const std::shared_ptr<Widget>& screen);
|
||||
void DrawScreen() const;
|
||||
|
||||
void popScreen();
|
||||
void RenderU8G2() const;
|
||||
|
||||
static void pushKey(SDL_Keycode key);
|
||||
void SetScreen(const std::shared_ptr<Widget> &screen);
|
||||
|
||||
void PushScreen(const std::shared_ptr<Widget> &screen);
|
||||
|
||||
void PopScreen();
|
||||
|
||||
static void PushKey(SDL_Keycode key);
|
||||
|
||||
std::vector<std::shared_ptr<UIWidget>> m_children{};
|
||||
|
||||
std::shared_ptr<Widget> widget;
|
||||
std::vector<std::shared_ptr<Widget>> history;
|
||||
};
|
||||
|
@@ -1,22 +1,30 @@
|
||||
#include "ui/Matrix.h"
|
||||
|
||||
Matrix::Matrix(Window *window): m_window(window) {
|
||||
Matrix::Matrix(Window *window) : m_window(window)
|
||||
{
|
||||
}
|
||||
|
||||
Window *Matrix::window() const {
|
||||
Window *Matrix::window() const
|
||||
{
|
||||
return m_window;
|
||||
}
|
||||
|
||||
void Matrix::draw_colored_grid(const int rows, const int cols, const float cellSize, const float spacing) const {
|
||||
void Matrix::DrawColoredGrid(const int rows, const int cols, const float cellSize, const float spacing) const
|
||||
{
|
||||
int i = 0;
|
||||
for (int w = 0; w < cols; w++) {
|
||||
for (int w = 0; w < cols; w++)
|
||||
{
|
||||
const auto phase = w % (2 * rows);
|
||||
|
||||
for (int h_raw = 0; h_raw < rows; h_raw++) {
|
||||
for (int h_raw = 0; h_raw < rows; h_raw++)
|
||||
{
|
||||
int h;
|
||||
if (phase < rows) {
|
||||
if (phase < rows)
|
||||
{
|
||||
h = h_raw;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
h = rows - 1 - h_raw;
|
||||
}
|
||||
|
||||
@@ -37,11 +45,12 @@ void Matrix::draw_colored_grid(const int rows, const int cols, const float cellS
|
||||
}
|
||||
}
|
||||
|
||||
void Matrix::render() const {
|
||||
void Matrix::Render() const
|
||||
{
|
||||
SDL_SetRenderDrawColor(m_window->renderer(), 0, 0, 0, 255);
|
||||
SDL_RenderClear(m_window->renderer());
|
||||
|
||||
draw_colored_grid(8, 32, 50.0f, 1.0f);
|
||||
DrawColoredGrid(8, 32, 50.0f, 1.0f);
|
||||
|
||||
SDL_RenderPresent(m_window->renderer());
|
||||
}
|
||||
|
@@ -2,16 +2,17 @@
|
||||
|
||||
#include "model/Window.h"
|
||||
|
||||
class Matrix {
|
||||
public:
|
||||
explicit Matrix(Window* window);
|
||||
class Matrix
|
||||
{
|
||||
public:
|
||||
explicit Matrix(Window *window);
|
||||
|
||||
[[nodiscard]] Window* window() const;
|
||||
[[nodiscard]] Window *window() const;
|
||||
|
||||
void render() const;
|
||||
void Render() const;
|
||||
|
||||
private:
|
||||
void draw_colored_grid(int rows, int cols, float cellSize, float spacing) const;
|
||||
private:
|
||||
void DrawColoredGrid(int rows, int cols, float cellSize, float spacing) const;
|
||||
|
||||
Window* m_window;
|
||||
Window *m_window;
|
||||
};
|
||||
|
@@ -1,10 +1,12 @@
|
||||
#include "ui/UIWidget.h"
|
||||
|
||||
UIWidget::UIWidget(void *appstate): m_context(static_cast<AppContext *>(appstate)) {
|
||||
UIWidget::UIWidget(void *appstate) : m_context(static_cast<AppContext *>(appstate))
|
||||
{
|
||||
}
|
||||
|
||||
UIWidget::~UIWidget() = default;
|
||||
|
||||
auto UIWidget::get_context() const -> AppContext* {
|
||||
auto UIWidget::GetContext() const -> AppContext *
|
||||
{
|
||||
return m_context;
|
||||
}
|
||||
|
@@ -2,15 +2,22 @@
|
||||
|
||||
#include "model/AppContext.h"
|
||||
|
||||
class UIWidget {
|
||||
class UIWidget
|
||||
{
|
||||
public:
|
||||
explicit UIWidget(void *appstate);
|
||||
|
||||
virtual ~UIWidget();
|
||||
|
||||
virtual void render() const = 0;
|
||||
virtual void Render() const = 0;
|
||||
|
||||
[[nodiscard]] AppContext *get_context() const;
|
||||
[[nodiscard]] virtual bool IsHit(int mouse_x, int mouse_y) const = 0;
|
||||
|
||||
virtual void OnTap(int mouse_x, int mouse_y) = 0;
|
||||
|
||||
virtual void ReleaseTap(int mouse_x, int mouse_y) = 0;
|
||||
|
||||
[[nodiscard]] AppContext *GetContext() const;
|
||||
|
||||
private:
|
||||
AppContext *m_context{};
|
||||
|
@@ -1,34 +1,49 @@
|
||||
#include "ui/widgets/Button.h"
|
||||
|
||||
#include "ResourceManager.h"
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
#include <SDL3_image/SDL_image.h>
|
||||
#include "ResourceManager.h"
|
||||
|
||||
auto pressed = false;
|
||||
|
||||
Button::Button(
|
||||
void* appState,
|
||||
const float x,
|
||||
const float y,
|
||||
const float width,
|
||||
std::function<void()> callback)
|
||||
: UIWidget(appState)
|
||||
, m_x(x)
|
||||
, m_y(y)
|
||||
, m_width(width)
|
||||
, m_callback(std::move(callback)) {
|
||||
Button::Button(void *appState, const float x, const float y, const float width, std::function<void()> callback)
|
||||
: UIWidget(appState), m_x(x), m_y(y), m_width(width), m_callback(std::move(callback))
|
||||
{
|
||||
}
|
||||
|
||||
void Button::render() const {
|
||||
const auto button = ResourceManager::getInstance().get_texture(
|
||||
get_context()->renderer(), "assets/button_normal.png");
|
||||
const auto overlay = ResourceManager::getInstance().get_texture(
|
||||
get_context()->renderer(), "assets/button_pressed_overlay.png");
|
||||
void Button::Render() const
|
||||
{
|
||||
const auto button =
|
||||
ResourceManager::Instance().GetTextureByName(GetContext()->MainRenderer(), "button_normal.png");
|
||||
const auto overlay =
|
||||
ResourceManager::Instance().GetTextureByName(GetContext()->MainRenderer(), "button_pressed_overlay.png");
|
||||
|
||||
const auto dst = SDL_FRect(m_x, m_y, m_width, m_width);
|
||||
SDL_RenderTexture(get_context()->renderer(), button, nullptr, &dst);
|
||||
if(pressed) {
|
||||
SDL_RenderTexture(get_context()->renderer(), overlay, nullptr, &dst);
|
||||
SDL_RenderTexture(GetContext()->MainRenderer(), button, nullptr, &dst);
|
||||
if (m_isPressed)
|
||||
{
|
||||
SDL_RenderTexture(GetContext()->MainRenderer(), overlay, nullptr, &dst);
|
||||
}
|
||||
}
|
||||
|
||||
bool Button::IsHit(const int mouse_x, const int mouse_y) const
|
||||
{
|
||||
const auto fx = static_cast<float>(mouse_x);
|
||||
const auto fy = static_cast<float>(mouse_y);
|
||||
return (fx >= m_x && fx <= (m_x + m_width) &&
|
||||
fy >= m_y && fy <= (m_y + m_width)) || m_isPressed;
|
||||
}
|
||||
|
||||
void Button::OnTap(int mouse_x, int mouse_y)
|
||||
{
|
||||
if (m_callback)
|
||||
{
|
||||
m_isPressed = true;
|
||||
m_callback();
|
||||
}
|
||||
}
|
||||
|
||||
void Button::ReleaseTap(int mouse_x, int mouse_y)
|
||||
{
|
||||
m_isPressed = false;
|
||||
}
|
@@ -6,15 +6,23 @@
|
||||
|
||||
#define BUTTON_WIDTH (35)
|
||||
|
||||
class Button final : public UIWidget {
|
||||
public:
|
||||
Button(void* appState, float x, float y, float width, std::function<void()> callback);
|
||||
class Button final : public UIWidget
|
||||
{
|
||||
public:
|
||||
Button(void *appState, float x, float y, float width, std::function<void()> callback);
|
||||
|
||||
void render() const override;
|
||||
void Render() const override;
|
||||
|
||||
[[nodiscard]] bool IsHit(int mouse_x, int mouse_y) const override;
|
||||
|
||||
void OnTap(int mouse_x, int mouse_y) override;
|
||||
|
||||
void ReleaseTap(int mouse_x, int mouse_y) override;
|
||||
|
||||
private:
|
||||
float m_x;
|
||||
float m_y;
|
||||
float m_width;
|
||||
std::function<void()> m_callback;
|
||||
bool m_isPressed = false;
|
||||
};
|
||||
|
@@ -1,24 +1,82 @@
|
||||
#include "D_Pad.h"
|
||||
#include "ui/widgets/D_Pad.h"
|
||||
|
||||
#include "ResourceManager.h"
|
||||
|
||||
D_Pad::D_Pad(
|
||||
void* appState,
|
||||
const float x,
|
||||
const float y,
|
||||
const float width,
|
||||
std::function<void(int)> callback)
|
||||
: UIWidget(appState)
|
||||
, m_x(x)
|
||||
, m_y(y)
|
||||
, m_width(width)
|
||||
, m_callback(std::move(callback)) {
|
||||
D_Pad::D_Pad(void *appState, const float x, const float y, const float width, std::function<void(Direction)> callback)
|
||||
: UIWidget(appState), m_x(x), m_y(y), m_width(width), m_callback(std::move(callback))
|
||||
{
|
||||
}
|
||||
|
||||
void D_Pad::render() const {
|
||||
const auto dPad = ResourceManager::getInstance().get_texture(
|
||||
get_context()->renderer(), "assets/d-pad_normal.png");
|
||||
void D_Pad::Render() const
|
||||
{
|
||||
const auto dPad =
|
||||
ResourceManager::Instance().GetTextureByName(GetContext()->MainRenderer(), "d-pad_normal.png");
|
||||
|
||||
const auto dst = SDL_FRect(m_x, m_y, m_width, m_width);
|
||||
SDL_RenderTexture(get_context()->renderer(), dPad, nullptr, &dst);
|
||||
SDL_RenderTexture(GetContext()->MainRenderer(), dPad, nullptr, &dst);
|
||||
}
|
||||
|
||||
bool D_Pad::IsHit(const int mouse_x, const int mouse_y) const
|
||||
{
|
||||
const auto fx = static_cast<float>(mouse_x);
|
||||
const auto fy = static_cast<float>(mouse_y);
|
||||
return (fx >= m_x && fx <= (m_x + m_width) &&
|
||||
fy >= m_y && fy <= (m_y + m_width));
|
||||
}
|
||||
|
||||
D_Pad::Direction D_Pad::GetDirectionFromTap(const float local_x, const float local_y) const
|
||||
{
|
||||
const float segment = m_width / 3.0f;
|
||||
|
||||
int col = -1;
|
||||
if (local_x < segment)
|
||||
col = 0;
|
||||
else if (local_x < 2 * segment)
|
||||
col = 1;
|
||||
else if (local_x <= m_width)
|
||||
col = 2;
|
||||
else
|
||||
return Direction::NONE;
|
||||
|
||||
int row = -1;
|
||||
if (local_y < segment)
|
||||
row = 0;
|
||||
else if (local_y < 2 * segment)
|
||||
row = 1;
|
||||
else if (local_y <= m_width)
|
||||
row = 2;
|
||||
else
|
||||
return Direction::NONE;
|
||||
|
||||
if (col == 1 && row == 0)
|
||||
return Direction::UP;
|
||||
if (col == 1 && row == 2)
|
||||
return Direction::DOWN;
|
||||
if (col == 0 && row == 1)
|
||||
return Direction::LEFT;
|
||||
if (col == 2 && row == 1)
|
||||
return Direction::RIGHT;
|
||||
|
||||
return Direction::NONE;
|
||||
}
|
||||
|
||||
void D_Pad::OnTap(const int mouse_x, const int mouse_y)
|
||||
{
|
||||
if (m_callback)
|
||||
{
|
||||
const auto local_x = static_cast<float>(mouse_x) - m_x;
|
||||
const auto local_y = static_cast<float>(mouse_y) - m_y;
|
||||
|
||||
if (local_x >= 0 && local_x <= m_width && local_y >= 0 && local_y <= m_width)
|
||||
{
|
||||
const auto dir = GetDirectionFromTap(local_x, local_y);
|
||||
m_callback(dir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void D_Pad::ReleaseTap(const int mouse_x, const int mouse_y)
|
||||
{
|
||||
///
|
||||
}
|
@@ -5,15 +5,25 @@
|
||||
|
||||
#define DPAD_WIDTH (105)
|
||||
|
||||
class D_Pad final : public UIWidget {
|
||||
public:
|
||||
D_Pad(void* appState, float x, float y, float width, std::function<void(int)> callback);
|
||||
|
||||
void render() const override;
|
||||
class D_Pad final : public UIWidget
|
||||
{
|
||||
public:
|
||||
enum class Direction { NONE, UP, DOWN, LEFT, RIGHT };
|
||||
|
||||
D_Pad(void *appState, float x, float y, float width, std::function<void(Direction)> callback);
|
||||
|
||||
void Render() const override;
|
||||
|
||||
[[nodiscard]] bool IsHit(int mouse_x, int mouse_y) const override;
|
||||
|
||||
void OnTap(int mouse_x, int mouse_y) override;
|
||||
|
||||
void ReleaseTap(int mouse_x, int mouse_y) override;
|
||||
|
||||
private:
|
||||
float m_x;
|
||||
float m_y;
|
||||
float m_width;
|
||||
std::function<void(int)> m_callback;
|
||||
float m_x, m_y, m_width;
|
||||
std::function<void(Direction)> m_callback;
|
||||
|
||||
[[nodiscard]] Direction GetDirectionFromTap(float local_x, float local_y) const;
|
||||
};
|
||||
|
Reference in New Issue
Block a user