Skip to main content

Theme

Struct Theme 

Source
pub struct Theme {
    pub name: Cow<'static, str>,
    pub light: Option<ThemeMode>,
    pub dark: Option<ThemeMode>,
    pub layout: LayoutTheme,
    pub icon_set: Option<IconSet>,
    pub icon_theme: Option<Cow<'static, str>>,
}
Expand description

A complete native theme with a name and optional light/dark variants.

This is the top-level type that theme files deserialize into and that platform readers produce.

§Examples

use native_theme::theme::Theme;

// Load a bundled preset
let theme = Theme::preset("dracula").unwrap();
assert_eq!(theme.name, "Dracula");

// Parse from a TOML string
let toml = r##"
name = "Custom"
[light.defaults]
accent_color = "#ff6600"
"##;
let custom = Theme::from_toml(toml).unwrap();
assert_eq!(custom.name, "Custom");

// Merge themes (overlay wins for populated fields)
let mut base = Theme::preset("catppuccin-mocha").unwrap();
base.merge(&custom);
assert_eq!(base.name, "Catppuccin Mocha"); // base name is preserved

Fields§

§name: Cow<'static, str>

Theme name (e.g., “Breeze”, “Adwaita”, “Windows 11”).

Uses Cow<'static, str> so bundled presets can store borrowed &'static str values without per-load String allocations. User-provided names (from TOML files or runtime detection) are Cow::Owned.

§light: Option<ThemeMode>

Light variant of the theme.

§dark: Option<ThemeMode>

Dark variant of the theme.

§layout: LayoutTheme

Layout spacing constants (shared between light and dark variants).

§icon_set: Option<IconSet>

Which icon loading mechanism to use (Freedesktop, Material, Lucide, SfSymbols, SegoeIcons). Shared across light and dark variants. When None, filled during resolution from system_icon_set().

§Examples

use native_theme::theme::{Theme, IconSet};

let theme = Theme::preset("material")?;
assert_eq!(theme.icon_set, Some(IconSet::Material));
§icon_theme: Option<Cow<'static, str>>

Visual icon theme name (shared across light and dark variants).

Acts as the default when a variant’s ThemeDefaults::icon_theme is None. Variants that need a different icon theme per color mode (e.g. KDE Plasma: "breeze" light / "breeze-dark" dark) set the override on ThemeDefaults::icon_theme.

Precedence at resolve time:

  1. ThemeMode::defaults.icon_theme — per-variant override (if set)
  2. Theme::icon_theme — this field (if set)
  3. system_icon_theme() — runtime detection; none where it fails

See doc 1 §20 and docs/todo_v0.5.7_gaps.md §G4 for the design rationale.

Implementations§

Source§

impl Theme

Source

pub fn merge(&mut self, overlay: &Self)

Merge an overlay theme into this theme.

The base name is kept. For each variant (light/dark):

  • If both base and overlay have a variant, they are merged recursively.
  • If only the overlay has a variant, it is cloned into the base.
  • If only the base has a variant (or neither), no change.
Source

pub fn pick_variant(&self, mode: ColorMode) -> Result<&ThemeMode>

Pick the appropriate variant for the given mode, with cross-fallback.

When mode is ColorMode::Dark, prefers dark and falls back to light. When mode is ColorMode::Light, prefers light and falls back to dark.

§Errors

Returns Error::NoVariant if the theme has no variants at all.

Source

pub fn into_variant(self, mode: ColorMode) -> Result<ThemeMode>

Extract a variant by consuming the theme, avoiding a clone.

When mode is ColorMode::Dark, returns the dark variant (falling back to light). When ColorMode::Light, returns light (falling back to dark).

Use this when you own the Theme and don’t need it afterward. For read-only inspection, use pick_variant().

§Errors

Returns Error::NoVariant if the theme has no variants at all.

§Examples
use native_theme::theme::ColorMode;

let theme = native_theme::theme::Theme::preset("dracula")?;
let variant = theme.into_variant(ColorMode::Dark)?;
let resolved = variant.resolve_system()?;
Source

pub fn resolve(&self, mode: ColorMode) -> Result<Resolved>

Resolve this theme for a color mode into a ready-to-render bundle.

Picks the variant (with cross-fallback), applies inheritance and validation to produce a ResolvedTheme, and resolves the shared icon_set / icon_theme fields. This is the one-call path from a parsed Theme to the values a UI framework needs.

