* Use a single row, instead of centering the search bar within a double-row toolbar. * Search query controls on the left, navigation on the right * Semantic is the final mode, for greater stability between buffer and project search. * Prevent query editor from moving when toggling path filters
175 lines
5.5 KiB
Rust
175 lines
5.5 KiB
Rust
use std::borrow::Cow;
|
|
|
|
use gpui::{
|
|
elements::{Label, MouseEventHandler, Svg},
|
|
platform::{CursorStyle, MouseButton},
|
|
scene::{CornerRadii, MouseClick},
|
|
Action, AnyElement, Element, EventContext, View, ViewContext,
|
|
};
|
|
use workspace::searchable::Direction;
|
|
|
|
use crate::{
|
|
mode::{SearchMode, Side},
|
|
SelectNextMatch, SelectPrevMatch,
|
|
};
|
|
|
|
pub(super) fn render_nav_button<V: View>(
|
|
icon: &'static str,
|
|
direction: Direction,
|
|
active: bool,
|
|
on_click: impl Fn(MouseClick, &mut V, &mut EventContext<V>) + 'static,
|
|
cx: &mut ViewContext<V>,
|
|
) -> AnyElement<V> {
|
|
let action: Box<dyn Action>;
|
|
let tooltip;
|
|
|
|
match direction {
|
|
Direction::Prev => {
|
|
action = Box::new(SelectPrevMatch);
|
|
tooltip = "Select Previous Match";
|
|
}
|
|
Direction::Next => {
|
|
action = Box::new(SelectNextMatch);
|
|
tooltip = "Select Next Match";
|
|
}
|
|
};
|
|
let tooltip_style = theme::current(cx).tooltip.clone();
|
|
let cursor_style = if active {
|
|
CursorStyle::PointingHand
|
|
} else {
|
|
CursorStyle::default()
|
|
};
|
|
enum NavButton {}
|
|
MouseEventHandler::new::<NavButton, _>(direction as usize, cx, |state, cx| {
|
|
let theme = theme::current(cx);
|
|
let style = theme
|
|
.search
|
|
.nav_button
|
|
.in_state(active)
|
|
.style_for(state)
|
|
.clone();
|
|
let mut container_style = style.container.clone();
|
|
let label = Label::new(icon, style.label.clone()).aligned().contained();
|
|
container_style.corner_radii = match direction {
|
|
Direction::Prev => CornerRadii {
|
|
bottom_right: 0.,
|
|
top_right: 0.,
|
|
..container_style.corner_radii
|
|
},
|
|
Direction::Next => CornerRadii {
|
|
bottom_left: 0.,
|
|
top_left: 0.,
|
|
..container_style.corner_radii
|
|
},
|
|
};
|
|
if direction == Direction::Prev {
|
|
// Remove right border so that when both Next and Prev buttons are
|
|
// next to one another, there's no double border between them.
|
|
container_style.border.right = false;
|
|
}
|
|
label.with_style(container_style)
|
|
})
|
|
.on_click(MouseButton::Left, on_click)
|
|
.with_cursor_style(cursor_style)
|
|
.with_tooltip::<NavButton>(
|
|
direction as usize,
|
|
tooltip.to_string(),
|
|
Some(action),
|
|
tooltip_style,
|
|
cx,
|
|
)
|
|
.into_any()
|
|
}
|
|
|
|
pub(crate) fn render_search_mode_button<V: View>(
|
|
mode: SearchMode,
|
|
side: Option<Side>,
|
|
is_active: bool,
|
|
on_click: impl Fn(MouseClick, &mut V, &mut EventContext<V>) + 'static,
|
|
cx: &mut ViewContext<V>,
|
|
) -> AnyElement<V> {
|
|
let tooltip_style = theme::current(cx).tooltip.clone();
|
|
enum SearchModeButton {}
|
|
MouseEventHandler::new::<SearchModeButton, _>(mode.region_id(), cx, |state, cx| {
|
|
let theme = theme::current(cx);
|
|
let style = theme
|
|
.search
|
|
.mode_button
|
|
.in_state(is_active)
|
|
.style_for(state)
|
|
.clone();
|
|
|
|
let mut container_style = style.container;
|
|
if let Some(button_side) = side {
|
|
if button_side == Side::Left {
|
|
container_style.border.left = true;
|
|
container_style.corner_radii = CornerRadii {
|
|
bottom_right: 0.,
|
|
top_right: 0.,
|
|
..container_style.corner_radii
|
|
};
|
|
} else {
|
|
container_style.border.left = false;
|
|
container_style.corner_radii = CornerRadii {
|
|
bottom_left: 0.,
|
|
top_left: 0.,
|
|
..container_style.corner_radii
|
|
};
|
|
}
|
|
} else {
|
|
container_style.border.left = false;
|
|
container_style.corner_radii = CornerRadii::default();
|
|
}
|
|
|
|
Label::new(mode.label(), style.text)
|
|
.aligned()
|
|
.contained()
|
|
.with_style(container_style)
|
|
.constrained()
|
|
.with_height(theme.search.search_bar_row_height)
|
|
})
|
|
.on_click(MouseButton::Left, on_click)
|
|
.with_cursor_style(CursorStyle::PointingHand)
|
|
.with_tooltip::<SearchModeButton>(
|
|
mode.region_id(),
|
|
mode.tooltip_text().to_owned(),
|
|
Some(mode.activate_action()),
|
|
tooltip_style,
|
|
cx,
|
|
)
|
|
.into_any()
|
|
}
|
|
|
|
pub(crate) fn render_option_button_icon<V: View>(
|
|
is_active: bool,
|
|
icon: &'static str,
|
|
id: usize,
|
|
label: impl Into<Cow<'static, str>>,
|
|
action: Box<dyn Action>,
|
|
on_click: impl Fn(MouseClick, &mut V, &mut EventContext<V>) + 'static,
|
|
cx: &mut ViewContext<V>,
|
|
) -> AnyElement<V> {
|
|
let tooltip_style = theme::current(cx).tooltip.clone();
|
|
MouseEventHandler::new::<V, _>(id, cx, |state, cx| {
|
|
let theme = theme::current(cx);
|
|
let style = theme
|
|
.search
|
|
.option_button
|
|
.in_state(is_active)
|
|
.style_for(state);
|
|
Svg::new(icon)
|
|
.with_color(style.color.clone())
|
|
.constrained()
|
|
.with_width(style.icon_width)
|
|
.contained()
|
|
.with_style(style.container)
|
|
.constrained()
|
|
.with_height(theme.search.option_button_height)
|
|
.with_width(style.button_width)
|
|
})
|
|
.on_click(MouseButton::Left, on_click)
|
|
.with_cursor_style(CursorStyle::PointingHand)
|
|
.with_tooltip::<V>(id, label, Some(action), tooltip_style, cx)
|
|
.into_any()
|
|
}
|