Merge branch 'master' of https://github.com/hecrj/iced into wgpu_outdatedframe

This commit is contained in:
Billy Messenger 2021-07-22 12:37:39 -05:00
commit e822f654e4
219 changed files with 6266 additions and 1761 deletions

View file

@ -1,6 +1,6 @@
[package]
name = "iced_winit"
version = "0.2.0"
version = "0.3.0"
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
edition = "2018"
description = "A winit runtime for Iced"
@ -14,21 +14,25 @@ categories = ["gui"]
debug = ["iced_native/debug"]
[dependencies]
winit = "0.24"
window_clipboard = "0.1"
window_clipboard = "0.2"
log = "0.4"
thiserror = "1.0"
[dependencies.winit]
version = "0.25"
git = "https://github.com/iced-rs/winit"
rev = "844485272a7412cb35cdbfac3524decdf59475ca"
[dependencies.iced_native]
version = "0.3"
version = "0.4"
path = "../native"
[dependencies.iced_graphics]
version = "0.1"
version = "0.2"
path = "../graphics"
[dependencies.iced_futures]
version = "0.2"
version = "0.3"
path = "../futures"
[target.'cfg(target_os = "windows")'.dependencies.winapi]

View file

@ -20,7 +20,7 @@ It exposes a renderer-agnostic `Application` trait that can be implemented and t
Add `iced_winit` as a dependency in your `Cargo.toml`:
```toml
iced_winit = "0.2"
iced_winit = "0.3"
```
__Iced moves fast and the `master` branch can contain breaking changes!__ If

View file

