Skip to content

Commit 42bcfcf

Browse files
committed
test: write more mouse tests
1 parent 899a368 commit 42bcfcf

4 files changed

Lines changed: 832 additions & 37 deletions

File tree

tests/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ set(SDL_TEST_SOURCES
1111
sdl/SDLTestMain.cpp
1212
sdl/MouseTests.cpp
1313
sdl/TestElements.h
14+
sdl/ExtendedTestElements.h
1415
sdl/TestContext.h
1516
sdl/TestConfig.h
1617
sdl/RobotSDLTestFixture.h
@@ -43,6 +44,6 @@ add_custom_target(build_sdl_tests ALL DEPENDS ${SDL_TEST_NAME})
4344
# Add automated tests (exclude interactive tests)
4445
add_test(
4546
NAME SDLFunctionalTests
46-
COMMAND ${SDL_TEST_NAME}
47+
COMMAND ${SDL_TEST_NAME} --run-tests
4748
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/bin
4849
)

tests/sdl/ExtendedTestElements.h

Lines changed: 294 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,294 @@
1+
#pragma once
2+
3+
#include <SDL.h>
4+
#include <string>
5+
#include <functional>
6+
#include <string_view>
7+
#include <optional>
8+
#include <memory>
9+
#include <chrono>
10+
11+
#include "TestElements.h"
12+
13+
namespace RobotTest {
14+
15+
// Extended button that tracks double clicks
16+
class DoubleClickButton : public TestElement {
17+
public:
18+
DoubleClickButton(SDL_Rect rect, Color color, std::string name)
19+
: rect_(rect), color_(color), name_(std::move(name)),
20+
clicked_(false), doubleClicked_(false),
21+
lastClickTime_(std::chrono::steady_clock::now() - std::chrono::seconds(10)) {}
22+
23+
void draw(SDL_Renderer* renderer) const override {
24+
// Set color based on state
25+
Color drawColor = doubleClicked_ ? color_ :
26+
clicked_ ? color_.darken(0.3f) : color_.darken(0.6f);
27+
28+
SDL_SetRenderDrawColor(renderer, drawColor.r, drawColor.g, drawColor.b, drawColor.a);
29+
SDL_RenderFillRect(renderer, &rect_);
30+
31+
// Draw border
32+
SDL_SetRenderDrawColor(renderer, Color::White().r, Color::White().g, Color::White().b, Color::White().a);
33+
SDL_RenderDrawRect(renderer, &rect_);
34+
}
35+
36+
[[nodiscard]] bool isInside(int x, int y) const override {
37+
return (x >= rect_.x && x < rect_.x + rect_.w &&
38+
y >= rect_.y && y < rect_.y + rect_.h);
39+
}
40+
41+
void handleClick() {
42+
auto now = std::chrono::steady_clock::now();
43+
auto timeSinceLastClick = std::chrono::duration_cast<std::chrono::milliseconds>(
44+
now - lastClickTime_).count();
45+
46+
if (timeSinceLastClick < 300) { // Double-click threshold
47+
doubleClicked_ = true;
48+
} else {
49+
clicked_ = true;
50+
doubleClicked_ = false;
51+
}
52+
53+
lastClickTime_ = now;
54+
}
55+
56+
[[nodiscard]] bool wasClicked() const {
57+
return clicked_;
58+
}
59+
60+
[[nodiscard]] bool wasDoubleClicked() const {
61+
return doubleClicked_;
62+
}
63+
64+
void reset() override {
65+
clicked_ = false;
66+
doubleClicked_ = false;
67+
lastClickTime_ = std::chrono::steady_clock::now() - std::chrono::seconds(10);
68+
}
69+
70+
[[nodiscard]] SDL_Rect getRect() const override {
71+
return rect_;
72+
}
73+
74+
[[nodiscard]] std::string_view getName() const override {
75+
return name_;
76+
}
77+
78+
private:
79+
SDL_Rect rect_;
80+
Color color_;
81+
std::string name_;
82+
bool clicked_;
83+
bool doubleClicked_;
84+
std::chrono::time_point<std::chrono::steady_clock> lastClickTime_;
85+
};
86+
87+
// Button that responds to right clicks
88+
class RightClickButton : public TestElement {
89+
public:
90+
RightClickButton(SDL_Rect rect, Color color, std::string name)
91+
: rect_(rect), color_(color), name_(std::move(name)), rightClicked_(false) {}
92+
93+
void draw(SDL_Renderer* renderer) const override {
94+
// Set color based on state
95+
Color drawColor = rightClicked_ ? color_ : color_.darken(0.5f);
96+
97+
SDL_SetRenderDrawColor(renderer, drawColor.r, drawColor.g, drawColor.b, drawColor.a);
98+
SDL_RenderFillRect(renderer, &rect_);
99+
100+
// Draw border
101+
SDL_SetRenderDrawColor(renderer, Color::White().r, Color::White().g, Color::White().b, Color::White().a);
102+
SDL_RenderDrawRect(renderer, &rect_);
103+
}
104+
105+
[[nodiscard]] bool isInside(int x, int y) const override {
106+
return (x >= rect_.x && x < rect_.x + rect_.w &&
107+
y >= rect_.y && y < rect_.y + rect_.h);
108+
}
109+
110+
void handleRightClick() {
111+
rightClicked_ = true;
112+
}
113+
114+
[[nodiscard]] bool wasRightClicked() const {
115+
return rightClicked_;
116+
}
117+
118+
void reset() override {
119+
rightClicked_ = false;
120+
}
121+
122+
[[nodiscard]] SDL_Rect getRect() const override {
123+
return rect_;
124+
}
125+
126+
[[nodiscard]] std::string_view getName() const override {
127+
return name_;
128+
}
129+
130+
private:
131+
SDL_Rect rect_;
132+
Color color_;
133+
std::string name_;
134+
bool rightClicked_;
135+
};
136+
137+
// Scrollable area for testing scroll functionality
138+
class ScrollArea : public TestElement {
139+
public:
140+
ScrollArea(SDL_Rect rect, Color color, std::string name)
141+
: rect_(rect), color_(color), name_(std::move(name)), scrollY_(0),
142+
contentHeight_(500) // Content is taller than visible area
143+
{}
144+
145+
void draw(SDL_Renderer* renderer) const override {
146+
// Draw visible area background
147+
SDL_SetRenderDrawColor(renderer, color_.r, color_.g, color_.b, color_.a);
148+
SDL_RenderFillRect(renderer, &rect_);
149+
150+
// Draw border
151+
SDL_SetRenderDrawColor(renderer, Color::Black().r, Color::Black().g, Color::Black().b, Color::Black().a);
152+
SDL_RenderDrawRect(renderer, &rect_);
153+
154+
// Set up a clipping rectangle for the content area
155+
SDL_Rect clipRect = rect_;
156+
SDL_RenderSetClipRect(renderer, &clipRect);
157+
158+
// Draw content (series of colored lines)
159+
const int lineHeight = 20;
160+
const int numLines = contentHeight_ / lineHeight;
161+
162+
for (int i = 0; i < numLines; ++i) {
163+
// Calculate line Y position with scroll offset
164+
int lineY = rect_.y + (i * lineHeight) - scrollY_;
165+
166+
// Skip if line is outside visible area
167+
if (lineY + lineHeight < rect_.y || lineY > rect_.y + rect_.h) {
168+
continue;
169+
}
170+
171+
// Alternate colors
172+
Color lineColor = (i % 2 == 0) ? Color::Blue() : Color::Green();
173+
SDL_SetRenderDrawColor(renderer, lineColor.r, lineColor.g, lineColor.b, lineColor.a);
174+
175+
SDL_Rect lineRect = {rect_.x + 2, lineY, rect_.w - 4, lineHeight};
176+
SDL_RenderFillRect(renderer, &lineRect);
177+
178+
// Draw line number
179+
// Text rendering would go here if we had SDL_ttf
180+
}
181+
182+
// Draw scrollbar track
183+
SDL_Rect scrollTrack = {
184+
rect_.x + rect_.w - 15,
185+
rect_.y,
186+
15,
187+
rect_.h
188+
};
189+
SDL_SetRenderDrawColor(renderer, 50, 50, 50, 255);
190+
SDL_RenderFillRect(renderer, &scrollTrack);
191+
192+
// Draw scrollbar thumb
193+
float visibleRatio = static_cast<float>(rect_.h) / contentHeight_;
194+
int thumbHeight = static_cast<int>(rect_.h * visibleRatio);
195+
int thumbY = rect_.y + static_cast<int>((static_cast<float>(scrollY_) /
196+
(contentHeight_ - rect_.h)) * (rect_.h - thumbHeight));
197+
198+
SDL_Rect scrollThumb = {
199+
rect_.x + rect_.w - 15,
200+
thumbY,
201+
15,
202+
thumbHeight
203+
};
204+
SDL_SetRenderDrawColor(renderer, 150, 150, 150, 255);
205+
SDL_RenderFillRect(renderer, &scrollThumb);
206+
207+
// Reset clipping rectangle
208+
SDL_RenderSetClipRect(renderer, nullptr);
209+
}
210+
211+
[[nodiscard]] bool isInside(int x, int y) const override {
212+
return (x >= rect_.x && x < rect_.x + rect_.w &&
213+
y >= rect_.y && y < rect_.y + rect_.h);
214+
}
215+
216+
void handleScroll(int scrollAmount) {
217+
scrollY_ += scrollAmount * 15; // Scale the scroll amount
218+
219+
// Clamp scrollY to valid range
220+
if (scrollY_ < 0) {
221+
scrollY_ = 0;
222+
}
223+
224+
int maxScroll = contentHeight_ - rect_.h;
225+
if (maxScroll < 0) {
226+
maxScroll = 0;
227+
}
228+
229+
if (scrollY_ > maxScroll) {
230+
scrollY_ = maxScroll;
231+
}
232+
}
233+
234+
[[nodiscard]] int getScrollY() const {
235+
return scrollY_;
236+
}
237+
238+
void reset() override {
239+
scrollY_ = 0;
240+
}
241+
242+
[[nodiscard]] SDL_Rect getRect() const override {
243+
return rect_;
244+
}
245+
246+
[[nodiscard]] std::string_view getName() const override {
247+
return name_;
248+
}
249+
250+
private:
251+
SDL_Rect rect_;
252+
Color color_;
253+
std::string name_;
254+
int scrollY_;
255+
int contentHeight_;
256+
};
257+
258+
// Factory function to create a double-click button
259+
inline std::unique_ptr<DoubleClickButton> createDoubleClickButton(
260+
int x, int y, int width, int height,
261+
Color color, std::string name)
262+
{
263+
return std::make_unique<DoubleClickButton>(
264+
SDL_Rect{x, y, width, height},
265+
color,
266+
std::move(name)
267+
);
268+
}
269+
270+
// Factory function to create a right-click button
271+
inline std::unique_ptr<RightClickButton> createRightClickButton(
272+
int x, int y, int width, int height,
273+
Color color, std::string name)
274+
{
275+
return std::make_unique<RightClickButton>(
276+
SDL_Rect{x, y, width, height},
277+
color,
278+
std::move(name)
279+
);
280+
}
281+
282+
// Factory function to create a scroll area
283+
inline std::unique_ptr<ScrollArea> createScrollArea(
284+
int x, int y, int width, int height,
285+
Color color, std::string name)
286+
{
287+
return std::make_unique<ScrollArea>(
288+
SDL_Rect{x, y, width, height},
289+
color,
290+
std::move(name)
291+
);
292+
}
293+
294+
} // namespace RobotTest

0 commit comments

Comments
 (0)