Detailed changes
@@ -0,0 +1,73 @@
+use super::Element;
+use crate::PaintContext;
+use pathfinder_geometry::{
+ rect::RectF,
+ vector::{vec2f, Vector2F},
+};
+
+pub struct Canvas<F>(F)
+where
+ F: FnMut(RectF, &mut PaintContext);
+
+impl<F> Canvas<F>
+where
+ F: FnMut(RectF, &mut PaintContext),
+{
+ pub fn new(f: F) -> Self {
+ Self(f)
+ }
+}
+
+impl<F> Element for Canvas<F>
+where
+ F: FnMut(RectF, &mut PaintContext),
+{
+ type LayoutState = ();
+ type PaintState = ();
+
+ fn layout(
+ &mut self,
+ constraint: crate::SizeConstraint,
+ _: &mut crate::LayoutContext,
+ ) -> (Vector2F, Self::LayoutState) {
+ let x = if constraint.max.x().is_finite() {
+ constraint.max.x()
+ } else {
+ constraint.min.x()
+ };
+ let y = if constraint.max.y().is_finite() {
+ constraint.max.y()
+ } else {
+ constraint.min.y()
+ };
+ (vec2f(x, y), ())
+ }
+
+ fn paint(
+ &mut self,
+ bounds: RectF,
+ _: &mut Self::LayoutState,
+ ctx: &mut PaintContext,
+ ) -> Self::PaintState {
+ self.0(bounds, ctx)
+ }
+
+ fn after_layout(
+ &mut self,
+ _: Vector2F,
+ _: &mut Self::LayoutState,
+ _: &mut crate::AfterLayoutContext,
+ ) {
+ }
+
+ fn dispatch_event(
+ &mut self,
+ _: &crate::Event,
+ _: RectF,
+ _: &mut Self::LayoutState,
+ _: &mut Self::PaintState,
+ _: &mut crate::EventContext,
+ ) -> bool {
+ false
+ }
+}
@@ -1,4 +1,5 @@
mod align;
+mod canvas;
mod constrained_box;
mod container;
mod empty;
@@ -13,6 +14,7 @@ mod uniform_list;
pub use crate::presenter::ChildView;
pub use align::*;
+pub use canvas::*;
pub use constrained_box::*;
pub use container::*;
pub use empty::*;
@@ -1181,6 +1181,10 @@ impl workspace::ItemView for BufferView {
fn save(&self, ctx: &mut MutableAppContext) -> Option<Task<Result<()>>> {
self.buffer.update(ctx, |buffer, ctx| buffer.save(ctx))
}
+
+ fn is_modified(&self, ctx: &AppContext) -> bool {
+ self.buffer.as_ref(ctx).is_modified()
+ }
}
impl Selection {
@@ -1,7 +1,11 @@
use super::{ItemViewHandle, SplitDirection};
use crate::{settings::Settings, watch};
use gpui::{
- color::ColorU, elements::*, keymap::Binding, App, AppContext, Border, Entity, View, ViewContext,
+ color::{ColorF, ColorU},
+ elements::*,
+ geometry::{rect::RectF, vector::vec2f},
+ keymap::Binding,
+ App, AppContext, Border, Entity, Quad, View, ViewContext,
};
use std::cmp;
@@ -190,7 +194,32 @@ impl Pane {
let padding = 6.;
let mut container = Container::new(
Align::new(
- Label::new(title, settings.ui_font_family, settings.ui_font_size).boxed(),
+ Flex::row()
+ .with_child(
+ Expanded::new(
+ 1.0,
+ Label::new(title, settings.ui_font_family, settings.ui_font_size)
+ .boxed(),
+ )
+ .boxed(),
+ )
+ .with_child(
+ Expanded::new(
+ 1.0,
+ LineBox::new(
+ settings.ui_font_family,
+ settings.ui_font_size,
+ ConstrainedBox::new(Self::render_modified_icon(
+ item.is_modified(app),
+ ))
+ .with_max_width(12.)
+ .boxed(),
+ )
+ .boxed(),
+ )
+ .boxed(),
+ )
+ .boxed(),
)
.boxed(),
)
@@ -243,6 +272,26 @@ impl Pane {
row.boxed()
}
+
+ fn render_modified_icon(is_modified: bool) -> ElementBox {
+ Canvas::new(move |bounds, ctx| {
+ if is_modified {
+ let padding = if bounds.height() < bounds.width() {
+ vec2f(bounds.width() - bounds.height(), 0.0)
+ } else {
+ vec2f(0.0, bounds.height() - bounds.width())
+ };
+ let square = RectF::new(bounds.origin() + padding / 2., bounds.size() - padding);
+ ctx.scene.push_quad(Quad {
+ bounds: square,
+ background: Some(ColorF::new(0.639, 0.839, 1.0, 1.0).to_u8()),
+ border: Default::default(),
+ corner_radius: square.width() / 2.,
+ });
+ }
+ })
+ .boxed()
+ }
}
impl Entity for Pane {
@@ -22,6 +22,9 @@ pub trait ItemView: View {
{
None
}
+ fn is_modified(&self, _: &AppContext) -> bool {
+ false
+ }
fn save(&self, _: &mut MutableAppContext) -> Option<Task<anyhow::Result<()>>> {
None
}
@@ -35,6 +38,7 @@ pub trait ItemViewHandle: Send + Sync {
fn set_parent_pane(&self, pane: &ViewHandle<Pane>, app: &mut MutableAppContext);
fn id(&self) -> usize;
fn to_any(&self) -> AnyViewHandle;
+ fn is_modified(&self, ctx: &AppContext) -> bool;
fn save(&self, ctx: &mut MutableAppContext) -> Option<Task<anyhow::Result<()>>>;
}
@@ -75,6 +79,10 @@ impl<T: ItemView> ItemViewHandle for ViewHandle<T> {
self.update(ctx, |item, ctx| item.save(ctx.app_mut()))
}
+ fn is_modified(&self, ctx: &AppContext) -> bool {
+ self.as_ref(ctx).is_modified(ctx)
+ }
+
fn id(&self) -> usize {
self.id()
}