@ -14,6 +14,7 @@ use iced_futures::futures;
use iced_futures::futures::channel::mpsc;
use iced_graphics::window;
use iced_native::program::Program;
use iced_native::Menu;
use iced_native::{Cache, UserInterface};
use std::mem::ManuallyDrop;
@ -29,7 +30,7 @@ use std::mem::ManuallyDrop;
///
/// When using an [`Application`] with the `debug` feature enabled, a debug view
/// can be toggled by pressing `F12`.
pub trait Application: Program {
pub trait Application: Program<Clipboard = Clipboard> {
/// The data needed to initialize your [`Application`].
type Flags;
@ -91,6 +92,20 @@ pub trait Application: Program {
fn scale_factor(&self) -> f64 {
1.0
}
/// Returns whether the [`Application`] should be terminated.
///
/// By default, it returns `false`.
fn should_exit(&self) -> bool {
false
}
/// Returns the current system [`Menu`] of the [`Application`].
///
/// By default, it returns an empty [`Menu`].
fn menu(&self) -> Menu<Self::Message> {
Menu::new()
}
}
/// Runs an [`Application`] with an executor, compositor, and the provided
@ -111,8 +126,6 @@ where
let mut debug = Debug::new();
debug.startup_started();
let (compositor, renderer) = C::new(compositor_settings)?;
let event_loop = EventLoop::with_user_event();
let mut runtime = {
@ -140,19 +153,23 @@ where
application.mode(),
event_loop.primary_monitor(),
)
.with_menu(Some(conversion::menu(&application.menu())))
.build(&event_loop)
.map_err(Error::WindowCreationFailed)?;
let (compositor, renderer) = C::new(compositor_settings, Some(&window))?;
let (mut sender, receiver) = mpsc::unbounded();
let mut instance = Box::pin(run_instance::<A, E, C>(
application,
compositor,
renderer,
window,
runtime,
debug,
receiver,
window,
settings.exit_on_close_request,
));
let mut context = task::Context::from_waker(task::noop_waker_ref());
@ -164,7 +181,22 @@ where
return;
}
if let Some(event) = event.to_static() {
let event = match event {
winit::event::Event::WindowEvent {
event:
winit::event::WindowEvent::ScaleFactorChanged {
new_inner_size,
..
},
window_id,
} => Some(winit::event::Event::WindowEvent {
event: winit::event::WindowEvent::Resized(*new_inner_size),
window_id,
}),
_ => event.to_static(),
};
if let Some(event) = event {
sender.start_send(event).expect("Send event");
let poll = instance.as_mut().poll(&mut context);
@ -181,10 +213,11 @@ async fn run_instance<A, E, C>(
mut application: A,
mut compositor: C,
mut renderer: A::Renderer,
window: winit::window::Window,
mut runtime: Runtime<E, Proxy<A::Message>, A::Message>,
mut debug: Debug,
mut receiver: mpsc::UnboundedReceiver<winit::event::Event<'_, A::Message>>,
window: winit::window::Window,
exit_on_close_request: bool,
) where
A: Application + 'static,
E: Executor + 'static,
@ -194,7 +227,7 @@ async fn run_instance<A, E, C>(
use winit::event;
let surface = compositor.create_surface(&window);
let clipboard = Clipboard::new(&window);
let mut clipboard = Clipboard::connect(&window);
let mut state = State::new(&application, &window);
let mut viewport_version = state.viewport_version();
@ -237,8 +270,8 @@ async fn run_instance<A, E, C>(
let statuses = user_interface.update(
&events,
state.cursor_position(),
clipboard.as_ref().map(|c| c as _),
&mut renderer,
&mut clipboard,
&mut messages,
);
@ -257,12 +290,15 @@ async fn run_instance<A, E, C>(
&mut application,
&mut runtime,
&mut debug,
&mut clipboard,
&mut messages,
);
// Update window
state.synchronize(&application, &window);
let should_exit = application.should_exit();
user_interface = ManuallyDrop::new(build_user_interface(
&mut application,
cache,
@ -270,6 +306,10 @@ async fn run_instance<A, E, C>(
state.logical_size(),
&mut debug,
));
if should_exit {
break;
}
}
debug.draw_started();
@ -279,15 +319,30 @@ async fn run_instance<A, E, C>(
window.request_redraw();
}
event::Event::PlatformSpecific(event::PlatformSpecific::MacOS(
event::MacOS::ReceivedUrl(url),
)) => {
use iced_native::event;
events.push(iced_native::Event::PlatformSpecific(
event::PlatformSpecific::MacOS(event::MacOS::ReceivedUrl(
url,
)),
));
}
event::Event::UserEvent(message) => {
messages.push(message);
}
event::Event::RedrawRequested(_) => {
let physical_size = state.physical_size();
if physical_size.width == 0 || physical_size.height == 0 {
continue;
}
debug.render_started();
let current_viewport_version = state.viewport_version();
if viewport_version != current_viewport_version {
let physical_size = state.physical_size();
let logical_size = state.logical_size();
debug.layout_started();
@ -338,11 +393,23 @@ async fn run_instance<A, E, C>(
window.request_redraw();
}
}
event::Event::WindowEvent {
event: event::WindowEvent::MenuEntryActivated(entry_id),
..
} => {
if let Some(message) =
conversion::menu_message(state.menu(), entry_id)
{
messages.push(message);
}
}
event::Event::WindowEvent {
event: window_event,
..
} => {
if requests_exit(&window_event, state.modifiers()) {
if requests_exit(&window_event, state.modifiers())
&& exit_on_close_request
{
break;
}
@ -414,13 +481,14 @@ pub fn update<A: Application, E: Executor>(
application: &mut A,
runtime: &mut Runtime<E, Proxy<A::Message>, A::Message>,
debug: &mut Debug,
clipboard: &mut A::Clipboard,
messages: &mut Vec<A::Message>,
) {
for message in messages.drain(..) {
debug.log_message(&message);
debug.update_started();
let command = runtime.enter(|| application.update(message));
let command = runtime.enter(|| application.update(message, clipboard));
debug.update_finished();
runtime.spawn(command);

View file

@ -1,14 +1,15 @@
use crate::conversion;
use crate::{Application, Color, Debug, Mode, Point, Size, Viewport};
use crate::{Application, Color, Debug, Menu, Mode, Point, Size, Viewport};
use std::marker::PhantomData;
use winit::event::WindowEvent;
use winit::event::{Touch, WindowEvent};
use winit::window::Window;
/// The state of a windowed [`Application`].
#[derive(Debug, Clone)]
pub struct State<A: Application> {
title: String,
menu: Menu<A::Message>,
mode: Mode,
background_color: Color,
scale_factor: f64,
@ -23,6 +24,7 @@ impl<A: Application> State<A> {
/// Creates a new [`State`] for the provided [`Application`] and window.
pub fn new(application: &A, window: &Window) -> Self {
let title = application.title();
let menu = application.menu();
let mode = application.mode();
let background_color = application.background_color();
let scale_factor = application.scale_factor();
@ -38,6 +40,7 @@ impl<A: Application> State<A> {
Self {
title,
menu,
mode,
background_color,
scale_factor,
@ -50,6 +53,11 @@ impl<A: Application> State<A> {
}
}
/// Returns the current [`Menu`] of the [`State`].
pub fn menu(&self) -> &Menu<A::Message> {
&self.menu
}
/// Returns the current background [`Color`] of the [`State`].
pub fn background_color(&self) -> Color {
self.background_color
@ -128,7 +136,10 @@ impl<A: Application> State<A> {
self.viewport_version = self.viewport_version.wrapping_add(1);
}
WindowEvent::CursorMoved { position, .. } => {
WindowEvent::CursorMoved { position, .. }
| WindowEvent::Touch(Touch {
location: position, ..
}) => {
self.cursor_position = *position;
}
WindowEvent::CursorLeft { .. } => {
@ -179,6 +190,8 @@ impl<A: Application> State<A> {
new_mode,
));
window.set_visible(conversion::visible(new_mode));
self.mode = new_mode;
}
@ -198,5 +211,14 @@ impl<A: Application> State<A> {
self.scale_factor = new_scale_factor;
}
// Update menu
let new_menu = application.menu();
if self.menu != new_menu {
window.set_menu(Some(conversion::menu(&new_menu)));
self.menu = new_menu;
}
}
}

View file

@ -1,17 +1,54 @@
/// A buffer for short-term storage and transfer within and between
/// applications.
#[allow(missing_debug_implementations)]
pub struct Clipboard(window_clipboard::Clipboard);
pub struct Clipboard {
state: State,
}
enum State {
Connected(window_clipboard::Clipboard),
Unavailable,
}
impl Clipboard {
/// Creates a new [`Clipboard`] for the given window.
pub fn new(window: &winit::window::Window) -> Option<Clipboard> {
window_clipboard::Clipboard::new(window).map(Clipboard).ok()
pub fn connect(window: &winit::window::Window) -> Clipboard {
let state = window_clipboard::Clipboard::connect(window)
.ok()
.map(State::Connected)
.unwrap_or(State::Unavailable);
Clipboard { state }
}
/// Reads the current content of the [`Clipboard`] as text.
pub fn read(&self) -> Option<String> {
match &self.state {
State::Connected(clipboard) => clipboard.read().ok(),
State::Unavailable => None,
}
}
/// Writes the given text contents to the [`Clipboard`].
pub fn write(&mut self, contents: String) {
match &mut self.state {
State::Connected(clipboard) => match clipboard.write(contents) {
Ok(()) => {}
Err(error) => {
log::warn!("error writing to clipboard: {}", error)
}
},
State::Unavailable => {}
}
}
}
impl iced_native::Clipboard for Clipboard {
fn content(&self) -> Option<String> {
self.0.read().ok()
fn read(&self) -> Option<String> {
self.read()
}
fn write(&mut self, contents: String) {
self.write(contents)
}
}

View file

@ -2,10 +2,12 @@
//!
//! [`winit`]: https://github.com/rust-windowing/winit
//! [`iced_native`]: https://github.com/hecrj/iced/tree/master/native
use crate::{
keyboard::{self, KeyCode, Modifiers},
mouse, window, Event, Mode, Point,
};
use crate::keyboard;
use crate::menu::{self, Menu};
use crate::mouse;
use crate::touch;
use crate::window;
use crate::{Event, Mode, Point, Position};
/// Converts a winit window event into an iced event.
pub fn window_event(
@ -32,12 +34,14 @@ pub fn window_event(
height: logical_size.height,
}))
}
WindowEvent::CloseRequested => {
Some(Event::Window(window::Event::CloseRequested))
}
WindowEvent::CursorMoved { position, .. } => {
let position = position.to_logical::<f64>(scale_factor);
Some(Event::Mouse(mouse::Event::CursorMoved {
x: position.x as f32,
y: position.y as f32,
position: Point::new(position.x as f32, position.y as f32),
}))
}
WindowEvent::CursorEntered { .. } => {
@ -109,6 +113,11 @@ pub fn window_event(
WindowEvent::ModifiersChanged(new_modifiers) => Some(Event::Keyboard(
keyboard::Event::ModifiersChanged(self::modifiers(*new_modifiers)),
)),
WindowEvent::Focused(focused) => Some(Event::Window(if *focused {
window::Event::Focused
} else {
window::Event::Unfocused
})),
WindowEvent::HoveredFile(path) => {
Some(Event::Window(window::Event::FileHovered(path.clone())))
}
@ -118,10 +127,56 @@ pub fn window_event(
WindowEvent::HoveredFileCancelled => {
Some(Event::Window(window::Event::FilesHoveredLeft))
}
WindowEvent::Touch(touch) => {
Some(Event::Touch(touch_event(*touch, scale_factor)))
}
_ => None,
}
}
/// Converts a [`Position`] to a [`winit`] logical position for a given monitor.
///
/// [`winit`]: https://github.com/rust-windowing/winit
pub fn position(
monitor: Option<&winit::monitor::MonitorHandle>,
(width, height): (u32, u32),
position: Position,
) -> Option<winit::dpi::Position> {
match position {
Position::Default => None,
Position::Specific(x, y) => {
Some(winit::dpi::Position::Logical(winit::dpi::LogicalPosition {
x: f64::from(x),
y: f64::from(y),
}))
}
Position::Centered => {
if let Some(monitor) = monitor {
let start = monitor.position();
let resolution: winit::dpi::LogicalSize<f64> =
monitor.size().to_logical(monitor.scale_factor());
let centered: winit::dpi::PhysicalPosition<i32> =
winit::dpi::LogicalPosition {
x: (resolution.width - f64::from(width)) / 2.0,
y: (resolution.height - f64::from(height)) / 2.0,
}
.to_physical(monitor.scale_factor());
Some(winit::dpi::Position::Physical(
winit::dpi::PhysicalPosition {
x: start.x + centered.x,
y: start.y + centered.y,
},
))
} else {
None
}
}
}
}
/// Converts a [`Mode`] to a [`winit`] fullscreen mode.
///
/// [`winit`]: https://github.com/rust-windowing/winit
@ -130,13 +185,125 @@ pub fn fullscreen(
mode: Mode,
) -> Option<winit::window::Fullscreen> {
match mode {
Mode::Windowed => None,
Mode::Windowed | Mode::Hidden => None,
Mode::Fullscreen => {
Some(winit::window::Fullscreen::Borderless(monitor))
}
}
}
/// Converts a [`Mode`] to a visibility flag.
pub fn visible(mode: Mode) -> bool {
match mode {
Mode::Windowed | Mode::Fullscreen => true,
Mode::Hidden => false,
}
}
/// Converts a `Hotkey` from [`iced_native`] to a [`winit`] Hotkey.
///
/// [`winit`]: https://github.com/rust-windowing/winit
/// [`iced_native`]: https://github.com/hecrj/iced/tree/master/native
fn hotkey(hotkey: keyboard::Hotkey) -> winit::window::Hotkey {
use winit::event::ModifiersState;
let mut modifiers = ModifiersState::empty();
modifiers.set(ModifiersState::CTRL, hotkey.modifiers.control());
modifiers.set(ModifiersState::SHIFT, hotkey.modifiers.shift());
modifiers.set(ModifiersState::ALT, hotkey.modifiers.alt());
modifiers.set(ModifiersState::LOGO, hotkey.modifiers.logo());
winit::window::Hotkey::new(modifiers, to_virtual_keycode(hotkey.key))
}
/// Converts a `Menu` from [`iced_native`] to a [`winit`] menu.
///
/// [`winit`]: https://github.com/rust-windowing/winit
/// [`iced_native`]: https://github.com/hecrj/iced/tree/master/native
pub fn menu<Message>(menu: &Menu<Message>) -> winit::window::Menu {
fn menu_i<Message>(
converted: &mut winit::window::Menu,
starting_id: usize,
menu: &Menu<Message>,
) -> usize {
let mut id = starting_id;
for item in menu.iter() {
match item {
menu::Entry::Item { title, hotkey, .. } => {
converted.add_item(id, title, hotkey.map(self::hotkey));
id += 1;
}
menu::Entry::Dropdown { title, submenu } => {
let mut converted_submenu = winit::window::Menu::new();
let n_children =
menu_i(&mut converted_submenu, id, submenu);
converted.add_dropdown(title, converted_submenu);
id += n_children;
}
menu::Entry::Separator => {
converted.add_separator();
}
}
}
id - starting_id
}
let mut converted = winit::window::Menu::default();
let _ = menu_i(&mut converted, 0, menu);
converted
}
/// Given a [`Menu`] and an identifier of a [`menu::Entry`], it returns the
/// `Message` that should be produced when that entry is activated.
pub fn menu_message<Message>(menu: &Menu<Message>, id: u32) -> Option<Message>
where
Message: Clone,
{
fn find_message<Message>(
target: u32,
starting_id: u32,
menu: &Menu<Message>,
) -> Result<Message, u32>
where
Message: Clone,
{
let mut id = starting_id;
for entry in menu.iter() {
match entry {
menu::Entry::Item { on_activation, .. } => {
if id == target {
return Ok(on_activation.clone());
}
id += 1;
}
menu::Entry::Dropdown { submenu, .. } => {
match find_message(target, id, submenu) {
Ok(message) => {
return Ok(message);
}
Err(n_children) => {
id += n_children;
}
}
}
menu::Entry::Separator => {}
}
}
Err(id - starting_id)
}
find_message(id, 0, menu).ok()
}
/// Converts a `MouseCursor` from [`iced_native`] to a [`winit`] cursor icon.
///
/// [`winit`]: https://github.com/rust-windowing/winit
@ -181,13 +348,17 @@ pub fn mouse_button(mouse_button: winit::event::MouseButton) -> mouse::Button {
///
/// [`winit`]: https://github.com/rust-windowing/winit
/// [`iced_native`]: https://github.com/hecrj/iced/tree/master/native
pub fn modifiers(modifiers: winit::event::ModifiersState) -> Modifiers {
Modifiers {
shift: modifiers.shift(),
control: modifiers.ctrl(),
alt: modifiers.alt(),
logo: modifiers.logo(),
}
pub fn modifiers(
modifiers: winit::event::ModifiersState,
) -> keyboard::Modifiers {
let mut result = keyboard::Modifiers::empty();
result.set(keyboard::Modifiers::SHIFT, modifiers.shift());
result.set(keyboard::Modifiers::CTRL, modifiers.ctrl());
result.set(keyboard::Modifiers::ALT, modifiers.alt());
result.set(keyboard::Modifiers::LOGO, modifiers.logo());
result
}
/// Converts a physical cursor position to a logical `Point`.
@ -200,11 +371,223 @@ pub fn cursor_position(
Point::new(logical_position.x, logical_position.y)
}
/// Converts a `Touch` from [`winit`] to an [`iced_native`] touch event.
///
/// [`winit`]: https://github.com/rust-windowing/winit
/// [`iced_native`]: https://github.com/hecrj/iced/tree/master/native
pub fn touch_event(
touch: winit::event::Touch,
scale_factor: f64,
) -> touch::Event {
let id = touch::Finger(touch.id);
let position = {
let location = touch.location.to_logical::<f64>(scale_factor);
Point::new(location.x as f32, location.y as f32)
};
match touch.phase {
winit::event::TouchPhase::Started => {
touch::Event::FingerPressed { id, position }
}
winit::event::TouchPhase::Moved => {
touch::Event::FingerMoved { id, position }
}
winit::event::TouchPhase::Ended => {
touch::Event::FingerLifted { id, position }
}
winit::event::TouchPhase::Cancelled => {
touch::Event::FingerLost { id, position }
}
}
}
/// Converts a `KeyCode` from [`iced_native`] to an [`winit`] key code.
///
/// [`winit`]: https://github.com/rust-windowing/winit
/// [`iced_native`]: https://github.com/hecrj/iced/tree/master/native
fn to_virtual_keycode(
keycode: keyboard::KeyCode,
) -> winit::event::VirtualKeyCode {
use keyboard::KeyCode;
use winit::event::VirtualKeyCode;
match keycode {
KeyCode::Key1 => VirtualKeyCode::Key1,
KeyCode::Key2 => VirtualKeyCode::Key2,
KeyCode::Key3 => VirtualKeyCode::Key3,
KeyCode::Key4 => VirtualKeyCode::Key4,
KeyCode::Key5 => VirtualKeyCode::Key5,
KeyCode::Key6 => VirtualKeyCode::Key6,
KeyCode::Key7 => VirtualKeyCode::Key7,
KeyCode::Key8 => VirtualKeyCode::Key8,
KeyCode::Key9 => VirtualKeyCode::Key9,
KeyCode::Key0 => VirtualKeyCode::Key0,
KeyCode::A => VirtualKeyCode::A,
KeyCode::B => VirtualKeyCode::B,
KeyCode::C => VirtualKeyCode::C,
KeyCode::D => VirtualKeyCode::D,
KeyCode::E => VirtualKeyCode::E,
KeyCode::F => VirtualKeyCode::F,
KeyCode::G => VirtualKeyCode::G,
KeyCode::H => VirtualKeyCode::H,
KeyCode::I => VirtualKeyCode::I,
KeyCode::J => VirtualKeyCode::J,
KeyCode::K => VirtualKeyCode::K,
KeyCode::L => VirtualKeyCode::L,
KeyCode::M => VirtualKeyCode::M,
KeyCode::N => VirtualKeyCode::N,
KeyCode::O => VirtualKeyCode::O,
KeyCode::P => VirtualKeyCode::P,
KeyCode::Q => VirtualKeyCode::Q,
KeyCode::R => VirtualKeyCode::R,
KeyCode::S => VirtualKeyCode::S,
KeyCode::T => VirtualKeyCode::T,
KeyCode::U => VirtualKeyCode::U,
KeyCode::V => VirtualKeyCode::V,
KeyCode::W => VirtualKeyCode::W,
KeyCode::X => VirtualKeyCode::X,
KeyCode::Y => VirtualKeyCode::Y,
KeyCode::Z => VirtualKeyCode::Z,
KeyCode::Escape => VirtualKeyCode::Escape,
KeyCode::F1 => VirtualKeyCode::F1,
KeyCode::F2 => VirtualKeyCode::F2,
KeyCode::F3 => VirtualKeyCode::F3,
KeyCode::F4 => VirtualKeyCode::F4,
KeyCode::F5 => VirtualKeyCode::F5,
KeyCode::F6 => VirtualKeyCode::F6,
KeyCode::F7 => VirtualKeyCode::F7,
KeyCode::F8 => VirtualKeyCode::F8,
KeyCode::F9 => VirtualKeyCode::F9,
KeyCode::F10 => VirtualKeyCode::F10,
KeyCode::F11 => VirtualKeyCode::F11,
KeyCode::F12 => VirtualKeyCode::F12,
KeyCode::F13 => VirtualKeyCode::F13,
KeyCode::F14 => VirtualKeyCode::F14,
KeyCode::F15 => VirtualKeyCode::F15,
KeyCode::F16 => VirtualKeyCode::F16,
KeyCode::F17 => VirtualKeyCode::F17,
KeyCode::F18 => VirtualKeyCode::F18,
KeyCode::F19 => VirtualKeyCode::F19,
KeyCode::F20 => VirtualKeyCode::F20,
KeyCode::F21 => VirtualKeyCode::F21,
KeyCode::F22 => VirtualKeyCode::F22,
KeyCode::F23 => VirtualKeyCode::F23,
KeyCode::F24 => VirtualKeyCode::F24,
KeyCode::Snapshot => VirtualKeyCode::Snapshot,
KeyCode::Scroll => VirtualKeyCode::Scroll,
KeyCode::Pause => VirtualKeyCode::Pause,
KeyCode::Insert => VirtualKeyCode::Insert,
KeyCode::Home => VirtualKeyCode::Home,
KeyCode::Delete => VirtualKeyCode::Delete,
KeyCode::End => VirtualKeyCode::End,
KeyCode::PageDown => VirtualKeyCode::PageDown,
KeyCode::PageUp => VirtualKeyCode::PageUp,
KeyCode::Left => VirtualKeyCode::Left,
KeyCode::Up => VirtualKeyCode::Up,
KeyCode::Right => VirtualKeyCode::Right,
KeyCode::Down => VirtualKeyCode::Down,
KeyCode::Backspace => VirtualKeyCode::Back,
KeyCode::Enter => VirtualKeyCode::Return,
KeyCode::Space => VirtualKeyCode::Space,
KeyCode::Compose => VirtualKeyCode::Compose,
KeyCode::Caret => VirtualKeyCode::Caret,
KeyCode::Numlock => VirtualKeyCode::Numlock,
KeyCode::Numpad0 => VirtualKeyCode::Numpad0,
KeyCode::Numpad1 => VirtualKeyCode::Numpad1,
KeyCode::Numpad2 => VirtualKeyCode::Numpad2,
KeyCode::Numpad3 => VirtualKeyCode::Numpad3,
KeyCode::Numpad4 => VirtualKeyCode::Numpad4,
KeyCode::Numpad5 => VirtualKeyCode::Numpad5,
KeyCode::Numpad6 => VirtualKeyCode::Numpad6,
KeyCode::Numpad7 => VirtualKeyCode::Numpad7,
KeyCode::Numpad8 => VirtualKeyCode::Numpad8,
KeyCode::Numpad9 => VirtualKeyCode::Numpad9,
KeyCode::AbntC1 => VirtualKeyCode::AbntC1,
KeyCode::AbntC2 => VirtualKeyCode::AbntC2,
KeyCode::NumpadAdd => VirtualKeyCode::NumpadAdd,
KeyCode::Plus => VirtualKeyCode::Plus,
KeyCode::Apostrophe => VirtualKeyCode::Apostrophe,
KeyCode::Apps => VirtualKeyCode::Apps,
KeyCode::At => VirtualKeyCode::At,
KeyCode::Ax => VirtualKeyCode::Ax,
KeyCode::Backslash => VirtualKeyCode::Backslash,
KeyCode::Calculator => VirtualKeyCode::Calculator,
KeyCode::Capital => VirtualKeyCode::Capital,
KeyCode::Colon => VirtualKeyCode::Colon,
KeyCode::Comma => VirtualKeyCode::Comma,
KeyCode::Convert => VirtualKeyCode::Convert,
KeyCode::NumpadDecimal => VirtualKeyCode::NumpadDecimal,
KeyCode::NumpadDivide => VirtualKeyCode::NumpadDivide,
KeyCode::Equals => VirtualKeyCode::Equals,
KeyCode::Grave => VirtualKeyCode::Grave,
KeyCode::Kana => VirtualKeyCode::Kana,
KeyCode::Kanji => VirtualKeyCode::Kanji,
KeyCode::LAlt => VirtualKeyCode::LAlt,
KeyCode::LBracket => VirtualKeyCode::LBracket,
KeyCode::LControl => VirtualKeyCode::LControl,
KeyCode::LShift => VirtualKeyCode::LShift,
KeyCode::LWin => VirtualKeyCode::LWin,
KeyCode::Mail => VirtualKeyCode::Mail,
KeyCode::MediaSelect => VirtualKeyCode::MediaSelect,
KeyCode::MediaStop => VirtualKeyCode::MediaStop,
KeyCode::Minus => VirtualKeyCode::Minus,
KeyCode::NumpadMultiply => VirtualKeyCode::NumpadMultiply,
KeyCode::Mute => VirtualKeyCode::Mute,
KeyCode::MyComputer => VirtualKeyCode::MyComputer,
KeyCode::NavigateForward => VirtualKeyCode::NavigateForward,
KeyCode::NavigateBackward => VirtualKeyCode::NavigateBackward,
KeyCode::NextTrack => VirtualKeyCode::NextTrack,
KeyCode::NoConvert => VirtualKeyCode::NoConvert,
KeyCode::NumpadComma => VirtualKeyCode::NumpadComma,
KeyCode::NumpadEnter => VirtualKeyCode::NumpadEnter,
KeyCode::NumpadEquals => VirtualKeyCode::NumpadEquals,
KeyCode::OEM102 => VirtualKeyCode::OEM102,
KeyCode::Period => VirtualKeyCode::Period,
KeyCode::PlayPause => VirtualKeyCode::PlayPause,
KeyCode::Power => VirtualKeyCode::Power,
KeyCode::PrevTrack => VirtualKeyCode::PrevTrack,
KeyCode::RAlt => VirtualKeyCode::RAlt,
KeyCode::RBracket => VirtualKeyCode::RBracket,
KeyCode::RControl => VirtualKeyCode::RControl,
KeyCode::RShift => VirtualKeyCode::RShift,
KeyCode::RWin => VirtualKeyCode::RWin,
KeyCode::Semicolon => VirtualKeyCode::Semicolon,
KeyCode::Slash => VirtualKeyCode::Slash,
KeyCode::Sleep => VirtualKeyCode::Sleep,
KeyCode::Stop => VirtualKeyCode::Stop,
KeyCode::NumpadSubtract => VirtualKeyCode::NumpadSubtract,
KeyCode::Sysrq => VirtualKeyCode::Sysrq,
KeyCode::Tab => VirtualKeyCode::Tab,
KeyCode::Underline => VirtualKeyCode::Underline,
KeyCode::Unlabeled => VirtualKeyCode::Unlabeled,
KeyCode::VolumeDown => VirtualKeyCode::VolumeDown,
KeyCode::VolumeUp => VirtualKeyCode::VolumeUp,
KeyCode::Wake => VirtualKeyCode::Wake,
KeyCode::WebBack => VirtualKeyCode::WebBack,
KeyCode::WebFavorites => VirtualKeyCode::WebFavorites,
KeyCode::WebForward => VirtualKeyCode::WebForward,
KeyCode::WebHome => VirtualKeyCode::WebHome,
KeyCode::WebRefresh => VirtualKeyCode::WebRefresh,
KeyCode::WebSearch => VirtualKeyCode::WebSearch,
KeyCode::WebStop => VirtualKeyCode::WebStop,
KeyCode::Yen => VirtualKeyCode::Yen,
KeyCode::Copy => VirtualKeyCode::Copy,
KeyCode::Paste => VirtualKeyCode::Paste,
KeyCode::Cut => VirtualKeyCode::Cut,
KeyCode::Asterisk => VirtualKeyCode::Asterisk,
}
}
/// Converts a `VirtualKeyCode` from [`winit`] to an [`iced_native`] key code.
///
/// [`winit`]: https://github.com/rust-windowing/winit
/// [`iced_native`]: https://github.com/hecrj/iced/tree/master/native
pub fn key_code(virtual_keycode: winit::event::VirtualKeyCode) -> KeyCode {
pub fn key_code(
virtual_keycode: winit::event::VirtualKeyCode,
) -> keyboard::KeyCode {
use keyboard::KeyCode;
match virtual_keycode {
winit::event::VirtualKeyCode::Key1 => KeyCode::Key1,
winit::event::VirtualKeyCode::Key2 => KeyCode::Key2,

View file

@ -31,12 +31,14 @@ pub mod settings;
mod clipboard;
mod error;
mod mode;
mod position;
mod proxy;
pub use application::Application;
pub use clipboard::Clipboard;
pub use error::Error;
pub use mode::Mode;
pub use position::Position;
pub use proxy::Proxy;
pub use settings::Settings;

View file

@ -6,4 +6,7 @@ pub enum Mode {
/// The application takes the whole screen of its current monitor.
Fullscreen,
/// The application is hidden
Hidden,
}

22
winit/src/position.rs Normal file
View file

@ -0,0 +1,22 @@
/// The position of a window in a given screen.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Position {
/// The platform-specific default position for a new window.
Default,
/// The window is completely centered on the screen.
Centered,
/// The window is positioned with specific coordinates: `(X, Y)`.
///
/// When the decorations of the window are enabled, Windows 10 will add some
/// invisible padding to the window. This padding gets included in the
/// position. So if you have decorations enabled and want the window to be
/// at (0, 0) you would have to set the position to
/// `(PADDING_X, PADDING_Y)`.
Specific(i32, i32),
}
impl Default for Position {
fn default() -> Self {
Self::Default
}
}

View file

@ -9,7 +9,7 @@ mod platform;
pub use platform::PlatformSpecific;
use crate::conversion;
use crate::Mode;
use crate::{Mode, Position};
use winit::monitor::MonitorHandle;
use winit::window::WindowBuilder;
@ -23,6 +23,10 @@ pub struct Settings<Flags> {
///
/// [`Application`]: crate::Application
pub flags: Flags,
/// Whether the [`Application`] should exit when the user requests the
/// window to close (e.g. the user presses the close button).
pub exit_on_close_request: bool,
}
/// The window settings of an application.
@ -31,6 +35,9 @@ pub struct Window {
/// The size of the window.
pub size: (u32, u32),
/// The position of the window.
pub position: Position,
/// The minimum size of the window.
pub min_size: Option<(u32, u32)>,
@ -76,7 +83,15 @@ impl Window {
.with_transparent(self.transparent)
.with_window_icon(self.icon)
.with_always_on_top(self.always_on_top)
.with_fullscreen(conversion::fullscreen(primary_monitor, mode));
.with_visible(conversion::visible(mode));
if let Some(position) = conversion::position(
primary_monitor.as_ref(),
self.size,
self.position,
) {
window_builder = window_builder.with_position(position);
}
if let Some((width, height)) = self.min_size {
window_builder = window_builder
@ -95,8 +110,13 @@ impl Window {
if let Some(parent) = self.platform_specific.parent {
window_builder = window_builder.with_parent_window(parent);
}
window_builder = window_builder
.with_drag_and_drop(self.platform_specific.drag_and_drop);
}
window_builder = window_builder
.with_fullscreen(conversion::fullscreen(primary_monitor, mode));
window_builder
}
}
@ -105,6 +125,7 @@ impl Default for Window {
fn default() -> Window {
Window {
size: (1024, 768),
position: Position::default(),
min_size: None,
max_size: None,
resizable: true,

View file

@ -2,8 +2,20 @@
//! Platform specific settings for Windows.
/// The platform specific window settings of an application.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct PlatformSpecific {
/// Parent Window
/// Parent window
pub parent: Option<winapi::shared::windef::HWND>,
/// Drag and drop support
pub drag_and_drop: bool,
}
impl Default for PlatformSpecific {
fn default() -> Self {
Self {
parent: None,
drag_and_drop: true,
}
}
}