History

Allow dragging tabs (#3616)

Max Brunsfeld committed 2 years ago

Commit e09b07d2 parents 2e00da5 636222110 files · +154 −587Browse files

Unified · Split

10 files
  1. crates/collab_ui2/src/chat_panel.rs +5 −1
  2. crates/gpui2/src/elements/div.rs +28 −10
  3. crates/gpui2/src/styled.rs +1 −1
  4. crates/picker2/src/picker2.rs +1 −1
  5. crates/storybook2/src/story_selector.rs +1 −1
  6. crates/ui2/src/components/list/list_item.rs +0 −8
  7. crates/ui2/src/components/stories/tab_bar.rs +3 −13
  8. crates/ui2/src/components/tab.rs +15 −37
  9. crates/ui2/src/components/tab_bar.rs +14 −6
  10. crates/workspace2/src/pane.rs +86 −509
crates/collab_ui2/src/chat_panel.rs+5−1
@@ -288,7 +288,11 @@ impl ChatPanel { · 287 unmodified lines
288 ),288 ),
289 ),289 ),
290 )290 )
291 .child(div().grow().child(self.render_active_channel_messages(cx)))291 .child(
292 div()
293 .flex_grow()
294 .child(self.render_active_channel_messages(cx)),
295 )
292 .child(296 .child(
293 div()297 div()
294 .z_index(1)298 .z_index(1)
crates/gpui2/src/elements/div.rs+28−10
@@ -29,7 +29,7 @@ pub struct GroupStyle { · 28 unmodified lines
29 pub style: Box<StyleRefinement>,29 pub style: Box<StyleRefinement>,
30}30}
31 31
32pub trait InteractiveElement: Sized + Element {32pub trait InteractiveElement: Sized {
33 fn interactivity(&mut self) -> &mut Interactivity;33 fn interactivity(&mut self) -> &mut Interactivity;
34 34
35 fn group(mut self, group: impl Into<SharedString>) -> Self {35 fn group(mut self, group: impl Into<SharedString>) -> Self {
@@ -61,6 +61,10 @@ pub trait InteractiveElement: Sized + Element { · 25 unmodified lines
61 }61 }
62 62
63 fn hover(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self {63 fn hover(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self {
64 debug_assert!(
65 self.interactivity().hover_style.is_none(),
66 "hover style already set"
67 );
64 self.interactivity().hover_style = Some(Box::new(f(StyleRefinement::default())));68 self.interactivity().hover_style = Some(Box::new(f(StyleRefinement::default())));
65 self69 self
66 }70 }
@@ -436,7 +440,6 @@ pub trait StatefulInteractiveElement: InteractiveElement { · 369 unmodified lines
436 "calling tooltip more than once on the same element is not supported"440 "calling tooltip more than once on the same element is not supported"
437 );441 );
438 self.interactivity().tooltip_builder = Some(Rc::new(build_tooltip));442 self.interactivity().tooltip_builder = Some(Rc::new(build_tooltip));
439
440 self443 self
441 }444 }
442}445}
@@ -1013,6 +1016,10 @@ impl Interactivity { · 570 unmodified lines
1013 1016
1014 let overflow = style.overflow;1017 let overflow = style.overflow;
1015 if overflow.x == Overflow::Scroll || overflow.y == Overflow::Scroll {1018 if overflow.x == Overflow::Scroll || overflow.y == Overflow::Scroll {
1019 if let Some(scroll_handle) = &self.scroll_handle {
1020 scroll_handle.0.borrow_mut().overflow = overflow;
1021 }
1022
1016 let scroll_offset = element_state1023 let scroll_offset = element_state
1017 .scroll_offset1024 .scroll_offset
1018 .get_or_insert_with(Rc::default)1025 .get_or_insert_with(Rc::default)
@@ -1314,16 +1321,16 @@ where · 295 unmodified lines
1314 1321
1315impl<E> IntoElement for Focusable<E>1322impl<E> IntoElement for Focusable<E>
1316where1323where
1317 E: Element,1324 E: IntoElement,
1318{1325{
1319 type Element = E;1326 type Element = E::Element;
1320 1327
1321 fn element_id(&self) -> Option<ElementId> {1328 fn element_id(&self) -> Option<ElementId> {
1322 self.element.element_id()1329 self.element.element_id()
1323 }1330 }
1324 1331
1325 fn into_element(self) -> Self::Element {1332 fn into_element(self) -> Self::Element {
1326 self.element1333 self.element.into_element()
1327 }1334 }
1328}1335}
1329 1336
@@ -1417,6 +1424,7 @@ struct ScrollHandleState { · 87 unmodified lines
1417 bounds: Bounds<Pixels>,1424 bounds: Bounds<Pixels>,
1418 child_bounds: Vec<Bounds<Pixels>>,1425 child_bounds: Vec<Bounds<Pixels>>,
1419 requested_scroll_top: Option<(usize, Pixels)>,1426 requested_scroll_top: Option<(usize, Pixels)>,
1427 overflow: Point<Overflow>,
1420}1428}
1421 1429
1422#[derive(Clone)]1430#[derive(Clone)]
@@ -1462,12 +1470,22 @@ impl ScrollHandle { · 39 unmodified lines
1462 return;1470 return;
1463 };1471 };
1464 1472
1465 let scroll_offset = state.offset.borrow().y;1473 let mut scroll_offset = state.offset.borrow_mut();
1466 1474
1467 if bounds.top() + scroll_offset < state.bounds.top() {1475 if state.overflow.y == Overflow::Scroll {
1468 state.offset.borrow_mut().y = state.bounds.top() - bounds.top();1476 if bounds.top() + scroll_offset.y < state.bounds.top() {
1469 } else if bounds.bottom() + scroll_offset > state.bounds.bottom() {1477 scroll_offset.y = state.bounds.top() - bounds.top();
1470 state.offset.borrow_mut().y = state.bounds.bottom() - bounds.bottom();1478 } else if bounds.bottom() + scroll_offset.y > state.bounds.bottom() {
1479 scroll_offset.y = state.bounds.bottom() - bounds.bottom();
1480 }
1481 }
1482
1483 if state.overflow.x == Overflow::Scroll {
1484 if bounds.left() + scroll_offset.x < state.bounds.left() {
1485 scroll_offset.x = state.bounds.left() - bounds.left();
1486 } else if bounds.right() + scroll_offset.x > state.bounds.right() {
1487 scroll_offset.x = state.bounds.right() - bounds.right();
1488 }
1471 }1489 }
1472 }1490 }
1473 1491
crates/gpui2/src/styled.rs+1−1
@@ -303,7 +303,7 @@ pub trait Styled: Sized { · 302 unmodified lines
303 303
304 /// Sets the element to allow a flex item to grow to fill any available space.304 /// Sets the element to allow a flex item to grow to fill any available space.
305 /// [Docs](https://tailwindcss.com/docs/flex-grow)305 /// [Docs](https://tailwindcss.com/docs/flex-grow)
306 fn grow(mut self) -> Self {306 fn flex_grow(mut self) -> Self {
307 self.style().flex_grow = Some(1.);307 self.style().flex_grow = Some(1.);
308 self308 self
309 }309 }
crates/picker2/src/picker2.rs+1−1
@@ -228,7 +228,7 @@ impl<D: PickerDelegate> Render for Picker<D> { · 227 unmodified lines
228 .when(self.delegate.match_count() > 0, |el| {228 .when(self.delegate.match_count() > 0, |el| {
229 el.child(229 el.child(
230 v_stack()230 v_stack()
231 .grow()231 .flex_grow()
232 .child(232 .child(
233 uniform_list(233 uniform_list(
234 cx.view().clone(),234 cx.view().clone(),
crates/storybook2/src/story_selector.rs+1−1
@@ -61,7 +61,7 @@ impl ComponentStory { · 60 unmodified lines
61 Self::Scroll => ScrollStory::view(cx).into(),61 Self::Scroll => ScrollStory::view(cx).into(),
62 Self::Text => TextStory::view(cx).into(),62 Self::Text => TextStory::view(cx).into(),
63 Self::Tab => cx.build_view(|_| ui::TabStory).into(),63 Self::Tab => cx.build_view(|_| ui::TabStory).into(),
64 Self::TabBar => cx.build_view(|cx| ui::TabBarStory::new(cx)).into(),64 Self::TabBar => cx.build_view(|_| ui::TabBarStory).into(),
65 Self::ViewportUnits => cx.build_view(|_| crate::stories::ViewportUnitsStory).into(),65 Self::ViewportUnits => cx.build_view(|_| crate::stories::ViewportUnitsStory).into(),
66 Self::ZIndex => cx.build_view(|_| ZIndexStory).into(),66 Self::ZIndex => cx.build_view(|_| ZIndexStory).into(),
67 Self::Picker => PickerStory::new(cx).into(),67 Self::Picker => PickerStory::new(cx).into(),
crates/ui2/src/components/list/list_item.rs+0−8
@@ -54,14 +54,6 @@ impl ListItem { · 53 unmodified lines
54 self54 self
55 }55 }
56 56
57 pub fn on_drag(
58 mut self,
59 handler: impl Fn(&MouseDownEvent, &mut WindowContext) + 'static,
60 ) -> Self {
61 self.on_secondary_mouse_down = Some(Box::new(handler));
62 self
63 }
64
65 pub fn tooltip(mut self, tooltip: impl Fn(&mut WindowContext) -> AnyView + 'static) -> Self {57 pub fn tooltip(mut self, tooltip: impl Fn(&mut WindowContext) -> AnyView + 'static) -> Self {
66 self.tooltip = Some(Box::new(tooltip));58 self.tooltip = Some(Box::new(tooltip));
67 self59 self
crates/ui2/src/components/stories/tab_bar.rs+3−13
@@ -1,19 +1,9 @@
1use gpui::{Div, FocusHandle, Render};1use gpui::{Div, Render};
2use story::Story;2use story::Story;
3 3
4use crate::{prelude::*, Tab, TabBar, TabPosition};4use crate::{prelude::*, Tab, TabBar, TabPosition};
5 5
6pub struct TabBarStory {6pub struct TabBarStory;
7 tab_bar_focus_handle: FocusHandle,
8}
9
10impl TabBarStory {
11 pub fn new(cx: &mut ViewContext<Self>) -> Self {
12 Self {
13 tab_bar_focus_handle: cx.focus_handle(),
14 }
15 }
16}
17 7
18impl Render for TabBarStory {8impl Render for TabBarStory {
19 type Element = Div;9 type Element = Div;
@@ -48,7 +38,7 @@ impl Render for TabBarStory { · 28 unmodified lines
48 .child(Story::label("Default"))38 .child(Story::label("Default"))
49 .child(39 .child(
50 h_stack().child(40 h_stack().child(
51 TabBar::new("tab_bar_1", self.tab_bar_focus_handle.clone())41 TabBar::new("tab_bar_1")
52 .start_child(42 .start_child(
53 IconButton::new("navigate_backward", Icon::ArrowLeft)43 IconButton::new("navigate_backward", Icon::ArrowLeft)
54 .icon_size(IconSize::Small),44 .icon_size(IconSize::Small),
crates/ui2/src/components/tab.rs+15−37
@@ -1,10 +1,7 @@
1use std::cmp::Ordering;
2use std::rc::Rc;
3
4use gpui::{AnyElement, AnyView, ClickEvent, IntoElement, MouseButton};
5use smallvec::SmallVec;
6
7use crate::prelude::*;1use crate::prelude::*;
2use gpui::{AnyElement, IntoElement, Stateful};
3use smallvec::SmallVec;
4use std::cmp::Ordering;
8 5
9/// The position of a [`Tab`] within a list of tabs.6/// The position of a [`Tab`] within a list of tabs.
10#[derive(Debug, PartialEq, Eq, Clone, Copy)]7#[derive(Debug, PartialEq, Eq, Clone, Copy)]
@@ -29,12 +26,10 @@ pub enum TabCloseSide { · 18 unmodified lines
29 26
30#[derive(IntoElement)]27#[derive(IntoElement)]
31pub struct Tab {28pub struct Tab {
32 id: ElementId,29 div: Stateful<Div>,
33 selected: bool,30 selected: bool,
34 position: TabPosition,31 position: TabPosition,
35 close_side: TabCloseSide,32 close_side: TabCloseSide,
36 on_click: Option<Rc<dyn Fn(&ClickEvent, &mut WindowContext) + 'static>>,
37 tooltip: Option<Box<dyn Fn(&mut WindowContext) -> AnyView + 'static>>,
38 start_slot: Option<AnyElement>,33 start_slot: Option<AnyElement>,
39 end_slot: Option<AnyElement>,34 end_slot: Option<AnyElement>,
40 children: SmallVec<[AnyElement; 2]>,35 children: SmallVec<[AnyElement; 2]>,
@@ -43,12 +38,10 @@ pub struct Tab { · 2 unmodified lines
43impl Tab {38impl Tab {
44 pub fn new(id: impl Into<ElementId>) -> Self {39 pub fn new(id: impl Into<ElementId>) -> Self {
45 Self {40 Self {
46 id: id.into(),41 div: div().id(id),
47 selected: false,42 selected: false,
48 position: TabPosition::First,43 position: TabPosition::First,
49 close_side: TabCloseSide::End,44 close_side: TabCloseSide::End,
50 on_click: None,
51 tooltip: None,
52 start_slot: None,45 start_slot: None,
53 end_slot: None,46 end_slot: None,
54 children: SmallVec::new(),47 children: SmallVec::new(),
@@ -65,16 +58,6 @@ impl Tab { · 10 unmodified lines
65 self58 self
66 }59 }
67 60
68 pub fn on_click(mut self, handler: impl Fn(&ClickEvent, &mut WindowContext) + 'static) -> Self {
69 self.on_click = Some(Rc::new(handler));
70 self
71 }
72
73 pub fn tooltip(mut self, tooltip: impl Fn(&mut WindowContext) -> AnyView + 'static) -> Self {
74 self.tooltip = Some(Box::new(tooltip));
75 self
76 }
77
78 pub fn start_slot<E: IntoElement>(mut self, element: impl Into<Option<E>>) -> Self {61 pub fn start_slot<E: IntoElement>(mut self, element: impl Into<Option<E>>) -> Self {
79 self.start_slot = element.into().map(IntoElement::into_any_element);62 self.start_slot = element.into().map(IntoElement::into_any_element);
80 self63 self
@@ -86,6 +69,14 @@ impl Tab { · 5 unmodified lines
86 }69 }
87}70}
88 71
72impl InteractiveElement for Tab {
73 fn interactivity(&mut self) -> &mut gpui::Interactivity {
74 self.div.interactivity()
75 }
76}
77
78impl StatefulInteractiveElement for Tab {}
79
89impl Selectable for Tab {80impl Selectable for Tab {
90 fn selected(mut self, selected: bool) -> Self {81 fn selected(mut self, selected: bool) -> Self {
91 self.selected = selected;82 self.selected = selected;
@@ -100,7 +91,7 @@ impl ParentElement for Tab { · 8 unmodified lines
100}91}
101 92
102impl RenderOnce for Tab {93impl RenderOnce for Tab {
103 type Rendered = Div;94 type Rendered = Stateful<Div>;
104 95
105 fn render(self, cx: &mut WindowContext) -> Self::Rendered {96 fn render(self, cx: &mut WindowContext) -> Self::Rendered {
106 const HEIGHT_IN_REMS: f32 = 30. / 16.;97 const HEIGHT_IN_REMS: f32 = 30. / 16.;
@@ -120,7 +111,7 @@ impl RenderOnce for Tab { · 13 unmodified lines
120 ),111 ),
121 };112 };
122 113
123 div()114 self.div
124 .h(rems(HEIGHT_IN_REMS))115 .h(rems(HEIGHT_IN_REMS))
125 .bg(tab_bg)116 .bg(tab_bg)
126 .border_color(cx.theme().colors().border)117 .border_color(cx.theme().colors().border)
@@ -146,7 +137,6 @@ impl RenderOnce for Tab { · 19 unmodified lines
146 .child(137 .child(
147 h_stack()138 h_stack()
148 .group("")139 .group("")
149 .id(self.id)
150 .relative()140 .relative()
151 .h_full()141 .h_full()
152 .px_5()142 .px_5()
@@ -154,18 +144,6 @@ impl RenderOnce for Tab { · 1 unmodified line
154 .text_color(text_color)144 .text_color(text_color)
155 // .hover(|style| style.bg(tab_hover_bg))145 // .hover(|style| style.bg(tab_hover_bg))
156 // .active(|style| style.bg(tab_active_bg))146 // .active(|style| style.bg(tab_active_bg))
157 .when_some(self.on_click, |tab, on_click| {
158 tab.cursor_pointer().on_click(move |event, cx| {
159 // HACK: GPUI currently fires `on_click` with any mouse button,
160 // but we only care about the left button.
161 if event.down.button == MouseButton::Left {
162 (on_click)(event, cx)
163 }
164 })
165 })
166 .when_some(self.tooltip, |tab, tooltip| {
167 tab.tooltip(move |cx| tooltip(cx))
168 })
169 .child(147 .child(
170 h_stack()148 h_stack()
171 .w_3()149 .w_3()
crates/ui2/src/components/tab_bar.rs+14−6
@@ -1,4 +1,4 @@
1use gpui::{AnyElement, FocusHandle, Focusable, Stateful};1use gpui::{AnyElement, ScrollHandle, Stateful};
2use smallvec::SmallVec;2use smallvec::SmallVec;
3 3
4use crate::prelude::*;4use crate::prelude::*;
@@ -6,23 +6,28 @@ use crate::prelude::*; · 1 unmodified line
6#[derive(IntoElement)]6#[derive(IntoElement)]
7pub struct TabBar {7pub struct TabBar {
8 id: ElementId,8 id: ElementId,
9 focus_handle: FocusHandle,
10 start_children: SmallVec<[AnyElement; 2]>,9 start_children: SmallVec<[AnyElement; 2]>,
11 children: SmallVec<[AnyElement; 2]>,10 children: SmallVec<[AnyElement; 2]>,
12 end_children: SmallVec<[AnyElement; 2]>,11 end_children: SmallVec<[AnyElement; 2]>,
12 scroll_handle: Option<ScrollHandle>,
13}13}
14 14
15impl TabBar {15impl TabBar {
16 pub fn new(id: impl Into<ElementId>, focus_handle: FocusHandle) -> Self {16 pub fn new(id: impl Into<ElementId>) -> Self {
17 Self {17 Self {
18 id: id.into(),18 id: id.into(),
19 focus_handle,
20 start_children: SmallVec::new(),19 start_children: SmallVec::new(),
21 children: SmallVec::new(),20 children: SmallVec::new(),
22 end_children: SmallVec::new(),21 end_children: SmallVec::new(),
22 scroll_handle: None,
23 }23 }
24 }24 }
25 25
26 pub fn track_scroll(mut self, scroll_handle: ScrollHandle) -> Self {
27 self.scroll_handle = Some(scroll_handle);
28 self
29 }
30
26 pub fn start_children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> {31 pub fn start_children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> {
27 &mut self.start_children32 &mut self.start_children
28 }33 }
@@ -84,7 +89,7 @@ impl ParentElement for TabBar { · 55 unmodified lines
84}89}
85 90
86impl RenderOnce for TabBar {91impl RenderOnce for TabBar {
87 type Rendered = Focusable<Stateful<Div>>;92 type Rendered = Stateful<Div>;
88 93
89 fn render(self, cx: &mut WindowContext) -> Self::Rendered {94 fn render(self, cx: &mut WindowContext) -> Self::Rendered {
90 const HEIGHT_IN_REMS: f32 = 30. / 16.;95 const HEIGHT_IN_REMS: f32 = 30. / 16.;
@@ -92,7 +97,6 @@ impl RenderOnce for TabBar { · 1 unmodified line
92 div()97 div()
93 .id(self.id)98 .id(self.id)
94 .group("tab_bar")99 .group("tab_bar")
95 .track_focus(&self.focus_handle)
96 .flex()100 .flex()
97 .flex_none()101 .flex_none()
98 .w_full()102 .w_full()
@@ -128,7 +132,11 @@ impl RenderOnce for TabBar { · 29 unmodified lines
128 h_stack()132 h_stack()
129 .id("tabs")133 .id("tabs")
130 .z_index(2)134 .z_index(2)
135 .flex_grow()
131 .overflow_x_scroll()136 .overflow_x_scroll()
137 .when_some(self.scroll_handle, |cx, scroll_handle| {
138 cx.track_scroll(&scroll_handle)
139 })
132 .children(self.children),140 .children(self.children),
133 ),141 ),
134 )142 )
crates/workspace2/src/pane.rs+86−509
@@ -10,7 +10,7 @@ use gpui::{ · 9 unmodified lines
10 actions, impl_actions, overlay, prelude::*, Action, AnchorCorner, AnyWeakView, AppContext,10 actions, impl_actions, overlay, prelude::*, Action, AnchorCorner, AnyWeakView, AppContext,
11 AsyncWindowContext, DismissEvent, Div, EntityId, EventEmitter, FocusHandle, Focusable,11 AsyncWindowContext, DismissEvent, Div, EntityId, EventEmitter, FocusHandle, Focusable,
12 FocusableView, Model, MouseButton, NavigationDirection, Pixels, Point, PromptLevel, Render,12 FocusableView, Model, MouseButton, NavigationDirection, Pixels, Point, PromptLevel, Render,
13 Subscription, Task, View, ViewContext, VisualContext, WeakView, WindowContext,13 ScrollHandle, Subscription, Task, View, ViewContext, VisualContext, WeakView, WindowContext,
14};14};
15use parking_lot::Mutex;15use parking_lot::Mutex;
16use project::{Project, ProjectEntryId, ProjectPath};16use project::{Project, ProjectEntryId, ProjectPath};
@@ -25,13 +25,14 @@ use std::{ · 8 unmodified lines
25 Arc,25 Arc,
26 },26 },
27};27};
28use theme::ThemeSettings;
28 29
29use ui::{30use ui::{
30 h_stack, prelude::*, right_click_menu, ButtonSize, Color, Icon, IconButton, IconSize,31 h_stack, prelude::*, right_click_menu, ButtonSize, Color, Icon, IconButton, IconSize,
31 Indicator, Label, Tab, TabBar, TabPosition, Tooltip,32 Indicator, Label, Tab, TabBar, TabPosition, Tooltip,
32};33};
33use ui::{v_stack, ContextMenu};34use ui::{v_stack, ContextMenu};
34use util::{maybe, truncate_and_remove_front};35use util::{maybe, truncate_and_remove_front, ResultExt};
35 36
36#[derive(PartialEq, Clone, Copy, Deserialize, Debug)]37#[derive(PartialEq, Clone, Copy, Deserialize, Debug)]
37#[serde(rename_all = "camelCase")]38#[serde(rename_all = "camelCase")]
@@ -176,10 +177,8 @@ pub struct Pane { · 138 unmodified lines
176 was_focused: bool,177 was_focused: bool,
177 active_item_index: usize,178 active_item_index: usize,
178 last_focused_view_by_item: HashMap<EntityId, FocusHandle>,179 last_focused_view_by_item: HashMap<EntityId, FocusHandle>,
179 autoscroll: bool,
180 nav_history: NavHistory,180 nav_history: NavHistory,
181 toolbar: View<Toolbar>,181 toolbar: View<Toolbar>,
182 tab_bar_focus_handle: FocusHandle,
183 new_item_menu: Option<View<ContextMenu>>,182 new_item_menu: Option<View<ContextMenu>>,
184 split_item_menu: Option<View<ContextMenu>>,183 split_item_menu: Option<View<ContextMenu>>,
185 // tab_context_menu: ViewHandle<ContextMenu>,184 // tab_context_menu: ViewHandle<ContextMenu>,
@@ -189,6 +188,7 @@ pub struct Pane { · 3 unmodified lines
189 can_split: bool,188 can_split: bool,
190 // render_tab_bar_buttons: Rc<dyn Fn(&mut Pane, &mut ViewContext<Pane>) -> AnyElement<Pane>>,189 // render_tab_bar_buttons: Rc<dyn Fn(&mut Pane, &mut ViewContext<Pane>) -> AnyElement<Pane>>,
191 subscriptions: Vec<Subscription>,190 subscriptions: Vec<Subscription>,
191 tab_bar_scroll_handle: ScrollHandle,
192}192}
193 193
194pub struct ItemNavHistory {194pub struct ItemNavHistory {
@@ -231,6 +231,14 @@ pub struct NavigationEntry { · 36 unmodified lines
231 pub timestamp: usize,231 pub timestamp: usize,
232}232}
233 233
234struct DraggedTab {
235 pub pane: View<Pane>,
236 pub ix: usize,
237 pub item_id: EntityId,
238 pub detail: usize,
239 pub is_active: bool,
240}
241
234// pub struct DraggedItem {242// pub struct DraggedItem {
235// pub handle: Box<dyn ItemHandle>,243// pub handle: Box<dyn ItemHandle>,
236// pub pane: WeakView<Pane>,244// pub pane: WeakView<Pane>,
@@ -344,7 +352,6 @@ impl Pane { · 107 unmodified lines
344 zoomed: false,352 zoomed: false,
345 active_item_index: 0,353 active_item_index: 0,
346 last_focused_view_by_item: Default::default(),354 last_focused_view_by_item: Default::default(),
347 autoscroll: false,
348 nav_history: NavHistory(Arc::new(Mutex::new(NavHistoryState {355 nav_history: NavHistory(Arc::new(Mutex::new(NavHistoryState {
349 mode: NavigationMode::Normal,356 mode: NavigationMode::Normal,
350 backward_stack: Default::default(),357 backward_stack: Default::default(),
@@ -355,9 +362,9 @@ impl Pane { · 4 unmodified lines
355 next_timestamp,362 next_timestamp,
356 }))),363 }))),
357 toolbar: cx.build_view(|_| Toolbar::new()),364 toolbar: cx.build_view(|_| Toolbar::new()),
358 tab_bar_focus_handle: cx.focus_handle(),
359 new_item_menu: None,365 new_item_menu: None,
360 split_item_menu: None,366 split_item_menu: None,
367 tab_bar_scroll_handle: ScrollHandle::new(),
361 // tab_bar_context_menu: TabBarContextMenu {368 // tab_bar_context_menu: TabBarContextMenu {
362 // kind: TabBarContextMenuKind::New,369 // kind: TabBarContextMenuKind::New,
363 // handle: context_menu,370 // handle: context_menu,
@@ -460,8 +467,8 @@ impl Pane { · 96 unmodified lines
460 }467 }
461 468
462 active_item.focus_handle(cx).focus(cx);469 active_item.focus_handle(cx).focus(cx);
463 } else if !self.tab_bar_focus_handle.contains_focused(cx) {470 } else if let Some(focused) = cx.focused() {
464 if let Some(focused) = cx.focused() {471 if !self.context_menu_focused(cx) {
465 self.last_focused_view_by_item472 self.last_focused_view_by_item
466 .insert(active_item.item_id(), focused);473 .insert(active_item.item_id(), focused);
467 }474 }
@@ -469,6 +476,13 @@ impl Pane { · 1 unmodified line
469 }476 }
470 }477 }
471 478
479 fn context_menu_focused(&self, cx: &mut ViewContext<Self>) -> bool {
480 self.new_item_menu
481 .as_ref()
482 .or(self.split_item_menu.as_ref())
483 .map_or(false, |menu| menu.focus_handle(cx).is_focused(cx))
484 }
485
472 fn focus_out(&mut self, cx: &mut ViewContext<Self>) {486 fn focus_out(&mut self, cx: &mut ViewContext<Self>) {
473 self.was_focused = false;487 self.was_focused = false;
474 self.toolbar.update(cx, |toolbar, cx| {488 self.toolbar.update(cx, |toolbar, cx| {
@@ -785,7 +799,7 @@ impl Pane { · 310 unmodified lines
785 self.focus_active_item(cx);799 self.focus_active_item(cx);
786 }800 }
787 801
788 self.autoscroll = true;802 self.tab_bar_scroll_handle.scroll_to_item(index);
789 cx.notify();803 cx.notify();
790 }804 }
791 }805 }
@@ -1478,8 +1492,7 @@ impl Pane { · 686 unmodified lines
1478 Some(Indicator::dot().color(indicator_color))1492 Some(Indicator::dot().color(indicator_color))
1479 });1493 });
1480 1494
1481 let id = item.item_id();1495 let item_id = item.item_id();
1482
1483 let is_first_item = ix == 0;1496 let is_first_item = ix == 0;
1484 let is_last_item = ix == self.items.len() - 1;1497 let is_last_item = ix == self.items.len() - 1;
1485 let position_relative_to_active_item = ix.cmp(&self.active_item_index);1498 let position_relative_to_active_item = ix.cmp(&self.active_item_index);
@@ -1501,11 +1514,24 @@ impl Pane { · 15 unmodified lines
1501 .on_click(cx.listener(move |pane: &mut Self, event, cx| {1514 .on_click(cx.listener(move |pane: &mut Self, event, cx| {
1502 pane.activate_item(ix, true, true, cx)1515 pane.activate_item(ix, true, true, cx)
1503 }))1516 }))
1504 // .on_drag(move |pane, cx| pane.render_tab(ix, item.boxed_clone(), detail, cx))1517 .on_drag({
1505 // .drag_over::<DraggedTab>(|d| d.bg(cx.theme().colors().element_drop_target))1518 let pane = cx.view().clone();
1506 // .on_drop(|_view, state: View<DraggedTab>, cx| {1519 move |cx| {
1507 // eprintln!("{:?}", state.read(cx));1520 cx.build_view(|cx| DraggedTab {
1508 // })1521 pane: pane.clone(),
1522 detail,
1523 item_id,
1524 is_active,
1525 ix,
1526 })
1527 }
1528 })
1529 .drag_over::<DraggedTab>(|tab| tab.bg(cx.theme().colors().tab_active_background))
1530 .on_drop(
1531 cx.listener(move |this, dragged_tab: &View<DraggedTab>, cx| {
1532 this.handle_tab_drop(dragged_tab, ix, cx)
1533 }),
1534 )
1509 .when_some(item.tab_tooltip_text(cx), |tab, text| {1535 .when_some(item.tab_tooltip_text(cx), |tab, text| {
1510 tab.tooltip(move |cx| Tooltip::text(text.clone(), cx))1536 tab.tooltip(move |cx| Tooltip::text(text.clone(), cx))
1511 })1537 })
@@ -1516,7 +1542,7 @@ impl Pane { · 4 unmodified lines
1516 .size(ButtonSize::None)1542 .size(ButtonSize::None)
1517 .icon_size(IconSize::XSmall)1543 .icon_size(IconSize::XSmall)
1518 .on_click(cx.listener(move |pane, _, cx| {1544 .on_click(cx.listener(move |pane, _, cx| {
1519 pane.close_item_by_id(id, SaveIntent::Close, cx)1545 pane.close_item_by_id(item_id, SaveIntent::Close, cx)
1520 .detach_and_log_err(cx);1546 .detach_and_log_err(cx);
1521 })),1547 })),
1522 )1548 )
@@ -1562,7 +1588,8 @@ impl Pane { · 39 unmodified lines
1562 }1588 }
1563 1589
1564 fn render_tab_bar(&mut self, cx: &mut ViewContext<'_, Pane>) -> impl IntoElement {1590 fn render_tab_bar(&mut self, cx: &mut ViewContext<'_, Pane>) -> impl IntoElement {
1565 TabBar::new("tab_bar", self.tab_bar_focus_handle.clone())1591 TabBar::new("tab_bar")
1592 .track_scroll(self.tab_bar_scroll_handle.clone())
1566 .start_child(1593 .start_child(
1567 IconButton::new("navigate_backward", Icon::ArrowLeft)1594 IconButton::new("navigate_backward", Icon::ArrowLeft)
1568 .icon_size(IconSize::Small)1595 .icon_size(IconSize::Small)
@@ -1635,6 +1662,19 @@ impl Pane { · 66 unmodified lines
1635 .zip(self.tab_details(cx))1662 .zip(self.tab_details(cx))
1636 .map(|((ix, item), detail)| self.render_tab(ix, item, detail, cx)),1663 .map(|((ix, item), detail)| self.render_tab(ix, item, detail, cx)),
1637 )1664 )
1665 .child(
1666 div()
1667 .h_full()
1668 .flex_grow()
1669 .drag_over::<DraggedTab>(|bar| {
1670 bar.bg(cx.theme().colors().tab_active_background)
1671 })
1672 .on_drop(
1673 cx.listener(move |this, dragged_tab: &View<DraggedTab>, cx| {
1674 this.handle_tab_drop(dragged_tab, this.items.len(), cx)
1675 }),
1676 ),
1677 )
1638 }1678 }
1639 1679
1640 fn render_menu_overlay(menu: &View<ContextMenu>) -> Div {1680 fn render_menu_overlay(menu: &View<ContextMenu>) -> Div {
@@ -1647,161 +1687,6 @@ impl Pane { · 6 unmodified lines
1647 .child(overlay().anchor(AnchorCorner::TopRight).child(menu.clone()))1687 .child(overlay().anchor(AnchorCorner::TopRight).child(menu.clone()))
1648 }1688 }
1649 1689
1650 // fn render_tabs(&mut self, cx: &mut ViewContext<Self>) -> impl Element<Self> {
1651 // let theme = theme::current(cx).clone();
1652
1653 // let pane = cx.handle().downgrade();
1654 // let autoscroll = if mem::take(&mut self.autoscroll) {
1655 // Some(self.active_item_index)
1656 // } else {
1657 // None
1658 // };
1659
1660 // let pane_active = self.has_focus;
1661
1662 // enum Tabs {}
1663 // let mut row = Flex::row().scrollable::<Tabs>(1, autoscroll, cx);
1664 // for (ix, (item, detail)) in self
1665 // .items
1666 // .iter()
1667 // .cloned()
1668 // .zip(self.tab_details(cx))
1669 // .enumerate()
1670 // {
1671 // let git_status = item
1672 // .project_path(cx)
1673 // .and_then(|path| self.project.read(cx).entry_for_path(&path, cx))
1674 // .and_then(|entry| entry.git_status());
1675
1676 // let detail = if detail == 0 { None } else { Some(detail) };
1677 // let tab_active = ix == self.active_item_index;
1678
1679 // row.add_child({
1680 // enum TabDragReceiver {}
1681 // let mut receiver =
1682 // dragged_item_receiver::<TabDragReceiver, _, _>(self, ix, ix, true, None, cx, {
1683 // let item = item.clone();
1684 // let pane = pane.clone();
1685 // let detail = detail.clone();
1686
1687 // let theme = theme::current(cx).clone();
1688 // let mut tooltip_theme = theme.tooltip.clone();
1689 // tooltip_theme.max_text_width = None;
1690 // let tab_tooltip_text =
1691 // item.tab_tooltip_text(cx).map(|text| text.into_owned());
1692
1693 // let mut tab_style = theme
1694 // .workspace
1695 // .tab_bar
1696 // .tab_style(pane_active, tab_active)
1697 // .clone();
1698 // let should_show_status = settings::get::<ItemSettings>(cx).git_status;
1699 // if should_show_status && git_status != None {
1700 // tab_style.label.text.color = match git_status.unwrap() {
1701 // GitFileStatus::Added => tab_style.git.inserted,
1702 // GitFileStatus::Modified => tab_style.git.modified,
1703 // GitFileStatus::Conflict => tab_style.git.conflict,
1704 // };
1705 // }
1706
1707 // move |mouse_state, cx| {
1708 // let hovered = mouse_state.hovered();
1709
1710 // enum Tab {}
1711 // let mouse_event_handler =
1712 // MouseEventHandler::new::<Tab, _>(ix, cx, |_, cx| {
1713 // Self::render_tab(
1714 // &item,
1715 // pane.clone(),
1716 // ix == 0,
1717 // detail,
1718 // hovered,
1719 // &tab_style,
1720 // cx,
1721 // )
1722 // })
1723 // .on_down(MouseButton::Left, move |_, this, cx| {
1724 // this.activate_item(ix, true, true, cx);
1725 // })
1726 // .on_click(MouseButton::Middle, {
1727 // let item_id = item.id();
1728 // move |_, pane, cx| {
1729 // pane.close_item_by_id(item_id, SaveIntent::Close, cx)
1730 // .detach_and_log_err(cx);
1731 // }
1732 // })
1733 // .on_down(
1734 // MouseButton::Right,
1735 // move |event, pane, cx| {
1736 // pane.deploy_tab_context_menu(event.position, item.id(), cx);
1737 // },
1738 // );
1739
1740 // if let Some(tab_tooltip_text) = tab_tooltip_text {
1741 // mouse_event_handler
1742 // .with_tooltip::<Self>(
1743 // ix,
1744 // tab_tooltip_text,
1745 // None,
1746 // tooltip_theme,
1747 // cx,
1748 // )
1749 // .into_any()
1750 // } else {
1751 // mouse_event_handler.into_any()
1752 // }
1753 // }
1754 // });
1755
1756 // if !pane_active || !tab_active {
1757 // receiver = receiver.with_cursor_style(CursorStyle::PointingHand);
1758 // }
1759
1760 // receiver.as_draggable(
1761 // DraggedItem {
1762 // handle: item,
1763 // pane: pane.clone(),
1764 // },
1765 // {
1766 // let theme = theme::current(cx).clone();
1767
1768 // let detail = detail.clone();
1769 // move |_, dragged_item: &DraggedItem, cx: &mut ViewContext<Workspace>| {
1770 // let tab_style = &theme.workspace.tab_bar.dragged_tab;
1771 // Self::render_dragged_tab(
1772 // &dragged_item.handle,
1773 // dragged_item.pane.clone(),
1774 // false,
1775 // detail,
1776 // false,
1777 // &tab_style,
1778 // cx,
1779 // )
1780 // }
1781 // },
1782 // )
1783 // })
1784 // }
1785
1786 // // Use the inactive tab style along with the current pane's active status to decide how to render
1787 // // the filler
1788 // let filler_index = self.items.len();
1789 // let filler_style = theme.workspace.tab_bar.tab_style(pane_active, false);
1790 // enum Filler {}
1791 // row.add_child(
1792 // dragged_item_receiver::<Filler, _, _>(self, 0, filler_index, true, None, cx, |_, _| {
1793 // Empty::new()
1794 // .contained()
1795 // .with_style(filler_style.container)
1796 // .with_border(filler_style.container.border)
1797 // })
1798 // .flex(1., true)
1799 // .into_any_named("filler"),
1800 // );
1801
1802 // row
1803 // }
1804
1805 fn tab_details(&self, cx: &AppContext) -> Vec<usize> {1690 fn tab_details(&self, cx: &AppContext) -> Vec<usize> {
1806 let mut tab_details = self.items.iter().map(|_| 0).collect::<Vec<_>>();1691 let mut tab_details = self.items.iter().map(|_| 0).collect::<Vec<_>>();
1807 1692
@@ -1839,192 +1724,6 @@ impl Pane { · 31 unmodified lines
1839 tab_details1724 tab_details
1840 }1725 }
1841 1726
1842 // fn render_tab(
1843 // item: &Box<dyn ItemHandle>,
1844 // pane: WeakView<Pane>,
1845 // first: bool,
1846 // detail: Option<usize>,
1847 // hovered: bool,
1848 // tab_style: &theme::Tab,
1849 // cx: &mut ViewContext<Self>,
1850 // ) -> AnyElement<Self> {
1851 // let title = item.tab_content(detail, &tab_style, cx);
1852 // Self::render_tab_with_title(title, item, pane, first, hovered, tab_style, cx)
1853 // }
1854
1855 // fn render_dragged_tab(
1856 // item: &Box<dyn ItemHandle>,
1857 // pane: WeakView<Pane>,
1858 // first: bool,
1859 // detail: Option<usize>,
1860 // hovered: bool,
1861 // tab_style: &theme::Tab,
1862 // cx: &mut ViewContext<Workspace>,
1863 // ) -> AnyElement<Workspace> {
1864 // let title = item.dragged_tab_content(detail, &tab_style, cx);
1865 // Self::render_tab_with_title(title, item, pane, first, hovered, tab_style, cx)
1866 // }
1867
1868 // fn render_tab_with_title<T: View>(
1869 // title: AnyElement<T>,
1870 // item: &Box<dyn ItemHandle>,
1871 // pane: WeakView<Pane>,
1872 // first: bool,
1873 // hovered: bool,
1874 // tab_style: &theme::Tab,
1875 // cx: &mut ViewContext<T>,
1876 // ) -> AnyElement<T> {
1877 // let mut container = tab_style.container.clone();
1878 // if first {
1879 // container.border.left = false;
1880 // }
1881
1882 // let buffer_jewel_element = {
1883 // let diameter = 7.0;
1884 // let icon_color = if item.has_conflict(cx) {
1885 // Some(tab_style.icon_conflict)
1886 // } else if item.is_dirty(cx) {
1887 // Some(tab_style.icon_dirty)
1888 // } else {
1889 // None
1890 // };
1891
1892 // Canvas::new(move |bounds, _, _, cx| {
1893 // if let Some(color) = icon_color {
1894 // let square = RectF::new(bounds.origin(), vec2f(diameter, diameter));
1895 // cx.scene().push_quad(Quad {
1896 // bounds: square,
1897 // background: Some(color),
1898 // border: Default::default(),
1899 // corner_radii: (diameter / 2.).into(),
1900 // });
1901 // }
1902 // })
1903 // .constrained()
1904 // .with_width(diameter)
1905 // .with_height(diameter)
1906 // .aligned()
1907 // };
1908
1909 // let title_element = title.aligned().contained().with_style(ContainerStyle {
1910 // margin: Margin {
1911 // left: tab_style.spacing,
1912 // right: tab_style.spacing,
1913 // ..Default::default()
1914 // },
1915 // ..Default::default()
1916 // });
1917
1918 // let close_element = if hovered {
1919 // let item_id = item.id();
1920 // enum TabCloseButton {}
1921 // let icon = Svg::new("icons/x.svg");
1922 // MouseEventHandler::new::<TabCloseButton, _>(item_id, cx, |mouse_state, _| {
1923 // if mouse_state.hovered() {
1924 // icon.with_color(tab_style.icon_close_active)
1925 // } else {
1926 // icon.with_color(tab_style.icon_close)
1927 // }
1928 // })
1929 // .with_padding(Padding::uniform(4.))
1930 // .with_cursor_style(CursorStyle::PointingHand)
1931 // .on_click(MouseButton::Left, {
1932 // let pane = pane.clone();
1933 // move |_, _, cx| {
1934 // let pane = pane.clone();
1935 // cx.window_context().defer(move |cx| {
1936 // if let Some(pane) = pane.upgrade(cx) {
1937 // pane.update(cx, |pane, cx| {
1938 // pane.close_item_by_id(item_id, SaveIntent::Close, cx)
1939 // .detach_and_log_err(cx);
1940 // });
1941 // }
1942 // });
1943 // }
1944 // })
1945 // .into_any_named("close-tab-icon")
1946 // .constrained()
1947 // } else {
1948 // Empty::new().constrained()
1949 // }
1950 // .with_width(tab_style.close_icon_width)
1951 // .aligned();
1952
1953 // let close_right = settings::get::<ItemSettings>(cx).close_position.right();
1954
1955 // if close_right {
1956 // Flex::row()
1957 // .with_child(buffer_jewel_element)
1958 // .with_child(title_element)
1959 // .with_child(close_element)
1960 // } else {
1961 // Flex::row()
1962 // .with_child(close_element)
1963 // .with_child(title_element)
1964 // .with_child(buffer_jewel_element)
1965 // }
1966 // .contained()
1967 // .with_style(container)
1968 // .constrained()
1969 // .with_height(tab_style.height)
1970 // .into_any()
1971 // }
1972
1973 // pub fn render_tab_bar_button<
1974 // F1: 'static + Fn(&mut Pane, &mut EventContext<Pane>),
1975 // F2: 'static + Fn(&mut Pane, &mut EventContext<Pane>),
1976 // >(
1977 // index: usize,
1978 // icon: &'static str,
1979 // is_active: bool,
1980 // tooltip: Option<(&'static str, Option<Box<dyn Action>>)>,
1981 // cx: &mut ViewContext<Pane>,
1982 // on_click: F1,
1983 // on_down: F2,
1984 // context_menu: Option<ViewHandle<ContextMenu>>,
1985 // ) -> AnyElement<Pane> {
1986 // enum TabBarButton {}
1987
1988 // let mut button = MouseEventHandler::new::<TabBarButton, _>(index, cx, |mouse_state, cx| {
1989 // let theme = &settings2::get::<ThemeSettings>(cx).theme.workspace.tab_bar;
1990 // let style = theme.pane_button.in_state(is_active).style_for(mouse_state);
1991 // Svg::new(icon)
1992 // .with_color(style.color)
1993 // .constrained()
1994 // .with_width(style.icon_width)
1995 // .aligned()
1996 // .constrained()
1997 // .with_width(style.button_width)
1998 // .with_height(style.button_width)
1999 // })
2000 // .with_cursor_style(CursorStyle::PointingHand)
2001 // .on_down(MouseButton::Left, move |_, pane, cx| on_down(pane, cx))
2002 // .on_click(MouseButton::Left, move |_, pane, cx| on_click(pane, cx))
2003 // .into_any();
2004 // if let Some((tooltip, action)) = tooltip {
2005 // let tooltip_style = settings::get::<ThemeSettings>(cx).theme.tooltip.clone();
2006 // button = button
2007 // .with_tooltip::<TabBarButton>(index, tooltip, action, tooltip_style, cx)
2008 // .into_any();
2009 // }
2010
2011 // Stack::new()
2012 // .with_child(button)
2013 // .with_children(
2014 // context_menu.map(|menu| ChildView::new(&menu, cx).aligned().bottom().right()),
2015 // )
2016 // .flex(1., false)
2017 // .into_any_named("tab bar button")
2018 // }
2019
2020 // fn render_blank_pane(&self, theme: &Theme, _cx: &mut ViewContext<Self>) -> AnyElement<Self> {
2021 // let background = theme.workspace.background;
2022 // Empty::new()
2023 // .contained()
2024 // .with_background_color(background)
2025 // .into_any()
2026 // }
2027
2028 pub fn set_zoomed(&mut self, zoomed: bool, cx: &mut ViewContext<Self>) {1727 pub fn set_zoomed(&mut self, zoomed: bool, cx: &mut ViewContext<Self>) {
2029 self.zoomed = zoomed;1728 self.zoomed = zoomed;
2030 cx.notify();1729 cx.notify();
@@ -2033,6 +1732,25 @@ impl Pane { · 2 unmodified lines
2033 pub fn is_zoomed(&self) -> bool {1732 pub fn is_zoomed(&self) -> bool {
2034 self.zoomed1733 self.zoomed
2035 }1734 }
1735
1736 fn handle_tab_drop(
1737 &mut self,
1738 dragged_tab: &View<DraggedTab>,
1739 ix: usize,
1740 cx: &mut ViewContext<'_, Pane>,
1741 ) {
1742 let dragged_tab = dragged_tab.read(cx);
1743 let item_id = dragged_tab.item_id;
1744 let from_pane = dragged_tab.pane.clone();
1745 let to_pane = cx.view().clone();
1746 self.workspace
1747 .update(cx, |workspace, cx| {
1748 cx.defer(move |workspace, cx| {
1749 workspace.move_item(from_pane, to_pane, item_id, ix, cx);
1750 });
1751 })
1752 .log_err();
1753 }
2036}1754}
2037 1755
2038impl FocusableView for Pane {1756impl FocusableView for Pane {
@@ -2134,148 +1852,6 @@ impl Render for Pane { · 95 unmodified lines
2134 .justify_center()1852 .justify_center()
2135 .child(Label::new("Open a file or project to get started.").color(Color::Muted))1853 .child(Label::new("Open a file or project to get started.").color(Color::Muted))
2136 })1854 })
2137 // enum MouseNavigationHandler {}
2138 // MouseEventHandler::new::<MouseNavigationHandler, _>(0, cx, |_, cx| {
2139 // let active_item_index = self.active_item_index;
2140 // if let Some(active_item) = self.active_item() {
2141 // Flex::column()
2142 // .with_child({
2143 // let theme = theme::current(cx).clone();
2144 // let mut stack = Stack::new();
2145 // enum TabBarEventHandler {}
2146 // stack.add_child(
2147 // MouseEventHandler::new::<TabBarEventHandler, _>(0, cx, |_, _| {
2148 // Empty::new()
2149 // .contained()
2150 // .with_style(theme.workspace.tab_bar.container)
2151 // })
2152 // .on_down(
2153 // MouseButton::Left,
2154 // move |_, this, cx| {
2155 // this.activate_item(active_item_index, true, true, cx);
2156 // },
2157 // ),
2158 // );
2159 // let tooltip_style = theme.tooltip.clone();
2160 // let tab_bar_theme = theme.workspace.tab_bar.clone();
2161 // let nav_button_height = tab_bar_theme.height;
2162 // let button_style = tab_bar_theme.nav_button;
2163 // let border_for_nav_buttons = tab_bar_theme
2164 // .tab_style(false, false)
2165 // .container
2166 // .border
2167 // .clone();
2168 // let mut tab_row = Flex::row()
2169 // .with_child(nav_button(
2170 // "icons/arrow_left.svg",
2171 // button_style.clone(),
2172 // nav_button_height,
2173 // tooltip_style.clone(),
2174 // self.can_navigate_backward(),
2175 // {
2176 // move |pane, cx| {
2177 // if let Some(workspace) = pane.workspace.upgrade(cx) {
2178 // let pane = cx.weak_handle();
2179 // cx.window_context().defer(move |cx| {
2180 // workspace.update(cx, |workspace, cx| {
2181 // workspace
2182 // .go_back(pane, cx)
2183 // .detach_and_log_err(cx)
2184 // })
2185 // })
2186 // }
2187 // }
2188 // },
2189 // super::GoBack,
2190 // "Go Back",
2191 // cx,
2192 // ))
2193 // .with_child(
2194 // nav_button(
2195 // "icons/arrow_right.svg",
2196 // button_style.clone(),
2197 // nav_button_height,
2198 // tooltip_style,
2199 // self.can_navigate_forward(),
2200 // {
2201 // move |pane, cx| {
2202 // if let Some(workspace) = pane.workspace.upgrade(cx) {
2203 // let pane = cx.weak_handle();
2204 // cx.window_context().defer(move |cx| {
2205 // workspace.update(cx, |workspace, cx| {
2206 // workspace
2207 // .go_forward(pane, cx)
2208 // .detach_and_log_err(cx)
2209 // })
2210 // })
2211 // }
2212 // }
2213 // },
2214 // super::GoForward,
2215 // "Go Forward",
2216 // cx,
2217 // )
2218 // .contained()
2219 // .with_border(border_for_nav_buttons),
2220 // )
2221 // .with_child(self.render_tabs(cx).flex(1., true).into_any_named("tabs"));
2222 // if self.has_focus {
2223 // let render_tab_bar_buttons = self.render_tab_bar_buttons.clone();
2224 // tab_row.add_child(
2225 // (render_tab_bar_buttons)(self, cx)
2226 // .contained()
2227 // .with_style(theme.workspace.tab_bar.pane_button_container)
2228 // .flex(1., false)
2229 // .into_any(),
2230 // )
2231 // }
2232 // stack.add_child(tab_row);
2233 // stack
2234 // .constrained()
2235 // .with_height(theme.workspace.tab_bar.height)
2236 // .flex(1., false)
2237 // .into_any_named("tab bar")
2238 // })
2239 // .with_child({
2240 // enum PaneContentTabDropTarget {}
2241 // dragged_item_receiver::<PaneContentTabDropTarget, _, _>(
2242 // self,
2243 // 0,
2244 // self.active_item_index + 1,
2245 // !self.can_split,
2246 // if self.can_split { Some(100.) } else { None },
2247 // cx,
2248 // {
2249 // let toolbar = self.toolbar.clone();
2250 // let toolbar_hidden = toolbar.read(cx).hidden();
2251 // move |_, cx| {
2252 // Flex::column()
2253 // .with_children(
2254 // (!toolbar_hidden)
2255 // .then(|| ChildView::new(&toolbar, cx).expanded()),
2256 // )
2257 // .with_child(
2258 // ChildView::new(active_item.as_any(), cx).flex(1., true),
2259 // )
2260 // }
2261 // },
2262 // )
2263 // .flex(1., true)
2264 // })
2265 // .with_child(ChildView::new(&self.tab_context_menu, cx))
2266 // .into_any()
2267 // } else {
2268 // enum EmptyPane {}
2269 // let theme = theme::current(cx).clone();
2270 // dragged_item_receiver::<EmptyPane, _, _>(self, 0, 0, false, None, cx, |_, cx| {
2271 // self.render_blank_pane(&theme, cx)
2272 // })
2273 // .on_down(MouseButton::Left, |_, _, cx| {
2274 // cx.focus_parent();
2275 // })
2276 // .into_any()
2277 // }
2278 // })
2279 .on_mouse_down(1855 .on_mouse_down(
2280 MouseButton::Navigate(NavigationDirection::Back),1856 MouseButton::Navigate(NavigationDirection::Back),
2281 cx.listener(|pane, _, cx| {1857 cx.listener(|pane, _, cx| {
@@ -2302,7 +1878,6 @@ impl Render for Pane { · 20 unmodified lines
2302 }1878 }
2303 }),1879 }),
2304 )1880 )
2305 // .into_any_named("pane")
2306 }1881 }
2307 1882
2308 // fn focus_in(&mut self, focused: AnyViewHandle, cx: &mut ViewContext<Self>) {1883 // fn focus_in(&mut self, focused: AnyViewHandle, cx: &mut ViewContext<Self>) {
@@ -3131,15 +2706,17 @@ fn dirty_message_for(buffer_path: Option<ProjectPath>) -> String { · 822 unmodified lines
3131// }2706// }
3132// }2707// }
3133 2708
3134#[derive(Clone, Debug)]
3135struct DraggedTab {
3136 title: String,
3137}
3138
3139impl Render for DraggedTab {2709impl Render for DraggedTab {
3140 type Element = Div;2710 type Element = <Tab as RenderOnce>::Rendered;
3141 2711
3142 fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {2712 fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
3143 div().w_8().h_4().bg(gpui::red())2713 let ui_font = ThemeSettings::get_global(cx).ui_font.family.clone();
2714 let item = &self.pane.read(cx).items[self.ix];
2715 let label = item.tab_content(Some(self.detail), false, cx);
2716 Tab::new("")
2717 .selected(self.is_active)
2718 .child(label)
2719 .render(cx)
2720 .font(ui_font)
3144 }2721 }
3145}2722}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t