"Final" image polish (#3342)
* Improve the Image API a bit * Improve image view demo * Better names * calculate -> calc
This commit is contained in:
parent
d7d222d3f6
commit
2bbceb856b
|
|
@ -187,7 +187,7 @@ impl Widget for Button<'_> {
|
|||
|
||||
let image_size = if let Some(image) = &image {
|
||||
image
|
||||
.load_and_calculate_size(ui, space_available_for_image)
|
||||
.load_and_calc_size(ui, space_available_for_image)
|
||||
.unwrap_or(space_available_for_image)
|
||||
} else {
|
||||
Vec2::ZERO
|
||||
|
|
@ -276,7 +276,7 @@ impl Widget for Button<'_> {
|
|||
image_size,
|
||||
);
|
||||
cursor_x += image_size.x;
|
||||
let tlr = image.load(ui);
|
||||
let tlr = image.load_for_size(ui.ctx(), image_size);
|
||||
widgets::image::paint_texture_load_result(
|
||||
ui,
|
||||
&tlr,
|
||||
|
|
@ -605,11 +605,12 @@ impl<'a> Widget for ImageButton<'a> {
|
|||
Vec2::ZERO
|
||||
};
|
||||
|
||||
let tlr = self.image.load(ui);
|
||||
let texture_size = tlr.as_ref().ok().and_then(|t| t.size());
|
||||
let available_size_for_image = ui.available_size() - 2.0 * padding;
|
||||
let tlr = self.image.load_for_size(ui.ctx(), available_size_for_image);
|
||||
let original_image_size = tlr.as_ref().ok().and_then(|t| t.size());
|
||||
let image_size = self
|
||||
.image
|
||||
.calculate_size(ui.available_size() - 2.0 * padding, texture_size);
|
||||
.calc_size(available_size_for_image, original_image_size);
|
||||
|
||||
let padded_size = image_size + 2.0 * padding;
|
||||
let (rect, response) = ui.allocate_exact_size(padded_size, self.sense);
|
||||
|
|
|
|||
|
|
@ -239,14 +239,14 @@ impl<'a, T: Into<ImageSource<'a>>> From<T> for Image<'a> {
|
|||
impl<'a> Image<'a> {
|
||||
/// Returns the size the image will occupy in the final UI.
|
||||
#[inline]
|
||||
pub fn calculate_size(&self, available_size: Vec2, image_size: Option<Vec2>) -> Vec2 {
|
||||
let image_size = image_size.unwrap_or(Vec2::splat(24.0)); // Fallback for still-loading textures, or failure to load.
|
||||
self.size.get(available_size, image_size)
|
||||
pub fn calc_size(&self, available_size: Vec2, original_image_size: Option<Vec2>) -> Vec2 {
|
||||
let original_image_size = original_image_size.unwrap_or(Vec2::splat(24.0)); // Fallback for still-loading textures, or failure to load.
|
||||
self.size.calc_size(available_size, original_image_size)
|
||||
}
|
||||
|
||||
pub fn load_and_calculate_size(&self, ui: &mut Ui, available_size: Vec2) -> Option<Vec2> {
|
||||
let image_size = self.load(ui).ok()?.size()?;
|
||||
Some(self.size.get(available_size, image_size))
|
||||
pub fn load_and_calc_size(&self, ui: &mut Ui, available_size: Vec2) -> Option<Vec2> {
|
||||
let image_size = self.load_for_size(ui.ctx(), available_size).ok()?.size()?;
|
||||
Some(self.size.calc_size(available_size, image_size))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
@ -269,13 +269,15 @@ impl<'a> Image<'a> {
|
|||
|
||||
/// Load the image from its [`Image::source`], returning the resulting [`SizedTexture`].
|
||||
///
|
||||
/// The `available_size` is used as a hint when e.g. rendering an svg.
|
||||
///
|
||||
/// # Errors
|
||||
/// May fail if they underlying [`Context::try_load_texture`] call fails.
|
||||
pub fn load(&self, ui: &Ui) -> TextureLoadResult {
|
||||
let size_hint = self.size.hint(ui.available_size());
|
||||
pub fn load_for_size(&self, ctx: &Context, available_size: Vec2) -> TextureLoadResult {
|
||||
let size_hint = self.size.hint(available_size);
|
||||
self.source
|
||||
.clone()
|
||||
.load(ui.ctx(), self.texture_options, size_hint)
|
||||
.load(ctx, self.texture_options, size_hint)
|
||||
}
|
||||
|
||||
/// Paint the image in the given rectangle.
|
||||
|
|
@ -283,7 +285,7 @@ impl<'a> Image<'a> {
|
|||
pub fn paint_at(&self, ui: &mut Ui, rect: Rect) {
|
||||
paint_texture_load_result(
|
||||
ui,
|
||||
&self.load(ui),
|
||||
&self.load_for_size(ui.ctx(), rect.size()),
|
||||
rect,
|
||||
self.show_loading_spinner,
|
||||
&self.image_options,
|
||||
|
|
@ -293,9 +295,9 @@ impl<'a> Image<'a> {
|
|||
|
||||
impl<'a> Widget for Image<'a> {
|
||||
fn ui(self, ui: &mut Ui) -> Response {
|
||||
let tlr = self.load(ui);
|
||||
let texture_size = tlr.as_ref().ok().and_then(|t| t.size());
|
||||
let ui_size = self.calculate_size(ui.available_size(), texture_size);
|
||||
let tlr = self.load_for_size(ui.ctx(), ui.available_size());
|
||||
let original_image_size = tlr.as_ref().ok().and_then(|t| t.size());
|
||||
let ui_size = self.calc_size(ui.available_size(), original_image_size);
|
||||
|
||||
let (rect, response) = ui.allocate_exact_size(ui_size, self.sense);
|
||||
paint_texture_load_result(
|
||||
|
|
@ -364,29 +366,29 @@ impl ImageFit {
|
|||
}
|
||||
|
||||
impl ImageSize {
|
||||
/// Size hint for e.g. rasterizing an svg.
|
||||
pub fn hint(&self, available_size: Vec2) -> SizeHint {
|
||||
if self.maintain_aspect_ratio {
|
||||
return SizeHint::Scale(1.0.ord());
|
||||
};
|
||||
|
||||
let fit = match self.fit {
|
||||
let size = match self.fit {
|
||||
ImageFit::Original { scale } => return SizeHint::Scale(scale.ord()),
|
||||
ImageFit::Fraction(fract) => available_size * fract,
|
||||
ImageFit::Exact(size) => size,
|
||||
};
|
||||
|
||||
let fit = fit.min(self.max_size);
|
||||
let size = size.min(self.max_size);
|
||||
|
||||
// TODO(emilk): take pixels_per_point into account here!
|
||||
|
||||
// `inf` on an axis means "any value"
|
||||
match (fit.x.is_finite(), fit.y.is_finite()) {
|
||||
(true, true) => SizeHint::Size(fit.x.round() as u32, fit.y.round() as u32),
|
||||
(true, false) => SizeHint::Width(fit.x.round() as u32),
|
||||
(false, true) => SizeHint::Height(fit.y.round() as u32),
|
||||
match (size.x.is_finite(), size.y.is_finite()) {
|
||||
(true, true) => SizeHint::Size(size.x.round() as u32, size.y.round() as u32),
|
||||
(true, false) => SizeHint::Width(size.x.round() as u32),
|
||||
(false, true) => SizeHint::Height(size.y.round() as u32),
|
||||
(false, false) => SizeHint::Scale(1.0.ord()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get(&self, available_size: Vec2, image_size: Vec2) -> Vec2 {
|
||||
/// Calculate the final on-screen size in points.
|
||||
pub fn calc_size(&self, available_size: Vec2, original_image_size: Vec2) -> Vec2 {
|
||||
let Self {
|
||||
maintain_aspect_ratio,
|
||||
max_size,
|
||||
|
|
@ -394,7 +396,7 @@ impl ImageSize {
|
|||
} = *self;
|
||||
match fit {
|
||||
ImageFit::Original { scale } => {
|
||||
let image_size = image_size * scale;
|
||||
let image_size = original_image_size * scale;
|
||||
if image_size.x <= max_size.x && image_size.y <= max_size.y {
|
||||
image_size
|
||||
} else {
|
||||
|
|
@ -403,11 +405,11 @@ impl ImageSize {
|
|||
}
|
||||
ImageFit::Fraction(fract) => {
|
||||
let scale_to_size = (available_size * fract).min(max_size);
|
||||
scale_to_fit(image_size, scale_to_size, maintain_aspect_ratio)
|
||||
scale_to_fit(original_image_size, scale_to_size, maintain_aspect_ratio)
|
||||
}
|
||||
ImageFit::Exact(size) => {
|
||||
let scale_to_size = size.min(max_size);
|
||||
scale_to_fit(image_size, scale_to_size, maintain_aspect_ratio)
|
||||
scale_to_fit(original_image_size, scale_to_size, maintain_aspect_ratio)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -483,6 +485,15 @@ impl<'a> std::fmt::Debug for ImageSource<'a> {
|
|||
}
|
||||
|
||||
impl<'a> ImageSource<'a> {
|
||||
/// Size of the texture, if known.
|
||||
#[inline]
|
||||
pub fn texture_size(&self) -> Option<Vec2> {
|
||||
match self {
|
||||
ImageSource::Texture(texture) => Some(texture.size),
|
||||
ImageSource::Uri(_) | ImageSource::Bytes(_, _) => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// # Errors
|
||||
/// Failure to load the texture.
|
||||
pub fn load(
|
||||
|
|
|
|||
|
|
@ -105,13 +105,17 @@ impl eframe::App for ImageViewer {
|
|||
|
||||
// bg_fill
|
||||
ui.add_space(2.0);
|
||||
ui.label("Background color");
|
||||
ui.color_edit_button_srgba(&mut self.image_options.bg_fill);
|
||||
ui.horizontal(|ui| {
|
||||
ui.color_edit_button_srgba(&mut self.image_options.bg_fill);
|
||||
ui.label("Background color");
|
||||
});
|
||||
|
||||
// tint
|
||||
ui.add_space(2.0);
|
||||
ui.label("Tint");
|
||||
ui.color_edit_button_srgba(&mut self.image_options.tint);
|
||||
ui.horizontal(|ui| {
|
||||
ui.color_edit_button_srgba(&mut self.image_options.tint);
|
||||
ui.label("Tint");
|
||||
});
|
||||
|
||||
// fit
|
||||
ui.add_space(10.0);
|
||||
|
|
|
|||
|
|
@ -212,7 +212,7 @@ impl WrapApp {
|
|||
),
|
||||
#[cfg(feature = "image_viewer")]
|
||||
(
|
||||
"🖼️ Image Viewer",
|
||||
"🖼 Image Viewer",
|
||||
Anchor::ImageViewer,
|
||||
&mut self.state.image_viewer as &mut dyn eframe::App,
|
||||
),
|
||||
|
|
|
|||
Loading…
Reference in New Issue