use std::collections::{BTreeMap, HashMap, VecDeque};
use std::fmt::Debug;
use hyprland::data::Client;
use hyprland::shared::WorkspaceId;
use crate::{MonitorData, MonitorId, WorkspaceData};
pub fn sort_clients<SC>(
clients: Vec<SC>,
ignore_workspaces: bool,
ignore_monitors: bool,
) -> Vec<SC>
where
SC: SortableClient + Debug,
{
let monitors: Vec<Vec<Vec<SC>>> = match (ignore_workspaces, ignore_monitors) {
(true, true) => {
panic!("Can't ignore workspaces and monitors at the same time (currently not implemented)");
}
(true, false) => {
let mut monitors: BTreeMap<MonitorId, Vec<SC>> = BTreeMap::new();
for client in clients {
monitors.entry(client.m()).or_default().push(client);
}
monitors.into_values().map(|m| vec![m]).collect()
}
(false, true) => {
let mut workspaces: BTreeMap<WorkspaceId, Vec<SC>> = BTreeMap::new();
for client in clients {
workspaces.entry(client.wsi(client.m())).or_default().push(client);
}
workspaces.into_values().map(|m| vec![m]).collect()
}
(false, false) => {
let mut monitors: BTreeMap<MonitorId, BTreeMap<WorkspaceId, Vec<SC>>> = BTreeMap::new();
for client in clients {
monitors.entry(client.m()).or_default().entry(client.ws()).or_default().push(client);
}
monitors.into_values().map(|m| m.into_values().collect()).collect()
}
};
let mut sorted_clients: Vec<SC> = vec![];
for ws in monitors {
for mut ws_clients in ws {
ws_clients.sort_by(|a, b| {
if a.y() != b.y() {
a.y().cmp(&b.y())
} else {
a.x().cmp(&b.x())
}
});
let mut clients_queue: VecDeque<SC> = VecDeque::from(ws_clients);
let mut first = clients_queue.pop_front();
while let Some(current) = first {
let rest = clients_queue
.iter()
.enumerate()
.filter(|c| c.1.y() >= current.y() + current.h())
.collect::<Vec<_>>();
let next = rest
.iter()
.filter(|c| {
for c2 in rest.iter() {
if c2.1.x() < c.1.x()
&& c2.1.y() + c2.1.h() > c.1.y()
&& c2.1.y() < c.1.y() + c.1.h()
{
return false;
}
}
true
})
.min_by(|a, b| a.1.y().cmp(&b.1.y()))
.map(|c| c.0);
let next_first = next.and_then(|next| clients_queue.remove(next));
let next_line_y = next_first
.as_ref()
.map(|c| c.y())
.unwrap_or_else(|| current.y() + current.h());
let top = current.y();
let mut left = current.x();
let mut bottom = current.y() + current.h();
sorted_clients.push(current);
while let Some(index) = get_next_index(left, top, bottom, next_line_y, clients_queue.iter())
{
let next = clients_queue
.remove(index)
.expect("Expected element not found?");
left = next.x();
bottom = bottom.max(next.y() + next.h());
sorted_clients.push(next);
}
first = next_first;
}
}
}
sorted_clients
}
fn get_next_index<'a, SC>(
left: u16,
top: u16,
bottom: u16,
top_next: u16,
ve: impl Iterator<Item=&'a SC>,
) -> Option<usize>
where
SC: SortableClient + Debug + 'a,
{
let mut current_x: Option<u16> = None;
let mut current_y: Option<u16> = None;
let mut index: Option<usize> = None;
for (i, v) in ve.enumerate() {
if left <= v.x()
&& top <= v.y()
&& v.y() <= bottom
&& v.y() < top_next
&& (current_x.is_none()
|| current_y.is_none()
|| v.x() < current_x.unwrap()
|| v.y() < current_y.unwrap())
{
current_x = Some(v.x());
current_y = Some(v.y());
index = Some(i);
}
}
index
}
pub fn update_clients<SC>(clients: Vec<SC>, workspace_data: &HashMap<WorkspaceId, WorkspaceData>, monitor_data: Option<&HashMap<MonitorId, MonitorData>>) -> Vec<SC>
where
SC: SortableClient + Debug,
{
clients.into_iter().map(|mut c| {
let ws = workspace_data
.get(&c.ws())
.unwrap_or_else(|| panic!("Workspace {:?} not found", c.ws()));
let (md_x, md_y) = if let Some(mdt) = monitor_data {
mdt.get(&c.m())
.map(|md| (md.x, md.y))
.unwrap_or_else(|| panic!("Monitor {:?} not found", c.m()))
} else {
(0, 0)
};
c.set_x(c.x() + ws.x - md_x); c.set_y(c.y() + ws.y - md_y); c
}).collect()
}
pub trait SortableClient {
fn x(&self) -> u16;
fn y(&self) -> u16;
fn w(&self) -> u16;
fn h(&self) -> u16;
fn ws(&self) -> WorkspaceId;
fn wsi(&self, monitor_index: MonitorId) -> i32;
fn m(&self) -> MonitorId;
fn set_x(&mut self, x: u16);
fn set_y(&mut self, y: u16);
fn identifier(&self) -> String;
}
pub const MONITOR_WORKSPACE_INDEX_OFFSET: i32 = 10;
impl SortableClient for Client {
fn x(&self) -> u16 {
self.at.0 as u16
}
fn y(&self) -> u16 {
self.at.1 as u16
}
fn w(&self) -> u16 {
self.size.0 as u16
}
fn h(&self) -> u16 {
self.size.1 as u16
}
fn ws(&self) -> WorkspaceId {
self.workspace.id
}
fn wsi(&self, monitor_index: MonitorId) -> i32 {
self.workspace.id - (MONITOR_WORKSPACE_INDEX_OFFSET * monitor_index as i32)
}
fn m(&self) -> MonitorId { self.monitor }
fn set_x(&mut self, x: u16) {
self.at.0 = x as i16;
}
fn set_y(&mut self, y: u16) {
self.at.1 = y as i16;
}
fn identifier(&self) -> String {
self.title.to_string()
}
}
#[allow(dead_code)]
fn pretty_print<T: Debug>(nested_vector: &[Vec<Vec<T>>]) {
for (i, inner_vector) in nested_vector.iter().enumerate() {
println!("Vector {}:", i);
for (j, second_inner_vector) in inner_vector.iter().enumerate() {
println!("\tInner Vector {}: ", j);
for (k, item) in second_inner_vector.iter().enumerate() {
println!("\t\tItem {}: {:?}", k, item);
}
}
}
}