Refactoring
Trying to find nice coding patterns as I'm learning Rust
This commit is contained in:
parent
50eb38aae1
commit
dced5cba03
3
Linux/.vscode/settings.json
vendored
3
Linux/.vscode/settings.json
vendored
@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
"nixEnvSelector.nixFile": "${workspaceFolder}/shell.nix",
|
"nixEnvSelector.nixFile": "${workspaceFolder}/shell.nix",
|
||||||
"files.trimTrailingWhitespace": true
|
"files.trimTrailingWhitespace": true,
|
||||||
|
"rust-analyzer.imports.granularity.group": "item"
|
||||||
}
|
}
|
85
Linux/Cargo.lock
generated
85
Linux/Cargo.lock
generated
@ -17,6 +17,8 @@ dependencies = [
|
|||||||
"rust-i18n",
|
"rust-i18n",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"serialport",
|
||||||
|
"tracker",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -211,6 +213,12 @@ version = "1.0.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422"
|
checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "core-foundation-sys"
|
||||||
|
version = "0.8.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crc32fast"
|
name = "crc32fast"
|
||||||
version = "1.4.2"
|
version = "1.4.2"
|
||||||
@ -803,6 +811,16 @@ dependencies = [
|
|||||||
"hashbrown 0.14.5",
|
"hashbrown 0.14.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "io-kit-sys"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "617ee6cf8e3f66f3b4ea67a4058564628cde41901316e19f559e14c7c72c5e7b"
|
||||||
|
dependencies = [
|
||||||
|
"core-foundation-sys",
|
||||||
|
"mach2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "is_terminal_polyfill"
|
name = "is_terminal_polyfill"
|
||||||
version = "1.70.0"
|
version = "1.70.0"
|
||||||
@ -868,6 +886,15 @@ version = "0.4.21"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
|
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mach2"
|
||||||
|
version = "0.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
version = "2.7.2"
|
version = "2.7.2"
|
||||||
@ -909,6 +936,17 @@ dependencies = [
|
|||||||
"getrandom",
|
"getrandom",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nix"
|
||||||
|
version = "0.26.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 1.3.2",
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "normpath"
|
name = "normpath"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
@ -1271,6 +1309,24 @@ dependencies = [
|
|||||||
"yaml-rust",
|
"yaml-rust",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serialport"
|
||||||
|
version = "4.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "de7c4f0cce25b9b3518eea99618112f9ee4549f974480c8f43d3c06f03c131a0"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.5.0",
|
||||||
|
"cfg-if",
|
||||||
|
"core-foundation-sys",
|
||||||
|
"io-kit-sys",
|
||||||
|
"mach2",
|
||||||
|
"nix",
|
||||||
|
"regex",
|
||||||
|
"scopeguard",
|
||||||
|
"unescaper",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "slab"
|
name = "slab"
|
||||||
version = "0.4.9"
|
version = "0.4.9"
|
||||||
@ -1480,6 +1536,26 @@ dependencies = [
|
|||||||
"once_cell",
|
"once_cell",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracker"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ce5c98457ff700aaeefcd4a4a492096e78a2af1dd8523c66e94a3adb0fdbd415"
|
||||||
|
dependencies = [
|
||||||
|
"tracker-macros",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracker-macros"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dc19eb2373ccf3d1999967c26c3d44534ff71ae5d8b9dacf78f4b13132229e48"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.66",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "triomphe"
|
name = "triomphe"
|
||||||
version = "0.1.12"
|
version = "0.1.12"
|
||||||
@ -1491,6 +1567,15 @@ dependencies = [
|
|||||||
"stable_deref_trait",
|
"stable_deref_trait",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unescaper"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c878a167baa8afd137494101a688ef8c67125089ff2249284bd2b5f9bfedb815"
|
||||||
|
dependencies = [
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.12"
|
version = "1.0.12"
|
||||||
|
@ -15,6 +15,8 @@ relm4-icons = "0.8.3"
|
|||||||
rust-i18n = "3.0.1"
|
rust-i18n = "3.0.1"
|
||||||
serde = { version = "1.0.203", features = ["derive"] }
|
serde = { version = "1.0.203", features = ["derive"] }
|
||||||
serde_json = "1.0.117"
|
serde_json = "1.0.117"
|
||||||
|
serialport = { version = "4.4.0", default-features = false }
|
||||||
|
tracker = "0.2.2"
|
||||||
|
|
||||||
[dependencies.min-rs]
|
[dependencies.min-rs]
|
||||||
git = "https://github.com/MvRens/min-rs.git"
|
git = "https://github.com/MvRens/min-rs.git"
|
@ -4,3 +4,13 @@ devices:
|
|||||||
serial_min:
|
serial_min:
|
||||||
name:
|
name:
|
||||||
en: Serial device using MIN protocol
|
en: Serial device using MIN protocol
|
||||||
|
|
||||||
|
serial_min:
|
||||||
|
settings:
|
||||||
|
port:
|
||||||
|
label:
|
||||||
|
en: Serial port
|
||||||
|
custom:
|
||||||
|
en: Custom...
|
||||||
|
custom_port_placeholder:
|
||||||
|
en: e.g. /dev/ttyACM0
|
@ -5,6 +5,7 @@
|
|||||||
gtk4
|
gtk4
|
||||||
graphene
|
graphene
|
||||||
gdk-pixbuf
|
gdk-pixbuf
|
||||||
|
libudev-zero
|
||||||
];
|
];
|
||||||
|
|
||||||
# For a reason I'm yet to find out, my VSCode terminal sets GDK_BACKEND to x11.
|
# For a reason I'm yet to find out, my VSCode terminal sets GDK_BACKEND to x11.
|
||||||
|
@ -9,6 +9,6 @@ pub fn register(registry: &mut Registry<ActionRegistryItem>)
|
|||||||
{
|
{
|
||||||
registry.register(ActionRegistryItem
|
registry.register(ActionRegistryItem
|
||||||
{
|
{
|
||||||
unique_id: UniqueId::new("pipewire.set_volume")
|
unique_id: UniqueId::from("pipewire.set_volume")
|
||||||
});
|
});
|
||||||
}
|
}
|
@ -7,7 +7,7 @@ pub struct EmulatorWindow
|
|||||||
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Msg
|
pub enum EmulatorWindowMessage
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -16,7 +16,7 @@ pub enum Msg
|
|||||||
impl SimpleComponent for EmulatorWindow
|
impl SimpleComponent for EmulatorWindow
|
||||||
{
|
{
|
||||||
type Init = ();
|
type Init = ();
|
||||||
type Input = Msg;
|
type Input = EmulatorWindowMessage;
|
||||||
type Output = ();
|
type Output = ();
|
||||||
|
|
||||||
view!
|
view!
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
use emulatorwindow::EmulatorWindow;
|
use emulatorwindow::EmulatorWindow;
|
||||||
use relm4::{component::Connector, ComponentController};
|
use relm4::component::Connector;
|
||||||
use relm4::Component;
|
use relm4::Component;
|
||||||
use relm4::gtk::prelude::*;
|
use relm4::gtk::prelude::*;
|
||||||
|
use relm4::ComponentController;
|
||||||
|
|
||||||
use crate::registry::Registry;
|
use crate::registry::Registry;
|
||||||
use crate::util::unique_id::UniqueId;
|
use crate::util::unique_id::UniqueId;
|
||||||
use super::{Device, DeviceRegistryItem};
|
use super::Device;
|
||||||
|
use super::DeviceRegistryItem;
|
||||||
|
|
||||||
|
|
||||||
pub mod emulatorwindow;
|
pub mod emulatorwindow;
|
||||||
@ -13,7 +15,7 @@ pub mod emulatorwindow;
|
|||||||
|
|
||||||
pub struct EmulatorWindowDevice
|
pub struct EmulatorWindowDevice
|
||||||
{
|
{
|
||||||
window: Option<Connector<EmulatorWindow>>
|
window: Connector<EmulatorWindow>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -21,9 +23,12 @@ impl EmulatorWindowDevice
|
|||||||
{
|
{
|
||||||
fn new() -> Self
|
fn new() -> Self
|
||||||
{
|
{
|
||||||
|
let builder = EmulatorWindow::builder();
|
||||||
|
let window = builder.launch({});
|
||||||
|
|
||||||
EmulatorWindowDevice
|
EmulatorWindowDevice
|
||||||
{
|
{
|
||||||
window: None
|
window
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -31,20 +36,14 @@ impl EmulatorWindowDevice
|
|||||||
|
|
||||||
impl Device for EmulatorWindowDevice
|
impl Device for EmulatorWindowDevice
|
||||||
{
|
{
|
||||||
fn activate(&mut self)
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl Drop for EmulatorWindowDevice
|
||||||
|
{
|
||||||
|
fn drop(&mut self)
|
||||||
{
|
{
|
||||||
if self.window.is_some() { return }
|
self.window.widget().close();
|
||||||
|
|
||||||
let builder = EmulatorWindow::builder();
|
|
||||||
self.window = Some(builder.launch({}));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fn deactivate(&mut self)
|
|
||||||
{
|
|
||||||
let Some(window) = self.window.take() else { return };
|
|
||||||
|
|
||||||
window.widget().close();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,7 +51,8 @@ impl Device for EmulatorWindowDevice
|
|||||||
pub fn register(registry: &mut Registry<DeviceRegistryItem>)
|
pub fn register(registry: &mut Registry<DeviceRegistryItem>)
|
||||||
{
|
{
|
||||||
registry.register(DeviceRegistryItem {
|
registry.register(DeviceRegistryItem {
|
||||||
unique_id: UniqueId::new("emulator"),
|
unique_id: UniqueId::from("emulator"),
|
||||||
factory: || Box::new(EmulatorWindowDevice::new())
|
factory: || Box::new(EmulatorWindowDevice::new()),
|
||||||
|
settings_widget_factory: || None
|
||||||
});
|
});
|
||||||
}
|
}
|
@ -4,20 +4,20 @@ pub mod serial_min;
|
|||||||
|
|
||||||
use crate::registry::Registry;
|
use crate::registry::Registry;
|
||||||
use crate::registry::RegistryItem;
|
use crate::registry::RegistryItem;
|
||||||
|
use crate::ui::EmbeddedWidgetConnector;
|
||||||
use crate::util::unique_id::UniqueId;
|
use crate::util::unique_id::UniqueId;
|
||||||
|
|
||||||
|
|
||||||
pub struct DeviceRegistryItem
|
pub struct DeviceRegistryItem
|
||||||
{
|
{
|
||||||
pub unique_id: UniqueId,
|
pub unique_id: UniqueId,
|
||||||
pub factory: fn() -> Box<dyn Device>
|
pub factory: fn() -> Box<dyn Device>,
|
||||||
|
pub settings_widget_factory: fn() -> Option<Box<dyn EmbeddedWidgetConnector>>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub trait Device
|
pub trait Device
|
||||||
{
|
{
|
||||||
fn activate(&mut self);
|
|
||||||
fn deactivate(&mut self);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,6 +1,14 @@
|
|||||||
|
use relm4::Component;
|
||||||
|
use settingswidget::SerialMinSettingsInit;
|
||||||
|
use settingswidget::SerialMinSettingsWidget;
|
||||||
|
|
||||||
use crate::registry::Registry;
|
use crate::registry::Registry;
|
||||||
use crate::util::unique_id::UniqueId;
|
use crate::util::unique_id::UniqueId;
|
||||||
use super::{Device, DeviceRegistryItem};
|
use super::Device;
|
||||||
|
use super::DeviceRegistryItem;
|
||||||
|
|
||||||
|
|
||||||
|
pub mod settingswidget;
|
||||||
|
|
||||||
|
|
||||||
pub struct SerialMinDevice
|
pub struct SerialMinDevice
|
||||||
@ -11,23 +19,20 @@ pub struct SerialMinDevice
|
|||||||
|
|
||||||
impl Device for SerialMinDevice
|
impl Device for SerialMinDevice
|
||||||
{
|
{
|
||||||
fn activate(&mut self)
|
|
||||||
{
|
|
||||||
//todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fn deactivate(&mut self)
|
|
||||||
{
|
|
||||||
//todo!()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn register(registry: &mut Registry<DeviceRegistryItem>)
|
pub fn register(registry: &mut Registry<DeviceRegistryItem>)
|
||||||
{
|
{
|
||||||
registry.register(DeviceRegistryItem {
|
registry.register(DeviceRegistryItem {
|
||||||
unique_id: UniqueId::new("serial_min"),
|
unique_id: UniqueId::from("serial_min"),
|
||||||
factory: || Box::new(SerialMinDevice {})
|
factory: || Box::new(SerialMinDevice {}),
|
||||||
|
settings_widget_factory: ||
|
||||||
|
{
|
||||||
|
let builder = SerialMinSettingsWidget::builder();
|
||||||
|
Some(Box::new(builder.launch(SerialMinSettingsInit
|
||||||
|
{
|
||||||
|
})))
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
183
Linux/src/devices/serial_min/settingswidget.rs
Normal file
183
Linux/src/devices/serial_min/settingswidget.rs
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
use gtk::StringList;
|
||||||
|
use gtk::glib::clone;
|
||||||
|
use relm4::component::Connector;
|
||||||
|
use relm4::prelude::*;
|
||||||
|
use relm4::gtk::prelude::*;
|
||||||
|
use serialport::SerialPortInfo;
|
||||||
|
|
||||||
|
use crate::ui::EmbeddedWidgetConnector;
|
||||||
|
|
||||||
|
|
||||||
|
#[tracker::track]
|
||||||
|
pub struct SerialMinSettingsWidget
|
||||||
|
{
|
||||||
|
#[do_not_track]
|
||||||
|
ports: Vec<String>,
|
||||||
|
|
||||||
|
custom_port: String,
|
||||||
|
custom_port_visible: bool
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum SerialMinSettingsWidgetMessage
|
||||||
|
{
|
||||||
|
PortChanged(usize),
|
||||||
|
CustomPortChanged(String)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub struct SerialMinSettingsInit
|
||||||
|
{
|
||||||
|
// this needs a good design - we need to be able to modify the device instance, but
|
||||||
|
// we can't pass the reference or an Rc to the device due to the design of create_settings_widget.
|
||||||
|
// Either seperate the UI from the Device, or pass a middle man (sender/receiver style perhaps?)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub struct SerialMinSettingsWidgets
|
||||||
|
{
|
||||||
|
custom_port_input: gtk::Entry
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl SimpleComponent for SerialMinSettingsWidget
|
||||||
|
{
|
||||||
|
type Init = SerialMinSettingsInit;
|
||||||
|
type Input = SerialMinSettingsWidgetMessage;
|
||||||
|
type Output = ();
|
||||||
|
type Root = gtk::Box;
|
||||||
|
type Widgets = SerialMinSettingsWidgets;
|
||||||
|
|
||||||
|
|
||||||
|
fn init_root() -> Self::Root
|
||||||
|
{
|
||||||
|
gtk::Box::builder()
|
||||||
|
.hexpand(true)
|
||||||
|
.orientation(gtk::Orientation::Vertical)
|
||||||
|
.spacing(8)
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn init(_data: Self::Init, root: Self::Root, sender: ComponentSender<Self>, ) -> ComponentParts<Self>
|
||||||
|
{
|
||||||
|
let port_label = gtk::Label::builder()
|
||||||
|
.label(t!("serial_min.settings.port.label"))
|
||||||
|
.halign(gtk::Align::Start)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
root.append(&port_label);
|
||||||
|
|
||||||
|
|
||||||
|
let ports_list = serialport::available_ports().unwrap_or(Vec::<SerialPortInfo>::new());
|
||||||
|
let ports: Vec<String> = ports_list.iter().map(|p| p.port_name.clone()).collect();
|
||||||
|
|
||||||
|
let port_model_vec: Vec<&str> = ports.iter().map(|p| p.as_str()).collect();
|
||||||
|
let port_model = StringList::new(&port_model_vec);
|
||||||
|
|
||||||
|
port_model.append(t!("serial_min.settings.port.custom").as_ref());
|
||||||
|
|
||||||
|
let port_select = gtk::DropDown::builder()
|
||||||
|
.model(&port_model)
|
||||||
|
.selected(ports.len().try_into().unwrap_or(gtk::ffi::GTK_INVALID_LIST_POSITION))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
root.append(&port_select);
|
||||||
|
|
||||||
|
|
||||||
|
let port_select_cloned = port_select.clone();
|
||||||
|
port_select.connect_selected_notify(clone!(
|
||||||
|
@strong sender => move |_|
|
||||||
|
{
|
||||||
|
let active_index = port_select_cloned.selected();
|
||||||
|
if active_index == gtk::ffi::GTK_INVALID_LIST_POSITION { return };
|
||||||
|
|
||||||
|
if let Ok(active_index_usize) = usize::try_from(active_index)
|
||||||
|
{
|
||||||
|
sender.input(SerialMinSettingsWidgetMessage::PortChanged(active_index_usize));
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
let custom_port_input = gtk::Entry::builder()
|
||||||
|
.hexpand(true)
|
||||||
|
.placeholder_text(t!("serial_min.settings.custom_port_placeholder"))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
root.append(&custom_port_input);
|
||||||
|
|
||||||
|
|
||||||
|
let custom_port_input_cloned = custom_port_input.clone();
|
||||||
|
custom_port_input.connect_changed(clone!(
|
||||||
|
@strong sender => move |_|
|
||||||
|
{
|
||||||
|
sender.input(SerialMinSettingsWidgetMessage::CustomPortChanged(String::from(custom_port_input_cloned.text().as_str())));
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
|
|
||||||
|
let model = SerialMinSettingsWidget
|
||||||
|
{
|
||||||
|
ports,
|
||||||
|
|
||||||
|
custom_port: String::new(),
|
||||||
|
custom_port_visible: true,
|
||||||
|
|
||||||
|
tracker: 0
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// TODO load settings
|
||||||
|
|
||||||
|
|
||||||
|
let widgets = SerialMinSettingsWidgets
|
||||||
|
{
|
||||||
|
custom_port_input
|
||||||
|
};
|
||||||
|
|
||||||
|
ComponentParts { model, widgets }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn update(&mut self, msg: Self::Input, _sender: ComponentSender<Self>)
|
||||||
|
{
|
||||||
|
match msg
|
||||||
|
{
|
||||||
|
SerialMinSettingsWidgetMessage::PortChanged(index) =>
|
||||||
|
{
|
||||||
|
self.set_custom_port_visible(index >= self.ports.len());
|
||||||
|
},
|
||||||
|
|
||||||
|
SerialMinSettingsWidgetMessage::CustomPortChanged(value) =>
|
||||||
|
{
|
||||||
|
self.set_custom_port(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn update_view(&self, widgets: &mut Self::Widgets, _sender: ComponentSender<Self>)
|
||||||
|
{
|
||||||
|
if self.changed_custom_port_visible()
|
||||||
|
{
|
||||||
|
log::info!("Visible: {}", self.custom_port_visible);
|
||||||
|
widgets.custom_port_input.set_visible(self.custom_port_visible);
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.changed_custom_port()
|
||||||
|
{
|
||||||
|
// should this sync two-way or not?
|
||||||
|
//widgets
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl EmbeddedWidgetConnector for Connector<SerialMinSettingsWidget>
|
||||||
|
{
|
||||||
|
fn root(&self) -> &relm4::gtk::Widget
|
||||||
|
{
|
||||||
|
self.widget().as_ref()
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +1,4 @@
|
|||||||
use std::cell::RefCell;
|
|
||||||
use std::rc::Rc;
|
|
||||||
use env_logger::Env;
|
use env_logger::Env;
|
||||||
use mainwindow::MainWindowInit;
|
|
||||||
use orchestrator::Orchestrator;
|
|
||||||
use relm4::prelude::*;
|
use relm4::prelude::*;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
@ -12,6 +8,7 @@ i18n!("locales");
|
|||||||
|
|
||||||
|
|
||||||
pub mod util;
|
pub mod util;
|
||||||
|
pub mod ui;
|
||||||
pub mod registry;
|
pub mod registry;
|
||||||
pub mod devices;
|
pub mod devices;
|
||||||
pub mod actions;
|
pub mod actions;
|
||||||
@ -28,13 +25,6 @@ fn main()
|
|||||||
|
|
||||||
relm4_icons::initialize_icons();
|
relm4_icons::initialize_icons();
|
||||||
|
|
||||||
let orchestrator = Rc::new(RefCell::new(Orchestrator::new()));
|
|
||||||
|
|
||||||
let app = RelmApp::new("com.github.mvrens.massiveknob");
|
let app = RelmApp::new("com.github.mvrens.massiveknob");
|
||||||
app.run::<mainwindow::MainWindow>(MainWindowInit
|
app.run::<mainwindow::MainWindow>(());
|
||||||
{
|
|
||||||
orchestrator: Rc::clone(&orchestrator)
|
|
||||||
});
|
|
||||||
|
|
||||||
orchestrator.borrow_mut().finalize();
|
|
||||||
}
|
}
|
@ -1,59 +1,49 @@
|
|||||||
use std::cell::RefCell;
|
|
||||||
use std::rc::Rc;
|
|
||||||
use gtk::glib::clone;
|
use gtk::glib::clone;
|
||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
use relm4::prelude::*;
|
use relm4::prelude::*;
|
||||||
|
|
||||||
use crate::orchestrator::Orchestrator;
|
use crate::orchestrator::Orchestrator;
|
||||||
use crate::registry::RegistryItem;
|
use crate::registry::RegistryItem;
|
||||||
|
use crate::ui::EmbeddedWidgetConnector;
|
||||||
use crate::util::unique_id::UniqueId;
|
use crate::util::unique_id::UniqueId;
|
||||||
|
|
||||||
|
#[tracker::track]
|
||||||
pub struct MainWindow
|
pub struct MainWindow
|
||||||
{
|
{
|
||||||
orchestrator: Rc<RefCell<Orchestrator>>,
|
#[do_not_track]
|
||||||
devices_sorted: Vec<SortedDevice>
|
orchestrator: Orchestrator,
|
||||||
}
|
|
||||||
|
|
||||||
|
#[do_not_track]
|
||||||
|
devices_sorted: Vec<SortedDevice>,
|
||||||
|
|
||||||
pub struct MainWindowInit
|
#[no_eq]
|
||||||
{
|
device_settings_widget: Option<Box<dyn EmbeddedWidgetConnector>>
|
||||||
pub orchestrator: Rc<RefCell<Orchestrator>>
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
impl std::fmt::Debug for MainWindowInit
|
|
||||||
{
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
|
|
||||||
{
|
|
||||||
f.debug_struct("MainWindowInit")
|
|
||||||
// Skip orchestrator
|
|
||||||
.finish()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum MainWindowMsg
|
pub enum MainWindowMsg
|
||||||
{
|
{
|
||||||
|
DeviceInitial(usize),
|
||||||
DeviceChanged(usize)
|
DeviceChanged(usize)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub struct MainWindowWidgets
|
pub struct MainWindowWidgets
|
||||||
{
|
{
|
||||||
_device: MainWindowDeviceWidgets
|
device: MainWindowDeviceWidgets
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub struct MainWindowDeviceWidgets
|
pub struct MainWindowDeviceWidgets
|
||||||
{
|
{
|
||||||
_devices_combobox: gtk::ComboBoxText
|
settings_container: gtk::Box
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl SimpleComponent for MainWindow
|
impl SimpleComponent for MainWindow
|
||||||
{
|
{
|
||||||
type Init = MainWindowInit;
|
type Init = ();
|
||||||
type Input = MainWindowMsg;
|
type Input = MainWindowMsg;
|
||||||
type Output = ();
|
type Output = ();
|
||||||
type Root = gtk::Window;
|
type Root = gtk::Window;
|
||||||
@ -71,20 +61,14 @@ impl SimpleComponent for MainWindow
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn init(data: Self::Init, window: Self::Root, sender: ComponentSender<Self>) -> ComponentParts<Self>
|
fn init(_data: Self::Init, window: Self::Root, sender: ComponentSender<Self>) -> ComponentParts<Self>
|
||||||
{
|
{
|
||||||
{
|
let orchestrator = Orchestrator::new();
|
||||||
let mut init_orchestrator = data.orchestrator.borrow_mut();
|
|
||||||
init_orchestrator.initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
let orchestrator = data.orchestrator.borrow();
|
|
||||||
|
|
||||||
let mut devices_sorted: Vec<SortedDevice> = orchestrator.devices()
|
let mut devices_sorted: Vec<SortedDevice> = orchestrator.devices()
|
||||||
.map(|device| SortedDevice
|
.map(|device| SortedDevice
|
||||||
{
|
{
|
||||||
unique_id: device.unique_id(),
|
unique_id: device.unique_id.clone(),
|
||||||
name: device.name()
|
name: device.name()
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
@ -94,8 +78,12 @@ impl SimpleComponent for MainWindow
|
|||||||
|
|
||||||
let model = MainWindow
|
let model = MainWindow
|
||||||
{
|
{
|
||||||
orchestrator: data.orchestrator.clone(),
|
orchestrator,
|
||||||
devices_sorted
|
devices_sorted,
|
||||||
|
|
||||||
|
device_settings_widget: None,
|
||||||
|
|
||||||
|
tracker: 0
|
||||||
};
|
};
|
||||||
|
|
||||||
let widgets = MainWindowBuilder::new(&window, &model, &sender).build();
|
let widgets = MainWindowBuilder::new(&window, &model, &sender).build();
|
||||||
@ -108,18 +96,53 @@ impl SimpleComponent for MainWindow
|
|||||||
{
|
{
|
||||||
match msg
|
match msg
|
||||||
{
|
{
|
||||||
MainWindowMsg::DeviceChanged(index) =>
|
MainWindowMsg::DeviceInitial(index) => self.apply_device_settings_widget(index, true),
|
||||||
{
|
MainWindowMsg::DeviceChanged(index) => self.apply_device_settings_widget(index, false)
|
||||||
let mut orchestrator = self.orchestrator.borrow_mut();
|
}
|
||||||
let device = &self.devices_sorted[index];
|
}
|
||||||
|
|
||||||
orchestrator.set_current_device_id(device.unique_id.clone());
|
|
||||||
|
fn update_view(&self, widgets: &mut Self::Widgets, _sender: ComponentSender<Self>)
|
||||||
|
{
|
||||||
|
if self.changed(MainWindow::device_settings_widget())
|
||||||
|
{
|
||||||
|
let current_child = widgets.device.settings_container.last_child();
|
||||||
|
if let Some(current_child) = ¤t_child
|
||||||
|
{
|
||||||
|
widgets.device.settings_container.remove(current_child);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(new_child) = &self.device_settings_widget
|
||||||
|
{
|
||||||
|
widgets.device.settings_container.append(new_child.as_ref().root());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl MainWindow
|
||||||
|
{
|
||||||
|
fn apply_device_settings_widget(&mut self, index: usize, initial: bool)
|
||||||
|
{
|
||||||
|
let mut widget = None;
|
||||||
|
{
|
||||||
|
if initial
|
||||||
|
{
|
||||||
|
self.orchestrator.with_active_device(|device_instance, cookie| { widget = device_instance.create_settings_widget(cookie) });
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
let device_id = self.devices_sorted[index].unique_id.clone();
|
||||||
|
self.orchestrator.set_active_device_id(&device_id, |device_instance, cookie| { widget = device_instance.create_settings_widget(cookie) });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.set_device_settings_widget(widget)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
struct MainWindowBuilder<'a>
|
struct MainWindowBuilder<'a>
|
||||||
{
|
{
|
||||||
window: &'a gtk::Window,
|
window: &'a gtk::Window,
|
||||||
@ -148,7 +171,7 @@ impl<'a> MainWindowBuilder<'a>
|
|||||||
|
|
||||||
MainWindowWidgets
|
MainWindowWidgets
|
||||||
{
|
{
|
||||||
_device: self.init_device_tab(&tabs)
|
device: self.init_device_tab(&tabs)
|
||||||
//Self::new_box_tab(&tabs, "mainwindow.tab.analoginputs");
|
//Self::new_box_tab(&tabs, "mainwindow.tab.analoginputs");
|
||||||
//Self::new_box_tab(&tabs, "mainwindow.tab.digitalinputs");
|
//Self::new_box_tab(&tabs, "mainwindow.tab.digitalinputs");
|
||||||
//Self::add_box_tab(&tabs, "mainwindow.tab.analogoutputs");
|
//Self::add_box_tab(&tabs, "mainwindow.tab.analogoutputs");
|
||||||
@ -171,11 +194,27 @@ impl<'a> MainWindowBuilder<'a>
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
let devices_combobox = gtk::ComboBoxText::builder()
|
let devices_combobox = gtk::ComboBoxText::builder().build();
|
||||||
.build();
|
tab.append(&devices_combobox);
|
||||||
|
|
||||||
|
|
||||||
|
let active_device_id = self.model.orchestrator.active_device_id();
|
||||||
|
for (index, device) in self.model.devices_sorted.iter().enumerate()
|
||||||
|
{
|
||||||
|
devices_combobox.append_text(device.name.as_str());
|
||||||
|
|
||||||
|
if let Some(device_id) = &active_device_id
|
||||||
|
{
|
||||||
|
if *device_id == device.unique_id
|
||||||
|
{
|
||||||
|
devices_combobox.set_active(Some(index as u32));
|
||||||
|
sender.input(MainWindowMsg::DeviceInitial(index));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
let devices_combobox_cloned = devices_combobox.clone();
|
let devices_combobox_cloned = devices_combobox.clone();
|
||||||
|
|
||||||
devices_combobox.connect_changed(clone!(
|
devices_combobox.connect_changed(clone!(
|
||||||
@strong sender => move |_|
|
@strong sender => move |_|
|
||||||
{
|
{
|
||||||
@ -188,29 +227,14 @@ impl<'a> MainWindowBuilder<'a>
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
tab.append(&devices_combobox);
|
|
||||||
|
|
||||||
|
let settings_container = gtk::Box::builder().build();
|
||||||
let current_device_id = self.model.orchestrator.borrow().current_device_id();
|
tab.append(&settings_container);
|
||||||
|
|
||||||
|
|
||||||
for (index, device) in self.model.devices_sorted.iter().enumerate()
|
|
||||||
{
|
|
||||||
devices_combobox.append_text(device.name.as_str());
|
|
||||||
|
|
||||||
if let Some(device_id) = current_device_id.clone()
|
|
||||||
{
|
|
||||||
if device_id == device.unique_id
|
|
||||||
{
|
|
||||||
devices_combobox.set_active(Some(index as u32));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
MainWindowDeviceWidgets
|
MainWindowDeviceWidgets
|
||||||
{
|
{
|
||||||
_devices_combobox: devices_combobox
|
settings_container
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -237,6 +261,7 @@ impl<'a> MainWindowBuilder<'a>
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
struct SortedDevice
|
struct SortedDevice
|
||||||
{
|
{
|
||||||
unique_id: UniqueId,
|
unique_id: UniqueId,
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
|
use std::borrow::{Borrow, BorrowMut};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::actions;
|
use crate::actions;
|
||||||
use crate::actions::ActionRegistryItem;
|
//use crate::actions::ActionRegistryItem;
|
||||||
use crate::config::json::JsonConfigManager;
|
use crate::config::json::JsonConfigManager;
|
||||||
use crate::config::{ConfigManager, ConfigName};
|
use crate::config::{ConfigManager, ConfigName};
|
||||||
use crate::devices::{self, Device};
|
use crate::devices::{self, Device};
|
||||||
@ -14,15 +17,13 @@ mod settings;
|
|||||||
pub struct Orchestrator
|
pub struct Orchestrator
|
||||||
{
|
{
|
||||||
config_manager: ConfigManager,
|
config_manager: ConfigManager,
|
||||||
|
settings_name: ConfigName,
|
||||||
|
|
||||||
device_registry: Registry<DeviceRegistryItem>,
|
device_registry: Registry<DeviceRegistryItem>,
|
||||||
action_registry: Registry<ActionRegistryItem>,
|
//action_registry: Registry<ActionRegistryItem>,
|
||||||
|
|
||||||
settings_name: ConfigName,
|
// current_device_instance: Option<Box<dyn Device>>
|
||||||
settings: settings::Settings,
|
active_device: Option<ActiveDevice>
|
||||||
|
|
||||||
|
|
||||||
current_device_instance: Option<Box<dyn Device>>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -31,117 +32,151 @@ impl Orchestrator
|
|||||||
pub fn new() -> Self
|
pub fn new() -> Self
|
||||||
{
|
{
|
||||||
let config_manager = ConfigManager::new();
|
let config_manager = ConfigManager::new();
|
||||||
|
|
||||||
let settings_name = ConfigName::new("settings");
|
let settings_name = ConfigName::new("settings");
|
||||||
let settings = match config_manager.read_json(&settings_name).expect("Error reading settings")
|
let settings = match config_manager.read_json(&settings_name).expect("Error reading settings")
|
||||||
{
|
{
|
||||||
None => settings::Settings::new(),
|
None => settings::Settings::default(),
|
||||||
Some(v) => v
|
Some(v) => v
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
let mut device_registry = Registry::new();
|
let mut device_registry = Registry::new();
|
||||||
let mut action_registry = Registry::new();
|
let mut action_registry = Registry::new();
|
||||||
|
|
||||||
devices::register(&mut device_registry);
|
devices::register(&mut device_registry);
|
||||||
actions::register(&mut action_registry);
|
actions::register(&mut action_registry);
|
||||||
|
|
||||||
Self
|
let mut instance = Self
|
||||||
{
|
{
|
||||||
config_manager,
|
config_manager,
|
||||||
|
settings_name,
|
||||||
|
|
||||||
device_registry,
|
device_registry,
|
||||||
action_registry,
|
//action_registry,
|
||||||
|
|
||||||
settings_name,
|
//settings,
|
||||||
settings,
|
|
||||||
|
|
||||||
|
|
||||||
current_device_instance: None
|
active_device: None
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
instance.initialize(settings);
|
||||||
|
instance
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn initialize(&mut self, settings: settings::Settings)
|
||||||
|
{
|
||||||
|
if let Some(device_id) = settings.device_id
|
||||||
|
{
|
||||||
|
self.set_active_device(Some(UniqueId::from(device_id)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn initialize(&mut self)
|
|
||||||
{
|
|
||||||
self.set_current_device(self.current_device_id());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pub fn finalize(&mut self)
|
|
||||||
{
|
|
||||||
self.set_current_device(None);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pub fn devices(&self) -> impl Iterator<Item = &DeviceRegistryItem>
|
pub fn devices(&self) -> impl Iterator<Item = &DeviceRegistryItem>
|
||||||
{
|
{
|
||||||
self.device_registry.iter()
|
self.device_registry.iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn current_device_id(&self) -> Option<UniqueId>
|
pub fn active_device_id(&self) -> Option<UniqueId>
|
||||||
{
|
{
|
||||||
let Some(device_id) = &self.settings.device_id else { return None };
|
let Some(active_device) = &self.active_device else { return None };
|
||||||
Some(UniqueId::new(device_id.as_str()))
|
Some(active_device.id.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
|
||||||
pub fn current_device(&self) -> Option<&DeviceRegistryItem>
|
pub fn current_device(&self) -> Option<&DeviceRegistryItem>
|
||||||
{
|
{
|
||||||
let Some(device_id) = self.current_device_id() else { return None };
|
let Some(device_id) = self.current_device_id() else { return None };
|
||||||
self.device_registry.by_id(device_id)
|
self.device_registry.by_id(device_id)
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
pub fn set_current_device_id(&mut self, id: UniqueId)
|
pub fn with_active_device<F>(&self, callback: F) where F: FnOnce(&dyn Device)
|
||||||
{
|
{
|
||||||
let new_id = Some(String::from(id.as_str()));
|
let Some(active_device) = self.active_device else { return };
|
||||||
if new_id == self.settings.device_id { return; }
|
let instance = active_device.instance.clone();
|
||||||
|
|
||||||
self.settings.device_id = new_id;
|
callback(instance.as_ref().as_ref());
|
||||||
|
|
||||||
|
self.active_device.as_ref().map(|device| callback(&*device.instance.clone()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
pub fn set_active_device_id<F>(&mut self, id: &UniqueId, on_changed: F) where F: FnOnce(&dyn Device)
|
||||||
|
{
|
||||||
|
let id = Some(id.clone());
|
||||||
|
if id == self.active_device_id() { return }
|
||||||
|
|
||||||
|
self.set_active_device(id);
|
||||||
self.store_settings();
|
self.store_settings();
|
||||||
|
|
||||||
self.set_current_device(Some(id));
|
self.with_active_device(on_changed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fn store_settings(&self)
|
fn store_settings(&self)
|
||||||
{
|
{
|
||||||
if let Err(e) = self.config_manager.write_json(&self.settings_name, &self.settings)
|
let settings = settings::Settings
|
||||||
|
{
|
||||||
|
device_id: match &self.active_device
|
||||||
|
{
|
||||||
|
None => None,
|
||||||
|
Some(v) => Some(v.id.clone().into())
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Err(e) = self.config_manager.write_json(&self.settings_name, &settings)
|
||||||
{
|
{
|
||||||
log::error!("Error writing settings: {e}");
|
log::error!("Error writing settings: {e}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn set_current_device(&mut self, id: Option<UniqueId>)
|
|
||||||
|
fn set_active_device(&mut self, id: Option<UniqueId>)
|
||||||
{
|
{
|
||||||
let prev_device_instance;
|
self.active_device = match id
|
||||||
let new_device = match id
|
|
||||||
{
|
{
|
||||||
None => None,
|
None => None,
|
||||||
Some(v) => self.device_registry.by_id(v)
|
Some(v) =>
|
||||||
|
match self.device_registry.by_id(&v)
|
||||||
|
{
|
||||||
|
None => None,
|
||||||
|
Some(d) =>
|
||||||
|
{
|
||||||
|
Some(ActiveDevice
|
||||||
|
{
|
||||||
|
id: v.clone(),
|
||||||
|
instance: Arc::new((d.factory)())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// Replace the device instance
|
|
||||||
if let Some(new_device) = new_device
|
|
||||||
{
|
|
||||||
let mut new_device_instance = (new_device.factory)();
|
|
||||||
new_device_instance.activate();
|
|
||||||
|
|
||||||
prev_device_instance = self.current_device_instance.replace(new_device_instance);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
prev_device_instance = self.current_device_instance.take();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Deactivate the previous instance
|
|
||||||
if let Some(mut prev_device_instance) = prev_device_instance
|
|
||||||
{
|
|
||||||
prev_device_instance.deactivate();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl Drop for Orchestrator
|
||||||
|
{
|
||||||
|
fn drop(&mut self)
|
||||||
|
{
|
||||||
|
self.set_active_device(None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
struct ActiveDevice
|
||||||
|
{
|
||||||
|
id: UniqueId,
|
||||||
|
instance: Arc<Box<dyn Device>>
|
||||||
|
}
|
@ -7,9 +7,9 @@ pub struct Settings
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl Settings
|
impl Default for Settings
|
||||||
{
|
{
|
||||||
pub fn new() -> Self
|
fn default() -> Self
|
||||||
{
|
{
|
||||||
Self
|
Self
|
||||||
{
|
{
|
||||||
|
@ -49,7 +49,7 @@ impl<T> Registry<T> where T: RegistryItem
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn by_id(&self, id: UniqueId) -> Option<&T>
|
pub fn by_id(&self, id: &UniqueId) -> Option<&T>
|
||||||
{
|
{
|
||||||
self.items.get(id.as_str())
|
self.items.get(id.as_str())
|
||||||
}
|
}
|
||||||
|
4
Linux/src/ui/mod.rs
Normal file
4
Linux/src/ui/mod.rs
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
pub trait EmbeddedWidgetConnector
|
||||||
|
{
|
||||||
|
fn root(&self) -> &relm4::gtk::Widget;
|
||||||
|
}
|
@ -50,6 +50,33 @@ impl<T: ValidatedStringPattern> Clone for ValidatedString<T>
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl<T: ValidatedStringPattern> From<&str> for ValidatedString<T>
|
||||||
|
{
|
||||||
|
fn from(value: &str) -> Self
|
||||||
|
{
|
||||||
|
Self::new(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl<T: ValidatedStringPattern> From<String> for ValidatedString<T>
|
||||||
|
{
|
||||||
|
fn from(value: String) -> Self
|
||||||
|
{
|
||||||
|
Self::new(value.as_str())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl<T: ValidatedStringPattern> Into<String> for ValidatedString<T>
|
||||||
|
{
|
||||||
|
fn into(self) -> String
|
||||||
|
{
|
||||||
|
self.inner.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
pub trait ValidatedStringPattern
|
pub trait ValidatedStringPattern
|
||||||
{
|
{
|
||||||
fn pattern() -> &'static str;
|
fn pattern() -> &'static str;
|
||||||
|
Loading…
Reference in New Issue
Block a user