Style Grab Bag (#3487)

[[PR Description]]

- Add pane empty state
- Ensure tab bar doesn't resize when a tab is added
- Make ButtonLike respect the style of a disabled button
- Add additional cursors to gpui2

Release Notes:

- N/A
This commit is contained in:
Nate Butler 2023-12-04 11:55:26 -05:00 committed by GitHub
commit 4f4029524f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 318 additions and 47 deletions

View File

@ -472,13 +472,27 @@ pub enum PromptLevel {
Critical,
}
/// The style of the cursor (pointer)
#[derive(Copy, Clone, Debug)]
pub enum CursorStyle {
Arrow,
ResizeLeftRight,
ResizeUpDown,
PointingHand,
IBeam,
Crosshair,
ClosedHand,
OpenHand,
PointingHand,
ResizeLeft,
ResizeRight,
ResizeLeftRight,
ResizeUp,
ResizeDown,
ResizeUpDown,
DisappearingItem,
IBeamCursorForVerticalLayout,
OperationNotAllowed,
DragLink,
DragCopy,
ContextualMenu,
}
impl Default for CursorStyle {

View File

@ -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];

View File

@ -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 {

View File

@ -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::*;

View File

@ -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)),
)
}))
}
}

View File

@ -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(),

View File

@ -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),

View File

@ -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)
.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| {

View File

@ -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,27 +1556,24 @@ 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)
@ -1595,7 +1594,6 @@ impl Pane {
.disabled(!self.can_navigate_forward()),
),
),
),
)
.child(
div().flex_1().h_full().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 {}