first pass of merging in warp (doesn't build)

This commit is contained in:
Ryan Ward
2026-07-01 16:08:58 -05:00
parent 2f64909469
commit 4770ac06b5
3662 changed files with 414574 additions and 89772 deletions
+97 -26
View File
@@ -1,24 +1,28 @@
use crate::ui_components::blended_colors;
use crate::{appearance::Appearance, themes::theme::Fill, ui_components::icons};
use pathfinder_geometry::vector::vec2f;
use galaxyui::color::ColorU;
use galaxyui::elements::{
Align, Border, ChildAnchor, ChildView, ConstrainedBox, Container, CornerRadius,
CrossAxisAlignment, Dismiss, Element, Flex, MouseStateHandle, OffsetPositioning, ParentAnchor,
ParentElement, ParentOffsetBounds, Percentage, Radius, Shrinkable, Stack, Text,
};
use galaxyui::fonts::{Properties, Weight};
use galaxyui::keymap::{FixedBinding, Keystroke};
use galaxyui::ui_components::components::{Coords, UiComponent, UiComponentStyles};
use galaxyui::{
color::ColorU,
elements::{
Align, Border, ChildAnchor, ChildView, ConstrainedBox, Container, CornerRadius,
CrossAxisAlignment, Dismiss, Element, Flex, MouseStateHandle, OffsetPositioning,
ParentAnchor, ParentElement, ParentOffsetBounds, Radius, Shrinkable, Stack, Text,
},
fonts::{Properties, Weight},
keymap::FixedBinding,
ui_components::components::{Coords, UiComponent, UiComponentStyles},
AppContext, Entity, FocusContext, ModelHandle, SingletonEntity, TypedActionView, View,
ViewContext, ViewHandle,
};
use pathfinder_geometry::vector::vec2f;
use crate::appearance::Appearance;
use crate::themes::theme::Fill;
use crate::ui_components::{blended_colors, icons};
pub const MODAL_CORNER_RADIUS: Radius = Radius::Pixels(8.);
pub const MODAL_WIDTH: f32 = 440.;
pub const MODAL_HEADER_HEIGHT: f32 = 70.;
pub const MODAL_PADDING: f32 = 28.;
pub const MODAL_BACKDROP_OPACITY: u8 = 179;
const MODAL_TOP_MARGIN: f32 = 35.;
#[derive(Clone)]
pub struct Modal<T> {
@@ -34,6 +38,9 @@ pub struct Modal<T> {
close_modal_hover_state: MouseStateHandle,
background_opacity: u8,
offset_positioning: OffsetPositioning,
max_height_percentage: Option<f32>,
/// Optional keystroke to display alongside the close button.
dismiss_keystroke: Option<Keystroke>,
}
#[derive(Clone, Debug, Default)]
@@ -101,7 +108,7 @@ pub fn init(app: &mut AppContext) {
)]);
}
#[derive(PartialEq, Eq)]
#[derive(PartialEq, Eq, Debug)]
pub enum ModalEvent {
Close,
}
@@ -156,8 +163,10 @@ impl<T: View> Modal<T> {
..Default::default()
},
close_modal_hover_state: Default::default(),
background_opacity: 179,
background_opacity: MODAL_BACKDROP_OPACITY,
offset_positioning: Self::default_offset_positioning(),
max_height_percentage: None,
dismiss_keystroke: None,
}
}
@@ -195,6 +204,17 @@ impl<T: View> Modal<T> {
self.background_opacity = opacity;
self
}
/// Caps the modal height at a percentage of the containing window height.
pub fn with_max_height_percentage(mut self, percentage: f32) -> Self {
self.max_height_percentage = Some(percentage.clamp(0., 1.));
self
}
/// Set the keystroke to display alongside the close button.
pub fn with_dismiss_keystroke(mut self, keystroke: Keystroke) -> Self {
self.dismiss_keystroke = Some(keystroke);
self
}
pub fn set_title(&mut self, title: Option<String>) {
self.title = title;
@@ -236,13 +256,44 @@ impl<T: View> Modal<T> {
}
fn render_close_modal_button(&self, appearance: &Appearance) -> Box<dyn Element> {
use ui_components::{keyboard_shortcut, Component};
const BUTTON_DIAMETER: f32 = 24.;
appearance
let close_button = appearance
.ui_builder()
.close_button(BUTTON_DIAMETER, self.close_modal_hover_state.clone())
.build()
.on_click(|ctx, _, _| ctx.dispatch_typed_action(ModalAction::Close))
.finish()
.finish();
if let Some(keystroke) = &self.dismiss_keystroke {
let theme = appearance.theme();
Flex::row()
.with_cross_axis_alignment(CrossAxisAlignment::Center)
.with_child(close_button)
.with_child(
Container::new(keyboard_shortcut::KeyboardShortcut.render(
appearance,
keyboard_shortcut::Params {
keystroke: keystroke.clone(),
options: keyboard_shortcut::Options {
font_color: Some(theme.nonactive_ui_text_color().into()),
background: Some(blended_colors::neutral_3(theme).into()),
border_fill: None,
sizing: keyboard_shortcut::Sizing {
font_size: 11.,
padding: 5.,
},
},
},
))
.with_margin_left(4.)
.finish(),
)
.finish()
} else {
close_button
}
}
fn render_header_icon(&self, appearance: &Appearance) -> Option<Box<dyn Element>> {
@@ -345,7 +396,7 @@ impl<T: View> Modal<T> {
}
}
fn render_body(&self) -> Box<dyn Element> {
fn render_body(&self, max_height: f32) -> Box<dyn Element> {
let mut container = Container::new(ChildView::new(&self.body).finish());
if self.title.is_some() {
@@ -365,7 +416,7 @@ impl<T: View> Modal<T> {
.with_padding_bottom(padding.bottom);
}
ConstrainedBox::new(container.finish())
.with_max_height(self.body_styles.height.unwrap())
.with_max_height(max_height)
.finish()
}
@@ -413,17 +464,32 @@ impl<T: View> View for Modal<T> {
fn render(&self, app: &AppContext) -> Box<dyn Element> {
let appearance = Appearance::as_ref(app);
let has_relative_max_height = self.max_height_percentage.is_some();
let body_max_height = if has_relative_max_height {
f32::INFINITY
} else {
self.body_styles.height.unwrap()
};
let modal_max_height = if has_relative_max_height {
f32::INFINITY
} else {
self.modal_styles.height.unwrap()
};
let body = self.render_body(body_max_height);
let header = self.render_header(appearance);
let contents = if let Some(header) = header {
Flex::column()
.with_child(header)
.with_child(self.render_body())
.finish()
let mut contents = Flex::column().with_child(header);
if has_relative_max_height {
contents.add_child(Shrinkable::new(1., body).finish());
} else {
contents.add_child(body);
}
contents.finish()
} else {
self.render_body()
body
};
let mut modal = ConstrainedBox::new(
let modal = ConstrainedBox::new(
Container::new(contents)
.with_background(blended_colors::neutral_2(appearance.theme()))
.with_corner_radius(self.modal_styles.border_radius.unwrap_or_default())
@@ -431,12 +497,17 @@ impl<T: View> View for Modal<T> {
Border::all(self.modal_styles.border_width.unwrap())
.with_border_fill(self.modal_styles.border_color.unwrap()),
)
.with_margin_top(35.)
.with_margin_top(MODAL_TOP_MARGIN)
.finish(),
)
.with_max_width(self.modal_styles.width.unwrap())
.with_max_height(self.modal_styles.height.unwrap())
.with_max_height(modal_max_height)
.finish();
let mut modal = if let Some(max_height_percentage) = self.max_height_percentage {
Percentage::height(max_height_percentage, modal).finish()
} else {
modal
};
if self.dismiss_on_click {
modal = Dismiss::new(modal)