mirror of
https://github.com/zed-industries/zed.git
synced 2025-01-24 02:46:43 +00:00
Add png image loading to gpui
add zed logo into welcome experience Co-authored-by: Nathan <nathan@zed.dev>
This commit is contained in:
parent
f89f33347d
commit
4c179875ab
11 changed files with 76 additions and 33 deletions
BIN
assets/images/zed-logo-90x90.png
Normal file
BIN
assets/images/zed-logo-90x90.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
|
@ -823,7 +823,7 @@ impl CollabTitlebarItem {
|
||||||
avatar_style: AvatarStyle,
|
avatar_style: AvatarStyle,
|
||||||
background_color: Color,
|
background_color: Color,
|
||||||
) -> ElementBox {
|
) -> ElementBox {
|
||||||
Image::new(avatar)
|
Image::from_data(avatar)
|
||||||
.with_style(avatar_style.image)
|
.with_style(avatar_style.image)
|
||||||
.aligned()
|
.aligned()
|
||||||
.contained()
|
.contained()
|
||||||
|
|
|
@ -128,7 +128,7 @@ impl PickerDelegate for ContactFinder {
|
||||||
.style_for(mouse_state, selected);
|
.style_for(mouse_state, selected);
|
||||||
Flex::row()
|
Flex::row()
|
||||||
.with_children(user.avatar.clone().map(|avatar| {
|
.with_children(user.avatar.clone().map(|avatar| {
|
||||||
Image::new(avatar)
|
Image::from_data(avatar)
|
||||||
.with_style(theme.contact_finder.contact_avatar)
|
.with_style(theme.contact_finder.contact_avatar)
|
||||||
.aligned()
|
.aligned()
|
||||||
.left()
|
.left()
|
||||||
|
|
|
@ -726,7 +726,7 @@ impl ContactList {
|
||||||
) -> ElementBox {
|
) -> ElementBox {
|
||||||
Flex::row()
|
Flex::row()
|
||||||
.with_children(user.avatar.clone().map(|avatar| {
|
.with_children(user.avatar.clone().map(|avatar| {
|
||||||
Image::new(avatar)
|
Image::from_data(avatar)
|
||||||
.with_style(theme.contact_avatar)
|
.with_style(theme.contact_avatar)
|
||||||
.aligned()
|
.aligned()
|
||||||
.left()
|
.left()
|
||||||
|
@ -1080,7 +1080,7 @@ impl ContactList {
|
||||||
};
|
};
|
||||||
Stack::new()
|
Stack::new()
|
||||||
.with_child(
|
.with_child(
|
||||||
Image::new(avatar)
|
Image::from_data(avatar)
|
||||||
.with_style(theme.contact_avatar)
|
.with_style(theme.contact_avatar)
|
||||||
.aligned()
|
.aligned()
|
||||||
.left()
|
.left()
|
||||||
|
@ -1173,7 +1173,7 @@ impl ContactList {
|
||||||
|
|
||||||
let mut row = Flex::row()
|
let mut row = Flex::row()
|
||||||
.with_children(user.avatar.clone().map(|avatar| {
|
.with_children(user.avatar.clone().map(|avatar| {
|
||||||
Image::new(avatar)
|
Image::from_data(avatar)
|
||||||
.with_style(theme.contact_avatar)
|
.with_style(theme.contact_avatar)
|
||||||
.aligned()
|
.aligned()
|
||||||
.left()
|
.left()
|
||||||
|
|
|
@ -108,7 +108,7 @@ impl IncomingCallNotification {
|
||||||
.unwrap_or(&default_project);
|
.unwrap_or(&default_project);
|
||||||
Flex::row()
|
Flex::row()
|
||||||
.with_children(self.call.calling_user.avatar.clone().map(|avatar| {
|
.with_children(self.call.calling_user.avatar.clone().map(|avatar| {
|
||||||
Image::new(avatar)
|
Image::from_data(avatar)
|
||||||
.with_style(theme.caller_avatar)
|
.with_style(theme.caller_avatar)
|
||||||
.aligned()
|
.aligned()
|
||||||
.boxed()
|
.boxed()
|
||||||
|
|
|
@ -24,7 +24,7 @@ pub fn render_user_notification<V: View, A: Action + Clone>(
|
||||||
.with_child(
|
.with_child(
|
||||||
Flex::row()
|
Flex::row()
|
||||||
.with_children(user.avatar.clone().map(|avatar| {
|
.with_children(user.avatar.clone().map(|avatar| {
|
||||||
Image::new(avatar)
|
Image::from_data(avatar)
|
||||||
.with_style(theme.header_avatar)
|
.with_style(theme.header_avatar)
|
||||||
.aligned()
|
.aligned()
|
||||||
.constrained()
|
.constrained()
|
||||||
|
|
|
@ -108,7 +108,7 @@ impl ProjectSharedNotification {
|
||||||
let theme = &cx.global::<Settings>().theme.project_shared_notification;
|
let theme = &cx.global::<Settings>().theme.project_shared_notification;
|
||||||
Flex::row()
|
Flex::row()
|
||||||
.with_children(self.owner.avatar.clone().map(|avatar| {
|
.with_children(self.owner.avatar.clone().map(|avatar| {
|
||||||
Image::new(avatar)
|
Image::from_data(avatar)
|
||||||
.with_style(theme.owner_avatar)
|
.with_style(theme.owner_avatar)
|
||||||
.aligned()
|
.aligned()
|
||||||
.boxed()
|
.boxed()
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
use anyhow::{anyhow, Result};
|
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 {
|
pub trait AssetSource: 'static + Send + Sync {
|
||||||
fn load(&self, path: &str) -> Result<Cow<[u8]>>;
|
fn load(&self, path: &str) -> Result<Cow<[u8]>>;
|
||||||
|
@ -22,6 +25,7 @@ impl AssetSource for () {
|
||||||
pub struct AssetCache {
|
pub struct AssetCache {
|
||||||
source: Box<dyn AssetSource>,
|
source: Box<dyn AssetSource>,
|
||||||
svgs: RefCell<HashMap<String, usvg::Tree>>,
|
svgs: RefCell<HashMap<String, usvg::Tree>>,
|
||||||
|
pngs: RefCell<HashMap<String, Arc<ImageData>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AssetCache {
|
impl AssetCache {
|
||||||
|
@ -29,6 +33,7 @@ impl AssetCache {
|
||||||
Self {
|
Self {
|
||||||
source: Box::new(source),
|
source: Box::new(source),
|
||||||
svgs: RefCell::new(HashMap::new()),
|
svgs: RefCell::new(HashMap::new()),
|
||||||
|
pngs: RefCell::new(HashMap::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,4 +48,18 @@ impl AssetCache {
|
||||||
Ok(svg)
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,8 +11,13 @@ use crate::{
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::{ops::Range, sync::Arc};
|
use std::{ops::Range, sync::Arc};
|
||||||
|
|
||||||
|
enum ImageSource {
|
||||||
|
Path(&'static str),
|
||||||
|
Data(Arc<ImageData>),
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Image {
|
pub struct Image {
|
||||||
data: Arc<ImageData>,
|
source: ImageSource,
|
||||||
style: ImageStyle,
|
style: ImageStyle,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,9 +36,16 @@ pub struct ImageStyle {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Image {
|
impl Image {
|
||||||
pub fn new(data: Arc<ImageData>) -> Self {
|
pub fn new(asset_path: &'static str) -> Self {
|
||||||
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(),
|
style: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,39 +57,53 @@ impl Image {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Element for Image {
|
impl Element for Image {
|
||||||
type LayoutState = ();
|
type LayoutState = Option<Arc<ImageData>>;
|
||||||
type PaintState = ();
|
type PaintState = ();
|
||||||
|
|
||||||
fn layout(
|
fn layout(
|
||||||
&mut self,
|
&mut self,
|
||||||
constraint: SizeConstraint,
|
constraint: SizeConstraint,
|
||||||
_: &mut LayoutContext,
|
cx: &mut LayoutContext,
|
||||||
) -> (Vector2F, Self::LayoutState) {
|
) -> (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(
|
let desired_size = vec2f(
|
||||||
self.style.width.unwrap_or_else(|| constraint.max.x()),
|
self.style.width.unwrap_or_else(|| constraint.max.x()),
|
||||||
self.style.height.unwrap_or_else(|| constraint.max.y()),
|
self.style.height.unwrap_or_else(|| constraint.max.y()),
|
||||||
);
|
);
|
||||||
let size = constrain_size_preserving_aspect_ratio(
|
let size = constrain_size_preserving_aspect_ratio(
|
||||||
constraint.constrain(desired_size),
|
constraint.constrain(desired_size),
|
||||||
self.data.size().to_f32(),
|
data.size().to_f32(),
|
||||||
);
|
);
|
||||||
(size, ())
|
|
||||||
|
(size, Some(data))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint(
|
fn paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
bounds: RectF,
|
bounds: RectF,
|
||||||
_: RectF,
|
_: RectF,
|
||||||
_: &mut Self::LayoutState,
|
layout: &mut Self::LayoutState,
|
||||||
cx: &mut PaintContext,
|
cx: &mut PaintContext,
|
||||||
) -> Self::PaintState {
|
) -> Self::PaintState {
|
||||||
cx.scene.push_image(scene::Image {
|
if let Some(data) = layout {
|
||||||
bounds,
|
cx.scene.push_image(scene::Image {
|
||||||
border: self.style.border,
|
bounds,
|
||||||
corner_radius: self.style.corner_radius,
|
border: self.style.border,
|
||||||
grayscale: self.style.grayscale,
|
corner_radius: self.style.corner_radius,
|
||||||
data: self.data.clone(),
|
grayscale: self.style.grayscale,
|
||||||
});
|
data: data.clone(),
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rect_for_text_range(
|
fn rect_for_text_range(
|
||||||
|
|
|
@ -1325,7 +1325,7 @@ impl View for ProjectPanel {
|
||||||
Canvas::new(|bounds, _visible_bounds, cx| {
|
Canvas::new(|bounds, _visible_bounds, cx| {
|
||||||
cx.scene.push_quad(gpui::Quad {
|
cx.scene.push_quad(gpui::Quad {
|
||||||
bounds,
|
bounds,
|
||||||
background: Some(Color::red()),
|
background: Some(Color::transparent_black()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,14 +1,13 @@
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use gpui::{
|
use gpui::{
|
||||||
color::Color,
|
elements::{Canvas, Empty, Flex, Image, Label, MouseEventHandler, ParentElement, Stack},
|
||||||
elements::{Canvas, Empty, Flex, Label, MouseEventHandler, ParentElement, Stack, Svg},
|
|
||||||
geometry::rect::RectF,
|
geometry::rect::RectF,
|
||||||
Action, Element, ElementBox, Entity, MouseButton, MouseRegion, MutableAppContext,
|
Action, Element, ElementBox, Entity, MouseButton, MouseRegion, MutableAppContext,
|
||||||
RenderContext, Subscription, View, ViewContext,
|
RenderContext, Subscription, View, ViewContext,
|
||||||
};
|
};
|
||||||
use settings::{settings_file::SettingsFile, Settings, SettingsFileContent};
|
use settings::{settings_file::SettingsFile, Settings, SettingsFileContent};
|
||||||
use theme::{CheckboxStyle, ContainedText, Interactive};
|
use theme::CheckboxStyle;
|
||||||
use workspace::{item::Item, Welcome, Workspace};
|
use workspace::{item::Item, Welcome, Workspace};
|
||||||
|
|
||||||
pub fn init(cx: &mut MutableAppContext) {
|
pub fn init(cx: &mut MutableAppContext) {
|
||||||
|
@ -72,15 +71,14 @@ impl View for WelcomePage {
|
||||||
.with_children([
|
.with_children([
|
||||||
Flex::row()
|
Flex::row()
|
||||||
.with_children([
|
.with_children([
|
||||||
Svg::new("icons/terminal_16.svg")
|
Image::new("images/zed-logo-90x90.png")
|
||||||
.with_color(Color::red())
|
|
||||||
.constrained()
|
.constrained()
|
||||||
.with_width(100.)
|
.with_width(90.)
|
||||||
.with_height(100.)
|
.with_height(90.)
|
||||||
.aligned()
|
.aligned()
|
||||||
.contained()
|
.contained()
|
||||||
.boxed(),
|
.boxed(),
|
||||||
Label::new("Zed", theme.editor.hover_popover.prose.clone()).boxed(),
|
// Label::new("Zed", theme.editor.hover_popover.prose.clone()).boxed(),
|
||||||
])
|
])
|
||||||
.boxed(),
|
.boxed(),
|
||||||
Label::new(
|
Label::new(
|
||||||
|
|
Loading…
Reference in a new issue