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
This Question is from the Lesson:

Pixel Density and High-DPI Displays

Learn how to create SDL applications that look great on modern displays across different platforms

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

This Question is from the Lesson:

Pixel Density and High-DPI Displays

Learn how to create SDL applications that look great on modern displays across different platforms

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

This course includes:

  • 128 Lessons
  • 92% Positive Reviews
  • Regularly Updated
  • Help and FAQs
Free, Unlimited Access

Professional C++

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

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