Detailed changes
@@ -9,7 +9,7 @@ use crate::{
};
use anyhow::{anyhow, Result};
use keymap::MatchResult;
-use parking_lot::Mutex;
+use parking_lot::{Mutex, RwLock};
use pathfinder_geometry::{rect::RectF, vector::vec2f};
use platform::Event;
use postage::{sink::Sink as _, stream::Stream as _};
@@ -900,7 +900,7 @@ impl MutableAppContext {
}
}
- let mut values = self.ctx.values.lock();
+ let mut values = self.ctx.values.write();
for key in dropped_values {
values.remove(&key);
}
@@ -1322,7 +1322,7 @@ impl AsRef<AppContext> for MutableAppContext {
pub struct AppContext {
models: HashMap<usize, Box<dyn AnyModel>>,
windows: HashMap<usize, Window>,
- values: Mutex<HashMap<(TypeId, usize), Box<dyn Any>>>,
+ values: RwLock<HashMap<(TypeId, usize), Box<dyn Any>>>,
background: Arc<executor::Background>,
ref_counts: Arc<Mutex<RefCounts>>,
thread_pool: scoped_pool::Pool,
@@ -1376,7 +1376,7 @@ impl AppContext {
pub fn value<Tag: 'static, T: 'static + Default>(&self, id: usize) -> ValueHandle<T> {
let key = (TypeId::of::<Tag>(), id);
- let mut values = self.values.lock();
+ let mut values = self.values.write();
values.entry(key).or_insert_with(|| Box::new(T::default()));
ValueHandle::new(TypeId::of::<Tag>(), id, &self.ref_counts)
}
@@ -2387,10 +2387,20 @@ impl<T: 'static> ValueHandle<T> {
}
}
- pub fn map<R>(&self, ctx: &AppContext, f: impl FnOnce(&mut T) -> R) -> R {
+ pub fn read<R>(&self, ctx: &AppContext, f: impl FnOnce(&T) -> R) -> R {
f(ctx
.values
- .lock()
+ .read()
+ .get(&(self.tag_type_id, self.id))
+ .unwrap()
+ .downcast_ref()
+ .unwrap())
+ }
+
+ pub fn update<R>(&self, ctx: &AppContext, f: impl FnOnce(&mut T) -> R) -> R {
+ f(ctx
+ .values
+ .write()
.get_mut(&(self.tag_type_id, self.id))
.unwrap()
.downcast_mut()
@@ -22,9 +22,13 @@ impl MouseEventHandler {
Tag: 'static,
F: FnOnce(MouseState) -> ElementBox,
{
- let state = ctx.value::<Tag, _>(id);
- let child = state.map(ctx, |state| render_child(*state));
- Self { state, child }
+ let state_handle = ctx.value::<Tag, _>(id);
+ let state = state_handle.read(ctx, |state| *state);
+ let child = render_child(state);
+ Self {
+ state: state_handle,
+ child,
+ }
}
}
@@ -68,7 +72,7 @@ impl Element for MouseEventHandler {
) -> bool {
let handled_in_child = self.child.dispatch_event(event, ctx);
- self.state.map(ctx.app, |state| match event {
+ self.state.update(ctx.app, |state| match event {
Event::MouseMoved { position } => {
let mouse_in = bounds.contains_point(*position);
if state.hovered != mouse_in {
@@ -510,7 +510,7 @@ impl Renderer {
);
// Snap sprite to pixel grid.
- let origin = (icon.bounds.origin() * scene.scale_factor()).floor();
+ let origin = (icon.bounds.origin() * scene.scale_factor()); //.floor();
sprites_by_atlas
.entry(sprite.atlas_id)
.or_insert_with(Vec::new)
@@ -49,7 +49,8 @@ typedef enum {
typedef struct {
vector_float2 origin;
- vector_float2 size;
+ vector_float2 target_size;
+ vector_float2 source_size;
vector_float2 atlas_origin;
vector_uchar4 color;
uint8_t compute_winding;
@@ -186,9 +186,9 @@ vertex SpriteFragmentInput sprite_vertex(
) {
float2 unit_vertex = unit_vertices[unit_vertex_id];
GPUISprite sprite = sprites[sprite_id];
- float2 position = unit_vertex * sprite.size + sprite.origin;
+ float2 position = unit_vertex * sprite.target_size + sprite.origin;
float4 device_position = to_device_position(position, *viewport_size);
- float2 atlas_position = (unit_vertex * sprite.size + sprite.atlas_origin) / *atlas_size;
+ float2 atlas_position = (unit_vertex * sprite.source_size + sprite.atlas_origin) / *atlas_size;
return SpriteFragmentInput {
device_position,
@@ -140,8 +140,23 @@ impl SpriteCache {
size: Vector2F,
path: Cow<'static, str>,
svg: usvg::Tree,
+ target_position: Vector2F,
scale_factor: f32,
) -> IconSprite {
+ const SUBPIXEL_VARIANTS: u8 = 4;
+
+ let target_position = target_position * scale_factor;
+ let subpixel_variant = (
+ (target_position.x().fract() * SUBPIXEL_VARIANTS as f32).round() as u8
+ % SUBPIXEL_VARIANTS,
+ (target_position.y().fract() * SUBPIXEL_VARIANTS as f32).round() as u8
+ % SUBPIXEL_VARIANTS,
+ );
+ let subpixel_shift = vec2f(
+ subpixel_variant.0 as f32 / SUBPIXEL_VARIANTS as f32,
+ subpixel_variant.1 as f32 / SUBPIXEL_VARIANTS as f32,
+ );
+
let atlases = &mut self.atlases;
let atlas_size = self.atlas_size;
let device = &self.device;
@@ -215,9 +215,11 @@ impl Pane {
)
.with_child(
Align::new(Self::render_tab_icon(
+ item.id(),
line_height - 2.,
mouse_state.hovered,
item.is_dirty(ctx),
+ ctx,
))
.right()
.boxed(),
@@ -281,14 +283,33 @@ impl Pane {
.named("tabs")
}
- fn render_tab_icon(close_icon_size: f32, tab_hovered: bool, is_modified: bool) -> ElementBox {
+ fn render_tab_icon(
+ item_id: usize,
+ close_icon_size: f32,
+ tab_hovered: bool,
+ is_modified: bool,
+ ctx: &AppContext,
+ ) -> ElementBox {
+ enum TabCloseButton {}
+
let modified_color = ColorU::from_u32(0x556de8ff);
let icon = if tab_hovered {
let mut icon = Svg::new("icons/x.svg");
- if is_modified {
- icon = icon.with_color(modified_color);
- }
- icon.named("close-tab-icon")
+
+ MouseEventHandler::new::<TabCloseButton, _>(item_id, ctx, |mouse_state| {
+ if mouse_state.hovered {
+ Container::new(icon.with_color(ColorU::white()).boxed())
+ .with_background_color(modified_color)
+ .with_corner_radius(close_icon_size / 2.)
+ .boxed()
+ } else {
+ if is_modified {
+ icon = icon.with_color(modified_color);
+ }
+ icon.boxed()
+ }
+ })
+ .named("close-tab-icon")
} else {
let diameter = 8.;
ConstrainedBox::new(