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