use crate::Sender;
use crate::factory::sync::builder::FactoryBuilder;
use crate::factory::sync::component_storage::ComponentStorage;
use crate::factory::sync::traits::CloneableFactoryComponent;
use crate::factory::{DynamicIndex, FactoryComponent, FactoryView};
use super::{ModelStateValue, RenderedState};
use std::collections::hash_map::DefaultHasher;
use std::collections::VecDeque;
use std::hash::Hash;
use std::iter::FusedIterator;
use std::ops::{Deref, Index, IndexMut};
#[cfg(feature = "libadwaita")]
use gtk::prelude::Cast;
#[cfg(feature = "libadwaita")]
use std::hash::Hasher;
#[derive(Debug)]
#[must_use]
pub struct FactoryVecDequeGuard<'a, C: FactoryComponent> {
inner: &'a mut FactoryVecDeque<C>,
}
impl<'a, C: FactoryComponent> Drop for FactoryVecDequeGuard<'a, C> {
fn drop(&mut self) {
self.inner.render_changes();
}
}
impl<'a, C: FactoryComponent> FactoryVecDequeGuard<'a, C> {
fn new(inner: &'a mut FactoryVecDeque<C>) -> Self {
#[allow(unused_mut)]
#[allow(clippy::let_and_return)]
let mut guard = FactoryVecDequeGuard { inner };
#[cfg(feature = "libadwaita")]
guard.apply_external_updates();
guard
}
pub fn drop(self) {
drop(self);
}
#[cfg(feature = "libadwaita")]
fn apply_external_updates(&mut self) {
if let Some(tab_view) = self.inner.widget().dynamic_cast_ref::<adw::TabView>() {
let length = tab_view.n_pages();
let mut hash_values: Vec<u64> = Vec::with_capacity(usize::try_from(length).unwrap());
for i in 0..length {
let page = tab_view.nth_page(i);
let mut hasher = DefaultHasher::default();
page.hash(&mut hasher);
hash_values.push(hasher.finish());
}
for (index, hash) in hash_values.iter().enumerate() {
if self
.inner
.rendered_state
.get(index)
.map(|state| state.widget_hash)
== Some(*hash)
{
let old_position = self
.inner
.rendered_state
.iter()
.position(|state| state.widget_hash == *hash)
.expect("A new widget was added");
let elem = self.inner.rendered_state.remove(old_position).unwrap();
self.inner.rendered_state.insert(index, elem);
self.move_to(old_position, index);
}
}
let mut index = 0;
while index < self.inner.rendered_state.len() {
let hash = self.inner.rendered_state[index].widget_hash;
if hash_values.contains(&hash) {
index += 1;
} else {
self.inner.rendered_state.remove(index);
self.remove(index);
}
}
}
}
pub fn get_mut(&mut self, index: usize) -> Option<&mut C> {
if let Some(state) = self.inner.model_state.get_mut(index) {
state.changed = true;
}
self.inner
.components
.get_mut(index)
.map(ComponentStorage::get_mut)
}
pub fn back_mut(&mut self) -> Option<&mut C> {
self.get_mut(self.len().wrapping_sub(1))
}
pub fn front_mut(&mut self) -> Option<&mut C> {
self.get_mut(0)
}
pub fn pop_back(&mut self) -> Option<C> {
if self.is_empty() {
None
} else {
self.remove(self.len() - 1)
}
}
pub fn pop_front(&mut self) -> Option<C> {
self.remove(0)
}
pub fn remove(&mut self, index: usize) -> Option<C> {
self.inner.model_state.remove(index);
let component = self.inner.components.remove(index);
for states in self.inner.model_state.iter_mut().skip(index) {
states.index.decrement();
}
if let Some(comp) = &component {
if let Some(widget) = &comp.returned_widget() {
self.widget.factory_remove(widget);
}
}
component.map(ComponentStorage::extract)
}
pub fn push_back(&mut self, init: C::Init) -> DynamicIndex {
let index = self.len();
self.insert(index, init)
}
pub fn push_front(&mut self, init: C::Init) -> DynamicIndex {
self.insert(0, init)
}
pub fn insert(&mut self, index: usize, init: C::Init) -> DynamicIndex {
let dyn_index = DynamicIndex::new(index);
for states in self.inner.model_state.iter_mut().skip(index) {
states.index.increment();
}
let builder = FactoryBuilder::new(&dyn_index, init);
self.inner
.components
.insert(index, ComponentStorage::Builder(builder));
self.inner.model_state.insert(
index,
ModelStateValue {
index: dyn_index.clone(),
uid: self.uid_counter,
changed: false,
},
);
self.inner.uid_counter += 1;
dyn_index
}
pub fn swap(&mut self, first: usize, second: usize) {
if first != second {
self.inner.model_state.swap(first, second);
self.inner.components.swap(first, second);
self.model_state[first].index.set_value(first);
self.model_state[second].index.set_value(second);
}
}
pub fn move_to(&mut self, current_position: usize, target: usize) {
if current_position != target {
let elem = self.inner.model_state.remove(current_position).unwrap();
elem.index.set_value(target);
self.inner.model_state.insert(target, elem);
let comp = self.inner.components.remove(current_position).unwrap();
self.inner.components.insert(target, comp);
if current_position > target {
for state in self
.inner
.model_state
.iter_mut()
.skip(target + 1)
.take(current_position - target)
{
state.index.increment();
}
} else {
for state in self
.inner
.model_state
.iter_mut()
.skip(current_position)
.take(target - current_position)
{
state.index.decrement();
}
}
}
}
pub fn move_front(&mut self, current_position: usize) {
self.move_to(current_position, 0);
}
pub fn move_back(&mut self, current_position: usize) {
self.move_to(current_position, self.len() - 1);
}
pub fn clear(&mut self) {
self.inner.model_state.clear();
for component in self.inner.components.drain(..) {
if let Some(widget) = component.returned_widget() {
self.inner.widget.factory_remove(widget);
}
}
}
pub fn iter_mut(
&mut self,
) -> impl Iterator<Item = &mut C> + DoubleEndedIterator + ExactSizeIterator + FusedIterator
{
self.inner
.components
.iter_mut()
.zip(self.inner.model_state.iter_mut())
.map(|(component, state)| {
state.changed = true;
component.get_mut()
})
}
}
impl<'a, C: FactoryComponent> Deref for FactoryVecDequeGuard<'a, C> {
type Target = FactoryVecDeque<C>;
fn deref(&self) -> &Self::Target {
self.inner
}
}
impl<'a, C: FactoryComponent> Index<usize> for FactoryVecDequeGuard<'a, C> {
type Output = C;
fn index(&self, index: usize) -> &Self::Output {
self.inner.index(index)
}
}
impl<'a, C: FactoryComponent> IndexMut<usize> for FactoryVecDequeGuard<'a, C> {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
self.get_mut(index)
.expect("Called `get_mut` on an invalid index")
}
}
#[derive(Debug)]
pub struct FactoryVecDeque<C: FactoryComponent> {
widget: C::ParentWidget,
parent_sender: Sender<C::ParentInput>,
components: VecDeque<ComponentStorage<C>>,
model_state: VecDeque<ModelStateValue>,
rendered_state: VecDeque<RenderedState>,
uid_counter: u16,
}
impl<C: FactoryComponent> Drop for FactoryVecDeque<C> {
fn drop(&mut self) {
for component in &mut self.components {
if let Some(widget) = component.returned_widget() {
self.widget.factory_remove(widget);
}
}
}
}
impl<C: FactoryComponent> Index<usize> for FactoryVecDeque<C> {
type Output = C;
fn index(&self, index: usize) -> &Self::Output {
self.get(index).expect("Called `get` on an invalid index")
}
}
impl<C: FactoryComponent> FactoryVecDeque<C> {
#[must_use]
pub fn new(widget: C::ParentWidget, parent_sender: &Sender<C::ParentInput>) -> Self {
Self {
widget,
parent_sender: parent_sender.clone(),
components: VecDeque::new(),
model_state: VecDeque::new(),
rendered_state: VecDeque::new(),
uid_counter: 1,
}
}
pub fn guard(&mut self) -> FactoryVecDequeGuard<'_, C> {
FactoryVecDequeGuard::new(self)
}
fn render_changes(&mut self) {
let mut first_position_change_idx = None;
let components = &mut self.components;
let rendered_state = &mut self.rendered_state;
for (index, state) in self.model_state.iter().enumerate() {
if state.uid == rendered_state.front().map(|r| r.uid).unwrap_or_default() {
rendered_state.pop_front();
if state.changed {
components[index].state_change_notify();
}
} else if let Some(rendered_index) =
rendered_state.iter().position(|r| r.uid == state.uid)
{
if first_position_change_idx.is_none() {
first_position_change_idx = Some(index);
}
rendered_state.remove(rendered_index);
let widget = components[index].returned_widget().unwrap();
if index == 0 {
self.widget.factory_move_start(widget);
} else {
let previous_widget = components[index - 1].returned_widget().unwrap();
self.widget.factory_move_after(widget, previous_widget);
}
if state.changed {
components[index].state_change_notify();
}
} else {
if first_position_change_idx.is_none() {
first_position_change_idx = Some(index);
}
let comp = &components[index];
let insert_widget = comp.widget();
let position = C::position(comp.get(), index);
let returned_widget = if index == 0 {
self.widget.factory_prepend(insert_widget, &position)
} else {
let previous_widget = components[index - 1].returned_widget().unwrap();
self.widget
.factory_insert_after(insert_widget, &position, previous_widget)
};
let component = components.remove(index).unwrap();
let dyn_index = &self.model_state[index].index;
let component = component
.launch(dyn_index, returned_widget, &self.parent_sender)
.unwrap();
components.insert(index, component);
}
}
self.model_state.iter_mut().for_each(|s| s.changed = false);
self.rendered_state = self
.model_state
.iter()
.zip(components.iter())
.map(|(s, c)| {
let mut hasher = DefaultHasher::default();
c.returned_widget().unwrap().hash(&mut hasher);
RenderedState {
uid: s.uid,
#[cfg(feature = "libadwaita")]
widget_hash: hasher.finish(),
}
})
.collect();
if let Some(change_index) = first_position_change_idx {
for (index, comp) in components.iter().enumerate().skip(change_index) {
let position = C::position(comp.get(), index);
self.widget
.factory_update_position(comp.returned_widget().unwrap(), &position);
}
}
}
pub fn len(&self) -> usize {
self.components.len()
}
pub fn is_empty(&self) -> bool {
self.components.is_empty()
}
pub fn send(&self, index: usize, msg: C::Input) {
self.components[index].send(msg);
}
pub fn get(&self, index: usize) -> Option<&C> {
self.components.get(index).map(ComponentStorage::get)
}
pub fn back(&self) -> Option<&C> {
self.get(self.len().wrapping_sub(1))
}
pub fn front(&self) -> Option<&C> {
self.get(0)
}
pub const fn widget(&self) -> &C::ParentWidget {
&self.widget
}
pub fn iter(
&self,
) -> impl Iterator<Item = &C> + DoubleEndedIterator + ExactSizeIterator + FusedIterator {
self.components.iter().map(ComponentStorage::get)
}
pub fn from_vec(
component_vec: Vec<C::Init>,
widget: C::ParentWidget,
parent_sender: &Sender<C::ParentInput>,
) -> Self {
let mut output = Self::new(widget, parent_sender);
{
let mut edit = output.guard();
for component in component_vec {
edit.push_back(component);
}
edit.drop();
}
output
}
}
impl<C: FactoryComponent> Clone for FactoryVecDeque<C>
where
C: CloneableFactoryComponent,
{
fn clone(&self) -> Self {
let mut clone = FactoryVecDeque::new(self.widget.clone(), &self.parent_sender.clone());
for item in self.iter() {
let init = C::get_init(item);
clone.guard().push_back(init);
}
clone
}
}