mirror of
https://github.com/zed-industries/zed.git
synced 2024-11-10 05:37:29 +03:00
Merge branch 'gpui2' into gpui2ui-debug-panel
This commit is contained in:
commit
7ed891e0c6
@ -423,18 +423,27 @@ where
|
||||
element_state: Option<Self::ElementState>,
|
||||
cx: &mut ViewContext<Self::ViewState>,
|
||||
) -> Self::ElementState {
|
||||
cx.with_focus(
|
||||
self.focusability.focus_handle().cloned(),
|
||||
mem::take(&mut self.listeners.key_down),
|
||||
mem::take(&mut self.listeners.key_up),
|
||||
mem::take(&mut self.listeners.focus),
|
||||
|cx| {
|
||||
for listener in self.listeners.focus.iter().cloned() {
|
||||
cx.on_focus_changed(move |view, event, cx| listener(view, event, cx));
|
||||
}
|
||||
|
||||
let key_listeners = mem::take(&mut self.listeners.key);
|
||||
cx.with_key_listeners(&key_listeners, |cx| {
|
||||
if let Some(focus_handle) = self.focusability.focus_handle().cloned() {
|
||||
cx.with_focus(focus_handle, |cx| {
|
||||
for child in &mut self.children {
|
||||
child.initialize(view_state, cx);
|
||||
}
|
||||
})
|
||||
} else {
|
||||
for child in &mut self.children {
|
||||
child.initialize(view_state, cx);
|
||||
}
|
||||
element_state.unwrap_or_default()
|
||||
},
|
||||
)
|
||||
}
|
||||
});
|
||||
self.listeners.key = key_listeners;
|
||||
|
||||
element_state.unwrap_or_default()
|
||||
}
|
||||
|
||||
fn layout(
|
||||
|
@ -2,7 +2,11 @@ use crate::{
|
||||
point, Bounds, DispatchPhase, FocusHandle, Keystroke, Modifiers, Pixels, Point, ViewContext,
|
||||
};
|
||||
use smallvec::SmallVec;
|
||||
use std::{any::Any, ops::Deref};
|
||||
use std::{
|
||||
any::{Any, TypeId},
|
||||
ops::Deref,
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct KeyDownEvent {
|
||||
@ -221,43 +225,40 @@ pub struct FocusEvent {
|
||||
pub focused: Option<FocusHandle>,
|
||||
}
|
||||
|
||||
pub type MouseDownListener<V> = Box<
|
||||
pub type MouseDownListener<V> = Arc<
|
||||
dyn Fn(&mut V, &MouseDownEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
>;
|
||||
pub type MouseUpListener<V> = Box<
|
||||
pub type MouseUpListener<V> = Arc<
|
||||
dyn Fn(&mut V, &MouseUpEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
>;
|
||||
pub type MouseClickListener<V> =
|
||||
Box<dyn Fn(&mut V, &MouseClickEvent, &mut ViewContext<V>) + Send + Sync + 'static>;
|
||||
Arc<dyn Fn(&mut V, &MouseClickEvent, &mut ViewContext<V>) + Send + Sync + 'static>;
|
||||
|
||||
pub type MouseMoveListener<V> = Box<
|
||||
pub type MouseMoveListener<V> = Arc<
|
||||
dyn Fn(&mut V, &MouseMoveEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
>;
|
||||
|
||||
pub type ScrollWheelListener<V> = Box<
|
||||
pub type ScrollWheelListener<V> = Arc<
|
||||
dyn Fn(&mut V, &ScrollWheelEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
>;
|
||||
|
||||
pub type KeyDownListener<V> =
|
||||
Box<dyn Fn(&mut V, &KeyDownEvent, DispatchPhase, &mut ViewContext<V>) + Send + Sync + 'static>;
|
||||
|
||||
pub type KeyUpListener<V> =
|
||||
Box<dyn Fn(&mut V, &KeyUpEvent, DispatchPhase, &mut ViewContext<V>) + Send + Sync + 'static>;
|
||||
pub type KeyListener<V> =
|
||||
Arc<dyn Fn(&mut V, &dyn Any, DispatchPhase, &mut ViewContext<V>) + Send + Sync + 'static>;
|
||||
|
||||
pub type FocusListener<V> =
|
||||
Box<dyn Fn(&mut V, &FocusEvent, &mut ViewContext<V>) + Send + Sync + 'static>;
|
||||
Arc<dyn Fn(&mut V, &FocusEvent, &mut ViewContext<V>) + Send + Sync + 'static>;
|
||||
|
||||
pub struct EventListeners<V: 'static> {
|
||||
pub mouse_down: SmallVec<[MouseDownListener<V>; 2]>,
|
||||
@ -265,8 +266,7 @@ pub struct EventListeners<V: 'static> {
|
||||
pub mouse_click: SmallVec<[MouseClickListener<V>; 2]>,
|
||||
pub mouse_move: SmallVec<[MouseMoveListener<V>; 2]>,
|
||||
pub scroll_wheel: SmallVec<[ScrollWheelListener<V>; 2]>,
|
||||
pub key_down: SmallVec<[KeyDownListener<V>; 2]>,
|
||||
pub key_up: SmallVec<[KeyUpListener<V>; 2]>,
|
||||
pub key: SmallVec<[(TypeId, KeyListener<V>); 32]>,
|
||||
pub focus: SmallVec<[FocusListener<V>; 2]>,
|
||||
}
|
||||
|
||||
@ -278,8 +278,7 @@ impl<V> Default for EventListeners<V> {
|
||||
mouse_click: SmallVec::new(),
|
||||
mouse_move: SmallVec::new(),
|
||||
scroll_wheel: SmallVec::new(),
|
||||
key_down: SmallVec::new(),
|
||||
key_up: SmallVec::new(),
|
||||
key: SmallVec::new(),
|
||||
focus: SmallVec::new(),
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
use std::{any::TypeId, sync::Arc};
|
||||
|
||||
use crate::{
|
||||
DispatchPhase, FocusEvent, FocusHandle, Interactive, KeyDownEvent, KeyUpEvent, StyleRefinement,
|
||||
ViewContext,
|
||||
@ -46,7 +48,7 @@ pub trait Focus: Interactive {
|
||||
let handle = self.handle().clone();
|
||||
self.listeners()
|
||||
.focus
|
||||
.push(Box::new(move |view, event, cx| {
|
||||
.push(Arc::new(move |view, event, cx| {
|
||||
if event.focused.as_ref() == Some(&handle) {
|
||||
listener(view, event, cx)
|
||||
}
|
||||
@ -67,7 +69,7 @@ pub trait Focus: Interactive {
|
||||
let handle = self.handle().clone();
|
||||
self.listeners()
|
||||
.focus
|
||||
.push(Box::new(move |view, event, cx| {
|
||||
.push(Arc::new(move |view, event, cx| {
|
||||
if event.blurred.as_ref() == Some(&handle) {
|
||||
listener(view, event, cx)
|
||||
}
|
||||
@ -88,7 +90,7 @@ pub trait Focus: Interactive {
|
||||
let handle = self.handle().clone();
|
||||
self.listeners()
|
||||
.focus
|
||||
.push(Box::new(move |view, event, cx| {
|
||||
.push(Arc::new(move |view, event, cx| {
|
||||
let descendant_blurred = event
|
||||
.blurred
|
||||
.as_ref()
|
||||
@ -118,7 +120,7 @@ pub trait Focus: Interactive {
|
||||
let handle = self.handle().clone();
|
||||
self.listeners()
|
||||
.focus
|
||||
.push(Box::new(move |view, event, cx| {
|
||||
.push(Arc::new(move |view, event, cx| {
|
||||
let descendant_blurred = event
|
||||
.blurred
|
||||
.as_ref()
|
||||
@ -148,7 +150,13 @@ pub trait Focus: Interactive {
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.listeners().key_down.push(Box::new(listener));
|
||||
self.listeners().key.push((
|
||||
TypeId::of::<KeyDownEvent>(),
|
||||
Arc::new(move |view, event, phase, cx| {
|
||||
let event = event.downcast_ref().unwrap();
|
||||
listener(view, event, phase, cx)
|
||||
}),
|
||||
));
|
||||
self
|
||||
}
|
||||
|
||||
@ -162,7 +170,13 @@ pub trait Focus: Interactive {
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.listeners().key_up.push(Box::new(listener));
|
||||
self.listeners().key.push((
|
||||
TypeId::of::<KeyUpEvent>(),
|
||||
Arc::new(move |view, event, phase, cx| {
|
||||
let event = event.downcast_ref().unwrap();
|
||||
listener(view, event, phase, cx)
|
||||
}),
|
||||
));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::{
|
||||
DispatchPhase, Element, EventListeners, MouseButton, MouseClickEvent, MouseDownEvent,
|
||||
MouseMoveEvent, MouseUpEvent, ScrollWheelEvent, ViewContext,
|
||||
@ -19,7 +21,7 @@ pub trait Interactive: Element {
|
||||
{
|
||||
self.listeners()
|
||||
.mouse_down
|
||||
.push(Box::new(move |view, event, bounds, phase, cx| {
|
||||
.push(Arc::new(move |view, event, bounds, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble
|
||||
&& event.button == button
|
||||
&& bounds.contains_point(&event.position)
|
||||
@ -43,7 +45,7 @@ pub trait Interactive: Element {
|
||||
{
|
||||
self.listeners()
|
||||
.mouse_up
|
||||
.push(Box::new(move |view, event, bounds, phase, cx| {
|
||||
.push(Arc::new(move |view, event, bounds, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble
|
||||
&& event.button == button
|
||||
&& bounds.contains_point(&event.position)
|
||||
@ -67,7 +69,7 @@ pub trait Interactive: Element {
|
||||
{
|
||||
self.listeners()
|
||||
.mouse_down
|
||||
.push(Box::new(move |view, event, bounds, phase, cx| {
|
||||
.push(Arc::new(move |view, event, bounds, phase, cx| {
|
||||
if phase == DispatchPhase::Capture
|
||||
&& event.button == button
|
||||
&& !bounds.contains_point(&event.position)
|
||||
@ -91,7 +93,7 @@ pub trait Interactive: Element {
|
||||
{
|
||||
self.listeners()
|
||||
.mouse_up
|
||||
.push(Box::new(move |view, event, bounds, phase, cx| {
|
||||
.push(Arc::new(move |view, event, bounds, phase, cx| {
|
||||
if phase == DispatchPhase::Capture
|
||||
&& event.button == button
|
||||
&& !bounds.contains_point(&event.position)
|
||||
@ -114,7 +116,7 @@ pub trait Interactive: Element {
|
||||
{
|
||||
self.listeners()
|
||||
.mouse_move
|
||||
.push(Box::new(move |view, event, bounds, phase, cx| {
|
||||
.push(Arc::new(move |view, event, bounds, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
|
||||
handler(view, event, cx);
|
||||
}
|
||||
@ -134,7 +136,7 @@ pub trait Interactive: Element {
|
||||
{
|
||||
self.listeners()
|
||||
.scroll_wheel
|
||||
.push(Box::new(move |view, event, bounds, phase, cx| {
|
||||
.push(Arc::new(move |view, event, bounds, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
|
||||
handler(view, event, cx);
|
||||
}
|
||||
@ -156,7 +158,7 @@ pub trait Click: Interactive {
|
||||
{
|
||||
self.listeners()
|
||||
.mouse_click
|
||||
.push(Box::new(move |view, event, cx| handler(view, event, cx)));
|
||||
.push(Arc::new(move |view, event, cx| handler(view, event, cx)));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,12 @@
|
||||
use crate::{
|
||||
px, size, AnyBox, AnyView, AppContext, AsyncWindowContext, AvailableSpace, BorrowAppContext,
|
||||
Bounds, BoxShadow, Context, Corners, DevicePixels, DisplayId, Edges, Effect, Element, EntityId,
|
||||
EventEmitter, FocusEvent, FocusListener, FontId, GlobalElementId, GlyphId, Handle, Hsla,
|
||||
ImageData, InputEvent, IsZero, KeyDownEvent, KeyDownListener, KeyUpEvent, KeyUpListener,
|
||||
LayoutId, MainThread, MainThreadOnly, MonochromeSprite, MouseMoveEvent, Path, Pixels, Platform,
|
||||
PlatformAtlas, PlatformWindow, Point, PolychromeSprite, Quad, Reference, RenderGlyphParams,
|
||||
RenderImageParams, RenderSvgParams, ScaledPixels, SceneBuilder, Shadow, SharedString, Size,
|
||||
Style, Subscription, TaffyLayoutEngine, Task, Underline, UnderlineStyle, WeakHandle,
|
||||
WindowOptions, SUBPIXEL_VARIANTS,
|
||||
EventEmitter, FocusEvent, FontId, GlobalElementId, GlyphId, Handle, Hsla, ImageData,
|
||||
InputEvent, IsZero, KeyListener, LayoutId, MainThread, MainThreadOnly, MonochromeSprite,
|
||||
MouseMoveEvent, Path, Pixels, Platform, PlatformAtlas, PlatformWindow, Point, PolychromeSprite,
|
||||
Quad, Reference, RenderGlyphParams, RenderImageParams, RenderSvgParams, ScaledPixels,
|
||||
SceneBuilder, Shadow, SharedString, Size, Style, Subscription, TaffyLayoutEngine, Task,
|
||||
Underline, UnderlineStyle, WeakHandle, WindowOptions, SUBPIXEL_VARIANTS,
|
||||
};
|
||||
use anyhow::Result;
|
||||
use collections::HashMap;
|
||||
@ -45,15 +44,8 @@ pub enum DispatchPhase {
|
||||
Capture,
|
||||
}
|
||||
|
||||
type AnyMouseEventListener =
|
||||
Box<dyn Fn(&dyn Any, DispatchPhase, &mut WindowContext) + Send + Sync + 'static>;
|
||||
type AnyKeyboardEventListener =
|
||||
Box<dyn Fn(&dyn Any, DispatchPhase, &mut WindowContext) + Send + Sync + 'static>;
|
||||
type AnyFocusListener = Box<dyn Fn(&FocusEvent, &mut WindowContext) + Send + Sync + 'static>;
|
||||
type AnyKeyDownListener =
|
||||
Box<dyn Fn(&KeyDownEvent, DispatchPhase, &mut WindowContext) + Send + Sync + 'static>;
|
||||
type AnyKeyUpListener =
|
||||
Box<dyn Fn(&KeyUpEvent, DispatchPhase, &mut WindowContext) + Send + Sync + 'static>;
|
||||
type AnyListener = Arc<dyn Fn(&dyn Any, DispatchPhase, &mut WindowContext) + Send + Sync + 'static>;
|
||||
type AnyFocusListener = Arc<dyn Fn(&FocusEvent, &mut WindowContext) + Send + Sync + 'static>;
|
||||
|
||||
slotmap::new_key_type! { pub struct FocusId; }
|
||||
|
||||
@ -153,9 +145,10 @@ pub struct Window {
|
||||
element_states: HashMap<GlobalElementId, AnyBox>,
|
||||
z_index_stack: StackingOrder,
|
||||
content_mask_stack: Vec<ContentMask<Pixels>>,
|
||||
mouse_listeners: HashMap<TypeId, Vec<(StackingOrder, AnyMouseEventListener)>>,
|
||||
keyboard_listeners: HashMap<TypeId, Vec<AnyKeyboardEventListener>>,
|
||||
focus_stack: Vec<FocusStackFrame>,
|
||||
mouse_listeners: HashMap<TypeId, Vec<(StackingOrder, AnyListener)>>,
|
||||
key_listeners: HashMap<TypeId, Vec<AnyListener>>,
|
||||
key_events_enabled: bool,
|
||||
focus_stack: Vec<FocusId>,
|
||||
focus_parents_by_child: HashMap<FocusId, FocusId>,
|
||||
pub(crate) focus_listeners: Vec<AnyFocusListener>,
|
||||
pub(crate) focus_handles: Arc<RwLock<SlotMap<FocusId, AtomicUsize>>>,
|
||||
@ -226,7 +219,8 @@ impl Window {
|
||||
z_index_stack: StackingOrder(SmallVec::new()),
|
||||
content_mask_stack: Vec::new(),
|
||||
mouse_listeners: HashMap::default(),
|
||||
keyboard_listeners: HashMap::default(),
|
||||
key_listeners: HashMap::default(),
|
||||
key_events_enabled: true,
|
||||
focus_stack: Vec::new(),
|
||||
focus_parents_by_child: HashMap::default(),
|
||||
focus_listeners: Vec::new(),
|
||||
@ -262,12 +256,6 @@ impl ContentMask<Pixels> {
|
||||
}
|
||||
}
|
||||
|
||||
struct FocusStackFrame {
|
||||
handle: FocusHandle,
|
||||
key_down_listeners: SmallVec<[AnyKeyDownListener; 2]>,
|
||||
key_up_listeners: SmallVec<[AnyKeyUpListener; 2]>,
|
||||
}
|
||||
|
||||
pub struct WindowContext<'a, 'w> {
|
||||
app: Reference<'a, AppContext>,
|
||||
pub(crate) window: Reference<'w, Window>,
|
||||
@ -468,7 +456,7 @@ impl<'a, 'w> WindowContext<'a, 'w> {
|
||||
.or_default()
|
||||
.push((
|
||||
order,
|
||||
Box::new(move |event: &dyn Any, phase, cx| {
|
||||
Arc::new(move |event: &dyn Any, phase, cx| {
|
||||
handler(event.downcast_ref().unwrap(), phase, cx)
|
||||
}),
|
||||
))
|
||||
@ -479,10 +467,10 @@ impl<'a, 'w> WindowContext<'a, 'w> {
|
||||
handler: impl Fn(&Event, DispatchPhase, &mut WindowContext) + Send + Sync + 'static,
|
||||
) {
|
||||
self.window
|
||||
.keyboard_listeners
|
||||
.key_listeners
|
||||
.entry(TypeId::of::<Event>())
|
||||
.or_default()
|
||||
.push(Box::new(move |event: &dyn Any, phase, cx| {
|
||||
.push(Arc::new(move |event: &dyn Any, phase, cx| {
|
||||
handler(event.downcast_ref().unwrap(), phase, cx)
|
||||
}))
|
||||
}
|
||||
@ -833,8 +821,9 @@ impl<'a, 'w> WindowContext<'a, 'w> {
|
||||
// Clear focus state, because we determine what is focused when the new elements
|
||||
// in the upcoming frame are initialized.
|
||||
window.focus_listeners.clear();
|
||||
window.keyboard_listeners.values_mut().for_each(Vec::clear);
|
||||
window.key_listeners.values_mut().for_each(Vec::clear);
|
||||
window.focus_parents_by_child.clear();
|
||||
window.key_events_enabled = true;
|
||||
}
|
||||
|
||||
fn end_frame(&mut self) {
|
||||
@ -893,7 +882,7 @@ impl<'a, 'w> WindowContext<'a, 'w> {
|
||||
} else if let Some(any_keyboard_event) = event.keyboard_event() {
|
||||
if let Some(mut handlers) = self
|
||||
.window
|
||||
.keyboard_listeners
|
||||
.key_listeners
|
||||
.remove(&any_keyboard_event.type_id())
|
||||
{
|
||||
for handler in &handlers {
|
||||
@ -914,13 +903,13 @@ impl<'a, 'w> WindowContext<'a, 'w> {
|
||||
|
||||
handlers.extend(
|
||||
self.window
|
||||
.keyboard_listeners
|
||||
.key_listeners
|
||||
.get_mut(&any_keyboard_event.type_id())
|
||||
.into_iter()
|
||||
.flat_map(|handlers| handlers.drain(..)),
|
||||
);
|
||||
self.window
|
||||
.keyboard_listeners
|
||||
.key_listeners
|
||||
.insert(any_keyboard_event.type_id(), handlers);
|
||||
}
|
||||
}
|
||||
@ -1218,78 +1207,69 @@ impl<'a, 'w, V: Send + Sync + 'static> ViewContext<'a, 'w, V> {
|
||||
});
|
||||
}
|
||||
|
||||
pub fn with_focus<R>(
|
||||
pub fn on_focus_changed(
|
||||
&mut self,
|
||||
focus_handle: Option<FocusHandle>,
|
||||
key_down: impl IntoIterator<Item = KeyDownListener<V>>,
|
||||
key_up: impl IntoIterator<Item = KeyUpListener<V>>,
|
||||
focus: impl IntoIterator<Item = FocusListener<V>>,
|
||||
listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext<V>) + Send + Sync + 'static,
|
||||
) {
|
||||
let handle = self.handle();
|
||||
self.window.focus_listeners.push(Arc::new(move |event, cx| {
|
||||
handle
|
||||
.update(cx, |view, cx| listener(view, event, cx))
|
||||
.log_err();
|
||||
}));
|
||||
}
|
||||
|
||||
pub fn with_key_listeners<R>(
|
||||
&mut self,
|
||||
key_listeners: &[(TypeId, KeyListener<V>)],
|
||||
f: impl FnOnce(&mut Self) -> R,
|
||||
) -> R {
|
||||
let Some(focus_handle) = focus_handle else {
|
||||
return f(self);
|
||||
};
|
||||
|
||||
let handle = self.handle();
|
||||
let window = &mut *self.window;
|
||||
|
||||
for listener in focus {
|
||||
let handle = handle.clone();
|
||||
window.focus_listeners.push(Box::new(move |event, cx| {
|
||||
handle
|
||||
.update(cx, |view, cx| listener(view, event, cx))
|
||||
.log_err();
|
||||
}));
|
||||
}
|
||||
|
||||
let mut focus_stack = mem::take(&mut window.focus_stack);
|
||||
if let Some(parent_frame) = focus_stack.last() {
|
||||
window
|
||||
.focus_parents_by_child
|
||||
.insert(focus_handle.id, parent_frame.handle.id);
|
||||
}
|
||||
|
||||
let mut frame = FocusStackFrame {
|
||||
handle: focus_handle.clone(),
|
||||
key_down_listeners: SmallVec::new(),
|
||||
key_up_listeners: SmallVec::new(),
|
||||
};
|
||||
|
||||
for listener in key_down {
|
||||
let handle = handle.clone();
|
||||
frame
|
||||
.key_down_listeners
|
||||
.push(Box::new(move |event, phase, cx| {
|
||||
handle
|
||||
.update(cx, |view, cx| listener(view, event, phase, cx))
|
||||
.log_err();
|
||||
}));
|
||||
}
|
||||
for listener in key_up {
|
||||
let handle = handle.clone();
|
||||
frame
|
||||
.key_up_listeners
|
||||
.push(Box::new(move |event, phase, cx| {
|
||||
handle
|
||||
.update(cx, |view, cx| listener(view, event, phase, cx))
|
||||
.log_err();
|
||||
}));
|
||||
}
|
||||
focus_stack.push(frame);
|
||||
|
||||
if Some(focus_handle.id) == window.focus {
|
||||
for focus_frame in &mut focus_stack {
|
||||
for listener in focus_frame.key_down_listeners.drain(..) {
|
||||
self.window_cx.on_keyboard_event(listener);
|
||||
}
|
||||
for listener in focus_frame.key_up_listeners.drain(..) {
|
||||
self.window_cx.on_keyboard_event(listener);
|
||||
}
|
||||
if self.window.key_events_enabled {
|
||||
let handle = self.handle();
|
||||
for (type_id, listener) in key_listeners {
|
||||
let handle = handle.clone();
|
||||
let listener = listener.clone();
|
||||
self.window
|
||||
.key_listeners
|
||||
.entry(*type_id)
|
||||
.or_default()
|
||||
.push(Arc::new(move |event, phase, cx| {
|
||||
handle
|
||||
.update(cx, |view, cx| listener(view, event, phase, cx))
|
||||
.log_err();
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
self.window.focus_stack = focus_stack;
|
||||
let result = f(self);
|
||||
|
||||
if self.window.key_events_enabled {
|
||||
for (type_id, _) in key_listeners {
|
||||
self.window.key_listeners.get_mut(type_id).unwrap().pop();
|
||||
}
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
pub fn with_focus<R>(
|
||||
&mut self,
|
||||
focus_handle: FocusHandle,
|
||||
f: impl FnOnce(&mut Self) -> R,
|
||||
) -> R {
|
||||
if let Some(parent_focus_id) = self.window.focus_stack.last().copied() {
|
||||
self.window
|
||||
.focus_parents_by_child
|
||||
.insert(focus_handle.id, parent_focus_id);
|
||||
}
|
||||
self.window.focus_stack.push(focus_handle.id);
|
||||
|
||||
if Some(focus_handle.id) == self.window.focus {
|
||||
self.window.key_events_enabled = false;
|
||||
}
|
||||
|
||||
let result = f(self);
|
||||
|
||||
self.window.focus_stack.pop();
|
||||
result
|
||||
}
|
||||
|
@ -72,8 +72,7 @@ trait Styles: Styled + Sized {
|
||||
self.bg(rgb::<Hsla>(0xe5e8fc))
|
||||
.border_5()
|
||||
.border_color(rgb::<Hsla>(0x112382))
|
||||
// HACK: Simulate `line-height: 55px`.
|
||||
.pt(px(16.))
|
||||
.line_height(px(55.))
|
||||
// HACK: Simulate `text-align: center`.
|
||||
.pl(px(24.))
|
||||
}
|
||||
@ -119,8 +118,7 @@ impl<S: 'static + Send + Sync> ZIndexExample<S> {
|
||||
.text_color(rgb::<Hsla>(0x000000))
|
||||
.border_5()
|
||||
.border_color(rgb::<Hsla>(0xe3e0a1))
|
||||
// HACK: Simulate `line-height: 215px`.
|
||||
.pt(px(100.))
|
||||
.line_height(px(215.))
|
||||
// HACK: Simulate `text-align: center`.
|
||||
.pl(px(24.))
|
||||
.z_index(self.z_index)
|
||||
|
@ -17,7 +17,7 @@ use log::LevelFilter;
|
||||
use simplelog::SimpleLogger;
|
||||
use story_selector::ComponentStory;
|
||||
use ui::prelude::*;
|
||||
use ui::themed;
|
||||
use ui::{themed, with_settings, FakeSettings};
|
||||
|
||||
use crate::assets::Assets;
|
||||
use crate::story_selector::StorySelector;
|
||||
@ -68,8 +68,10 @@ fn main() {
|
||||
move |cx| {
|
||||
view(
|
||||
cx.entity(|cx| {
|
||||
cx.with_global(theme.clone(), |cx| {
|
||||
StoryWrapper::new(selector.story(cx), theme)
|
||||
cx.with_global(FakeSettings::default(), |cx| {
|
||||
cx.with_global(theme.clone(), |cx| {
|
||||
StoryWrapper::new(selector.story(cx), theme)
|
||||
})
|
||||
})
|
||||
}),
|
||||
StoryWrapper::render,
|
||||
@ -85,20 +87,27 @@ fn main() {
|
||||
pub struct StoryWrapper {
|
||||
story: AnyView,
|
||||
theme: Theme,
|
||||
settings: FakeSettings,
|
||||
}
|
||||
|
||||
impl StoryWrapper {
|
||||
pub(crate) fn new(story: AnyView, theme: Theme) -> Self {
|
||||
Self { story, theme }
|
||||
Self {
|
||||
story,
|
||||
theme,
|
||||
settings: FakeSettings::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl Element<ViewState = Self> {
|
||||
themed(self.theme.clone(), cx, |cx| {
|
||||
div()
|
||||
.flex()
|
||||
.flex_col()
|
||||
.size_full()
|
||||
.child(self.story.clone())
|
||||
with_settings(self.settings.clone(), cx, |cx| {
|
||||
themed(self.theme.clone(), cx, |cx| {
|
||||
div()
|
||||
.flex()
|
||||
.flex_col()
|
||||
.size_full()
|
||||
.child(self.story.clone())
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ impl<S: 'static + Send + Sync + Clone> AssistantPanel<S> {
|
||||
fn render(&mut self, view: &mut S, cx: &mut ViewContext<S>) -> impl Element<ViewState = S> {
|
||||
let theme = theme(cx);
|
||||
|
||||
Panel::new(self.scroll_state.clone())
|
||||
Panel::new(cx)
|
||||
.children(vec![div()
|
||||
.flex()
|
||||
.flex_col()
|
||||
|
@ -138,13 +138,10 @@ mod stories {
|
||||
Story::container(cx)
|
||||
.child(Story::title_for::<_, ChatPanel<S>>(cx))
|
||||
.child(Story::label(cx, "Default"))
|
||||
.child(
|
||||
Panel::new(ScrollState::default())
|
||||
.child(ChatPanel::new(ScrollState::default())),
|
||||
)
|
||||
.child(Panel::new(cx).child(ChatPanel::new(ScrollState::default())))
|
||||
.child(Story::label(cx, "With Mesages"))
|
||||
.child(Panel::new(ScrollState::default()).child(
|
||||
ChatPanel::new(ScrollState::default()).messages(vec![
|
||||
.child(
|
||||
Panel::new(cx).child(ChatPanel::new(ScrollState::default()).messages(vec![
|
||||
ChatMessage::new(
|
||||
"osiewicz".to_string(),
|
||||
"is this thing on?".to_string(),
|
||||
@ -159,8 +156,8 @@ mod stories {
|
||||
.unwrap()
|
||||
.naive_local(),
|
||||
),
|
||||
]),
|
||||
))
|
||||
])),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -78,8 +78,8 @@ impl<S: 'static + Send + Sync> IconButton<S> {
|
||||
let mut button = h_stack()
|
||||
.justify_center()
|
||||
.rounded_md()
|
||||
.py(ui_size(0.25))
|
||||
.px(ui_size(6. / 14.))
|
||||
.py(ui_size(cx, 0.25))
|
||||
.px(ui_size(cx, 6. / 14.))
|
||||
.when(self.variant == ButtonVariant::Filled, |this| {
|
||||
this.bg(color.filled_element)
|
||||
})
|
||||
|
@ -363,7 +363,7 @@ impl<S: 'static + Send + Sync + Clone> ListEntry<S> {
|
||||
let theme = theme(cx);
|
||||
let system_color = SystemColor::new();
|
||||
let color = ThemeColor::new(cx);
|
||||
let setting = user_settings();
|
||||
let settings = user_settings(cx);
|
||||
|
||||
let left_content = match self.left_content.clone() {
|
||||
Some(LeftContent::Icon(i)) => Some(
|
||||
@ -395,7 +395,7 @@ impl<S: 'static + Send + Sync + Clone> ListEntry<S> {
|
||||
// .ml(rems(0.75 * self.indent_level as f32))
|
||||
.children((0..self.indent_level).map(|_| {
|
||||
div()
|
||||
.w(*setting.list_indent_depth)
|
||||
.w(*settings.list_indent_depth)
|
||||
.h_full()
|
||||
.flex()
|
||||
.justify_center()
|
||||
|
@ -53,15 +53,15 @@ pub struct Panel<S: 'static + Send + Sync> {
|
||||
}
|
||||
|
||||
impl<S: 'static + Send + Sync> Panel<S> {
|
||||
pub fn new(scroll_state: ScrollState) -> Self {
|
||||
let setting = user_settings();
|
||||
pub fn new(cx: &mut WindowContext) -> Self {
|
||||
let settings = user_settings(cx);
|
||||
|
||||
Self {
|
||||
state_type: PhantomData,
|
||||
scroll_state,
|
||||
scroll_state: ScrollState::default(),
|
||||
current_side: PanelSide::default(),
|
||||
allowed_sides: PanelAllowedSides::default(),
|
||||
initial_width: *setting.default_panel_size,
|
||||
initial_width: *settings.default_panel_size,
|
||||
width: None,
|
||||
children: SmallVec::new(),
|
||||
}
|
||||
@ -175,7 +175,7 @@ mod stories {
|
||||
.child(Story::title_for::<_, Panel<S>>(cx))
|
||||
.child(Story::label(cx, "Default"))
|
||||
.child(
|
||||
Panel::new(ScrollState::default()).child(
|
||||
Panel::new(cx).child(
|
||||
div()
|
||||
.overflow_y_scroll(ScrollState::default())
|
||||
.children((0..100).map(|ix| Label::new(format!("Item {}", ix + 1)))),
|
||||
|
@ -87,7 +87,7 @@ mod stories {
|
||||
.child(Story::title_for::<_, ProjectPanel<S>>(cx))
|
||||
.child(Story::label(cx, "Default"))
|
||||
.child(
|
||||
Panel::new(ScrollState::default())
|
||||
Panel::new(cx)
|
||||
.child(ProjectPanel::new(ScrollState::default())),
|
||||
)
|
||||
}
|
||||
|
@ -95,7 +95,7 @@ impl TitleBar {
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl Element<ViewState = Self> {
|
||||
let theme = theme(cx);
|
||||
let color = ThemeColor::new(cx);
|
||||
let setting = user_settings();
|
||||
let settings = user_settings(cx);
|
||||
|
||||
// let has_focus = cx.window_is_active();
|
||||
let has_focus = true;
|
||||
@ -127,7 +127,7 @@ impl TitleBar {
|
||||
.flex()
|
||||
.items_center()
|
||||
.gap_1()
|
||||
.when(*setting.titlebar.show_project_owner, |this| {
|
||||
.when(*settings.titlebar.show_project_owner, |this| {
|
||||
this.child(Button::new("iamnbutler"))
|
||||
})
|
||||
.child(Button::new("zed"))
|
||||
|
@ -224,7 +224,7 @@ impl Workspace {
|
||||
.border_color(theme.lowest.base.default.border)
|
||||
.children(
|
||||
Some(
|
||||
Panel::new(self.left_panel_scroll_state.clone())
|
||||
Panel::new(cx)
|
||||
.side(PanelSide::Left)
|
||||
.child(ProjectPanel::new(ScrollState::default())),
|
||||
)
|
||||
@ -232,7 +232,7 @@ impl Workspace {
|
||||
)
|
||||
.children(
|
||||
Some(
|
||||
Panel::new(self.left_panel_scroll_state.clone())
|
||||
Panel::new(cx)
|
||||
.child(CollabPanel::new(ScrollState::default()))
|
||||
.side(PanelSide::Left),
|
||||
)
|
||||
@ -245,7 +245,7 @@ impl Workspace {
|
||||
.child(div().flex().flex_1().child(root_group))
|
||||
.children(
|
||||
Some(
|
||||
Panel::new(self.bottom_panel_scroll_state.clone())
|
||||
Panel::new(cx)
|
||||
.child(Terminal::new())
|
||||
.allowed_sides(PanelAllowedSides::BottomOnly)
|
||||
.side(PanelSide::Bottom),
|
||||
@ -254,10 +254,8 @@ impl Workspace {
|
||||
),
|
||||
)
|
||||
.children(
|
||||
Some(
|
||||
Panel::new(self.right_panel_scroll_state.clone())
|
||||
.side(PanelSide::Right)
|
||||
.child(ChatPanel::new(ScrollState::default()).messages(vec![
|
||||
Some(Panel::new(cx).side(PanelSide::Right).child(
|
||||
ChatPanel::new(ScrollState::default()).messages(vec![
|
||||
ChatMessage::new(
|
||||
"osiewicz".to_string(),
|
||||
"is this thing on?".to_string(),
|
||||
@ -272,24 +270,21 @@ impl Workspace {
|
||||
.unwrap()
|
||||
.naive_local(),
|
||||
),
|
||||
])),
|
||||
)
|
||||
]),
|
||||
))
|
||||
.filter(|_| self.is_chat_panel_open()),
|
||||
)
|
||||
.children(
|
||||
Some(
|
||||
Panel::new(self.right_panel_scroll_state.clone())
|
||||
Panel::new(cx)
|
||||
.side(PanelSide::Right)
|
||||
.child(div().w_96().h_full().child("Notifications")),
|
||||
)
|
||||
.filter(|_| self.is_notifications_panel_open()),
|
||||
)
|
||||
.children(
|
||||
Some(
|
||||
Panel::new(self.right_panel_scroll_state.clone())
|
||||
.child(AssistantPanel::new()),
|
||||
)
|
||||
.filter(|_| self.is_assistant_panel_open()),
|
||||
Some(Panel::new(cx).child(AssistantPanel::new()))
|
||||
.filter(|_| self.is_assistant_panel_open()),
|
||||
),
|
||||
)
|
||||
.child(StatusBar::new())
|
||||
|
@ -149,11 +149,11 @@ impl<S: 'static + Send + Sync + Clone> Button<S> {
|
||||
fn render(&mut self, _view: &mut S, cx: &mut ViewContext<S>) -> impl Element<ViewState = S> {
|
||||
let icon_color = self.icon_color();
|
||||
let border_color = self.border_color(cx);
|
||||
let setting = user_settings();
|
||||
let settings = user_settings(cx);
|
||||
|
||||
let mut el = h_stack()
|
||||
.p_1()
|
||||
.text_size(ui_size(1.))
|
||||
.text_size(ui_size(cx, 1.))
|
||||
.rounded_md()
|
||||
.border()
|
||||
.border_color(border_color)
|
||||
|
@ -180,8 +180,8 @@ impl<S: 'static + Send + Sync> IconElement<S> {
|
||||
let theme = theme(cx);
|
||||
let fill = self.color.color(theme);
|
||||
let svg_size = match self.size {
|
||||
IconSize::Small => ui_size(12. / 14.),
|
||||
IconSize::Medium => ui_size(15. / 14.),
|
||||
IconSize::Small => ui_size(cx, 12. / 14.),
|
||||
IconSize::Medium => ui_size(cx, 15. / 14.),
|
||||
};
|
||||
|
||||
svg()
|
||||
|
@ -96,7 +96,7 @@ impl<S: 'static + Send + Sync + Clone> Label<S> {
|
||||
.bg(LabelColor::Hidden.hsla(cx)),
|
||||
)
|
||||
})
|
||||
.text_size(ui_size(1.))
|
||||
.text_size(ui_size(cx, 1.))
|
||||
.when(self.line_height_style == LineHeightStyle::UILabel, |this| {
|
||||
this.line_height(relative(1.))
|
||||
})
|
||||
|
@ -14,6 +14,14 @@ pub use elements::*;
|
||||
pub use prelude::*;
|
||||
pub use static_data::*;
|
||||
|
||||
// This needs to be fully qualified with `crate::` otherwise we get a panic
|
||||
// at:
|
||||
// thread '<unnamed>' panicked at crates/gpui3/src/platform/mac/platform.rs:66:81:
|
||||
// called `Option::unwrap()` on a `None` value
|
||||
//
|
||||
// AFAICT this is something to do with conflicting names between crates and modules that
|
||||
// interfaces with declaring the `ClassDecl`.
|
||||
pub use crate::settings::*;
|
||||
pub use crate::theme::*;
|
||||
|
||||
#[cfg(feature = "stories")]
|
||||
|
@ -142,12 +142,12 @@ impl HighlightColor {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ui_size(size: f32) -> Rems {
|
||||
pub fn ui_size(cx: &mut WindowContext, size: f32) -> Rems {
|
||||
const UI_SCALE_RATIO: f32 = 0.875;
|
||||
|
||||
let setting = user_settings();
|
||||
let settings = user_settings(cx);
|
||||
|
||||
rems(*setting.ui_scale * UI_SCALE_RATIO * size)
|
||||
rems(*settings.ui_scale * UI_SCALE_RATIO * size)
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, EnumIter)]
|
||||
|
@ -1,15 +1,14 @@
|
||||
use std::ops::Deref;
|
||||
|
||||
use gpui3::{rems, AbsoluteLength};
|
||||
use gpui3::{
|
||||
rems, AbsoluteLength, AnyElement, BorrowAppContext, Bounds, LayoutId, Pixels, WindowContext,
|
||||
};
|
||||
|
||||
use crate::DisclosureControlStyle;
|
||||
use crate::prelude::*;
|
||||
|
||||
// This is a fake static example of user settings overriding the default settings
|
||||
pub fn user_settings() -> Settings {
|
||||
let mut settings = Settings::default();
|
||||
settings.list_indent_depth = SettingValue::UserDefined(rems(0.5).into());
|
||||
// settings.ui_scale = SettingValue::UserDefined(2.);
|
||||
settings
|
||||
/// Returns the user settings.
|
||||
pub fn user_settings(cx: &WindowContext) -> FakeSettings {
|
||||
cx.global::<FakeSettings>().clone()
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
@ -48,7 +47,7 @@ impl Default for TitlebarSettings {
|
||||
|
||||
// These should be merged into settings
|
||||
#[derive(Clone)]
|
||||
pub struct Settings {
|
||||
pub struct FakeSettings {
|
||||
pub default_panel_size: SettingValue<AbsoluteLength>,
|
||||
pub list_disclosure_style: SettingValue<DisclosureControlStyle>,
|
||||
pub list_indent_depth: SettingValue<AbsoluteLength>,
|
||||
@ -56,7 +55,7 @@ pub struct Settings {
|
||||
pub ui_scale: SettingValue<f32>,
|
||||
}
|
||||
|
||||
impl Default for Settings {
|
||||
impl Default for FakeSettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
titlebar: TitlebarSettings::default(),
|
||||
@ -68,4 +67,79 @@ impl Default for Settings {
|
||||
}
|
||||
}
|
||||
|
||||
impl Settings {}
|
||||
impl FakeSettings {}
|
||||
|
||||
pub fn with_settings<E, F>(
|
||||
settings: FakeSettings,
|
||||
cx: &mut ViewContext<E::ViewState>,
|
||||
build_child: F,
|
||||
) -> WithSettings<E>
|
||||
where
|
||||
E: Element,
|
||||
F: FnOnce(&mut ViewContext<E::ViewState>) -> E,
|
||||
{
|
||||
let child = cx.with_global(theme.clone(), |cx| build_child(cx));
|
||||
WithSettings { settings, child }
|
||||
}
|
||||
|
||||
pub struct WithSettings<E> {
|
||||
pub(crate) settings: FakeSettings,
|
||||
pub(crate) child: E,
|
||||
}
|
||||
|
||||
impl<E> IntoAnyElement<E::ViewState> for WithSettings<E>
|
||||
where
|
||||
E: Element,
|
||||
{
|
||||
fn into_any(self) -> AnyElement<E::ViewState> {
|
||||
AnyElement::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Element> Element for WithSettings<E> {
|
||||
type ViewState = E::ViewState;
|
||||
type ElementState = E::ElementState;
|
||||
|
||||
fn id(&self) -> Option<gpui3::ElementId> {
|
||||
None
|
||||
}
|
||||
|
||||
fn initialize(
|
||||
&mut self,
|
||||
view_state: &mut Self::ViewState,
|
||||
element_state: Option<Self::ElementState>,
|
||||
cx: &mut ViewContext<Self::ViewState>,
|
||||
) -> Self::ElementState {
|
||||
cx.with_global(self.settings.clone(), |cx| {
|
||||
self.child.initialize(view_state, element_state, cx)
|
||||
})
|
||||
}
|
||||
|
||||
fn layout(
|
||||
&mut self,
|
||||
view_state: &mut E::ViewState,
|
||||
element_state: &mut Self::ElementState,
|
||||
cx: &mut ViewContext<E::ViewState>,
|
||||
) -> LayoutId
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
cx.with_global(self.settings.clone(), |cx| {
|
||||
self.child.layout(view_state, element_state, cx)
|
||||
})
|
||||
}
|
||||
|
||||
fn paint(
|
||||
&mut self,
|
||||
bounds: Bounds<Pixels>,
|
||||
view_state: &mut Self::ViewState,
|
||||
frame_state: &mut Self::ElementState,
|
||||
cx: &mut ViewContext<Self::ViewState>,
|
||||
) where
|
||||
Self: Sized,
|
||||
{
|
||||
cx.with_global(self.settings.clone(), |cx| {
|
||||
self.child.paint(bounds, view_state, frame_state, cx);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user