pane_group.rs

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