ui/src/elements/grid.rs

872 lines
25 KiB
Rust
Raw Normal View History

2023-01-16 09:53:52 +00:00
use crate::prelude::*;
use anyhow::Result;
use crate::builder::validator::gridinfo::GridInfo;
2023-01-18 06:28:32 +00:00
use std::sync::{
Arc, RwLock, RwLockReadGuard,
2025-03-04 10:37:45 +00:00
atomic::{AtomicBool, AtomicU32, Ordering::SeqCst},
2023-01-16 09:53:52 +00:00
};
use std::{ops::Deref, sync::Weak};
use super::fill_type::FillType;
2024-05-25 07:42:05 +00:00
pub enum ConnectDirection {
East,
West,
South,
North,
}
2023-01-16 09:53:52 +00:00
#[derive(Clone)]
2025-03-04 11:25:02 +00:00
enum ChildState {
2023-01-16 09:53:52 +00:00
Some {
2025-03-04 11:25:02 +00:00
child: Arc<dyn GuiElementTraits>,
2023-01-16 09:53:52 +00:00
x: u32,
y: u32,
},
Extend {
2025-03-04 11:25:02 +00:00
weak_child: Weak<dyn GuiElementTraits>,
2023-01-16 09:53:52 +00:00
x: u32,
y: u32,
},
None,
}
2025-03-04 11:25:02 +00:00
impl ChildState {
2023-01-16 09:53:52 +00:00
fn downgrade(&self) -> Self {
match self {
Self::Some { child, x, y } => Self::Extend {
weak_child: Arc::downgrade(child),
x: *x,
y: *y,
},
_ => panic!(),
}
}
fn is_some(&self) -> bool {
match self {
ChildState::Some { .. } => true,
ChildState::Extend { .. } => false,
ChildState::None => false,
}
}
fn is_extend(&self) -> bool {
match self {
ChildState::Some { .. } => false,
ChildState::Extend { .. } => true,
ChildState::None => false,
}
}
2025-03-04 11:25:02 +00:00
fn get_some(&self) -> Option<(&Arc<dyn GuiElementTraits>, u32, u32)> {
2023-01-16 09:53:52 +00:00
match self {
ChildState::Some { child, x, y } => Some((child, *x, *y)),
ChildState::Extend { .. } => None,
ChildState::None => None,
}
}
2025-03-04 11:25:02 +00:00
fn get(&self) -> Option<(Arc<dyn GuiElementTraits>, u32, u32)> {
2023-01-16 09:53:52 +00:00
match self {
ChildState::Some { child, x, y } => Some((child.clone(), *x, *y)),
2023-01-18 06:28:32 +00:00
ChildState::Extend { weak_child, x, y } => {
weak_child.upgrade().map(|child| (child, *x, *y))
}
2023-01-16 09:53:52 +00:00
ChildState::None => None,
}
}
fn map<C, R>(&self, f: C) -> Option<R>
where
2025-03-04 11:25:02 +00:00
C: FnOnce(&Arc<dyn GuiElementTraits>) -> R,
2023-01-16 09:53:52 +00:00
{
match self {
ChildState::Some { child, .. } => Some(f(child)),
ChildState::Extend { weak_child, .. } => weak_child.upgrade().map(|child| f(&child)),
ChildState::None => None,
}
}
}
2025-03-04 11:25:02 +00:00
pub struct Grid {
2023-01-16 09:53:52 +00:00
pub(crate) framable: Arc<Framable>,
background: RwLock<Option<FillType>>,
2025-03-04 11:25:02 +00:00
children: RwLock<Vec<Vec<ChildState>>>,
2023-01-16 09:53:52 +00:00
dim_x: usize,
dim_y: usize,
padding: AtomicU32,
margin: AtomicU32,
visible: AtomicBool,
}
2025-03-04 11:25:02 +00:00
impl Grid {
2023-01-16 09:53:52 +00:00
pub fn new(
2025-03-04 11:25:02 +00:00
gui_handler: &GuiHandler,
2023-01-16 09:53:52 +00:00
dim_x: usize,
dim_y: usize,
top_level: bool,
) -> Result<Arc<Self>> {
let grid = Arc::new(Grid {
2025-03-04 10:37:45 +00:00
framable: Framable::new(gui_handler.width(), gui_handler.height(), top_level)?,
2023-01-16 09:53:52 +00:00
background: RwLock::new(None),
children: RwLock::new(vec![vec![ChildState::None; dim_y]; dim_x]),
dim_x,
dim_y,
padding: AtomicU32::new(0),
margin: AtomicU32::new(10),
visible: AtomicBool::new(false),
});
2025-03-04 11:25:02 +00:00
// if top_level {
// let weak_grid = Arc::downgrade(&grid);
2023-01-16 09:53:52 +00:00
2025-03-04 11:25:02 +00:00
// grid.framable.add_callback(
// weak_grid.clone(),
// Box::new(move |gui_handler| {
// if let Some(grid) = weak_grid.upgrade() {
// grid.calculate_child_positions(gui_handler)?;
// }
2023-01-16 09:53:52 +00:00
2025-03-04 11:25:02 +00:00
// Ok(())
// }),
// );
// }
2023-01-16 09:53:52 +00:00
Ok(grid)
}
pub fn dimensions(&self) -> (usize, usize) {
(self.dim_x, self.dim_y)
}
2025-03-04 10:37:45 +00:00
pub fn set_background(
&self,
2025-03-04 11:25:02 +00:00
gui_handler: &mut GuiHandler,
2025-03-04 10:37:45 +00:00
background: impl Into<FillTypeInfo>,
) -> Result<()> {
super::set_background(
gui_handler,
self.visible(),
&self.framable,
&self.background,
background,
)
2023-01-16 09:53:52 +00:00
}
pub(crate) fn background(&self) -> RwLockReadGuard<'_, Option<FillType>> {
self.background.read().unwrap()
}
pub fn set_margin(&self, margin: u32) {
self.margin.store(margin, SeqCst);
}
pub fn set_padding(&self, padding: u32) {
self.padding.store(padding, SeqCst);
}
2025-03-04 11:25:02 +00:00
pub fn child_at(&self, x: usize, y: usize) -> Result<Option<Arc<dyn GuiElementTraits>>> {
2023-01-18 06:28:32 +00:00
if x >= self.dim_x {
return Err(anyhow::anyhow!(
"Tried to access Grid at {} while only being {} wide",
x,
self.dim_x
));
}
if y >= self.dim_y {
return Err(anyhow::anyhow!(
"Tried to access Grid at {} while only being {} tall",
y,
self.dim_y
));
}
2023-01-16 09:53:52 +00:00
Ok(self.children.read().unwrap()[x][y].map(|c| c.clone()))
}
2025-03-04 10:37:45 +00:00
pub fn detach(
&self,
2025-03-04 11:25:02 +00:00
gui_handler: &mut GuiHandler,
2025-03-04 10:37:45 +00:00
pos_x: usize,
pos_y: usize,
2025-03-04 11:25:02 +00:00
) -> Result<Option<Arc<dyn GuiElementTraits>>> {
2023-01-16 09:53:52 +00:00
if cfg!(debug_assertions) {
if pos_x >= self.dim_x as usize {
panic!(
"x position ({}) must not be bigger than grid x-dimension ({})",
pos_x, self.dim_x
);
}
if pos_y >= self.dim_y as usize {
panic!(
"y position ({}) must not be bigger than grid y-dimension ({})",
pos_y, self.dim_y
);
}
}
let current = self.children.write().unwrap()[pos_x][pos_y].clone();
if current.is_extend() {
todo!();
}
self.children.write().unwrap()[pos_x][pos_y] = ChildState::None;
match current.get() {
Some((child, _x, _y)) => {
if self.visible() {
if let Some(child_visibility) = child.visibility() {
2025-03-04 10:37:45 +00:00
child_visibility.set_visibility(gui_handler, false)?;
2023-01-16 09:53:52 +00:00
}
}
Ok(Some(child))
}
None => Ok(None),
}
}
/// Returns `true` if item got detached
2025-03-04 10:37:45 +00:00
pub fn detach_item(
&self,
2025-03-04 11:25:02 +00:00
gui_handler: &mut GuiHandler,
item: Arc<dyn GuiElementTraits>,
2025-03-04 10:37:45 +00:00
) -> Result<bool> {
2023-01-16 09:53:52 +00:00
let mut grid = self.children.write().unwrap();
let mut removed = false;
'outer: for column in grid.iter_mut() {
for child_opt in column.iter_mut() {
let mut remove = false;
if let Some((child, _x, _y)) = child_opt.get() {
// ugly workaround because Arc::ptr_eq does not work (7th, April 2020)
let item_ptr = Arc::into_raw(item.clone());
let child_ptr = Arc::into_raw(child.clone());
if std::ptr::eq(item_ptr, child_ptr) {
remove = true;
if self.visible() {
if let Some(child_visibility) = child.visibility() {
2025-03-04 10:37:45 +00:00
child_visibility.set_visibility(gui_handler, false)?;
2023-01-16 09:53:52 +00:00
}
}
}
unsafe {
Arc::from_raw(item_ptr);
Arc::from_raw(child_ptr);
}
}
if remove {
*child_opt = ChildState::None;
removed = true;
break 'outer;
}
}
}
Ok(removed)
}
2025-03-04 11:25:02 +00:00
pub fn set_position(&self, gui_handler: &mut GuiHandler, x: i32, y: i32) -> Result<()> {
2023-01-16 09:53:52 +00:00
// update own position
2025-03-04 10:37:45 +00:00
self.framable.change_position(gui_handler, x, y)?;
2023-01-16 09:53:52 +00:00
if let Some(background) = self.background.read().unwrap().as_ref() {
2025-03-04 10:37:45 +00:00
background.update_frame(gui_handler)?;
2023-01-16 09:53:52 +00:00
}
2025-03-04 10:37:45 +00:00
self.calculate_child_positions(gui_handler)?;
2023-01-16 09:53:52 +00:00
Ok(())
}
2025-03-04 11:25:02 +00:00
fn calculate_child_positions(&self, gui_handler: &mut GuiHandler) -> Result<()> {
2023-01-16 09:53:52 +00:00
// recalculate positions of the children
let children = self.children.read().unwrap();
for (x, row) in children.iter().enumerate() {
for (y, child_opt) in row.iter().enumerate() {
if let Some((child, dim_x, dim_y)) = child_opt.get_some() {
if let Some(child_gridable) = child.gridable() {
2025-03-04 10:37:45 +00:00
self.child_position(gui_handler, child_gridable, x, y, dim_x, dim_y)?;
2023-01-16 09:53:52 +00:00
}
}
}
}
Ok(())
}
pub fn position(&self) -> (i32, i32) {
(self.framable.left(), self.framable.top())
}
pub fn extents(&self) -> (u32, u32) {
let width = (self.framable.right() as i32 - self.framable.left()) as u32;
let height = (self.framable.bottom() as i32 - self.framable.top()) as u32;
(width, height)
}
2025-03-04 11:25:02 +00:00
pub fn disallow_position_scale(&self, gui_handler: &mut GuiHandler) -> Result<()> {
2025-03-04 10:37:45 +00:00
self.framable.allow_position_scale(gui_handler, false)
2023-01-16 09:53:52 +00:00
}
2025-03-04 11:25:02 +00:00
pub fn disallow_size_scale(&self, gui_handler: &mut GuiHandler) -> Result<()> {
2025-03-04 10:37:45 +00:00
self.framable.allow_size_scale(gui_handler, false)
2023-01-16 09:53:52 +00:00
}
2025-03-04 10:37:45 +00:00
pub fn connect(
2024-05-25 07:42:05 +00:00
&self,
direction: ConnectDirection,
2025-03-04 11:25:02 +00:00
elements: impl IntoIterator<Item = (usize, &Arc<Selectable>)>,
2024-05-25 07:42:05 +00:00
) -> Result<()> {
for (index, selectable) in elements {
match direction {
ConnectDirection::East => {
let y = index;
for x in (0..self.dim_x).rev() {
if let Some(child) = self.child_at(x, y)? {
if let Some(gridable) = child.gridable() {
if let Some(grid_selectable) = gridable.selectable() {
Selectable::connect_horizontally(grid_selectable, selectable);
break;
}
}
}
}
}
ConnectDirection::West => {
let y = index;
for x in 0..self.dim_x {
if let Some(child) = self.child_at(x, y)? {
if let Some(gridable) = child.gridable() {
if let Some(grid_selectable) = gridable.selectable() {
Selectable::connect_horizontally(selectable, grid_selectable);
break;
}
}
}
}
}
ConnectDirection::South => {
let x = index;
for y in (0..self.dim_y).rev() {
if let Some(child) = self.child_at(x, y)? {
if let Some(gridable) = child.gridable() {
if let Some(grid_selectable) = gridable.selectable() {
Selectable::connect_vertically(grid_selectable, selectable);
break;
}
}
}
}
}
ConnectDirection::North => {
let x = index;
for y in (0..self.dim_y).rev() {
if let Some(child) = self.child_at(x, y)? {
if let Some(gridable) = child.gridable() {
if let Some(grid_selectable) = gridable.selectable() {
Selectable::connect_vertically(grid_selectable, selectable);
break;
}
}
}
}
}
}
}
Ok(())
}
2023-01-16 09:53:52 +00:00
pub fn attach(
&self,
2025-03-04 11:25:02 +00:00
gui_handler: &mut GuiHandler,
child: Arc<dyn GuiElementTraits>,
2023-01-16 09:53:52 +00:00
pos_x: usize,
pos_y: usize,
dim_x: u32,
dim_y: u32,
) -> Result<()> {
if pos_x >= self.dim_x as usize {
panic!(
"x postion ({}) must not be bigger than grid x-dimension ({})",
pos_x, self.dim_x
);
}
if pos_y >= self.dim_y as usize {
panic!(
"y postion ({}) must not be bigger than grid y-dimension ({})",
pos_y, self.dim_y
);
}
assert_ne!(dim_x, 0);
assert_ne!(dim_y, 0);
// get grid
let mut grid = self.children.write().unwrap();
if let Some(child_gridable) = child.gridable() {
// check for neighbourships
if let Some(current_selectable) = child_gridable.selectable() {
Self::set_neighbours(
&*grid,
current_selectable,
(pos_x, pos_y),
(self.dim_x, self.dim_y),
)?;
}
if self.framable.is_framed() {
2025-03-04 10:37:45 +00:00
self.child_position(gui_handler, child_gridable, pos_x, pos_y, dim_x, dim_y)?;
2023-01-16 09:53:52 +00:00
}
child_gridable.set_layer(self.framable.ui_layer())?;
}
2024-04-22 07:48:32 +00:00
// disable the old element
match &grid[pos_x][pos_y] {
ChildState::Some { child, .. } => {
if self.visible() {
if let Some(child_visibility) = child.visibility() {
2025-03-04 10:37:45 +00:00
child_visibility.set_visibility(gui_handler, false)?;
2024-04-22 07:48:32 +00:00
}
}
}
ChildState::Extend { .. } => todo!(),
ChildState::None => (),
}
2023-01-16 09:53:52 +00:00
if self.visible() {
if let Some(child_visibility) = child.visibility() {
2025-03-04 10:37:45 +00:00
child_visibility.set_visibility(gui_handler, true)?;
2023-01-16 09:53:52 +00:00
}
}
let child_state = ChildState::Some {
child,
x: dim_x,
y: dim_y,
};
let weak = child_state.downgrade();
// insert the element
for x in pos_x..(pos_x + dim_x as usize) {
for y in pos_y..(pos_y + dim_y as usize) {
grid[x][y] = weak.clone();
}
}
grid[pos_x][pos_y] = child_state;
Ok(())
}
pub fn has_attachment_at(&self, x: usize, y: usize) -> Result<bool> {
let children = self.children.read().unwrap();
Ok(children[x][y].is_some())
}
pub fn try_from(
grid_info: &GridInfo,
2025-03-04 11:25:02 +00:00
gui_handler: &mut GuiHandler,
2023-01-16 09:53:52 +00:00
top_level: bool,
) -> Result<Arc<Self>> {
let grid = Grid::new(
2025-03-04 10:37:45 +00:00
gui_handler,
2023-01-16 09:53:52 +00:00
grid_info.x_dimension.get()?,
grid_info.y_dimension.get()?,
top_level,
)?;
grid.set_margin(grid_info.margin);
grid.set_padding(grid_info.padding);
if let Some(background) = &grid_info.background_type {
2025-03-04 10:37:45 +00:00
grid.set_background(gui_handler, background.clone())?;
2023-01-16 09:53:52 +00:00
}
Ok(grid)
}
2025-03-04 10:37:45 +00:00
pub fn change_position_unscaled(
&self,
2025-03-04 11:25:02 +00:00
gui_handler: &mut GuiHandler,
2025-03-04 10:37:45 +00:00
x: i32,
y: i32,
) -> Result<()> {
self.framable.change_position_unscaled(gui_handler, x, y)?;
2024-04-21 06:28:17 +00:00
if let Some(background) = self.background.read().unwrap().as_ref() {
2025-03-04 10:37:45 +00:00
background.update_frame(gui_handler)?;
2024-04-21 06:28:17 +00:00
}
2025-03-04 10:37:45 +00:00
self.calculate_child_positions(gui_handler)?;
2024-04-21 06:28:17 +00:00
Ok(())
}
2023-01-16 09:53:52 +00:00
fn child_position(
&self,
2025-03-04 11:25:02 +00:00
gui_handler: &mut GuiHandler,
child: &dyn Gridable,
2023-01-16 09:53:52 +00:00
pos_x: usize,
pos_y: usize,
dim_x: u32,
dim_y: u32,
) -> Result<()> {
// calculate the extents for the new child
let single_width = ((self.framable.right() as i32 - self.framable.left())
- (2 * self.padding.load(SeqCst) as i32
+ (self.dim_x as i32 - 1) * self.margin.load(SeqCst) as i32))
/ self.dim_x as i32;
let single_height = ((self.framable.bottom() as i32 - self.framable.top())
- (2 * self.padding.load(SeqCst) as i32
+ (self.dim_y as i32 - 1) * self.margin.load(SeqCst) as i32))
/ self.dim_y as i32;
let child_width = if dim_x == 1 {
single_width
} else {
single_width + (dim_x - 1) as i32 * (single_width + self.margin.load(SeqCst) as i32)
};
let child_height = if dim_y == 1 {
single_height
} else {
single_height + (dim_y - 1) as i32 * (single_height + self.margin.load(SeqCst) as i32)
};
2025-03-04 10:37:45 +00:00
let win_width = gui_handler.width();
let win_height = gui_handler.height();
2023-01-16 09:53:52 +00:00
let y_align = match self.framable.vertical_alignment() {
VerticalAlign::Top => 0,
VerticalAlign::Middle => win_height / 2,
VerticalAlign::Bottom => win_height,
VerticalAlign::NotSet => panic!("grid: vertical alignment is not set"),
};
let x_align = match self.framable.horizontal_alignment() {
HorizontalAlign::Left => 0,
HorizontalAlign::Middle => win_width / 2,
HorizontalAlign::Right => win_width,
HorizontalAlign::NotSet => panic!("grid: horizontal alignment is not set"),
};
let child_x = self.framable.left()
+ self.padding.load(SeqCst) as i32
+ pos_x as i32 * (single_width + self.margin.load(SeqCst) as i32);
let child_y = self.framable.top()
+ self.padding.load(SeqCst) as i32
+ pos_y as i32 * (single_height + self.margin.load(SeqCst) as i32);
child.set_frame(
2025-03-04 10:37:45 +00:00
gui_handler,
2023-01-16 09:53:52 +00:00
child_x - x_align as i32,
child_y - y_align as i32,
child_width as u32,
child_height as u32,
self.framable.vertical_alignment(),
self.framable.horizontal_alignment(),
)?;
Ok(())
}
2025-03-04 11:25:02 +00:00
pub fn select(&self, gui_handler: &mut GuiHandler, x: u32, y: u32) -> Result<()> {
2023-01-16 09:53:52 +00:00
match self.children.read().unwrap()[x as usize][y as usize].get_some() {
Some((child, ..)) => match child.gridable() {
Some(gridable) => match gridable.selectable() {
Some(selectable) => {
2025-03-04 10:37:45 +00:00
selectable.select(gui_handler)?;
2023-01-16 09:53:52 +00:00
Ok(())
}
None => panic!("gridable at position ({}, {}), is not selectable", x, y),
},
None => panic!("element at position ({}, {}) is not a gridable", x, y),
},
None => panic!("no element at position ({}, {})", x, y),
}
}
2025-03-04 11:25:02 +00:00
fn disable_tree(&self, gui_handler: &mut GuiHandler) -> Result<()> {
2025-03-04 10:37:45 +00:00
self.framable.delete(gui_handler)?;
2023-01-16 09:53:52 +00:00
if let Some(background) = self.background.read().unwrap().as_ref() {
2025-03-04 10:37:45 +00:00
background.disable(gui_handler)?;
2023-01-16 09:53:52 +00:00
}
2025-03-04 10:37:45 +00:00
self.set_tree_visibility(gui_handler, false)?;
2023-01-16 09:53:52 +00:00
Ok(())
}
2025-03-04 11:25:02 +00:00
fn set_tree_visibility(&self, gui_handler: &mut GuiHandler, visible: bool) -> Result<()> {
2023-01-16 09:53:52 +00:00
let tree = self.children.read().unwrap();
for row in tree.deref() {
for child_state in row {
if let Some((child, ..)) = child_state.get_some() {
if let Some(visibility) = child.visibility() {
2025-03-04 10:37:45 +00:00
visibility.set_visibility(gui_handler, visible)?;
2023-01-16 09:53:52 +00:00
}
}
}
}
Ok(())
}
#[inline]
fn set_neighbours(
2025-03-04 11:25:02 +00:00
grid: &Vec<Vec<ChildState>>,
current_child: &Arc<Selectable>,
2023-01-16 09:53:52 +00:00
pos: (usize, usize),
dim: (usize, usize),
) -> Result<()> {
// set east neighbour
Self::set_east_neighbour(grid, current_child, pos, dim)?;
// set west neighbour
Self::set_west_neighbour(grid, current_child, pos, dim)?;
// set north neighbour
Self::set_north_neighbour(grid, current_child, pos, dim)?;
// set south neighbour
Self::set_south_neighbour(grid, current_child, pos, dim)?;
Ok(())
}
#[inline]
fn set_north_neighbour(
2025-03-04 11:25:02 +00:00
grid: &Vec<Vec<ChildState>>,
current_child: &Arc<Selectable>,
2023-01-16 09:53:52 +00:00
pos: (usize, usize),
dim: (usize, usize),
) -> Result<bool> {
match Self::search_neighbour_in_direction(grid, pos, (0, 1), dim) {
2024-05-18 07:39:15 +00:00
Some(neighbour) => {
current_child.set_south_neighbour(Some(&neighbour));
neighbour.set_north_neighbour(Some(current_child));
2023-01-16 09:53:52 +00:00
Ok(true)
}
None => Ok(false),
}
}
#[inline]
fn set_south_neighbour(
2025-03-04 11:25:02 +00:00
grid: &Vec<Vec<ChildState>>,
current_child: &Arc<Selectable>,
2023-01-16 09:53:52 +00:00
pos: (usize, usize),
dim: (usize, usize),
) -> Result<bool> {
match Self::search_neighbour_in_direction(grid, pos, (0, -1), dim) {
2024-05-18 07:39:15 +00:00
Some(neighbour) => {
current_child.set_north_neighbour(Some(&neighbour));
neighbour.set_south_neighbour(Some(current_child));
2023-01-16 09:53:52 +00:00
Ok(true)
}
None => Ok(false),
}
}
#[inline]
fn set_east_neighbour(
2025-03-04 11:25:02 +00:00
grid: &Vec<Vec<ChildState>>,
current_child: &Arc<Selectable>,
2023-01-16 09:53:52 +00:00
pos: (usize, usize),
dim: (usize, usize),
) -> Result<bool> {
match Self::search_neighbour_in_direction(grid, pos, (1, 0), dim) {
2024-05-18 07:39:15 +00:00
Some(neighbour) => {
current_child.set_east_neighbour(Some(&neighbour));
neighbour.set_west_neighbour(Some(current_child));
2023-01-16 09:53:52 +00:00
Ok(true)
}
None => Ok(false),
}
}
#[inline]
fn set_west_neighbour(
2025-03-04 11:25:02 +00:00
grid: &Vec<Vec<ChildState>>,
current_child: &Arc<Selectable>,
2023-01-16 09:53:52 +00:00
pos: (usize, usize),
dim: (usize, usize),
) -> Result<bool> {
match Self::search_neighbour_in_direction(grid, pos, (-1, 0), dim) {
2024-05-18 07:39:15 +00:00
Some(neighbour) => {
current_child.set_west_neighbour(Some(&neighbour));
neighbour.set_east_neighbour(Some(current_child));
2023-01-16 09:53:52 +00:00
Ok(true)
}
None => Ok(false),
}
}
#[inline]
fn search_neighbour_in_direction(
2025-03-04 11:25:02 +00:00
grid: &Vec<Vec<ChildState>>,
2023-01-16 09:53:52 +00:00
pos: (usize, usize),
dir: (i32, i32),
dim: (usize, usize),
2025-03-04 11:25:02 +00:00
) -> Option<Arc<Selectable>> {
2023-01-16 09:53:52 +00:00
let (mut x, mut y) = pos;
let (x_step, y_step) = dir;
let (dim_x, dim_y) = dim;
while ((x as i32 + x_step) < dim_x as i32 && (x as i32 + x_step) >= 0)
&& ((y as i32 + y_step) < dim_y as i32 && (y as i32 + y_step) >= 0)
{
x = (x as i32 + x_step) as usize;
y = (y as i32 + y_step) as usize;
if let Some((neighbour, ..)) = grid[x][y].get() {
if let Some(gridable) = neighbour.gridable() {
if let Some(selectable) = gridable.selectable() {
return Some(selectable.clone());
}
}
}
}
None
}
}
2025-03-04 11:25:02 +00:00
impl GuiElementTraits for Grid {
fn gridable(&self) -> Option<&dyn Gridable> {
2023-01-16 09:53:52 +00:00
Some(self)
}
fn visibility(&self) -> Option<&dyn Visibility> {
Some(self)
}
2025-03-04 11:25:02 +00:00
fn downcast<'a>(&'a self) -> Option<GuiElement<'a>> {
2023-01-16 09:53:52 +00:00
Some(GuiElement::Grid(self))
}
}
2025-03-04 11:25:02 +00:00
impl Visibility for Grid {
2023-01-16 09:53:52 +00:00
fn visible(&self) -> bool {
self.visible.load(SeqCst)
}
2025-03-04 11:25:02 +00:00
fn set_visibility(&self, gui_handler: &mut GuiHandler, visibility: bool) -> Result<()> {
2023-01-16 09:53:52 +00:00
if visibility != self.visible.load(SeqCst) {
self.visible.store(visibility, SeqCst);
if visibility {
2025-03-04 10:37:45 +00:00
self.framable.add(gui_handler)?;
2023-01-16 09:53:52 +00:00
if let Some(background) = self.background.read().unwrap().as_ref() {
2025-03-04 10:37:45 +00:00
background.enable(gui_handler)?;
2023-01-16 09:53:52 +00:00
}
2025-03-04 10:37:45 +00:00
self.set_tree_visibility(gui_handler, true)?;
2023-01-16 09:53:52 +00:00
} else {
2025-03-04 10:37:45 +00:00
self.disable_tree(gui_handler)?;
2023-01-16 09:53:52 +00:00
}
}
Ok(())
}
}
2025-03-04 11:25:02 +00:00
impl Gridable for Grid {
2023-01-16 09:53:52 +00:00
fn set_frame(
&self,
2025-03-04 11:25:02 +00:00
gui_handler: &mut GuiHandler,
2023-01-16 09:53:52 +00:00
x: i32,
y: i32,
w: u32,
h: u32,
vert_align: VerticalAlign,
hori_align: HorizontalAlign,
) -> Result<()> {
2025-03-04 10:37:45 +00:00
self.framable
.set_frame(gui_handler, x, y, w, h, vert_align, hori_align);
2023-01-16 09:53:52 +00:00
if let Some(background) = self.background.read().unwrap().as_ref() {
2025-03-04 10:37:45 +00:00
background.update_frame(gui_handler)?;
2023-01-16 09:53:52 +00:00
}
2025-03-04 10:37:45 +00:00
self.calculate_child_positions(gui_handler)?;
2023-01-16 09:53:52 +00:00
Ok(())
}
2025-03-04 11:25:02 +00:00
fn selectable(&self) -> Option<&Arc<Selectable>> {
2023-01-16 09:53:52 +00:00
None
}
fn type_name(&self) -> &str {
"Grid"
}
fn set_layer(&self, layer: i32) -> Result<()> {
self.framable.set_ui_layer(layer);
if let Some(background) = self.background.read().unwrap().as_ref() {
background.set_ui_layer(layer);
}
for row in self.children.read().unwrap().iter() {
for child_state in row.iter() {
if let Some((child, ..)) = child_state.get_some() {
if let Some(gridable) = child.gridable() {
gridable.set_layer(layer)?;
}
}
}
}
Ok(())
}
2024-04-21 05:41:08 +00:00
fn position_extent(&self) -> (i32, i32, u32, u32) {
self.framable.position()
}
2023-01-16 09:53:52 +00:00
}