Render a close tab button on tab hover

Co-Authored-By: Max Brunsfeld <maxbrunsfeld@gmail.com>
This commit is contained in:
Nathan Sobo 2021-04-27 11:58:59 -06:00
parent bb95d58c79
commit eca9f495a1
8 changed files with 96 additions and 71 deletions

View File

@ -12,8 +12,8 @@ pub struct MouseEventHandler {
#[derive(Clone, Copy, Debug, Default)]
pub struct MouseState {
hovered: bool,
clicked: bool,
pub hovered: bool,
pub clicked: bool,
}
impl MouseEventHandler {

View File

@ -1,3 +1,5 @@
use std::borrow::Cow;
use serde_json::json;
use crate::{
@ -11,14 +13,14 @@ use crate::{
};
pub struct Svg {
path: String,
path: Cow<'static, str>,
color: ColorU,
}
impl Svg {
pub fn new(path: String) -> Self {
pub fn new(path: impl Into<Cow<'static, str>>) -> Self {
Self {
path,
path: path.into(),
color: ColorU::black(),
}
}

View File

@ -9,7 +9,7 @@ use crate::{
use etagere::BucketedAtlasAllocator;
use metal::{MTLPixelFormat, TextureDescriptor};
use ordered_float::OrderedFloat;
use std::{collections::HashMap, sync::Arc};
use std::{borrow::Cow, collections::HashMap, sync::Arc};
#[derive(Hash, Eq, PartialEq)]
struct GlyphDescriptor {
@ -29,7 +29,7 @@ pub struct GlyphSprite {
#[derive(Hash, Eq, PartialEq)]
struct IconDescriptor {
path: String,
path: Cow<'static, str>,
width: i32,
height: i32,
}
@ -138,7 +138,7 @@ impl SpriteCache {
pub fn render_icon(
&mut self,
size: Vector2F,
path: String,
path: Cow<'static, str>,
svg: usvg::Tree,
scale_factor: f32,
) -> IconSprite {

View File

@ -1,3 +1,5 @@
use std::borrow::Cow;
use serde_json::json;
use crate::{
@ -51,7 +53,7 @@ pub struct Glyph {
pub struct Icon {
pub bounds: RectF,
pub svg: usvg::Tree,
pub path: String,
pub path: Cow<'static, str>,
pub color: ColorU,
}

View File

3
zed/assets/icons/x.svg Normal file
View File

@ -0,0 +1,3 @@
<svg width="10" height="10" viewBox="0 0 10 10" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M0.720011 0.72003C0.860631 0.57958 1.05126 0.50069 1.25001 0.50069C1.44876 0.50069 1.63938 0.57958 1.78001 0.72003L5.00001 3.94003L8.22001 0.72003C8.28871 0.64634 8.37151 0.58724 8.46351 0.54625C8.55551 0.50526 8.65481 0.48322 8.75551 0.48144C8.85621 0.47966 8.95621 0.49819 9.04961 0.53591C9.14301 0.57363 9.22781 0.62977 9.29901 0.70099C9.37031 0.77221 9.42641 0.85705 9.46411 0.95043C9.50181 1.04382 9.52041 1.14385 9.51861 1.24455C9.51681 1.34526 9.49481 1.44457 9.45381 1.53657C9.41281 1.62857 9.35371 1.71137 9.28001 1.78003L6.06001 5.00003L9.28001 8.22003C9.35371 8.28873 9.41281 8.37153 9.45381 8.46353C9.49481 8.55553 9.51681 8.65483 9.51861 8.75553C9.52041 8.85623 9.50181 8.95623 9.46411 9.04963C9.42641 9.14303 9.37031 9.22783 9.29901 9.29903C9.22781 9.37033 9.14301 9.42643 9.04961 9.46413C8.95621 9.50183 8.85621 9.52043 8.75551 9.51863C8.65481 9.51683 8.55551 9.49483 8.46351 9.45383C8.37151 9.41283 8.28871 9.35373 8.22001 9.28003L5.00001 6.06003L1.78001 9.28003C1.63783 9.41253 1.44978 9.48463 1.25548 9.48123C1.06118 9.47773 0.875801 9.39903 0.738381 9.26163C0.600971 9.12423 0.522261 8.93883 0.518831 8.74453C0.515401 8.55023 0.587531 8.36223 0.720011 8.22003L3.94001 5.00003L0.720011 1.78003C0.579561 1.63941 0.500671 1.44878 0.500671 1.25003C0.500671 1.05128 0.579561 0.86066 0.720011 0.72003Z" fill="#000000"/>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -187,7 +187,7 @@ impl FileFinder {
LineBox::new(
settings.ui_font_family,
settings.ui_font_size,
Svg::new("icons/file-16.svg".into()).boxed(),
Svg::new("icons/file-16.svg").boxed(),
)
.boxed(),
)

View File

@ -183,54 +183,61 @@ impl Pane {
let mut row = Flex::row();
let last_item_ix = self.items.len() - 1;
for (ix, item) in self.items.iter().enumerate() {
let title = item.title(ctx);
let mut border = Border::new(1.0, border_color);
border.left = ix > 0;
border.right = ix == last_item_ix;
border.bottom = ix != self.active_item;
let padding = 6.;
let mut container = Container::new(
Stack::new()
.with_child(
Align::new(
Label::new(title, settings.ui_font_family, settings.ui_font_size)
.boxed(),
)
.boxed(),
)
.with_child(
LineBox::new(
settings.ui_font_family,
settings.ui_font_size,
Align::new(Self::render_modified_icon(item.is_dirty(ctx)))
.right()
.boxed(),
)
.boxed(),
)
.boxed(),
)
.with_vertical_padding(padding)
.with_horizontal_padding(10.)
.with_border(border);
if ix == self.active_item {
container = container
.with_background_color(ColorU::white())
.with_padding_bottom(padding + border.width);
} else {
container = container.with_background_color(ColorU::from_u32(0xeaeaebff));
}
enum Tab {}
row.add_child(
Expanded::new(
1.0,
MouseEventHandler::new::<Tab, _>(item.id(), ctx, |mouse_state| {
log::info!("mouse event handler {:?}", mouse_state);
let title = item.title(ctx);
let mut border = Border::new(1.0, border_color);
border.left = ix > 0;
border.right = ix == last_item_ix;
border.bottom = ix != self.active_item;
let padding = 6.;
let mut container = Container::new(
Stack::new()
.with_child(
Align::new(
Label::new(
title,
settings.ui_font_family,
settings.ui_font_size,
)
.boxed(),
)
.boxed(),
)
.with_child(
LineBox::new(
settings.ui_font_family,
settings.ui_font_size,
Align::new(Self::render_tab_icon(
mouse_state.hovered,
item.is_dirty(ctx),
))
.right()
.boxed(),
)
.boxed(),
)
.boxed(),
)
.with_vertical_padding(padding)
.with_horizontal_padding(10.)
.with_border(border);
if ix == self.active_item {
container = container
.with_background_color(ColorU::white())
.with_padding_bottom(padding + border.width);
} else {
container =
container.with_background_color(ColorU::from_u32(0xeaeaebff));
}
ConstrainedBox::new(
EventHandler::new(container.boxed())
.on_mouse_down(move |ctx| {
@ -290,25 +297,36 @@ impl Pane {
row.named("tabs")
}
fn render_modified_icon(is_modified: bool) -> ElementBox {
let diameter = 8.;
ConstrainedBox::new(
Canvas::new(move |bounds, ctx| {
if is_modified {
let square = RectF::new(bounds.origin(), vec2f(diameter, diameter));
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: diameter / 2.,
});
}
})
.boxed(),
)
.with_width(diameter)
.with_height(diameter)
.named("tab-right-icon")
fn render_tab_icon(tab_hovered: bool, is_modified: bool) -> ElementBox {
let modified_color = ColorU::from_u32(0x556de8ff);
if tab_hovered {
let mut icon = Svg::new("icons/x.svg");
if is_modified {
icon = icon.with_color(modified_color);
}
ConstrainedBox::new(icon.boxed())
.with_width(10.)
.named("close-tab-icon")
} else {
let diameter = 8.;
ConstrainedBox::new(
Canvas::new(move |bounds, ctx| {
if is_modified {
let square = RectF::new(bounds.origin(), vec2f(diameter, diameter));
ctx.scene.push_quad(Quad {
bounds: square,
background: Some(modified_color),
border: Default::default(),
corner_radius: diameter / 2.,
});
}
})
.boxed(),
)
.with_width(diameter)
.with_height(diameter)
.named("unsaved-tab-icon")
}
}
}