aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormetamuffin <yvchraiqi@protonmail.com>2022-08-16 18:06:43 +0200
committermetamuffin <yvchraiqi@protonmail.com>2022-08-16 18:06:43 +0200
commit32bfbe158ab695c9258c13e6f32a619b780d8930 (patch)
treedcb09c291f31250e0a2ada3f09230fa47cb817b7
parent9a306095aa701f372242f3dcbb76a09b4694762d (diff)
downloadkarlender-32bfbe158ab695c9258c13e6f32a619b780d8930.tar
karlender-32bfbe158ab695c9258c13e6f32a619b780d8930.tar.bz2
karlender-32bfbe158ab695c9258c13e6f32a619b780d8930.tar.zst
stuff
-rw-r--r--karld/src/interface.rs4
-rw-r--r--karld/src/main.rs2
-rw-r--r--karlgui/src/client.rs14
-rw-r--r--karlgui/src/edit.rs233
-rw-r--r--karlgui/src/main.rs199
5 files changed, 267 insertions, 185 deletions
diff --git a/karld/src/interface.rs b/karld/src/interface.rs
index 750f307..f283733 100644
--- a/karld/src/interface.rs
+++ b/karld/src/interface.rs
@@ -7,6 +7,10 @@ use std::os::unix::net::{UnixListener, UnixStream};
use std::thread;
pub fn network_loop() {
+ if std::fs::try_exists(socket_path()).unwrap() {
+ info!("delete old socket");
+ std::fs::remove_file(socket_path()).unwrap();
+ }
let listener = UnixListener::bind(socket_path()).unwrap();
info!("listening.");
let mut id_counter = 0;
diff --git a/karld/src/main.rs b/karld/src/main.rs
index 414b1e6..10130d7 100644
--- a/karld/src/main.rs
+++ b/karld/src/main.rs
@@ -1,4 +1,5 @@
#![feature(box_syntax)]
+#![feature(fs_try_exists)]
pub mod condition;
pub mod helper;
@@ -126,6 +127,7 @@ lazy_static::lazy_static! {
}
pub fn handle_packet(client: u32, packet: ServerboundPacket, responder: Sender<ClientboundPacket>) {
+ std::thread::sleep(std::time::Duration::from_millis(75));
match packet {
ServerboundPacket::Sync => {
let _ = responder.send(ClientboundPacket::Sync);
diff --git a/karlgui/src/client.rs b/karlgui/src/client.rs
index 9f2dfc7..b027cdc 100644
--- a/karlgui/src/client.rs
+++ b/karlgui/src/client.rs
@@ -9,6 +9,7 @@ use std::{
pub struct Client {
socket: UnixStream,
+ pub busy: bool,
pub receiver: Receiver<ClientboundPacket>,
}
@@ -27,10 +28,15 @@ impl Client {
sender.send(p).unwrap();
}
});
- let mut c = Self { receiver, socket };
+ let mut c = Self {
+ receiver,
+ socket,
+ busy: true,
+ };
c.send(ServerboundPacket::Handshake {
version: version!(),
});
+ c.send(ServerboundPacket::Sync);
return c;
}
@@ -40,4 +46,10 @@ impl Client {
.write_fmt(format_args!("{}\n", serde_json::to_string(&p).unwrap()))
.unwrap()
}
+
+ pub fn send_sync(&mut self, p: ServerboundPacket) {
+ self.busy = true;
+ self.send(p);
+ self.send(ServerboundPacket::Sync);
+ }
}
diff --git a/karlgui/src/edit.rs b/karlgui/src/edit.rs
new file mode 100644
index 0000000..d2f7150
--- /dev/null
+++ b/karlgui/src/edit.rs
@@ -0,0 +1,233 @@
+use std::ops::Range;
+
+use egui::{Color32, DragValue, RichText, Ui};
+use karlcommon::{Condition, Property, Schedule, Task};
+
+pub struct ShowOrEdit<T> {
+ pub inner: T,
+ pub edit: bool,
+}
+
+impl<T: EditableWidget> ShowOrEdit<T> {
+ pub fn new(inner: T, edit: bool) -> ShowOrEdit<T> {
+ Self { inner, edit }
+ }
+ pub fn changed(&mut self, ui: &mut Ui) -> bool {
+ let changed = match self.edit {
+ true => {
+ if ui.button("💾 Save").clicked() {
+ self.edit = false;
+ true
+ } else {
+ false
+ }
+ }
+ false => {
+ if ui.button("✏ Edit").clicked() {
+ self.edit = true;
+ }
+ false
+ }
+ };
+ self.inner.ui(ui, self.edit);
+ changed
+ }
+}
+
+pub trait EditableWidget {
+ fn ui(&mut self, ui: &mut Ui, edit: bool);
+}
+
+impl EditableWidget for Task {
+ fn ui(&mut self, ui: &mut Ui, edit: bool) {
+ ui.heading(&self.name);
+ ui.indent((), |ui| {
+ if let Some(d) = &mut self.description {
+ if edit {
+ ui.text_edit_singleline(d);
+ } else {
+ ui.label(&*d);
+ }
+ }
+ ui.horizontal(|ui| {
+ ui.label("Tags:");
+ for t in &self.tags {
+ ui.colored_label(Color32::LIGHT_GREEN, t);
+ }
+ });
+ self.schedule.ui(ui, edit);
+ });
+ }
+}
+
+impl EditableWidget for Schedule {
+ fn ui(&mut self, ui: &mut Ui, edit: bool) {
+ match self {
+ Schedule::Never => {
+ ui.label("No schedule");
+ }
+ Schedule::Dynamic {
+ priority,
+ scheduled,
+ duration,
+ condition,
+ } => {
+ ui.horizontal(|ui| {
+ ui.label("Dynamic with priority");
+ ui.label(&format!(" {} ", priority));
+ });
+ }
+ Schedule::Condition(c) => c.ui(ui, edit),
+ Schedule::Static(t) => t.ui(ui, edit),
+ }
+ }
+}
+
+impl EditableWidget for Condition {
+ fn ui(&mut self, ui: &mut Ui, edit: bool) {
+ ui.group(|ui| match self {
+ Condition::Never => {
+ ui.label("never");
+ }
+ Condition::From(c) => {
+ ui.horizontal(|ui| {
+ ui.label("Starting from");
+ c.ui(ui, edit);
+ if edit {
+ ui.menu_button("✏ Change type", |ui| {
+ add_condition(ui, |d| *c = Box::new(d))
+ });
+ }
+ });
+ }
+ Condition::Invert(c) => {
+ ui.horizontal(|ui| {
+ ui.label("not when");
+ c.ui(ui, edit);
+ if edit {
+ ui.menu_button("✏ Change type", |ui| {
+ add_condition(ui, |d| *c = Box::new(d))
+ });
+ }
+ });
+ }
+ Condition::Or(cs) => combine_condition(ui, edit, "or", cs),
+ Condition::And(cs) => combine_condition(ui, edit, "and", cs),
+ Condition::Equal {
+ prop,
+ value,
+ modulus: _,
+ } => {
+ ui.horizontal(|ui| {
+ ui.label("when");
+ if edit {
+ egui::ComboBox::from_id_source(ui.id())
+ .selected_text(prop.to_str())
+ .show_ui(ui, |ui| {
+ for v in Property::VALUES {
+ ui.selectable_value(prop, *v, v.to_str());
+ }
+ });
+ } else {
+ ui.label(prop.to_str());
+ }
+ ui.label("=");
+ if edit {
+ ui.add(DragValue::new(value));
+ } else {
+ ui.label(&format!("{}", value));
+ }
+ });
+ }
+ Condition::Range {
+ prop,
+ min,
+ max,
+ modulus: _,
+ } => {
+ ui.horizontal(|ui| {
+ ui.label("when ");
+ ui.label(&format!("{}", min));
+ ui.label("≤");
+ ui.label(&format!("{:?}", prop));
+ ui.label("<");
+ ui.label(&format!("{}", max))
+ });
+ }
+ });
+ }
+}
+
+impl EditableWidget for Range<i64> {
+ fn ui(&mut self, ui: &mut Ui, edit: bool) {
+ ui.label("todo");
+ }
+}
+
+fn combine_condition(ui: &mut Ui, edit: bool, combinator: &str, cs: &mut Vec<Condition>) {
+ ui.vertical(|ui| {
+ let mut remove = None;
+ for (i, c) in cs.iter_mut().enumerate() {
+ ui.push_id(i, |ui| {
+ ui.horizontal(|ui| {
+ ui.label(if i != 0 { combinator } else { "" });
+ c.ui(ui, edit);
+ if edit {
+ if ui.button(RichText::from("🗑").color(Color32::RED)).clicked() {
+ remove = Some(i);
+ }
+ }
+ });
+ });
+ }
+ if edit {
+ ui.menu_button("➕ Add condition", |ui| {
+ add_condition(ui, |e| {
+ cs.push(e);
+ })
+ });
+ }
+ if let Some(remove) = remove {
+ cs.remove(remove);
+ }
+ });
+}
+
+fn add_condition(ui: &mut Ui, mut add: impl FnMut(Condition) -> ()) {
+ ui.menu_button("Combinators", |ui| {
+ if ui.button("And").clicked() {
+ add(Condition::And(vec![]))
+ }
+ if ui.button("Or").clicked() {
+ add(Condition::Or(vec![]))
+ }
+ });
+ ui.menu_button("Constraints", |ui| {
+ if ui.button("Equal").clicked() {
+ add(Condition::Equal {
+ modulus: None,
+ prop: Property::Unix,
+ value: 0,
+ })
+ }
+ if ui.button("Range").clicked() {
+ add(Condition::Range {
+ prop: Property::Unix,
+ min: 0,
+ max: 10,
+ modulus: None,
+ })
+ }
+ if ui.button("Never").clicked() {
+ add(Condition::Never)
+ }
+ });
+ ui.menu_button("Modifier", |ui| {
+ if ui.button("Invert").clicked() {
+ add(Condition::Invert(Box::new(Condition::Never)))
+ }
+ if ui.button("Starting from").clicked() {
+ add(Condition::From(Box::new(Condition::Never)))
+ }
+ });
+}
diff --git a/karlgui/src/main.rs b/karlgui/src/main.rs
index b92d95b..3832044 100644
--- a/karlgui/src/main.rs
+++ b/karlgui/src/main.rs
@@ -1,17 +1,13 @@
pub mod client;
+pub mod edit;
use crate::client::Client;
+use edit::ShowOrEdit;
use eframe::CreationContext;
-use egui::{text::LayoutJob, CentralPanel, Color32, DragValue, Response, TextFormat, Ui, Widget};
-use karlcommon::{
- socket_path, ClientboundPacket, Condition, Property, Schedule, ServerboundPacket, Task,
-};
+use egui::CentralPanel;
+use karlcommon::{socket_path, ClientboundPacket, ServerboundPacket, Task};
use log::{error, info};
-use std::{
- ops::{Deref, DerefMut, Range},
- os::unix::net::UnixStream,
- process::exit,
-};
+use std::{os::unix::net::UnixStream, process::exit};
fn main() {
env_logger::init();
@@ -55,6 +51,9 @@ impl App {
ClientboundPacket::TaskList(t) => {
self.tasks = t.into_iter().map(|t| ShowOrEdit::new(t, false)).collect()
}
+ ClientboundPacket::Sync => {
+ self.client.busy = false;
+ }
_ => {}
}
}
@@ -65,183 +64,15 @@ impl eframe::App for App {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
self.update_network();
CentralPanel::default().show(ctx, |ui| {
- for t in &mut self.tasks {
- t.ui(ui);
- ui.separator();
- }
- });
- }
-}
-
-struct ShowOrEdit<T> {
- pub inner: T,
- pub edit: bool,
-}
-
-impl<T: EditableWidget> ShowOrEdit<T> {
- pub fn new(inner: T, edit: bool) -> ShowOrEdit<T> {
- Self { inner, edit }
- }
- pub fn ui(&mut self, ui: &mut Ui) {
- match self.edit {
- true => {
- if ui.button("💾 Save").clicked() {
- self.edit = false;
- }
- }
- false => {
- if ui.button("✏ Edit").clicked() {
- self.edit = true;
- }
- }
- }
- self.inner.ui(ui, self.edit);
- }
-}
-
-trait EditableWidget {
- fn ui(&mut self, ui: &mut Ui, edit: bool);
-}
-
-impl EditableWidget for Task {
- fn ui(&mut self, ui: &mut Ui, edit: bool) {
- ui.heading(&self.name);
- ui.indent((), |ui| {
- if let Some(d) = &self.description {
- ui.label(d);
- }
- ui.horizontal(|ui| {
- ui.label("Tags:");
- for t in &self.tags {
- ui.colored_label(Color32::LIGHT_GREEN, t);
+ ui.add_enabled_ui(!self.client.busy, |ui| {
+ for t in &mut self.tasks {
+ if t.changed(ui) {
+ self.client
+ .send_sync(ServerboundPacket::UpdateTask(t.inner.clone()))
+ }
+ ui.separator();
}
});
- self.schedule.ui(ui, edit);
});
}
}
-
-impl EditableWidget for Schedule {
- fn ui(&mut self, ui: &mut Ui, edit: bool) {
- match self {
- Schedule::Never => {
- let mut j = LayoutJob::default();
- j.append(
- "No schedule",
- 0.0,
- TextFormat {
- italics: true,
- ..Default::default()
- },
- );
- ui.label(j);
- }
- Schedule::Dynamic {
- priority,
- scheduled,
- duration,
- condition,
- } => {
- ui.horizontal(|ui| {
- ui.label("Dynamic with priority");
- ui.label(&format!(" {} ", priority));
- });
- }
- Schedule::Condition(c) => c.ui(ui, edit),
- Schedule::Static(t) => t.ui(ui, edit),
- }
- }
-}
-
-impl EditableWidget for Condition {
- fn ui(&mut self, ui: &mut Ui, edit: bool) {
- ui.group(|ui| match self {
- Condition::Never => {
- ui.label("never");
- }
- Condition::From(c) => {
- ui.horizontal(|ui| {
- ui.label("Starting from");
- c.ui(ui, edit);
- });
- }
- Condition::Or(cs) => {
- ui.vertical(|ui| {
- for (i, c) in cs.iter_mut().enumerate() {
- ui.push_id(i, |ui| {
- ui.horizontal(|ui| {
- ui.label(if i != 0 { "or " } else { " " });
- c.ui(ui, edit);
- });
- });
- }
- });
- }
- Condition::And(cs) => {
- ui.vertical(|ui| {
- for (i, c) in cs.iter_mut().enumerate() {
- ui.push_id(i, |ui| {
- ui.horizontal(|ui| {
- ui.label(if i != 0 { "and" } else { "" });
- c.ui(ui, edit);
- });
- });
- }
- });
- }
- Condition::Invert(c) => {
- ui.horizontal(|ui| {
- ui.label("not when");
- c.ui(ui, edit);
- });
- }
- Condition::Equal {
- prop,
- value,
- modulus,
- } => {
- ui.horizontal(|ui| {
- ui.label("when");
- if edit {
- egui::ComboBox::from_id_source(ui.id())
- .selected_text(prop.to_str())
- .show_ui(ui, |ui| {
- for v in Property::VALUES {
- ui.selectable_value(prop, *v, v.to_str());
- }
- });
- } else {
- ui.label(&format!("{:?}", prop));
- }
- ui.label("=");
- if edit {
- ui.add(DragValue::new(value));
- } else {
- ui.label(&format!("{}", value));
- }
- });
- }
- Condition::Range {
- prop,
- min,
- max,
- modulus,
- } => {
- ui.horizontal(|ui| {
- ui.label("when ");
- ui.label(&format!("{}", min));
- ui.label("≤");
- ui.label(&format!("{:?}", prop));
- ui.label("<");
- ui.label(&format!("{}", max))
- });
- }
- });
- }
-}
-
-impl EditableWidget for Range<i64> {
- fn ui(&mut self, ui: &mut Ui, edit: bool) {
- ui.label("todo");
- }
-}