Detailed changes
@@ -89,10 +89,6 @@
"top": 7
}
},
- "margin": {
- "bottom": 52,
- "top": 52
- },
"shadow": {
"blur": 16,
"color": "#00000052",
@@ -158,6 +154,13 @@
"right": 8
}
},
+ "modal": {
+ "margin": {
+ "bottom": 52,
+ "top": 52
+ },
+ "cursor": "Arrow"
+ },
"left_sidebar": {
"width": 30,
"background": "#1c1c1c",
@@ -89,10 +89,6 @@
"top": 7
}
},
- "margin": {
- "bottom": 52,
- "top": 52
- },
"shadow": {
"blur": 16,
"color": "#0000001f",
@@ -158,6 +154,13 @@
"right": 8
}
},
+ "modal": {
+ "margin": {
+ "bottom": 52,
+ "top": 52
+ },
+ "cursor": "Arrow"
+ },
"left_sidebar": {
"width": 30,
"background": "#f8f8f8",
@@ -16,6 +16,7 @@ use gpui::{
PathBuilder,
},
json::{self, ToJson},
+ platform::CursorStyle,
text_layout::{self, Line, RunStyle, TextLayoutCache},
AppContext, Axis, Border, Element, ElementBox, Event, EventContext, LayoutContext,
MutableAppContext, PaintContext, Quad, Scene, SizeConstraint, ViewContext, WeakViewHandle,
@@ -329,6 +330,7 @@ impl EditorElement {
let content_origin = bounds.origin() + vec2f(layout.gutter_margin, 0.);
cx.scene.push_layer(Some(bounds));
+ cx.scene.push_cursor_style(bounds, CursorStyle::IBeam);
for (range, color) in &layout.highlighted_ranges {
self.paint_highlighted_range(
@@ -161,29 +161,25 @@ impl View for GoToLine {
self.max_point.row + 1
);
- Align::new(
- ConstrainedBox::new(
- Container::new(
- Flex::new(Axis::Vertical)
- .with_child(
- Container::new(ChildView::new(&self.line_editor).boxed())
- .with_style(theme.input_editor.container)
- .boxed(),
- )
- .with_child(
- Container::new(Label::new(label, theme.empty.label.clone()).boxed())
- .with_style(theme.empty.container)
- .boxed(),
- )
- .boxed(),
- )
- .with_style(theme.container)
- .boxed(),
+ ConstrainedBox::new(
+ Container::new(
+ Flex::new(Axis::Vertical)
+ .with_child(
+ Container::new(ChildView::new(&self.line_editor).boxed())
+ .with_style(theme.input_editor.container)
+ .boxed(),
+ )
+ .with_child(
+ Container::new(Label::new(label, theme.empty.label.clone()).boxed())
+ .with_style(theme.empty.container)
+ .boxed(),
+ )
+ .boxed(),
)
- .with_max_width(500.0)
+ .with_style(theme.container)
.boxed(),
)
- .top()
+ .with_max_width(500.0)
.named("go to line")
}
@@ -4,7 +4,7 @@ use crate::{
elements::ElementBox,
executor::{self, Task},
keymap::{self, Binding, Keystroke},
- platform::{self, CursorStyle, Platform, PromptLevel, WindowOptions},
+ platform::{self, Platform, PromptLevel, WindowOptions},
presenter::Presenter,
util::post_inc,
AssetCache, AssetSource, ClipboardItem, FontCache, PathPromptOptions, TextLayoutCache,
@@ -31,10 +31,7 @@ use std::{
path::{Path, PathBuf},
pin::Pin,
rc::{self, Rc},
- sync::{
- atomic::{AtomicUsize, Ordering::SeqCst},
- Arc, Weak,
- },
+ sync::{Arc, Weak},
time::Duration,
};
@@ -766,7 +763,6 @@ pub struct MutableAppContext {
pending_global_notifications: HashSet<TypeId>,
pending_flushes: usize,
flushing_effects: bool,
- next_cursor_style_handle_id: Arc<AtomicUsize>,
halt_action_dispatch: bool,
}
@@ -818,7 +814,6 @@ impl MutableAppContext {
pending_global_notifications: HashSet::new(),
pending_flushes: 0,
flushing_effects: false,
- next_cursor_style_handle_id: Default::default(),
halt_action_dispatch: false,
}
}
@@ -1949,16 +1944,6 @@ impl MutableAppContext {
self.presenters_and_platform_windows = presenters;
}
- pub fn set_cursor_style(&mut self, style: CursorStyle) -> CursorStyleHandle {
- self.platform.set_cursor_style(style);
- let id = self.next_cursor_style_handle_id.fetch_add(1, SeqCst);
- CursorStyleHandle {
- id,
- next_cursor_style_handle_id: self.next_cursor_style_handle_id.clone(),
- platform: self.platform(),
- }
- }
-
fn handle_subscription_effect(
&mut self,
entity_id: usize,
@@ -4452,20 +4437,6 @@ impl<T> Drop for ElementStateHandle<T> {
}
}
-pub struct CursorStyleHandle {
- id: usize,
- next_cursor_style_handle_id: Arc<AtomicUsize>,
- platform: Arc<dyn Platform>,
-}
-
-impl Drop for CursorStyleHandle {
- fn drop(&mut self) {
- if self.id + 1 == self.next_cursor_style_handle_id.load(SeqCst) {
- self.platform.set_cursor_style(CursorStyle::Arrow);
- }
- }
-}
-
#[must_use]
pub enum Subscription {
Subscription {
@@ -1,17 +1,17 @@
-use pathfinder_geometry::rect::RectF;
-use serde::Deserialize;
-use serde_json::json;
-
use crate::{
color::Color,
geometry::{
deserialize_vec2f,
+ rect::RectF,
vector::{vec2f, Vector2F},
},
json::ToJson,
+ platform::CursorStyle,
scene::{self, Border, Quad},
Element, ElementBox, Event, EventContext, LayoutContext, PaintContext, SizeConstraint,
};
+use serde::Deserialize;
+use serde_json::json;
#[derive(Clone, Copy, Debug, Default, Deserialize)]
pub struct ContainerStyle {
@@ -27,6 +27,8 @@ pub struct ContainerStyle {
pub corner_radius: f32,
#[serde(default)]
pub shadow: Option<Shadow>,
+ #[serde(default)]
+ pub cursor: Option<CursorStyle>,
}
pub struct Container {
@@ -128,6 +130,11 @@ impl Container {
self
}
+ pub fn with_cursor(mut self, style: CursorStyle) -> Self {
+ self.style.cursor = Some(style);
+ self
+ }
+
fn margin_size(&self) -> Vector2F {
vec2f(
self.style.margin.left + self.style.margin.right,
@@ -205,6 +212,10 @@ impl Element for Container {
});
}
+ if let Some(style) = self.style.cursor {
+ cx.scene.push_cursor_style(quad_bounds, style);
+ }
+
let child_origin =
quad_bounds.origin() + vec2f(self.style.padding.left, self.style.padding.top);
@@ -5,8 +5,8 @@ use crate::{
vector::{vec2f, Vector2F},
},
platform::CursorStyle,
- CursorStyleHandle, DebugContext, Element, ElementBox, ElementStateContext, ElementStateHandle,
- Event, EventContext, LayoutContext, PaintContext, SizeConstraint,
+ DebugContext, Element, ElementBox, ElementStateContext, ElementStateHandle, Event,
+ EventContext, LayoutContext, PaintContext, SizeConstraint,
};
use serde_json::json;
@@ -25,7 +25,6 @@ pub struct MouseState {
pub hovered: bool,
pub clicked: bool,
prev_drag_position: Option<Vector2F>,
- cursor_style_handle: Option<CursorStyleHandle>,
}
impl MouseEventHandler {
@@ -72,6 +71,14 @@ impl MouseEventHandler {
self.padding = padding;
self
}
+
+ fn hit_bounds(&self, bounds: RectF) -> RectF {
+ RectF::from_points(
+ bounds.origin() - vec2f(self.padding.left, self.padding.top),
+ bounds.lower_right() + vec2f(self.padding.right, self.padding.bottom),
+ )
+ .round_out()
+ }
}
impl Element for MouseEventHandler {
@@ -93,6 +100,10 @@ impl Element for MouseEventHandler {
_: &mut Self::LayoutState,
cx: &mut PaintContext,
) -> Self::PaintState {
+ if let Some(cursor_style) = self.cursor_style {
+ cx.scene
+ .push_cursor_style(self.hit_bounds(bounds), cursor_style);
+ }
self.child.paint(bounds.origin(), visible_bounds, cx);
}
@@ -105,19 +116,13 @@ impl Element for MouseEventHandler {
_: &mut Self::PaintState,
cx: &mut EventContext,
) -> bool {
- let cursor_style = self.cursor_style;
+ let hit_bounds = self.hit_bounds(visible_bounds);
let mouse_down_handler = self.mouse_down_handler.as_mut();
let click_handler = self.click_handler.as_mut();
let drag_handler = self.drag_handler.as_mut();
let handled_in_child = self.child.dispatch_event(event, cx);
- let hit_bounds = RectF::from_points(
- visible_bounds.origin() - vec2f(self.padding.left, self.padding.top),
- visible_bounds.lower_right() + vec2f(self.padding.right, self.padding.bottom),
- )
- .round_out();
-
self.state.update(cx, |state, cx| match event {
Event::MouseMoved {
position,
@@ -127,16 +132,6 @@ impl Element for MouseEventHandler {
let mouse_in = hit_bounds.contains_point(*position);
if state.hovered != mouse_in {
state.hovered = mouse_in;
- if let Some(cursor_style) = cursor_style {
- if !state.clicked {
- if state.hovered {
- state.cursor_style_handle =
- Some(cx.set_cursor_style(cursor_style));
- } else {
- state.cursor_style_handle = None;
- }
- }
- }
cx.notify();
return true;
}
@@ -160,9 +155,6 @@ impl Element for MouseEventHandler {
state.prev_drag_position = None;
if !handled_in_child && state.clicked {
state.clicked = false;
- if !state.hovered {
- state.cursor_style_handle = None;
- }
cx.notify();
if let Some(handler) = click_handler {
if hit_bounds.contains_point(*position) {
@@ -21,6 +21,7 @@ use anyhow::{anyhow, Result};
use async_task::Runnable;
pub use event::{Event, NavigationDirection};
use postage::oneshot;
+use serde::Deserialize;
use std::{
any::Any,
path::{Path, PathBuf},
@@ -125,11 +126,12 @@ pub enum PromptLevel {
Critical,
}
-#[derive(Copy, Clone, Debug)]
+#[derive(Copy, Clone, Debug, Deserialize)]
pub enum CursorStyle {
Arrow,
ResizeLeftRight,
PointingHand,
+ IBeam,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
@@ -583,6 +583,7 @@ impl platform::Platform for MacPlatform {
CursorStyle::Arrow => msg_send![class!(NSCursor), arrowCursor],
CursorStyle::ResizeLeftRight => msg_send![class!(NSCursor), resizeLeftRightCursor],
CursorStyle::PointingHand => msg_send![class!(NSCursor), pointingHandCursor],
+ CursorStyle::IBeam => msg_send![class!(NSCursor), IBeamCursor],
};
let _: () = msg_send![cursor, set];
}
@@ -4,7 +4,7 @@ use crate::{
font_cache::FontCache,
geometry::rect::RectF,
json::{self, ToJson},
- platform::Event,
+ platform::{CursorStyle, Event},
text_layout::TextLayoutCache,
Action, AnyModelHandle, AnyViewHandle, AnyWeakModelHandle, AssetCache, ElementBox,
ElementStateContext, Entity, FontSystem, ModelHandle, ReadModel, ReadView, Scene,
@@ -22,6 +22,7 @@ pub struct Presenter {
window_id: usize,
pub(crate) rendered_views: HashMap<usize, ElementBox>,
parents: HashMap<usize, usize>,
+ cursor_styles: Vec<(RectF, CursorStyle)>,
font_cache: Arc<FontCache>,
text_layout_cache: TextLayoutCache,
asset_cache: Arc<AssetCache>,
@@ -42,6 +43,7 @@ impl Presenter {
window_id,
rendered_views: cx.render_views(window_id, titlebar_height),
parents: HashMap::new(),
+ cursor_styles: Default::default(),
font_cache,
text_layout_cache,
asset_cache,
@@ -118,6 +120,7 @@ impl Presenter {
RectF::new(Vector2F::zero(), window_size),
);
self.text_layout_cache.finish_frame();
+ self.cursor_styles = scene.cursor_styles();
if let Some(event) = self.last_mouse_moved_event.clone() {
self.dispatch_event(event, cx)
@@ -171,8 +174,21 @@ impl Presenter {
pub fn dispatch_event(&mut self, event: Event, cx: &mut MutableAppContext) {
if let Some(root_view_id) = cx.root_view_id(self.window_id) {
match event {
- Event::MouseMoved { .. } => {
+ Event::MouseMoved {
+ position,
+ left_mouse_down,
+ } => {
self.last_mouse_moved_event = Some(event.clone());
+
+ if !left_mouse_down {
+ cx.platform().set_cursor_style(CursorStyle::Arrow);
+ for (bounds, style) in self.cursor_styles.iter().rev() {
+ if bounds.contains_point(position) {
+ cx.platform().set_cursor_style(*style);
+ break;
+ }
+ }
+ }
}
Event::LeftMouseDragged { position } => {
self.last_mouse_moved_event = Some(Event::MouseMoved {
@@ -7,6 +7,7 @@ use crate::{
fonts::{FontId, GlyphId},
geometry::{rect::RectF, vector::Vector2F},
json::ToJson,
+ platform::CursorStyle,
ImageData,
};
@@ -32,6 +33,7 @@ pub struct Layer {
image_glyphs: Vec<ImageGlyph>,
icons: Vec<Icon>,
paths: Vec<Path>,
+ cursor_styles: Vec<(RectF, CursorStyle)>,
}
#[derive(Default, Debug)]
@@ -173,6 +175,13 @@ impl Scene {
self.stacking_contexts.iter().flat_map(|s| &s.layers)
}
+ pub fn cursor_styles(&self) -> Vec<(RectF, CursorStyle)> {
+ self.layers()
+ .flat_map(|layer| &layer.cursor_styles)
+ .copied()
+ .collect()
+ }
+
pub fn push_stacking_context(&mut self, clip_bounds: Option<RectF>) {
self.active_stacking_context_stack
.push(self.stacking_contexts.len());
@@ -197,6 +206,10 @@ impl Scene {
self.active_layer().push_quad(quad)
}
+ pub fn push_cursor_style(&mut self, bounds: RectF, style: CursorStyle) {
+ self.active_layer().push_cursor_style(bounds, style);
+ }
+
pub fn push_image(&mut self, image: Image) {
self.active_layer().push_image(image)
}
@@ -285,6 +298,7 @@ impl Layer {
glyphs: Default::default(),
icons: Default::default(),
paths: Default::default(),
+ cursor_styles: Default::default(),
}
}
@@ -302,6 +316,14 @@ impl Layer {
self.quads.as_slice()
}
+ fn push_cursor_style(&mut self, bounds: RectF, style: CursorStyle) {
+ if let Some(bounds) = bounds.intersection(self.clip_bounds.unwrap_or(bounds)) {
+ if can_draw(bounds) {
+ self.cursor_styles.push((bounds, style));
+ }
+ }
+ }
+
fn push_underline(&mut self, underline: Underline) {
if underline.width > 0. {
self.underlines.push(underline);
@@ -99,8 +99,6 @@ impl<D: PickerDelegate> View for Picker<D> {
.constrained()
.with_max_width(self.max_size.x())
.with_max_height(self.max_size.y())
- .aligned()
- .top()
.named("picker")
}
@@ -43,6 +43,7 @@ pub struct Workspace {
pub status_bar: StatusBar,
pub toolbar: Toolbar,
pub disconnected_overlay: ContainedText,
+ pub modal: ContainerStyle,
}
#[derive(Clone, Deserialize, Default)]
@@ -1983,7 +1983,14 @@ impl View for Workspace {
content.add_child(self.right_sidebar.render(&theme, cx));
content.boxed()
})
- .with_children(self.modal.as_ref().map(|m| ChildView::new(m).boxed()))
+ .with_children(self.modal.as_ref().map(|m| {
+ ChildView::new(m)
+ .contained()
+ .with_style(theme.workspace.modal)
+ .aligned()
+ .top()
+ .boxed()
+ }))
.flex(1.0, true)
.boxed(),
)
@@ -50,10 +50,6 @@ export default function selectorModal(theme: Theme): Object {
top: 7,
},
},
- margin: {
- bottom: 52,
- top: 52,
- },
shadow: shadow(theme),
};
}
@@ -75,6 +75,13 @@ export default function workspace(theme: Theme) {
leaderBorderWidth: 2.0,
tab,
activeTab,
+ modal: {
+ margin: {
+ bottom: 52,
+ top: 52,
+ },
+ cursor: "Arrow"
+ },
leftSidebar: {
...sidebar,
border: border(theme, "primary", { right: true }),