1use super::Scaling;
9use kas::draw::ImageHandle;
10use kas::layout::LogicalSize;
11use kas::prelude::*;
12use kas::theme::MarginStyle;
13
14#[impl_self]
15mod Sprite {
16 #[derive(Debug, Default)]
23 #[widget]
24 pub struct Sprite {
25 core: widget_core!(),
26 scaling: Scaling,
27 image_size: Size,
28 handle: Option<ImageHandle>,
29 }
30
31 impl Self {
32 #[inline]
34 pub fn new() -> Self {
35 Self::default()
36 }
37
38 pub fn set(&mut self, cx: &mut EventCx, handle: ImageHandle) -> bool {
42 let draw = cx.draw_shared();
43 if let Some(old_handle) = self.handle.take() {
44 draw.image_free(old_handle);
45 }
46
47 if let Some(size) = draw.image_size(&handle) {
48 if self.scaling.size == LogicalSize::default() && self.image_size != size {
49 cx.resize();
50 }
51 self.image_size = size;
52 self.handle = Some(handle);
53 true
54 } else {
55 self.image_size = Size::ZERO;
56 false
57 }
58 }
59
60 #[inline]
65 pub fn handle(&self) -> Option<&ImageHandle> {
66 self.handle.as_ref()
67 }
68
69 #[inline]
74 pub fn image_size(&self) -> Size {
75 self.image_size
76 }
77
78 pub fn clear(&mut self, cx: &mut EventCx) {
80 if let Some(handle) = self.handle.take() {
81 cx.draw_shared().image_free(handle);
82 if self.scaling.size == LogicalSize::default() {
83 cx.resize();
84 }
85 }
86 }
87
88 pub fn set_logical_size(&mut self, size: impl Into<LogicalSize>) {
92 self.scaling.size = size.into();
93 }
94
95 #[must_use]
99 pub fn with_logical_size(mut self, size: impl Into<LogicalSize>) -> Self {
100 self.scaling.size = size.into();
101 self
102 }
103
104 #[must_use]
108 #[inline]
109 pub fn with_margin_style(mut self, style: MarginStyle) -> Self {
110 self.scaling.margins = style;
111 self
112 }
113
114 #[must_use]
120 #[inline]
121 pub fn with_fixed_aspect_ratio(mut self, fixed: bool) -> Self {
122 self.scaling.fix_aspect = fixed;
123 self
124 }
125
126 #[must_use]
131 #[inline]
132 pub fn with_stretch(mut self, stretch: Stretch) -> Self {
133 self.scaling.stretch = stretch;
134 self
135 }
136 }
137
138 impl Layout for Self {
139 fn size_rules(&mut self, cx: &mut SizeCx, axis: AxisInfo) -> SizeRules {
140 if self.scaling.size == LogicalSize::default() {
141 let scale: i32 = (cx.scale_factor() * 0.9).cast_nearest();
142 debug_assert!(scale >= 1);
143 SizeRules::fixed(self.image_size.extract(axis) * scale)
144 .with_margins(cx.margins(self.scaling.margins).extract(axis))
145 } else {
146 self.scaling.size_rules(cx, axis)
147 }
148 }
149
150 fn set_rect(&mut self, cx: &mut SizeCx, rect: Rect, hints: AlignHints) {
151 let align = hints.complete_default();
152 let rect = if self.scaling.size == LogicalSize::default() {
153 let image_size = self.image_size.max(Size::splat(1));
155 let scale = (rect.size.0 / image_size.0)
156 .min(rect.size.1 / image_size.1)
157 .max(1);
158 let size = self.image_size * scale;
159 align.aligned_rect(size, rect)
160 } else {
161 let scale_factor = cx.scale_factor();
162 self.scaling.align(rect, align, scale_factor)
163 };
164 self.core.set_rect(rect);
165 }
166
167 fn draw(&self, mut draw: DrawCx) {
168 if let Some(id) = self.handle.as_ref().map(|h| h.id()) {
169 draw.image(self.rect(), id);
170 }
171 }
172 }
173
174 impl Tile for Self {
175 fn role(&self, _: &mut dyn RoleCx) -> Role<'_> {
176 Role::Image
177 }
178 }
179}