aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/crepe/api/Button.cpp3
-rw-r--r--src/crepe/api/Button.h12
-rw-r--r--src/crepe/api/Config.h5
-rw-r--r--src/crepe/api/Event.h97
-rw-r--r--src/crepe/api/KeyCodes.h6
-rw-r--r--src/crepe/facade/SDLContext.cpp88
-rw-r--r--src/crepe/facade/SDLContext.h61
-rw-r--r--src/crepe/system/InputSystem.cpp235
-rw-r--r--src/crepe/system/InputSystem.h13
-rw-r--r--src/example/button.cpp1
-rw-r--r--src/test/EventTest.cpp55
-rw-r--r--src/test/InputTest.cpp84
12 files changed, 420 insertions, 240 deletions
diff --git a/src/crepe/api/Button.cpp b/src/crepe/api/Button.cpp
index 76f74f0..305922c 100644
--- a/src/crepe/api/Button.cpp
+++ b/src/crepe/api/Button.cpp
@@ -3,9 +3,8 @@
namespace crepe {
Button::Button(game_object_id_t id, const vec2 & dimensions, const vec2 & offset,
- const std::function<void()> & on_click, bool is_toggle)
+ const std::function<void()> & on_click)
: UIObject(id, dimensions, offset),
- is_toggle(is_toggle),
on_click(on_click) {}
} // namespace crepe
diff --git a/src/crepe/api/Button.h b/src/crepe/api/Button.h
index 61b18d7..08f5dec 100644
--- a/src/crepe/api/Button.h
+++ b/src/crepe/api/Button.h
@@ -15,19 +15,11 @@ public:
* \param id The unique ID of the game object associated with this button.
* \param dimensions The width and height of the UIObject
* \param offset The offset relative this GameObjects Transform
- * \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, const vec2 & dimensions, const vec2 & offset,
- const std::function<void()> & on_click, bool is_toggle = false);
+ const std::function<void()> & on_click);
- /**
- * \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 = false;
// TODO: create separate toggle button class
/**
* \brief The callback function to be executed when the button is clicked.
@@ -56,8 +48,6 @@ public:
private:
//! friend relation for is_pressed and hover variables
friend class InputSystem;
- //! Indicates whether the toggle button is pressed
- bool is_pressed = false;
//! Indicates whether the mouse is currently hovering over the button
bool hover = false;
diff --git a/src/crepe/api/Config.h b/src/crepe/api/Config.h
index 6472270..925ded8 100644
--- a/src/crepe/api/Config.h
+++ b/src/crepe/api/Config.h
@@ -76,6 +76,11 @@ struct Config final {
*/
std::string root_pattern = ".crepe-root";
} asset;
+ //! Configuration for click tolerance.
+ struct {
+ //! The maximum number of pixels the mouse can move between MouseDown and MouseUp events to be considered a click.
+ int click_tolerance = 5;
+ } input;
//! Audio system settings
struct {
diff --git a/src/crepe/api/Event.h b/src/crepe/api/Event.h
index f2f3daf..d3e99af 100644
--- a/src/crepe/api/Event.h
+++ b/src/crepe/api/Event.h
@@ -4,7 +4,7 @@
#include <string>
#include "KeyCodes.h"
-
+#include "types.h"
namespace crepe {
/**
@@ -38,11 +38,8 @@ public:
*/
class MousePressEvent : public Event {
public:
- //! X-coordinate of the mouse position at the time of the event.
- int mouse_x = 0;
-
- //! Y-coordinate of the mouse position at the time of the event.
- int mouse_y = 0;
+ //! mouse position
+ ivec2 mouse_pos = {0, 0};
//! The mouse button that was pressed.
MouseButton button = MouseButton::NONE;
@@ -53,11 +50,8 @@ public:
*/
class MouseClickEvent : public Event {
public:
- //! X-coordinate of the mouse position at the time of the event.
- int mouse_x = 0;
-
- //! Y-coordinate of the mouse position at the time of the event.
- int mouse_y = 0;
+ //! mouse position
+ ivec2 mouse_pos = {0, 0};
//! The mouse button that was clicked.
MouseButton button = MouseButton::NONE;
@@ -68,11 +62,8 @@ public:
*/
class MouseReleaseEvent : public Event {
public:
- //! X-coordinate of the mouse position at the time of the event.
- int mouse_x = 0;
-
- //! Y-coordinate of the mouse position at the time of the event.
- int mouse_y = 0;
+ //! mouse position
+ ivec2 mouse_pos = {0, 0};
//! The mouse button that was released.
MouseButton button = MouseButton::NONE;
@@ -83,17 +74,10 @@ public:
*/
class MouseMoveEvent : public Event {
public:
- //! X-coordinate of the mouse position at the time of the event.
- int mouse_x = 0;
-
- //! Y-coordinate of the mouse position at the time of the event.
- int mouse_y = 0;
-
- // Movement since last event in x
- int delta_x = 0;
-
- // Movement since last event in y
- int delta_y = 0;
+ //! new mouse position
+ ivec2 mouse_pos = {0, 0};
+ //! The change in mouse position relative to the last position (in pixels).
+ ivec2 mouse_delta = {0, 0};
};
/**
@@ -101,12 +85,8 @@ public:
*/
class MouseScrollEvent : public Event {
public:
- //! X-coordinate of the mouse position at the time of the event.
- int mouse_x = 0;
-
- //! Y-coordinate of the mouse position at the time of the event.
- int mouse_y = 0;
-
+ //! mouse position when the scroll happened.
+ ivec2 mouse_pos = {0, 0};
//! scroll direction (-1 = down, 1 = up)
int scroll_direction = 0;
//! scroll amount in y axis (from and away from the person).
@@ -127,4 +107,55 @@ public:
*/
class ShutDownEvent : public Event {};
+/**
+ * \brief Event triggered to indicate the window is overlapped by another window.
+ *
+ * When two windows overlap the bottom window gets distorted and that window has to be redrawn.
+ */
+class WindowExposeEvent : public Event {};
+
+/**
+ * \brief Event triggered to indicate the window is resized.
+ */
+class WindowResizeEvent : public Event {
+public:
+ //! new window dimensions
+ ivec2 dimensions = {0, 0};
+};
+
+/**
+ * \brief Event triggered to indicate the window is moved.
+ */
+class WindowMoveEvent : public Event {
+public:
+ //! The change in position relative to the last position (in pixels).
+ ivec2 delta_move = {0, 0};
+};
+
+/**
+ * \brief Event triggered to indicate the window is minimized.
+ */
+class WindowMinimizeEvent : public Event {};
+
+/**
+ * \brief Event triggered to indicate the window is maximized
+ */
+class WindowMaximizeEvent : public Event {};
+
+/**
+ * \brief Event triggered to indicate the window gained focus
+ *
+ * This event is triggered when the window receives focus, meaning it becomes the active window
+ * for user interaction.
+ */
+class WindowFocusGainEvent : public Event {};
+
+/**
+ * \brief Event triggered to indicate the window lost focus
+ *
+ * This event is triggered when the window loses focus, meaning it is no longer the active window
+ * for user interaction.
+ */
+class WindowFocusLostEvent : public Event {};
+
} // namespace crepe
diff --git a/src/crepe/api/KeyCodes.h b/src/crepe/api/KeyCodes.h
index fcfc080..f704fbb 100644
--- a/src/crepe/api/KeyCodes.h
+++ b/src/crepe/api/KeyCodes.h
@@ -13,7 +13,7 @@ enum class MouseButton {
};
//! Enumeration for keyboard key inputs, including printable characters, function keys, and keypad keys.
-enum class Keycode {
+typedef enum {
NONE = 0, //!< No key input.
SPACE = 32, //!< Spacebar.
APOSTROPHE = 39, //!< Apostrophe (').
@@ -150,5 +150,7 @@ enum class Keycode {
RIGHT_SUPER = 347,
/// \}
MENU = 348, //!< Menu key.
-};
+ //! Not actually a key instead its the amount of keycodes there are for array indexing
+ NUM_KEYCODES = 512,
+} Keycode;
} // namespace crepe
diff --git a/src/crepe/facade/SDLContext.cpp b/src/crepe/facade/SDLContext.cpp
index 20bb030..4552605 100644
--- a/src/crepe/facade/SDLContext.cpp
+++ b/src/crepe/facade/SDLContext.cpp
@@ -75,11 +75,12 @@ SDLContext::~SDLContext() {
SDL_Quit();
}
-Keycode SDLContext::sdl_to_keycode(SDL_Keycode sdl_key) {
+Keycode SDLContext::sdl_to_keycode(SDL_Scancode sdl_key) {
static const std::array<Keycode, SDL_NUM_SCANCODES> LOOKUP_TABLE = [] {
std::array<Keycode, SDL_NUM_SCANCODES> table{};
table.fill(Keycode::NONE);
+ // Map all SDL scancodes to Keycodes
table[SDL_SCANCODE_SPACE] = Keycode::SPACE;
table[SDL_SCANCODE_APOSTROPHE] = Keycode::APOSTROPHE;
table[SDL_SCANCODE_COMMA] = Keycode::COMMA;
@@ -181,13 +182,27 @@ Keycode SDLContext::sdl_to_keycode(SDL_Keycode sdl_key) {
return table;
}();
-
if (sdl_key < 0 || sdl_key >= SDL_NUM_SCANCODES) {
return Keycode::NONE;
}
-
return LOOKUP_TABLE[sdl_key];
}
+std::array<bool, Keycode::NUM_KEYCODES> SDLContext::get_keyboard_state() {
+ // Array to hold the key states (true if pressed, false if not)
+ std::array<bool, Keycode::NUM_KEYCODES> keyState{};
+ SDL_PumpEvents();
+ const Uint8 * current_state = SDL_GetKeyboardState(nullptr);
+
+ for (int i = 0; i < SDL_NUM_SCANCODES; ++i) {
+ Keycode key = sdl_to_keycode(static_cast<SDL_Scancode>(i));
+
+ if (key != Keycode::NONE) {
+ keyState[key] = current_state[i] != 0;
+ }
+ }
+
+ return keyState;
+}
MouseButton SDLContext::sdl_to_mousebutton(Uint8 sdl_button) {
static const std::array<MouseButton, 5> MOUSE_BUTTON_LOOKUP_TABLE = [] {
@@ -368,35 +383,32 @@ ivec2 SDLContext::get_size(const Texture & ctx) {
std::vector<SDLContext::EventData> SDLContext::get_events() {
std::vector<SDLContext::EventData> event_list;
SDL_Event event;
- const CameraAuxiliaryData & cam = this->cam_aux_data;
while (SDL_PollEvent(&event)) {
ivec2 mouse_pos;
mouse_pos.x = (event.button.x - cam.bar_size.x) / cam.render_scale.x;
mouse_pos.y = (event.button.y - cam.bar_size.y) / cam.render_scale.y;
switch (event.type) {
case SDL_QUIT:
- event_list.push_back(EventData{
- .event_type = SDLContext::EventType::SHUTDOWN,
- });
+ event_list.push_back({SDLContext::EventType::SHUTDOWN, {}, {}, {}});
break;
case SDL_KEYDOWN:
- event_list.push_back(EventData{
- .event_type = SDLContext::EventType::KEYDOWN,
- .key = sdl_to_keycode(event.key.keysym.scancode),
- .key_repeat = (event.key.repeat != 0),
- });
+ event_list.push_back(
+ {SDLContext::EventType::KEYDOWN,
+ {sdl_to_keycode(event.key.keysym.scancode), event.key.repeat != 0},
+ {},
+ {}});
break;
case SDL_KEYUP:
- event_list.push_back(EventData{
- .event_type = SDLContext::EventType::KEYUP,
- .key = sdl_to_keycode(event.key.keysym.scancode),
- });
+ event_list.push_back({SDLContext::EventType::KEYUP,
+ {sdl_to_keycode(event.key.keysym.scancode), false},
+ {},
+ {}});
break;
case SDL_MOUSEBUTTONDOWN:
event_list.push_back(EventData{
.event_type = SDLContext::EventType::MOUSEDOWN,
.mouse_button = sdl_to_mousebutton(event.button.button),
- .mouse_position = mouse_pos,
+ .mouse_position = {event.button.x, event.button.y},
});
break;
case SDL_MOUSEBUTTONUP: {
@@ -405,21 +417,21 @@ std::vector<SDLContext::EventData> SDLContext::get_events() {
event_list.push_back(EventData{
.event_type = SDLContext::EventType::MOUSEUP,
.mouse_button = sdl_to_mousebutton(event.button.button),
- .mouse_position = mouse_pos,
+ .mouse_position = {event.button.x, event.button.y},
});
} break;
case SDL_MOUSEMOTION: {
event_list.push_back(
EventData{.event_type = SDLContext::EventType::MOUSEMOVE,
- .mouse_position = mouse_pos,
+ .mouse_position = {event.motion.x, event.motion.y},
.rel_mouse_move = {event.motion.xrel, event.motion.yrel}});
} break;
case SDL_MOUSEWHEEL: {
event_list.push_back(EventData{
.event_type = SDLContext::EventType::MOUSEWHEEL,
- .mouse_position = mouse_pos,
+ .mouse_position = {event.motion.x, event.motion.y},
// TODO: why is this needed?
.scroll_direction = event.wheel.y < 0 ? -1 : 1,
.scroll_delta = event.wheel.preciseY,
@@ -427,8 +439,44 @@ std::vector<SDLContext::EventData> SDLContext::get_events() {
} break;
}
}
+
return event_list;
}
+
+// Separate function for SDL_WINDOWEVENT subtypes
+void SDLContext::handle_window_event(const SDL_WindowEvent & window_event,
+ std::vector<SDLContext::EventData> & event_list) {
+ switch (window_event.event) {
+ case SDL_WINDOWEVENT_EXPOSED:
+ event_list.push_back({SDLContext::EventType::WINDOW_EXPOSE, {}, {}, {}});
+ break;
+ case SDL_WINDOWEVENT_RESIZED:
+ event_list.push_back({SDLContext::EventType::WINDOW_RESIZE,
+ {},
+ {},
+ {{}, {window_event.data1, window_event.data2}}});
+ break;
+ case SDL_WINDOWEVENT_MOVED:
+ event_list.push_back({SDLContext::EventType::WINDOW_MOVE,
+ {},
+ {},
+ {{window_event.data1, window_event.data2}, {}}});
+ break;
+ case SDL_WINDOWEVENT_MINIMIZED:
+ event_list.push_back({SDLContext::EventType::WINDOW_MINIMIZE, {}, {}, {}});
+ break;
+ case SDL_WINDOWEVENT_MAXIMIZED:
+ event_list.push_back({SDLContext::EventType::WINDOW_MAXIMIZE, {}, {}, {}});
+ break;
+ case SDL_WINDOWEVENT_FOCUS_GAINED:
+ event_list.push_back({SDLContext::EventType::WINDOW_FOCUS_GAIN, {}, {}, {}});
+ break;
+ case SDL_WINDOWEVENT_FOCUS_LOST:
+ event_list.push_back({SDLContext::EventType::WINDOW_FOCUS_LOST, {}, {}, {}});
+ break;
+ }
+}
+
void SDLContext::set_color_texture(const Texture & texture, const Color & color) {
SDL_SetTextureColorMod(texture.get_img(), color.r, color.g, color.b);
SDL_SetTextureAlphaMod(texture.get_img(), color.a);
diff --git a/src/crepe/facade/SDLContext.h b/src/crepe/facade/SDLContext.h
index bcadf87..0a2456d 100644
--- a/src/crepe/facade/SDLContext.h
+++ b/src/crepe/facade/SDLContext.h
@@ -5,6 +5,7 @@
#include <SDL2/SDL_rect.h>
#include <SDL2/SDL_render.h>
#include <SDL2/SDL_video.h>
+#include <array>
#include <cmath>
#include <functional>
#include <memory>
@@ -79,19 +80,54 @@ public:
KEYUP,
KEYDOWN,
SHUTDOWN,
-
+ WINDOW_MINIMIZE,
+ WINDOW_MAXIMIZE,
+ WINDOW_FOCUS_GAIN,
+ WINDOW_FOCUS_LOST,
+ WINDOW_MOVE,
+ WINDOW_RESIZE,
+ WINDOW_EXPOSE,
};
- //! EventData struct for passing event data from facade
- struct EventData {
- SDLContext::EventType event_type = SDLContext::EventType::NONE;
+ struct KeyData {
Keycode key = Keycode::NONE;
bool key_repeat = false;
+ };
+ struct MouseData {
MouseButton mouse_button = MouseButton::NONE;
ivec2 mouse_position = {-1, -1};
int scroll_direction = -1;
float scroll_delta = INFINITY;
ivec2 rel_mouse_move = {-1, -1};
};
+ struct WindowData {
+ ivec2 move_delta;
+ ivec2 resize_dimension;
+ };
+ //! EventData struct for passing event data from facade
+ struct EventData {
+ SDLContext::EventType event_type = SDLContext::EventType::NONE;
+ KeyData key_data;
+ MouseData mouse_data;
+ WindowData window_data;
+ };
+ /**
+ * \brief Retrieves the current state of the keyboard.
+ *
+ * This method returns the state of all keys on the keyboard, represented as a
+ * `std::array` of boolean values. Each element of the array corresponds to a
+ * specific key defined in the `Keycode` enum, and the value indicates whether
+ * the key is currently pressed (true) or not pressed (false).
+ *
+ * \return A `std::array<bool, Keycode::NUM_KEYCODES>` representing the state of
+ * each key on the keyboard, where `true` means the key is pressed, and
+ * `false` means it is not pressed.
+ */
+ std::array<bool, Keycode::NUM_KEYCODES> get_keyboard_state();
+ /**
+ * \brief Gets the singleton instance of SDLContext.
+ * \return Reference to the SDLContext instance.
+ */
+ static SDLContext & get_instance();
public:
SDLContext(const SDLContext &) = delete;
@@ -123,17 +159,24 @@ public:
* \return Events that occurred since last call to `get_events()`
*/
std::vector<SDLContext::EventData> get_events();
-
/**
- * \brief Converts an SDL key code to the custom Keycode type.
+ * \brief Fills event_list with triggered window events
+ *
+ * This method checks if any window events are triggered and adds them to the event_list.
+ *
+ */
+ void handle_window_event(const SDL_WindowEvent & window_event,
+ std::vector<SDLContext::EventData> & event_list);
+ /**
+ * \brief Converts an SDL scan code to the custom Keycode type.
*
- * This method maps an SDL key code to the corresponding `Keycode` enum value,
+ * This method maps an SDL scan code to the corresponding `Keycode` enum value,
* which is used internally by the system to identify the keys.
*
- * \param sdl_key The SDL key code to convert.
+ * \param sdl_key The SDL scan code to convert.
* \return The corresponding `Keycode` value or `Keycode::NONE` if the key is unrecognized.
*/
- Keycode sdl_to_keycode(SDL_Keycode sdl_key);
+ Keycode sdl_to_keycode(SDL_Scancode 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 a710ae2..459feb3 100644
--- a/src/crepe/system/InputSystem.cpp
+++ b/src/crepe/system/InputSystem.cpp
@@ -1,3 +1,4 @@
+
#include "../api/Button.h"
#include "../manager/ComponentManager.h"
#include "../manager/EventManager.h"
@@ -16,6 +17,7 @@ void InputSystem::update() {
RefVector<Button> buttons = mgr.get_components_by_type<Button>();
RefVector<Camera> cameras = mgr.get_components_by_type<Camera>();
OptionalRef<Camera> curr_cam_ref;
+
// Find the active camera
for (Camera & cam : cameras) {
if (!cam.active) continue;
@@ -23,149 +25,182 @@ void InputSystem::update() {
break;
}
if (!curr_cam_ref) return;
+
Camera & current_cam = curr_cam_ref;
RefVector<Transform> transform_vec
= mgr.get_components_by_id<Transform>(current_cam.game_object_id);
Transform & cam_transform = transform_vec.front().get();
- int camera_origin_x = cam_transform.position.x + current_cam.data.postion_offset.x
- - (current_cam.viewport_size.x / 2);
- int camera_origin_y = cam_transform.position.y + current_cam.data.postion_offset.y
- - (current_cam.viewport_size.y / 2);
+
+ ivec2 camera_origin;
+ camera_origin.y = cam_transform.position.y + current_cam.data.postion_offset.y
+ - (current_cam.viewport_size.y / 2);
+ camera_origin.x = cam_transform.position.x + current_cam.data.postion_offset.x
+ - (current_cam.viewport_size.x / 2);
for (const SDLContext::EventData & event : event_list) {
- int world_mouse_x = event.mouse_position.x + camera_origin_x;
- int world_mouse_y = event.mouse_position.y + camera_origin_y;
- // check if the mouse is within the viewport
- bool mouse_in_viewport
- = !(world_mouse_x < camera_origin_x
- || world_mouse_x > camera_origin_x + current_cam.viewport_size.x
- || world_mouse_y < camera_origin_y
- || world_mouse_y > camera_origin_y + current_cam.viewport_size.y);
-
- switch (event.event_type) {
- case SDLContext::EventType::KEYDOWN:
- event_mgr.queue_event<KeyPressEvent>(KeyPressEvent{
- .repeat = event.key_repeat,
- .key = event.key,
- });
- break;
- case SDLContext::EventType::KEYUP:
- event_mgr.queue_event<KeyReleaseEvent>(KeyReleaseEvent{
- .key = event.key,
- });
- break;
- case SDLContext::EventType::MOUSEDOWN:
- if (!mouse_in_viewport) {
+ // Only calculate mouse coordinates for relevant events
+ if (event.event_type == SDLContext::EventType::MOUSEDOWN
+ || event.event_type == SDLContext::EventType::MOUSEUP
+ || event.event_type == SDLContext::EventType::MOUSEMOVE
+ || event.event_type == SDLContext::EventType::MOUSEWHEEL) {
+
+ ivec2 adjusted_mouse;
+ adjusted_mouse.x = event.mouse_data.mouse_position.x + camera_origin.x;
+ adjusted_mouse.y = event.mouse_data.mouse_position.y + camera_origin.y;
+ // Check if the mouse is within the viewport
+ bool mouse_in_viewport
+ = !(adjusted_mouse.x < camera_origin.x
+ || adjusted_mouse.x > camera_origin.x + current_cam.viewport_size.x
+ || adjusted_mouse.y < camera_origin.y
+ || adjusted_mouse.y > camera_origin.y + current_cam.viewport_size.y);
+
+ if (!mouse_in_viewport) continue;
+
+ // Handle mouse-specific events
+ switch (event.event_type) {
+ case SDLContext::EventType::MOUSEDOWN:
+ event_mgr.queue_event<MousePressEvent>({
+ .mouse_pos = {adjusted_mouse.x, adjusted_mouse.y},
+ .button = event.mouse_data.mouse_button,
+ });
+ this->last_mouse_down_position = {adjusted_mouse.x, adjusted_mouse.y};
+ this->last_mouse_button = event.mouse_data.mouse_button;
break;
- }
- event_mgr.queue_event<MousePressEvent>(MousePressEvent{
- .mouse_x = world_mouse_x,
- .mouse_y = world_mouse_y,
- .button = event.mouse_button,
- });
- this->last_mouse_down_position = {world_mouse_x, world_mouse_y};
- this->last_mouse_button = event.mouse_button;
- break;
- case SDLContext::EventType::MOUSEUP: {
- if (!mouse_in_viewport) {
+
+ case SDLContext::EventType::MOUSEUP: {
+ event_mgr.queue_event<MouseReleaseEvent>({
+ .mouse_pos = {adjusted_mouse.x, adjusted_mouse.y},
+ .button = event.mouse_data.mouse_button,
+ });
+ int delta_x = adjusted_mouse.x - this->last_mouse_down_position.x;
+ int delta_y = adjusted_mouse.y - this->last_mouse_down_position.y;
+
+ if (this->last_mouse_button == event.mouse_data.mouse_button
+ && std::abs(delta_x) <= click_tolerance
+ && std::abs(delta_y) <= click_tolerance) {
+ event_mgr.queue_event<MouseClickEvent>({
+ .mouse_pos = {adjusted_mouse.x, adjusted_mouse.y},
+ .button = event.mouse_data.mouse_button,
+ });
+ this->handle_click(event.mouse_data.mouse_button, adjusted_mouse);
+ }
break;
}
- event_mgr.queue_event<MouseReleaseEvent>(MouseReleaseEvent{
- .mouse_x = world_mouse_x,
- .mouse_y = world_mouse_y,
- .button = event.mouse_button,
- });
- //check if its a click by checking the last button down
- int delta_x = world_mouse_x - this->last_mouse_down_position.x;
- int delta_y = world_mouse_y - this->last_mouse_down_position.y;
-
- if (this->last_mouse_button == event.mouse_button
- && std::abs(delta_x) <= click_tolerance
- && std::abs(delta_y) <= click_tolerance) {
- event_mgr.queue_event<MouseClickEvent>(MouseClickEvent{
- .mouse_x = world_mouse_x,
- .mouse_y = world_mouse_y,
- .button = event.mouse_button,
+
+ case SDLContext::EventType::MOUSEMOVE:
+ event_mgr.queue_event<MouseMoveEvent>({
+ .mouse_pos = {adjusted_mouse.x, adjusted_mouse.y},
+ .mouse_delta = event.mouse_data.rel_mouse_move,
});
+ this->handle_move(event, adjusted_mouse);
+ break;
- this->handle_click(event.mouse_button, world_mouse_x, world_mouse_y);
- }
- } break;
- case SDLContext::EventType::MOUSEMOVE:
- if (!mouse_in_viewport) {
+ case SDLContext::EventType::MOUSEWHEEL:
+ event_mgr.queue_event<MouseScrollEvent>({
+ .mouse_pos = {adjusted_mouse.x, adjusted_mouse.y},
+ .scroll_direction = event.mouse_data.scroll_direction,
+ .scroll_delta = event.mouse_data.scroll_delta,
+ });
break;
- }
- event_mgr.queue_event<MouseMoveEvent>(MouseMoveEvent{
- .mouse_x = world_mouse_x,
- .mouse_y = world_mouse_y,
- .delta_x = event.rel_mouse_move.x,
- .delta_y = event.rel_mouse_move.y,
- });
- this->handle_move(event, world_mouse_x, world_mouse_y);
- break;
- case SDLContext::EventType::MOUSEWHEEL:
- event_mgr.queue_event<MouseScrollEvent>(MouseScrollEvent{
- .mouse_x = world_mouse_x,
- .mouse_y = world_mouse_y,
- .scroll_direction = event.scroll_direction,
- .scroll_delta = event.scroll_delta,
- });
- break;
- case SDLContext::EventType::SHUTDOWN:
- event_mgr.queue_event<ShutDownEvent>(ShutDownEvent{});
- break;
- default:
- break;
+
+ default:
+ break;
+ }
+ } else {
+ // Handle non-mouse events
+ switch (event.event_type) {
+ case SDLContext::EventType::KEYDOWN:
+ event_mgr.queue_event<KeyPressEvent>(
+ {.repeat = event.key_data.key_repeat, .key = event.key_data.key});
+ break;
+ case SDLContext::EventType::KEYUP:
+ event_mgr.queue_event<KeyReleaseEvent>({.key = event.key_data.key});
+ break;
+ case SDLContext::EventType::SHUTDOWN:
+ event_mgr.queue_event<ShutDownEvent>({});
+ break;
+ case SDLContext::EventType::WINDOW_EXPOSE:
+ event_mgr.queue_event<WindowExposeEvent>({});
+ break;
+ case SDLContext::EventType::WINDOW_RESIZE:
+ event_mgr.queue_event<WindowResizeEvent>(
+ WindowResizeEvent{.dimensions = event.window_data.resize_dimension});
+ break;
+ case SDLContext::EventType::WINDOW_MOVE:
+ event_mgr.queue_event<WindowMoveEvent>(
+ {.delta_move = event.window_data.move_delta});
+ break;
+ case SDLContext::EventType::WINDOW_MINIMIZE:
+ event_mgr.queue_event<WindowMinimizeEvent>({});
+ break;
+ case SDLContext::EventType::WINDOW_MAXIMIZE:
+ event_mgr.queue_event<WindowMaximizeEvent>({});
+ break;
+ case SDLContext::EventType::WINDOW_FOCUS_GAIN:
+ event_mgr.queue_event<WindowFocusGainEvent>({});
+ break;
+ case SDLContext::EventType::WINDOW_FOCUS_LOST:
+ event_mgr.queue_event<WindowFocusLostEvent>({});
+ break;
+ default:
+ break;
+ }
}
}
}
+
void InputSystem::handle_move(const SDLContext::EventData & event_data,
- const int world_mouse_x, const int world_mouse_y) {
+ const ivec2& mouse_pos) {
ComponentManager & mgr = this->mediator.component_manager;
RefVector<Button> buttons = mgr.get_components_by_type<Button>();
for (Button & button : buttons) {
+ if(!button.active) continue;
RefVector<Transform> transform_vec
= mgr.get_components_by_id<Transform>(button.game_object_id);
Transform & transform(transform_vec.front().get());
bool was_hovering = button.hover;
- if (button.active
- && this->is_mouse_inside_button(world_mouse_x, world_mouse_y, button, transform)) {
+ if (this->is_mouse_inside_button(mouse_pos, button,
+ transform)) {
button.hover = true;
- if (!was_hovering && button.on_mouse_enter) {
+ if(!button.on_mouse_enter) continue;
+ if (!was_hovering) {
button.on_mouse_enter();
}
} else {
button.hover = false;
// Trigger the on_exit callback if the hover state just changed to false
- if (was_hovering && button.on_mouse_exit) {
+ if(!button.on_mouse_exit) continue;
+ if (was_hovering) {
button.on_mouse_exit();
}
}
}
}
-void InputSystem::handle_click(const MouseButton & mouse_button, const int world_mouse_x,
- const int world_mouse_y) {
+void InputSystem::handle_click(const MouseButton & mouse_button, const ivec2& mouse_pos) {
ComponentManager & mgr = this->mediator.component_manager;
RefVector<Button> buttons = mgr.get_components_by_type<Button>();
for (Button & button : buttons) {
+ if(!button.active) continue;
+ if (!button.on_click) continue;
RefVector<Transform> transform_vec
= mgr.get_components_by_id<Transform>(button.game_object_id);
Transform & transform = transform_vec.front().get();
-
- if (button.active
- && this->is_mouse_inside_button(world_mouse_x, world_mouse_y, button, transform)) {
- this->handle_button_press(button);
+
+ if (this->is_mouse_inside_button(mouse_pos, button,
+ transform)) {
+
+ button.on_click();
}
}
}
-bool InputSystem::is_mouse_inside_button(const int mouse_x, const int mouse_y,
+bool InputSystem::is_mouse_inside_button(const ivec2& mouse_pos,
const Button & button, const Transform & transform) {
int actual_x = transform.position.x + button.offset.x;
int actual_y = transform.position.y + button.offset.y;
@@ -174,17 +209,7 @@ bool InputSystem::is_mouse_inside_button(const int mouse_x, const int mouse_y,
int half_height = button.dimensions.y / 2;
// Check if the mouse is within the button's boundaries
- return mouse_x >= actual_x - half_width && mouse_x <= actual_x + half_width
- && mouse_y >= actual_y - half_height && mouse_y <= actual_y + half_height;
+ return mouse_pos.x >= actual_x - half_width && mouse_pos.x <= actual_x + half_width
+ && mouse_pos.y >= actual_y - half_height && mouse_pos.y <= actual_y + half_height;
}
-void InputSystem::handle_button_press(Button & button) {
- if (button.is_toggle) {
- if (!button.is_pressed && button.on_click) {
- button.on_click();
- }
- button.is_pressed = !button.is_pressed;
- } else if (button.on_click) {
- button.on_click();
- }
-}
diff --git a/src/crepe/system/InputSystem.h b/src/crepe/system/InputSystem.h
index 87e86f8..3703635 100644
--- a/src/crepe/system/InputSystem.h
+++ b/src/crepe/system/InputSystem.h
@@ -1,5 +1,6 @@
#pragma once
+#include "../api/Config.h"
#include "../facade/SDLContext.h"
#include "../types.h"
#include "../util/OptionalRef.h"
@@ -37,8 +38,8 @@ private:
//! Stores the last mouse button pressed.
MouseButton last_mouse_button = MouseButton::NONE;
- //! The maximum allowable distance between mouse down and mouse up to register as a click.
- const int click_tolerance = 5;
+ //! The maximum allowable distance between mouse down and mouse up to register as a click. This can be changed using the Config.
+ int click_tolerance = Config::get_instance().input.click_tolerance;
/**
* \brief Handles the mouse click event.
@@ -48,8 +49,7 @@ private:
*
* This method processes the mouse click event and triggers the corresponding button action.
*/
- void handle_click(const MouseButton & mouse_button, const int world_mouse_x,
- const int world_mouse_y);
+ void handle_click(const MouseButton & mouse_button,const ivec2& mouse_pos);
/**
* \brief Handles the mouse movement event.
@@ -59,8 +59,7 @@ private:
*
* This method processes the mouse movement event and updates the button hover state.
*/
- void handle_move(const SDLContext::EventData & event_data, const int world_mouse_x,
- const int world_mouse_y);
+ void handle_move(const SDLContext::EventData & event_data, const ivec2& mouse_pos);
/**
* \brief Checks if the mouse position is inside the bounds of the button.
@@ -70,7 +69,7 @@ private:
* \param transform The transform component of the button.
* \return True if the mouse is inside the button, false otherwise.
*/
- bool is_mouse_inside_button(const int world_mouse_x, const int world_mouse_y,
+ bool is_mouse_inside_button(const ivec2& mouse_pos,
const Button & button, const Transform & transform);
/**
diff --git a/src/example/button.cpp b/src/example/button.cpp
index 00bdc28..f2e77f6 100644
--- a/src/example/button.cpp
+++ b/src/example/button.cpp
@@ -15,7 +15,6 @@
#include <crepe/system/InputSystem.h>
#include <crepe/system/RenderSystem.h>
#include <crepe/types.h>
-#include <iostream>
using namespace crepe;
using namespace std;
diff --git a/src/test/EventTest.cpp b/src/test/EventTest.cpp
index 82272b5..f57a6de 100644
--- a/src/test/EventTest.cpp
+++ b/src/test/EventTest.cpp
@@ -48,16 +48,16 @@ TEST_F(EventManagerTest, EventManagerTest_trigger_all_channels) {
EventHandler<MouseClickEvent> mouse_handler = [&](const MouseClickEvent & e) {
triggered = true;
- EXPECT_EQ(e.mouse_x, 100);
- EXPECT_EQ(e.mouse_y, 200);
+ EXPECT_EQ(e.mouse_pos.x, 100);
+ EXPECT_EQ(e.mouse_pos.y, 200);
EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE);
return false;
};
event_mgr.subscribe<MouseClickEvent>(mouse_handler, EventManager::CHANNEL_ALL);
- MouseClickEvent click_event{
- .mouse_x = 100, .mouse_y = 200, .button = MouseButton::LEFT_MOUSE};
- event_mgr.trigger_event<MouseClickEvent>(click_event, EventManager::CHANNEL_ALL);
+ MouseClickEvent click_event{.mouse_pos = {100, 200}, .button = MouseButton::LEFT_MOUSE};
+ EventManager::get_instance().trigger_event<MouseClickEvent>(click_event,
+ EventManager::CHANNEL_ALL);
EXPECT_TRUE(triggered);
}
@@ -66,16 +66,16 @@ TEST_F(EventManagerTest, EventManagerTest_trigger_one_channel) {
int test_channel = 1;
EventHandler<MouseClickEvent> mouse_handler = [&](const MouseClickEvent & e) {
triggered = true;
- EXPECT_EQ(e.mouse_x, 100);
- EXPECT_EQ(e.mouse_y, 200);
+ EXPECT_EQ(e.mouse_pos.x, 100);
+ EXPECT_EQ(e.mouse_pos.y, 200);
EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE);
return false;
};
event_mgr.subscribe<MouseClickEvent>(mouse_handler, test_channel);
- MouseClickEvent click_event{
- .mouse_x = 100, .mouse_y = 200, .button = MouseButton::LEFT_MOUSE};
- event_mgr.trigger_event<MouseClickEvent>(click_event, EventManager::CHANNEL_ALL);
+ MouseClickEvent click_event{.mouse_pos = {100, 200}, .button = MouseButton::LEFT_MOUSE};
+ EventManager::get_instance().trigger_event<MouseClickEvent>(click_event,
+ EventManager::CHANNEL_ALL);
EXPECT_FALSE(triggered);
event_mgr.trigger_event<MouseClickEvent>(click_event, test_channel);
@@ -90,25 +90,24 @@ TEST_F(EventManagerTest, EventManagerTest_callback_propagation) {
// Handlers
EventHandler<MouseClickEvent> mouse_handler_true = [&](const MouseClickEvent & e) {
triggered_true = true;
- EXPECT_EQ(e.mouse_x, 100);
- EXPECT_EQ(e.mouse_y, 200);
+ EXPECT_EQ(e.mouse_pos.x, 100);
+ EXPECT_EQ(e.mouse_pos.y, 200);
EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE);
return true; // Stops propagation
};
EventHandler<MouseClickEvent> mouse_handler_false = [&](const MouseClickEvent & e) {
triggered_false = true;
- EXPECT_EQ(e.mouse_x, 100);
- EXPECT_EQ(e.mouse_y, 200);
+ EXPECT_EQ(e.mouse_pos.x, 100);
+ EXPECT_EQ(e.mouse_pos.y, 200);
EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE);
return false; // Allows propagation
};
// Test event
- MouseClickEvent click_event{
- .mouse_x = 100, .mouse_y = 200, .button = MouseButton::LEFT_MOUSE};
- event_mgr.subscribe<MouseClickEvent>(mouse_handler_true, EventManager::CHANNEL_ALL);
- event_mgr.subscribe<MouseClickEvent>(mouse_handler_false, EventManager::CHANNEL_ALL);
+ MouseClickEvent click_event{.mouse_pos = {100, 200}, .button = MouseButton::LEFT_MOUSE};
+ event_manager.subscribe<MouseClickEvent>(mouse_handler_true, EventManager::CHANNEL_ALL);
+ event_manager.subscribe<MouseClickEvent>(mouse_handler_false, EventManager::CHANNEL_ALL);
// Trigger event
event_mgr.trigger_event<MouseClickEvent>(click_event, EventManager::CHANNEL_ALL);
@@ -172,16 +171,16 @@ TEST_F(EventManagerTest, EventManagerTest_unsubscribe) {
// Define EventHandlers
EventHandler<MouseClickEvent> mouse_handler1 = [&](const MouseClickEvent & e) {
triggered1 = true;
- EXPECT_EQ(e.mouse_x, 100);
- EXPECT_EQ(e.mouse_y, 200);
+ EXPECT_EQ(e.mouse_pos.x, 100);
+ EXPECT_EQ(e.mouse_pos.y, 200);
EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE);
return false; // Allows propagation
};
EventHandler<MouseClickEvent> mouse_handler2 = [&](const MouseClickEvent & e) {
triggered2 = true;
- EXPECT_EQ(e.mouse_x, 100);
- EXPECT_EQ(e.mouse_y, 200);
+ EXPECT_EQ(e.mouse_pos.x, 100);
+ EXPECT_EQ(e.mouse_pos.y, 200);
EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE);
return false; // Allows propagation
};
@@ -190,8 +189,8 @@ TEST_F(EventManagerTest, EventManagerTest_unsubscribe) {
subscription_t handler2_id = event_mgr.subscribe<MouseClickEvent>(mouse_handler2);
// Queue events
- event_mgr.queue_event<MouseClickEvent>(
- MouseClickEvent{.mouse_x = 100, .mouse_y = 200, .button = MouseButton::LEFT_MOUSE});
+ event_manager.queue_event<MouseClickEvent>(
+ MouseClickEvent{.mouse_pos = {100, 200}, .button = MouseButton::LEFT_MOUSE});
// Dispatch events - both handlers should be triggered
event_mgr.dispatch_events();
@@ -206,8 +205,8 @@ TEST_F(EventManagerTest, EventManagerTest_unsubscribe) {
event_mgr.unsubscribe(handler1_id);
// Queue the same event again
- event_mgr.queue_event<MouseClickEvent>(
- MouseClickEvent{.mouse_x = 100, .mouse_y = 200, .button = MouseButton::LEFT_MOUSE});
+ event_manager.queue_event<MouseClickEvent>(
+ MouseClickEvent{.mouse_pos = {100, 200}, .button = MouseButton::LEFT_MOUSE});
// Dispatch events - only handler 2 should be triggered, handler 1 should NOT
event_mgr.dispatch_events();
@@ -221,8 +220,8 @@ TEST_F(EventManagerTest, EventManagerTest_unsubscribe) {
event_mgr.unsubscribe(handler2_id);
// Queue the event again
- event_mgr.queue_event<MouseClickEvent>(
- MouseClickEvent{.mouse_x = 100, .mouse_y = 200, .button = MouseButton::LEFT_MOUSE});
+ event_manager.queue_event<MouseClickEvent>(
+ MouseClickEvent{.mouse_pos = {100, 200}, .button = MouseButton::LEFT_MOUSE});
// Dispatch events - no handler should be triggered
event_mgr.dispatch_events();
diff --git a/src/test/InputTest.cpp b/src/test/InputTest.cpp
index 29ef941..a6e60b5 100644
--- a/src/test/InputTest.cpp
+++ b/src/test/InputTest.cpp
@@ -31,11 +31,7 @@ public:
//GameObject camera;
protected:
- void SetUp() override {
- mediator.event_manager = event_manager;
- mediator.component_manager = mgr;
- 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;
@@ -67,8 +63,8 @@ TEST_F(InputTest, MouseDown) {
EventHandler<MousePressEvent> on_mouse_down = [&](const MousePressEvent & event) {
mouse_triggered = true;
//middle of the screen = 0,0
- EXPECT_EQ(event.mouse_x, 0);
- EXPECT_EQ(event.mouse_y, 0);
+ EXPECT_EQ(event.mouse_pos.x, 0);
+ EXPECT_EQ(event.mouse_pos.y, 0);
EXPECT_EQ(event.button, MouseButton::LEFT_MOUSE);
return false;
};
@@ -96,8 +92,8 @@ TEST_F(InputTest, MouseUp) {
bool function_triggered = false;
EventHandler<MouseReleaseEvent> on_mouse_release = [&](const MouseReleaseEvent & e) {
function_triggered = true;
- EXPECT_EQ(e.mouse_x, 0);
- EXPECT_EQ(e.mouse_y, 0);
+ EXPECT_EQ(e.mouse_pos.x, 0);
+ EXPECT_EQ(e.mouse_pos.y, 0);
EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE);
return false;
};
@@ -124,10 +120,10 @@ TEST_F(InputTest, MouseMove) {
bool function_triggered = false;
EventHandler<MouseMoveEvent> on_mouse_move = [&](const MouseMoveEvent & e) {
function_triggered = true;
- EXPECT_EQ(e.mouse_x, 0);
- EXPECT_EQ(e.mouse_y, 0);
- EXPECT_EQ(e.delta_x, 10);
- EXPECT_EQ(e.delta_y, 10);
+ EXPECT_EQ(e.mouse_pos.x, 0);
+ EXPECT_EQ(e.mouse_pos.y, 0);
+ EXPECT_EQ(e.mouse_delta.x, 10);
+ EXPECT_EQ(e.mouse_delta.y, 10);
return false;
};
event_manager.subscribe<MouseMoveEvent>(on_mouse_move);
@@ -210,8 +206,8 @@ TEST_F(InputTest, MouseClick) {
EventHandler<MouseClickEvent> on_mouse_click = [&](const MouseClickEvent & event) {
on_click_triggered = true;
EXPECT_EQ(event.button, MouseButton::LEFT_MOUSE);
- EXPECT_EQ(event.mouse_x, 0);
- EXPECT_EQ(event.mouse_y, 0);
+ EXPECT_EQ(event.mouse_pos.x, 0);
+ EXPECT_EQ(event.mouse_pos.y, 0);
return false;
};
event_manager.subscribe<MouseClickEvent>(on_mouse_click);
@@ -231,13 +227,10 @@ TEST_F(InputTest, testButtonClick) {
bool button_clicked = false;
std::function<void()> on_click = [&]() { button_clicked = true; };
auto & button
- = button_obj.add_component<Button>(vec2{100, 100}, vec2{0, 0}, on_click, false);
+ = button_obj.add_component<Button>(vec2{100, 100}, vec2{0, 0}, on_click);
bool hover = false;
button.active = true;
-
- button.is_pressed = false;
- button.is_toggle = false;
this->simulate_mouse_click(999, 999, SDL_BUTTON_LEFT);
input_system.update();
event_manager.dispatch_events();
@@ -258,10 +251,8 @@ TEST_F(InputTest, testButtonHover) {
bool button_clicked = false;
std::function<void()> on_click = [&]() { button_clicked = true; };
auto & button
- = button_obj.add_component<Button>(vec2{100, 100}, vec2{0, 0}, on_click, false);
+ = button_obj.add_component<Button>(vec2{100, 100}, vec2{0, 0}, on_click);
button.active = true;
- button.is_pressed = false;
- button.is_toggle = false;
// Mouse not on button
SDL_Event event;
@@ -291,3 +282,52 @@ TEST_F(InputTest, testButtonHover) {
event_manager.dispatch_events();
EXPECT_TRUE(button.hover);
}
+
+TEST_F(InputTest, WindowResizeTest) {
+ GameObject obj = mgr.new_object("camera", "camera", vec2{0, 0}, 0, 1);
+ auto & camera = obj.add_component<Camera>(
+ ivec2{0, 0}, vec2{500, 500}, Camera::Data{.bg_color = Color::WHITE, .zoom = 1.0f});
+ camera.active = true;
+ bool callback_triggered = false;
+ EventHandler<WindowResizeEvent> on_window_resize = [&](const WindowResizeEvent & event) {
+ callback_triggered = true;
+ EXPECT_EQ(event.dimensions.x, 800);
+ EXPECT_EQ(event.dimensions.y, 600);
+ return false;
+ };
+ event_manager.subscribe<WindowResizeEvent>(on_window_resize);
+ SDL_Event resize_event;
+ SDL_zero(resize_event);
+ resize_event.type = SDL_WINDOWEVENT;
+ resize_event.window.event = SDL_WINDOWEVENT_RESIZED;
+ resize_event.window.data1 = 800; // new width
+ resize_event.window.data2 = 600; // new height
+ SDL_PushEvent(&resize_event);
+ input_system.update();
+ event_manager.dispatch_events();
+ EXPECT_TRUE(callback_triggered);
+}
+TEST_F(InputTest, WindowMoveTest) {
+ GameObject obj = mgr.new_object("camera", "camera", vec2{0, 0}, 0, 1);
+ auto & camera = obj.add_component<Camera>(
+ ivec2{0, 0}, vec2{500, 500}, Camera::Data{.bg_color = Color::WHITE, .zoom = 1.0f});
+ camera.active = true;
+ bool callback_triggered = false;
+ EventHandler<WindowMoveEvent> on_window_move = [&](const WindowMoveEvent & event) {
+ callback_triggered = true;
+ EXPECT_EQ(event.delta_move.x, 800);
+ EXPECT_EQ(event.delta_move.y, 600);
+ return false;
+ };
+ event_manager.subscribe<WindowMoveEvent>(on_window_move);
+ SDL_Event resize_event;
+ SDL_zero(resize_event);
+ resize_event.type = SDL_WINDOWEVENT;
+ resize_event.window.event = SDL_WINDOWEVENT_MOVED;
+ resize_event.window.data1 = 800; // new width
+ resize_event.window.data2 = 600; // new height
+ SDL_PushEvent(&resize_event);
+ input_system.update();
+ event_manager.dispatch_events();
+ EXPECT_TRUE(callback_triggered);
+}