ADD: ClickableUiComponent
This commit is contained in:
parent
16b4747175
commit
a8c8e1770c
@ -236,6 +236,12 @@ add_executable(Dicewars_Siedler src/main.cpp
|
||||
src/engine/core/inputsOutputs/stateControl/inputUser/GameInputUser.h
|
||||
src/engine/core/inputsOutputs/stateControl/StateRegistry.cpp
|
||||
src/engine/core/inputsOutputs/stateControl/StateRegistry.h
|
||||
src/engine/core/gui/uiComponent/ClickableUiComponent.cpp
|
||||
src/engine/core/gui/uiComponent/ClickableUiComponent.h
|
||||
src/engine/core/inputsOutputs/stateControl/inputUser/UiInputUser.cpp
|
||||
src/engine/core/inputsOutputs/stateControl/inputUser/UiInputUser.h
|
||||
src/engine/core/gui/uiComponent/EventData.cpp
|
||||
src/engine/core/gui/uiComponent/EventData.h
|
||||
)
|
||||
|
||||
target_compile_options(Dicewars_Siedler PRIVATE
|
||||
|
||||
@ -50,12 +50,13 @@ Application::~Application()
|
||||
void Application::run() {
|
||||
while (!window->shouldClose())
|
||||
{
|
||||
window->OnUpdate();
|
||||
updateTime();
|
||||
for (Layer* layer : layers)
|
||||
{
|
||||
layer->onUpdate();
|
||||
}
|
||||
window->OnUpdate();
|
||||
|
||||
InputManager::update();
|
||||
|
||||
mouse->update();
|
||||
|
||||
64
src/engine/core/gui/uiComponent/ClickableUiComponent.cpp
Normal file
64
src/engine/core/gui/uiComponent/ClickableUiComponent.cpp
Normal file
@ -0,0 +1,64 @@
|
||||
//
|
||||
// Created by sebastian on 15.02.26.
|
||||
//
|
||||
|
||||
#include "ClickableUiComponent.h"
|
||||
|
||||
#include "../../Application.h"
|
||||
|
||||
void ClickableUiComponent::checkMouseOver() {
|
||||
glm::vec2 mousepos = Application::getInstance().mouse->getXY();
|
||||
bool mouseOverStatus = UiComponent::isMouseOver(mousepos.x, mousepos.y);
|
||||
if (this->mousedOver != mouseOverStatus) {
|
||||
mouseOver(mouseOverStatus);
|
||||
}
|
||||
}
|
||||
|
||||
void ClickableUiComponent::checkClicks() {
|
||||
checkMouseButton(MouseButton::LEFT, *Application::getInstance().mouse);
|
||||
checkMouseButton(MouseButton::RIGHT, *Application::getInstance().mouse);
|
||||
checkMouseButton(MouseButton::MIDDLE, *Application::getInstance().mouse);
|
||||
}
|
||||
|
||||
void ClickableUiComponent::checkMouseButton(MouseButton button, Mouse &mouse) {
|
||||
if (Application::getInstance().mouse->isClickEvent(button)) {
|
||||
click(button, true);
|
||||
} else if (Application::getInstance().mouse->isReleaseEvent(button)) {
|
||||
click(button, false);
|
||||
}
|
||||
}
|
||||
|
||||
void ClickableUiComponent::onUpdate(float dt) {
|
||||
if (blocked) return;
|
||||
|
||||
checkMouseOver();
|
||||
if (mousedOver) {
|
||||
checkClicks();
|
||||
} else {
|
||||
applyCurrentStyle(UiEventType::NONE);
|
||||
}
|
||||
}
|
||||
|
||||
void ClickableUiComponent::mouseOver(bool newMouseOverState) {
|
||||
this->mousedOver = newMouseOverState;
|
||||
// Todo: When complex animation system is integrated, triggering of animation starts here
|
||||
applyCurrentStyle(UiEventType::MOUSE_OVER);
|
||||
MouseEventData mouse_event_data = MouseEventData(std::nullopt, mousedOver);
|
||||
fireEvent(mouse_event_data);
|
||||
}
|
||||
|
||||
void ClickableUiComponent::click(MouseButton button, bool buttonDown) {
|
||||
if (buttonDown) {
|
||||
applyCurrentStyle(UiEventType::MOUSE_CLICK);
|
||||
} else {
|
||||
applyCurrentStyle(UiEventType::NONE);
|
||||
}
|
||||
fireEvent(MouseEventData(button, buttonDown));
|
||||
}
|
||||
|
||||
void ClickableUiComponent::applyCurrentStyle(UiEventType eventType) {
|
||||
if (visualStyles.contains(eventType)) {
|
||||
currentVisualStyle = visualStyles.at(eventType);
|
||||
}
|
||||
|
||||
}
|
||||
62
src/engine/core/gui/uiComponent/ClickableUiComponent.h
Normal file
62
src/engine/core/gui/uiComponent/ClickableUiComponent.h
Normal file
@ -0,0 +1,62 @@
|
||||
//
|
||||
// Created by sebastian on 15.02.26.
|
||||
//
|
||||
|
||||
#ifndef DICEWARS_SIEDLER_CLICKABLEUICOMPONENT_H
|
||||
#define DICEWARS_SIEDLER_CLICKABLEUICOMPONENT_H
|
||||
#include "EventData.h"
|
||||
#include "UiComponent.h"
|
||||
|
||||
struct VisualStyle {
|
||||
float brightness = 1.0f;
|
||||
glm::vec3 tintColor = glm::vec3(0.0f);
|
||||
float tintStrength = 0.0f;
|
||||
};
|
||||
|
||||
enum class UiEventType {
|
||||
MOUSE_OVER,
|
||||
MOUSE_CLICK,
|
||||
NONE
|
||||
};
|
||||
|
||||
class Mouse;
|
||||
|
||||
class ClickableUiComponent : public UiComponent {
|
||||
public:
|
||||
using MouseCallback = std::function<void(const MouseEventData&)>;
|
||||
ClickableUiComponent(const LayoutStyle &style) : UiComponent(style) {};
|
||||
|
||||
void addMouseListener(MouseCallback callback) {
|
||||
mouseListeners.push_back(std::move(callback));
|
||||
}
|
||||
|
||||
void fireEvent(const MouseEventData& event) {
|
||||
for (auto& listener: mouseListeners) {
|
||||
listener(event);
|
||||
}
|
||||
}
|
||||
|
||||
void setVisualStyle(UiEventType eventType, const VisualStyle& style) {
|
||||
visualStyles[eventType] = style;
|
||||
}
|
||||
private:
|
||||
std::vector<MouseCallback> mouseListeners;
|
||||
bool blocked = false;
|
||||
bool mousedOver = false;
|
||||
|
||||
void checkMouseOver();
|
||||
void checkClicks();
|
||||
void checkMouseButton(MouseButton button, Mouse& mouse);
|
||||
protected:
|
||||
void onUpdate(float dt) override;
|
||||
void mouseOver(bool newMouseOverState);
|
||||
void click(MouseButton button, bool buttonDown);
|
||||
|
||||
VisualStyle currentVisualStyle; // für Rendering
|
||||
std::unordered_map<UiEventType, VisualStyle> visualStyles;
|
||||
|
||||
void applyCurrentStyle(UiEventType eventType);
|
||||
};
|
||||
|
||||
|
||||
#endif //DICEWARS_SIEDLER_CLICKABLEUICOMPONENT_H
|
||||
5
src/engine/core/gui/uiComponent/EventData.cpp
Normal file
5
src/engine/core/gui/uiComponent/EventData.cpp
Normal file
@ -0,0 +1,5 @@
|
||||
//
|
||||
// Created by sebastian on 15.02.26.
|
||||
//
|
||||
|
||||
#include "EventData.h"
|
||||
39
src/engine/core/gui/uiComponent/EventData.h
Normal file
39
src/engine/core/gui/uiComponent/EventData.h
Normal file
@ -0,0 +1,39 @@
|
||||
//
|
||||
// Created by sebastian on 15.02.26.
|
||||
//
|
||||
|
||||
#ifndef DICEWARS_SIEDLER_EVENTDATA_H
|
||||
#define DICEWARS_SIEDLER_EVENTDATA_H
|
||||
|
||||
|
||||
enum class MouseButton;
|
||||
|
||||
#include <optional>
|
||||
|
||||
struct MouseEventData {
|
||||
std::optional<MouseButton> button;
|
||||
bool eventState;
|
||||
|
||||
MouseEventData(std::optional<MouseButton> btn, bool state)
|
||||
: button(btn), eventState(state) {}
|
||||
|
||||
bool isClick(MouseButton btn) const {
|
||||
return eventState && button.has_value() && button.value() == btn;
|
||||
}
|
||||
|
||||
bool isCompleteClick(MouseButton btn) const {
|
||||
return !eventState && button.has_value() && button.value() == btn;
|
||||
}
|
||||
|
||||
bool isMouseOver() const {
|
||||
return eventState && !button.has_value();
|
||||
}
|
||||
|
||||
bool isMouseOff() const {
|
||||
return !eventState && !button.has_value();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif //DICEWARS_SIEDLER_EVENTDATA_H
|
||||
@ -8,20 +8,17 @@
|
||||
|
||||
#include "UiText.h"
|
||||
|
||||
UiButton::UiButton(const GLuint textureID, std::string label, Font &font, const LayoutStyle &style): textureID(textureID), text(std::move(label)), font(font), UiComponent(style) {
|
||||
}
|
||||
|
||||
void UiButton::onClick() {
|
||||
if (clickListener) {
|
||||
clickListener();
|
||||
}
|
||||
UiButton::UiButton(const GLuint textureID, std::string label, Font &font, const LayoutStyle &style): ClickableUiComponent(style), text(std::move(label)), font(font), textureID(textureID) {
|
||||
visualStyles[UiEventType::NONE] = {1.0f, glm::vec3(0.0f), 0.0f};
|
||||
visualStyles[UiEventType::MOUSE_OVER] = {1.15f, glm::vec3(0.0f), 0.0f};
|
||||
visualStyles[UiEventType::MOUSE_CLICK] = {1.0f, glm::vec3(0.3f, 0.6f, 1.0f), 0.15f};
|
||||
}
|
||||
|
||||
void UiButton::onCollectRenderData(UiRenderBundle &uiRenderBundle) {
|
||||
glm::vec2 position = glm::vec2(uiPositioner.screenSpace.x, uiPositioner.screenSpace.y);
|
||||
glm::vec2 size = glm::vec2(uiPositioner.screenSpace.width, uiPositioner.screenSpace.height);
|
||||
|
||||
VisualStyle visualStyle = getVisualStyle();
|
||||
VisualStyle visualStyle = currentVisualStyle;
|
||||
|
||||
GUITextureBuilder textureBuilder;
|
||||
textureBuilder = textureBuilder.Foreground(textureID);
|
||||
@ -35,14 +32,3 @@ void UiButton::onCollectRenderData(UiRenderBundle &uiRenderBundle) {
|
||||
|
||||
uiRenderBundle.addGUIText(std::make_shared<GUIText>(font, text, uiPositioner.screenSpace));
|
||||
}
|
||||
|
||||
VisualStyle UiButton::getVisualStyle() const {
|
||||
switch (state) {
|
||||
case UiElementState::PRESSED:
|
||||
return {1.0f, glm::vec3(0.3, 0.6, 1.0), 0.15f};
|
||||
case UiElementState::HOVERED:
|
||||
return {1.15f, glm::vec3(0.0f), 0.0f};
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,25 +4,16 @@
|
||||
|
||||
#ifndef DICEWARS_SIEDLER_UIBUTTON_H
|
||||
#define DICEWARS_SIEDLER_UIBUTTON_H
|
||||
#include "ClickableUiComponent.h"
|
||||
#include "UiComponent.h"
|
||||
|
||||
struct VisualStyle {
|
||||
float brightness = 1.0f;
|
||||
glm::vec3 tintColor = glm::vec3(0.0f);
|
||||
float tintStrength = 0.0f;
|
||||
};
|
||||
|
||||
class Font;
|
||||
|
||||
class UiButton : public UiComponent{
|
||||
class UiButton : public ClickableUiComponent {
|
||||
public:
|
||||
UiButton(GLuint textureID, std::string label, Font& font, const LayoutStyle& style);
|
||||
void setOnClick(std::function<void()> callback) {
|
||||
printf("Clicklister added!\n");
|
||||
clickListener = std::move(callback);
|
||||
}
|
||||
|
||||
void onClick() override;
|
||||
protected:
|
||||
void onCollectRenderData(UiRenderBundle &uiRenderBundle) override;
|
||||
|
||||
@ -30,10 +21,6 @@ private:
|
||||
std::string text;
|
||||
Font& font;
|
||||
GLuint textureID;
|
||||
|
||||
VisualStyle getVisualStyle() const;
|
||||
|
||||
std::function<void()> clickListener;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -52,22 +52,6 @@ UiComponent* UiComponent::getChildAtIndex(size_t t) const {
|
||||
}
|
||||
|
||||
void UiComponent::onUpdate(float) {
|
||||
glm::vec2 mousePos = InputManager::getMousePositionNormalized();
|
||||
bool hoveredNow = isMouseOver(mousePos.x, mousePos.y);
|
||||
|
||||
bool pressedThisFrame = hoveredNow && InputManager::isMouseButtonPressed(GLFW_MOUSE_BUTTON_LEFT);
|
||||
bool releasedFrame = InputManager::isMouseButtonReleased(GLFW_MOUSE_BUTTON_LEFT);
|
||||
|
||||
if (pressedThisFrame) {
|
||||
state = UiElementState::PRESSED;
|
||||
} else if (releasedFrame) {
|
||||
if (state == UiElementState::PRESSED && hoveredNow) {
|
||||
onClick();
|
||||
}
|
||||
state = hoveredNow ? UiElementState::HOVERED : UiElementState::NORMAL;
|
||||
} else {
|
||||
if (state != UiElementState::PRESSED)
|
||||
state = hoveredNow ? UiElementState::HOVERED : UiElementState::NORMAL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -37,14 +37,11 @@ public:
|
||||
void setLayoutStyle(const LayoutStyle& style) {
|
||||
uiPositioner.setLayout(style);
|
||||
}
|
||||
|
||||
[[nodiscard]] bool isHovered() const { return state == UiElementState::HOVERED; }
|
||||
virtual void onClick() {};
|
||||
|
||||
UiComponent* getChildAtIndex(size_t t) const;
|
||||
protected:
|
||||
bool visible = true;
|
||||
UiElementState state = UiElementState::NORMAL;
|
||||
|
||||
virtual void onUpdate(float );
|
||||
virtual void onCollectRenderData(UiRenderBundle& uiRenderBundle) {}
|
||||
|
||||
@ -46,10 +46,16 @@ float Mouse::getScroll() {
|
||||
}
|
||||
|
||||
void Mouse::update() {
|
||||
buttonsClickedThisFrame.clear();
|
||||
buttonsReleasedThisFrame.clear();
|
||||
|
||||
updateDetlas();
|
||||
scroll = 0.0f;
|
||||
|
||||
buttonsClickedThisFrame.clear();
|
||||
buttonsReleasedThisFrame.clear();
|
||||
}
|
||||
|
||||
glm::vec2 Mouse::getXY() const {
|
||||
return {x, y};
|
||||
}
|
||||
|
||||
void Mouse::reportButtonClick(int button) {
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
#include <unordered_set>
|
||||
|
||||
#include "MouseButton.h"
|
||||
#include "glm/vec2.hpp"
|
||||
|
||||
class Window;
|
||||
|
||||
@ -22,6 +23,7 @@ public:
|
||||
float getDY();
|
||||
float getScroll();
|
||||
void update();
|
||||
glm::vec2 getXY() const;
|
||||
private:
|
||||
std::unordered_set<int> buttonsDown;
|
||||
std::unordered_set<int> buttonsClickedThisFrame;
|
||||
|
||||
@ -0,0 +1,5 @@
|
||||
//
|
||||
// Created by sebastian on 15.02.26.
|
||||
//
|
||||
|
||||
#include "UiInputUser.h"
|
||||
@ -0,0 +1,14 @@
|
||||
//
|
||||
// Created by sebastian on 15.02.26.
|
||||
//
|
||||
|
||||
#ifndef DICEWARS_SIEDLER_UIINPUTUSER_H
|
||||
#define DICEWARS_SIEDLER_UIINPUTUSER_H
|
||||
#include "../InputUser.h"
|
||||
|
||||
|
||||
class UiInputUser : public InputUser {
|
||||
};
|
||||
|
||||
|
||||
#endif //DICEWARS_SIEDLER_UIINPUTUSER_H
|
||||
@ -27,6 +27,7 @@ UILayer::UILayer() {
|
||||
Loader& loader = Loader::instance();
|
||||
guiRenderer = std::make_unique<GUIRenderer>(loader);
|
||||
textRenderer = std::make_unique<TextRenderer>();
|
||||
uiInputUser = std::make_unique<UiInputUser>();
|
||||
}
|
||||
|
||||
void UILayer::onAttach() {
|
||||
@ -94,8 +95,19 @@ void UILayer::onAttach() {
|
||||
auto minimap = std::make_unique<UiImage>(minimapTextureID, backgroundTextureID, minimapStyle);
|
||||
rootContainer->addChild(std::move(minimap));
|
||||
|
||||
float screenHeight = Application::getInstance().getWindow().GetHeight();
|
||||
float menuHeight = 200.f;
|
||||
LayoutStyle style;
|
||||
style.width = SizeValue(200, SizeUnit::Pixels);
|
||||
style.height = SizeValue(50.f, SizeUnit::Pixels);
|
||||
style.margin.top = {10.f, SizeUnit::Pixels};
|
||||
style.margin.left = {20.f, SizeUnit::Pixels};
|
||||
|
||||
auto uiButton = std::make_unique<UiButton>(AssetManager::getTexture("background")->getTextureID(), "Test", *font , style);
|
||||
uiButton->addMouseListener([](const MouseEventData& e) {
|
||||
if (e.isClick(MouseButton::LEFT)) {
|
||||
std::cout << "Button clicked!" << std::endl;
|
||||
}
|
||||
});
|
||||
rootContainer->addChild(std::move(uiButton));
|
||||
|
||||
auto buildingMenuContainer = std::make_unique<UiBuildingMenuContainer>();
|
||||
auto buildingMenuContainerContainer = std::make_unique<UiContainer>();
|
||||
@ -107,6 +119,8 @@ void UILayer::onAttach() {
|
||||
buildingMenuContainerContainer->addChild(std::move(buildingMenuContainer));
|
||||
|
||||
rootContainer->addChild(std::move(buildingMenuContainerContainer));
|
||||
|
||||
Application::getInstance().stateManager->registerMouseUser(uiInputUser.get(), {StateRegistry::get().uiState});
|
||||
}
|
||||
|
||||
void UILayer::onUpdate() {
|
||||
@ -124,7 +138,10 @@ void UILayer::onUpdate() {
|
||||
|
||||
Dimensions rootParent {0.0, 0.0, 1.0, 1.0f};
|
||||
rootContainer->uiPositioner.compute(rootParent);
|
||||
rootContainer->update(0.f); //Todo: Determine frame time
|
||||
if (uiInputUser->isMouseEnabled()) {
|
||||
rootContainer->update(0.f); //Todo: Determine frame time
|
||||
}
|
||||
|
||||
|
||||
UiRenderBundle renderBundle;
|
||||
if (rootContainer) {
|
||||
|
||||
@ -10,6 +10,7 @@
|
||||
#include "../engine/core/events/EventBus.h"
|
||||
#include "../engine/core/gui/text/Font.h"
|
||||
#include "../engine/core/gui/uiMain/UiContainer.h"
|
||||
#include "../engine/core/inputsOutputs/stateControl/inputUser/UiInputUser.h"
|
||||
#include "../engine/layer/Layer.h"
|
||||
#include "../engine/renderer/GUIRenderer.h"
|
||||
#include "../engine/renderer/TextRenderer.h"
|
||||
@ -25,6 +26,7 @@ private:
|
||||
std::unique_ptr<Font> mediumFont;
|
||||
std::unique_ptr<UiContainer> rootContainer;
|
||||
|
||||
std::unique_ptr<UiInputUser> uiInputUser;
|
||||
size_t inventoryContainerID;
|
||||
size_t turnTextID;
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user