Image
Group: Data
Code
pub struct ImageDemo {
menu_bar: MenuBar,
last_action: Option<String>,
}
impl ImageDemo {
pub fn new() -> Self {
Self {
menu_bar: MenuBar {
id: WidgetId::new("gallery:image:menu-bar"),
items: vec![
menu_item("gallery:image:file", "&File"),
menu_item("gallery:image:edit", "&Edit"),
menu_item("gallery:image:view", "&View"),
],
open_item: None,
focused_item: None,
},
last_action: None,
}
}
fn logo(&self, variant: usize) -> Image {
Image {
id: WidgetId::new("gallery:image:logo"),
source: ImageSource::Bytes(LOGO_PNG.to_vec()),
intrinsic_size: Some((24, 24)),
fit: if variant == 1 {
ImageFit::Cover
} else {
ImageFit::Contain
},
fallback_text: "[Q]".into(),
}
}
fn bar_rects(area: Rect, backend: &dyn Backend) -> (Rect, Rect, Rect) {
let lh = backend.line_height();
let full = Rect::new(area.x, area.y, area.width, lh);
let icon_width = lh * 4.0;
let icon_rect = Rect::new(full.x, full.y, icon_width, full.height);
let items_rect = Rect::new(
full.x + icon_width,
full.y,
(full.width - icon_width).max(0.0),
full.height,
);
(full, icon_rect, items_rect)
}
fn status(&self) -> StatusBar {
let msg = match &self.last_action {
Some(a) => format!(" last: {a} "),
None => " click a menu item or the logo ".into(),
};
StatusBar {
id: WidgetId::new("gallery:image:status"),
left_segments: vec![StatusBarSegment {
text: msg,
fg: Color::rgb(255, 255, 255),
bg: Color::rgb(40, 80, 120),
bold: false,
action_id: None,
}],
right_segments: vec![],
}
}
fn status_rect(area: Rect, backend: &dyn Backend) -> Rect {
let lh = backend.line_height();
Rect::new(area.x, area.y + area.height - lh, area.width, lh)
}
}
impl Default for ImageDemo {
fn default() -> Self {
Self::new()
}
}
impl Demo for ImageDemo {
fn name(&self) -> &'static str {
"Image"
}
fn group(&self) -> &'static str {
"Data"
}
fn variants(&self) -> &'static [&'static str] {
&["Contain", "Cover"]
}
fn render(&self, variant: usize, backend: &mut dyn Backend, area: Rect) {
let (_full, icon_rect, items_rect) = Self::bar_rects(area, backend);
let _ = backend.draw_image(icon_rect, &self.logo(variant));
let _ = backend.draw_menu_bar(items_rect, &self.menu_bar);
let status_rect = Self::status_rect(area, backend);
let _ = backend.draw_status_bar_interactive(
status_rect,
&self.status(),
&InteractionState::new(),
);
}
fn handle(
&mut self,
variant: usize,
event: &UiEvent,
backend: &mut dyn Backend,
area: Rect,
) -> Reaction {
match event {
UiEvent::MouseDown {
button: MouseButton::Left,
position,
..
} => {
let (_full, icon_rect, items_rect) = Self::bar_rects(area, backend);
let image_layout = self.logo(variant).layout(icon_rect);
if image_layout.hit_test(position.x, position.y) == ImageHit::Image {
self.last_action = Some("clicked logo".into());
return Reaction::Redraw;
}
let layout = backend.menu_bar_layout(items_rect, &self.menu_bar);
if let MenuBarHit::Item(idx) = layout.hit_test(position.x, position.y) {
self.last_action =
Some(format!("activated: {}", self.menu_bar.items[idx].label));
return Reaction::Redraw;
}
Reaction::Continue
}
_ => Reaction::Continue,
}
}
fn source(&self) -> &'static str {
extract_region(SOURCE)
}
fn data(&self, variant: usize) -> serde_json::Value {
serde_json::json!({
"image": self.logo(variant),
"last_action": self.last_action,
})
}
fn caps_note(&self, _variant: usize, _caps: &BackendCaps) -> Option<String> {
None
}
}
Backends
| Variant | TUI | GTK | macOS | Windows |
|---|---|---|---|---|
| Contain | ||||
| Cover |