platform.rs

  1mod events;
  2mod keystroke;
  3#[cfg(target_os = "macos")]
  4mod mac;
  5#[cfg(any(test, feature = "test"))]
  6mod test;
  7
  8use crate::{
  9    AnyWindowHandle, Bounds, FontFeatures, FontId, FontMetrics, FontStyle, FontWeight, GlyphId,
 10    LineLayout, Pixels, Point, RunStyle, SharedString, Size,
 11};
 12use async_task::Runnable;
 13use futures::channel::oneshot;
 14use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle};
 15use std::{any::Any, fmt::Debug, ops::Range, rc::Rc, sync::Arc};
 16use uuid::Uuid;
 17
 18pub use events::*;
 19pub use keystroke::*;
 20#[cfg(target_os = "macos")]
 21pub use mac::*;
 22#[cfg(any(test, feature = "test"))]
 23pub use test::*;
 24
 25pub trait Platform {
 26    fn dispatcher(&self) -> Arc<dyn PlatformDispatcher>;
 27    fn font_system(&self) -> Arc<dyn PlatformTextSystem>;
 28
 29    fn open_window(
 30        &self,
 31        handle: AnyWindowHandle,
 32        options: WindowOptions,
 33    ) -> Box<dyn PlatformWindow>;
 34}
 35
 36pub trait PlatformScreen: Debug {
 37    fn as_any(&self) -> &dyn Any;
 38    fn bounds(&self) -> Bounds<Pixels>;
 39    fn content_bounds(&self) -> Bounds<Pixels>;
 40    fn display_uuid(&self) -> Option<Uuid>;
 41}
 42
 43pub trait PlatformWindow: HasRawWindowHandle + HasRawDisplayHandle {
 44    fn bounds(&self) -> WindowBounds;
 45    fn content_size(&self) -> Size<Pixels>;
 46    fn scale_factor(&self) -> f32;
 47    fn titlebar_height(&self) -> Pixels;
 48    fn appearance(&self) -> WindowAppearance;
 49    fn screen(&self) -> Rc<dyn PlatformScreen>;
 50    fn mouse_position(&self) -> Point<Pixels>;
 51    fn as_any_mut(&mut self) -> &mut dyn Any;
 52    fn set_input_handler(&mut self, input_handler: Box<dyn InputHandler>);
 53    fn prompt(
 54        &self,
 55        level: WindowPromptLevel,
 56        msg: &str,
 57        answers: &[&str],
 58    ) -> oneshot::Receiver<usize>;
 59    fn activate(&self);
 60    fn set_title(&mut self, title: &str);
 61    fn set_edited(&mut self, edited: bool);
 62    fn show_character_palette(&self);
 63    fn minimize(&self);
 64    fn zoom(&self);
 65    fn toggle_full_screen(&self);
 66    fn on_event(&mut self, callback: Box<dyn FnMut(Event) -> bool>);
 67    fn on_active_status_change(&mut self, callback: Box<dyn FnMut(bool)>);
 68    fn on_resize(&mut self, callback: Box<dyn FnMut()>);
 69    fn on_fullscreen(&mut self, callback: Box<dyn FnMut(bool)>);
 70    fn on_moved(&mut self, callback: Box<dyn FnMut()>);
 71    fn on_should_close(&mut self, callback: Box<dyn FnMut() -> bool>);
 72    fn on_close(&mut self, callback: Box<dyn FnOnce()>);
 73    fn on_appearance_changed(&mut self, callback: Box<dyn FnMut()>);
 74    fn is_topmost_for_position(&self, position: Point<Pixels>) -> bool;
 75}
 76
 77pub trait PlatformDispatcher: Send + Sync {
 78    fn is_main_thread(&self) -> bool;
 79    fn run_on_main_thread(&self, task: Runnable);
 80}
 81
 82pub trait PlatformTextSystem: Send + Sync {
 83    fn add_fonts(&self, fonts: &[Arc<Vec<u8>>]) -> anyhow::Result<()>;
 84    fn all_families(&self) -> Vec<String>;
 85    fn load_family(&self, name: &str, features: &FontFeatures) -> anyhow::Result<Vec<FontId>>;
 86    fn select_font(
 87        &self,
 88        font_ids: &[FontId],
 89        weight: FontWeight,
 90        style: FontStyle,
 91    ) -> anyhow::Result<FontId>;
 92    fn font_metrics(&self, font_id: FontId) -> FontMetrics;
 93    fn typographic_bounds(
 94        &self,
 95        font_id: FontId,
 96        glyph_id: GlyphId,
 97    ) -> anyhow::Result<Bounds<Pixels>>;
 98    fn advance(&self, font_id: FontId, glyph_id: GlyphId) -> anyhow::Result<Point<Pixels>>;
 99    fn glyph_for_char(&self, font_id: FontId, ch: char) -> Option<GlyphId>;
100    fn rasterize_glyph(
101        &self,
102        font_id: FontId,
103        font_size: f32,
104        glyph_id: GlyphId,
105        subpixel_shift: Point<Pixels>,
106        scale_factor: f32,
107        options: RasterizationOptions,
108    ) -> Option<(Bounds<u32>, Vec<u8>)>;
109    fn layout_line(&self, text: &str, font_size: Pixels, runs: &[(usize, RunStyle)]) -> LineLayout;
110    fn wrap_line(
111        &self,
112        text: &str,
113        font_id: FontId,
114        font_size: Pixels,
115        width: Pixels,
116    ) -> Vec<usize>;
117}
118
119pub trait InputHandler {
120    fn selected_text_range(&self) -> Option<Range<usize>>;
121    fn marked_text_range(&self) -> Option<Range<usize>>;
122    fn text_for_range(&self, range_utf16: Range<usize>) -> Option<String>;
123    fn replace_text_in_range(&mut self, replacement_range: Option<Range<usize>>, text: &str);
124    fn replace_and_mark_text_in_range(
125        &mut self,
126        range_utf16: Option<Range<usize>>,
127        new_text: &str,
128        new_selected_range: Option<Range<usize>>,
129    );
130    fn unmark_text(&mut self);
131    fn bounds_for_range(&self, range_utf16: Range<usize>) -> Option<Bounds<f32>>;
132}
133
134#[derive(Copy, Clone, Debug)]
135pub enum RasterizationOptions {
136    Alpha,
137    Bgra,
138}
139
140#[derive(Debug)]
141pub struct WindowOptions {
142    pub bounds: WindowBounds,
143    pub titlebar: Option<TitlebarOptions>,
144    pub center: bool,
145    pub focus: bool,
146    pub show: bool,
147    pub kind: WindowKind,
148    pub is_movable: bool,
149    pub screen: Option<Rc<dyn PlatformScreen>>,
150}
151
152impl Default for WindowOptions {
153    fn default() -> Self {
154        Self {
155            bounds: WindowBounds::default(),
156            titlebar: Some(TitlebarOptions {
157                title: Default::default(),
158                appears_transparent: Default::default(),
159                traffic_light_position: Default::default(),
160            }),
161            center: false,
162            focus: true,
163            show: true,
164            kind: WindowKind::Normal,
165            is_movable: true,
166            screen: None,
167        }
168    }
169}
170
171#[derive(Debug, Default)]
172pub struct TitlebarOptions {
173    pub title: Option<SharedString>,
174    pub appears_transparent: bool,
175    pub traffic_light_position: Option<Point<Pixels>>,
176}
177
178#[derive(Copy, Clone, Debug)]
179pub enum Appearance {
180    Light,
181    VibrantLight,
182    Dark,
183    VibrantDark,
184}
185
186impl Default for Appearance {
187    fn default() -> Self {
188        Self::Light
189    }
190}
191
192#[derive(Copy, Clone, Debug, PartialEq, Eq)]
193pub enum WindowKind {
194    Normal,
195    PopUp,
196}
197
198#[derive(Copy, Clone, Debug, PartialEq, Default)]
199pub enum WindowBounds {
200    Fullscreen,
201    #[default]
202    Maximized,
203    Fixed(Bounds<Pixels>),
204}
205
206#[derive(Copy, Clone, Debug)]
207pub enum WindowAppearance {
208    Light,
209    VibrantLight,
210    Dark,
211    VibrantDark,
212}
213
214impl Default for WindowAppearance {
215    fn default() -> Self {
216        Self::Light
217    }
218}
219
220#[derive(Copy, Clone, Debug, PartialEq, Default)]
221pub enum WindowPromptLevel {
222    #[default]
223    Info,
224    Warning,
225    Critical,
226}