Skip to content

ui

Namespace-scope declarations of ui from the themes headers.

Enumerations

ButtonState

enum class ButtonState

Header: winui/ui/themes/Theme.hpp.

The interaction state a control derives from its input flags. Focus is not one of them. The focus visual is a separate ring a control draws on top of whichever of these four states it is in, so a focused and hovered control keeps its hover look.

Value
Normal At rest.
Hover The pointer is over the control.
Pressed Held down by the pointer or the keyboard.
Disabled The control is disabled; wins over the other three.

CornerPreference

enum class CornerPreference

Header: winui/ui/themes/Theme.hpp.

How the corners of the system-drawn window frame are rounded. An era theme sets this so the frame matches the content, so a Windows 95 theme asks for square corners. Windows 11 only.

Value
Default The system decides: round on Windows 11.
DoNotRound Square corners.
Round The standard window radius.
RoundSmall The smaller menu and flyout radius.

FrameColorKind

enum class FrameColorKind

Header: winui/ui/themes/Theme.hpp.

Which of the four answers a FrameColor holds.

Value
Follow No opinion; the next layer decides (see follow()).
SystemDefault The system's own color.
None Draw nothing. For the border only.
Custom The color in operator*().

ThemeDividerVisual

enum class ThemeDividerVisual

Header: winui/ui/themes/Theme.hpp.

How dividers and separators are drawn, Toolbar's separators included: the classic two-line etched groove from surfaces.separator_light and separator_dark, the default, or Fluent's flat single line in colors.divider. Only Theme::fluent() picks the flat line. Every other theme keeps the groove.

Value
EtchedGroove Two 1px lines, surfaces.separator_light / separator_dark.
FlatStroke One 1px line in colors.divider.

ThemeDisclosureVisual

enum class ThemeDisclosureVisual

Header: winui/ui/themes/Theme.hpp.

How a control marks that something opens, drops down or expands: Expander, TreeView, NavigationShell, Breadcrumb, DropdownButton, SplitButton, NumberBox's spin buttons and a menu's submenu arrow. Fluent and every theme after Windows 2000 draw the icon font's chevrons. The classic themes draw solid arrows and plus/minus boxes.

Value
IconChevron The icon font's line chevrons (glyphs::ChevronDown and the rest).
ClassicArrow The classic solid arrows, 7 x 4 at 96 DPI (draw_classic_arrow()), as on scroll bars and submenus, and a tree view's 9 x 9 plus/minus box (draw_classic_tree_button()).

ThemePopupShadow

enum class ThemePopupShadow

Header: winui/ui/themes/Theme.hpp.

Which drop shadow an open popup casts (render/OverlayShadow.hpp). Fluent's two-light shadow follows from an elevation scale, where every kind of surface has a height. Aero casts no shadow under a button, card or panel. Its only shadow is an offset block with a 5 px fall-off under a menu, tooltip or drop-down. Defaults to the Fluent shadow.

Value
FluentTwoLight Fluent's soft two-light elevation shadow.
AeroDropShadow An offset block with a 5 px fall-off, as Luna and Aero draw it.
None No shadow at all. Menus, drop-downs and dialogs are plain rectangles on the surface below them.

ThemePopupAnimation

enum class ThemePopupAnimation

Header: winui/ui/themes/Theme.hpp.

