Out-of-Window Selection Rectangle
How can I implement a selection rectangle that works even if the user drags outside the window?
Implementing a selection rectangle that works outside the window requires combining mouse capture with proper state tracking. Here's a complete implementation that handles this scenario:
#include <SDL.h>
#include <iostream>
class SelectionRectangle {
public:
SelectionRectangle() : isSelecting{false} {}
void HandleMouseDown(
const SDL_MouseButtonEvent& event) {
if (event.button == SDL_BUTTON_LEFT) {
startX = event.x;
startY = event.y;
currentX = event.x;
currentY = event.y;
isSelecting = true;
// Enable mouse capture for out-of-window
// tracking
SDL_CaptureMouse(SDL_TRUE);
}
}
void HandleMouseUp(
const SDL_MouseButtonEvent& event) {
if (event.button == SDL_BUTTON_LEFT) {
isSelecting = false;
SDL_CaptureMouse(SDL_FALSE);
// Calculate final selection area
int width = std::abs(currentX - startX);
int height = std::abs(currentY - startY);
std::cout << "Final selection: " << width
<< "x" << height << " pixels\n";
}
}
void HandleMouseMotion(
const SDL_MouseMotionEvent& event) {
if (isSelecting) {
currentX = event.x;
currentY = event.y;
}
}
void Render(SDL_Renderer* renderer) {
if (isSelecting) {
// Calculate rectangle dimensions
int x = std::min(startX, currentX);
int y = std::min(startY, currentY);
int w = std::abs(currentX - startX);
int h = std::abs(currentY - startY);
// Draw selection rectangle
SDL_SetRenderDrawColor(
renderer, 0, 120, 255, 255);
SDL_Rect selectionRect{x, y, w, h};
SDL_RenderDrawRect(renderer,
&selectionRect);
// Draw semi-transparent fill
SDL_SetRenderDrawColor(
renderer, 0, 120, 255, 64);
SDL_SetRenderDrawBlendMode(
renderer, SDL_BLENDMODE_BLEND);
SDL_RenderFillRect(renderer,
&selectionRect);
}
}
bool IsSelecting() const {
return isSelecting;
}
private:
bool isSelecting;
int startX, startY;
int currentX, currentY;
};
int main(int argc, char** argv) {
SDL_Init(SDL_INIT_VIDEO);
SDL_Window* window =
SDL_CreateWindow("Selection Rectangle",
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
800, 600,
SDL_WINDOW_SHOWN);
SDL_Renderer* renderer =
SDL_CreateRenderer(window, -1,
SDL_RENDERER_ACCELERATED);
SelectionRectangle selection;
bool running = true;
while (running) {
SDL_Event event;
while (SDL_PollEvent(&event)) {
if (event.type ==
SDL_QUIT) { running = false; } else if (
event.type == SDL_MOUSEBUTTONDOWN) {
selection.HandleMouseDown(event.button);
} else if (event.type ==
SDL_MOUSEBUTTONUP) {
selection.HandleMouseUp(event.button);
} else if (event.type ==
SDL_MOUSEMOTION) {
selection.HandleMouseMotion(
event.motion);
}
}
// Clear and render
SDL_SetRenderDrawColor(renderer, 255, 255,
255, 255);
SDL_RenderClear(renderer);
selection.Render(renderer);
SDL_RenderPresent(renderer);
}
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
Key features of this implementation:
Mouse Capture Management
- Enables capture when selection starts
- Disables capture when selection ends
- Handles out-of-window mouse movement
Selection State Tracking
- Stores both start and current positions
- Updates continuously during mouse movement
- Calculates correct dimensions regardless of drag direction
Visual Feedback
- Renders selection rectangle with outline
- Includes semi-transparent fill
- Updates in real-time as selection changes
Error Handling
- Safely manages mouse capture state
- Handles window focus changes properly
- Cleans up resources appropriately
Mouse Capture and Global Mouse State
Learn how to track mouse movements and button states across your entire application, even when the mouse leaves your window.