first pass of merging in warp (doesn't build)
This commit is contained in:
+97
-26
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user