How a menu (MenuFlyout, the menu bar's menus, a context menu) and a drop-down list (ComboBox) come into view. Every era animates these differently: - Fluent 2, Fluent, MDL2 and Metro (the defaults): a menu slides out from its own edge over 250 ms and fades out over 83 ms. A drop-down list appears at once. - Aero and Luna follow the system's animation settings. A menu fades in when menu fading is on, slides in when it is off, and does neither when menu animation is off. A drop-down list slides open when list box animation is on. Both run 200 ms, and a menu closes at once. resolve_theme() reads the settings from OsThemeSnapshot. - Windows 9x, 3.x and 1.x/2.x: no animation.

Value
Slide Slides out from its own edge.
Fade Fades in.
None Appears at once.

ThemeVariant

enum class ThemeVariant

Header: winui/ui/themes/Theme.hpp.

The design language (era) the whole UI is drawn in, chosen independently of the Windows version the app runs on. ThemeVariant::System, the default, draws the look of the running Windows: Fluent 2 on Windows 11 and Fluent before it. Fluent2 is the primary target.

System, Fluent2 and Fluent are always available. The era themes (Mdl2 to Windows1x) are linked into an app only once it calls enable_era_themes(). Before that, asking for one draws the System look.

Dark and light are not variants. They are set by ThemeMode, which by default follows the system. Fluent2, Fluent, Metro and Mdl2 have a dark and a light palette and honor ThemeMode and ThemeRequest::accent_override. Every other variant has one fixed, light palette and ignores both (theme_variant_supports_dark_mode()).

Under high contrast every variant draws its own era's high-contrast look. Windows 9x, 3.x and 1.x take the contrast colors as one more color scheme, Luna and Aero fall back to the Classic look as XP and 7 did, and Metro, MDL2 and Fluent keep their shapes in contrast colors. The colors are the system's contrast theme while one is on, and the era's own contrast scheme when an app forces ThemeMode::HighContrast without one.

Example:

int run_retro()
{
    ui::Window retro{{
        .title = "Retro",
        .theme = ui::ThemeRequest{.variant = ui::ThemeVariant::Windows9x}, // light-only, ignores ThemeMode
    }};
    return ui::run(retro);
}

Value
System The look of the running Windows: Fluent2 on Windows 11 and Fluent on Windows 10 and earlier (OsThemeSnapshot::system_variant). The default. A resolved Theme never reports it. Its Theme::variant is the variant System stood for.
Fluent2 Fluent 2, Windows 11's design, whatever Windows the app runs on. The primary target, with resolve_high_contrast() under high contrast.
Fluent Fluent 1: the original Fluent Design System as it shipped on Windows 10, from 1709 (2017) through early 2021. Follows dark and light mode and the accent, like Fluent2. Windows 11 is Fluent2. See resolve_fluent1() for what this variant changes.
Mdl2 MDL2 ("Microsoft Design Language 2"): Windows 10's original flat, square look with the accent as its only color, as it shipped from 1507 (2015-07-29) through 1703 (2017-04-11), before Fluent. No material, no elevation, and no rounded corners except the Slider thumb and the ToggleSwitch track. Follows dark and light mode and the accent, like Fluent2, Fluent and Metro. Its colors come from the 24 base colors of an Mdl2Palette, in a light and a dark set. The name is a press convention. No Microsoft document of the era uses it.
Metro MDL ("Metro Design Language"): Windows 8 and 8.1 merged into one entry. It follows Windows 8.1, with its dark mode and user accent.
Aero Aero: Windows Vista and 7 merged into one entry, defaulting to Windows 7's column. The two releases barely differ. The only change a control shows is disabled text, which went from #808080 to #6D6D6D. Aero has no control accent, since the user's glass color tinted the frame, taskbar and Start menu but never a control. This variant ignores both ThemeMode's light and dark and ThemeRequest::accent_override.
Luna Luna: Windows XP's default visual style.
Windows9x Windows 9x: Windows 95, 98, and 2000 merged into one entry. Defaults to the Windows 95 and 98 "Windows Standard" scheme (ClassicPalette::windows_standard()). ThemeRequest::classic_scheme swaps in any other ClassicPalette, such as ClassicPalette::windows_standard_2000().
Windows3x Windows 3.x: before hot tracking, Active Desktop and the four-color bevel of Windows 95.
Windows1x Early Windows: Windows 1.01 (1985-11) through 2.11 (1989-03), the design language Windows 3.0 replaced in May 1990. It has no sense of depth at all: no bevel, no gray #C0C0C0 face, no light source, no highlight and shadow pair and no drop shadow. All of its chrome is black and white, and the only depth cue is a one-pixel frame line. It has ten colors, thirteen from 2.0, with no button face, selection or disabled-text color among them. That is why its colors are an EarlyPalette instead of a ClassicPalette, and its theme comes from Theme::early() instead of Theme::classic(). What sets "Windows 1" apart from "Windows 2" happens at 2.03 in December 1987, when windows stopped being tiled. This one variant covers both and defaults to the Windows 2.03 color palette. EarlyPalette::windows_1x_mono() and the other two palettes are one ThemeRequest::early_scheme away. The four palettes are separate looks, so pick a version first, then a display type, and do not mix them.

ThemeMode

enum class ThemeMode

Header: winui/ui/themes/ThemeSource.hpp.

Which light, dark or contrast appearance a ThemeRequest asks for.

Only the variants for which theme_variant_supports_dark_mode() is true tell Light and Dark apart. HighContrast applies to every variant.

Value
System Follow the system's light or dark setting as it changes (the default).
Light Always light, whatever the system setting.
Dark Always dark, whatever the system setting.
HighContrast The system's contrast theme while one is on, otherwise the variant's own contrast colors (see resolve_theme()).

AnimationPreference

enum class AnimationPreference

Header: winui/ui/themes/ThemeSource.hpp.

Whether controls animate: follow the system's "Animation effects" setting, or force it either way.

With animations off, every transition the framework plays itself lands on its end state at once: control state tweens, transitions, implicit and brush transitions, popup motion, animated icons, animated scrolling and connected animations. Timers that are not animations (tooltip delay, caret blink, key repeat) keep running, and an indeterminate ProgressBar or ProgressRing keeps moving, since that motion is what tells the user work is going on.

Example:

// A "Reduce motion" switch in an app's settings page:
void set_reduce_motion(bool reduce_motion)
{
    ui::ThemeRequest request = window.theme_request();
    request.animations       = reduce_motion ? ui::AnimationPreference::Off : ui::AnimationPreference::System;
    window.set_theme(request);
}

Value
System Follow OsThemeSnapshot::animations_enabled as it changes (the default).
On Always animate, whatever the system setting.
Off Never animate, whatever the system setting.

Functions

classic_lighter

Color classic_lighter(const Color& c, float percent = 1.0f)

Header: winui/ui/themes/ClassicPalette.hpp.

Lightens c the way the classic 3-D ramp is derived from a face color. The color's luminosity moves toward white by up to half the remaining distance, and percent, clamped to [0,1], scales that move. Hue, saturation and alpha are kept.

Example:

const ui::Color face  = ui::Color::from_rgba(128, 64, 128); // a custom face
const ui::Color light = ui::classic_lighter(face, 0.5f);    // the bevel's outer light ring
const ui::Color dark  = ui::classic_darker(face, 1.0f);     // the bevel's outer dark ring

classic_darker

Color classic_darker(const Color& c, float percent = 1.0f)

Header: winui/ui/themes/ClassicPalette.hpp.

Darkens c the same way classic_lighter() lightens it. The luminosity moves toward black by up to a third, scaled by percent, which is clamped to [0,1]. Hue, saturation and alpha are kept.

classic_bevel_ramp_from_face

ClassicBevelRamp classic_bevel_ramp_from_face(const Color& face)

Header: winui/ui/themes/ClassicPalette.hpp.

Derives the whole classic 3-D ramp from one face color. light is classic_lighter(face, 0.5), highlight is classic_lighter(face, 1.0), shadow is classic_darker(face, 0.5) and dark_shadow is classic_darker(face, 1.0).

When face is exactly one of the two standard grays, the ramp that era ships is returned as is, because neither can be derived: - 0xC0C0C0 (Windows 95 and 98 SE): 0xDFDFDF, white, 0x808080 and black. Its light ring sits between the face and the highlight. - 0xD4D0C8 (Windows 2000, and XP's Classic scheme): the face itself, white, 0x808080 and 0x404040. The light ring equals the face, and the dark ring is softer than black.

Any other face color, as in a custom scheme, gets the computed ramp.

Example:

// In a custom control's render_override(): a raised teal panel. Teal is no canonical gray, so its
// ramp is computed, with `highlight` equal to classic_lighter(face, 1.0f).
class TealPanelControl : public ui::Element
{
protected:
    void render_override(ui::Renderer& renderer, const ui::RenderContext&) const override
    {
        const ui::Color            face = ui::Color::from_rgba(0, 128, 128);
        const ui::ClassicBevelRamp ramp = ui::classic_bevel_ramp_from_face(face);
        renderer.fill_rounded_rect(bounds(), 0.0f, face);
        ui::draw_bevel_border(renderer, bounds(), ui::BorderStyle::Raised, ramp.light, ramp.highlight,
                              ramp.shadow, ramp.dark_shadow, 1.0f);
    }
};

// Windows 2000's gray gets its published ramp instead: `#D4D0C8` (the face itself), white,
// `#808080` and `#404040`.
const ui::ClassicBevelRamp win2000 = ui::classic_bevel_ramp_from_face(ui::Color::from_argb(0xFFD4D0C8));

early_reverse_video

std::pair<Color, Color> early_reverse_video(const Color& background, const Color& foreground)

Header: winui/ui/themes/EarlyPalette.hpp.

Reverse video, the era's only way to show a selected state, which is why the palettes above have no selection color. A selected run swaps its foreground and background. Returns the swapped pair as {background, foreground}.

The swap keeps the palette's own colors. Inverting each pixel instead would turn the 2.03 color palette's cyan menu red. On monochrome palettes both give the same result.

Example:

const ui::EarlyPalette p         = ui::EarlyPalette::windows_2x_color();
const ui::Rect         item_rect = {0, 0, 80, 20};
const auto [fill, text] = ui::early_reverse_video(p.menu, p.menu_text); // a selected menu item
renderer.fill_rounded_rect(item_rect, 0.0f, fill);
renderer.draw_text("Open...", item_rect, text, theme.text_style);

early_dither_gray

Color early_dither_gray(const Color& ink, const Color& paper)

Header: winui/ui/themes/EarlyPalette.hpp.

The era's gray as one flat color. The era has no disabled-text color and grays disabled items with a 50 % checkerboard of ink and paper. Renderer has no pattern fill, so this returns the checkerboard's average, the midpoint of the two colors. Black on white gives #808080, the gray the Windows 1.01 monochrome palette uses for the desktop and inactive captions.

Only the text grays out. A disabled push button keeps its frame, corners and border and grays its label.

Example:

const ui::EarlyPalette p          = ui::EarlyPalette::windows_1x_mono();
const ui::Color        gray       = ui::early_dither_gray(p.window_text, p.window); // ~`#808080`
const ui::Rect         label_rect = {0, 0, 80, 20};
const bool             enabled    = false;
renderer.draw_text("Cancel", label_rect, enabled ? p.window_text : gray, theme.text_style);

merge_chrome

ChromeHints merge_chrome(const ChromeHints& theme, const ChromeOverrides& overrides)

Header: winui/ui/themes/Theme.hpp.

The frame settings a window applies: overrides layered over theme.

resolve_theme

Theme resolve_theme(const ThemeRequest& request, const OsThemeSnapshot& os)

Header: winui/ui/themes/ThemeSource.hpp.

Resolves an app's request against the system's settings into a Theme. High contrast, when it is on because the system reports it or the app asked for ThemeMode::HighContrast, wins over every other color input (mode, accent_override, classic_scheme, early_scheme), since apps don't keep their brand colors under high contrast. variant still picks the era the contrast colors are drawn in. The system's contrast theme (os.hc) is the user's choice and always supplies the colors. A forced high contrast with no contrast theme on takes the variant's own contrast colors: Aquatic for Fluent 2, Windows 10's High Contrast Black for Fluent, MDL2 and Metro, the XP and Windows 98 High Contrast Black schemes for Luna, Aero and Windows 9x, Windows 3.1's Monochrome scheme, and the matching monochrome palette for Early Windows.

Example:

ui::OsThemeSnapshot os;
os.dark = true;

// The app asks for light, so the system being dark doesn't change the result.
const ui::Theme theme = ui::resolve_theme(ui::ThemeRequest{.mode = ui::ThemeMode::Light}, os);
window.pin_theme(theme);

enable_era_themes

void enable_era_themes()

Header: winui/ui/themes/ThemeSource.hpp.

Links the era themes into the app, ThemeVariant::Mdl2 to ThemeVariant::Windows1x, with their window frames. Until it is called they are left out of the executable, and a ThemeRequest asking for one draws ThemeVariant::System instead. Call it once, before the first window. Calling it again does nothing.

Example:

int main()
{
    ui::enable_era_themes();
    ui::Window window{{.title = "Retro", .theme = ui::ThemeRequest{.variant = ui::ThemeVariant::Luna}}};
    return ui::run(window);
}

era_themes_enabled

bool era_themes_enabled()

Header: winui/ui/themes/ThemeSource.hpp.

Whether enable_era_themes() was called, so the era variants draw as themselves.

theme_variant_supports_dark_mode

bool theme_variant_supports_dark_mode(ThemeVariant variant)

Header: winui/ui/themes/ThemeSource.hpp.

Whether variant tells ThemeRequest::mode's Dark and Light apart: true for System, Fluent2, Fluent, Metro and Mdl2. Every other variant has one fixed, light palette and looks the same whatever mode says, except ThemeMode::HighContrast, which still replaces its colors. A UI with a variant picker and a dark/light switch uses it to disable the switch when it would have no effect.

os_theme

OsThemeSnapshot os_theme()

Header: winui/ui/themes/ThemeSource.hpp.

What the operating system's theme is right now: light or dark, the accent color, high contrast. A window that follows the system already tracks this by itself; ask for it to pre-select a theme picker to match, or to resolve a theme before a window exists. A platform with no backend returns the defaults.

Example:

ui::Property<bool> dark{ui::os_theme().dark};