From 4ef59899d1234c5156bf1efe3f058adfd373383d Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Wed, 2 Aug 2023 13:05:29 +0200 Subject: [PATCH] WIP: Add ButtonSide element --- crates/search/Cargo.toml | 4 +- crates/search/src/project_search.rs | 172 ++++++++++++++++++++++++++-- styles/src/style_tree/search.ts | 6 +- 3 files changed, 165 insertions(+), 17 deletions(-) diff --git a/crates/search/Cargo.toml b/crates/search/Cargo.toml index 3a59f9a5cd..64421f5431 100644 --- a/crates/search/Cargo.toml +++ b/crates/search/Cargo.toml @@ -30,11 +30,11 @@ serde_derive.workspace = true smallvec.workspace = true smol.workspace = true globset.workspace = true - +serde_json.workspace = true [dev-dependencies] client = { path = "../client", features = ["test-support"] } editor = { path = "../editor", features = ["test-support"] } gpui = { path = "../gpui", features = ["test-support"] } -serde_json.workspace = true + workspace = { path = "../workspace", features = ["test-support"] } unindent.workspace = true diff --git a/crates/search/src/project_search.rs b/crates/search/src/project_search.rs index 44586b6102..4d86134a1f 100644 --- a/crates/search/src/project_search.rs +++ b/crates/search/src/project_search.rs @@ -10,6 +10,10 @@ use editor::{ }; use futures::StreamExt; use globset::{Glob, GlobMatcher}; +use gpui::color::Color; +use gpui::geometry::rect::RectF; +use gpui::json::{self, ToJson}; +use gpui::SceneBuilder; use gpui::{ actions, elements::*, @@ -17,6 +21,7 @@ use gpui::{ Action, AnyElement, AnyViewHandle, AppContext, Entity, ModelContext, ModelHandle, Subscription, Task, View, ViewContext, ViewHandle, WeakModelHandle, WeakViewHandle, }; +use gpui::{scene::Path, Border, LayoutContext}; use menu::Confirm; use postage::stream::Stream; use project::{search::SearchQuery, Entry, Project}; @@ -958,6 +963,113 @@ impl Default for ProjectSearchBar { Self::new() } } +type CreatePath = fn(RectF, Color) -> Path; + +pub struct ButtonSide { + color: Color, + factory: CreatePath, +} + +impl ButtonSide { + fn new(color: Color, factory: CreatePath) -> Self { + Self { color, factory } + } + pub fn left(color: Color) -> Self { + Self::new(color, left_button_side) + } + pub fn right(color: Color) -> Self { + Self::new(color, right_button_side) + } +} + +fn left_button_side(bounds: RectF, color: Color) -> Path { + use gpui::geometry::PathBuilder; + let mut path = PathBuilder::new(); + path.reset(bounds.lower_right()); + path.line_to(bounds.upper_right()); + let mut middle_point = bounds.origin(); + let distance_to_line = (middle_point.y() - bounds.lower_left().y()) / 4.; + middle_point.set_y(middle_point.y() - distance_to_line); + path.curve_to(middle_point, bounds.origin()); + let mut target = bounds.lower_left(); + target.set_y(target.y() + distance_to_line); + path.line_to(target); + //path.curve_to(bounds.lower_right(), bounds.upper_right()); + path.curve_to(bounds.lower_right(), bounds.lower_left()); + path.build(color, None) +} + +fn right_button_side(bounds: RectF, color: Color) -> Path { + use gpui::geometry::PathBuilder; + let mut path = PathBuilder::new(); + path.reset(bounds.lower_left()); + path.line_to(bounds.origin()); + let mut middle_point = bounds.upper_right(); + let distance_to_line = (middle_point.y() - bounds.lower_right().y()) / 4.; + middle_point.set_y(middle_point.y() - distance_to_line); + path.curve_to(middle_point, bounds.upper_right()); + let mut target = bounds.lower_right(); + target.set_y(target.y() + distance_to_line); + path.line_to(target); + //path.curve_to(bounds.lower_right(), bounds.upper_right()); + path.curve_to(bounds.lower_left(), bounds.lower_right()); + path.build(color, None) +} + +impl Element for ButtonSide { + type LayoutState = (); + + type PaintState = (); + + fn layout( + &mut self, + constraint: gpui::SizeConstraint, + _: &mut ProjectSearchBar, + _: &mut LayoutContext, + ) -> (gpui::geometry::vector::Vector2F, Self::LayoutState) { + (constraint.max, ()) + } + + fn paint( + &mut self, + scene: &mut SceneBuilder, + bounds: RectF, + _: RectF, + _: &mut Self::LayoutState, + _: &mut ProjectSearchBar, + _: &mut ViewContext, + ) -> Self::PaintState { + scene.push_path((self.factory)(bounds, self.color)); + } + + fn rect_for_text_range( + &self, + _: Range, + _: RectF, + _: RectF, + _: &Self::LayoutState, + _: &Self::PaintState, + _: &ProjectSearchBar, + _: &ViewContext, + ) -> Option { + None + } + + fn debug( + &self, + bounds: RectF, + _: &Self::LayoutState, + _: &Self::PaintState, + _: &ProjectSearchBar, + _: &ViewContext, + ) -> gpui::json::Value { + json::json!({ + "type": "ButtonSide", + "bounds": bounds.to_json(), + "color": self.color.to_json(), + }) + } +} impl ProjectSearchBar { pub fn new() -> Self { @@ -1276,14 +1388,32 @@ impl ProjectSearchBar { let option = SearchOptions::REGEX; MouseEventHandler::::new(option.bits as usize, cx, |state, cx| { let theme = theme::current(cx); - let style = theme + let mut style = theme .search .option_button .in_state(is_active) - .style_for(state); - Label::new(icon, style.text.clone()) - .contained() - .with_style(style.container) + .style_for(state) + .clone(); + style.container.border.right = false; + Flex::row() + .with_child( + Label::new(icon, style.text.clone()) + .contained() + .with_style(style.container), + ) + .with_child( + ButtonSide::right( + style + .container + .background_color + .unwrap_or_else(gpui::color::Color::transparent_black), + ) + .contained() + .constrained() + .with_max_width(theme.titlebar.avatar_ribbon.width / 2.) + .aligned() + .bottom(), + ) }) .on_click(MouseButton::Left, move |_, this, cx| { this.toggle_search_option(option, cx); @@ -1347,14 +1477,32 @@ impl ProjectSearchBar { enum NormalSearchTag {} MouseEventHandler::::new(region_id, cx, |state, cx| { let theme = theme::current(cx); - let style = theme + let mut style = theme .search .option_button .in_state(is_active) - .style_for(state); - Label::new("Text", style.text.clone()) - .contained() - .with_style(style.container) + .style_for(state) + .clone(); + style.container.border.left = false; + Flex::row() + .with_child( + ButtonSide::left( + style + .container + .background_color + .unwrap_or_else(gpui::color::Color::transparent_black), + ) + .contained() + .constrained() + .with_max_width(theme.titlebar.avatar_ribbon.width / 2.) + .aligned() + .bottom(), + ) + .with_child( + Label::new("Text", style.text.clone()) + .contained() + .with_style(style.container), + ) }) .on_click(MouseButton::Left, move |_, this, cx| { if let Some(search) = this.active_project_search.as_mut() { @@ -1592,7 +1740,9 @@ impl View for ProjectSearchBar { .with_child(normal_search) .with_children(semantic_index) .with_child(regex_button) - .flex(1., true) + .constrained() + .with_height(theme.workspace.toolbar.height) + .contained() .aligned() .right(), ), diff --git a/styles/src/style_tree/search.ts b/styles/src/style_tree/search.ts index 94b52aa664..356cd77f97 100644 --- a/styles/src/style_tree/search.ts +++ b/styles/src/style_tree/search.ts @@ -44,11 +44,9 @@ export default function search(): any { base: { ...text(theme.highest, "mono", "on"), background: background(theme.highest, "on"), - corner_radius: 2, + border: border(theme.highest, "on"), - margin: { - right: 2, - }, + padding: { bottom: 6, left: 6,