mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Begin implementing container widget with an image background
This commit is contained in:
parent
6a4b7b70c2
commit
b5d31f6cba
@ -87,6 +87,13 @@ impl PlayState for MainMenuState {
|
|||||||
Event::Ui(event) => {
|
Event::Ui(event) => {
|
||||||
self.main_menu_ui.handle_event(event);
|
self.main_menu_ui.handle_event(event);
|
||||||
},
|
},
|
||||||
|
// Pass events to iced ui.
|
||||||
|
Event::IcedUi(event) => {
|
||||||
|
self.main_menu_ui.handle_iced_event(event);
|
||||||
|
},
|
||||||
|
Event::InputUpdate(crate::window::GameInput::Jump, true) => {
|
||||||
|
self.main_menu_ui.show_iced ^= true;
|
||||||
|
},
|
||||||
// Ignore all other events.
|
// Ignore all other events.
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,6 @@ use conrod_core::{
|
|||||||
widget::{text_box::Event as TextBoxEvent, Button, Image, List, Rectangle, Text, TextBox},
|
widget::{text_box::Event as TextBoxEvent, Button, Image, List, Rectangle, Text, TextBox},
|
||||||
widget_ids, Borderable, Color, Colorable, Labelable, Positionable, Sizeable, Widget,
|
widget_ids, Borderable, Color, Colorable, Labelable, Positionable, Sizeable, Widget,
|
||||||
};
|
};
|
||||||
use iced::{Column, Row};
|
|
||||||
use image::DynamicImage;
|
use image::DynamicImage;
|
||||||
use rand::{seq::SliceRandom, thread_rng, Rng};
|
use rand::{seq::SliceRandom, thread_rng, Rng};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
@ -194,17 +193,44 @@ struct IcedState {
|
|||||||
pub type Message = Event;
|
pub type Message = Event;
|
||||||
impl IcedState {
|
impl IcedState {
|
||||||
pub fn view(&mut self) -> Element<Message> {
|
pub fn view(&mut self) -> Element<Message> {
|
||||||
use iced::Length;
|
use iced::{Align, Column, Container, Length, Row};
|
||||||
|
use ui::ice::Image;
|
||||||
|
use vek::*;
|
||||||
|
|
||||||
let image1 = ui::ice::Image::new((self.imgs.bg, ui::Rotation::None));
|
let buttons = Column::with_children(vec![
|
||||||
let image2 = ui::ice::Image::new((self.imgs.bg, ui::Rotation::None));
|
Image::new(self.imgs.button).fix_aspect_ratio().into(),
|
||||||
let image3 = ui::ice::Image::new((self.imgs.bg, ui::Rotation::None));
|
Image::new(self.imgs.button).fix_aspect_ratio().into(),
|
||||||
|
Image::new(self.imgs.button).fix_aspect_ratio().into(),
|
||||||
|
])
|
||||||
|
.width(Length::Fill)
|
||||||
|
.max_width(200)
|
||||||
|
.spacing(5)
|
||||||
|
.padding(10);
|
||||||
|
|
||||||
Row::with_children(vec![image1.into(), image2.into(), image3.into()])
|
let buttons = Container::new(buttons)
|
||||||
|
.width(Length::Fill)
|
||||||
|
.height(Length::Fill)
|
||||||
|
.align_y(Align::End)
|
||||||
|
.padding(20);
|
||||||
|
|
||||||
|
let banner_content =
|
||||||
|
Column::with_children(vec![Image::new(self.imgs.v_logo).fix_aspect_ratio().into()]);
|
||||||
|
let banner = ui::ice::BackgroundContainer::new(self.imgs.banner, banner_content)
|
||||||
|
.color(Rgba::new(255, 255, 255, 230))
|
||||||
|
.fix_aspect_ratio()
|
||||||
|
.width(Length::Fill)
|
||||||
|
.height(Length::Fill);
|
||||||
|
|
||||||
|
let image3 = Image::new(self.imgs.banner_bottom).fix_aspect_ratio();
|
||||||
|
|
||||||
|
let content = Row::with_children(vec![buttons.into(), banner.into(), image3.into()])
|
||||||
|
.width(Length::Fill)
|
||||||
|
.height(Length::Fill)
|
||||||
|
.spacing(10);
|
||||||
|
|
||||||
|
ui::ice::BackgroundContainer::new(self.imgs.bg, content)
|
||||||
.width(Length::Fill)
|
.width(Length::Fill)
|
||||||
.height(Length::Fill)
|
.height(Length::Fill)
|
||||||
.spacing(20)
|
|
||||||
.padding(20)
|
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -236,6 +262,7 @@ pub struct MainMenuUi {
|
|||||||
voxygen_i18n: std::sync::Arc<VoxygenLocalization>,
|
voxygen_i18n: std::sync::Arc<VoxygenLocalization>,
|
||||||
fonts: ConrodVoxygenFonts,
|
fonts: ConrodVoxygenFonts,
|
||||||
tip_no: u16,
|
tip_no: u16,
|
||||||
|
pub show_iced: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> MainMenuUi {
|
impl<'a> MainMenuUi {
|
||||||
@ -314,6 +341,7 @@ impl<'a> MainMenuUi {
|
|||||||
voxygen_i18n,
|
voxygen_i18n,
|
||||||
fonts,
|
fonts,
|
||||||
tip_no: 0,
|
tip_no: 0,
|
||||||
|
show_iced: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -975,6 +1003,8 @@ impl<'a> MainMenuUi {
|
|||||||
|
|
||||||
pub fn render(&self, renderer: &mut Renderer) {
|
pub fn render(&self, renderer: &mut Renderer) {
|
||||||
self.ui.render(renderer, None);
|
self.ui.render(renderer, None);
|
||||||
|
if self.show_iced {
|
||||||
self.ice_ui.render(renderer);
|
self.ice_ui.render(renderer);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -187,6 +187,27 @@ impl GraphicCache {
|
|||||||
self.textures.get(id.0).expect("Invalid TexId used")
|
self.textures.get(id.0).expect("Invalid TexId used")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_graphic_dims(&self, (id, rot): (Id, Rotation)) -> Option<(u32, u32)> {
|
||||||
|
use image::GenericImageView;
|
||||||
|
self.get_graphic(id)
|
||||||
|
.and_then(|graphic| match graphic {
|
||||||
|
Graphic::Image(image) => Some(image.dimensions()),
|
||||||
|
Graphic::Voxel(segment, _, _) => {
|
||||||
|
use common::vol::SizedVol;
|
||||||
|
let size = segment.size();
|
||||||
|
// TODO: HACK because they can be rotated arbitrarily, remove
|
||||||
|
Some((size.x, size.z))
|
||||||
|
},
|
||||||
|
Graphic::Blank => None,
|
||||||
|
})
|
||||||
|
.and_then(|(w, h)| match rot {
|
||||||
|
Rotation::None | Rotation::Cw180 => Some((w, h)),
|
||||||
|
Rotation::Cw90 | Rotation::Cw270 => Some((h, w)),
|
||||||
|
// TODO: need dims for these?
|
||||||
|
Rotation::SourceNorth | Rotation::TargetNorth => None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub fn clear_cache(&mut self, renderer: &mut Renderer) {
|
pub fn clear_cache(&mut self, renderer: &mut Renderer) {
|
||||||
self.cache_map.clear();
|
self.cache_map.clear();
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ mod winit_conversion;
|
|||||||
pub use graphic::{Id, Rotation};
|
pub use graphic::{Id, Rotation};
|
||||||
pub use iced::Event;
|
pub use iced::Event;
|
||||||
pub use renderer::IcedRenderer;
|
pub use renderer::IcedRenderer;
|
||||||
pub use widget::image::Image;
|
pub use widget::{background_container::BackgroundContainer, image::Image};
|
||||||
pub use winit_conversion::window_event;
|
pub use winit_conversion::window_event;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
|
mod background_container;
|
||||||
mod column;
|
mod column;
|
||||||
|
mod container;
|
||||||
mod image;
|
mod image;
|
||||||
mod row;
|
mod row;
|
||||||
|
|
||||||
@ -7,7 +9,7 @@ use super::{
|
|||||||
cache::Cache,
|
cache::Cache,
|
||||||
graphic::{self, Graphic, TexId},
|
graphic::{self, Graphic, TexId},
|
||||||
},
|
},
|
||||||
widget,
|
widget, Rotation,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
render::{
|
render::{
|
||||||
@ -15,6 +17,7 @@ use crate::{
|
|||||||
},
|
},
|
||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
|
use common::util::srgba_to_linear;
|
||||||
//use log::warn;
|
//use log::warn;
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
use vek::*;
|
use vek::*;
|
||||||
@ -56,11 +59,16 @@ pub enum Primitive {
|
|||||||
primitives: Vec<Primitive>,
|
primitives: Vec<Primitive>,
|
||||||
},
|
},
|
||||||
Image {
|
Image {
|
||||||
handle: widget::image::Handle,
|
handle: (widget::image::Handle, Rotation),
|
||||||
bounds: iced::Rectangle,
|
bounds: iced::Rectangle,
|
||||||
|
color: Rgba<u8>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Optimization idea inspired by what I think iced wgpu renderer may be doing
|
||||||
|
// Could have layers of things which don't intersect and thus can be reordered
|
||||||
|
// arbitrarily
|
||||||
|
|
||||||
pub struct IcedRenderer {
|
pub struct IcedRenderer {
|
||||||
//image_map: Map<(Image, Rotation)>,
|
//image_map: Map<(Image, Rotation)>,
|
||||||
cache: Cache,
|
cache: Cache,
|
||||||
@ -241,7 +249,11 @@ impl IcedRenderer {
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.for_each(|p| self.draw_primitive(p, renderer));
|
.for_each(|p| self.draw_primitive(p, renderer));
|
||||||
},
|
},
|
||||||
Primitive::Image { handle, bounds } => {
|
Primitive::Image {
|
||||||
|
handle,
|
||||||
|
bounds,
|
||||||
|
color,
|
||||||
|
} => {
|
||||||
let (graphic_id, rotation) = handle;
|
let (graphic_id, rotation) = handle;
|
||||||
let gl_aabr = self.gl_aabr(bounds);
|
let gl_aabr = self.gl_aabr(bounds);
|
||||||
|
|
||||||
@ -252,11 +264,7 @@ impl IcedRenderer {
|
|||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO provide color with the image
|
let color = srgba_to_linear(color.map(|e| e as f32 / 255.0));
|
||||||
// let color =
|
|
||||||
// srgba_to_linear(color.unwrap_or(conrod_core::color::WHITE).to_fsa().
|
|
||||||
// into());
|
|
||||||
let color = Rgba::from([1.0, 0.0, 1.0, 0.5]);
|
|
||||||
|
|
||||||
let resolution = Vec2::new(
|
let resolution = Vec2::new(
|
||||||
(gl_aabr.size().w * self.half_res.x).round() as u16,
|
(gl_aabr.size().w * self.half_res.x).round() as u16,
|
||||||
@ -359,6 +367,7 @@ impl IcedRenderer {
|
|||||||
// offsets from the center of the sceen to pixels
|
// offsets from the center of the sceen to pixels
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn align(res: Vec2<u16>) -> Vec2<f32> {
|
fn align(res: Vec2<u16>) -> Vec2<f32> {
|
||||||
|
// TODO: does this logic still apply in iced's coordinate system?
|
||||||
// If the resolution is odd then the center of the screen will be within the
|
// If the resolution is odd then the center of the screen will be within the
|
||||||
// middle of a pixel so we need to offset by 0.5 pixels to be on the edge of
|
// middle of a pixel so we need to offset by 0.5 pixels to be on the edge of
|
||||||
// a pixel
|
// a pixel
|
||||||
|
28
voxygen/src/ui/ice/renderer/background_container.rs
Normal file
28
voxygen/src/ui/ice/renderer/background_container.rs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
use super::{
|
||||||
|
super::widget::{background_container, image},
|
||||||
|
IcedRenderer, Primitive,
|
||||||
|
};
|
||||||
|
use iced::{Element, Layout, Point};
|
||||||
|
|
||||||
|
impl background_container::Renderer for IcedRenderer {
|
||||||
|
fn draw<M>(
|
||||||
|
&mut self,
|
||||||
|
defaults: &Self::Defaults,
|
||||||
|
layout: Layout<'_>,
|
||||||
|
cursor_position: Point,
|
||||||
|
background: image::Handle,
|
||||||
|
color: vek::Rgba<u8>,
|
||||||
|
content: &Element<'_, M, Self>,
|
||||||
|
content_layout: Layout<'_>,
|
||||||
|
) -> Self::Output {
|
||||||
|
let image_primitive = image::Renderer::draw(self, background, color, layout).0;
|
||||||
|
let (content_primitive, mouse_cursor) =
|
||||||
|
content.draw(self, defaults, content_layout, cursor_position);
|
||||||
|
(
|
||||||
|
Primitive::Group {
|
||||||
|
primitives: vec![image_primitive, content_primitive],
|
||||||
|
},
|
||||||
|
mouse_cursor,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
22
voxygen/src/ui/ice/renderer/container.rs
Normal file
22
voxygen/src/ui/ice/renderer/container.rs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
use super::{IcedRenderer, Primitive};
|
||||||
|
use iced::{container, Element, Layout, MouseCursor, Point, Rectangle};
|
||||||
|
|
||||||
|
impl container::Renderer for IcedRenderer {
|
||||||
|
type Style = ();
|
||||||
|
|
||||||
|
fn draw<M>(
|
||||||
|
&mut self,
|
||||||
|
defaults: &Self::Defaults,
|
||||||
|
bounds: Rectangle,
|
||||||
|
cursor_position: Point,
|
||||||
|
_style_sheet: &Self::Style,
|
||||||
|
content: &Element<'_, M, Self>,
|
||||||
|
content_layout: Layout<'_>,
|
||||||
|
) -> Self::Output {
|
||||||
|
let (content, mouse_cursor) = content.draw(self, defaults, content_layout, cursor_position);
|
||||||
|
|
||||||
|
// We may have more stuff here if styles are used
|
||||||
|
|
||||||
|
(content, mouse_cursor)
|
||||||
|
}
|
||||||
|
}
|
@ -1,12 +1,30 @@
|
|||||||
use super::{super::widget::image, IcedRenderer, Primitive};
|
use super::{
|
||||||
|
super::{widget::image, Rotation},
|
||||||
|
IcedRenderer, Primitive,
|
||||||
|
};
|
||||||
use iced::MouseCursor;
|
use iced::MouseCursor;
|
||||||
|
use vek::Rgba;
|
||||||
|
|
||||||
impl image::Renderer for IcedRenderer {
|
impl image::Renderer for IcedRenderer {
|
||||||
fn draw(&mut self, handle: image::Handle, layout: iced::Layout<'_>) -> Self::Output {
|
fn dimensions(&self, handle: image::Handle) -> (u32, u32) {
|
||||||
|
self.cache
|
||||||
|
.graphic_cache()
|
||||||
|
.get_graphic_dims((handle, Rotation::None))
|
||||||
|
// TODO: don't unwrap
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw(
|
||||||
|
&mut self,
|
||||||
|
handle: image::Handle,
|
||||||
|
color: Rgba<u8>,
|
||||||
|
layout: iced::Layout<'_>,
|
||||||
|
) -> Self::Output {
|
||||||
(
|
(
|
||||||
Primitive::Image {
|
Primitive::Image {
|
||||||
handle,
|
handle: (handle, Rotation::None),
|
||||||
bounds: layout.bounds(),
|
bounds: layout.bounds(),
|
||||||
|
color,
|
||||||
},
|
},
|
||||||
MouseCursor::OutOfBounds,
|
MouseCursor::OutOfBounds,
|
||||||
)
|
)
|
||||||
|
34
voxygen/src/ui/ice/renderer/row.rs
Normal file
34
voxygen/src/ui/ice/renderer/row.rs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
use super::{IcedRenderer, Primitive};
|
||||||
|
use iced::{row, Element, Layout, MouseCursor, Point};
|
||||||
|
|
||||||
|
impl row::Renderer for IcedRenderer {
|
||||||
|
fn draw<M>(
|
||||||
|
&mut self,
|
||||||
|
defaults: &Self::Defaults,
|
||||||
|
children: &[Element<'_, M, Self>],
|
||||||
|
layout: Layout<'_>,
|
||||||
|
cursor_position: Point,
|
||||||
|
) -> Self::Output {
|
||||||
|
let mut mouse_cursor = MouseCursor::OutOfBounds;
|
||||||
|
|
||||||
|
(
|
||||||
|
Primitive::Group {
|
||||||
|
primitives: children
|
||||||
|
.iter()
|
||||||
|
.zip(layout.children())
|
||||||
|
.map(|(child, layout)| {
|
||||||
|
let (primitive, new_mouse_cursor) =
|
||||||
|
child.draw(self, defaults, layout, cursor_position);
|
||||||
|
|
||||||
|
if new_mouse_cursor > mouse_cursor {
|
||||||
|
mouse_cursor = new_mouse_cursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
primitive
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
},
|
||||||
|
mouse_cursor,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -1 +1,2 @@
|
|||||||
|
pub mod background_container;
|
||||||
pub mod image;
|
pub mod image;
|
||||||
|
169
voxygen/src/ui/ice/widget/background_container.rs
Normal file
169
voxygen/src/ui/ice/widget/background_container.rs
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
use iced::{layout, Element, Hasher, Layout, Length, Point, Size, Widget};
|
||||||
|
use std::u32;
|
||||||
|
use vek::Rgba;
|
||||||
|
|
||||||
|
// Note: it might be more efficient to make this generic over the content type
|
||||||
|
|
||||||
|
// Note: maybe we could just use the container styling for this
|
||||||
|
|
||||||
|
/// This widget is displays a background image behind it's content
|
||||||
|
pub struct BackgroundContainer<'a, M, R: self::Renderer> {
|
||||||
|
width: Length,
|
||||||
|
height: Length,
|
||||||
|
max_width: u32,
|
||||||
|
max_height: u32,
|
||||||
|
background: super::image::Handle,
|
||||||
|
fix_aspect_ratio: bool,
|
||||||
|
content: Element<'a, M, R>,
|
||||||
|
color: Rgba<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, M, R> BackgroundContainer<'a, M, R>
|
||||||
|
where
|
||||||
|
R: self::Renderer,
|
||||||
|
{
|
||||||
|
pub fn new(background: super::image::Handle, content: impl Into<Element<'a, M, R>>) -> Self {
|
||||||
|
Self {
|
||||||
|
width: Length::Shrink,
|
||||||
|
height: Length::Shrink,
|
||||||
|
max_width: u32::MAX,
|
||||||
|
max_height: u32::MAX,
|
||||||
|
background,
|
||||||
|
fix_aspect_ratio: false,
|
||||||
|
content: content.into(),
|
||||||
|
color: Rgba::broadcast(255),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn width(mut self, width: Length) -> Self {
|
||||||
|
self.width = width;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn height(mut self, height: Length) -> Self {
|
||||||
|
self.height = height;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn max_width(mut self, max_width: u32) -> Self {
|
||||||
|
self.max_width = max_width;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn max_height(mut self, max_height: u32) -> Self {
|
||||||
|
self.max_height = max_height;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fix_aspect_ratio(mut self) -> Self {
|
||||||
|
self.fix_aspect_ratio = true;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn color(mut self, color: Rgba<u8>) -> Self {
|
||||||
|
self.color = color;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, M, R> Widget<M, R> for BackgroundContainer<'a, M, R>
|
||||||
|
where
|
||||||
|
R: self::Renderer,
|
||||||
|
{
|
||||||
|
fn width(&self) -> Length { self.width }
|
||||||
|
|
||||||
|
fn height(&self) -> Length { self.height }
|
||||||
|
|
||||||
|
fn layout(&self, renderer: &R, limits: &layout::Limits) -> layout::Node {
|
||||||
|
let limits = limits
|
||||||
|
.loose() // why does iced's container do this?
|
||||||
|
.max_width(self.max_width)
|
||||||
|
.max_height(self.max_height)
|
||||||
|
.width(self.width)
|
||||||
|
.height(self.height);
|
||||||
|
|
||||||
|
let (size, content) = if self.fix_aspect_ratio {
|
||||||
|
let (w, h) = renderer.dimensions(self.background);
|
||||||
|
// To fix the aspect ratio we have to have a separate layout from the content
|
||||||
|
// because we can't force the content to have a specific aspect ratio
|
||||||
|
let aspect_ratio = w as f32 / h as f32;
|
||||||
|
// To do this we need to figure out the max width/height of the limits
|
||||||
|
// and then adjust one down to meet the aspect ratio
|
||||||
|
let max_size = limits.max();
|
||||||
|
let (max_width, max_height) = (max_size.width as f32, max_size.height as f32);
|
||||||
|
let max_aspect_ratio = max_width / max_height;
|
||||||
|
let limits = if max_aspect_ratio > aspect_ratio {
|
||||||
|
limits.max_width((max_height * aspect_ratio) as u32)
|
||||||
|
} else {
|
||||||
|
limits.max_height((max_width / aspect_ratio) as u32)
|
||||||
|
};
|
||||||
|
// Get content size
|
||||||
|
// again, why is loose() used here?
|
||||||
|
let content = self.content.layout(renderer, &limits.loose());
|
||||||
|
// This time we need to adjust up to meet the aspect ratio
|
||||||
|
// so that the container is larger than the contents
|
||||||
|
let content_size = content.size();
|
||||||
|
let content_aspect_ratio = content_size.width as f32 / content_size.height as f32;
|
||||||
|
let size = if content_aspect_ratio > aspect_ratio {
|
||||||
|
Size::new(content_size.width, content_size.width / aspect_ratio)
|
||||||
|
} else {
|
||||||
|
Size::new(content_size.height * aspect_ratio, content_size.width)
|
||||||
|
};
|
||||||
|
|
||||||
|
(size, content)
|
||||||
|
} else {
|
||||||
|
// again, why is loose() used here?
|
||||||
|
let content = self.content.layout(renderer, &limits.loose());
|
||||||
|
let size = limits.resolve(content.size());
|
||||||
|
//self.content.layout(renderer, limits)
|
||||||
|
|
||||||
|
(size, content)
|
||||||
|
};
|
||||||
|
|
||||||
|
layout::Node::with_children(size, vec![content])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw(
|
||||||
|
&self,
|
||||||
|
renderer: &mut R,
|
||||||
|
defaults: &R::Defaults,
|
||||||
|
layout: Layout<'_>,
|
||||||
|
cursor_position: Point,
|
||||||
|
) -> R::Output {
|
||||||
|
self::Renderer::draw(
|
||||||
|
renderer,
|
||||||
|
defaults,
|
||||||
|
layout,
|
||||||
|
cursor_position,
|
||||||
|
self.background,
|
||||||
|
self.color,
|
||||||
|
&self.content,
|
||||||
|
layout.children().next().unwrap(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hash_layout(&self, state: &mut Hasher) { self.content.hash_layout(state); }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Renderer: iced::Renderer + super::image::Renderer {
|
||||||
|
fn draw<M>(
|
||||||
|
&mut self,
|
||||||
|
defaults: &Self::Defaults,
|
||||||
|
layout: Layout<'_>,
|
||||||
|
cursor_position: Point,
|
||||||
|
background: super::image::Handle,
|
||||||
|
color: Rgba<u8>,
|
||||||
|
content: &Element<'_, M, Self>,
|
||||||
|
content_layout: Layout<'_>,
|
||||||
|
) -> Self::Output;
|
||||||
|
}
|
||||||
|
|
||||||
|
// They got to live ¯\_(ツ)_/¯
|
||||||
|
impl<'a, M: 'a, R: 'a> From<BackgroundContainer<'a, M, R>> for Element<'a, M, R>
|
||||||
|
where
|
||||||
|
R: self::Renderer,
|
||||||
|
{
|
||||||
|
fn from(background_container: BackgroundContainer<'a, M, R>) -> Element<'a, M, R> {
|
||||||
|
Element::new(background_container)
|
||||||
|
}
|
||||||
|
}
|
@ -1,17 +1,20 @@
|
|||||||
use super::super::super::graphic::{self, Rotation};
|
use super::super::graphic;
|
||||||
use iced::{layout, Element, Hasher, Layout, Length, Point, Size, Widget};
|
use iced::{layout, Element, Hasher, Layout, Length, Point, Widget};
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
|
use vek::Rgba;
|
||||||
|
|
||||||
// TODO: consider iced's approach to images and caching image data
|
// TODO: consider iced's approach to images and caching image data
|
||||||
// Also `Graphic` might be a better name for this is it wasn't already in use
|
// Also `Graphic` might be a better name for this is it wasn't already in use
|
||||||
// elsewhere
|
// elsewhere
|
||||||
|
|
||||||
pub type Handle = (graphic::Id, Rotation);
|
pub type Handle = graphic::Id;
|
||||||
|
|
||||||
pub struct Image {
|
pub struct Image {
|
||||||
handle: Handle,
|
handle: Handle,
|
||||||
width: Length,
|
width: Length,
|
||||||
height: Length,
|
height: Length,
|
||||||
|
fix_aspect_ratio: bool,
|
||||||
|
color: Rgba<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Image {
|
impl Image {
|
||||||
@ -22,6 +25,8 @@ impl Image {
|
|||||||
handle,
|
handle,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
|
fix_aspect_ratio: false,
|
||||||
|
color: Rgba::broadcast(255),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,6 +39,16 @@ impl Image {
|
|||||||
self.height = height;
|
self.height = height;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn fix_aspect_ratio(mut self) -> Self {
|
||||||
|
self.fix_aspect_ratio = true;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn color(mut self, color: Rgba<u8>) -> Self {
|
||||||
|
self.color = color;
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M, R> Widget<M, R> for Image
|
impl<M, R> Widget<M, R> for Image
|
||||||
@ -44,9 +59,23 @@ where
|
|||||||
|
|
||||||
fn height(&self) -> Length { self.height }
|
fn height(&self) -> Length { self.height }
|
||||||
|
|
||||||
fn layout(&self, _renderer: &R, limits: &layout::Limits) -> layout::Node {
|
fn layout(&self, renderer: &R, limits: &layout::Limits) -> layout::Node {
|
||||||
// We don't care about aspect ratios here :p
|
let mut size = limits.width(self.width).height(self.height).max();
|
||||||
let size = limits.width(self.width).height(self.height).max();
|
|
||||||
|
if self.fix_aspect_ratio {
|
||||||
|
let aspect_ratio = {
|
||||||
|
let (w, h) = renderer.dimensions(self.handle);
|
||||||
|
w as f32 / h as f32
|
||||||
|
};
|
||||||
|
|
||||||
|
let max_aspect_ratio = size.width / size.height;
|
||||||
|
|
||||||
|
if max_aspect_ratio > aspect_ratio {
|
||||||
|
size.width = size.height * aspect_ratio;
|
||||||
|
} else {
|
||||||
|
size.height = size.width / aspect_ratio;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
layout::Node::new(size)
|
layout::Node::new(size)
|
||||||
}
|
}
|
||||||
@ -54,11 +83,11 @@ where
|
|||||||
fn draw(
|
fn draw(
|
||||||
&self,
|
&self,
|
||||||
renderer: &mut R,
|
renderer: &mut R,
|
||||||
_defaults: &R::Defaults,
|
defaults: &R::Defaults,
|
||||||
layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
_cursor_position: Point,
|
_cursor_position: Point,
|
||||||
) -> R::Output {
|
) -> R::Output {
|
||||||
renderer.draw(self.handle, layout)
|
renderer.draw(self.handle, self.color, layout)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hash_layout(&self, state: &mut Hasher) {
|
fn hash_layout(&self, state: &mut Hasher) {
|
||||||
@ -68,7 +97,8 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait Renderer: iced::Renderer {
|
pub trait Renderer: iced::Renderer {
|
||||||
fn draw(&mut self, handle: Handle, layout: Layout<'_>) -> Self::Output;
|
fn dimensions(&self, handle: Handle) -> (u32, u32);
|
||||||
|
fn draw(&mut self, handle: Handle, color: Rgba<u8>, layout: Layout<'_>) -> Self::Output;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, M, R> From<Image> for Element<'a, M, R>
|
impl<'a, M, R> From<Image> for Element<'a, M, R>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user