diff --git a/assets/images/zed-logo-90x90.png b/assets/images/zed-logo-90x90.png new file mode 100644 index 0000000000..17f92d2c1a Binary files /dev/null and b/assets/images/zed-logo-90x90.png differ diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index f9f5738ad2..a16c31595f 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -823,7 +823,7 @@ impl CollabTitlebarItem { avatar_style: AvatarStyle, background_color: Color, ) -> ElementBox { - Image::new(avatar) + Image::from_data(avatar) .with_style(avatar_style.image) .aligned() .contained() diff --git a/crates/collab_ui/src/contact_finder.rs b/crates/collab_ui/src/contact_finder.rs index 98f70e83f0..cb55669ab0 100644 --- a/crates/collab_ui/src/contact_finder.rs +++ b/crates/collab_ui/src/contact_finder.rs @@ -128,7 +128,7 @@ impl PickerDelegate for ContactFinder { .style_for(mouse_state, selected); Flex::row() .with_children(user.avatar.clone().map(|avatar| { - Image::new(avatar) + Image::from_data(avatar) .with_style(theme.contact_finder.contact_avatar) .aligned() .left() diff --git a/crates/collab_ui/src/contact_list.rs b/crates/collab_ui/src/contact_list.rs index 3bb036d336..203d130b5b 100644 --- a/crates/collab_ui/src/contact_list.rs +++ b/crates/collab_ui/src/contact_list.rs @@ -726,7 +726,7 @@ impl ContactList { ) -> ElementBox { Flex::row() .with_children(user.avatar.clone().map(|avatar| { - Image::new(avatar) + Image::from_data(avatar) .with_style(theme.contact_avatar) .aligned() .left() @@ -1080,7 +1080,7 @@ impl ContactList { }; Stack::new() .with_child( - Image::new(avatar) + Image::from_data(avatar) .with_style(theme.contact_avatar) .aligned() .left() @@ -1173,7 +1173,7 @@ impl ContactList { let mut row = Flex::row() .with_children(user.avatar.clone().map(|avatar| { - Image::new(avatar) + Image::from_data(avatar) .with_style(theme.contact_avatar) .aligned() .left() diff --git a/crates/collab_ui/src/incoming_call_notification.rs b/crates/collab_ui/src/incoming_call_notification.rs index a0f54abe38..6fb0278218 100644 --- a/crates/collab_ui/src/incoming_call_notification.rs +++ b/crates/collab_ui/src/incoming_call_notification.rs @@ -108,7 +108,7 @@ impl IncomingCallNotification { .unwrap_or(&default_project); Flex::row() .with_children(self.call.calling_user.avatar.clone().map(|avatar| { - Image::new(avatar) + Image::from_data(avatar) .with_style(theme.caller_avatar) .aligned() .boxed() diff --git a/crates/collab_ui/src/notifications.rs b/crates/collab_ui/src/notifications.rs index 06b6cf2a90..21c2d2c218 100644 --- a/crates/collab_ui/src/notifications.rs +++ b/crates/collab_ui/src/notifications.rs @@ -24,7 +24,7 @@ pub fn render_user_notification( .with_child( Flex::row() .with_children(user.avatar.clone().map(|avatar| { - Image::new(avatar) + Image::from_data(avatar) .with_style(theme.header_avatar) .aligned() .constrained() diff --git a/crates/collab_ui/src/project_shared_notification.rs b/crates/collab_ui/src/project_shared_notification.rs index edf0354eec..b24f3492da 100644 --- a/crates/collab_ui/src/project_shared_notification.rs +++ b/crates/collab_ui/src/project_shared_notification.rs @@ -108,7 +108,7 @@ impl ProjectSharedNotification { let theme = &cx.global::().theme.project_shared_notification; Flex::row() .with_children(self.owner.avatar.clone().map(|avatar| { - Image::new(avatar) + Image::from_data(avatar) .with_style(theme.owner_avatar) .aligned() .boxed() diff --git a/crates/gpui/src/assets.rs b/crates/gpui/src/assets.rs index ac0d72dee9..2170d215af 100644 --- a/crates/gpui/src/assets.rs +++ b/crates/gpui/src/assets.rs @@ -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>; @@ -22,6 +25,7 @@ impl AssetSource for () { pub struct AssetCache { source: Box, svgs: RefCell>, + pngs: RefCell>>, } 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> { + 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) + } + } } diff --git a/crates/gpui/src/elements/image.rs b/crates/gpui/src/elements/image.rs index 37cb01ace8..cc49308e15 100644 --- a/crates/gpui/src/elements/image.rs +++ b/crates/gpui/src/elements/image.rs @@ -11,8 +11,13 @@ use crate::{ use serde::Deserialize; use std::{ops::Range, sync::Arc}; +enum ImageSource { + Path(&'static str), + Data(Arc), +} + pub struct Image { - data: Arc, + source: ImageSource, style: ImageStyle, } @@ -31,9 +36,16 @@ pub struct ImageStyle { } impl Image { - pub fn new(data: Arc) -> 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) -> Self { + Self { + source: ImageSource::Data(data), style: Default::default(), } } @@ -45,39 +57,53 @@ impl Image { } impl Element for Image { - type LayoutState = (); + type LayoutState = Option>; 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( diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index 1cefc558f0..9df6581d20 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/crates/project_panel/src/project_panel.rs @@ -1325,7 +1325,7 @@ impl View for ProjectPanel { Canvas::new(|bounds, _visible_bounds, cx| { cx.scene.push_quad(gpui::Quad { bounds, - background: Some(Color::red()), + background: Some(Color::transparent_black()), ..Default::default() }) }) diff --git a/crates/welcome/src/welcome.rs b/crates/welcome/src/welcome.rs index 7bf6c26302..232fd1bcb7 100644 --- a/crates/welcome/src/welcome.rs +++ b/crates/welcome/src/welcome.rs @@ -1,14 +1,13 @@ use std::borrow::Cow; use gpui::{ - color::Color, - elements::{Canvas, Empty, Flex, Label, MouseEventHandler, ParentElement, Stack, Svg}, + elements::{Canvas, Empty, Flex, Image, Label, MouseEventHandler, ParentElement, Stack}, geometry::rect::RectF, Action, Element, ElementBox, Entity, MouseButton, MouseRegion, MutableAppContext, RenderContext, Subscription, View, ViewContext, }; use settings::{settings_file::SettingsFile, Settings, SettingsFileContent}; -use theme::{CheckboxStyle, ContainedText, Interactive}; +use theme::CheckboxStyle; use workspace::{item::Item, Welcome, Workspace}; pub fn init(cx: &mut MutableAppContext) { @@ -72,15 +71,14 @@ impl View for WelcomePage { .with_children([ Flex::row() .with_children([ - Svg::new("icons/terminal_16.svg") - .with_color(Color::red()) + Image::new("images/zed-logo-90x90.png") .constrained() - .with_width(100.) - .with_height(100.) + .with_width(90.) + .with_height(90.) .aligned() .contained() .boxed(), - Label::new("Zed", theme.editor.hover_popover.prose.clone()).boxed(), + // Label::new("Zed", theme.editor.hover_popover.prose.clone()).boxed(), ]) .boxed(), Label::new(