Merge branch 'master' into beacon
This commit is contained in:
commit
8bd5de72ea
371 changed files with 33138 additions and 12950 deletions
File diff suppressed because it is too large
Load diff
|
|
@ -1,209 +0,0 @@
|
|||
use crate::application;
|
||||
use crate::conversion;
|
||||
use crate::core::mouse;
|
||||
use crate::core::{Color, Size};
|
||||
use crate::debug;
|
||||
use crate::graphics::Viewport;
|
||||
use crate::Application;
|
||||
|
||||
use std::marker::PhantomData;
|
||||
use winit::event::{Touch, WindowEvent};
|
||||
use winit::window::Window;
|
||||
|
||||
/// The state of a windowed [`Application`].
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct State<A: Application>
|
||||
where
|
||||
A::Theme: application::DefaultStyle,
|
||||
{
|
||||
title: String,
|
||||
scale_factor: f64,
|
||||
viewport: Viewport,
|
||||
viewport_version: usize,
|
||||
cursor_position: Option<winit::dpi::PhysicalPosition<f64>>,
|
||||
modifiers: winit::keyboard::ModifiersState,
|
||||
theme: A::Theme,
|
||||
appearance: application::Appearance,
|
||||
application: PhantomData<A>,
|
||||
}
|
||||
|
||||
impl<A: Application> State<A>
|
||||
where
|
||||
A::Theme: application::DefaultStyle,
|
||||
{
|
||||
/// Creates a new [`State`] for the provided [`Application`] and window.
|
||||
pub fn new(application: &A, window: &Window) -> Self {
|
||||
let title = application.title();
|
||||
let scale_factor = application.scale_factor();
|
||||
let theme = application.theme();
|
||||
let appearance = application.style(&theme);
|
||||
|
||||
debug::theme_changed(|| application::DefaultStyle::palette(&theme));
|
||||
|
||||
let viewport = {
|
||||
let physical_size = window.inner_size();
|
||||
|
||||
Viewport::with_physical_size(
|
||||
Size::new(physical_size.width, physical_size.height),
|
||||
window.scale_factor() * scale_factor,
|
||||
)
|
||||
};
|
||||
|
||||
Self {
|
||||
title,
|
||||
scale_factor,
|
||||
viewport,
|
||||
viewport_version: 0,
|
||||
cursor_position: None,
|
||||
modifiers: winit::keyboard::ModifiersState::default(),
|
||||
theme,
|
||||
appearance,
|
||||
application: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the current [`Viewport`] of the [`State`].
|
||||
pub fn viewport(&self) -> &Viewport {
|
||||
&self.viewport
|
||||
}
|
||||
|
||||
/// Returns the version of the [`Viewport`] of the [`State`].
|
||||
///
|
||||
/// The version is incremented every time the [`Viewport`] changes.
|
||||
pub fn viewport_version(&self) -> usize {
|
||||
self.viewport_version
|
||||
}
|
||||
|
||||
/// Returns the physical [`Size`] of the [`Viewport`] of the [`State`].
|
||||
pub fn physical_size(&self) -> Size<u32> {
|
||||
self.viewport.physical_size()
|
||||
}
|
||||
|
||||
/// Returns the logical [`Size`] of the [`Viewport`] of the [`State`].
|
||||
pub fn logical_size(&self) -> Size<f32> {
|
||||
self.viewport.logical_size()
|
||||
}
|
||||
|
||||
/// Returns the current scale factor of the [`Viewport`] of the [`State`].
|
||||
pub fn scale_factor(&self) -> f64 {
|
||||
self.viewport.scale_factor()
|
||||
}
|
||||
|
||||
/// Returns the current cursor position of the [`State`].
|
||||
pub fn cursor(&self) -> mouse::Cursor {
|
||||
self.cursor_position
|
||||
.map(|cursor_position| {
|
||||
conversion::cursor_position(
|
||||
cursor_position,
|
||||
self.viewport.scale_factor(),
|
||||
)
|
||||
})
|
||||
.map(mouse::Cursor::Available)
|
||||
.unwrap_or(mouse::Cursor::Unavailable)
|
||||
}
|
||||
|
||||
/// Returns the current keyboard modifiers of the [`State`].
|
||||
pub fn modifiers(&self) -> winit::keyboard::ModifiersState {
|
||||
self.modifiers
|
||||
}
|
||||
|
||||
/// Returns the current theme of the [`State`].
|
||||
pub fn theme(&self) -> &A::Theme {
|
||||
&self.theme
|
||||
}
|
||||
|
||||
/// Returns the current background [`Color`] of the [`State`].
|
||||
pub fn background_color(&self) -> Color {
|
||||
self.appearance.background_color
|
||||
}
|
||||
|
||||
/// Returns the current text [`Color`] of the [`State`].
|
||||
pub fn text_color(&self) -> Color {
|
||||
self.appearance.text_color
|
||||
}
|
||||
|
||||
/// Processes the provided window event and updates the [`State`]
|
||||
/// accordingly.
|
||||
pub fn update(&mut self, window: &Window, event: &WindowEvent) {
|
||||
match event {
|
||||
WindowEvent::Resized(new_size) => {
|
||||
let size = Size::new(new_size.width, new_size.height);
|
||||
|
||||
self.viewport = Viewport::with_physical_size(
|
||||
size,
|
||||
window.scale_factor() * self.scale_factor,
|
||||
);
|
||||
|
||||
self.viewport_version = self.viewport_version.wrapping_add(1);
|
||||
}
|
||||
WindowEvent::ScaleFactorChanged {
|
||||
scale_factor: new_scale_factor,
|
||||
..
|
||||
} => {
|
||||
let size = self.viewport.physical_size();
|
||||
|
||||
self.viewport = Viewport::with_physical_size(
|
||||
size,
|
||||
new_scale_factor * self.scale_factor,
|
||||
);
|
||||
|
||||
self.viewport_version = self.viewport_version.wrapping_add(1);
|
||||
}
|
||||
WindowEvent::CursorMoved { position, .. }
|
||||
| WindowEvent::Touch(Touch {
|
||||
location: position, ..
|
||||
}) => {
|
||||
self.cursor_position = Some(*position);
|
||||
}
|
||||
WindowEvent::CursorLeft { .. } => {
|
||||
self.cursor_position = None;
|
||||
}
|
||||
WindowEvent::ModifiersChanged(new_modifiers) => {
|
||||
self.modifiers = new_modifiers.state();
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
/// Synchronizes the [`State`] with its [`Application`] and its respective
|
||||
/// window.
|
||||
///
|
||||
/// Normally an [`Application`] should be synchronized with its [`State`]
|
||||
/// and window after calling [`crate::application::update`].
|
||||
pub fn synchronize(&mut self, application: &A, window: &Window) {
|
||||
// Update window title
|
||||
let new_title = application.title();
|
||||
|
||||
if self.title != new_title {
|
||||
window.set_title(&new_title);
|
||||
|
||||
self.title = new_title;
|
||||
}
|
||||
|
||||
// Update scale factor and size
|
||||
let new_scale_factor = application.scale_factor();
|
||||
let new_size = window.inner_size();
|
||||
let current_size = self.viewport.physical_size();
|
||||
|
||||
if self.scale_factor != new_scale_factor
|
||||
|| (current_size.width, current_size.height)
|
||||
!= (new_size.width, new_size.height)
|
||||
{
|
||||
self.viewport = Viewport::with_physical_size(
|
||||
Size::new(new_size.width, new_size.height),
|
||||
window.scale_factor() * new_scale_factor,
|
||||
);
|
||||
self.viewport_version = self.viewport_version.wrapping_add(1);
|
||||
|
||||
self.scale_factor = new_scale_factor;
|
||||
}
|
||||
|
||||
// Update theme and appearance
|
||||
self.theme = application.theme();
|
||||
self.appearance = application.style(&self.theme);
|
||||
|
||||
debug::theme_changed(|| {
|
||||
application::DefaultStyle::palette(&self.theme)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
//! Access the clipboard.
|
||||
|
||||
use crate::core::clipboard::Kind;
|
||||
use std::sync::Arc;
|
||||
use winit::window::{Window, WindowId};
|
||||
|
||||
/// A buffer for short-term storage and transfer within and between
|
||||
/// applications.
|
||||
|
|
@ -10,18 +12,33 @@ pub struct Clipboard {
|
|||
}
|
||||
|
||||
enum State {
|
||||
Connected(window_clipboard::Clipboard),
|
||||
Connected {
|
||||
clipboard: window_clipboard::Clipboard,
|
||||
// Held until drop to satisfy the safety invariants of
|
||||
// `window_clipboard::Clipboard`.
|
||||
//
|
||||
// Note that the field ordering is load-bearing.
|
||||
#[allow(dead_code)]
|
||||
window: Arc<Window>,
|
||||
},
|
||||
Unavailable,
|
||||
}
|
||||
|
||||
impl Clipboard {
|
||||
/// Creates a new [`Clipboard`] for the given window.
|
||||
pub fn connect(window: &winit::window::Window) -> Clipboard {
|
||||
pub fn connect(window: Arc<Window>) -> Clipboard {
|
||||
// SAFETY: The window handle will stay alive throughout the entire
|
||||
// lifetime of the `window_clipboard::Clipboard` because we hold
|
||||
// the `Arc<Window>` together with `State`, and enum variant fields
|
||||
// get dropped in declaration order.
|
||||
#[allow(unsafe_code)]
|
||||
let state = unsafe { window_clipboard::Clipboard::connect(window) }
|
||||
.ok()
|
||||
.map(State::Connected)
|
||||
.unwrap_or(State::Unavailable);
|
||||
let clipboard =
|
||||
unsafe { window_clipboard::Clipboard::connect(&window) };
|
||||
|
||||
let state = match clipboard {
|
||||
Ok(clipboard) => State::Connected { clipboard, window },
|
||||
Err(_) => State::Unavailable,
|
||||
};
|
||||
|
||||
Clipboard { state }
|
||||
}
|
||||
|
|
@ -37,7 +54,7 @@ impl Clipboard {
|
|||
/// Reads the current content of the [`Clipboard`] as text.
|
||||
pub fn read(&self, kind: Kind) -> Option<String> {
|
||||
match &self.state {
|
||||
State::Connected(clipboard) => match kind {
|
||||
State::Connected { clipboard, .. } => match kind {
|
||||
Kind::Standard => clipboard.read().ok(),
|
||||
Kind::Primary => clipboard.read_primary().and_then(Result::ok),
|
||||
},
|
||||
|
|
@ -48,7 +65,7 @@ impl Clipboard {
|
|||
/// Writes the given text contents to the [`Clipboard`].
|
||||
pub fn write(&mut self, kind: Kind, contents: String) {
|
||||
match &mut self.state {
|
||||
State::Connected(clipboard) => {
|
||||
State::Connected { clipboard, .. } => {
|
||||
let result = match kind {
|
||||
Kind::Standard => clipboard.write(contents),
|
||||
Kind::Primary => {
|
||||
|
|
@ -66,6 +83,14 @@ impl Clipboard {
|
|||
State::Unavailable => {}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the identifier of the window used to create the [`Clipboard`], if any.
|
||||
pub fn window_id(&self) -> Option<WindowId> {
|
||||
match &self.state {
|
||||
State::Connected { window, .. } => Some(window.id()),
|
||||
State::Unavailable => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::core::Clipboard for Clipboard {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
//! Convert [`winit`] types into [`iced_runtime`] types, and viceversa.
|
||||
//!
|
||||
//! [`winit`]: https://github.com/rust-windowing/winit
|
||||
//! [`iced_runtime`]: https://github.com/iced-rs/iced/tree/0.12/runtime
|
||||
//! [`iced_runtime`]: https://github.com/iced-rs/iced/tree/0.13/runtime
|
||||
use crate::core::input_method;
|
||||
use crate::core::keyboard;
|
||||
use crate::core::mouse;
|
||||
use crate::core::touch;
|
||||
|
|
@ -23,6 +24,12 @@ pub fn window_attributes(
|
|||
width: settings.size.width,
|
||||
height: settings.size.height,
|
||||
})
|
||||
.with_maximized(settings.maximized)
|
||||
.with_fullscreen(
|
||||
settings
|
||||
.fullscreen
|
||||
.then_some(winit::window::Fullscreen::Borderless(None)),
|
||||
)
|
||||
.with_resizable(settings.resizable)
|
||||
.with_enabled_buttons(if settings.resizable {
|
||||
winit::window::WindowButtons::all()
|
||||
|
|
@ -73,16 +80,16 @@ pub fn window_attributes(
|
|||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
use winit::platform::windows::WindowAttributesExtWindows;
|
||||
#[allow(unsafe_code)]
|
||||
unsafe {
|
||||
attributes = attributes
|
||||
.with_parent_window(settings.platform_specific.parent);
|
||||
}
|
||||
|
||||
attributes = attributes
|
||||
.with_drag_and_drop(settings.platform_specific.drag_and_drop);
|
||||
|
||||
attributes = attributes
|
||||
.with_skip_taskbar(settings.platform_specific.skip_taskbar);
|
||||
|
||||
attributes = attributes.with_undecorated_shadow(
|
||||
settings.platform_specific.undecorated_shadow,
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
|
|
@ -105,10 +112,14 @@ pub fn window_attributes(
|
|||
{
|
||||
use winit::platform::x11::WindowAttributesExtX11;
|
||||
|
||||
attributes = attributes.with_name(
|
||||
&settings.platform_specific.application_id,
|
||||
&settings.platform_specific.application_id,
|
||||
);
|
||||
attributes = attributes
|
||||
.with_override_redirect(
|
||||
settings.platform_specific.override_redirect,
|
||||
)
|
||||
.with_name(
|
||||
&settings.platform_specific.application_id,
|
||||
&settings.platform_specific.application_id,
|
||||
);
|
||||
}
|
||||
#[cfg(feature = "wayland")]
|
||||
{
|
||||
|
|
@ -126,27 +137,24 @@ pub fn window_attributes(
|
|||
|
||||
/// Converts a winit window event into an iced event.
|
||||
pub fn window_event(
|
||||
id: window::Id,
|
||||
event: winit::event::WindowEvent,
|
||||
scale_factor: f64,
|
||||
modifiers: winit::keyboard::ModifiersState,
|
||||
) -> Option<Event> {
|
||||
use winit::event::Ime;
|
||||
use winit::event::WindowEvent;
|
||||
|
||||
match event {
|
||||
WindowEvent::Resized(new_size) => {
|
||||
let logical_size = new_size.to_logical(scale_factor);
|
||||
|
||||
Some(Event::Window(
|
||||
id,
|
||||
window::Event::Resized {
|
||||
width: logical_size.width,
|
||||
height: logical_size.height,
|
||||
},
|
||||
))
|
||||
Some(Event::Window(window::Event::Resized(Size {
|
||||
width: logical_size.width,
|
||||
height: logical_size.height,
|
||||
})))
|
||||
}
|
||||
WindowEvent::CloseRequested => {
|
||||
Some(Event::Window(id, window::Event::CloseRequested))
|
||||
Some(Event::Window(window::Event::CloseRequested))
|
||||
}
|
||||
WindowEvent::CursorMoved { position, .. } => {
|
||||
let position = position.to_logical::<f64>(scale_factor);
|
||||
|
|
@ -191,8 +199,10 @@ pub fn window_event(
|
|||
}))
|
||||
}
|
||||
},
|
||||
// Ignore keyboard presses/releases during window focus/unfocus
|
||||
WindowEvent::KeyboardInput { is_synthetic, .. } if is_synthetic => None,
|
||||
WindowEvent::KeyboardInput { event, .. } => Some(Event::Keyboard({
|
||||
let logical_key = {
|
||||
let key = {
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
{
|
||||
use winit::platform::modifier_supplement::KeyEventExtModifierSupplement;
|
||||
|
|
@ -202,7 +212,7 @@ pub fn window_event(
|
|||
#[cfg(target_arch = "wasm32")]
|
||||
{
|
||||
// TODO: Fix inconsistent API on Wasm
|
||||
event.logical_key
|
||||
event.logical_key.clone()
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -223,9 +233,16 @@ pub fn window_event(
|
|||
}.filter(|text| !text.as_str().chars().any(is_private_use));
|
||||
|
||||
let winit::event::KeyEvent {
|
||||
state, location, ..
|
||||
state,
|
||||
location,
|
||||
logical_key,
|
||||
physical_key,
|
||||
..
|
||||
} = event;
|
||||
let key = key(logical_key);
|
||||
|
||||
let key = self::key(key);
|
||||
let modified_key = self::key(logical_key);
|
||||
let physical_key = self::physical_key(physical_key);
|
||||
let modifiers = self::modifiers(modifiers);
|
||||
|
||||
let location = match location {
|
||||
|
|
@ -245,6 +262,8 @@ pub fn window_event(
|
|||
winit::event::ElementState::Pressed => {
|
||||
keyboard::Event::KeyPressed {
|
||||
key,
|
||||
modified_key,
|
||||
physical_key,
|
||||
modifiers,
|
||||
location,
|
||||
text,
|
||||
|
|
@ -253,6 +272,8 @@ pub fn window_event(
|
|||
winit::event::ElementState::Released => {
|
||||
keyboard::Event::KeyReleased {
|
||||
key,
|
||||
modified_key,
|
||||
physical_key,
|
||||
modifiers,
|
||||
location,
|
||||
}
|
||||
|
|
@ -264,22 +285,28 @@ pub fn window_event(
|
|||
self::modifiers(new_modifiers.state()),
|
||||
)))
|
||||
}
|
||||
WindowEvent::Focused(focused) => Some(Event::Window(
|
||||
id,
|
||||
if focused {
|
||||
window::Event::Focused
|
||||
} else {
|
||||
window::Event::Unfocused
|
||||
},
|
||||
)),
|
||||
WindowEvent::Ime(event) => Some(Event::InputMethod(match event {
|
||||
Ime::Enabled => input_method::Event::Opened,
|
||||
Ime::Preedit(content, size) => input_method::Event::Preedit(
|
||||
content,
|
||||
size.map(|(start, end)| (start..end)),
|
||||
),
|
||||
Ime::Commit(content) => input_method::Event::Commit(content),
|
||||
Ime::Disabled => input_method::Event::Closed,
|
||||
})),
|
||||
WindowEvent::Focused(focused) => Some(Event::Window(if focused {
|
||||
window::Event::Focused
|
||||
} else {
|
||||
window::Event::Unfocused
|
||||
})),
|
||||
WindowEvent::HoveredFile(path) => {
|
||||
Some(Event::Window(id, window::Event::FileHovered(path.clone())))
|
||||
Some(Event::Window(window::Event::FileHovered(path.clone())))
|
||||
}
|
||||
WindowEvent::DroppedFile(path) => {
|
||||
Some(Event::Window(id, window::Event::FileDropped(path.clone())))
|
||||
Some(Event::Window(window::Event::FileDropped(path.clone())))
|
||||
}
|
||||
WindowEvent::HoveredFileCancelled => {
|
||||
Some(Event::Window(id, window::Event::FilesHoveredLeft))
|
||||
Some(Event::Window(window::Event::FilesHoveredLeft))
|
||||
}
|
||||
WindowEvent::Touch(touch) => {
|
||||
Some(Event::Touch(touch_event(touch, scale_factor)))
|
||||
|
|
@ -288,7 +315,7 @@ pub fn window_event(
|
|||
let winit::dpi::LogicalPosition { x, y } =
|
||||
position.to_logical(scale_factor);
|
||||
|
||||
Some(Event::Window(id, window::Event::Moved { x, y }))
|
||||
Some(Event::Window(window::Event::Moved(Point::new(x, y))))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
|
|
@ -434,8 +461,19 @@ pub fn mouse_interaction(
|
|||
winit::window::CursorIcon::EwResize
|
||||
}
|
||||
Interaction::ResizingVertically => winit::window::CursorIcon::NsResize,
|
||||
Interaction::ResizingDiagonallyUp => {
|
||||
winit::window::CursorIcon::NeswResize
|
||||
}
|
||||
Interaction::ResizingDiagonallyDown => {
|
||||
winit::window::CursorIcon::NwseResize
|
||||
}
|
||||
Interaction::NotAllowed => winit::window::CursorIcon::NotAllowed,
|
||||
Interaction::ZoomIn => winit::window::CursorIcon::ZoomIn,
|
||||
Interaction::ZoomOut => winit::window::CursorIcon::ZoomOut,
|
||||
Interaction::Cell => winit::window::CursorIcon::Cell,
|
||||
Interaction::Move => winit::window::CursorIcon::Move,
|
||||
Interaction::Copy => winit::window::CursorIcon::Copy,
|
||||
Interaction::Help => winit::window::CursorIcon::Help,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -513,7 +551,7 @@ pub fn touch_event(
|
|||
}
|
||||
}
|
||||
|
||||
/// Converts a `VirtualKeyCode` from [`winit`] to an [`iced`] key code.
|
||||
/// Converts a `Key` from [`winit`] to an [`iced`] key.
|
||||
///
|
||||
/// [`winit`]: https://github.com/rust-windowing/winit
|
||||
/// [`iced`]: https://github.com/iced-rs/iced/tree/0.12
|
||||
|
|
@ -842,7 +880,258 @@ pub fn key(key: winit::keyboard::Key) -> keyboard::Key {
|
|||
}
|
||||
}
|
||||
|
||||
/// Converts some [`UserAttention`] into it's `winit` counterpart.
|
||||
/// Converts a `PhysicalKey` from [`winit`] to an [`iced`] physical key.
|
||||
///
|
||||
/// [`winit`]: https://github.com/rust-windowing/winit
|
||||
/// [`iced`]: https://github.com/iced-rs/iced/tree/0.12
|
||||
pub fn physical_key(
|
||||
physical_key: winit::keyboard::PhysicalKey,
|
||||
) -> keyboard::key::Physical {
|
||||
match physical_key {
|
||||
winit::keyboard::PhysicalKey::Code(code) => key_code(code)
|
||||
.map(keyboard::key::Physical::Code)
|
||||
.unwrap_or(keyboard::key::Physical::Unidentified(
|
||||
keyboard::key::NativeCode::Unidentified,
|
||||
)),
|
||||
winit::keyboard::PhysicalKey::Unidentified(code) => {
|
||||
keyboard::key::Physical::Unidentified(native_key_code(code))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts a `KeyCode` from [`winit`] to an [`iced`] key code.
|
||||
///
|
||||
/// [`winit`]: https://github.com/rust-windowing/winit
|
||||
/// [`iced`]: https://github.com/iced-rs/iced/tree/0.12
|
||||
pub fn key_code(
|
||||
key_code: winit::keyboard::KeyCode,
|
||||
) -> Option<keyboard::key::Code> {
|
||||
use winit::keyboard::KeyCode;
|
||||
|
||||
Some(match key_code {
|
||||
KeyCode::Backquote => keyboard::key::Code::Backquote,
|
||||
KeyCode::Backslash => keyboard::key::Code::Backslash,
|
||||
KeyCode::BracketLeft => keyboard::key::Code::BracketLeft,
|
||||
KeyCode::BracketRight => keyboard::key::Code::BracketRight,
|
||||
KeyCode::Comma => keyboard::key::Code::Comma,
|
||||
KeyCode::Digit0 => keyboard::key::Code::Digit0,
|
||||
KeyCode::Digit1 => keyboard::key::Code::Digit1,
|
||||
KeyCode::Digit2 => keyboard::key::Code::Digit2,
|
||||
KeyCode::Digit3 => keyboard::key::Code::Digit3,
|
||||
KeyCode::Digit4 => keyboard::key::Code::Digit4,
|
||||
KeyCode::Digit5 => keyboard::key::Code::Digit5,
|
||||
KeyCode::Digit6 => keyboard::key::Code::Digit6,
|
||||
KeyCode::Digit7 => keyboard::key::Code::Digit7,
|
||||
KeyCode::Digit8 => keyboard::key::Code::Digit8,
|
||||
KeyCode::Digit9 => keyboard::key::Code::Digit9,
|
||||
KeyCode::Equal => keyboard::key::Code::Equal,
|
||||
KeyCode::IntlBackslash => keyboard::key::Code::IntlBackslash,
|
||||
KeyCode::IntlRo => keyboard::key::Code::IntlRo,
|
||||
KeyCode::IntlYen => keyboard::key::Code::IntlYen,
|
||||
KeyCode::KeyA => keyboard::key::Code::KeyA,
|
||||
KeyCode::KeyB => keyboard::key::Code::KeyB,
|
||||
KeyCode::KeyC => keyboard::key::Code::KeyC,
|
||||
KeyCode::KeyD => keyboard::key::Code::KeyD,
|
||||
KeyCode::KeyE => keyboard::key::Code::KeyE,
|
||||
KeyCode::KeyF => keyboard::key::Code::KeyF,
|
||||
KeyCode::KeyG => keyboard::key::Code::KeyG,
|
||||
KeyCode::KeyH => keyboard::key::Code::KeyH,
|
||||
KeyCode::KeyI => keyboard::key::Code::KeyI,
|
||||
KeyCode::KeyJ => keyboard::key::Code::KeyJ,
|
||||
KeyCode::KeyK => keyboard::key::Code::KeyK,
|
||||
KeyCode::KeyL => keyboard::key::Code::KeyL,
|
||||
KeyCode::KeyM => keyboard::key::Code::KeyM,
|
||||
KeyCode::KeyN => keyboard::key::Code::KeyN,
|
||||
KeyCode::KeyO => keyboard::key::Code::KeyO,
|
||||
KeyCode::KeyP => keyboard::key::Code::KeyP,
|
||||
KeyCode::KeyQ => keyboard::key::Code::KeyQ,
|
||||
KeyCode::KeyR => keyboard::key::Code::KeyR,
|
||||
KeyCode::KeyS => keyboard::key::Code::KeyS,
|
||||
KeyCode::KeyT => keyboard::key::Code::KeyT,
|
||||
KeyCode::KeyU => keyboard::key::Code::KeyU,
|
||||
KeyCode::KeyV => keyboard::key::Code::KeyV,
|
||||
KeyCode::KeyW => keyboard::key::Code::KeyW,
|
||||
KeyCode::KeyX => keyboard::key::Code::KeyX,
|
||||
KeyCode::KeyY => keyboard::key::Code::KeyY,
|
||||
KeyCode::KeyZ => keyboard::key::Code::KeyZ,
|
||||
KeyCode::Minus => keyboard::key::Code::Minus,
|
||||
KeyCode::Period => keyboard::key::Code::Period,
|
||||
KeyCode::Quote => keyboard::key::Code::Quote,
|
||||
KeyCode::Semicolon => keyboard::key::Code::Semicolon,
|
||||
KeyCode::Slash => keyboard::key::Code::Slash,
|
||||
KeyCode::AltLeft => keyboard::key::Code::AltLeft,
|
||||
KeyCode::AltRight => keyboard::key::Code::AltRight,
|
||||
KeyCode::Backspace => keyboard::key::Code::Backspace,
|
||||
KeyCode::CapsLock => keyboard::key::Code::CapsLock,
|
||||
KeyCode::ContextMenu => keyboard::key::Code::ContextMenu,
|
||||
KeyCode::ControlLeft => keyboard::key::Code::ControlLeft,
|
||||
KeyCode::ControlRight => keyboard::key::Code::ControlRight,
|
||||
KeyCode::Enter => keyboard::key::Code::Enter,
|
||||
KeyCode::SuperLeft => keyboard::key::Code::SuperLeft,
|
||||
KeyCode::SuperRight => keyboard::key::Code::SuperRight,
|
||||
KeyCode::ShiftLeft => keyboard::key::Code::ShiftLeft,
|
||||
KeyCode::ShiftRight => keyboard::key::Code::ShiftRight,
|
||||
KeyCode::Space => keyboard::key::Code::Space,
|
||||
KeyCode::Tab => keyboard::key::Code::Tab,
|
||||
KeyCode::Convert => keyboard::key::Code::Convert,
|
||||
KeyCode::KanaMode => keyboard::key::Code::KanaMode,
|
||||
KeyCode::Lang1 => keyboard::key::Code::Lang1,
|
||||
KeyCode::Lang2 => keyboard::key::Code::Lang2,
|
||||
KeyCode::Lang3 => keyboard::key::Code::Lang3,
|
||||
KeyCode::Lang4 => keyboard::key::Code::Lang4,
|
||||
KeyCode::Lang5 => keyboard::key::Code::Lang5,
|
||||
KeyCode::NonConvert => keyboard::key::Code::NonConvert,
|
||||
KeyCode::Delete => keyboard::key::Code::Delete,
|
||||
KeyCode::End => keyboard::key::Code::End,
|
||||
KeyCode::Help => keyboard::key::Code::Help,
|
||||
KeyCode::Home => keyboard::key::Code::Home,
|
||||
KeyCode::Insert => keyboard::key::Code::Insert,
|
||||
KeyCode::PageDown => keyboard::key::Code::PageDown,
|
||||
KeyCode::PageUp => keyboard::key::Code::PageUp,
|
||||
KeyCode::ArrowDown => keyboard::key::Code::ArrowDown,
|
||||
KeyCode::ArrowLeft => keyboard::key::Code::ArrowLeft,
|
||||
KeyCode::ArrowRight => keyboard::key::Code::ArrowRight,
|
||||
KeyCode::ArrowUp => keyboard::key::Code::ArrowUp,
|
||||
KeyCode::NumLock => keyboard::key::Code::NumLock,
|
||||
KeyCode::Numpad0 => keyboard::key::Code::Numpad0,
|
||||
KeyCode::Numpad1 => keyboard::key::Code::Numpad1,
|
||||
KeyCode::Numpad2 => keyboard::key::Code::Numpad2,
|
||||
KeyCode::Numpad3 => keyboard::key::Code::Numpad3,
|
||||
KeyCode::Numpad4 => keyboard::key::Code::Numpad4,
|
||||
KeyCode::Numpad5 => keyboard::key::Code::Numpad5,
|
||||
KeyCode::Numpad6 => keyboard::key::Code::Numpad6,
|
||||
KeyCode::Numpad7 => keyboard::key::Code::Numpad7,
|
||||
KeyCode::Numpad8 => keyboard::key::Code::Numpad8,
|
||||
KeyCode::Numpad9 => keyboard::key::Code::Numpad9,
|
||||
KeyCode::NumpadAdd => keyboard::key::Code::NumpadAdd,
|
||||
KeyCode::NumpadBackspace => keyboard::key::Code::NumpadBackspace,
|
||||
KeyCode::NumpadClear => keyboard::key::Code::NumpadClear,
|
||||
KeyCode::NumpadClearEntry => keyboard::key::Code::NumpadClearEntry,
|
||||
KeyCode::NumpadComma => keyboard::key::Code::NumpadComma,
|
||||
KeyCode::NumpadDecimal => keyboard::key::Code::NumpadDecimal,
|
||||
KeyCode::NumpadDivide => keyboard::key::Code::NumpadDivide,
|
||||
KeyCode::NumpadEnter => keyboard::key::Code::NumpadEnter,
|
||||
KeyCode::NumpadEqual => keyboard::key::Code::NumpadEqual,
|
||||
KeyCode::NumpadHash => keyboard::key::Code::NumpadHash,
|
||||
KeyCode::NumpadMemoryAdd => keyboard::key::Code::NumpadMemoryAdd,
|
||||
KeyCode::NumpadMemoryClear => keyboard::key::Code::NumpadMemoryClear,
|
||||
KeyCode::NumpadMemoryRecall => keyboard::key::Code::NumpadMemoryRecall,
|
||||
KeyCode::NumpadMemoryStore => keyboard::key::Code::NumpadMemoryStore,
|
||||
KeyCode::NumpadMemorySubtract => {
|
||||
keyboard::key::Code::NumpadMemorySubtract
|
||||
}
|
||||
KeyCode::NumpadMultiply => keyboard::key::Code::NumpadMultiply,
|
||||
KeyCode::NumpadParenLeft => keyboard::key::Code::NumpadParenLeft,
|
||||
KeyCode::NumpadParenRight => keyboard::key::Code::NumpadParenRight,
|
||||
KeyCode::NumpadStar => keyboard::key::Code::NumpadStar,
|
||||
KeyCode::NumpadSubtract => keyboard::key::Code::NumpadSubtract,
|
||||
KeyCode::Escape => keyboard::key::Code::Escape,
|
||||
KeyCode::Fn => keyboard::key::Code::Fn,
|
||||
KeyCode::FnLock => keyboard::key::Code::FnLock,
|
||||
KeyCode::PrintScreen => keyboard::key::Code::PrintScreen,
|
||||
KeyCode::ScrollLock => keyboard::key::Code::ScrollLock,
|
||||
KeyCode::Pause => keyboard::key::Code::Pause,
|
||||
KeyCode::BrowserBack => keyboard::key::Code::BrowserBack,
|
||||
KeyCode::BrowserFavorites => keyboard::key::Code::BrowserFavorites,
|
||||
KeyCode::BrowserForward => keyboard::key::Code::BrowserForward,
|
||||
KeyCode::BrowserHome => keyboard::key::Code::BrowserHome,
|
||||
KeyCode::BrowserRefresh => keyboard::key::Code::BrowserRefresh,
|
||||
KeyCode::BrowserSearch => keyboard::key::Code::BrowserSearch,
|
||||
KeyCode::BrowserStop => keyboard::key::Code::BrowserStop,
|
||||
KeyCode::Eject => keyboard::key::Code::Eject,
|
||||
KeyCode::LaunchApp1 => keyboard::key::Code::LaunchApp1,
|
||||
KeyCode::LaunchApp2 => keyboard::key::Code::LaunchApp2,
|
||||
KeyCode::LaunchMail => keyboard::key::Code::LaunchMail,
|
||||
KeyCode::MediaPlayPause => keyboard::key::Code::MediaPlayPause,
|
||||
KeyCode::MediaSelect => keyboard::key::Code::MediaSelect,
|
||||
KeyCode::MediaStop => keyboard::key::Code::MediaStop,
|
||||
KeyCode::MediaTrackNext => keyboard::key::Code::MediaTrackNext,
|
||||
KeyCode::MediaTrackPrevious => keyboard::key::Code::MediaTrackPrevious,
|
||||
KeyCode::Power => keyboard::key::Code::Power,
|
||||
KeyCode::Sleep => keyboard::key::Code::Sleep,
|
||||
KeyCode::AudioVolumeDown => keyboard::key::Code::AudioVolumeDown,
|
||||
KeyCode::AudioVolumeMute => keyboard::key::Code::AudioVolumeMute,
|
||||
KeyCode::AudioVolumeUp => keyboard::key::Code::AudioVolumeUp,
|
||||
KeyCode::WakeUp => keyboard::key::Code::WakeUp,
|
||||
KeyCode::Meta => keyboard::key::Code::Meta,
|
||||
KeyCode::Hyper => keyboard::key::Code::Hyper,
|
||||
KeyCode::Turbo => keyboard::key::Code::Turbo,
|
||||
KeyCode::Abort => keyboard::key::Code::Abort,
|
||||
KeyCode::Resume => keyboard::key::Code::Resume,
|
||||
KeyCode::Suspend => keyboard::key::Code::Suspend,
|
||||
KeyCode::Again => keyboard::key::Code::Again,
|
||||
KeyCode::Copy => keyboard::key::Code::Copy,
|
||||
KeyCode::Cut => keyboard::key::Code::Cut,
|
||||
KeyCode::Find => keyboard::key::Code::Find,
|
||||
KeyCode::Open => keyboard::key::Code::Open,
|
||||
KeyCode::Paste => keyboard::key::Code::Paste,
|
||||
KeyCode::Props => keyboard::key::Code::Props,
|
||||
KeyCode::Select => keyboard::key::Code::Select,
|
||||
KeyCode::Undo => keyboard::key::Code::Undo,
|
||||
KeyCode::Hiragana => keyboard::key::Code::Hiragana,
|
||||
KeyCode::Katakana => keyboard::key::Code::Katakana,
|
||||
KeyCode::F1 => keyboard::key::Code::F1,
|
||||
KeyCode::F2 => keyboard::key::Code::F2,
|
||||
KeyCode::F3 => keyboard::key::Code::F3,
|
||||
KeyCode::F4 => keyboard::key::Code::F4,
|
||||
KeyCode::F5 => keyboard::key::Code::F5,
|
||||
KeyCode::F6 => keyboard::key::Code::F6,
|
||||
KeyCode::F7 => keyboard::key::Code::F7,
|
||||
KeyCode::F8 => keyboard::key::Code::F8,
|
||||
KeyCode::F9 => keyboard::key::Code::F9,
|
||||
KeyCode::F10 => keyboard::key::Code::F10,
|
||||
KeyCode::F11 => keyboard::key::Code::F11,
|
||||
KeyCode::F12 => keyboard::key::Code::F12,
|
||||
KeyCode::F13 => keyboard::key::Code::F13,
|
||||
KeyCode::F14 => keyboard::key::Code::F14,
|
||||
KeyCode::F15 => keyboard::key::Code::F15,
|
||||
KeyCode::F16 => keyboard::key::Code::F16,
|
||||
KeyCode::F17 => keyboard::key::Code::F17,
|
||||
KeyCode::F18 => keyboard::key::Code::F18,
|
||||
KeyCode::F19 => keyboard::key::Code::F19,
|
||||
KeyCode::F20 => keyboard::key::Code::F20,
|
||||
KeyCode::F21 => keyboard::key::Code::F21,
|
||||
KeyCode::F22 => keyboard::key::Code::F22,
|
||||
KeyCode::F23 => keyboard::key::Code::F23,
|
||||
KeyCode::F24 => keyboard::key::Code::F24,
|
||||
KeyCode::F25 => keyboard::key::Code::F25,
|
||||
KeyCode::F26 => keyboard::key::Code::F26,
|
||||
KeyCode::F27 => keyboard::key::Code::F27,
|
||||
KeyCode::F28 => keyboard::key::Code::F28,
|
||||
KeyCode::F29 => keyboard::key::Code::F29,
|
||||
KeyCode::F30 => keyboard::key::Code::F30,
|
||||
KeyCode::F31 => keyboard::key::Code::F31,
|
||||
KeyCode::F32 => keyboard::key::Code::F32,
|
||||
KeyCode::F33 => keyboard::key::Code::F33,
|
||||
KeyCode::F34 => keyboard::key::Code::F34,
|
||||
KeyCode::F35 => keyboard::key::Code::F35,
|
||||
_ => None?,
|
||||
})
|
||||
}
|
||||
|
||||
/// Converts a `NativeKeyCode` from [`winit`] to an [`iced`] native key code.
|
||||
///
|
||||
/// [`winit`]: https://github.com/rust-windowing/winit
|
||||
/// [`iced`]: https://github.com/iced-rs/iced/tree/0.12
|
||||
pub fn native_key_code(
|
||||
native_key_code: winit::keyboard::NativeKeyCode,
|
||||
) -> keyboard::key::NativeCode {
|
||||
use winit::keyboard::NativeKeyCode;
|
||||
|
||||
match native_key_code {
|
||||
NativeKeyCode::Unidentified => keyboard::key::NativeCode::Unidentified,
|
||||
NativeKeyCode::Android(code) => {
|
||||
keyboard::key::NativeCode::Android(code)
|
||||
}
|
||||
NativeKeyCode::MacOS(code) => keyboard::key::NativeCode::MacOS(code),
|
||||
NativeKeyCode::Windows(code) => {
|
||||
keyboard::key::NativeCode::Windows(code)
|
||||
}
|
||||
NativeKeyCode::Xkb(code) => keyboard::key::NativeCode::Xkb(code),
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts some [`UserAttention`] into its `winit` counterpart.
|
||||
///
|
||||
/// [`UserAttention`]: window::UserAttention
|
||||
pub fn user_attention(
|
||||
|
|
@ -858,7 +1147,31 @@ pub fn user_attention(
|
|||
}
|
||||
}
|
||||
|
||||
/// Converts some [`window::Icon`] into it's `winit` counterpart.
|
||||
/// Converts some [`window::Direction`] into a [`winit::window::ResizeDirection`].
|
||||
pub fn resize_direction(
|
||||
resize_direction: window::Direction,
|
||||
) -> winit::window::ResizeDirection {
|
||||
match resize_direction {
|
||||
window::Direction::North => winit::window::ResizeDirection::North,
|
||||
window::Direction::South => winit::window::ResizeDirection::South,
|
||||
window::Direction::East => winit::window::ResizeDirection::East,
|
||||
window::Direction::West => winit::window::ResizeDirection::West,
|
||||
window::Direction::NorthEast => {
|
||||
winit::window::ResizeDirection::NorthEast
|
||||
}
|
||||
window::Direction::NorthWest => {
|
||||
winit::window::ResizeDirection::NorthWest
|
||||
}
|
||||
window::Direction::SouthEast => {
|
||||
winit::window::ResizeDirection::SouthEast
|
||||
}
|
||||
window::Direction::SouthWest => {
|
||||
winit::window::ResizeDirection::SouthWest
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts some [`window::Icon`] into its `winit` counterpart.
|
||||
///
|
||||
/// Returns `None` if there is an error during the conversion.
|
||||
pub fn icon(icon: window::Icon) -> Option<winit::window::Icon> {
|
||||
|
|
@ -867,6 +1180,17 @@ pub fn icon(icon: window::Icon) -> Option<winit::window::Icon> {
|
|||
winit::window::Icon::from_rgba(pixels, size.width, size.height).ok()
|
||||
}
|
||||
|
||||
/// Convertions some [`input_method::Purpose`] to its `winit` counterpart.
|
||||
pub fn ime_purpose(
|
||||
purpose: input_method::Purpose,
|
||||
) -> winit::window::ImePurpose {
|
||||
match purpose {
|
||||
input_method::Purpose::Normal => winit::window::ImePurpose::Normal,
|
||||
input_method::Purpose::Secure => winit::window::ImePurpose::Password,
|
||||
input_method::Purpose::Terminal => winit::window::ImePurpose::Terminal,
|
||||
}
|
||||
}
|
||||
|
||||
// See: https://en.wikipedia.org/wiki/Private_Use_Areas
|
||||
fn is_private_use(c: char) -> bool {
|
||||
('\u{E000}'..='\u{F8FF}').contains(&c)
|
||||
|
|
|
|||
|
|
@ -5,13 +5,13 @@
|
|||
//! `iced_winit` offers some convenient abstractions on top of [`iced_runtime`]
|
||||
//! to quickstart development when using [`winit`].
|
||||
//!
|
||||
//! It exposes a renderer-agnostic [`Application`] trait that can be implemented
|
||||
//! It exposes a renderer-agnostic [`Program`] trait that can be implemented
|
||||
//! and then run with a simple call. The use of this trait is optional.
|
||||
//!
|
||||
//! Additionally, a [`conversion`] module is available for users that decide to
|
||||
//! implement a custom event loop.
|
||||
//!
|
||||
//! [`iced_runtime`]: https://github.com/iced-rs/iced/tree/0.12/runtime
|
||||
//! [`iced_runtime`]: https://github.com/iced-rs/iced/tree/0.13/runtime
|
||||
//! [`winit`]: https://github.com/rust-windowing/winit
|
||||
//! [`conversion`]: crate::conversion
|
||||
#![doc(
|
||||
|
|
@ -25,24 +25,23 @@ pub use iced_runtime::debug;
|
|||
pub use iced_runtime::futures;
|
||||
pub use winit;
|
||||
|
||||
#[cfg(feature = "multi-window")]
|
||||
pub mod multi_window;
|
||||
|
||||
#[cfg(feature = "application")]
|
||||
pub mod application;
|
||||
pub mod clipboard;
|
||||
pub mod conversion;
|
||||
pub mod settings;
|
||||
|
||||
#[cfg(feature = "program")]
|
||||
pub mod program;
|
||||
|
||||
#[cfg(feature = "system")]
|
||||
pub mod system;
|
||||
|
||||
mod error;
|
||||
mod proxy;
|
||||
|
||||
#[cfg(feature = "application")]
|
||||
pub use application::Application;
|
||||
pub use clipboard::Clipboard;
|
||||
pub use error::Error;
|
||||
pub use proxy::Proxy;
|
||||
pub use settings::Settings;
|
||||
|
||||
#[cfg(feature = "program")]
|
||||
pub use program::Program;
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,157 +0,0 @@
|
|||
use crate::core::mouse;
|
||||
use crate::core::window::Id;
|
||||
use crate::core::{Point, Size};
|
||||
use crate::graphics::Compositor;
|
||||
use crate::multi_window::{Application, DefaultStyle, State};
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use std::sync::Arc;
|
||||
use winit::monitor::MonitorHandle;
|
||||
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct WindowManager<A, C>
|
||||
where
|
||||
A: Application,
|
||||
C: Compositor<Renderer = A::Renderer>,
|
||||
A::Theme: DefaultStyle,
|
||||
{
|
||||
aliases: BTreeMap<winit::window::WindowId, Id>,
|
||||
entries: BTreeMap<Id, Window<A, C>>,
|
||||
}
|
||||
|
||||
impl<A, C> WindowManager<A, C>
|
||||
where
|
||||
A: Application,
|
||||
C: Compositor<Renderer = A::Renderer>,
|
||||
A::Theme: DefaultStyle,
|
||||
{
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
aliases: BTreeMap::new(),
|
||||
entries: BTreeMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert(
|
||||
&mut self,
|
||||
id: Id,
|
||||
window: Arc<winit::window::Window>,
|
||||
application: &A,
|
||||
compositor: &mut C,
|
||||
exit_on_close_request: bool,
|
||||
) -> &mut Window<A, C> {
|
||||
let state = State::new(application, id, &window);
|
||||
let viewport_version = state.viewport_version();
|
||||
let physical_size = state.physical_size();
|
||||
let surface = compositor.create_surface(
|
||||
window.clone(),
|
||||
physical_size.width,
|
||||
physical_size.height,
|
||||
);
|
||||
let renderer = compositor.create_renderer();
|
||||
|
||||
let _ = self.aliases.insert(window.id(), id);
|
||||
|
||||
let _ = self.entries.insert(
|
||||
id,
|
||||
Window {
|
||||
raw: window,
|
||||
state,
|
||||
viewport_version,
|
||||
exit_on_close_request,
|
||||
surface,
|
||||
renderer,
|
||||
mouse_interaction: mouse::Interaction::None,
|
||||
},
|
||||
);
|
||||
|
||||
self.entries
|
||||
.get_mut(&id)
|
||||
.expect("Get window that was just inserted")
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.entries.is_empty()
|
||||
}
|
||||
|
||||
pub fn iter_mut(
|
||||
&mut self,
|
||||
) -> impl Iterator<Item = (Id, &mut Window<A, C>)> {
|
||||
self.entries.iter_mut().map(|(k, v)| (*k, v))
|
||||
}
|
||||
|
||||
pub fn get_mut(&mut self, id: Id) -> Option<&mut Window<A, C>> {
|
||||
self.entries.get_mut(&id)
|
||||
}
|
||||
|
||||
pub fn get_mut_alias(
|
||||
&mut self,
|
||||
id: winit::window::WindowId,
|
||||
) -> Option<(Id, &mut Window<A, C>)> {
|
||||
let id = self.aliases.get(&id).copied()?;
|
||||
|
||||
Some((id, self.get_mut(id)?))
|
||||
}
|
||||
|
||||
pub fn last_monitor(&self) -> Option<MonitorHandle> {
|
||||
self.entries.values().last()?.raw.current_monitor()
|
||||
}
|
||||
|
||||
pub fn remove(&mut self, id: Id) -> Option<Window<A, C>> {
|
||||
let window = self.entries.remove(&id)?;
|
||||
let _ = self.aliases.remove(&window.raw.id());
|
||||
|
||||
Some(window)
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, C> Default for WindowManager<A, C>
|
||||
where
|
||||
A: Application,
|
||||
C: Compositor<Renderer = A::Renderer>,
|
||||
A::Theme: DefaultStyle,
|
||||
{
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct Window<A, C>
|
||||
where
|
||||
A: Application,
|
||||
C: Compositor<Renderer = A::Renderer>,
|
||||
A::Theme: DefaultStyle,
|
||||
{
|
||||
pub raw: Arc<winit::window::Window>,
|
||||
pub state: State<A>,
|
||||
pub viewport_version: u64,
|
||||
pub exit_on_close_request: bool,
|
||||
pub mouse_interaction: mouse::Interaction,
|
||||
pub surface: C::Surface,
|
||||
pub renderer: A::Renderer,
|
||||
}
|
||||
|
||||
impl<A, C> Window<A, C>
|
||||
where
|
||||
A: Application,
|
||||
C: Compositor<Renderer = A::Renderer>,
|
||||
A::Theme: DefaultStyle,
|
||||
{
|
||||
pub fn position(&self) -> Option<Point> {
|
||||
self.raw
|
||||
.inner_position()
|
||||
.ok()
|
||||
.map(|position| position.to_logical(self.raw.scale_factor()))
|
||||
.map(|position| Point {
|
||||
x: position.x,
|
||||
y: position.y,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn size(&self) -> Size {
|
||||
let size = self.raw.inner_size().to_logical(self.raw.scale_factor());
|
||||
|
||||
Size::new(size.width, size.height)
|
||||
}
|
||||
}
|
||||
1579
winit/src/program.rs
Normal file
1579
winit/src/program.rs
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -1,17 +1,18 @@
|
|||
use crate::conversion;
|
||||
use crate::core::{mouse, window};
|
||||
use crate::core::{Color, Size};
|
||||
use crate::core::{mouse, theme, window};
|
||||
use crate::graphics::Viewport;
|
||||
use crate::multi_window::{self, Application};
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use crate::program::Program;
|
||||
|
||||
use winit::event::{Touch, WindowEvent};
|
||||
use winit::window::Window;
|
||||
|
||||
/// The state of a multi-windowed [`Application`].
|
||||
pub struct State<A: Application>
|
||||
use std::fmt::{Debug, Formatter};
|
||||
|
||||
/// The state of a multi-windowed [`Program`].
|
||||
pub struct State<P: Program>
|
||||
where
|
||||
A::Theme: multi_window::DefaultStyle,
|
||||
P::Theme: theme::Base,
|
||||
{
|
||||
title: String,
|
||||
scale_factor: f64,
|
||||
|
|
@ -19,13 +20,13 @@ where
|
|||
viewport_version: u64,
|
||||
cursor_position: Option<winit::dpi::PhysicalPosition<f64>>,
|
||||
modifiers: winit::keyboard::ModifiersState,
|
||||
theme: A::Theme,
|
||||
appearance: multi_window::Appearance,
|
||||
theme: P::Theme,
|
||||
style: theme::Style,
|
||||
}
|
||||
|
||||
impl<A: Application> Debug for State<A>
|
||||
impl<P: Program> Debug for State<P>
|
||||
where
|
||||
A::Theme: multi_window::DefaultStyle,
|
||||
P::Theme: theme::Base,
|
||||
{
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("multi_window::State")
|
||||
|
|
@ -34,25 +35,25 @@ where
|
|||
.field("viewport", &self.viewport)
|
||||
.field("viewport_version", &self.viewport_version)
|
||||
.field("cursor_position", &self.cursor_position)
|
||||
.field("appearance", &self.appearance)
|
||||
.field("style", &self.style)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: Application> State<A>
|
||||
impl<P: Program> State<P>
|
||||
where
|
||||
A::Theme: multi_window::DefaultStyle,
|
||||
P::Theme: theme::Base,
|
||||
{
|
||||
/// Creates a new [`State`] for the provided [`Application`]'s `window`.
|
||||
/// Creates a new [`State`] for the provided [`Program`]'s `window`.
|
||||
pub fn new(
|
||||
application: &A,
|
||||
application: &P,
|
||||
window_id: window::Id,
|
||||
window: &Window,
|
||||
) -> Self {
|
||||
let title = application.title(window_id);
|
||||
let scale_factor = application.scale_factor(window_id);
|
||||
let theme = application.theme(window_id);
|
||||
let appearance = application.style(&theme);
|
||||
let style = application.style(&theme);
|
||||
|
||||
let viewport = {
|
||||
let physical_size = window.inner_size();
|
||||
|
|
@ -71,7 +72,7 @@ where
|
|||
cursor_position: None,
|
||||
modifiers: winit::keyboard::ModifiersState::default(),
|
||||
theme,
|
||||
appearance,
|
||||
style,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -121,18 +122,18 @@ where
|
|||
}
|
||||
|
||||
/// Returns the current theme of the [`State`].
|
||||
pub fn theme(&self) -> &A::Theme {
|
||||
pub fn theme(&self) -> &P::Theme {
|
||||
&self.theme
|
||||
}
|
||||
|
||||
/// Returns the current background [`Color`] of the [`State`].
|
||||
pub fn background_color(&self) -> Color {
|
||||
self.appearance.background_color
|
||||
self.style.background_color
|
||||
}
|
||||
|
||||
/// Returns the current text [`Color`] of the [`State`].
|
||||
pub fn text_color(&self) -> Color {
|
||||
self.appearance.text_color
|
||||
self.style.text_color
|
||||
}
|
||||
|
||||
/// Processes the provided window event and updates the [`State`] accordingly.
|
||||
|
|
@ -177,14 +178,14 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// Synchronizes the [`State`] with its [`Application`] and its respective
|
||||
/// Synchronizes the [`State`] with its [`Program`] and its respective
|
||||
/// window.
|
||||
///
|
||||
/// Normally, an [`Application`] should be synchronized with its [`State`]
|
||||
/// Normally, a [`Program`] should be synchronized with its [`State`]
|
||||
/// and window after calling [`State::update`].
|
||||
pub fn synchronize(
|
||||
&mut self,
|
||||
application: &A,
|
||||
application: &P,
|
||||
window_id: window::Id,
|
||||
window: &Window,
|
||||
) {
|
||||
|
|
@ -216,6 +217,6 @@ where
|
|||
|
||||
// Update theme and appearance
|
||||
self.theme = application.theme(window_id);
|
||||
self.appearance = application.style(&self.theme);
|
||||
self.style = application.style(&self.theme);
|
||||
}
|
||||
}
|
||||
422
winit/src/program/window_manager.rs
Normal file
422
winit/src/program/window_manager.rs
Normal file
|
|
@ -0,0 +1,422 @@
|
|||
use crate::conversion;
|
||||
use crate::core::alignment;
|
||||
use crate::core::input_method;
|
||||
use crate::core::mouse;
|
||||
use crate::core::renderer;
|
||||
use crate::core::text;
|
||||
use crate::core::theme;
|
||||
use crate::core::time::Instant;
|
||||
use crate::core::window::{Id, RedrawRequest};
|
||||
use crate::core::{
|
||||
Color, InputMethod, Padding, Point, Rectangle, Size, Text, Vector,
|
||||
};
|
||||
use crate::graphics::Compositor;
|
||||
use crate::program::{Program, State};
|
||||
|
||||
use winit::dpi::{LogicalPosition, LogicalSize};
|
||||
use winit::monitor::MonitorHandle;
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct WindowManager<P, C>
|
||||
where
|
||||
P: Program,
|
||||
C: Compositor<Renderer = P::Renderer>,
|
||||
P::Theme: theme::Base,
|
||||
{
|
||||
aliases: BTreeMap<winit::window::WindowId, Id>,
|
||||
entries: BTreeMap<Id, Window<P, C>>,
|
||||
}
|
||||
|
||||
impl<P, C> WindowManager<P, C>
|
||||
where
|
||||
P: Program,
|
||||
C: Compositor<Renderer = P::Renderer>,
|
||||
P::Theme: theme::Base,
|
||||
{
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
aliases: BTreeMap::new(),
|
||||
entries: BTreeMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert(
|
||||
&mut self,
|
||||
id: Id,
|
||||
window: Arc<winit::window::Window>,
|
||||
application: &P,
|
||||
compositor: &mut C,
|
||||
exit_on_close_request: bool,
|
||||
) -> &mut Window<P, C> {
|
||||
let state = State::new(application, id, &window);
|
||||
let viewport_version = state.viewport_version();
|
||||
let physical_size = state.physical_size();
|
||||
let surface = compositor.create_surface(
|
||||
window.clone(),
|
||||
physical_size.width,
|
||||
physical_size.height,
|
||||
);
|
||||
let renderer = compositor.create_renderer();
|
||||
|
||||
let _ = self.aliases.insert(window.id(), id);
|
||||
|
||||
let _ = self.entries.insert(
|
||||
id,
|
||||
Window {
|
||||
raw: window,
|
||||
state,
|
||||
viewport_version,
|
||||
exit_on_close_request,
|
||||
surface,
|
||||
renderer,
|
||||
mouse_interaction: mouse::Interaction::None,
|
||||
redraw_at: None,
|
||||
preedit: None,
|
||||
ime_state: None,
|
||||
},
|
||||
);
|
||||
|
||||
self.entries
|
||||
.get_mut(&id)
|
||||
.expect("Get window that was just inserted")
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.entries.is_empty()
|
||||
}
|
||||
|
||||
pub fn is_idle(&self) -> bool {
|
||||
self.entries
|
||||
.values()
|
||||
.all(|window| window.redraw_at.is_none())
|
||||
}
|
||||
|
||||
pub fn redraw_at(&self) -> Option<Instant> {
|
||||
self.entries
|
||||
.values()
|
||||
.filter_map(|window| window.redraw_at)
|
||||
.min()
|
||||
}
|
||||
|
||||
pub fn first(&self) -> Option<&Window<P, C>> {
|
||||
self.entries.first_key_value().map(|(_id, window)| window)
|
||||
}
|
||||
|
||||
pub fn iter_mut(
|
||||
&mut self,
|
||||
) -> impl Iterator<Item = (Id, &mut Window<P, C>)> {
|
||||
self.entries.iter_mut().map(|(k, v)| (*k, v))
|
||||
}
|
||||
|
||||
pub fn get(&self, id: Id) -> Option<&Window<P, C>> {
|
||||
self.entries.get(&id)
|
||||
}
|
||||
|
||||
pub fn get_mut(&mut self, id: Id) -> Option<&mut Window<P, C>> {
|
||||
self.entries.get_mut(&id)
|
||||
}
|
||||
|
||||
pub fn get_mut_alias(
|
||||
&mut self,
|
||||
id: winit::window::WindowId,
|
||||
) -> Option<(Id, &mut Window<P, C>)> {
|
||||
let id = self.aliases.get(&id).copied()?;
|
||||
|
||||
Some((id, self.get_mut(id)?))
|
||||
}
|
||||
|
||||
pub fn last_monitor(&self) -> Option<MonitorHandle> {
|
||||
self.entries.values().last()?.raw.current_monitor()
|
||||
}
|
||||
|
||||
pub fn remove(&mut self, id: Id) -> Option<Window<P, C>> {
|
||||
let window = self.entries.remove(&id)?;
|
||||
let _ = self.aliases.remove(&window.raw.id());
|
||||
|
||||
Some(window)
|
||||
}
|
||||
}
|
||||
|
||||
impl<P, C> Default for WindowManager<P, C>
|
||||
where
|
||||
P: Program,
|
||||
C: Compositor<Renderer = P::Renderer>,
|
||||
P::Theme: theme::Base,
|
||||
{
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct Window<P, C>
|
||||
where
|
||||
P: Program,
|
||||
C: Compositor<Renderer = P::Renderer>,
|
||||
P::Theme: theme::Base,
|
||||
{
|
||||
pub raw: Arc<winit::window::Window>,
|
||||
pub state: State<P>,
|
||||
pub viewport_version: u64,
|
||||
pub exit_on_close_request: bool,
|
||||
pub mouse_interaction: mouse::Interaction,
|
||||
pub surface: C::Surface,
|
||||
pub renderer: P::Renderer,
|
||||
pub redraw_at: Option<Instant>,
|
||||
preedit: Option<Preedit<P::Renderer>>,
|
||||
ime_state: Option<(Point, input_method::Purpose)>,
|
||||
}
|
||||
|
||||
impl<P, C> Window<P, C>
|
||||
where
|
||||
P: Program,
|
||||
C: Compositor<Renderer = P::Renderer>,
|
||||
P::Theme: theme::Base,
|
||||
{
|
||||
pub fn position(&self) -> Option<Point> {
|
||||
self.raw
|
||||
.outer_position()
|
||||
.ok()
|
||||
.map(|position| position.to_logical(self.raw.scale_factor()))
|
||||
.map(|position| Point {
|
||||
x: position.x,
|
||||
y: position.y,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn size(&self) -> Size {
|
||||
let size = self.raw.inner_size().to_logical(self.raw.scale_factor());
|
||||
|
||||
Size::new(size.width, size.height)
|
||||
}
|
||||
|
||||
pub fn request_redraw(&mut self, redraw_request: RedrawRequest) {
|
||||
match redraw_request {
|
||||
RedrawRequest::NextFrame => {
|
||||
self.raw.request_redraw();
|
||||
self.redraw_at = None;
|
||||
}
|
||||
RedrawRequest::At(at) => {
|
||||
self.redraw_at = Some(at);
|
||||
}
|
||||
RedrawRequest::Wait => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn request_input_method(&mut self, input_method: InputMethod) {
|
||||
match input_method {
|
||||
InputMethod::Disabled => {
|
||||
self.disable_ime();
|
||||
}
|
||||
InputMethod::Enabled {
|
||||
position,
|
||||
purpose,
|
||||
preedit,
|
||||
} => {
|
||||
self.enable_ime(position, purpose);
|
||||
|
||||
if let Some(preedit) = preedit {
|
||||
if preedit.content.is_empty() {
|
||||
self.preedit = None;
|
||||
} else {
|
||||
let mut overlay =
|
||||
self.preedit.take().unwrap_or_else(Preedit::new);
|
||||
|
||||
overlay.update(
|
||||
position,
|
||||
&preedit,
|
||||
self.state.background_color(),
|
||||
&self.renderer,
|
||||
);
|
||||
|
||||
self.preedit = Some(overlay);
|
||||
}
|
||||
} else {
|
||||
self.preedit = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw_preedit(&mut self) {
|
||||
if let Some(preedit) = &self.preedit {
|
||||
preedit.draw(
|
||||
&mut self.renderer,
|
||||
self.state.text_color(),
|
||||
self.state.background_color(),
|
||||
&Rectangle::new(
|
||||
Point::ORIGIN,
|
||||
self.state.viewport().logical_size(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn enable_ime(&mut self, position: Point, purpose: input_method::Purpose) {
|
||||
if self.ime_state.is_none() {
|
||||
self.raw.set_ime_allowed(true);
|
||||
}
|
||||
|
||||
if self.ime_state != Some((position, purpose)) {
|
||||
self.raw.set_ime_cursor_area(
|
||||
LogicalPosition::new(position.x, position.y),
|
||||
LogicalSize::new(10, 10), // TODO?
|
||||
);
|
||||
self.raw.set_ime_purpose(conversion::ime_purpose(purpose));
|
||||
|
||||
self.ime_state = Some((position, purpose));
|
||||
}
|
||||
}
|
||||
|
||||
fn disable_ime(&mut self) {
|
||||
if self.ime_state.is_some() {
|
||||
self.raw.set_ime_allowed(false);
|
||||
self.ime_state = None;
|
||||
}
|
||||
|
||||
self.preedit = None;
|
||||
}
|
||||
}
|
||||
|
||||
struct Preedit<Renderer>
|
||||
where
|
||||
Renderer: text::Renderer,
|
||||
{
|
||||
position: Point,
|
||||
content: Renderer::Paragraph,
|
||||
spans: Vec<text::Span<'static, (), Renderer::Font>>,
|
||||
}
|
||||
|
||||
impl<Renderer> Preedit<Renderer>
|
||||
where
|
||||
Renderer: text::Renderer,
|
||||
{
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
position: Point::ORIGIN,
|
||||
spans: Vec::new(),
|
||||
content: Renderer::Paragraph::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn update(
|
||||
&mut self,
|
||||
position: Point,
|
||||
preedit: &input_method::Preedit,
|
||||
background: Color,
|
||||
renderer: &Renderer,
|
||||
) {
|
||||
self.position = position;
|
||||
|
||||
let spans = match &preedit.selection {
|
||||
Some(selection) => {
|
||||
vec![
|
||||
text::Span::new(&preedit.content[..selection.start]),
|
||||
text::Span::new(if selection.start == selection.end {
|
||||
"\u{200A}"
|
||||
} else {
|
||||
&preedit.content[selection.start..selection.end]
|
||||
})
|
||||
.color(background),
|
||||
text::Span::new(&preedit.content[selection.end..]),
|
||||
]
|
||||
}
|
||||
_ => vec![text::Span::new(&preedit.content)],
|
||||
};
|
||||
|
||||
if spans != self.spans.as_slice() {
|
||||
use text::Paragraph as _;
|
||||
|
||||
self.content = Renderer::Paragraph::with_spans(Text {
|
||||
content: &spans,
|
||||
bounds: Size::INFINITY,
|
||||
size: preedit
|
||||
.text_size
|
||||
.unwrap_or_else(|| renderer.default_size()),
|
||||
line_height: text::LineHeight::default(),
|
||||
font: renderer.default_font(),
|
||||
horizontal_alignment: alignment::Horizontal::Left,
|
||||
vertical_alignment: alignment::Vertical::Top,
|
||||
shaping: text::Shaping::Advanced,
|
||||
wrapping: text::Wrapping::None,
|
||||
});
|
||||
|
||||
self.spans.clear();
|
||||
self.spans
|
||||
.extend(spans.into_iter().map(text::Span::to_static));
|
||||
}
|
||||
}
|
||||
|
||||
fn draw(
|
||||
&self,
|
||||
renderer: &mut Renderer,
|
||||
color: Color,
|
||||
background: Color,
|
||||
viewport: &Rectangle,
|
||||
) {
|
||||
use text::Paragraph as _;
|
||||
|
||||
if self.content.min_width() < 1.0 {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut bounds = Rectangle::new(
|
||||
self.position - Vector::new(0.0, self.content.min_height()),
|
||||
self.content.min_bounds(),
|
||||
);
|
||||
|
||||
bounds.x = bounds
|
||||
.x
|
||||
.max(viewport.x)
|
||||
.min(viewport.x + viewport.width - bounds.width);
|
||||
|
||||
bounds.y = bounds
|
||||
.y
|
||||
.max(viewport.y)
|
||||
.min(viewport.y + viewport.height - bounds.height);
|
||||
|
||||
renderer.with_layer(bounds, |renderer| {
|
||||
renderer.fill_quad(
|
||||
renderer::Quad {
|
||||
bounds,
|
||||
..Default::default()
|
||||
},
|
||||
background,
|
||||
);
|
||||
|
||||
renderer.fill_paragraph(
|
||||
&self.content,
|
||||
bounds.position(),
|
||||
color,
|
||||
bounds,
|
||||
);
|
||||
|
||||
const UNDERLINE: f32 = 2.0;
|
||||
|
||||
renderer.fill_quad(
|
||||
renderer::Quad {
|
||||
bounds: bounds.shrink(Padding {
|
||||
top: bounds.height - UNDERLINE,
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
},
|
||||
color,
|
||||
);
|
||||
|
||||
for span_bounds in self.content.span_bounds(1) {
|
||||
renderer.fill_quad(
|
||||
renderer::Quad {
|
||||
bounds: span_bounds
|
||||
+ (bounds.position() - Point::ORIGIN),
|
||||
..Default::default()
|
||||
},
|
||||
color,
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -1,20 +1,21 @@
|
|||
use crate::futures::futures::{
|
||||
Future, Sink, StreamExt,
|
||||
channel::mpsc,
|
||||
select,
|
||||
task::{Context, Poll},
|
||||
Future, Sink, StreamExt,
|
||||
};
|
||||
use crate::runtime::Action;
|
||||
use std::pin::Pin;
|
||||
|
||||
/// An event loop proxy with backpressure that implements `Sink`.
|
||||
#[derive(Debug)]
|
||||
pub struct Proxy<Message: 'static> {
|
||||
raw: winit::event_loop::EventLoopProxy<Message>,
|
||||
sender: mpsc::Sender<Message>,
|
||||
pub struct Proxy<T: 'static> {
|
||||
raw: winit::event_loop::EventLoopProxy<Action<T>>,
|
||||
sender: mpsc::Sender<Action<T>>,
|
||||
notifier: mpsc::Sender<usize>,
|
||||
}
|
||||
|
||||
impl<Message: 'static> Clone for Proxy<Message> {
|
||||
impl<T: 'static> Clone for Proxy<T> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
raw: self.raw.clone(),
|
||||
|
|
@ -24,12 +25,12 @@ impl<Message: 'static> Clone for Proxy<Message> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<Message: 'static> Proxy<Message> {
|
||||
impl<T: 'static> Proxy<T> {
|
||||
const MAX_SIZE: usize = 100;
|
||||
|
||||
/// Creates a new [`Proxy`] from an `EventLoopProxy`.
|
||||
pub fn new(
|
||||
raw: winit::event_loop::EventLoopProxy<Message>,
|
||||
raw: winit::event_loop::EventLoopProxy<Action<T>>,
|
||||
) -> (Self, impl Future<Output = ()>) {
|
||||
let (notifier, mut processed) = mpsc::channel(Self::MAX_SIZE);
|
||||
let (sender, mut receiver) = mpsc::channel(Self::MAX_SIZE);
|
||||
|
|
@ -72,16 +73,27 @@ impl<Message: 'static> Proxy<Message> {
|
|||
)
|
||||
}
|
||||
|
||||
/// Sends a `Message` to the event loop.
|
||||
/// Sends a value to the event loop.
|
||||
///
|
||||
/// Note: This skips the backpressure mechanism with an unbounded
|
||||
/// channel. Use sparingly!
|
||||
pub fn send(&mut self, message: Message)
|
||||
pub fn send(&mut self, value: T)
|
||||
where
|
||||
Message: std::fmt::Debug,
|
||||
T: std::fmt::Debug,
|
||||
{
|
||||
self.send_action(Action::Output(value));
|
||||
}
|
||||
|
||||
/// Sends an action to the event loop.
|
||||
///
|
||||
/// Note: This skips the backpressure mechanism with an unbounded
|
||||
/// channel. Use sparingly!
|
||||
pub fn send_action(&mut self, action: Action<T>)
|
||||
where
|
||||
T: std::fmt::Debug,
|
||||
{
|
||||
self.raw
|
||||
.send_event(message)
|
||||
.send_event(action)
|
||||
.expect("Send message to event loop");
|
||||
}
|
||||
|
||||
|
|
@ -92,7 +104,7 @@ impl<Message: 'static> Proxy<Message> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<Message: 'static> Sink<Message> for Proxy<Message> {
|
||||
impl<T: 'static> Sink<Action<T>> for Proxy<T> {
|
||||
type Error = mpsc::SendError;
|
||||
|
||||
fn poll_ready(
|
||||
|
|
@ -104,9 +116,9 @@ impl<Message: 'static> Sink<Message> for Proxy<Message> {
|
|||
|
||||
fn start_send(
|
||||
mut self: Pin<&mut Self>,
|
||||
message: Message,
|
||||
action: Action<T>,
|
||||
) -> Result<(), Self::Error> {
|
||||
self.sender.start_send(message)
|
||||
self.sender.start_send(action)
|
||||
}
|
||||
|
||||
fn poll_flush(
|
||||
|
|
|
|||
|
|
@ -1,25 +1,26 @@
|
|||
//! Configure your application.
|
||||
use crate::core::window;
|
||||
use crate::core;
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
||||
/// The settings of an application.
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct Settings<Flags> {
|
||||
pub struct Settings {
|
||||
/// The identifier of the application.
|
||||
///
|
||||
/// If provided, this identifier may be used to identify the application or
|
||||
/// communicate with it through the windowing system.
|
||||
pub id: Option<String>,
|
||||
|
||||
/// The [`window::Settings`].
|
||||
pub window: window::Settings,
|
||||
|
||||
/// The data needed to initialize an [`Application`].
|
||||
///
|
||||
/// [`Application`]: crate::Application
|
||||
pub flags: Flags,
|
||||
|
||||
/// The fonts to load on boot.
|
||||
pub fonts: Vec<Cow<'static, [u8]>>,
|
||||
}
|
||||
|
||||
impl From<core::Settings> for Settings {
|
||||
fn from(settings: core::Settings) -> Self {
|
||||
Self {
|
||||
id: settings.id,
|
||||
fonts: settings.fonts,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,13 @@
|
|||
//! Access the native system.
|
||||
use crate::graphics::compositor;
|
||||
use crate::runtime::command::{self, Command};
|
||||
use crate::runtime::system::{Action, Information};
|
||||
use crate::runtime::{self, Task};
|
||||
|
||||
/// Query for available system information.
|
||||
pub fn fetch_information<Message>(
|
||||
f: impl Fn(Information) -> Message + Send + 'static,
|
||||
) -> Command<Message> {
|
||||
Command::single(command::Action::System(Action::QueryInformation(
|
||||
Box::new(f),
|
||||
)))
|
||||
pub fn fetch_information() -> Task<Information> {
|
||||
runtime::task::oneshot(|channel| {
|
||||
runtime::Action::System(Action::QueryInformation(channel))
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn information(
|
||||
|
|
@ -19,7 +17,11 @@ pub(crate) fn information(
|
|||
let mut system = System::new_all();
|
||||
system.refresh_all();
|
||||
|
||||
let cpu = system.global_cpu_info();
|
||||
let cpu_brand = system
|
||||
.cpus()
|
||||
.first()
|
||||
.map(|cpu| cpu.brand().to_string())
|
||||
.unwrap_or_default();
|
||||
|
||||
let memory_used = sysinfo::get_current_pid()
|
||||
.and_then(|pid| system.process(pid).ok_or("Process not found"))
|
||||
|
|
@ -31,7 +33,7 @@ pub(crate) fn information(
|
|||
system_kernel: System::kernel_version(),
|
||||
system_version: System::long_os_version(),
|
||||
system_short_version: System::os_version(),
|
||||
cpu_brand: cpu.brand().into(),
|
||||
cpu_brand,
|
||||
cpu_cores: system.physical_core_count(),
|
||||
memory_total: system.total_memory(),
|
||||
memory_used,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue