From 938ed06202535a7d471c8943729c21bb8c1d285b Mon Sep 17 00:00:00 2001 From: amrbashir Date: Wed, 27 Mar 2024 00:55:32 +0200 Subject: [PATCH 1/2] refactor!: migrate to `dpi` crate --- .changes/dpi-crate.md | 11 + Cargo.toml | 3 +- examples/tao.rs | 3 +- .../windows-common-controls-v6/src/main.rs | 3 +- examples/winit.rs | 3 +- examples/wry.rs | 9 +- src/dpi.rs | 237 ------------------ src/items/submenu.rs | 3 +- src/lib.rs | 5 +- src/menu.rs | 2 +- src/platform_impl/gtk/mod.rs | 3 +- src/platform_impl/macos/mod.rs | 8 +- src/platform_impl/windows/mod.rs | 3 +- 13 files changed, 35 insertions(+), 258 deletions(-) create mode 100644 .changes/dpi-crate.md delete mode 100644 src/dpi.rs diff --git a/.changes/dpi-crate.md b/.changes/dpi-crate.md new file mode 100644 index 00000000..e3c728bb --- /dev/null +++ b/.changes/dpi-crate.md @@ -0,0 +1,11 @@ +--- +"muda": "minor" +--- + +Moved the following items into `dpi` module which is just an export of `dpi` crate: + +- `Pixel` +- `validate_scale_factor` +- `LogicalPosition` +- `PhysicalPosition` +- `Position` diff --git a/Cargo.toml b/Cargo.toml index d7a467ac..e3d943a6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ categories = [ "gui" ] default = [ "libxdo" ] libxdo = [ "dep:libxdo" ] common-controls-v6 = [ ] -serde = [ "dep:serde" ] +serde = [ "dep:serde", "dpi/serde" ] [dependencies] crossbeam-channel = "0.5" @@ -22,6 +22,7 @@ keyboard-types = "0.7" once_cell = "1" thiserror = "1" serde = { version = "1", optional = true } +dpi = "0.1" [target."cfg(target_os = \"windows\")".dependencies.windows-sys] version = "0.52" diff --git a/examples/tao.rs b/examples/tao.rs index f6cf0b3f..cfef0663 100644 --- a/examples/tao.rs +++ b/examples/tao.rs @@ -5,8 +5,9 @@ #![allow(unused)] use muda::{ accelerator::{Accelerator, Code, Modifiers}, + dpi::{PhysicalPosition, Position}, AboutMetadata, CheckMenuItem, ContextMenu, IconMenuItem, Menu, MenuEvent, MenuItem, - PhysicalPosition, Position, PredefinedMenuItem, Submenu, + PredefinedMenuItem, Submenu, }; #[cfg(target_os = "macos")] use tao::platform::macos::WindowExtMacOS; diff --git a/examples/windows-common-controls-v6/src/main.rs b/examples/windows-common-controls-v6/src/main.rs index 2b56dee8..872ac8b4 100644 --- a/examples/windows-common-controls-v6/src/main.rs +++ b/examples/windows-common-controls-v6/src/main.rs @@ -5,8 +5,9 @@ #![allow(unused)] use muda::{ accelerator::{Accelerator, Code, Modifiers}, + dpi::{PhysicalPosition, Position}, AboutMetadata, CheckMenuItem, ContextMenu, IconMenuItem, Menu, MenuEvent, MenuItem, - PhysicalPosition, Position, PredefinedMenuItem, Submenu, + PredefinedMenuItem, Submenu, }; #[cfg(target_os = "macos")] use tao::platform::macos::{EventLoopBuilderExtMacOS, WindowExtMacOS}; diff --git a/examples/winit.rs b/examples/winit.rs index 7b7cb9e1..11a30892 100644 --- a/examples/winit.rs +++ b/examples/winit.rs @@ -5,8 +5,9 @@ #![allow(unused)] use muda::{ accelerator::{Accelerator, Code, Modifiers}, + dpi::{PhysicalPosition, Position}, AboutMetadata, CheckMenuItem, ContextMenu, IconMenuItem, Menu, MenuEvent, MenuItem, - PhysicalPosition, Position, PredefinedMenuItem, Submenu, + PredefinedMenuItem, Submenu, }; #[cfg(target_os = "macos")] use winit::platform::macos::{EventLoopBuilderExtMacOS, WindowExtMacOS}; diff --git a/examples/wry.rs b/examples/wry.rs index 964f9ce8..6d213934 100644 --- a/examples/wry.rs +++ b/examples/wry.rs @@ -7,6 +7,7 @@ use std::rc::Rc; use muda::{ accelerator::{Accelerator, Code, Modifiers}, + dpi::Position, AboutMetadata, CheckMenuItem, ContextMenu, IconMenuItem, Menu, MenuEvent, MenuItem, PredefinedMenuItem, Submenu, }; @@ -254,11 +255,7 @@ fn main() -> wry::Result<()> { y += menu_bar.allocated_height(); } - show_context_menu( - &window, - &file_m_c, - Some(muda::Position::Logical((x, y).into())), - ) + show_context_menu(&window, &file_m_c, Some(Position::Logical((x, y).into()))) } } }; @@ -306,7 +303,7 @@ fn main() -> wry::Result<()> { }) } -fn show_context_menu(window: &Window, menu: &dyn ContextMenu, position: Option) { +fn show_context_menu(window: &Window, menu: &dyn ContextMenu, position: Option) { println!("Show context menu at position {position:?}"); #[cfg(target_os = "windows")] menu.show_context_menu_for_hwnd(window.hwnd() as _, position); diff --git a/src/dpi.rs b/src/dpi.rs deleted file mode 100644 index a3082190..00000000 --- a/src/dpi.rs +++ /dev/null @@ -1,237 +0,0 @@ -// Copyright 2022-2022 Tauri Programme within The Commons Conservancy -// SPDX-License-Identifier: Apache-2.0 -// SPDX-License-Identifier: MIT - -pub trait Pixel: Copy + Into { - fn from_f64(f: f64) -> Self; - fn cast(self) -> P { - P::from_f64(self.into()) - } -} - -impl Pixel for u8 { - fn from_f64(f: f64) -> Self { - f.round() as u8 - } -} -impl Pixel for u16 { - fn from_f64(f: f64) -> Self { - f.round() as u16 - } -} -impl Pixel for u32 { - fn from_f64(f: f64) -> Self { - f.round() as u32 - } -} -impl Pixel for i8 { - fn from_f64(f: f64) -> Self { - f.round() as i8 - } -} -impl Pixel for i16 { - fn from_f64(f: f64) -> Self { - f.round() as i16 - } -} -impl Pixel for i32 { - fn from_f64(f: f64) -> Self { - f.round() as i32 - } -} -impl Pixel for f32 { - fn from_f64(f: f64) -> Self { - f as f32 - } -} -impl Pixel for f64 { - fn from_f64(f: f64) -> Self { - f - } -} - -/// Checks that the scale factor is a normal positive `f64`. -/// -/// All functions that take a scale factor assert that this will return `true`. If you're sourcing scale factors from -/// anywhere other than winit, it's recommended to validate them using this function before passing them to winit; -/// otherwise, you risk panics. -#[inline] -pub fn validate_scale_factor(scale_factor: f64) -> bool { - scale_factor.is_sign_positive() && scale_factor.is_normal() -} - -/// A position represented in logical pixels. -/// -/// The position is stored as floats, so please be careful. Casting floats to integers truncates the -/// fractional part, which can cause noticable issues. To help with that, an `Into<(i32, i32)>` -/// implementation is provided which does the rounding for you. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Default, Hash)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct LogicalPosition

