Pixel Density and High-DPI Displays

UI Elements and DPI

How do I handle DPI scaling for UI elements like buttons that need to stay a specific physical size?

Abstract art representing computer programming

When creating UI elements that need to maintain a consistent physical size across different DPI settings, we need to consider both scaling and positioning. Here's a comprehensive approach to DPI-aware UI elements.

Creating a Basic UI System

Let's create a simple button class that maintains physical size:

// UISystem.h
#include <SDL.h>
#include <string>
#include <functional>

float GetDPIScale(SDL_Window* Window) {/*...*/} class Button { SDL_Rect Bounds; std::string Text; // Width in screen coordinates float PhysicalWidth; // Height in screen coordinates float PhysicalHeight; public: Button( float X, float Y, float Width, float Height, const std::string& ButtonText) : PhysicalWidth{Width} , PhysicalHeight{Height} , Text{ButtonText} { Bounds.x = int(X); Bounds.y = int(Y); // Initial size without scaling UpdateSize(1.0f); } void UpdateSize(float Scale) { Bounds.w = int(PhysicalWidth * Scale); Bounds.h = int(PhysicalHeight * Scale); } void Draw(SDL_Renderer* Renderer) { // Draw button background SDL_SetRenderDrawColor( Renderer, 200, 200, 200, 255); SDL_RenderFillRect(Renderer, &Bounds); // Draw border SDL_SetRenderDrawColor( Renderer, 100, 100, 100, 255); SDL_RenderDrawRect(Renderer, &Bounds); } bool Contains(int X, int Y) { return X >= Bounds.x && X < Bounds.x + Bounds.w && Y >= Bounds.y && Y < Bounds.y + Bounds.h; } }; class UISystem { std::vector<Button> Buttons; float CurrentScale{1.0f}; public: void AddButton( float X, float Y, float Width, float Height, const std::string& Text) { Buttons.emplace_back( X, Y, Width, Height, Text); Buttons.back().UpdateSize(CurrentScale); } void UpdateDPIScale(float NewScale) { if (CurrentScale != NewScale) { CurrentScale = NewScale; for (auto& Button : Buttons) { Button.UpdateSize(NewScale); } } } void Draw(SDL_Renderer* Renderer) { for (auto& Button : Buttons) { Button.Draw(Renderer); } } };

Using the UI System

Here's how to use this system in a real application:

// main.cpp
#include <SDL.h>
#include "UISystem.h"

int main() {
  SDL_SetHint(
    SDL_HINT_WINDOWS_DPI_SCALING, "1");
  SDL_Init(SDL_INIT_VIDEO);

  SDL_Window* Window{
    SDL_CreateWindow(
      "UI Scaling Demo",
      SDL_WINDOWPOS_UNDEFINED,
      SDL_WINDOWPOS_UNDEFINED,
      800, 600,
      SDL_WINDOW_ALLOW_HIGHDPI
    )};

  SDL_Renderer* Renderer{
    SDL_CreateRenderer(
      Window, -1, SDL_RENDERER_ACCELERATED)};

  UISystem UI;
  UI.AddButton(50, 50, 200, 60, "Click Me");
  UI.AddButton(50, 150, 200, 60, "Options");

  float Scale{GetDPIScale(Window)};
  UI.UpdateDPIScale(Scale);

  SDL_Event E;
  bool Running{true};
  while (Running) {
    while (SDL_PollEvent(&E)) {
      if (E.type == SDL_QUIT) Running = false;
      if (E.type == SDL_WINDOWEVENT) {
        if (
           E.window.event == SDL_WINDOWEVENT_RESIZED
        || E.window.event == SDL_WINDOWEVENT_MOVED
        ) {
          Scale = GetDPIScale(Window);
          UI.UpdateDPIScale(Scale);
        }
      }
    }

    SDL_SetRenderDrawColor(
      Renderer, 240, 240, 240, 255);
    SDL_RenderClear(Renderer);

    UI.Draw(Renderer);

    SDL_RenderPresent(Renderer);
  }

  SDL_DestroyRenderer(Renderer);
  SDL_DestroyWindow(Window);
  SDL_Quit();
  return 0;
}

The key points to remember when implementing DPI-aware UI elements are:

  • Store physical sizes separately from rendered sizes
  • Update all UI elements when DPI scale changes
  • Consider input handling relative to scaled coordinates
  • Test with different DPI settings to ensure consistency

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

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:

  • 71 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