icon_set falls back to system_icon_set() when the TOML omits it. icon_theme uses three-tier precedence:

  1. The picked variant’s defaults.icon_theme (per-mode override).
  2. Theme::icon_theme (shared across variants).
  3. system_icon_theme() (runtime detect).

Where no tier gives a name — the TOML states none and detection fails — Resolved::icon_theme is None; the resolution itself does not fail over it, and system_icon_theme() gives the reason. Resolved::icon_theme_explicit reports whether tiers 1 or 2 fired (value came from TOML) versus tier 3 (runtime detection).

Uses ResolutionContext::from_system for DPI and button-order. For custom contexts, construct the variant manually and call ThemeMode::into_resolved.

§Errors

Returns crate::Error::NoVariant when the theme has no variants, or crate::Error::ResolutionIncomplete / crate::Error::ResolutionInvalid when the picked variant cannot be fully resolved.

§Examples
use native_theme::theme::{ColorMode, Theme};

// Theme-level `icon_theme` (tier 2) — applies to both modes.
let material = Theme::preset("material")?;
let r = material.resolve(ColorMode::Dark)?;
assert_eq!(r.icon_theme.as_deref(), Some("material"));
assert!(r.icon_theme_explicit);

// Per-variant `icon_theme` (tier 1) — differs by mode.
let breeze = Theme::preset("kde-breeze")?;
assert_eq!(breeze.resolve(ColorMode::Light)?.icon_theme.as_deref(), Some("breeze"));
assert_eq!(breeze.resolve(ColorMode::Dark)?.icon_theme.as_deref(), Some("breeze-dark"));
Source

pub fn is_empty(&self) -> bool

Returns true if the theme has no variants set.

Source

pub fn preset(name: &str) -> Result<Self>

Load a bundled theme preset by name.

Returns the preset as a fully populated Theme with both light and dark variants.

§Errors

Returns crate::Error::UnknownPreset if the preset name is not recognized.

§Examples
let theme = native_theme::theme::Theme::preset("catppuccin-mocha")?;
assert!(theme.light.is_some());

Bundled preset names are Cow::Borrowed (no allocation):

use native_theme::theme::Theme;

let theme = Theme::preset("dracula")?;
assert!(matches!(theme.name, std::borrow::Cow::Borrowed(_)));
Source

pub fn from_toml(toml_str: &str) -> Result<Self>

Parse a TOML string into a Theme.

§TOML Format

Theme files use the following structure. Every field is optional – omit any field you don’t need. Unknown fields are silently ignored; lint_toml reports them. Hex colors accept #RRGGBB or #RRGGBBAA format. A size carries its unit in its key: _px for logical pixels, and size_pt or size_px for a font. A widget border’s padding takes one key per side (padding_top_px, padding_right_px, padding_bottom_px, padding_left_px) or one per axis (padding_horizontal_px, padding_vertical_px), not both for the same axis.

use native_theme::theme::Theme;

let toml = r##"
name = "My Theme"

[light.defaults]
accent_color = "#4a90d9"
background_color = "#fafafa"
text_color = "#2e3436"
surface_color = "#ffffff"
muted_color = "#929292"
shadow_color = "#00000018"
danger_color = "#dc3545"
warning_color = "#f0ad4e"
success_color = "#28a745"
info_color = "#4a90d9"
selection_background = "#4a90d9"
selection_text_color = "#ffffff"
link_color = "#2a6cb6"
focus_ring_color = "#4a90d9"
disabled_text_color = "#c0c0c0"
disabled_opacity = 0.5

[light.defaults.font]
family = "sans-serif"
size_pt = 10.0

[light.defaults.mono_font]
family = "monospace"
size_pt = 10.0

[light.defaults.border]
color = "#c0c0c0"
corner_radius_px = 6.0
corner_radius_lg_px = 12.0
line_width_px = 1.0
opacity = 0.15
shadow_enabled = true

[light.button]
background_color = "#e8e8e8"
min_height_px = 32.0

[light.button.font]
color = "#2e3436"

[light.button.border]
padding_horizontal_px = 12.0
padding_vertical_px = 6.0

[light.tooltip]
background_color = "#2e3436"
max_width_px = 300.0

[light.tooltip.font]
color = "#f0f0f0"

# [dark.*] mirrors the same structure as [light.*]
"##;

