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