tileme 0.0.3

(Not yet) A tiling window manager for Windows 10
//! An internal data structure and associated helpers for simplifying actions around
//! manipulating focusable ordered collections.

#![allow(dead_code)]

use std::{
    collections::VecDeque,
    fmt,
    ops::{Index, IndexMut},
};

/// A direction to permute a Ring
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Direction {
    /// increase the index, wrapping if needed
    Forward,
    /// decrease the index, wrapping if needed
    Backward,
}

impl Direction {
    /// Invert this Direction
    pub fn reverse(&self) -> Direction {
        match self {
            Direction::Forward => Direction::Backward,
            Direction::Backward => Direction::Forward,
        }
    }
}

/// Where a given element should be inserted into a Ring
#[derive(Debug, Copy, Clone)]
pub enum InsertPoint {
    /// At the specified index (last if out of bounds)
    Index(usize),
    /// In place of the current focused element (pushing focused and later down in the stack)
    Focused,
    /// After the current focused element (pushing later elements down in the stack)
    AfterFocused,
    /// As the first element in the stack
    First,
    /// As the last element in the stack
    Last,
}

/// Used with WindowManager helper functions to select an element from the
/// known workspaces or clients.
#[derive(Clone, Copy)]
pub enum Selector<'a, T> {
    /// The focused element of the target collection.
    Focused,
    /// The element at this index.
    Index(usize),
    /// The first element satisfying this condition.
    Condition(&'a dyn Fn(&T) -> bool),
}

impl<'a, T> fmt::Debug for Selector<'a, T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::Focused => f.debug_struct("Selector::Focused").finish(),
            Self::Index(i) => f.debug_struct("Selector::Index").field("index", i).finish(),
            Self::Condition(_func) => f
                .debug_struct("Selector::Condition")
                .field("condition", &stringify!(_func))
                .finish(),
        }
    }
}

/**

 * A Collection<T> that has both an order for its elements and a focused element
 * at some index.
 *
 * Supports rotating the position of the elements and rotating which element
 * is focused independently of one another.
 */
#[derive(Debug, Clone, PartialEq)]
pub(crate) struct Ring<T> {
    elements: VecDeque<T>,
    focused: usize,
}

impl<T> Ring<T> {
    pub fn new(elements: Vec<T>) -> Ring<T> {
        Ring {
            elements: elements.into(),
            focused: 0,
        }
    }

    pub fn would_wrap(&self, dir: Direction) -> bool {
        let wrap_back = self.focused == 0 && dir == Direction::Backward;
        let wrap_forward = self.focused == self.elements.len() - 1 && dir == Direction::Forward;

        wrap_back || wrap_forward
    }

    pub fn focused_index(&self) -> usize {
        self.focused
    }

    pub fn focused(&self) -> Option<&T> {
        self.elements.get(self.focused)
    }

    pub fn focused_mut(&mut self) -> Option<&mut T> {
        self.elements.get_mut(self.focused)
    }

    pub fn rotate(&mut self, direction: Direction) {
        if self.elements.is_empty() {
            return;
        }
        match direction {
            Direction::Forward => self.elements.rotate_right(1),
            Direction::Backward => self.elements.rotate_left(1),
        }
    }

    fn next_index(&self, direction: Direction) -> usize {
        let max = self.elements.len() - 1;
        match direction {
            Direction::Forward => {
                if self.focused == max {
                    0
                } else {
                    self.focused + 1
                }
            }
            Direction::Backward => {
                if self.focused == 0 {
                    max
                } else {
                    self.focused - 1
                }
            }
        }
    }

    pub fn cycle_focus(&mut self, direction: Direction) -> Option<&T> {
        self.focused = self.next_index(direction);
        self.focused()
    }

    pub fn drag_focused(&mut self, direction: Direction) -> Option<&T> {
        match (self.focused, self.next_index(direction), direction) {
            (0, _, Direction::Backward) => self.rotate(direction),
            (_, 0, Direction::Forward) => self.rotate(direction),
            (focused, other, _) => self.elements.swap(focused, other),
        }

        self.cycle_focus(direction)
    }

    pub fn len(&self) -> usize {
        self.elements.len()
    }

    pub fn insert_at(&mut self, insert_point: &InsertPoint, element: T) {
        match insert_point {
            InsertPoint::Index(ix) => self.elements.insert(*ix, element),
            InsertPoint::Focused => self.elements.insert(self.focused_index(), element),
            InsertPoint::First => self.elements.push_front(element),
            InsertPoint::Last => self.elements.push_back(element),
            InsertPoint::AfterFocused => {
                let ix = self.focused_index() + 1;
                if ix > self.elements.len() {
                    self.elements.push_back(element)
                } else {
                    self.elements.insert(ix, element)
                }
            }
        }
    }