{ - pub x: P, - pub y: P, -} - -impl

LogicalPosition

{ - #[inline] - pub const fn new(x: P, y: P) -> Self { - LogicalPosition { x, y } - } -} - -impl LogicalPosition

{ - #[inline] - pub fn from_physical>, X: Pixel>( - physical: T, - scale_factor: f64, - ) -> Self { - physical.into().to_logical(scale_factor) - } - - #[inline] - pub fn to_physical(&self, scale_factor: f64) -> PhysicalPosition { - assert!(validate_scale_factor(scale_factor)); - let x = self.x.into() * scale_factor; - let y = self.y.into() * scale_factor; - PhysicalPosition::new(x, y).cast() - } - - #[inline] - pub fn cast(&self) -> LogicalPosition { - LogicalPosition { - x: self.x.cast(), - y: self.y.cast(), - } - } -} - -impl From<(X, X)> for LogicalPosition

{ - fn from((x, y): (X, X)) -> LogicalPosition

{ - LogicalPosition::new(x.cast(), y.cast()) - } -} - -impl From> for (X, X) { - fn from(p: LogicalPosition

) -> (X, X) { - (p.x.cast(), p.y.cast()) - } -} - -impl From<[X; 2]> for LogicalPosition

{ - fn from([x, y]: [X; 2]) -> LogicalPosition

{ - LogicalPosition::new(x.cast(), y.cast()) - } -} - -impl From> for [X; 2] { - fn from(p: LogicalPosition

) -> [X; 2] { - [p.x.cast(), p.y.cast()] - } -} - -/// A position represented in physical pixels. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Default, Hash)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct PhysicalPosition

{ - pub x: P, - pub y: P, -} - -impl

PhysicalPosition

{ - #[inline] - pub const fn new(x: P, y: P) -> Self { - PhysicalPosition { x, y } - } -} - -impl PhysicalPosition

{ - #[inline] - pub fn from_logical>, X: Pixel>( - logical: T, - scale_factor: f64, - ) -> Self { - logical.into().to_physical(scale_factor) - } - - #[inline] - pub fn to_logical(&self, scale_factor: f64) -> LogicalPosition { - assert!(validate_scale_factor(scale_factor)); - let x = self.x.into() / scale_factor; - let y = self.y.into() / scale_factor; - LogicalPosition::new(x, y).cast() - } - - #[inline] - pub fn cast(&self) -> PhysicalPosition { - PhysicalPosition { - x: self.x.cast(), - y: self.y.cast(), - } - } -} - -impl From<(X, X)> for PhysicalPosition

{ - fn from((x, y): (X, X)) -> PhysicalPosition

{ - PhysicalPosition::new(x.cast(), y.cast()) - } -} - -impl From> for (X, X) { - fn from(p: PhysicalPosition

) -> (X, X) { - (p.x.cast(), p.y.cast()) - } -} - -impl From<[X; 2]> for PhysicalPosition

{ - fn from([x, y]: [X; 2]) -> PhysicalPosition

{ - PhysicalPosition::new(x.cast(), y.cast()) - } -} - -impl From> for [X; 2] { - fn from(p: PhysicalPosition

) -> [X; 2] { - [p.x.cast(), p.y.cast()] - } -} - -/// A position that's either physical or logical. -#[derive(Debug, Copy, Clone, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum Position { - Physical(PhysicalPosition), - Logical(LogicalPosition), -} - -impl Position { - pub fn new>(position: S) -> Position { - position.into() - } - - pub fn to_logical(&self, scale_factor: f64) -> LogicalPosition

{ - match *self { - Position::Physical(position) => position.to_logical(scale_factor), - Position::Logical(position) => position.cast(), - } - } - - pub fn to_physical(&self, scale_factor: f64) -> PhysicalPosition

{ - match *self { - Position::Physical(position) => position.cast(), - Position::Logical(position) => position.to_physical(scale_factor), - } - } -} - -impl From> for Position { - #[inline] - fn from(position: PhysicalPosition

) -> Position { - Position::Physical(position.cast()) - } -} - -impl From> for Position { - #[inline] - fn from(position: LogicalPosition

) -> Position { - Position::Logical(position.cast()) - } -} diff --git a/src/items/submenu.rs b/src/items/submenu.rs index 87574c08..35319f87 100644 --- a/src/items/submenu.rs +++ b/src/items/submenu.rs @@ -5,7 +5,8 @@ use std::{cell::RefCell, mem, rc::Rc}; use crate::{ - sealed::IsMenuItemBase, util::AddOp, ContextMenu, IsMenuItem, MenuId, MenuItemKind, Position, + dpi::Position, sealed::IsMenuItemBase, util::AddOp, ContextMenu, IsMenuItem, MenuId, + MenuItemKind, }; /// A menu that can be added to a [`Menu`] or another [`Submenu`]. diff --git a/src/lib.rs b/src/lib.rs index cd95a7d7..3db393ba 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -132,7 +132,6 @@ use once_cell::sync::{Lazy, OnceCell}; mod about_metadata; pub mod accelerator; mod builders; -mod dpi; mod error; mod icon; mod items; @@ -147,7 +146,7 @@ extern crate objc; pub use about_metadata::AboutMetadata; pub use builders::*; -pub use dpi::*; +pub use dpi; pub use error::*; pub use icon::{BadIcon, Icon, NativeIcon}; pub use items::*; @@ -311,7 +310,7 @@ pub trait ContextMenu { /// /// - `position` is relative to the window top-left corner, if `None`, the cursor position is used. #[cfg(target_os = "windows")] - fn show_context_menu_for_hwnd(&self, hwnd: isize, position: Option); + fn show_context_menu_for_hwnd(&self, hwnd: isize, position: Option); /// Attach the menu subclass handler to the given hwnd /// so you can recieve events from that window using [MenuEvent::receiver] diff --git a/src/menu.rs b/src/menu.rs index 41948062..42c19d52 100644 --- a/src/menu.rs +++ b/src/menu.rs @@ -4,7 +4,7 @@ use std::{cell::RefCell, rc::Rc}; -use crate::{util::AddOp, ContextMenu, IsMenuItem, MenuId, MenuItemKind, Position}; +use crate::{dpi::Position, util::AddOp, ContextMenu, IsMenuItem, MenuId, MenuItemKind}; /// A root menu that can be added to a Window on Windows and Linux /// and used as the app global menu on macOS. diff --git a/src/platform_impl/gtk/mod.rs b/src/platform_impl/gtk/mod.rs index 585ed2fe..cb837874 100644 --- a/src/platform_impl/gtk/mod.rs +++ b/src/platform_impl/gtk/mod.rs @@ -9,10 +9,11 @@ pub(crate) use icon::PlatformIcon; use crate::{ accelerator::Accelerator, + dpi::Position, icon::{Icon, NativeIcon}, items::*, util::{AddOp, Counter}, - IsMenuItem, MenuEvent, MenuId, MenuItemKind, MenuItemType, Position, + IsMenuItem, MenuEvent, MenuId, MenuItemKind, MenuItemType, }; use accelerator::{from_gtk_mnemonic, parse_accelerator, to_gtk_mnemonic}; use gtk::{gdk, prelude::*, AboutDialog, Container, Orientation}; diff --git a/src/platform_impl/macos/mod.rs b/src/platform_impl/macos/mod.rs index 568114e1..e951c28d 100644 --- a/src/platform_impl/macos/mod.rs +++ b/src/platform_impl/macos/mod.rs @@ -25,10 +25,11 @@ use objc::{ use self::util::{app_name_string, strip_mnemonic}; use crate::{ accelerator::Accelerator, + dpi::{LogicalPosition, Position}, icon::{Icon, NativeIcon}, items::*, util::{AddOp, Counter}, - IsMenuItem, LogicalPosition, MenuEvent, MenuId, MenuItemKind, MenuItemType, Position, + IsMenuItem, MenuEvent, MenuId, MenuItemKind, MenuItemType, }; static COUNTER: Counter = Counter::new(); @@ -1076,11 +1077,10 @@ fn show_context_menu(ns_menu: id, view: id, position: Option) { (location, view) } else { let mouse_location: NSPoint = msg_send![class!(NSEvent), mouseLocation]; - let pos = Position::Logical(LogicalPosition { + let pos = LogicalPosition { x: mouse_location.x, y: mouse_location.y, - }); - let pos = pos.to_logical(scale_factor); + }; let location = NSPoint::new(pos.x, pos.y); (location, nil) }; diff --git a/src/platform_impl/windows/mod.rs b/src/platform_impl/windows/mod.rs index 0149805f..de31fd23 100644 --- a/src/platform_impl/windows/mod.rs +++ b/src/platform_impl/windows/mod.rs @@ -12,10 +12,11 @@ pub(crate) use self::icon::WinIcon as PlatformIcon; use crate::{ accelerator::Accelerator, + dpi::Position, icon::{Icon, NativeIcon}, items::PredefinedMenuItemType, util::{AddOp, Counter}, - AboutMetadata, IsMenuItem, MenuEvent, MenuId, MenuItemKind, MenuItemType, Position, + AboutMetadata, IsMenuItem, MenuEvent, MenuId, MenuItemKind, MenuItemType, }; use std::{ cell::{RefCell, RefMut}, From 5e8e3e32ad746c04f697d78df7c286f0f4a6112e Mon Sep 17 00:00:00 2001 From: amrbashir Date: Wed, 27 Mar 2024 01:05:48 +0200 Subject: [PATCH 2/2] fix macOS and Linux builds --- src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 3db393ba..754bd68b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -100,7 +100,7 @@ //! # #[cfg(target_os = "macos")] //! # let nsview = 0 as *mut objc::runtime::Object; //! // --snip-- -//! let position = muda::PhysicalPosition { x: 100., y: 120. }; +//! let position = muda::dpi::PhysicalPosition { x: 100., y: 120. }; //! #[cfg(target_os = "windows")] //! menu.show_context_menu_for_hwnd(window_hwnd, Some(position.into())); //! #[cfg(target_os = "linux")] @@ -327,7 +327,7 @@ pub trait ContextMenu { /// /// - `position` is relative to the window top-left corner, if `None`, the cursor position is used. #[cfg(target_os = "linux")] - fn show_context_menu_for_gtk_window(&self, w: >k::Window, position: Option); + fn show_context_menu_for_gtk_window(&self, w: >k::Window, position: Option); /// Get the underlying gtk menu reserved for context menus. #[cfg(target_os = "linux")] @@ -337,7 +337,7 @@ pub trait ContextMenu { /// /// - `position` is relative to the window top-left corner, if `None`, the cursor position is used. #[cfg(target_os = "macos")] - fn show_context_menu_for_nsview(&self, view: cocoa::base::id, position: Option); + fn show_context_menu_for_nsview(&self, view: cocoa::base::id, position: Option); /// Get the underlying NSMenu reserved for context menus. #[cfg(target_os = "macos")]