]> git.proxmox.com Git - pve-installer.git/commitdiff
tui: add `NumericEditView` and `DiskSizeInputView` components
authorChristoph Heiss <c.heiss@proxmox.com>
Tue, 30 May 2023 09:35:52 +0000 (11:35 +0200)
committerChristoph Heiss <c.heiss@proxmox.com>
Wed, 14 Jun 2023 08:39:56 +0000 (10:39 +0200)
Signed-off-by: Christoph Heiss <c.heiss@proxmox.com>
proxmox-tui-installer/src/main.rs
proxmox-tui-installer/src/views.rs [new file with mode: 0644]

index 26baef9ff68fe9c019875ab9a5a3491e46c0d121..f9104e7fe71ad7eb14ae5ba28abba49048c2a874 100644 (file)
@@ -1,5 +1,7 @@
 #![forbid(unsafe_code)]
 
+mod views;
+
 use cursive::{
     event::Event,
     view::{Resizable, ViewWrapper},
diff --git a/proxmox-tui-installer/src/views.rs b/proxmox-tui-installer/src/views.rs
new file mode 100644 (file)
index 0000000..50b8e42
--- /dev/null
@@ -0,0 +1,106 @@
+use std::str::FromStr;
+
+use cursive::{
+    event::{Event, EventResult},
+    view::{Resizable, ViewWrapper},
+    views::{DummyView, EditView, LinearLayout, ResizedView, TextView},
+    View,
+};
+
+pub struct NumericEditView {
+    view: EditView,
+    max_value: Option<f64>,
+}
+
+impl NumericEditView {
+    pub fn new() -> Self {
+        Self {
+            view: EditView::new().content("0."),
+            max_value: None,
+        }
+    }
+
+    pub fn max_value(mut self, max: f64) -> Self {
+        self.max_value = Some(max);
+        self
+    }
+
+    pub fn set_content(&mut self, content: f64) {
+        self.view.set_content(content.to_string());
+    }
+
+    pub fn content(mut self, content: f64) -> Self {
+        let _ = self.view.set_content(content.to_string());
+        self
+    }
+
+    pub fn get_content(&self) -> Result<f64, <f64 as FromStr>::Err> {
+        self.view.get_content().parse()
+    }
+}
+
+impl ViewWrapper for NumericEditView {
+    cursive::wrap_impl!(self.view: EditView);
+
+    fn wrap_on_event(&mut self, event: Event) -> EventResult {
+        let result = match event {
+            Event::Char(c) if !(c.is_numeric() || c == '.') => EventResult::consumed(),
+            _ => self.view.on_event(event),
+        };
+
+        if let Some(max) = self.max_value {
+            if let Ok(val) = self.get_content() {
+                if val > max {
+                    let cb = self.view.remove(1);
+                    return EventResult::with_cb_once(move |siv| {
+                        result.process(siv);
+                        cb(siv);
+                    });
+                }
+            }
+        }
+
+        result
+    }
+}
+
+pub struct DiskSizeInputView {
+    view: LinearLayout,
+}
+
+impl DiskSizeInputView {
+    pub fn new(label: &str) -> Self {
+        let view = LinearLayout::horizontal()
+            .child(TextView::new(format!("{label}: ")))
+            .child(DummyView.full_width())
+            .child(NumericEditView::new().full_width())
+            .child(TextView::new(" GB"));
+
+        Self { view }
+    }
+
+    pub fn content(mut self, content: u64) -> Self {
+        let val = (content as f64) / 1024. / 1024.;
+
+        self.with_view_mut(|v| {
+            v.get_child_mut(2)?
+                .downcast_mut::<ResizedView<NumericEditView>>()?
+                .with_view_mut(|v| v.set_content(val))
+        });
+
+        self
+    }
+
+    pub fn get_content(&mut self) -> Option<u64> {
+        self.with_view_mut(|v| {
+            v.get_child_mut(2)?
+                .downcast_mut::<ResizedView<NumericEditView>>()?
+                .with_view_mut(|v| v.get_content().ok().map(|val| (val * 1024. * 1024.) as u64))?
+        })
+        .flatten()
+    }
+}
+
+impl ViewWrapper for DiskSizeInputView {
+    cursive::wrap_impl!(self.view: LinearLayout);
+}