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