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