Merge branch 'main' into focus-handlers-on-draw
This commit is contained in:
commit
4be84f3db0
108 changed files with 4470 additions and 3168 deletions
|
@ -1091,6 +1091,12 @@ impl AppContext {
|
|||
pub fn has_active_drag(&self) -> bool {
|
||||
self.active_drag.is_some()
|
||||
}
|
||||
|
||||
pub fn active_drag<T: 'static>(&self) -> Option<&T> {
|
||||
self.active_drag
|
||||
.as_ref()
|
||||
.and_then(|drag| drag.value.downcast_ref())
|
||||
}
|
||||
}
|
||||
|
||||
impl Context for AppContext {
|
||||
|
@ -1241,6 +1247,7 @@ impl<G: 'static> DerefMut for GlobalLease<G> {
|
|||
/// within the window or by dragging into the app from the underlying platform.
|
||||
pub struct AnyDrag {
|
||||
pub view: AnyView,
|
||||
pub value: Box<dyn Any>,
|
||||
pub cursor_offset: Point<Pixels>,
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ pub trait IntoElement: Sized {
|
|||
self.into_element().into_any()
|
||||
}
|
||||
|
||||
fn draw<T, R>(
|
||||
fn draw_and_update_state<T, R>(
|
||||
self,
|
||||
origin: Point<Pixels>,
|
||||
available_space: Size<T>,
|
||||
|
@ -92,7 +92,7 @@ pub trait Element: 'static + IntoElement {
|
|||
cx: &mut WindowContext,
|
||||
) -> (LayoutId, Self::State);
|
||||
|
||||
fn paint(self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext);
|
||||
fn paint(&mut self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext);
|
||||
|
||||
fn into_any(self) -> AnyElement {
|
||||
AnyElement::new(self)
|
||||
|
@ -150,8 +150,8 @@ impl<C: RenderOnce> Element for Component<C> {
|
|||
}
|
||||
}
|
||||
|
||||
fn paint(self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext) {
|
||||
let element = state.rendered_element.take().unwrap();
|
||||
fn paint(&mut self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext) {
|
||||
let mut element = state.rendered_element.take().unwrap();
|
||||
if let Some(element_id) = element.element_id() {
|
||||
cx.with_element_state(element_id, |element_state, cx| {
|
||||
let mut element_state = element_state.unwrap();
|
||||
|
@ -420,7 +420,7 @@ impl AnyElement {
|
|||
self.0.layout(cx)
|
||||
}
|
||||
|
||||
pub fn paint(mut self, cx: &mut WindowContext) {
|
||||
pub fn paint(&mut self, cx: &mut WindowContext) {
|
||||
self.0.paint(cx)
|
||||
}
|
||||
|
||||
|
@ -435,7 +435,7 @@ impl AnyElement {
|
|||
|
||||
/// Initializes this element and performs layout in the available space, then paints it at the given origin.
|
||||
pub fn draw(
|
||||
mut self,
|
||||
&mut self,
|
||||
origin: Point<Pixels>,
|
||||
available_space: Size<AvailableSpace>,
|
||||
cx: &mut WindowContext,
|
||||
|
@ -465,8 +465,8 @@ impl Element for AnyElement {
|
|||
(layout_id, ())
|
||||
}
|
||||
|
||||
fn paint(self, _: Bounds<Pixels>, _: &mut Self::State, cx: &mut WindowContext) {
|
||||
self.paint(cx);
|
||||
fn paint(&mut self, _: Bounds<Pixels>, _: &mut Self::State, cx: &mut WindowContext) {
|
||||
self.paint(cx)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -482,48 +482,37 @@ impl IntoElement for AnyElement {
|
|||
}
|
||||
}
|
||||
|
||||
// impl<V, E, F> Element for Option<F>
|
||||
// where
|
||||
// V: 'static,
|
||||
// E: Element,
|
||||
// F: FnOnce(&mut V, &mut WindowContext<'_, V>) -> E + 'static,
|
||||
// {
|
||||
// type State = Option<AnyElement>;
|
||||
/// The empty element, which renders nothing.
|
||||
pub type Empty = ();
|
||||
|
||||
// fn element_id(&self) -> Option<ElementId> {
|
||||
// None
|
||||
// }
|
||||
impl IntoElement for () {
|
||||
type Element = Self;
|
||||
|
||||
// fn layout(
|
||||
// &mut self,
|
||||
// _: Option<Self::State>,
|
||||
// cx: &mut WindowContext,
|
||||
// ) -> (LayoutId, Self::State) {
|
||||
// let render = self.take().unwrap();
|
||||
// let mut element = (render)(view_state, cx).into_any();
|
||||
// let layout_id = element.layout(view_state, cx);
|
||||
// (layout_id, Some(element))
|
||||
// }
|
||||
fn element_id(&self) -> Option<ElementId> {
|
||||
None
|
||||
}
|
||||
|
||||
// fn paint(
|
||||
// self,
|
||||
// _bounds: Bounds<Pixels>,
|
||||
// rendered_element: &mut Self::State,
|
||||
// cx: &mut WindowContext,
|
||||
// ) {
|
||||
// rendered_element.take().unwrap().paint(view_state, cx);
|
||||
// }
|
||||
// }
|
||||
fn into_element(self) -> Self::Element {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
// impl<V, E, F> RenderOnce for Option<F>
|
||||
// where
|
||||
// V: 'static,
|
||||
// E: Element,
|
||||
// F: FnOnce(&mut V, &mut WindowContext) -> E + 'static,
|
||||
// {
|
||||
// type Element = Self;
|
||||
impl Element for () {
|
||||
type State = ();
|
||||
|
||||
// fn render(self) -> Self::Element {
|
||||
// self
|
||||
// }
|
||||
// }
|
||||
fn layout(
|
||||
&mut self,
|
||||
_state: Option<Self::State>,
|
||||
cx: &mut WindowContext,
|
||||
) -> (LayoutId, Self::State) {
|
||||
(cx.request_layout(&crate::Style::default(), None), ())
|
||||
}
|
||||
|
||||
fn paint(
|
||||
&mut self,
|
||||
_bounds: Bounds<Pixels>,
|
||||
_state: &mut Self::State,
|
||||
_cx: &mut WindowContext,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,15 +2,15 @@ use refineable::Refineable as _;
|
|||
|
||||
use crate::{Bounds, Element, IntoElement, Pixels, Style, StyleRefinement, Styled, WindowContext};
|
||||
|
||||
pub fn canvas(callback: impl 'static + FnOnce(Bounds<Pixels>, &mut WindowContext)) -> Canvas {
|
||||
pub fn canvas(callback: impl 'static + FnOnce(&Bounds<Pixels>, &mut WindowContext)) -> Canvas {
|
||||
Canvas {
|
||||
paint_callback: Box::new(callback),
|
||||
paint_callback: Some(Box::new(callback)),
|
||||
style: StyleRefinement::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Canvas {
|
||||
paint_callback: Box<dyn FnOnce(Bounds<Pixels>, &mut WindowContext)>,
|
||||
paint_callback: Option<Box<dyn FnOnce(&Bounds<Pixels>, &mut WindowContext)>>,
|
||||
style: StyleRefinement,
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,7 @@ impl IntoElement for Canvas {
|
|||
}
|
||||
|
||||
impl Element for Canvas {
|
||||
type State = ();
|
||||
type State = Style;
|
||||
|
||||
fn layout(
|
||||
&mut self,
|
||||
|
@ -37,11 +37,13 @@ impl Element for Canvas {
|
|||
let mut style = Style::default();
|
||||
style.refine(&self.style);
|
||||
let layout_id = cx.request_layout(&style, []);
|
||||
(layout_id, ())
|
||||
(layout_id, style)
|
||||
}
|
||||
|
||||
fn paint(self, bounds: Bounds<Pixels>, _: &mut (), cx: &mut WindowContext) {
|
||||
(self.paint_callback)(bounds, cx)
|
||||
fn paint(&mut self, bounds: Bounds<Pixels>, style: &mut Style, cx: &mut WindowContext) {
|
||||
style.paint(bounds, cx, |cx| {
|
||||
(self.paint_callback.take().unwrap())(&bounds, cx)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -81,11 +81,12 @@ impl Element for Img {
|
|||
}
|
||||
|
||||
fn paint(
|
||||
self,
|
||||
&mut self,
|
||||
bounds: Bounds<Pixels>,
|
||||
element_state: &mut Self::State,
|
||||
cx: &mut WindowContext,
|
||||
) {
|
||||
let source = self.source.clone();
|
||||
self.interactivity.paint(
|
||||
bounds,
|
||||
bounds.size,
|
||||
|
@ -94,7 +95,7 @@ impl Element for Img {
|
|||
|style, _scroll_offset, cx| {
|
||||
let corner_radii = style.corner_radii.to_pixels(bounds.size, cx.rem_size());
|
||||
cx.with_z_index(1, |cx| {
|
||||
match self.source {
|
||||
match source {
|
||||
ImageSource::Uri(uri) => {
|
||||
let image_future = cx.image_cache.get(uri.clone());
|
||||
if let Some(data) = image_future
|
||||
|
|
|
@ -257,7 +257,7 @@ impl Element for List {
|
|||
}
|
||||
|
||||
fn paint(
|
||||
self,
|
||||
&mut self,
|
||||
bounds: crate::Bounds<crate::Pixels>,
|
||||
_state: &mut Self::State,
|
||||
cx: &mut crate::WindowContext,
|
||||
|
@ -385,7 +385,7 @@ impl Element for List {
|
|||
// Paint the visible items
|
||||
let mut item_origin = bounds.origin;
|
||||
item_origin.y -= scroll_top.offset_in_item;
|
||||
for mut item_element in item_elements {
|
||||
for item_element in &mut item_elements {
|
||||
let item_height = item_element.measure(available_item_space, cx).height;
|
||||
item_element.draw(item_origin, available_item_space, cx);
|
||||
item_origin.y += item_height;
|
||||
|
|
|
@ -81,7 +81,7 @@ impl Element for Overlay {
|
|||
}
|
||||
|
||||
fn paint(
|
||||
self,
|
||||
&mut self,
|
||||
bounds: crate::Bounds<crate::Pixels>,
|
||||
element_state: &mut Self::State,
|
||||
cx: &mut WindowContext,
|
||||
|
@ -149,7 +149,7 @@ impl Element for Overlay {
|
|||
|
||||
cx.with_element_offset(desired.origin - bounds.origin, |cx| {
|
||||
cx.break_content_mask(|cx| {
|
||||
for child in self.children {
|
||||
for child in &mut self.children {
|
||||
child.paint(cx);
|
||||
}
|
||||
})
|
||||
|
|
|
@ -36,8 +36,12 @@ impl Element for Svg {
|
|||
})
|
||||
}
|
||||
|
||||
fn paint(self, bounds: Bounds<Pixels>, element_state: &mut Self::State, cx: &mut WindowContext)
|
||||
where
|
||||
fn paint(
|
||||
&mut self,
|
||||
bounds: Bounds<Pixels>,
|
||||
element_state: &mut Self::State,
|
||||
cx: &mut WindowContext,
|
||||
) where
|
||||
Self: Sized,
|
||||
{
|
||||
self.interactivity
|
||||
|
|
|
@ -6,7 +6,7 @@ use crate::{
|
|||
use anyhow::anyhow;
|
||||
use parking_lot::{Mutex, MutexGuard};
|
||||
use smallvec::SmallVec;
|
||||
use std::{cell::Cell, ops::Range, rc::Rc, sync::Arc};
|
||||
use std::{cell::Cell, mem, ops::Range, rc::Rc, sync::Arc};
|
||||
use util::ResultExt;
|
||||
|
||||
impl Element for &'static str {
|
||||
|
@ -22,7 +22,7 @@ impl Element for &'static str {
|
|||
(layout_id, state)
|
||||
}
|
||||
|
||||
fn paint(self, bounds: Bounds<Pixels>, state: &mut TextState, cx: &mut WindowContext) {
|
||||
fn paint(&mut self, bounds: Bounds<Pixels>, state: &mut TextState, cx: &mut WindowContext) {
|
||||
state.paint(bounds, self, cx)
|
||||
}
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ impl Element for SharedString {
|
|||
(layout_id, state)
|
||||
}
|
||||
|
||||
fn paint(self, bounds: Bounds<Pixels>, state: &mut TextState, cx: &mut WindowContext) {
|
||||
fn paint(&mut self, bounds: Bounds<Pixels>, state: &mut TextState, cx: &mut WindowContext) {
|
||||
let text_str: &str = self.as_ref();
|
||||
state.paint(bounds, text_str, cx)
|
||||
}
|
||||
|
@ -128,7 +128,7 @@ impl Element for StyledText {
|
|||
(layout_id, state)
|
||||
}
|
||||
|
||||
fn paint(self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext) {
|
||||
fn paint(&mut self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext) {
|
||||
state.paint(bounds, &self.text, cx)
|
||||
}
|
||||
}
|
||||
|
@ -356,8 +356,8 @@ impl Element for InteractiveText {
|
|||
}
|
||||
}
|
||||
|
||||
fn paint(self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext) {
|
||||
if let Some(click_listener) = self.click_listener {
|
||||
fn paint(&mut self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext) {
|
||||
if let Some(click_listener) = self.click_listener.take() {
|
||||
if let Some(ix) = state
|
||||
.text_state
|
||||
.index_for_position(bounds, cx.mouse_position())
|
||||
|
@ -374,13 +374,14 @@ impl Element for InteractiveText {
|
|||
let text_state = state.text_state.clone();
|
||||
let mouse_down = state.mouse_down_index.clone();
|
||||
if let Some(mouse_down_index) = mouse_down.get() {
|
||||
let clickable_ranges = mem::take(&mut self.clickable_ranges);
|
||||
cx.on_mouse_event(move |event: &MouseUpEvent, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble {
|
||||
if let Some(mouse_up_index) =
|
||||
text_state.index_for_position(bounds, event.position)
|
||||
{
|
||||
click_listener(
|
||||
&self.clickable_ranges,
|
||||
&clickable_ranges,
|
||||
InteractiveTextClickEvent {
|
||||
mouse_down_index,
|
||||
mouse_up_index,
|
||||
|
|
|
@ -10,6 +10,7 @@ use taffy::style::Overflow;
|
|||
/// uniform_list provides lazy rendering for a set of items that are of uniform height.
|
||||
/// When rendered into a container with overflow-y: hidden and a fixed (or max) height,
|
||||
/// uniform_list will only render the visible subset of items.
|
||||
#[track_caller]
|
||||
pub fn uniform_list<I, R, V>(
|
||||
view: View<V>,
|
||||
id: I,
|
||||
|
@ -42,6 +43,10 @@ where
|
|||
interactivity: Interactivity {
|
||||
element_id: Some(id.into()),
|
||||
base_style: Box::new(base_style),
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
location: Some(*core::panic::Location::caller()),
|
||||
|
||||
..Default::default()
|
||||
},
|
||||
scroll_handle: None,
|
||||
|
@ -150,7 +155,7 @@ impl Element for UniformList {
|
|||
}
|
||||
|
||||
fn paint(
|
||||
self,
|
||||
&mut self,
|
||||
bounds: Bounds<crate::Pixels>,
|
||||
element_state: &mut Self::State,
|
||||
cx: &mut WindowContext,
|
||||
|
@ -197,41 +202,41 @@ impl Element for UniformList {
|
|||
);
|
||||
|
||||
cx.with_z_index(style.z_index.unwrap_or(0), |cx| {
|
||||
style.paint(bounds, cx);
|
||||
style.paint(bounds, cx, |cx| {
|
||||
if self.item_count > 0 {
|
||||
if let Some(scroll_handle) = self.scroll_handle.clone() {
|
||||
scroll_handle.0.borrow_mut().replace(ScrollHandleState {
|
||||
item_height,
|
||||
list_height: padded_bounds.size.height,
|
||||
scroll_offset: shared_scroll_offset,
|
||||
});
|
||||
}
|
||||
|
||||
if self.item_count > 0 {
|
||||
if let Some(scroll_handle) = self.scroll_handle.clone() {
|
||||
scroll_handle.0.borrow_mut().replace(ScrollHandleState {
|
||||
item_height,
|
||||
list_height: padded_bounds.size.height,
|
||||
scroll_offset: shared_scroll_offset,
|
||||
let first_visible_element_ix =
|
||||
(-scroll_offset.y / item_height).floor() as usize;
|
||||
let last_visible_element_ix =
|
||||
((-scroll_offset.y + padded_bounds.size.height) / item_height)
|
||||
.ceil() as usize;
|
||||
let visible_range = first_visible_element_ix
|
||||
..cmp::min(last_visible_element_ix, self.item_count);
|
||||
|
||||
let mut items = (self.render_items)(visible_range.clone(), cx);
|
||||
cx.with_z_index(1, |cx| {
|
||||
let content_mask = ContentMask { bounds };
|
||||
cx.with_content_mask(Some(content_mask), |cx| {
|
||||
for (item, ix) in items.iter_mut().zip(visible_range) {
|
||||
let item_origin = padded_bounds.origin
|
||||
+ point(px(0.), item_height * ix + scroll_offset.y);
|
||||
let available_space = size(
|
||||
AvailableSpace::Definite(padded_bounds.size.width),
|
||||
AvailableSpace::Definite(item_height),
|
||||
);
|
||||
item.draw(item_origin, available_space, cx);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
let first_visible_element_ix =
|
||||
(-scroll_offset.y / item_height).floor() as usize;
|
||||
let last_visible_element_ix =
|
||||
((-scroll_offset.y + padded_bounds.size.height) / item_height).ceil()
|
||||
as usize;
|
||||
let visible_range = first_visible_element_ix
|
||||
..cmp::min(last_visible_element_ix, self.item_count);
|
||||
|
||||
let items = (self.render_items)(visible_range.clone(), cx);
|
||||
cx.with_z_index(1, |cx| {
|
||||
let content_mask = ContentMask { bounds };
|
||||
cx.with_content_mask(Some(content_mask), |cx| {
|
||||
for (item, ix) in items.into_iter().zip(visible_range) {
|
||||
let item_origin = padded_bounds.origin
|
||||
+ point(px(0.), item_height * ix + scroll_offset.y);
|
||||
let available_space = size(
|
||||
AvailableSpace::Definite(padded_bounds.size.width),
|
||||
AvailableSpace::Definite(item_height),
|
||||
);
|
||||
item.draw(item_origin, available_space, cx);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
})
|
||||
},
|
||||
);
|
||||
|
|
|
@ -1592,6 +1592,17 @@ impl Edges<Pixels> {
|
|||
}
|
||||
}
|
||||
|
||||
impl Into<Edges<Pixels>> for f32 {
|
||||
fn into(self) -> Edges<Pixels> {
|
||||
Edges {
|
||||
top: self.into(),
|
||||
right: self.into(),
|
||||
bottom: self.into(),
|
||||
left: self.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents the corners of a box in a 2D space, such as border radius.
|
||||
///
|
||||
/// Each field represents the size of the corner on one side of the box: `top_left`, `top_right`, `bottom_right`, and `bottom_left`.
|
||||
|
@ -1808,6 +1819,28 @@ where
|
|||
|
||||
impl<T> Copy for Corners<T> where T: Copy + Clone + Default + Debug {}
|
||||
|
||||
impl Into<Corners<Pixels>> for f32 {
|
||||
fn into(self) -> Corners<Pixels> {
|
||||
Corners {
|
||||
top_left: self.into(),
|
||||
top_right: self.into(),
|
||||
bottom_right: self.into(),
|
||||
bottom_left: self.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<Corners<Pixels>> for Pixels {
|
||||
fn into(self) -> Corners<Pixels> {
|
||||
Corners {
|
||||
top_left: self,
|
||||
top_right: self,
|
||||
bottom_right: self,
|
||||
bottom_left: self,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a length in pixels, the base unit of measurement in the UI framework.
|
||||
///
|
||||
/// `Pixels` is a value type that represents an absolute length in pixels, which is used
|
||||
|
|
|
@ -147,6 +147,7 @@ pub trait PlatformWindow {
|
|||
fn appearance(&self) -> WindowAppearance;
|
||||
fn display(&self) -> Rc<dyn PlatformDisplay>;
|
||||
fn mouse_position(&self) -> Point<Pixels>;
|
||||
fn modifiers(&self) -> Modifiers;
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any;
|
||||
fn set_input_handler(&mut self, input_handler: Box<dyn PlatformInputHandler>);
|
||||
fn clear_input_handler(&mut self);
|
||||
|
|
|
@ -187,6 +187,8 @@ impl MetalRenderer {
|
|||
}
|
||||
|
||||
pub fn draw(&mut self, scene: &Scene) {
|
||||
let start = std::time::Instant::now();
|
||||
|
||||
let layer = self.layer.clone();
|
||||
let viewport_size = layer.drawable_size();
|
||||
let viewport_size: Size<DevicePixels> = size(
|
||||
|
@ -303,6 +305,10 @@ impl MetalRenderer {
|
|||
|
||||
command_buffer.commit();
|
||||
self.sprite_atlas.clear_textures(AtlasTextureKind::Path);
|
||||
|
||||
let duration_since_start = start.elapsed();
|
||||
println!("renderer draw: {:?}", duration_since_start);
|
||||
|
||||
command_buffer.wait_until_completed();
|
||||
drawable.present();
|
||||
}
|
||||
|
|
|
@ -9,9 +9,10 @@ use crate::{
|
|||
use block::ConcreteBlock;
|
||||
use cocoa::{
|
||||
appkit::{
|
||||
CGPoint, NSApplication, NSBackingStoreBuffered, NSFilenamesPboardType, NSPasteboard,
|
||||
NSScreen, NSView, NSViewHeightSizable, NSViewWidthSizable, NSWindow, NSWindowButton,
|
||||
NSWindowCollectionBehavior, NSWindowStyleMask, NSWindowTitleVisibility,
|
||||
CGPoint, NSApplication, NSBackingStoreBuffered, NSEventModifierFlags,
|
||||
NSFilenamesPboardType, NSPasteboard, NSScreen, NSView, NSViewHeightSizable,
|
||||
NSViewWidthSizable, NSWindow, NSWindowButton, NSWindowCollectionBehavior,
|
||||
NSWindowStyleMask, NSWindowTitleVisibility,
|
||||
},
|
||||
base::{id, nil},
|
||||
foundation::{
|
||||
|
@ -744,6 +745,26 @@ impl PlatformWindow for MacWindow {
|
|||
convert_mouse_position(position, self.content_size().height)
|
||||
}
|
||||
|
||||
fn modifiers(&self) -> Modifiers {
|
||||
unsafe {
|
||||
let modifiers: NSEventModifierFlags = msg_send![class!(NSEvent), modifierFlags];
|
||||
|
||||
let control = modifiers.contains(NSEventModifierFlags::NSControlKeyMask);
|
||||
let alt = modifiers.contains(NSEventModifierFlags::NSAlternateKeyMask);
|
||||
let shift = modifiers.contains(NSEventModifierFlags::NSShiftKeyMask);
|
||||
let command = modifiers.contains(NSEventModifierFlags::NSCommandKeyMask);
|
||||
let function = modifiers.contains(NSEventModifierFlags::NSFunctionKeyMask);
|
||||
|
||||
Modifiers {
|
||||
control,
|
||||
alt,
|
||||
shift,
|
||||
command,
|
||||
function,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any {
|
||||
self
|
||||
}
|
||||
|
|
|
@ -79,6 +79,10 @@ impl PlatformWindow for TestWindow {
|
|||
Point::default()
|
||||
}
|
||||
|
||||
fn modifiers(&self) -> crate::Modifiers {
|
||||
crate::Modifiers::default()
|
||||
}
|
||||
|
||||
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ pub type LayerId = u32;
|
|||
pub type DrawOrder = u32;
|
||||
|
||||
pub(crate) struct SceneBuilder {
|
||||
last_order: Option<(StackingOrder, LayerId)>,
|
||||
layers_by_order: BTreeMap<StackingOrder, LayerId>,
|
||||
splitter: BspSplitter<(PrimitiveKind, usize)>,
|
||||
shadows: Vec<Shadow>,
|
||||
|
@ -31,6 +32,7 @@ pub(crate) struct SceneBuilder {
|
|||
impl Default for SceneBuilder {
|
||||
fn default() -> Self {
|
||||
SceneBuilder {
|
||||
last_order: None,
|
||||
layers_by_order: BTreeMap::new(),
|
||||
splitter: BspSplitter::new(),
|
||||
shadows: Vec::new(),
|
||||
|
@ -52,6 +54,7 @@ impl SceneBuilder {
|
|||
layer_z_values[*layer_id as usize] = ix as f32 / self.layers_by_order.len() as f32;
|
||||
}
|
||||
self.layers_by_order.clear();
|
||||
self.last_order = None;
|
||||
|
||||
// Add all primitives to the BSP splitter to determine draw order
|
||||
self.splitter.reset();
|
||||
|
@ -156,14 +159,7 @@ impl SceneBuilder {
|
|||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
next_id
|
||||
};
|
||||
|
||||
let layer_id = self.layer_id_for_order(order);
|
||||
match primitive {
|
||||
Primitive::Shadow(mut shadow) => {
|
||||
shadow.order = layer_id;
|
||||
|
@ -196,6 +192,24 @@ impl SceneBuilder {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn layer_id_for_order(&mut self, order: &StackingOrder) -> u32 {
|
||||
if let Some((last_order, last_layer_id)) = self.last_order.as_ref() {
|
||||
if last_order == 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);
|
||||
next_id
|
||||
};
|
||||
self.last_order = Some((order.clone(), layer_id));
|
||||
layer_id
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Scene {
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use std::{iter, mem, ops::Range};
|
||||
|
||||
use crate::{
|
||||
black, phi, point, rems, AbsoluteLength, BorrowAppContext, BorrowWindow, Bounds, ContentMask,
|
||||
Corners, CornersRefinement, CursorStyle, DefiniteLength, Edges, EdgesRefinement, Font,
|
||||
FontFeatures, FontStyle, FontWeight, Hsla, Length, Pixels, Point, PointRefinement, Rgba,
|
||||
black, phi, point, quad, rems, AbsoluteLength, BorrowAppContext, BorrowWindow, Bounds,
|
||||
ContentMask, Corners, CornersRefinement, CursorStyle, DefiniteLength, Edges, EdgesRefinement,
|
||||
Font, FontFeatures, FontStyle, FontWeight, Hsla, Length, Pixels, Point, PointRefinement, Rgba,
|
||||
SharedString, Size, SizeRefinement, Styled, TextRun, WindowContext,
|
||||
};
|
||||
use collections::HashSet;
|
||||
|
@ -14,6 +14,9 @@ pub use taffy::style::{
|
|||
Overflow, Position,
|
||||
};
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
pub struct DebugBelow;
|
||||
|
||||
pub type StyleCascade = Cascade<Style>;
|
||||
|
||||
#[derive(Clone, Refineable, Debug)]
|
||||
|
@ -107,7 +110,12 @@ pub struct Style {
|
|||
/// The mouse cursor style shown when the mouse pointer is over an element.
|
||||
pub mouse_cursor: Option<CursorStyle>,
|
||||
|
||||
pub z_index: Option<u32>,
|
||||
pub z_index: Option<u8>,
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
pub debug: bool,
|
||||
#[cfg(debug_assertions)]
|
||||
pub debug_below: bool,
|
||||
}
|
||||
|
||||
impl Styled for StyleRefinement {
|
||||
|
@ -334,7 +342,22 @@ impl Style {
|
|||
}
|
||||
|
||||
/// Paints the background of an element styled with this style.
|
||||
pub fn paint(&self, bounds: Bounds<Pixels>, cx: &mut WindowContext) {
|
||||
pub fn paint(
|
||||
&self,
|
||||
bounds: Bounds<Pixels>,
|
||||
cx: &mut WindowContext,
|
||||
continuation: impl FnOnce(&mut WindowContext),
|
||||
) {
|
||||
#[cfg(debug_assertions)]
|
||||
if self.debug_below {
|
||||
cx.set_global(DebugBelow)
|
||||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
if self.debug || cx.has_global::<DebugBelow>() {
|
||||
cx.paint_quad(crate::outline(bounds, crate::red()));
|
||||
}
|
||||
|
||||
let rem_size = cx.rem_size();
|
||||
|
||||
cx.with_z_index(0, |cx| {
|
||||
|
@ -348,15 +371,24 @@ impl Style {
|
|||
let background_color = self.background.as_ref().and_then(Fill::color);
|
||||
if background_color.is_some() || self.is_border_visible() {
|
||||
cx.with_z_index(1, |cx| {
|
||||
cx.paint_quad(
|
||||
cx.paint_quad(quad(
|
||||
bounds,
|
||||
self.corner_radii.to_pixels(bounds.size, rem_size),
|
||||
background_color.unwrap_or_default(),
|
||||
self.border_widths.to_pixels(rem_size),
|
||||
self.border_color.unwrap_or_default(),
|
||||
);
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
cx.with_z_index(2, |cx| {
|
||||
continuation(cx);
|
||||
});
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
if self.debug_below {
|
||||
cx.remove_global::<DebugBelow>();
|
||||
}
|
||||
}
|
||||
|
||||
fn is_border_visible(&self) -> bool {
|
||||
|
@ -404,6 +436,11 @@ impl Default for Style {
|
|||
text: TextStyleRefinement::default(),
|
||||
mouse_cursor: None,
|
||||
z_index: None,
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
debug: false,
|
||||
#[cfg(debug_assertions)]
|
||||
debug_below: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ pub trait Styled: Sized {
|
|||
|
||||
gpui2_macros::style_helpers!();
|
||||
|
||||
fn z_index(mut self, z_index: u32) -> Self {
|
||||
fn z_index(mut self, z_index: u8) -> Self {
|
||||
self.style().z_index = Some(z_index);
|
||||
self
|
||||
}
|
||||
|
@ -633,4 +633,16 @@ pub trait Styled: Sized {
|
|||
.line_height = Some(line_height.into());
|
||||
self
|
||||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
fn debug(mut self) -> Self {
|
||||
self.style().debug = Some(true);
|
||||
self
|
||||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
fn debug_below(mut self) -> Self {
|
||||
self.style().debug_below = Some(true);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use crate::{
|
||||
black, point, px, size, transparent_black, BorrowWindow, Bounds, Corners, Edges, Hsla,
|
||||
LineLayout, Pixels, Point, Result, SharedString, UnderlineStyle, WindowContext, WrapBoundary,
|
||||
WrappedLineLayout,
|
||||
black, fill, point, px, size, BorrowWindow, Bounds, Hsla, LineLayout, Pixels, Point, Result,
|
||||
SharedString, UnderlineStyle, WindowContext, WrapBoundary, WrappedLineLayout,
|
||||
};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use smallvec::SmallVec;
|
||||
|
@ -109,16 +108,13 @@ fn paint_line(
|
|||
if wraps.peek() == Some(&&WrapBoundary { run_ix, glyph_ix }) {
|
||||
wraps.next();
|
||||
if let Some((background_origin, background_color)) = current_background.as_mut() {
|
||||
cx.paint_quad(
|
||||
cx.paint_quad(fill(
|
||||
Bounds {
|
||||
origin: *background_origin,
|
||||
size: size(glyph_origin.x - background_origin.x, line_height),
|
||||
},
|
||||
Corners::default(),
|
||||
*background_color,
|
||||
Edges::default(),
|
||||
transparent_black(),
|
||||
);
|
||||
));
|
||||
background_origin.x = origin.x;
|
||||
background_origin.y += line_height;
|
||||
}
|
||||
|
@ -180,16 +176,13 @@ fn paint_line(
|
|||
}
|
||||
|
||||
if let Some((background_origin, background_color)) = finished_background {
|
||||
cx.paint_quad(
|
||||
cx.paint_quad(fill(
|
||||
Bounds {
|
||||
origin: background_origin,
|
||||
size: size(glyph_origin.x - background_origin.x, line_height),
|
||||
},
|
||||
Corners::default(),
|
||||
background_color,
|
||||
Edges::default(),
|
||||
transparent_black(),
|
||||
);
|
||||
));
|
||||
}
|
||||
|
||||
if let Some((underline_origin, underline_style)) = finished_underline {
|
||||
|
@ -235,16 +228,13 @@ fn paint_line(
|
|||
}
|
||||
|
||||
if let Some((background_origin, background_color)) = current_background.take() {
|
||||
cx.paint_quad(
|
||||
cx.paint_quad(fill(
|
||||
Bounds {
|
||||
origin: background_origin,
|
||||
size: size(last_line_end_x - background_origin.x, line_height),
|
||||
},
|
||||
Corners::default(),
|
||||
background_color,
|
||||
Edges::default(),
|
||||
transparent_black(),
|
||||
);
|
||||
));
|
||||
}
|
||||
|
||||
if let Some((underline_start, underline_style)) = current_underline.take() {
|
||||
|
|
|
@ -7,6 +7,7 @@ use crate::{
|
|||
use anyhow::{Context, Result};
|
||||
use std::{
|
||||
any::TypeId,
|
||||
fmt,
|
||||
hash::{Hash, Hasher},
|
||||
};
|
||||
|
||||
|
@ -90,7 +91,7 @@ impl<V: Render> Element for View<V> {
|
|||
(layout_id, Some(element))
|
||||
}
|
||||
|
||||
fn paint(self, _: Bounds<Pixels>, element: &mut Self::State, cx: &mut WindowContext) {
|
||||
fn paint(&mut self, _: Bounds<Pixels>, element: &mut Self::State, cx: &mut WindowContext) {
|
||||
element.take().unwrap().paint(cx);
|
||||
}
|
||||
}
|
||||
|
@ -170,7 +171,7 @@ impl<V> Eq for WeakView<V> {}
|
|||
pub struct AnyView {
|
||||
model: AnyModel,
|
||||
layout: fn(&AnyView, &mut WindowContext) -> (LayoutId, AnyElement),
|
||||
paint: fn(&AnyView, AnyElement, &mut WindowContext),
|
||||
paint: fn(&AnyView, &mut AnyElement, &mut WindowContext),
|
||||
}
|
||||
|
||||
impl AnyView {
|
||||
|
@ -208,9 +209,20 @@ impl AnyView {
|
|||
cx: &mut WindowContext,
|
||||
) {
|
||||
cx.with_absolute_element_offset(origin, |cx| {
|
||||
let (layout_id, rendered_element) = (self.layout)(self, cx);
|
||||
let start_time = std::time::Instant::now();
|
||||
let (layout_id, mut rendered_element) = (self.layout)(self, cx);
|
||||
let duration = start_time.elapsed();
|
||||
println!("request layout: {:?}", duration);
|
||||
|
||||
let start_time = std::time::Instant::now();
|
||||
cx.compute_layout(layout_id, available_space);
|
||||
(self.paint)(self, rendered_element, cx);
|
||||
let duration = start_time.elapsed();
|
||||
println!("compute layout: {:?}", duration);
|
||||
|
||||
let start_time = std::time::Instant::now();
|
||||
(self.paint)(self, &mut rendered_element, cx);
|
||||
let duration = start_time.elapsed();
|
||||
println!("paint: {:?}", duration);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -237,12 +249,12 @@ impl Element for AnyView {
|
|||
(layout_id, Some(state))
|
||||
}
|
||||
|
||||
fn paint(self, _: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext) {
|
||||
fn paint(&mut self, _: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext) {
|
||||
debug_assert!(
|
||||
state.is_some(),
|
||||
"state is None. Did you include an AnyView twice in the tree?"
|
||||
);
|
||||
(self.paint)(&self, state.take().unwrap(), cx)
|
||||
(self.paint)(&self, state.as_mut().unwrap(), cx)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -273,7 +285,7 @@ impl IntoElement for AnyView {
|
|||
pub struct AnyWeakView {
|
||||
model: AnyWeakModel,
|
||||
layout: fn(&AnyView, &mut WindowContext) -> (LayoutId, AnyElement),
|
||||
paint: fn(&AnyView, AnyElement, &mut WindowContext),
|
||||
paint: fn(&AnyView, &mut AnyElement, &mut WindowContext),
|
||||
}
|
||||
|
||||
impl AnyWeakView {
|
||||
|
@ -297,6 +309,20 @@ impl<V: 'static + Render> From<WeakView<V>> for AnyWeakView {
|
|||
}
|
||||
}
|
||||
|
||||
impl PartialEq for AnyWeakView {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.model == other.model
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for AnyWeakView {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("AnyWeakView")
|
||||
.field("entity_id", &self.model.entity_id)
|
||||
.finish_non_exhaustive()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, E> Render for T
|
||||
where
|
||||
T: 'static + FnMut(&mut WindowContext) -> E,
|
||||
|
@ -324,7 +350,7 @@ mod any_view {
|
|||
|
||||
pub(crate) fn paint<V: 'static + Render>(
|
||||
_view: &AnyView,
|
||||
element: AnyElement,
|
||||
element: &mut AnyElement,
|
||||
cx: &mut WindowContext,
|
||||
) {
|
||||
element.paint(cx);
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
use crate::{
|
||||
key_dispatch::DispatchActionListener, px, size, Action, AnyDrag, AnyView, AppContext,
|
||||
AsyncWindowContext, AvailableSpace, Bounds, BoxShadow, Context, Corners, CursorStyle,
|
||||
DevicePixels, DispatchNodeId, DispatchTree, DisplayId, Edges, Effect, Entity, EntityId,
|
||||
EventEmitter, FileDropEvent, Flatten, FontId, GlobalElementId, GlyphId, Hsla, ImageData,
|
||||
InputEvent, IsZero, KeyBinding, KeyContext, KeyDownEvent, KeystrokeEvent, LayoutId, Model,
|
||||
ModelContext, Modifiers, MonochromeSprite, MouseButton, MouseMoveEvent, MouseUpEvent, Path,
|
||||
Pixels, PlatformAtlas, PlatformDisplay, PlatformInputHandler, PlatformWindow, Point,
|
||||
key_dispatch::DispatchActionListener, px, size, transparent_black, Action, AnyDrag, AnyView,
|
||||
AppContext, AsyncWindowContext, AvailableSpace, Bounds, BoxShadow, Context, Corners,
|
||||
CursorStyle, DevicePixels, DispatchNodeId, DispatchTree, DisplayId, Edges, Effect, Entity,
|
||||
EntityId, EventEmitter, FileDropEvent, Flatten, FontId, GlobalElementId, GlyphId, Hsla,
|
||||
ImageData, InputEvent, IsZero, KeyBinding, KeyContext, KeyDownEvent, KeystrokeEvent, LayoutId,
|
||||
Model, ModelContext, Modifiers, MonochromeSprite, MouseButton, MouseMoveEvent, MouseUpEvent,
|
||||
Path, Pixels, PlatformAtlas, PlatformDisplay, PlatformInputHandler, PlatformWindow, Point,
|
||||
PolychromeSprite, PromptLevel, Quad, Render, RenderGlyphParams, RenderImageParams,
|
||||
RenderSvgParams, ScaledPixels, Scene, SceneBuilder, Shadow, SharedString, Size, Style,
|
||||
SubscriberSet, Subscription, Surface, TaffyLayoutEngine, Task, Underline, UnderlineStyle, View,
|
||||
VisualContext, WeakView, WindowBounds, WindowOptions, SUBPIXEL_VARIANTS,
|
||||
};
|
||||
use anyhow::{anyhow, Context as _, Result};
|
||||
use collections::HashMap;
|
||||
use collections::FxHashMap;
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use futures::{
|
||||
channel::{mpsc, oneshot},
|
||||
|
@ -38,12 +38,24 @@ use std::{
|
|||
};
|
||||
use util::ResultExt;
|
||||
|
||||
const ACTIVE_DRAG_Z_INDEX: u32 = 1;
|
||||
const ACTIVE_DRAG_Z_INDEX: u8 = 1;
|
||||
|
||||
/// A global stacking order, which is created by stacking successive z-index values.
|
||||
/// Each z-index will always be interpreted in the context of its parent z-index.
|
||||
#[derive(Deref, DerefMut, Ord, PartialOrd, Eq, PartialEq, Clone, Default, Debug)]
|
||||
pub struct StackingOrder(pub(crate) SmallVec<[u32; 16]>);
|
||||
#[derive(Deref, DerefMut, Clone, Debug, Ord, PartialOrd, PartialEq, Eq)]
|
||||
pub struct StackingOrder {
|
||||
#[deref]
|
||||
#[deref_mut]
|
||||
z_indices: SmallVec<[u8; 64]>,
|
||||
}
|
||||
|
||||
impl Default for StackingOrder {
|
||||
fn default() -> Self {
|
||||
StackingOrder {
|
||||
z_indices: SmallVec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents the two different phases when dispatching events.
|
||||
#[derive(Default, Copy, Clone, Debug, Eq, PartialEq)]
|
||||
|
@ -235,12 +247,14 @@ pub struct Window {
|
|||
blur_listeners: SubscriberSet<(), AnyObserver>,
|
||||
default_prevented: bool,
|
||||
mouse_position: Point<Pixels>,
|
||||
modifiers: Modifiers,
|
||||
requested_cursor_style: Option<CursorStyle>,
|
||||
scale_factor: f32,
|
||||
bounds: WindowBounds,
|
||||
bounds_observers: SubscriberSet<(), AnyObserver>,
|
||||
active: bool,
|
||||
pub(crate) dirty: bool,
|
||||
pub(crate) drawing: bool,
|
||||
activation_observers: SubscriberSet<(), AnyObserver>,
|
||||
pub(crate) focus: Option<FocusId>,
|
||||
|
||||
|
@ -257,8 +271,8 @@ pub(crate) struct ElementStateBox {
|
|||
// #[derive(Default)]
|
||||
pub(crate) struct Frame {
|
||||
focus: Option<FocusId>,
|
||||
pub(crate) element_states: HashMap<GlobalElementId, ElementStateBox>,
|
||||
mouse_listeners: HashMap<TypeId, Vec<(StackingOrder, AnyMouseListener)>>,
|
||||
pub(crate) element_states: FxHashMap<GlobalElementId, ElementStateBox>,
|
||||
mouse_listeners: FxHashMap<TypeId, Vec<(StackingOrder, AnyMouseListener)>>,
|
||||
pub(crate) dispatch_tree: DispatchTree,
|
||||
pub(crate) scene_builder: SceneBuilder,
|
||||
pub(crate) depth_map: Vec<(StackingOrder, Bounds<Pixels>)>,
|
||||
|
@ -271,8 +285,8 @@ impl Frame {
|
|||
fn new(dispatch_tree: DispatchTree) -> Self {
|
||||
Frame {
|
||||
focus: None,
|
||||
element_states: HashMap::default(),
|
||||
mouse_listeners: HashMap::default(),
|
||||
element_states: FxHashMap::default(),
|
||||
mouse_listeners: FxHashMap::default(),
|
||||
dispatch_tree,
|
||||
scene_builder: SceneBuilder::default(),
|
||||
z_index_stack: StackingOrder::default(),
|
||||
|
@ -313,6 +327,7 @@ impl Window {
|
|||
let display_id = platform_window.display().id();
|
||||
let sprite_atlas = platform_window.sprite_atlas();
|
||||
let mouse_position = platform_window.mouse_position();
|
||||
let modifiers = platform_window.modifiers();
|
||||
let content_size = platform_window.content_size();
|
||||
let scale_factor = platform_window.scale_factor();
|
||||
let bounds = platform_window.bounds();
|
||||
|
@ -376,12 +391,14 @@ impl Window {
|
|||
blur_listeners: SubscriberSet::new(),
|
||||
default_prevented: true,
|
||||
mouse_position,
|
||||
modifiers,
|
||||
requested_cursor_style: None,
|
||||
scale_factor,
|
||||
bounds,
|
||||
bounds_observers: SubscriberSet::new(),
|
||||
active: false,
|
||||
dirty: false,
|
||||
drawing: false,
|
||||
activation_observers: SubscriberSet::new(),
|
||||
focus: None,
|
||||
|
||||
|
@ -435,7 +452,9 @@ impl<'a> WindowContext<'a> {
|
|||
|
||||
/// Mark the window as dirty, scheduling it to be redrawn on the next frame.
|
||||
pub fn notify(&mut self) {
|
||||
self.window.dirty = true;
|
||||
if !self.window.drawing {
|
||||
self.window.dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// Close this window.
|
||||
|
@ -805,7 +824,7 @@ impl<'a> WindowContext<'a> {
|
|||
/// a specific need to register a global listener.
|
||||
pub fn on_mouse_event<Event: 'static>(
|
||||
&mut self,
|
||||
handler: impl Fn(&Event, DispatchPhase, &mut WindowContext) + 'static,
|
||||
mut handler: impl FnMut(&Event, DispatchPhase, &mut WindowContext) + 'static,
|
||||
) {
|
||||
let order = self.window.next_frame.z_index_stack.clone();
|
||||
self.window
|
||||
|
@ -879,13 +898,18 @@ impl<'a> WindowContext<'a> {
|
|||
self.window.mouse_position
|
||||
}
|
||||
|
||||
/// The current state of the keyboard's modifiers
|
||||
pub fn modifiers(&self) -> Modifiers {
|
||||
self.window.modifiers
|
||||
}
|
||||
|
||||
pub fn set_cursor_style(&mut self, style: CursorStyle) {
|
||||
self.window.requested_cursor_style = Some(style)
|
||||
}
|
||||
|
||||
/// Called during painting to invoke the given closure in a new stacking context. The given
|
||||
/// z-index is interpreted relative to the previous call to `stack`.
|
||||
pub fn with_z_index<R>(&mut self, z_index: u32, f: impl FnOnce(&mut Self) -> R) -> R {
|
||||
pub fn with_z_index<R>(&mut self, z_index: u8, f: impl FnOnce(&mut Self) -> R) -> R {
|
||||
self.window.next_frame.z_index_stack.push(z_index);
|
||||
let result = f(self);
|
||||
self.window.next_frame.z_index_stack.pop();
|
||||
|
@ -965,14 +989,8 @@ impl<'a> WindowContext<'a> {
|
|||
|
||||
/// Paint one or more quads into the scene for the next frame at the current stacking context.
|
||||
/// Quads are colored rectangular regions with an optional background, border, and corner radius.
|
||||
pub fn paint_quad(
|
||||
&mut self,
|
||||
bounds: Bounds<Pixels>,
|
||||
corner_radii: Corners<Pixels>,
|
||||
background: impl Into<Hsla>,
|
||||
border_widths: Edges<Pixels>,
|
||||
border_color: impl Into<Hsla>,
|
||||
) {
|
||||
/// see [`fill`], [`outline`], and [`quad`] to construct this type.
|
||||
pub fn paint_quad(&mut self, quad: PaintQuad) {
|
||||
let scale_factor = self.scale_factor();
|
||||
let content_mask = self.content_mask();
|
||||
|
||||
|
@ -981,12 +999,12 @@ impl<'a> WindowContext<'a> {
|
|||
&window.next_frame.z_index_stack,
|
||||
Quad {
|
||||
order: 0,
|
||||
bounds: bounds.scale(scale_factor),
|
||||
bounds: quad.bounds.scale(scale_factor),
|
||||
content_mask: content_mask.scale(scale_factor),
|
||||
background: background.into(),
|
||||
border_color: border_color.into(),
|
||||
corner_radii: corner_radii.scale(scale_factor),
|
||||
border_widths: border_widths.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),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -1238,6 +1256,10 @@ impl<'a> WindowContext<'a> {
|
|||
|
||||
/// Draw pixels to the display for this window based on the contents of its scene.
|
||||
pub(crate) fn draw(&mut self) -> Scene {
|
||||
let t0 = std::time::Instant::now();
|
||||
self.window.dirty = false;
|
||||
self.window.drawing = true;
|
||||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
{
|
||||
self.window.focus_invalidated = false;
|
||||
|
@ -1325,7 +1347,8 @@ impl<'a> WindowContext<'a> {
|
|||
self.platform.set_cursor_style(cursor_style);
|
||||
}
|
||||
|
||||
self.window.dirty = false;
|
||||
self.window.drawing = false;
|
||||
eprintln!("window draw: {:?}", t0.elapsed());
|
||||
|
||||
scene
|
||||
}
|
||||
|
@ -1342,16 +1365,34 @@ impl<'a> WindowContext<'a> {
|
|||
// API for the mouse position can only occur on the main thread.
|
||||
InputEvent::MouseMove(mouse_move) => {
|
||||
self.window.mouse_position = mouse_move.position;
|
||||
self.window.modifiers = mouse_move.modifiers;
|
||||
InputEvent::MouseMove(mouse_move)
|
||||
}
|
||||
InputEvent::MouseDown(mouse_down) => {
|
||||
self.window.mouse_position = mouse_down.position;
|
||||
self.window.modifiers = mouse_down.modifiers;
|
||||
InputEvent::MouseDown(mouse_down)
|
||||
}
|
||||
InputEvent::MouseUp(mouse_up) => {
|
||||
self.window.mouse_position = mouse_up.position;
|
||||
self.window.modifiers = mouse_up.modifiers;
|
||||
InputEvent::MouseUp(mouse_up)
|
||||
}
|
||||
InputEvent::MouseExited(mouse_exited) => {
|
||||
// todo!("Should we record that the mouse is outside of the window somehow? Or are these global pixels?")
|
||||
self.window.modifiers = mouse_exited.modifiers;
|
||||
|
||||
InputEvent::MouseExited(mouse_exited)
|
||||
}
|
||||
InputEvent::ModifiersChanged(modifiers_changed) => {
|
||||
self.window.modifiers = modifiers_changed.modifiers;
|
||||
InputEvent::ModifiersChanged(modifiers_changed)
|
||||
}
|
||||
InputEvent::ScrollWheel(scroll_wheel) => {
|
||||
self.window.mouse_position = scroll_wheel.position;
|
||||
self.window.modifiers = scroll_wheel.modifiers;
|
||||
InputEvent::ScrollWheel(scroll_wheel)
|
||||
}
|
||||
// Translate dragging and dropping of external files from the operating system
|
||||
// to internal drag and drop events.
|
||||
InputEvent::FileDrop(file_drop) => match file_drop {
|
||||
|
@ -1359,6 +1400,7 @@ impl<'a> WindowContext<'a> {
|
|||
self.window.mouse_position = position;
|
||||
if self.active_drag.is_none() {
|
||||
self.active_drag = Some(AnyDrag {
|
||||
value: Box::new(files.clone()),
|
||||
view: self.build_view(|_| files).into(),
|
||||
cursor_offset: position,
|
||||
});
|
||||
|
@ -1394,7 +1436,7 @@ impl<'a> WindowContext<'a> {
|
|||
click_count: 1,
|
||||
}),
|
||||
},
|
||||
_ => event,
|
||||
InputEvent::KeyDown(_) | InputEvent::KeyUp(_) => event,
|
||||
};
|
||||
|
||||
if let Some(any_mouse_event) = event.mouse_event() {
|
||||
|
@ -2190,7 +2232,7 @@ impl<'a, V: 'static> ViewContext<'a, V> {
|
|||
&mut self.window_cx
|
||||
}
|
||||
|
||||
pub fn with_z_index<R>(&mut self, z_index: u32, f: impl FnOnce(&mut Self) -> R) -> R {
|
||||
pub fn with_z_index<R>(&mut self, z_index: u8, f: impl FnOnce(&mut Self) -> R) -> R {
|
||||
self.window.next_frame.z_index_stack.push(z_index);
|
||||
let result = f(self);
|
||||
self.window.next_frame.z_index_stack.pop();
|
||||
|
@ -2327,10 +2369,12 @@ impl<'a, V: 'static> ViewContext<'a, V> {
|
|||
}
|
||||
|
||||
pub fn notify(&mut self) {
|
||||
self.window_cx.notify();
|
||||
self.window_cx.app.push_effect(Effect::Notify {
|
||||
emitter: self.view.model.entity_id,
|
||||
});
|
||||
if !self.window.drawing {
|
||||
self.window_cx.notify();
|
||||
self.window_cx.app.push_effect(Effect::Notify {
|
||||
emitter: self.view.model.entity_id,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub fn observe_window_bounds(
|
||||
|
@ -2865,12 +2909,12 @@ impl AnyWindowHandle {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
impl From<SmallVec<[u32; 16]>> for StackingOrder {
|
||||
fn from(small_vec: SmallVec<[u32; 16]>) -> Self {
|
||||
StackingOrder(small_vec)
|
||||
}
|
||||
}
|
||||
// #[cfg(any(test, feature = "test-support"))]
|
||||
// impl From<SmallVec<[u32; 16]>> for StackingOrder {
|
||||
// fn from(small_vec: SmallVec<[u32; 16]>) -> Self {
|
||||
// StackingOrder(small_vec)
|
||||
// }
|
||||
// }
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
|
||||
pub enum ElementId {
|
||||
|
@ -2946,3 +2990,85 @@ impl From<(&'static str, u64)> for ElementId {
|
|||
ElementId::NamedInteger(name.into(), id as usize)
|
||||
}
|
||||
}
|
||||
|
||||
/// A rectangle, to be rendered on the screen by GPUI at the given position and size.
|
||||
pub struct PaintQuad {
|
||||
bounds: Bounds<Pixels>,
|
||||
corner_radii: Corners<Pixels>,
|
||||
background: Hsla,
|
||||
border_widths: Edges<Pixels>,
|
||||
border_color: Hsla,
|
||||
}
|
||||
|
||||
impl PaintQuad {
|
||||
/// Set the corner radii of the quad.
|
||||
pub fn corner_radii(self, corner_radii: impl Into<Corners<Pixels>>) -> Self {
|
||||
PaintQuad {
|
||||
corner_radii: corner_radii.into(),
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the border widths of the quad.
|
||||
pub fn border_widths(self, border_widths: impl Into<Edges<Pixels>>) -> Self {
|
||||
PaintQuad {
|
||||
border_widths: border_widths.into(),
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the border color of the quad.
|
||||
pub fn border_color(self, border_color: impl Into<Hsla>) -> Self {
|
||||
PaintQuad {
|
||||
border_color: border_color.into(),
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the background color of the quad.
|
||||
pub fn background(self, background: impl Into<Hsla>) -> Self {
|
||||
PaintQuad {
|
||||
background: background.into(),
|
||||
..self
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a quad with the given parameters.
|
||||
pub fn quad(
|
||||
bounds: Bounds<Pixels>,
|
||||
corner_radii: impl Into<Corners<Pixels>>,
|
||||
background: impl Into<Hsla>,
|
||||
border_widths: impl Into<Edges<Pixels>>,
|
||||
border_color: impl Into<Hsla>,
|
||||
) -> PaintQuad {
|
||||
PaintQuad {
|
||||
bounds,
|
||||
corner_radii: corner_radii.into(),
|
||||
background: background.into(),
|
||||
border_widths: border_widths.into(),
|
||||
border_color: border_color.into(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a filled quad with the given bounds and background color.
|
||||
pub fn fill(bounds: impl Into<Bounds<Pixels>>, background: impl Into<Hsla>) -> PaintQuad {
|
||||
PaintQuad {
|
||||
bounds: bounds.into(),
|
||||
corner_radii: (0.).into(),
|
||||
background: background.into(),
|
||||
border_widths: (0.).into(),
|
||||
border_color: transparent_black(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a rectangle outline with the given bounds, border color, and a 1px border width
|
||||
pub fn outline(bounds: impl Into<Bounds<Pixels>>, border_color: impl Into<Hsla>) -> PaintQuad {
|
||||
PaintQuad {
|
||||
bounds: bounds.into(),
|
||||
corner_radii: (0.).into(),
|
||||
background: transparent_black(),
|
||||
border_widths: (1.).into(),
|
||||
border_color: border_color.into(),
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue