use windui::prelude::*;
const FG: u32 = 0x2D3436;
const SUB: u32 = 0x636E72;
const CARD: u32 = 0xFFFFFF;
const BG: u32 = 0xEEF1F5;
fn gradient(w: u32, h: u32) -> Vec<u8> {
let mut v = Vec::with_capacity((w * h * 4) as usize);
for y in 0..h {
for x in 0..w {
let fx = x as f32 / (w - 1).max(1) as f32;
let fy = y as f32 / (h - 1).max(1) as f32;
let r = (220.0 * (1.0 - fx)) as u8;
let g = (200.0 * fy) as u8;
let b = (220.0 * fx + 40.0) as u8;
v.extend_from_slice(&[r, g, b, 255]);
}
}
v
}
fn plus_icon(size: u32) -> Vec<u8> {
let mut v = vec![0u8; (size * size * 4) as usize];
let c = size / 2;
let thick = (size / 6).max(1);
for y in 0..size {
for x in 0..size {
let on = (x.abs_diff(c) <= thick) || (y.abs_diff(c) <= thick);
if on {
let i = ((y * size + x) * 4) as usize;
v[i..i + 4].copy_from_slice(&[255, 255, 255, 255]);
}
}
}
v
}
fn solid(size: u32, r: u8, g: u8, b: u8) -> Vec<u8> {
[r, g, b, 255].repeat((size * size) as usize)
}
fn card(title: &str, body: Element) -> Element {
Element::col()
.width_match()
.bg(Color::hex(CARD))
.corner(10.0)
.padding(16)
.spacing(10)
.child(
Element::label(title)
.font_size(16.0)
.fg(Color::hex(FG))
.height(24)
.width_match(),
)
.child(Element::divider())
.child(body)
}
fn demo(label: &str, img: Element) -> Element {
Element::col()
.spacing(4)
.child(
img.width(96)
.height(72)
.bg(Color::hex(0xF6F8FA))
.border(Color::hex(0xDDDDDD), 1),
)
.child(
Element::label(label)
.font_size(12.0)
.fg(Color::hex(SUB))
.height(16),
)
}
fn main() {
let grad = gradient(64, 48); let icon = plus_icon(32);
let fit_row = Element::row()
.spacing(12)
.child(demo(
"Contain",
Element::image_rgba(64, 48, &grad).fit(Fit::Contain),
))
.child(demo(
"Cover",
Element::image_rgba(64, 48, &grad).fit(Fit::Cover),
))
.child(demo(
"Fill",
Element::image_rgba(64, 48, &grad).fit(Fit::Fill),
))
.child(demo(
"None",
Element::image_rgba(64, 48, &grad).fit(Fit::None),
));
let corner_row = Element::row()
.spacing(12)
.cross(Align::Center)
.child(demo(
"圆角 12",
Element::image_rgba(64, 48, &grad)
.fit(Fit::Cover)
.corner(12.0),
))
.child(
Element::col()
.spacing(4)
.child(
Element::image_rgba(64, 48, &grad)
.fit(Fit::Cover)
.corner(36.0)
.width(72)
.height(72),
)
.child(
Element::label("圆形")
.font_size(12.0)
.fg(Color::hex(SUB))
.height(16),
),
)
.child(demo("占位(加载失败)", Element::image("不存在的文件.png")));
let state_row = Element::row()
.spacing(12)
.cross(Align::Center)
.child(Element::button("新建").icon_rgba(32, 32, &icon))
.child(
Element::button("禁用")
.icon_rgba(32, 32, &icon)
.disabled(true),
)
.child(demo(
"着色(accent)",
Element::image_content(
ImageContent::from_rgba(32, 32, &icon)
.fit(Fit::Contain)
.tint(Color::hex(0x4C8BF5)),
),
));
let picked = signal(0usize);
let icon_list = Element::list_icons(
vec![
(
"收件箱",
ImageContent::from_rgba(24, 24, &solid(24, 0x4C, 0x8B, 0xF5)),
),
(
"已发送",
ImageContent::from_rgba(24, 24, &solid(24, 0x2E, 0xC4, 0x8B)),
),
(
"草稿箱",
ImageContent::from_rgba(24, 24, &solid(24, 0xF5, 0xA6, 0x23)),
),
(
"垃圾箱",
ImageContent::from_rgba(24, 24, &solid(24, 0xE5, 0x48, 0x4D)),
),
],
picked,
)
.height(150)
.width_match()
.bg(Color::hex(0xF6F8FA))
.corner(8.0);
let svg_circle: &[u8] = br##"<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><defs><linearGradient id="g" x1="0" y1="0" x2="1" y2="1"><stop offset="0" stop-color="#ff6b9d"/><stop offset="1" stop-color="#4c8bf5"/></linearGradient></defs><circle cx="32" cy="32" r="28" fill="url(#g)"/></svg>"##;
let svg_check: &[u8] = br##"<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9 16.2 4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4z" fill="#000000"/></svg>"##;
let svg_row = Element::row()
.spacing(12)
.cross(Align::Center)
.child(demo(
"SVG 固有",
Element::image_svg(svg_circle, None).fit(Fit::Contain),
))
.child(demo(
"SVG 192px 光栅",
Element::image_svg(svg_circle, Some(192)).fit(Fit::Contain),
))
.child(demo(
"SVG 着色",
Element::image_svg(svg_check, Some(64))
.fit(Fit::Contain)
.tint(Color::hex(0x4C8BF5)),
))
.child(Element::button("SVG 图标").icon_svg(svg_check, Some(32)));
#[allow(unused_mut)]
let mut svg_body = Element::col().spacing(10).child(svg_row);
#[cfg(feature = "svg-text")]
{
let svg_text: &[u8] = r##"<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 220 40"><text x="6" y="29" font-size="26" font-family="Segoe UI, Arial" fill="#4c8bf5">Hello, SVG 文字</text></svg>"##.as_bytes();
svg_body = svg_body.child(Element::divider()).child(
Element::image_svg(svg_text, Some(440))
.fit(Fit::Contain)
.height(40)
.width_match(),
);
}
let body = Element::col()
.width_match()
.spacing(14)
.child(card("适配模式(源图 4:3,框 96×72)", fit_row))
.child(card("圆角裁剪 & 占位", corner_row))
.child(card("状态:正常/禁用 + 单色图标着色", state_row))
.child(card("SVG 矢量(resvg 光栅化 + 着色)", svg_body))
.child(card("列表行图标(list_icons)", icon_list));
let ui = Element::stack().fill().bg(Color::hex(BG)).child(
Element::col()
.fill()
.padding(18)
.spacing(12)
.child(
Element::label("图片支持")
.font_size(24.0)
.fg(Color::hex(0x1A1A2E))
.height(34)
.width_match(),
)
.child(Element::scroll().fill().child(body)),
);
App::new("windui — 图片示例", 480, 760)
.bg(Color::hex(BG))
.screenshot_from_args()
.content(ui)
.run();
}