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
@@ -1,23 +1,16 @@
use pathfinder_geometry::vector::vec2f;
use std::borrow::Cow;
use pathfinder_geometry::vector::vec2f;
use crate::elements::{
Align, ChildAnchor, CrossAxisAlignment, Flex, MainAxisAlignment, MainAxisSize,
Align, Border, ChildAnchor, ConstrainedBox, Container, CrossAxisAlignment, Element, Empty,
Flex, Hoverable, Icon, MainAxisAlignment, MainAxisSize, MouseState, MouseStateHandle,
OffsetPositioning, ParentAnchor, ParentElement, ParentOffsetBounds, Shrinkable, Stack,
};
use crate::geometry::vector::Vector2F;
use crate::platform::Cursor;
use crate::{
elements::{
Border, ConstrainedBox, Container, Element, Empty, Hoverable, Icon, MouseState,
MouseStateHandle,
},
ui_components::{
components::{UiComponent, UiComponentStyles},
text::Span,
},
};
use crate::ui_components::components::{UiComponent, UiComponentStyles};
use crate::ui_components::text::Span;
/// Enum specifying relative alignment of the text and icon within
/// a button. "First" is used instead of left/right to make this
@@ -1,16 +1,15 @@
use lazy_static::lazy_static;
use crate::color::ColorU;
use crate::elements::{ChildAnchor, ParentAnchor, ParentOffsetBounds};
use crate::elements::{
Align, Border, ChildAnchor, ConstrainedBox, Container, Element, Flex, Hoverable, Icon,
MouseState, MouseStateHandle, OffsetPositioning, ParentAnchor, ParentElement,
ParentOffsetBounds, Rect, Stack,
};
use crate::geometry::vector::Vector2F;
use crate::prelude::{Coords, Fill};
use crate::{
elements::{
Align, Border, ConstrainedBox, Container, Element, Flex, Hoverable, Icon, MouseState,
MouseStateHandle, OffsetPositioning, ParentElement, Rect, Stack,
},
ui_components::components::{UiComponent, UiComponentStyles},
ui_components::text::Span,
};
use lazy_static::lazy_static;
use crate::ui_components::components::{UiComponent, UiComponentStyles};
use crate::ui_components::text::Span;
const CHECK_SVG_PATH: &str = "bundled/svg/check-thick.svg";
+16 -20
View File
@@ -1,16 +1,11 @@
use crate::{
elements::{
ConstrainedBox, Container, CrossAxisAlignment, Flex, Icon, MainAxisAlignment, MainAxisSize,
ParentElement,
},
scene::Border,
Element,
};
use super::{
components::{UiComponent, UiComponentStyles},
text::Span,
use super::components::{UiComponent, UiComponentStyles};
use super::text::Span;
use crate::elements::{
ConstrainedBox, Container, CrossAxisAlignment, Flex, Icon, MainAxisAlignment, MainAxisSize,
ParentElement,
};
use crate::scene::Border;
use crate::Element;
pub struct Chip {
label: String,
@@ -54,6 +49,7 @@ impl UiComponent for Chip {
.with_cross_axis_alignment(CrossAxisAlignment::Center)
.with_main_axis_size(MainAxisSize::Min);
let has_icon = self.icon.is_some();
if let Some(icon) = self.icon {
label_and_button.add_child(
ConstrainedBox::new(icon.finish())
@@ -63,15 +59,15 @@ impl UiComponent for Chip {
);
}
label_and_button.add_child(
Container::new(
ConstrainedBox::new(Span::new(self.label, styles).build().finish())
.with_max_width(240.)
.finish(),
)
.with_margin_left(5.)
.finish(),
let mut label_container = Container::new(
ConstrainedBox::new(Span::new(self.label, styles).build().finish())
.with_max_width(240.)
.finish(),
);
if has_icon {
label_container = label_container.with_margin_left(5.);
}
label_and_button.add_child(label_container.finish());
if let Some(close_button) = self.close_button {
label_and_button.add_child(Container::new(close_button).with_margin_left(10.).finish());
@@ -1,9 +1,7 @@
use crate::{
color::ColorU,
elements::{Element, Fill},
fonts::{FamilyId, Properties, Weight},
scene::CornerRadius,
};
use crate::color::ColorU;
use crate::elements::{Element, Fill};
use crate::fonts::{FamilyId, Properties, Weight};
use crate::scene::CornerRadius;
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
pub enum BorderStyle {
@@ -167,5 +165,5 @@ pub trait UiComponent {
}
#[cfg(test)]
#[path = "components_test.rs"]
#[path = "components_tests.rs"]
mod tests;
@@ -0,0 +1,26 @@
use super::*;
#[test]
fn ui_element_style_merge_test() {
let style1 = UiComponentStyles {
width: Some(24.),
..Default::default()
};
let style2 = UiComponentStyles {
width: Some(25.),
font_size: Some(14.),
..Default::default()
};
assert_eq!(style2, style1.merge(style2));
let style3 = UiComponentStyles {
font_size: Some(14.),
..Default::default()
};
let style4 = UiComponentStyles {
width: Some(24.),
font_size: Some(14.),
..Default::default()
};
assert_eq!(style4, style1.merge(style3));
}
@@ -3,20 +3,15 @@ use std::sync::Arc;
use itertools::Itertools;
use crate::elements::{Icon, DEFAULT_UI_LINE_HEIGHT_RATIO};
use crate::{
elements::{
Align, ConstrainedBox, Container, CrossAxisAlignment, Element, Flex, MinSize, ParentElement,
},
keymap::Keystroke,
platform::OperatingSystem,
scene::Border,
};
use super::{
components::{UiComponent, UiComponentStyles},
text::Span,
use super::components::{UiComponent, UiComponentStyles};
use super::text::Span;
use crate::elements::{
Align, ConstrainedBox, Container, CrossAxisAlignment, Element, Flex, Icon, MinSize,
ParentElement, DEFAULT_UI_LINE_HEIGHT_RATIO,
};
use crate::keymap::Keystroke;
use crate::platform::OperatingSystem;
use crate::scene::Border;
type IconForKeystrokeFn = Arc<dyn Fn(&str) -> Option<Icon>>;
@@ -1,10 +1,8 @@
use crate::{
elements::{Border, Container, Element, Hoverable, MouseState, MouseStateHandle, Text},
fonts::Properties,
platform::Cursor,
ui_components::components::{UiComponent, UiComponentStyles},
EventContext,
};
use crate::elements::{Border, Container, Element, Hoverable, MouseState, MouseStateHandle, Text};
use crate::fonts::Properties;
use crate::platform::Cursor;
use crate::ui_components::components::{UiComponent, UiComponentStyles};
use crate::EventContext;
pub type OnClickFn = Box<dyn Fn(&mut EventContext)>;
@@ -1,9 +1,7 @@
use pathfinder_color::ColorU;
use crate::{
elements::{Container, Element, Flex, ParentElement, Text},
ui_components::components::{Coords, UiComponent, UiComponentStyles},
};
use crate::elements::{Container, Element, Flex, ParentElement, Text};
use crate::ui_components::components::{Coords, UiComponent, UiComponentStyles};
const BULLET: &str = "";
@@ -1,8 +1,5 @@
use crate::elements::{ConstrainedBox, Empty, Flex, ParentElement};
use crate::{
elements::{Container, Element},
ui_components::components::{UiComponent, UiComponentStyles},
};
use crate::elements::{ConstrainedBox, Container, Element, Empty, Flex, ParentElement};
use crate::ui_components::components::{UiComponent, UiComponentStyles};
pub struct ProgressBar {
progress: f32,
@@ -1,23 +1,20 @@
use std::{borrow::Cow, rc::Rc};
use crate::{elements::FormattedTextElement, platform::Cursor, AppContext, EventContext};
use std::borrow::Cow;
use std::rc::Rc;
use lazy_static::lazy_static;
use parking_lot::Mutex;
use pathfinder_color::ColorU;
use pathfinder_geometry::vector::Vector2F;
use crate::{
elements::{
ChildAnchor, ConstrainedBox, Container, CrossAxisAlignment, Flex, Hoverable,
MouseStateHandle, OffsetPositioning, ParentAnchor, ParentElement, ParentOffsetBounds, Rect,
Stack,
},
scene::{Border, CornerRadius, Radius},
Element,
};
use super::components::{Coords, UiComponent, UiComponentStyles};
use lazy_static::lazy_static;
use crate::elements::{
ChildAnchor, ConstrainedBox, Container, CrossAxisAlignment, Flex, FormattedTextElement,
Hoverable, MouseStateHandle, OffsetPositioning, ParentAnchor, ParentElement,
ParentOffsetBounds, Rect, Stack,
};
use crate::platform::Cursor;
use crate::scene::{Border, CornerRadius, Radius};
use crate::{AppContext, Element, EventContext};
const LABEL_LEFT_MARGIN: f32 = 8.;
const BORDER_WIDTH: f32 = 1.5;
@@ -1,25 +1,21 @@
use core::fmt;
use std::borrow::Cow;
use std::boxed::Box;
use itertools::Itertools;
use crate::{
color::ColorU,
elements::{
Align, Border, ConstrainedBox, Container, CornerRadius, CrossAxisAlignment, Fill, Flex,
Icon, MainAxisAlignment, MouseStateHandle, ParentElement, Radius, Text,
},
fonts::FamilyId,
platform::Cursor,
ui_components::{
button::Button,
components::{Coords, UiComponent, UiComponentStyles},
tool_tip::{Tooltip, TooltipWithSublabel},
},
AppContext, Element, Entity, TypedActionView, View, ViewContext,
};
use core::fmt;
use std::{borrow::Cow, boxed::Box};
use super::button::ButtonTooltipPosition;
use crate::color::ColorU;
use crate::elements::{
Align, Border, ConstrainedBox, Container, CornerRadius, CrossAxisAlignment, Fill, Flex, Icon,
MainAxisAlignment, MouseStateHandle, ParentElement, Radius, Text,
};
use crate::fonts::FamilyId;
use crate::platform::Cursor;
use crate::ui_components::button::Button;
use crate::ui_components::components::{Coords, UiComponent, UiComponentStyles};
use crate::ui_components::tool_tip::{Tooltip, TooltipWithSublabel};
use crate::{AppContext, Element, Entity, TypedActionView, View, ViewContext};
const MAX_WIDTH: f32 = 300.0;
/// A segmented control component with multiple selectable options
@@ -236,7 +232,10 @@ impl<T: SegmentedControlOption> View for SegmentedControl<T> {
);
if let Some(label_config) = option_config.label.take() {
let font_size = if cfg!(any(windows, target_os = "linux")) {
let font_size = if cfg!(any(
windows,
any(target_os = "linux", target_os = "freebsd")
)) {
// Reduce the font size by one to avoid text being cut off on Windows and Linux.
self.styles.font_size.unwrap_or(12.0) - 1.0
} else {
+208 -98
View File
@@ -1,22 +1,22 @@
use std::{ops::Range, sync::Arc};
use std::ops::Range;
use std::sync::Arc;
use crate::platform::Cursor;
use crate::{
elements::{
AnchorPair, ConstrainedBox, Container, CornerRadius, DragAxis, Draggable, DraggableState,
DropShadow, Fill, Hoverable, MouseStateHandle, OffsetPositioning, OffsetType,
ParentElement, ParentOffsetBounds, PositionedElementOffsetBounds, PositioningAxis, Radius,
Rect, SavePosition, Stack, XAxisAnchor, YAxisAnchor,
},
ui_components::components::UiComponentStyles,
AppContext, Element, EventContext,
};
use lazy_static::lazy_static;
use parking_lot::{Mutex, RwLock};
use pathfinder_color::ColorU;
use pathfinder_geometry::{rect::RectF, vector::vec2f};
use pathfinder_geometry::rect::RectF;
use pathfinder_geometry::vector::vec2f;
use super::components::UiComponent;
use crate::elements::{
AnchorPair, ConstrainedBox, Container, CornerRadius, DragAxis, Draggable, DraggableState,
DropShadow, Fill, Hoverable, MouseStateHandle, OffsetPositioning, OffsetType, ParentElement,
ParentOffsetBounds, PositionedElementOffsetBounds, PositioningAxis, Radius, Rect, SavePosition,
Stack, XAxisAnchor, YAxisAnchor,
};
use crate::platform::Cursor;
use crate::ui_components::components::UiComponentStyles;
use crate::{AppContext, Element, EventContext};
const DEFAULT_THUMB_SIZE: f32 = 18.;
const DEFAULT_TRACK_HEIGHT: f32 = 4.;
@@ -61,15 +61,6 @@ impl SliderStateHandle {
self.inner.lock().thumb_offset_x
}
// Returns the 'value' represented by the slider's current position along the track. The
// returned value is normalized to the given value_range.
fn get_value(&self, draggable_width: f32, value_range: &Range<f32>) -> f32 {
let state = self.inner.lock();
let thumb_offset_x = state.thumb_offset_x.unwrap_or(0.);
let canonical_value = thumb_offset_x / draggable_width;
canonical_value * (value_range.end - value_range.start) + value_range.start
}
/// Sets the inner [`SliderState`] to `new_state`.
fn store(&self, new_state: SliderState) {
let mut guard = self.inner.lock();
@@ -89,6 +80,18 @@ impl SliderStateHandle {
/// value has changed.
type OnValueChangedFn = dyn Fn(&mut EventContext, &AppContext, f32) + 'static;
/// Shared track geometry and snapping configuration passed to every
/// slider callback registration function.
#[derive(Clone)]
struct SliderTrackConfig {
track_position_id: String,
thumb_size: f32,
value_range: Range<f32>,
step: Option<f32>,
snap_values: Option<Arc<Vec<f32>>>,
state_handle: SliderStateHandle,
}
/// Slider UiComponent for modulating a value between given bounds.
///
/// Builder methods allow the caller to configure the styling of the slider, as well as set a
@@ -106,6 +109,8 @@ pub struct Slider {
styles: UiComponentStyles,
value_range: Range<f32>,
default_value: Option<f32>,
step: Option<f32>,
snap_values: Option<Arc<Vec<f32>>>,
}
impl Slider {
@@ -121,12 +126,33 @@ impl Slider {
thumb_fill: *DEFAULT_THUMB_FILL,
value_range: 0.0..1.,
default_value: None,
step: None,
snap_values: None,
styles: UiComponentStyles {
..Default::default()
},
}
}
/// Sets a step size so that both the thumb and emitted value snap to
/// discrete increments of `step` from `value_range.start`. `value_range.end`
/// is always reachable even if it isn't step-aligned.
pub fn with_step(mut self, step: f32) -> Self {
self.step = Some(step);
self
}
/// Sets an explicit list of discrete values that the slider snaps to.
/// Drag/drop/click events snap to the nearest value in the list by
/// absolute distance, and the thumb is positioned **linearly** based on
/// the value (`(value - start) / (end - start)`) — this keeps
/// non-step-aligned inputs from looking logarithmic. Takes precedence
/// over [`Self::with_step`] when set.
pub fn with_snap_values(mut self, values: Vec<f32>) -> Self {
self.snap_values = Some(Arc::new(values));
self
}
pub fn with_thumb_size(mut self, thumb_size: f32) -> Self {
self.thumb_size = thumb_size;
self
@@ -184,21 +210,33 @@ impl Slider {
/// thumb.
///
/// This callback stores the thumb's x-axis offset from the start of the track in the
/// given `SliderStateHandle`.
fn register_on_drag_start_callback(
thumb_draggable: &mut Draggable,
track_position_id: String,
state_handle: SliderStateHandle,
) {
/// given `SliderStateHandle`, snapping if configured.
fn register_on_drag_start_callback(thumb_draggable: &mut Draggable, config: SliderTrackConfig) {
thumb_draggable.set_on_drag_start(move |event_ctx, _app, thumb_position| {
let track_position = event_ctx
.element_position_by_id(track_position_id.as_str())
.element_position_by_id(config.track_position_id.as_str())
.expect("Track should be laid out by the time the slider is dragged.");
// Save the position along the x-axis of the thumb when the drag started.
state_handle.store(SliderState {
thumb_offset_x: Some(thumb_position.origin_x() - track_position.origin_x()),
let raw_offset_x = thumb_position.origin_x() - track_position.origin_x();
let draggable_width = draggable_width(track_position, config.thumb_size);
let (snapped_offset_x, _) = snap_offset_and_value(
raw_offset_x,
draggable_width,
&config.value_range,
config.step,
config.snap_values.as_deref().map(Vec::as_slice),
);
config.state_handle.store(SliderState {
thumb_offset_x: Some(snapped_offset_x),
});
let delta = snapped_offset_x - raw_offset_x;
if delta.abs() > f32::EPSILON {
config
.state_handle
.thumb_draggable_state
.adjust_mouse_position(vec2f(delta, 0.));
}
});
}
@@ -211,31 +249,39 @@ impl Slider {
/// state.
fn register_on_drag_callback(
thumb_draggable: &mut Draggable,
track_position_id: String,
thumb_size: f32,
value_range: Range<f32>,
state_handle: SliderStateHandle,
config: SliderTrackConfig,
on_drag_callback: Option<Box<OnValueChangedFn>>,
) {
thumb_draggable.set_on_drag(move |event_ctx, app, thumb_position, _| {
let track_position = event_ctx
.element_position_by_id(track_position_id.as_str())
.element_position_by_id(config.track_position_id.as_str())
.expect("Track should be laid out by the time the slider is dragged.");
let current_thumb_offset_x = thumb_position.origin_x() - track_position.origin_x();
let raw_offset_x = thumb_position.origin_x() - track_position.origin_x();
let draggable_width = draggable_width(track_position, config.thumb_size);
let (snapped_offset_x, snapped_value) = snap_offset_and_value(
raw_offset_x,
draggable_width,
&config.value_range,
config.step,
config.snap_values.as_deref().map(Vec::as_slice),
);
// The on_drag callback is called even if the draggable element's position
// hasn't changed -- only call the on_change callback if the slider's
// position has changed.
if Some(current_thumb_offset_x) != state_handle.thumb_offset_x() {
state_handle.store(SliderState {
thumb_offset_x: Some(current_thumb_offset_x),
let delta = snapped_offset_x - raw_offset_x;
if delta.abs() > f32::EPSILON {
config
.state_handle
.thumb_draggable_state
.adjust_mouse_position(vec2f(delta, 0.));
}
if Some(snapped_offset_x) != config.state_handle.thumb_offset_x() {
config.state_handle.store(SliderState {
thumb_offset_x: Some(snapped_offset_x),
});
if let Some(callback) = &on_drag_callback {
let draggable_width = draggable_width(track_position, thumb_size);
let updated_value = state_handle.get_value(draggable_width, &value_range);
callback(event_ctx, app, updated_value);
callback(event_ctx, app, snapped_value);
}
}
});
@@ -249,24 +295,28 @@ impl Slider {
/// `thumb_offset_x` in the slider's state.
fn register_on_drop_callback(
thumb_draggable: &mut Draggable,
track_position_id: String,
thumb_size: f32,
value_range: Range<f32>,
state_handle: SliderStateHandle,
config: SliderTrackConfig,
on_change_callback: Option<Arc<OnValueChangedFn>>,
) {
thumb_draggable.set_on_drop(move |event_ctx, app, thumb_position, _| {
let track_position = event_ctx
.element_position_by_id(track_position_id.as_str())
.element_position_by_id(config.track_position_id.as_str())
.expect("Track should be laid out by the time the slider is dropped.");
state_handle.store(SliderState {
thumb_offset_x: Some(thumb_position.origin_x() - track_position.origin_x()),
let raw_offset_x = thumb_position.origin_x() - track_position.origin_x();
let draggable_width = draggable_width(track_position, config.thumb_size);
let (snapped_offset_x, snapped_value) = snap_offset_and_value(
raw_offset_x,
draggable_width,
&config.value_range,
config.step,
config.snap_values.as_deref().map(Vec::as_slice),
);
config.state_handle.store(SliderState {
thumb_offset_x: Some(snapped_offset_x),
});
if let Some(callback) = &on_change_callback {
let draggable_width = draggable_width(track_position, thumb_size);
let updated_value = state_handle.get_value(draggable_width, &value_range);
callback(event_ctx, app, updated_value);
callback(event_ctx, app, snapped_value);
}
});
}
@@ -278,42 +328,113 @@ impl Slider {
/// dragged the thumb to that location, without all the intermediate on_drag calls.
fn register_on_click_callback(
track_hoverable: Hoverable,
track_position_id: String,
thumb_size: f32,
value_range: Range<f32>,
state_handle: SliderStateHandle,
config: SliderTrackConfig,
on_change_callback: Option<Arc<OnValueChangedFn>>,
) -> Hoverable {
track_hoverable.on_click(move |event_ctx, app, click_position| {
let Some(track_position) = event_ctx.element_position_by_id(track_position_id.as_str())
let Some(track_position) =
event_ctx.element_position_by_id(config.track_position_id.as_str())
else {
return;
};
let click_position_x = click_position.x();
let padding = thumb_size / 2.;
let padding = config.thumb_size / 2.;
let min_x = track_position.min_x() + padding;
let max_x = track_position.max_x() - padding;
// If the user clicks outside of the actual visible portion of the track,
// we do not proceed.
if min_x > click_position_x || max_x < click_position_x {
return;
}
state_handle.store(SliderState {
thumb_offset_x: Some(click_position_x - min_x),
let raw_offset_x = click_position_x - min_x;
let draggable_width = draggable_width(track_position, config.thumb_size);
let (snapped_offset_x, snapped_value) = snap_offset_and_value(
raw_offset_x,
draggable_width,
&config.value_range,
config.step,
config.snap_values.as_deref().map(Vec::as_slice),
);
config.state_handle.store(SliderState {
thumb_offset_x: Some(snapped_offset_x),
});
if let Some(callback) = &on_change_callback {
let draggable_width = draggable_width(track_position, thumb_size);
let updated_value = state_handle.get_value(draggable_width, &value_range);
callback(event_ctx, app, updated_value);
callback(event_ctx, app, snapped_value);
}
})
}
}
/// Snaps `raw_offset_x` (a pixel offset along the slider track) to the
/// nearest discrete position, returning both the snapped pixel offset and
/// the corresponding value.
///
/// If `snap_values` is provided it takes precedence: the raw value (linearly
/// derived from the pixel position and `value_range`) is snapped to the
/// nearest entry in the list by absolute distance, and the returned pixel
/// offset is positioned **linearly** by the snapped value — so positions
/// along the slider always match the value scale. Otherwise `step` (if any)
/// is used for linear stepping from `value_range.start`.
fn snap_offset_and_value(
raw_offset_x: f32,
draggable_width: f32,
value_range: &Range<f32>,
step: Option<f32>,
snap_values: Option<&[f32]>,
) -> (f32, f32) {
if draggable_width <= 0. {
return (raw_offset_x, value_range.start);
}
let canonical = (raw_offset_x / draggable_width).clamp(0., 1.);
let raw_value = canonical * (value_range.end - value_range.start) + value_range.start;
if let Some(values) = snap_values {
if !values.is_empty() {
// Snap to nearest value by absolute distance.
let snapped_value = values.iter().copied().fold(values[0], |best, v| {
if (v - raw_value).abs() < (best - raw_value).abs() {
v
} else {
best
}
});
let snapped_canonical = value_to_canonical_linear(snapped_value, value_range);
return (snapped_canonical * draggable_width, snapped_value);
}
}
let Some(step) = step.filter(|s| *s > 0.) else {
return (raw_offset_x, raw_value);
};
// Snap to nearest step from `range.start`, with `range.end` always reachable.
let snapped_value = if value_range.end - raw_value < step / 2. {
value_range.end
} else {
let offset_from_start = raw_value - value_range.start;
let steps = (offset_from_start / step).round();
(value_range.start + steps * step).clamp(value_range.start, value_range.end)
};
let snapped_canonical = value_to_canonical_linear(snapped_value, value_range);
(snapped_canonical * draggable_width, snapped_value)
}
/// Linearly maps `value` to a canonical 0..1 position along the slider
/// track. Used both for snap positioning and for rendering `default_value`,
/// so non-snap values (e.g. typed into a freeform input box) render at a
/// position proportional to their actual magnitude.
fn value_to_canonical_linear(value: f32, value_range: &Range<f32>) -> f32 {
let span = value_range.end - value_range.start;
if span <= 0. {
return 0.;
}
((value - value_range.start) / span).clamp(0., 1.)
}
impl UiComponent for Slider {
type ElementType = Container;
@@ -330,6 +451,8 @@ impl UiComponent for Slider {
styles,
value_range,
default_value,
step,
snap_values,
} = self;
let track_position_id = slider_track_position_id.clone();
@@ -354,25 +477,20 @@ impl UiComponent for Slider {
})
});
Self::register_on_drag_start_callback(
&mut slider_thumb,
slider_track_position_id.clone(),
state_handle.clone(),
);
Self::register_on_drag_callback(
&mut slider_thumb,
slider_track_position_id.clone(),
let config = SliderTrackConfig {
track_position_id: slider_track_position_id.clone(),
thumb_size,
value_range.clone(),
state_handle.clone(),
on_drag_callback,
);
value_range: value_range.clone(),
step,
snap_values,
state_handle: state_handle.clone(),
};
Self::register_on_drag_start_callback(&mut slider_thumb, config.clone());
Self::register_on_drag_callback(&mut slider_thumb, config.clone(), on_drag_callback);
Self::register_on_drop_callback(
&mut slider_thumb,
slider_track_position_id.clone(),
thumb_size,
value_range.clone(),
state_handle.clone(),
config.clone(),
on_change_callback.clone(),
);
@@ -380,14 +498,7 @@ impl UiComponent for Slider {
render_track(thumb_size, styles.width, track_height, track_fill)
});
let track = Self::register_on_click_callback(
track,
slider_track_position_id.clone(),
thumb_size,
value_range.clone(),
state_handle.clone(),
on_change_callback.clone(),
);
let track = Self::register_on_click_callback(track, config, on_change_callback.clone());
let mut slider = Stack::new();
@@ -399,10 +510,7 @@ impl UiComponent for Slider {
Some(offset_x) => OffsetType::Pixel(offset_x),
None => OffsetType::Percentage(
default_value
.map(|value| {
((value - value_range.start) / (value_range.end - value_range.start))
.clamp(0., 1.)
})
.map(|value| value_to_canonical_linear(value, &value_range))
.unwrap_or(0.),
),
};
@@ -448,6 +556,8 @@ impl UiComponent for Slider {
thumb_fill: self.thumb_fill,
value_range: self.value_range,
default_value: self.default_value,
step: self.step,
snap_values: self.snap_values,
styles: self.styles.merge(styles),
}
}
@@ -1,21 +1,17 @@
use lazy_static::lazy_static;
use crate::color::ColorU;
use crate::elements::{
AnchorPair, ChildAnchor, Empty, Fill, OffsetPositioning, OffsetType, ParentAnchor,
ParentOffsetBounds, PositioningAxis, Stack, XAxisAnchor, YAxisAnchor,
AnchorPair, ChildAnchor, ConstrainedBox, Container, CornerRadius, Element, Empty, Fill, Flex,
Hoverable, MouseState, MouseStateHandle, OffsetPositioning, OffsetType, ParentAnchor,
ParentElement, ParentOffsetBounds, PositioningAxis, Rect, Stack, XAxisAnchor, YAxisAnchor,
};
use crate::geometry::vector::vec2f;
use crate::platform::Cursor;
use crate::scene::{DropShadow, Radius};
use crate::{
elements::{
ConstrainedBox, Container, CornerRadius, Element, Flex, Hoverable, MouseState,
MouseStateHandle, ParentElement, Rect,
},
ui_components::components::{UiComponent, UiComponentStyles},
ui_components::text::Span,
ui_components::tool_tip::Tooltip,
};
use lazy_static::lazy_static;
use crate::ui_components::components::{UiComponent, UiComponentStyles};
use crate::ui_components::text::Span;
use crate::ui_components::tool_tip::Tooltip;
const DEFAULT_THUMB_HEIGHT: f32 = 18.;
@@ -1,13 +1,13 @@
use std::borrow::Cow;
use crate::elements::{Highlight, HighlightedRange, DEFAULT_UI_LINE_HEIGHT_RATIO};
use crate::{
elements::{Container, Element, Text},
fonts::Properties,
ui_components::components::{UiComponent, UiComponentStyles},
};
use itertools::Itertools;
use crate::elements::{
Container, Element, Highlight, HighlightedRange, Text, DEFAULT_UI_LINE_HEIGHT_RATIO,
};
use crate::fonts::Properties;
use crate::ui_components::components::{UiComponent, UiComponentStyles};
#[derive(Debug, Clone, Default)]
pub struct WrappableText {
text: Cow<'static, str>,
@@ -1,9 +1,6 @@
use crate::elements::{ChildView, Clipped};
use crate::{
elements::{Border, ConstrainedBox, Container, Element},
ui_components::components::{UiComponent, UiComponentStyles},
View, ViewHandle,
};
use crate::elements::{Border, ChildView, Clipped, ConstrainedBox, Container, Element};
use crate::ui_components::components::{UiComponent, UiComponentStyles};
use crate::{View, ViewHandle};
pub struct TextInput<T: View> {
editor: ViewHandle<T>,
@@ -1,18 +1,13 @@
use pathfinder_geometry::vector::vec2f;
use crate::{
elements::{
ChildAnchor, ConstrainedBox, Container, Empty, Hoverable, MouseState, MouseStateHandle,
OffsetPositioning, ParentAnchor, ParentElement, ParentOffsetBounds, Stack,
},
scene::Border,
Element,
};
use super::{
components::{UiComponent, UiComponentStyles},
text::Span,
use super::components::{UiComponent, UiComponentStyles};
use super::text::Span;
use crate::elements::{
ChildAnchor, ConstrainedBox, Container, Empty, Hoverable, MouseState, MouseStateHandle,
OffsetPositioning, ParentAnchor, ParentElement, ParentOffsetBounds, Stack,
};
use crate::scene::Border;
use crate::Element;
/// A button element used to toggle a single value on or off.
pub struct ToggleButton {
@@ -1,24 +1,21 @@
use std::{borrow::Cow, rc::Rc, sync::Arc};
use crate::{
elements::{
Container, CrossAxisAlignment, Empty, Flex, Hoverable, MainAxisSize, MouseStateHandle,
ParentElement, Shrinkable,
},
platform::Cursor,
scene::{CornerRadius, Radius},
AppContext, Element, EventContext,
};
use std::borrow::Cow;
use std::rc::Rc;
use std::sync::Arc;
use lazy_static::lazy_static;
use parking_lot::Mutex;
use pathfinder_color::ColorU;
use pathfinder_geometry::vector::Vector2F;
use super::{
components::{UiComponent, UiComponentStyles},
text::Span,
use super::components::{UiComponent, UiComponentStyles};
use super::text::Span;
use crate::elements::{
Container, CrossAxisAlignment, Empty, Flex, Hoverable, MainAxisSize, MouseStateHandle,
ParentElement, Shrinkable,
};
use lazy_static::lazy_static;
use crate::platform::Cursor;
use crate::scene::{CornerRadius, Radius};
use crate::{AppContext, Element, EventContext};
const BORDER_RADIUS: f32 = 4.;
const BUTTON_VERTICAL_PADDING: f32 = 2.;
@@ -1,9 +1,8 @@
use crate::{
elements::{Border, Container, Element, Flex, ParentElement, Text},
ui_components::components::{UiComponent, UiComponentStyles},
};
use pathfinder_color::ColorU;
use crate::elements::{Border, Container, Element, Flex, ParentElement, Text};
use crate::ui_components::components::{UiComponent, UiComponentStyles};
pub struct Tooltip {
label: String,
styles: UiComponentStyles,