assert!(Theme::lint_toml(toml)?.is_empty());
let theme = Theme::from_toml(toml)?;
let light = theme.light.as_ref();
assert_eq!(light.and_then(|v| v.button.min_height), Some(32.0));
assert_eq!(light.and_then(|v| v.tooltip.max_width), Some(300.0));
assert_eq!(
    light.and_then(|v| v.defaults.border.corner_radius),
    Some(6.0)
);
let button_border = light.and_then(|v| v.button.border.as_ref());
assert_eq!(button_border.and_then(|b| b.padding_left), Some(12.0));
assert_eq!(button_border.and_then(|b| b.padding_bottom), Some(6.0));
§Errors

Returns crate::Error::Toml if the TOML is invalid.

§Examples
let toml = r##"
name = "My Theme"
[light.defaults]
accent_color = "#ff0000"
"##;
let theme = native_theme::theme::Theme::from_toml(toml).unwrap();
assert_eq!(theme.name, "My Theme");
Source

pub fn from_file(path: impl AsRef<Path>) -> Result<Self>

Load a Theme from a TOML file.

§Errors

Returns crate::Error::Io if the file cannot be read, or crate::Error::Toml if the TOML content is invalid.

§Examples
let theme = native_theme::theme::Theme::from_file("my-theme.toml").unwrap();
Source

pub fn list_presets() -> &'static [PresetInfo]

List all available bundled presets with structured metadata.

Returns a static slice of PresetInfo entries, one per bundled preset. Each entry carries the machine-readable key, human-readable display name, target platform tags, and a light_only flag.

§Examples
let presets = native_theme::theme::Theme::list_presets();
assert_eq!(presets.len(), 16);
assert_eq!(presets[0].key, "kde-breeze");
assert_eq!(presets[0].display_name, "KDE Breeze");
Source

pub fn list_presets_for_platform() -> Vec<PresetInfo>

List presets appropriate for the current platform, with structured metadata.

Platform-specific presets (kde-breeze, adwaita, windows-11, macos-sonoma, ios) are only included on their native platform. Community themes are always included.

Note: Unlike list_presets() which returns a static slice, this method returns Vec because it filters the preset list at runtime based on the detected platform.

§Examples
let presets = native_theme::theme::Theme::list_presets_for_platform();
// On Linux KDE: includes kde-breeze, adwaita, plus all community themes
// On Windows: includes windows-11 plus all community themes
assert!(!presets.is_empty());
Source

pub fn to_toml(&self) -> Result<String>

Serialize this theme to a TOML string.

§Errors

Returns crate::Error::ReaderFailed if serialization fails.

§Examples
let theme = native_theme::theme::Theme::preset("catppuccin-mocha").unwrap();
let toml_str = theme.to_toml().unwrap();
assert!(toml_str.contains("name = \"Catppuccin Mocha\""));
Source

pub fn lint_toml(toml_str: &str) -> Result<Vec<String>>

Check a TOML string for unrecognized field names.

Parses the TOML as a generic table and walks all keys, comparing against the known fields for each section. Returns a Vec<String> of warnings for any keys that don’t match a known field. An empty vec means all keys are recognized.

This is an opt-in linting tool for theme authors. It does NOT affect from_toml() behavior (which silently ignores unknown fields via serde).

§Errors

Returns Err if the TOML string cannot be parsed at all.

§Examples
let warnings = native_theme::theme::Theme::lint_toml(r##"
name = "Test"
[light.defaults]
backround = "#ffffff"
"##).unwrap();
assert_eq!(warnings.len(), 1);
assert!(warnings[0].contains("backround"));

Trait Implementations§

Source§

impl Clone for Theme

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Theme

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for Theme

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl<'de> Deserialize<'de> for Theme

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl PartialEq for Theme

Source§

fn eq(&self, other: &Self) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl Serialize for Theme

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more
Source§

impl StructuralPartialEq for Theme

Auto Trait Implementations§

§

impl Freeze for Theme

§

impl RefUnwindSafe for Theme

§

impl Send for Theme

§

impl Sync for Theme

§

impl Unpin for Theme

§

impl UnsafeUnpin for Theme

§

impl UnwindSafe for Theme

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> NoneValue for T
where T: Default,

Source§

type NoneType = T

Source§

fn null_value() -> T

The none-equivalent value.
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more