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