pane_group.rs

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