use std::{
fmt,
hash::{Hash, Hasher},
cmp::Ordering,
rc::Rc,
collections::{BTreeMap, HashSet},
sync::atomic::{AtomicUsize, Ordering as AtomicOrdering},
path::PathBuf,
};
#[cfg(target_os = "windows")]
use std::ffi::c_void;
#[cfg(not(test))]
#[cfg(debug_assertions)]
use std::time::Duration;
use azul_css::{Css, LayoutPoint, LayoutRect, CssPath};
#[cfg(debug_assertions)]
#[cfg(not(test))]
use azul_css::HotReloadHandler;
use crate::{
FastHashMap,
app_resources::Epoch,
dom::{DomId, EventFilter},
id_tree::NodeId,
callbacks::{PipelineId, DocumentId, Callback, ScrollPosition, HitTestItem, UpdateScreen, Redraw},
ui_solver::{OverflowingScrollNode, ExternalScrollId, ScrolledNodes},
ui_state::UiState,
display_list::{SolvedLayoutCache, GlTextureCache, CachedDisplayList},
};
use gleam::gl::Gl;
pub const DEFAULT_TITLE: &str = "Azul App";
pub const DEFAULT_WIDTH: f32 = 800.0;
pub const DEFAULT_HEIGHT: f32 = 600.0;
static LAST_WINDOW_ID: AtomicUsize = AtomicUsize::new(0);
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
pub struct WindowId { id: usize }
impl WindowId {
pub fn new() -> Self {
WindowId { id: LAST_WINDOW_ID.fetch_add(1, AtomicOrdering::SeqCst) }
}
}
static LAST_ICON_KEY: AtomicUsize = AtomicUsize::new(0);
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub struct IconKey { id: usize }
impl IconKey {
pub fn new() -> Self {
Self { id: LAST_ICON_KEY.fetch_add(1, AtomicOrdering::SeqCst) }
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum MouseCursorType {
Default,
Crosshair,
Hand,
Arrow,
Move,
Text,
Wait,
Help,
Progress,
NotAllowed,
ContextMenu,
Cell,
VerticalText,
Alias,
Copy,
NoDrop,
Grab,
Grabbing,
AllScroll,
ZoomIn,
ZoomOut,
EResize,
NResize,
NeResize,
NwResize,
SResize,
SeResize,
SwResize,
WResize,
EwResize,
NsResize,
NeswResize,
NwseResize,
ColResize,
RowResize,
}
impl Default for MouseCursorType {
fn default() -> Self {
MouseCursorType::Default
}
}
pub type ScanCode = u32;
#[derive(Default, Debug, Clone, PartialEq)]
pub struct KeyboardState {
pub shift_down: bool,
pub ctrl_down: bool,
pub alt_down: bool,
pub super_down: bool,
pub current_char: Option<char>,
pub current_virtual_keycode: Option<VirtualKeyCode>,
pub pressed_virtual_keycodes: HashSet<VirtualKeyCode>,
pub pressed_scancodes: HashSet<ScanCode>,
}
#[derive(Debug, Copy, Clone, PartialOrd, PartialEq)]
pub struct MouseState {
pub mouse_cursor_type: Option<MouseCursorType>,
pub cursor_position: CursorPosition,
pub is_cursor_locked: bool,
pub left_down: bool,
pub right_down: bool,
pub middle_down: bool,
pub scroll_x: Option<f32>,
pub scroll_y: Option<f32>,
}
impl Default for MouseState {
fn default() -> Self {
Self {
mouse_cursor_type: Some(MouseCursorType::Default),
cursor_position: CursorPosition::default(),
is_cursor_locked: false,
left_down: false,
right_down: false,
middle_down: false,
scroll_x: None,
scroll_y: None,
}
}
}
impl MouseState {
pub fn mouse_down(&self) -> bool {
self.right_down || self.left_down || self.middle_down
}
pub fn get_scroll_x(&self) -> f32 {
self.scroll_x.unwrap_or(0.0)
}
pub fn get_scroll_y(&self) -> f32 {
self.scroll_y.unwrap_or(0.0)
}
pub fn get_scroll(&self) -> (f32, f32) {
(self.get_scroll_x(), self.get_scroll_y())
}
}
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
pub enum CursorPosition {
OutOfWindow,
Uninitialized,
InWindow(LogicalPosition),
}
impl Default for CursorPosition {
fn default() -> CursorPosition {
CursorPosition::Uninitialized
}
}
impl CursorPosition {
pub fn get_position(&self) -> Option<LogicalPosition> {
match self {
CursorPosition::InWindow(logical_pos) => Some(*logical_pos),
CursorPosition::OutOfWindow | CursorPosition::Uninitialized => None,
}
}
}
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct DebugState {
pub profiler_dbg: bool,
pub render_target_dbg: bool,
pub texture_cache_dbg: bool,
pub gpu_time_queries: bool,
pub gpu_sample_queries: bool,
pub disable_batching: bool,
pub epochs: bool,
pub compact_profiler: bool,
pub echo_driver_messages: bool,
pub new_frame_indicator: bool,
pub new_scene_indicator: bool,
pub show_overdraw: bool,
pub gpu_cache_dbg: bool,
}
#[derive(Debug, Default)]
pub struct ScrollStates(pub FastHashMap<ExternalScrollId, ScrollState>);
impl ScrollStates {
pub fn new() -> ScrollStates {
ScrollStates::default()
}
#[must_use]
pub fn get_scroll_position(&self, scroll_id: &ExternalScrollId) -> Option<LayoutPoint> {
self.0.get(&scroll_id).map(|entry| entry.get())
}
pub fn set_scroll_position(&mut self, node: &OverflowingScrollNode, scroll_position: LayoutPoint) {
self.0.entry(node.parent_external_scroll_id)
.or_insert_with(|| ScrollState::default())
.set(scroll_position.x, scroll_position.y, &node.child_rect);
}
#[must_use]
pub fn get_scroll_position_and_mark_as_used(&mut self, scroll_id: &ExternalScrollId) -> Option<LayoutPoint> {
let entry = self.0.get_mut(&scroll_id)?;
Some(entry.get_and_mark_as_used())
}
pub fn scroll_node(&mut self, node: &OverflowingScrollNode, scroll_by_x: f32, scroll_by_y: f32) {
self.0.entry(node.parent_external_scroll_id)
.or_insert_with(|| ScrollState::default())
.add(scroll_by_x, scroll_by_y, &node.child_rect);
}
pub fn remove_unused_scroll_states(&mut self) {
self.0.retain(|_, state| state.used_this_frame);
}
}
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
pub struct ScrollState {
pub scroll_position: LayoutPoint,
pub used_this_frame: bool,
}
impl ScrollState {
pub fn get(&self) -> LayoutPoint {
self.scroll_position
}
pub fn add(&mut self, x: f32, y: f32, child_rect: &LayoutRect) {
self.scroll_position.x = (self.scroll_position.x + x).max(0.0).min(child_rect.size.width);
self.scroll_position.y = (self.scroll_position.y + y).max(0.0).min(child_rect.size.height);
}
pub fn set(&mut self, x: f32, y: f32, child_rect: &LayoutRect) {
self.scroll_position.x = x.max(0.0).min(child_rect.size.width);
self.scroll_position.y = y.max(0.0).min(child_rect.size.height);
}
pub fn get_and_mark_as_used(&mut self) -> LayoutPoint {
self.used_this_frame = true;
self.scroll_position
}
}
impl Default for ScrollState {
fn default() -> Self {
ScrollState {
scroll_position: LayoutPoint::zero(),
used_this_frame: true,
}
}
}
pub fn update_full_window_state(
full_window_state: &mut FullWindowState,
window_state: &WindowState
) {
full_window_state.title = window_state.title.clone();
full_window_state.size = window_state.size;
full_window_state.position = window_state.position;
full_window_state.flags = window_state.flags;
full_window_state.debug_state = window_state.debug_state;
full_window_state.keyboard_state = window_state.keyboard_state.clone();
full_window_state.mouse_state = window_state.mouse_state;
full_window_state.ime_position = window_state.ime_position;
full_window_state.platform_specific_options = window_state.platform_specific_options.clone();
}
pub fn clear_scroll_state(window_state: &mut FullWindowState) {
window_state.mouse_state.scroll_x = None;
window_state.mouse_state.scroll_y = None;
}
pub struct WindowInternal {
pub document_id: DocumentId,
pub pipeline_id: PipelineId,
pub epoch: Epoch,
pub cached_display_list: CachedDisplayList,
pub layout_result: SolvedLayoutCache,
pub gl_texture_cache: GlTextureCache,
pub scrolled_nodes: BTreeMap<DomId, ScrolledNodes>,
pub scroll_states: ScrollStates,
}
impl WindowInternal {
pub fn get_current_scroll_states(&self, ui_states: &BTreeMap<DomId, UiState>)
-> BTreeMap<DomId, BTreeMap<NodeId, ScrollPosition>>
{
self.scrolled_nodes.iter().filter_map(|(dom_id, scrolled_nodes)| {
let layout_result = self.layout_result.solved_layouts.get(dom_id)?;
let ui_state = &ui_states.get(dom_id)?;
let scroll_positions = scrolled_nodes.overflowing_nodes.iter().filter_map(|(node_id, overflowing_node)| {
let scroll_location = self.scroll_states.get_scroll_position(&overflowing_node.parent_external_scroll_id)?;
let parent_node = ui_state.get_dom().arena.node_hierarchy[*node_id].parent.unwrap_or(NodeId::ZERO);
let scroll_position = ScrollPosition {
scroll_frame_rect: overflowing_node.child_rect,
parent_rect: layout_result.rects[parent_node].to_layouted_rectangle(),
scroll_location,
};
Some((*node_id, scroll_position))
}).collect();
Some((dom_id.clone(), scroll_positions))
}).collect()
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct WindowState {
pub title: String,
pub size: WindowSize,
pub position: Option<PhysicalPosition<u32>>,
pub flags: WindowFlags,
pub debug_state: DebugState,
pub keyboard_state: KeyboardState,
pub mouse_state: MouseState,
pub ime_position: Option<LogicalPosition>,
pub platform_specific_options: PlatformSpecificOptions,
pub css: Css,
}
#[derive(Debug, Clone, PartialEq)]
pub struct FullWindowState {
pub title: String,
pub size: WindowSize,
pub position: Option<PhysicalPosition<u32>>,
pub flags: WindowFlags,
pub debug_state: DebugState,
pub keyboard_state: KeyboardState,
pub mouse_state: MouseState,
pub ime_position: Option<LogicalPosition>,
pub platform_specific_options: PlatformSpecificOptions,
pub css: Css,
pub previous_window_state: Option<Box<FullWindowState>>,
pub hovered_file: Option<PathBuf>,
pub dropped_file: Option<PathBuf>,
pub focused_node: Option<(DomId, NodeId)>,
pub hovered_nodes: BTreeMap<DomId, BTreeMap<NodeId, HitTestItem>>,
}
impl Default for FullWindowState {
fn default() -> Self {
Self {
title: DEFAULT_TITLE.into(),
size: WindowSize::default(),
position: None,
flags: WindowFlags::default(),
debug_state: DebugState::default(),
keyboard_state: KeyboardState::default(),
mouse_state: MouseState::default(),
ime_position: None,
platform_specific_options: PlatformSpecificOptions::default(),
css: Css::default(),
previous_window_state: None,
hovered_file: None,
dropped_file: None,
focused_node: None,
hovered_nodes: BTreeMap::default(),
}
}
}
impl FullWindowState {
pub fn get_mouse_state(&self) -> &MouseState {
&self.mouse_state
}
pub fn get_keyboard_state(&self) -> &KeyboardState {
&self.keyboard_state
}
pub fn get_hovered_file(&self) -> Option<&PathBuf> {
self.hovered_file.as_ref()
}
pub fn get_dropped_file(&self) -> Option<&PathBuf> {
self.dropped_file.as_ref()
}
pub fn get_previous_window_state(&self) -> Option<&Box<FullWindowState>> {
self.previous_window_state.as_ref()
}
}
impl From<WindowState> for FullWindowState {
fn from(window_state: WindowState) -> FullWindowState {
FullWindowState {
title: window_state.title,
size: window_state.size,
position: window_state.position,
flags: window_state.flags,
debug_state: window_state.debug_state,
keyboard_state: window_state.keyboard_state,
mouse_state: window_state.mouse_state,
ime_position: window_state.ime_position,
platform_specific_options: window_state.platform_specific_options,
css: window_state.css,
.. Default::default()
}
}
}
impl From<FullWindowState> for WindowState {
fn from(full_window_state: FullWindowState) -> WindowState {
WindowState {
title: full_window_state.title,
size: full_window_state.size,
position: full_window_state.position,
flags: full_window_state.flags,
debug_state: full_window_state.debug_state,
keyboard_state: full_window_state.keyboard_state,
mouse_state: full_window_state.mouse_state,
ime_position: full_window_state.ime_position,
platform_specific_options: full_window_state.platform_specific_options,
css: full_window_state.css,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct CallCallbacksResult {
pub needs_restyle_hover_active: bool,
pub needs_relayout_hover_active: bool,
pub needs_restyle_focus_changed: bool,
pub should_scroll_render: bool,
pub callbacks_update_screen: UpdateScreen,
pub modified_window_state: WindowState,
}
impl CallCallbacksResult {
pub fn should_relayout(&self) -> bool {
self.needs_relayout_hover_active ||
self.callbacks_update_screen == Redraw
}
pub fn should_restyle(&self) -> bool {
self.should_relayout() ||
self.needs_restyle_focus_changed ||
self.needs_restyle_hover_active
}
pub fn should_rerender(&self) -> bool {
self.should_restyle() ||
self.should_scroll_render
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
pub struct WindowFlags {
pub is_maximized: bool,
pub is_fullscreen: bool,
pub has_decorations: bool,
pub is_visible: bool,
pub is_always_on_top: bool,
pub is_resizable: bool,
}
impl Default for WindowFlags {
fn default() -> Self {
Self {
is_maximized: false,
is_fullscreen: false,
has_decorations: true,
is_visible: true,
is_always_on_top: false,
is_resizable: true,
}
}
}
#[cfg(target_arch = "wasm32")]
pub type PlatformSpecificOptions = WasmWindowOptions;
#[cfg(target_os = "windows")]
pub type PlatformSpecificOptions = WindowsWindowOptions;
#[cfg(target_os = "linux")]
pub type PlatformSpecificOptions = LinuxWindowOptions;
#[cfg(target_os = "macos")]
pub type PlatformSpecificOptions = MacWindowOptions;
#[cfg(target_arch = "wasm32")]
#[derive(Debug, Default, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub struct WasmWindowOptions {
}
#[cfg(target_os = "windows")]
#[derive(Debug, Default, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub struct WindowsWindowOptions {
pub no_redirection_bitmap: bool,
pub window_icon: Option<WindowIcon>,
pub taskbar_icon: Option<TaskBarIcon>,
pub parent_window: Option<*mut c_void>,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum XWindowType {
Desktop,
Dock,
Toolbar,
Menu,
Utility,
Splash,
Dialog,
DropdownMenu,
PopupMenu,
Tooltip,
Notification,
Combo,
Dnd,
Normal,
}
impl Default for XWindowType {
fn default() -> Self {
XWindowType::Normal
}
}
#[cfg(target_os = "linux")]
#[derive(Debug, Default, Clone, PartialEq, PartialOrd)]
pub struct LinuxWindowOptions {
pub x11_visual: Option<*const ()>,
pub x11_screen: Option<i32>,
pub x11_wm_classes: Vec<(String, String)>,
pub x11_override_redirect: bool,
pub x11_window_types: Vec<XWindowType>,
pub x11_gtk_theme_variant: Option<String>,
pub x11_resize_increments: Option<LogicalSize>,
pub x11_base_size: Option<LogicalSize>,
pub wayland_app_id: Option<String>,
pub request_user_attention: bool,
pub wayland_theme: Option<WaylandTheme>,
pub window_icon: Option<WindowIcon>,
}
#[cfg(target_os = "macos")]
#[derive(Debug, Default, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub struct MacWindowOptions {
pub request_user_attention: bool,
}
impl WindowState {
pub fn new(css: Css) -> Self { Self { css, .. Default::default() } }
pub fn with_css(self, css: Css) -> Self { Self { css, .. self } }
pub fn get_mouse_state(&self) -> &MouseState {
&self.mouse_state
}
pub fn get_keyboard_state(&self) -> &KeyboardState {
&self.keyboard_state
}
pub fn get_physical_size(&self) -> (usize, usize) {
(self.size.dimensions.width as usize, self.size.dimensions.height as usize)
}
pub fn get_hidpi_factor(&self) -> f32 {
self.size.hidpi_factor
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum FullScreenMode {
SlowFullScreen,
FastFullScreen,
SlowWindowed,
FastWindowed,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct WaylandTheme {
pub primary_active: [u8; 4],
pub primary_inactive: [u8; 4],
pub secondary_active: [u8; 4],
pub secondary_inactive: [u8; 4],
pub close_button_hovered: [u8; 4],
pub close_button: [u8; 4],
pub maximize_button_hovered: [u8; 4],
pub maximize_button: [u8; 4],
pub minimize_button_hovered: [u8; 4],
pub minimize_button: [u8; 4],
}
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
pub struct WindowSize {
pub dimensions: LogicalSize,
pub hidpi_factor: f32,
pub winit_hidpi_factor: f32,
pub min_dimensions: Option<LogicalSize>,
pub max_dimensions: Option<LogicalSize>,
}
impl WindowSize {
pub fn get_logical_size(&self) -> LogicalSize {
self.dimensions
}
pub fn get_physical_size(&self) -> PhysicalSize<u32> {
self.dimensions.to_physical(self.hidpi_factor)
}
pub fn get_reverse_logical_size(&self) -> LogicalSize {
LogicalSize::new(
self.dimensions.width * self.hidpi_factor / self.winit_hidpi_factor,
self.dimensions.height * self.hidpi_factor / self.winit_hidpi_factor,
)
}
}
impl Default for WindowSize {
fn default() -> Self {
Self {
dimensions: LogicalSize::new(DEFAULT_WIDTH, DEFAULT_HEIGHT),
hidpi_factor: 1.0,
winit_hidpi_factor: 1.0,
min_dimensions: None,
max_dimensions: None,
}
}
}
impl Default for WindowState {
fn default() -> Self {
Self {
title: DEFAULT_TITLE.into(),
size: WindowSize::default(),
position: None,
flags: WindowFlags::default(),
debug_state: DebugState::default(),
keyboard_state: KeyboardState::default(),
mouse_state: MouseState::default(),
ime_position: None,
platform_specific_options: PlatformSpecificOptions::default(),
css: Css::default(),
}
}
}
pub struct WindowCreateOptions {
pub state: WindowState,
pub renderer_type: RendererType,
#[cfg(debug_assertions)]
#[cfg(not(test))]
pub hot_reload_handler: Option<Box<dyn HotReloadHandler>>,
}
impl fmt::Debug for WindowCreateOptions {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
#[cfg(debug_assertions)]
#[cfg(not(test))] {
write!(f, "WindowCreateOptions {{ state: {:?}, renderer_type: {:?}, hot_reload_handler: {:?} }}",
self.state, self.renderer_type, self.hot_reload_handler.is_some())
}
#[cfg(any(not(debug_assertions), test))] {
write!(f, "WindowCreateOptions {{ state: {:?}, renderer_type: {:?} }}", self.state, self.renderer_type)
}
}
}
impl Default for WindowCreateOptions {
fn default() -> Self {
Self {
state: WindowState::default(),
renderer_type: RendererType::default(),
#[cfg(debug_assertions)]
#[cfg(not(test))]
hot_reload_handler: None,
}
}
}
impl WindowCreateOptions {
pub fn new(css: Css) -> Self {
Self {
state: WindowState::new(css),
.. Default::default()
}
}
pub fn with_css(mut self, css: Css) -> Self {
self.state.css = css;
self
}
#[cfg(not(test))]
#[cfg(debug_assertions)]
pub fn new_hot_reload(hot_reload_handler: Box<dyn HotReloadHandler>) -> Self {
Self {
hot_reload_handler: Some(hot_reload_handler),
.. Default::default()
}
}
}
#[cfg(not(test))]
#[cfg(debug_assertions)]
pub struct HotReloader(pub Box<dyn HotReloadHandler>);
#[cfg(not(test))]
#[cfg(debug_assertions)]
impl HotReloader {
pub fn new(hot_reload_handler: Box<dyn HotReloadHandler>) -> Self {
Self(hot_reload_handler)
}
pub fn get_reload_interval(&self) -> Duration {
self.0.get_reload_interval()
}
pub fn reload_style(&self) -> Result<Css, String> {
match self.0.reload_style() {
Ok(mut new_css) => {
new_css.sort_by_specificity();
Ok(new_css)
},
Err(why) => {
Err(format!("{}", why))
},
}
}
}
pub enum RendererType {
Default,
ForceHardware,
ForceSoftware,
Custom(Rc<dyn Gl>),
}
impl RendererType {
#[inline(always)]
fn get_type(&self) -> RendererTypeNoData {
match self {
RendererType::Default => RendererTypeNoData::Default,
RendererType::ForceHardware => RendererTypeNoData::ForceHardware,
RendererType::ForceSoftware => RendererTypeNoData::ForceSoftware,
RendererType::Custom(_) => RendererTypeNoData::Custom,
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
enum RendererTypeNoData {
Default,
ForceHardware,
ForceSoftware,
Custom,
}
impl Clone for RendererType {
fn clone(&self) -> Self {
use self::RendererType::*;
match self {
Default => Default,
ForceHardware => ForceHardware,
ForceSoftware => ForceSoftware,
Custom(gl) => Custom(gl.clone()),
}
}
}
impl PartialOrd for RendererType {
fn partial_cmp(&self, other: &RendererType) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for RendererType {
fn cmp(&self, other: &RendererType) -> Ordering {
self.get_type().cmp(&other.get_type())
}
}
impl PartialEq for RendererType {
fn eq(&self, other: &RendererType) -> bool {
self.get_type().eq(&other.get_type())
}
}
impl Eq for RendererType { }
impl Hash for RendererType {
fn hash<H>(&self, state: &mut H) where H: Hasher {
self.get_type().hash(state);
}
}
impl fmt::Debug for RendererType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
RendererType::Default => write!(f, "Default"),
RendererType::ForceHardware => write!(f, "ForceHardware"),
RendererType::ForceSoftware => write!(f, "ForceSoftware"),
RendererType::Custom(_) => write!(f, "Custom"),
}
}
}
impl Default for RendererType {
fn default() -> Self {
RendererType::Default
}
}
pub enum AzulUpdateEvent {
CreateWindow {
window_create_options: WindowCreateOptions,
},
CloseWindow {
window_id: WindowId,
},
DoHitTest {
window_id: WindowId,
},
RebuildUi {
window_id: WindowId,
},
RestyleUi {
window_id: WindowId,
skip_layout: bool,
},
RelayoutUi {
window_id: WindowId,
},
RebuildDisplayList {
window_id: WindowId,
},
SendDisplayListToWebRender {
window_id: WindowId,
},
UpdateScrollStates {
window_id: WindowId,
},
UpdateAnimations {
window_id: WindowId,
},
UpdateImages {
window_id: WindowId,
},
}
impl fmt::Debug for AzulUpdateEvent {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use self::AzulUpdateEvent::*;
match self {
CreateWindow { window_create_options } => write!(f, "CreateWindow {{ window_create_options: {:?} }}", window_create_options),
CloseWindow { window_id } => write!(f, "CloseWindow {{ window_id: {:?} }}", window_id),
DoHitTest { window_id } => write!(f, "DoHitTest {{ window_id: {:?} }}", window_id),
RebuildUi { window_id } => write!(f, "RebuildUi {{ window_id: {:?} }}", window_id),
RestyleUi { window_id, skip_layout } => write!(f, "RestyleUi {{ window_id: {:?}, skip_layout: {:?} }}", window_id, skip_layout),
RelayoutUi { window_id } => write!(f, "RelayoutUi {{ window_id: {:?} }}", window_id),
RebuildDisplayList { window_id } => write!(f, "RebuildDisplayList {{ window_id: {:?} }}", window_id),
SendDisplayListToWebRender { window_id } => write!(f, "SendDisplayListToWebRender {{ window_id: {:?} }}", window_id),
UpdateScrollStates { window_id } => write!(f, "UpdateScrollStates {{ window_id: {:?} }}", window_id),
UpdateAnimations { window_id } => write!(f, "UpdateAnimations {{ window_id: {:?} }}", window_id),
UpdateImages { window_id } => write!(f, "UpdateImages {{ window_id: {:?} }}", window_id),
}
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Ord, Eq, Hash)]
pub enum UpdateFocusWarning {
FocusInvalidDomId(DomId),
FocusInvalidNodeId(NodeId),
CouldNotFindFocusNode(CssPath),
}
impl ::std::fmt::Display for UpdateFocusWarning {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
use self::UpdateFocusWarning::*;
match self {
FocusInvalidDomId(dom_id) => write!(f, "Focusing on DOM with invalid ID: {:?}", dom_id),
FocusInvalidNodeId(node_id) => write!(f, "Focusing on node with invalid ID: {}", node_id),
CouldNotFindFocusNode(css_path) => write!(f, "Could not find focus node for path: {}", css_path),
}
}
}
pub struct DetermineCallbackResult {
pub hit_test_item: Option<HitTestItem>,
pub normal_callbacks: BTreeMap<EventFilter, Callback>,
}
impl DetermineCallbackResult {
pub fn has_normal_callbacks(&self) -> bool {
!self.normal_callbacks.is_empty()
}
pub fn has_any_callbacks(&self) -> bool {
self.has_normal_callbacks()
}
}
impl Default for DetermineCallbackResult {
fn default() -> Self {
DetermineCallbackResult {
hit_test_item: None,
normal_callbacks: BTreeMap::new(),
}
}
}
impl Clone for DetermineCallbackResult {
fn clone(&self) -> Self {
DetermineCallbackResult {
hit_test_item: self.hit_test_item.clone(),
normal_callbacks: self.normal_callbacks.clone(),
}
}
}
impl fmt::Debug for DetermineCallbackResult {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f,
"DetermineCallbackResult {{ \
hit_test_item: {:?},\
normal_callbacks: {:#?},\
}}",
self.hit_test_item,
self.normal_callbacks.keys().collect::<Vec<_>>(),
)
}
}
pub struct CallbacksOfHitTest {
pub nodes_with_callbacks: BTreeMap<NodeId, DetermineCallbackResult>,
pub needs_relayout_anyways: bool,
pub needs_redraw_anyways: bool,
}
impl Default for CallbacksOfHitTest {
fn default() -> Self {
Self {
nodes_with_callbacks: BTreeMap::new(),
needs_redraw_anyways: false,
needs_relayout_anyways: false,
}
}
}
impl fmt::Debug for CallbacksOfHitTest {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f,
"CallbacksOfHitTest {{ \
nodes_with_callbacks: {:#?},
needs_relayout_anyways: {:?},
needs_redraw_anyways: {:?},
}}",
self.nodes_with_callbacks,
self.needs_relayout_anyways,
self.needs_redraw_anyways,
)
}
}
impl CallbacksOfHitTest {
pub fn should_call_callbacks(&self) -> bool {
!self.nodes_with_callbacks.is_empty() &&
self.nodes_with_callbacks.values().any(|n| n.has_any_callbacks())
}
}
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
pub struct LogicalPosition {
pub x: f32,
pub y: f32,
}
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
pub struct LogicalSize {
pub width: f32,
pub height: f32,
}
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
pub struct PhysicalPosition<T> {
pub x: T,
pub y: T,
}
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
pub struct PhysicalSize<T> {
pub width: T,
pub height: T,
}
impl LogicalPosition {
#[inline(always)]
pub const fn new(x: f32, y: f32) -> Self { Self { x, y } }
#[inline(always)]
pub const fn zero() -> Self { Self::new(0.0, 0.0) }
#[inline(always)]
pub fn to_physical(self, hidpi_factor: f32) -> PhysicalPosition<u32> {
PhysicalPosition {
x: (self.x * hidpi_factor) as u32,
y: (self.y * hidpi_factor) as u32,
}
}
}
impl<T> PhysicalPosition<T> {
#[inline(always)]
pub const fn new(x: T, y: T) -> Self { Self { x, y } }
}
impl PhysicalPosition<u32> {
#[inline(always)]
pub const fn zero() -> Self { Self::new(0, 0) }
#[inline(always)]
pub fn to_logical(self, hidpi_factor: f32) -> LogicalPosition {
LogicalPosition {
x: self.x as f32 / hidpi_factor,
y: self.y as f32 / hidpi_factor,
}
}
}
impl PhysicalPosition<f64> {
#[inline(always)]
pub const fn zero() -> Self { Self::new(0.0, 0.0) }
#[inline(always)]
pub fn to_logical(self, hidpi_factor: f32) -> LogicalPosition {
LogicalPosition {
x: self.x as f32 / hidpi_factor,
y: self.y as f32 / hidpi_factor,
}
}
}
impl LogicalSize {
#[inline(always)]
pub const fn new(width: f32, height: f32) -> Self { Self { width, height } }
#[inline(always)]
pub const fn zero() -> Self { Self::new(0.0, 0.0) }
#[inline(always)]
pub fn to_physical(self, hidpi_factor: f32) -> PhysicalSize<u32> {
PhysicalSize {
width: (self.width * hidpi_factor) as u32,
height: (self.height * hidpi_factor) as u32,
}
}
}
impl<T> PhysicalSize<T> {
#[inline(always)]
pub const fn new(width: T, height: T) -> Self { Self { width, height } }
}
impl PhysicalSize<u32> {
#[inline(always)]
pub const fn zero() -> Self { Self::new(0, 0) }
#[inline(always)]
pub fn to_logical(self, hidpi_factor: f32) -> LogicalSize {
LogicalSize {
width: self.width as f32 / hidpi_factor,
height: self.height as f32 / hidpi_factor,
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum AcceleratorKey {
Ctrl,
Alt,
Shift,
Key(VirtualKeyCode),
}
impl AcceleratorKey {
pub fn matches(&self, keyboard_state: &KeyboardState) -> bool {
use self::AcceleratorKey::*;
match self {
Ctrl => keyboard_state.ctrl_down,
Alt => keyboard_state.alt_down,
Shift => keyboard_state.shift_down,
Key(k) => keyboard_state.pressed_virtual_keycodes.contains(k),
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum VirtualKeyCode {
Key1,
Key2,
Key3,
Key4,
Key5,
Key6,
Key7,
Key8,
Key9,
Key0,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z,
Escape,
F1,
F2,
F3,
F4,
F5,
F6,
F7,
F8,
F9,
F10,
F11,
F12,
F13,
F14,
F15,
F16,
F17,
F18,
F19,
F20,
F21,
F22,
F23,
F24,
Snapshot,
Scroll,
Pause,
Insert,
Home,
Delete,
End,
PageDown,
PageUp,
Left,
Up,
Right,
Down,
Back,
Return,
Space,
Compose,
Caret,
Numlock,
Numpad0,
Numpad1,
Numpad2,
Numpad3,
Numpad4,
Numpad5,
Numpad6,
Numpad7,
Numpad8,
Numpad9,
AbntC1,
AbntC2,
Add,
Apostrophe,
Apps,
At,
Ax,
Backslash,
Calculator,
Capital,
Colon,
Comma,
Convert,
Decimal,
Divide,
Equals,
Grave,
Kana,
Kanji,
LAlt,
LBracket,
LControl,
LShift,
LWin,
Mail,
MediaSelect,
MediaStop,
Minus,
Multiply,
Mute,
MyComputer,
NavigateForward,
NavigateBackward,
NextTrack,
NoConvert,
NumpadComma,
NumpadEnter,
NumpadEquals,
OEM102,
Period,
PlayPause,
Power,
PrevTrack,
RAlt,
RBracket,
RControl,
RShift,
RWin,
Semicolon,
Slash,
Sleep,
Stop,
Subtract,
Sysrq,
Tab,
Underline,
Unlabeled,
VolumeDown,
VolumeUp,
Wake,
WebBack,
WebFavorites,
WebForward,
WebHome,
WebRefresh,
WebSearch,
WebStop,
Yen,
Copy,
Paste,
Cut,
}
#[derive(Debug, Clone)]
pub enum WindowIcon {
Small { key: IconKey, rgba_bytes: Vec<u8> },
Large { key: IconKey, rgba_bytes: Vec<u8> },
}
impl WindowIcon {
pub fn get_key(&self) -> IconKey {
match &self {
WindowIcon::Small { key, .. } => *key,
WindowIcon::Large { key, .. } => *key,
}
}
}
impl PartialEq for WindowIcon {
fn eq(&self, rhs: &Self) -> bool {
self.get_key() == rhs.get_key()
}
}
impl PartialOrd for WindowIcon {
fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
Some((self.get_key()).cmp(&rhs.get_key()))
}
}
impl Eq for WindowIcon { }
impl Ord for WindowIcon {
fn cmp(&self, rhs: &Self) -> Ordering {
(self.get_key()).cmp(&rhs.get_key())
}
}
impl Hash for WindowIcon {
fn hash<H>(&self, state: &mut H) where H: Hasher {
self.get_key().hash(state);
}
}
#[derive(Debug, Clone)]
pub struct TaskBarIcon {
pub key: IconKey,
pub rgba_bytes: Vec<u8>,
}
impl PartialEq for TaskBarIcon {
fn eq(&self, rhs: &Self) -> bool {
self.key == rhs.key
}
}
impl PartialOrd for TaskBarIcon {
fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
Some((self.key).cmp(&rhs.key))
}
}
impl Eq for TaskBarIcon { }
impl Ord for TaskBarIcon {
fn cmp(&self, rhs: &Self) -> Ordering {
(self.key).cmp(&rhs.key)
}
}
impl Hash for TaskBarIcon {
fn hash<H>(&self, state: &mut H) where H: Hasher {
self.key.hash(state);
}
}