use super::values::{is_resource_text, resource_color, text_attr};
use super::{Element, RAW_VALUE};
pub(crate) fn is_builtin(kind: &str) -> bool {
CONTAINERS.contains(&kind) || LEAVES.contains(&kind)
}
pub(crate) fn is_custom_component(kind: &str) -> bool {
!is_builtin(kind) && is_component_name(kind)
}
pub(crate) fn is_common_attr(key: &str) -> bool {
COMMON_ATTRS.contains(&key) || key == yog_ids::yui_attr::VISIBLE
}
pub(super) const CONTAINERS: &[&str] = &[
yog_ids::yui::SCREEN,
yog_ids::yui::CANVAS,
yog_ids::yui::COLUMN,
yog_ids::yui::ROW,
yog_ids::yui::SCROLL_VIEW,
yog_ids::yui::GRID,
];
pub(super) const LEAVES: &[&str] = &[
yog_ids::yui::LABEL,
yog_ids::yui::BUTTON,
yog_ids::yui::TEXT_BOX,
yog_ids::yui::ITEM_SLOT,
yog_ids::yui::INV_SLOT,
yog_ids::yui::SLOT,
yog_ids::yui::PLAYER_INVENTORY,
yog_ids::yui::IMAGE,
yog_ids::yui::SPACER,
yog_ids::yui::SURFACE,
yog_ids::yui::MACHINE,
];
pub(super) const COMMON_ATTRS: &[&str] = &[
yog_ids::yui_attr::ID,
yog_ids::yui_attr::X,
yog_ids::yui_attr::Y,
yog_ids::yui_attr::W,
yog_ids::yui_attr::H,
yog_ids::yui_attr::MIN_W,
yog_ids::yui_attr::MIN_H,
yog_ids::yui_attr::FLEX,
yog_ids::yui_attr::DOCK,
yog_ids::yui_attr::GAP,
yog_ids::yui_attr::PADDING,
yog_ids::yui_attr::BG,
yog_ids::yui_attr::COLOR,
yog_ids::yui_attr::ALIGN,
yog_ids::yui_attr::HALIGN,
yog_ids::yui_attr::VALIGN,
yog_ids::yui_attr::MARGIN,
yog_ids::yui_attr::FONT_SCALE,
yog_ids::yui_attr::FONT,
yog_ids::yui_attr::SHADOW,
yog_ids::yui_attr::NO_WRAP,
yog_ids::yui_attr::ELLIPSIS,
yog_ids::yui_attr::FOCUS_STYLE,
yog_ids::yui_attr::FOCUS_COLOR,
yog_ids::yui_attr::ENABLED,
yog_ids::yui_attr::ON_CLICK,
yog_ids::yui_attr::TOOLTIP,
];
pub(super) fn kind_attrs(kind: &str) -> &'static [&'static str] {
match kind {
yog_ids::yui::SCREEN => &[
yog_ids::yui_attr::WIDTH,
yog_ids::yui_attr::HEIGHT,
yog_ids::yui_attr::ANCHOR,
yog_ids::yui_attr::MODAL,
yog_ids::yui_attr::PAUSE,
yog_ids::yui_attr::LIVE,
yog_ids::yui_attr::THEME,
],
yog_ids::yui::LABEL | yog_ids::yui::BUTTON => &[yog_ids::yui_attr::TEXT],
yog_ids::yui::TEXT_BOX => &[
yog_ids::yui_attr::TEXT,
yog_ids::yui_attr::PLACEHOLDER,
yog_ids::yui_attr::MAX_LENGTH,
yog_ids::yui_attr::ON_CHANGE,
yog_ids::yui_attr::ON_SUBMIT,
],
yog_ids::yui::ITEM_SLOT => &[yog_ids::yui_attr::ITEM],
yog_ids::yui::INV_SLOT => &[yog_ids::yui_attr::ITEM, yog_ids::yui_attr::COUNT],
yog_ids::yui::SLOT => &[yog_ids::yui_attr::INDEX, yog_ids::yui_attr::ACCEPTS],
yog_ids::yui::IMAGE => &[
yog_ids::yui_attr::SOURCE,
yog_ids::yui_attr::STRETCH,
yog_ids::yui_attr::UV,
yog_ids::yui_attr::TINT,
],
yog_ids::yui::SURFACE => &[yog_ids::yui_attr::SOURCE],
yog_ids::yui::MACHINE => &[
yog_ids::yui_attr::KIND,
yog_ids::yui_attr::RESULT,
yog_ids::yui_attr::PLACES,
],
_ => &[],
}
}
pub(super) fn is_component_name(kind: &str) -> bool {
kind.chars().next().is_some_and(|c| c.is_ascii_uppercase())
&& kind.chars().all(|c| c.is_ascii_alphanumeric() || c == '_')
}
pub(super) fn component_expr(el: &Element) -> Result<String, String> {
let props: Vec<String> = el
.attrs
.iter()
.filter(|(k, _)| !COMMON_ATTRS.contains(&k.as_str()))
.map(|(k, v)| {
if let Some(rust) = v.strip_prefix(RAW_VALUE) {
return Ok(format!("({k:?}, &*{rust})"));
}
match v.strip_prefix('@') {
Some(rest) if !is_resource_text(rest) && resource_color(rest).is_some() => {
let c = resource_color(rest).unwrap_or_default();
Ok(format!("({k:?}, \"#{c:08X}\")"))
}
Some(rest) if !rest.trim().is_empty() => {
Ok(format!("({k:?}, &*{})", text_attr(el, k, v)?))
}
_ => Ok(format!("({k:?}, {v:?})")),
}
})
.collect::<Result<_, String>>()?;
Ok(format!(
"::yog_api::ui::component::build({:?}, &[{}])",
el.name,
props.join(", ")
))
}
pub(super) fn wpf_hint(key: &str) -> Option<&'static str> {
Some(match key {
"HorizontalAlignment" => "halign",
"VerticalAlignment" => "valign",
"Margin" => "margin",
"Padding" => "padding",
"Width" => "w",
"Height" => "h",
"MinWidth" => "min_w",
"MinHeight" => "min_h",
"Background" => "bg",
"Foreground" => "color",
"Text" | "Content" => "text",
"RowDefinitions" => "rows",
"ColumnDefinitions" => "columns",
"RowSpacing" => "row_spacing",
"ColumnSpacing" => "column_spacing",
"Visibility" => "visible",
"IsEnabled" => "enabled",
_ => return None,
})
}