use std::cell::UnsafeCell;
use std::marker::PhantomPinned;
use std::pin::Pin;
use std::sync::Arc;
use crate::co;
use crate::decl::*;
use crate::gui::privs::*;
use crate::msg::*;
use crate::prelude::*;
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub enum Horz {
None,
Repos,
Resize,
}
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub enum Vert {
None,
Repos,
Resize,
}
struct ChildInfo {
hchild: HWND,
horz: Horz,
vert: Vert,
rc_orig: Option<RECT>, }
struct LayoutObj {
ctrls: UnsafeCell<Vec<ChildInfo>>,
sz_parent_orig: UnsafeCell<Option<SIZE>>, _pin: PhantomPinned,
}
#[derive(Clone)]
pub(in crate::gui) struct Layout(Pin<Arc<LayoutObj>>);
impl Layout {
#[must_use]
pub(in crate::gui) fn new() -> Self {
Self(Arc::pin(LayoutObj {
ctrls: UnsafeCell::new(Vec::new()),
sz_parent_orig: UnsafeCell::new(None),
_pin: PhantomPinned,
}))
}
pub(in crate::gui) fn add_child(
&self,
hparent: &HWND,
hchild: &HWND,
resize_behavior: (Horz, Vert),
) {
if *hparent == HWND::NULL || *hchild == HWND::NULL {
panic!("Cannot add resizer entries before window/control creation.");
}
let (horz, vert) = resize_behavior;
if horz != Horz::None || vert != Vert::None {
let ctrls = unsafe { &mut *self.0.ctrls.get() };
if ctrls.is_empty() {
let rc_parent = hparent.GetClientRect().expect(DONTFAIL);
*unsafe { &mut *self.0.sz_parent_orig.get() } = Some(
SIZE::with(rc_parent.right, rc_parent.bottom), );
}
ctrls.push(ChildInfo {
hchild: unsafe { hchild.raw_copy() },
horz,
vert,
rc_orig: None,
});
}
}
pub(in crate::gui) fn rearrange(&self, p: wm::Size) {
let ctrls = unsafe { &mut *self.0.ctrls.get() };
if ctrls.is_empty() || p.request == co::SIZE_R::MINIMIZED
{
return; }
let sz_parent_orig = match unsafe { &mut *self.0.sz_parent_orig.get() } {
Some(sz) => *sz,
None => panic!("Original parent client area was not saved."),
};
let mut hdwp = HDWP::BeginDeferWindowPos(ctrls.len() as _).expect(DONTFAIL);
for ctrl in ctrls.iter_mut() {
let mut uflags = co::SWP::NOZORDER;
if ctrl.horz == Horz::Repos && ctrl.vert == Vert::Repos {
uflags |= co::SWP::NOSIZE; } else if ctrl.horz == Horz::Resize && ctrl.vert == Vert::Resize {
uflags |= co::SWP::NOMOVE; }
let rc_orig = match &ctrl.rc_orig {
Some(rc) => *rc,
None => {
let rc = ctrl
.hchild
.GetParent()
.expect(DONTFAIL)
.ScreenToClientRc(ctrl.hchild.GetWindowRect().expect(DONTFAIL))
.expect(DONTFAIL);
ctrl.rc_orig = Some(rc); rc
},
};
hdwp.DeferWindowPos(
&ctrl.hchild,
HwndPlace::None,
POINT::with(
match ctrl.horz {
Horz::Repos => p.client_area.cx - sz_parent_orig.cx + rc_orig.left,
_ => rc_orig.left, },
match ctrl.vert {
Vert::Repos => p.client_area.cy - sz_parent_orig.cy + rc_orig.top,
_ => rc_orig.top, },
),
SIZE::with(
match ctrl.horz {
Horz::Resize => {
p.client_area.cx - sz_parent_orig.cx + rc_orig.right - rc_orig.left
},
_ => rc_orig.right - rc_orig.left, },
match ctrl.vert {
Vert::Resize => {
p.client_area.cy - sz_parent_orig.cy + rc_orig.bottom - rc_orig.top
},
_ => rc_orig.bottom - rc_orig.top, },
),
uflags,
)
.expect(DONTFAIL);
}
}
}