diff --git a/src/tree/container.rs b/src/tree/container.rs index 3b981490..3fbda5a7 100644 --- a/src/tree/container.rs +++ b/src/tree/container.rs @@ -1,4 +1,5 @@ mod drag_destination; +mod layout; mod tasks; pub use drag_destination::default_tile_drag_destination; @@ -45,7 +46,7 @@ use { cell::{Cell, RefCell}, fmt::{Debug, Formatter}, mem, - ops::{Deref, DerefMut, Sub}, + ops::{Deref, DerefMut}, rc::Rc, }, }; @@ -190,23 +191,6 @@ struct CursorState { op: Option, } -impl ContainerChild { - fn position_content(&self) { - let mut content = self.content.get(); - let body = self.body.get(); - let width = content.width(); - let height = content.height(); - // let x1 = body.x1() + (body.width() - width) / 2; - // let y1 = body.y1() + (body.height() - height) / 2; - let x1 = body.x1(); - let y1 = body.y1(); - content = Rect::new_sized_saturating(x1, y1, width, height); - // log::debug!("body: {:?}", body); - // log::debug!("content: {:?}", content); - self.content.set(content); - } -} - impl ContainerNode { pub fn new( state: &Rc, @@ -391,218 +375,6 @@ impl ContainerNode { } } - pub fn predict_child_body_size(&self) -> (i32, i32) { - if self.mono_child.is_some() { - let mb = self.mono_body.get(); - return (mb.width(), mb.height()); - } - let nc = self.num_children.get() as i32 + 1; - match self.split.get() { - ContainerSplit::Horizontal => { - let spacing = self.child_spacing(); - let content_w = self.width.get().sub((nc - 1) * spacing).max(0); - (content_w / nc, self.height.get()) - } - ContainerSplit::Vertical => { - let spacing = self.child_spacing(); - let content_h = self.height.get().sub((nc - 1) * spacing).max(0); - (self.width.get(), content_h / nc) - } - } - } - - pub fn on_spaces_changed(self: &Rc) { - self.update_content_size(); - // log::info!("on_spaces_changed"); - self.schedule_layout(); - self.schedule_compute_render_positions(); - } - - pub fn on_colors_changed(self: &Rc) { - self.schedule_compute_render_positions(); - } - - fn damage(&self) { - let bw = if self.state.theme.sizes.gap.get() != 0 { - self.state.theme.sizes.border_width.get() - } else { - 0 - }; - self.state.damage(Rect::new_sized_saturating( - self.abs_x1.get() - bw, - self.abs_y1.get() - bw, - self.width.get() + 2 * bw, - self.height.get() + 2 * bw, - )); - } - - fn child_spacing(&self) -> i32 { - let gap = self.state.theme.sizes.gap.get(); - let bw = self.state.theme.sizes.border_width.get(); - if gap == 0 { bw } else { gap + 2 * bw } - } - - fn schedule_layout(self: &Rc) { - if self.state.layout_animations_requested.get() || self.state.layout_animations_active.get() - { - self.animate_next_layout.set(true); - } - if !self.layout_scheduled.replace(true) { - self.state.pending_container_layout.push(self.clone()); - } - } - - fn schedule_layout_immediate(self: &Rc) { - self.schedule_layout(); - if self.toplevel_data.visible.get() { - self.damage(); - } - } - - fn all_children_match_body(&self) -> bool { - if let Some(mono) = self.mono_child.get() { - let body = self.mono_body.get(); - let content = mono.content.get(); - return content.width() == body.width() && content.height() == body.height(); - } - for child in self.children.iter() { - let body = child.body.get(); - let content = child.content.get(); - if content.width() != body.width() || content.height() != body.height() { - return false; - } - } - true - } - - fn perform_layout(self: &Rc) { - self.layout_scheduled.set(false); - if self.num_children.get() == 0 { - self.mono_transition_animation_pending.set(false); - return; - } - if let Some(child) = self.mono_child.get() { - self.perform_mono_layout(&child); - } else { - self.perform_split_layout(); - } - self.state.tree_changed(); - // log::info!("perform_layout"); - self.schedule_compute_render_positions(); - self.layout_complete.trigger(); - if self.all_children_match_body() { - self.all_children_resized.trigger(); - if self.toplevel_data.visible.get() { - self.damage(); - } - } - self.mono_transition_animation_pending.set(false); - } - - fn perform_mono_layout(self: &Rc, child: &ContainerChild) { - let mb = self.mono_body.get(); - child - .node - .clone() - .tl_change_extents(&mb.move_(self.abs_x1.get(), self.abs_y1.get())); - self.mono_content - .set(child.content.get().at_point(mb.x1(), mb.y1())); - } - - fn perform_split_layout(self: &Rc) { - let sum_factors = self.sum_factors.get(); - let split = self.split.get(); - let spacing = self.child_spacing(); - let (content_size, other_content_size) = match split { - ContainerSplit::Horizontal => (self.content_width.get(), self.content_height.get()), - ContainerSplit::Vertical => (self.content_height.get(), self.content_width.get()), - }; - let num_children = self.num_children.get(); - if num_children == 0 { - return; - } - let mut pos = 0; - let mut remaining_content_size = content_size; - for child in self.children.iter() { - let factor = child.factor.get() / sum_factors; - child.factor.set(factor); - let mut body_size = (content_size as f64 * factor).round() as i32; - body_size = body_size.min(remaining_content_size); - remaining_content_size -= body_size; - let (x1, y1, width, height) = match split { - ContainerSplit::Horizontal => (pos, 0, body_size, other_content_size), - _ => (0, pos, other_content_size, body_size), - }; - let body = Rect::new_sized_saturating(x1, y1, width, height); - child.body.set(body); - pos += body_size + spacing; - } - if remaining_content_size > 0 { - let size_per = remaining_content_size / num_children as i32; - let mut rem = remaining_content_size % num_children as i32; - pos = 0; - for child in self.children.iter() { - let mut body = child.body.get(); - let mut add = size_per; - if rem > 0 { - rem -= 1; - add += 1; - } - let (x1, y1, width, height, size) = match split { - ContainerSplit::Horizontal => { - let width = body.width() + add; - (pos, 0, width, other_content_size, width) - } - _ => { - let height = body.height() + add; - (0, pos, other_content_size, height, height) - } - }; - body = Rect::new_sized_saturating(x1, y1, width, height); - child.body.set(body); - pos += size + spacing; - } - } - self.sum_factors.set(1.0); - for child in self.children.iter() { - let body = child.body.get(); - let body = body.move_(self.abs_x1.get(), self.abs_y1.get()); - child.node.clone().tl_change_extents(&body); - child.position_content(); - } - } - - fn update_content_size(&self) { - let nc = self.num_children.get(); - let spacing = self.child_spacing(); - match self.split.get() { - ContainerSplit::Horizontal => { - let new_content_size = self.width.get().sub((nc - 1) as i32 * spacing).max(0); - self.content_width.set(new_content_size); - self.content_height.set(self.height.get()); - } - ContainerSplit::Vertical => { - let new_content_size = self.height.get().sub((nc - 1) as i32 * spacing).max(0); - self.content_height.set(new_content_size); - self.content_width.set(self.width.get()); - } - } - let tab_bar_height = if self.mono_child.is_some() { - // Tab bar sits above the window with a configurable gap. - let tbh = self.state.theme.sizes.tab_bar_height.get(); - let gap = self.state.theme.sizes.tab_bar_gap.get(); - tbh + gap - } else { - 0 - }; - self.mono_body.set(Rect::new_sized_saturating( - 0, - tab_bar_height, - self.width.get(), - (self.height.get() - tab_bar_height).max(0), - )); - } - fn pointer_move( self: &Rc, _seat: &Rc, diff --git a/src/tree/container/layout.rs b/src/tree/container/layout.rs new file mode 100644 index 00000000..e04f2366 --- /dev/null +++ b/src/tree/container/layout.rs @@ -0,0 +1,236 @@ +use { + super::{ContainerChild, ContainerNode, ContainerSplit}, + crate::rect::Rect, + std::{ops::Sub, rc::Rc}, +}; + +impl ContainerChild { + pub(super) fn position_content(&self) { + let mut content = self.content.get(); + let body = self.body.get(); + let width = content.width(); + let height = content.height(); + // let x1 = body.x1() + (body.width() - width) / 2; + // let y1 = body.y1() + (body.height() - height) / 2; + let x1 = body.x1(); + let y1 = body.y1(); + content = Rect::new_sized_saturating(x1, y1, width, height); + // log::debug!("body: {:?}", body); + // log::debug!("content: {:?}", content); + self.content.set(content); + } +} + +impl ContainerNode { + pub fn predict_child_body_size(&self) -> (i32, i32) { + if self.mono_child.is_some() { + let mb = self.mono_body.get(); + return (mb.width(), mb.height()); + } + let nc = self.num_children.get() as i32 + 1; + match self.split.get() { + ContainerSplit::Horizontal => { + let spacing = self.child_spacing(); + let content_w = self.width.get().sub((nc - 1) * spacing).max(0); + (content_w / nc, self.height.get()) + } + ContainerSplit::Vertical => { + let spacing = self.child_spacing(); + let content_h = self.height.get().sub((nc - 1) * spacing).max(0); + (self.width.get(), content_h / nc) + } + } + } + + pub fn on_spaces_changed(self: &Rc) { + self.update_content_size(); + // log::info!("on_spaces_changed"); + self.schedule_layout(); + self.schedule_compute_render_positions(); + } + + pub fn on_colors_changed(self: &Rc) { + self.schedule_compute_render_positions(); + } + + pub(super) fn damage(&self) { + let bw = if self.state.theme.sizes.gap.get() != 0 { + self.state.theme.sizes.border_width.get() + } else { + 0 + }; + self.state.damage(Rect::new_sized_saturating( + self.abs_x1.get() - bw, + self.abs_y1.get() - bw, + self.width.get() + 2 * bw, + self.height.get() + 2 * bw, + )); + } + + pub(super) fn child_spacing(&self) -> i32 { + let gap = self.state.theme.sizes.gap.get(); + let bw = self.state.theme.sizes.border_width.get(); + if gap == 0 { bw } else { gap + 2 * bw } + } + + pub(super) fn schedule_layout(self: &Rc) { + if self.state.layout_animations_requested.get() || self.state.layout_animations_active.get() + { + self.animate_next_layout.set(true); + } + if !self.layout_scheduled.replace(true) { + self.state.pending_container_layout.push(self.clone()); + } + } + + pub(super) fn schedule_layout_immediate(self: &Rc) { + self.schedule_layout(); + if self.toplevel_data.visible.get() { + self.damage(); + } + } + + pub(super) fn all_children_match_body(&self) -> bool { + if let Some(mono) = self.mono_child.get() { + let body = self.mono_body.get(); + let content = mono.content.get(); + return content.width() == body.width() && content.height() == body.height(); + } + for child in self.children.iter() { + let body = child.body.get(); + let content = child.content.get(); + if content.width() != body.width() || content.height() != body.height() { + return false; + } + } + true + } + + pub(super) fn perform_layout(self: &Rc) { + self.layout_scheduled.set(false); + if self.num_children.get() == 0 { + self.mono_transition_animation_pending.set(false); + return; + } + if let Some(child) = self.mono_child.get() { + self.perform_mono_layout(&child); + } else { + self.perform_split_layout(); + } + self.state.tree_changed(); + // log::info!("perform_layout"); + self.schedule_compute_render_positions(); + self.layout_complete.trigger(); + if self.all_children_match_body() { + self.all_children_resized.trigger(); + if self.toplevel_data.visible.get() { + self.damage(); + } + } + self.mono_transition_animation_pending.set(false); + } + + fn perform_mono_layout(self: &Rc, child: &ContainerChild) { + let mb = self.mono_body.get(); + child + .node + .clone() + .tl_change_extents(&mb.move_(self.abs_x1.get(), self.abs_y1.get())); + self.mono_content + .set(child.content.get().at_point(mb.x1(), mb.y1())); + } + + fn perform_split_layout(self: &Rc) { + let sum_factors = self.sum_factors.get(); + let split = self.split.get(); + let spacing = self.child_spacing(); + let (content_size, other_content_size) = match split { + ContainerSplit::Horizontal => (self.content_width.get(), self.content_height.get()), + ContainerSplit::Vertical => (self.content_height.get(), self.content_width.get()), + }; + let num_children = self.num_children.get(); + if num_children == 0 { + return; + } + let mut pos = 0; + let mut remaining_content_size = content_size; + for child in self.children.iter() { + let factor = child.factor.get() / sum_factors; + child.factor.set(factor); + let mut body_size = (content_size as f64 * factor).round() as i32; + body_size = body_size.min(remaining_content_size); + remaining_content_size -= body_size; + let (x1, y1, width, height) = match split { + ContainerSplit::Horizontal => (pos, 0, body_size, other_content_size), + _ => (0, pos, other_content_size, body_size), + }; + let body = Rect::new_sized_saturating(x1, y1, width, height); + child.body.set(body); + pos += body_size + spacing; + } + if remaining_content_size > 0 { + let size_per = remaining_content_size / num_children as i32; + let mut rem = remaining_content_size % num_children as i32; + pos = 0; + for child in self.children.iter() { + let mut body = child.body.get(); + let mut add = size_per; + if rem > 0 { + rem -= 1; + add += 1; + } + let (x1, y1, width, height, size) = match split { + ContainerSplit::Horizontal => { + let width = body.width() + add; + (pos, 0, width, other_content_size, width) + } + _ => { + let height = body.height() + add; + (0, pos, other_content_size, height, height) + } + }; + body = Rect::new_sized_saturating(x1, y1, width, height); + child.body.set(body); + pos += size + spacing; + } + } + self.sum_factors.set(1.0); + for child in self.children.iter() { + let body = child.body.get(); + let body = body.move_(self.abs_x1.get(), self.abs_y1.get()); + child.node.clone().tl_change_extents(&body); + child.position_content(); + } + } + + pub(super) fn update_content_size(&self) { + let nc = self.num_children.get(); + let spacing = self.child_spacing(); + match self.split.get() { + ContainerSplit::Horizontal => { + let new_content_size = self.width.get().sub((nc - 1) as i32 * spacing).max(0); + self.content_width.set(new_content_size); + self.content_height.set(self.height.get()); + } + ContainerSplit::Vertical => { + let new_content_size = self.height.get().sub((nc - 1) as i32 * spacing).max(0); + self.content_height.set(new_content_size); + self.content_width.set(self.width.get()); + } + } + let tab_bar_height = if self.mono_child.is_some() { + // Tab bar sits above the window with a configurable gap. + let tbh = self.state.theme.sizes.tab_bar_height.get(); + let gap = self.state.theme.sizes.tab_bar_gap.get(); + tbh + gap + } else { + 0 + }; + self.mono_body.set(Rect::new_sized_saturating( + 0, + tab_bar_height, + self.width.get(), + (self.height.get() - tab_bar_height).max(0), + )); + } +}