Merge branch 'main' into copilot2

This commit is contained in:
Piotr Osiewicz
2023-12-06 15:13:13 +01:00
100 changed files with 10636 additions and 3033 deletions
+15 -4
View File
@@ -482,10 +482,6 @@ impl<T: 'static> WeakModel<T> {
/// Update the entity referenced by this model with the given function if
/// the referenced entity still exists. Returns an error if the entity has
/// been released.
///
/// The update function receives a context appropriate for its environment.
/// When updating in an `AppContext`, it receives a `ModelContext`.
/// When updating an a `WindowContext`, it receives a `ViewContext`.
pub fn update<C, R>(
&self,
cx: &mut C,
@@ -501,6 +497,21 @@ impl<T: 'static> WeakModel<T> {
.map(|this| cx.update_model(&this, update)),
)
}
/// Reads the entity referenced by this model with the given function if
/// the referenced entity still exists. Returns an error if the entity has
/// been released.
pub fn read_with<C, R>(&self, cx: &C, read: impl FnOnce(&T, &AppContext) -> R) -> Result<R>
where
C: Context,
Result<C::Result<R>>: crate::Flatten<R>,
{
crate::Flatten::flatten(
self.upgrade()
.ok_or_else(|| anyhow!("entity release"))
.map(|this| cx.read_model(&this, read)),
)
}
}
impl<T> Hash for WeakModel<T> {
+52
View File
@@ -0,0 +1,52 @@
use refineable::Refineable as _;
use crate::{Bounds, Element, IntoElement, Pixels, Style, StyleRefinement, Styled, WindowContext};
pub fn canvas(callback: impl 'static + FnOnce(Bounds<Pixels>, &mut WindowContext)) -> Canvas {
Canvas {
paint_callback: Box::new(callback),
style: StyleRefinement::default(),
}
}
pub struct Canvas {
paint_callback: Box<dyn FnOnce(Bounds<Pixels>, &mut WindowContext)>,
style: StyleRefinement,
}
impl IntoElement for Canvas {
type Element = Self;
fn element_id(&self) -> Option<crate::ElementId> {
None
}
fn into_element(self) -> Self::Element {
self
}
}
impl Element for Canvas {
type State = ();
fn layout(
&mut self,
_: Option<Self::State>,
cx: &mut WindowContext,
) -> (crate::LayoutId, Self::State) {
let mut style = Style::default();
style.refine(&self.style);
let layout_id = cx.request_layout(&style, []);
(layout_id, ())
}
fn paint(self, bounds: Bounds<Pixels>, _: &mut (), cx: &mut WindowContext) {
(self.paint_callback)(bounds, cx)
}
}
impl Styled for Canvas {
fn style(&mut self) -> &mut crate::StyleRefinement {
&mut self.style
}
}
+18 -14
View File
@@ -221,20 +221,6 @@ pub trait InteractiveElement: Sized + Element {
/// Add a listener for the given action, fires during the bubble event phase
fn on_action<A: Action>(mut self, listener: impl Fn(&A, &mut WindowContext) + 'static) -> Self {
// NOTE: this debug assert has the side-effect of working around
// a bug where a crate consisting only of action definitions does
// not register the actions in debug builds:
//
// https://github.com/rust-lang/rust/issues/47384
// https://github.com/mmastrac/rust-ctor/issues/280
//
// if we are relying on this side-effect still, removing the debug_assert!
// likely breaks the command_palette tests.
// debug_assert!(
// A::is_registered(),
// "{:?} is not registered as an action",
// A::qualified_name()
// );
self.interactivity().action_listeners.push((
TypeId::of::<A>(),
Box::new(move |action, phase, cx| {
@@ -247,6 +233,23 @@ pub trait InteractiveElement: Sized + Element {
self
}
fn on_boxed_action(
mut self,
action: &Box<dyn Action>,
listener: impl Fn(&Box<dyn Action>, &mut WindowContext) + 'static,
) -> Self {
let action = action.boxed_clone();
self.interactivity().action_listeners.push((
(*action).type_id(),
Box::new(move |_, phase, cx| {
if phase == DispatchPhase::Bubble {
(listener)(&action, cx)
}
}),
));
self
}
fn on_key_down(
mut self,
listener: impl Fn(&KeyDownEvent, &mut WindowContext) + 'static,
@@ -866,6 +869,7 @@ impl Interactivity {
}
if self.hover_style.is_some()
|| self.base_style.mouse_cursor.is_some()
|| cx.active_drag.is_some() && !self.drag_over_styles.is_empty()
{
let bounds = bounds.intersect(&cx.content_mask().bounds);
+2
View File
@@ -1,3 +1,4 @@
mod canvas;
mod div;
mod img;
mod overlay;
@@ -5,6 +6,7 @@ mod svg;
mod text;
mod uniform_list;
pub use canvas::*;
pub use div::*;
pub use img::*;
pub use overlay::*;
+17 -3
View File
@@ -16,7 +16,7 @@ pub struct DispatchNodeId(usize);
pub(crate) struct DispatchTree {
node_stack: Vec<DispatchNodeId>,
context_stack: Vec<KeyContext>,
pub(crate) context_stack: Vec<KeyContext>,
nodes: Vec<DispatchNode>,
focusable_node_ids: HashMap<FocusId, DispatchNodeId>,
keystroke_matchers: HashMap<SmallVec<[KeyContext; 4]>, KeystrokeMatcher>,
@@ -163,11 +163,25 @@ impl DispatchTree {
actions
}
pub fn bindings_for_action(&self, action: &dyn Action) -> Vec<KeyBinding> {
pub fn bindings_for_action(
&self,
action: &dyn Action,
context_stack: &Vec<KeyContext>,
) -> Vec<KeyBinding> {
self.keymap
.lock()
.bindings_for_action(action.type_id())
.filter(|candidate| candidate.action.partial_eq(action))
.filter(|candidate| {
if !candidate.action.partial_eq(action) {
return false;
}
for i in 1..context_stack.len() {
if candidate.matches_context(&context_stack[0..=i]) {
return true;
}
}
return false;
})
.cloned()
.collect()
}
@@ -7,6 +7,7 @@ use std::{
use crate::DisplayId;
use collections::HashMap;
use parking_lot::Mutex;
pub use sys::CVSMPTETime as SmtpeTime;
pub use sys::CVTimeStamp as VideoTimestamp;
pub(crate) struct MacDisplayLinker {
@@ -153,7 +154,7 @@ mod sys {
kCVTimeStampTopField | kCVTimeStampBottomField;
#[repr(C)]
#[derive(Clone, Copy)]
#[derive(Clone, Copy, Default)]
pub struct CVSMPTETime {
pub subframes: i16,
pub subframe_divisor: i16,
+15 -8
View File
@@ -147,18 +147,25 @@ impl Platform for TestPlatform {
fn set_display_link_output_callback(
&self,
_display_id: DisplayId,
_callback: Box<dyn FnMut(&crate::VideoTimestamp, &crate::VideoTimestamp) + Send>,
mut callback: Box<dyn FnMut(&crate::VideoTimestamp, &crate::VideoTimestamp) + Send>,
) {
unimplemented!()
let timestamp = crate::VideoTimestamp {
version: 0,
video_time_scale: 0,
video_time: 0,
host_time: 0,
rate_scalar: 0.0,
video_refresh_period: 0,
smpte_time: crate::SmtpeTime::default(),
flags: 0,
reserved: 0,
};
callback(&timestamp, &timestamp)
}
fn start_display_link(&self, _display_id: DisplayId) {
unimplemented!()
}
fn start_display_link(&self, _display_id: DisplayId) {}
fn stop_display_link(&self, _display_id: DisplayId) {
unimplemented!()
}
fn stop_display_link(&self, _display_id: DisplayId) {}
fn open_url(&self, _url: &str) {
unimplemented!()
+16 -16
View File
@@ -72,7 +72,7 @@ impl TextSystem {
}
}
pub fn bounding_box(&self, font_id: FontId, font_size: Pixels) -> Result<Bounds<Pixels>> {
pub fn bounding_box(&self, font_id: FontId, font_size: Pixels) -> Bounds<Pixels> {
self.read_metrics(font_id, |metrics| metrics.bounding_box(font_size))
}
@@ -89,9 +89,9 @@ impl TextSystem {
let bounds = self
.platform_text_system
.typographic_bounds(font_id, glyph_id)?;
self.read_metrics(font_id, |metrics| {
Ok(self.read_metrics(font_id, |metrics| {
(bounds / metrics.units_per_em as f32 * font_size.0).map(px)
})
}))
}
pub fn advance(&self, font_id: FontId, font_size: Pixels, ch: char) -> Result<Size<Pixels>> {
@@ -100,28 +100,28 @@ impl TextSystem {
.glyph_for_char(font_id, ch)
.ok_or_else(|| anyhow!("glyph not found for character '{}'", ch))?;
let result = self.platform_text_system.advance(font_id, glyph_id)?
/ self.units_per_em(font_id)? as f32;
/ self.units_per_em(font_id) as f32;
Ok(result * font_size)
}
pub fn units_per_em(&self, font_id: FontId) -> Result<u32> {
pub fn units_per_em(&self, font_id: FontId) -> u32 {
self.read_metrics(font_id, |metrics| metrics.units_per_em as u32)
}
pub fn cap_height(&self, font_id: FontId, font_size: Pixels) -> Result<Pixels> {
pub fn cap_height(&self, font_id: FontId, font_size: Pixels) -> Pixels {
self.read_metrics(font_id, |metrics| metrics.cap_height(font_size))
}
pub fn x_height(&self, font_id: FontId, font_size: Pixels) -> Result<Pixels> {
pub fn x_height(&self, font_id: FontId, font_size: Pixels) -> Pixels {
self.read_metrics(font_id, |metrics| metrics.x_height(font_size))
}
pub fn ascent(&self, font_id: FontId, font_size: Pixels) -> Result<Pixels> {
pub fn ascent(&self, font_id: FontId, font_size: Pixels) -> Pixels {
self.read_metrics(font_id, |metrics| metrics.ascent(font_size))
}
pub fn descent(&self, font_id: FontId, font_size: Pixels) -> Result<Pixels> {
pub fn descent(&self, font_id: FontId, font_size: Pixels) -> Pixels {
self.read_metrics(font_id, |metrics| metrics.descent(font_size))
}
@@ -130,24 +130,24 @@ impl TextSystem {
font_id: FontId,
font_size: Pixels,
line_height: Pixels,
) -> Result<Pixels> {
let ascent = self.ascent(font_id, font_size)?;
let descent = self.descent(font_id, font_size)?;
) -> Pixels {
let ascent = self.ascent(font_id, font_size);
let descent = self.descent(font_id, font_size);
let padding_top = (line_height - ascent - descent) / 2.;
Ok(padding_top + ascent)
padding_top + ascent
}
fn read_metrics<T>(&self, font_id: FontId, read: impl FnOnce(&FontMetrics) -> T) -> Result<T> {
fn read_metrics<T>(&self, font_id: FontId, read: impl FnOnce(&FontMetrics) -> T) -> T {
let lock = self.font_metrics.upgradable_read();
if let Some(metrics) = lock.get(&font_id) {
Ok(read(metrics))
read(metrics)
} else {
let mut lock = RwLockUpgradableReadGuard::upgrade(lock);
let metrics = lock
.entry(font_id)
.or_insert_with(|| self.platform_text_system.font_metrics(font_id));
Ok(read(metrics))
read(metrics)
}
}
+1 -3
View File
@@ -101,9 +101,7 @@ fn paint_line(
let mut glyph_origin = origin;
let mut prev_glyph_position = Point::default();
for (run_ix, run) in layout.runs.iter().enumerate() {
let max_glyph_size = text_system
.bounding_box(run.font_id, layout.font_size)?
.size;
let max_glyph_size = text_system.bounding_box(run.font_id, layout.font_size).size;
for (glyph_ix, glyph) in run.glyphs.iter().enumerate() {
glyph_origin.x += glyph.position.x - prev_glyph_position.x;
+47 -8
View File
@@ -1350,6 +1350,8 @@ impl<'a> WindowContext<'a> {
.dispatch_tree
.dispatch_path(node_id);
let mut actions: Vec<Box<dyn Action>> = Vec::new();
// Capture phase
let mut context_stack: SmallVec<[KeyContext; 16]> = SmallVec::new();
self.propagate_event = true;
@@ -1384,22 +1386,26 @@ impl<'a> WindowContext<'a> {
let node = self.window.current_frame.dispatch_tree.node(*node_id);
if !node.context.is_empty() {
if let Some(key_down_event) = event.downcast_ref::<KeyDownEvent>() {
if let Some(action) = self
if let Some(found) = self
.window
.current_frame
.dispatch_tree
.dispatch_key(&key_down_event.keystroke, &context_stack)
{
self.dispatch_action_on_node(*node_id, action);
if !self.propagate_event {
return;
}
actions.push(found.boxed_clone())
}
}
context_stack.pop();
}
}
for action in actions {
self.dispatch_action_on_node(node_id, action);
if !self.propagate_event {
return;
}
}
}
}
@@ -1427,7 +1433,6 @@ impl<'a> WindowContext<'a> {
}
}
}
// Bubble phase
for node_id in dispatch_path.iter().rev() {
let node = self.window.current_frame.dispatch_tree.node(*node_id);
@@ -1505,9 +1510,30 @@ impl<'a> WindowContext<'a> {
pub fn bindings_for_action(&self, action: &dyn Action) -> Vec<KeyBinding> {
self.window
.current_frame
.previous_frame
.dispatch_tree
.bindings_for_action(action)
.bindings_for_action(
action,
&self.window.previous_frame.dispatch_tree.context_stack,
)
}
pub fn bindings_for_action_in(
&self,
action: &dyn Action,
focus_handle: &FocusHandle,
) -> Vec<KeyBinding> {
let dispatch_tree = &self.window.previous_frame.dispatch_tree;
let Some(node_id) = dispatch_tree.focusable_node_id(focus_handle.id) else {
return vec![];
};
let context_stack = dispatch_tree
.dispatch_path(node_id)
.into_iter()
.map(|node_id| dispatch_tree.node(node_id).context.clone())
.collect();
dispatch_tree.bindings_for_action(action, &context_stack)
}
pub fn listener_for<V: Render, E>(
@@ -2742,6 +2768,7 @@ pub enum ElementId {
Integer(usize),
Name(SharedString),
FocusHandle(FocusId),
NamedInteger(SharedString, usize),
}
impl ElementId {
@@ -2791,3 +2818,15 @@ impl<'a> From<&'a FocusHandle> for ElementId {
ElementId::FocusHandle(handle.id)
}
}
impl From<(&'static str, EntityId)> for ElementId {
fn from((name, id): (&'static str, EntityId)) -> Self {
ElementId::NamedInteger(name.into(), id.as_u64() as usize)
}
}
impl From<(&'static str, usize)> for ElementId {
fn from((name, id): (&'static str, usize)) -> Self {
ElementId::NamedInteger(name.into(), id)
}
}