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