Merge branch 'main' into disclosable-component
This commit is contained in:
commit
707ca34f19
139 changed files with 13495 additions and 1061 deletions
|
@ -7,42 +7,6 @@ pub mod test_app_context;
|
|||
pub(crate) mod window;
|
||||
mod window_input_handler;
|
||||
|
||||
use std::{
|
||||
any::{type_name, Any, TypeId},
|
||||
cell::RefCell,
|
||||
fmt::{self, Debug},
|
||||
hash::{Hash, Hasher},
|
||||
marker::PhantomData,
|
||||
mem,
|
||||
ops::{Deref, DerefMut, Range},
|
||||
path::{Path, PathBuf},
|
||||
pin::Pin,
|
||||
rc::{self, Rc},
|
||||
sync::{Arc, Weak},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
|
||||
use derive_more::Deref;
|
||||
use parking_lot::Mutex;
|
||||
use postage::oneshot;
|
||||
use smallvec::SmallVec;
|
||||
use smol::prelude::*;
|
||||
use util::ResultExt;
|
||||
use uuid::Uuid;
|
||||
|
||||
pub use action::*;
|
||||
use callback_collection::CallbackCollection;
|
||||
use collections::{hash_map::Entry, BTreeMap, HashMap, HashSet, VecDeque};
|
||||
pub use menu::*;
|
||||
use platform::Event;
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
use ref_counts::LeakDetector;
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
pub use test_app_context::{ContextHandle, TestAppContext};
|
||||
use window_input_handler::WindowInputHandler;
|
||||
|
||||
use crate::{
|
||||
elements::{AnyElement, AnyRootElement, RootElement},
|
||||
executor::{self, Task},
|
||||
|
@ -57,8 +21,39 @@ use crate::{
|
|||
window::{Window, WindowContext},
|
||||
AssetCache, AssetSource, ClipboardItem, FontCache, MouseRegionId,
|
||||
};
|
||||
|
||||
use self::ref_counts::RefCounts;
|
||||
pub use action::*;
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use callback_collection::CallbackCollection;
|
||||
use collections::{hash_map::Entry, BTreeMap, HashMap, HashSet, VecDeque};
|
||||
use derive_more::Deref;
|
||||
pub use menu::*;
|
||||
use parking_lot::Mutex;
|
||||
use platform::Event;
|
||||
use postage::oneshot;
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
use ref_counts::LeakDetector;
|
||||
use ref_counts::RefCounts;
|
||||
use smallvec::SmallVec;
|
||||
use smol::prelude::*;
|
||||
use std::{
|
||||
any::{type_name, Any, TypeId},
|
||||
cell::RefCell,
|
||||
fmt::{self, Debug},
|
||||
hash::{Hash, Hasher},
|
||||
marker::PhantomData,
|
||||
mem,
|
||||
ops::{Deref, DerefMut, Range},
|
||||
path::{Path, PathBuf},
|
||||
pin::Pin,
|
||||
rc::{self, Rc},
|
||||
sync::{Arc, Weak},
|
||||
time::Duration,
|
||||
};
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
pub use test_app_context::{ContextHandle, TestAppContext};
|
||||
use util::ResultExt;
|
||||
use uuid::Uuid;
|
||||
use window_input_handler::WindowInputHandler;
|
||||
|
||||
pub trait Entity: 'static {
|
||||
type Event;
|
||||
|
@ -73,10 +68,12 @@ pub trait Entity: 'static {
|
|||
}
|
||||
|
||||
pub trait View: Entity + Sized {
|
||||
fn ui_name() -> &'static str;
|
||||
fn render(&mut self, cx: &mut ViewContext<'_, '_, Self>) -> AnyElement<Self>;
|
||||
fn focus_in(&mut self, _: AnyViewHandle, _: &mut ViewContext<Self>) {}
|
||||
fn focus_out(&mut self, _: AnyViewHandle, _: &mut ViewContext<Self>) {}
|
||||
fn ui_name() -> &'static str {
|
||||
type_name::<Self>()
|
||||
}
|
||||
fn key_down(&mut self, _: &KeyDownEvent, _: &mut ViewContext<Self>) -> bool {
|
||||
false
|
||||
}
|
||||
|
@ -640,7 +637,7 @@ impl AppContext {
|
|||
pub fn add_action<A, V, F, R>(&mut self, handler: F)
|
||||
where
|
||||
A: Action,
|
||||
V: View,
|
||||
V: 'static,
|
||||
F: 'static + FnMut(&mut V, &A, &mut ViewContext<V>) -> R,
|
||||
{
|
||||
self.add_action_internal(handler, false)
|
||||
|
@ -649,7 +646,7 @@ impl AppContext {
|
|||
pub fn capture_action<A, V, F>(&mut self, handler: F)
|
||||
where
|
||||
A: Action,
|
||||
V: View,
|
||||
V: 'static,
|
||||
F: 'static + FnMut(&mut V, &A, &mut ViewContext<V>),
|
||||
{
|
||||
self.add_action_internal(handler, true)
|
||||
|
@ -658,7 +655,7 @@ impl AppContext {
|
|||
fn add_action_internal<A, V, F, R>(&mut self, mut handler: F, capture: bool)
|
||||
where
|
||||
A: Action,
|
||||
V: View,
|
||||
V: 'static,
|
||||
F: 'static + FnMut(&mut V, &A, &mut ViewContext<V>) -> R,
|
||||
{
|
||||
let handler = Box::new(
|
||||
|
@ -699,7 +696,7 @@ impl AppContext {
|
|||
pub fn add_async_action<A, V, F>(&mut self, mut handler: F)
|
||||
where
|
||||
A: Action,
|
||||
V: View,
|
||||
V: 'static,
|
||||
F: 'static + FnMut(&mut V, &A, &mut ViewContext<V>) -> Option<Task<Result<()>>>,
|
||||
{
|
||||
self.add_action(move |view, action, cx| {
|
||||
|
@ -898,8 +895,8 @@ impl AppContext {
|
|||
|
||||
fn observe_focus<F, V>(&mut self, handle: &ViewHandle<V>, mut callback: F) -> Subscription
|
||||
where
|
||||
V: 'static,
|
||||
F: 'static + FnMut(ViewHandle<V>, bool, &mut WindowContext) -> bool,
|
||||
V: View,
|
||||
{
|
||||
let subscription_id = post_inc(&mut self.next_subscription_id);
|
||||
let observed = handle.downgrade();
|
||||
|
@ -1382,15 +1379,15 @@ impl AppContext {
|
|||
self.windows.keys().copied()
|
||||
}
|
||||
|
||||
pub fn read_view<T: View>(&self, handle: &ViewHandle<T>) -> &T {
|
||||
pub fn read_view<V: 'static>(&self, handle: &ViewHandle<V>) -> &V {
|
||||
if let Some(view) = self.views.get(&(handle.window, handle.view_id)) {
|
||||
view.as_any().downcast_ref().expect("downcast is type safe")
|
||||
} else {
|
||||
panic!("circular view reference for type {}", type_name::<T>());
|
||||
panic!("circular view reference for type {}", type_name::<V>());
|
||||
}
|
||||
}
|
||||
|
||||
fn upgrade_view_handle<T: View>(&self, handle: &WeakViewHandle<T>) -> Option<ViewHandle<T>> {
|
||||
fn upgrade_view_handle<V: 'static>(&self, handle: &WeakViewHandle<V>) -> Option<ViewHandle<V>> {
|
||||
if self.ref_counts.lock().is_entity_alive(handle.view_id) {
|
||||
Some(ViewHandle::new(
|
||||
handle.window,
|
||||
|
@ -1659,6 +1656,9 @@ impl AppContext {
|
|||
subscription_id,
|
||||
callback,
|
||||
),
|
||||
Effect::RepaintWindow { window } => {
|
||||
self.handle_repaint_window_effect(window)
|
||||
}
|
||||
}
|
||||
self.pending_notifications.clear();
|
||||
} else {
|
||||
|
@ -1896,6 +1896,15 @@ impl AppContext {
|
|||
});
|
||||
}
|
||||
|
||||
fn handle_repaint_window_effect(&mut self, window: AnyWindowHandle) {
|
||||
self.update_window(window, |cx| {
|
||||
cx.layout(false).log_err();
|
||||
if let Some(scene) = cx.paint().log_err() {
|
||||
cx.window.platform_window.present_scene(scene);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn handle_window_activation_effect(&mut self, window: AnyWindowHandle, active: bool) -> bool {
|
||||
self.update_window(window, |cx| {
|
||||
if cx.window.is_active == active {
|
||||
|
@ -2151,7 +2160,7 @@ struct ViewMetadata {
|
|||
keymap_context: KeymapContext,
|
||||
}
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
#[derive(Default, Clone, Debug)]
|
||||
pub struct WindowInvalidation {
|
||||
pub updated: HashSet<usize>,
|
||||
pub removed: Vec<usize>,
|
||||
|
@ -2255,6 +2264,9 @@ pub enum Effect {
|
|||
window: AnyWindowHandle,
|
||||
is_active: bool,
|
||||
},
|
||||
RepaintWindow {
|
||||
window: AnyWindowHandle,
|
||||
},
|
||||
WindowActivationObservation {
|
||||
window: AnyWindowHandle,
|
||||
subscription_id: usize,
|
||||
|
@ -2448,6 +2460,10 @@ impl Debug for Effect {
|
|||
.debug_struct("Effect::ActiveLabeledTasksObservation")
|
||||
.field("subscription_id", subscription_id)
|
||||
.finish(),
|
||||
Effect::RepaintWindow { window } => f
|
||||
.debug_struct("Effect::RepaintWindow")
|
||||
.field("window_id", &window.id())
|
||||
.finish(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2543,10 +2559,7 @@ pub trait AnyView {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V> AnyView for V
|
||||
where
|
||||
V: View,
|
||||
{
|
||||
impl<V: View> AnyView for V {
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
|
@ -2878,7 +2891,7 @@ pub struct ViewContext<'a, 'b, T: ?Sized> {
|
|||
view_type: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<'a, 'b, T: View> Deref for ViewContext<'a, 'b, T> {
|
||||
impl<'a, 'b, V> Deref for ViewContext<'a, 'b, V> {
|
||||
type Target = WindowContext<'a>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
|
@ -2886,14 +2899,14 @@ impl<'a, 'b, T: View> Deref for ViewContext<'a, 'b, T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: View> DerefMut for ViewContext<'_, '_, T> {
|
||||
impl<'a, 'b, V> DerefMut for ViewContext<'a, 'b, V> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.window_context
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b, V: View> ViewContext<'a, 'b, V> {
|
||||
pub(crate) fn mutable(window_context: &'b mut WindowContext<'a>, view_id: usize) -> Self {
|
||||
impl<'a, 'b, V: 'static> ViewContext<'a, 'b, V> {
|
||||
pub fn mutable(window_context: &'b mut WindowContext<'a>, view_id: usize) -> Self {
|
||||
Self {
|
||||
window_context: Reference::Mutable(window_context),
|
||||
view_id,
|
||||
|
@ -2901,7 +2914,7 @@ impl<'a, 'b, V: View> ViewContext<'a, 'b, V> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn immutable(window_context: &'b WindowContext<'a>, view_id: usize) -> Self {
|
||||
pub fn immutable(window_context: &'b WindowContext<'a>, view_id: usize) -> Self {
|
||||
Self {
|
||||
window_context: Reference::Immutable(window_context),
|
||||
view_id,
|
||||
|
@ -2913,6 +2926,12 @@ impl<'a, 'b, V: View> ViewContext<'a, 'b, V> {
|
|||
&mut self.window_context
|
||||
}
|
||||
|
||||
pub fn notify(&mut self) {
|
||||
let window = self.window_handle;
|
||||
let view_id = self.view_id;
|
||||
self.window_context.notify_view(window, view_id);
|
||||
}
|
||||
|
||||
pub fn handle(&self) -> ViewHandle<V> {
|
||||
ViewHandle::new(
|
||||
self.window_handle,
|
||||
|
@ -3226,21 +3245,6 @@ impl<'a, 'b, V: View> ViewContext<'a, 'b, V> {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn emit(&mut self, payload: V::Event) {
|
||||
self.window_context
|
||||
.pending_effects
|
||||
.push_back(Effect::Event {
|
||||
entity_id: self.view_id,
|
||||
payload: Box::new(payload),
|
||||
});
|
||||
}
|
||||
|
||||
pub fn notify(&mut self) {
|
||||
let window = self.window_handle;
|
||||
let view_id = self.view_id;
|
||||
self.window_context.notify_view(window, view_id);
|
||||
}
|
||||
|
||||
pub fn defer(&mut self, callback: impl 'static + FnOnce(&mut V, &mut ViewContext<V>)) {
|
||||
let handle = self.handle();
|
||||
self.window_context
|
||||
|
@ -3341,6 +3345,10 @@ impl<'a, 'b, V: View> ViewContext<'a, 'b, V> {
|
|||
self.element_state::<Tag, T>(element_id, T::default())
|
||||
}
|
||||
|
||||
pub fn rem_pixels(&self) -> f32 {
|
||||
16.
|
||||
}
|
||||
|
||||
pub fn default_element_state_dynamic<T: 'static + Default>(
|
||||
&mut self,
|
||||
tag: TypeTag,
|
||||
|
@ -3350,6 +3358,17 @@ impl<'a, 'b, V: View> ViewContext<'a, 'b, V> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V: View> ViewContext<'_, '_, V> {
|
||||
pub fn emit(&mut self, event: V::Event) {
|
||||
self.window_context
|
||||
.pending_effects
|
||||
.push_back(Effect::Event {
|
||||
entity_id: self.view_id,
|
||||
payload: Box::new(event),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
pub struct TypeTag {
|
||||
tag: TypeId,
|
||||
|
@ -3428,15 +3447,27 @@ impl<V> BorrowWindowContext for ViewContext<'_, '_, V> {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct LayoutContext<'a, 'b, 'c, V: View> {
|
||||
view_context: &'c mut ViewContext<'a, 'b, V>,
|
||||
/// Methods shared by both LayoutContext and PaintContext
|
||||
///
|
||||
/// It's that PaintContext should be implemented in terms of layout context and
|
||||
/// deref to it, in which case we wouldn't need this.
|
||||
pub trait RenderContext<'a, 'b, V> {
|
||||
fn text_style(&self) -> TextStyle;
|
||||
fn push_text_style(&mut self, style: TextStyle);
|
||||
fn pop_text_style(&mut self);
|
||||
fn as_view_context(&mut self) -> &mut ViewContext<'a, 'b, V>;
|
||||
}
|
||||
|
||||
pub struct LayoutContext<'a, 'b, 'c, V> {
|
||||
// Nathan: Making this is public while I work on playground.
|
||||
pub view_context: &'c mut ViewContext<'a, 'b, V>,
|
||||
new_parents: &'c mut HashMap<usize, usize>,
|
||||
views_to_notify_if_ancestors_change: &'c mut HashMap<usize, SmallVec<[usize; 2]>>,
|
||||
text_style_stack: Vec<Arc<TextStyle>>,
|
||||
text_style_stack: Vec<TextStyle>,
|
||||
pub refreshing: bool,
|
||||
}
|
||||
|
||||
impl<'a, 'b, 'c, V: View> LayoutContext<'a, 'b, 'c, V> {
|
||||
impl<'a, 'b, 'c, V> LayoutContext<'a, 'b, 'c, V> {
|
||||
pub fn new(
|
||||
view_context: &'c mut ViewContext<'a, 'b, V>,
|
||||
new_parents: &'c mut HashMap<usize, usize>,
|
||||
|
@ -3500,26 +3531,39 @@ impl<'a, 'b, 'c, V: View> LayoutContext<'a, 'b, 'c, V> {
|
|||
.push(self_view_id);
|
||||
}
|
||||
|
||||
pub fn text_style(&self) -> Arc<TextStyle> {
|
||||
self.text_style_stack
|
||||
.last()
|
||||
.cloned()
|
||||
.unwrap_or(Default::default())
|
||||
}
|
||||
|
||||
pub fn with_text_style<S, F, T>(&mut self, style: S, f: F) -> T
|
||||
pub fn with_text_style<F, T>(&mut self, style: TextStyle, f: F) -> T
|
||||
where
|
||||
S: Into<Arc<TextStyle>>,
|
||||
F: FnOnce(&mut Self) -> T,
|
||||
{
|
||||
self.text_style_stack.push(style.into());
|
||||
self.push_text_style(style);
|
||||
let result = f(self);
|
||||
self.text_style_stack.pop();
|
||||
self.pop_text_style();
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b, 'c, V: View> Deref for LayoutContext<'a, 'b, 'c, V> {
|
||||
impl<'a, 'b, 'c, V> RenderContext<'a, 'b, V> for LayoutContext<'a, 'b, 'c, V> {
|
||||
fn text_style(&self) -> TextStyle {
|
||||
self.text_style_stack
|
||||
.last()
|
||||
.cloned()
|
||||
.unwrap_or(TextStyle::default(&self.font_cache))
|
||||
}
|
||||
|
||||
fn push_text_style(&mut self, style: TextStyle) {
|
||||
self.text_style_stack.push(style);
|
||||
}
|
||||
|
||||
fn pop_text_style(&mut self) {
|
||||
self.text_style_stack.pop();
|
||||
}
|
||||
|
||||
fn as_view_context(&mut self) -> &mut ViewContext<'a, 'b, V> {
|
||||
&mut self.view_context
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b, 'c, V> Deref for LayoutContext<'a, 'b, 'c, V> {
|
||||
type Target = ViewContext<'a, 'b, V>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
|
@ -3527,13 +3571,13 @@ impl<'a, 'b, 'c, V: View> Deref for LayoutContext<'a, 'b, 'c, V> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V: View> DerefMut for LayoutContext<'_, '_, '_, V> {
|
||||
impl<V> DerefMut for LayoutContext<'_, '_, '_, V> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.view_context
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: View> BorrowAppContext for LayoutContext<'_, '_, '_, V> {
|
||||
impl<V> BorrowAppContext for LayoutContext<'_, '_, '_, V> {
|
||||
fn read_with<T, F: FnOnce(&AppContext) -> T>(&self, f: F) -> T {
|
||||
BorrowAppContext::read_with(&*self.view_context, f)
|
||||
}
|
||||
|
@ -3543,7 +3587,7 @@ impl<V: View> BorrowAppContext for LayoutContext<'_, '_, '_, V> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V: View> BorrowWindowContext for LayoutContext<'_, '_, '_, V> {
|
||||
impl<V> BorrowWindowContext for LayoutContext<'_, '_, '_, V> {
|
||||
type Result<T> = T;
|
||||
|
||||
fn read_window<T, F: FnOnce(&WindowContext) -> T>(&self, window: AnyWindowHandle, f: F) -> T {
|
||||
|
@ -3573,39 +3617,42 @@ impl<V: View> BorrowWindowContext for LayoutContext<'_, '_, '_, V> {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct PaintContext<'a, 'b, 'c, V: View> {
|
||||
view_context: &'c mut ViewContext<'a, 'b, V>,
|
||||
text_style_stack: Vec<Arc<TextStyle>>,
|
||||
pub struct PaintContext<'a, 'b, 'c, V> {
|
||||
pub view_context: &'c mut ViewContext<'a, 'b, V>,
|
||||
text_style_stack: Vec<TextStyle>,
|
||||
}
|
||||
|
||||
impl<'a, 'b, 'c, V: View> PaintContext<'a, 'b, 'c, V> {
|
||||
impl<'a, 'b, 'c, V> PaintContext<'a, 'b, 'c, V> {
|
||||
pub fn new(view_context: &'c mut ViewContext<'a, 'b, V>) -> Self {
|
||||
Self {
|
||||
view_context,
|
||||
text_style_stack: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn text_style(&self) -> Arc<TextStyle> {
|
||||
impl<'a, 'b, 'c, V> RenderContext<'a, 'b, V> for PaintContext<'a, 'b, 'c, V> {
|
||||
fn text_style(&self) -> TextStyle {
|
||||
self.text_style_stack
|
||||
.last()
|
||||
.cloned()
|
||||
.unwrap_or(Default::default())
|
||||
.unwrap_or(TextStyle::default(&self.font_cache))
|
||||
}
|
||||
|
||||
pub fn with_text_style<S, F, T>(&mut self, style: S, f: F) -> T
|
||||
where
|
||||
S: Into<Arc<TextStyle>>,
|
||||
F: FnOnce(&mut Self) -> T,
|
||||
{
|
||||
self.text_style_stack.push(style.into());
|
||||
let result = f(self);
|
||||
fn push_text_style(&mut self, style: TextStyle) {
|
||||
self.text_style_stack.push(style);
|
||||
}
|
||||
|
||||
fn pop_text_style(&mut self) {
|
||||
self.text_style_stack.pop();
|
||||
result
|
||||
}
|
||||
|
||||
fn as_view_context(&mut self) -> &mut ViewContext<'a, 'b, V> {
|
||||
&mut self.view_context
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b, 'c, V: View> Deref for PaintContext<'a, 'b, 'c, V> {
|
||||
impl<'a, 'b, 'c, V> Deref for PaintContext<'a, 'b, 'c, V> {
|
||||
type Target = ViewContext<'a, 'b, V>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
|
@ -3613,13 +3660,13 @@ impl<'a, 'b, 'c, V: View> Deref for PaintContext<'a, 'b, 'c, V> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V: View> DerefMut for PaintContext<'_, '_, '_, V> {
|
||||
impl<V> DerefMut for PaintContext<'_, '_, '_, V> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.view_context
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: View> BorrowAppContext for PaintContext<'_, '_, '_, V> {
|
||||
impl<V> BorrowAppContext for PaintContext<'_, '_, '_, V> {
|
||||
fn read_with<T, F: FnOnce(&AppContext) -> T>(&self, f: F) -> T {
|
||||
BorrowAppContext::read_with(&*self.view_context, f)
|
||||
}
|
||||
|
@ -3629,7 +3676,7 @@ impl<V: View> BorrowAppContext for PaintContext<'_, '_, '_, V> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V: View> BorrowWindowContext for PaintContext<'_, '_, '_, V> {
|
||||
impl<V> BorrowWindowContext for PaintContext<'_, '_, '_, V> {
|
||||
type Result<T> = T;
|
||||
|
||||
fn read_window<T, F>(&self, window: AnyWindowHandle, f: F) -> Self::Result<T>
|
||||
|
@ -3661,25 +3708,37 @@ impl<V: View> BorrowWindowContext for PaintContext<'_, '_, '_, V> {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct EventContext<'a, 'b, 'c, V: View> {
|
||||
pub struct EventContext<'a, 'b, 'c, V> {
|
||||
view_context: &'c mut ViewContext<'a, 'b, V>,
|
||||
pub(crate) handled: bool,
|
||||
// I would like to replace handled with this.
|
||||
// Being additive for now.
|
||||
pub bubble: bool,
|
||||
}
|
||||
|
||||
impl<'a, 'b, 'c, V: View> EventContext<'a, 'b, 'c, V> {
|
||||
pub(crate) fn new(view_context: &'c mut ViewContext<'a, 'b, V>) -> Self {
|
||||
impl<'a, 'b, 'c, V: 'static> EventContext<'a, 'b, 'c, V> {
|
||||
pub fn new(view_context: &'c mut ViewContext<'a, 'b, V>) -> Self {
|
||||
EventContext {
|
||||
view_context,
|
||||
handled: true,
|
||||
bubble: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn propagate_event(&mut self) {
|
||||
self.handled = false;
|
||||
}
|
||||
|
||||
pub fn bubble_event(&mut self) {
|
||||
self.bubble = true;
|
||||
}
|
||||
|
||||
pub fn event_bubbled(&self) -> bool {
|
||||
self.bubble
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b, 'c, V: View> Deref for EventContext<'a, 'b, 'c, V> {
|
||||
impl<'a, 'b, 'c, V> Deref for EventContext<'a, 'b, 'c, V> {
|
||||
type Target = ViewContext<'a, 'b, V>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
|
@ -3687,13 +3746,13 @@ impl<'a, 'b, 'c, V: View> Deref for EventContext<'a, 'b, 'c, V> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V: View> DerefMut for EventContext<'_, '_, '_, V> {
|
||||
impl<V> DerefMut for EventContext<'_, '_, '_, V> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.view_context
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: View> BorrowAppContext for EventContext<'_, '_, '_, V> {
|
||||
impl<V> BorrowAppContext for EventContext<'_, '_, '_, V> {
|
||||
fn read_with<T, F: FnOnce(&AppContext) -> T>(&self, f: F) -> T {
|
||||
BorrowAppContext::read_with(&*self.view_context, f)
|
||||
}
|
||||
|
@ -3703,7 +3762,7 @@ impl<V: View> BorrowAppContext for EventContext<'_, '_, '_, V> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V: View> BorrowWindowContext for EventContext<'_, '_, '_, V> {
|
||||
impl<V> BorrowWindowContext for EventContext<'_, '_, '_, V> {
|
||||
type Result<T> = T;
|
||||
|
||||
fn read_window<T, F: FnOnce(&WindowContext) -> T>(&self, window: AnyWindowHandle, f: F) -> T {
|
||||
|
@ -4031,7 +4090,7 @@ impl<V> Clone for WindowHandle<V> {
|
|||
|
||||
impl<V> Copy for WindowHandle<V> {}
|
||||
|
||||
impl<V: View> WindowHandle<V> {
|
||||
impl<V: 'static> WindowHandle<V> {
|
||||
fn new(window_id: usize) -> Self {
|
||||
WindowHandle {
|
||||
any_handle: AnyWindowHandle::new(window_id, TypeId::of::<V>()),
|
||||
|
@ -4069,7 +4128,9 @@ impl<V: View> WindowHandle<V> {
|
|||
.update(cx, update)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: View> WindowHandle<V> {
|
||||
pub fn replace_root<C, F>(&self, cx: &mut C, build_root: F) -> C::Result<ViewHandle<V>>
|
||||
where
|
||||
C: BorrowWindowContext,
|
||||
|
@ -4149,7 +4210,7 @@ impl AnyWindowHandle {
|
|||
self.update(cx, |cx| cx.add_view(build_view))
|
||||
}
|
||||
|
||||
pub fn downcast<V: View>(self) -> Option<WindowHandle<V>> {
|
||||
pub fn downcast<V: 'static>(self) -> Option<WindowHandle<V>> {
|
||||
if self.root_view_type == TypeId::of::<V>() {
|
||||
Some(WindowHandle {
|
||||
any_handle: self,
|
||||
|
@ -4160,7 +4221,7 @@ impl AnyWindowHandle {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn root_is<V: View>(&self) -> bool {
|
||||
pub fn root_is<V: 'static>(&self) -> bool {
|
||||
self.root_view_type == TypeId::of::<V>()
|
||||
}
|
||||
|
||||
|
@ -4238,9 +4299,9 @@ impl AnyWindowHandle {
|
|||
}
|
||||
|
||||
#[repr(transparent)]
|
||||
pub struct ViewHandle<T> {
|
||||
pub struct ViewHandle<V> {
|
||||
any_handle: AnyViewHandle,
|
||||
view_type: PhantomData<T>,
|
||||
view_type: PhantomData<V>,
|
||||
}
|
||||
|
||||
impl<T> Deref for ViewHandle<T> {
|
||||
|
@ -4251,15 +4312,15 @@ impl<T> Deref for ViewHandle<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: View> ViewHandle<T> {
|
||||
impl<V: 'static> ViewHandle<V> {
|
||||
fn new(window: AnyWindowHandle, view_id: usize, ref_counts: &Arc<Mutex<RefCounts>>) -> Self {
|
||||
Self {
|
||||
any_handle: AnyViewHandle::new(window, view_id, TypeId::of::<T>(), ref_counts.clone()),
|
||||
any_handle: AnyViewHandle::new(window, view_id, TypeId::of::<V>(), ref_counts.clone()),
|
||||
view_type: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn downgrade(&self) -> WeakViewHandle<T> {
|
||||
pub fn downgrade(&self) -> WeakViewHandle<V> {
|
||||
WeakViewHandle::new(self.window, self.view_id)
|
||||
}
|
||||
|
||||
|
@ -4275,14 +4336,14 @@ impl<T: View> ViewHandle<T> {
|
|||
self.view_id
|
||||
}
|
||||
|
||||
pub fn read<'a>(&self, cx: &'a AppContext) -> &'a T {
|
||||
pub fn read<'a>(&self, cx: &'a AppContext) -> &'a V {
|
||||
cx.read_view(self)
|
||||
}
|
||||
|
||||
pub fn read_with<C, F, S>(&self, cx: &C, read: F) -> C::Result<S>
|
||||
where
|
||||
C: BorrowWindowContext,
|
||||
F: FnOnce(&T, &ViewContext<T>) -> S,
|
||||
F: FnOnce(&V, &ViewContext<V>) -> S,
|
||||
{
|
||||
cx.read_window(self.window, |cx| {
|
||||
let cx = ViewContext::immutable(cx, self.view_id);
|
||||
|
@ -4293,7 +4354,7 @@ impl<T: View> ViewHandle<T> {
|
|||
pub fn update<C, F, S>(&self, cx: &mut C, update: F) -> C::Result<S>
|
||||
where
|
||||
C: BorrowWindowContext,
|
||||
F: FnOnce(&mut T, &mut ViewContext<T>) -> S,
|
||||
F: FnOnce(&mut V, &mut ViewContext<V>) -> S,
|
||||
{
|
||||
let mut update = Some(update);
|
||||
|
||||
|
@ -4429,8 +4490,8 @@ impl AnyViewHandle {
|
|||
TypeId::of::<T>() == self.view_type
|
||||
}
|
||||
|
||||
pub fn downcast<T: View>(self) -> Option<ViewHandle<T>> {
|
||||
if self.is::<T>() {
|
||||
pub fn downcast<V: 'static>(self) -> Option<ViewHandle<V>> {
|
||||
if self.is::<V>() {
|
||||
Some(ViewHandle {
|
||||
any_handle: self,
|
||||
view_type: PhantomData,
|
||||
|
@ -4440,8 +4501,8 @@ impl AnyViewHandle {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn downcast_ref<T: View>(&self) -> Option<&ViewHandle<T>> {
|
||||
if self.is::<T>() {
|
||||
pub fn downcast_ref<V: 'static>(&self) -> Option<&ViewHandle<V>> {
|
||||
if self.is::<V>() {
|
||||
Some(unsafe { mem::transmute(self) })
|
||||
} else {
|
||||
None
|
||||
|
@ -4640,7 +4701,7 @@ impl<T> WeakHandle for WeakViewHandle<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V: View> WeakViewHandle<V> {
|
||||
impl<V: 'static> WeakViewHandle<V> {
|
||||
fn new(window: AnyWindowHandle, view_id: usize) -> Self {
|
||||
Self {
|
||||
any_handle: AnyWeakViewHandle {
|
||||
|
@ -4680,28 +4741,47 @@ impl<V: View> WeakViewHandle<V> {
|
|||
cx.read(|cx| {
|
||||
let handle = cx
|
||||
.upgrade_view_handle(self)
|
||||
.ok_or_else(|| anyhow!("view {} was dropped", V::ui_name()))?;
|
||||
.ok_or_else(|| anyhow!("view was dropped"))?;
|
||||
cx.read_window(self.window, |cx| handle.read_with(cx, read))
|
||||
.ok_or_else(|| anyhow!("window was removed"))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn update<T>(
|
||||
pub fn update<T, B>(
|
||||
&self,
|
||||
cx: &mut AsyncAppContext,
|
||||
cx: &mut B,
|
||||
update: impl FnOnce(&mut V, &mut ViewContext<V>) -> T,
|
||||
) -> Result<T> {
|
||||
cx.update(|cx| {
|
||||
let handle = cx
|
||||
.upgrade_view_handle(self)
|
||||
.ok_or_else(|| anyhow!("view {} was dropped", V::ui_name()))?;
|
||||
cx.update_window(self.window, |cx| handle.update(cx, update))
|
||||
.ok_or_else(|| anyhow!("window was removed"))
|
||||
) -> Result<T>
|
||||
where
|
||||
B: BorrowWindowContext,
|
||||
B::Result<Option<T>>: Flatten<T>,
|
||||
{
|
||||
cx.update_window(self.window(), |cx| {
|
||||
cx.upgrade_view_handle(self)
|
||||
.map(|handle| handle.update(cx, update))
|
||||
})
|
||||
.flatten()
|
||||
.ok_or_else(|| anyhow!("window was removed"))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Deref for WeakViewHandle<T> {
|
||||
pub trait Flatten<T> {
|
||||
fn flatten(self) -> Option<T>;
|
||||
}
|
||||
|
||||
impl<T> Flatten<T> for Option<Option<T>> {
|
||||
fn flatten(self) -> Option<T> {
|
||||
self.flatten()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Flatten<T> for Option<T> {
|
||||
fn flatten(self) -> Option<T> {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<V> Deref for WeakViewHandle<V> {
|
||||
type Target = AnyWeakViewHandle;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
|
@ -4709,7 +4789,7 @@ impl<T> Deref for WeakViewHandle<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> Clone for WeakViewHandle<T> {
|
||||
impl<V> Clone for WeakViewHandle<V> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
any_handle: self.any_handle.clone(),
|
||||
|
@ -5263,6 +5343,7 @@ mod tests {
|
|||
button: MouseButton::Left,
|
||||
modifiers: Default::default(),
|
||||
click_count: 1,
|
||||
is_down: true,
|
||||
}),
|
||||
false,
|
||||
);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::{
|
||||
elements::AnyRootElement,
|
||||
geometry::rect::RectF,
|
||||
geometry::{rect::RectF, Size},
|
||||
json::ToJson,
|
||||
keymap_matcher::{Binding, KeymapContext, Keystroke, MatchResult},
|
||||
platform::{
|
||||
|
@ -8,8 +8,9 @@ use crate::{
|
|||
MouseButton, MouseMovedEvent, PromptLevel, WindowBounds,
|
||||
},
|
||||
scene::{
|
||||
CursorRegion, MouseClick, MouseClickOut, MouseDown, MouseDownOut, MouseDrag, MouseEvent,
|
||||
MouseHover, MouseMove, MouseMoveOut, MouseScrollWheel, MouseUp, MouseUpOut, Scene,
|
||||
CursorRegion, EventHandler, MouseClick, MouseClickOut, MouseDown, MouseDownOut, MouseDrag,
|
||||
MouseEvent, MouseHover, MouseMove, MouseMoveOut, MouseScrollWheel, MouseUp, MouseUpOut,
|
||||
Scene,
|
||||
},
|
||||
text_layout::TextLayoutCache,
|
||||
util::post_inc,
|
||||
|
@ -31,7 +32,11 @@ use sqlez::{
|
|||
use std::{
|
||||
any::TypeId,
|
||||
mem,
|
||||
ops::{Deref, DerefMut, Range},
|
||||
ops::{Deref, DerefMut, Range, Sub},
|
||||
};
|
||||
use taffy::{
|
||||
tree::{Measurable, MeasureFunc},
|
||||
Taffy,
|
||||
};
|
||||
use util::ResultExt;
|
||||
use uuid::Uuid;
|
||||
|
@ -39,6 +44,7 @@ use uuid::Uuid;
|
|||
use super::{Reference, ViewMetadata};
|
||||
|
||||
pub struct Window {
|
||||
layout_engines: Vec<LayoutEngine>,
|
||||
pub(crate) root_view: Option<AnyViewHandle>,
|
||||
pub(crate) focused_view_id: Option<usize>,
|
||||
pub(crate) parents: HashMap<usize, usize>,
|
||||
|
@ -51,6 +57,7 @@ pub struct Window {
|
|||
appearance: Appearance,
|
||||
cursor_regions: Vec<CursorRegion>,
|
||||
mouse_regions: Vec<(MouseRegion, usize)>,
|
||||
event_handlers: Vec<EventHandler>,
|
||||
last_mouse_moved_event: Option<Event>,
|
||||
pub(crate) hovered_region_ids: Vec<MouseRegionId>,
|
||||
pub(crate) clicked_region_ids: Vec<MouseRegionId>,
|
||||
|
@ -67,12 +74,13 @@ impl Window {
|
|||
build_view: F,
|
||||
) -> Self
|
||||
where
|
||||
F: FnOnce(&mut ViewContext<V>) -> V,
|
||||
V: View,
|
||||
F: FnOnce(&mut ViewContext<V>) -> V,
|
||||
{
|
||||
let titlebar_height = platform_window.titlebar_height();
|
||||
let appearance = platform_window.appearance();
|
||||
let mut window = Self {
|
||||
layout_engines: Vec::new(),
|
||||
root_view: None,
|
||||
focused_view_id: None,
|
||||
parents: Default::default(),
|
||||
|
@ -83,6 +91,7 @@ impl Window {
|
|||
rendered_views: Default::default(),
|
||||
cursor_regions: Default::default(),
|
||||
mouse_regions: Default::default(),
|
||||
event_handlers: Default::default(),
|
||||
text_layout_cache: TextLayoutCache::new(cx.font_system.clone()),
|
||||
last_mouse_moved_event: None,
|
||||
hovered_region_ids: Default::default(),
|
||||
|
@ -109,6 +118,10 @@ impl Window {
|
|||
.as_ref()
|
||||
.expect("root_view called during window construction")
|
||||
}
|
||||
|
||||
pub fn take_event_handlers(&mut self) -> Vec<EventHandler> {
|
||||
mem::take(&mut self.event_handlers)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct WindowContext<'a> {
|
||||
|
@ -207,6 +220,24 @@ impl<'a> WindowContext<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn repaint(&mut self) {
|
||||
let window = self.window();
|
||||
self.pending_effects
|
||||
.push_back(Effect::RepaintWindow { window });
|
||||
}
|
||||
|
||||
pub fn layout_engine(&mut self) -> Option<&mut LayoutEngine> {
|
||||
self.window.layout_engines.last_mut()
|
||||
}
|
||||
|
||||
pub fn push_layout_engine(&mut self, engine: LayoutEngine) {
|
||||
self.window.layout_engines.push(engine);
|
||||
}
|
||||
|
||||
pub fn pop_layout_engine(&mut self) -> Option<LayoutEngine> {
|
||||
self.window.layout_engines.pop()
|
||||
}
|
||||
|
||||
pub fn remove_window(&mut self) {
|
||||
self.removed = true;
|
||||
}
|
||||
|
@ -227,6 +258,10 @@ impl<'a> WindowContext<'a> {
|
|||
self.window.platform_window.content_size()
|
||||
}
|
||||
|
||||
pub fn mouse_position(&self) -> Vector2F {
|
||||
self.window.mouse_position
|
||||
}
|
||||
|
||||
pub fn text_layout_cache(&self) -> &TextLayoutCache {
|
||||
&self.window.text_layout_cache
|
||||
}
|
||||
|
@ -242,14 +277,11 @@ impl<'a> WindowContext<'a> {
|
|||
Some(result)
|
||||
}
|
||||
|
||||
pub(crate) fn update_view<T, S>(
|
||||
pub(crate) fn update_view<V: 'static, S>(
|
||||
&mut self,
|
||||
handle: &ViewHandle<T>,
|
||||
update: &mut dyn FnMut(&mut T, &mut ViewContext<T>) -> S,
|
||||
) -> S
|
||||
where
|
||||
T: View,
|
||||
{
|
||||
handle: &ViewHandle<V>,
|
||||
update: &mut dyn FnMut(&mut V, &mut ViewContext<V>) -> S,
|
||||
) -> S {
|
||||
self.update_any_view(handle.view_id, |view, cx| {
|
||||
let mut cx = ViewContext::mutable(cx, handle.view_id);
|
||||
update(
|
||||
|
@ -475,6 +507,8 @@ impl<'a> WindowContext<'a> {
|
|||
}
|
||||
|
||||
pub(crate) fn dispatch_event(&mut self, event: Event, event_reused: bool) -> bool {
|
||||
self.dispatch_to_new_event_handlers(&event);
|
||||
|
||||
let mut mouse_events = SmallVec::<[_; 2]>::new();
|
||||
let mut notified_views: HashSet<usize> = Default::default();
|
||||
let handle = self.window_handle;
|
||||
|
@ -852,6 +886,18 @@ impl<'a> WindowContext<'a> {
|
|||
any_event_handled
|
||||
}
|
||||
|
||||
fn dispatch_to_new_event_handlers(&mut self, event: &Event) {
|
||||
if let Some(mouse_event) = event.mouse_event() {
|
||||
let event_handlers = self.window.take_event_handlers();
|
||||
for event_handler in event_handlers.iter().rev() {
|
||||
if event_handler.event_type == mouse_event.type_id() {
|
||||
(event_handler.handler)(mouse_event, self);
|
||||
}
|
||||
}
|
||||
self.window.event_handlers = event_handlers;
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn dispatch_key_down(&mut self, event: &KeyDownEvent) -> bool {
|
||||
let handle = self.window_handle;
|
||||
if let Some(focused_view_id) = self.window.focused_view_id {
|
||||
|
@ -942,14 +988,16 @@ impl<'a> WindowContext<'a> {
|
|||
Ok(element)
|
||||
}
|
||||
|
||||
pub(crate) fn layout(&mut self, refreshing: bool) -> Result<HashMap<usize, usize>> {
|
||||
pub fn layout(&mut self, refreshing: bool) -> Result<HashMap<usize, usize>> {
|
||||
let window_size = self.window.platform_window.content_size();
|
||||
let root_view_id = self.window.root_view().id();
|
||||
|
||||
let mut rendered_root = self.window.rendered_views.remove(&root_view_id).unwrap();
|
||||
|
||||
let mut new_parents = HashMap::default();
|
||||
let mut views_to_notify_if_ancestors_change = HashMap::default();
|
||||
rendered_root.layout(
|
||||
SizeConstraint::strict(window_size),
|
||||
SizeConstraint::new(window_size, window_size),
|
||||
&mut new_parents,
|
||||
&mut views_to_notify_if_ancestors_change,
|
||||
refreshing,
|
||||
|
@ -982,7 +1030,7 @@ impl<'a> WindowContext<'a> {
|
|||
Ok(old_parents)
|
||||
}
|
||||
|
||||
pub(crate) fn paint(&mut self) -> Result<Scene> {
|
||||
pub fn paint(&mut self) -> Result<Scene> {
|
||||
let window_size = self.window.platform_window.content_size();
|
||||
let scale_factor = self.window.platform_window.scale_factor();
|
||||
|
||||
|
@ -1001,9 +1049,10 @@ impl<'a> WindowContext<'a> {
|
|||
.insert(root_view_id, rendered_root);
|
||||
|
||||
self.window.text_layout_cache.finish_frame();
|
||||
let scene = scene_builder.build();
|
||||
let mut scene = scene_builder.build();
|
||||
self.window.cursor_regions = scene.cursor_regions();
|
||||
self.window.mouse_regions = scene.mouse_regions();
|
||||
self.window.event_handlers = scene.take_event_handlers();
|
||||
|
||||
if self.window_is_active() {
|
||||
if let Some(event) = self.window.last_mouse_moved_event.clone() {
|
||||
|
@ -1014,6 +1063,11 @@ impl<'a> WindowContext<'a> {
|
|||
Ok(scene)
|
||||
}
|
||||
|
||||
pub fn root_element(&self) -> &Box<dyn AnyRootElement> {
|
||||
let view_id = self.window.root_view().id();
|
||||
self.window.rendered_views.get(&view_id).unwrap()
|
||||
}
|
||||
|
||||
pub fn rect_for_text_range(&self, range_utf16: Range<usize>) -> Option<RectF> {
|
||||
let focused_view_id = self.window.focused_view_id?;
|
||||
self.window
|
||||
|
@ -1216,6 +1270,119 @@ impl<'a> WindowContext<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct LayoutEngine(Taffy);
|
||||
pub use taffy::style::Style as LayoutStyle;
|
||||
|
||||
impl LayoutEngine {
|
||||
pub fn new() -> Self {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
pub fn add_node<C>(&mut self, style: LayoutStyle, children: C) -> Result<LayoutId>
|
||||
where
|
||||
C: IntoIterator<Item = LayoutId>,
|
||||
{
|
||||
Ok(self
|
||||
.0
|
||||
.new_with_children(style, &children.into_iter().collect::<Vec<_>>())?)
|
||||
}
|
||||
|
||||
pub fn add_measured_node<F>(&mut self, style: LayoutStyle, measure: F) -> Result<LayoutId>
|
||||
where
|
||||
F: Fn(MeasureParams) -> Size<f32> + Sync + Send + 'static,
|
||||
{
|
||||
Ok(self
|
||||
.0
|
||||
.new_leaf_with_measure(style, MeasureFunc::Boxed(Box::new(MeasureFn(measure))))?)
|
||||
}
|
||||
|
||||
pub fn compute_layout(&mut self, root: LayoutId, available_space: Vector2F) -> Result<()> {
|
||||
self.0.compute_layout(
|
||||
root,
|
||||
taffy::geometry::Size {
|
||||
width: available_space.x().into(),
|
||||
height: available_space.y().into(),
|
||||
},
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn computed_layout(&mut self, node: LayoutId) -> Result<EngineLayout> {
|
||||
Ok(self.0.layout(node)?.into())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MeasureFn<F>(F);
|
||||
|
||||
impl<F: Send + Sync> Measurable for MeasureFn<F>
|
||||
where
|
||||
F: Fn(MeasureParams) -> Size<f32>,
|
||||
{
|
||||
fn measure(
|
||||
&self,
|
||||
known_dimensions: taffy::prelude::Size<Option<f32>>,
|
||||
available_space: taffy::prelude::Size<taffy::style::AvailableSpace>,
|
||||
) -> taffy::prelude::Size<f32> {
|
||||
(self.0)(MeasureParams {
|
||||
known_dimensions: known_dimensions.into(),
|
||||
available_space: available_space.into(),
|
||||
})
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct EngineLayout {
|
||||
pub bounds: RectF,
|
||||
pub order: u32,
|
||||
}
|
||||
|
||||
pub struct MeasureParams {
|
||||
pub known_dimensions: Size<Option<f32>>,
|
||||
pub available_space: Size<AvailableSpace>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum AvailableSpace {
|
||||
/// The amount of space available is the specified number of pixels
|
||||
Pixels(f32),
|
||||
/// The amount of space available is indefinite and the node should be laid out under a min-content constraint
|
||||
MinContent,
|
||||
/// The amount of space available is indefinite and the node should be laid out under a max-content constraint
|
||||
MaxContent,
|
||||
}
|
||||
|
||||
impl Default for AvailableSpace {
|
||||
fn default() -> Self {
|
||||
Self::Pixels(0.)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<taffy::prelude::AvailableSpace> for AvailableSpace {
|
||||
fn from(value: taffy::prelude::AvailableSpace) -> Self {
|
||||
match value {
|
||||
taffy::prelude::AvailableSpace::Definite(pixels) => Self::Pixels(pixels),
|
||||
taffy::prelude::AvailableSpace::MinContent => Self::MinContent,
|
||||
taffy::prelude::AvailableSpace::MaxContent => Self::MaxContent,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&taffy::tree::Layout> for EngineLayout {
|
||||
fn from(value: &taffy::tree::Layout) -> Self {
|
||||
Self {
|
||||
bounds: RectF::new(
|
||||
vec2f(value.location.x, value.location.y),
|
||||
vec2f(value.size.width, value.size.height),
|
||||
),
|
||||
order: value.order,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type LayoutId = taffy::prelude::NodeId;
|
||||
|
||||
pub struct RenderParams {
|
||||
pub view_id: usize,
|
||||
pub titlebar_height: f32,
|
||||
|
@ -1324,6 +1491,12 @@ impl SizeConstraint {
|
|||
max: size,
|
||||
}
|
||||
}
|
||||
pub fn loose(max: Vector2F) -> Self {
|
||||
Self {
|
||||
min: Vector2F::zero(),
|
||||
max,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn strict_along(axis: Axis, max: f32) -> Self {
|
||||
match axis {
|
||||
|
@ -1360,6 +1533,17 @@ impl SizeConstraint {
|
|||
}
|
||||
}
|
||||
|
||||
impl Sub<Vector2F> for SizeConstraint {
|
||||
type Output = SizeConstraint;
|
||||
|
||||
fn sub(self, rhs: Vector2F) -> SizeConstraint {
|
||||
SizeConstraint {
|
||||
min: self.min - rhs,
|
||||
max: self.max - rhs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for SizeConstraint {
|
||||
fn default() -> Self {
|
||||
SizeConstraint {
|
||||
|
@ -1378,6 +1562,7 @@ impl ToJson for SizeConstraint {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ChildView {
|
||||
view_id: usize,
|
||||
view_name: &'static str,
|
||||
|
@ -1393,7 +1578,7 @@ impl ChildView {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V: View> Element<V> for ChildView {
|
||||
impl<V: 'static> Element<V> for ChildView {
|
||||
type LayoutState = ();
|
||||
type PaintState = ();
|
||||
|
||||
|
|
|
@ -15,35 +15,75 @@ use serde_json::json;
|
|||
|
||||
#[derive(Clone, Copy, Default, PartialEq, Eq, Hash, PartialOrd, Ord, JsonSchema)]
|
||||
#[repr(transparent)]
|
||||
pub struct Color(#[schemars(with = "String")] ColorU);
|
||||
pub struct Color(#[schemars(with = "String")] pub ColorU);
|
||||
|
||||
pub fn color(rgba: u32) -> Color {
|
||||
Color::from_u32(rgba)
|
||||
}
|
||||
|
||||
pub fn rgb(r: f32, g: f32, b: f32) -> Color {
|
||||
Color(ColorF::new(r, g, b, 1.).to_u8())
|
||||
}
|
||||
|
||||
pub fn rgba(r: f32, g: f32, b: f32, a: f32) -> Color {
|
||||
Color(ColorF::new(r, g, b, a).to_u8())
|
||||
}
|
||||
|
||||
pub fn transparent_black() -> Color {
|
||||
Color(ColorU::transparent_black())
|
||||
}
|
||||
|
||||
pub fn black() -> Color {
|
||||
Color(ColorU::black())
|
||||
}
|
||||
|
||||
pub fn white() -> Color {
|
||||
Color(ColorU::white())
|
||||
}
|
||||
|
||||
pub fn red() -> Color {
|
||||
color(0xff0000ff)
|
||||
}
|
||||
|
||||
pub fn green() -> Color {
|
||||
color(0x00ff00ff)
|
||||
}
|
||||
|
||||
pub fn blue() -> Color {
|
||||
color(0x0000ffff)
|
||||
}
|
||||
|
||||
pub fn yellow() -> Color {
|
||||
color(0xffff00ff)
|
||||
}
|
||||
|
||||
impl Color {
|
||||
pub fn transparent_black() -> Self {
|
||||
Self(ColorU::transparent_black())
|
||||
transparent_black()
|
||||
}
|
||||
|
||||
pub fn black() -> Self {
|
||||
Self(ColorU::black())
|
||||
black()
|
||||
}
|
||||
|
||||
pub fn white() -> Self {
|
||||
Self(ColorU::white())
|
||||
white()
|
||||
}
|
||||
|
||||
pub fn red() -> Self {
|
||||
Self(ColorU::from_u32(0xff0000ff))
|
||||
Color::from_u32(0xff0000ff)
|
||||
}
|
||||
|
||||
pub fn green() -> Self {
|
||||
Self(ColorU::from_u32(0x00ff00ff))
|
||||
Color::from_u32(0x00ff00ff)
|
||||
}
|
||||
|
||||
pub fn blue() -> Self {
|
||||
Self(ColorU::from_u32(0x0000ffff))
|
||||
Color::from_u32(0x0000ffff)
|
||||
}
|
||||
|
||||
pub fn yellow() -> Self {
|
||||
Self(ColorU::from_u32(0xffff00ff))
|
||||
Color::from_u32(0xffff00ff)
|
||||
}
|
||||
|
||||
pub fn new(r: u8, g: u8, b: u8, a: u8) -> Self {
|
||||
|
@ -101,6 +141,12 @@ impl<'de> Deserialize<'de> for Color {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<u32> for Color {
|
||||
fn from(value: u32) -> Self {
|
||||
Self(ColorU::from_u32(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl ToJson for Color {
|
||||
fn to_json(&self) -> serde_json::Value {
|
||||
json!(format!(
|
||||
|
|
|
@ -34,7 +34,7 @@ use crate::{
|
|||
rect::RectF,
|
||||
vector::{vec2f, Vector2F},
|
||||
},
|
||||
json, Action, LayoutContext, PaintContext, SceneBuilder, SizeConstraint, TypeTag, View,
|
||||
json, Action, Entity, LayoutContext, PaintContext, SceneBuilder, SizeConstraint, TypeTag, View,
|
||||
ViewContext, WeakViewHandle, WindowContext,
|
||||
};
|
||||
use anyhow::{anyhow, Result};
|
||||
|
@ -42,14 +42,19 @@ use collections::HashMap;
|
|||
use core::panic;
|
||||
use json::ToJson;
|
||||
use smallvec::SmallVec;
|
||||
use std::{any::Any, borrow::Cow, mem, ops::Range};
|
||||
use std::{
|
||||
any::{type_name, Any},
|
||||
borrow::Cow,
|
||||
mem,
|
||||
ops::Range,
|
||||
};
|
||||
|
||||
pub trait Element<V: View>: 'static {
|
||||
pub trait Element<V: 'static>: 'static {
|
||||
type LayoutState;
|
||||
type PaintState;
|
||||
|
||||
fn view_name(&self) -> &'static str {
|
||||
V::ui_name()
|
||||
type_name::<V>()
|
||||
}
|
||||
|
||||
fn layout(
|
||||
|
@ -252,11 +257,7 @@ pub trait Element<V: View>: 'static {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait RenderElement {
|
||||
fn render<V: View>(&mut self, view: &mut V, cx: &mut ViewContext<V>) -> AnyElement<V>;
|
||||
}
|
||||
|
||||
trait AnyElementState<V: View> {
|
||||
trait AnyElementState<V> {
|
||||
fn layout(
|
||||
&mut self,
|
||||
constraint: SizeConstraint,
|
||||
|
@ -270,7 +271,7 @@ trait AnyElementState<V: View> {
|
|||
origin: Vector2F,
|
||||
visible_bounds: RectF,
|
||||
view: &mut V,
|
||||
cx: &mut ViewContext<V>,
|
||||
cx: &mut PaintContext<V>,
|
||||
);
|
||||
|
||||
fn rect_for_text_range(
|
||||
|
@ -287,7 +288,7 @@ trait AnyElementState<V: View> {
|
|||
fn metadata(&self) -> Option<&dyn Any>;
|
||||
}
|
||||
|
||||
enum ElementState<V: View, E: Element<V>> {
|
||||
enum ElementState<V: 'static, E: Element<V>> {
|
||||
Empty,
|
||||
Init {
|
||||
element: E,
|
||||
|
@ -308,7 +309,7 @@ enum ElementState<V: View, E: Element<V>> {
|
|||
},
|
||||
}
|
||||
|
||||
impl<V: View, E: Element<V>> AnyElementState<V> for ElementState<V, E> {
|
||||
impl<V, E: Element<V>> AnyElementState<V> for ElementState<V, E> {
|
||||
fn layout(
|
||||
&mut self,
|
||||
constraint: SizeConstraint,
|
||||
|
@ -351,7 +352,7 @@ impl<V: View, E: Element<V>> AnyElementState<V> for ElementState<V, E> {
|
|||
origin: Vector2F,
|
||||
visible_bounds: RectF,
|
||||
view: &mut V,
|
||||
cx: &mut ViewContext<V>,
|
||||
cx: &mut PaintContext<V>,
|
||||
) {
|
||||
*self = match mem::take(self) {
|
||||
ElementState::PostLayout {
|
||||
|
@ -490,18 +491,18 @@ impl<V: View, E: Element<V>> AnyElementState<V> for ElementState<V, E> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V: View, E: Element<V>> Default for ElementState<V, E> {
|
||||
impl<V, E: Element<V>> Default for ElementState<V, E> {
|
||||
fn default() -> Self {
|
||||
Self::Empty
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AnyElement<V: View> {
|
||||
pub struct AnyElement<V> {
|
||||
state: Box<dyn AnyElementState<V>>,
|
||||
name: Option<Cow<'static, str>>,
|
||||
}
|
||||
|
||||
impl<V: View> AnyElement<V> {
|
||||
impl<V> AnyElement<V> {
|
||||
pub fn name(&self) -> Option<&str> {
|
||||
self.name.as_deref()
|
||||
}
|
||||
|
@ -527,7 +528,7 @@ impl<V: View> AnyElement<V> {
|
|||
origin: Vector2F,
|
||||
visible_bounds: RectF,
|
||||
view: &mut V,
|
||||
cx: &mut ViewContext<V>,
|
||||
cx: &mut PaintContext<V>,
|
||||
) {
|
||||
self.state.paint(scene, origin, visible_bounds, view, cx);
|
||||
}
|
||||
|
@ -569,7 +570,7 @@ impl<V: View> AnyElement<V> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V: View> Element<V> for AnyElement<V> {
|
||||
impl<V: 'static> Element<V> for AnyElement<V> {
|
||||
type LayoutState = ();
|
||||
type PaintState = ();
|
||||
|
||||
|
@ -627,12 +628,18 @@ impl<V: View> Element<V> for AnyElement<V> {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct RootElement<V: View> {
|
||||
impl Entity for AnyElement<()> {
|
||||
type Event = ();
|
||||
}
|
||||
|
||||
// impl View for AnyElement<()> {}
|
||||
|
||||
pub struct RootElement<V> {
|
||||
element: AnyElement<V>,
|
||||
view: WeakViewHandle<V>,
|
||||
}
|
||||
|
||||
impl<V: View> RootElement<V> {
|
||||
impl<V> RootElement<V> {
|
||||
pub fn new(element: AnyElement<V>, view: WeakViewHandle<V>) -> Self {
|
||||
Self { element, view }
|
||||
}
|
||||
|
@ -700,7 +707,9 @@ impl<V: View> AnyRootElement for RootElement<V> {
|
|||
.ok_or_else(|| anyhow!("paint called on a root element for a dropped view"))?;
|
||||
|
||||
view.update(cx, |view, cx| {
|
||||
self.element.paint(scene, origin, visible_bounds, view, cx);
|
||||
let mut cx = PaintContext::new(cx);
|
||||
self.element
|
||||
.paint(scene, origin, visible_bounds, view, &mut cx);
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
@ -740,7 +749,7 @@ impl<V: View> AnyRootElement for RootElement<V> {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait ParentElement<'a, V: View>: Extend<AnyElement<V>> + Sized {
|
||||
pub trait ParentElement<'a, V: 'static>: Extend<AnyElement<V>> + Sized {
|
||||
fn add_children<E: Element<V>>(&mut self, children: impl IntoIterator<Item = E>) {
|
||||
self.extend(children.into_iter().map(|child| child.into_any()));
|
||||
}
|
||||
|
@ -760,7 +769,12 @@ pub trait ParentElement<'a, V: View>: Extend<AnyElement<V>> + Sized {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, V: View, T> ParentElement<'a, V> for T where T: Extend<AnyElement<V>> {}
|
||||
impl<'a, V, T> ParentElement<'a, V> for T
|
||||
where
|
||||
V: 'static,
|
||||
T: Extend<AnyElement<V>>,
|
||||
{
|
||||
}
|
||||
|
||||
pub fn constrain_size_preserving_aspect_ratio(max_size: Vector2F, size: Vector2F) -> Vector2F {
|
||||
if max_size.x().is_infinite() && max_size.y().is_infinite() {
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
use crate::{
|
||||
geometry::{rect::RectF, vector::Vector2F},
|
||||
json, AnyElement, Element, LayoutContext, PaintContext, SceneBuilder, SizeConstraint, View,
|
||||
json, AnyElement, Element, LayoutContext, PaintContext, SceneBuilder, SizeConstraint,
|
||||
ViewContext,
|
||||
};
|
||||
use json::ToJson;
|
||||
|
||||
use serde_json::json;
|
||||
|
||||
pub struct Align<V: View> {
|
||||
pub struct Align<V> {
|
||||
child: AnyElement<V>,
|
||||
alignment: Vector2F,
|
||||
}
|
||||
|
||||
impl<V: View> Align<V> {
|
||||
impl<V> Align<V> {
|
||||
pub fn new(child: AnyElement<V>) -> Self {
|
||||
Self {
|
||||
child,
|
||||
|
@ -41,7 +41,7 @@ impl<V: View> Align<V> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V: View> Element<V> for Align<V> {
|
||||
impl<V: 'static> Element<V> for Align<V> {
|
||||
type LayoutState = ();
|
||||
type PaintState = ();
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ use std::marker::PhantomData;
|
|||
use super::Element;
|
||||
use crate::{
|
||||
json::{self, json},
|
||||
PaintContext, SceneBuilder, View, ViewContext,
|
||||
PaintContext, SceneBuilder, ViewContext,
|
||||
};
|
||||
use json::ToJson;
|
||||
use pathfinder_geometry::{
|
||||
|
@ -15,7 +15,6 @@ pub struct Canvas<V, F>(F, PhantomData<V>);
|
|||
|
||||
impl<V, F> Canvas<V, F>
|
||||
where
|
||||
V: View,
|
||||
F: FnMut(&mut SceneBuilder, RectF, RectF, &mut V, &mut ViewContext<V>),
|
||||
{
|
||||
pub fn new(f: F) -> Self {
|
||||
|
@ -23,7 +22,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<V: View, F> Element<V> for Canvas<V, F>
|
||||
impl<V: 'static, F> Element<V> for Canvas<V, F>
|
||||
where
|
||||
F: 'static + FnMut(&mut SceneBuilder, RectF, RectF, &mut V, &mut ViewContext<V>),
|
||||
{
|
||||
|
|
|
@ -4,21 +4,21 @@ use pathfinder_geometry::{rect::RectF, vector::Vector2F};
|
|||
use serde_json::json;
|
||||
|
||||
use crate::{
|
||||
json, AnyElement, Element, LayoutContext, PaintContext, SceneBuilder, SizeConstraint, View,
|
||||
json, AnyElement, Element, LayoutContext, PaintContext, SceneBuilder, SizeConstraint,
|
||||
ViewContext,
|
||||
};
|
||||
|
||||
pub struct Clipped<V: View> {
|
||||
pub struct Clipped<V> {
|
||||
child: AnyElement<V>,
|
||||
}
|
||||
|
||||
impl<V: View> Clipped<V> {
|
||||
impl<V> Clipped<V> {
|
||||
pub fn new(child: AnyElement<V>) -> Self {
|
||||
Self { child }
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: View> Element<V> for Clipped<V> {
|
||||
impl<V: 'static> Element<V> for Clipped<V> {
|
||||
type LayoutState = ();
|
||||
type PaintState = ();
|
||||
|
||||
|
|
|
@ -3,17 +3,16 @@ use std::{any::Any, marker::PhantomData};
|
|||
use pathfinder_geometry::{rect::RectF, vector::Vector2F};
|
||||
|
||||
use crate::{
|
||||
AnyElement, Element, LayoutContext, PaintContext, SceneBuilder, SizeConstraint, View,
|
||||
ViewContext,
|
||||
AnyElement, Element, LayoutContext, PaintContext, SceneBuilder, SizeConstraint, ViewContext,
|
||||
};
|
||||
|
||||
use super::Empty;
|
||||
|
||||
/// The core stateless component trait, simply rendering an element tree
|
||||
pub trait Component {
|
||||
fn render<V: View>(self, cx: &mut ViewContext<V>) -> AnyElement<V>;
|
||||
fn render<V: 'static>(self, cx: &mut ViewContext<V>) -> AnyElement<V>;
|
||||
|
||||
fn element<V: View>(self) -> ComponentAdapter<V, Self>
|
||||
fn element<V: 'static>(self) -> ComponentAdapter<V, Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
|
@ -27,7 +26,7 @@ pub trait Component {
|
|||
StylableAdapter::new(self)
|
||||
}
|
||||
|
||||
fn stateful<V: View>(self) -> StatefulAdapter<Self, V>
|
||||
fn stateful<V: 'static>(self) -> StatefulAdapter<Self, V>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
|
@ -91,7 +90,7 @@ impl<C: Component> SafeStylable for StylableAdapter<C> {
|
|||
/// want to take click handler callbacks Unfortunately, the generic bound on the
|
||||
/// Component trait makes it incompatible with the stateless components above.
|
||||
// So let's just replicate them for now
|
||||
pub trait StatefulComponent<V: View> {
|
||||
pub trait StatefulComponent<V: 'static> {
|
||||
fn render(self, v: &mut V, cx: &mut ViewContext<V>) -> AnyElement<V>;
|
||||
|
||||
fn element(self) -> ComponentAdapter<V, Self>
|
||||
|
@ -118,21 +117,21 @@ pub trait StatefulComponent<V: View> {
|
|||
|
||||
/// It is trivial to convert stateless components to stateful components, so lets
|
||||
/// do so en masse. Note that the reverse is impossible without a helper.
|
||||
impl<V: View, C: Component> StatefulComponent<V> for C {
|
||||
impl<V: 'static, C: Component> StatefulComponent<V> for C {
|
||||
fn render(self, _: &mut V, cx: &mut ViewContext<V>) -> AnyElement<V> {
|
||||
self.render(cx)
|
||||
}
|
||||
}
|
||||
|
||||
/// Same as stylable, but generic over a view type
|
||||
pub trait StatefulStylable<V: View>: StatefulComponent<V> {
|
||||
pub trait StatefulStylable<V: 'static>: StatefulComponent<V> {
|
||||
type Style: Clone;
|
||||
|
||||
fn with_style(self, style: Self::Style) -> Self;
|
||||
}
|
||||
|
||||
/// Same as SafeStylable, but generic over a view type
|
||||
pub trait StatefulSafeStylable<V: View> {
|
||||
pub trait StatefulSafeStylable<V: 'static> {
|
||||
type Style: Clone;
|
||||
type Output: StatefulComponent<V>;
|
||||
|
||||
|
@ -140,7 +139,7 @@ pub trait StatefulSafeStylable<V: View> {
|
|||
}
|
||||
|
||||
/// Converting from stateless to stateful
|
||||
impl<V: View, C: SafeStylable> StatefulSafeStylable<V> for C {
|
||||
impl<V: 'static, C: SafeStylable> StatefulSafeStylable<V> for C {
|
||||
type Style = C::Style;
|
||||
|
||||
type Output = C::Output;
|
||||
|
@ -156,7 +155,7 @@ pub struct StatefulAdapter<C, V> {
|
|||
phantom: std::marker::PhantomData<V>,
|
||||
}
|
||||
|
||||
impl<C: Component, V: View> StatefulAdapter<C, V> {
|
||||
impl<C: Component, V: 'static> StatefulAdapter<C, V> {
|
||||
pub fn new(component: C) -> Self {
|
||||
Self {
|
||||
component,
|
||||
|
@ -165,7 +164,7 @@ impl<C: Component, V: View> StatefulAdapter<C, V> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<C: Component, V: View> StatefulComponent<V> for StatefulAdapter<C, V> {
|
||||
impl<C: Component, V: 'static> StatefulComponent<V> for StatefulAdapter<C, V> {
|
||||
fn render(self, _: &mut V, cx: &mut ViewContext<V>) -> AnyElement<V> {
|
||||
self.component.render(cx)
|
||||
}
|
||||
|
@ -173,12 +172,12 @@ impl<C: Component, V: View> StatefulComponent<V> for StatefulAdapter<C, V> {
|
|||
|
||||
// A helper for converting stateful but style-less components into stylable ones
|
||||
// by using `()` as the style type
|
||||
pub struct StatefulStylableAdapter<C: StatefulComponent<V>, V: View> {
|
||||
pub struct StatefulStylableAdapter<C: StatefulComponent<V>, V: 'static> {
|
||||
component: C,
|
||||
phantom: std::marker::PhantomData<V>,
|
||||
}
|
||||
|
||||
impl<C: StatefulComponent<V>, V: View> StatefulStylableAdapter<C, V> {
|
||||
impl<C: StatefulComponent<V>, V: 'static> StatefulStylableAdapter<C, V> {
|
||||
pub fn new(component: C) -> Self {
|
||||
Self {
|
||||
component,
|
||||
|
@ -187,7 +186,9 @@ impl<C: StatefulComponent<V>, V: View> StatefulStylableAdapter<C, V> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<C: StatefulComponent<V>, V: View> StatefulSafeStylable<V> for StatefulStylableAdapter<C, V> {
|
||||
impl<C: StatefulComponent<V>, V: 'static> StatefulSafeStylable<V>
|
||||
for StatefulStylableAdapter<C, V>
|
||||
{
|
||||
type Style = ();
|
||||
|
||||
type Output = C;
|
||||
|
@ -205,7 +206,7 @@ pub struct StatelessElementAdapter {
|
|||
}
|
||||
|
||||
impl StatelessElementAdapter {
|
||||
pub fn new<V: View>(element: AnyElement<V>) -> Self {
|
||||
pub fn new<V: 'static>(element: AnyElement<V>) -> Self {
|
||||
StatelessElementAdapter {
|
||||
element: Box::new(element) as Box<dyn Any>,
|
||||
}
|
||||
|
@ -213,7 +214,7 @@ impl StatelessElementAdapter {
|
|||
}
|
||||
|
||||
impl Component for StatelessElementAdapter {
|
||||
fn render<V: View>(self, _: &mut ViewContext<V>) -> AnyElement<V> {
|
||||
fn render<V: 'static>(self, _: &mut ViewContext<V>) -> AnyElement<V> {
|
||||
*self
|
||||
.element
|
||||
.downcast::<AnyElement<V>>()
|
||||
|
@ -222,12 +223,12 @@ impl Component for StatelessElementAdapter {
|
|||
}
|
||||
|
||||
// For converting elements into stateful components
|
||||
pub struct StatefulElementAdapter<V: View> {
|
||||
pub struct StatefulElementAdapter<V: 'static> {
|
||||
element: AnyElement<V>,
|
||||
_phantom: std::marker::PhantomData<V>,
|
||||
}
|
||||
|
||||
impl<V: View> StatefulElementAdapter<V> {
|
||||
impl<V: 'static> StatefulElementAdapter<V> {
|
||||
pub fn new(element: AnyElement<V>) -> Self {
|
||||
Self {
|
||||
element,
|
||||
|
@ -236,7 +237,7 @@ impl<V: View> StatefulElementAdapter<V> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V: View> StatefulComponent<V> for StatefulElementAdapter<V> {
|
||||
impl<V: 'static> StatefulComponent<V> for StatefulElementAdapter<V> {
|
||||
fn render(self, _: &mut V, _: &mut ViewContext<V>) -> AnyElement<V> {
|
||||
self.element
|
||||
}
|
||||
|
@ -244,7 +245,7 @@ impl<V: View> StatefulComponent<V> for StatefulElementAdapter<V> {
|
|||
|
||||
/// A convenient shorthand for creating an empty component.
|
||||
impl Component for () {
|
||||
fn render<V: View>(self, _: &mut ViewContext<V>) -> AnyElement<V> {
|
||||
fn render<V: 'static>(self, _: &mut ViewContext<V>) -> AnyElement<V> {
|
||||
Empty::new().into_any()
|
||||
}
|
||||
}
|
||||
|
@ -258,13 +259,13 @@ impl Stylable for () {
|
|||
}
|
||||
|
||||
// For converting components back into Elements
|
||||
pub struct ComponentAdapter<V: View, E> {
|
||||
pub struct ComponentAdapter<V: 'static, E> {
|
||||
component: Option<E>,
|
||||
element: Option<AnyElement<V>>,
|
||||
phantom: PhantomData<V>,
|
||||
}
|
||||
|
||||
impl<E, V: View> ComponentAdapter<V, E> {
|
||||
impl<E, V: 'static> ComponentAdapter<V, E> {
|
||||
pub fn new(e: E) -> Self {
|
||||
Self {
|
||||
component: Some(e),
|
||||
|
@ -274,7 +275,7 @@ impl<E, V: View> ComponentAdapter<V, E> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V: View, C: StatefulComponent<V> + 'static> Element<V> for ComponentAdapter<V, C> {
|
||||
impl<V: 'static, C: StatefulComponent<V> + 'static> Element<V> for ComponentAdapter<V, C> {
|
||||
type LayoutState = ();
|
||||
|
||||
type PaintState = ();
|
||||
|
|
|
@ -5,21 +5,21 @@ use serde_json::json;
|
|||
|
||||
use crate::{
|
||||
geometry::{rect::RectF, vector::Vector2F},
|
||||
json, AnyElement, Element, LayoutContext, PaintContext, SceneBuilder, SizeConstraint, View,
|
||||
json, AnyElement, Element, LayoutContext, PaintContext, SceneBuilder, SizeConstraint,
|
||||
ViewContext,
|
||||
};
|
||||
|
||||
pub struct ConstrainedBox<V: View> {
|
||||
pub struct ConstrainedBox<V> {
|
||||
child: AnyElement<V>,
|
||||
constraint: Constraint<V>,
|
||||
}
|
||||
|
||||
pub enum Constraint<V: View> {
|
||||
pub enum Constraint<V> {
|
||||
Static(SizeConstraint),
|
||||
Dynamic(Box<dyn FnMut(SizeConstraint, &mut V, &mut LayoutContext<V>) -> SizeConstraint>),
|
||||
}
|
||||
|
||||
impl<V: View> ToJson for Constraint<V> {
|
||||
impl<V> ToJson for Constraint<V> {
|
||||
fn to_json(&self) -> serde_json::Value {
|
||||
match self {
|
||||
Constraint::Static(constraint) => constraint.to_json(),
|
||||
|
@ -28,7 +28,7 @@ impl<V: View> ToJson for Constraint<V> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V: View> ConstrainedBox<V> {
|
||||
impl<V: 'static> ConstrainedBox<V> {
|
||||
pub fn new(child: impl Element<V>) -> Self {
|
||||
Self {
|
||||
child: child.into_any(),
|
||||
|
@ -132,7 +132,7 @@ impl<V: View> ConstrainedBox<V> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V: View> Element<V> for ConstrainedBox<V> {
|
||||
impl<V: 'static> Element<V> for ConstrainedBox<V> {
|
||||
type LayoutState = ();
|
||||
type PaintState = ();
|
||||
|
||||
|
|
|
@ -10,8 +10,7 @@ use crate::{
|
|||
json::ToJson,
|
||||
platform::CursorStyle,
|
||||
scene::{self, Border, CornerRadii, CursorRegion, Quad},
|
||||
AnyElement, Element, LayoutContext, PaintContext, SceneBuilder, SizeConstraint, View,
|
||||
ViewContext,
|
||||
AnyElement, Element, LayoutContext, PaintContext, SceneBuilder, SizeConstraint, ViewContext,
|
||||
};
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
|
@ -55,12 +54,12 @@ impl ContainerStyle {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct Container<V: View> {
|
||||
pub struct Container<V> {
|
||||
child: AnyElement<V>,
|
||||
style: ContainerStyle,
|
||||
}
|
||||
|
||||
impl<V: View> Container<V> {
|
||||
impl<V> Container<V> {
|
||||
pub fn new(child: AnyElement<V>) -> Self {
|
||||
Self {
|
||||
child,
|
||||
|
@ -207,7 +206,7 @@ impl<V: View> Container<V> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V: View> Element<V> for Container<V> {
|
||||
impl<V: 'static> Element<V> for Container<V> {
|
||||
type LayoutState = ();
|
||||
type PaintState = ();
|
||||
|
||||
|
@ -358,8 +357,8 @@ impl ToJson for ContainerStyle {
|
|||
#[derive(Clone, Copy, Debug, Default, JsonSchema)]
|
||||
pub struct Margin {
|
||||
pub top: f32,
|
||||
pub left: f32,
|
||||
pub bottom: f32,
|
||||
pub left: f32,
|
||||
pub right: f32,
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ use crate::{
|
|||
vector::{vec2f, Vector2F},
|
||||
},
|
||||
json::{json, ToJson},
|
||||
LayoutContext, PaintContext, SceneBuilder, View, ViewContext,
|
||||
LayoutContext, PaintContext, SceneBuilder, ViewContext,
|
||||
};
|
||||
use crate::{Element, SizeConstraint};
|
||||
|
||||
|
@ -26,7 +26,7 @@ impl Empty {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V: View> Element<V> for Empty {
|
||||
impl<V: 'static> Element<V> for Empty {
|
||||
type LayoutState = ();
|
||||
type PaintState = ();
|
||||
|
||||
|
|
|
@ -2,18 +2,18 @@ use std::ops::Range;
|
|||
|
||||
use crate::{
|
||||
geometry::{rect::RectF, vector::Vector2F},
|
||||
json, AnyElement, Element, LayoutContext, PaintContext, SceneBuilder, SizeConstraint, View,
|
||||
json, AnyElement, Element, LayoutContext, PaintContext, SceneBuilder, SizeConstraint,
|
||||
ViewContext,
|
||||
};
|
||||
use serde_json::json;
|
||||
|
||||
pub struct Expanded<V: View> {
|
||||
pub struct Expanded<V> {
|
||||
child: AnyElement<V>,
|
||||
full_width: bool,
|
||||
full_height: bool,
|
||||
}
|
||||
|
||||
impl<V: View> Expanded<V> {
|
||||
impl<V: 'static> Expanded<V> {
|
||||
pub fn new(child: impl Element<V>) -> Self {
|
||||
Self {
|
||||
child: child.into_any(),
|
||||
|
@ -35,7 +35,7 @@ impl<V: View> Expanded<V> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V: View> Element<V> for Expanded<V> {
|
||||
impl<V: 'static> Element<V> for Expanded<V> {
|
||||
type LayoutState = ();
|
||||
type PaintState = ();
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ use std::{any::Any, cell::Cell, f32::INFINITY, ops::Range, rc::Rc};
|
|||
use crate::{
|
||||
json::{self, ToJson, Value},
|
||||
AnyElement, Axis, Element, ElementStateHandle, LayoutContext, PaintContext, SceneBuilder,
|
||||
SizeConstraint, Vector2FExt, View, ViewContext,
|
||||
SizeConstraint, Vector2FExt, ViewContext,
|
||||
};
|
||||
use pathfinder_geometry::{
|
||||
rect::RectF,
|
||||
|
@ -17,7 +17,7 @@ struct ScrollState {
|
|||
scroll_position: Cell<f32>,
|
||||
}
|
||||
|
||||
pub struct Flex<V: View> {
|
||||
pub struct Flex<V> {
|
||||
axis: Axis,
|
||||
children: Vec<AnyElement<V>>,
|
||||
scroll_state: Option<(ElementStateHandle<Rc<ScrollState>>, usize)>,
|
||||
|
@ -25,7 +25,7 @@ pub struct Flex<V: View> {
|
|||
spacing: f32,
|
||||
}
|
||||
|
||||
impl<V: View> Flex<V> {
|
||||
impl<V: 'static> Flex<V> {
|
||||
pub fn new(axis: Axis) -> Self {
|
||||
Self {
|
||||
axis,
|
||||
|
@ -127,13 +127,13 @@ impl<V: View> Flex<V> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V: View> Extend<AnyElement<V>> for Flex<V> {
|
||||
impl<V> Extend<AnyElement<V>> for Flex<V> {
|
||||
fn extend<T: IntoIterator<Item = AnyElement<V>>>(&mut self, children: T) {
|
||||
self.children.extend(children);
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: View> Element<V> for Flex<V> {
|
||||
impl<V: 'static> Element<V> for Flex<V> {
|
||||
type LayoutState = f32;
|
||||
type PaintState = ();
|
||||
|
||||
|
@ -422,12 +422,12 @@ struct FlexParentData {
|
|||
float: bool,
|
||||
}
|
||||
|
||||
pub struct FlexItem<V: View> {
|
||||
pub struct FlexItem<V> {
|
||||
metadata: FlexParentData,
|
||||
child: AnyElement<V>,
|
||||
}
|
||||
|
||||
impl<V: View> FlexItem<V> {
|
||||
impl<V: 'static> FlexItem<V> {
|
||||
pub fn new(child: impl Element<V>) -> Self {
|
||||
FlexItem {
|
||||
metadata: FlexParentData {
|
||||
|
@ -449,7 +449,7 @@ impl<V: View> FlexItem<V> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V: View> Element<V> for FlexItem<V> {
|
||||
impl<V: 'static> Element<V> for FlexItem<V> {
|
||||
type LayoutState = ();
|
||||
type PaintState = ();
|
||||
|
||||
|
|
|
@ -3,16 +3,15 @@ use std::ops::Range;
|
|||
use crate::{
|
||||
geometry::{rect::RectF, vector::Vector2F},
|
||||
json::json,
|
||||
AnyElement, Element, LayoutContext, PaintContext, SceneBuilder, SizeConstraint, View,
|
||||
ViewContext,
|
||||
AnyElement, Element, LayoutContext, PaintContext, SceneBuilder, SizeConstraint, ViewContext,
|
||||
};
|
||||
|
||||
pub struct Hook<V: View> {
|
||||
pub struct Hook<V> {
|
||||
child: AnyElement<V>,
|
||||
after_layout: Option<Box<dyn FnMut(Vector2F, &mut ViewContext<V>)>>,
|
||||
}
|
||||
|
||||
impl<V: View> Hook<V> {
|
||||
impl<V: 'static> Hook<V> {
|
||||
pub fn new(child: impl Element<V>) -> Self {
|
||||
Self {
|
||||
child: child.into_any(),
|
||||
|
@ -29,7 +28,7 @@ impl<V: View> Hook<V> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V: View> Element<V> for Hook<V> {
|
||||
impl<V: 'static> Element<V> for Hook<V> {
|
||||
type LayoutState = ();
|
||||
type PaintState = ();
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ use crate::{
|
|||
},
|
||||
json::{json, ToJson},
|
||||
scene, Border, Element, ImageData, LayoutContext, PaintContext, SceneBuilder, SizeConstraint,
|
||||
View, ViewContext,
|
||||
ViewContext,
|
||||
};
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
|
@ -57,7 +57,7 @@ impl Image {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V: View> Element<V> for Image {
|
||||
impl<V: 'static> Element<V> for Image {
|
||||
type LayoutState = Option<Arc<ImageData>>;
|
||||
type PaintState = ();
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ impl KeystrokeLabel {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V: View> Element<V> for KeystrokeLabel {
|
||||
impl<V: 'static> Element<V> for KeystrokeLabel {
|
||||
type LayoutState = AnyElement<V>;
|
||||
type PaintState = ();
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ use crate::{
|
|||
},
|
||||
json::{ToJson, Value},
|
||||
text_layout::{Line, RunStyle},
|
||||
Element, LayoutContext, PaintContext, SceneBuilder, SizeConstraint, View, ViewContext,
|
||||
Element, LayoutContext, PaintContext, SceneBuilder, SizeConstraint, ViewContext,
|
||||
};
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
|
@ -128,7 +128,7 @@ impl Label {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V: View> Element<V> for Label {
|
||||
impl<V: 'static> Element<V> for Label {
|
||||
type LayoutState = Line;
|
||||
type PaintState = ();
|
||||
|
||||
|
|
|
@ -5,16 +5,16 @@ use crate::{
|
|||
},
|
||||
json::json,
|
||||
AnyElement, Element, LayoutContext, MouseRegion, PaintContext, SceneBuilder, SizeConstraint,
|
||||
View, ViewContext,
|
||||
ViewContext,
|
||||
};
|
||||
use std::{cell::RefCell, collections::VecDeque, fmt::Debug, ops::Range, rc::Rc};
|
||||
use sum_tree::{Bias, SumTree};
|
||||
|
||||
pub struct List<V: View> {
|
||||
pub struct List<V> {
|
||||
state: ListState<V>,
|
||||
}
|
||||
|
||||
pub struct ListState<V: View>(Rc<RefCell<StateInner<V>>>);
|
||||
pub struct ListState<V>(Rc<RefCell<StateInner<V>>>);
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub enum Orientation {
|
||||
|
@ -22,7 +22,7 @@ pub enum Orientation {
|
|||
Bottom,
|
||||
}
|
||||
|
||||
struct StateInner<V: View> {
|
||||
struct StateInner<V> {
|
||||
last_layout_width: Option<f32>,
|
||||
render_item: Box<dyn FnMut(&mut V, usize, &mut ViewContext<V>) -> AnyElement<V>>,
|
||||
rendered_range: Range<usize>,
|
||||
|
@ -40,13 +40,13 @@ pub struct ListOffset {
|
|||
pub offset_in_item: f32,
|
||||
}
|
||||
|
||||
enum ListItem<V: View> {
|
||||
enum ListItem<V> {
|
||||
Unrendered,
|
||||
Rendered(Rc<RefCell<AnyElement<V>>>),
|
||||
Removed(f32),
|
||||
}
|
||||
|
||||
impl<V: View> Clone for ListItem<V> {
|
||||
impl<V> Clone for ListItem<V> {
|
||||
fn clone(&self) -> Self {
|
||||
match self {
|
||||
Self::Unrendered => Self::Unrendered,
|
||||
|
@ -56,7 +56,7 @@ impl<V: View> Clone for ListItem<V> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V: View> Debug for ListItem<V> {
|
||||
impl<V> Debug for ListItem<V> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Unrendered => write!(f, "Unrendered"),
|
||||
|
@ -86,13 +86,13 @@ struct UnrenderedCount(usize);
|
|||
#[derive(Clone, Debug, Default)]
|
||||
struct Height(f32);
|
||||
|
||||
impl<V: View> List<V> {
|
||||
impl<V> List<V> {
|
||||
pub fn new(state: ListState<V>) -> Self {
|
||||
Self { state }
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: View> Element<V> for List<V> {
|
||||
impl<V: 'static> Element<V> for List<V> {
|
||||
type LayoutState = ListOffset;
|
||||
type PaintState = ();
|
||||
|
||||
|
@ -347,7 +347,7 @@ impl<V: View> Element<V> for List<V> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V: View> ListState<V> {
|
||||
impl<V: 'static> ListState<V> {
|
||||
pub fn new<D, F>(
|
||||
element_count: usize,
|
||||
orientation: Orientation,
|
||||
|
@ -440,13 +440,13 @@ impl<V: View> ListState<V> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V: View> Clone for ListState<V> {
|
||||
impl<V> Clone for ListState<V> {
|
||||
fn clone(&self) -> Self {
|
||||
Self(self.0.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: View> StateInner<V> {
|
||||
impl<V: 'static> StateInner<V> {
|
||||
fn render_item(
|
||||
&mut self,
|
||||
ix: usize,
|
||||
|
@ -560,7 +560,7 @@ impl<V: View> StateInner<V> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V: View> ListItem<V> {
|
||||
impl<V> ListItem<V> {
|
||||
fn remove(&self) -> Self {
|
||||
match self {
|
||||
ListItem::Unrendered => ListItem::Unrendered,
|
||||
|
@ -570,7 +570,7 @@ impl<V: View> ListItem<V> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V: View> sum_tree::Item for ListItem<V> {
|
||||
impl<V> sum_tree::Item for ListItem<V> {
|
||||
type Summary = ListItemSummary;
|
||||
|
||||
fn summary(&self) -> Self::Summary {
|
||||
|
@ -944,7 +944,7 @@ mod tests {
|
|||
type Event = ();
|
||||
}
|
||||
|
||||
impl View for TestView {
|
||||
impl crate::View for TestView {
|
||||
fn ui_name() -> &'static str {
|
||||
"TestView"
|
||||
}
|
||||
|
@ -968,7 +968,7 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V: View> Element<V> for TestElement {
|
||||
impl<V: 'static> Element<V> for TestElement {
|
||||
type LayoutState = ();
|
||||
type PaintState = ();
|
||||
|
||||
|
|
|
@ -11,12 +11,12 @@ use crate::{
|
|||
MouseHover, MouseMove, MouseMoveOut, MouseScrollWheel, MouseUp, MouseUpOut,
|
||||
},
|
||||
AnyElement, Element, EventContext, LayoutContext, MouseRegion, MouseState, PaintContext,
|
||||
SceneBuilder, SizeConstraint, TypeTag, View, ViewContext,
|
||||
SceneBuilder, SizeConstraint, TypeTag, ViewContext,
|
||||
};
|
||||
use serde_json::json;
|
||||
use std::ops::Range;
|
||||
|
||||
pub struct MouseEventHandler<V: View> {
|
||||
pub struct MouseEventHandler<V: 'static> {
|
||||
child: AnyElement<V>,
|
||||
region_id: usize,
|
||||
cursor_style: Option<CursorStyle>,
|
||||
|
@ -31,7 +31,7 @@ pub struct MouseEventHandler<V: View> {
|
|||
|
||||
/// Element which provides a render_child callback with a MouseState and paints a mouse
|
||||
/// region under (or above) it for easy mouse event handling.
|
||||
impl<V: View> MouseEventHandler<V> {
|
||||
impl<V: 'static> MouseEventHandler<V> {
|
||||
pub fn for_child<Tag: 'static>(child: impl Element<V>, region_id: usize) -> Self {
|
||||
Self {
|
||||
child: child.into_any(),
|
||||
|
@ -267,7 +267,7 @@ impl<V: View> MouseEventHandler<V> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V: View> Element<V> for MouseEventHandler<V> {
|
||||
impl<V: 'static> Element<V> for MouseEventHandler<V> {
|
||||
type LayoutState = ();
|
||||
type PaintState = ();
|
||||
|
||||
|
|
|
@ -4,11 +4,11 @@ use crate::{
|
|||
geometry::{rect::RectF, vector::Vector2F},
|
||||
json::ToJson,
|
||||
AnyElement, Axis, Element, LayoutContext, MouseRegion, PaintContext, SceneBuilder,
|
||||
SizeConstraint, View, ViewContext,
|
||||
SizeConstraint, ViewContext,
|
||||
};
|
||||
use serde_json::json;
|
||||
|
||||
pub struct Overlay<V: View> {
|
||||
pub struct Overlay<V> {
|
||||
child: AnyElement<V>,
|
||||
anchor_position: Option<Vector2F>,
|
||||
anchor_corner: AnchorCorner,
|
||||
|
@ -73,7 +73,7 @@ impl AnchorCorner {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V: View> Overlay<V> {
|
||||
impl<V: 'static> Overlay<V> {
|
||||
pub fn new(child: impl Element<V>) -> Self {
|
||||
Self {
|
||||
child: child.into_any(),
|
||||
|
@ -117,7 +117,7 @@ impl<V: View> Overlay<V> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V: View> Element<V> for Overlay<V> {
|
||||
impl<V: 'static> Element<V> for Overlay<V> {
|
||||
type LayoutState = Vector2F;
|
||||
type PaintState = ();
|
||||
|
||||
|
|
|
@ -59,7 +59,7 @@ where
|
|||
.and_then(|map| map.0.get(&tag))
|
||||
}
|
||||
|
||||
pub struct Resizable<V: View> {
|
||||
pub struct Resizable<V: 'static> {
|
||||
child: AnyElement<V>,
|
||||
tag: TypeTag,
|
||||
handle_side: HandleSide,
|
||||
|
@ -69,7 +69,7 @@ pub struct Resizable<V: View> {
|
|||
|
||||
const DEFAULT_HANDLE_SIZE: f32 = 4.0;
|
||||
|
||||
impl<V: View> Resizable<V> {
|
||||
impl<V: 'static> Resizable<V> {
|
||||
pub fn new<Tag: 'static>(
|
||||
child: AnyElement<V>,
|
||||
handle_side: HandleSide,
|
||||
|
@ -97,7 +97,7 @@ impl<V: View> Resizable<V> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V: View> Element<V> for Resizable<V> {
|
||||
impl<V: 'static> Element<V> for Resizable<V> {
|
||||
type LayoutState = SizeConstraint;
|
||||
type PaintState = ();
|
||||
|
||||
|
@ -219,12 +219,12 @@ impl<V: View> Element<V> for Resizable<V> {
|
|||
#[derive(Debug, Default)]
|
||||
struct ProviderMap(HashMap<TypeTag, (RectF, RectF)>);
|
||||
|
||||
pub struct BoundsProvider<V: View, P> {
|
||||
pub struct BoundsProvider<V: 'static, P> {
|
||||
child: AnyElement<V>,
|
||||
phantom: std::marker::PhantomData<P>,
|
||||
}
|
||||
|
||||
impl<V: View, P: 'static> BoundsProvider<V, P> {
|
||||
impl<V: 'static, P: 'static> BoundsProvider<V, P> {
|
||||
pub fn new(child: AnyElement<V>) -> Self {
|
||||
Self {
|
||||
child,
|
||||
|
|
|
@ -3,17 +3,16 @@ use std::ops::Range;
|
|||
use crate::{
|
||||
geometry::{rect::RectF, vector::Vector2F},
|
||||
json::{self, json, ToJson},
|
||||
AnyElement, Element, LayoutContext, PaintContext, SceneBuilder, SizeConstraint, View,
|
||||
ViewContext,
|
||||
AnyElement, Element, LayoutContext, PaintContext, SceneBuilder, SizeConstraint, ViewContext,
|
||||
};
|
||||
|
||||
/// Element which renders it's children in a stack on top of each other.
|
||||
/// The first child determines the size of the others.
|
||||
pub struct Stack<V: View> {
|
||||
pub struct Stack<V> {
|
||||
children: Vec<AnyElement<V>>,
|
||||
}
|
||||
|
||||
impl<V: View> Default for Stack<V> {
|
||||
impl<V> Default for Stack<V> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
children: Vec::new(),
|
||||
|
@ -21,13 +20,13 @@ impl<V: View> Default for Stack<V> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V: View> Stack<V> {
|
||||
impl<V> Stack<V> {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: View> Element<V> for Stack<V> {
|
||||
impl<V: 'static> Element<V> for Stack<V> {
|
||||
type LayoutState = ();
|
||||
type PaintState = ();
|
||||
|
||||
|
@ -99,7 +98,7 @@ impl<V: View> Element<V> for Stack<V> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V: View> Extend<AnyElement<V>> for Stack<V> {
|
||||
impl<V> Extend<AnyElement<V>> for Stack<V> {
|
||||
fn extend<T: IntoIterator<Item = AnyElement<V>>>(&mut self, children: T) {
|
||||
self.children.extend(children)
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ use crate::{
|
|||
rect::RectF,
|
||||
vector::{vec2f, Vector2F},
|
||||
},
|
||||
scene, Element, LayoutContext, SceneBuilder, SizeConstraint, View, ViewContext,
|
||||
scene, Element, LayoutContext, SceneBuilder, SizeConstraint, ViewContext,
|
||||
};
|
||||
use schemars::JsonSchema;
|
||||
use serde_derive::Deserialize;
|
||||
|
@ -27,7 +27,7 @@ impl Svg {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn for_style<V: View>(style: SvgStyle) -> impl Element<V> {
|
||||
pub fn for_style<V: 'static>(style: SvgStyle) -> impl Element<V> {
|
||||
Self::new(style.asset)
|
||||
.with_color(style.color)
|
||||
.constrained()
|
||||
|
@ -41,7 +41,7 @@ impl Svg {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V: View> Element<V> for Svg {
|
||||
impl<V: 'static> Element<V> for Svg {
|
||||
type LayoutState = Option<usvg::Tree>;
|
||||
type PaintState = ();
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ use crate::{
|
|||
json::{ToJson, Value},
|
||||
text_layout::{Line, RunStyle, ShapedBoundary},
|
||||
AppContext, Element, FontCache, LayoutContext, PaintContext, SceneBuilder, SizeConstraint,
|
||||
TextLayoutCache, View, ViewContext,
|
||||
TextLayoutCache, ViewContext,
|
||||
};
|
||||
use log::warn;
|
||||
use serde_json::json;
|
||||
|
@ -70,7 +70,7 @@ impl Text {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V: View> Element<V> for Text {
|
||||
impl<V: 'static> Element<V> for Text {
|
||||
type LayoutState = LayoutState;
|
||||
type PaintState = ();
|
||||
|
||||
|
@ -338,7 +338,7 @@ impl<V: View> Element<V> for Text {
|
|||
}
|
||||
|
||||
/// Perform text layout on a series of highlighted chunks of text.
|
||||
fn layout_highlighted_chunks<'a>(
|
||||
pub fn layout_highlighted_chunks<'a>(
|
||||
chunks: impl Iterator<Item = (&'a str, Option<HighlightStyle>)>,
|
||||
text_style: &TextStyle,
|
||||
text_layout_cache: &TextLayoutCache,
|
||||
|
|
|
@ -7,7 +7,7 @@ use crate::{
|
|||
geometry::{rect::RectF, vector::Vector2F},
|
||||
json::json,
|
||||
Action, Axis, ElementStateHandle, LayoutContext, PaintContext, SceneBuilder, SizeConstraint,
|
||||
Task, TypeTag, View, ViewContext,
|
||||
Task, TypeTag, ViewContext,
|
||||
};
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
|
@ -22,7 +22,7 @@ use util::ResultExt;
|
|||
|
||||
const DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(500);
|
||||
|
||||
pub struct Tooltip<V: View> {
|
||||
pub struct Tooltip<V> {
|
||||
child: AnyElement<V>,
|
||||
tooltip: Option<AnyElement<V>>,
|
||||
_state: ElementStateHandle<Rc<TooltipState>>,
|
||||
|
@ -52,7 +52,7 @@ pub struct KeystrokeStyle {
|
|||
text: TextStyle,
|
||||
}
|
||||
|
||||
impl<V: View> Tooltip<V> {
|
||||
impl<V: 'static> Tooltip<V> {
|
||||
pub fn new<Tag: 'static>(
|
||||
id: usize,
|
||||
text: impl Into<Cow<'static, str>>,
|
||||
|
@ -181,7 +181,7 @@ impl<V: View> Tooltip<V> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V: View> Element<V> for Tooltip<V> {
|
||||
impl<V: 'static> Element<V> for Tooltip<V> {
|
||||
type LayoutState = ();
|
||||
type PaintState = ();
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ use crate::{
|
|||
},
|
||||
json::{self, json},
|
||||
platform::ScrollWheelEvent,
|
||||
AnyElement, LayoutContext, MouseRegion, PaintContext, SceneBuilder, View, ViewContext,
|
||||
AnyElement, LayoutContext, MouseRegion, PaintContext, SceneBuilder, ViewContext,
|
||||
};
|
||||
use json::ToJson;
|
||||
use std::{cell::RefCell, cmp, ops::Range, rc::Rc};
|
||||
|
@ -36,13 +36,13 @@ struct StateInner {
|
|||
scroll_to: Option<ScrollTarget>,
|
||||
}
|
||||
|
||||
pub struct UniformListLayoutState<V: View> {
|
||||
pub struct UniformListLayoutState<V> {
|
||||
scroll_max: f32,
|
||||
item_height: f32,
|
||||
items: Vec<AnyElement<V>>,
|
||||
}
|
||||
|
||||
pub struct UniformList<V: View> {
|
||||
pub struct UniformList<V> {
|
||||
state: UniformListState,
|
||||
item_count: usize,
|
||||
#[allow(clippy::type_complexity)]
|
||||
|
@ -53,7 +53,7 @@ pub struct UniformList<V: View> {
|
|||
view_id: usize,
|
||||
}
|
||||
|
||||
impl<V: View> UniformList<V> {
|
||||
impl<V: 'static> UniformList<V> {
|
||||
pub fn new<F>(
|
||||
state: UniformListState,
|
||||
item_count: usize,
|
||||
|
@ -61,7 +61,6 @@ impl<V: View> UniformList<V> {
|
|||
append_items: F,
|
||||
) -> Self
|
||||
where
|
||||
V: View,
|
||||
F: 'static + Fn(&mut V, Range<usize>, &mut Vec<AnyElement<V>>, &mut ViewContext<V>),
|
||||
{
|
||||
Self {
|
||||
|
@ -151,7 +150,7 @@ impl<V: View> UniformList<V> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V: View> Element<V> for UniformList<V> {
|
||||
impl<V: 'static> Element<V> for UniformList<V> {
|
||||
type LayoutState = UniformListLayoutState<V>;
|
||||
type PaintState = ();
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ pub use font_kit::{
|
|||
properties::{Properties, Stretch, Style, Weight},
|
||||
};
|
||||
use ordered_float::OrderedFloat;
|
||||
use refineable::Refineable;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{de, Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
|
@ -59,7 +60,7 @@ pub struct Features {
|
|||
pub zero: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, JsonSchema)]
|
||||
#[derive(Clone, Debug, JsonSchema, Refineable)]
|
||||
pub struct TextStyle {
|
||||
pub color: Color,
|
||||
pub font_family_name: Arc<str>,
|
||||
|
@ -69,6 +70,7 @@ pub struct TextStyle {
|
|||
#[schemars(with = "PropertiesDef")]
|
||||
pub font_properties: Properties,
|
||||
pub underline: Underline,
|
||||
pub soft_wrap: bool,
|
||||
}
|
||||
|
||||
impl TextStyle {
|
||||
|
@ -90,20 +92,11 @@ impl TextStyle {
|
|||
font_size: refinement.font_size.unwrap_or(self.font_size),
|
||||
font_properties: refinement.font_properties.unwrap_or(self.font_properties),
|
||||
underline: refinement.underline.unwrap_or(self.underline),
|
||||
soft_wrap: refinement.soft_wrap.unwrap_or(self.soft_wrap),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TextStyleRefinement {
|
||||
pub color: Option<Color>,
|
||||
pub font_family_name: Option<Arc<str>>,
|
||||
pub font_family_id: Option<FamilyId>,
|
||||
pub font_id: Option<FontId>,
|
||||
pub font_size: Option<f32>,
|
||||
pub font_properties: Option<Properties>,
|
||||
pub underline: Option<Underline>,
|
||||
}
|
||||
|
||||
#[derive(JsonSchema)]
|
||||
#[serde(remote = "Properties")]
|
||||
pub struct PropertiesDef {
|
||||
|
@ -222,9 +215,31 @@ impl TextStyle {
|
|||
font_size,
|
||||
font_properties,
|
||||
underline,
|
||||
soft_wrap: false,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn default(font_cache: &FontCache) -> Self {
|
||||
let font_family_id = font_cache.known_existing_family();
|
||||
let font_id = font_cache
|
||||
.select_font(font_family_id, &Default::default())
|
||||
.expect("did not have any font in system-provided family");
|
||||
let font_family_name = font_cache
|
||||
.family_name(font_family_id)
|
||||
.expect("we loaded this family from the font cache, so this should work");
|
||||
|
||||
Self {
|
||||
color: Color::default(),
|
||||
font_family_name,
|
||||
font_family_id,
|
||||
font_id,
|
||||
font_size: 14.,
|
||||
font_properties: Default::default(),
|
||||
underline: Default::default(),
|
||||
soft_wrap: true,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_font_size(mut self, font_size: f32) -> Self {
|
||||
self.font_size = font_size;
|
||||
self
|
||||
|
@ -352,24 +367,7 @@ impl Default for TextStyle {
|
|||
let font_cache = font_cache
|
||||
.as_ref()
|
||||
.expect("TextStyle::default can only be called within a call to with_font_cache");
|
||||
|
||||
let font_family_id = font_cache.known_existing_family();
|
||||
let font_id = font_cache
|
||||
.select_font(font_family_id, &Default::default())
|
||||
.expect("did not have any font in system-provided family");
|
||||
let font_family_name = font_cache
|
||||
.family_name(font_family_id)
|
||||
.expect("we loaded this family from the font cache, so this should work");
|
||||
|
||||
Self {
|
||||
color: Default::default(),
|
||||
font_family_name,
|
||||
font_family_id,
|
||||
font_id,
|
||||
font_size: 14.,
|
||||
font_properties: Default::default(),
|
||||
underline: Default::default(),
|
||||
}
|
||||
Self::default(font_cache)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ use super::scene::{Path, PathVertex};
|
|||
use crate::{color::Color, json::ToJson};
|
||||
pub use pathfinder_geometry::*;
|
||||
use rect::RectF;
|
||||
use refineable::Refineable;
|
||||
use serde::{Deserialize, Deserializer};
|
||||
use serde_json::json;
|
||||
use vector::{vec2f, Vector2F};
|
||||
|
@ -131,3 +132,258 @@ impl ToJson for RectF {
|
|||
json!({"origin": self.origin().to_json(), "size": self.size().to_json()})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Refineable)]
|
||||
pub struct Point<T: Clone + Default> {
|
||||
pub x: T,
|
||||
pub y: T,
|
||||
}
|
||||
|
||||
impl<T: Clone + Default> Clone for Point<T> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
x: self.x.clone(),
|
||||
y: self.y.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone + Default> Into<taffy::geometry::Point<T>> for Point<T> {
|
||||
fn into(self) -> taffy::geometry::Point<T> {
|
||||
taffy::geometry::Point {
|
||||
x: self.x,
|
||||
y: self.y,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Refineable)]
|
||||
pub struct Size<T: Clone + Default> {
|
||||
pub width: T,
|
||||
pub height: T,
|
||||
}
|
||||
|
||||
impl<S, T: Clone + Default> From<taffy::geometry::Size<S>> for Size<T>
|
||||
where
|
||||
S: Into<T>,
|
||||
{
|
||||
fn from(value: taffy::geometry::Size<S>) -> Self {
|
||||
Self {
|
||||
width: value.width.into(),
|
||||
height: value.height.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<S, T: Clone + Default> Into<taffy::geometry::Size<S>> for Size<T>
|
||||
where
|
||||
T: Into<S>,
|
||||
{
|
||||
fn into(self) -> taffy::geometry::Size<S> {
|
||||
taffy::geometry::Size {
|
||||
width: self.width.into(),
|
||||
height: self.height.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Size<DefiniteLength> {
|
||||
pub fn zero() -> Self {
|
||||
Self {
|
||||
width: pixels(0.),
|
||||
height: pixels(0.),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_taffy(&self, rem_size: f32) -> taffy::geometry::Size<taffy::style::LengthPercentage> {
|
||||
taffy::geometry::Size {
|
||||
width: self.width.to_taffy(rem_size),
|
||||
height: self.height.to_taffy(rem_size),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Size<Length> {
|
||||
pub fn auto() -> Self {
|
||||
Self {
|
||||
width: Length::Auto,
|
||||
height: Length::Auto,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_taffy<T: From<taffy::prelude::LengthPercentageAuto>>(
|
||||
&self,
|
||||
rem_size: f32,
|
||||
) -> taffy::geometry::Size<T> {
|
||||
taffy::geometry::Size {
|
||||
width: self.width.to_taffy(rem_size).into(),
|
||||
height: self.height.to_taffy(rem_size).into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Refineable)]
|
||||
pub struct Edges<T: Clone + Default> {
|
||||
pub top: T,
|
||||
pub right: T,
|
||||
pub bottom: T,
|
||||
pub left: T,
|
||||
}
|
||||
|
||||
impl Edges<DefiniteLength> {
|
||||
pub fn zero() -> Self {
|
||||
Self {
|
||||
top: pixels(0.),
|
||||
right: pixels(0.),
|
||||
bottom: pixels(0.),
|
||||
left: pixels(0.),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_taffy(&self, rem_size: f32) -> taffy::geometry::Rect<taffy::style::LengthPercentage> {
|
||||
taffy::geometry::Rect {
|
||||
top: self.top.to_taffy(rem_size),
|
||||
right: self.right.to_taffy(rem_size),
|
||||
bottom: self.bottom.to_taffy(rem_size),
|
||||
left: self.left.to_taffy(rem_size),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Edges<Length> {
|
||||
pub fn auto() -> Self {
|
||||
Self {
|
||||
top: Length::Auto,
|
||||
right: Length::Auto,
|
||||
bottom: Length::Auto,
|
||||
left: Length::Auto,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn zero() -> Self {
|
||||
Self {
|
||||
top: pixels(0.),
|
||||
right: pixels(0.),
|
||||
bottom: pixels(0.),
|
||||
left: pixels(0.),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_taffy(
|
||||
&self,
|
||||
rem_size: f32,
|
||||
) -> taffy::geometry::Rect<taffy::style::LengthPercentageAuto> {
|
||||
taffy::geometry::Rect {
|
||||
top: self.top.to_taffy(rem_size),
|
||||
right: self.right.to_taffy(rem_size),
|
||||
bottom: self.bottom.to_taffy(rem_size),
|
||||
left: self.left.to_taffy(rem_size),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum AbsoluteLength {
|
||||
Pixels(f32),
|
||||
Rems(f32),
|
||||
}
|
||||
|
||||
impl AbsoluteLength {
|
||||
pub fn to_pixels(&self, rem_size: f32) -> f32 {
|
||||
match self {
|
||||
AbsoluteLength::Pixels(pixels) => *pixels,
|
||||
AbsoluteLength::Rems(rems) => rems * rem_size,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for AbsoluteLength {
|
||||
fn default() -> Self {
|
||||
Self::Pixels(0.0)
|
||||
}
|
||||
}
|
||||
|
||||
/// A non-auto length that can be defined in pixels, rems, or percent of parent.
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum DefiniteLength {
|
||||
Absolute(AbsoluteLength),
|
||||
Relative(f32), // Percent, from 0 to 100.
|
||||
}
|
||||
|
||||
impl DefiniteLength {
|
||||
fn to_taffy(&self, rem_size: f32) -> taffy::style::LengthPercentage {
|
||||
match self {
|
||||
DefiniteLength::Absolute(length) => match length {
|
||||
AbsoluteLength::Pixels(pixels) => taffy::style::LengthPercentage::Length(*pixels),
|
||||
AbsoluteLength::Rems(rems) => {
|
||||
taffy::style::LengthPercentage::Length(rems * rem_size)
|
||||
}
|
||||
},
|
||||
DefiniteLength::Relative(fraction) => {
|
||||
taffy::style::LengthPercentage::Percent(*fraction)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<AbsoluteLength> for DefiniteLength {
|
||||
fn from(length: AbsoluteLength) -> Self {
|
||||
Self::Absolute(length)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for DefiniteLength {
|
||||
fn default() -> Self {
|
||||
Self::Absolute(AbsoluteLength::default())
|
||||
}
|
||||
}
|
||||
|
||||
/// A length that can be defined in pixels, rems, percent of parent, or auto.
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum Length {
|
||||
Definite(DefiniteLength),
|
||||
Auto,
|
||||
}
|
||||
|
||||
pub fn relative<T: From<DefiniteLength>>(fraction: f32) -> T {
|
||||
DefiniteLength::Relative(fraction).into()
|
||||
}
|
||||
|
||||
pub fn rems<T: From<AbsoluteLength>>(rems: f32) -> T {
|
||||
AbsoluteLength::Rems(rems).into()
|
||||
}
|
||||
|
||||
pub fn pixels<T: From<AbsoluteLength>>(pixels: f32) -> T {
|
||||
AbsoluteLength::Pixels(pixels).into()
|
||||
}
|
||||
|
||||
pub fn auto() -> Length {
|
||||
Length::Auto
|
||||
}
|
||||
|
||||
impl Length {
|
||||
pub fn to_taffy(&self, rem_size: f32) -> taffy::prelude::LengthPercentageAuto {
|
||||
match self {
|
||||
Length::Definite(length) => length.to_taffy(rem_size).into(),
|
||||
Length::Auto => taffy::prelude::LengthPercentageAuto::Auto,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<DefiniteLength> for Length {
|
||||
fn from(length: DefiniteLength) -> Self {
|
||||
Self::Definite(length)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<AbsoluteLength> for Length {
|
||||
fn from(length: AbsoluteLength) -> Self {
|
||||
Self::Definite(length.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Length {
|
||||
fn default() -> Self {
|
||||
Self::Definite(DefiniteLength::default())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,10 @@ pub mod json;
|
|||
pub mod keymap_matcher;
|
||||
pub mod platform;
|
||||
pub use gpui_macros::{test, Element};
|
||||
pub use window::{Axis, RectFExt, SizeConstraint, Vector2FExt, WindowContext};
|
||||
pub use window::{
|
||||
Axis, EngineLayout, LayoutEngine, LayoutId, RectFExt, SizeConstraint, Vector2FExt,
|
||||
WindowContext,
|
||||
};
|
||||
|
||||
pub use anyhow;
|
||||
pub use serde_json;
|
||||
|
|
|
@ -192,7 +192,7 @@ impl<'a> WindowOptions<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Default)]
|
||||
pub struct TitlebarOptions<'a> {
|
||||
pub title: Option<&'a str>,
|
||||
pub appears_transparent: bool,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use std::ops::Deref;
|
||||
use std::{any::Any, ops::Deref};
|
||||
|
||||
use pathfinder_geometry::vector::vec2f;
|
||||
|
||||
|
@ -142,6 +142,7 @@ pub struct MouseButtonEvent {
|
|||
pub position: Vector2F,
|
||||
pub modifiers: Modifiers,
|
||||
pub click_count: usize,
|
||||
pub is_down: bool,
|
||||
}
|
||||
|
||||
impl Deref for MouseButtonEvent {
|
||||
|
@ -174,6 +175,7 @@ impl MouseMovedEvent {
|
|||
button: self.pressed_button.unwrap_or(button),
|
||||
modifiers: self.modifiers,
|
||||
click_count: 0,
|
||||
is_down: self.pressed_button.is_some(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -211,10 +213,24 @@ impl Event {
|
|||
Event::KeyDown { .. } => None,
|
||||
Event::KeyUp { .. } => None,
|
||||
Event::ModifiersChanged { .. } => None,
|
||||
Event::MouseDown(event) | Event::MouseUp(event) => Some(event.position),
|
||||
Event::MouseDown(event) => Some(event.position),
|
||||
Event::MouseUp(event) => Some(event.position),
|
||||
Event::MouseMoved(event) => Some(event.position),
|
||||
Event::MouseExited(event) => Some(event.position),
|
||||
Event::ScrollWheel(event) => Some(event.position),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mouse_event<'a>(&'a self) -> Option<&'a dyn Any> {
|
||||
match self {
|
||||
Event::KeyDown { .. } => None,
|
||||
Event::KeyUp { .. } => None,
|
||||
Event::ModifiersChanged { .. } => None,
|
||||
Event::MouseDown(event) => Some(event),
|
||||
Event::MouseUp(event) => Some(event),
|
||||
Event::MouseMoved(event) => Some(event),
|
||||
Event::MouseExited(event) => Some(event),
|
||||
Event::ScrollWheel(event) => Some(event),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -132,6 +132,7 @@ impl Event {
|
|||
),
|
||||
modifiers: read_modifiers(native_event),
|
||||
click_count: native_event.clickCount() as usize,
|
||||
is_down: true,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@ -158,6 +159,7 @@ impl Event {
|
|||
),
|
||||
modifiers: read_modifiers(native_event),
|
||||
click_count: native_event.clickCount() as usize,
|
||||
is_down: false,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
mod mouse_event;
|
||||
mod mouse_region;
|
||||
mod region;
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
use collections::HashSet;
|
||||
|
@ -8,7 +9,12 @@ use schemars::JsonSchema;
|
|||
use serde::Deserialize;
|
||||
use serde_derive::Serialize;
|
||||
use serde_json::json;
|
||||
use std::{borrow::Cow, sync::Arc};
|
||||
use std::{
|
||||
any::{Any, TypeId},
|
||||
borrow::Cow,
|
||||
rc::Rc,
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
color::Color,
|
||||
|
@ -16,7 +22,7 @@ use crate::{
|
|||
geometry::{rect::RectF, vector::Vector2F},
|
||||
json::ToJson,
|
||||
platform::{current::Surface, CursorStyle},
|
||||
ImageData,
|
||||
ImageData, WindowContext,
|
||||
};
|
||||
pub use mouse_event::*;
|
||||
pub use mouse_region::*;
|
||||
|
@ -25,6 +31,8 @@ pub struct SceneBuilder {
|
|||
scale_factor: f32,
|
||||
stacking_contexts: Vec<StackingContext>,
|
||||
active_stacking_context_stack: Vec<usize>,
|
||||
/// Used by the playground crate.
|
||||
pub event_handlers: Vec<EventHandler>,
|
||||
#[cfg(debug_assertions)]
|
||||
mouse_region_ids: HashSet<MouseRegionId>,
|
||||
}
|
||||
|
@ -32,6 +40,7 @@ pub struct SceneBuilder {
|
|||
pub struct Scene {
|
||||
scale_factor: f32,
|
||||
stacking_contexts: Vec<StackingContext>,
|
||||
event_handlers: Vec<EventHandler>,
|
||||
}
|
||||
|
||||
struct StackingContext {
|
||||
|
@ -272,6 +281,12 @@ impl Scene {
|
|||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn take_event_handlers(&mut self) -> Vec<EventHandler> {
|
||||
self.event_handlers
|
||||
.sort_by(|a, b| a.order.cmp(&b.order).reverse());
|
||||
std::mem::take(&mut self.event_handlers)
|
||||
}
|
||||
}
|
||||
|
||||
impl SceneBuilder {
|
||||
|
@ -283,6 +298,7 @@ impl SceneBuilder {
|
|||
active_stacking_context_stack: vec![0],
|
||||
#[cfg(debug_assertions)]
|
||||
mouse_region_ids: Default::default(),
|
||||
event_handlers: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -292,6 +308,7 @@ impl SceneBuilder {
|
|||
Scene {
|
||||
scale_factor: self.scale_factor,
|
||||
stacking_contexts: self.stacking_contexts,
|
||||
event_handlers: self.event_handlers,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -688,6 +705,13 @@ impl MouseRegion {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct EventHandler {
|
||||
pub order: u32,
|
||||
// The &dyn Any parameter below expects an event.
|
||||
pub handler: Rc<dyn Fn(&dyn Any, &mut WindowContext) -> bool>,
|
||||
pub event_type: TypeId,
|
||||
}
|
||||
|
||||
fn can_draw(bounds: RectF) -> bool {
|
||||
let size = bounds.size();
|
||||
size.x() > 0. && size.y() > 0.
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
use crate::{
|
||||
platform::MouseButton, window::WindowContext, EventContext, TypeTag, View, ViewContext,
|
||||
};
|
||||
use crate::{platform::MouseButton, window::WindowContext, EventContext, TypeTag, ViewContext};
|
||||
use collections::HashMap;
|
||||
use pathfinder_geometry::rect::RectF;
|
||||
use smallvec::SmallVec;
|
||||
|
@ -72,7 +70,7 @@ impl MouseRegion {
|
|||
|
||||
pub fn on_down<V, F>(mut self, button: MouseButton, handler: F) -> Self
|
||||
where
|
||||
V: View,
|
||||
V: 'static,
|
||||
F: Fn(MouseDown, &mut V, &mut EventContext<V>) + 'static,
|
||||
{
|
||||
self.handlers = self.handlers.on_down(button, handler);
|
||||
|
@ -81,7 +79,7 @@ impl MouseRegion {
|
|||
|
||||
pub fn on_up<V, F>(mut self, button: MouseButton, handler: F) -> Self
|
||||
where
|
||||
V: View,
|
||||
V: 'static,
|
||||
F: Fn(MouseUp, &mut V, &mut EventContext<V>) + 'static,
|
||||
{
|
||||
self.handlers = self.handlers.on_up(button, handler);
|
||||
|
@ -90,7 +88,7 @@ impl MouseRegion {
|
|||
|
||||
pub fn on_click<V, F>(mut self, button: MouseButton, handler: F) -> Self
|
||||
where
|
||||
V: View,
|
||||
V: 'static,
|
||||
F: Fn(MouseClick, &mut V, &mut EventContext<V>) + 'static,
|
||||
{
|
||||
self.handlers = self.handlers.on_click(button, handler);
|
||||
|
@ -99,7 +97,7 @@ impl MouseRegion {
|
|||
|
||||
pub fn on_click_out<V, F>(mut self, button: MouseButton, handler: F) -> Self
|
||||
where
|
||||
V: View,
|
||||
V: 'static,
|
||||
F: Fn(MouseClickOut, &mut V, &mut EventContext<V>) + 'static,
|
||||
{
|
||||
self.handlers = self.handlers.on_click_out(button, handler);
|
||||
|
@ -108,7 +106,7 @@ impl MouseRegion {
|
|||
|
||||
pub fn on_down_out<V, F>(mut self, button: MouseButton, handler: F) -> Self
|
||||
where
|
||||
V: View,
|
||||
V: 'static,
|
||||
F: Fn(MouseDownOut, &mut V, &mut EventContext<V>) + 'static,
|
||||
{
|
||||
self.handlers = self.handlers.on_down_out(button, handler);
|
||||
|
@ -117,7 +115,7 @@ impl MouseRegion {
|
|||
|
||||
pub fn on_up_out<V, F>(mut self, button: MouseButton, handler: F) -> Self
|
||||
where
|
||||
V: View,
|
||||
V: 'static,
|
||||
F: Fn(MouseUpOut, &mut V, &mut EventContext<V>) + 'static,
|
||||
{
|
||||
self.handlers = self.handlers.on_up_out(button, handler);
|
||||
|
@ -126,7 +124,7 @@ impl MouseRegion {
|
|||
|
||||
pub fn on_drag<V, F>(mut self, button: MouseButton, handler: F) -> Self
|
||||
where
|
||||
V: View,
|
||||
V: 'static,
|
||||
F: Fn(MouseDrag, &mut V, &mut EventContext<V>) + 'static,
|
||||
{
|
||||
self.handlers = self.handlers.on_drag(button, handler);
|
||||
|
@ -135,7 +133,7 @@ impl MouseRegion {
|
|||
|
||||
pub fn on_hover<V, F>(mut self, handler: F) -> Self
|
||||
where
|
||||
V: View,
|
||||
V: 'static,
|
||||
F: Fn(MouseHover, &mut V, &mut EventContext<V>) + 'static,
|
||||
{
|
||||
self.handlers = self.handlers.on_hover(handler);
|
||||
|
@ -144,7 +142,7 @@ impl MouseRegion {
|
|||
|
||||
pub fn on_move<V, F>(mut self, handler: F) -> Self
|
||||
where
|
||||
V: View,
|
||||
V: 'static,
|
||||
F: Fn(MouseMove, &mut V, &mut EventContext<V>) + 'static,
|
||||
{
|
||||
self.handlers = self.handlers.on_move(handler);
|
||||
|
@ -153,7 +151,7 @@ impl MouseRegion {
|
|||
|
||||
pub fn on_move_out<V, F>(mut self, handler: F) -> Self
|
||||
where
|
||||
V: View,
|
||||
V: 'static,
|
||||
F: Fn(MouseMoveOut, &mut V, &mut EventContext<V>) + 'static,
|
||||
{
|
||||
self.handlers = self.handlers.on_move_out(handler);
|
||||
|
@ -162,7 +160,7 @@ impl MouseRegion {
|
|||
|
||||
pub fn on_scroll<V, F>(mut self, handler: F) -> Self
|
||||
where
|
||||
V: View,
|
||||
V: 'static,
|
||||
F: Fn(MouseScrollWheel, &mut V, &mut EventContext<V>) + 'static,
|
||||
{
|
||||
self.handlers = self.handlers.on_scroll(handler);
|
||||
|
@ -314,7 +312,7 @@ impl HandlerSet {
|
|||
|
||||
pub fn on_move<V, F>(mut self, handler: F) -> Self
|
||||
where
|
||||
V: View,
|
||||
V: 'static,
|
||||
F: Fn(MouseMove, &mut V, &mut EventContext<V>) + 'static,
|
||||
{
|
||||
self.insert(MouseEvent::move_disc(), None,
|
||||
|
@ -336,7 +334,7 @@ impl HandlerSet {
|
|||
|
||||
pub fn on_move_out<V, F>(mut self, handler: F) -> Self
|
||||
where
|
||||
V: View,
|
||||
V: 'static,
|
||||
F: Fn(MouseMoveOut, &mut V, &mut EventContext<V>) + 'static,
|
||||
{
|
||||
self.insert(MouseEvent::move_out_disc(), None,
|
||||
|
@ -358,7 +356,7 @@ impl HandlerSet {
|
|||
|
||||
pub fn on_down<V, F>(mut self, button: MouseButton, handler: F) -> Self
|
||||
where
|
||||
V: View,
|
||||
V: 'static,
|
||||
F: Fn(MouseDown, &mut V, &mut EventContext<V>) + 'static,
|
||||
{
|
||||
self.insert(MouseEvent::down_disc(), Some(button),
|
||||
|
@ -380,7 +378,7 @@ impl HandlerSet {
|
|||
|
||||
pub fn on_up<V, F>(mut self, button: MouseButton, handler: F) -> Self
|
||||
where
|
||||
V: View,
|
||||
V: 'static,
|
||||
F: Fn(MouseUp, &mut V, &mut EventContext<V>) + 'static,
|
||||
{
|
||||
self.insert(MouseEvent::up_disc(), Some(button),
|
||||
|
@ -402,7 +400,7 @@ impl HandlerSet {
|
|||
|
||||
pub fn on_click<V, F>(mut self, button: MouseButton, handler: F) -> Self
|
||||
where
|
||||
V: View,
|
||||
V: 'static,
|
||||
F: Fn(MouseClick, &mut V, &mut EventContext<V>) + 'static,
|
||||
{
|
||||
self.insert(MouseEvent::click_disc(), Some(button),
|
||||
|
@ -424,7 +422,7 @@ impl HandlerSet {
|
|||
|
||||
pub fn on_click_out<V, F>(mut self, button: MouseButton, handler: F) -> Self
|
||||
where
|
||||
V: View,
|
||||
V: 'static,
|
||||
F: Fn(MouseClickOut, &mut V, &mut EventContext<V>) + 'static,
|
||||
{
|
||||
self.insert(MouseEvent::click_out_disc(), Some(button),
|
||||
|
@ -446,7 +444,7 @@ impl HandlerSet {
|
|||
|
||||
pub fn on_down_out<V, F>(mut self, button: MouseButton, handler: F) -> Self
|
||||
where
|
||||
V: View,
|
||||
V: 'static,
|
||||
F: Fn(MouseDownOut, &mut V, &mut EventContext<V>) + 'static,
|
||||
{
|
||||
self.insert(MouseEvent::down_out_disc(), Some(button),
|
||||
|
@ -468,7 +466,7 @@ impl HandlerSet {
|
|||
|
||||
pub fn on_up_out<V, F>(mut self, button: MouseButton, handler: F) -> Self
|
||||
where
|
||||
V: View,
|
||||
V: 'static,
|
||||
F: Fn(MouseUpOut, &mut V, &mut EventContext<V>) + 'static,
|
||||
{
|
||||
self.insert(MouseEvent::up_out_disc(), Some(button),
|
||||
|
@ -490,7 +488,7 @@ impl HandlerSet {
|
|||
|
||||
pub fn on_drag<V, F>(mut self, button: MouseButton, handler: F) -> Self
|
||||
where
|
||||
V: View,
|
||||
V: 'static,
|
||||
F: Fn(MouseDrag, &mut V, &mut EventContext<V>) + 'static,
|
||||
{
|
||||
self.insert(MouseEvent::drag_disc(), Some(button),
|
||||
|
@ -512,7 +510,7 @@ impl HandlerSet {
|
|||
|
||||
pub fn on_hover<V, F>(mut self, handler: F) -> Self
|
||||
where
|
||||
V: View,
|
||||
V: 'static,
|
||||
F: Fn(MouseHover, &mut V, &mut EventContext<V>) + 'static,
|
||||
{
|
||||
self.insert(MouseEvent::hover_disc(), None,
|
||||
|
@ -534,7 +532,7 @@ impl HandlerSet {
|
|||
|
||||
pub fn on_scroll<V, F>(mut self, handler: F) -> Self
|
||||
where
|
||||
V: View,
|
||||
V: 'static,
|
||||
F: Fn(MouseScrollWheel, &mut V, &mut EventContext<V>) + 'static,
|
||||
{
|
||||
self.insert(MouseEvent::scroll_wheel_disc(), None,
|
||||
|
|
7
crates/gpui/src/scene/region.rs
Normal file
7
crates/gpui/src/scene/region.rs
Normal file
|
@ -0,0 +1,7 @@
|
|||
// use crate::geometry::rect::RectF;
|
||||
// use crate::WindowContext;
|
||||
|
||||
// struct Region {
|
||||
// pub bounds: RectF,
|
||||
// pub click_handler: Option<Rc<dyn Fn(&dyn Any, MouseEvent, &mut WindowContext)>>,
|
||||
// }
|
|
@ -212,7 +212,7 @@ pub struct Glyph {
|
|||
}
|
||||
|
||||
impl Line {
|
||||
fn new(layout: Arc<LineLayout>, runs: &[(usize, RunStyle)]) -> Self {
|
||||
pub fn new(layout: Arc<LineLayout>, runs: &[(usize, RunStyle)]) -> Self {
|
||||
let mut style_runs = SmallVec::new();
|
||||
for (len, style) in runs {
|
||||
style_runs.push(StyleRun {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue