use crate::io::*;
use crate::util;
use log::warn;
use serde::{Serialize, Deserialize};
use std::net::SocketAddr;
pub type Index = u8;
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct Cluster {
local_screen: Index,
screens: Vec<Screen>,
focus: Focus,
selections: Vec<Index>,
}
#[derive(Clone, Copy, Serialize, Deserialize, Debug)]
pub struct Focus {
index: Index,
pos: Dimensions,
}
impl Cluster {
pub fn new(width: i32, height: i32, x: i32, y: i32) -> Self {
use std::fs::File;
let app_dir = util::user_app_dir("elemeld").unwrap();
let screens = match File::open(app_dir.join("screens.json")) {
Ok(file) => serde_json::from_reader(file).map_err(|err| {
warn!("Failed to parse screens.json: {}", err);
}).ok(),
Err(err) => {
warn!("Failed to open screens.json {}", err);
None
},
};
Self {
local_screen: 0,
screens: match screens {
Some(screens) => screens,
None => vec![Screen::new(width, height)],
},
focus: Focus {
index: 0,
pos: Dimensions { x, y },
},
selections: vec![0, 0],
}
}
pub fn process_host_output_event(&mut self, event: HostOutputEvent) -> Vec<InputEvent> {
match event {
HostOutputEvent::Motion(event) => {
if event.dx != 0 || event.dy != 0 {
let focus = Focus {
index: self.focus.index,
pos: Dimensions {
x: self.focus.pos.x + event.dx,
y: self.focus.pos.y + event.dy,
}
};
let mut events = vec![];
if let Some(grab) = self.refocus(focus) {
events.push(InputEvent::Host(HostInputEvent::Grab(grab)));
}
events.push(InputEvent::Net(NetEvent::Focus(focus)));
events
} else {
vec![]
}
},
HostOutputEvent::Selection(event) => {
println!("{:?}", event);
vec![]
},
event => {
if !self.locally_focused() {
match event {
HostOutputEvent::Button(event) => vec![InputEvent::Net(NetEvent::Button(event))],
HostOutputEvent::Key(event) => vec![InputEvent::Net(NetEvent::Key(event))],
_ => vec![],
}
} else {
vec![]
}
},
}
}
pub fn process_net_output_event(&mut self, event: NetEvent) -> Vec<InputEvent> {
if self.locally_focused() {
match event {
NetEvent::Button(event) => vec![InputEvent::Host(HostInputEvent::Button(event))],
NetEvent::Key(event) => vec![InputEvent::Host(HostInputEvent::Key(event))],
_ => vec![],
}
} else {
vec![]
}
}
pub fn focused_screen(&self) -> &Screen {
&self.screens[self.focus.index as usize]
}
fn locally_focused(&self) -> bool {
self.focus.index == self.local_screen
}
fn reset_local_screen(&mut self) {
for ip in util::get_host_ips().unwrap() {
for (i, screen) in self.screens.iter().enumerate() {
for addr in &screen.addrs {
if addr.ip() == ip {
self.local_screen = i as Index;
return;
}
}
}
}
panic!("Local IP was not found in cluster");
}
pub fn refocus(&mut self, focus: Focus) -> Option<GrabEvent> {
let was_focused = self.locally_focused();
self.focus = self.normalize_focus(focus);
let focused = self.locally_focused();
if focused != was_focused {
Some(GrabEvent { grab: focused })
} else {
None
}
}
fn normalize_focus(&self, focus: Focus) -> Focus {
self.normalize_y(self.normalize_x(focus))
}
fn normalize_x(&self, focus: Focus) -> Focus {
let screen = &self.screens[focus.index as usize];
if focus.pos.x <= 0 {
match screen.edges.left {
Some(index) => {
let new_screen = &self.screens[index as usize];
return self.normalize_x(Focus {
index,
pos: Dimensions {
x: focus.pos.x + new_screen.size.x - 2,
y: focus.pos.y * new_screen.size.y / screen.size.y,
}
})
},
None => if focus.pos.x < 0 {
return Focus {
index: focus.index,
pos: Dimensions {
x: 0,
y: focus.pos.y,
}
}
},
}
} else if focus.pos.x >= screen.size.x - 1 {
match screen.edges.right {
Some(index) => {
let new_screen = &self.screens[index as usize];
return self.normalize_x(Focus {
index,
pos: Dimensions {
x: focus.pos.x - screen.size.x + 2,
y: focus.pos.y * new_screen.size.y / screen.size.y,
}
})
},
None => if focus.pos.x > screen.size.x - 1 {
return Focus {
index: focus.index,
pos: Dimensions {
x: screen.size.x - 1,
y: focus.pos.y,
}
}
},
}
}
focus
}
fn normalize_y(&self, focus: Focus) -> Focus {
let screen = &self.screens[focus.index as usize];
if focus.pos.y <= 0 {
match screen.edges.top {
Some(index) => {
let new_screen = &self.screens[index as usize];
return self.normalize_y(Focus {
index,
pos: Dimensions {
x: focus.pos.x * new_screen.size.x / screen.size.x,
y: focus.pos.y + new_screen.size.y - 2,
}
})
},
None => if focus.pos.y < 0 {
return Focus {
index: focus.index,
pos: Dimensions {
x: focus.pos.x,
y: 0,
}
}
},
}
} else if focus.pos.y >= screen.size.y - 1 {
match screen.edges.bottom {
Some(index) => {
let new_screen = &self.screens[index as usize];
return self.normalize_y(Focus {
index,
pos: Dimensions {
x: focus.pos.x * new_screen.size.x / screen.size.x,
y: focus.pos.y - screen.size.y + 2,
}
})
},
None => if focus.pos.y > screen.size.y - 1 {
return Focus {
index: focus.index,
pos: Dimensions {
x: focus.pos.x,
y: screen.size.y - 1,
}
}
},
}
}
focus
}
fn add(&mut self, mut new_screen: Screen) {
let new_index = self.screens.len() as Index;
let mut index = 0 as Index;
loop {
let screen = &mut self.screens[index as usize];
index = match screen.edges.right {
Some(index) => index,
None => {
screen.edges.right = Some(new_index);
new_screen.edges.left = Some(index);
break;
}
}
}
self.screens.push(new_screen);
}
pub fn merge(&mut self, other: Self) {
'outer: for other_screen in other.screens {
for other_addr in &other_screen.addrs {
for screen in &self.screens {
for addr in &screen.addrs {
if addr.ip() == other_addr.ip() {
continue 'outer;
}
}
}
}
self.add(other_screen);
}
}
pub fn replace(&mut self, mut other: Self) -> Option<GrabEvent> {
other.reset_local_screen();
let event = other.refocus(other.focus);
*self = other;
event
}
pub fn get_screens(&self) -> &[Screen] {
&self.screens
}
pub fn set_screens(&mut self, screens: Vec<Screen>) {
self.screens = screens;
self.reset_local_screen();
}
}
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct Screen {
name: String,
size: Dimensions,
edges: Edges,
addrs: Vec<SocketAddr>,
}
impl Screen {
pub fn new(width: i32, height: i32) -> Self {
let port = 24242; Self {
name: util::get_host_name().unwrap(),
addrs: util::get_host_ips().unwrap()
.filter_map(|addr| {
if !addr.is_loopback() {
Some(SocketAddr::new(addr, port))
} else {
None
}
})
.collect(),
size: Dimensions { x: width, y: height },
edges: Edges {
top: None,
right: None,
bottom: None,
left: None
}
}
}
pub fn default_route(&self) -> &SocketAddr {
&self.addrs[0]
}
}
#[derive(Clone, Copy, Serialize, Deserialize, Debug)]
struct Dimensions {
x: i32,
y: i32,
}
#[derive(Clone, Copy, Serialize, Deserialize, Debug)]
struct Edges {
top: Option<Index>,
right: Option<Index>,
bottom: Option<Index>,
left: Option<Index>,
}