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