Started implementing VarValue: PartialEq.
This commit is contained in:
parent
4dcdee7d2f
commit
a5bef70ebd
|
@ -607,7 +607,7 @@ impl_from_and_into_var! {
|
|||
///
|
||||
/// [`corner_radius`]: fn@corner_radius
|
||||
/// [`corner_radius_fit`]: fn@corner_radius_fit
|
||||
#[derive(Clone, Copy, Default, serde::Serialize, serde::Deserialize)]
|
||||
#[derive(Clone, Copy, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
||||
pub enum CornerRadiusFit {
|
||||
/// Corner radius is computed for each usage.
|
||||
None,
|
||||
|
|
|
@ -27,7 +27,7 @@ use crate::{
|
|||
/// ```
|
||||
///
|
||||
/// The example above creates a filter that lowers the opacity to `50%` and blurs by `3px`.
|
||||
#[derive(Clone, Default)]
|
||||
#[derive(Clone, Default, PartialEq)]
|
||||
pub struct Filter {
|
||||
filters: Vec<FilterData>,
|
||||
needs_layout: bool,
|
||||
|
@ -207,7 +207,7 @@ impl Layout2d for Filter {
|
|||
/// A computed [`Filter`], ready for Webrender.
|
||||
pub type RenderFilter = Vec<FilterOp>;
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, PartialEq)]
|
||||
enum FilterData {
|
||||
Op(FilterOp),
|
||||
Blur(Length),
|
||||
|
|
|
@ -109,7 +109,7 @@ impl<S: Config, F: Config> AnyConfig for FallbackConfig<S, F> {
|
|||
// based on `Var::bind_bidi` code.
|
||||
let binding_tag = BindMapBidiTag::new_unique();
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
struct ResetTag;
|
||||
|
||||
// fallback->res binding can re-enable on reset.
|
||||
|
|
|
@ -1449,12 +1449,12 @@ impl LAYOUT {
|
|||
}
|
||||
|
||||
/// Current screen PPI.
|
||||
pub fn screen_ppi(&self) -> f32 {
|
||||
pub fn screen_ppi(&self) -> Ppi {
|
||||
LAYOUT_CTX.get().metrics.screen_ppi()
|
||||
}
|
||||
|
||||
/// Calls `f` with `screen_ppi` in the context.
|
||||
pub fn with_screen_ppi<R>(&self, screen_ppi: f32, f: impl FnOnce() -> R) -> R {
|
||||
pub fn with_screen_ppi<R>(&self, screen_ppi: Ppi, f: impl FnOnce() -> R) -> R {
|
||||
self.with_context(self.metrics().with_screen_ppi(screen_ppi), f)
|
||||
}
|
||||
|
||||
|
@ -2730,7 +2730,7 @@ pub struct LayoutMetricsSnapshot {
|
|||
/// The [`screen_ppi`].
|
||||
///
|
||||
/// [`screen_ppi`]: LayoutMetrics::screen_ppi
|
||||
pub screen_ppi: f32,
|
||||
pub screen_ppi: Ppi,
|
||||
|
||||
/// The [`direction`].
|
||||
///
|
||||
|
@ -2751,7 +2751,7 @@ impl LayoutMetricsSnapshot {
|
|||
&& (!mask.contains(LayoutMask::ROOT_FONT_SIZE) || self.root_font_size == other.root_font_size)
|
||||
&& (!mask.contains(LayoutMask::SCALE_FACTOR) || self.scale_factor == other.scale_factor)
|
||||
&& (!mask.contains(LayoutMask::VIEWPORT) || self.viewport == other.viewport)
|
||||
&& (!mask.contains(LayoutMask::SCREEN_PPI) || about_eq(self.screen_ppi, other.screen_ppi, 0.0001))
|
||||
&& (!mask.contains(LayoutMask::SCREEN_PPI) || self.screen_ppi == other.screen_ppi)
|
||||
&& (!mask.contains(LayoutMask::DIRECTION) || self.direction == other.direction)
|
||||
&& (!mask.contains(LayoutMask::LEFTOVER) || self.leftover == other.leftover)
|
||||
}
|
||||
|
@ -2764,7 +2764,7 @@ impl PartialEq for LayoutMetricsSnapshot {
|
|||
&& self.root_font_size == other.root_font_size
|
||||
&& self.scale_factor == other.scale_factor
|
||||
&& self.viewport == other.viewport
|
||||
&& about_eq(self.screen_ppi, other.screen_ppi, 0.0001)
|
||||
&& self.screen_ppi == other.screen_ppi
|
||||
}
|
||||
}
|
||||
impl std::hash::Hash for LayoutMetricsSnapshot {
|
||||
|
@ -2775,7 +2775,7 @@ impl std::hash::Hash for LayoutMetricsSnapshot {
|
|||
self.root_font_size.hash(state);
|
||||
self.scale_factor.hash(state);
|
||||
self.viewport.hash(state);
|
||||
about_eq_hash(self.screen_ppi, 0.0001, state);
|
||||
self.screen_ppi.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2800,7 +2800,7 @@ impl LayoutMetrics {
|
|||
root_font_size: font_size,
|
||||
scale_factor,
|
||||
viewport,
|
||||
screen_ppi: 96.0,
|
||||
screen_ppi: Ppi::default(),
|
||||
direction: LayoutDirection::default(),
|
||||
leftover: euclid::size2(None, None),
|
||||
},
|
||||
|
@ -2880,7 +2880,7 @@ impl LayoutMetrics {
|
|||
///
|
||||
/// [`MONITORS`]: crate::window::MONITORS
|
||||
/// [`scale_factor`]: LayoutMetrics::scale_factor
|
||||
pub fn screen_ppi(&self) -> f32 {
|
||||
pub fn screen_ppi(&self) -> Ppi {
|
||||
self.s.screen_ppi
|
||||
}
|
||||
|
||||
|
@ -2933,7 +2933,7 @@ impl LayoutMetrics {
|
|||
/// Sets the [`screen_ppi`].
|
||||
///
|
||||
/// [`screen_ppi`]: Self::screen_ppi
|
||||
pub fn with_screen_ppi(mut self, screen_ppi: f32) -> Self {
|
||||
pub fn with_screen_ppi(mut self, screen_ppi: Ppi) -> Self {
|
||||
self.s.screen_ppi = screen_ppi;
|
||||
self
|
||||
}
|
||||
|
|
|
@ -576,6 +576,12 @@ impl<K: Eq + Hash + Send> FromParallelIterator<K> for IdSet<K> {
|
|||
Self(FromParallelIterator::from_par_iter(par_iter))
|
||||
}
|
||||
}
|
||||
impl<K: Eq + Hash> PartialEq for IdSet<K> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.0 == other.0
|
||||
}
|
||||
}
|
||||
impl<K: Eq + Hash> Eq for IdSet<K> {}
|
||||
|
||||
/// Entry in [`IdMap`].
|
||||
pub type IdEntry<'a, K, V> = hashbrown::hash_map::Entry<'a, K, V, BuildIdHasher>;
|
||||
|
|
|
@ -493,7 +493,7 @@ impl<const N: usize> crate::var::IntoVar<Shortcuts> for [Shortcut; N] {
|
|||
}
|
||||
|
||||
/// Multiple shortcuts.
|
||||
#[derive(Default, Clone, serde::Serialize, serde::Deserialize)]
|
||||
#[derive(Default, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
||||
pub struct Shortcuts(pub Vec<Shortcut>);
|
||||
impl Shortcuts {
|
||||
/// New default (empty).
|
||||
|
|
|
@ -590,7 +590,7 @@ impl fmt::Debug for GradientStop {
|
|||
/// Stops in a gradient.
|
||||
///
|
||||
/// Use [`stops!`] to create a new instance, you can convert from arrays for simpler gradients.
|
||||
#[derive(Clone, serde::Serialize, serde::Deserialize)]
|
||||
#[derive(Clone, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||
pub struct GradientStops {
|
||||
/// First color stop.
|
||||
pub start: ColorStop,
|
||||
|
|
|
@ -187,7 +187,7 @@ impl Img {
|
|||
/// [`ppi`]: Self::ppi
|
||||
/// [`screen_ppi`]: LayoutMetrics::screen_ppi
|
||||
pub fn layout_size(&self, ctx: &LayoutMetrics) -> PxSize {
|
||||
self.calc_size(ctx, ImagePpi::splat(ctx.screen_ppi()), false)
|
||||
self.calc_size(ctx, ImagePpi::splat(ctx.screen_ppi().0), false)
|
||||
}
|
||||
|
||||
/// Calculate a layout size for the image.
|
||||
|
@ -210,8 +210,8 @@ impl Img {
|
|||
let mut size = self.size();
|
||||
|
||||
let fct = ctx.scale_factor().0;
|
||||
size.width *= (s_ppi / dpi.x) * fct;
|
||||
size.height *= (s_ppi / dpi.y) * fct;
|
||||
size.width *= (s_ppi.0 / dpi.x) * fct;
|
||||
size.height *= (s_ppi.0 / dpi.y) * fct;
|
||||
|
||||
size
|
||||
}
|
||||
|
@ -954,6 +954,19 @@ impl<U: 'static> ops::BitOrAssign for ImageSourceFilter<U> {
|
|||
*self = mem::replace(self, Self::BlockAll).or(rhs);
|
||||
}
|
||||
}
|
||||
impl<U> PartialEq for ImageSourceFilter<U> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
// can only fail by returning `false` in some cases where the value pointer is actually equal.
|
||||
// see: https://github.com/rust-lang/rust/issues/103763
|
||||
//
|
||||
// we are fine with this, worst case is just an extra var update
|
||||
#[allow(clippy::vtable_address_comparisons)]
|
||||
(Self::Custom(l0), Self::Custom(r0)) => Arc::ptr_eq(l0, r0),
|
||||
_ => core::mem::discriminant(self) == core::mem::discriminant(other),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a [`ImageSource::Read`] path request filter.
|
||||
///
|
||||
|
@ -1030,7 +1043,7 @@ impl<F: Fn(&task::http::Uri) -> bool + Send + Sync + 'static> From<F> for UriFil
|
|||
}
|
||||
|
||||
/// Limits for image loading and decoding.
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct ImageLimits {
|
||||
/// Maximum encoded file size allowed.
|
||||
///
|
||||
|
|
|
@ -435,7 +435,7 @@ pub trait L10nSource: Send + 'static {
|
|||
fn available_langs_status(&mut self) -> BoxedVar<LangResourceStatus>;
|
||||
|
||||
/// Gets a read-only variable that provides the fluent resource for the `lang` and `file` if available.
|
||||
fn lang_resource(&mut self, lang: Lang, file: Txt) -> BoxedVar<Option<Arc<fluent::FluentResource>>>;
|
||||
fn lang_resource(&mut self, lang: Lang, file: Txt) -> BoxedVar<Option<ArcEq<fluent::FluentResource>>>;
|
||||
/// Gets a read-only variable that is the status of the [`lang_resource`] value.
|
||||
///
|
||||
/// [`lang_resource`]: Self::lang_resource
|
||||
|
|
|
@ -23,7 +23,7 @@ pub(super) struct L10nService {
|
|||
sys_lang: ArcVar<Langs>,
|
||||
app_lang: ArcCowVar<Langs, ArcVar<Langs>>,
|
||||
|
||||
perm_res: Vec<BoxedVar<Option<Arc<fluent::FluentResource>>>>,
|
||||
perm_res: Vec<BoxedVar<Option<ArcEq<fluent::FluentResource>>>>,
|
||||
bundles: HashMap<(Langs, Txt), BoxedWeakVar<ArcFluentBundle>>,
|
||||
}
|
||||
impl L10nService {
|
||||
|
@ -205,7 +205,7 @@ impl L10nService {
|
|||
res.map(move |r| {
|
||||
let mut bundle = ConcurrentFluentBundle::new_concurrent(vec![lang.clone()]);
|
||||
if let Some(r) = r {
|
||||
bundle.add_resource_overriding(r.clone());
|
||||
bundle.add_resource_overriding(r.0.clone());
|
||||
}
|
||||
ArcFluentBundle(Arc::new(bundle))
|
||||
})
|
||||
|
@ -222,7 +222,7 @@ impl L10nService {
|
|||
res.build(move |res| {
|
||||
let mut bundle = ConcurrentFluentBundle::new_concurrent(langs.clone());
|
||||
for r in res.iter().flatten() {
|
||||
bundle.add_resource_overriding(r.clone());
|
||||
bundle.add_resource_overriding(r.0.clone());
|
||||
}
|
||||
ArcFluentBundle(Arc::new(bundle))
|
||||
})
|
||||
|
@ -272,6 +272,11 @@ impl fmt::Debug for ArcFluentBundle {
|
|||
write!(f, "ArcFluentBundle")
|
||||
}
|
||||
}
|
||||
impl PartialEq for ArcFluentBundle {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
Arc::ptr_eq(&self.0, &other.0)
|
||||
}
|
||||
}
|
||||
impl ops::Deref for ArcFluentBundle {
|
||||
type Target = ConcurrentFluentBundle;
|
||||
|
||||
|
@ -329,7 +334,7 @@ fn format_fallback(file: &str, id: &str, attribute: &str, fallback: &Txt, args:
|
|||
Txt::from_str(txt.as_ref())
|
||||
}
|
||||
|
||||
fn fluent_args_var(args: Vec<(Txt, BoxedVar<L10nArgument>)>) -> impl Var<Arc<Mutex<fluent::FluentArgs<'static>>>> {
|
||||
fn fluent_args_var(args: Vec<(Txt, BoxedVar<L10nArgument>)>) -> impl Var<ArcEq<Mutex<fluent::FluentArgs<'static>>>> {
|
||||
let mut fluent_args = MergeVarBuilder::new();
|
||||
let mut names = Vec::with_capacity(args.len());
|
||||
for (name, arg) in args {
|
||||
|
@ -344,7 +349,7 @@ fn fluent_args_var(args: Vec<(Txt, BoxedVar<L10nArgument>)>) -> impl Var<Arc<Mut
|
|||
}
|
||||
|
||||
// Mutex because ValueType is not Sync
|
||||
Arc::new(Mutex::new(args))
|
||||
ArcEq::new(Mutex::new(args))
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -140,7 +140,7 @@ impl L10nSource for L10nDir {
|
|||
self.dir_watch_status.clone()
|
||||
}
|
||||
|
||||
fn lang_resource(&mut self, lang: Lang, file: Txt) -> BoxedVar<Option<Arc<fluent::FluentResource>>> {
|
||||
fn lang_resource(&mut self, lang: Lang, file: Txt) -> BoxedVar<Option<ArcEq<fluent::FluentResource>>> {
|
||||
match self.res.entry((lang, file)) {
|
||||
std::collections::hash_map::Entry::Occupied(mut e) => {
|
||||
if let Some(out) = e.get().res.upgrade() {
|
||||
|
@ -173,7 +173,7 @@ impl L10nSource for L10nDir {
|
|||
}
|
||||
}
|
||||
struct L10nFile {
|
||||
res: BoxedWeakVar<Option<Arc<fluent::FluentResource>>>,
|
||||
res: BoxedWeakVar<Option<ArcEq<fluent::FluentResource>>>,
|
||||
status: ArcVar<LangResourceStatus>,
|
||||
}
|
||||
impl L10nFile {
|
||||
|
@ -184,7 +184,7 @@ impl L10nFile {
|
|||
}
|
||||
}
|
||||
}
|
||||
fn load_file(status: ArcVar<LangResourceStatus>, dir: &Path, lang: &Lang, file: &Txt) -> BoxedVar<Option<Arc<fluent::FluentResource>>> {
|
||||
fn load_file(status: ArcVar<LangResourceStatus>, dir: &Path, lang: &Lang, file: &Txt) -> BoxedVar<Option<ArcEq<fluent::FluentResource>>> {
|
||||
status.set_ne(LangResourceStatus::Loading);
|
||||
|
||||
let path = if file.is_empty() {
|
||||
|
@ -204,7 +204,7 @@ fn load_file(status: ArcVar<LangResourceStatus>, dir: &Path, lang: &Lang, file:
|
|||
Ok(flt) => {
|
||||
// ok
|
||||
// Loaded set by `r` to avoid race condition in waiter.
|
||||
return Some(Some(Arc::new(flt)));
|
||||
return Some(Some(ArcEq::new(flt)));
|
||||
}
|
||||
Err(e) => {
|
||||
let e = FluentParserErrors(e.1);
|
||||
|
@ -302,7 +302,7 @@ impl L10nSource for SwapL10nSource {
|
|||
self.available_langs_status.read_only().boxed()
|
||||
}
|
||||
|
||||
fn lang_resource(&mut self, lang: Lang, file: Txt) -> BoxedVar<Option<Arc<fluent::FluentResource>>> {
|
||||
fn lang_resource(&mut self, lang: Lang, file: Txt) -> BoxedVar<Option<ArcEq<fluent::FluentResource>>> {
|
||||
match self.res.entry((lang, file)) {
|
||||
std::collections::hash_map::Entry::Occupied(mut e) => {
|
||||
if let Some(res) = e.get().res.upgrade() {
|
||||
|
@ -366,7 +366,7 @@ impl L10nSource for SwapL10nSource {
|
|||
}
|
||||
}
|
||||
struct SwapFile {
|
||||
res: BoxedWeakVar<Option<Arc<fluent::FluentResource>>>,
|
||||
res: BoxedWeakVar<Option<ArcEq<fluent::FluentResource>>>,
|
||||
status: ArcVar<LangResourceStatus>,
|
||||
actual_weak_res: VarHandle,
|
||||
res_strong_actual: VarHandle,
|
||||
|
@ -395,7 +395,7 @@ impl L10nSource for NilL10nSource {
|
|||
LocalVar(LangResourceStatus::NotAvailable).boxed()
|
||||
}
|
||||
|
||||
fn lang_resource(&mut self, _: Lang, _: Txt) -> BoxedVar<Option<Arc<fluent::FluentResource>>> {
|
||||
fn lang_resource(&mut self, _: Lang, _: Txt) -> BoxedVar<Option<ArcEq<fluent::FluentResource>>> {
|
||||
LocalVar(None).boxed()
|
||||
}
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ impl LangResources {
|
|||
#[derive(Clone)]
|
||||
#[must_use = "resource can unload if dropped"]
|
||||
pub struct LangResource {
|
||||
pub(super) res: BoxedVar<Option<Arc<fluent::FluentResource>>>,
|
||||
pub(super) res: BoxedVar<Option<ArcEq<fluent::FluentResource>>>,
|
||||
pub(super) status: BoxedVar<LangResourceStatus>,
|
||||
}
|
||||
|
||||
|
@ -57,7 +57,7 @@ impl fmt::Debug for LangResource {
|
|||
}
|
||||
impl LangResource {
|
||||
/// Read-only variable with the resource.
|
||||
pub fn resource(&self) -> &BoxedVar<Option<Arc<fluent::FluentResource>>> {
|
||||
pub fn resource(&self) -> &BoxedVar<Option<ArcEq<fluent::FluentResource>>> {
|
||||
&self.res
|
||||
}
|
||||
|
||||
|
@ -184,7 +184,7 @@ impl L10nMessageBuilder {
|
|||
/// Represents an argument value for a localization message.
|
||||
///
|
||||
/// See [`L10nMessageBuilder::arg`] for more details.
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum L10nArgument {
|
||||
/// String.
|
||||
Txt(Txt),
|
||||
|
@ -549,6 +549,20 @@ impl<V> IntoIterator for LangMap<V> {
|
|||
self.inner.into_iter()
|
||||
}
|
||||
}
|
||||
impl<V: PartialEq> PartialEq for LangMap<V> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
if self.len() != other.len() {
|
||||
return false;
|
||||
}
|
||||
for (k, v) in &self.inner {
|
||||
if other.get_exact(k) != Some(v) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
impl<V: Eq> Eq for LangMap<V> {}
|
||||
|
||||
/// Errors found parsing a fluent resource file.
|
||||
#[derive(Clone, Debug)]
|
||||
|
|
|
@ -341,6 +341,19 @@ impl fmt::Debug for TextTransformFn {
|
|||
}
|
||||
}
|
||||
}
|
||||
impl PartialEq for TextTransformFn {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
// can only fail by returning `false` in some cases where the value pointer is actually equal.
|
||||
// see: https://github.com/rust-lang/rust/issues/103763
|
||||
//
|
||||
// we are fine with this, worst case is just an extra var update
|
||||
#[allow(clippy::vtable_address_comparisons)]
|
||||
(Self::Custom(l0), Self::Custom(r0)) => Arc::ptr_eq(l0, r0),
|
||||
_ => core::mem::discriminant(self) == core::mem::discriminant(other),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Text white space transform.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
|
||||
|
|
|
@ -26,7 +26,7 @@ pub const FEATURE_DISABLED: u32 = 0;
|
|||
type FontFeaturesMap = FxHashMap<FontFeatureName, u32>;
|
||||
|
||||
/// Font features configuration.
|
||||
#[derive(Default, Clone)]
|
||||
#[derive(Default, Clone, PartialEq)]
|
||||
pub struct FontFeatures(FontFeaturesMap);
|
||||
impl FontFeatures {
|
||||
/// New default.
|
||||
|
@ -1571,7 +1571,7 @@ pub type FontVariationName = &'static [u8; 4];
|
|||
/// A small map of font variations.
|
||||
///
|
||||
/// Use [`font_variations!`] to manually initialize.
|
||||
#[derive(Default, Clone)]
|
||||
#[derive(Default, Clone, PartialEq)]
|
||||
pub struct FontVariations(Vec<(FontVariationName, f32)>);
|
||||
impl FontVariations {
|
||||
/// New empty.
|
||||
|
|
|
@ -27,7 +27,7 @@ use crate::{
|
|||
l10n::LangMap,
|
||||
task,
|
||||
units::*,
|
||||
var::{response_done_var, var, AnyVar, ArcVar, ResponseVar, Var},
|
||||
var::{response_done_var, var, AnyVar, ArcVar, ResponseVar, Var, ArcEq},
|
||||
};
|
||||
|
||||
event! {
|
||||
|
@ -198,9 +198,9 @@ impl FONTS {
|
|||
///
|
||||
/// The returned response is already set if the font is [`CustomFont::from_bytes`] or [`CustomFont::from_other`] and the other
|
||||
/// is already loaded, otherwise the returned response will update once when the font finishes loading.
|
||||
pub fn register(&self, custom_font: CustomFont) -> ResponseVar<Result<(), Arc<FontLoadingError>>> {
|
||||
pub fn register(&self, custom_font: CustomFont) -> ResponseVar<Result<(), ArcEq<FontLoadingError>>> {
|
||||
task::poll_respond(async move {
|
||||
FontFaceLoader::register(custom_font).await.map_err(Arc::new)?;
|
||||
FontFaceLoader::register(custom_font).await.map_err(ArcEq::new)?;
|
||||
GENERIC_FONTS_SV.write().notify(FontChange::CustomFonts);
|
||||
Ok(())
|
||||
})
|
||||
|
|
|
@ -783,7 +783,7 @@ pub type TimerVar = ReadOnlyArcVar<Timer>;
|
|||
///
|
||||
/// This type uses interior mutability to communicate with the timer, the values provided by the methods
|
||||
/// can be changed anytime by the [`TimerVar`] owners without the variable updating.
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub struct Timer(TimerHandle);
|
||||
impl fmt::Debug for Timer {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
|
|
|
@ -667,7 +667,7 @@ impl FactorUnits for i32 {
|
|||
}
|
||||
|
||||
/// Scale factor applied to ***x*** and ***y*** dimensions.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub struct Factor2d {
|
||||
/// Scale factor applied in the ***x*** dimension.
|
||||
pub x: Factor,
|
||||
|
@ -949,7 +949,7 @@ impl ops::DivAssign<Factor2d> for DipRect {
|
|||
}
|
||||
|
||||
/// Scale factor applied to margins.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub struct FactorSideOffsets {
|
||||
/// Factor of top offset.
|
||||
pub top: Factor,
|
||||
|
|
|
@ -3,7 +3,7 @@ use std::fmt;
|
|||
use crate::impl_from_and_into_var;
|
||||
|
||||
/// Pixels-per-inch resolution.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||
#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct Ppi(pub f32);
|
||||
impl Ppi {
|
||||
|
@ -23,6 +23,16 @@ impl Default for Ppi {
|
|||
Ppi(96.0)
|
||||
}
|
||||
}
|
||||
impl PartialEq for Ppi {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
super::about_eq(self.0, other.0, 0.0001)
|
||||
}
|
||||
}
|
||||
impl std::hash::Hash for Ppi {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
super::about_eq_hash(self.0, 0.0001, state)
|
||||
}
|
||||
}
|
||||
|
||||
/// Pixels-per-meter resolution.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||
|
|
|
@ -17,12 +17,12 @@ use super::{AngleRadian, AngleUnits, Factor, Layout1d, Length, PxTransform};
|
|||
/// ```
|
||||
///
|
||||
///
|
||||
#[derive(Clone, Default, Debug, serde::Serialize, serde::Deserialize)]
|
||||
#[derive(Clone, Default, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||
pub struct Transform {
|
||||
parts: Vec<TransformPart>,
|
||||
needs_layout: bool,
|
||||
}
|
||||
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
|
||||
#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||
enum TransformPart {
|
||||
Computed(PxTransform),
|
||||
Translate(Length, Length),
|
||||
|
|
|
@ -121,8 +121,16 @@ pub mod types {
|
|||
///
|
||||
/// This trait is used like a type alias for traits and is
|
||||
/// already implemented for all types it applies to.
|
||||
pub trait VarValue: fmt::Debug + Clone + Any + Send + Sync {}
|
||||
impl<T: fmt::Debug + Clone + Any + Send + Sync> VarValue for T {}
|
||||
///
|
||||
/// # Implementing
|
||||
///
|
||||
/// Types need to be `Debug + Clone + PartialEq + Send + Sync + Any` to auto-implement this trait,
|
||||
/// if you want to place an external type in a variable and it does not implement all the traits
|
||||
/// you may need to declare a *newtype* wrapper, if the external type is `Debug + Send + Sync + Any` at
|
||||
/// least you can use the [`ArcEq<T>`] wrapper to quickly implement `Clone + PartialEq`, this is particularly
|
||||
/// useful for error types in [`ResponseVar<Result<_, E>>`].
|
||||
pub trait VarValue: fmt::Debug + Clone + PartialEq + Any + Send + Sync {}
|
||||
impl<T: fmt::Debug + Clone + Any + PartialEq + Send + Sync> VarValue for T {}
|
||||
|
||||
/// Trait implemented for all [`VarValue`] types.
|
||||
pub trait AnyVarValue: fmt::Debug + Any + Send + Sync {
|
||||
|
@ -415,6 +423,41 @@ impl IntoIterator for VarHandles {
|
|||
}
|
||||
}
|
||||
|
||||
/// Arc value that implements equality by pointer comparison.
|
||||
///
|
||||
/// This type allows types external types that are only `Debug + Send + Sync` to become
|
||||
/// a full [`VarValue`] to be allowed as a variable value.
|
||||
pub struct ArcEq<T: fmt::Debug + Send + Sync>(pub Arc<T>);
|
||||
impl<T: fmt::Debug + Send + Sync> ops::Deref for ArcEq<T> {
|
||||
type Target = Arc<T>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
impl<T: fmt::Debug + Send + Sync> ArcEq<T> {
|
||||
/// Constructs a new `ArcEq<T>`.
|
||||
pub fn new(value: T) -> Self {
|
||||
Self(Arc::new(value))
|
||||
}
|
||||
}
|
||||
impl<T: fmt::Debug + Send + Sync> PartialEq for ArcEq<T> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
Arc::ptr_eq(&self.0, &other.0)
|
||||
}
|
||||
}
|
||||
impl<T: fmt::Debug + Send + Sync> Eq for ArcEq<T> {}
|
||||
impl<T: fmt::Debug + Send + Sync> Clone for ArcEq<T> {
|
||||
fn clone(&self) -> Self {
|
||||
Self(Arc::clone(&self.0))
|
||||
}
|
||||
}
|
||||
impl<T: fmt::Debug + Send + Sync> fmt::Debug for ArcEq<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Debug::fmt(&*self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
/// Methods of [`Var<T>`] that don't depend on the value type.
|
||||
///
|
||||
/// This trait is [sealed] and cannot be implemented for types outside of `zero_ui_core`.
|
||||
|
@ -570,7 +613,7 @@ pub trait AnyVar: Any + Send + Sync + crate::private::Sealed {
|
|||
|
||||
/// Represents an [`AnyVar`] *pointer* that can be used for comparison.
|
||||
///
|
||||
/// If two of these values are equal, both variables point to the same *rc* or *context* at the moment of comparison.
|
||||
/// If two of these values are equal, both variables point to the same *arc* or *context* at the moment of comparison.
|
||||
pub struct VarPtr<'a> {
|
||||
_lt: std::marker::PhantomData<&'a ()>,
|
||||
eq: VarPtrData,
|
||||
|
|
|
@ -23,7 +23,7 @@ pub type ResponderVar<T> = ArcVar<Response<T>>;
|
|||
|
||||
pub type ResponseVar<T> = types::ReadOnlyVar<Response<T>, ArcVar<Response<T>>>;
|
||||
/// Raw value in a [`ResponseVar`] or [`ResponseSender`].
|
||||
#[derive(Clone, Copy)]
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
pub enum Response<T: VarValue> {
|
||||
/// Responder has not set the response yet.
|
||||
Waiting,
|
||||
|
|
|
@ -818,6 +818,11 @@ mod flat_map {
|
|||
pub bar: bool,
|
||||
pub var: ArcVar<usize>,
|
||||
}
|
||||
impl PartialEq for Foo {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.bar == other.bar && self.var.var_ptr() == other.var.var_ptr()
|
||||
}
|
||||
}
|
||||
impl fmt::Debug for Foo {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("Foo").field("bar", &self.bar).finish_non_exhaustive()
|
||||
|
|
|
@ -1109,7 +1109,7 @@ pub fn new_dyn_other<'a, T: Any + Send>(
|
|||
/// Error value used in a reference to an [`UiNode`] property input is made in `when` expression.
|
||||
///
|
||||
/// Only variables and values can be referenced in `when` expression.
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub struct UiNodeInWhenExprError;
|
||||
impl fmt::Debug for UiNodeInWhenExprError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
|
@ -1129,7 +1129,7 @@ impl std::error::Error for UiNodeInWhenExprError {}
|
|||
/// Error value used in a reference to an [`UiNodeList`] property input is made in `when` expression.
|
||||
///
|
||||
/// Only variables and values can be referenced in `when` expression.
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub struct UiNodeListInWhenExprError;
|
||||
impl fmt::Debug for UiNodeListInWhenExprError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
|
@ -1149,7 +1149,7 @@ impl std::error::Error for UiNodeListInWhenExprError {}
|
|||
/// Error value used in a reference to an [`UiNodeList`] property input is made in `when` expression.
|
||||
///
|
||||
/// Only variables and values can be referenced in `when` expression.
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub struct WidgetHandlerInWhenExprError;
|
||||
impl fmt::Debug for WidgetHandlerInWhenExprError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
|
|
|
@ -195,7 +195,7 @@ impl HeadlessAppWindowExt for HeadlessApp {
|
|||
{
|
||||
let response = WINDOWS.open(new_window);
|
||||
self.run_task(async move {
|
||||
let window_id = response.wait_rsp().await.window_id;
|
||||
let window_id = response.wait_rsp().await;
|
||||
if !WINDOWS.is_loaded(window_id) {
|
||||
let rcv = FRAME_IMAGE_READY_EVENT.receiver();
|
||||
while let Ok(args) = rcv.recv_async().await {
|
||||
|
|
|
@ -1619,7 +1619,7 @@ impl ContentCtrl {
|
|||
}
|
||||
|
||||
/// Run an `action` in the context of a monitor screen that is parent of this content.
|
||||
pub fn outer_layout<R>(&mut self, scale_factor: Factor, screen_ppi: f32, screen_size: PxSize, action: impl FnOnce() -> R) -> R {
|
||||
pub fn outer_layout<R>(&mut self, scale_factor: Factor, screen_ppi: Ppi, screen_size: PxSize, action: impl FnOnce() -> R) -> R {
|
||||
let metrics = LayoutMetrics::new(scale_factor, screen_size, Length::pt_to_px(11.0, scale_factor)).with_screen_ppi(screen_ppi);
|
||||
LAYOUT.with_context(metrics, action)
|
||||
}
|
||||
|
@ -1630,7 +1630,7 @@ impl ContentCtrl {
|
|||
&mut self,
|
||||
layout_widgets: Arc<LayoutUpdates>,
|
||||
scale_factor: Factor,
|
||||
screen_ppi: f32,
|
||||
screen_ppi: Ppi,
|
||||
min_size: PxSize,
|
||||
max_size: PxSize,
|
||||
size: PxSize,
|
||||
|
|
|
@ -93,9 +93,6 @@ app_local! {
|
|||
/// [`WindowManager`]: crate::window::WindowManager
|
||||
pub struct MONITORS;
|
||||
impl MONITORS {
|
||||
/// Initial PPI of monitors, `96.0`.
|
||||
pub const DEFAULT_PPI: f32 = 96.0;
|
||||
|
||||
/// Get monitor info.
|
||||
///
|
||||
/// Returns `None` if the monitor was not found or the app is running in headless mode without renderer.
|
||||
|
@ -169,7 +166,7 @@ impl MonitorsService {
|
|||
/// "Monitor" configuration used by windows in [headless mode].
|
||||
///
|
||||
/// [headless mode]: crate::window::WindowMode::is_headless
|
||||
#[derive(Clone, Copy)]
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
pub struct HeadlessMonitor {
|
||||
/// The scale factor used for the headless layout and rendering.
|
||||
///
|
||||
|
@ -191,11 +188,11 @@ pub struct HeadlessMonitor {
|
|||
/// Pixel-per-inches used for the headless layout and rendering.
|
||||
///
|
||||
/// [`MONITORS::DEFAULT_PPI`] by default.
|
||||
pub ppi: f32,
|
||||
pub ppi: Ppi,
|
||||
}
|
||||
impl fmt::Debug for HeadlessMonitor {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
if f.alternate() || about_eq(self.ppi, MONITORS::DEFAULT_PPI, 0.001) {
|
||||
if f.alternate() || self.ppi != Ppi::default() {
|
||||
f.debug_struct("HeadlessMonitor")
|
||||
.field("scale_factor", &self.scale_factor)
|
||||
.field("screen_size", &self.size)
|
||||
|
@ -212,7 +209,7 @@ impl HeadlessMonitor {
|
|||
HeadlessMonitor {
|
||||
scale_factor: None,
|
||||
size,
|
||||
ppi: MONITORS::DEFAULT_PPI,
|
||||
ppi: Ppi::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -221,7 +218,7 @@ impl HeadlessMonitor {
|
|||
HeadlessMonitor {
|
||||
scale_factor: Some(scale_factor),
|
||||
size,
|
||||
ppi: MONITORS::DEFAULT_PPI,
|
||||
ppi: Ppi::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -258,7 +255,7 @@ pub struct MonitorInfo {
|
|||
size: ArcVar<PxSize>,
|
||||
video_modes: ArcVar<Vec<VideoMode>>,
|
||||
scale_factor: ArcVar<Factor>,
|
||||
ppi: ArcVar<f32>,
|
||||
ppi: ArcVar<Ppi>,
|
||||
}
|
||||
impl fmt::Debug for MonitorInfo {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
|
@ -276,7 +273,7 @@ impl MonitorInfo {
|
|||
size: var(info.size),
|
||||
scale_factor: var(info.scale_factor.fct()),
|
||||
video_modes: var(info.video_modes),
|
||||
ppi: var(MONITORS::DEFAULT_PPI),
|
||||
ppi: var(Ppi::default()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -332,7 +329,7 @@ impl MonitorInfo {
|
|||
self.scale_factor.read_only()
|
||||
}
|
||||
/// PPI config var.
|
||||
pub fn ppi(&self) -> ArcVar<f32> {
|
||||
pub fn ppi(&self) -> ArcVar<Ppi> {
|
||||
self.ppi.clone()
|
||||
}
|
||||
|
||||
|
@ -366,7 +363,7 @@ impl MonitorInfo {
|
|||
size: var(defaults.size.to_px(fct.0)),
|
||||
video_modes: var(vec![]),
|
||||
scale_factor: var(fct),
|
||||
ppi: var(MONITORS::DEFAULT_PPI),
|
||||
ppi: var(Ppi::default()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -83,7 +83,7 @@ impl WindowsService {
|
|||
id: WindowId,
|
||||
new_window: UiTask<WindowRoot>,
|
||||
force_headless: Option<WindowMode>,
|
||||
) -> ResponseVar<WindowOpenArgs> {
|
||||
) -> ResponseVar<WindowId> {
|
||||
let (responder, response) = response_var();
|
||||
let request = OpenWindowRequest {
|
||||
id,
|
||||
|
@ -265,7 +265,7 @@ impl WINDOWS {
|
|||
///
|
||||
/// The `new_window` future runs in a [`UiTask`] inside the new [`WINDOW`] context.
|
||||
///
|
||||
/// Returns a response variable that will update once when the window is opened, note that while the `window_id` is
|
||||
/// Returns a response variable that will update once when the window is opened, note that while the [`WINDOW`] is
|
||||
/// available in the `new_window` argument already, the window is only available in this service after
|
||||
/// the returned variable updates. Also note that the window might not be fully [loaded] yet.
|
||||
///
|
||||
|
@ -273,7 +273,7 @@ impl WINDOWS {
|
|||
/// can use the context [`WINDOW`] to set variables that will be read on init with the new value.
|
||||
///
|
||||
/// [loaded]: Self::is_loaded
|
||||
pub fn open(&self, new_window: impl Future<Output = WindowRoot> + Send + 'static) -> ResponseVar<WindowOpenArgs> {
|
||||
pub fn open(&self, new_window: impl Future<Output = WindowRoot> + Send + 'static) -> ResponseVar<WindowId> {
|
||||
WINDOWS_SV
|
||||
.write()
|
||||
.open_impl(WindowId::new_unique(), UiTask::new(None, new_window), None)
|
||||
|
@ -288,7 +288,7 @@ impl WINDOWS {
|
|||
&self,
|
||||
window_id: impl Into<WindowId>,
|
||||
new_window: impl Future<Output = WindowRoot> + Send + 'static,
|
||||
) -> ResponseVar<WindowOpenArgs> {
|
||||
) -> ResponseVar<WindowId> {
|
||||
let window_id = window_id.into();
|
||||
self.assert_id_unused(window_id);
|
||||
WINDOWS_SV.write().open_impl(window_id, UiTask::new(None, new_window), None)
|
||||
|
@ -306,7 +306,7 @@ impl WINDOWS {
|
|||
&self,
|
||||
new_window: impl Future<Output = WindowRoot> + Send + 'static,
|
||||
with_renderer: bool,
|
||||
) -> ResponseVar<WindowOpenArgs> {
|
||||
) -> ResponseVar<WindowId> {
|
||||
WINDOWS_SV.write().open_impl(
|
||||
WindowId::new_unique(),
|
||||
UiTask::new(None, new_window),
|
||||
|
@ -328,7 +328,7 @@ impl WINDOWS {
|
|||
window_id: impl Into<WindowId>,
|
||||
new_window: impl Future<Output = WindowRoot> + Send + 'static,
|
||||
with_renderer: bool,
|
||||
) -> ResponseVar<WindowOpenArgs> {
|
||||
) -> ResponseVar<WindowId> {
|
||||
let window_id = window_id.into();
|
||||
self.assert_id_unused(window_id);
|
||||
WINDOWS_SV.write().open_impl(
|
||||
|
@ -554,7 +554,7 @@ impl WINDOWS {
|
|||
&self,
|
||||
window_id: impl Into<WindowId>,
|
||||
open: impl Future<Output = WindowRoot> + Send + 'static,
|
||||
) -> Option<ResponseVar<WindowOpenArgs>> {
|
||||
) -> Option<ResponseVar<WindowId>> {
|
||||
let window_id = window_id.into();
|
||||
if self.focus(window_id).is_ok() {
|
||||
None
|
||||
|
@ -864,14 +864,13 @@ impl WINDOWS {
|
|||
let window_id = task.ctx.id();
|
||||
let (window, info, responder) = task.finish(wns.open_loading.remove(&window_id).unwrap());
|
||||
|
||||
let args = WindowOpenArgs::now(window_id);
|
||||
if wns.windows.insert(window_id, window).is_some() {
|
||||
// id conflict resolved on request.
|
||||
unreachable!();
|
||||
}
|
||||
wns.windows_info.insert(info.id, info);
|
||||
|
||||
responder.respond(args.clone());
|
||||
responder.respond(window_id);
|
||||
// WINDOW_OPEN_EVENT.notify happens after init, so that handlers
|
||||
// on the window itself can subscribe to the event.
|
||||
} else {
|
||||
|
@ -1148,7 +1147,7 @@ struct OpenWindowRequest {
|
|||
id: WindowId,
|
||||
new: Mutex<UiTask<WindowRoot>>, // never locked, makes `OpenWindowRequest: Sync`
|
||||
force_headless: Option<WindowMode>,
|
||||
responder: ResponderVar<WindowOpenArgs>,
|
||||
responder: ResponderVar<WindowId>,
|
||||
}
|
||||
struct CloseWindowRequest {
|
||||
responder: ResponderVar<CloseWindowResult>,
|
||||
|
@ -1159,7 +1158,7 @@ struct AppWindowTask {
|
|||
ctx: WindowCtx,
|
||||
mode: WindowMode,
|
||||
task: Mutex<UiTask<WindowRoot>>, // never locked, used to make `AppWindowTask: Sync`
|
||||
responder: ResponderVar<WindowOpenArgs>,
|
||||
responder: ResponderVar<WindowId>,
|
||||
}
|
||||
impl AppWindowTask {
|
||||
fn new(
|
||||
|
@ -1167,7 +1166,7 @@ impl AppWindowTask {
|
|||
mode: WindowMode,
|
||||
color_scheme: ColorScheme,
|
||||
new: UiTask<WindowRoot>,
|
||||
responder: ResponderVar<WindowOpenArgs>,
|
||||
responder: ResponderVar<WindowId>,
|
||||
) -> Self {
|
||||
let primary_scale_factor = MONITORS
|
||||
.primary_monitor()
|
||||
|
@ -1198,7 +1197,7 @@ impl AppWindowTask {
|
|||
self.task.get_mut().is_ready()
|
||||
}
|
||||
|
||||
fn finish(self, loading: WindowLoading) -> (AppWindow, AppWindowInfo, ResponderVar<WindowOpenArgs>) {
|
||||
fn finish(self, loading: WindowLoading) -> (AppWindow, AppWindowInfo, ResponderVar<WindowId>) {
|
||||
let window = self.task.into_inner().into_result().unwrap_or_else(|_| panic!());
|
||||
let mut ctx = self.ctx;
|
||||
let mode = self.mode;
|
||||
|
|
|
@ -296,7 +296,7 @@ impl_from_and_into_var! {
|
|||
///
|
||||
/// The startup position affects the window once, at the moment the window
|
||||
/// is open just after the first [`UiNode::render`] call.
|
||||
#[derive(Clone, Copy, serde::Serialize, serde::Deserialize)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
||||
pub enum StartPosition {
|
||||
/// Resolves the `position` property.
|
||||
Default,
|
||||
|
|
|
@ -603,5 +603,11 @@ impl WindowVars {
|
|||
self.0.renderer_debug.clone()
|
||||
}
|
||||
}
|
||||
impl PartialEq for WindowVars {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
Arc::ptr_eq(&self.0, &other.0)
|
||||
}
|
||||
}
|
||||
impl Eq for WindowVars {}
|
||||
|
||||
pub(super) static WINDOW_VARS_ID: StaticStateId<WindowVars> = StaticStateId::new_unique();
|
||||
|
|
|
@ -91,6 +91,22 @@ pub struct IpcBytes {
|
|||
#[cfg(not(feature = "ipc"))]
|
||||
bytes: std::sync::Arc<Vec<u8>>,
|
||||
}
|
||||
/// Pointer equal.
|
||||
impl PartialEq for IpcBytes {
|
||||
#[cfg(not(feature = "ipc"))]
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
std::sync::Arc::ptr_eq(&self.bytes, &other.bytes)
|
||||
}
|
||||
|
||||
#[cfg(feature = "ipc")]
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (&self.bytes, &other.bytes) {
|
||||
(None, None) => true,
|
||||
(Some(a), Some(b)) => a.as_ptr() == b.as_ptr(),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl IpcBytes {
|
||||
/// Copy the `bytes` to a new shared memory allocation.
|
||||
pub fn from_slice(bytes: &[u8]) -> Self {
|
||||
|
|
|
@ -730,7 +730,7 @@ impl WindowState {
|
|||
}
|
||||
|
||||
/// [`Event::FrameRendered`] payload.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct EventFrameRendered {
|
||||
/// Window that was rendered.
|
||||
pub window: WindowId,
|
||||
|
@ -2080,7 +2080,7 @@ fn ppi_key(ppi: Option<ImagePpi>) -> Option<(u16, u16)> {
|
|||
/// Represents a successfully decoded image.
|
||||
///
|
||||
/// See [`Event::ImageLoaded`].
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
#[derive(Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct ImageLoadedData {
|
||||
/// Image ID.
|
||||
pub id: ImageId,
|
||||
|
|
|
@ -8,7 +8,7 @@ use crate::widgets::scroll::ScrollMode;
|
|||
/// See [`lazy`] property for more details.
|
||||
///
|
||||
/// [`lazy`]: fn@lazy
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub enum LazyMode {
|
||||
/// Node always loaded.
|
||||
Disabled,
|
||||
|
|
|
@ -311,7 +311,7 @@ pub fn img_loading_fn(child: impl UiNode, wgt_fn: impl IntoVar<WidgetFn<ImgLoadi
|
|||
/// Arguments for [`img_loading_fn`].
|
||||
///
|
||||
/// [`img_loading_fn`]: fn@img_loading_fn
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct ImgLoadingArgs {}
|
||||
|
||||
/// Arguments for [`on_load`].
|
||||
|
@ -324,7 +324,7 @@ pub struct ImgLoadArgs {}
|
|||
///
|
||||
/// [`on_error`]: fn@on_error
|
||||
/// [`img_error_fn`]: fn@img_error_fn
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct ImgErrorArgs {
|
||||
/// Error message.
|
||||
pub error: Txt,
|
||||
|
|
|
@ -232,8 +232,8 @@ pub fn image_presenter() -> impl UiNode {
|
|||
let mut scale = IMAGE_SCALE_VAR.get();
|
||||
if IMAGE_SCALE_PPI_VAR.get() {
|
||||
let sppi = metrics.screen_ppi();
|
||||
let ippi = CONTEXT_IMAGE_VAR.with(Img::ppi).unwrap_or(ImagePpi::splat(sppi));
|
||||
scale *= Factor2d::new(sppi / ippi.x, sppi / ippi.y);
|
||||
let ippi = CONTEXT_IMAGE_VAR.with(Img::ppi).unwrap_or(ImagePpi::splat(sppi.0));
|
||||
scale *= Factor2d::new(sppi.0 / ippi.x, sppi.0 / ippi.y);
|
||||
}
|
||||
if IMAGE_SCALE_FACTOR_VAR.get() {
|
||||
scale *= metrics.scale_factor();
|
||||
|
@ -261,8 +261,8 @@ pub fn image_presenter() -> impl UiNode {
|
|||
let mut scale = IMAGE_SCALE_VAR.get();
|
||||
if IMAGE_SCALE_PPI_VAR.get() {
|
||||
let sppi = metrics.screen_ppi();
|
||||
let ippi = CONTEXT_IMAGE_VAR.with(Img::ppi).unwrap_or(ImagePpi::splat(sppi));
|
||||
scale *= Factor2d::new(sppi / ippi.x, sppi / ippi.y);
|
||||
let ippi = CONTEXT_IMAGE_VAR.with(Img::ppi).unwrap_or(ImagePpi::splat(sppi.0));
|
||||
scale *= Factor2d::new(sppi.0 / ippi.x, sppi.0 / ippi.y);
|
||||
}
|
||||
if IMAGE_SCALE_FACTOR_VAR.get() {
|
||||
scale *= metrics.scale_factor();
|
||||
|
|
|
@ -26,7 +26,7 @@ use std::{fmt, mem, ops};
|
|||
/// [`stack::children_align`]: fn@crate::widgets::layouts::stack::children_align
|
||||
/// [`stack::spacing`]: fn@crate::widgets::layouts::stack::spacing
|
||||
/// [`Stack!`]: struct@crate::widgets::layouts::Stack
|
||||
#[derive(Default, Clone, serde::Serialize, serde::Deserialize)]
|
||||
#[derive(Default, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||
pub struct StackDirection {
|
||||
/// Point on the previous item where the next item is placed.
|
||||
pub place: Point,
|
||||
|
|
|
@ -98,6 +98,19 @@ impl fmt::Debug for ImageResolver {
|
|||
}
|
||||
}
|
||||
}
|
||||
impl PartialEq for ImageResolver {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
// can only fail by returning `false` in some cases where the value pointer is actually equal.
|
||||
// see: https://github.com/rust-lang/rust/issues/103763
|
||||
//
|
||||
// we are fine with this, worst case is just an extra var update
|
||||
#[allow(clippy::vtable_address_comparisons)]
|
||||
(Self::Resolve(l0), Self::Resolve(r0)) => Arc::ptr_eq(l0, r0),
|
||||
_ => core::mem::discriminant(self) == core::mem::discriminant(other),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Markdown link resolver.
|
||||
///
|
||||
|
@ -156,6 +169,19 @@ impl fmt::Debug for LinkResolver {
|
|||
}
|
||||
}
|
||||
}
|
||||
impl PartialEq for LinkResolver {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
// can only fail by returning `false` in some cases where the value pointer is actually equal.
|
||||
// see: https://github.com/rust-lang/rust/issues/103763
|
||||
//
|
||||
// we are fine with this, worst case is just an extra var update
|
||||
#[allow(clippy::vtable_address_comparisons)]
|
||||
(Self::Resolve(l0), Self::Resolve(r0)) => Arc::ptr_eq(l0, r0),
|
||||
_ => core::mem::discriminant(self) == core::mem::discriminant(other),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
event! {
|
||||
/// Event raised by markdown links when clicked.
|
||||
|
|
|
@ -169,7 +169,7 @@ command! {
|
|||
}
|
||||
|
||||
/// Parameters for the scroll and page commands.
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct ScrollRequest {
|
||||
/// If the [alt factor] should be applied to the base scroll unit when scrolling.
|
||||
///
|
||||
|
@ -231,7 +231,7 @@ impl_from_and_into_var! {
|
|||
}
|
||||
|
||||
/// Parameters for the [`SCROLL_TO_CMD`].
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct ScrollToRequest {
|
||||
/// Widget that will be scrolled into view.
|
||||
pub widget_id: WidgetId,
|
||||
|
@ -281,7 +281,7 @@ impl_from_and_into_var! {
|
|||
}
|
||||
|
||||
/// Defines how much the [`SCROLL_TO_CMD`] will scroll to showcase the target widget.
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum ScrollToMode {
|
||||
/// Scroll will change only just enough so that the widget inner rect is fully visible with the optional
|
||||
/// extra margin offsets.
|
||||
|
|
|
@ -227,7 +227,7 @@ pub fn auto_hide_extra(child: impl UiNode, extra: impl IntoVar<SideOffsets>) ->
|
|||
}
|
||||
|
||||
/// Arguments for scrollbar widget functions.
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct ScrollBarArgs {
|
||||
/// Scrollbar orientation.
|
||||
pub orientation: scrollbar::Orientation,
|
||||
|
|
|
@ -403,6 +403,16 @@ impl fmt::Debug for SmoothScrolling {
|
|||
.finish_non_exhaustive()
|
||||
}
|
||||
}
|
||||
impl PartialEq for SmoothScrolling {
|
||||
// can only fail by returning `false` in some cases where the value pointer is actually equal.
|
||||
// see: https://github.com/rust-lang/rust/issues/103763
|
||||
//
|
||||
// we are fine with this, worst case is just an extra var update
|
||||
#[allow(clippy::vtable_address_comparisons)]
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.duration == other.duration && Arc::ptr_eq(&self.easing, &other.easing)
|
||||
}
|
||||
}
|
||||
impl Default for SmoothScrolling {
|
||||
fn default() -> Self {
|
||||
Self::new(150.ms(), easing::linear)
|
||||
|
|
|
@ -287,6 +287,20 @@ impl Default for StyleFn {
|
|||
Self::nil()
|
||||
}
|
||||
}
|
||||
impl PartialEq for StyleFn {
|
||||
// can only fail by returning `false` in some cases where the value pointer is actually equal.
|
||||
// see: https://github.com/rust-lang/rust/issues/103763
|
||||
//
|
||||
// we are fine with this, worst case is just an extra var update
|
||||
#[allow(clippy::vtable_address_comparisons)]
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (&self.0, &other.0) {
|
||||
(None, None) => true,
|
||||
(Some(a), Some(b)) => Arc::ptr_eq(a, b),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl StyleFn {
|
||||
/// Default function, produces an empty style.
|
||||
pub fn nil() -> Self {
|
||||
|
|
|
@ -683,6 +683,11 @@ impl fmt::Debug for Selector {
|
|||
write!(f, "Selector(_)")
|
||||
}
|
||||
}
|
||||
impl PartialEq for Selector {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
Arc::ptr_eq(&self.0, &other.0)
|
||||
}
|
||||
}
|
||||
|
||||
/// Error for [`Selector`] operations.
|
||||
#[derive(Debug, Clone)]
|
||||
|
|
|
@ -43,6 +43,15 @@ impl<D> fmt::Debug for WidgetFn<D> {
|
|||
write!(f, "WidgetFn<{}>", pretty_type_name::<D>())
|
||||
}
|
||||
}
|
||||
impl<D> PartialEq for WidgetFn<D> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (&self.0, &other.0) {
|
||||
(None, None) => true,
|
||||
(Some(a), Some(b)) => Arc::ptr_eq(a, b),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<D> WidgetFn<D> {
|
||||
/// New from a closure that generates a node from data.
|
||||
pub fn new<U: UiNode>(func: impl Fn(D) -> U + Send + Sync + 'static) -> Self {
|
||||
|
|
|
@ -8,7 +8,7 @@ use std::time::Duration;
|
|||
/// Defines if a widget load affects the parent window load.
|
||||
///
|
||||
/// Widgets that support this behavior have a `block_window_load` property.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum BlockWindowLoad {
|
||||
/// Widget requests a [`WindowLoadingHandle`] and retains it until the widget is loaded.
|
||||
///
|
||||
|
|
|
@ -140,7 +140,7 @@ pub fn clear_color(child: impl UiNode, color: impl IntoVar<Rgba>) -> impl UiNode
|
|||
/// See the [`save_state`] property for more details.
|
||||
///
|
||||
/// [`save_state`]: fn@save_state
|
||||
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
|
||||
#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||
pub enum SaveState {
|
||||
/// Save & restore state.
|
||||
Enabled {
|
||||
|
|
Loading…
Reference in New Issue