Compare commits
5 Commits
fix-rust-l
...
paint-orde
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
92fda552d1 | ||
|
|
0d764afd4c | ||
|
|
678ff835d2 | ||
|
|
f531d953e3 | ||
|
|
6583c69612 |
@@ -1106,14 +1106,8 @@ impl AppContext {
|
||||
for window in self.windows() {
|
||||
window
|
||||
.update(self, |_, cx| {
|
||||
cx.window
|
||||
.rendered_frame
|
||||
.dispatch_tree
|
||||
.clear_pending_keystrokes();
|
||||
cx.window
|
||||
.next_frame
|
||||
.dispatch_tree
|
||||
.clear_pending_keystrokes();
|
||||
cx.window.rendered_frame.clear_pending_keystrokes();
|
||||
cx.window.next_frame.clear_pending_keystrokes();
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
|
||||
457
crates/gpui/src/frame.rs
Normal file
457
crates/gpui/src/frame.rs
Normal file
@@ -0,0 +1,457 @@
|
||||
use crate::{
|
||||
Action, ActionRegistry, AnyTooltip, Bounds, ContentMask, CursorStyle, DispatchPhase,
|
||||
ElementContext, EntityId, FocusId, GlobalElementId, KeyBinding, KeyContext, KeyEvent, Keymap,
|
||||
KeymatchResult, Keystroke, KeystrokeMatcher, MouseEvent, Pixels, PlatformInputHandler,
|
||||
Primitive, Scene, SceneIndex, SmallVec, WindowContext,
|
||||
};
|
||||
use collections::FxHashMap;
|
||||
use std::{
|
||||
any::{Any, TypeId},
|
||||
cell::RefCell,
|
||||
iter,
|
||||
ops::Range,
|
||||
rc::Rc,
|
||||
};
|
||||
|
||||
// pub(crate) struct Frame {
|
||||
// pub(crate) window_active: bool,
|
||||
|
||||
// #[cfg(any(test, feature = "test-support"))]
|
||||
// pub(crate) debug_bounds: FxHashMap<String, Bounds<Pixels>>,
|
||||
// }
|
||||
|
||||
pub struct Frame {
|
||||
elements: Vec<PaintedElement>,
|
||||
pub(crate) scene: Scene,
|
||||
focus: Option<FocusId>,
|
||||
pub(crate) window_active: bool,
|
||||
mouse_listeners: Vec<AnyMouseListener>,
|
||||
key_listeners: Vec<KeyListener>,
|
||||
action_listeners: Vec<ActionListener>,
|
||||
element_states: FxHashMap<GlobalElementId, ElementStateBox>,
|
||||
|
||||
element_stack: Vec<PaintedElementId>,
|
||||
context_stack: Vec<KeyContext>,
|
||||
content_mask_stack: Vec<ContentMask<Pixels>>,
|
||||
focusable_node_ids: FxHashMap<FocusId, PaintedElementId>,
|
||||
view_node_ids: FxHashMap<EntityId, PaintedElementId>,
|
||||
keystroke_matchers: FxHashMap<SmallVec<[KeyContext; 4]>, KeystrokeMatcher>,
|
||||
keymap: Rc<RefCell<Keymap>>,
|
||||
action_registry: Rc<ActionRegistry>,
|
||||
}
|
||||
|
||||
impl Frame {
|
||||
pub fn new(keymap: Rc<RefCell<Keymap>>, action_registry: Rc<ActionRegistry>) -> Self {
|
||||
Frame {
|
||||
keymap,
|
||||
action_registry,
|
||||
elements: Vec::new(),
|
||||
scene: Scene::default(),
|
||||
focus: None,
|
||||
window_active: false,
|
||||
mouse_listeners: Vec::new(),
|
||||
key_listeners: Vec::new(),
|
||||
action_listeners: Vec::new(),
|
||||
element_states: FxHashMap::default(),
|
||||
element_stack: Vec::new(),
|
||||
context_stack: Vec::new(),
|
||||
content_mask_stack: Vec::new(),
|
||||
focusable_node_ids: FxHashMap::default(),
|
||||
view_node_ids: FxHashMap::default(),
|
||||
keystroke_matchers: FxHashMap::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) {
|
||||
self.elements.clear();
|
||||
self.scene.clear();
|
||||
self.focus = None;
|
||||
self.mouse_listeners.clear();
|
||||
self.key_listeners.clear();
|
||||
self.action_listeners.clear();
|
||||
self.element_states.clear();
|
||||
self.element_stack.clear();
|
||||
self.context_stack.clear();
|
||||
self.content_mask_stack.clear();
|
||||
self.focusable_node_ids.clear();
|
||||
self.view_node_ids.clear();
|
||||
self.keystroke_matchers.clear();
|
||||
}
|
||||
|
||||
pub fn clear_pending_keystrokes(&mut self) {
|
||||
self.keystroke_matchers.clear();
|
||||
}
|
||||
|
||||
/// Preserve keystroke matchers from previous frames to support multi-stroke
|
||||
/// bindings across multiple frames.
|
||||
pub fn preserve_pending_keystrokes(
|
||||
&mut self,
|
||||
prev_frame: &mut Self,
|
||||
focus_id: Option<FocusId>,
|
||||
) {
|
||||
self.context_stack.clear();
|
||||
for element in self.dispatch_path(focus_id) {
|
||||
if let Some(context) = element.key_context.clone() {
|
||||
self.context_stack.push(context);
|
||||
}
|
||||
|
||||
if let Some((context_stack, matcher)) = prev_frame
|
||||
.keystroke_matchers
|
||||
.remove_entry(self.context_stack.as_slice())
|
||||
{
|
||||
self.keystroke_matchers.insert(context_stack, matcher);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_focus(&mut self, focus_id: Option<FocusId>) {
|
||||
self.focus = focus_id;
|
||||
}
|
||||
|
||||
pub fn set_window_active(&mut self, active: bool) {
|
||||
self.window_active = active;
|
||||
}
|
||||
|
||||
pub fn window_active(&self) -> bool {
|
||||
self.window_active
|
||||
}
|
||||
|
||||
pub fn focus_contains(&self, parent: FocusId, child: FocusId) -> bool {
|
||||
if parent == child {
|
||||
return true;
|
||||
}
|
||||
|
||||
if let Some(parent_node_id) = self.focusable_node_ids.get(&parent) {
|
||||
let mut current_node_id = self.focusable_node_ids.get(&child).copied();
|
||||
while let Some(node_id) = current_node_id {
|
||||
if node_id == *parent_node_id {
|
||||
return true;
|
||||
}
|
||||
current_node_id = self.elements[node_id.0].parent;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub fn focus_path(&self) -> SmallVec<[FocusId; 8]> {
|
||||
let Some(focus_id) = self.focus else {
|
||||
return SmallVec::new();
|
||||
};
|
||||
|
||||
let mut focus_path = self
|
||||
.dispatch_path(Some(focus_id))
|
||||
.flat_map(|element| element.focus_id)
|
||||
.collect::<SmallVec<[FocusId; 8]>>();
|
||||
focus_path.reverse(); // Reverse the path so it goes from the root to the focused node.
|
||||
focus_path
|
||||
}
|
||||
|
||||
pub fn view_path(&self, view_id: EntityId) -> SmallVec<[EntityId; 8]> {
|
||||
let Some(element_id) = self.view_node_ids.get(&view_id) else {
|
||||
return SmallVec::new();
|
||||
};
|
||||
|
||||
let mut view_path = self
|
||||
.ancestors(Some(*element_id))
|
||||
.flat_map(|element| element.view_id)
|
||||
.collect::<SmallVec<[EntityId; 8]>>();
|
||||
view_path.reverse(); // Reverse the path so it goes from the root to the focused node.
|
||||
view_path
|
||||
}
|
||||
|
||||
pub fn action_dispatch_path(&self, focus_id: Option<FocusId>) -> SmallVec<[ActionListener; 8]> {
|
||||
let mut action_dispatch_path = self
|
||||
.dispatch_path(focus_id)
|
||||
.flat_map(|element| {
|
||||
self.action_listeners[element.action_listeners.clone()]
|
||||
.iter()
|
||||
.cloned()
|
||||
})
|
||||
.collect::<SmallVec<[ActionListener; 8]>>();
|
||||
action_dispatch_path.reverse(); // Reverse the path so it goes from the root to the focused node.
|
||||
action_dispatch_path
|
||||
}
|
||||
|
||||
pub fn key_dispatch_path(&self, focus_id: Option<FocusId>) -> SmallVec<[KeyListener; 8]> {
|
||||
let mut key_dispatch_path: SmallVec<[KeyListener; 8]> = self
|
||||
.dispatch_path(focus_id)
|
||||
.flat_map(|element| {
|
||||
self.key_listeners[element.key_listeners.clone()]
|
||||
.iter()
|
||||
.cloned()
|
||||
})
|
||||
.collect::<SmallVec<[KeyListener; 8]>>();
|
||||
key_dispatch_path.reverse(); // Reverse the path so it goes from the root to the focused node.
|
||||
key_dispatch_path
|
||||
}
|
||||
|
||||
pub fn available_actions(&self, focus_id: Option<FocusId>) -> Vec<Box<dyn Action>> {
|
||||
let mut actions = Vec::<Box<dyn Action>>::new();
|
||||
for ActionListener { action_type, .. } in self.action_dispatch_path(focus_id) {
|
||||
if let Err(ix) = actions.binary_search_by_key(&action_type, |a| a.as_any().type_id()) {
|
||||
// Intentionally silence these errors without logging.
|
||||
// If an action cannot be built by default, it's not available.
|
||||
let action = self.action_registry.build_action_type(&action_type).ok();
|
||||
if let Some(action) = action {
|
||||
actions.insert(ix, action);
|
||||
}
|
||||
}
|
||||
}
|
||||
actions
|
||||
}
|
||||
|
||||
pub fn bindings_for_action(
|
||||
&self,
|
||||
action: &dyn Action,
|
||||
focus_id: Option<FocusId>,
|
||||
) -> Vec<KeyBinding> {
|
||||
let context_stack = self
|
||||
.dispatch_path(focus_id)
|
||||
.flat_map(|element| element.key_context.clone())
|
||||
.collect::<SmallVec<[KeyContext; 8]>>();
|
||||
|
||||
let keymap = self.keymap.borrow();
|
||||
keymap
|
||||
.bindings_for_action(action)
|
||||
.filter(|binding| {
|
||||
for i in 0..context_stack.len() {
|
||||
let context = &context_stack[0..=i];
|
||||
if keymap.binding_enabled(binding, context) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
})
|
||||
.cloned()
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn is_action_available(&self, action: &dyn Action, focus_id: Option<FocusId>) -> bool {
|
||||
for element in self.dispatch_path(focus_id) {
|
||||
if self.action_listeners[element.action_listeners.clone()]
|
||||
.iter()
|
||||
.any(|listener| listener.action_type == action.as_any().type_id())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub fn match_keystroke(
|
||||
&mut self,
|
||||
keystroke: &Keystroke,
|
||||
focus_id: Option<FocusId>,
|
||||
) -> KeymatchResult {
|
||||
let mut bindings = SmallVec::<[KeyBinding; 1]>::new();
|
||||
let mut pending = false;
|
||||
|
||||
let mut context_stack: SmallVec<[KeyContext; 4]> = SmallVec::new();
|
||||
|
||||
for element in self.dispatch_path(focus_id) {
|
||||
if let Some(context) = element.key_context.clone() {
|
||||
context_stack.push(context);
|
||||
}
|
||||
}
|
||||
|
||||
while !context_stack.is_empty() {
|
||||
let keystroke_matcher = self
|
||||
.keystroke_matchers
|
||||
.entry(context_stack.clone())
|
||||
.or_insert_with(|| KeystrokeMatcher::new(self.keymap.clone()));
|
||||
|
||||
let result = keystroke_matcher.match_keystroke(keystroke, &context_stack);
|
||||
if result.pending && !pending && !bindings.is_empty() {
|
||||
context_stack.pop();
|
||||
continue;
|
||||
}
|
||||
|
||||
pending = result.pending || pending;
|
||||
for new_binding in result.bindings {
|
||||
match bindings
|
||||
.iter()
|
||||
.position(|el| el.keystrokes.len() < new_binding.keystrokes.len())
|
||||
{
|
||||
Some(idx) => {
|
||||
bindings.insert(idx, new_binding);
|
||||
}
|
||||
None => bindings.push(new_binding),
|
||||
}
|
||||
}
|
||||
context_stack.pop();
|
||||
}
|
||||
|
||||
KeymatchResult { bindings, pending }
|
||||
}
|
||||
|
||||
pub fn has_pending_keystrokes(&self) -> bool {
|
||||
self.keystroke_matchers
|
||||
.iter()
|
||||
.any(|(_, matcher)| matcher.has_pending_keystrokes())
|
||||
}
|
||||
|
||||
fn dispatch_path(&self, focus_id: Option<FocusId>) -> impl Iterator<Item = &PaintedElement> {
|
||||
let mut current_node_id = focus_id
|
||||
.and_then(|focus_id| self.focusable_node_ids.get(&focus_id).copied())
|
||||
.or_else(|| self.elements.is_empty().then(|| PaintedElementId(0)));
|
||||
self.ancestors(current_node_id)
|
||||
}
|
||||
|
||||
fn ancestors(
|
||||
&self,
|
||||
mut current_node_id: Option<PaintedElementId>,
|
||||
) -> impl Iterator<Item = &PaintedElement> {
|
||||
iter::from_fn(move || {
|
||||
let node_id = current_node_id?;
|
||||
current_node_id = self.elements[node_id.0].parent;
|
||||
Some(&self.elements[node_id.0])
|
||||
})
|
||||
}
|
||||
|
||||
pub fn push_element(&mut self) {
|
||||
let parent = self.element_stack.last().copied();
|
||||
let element_id = PaintedElementId(self.elements.len());
|
||||
let scene_index = self.scene.current_index();
|
||||
self.elements.push(PaintedElement {
|
||||
parent,
|
||||
scene_primitives: scene_index.clone()..scene_index,
|
||||
mouse_listeners: self.mouse_listeners.len()..self.mouse_listeners.len(),
|
||||
key_listeners: self.key_listeners.len()..self.key_listeners.len(),
|
||||
action_listeners: self.action_listeners.len()..self.action_listeners.len(),
|
||||
..Default::default()
|
||||
});
|
||||
self.element_stack.push(element_id);
|
||||
}
|
||||
|
||||
pub fn pop_element(&mut self) {
|
||||
let element = &self.elements[self.active_element_id().0];
|
||||
if element.key_context.is_some() {
|
||||
self.context_stack.pop();
|
||||
}
|
||||
self.element_stack.pop();
|
||||
}
|
||||
|
||||
pub fn set_key_context(&mut self, context: KeyContext) {
|
||||
let element_id = self.active_element_id();
|
||||
self.elements[element_id.0].key_context = Some(context.clone());
|
||||
self.context_stack.push(context);
|
||||
}
|
||||
|
||||
pub fn set_focus_id(&mut self, focus_id: FocusId) {
|
||||
let element_id = self.active_element_id();
|
||||
self.elements[element_id.0].focus_id = Some(focus_id);
|
||||
self.focusable_node_ids.insert(focus_id, element_id);
|
||||
}
|
||||
|
||||
pub fn set_view_id(&mut self, view_id: EntityId) {
|
||||
let element_id = self.active_element_id();
|
||||
self.elements[element_id.0].view_id = Some(view_id);
|
||||
self.view_node_ids.insert(view_id, element_id);
|
||||
}
|
||||
|
||||
pub fn paint_primitive<P: Into<Primitive>>(&mut self, build_primitive: impl FnOnce(u32) -> P) {
|
||||
self.scene.paint_primitive(build_primitive);
|
||||
let element_id = self.active_element_id();
|
||||
self.elements[element_id.0].scene_primitives.end = self.scene.current_index();
|
||||
}
|
||||
|
||||
pub fn on_mouse_event<E: MouseEvent>(
|
||||
&mut self,
|
||||
mut listener: impl 'static + FnMut(&E, DispatchPhase, &mut WindowContext),
|
||||
) {
|
||||
self.mouse_listeners.push(Rc::new(move |event, phase, cx| {
|
||||
if let Some(event) = event.downcast_ref::<E>() {
|
||||
listener(event, phase, cx);
|
||||
}
|
||||
}));
|
||||
self.active_element().mouse_listeners.end += 1;
|
||||
}
|
||||
|
||||
pub fn on_key_event<E: KeyEvent>(
|
||||
&mut self,
|
||||
listener: impl Fn(&E, DispatchPhase, &mut WindowContext) + 'static,
|
||||
) {
|
||||
self.key_listeners.push(Rc::new(|event, phase, cx| {
|
||||
if let Some(event) = event.downcast_ref::<E>() {
|
||||
listener(event, phase, cx);
|
||||
}
|
||||
}));
|
||||
self.active_element().key_listeners.end += 1;
|
||||
}
|
||||
|
||||
pub fn on_action(
|
||||
&mut self,
|
||||
action_type: TypeId,
|
||||
listener: Rc<dyn Fn(&dyn Any, DispatchPhase, &mut WindowContext) + 'static>,
|
||||
) {
|
||||
self.action_listeners.push(ActionListener {
|
||||
action_type,
|
||||
listener: Rc::new(|event, phase, cx| listener(event, phase, cx)),
|
||||
});
|
||||
|
||||
self.active_element().action_listeners.end += 1;
|
||||
}
|
||||
|
||||
pub fn set_input_handler(&mut self, handler: Option<PlatformInputHandler>) {
|
||||
self.active_element().input_handler = handler;
|
||||
}
|
||||
|
||||
pub fn set_tooltip(&mut self, tooltip: Option<AnyTooltip>) {
|
||||
self.active_element().tooltip = tooltip;
|
||||
}
|
||||
|
||||
pub fn set_cursor_style(&mut self, cursor_style: Option<CursorStyle>) {
|
||||
self.active_element().cursor_style = cursor_style;
|
||||
}
|
||||
|
||||
fn active_element_id(&self) -> PaintedElementId {
|
||||
self.element_stack
|
||||
.last()
|
||||
.copied()
|
||||
.expect("There should be an active element")
|
||||
}
|
||||
|
||||
fn active_element(&mut self) -> &mut PaintedElement {
|
||||
let element_id = self.active_element_id();
|
||||
&mut self.elements[element_id.0]
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct PaintedElement {
|
||||
id: Option<GlobalElementId>,
|
||||
bounds: Bounds<Pixels>,
|
||||
content_mask: ContentMask<Pixels>,
|
||||
opaque: bool,
|
||||
scene_primitives: Range<SceneIndex>,
|
||||
mouse_listeners: Range<usize>,
|
||||
key_listeners: Range<usize>,
|
||||
action_listeners: Range<usize>,
|
||||
input_handler: Option<PlatformInputHandler>,
|
||||
tooltip: Option<AnyTooltip>,
|
||||
cursor_style: Option<CursorStyle>,
|
||||
key_context: Option<KeyContext>,
|
||||
focus_id: Option<FocusId>,
|
||||
view_id: Option<EntityId>,
|
||||
parent: Option<PaintedElementId>,
|
||||
}
|
||||
|
||||
pub(crate) struct ElementStateBox {
|
||||
pub(crate) inner: Box<dyn Any>,
|
||||
pub(crate) parent_view_id: EntityId,
|
||||
#[cfg(debug_assertions)]
|
||||
pub(crate) type_name: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||
struct PaintedElementId(usize);
|
||||
|
||||
type AnyMouseListener = Rc<dyn Fn(&dyn Any, DispatchPhase, &mut ElementContext) + 'static>;
|
||||
|
||||
type KeyListener = Rc<dyn Fn(&dyn Any, DispatchPhase, &mut ElementContext)>;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct ActionListener {
|
||||
pub(crate) action_type: TypeId,
|
||||
pub(crate) listener: Rc<dyn Fn(&dyn Any, DispatchPhase, &mut WindowContext)>,
|
||||
}
|
||||
@@ -74,6 +74,7 @@ mod color;
|
||||
mod element;
|
||||
mod elements;
|
||||
mod executor;
|
||||
mod frame;
|
||||
mod geometry;
|
||||
mod image_cache;
|
||||
mod input;
|
||||
@@ -122,6 +123,7 @@ pub use ctor::ctor;
|
||||
pub use element::*;
|
||||
pub use elements::*;
|
||||
pub use executor::*;
|
||||
pub use frame::*;
|
||||
pub use geometry::*;
|
||||
pub use gpui_macros::{register_action, test, IntoElement, Render};
|
||||
use image_cache::*;
|
||||
|
||||
@@ -68,26 +68,22 @@ impl<V: 'static> ElementInputHandler<V> {
|
||||
}
|
||||
|
||||
impl<V: ViewInputHandler> InputHandler for ElementInputHandler<V> {
|
||||
fn selected_text_range(&mut self, cx: &mut WindowContext) -> Option<Range<usize>> {
|
||||
fn selected_text_range(&self, cx: &mut WindowContext) -> Option<Range<usize>> {
|
||||
self.view
|
||||
.update(cx, |view, cx| view.selected_text_range(cx))
|
||||
}
|
||||
|
||||
fn marked_text_range(&mut self, cx: &mut WindowContext) -> Option<Range<usize>> {
|
||||
fn marked_text_range(&self, cx: &mut WindowContext) -> Option<Range<usize>> {
|
||||
self.view.update(cx, |view, cx| view.marked_text_range(cx))
|
||||
}
|
||||
|
||||
fn text_for_range(
|
||||
&mut self,
|
||||
range_utf16: Range<usize>,
|
||||
cx: &mut WindowContext,
|
||||
) -> Option<String> {
|
||||
fn text_for_range(&self, range_utf16: Range<usize>, cx: &mut WindowContext) -> Option<String> {
|
||||
self.view
|
||||
.update(cx, |view, cx| view.text_for_range(range_utf16, cx))
|
||||
}
|
||||
|
||||
fn replace_text_in_range(
|
||||
&mut self,
|
||||
&self,
|
||||
replacement_range: Option<Range<usize>>,
|
||||
text: &str,
|
||||
cx: &mut WindowContext,
|
||||
@@ -98,7 +94,7 @@ impl<V: ViewInputHandler> InputHandler for ElementInputHandler<V> {
|
||||
}
|
||||
|
||||
fn replace_and_mark_text_in_range(
|
||||
&mut self,
|
||||
&self,
|
||||
range_utf16: Option<Range<usize>>,
|
||||
new_text: &str,
|
||||
new_selected_range: Option<Range<usize>>,
|
||||
@@ -109,12 +105,12 @@ impl<V: ViewInputHandler> InputHandler for ElementInputHandler<V> {
|
||||
});
|
||||
}
|
||||
|
||||
fn unmark_text(&mut self, cx: &mut WindowContext) {
|
||||
fn unmark_text(&self, cx: &mut WindowContext) {
|
||||
self.view.update(cx, |view, cx| view.unmark_text(cx));
|
||||
}
|
||||
|
||||
fn bounds_for_range(
|
||||
&mut self,
|
||||
&self,
|
||||
range_utf16: Range<usize>,
|
||||
cx: &mut WindowContext,
|
||||
) -> Option<Bounds<Pixels>> {
|
||||
|
||||
@@ -108,6 +108,10 @@ impl DispatchTree {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.nodes.len()
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) {
|
||||
self.node_stack.clear();
|
||||
self.context_stack.clear();
|
||||
|
||||
@@ -430,30 +430,26 @@ pub trait InputHandler: 'static {
|
||||
/// Corresponds to [selectedRange()](https://developer.apple.com/documentation/appkit/nstextinputclient/1438242-selectedrange)
|
||||
///
|
||||
/// Return value is in terms of UTF-16 characters, from 0 to the length of the document
|
||||
fn selected_text_range(&mut self, cx: &mut WindowContext) -> Option<Range<usize>>;
|
||||
fn selected_text_range(&self, cx: &mut WindowContext) -> Option<Range<usize>>;
|
||||
|
||||
/// Get the range of the currently marked text, if any
|
||||
/// Corresponds to [markedRange()](https://developer.apple.com/documentation/appkit/nstextinputclient/1438250-markedrange)
|
||||
///
|
||||
/// Return value is in terms of UTF-16 characters, from 0 to the length of the document
|
||||
fn marked_text_range(&mut self, cx: &mut WindowContext) -> Option<Range<usize>>;
|
||||
fn marked_text_range(&self, cx: &mut WindowContext) -> Option<Range<usize>>;
|
||||
|
||||
/// Get the text for the given document range in UTF-16 characters
|
||||
/// Corresponds to [attributedSubstring(forProposedRange: actualRange:)](https://developer.apple.com/documentation/appkit/nstextinputclient/1438238-attributedsubstring)
|
||||
///
|
||||
/// range_utf16 is in terms of UTF-16 characters
|
||||
fn text_for_range(
|
||||
&mut self,
|
||||
range_utf16: Range<usize>,
|
||||
cx: &mut WindowContext,
|
||||
) -> Option<String>;
|
||||
fn text_for_range(&self, range_utf16: Range<usize>, cx: &mut WindowContext) -> Option<String>;
|
||||
|
||||
/// Replace the text in the given document range with the given text
|
||||
/// Corresponds to [insertText(_:replacementRange:)](https://developer.apple.com/documentation/appkit/nstextinputclient/1438258-inserttext)
|
||||
///
|
||||
/// replacement_range is in terms of UTF-16 characters
|
||||
fn replace_text_in_range(
|
||||
&mut self,
|
||||
&self,
|
||||
replacement_range: Option<Range<usize>>,
|
||||
text: &str,
|
||||
cx: &mut WindowContext,
|
||||
@@ -466,7 +462,7 @@ pub trait InputHandler: 'static {
|
||||
/// range_utf16 is in terms of UTF-16 characters
|
||||
/// new_selected_range is in terms of UTF-16 characters
|
||||
fn replace_and_mark_text_in_range(
|
||||
&mut self,
|
||||
&self,
|
||||
range_utf16: Option<Range<usize>>,
|
||||
new_text: &str,
|
||||
new_selected_range: Option<Range<usize>>,
|
||||
@@ -475,14 +471,14 @@ pub trait InputHandler: 'static {
|
||||
|
||||
/// Remove the IME 'composing' state from the document
|
||||
/// Corresponds to [unmarkText()](https://developer.apple.com/documentation/appkit/nstextinputclient/1438239-unmarktext)
|
||||
fn unmark_text(&mut self, cx: &mut WindowContext);
|
||||
fn unmark_text(&self, cx: &mut WindowContext);
|
||||
|
||||
/// Get the bounds of the given document range in screen coordinates
|
||||
/// Corresponds to [firstRect(forCharacterRange:actualRange:)](https://developer.apple.com/documentation/appkit/nstextinputclient/1438240-firstrect)
|
||||
///
|
||||
/// This is used for positioning the IME candidate window
|
||||
fn bounds_for_range(
|
||||
&mut self,
|
||||
&self,
|
||||
range_utf16: Range<usize>,
|
||||
cx: &mut WindowContext,
|
||||
) -> Option<Bounds<Pixels>>;
|
||||
|
||||
@@ -1,16 +1,12 @@
|
||||
use crate::{
|
||||
point, AtlasTextureId, AtlasTile, Bounds, ContentMask, Corners, Edges, EntityId, Hsla, Pixels,
|
||||
Point, ScaledPixels, StackingOrder,
|
||||
Point, ScaledPixels,
|
||||
};
|
||||
use collections::{BTreeMap, FxHashSet};
|
||||
use std::{fmt::Debug, iter::Peekable, slice};
|
||||
|
||||
#[allow(non_camel_case_types, unused)]
|
||||
pub(crate) type PathVertex_ScaledPixels = PathVertex<ScaledPixels>;
|
||||
|
||||
pub(crate) type LayerId = u32;
|
||||
pub(crate) type DrawOrder = u32;
|
||||
|
||||
#[derive(Default, Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
||||
#[repr(C)]
|
||||
pub(crate) struct ViewId {
|
||||
@@ -35,11 +31,20 @@ impl From<ViewId> for EntityId {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
/// An index into all the geometry in a `Scene` at a point in time.
|
||||
pub(crate) struct SceneIndex {
|
||||
pub(crate) shadows: usize,
|
||||
pub(crate) quads: usize,
|
||||
pub(crate) paths: usize,
|
||||
pub(crate) underlines: usize,
|
||||
pub(crate) monochrome_sprites: usize,
|
||||
pub(crate) polychrome_sprites: usize,
|
||||
pub(crate) surfaces: usize,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub(crate) struct Scene {
|
||||
last_layer: Option<(StackingOrder, LayerId)>,
|
||||
layers_by_order: BTreeMap<StackingOrder, LayerId>,
|
||||
orders_by_layer: BTreeMap<LayerId, StackingOrder>,
|
||||
pub(crate) shadows: Vec<Shadow>,
|
||||
pub(crate) quads: Vec<Quad>,
|
||||
pub(crate) paths: Vec<Path<ScaledPixels>>,
|
||||
@@ -47,13 +52,11 @@ pub(crate) struct Scene {
|
||||
pub(crate) monochrome_sprites: Vec<MonochromeSprite>,
|
||||
pub(crate) polychrome_sprites: Vec<PolychromeSprite>,
|
||||
pub(crate) surfaces: Vec<Surface>,
|
||||
pub(crate) primitive_count: u32,
|
||||
}
|
||||
|
||||
impl Scene {
|
||||
pub fn clear(&mut self) {
|
||||
self.last_layer = None;
|
||||
self.layers_by_order.clear();
|
||||
self.orders_by_layer.clear();
|
||||
self.shadows.clear();
|
||||
self.quads.clear();
|
||||
self.paths.clear();
|
||||
@@ -61,6 +64,19 @@ impl Scene {
|
||||
self.monochrome_sprites.clear();
|
||||
self.polychrome_sprites.clear();
|
||||
self.surfaces.clear();
|
||||
self.primitive_count = 0;
|
||||
}
|
||||
|
||||
pub fn current_index(&self) -> SceneIndex {
|
||||
SceneIndex {
|
||||
shadows: self.shadows.len(),
|
||||
quads: self.quads.len(),
|
||||
paths: self.paths.len(),
|
||||
underlines: self.underlines.len(),
|
||||
monochrome_sprites: self.monochrome_sprites.len(),
|
||||
polychrome_sprites: self.polychrome_sprites.len(),
|
||||
surfaces: self.surfaces.len(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn paths(&self) -> &[Path<ScaledPixels>] {
|
||||
@@ -93,8 +109,12 @@ impl Scene {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn insert(&mut self, order: &StackingOrder, primitive: impl Into<Primitive>) {
|
||||
let primitive = primitive.into();
|
||||
pub(crate) fn paint_primitive<T: Into<Primitive>>(
|
||||
&mut self,
|
||||
build_primitive: impl FnOnce(u32) -> T,
|
||||
) {
|
||||
let primitive = build_primitive(self.primitive_count).into();
|
||||
|
||||
let clipped_bounds = primitive
|
||||
.bounds()
|
||||
.intersect(&primitive.content_mask().bounds);
|
||||
@@ -104,150 +124,57 @@ impl Scene {
|
||||
return;
|
||||
}
|
||||
|
||||
let layer_id = self.layer_id_for_order(order);
|
||||
match primitive {
|
||||
Primitive::Shadow(mut shadow) => {
|
||||
shadow.layer_id = layer_id;
|
||||
self.shadows.push(shadow);
|
||||
}
|
||||
Primitive::Quad(mut quad) => {
|
||||
quad.layer_id = layer_id;
|
||||
self.quads.push(quad);
|
||||
}
|
||||
Primitive::Path(mut path) => {
|
||||
path.layer_id = layer_id;
|
||||
path.id = PathId(self.paths.len());
|
||||
self.paths.push(path);
|
||||
}
|
||||
Primitive::Underline(mut underline) => {
|
||||
underline.layer_id = layer_id;
|
||||
self.underlines.push(underline);
|
||||
}
|
||||
Primitive::MonochromeSprite(mut sprite) => {
|
||||
sprite.layer_id = layer_id;
|
||||
self.monochrome_sprites.push(sprite);
|
||||
}
|
||||
Primitive::PolychromeSprite(mut sprite) => {
|
||||
sprite.layer_id = layer_id;
|
||||
self.polychrome_sprites.push(sprite);
|
||||
}
|
||||
Primitive::Surface(mut surface) => {
|
||||
surface.layer_id = layer_id;
|
||||
self.surfaces.push(surface);
|
||||
}
|
||||
}
|
||||
|
||||
self.primitive_count += 1;
|
||||
}
|
||||
|
||||
fn layer_id_for_order(&mut self, order: &StackingOrder) -> LayerId {
|
||||
if let Some((last_order, last_layer_id)) = self.last_layer.as_ref() {
|
||||
if order == last_order {
|
||||
return *last_layer_id;
|
||||
}
|
||||
}
|
||||
|
||||
let layer_id = if let Some(layer_id) = self.layers_by_order.get(order) {
|
||||
*layer_id
|
||||
} else {
|
||||
let next_id = self.layers_by_order.len() as LayerId;
|
||||
self.layers_by_order.insert(order.clone(), next_id);
|
||||
self.orders_by_layer.insert(next_id, order.clone());
|
||||
next_id
|
||||
};
|
||||
self.last_layer = Some((order.clone(), layer_id));
|
||||
layer_id
|
||||
}
|
||||
|
||||
pub fn reuse_views(&mut self, views: &FxHashSet<EntityId>, prev_scene: &mut Self) {
|
||||
for shadow in prev_scene.shadows.drain(..) {
|
||||
if views.contains(&shadow.view_id.into()) {
|
||||
let order = &prev_scene.orders_by_layer[&shadow.layer_id];
|
||||
self.insert(order, shadow);
|
||||
}
|
||||
}
|
||||
|
||||
for quad in prev_scene.quads.drain(..) {
|
||||
if views.contains(&quad.view_id.into()) {
|
||||
let order = &prev_scene.orders_by_layer[&quad.layer_id];
|
||||
self.insert(order, quad);
|
||||
}
|
||||
}
|
||||
|
||||
for path in prev_scene.paths.drain(..) {
|
||||
if views.contains(&path.view_id.into()) {
|
||||
let order = &prev_scene.orders_by_layer[&path.layer_id];
|
||||
self.insert(order, path);
|
||||
}
|
||||
}
|
||||
|
||||
for underline in prev_scene.underlines.drain(..) {
|
||||
if views.contains(&underline.view_id.into()) {
|
||||
let order = &prev_scene.orders_by_layer[&underline.layer_id];
|
||||
self.insert(order, underline);
|
||||
}
|
||||
}
|
||||
|
||||
for sprite in prev_scene.monochrome_sprites.drain(..) {
|
||||
if views.contains(&sprite.view_id.into()) {
|
||||
let order = &prev_scene.orders_by_layer[&sprite.layer_id];
|
||||
self.insert(order, sprite);
|
||||
}
|
||||
}
|
||||
|
||||
for sprite in prev_scene.polychrome_sprites.drain(..) {
|
||||
if views.contains(&sprite.view_id.into()) {
|
||||
let order = &prev_scene.orders_by_layer[&sprite.layer_id];
|
||||
self.insert(order, sprite);
|
||||
}
|
||||
}
|
||||
|
||||
for surface in prev_scene.surfaces.drain(..) {
|
||||
if views.contains(&surface.view_id.into()) {
|
||||
let order = &prev_scene.orders_by_layer[&surface.layer_id];
|
||||
self.insert(order, surface);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn finish(&mut self) {
|
||||
let mut orders = vec![0; self.layers_by_order.len()];
|
||||
for (ix, layer_id) in self.layers_by_order.values().enumerate() {
|
||||
orders[*layer_id as usize] = ix as u32;
|
||||
}
|
||||
|
||||
for shadow in &mut self.shadows {
|
||||
shadow.order = orders[shadow.layer_id as usize];
|
||||
}
|
||||
self.shadows.sort_by_key(|shadow| shadow.order);
|
||||
|
||||
for quad in &mut self.quads {
|
||||
quad.order = orders[quad.layer_id as usize];
|
||||
}
|
||||
self.quads.sort_by_key(|quad| quad.order);
|
||||
|
||||
for path in &mut self.paths {
|
||||
path.order = orders[path.layer_id as usize];
|
||||
}
|
||||
self.paths.sort_by_key(|path| path.order);
|
||||
|
||||
for underline in &mut self.underlines {
|
||||
underline.order = orders[underline.layer_id as usize];
|
||||
}
|
||||
self.underlines.sort_by_key(|underline| underline.order);
|
||||
|
||||
for monochrome_sprite in &mut self.monochrome_sprites {
|
||||
monochrome_sprite.order = orders[monochrome_sprite.layer_id as usize];
|
||||
}
|
||||
self.monochrome_sprites.sort_by_key(|sprite| sprite.order);
|
||||
|
||||
for polychrome_sprite in &mut self.polychrome_sprites {
|
||||
polychrome_sprite.order = orders[polychrome_sprite.layer_id as usize];
|
||||
}
|
||||
self.polychrome_sprites.sort_by_key(|sprite| sprite.order);
|
||||
|
||||
for surface in &mut self.surfaces {
|
||||
surface.order = orders[surface.layer_id as usize];
|
||||
}
|
||||
self.surfaces.sort_by_key(|surface| surface.order);
|
||||
pub fn reuse_subscene(&mut self, prev_scene: &mut Self, start: SceneIndex, end: SceneIndex) {
|
||||
self.shadows
|
||||
.extend(prev_scene.shadows.drain(start.shadows..end.shadows));
|
||||
self.quads
|
||||
.extend(prev_scene.quads.drain(start.quads..end.quads));
|
||||
self.paths
|
||||
.extend(prev_scene.paths.drain(start.paths..end.paths));
|
||||
self.underlines.extend(
|
||||
prev_scene
|
||||
.underlines
|
||||
.drain(start.underlines..end.underlines),
|
||||
);
|
||||
self.monochrome_sprites.extend(
|
||||
prev_scene
|
||||
.monochrome_sprites
|
||||
.drain(start.monochrome_sprites..end.monochrome_sprites),
|
||||
);
|
||||
self.polychrome_sprites.extend(
|
||||
prev_scene
|
||||
.polychrome_sprites
|
||||
.drain(start.polychrome_sprites..end.polychrome_sprites),
|
||||
);
|
||||
self.surfaces
|
||||
.extend(prev_scene.surfaces.drain(start.surfaces..end.surfaces));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -281,25 +208,31 @@ impl<'a> Iterator for BatchIterator<'a> {
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let mut orders_and_kinds = [
|
||||
(
|
||||
self.shadows_iter.peek().map(|s| s.order),
|
||||
self.shadows_iter.peek().map(|s| s.draw_order),
|
||||
PrimitiveKind::Shadow,
|
||||
),
|
||||
(self.quads_iter.peek().map(|q| q.order), PrimitiveKind::Quad),
|
||||
(self.paths_iter.peek().map(|q| q.order), PrimitiveKind::Path),
|
||||
(
|
||||
self.underlines_iter.peek().map(|u| u.order),
|
||||
self.quads_iter.peek().map(|q| q.draw_order),
|
||||
PrimitiveKind::Quad,
|
||||
),
|
||||
(
|
||||
self.paths_iter.peek().map(|q| q.draw_order),
|
||||
PrimitiveKind::Path,
|
||||
),
|
||||
(
|
||||
self.underlines_iter.peek().map(|u| u.draw_order),
|
||||
PrimitiveKind::Underline,
|
||||
),
|
||||
(
|
||||
self.monochrome_sprites_iter.peek().map(|s| s.order),
|
||||
self.monochrome_sprites_iter.peek().map(|s| s.draw_order),
|
||||
PrimitiveKind::MonochromeSprite,
|
||||
),
|
||||
(
|
||||
self.polychrome_sprites_iter.peek().map(|s| s.order),
|
||||
self.polychrome_sprites_iter.peek().map(|s| s.draw_order),
|
||||
PrimitiveKind::PolychromeSprite,
|
||||
),
|
||||
(
|
||||
self.surfaces_iter.peek().map(|s| s.order),
|
||||
self.surfaces_iter.peek().map(|s| s.draw_order),
|
||||
PrimitiveKind::Surface,
|
||||
),
|
||||
];
|
||||
@@ -320,7 +253,7 @@ impl<'a> Iterator for BatchIterator<'a> {
|
||||
self.shadows_iter.next();
|
||||
while self
|
||||
.shadows_iter
|
||||
.next_if(|shadow| (shadow.order, batch_kind) < max_order_and_kind)
|
||||
.next_if(|shadow| (shadow.draw_order, batch_kind) < max_order_and_kind)
|
||||
.is_some()
|
||||
{
|
||||
shadows_end += 1;
|
||||
@@ -336,7 +269,7 @@ impl<'a> Iterator for BatchIterator<'a> {
|
||||
self.quads_iter.next();
|
||||
while self
|
||||
.quads_iter
|
||||
.next_if(|quad| (quad.order, batch_kind) < max_order_and_kind)
|
||||
.next_if(|quad| (quad.draw_order, batch_kind) < max_order_and_kind)
|
||||
.is_some()
|
||||
{
|
||||
quads_end += 1;
|
||||
@@ -350,7 +283,7 @@ impl<'a> Iterator for BatchIterator<'a> {
|
||||
self.paths_iter.next();
|
||||
while self
|
||||
.paths_iter
|
||||
.next_if(|path| (path.order, batch_kind) < max_order_and_kind)
|
||||
.next_if(|path| (path.draw_order, batch_kind) < max_order_and_kind)
|
||||
.is_some()
|
||||
{
|
||||
paths_end += 1;
|
||||
@@ -364,7 +297,7 @@ impl<'a> Iterator for BatchIterator<'a> {
|
||||
self.underlines_iter.next();
|
||||
while self
|
||||
.underlines_iter
|
||||
.next_if(|underline| (underline.order, batch_kind) < max_order_and_kind)
|
||||
.next_if(|underline| (underline.draw_order, batch_kind) < max_order_and_kind)
|
||||
.is_some()
|
||||
{
|
||||
underlines_end += 1;
|
||||
@@ -382,7 +315,7 @@ impl<'a> Iterator for BatchIterator<'a> {
|
||||
while self
|
||||
.monochrome_sprites_iter
|
||||
.next_if(|sprite| {
|
||||
(sprite.order, batch_kind) < max_order_and_kind
|
||||
(sprite.draw_order, batch_kind) < max_order_and_kind
|
||||
&& sprite.tile.texture_id == texture_id
|
||||
})
|
||||
.is_some()
|
||||
@@ -403,7 +336,7 @@ impl<'a> Iterator for BatchIterator<'a> {
|
||||
while self
|
||||
.polychrome_sprites_iter
|
||||
.next_if(|sprite| {
|
||||
(sprite.order, batch_kind) < max_order_and_kind
|
||||
(sprite.draw_order, batch_kind) < max_order_and_kind
|
||||
&& sprite.tile.texture_id == texture_id
|
||||
})
|
||||
.is_some()
|
||||
@@ -422,7 +355,7 @@ impl<'a> Iterator for BatchIterator<'a> {
|
||||
self.surfaces_iter.next();
|
||||
while self
|
||||
.surfaces_iter
|
||||
.next_if(|surface| (surface.order, batch_kind) < max_order_and_kind)
|
||||
.next_if(|surface| (surface.draw_order, batch_kind) < max_order_and_kind)
|
||||
.is_some()
|
||||
{
|
||||
surfaces_end += 1;
|
||||
@@ -504,9 +437,7 @@ pub(crate) enum PrimitiveBatch<'a> {
|
||||
#[derive(Default, Debug, Clone, Eq, PartialEq)]
|
||||
#[repr(C)]
|
||||
pub(crate) struct Quad {
|
||||
pub view_id: ViewId,
|
||||
pub layer_id: LayerId,
|
||||
pub order: DrawOrder,
|
||||
pub draw_order: u32,
|
||||
pub bounds: Bounds<ScaledPixels>,
|
||||
pub content_mask: ContentMask<ScaledPixels>,
|
||||
pub background: Hsla,
|
||||
@@ -517,7 +448,7 @@ pub(crate) struct Quad {
|
||||
|
||||
impl Ord for Quad {
|
||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||
self.order.cmp(&other.order)
|
||||
self.draw_order.cmp(&other.draw_order)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -536,9 +467,7 @@ impl From<Quad> for Primitive {
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
#[repr(C)]
|
||||
pub(crate) struct Underline {
|
||||
pub view_id: ViewId,
|
||||
pub layer_id: LayerId,
|
||||
pub order: DrawOrder,
|
||||
pub draw_order: u32,
|
||||
pub bounds: Bounds<ScaledPixels>,
|
||||
pub content_mask: ContentMask<ScaledPixels>,
|
||||
pub color: Hsla,
|
||||
@@ -548,7 +477,7 @@ pub(crate) struct Underline {
|
||||
|
||||
impl Ord for Underline {
|
||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||
self.order.cmp(&other.order)
|
||||
self.draw_order.cmp(&other.draw_order)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -567,9 +496,7 @@ impl From<Underline> for Primitive {
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
#[repr(C)]
|
||||
pub(crate) struct Shadow {
|
||||
pub view_id: ViewId,
|
||||
pub layer_id: LayerId,
|
||||
pub order: DrawOrder,
|
||||
pub draw_order: u32,
|
||||
pub bounds: Bounds<ScaledPixels>,
|
||||
pub corner_radii: Corners<ScaledPixels>,
|
||||
pub content_mask: ContentMask<ScaledPixels>,
|
||||
@@ -580,7 +507,7 @@ pub(crate) struct Shadow {
|
||||
|
||||
impl Ord for Shadow {
|
||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||
self.order.cmp(&other.order)
|
||||
self.draw_order.cmp(&other.draw_order)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -599,30 +526,13 @@ impl From<Shadow> for Primitive {
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
#[repr(C)]
|
||||
pub(crate) struct MonochromeSprite {
|
||||
pub view_id: ViewId,
|
||||
pub layer_id: LayerId,
|
||||
pub order: DrawOrder,
|
||||
pub draw_order: u32,
|
||||
pub bounds: Bounds<ScaledPixels>,
|
||||
pub content_mask: ContentMask<ScaledPixels>,
|
||||
pub color: Hsla,
|
||||
pub tile: AtlasTile,
|
||||
}
|
||||
|
||||
impl Ord for MonochromeSprite {
|
||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||
match self.order.cmp(&other.order) {
|
||||
std::cmp::Ordering::Equal => self.tile.tile_id.cmp(&other.tile.tile_id),
|
||||
order => order,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for MonochromeSprite {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MonochromeSprite> for Primitive {
|
||||
fn from(sprite: MonochromeSprite) -> Self {
|
||||
Primitive::MonochromeSprite(sprite)
|
||||
@@ -632,9 +542,7 @@ impl From<MonochromeSprite> for Primitive {
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
#[repr(C)]
|
||||
pub(crate) struct PolychromeSprite {
|
||||
pub view_id: ViewId,
|
||||
pub layer_id: LayerId,
|
||||
pub order: DrawOrder,
|
||||
pub draw_order: u32,
|
||||
pub bounds: Bounds<ScaledPixels>,
|
||||
pub content_mask: ContentMask<ScaledPixels>,
|
||||
pub corner_radii: Corners<ScaledPixels>,
|
||||
@@ -643,21 +551,6 @@ pub(crate) struct PolychromeSprite {
|
||||
pub pad: u32, // align to 8 bytes
|
||||
}
|
||||
|
||||
impl Ord for PolychromeSprite {
|
||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||
match self.order.cmp(&other.order) {
|
||||
std::cmp::Ordering::Equal => self.tile.tile_id.cmp(&other.tile.tile_id),
|
||||
order => order,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for PolychromeSprite {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PolychromeSprite> for Primitive {
|
||||
fn from(sprite: PolychromeSprite) -> Self {
|
||||
Primitive::PolychromeSprite(sprite)
|
||||
@@ -666,27 +559,13 @@ impl From<PolychromeSprite> for Primitive {
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub(crate) struct Surface {
|
||||
pub view_id: ViewId,
|
||||
pub layer_id: LayerId,
|
||||
pub order: DrawOrder,
|
||||
pub draw_order: u32,
|
||||
pub bounds: Bounds<ScaledPixels>,
|
||||
pub content_mask: ContentMask<ScaledPixels>,
|
||||
#[cfg(target_os = "macos")]
|
||||
pub image_buffer: media::core_video::CVImageBuffer,
|
||||
}
|
||||
|
||||
impl Ord for Surface {
|
||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||
self.order.cmp(&other.order)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Surface {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Surface> for Primitive {
|
||||
fn from(surface: Surface) -> Self {
|
||||
Primitive::Surface(surface)
|
||||
@@ -699,10 +578,8 @@ pub(crate) struct PathId(pub(crate) usize);
|
||||
/// A line made up of a series of vertices and control points.
|
||||
#[derive(Debug)]
|
||||
pub struct Path<P: Clone + Default + Debug> {
|
||||
pub(crate) draw_order: u32,
|
||||
pub(crate) id: PathId,
|
||||
pub(crate) view_id: ViewId,
|
||||
layer_id: LayerId,
|
||||
order: DrawOrder,
|
||||
pub(crate) bounds: Bounds<P>,
|
||||
pub(crate) content_mask: ContentMask<P>,
|
||||
pub(crate) vertices: Vec<PathVertex<P>>,
|
||||
@@ -716,10 +593,8 @@ impl Path<Pixels> {
|
||||
/// Create a new path with the given starting point.
|
||||
pub fn new(start: Point<Pixels>) -> Self {
|
||||
Self {
|
||||
draw_order: 0,
|
||||
id: PathId(0),
|
||||
view_id: ViewId::default(),
|
||||
layer_id: LayerId::default(),
|
||||
order: DrawOrder::default(),
|
||||
vertices: Vec::new(),
|
||||
start,
|
||||
current: start,
|
||||
@@ -736,10 +611,8 @@ impl Path<Pixels> {
|
||||
/// Scale this path by the given factor.
|
||||
pub fn scale(&self, factor: f32) -> Path<ScaledPixels> {
|
||||
Path {
|
||||
draw_order: self.draw_order,
|
||||
id: self.id,
|
||||
view_id: self.view_id,
|
||||
layer_id: self.layer_id,
|
||||
order: self.order,
|
||||
bounds: self.bounds.scale(factor),
|
||||
content_mask: self.content_mask.scale(factor),
|
||||
vertices: self
|
||||
@@ -825,13 +698,13 @@ impl Eq for Path<ScaledPixels> {}
|
||||
|
||||
impl PartialEq for Path<ScaledPixels> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.order == other.order
|
||||
self.draw_order == other.draw_order
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for Path<ScaledPixels> {
|
||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||
self.order.cmp(&other.order)
|
||||
self.draw_order.cmp(&other.draw_order)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
use crate::{
|
||||
seal::Sealed, AnyElement, AnyModel, AnyWeakModel, AppContext, AvailableSpace, Bounds,
|
||||
ContentMask, Element, ElementContext, ElementId, Entity, EntityId, Flatten, FocusHandle,
|
||||
FocusableView, IntoElement, LayoutId, Model, Pixels, Point, Render, Size, StackingOrder, Style,
|
||||
TextStyle, ViewContext, VisualContext, WeakModel,
|
||||
FocusableView, FrameIndex, IntoElement, LayoutId, Model, Pixels, Point, Render, Size,
|
||||
StackingOrder, Style, TextStyle, ViewContext, VisualContext, WeakModel,
|
||||
};
|
||||
use anyhow::{Context, Result};
|
||||
use std::{
|
||||
any::{type_name, TypeId},
|
||||
fmt,
|
||||
hash::{Hash, Hasher},
|
||||
ops::Range,
|
||||
};
|
||||
|
||||
/// A view is a piece of state that can be presented on screen by implementing the [Render] trait.
|
||||
@@ -24,15 +25,16 @@ impl<V> Sealed for View<V> {}
|
||||
pub struct AnyViewState {
|
||||
root_style: Style,
|
||||
next_stacking_order_id: u16,
|
||||
cache_key: Option<ViewCacheKey>,
|
||||
cache_state: Option<ViewCacheState>,
|
||||
element: Option<AnyElement>,
|
||||
}
|
||||
|
||||
struct ViewCacheKey {
|
||||
struct ViewCacheState {
|
||||
bounds: Bounds<Pixels>,
|
||||
stacking_order: StackingOrder,
|
||||
content_mask: ContentMask<Pixels>,
|
||||
text_style: TextStyle,
|
||||
subframe_range: Range<FrameIndex>,
|
||||
}
|
||||
|
||||
impl<V: 'static> Entity<V> for View<V> {
|
||||
@@ -297,7 +299,7 @@ impl Element for AnyView {
|
||||
let state = AnyViewState {
|
||||
root_style,
|
||||
next_stacking_order_id: 0,
|
||||
cache_key: None,
|
||||
cache_state: None,
|
||||
element: Some(element),
|
||||
};
|
||||
(layout_id, state)
|
||||
@@ -311,23 +313,25 @@ impl Element for AnyView {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(cache_key) = state.cache_key.as_mut() {
|
||||
if cache_key.bounds == bounds
|
||||
&& cache_key.content_mask == cx.content_mask()
|
||||
&& cache_key.stacking_order == *cx.stacking_order()
|
||||
&& cache_key.text_style == cx.text_style()
|
||||
if let Some(cache_state) = state.cache_state.as_mut() {
|
||||
if cache_state.bounds == bounds
|
||||
&& cache_state.content_mask == cx.content_mask()
|
||||
&& cache_state.stacking_order == *cx.stacking_order()
|
||||
&& cache_state.text_style == cx.text_style()
|
||||
{
|
||||
cx.reuse_view(state.next_stacking_order_id);
|
||||
cx.reuse_view(cache_state.subframe_range.clone());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let subframe_start = cx.window.next_frame.current_index();
|
||||
if let Some(mut element) = state.element.take() {
|
||||
element.paint(cx);
|
||||
} else {
|
||||
let mut element = (self.request_layout)(self, cx).1;
|
||||
element.draw(bounds.origin, bounds.size.into(), cx);
|
||||
}
|
||||
let subframe_end = cx.window.next_frame.current_index();
|
||||
|
||||
state.next_stacking_order_id = cx
|
||||
.window
|
||||
@@ -336,11 +340,12 @@ impl Element for AnyView {
|
||||
.last()
|
||||
.copied()
|
||||
.unwrap();
|
||||
state.cache_key = Some(ViewCacheKey {
|
||||
state.cache_state = Some(ViewCacheState {
|
||||
bounds,
|
||||
stacking_order: cx.stacking_order().clone(),
|
||||
content_mask: cx.content_mask(),
|
||||
text_style: cx.text_style(),
|
||||
subframe_range: subframe_start..subframe_end,
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use crate::{
|
||||
px, size, transparent_black, Action, AnyDrag, AnyView, AppContext, Arena, AsyncWindowContext,
|
||||
AvailableSpace, Bounds, Context, Corners, CursorStyle, DispatchActionListener, DispatchNodeId,
|
||||
DispatchTree, DisplayId, Edges, Effect, Entity, EntityId, EventEmitter, FileDropEvent, Flatten,
|
||||
Global, GlobalElementId, Hsla, KeyBinding, KeyContext, KeyDownEvent, KeyMatch, KeymatchResult,
|
||||
frame::ActionListener, px, size, transparent_black, Action, AnyDrag, AnyView, AppContext,
|
||||
Arena, AsyncWindowContext, AvailableSpace, Bounds, Context, Corners, CursorStyle, DisplayId,
|
||||
Edges, Effect, Entity, EntityId, EventEmitter, FileDropEvent, Flatten, Frame, Global,
|
||||
GlobalElementId, Hsla, KeyBinding, KeyContext, KeyDownEvent, KeyMatch, KeymatchResult,
|
||||
Keystroke, KeystrokeEvent, Model, ModelContext, Modifiers, MouseButton, MouseMoveEvent,
|
||||
MouseUpEvent, Pixels, PlatformAtlas, PlatformDisplay, PlatformInput, PlatformWindow, Point,
|
||||
PromptLevel, Render, ScaledPixels, SharedString, Size, SubscriberSet, Subscription,
|
||||
@@ -126,10 +126,7 @@ impl FocusId {
|
||||
|
||||
/// Obtains whether this handle contains the given handle in the most recently rendered frame.
|
||||
pub(crate) fn contains(&self, other: Self, cx: &WindowContext) -> bool {
|
||||
cx.window
|
||||
.rendered_frame
|
||||
.dispatch_tree
|
||||
.focus_contains(*self, other)
|
||||
cx.window.rendered_frame.focus_contains(*self, other)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -314,13 +311,6 @@ impl PendingInput {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct ElementStateBox {
|
||||
pub(crate) inner: Box<dyn Any>,
|
||||
pub(crate) parent_view_id: EntityId,
|
||||
#[cfg(debug_assertions)]
|
||||
pub(crate) type_name: &'static str,
|
||||
}
|
||||
|
||||
impl Window {
|
||||
pub(crate) fn new(
|
||||
handle: AnyWindowHandle,
|
||||
@@ -449,8 +439,8 @@ impl Window {
|
||||
layout_engine: Some(TaffyLayoutEngine::new()),
|
||||
root_view: None,
|
||||
element_id_stack: GlobalElementId::default(),
|
||||
rendered_frame: Frame::new(DispatchTree::new(cx.keymap.clone(), cx.actions.clone())),
|
||||
next_frame: Frame::new(DispatchTree::new(cx.keymap.clone(), cx.actions.clone())),
|
||||
rendered_frame: Frame::new(cx.keymap.clone(), cx.actions.clone()),
|
||||
next_frame: Frame::new(cx.keymap.clone(), cx.actions.clone()),
|
||||
next_frame_callbacks,
|
||||
dirty_views: FxHashSet::default(),
|
||||
focus_handles: Arc::new(RwLock::new(SlotMap::with_key())),
|
||||
@@ -561,10 +551,7 @@ impl<'a> WindowContext<'a> {
|
||||
}
|
||||
|
||||
self.window.focus = Some(handle.id);
|
||||
self.window
|
||||
.rendered_frame
|
||||
.dispatch_tree
|
||||
.clear_pending_keystrokes();
|
||||
self.window.rendered_frame.clear_pending_keystrokes();
|
||||
self.refresh();
|
||||
}
|
||||
|
||||
@@ -591,20 +578,10 @@ impl<'a> WindowContext<'a> {
|
||||
|
||||
/// Dispatch the given action on the currently focused element.
|
||||
pub fn dispatch_action(&mut self, action: Box<dyn Action>) {
|
||||
let focus_handle = self.focused();
|
||||
|
||||
let focus_id = self.window.focus;
|
||||
self.defer(move |cx| {
|
||||
let node_id = focus_handle
|
||||
.and_then(|handle| {
|
||||
cx.window
|
||||
.rendered_frame
|
||||
.dispatch_tree
|
||||
.focusable_node_id(handle.id)
|
||||
})
|
||||
.unwrap_or_else(|| cx.window.rendered_frame.dispatch_tree.root_node_id());
|
||||
|
||||
cx.propagate_event = true;
|
||||
cx.dispatch_action_on_node(node_id, action);
|
||||
cx.dispatch_action_on(focus_id, action);
|
||||
})
|
||||
}
|
||||
|
||||
@@ -632,14 +609,8 @@ impl<'a> WindowContext<'a> {
|
||||
}
|
||||
|
||||
pub(crate) fn clear_pending_keystrokes(&mut self) {
|
||||
self.window
|
||||
.rendered_frame
|
||||
.dispatch_tree
|
||||
.clear_pending_keystrokes();
|
||||
self.window
|
||||
.next_frame
|
||||
.dispatch_tree
|
||||
.clear_pending_keystrokes();
|
||||
self.window.rendered_frame.clear_pending_keystrokes();
|
||||
self.window.next_frame.clear_pending_keystrokes();
|
||||
}
|
||||
|
||||
/// Schedules the given function to be run at the end of the current effect cycle, allowing entities
|
||||
@@ -834,19 +805,9 @@ impl<'a> WindowContext<'a> {
|
||||
|
||||
/// Determine whether the given action is available along the dispatch path to the currently focused element.
|
||||
pub fn is_action_available(&self, action: &dyn Action) -> bool {
|
||||
let target = self
|
||||
.focused()
|
||||
.and_then(|focused_handle| {
|
||||
self.window
|
||||
.rendered_frame
|
||||
.dispatch_tree
|
||||
.focusable_node_id(focused_handle.id)
|
||||
})
|
||||
.unwrap_or_else(|| self.window.rendered_frame.dispatch_tree.root_node_id());
|
||||
self.window
|
||||
.rendered_frame
|
||||
.dispatch_tree
|
||||
.is_action_available(action, target)
|
||||
.is_action_available(action, self.window.focus)
|
||||
}
|
||||
|
||||
/// The position of the mouse relative to the window.
|
||||
@@ -863,36 +824,38 @@ impl<'a> WindowContext<'a> {
|
||||
/// on top of the given level. Layers who are extensions of the queried layer
|
||||
/// are not considered to be on top of queried layer.
|
||||
pub fn was_top_layer(&self, point: &Point<Pixels>, layer: &StackingOrder) -> bool {
|
||||
// Precondition: the depth map is ordered from topmost to bottomost.
|
||||
todo!()
|
||||
|
||||
for (opaque_layer, _, bounds) in self.window.rendered_frame.depth_map.iter() {
|
||||
if layer >= opaque_layer {
|
||||
// The queried layer is either above or is the same as the this opaque layer.
|
||||
// Anything after this point is guaranteed to be below the queried layer.
|
||||
return true;
|
||||
}
|
||||
// // Precondition: the depth map is ordered from topmost to bottomost.
|
||||
|
||||
if !bounds.contains(point) {
|
||||
// This opaque layer is above the queried layer but it doesn't contain
|
||||
// the given position, so we can ignore it even if it's above.
|
||||
continue;
|
||||
}
|
||||
// for (opaque_layer, _, bounds) in self.window.rendered_frame.depth_map.iter() {
|
||||
// if layer >= opaque_layer {
|
||||
// // The queried layer is either above or is the same as the this opaque layer.
|
||||
// // Anything after this point is guaranteed to be below the queried layer.
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// At this point, we've established that this opaque layer is on top of the queried layer
|
||||
// and contains the position:
|
||||
// If neither the opaque layer or the queried layer is an extension of the other then
|
||||
// we know they are on different stacking orders, and return false.
|
||||
let is_on_same_layer = opaque_layer
|
||||
.iter()
|
||||
.zip(layer.iter())
|
||||
.all(|(a, b)| a.z_index == b.z_index);
|
||||
// if !bounds.contains(point) {
|
||||
// // This opaque layer is above the queried layer but it doesn't contain
|
||||
// // the given position, so we can ignore it even if it's above.
|
||||
// continue;
|
||||
// }
|
||||
|
||||
if !is_on_same_layer {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// // At this point, we've established that this opaque layer is on top of the queried layer
|
||||
// // and contains the position:
|
||||
// // If neither the opaque layer or the queried layer is an extension of the other then
|
||||
// // we know they are on different stacking orders, and return false.
|
||||
// let is_on_same_layer = opaque_layer
|
||||
// .iter()
|
||||
// .zip(layer.iter())
|
||||
// .all(|(a, b)| a.z_index == b.z_index);
|
||||
|
||||
true
|
||||
// if !is_on_same_layer {
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
|
||||
// true
|
||||
}
|
||||
|
||||
pub(crate) fn was_top_layer_under_active_drag(
|
||||
@@ -900,52 +863,53 @@ impl<'a> WindowContext<'a> {
|
||||
point: &Point<Pixels>,
|
||||
layer: &StackingOrder,
|
||||
) -> bool {
|
||||
todo!()
|
||||
// Precondition: the depth map is ordered from topmost to bottomost.
|
||||
|
||||
for (opaque_layer, _, bounds) in self.window.rendered_frame.depth_map.iter() {
|
||||
if layer >= opaque_layer {
|
||||
// The queried layer is either above or is the same as the this opaque layer.
|
||||
// Anything after this point is guaranteed to be below the queried layer.
|
||||
return true;
|
||||
}
|
||||
// for (opaque_layer, _, bounds) in self.window.rendered_frame.depth_map.iter() {
|
||||
// if layer >= opaque_layer {
|
||||
// // The queried layer is either above or is the same as the this opaque layer.
|
||||
// // Anything after this point is guaranteed to be below the queried layer.
|
||||
// return true;
|
||||
// }
|
||||
|
||||
if !bounds.contains(point) {
|
||||
// This opaque layer is above the queried layer but it doesn't contain
|
||||
// the given position, so we can ignore it even if it's above.
|
||||
continue;
|
||||
}
|
||||
// if !bounds.contains(point) {
|
||||
// // This opaque layer is above the queried layer but it doesn't contain
|
||||
// // the given position, so we can ignore it even if it's above.
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// All normal content is rendered with a base z-index of 0, we know that if the root of this opaque layer
|
||||
// equals `ACTIVE_DRAG_Z_INDEX` then it must be the drag layer and we can ignore it as we are
|
||||
// looking to see if the queried layer was the topmost underneath the drag layer.
|
||||
if opaque_layer
|
||||
.first()
|
||||
.map(|c| c.z_index == ACTIVE_DRAG_Z_INDEX)
|
||||
.unwrap_or(false)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// // All normal content is rendered with a base z-index of 0, we know that if the root of this opaque layer
|
||||
// // equals `ACTIVE_DRAG_Z_INDEX` then it must be the drag layer and we can ignore it as we are
|
||||
// // looking to see if the queried layer was the topmost underneath the drag layer.
|
||||
// if opaque_layer
|
||||
// .first()
|
||||
// .map(|c| c.z_index == ACTIVE_DRAG_Z_INDEX)
|
||||
// .unwrap_or(false)
|
||||
// {
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// At this point, we've established that this opaque layer is on top of the queried layer
|
||||
// and contains the position:
|
||||
// If neither the opaque layer or the queried layer is an extension of the other then
|
||||
// we know they are on different stacking orders, and return false.
|
||||
let is_on_same_layer = opaque_layer
|
||||
.iter()
|
||||
.zip(layer.iter())
|
||||
.all(|(a, b)| a.z_index == b.z_index);
|
||||
// // At this point, we've established that this opaque layer is on top of the queried layer
|
||||
// // and contains the position:
|
||||
// // If neither the opaque layer or the queried layer is an extension of the other then
|
||||
// // we know they are on different stacking orders, and return false.
|
||||
// let is_on_same_layer = opaque_layer
|
||||
// .iter()
|
||||
// .zip(layer.iter())
|
||||
// .all(|(a, b)| a.z_index == b.z_index);
|
||||
|
||||
if !is_on_same_layer {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// if !is_on_same_layer {
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
|
||||
true
|
||||
// true
|
||||
}
|
||||
|
||||
/// Called during painting to get the current stacking order.
|
||||
pub fn stacking_order(&self) -> &StackingOrder {
|
||||
&self.window.next_frame.z_index_stack
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Produces a new frame and assigns it to `rendered_frame`. To actually show
|
||||
@@ -954,12 +918,6 @@ impl<'a> WindowContext<'a> {
|
||||
self.window.dirty.set(false);
|
||||
self.window.drawing = true;
|
||||
|
||||
if let Some(requested_handler) = self.window.rendered_frame.requested_input_handler.as_mut()
|
||||
{
|
||||
let input_handler = self.window.platform_window.take_input_handler();
|
||||
requested_handler.handler = input_handler;
|
||||
}
|
||||
|
||||
let root_view = self.window.root_view.take().unwrap();
|
||||
self.with_element_context(|cx| {
|
||||
cx.with_z_index(0, |cx| {
|
||||
@@ -967,7 +925,7 @@ impl<'a> WindowContext<'a> {
|
||||
// We need to use cx.cx here so we can utilize borrow splitting
|
||||
for (action_type, action_listeners) in &cx.cx.app.global_action_listeners {
|
||||
for action_listener in action_listeners.iter().cloned() {
|
||||
cx.cx.window.next_frame.dispatch_tree.on_action(
|
||||
cx.cx.window.next_frame.on_action(
|
||||
*action_type,
|
||||
Rc::new(
|
||||
move |action: &dyn Any, phase, cx: &mut WindowContext<'_>| {
|
||||
@@ -1010,15 +968,14 @@ impl<'a> WindowContext<'a> {
|
||||
}
|
||||
self.window.dirty_views.clear();
|
||||
|
||||
self.window.next_frame.preserve_pending_keystrokes(
|
||||
&mut self.window.rendered_frame.dispatch_tree,
|
||||
self.window.focus,
|
||||
);
|
||||
self.window.next_frame.set_focus(self.window.focus);
|
||||
self.window
|
||||
.next_frame
|
||||
.dispatch_tree
|
||||
.preserve_pending_keystrokes(
|
||||
&mut self.window.rendered_frame.dispatch_tree,
|
||||
self.window.focus,
|
||||
);
|
||||
self.window.next_frame.focus = self.window.focus;
|
||||
self.window.next_frame.window_active = self.window.active.get();
|
||||
.set_window_active(self.window.active.get());
|
||||
self.window.root_view = Some(root_view);
|
||||
|
||||
// Set the cursor only if we're the active window.
|
||||
@@ -1042,9 +999,10 @@ impl<'a> WindowContext<'a> {
|
||||
self.window.layout_engine.as_mut().unwrap().clear();
|
||||
self.text_system()
|
||||
.finish_frame(&self.window.next_frame.reused_views);
|
||||
self.window
|
||||
.next_frame
|
||||
.finish(&mut self.window.rendered_frame);
|
||||
// todo!()
|
||||
// self.window
|
||||
// .next_frame
|
||||
// .finish(&mut self.window.rendered_frame);
|
||||
ELEMENT_ARENA.with_borrow_mut(|element_arena| {
|
||||
let percentage = (element_arena.len() as f32 / element_arena.capacity() as f32) * 100.;
|
||||
if percentage >= 80. {
|
||||
@@ -1226,56 +1184,54 @@ impl<'a> WindowContext<'a> {
|
||||
}
|
||||
|
||||
fn dispatch_mouse_event(&mut self, event: &dyn Any) {
|
||||
if let Some(mut handlers) = self
|
||||
.window
|
||||
.rendered_frame
|
||||
.mouse_listeners
|
||||
.remove(&event.type_id())
|
||||
{
|
||||
// Because handlers may add other handlers, we sort every time.
|
||||
handlers.sort_by(|(a, _, _), (b, _, _)| a.cmp(b));
|
||||
todo!()
|
||||
// if let Some(mut handlers) = self
|
||||
// .window
|
||||
// .rendered_frame
|
||||
// .mouse_listeners
|
||||
// .remove(&event.type_id())
|
||||
// {
|
||||
// // Capture phase, events bubble from back to front. Handlers for this phase are used for
|
||||
// // special purposes, such as detecting events outside of a given Bounds.
|
||||
// for (_, _, handler) in &mut handlers {
|
||||
// self.with_element_context(|cx| {
|
||||
// handler(event, DispatchPhase::Capture, cx);
|
||||
// });
|
||||
// if !self.app.propagate_event {
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
// Capture phase, events bubble from back to front. Handlers for this phase are used for
|
||||
// special purposes, such as detecting events outside of a given Bounds.
|
||||
for (_, _, handler) in &mut handlers {
|
||||
self.with_element_context(|cx| {
|
||||
handler(event, DispatchPhase::Capture, cx);
|
||||
});
|
||||
if !self.app.propagate_event {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// // Bubble phase, where most normal handlers do their work.
|
||||
// if self.app.propagate_event {
|
||||
// for (_, _, handler) in handlers.iter_mut().rev() {
|
||||
// self.with_element_context(|cx| {
|
||||
// handler(event, DispatchPhase::Bubble, cx);
|
||||
// });
|
||||
// if !self.app.propagate_event {
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// Bubble phase, where most normal handlers do their work.
|
||||
if self.app.propagate_event {
|
||||
for (_, _, handler) in handlers.iter_mut().rev() {
|
||||
self.with_element_context(|cx| {
|
||||
handler(event, DispatchPhase::Bubble, cx);
|
||||
});
|
||||
if !self.app.propagate_event {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// self.window
|
||||
// .rendered_frame
|
||||
// .mouse_listeners
|
||||
// .insert(event.type_id(), handlers);
|
||||
// }
|
||||
|
||||
self.window
|
||||
.rendered_frame
|
||||
.mouse_listeners
|
||||
.insert(event.type_id(), handlers);
|
||||
}
|
||||
|
||||
if self.app.propagate_event && self.has_active_drag() {
|
||||
if event.is::<MouseMoveEvent>() {
|
||||
// If this was a mouse move event, redraw the window so that the
|
||||
// active drag can follow the mouse cursor.
|
||||
self.refresh();
|
||||
} else if event.is::<MouseUpEvent>() {
|
||||
// If this was a mouse up event, cancel the active drag and redraw
|
||||
// the window.
|
||||
self.active_drag = None;
|
||||
self.refresh();
|
||||
}
|
||||
}
|
||||
// if self.app.propagate_event && self.has_active_drag() {
|
||||
// if event.is::<MouseMoveEvent>() {
|
||||
// // If this was a mouse move event, redraw the window so that the
|
||||
// // active drag can follow the mouse cursor.
|
||||
// self.refresh();
|
||||
// } else if event.is::<MouseUpEvent>() {
|
||||
// // If this was a mouse up event, cancel the active drag and redraw
|
||||
// // the window.
|
||||
// self.active_drag = None;
|
||||
// self.refresh();
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
fn dispatch_key_event(&mut self, event: &dyn Any) {
|
||||
@@ -1283,29 +1239,14 @@ impl<'a> WindowContext<'a> {
|
||||
self.draw();
|
||||
}
|
||||
|
||||
let node_id = self
|
||||
.window
|
||||
.focus
|
||||
.and_then(|focus_id| {
|
||||
self.window
|
||||
.rendered_frame
|
||||
.dispatch_tree
|
||||
.focusable_node_id(focus_id)
|
||||
})
|
||||
.unwrap_or_else(|| self.window.rendered_frame.dispatch_tree.root_node_id());
|
||||
|
||||
let dispatch_path = self
|
||||
.window
|
||||
.rendered_frame
|
||||
.dispatch_tree
|
||||
.dispatch_path(node_id);
|
||||
let focus_id = self.window.focus;
|
||||
let dispatch_path = self.window.rendered_frame.key_dispatch_path(focus_id);
|
||||
|
||||
if let Some(key_down_event) = event.downcast_ref::<KeyDownEvent>() {
|
||||
let KeymatchResult { bindings, pending } = self
|
||||
.window
|
||||
.rendered_frame
|
||||
.dispatch_tree
|
||||
.dispatch_key(&key_down_event.keystroke, &dispatch_path);
|
||||
.match_keystroke(&key_down_event.keystroke, focus_id);
|
||||
|
||||
if pending {
|
||||
let mut currently_pending = self.window.pending_input.take().unwrap_or_default();
|
||||
@@ -1335,8 +1276,11 @@ impl<'a> WindowContext<'a> {
|
||||
self.window.pending_input = Some(currently_pending);
|
||||
|
||||
self.propagate_event = false;
|
||||
|
||||
return;
|
||||
} else if let Some(currently_pending) = self.window.pending_input.take() {
|
||||
}
|
||||
|
||||
if let Some(currently_pending) = self.window.pending_input.take() {
|
||||
if bindings
|
||||
.iter()
|
||||
.all(|binding| !currently_pending.used_by_binding(binding))
|
||||
@@ -1351,7 +1295,7 @@ impl<'a> WindowContext<'a> {
|
||||
|
||||
self.propagate_event = true;
|
||||
for binding in bindings {
|
||||
self.dispatch_action_on_node(node_id, binding.action.boxed_clone());
|
||||
self.dispatch_action_on(focus_id, binding.action.boxed_clone());
|
||||
if !self.propagate_event {
|
||||
self.dispatch_keystroke_observers(event, Some(binding.action));
|
||||
return;
|
||||
@@ -1359,7 +1303,7 @@ impl<'a> WindowContext<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
self.dispatch_key_down_up_event(event, &dispatch_path);
|
||||
self.dispatch_key_down_up_event(event, focus_id);
|
||||
if !self.propagate_event {
|
||||
return;
|
||||
}
|
||||
@@ -1367,61 +1311,37 @@ impl<'a> WindowContext<'a> {
|
||||
self.dispatch_keystroke_observers(event, None);
|
||||
}
|
||||
|
||||
fn dispatch_key_down_up_event(
|
||||
&mut self,
|
||||
event: &dyn Any,
|
||||
dispatch_path: &SmallVec<[DispatchNodeId; 32]>,
|
||||
) {
|
||||
fn dispatch_key_down_up_event(&mut self, event: &dyn Any, focus_id: Option<FocusId>) {
|
||||
// Capture phase
|
||||
for node_id in dispatch_path {
|
||||
let node = self.window.rendered_frame.dispatch_tree.node(*node_id);
|
||||
|
||||
for key_listener in node.key_listeners.clone() {
|
||||
self.with_element_context(|cx| {
|
||||
key_listener(event, DispatchPhase::Capture, cx);
|
||||
});
|
||||
if !self.propagate_event {
|
||||
return;
|
||||
}
|
||||
let key_dispatch_path = self.window.rendered_frame.key_dispatch_path(focus_id);
|
||||
for key_listener in &key_dispatch_path {
|
||||
self.with_element_context(|cx| {
|
||||
key_listener(event, DispatchPhase::Capture, cx);
|
||||
});
|
||||
if !self.propagate_event {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Bubble phase
|
||||
for node_id in dispatch_path.iter().rev() {
|
||||
// Handle low level key events
|
||||
let node = self.window.rendered_frame.dispatch_tree.node(*node_id);
|
||||
for key_listener in node.key_listeners.clone() {
|
||||
self.with_element_context(|cx| {
|
||||
key_listener(event, DispatchPhase::Bubble, cx);
|
||||
});
|
||||
if !self.propagate_event {
|
||||
return;
|
||||
}
|
||||
for key_listener in key_dispatch_path.iter().rev() {
|
||||
self.with_element_context(|cx| {
|
||||
key_listener(event, DispatchPhase::Bubble, cx);
|
||||
});
|
||||
if !self.propagate_event {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Determine whether a potential multi-stroke key binding is in progress on this window.
|
||||
pub fn has_pending_keystrokes(&self) -> bool {
|
||||
self.window
|
||||
.rendered_frame
|
||||
.dispatch_tree
|
||||
.has_pending_keystrokes()
|
||||
self.window.rendered_frame.has_pending_keystrokes()
|
||||
}
|
||||
|
||||
fn replay_pending_input(&mut self, currently_pending: PendingInput) {
|
||||
let node_id = self
|
||||
.window
|
||||
.focus
|
||||
.and_then(|focus_id| {
|
||||
self.window
|
||||
.rendered_frame
|
||||
.dispatch_tree
|
||||
.focusable_node_id(focus_id)
|
||||
})
|
||||
.unwrap_or_else(|| self.window.rendered_frame.dispatch_tree.root_node_id());
|
||||
|
||||
if self.window.focus != currently_pending.focus {
|
||||
let focus_id = self.window.focus;
|
||||
if focus_id != currently_pending.focus {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1429,25 +1349,19 @@ impl<'a> WindowContext<'a> {
|
||||
|
||||
self.propagate_event = true;
|
||||
for binding in currently_pending.bindings {
|
||||
self.dispatch_action_on_node(node_id, binding.action.boxed_clone());
|
||||
self.dispatch_action_on(focus_id, binding.action.boxed_clone());
|
||||
if !self.propagate_event {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let dispatch_path = self
|
||||
.window
|
||||
.rendered_frame
|
||||
.dispatch_tree
|
||||
.dispatch_path(node_id);
|
||||
|
||||
for keystroke in currently_pending.keystrokes {
|
||||
let event = KeyDownEvent {
|
||||
keystroke,
|
||||
is_held: false,
|
||||
};
|
||||
|
||||
self.dispatch_key_down_up_event(&event, &dispatch_path);
|
||||
self.dispatch_key_down_up_event(&event, focus_id);
|
||||
if !self.propagate_event {
|
||||
return;
|
||||
}
|
||||
@@ -1461,52 +1375,43 @@ impl<'a> WindowContext<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn dispatch_action_on_node(&mut self, node_id: DispatchNodeId, action: Box<dyn Action>) {
|
||||
let dispatch_path = self
|
||||
.window
|
||||
.rendered_frame
|
||||
.dispatch_tree
|
||||
.dispatch_path(node_id);
|
||||
fn dispatch_action_on(&mut self, focus_id: Option<FocusId>, action: Box<dyn Action>) {
|
||||
let dispatch_path = self.window.rendered_frame.action_dispatch_path(focus_id);
|
||||
|
||||
// Capture phase
|
||||
for node_id in &dispatch_path {
|
||||
let node = self.window.rendered_frame.dispatch_tree.node(*node_id);
|
||||
for DispatchActionListener {
|
||||
action_type,
|
||||
listener,
|
||||
} in node.action_listeners.clone()
|
||||
{
|
||||
let any_action = action.as_any();
|
||||
if action_type == any_action.type_id() {
|
||||
self.with_element_context(|cx| {
|
||||
listener(any_action, DispatchPhase::Capture, cx);
|
||||
});
|
||||
for ActionListener {
|
||||
action_type,
|
||||
listener,
|
||||
} in &dispatch_path
|
||||
{
|
||||
let any_action = action.as_any();
|
||||
if *action_type == any_action.type_id() {
|
||||
self.with_element_context(|cx| {
|
||||
listener(any_action, DispatchPhase::Capture, cx);
|
||||
});
|
||||
|
||||
if !self.propagate_event {
|
||||
return;
|
||||
}
|
||||
if !self.propagate_event {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Bubble phase
|
||||
for node_id in dispatch_path.iter().rev() {
|
||||
let node = self.window.rendered_frame.dispatch_tree.node(*node_id);
|
||||
for DispatchActionListener {
|
||||
action_type,
|
||||
listener,
|
||||
} in node.action_listeners.clone()
|
||||
{
|
||||
let any_action = action.as_any();
|
||||
if action_type == any_action.type_id() {
|
||||
self.propagate_event = false; // Actions stop propagation by default during the bubble phase
|
||||
for ActionListener {
|
||||
action_type,
|
||||
listener,
|
||||
} in dispatch_path.iter().rev()
|
||||
{
|
||||
let any_action = action.as_any();
|
||||
if *action_type == any_action.type_id() {
|
||||
self.propagate_event = false; // Actions stop propagation by default during the bubble phase
|
||||
|
||||
self.with_element_context(|cx| {
|
||||
listener(any_action, DispatchPhase::Bubble, cx);
|
||||
});
|
||||
self.with_element_context(|cx| {
|
||||
listener(any_action, DispatchPhase::Bubble, cx);
|
||||
});
|
||||
|
||||
if !self.propagate_event {
|
||||
return;
|
||||
}
|
||||
if !self.propagate_event {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1567,32 +1472,16 @@ impl<'a> WindowContext<'a> {
|
||||
|
||||
/// Returns all available actions for the focused element.
|
||||
pub fn available_actions(&self) -> Vec<Box<dyn Action>> {
|
||||
let node_id = self
|
||||
.window
|
||||
.focus
|
||||
.and_then(|focus_id| {
|
||||
self.window
|
||||
.rendered_frame
|
||||
.dispatch_tree
|
||||
.focusable_node_id(focus_id)
|
||||
})
|
||||
.unwrap_or_else(|| self.window.rendered_frame.dispatch_tree.root_node_id());
|
||||
|
||||
self.window
|
||||
.rendered_frame
|
||||
.dispatch_tree
|
||||
.available_actions(node_id)
|
||||
.available_actions(self.window.focus)
|
||||
}
|
||||
|
||||
/// Returns key bindings that invoke the given action on the currently focused element.
|
||||
pub fn bindings_for_action(&self, action: &dyn Action) -> Vec<KeyBinding> {
|
||||
self.window
|
||||
.rendered_frame
|
||||
.dispatch_tree
|
||||
.bindings_for_action(
|
||||
action,
|
||||
&self.window.rendered_frame.dispatch_tree.context_stack,
|
||||
)
|
||||
.bindings_for_action(action, self.window.focus)
|
||||
}
|
||||
|
||||
/// Returns any bindings that would invoke the given action on the given focus handle if it were focused.
|
||||
@@ -1601,17 +1490,9 @@ impl<'a> WindowContext<'a> {
|
||||
action: &dyn Action,
|
||||
focus_handle: &FocusHandle,
|
||||
) -> Vec<KeyBinding> {
|
||||
let dispatch_tree = &self.window.rendered_frame.dispatch_tree;
|
||||
|
||||
let Some(node_id) = dispatch_tree.focusable_node_id(focus_handle.id) else {
|
||||
return vec![];
|
||||
};
|
||||
let context_stack: Vec<_> = dispatch_tree
|
||||
.dispatch_path(node_id)
|
||||
.into_iter()
|
||||
.filter_map(|node_id| dispatch_tree.node(node_id).context.clone())
|
||||
.collect();
|
||||
dispatch_tree.bindings_for_action(action, &context_stack)
|
||||
self.window
|
||||
.rendered_frame
|
||||
.bindings_for_action(action, Some(focus_handle.id))
|
||||
}
|
||||
|
||||
/// Returns a generic event listener that invokes the given listener with the view and context associated with the given view handle.
|
||||
@@ -1647,15 +1528,6 @@ impl<'a> WindowContext<'a> {
|
||||
.on_should_close(Box::new(move || this.update(|cx| f(cx)).unwrap_or(true)))
|
||||
}
|
||||
|
||||
pub(crate) fn parent_view_id(&self) -> EntityId {
|
||||
*self
|
||||
.window
|
||||
.next_frame
|
||||
.view_stack
|
||||
.last()
|
||||
.expect("a view should always be on the stack while drawing")
|
||||
}
|
||||
|
||||
/// Register an action listener on the window for the next frame. The type of action
|
||||
/// is determined by the first parameter of the given listener. When the next frame is rendered
|
||||
/// the listener will be cleared.
|
||||
@@ -1669,7 +1541,6 @@ impl<'a> WindowContext<'a> {
|
||||
) {
|
||||
self.window
|
||||
.next_frame
|
||||
.dispatch_tree
|
||||
.on_action(action_type, Rc::new(listener));
|
||||
}
|
||||
}
|
||||
@@ -2081,7 +1952,6 @@ impl<'a, V: 'static> ViewContext<'a, V> {
|
||||
for view_id in self
|
||||
.window
|
||||
.rendered_frame
|
||||
.dispatch_tree
|
||||
.view_path(self.view.entity_id())
|
||||
.into_iter()
|
||||
.rev()
|
||||
|
||||
@@ -16,12 +16,13 @@ use std::{
|
||||
any::{Any, TypeId},
|
||||
borrow::{Borrow, BorrowMut, Cow},
|
||||
mem,
|
||||
ops::Range,
|
||||
rc::Rc,
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use anyhow::Result;
|
||||
use collections::{FxHashMap, FxHashSet};
|
||||
use collections::FxHashMap;
|
||||
use derive_more::{Deref, DerefMut};
|
||||
#[cfg(target_os = "macos")]
|
||||
use media::core_video::CVImageBuffer;
|
||||
@@ -34,132 +35,135 @@ use crate::{
|
||||
EntityId, FocusHandle, FocusId, FontId, GlobalElementId, GlyphId, Hsla, ImageData,
|
||||
InputHandler, IsZero, KeyContext, KeyEvent, LayoutId, MonochromeSprite, MouseEvent, PaintQuad,
|
||||
Path, Pixels, PlatformInputHandler, Point, PolychromeSprite, Quad, RenderGlyphParams,
|
||||
RenderImageParams, RenderSvgParams, Scene, Shadow, SharedString, Size, StackingContext,
|
||||
StackingOrder, StrikethroughStyle, Style, TextStyleRefinement, Underline, UnderlineStyle,
|
||||
Window, WindowContext, SUBPIXEL_VARIANTS,
|
||||
RenderImageParams, RenderSvgParams, Scene, SceneIndex, Shadow, SharedString, Size,
|
||||
StackingContext, StackingOrder, StrikethroughStyle, Style, TextStyleRefinement, Underline,
|
||||
UnderlineStyle, Window, WindowContext, SUBPIXEL_VARIANTS,
|
||||
};
|
||||
|
||||
type AnyMouseListener = Box<dyn FnMut(&dyn Any, DispatchPhase, &mut ElementContext) + 'static>;
|
||||
|
||||
pub(crate) struct RequestedInputHandler {
|
||||
pub(crate) view_id: EntityId,
|
||||
pub(crate) handler: Option<PlatformInputHandler>,
|
||||
}
|
||||
|
||||
pub(crate) struct TooltipRequest {
|
||||
pub(crate) view_id: EntityId,
|
||||
pub(crate) tooltip: AnyTooltip,
|
||||
}
|
||||
|
||||
pub(crate) struct Frame {
|
||||
pub(crate) focus: Option<FocusId>,
|
||||
pub(crate) window_active: bool,
|
||||
pub(crate) element_states: FxHashMap<GlobalElementId, ElementStateBox>,
|
||||
pub(crate) mouse_listeners: FxHashMap<TypeId, Vec<(StackingOrder, EntityId, AnyMouseListener)>>,
|
||||
pub(crate) dispatch_tree: DispatchTree,
|
||||
pub(crate) scene: Scene,
|
||||
pub(crate) depth_map: Vec<(StackingOrder, EntityId, Bounds<Pixels>)>,
|
||||
pub(crate) z_index_stack: StackingOrder,
|
||||
pub(crate) next_stacking_order_ids: Vec<u16>,
|
||||
pub(crate) next_root_z_index: u16,
|
||||
pub(crate) content_mask_stack: Vec<ContentMask<Pixels>>,
|
||||
pub(crate) element_offset_stack: Vec<Point<Pixels>>,
|
||||
pub(crate) requested_input_handler: Option<RequestedInputHandler>,
|
||||
pub(crate) tooltip_request: Option<TooltipRequest>,
|
||||
pub(crate) cursor_styles: FxHashMap<EntityId, CursorStyle>,
|
||||
pub(crate) requested_cursor_style: Option<CursorStyle>,
|
||||
pub(crate) view_stack: Vec<EntityId>,
|
||||
pub(crate) reused_views: FxHashSet<EntityId>,
|
||||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
pub(crate) debug_bounds: FxHashMap<String, Bounds<Pixels>>,
|
||||
/// Identifies a moment in time during construction of a frame. Used for reusing cached subsets of a previous frame.
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct FrameIndex {
|
||||
mouse_listeners: usize,
|
||||
dispatch_nodes: usize,
|
||||
scene_index: SceneIndex,
|
||||
}
|
||||
|
||||
impl Frame {
|
||||
pub(crate) fn new(dispatch_tree: DispatchTree) -> Self {
|
||||
Frame {
|
||||
focus: None,
|
||||
window_active: false,
|
||||
element_states: FxHashMap::default(),
|
||||
mouse_listeners: FxHashMap::default(),
|
||||
dispatch_tree,
|
||||
scene: Scene::default(),
|
||||
depth_map: Vec::new(),
|
||||
z_index_stack: StackingOrder::default(),
|
||||
next_stacking_order_ids: vec![0],
|
||||
next_root_z_index: 0,
|
||||
content_mask_stack: Vec::new(),
|
||||
element_offset_stack: Vec::new(),
|
||||
requested_input_handler: None,
|
||||
tooltip_request: None,
|
||||
cursor_styles: FxHashMap::default(),
|
||||
requested_cursor_style: None,
|
||||
view_stack: Vec::new(),
|
||||
reused_views: FxHashSet::default(),
|
||||
// pub(crate) struct Frame {
|
||||
// pub(crate) focus: Option<FocusId>,
|
||||
// pub(crate) window_active: bool,
|
||||
// pub(crate) element_states: FxHashMap<GlobalElementId, ElementStateBox>,
|
||||
// pub(crate) mouse_listeners: FxHashMap<TypeId, Vec<(StackingOrder, EntityId, AnyMouseListener)>>,
|
||||
// pub(crate) input_handlers: Vec<PlatformInputHandler>,
|
||||
// pub(crate) dispatch_tree: DispatchTree,
|
||||
// pub(crate) scene: Scene,
|
||||
// pub(crate) depth_map: Vec<(StackingOrder, EntityId, Bounds<Pixels>)>,
|
||||
// pub(crate) z_index_stack: StackingOrder,
|
||||
// pub(crate) next_stacking_order_ids: Vec<u16>,
|
||||
// pub(crate) next_root_z_index: u16,
|
||||
// pub(crate) content_mask_stack: Vec<ContentMask<Pixels>>,
|
||||
// pub(crate) element_offset_stack: Vec<Point<Pixels>>,
|
||||
// pub(crate) tooltip_request: Option<TooltipRequest>,
|
||||
// pub(crate) cursor_styles: FxHashMap<EntityId, CursorStyle>,
|
||||
// pub(crate) requested_cursor_style: Option<CursorStyle>,
|
||||
// pub(crate) view_stack: Vec<EntityId>,
|
||||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
debug_bounds: FxHashMap::default(),
|
||||
}
|
||||
}
|
||||
// #[cfg(any(test, feature = "test-support"))]
|
||||
// pub(crate) debug_bounds: FxHashMap<String, Bounds<Pixels>>,
|
||||
// }
|
||||
|
||||
pub(crate) fn clear(&mut self) {
|
||||
self.element_states.clear();
|
||||
self.mouse_listeners.values_mut().for_each(Vec::clear);
|
||||
self.dispatch_tree.clear();
|
||||
self.depth_map.clear();
|
||||
self.next_stacking_order_ids = vec![0];
|
||||
self.next_root_z_index = 0;
|
||||
self.reused_views.clear();
|
||||
self.scene.clear();
|
||||
self.requested_input_handler.take();
|
||||
self.tooltip_request.take();
|
||||
self.cursor_styles.clear();
|
||||
self.requested_cursor_style.take();
|
||||
debug_assert_eq!(self.view_stack.len(), 0);
|
||||
}
|
||||
// impl Frame {
|
||||
// pub(crate) fn new(dispatch_tree: DispatchTree) -> Self {
|
||||
// Frame {
|
||||
// focus: None,
|
||||
// window_active: false,
|
||||
// element_states: FxHashMap::default(),
|
||||
// mouse_listeners: FxHashMap::default(),
|
||||
// input_handlers: Vec::new(),
|
||||
// dispatch_tree,
|
||||
// scene: Scene::default(),
|
||||
// depth_map: Vec::new(),
|
||||
// z_index_stack: StackingOrder::default(),
|
||||
// next_stacking_order_ids: vec![0],
|
||||
// next_root_z_index: 0,
|
||||
// content_mask_stack: Vec::new(),
|
||||
// element_offset_stack: Vec::new(),
|
||||
// tooltip_request: None,
|
||||
// cursor_styles: FxHashMap::default(),
|
||||
// requested_cursor_style: None,
|
||||
// view_stack: Vec::new(),
|
||||
|
||||
pub(crate) fn focus_path(&self) -> SmallVec<[FocusId; 8]> {
|
||||
self.focus
|
||||
.map(|focus_id| self.dispatch_tree.focus_path(focus_id))
|
||||
.unwrap_or_default()
|
||||
}
|
||||
// #[cfg(any(test, feature = "test-support"))]
|
||||
// debug_bounds: FxHashMap::default(),
|
||||
// }
|
||||
// }
|
||||
|
||||
pub(crate) fn finish(&mut self, prev_frame: &mut Self) {
|
||||
// Reuse mouse listeners that didn't change since the last frame.
|
||||
for (type_id, listeners) in &mut prev_frame.mouse_listeners {
|
||||
let next_listeners = self.mouse_listeners.entry(*type_id).or_default();
|
||||
for (order, view_id, listener) in listeners.drain(..) {
|
||||
if self.reused_views.contains(&view_id) {
|
||||
next_listeners.push((order, view_id, listener));
|
||||
}
|
||||
}
|
||||
}
|
||||
// pub(crate) fn clear(&mut self) {
|
||||
// self.element_states.clear();
|
||||
// self.mouse_listeners.values_mut().for_each(Vec::clear);
|
||||
// self.input_handlers.clear();
|
||||
// self.dispatch_tree.clear();
|
||||
// self.depth_map.clear();
|
||||
// self.next_stacking_order_ids = vec![0];
|
||||
// self.next_root_z_index = 0;
|
||||
// self.scene.clear();
|
||||
// self.tooltip_request.take();
|
||||
// self.cursor_styles.clear();
|
||||
// self.requested_cursor_style.take();
|
||||
// debug_assert_eq!(self.view_stack.len(), 0);
|
||||
// }
|
||||
|
||||
// Reuse entries in the depth map that didn't change since the last frame.
|
||||
for (order, view_id, bounds) in prev_frame.depth_map.drain(..) {
|
||||
if self.reused_views.contains(&view_id) {
|
||||
match self
|
||||
.depth_map
|
||||
.binary_search_by(|(level, _, _)| order.cmp(level))
|
||||
{
|
||||
Ok(i) | Err(i) => self.depth_map.insert(i, (order, view_id, bounds)),
|
||||
}
|
||||
}
|
||||
}
|
||||
// pub(crate) fn focus_path(&self) -> SmallVec<[FocusId; 8]> {
|
||||
// self.focus
|
||||
// .map(|focus_id| self.dispatch_tree.focus_path(focus_id))
|
||||
// .unwrap_or_default()
|
||||
// }
|
||||
|
||||
// Retain element states for views that didn't change since the last frame.
|
||||
for (element_id, state) in prev_frame.element_states.drain() {
|
||||
if self.reused_views.contains(&state.parent_view_id) {
|
||||
self.element_states.entry(element_id).or_insert(state);
|
||||
}
|
||||
}
|
||||
// pub(crate) fn current_index(&self) -> FrameIndex {
|
||||
// FrameIndex {
|
||||
// scene_index: self.scene.current_index(),
|
||||
// mouse_listeners: self.mouse_listeners.len(),
|
||||
// dispatch_nodes: self.dispatch_tree.len(),
|
||||
// }
|
||||
// }
|
||||
|
||||
// Reuse geometry that didn't change since the last frame.
|
||||
self.scene
|
||||
.reuse_views(&self.reused_views, &mut prev_frame.scene);
|
||||
self.scene.finish();
|
||||
}
|
||||
}
|
||||
// pub(crate) fn finish(&mut self, prev_frame: &mut Self) {
|
||||
// // Reuse mouse listeners that didn't change since the last frame.
|
||||
// for (type_id, listeners) in &mut prev_frame.mouse_listeners {
|
||||
// let next_listeners = self.mouse_listeners.entry(*type_id).or_default();
|
||||
// for (order, view_id, listener) in listeners.drain(..) {
|
||||
// if self.reused_views.contains(&view_id) {
|
||||
// next_listeners.push((order, view_id, listener));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// // Reuse entries in the depth map that didn't change since the last frame.
|
||||
// for (order, view_id, bounds) in prev_frame.depth_map.drain(..) {
|
||||
// if self.reused_views.contains(&view_id) {
|
||||
// match self
|
||||
// .depth_map
|
||||
// .binary_search_by(|(level, _, _)| order.cmp(level))
|
||||
// {
|
||||
// Ok(i) | Err(i) => self.depth_map.insert(i, (order, view_id, bounds)),
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// // Retain element states for views that didn't change since the last frame.
|
||||
// for (element_id, state) in prev_frame.element_states.drain() {
|
||||
// if self.reused_views.contains(&state.parent_view_id) {
|
||||
// self.element_states.entry(element_id).or_insert(state);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
/// This context is used for assisting in the implementation of the element trait
|
||||
#[derive(Deref, DerefMut)]
|
||||
@@ -310,8 +314,9 @@ impl<'a> VisualContext for ElementContext<'a> {
|
||||
}
|
||||
|
||||
impl<'a> ElementContext<'a> {
|
||||
pub(crate) fn reuse_view(&mut self, next_stacking_order_id: u16) {
|
||||
pub(crate) fn reuse_view(&mut self, subframe_range: Range<FrameIndex>) {
|
||||
let view_id = self.parent_view_id();
|
||||
|
||||
let grafted_view_ids = self
|
||||
.cx
|
||||
.window
|
||||
@@ -651,6 +656,7 @@ impl<'a> ElementContext<'a> {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Paint one or more drop shadows into the scene for the next frame at the current z-index.
|
||||
pub fn paint_shadows(
|
||||
&mut self,
|
||||
@@ -666,20 +672,18 @@ impl<'a> ElementContext<'a> {
|
||||
let mut shadow_bounds = bounds;
|
||||
shadow_bounds.origin += shadow.offset;
|
||||
shadow_bounds.dilate(shadow.spread_radius);
|
||||
window.next_frame.scene.insert(
|
||||
&window.next_frame.z_index_stack,
|
||||
Shadow {
|
||||
view_id: view_id.into(),
|
||||
layer_id: 0,
|
||||
order: 0,
|
||||
window
|
||||
.next_frame
|
||||
.scene
|
||||
.paint_primitive(|draw_order| Shadow {
|
||||
draw_order,
|
||||
bounds: shadow_bounds.scale(scale_factor),
|
||||
content_mask: content_mask.scale(scale_factor),
|
||||
corner_radii: corner_radii.scale(scale_factor),
|
||||
color: shadow.color,
|
||||
blur_radius: shadow.blur_radius.scale(scale_factor),
|
||||
pad: 0,
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -692,20 +696,15 @@ impl<'a> ElementContext<'a> {
|
||||
let view_id = self.parent_view_id();
|
||||
|
||||
let window = &mut *self.window;
|
||||
window.next_frame.scene.insert(
|
||||
&window.next_frame.z_index_stack,
|
||||
Quad {
|
||||
view_id: view_id.into(),
|
||||
layer_id: 0,
|
||||
order: 0,
|
||||
bounds: quad.bounds.scale(scale_factor),
|
||||
content_mask: content_mask.scale(scale_factor),
|
||||
background: quad.background,
|
||||
border_color: quad.border_color,
|
||||
corner_radii: quad.corner_radii.scale(scale_factor),
|
||||
border_widths: quad.border_widths.scale(scale_factor),
|
||||
},
|
||||
);
|
||||
window.next_frame.scene.paint_primitive(|draw_order| Quad {
|
||||
draw_order,
|
||||
bounds: quad.bounds.scale(scale_factor),
|
||||
content_mask: content_mask.scale(scale_factor),
|
||||
background: quad.background,
|
||||
border_color: quad.border_color,
|
||||
corner_radii: quad.corner_radii.scale(scale_factor),
|
||||
border_widths: quad.border_widths.scale(scale_factor),
|
||||
});
|
||||
}
|
||||
|
||||
/// Paint the given `Path` into the scene for the next frame at the current z-index.
|
||||
@@ -716,12 +715,11 @@ impl<'a> ElementContext<'a> {
|
||||
|
||||
path.content_mask = content_mask;
|
||||
path.color = color.into();
|
||||
path.view_id = view_id.into();
|
||||
let window = &mut *self.window;
|
||||
window
|
||||
.next_frame
|
||||
.scene
|
||||
.insert(&window.next_frame.z_index_stack, path.scale(scale_factor));
|
||||
window.next_frame.scene.paint_primitive(|draw_order| {
|
||||
path.draw_order = draw_order;
|
||||
path.scale(scale_factor)
|
||||
});
|
||||
}
|
||||
|
||||
/// Paint an underline into the scene for the next frame at the current z-index.
|
||||
@@ -745,19 +743,17 @@ impl<'a> ElementContext<'a> {
|
||||
let view_id = self.parent_view_id();
|
||||
|
||||
let window = &mut *self.window;
|
||||
window.next_frame.scene.insert(
|
||||
&window.next_frame.z_index_stack,
|
||||
Underline {
|
||||
view_id: view_id.into(),
|
||||
layer_id: 0,
|
||||
order: 0,
|
||||
window
|
||||
.next_frame
|
||||
.scene
|
||||
.paint_primitive(|draw_order| Underline {
|
||||
draw_order,
|
||||
bounds: bounds.scale(scale_factor),
|
||||
content_mask: content_mask.scale(scale_factor),
|
||||
color: style.color.unwrap_or_default(),
|
||||
thickness: style.thickness.scale(scale_factor),
|
||||
wavy: style.wavy,
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/// Paint a strikethrough into the scene for the next frame at the current z-index.
|
||||
@@ -777,19 +773,17 @@ impl<'a> ElementContext<'a> {
|
||||
let view_id = self.parent_view_id();
|
||||
|
||||
let window = &mut *self.window;
|
||||
window.next_frame.scene.insert(
|
||||
&window.next_frame.z_index_stack,
|
||||
Underline {
|
||||
view_id: view_id.into(),
|
||||
layer_id: 0,
|
||||
order: 0,
|
||||
window
|
||||
.next_frame
|
||||
.scene
|
||||
.paint_primitive(|draw_order| Underline {
|
||||
draw_order,
|
||||
bounds: bounds.scale(scale_factor),
|
||||
content_mask: content_mask.scale(scale_factor),
|
||||
thickness: style.thickness.scale(scale_factor),
|
||||
color: style.color.unwrap_or_default(),
|
||||
wavy: false,
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/// Paints a monochrome (non-emoji) glyph into the scene for the next frame at the current z-index.
|
||||
@@ -837,18 +831,16 @@ impl<'a> ElementContext<'a> {
|
||||
let content_mask = self.content_mask().scale(scale_factor);
|
||||
let view_id = self.parent_view_id();
|
||||
let window = &mut *self.window;
|
||||
window.next_frame.scene.insert(
|
||||
&window.next_frame.z_index_stack,
|
||||
MonochromeSprite {
|
||||
view_id: view_id.into(),
|
||||
layer_id: 0,
|
||||
order: 0,
|
||||
window
|
||||
.next_frame
|
||||
.scene
|
||||
.paint_primitive(|draw_order| MonochromeSprite {
|
||||
draw_order,
|
||||
bounds,
|
||||
content_mask,
|
||||
color,
|
||||
tile,
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -895,20 +887,18 @@ impl<'a> ElementContext<'a> {
|
||||
let view_id = self.parent_view_id();
|
||||
let window = &mut *self.window;
|
||||
|
||||
window.next_frame.scene.insert(
|
||||
&window.next_frame.z_index_stack,
|
||||
PolychromeSprite {
|
||||
view_id: view_id.into(),
|
||||
layer_id: 0,
|
||||
order: 0,
|
||||
window
|
||||
.next_frame
|
||||
.scene
|
||||
.paint_primitive(|draw_order| PolychromeSprite {
|
||||
draw_order,
|
||||
bounds,
|
||||
corner_radii: Default::default(),
|
||||
content_mask,
|
||||
tile,
|
||||
grayscale: false,
|
||||
pad: 0,
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -941,18 +931,16 @@ impl<'a> ElementContext<'a> {
|
||||
let view_id = self.parent_view_id();
|
||||
|
||||
let window = &mut *self.window;
|
||||
window.next_frame.scene.insert(
|
||||
&window.next_frame.z_index_stack,
|
||||
MonochromeSprite {
|
||||
view_id: view_id.into(),
|
||||
layer_id: 0,
|
||||
order: 0,
|
||||
window
|
||||
.next_frame
|
||||
.scene
|
||||
.paint_primitive(|draw_order| MonochromeSprite {
|
||||
draw_order,
|
||||
bounds,
|
||||
content_mask,
|
||||
color,
|
||||
tile,
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -980,20 +968,18 @@ impl<'a> ElementContext<'a> {
|
||||
let view_id = self.parent_view_id();
|
||||
|
||||
let window = &mut *self.window;
|
||||
window.next_frame.scene.insert(
|
||||
&window.next_frame.z_index_stack,
|
||||
PolychromeSprite {
|
||||
view_id: view_id.into(),
|
||||
layer_id: 0,
|
||||
order: 0,
|
||||
window
|
||||
.next_frame
|
||||
.scene
|
||||
.paint_primitive(|draw_order| PolychromeSprite {
|
||||
draw_order,
|
||||
bounds,
|
||||
content_mask,
|
||||
corner_radii,
|
||||
tile,
|
||||
grayscale,
|
||||
pad: 0,
|
||||
},
|
||||
);
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1005,17 +991,15 @@ impl<'a> ElementContext<'a> {
|
||||
let content_mask = self.content_mask().scale(scale_factor);
|
||||
let view_id = self.parent_view_id();
|
||||
let window = &mut *self.window;
|
||||
window.next_frame.scene.insert(
|
||||
&window.next_frame.z_index_stack,
|
||||
crate::Surface {
|
||||
view_id: view_id.into(),
|
||||
layer_id: 0,
|
||||
order: 0,
|
||||
window
|
||||
.next_frame
|
||||
.scene
|
||||
.paint_primitive(|draw_order| crate::Surface {
|
||||
draw_order,
|
||||
bounds,
|
||||
content_mask,
|
||||
image_buffer,
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
|
||||
Reference in New Issue
Block a user