Merge remote-tracking branch 'origin/main' into code-actions-2

This commit is contained in:
Antonio Scandurra 2023-11-10 11:01:23 +01:00
commit a0987f1121
79 changed files with 10335 additions and 2660 deletions

View file

@ -1,14 +1,15 @@
use crate::{
px, size, Action, AnyBox, AnyDrag, AnyView, AppContext, AsyncWindowContext, AvailableSpace,
Bounds, BoxShadow, Context, Corners, CursorStyle, DevicePixels, DispatchContext, DisplayId,
Edges, Effect, Entity, EntityId, EventEmitter, FileDropEvent, FocusEvent, FontId,
GlobalElementId, GlyphId, Hsla, ImageData, InputEvent, IsZero, KeyListener, KeyMatch,
KeyMatcher, Keystroke, LayoutId, Model, ModelContext, Modifiers, MonochromeSprite, MouseButton,
MouseDownEvent, MouseMoveEvent, MouseUpEvent, Path, Pixels, PlatformAtlas, PlatformDisplay,
PlatformInputHandler, PlatformWindow, Point, PolychromeSprite, PromptLevel, Quad, Render,
RenderGlyphParams, RenderImageParams, RenderSvgParams, ScaledPixels, SceneBuilder, Shadow,
SharedString, Size, Style, SubscriberSet, Subscription, TaffyLayoutEngine, Task, Underline,
UnderlineStyle, View, VisualContext, WeakView, WindowBounds, WindowOptions, SUBPIXEL_VARIANTS,
build_action_from_type, px, size, Action, AnyBox, AnyDrag, AnyView, AppContext,
AsyncWindowContext, AvailableSpace, Bounds, BoxShadow, Context, Corners, CursorStyle,
DevicePixels, DispatchContext, DisplayId, Edges, Effect, Entity, EntityId, EventEmitter,
FileDropEvent, FocusEvent, FontId, GlobalElementId, GlyphId, Hsla, ImageData, InputEvent,
IsZero, KeyListener, KeyMatch, KeyMatcher, Keystroke, LayoutId, Model, ModelContext, Modifiers,
MonochromeSprite, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Path, Pixels,
PlatformAtlas, PlatformDisplay, PlatformInputHandler, PlatformWindow, Point, PolychromeSprite,
PromptLevel, Quad, Render, RenderGlyphParams, RenderImageParams, RenderSvgParams, ScaledPixels,
SceneBuilder, Shadow, SharedString, Size, Style, SubscriberSet, Subscription,
TaffyLayoutEngine, Task, Underline, UnderlineStyle, View, VisualContext, WeakView,
WindowBounds, WindowOptions, SUBPIXEL_VARIANTS,
};
use anyhow::{anyhow, Result};
use collections::HashMap;
@ -145,6 +146,11 @@ impl FocusHandle {
}
}
/// Moves the focus to the element associated with this handle.
pub fn focus(&self, cx: &mut WindowContext) {
cx.focus(self)
}
/// Obtains whether the element associated with this handle is currently focused.
pub fn is_focused(&self, cx: &WindowContext) -> bool {
self.id.is_focused(cx)
@ -227,7 +233,7 @@ pub(crate) struct Frame {
key_matchers: HashMap<GlobalElementId, KeyMatcher>,
mouse_listeners: HashMap<TypeId, Vec<(StackingOrder, AnyListener)>>,
pub(crate) focus_listeners: Vec<AnyFocusListener>,
key_dispatch_stack: Vec<KeyDispatchStackFrame>,
pub(crate) key_dispatch_stack: Vec<KeyDispatchStackFrame>,
freeze_key_dispatch_stack: bool,
focus_parents_by_child: HashMap<FocusId, FocusId>,
pub(crate) scene_builder: SceneBuilder,
@ -326,7 +332,7 @@ impl Window {
/// find the focused element. We interleave key listeners with dispatch contexts so we can use the
/// contexts when matching key events against the keymap. A key listener can be either an action
/// handler or a [KeyDown] / [KeyUp] event listener.
enum KeyDispatchStackFrame {
pub(crate) enum KeyDispatchStackFrame {
Listener {
event_type: TypeId,
listener: AnyKeyListener,
@ -401,11 +407,18 @@ impl<'a> WindowContext<'a> {
/// Move focus to the element associated with the given `FocusHandle`.
pub fn focus(&mut self, handle: &FocusHandle) {
if self.window.focus == Some(handle.id) {
return;
}
if self.window.last_blur.is_none() {
self.window.last_blur = Some(self.window.focus);
}
self.window.focus = Some(handle.id);
// self.window.current_frame.key_dispatch_stack.clear()
// self.window.root_view.initialize()
self.app.push_effect(Effect::FocusChanged {
window_handle: self.window.handle,
focused: Some(handle.id),
@ -427,6 +440,14 @@ impl<'a> WindowContext<'a> {
self.notify();
}
pub fn dispatch_action(&mut self, action: Box<dyn Action>) {
self.defer(|cx| {
cx.app.propagate_event = true;
let stack = cx.dispatch_stack();
cx.dispatch_action_internal(action, &stack[..])
})
}
/// Schedules the given function to be run at the end of the current effect cycle, allowing entities
/// that are currently on the stack to be returned to the app.
pub fn defer(&mut self, f: impl FnOnce(&mut WindowContext) + 'static) {
@ -1058,6 +1079,26 @@ impl<'a> WindowContext<'a> {
self.window.dirty = false;
}
pub(crate) fn dispatch_stack(&mut self) -> Vec<KeyDispatchStackFrame> {
let root_view = self.window.root_view.take().unwrap();
let window = &mut *self.window;
let mut spare_frame = Frame::default();
mem::swap(&mut spare_frame, &mut window.previous_frame);
self.start_frame();
root_view.draw_dispatch_stack(self);
let window = &mut *self.window;
// restore the old values of current and previous frame,
// putting the new frame into spare_frame.
mem::swap(&mut window.current_frame, &mut window.previous_frame);
mem::swap(&mut spare_frame, &mut window.previous_frame);
self.window.root_view = Some(root_view);
spare_frame.key_dispatch_stack
}
/// Rotate the current frame and the previous frame, then clear the current frame.
/// We repopulate all state in the current frame during each paint.
fn start_frame(&mut self) {
@ -1202,7 +1243,7 @@ impl<'a> WindowContext<'a> {
DispatchPhase::Capture,
self,
) {
self.dispatch_action(action, &key_dispatch_stack[..ix]);
self.dispatch_action_internal(action, &key_dispatch_stack[..ix]);
}
if !self.app.propagate_event {
break;
@ -1229,7 +1270,10 @@ impl<'a> WindowContext<'a> {
DispatchPhase::Bubble,
self,
) {
self.dispatch_action(action, &key_dispatch_stack[..ix]);
self.dispatch_action_internal(
action,
&key_dispatch_stack[..ix],
);
}
if !self.app.propagate_event {
@ -1301,7 +1345,29 @@ impl<'a> WindowContext<'a> {
self.window.platform_window.prompt(level, msg, answers)
}
fn dispatch_action(
pub fn available_actions(&self) -> impl Iterator<Item = Box<dyn Action>> + '_ {
let key_dispatch_stack = &self.window.previous_frame.key_dispatch_stack;
key_dispatch_stack.iter().filter_map(|frame| {
match frame {
// todo!factor out a KeyDispatchStackFrame::Action
KeyDispatchStackFrame::Listener {
event_type,
listener: _,
} => {
match build_action_from_type(event_type) {
Ok(action) => Some(action),
Err(err) => {
dbg!(err);
None
} // we'll hit his if TypeId == KeyDown
}
}
KeyDispatchStackFrame::Context(_) => None,
}
})
}
pub(crate) fn dispatch_action_internal(
&mut self,
action: Box<dyn Action>,
dispatch_stack: &[KeyDispatchStackFrame],