Added multi-touch, added on press down
This commit is contained in:
parent
a06cb77a66
commit
4a542fd6c8
@ -31,7 +31,7 @@
|
|||||||
"vertical_gravity": "bottom",
|
"vertical_gravity": "bottom",
|
||||||
"textures": {
|
"textures": {
|
||||||
"normal": "resources/fire.png",
|
"normal": "resources/fire.png",
|
||||||
"hover": "resources/fire2.png",
|
"hover": "resources/fire.png",
|
||||||
"pressed": "resources/fire2.png",
|
"pressed": "resources/fire2.png",
|
||||||
"disabled": "resources/fire_disabled.png"
|
"disabled": "resources/fire_disabled.png"
|
||||||
}
|
}
|
||||||
@ -47,7 +47,7 @@
|
|||||||
"vertical_gravity": "bottom",
|
"vertical_gravity": "bottom",
|
||||||
"textures": {
|
"textures": {
|
||||||
"normal": "resources/fire.png",
|
"normal": "resources/fire.png",
|
||||||
"hover": "resources/fire2.png",
|
"hover": "resources/fire.png",
|
||||||
"pressed": "resources/fire2.png",
|
"pressed": "resources/fire2.png",
|
||||||
"disabled": "resources/fire_disabled.png"
|
"disabled": "resources/fire_disabled.png"
|
||||||
}
|
}
|
||||||
|
|||||||
78
src/Game.cpp
78
src/Game.cpp
@ -369,33 +369,56 @@ namespace ZL
|
|||||||
if (event.type == SDL_FINGERDOWN) {
|
if (event.type == SDL_FINGERDOWN) {
|
||||||
int mx = static_cast<int>(event.tfinger.x * Environment::projectionWidth);
|
int mx = static_cast<int>(event.tfinger.x * Environment::projectionWidth);
|
||||||
int my = static_cast<int>(event.tfinger.y * Environment::projectionHeight);
|
int my = static_cast<int>(event.tfinger.y * Environment::projectionHeight);
|
||||||
handleDown(mx, my);
|
handleDown(static_cast<int64_t>(event.tfinger.fingerId), mx, my);
|
||||||
}
|
}
|
||||||
else if (event.type == SDL_FINGERUP) {
|
else if (event.type == SDL_FINGERUP) {
|
||||||
int mx = static_cast<int>(event.tfinger.x * Environment::projectionWidth);
|
int mx = static_cast<int>(event.tfinger.x * Environment::projectionWidth);
|
||||||
int my = static_cast<int>(event.tfinger.y * Environment::projectionHeight);
|
int my = static_cast<int>(event.tfinger.y * Environment::projectionHeight);
|
||||||
handleUp(mx, my);
|
handleUp(static_cast<int64_t>(event.tfinger.fingerId), mx, my);
|
||||||
}
|
}
|
||||||
else if (event.type == SDL_FINGERMOTION) {
|
else if (event.type == SDL_FINGERMOTION) {
|
||||||
int mx = static_cast<int>(event.tfinger.x * Environment::projectionWidth);
|
int mx = static_cast<int>(event.tfinger.x * Environment::projectionWidth);
|
||||||
int my = static_cast<int>(event.tfinger.y * Environment::projectionHeight);
|
int my = static_cast<int>(event.tfinger.y * Environment::projectionHeight);
|
||||||
handleMotion(mx, my);
|
handleMotion(static_cast<int64_t>(event.tfinger.fingerId), mx, my);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
// Emscripten on mobile browser: handle real touch events with per-finger IDs.
|
||||||
|
// SDL_HINT_TOUCH_MOUSE_EVENTS="0" is set in main.cpp so these don't
|
||||||
|
// also fire SDL_MOUSEBUTTONDOWN, preventing double-processing.
|
||||||
|
#ifdef EMSCRIPTEN
|
||||||
|
if (event.type == SDL_FINGERDOWN) {
|
||||||
|
int mx = static_cast<int>(event.tfinger.x * Environment::projectionWidth);
|
||||||
|
int my = static_cast<int>(event.tfinger.y * Environment::projectionHeight);
|
||||||
|
handleDown(static_cast<int64_t>(event.tfinger.fingerId), mx, my);
|
||||||
|
//std::cout << "Finger down: id=" << event.tfinger.fingerId << " x=" << mx << " y=" << my << std::endl;
|
||||||
|
}
|
||||||
|
else if (event.type == SDL_FINGERUP) {
|
||||||
|
int mx = static_cast<int>(event.tfinger.x * Environment::projectionWidth);
|
||||||
|
int my = static_cast<int>(event.tfinger.y * Environment::projectionHeight);
|
||||||
|
handleUp(static_cast<int64_t>(event.tfinger.fingerId), mx, my);
|
||||||
|
//std::cout << "Finger up: id=" << event.tfinger.fingerId << " x=" << mx << " y=" << my << std::endl;
|
||||||
|
}
|
||||||
|
else if (event.type == SDL_FINGERMOTION) {
|
||||||
|
int mx = static_cast<int>(event.tfinger.x * Environment::projectionWidth);
|
||||||
|
int my = static_cast<int>(event.tfinger.y * Environment::projectionHeight);
|
||||||
|
handleMotion(static_cast<int64_t>(event.tfinger.fingerId), mx, my);
|
||||||
|
//std::cout << "Finger motion: id=" << event.tfinger.fingerId << " x=" << mx << " y=" << my << std::endl;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (event.type == SDL_MOUSEBUTTONDOWN || event.type == SDL_MOUSEBUTTONUP) {
|
if (event.type == SDL_MOUSEBUTTONDOWN || event.type == SDL_MOUSEBUTTONUP) {
|
||||||
// Преобразуем экранные пиксели в проекционные единицы
|
// Преобразуем экранные пиксели в проекционные единицы
|
||||||
int mx = static_cast<int>((float)event.button.x / Environment::width * Environment::projectionWidth);
|
int mx = static_cast<int>((float)event.button.x / Environment::width * Environment::projectionWidth);
|
||||||
int my = static_cast<int>((float)event.button.y / Environment::height * Environment::projectionHeight);
|
int my = static_cast<int>((float)event.button.y / Environment::height * Environment::projectionHeight);
|
||||||
|
|
||||||
if (event.type == SDL_MOUSEBUTTONDOWN) handleDown(mx, my);
|
if (event.type == SDL_MOUSEBUTTONDOWN) handleDown(ZL::UiManager::MOUSE_FINGER_ID, mx, my);
|
||||||
else handleUp(mx, my);
|
else handleUp(ZL::UiManager::MOUSE_FINGER_ID, mx, my);
|
||||||
|
//std::cout << "Mouse button " << (event.type == SDL_MOUSEBUTTONDOWN ? "down" : "up") << ": x=" << mx << " y=" << my << std::endl;
|
||||||
}
|
}
|
||||||
else if (event.type == SDL_MOUSEMOTION) {
|
else if (event.type == SDL_MOUSEMOTION) {
|
||||||
int mx = static_cast<int>((float)event.motion.x / Environment::width * Environment::projectionWidth);
|
int mx = static_cast<int>((float)event.motion.x / Environment::width * Environment::projectionWidth);
|
||||||
int my = static_cast<int>((float)event.motion.y / Environment::height * Environment::projectionHeight);
|
int my = static_cast<int>((float)event.motion.y / Environment::height * Environment::projectionHeight);
|
||||||
handleMotion(mx, my);
|
handleMotion(ZL::UiManager::MOUSE_FINGER_ID, mx, my);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*if (event.type == SDL_MOUSEBUTTONDOWN) {
|
/*if (event.type == SDL_MOUSEBUTTONDOWN) {
|
||||||
@ -507,62 +530,53 @@ namespace ZL
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::handleDown(int mx, int my)
|
void Game::handleDown(int64_t fingerId, int mx, int my)
|
||||||
{
|
{
|
||||||
int uiX = mx;
|
int uiX = mx;
|
||||||
int uiY = Environment::projectionHeight - my;
|
int uiY = Environment::projectionHeight - my;
|
||||||
|
|
||||||
menuManager.uiManager.onMouseDown(uiX, uiY);
|
menuManager.uiManager.onTouchDown(fingerId, uiX, uiY);
|
||||||
|
|
||||||
bool uiHandled = false;
|
if (!menuManager.uiManager.isUiInteractionForFinger(fingerId)) {
|
||||||
|
|
||||||
for (const auto& button : menuManager.uiManager.findButton("") ? std::vector<std::shared_ptr<UiButton>>{} : std::vector<std::shared_ptr<UiButton>>{}) {
|
|
||||||
(void)button;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto pressedSlider = [&]() -> std::shared_ptr<UiSlider> {
|
|
||||||
for (const auto& slider : menuManager.uiManager.findSlider("") ? std::vector<std::shared_ptr<UiSlider>>{} : std::vector<std::shared_ptr<UiSlider>>{}) {
|
|
||||||
(void)slider;
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}();
|
|
||||||
|
|
||||||
if (!menuManager.uiManager.isUiInteraction()) {
|
|
||||||
if (menuManager.shouldRenderSpace()) {
|
if (menuManager.shouldRenderSpace()) {
|
||||||
space.handleDown(mx, my);
|
space.handleDown(mx, my);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::handleUp(int mx, int my)
|
void Game::handleUp(int64_t fingerId, int mx, int my)
|
||||||
{
|
{
|
||||||
int uiX = mx;
|
int uiX = mx;
|
||||||
int uiY = Environment::projectionHeight - my;
|
int uiY = Environment::projectionHeight - my;
|
||||||
|
|
||||||
menuManager.uiManager.onMouseUp(uiX, uiY);
|
// Check BEFORE onTouchUp erases the finger from the map.
|
||||||
|
// If this finger started on a UI element, don't notify space —
|
||||||
|
// otherwise space would think the ship-control finger was released.
|
||||||
|
bool wasUiInteraction = menuManager.uiManager.isUiInteractionForFinger(fingerId);
|
||||||
|
menuManager.uiManager.onTouchUp(fingerId, uiX, uiY);
|
||||||
|
|
||||||
if (!menuManager.uiManager.isUiInteraction()) {
|
if (!wasUiInteraction) {
|
||||||
if (menuManager.shouldRenderSpace()) {
|
if (menuManager.shouldRenderSpace()) {
|
||||||
space.handleUp(mx, my);
|
space.handleUp(mx, my);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::handleMotion(int mx, int my)
|
void Game::handleMotion(int64_t fingerId, int mx, int my)
|
||||||
{
|
{
|
||||||
int uiX = mx;
|
int uiX = mx;
|
||||||
int uiY = Environment::projectionHeight - my;
|
int uiY = Environment::projectionHeight - my;
|
||||||
|
|
||||||
menuManager.uiManager.onMouseMove(uiX, uiY);
|
// Check before onTouchMove so the "started on UI" state is preserved
|
||||||
|
// regardless of what onTouchMove does internally.
|
||||||
|
bool wasUiInteraction = menuManager.uiManager.isUiInteractionForFinger(fingerId);
|
||||||
|
menuManager.uiManager.onTouchMove(fingerId, uiX, uiY);
|
||||||
|
|
||||||
if (!menuManager.uiManager.isUiInteraction()) {
|
if (!wasUiInteraction) {
|
||||||
if (menuManager.shouldRenderSpace()) {
|
if (menuManager.shouldRenderSpace()) {
|
||||||
space.handleMotion(mx, my);
|
space.handleMotion(mx, my);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -13,6 +13,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <cstdint>
|
||||||
#include <render/TextRenderer.h>
|
#include <render/TextRenderer.h>
|
||||||
#include "MenuManager.h"
|
#include "MenuManager.h"
|
||||||
#include "Space.h"
|
#include "Space.h"
|
||||||
@ -50,9 +51,9 @@ namespace ZL {
|
|||||||
void drawUI();
|
void drawUI();
|
||||||
void drawUnderMainMenu();
|
void drawUnderMainMenu();
|
||||||
void drawLoading();
|
void drawLoading();
|
||||||
void handleDown(int mx, int my);
|
void handleDown(int64_t fingerId, int mx, int my);
|
||||||
void handleUp(int mx, int my);
|
void handleUp(int64_t fingerId, int mx, int my);
|
||||||
void handleMotion(int mx, int my);
|
void handleMotion(int64_t fingerId, int mx, int my);
|
||||||
|
|
||||||
#ifdef EMSCRIPTEN
|
#ifdef EMSCRIPTEN
|
||||||
static Game* s_instance;
|
static Game* s_instance;
|
||||||
|
|||||||
@ -143,18 +143,18 @@ namespace ZL {
|
|||||||
|
|
||||||
uiManager.startAnimationOnNode("backgroundNode", "bgScroll");
|
uiManager.startAnimationOnNode("backgroundNode", "bgScroll");
|
||||||
|
|
||||||
uiManager.setButtonCallback("shootButton", [this](const std::string&) {
|
uiManager.setButtonPressCallback("shootButton", [this](const std::string&) {
|
||||||
if (onFirePressed) onFirePressed();
|
if (onFirePressed) onFirePressed();
|
||||||
});
|
});
|
||||||
uiManager.setButtonCallback("shootButton2", [this](const std::string&) {
|
uiManager.setButtonPressCallback("shootButton2", [this](const std::string&) {
|
||||||
if (onFirePressed) onFirePressed();
|
if (onFirePressed) onFirePressed();
|
||||||
});
|
});
|
||||||
uiManager.setButtonCallback("plusButton", [this](const std::string&) {
|
uiManager.setButtonPressCallback("plusButton", [this](const std::string&) {
|
||||||
int newVel = Environment::shipState.selectedVelocity + 1;
|
int newVel = Environment::shipState.selectedVelocity + 1;
|
||||||
if (newVel > 4) newVel = 4;
|
if (newVel > 4) newVel = 4;
|
||||||
if (onVelocityChanged) onVelocityChanged(newVel);
|
if (onVelocityChanged) onVelocityChanged(newVel);
|
||||||
});
|
});
|
||||||
uiManager.setButtonCallback("minusButton", [this](const std::string&) {
|
uiManager.setButtonPressCallback("minusButton", [this](const std::string&) {
|
||||||
int newVel = Environment::shipState.selectedVelocity - 1;
|
int newVel = Environment::shipState.selectedVelocity - 1;
|
||||||
if (newVel < 0) newVel = 0;
|
if (newVel < 0) newVel = 0;
|
||||||
if (onVelocityChanged) onVelocityChanged(newVel);
|
if (onVelocityChanged) onVelocityChanged(newVel);
|
||||||
|
|||||||
@ -769,6 +769,16 @@ namespace ZL {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool UiManager::setButtonPressCallback(const std::string& name, std::function<void(const std::string&)> cb) {
|
||||||
|
auto b = findButton(name);
|
||||||
|
if (!b) {
|
||||||
|
std::cerr << "UiManager: setButtonPressCallback failed, button not found: " << name << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
b->onPress = std::move(cb);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool UiManager::addSlider(const std::string& name, const UiRect& rect, Renderer& renderer, const std::string& zipFile,
|
bool UiManager::addSlider(const std::string& name, const UiRect& rect, Renderer& renderer, const std::string& zipFile,
|
||||||
const std::string& trackPath, const std::string& knobPath, float initialValue, bool vertical) {
|
const std::string& trackPath, const std::string& knobPath, float initialValue, bool vertical) {
|
||||||
|
|
||||||
@ -855,8 +865,8 @@ namespace ZL {
|
|||||||
prev.sliders = sliders;
|
prev.sliders = sliders;
|
||||||
prev.textFields = textFields;
|
prev.textFields = textFields;
|
||||||
prev.staticImages = staticImages;
|
prev.staticImages = staticImages;
|
||||||
prev.pressedButton = pressedButton;
|
prev.pressedButtons = pressedButtons;
|
||||||
prev.pressedSlider = pressedSlider;
|
prev.pressedSliders = pressedSliders;
|
||||||
prev.focusedTextField = focusedTextField;
|
prev.focusedTextField = focusedTextField;
|
||||||
prev.path = "";
|
prev.path = "";
|
||||||
|
|
||||||
@ -906,8 +916,8 @@ namespace ZL {
|
|||||||
sliders = s.sliders;
|
sliders = s.sliders;
|
||||||
textFields = s.textFields;
|
textFields = s.textFields;
|
||||||
staticImages = s.staticImages;
|
staticImages = s.staticImages;
|
||||||
pressedButton = s.pressedButton;
|
pressedButtons = s.pressedButtons;
|
||||||
pressedSlider = s.pressedSlider;
|
pressedSliders = s.pressedSliders;
|
||||||
focusedTextField = s.focusedTextField;
|
focusedTextField = s.focusedTextField;
|
||||||
|
|
||||||
animCallbacks = s.animCallbacks;
|
animCallbacks = s.animCallbacks;
|
||||||
@ -1122,21 +1132,25 @@ namespace ZL {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UiManager::onMouseMove(int x, int y) {
|
void UiManager::onTouchMove(int64_t fingerId, int x, int y) {
|
||||||
for (auto& b : buttons) {
|
// Hover state updates only make sense for mouse (single pointer)
|
||||||
if (b->state != ButtonState::Disabled)
|
if (fingerId == MOUSE_FINGER_ID) {
|
||||||
{
|
for (auto& b : buttons) {
|
||||||
if (b->rect.containsConsideringBorder((float)x, (float)y, b->border)) {
|
if (b->state != ButtonState::Disabled)
|
||||||
if (b->state != ButtonState::Pressed) b->state = ButtonState::Hover;
|
{
|
||||||
}
|
if (b->rect.containsConsideringBorder((float)x, (float)y, b->border)) {
|
||||||
else {
|
if (b->state != ButtonState::Pressed) b->state = ButtonState::Hover;
|
||||||
if (b->state != ButtonState::Pressed) b->state = ButtonState::Normal;
|
}
|
||||||
|
else {
|
||||||
|
if (b->state != ButtonState::Pressed) b->state = ButtonState::Normal;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pressedSlider) {
|
auto it = pressedSliders.find(fingerId);
|
||||||
auto s = pressedSlider;
|
if (it != pressedSliders.end()) {
|
||||||
|
auto s = it->second;
|
||||||
float t;
|
float t;
|
||||||
if (s->vertical) {
|
if (s->vertical) {
|
||||||
t = (y - s->rect.y) / s->rect.h;
|
t = (y - s->rect.y) / s->rect.h;
|
||||||
@ -1153,20 +1167,22 @@ namespace ZL {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void UiManager::onMouseDown(int x, int y) {
|
void UiManager::onTouchDown(int64_t fingerId, int x, int y) {
|
||||||
for (auto& b : buttons) {
|
for (auto& b : buttons) {
|
||||||
if (b->state != ButtonState::Disabled)
|
if (b->state != ButtonState::Disabled)
|
||||||
{
|
{
|
||||||
if (b->rect.containsConsideringBorder((float)x, (float)y, b->border)) {
|
if (b->rect.containsConsideringBorder((float)x, (float)y, b->border)) {
|
||||||
b->state = ButtonState::Pressed;
|
b->state = ButtonState::Pressed;
|
||||||
pressedButton = b;
|
pressedButtons[fingerId] = b;
|
||||||
|
if (b->onPress) b->onPress(b->name);
|
||||||
|
break; // a single finger can only press one button
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& s : sliders) {
|
for (auto& s : sliders) {
|
||||||
if (s->rect.contains((float)x, (float)y)) {
|
if (s->rect.contains((float)x, (float)y)) {
|
||||||
pressedSlider = s;
|
pressedSliders[fingerId] = s;
|
||||||
float t;
|
float t;
|
||||||
if (s->vertical) {
|
if (s->vertical) {
|
||||||
t = (y - s->rect.y) / s->rect.h;
|
t = (y - s->rect.y) / s->rect.h;
|
||||||
@ -1194,29 +1210,32 @@ namespace ZL {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UiManager::onMouseUp(int x, int y) {
|
void UiManager::onTouchUp(int64_t fingerId, int x, int y) {
|
||||||
std::vector<std::shared_ptr<UiButton>> clicked;
|
std::vector<std::shared_ptr<UiButton>> clicked;
|
||||||
|
|
||||||
for (auto& b : buttons) {
|
auto btnIt = pressedButtons.find(fingerId);
|
||||||
if (!b) continue;
|
if (btnIt != pressedButtons.end()) {
|
||||||
bool contains = b->rect.contains((float)x, (float)y);
|
auto b = btnIt->second;
|
||||||
|
if (b) {
|
||||||
if (b->state == ButtonState::Pressed) {
|
bool contains = b->rect.contains((float)x, (float)y);
|
||||||
if (contains && pressedButton == b) {
|
if (b->state == ButtonState::Pressed) {
|
||||||
clicked.push_back(b);
|
if (contains) {
|
||||||
|
clicked.push_back(b);
|
||||||
|
}
|
||||||
|
// On mouse: leave Hover if still over button. On touch: always Normal.
|
||||||
|
b->state = (contains && fingerId == MOUSE_FINGER_ID) ? ButtonState::Hover : ButtonState::Normal;
|
||||||
}
|
}
|
||||||
b->state = contains ? ButtonState::Hover : ButtonState::Normal;
|
|
||||||
}
|
}
|
||||||
|
pressedButtons.erase(btnIt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pressedSliders.erase(fingerId);
|
||||||
|
|
||||||
for (auto& b : clicked) {
|
for (auto& b : clicked) {
|
||||||
if (b->onClick) {
|
if (b->onClick) {
|
||||||
b->onClick(b->name);
|
b->onClick(b->name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pressedButton.reset();
|
|
||||||
if (pressedSlider) pressedSlider.reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void UiManager::onKeyPress(unsigned char key) {
|
void UiManager::onKeyPress(unsigned char key) {
|
||||||
|
|||||||
@ -10,6 +10,7 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
namespace ZL {
|
namespace ZL {
|
||||||
|
|
||||||
@ -93,6 +94,7 @@ namespace ZL {
|
|||||||
VertexRenderStruct mesh;
|
VertexRenderStruct mesh;
|
||||||
|
|
||||||
std::function<void(const std::string&)> onClick;
|
std::function<void(const std::string&)> onClick;
|
||||||
|
std::function<void(const std::string&)> onPress; // fires on touch/mouse down
|
||||||
|
|
||||||
// animation runtime
|
// animation runtime
|
||||||
float animOffsetX = 0.0f;
|
float animOffsetX = 0.0f;
|
||||||
@ -224,19 +226,35 @@ namespace ZL {
|
|||||||
public:
|
public:
|
||||||
UiManager() = default;
|
UiManager() = default;
|
||||||
|
|
||||||
|
// Sentinel finger ID used for mouse events on desktop/web
|
||||||
|
static constexpr int64_t MOUSE_FINGER_ID = -1LL;
|
||||||
|
|
||||||
void replaceRoot(std::shared_ptr<UiNode> newRoot);
|
void replaceRoot(std::shared_ptr<UiNode> newRoot);
|
||||||
void loadFromFile(const std::string& path, Renderer& renderer, const std::string& zipFile = "");
|
void loadFromFile(const std::string& path, Renderer& renderer, const std::string& zipFile = "");
|
||||||
|
|
||||||
void draw(Renderer& renderer);
|
void draw(Renderer& renderer);
|
||||||
|
|
||||||
void onMouseMove(int x, int y);
|
// Multi-touch methods (used directly for touch events with per-finger IDs)
|
||||||
void onMouseDown(int x, int y);
|
void onTouchDown(int64_t fingerId, int x, int y);
|
||||||
void onMouseUp(int x, int y);
|
void onTouchUp(int64_t fingerId, int x, int y);
|
||||||
|
void onTouchMove(int64_t fingerId, int x, int y);
|
||||||
|
|
||||||
|
// Mouse convenience wrappers (delegate to touch with MOUSE_FINGER_ID)
|
||||||
|
void onMouseMove(int x, int y) { onTouchMove(MOUSE_FINGER_ID, x, y); }
|
||||||
|
void onMouseDown(int x, int y) { onTouchDown(MOUSE_FINGER_ID, x, y); }
|
||||||
|
void onMouseUp(int x, int y) { onTouchUp(MOUSE_FINGER_ID, x, y); }
|
||||||
|
|
||||||
void onKeyPress(unsigned char key);
|
void onKeyPress(unsigned char key);
|
||||||
void onKeyBackspace();
|
void onKeyBackspace();
|
||||||
|
|
||||||
|
// Returns true if any finger is currently interacting with UI
|
||||||
bool isUiInteraction() const {
|
bool isUiInteraction() const {
|
||||||
return pressedButton != nullptr || pressedSlider != nullptr || focusedTextField != nullptr;
|
return !pressedButtons.empty() || !pressedSliders.empty() || focusedTextField != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if this specific finger is currently interacting with UI
|
||||||
|
bool isUiInteractionForFinger(int64_t fingerId) const {
|
||||||
|
return pressedButtons.count(fingerId) > 0 || pressedSliders.count(fingerId) > 0 || focusedTextField != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void stopAllAnimations() {
|
void stopAllAnimations() {
|
||||||
@ -255,6 +273,7 @@ namespace ZL {
|
|||||||
std::shared_ptr<UiButton> findButton(const std::string& name);
|
std::shared_ptr<UiButton> findButton(const std::string& name);
|
||||||
|
|
||||||
bool setButtonCallback(const std::string& name, std::function<void(const std::string&)> cb);
|
bool setButtonCallback(const std::string& name, std::function<void(const std::string&)> cb);
|
||||||
|
bool setButtonPressCallback(const std::string& name, std::function<void(const std::string&)> cb);
|
||||||
|
|
||||||
bool addSlider(const std::string& name, const UiRect& rect, Renderer& renderer, const std::string& zipFile,
|
bool addSlider(const std::string& name, const UiRect& rect, Renderer& renderer, const std::string& zipFile,
|
||||||
const std::string& trackPath, const std::string& knobPath, float initialValue = 0.0f, bool vertical = true);
|
const std::string& trackPath, const std::string& knobPath, float initialValue = 0.0f, bool vertical = true);
|
||||||
@ -322,8 +341,9 @@ namespace ZL {
|
|||||||
std::map<std::shared_ptr<UiNode>, std::vector<ActiveAnim>> nodeActiveAnims;
|
std::map<std::shared_ptr<UiNode>, std::vector<ActiveAnim>> nodeActiveAnims;
|
||||||
std::map<std::pair<std::string, std::string>, std::function<void()>> animCallbacks; // key: (nodeName, animName)
|
std::map<std::pair<std::string, std::string>, std::function<void()>> animCallbacks; // key: (nodeName, animName)
|
||||||
|
|
||||||
std::shared_ptr<UiButton> pressedButton;
|
// Per-finger tracking for multi-touch support
|
||||||
std::shared_ptr<UiSlider> pressedSlider;
|
std::map<int64_t, std::shared_ptr<UiButton>> pressedButtons;
|
||||||
|
std::map<int64_t, std::shared_ptr<UiSlider>> pressedSliders;
|
||||||
std::shared_ptr<UiTextField> focusedTextField;
|
std::shared_ptr<UiTextField> focusedTextField;
|
||||||
|
|
||||||
struct MenuState {
|
struct MenuState {
|
||||||
@ -332,8 +352,8 @@ namespace ZL {
|
|||||||
std::vector<std::shared_ptr<UiSlider>> sliders;
|
std::vector<std::shared_ptr<UiSlider>> sliders;
|
||||||
std::vector<std::shared_ptr<UiTextField>> textFields;
|
std::vector<std::shared_ptr<UiTextField>> textFields;
|
||||||
std::vector<std::shared_ptr<UiStaticImage>> staticImages;
|
std::vector<std::shared_ptr<UiStaticImage>> staticImages;
|
||||||
std::shared_ptr<UiButton> pressedButton;
|
std::map<int64_t, std::shared_ptr<UiButton>> pressedButtons;
|
||||||
std::shared_ptr<UiSlider> pressedSlider;
|
std::map<int64_t, std::shared_ptr<UiSlider>> pressedSliders;
|
||||||
std::shared_ptr<UiTextField> focusedTextField;
|
std::shared_ptr<UiTextField> focusedTextField;
|
||||||
std::string path;
|
std::string path;
|
||||||
std::map<std::pair<std::string, std::string>, std::function<void()>> animCallbacks;
|
std::map<std::pair<std::string, std::string>, std::function<void()>> animCallbacks;
|
||||||
|
|||||||
@ -127,7 +127,11 @@ int main(int argc, char* argv[]) {
|
|||||||
// канваса и отправит SDL_WINDOWEVENT_RESIZED для настройки проекции.
|
// канваса и отправит SDL_WINDOWEVENT_RESIZED для настройки проекции.
|
||||||
applyResize(canvasW, canvasH);
|
applyResize(canvasW, canvasH);
|
||||||
|
|
||||||
|
// Prevent mouse clicks from generating fake SDL_FINGERDOWN events (desktop browser)
|
||||||
SDL_SetHint(SDL_HINT_MOUSE_TOUCH_EVENTS, "0");
|
SDL_SetHint(SDL_HINT_MOUSE_TOUCH_EVENTS, "0");
|
||||||
|
// Prevent touch events from generating fake SDL_MOUSEBUTTONDOWN events (mobile browser),
|
||||||
|
// since we now handle SDL_FINGERDOWN directly for multi-touch support.
|
||||||
|
SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0");
|
||||||
|
|
||||||
emscripten_set_main_loop(MainLoop, 0, 1);
|
emscripten_set_main_loop(MainLoop, 0, 1);
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user