co-authored-by: conrad <conrad@zed.dev>
co-authored-by: Nathan <nathan@zed.dev>
This commit is contained in:
Mikayla
2023-11-20 14:46:01 -08:00
co-authored by conrad Nathan
parent 6985b70859
commit 2c4d83c9af
96 changed files with 1926 additions and 1955 deletions
+7 -7
View File
@@ -7,10 +7,10 @@ pub struct Avatar {
shape: Shape,
}
impl<V: 'static> Component<V> for Avatar {
type Rendered = Img<V>;
impl Component for Avatar {
type Rendered = Img;
fn render(self, _view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
fn render(self, _: &mut WindowContext) -> Self::Rendered {
let mut img = img();
if self.shape == Shape::Circle {
@@ -51,12 +51,12 @@ mod stories {
pub struct AvatarStory;
impl Render<Self> for AvatarStory {
type Element = Div<Self>;
impl Render for AvatarStory {
type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
fn render(&mut self, cx: &mut WindowContext) -> Self::Element {
Story::container(cx)
.child(Story::title_for::<_, Avatar>(cx))
.child(Story::title_for::<Avatar>(cx))
.child(Story::label(cx, "Default"))
.child(Avatar::new(
"https://avatars.githubusercontent.com/u/1714999?v=4",
+19 -15
View File
@@ -1,8 +1,8 @@
use std::sync::Arc;
use std::rc::Rc;
use gpui::{
DefiniteLength, DefiniteLength, Div, Hsla, MouseButton, RenderOnce, Stateful,
StatefulInteractiveElement, WindowContext,
DefiniteLength, Div, Hsla, MouseButton, MouseDownEvent, RenderOnce, StatefulInteractiveElement,
WindowContext,
};
use crate::prelude::*;
@@ -64,9 +64,10 @@ impl ButtonVariant {
}
}
#[derive(RenderOnce)]
pub struct Button {
disabled: bool,
click_handler: Option<CallbackHandle<()>>,
click_handler: Option<Rc<dyn Fn(&MouseDownEvent, &mut WindowContext)>>,
icon: Option<Icon>,
icon_position: Option<IconPosition>,
label: SharedString,
@@ -75,10 +76,10 @@ pub struct Button {
color: Option<TextColor>,
}
impl RenderOnce for Button {
type Element = Stateful<Div>;
impl Component for Button {
type Rendered = gpui::Stateful<Div>;
fn render(self) -> Self::Rendered {
fn render(self, cx: &mut WindowContext) -> Self::Rendered {
let (icon_color, label_color) = match (self.disabled, self.color) {
(true, _) => (TextColor::Disabled, TextColor::Disabled),
(_, None) => (TextColor::Default, TextColor::Default),
@@ -116,9 +117,9 @@ impl RenderOnce for Button {
button = button.w(width).justify_center();
}
if let Some(click_handler) = self.handlers.click.clone() {
button = button.on_mouse_down(MouseButton::Left, move |state, event, cx| {
click_handler(state, cx);
if let Some(click_handler) = self.click_handler.clone() {
button = button.on_mouse_down(MouseButton::Left, move |event, cx| {
click_handler(event, cx);
});
}
@@ -167,8 +168,11 @@ impl Button {
self
}
pub fn on_click(mut self, handler: CallbackHandle<()>) -> Self {
self.handlers.click = Some(handler);
pub fn on_click(
mut self,
handler: impl Fn(&MouseDownEvent, &mut WindowContext) + 'static,
) -> Self {
self.click_handler = Some(Rc::new(handler));
self
}
@@ -215,15 +219,15 @@ impl Component for ButtonGroup {
let mut group = h_stack();
for button in self.buttons.into_iter() {
group = group.child(button.render(view, cx));
group = group.child(button.render(cx));
}
group
}
}
impl<V: 'static> ButtonGroup<V> {
pub fn new(buttons: Vec<Button<V>>) -> Self {
impl ButtonGroup {
pub fn new(buttons: Vec<Button>) -> Self {
Self { buttons }
}
}
+16 -20
View File
@@ -1,10 +1,10 @@
use gpui::{div, prelude::*, Div, Element, ElementId, RenderOnce, Stateful, Styled, ViewContext};
use std::sync::Arc;
use gpui::{div, prelude::*, Div, Element, ElementId, RenderOnce, Styled, WindowContext};
use theme2::ActiveTheme;
use crate::{Icon, IconElement, Selection, TextColor};
pub type CheckHandler<V> = Arc<dyn Fn(Selection, &mut V, &mut ViewContext<V>) + Send + Sync>;
pub type CheckHandler = Box<dyn Fn(&Selection, &mut WindowContext) + 'static>;
/// # Checkbox
///
@@ -12,17 +12,17 @@ pub type CheckHandler<V> = Arc<dyn Fn(Selection, &mut V, &mut ViewContext<V>) +
/// Each checkbox works independently from other checkboxes in the list,
/// therefore checking an additional box does not affect any other selections.
#[derive(RenderOnce)]
pub struct Checkbox<V: 'static> {
pub struct Checkbox {
id: ElementId,
checked: Selection,
disabled: bool,
on_click: Option<CheckHandler<V>>,
on_click: Option<CheckHandler>,
}
impl<V: 'static> Component<V> for Checkbox<V> {
type Rendered = Stateful<V, Div<V>>;
impl Component for Checkbox {
type Rendered = gpui::Stateful<Div>;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
fn render(self, cx: &mut WindowContext) -> Self::Rendered {
let group_id = format!("checkbox_group_{:?}", self.id);
let icon = match self.checked {
@@ -137,13 +137,11 @@ impl<V: 'static> Component<V> for Checkbox<V> {
)
.when_some(
self.on_click.filter(|_| !self.disabled),
|this, on_click| {
this.on_click(move |view, _, cx| on_click(self.checked.inverse(), view, cx))
},
|this, on_click| this.on_click(move |_, cx| on_click(&self.checked.inverse(), cx)),
)
}
}
impl<V: 'static> Checkbox<V> {
impl Checkbox {
pub fn new(id: impl Into<ElementId>, checked: Selection) -> Self {
Self {
id: id.into(),
@@ -160,13 +158,13 @@ impl<V: 'static> Checkbox<V> {
pub fn on_click(
mut self,
handler: impl 'static + Fn(Selection, &mut V, &mut ViewContext<V>) + Send + Sync,
handler: impl 'static + Fn(&Selection, &mut WindowContext) + Send + Sync,
) -> Self {
self.on_click = Some(Arc::new(handler));
self.on_click = Some(Box::new(handler));
self
}
pub fn render(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
pub fn render(self, cx: &mut WindowContext) -> impl Element {
let group_id = format!("checkbox_group_{:?}", self.id);
let icon = match self.checked {
@@ -281,9 +279,7 @@ impl<V: 'static> Checkbox<V> {
)
.when_some(
self.on_click.filter(|_| !self.disabled),
|this, on_click| {
this.on_click(move |view, _, cx| on_click(self.checked.inverse(), view, cx))
},
|this, on_click| this.on_click(move |_, cx| on_click(&self.checked.inverse(), cx)),
)
}
}
@@ -299,8 +295,8 @@ mod stories {
pub struct CheckboxStory;
impl Render<Self> for CheckboxStory {
type Element = Div<Self>;
impl Render for CheckboxStory {
type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
Story::container(cx)
+56 -62
View File
@@ -4,44 +4,39 @@ use std::rc::Rc;
use crate::{prelude::*, v_stack, List, ListItem};
use crate::{ListEntry, ListSeparator, ListSubHeader};
use gpui::{
overlay, px, Action, AnchorCorner, AnyElement, AppContext, Bounds, DispatchPhase, Div,
EventEmitter, FocusHandle, FocusableView, LayoutId, ManagedView, Manager, MouseButton,
MouseDownEvent, Pixels, Point, Render, RenderOnce, View, VisualContext, WeakView,
overlay, px, Action, AnchorCorner, AnyElement, AppContext, Bounds, ClickEvent, DispatchPhase,
Div, EventEmitter, FocusHandle, FocusableView, LayoutId, ManagedView, Manager, MouseButton,
MouseDownEvent, Pixels, Point, Render, RenderOnce, View, VisualContext,
};
pub enum ContextMenuItem<V> {
pub enum ContextMenuItem {
Separator(ListSeparator),
Header(ListSubHeader),
Entry(
ListEntry<ContextMenu<V>>,
Rc<dyn Fn(&mut V, &mut ViewContext<V>)>,
),
Entry(ListEntry, Rc<dyn Fn(&ClickEvent, &mut WindowContext)>),
}
pub struct ContextMenu<V> {
items: Vec<ContextMenuItem<V>>,
pub struct ContextMenu {
items: Vec<ContextMenuItem>,
focus_handle: FocusHandle,
handle: WeakView<V>,
}
impl<V: 'static> FocusableView for ContextMenu<V> {
impl FocusableView for ContextMenu {
fn focus_handle(&self, _cx: &AppContext) -> FocusHandle {
self.focus_handle.clone()
}
}
impl<V: 'static> EventEmitter<Manager> for ContextMenu<V> {}
impl EventEmitter<Manager> for ContextMenu {}
impl<V: 'static> ContextMenu<V> {
impl ContextMenu {
pub fn build(
cx: &mut ViewContext<V>,
f: impl FnOnce(Self, &mut ViewContext<Self>) -> Self,
cx: &mut WindowContext,
f: impl FnOnce(Self, &mut WindowContext) -> Self,
) -> View<Self> {
let handle = cx.view().downgrade();
// let handle = cx.view().downgrade();
cx.build_view(|cx| {
f(
Self {
handle,
items: Default::default(),
focus_handle: cx.focus_handle(),
},
@@ -63,15 +58,15 @@ impl<V: 'static> ContextMenu<V> {
pub fn entry(
mut self,
view: ListEntry<Self>,
on_click: impl Fn(&mut V, &mut ViewContext<V>) + 'static,
view: ListEntry,
on_click: impl Fn(&ClickEvent, &mut WindowContext) + 'static,
) -> Self {
self.items
.push(ContextMenuItem::Entry(view, Rc::new(on_click)));
self
}
pub fn action(self, view: ListEntry<Self>, action: Box<dyn Action>) -> Self {
pub fn action(self, view: ListEntry, action: Box<dyn Action>) -> Self {
// todo: add the keybindings to the list entry
self.entry(view, move |_, cx| cx.dispatch_action(action.boxed_clone()))
}
@@ -86,21 +81,23 @@ impl<V: 'static> ContextMenu<V> {
}
}
impl<V: 'static> Render<Self> for ContextMenu<V> {
type Element = Div<Self>;
impl Render for ContextMenu {
type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
div().elevation_2(cx).flex().flex_row().child(
v_stack()
.min_w(px(200.))
.track_focus(&self.focus_handle)
.on_mouse_down_out(|this: &mut Self, _, cx| this.cancel(&Default::default(), cx))
.on_mouse_down_out(
cx.listener(|this: &mut Self, _, cx| this.cancel(&Default::default(), cx)),
)
// .on_action(ContextMenu::select_first)
// .on_action(ContextMenu::select_last)
// .on_action(ContextMenu::select_next)
// .on_action(ContextMenu::select_prev)
.on_action(ContextMenu::confirm)
.on_action(ContextMenu::cancel)
.on_action(cx.listener(ContextMenu::confirm))
.on_action(cx.listener(ContextMenu::cancel))
.flex_none()
// .bg(cx.theme().colors().elevated_surface_background)
// .border()
@@ -115,10 +112,11 @@ impl<V: 'static> Render<Self> for ContextMenu<V> {
ContextMenuItem::Header(header) => ListItem::Header(header.clone()),
ContextMenuItem::Entry(entry, callback) => {
let callback = callback.clone();
let handle = self.handle.clone();
ListItem::Entry(entry.clone().on_click(move |this, cx| {
handle.update(cx, |view, cx| callback(view, cx)).ok();
cx.emit(Manager::Dismiss);
let dismiss = cx.listener(|_, _, cx| cx.emit(Manager::Dismiss));
ListItem::Entry(entry.clone().on_click(move |event, cx| {
callback(event, cx);
dismiss(event, cx)
}))
}
})
@@ -128,22 +126,21 @@ impl<V: 'static> Render<Self> for ContextMenu<V> {
}
}
pub struct MenuHandle<V: 'static, M: ManagedView> {
pub struct MenuHandle<M: ManagedView> {
id: ElementId,
child_builder: Option<Box<dyn FnOnce(bool) -> AnyElement<V> + 'static>>,
menu_builder: Option<Rc<dyn Fn(&mut V, &mut ViewContext<V>) -> View<M> + 'static>>,
child_builder: Option<Box<dyn FnOnce(bool) -> AnyElement + 'static>>,
menu_builder: Option<Rc<dyn Fn(&mut WindowContext) -> View<M> + 'static>>,
anchor: Option<AnchorCorner>,
attach: Option<AnchorCorner>,
}
impl<V: 'static, M: ManagedView> MenuHandle<V, M> {
pub fn menu(mut self, f: impl Fn(&mut V, &mut ViewContext<V>) -> View<M> + 'static) -> Self {
impl<M: ManagedView> MenuHandle<M> {
pub fn menu(mut self, f: impl Fn(&mut WindowContext) -> View<M> + 'static) -> Self {
self.menu_builder = Some(Rc::new(f));
self
}
pub fn child<R: RenderOnce<V>>(mut self, f: impl FnOnce(bool) -> R + 'static) -> Self {
pub fn child<R: RenderOnce>(mut self, f: impl FnOnce(bool) -> R + 'static) -> Self {
self.child_builder = Some(Box::new(|b| f(b).render_once().into_any()));
self
}
@@ -162,7 +159,7 @@ impl<V: 'static, M: ManagedView> MenuHandle<V, M> {
}
}
pub fn menu_handle<V: 'static, M: ManagedView>(id: impl Into<ElementId>) -> MenuHandle<V, M> {
pub fn menu_handle<M: ManagedView>(id: impl Into<ElementId>) -> MenuHandle<M> {
MenuHandle {
id: id.into(),
child_builder: None,
@@ -172,21 +169,20 @@ pub fn menu_handle<V: 'static, M: ManagedView>(id: impl Into<ElementId>) -> Menu
}
}
pub struct MenuHandleState<V, M> {
pub struct MenuHandleState<M> {
menu: Rc<RefCell<Option<View<M>>>>,
position: Rc<RefCell<Point<Pixels>>>,
child_layout_id: Option<LayoutId>,
child_element: Option<AnyElement<V>>,
menu_element: Option<AnyElement<V>>,
child_element: Option<AnyElement>,
menu_element: Option<AnyElement>,
}
impl<V: 'static, M: ManagedView> Element<V> for MenuHandle<V, M> {
type State = MenuHandleState<V, M>;
impl<M: ManagedView> Element for MenuHandle<M> {
type State = MenuHandleState<M>;
fn layout(
&mut self,
view_state: &mut V,
element_state: Option<Self::State>,
cx: &mut crate::ViewContext<V>,
cx: &mut WindowContext,
) -> (gpui::LayoutId, Self::State) {
let (menu, position) = if let Some(element_state) = element_state {
(element_state.menu, element_state.position)
@@ -197,14 +193,14 @@ impl<V: 'static, M: ManagedView> Element<V> for MenuHandle<V, M> {
let mut menu_layout_id = None;
let menu_element = menu.borrow_mut().as_mut().map(|menu| {
let mut overlay = overlay::<V>().snap_to_window();
let mut overlay = overlay().snap_to_window();
if let Some(anchor) = self.anchor {
overlay = overlay.anchor(anchor);
}
overlay = overlay.position(*position.borrow());
let mut element = overlay.child(menu.clone()).into_any();
menu_layout_id = Some(element.layout(view_state, cx));
menu_layout_id = Some(element.layout(cx));
element
});
@@ -215,7 +211,7 @@ impl<V: 'static, M: ManagedView> Element<V> for MenuHandle<V, M> {
let child_layout_id = child_element
.as_mut()
.map(|child_element| child_element.layout(view_state, cx));
.map(|child_element| child_element.layout(cx));
let layout_id = cx.request_layout(
&gpui::Style::default(),
@@ -237,16 +233,15 @@ impl<V: 'static, M: ManagedView> Element<V> for MenuHandle<V, M> {
fn paint(
self,
bounds: Bounds<gpui::Pixels>,
view_state: &mut V,
element_state: &mut Self::State,
cx: &mut crate::ViewContext<V>,
cx: &mut WindowContext,
) {
if let Some(child) = element_state.child_element.take() {
child.paint(view_state, cx);
child.paint(cx);
}
if let Some(menu) = element_state.menu_element.take() {
menu.paint(view_state, cx);
menu.paint(cx);
return;
}
@@ -258,7 +253,7 @@ impl<V: 'static, M: ManagedView> Element<V> for MenuHandle<V, M> {
let attach = self.attach.clone();
let child_layout_id = element_state.child_layout_id.clone();
cx.on_mouse_event(move |view_state, event: &MouseDownEvent, phase, cx| {
cx.on_mouse_event(move |event: &MouseDownEvent, phase, cx| {
if phase == DispatchPhase::Bubble
&& event.button == MouseButton::Right
&& bounds.contains_point(&event.position)
@@ -266,9 +261,9 @@ impl<V: 'static, M: ManagedView> Element<V> for MenuHandle<V, M> {
cx.stop_propagation();
cx.prevent_default();
let new_menu = (builder)(view_state, cx);
let new_menu = (builder)(cx);
let menu2 = menu.clone();
cx.subscribe(&new_menu, move |this, modal, e, cx| match e {
cx.subscribe(&new_menu, move |modal, e, cx| match e {
&Manager::Dismiss => {
*menu2.borrow_mut() = None;
cx.notify();
@@ -291,7 +286,7 @@ impl<V: 'static, M: ManagedView> Element<V> for MenuHandle<V, M> {
}
}
impl<V: 'static, M: ManagedView> RenderOnce<V> for MenuHandle<V, M> {
impl<M: ManagedView> RenderOnce for MenuHandle<M> {
type Element = Self;
fn element_id(&self) -> Option<gpui::ElementId> {
@@ -314,11 +309,10 @@ mod stories {
actions!(PrintCurrentDate, PrintBestFood);
fn build_menu<V: Render<V>>(
cx: &mut ViewContext<V>,
fn build_menu<V: Render>(
cx: &mut WindowContext,
header: impl Into<SharedString>,
) -> View<ContextMenu<V>> {
let handle = cx.view().clone();
) -> View<ContextMenu> {
ContextMenu::build(cx, |menu, _| {
menu.header(header)
.separator()
@@ -334,8 +328,8 @@ mod stories {
pub struct ContextMenuStory;
impl Render<Self> for ContextMenuStory {
type Element = Div<Self>;
impl Render for ContextMenuStory {
type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
Story::container(cx)
+9 -9
View File
@@ -2,16 +2,16 @@ use crate::prelude::*;
use crate::{v_stack, ButtonGroup};
#[derive(RenderOnce)]
pub struct Details<V: 'static> {
pub struct Details {
text: &'static str,
meta: Option<&'static str>,
actions: Option<ButtonGroup<V>>,
actions: Option<ButtonGroup>,
}
impl<V: 'static> Component<V> for Details<V> {
type Rendered = Div<V>;
impl Component for Details {
type Rendered = Div;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
fn render(self, cx: &mut WindowContext) -> Self::Rendered {
v_stack()
.p_1()
.gap_0p5()
@@ -24,7 +24,7 @@ impl<V: 'static> Component<V> for Details<V> {
}
}
impl<V: 'static> Details<V> {
impl Details {
pub fn new(text: &'static str) -> Self {
Self {
text,
@@ -38,7 +38,7 @@ impl<V: 'static> Details<V> {
self
}
pub fn actions(mut self, actions: ButtonGroup<V>) -> Self {
pub fn actions(mut self, actions: ButtonGroup) -> Self {
self.actions = Some(actions);
self
}
@@ -56,8 +56,8 @@ mod stories {
pub struct DetailsStory;
impl Render<Self> for DetailsStory {
type Element = Div<Self>;
impl Render for DetailsStory {
type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
Story::container(cx)
+4 -4
View File
@@ -13,10 +13,10 @@ pub struct Divider {
inset: bool,
}
impl<V: 'static> Component<V> for Divider {
type Rendered = Div<V>;
impl Component for Divider {
type Rendered = Div;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
fn render(self, cx: &mut WindowContext) -> Self::Rendered {
div()
.map(|this| match self.direction {
DividerDirection::Horizontal => {
@@ -50,7 +50,7 @@ impl Divider {
self
}
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
fn render(self, cx: &mut WindowContext) -> impl Element {
div()
.map(|this| match self.direction {
DividerDirection::Horizontal => {
@@ -5,7 +5,7 @@ use crate::{prelude::*, v_stack};
/// Create an elevated surface.
///
/// Must be used inside of a relative parent element
pub fn elevated_surface<V: 'static>(level: ElevationIndex, cx: &mut ViewContext<V>) -> Div<V> {
pub fn elevated_surface(level: ElevationIndex, cx: &mut WindowContext) -> Div {
let colors = cx.theme().colors();
// let shadow = BoxShadow {
@@ -23,6 +23,6 @@ pub fn elevated_surface<V: 'static>(level: ElevationIndex, cx: &mut ViewContext<
.shadow(level.shadow())
}
pub fn modal<V: 'static>(cx: &mut ViewContext<V>) -> Div<V> {
pub fn modal(cx: &mut WindowContext) -> Div {
elevated_surface(ElevationIndex::ModalSurface, cx)
}
+5 -5
View File
@@ -6,10 +6,10 @@ pub struct Facepile {
players: Vec<Player>,
}
impl<V: 'static> Component<V> for Facepile {
type Rendered = Div<V>;
impl Component for Facepile {
type Rendered = Div;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
fn render(self, cx: &mut WindowContext) -> Self::Rendered {
let player_count = self.players.len();
let player_list = self.players.iter().enumerate().map(|(ix, player)| {
let isnt_last = ix < player_count - 1;
@@ -42,8 +42,8 @@ mod stories {
pub struct FacepileStory;
impl Render<Self> for FacepileStory {
type Element = Div<Self>;
impl Render for FacepileStory {
type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
let players = static_players();
+6 -6
View File
@@ -136,10 +136,10 @@ pub struct IconElement {
size: IconSize,
}
impl<V: 'static> Component<V> for IconElement {
type Rendered = Svg<V>;
impl Component for IconElement {
type Rendered = Svg;
fn render(self, _view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
fn render(self, cx: &mut WindowContext) -> Self::Rendered {
let svg_size = match self.size {
IconSize::Small => rems(0.75),
IconSize::Medium => rems(0.9375),
@@ -180,7 +180,7 @@ impl IconElement {
self
}
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
fn render(self, cx: &mut WindowContext) -> impl Element {
let svg_size = match self.size {
IconSize::Small => rems(0.75),
IconSize::Medium => rems(0.9375),
@@ -208,8 +208,8 @@ mod stories {
pub struct IconStory;
impl Render<Self> for IconStory {
type Element = Div<Self>;
impl Render for IconStory {
type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
let icons = Icon::iter();
+20 -31
View File
@@ -1,33 +1,22 @@
use crate::{h_stack, prelude::*, ClickHandler, Icon, IconElement};
use gpui::{prelude::*, Action, AnyView, Div, MouseButton, Stateful};
use std::sync::Arc;
struct IconButtonHandlers<V: 'static> {
click: Option<ClickHandler<V>>,
}
impl<V: 'static> Default for IconButtonHandlers<V> {
fn default() -> Self {
Self { click: None }
}
}
use crate::{h_stack, prelude::*, Icon, IconElement};
use gpui::{prelude::*, Action, AnyView, Div, MouseButton, MouseDownEvent, Stateful};
#[derive(RenderOnce)]
pub struct IconButton<V: 'static> {
pub struct IconButton {
id: ElementId,
icon: Icon,
color: TextColor,
variant: ButtonVariant,
state: InteractionState,
selected: bool,
tooltip: Option<Box<dyn Fn(&mut V, &mut ViewContext<V>) -> AnyView + 'static>>,
handlers: IconButtonHandlers<V>,
tooltip: Option<Box<dyn Fn(&mut WindowContext) -> AnyView + 'static>>,
on_mouse_down: Option<Box<dyn Fn(&MouseDownEvent, &mut WindowContext) + 'static>>,
}
impl<V: 'static> Component<V> for IconButton<V> {
type Rendered = Stateful<V, Div<V>>;
impl Component for IconButton {
type Rendered = Stateful<Div>;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
fn render(self, cx: &mut WindowContext) -> Self::Rendered {
let icon_color = match (self.state, self.color) {
(InteractionState::Disabled, _) => TextColor::Disabled,
(InteractionState::Active, _) => TextColor::Selected,
@@ -65,16 +54,16 @@ impl<V: 'static> Component<V> for IconButton<V> {
.active(|style| style.bg(bg_active_color))
.child(IconElement::new(self.icon).color(icon_color));
if let Some(click_handler) = self.handlers.click.clone() {
button = button.on_mouse_down(MouseButton::Left, move |state, event, cx| {
if let Some(click_handler) = self.on_mouse_down {
button = button.on_mouse_down(MouseButton::Left, move |event, cx| {
cx.stop_propagation();
click_handler(state, cx);
click_handler(event, cx);
})
}
if let Some(tooltip) = self.tooltip {
if !self.selected {
button = button.tooltip(move |view: &mut V, cx| (tooltip)(view, cx))
button = button.tooltip(move |cx| tooltip(cx))
}
}
@@ -82,7 +71,7 @@ impl<V: 'static> Component<V> for IconButton<V> {
}
}
impl<V: 'static> IconButton<V> {
impl IconButton {
pub fn new(id: impl Into<ElementId>, icon: Icon) -> Self {
Self {
id: id.into(),
@@ -92,7 +81,7 @@ impl<V: 'static> IconButton<V> {
state: InteractionState::default(),
selected: false,
tooltip: None,
handlers: IconButtonHandlers::default(),
on_mouse_down: None,
}
}
@@ -121,16 +110,16 @@ impl<V: 'static> IconButton<V> {
self
}
pub fn tooltip(
mut self,
tooltip: impl Fn(&mut V, &mut ViewContext<V>) -> AnyView + 'static,
) -> Self {
pub fn tooltip(mut self, tooltip: impl Fn(&mut WindowContext) -> AnyView + 'static) -> Self {
self.tooltip = Some(Box::new(tooltip));
self
}
pub fn on_click(mut self, handler: impl 'static + Fn(&mut V, &mut ViewContext<V>)) -> Self {
self.handlers.click = Some(Arc::new(handler));
pub fn on_click(
mut self,
handler: impl 'static + Fn(&MouseDownEvent, &mut WindowContext),
) -> Self {
self.on_mouse_down = Some(Box::new(handler));
self
}
+4 -4
View File
@@ -4,10 +4,10 @@ use gpui::{px, Div, RenderOnce};
#[derive(RenderOnce)]
pub struct UnreadIndicator;
impl<V: 'static> Component<V> for UnreadIndicator {
type Rendered = Div<V>;
impl Component for UnreadIndicator {
type Rendered = Div;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
fn render(self, cx: &mut WindowContext) -> Self::Rendered {
div()
.rounded_full()
.border_2()
@@ -24,7 +24,7 @@ impl UnreadIndicator {
Self
}
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
fn render(self, cx: &mut WindowContext) -> impl Element {
div()
.rounded_full()
.border_2()
+5 -5
View File
@@ -18,10 +18,10 @@ pub struct Input {
is_active: bool,
}
impl<V: 'static> Component<V> for Input {
type Rendered = Stateful<V, Div<V>>;
impl Component for Input {
type Rendered = Stateful<Div>;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
fn render(self, cx: &mut WindowContext) -> Self::Rendered {
let (input_bg, input_hover_bg, input_active_bg) = match self.variant {
InputVariant::Ghost => (
cx.theme().colors().ghost_element_background,
@@ -118,8 +118,8 @@ mod stories {
pub struct InputStory;
impl Render<Self> for InputStory {
type Element = Div<Self>;
impl Render for InputStory {
type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
Story::container(cx)
+8 -9
View File
@@ -10,10 +10,10 @@ pub struct KeyBinding {
key_binding: gpui::KeyBinding,
}
impl<V: 'static> Component<V> for KeyBinding {
type Rendered = Div<V>;
impl Component for KeyBinding {
type Rendered = Div;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
fn render(self, cx: &mut WindowContext) -> Self::Rendered {
div()
.flex()
.gap_2()
@@ -49,11 +49,10 @@ pub struct Key {
key: SharedString,
}
impl<V: 'static> Component<V> for Key {
type Rendered = Div<V>;
impl Component for Key {
type Rendered = Div;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
let _view: &mut V = view;
fn render(self, cx: &mut WindowContext) -> Self::Rendered {
div()
.px_2()
.py_0()
@@ -89,8 +88,8 @@ mod stories {
gpui::KeyBinding::new(key, NoAction {}, None)
}
impl Render<Self> for KeybindingStory {
type Element = Div<Self>;
impl Render for KeybindingStory {
type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
let all_modifier_permutations =
+8 -8
View File
@@ -68,10 +68,10 @@ pub struct Label {
strikethrough: bool,
}
impl<V: 'static> Component<V> for Label {
type Rendered = Div<V>;
impl Component for Label {
type Rendered = Div;
fn render(self, _view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
fn render(self, cx: &mut WindowContext) -> Self::Rendered {
div()
.when(self.strikethrough, |this| {
this.relative().child(
@@ -136,10 +136,10 @@ pub struct HighlightedLabel {
strikethrough: bool,
}
impl<V: 'static> Component<V> for HighlightedLabel {
type Rendered = Div<V>;
impl Component for HighlightedLabel {
type Rendered = Div;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
fn render(self, cx: &mut WindowContext) -> Self::Rendered {
let highlight_color = cx.theme().colors().text_accent;
let mut text_style = cx.text_style().clone();
@@ -242,8 +242,8 @@ mod stories {
pub struct LabelStory;
impl Render<Self> for LabelStory {
type Element = Div<Self>;
impl Render for LabelStory {
type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
Story::container(cx)
+40 -42
View File
@@ -1,4 +1,4 @@
use gpui::{div, Div, RenderOnce, Stateful, StatefulInteractiveElement};
use gpui::{div, ClickEvent, Div, RenderOnce, Stateful, StatefulInteractiveElement};
use std::rc::Rc;
use crate::settings::user_settings;
@@ -32,10 +32,10 @@ pub struct ListHeader {
toggle: Toggle,
}
impl<V: 'static> Component<V> for ListHeader {
type Rendered = Div<V>;
impl Component for ListHeader {
type Rendered = Div;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
fn render(self, cx: &mut WindowContext) -> Self::Rendered {
let disclosure_control = disclosure_control(self.toggle);
let meta = match self.meta {
@@ -198,7 +198,7 @@ impl ListSubHeader {
self
}
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
fn render(self, cx: &mut WindowContext) -> impl Element {
h_stack().flex_1().w_full().relative().py_1().child(
div()
.h_6()
@@ -233,36 +233,36 @@ pub enum ListEntrySize {
}
#[derive(Clone)]
pub enum ListItem<V: 'static> {
Entry(ListEntry<V>),
pub enum ListItem {
Entry(ListEntry),
Separator(ListSeparator),
Header(ListSubHeader),
}
impl<V: 'static> From<ListEntry<V>> for ListItem<V> {
fn from(entry: ListEntry<V>) -> Self {
impl From<ListEntry> for ListItem {
fn from(entry: ListEntry) -> Self {
Self::Entry(entry)
}
}
impl<V: 'static> From<ListSeparator> for ListItem<V> {
impl From<ListSeparator> for ListItem {
fn from(entry: ListSeparator) -> Self {
Self::Separator(entry)
}
}
impl<V: 'static> From<ListSubHeader> for ListItem<V> {
impl From<ListSubHeader> for ListItem {
fn from(entry: ListSubHeader) -> Self {
Self::Header(entry)
}
}
impl<V: 'static> ListItem<V> {
impl ListItem {
pub fn new(label: Label) -> Self {
Self::Entry(ListEntry::new(label))
}
pub fn as_entry(&mut self) -> Option<&mut ListEntry<V>> {
pub fn as_entry(&mut self) -> Option<&mut ListEntry> {
if let Self::Entry(entry) = self {
Some(entry)
} else {
@@ -270,17 +270,17 @@ impl<V: 'static> ListItem<V> {
}
}
fn render(self, view: &mut V, ix: usize, cx: &mut ViewContext<V>) -> Div<V> {
fn render(self, ix: usize, cx: &mut WindowContext) -> Div {
match self {
ListItem::Entry(entry) => div().child(entry.render(ix, cx)),
ListItem::Separator(separator) => div().child(separator.render(view, cx)),
ListItem::Header(header) => div().child(header.render(view, cx)),
ListItem::Separator(separator) => div().child(separator.render(cx)),
ListItem::Header(header) => div().child(header.render(cx)),
}
}
}
// #[derive(RenderOnce)]
pub struct ListEntry<V> {
pub struct ListEntry {
disabled: bool,
// TODO: Reintroduce this
// disclosure_control_style: DisclosureControlVisibility,
@@ -291,10 +291,10 @@ pub struct ListEntry<V> {
size: ListEntrySize,
toggle: Toggle,
variant: ListItemVariant,
on_click: Option<Rc<dyn Fn(&mut V, &mut ViewContext<V>) + 'static>>,
on_click: Option<Rc<dyn Fn(&ClickEvent, &mut WindowContext) + 'static>>,
}
impl<V> Clone for ListEntry<V> {
impl Clone for ListEntry {
fn clone(&self) -> Self {
Self {
disabled: self.disabled,
@@ -310,7 +310,7 @@ impl<V> Clone for ListEntry<V> {
}
}
impl<V: 'static> ListEntry<V> {
impl ListEntry {
pub fn new(label: Label) -> Self {
Self {
disabled: false,
@@ -325,7 +325,7 @@ impl<V: 'static> ListEntry<V> {
}
}
pub fn on_click(mut self, handler: impl Fn(&mut V, &mut ViewContext<V>) + 'static) -> Self {
pub fn on_click(mut self, handler: impl Fn(&ClickEvent, &mut WindowContext) + 'static) -> Self {
self.on_click = Some(Rc::new(handler));
self
}
@@ -365,7 +365,7 @@ impl<V: 'static> ListEntry<V> {
self
}
fn render(self, ix: usize, cx: &mut ViewContext<V>) -> Stateful<V, Div<V>> {
fn render(self, ix: usize, cx: &mut WindowContext) -> Stateful<Div> {
let settings = user_settings(cx);
let left_content = match self.left_slot.clone() {
@@ -392,13 +392,11 @@ impl<V: 'static> ListEntry<V> {
style.background = Some(cx.theme().colors().editor_background.into());
style
})
.on_click({
let on_click = self.on_click.clone();
move |view: &mut V, event, cx| {
if let Some(on_click) = &on_click {
(on_click)(view, cx)
}
.map(|div| {
if let Some(on_click) = self.on_click.clone() {
div.on_click(move |e, cx| on_click(e, cx))
} else {
div
}
})
.bg(cx.theme().colors().surface_background)
@@ -444,17 +442,17 @@ impl ListSeparator {
}
}
impl<V: 'static> Component<V> for ListSeparator {
type Rendered = Div<V>;
impl Component for ListSeparator {
type Rendered = Div;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
fn render(self, cx: &mut WindowContext) -> Self::Rendered {
div().h_px().w_full().bg(cx.theme().colors().border_variant)
}
}
#[derive(RenderOnce)]
pub struct List<V: 'static> {
items: Vec<ListItem<V>>,
pub struct List {
items: Vec<ListItem>,
/// Message to display when the list is empty
/// Defaults to "No items"
empty_message: SharedString,
@@ -462,16 +460,16 @@ pub struct List<V: 'static> {
toggle: Toggle,
}
impl<V: 'static> Component<V> for List<V> {
type Rendered = Div<V>;
impl Component for List {
type Rendered = Div;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
fn render(self, cx: &mut WindowContext) -> Self::Rendered {
let list_content = match (self.items.is_empty(), self.toggle) {
(false, _) => div().children(
self.items
.into_iter()
.enumerate()
.map(|(ix, item)| item.render(view, ix, cx)),
.map(|(ix, item)| item.render(ix, cx)),
),
(true, Toggle::Toggled(false)) => div(),
(true, _) => {
@@ -487,8 +485,8 @@ impl<V: 'static> Component<V> for List<V> {
}
}
impl<V: 'static> List<V> {
pub fn new(items: Vec<ListItem<V>>) -> Self {
impl List {
pub fn new(items: Vec<ListItem>) -> Self {
Self {
items,
empty_message: "No items".into(),
@@ -512,13 +510,13 @@ impl<V: 'static> List<V> {
self
}
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
fn render(self, cx: &mut WindowContext) -> impl Element {
let list_content = match (self.items.is_empty(), self.toggle) {
(false, _) => div().children(
self.items
.into_iter()
.enumerate()
.map(|(ix, item)| item.render(view, ix, cx)),
.map(|(ix, item)| item.render(ix, cx)),
),
(true, Toggle::Toggled(false)) => div(),
(true, _) => {
+13 -14
View File
@@ -1,22 +1,21 @@
use gpui::{AnyElement, Div, RenderOnce, Stateful};
use gpui::{AnyElement, Div, RenderOnce};
use smallvec::SmallVec;
use crate::{h_stack, prelude::*, v_stack, Button, Icon, IconButton, Label};
#[derive(RenderOnce)]
pub struct Modal<V: 'static> {
pub struct Modal {
id: ElementId,
title: Option<SharedString>,
primary_action: Option<Button<V>>,
secondary_action: Option<Button<V>>,
children: SmallVec<[AnyElement<V>; 2]>,
primary_action: Option<Button>,
secondary_action: Option<Button>,
children: SmallVec<[AnyElement; 2]>,
}
impl<V: 'static> Component<V> for Modal<V> {
type Rendered = Stateful<V, Div<V>>;
impl Component for Modal {
type Rendered = gpui::Stateful<Div>;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
let _view: &mut V = view;
fn render(self, cx: &mut WindowContext) -> Self::Rendered {
v_stack()
.id(self.id.clone())
.w_96()
@@ -52,7 +51,7 @@ impl<V: 'static> Component<V> for Modal<V> {
}
}
impl<V: 'static> Modal<V> {
impl Modal {
pub fn new(id: impl Into<ElementId>) -> Self {
Self {
id: id.into(),
@@ -68,19 +67,19 @@ impl<V: 'static> Modal<V> {
self
}
pub fn primary_action(mut self, action: Button<V>) -> Self {
pub fn primary_action(mut self, action: Button) -> Self {
self.primary_action = Some(action);
self
}
pub fn secondary_action(mut self, action: Button<V>) -> Self {
pub fn secondary_action(mut self, action: Button) -> Self {
self.secondary_action = Some(action);
self
}
}
impl<V: 'static> ParentElement<V> for Modal<V> {
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
impl ParentElement for Modal {
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> {
&mut self.children
}
}
@@ -22,7 +22,7 @@ impl NotificationToast {
self
}
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
fn render(self, cx: &mut WindowContext) -> impl Element {
h_stack()
.z_index(5)
.absolute()
+8 -9
View File
@@ -1,7 +1,6 @@
use crate::{h_stack, prelude::*, v_stack, KeyBinding, Label};
use gpui::prelude::*;
use gpui::Div;
use gpui::Stateful;
#[derive(RenderOnce)]
pub struct Palette {
@@ -12,10 +11,10 @@ pub struct Palette {
default_order: OrderMethod,
}
impl<V: 'static> Component<V> for Palette {
type Rendered = Stateful<V, Div<V>>;
impl Component for Palette {
type Rendered = gpui::Stateful<Div>;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
fn render(self, cx: &mut WindowContext) -> Self::Rendered {
v_stack()
.id(self.id)
.w_96()
@@ -116,10 +115,10 @@ pub struct PaletteItem {
pub key_binding: Option<KeyBinding>,
}
impl<V: 'static> Component<V> for PaletteItem {
type Rendered = Div<V>;
impl Component for PaletteItem {
type Rendered = Div;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
fn render(self, cx: &mut WindowContext) -> Self::Rendered {
div()
.flex()
.flex_row()
@@ -173,8 +172,8 @@ mod stories {
pub struct PaletteStory;
impl Render<Self> for PaletteStory {
type Element = Div<Self>;
impl Render for PaletteStory {
type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
{
+12 -12
View File
@@ -1,4 +1,4 @@
use gpui::{prelude::*, AbsoluteLength, AnyElement, Div, RenderOnce, Stateful};
use gpui::{prelude::*, AbsoluteLength, AnyElement, Div, RenderOnce};
use smallvec::SmallVec;
use crate::prelude::*;
@@ -39,20 +39,20 @@ pub enum PanelSide {
use std::collections::HashSet;
#[derive(RenderOnce)]
pub struct Panel<V: 'static> {
pub struct Panel {
id: ElementId,
current_side: PanelSide,
/// Defaults to PanelAllowedSides::LeftAndRight
allowed_sides: PanelAllowedSides,
initial_width: AbsoluteLength,
width: Option<AbsoluteLength>,
children: SmallVec<[AnyElement<V>; 2]>,
children: SmallVec<[AnyElement; 2]>,
}
impl<V: 'static> Component<V> for Panel<V> {
type Rendered = Stateful<V, Div<V>>;
impl Component for Panel {
type Rendered = gpui::Stateful<Div>;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
fn render(self, cx: &mut WindowContext) -> Self::Rendered {
let current_size = self.width.unwrap_or(self.initial_width);
v_stack()
@@ -73,7 +73,7 @@ impl<V: 'static> Component<V> for Panel<V> {
}
}
impl<V: 'static> Panel<V> {
impl Panel {
pub fn new(id: impl Into<ElementId>, cx: &mut WindowContext) -> Self {
let settings = user_settings(cx);
@@ -117,8 +117,8 @@ impl<V: 'static> Panel<V> {
}
}
impl<V: 'static> ParentElement<V> for Panel<V> {
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
impl ParentElement for Panel {
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> {
&mut self.children
}
}
@@ -134,12 +134,12 @@ mod stories {
pub struct PanelStory;
impl Render<Self> for PanelStory {
type Element = Div<Self>;
impl Render for PanelStory {
type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
Story::container(cx)
.child(Story::title_for::<_, Panel<Self>>(cx))
.child(Story::title_for::<Panel<Self>>(cx))
.child(Story::label(cx, "Default"))
.child(
Panel::new("panel", cx).child(
+3 -3
View File
@@ -1,4 +1,4 @@
use gpui::{Hsla, ViewContext};
use gpui::Hsla;
use crate::prelude::*;
@@ -156,11 +156,11 @@ impl Player {
self
}
pub fn cursor_color<V: 'static>(&self, cx: &mut ViewContext<V>) -> Hsla {
pub fn cursor_color(&self, cx: &mut WindowContext) -> Hsla {
cx.theme().styles.player.0[self.index % cx.theme().styles.player.0.len()].cursor
}
pub fn selection_color<V: 'static>(&self, cx: &mut ViewContext<V>) -> Hsla {
pub fn selection_color(&self, cx: &mut WindowContext) -> Hsla {
cx.theme().styles.player.0[self.index % cx.theme().styles.player.0.len()].selection
}
+3 -3
View File
@@ -8,10 +8,10 @@ pub struct PlayerStack {
player_with_call_status: PlayerWithCallStatus,
}
impl<V: 'static> Component<V> for PlayerStack {
type Rendered = Div<V>;
impl Component for PlayerStack {
type Rendered = Div;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
fn render(self, cx: &mut WindowContext) -> Self::Rendered {
let player = self.player_with_call_status.get_player();
let followers = self
+2 -2
View File
@@ -5,13 +5,13 @@ use crate::StyledExt;
/// Horizontally stacks elements.
///
/// Sets `flex()`, `flex_row()`, `items_center()`
pub fn h_stack<V: 'static>() -> Div<V> {
pub fn h_stack() -> Div {
div().h_flex()
}
/// Vertically stacks elements.
///
/// Sets `flex()`, `flex_col()`
pub fn v_stack<V: 'static>() -> Div<V> {
pub fn v_stack() -> Div {
div().v_flex()
}
+250 -250
View File
@@ -1,276 +1,276 @@
use crate::prelude::*;
use crate::{Icon, IconElement, Label, TextColor};
use gpui::{prelude::*, red, Div, ElementId, Render, RenderOnce, Stateful, View};
// use crate::prelude::*;
// use crate::{Icon, IconElement, Label, TextColor};
// use gpui::{prelude::*, red, Div, ElementId, Render, RenderOnce, View};
#[derive(RenderOnce, Clone)]
pub struct Tab {
id: ElementId,
title: String,
icon: Option<Icon>,
current: bool,
dirty: bool,
fs_status: FileSystemStatus,
git_status: GitStatus,
diagnostic_status: DiagnosticStatus,
close_side: IconSide,
}
// #[derive(RenderOnce, Clone)]
// pub struct Tab {
// id: ElementId,
// title: String,
// icon: Option<Icon>,
// current: bool,
// dirty: bool,
// fs_status: FileSystemStatus,
// git_status: GitStatus,
// diagnostic_status: DiagnosticStatus,
// close_side: IconSide,
// }
#[derive(Clone, Debug)]
struct TabDragState {
title: String,
}
// #[derive(Clone, Debug)]
// struct TabDragState {
// title: String,
// }
impl Render<Self> for TabDragState {
type Element = Div<Self>;
// impl Render for TabDragState {
// type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
div().w_8().h_4().bg(red())
}
}
// fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
// div().w_8().h_4().bg(red())
// }
// }
impl<V: 'static> Component<V> for Tab {
type Rendered = Stateful<V, Div<V>>;
// impl Component for Tab {
// type Rendered = gpui::Stateful<Div>;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
let has_fs_conflict = self.fs_status == FileSystemStatus::Conflict;
let is_deleted = self.fs_status == FileSystemStatus::Deleted;
// fn render(self, cx: &mut WindowContext) -> Self::Rendered {
// let has_fs_conflict = self.fs_status == FileSystemStatus::Conflict;
// let is_deleted = self.fs_status == FileSystemStatus::Deleted;
let label = match (self.git_status, is_deleted) {
(_, true) | (GitStatus::Deleted, false) => Label::new(self.title.clone())
.color(TextColor::Hidden)
.set_strikethrough(true),
(GitStatus::None, false) => Label::new(self.title.clone()),
(GitStatus::Created, false) => Label::new(self.title.clone()).color(TextColor::Created),
(GitStatus::Modified, false) => {
Label::new(self.title.clone()).color(TextColor::Modified)
}
(GitStatus::Renamed, false) => Label::new(self.title.clone()).color(TextColor::Accent),
(GitStatus::Conflict, false) => Label::new(self.title.clone()),
};
// let label = match (self.git_status, is_deleted) {
// (_, true) | (GitStatus::Deleted, false) => Label::new(self.title.clone())
// .color(TextColor::Hidden)
// .set_strikethrough(true),
// (GitStatus::None, false) => Label::new(self.title.clone()),
// (GitStatus::Created, false) => Label::new(self.title.clone()).color(TextColor::Created),
// (GitStatus::Modified, false) => {
// Label::new(self.title.clone()).color(TextColor::Modified)
// }
// (GitStatus::Renamed, false) => Label::new(self.title.clone()).color(TextColor::Accent),
// (GitStatus::Conflict, false) => Label::new(self.title.clone()),
// };
let close_icon = || IconElement::new(Icon::Close).color(TextColor::Muted);
// let close_icon = || IconElement::new(Icon::Close).color(TextColor::Muted);
let (tab_bg, tab_hover_bg, tab_active_bg) = match self.current {
false => (
cx.theme().colors().tab_inactive_background,
cx.theme().colors().ghost_element_hover,
cx.theme().colors().ghost_element_active,
),
true => (
cx.theme().colors().tab_active_background,
cx.theme().colors().element_hover,
cx.theme().colors().element_active,
),
};
// let (tab_bg, tab_hover_bg, tab_active_bg) = match self.current {
// false => (
// cx.theme().colors().tab_inactive_background,
// cx.theme().colors().ghost_element_hover,
// cx.theme().colors().ghost_element_active,
// ),
// true => (
// cx.theme().colors().tab_active_background,
// cx.theme().colors().element_hover,
// cx.theme().colors().element_active,
// ),
// };
let drag_state = TabDragState {
title: self.title.clone(),
};
// let drag_state = TabDragState {
// title: self.title.clone(),
// };
div()
.id(self.id.clone())
.on_drag(move |_view, cx| cx.build_view(|cx| drag_state.clone()))
.drag_over::<TabDragState>(|d| d.bg(cx.theme().colors().drop_target_background))
.on_drop(|_view, state: View<TabDragState>, cx| {
eprintln!("{:?}", state.read(cx));
})
.px_2()
.py_0p5()
.flex()
.items_center()
.justify_center()
.bg(tab_bg)
.hover(|h| h.bg(tab_hover_bg))
.active(|a| a.bg(tab_active_bg))
.child(
div()
.px_1()
.flex()
.items_center()
.gap_1p5()
.children(has_fs_conflict.then(|| {
IconElement::new(Icon::ExclamationTriangle)
.size(crate::IconSize::Small)
.color(TextColor::Warning)
}))
.children(self.icon.map(IconElement::new))
.children(if self.close_side == IconSide::Left {
Some(close_icon())
} else {
None
})
.child(label)
.children(if self.close_side == IconSide::Right {
Some(close_icon())
} else {
None
}),
)
}
}
// div()
// .id(self.id.clone())
// .on_drag(move |_view, cx| cx.build_view(|cx| drag_state.clone()))
// .drag_over::<TabDragState>(|d| d.bg(cx.theme().colors().drop_target_background))
// .on_drop(|_view, state: View<TabDragState>, cx| {
// eprintln!("{:?}", state.read(cx));
// })
// .px_2()
// .py_0p5()
// .flex()
// .items_center()
// .justify_center()
// .bg(tab_bg)
// .hover(|h| h.bg(tab_hover_bg))
// .active(|a| a.bg(tab_active_bg))
// .child(
// div()
// .px_1()
// .flex()
// .items_center()
// .gap_1p5()
// .children(has_fs_conflict.then(|| {
// IconElement::new(Icon::ExclamationTriangle)
// .size(crate::IconSize::Small)
// .color(TextColor::Warning)
// }))
// .children(self.icon.map(IconElement::new))
// .children(if self.close_side == IconSide::Left {
// Some(close_icon())
// } else {
// None
// })
// .child(label)
// .children(if self.close_side == IconSide::Right {
// Some(close_icon())
// } else {
// None
// }),
// )
// }
// }
impl Tab {
pub fn new(id: impl Into<ElementId>) -> Self {
Self {
id: id.into(),
title: "untitled".to_string(),
icon: None,
current: false,
dirty: false,
fs_status: FileSystemStatus::None,
git_status: GitStatus::None,
diagnostic_status: DiagnosticStatus::None,
close_side: IconSide::Right,
}
}
// impl Tab {
// pub fn new(id: impl Into<ElementId>) -> Self {
// Self {
// id: id.into(),
// title: "untitled".to_string(),
// icon: None,
// current: false,
// dirty: false,
// fs_status: FileSystemStatus::None,
// git_status: GitStatus::None,
// diagnostic_status: DiagnosticStatus::None,
// close_side: IconSide::Right,
// }
// }
pub fn current(mut self, current: bool) -> Self {
self.current = current;
self
}
// pub fn current(mut self, current: bool) -> Self {
// self.current = current;
// self
// }
pub fn title(mut self, title: String) -> Self {
self.title = title;
self
}
// pub fn title(mut self, title: String) -> Self {
// self.title = title;
// self
// }
pub fn icon<I>(mut self, icon: I) -> Self
where
I: Into<Option<Icon>>,
{
self.icon = icon.into();
self
}
// pub fn icon<I>(mut self, icon: I) -> Self
// where
// I: Into<Option<Icon>>,
// {
// self.icon = icon.into();
// self
// }
pub fn dirty(mut self, dirty: bool) -> Self {
self.dirty = dirty;
self
}
// pub fn dirty(mut self, dirty: bool) -> Self {
// self.dirty = dirty;
// self
// }
pub fn fs_status(mut self, fs_status: FileSystemStatus) -> Self {
self.fs_status = fs_status;
self
}
// pub fn fs_status(mut self, fs_status: FileSystemStatus) -> Self {
// self.fs_status = fs_status;
// self
// }
pub fn git_status(mut self, git_status: GitStatus) -> Self {
self.git_status = git_status;
self
}
// pub fn git_status(mut self, git_status: GitStatus) -> Self {
// self.git_status = git_status;
// self
// }
pub fn diagnostic_status(mut self, diagnostic_status: DiagnosticStatus) -> Self {
self.diagnostic_status = diagnostic_status;
self
}
// pub fn diagnostic_status(mut self, diagnostic_status: DiagnosticStatus) -> Self {
// self.diagnostic_status = diagnostic_status;
// self
// }
pub fn close_side(mut self, close_side: IconSide) -> Self {
self.close_side = close_side;
self
}
}
// pub fn close_side(mut self, close_side: IconSide) -> Self {
// self.close_side = close_side;
// self
// }
// }
#[cfg(feature = "stories")]
pub use stories::*;
// #[cfg(feature = "stories")]
// pub use stories::*;
#[cfg(feature = "stories")]
mod stories {
use super::*;
use crate::{h_stack, v_stack, Icon, Story};
use strum::IntoEnumIterator;
// #[cfg(feature = "stories")]
// mod stories {
// use super::*;
// use crate::{h_stack, v_stack, Icon, Story};
// use strum::IntoEnumIterator;
pub struct TabStory;
// pub struct TabStory;
impl Render<Self> for TabStory {
type Element = Div<Self>;
// impl Render for TabStory {
// type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
let git_statuses = GitStatus::iter();
let fs_statuses = FileSystemStatus::iter();
// fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
// let git_statuses = GitStatus::iter();
// let fs_statuses = FileSystemStatus::iter();
Story::container(cx)
.child(Story::title_for::<_, Tab>(cx))
.child(
h_stack().child(
v_stack()
.gap_2()
.child(Story::label(cx, "Default"))
.child(Tab::new("default")),
),
)
.child(
h_stack().child(
v_stack().gap_2().child(Story::label(cx, "Current")).child(
h_stack()
.gap_4()
.child(
Tab::new("current")
.title("Current".to_string())
.current(true),
)
.child(
Tab::new("not_current")
.title("Not Current".to_string())
.current(false),
),
),
),
)
.child(
h_stack().child(
v_stack()
.gap_2()
.child(Story::label(cx, "Titled"))
.child(Tab::new("titled").title("label".to_string())),
),
)
.child(
h_stack().child(
v_stack()
.gap_2()
.child(Story::label(cx, "With Icon"))
.child(
Tab::new("with_icon")
.title("label".to_string())
.icon(Some(Icon::Envelope)),
),
),
)
.child(
h_stack().child(
v_stack()
.gap_2()
.child(Story::label(cx, "Close Side"))
.child(
h_stack()
.gap_4()
.child(
Tab::new("left")
.title("Left".to_string())
.close_side(IconSide::Left),
)
.child(Tab::new("right").title("Right".to_string())),
),
),
)
.child(
v_stack()
.gap_2()
.child(Story::label(cx, "Git Status"))
.child(h_stack().gap_4().children(git_statuses.map(|git_status| {
Tab::new("git_status")
.title(git_status.to_string())
.git_status(git_status)
}))),
)
.child(
v_stack()
.gap_2()
.child(Story::label(cx, "File System Status"))
.child(h_stack().gap_4().children(fs_statuses.map(|fs_status| {
Tab::new("file_system_status")
.title(fs_status.to_string())
.fs_status(fs_status)
}))),
)
}
}
}
// Story::container(cx)
// .child(Story::title_for::<_, Tab>(cx))
// .child(
// h_stack().child(
// v_stack()
// .gap_2()
// .child(Story::label(cx, "Default"))
// .child(Tab::new("default")),
// ),
// )
// .child(
// h_stack().child(
// v_stack().gap_2().child(Story::label(cx, "Current")).child(
// h_stack()
// .gap_4()
// .child(
// Tab::new("current")
// .title("Current".to_string())
// .current(true),
// )
// .child(
// Tab::new("not_current")
// .title("Not Current".to_string())
// .current(false),
// ),
// ),
// ),
// )
// .child(
// h_stack().child(
// v_stack()
// .gap_2()
// .child(Story::label(cx, "Titled"))
// .child(Tab::new("titled").title("label".to_string())),
// ),
// )
// .child(
// h_stack().child(
// v_stack()
// .gap_2()
// .child(Story::label(cx, "With Icon"))
// .child(
// Tab::new("with_icon")
// .title("label".to_string())
// .icon(Some(Icon::Envelope)),
// ),
// ),
// )
// .child(
// h_stack().child(
// v_stack()
// .gap_2()
// .child(Story::label(cx, "Close Side"))
// .child(
// h_stack()
// .gap_4()
// .child(
// Tab::new("left")
// .title("Left".to_string())
// .close_side(IconSide::Left),
// )
// .child(Tab::new("right").title("Right".to_string())),
// ),
// ),
// )
// .child(
// v_stack()
// .gap_2()
// .child(Story::label(cx, "Git Status"))
// .child(h_stack().gap_4().children(git_statuses.map(|git_status| {
// Tab::new("git_status")
// .title(git_status.to_string())
// .git_status(git_status)
// }))),
// )
// .child(
// v_stack()
// .gap_2()
// .child(Story::label(cx, "File System Status"))
// .child(h_stack().gap_4().children(fs_statuses.map(|fs_status| {
// Tab::new("file_system_status")
// .title(fs_status.to_string())
// .fs_status(fs_status)
// }))),
// )
// }
// }
// }
+12 -12
View File
@@ -23,15 +23,15 @@ pub enum ToastOrigin {
///
/// Only one toast may be visible at a time.
#[derive(RenderOnce)]
pub struct Toast<V: 'static> {
pub struct Toast {
origin: ToastOrigin,
children: SmallVec<[AnyElement<V>; 2]>,
children: SmallVec<[AnyElement; 2]>,
}
impl<V: 'static> Component<V> for Toast<V> {
type Rendered = Div<V>;
impl Component for Toast {
type Rendered = Div;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
fn render(self, cx: &mut WindowContext) -> Self::Rendered {
let mut div = div();
if self.origin == ToastOrigin::Bottom {
@@ -54,7 +54,7 @@ impl<V: 'static> Component<V> for Toast<V> {
}
}
impl<V: 'static> Toast<V> {
impl Toast {
pub fn new(origin: ToastOrigin) -> Self {
Self {
origin,
@@ -62,7 +62,7 @@ impl<V: 'static> Toast<V> {
}
}
fn render(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
fn render(self, cx: &mut WindowContext) -> impl Element {
let mut div = div();
if self.origin == ToastOrigin::Bottom {
@@ -85,8 +85,8 @@ impl<V: 'static> Toast<V> {
}
}
impl<V: 'static> ParentElement<V> for Toast<V> {
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
impl ParentElement for Toast {
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> {
&mut self.children
}
}
@@ -104,12 +104,12 @@ mod stories {
pub struct ToastStory;
impl Render<Self> for ToastStory {
type Element = Div<Self>;
impl Render for ToastStory {
type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
Story::container(cx)
.child(Story::title_for::<_, Toast<Self>>(cx))
.child(Story::title_for::<Toast<Self>>(cx))
.child(Story::label(cx, "Default"))
.child(Toast::new(ToastOrigin::Bottom).child(Label::new("label")))
}
+1 -1
View File
@@ -44,7 +44,7 @@ impl From<bool> for Toggle {
}
}
pub fn disclosure_control<V: 'static>(toggle: Toggle) -> impl Element<V> {
pub fn disclosure_control(toggle: Toggle) -> impl Element {
match (toggle.is_toggleable(), toggle.is_toggled()) {
(false, _) => div(),
(_, true) => div().child(
+4 -4
View File
@@ -4,10 +4,10 @@ use gpui::{Div, RenderOnce};
#[derive(RenderOnce)]
pub struct ToolDivider;
impl<V: 'static> Component<V> for ToolDivider {
type Rendered = Div<V>;
impl Component for ToolDivider {
type Rendered = Div;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
fn render(self, cx: &mut WindowContext) -> Self::Rendered {
div().w_px().h_3().bg(cx.theme().colors().border)
}
}
@@ -17,7 +17,7 @@ impl ToolDivider {
Self
}
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
fn render(self, cx: &mut WindowContext) -> impl Element {
div().w_px().h_3().bg(cx.theme().colors().border)
}
}
+2 -2
View File
@@ -67,8 +67,8 @@ impl Tooltip {
}
}
impl Render<Self> for Tooltip {
type Element = Overlay<Self>;
impl Render for Tooltip {
type Element = Overlay;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
let ui_font = ThemeSettings::get_global(cx).ui_font.family.clone();