diff --git a/Cargo.toml b/Cargo.toml
index bb6f20e..2e2a68a 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,7 +13,7 @@ piccolo = "0.3.3"
unicode-segmentation = "1.11.0"
unicode-width = "0.1.13"
wasm-bindgen = "0.2.92"
-web-sys = { version = "0.3.69", features = ["ResizeObserver"] }
+web-sys = { version = "0.3.69", features = ["ResizeObserver", "DomRect", "CssStyleDeclaration"] }
yew = { version = "0.21.0", features = ["csr"] }
minicrossterm = { git = "https://git.blastmud.org/blasthavers/minicrossterm.git", rev = "494f89daef41162fbd89d5266e261018ed5ff6dc" }
thiserror = "1.0.63"
diff --git a/src/main.rs b/src/main.rs
index 18e8d24..a6464ef 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -7,8 +7,10 @@ pub mod command_handler;
pub mod lineengine;
pub mod lua_state;
pub mod parsing;
+pub mod split_panel;
pub mod term_view;
use crate::lua_state::{install_lua_globals, LuaState};
+use crate::split_panel::*;
use crate::term_view::*;
#[derive(Properties)]
@@ -37,9 +39,9 @@ fn app() -> Html {
install_lua_globals(&global).expect("Couldn't install Lua globals");
html! {
-
-
-
+
+ }}
+ second={ html! { } }/>
}
}
diff --git a/src/split_panel.rs b/src/split_panel.rs
new file mode 100644
index 0000000..2e69f3f
--- /dev/null
+++ b/src/split_panel.rs
@@ -0,0 +1,101 @@
+use std::rc::Rc;
+
+use wasm_bindgen::JsCast;
+use web_sys::{Element, PointerEvent};
+use yew::{function_component, html, use_state_eq, Callback, Html, Properties, UseStateHandle};
+#[derive(Clone, Eq, PartialEq)]
+pub enum PanelDirection {
+ Horizontal,
+ Vertical,
+}
+
+#[derive(PartialEq, Properties)]
+pub struct SplitPanelProps {
+ pub direction: PanelDirection,
+ pub first: Html,
+ pub second: Html,
+}
+
+#[function_component(SplitPanel)]
+pub fn split_panel(props: &SplitPanelProps) -> Html {
+ let is_dragging: Rc>> = use_state_eq(|| None).into();
+ let dragged_space: Rc>> = use_state_eq(|| None).into();
+ let wrapper_class = match props.direction {
+ PanelDirection::Horizontal => "hpanelwrapper",
+ PanelDirection::Vertical => "vpanelwrapper",
+ };
+ let wrapper_class = if (**is_dragging).is_some() {
+ format!("{} dragging", wrapper_class)
+ } else {
+ wrapper_class.to_owned()
+ };
+ let panel_class = match props.direction {
+ PanelDirection::Horizontal => "hpanel",
+ PanelDirection::Vertical => "vpanel",
+ };
+ let divider_class = match props.direction {
+ PanelDirection::Horizontal => "hdivider",
+ PanelDirection::Vertical => "vdivider",
+ };
+ let row_or_col = match props.direction {
+ PanelDirection::Horizontal => "columns",
+ PanelDirection::Vertical => "rows",
+ };
+
+ let layout = match **dragged_space {
+ None => format!("grid-template-{}: 1fr 4px 1fr", row_or_col),
+ Some(custom) => format!("grid-template-{}: {}px 4px 1fr", row_or_col, custom),
+ };
+ let is_dragging_forup = is_dragging.clone();
+ let dragged_space_formove = dragged_space.clone();
+ let dir = props.direction.clone();
+ match **is_dragging {
+ None => {
+ html! {
+
+
{props.first.clone()}
+
{},
+ Some(t) => {
+ let el: Element = JsCast::unchecked_into::
(
+ JsCast::unchecked_into::(t)
+ .parent_node().expect("Parent exists"));
+ let top =
+ match dir {
+ PanelDirection::Horizontal => el.get_bounding_client_rect().x(),
+ PanelDirection::Vertical => el.get_bounding_client_rect().y()
+ };
+ is_dragging.set(Some(top));
+ }
+ }
+ })}
+ />
+ {props.second.clone()}
+
+ }
+ }
+ Some(start) => {
+ html! {
+
e.client_x() as f64,
+ PanelDirection::Vertical => e.client_y() as f64
+ } - start - 2.0;
+ (*dragged_space_formove).set(Some(distance));
+ })}
+ >
+
{props.first.clone()}
+
+
{props.second.clone()}
+
+ }
+ }
+ }
+}
diff --git a/styles.css b/styles.css
index 5bd5bfd..7c066e7 100644
--- a/styles.css
+++ b/styles.css
@@ -10,24 +10,52 @@ body {
position: absolute;
top: 0; left: 0; right: 0; bottom: 0;
}
-.vpane {
- display: flex;
- flex-direction: column;
- justify-content: stretch;
+.vpanelwrapper {
+ display: grid;
+ grid-template-rows: 1fr 4px 1fr;
+ width: 100%;
+ height: 100%;
}
-.hpane {
- display: flex;
- flex-direction: row;
- justify-content: stretch;
+.hpanelwrapper {
+ display: grid;
+ grid-template-columns: 1fr 4px 1fr;
+ width: 100%;
+ height: 100%;
+}
+.dragging.vpanelwrapper {
+ cursor: row-resize;
+ user-select: none;
+}
+.dragging.hpanelwrapper {
+ cursor: col-resize;
+ user-select: none;
+}
+.vdivider {
+ min-height: 4px;
+ background: grey;
+ cursor: row-resize;
+}
+.hdivider {
+ min-height: 4px;
+ background: grey;
+ cursor: col-resize;
+}
+.vpanel {
+ min-width: 0px;
+ min-height: 0px;
+}
+.hpanel {
+ min-width: 0px;
+ min-height: 0px;
}
.toplevel {
position: absolute;
top: 0; left: 0; right: 0; bottom: 0;
}
.hterminal {
- flex: 1 1 0;
min-width: 10px;
min-height: 10px;
border: solid grey 1px;
padding: 2px;
+ height: 100%;
}