    pub fn insert(&mut self, index: usize, element: T) {
        self.elements.insert(index, element);
    }

    pub fn push(&mut self, element: T) {
        self.elements.push_back(element);
    }

    pub fn iter(&self) -> std::collections::vec_deque::Iter<'_, T> {
        self.elements.iter()
    }

    pub fn iter_mut(&mut self) -> std::collections::vec_deque::IterMut<'_, T> {
        self.elements.iter_mut()
    }

    pub fn get(&self, index: usize) -> Option<&T> {
        self.elements.get(index)
    }

    pub fn get_mut(&mut self, index: usize) -> Option<&mut T> {
        self.elements.get_mut(index)
    }

    fn clamp_focus(&mut self) {
        if self.focused > 0 && self.focused >= self.elements.len() - 1 {
            self.focused -= 1;
        }
    }

    fn element_by(&self, cond: impl Fn(&T) -> bool) -> Option<(usize, &T)> {
        self.elements.iter().enumerate().find(|(_, e)| cond(*e))
    }

    fn element_by_mut(&mut self, cond: impl Fn(&T) -> bool) -> Option<(usize, &mut T)> {
        self.elements.iter_mut().enumerate().find(|(_, e)| cond(*e))
    }

    pub fn index(&self, s: &Selector<'_, T>) -> Option<usize> {
        match s {
            Selector::Focused => Some(self.focused_index()),
            Selector::Index(i) => {
                if *i < self.len() {
                    Some(*i)
                } else {
                    None
                }
            }
            Selector::Condition(f) => self.element_by(f).map(|(i, _)| i),
        }
    }

    pub fn element(&self, s: &Selector<'_, T>) -> Option<&T> {
        match s {
            Selector::Focused => self.focused(),
            Selector::Index(i) => self.elements.get(*i),
            Selector::Condition(f) => self.element_by(f).map(|(_, e)| e),
        }
    }

    pub fn element_mut(&mut self, s: &Selector<'_, T>) -> Option<&mut T> {
        match s {
            Selector::Focused => self.focused_mut(),
            Selector::Index(i) => self.elements.get_mut(*i),
            Selector::Condition(f) => self.element_by_mut(f).map(|(_, e)| e),
        }
    }

    pub fn all_elements(&self, s: &Selector<'_, T>) -> Vec<&T> {
        match s {
            Selector::Focused => self.focused().into_iter().collect(),
            Selector::Index(i) => self.elements.get(*i).into_iter().collect(),
            Selector::Condition(f) => self.elements.iter().filter(|e| f(*e)).collect(),
        }
    }

    pub fn all_elements_mut(&mut self, s: &Selector<'_, T>) -> Vec<&mut T> {
        match s {
            Selector::Focused => self.focused_mut().into_iter().collect(),
            Selector::Index(i) => self.elements.get_mut(*i).into_iter().collect(),
            Selector::Condition(f) => self.elements.iter_mut().filter(|e| f(*e)).collect(),
        }
    }

    pub fn focus(&mut self, s: &Selector<'_, T>) -> Option<&T> {
        match s {
            Selector::Focused => self.focused(),
            Selector::Index(i) => {
                self.focused = *i;
                self.focused()
            }
            Selector::Condition(f) => {
                if let Some((i, _)) = self.element_by(f) {
                    self.focused = i;
                    Some(&self.elements[self.focused])
                } else {
                    None
                }
            }
        }
    }

    pub fn remove(&mut self, s: &Selector<'_, T>) -> Option<T> {
        match s {
            Selector::Focused => {
                let c = self.elements.remove(self.focused);
                self.clamp_focus();
                c
            }
            Selector::Index(i) => {
                let c = self.elements.remove(*i);
                self.clamp_focus();
                c
            }
            Selector::Condition(f) => {
                if let Some((i, _)) = self.element_by(f) {
                    let c = self.elements.remove(i);
                    self.clamp_focus();
                    c
                } else {
                    None
                }
            }
        }
    }
}

impl<T: PartialEq> Ring<T> {
    pub fn equivalent_selectors(&self, s: &Selector<'_, T>, t: &Selector<'_, T>) -> bool {
        match (self.element(&s), self.element(&t)) {
            (Some(e), Some(f)) => e == f,
            _ => false,
        }
    }
}

impl<T: Clone> Ring<T> {
    #[allow(dead_code)]
    pub fn as_vec(&self) -> Vec<T> {
        self.iter().cloned().collect()
    }
}

impl<T> Index<usize> for Ring<T> {
    type Output = T;

    fn index(&self, index: usize) -> &Self::Output {
        &self.elements[index]
    }
}

impl<T> IndexMut<usize> for Ring<T> {
    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
        &mut self.elements[index]
    }
}