aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/crepe/api/Button.cpp7
-rw-r--r--src/crepe/api/Button.h52
-rw-r--r--src/crepe/api/Event.h7
-rw-r--r--src/crepe/api/UiObject.cpp2
-rw-r--r--src/crepe/api/UiObject.h2
-rw-r--r--src/crepe/facade/SDLContext.h14
-rw-r--r--src/crepe/system/InputSystem.cpp46
-rw-r--r--src/crepe/system/InputSystem.h7
-rw-r--r--src/test/inputTest.cpp45
9 files changed, 109 insertions, 73 deletions
diff --git a/src/crepe/api/Button.cpp b/src/crepe/api/Button.cpp
index 547c0fc..077a5e7 100644
--- a/src/crepe/api/Button.cpp
+++ b/src/crepe/api/Button.cpp
@@ -1,5 +1,8 @@
#include "Button.h"
-using namespace crepe;
+namespace crepe {
-Button::Button(game_object_id_t id) : UiObject(id) {}
+Button::Button(game_object_id_t id, int width, int height, bool is_toggle, std::function<void()> on_click)
+ : UiObject(id, width, height), is_toggle(is_toggle), is_pressed(false), hover(false), on_click(on_click) {}
+
+} // namespace crepe
diff --git a/src/crepe/api/Button.h b/src/crepe/api/Button.h
index 0056238..df6f1e0 100644
--- a/src/crepe/api/Button.h
+++ b/src/crepe/api/Button.h
@@ -1,7 +1,6 @@
#pragma once
#include <functional>
-
#include "UiObject.h"
namespace crepe {
@@ -9,34 +8,59 @@ namespace crepe {
/**
* \class Button
* \brief Represents a clickable UI button, derived from the UiObject class.
+ *
+ * This class provides functionality for a button in the UI, including toggle state,
+ * click handling, and mouse hover detection. A callback function can be provided to
+ * handle button clicks.
*/
class Button : public UiObject {
public:
/**
- * \brief Constructs a Button with the specified game object ID.
+ * \brief Constructs a Button with the specified game object ID and dimensions.
+ *
* \param id The unique ID of the game object associated with this button.
+ * \param width The width of the button.
+ * \param height The height of the button.
+ * \param is_toggle Optional flag to indicate if the button is a toggle button. Defaults to false.
+ * \param on_click callback function that will be invoked when the button is clicked.
*/
- Button(game_object_id_t id);
-
- //! Indicates if the button is interactable (can be clicked).
- bool interactable = true;
+ Button(game_object_id_t id, int width, int height, bool is_toggle = false, std::function<void()> on_click = nullptr);
- //! Indicates if the button is a toggle button (can be pressed and released).
- bool is_toggle = false;
+ /**
+ * \brief Indicates if the button is a toggle button (can be pressed and released).
+ *
+ * A toggle button allows for a pressed/released state, whereas a regular button
+ * typically only has an on-click state.
+ */
+ bool is_toggle;
- //! Indicates whether the button is currently pressed.
- bool is_pressed = false;
+ /**
+ * \brief Indicates whether the button is currently pressed.
+ *
+ * This state is true when the button is actively pressed and false otherwise.
+ */
+ bool is_pressed;
- //! Indicates whether the mouse is currently hovering over the button.
- bool hover = false;
+ /**
+ * \brief Indicates whether the mouse is currently hovering over the button.
+ *
+ * This is set to true when the mouse is over the button and false otherwise.
+ */
+ bool hover;
- //! The callback function to be executed when the button is clicked.
+ /**
+ * \brief The callback function to be executed when the button is clicked.
+ *
+ * This function is invoked whenever the button is clicked. It can be set to any
+ * function that matches the signature `void()`. Defaults to nullptr.
+ */
std::function<void()> on_click;
public:
/**
* \brief Retrieves the maximum number of instances allowed for this button type.
- * \return Always returns 1, as only a single instance is allowed.
+ *
+ * \return Always returns 1, as only a single instance of this type is allowed.
*/
virtual int get_instances_max() const override { return 1; }
};
diff --git a/src/crepe/api/Event.h b/src/crepe/api/Event.h
index b13abc1..a7d5511 100644
--- a/src/crepe/api/Event.h
+++ b/src/crepe/api/Event.h
@@ -88,10 +88,12 @@ public:
//! Y-coordinate of the mouse position at the time of the event.
int mouse_y = 0;
+
// Relative movement in x
- int rel_x;
+ int rel_x = 0;
+
// Relative movement in y
- int rel_y;
+ int rel_y = 0;
};
/**
@@ -104,6 +106,7 @@ public:
//! Y-coordinate of the mouse position at the time of the event.
int scroll_y = 0;
+
//! scroll direction (-1 = down, 1 = up)
int direction = 0;
};
diff --git a/src/crepe/api/UiObject.cpp b/src/crepe/api/UiObject.cpp
index 1c11fc3..987fc06 100644
--- a/src/crepe/api/UiObject.cpp
+++ b/src/crepe/api/UiObject.cpp
@@ -2,4 +2,4 @@
using namespace crepe;
-UiObject::UiObject(game_object_id_t id) : Component(id){};
+UiObject::UiObject(game_object_id_t id,int width,int height) : Component(id),width(width),height(height){};
diff --git a/src/crepe/api/UiObject.h b/src/crepe/api/UiObject.h
index 7bd1c2e..6b0323e 100644
--- a/src/crepe/api/UiObject.h
+++ b/src/crepe/api/UiObject.h
@@ -14,7 +14,7 @@ public:
* \brief Constructs a UiObject with the specified game object ID.
* \param id The unique ID of the game object associated with this UI object.
*/
- UiObject(game_object_id_t id);
+ UiObject(game_object_id_t id,int width,int height);
//! The width of the UI object.
int width = 0;
diff --git a/src/crepe/facade/SDLContext.h b/src/crepe/facade/SDLContext.h
index 3e0b073..9f18728 100644
--- a/src/crepe/facade/SDLContext.h
+++ b/src/crepe/facade/SDLContext.h
@@ -11,20 +11,16 @@
#include <string>
#include <utility>
-#include "../api/Event.h"
-#include "../api/KeyCodes.h"
-#include "../api/Sprite.h"
-#include "../api/Transform.h"
-#include "../api/Vector2.h"
+#include "api/Event.h"
+#include "api/KeyCodes.h"
+#include "api/Sprite.h"
+#include "api/Transform.h"
#include "api/Camera.h"
#include "types.h"
namespace crepe {
-// TODO: SDL_Keycode is defined in a header not distributed with crepe, which means this
-// typedef is unusable when crepe is packaged. Wouter will fix this later.
-//typedef SDL_Keycode CREPE_KEYCODES;
class LoopManager;
class InputSystem;
/**
@@ -93,7 +89,7 @@ private:
* @param sdlKey The SDL key code to convert.
* @return The corresponding `Keycode` value.
*/
- Keycode sdl_to_keycode(SDL_Keycode sdlKey);
+ Keycode sdl_to_keycode(SDL_Keycode sdl_key);
/**
* @brief Converts an SDL mouse button code to the custom MouseButton type.
diff --git a/src/crepe/system/InputSystem.cpp b/src/crepe/system/InputSystem.cpp
index 9690fec..590be8d 100644
--- a/src/crepe/system/InputSystem.cpp
+++ b/src/crepe/system/InputSystem.cpp
@@ -1,8 +1,8 @@
-#include "../api/Button.h"
-#include "../api/EventManager.h"
+#include "api/Button.h"
+#include "api/EventManager.h"
#include "ComponentManager.h"
-#include "system/InputSystem.h"
+#include "InputSystem.h"
using namespace crepe;
@@ -36,17 +36,15 @@ void InputSystem::update() {
break;
}
case SDLContext::EventType::MOUSEUP: {
- MouseReleaseEvent mouse_release_event = MouseReleaseEvent{
+ event_mgr.queue_event<MouseReleaseEvent>(MouseReleaseEvent{
.mouse_x = event.mouse_position.first,
.mouse_y = event.mouse_position.second,
.button = event.mouse_button,
- };
- event_mgr.queue_event<MouseReleaseEvent>(mouse_release_event);
+ });
- // Calculate deltas for click detection
int delta_x = event.mouse_position.first - last_mouse_down_position.first;
int delta_y = event.mouse_position.second - last_mouse_down_position.second;
-
+
if (last_mouse_button == event.mouse_button
&& std::abs(delta_x) <= click_tolerance
&& std::abs(delta_y) <= click_tolerance) {
@@ -96,10 +94,10 @@ void InputSystem::handle_move(const SDLContext::EventData & event_data) {
= mgr.get_components_by_type<Transform>();
for (Button & button : buttons) {
- Transform * transform = find_transform_for_button(button, transforms);
+ OptionalRef<Transform> transform = find_transform_for_button(button, transforms);
if (!transform) continue;
- if (button.interactable && is_mouse_inside_button(event_data, button, *transform)) {
+ if (button.active && is_mouse_inside_button(event_data, button, transform)) {
button.hover = true;
} else {
button.hover = false;
@@ -111,29 +109,31 @@ void InputSystem::handle_click(const SDLContext::EventData & event_data) {
ComponentManager & mgr = this->component_manager;
std::vector<std::reference_wrapper<Button>> buttons = mgr.get_components_by_type<Button>();
- std::vector<std::reference_wrapper<Transform>> transforms
- = mgr.get_components_by_type<Transform>();
+ std::vector<std::reference_wrapper<Transform>> transforms = mgr.get_components_by_type<Transform>();
for (Button & button : buttons) {
- Transform * transform = find_transform_for_button(button, transforms);
- if (!transform) continue;
+ OptionalRef<Transform> transform_ref = find_transform_for_button(button, transforms);
- if (button.interactable && is_mouse_inside_button(event_data, button, *transform)) {
+ if (button.active && is_mouse_inside_button(event_data, button, transform_ref)) {
handle_button_press(button);
}
}
}
-Transform * InputSystem::find_transform_for_button(
- Button & button, std::vector<std::reference_wrapper<Transform>> & transforms) {
- for (Transform & transform : transforms) {
- if (button.game_object_id == transform.game_object_id) {
- return &transform;
- }
- }
- return nullptr;
+
+OptionalRef<Transform> InputSystem::find_transform_for_button(
+ Button & button, std::vector<std::reference_wrapper<Transform>> & transforms) {
+
+ for (auto& transform : transforms) {
+ if (button.game_object_id == transform.get().game_object_id) {
+ return OptionalRef<Transform>(transform);
+ }
+ }
+
+ return OptionalRef<Transform>();
}
+
bool InputSystem::is_mouse_inside_button(const SDLContext::EventData & event_data,
const Button & button, const Transform & transform) {
return event_data.mouse_position.first >= transform.position.x
diff --git a/src/crepe/system/InputSystem.h b/src/crepe/system/InputSystem.h
index cd7ca77..8b47e49 100644
--- a/src/crepe/system/InputSystem.h
+++ b/src/crepe/system/InputSystem.h
@@ -1,11 +1,14 @@
#pragma once
+#include "facade/SDLContext.h"
+#include "util/OptionalRef.h"
+
#include "System.h"
-#include "../facade/SDLContext.h"
namespace crepe {
class Button;
+
class Transform;
/**
* \class InputSystem
@@ -57,7 +60,7 @@ private:
* \param transforms A list of transforms to search through.
* \return A pointer to the transform of the button, or nullptr if not found.
*/
- Transform *
+ OptionalRef<Transform>
find_transform_for_button(Button & button,
std::vector<std::reference_wrapper<Transform>> & transforms);
diff --git a/src/test/inputTest.cpp b/src/test/inputTest.cpp
index 3a9d341..0e3e097 100644
--- a/src/test/inputTest.cpp
+++ b/src/test/inputTest.cpp
@@ -20,12 +20,14 @@ using namespace crepe;
class InputTest : public ::testing::Test {
public:
ComponentManager mgr{};
- InputSystem input_system{mgr};
+ InputSystem input_system{mgr}; // Initializes the InputSystem with the ComponentManager
- EventManager & event_manager = EventManager::get_instance();
+ EventManager& event_manager = EventManager::get_instance();
protected:
- void SetUp() override { event_manager.clear(); }
+ void SetUp() override {
+ event_manager.clear();
+ }
void simulate_mouse_click(int mouse_x, int mouse_y, Uint8 mouse_button) {
SDL_Event event;
@@ -37,6 +39,8 @@ protected:
event.button.y = mouse_y;
event.button.button = mouse_button;
SDL_PushEvent(&event);
+
+ // Simulate Mouse Button Up event
SDL_zero(event);
event.type = SDL_MOUSEBUTTONUP;
event.button.x = mouse_x;
@@ -48,7 +52,7 @@ protected:
TEST_F(InputTest, MouseDown) {
bool mouse_triggered = false;
- EventHandler<MousePressEvent> on_mouse_down = [&](const MousePressEvent & event) {
+ EventHandler<MousePressEvent> on_mouse_down = [&](const MousePressEvent& event) {
mouse_triggered = true;
EXPECT_EQ(event.mouse_x, 10);
EXPECT_EQ(event.mouse_y, 10);
@@ -64,6 +68,7 @@ TEST_F(InputTest, MouseDown) {
event.button.y = 10;
event.button.button = SDL_BUTTON_LEFT;
SDL_PushEvent(&event);
+
input_system.update();
event_manager.dispatch_events();
EXPECT_TRUE(mouse_triggered);
@@ -71,8 +76,7 @@ TEST_F(InputTest, MouseDown) {
TEST_F(InputTest, MouseUp) {
bool function_triggered = false;
- EventHandler<MouseReleaseEvent> on_mouse_release = [&](const MouseReleaseEvent & e) {
- // Handle the mouse click event here
+ EventHandler<MouseReleaseEvent> on_mouse_release = [&](const MouseReleaseEvent& e) {
function_triggered = true;
EXPECT_EQ(e.mouse_x, 10);
EXPECT_EQ(e.mouse_y, 10);
@@ -88,6 +92,7 @@ TEST_F(InputTest, MouseUp) {
event.button.y = 10;
event.button.button = SDL_BUTTON_LEFT;
SDL_PushEvent(&event);
+
input_system.update();
event_manager.dispatch_events();
EXPECT_TRUE(function_triggered);
@@ -95,8 +100,7 @@ TEST_F(InputTest, MouseUp) {
TEST_F(InputTest, MouseMove) {
bool function_triggered = false;
- EventHandler<MouseMoveEvent> on_mouse_move = [&](const MouseMoveEvent & e) {
- // Handle the mouse click event here
+ EventHandler<MouseMoveEvent> on_mouse_move = [&](const MouseMoveEvent& e) {
function_triggered = true;
EXPECT_EQ(e.mouse_x, 10);
EXPECT_EQ(e.mouse_y, 10);
@@ -114,6 +118,7 @@ TEST_F(InputTest, MouseMove) {
event.motion.xrel = 10;
event.motion.yrel = 10;
SDL_PushEvent(&event);
+
input_system.update();
event_manager.dispatch_events();
EXPECT_TRUE(function_triggered);
@@ -123,7 +128,7 @@ TEST_F(InputTest, KeyDown) {
bool function_triggered = false;
// Define event handler for KeyPressEvent
- EventHandler<KeyPressEvent> on_key_press = [&](const KeyPressEvent & event) {
+ EventHandler<KeyPressEvent> on_key_press = [&](const KeyPressEvent& event) {
function_triggered = true;
EXPECT_EQ(event.key, Keycode::B); // Validate the key is 'B'
EXPECT_EQ(event.repeat, true); // Validate repeat flag
@@ -148,7 +153,7 @@ TEST_F(InputTest, KeyDown) {
TEST_F(InputTest, KeyUp) {
bool function_triggered = false;
- EventHandler<KeyReleaseEvent> on_key_release = [&](const KeyReleaseEvent & event) {
+ EventHandler<KeyReleaseEvent> on_key_release = [&](const KeyReleaseEvent& event) {
function_triggered = true;
EXPECT_EQ(event.key, Keycode::B);
return false;
@@ -160,6 +165,7 @@ TEST_F(InputTest, KeyUp) {
event.type = SDL_KEYUP;
event.key.keysym.scancode = SDL_SCANCODE_B;
SDL_PushEvent(&event);
+
input_system.update();
event_manager.dispatch_events();
EXPECT_TRUE(function_triggered);
@@ -167,7 +173,7 @@ TEST_F(InputTest, KeyUp) {
TEST_F(InputTest, MouseClick) {
bool on_click_triggered = false;
- EventHandler<MouseClickEvent> on_mouse_click = [&](const MouseClickEvent & event) {
+ EventHandler<MouseClickEvent> on_mouse_click = [&](const MouseClickEvent& event) {
on_click_triggered = true;
EXPECT_EQ(event.button, MouseButton::LEFT_MOUSE);
EXPECT_EQ(event.mouse_x, 10);
@@ -184,13 +190,11 @@ TEST_F(InputTest, MouseClick) {
TEST_F(InputTest, testButtonClick) {
GameObject obj = mgr.new_object("body", "person", vec2{0, 0}, 0, 1);
- auto & button = obj.add_component<Button>();
+
+ auto& button = obj.add_component<Button>(100,100);
bool button_clicked = false;
bool hover = false;
button.active = true;
- button.interactable = true;
- button.width = 100;
- button.height = 100;
std::function<void()> on_click = [&]() { button_clicked = true; };
button.on_click = on_click;
button.is_pressed = false;
@@ -199,6 +203,7 @@ TEST_F(InputTest, testButtonClick) {
input_system.update();
event_manager.dispatch_events();
EXPECT_FALSE(button_clicked);
+
this->simulate_mouse_click(10, 10, SDL_BUTTON_LEFT);
input_system.update();
event_manager.dispatch_events();
@@ -207,15 +212,15 @@ TEST_F(InputTest, testButtonClick) {
TEST_F(InputTest, testButtonHover) {
GameObject obj = mgr.new_object("body", "person", vec2{0, 0}, 0, 1);
- auto & button = obj.add_component<Button>();
+ auto& button = obj.add_component<Button>(100,100);
bool button_clicked = false;
button.active = true;
- button.interactable = true;
button.width = 100;
button.height = 100;
button.is_pressed = false;
button.is_toggle = false;
- //mouse not on button
+
+ // Mouse not on button
SDL_Event event;
SDL_zero(event);
event.type = SDL_MOUSEMOTION;
@@ -228,7 +233,8 @@ TEST_F(InputTest, testButtonHover) {
input_system.update();
event_manager.dispatch_events();
EXPECT_FALSE(button.hover);
- //mouse on button
+
+ // Mouse on button
SDL_Event hover_event;
SDL_zero(hover_event);
hover_event.type = SDL_MOUSEMOTION;
@@ -237,6 +243,7 @@ TEST_F(InputTest, testButtonHover) {
hover_event.motion.xrel = 10;
hover_event.motion.yrel = 10;
SDL_PushEvent(&hover_event);
+
input_system.update();
event_manager.dispatch_events();
EXPECT_TRUE(button.hover);