Detailed changes
@@ -5,7 +5,7 @@ use crate::{
ViewContext,
};
use anyhow::Result;
-use gpui::{geometry::vector::Vector2F, platform::MouseButtonEvent, LayoutId};
+use gpui::{color::Color, geometry::vector::Vector2F, platform::MouseButtonEvent, LayoutId};
use refineable::{CascadeSlot, Refineable, RefinementCascade};
use smallvec::SmallVec;
use std::{cell::Cell, rc::Rc};
@@ -73,10 +73,15 @@ impl<V: 'static, E: Element<V> + Styleable> Element<V> for Pressable<E> {
if bounds.contains_point(event.position) {
pressed.set(true);
cx.repaint();
+ } else {
+ cx.bubble_event();
}
- } else if pressed.get() {
- pressed.set(false);
- cx.repaint();
+ } else {
+ if pressed.get() {
+ pressed.set(false);
+ cx.repaint();
+ }
+ cx.bubble_event();
}
});
@@ -12,7 +12,6 @@ mod tool_divider;
pub use avatar::avatar;
pub use avatar::Avatar;
pub use icon_button::icon_button;
-pub use icon_button::IconButton;
pub use tab::tab;
pub use tab::Tab;
pub use tool_divider::tool_divider;
@@ -12,7 +12,7 @@ pub struct IconButton {
state: InteractionState,
}
-pub fn icon_button<V: 'static>(path: &'static str) -> IconButton {
+pub fn icon_button(path: &'static str) -> IconButton {
IconButton {
path,
variant: ButtonVariant::default(),
@@ -1,123 +0,0 @@
-// use crate::prelude::{ButtonVariant, UIState};
-// use crate::theme::theme;
-// use gpui2::elements::svg;
-// use gpui2::style::{StyleHelpers, Styleable};
-// use gpui2::{elements::div, IntoElement};
-// use gpui2::{Element, ParentElement, ViewContext};
-
-// #[derive(Element)]
-// pub(crate) struct IconButton {
-// path: &'static str,
-// variant: ButtonVariant,
-// state: UIState,
-// }
-
-// pub fn icon_button<V: 'static>(path: &'static str) -> IconButton {
-// IconButton {
-// path,
-// variant: ButtonVariant::Filled,
-// state: UIState::Default,
-// }
-// }
-
-// impl IconButton {
-// fn variant(mut self, variant: ButtonVariant) -> Self {
-// self.variant = variant;
-
-// // Example of more interesting setter behavior
-// // FilledButtons must be disabled
-// if self.variant == ButtonVariant::Filled {
-// self.state = UIState::Disabled;
-// }
-
-// self
-// }
-
-// fn state(mut self, state: UIState) -> Self {
-// // Example of more interesting setter behavior:
-// // GhostButtons Cannot be disabled
-// // Debug asserts are compiled out when we make a new release.
-// // Useful for making sure developers develop correctly without breaking
-// // everything
-// debug_assert!(self.variant != ButtonVariant::Ghost && state != UIState::Disabled);
-
-// self.state = state;
-// self
-// }
-
-// // const state = {
-// // foo: "foo",
-// // bar: "bar"
-// // } as const
-// //
-// // type State = typeof state[keyof typeof something]
-// //
-// // type Button {
-// // style: State
-// // }
-// //
-// // <Button style="foo" /> State['foo']
-
-// fn render_warning<V: 'static>(&mut self) -> impl IntoElement<V> {
-// div()
-// }
-
-// fn render<V: 'static>(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
-// let theme = theme(cx);
-
-// let icon_color;
-
-// enum Severity {
-// Low,
-// Medium,
-// High,
-// }
-
-// // Enum declaration and match statement example
-// enum Style {
-// Error,
-// Warning(Severity),
-// Foo,
-// Bar,
-// Baz,
-// }
-
-// let style = Style::Warning(Severity::High);
-
-// match style {
-// Error => return self.render_warning(),
-// Warning(severity) => match severity {
-// Low => {}
-// Medium => {}
-// High => {}
-// },
-// Foo => {}
-// Bar => {}
-// Baz => {}
-// }
-
-// if self.state == UIState::Disabled {
-// icon_color = theme.highest.base.disabled.foreground;
-// } else {
-// icon_color = theme.highest.base.default.foreground;
-// }
-
-// let mut div = div();
-
-// if self.variant == ButtonVariant::Filled {
-// div = div.fill(theme.highest.on.default.background);
-// }
-
-// div.w_7()
-// .h_6()
-// .flex()
-// .items_center()
-// .justify_center()
-// .rounded_md()
-// .hover()
-// .fill(theme.highest.base.hovered.background)
-// .active()
-// .fill(theme.highest.base.pressed.background)
-// .child(svg().path(self.path).w_4().h_4().fill(icon_color))
-// }
-// }
@@ -1,7 +1,10 @@
mod chat_panel;
+mod status_bar;
mod tab_bar;
mod title_bar;
pub(crate) use chat_panel::chat_panel;
+pub use status_bar::status_bar;
+pub use status_bar::StatusBar;
pub(crate) use tab_bar::tab_bar;
pub(crate) use title_bar::title_bar;
@@ -1,6 +1,6 @@
use std::marker::PhantomData;
-use crate::components::{icon_button, IconButton};
+use crate::components::icon_button;
use crate::theme::theme;
use gpui2::elements::div::ScrollState;
use gpui2::style::StyleHelpers;
@@ -57,8 +57,8 @@ impl<V: 'static> ChatPanel<V> {
.flex()
.items_center()
.gap_px()
- .child(icon_button::<IconButton>("icons/plus.svg"))
- .child(icon_button::<IconButton>("icons/split.svg")),
+ .child(icon_button("icons/plus.svg"))
+ .child(icon_button("icons/split.svg")),
),
)
}
@@ -0,0 +1,109 @@
+use std::marker::PhantomData;
+
+use crate::components::icon_button;
+use crate::theme::{theme, Theme};
+use gpui2::style::StyleHelpers;
+use gpui2::{elements::div, IntoElement};
+use gpui2::{Element, ParentElement, ViewContext};
+
+#[derive(Default, PartialEq)]
+pub enum Tool {
+ #[default]
+ ProjectPanel,
+ CollaborationPanel,
+ Terminal,
+ Assistant,
+ Feedback,
+ Diagnostics,
+}
+
+struct ToolGroup {
+ active_index: Option<usize>,
+ tools: Vec<Tool>,
+}
+
+impl Default for ToolGroup {
+ fn default() -> Self {
+ ToolGroup {
+ active_index: None,
+ tools: vec![],
+ }
+ }
+}
+
+#[derive(Element)]
+pub struct StatusBar<V: 'static> {
+ view_type: PhantomData<V>,
+ left_tools: Option<ToolGroup>,
+ right_tools: Option<ToolGroup>,
+ bottom_tools: Option<ToolGroup>,
+}
+
+pub fn status_bar<V: 'static>() -> StatusBar<V> {
+ StatusBar {
+ view_type: PhantomData,
+ left_tools: None,
+ right_tools: None,
+ bottom_tools: None,
+ }
+}
+
+impl<V: 'static> StatusBar<V> {
+ pub fn left_tool(mut self, tool: Tool, active_index: Option<usize>) -> Self {
+ self.left_tools = {
+ let mut tools = vec![tool];
+ tools.extend(self.left_tools.take().unwrap_or_default().tools);
+ Some(ToolGroup {
+ active_index,
+ tools,
+ })
+ };
+ self
+ }
+
+ pub fn right_tool(mut self, tool: Tool, active_index: Option<usize>) -> Self {
+ self.right_tools = {
+ let mut tools = vec![tool];
+ tools.extend(self.left_tools.take().unwrap_or_default().tools);
+ Some(ToolGroup {
+ active_index,
+ tools,
+ })
+ };
+ self
+ }
+
+ pub fn bottom_tool(mut self, tool: Tool, active_index: Option<usize>) -> Self {
+ self.bottom_tools = {
+ let mut tools = vec![tool];
+ tools.extend(self.left_tools.take().unwrap_or_default().tools);
+ Some(ToolGroup {
+ active_index,
+ tools,
+ })
+ };
+ self
+ }
+
+ fn render(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
+ let theme = theme(cx);
+
+ div()
+ .flex()
+ .items_center()
+ .justify_between()
+ .w_full()
+ .fill(theme.lowest.base.default.background)
+ .child(self.left_tools(theme))
+ .child(div())
+ }
+
+ fn left_tools(&self, theme: &Theme) -> impl Element<V> {
+ div()
+ .flex()
+ .items_center()
+ .gap_px()
+ .child(icon_button("icons/folder_tree_16.svg"))
+ .child(icon_button("icons/bolt_16.svg"))
+ }
+}
@@ -1,6 +1,6 @@
use std::marker::PhantomData;
-use crate::components::{icon_button, tab, IconButton};
+use crate::components::{icon_button, tab};
use crate::prelude::InteractionState;
use crate::theme::theme;
use gpui2::elements::div::ScrollState;
@@ -43,11 +43,11 @@ impl<V: 'static> TabBar<V> {
.items_center()
.gap_px()
.child(
- icon_button::<IconButton>("icons/arrow_left.svg")
+ icon_button("icons/arrow_left.svg")
.state(InteractionState::Enabled.if_enabled(can_navigate_back)),
)
.child(
- icon_button::<IconButton>("icons/arrow_right.svg").state(
+ icon_button("icons/arrow_right.svg").state(
InteractionState::Enabled.if_enabled(can_navigate_forward),
),
),
@@ -83,8 +83,8 @@ impl<V: 'static> TabBar<V> {
.flex()
.items_center()
.gap_px()
- .child(icon_button::<IconButton>("icons/plus.svg"))
- .child(icon_button::<IconButton>("icons/split.svg")),
+ .child(icon_button("icons/plus.svg"))
+ .child(icon_button("icons/split.svg")),
),
)
}
@@ -1,6 +1,6 @@
use std::marker::PhantomData;
-use crate::components::{avatar, icon_button, tool_divider, Avatar, IconButton};
+use crate::components::{avatar, icon_button, tool_divider, Avatar};
use crate::prelude::Shape;
use crate::theme::theme;
use gpui2::style::{StyleHelpers, Styleable};
@@ -29,6 +29,37 @@ impl<V: 'static> TitleBar<V> {
.w_full()
.h_8()
.fill(theme.lowest.base.default.background)
+ .child(
+ div()
+ .flex()
+ .items_center()
+ .child(
+ div()
+ .px_2()
+ .flex()
+ .items_center()
+ .gap_1()
+ .child(icon_button("icons/stop_sharing.svg"))
+ .child(icon_button("icons/exit.svg")),
+ )
+ .child(tool_divider())
+ .child(
+ div()
+ .px_2()
+ .flex()
+ .items_center()
+ .gap_1()
+ .child(icon_button("icons/radix/mic.svg"))
+ .child(icon_button("icons/radix/speaker-loud.svg"))
+ .child(icon_button("icons/radix/desktop.svg")),
+ )
+ .child(
+ div().px_2().flex().items_center().child(
+ avatar::<Avatar>("https://avatars.githubusercontent.com/u/1714999?v=4")
+ .shape(Shape::RoundedRectangle),
+ ),
+ ),
+ )
.child(
div()
.flex()
@@ -111,8 +142,8 @@ impl<V: 'static> TitleBar<V> {
.flex()
.items_center()
.gap_1()
- .child(icon_button::<IconButton>("icons/stop_sharing.svg"))
- .child(icon_button::<IconButton>("icons/exit.svg")),
+ .child(icon_button("icons/stop_sharing.svg"))
+ .child(icon_button("icons/exit.svg")),
)
.child(tool_divider())
.child(
@@ -121,9 +152,9 @@ impl<V: 'static> TitleBar<V> {
.flex()
.items_center()
.gap_1()
- .child(icon_button::<IconButton>("icons/radix/mic.svg"))
- .child(icon_button::<IconButton>("icons/radix/speaker-loud.svg"))
- .child(icon_button::<IconButton>("icons/radix/desktop.svg")),
+ .child(icon_button("icons/radix/mic.svg"))
+ .child(icon_button("icons/radix/speaker-loud.svg"))
+ .child(icon_button("icons/radix/desktop.svg")),
)
.child(
div().px_2().flex().items_center().child(
@@ -2,10 +2,15 @@
use crate::theme::Theme;
use ::theme as legacy_theme;
+use components::icon_button;
use element_ext::ElementExt;
-use gpui2::{serde_json, vec2f, view, Element, RectF, ViewContext, WindowBounds};
+use gpui2::{
+ elements::div, serde_json, style::StyleHelpers, vec2f, view, Element, ParentElement, RectF,
+ ViewContext, WindowBounds,
+};
use legacy_theme::ThemeSettings;
use log::LevelFilter;
+use modules::title_bar;
use settings::{default_settings, SettingsStore};
use simplelog::SimpleLogger;
@@ -1,6 +1,6 @@
use crate::{
collab_panel::collab_panel,
- modules::{chat_panel, tab_bar, title_bar},
+ modules::{chat_panel, status_bar, tab_bar, title_bar},
theme::theme,
};
use gpui2::{
@@ -59,6 +59,7 @@ impl WorkspaceElement {
.child(chat_panel(self.right_scroll_state.clone())),
)
.child(statusbar())
+ .child(status_bar())
}
}