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