Merge pull request #2199 from zed-industries/welcome-experience

Welcome experience
This commit is contained in:
Mikayla Maki 2023-03-10 10:48:30 -08:00 committed by GitHub
commit 37d01c7fb3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
63 changed files with 2649 additions and 675 deletions

View file

@ -5086,7 +5086,7 @@ impl<T: Entity> From<WeakModelHandle<T>> for AnyWeakModelHandle {
}
}
#[derive(Debug)]
#[derive(Debug, Copy)]
pub struct WeakViewHandle<T> {
window_id: usize,
view_id: usize,

View file

@ -1,5 +1,8 @@
use anyhow::{anyhow, Result};
use std::{borrow::Cow, cell::RefCell, collections::HashMap};
use image::ImageFormat;
use std::{borrow::Cow, cell::RefCell, collections::HashMap, sync::Arc};
use crate::ImageData;
pub trait AssetSource: 'static + Send + Sync {
fn load(&self, path: &str) -> Result<Cow<[u8]>>;
@ -22,6 +25,7 @@ impl AssetSource for () {
pub struct AssetCache {
source: Box<dyn AssetSource>,
svgs: RefCell<HashMap<String, usvg::Tree>>,
pngs: RefCell<HashMap<String, Arc<ImageData>>>,
}
impl AssetCache {
@ -29,6 +33,7 @@ impl AssetCache {
Self {
source: Box::new(source),
svgs: RefCell::new(HashMap::new()),
pngs: RefCell::new(HashMap::new()),
}
}
@ -43,4 +48,18 @@ impl AssetCache {
Ok(svg)
}
}
pub fn png(&self, path: &str) -> Result<Arc<ImageData>> {
let mut pngs = self.pngs.borrow_mut();
if let Some(png) = pngs.get(path) {
Ok(png.clone())
} else {
let bytes = self.source.load(path)?;
let image = ImageData::new(
image::load_from_memory_with_format(&bytes, ImageFormat::Png)?.into_bgra8(),
);
pngs.insert(path.to_string(), image.clone());
Ok(image)
}
}
}

View file

@ -153,7 +153,9 @@ impl Element for ConstrainedBox {
_: &mut Self::LayoutState,
cx: &mut PaintContext,
) -> Self::PaintState {
self.child.paint(bounds.origin(), visible_bounds, cx);
cx.paint_layer(Some(visible_bounds), |cx| {
self.child.paint(bounds.origin(), visible_bounds, cx);
})
}
fn rect_for_text_range(

View file

@ -22,6 +22,7 @@ pub struct Flex {
axis: Axis,
children: Vec<ElementBox>,
scroll_state: Option<(ElementStateHandle<Rc<ScrollState>>, usize)>,
child_alignment: f32,
}
impl Flex {
@ -30,6 +31,7 @@ impl Flex {
axis,
children: Default::default(),
scroll_state: None,
child_alignment: -1.,
}
}
@ -41,6 +43,15 @@ impl Flex {
Self::new(Axis::Vertical)
}
/// Render children centered relative to the cross-axis of the parent flex.
///
/// If this is a flex row, children will be centered vertically. If this is a
/// flex column, children will be centered horizontally.
pub fn align_children_center(mut self) -> Self {
self.child_alignment = 0.;
self
}
pub fn scrollable<Tag, V>(
mut self,
element_id: usize,
@ -309,7 +320,30 @@ impl Element for Flex {
}
}
child.paint(child_origin, visible_bounds, cx);
// We use the child_alignment f32 to determine a point along the cross axis of the
// overall flex element and each child. We then align these points. So 0 would center
// each child relative to the overall height/width of the flex. -1 puts children at
// the start. 1 puts children at the end.
let aligned_child_origin = {
let cross_axis = self.axis.invert();
let my_center = bounds.size().along(cross_axis) / 2.;
let my_target = my_center + my_center * self.child_alignment;
let child_center = child.size().along(cross_axis) / 2.;
let child_target = child_center + child_center * self.child_alignment;
let mut aligned_child_origin = child_origin;
match self.axis {
Axis::Horizontal => aligned_child_origin
.set_y(aligned_child_origin.y() - (child_target - my_target)),
Axis::Vertical => aligned_child_origin
.set_x(aligned_child_origin.x() - (child_target - my_target)),
}
aligned_child_origin
};
child.paint(aligned_child_origin, visible_bounds, cx);
match self.axis {
Axis::Horizontal => child_origin += vec2f(child.size().x(), 0.0),

View file

@ -11,8 +11,13 @@ use crate::{
use serde::Deserialize;
use std::{ops::Range, sync::Arc};
enum ImageSource {
Path(&'static str),
Data(Arc<ImageData>),
}
pub struct Image {
data: Arc<ImageData>,
source: ImageSource,
style: ImageStyle,
}
@ -31,9 +36,16 @@ pub struct ImageStyle {
}
impl Image {
pub fn new(data: Arc<ImageData>) -> Self {
pub fn new(asset_path: &'static str) -> Self {
Self {
data,
source: ImageSource::Path(asset_path),
style: Default::default(),
}
}
pub fn from_data(data: Arc<ImageData>) -> Self {
Self {
source: ImageSource::Data(data),
style: Default::default(),
}
}
@ -45,39 +57,53 @@ impl Image {
}
impl Element for Image {
type LayoutState = ();
type LayoutState = Option<Arc<ImageData>>;
type PaintState = ();
fn layout(
&mut self,
constraint: SizeConstraint,
_: &mut LayoutContext,
cx: &mut LayoutContext,
) -> (Vector2F, Self::LayoutState) {
let data = match &self.source {
ImageSource::Path(path) => match cx.asset_cache.png(path) {
Ok(data) => data,
Err(error) => {
log::error!("could not load image: {}", error);
return (Vector2F::zero(), None);
}
},
ImageSource::Data(data) => data.clone(),
};
let desired_size = vec2f(
self.style.width.unwrap_or_else(|| constraint.max.x()),
self.style.height.unwrap_or_else(|| constraint.max.y()),
);
let size = constrain_size_preserving_aspect_ratio(
constraint.constrain(desired_size),
self.data.size().to_f32(),
data.size().to_f32(),
);
(size, ())
(size, Some(data))
}
fn paint(
&mut self,
bounds: RectF,
_: RectF,
_: &mut Self::LayoutState,
layout: &mut Self::LayoutState,
cx: &mut PaintContext,
) -> Self::PaintState {
cx.scene.push_image(scene::Image {
bounds,
border: self.style.border,
corner_radius: self.style.corner_radius,
grayscale: self.style.grayscale,
data: self.data.clone(),
});
if let Some(data) = layout {
cx.scene.push_image(scene::Image {
bounds,
border: self.style.border,
corner_radius: self.style.corner_radius,
grayscale: self.style.grayscale,
data: data.clone(),
});
}
}
fn rect_for_text_range(