use super::*;
use crate::draw_context::DrawCtx;
use crate::scrollbar::{scrollbar_base, scrollbar_drag_delta, scrollbar_max_scroll, scrollbar_thumb, ScrollAxis};
use crate::text_layout::build_text_lines;
use crate::widget_tree::{TreeCustomRender, WidgetHandle, WidgetStateHandleDyn, WidgetTreeNode, WidgetTreeNodeKind};
use std::cell::RefCell;
mod command;
pub use command::{CustomRenderArgs, TextWrap};
pub(crate) use command::Command;
mod dispatch;
mod draw;
mod interaction;
mod layout_api;
mod panels;
mod tree;
#[cfg(test)]
mod tests;
pub struct Container {
pub(crate) atlas: AtlasHandle,
pub(crate) style: Rc<Style>,
pub(crate) name: String,
pub(crate) rect: Recti,
pub(crate) body: Recti,
pub(crate) content_size: Dimensioni,
pub(crate) scroll: Vec2i,
pub(crate) zindex: i32,
pub(crate) command_list: Vec<Command>,
pub(crate) triangle_vertices: Vec<Vertex>,
pub(crate) clip_stack: Vec<Recti>,
pub(crate) layout: LayoutManager,
pub(crate) hover: Option<WidgetId>,
pub(crate) focus: Option<WidgetId>,
hover_root_child: Option<ContainerId>,
hover_root_child_rect: Option<Recti>,
next_hover_root_child: Option<ContainerId>,
next_hover_root_child_rect: Option<Recti>,
pub(crate) updated_focus: bool,
pub(crate) scrollbar_y_state: Internal,
pub(crate) scrollbar_x_state: Internal,
pub(crate) input: Rc<RefCell<Input>>,
input_snapshot: Option<Rc<InputSnapshot>>,
pub(crate) in_hover_root: bool,
pub(crate) popup_just_opened: bool,
pending_scroll: Option<Vec2i>,
scroll_enabled: bool,
tree_cache: WidgetTreeCache,
panels: Vec<ContainerHandle>,
}
impl Container {
pub(crate) fn new(name: &str, atlas: AtlasHandle, style: Rc<Style>, input: Rc<RefCell<Input>>) -> Self {
Self {
name: name.to_string(),
style,
atlas,
rect: Recti::default(),
body: Recti::default(),
content_size: Dimensioni::default(),
scroll: Vec2i::default(),
zindex: 0,
command_list: Vec::default(),
triangle_vertices: Vec::default(),
clip_stack: Vec::default(),
hover: None,
focus: None,
hover_root_child: None,
hover_root_child_rect: None,
next_hover_root_child: None,
next_hover_root_child_rect: None,
updated_focus: false,
layout: LayoutManager::default(),
scrollbar_y_state: Internal::new("!scrollbary"),
scrollbar_x_state: Internal::new("!scrollbarx"),
popup_just_opened: false,
in_hover_root: false,
input,
input_snapshot: None,
pending_scroll: None,
scroll_enabled: true,
tree_cache: WidgetTreeCache::default(),
panels: Default::default(),
}
}
pub(crate) fn reset(&mut self) {
self.command_list.clear();
self.triangle_vertices.clear();
self.clip_stack.clear();
self.body = Recti::default();
self.content_size = Dimensioni::default();
self.scroll = Vec2i::default();
self.hover = None;
self.focus = None;
self.clear_root_frame_state();
self.updated_focus = false;
self.input_snapshot = None;
self.popup_just_opened = false;
self.scroll_enabled = true;
self.panels.clear();
self.tree_cache.clear();
}
pub(crate) fn clear_root_frame_state(&mut self) {
self.hover_root_child = None;
self.hover_root_child_rect = None;
self.next_hover_root_child = None;
self.next_hover_root_child_rect = None;
self.in_hover_root = false;
self.pending_scroll = None;
}
pub(crate) fn prepare(&mut self) {
self.command_list.clear();
assert!(self.clip_stack.is_empty());
self.panels.clear();
self.input_snapshot = None;
self.next_hover_root_child = None;
self.next_hover_root_child_rect = None;
self.pending_scroll = None;
self.scroll_enabled = true;
self.tree_cache.begin_frame();
}
pub(crate) fn seed_pending_scroll(&mut self, delta: Option<Vec2i>) {
self.pending_scroll = delta;
}
pub fn finish(&mut self) {
for panel in &mut self.panels {
panel.finish();
}
if !self.updated_focus {
self.focus = None;
}
self.updated_focus = false;
self.hover_root_child = self.next_hover_root_child;
self.hover_root_child_rect = self.next_hover_root_child_rect;
self.next_hover_root_child = None;
self.next_hover_root_child_rect = None;
self.tree_cache.finish_frame();
}
pub fn rect(&self) -> Recti {
self.rect
}
pub fn set_rect(&mut self, rect: Recti) {
self.rect = rect;
}
pub fn body(&self) -> Recti {
self.body
}
pub fn scroll(&self) -> Vec2i {
self.scroll
}
pub fn set_scroll(&mut self, scroll: Vec2i) {
self.scroll = scroll;
}
pub fn content_size(&self) -> Dimensioni {
self.content_size
}
#[cfg(test)]
pub(crate) fn panel_count(&self) -> usize {
self.panels.len()
}
fn clamp(x: i32, a: i32, b: i32) -> i32 {
min(b, max(a, x))
}
fn baseline_aligned_top(rect: Recti, line_height: i32, baseline: i32) -> i32 {
if rect.height >= line_height {
return rect.y + (rect.height - line_height) / 2;
}
let baseline_center = rect.y + rect.height / 2;
let min_top = rect.y + rect.height - line_height;
let max_top = rect.y;
Self::clamp(baseline_center - baseline, min_top, max_top)
}
fn vertical_text_padding(padding: i32) -> i32 {
max(1, padding / 2)
}
}