Add support for resizing splits and docks, as well as utilities (#3595)
Making this PR to upstream changes to util and GPUI2, resizing exists but isn't working yet. Release Notes: - N/A
This commit is contained in:
@@ -513,6 +513,10 @@ impl AppContext {
|
||||
self.platform.path_for_auxiliary_executable(name)
|
||||
}
|
||||
|
||||
pub fn double_click_interval(&self) -> Duration {
|
||||
self.platform.double_click_interval()
|
||||
}
|
||||
|
||||
pub fn prompt_for_paths(
|
||||
&self,
|
||||
options: PathPromptOptions,
|
||||
|
||||
@@ -761,7 +761,7 @@ pub struct InteractiveBounds {
|
||||
|
||||
impl InteractiveBounds {
|
||||
pub fn visibly_contains(&self, point: &Point<Pixels>, cx: &WindowContext) -> bool {
|
||||
self.bounds.contains_point(point) && cx.was_top_layer(&point, &self.stacking_order)
|
||||
self.bounds.contains(point) && cx.was_top_layer(&point, &self.stacking_order)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -860,10 +860,10 @@ impl Interactivity {
|
||||
.and_then(|group_hover| GroupBounds::get(&group_hover.group, cx));
|
||||
|
||||
if let Some(group_bounds) = hover_group_bounds {
|
||||
let hovered = group_bounds.contains_point(&cx.mouse_position());
|
||||
let hovered = group_bounds.contains(&cx.mouse_position());
|
||||
cx.on_mouse_event(move |event: &MouseMoveEvent, phase, cx| {
|
||||
if phase == DispatchPhase::Capture {
|
||||
if group_bounds.contains_point(&event.position) != hovered {
|
||||
if group_bounds.contains(&event.position) != hovered {
|
||||
cx.notify();
|
||||
}
|
||||
}
|
||||
@@ -875,10 +875,10 @@ impl Interactivity {
|
||||
|| cx.active_drag.is_some() && !self.drag_over_styles.is_empty()
|
||||
{
|
||||
let bounds = bounds.intersect(&cx.content_mask().bounds);
|
||||
let hovered = bounds.contains_point(&cx.mouse_position());
|
||||
let hovered = bounds.contains(&cx.mouse_position());
|
||||
cx.on_mouse_event(move |event: &MouseMoveEvent, phase, cx| {
|
||||
if phase == DispatchPhase::Capture {
|
||||
if bounds.contains_point(&event.position) != hovered {
|
||||
if bounds.contains(&event.position) != hovered {
|
||||
cx.notify();
|
||||
}
|
||||
}
|
||||
@@ -1068,8 +1068,8 @@ impl Interactivity {
|
||||
let interactive_bounds = interactive_bounds.clone();
|
||||
cx.on_mouse_event(move |down: &MouseDownEvent, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble {
|
||||
let group = active_group_bounds
|
||||
.map_or(false, |bounds| bounds.contains_point(&down.position));
|
||||
let group =
|
||||
active_group_bounds.map_or(false, |bounds| bounds.contains(&down.position));
|
||||
let element = interactive_bounds.visibly_contains(&down.position, cx);
|
||||
if group || element {
|
||||
*active_state.borrow_mut() = ElementClickedState { group, element };
|
||||
@@ -1183,7 +1183,7 @@ impl Interactivity {
|
||||
let mouse_position = cx.mouse_position();
|
||||
if let Some(group_hover) = self.group_hover_style.as_ref() {
|
||||
if let Some(group_bounds) = GroupBounds::get(&group_hover.group, cx) {
|
||||
if group_bounds.contains_point(&mouse_position)
|
||||
if group_bounds.contains(&mouse_position)
|
||||
&& cx.was_top_layer(&mouse_position, cx.stacking_order())
|
||||
{
|
||||
style.refine(&group_hover.style);
|
||||
@@ -1193,7 +1193,7 @@ impl Interactivity {
|
||||
if self.hover_style.is_some() {
|
||||
if bounds
|
||||
.intersect(&cx.content_mask().bounds)
|
||||
.contains_point(&mouse_position)
|
||||
.contains(&mouse_position)
|
||||
&& cx.was_top_layer(&mouse_position, cx.stacking_order())
|
||||
{
|
||||
style.refine(&self.hover_style);
|
||||
@@ -1204,7 +1204,7 @@ impl Interactivity {
|
||||
for (state_type, group_drag_style) in &self.group_drag_over_styles {
|
||||
if let Some(group_bounds) = GroupBounds::get(&group_drag_style.group, cx) {
|
||||
if *state_type == drag.view.entity_type()
|
||||
&& group_bounds.contains_point(&mouse_position)
|
||||
&& group_bounds.contains(&mouse_position)
|
||||
{
|
||||
style.refine(&group_drag_style.style);
|
||||
}
|
||||
@@ -1215,7 +1215,7 @@ impl Interactivity {
|
||||
if *state_type == drag.view.entity_type()
|
||||
&& bounds
|
||||
.intersect(&cx.content_mask().bounds)
|
||||
.contains_point(&mouse_position)
|
||||
.contains(&mouse_position)
|
||||
{
|
||||
style.refine(drag_over_style);
|
||||
}
|
||||
|
||||
@@ -253,7 +253,7 @@ impl TextState {
|
||||
}
|
||||
|
||||
fn index_for_position(&self, bounds: Bounds<Pixels>, position: Point<Pixels>) -> Option<usize> {
|
||||
if !bounds.contains_point(&position) {
|
||||
if !bounds.contains(&position) {
|
||||
return None;
|
||||
}
|
||||
|
||||
|
||||
@@ -57,8 +57,12 @@ where
|
||||
T: 'static,
|
||||
E: 'static + Debug,
|
||||
{
|
||||
#[track_caller]
|
||||
pub fn detach_and_log_err(self, cx: &mut AppContext) {
|
||||
cx.foreground_executor().spawn(self.log_err()).detach();
|
||||
let location = core::panic::Location::caller();
|
||||
cx.foreground_executor()
|
||||
.spawn(self.log_tracked_err(*location))
|
||||
.detach();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,62 @@ use std::{
|
||||
ops::{Add, Div, Mul, MulAssign, Sub},
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
pub enum Axis {
|
||||
Vertical,
|
||||
Horizontal,
|
||||
}
|
||||
|
||||
impl Axis {
|
||||
pub fn invert(&self) -> Self {
|
||||
match self {
|
||||
Axis::Vertical => Axis::Horizontal,
|
||||
Axis::Horizontal => Axis::Vertical,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Along {
|
||||
type Unit;
|
||||
|
||||
fn along(&self, axis: Axis) -> Self::Unit;
|
||||
|
||||
fn apply_along(&self, axis: Axis, f: impl FnOnce(Self::Unit) -> Self::Unit) -> Self;
|
||||
}
|
||||
|
||||
impl sqlez::bindable::StaticColumnCount for Axis {}
|
||||
impl sqlez::bindable::Bind for Axis {
|
||||
fn bind(
|
||||
&self,
|
||||
statement: &sqlez::statement::Statement,
|
||||
start_index: i32,
|
||||
) -> anyhow::Result<i32> {
|
||||
match self {
|
||||
Axis::Horizontal => "Horizontal",
|
||||
Axis::Vertical => "Vertical",
|
||||
}
|
||||
.bind(statement, start_index)
|
||||
}
|
||||
}
|
||||
|
||||
impl sqlez::bindable::Column for Axis {
|
||||
fn column(
|
||||
statement: &mut sqlez::statement::Statement,
|
||||
start_index: i32,
|
||||
) -> anyhow::Result<(Self, i32)> {
|
||||
String::column(statement, start_index).and_then(|(axis_text, next_index)| {
|
||||
Ok((
|
||||
match axis_text.as_str() {
|
||||
"Horizontal" => Axis::Horizontal,
|
||||
"Vertical" => Axis::Vertical,
|
||||
_ => anyhow::bail!("Stored serialized item kind is incorrect"),
|
||||
},
|
||||
next_index,
|
||||
))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Describes a location in a 2D cartesian coordinate space.
|
||||
///
|
||||
/// It holds two public fields, `x` and `y`, which represent the coordinates in the space.
|
||||
@@ -96,6 +152,30 @@ impl<T: Clone + Debug + Default> Point<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone + Debug + Default> Along for Point<T> {
|
||||
type Unit = T;
|
||||
|
||||
fn along(&self, axis: Axis) -> T {
|
||||
match axis {
|
||||
Axis::Horizontal => self.x.clone(),
|
||||
Axis::Vertical => self.y.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_along(&self, axis: Axis, f: impl FnOnce(T) -> T) -> Point<T> {
|
||||
match axis {
|
||||
Axis::Horizontal => Point {
|
||||
x: f(self.x.clone()),
|
||||
y: self.y.clone(),
|
||||
},
|
||||
Axis::Vertical => Point {
|
||||
x: self.x.clone(),
|
||||
y: f(self.y.clone()),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Point<Pixels> {
|
||||
/// Scales the point by a given factor, which is typically derived from the resolution
|
||||
/// of a target display to ensure proper sizing of UI elements.
|
||||
@@ -373,6 +453,34 @@ impl Size<Pixels> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Along for Size<T>
|
||||
where
|
||||
T: Clone + Default + Debug,
|
||||
{
|
||||
type Unit = T;
|
||||
|
||||
fn along(&self, axis: Axis) -> T {
|
||||
match axis {
|
||||
Axis::Horizontal => self.width.clone(),
|
||||
Axis::Vertical => self.height.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the value of this size along the given axis.
|
||||
fn apply_along(&self, axis: Axis, f: impl FnOnce(T) -> T) -> Self {
|
||||
match axis {
|
||||
Axis::Horizontal => Size {
|
||||
width: f(self.width.clone()),
|
||||
height: self.height.clone(),
|
||||
},
|
||||
Axis::Vertical => Size {
|
||||
width: self.width.clone(),
|
||||
height: f(self.height.clone()),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Size<T>
|
||||
where
|
||||
T: PartialOrd + Clone + Default + Debug,
|
||||
@@ -992,7 +1100,7 @@ where
|
||||
/// assert!(bounds.contains_point(&inside_point));
|
||||
/// assert!(!bounds.contains_point(&outside_point));
|
||||
/// ```
|
||||
pub fn contains_point(&self, point: &Point<T>) -> bool {
|
||||
pub fn contains(&self, point: &Point<T>) -> bool {
|
||||
point.x >= self.origin.x
|
||||
&& point.x <= self.origin.x.clone() + self.size.width.clone()
|
||||
&& point.y >= self.origin.y
|
||||
|
||||
@@ -131,6 +131,12 @@ pub struct MouseMoveEvent {
|
||||
pub modifiers: Modifiers,
|
||||
}
|
||||
|
||||
impl MouseMoveEvent {
|
||||
pub fn dragging(&self) -> bool {
|
||||
self.pressed_button == Some(MouseButton::Left)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ScrollWheelEvent {
|
||||
pub position: Point<Pixels>,
|
||||
|
||||
@@ -105,6 +105,7 @@ pub(crate) trait Platform: 'static {
|
||||
fn app_version(&self) -> Result<SemanticVersion>;
|
||||
fn app_path(&self) -> Result<PathBuf>;
|
||||
fn local_timezone(&self) -> UtcOffset;
|
||||
fn double_click_interval(&self) -> Duration;
|
||||
fn path_for_auxiliary_executable(&self, name: &str) -> Result<PathBuf>;
|
||||
|
||||
fn set_cursor_style(&self, style: CursorStyle);
|
||||
|
||||
@@ -49,6 +49,7 @@ use std::{
|
||||
rc::Rc,
|
||||
slice, str,
|
||||
sync::Arc,
|
||||
time::Duration,
|
||||
};
|
||||
use time::UtcOffset;
|
||||
|
||||
@@ -657,6 +658,13 @@ impl Platform for MacPlatform {
|
||||
"macOS"
|
||||
}
|
||||
|
||||
fn double_click_interval(&self) -> Duration {
|
||||
unsafe {
|
||||
let double_click_interval: f64 = msg_send![class!(NSEvent), doubleClickInterval];
|
||||
Duration::from_secs_f64(double_click_interval)
|
||||
}
|
||||
}
|
||||
|
||||
fn os_version(&self) -> Result<SemanticVersion> {
|
||||
unsafe {
|
||||
let process_info = NSProcessInfo::processInfo(nil);
|
||||
|
||||
@@ -12,6 +12,7 @@ use std::{
|
||||
path::PathBuf,
|
||||
rc::{Rc, Weak},
|
||||
sync::Arc,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
pub struct TestPlatform {
|
||||
@@ -274,4 +275,8 @@ impl Platform for TestPlatform {
|
||||
fn delete_credentials(&self, _url: &str) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn double_click_interval(&self) -> std::time::Duration {
|
||||
Duration::from_millis(500)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -477,3 +477,12 @@ impl From<Pixels> for AvailableSpace {
|
||||
AvailableSpace::Definite(pixels)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Size<Pixels>> for Size<AvailableSpace> {
|
||||
fn from(size: Size<Pixels>) -> Self {
|
||||
Size {
|
||||
width: AvailableSpace::Definite(size.width),
|
||||
height: AvailableSpace::Definite(size.height),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,6 +60,16 @@ pub enum DispatchPhase {
|
||||
Capture,
|
||||
}
|
||||
|
||||
impl DispatchPhase {
|
||||
pub fn bubble(self) -> bool {
|
||||
self == DispatchPhase::Bubble
|
||||
}
|
||||
|
||||
pub fn capture(self) -> bool {
|
||||
self == DispatchPhase::Capture
|
||||
}
|
||||
}
|
||||
|
||||
type AnyObserver = Box<dyn FnMut(&mut WindowContext) -> bool + 'static>;
|
||||
type AnyMouseListener = Box<dyn FnMut(&dyn Any, DispatchPhase, &mut WindowContext) + 'static>;
|
||||
type AnyFocusListener = Box<dyn Fn(&FocusEvent, &mut WindowContext) + 'static>;
|
||||
@@ -866,7 +876,7 @@ impl<'a> WindowContext<'a> {
|
||||
/// same layer as the given stacking order.
|
||||
pub fn was_top_layer(&self, point: &Point<Pixels>, level: &StackingOrder) -> bool {
|
||||
for (stack, bounds) in self.window.rendered_frame.depth_map.iter() {
|
||||
if bounds.contains_point(point) {
|
||||
if bounds.contains(point) {
|
||||
return level.starts_with(stack) || stack.starts_with(level);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user