Fix layout of image::Viewer
This commit is contained in:
parent
0cdf8d56ee
commit
21b10dc103
2 changed files with 46 additions and 56 deletions
|
|
@ -5,7 +5,7 @@ use crate::{Primitive, Renderer};
|
||||||
use iced_native::image;
|
use iced_native::image;
|
||||||
use iced_native::image::viewer;
|
use iced_native::image::viewer;
|
||||||
use iced_native::mouse;
|
use iced_native::mouse;
|
||||||
use iced_native::{Rectangle, Vector};
|
use iced_native::{Rectangle, Size, Vector};
|
||||||
|
|
||||||
impl<B> viewer::Renderer for Renderer<B>
|
impl<B> viewer::Renderer for Renderer<B>
|
||||||
where
|
where
|
||||||
|
|
@ -15,7 +15,7 @@ where
|
||||||
&mut self,
|
&mut self,
|
||||||
state: &viewer::State,
|
state: &viewer::State,
|
||||||
bounds: Rectangle,
|
bounds: Rectangle,
|
||||||
image_bounds: Rectangle,
|
image_size: Size,
|
||||||
translation: Vector,
|
translation: Vector,
|
||||||
handle: image::Handle,
|
handle: image::Handle,
|
||||||
is_mouse_over: bool,
|
is_mouse_over: bool,
|
||||||
|
|
@ -28,7 +28,11 @@ where
|
||||||
translation,
|
translation,
|
||||||
content: Box::new(Primitive::Image {
|
content: Box::new(Primitive::Image {
|
||||||
handle,
|
handle,
|
||||||
bounds: image_bounds,
|
bounds: Rectangle {
|
||||||
|
x: bounds.x,
|
||||||
|
y: bounds.y,
|
||||||
|
..Rectangle::with_size(image_size)
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
offset: Vector::new(0, 0),
|
offset: Vector::new(0, 0),
|
||||||
|
|
@ -38,8 +42,8 @@ where
|
||||||
if state.is_cursor_clicked() {
|
if state.is_cursor_clicked() {
|
||||||
mouse::Interaction::Grabbing
|
mouse::Interaction::Grabbing
|
||||||
} else if is_mouse_over
|
} else if is_mouse_over
|
||||||
&& (image_bounds.width > bounds.width
|
&& (image_size.width > bounds.width
|
||||||
|| image_bounds.height > bounds.height)
|
|| image_size.height > bounds.height)
|
||||||
{
|
{
|
||||||
mouse::Interaction::Grab
|
mouse::Interaction::Grab
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -122,11 +122,7 @@ impl<'a> Viewer<'a> {
|
||||||
/// will be respected.
|
/// will be respected.
|
||||||
///
|
///
|
||||||
/// [`Viewer`]: struct.Viewer.html
|
/// [`Viewer`]: struct.Viewer.html
|
||||||
fn image_bounds<Renderer>(
|
fn image_size<Renderer>(&self, renderer: &Renderer, bounds: Size) -> Size
|
||||||
&self,
|
|
||||||
renderer: &Renderer,
|
|
||||||
bounds: Rectangle,
|
|
||||||
) -> Rectangle
|
|
||||||
where
|
where
|
||||||
Renderer: self::Renderer + image::Renderer,
|
Renderer: self::Renderer + image::Renderer,
|
||||||
{
|
{
|
||||||
|
|
@ -149,12 +145,7 @@ impl<'a> Viewer<'a> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Rectangle {
|
Size::new(width, height)
|
||||||
x: bounds.x,
|
|
||||||
y: bounds.y,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -189,19 +180,25 @@ where
|
||||||
|
|
||||||
fn layout(
|
fn layout(
|
||||||
&self,
|
&self,
|
||||||
_renderer: &Renderer,
|
renderer: &Renderer,
|
||||||
limits: &layout::Limits,
|
limits: &layout::Limits,
|
||||||
) -> layout::Node {
|
) -> layout::Node {
|
||||||
let padding = f32::from(self.padding);
|
let (width, height) = renderer.dimensions(&self.handle);
|
||||||
|
|
||||||
let limits = limits
|
let aspect_ratio = width as f32 / height as f32;
|
||||||
.max_width(self.max_width)
|
|
||||||
.max_height(self.max_height)
|
let mut size = limits
|
||||||
.width(self.width)
|
.width(self.width)
|
||||||
.height(self.height)
|
.height(self.height)
|
||||||
.pad(padding);
|
.resolve(Size::new(width as f32, height as f32));
|
||||||
|
|
||||||
let size = limits.resolve(Size::INFINITY);
|
let viewport_aspect_ratio = size.width / size.height;
|
||||||
|
|
||||||
|
if viewport_aspect_ratio > aspect_ratio {
|
||||||
|
size.width = width as f32 * size.height / height as f32;
|
||||||
|
} else {
|
||||||
|
size.height = height as f32 * size.width / width as f32;
|
||||||
|
}
|
||||||
|
|
||||||
layout::Node::new(size)
|
layout::Node::new(size)
|
||||||
}
|
}
|
||||||
|
|
@ -242,8 +239,8 @@ where
|
||||||
.min(self.max_scale),
|
.min(self.max_scale),
|
||||||
);
|
);
|
||||||
|
|
||||||
let image_bounds =
|
let image_size =
|
||||||
self.image_bounds(renderer, bounds);
|
self.image_size(renderer, bounds.size());
|
||||||
|
|
||||||
let factor = self.state.scale.unwrap()
|
let factor = self.state.scale.unwrap()
|
||||||
/ previous_scale
|
/ previous_scale
|
||||||
|
|
@ -259,13 +256,13 @@ where
|
||||||
+ self.state.current_offset * factor;
|
+ self.state.current_offset * factor;
|
||||||
|
|
||||||
self.state.current_offset = Vector::new(
|
self.state.current_offset = Vector::new(
|
||||||
if image_bounds.width > bounds.width {
|
if image_size.width > bounds.width {
|
||||||
self.state.current_offset.x
|
self.state.current_offset.x
|
||||||
+ adjustment.x
|
+ adjustment.x
|
||||||
} else {
|
} else {
|
||||||
0.0
|
0.0
|
||||||
},
|
},
|
||||||
if image_bounds.height > bounds.height {
|
if image_size.height > bounds.height {
|
||||||
self.state.current_offset.y
|
self.state.current_offset.y
|
||||||
+ adjustment.y
|
+ adjustment.y
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -290,14 +287,11 @@ where
|
||||||
}
|
}
|
||||||
Event::Mouse(mouse::Event::CursorMoved { position }) => {
|
Event::Mouse(mouse::Event::CursorMoved { position }) => {
|
||||||
if self.state.is_cursor_clicked() {
|
if self.state.is_cursor_clicked() {
|
||||||
let image_bounds = self.image_bounds(renderer, bounds);
|
let image_size =
|
||||||
|
self.image_size(renderer, bounds.size());
|
||||||
|
|
||||||
self.state.pan(
|
self.state
|
||||||
position.x,
|
.pan(position.x, position.y, bounds, image_size);
|
||||||
position.y,
|
|
||||||
bounds,
|
|
||||||
image_bounds,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
@ -322,15 +316,15 @@ where
|
||||||
) -> Renderer::Output {
|
) -> Renderer::Output {
|
||||||
let bounds = layout.bounds();
|
let bounds = layout.bounds();
|
||||||
|
|
||||||
let image_bounds = self.image_bounds(renderer, bounds);
|
let image_size = self.image_size(renderer, bounds.size());
|
||||||
|
|
||||||
let translation = {
|
let translation = {
|
||||||
let image_top_left = Vector::new(
|
let image_top_left = Vector::new(
|
||||||
bounds.width / 2.0 - image_bounds.width / 2.0,
|
bounds.width / 2.0 - image_size.width / 2.0,
|
||||||
bounds.height / 2.0 - image_bounds.height / 2.0,
|
bounds.height / 2.0 - image_size.height / 2.0,
|
||||||
);
|
);
|
||||||
|
|
||||||
image_top_left - self.state.offset(bounds, image_bounds)
|
image_top_left - self.state.offset(bounds, image_size)
|
||||||
};
|
};
|
||||||
|
|
||||||
let is_mouse_over = bounds.contains(cursor_position);
|
let is_mouse_over = bounds.contains(cursor_position);
|
||||||
|
|
@ -339,7 +333,7 @@ where
|
||||||
renderer,
|
renderer,
|
||||||
&self.state,
|
&self.state,
|
||||||
bounds,
|
bounds,
|
||||||
image_bounds,
|
image_size,
|
||||||
translation,
|
translation,
|
||||||
self.handle.clone(),
|
self.handle.clone(),
|
||||||
is_mouse_over,
|
is_mouse_over,
|
||||||
|
|
@ -384,31 +378,24 @@ impl State {
|
||||||
///
|
///
|
||||||
/// [`Viewer`]: struct.Viewer.html
|
/// [`Viewer`]: struct.Viewer.html
|
||||||
/// [`State`]: struct.State.html
|
/// [`State`]: struct.State.html
|
||||||
fn pan(
|
fn pan(&mut self, x: f32, y: f32, bounds: Rectangle, image_size: Size) {
|
||||||
&mut self,
|
let hidden_width = ((image_size.width - bounds.width) as f32 / 2.0)
|
||||||
x: f32,
|
|
||||||
y: f32,
|
|
||||||
bounds: Rectangle,
|
|
||||||
image_bounds: Rectangle,
|
|
||||||
) {
|
|
||||||
let hidden_width = ((image_bounds.width - bounds.width) as f32 / 2.0)
|
|
||||||
.max(0.0)
|
.max(0.0)
|
||||||
.round();
|
.round();
|
||||||
let hidden_height = ((image_bounds.height - bounds.height) as f32
|
let hidden_height = ((image_size.height - bounds.height) as f32 / 2.0)
|
||||||
/ 2.0)
|
|
||||||
.max(0.0)
|
.max(0.0)
|
||||||
.round();
|
.round();
|
||||||
|
|
||||||
let delta_x = x - self.starting_cursor_pos.unwrap().x;
|
let delta_x = x - self.starting_cursor_pos.unwrap().x;
|
||||||
let delta_y = y - self.starting_cursor_pos.unwrap().y;
|
let delta_y = y - self.starting_cursor_pos.unwrap().y;
|
||||||
|
|
||||||
if bounds.width < image_bounds.width {
|
if bounds.width < image_size.width {
|
||||||
self.current_offset.x = (self.starting_offset.x - delta_x)
|
self.current_offset.x = (self.starting_offset.x - delta_x)
|
||||||
.min(hidden_width)
|
.min(hidden_width)
|
||||||
.max(-1.0 * hidden_width);
|
.max(-1.0 * hidden_width);
|
||||||
}
|
}
|
||||||
|
|
||||||
if bounds.height < image_bounds.height {
|
if bounds.height < image_size.height {
|
||||||
self.current_offset.y = (self.starting_offset.y - delta_y)
|
self.current_offset.y = (self.starting_offset.y - delta_y)
|
||||||
.min(hidden_height)
|
.min(hidden_height)
|
||||||
.max(-1.0 * hidden_height);
|
.max(-1.0 * hidden_height);
|
||||||
|
|
@ -420,12 +407,11 @@ impl State {
|
||||||
///
|
///
|
||||||
/// [`Viewer`]: struct.Viewer.html
|
/// [`Viewer`]: struct.Viewer.html
|
||||||
/// [`State`]: struct.State.html
|
/// [`State`]: struct.State.html
|
||||||
fn offset(&self, bounds: Rectangle, image_bounds: Rectangle) -> Vector {
|
fn offset(&self, bounds: Rectangle, image_size: Size) -> Vector {
|
||||||
let hidden_width = ((image_bounds.width - bounds.width) as f32 / 2.0)
|
let hidden_width = ((image_size.width - bounds.width) as f32 / 2.0)
|
||||||
.max(0.0)
|
.max(0.0)
|
||||||
.round();
|
.round();
|
||||||
let hidden_height = ((image_bounds.height - bounds.height) as f32
|
let hidden_height = ((image_size.height - bounds.height) as f32 / 2.0)
|
||||||
/ 2.0)
|
|
||||||
.max(0.0)
|
.max(0.0)
|
||||||
.round();
|
.round();
|
||||||
|
|
||||||
|
|
@ -476,7 +462,7 @@ pub trait Renderer: crate::Renderer + Sized {
|
||||||
&mut self,
|
&mut self,
|
||||||
state: &State,
|
state: &State,
|
||||||
bounds: Rectangle,
|
bounds: Rectangle,
|
||||||
image_bounds: Rectangle,
|
image_size: Size,
|
||||||
translation: Vector,
|
translation: Vector,
|
||||||
handle: image::Handle,
|
handle: image::Handle,
|
||||||
is_mouse_over: bool,
|
is_mouse_over: bool,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue