Add back semi-funcitonal pane resizing code
This commit is contained in:
parent
25df11dd26
commit
fd34d1da31
10 changed files with 299 additions and 108 deletions
|
@ -389,9 +389,9 @@ impl EditorElement {
|
||||||
let mut click_count = event.click_count;
|
let mut click_count = event.click_count;
|
||||||
let modifiers = event.modifiers;
|
let modifiers = event.modifiers;
|
||||||
|
|
||||||
if gutter_bounds.contains_point(&event.position) {
|
if gutter_bounds.contains(&event.position) {
|
||||||
click_count = 3; // Simulate triple-click when clicking the gutter to select lines
|
click_count = 3; // Simulate triple-click when clicking the gutter to select lines
|
||||||
} else if !text_bounds.contains_point(&event.position) {
|
} else if !text_bounds.contains(&event.position) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if !cx.was_top_layer(&event.position, stacking_order) {
|
if !cx.was_top_layer(&event.position, stacking_order) {
|
||||||
|
@ -437,7 +437,7 @@ impl EditorElement {
|
||||||
text_bounds: Bounds<Pixels>,
|
text_bounds: Bounds<Pixels>,
|
||||||
cx: &mut ViewContext<Editor>,
|
cx: &mut ViewContext<Editor>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
if !text_bounds.contains_point(&event.position) {
|
if !text_bounds.contains(&event.position) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
let point_for_position = position_map.point_for_position(text_bounds, event.position);
|
let point_for_position = position_map.point_for_position(text_bounds, event.position);
|
||||||
|
@ -467,7 +467,7 @@ impl EditorElement {
|
||||||
|
|
||||||
if !pending_nonempty_selections
|
if !pending_nonempty_selections
|
||||||
&& event.modifiers.command
|
&& event.modifiers.command
|
||||||
&& text_bounds.contains_point(&event.position)
|
&& text_bounds.contains(&event.position)
|
||||||
&& cx.was_top_layer(&event.position, stacking_order)
|
&& cx.was_top_layer(&event.position, stacking_order)
|
||||||
{
|
{
|
||||||
let point = position_map.point_for_position(text_bounds, event.position);
|
let point = position_map.point_for_position(text_bounds, event.position);
|
||||||
|
@ -529,8 +529,8 @@ impl EditorElement {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let text_hovered = text_bounds.contains_point(&event.position);
|
let text_hovered = text_bounds.contains(&event.position);
|
||||||
let gutter_hovered = gutter_bounds.contains_point(&event.position);
|
let gutter_hovered = gutter_bounds.contains(&event.position);
|
||||||
let was_top = cx.was_top_layer(&event.position, stacking_order);
|
let was_top = cx.was_top_layer(&event.position, stacking_order);
|
||||||
|
|
||||||
editor.set_gutter_hovered(gutter_hovered, cx);
|
editor.set_gutter_hovered(gutter_hovered, cx);
|
||||||
|
@ -894,7 +894,7 @@ impl EditorElement {
|
||||||
bounds: text_bounds,
|
bounds: text_bounds,
|
||||||
}),
|
}),
|
||||||
|cx| {
|
|cx| {
|
||||||
if text_bounds.contains_point(&cx.mouse_position()) {
|
if text_bounds.contains(&cx.mouse_position()) {
|
||||||
if self
|
if self
|
||||||
.editor
|
.editor
|
||||||
.read(cx)
|
.read(cx)
|
||||||
|
@ -960,7 +960,7 @@ impl EditorElement {
|
||||||
|fold_element_state, cx| {
|
|fold_element_state, cx| {
|
||||||
if fold_element_state.is_active() {
|
if fold_element_state.is_active() {
|
||||||
gpui::blue()
|
gpui::blue()
|
||||||
} else if fold_bounds.contains_point(&cx.mouse_position()) {
|
} else if fold_bounds.contains(&cx.mouse_position()) {
|
||||||
gpui::black()
|
gpui::black()
|
||||||
} else {
|
} else {
|
||||||
gpui::red()
|
gpui::red()
|
||||||
|
|
|
@ -761,7 +761,7 @@ pub struct InteractiveBounds {
|
||||||
|
|
||||||
impl InteractiveBounds {
|
impl InteractiveBounds {
|
||||||
pub fn visibly_contains(&self, point: &Point<Pixels>, cx: &WindowContext) -> bool {
|
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));
|
.and_then(|group_hover| GroupBounds::get(&group_hover.group, cx));
|
||||||
|
|
||||||
if let Some(group_bounds) = hover_group_bounds {
|
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| {
|
cx.on_mouse_event(move |event: &MouseMoveEvent, phase, cx| {
|
||||||
if phase == DispatchPhase::Capture {
|
if phase == DispatchPhase::Capture {
|
||||||
if group_bounds.contains_point(&event.position) != hovered {
|
if group_bounds.contains(&event.position) != hovered {
|
||||||
cx.notify();
|
cx.notify();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -875,10 +875,10 @@ impl Interactivity {
|
||||||
|| cx.active_drag.is_some() && !self.drag_over_styles.is_empty()
|
|| cx.active_drag.is_some() && !self.drag_over_styles.is_empty()
|
||||||
{
|
{
|
||||||
let bounds = bounds.intersect(&cx.content_mask().bounds);
|
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| {
|
cx.on_mouse_event(move |event: &MouseMoveEvent, phase, cx| {
|
||||||
if phase == DispatchPhase::Capture {
|
if phase == DispatchPhase::Capture {
|
||||||
if bounds.contains_point(&event.position) != hovered {
|
if bounds.contains(&event.position) != hovered {
|
||||||
cx.notify();
|
cx.notify();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1067,8 +1067,8 @@ impl Interactivity {
|
||||||
let interactive_bounds = interactive_bounds.clone();
|
let interactive_bounds = interactive_bounds.clone();
|
||||||
cx.on_mouse_event(move |down: &MouseDownEvent, phase, cx| {
|
cx.on_mouse_event(move |down: &MouseDownEvent, phase, cx| {
|
||||||
if phase == DispatchPhase::Bubble {
|
if phase == DispatchPhase::Bubble {
|
||||||
let group = active_group_bounds
|
let group =
|
||||||
.map_or(false, |bounds| bounds.contains_point(&down.position));
|
active_group_bounds.map_or(false, |bounds| bounds.contains(&down.position));
|
||||||
let element = interactive_bounds.visibly_contains(&down.position, cx);
|
let element = interactive_bounds.visibly_contains(&down.position, cx);
|
||||||
if group || element {
|
if group || element {
|
||||||
*active_state.borrow_mut() = ElementClickedState { group, element };
|
*active_state.borrow_mut() = ElementClickedState { group, element };
|
||||||
|
@ -1182,7 +1182,7 @@ impl Interactivity {
|
||||||
let mouse_position = cx.mouse_position();
|
let mouse_position = cx.mouse_position();
|
||||||
if let Some(group_hover) = self.group_hover_style.as_ref() {
|
if let Some(group_hover) = self.group_hover_style.as_ref() {
|
||||||
if let Some(group_bounds) = GroupBounds::get(&group_hover.group, cx) {
|
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())
|
&& cx.was_top_layer(&mouse_position, cx.stacking_order())
|
||||||
{
|
{
|
||||||
style.refine(&group_hover.style);
|
style.refine(&group_hover.style);
|
||||||
|
@ -1192,7 +1192,7 @@ impl Interactivity {
|
||||||
if self.hover_style.is_some() {
|
if self.hover_style.is_some() {
|
||||||
if bounds
|
if bounds
|
||||||
.intersect(&cx.content_mask().bounds)
|
.intersect(&cx.content_mask().bounds)
|
||||||
.contains_point(&mouse_position)
|
.contains(&mouse_position)
|
||||||
&& cx.was_top_layer(&mouse_position, cx.stacking_order())
|
&& cx.was_top_layer(&mouse_position, cx.stacking_order())
|
||||||
{
|
{
|
||||||
style.refine(&self.hover_style);
|
style.refine(&self.hover_style);
|
||||||
|
@ -1203,7 +1203,7 @@ impl Interactivity {
|
||||||
for (state_type, group_drag_style) in &self.group_drag_over_styles {
|
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 let Some(group_bounds) = GroupBounds::get(&group_drag_style.group, cx) {
|
||||||
if *state_type == drag.view.entity_type()
|
if *state_type == drag.view.entity_type()
|
||||||
&& group_bounds.contains_point(&mouse_position)
|
&& group_bounds.contains(&mouse_position)
|
||||||
{
|
{
|
||||||
style.refine(&group_drag_style.style);
|
style.refine(&group_drag_style.style);
|
||||||
}
|
}
|
||||||
|
@ -1214,7 +1214,7 @@ impl Interactivity {
|
||||||
if *state_type == drag.view.entity_type()
|
if *state_type == drag.view.entity_type()
|
||||||
&& bounds
|
&& bounds
|
||||||
.intersect(&cx.content_mask().bounds)
|
.intersect(&cx.content_mask().bounds)
|
||||||
.contains_point(&mouse_position)
|
.contains(&mouse_position)
|
||||||
{
|
{
|
||||||
style.refine(drag_over_style);
|
style.refine(drag_over_style);
|
||||||
}
|
}
|
||||||
|
|
|
@ -253,7 +253,7 @@ impl TextState {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn index_for_position(&self, bounds: Bounds<Pixels>, position: Point<Pixels>) -> Option<usize> {
|
fn index_for_position(&self, bounds: Bounds<Pixels>, position: Point<Pixels>) -> Option<usize> {
|
||||||
if !bounds.contains_point(&position) {
|
if !bounds.contains(&position) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,14 @@ impl Axis {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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::StaticColumnCount for Axis {}
|
||||||
impl sqlez::bindable::Bind for Axis {
|
impl sqlez::bindable::Bind for Axis {
|
||||||
fn bind(
|
fn bind(
|
||||||
|
@ -142,8 +150,19 @@ impl<T: Clone + Debug + Default> Point<T> {
|
||||||
y: f(self.y.clone()),
|
y: f(self.y.clone()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn apply_along(&self, axis: Axis, f: impl FnOnce(T) -> T) -> 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 {
|
match axis {
|
||||||
Axis::Horizontal => Point {
|
Axis::Horizontal => Point {
|
||||||
x: f(self.x.clone()),
|
x: f(self.x.clone()),
|
||||||
|
@ -434,11 +453,13 @@ impl Size<Pixels> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Size<T>
|
impl<T> Along for Size<T>
|
||||||
where
|
where
|
||||||
T: Clone + Default + Debug,
|
T: Clone + Default + Debug,
|
||||||
{
|
{
|
||||||
pub fn along(&self, axis: Axis) -> T {
|
type Unit = T;
|
||||||
|
|
||||||
|
fn along(&self, axis: Axis) -> T {
|
||||||
match axis {
|
match axis {
|
||||||
Axis::Horizontal => self.width.clone(),
|
Axis::Horizontal => self.width.clone(),
|
||||||
Axis::Vertical => self.height.clone(),
|
Axis::Vertical => self.height.clone(),
|
||||||
|
@ -446,7 +467,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the value of this size along the given axis.
|
/// Returns the value of this size along the given axis.
|
||||||
pub fn apply_along(&self, axis: Axis, f: impl FnOnce(T) -> T) -> Self {
|
fn apply_along(&self, axis: Axis, f: impl FnOnce(T) -> T) -> Self {
|
||||||
match axis {
|
match axis {
|
||||||
Axis::Horizontal => Size {
|
Axis::Horizontal => Size {
|
||||||
width: f(self.width.clone()),
|
width: f(self.width.clone()),
|
||||||
|
@ -1079,7 +1100,7 @@ where
|
||||||
/// assert!(bounds.contains_point(&inside_point));
|
/// assert!(bounds.contains_point(&inside_point));
|
||||||
/// assert!(!bounds.contains_point(&outside_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
|
||||||
&& point.x <= self.origin.x.clone() + self.size.width.clone()
|
&& point.x <= self.origin.x.clone() + self.size.width.clone()
|
||||||
&& point.y >= self.origin.y
|
&& point.y >= self.origin.y
|
||||||
|
|
|
@ -131,6 +131,12 @@ pub struct MouseMoveEvent {
|
||||||
pub modifiers: Modifiers,
|
pub modifiers: Modifiers,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl MouseMoveEvent {
|
||||||
|
pub fn dragging(&self) -> bool {
|
||||||
|
self.pressed_button == Some(MouseButton::Left)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct ScrollWheelEvent {
|
pub struct ScrollWheelEvent {
|
||||||
pub position: Point<Pixels>,
|
pub position: Point<Pixels>,
|
||||||
|
|
|
@ -60,6 +60,16 @@ pub enum DispatchPhase {
|
||||||
Capture,
|
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 AnyObserver = Box<dyn FnMut(&mut WindowContext) -> bool + 'static>;
|
||||||
type AnyMouseListener = Box<dyn FnMut(&dyn Any, DispatchPhase, &mut WindowContext) + 'static>;
|
type AnyMouseListener = Box<dyn FnMut(&dyn Any, DispatchPhase, &mut WindowContext) + 'static>;
|
||||||
type AnyFocusListener = Box<dyn Fn(&FocusEvent, &mut WindowContext) + 'static>;
|
type AnyFocusListener = Box<dyn Fn(&FocusEvent, &mut WindowContext) + 'static>;
|
||||||
|
@ -859,7 +869,7 @@ impl<'a> WindowContext<'a> {
|
||||||
/// same layer as the given stacking order.
|
/// same layer as the given stacking order.
|
||||||
pub fn was_top_layer(&self, point: &Point<Pixels>, level: &StackingOrder) -> bool {
|
pub fn was_top_layer(&self, point: &Point<Pixels>, level: &StackingOrder) -> bool {
|
||||||
for (stack, bounds) in self.window.rendered_frame.depth_map.iter() {
|
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);
|
return level.starts_with(stack) || stack.starts_with(level);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -137,7 +137,7 @@ impl<M: ManagedView> Element for RightClickMenu<M> {
|
||||||
cx.on_mouse_event(move |event: &MouseDownEvent, phase, cx| {
|
cx.on_mouse_event(move |event: &MouseDownEvent, phase, cx| {
|
||||||
if phase == DispatchPhase::Bubble
|
if phase == DispatchPhase::Bubble
|
||||||
&& event.button == MouseButton::Right
|
&& event.button == MouseButton::Right
|
||||||
&& bounds.contains_point(&event.position)
|
&& bounds.contains(&event.position)
|
||||||
{
|
{
|
||||||
cx.stop_propagation();
|
cx.stop_propagation();
|
||||||
cx.prevent_default();
|
cx.prevent_default();
|
||||||
|
|
|
@ -1040,10 +1040,11 @@ impl Pane {
|
||||||
{
|
{
|
||||||
pane.remove_item(item_ix, false, cx);
|
pane.remove_item(item_ix, false, cx);
|
||||||
}
|
}
|
||||||
})?;
|
})
|
||||||
|
.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
pane.update(&mut cx, |_, cx| cx.notify())?;
|
pane.update(&mut cx, |_, cx| cx.notify()).ok();
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ use serde::Deserialize;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use ui::{prelude::*, Button};
|
use ui::{prelude::*, Button};
|
||||||
|
|
||||||
const HANDLE_HITBOX_SIZE: f32 = 4.0;
|
const HANDLE_HITBOX_SIZE: f32 = 10.0; //todo!(change this back to 4)
|
||||||
const HORIZONTAL_MIN_SIZE: f32 = 80.;
|
const HORIZONTAL_MIN_SIZE: f32 = 80.;
|
||||||
const VERTICAL_MIN_SIZE: f32 = 100.;
|
const VERTICAL_MIN_SIZE: f32 = 100.;
|
||||||
|
|
||||||
|
@ -576,7 +576,7 @@ impl PaneAxis {
|
||||||
|
|
||||||
for (idx, member) in self.members.iter().enumerate() {
|
for (idx, member) in self.members.iter().enumerate() {
|
||||||
if let Some(coordinates) = bounding_boxes[idx] {
|
if let Some(coordinates) = bounding_boxes[idx] {
|
||||||
if coordinates.contains_point(&coordinate) {
|
if coordinates.contains(&coordinate) {
|
||||||
return match member {
|
return match member {
|
||||||
Member::Pane(found) => Some(found),
|
Member::Pane(found) => Some(found),
|
||||||
Member::Axis(axis) => axis.pane_at_pixel_position(coordinate),
|
Member::Axis(axis) => axis.pane_at_pixel_position(coordinate),
|
||||||
|
@ -598,14 +598,24 @@ impl PaneAxis {
|
||||||
cx: &mut ViewContext<Workspace>,
|
cx: &mut ViewContext<Workspace>,
|
||||||
) -> gpui::AnyElement {
|
) -> gpui::AnyElement {
|
||||||
debug_assert!(self.members.len() == self.flexes.lock().len());
|
debug_assert!(self.members.len() == self.flexes.lock().len());
|
||||||
|
let mut active_pane_ix = None;
|
||||||
|
|
||||||
pane_axis(self.axis, basis, self.flexes.clone())
|
pane_axis(
|
||||||
|
self.axis,
|
||||||
|
basis,
|
||||||
|
self.flexes.clone(),
|
||||||
|
self.bounding_boxes.clone(),
|
||||||
|
)
|
||||||
.children(self.members.iter().enumerate().map(|(ix, member)| {
|
.children(self.members.iter().enumerate().map(|(ix, member)| {
|
||||||
|
if member.contains(active_pane) {
|
||||||
|
active_pane_ix = Some(ix);
|
||||||
|
}
|
||||||
|
|
||||||
match member {
|
match member {
|
||||||
Member::Axis(axis) => axis
|
Member::Axis(axis) => axis
|
||||||
.render(
|
.render(
|
||||||
project,
|
project,
|
||||||
basis,
|
(basis + ix) * 10,
|
||||||
follower_states,
|
follower_states,
|
||||||
active_pane,
|
active_pane,
|
||||||
zoomed,
|
zoomed,
|
||||||
|
@ -613,58 +623,16 @@ impl PaneAxis {
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
.into_any_element(),
|
.into_any_element(),
|
||||||
Member::Pane(pane) => pane.clone().into_any_element(),
|
Member::Pane(pane) => div()
|
||||||
|
.size_full()
|
||||||
|
.border()
|
||||||
|
.border_color(gpui::green())
|
||||||
|
.child(pane.clone())
|
||||||
|
.into_any_element(),
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
.with_active_pane(active_pane_ix)
|
||||||
.into_any_element()
|
.into_any_element()
|
||||||
|
|
||||||
// let mut pane_axis = PaneAxisElement::new(
|
|
||||||
// self.axis,
|
|
||||||
// basis,
|
|
||||||
// self.flexes.clone(),
|
|
||||||
// self.bounding_boxes.clone(),
|
|
||||||
// );
|
|
||||||
// let mut active_pane_ix = None;
|
|
||||||
|
|
||||||
// let mut members = self.members.iter().enumerate().peekable();
|
|
||||||
// while let Some((ix, member)) = members.next() {
|
|
||||||
// let last = members.peek().is_none();
|
|
||||||
|
|
||||||
// if member.contains(active_pane) {
|
|
||||||
// active_pane_ix = Some(ix);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// let mut member = member.render(
|
|
||||||
// project,
|
|
||||||
// (basis + ix) * 10,
|
|
||||||
// theme,
|
|
||||||
// follower_states,
|
|
||||||
// active_call,
|
|
||||||
// active_pane,
|
|
||||||
// zoomed,
|
|
||||||
// app_state,
|
|
||||||
// cx,
|
|
||||||
// );
|
|
||||||
|
|
||||||
// if !last {
|
|
||||||
// let mut border = theme.workspace.pane_divider;
|
|
||||||
// border.left = false;
|
|
||||||
// border.right = false;
|
|
||||||
// border.top = false;
|
|
||||||
// border.bottom = false;
|
|
||||||
|
|
||||||
// match self.axis {
|
|
||||||
// Axis::Vertical => border.bottom = true,
|
|
||||||
// Axis::Horizontal => border.right = true,
|
|
||||||
// }
|
|
||||||
|
|
||||||
// member = member.contained().with_border(border).into_any();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// pane_axis = pane_axis.with_child(member.into_any());
|
|
||||||
// }
|
|
||||||
// pane_axis.set_active_pane(active_pane_ix);
|
|
||||||
// pane_axis.into_any()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -727,18 +695,31 @@ impl SplitDirection {
|
||||||
}
|
}
|
||||||
|
|
||||||
mod element {
|
mod element {
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use gpui::{relative, AnyElement, Axis, Element, IntoElement, ParentElement, Style};
|
use std::{iter, sync::Arc};
|
||||||
|
|
||||||
|
use gpui::{
|
||||||
|
px, relative, Along, AnyElement, Axis, Bounds, CursorStyle, Element, IntoElement,
|
||||||
|
MouseMoveEvent, ParentElement, Pixels, Style, WindowContext,
|
||||||
|
};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
|
||||||
pub fn pane_axis(axis: Axis, basis: usize, flexes: Arc<Mutex<Vec<f32>>>) -> PaneAxisElement {
|
use super::{HANDLE_HITBOX_SIZE, HORIZONTAL_MIN_SIZE, VERTICAL_MIN_SIZE};
|
||||||
|
|
||||||
|
pub fn pane_axis(
|
||||||
|
axis: Axis,
|
||||||
|
basis: usize,
|
||||||
|
flexes: Arc<Mutex<Vec<f32>>>,
|
||||||
|
bounding_boxes: Arc<Mutex<Vec<Option<Bounds<Pixels>>>>>,
|
||||||
|
) -> PaneAxisElement {
|
||||||
PaneAxisElement {
|
PaneAxisElement {
|
||||||
axis,
|
axis,
|
||||||
basis,
|
basis,
|
||||||
flexes,
|
flexes,
|
||||||
|
bounding_boxes,
|
||||||
children: SmallVec::new(),
|
children: SmallVec::new(),
|
||||||
|
active_pane_ix: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -746,7 +727,145 @@ mod element {
|
||||||
axis: Axis,
|
axis: Axis,
|
||||||
basis: usize,
|
basis: usize,
|
||||||
flexes: Arc<Mutex<Vec<f32>>>,
|
flexes: Arc<Mutex<Vec<f32>>>,
|
||||||
|
bounding_boxes: Arc<Mutex<Vec<Option<Bounds<Pixels>>>>>,
|
||||||
children: SmallVec<[AnyElement; 2]>,
|
children: SmallVec<[AnyElement; 2]>,
|
||||||
|
active_pane_ix: Option<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PaneAxisElement {
|
||||||
|
pub fn with_active_pane(mut self, active_pane_ix: Option<usize>) -> Self {
|
||||||
|
self.active_pane_ix = active_pane_ix;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compute_resize(
|
||||||
|
flexes: &Arc<Mutex<Vec<f32>>>,
|
||||||
|
e: &MouseMoveEvent,
|
||||||
|
ix: usize,
|
||||||
|
axis: Axis,
|
||||||
|
axis_bounds: Bounds<Pixels>,
|
||||||
|
cx: &mut WindowContext,
|
||||||
|
) {
|
||||||
|
let min_size = match axis {
|
||||||
|
Axis::Horizontal => px(HORIZONTAL_MIN_SIZE),
|
||||||
|
Axis::Vertical => px(VERTICAL_MIN_SIZE),
|
||||||
|
};
|
||||||
|
let mut flexes = flexes.lock();
|
||||||
|
debug_assert!(flex_values_in_bounds(flexes.as_slice()));
|
||||||
|
|
||||||
|
let size = move |ix, flexes: &[f32]| {
|
||||||
|
axis_bounds.size.along(axis) * (flexes[ix] / flexes.len() as f32)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Don't allow resizing to less than the minimum size, if elements are already too small
|
||||||
|
if min_size - px(1.) > size(ix, flexes.as_slice()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut proposed_current_pixel_change =
|
||||||
|
(e.position - axis_bounds.origin).along(axis) - size(ix, flexes.as_slice());
|
||||||
|
|
||||||
|
let flex_changes = |pixel_dx, target_ix, next: isize, flexes: &[f32]| {
|
||||||
|
let flex_change = pixel_dx / axis_bounds.size.along(axis);
|
||||||
|
let current_target_flex = flexes[target_ix] + flex_change;
|
||||||
|
let next_target_flex = flexes[(target_ix as isize + next) as usize] - flex_change;
|
||||||
|
(current_target_flex, next_target_flex)
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut successors = iter::from_fn({
|
||||||
|
let forward = proposed_current_pixel_change > px(0.);
|
||||||
|
let mut ix_offset = 0;
|
||||||
|
let len = flexes.len();
|
||||||
|
move || {
|
||||||
|
let result = if forward {
|
||||||
|
(ix + 1 + ix_offset < len).then(|| ix + ix_offset)
|
||||||
|
} else {
|
||||||
|
(ix as isize - ix_offset as isize >= 0).then(|| ix - ix_offset)
|
||||||
|
};
|
||||||
|
|
||||||
|
ix_offset += 1;
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
while dbg!(proposed_current_pixel_change).abs() > px(0.) {
|
||||||
|
let Some(current_ix) = successors.next() else {
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
|
||||||
|
dbg!(current_ix);
|
||||||
|
|
||||||
|
let next_target_size = Pixels::max(
|
||||||
|
size(current_ix + 1, flexes.as_slice()) - proposed_current_pixel_change,
|
||||||
|
min_size,
|
||||||
|
);
|
||||||
|
|
||||||
|
let current_target_size = Pixels::max(
|
||||||
|
size(current_ix, flexes.as_slice()) + size(current_ix + 1, flexes.as_slice())
|
||||||
|
- next_target_size,
|
||||||
|
min_size,
|
||||||
|
);
|
||||||
|
|
||||||
|
let current_pixel_change =
|
||||||
|
current_target_size - size(current_ix, flexes.as_slice());
|
||||||
|
|
||||||
|
let (current_target_flex, next_target_flex) =
|
||||||
|
flex_changes(current_pixel_change, current_ix, 1, flexes.as_slice());
|
||||||
|
|
||||||
|
flexes[current_ix] = current_target_flex;
|
||||||
|
flexes[current_ix + 1] = next_target_flex;
|
||||||
|
|
||||||
|
proposed_current_pixel_change -= current_pixel_change;
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo!(reserialize workspace)
|
||||||
|
// workspace.schedule_serialize(cx);
|
||||||
|
cx.notify();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_handle(
|
||||||
|
flexes: Arc<Mutex<Vec<f32>>>,
|
||||||
|
axis: Axis,
|
||||||
|
ix: usize,
|
||||||
|
pane_bounds: Bounds<Pixels>,
|
||||||
|
axis_bounds: Bounds<Pixels>,
|
||||||
|
cx: &mut WindowContext,
|
||||||
|
) {
|
||||||
|
let handle_bounds = Bounds {
|
||||||
|
origin: pane_bounds.origin.apply_along(axis, |o| {
|
||||||
|
o + pane_bounds.size.along(axis) - Pixels(HANDLE_HITBOX_SIZE / 2.)
|
||||||
|
}),
|
||||||
|
size: pane_bounds
|
||||||
|
.size
|
||||||
|
.apply_along(axis, |_| Pixels(HANDLE_HITBOX_SIZE)),
|
||||||
|
};
|
||||||
|
|
||||||
|
cx.with_z_index(3, |cx| {
|
||||||
|
if handle_bounds.contains(&cx.mouse_position()) {
|
||||||
|
cx.set_cursor_style(match axis {
|
||||||
|
Axis::Vertical => CursorStyle::ResizeUpDown,
|
||||||
|
Axis::Horizontal => CursorStyle::ResizeLeftRight,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
cx.add_opaque_layer(handle_bounds);
|
||||||
|
|
||||||
|
cx.paint_quad(
|
||||||
|
handle_bounds,
|
||||||
|
Default::default(),
|
||||||
|
gpui::red(),
|
||||||
|
Default::default(),
|
||||||
|
gpui::red(),
|
||||||
|
);
|
||||||
|
|
||||||
|
cx.on_mouse_event(move |e: &MouseMoveEvent, phase, cx| {
|
||||||
|
if phase.bubble() && e.dragging() && handle_bounds.contains(&e.position) {
|
||||||
|
Self::compute_resize(&flexes, e, ix, axis, axis_bounds, cx)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntoElement for PaneAxisElement {
|
impl IntoElement for PaneAxisElement {
|
||||||
|
@ -784,16 +903,47 @@ mod element {
|
||||||
cx: &mut ui::prelude::WindowContext,
|
cx: &mut ui::prelude::WindowContext,
|
||||||
) {
|
) {
|
||||||
let flexes = self.flexes.lock().clone();
|
let flexes = self.flexes.lock().clone();
|
||||||
debug_assert!(flexes.len() == self.children.len());
|
|
||||||
|
|
||||||
let origin = bounds.origin;
|
|
||||||
let size = bounds.size;
|
|
||||||
let len = self.children.len();
|
let len = self.children.len();
|
||||||
let child_size = size.apply_along(self.axis, |val| val / len as f32);
|
debug_assert!(flexes.len() == len);
|
||||||
|
debug_assert!(flex_values_in_bounds(flexes.as_slice()));
|
||||||
|
|
||||||
|
let mut origin = bounds.origin;
|
||||||
|
let space_per_flex = bounds.size.along(self.axis) / len as f32;
|
||||||
|
|
||||||
|
let mut bounding_boxes = self.bounding_boxes.lock();
|
||||||
|
bounding_boxes.clear();
|
||||||
|
|
||||||
for (ix, child) in self.children.into_iter().enumerate() {
|
for (ix, child) in self.children.into_iter().enumerate() {
|
||||||
let origin =
|
//todo!(active_pane_magnification)
|
||||||
origin.apply_along(self.axis, |val| val + child_size.along(self.axis) * ix);
|
// If usign active pane magnification, need to switch to using
|
||||||
|
// 1 for all non-active panes, and then the magnification for the
|
||||||
|
// active pane.
|
||||||
|
let child_size = bounds
|
||||||
|
.size
|
||||||
|
.apply_along(self.axis, |_| space_per_flex * flexes[ix]);
|
||||||
|
|
||||||
|
let child_bounds = Bounds {
|
||||||
|
origin,
|
||||||
|
size: child_size,
|
||||||
|
};
|
||||||
|
bounding_boxes.push(Some(child_bounds));
|
||||||
|
cx.with_z_index(0, |cx| {
|
||||||
child.draw(origin, child_size.into(), cx);
|
child.draw(origin, child_size.into(), cx);
|
||||||
|
});
|
||||||
|
cx.with_z_index(1, |cx| {
|
||||||
|
if ix < len - 1 {
|
||||||
|
Self::push_handle(
|
||||||
|
self.flexes.clone(),
|
||||||
|
self.axis,
|
||||||
|
ix,
|
||||||
|
child_bounds,
|
||||||
|
bounds,
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
origin = origin.apply_along(self.axis, |val| val + child_size.along(self.axis));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -804,6 +954,9 @@ mod element {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn flex_values_in_bounds(flexes: &[f32]) -> bool {
|
||||||
|
(flexes.iter().copied().sum::<f32>() - flexes.len() as f32).abs() < 0.001
|
||||||
|
}
|
||||||
// // use std::{cell::RefCell, iter::from_fn, ops::Range, rc::Rc};
|
// // use std::{cell::RefCell, iter::from_fn, ops::Range, rc::Rc};
|
||||||
|
|
||||||
// // use gpui::{
|
// // use gpui::{
|
||||||
|
|
|
@ -2015,7 +2015,7 @@ impl Workspace {
|
||||||
};
|
};
|
||||||
let cursor = self.active_pane.read(cx).pixel_position_of_cursor(cx);
|
let cursor = self.active_pane.read(cx).pixel_position_of_cursor(cx);
|
||||||
let center = match cursor {
|
let center = match cursor {
|
||||||
Some(cursor) if bounding_box.contains_point(&cursor) => cursor,
|
Some(cursor) if bounding_box.contains(&cursor) => cursor,
|
||||||
_ => bounding_box.center(),
|
_ => bounding_box.center(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue