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.

Questions & Answers

Answers are generated by AI models and may not have been reviewed. Be mindful when running any code on your device.

Relative vs Global Mouse Coordinates
What's the difference between relative and global mouse coordinates? When should I use each?
Mouse Capture and Focus Loss
Why does mouse capture get disabled when my window loses focus? How can I prevent this?
Selective Mouse Button Auto-Capture
Is there a way to disable auto-capture for specific mouse buttons but keep it for others?
Or Ask your Own Question
Get an immediate answer to your specific question using our AI assistant