mirror of
https://github.com/zed-industries/zed.git
synced 2025-01-01 05:44:17 +00:00
Checkpoint: render SVGs
This commit is contained in:
parent
a1ee2db6d1
commit
4cf2ba20c2
13 changed files with 187 additions and 175 deletions
|
@ -8,9 +8,9 @@ pub use model_context::*;
|
|||
use refineable::Refineable;
|
||||
|
||||
use crate::{
|
||||
current_platform, run_on_main, spawn_on_main, Context, LayoutId, MainThread, MainThreadOnly,
|
||||
Platform, PlatformDispatcher, RootView, TextStyle, TextStyleRefinement, TextSystem, Window,
|
||||
WindowContext, WindowHandle, WindowId,
|
||||
current_platform, run_on_main, spawn_on_main, AssetSource, Context, LayoutId, MainThread,
|
||||
MainThreadOnly, Platform, PlatformDispatcher, RootView, SvgRenderer, TextStyle,
|
||||
TextStyleRefinement, TextSystem, Window, WindowContext, WindowHandle, WindowId,
|
||||
};
|
||||
use anyhow::{anyhow, Result};
|
||||
use collections::{HashMap, VecDeque};
|
||||
|
@ -29,16 +29,18 @@ use util::ResultExt;
|
|||
pub struct App(Arc<Mutex<MainThread<AppContext>>>);
|
||||
|
||||
impl App {
|
||||
pub fn production() -> Self {
|
||||
Self::new(current_platform())
|
||||
pub fn production(asset_source: Arc<dyn AssetSource>) -> Self {
|
||||
Self::new(current_platform(), asset_source)
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "test"))]
|
||||
pub fn test() -> Self {
|
||||
Self::new(Arc::new(super::TestPlatform::new()))
|
||||
let platform = Arc::new(super::TestPlatform::new());
|
||||
let asset_source = Arc::new(());
|
||||
Self::new(platform, asset_source)
|
||||
}
|
||||
|
||||
fn new(platform: Arc<dyn Platform>) -> Self {
|
||||
fn new(platform: Arc<dyn Platform>, asset_source: Arc<dyn AssetSource>) -> Self {
|
||||
let dispatcher = platform.dispatcher();
|
||||
let text_system = Arc::new(TextSystem::new(platform.text_system()));
|
||||
let entities = EntityMap::new();
|
||||
|
@ -49,6 +51,7 @@ impl App {
|
|||
platform: MainThreadOnly::new(platform, dispatcher.clone()),
|
||||
dispatcher,
|
||||
text_system,
|
||||
svg_renderer: SvgRenderer::new(asset_source),
|
||||
pending_updates: 0,
|
||||
text_style_stack: Vec::new(),
|
||||
state_stacks_by_type: HashMap::default(),
|
||||
|
@ -83,6 +86,7 @@ pub struct AppContext {
|
|||
dispatcher: Arc<dyn PlatformDispatcher>,
|
||||
text_system: Arc<TextSystem>,
|
||||
pending_updates: usize,
|
||||
pub(crate) svg_renderer: SvgRenderer,
|
||||
pub(crate) text_style_stack: Vec<TextStyleRefinement>,
|
||||
pub(crate) state_stacks_by_type: HashMap<TypeId, Vec<Box<dyn Any + Send + Sync>>>,
|
||||
pub(crate) unit_entity: Handle<()>,
|
||||
|
|
|
@ -44,6 +44,10 @@ impl ImageData {
|
|||
&self.data
|
||||
}
|
||||
|
||||
pub fn into_bytes(self) -> Vec<u8> {
|
||||
self.data.into_raw()
|
||||
}
|
||||
|
||||
pub fn size(&self) -> Size<DevicePixels> {
|
||||
let (width, height) = self.data.dimensions();
|
||||
size(width.into(), height.into())
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use crate::{Element, Layout, LayoutId, Result, Style, StyleHelpers, Styled};
|
||||
use crate::{Element, Layout, LayoutId, Result, SharedString, Style, StyleHelpers, Styled};
|
||||
use refineable::RefinementCascade;
|
||||
use std::{borrow::Cow, marker::PhantomData};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
pub struct Svg<S> {
|
||||
path: Option<Cow<'static, str>>,
|
||||
path: Option<SharedString>,
|
||||
style: RefinementCascade<Style>,
|
||||
state_type: PhantomData<S>,
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ pub fn svg<S>() -> Svg<S> {
|
|||
}
|
||||
|
||||
impl<S> Svg<S> {
|
||||
pub fn path(mut self, path: impl Into<Cow<'static, str>>) -> Self {
|
||||
pub fn path(mut self, path: impl Into<SharedString>) -> Self {
|
||||
self.path = Some(path.into());
|
||||
self
|
||||
}
|
||||
|
@ -41,28 +41,18 @@ impl<S: 'static> Element for Svg<S> {
|
|||
|
||||
fn paint(
|
||||
&mut self,
|
||||
_layout: Layout,
|
||||
layout: Layout,
|
||||
_: &mut Self::State,
|
||||
_: &mut Self::FrameState,
|
||||
_cx: &mut crate::ViewContext<S>,
|
||||
cx: &mut crate::ViewContext<S>,
|
||||
) -> Result<()>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
// todo!
|
||||
// let fill_color = self.computed_style().fill.and_then(|fill| fill.color());
|
||||
// if let Some((path, fill_color)) = self.path.as_ref().zip(fill_color) {
|
||||
// if let Some(svg_tree) = cx.asset_cache.svg(path).log_err() {
|
||||
// let icon = scene::Icon {
|
||||
// bounds: layout.bounds + parent_origin,
|
||||
// svg: svg_tree,
|
||||
// path: path.clone(),
|
||||
// color: Rgba::from(fill_color).into(),
|
||||
// };
|
||||
|
||||
// cx.scene().push_icon(icon);
|
||||
// }
|
||||
// }
|
||||
let fill_color = self.computed_style().fill.and_then(|fill| fill.color());
|
||||
if let Some((path, fill_color)) = self.path.as_ref().zip(fill_color) {
|
||||
cx.paint_svg(layout.bounds, layout.order, path.clone(), fill_color)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ mod scene;
|
|||
mod style;
|
||||
mod style_helpers;
|
||||
mod styled;
|
||||
mod svg_library;
|
||||
mod svg_renderer;
|
||||
mod taffy;
|
||||
mod text_system;
|
||||
mod util;
|
||||
|
@ -26,7 +26,7 @@ pub use elements::*;
|
|||
pub use executor::*;
|
||||
pub use geometry::*;
|
||||
pub use gpui3_macros::*;
|
||||
pub use svg_library::*;
|
||||
pub use svg_renderer::*;
|
||||
|
||||
pub use platform::*;
|
||||
pub use refineable::*;
|
||||
|
|
|
@ -7,7 +7,7 @@ mod test;
|
|||
|
||||
use crate::{
|
||||
AnyWindowHandle, Bounds, DevicePixels, Font, FontId, FontMetrics, GlyphId, Pixels, Point,
|
||||
RenderGlyphParams, Result, Scene, ShapedLine, SharedString, Size,
|
||||
RenderGlyphParams, RenderSvgParams, Result, Scene, ShapedLine, SharedString, Size,
|
||||
};
|
||||
use anyhow::anyhow;
|
||||
use async_task::Runnable;
|
||||
|
@ -147,7 +147,7 @@ pub trait PlatformWindow {
|
|||
fn is_topmost_for_position(&self, position: Point<Pixels>) -> bool;
|
||||
fn draw(&self, scene: Scene);
|
||||
|
||||
fn glyph_atlas(&self) -> Arc<dyn PlatformAtlas>;
|
||||
fn monochrome_sprite_atlas(&self) -> Arc<dyn PlatformAtlas>;
|
||||
}
|
||||
|
||||
pub trait PlatformDispatcher: Send + Sync {
|
||||
|
@ -178,7 +178,7 @@ pub trait PlatformTextSystem: Send + Sync {
|
|||
#[derive(PartialEq, Eq, Hash, Clone)]
|
||||
pub enum AtlasKey {
|
||||
Glyph(RenderGlyphParams),
|
||||
// Svg(RenderSvgParams),
|
||||
Svg(RenderSvgParams),
|
||||
}
|
||||
|
||||
impl From<RenderGlyphParams> for AtlasKey {
|
||||
|
@ -187,6 +187,12 @@ impl From<RenderGlyphParams> for AtlasKey {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<RenderSvgParams> for AtlasKey {
|
||||
fn from(params: RenderSvgParams) -> Self {
|
||||
Self::Svg(params)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait PlatformAtlas: Send + Sync {
|
||||
fn get_or_insert_with(
|
||||
&self,
|
||||
|
|
|
@ -20,7 +20,7 @@ pub struct MetalRenderer {
|
|||
sprites_pipeline_state: metal::RenderPipelineState,
|
||||
unit_vertices: metal::Buffer,
|
||||
instances: metal::Buffer,
|
||||
glyph_atlas: Arc<MetalAtlas>,
|
||||
monochrome_sprite_atlas: Arc<MetalAtlas>,
|
||||
}
|
||||
|
||||
impl MetalRenderer {
|
||||
|
@ -99,7 +99,7 @@ impl MetalRenderer {
|
|||
);
|
||||
|
||||
let command_queue = device.new_command_queue();
|
||||
let glyph_atlas = Arc::new(MetalAtlas::new(
|
||||
let monochrome_sprite_atlas = Arc::new(MetalAtlas::new(
|
||||
Size {
|
||||
width: DevicePixels(1024),
|
||||
height: DevicePixels(768),
|
||||
|
@ -115,7 +115,7 @@ impl MetalRenderer {
|
|||
sprites_pipeline_state,
|
||||
unit_vertices,
|
||||
instances,
|
||||
glyph_atlas,
|
||||
monochrome_sprite_atlas,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -123,8 +123,8 @@ impl MetalRenderer {
|
|||
&*self.layer
|
||||
}
|
||||
|
||||
pub fn glyph_atlas(&self) -> &Arc<MetalAtlas> {
|
||||
&self.glyph_atlas
|
||||
pub fn monochrome_sprite_atlas(&self) -> &Arc<MetalAtlas> {
|
||||
&self.monochrome_sprite_atlas
|
||||
}
|
||||
|
||||
pub fn draw(&mut self, scene: &mut Scene) {
|
||||
|
@ -277,7 +277,7 @@ impl MetalRenderer {
|
|||
}
|
||||
align_offset(offset);
|
||||
|
||||
let texture = self.glyph_atlas.texture(texture_id);
|
||||
let texture = self.monochrome_sprite_atlas.texture(texture_id);
|
||||
let texture_size = size(
|
||||
DevicePixels(texture.width() as i32),
|
||||
DevicePixels(texture.height() as i32),
|
||||
|
|
|
@ -886,8 +886,8 @@ impl PlatformWindow for MacWindow {
|
|||
}
|
||||
}
|
||||
|
||||
fn glyph_atlas(&self) -> Arc<dyn PlatformAtlas> {
|
||||
self.0.lock().renderer.glyph_atlas().clone()
|
||||
fn monochrome_sprite_atlas(&self) -> Arc<dyn PlatformAtlas> {
|
||||
self.0.lock().renderer.monochrome_sprite_atlas().clone()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,102 +0,0 @@
|
|||
use crate::{AssetSource, DevicePixels, ImageData, IsZero, Result, SharedString, Size};
|
||||
use anyhow::anyhow;
|
||||
use collections::HashMap;
|
||||
use parking_lot::{RwLock, RwLockUpgradableReadGuard};
|
||||
use std::hash::Hash;
|
||||
use std::sync::Arc;
|
||||
use usvg::Tree as SvgTree;
|
||||
|
||||
#[derive(Clone, PartialEq, Hash, Eq)]
|
||||
pub struct SvgRenderParams {
|
||||
path: SharedString,
|
||||
size: Size<DevicePixels>,
|
||||
}
|
||||
|
||||
pub struct SvgRenderer {
|
||||
asset_source: Arc<dyn AssetSource>,
|
||||
trees_by_path: RwLock<HashMap<SharedString, SvgTree>>,
|
||||
rendered: RwLock<HashMap<SvgRenderParams, Arc<ImageData>>>,
|
||||
}
|
||||
|
||||
impl SvgRenderer {
|
||||
pub fn render(&self, params: SvgRenderParams) -> Result<Arc<ImageData>> {
|
||||
if params.size.is_zero() {
|
||||
return Err(anyhow!("can't render at a zero size"));
|
||||
}
|
||||
|
||||
let rendered = self.rendered.upgradable_read();
|
||||
if let Some(image_data) = rendered.get(¶ms) {
|
||||
Ok(image_data.clone())
|
||||
} else {
|
||||
// There's no rendered SVG for the path at the requested size.
|
||||
// Have we already loaded a tree for the path?
|
||||
let trees_by_path = self.trees_by_path.upgradable_read();
|
||||
let tree = if let Some(tree) = trees_by_path.get(¶ms.path) {
|
||||
tree.clone()
|
||||
} else {
|
||||
// Load the tree
|
||||
let bytes = self.asset_source.load(¶ms.path)?;
|
||||
let tree = usvg::Tree::from_data(&bytes, &usvg::Options::default())?;
|
||||
let mut trees_by_path = RwLockUpgradableReadGuard::upgrade(trees_by_path);
|
||||
trees_by_path.insert(params.path.clone(), tree.clone());
|
||||
tree
|
||||
};
|
||||
|
||||
// Render the SVG to a pixmap with the specified width and height.
|
||||
// Convert the pixmap's pixels into an image data and cache it in `rendered`.
|
||||
let mut pixmap =
|
||||
tiny_skia::Pixmap::new(params.size.width.into(), params.size.height.into())
|
||||
.unwrap();
|
||||
resvg::render(
|
||||
&tree,
|
||||
usvg::FitTo::Width(params.size.width.into()),
|
||||
pixmap.as_mut(),
|
||||
);
|
||||
let alpha_mask = pixmap
|
||||
.pixels()
|
||||
.iter()
|
||||
.map(|p| p.alpha())
|
||||
.collect::<Vec<_>>();
|
||||
let mut rendered = RwLockUpgradableReadGuard::upgrade(rendered);
|
||||
let image_data = Arc::new(ImageData::from_raw(params.size, alpha_mask));
|
||||
rendered.insert(params, image_data.clone());
|
||||
|
||||
Ok(image_data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// impl SvgRenderer {
|
||||
// pub fn render_svg(
|
||||
// &mut self,
|
||||
// size: Vector2I,
|
||||
// path: Cow<'static, str>,
|
||||
// svg: usvg::Tree,
|
||||
// ) -> Option<IconSprite> {
|
||||
// let mut pixmap = tiny_skia::Pixmap::new(size.x() as u32, size.y() as u32)?;
|
||||
// resvg::render(&svg, usvg::FitTo::Width(size.x() as u32), pixmap.as_mut());
|
||||
|
||||
// let atlases = &mut self.atlases;
|
||||
// match self.icons.entry(IconDescriptor {
|
||||
// path,
|
||||
// width: size.x(),
|
||||
// height: size.y(),
|
||||
// }) {
|
||||
// Entry::Occupied(entry) => Some(entry.get().clone()),
|
||||
// Entry::Vacant(entry) => {
|
||||
// let mask = pixmap
|
||||
// .pixels()
|
||||
// .iter()
|
||||
// .map(|a| a.alpha())
|
||||
// .collect::<Vec<_>>();
|
||||
// let (alloc_id, atlas_bounds) = atlases.upload(size, &mask)?;
|
||||
// let icon_sprite = IconSprite {
|
||||
// atlas_id: alloc_id.atlas_id,
|
||||
// atlas_origin: atlas_bounds.origin(),
|
||||
// size,
|
||||
// };
|
||||
// Some(entry.insert(icon_sprite).clone())
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
47
crates/gpui3/src/svg_renderer.rs
Normal file
47
crates/gpui3/src/svg_renderer.rs
Normal file
|
@ -0,0 +1,47 @@
|
|||
use crate::{AssetSource, DevicePixels, IsZero, Result, SharedString, Size};
|
||||
use anyhow::anyhow;
|
||||
use std::hash::Hash;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Clone, PartialEq, Hash, Eq)]
|
||||
pub struct RenderSvgParams {
|
||||
pub(crate) path: SharedString,
|
||||
pub(crate) size: Size<DevicePixels>,
|
||||
}
|
||||
|
||||
pub struct SvgRenderer {
|
||||
asset_source: Arc<dyn AssetSource>,
|
||||
}
|
||||
|
||||
impl SvgRenderer {
|
||||
pub fn new(asset_source: Arc<dyn AssetSource>) -> Self {
|
||||
Self { asset_source }
|
||||
}
|
||||
|
||||
pub fn render(&self, params: &RenderSvgParams) -> Result<Vec<u8>> {
|
||||
if params.size.is_zero() {
|
||||
return Err(anyhow!("can't render at a zero size"));
|
||||
}
|
||||
|
||||
// Load the tree.
|
||||
let bytes = self.asset_source.load(¶ms.path)?;
|
||||
let tree = usvg::Tree::from_data(&bytes, &usvg::Options::default())?;
|
||||
|
||||
// Render the SVG to a pixmap with the specified width and height.
|
||||
let mut pixmap =
|
||||
tiny_skia::Pixmap::new(params.size.width.into(), params.size.height.into()).unwrap();
|
||||
resvg::render(
|
||||
&tree,
|
||||
usvg::FitTo::Width(params.size.width.into()),
|
||||
pixmap.as_mut(),
|
||||
);
|
||||
|
||||
// Convert the pixmap's pixels into an alpha mask.
|
||||
let alpha_mask = pixmap
|
||||
.pixels()
|
||||
.iter()
|
||||
.map(|p| p.alpha())
|
||||
.collect::<Vec<_>>();
|
||||
Ok(alpha_mask)
|
||||
}
|
||||
}
|
|
@ -1,9 +1,9 @@
|
|||
use crate::{
|
||||
px, AnyView, AppContext, AvailableSpace, BorrowAppContext, Bounds, Context, Corners, Effect,
|
||||
Element, EntityId, FontId, GlyphId, Handle, Hsla, IsZero, LayerId, LayoutId, MainThread,
|
||||
MainThreadOnly, MonochromeSprite, Pixels, PlatformAtlas, PlatformWindow, Point, Reference,
|
||||
RenderGlyphParams, ScaledPixels, Scene, Size, Style, TaffyLayoutEngine, WeakHandle,
|
||||
WindowOptions, SUBPIXEL_VARIANTS,
|
||||
px, AnyView, AppContext, AvailableSpace, BorrowAppContext, Bounds, Context, Corners,
|
||||
DevicePixels, Effect, Element, EntityId, FontId, GlyphId, Handle, Hsla, IsZero, LayerId,
|
||||
LayoutId, MainThread, MainThreadOnly, MonochromeSprite, Pixels, PlatformAtlas, PlatformWindow,
|
||||
Point, Reference, RenderGlyphParams, RenderSvgParams, ScaledPixels, Scene, SharedString, Size,
|
||||
Style, TaffyLayoutEngine, WeakHandle, WindowOptions, SUBPIXEL_VARIANTS,
|
||||
};
|
||||
use anyhow::Result;
|
||||
use futures::Future;
|
||||
|
@ -16,7 +16,7 @@ pub struct AnyWindow {}
|
|||
pub struct Window {
|
||||
handle: AnyWindowHandle,
|
||||
platform_window: MainThreadOnly<Box<dyn PlatformWindow>>,
|
||||
glyph_atlas: Arc<dyn PlatformAtlas>,
|
||||
monochrome_sprite_atlas: Arc<dyn PlatformAtlas>,
|
||||
rem_size: Pixels,
|
||||
content_size: Size<Pixels>,
|
||||
layout_engine: TaffyLayoutEngine,
|
||||
|
@ -35,7 +35,7 @@ impl Window {
|
|||
cx: &mut MainThread<AppContext>,
|
||||
) -> Self {
|
||||
let platform_window = cx.platform().open_window(handle, options);
|
||||
let glyph_atlas = platform_window.glyph_atlas();
|
||||
let monochrome_sprite_atlas = platform_window.monochrome_sprite_atlas();
|
||||
let mouse_position = platform_window.mouse_position();
|
||||
let content_size = platform_window.content_size();
|
||||
let scale_factor = platform_window.scale_factor();
|
||||
|
@ -58,7 +58,7 @@ impl Window {
|
|||
Window {
|
||||
handle,
|
||||
platform_window,
|
||||
glyph_atlas,
|
||||
monochrome_sprite_atlas,
|
||||
rem_size: px(16.),
|
||||
content_size,
|
||||
layout_engine: TaffyLayoutEngine::new(),
|
||||
|
@ -235,7 +235,7 @@ impl<'a, 'w> WindowContext<'a, 'w> {
|
|||
let layer_id = self.current_layer_id();
|
||||
let tile = self
|
||||
.window
|
||||
.glyph_atlas
|
||||
.monochrome_sprite_atlas
|
||||
.get_or_insert_with(¶ms.clone().into(), &mut || {
|
||||
self.text_system().rasterize_glyph(¶ms)
|
||||
})?;
|
||||
|
@ -259,6 +259,47 @@ impl<'a, 'w> WindowContext<'a, 'w> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn paint_svg(
|
||||
&mut self,
|
||||
bounds: Bounds<Pixels>,
|
||||
order: u32,
|
||||
path: SharedString,
|
||||
color: Hsla,
|
||||
) -> Result<()> {
|
||||
let scale_factor = self.scale_factor();
|
||||
let bounds = bounds.scale(scale_factor);
|
||||
// Render the SVG at twice the size to get a higher quality result.
|
||||
let params = RenderSvgParams {
|
||||
path,
|
||||
size: bounds
|
||||
.size
|
||||
.map(|pixels| DevicePixels::from((pixels.0 * 2.).ceil() as i32)),
|
||||
};
|
||||
|
||||
let layer_id = self.current_layer_id();
|
||||
let tile = self.window.monochrome_sprite_atlas.get_or_insert_with(
|
||||
¶ms.clone().into(),
|
||||
&mut || {
|
||||
let bytes = self.svg_renderer.render(¶ms)?;
|
||||
Ok((params.size, bytes))
|
||||
},
|
||||
)?;
|
||||
let content_mask = self.content_mask().scale(scale_factor);
|
||||
|
||||
self.window.scene.insert(
|
||||
layer_id,
|
||||
MonochromeSprite {
|
||||
order,
|
||||
bounds,
|
||||
content_mask,
|
||||
color,
|
||||
tile,
|
||||
},
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn draw(&mut self) -> Result<()> {
|
||||
let unit_entity = self.unit_entity.clone();
|
||||
self.update_entity(&unit_entity, |_, cx| {
|
||||
|
|
30
crates/storybook2/src/assets.rs
Normal file
30
crates/storybook2/src/assets.rs
Normal file
|
@ -0,0 +1,30 @@
|
|||
use std::borrow::Cow;
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use gpui3::{AssetSource, SharedString};
|
||||
use rust_embed::RustEmbed;
|
||||
|
||||
#[derive(RustEmbed)]
|
||||
#[folder = "../../assets"]
|
||||
#[include = "fonts/**/*"]
|
||||
#[include = "icons/**/*"]
|
||||
#[include = "themes/**/*"]
|
||||
#[include = "sounds/**/*"]
|
||||
#[include = "*.md"]
|
||||
#[exclude = "*.DS_Store"]
|
||||
pub struct Assets;
|
||||
|
||||
impl AssetSource for Assets {
|
||||
fn load(&self, path: &SharedString) -> Result<Cow<[u8]>> {
|
||||
Self::get(path.as_ref())
|
||||
.map(|f| f.data)
|
||||
.ok_or_else(|| anyhow!("could not find asset at path \"{}\"", path))
|
||||
}
|
||||
|
||||
fn list(&self, path: &SharedString) -> Result<Vec<SharedString>> {
|
||||
Ok(Self::iter()
|
||||
.filter(|p| p.starts_with(path.as_ref()))
|
||||
.map(SharedString::from)
|
||||
.collect())
|
||||
}
|
||||
}
|
|
@ -1,9 +1,13 @@
|
|||
#![allow(dead_code, unused_variables)]
|
||||
|
||||
use assets::Assets;
|
||||
use gpui3::{px, size, Bounds, WindowBounds, WindowOptions};
|
||||
use log::LevelFilter;
|
||||
use simplelog::SimpleLogger;
|
||||
use std::sync::Arc;
|
||||
use workspace::workspace;
|
||||
|
||||
mod assets;
|
||||
mod collab_panel;
|
||||
mod theme;
|
||||
mod themes;
|
||||
|
@ -19,7 +23,8 @@ fn main() {
|
|||
|
||||
SimpleLogger::init(LevelFilter::Info, Default::default()).expect("could not initialize logger");
|
||||
|
||||
gpui3::App::production().run(|cx| {
|
||||
let asset_source = Arc::new(Assets);
|
||||
gpui3::App::production(asset_source).run(|cx| {
|
||||
let window = cx.open_window(
|
||||
WindowOptions {
|
||||
bounds: WindowBounds::Fixed(Bounds {
|
||||
|
@ -35,29 +40,6 @@ fn main() {
|
|||
});
|
||||
}
|
||||
|
||||
use rust_embed::RustEmbed;
|
||||
use workspace::workspace;
|
||||
|
||||
#[derive(RustEmbed)]
|
||||
#[folder = "../../assets"]
|
||||
#[include = "themes/**/*"]
|
||||
#[include = "fonts/**/*"]
|
||||
#[include = "icons/**/*"]
|
||||
#[exclude = "*.DS_Store"]
|
||||
pub struct Assets;
|
||||
|
||||
// impl AssetSource for Assets {
|
||||
// fn load(&self, path: &str) -> Result<std::borrow::Cow<[u8]>> {
|
||||
// Self::get(path)
|
||||
// .map(|f| f.data)
|
||||
// .ok_or_else(|| anyhow!("could not find asset at path \"{}\"", path))
|
||||
// }
|
||||
|
||||
// fn list(&self, path: &str) -> Vec<std::borrow::Cow<'static, str>> {
|
||||
// Self::iter().filter(|p| p.starts_with(path)).collect()
|
||||
// }
|
||||
// }
|
||||
|
||||
// fn load_embedded_fonts(platform: &dyn gpui2::Platform) {
|
||||
// let font_paths = Assets.list("fonts");
|
||||
// let mut embedded_fonts = Vec::new();
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use std::{
|
||||
borrow::Cow,
|
||||
fmt::{self, Debug},
|
||||
sync::Arc,
|
||||
};
|
||||
|
@ -47,6 +48,15 @@ impl From<String> for ArcCow<'_, str> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> From<Cow<'a, str>> for ArcCow<'a, str> {
|
||||
fn from(value: Cow<'a, str>) -> Self {
|
||||
match value {
|
||||
Cow::Borrowed(borrowed) => Self::Borrowed(borrowed),
|
||||
Cow::Owned(owned) => Self::Owned(owned.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: ?Sized + ToOwned> std::borrow::Borrow<T> for ArcCow<'a, T> {
|
||||
fn borrow(&self) -> &T {
|
||||
match self {
|
||||
|
|
Loading…
Reference in a new issue