159 lines
6.0 KiB
Rust
159 lines
6.0 KiB
Rust
use iced::{
|
|
Border, Color, Theme,
|
|
theme::palette::{Extended, Pair},
|
|
widget::{button, container, text_editor, text_input},
|
|
};
|
|
use oa_core::Kind;
|
|
pub const BG: Color = Color::from_rgb(0.945, 0.956, 0.969);
|
|
pub const INK: Color = Color::from_rgb8(24, 33, 44);
|
|
pub const MUTED: Color = Color::from_rgb8(75, 89, 104);
|
|
pub const TEAL: Color = Color::from_rgb8(0, 102, 92);
|
|
/// Decorative dividers; essential outlines use BOUNDARY instead.
|
|
pub const LINE: Color = Color::from_rgb(0.86, 0.89, 0.91);
|
|
pub const BOUNDARY: Color = Color::from_rgb8(102, 117, 134);
|
|
const WARNING: Color = Color::from_rgb8(134, 91, 0);
|
|
const SELECTION: Color = Color::from_rgb8(217, 238, 232);
|
|
// Ordinary values remain INK; syntax selection has its own surface and palette.
|
|
const INPUT_SELECTION: Color = Color::from_rgb8(123, 142, 134);
|
|
const SOURCE_SELECTION: Color = Color::from_rgb8(128, 149, 139);
|
|
const SOURCE_INK: Color = Color::from_rgb8(33, 37, 41);
|
|
pub fn theme() -> Theme {
|
|
Theme::custom_with_fn(
|
|
"Arcadia Light",
|
|
iced::theme::Palette {
|
|
background: BG,
|
|
text: INK,
|
|
primary: TEAL,
|
|
success: TEAL,
|
|
warning: WARNING,
|
|
danger: Color::from_rgb(0.78, 0.22, 0.24),
|
|
},
|
|
|palette| {
|
|
let mut extended = Extended::generate(palette);
|
|
// Pair::new adjusts text toward a 6:1 target. Keep these reviewed
|
|
// colors exact; resolved style tests enforce each consumer contract.
|
|
let pair = |color, text| Pair { color, text };
|
|
extended.background.base = pair(BG, INK);
|
|
extended.background.weakest = pair(Color::WHITE, INK);
|
|
extended.background.weaker = pair(BG, INK);
|
|
// These pairs also supply pick-list/menu and disabled-control fills.
|
|
extended.background.weak = pair(Color::WHITE, INK);
|
|
extended.background.neutral = pair(LINE, INK);
|
|
extended.background.strong = pair(BOUNDARY, Color::WHITE);
|
|
extended.background.stronger = pair(MUTED, Color::WHITE);
|
|
extended.background.strongest = pair(MUTED, Color::WHITE);
|
|
extended.primary.base = pair(TEAL, Color::WHITE);
|
|
extended.primary.weak = pair(INPUT_SELECTION, INK);
|
|
extended.primary.strong = pair(Color::from_rgb8(0, 83, 75), Color::WHITE);
|
|
// Secondary base is both placeholder ink and a button background.
|
|
extended.secondary.base = pair(MUTED, Color::WHITE);
|
|
extended.secondary.weak = pair(LINE, INK);
|
|
extended.secondary.strong = pair(Color::from_rgb8(54, 68, 82), Color::WHITE);
|
|
extended.success.base = extended.primary.base;
|
|
extended.success.weak = pair(SELECTION, INK);
|
|
extended.success.strong = extended.primary.strong;
|
|
extended.warning.base = pair(WARNING, Color::WHITE);
|
|
extended.warning.weak = pair(Color::from_rgb8(250, 235, 203), INK);
|
|
extended.warning.strong = pair(Color::from_rgb8(103, 70, 0), Color::WHITE);
|
|
extended.danger.base = pair(palette.danger, Color::WHITE);
|
|
extended.danger.weak = pair(Color::from_rgb8(249, 227, 229), INK);
|
|
extended.danger.strong = pair(Color::from_rgb8(156, 34, 40), Color::WHITE);
|
|
extended
|
|
},
|
|
)
|
|
}
|
|
pub fn source_editor(theme: &Theme, status: text_editor::Status) -> text_editor::Style {
|
|
let mut style = text_editor::default(theme, status);
|
|
style.background = Color::WHITE.into();
|
|
style.value = SOURCE_INK;
|
|
style.placeholder = SOURCE_INK;
|
|
style.selection = SOURCE_SELECTION;
|
|
style
|
|
}
|
|
/// Inputs without an edit callback still support selection and copy in Iced.
|
|
pub fn selectable_input(theme: &Theme, status: text_input::Status) -> text_input::Style {
|
|
let mut style = text_input::default(theme, status);
|
|
if status == text_input::Status::Disabled {
|
|
style.value = INK;
|
|
}
|
|
style
|
|
}
|
|
pub fn card(_: &Theme) -> container::Style {
|
|
container::Style {
|
|
background: Some(Color::WHITE.into()),
|
|
border: Border {
|
|
color: LINE,
|
|
width: 1.,
|
|
radius: 10.into(),
|
|
},
|
|
..Default::default()
|
|
}
|
|
}
|
|
pub fn panel(_: &Theme) -> container::Style {
|
|
container::Style {
|
|
background: Some(Color::WHITE.into()),
|
|
border: Border {
|
|
color: LINE,
|
|
width: 1.,
|
|
radius: 0.into(),
|
|
},
|
|
..Default::default()
|
|
}
|
|
}
|
|
pub fn subtle(_: &Theme) -> container::Style {
|
|
container::Style {
|
|
background: Some(BG.into()),
|
|
border: Border {
|
|
radius: 8.into(),
|
|
..Default::default()
|
|
},
|
|
..Default::default()
|
|
}
|
|
}
|
|
pub fn nav(theme: &Theme, status: button::Status) -> button::Style {
|
|
let mut s = button::text(theme, status);
|
|
if status != button::Status::Disabled {
|
|
s.text_color = INK;
|
|
}
|
|
s.border.radius = 7.into();
|
|
if matches!(status, button::Status::Hovered | button::Status::Pressed) {
|
|
s.background = Some(BG.into());
|
|
}
|
|
s
|
|
}
|
|
pub fn selected(theme: &Theme, status: button::Status) -> button::Style {
|
|
let mut s = nav(theme, status);
|
|
s.background = Some(SELECTION.into());
|
|
s.border = Border {
|
|
color: TEAL,
|
|
width: 2.,
|
|
radius: 7.into(),
|
|
};
|
|
s
|
|
}
|
|
pub fn kind_color(kind: Kind) -> Color {
|
|
match kind {
|
|
Kind::Entity | Kind::System => Color::from_rgb(0.16, 0.40, 0.71),
|
|
Kind::Actor | Kind::SystemActor | Kind::Role => Color::from_rgb8(117, 68, 153),
|
|
Kind::Activity | Kind::Function => TEAL,
|
|
Kind::Capability | Kind::SystemCapability | Kind::Mission | Kind::OperationalMission => {
|
|
WARNING
|
|
}
|
|
Kind::Process
|
|
| Kind::FunctionalChain
|
|
| Kind::Scenario
|
|
| Kind::Occurrence
|
|
| Kind::Lifeline => Color::from_rgb(0.65, 0.33, 0.40),
|
|
Kind::StateMachine
|
|
| Kind::Region
|
|
| Kind::State
|
|
| Kind::Mode
|
|
| Kind::Initial
|
|
| Kind::Final => Color::from_rgb(0.38, 0.39, 0.68),
|
|
_ => Color::from_rgb8(50, 107, 128),
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests;
|