kr580 1.1.0

Desktop KR580VM80 / Intel 8080 emulator.
Documentation
use iced::widget::{Column, Row, Space, button, container};
use iced::{Background, Border, Color, Element, Length, alignment};

use super::super::theme::{
    DARK_COLOR_SCHEMES, LIGHT_COLOR_SCHEMES, color_scheme_group_label, color_scheme_label,
    color_scheme_palette, tokyo_blue, tokyo_border, tokyo_muted, tokyo_selection_blue,
    tokyo_surface, tokyo_surface_2, tokyo_text, ui_text,
};
use crate::app::{ContentFocus, Message, SettingsDialog};
use crate::i18n::Lang;
use crate::persistence::ColorScheme;

pub(super) fn theme_setting_row<'a>(
    dialog: &'a SettingsDialog,
    lang: Lang,
) -> Element<'a, Message> {
    let keyboard_focused = dialog.content_focus_is_visible(ContentFocus::Theme);

    let control = Column::new()
        .spacing(12)
        .push(theme_group(
            color_scheme_group_label(true, lang),
            &DARK_COLOR_SCHEMES,
            dialog.draft_color_scheme,
            keyboard_focused,
            lang,
        ))
        .push(theme_group(
            color_scheme_group_label(false, lang),
            &LIGHT_COLOR_SCHEMES,
            dialog.draft_color_scheme,
            keyboard_focused,
            lang,
        ));

    container(control).width(Length::Fill).into()
}

fn theme_group<'a>(
    label: &'static str,
    schemes: &'static [ColorScheme],
    active: ColorScheme,
    keyboard_focused: bool,
    lang: Lang,
) -> Element<'a, Message> {
    let mut column = Column::new()
        .spacing(6)
        .push(ui_text(label, 13, tokyo_muted()));
    for scheme in schemes {
        column = column.push(theme_option(*scheme, active, keyboard_focused, lang));
    }
    column.into()
}

fn theme_option<'a>(
    scheme: ColorScheme,
    active: ColorScheme,
    keyboard_focused: bool,
    lang: Lang,
) -> Element<'a, Message> {
    let selected = scheme == active;
    let content = Row::new()
        .align_y(alignment::Vertical::Center)
        .push(ui_text(color_scheme_label(scheme, lang), 15, tokyo_text()))
        .push(Space::new().width(Length::Fill))
        .push(palette_preview(scheme));

    button(container(content).padding([8, 12]))
        .on_press(Message::SettingsDraftColorSchemeChanged(scheme))
        .width(Length::Fill)
        .padding(0)
        .style(move |_theme, status| theme_option_style(status, selected, keyboard_focused))
        .into()
}

fn palette_preview<'a>(scheme: ColorScheme) -> Element<'a, Message> {
    let mut row = Row::new().spacing(6).align_y(alignment::Vertical::Center);
    for color in color_scheme_palette(scheme) {
        row = row.push(palette_square(color));
    }
    row.into()
}

pub(super) fn theme_search_matches(lang: Lang, lower_query: &str) -> bool {
    DARK_COLOR_SCHEMES
        .iter()
        .chain(LIGHT_COLOR_SCHEMES.iter())
        .any(|scheme| {
            color_scheme_label(*scheme, lang)
                .to_lowercase()
                .contains(lower_query)
        })
}

fn palette_square<'a>(color: Color) -> Element<'a, Message> {
    container(Space::new())
        .width(Length::Fixed(15.0))
        .height(Length::Fixed(15.0))
        .style(move |_theme| container::Style {
            background: Some(Background::Color(color)),
            border: Border {
                radius: 3.0.into(),
                width: 1.0,
                color: Color {
                    a: 0.45,
                    ..tokyo_border()
                },
            },
            ..container::Style::default()
        })
        .into()
}

fn theme_option_style(
    status: button::Status,
    selected: bool,
    keyboard_focused: bool,
) -> button::Style {
    let background = match (selected, status) {
        (true, _) => tokyo_selection_blue(),
        (false, button::Status::Pressed) => tokyo_surface_2(),
        (false, button::Status::Hovered) => tokyo_surface(),
        _ => Color::TRANSPARENT,
    };
    let border_color = if selected {
        tokyo_blue()
    } else if keyboard_focused {
        tokyo_text()
    } else {
        Color::TRANSPARENT
    };
    button::Style {
        background: Some(Background::Color(background)),
        text_color: tokyo_text(),
        border: Border {
            radius: 6.0.into(),
            width: if selected || keyboard_focused {
                1.0
            } else {
                0.0
            },
            color: border_color,
        },
        ..button::Style::default()
    }
}