Building a Modular UI System

Implementing Responsive UI Design in SDL

What's the best approach for implementing a responsive design that adapts to different window sizes?

Abstract art representing computer programming

Implementing a responsive design in SDL involves creating a flexible layout system that can adapt to different window sizes. Here's an approach to create a basic responsive UI:

First, let's define a LayoutManager class:

#include <SDL.h>
#include <memory>
#include <vector>

class UIComponent {
public:
  virtual void SetPosition(int x, int y) = 0;
  virtual void SetSize(int w, int h) = 0;
  virtual void Render(SDL_Surface* surface) = 0;
};

class LayoutManager {
private:
  std::vector<std::unique_ptr<UIComponent>>
  components;
  int windowWidth;
  int windowHeight;

public:
  LayoutManager(int w, int h)
    : windowWidth(w), windowHeight(h) {}

  void AddComponent(
      std::unique_ptr<UIComponent> component) {
    components.push_back(std::move(component));
  }

  void UpdateLayout() {
    // This is where the responsive layout logic
    // goes. For this example, we'll implement
    // a simple grid layout
    int gridColumns = 3;
    int gridRows =
        (components.size() + gridColumns - 1) /
        gridColumns;

    int cellWidth = windowWidth / gridColumns;
    int cellHeight = windowHeight / gridRows;

    for (size_t i = 0; i < components.size();
         ++i) {
      int row = i / gridColumns;
      int col = i % gridColumns;

      int x = col * cellWidth;
      int y = row * cellHeight;

      components[i]->SetPosition(x, y);
      components[i]->SetSize(cellWidth,
                             cellHeight);
    }
  }

  void Render(SDL_Surface* surface) {
    for (const auto& component : components) {
      component->Render(surface);
    }
  }

  void Resize(int w, int h) {
    windowWidth = w;
    windowHeight = h;
    UpdateLayout();
  }
};

Now, let's create a simple Button class that implements the UIComponent interface:

class Button : public UIComponent {
private:
  SDL_Rect bounds;
  SDL_Color color;

public:
  Button(SDL_Color c)
    : color(c) {}

  void SetPosition(int x, int y) override {
    bounds.x = x;
    bounds.y = y;
  }

  void SetSize(int w, int h) override {
    bounds.w = w;
    bounds.h = h;
  }

  void Render(SDL_Surface* surface) override {
    SDL_FillRect(surface, &bounds,
                 SDL_MapRGB(surface->format,
                            color.r, color.g,
                            color.b));
  }
};

Finally, let's implement the main application loop with responsive design:

#include <iostream>

class Application {
private:
  LayoutManager layout;

public:
  Application(int w, int h)
    : layout(w, h) {
    // Add some example components
    layout.AddComponent(
        std::make_unique<Button>(
            SDL_Color{255, 0, 0, 255}));
    layout.AddComponent(
        std::make_unique<Button>(
            SDL_Color{0, 255, 0, 255}));
    layout.AddComponent(
        std::make_unique<Button>(
            SDL_Color{0, 0, 255, 255}));
    layout.AddComponent(
        std::make_unique<Button>(
            SDL_Color{255, 255, 0, 255}));
    layout.UpdateLayout();
  }

  void HandleEvent(const SDL_Event& event) {
    if (event.type == SDL_WINDOWEVENT &&
        event.window.event ==
        SDL_WINDOWEVENT_SIZE_CHANGED) {
      layout.Resize(event.window.data1,
                    event.window.data2);
    }
  }

  void Render(SDL_Surface* surface) {
    SDL_FillRect(surface, nullptr,
                 SDL_MapRGB(surface->format,
                            255, 255, 255));
    layout.Render(surface);
  }
};

int main(int argc, char* argv[]) {
  if (SDL_Init(SDL_INIT_VIDEO) < 0) {
    std::cerr << "SDL could not initialize! "
        "SDL_Error: "
        << SDL_GetError() << "\n";
    return 1;
  }

  SDL_Window* window = SDL_CreateWindow(
      "SDL Responsive UI",
      SDL_WINDOWPOS_UNDEFINED,
      SDL_WINDOWPOS_UNDEFINED, 800, 600,
      SDL_WINDOW_RESIZABLE);
  if (window == nullptr) {
    std::cerr << "Window could not be created! "
        "SDL_Error: "
        << SDL_GetError() << "\n";
    return 1;
  }

  SDL_Surface* screenSurface =
      SDL_GetWindowSurface(window);

  Application app(800, 600);

  SDL_Event e;
  bool quit = false;

  while (!quit) {
    while (SDL_PollEvent(&e) != 0) {
      if (e.type == SDL_QUIT) { quit = true; }
      app.HandleEvent(e);
    }

    app.Render(screenSurface);
    SDL_UpdateWindowSurface(window);
  }

  SDL_DestroyWindow(window);
  SDL_Quit();

  return 0;
}

This implementation creates a simple responsive UI that adapts to different window sizes. The LayoutManager class handles the positioning and sizing of UI components based on the current window size. When the window is resized, the layout is updated automatically.

In a real-world application, you'd want to expand on this basic framework:

  • Implement more sophisticated layout algorithms (e.g., flexbox-like layouts)
  • Add support for different types of components (e.g., text, images)
  • Implement nested layouts for more complex UIs
  • Add support for different screen orientations (landscape vs. portrait)
  • Implement minimum and maximum sizes for components

Remember to handle edge cases, such as very small window sizes or extreme aspect ratios. Also, consider implementing smooth transitions when resizing to enhance the user experience.

This example provides a foundation for creating responsive UIs in your SDL application, allowing it to adapt to different screen sizes and window configurations.

This Question is from the Lesson:

Building a Modular UI System

Learn how to create a flexible and extensible UI system using C++ and SDL, focusing on component hierarchy and polymorphism.

Answers to questions are automatically generated and may not have been reviewed.

This Question is from the Lesson:

Building a Modular UI System

Learn how to create a flexible and extensible UI system using C++ and SDL, focusing on component hierarchy and polymorphism.

sdl2-promo.jpg
Part of the course:

Game Dev with SDL2

Learn C++ and SDL development by creating hands on, practical projects inspired by classic retro games

Free, unlimited access

This course includes:

  • 46 Lessons
  • 100+ Code Samples
  • 91% Positive Reviews
  • Regularly Updated
  • Help and FAQ
Free, Unlimited Access

Professional C++

Comprehensive course covering advanced concepts, and how to use them on large-scale projects.

Screenshot from Warhammer: Total War
Screenshot from Tomb Raider
Screenshot from Jedi: Fallen Order
Contact|Privacy Policy|Terms of Use
Copyright © 2024 - All Rights Reserved