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) => {
|
||||
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.
|
||||
_ => {},
|
||||
}
|
||||
|
@ -19,7 +19,6 @@ use conrod_core::{
|
||||
widget::{text_box::Event as TextBoxEvent, Button, Image, List, Rectangle, Text, TextBox},
|
||||
widget_ids, Borderable, Color, Colorable, Labelable, Positionable, Sizeable, Widget,
|
||||
};
|
||||
use iced::{Column, Row};
|
||||
use image::DynamicImage;
|
||||
use rand::{seq::SliceRandom, thread_rng, Rng};
|
||||
use std::time::Duration;
|
||||
@ -194,17 +193,44 @@ struct IcedState {
|
||||
pub type Message = Event;
|
||||
impl IcedState {
|
||||
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 image2 = ui::ice::Image::new((self.imgs.bg, ui::Rotation::None));
|
||||
let image3 = ui::ice::Image::new((self.imgs.bg, ui::Rotation::None));
|
||||
let buttons = Column::with_children(vec![
|
||||
Image::new(self.imgs.button).fix_aspect_ratio().into(),
|
||||
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)
|
||||
.height(Length::Fill)
|
||||
.spacing(20)
|
||||
.padding(20)
|
||||
.into()
|
||||
}
|
||||
|
||||
@ -236,6 +262,7 @@ pub struct MainMenuUi {
|
||||
voxygen_i18n: std::sync::Arc<VoxygenLocalization>,
|
||||
fonts: ConrodVoxygenFonts,
|
||||
tip_no: u16,
|
||||
pub show_iced: bool,
|
||||
}
|
||||
|
||||
impl<'a> MainMenuUi {
|
||||
@ -314,6 +341,7 @@ impl<'a> MainMenuUi {
|
||||
voxygen_i18n,
|
||||
fonts,
|
||||
tip_no: 0,
|
||||
show_iced: false,
|
||||
}
|
||||
}
|
||||
|
||||
@ -975,6 +1003,8 @@ impl<'a> MainMenuUi {
|
||||
|
||||
pub fn render(&self, renderer: &mut Renderer) {
|
||||
self.ui.render(renderer, None);
|
||||
self.ice_ui.render(renderer);
|
||||
if self.show_iced {
|
||||
self.ice_ui.render(renderer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -187,6 +187,27 @@ impl GraphicCache {
|
||||
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) {
|
||||
self.cache_map.clear();
|
||||
|
||||
|
@ -7,7 +7,7 @@ mod winit_conversion;
|
||||
pub use graphic::{Id, Rotation};
|
||||
pub use iced::Event;
|
||||
pub use renderer::IcedRenderer;
|
||||
pub use widget::image::Image;
|
||||
pub use widget::{background_container::BackgroundContainer, image::Image};
|
||||
pub use winit_conversion::window_event;
|
||||
|
||||
use super::{
|
||||
|
@ -1,4 +1,6 @@
|
||||
mod background_container;
|
||||
mod column;
|
||||
mod container;
|
||||
mod image;
|
||||
mod row;
|
||||
|
||||
@ -7,7 +9,7 @@ use super::{
|
||||
cache::Cache,
|
||||
graphic::{self, Graphic, TexId},
|
||||
},
|
||||
widget,
|
||||
widget, Rotation,
|
||||
};
|
||||
use crate::{
|
||||
render::{
|
||||
@ -15,6 +17,7 @@ use crate::{
|
||||
},
|
||||
Error,
|
||||
};
|
||||
use common::util::srgba_to_linear;
|
||||
//use log::warn;
|
||||
use std::ops::Range;
|
||||
use vek::*;
|
||||
@ -56,11 +59,16 @@ pub enum Primitive {
|
||||
primitives: Vec<Primitive>,
|
||||
},
|
||||
Image {
|
||||
handle: widget::image::Handle,
|
||||
handle: (widget::image::Handle, Rotation),
|
||||
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 {
|
||||
//image_map: Map<(Image, Rotation)>,
|
||||
cache: Cache,
|
||||
@ -241,7 +249,11 @@ impl IcedRenderer {
|
||||
.into_iter()
|
||||
.for_each(|p| self.draw_primitive(p, renderer));
|
||||
},
|
||||
Primitive::Image { handle, bounds } => {
|
||||
Primitive::Image {
|
||||
handle,
|
||||
bounds,
|
||||
color,
|
||||
} => {
|
||||
let (graphic_id, rotation) = handle;
|
||||
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.unwrap_or(conrod_core::color::WHITE).to_fsa().
|
||||
// into());
|
||||
let color = Rgba::from([1.0, 0.0, 1.0, 0.5]);
|
||||
let color = srgba_to_linear(color.map(|e| e as f32 / 255.0));
|
||||
|
||||
let resolution = Vec2::new(
|
||||
(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
|
||||
#[inline(always)]
|
||||
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
|
||||
// middle of a pixel so we need to offset by 0.5 pixels to be on the edge of
|
||||
// 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 vek::Rgba;
|
||||
|
||||
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 {
|
||||
handle,
|
||||
handle: (handle, Rotation::None),
|
||||
bounds: layout.bounds(),
|
||||
color,
|
||||
},
|
||||
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;
|
||||
|
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 iced::{layout, Element, Hasher, Layout, Length, Point, Size, Widget};
|
||||
use super::super::graphic;
|
||||
use iced::{layout, Element, Hasher, Layout, Length, Point, Widget};
|
||||
use std::hash::Hash;
|
||||
use vek::Rgba;
|
||||
|
||||
// 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
|
||||
// elsewhere
|
||||
|
||||
pub type Handle = (graphic::Id, Rotation);
|
||||
pub type Handle = graphic::Id;
|
||||
|
||||
pub struct Image {
|
||||
handle: Handle,
|
||||
width: Length,
|
||||
height: Length,
|
||||
fix_aspect_ratio: bool,
|
||||
color: Rgba<u8>,
|
||||
}
|
||||
|
||||
impl Image {
|
||||
@ -22,6 +25,8 @@ impl Image {
|
||||
handle,
|
||||
width,
|
||||
height,
|
||||
fix_aspect_ratio: false,
|
||||
color: Rgba::broadcast(255),
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,6 +39,16 @@ impl Image {
|
||||
self.height = 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<M, R> Widget<M, R> for Image
|
||||
@ -44,9 +59,23 @@ where
|
||||
|
||||
fn height(&self) -> Length { self.height }
|
||||
|
||||
fn layout(&self, _renderer: &R, limits: &layout::Limits) -> layout::Node {
|
||||
// We don't care about aspect ratios here :p
|
||||
let size = limits.width(self.width).height(self.height).max();
|
||||
fn layout(&self, renderer: &R, limits: &layout::Limits) -> layout::Node {
|
||||
let mut 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)
|
||||
}
|
||||
@ -54,11 +83,11 @@ where
|
||||
fn draw(
|
||||
&self,
|
||||
renderer: &mut R,
|
||||
_defaults: &R::Defaults,
|
||||
defaults: &R::Defaults,
|
||||
layout: Layout<'_>,
|
||||
_cursor_position: Point,
|
||||
) -> R::Output {
|
||||
renderer.draw(self.handle, layout)
|
||||
renderer.draw(self.handle, self.color, layout)
|
||||
}
|
||||
|
||||
fn hash_layout(&self, state: &mut Hasher) {
|
||||
@ -68,7 +97,8 @@ where
|
||||
}
|
||||
|
||||
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>
|
||||
|
Loading…
Reference in New Issue
Block a user