1use crate::{AppState, FollowerState, Pane, Workspace};
2use anyhow::{anyhow, bail, Result};
3use collections::HashMap;
4use db2::sqlez::{
5 bindable::{Bind, Column, StaticColumnCount},
6 statement::Statement,
7};
8use gpui::{
9 point, size, AnyWeakView, Bounds, Div, IntoElement, Model, Pixels, Point, View, ViewContext,
10};
11use parking_lot::Mutex;
12use project2::Project;
13use serde::Deserialize;
14use std::sync::Arc;
15use ui::prelude::*;
16
17const HANDLE_HITBOX_SIZE: f32 = 4.0;
18const HORIZONTAL_MIN_SIZE: f32 = 80.;
19const VERTICAL_MIN_SIZE: f32 = 100.;
20
21#[derive(Copy, Clone, PartialEq, Eq, Debug)]
22pub enum Axis {
23 Vertical,
24 Horizontal,
25}
26
27impl StaticColumnCount for Axis {}
28impl Bind for Axis {
29 fn bind(&self, statement: &Statement, start_index: i32) -> anyhow::Result<i32> {
30 match self {
31 Axis::Horizontal => "Horizontal",
32 Axis::Vertical => "Vertical",
33 }
34 .bind(statement, start_index)
35 }
36}
37
38impl Column for Axis {
39 fn column(statement: &mut Statement, start_index: i32) -> anyhow::Result<(Self, i32)> {
40 String::column(statement, start_index).and_then(|(axis_text, next_index)| {
41 Ok((
42 match axis_text.as_str() {
43 "Horizontal" => Axis::Horizontal,
44 "Vertical" => Axis::Vertical,
45 _ => bail!("Stored serialized item kind is incorrect"),
46 },
47 next_index,
48 ))
49 })
50 }
51}
52
53#[derive(Clone, PartialEq)]
54pub struct PaneGroup {
55 pub(crate) root: Member,
56}
57
58impl PaneGroup {
59 pub(crate) fn with_root(root: Member) -> Self {
60 Self { root }
61 }
62
63 pub fn new(pane: View<Pane>) -> Self {
64 Self {
65 root: Member::Pane(pane),
66 }
67 }
68
69 pub fn split(
70 &mut self,
71 old_pane: &View<Pane>,
72 new_pane: &View<Pane>,
73 direction: SplitDirection,
74 ) -> Result<()> {
75 match &mut self.root {
76 Member::Pane(pane) => {
77 if pane == old_pane {
78 self.root = Member::new_axis(old_pane.clone(), new_pane.clone(), direction);
79 Ok(())
80 } else {
81 Err(anyhow!("Pane not found"))
82 }
83 }
84 Member::Axis(axis) => axis.split(old_pane, new_pane, direction),
85 }
86 }
87
88 pub fn bounding_box_for_pane(&self, pane: &View<Pane>) -> Option<Bounds<Pixels>> {
89 match &self.root {
90 Member::Pane(_) => None,
91 Member::Axis(axis) => axis.bounding_box_for_pane(pane),
92 }
93 }
94
95 pub fn pane_at_pixel_position(&self, coordinate: Point<Pixels>) -> Option<&View<Pane>> {
96 match &self.root {
97 Member::Pane(pane) => Some(pane),
98 Member::Axis(axis) => axis.pane_at_pixel_position(coordinate),
99 }
100 }
101
102 /// Returns:
103 /// - Ok(true) if it found and removed a pane
104 /// - Ok(false) if it found but did not remove the pane
105 /// - Err(_) if it did not find the pane
106 pub fn remove(&mut self, pane: &View<Pane>) -> Result<bool> {
107 match &mut self.root {
108 Member::Pane(_) => Ok(false),
109 Member::Axis(axis) => {
110 if let Some(last_pane) = axis.remove(pane)? {
111 self.root = last_pane;
112 }
113 Ok(true)
114 }
115 }
116 }
117
118 pub fn swap(&mut self, from: &View<Pane>, to: &View<Pane>) {
119 match &mut self.root {
120 Member::Pane(_) => {}
121 Member::Axis(axis) => axis.swap(from, to),
122 };
123 }
124
125 pub(crate) fn render(
126 &self,
127 project: &Model<Project>,
128 follower_states: &HashMap<View<Pane>, FollowerState>,
129 active_pane: &View<Pane>,
130 zoomed: Option<&AnyWeakView>,
131 app_state: &Arc<AppState>,
132 cx: &mut ViewContext<Workspace>,
133 ) -> impl IntoElement {
134 self.root.render(
135 project,
136 0,
137 follower_states,
138 active_pane,
139 zoomed,
140 app_state,
141 cx,
142 )
143 }
144
145 pub(crate) fn panes(&self) -> Vec<&View<Pane>> {
146 let mut panes = Vec::new();
147 self.root.collect_panes(&mut panes);
148 panes
149 }
150
151 pub(crate) fn first_pane(&self) -> View<Pane> {
152 self.root.first_pane()
153 }
154}
155
156#[derive(Clone, PartialEq)]
157pub(crate) enum Member {
158 Axis(PaneAxis),
159 Pane(View<Pane>),
160}
161
162impl Member {
163 fn new_axis(old_pane: View<Pane>, new_pane: View<Pane>, direction: SplitDirection) -> Self {
164 use Axis::*;
165 use SplitDirection::*;
166
167 let axis = match direction {
168 Up | Down => Vertical,
169 Left | Right => Horizontal,
170 };
171
172 let members = match direction {
173 Up | Left => vec![Member::Pane(new_pane), Member::Pane(old_pane)],
174 Down | Right => vec![Member::Pane(old_pane), Member::Pane(new_pane)],
175 };
176
177 Member::Axis(PaneAxis::new(axis, members))
178 }
179
180 fn contains(&self, needle: &View<Pane>) -> bool {
181 match self {
182 Member::Axis(axis) => axis.members.iter().any(|member| member.contains(needle)),
183 Member::Pane(pane) => pane == needle,
184 }
185 }
186
187 fn first_pane(&self) -> View<Pane> {
188 match self {
189 Member::Axis(axis) => axis.members[0].first_pane(),
190 Member::Pane(pane) => pane.clone(),
191 }
192 }
193
194 pub fn render(
195 &self,
196 project: &Model<Project>,
197 basis: usize,
198 follower_states: &HashMap<View<Pane>, FollowerState>,
199 active_pane: &View<Pane>,
200 zoomed: Option<&AnyWeakView>,
201 app_state: &Arc<AppState>,
202 cx: &mut ViewContext<Workspace>,
203 ) -> impl IntoElement {
204 match self {
205 Member::Pane(pane) => {
206 // todo!()
207 // let pane_element = if Some(pane.into()) == zoomed {
208 // None
209 // } else {
210 // Some(pane)
211 // };
212
213 div().size_full().child(pane.clone()).into_any()
214
215 // Stack::new()
216 // .with_child(pane_element.contained().with_border(leader_border))
217 // .with_children(leader_status_box)
218 // .into_any()
219
220 // let el = div()
221 // .flex()
222 // .flex_1()
223 // .gap_px()
224 // .w_full()
225 // .h_full()
226 // .bg(cx.theme().colors().editor)
227 // .children();
228 }
229 Member::Axis(axis) => axis
230 .render(
231 project,
232 basis + 1,
233 follower_states,
234 active_pane,
235 zoomed,
236 app_state,
237 cx,
238 )
239 .into_any(),
240 }
241
242 // enum FollowIntoExternalProject {}
243
244 // match self {
245 // Member::Pane(pane) => {
246 // let pane_element = if Some(&**pane) == zoomed {
247 // Empty::new().into_any()
248 // } else {
249 // ChildView::new(pane, cx).into_any()
250 // };
251
252 // let leader = follower_states.get(pane).and_then(|state| {
253 // let room = active_call?.read(cx).room()?.read(cx);
254 // room.remote_participant_for_peer_id(state.leader_id)
255 // });
256
257 // let mut leader_border = Border::default();
258 // let mut leader_status_box = None;
259 // if let Some(leader) = &leader {
260 // let leader_color = theme
261 // .editor
262 // .selection_style_for_room_participant(leader.participant_index.0)
263 // .cursor;
264 // leader_border = Border::all(theme.workspace.leader_border_width, leader_color);
265 // leader_border
266 // .color
267 // .fade_out(1. - theme.workspace.leader_border_opacity);
268 // leader_border.overlay = true;
269
270 // leader_status_box = match leader.location {
271 // ParticipantLocation::SharedProject {
272 // project_id: leader_project_id,
273 // } => {
274 // if Some(leader_project_id) == project.read(cx).remote_id() {
275 // None
276 // } else {
277 // let leader_user = leader.user.clone();
278 // let leader_user_id = leader.user.id;
279 // Some(
280 // MouseEventHandler::new::<FollowIntoExternalProject, _>(
281 // pane.id(),
282 // cx,
283 // |_, _| {
284 // Label::new(
285 // format!(
286 // "Follow {} to their active project",
287 // leader_user.github_login,
288 // ),
289 // theme
290 // .workspace
291 // .external_location_message
292 // .text
293 // .clone(),
294 // )
295 // .contained()
296 // .with_style(
297 // theme.workspace.external_location_message.container,
298 // )
299 // },
300 // )
301 // .with_cursor_style(CursorStyle::PointingHand)
302 // .on_click(MouseButton::Left, move |_, this, cx| {
303 // crate::join_remote_project(
304 // leader_project_id,
305 // leader_user_id,
306 // this.app_state().clone(),
307 // cx,
308 // )
309 // .detach_and_log_err(cx);
310 // })
311 // .aligned()
312 // .bottom()
313 // .right()
314 // .into_any(),
315 // )
316 // }
317 // }
318 // ParticipantLocation::UnsharedProject => Some(
319 // Label::new(
320 // format!(
321 // "{} is viewing an unshared Zed project",
322 // leader.user.github_login
323 // ),
324 // theme.workspace.external_location_message.text.clone(),
325 // )
326 // .contained()
327 // .with_style(theme.workspace.external_location_message.container)
328 // .aligned()
329 // .bottom()
330 // .right()
331 // .into_any(),
332 // ),
333 // ParticipantLocation::External => Some(
334 // Label::new(
335 // format!(
336 // "{} is viewing a window outside of Zed",
337 // leader.user.github_login
338 // ),
339 // theme.workspace.external_location_message.text.clone(),
340 // )
341 // .contained()
342 // .with_style(theme.workspace.external_location_message.container)
343 // .aligned()
344 // .bottom()
345 // .right()
346 // .into_any(),
347 // ),
348 // };
349 // }
350
351 // Stack::new()
352 // .with_child(pane_element.contained().with_border(leader_border))
353 // .with_children(leader_status_box)
354 // .into_any()
355 // }
356 // Member::Axis(axis) => axis.render(
357 // project,
358 // basis + 1,
359 // theme,
360 // follower_states,
361 // active_call,
362 // active_pane,
363 // zoomed,
364 // app_state,
365 // cx,
366 // ),
367 // }
368 }
369
370 fn collect_panes<'a>(&'a self, panes: &mut Vec<&'a View<Pane>>) {
371 match self {
372 Member::Axis(axis) => {
373 for member in &axis.members {
374 member.collect_panes(panes);
375 }
376 }
377 Member::Pane(pane) => panes.push(pane),
378 }
379 }
380}
381
382#[derive(Clone)]
383pub(crate) struct PaneAxis {
384 pub axis: Axis,
385 pub members: Vec<Member>,
386 pub flexes: Arc<Mutex<Vec<f32>>>,
387 pub bounding_boxes: Arc<Mutex<Vec<Option<Bounds<Pixels>>>>>,
388}
389
390impl PartialEq for PaneAxis {
391 fn eq(&self, other: &Self) -> bool {
392 todo!()
393 }
394}
395
396impl PaneAxis {
397 pub fn new(axis: Axis, members: Vec<Member>) -> Self {
398 let flexes = Arc::new(Mutex::new(vec![1.; members.len()]));
399 let bounding_boxes = Arc::new(Mutex::new(vec![None; members.len()]));
400 Self {
401 axis,
402 members,
403 flexes,
404 bounding_boxes,
405 }
406 }
407
408 pub fn load(axis: Axis, members: Vec<Member>, flexes: Option<Vec<f32>>) -> Self {
409 let flexes = flexes.unwrap_or_else(|| vec![1.; members.len()]);
410 debug_assert!(members.len() == flexes.len());
411
412 let flexes = Arc::new(Mutex::new(flexes));
413 let bounding_boxes = Arc::new(Mutex::new(vec![None; members.len()]));
414 Self {
415 axis,
416 members,
417 flexes,
418 bounding_boxes,
419 }
420 }
421
422 fn split(
423 &mut self,
424 old_pane: &View<Pane>,
425 new_pane: &View<Pane>,
426 direction: SplitDirection,
427 ) -> Result<()> {
428 for (mut idx, member) in self.members.iter_mut().enumerate() {
429 match member {
430 Member::Axis(axis) => {
431 if axis.split(old_pane, new_pane, direction).is_ok() {
432 return Ok(());
433 }
434 }
435 Member::Pane(pane) => {
436 if pane == old_pane {
437 if direction.axis() == self.axis {
438 if direction.increasing() {
439 idx += 1;
440 }
441
442 self.members.insert(idx, Member::Pane(new_pane.clone()));
443 *self.flexes.lock() = vec![1.; self.members.len()];
444 } else {
445 *member =
446 Member::new_axis(old_pane.clone(), new_pane.clone(), direction);
447 }
448 return Ok(());
449 }
450 }
451 }
452 }
453 Err(anyhow!("Pane not found"))
454 }
455
456 fn remove(&mut self, pane_to_remove: &View<Pane>) -> Result<Option<Member>> {
457 let mut found_pane = false;
458 let mut remove_member = None;
459 for (idx, member) in self.members.iter_mut().enumerate() {
460 match member {
461 Member::Axis(axis) => {
462 if let Ok(last_pane) = axis.remove(pane_to_remove) {
463 if let Some(last_pane) = last_pane {
464 *member = last_pane;
465 }
466 found_pane = true;
467 break;
468 }
469 }
470 Member::Pane(pane) => {
471 if pane == pane_to_remove {
472 found_pane = true;
473 remove_member = Some(idx);
474 break;
475 }
476 }
477 }
478 }
479
480 if found_pane {
481 if let Some(idx) = remove_member {
482 self.members.remove(idx);
483 *self.flexes.lock() = vec![1.; self.members.len()];
484 }
485
486 if self.members.len() == 1 {
487 let result = self.members.pop();
488 *self.flexes.lock() = vec![1.; self.members.len()];
489 Ok(result)
490 } else {
491 Ok(None)
492 }
493 } else {
494 Err(anyhow!("Pane not found"))
495 }
496 }
497
498 fn swap(&mut self, from: &View<Pane>, to: &View<Pane>) {
499 for member in self.members.iter_mut() {
500 match member {
501 Member::Axis(axis) => axis.swap(from, to),
502 Member::Pane(pane) => {
503 if pane == from {
504 *member = Member::Pane(to.clone());
505 } else if pane == to {
506 *member = Member::Pane(from.clone())
507 }
508 }
509 }
510 }
511 }
512
513 fn bounding_box_for_pane(&self, pane: &View<Pane>) -> Option<Bounds<Pixels>> {
514 debug_assert!(self.members.len() == self.bounding_boxes.lock().len());
515
516 for (idx, member) in self.members.iter().enumerate() {
517 match member {
518 Member::Pane(found) => {
519 if pane == found {
520 return self.bounding_boxes.lock()[idx];
521 }
522 }
523 Member::Axis(axis) => {
524 if let Some(rect) = axis.bounding_box_for_pane(pane) {
525 return Some(rect);
526 }
527 }
528 }
529 }
530 None
531 }
532
533 fn pane_at_pixel_position(&self, coordinate: Point<Pixels>) -> Option<&View<Pane>> {
534 debug_assert!(self.members.len() == self.bounding_boxes.lock().len());
535
536 let bounding_boxes = self.bounding_boxes.lock();
537
538 for (idx, member) in self.members.iter().enumerate() {
539 if let Some(coordinates) = bounding_boxes[idx] {
540 if coordinates.contains_point(&coordinate) {
541 return match member {
542 Member::Pane(found) => Some(found),
543 Member::Axis(axis) => axis.pane_at_pixel_position(coordinate),
544 };
545 }
546 }
547 }
548 None
549 }
550
551 fn render(
552 &self,
553 project: &Model<Project>,
554 basis: usize,
555 follower_states: &HashMap<View<Pane>, FollowerState>,
556 active_pane: &View<Pane>,
557 zoomed: Option<&AnyWeakView>,
558 app_state: &Arc<AppState>,
559 cx: &mut ViewContext<Workspace>,
560 ) -> Div {
561 debug_assert!(self.members.len() == self.flexes.lock().len());
562
563 div()
564 .flex()
565 .flex_auto()
566 .map(|s| match self.axis {
567 Axis::Vertical => s.flex_col(),
568 Axis::Horizontal => s.flex_row(),
569 })
570 .children(self.members.iter().enumerate().map(|(ix, member)| {
571 match member {
572 Member::Axis(axis) => axis
573 .render(
574 project,
575 basis,
576 follower_states,
577 active_pane,
578 zoomed,
579 app_state,
580 cx,
581 )
582 .into_any_element(),
583 Member::Pane(pane) => pane.clone().into_any_element(),
584 }
585 }))
586
587 // let mut pane_axis = PaneAxisElement::new(
588 // self.axis,
589 // basis,
590 // self.flexes.clone(),
591 // self.bounding_boxes.clone(),
592 // );
593 // let mut active_pane_ix = None;
594
595 // let mut members = self.members.iter().enumerate().peekable();
596 // while let Some((ix, member)) = members.next() {
597 // let last = members.peek().is_none();
598
599 // if member.contains(active_pane) {
600 // active_pane_ix = Some(ix);
601 // }
602
603 // let mut member = member.render(
604 // project,
605 // (basis + ix) * 10,
606 // theme,
607 // follower_states,
608 // active_call,
609 // active_pane,
610 // zoomed,
611 // app_state,
612 // cx,
613 // );
614
615 // if !last {
616 // let mut border = theme.workspace.pane_divider;
617 // border.left = false;
618 // border.right = false;
619 // border.top = false;
620 // border.bottom = false;
621
622 // match self.axis {
623 // Axis::Vertical => border.bottom = true,
624 // Axis::Horizontal => border.right = true,
625 // }
626
627 // member = member.contained().with_border(border).into_any();
628 // }
629
630 // pane_axis = pane_axis.with_child(member.into_any());
631 // }
632 // pane_axis.set_active_pane(active_pane_ix);
633 // pane_axis.into_any()
634 }
635}
636
637#[derive(Clone, Copy, Debug, Deserialize, PartialEq)]
638pub enum SplitDirection {
639 Up,
640 Down,
641 Left,
642 Right,
643}
644
645impl SplitDirection {
646 pub fn all() -> [Self; 4] {
647 [Self::Up, Self::Down, Self::Left, Self::Right]
648 }
649
650 pub fn edge(&self, rect: Bounds<Pixels>) -> Pixels {
651 match self {
652 Self::Up => rect.origin.y,
653 Self::Down => rect.lower_left().y,
654 Self::Left => rect.lower_left().x,
655 Self::Right => rect.lower_right().x,
656 }
657 }
658
659 pub fn along_edge(&self, bounds: Bounds<Pixels>, length: Pixels) -> Bounds<Pixels> {
660 match self {
661 Self::Up => Bounds {
662 origin: bounds.origin,
663 size: size(bounds.size.width, length),
664 },
665 Self::Down => Bounds {
666 origin: point(bounds.lower_left().x, bounds.lower_left().y - length),
667 size: size(bounds.size.width, length),
668 },
669 Self::Left => Bounds {
670 origin: bounds.origin,
671 size: size(length, bounds.size.height),
672 },
673 Self::Right => Bounds {
674 origin: point(bounds.lower_right().x - length, bounds.lower_left().y),
675 size: size(length, bounds.size.height),
676 },
677 }
678 }
679
680 pub fn axis(&self) -> Axis {
681 match self {
682 Self::Up | Self::Down => Axis::Vertical,
683 Self::Left | Self::Right => Axis::Horizontal,
684 }
685 }
686
687 pub fn increasing(&self) -> bool {
688 match self {
689 Self::Left | Self::Up => false,
690 Self::Down | Self::Right => true,
691 }
692 }
693}
694
695// mod element {
696// // use std::{cell::RefCell, iter::from_fn, ops::Range, rc::Rc};
697
698// // use gpui::{
699// // geometry::{
700// // rect::Bounds<Pixels>,
701// // vector::{vec2f, Vector2F},
702// // },
703// // json::{self, ToJson},
704// // platform::{CursorStyle, MouseButton},
705// // scene::MouseDrag,
706// // AnyElement, Axis, CursorRegion, Element, EventContext, MouseRegion, Bounds<Pixels>Ext,
707// // SizeConstraint, Vector2FExt, ViewContext,
708// // };
709
710// use crate::{
711// pane_group::{HANDLE_HITBOX_SIZE, HORIZONTAL_MIN_SIZE, VERTICAL_MIN_SIZE},
712// Workspace, WorkspaceSettings,
713// };
714
715// pub struct PaneAxisElement {
716// axis: Axis,
717// basis: usize,
718// active_pane_ix: Option<usize>,
719// flexes: Rc<RefCell<Vec<f32>>>,
720// children: Vec<AnyElement<Workspace>>,
721// bounding_boxes: Rc<RefCell<Vec<Option<Bounds<Pixels>>>>>,
722// }
723
724// impl PaneAxisElement {
725// pub fn new(
726// axis: Axis,
727// basis: usize,
728// flexes: Rc<RefCell<Vec<f32>>>,
729// bounding_boxes: Rc<RefCell<Vec<Option<Bounds<Pixels>>>>>,
730// ) -> Self {
731// Self {
732// axis,
733// basis,
734// flexes,
735// bounding_boxes,
736// active_pane_ix: None,
737// children: Default::default(),
738// }
739// }
740
741// pub fn set_active_pane(&mut self, active_pane_ix: Option<usize>) {
742// self.active_pane_ix = active_pane_ix;
743// }
744
745// fn layout_children(
746// &mut self,
747// active_pane_magnification: f32,
748// constraint: SizeConstraint,
749// remaining_space: &mut f32,
750// remaining_flex: &mut f32,
751// cross_axis_max: &mut f32,
752// view: &mut Workspace,
753// cx: &mut ViewContext<Workspace>,
754// ) {
755// let flexes = self.flexes.borrow();
756// let cross_axis = self.axis.invert();
757// for (ix, child) in self.children.iter_mut().enumerate() {
758// let flex = if active_pane_magnification != 1. {
759// if let Some(active_pane_ix) = self.active_pane_ix {
760// if ix == active_pane_ix {
761// active_pane_magnification
762// } else {
763// 1.
764// }
765// } else {
766// 1.
767// }
768// } else {
769// flexes[ix]
770// };
771
772// let child_size = if *remaining_flex == 0.0 {
773// *remaining_space
774// } else {
775// let space_per_flex = *remaining_space / *remaining_flex;
776// space_per_flex * flex
777// };
778
779// let child_constraint = match self.axis {
780// Axis::Horizontal => SizeConstraint::new(
781// vec2f(child_size, constraint.min.y()),
782// vec2f(child_size, constraint.max.y()),
783// ),
784// Axis::Vertical => SizeConstraint::new(
785// vec2f(constraint.min.x(), child_size),
786// vec2f(constraint.max.x(), child_size),
787// ),
788// };
789// let child_size = child.layout(child_constraint, view, cx);
790// *remaining_space -= child_size.along(self.axis);
791// *remaining_flex -= flex;
792// *cross_axis_max = cross_axis_max.max(child_size.along(cross_axis));
793// }
794// }
795
796// fn handle_resize(
797// flexes: Rc<RefCell<Vec<f32>>>,
798// axis: Axis,
799// preceding_ix: usize,
800// child_start: Vector2F,
801// drag_bounds: Bounds<Pixels>,
802// ) -> impl Fn(MouseDrag, &mut Workspace, &mut EventContext<Workspace>) {
803// let size = move |ix, flexes: &[f32]| {
804// drag_bounds.length_along(axis) * (flexes[ix] / flexes.len() as f32)
805// };
806
807// move |drag, workspace: &mut Workspace, cx| {
808// if drag.end {
809// // TODO: Clear cascading resize state
810// return;
811// }
812// let min_size = match axis {
813// Axis::Horizontal => HORIZONTAL_MIN_SIZE,
814// Axis::Vertical => VERTICAL_MIN_SIZE,
815// };
816// let mut flexes = flexes.borrow_mut();
817
818// // Don't allow resizing to less than the minimum size, if elements are already too small
819// if min_size - 1. > size(preceding_ix, flexes.as_slice()) {
820// return;
821// }
822
823// let mut proposed_current_pixel_change = (drag.position - child_start).along(axis)
824// - size(preceding_ix, flexes.as_slice());
825
826// let flex_changes = |pixel_dx, target_ix, next: isize, flexes: &[f32]| {
827// let flex_change = pixel_dx / drag_bounds.length_along(axis);
828// let current_target_flex = flexes[target_ix] + flex_change;
829// let next_target_flex =
830// flexes[(target_ix as isize + next) as usize] - flex_change;
831// (current_target_flex, next_target_flex)
832// };
833
834// let mut successors = from_fn({
835// let forward = proposed_current_pixel_change > 0.;
836// let mut ix_offset = 0;
837// let len = flexes.len();
838// move || {
839// let result = if forward {
840// (preceding_ix + 1 + ix_offset < len).then(|| preceding_ix + ix_offset)
841// } else {
842// (preceding_ix as isize - ix_offset as isize >= 0)
843// .then(|| preceding_ix - ix_offset)
844// };
845
846// ix_offset += 1;
847
848// result
849// }
850// });
851
852// while proposed_current_pixel_change.abs() > 0. {
853// let Some(current_ix) = successors.next() else {
854// break;
855// };
856
857// let next_target_size = f32::max(
858// size(current_ix + 1, flexes.as_slice()) - proposed_current_pixel_change,
859// min_size,
860// );
861
862// let current_target_size = f32::max(
863// size(current_ix, flexes.as_slice())
864// + size(current_ix + 1, flexes.as_slice())
865// - next_target_size,
866// min_size,
867// );
868
869// let current_pixel_change =
870// current_target_size - size(current_ix, flexes.as_slice());
871
872// let (current_target_flex, next_target_flex) =
873// flex_changes(current_pixel_change, current_ix, 1, flexes.as_slice());
874
875// flexes[current_ix] = current_target_flex;
876// flexes[current_ix + 1] = next_target_flex;
877
878// proposed_current_pixel_change -= current_pixel_change;
879// }
880
881// workspace.schedule_serialize(cx);
882// cx.notify();
883// }
884// }
885// }
886
887// impl Extend<AnyElement<Workspace>> for PaneAxisElement {
888// fn extend<T: IntoIterator<Item = AnyElement<Workspace>>>(&mut self, children: T) {
889// self.children.extend(children);
890// }
891// }
892
893// impl Element<Workspace> for PaneAxisElement {
894// type LayoutState = f32;
895// type PaintState = ();
896
897// fn layout(
898// &mut self,
899// constraint: SizeConstraint,
900// view: &mut Workspace,
901// cx: &mut ViewContext<Workspace>,
902// ) -> (Vector2F, Self::LayoutState) {
903// debug_assert!(self.children.len() == self.flexes.borrow().len());
904
905// let active_pane_magnification =
906// settings::get::<WorkspaceSettings>(cx).active_pane_magnification;
907
908// let mut remaining_flex = 0.;
909
910// if active_pane_magnification != 1. {
911// let active_pane_flex = self
912// .active_pane_ix
913// .map(|_| active_pane_magnification)
914// .unwrap_or(1.);
915// remaining_flex += self.children.len() as f32 - 1. + active_pane_flex;
916// } else {
917// for flex in self.flexes.borrow().iter() {
918// remaining_flex += flex;
919// }
920// }
921
922// let mut cross_axis_max: f32 = 0.0;
923// let mut remaining_space = constraint.max_along(self.axis);
924
925// if remaining_space.is_infinite() {
926// panic!("flex contains flexible children but has an infinite constraint along the flex axis");
927// }
928
929// self.layout_children(
930// active_pane_magnification,
931// constraint,
932// &mut remaining_space,
933// &mut remaining_flex,
934// &mut cross_axis_max,
935// view,
936// cx,
937// );
938
939// let mut size = match self.axis {
940// Axis::Horizontal => vec2f(constraint.max.x() - remaining_space, cross_axis_max),
941// Axis::Vertical => vec2f(cross_axis_max, constraint.max.y() - remaining_space),
942// };
943
944// if constraint.min.x().is_finite() {
945// size.set_x(size.x().max(constraint.min.x()));
946// }
947// if constraint.min.y().is_finite() {
948// size.set_y(size.y().max(constraint.min.y()));
949// }
950
951// if size.x() > constraint.max.x() {
952// size.set_x(constraint.max.x());
953// }
954// if size.y() > constraint.max.y() {
955// size.set_y(constraint.max.y());
956// }
957
958// (size, remaining_space)
959// }
960
961// fn paint(
962// &mut self,
963// bounds: Bounds<Pixels>,
964// visible_bounds: Bounds<Pixels>,
965// remaining_space: &mut Self::LayoutState,
966// view: &mut Workspace,
967// cx: &mut ViewContext<Workspace>,
968// ) -> Self::PaintState {
969// let can_resize = settings::get::<WorkspaceSettings>(cx).active_pane_magnification == 1.;
970// let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default();
971
972// let overflowing = *remaining_space < 0.;
973// if overflowing {
974// cx.scene().push_layer(Some(visible_bounds));
975// }
976
977// let mut child_origin = bounds.origin();
978
979// let mut bounding_boxes = self.bounding_boxes.borrow_mut();
980// bounding_boxes.clear();
981
982// let mut children_iter = self.children.iter_mut().enumerate().peekable();
983// while let Some((ix, child)) = children_iter.next() {
984// let child_start = child_origin.clone();
985// child.paint(child_origin, visible_bounds, view, cx);
986
987// bounding_boxes.push(Some(Bounds<Pixels>::new(child_origin, child.size())));
988
989// match self.axis {
990// Axis::Horizontal => child_origin += vec2f(child.size().x(), 0.0),
991// Axis::Vertical => child_origin += vec2f(0.0, child.size().y()),
992// }
993
994// if can_resize && children_iter.peek().is_some() {
995// cx.scene().push_stacking_context(None, None);
996
997// let handle_origin = match self.axis {
998// Axis::Horizontal => child_origin - vec2f(HANDLE_HITBOX_SIZE / 2., 0.0),
999// Axis::Vertical => child_origin - vec2f(0.0, HANDLE_HITBOX_SIZE / 2.),
1000// };
1001
1002// let handle_bounds = match self.axis {
1003// Axis::Horizontal => Bounds<Pixels>::new(
1004// handle_origin,
1005// vec2f(HANDLE_HITBOX_SIZE, visible_bounds.height()),
1006// ),
1007// Axis::Vertical => Bounds<Pixels>::new(
1008// handle_origin,
1009// vec2f(visible_bounds.width(), HANDLE_HITBOX_SIZE),
1010// ),
1011// };
1012
1013// let style = match self.axis {
1014// Axis::Horizontal => CursorStyle::ResizeLeftRight,
1015// Axis::Vertical => CursorStyle::ResizeUpDown,
1016// };
1017
1018// cx.scene().push_cursor_region(CursorRegion {
1019// bounds: handle_bounds,
1020// style,
1021// });
1022
1023// enum ResizeHandle {}
1024// let mut mouse_region = MouseRegion::new::<ResizeHandle>(
1025// cx.view_id(),
1026// self.basis + ix,
1027// handle_bounds,
1028// );
1029// mouse_region = mouse_region
1030// .on_drag(
1031// MouseButton::Left,
1032// Self::handle_resize(
1033// self.flexes.clone(),
1034// self.axis,
1035// ix,
1036// child_start,
1037// visible_bounds.clone(),
1038// ),
1039// )
1040// .on_click(MouseButton::Left, {
1041// let flexes = self.flexes.clone();
1042// move |e, v: &mut Workspace, cx| {
1043// if e.click_count >= 2 {
1044// let mut borrow = flexes.borrow_mut();
1045// *borrow = vec![1.; borrow.len()];
1046// v.schedule_serialize(cx);
1047// cx.notify();
1048// }
1049// }
1050// });
1051// cx.scene().push_mouse_region(mouse_region);
1052
1053// cx.scene().pop_stacking_context();
1054// }
1055// }
1056
1057// if overflowing {
1058// cx.scene().pop_layer();
1059// }
1060// }
1061
1062// fn rect_for_text_range(
1063// &self,
1064// range_utf16: Range<usize>,
1065// _: Bounds<Pixels>,
1066// _: Bounds<Pixels>,
1067// _: &Self::LayoutState,
1068// _: &Self::PaintState,
1069// view: &Workspace,
1070// cx: &ViewContext<Workspace>,
1071// ) -> Option<Bounds<Pixels>> {
1072// self.children
1073// .iter()
1074// .find_map(|child| child.rect_for_text_range(range_utf16.clone(), view, cx))
1075// }
1076
1077// fn debug(
1078// &self,
1079// bounds: Bounds<Pixels>,
1080// _: &Self::LayoutState,
1081// _: &Self::PaintState,
1082// view: &Workspace,
1083// cx: &ViewContext<Workspace>,
1084// ) -> json::Value {
1085// serde_json::json!({
1086// "type": "PaneAxis",
1087// "bounds": bounds.to_json(),
1088// "axis": self.axis.to_json(),
1089// "flexes": *self.flexes.borrow(),
1090// "children": self.children.iter().map(|child| child.debug(view, cx)).collect::<Vec<json::Value>>()
1091// })
1092// }
1093// }
1094// }