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