agg_gui/widgets/
image_view.rs1use std::cell::RefCell;
12use std::rc::Rc;
13use std::sync::Arc;
14
15use crate::color::Color;
16use crate::event::{Event, EventResult};
17use crate::geometry::{Rect, Size};
18use crate::draw_ctx::DrawCtx;
19use crate::layout_props::{HAnchor, Insets, VAnchor, WidgetBase};
20use crate::text::Font;
21use crate::widget::Widget;
22
23pub struct ImageView {
24 bounds: Rect,
25 children: Vec<Box<dyn Widget>>, base: WidgetBase,
27 font: Arc<Font>,
28 source: Rc<RefCell<Option<(Vec<u8>, u32, u32)>>>,
29 placeholder: String,
31 min_height: f64,
33 outline: bool,
35 fill_background: bool,
38}
39
40impl ImageView {
41 pub fn new(
42 font: Arc<Font>,
43 source: Rc<RefCell<Option<(Vec<u8>, u32, u32)>>>,
44 ) -> Self {
45 Self {
46 bounds: Rect::default(),
47 children: Vec::new(),
48 base: WidgetBase::new(),
49 font,
50 source,
51 placeholder: "No image yet.".into(),
52 min_height: 120.0,
53 outline: true,
54 fill_background: true,
55 }
56 }
57
58 pub fn with_placeholder(mut self, text: impl Into<String>) -> Self {
59 self.placeholder = text.into(); self
60 }
61 pub fn with_min_height(mut self, h: f64) -> Self { self.min_height = h; self }
62 pub fn with_outline(mut self, on: bool) -> Self { self.outline = on; self }
63 pub fn with_fill_background(mut self, on: bool) -> Self {
64 self.fill_background = on; self
65 }
66
67 pub fn with_margin(mut self, m: Insets) -> Self { self.base.margin = m; self }
68 pub fn with_h_anchor(mut self, h: HAnchor) -> Self { self.base.h_anchor = h; self }
69 pub fn with_v_anchor(mut self, v: VAnchor) -> Self { self.base.v_anchor = v; self }
70 pub fn with_min_size(mut self, s: Size) -> Self { self.base.min_size = s; self }
71 pub fn with_max_size(mut self, s: Size) -> Self { self.base.max_size = s; self }
72}
73
74impl Widget for ImageView {
75 fn type_name(&self) -> &'static str { "ImageView" }
76 fn bounds(&self) -> Rect { self.bounds }
77 fn set_bounds(&mut self, b: Rect) { self.bounds = b; }
78 fn children(&self) -> &[Box<dyn Widget>] { &self.children }
79 fn children_mut(&mut self) -> &mut Vec<Box<dyn Widget>> { &mut self.children }
80
81 fn margin(&self) -> Insets { self.base.margin }
82 fn h_anchor(&self) -> HAnchor { self.base.h_anchor }
83 fn v_anchor(&self) -> VAnchor { self.base.v_anchor }
84 fn min_size(&self) -> Size { self.base.min_size }
85 fn max_size(&self) -> Size { self.base.max_size }
86
87 fn layout(&mut self, available: Size) -> Size {
88 let h = available.height.max(self.min_height);
89 self.bounds = Rect::new(0.0, 0.0, available.width, h);
90 Size::new(self.bounds.width, self.bounds.height)
91 }
92
93 fn paint(&mut self, ctx: &mut dyn DrawCtx) {
94 let v = ctx.visuals();
95 let w = self.bounds.width;
96 let h = self.bounds.height;
97
98 if self.fill_background {
99 ctx.set_fill_color(v.bg_color);
100 ctx.begin_path();
101 ctx.rounded_rect(0.0, 0.0, w, h, 4.0);
102 ctx.fill();
103 }
104
105 let src = self.source.borrow();
106 if let Some((pixels, iw, ih)) = src.as_ref() {
107 let iwf = *iw as f64;
108 let ihf = *ih as f64;
109 let scale = (w / iwf).min(h / ihf).max(0.0);
110 let dw = iwf * scale;
111 let dh = ihf * scale;
112 let dx = (w - dw) * 0.5;
113 let dy = (h - dh) * 0.5;
114 ctx.draw_image_rgba(pixels, *iw, *ih, dx, dy, dw, dh);
115
116 if self.outline {
117 ctx.set_stroke_color(v.text_color);
118 ctx.set_line_width(1.0);
119 ctx.begin_path();
120 ctx.rect(dx, dy, dw, dh);
121 ctx.stroke();
122 }
123 } else {
124 ctx.set_font(Arc::clone(&self.font));
125 ctx.set_font_size(13.0);
126 ctx.set_fill_color(v.text_dim);
127 if let Some(m) = ctx.measure_text(&self.placeholder) {
128 let tx = (w - m.width) * 0.5;
129 let ty = h * 0.5 - (m.ascent - m.descent) * 0.5;
130 ctx.fill_text(&self.placeholder, tx, ty);
131 }
132 }
133
134 let _ = Color::white();
136 }
137
138 fn on_event(&mut self, _: &Event) -> EventResult { EventResult::Ignored }
139}