Files
galaxy/app/src/view_components/compactible_split_action_button.rs
T

120 lines
3.8 KiB
Rust

use std::sync::Arc;
use warpui::elements::{ChildView, Flex, ParentElement, SavePosition};
use warpui::{Action, Element, TypedActionView, View, ViewContext, ViewHandle};
use crate::view_components::action_button::AdjoinedSide;
use crate::view_components::compactible_action_button::RenderCompactibleActionButton;
use crate::{
ui_components::icons::Icon,
view_components::action_button::{
ActionButton, ButtonSize, KeystrokeSource, NakedTheme, PrimaryRightBiasedTheme,
PrimaryTheme,
},
view_components::compactible_action_button::CompactibleActionButton,
};
/// A split button composed of a primary CompactibleActionButton and a trailing
/// icon-only menu button (chevron-down). The menu button may be used as an anchor
/// for a dropdown Menu via `with_menu`.
#[derive(Clone)]
#[allow(dead_code)]
pub struct CompactibleSplitActionButton {
primary_button: CompactibleActionButton,
menu_button: ViewHandle<ActionButton>,
save_position_id: Option<String>,
}
impl CompactibleSplitActionButton {
/// Creates a split button: a primary CompactibleActionButton and an icon-only
/// chevron menu button that inherits the same theme choice.
#[allow(dead_code)]
#[allow(clippy::too_many_arguments)]
pub fn new<T, A>(
label: String,
keybinding: Option<KeystrokeSource>,
size: ButtonSize,
action: A,
menu_action: A,
compact_icon: Icon,
use_primary_theme: bool,
save_position_id: Option<String>,
ctx: &mut ViewContext<'_, T>,
) -> Self
where
T: TypedActionView<Action = A> + View,
A: Action + Clone + 'static,
{
let mut primary_button = CompactibleActionButton::new(
label,
keybinding,
size,
action,
compact_icon,
if use_primary_theme {
Arc::new(PrimaryTheme)
} else {
Arc::new(NakedTheme)
},
ctx,
);
primary_button.set_adjoined_side(AdjoinedSide::Right, ctx);
// The down-caret icon-only menu button.
let menu_button = ctx.add_typed_action_view(|_ctx| {
ActionButton::new_with_boxed_theme(
"",
if use_primary_theme {
Arc::new(PrimaryRightBiasedTheme)
} else {
Arc::new(NakedTheme)
},
)
.with_size(size)
.with_icon(Icon::ChevronDown)
.with_adjoined_side(AdjoinedSide::Left)
.on_click(move |ctx| ctx.dispatch_typed_action(menu_action.clone()))
});
Self {
primary_button,
menu_button,
save_position_id,
}
}
fn render_button(&self, is_expanded: bool) -> Box<dyn Element> {
let button = if is_expanded {
self.primary_button.expanded_button()
} else {
self.primary_button.compact_button()
};
let row = Flex::row()
.with_child(ChildView::new(button).finish())
.with_child(ChildView::new(&self.menu_button).finish());
if let Some(save_position_id) = &self.save_position_id {
SavePosition::new(row.finish(), save_position_id).finish()
} else {
row.finish()
}
}
pub fn set_keybinding<T: View>(
&mut self,
keybinding: Option<KeystrokeSource>,
ctx: &mut ViewContext<T>,
) {
self.primary_button.set_keybinding(keybinding, ctx);
}
}
impl RenderCompactibleActionButton for CompactibleSplitActionButton {
fn render_expanded_button(&self) -> Box<dyn Element> {
self.render_button(true)
}
fn render_compact_button(&self) -> Box<dyn Element> {
self.render_button(false)
}
}