From bbbede68fc2a0167329c2b160ee306552678edb8 Mon Sep 17 00:00:00 2001 From: Imbris Date: Sun, 15 Dec 2019 12:13:52 -0500 Subject: [PATCH] Initial setup to use iced --- Cargo.lock | 127 +++++++- voxygen/Cargo.toml | 10 +- voxygen/src/hud/settings_window.rs | 1 - voxygen/src/menu/main/ui.rs | 74 ++++- voxygen/src/run.rs | 7 + voxygen/src/ui/ice/clipboard.rs | 12 + voxygen/src/ui/ice/mod.rs | 72 +++++ voxygen/src/ui/ice/renderer.rs | 400 +++++++++++++++++++++++++ voxygen/src/ui/ice/renderer/column.rs | 34 +++ voxygen/src/ui/ice/renderer/image.rs | 14 + voxygen/src/ui/ice/widget.rs | 1 + voxygen/src/ui/ice/widget/image.rs | 63 ++++ voxygen/src/ui/ice/winit_conversion.rs | 271 +++++++++++++++++ voxygen/src/ui/img_ids.rs | 19 ++ voxygen/src/ui/mod.rs | 9 +- voxygen/src/window.rs | 10 +- 16 files changed, 1104 insertions(+), 20 deletions(-) create mode 100644 voxygen/src/ui/ice/clipboard.rs create mode 100644 voxygen/src/ui/ice/mod.rs create mode 100644 voxygen/src/ui/ice/renderer.rs create mode 100644 voxygen/src/ui/ice/renderer/column.rs create mode 100644 voxygen/src/ui/ice/renderer/image.rs create mode 100644 voxygen/src/ui/ice/widget.rs create mode 100644 voxygen/src/ui/ice/widget/image.rs create mode 100644 voxygen/src/ui/ice/winit_conversion.rs diff --git a/Cargo.lock b/Cargo.lock index 42287b4056..e7f7f63ce1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -535,6 +535,46 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "clipboard-win" +version = "4.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5123c6b97286809fea9e38d2c9bf530edbcb9fc0d8f8272c28b0c95f067fa92d" +dependencies = [ + "error-code", + "str-buf", + "winapi 0.3.9", +] + +[[package]] +name = "clipboard_macos" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "145a7f9e9b89453bc0a5e32d166456405d389cea5b578f57f1274b1397588a95" +dependencies = [ + "objc", + "objc-foundation", + "objc_id", +] + +[[package]] +name = "clipboard_wayland" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "926d872adca0fc88173f8b7532c651e29ce67dc97323f4546c1c8af6610937fb" +dependencies = [ + "smithay-clipboard 0.5.2", +] + +[[package]] +name = "clipboard_x11" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "137cbd60c42327a8d63e710cee5a4d6a1ac41cdc90449ea2c2c63bd5e186290a" +dependencies = [ + "xcb", +] + [[package]] name = "cloudabi" version = "0.0.3" @@ -708,11 +748,11 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4423d79fed83ebd9ab81ec21fa97144300a961782158287dc9bf7eddac37ff0b" dependencies = [ - "clipboard-win", + "clipboard-win 3.1.1", "objc", "objc-foundation", "objc_id", - "smithay-clipboard", + "smithay-clipboard 0.6.1", "x11-clipboard", ] @@ -1324,6 +1364,16 @@ dependencies = [ "version_check 0.9.2", ] +[[package]] +name = "error-code" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b49c94f66f2d2c5ee8685039e458b4e6c9f13af7c28736baf10ce42966a5ab52" +dependencies = [ + "libc", + "str-buf", +] + [[package]] name = "euc" version = "0.5.1" @@ -1988,6 +2038,33 @@ dependencies = [ "want", ] +[[package]] +name = "iced_core" +version = "0.2.1" +source = "git+https://github.com/hecrj/iced#f46431600cb61d4e83e0ded1ca79525478436be3" + +[[package]] +name = "iced_futures" +version = "0.1.2" +source = "git+https://github.com/hecrj/iced#f46431600cb61d4e83e0ded1ca79525478436be3" +dependencies = [ + "futures 0.3.5", + "log", + "wasm-bindgen-futures", +] + +[[package]] +name = "iced_native" +version = "0.2.2" +source = "git+https://github.com/hecrj/iced#f46431600cb61d4e83e0ded1ca79525478436be3" +dependencies = [ + "iced_core", + "iced_futures", + "num-traits 0.2.12", + "twox-hash", + "unicode-segmentation", +] + [[package]] name = "ident_case" version = "1.0.1" @@ -4039,6 +4116,16 @@ dependencies = [ "wayland-protocols 0.28.1", ] +[[package]] +name = "smithay-clipboard" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e9db50a9b272938b767b731a1291f22f407315def4049db93871e8828034d5" +dependencies = [ + "smithay-client-toolkit 0.11.0", + "wayland-client 0.27.0", +] + [[package]] name = "smithay-clipboard" version = "0.6.1" @@ -4173,6 +4260,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" +[[package]] +name = "str-buf" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d44a3643b4ff9caf57abcee9c2c621d6c03d9135e0d8b589bd9afb5992cb176a" + [[package]] name = "string" version = "0.2.1" @@ -4669,6 +4762,9 @@ name = "twox-hash" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3bfd5b7557925ce778ff9b9ef90e3ade34c524b5ff10e239c69a42d546d2af56" +dependencies = [ + "rand 0.4.6", +] [[package]] name = "tynm" @@ -4989,6 +5085,7 @@ dependencies = [ "glutin", "guillotiere", "hashbrown 0.7.2", + "iced_native", "image", "inline_tweak", "itertools", @@ -5014,6 +5111,7 @@ dependencies = [ "veloren-server", "veloren-voxygen-anim", "veloren-world", + "window_clipboard", "winit", "winres", ] @@ -5171,6 +5269,18 @@ dependencies = [ "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7866cab0aa01de1edf8b5d7936938a7e397ee50ce24119aef3e1eaa3b6171da" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "wasm-bindgen-macro" version = "0.2.68" @@ -5448,6 +5558,19 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "window_clipboard" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b849e24b344ea3535bcda7320b8b7f3560bd2c3692de73153d3c64acc84203e5" +dependencies = [ + "clipboard-win 4.0.3", + "clipboard_macos", + "clipboard_wayland", + "clipboard_x11", + "raw-window-handle", +] + [[package]] name = "winit" version = "0.22.2" diff --git a/voxygen/Cargo.toml b/voxygen/Cargo.toml index e7a4d8a30d..7dfcd90ea8 100644 --- a/voxygen/Cargo.toml +++ b/voxygen/Cargo.toml @@ -24,9 +24,6 @@ common = {package = "veloren-common", path = "../common"} anim = {package = "veloren-voxygen-anim", path = "src/anim", default-features = false} # Graphics -conrod_core = {git = "https://gitlab.com/veloren/conrod.git", branch="copypasta_0.7"} -conrod_winit = {git = "https://gitlab.com/veloren/conrod.git", branch="copypasta_0.7"} -euc = {git = "https://github.com/zesterer/euc.git"} gfx = "0.18.2" gfx_device_gl = {version = "0.16.2", optional = true} gfx_gl = {version = "0.6.1", optional = true} @@ -34,6 +31,13 @@ glutin = {git = "https://github.com/rust-windowing/glutin.git", rev="63a1ea7d6e6 old_school_gfx_glutin_ext = "0.24" winit = {version = "0.22.2", features = ["serde"]} +# Ui +conrod_core = {git = "https://gitlab.com/veloren/conrod.git", branch="copypasta_0.7"} +conrod_winit = {git = "https://gitlab.com/veloren/conrod.git", branch="copypasta_0.7"} +euc = {git = "https://github.com/zesterer/euc.git"} +iced = {package = "iced_native", git = "https://github.com/hecrj/iced"} +window_clipboard = "0.1.1" + # ECS specs = {git = "https://github.com/amethyst/specs.git", rev = "7a2e348ab2223818bad487695c66c43db88050a5"} specs-idvs = {git = "https://gitlab.com/veloren/specs-idvs.git", branch = "specs-git"} diff --git a/voxygen/src/hud/settings_window.rs b/voxygen/src/hud/settings_window.rs index 59f5a6f14b..daa5148219 100644 --- a/voxygen/src/hud/settings_window.rs +++ b/voxygen/src/hud/settings_window.rs @@ -2317,7 +2317,6 @@ impl<'a> Widget for SettingsWindow<'a> { .global_state .window .window() - .window() .current_monitor() .unwrap() .video_modes() diff --git a/voxygen/src/menu/main/ui.rs b/voxygen/src/menu/main/ui.rs index bcb5a4a74b..72acdb123f 100644 --- a/voxygen/src/menu/main/ui.rs +++ b/voxygen/src/menu/main/ui.rs @@ -4,11 +4,13 @@ use crate::{ ui::{ self, fonts::ConrodVoxygenFonts, + ice::IcedUi, img_ids::{BlankGraphic, ImageGraphic, VoxelGraphic}, - Graphic, ImageFrame, Tooltip, Ui, + Graphic, Ui, }, GlobalState, }; +//ImageFrame, Tooltip, use common::assets::Asset; use conrod_core::{ color, @@ -17,6 +19,7 @@ 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; use image::DynamicImage; use rand::{seq::SliceRandom, thread_rng, Rng}; use std::time::Duration; @@ -122,6 +125,32 @@ image_ids! { } } +image_ids_ice! { + struct IcedImgs { + + v_logo: "voxygen.element.v_logo", + + info_frame: "voxygen.element.frames.info_frame_2", + banner: "voxygen.element.frames.banner", + + banner_bottom: "voxygen.element.frames.banner_bottom", + + + bg: "voxygen.background.bg_main", + banner_top: "voxygen.element.frames.banner_top", + button: "voxygen.element.buttons.button", + button_hover: "voxygen.element.buttons.button_hover", + button_press: "voxygen.element.buttons.button_press", + input_bg_top: "voxygen.element.misc_bg.textbox_top", + input_bg_mid: "voxygen.element.misc_bg.textbox_mid", + input_bg_bot: "voxygen.element.misc_bg.textbox_bot", + disclaimer: "voxygen.element.frames.disclaimer", + + + nothing: (), + } +} + rotation_image_ids! { pub struct ImgsRot { @@ -158,8 +187,31 @@ pub struct PopupData { popup_type: PopupType, } +// No state currently +struct IcedState { + imgs: IcedImgs, +} +pub type Message = Event; +impl IcedState { + pub fn view(&mut self) -> iced::Column { + Column::new().push(ui::ice::Image::new( + (self.imgs.bg, ui::Rotation::None), + 500.0, + 500.0, + )) + } + + pub fn update(message: Message) { + match message { + _ => unimplemented!(), + } + } +} + pub struct MainMenuUi { ui: Ui, + ice_ui: IcedUi, + ice_state: IcedState, ids: Ids, imgs: Imgs, rot_imgs: ImgsRot, @@ -225,8 +277,15 @@ impl<'a> MainMenuUi { let fonts = ConrodVoxygenFonts::load(&voxygen_i18n.fonts, &mut ui) .expect("Impossible to load fonts!"); + let mut ice_ui = IcedUi::new(window).unwrap(); + let ice_state = IcedState { + imgs: IcedImgs::load(&mut ice_ui).expect("Failed to load images"), + }; + Self { ui, + ice_ui, + ice_state, ids, imgs, rot_imgs, @@ -276,7 +335,7 @@ impl<'a> MainMenuUi { let intro_text = &self.voxygen_i18n.get("main.login_process"); // Tooltip - let _tooltip = Tooltip::new({ + /*let _tooltip = Tooltip::new({ // Edge images [t, b, r, l] // Corner images [tr, tl, br, bl] let edge = &self.rot_imgs.tt_side; @@ -291,7 +350,7 @@ impl<'a> MainMenuUi { .title_font_size(self.fonts.cyri.scale(15)) .desc_font_size(self.fonts.cyri.scale(10)) .font_id(self.fonts.cyri.conrod_id) - .desc_text_color(TEXT_COLOR_2); + .desc_text_color(TEXT_COLOR_2);*/ // Background image, Veloren logo, Alpha-Version Label Image::new(if self.connect { @@ -897,11 +956,18 @@ impl<'a> MainMenuUi { pub fn handle_event(&mut self, event: ui::Event) { self.ui.handle_event(event); } + pub fn handle_iced_event(&mut self, event: ui::ice::Event) { self.ice_ui.handle_event(event); } + pub fn maintain(&mut self, global_state: &mut GlobalState, dt: Duration) -> Vec { let events = self.update_layout(global_state, dt); self.ui.maintain(global_state.window.renderer_mut(), None); + self.ice_ui + .maintain(self.ice_state.view(), global_state.window.renderer_mut()); events } - pub fn render(&self, renderer: &mut Renderer) { self.ui.render(renderer, None); } + pub fn render(&self, renderer: &mut Renderer) { + self.ui.render(renderer, None); + self.ice_ui.render(renderer); + } } diff --git a/voxygen/src/run.rs b/voxygen/src/run.rs index a8eac50d09..8253440906 100644 --- a/voxygen/src/run.rs +++ b/voxygen/src/run.rs @@ -34,6 +34,13 @@ pub fn run(mut global_state: GlobalState, event_loop: EventLoop) { if let Some(event) = ui::Event::try_from(&event, global_state.window.window()) { global_state.window.send_event(Event::Ui(event)); } + // iced ui events + // TODO: no clone + if let winit::Event::WindowEvent { event, .. } = event.clone() { + if let Some(event) = ui::ice::window_event(event) { + global_state.window.send_event(Event::IcedUi(event)); + } + } match event { winit::event::Event::NewEvents(_) => { diff --git a/voxygen/src/ui/ice/clipboard.rs b/voxygen/src/ui/ice/clipboard.rs new file mode 100644 index 0000000000..feb78983ab --- /dev/null +++ b/voxygen/src/ui/ice/clipboard.rs @@ -0,0 +1,12 @@ +// Taken from https://github.com/hecrj/iced/blob/e1438774af809c2951c4c7446638500446c81111/winit/src/clipboard.rs +pub struct Clipboard(window_clipboard::Clipboard); + +impl Clipboard { + pub fn new(window: &winit::Window) -> Option { + window_clipboard::Clipboard::new(window).map(Clipboard).ok() + } +} + +impl iced::Clipboard for Clipboard { + fn content(&self) -> Option { self.0.read().ok() } +} diff --git a/voxygen/src/ui/ice/mod.rs b/voxygen/src/ui/ice/mod.rs new file mode 100644 index 0000000000..3b7c2b5902 --- /dev/null +++ b/voxygen/src/ui/ice/mod.rs @@ -0,0 +1,72 @@ +// tooltip_manager: TooltipManager, +mod clipboard; +mod renderer; +mod widget; +mod winit_conversion; + +pub use graphic::{Id, Rotation}; +pub use iced::Event; +pub use renderer::IcedRenderer; +pub use widget::image::Image; +pub use winit_conversion::window_event; + +use super::graphic::{self, Graphic}; +use crate::{render::Renderer, window::Window, Error}; +use clipboard::Clipboard; +use iced::{Cache, Element, MouseCursor, Size, UserInterface}; + +pub struct IcedUi { + renderer: IcedRenderer, + cache: Option, + events: Vec, + clipboard: Clipboard, +} +impl IcedUi { + pub fn new(window: &mut Window) -> Result { + Ok(Self { + renderer: IcedRenderer::new(window)?, + cache: Some(Cache::new()), + events: Vec::new(), + // TODO: handle None + clipboard: Clipboard::new(window.window()).unwrap(), + }) + } + + // Add an new graphic that is referencable via the returned Id + pub fn add_graphic(&mut self, graphic: Graphic) -> graphic::Id { + self.renderer.add_graphic(graphic) + } + + // TODO: handle scaling here + pub fn handle_event(&mut self, event: Event) { self.events.push(event); } + + // TODO: produce root internally??? + pub fn maintain<'a, M, E: Into>>( + &mut self, + root: E, + renderer: &mut Renderer, + ) -> (Vec, MouseCursor) { + // TODO: convert to f32 at source + let window_size = self.renderer.scaled_window_size().map(|e| e as f32); + + let mut user_interface = UserInterface::build( + root, + Size::new(window_size.x, window_size.y), + self.cache.take().unwrap(), + &mut self.renderer, + ); + + let messages = + user_interface.update(self.events.drain(..), Some(&self.clipboard), &self.renderer); + + let (primitive, mouse_cursor) = user_interface.draw(&mut self.renderer); + + self.renderer.draw(primitive, renderer); + + self.cache = Some(user_interface.into_cache()); + + (messages, mouse_cursor) + } + + pub fn render(&self, renderer: &mut Renderer) { self.renderer.render(renderer, None); } +} diff --git a/voxygen/src/ui/ice/renderer.rs b/voxygen/src/ui/ice/renderer.rs new file mode 100644 index 0000000000..0f3a1b1403 --- /dev/null +++ b/voxygen/src/ui/ice/renderer.rs @@ -0,0 +1,400 @@ +mod column; +mod image; + +use super::{ + super::{ + cache::Cache, + graphic::{self, Graphic, TexId}, + scale::{Scale, ScaleMode}, + }, + widget, +}; +use crate::{ + render::{ + create_ui_quad, Consts, DynamicModel, Globals, Mesh, Renderer, UiLocals, UiMode, UiPipeline, + }, + window::Window, + Error, +}; +//use log::warn; +use std::ops::Range; +use vek::*; + +enum DrawKind { + Image(TexId), + // Text and non-textured geometry + Plain, +} +enum DrawCommand { + Draw { kind: DrawKind, verts: Range }, + Scissor(Aabr), + WorldPos(Option), +} +impl DrawCommand { + fn image(verts: Range, id: TexId) -> DrawCommand { + DrawCommand::Draw { + kind: DrawKind::Image(id), + verts, + } + } + + fn plain(verts: Range) -> DrawCommand { + DrawCommand::Draw { + kind: DrawKind::Plain, + verts, + } + } +} + +enum State { + Image(TexId), + Plain, +} + +pub enum Primitive { + // Allocation :( + Group { + primitives: Vec, + }, + Image { + handle: widget::image::Handle, + bounds: iced::Rectangle, + }, +} + +pub struct IcedRenderer { + //image_map: Map<(Image, Rotation)>, + cache: Cache, + // Model for drawing the ui + model: DynamicModel, + // Consts to specify positions of ingame elements (e.g. Nametags) + ingame_locals: Vec>, + // Consts for default ui drawing position (ie the interface) + interface_locals: Consts, + default_globals: Consts, + + // Window size for updating scaling + //window_resized: Option>, + // Used to delay cache resizing until after current frame is drawn + //need_cache_resize: bool, + // Scaling of the ui + scale: Scale, + + half_res: Vec2, + // Pixel perfection alignment + align: Vec2, + // Pretend dims :) (i.e. scaled) + win_dims: Vec2, + + // Per-frame/update + current_state: State, + mesh: Mesh, + start: usize, + // Draw commands for the next render + draw_commands: Vec, + //current_scissor: Aabr, +} +impl IcedRenderer { + pub fn new(window: &mut Window) -> Result { + let scale = Scale::new(window, ScaleMode::Absolute(1.0)); + // TODO: looks like we can just get this from scale + let win_dims = scale.scaled_window_size().map(|e| e as f32); + + let renderer = window.renderer_mut(); + let res = renderer.get_resolution(); + + let half_res = res.map(|e| e as f32 / 2.0); + let align = align(res); + + Ok(Self { + cache: Cache::new(renderer)?, + draw_commands: Vec::new(), + model: renderer.create_dynamic_model(100)?, + interface_locals: renderer.create_consts(&[UiLocals::default()])?, + default_globals: renderer.create_consts(&[Globals::default()])?, + ingame_locals: Vec::new(), + //window_resized: None, + //need_cache_resize: false, + mesh: Mesh::new(), + current_state: State::Plain, + scale, + half_res, + align, + win_dims, + start: 0, + //current_scissor: default_scissor(renderer), + }) + } + + pub fn scaled_window_size(&self) -> Vec2 { self.scale.scaled_window_size() } + + pub fn add_graphic(&mut self, graphic: Graphic) -> graphic::Id { + self.cache.add_graphic(graphic) + } + + pub fn draw(&mut self, primitive: Primitive, renderer: &mut Renderer) { + /*if self.need_cache_resize { + // Resize graphic cache + self.cache.resize_graphic_cache(renderer).unwrap(); + // Resize glyph cache + self.cache.resize_glyph_cache(renderer).unwrap(); + + self.need_cache_resize = false; + }*/ + + // Re-use memory + self.draw_commands.clear(); + self.mesh.clear(); + + self.current_state = State::Plain; + self.start = 0; + + //self.current_scissor = default_scissor(renderer); + + self.draw_primitive(primitive, renderer); + + // Enter the final command. + self.draw_commands.push(match self.current_state { + State::Plain => DrawCommand::plain(self.start..self.mesh.vertices().len()), + State::Image(id) => DrawCommand::image(self.start..self.mesh.vertices().len(), id), + }); + + // Draw glyph cache (use for debugging). + /*self.draw_commands + .push(DrawCommand::Scissor(default_scissor(renderer))); + start = mesh.vertices().len(); + mesh.push_quad(create_ui_quad( + Aabr { + min: (-1.0, -1.0).into(), + max: (1.0, 1.0).into(), + }, + Aabr { + min: (0.0, 1.0).into(), + max: (1.0, 0.0).into(), + }, + Rgba::new(1.0, 1.0, 1.0, 0.8), + UiMode::Text, + )); + self.draw_commands + .push(DrawCommand::plain(start..mesh.vertices().len()));*/ + + // Create a larger dynamic model if the mesh is larger than the current model + // size. + if self.model.vbuf.len() < self.mesh.vertices().len() { + self.model = renderer + .create_dynamic_model(self.mesh.vertices().len() * 4 / 3) + .unwrap(); + } + // Update model with new mesh. + renderer.update_model(&self.model, &self.mesh, 0).unwrap(); + + // Handle window resizing. + /*if let Some(new_dims) = self.window_resized.take() { + let (old_w, old_h) = self.scale.scaled_window_size().into_tuple(); + self.scale.window_resized(new_dims, renderer); + let (w, h) = self.scale.scaled_window_size().into_tuple(); + self.ui.handle_event(Input::Resize(w, h)); + + // Avoid panic in graphic cache when minimizing. + // Avoid resetting cache if window size didn't change + // Somewhat inefficient for elements that won't change size after a window resize + let res = renderer.get_resolution(); + self.need_cache_resize = res.x > 0 && res.y > 0 && !(old_w == w && old_h == h); + }*/ + } + + fn gl_aabr(&self, bounds: iced::Rectangle) -> Aabr { + /*let (ui_win_w, ui_win_h) = self.win_dims.into_tuple(); + let (l, b) = aabr.min.into_tuple(); + let (r, t) = aabr.max.into_tuple(); + let vx = |x: f64| (x / ui_win_w * 2.0) as f32; + let vy = |y: f64| (y / ui_win_h * 2.0) as f32; + let min = Vec2::new( + ((vx(l) * half_res.x + x_align).round() - x_align) / half_res.x, + ((vy(b) * half_res.y + y_align).round() - y_align) / half_res.y, + ); + let max = Vec2::new( + ((vx(r) * half_res.x + x_align).round() - x_align) / half_res.x, + ((vy(t) * half_res.y + y_align).round() - y_align) / half_res.y, + );*/ + let flipped_y = self.win_dims.y - bounds.y; + let half_win_dims = self.win_dims.map(|e| e / 2.0); + let half_res = self.half_res; + let min = (((Vec2::new(bounds.x, flipped_y - bounds.height) - half_win_dims) + / half_win_dims + * half_res + + self.align) + .map(|e| e.round()) + - self.align) + / half_res; + let max = (((Vec2::new(bounds.x + bounds.width, flipped_y) - half_win_dims) + / half_win_dims + * half_res + + self.align) + .map(|e| e.round()) + - self.align) + / half_res; + Aabr { min, max } + } + + fn draw_primitive(&mut self, primitive: Primitive, renderer: &mut Renderer) { + match primitive { + Primitive::Group { primitives } => { + primitives + .into_iter() + .for_each(|p| self.draw_primitive(p, renderer)); + }, + Primitive::Image { handle, bounds } => { + let (graphic_id, rotation) = handle; + let gl_aabr = self.gl_aabr(bounds); + + let graphic_cache = self.cache.graphic_cache_mut(); + + match graphic_cache.get_graphic(graphic_id) { + Some(Graphic::Blank) | None => return, + _ => {}, + } + + // 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, 1.0, 1.0, 1.0]); + + let resolution = Vec2::new( + (gl_aabr.size().w * self.half_res.x).round() as u16, + (gl_aabr.size().h * self.half_res.y).round() as u16, + ); + // Transform the source rectangle into uv coordinate. + // TODO: Make sure this is right. + let source_aabr = { + let (uv_l, uv_r, uv_b, uv_t) = (0.0, 1.0, 0.0, 1.0); + /*match source_rect { + Some(src_rect) => { + let (l, r, b, t) = src_rect.l_r_b_t(); + ((l / image_w) as f32, + (r / image_w) as f32, + (b / image_h) as f32, + (t / image_h) as f32) + } + None => (0.0, 1.0, 0.0, 1.0), + };*/ + Aabr { + min: Vec2::new(uv_l, uv_b), + max: Vec2::new(uv_r, uv_t), + } + }; + + // Cache graphic at particular resolution. + let (uv_aabr, tex_id) = match graphic_cache.cache_res( + renderer, + graphic_id, + resolution, + source_aabr, + rotation, + ) { + // TODO: get dims from graphic_cache (or have it return floats directly) + Some((aabr, tex_id)) => { + let cache_dims = graphic_cache + .get_tex(tex_id) + .get_dimensions() + .map(|e| e as f32); + let min = Vec2::new(aabr.min.x as f32, aabr.max.y as f32) / cache_dims; + let max = Vec2::new(aabr.max.x as f32, aabr.min.y as f32) / cache_dims; + (Aabr { min, max }, tex_id) + }, + None => return, + }; + + match self.current_state { + // Switch to the image state if we are not in it already. + State::Plain => { + self.draw_commands + .push(DrawCommand::plain(self.start..self.mesh.vertices().len())); + self.start = self.mesh.vertices().len(); + self.current_state = State::Image(tex_id); + }, + // If the image is cached in a different texture switch to the new one + State::Image(id) => { + if id != tex_id { + self.draw_commands.push(DrawCommand::image( + self.start..self.mesh.vertices().len(), + id, + )); + self.start = self.mesh.vertices().len(); + self.current_state = State::Image(tex_id); + } + }, + } + + self.mesh + .push_quad(create_ui_quad(gl_aabr, uv_aabr, color, UiMode::Image)); + }, + } + } + + pub fn render(&self, renderer: &mut Renderer, maybe_globals: Option<&Consts>) { + let mut scissor = default_scissor(renderer); + let globals = maybe_globals.unwrap_or(&self.default_globals); + let mut locals = &self.interface_locals; + for draw_command in self.draw_commands.iter() { + match draw_command { + DrawCommand::Scissor(new_scissor) => { + scissor = *new_scissor; + }, + DrawCommand::WorldPos(index) => { + locals = index.map_or(&self.interface_locals, |i| &self.ingame_locals[i]); + }, + DrawCommand::Draw { kind, verts } => { + let tex = match kind { + DrawKind::Image(tex_id) => self.cache.graphic_cache().get_tex(*tex_id), + DrawKind::Plain => self.cache.glyph_cache_tex(), + }; + let model = self.model.submodel(verts.clone()); + renderer.render_ui_element(&model, tex, scissor, globals, locals); + }, + } + } + } +} + +// Given the the resolution determines the offset needed to align integer +// offsets from the center of the sceen to pixels +fn align(res: Vec2) -> Vec2 { + // 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 + res.map(|e| (e & 1) as f32 * 0.5) +} + +fn default_scissor(renderer: &Renderer) -> Aabr { + let (screen_w, screen_h) = renderer.get_resolution().map(|e| e as u16).into_tuple(); + Aabr { + min: Vec2 { x: 0, y: 0 }, + max: Vec2 { + x: screen_w, + y: screen_h, + }, + } +} + +impl iced::Renderer for IcedRenderer { + // Default styling + type Defaults = (); + // TODO: use graph of primitives to enable diffing??? + type Output = (Primitive, iced::MouseCursor); + + fn layout<'a, M>( + &mut self, + element: &iced::Element<'a, M, Self>, + limits: &iced::layout::Limits, + ) -> iced::layout::Node { + let node = element.layout(self, limits); + + // Trim text measurements cache? + + node + } +} + +// TODO: impl Debugger diff --git a/voxygen/src/ui/ice/renderer/column.rs b/voxygen/src/ui/ice/renderer/column.rs new file mode 100644 index 0000000000..80a9f7ace3 --- /dev/null +++ b/voxygen/src/ui/ice/renderer/column.rs @@ -0,0 +1,34 @@ +use super::{IcedRenderer, Primitive}; +use iced::{column, Element, Layout, MouseCursor, Point}; + +impl column::Renderer for IcedRenderer { + fn draw( + &mut self, + defaults: &Self::Defaults, + content: &[Element<'_, M, Self>], + layout: Layout<'_>, + cursor_position: Point, + ) -> Self::Output { + let mut mouse_cursor = MouseCursor::OutOfBounds; + + ( + Primitive::Group { + primitives: content + .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, + ) + } +} diff --git a/voxygen/src/ui/ice/renderer/image.rs b/voxygen/src/ui/ice/renderer/image.rs new file mode 100644 index 0000000000..7f25595774 --- /dev/null +++ b/voxygen/src/ui/ice/renderer/image.rs @@ -0,0 +1,14 @@ +use super::{super::widget::image, IcedRenderer, Primitive}; +use iced::MouseCursor; + +impl image::Renderer for IcedRenderer { + fn draw(&mut self, handle: image::Handle, layout: iced::Layout<'_>) -> Self::Output { + ( + Primitive::Image { + handle, + bounds: layout.bounds(), + }, + MouseCursor::OutOfBounds, + ) + } +} diff --git a/voxygen/src/ui/ice/widget.rs b/voxygen/src/ui/ice/widget.rs new file mode 100644 index 0000000000..14995d4228 --- /dev/null +++ b/voxygen/src/ui/ice/widget.rs @@ -0,0 +1 @@ +pub mod image; diff --git a/voxygen/src/ui/ice/widget/image.rs b/voxygen/src/ui/ice/widget/image.rs new file mode 100644 index 0000000000..bae4a1ea18 --- /dev/null +++ b/voxygen/src/ui/ice/widget/image.rs @@ -0,0 +1,63 @@ +use super::super::super::graphic::{self, Rotation}; +use iced::{layout, Element, Hasher, Layout, Length, Point, Size, Widget}; +use std::hash::Hash; + +// 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 struct Image { + handle: Handle, + size: Size, +} + +impl Image { + pub fn new(handle: Handle, w: f32, h: f32) -> Self { + let size = Size::new(w, h); + Self { handle, size } + } +} + +impl Widget for Image +where + R: self::Renderer, +{ + fn width(&self) -> Length { Length::Fill } + + fn height(&self) -> Length { Length::Fill } + + fn layout(&self, _renderer: &R, _limits: &layout::Limits) -> layout::Node { + // We don't care about aspect ratios here :p + layout::Node::new(self.size) + // Infinite sizes confusing + //layout::Node::new(limits.resolve(self.size)) + } + + fn draw( + &self, + renderer: &mut R, + _defaults: &R::Defaults, + layout: Layout<'_>, + _cursor_position: Point, + ) -> R::Output { + renderer.draw(self.handle, layout) + } + + fn hash_layout(&self, state: &mut Hasher) { + self.size.width.to_bits().hash(state); + self.size.height.to_bits().hash(state); + } +} + +pub trait Renderer: iced::Renderer { + fn draw(&mut self, handle: Handle, layout: Layout<'_>) -> Self::Output; +} + +impl<'a, M, R> From for Element<'a, M, R> +where + R: self::Renderer, +{ + fn from(image: Image) -> Element<'a, M, R> { Element::new(image) } +} diff --git a/voxygen/src/ui/ice/winit_conversion.rs b/voxygen/src/ui/ice/winit_conversion.rs new file mode 100644 index 0000000000..79538094ff --- /dev/null +++ b/voxygen/src/ui/ice/winit_conversion.rs @@ -0,0 +1,271 @@ +// Using reference impl: https://github.com/hecrj/iced/blob/e1438774af809c2951c4c7446638500446c81111/winit/src/conversion.rs +use iced::{ + input::{ + keyboard::{self, KeyCode, ModifiersState}, + mouse, ButtonState, + }, + window, Event, +}; + +/// Converts a winit event into an iced event. +pub fn window_event(event: winit::WindowEvent) -> Option { + use winit::WindowEvent; + + match event { + WindowEvent::Resized(new_size) => { + let logical_size: winit::dpi::LogicalSize = new_size; + + Some(Event::Window(window::Event::Resized { + width: logical_size.width as u32, + height: logical_size.height as u32, + })) + }, + WindowEvent::CursorMoved { position, .. } => { + let position: winit::dpi::LogicalPosition = position; + + Some(Event::Mouse(mouse::Event::CursorMoved { + x: position.x as f32, + y: position.y as f32, + })) + }, + WindowEvent::MouseInput { button, state, .. } => Some(Event::Mouse(mouse::Event::Input { + button: mouse_button(button), + state: button_state(state), + })), + WindowEvent::MouseWheel { delta, .. } => match delta { + winit::MouseScrollDelta::LineDelta(delta_x, delta_y) => { + Some(Event::Mouse(mouse::Event::WheelScrolled { + delta: mouse::ScrollDelta::Lines { + x: delta_x, + y: delta_y, + }, + })) + }, + winit::MouseScrollDelta::PixelDelta(position) => { + let position: winit::dpi::LogicalPosition = position; + Some(Event::Mouse(mouse::Event::WheelScrolled { + delta: mouse::ScrollDelta::Pixels { + x: position.x as f32, + y: position.y as f32, + }, + })) + }, + }, + WindowEvent::ReceivedCharacter(c) => { + Some(Event::Keyboard(keyboard::Event::CharacterReceived(c))) + }, + WindowEvent::KeyboardInput { + input: + winit::KeyboardInput { + virtual_keycode: Some(virtual_keycode), + state, + modifiers, + .. + }, + .. + } => Some(Event::Keyboard(keyboard::Event::Input { + key_code: key_code(virtual_keycode), + state: button_state(state), + modifiers: modifiers_state(modifiers), + })), + // iced also can use file hovering events but we don't need them right now + _ => None, + } +} + +// iced has a function for converting mouse cursors here + +/// Converts winit mouse button to iced mouse button +fn mouse_button(mouse_button: winit::MouseButton) -> mouse::Button { + match mouse_button { + winit::MouseButton::Left => mouse::Button::Left, + winit::MouseButton::Right => mouse::Button::Right, + winit::MouseButton::Middle => mouse::Button::Middle, + winit::MouseButton::Other(other) => mouse::Button::Other(other), + } +} + +/// Converts winit `ElementState` to an iced button state +fn button_state(element_state: winit::ElementState) -> ButtonState { + match element_state { + winit::ElementState::Pressed => ButtonState::Pressed, + winit::ElementState::Released => ButtonState::Released, + } +} + +/// Converts winit `ModifiersState` to iced `ModifiersState` +fn modifiers_state(modifiers: winit::ModifiersState) -> ModifiersState { + ModifiersState { + shift: modifiers.shift, + control: modifiers.ctrl, + alt: modifiers.alt, + logo: modifiers.logo, + } +} + +/// Converts winit `VirtualKeyCode` to iced `KeyCode` +fn key_code(virtual_keycode: winit::VirtualKeyCode) -> KeyCode { + match virtual_keycode { + winit::VirtualKeyCode::Key1 => KeyCode::Key1, + winit::VirtualKeyCode::Key2 => KeyCode::Key2, + winit::VirtualKeyCode::Key3 => KeyCode::Key3, + winit::VirtualKeyCode::Key4 => KeyCode::Key4, + winit::VirtualKeyCode::Key5 => KeyCode::Key5, + winit::VirtualKeyCode::Key6 => KeyCode::Key6, + winit::VirtualKeyCode::Key7 => KeyCode::Key7, + winit::VirtualKeyCode::Key8 => KeyCode::Key8, + winit::VirtualKeyCode::Key9 => KeyCode::Key9, + winit::VirtualKeyCode::Key0 => KeyCode::Key0, + winit::VirtualKeyCode::A => KeyCode::A, + winit::VirtualKeyCode::B => KeyCode::B, + winit::VirtualKeyCode::C => KeyCode::C, + winit::VirtualKeyCode::D => KeyCode::D, + winit::VirtualKeyCode::E => KeyCode::E, + winit::VirtualKeyCode::F => KeyCode::F, + winit::VirtualKeyCode::G => KeyCode::G, + winit::VirtualKeyCode::H => KeyCode::H, + winit::VirtualKeyCode::I => KeyCode::I, + winit::VirtualKeyCode::J => KeyCode::J, + winit::VirtualKeyCode::K => KeyCode::K, + winit::VirtualKeyCode::L => KeyCode::L, + winit::VirtualKeyCode::M => KeyCode::M, + winit::VirtualKeyCode::N => KeyCode::N, + winit::VirtualKeyCode::O => KeyCode::O, + winit::VirtualKeyCode::P => KeyCode::P, + winit::VirtualKeyCode::Q => KeyCode::Q, + winit::VirtualKeyCode::R => KeyCode::R, + winit::VirtualKeyCode::S => KeyCode::S, + winit::VirtualKeyCode::T => KeyCode::T, + winit::VirtualKeyCode::U => KeyCode::U, + winit::VirtualKeyCode::V => KeyCode::V, + winit::VirtualKeyCode::W => KeyCode::W, + winit::VirtualKeyCode::X => KeyCode::X, + winit::VirtualKeyCode::Y => KeyCode::Y, + winit::VirtualKeyCode::Z => KeyCode::Z, + winit::VirtualKeyCode::Escape => KeyCode::Escape, + winit::VirtualKeyCode::F1 => KeyCode::F1, + winit::VirtualKeyCode::F2 => KeyCode::F2, + winit::VirtualKeyCode::F3 => KeyCode::F3, + winit::VirtualKeyCode::F4 => KeyCode::F4, + winit::VirtualKeyCode::F5 => KeyCode::F5, + winit::VirtualKeyCode::F6 => KeyCode::F6, + winit::VirtualKeyCode::F7 => KeyCode::F7, + winit::VirtualKeyCode::F8 => KeyCode::F8, + winit::VirtualKeyCode::F9 => KeyCode::F9, + winit::VirtualKeyCode::F10 => KeyCode::F10, + winit::VirtualKeyCode::F11 => KeyCode::F11, + winit::VirtualKeyCode::F12 => KeyCode::F12, + winit::VirtualKeyCode::F13 => KeyCode::F13, + winit::VirtualKeyCode::F14 => KeyCode::F14, + winit::VirtualKeyCode::F15 => KeyCode::F15, + winit::VirtualKeyCode::F16 => KeyCode::F16, + winit::VirtualKeyCode::F17 => KeyCode::F17, + winit::VirtualKeyCode::F18 => KeyCode::F18, + winit::VirtualKeyCode::F19 => KeyCode::F19, + winit::VirtualKeyCode::F20 => KeyCode::F20, + winit::VirtualKeyCode::F21 => KeyCode::F21, + winit::VirtualKeyCode::F22 => KeyCode::F22, + winit::VirtualKeyCode::F23 => KeyCode::F23, + winit::VirtualKeyCode::F24 => KeyCode::F24, + winit::VirtualKeyCode::Snapshot => KeyCode::Snapshot, + winit::VirtualKeyCode::Scroll => KeyCode::Scroll, + winit::VirtualKeyCode::Pause => KeyCode::Pause, + winit::VirtualKeyCode::Insert => KeyCode::Insert, + winit::VirtualKeyCode::Home => KeyCode::Home, + winit::VirtualKeyCode::Delete => KeyCode::Delete, + winit::VirtualKeyCode::End => KeyCode::End, + winit::VirtualKeyCode::PageDown => KeyCode::PageDown, + winit::VirtualKeyCode::PageUp => KeyCode::PageUp, + winit::VirtualKeyCode::Left => KeyCode::Left, + winit::VirtualKeyCode::Up => KeyCode::Up, + winit::VirtualKeyCode::Right => KeyCode::Right, + winit::VirtualKeyCode::Down => KeyCode::Down, + winit::VirtualKeyCode::Back => KeyCode::Backspace, + winit::VirtualKeyCode::Return => KeyCode::Enter, + winit::VirtualKeyCode::Space => KeyCode::Space, + winit::VirtualKeyCode::Compose => KeyCode::Compose, + winit::VirtualKeyCode::Caret => KeyCode::Caret, + winit::VirtualKeyCode::Numlock => KeyCode::Numlock, + winit::VirtualKeyCode::Numpad0 => KeyCode::Numpad0, + winit::VirtualKeyCode::Numpad1 => KeyCode::Numpad1, + winit::VirtualKeyCode::Numpad2 => KeyCode::Numpad2, + winit::VirtualKeyCode::Numpad3 => KeyCode::Numpad3, + winit::VirtualKeyCode::Numpad4 => KeyCode::Numpad4, + winit::VirtualKeyCode::Numpad5 => KeyCode::Numpad5, + winit::VirtualKeyCode::Numpad6 => KeyCode::Numpad6, + winit::VirtualKeyCode::Numpad7 => KeyCode::Numpad7, + winit::VirtualKeyCode::Numpad8 => KeyCode::Numpad8, + winit::VirtualKeyCode::Numpad9 => KeyCode::Numpad9, + winit::VirtualKeyCode::AbntC1 => KeyCode::AbntC1, + winit::VirtualKeyCode::AbntC2 => KeyCode::AbntC2, + winit::VirtualKeyCode::Add => KeyCode::Add, + winit::VirtualKeyCode::Apostrophe => KeyCode::Apostrophe, + winit::VirtualKeyCode::Apps => KeyCode::Apps, + winit::VirtualKeyCode::At => KeyCode::At, + winit::VirtualKeyCode::Ax => KeyCode::Ax, + winit::VirtualKeyCode::Backslash => KeyCode::Backslash, + winit::VirtualKeyCode::Calculator => KeyCode::Calculator, + winit::VirtualKeyCode::Capital => KeyCode::Capital, + winit::VirtualKeyCode::Colon => KeyCode::Colon, + winit::VirtualKeyCode::Comma => KeyCode::Comma, + winit::VirtualKeyCode::Convert => KeyCode::Convert, + winit::VirtualKeyCode::Decimal => KeyCode::Decimal, + winit::VirtualKeyCode::Divide => KeyCode::Divide, + winit::VirtualKeyCode::Equals => KeyCode::Equals, + winit::VirtualKeyCode::Grave => KeyCode::Grave, + winit::VirtualKeyCode::Kana => KeyCode::Kana, + winit::VirtualKeyCode::Kanji => KeyCode::Kanji, + winit::VirtualKeyCode::LAlt => KeyCode::LAlt, + winit::VirtualKeyCode::LBracket => KeyCode::LBracket, + winit::VirtualKeyCode::LControl => KeyCode::LControl, + winit::VirtualKeyCode::LShift => KeyCode::LShift, + winit::VirtualKeyCode::LWin => KeyCode::LWin, + winit::VirtualKeyCode::Mail => KeyCode::Mail, + winit::VirtualKeyCode::MediaSelect => KeyCode::MediaSelect, + winit::VirtualKeyCode::MediaStop => KeyCode::MediaStop, + winit::VirtualKeyCode::Minus => KeyCode::Minus, + winit::VirtualKeyCode::Multiply => KeyCode::Multiply, + winit::VirtualKeyCode::Mute => KeyCode::Mute, + winit::VirtualKeyCode::MyComputer => KeyCode::MyComputer, + winit::VirtualKeyCode::NavigateForward => KeyCode::NavigateForward, + winit::VirtualKeyCode::NavigateBackward => KeyCode::NavigateBackward, + winit::VirtualKeyCode::NextTrack => KeyCode::NextTrack, + winit::VirtualKeyCode::NoConvert => KeyCode::NoConvert, + winit::VirtualKeyCode::NumpadComma => KeyCode::NumpadComma, + winit::VirtualKeyCode::NumpadEnter => KeyCode::NumpadEnter, + winit::VirtualKeyCode::NumpadEquals => KeyCode::NumpadEquals, + winit::VirtualKeyCode::OEM102 => KeyCode::OEM102, + winit::VirtualKeyCode::Period => KeyCode::Period, + winit::VirtualKeyCode::PlayPause => KeyCode::PlayPause, + winit::VirtualKeyCode::Power => KeyCode::Power, + winit::VirtualKeyCode::PrevTrack => KeyCode::PrevTrack, + winit::VirtualKeyCode::RAlt => KeyCode::RAlt, + winit::VirtualKeyCode::RBracket => KeyCode::RBracket, + winit::VirtualKeyCode::RControl => KeyCode::RControl, + winit::VirtualKeyCode::RShift => KeyCode::RShift, + winit::VirtualKeyCode::RWin => KeyCode::RWin, + winit::VirtualKeyCode::Semicolon => KeyCode::Semicolon, + winit::VirtualKeyCode::Slash => KeyCode::Slash, + winit::VirtualKeyCode::Sleep => KeyCode::Sleep, + winit::VirtualKeyCode::Stop => KeyCode::Stop, + winit::VirtualKeyCode::Subtract => KeyCode::Subtract, + winit::VirtualKeyCode::Sysrq => KeyCode::Sysrq, + winit::VirtualKeyCode::Tab => KeyCode::Tab, + winit::VirtualKeyCode::Underline => KeyCode::Underline, + winit::VirtualKeyCode::Unlabeled => KeyCode::Unlabeled, + winit::VirtualKeyCode::VolumeDown => KeyCode::VolumeDown, + winit::VirtualKeyCode::VolumeUp => KeyCode::VolumeUp, + winit::VirtualKeyCode::Wake => KeyCode::Wake, + winit::VirtualKeyCode::WebBack => KeyCode::WebBack, + winit::VirtualKeyCode::WebFavorites => KeyCode::WebFavorites, + winit::VirtualKeyCode::WebForward => KeyCode::WebForward, + winit::VirtualKeyCode::WebHome => KeyCode::WebHome, + winit::VirtualKeyCode::WebRefresh => KeyCode::WebRefresh, + winit::VirtualKeyCode::WebSearch => KeyCode::WebSearch, + winit::VirtualKeyCode::WebStop => KeyCode::WebStop, + winit::VirtualKeyCode::Yen => KeyCode::Yen, + winit::VirtualKeyCode::Copy => KeyCode::Copy, + winit::VirtualKeyCode::Paste => KeyCode::Paste, + winit::VirtualKeyCode::Cut => KeyCode::Cut, + } +} diff --git a/voxygen/src/ui/img_ids.rs b/voxygen/src/ui/img_ids.rs index cf828a0502..e6e740eb24 100644 --- a/voxygen/src/ui/img_ids.rs +++ b/voxygen/src/ui/img_ids.rs @@ -165,6 +165,25 @@ macro_rules! image_ids { )* }; } +#[macro_export] +macro_rules! image_ids_ice { + ($($v:vis struct $Ids:ident { $( <$T:ty> $( $name:ident: $specifier:expr ),* $(,)? )* })*) => { + $( + $v struct $Ids { + $($( $v $name: crate::ui::GraphicId, )*)* + } + + impl $Ids { + pub fn load(ui: &mut crate::ui::ice::IcedUi) -> Result { + use crate::ui::img_ids::GraphicCreator; + Ok(Self { + $($( $name: ui.add_graphic(<$T as GraphicCreator>::new_graphic($specifier)?), )*)* + }) + } + } + )* + }; +} // TODO: combine with the img_ids macro above using a marker for specific fields // that should be `Rotations` instead of `widget::Id` diff --git a/voxygen/src/ui/mod.rs b/voxygen/src/ui/mod.rs index 0e5ad64e6b..e5140145f9 100644 --- a/voxygen/src/ui/mod.rs +++ b/voxygen/src/ui/mod.rs @@ -7,9 +7,10 @@ mod widgets; pub mod img_ids; #[macro_use] pub mod fonts; +pub mod ice; pub use event::Event; -pub use graphic::{Graphic, SampleStrat, Transform}; +pub use graphic::{Graphic, Id as GraphicId, Rotation, SampleStrat, Transform}; pub use scale::{Scale, ScaleMode}; pub use widgets::{ image_frame::ImageFrame, @@ -36,7 +37,7 @@ use common::{assets, span, util::srgba_to_linear}; use conrod_core::{ event::Input, graph::{self, Graph}, - image::{self, Map}, + image::{Id as ImageId, Map}, input::{touch::Touch, Motion, Widget}, render::{Primitive, PrimitiveKind}, text::{self, font}, @@ -187,7 +188,7 @@ impl Ui { // Get a copy of Scale pub fn scale(&self) -> Scale { self.scale } - pub fn add_graphic(&mut self, graphic: Graphic) -> image::Id { + pub fn add_graphic(&mut self, graphic: Graphic) -> ImageId { self.image_map .insert((self.cache.add_graphic(graphic), Rotation::None)) } @@ -212,7 +213,7 @@ impl Ui { } } - pub fn replace_graphic(&mut self, id: image::Id, graphic: Graphic) { + pub fn replace_graphic(&mut self, id: ImageId, graphic: Graphic) { let graphic_id = if let Some((graphic_id, _)) = self.image_map.get(&id) { *graphic_id } else { diff --git a/voxygen/src/window.rs b/voxygen/src/window.rs index 79eb08a429..499b40777a 100644 --- a/voxygen/src/window.rs +++ b/voxygen/src/window.rs @@ -282,6 +282,8 @@ pub enum Event { InputUpdate(GameInput, bool), /// Event that the ui uses. Ui(ui::Event), + /// Event that the iced ui uses. + IcedUi(ui::ice::Event), /// The view distance has changed. ViewDistanceChanged(u32), /// Game settings have changed. @@ -622,12 +624,6 @@ impl Window { Ok((this, event_loop)) } - pub fn window( - &self, - ) -> &glutin::ContextWrapper { - &self.window - } - pub fn renderer(&self) -> &Renderer { &self.renderer } pub fn renderer_mut(&mut self) -> &mut Renderer { &mut self.renderer } @@ -1377,6 +1373,8 @@ impl Window { pub fn set_keybinding_mode(&mut self, game_input: GameInput) { self.remapping_keybindings = Some(game_input); } + + pub fn window(&self) -> &winit::Window { self.window.window() } } #[derive(Copy, Clone, Hash, Eq, PartialEq, Debug, Serialize, Deserialize)]