use super::Scaling;
use kas::draw::ImageHandle;
use kas::layout::LogicalSize;
use kas::prelude::*;
use kas::theme::MarginStyle;
#[impl_self]
mod Sprite {
#[derive(Debug, Default)]
#[widget]
pub struct Sprite {
core: widget_core!(),
scaling: Scaling,
image_size: Size,
handle: Option<ImageHandle>,
}
impl Self {
#[inline]
pub fn new() -> Self {
Self::default()
}
pub fn set(&mut self, cx: &mut EventCx, handle: ImageHandle) -> bool {
let draw = cx.draw_shared();
if let Some(old_handle) = self.handle.take() {
draw.image_free(old_handle);
}
if let Some(size) = draw.image_size(&handle) {
if self.scaling.size == LogicalSize::default() && self.image_size != size {
cx.resize();
}
self.image_size = size;
self.handle = Some(handle);
true
} else {
self.image_size = Size::ZERO;
false
}
}
#[inline]
pub fn handle(&self) -> Option<&ImageHandle> {
self.handle.as_ref()
}
#[inline]
pub fn image_size(&self) -> Size {
self.image_size
}
pub fn clear(&mut self, cx: &mut EventCx) {
if let Some(handle) = self.handle.take() {
cx.draw_shared().image_free(handle);
if self.scaling.size == LogicalSize::default() {
cx.resize();
}
}
}
pub fn set_logical_size(&mut self, size: impl Into<LogicalSize>) {
self.scaling.size = size.into();
}
#[must_use]
pub fn with_logical_size(mut self, size: impl Into<LogicalSize>) -> Self {
self.scaling.size = size.into();
self
}
#[must_use]
#[inline]
pub fn with_margin_style(mut self, style: MarginStyle) -> Self {
self.scaling.margins = style;
self
}
#[must_use]
#[inline]
pub fn with_fixed_aspect_ratio(mut self, fixed: bool) -> Self {
self.scaling.fix_aspect = fixed;
self
}
#[must_use]
#[inline]
pub fn with_stretch(mut self, stretch: Stretch) -> Self {
self.scaling.stretch = stretch;
self
}
}
impl Layout for Self {
fn size_rules(&mut self, cx: &mut SizeCx, axis: AxisInfo) -> SizeRules {
if self.scaling.size == LogicalSize::default() {
let scale: i32 = (cx.scale_factor() * 0.9).cast_nearest();
debug_assert!(scale >= 1);
SizeRules::fixed(self.image_size.extract(axis) * scale)
.with_margins(cx.margins(self.scaling.margins).extract(axis))
} else {
self.scaling.size_rules(cx, axis)
}
}
fn set_rect(&mut self, cx: &mut SizeCx, rect: Rect, hints: AlignHints) {
let align = hints.complete_default();
let rect = if self.scaling.size == LogicalSize::default() {
let image_size = self.image_size.max(Size::splat(1));
let scale = (rect.size.0 / image_size.0)
.min(rect.size.1 / image_size.1)
.max(1);
let size = self.image_size * scale;
align.aligned_rect(size, rect)
} else {
let scale_factor = cx.scale_factor();
self.scaling.align(rect, align, scale_factor)
};
self.core.set_rect(rect);
}
fn draw(&self, mut draw: DrawCx) {
if let Some(id) = self.handle.as_ref().map(|h| h.id()) {
draw.image(self.rect(), id);
}
}
}
impl Tile for Self {
fn role(&self, _: &mut dyn RoleCx) -> Role<'_> {
Role::Image
}
}
}