use crate::{Receiver, 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::VecDeque;
use std::collections::hash_map::DefaultHasher;
use std::hash::Hash;
use std::iter::FusedIterator;
use std::marker::PhantomData;
use std::ops::{Deref, Index, IndexMut};
#[cfg(feature = "libadwaita")]
use gtk::prelude::Cast;
use gtk::prelude::IsA;
#[cfg(feature = "libadwaita")]
use std::hash::Hasher;
#[derive(Debug)]
#[must_use]
pub struct FactoryVecDequeGuard<'a, C>
where
C: FactoryComponent<Index = DynamicIndex>,
{
inner: &'a mut FactoryVecDeque<C>,
}
impl<C> Drop for FactoryVecDequeGuard<'_, C>
where
C: FactoryComponent<Index = DynamicIndex>,
{
fn drop(&mut self) {
self.inner.render_changes();
}
}
impl<'a, C> FactoryVecDequeGuard<'a, C>
where
C: FactoryComponent<Index = DynamicIndex>,
{
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
&& 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.output_sender.clone());
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);
}
component.extract();
}
self.inner.rendered_state.clear();
self.inner.uid_counter = 1;
}
pub fn iter_mut(
&mut self,
) -> impl DoubleEndedIterator<Item = &mut C> + ExactSizeIterator + FusedIterator {
self.inner
.components
.iter_mut()
.zip(self.inner.model_state.iter_mut())
.map(|(component, state)| {
state.changed = true;
component.get_mut()
})
}
}
impl<C> Deref for FactoryVecDequeGuard<'_, C>
where
C: FactoryComponent<Index = DynamicIndex>,
{
type Target = FactoryVecDeque<C>;
fn deref(&self) -> &Self::Target {
self.inner
}
}
impl<C> Index<usize> for FactoryVecDequeGuard<'_, C>
where
C: FactoryComponent<Index = DynamicIndex>,
{
type Output = C;
fn index(&self, index: usize) -> &Self::Output {
self.inner.index(index)
}
}
impl<C> IndexMut<usize> for FactoryVecDequeGuard<'_, C>
where
C: FactoryComponent<Index = DynamicIndex>,
{
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 FactoryVecDequeBuilder<C>
where
C: FactoryComponent<Index = DynamicIndex>,
{
_component: PhantomData<C>,
}
impl<C> Default for FactoryVecDequeBuilder<C>
where
C: FactoryComponent<Index = DynamicIndex>,
{
fn default() -> Self {
Self::new()
}
}
impl<C> FactoryVecDequeBuilder<C>
where
C: FactoryComponent<Index = DynamicIndex>,
C::ParentWidget: Default,
{
#[must_use]
pub fn launch_default(self) -> FactoryVecDequeConnector<C> {
self.launch(Default::default())
}
}
impl<C> FactoryVecDequeBuilder<C>
where
C: FactoryComponent<Index = DynamicIndex>,
{
#[must_use]
pub fn new() -> Self {
Self {
_component: PhantomData,
}
}
pub fn launch(self, widget: C::ParentWidget) -> FactoryVecDequeConnector<C> {
let (output_sender, output_receiver) = crate::channel();
FactoryVecDequeConnector {
widget,
output_sender,
output_receiver,
}
}
}
#[derive(Debug)]
pub struct FactoryVecDequeConnector<C>
where
C: FactoryComponent<Index = DynamicIndex>,
{
widget: C::ParentWidget,
output_sender: Sender<C::Output>,
output_receiver: Receiver<C::Output>,
}
impl<C> FactoryVecDequeConnector<C>
where
C: FactoryComponent<Index = DynamicIndex>,
{
pub fn forward<F, Msg>(self, sender_: &Sender<Msg>, f: F) -> FactoryVecDeque<C>
where
F: Fn(C::Output) -> Msg + Send + 'static,
C::Output: Send,
Msg: Send + 'static,
{
let Self {
widget,
output_sender,
output_receiver,
} = self;
let sender_clone = sender_.clone();
crate::spawn(async move {
while let Some(msg) = output_receiver.recv().await {
if sender_clone.send(f(msg)).is_err() {
break;
}
}
});
FactoryVecDeque {
widget,
output_sender,
components: VecDeque::new(),
model_state: VecDeque::new(),
rendered_state: VecDeque::new(),
uid_counter: 1,
}
}
pub fn detach(self) -> FactoryVecDeque<C> {
let Self {
widget,
output_sender,
..
} = self;
FactoryVecDeque {
widget,
output_sender,
components: VecDeque::new(),
model_state: VecDeque::new(),
rendered_state: VecDeque::new(),
uid_counter: 1,
}
}
}
#[derive(Debug)]
pub struct FactoryVecDeque<C>
where
C: FactoryComponent<Index = DynamicIndex>,
{
widget: C::ParentWidget,
output_sender: Sender<C::Output>,
components: VecDeque<ComponentStorage<C>>,
model_state: VecDeque<ModelStateValue>,
rendered_state: VecDeque<RenderedState>,
uid_counter: usize,
}
impl<C> Drop for FactoryVecDeque<C>
where
C: FactoryComponent<Index = DynamicIndex>,
{
fn drop(&mut self) {
self.guard().clear();
}
}
impl<C> Index<usize> for FactoryVecDeque<C>
where
C: FactoryComponent<Index = DynamicIndex>,
{
type Output = C;
fn index(&self, index: usize) -> &Self::Output {
self.get(index).expect("Called `get` on an invalid index")
}
}
impl<C> FactoryVecDeque<C>
where
C: FactoryComponent<Index = DynamicIndex>,
{
#[must_use]
pub fn builder() -> FactoryVecDequeBuilder<C> {
FactoryVecDequeBuilder::new()
}
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(), &state.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).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(), &self.model_state[index].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 broadcast(&self, msg: C::Input)
where
C::Input: Clone,
{
self.components.iter().for_each(|c| c.send(msg.clone()));
}
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 DoubleEndedIterator<Item = &C> + ExactSizeIterator + FusedIterator {
self.components.iter().map(ComponentStorage::get)
}
pub fn from_iter(
component_iter: impl IntoIterator<Item = C::Init>,
widget: C::ParentWidget,
) -> Self {
let mut output = Self::builder().launch(widget).detach();
{
let mut edit = output.guard();
for component in component_iter {
edit.push_back(component);
}
edit.drop();
}
output
}
pub fn extend(&mut self, component_iter: impl IntoIterator<Item = C::Init>) {
let mut edit = self.guard();
for component in component_iter {
edit.push_back(component);
}
}
}
impl<C> Clone for FactoryVecDeque<C>
where
C: CloneableFactoryComponent + FactoryComponent<Index = DynamicIndex>,
{
fn clone(&self) -> Self {
let mut clone = FactoryVecDeque::builder()
.launch(self.widget.clone())
.detach();
for item in self.iter() {
let init = C::get_init(item);
clone.guard().push_back(init);
}
clone
}
}
impl<C> FactoryVecDeque<C>
where
C: FactoryComponent<Index = DynamicIndex>,
C::ParentWidget: IsA<gtk::Stack>,
C::Root: IsA<gtk::Widget>,
{
pub fn set_visible(&self, index: usize) -> bool {
if let Some(handle) = self.components.get(index) {
self.widget
.as_ref()
.set_visible_child(handle.widget().as_ref());
true
} else {
false
}
}
}