Detailed changes
@@ -472,13 +472,27 @@ pub enum PromptLevel {
Critical,
}
+/// The style of the cursor (pointer)
#[derive(Copy, Clone, Debug)]
pub enum CursorStyle {
Arrow,
+ IBeam,
+ Crosshair,
+ ClosedHand,
+ OpenHand,
+ PointingHand,
+ ResizeLeft,
+ ResizeRight,
ResizeLeftRight,
+ ResizeUp,
+ ResizeDown,
ResizeUpDown,
- PointingHand,
- IBeam,
+ DisappearingItem,
+ IBeamCursorForVerticalLayout,
+ OperationNotAllowed,
+ DragLink,
+ DragCopy,
+ ContextualMenu,
}
impl Default for CursorStyle {
@@ -724,16 +724,35 @@ impl Platform for MacPlatform {
}
}
+ /// Match cursor style to one of the styles available
+ /// in macOS's [NSCursor](https://developer.apple.com/documentation/appkit/nscursor).
fn set_cursor_style(&self, style: CursorStyle) {
unsafe {
let new_cursor: id = match style {
CursorStyle::Arrow => msg_send![class!(NSCursor), arrowCursor],
- CursorStyle::ResizeLeftRight => {
- msg_send![class!(NSCursor), resizeLeftRightCursor]
- }
- CursorStyle::ResizeUpDown => msg_send![class!(NSCursor), resizeUpDownCursor],
- CursorStyle::PointingHand => msg_send![class!(NSCursor), pointingHandCursor],
CursorStyle::IBeam => msg_send![class!(NSCursor), IBeamCursor],
+ CursorStyle::Crosshair => msg_send![class!(NSCursor), crosshairCursor],
+ CursorStyle::ClosedHand => msg_send![class!(NSCursor), closedHandCursor],
+ CursorStyle::OpenHand => msg_send![class!(NSCursor), openHandCursor],
+ CursorStyle::PointingHand => msg_send![class!(NSCursor), pointingHandCursor],
+ CursorStyle::ResizeLeft => msg_send![class!(NSCursor), resizeLeftCursor],
+ CursorStyle::ResizeRight => msg_send![class!(NSCursor), resizeRightCursor],
+ CursorStyle::ResizeLeftRight => msg_send![class!(NSCursor), resizeLeftRightCursor],
+ CursorStyle::ResizeUp => msg_send![class!(NSCursor), resizeUpCursor],
+ CursorStyle::ResizeDown => msg_send![class!(NSCursor), resizeDownCursor],
+ CursorStyle::ResizeUpDown => msg_send![class!(NSCursor), resizeUpDownCursor],
+ CursorStyle::DisappearingItem => {
+ msg_send![class!(NSCursor), disappearingItemCursor]
+ }
+ CursorStyle::IBeamCursorForVerticalLayout => {
+ msg_send![class!(NSCursor), IBeamCursorForVerticalLayout]
+ }
+ CursorStyle::OperationNotAllowed => {
+ msg_send![class!(NSCursor), operationNotAllowedCursor]
+ }
+ CursorStyle::DragLink => msg_send![class!(NSCursor), dragLinkCursor],
+ CursorStyle::DragCopy => msg_send![class!(NSCursor), dragCopyCursor],
+ CursorStyle::ContextualMenu => msg_send![class!(NSCursor), contextualMenuCursor],
};
let old_cursor: id = msg_send![class!(NSCursor), currentCursor];
@@ -101,6 +101,125 @@ pub trait Styled: Sized {
self
}
+ /// Sets cursor style when hovering over an element to `text`.
+ /// [Docs](https://tailwindcss.com/docs/cursor)
+ fn cursor_text(mut self) -> Self {
+ self.style().mouse_cursor = Some(CursorStyle::IBeam);
+ self
+ }
+
+ /// Sets cursor style when hovering over an element to `move`.
+ /// [Docs](https://tailwindcss.com/docs/cursor)
+ fn cursor_move(mut self) -> Self {
+ self.style().mouse_cursor = Some(CursorStyle::ClosedHand);
+ self
+ }
+
+ /// Sets cursor style when hovering over an element to `not-allowed`.
+ /// [Docs](https://tailwindcss.com/docs/cursor)
+ fn cursor_not_allowed(mut self) -> Self {
+ self.style().mouse_cursor = Some(CursorStyle::OperationNotAllowed);
+ self
+ }
+
+ /// Sets cursor style when hovering over an element to `context-menu`.
+ /// [Docs](https://tailwindcss.com/docs/cursor)
+ fn cursor_context_menu(mut self) -> Self {
+ self.style().mouse_cursor = Some(CursorStyle::ContextualMenu);
+ self
+ }
+
+ /// Sets cursor style when hovering over an element to `crosshair`.
+ /// [Docs](https://tailwindcss.com/docs/cursor)
+ fn cursor_crosshair(mut self) -> Self {
+ self.style().mouse_cursor = Some(CursorStyle::Crosshair);
+ self
+ }
+
+ /// Sets cursor style when hovering over an element to `vertical-text`.
+ /// [Docs](https://tailwindcss.com/docs/cursor)
+ fn cursor_vertical_text(mut self) -> Self {
+ self.style().mouse_cursor = Some(CursorStyle::IBeamCursorForVerticalLayout);
+ self
+ }
+
+ /// Sets cursor style when hovering over an element to `alias`.
+ /// [Docs](https://tailwindcss.com/docs/cursor)
+ fn cursor_alias(mut self) -> Self {
+ self.style().mouse_cursor = Some(CursorStyle::DragLink);
+ self
+ }
+
+ /// Sets cursor style when hovering over an element to `copy`.
+ /// [Docs](https://tailwindcss.com/docs/cursor)
+ fn cursor_copy(mut self) -> Self {
+ self.style().mouse_cursor = Some(CursorStyle::DragCopy);
+ self
+ }
+
+ /// Sets cursor style when hovering over an element to `no-drop`.
+ /// [Docs](https://tailwindcss.com/docs/cursor)
+ fn cursor_no_drop(mut self) -> Self {
+ self.style().mouse_cursor = Some(CursorStyle::OperationNotAllowed);
+ self
+ }
+
+ /// Sets cursor style when hovering over an element to `grab`.
+ /// [Docs](https://tailwindcss.com/docs/cursor)
+ fn cursor_grab(mut self) -> Self {
+ self.style().mouse_cursor = Some(CursorStyle::OpenHand);
+ self
+ }
+
+ /// Sets cursor style when hovering over an element to `grabbing`.
+ /// [Docs](https://tailwindcss.com/docs/cursor)
+ fn cursor_grabbing(mut self) -> Self {
+ self.style().mouse_cursor = Some(CursorStyle::ClosedHand);
+ self
+ }
+
+ /// Sets cursor style when hovering over an element to `col-resize`.
+ /// [Docs](https://tailwindcss.com/docs/cursor)
+ fn cursor_col_resize(mut self) -> Self {
+ self.style().mouse_cursor = Some(CursorStyle::ResizeLeftRight);
+ self
+ }
+
+ /// Sets cursor style when hovering over an element to `row-resize`.
+ /// [Docs](https://tailwindcss.com/docs/cursor)
+ fn cursor_row_resize(mut self) -> Self {
+ self.style().mouse_cursor = Some(CursorStyle::ResizeUpDown);
+ self
+ }
+
+ /// Sets cursor style when hovering over an element to `n-resize`.
+ /// [Docs](https://tailwindcss.com/docs/cursor)
+ fn cursor_n_resize(mut self) -> Self {
+ self.style().mouse_cursor = Some(CursorStyle::ResizeUp);
+ self
+ }
+
+ /// Sets cursor style when hovering over an element to `e-resize`.
+ /// [Docs](https://tailwindcss.com/docs/cursor)
+ fn cursor_e_resize(mut self) -> Self {
+ self.style().mouse_cursor = Some(CursorStyle::ResizeRight);
+ self
+ }
+
+ /// Sets cursor style when hovering over an element to `s-resize`.
+ /// [Docs](https://tailwindcss.com/docs/cursor)
+ fn cursor_s_resize(mut self) -> Self {
+ self.style().mouse_cursor = Some(CursorStyle::ResizeDown);
+ self
+ }
+
+ /// Sets cursor style when hovering over an element to `w-resize`.
+ /// [Docs](https://tailwindcss.com/docs/cursor)
+ fn cursor_w_resize(mut self) -> Self {
+ self.style().mouse_cursor = Some(CursorStyle::ResizeLeft);
+ self
+ }
+
/// Sets the whitespace of the element to `normal`.
/// [Docs](https://tailwindcss.com/docs/whitespace#normal)
fn whitespace_normal(mut self) -> Self {
@@ -1,4 +1,5 @@
mod auto_height_editor;
+mod cursor;
mod focus;
mod kitchen_sink;
mod picker;
@@ -7,6 +8,7 @@ mod text;
mod z_index;
pub use auto_height_editor::*;
+pub use cursor::*;
pub use focus::*;
pub use kitchen_sink::*;
pub use picker::*;
@@ -0,0 +1,112 @@
+use gpui::{Div, Render, Stateful};
+use story::Story;
+use ui::prelude::*;
+
+pub struct CursorStory;
+
+impl Render for CursorStory {
+ type Element = Div;
+
+ fn render(&mut self, _cx: &mut ViewContext<Self>) -> Self::Element {
+ let all_cursors: [(&str, Box<dyn Fn(Stateful<Div>) -> Stateful<Div>>); 19] = [
+ (
+ "cursor_default",
+ Box::new(|el: Stateful<Div>| el.cursor_default()),
+ ),
+ (
+ "cursor_pointer",
+ Box::new(|el: Stateful<Div>| el.cursor_pointer()),
+ ),
+ (
+ "cursor_text",
+ Box::new(|el: Stateful<Div>| el.cursor_text()),
+ ),
+ (
+ "cursor_move",
+ Box::new(|el: Stateful<Div>| el.cursor_move()),
+ ),
+ (
+ "cursor_not_allowed",
+ Box::new(|el: Stateful<Div>| el.cursor_not_allowed()),
+ ),
+ (
+ "cursor_context_menu",
+ Box::new(|el: Stateful<Div>| el.cursor_context_menu()),
+ ),
+ (
+ "cursor_crosshair",
+ Box::new(|el: Stateful<Div>| el.cursor_crosshair()),
+ ),
+ (
+ "cursor_vertical_text",
+ Box::new(|el: Stateful<Div>| el.cursor_vertical_text()),
+ ),
+ (
+ "cursor_alias",
+ Box::new(|el: Stateful<Div>| el.cursor_alias()),
+ ),
+ (
+ "cursor_copy",
+ Box::new(|el: Stateful<Div>| el.cursor_copy()),
+ ),
+ (
+ "cursor_no_drop",
+ Box::new(|el: Stateful<Div>| el.cursor_no_drop()),
+ ),
+ (
+ "cursor_grab",
+ Box::new(|el: Stateful<Div>| el.cursor_grab()),
+ ),
+ (
+ "cursor_grabbing",
+ Box::new(|el: Stateful<Div>| el.cursor_grabbing()),
+ ),
+ (
+ "cursor_col_resize",
+ Box::new(|el: Stateful<Div>| el.cursor_col_resize()),
+ ),
+ (
+ "cursor_row_resize",
+ Box::new(|el: Stateful<Div>| el.cursor_row_resize()),
+ ),
+ (
+ "cursor_n_resize",
+ Box::new(|el: Stateful<Div>| el.cursor_n_resize()),
+ ),
+ (
+ "cursor_e_resize",
+ Box::new(|el: Stateful<Div>| el.cursor_e_resize()),
+ ),
+ (
+ "cursor_s_resize",
+ Box::new(|el: Stateful<Div>| el.cursor_s_resize()),
+ ),
+ (
+ "cursor_w_resize",
+ Box::new(|el: Stateful<Div>| el.cursor_w_resize()),
+ ),
+ ];
+
+ Story::container()
+ .flex()
+ .gap_1()
+ .child(Story::title("cursor"))
+ .children(all_cursors.map(|(name, apply_cursor)| {
+ div().gap_1().flex().text_color(gpui::white()).child(
+ div()
+ .flex()
+ .items_center()
+ .justify_center()
+ .id(name)
+ .map(apply_cursor)
+ .w_64()
+ .h_8()
+ .bg(gpui::red())
+ .hover(|style| style.bg(gpui::blue()))
+ .active(|style| style.bg(gpui::green()))
+ .text_sm()
+ .child(Story::label(name)),
+ )
+ }))
+ }
+}
@@ -17,6 +17,7 @@ pub enum ComponentStory {
Button,
Checkbox,
ContextMenu,
+ Cursor,
Disclosure,
Focus,
Icon,
@@ -40,6 +41,7 @@ impl ComponentStory {
Self::Button => cx.build_view(|_| ui::ButtonStory).into(),
Self::Checkbox => cx.build_view(|_| ui::CheckboxStory).into(),
Self::ContextMenu => cx.build_view(|_| ui::ContextMenuStory).into(),
+ Self::Cursor => cx.build_view(|_| crate::stories::CursorStory).into(),
Self::Disclosure => cx.build_view(|_| ui::DisclosureStory).into(),
Self::Focus => FocusStory::view(cx).into(),
Self::Icon => cx.build_view(|_| ui::IconStory).into(),
@@ -52,13 +52,13 @@ pub(crate) fn one_dark() -> Theme {
element_hover: hsla(225.0 / 360., 11.8 / 100., 26.7 / 100., 1.0),
element_active: hsla(220.0 / 360., 11.8 / 100., 20.0 / 100., 1.0),
element_selected: hsla(224.0 / 360., 11.3 / 100., 26.1 / 100., 1.0),
- element_disabled: hsla(224.0 / 360., 11.3 / 100., 26.1 / 100., 1.0),
+ element_disabled: SystemColors::default().transparent,
drop_target_background: hsla(220.0 / 360., 8.3 / 100., 21.4 / 100., 1.0),
ghost_element_background: SystemColors::default().transparent,
ghost_element_hover: hsla(225.0 / 360., 11.8 / 100., 26.7 / 100., 1.0),
ghost_element_active: hsla(220.0 / 360., 11.8 / 100., 20.0 / 100., 1.0),
ghost_element_selected: hsla(224.0 / 360., 11.3 / 100., 26.1 / 100., 1.0),
- ghost_element_disabled: hsla(224.0 / 360., 11.3 / 100., 26.1 / 100., 1.0),
+ ghost_element_disabled: SystemColors::default().transparent,
text: hsla(221. / 360., 11. / 100., 86. / 100., 1.0),
text_muted: hsla(218.0 / 360., 7. / 100., 46. / 100., 1.0),
text_placeholder: hsla(220.0 / 360., 6.6 / 100., 44.5 / 100., 1.0),
@@ -323,12 +323,14 @@ impl RenderOnce for ButtonLike {
.id(self.id.clone())
.h(self.size.height())
.rounded_md()
- .when(!self.disabled, |el| el.cursor_pointer())
.gap_1()
.px_1()
.bg(self.style.enabled(cx).background)
- .hover(|hover| hover.bg(self.style.hovered(cx).background))
- .active(|active| active.bg(self.style.active(cx).background))
+ .when(!self.disabled, |this| {
+ this.cursor_pointer()
+ .hover(|hover| hover.bg(self.style.hovered(cx).background))
+ .active(|active| active.bg(self.style.active(cx).background))
+ })
.when_some(
self.on_click.filter(|_| !self.disabled),
|this, on_click| {
@@ -7,7 +7,7 @@ use crate::{
use anyhow::Result;
use collections::{HashMap, HashSet, VecDeque};
use gpui::{
- actions, overlay, prelude::*, Action, AnchorCorner, AnyWeakView, AppContext,
+ actions, overlay, prelude::*, rems, Action, AnchorCorner, AnyWeakView, AppContext,
AsyncWindowContext, DismissEvent, Div, EntityId, EventEmitter, FocusHandle, Focusable,
FocusableView, Model, Pixels, Point, PromptLevel, Render, Task, View, ViewContext,
VisualContext, WeakView, WindowContext,
@@ -26,7 +26,9 @@ use std::{
},
};
-use ui::{prelude::*, right_click_menu, Color, Icon, IconButton, IconElement, Tooltip};
+use ui::{
+ h_stack, prelude::*, right_click_menu, Color, Icon, IconButton, IconElement, Label, Tooltip,
+};
use ui::{v_stack, ContextMenu};
use util::truncate_and_remove_front;
@@ -1554,47 +1556,43 @@ impl Pane {
fn render_tab_bar(&mut self, cx: &mut ViewContext<'_, Pane>) -> impl IntoElement {
div()
- .group("tab_bar")
.id("tab_bar")
+ .group("tab_bar")
.track_focus(&self.tab_bar_focus_handle)
.w_full()
+ // 30px @ 16px/rem
+ .h(rems(1.875))
+ .overflow_hidden()
.flex()
+ .flex_none()
.bg(cx.theme().colors().tab_bar_background)
// Left Side
.child(
- div()
- .relative()
- .px_1()
+ h_stack()
+ .px_2()
.flex()
.flex_none()
- .gap_2()
+ .gap_1()
// Nav Buttons
.child(
- div()
- .right_0()
- .flex()
- .items_center()
- .gap_px()
- .child(
- div().border().border_color(gpui::red()).child(
- IconButton::new("navigate_backward", Icon::ArrowLeft)
- .on_click({
- let view = cx.view().clone();
- move |_, cx| view.update(cx, Self::navigate_backward)
- })
- .disabled(!self.can_navigate_backward()),
- ),
- )
- .child(
- div().border().border_color(gpui::red()).child(
- IconButton::new("navigate_forward", Icon::ArrowRight)
- .on_click({
- let view = cx.view().clone();
- move |_, cx| view.update(cx, Self::navigate_backward)
- })
- .disabled(!self.can_navigate_forward()),
- ),
- ),
+ div().border().border_color(gpui::red()).child(
+ IconButton::new("navigate_backward", Icon::ArrowLeft)
+ .on_click({
+ let view = cx.view().clone();
+ move |_, cx| view.update(cx, Self::navigate_backward)
+ })
+ .disabled(!self.can_navigate_backward()),
+ ),
+ )
+ .child(
+ div().border().border_color(gpui::red()).child(
+ IconButton::new("navigate_forward", Icon::ArrowRight)
+ .on_click({
+ let view = cx.view().clone();
+ move |_, cx| view.update(cx, Self::navigate_backward)
+ })
+ .disabled(!self.can_navigate_forward()),
+ ),
),
)
.child(
@@ -2186,8 +2184,11 @@ impl Render for Pane {
.child(if let Some(item) = self.active_item() {
div().flex().flex_1().child(item.to_any())
} else {
- // todo!()
- div().child("Empty Pane")
+ h_stack()
+ .items_center()
+ .size_full()
+ .justify_center()
+ .child(Label::new("Open a file or project to get started.").color(Color::Muted))
})
// enum MouseNavigationHandler {}