diff --git a/cue-ios/CueIOS/Views/ChlorineView.swift b/cue-ios/CueIOS/Views/ChlorineView.swift index 9e2ba0b..66ad192 100644 --- a/cue-ios/CueIOS/Views/ChlorineView.swift +++ b/cue-ios/CueIOS/Views/ChlorineView.swift @@ -7,11 +7,13 @@ struct ChlorineView: View { var body: some View { VStack(spacing: 0) { controlsRow + clPeakLabels Divider() GeometryReader { geo in if geo.size.width > 700 { HSplitLayout(ratio: 0.55) { VStack(spacing: 4) { + voltammogramPlot resultBanner chlorinePlot } @@ -21,8 +23,9 @@ struct ChlorineView: View { } else { ScrollView { VStack(spacing: 12) { + voltammogramPlot.frame(height: 250) resultBanner - chlorinePlot.frame(height: 350) + chlorinePlot.frame(height: 250) clTable.frame(height: 300) } .padding() @@ -37,6 +40,21 @@ struct ChlorineView: View { private var controlsRow: some View { ScrollView(.horizontal, showsIndicators: false) { HStack(spacing: 8) { + Button("Start LSV") { state.startLSV() } + .buttonStyle(ActionButtonStyle(color: .green)) + + Button(state.lsvManualPeaks ? "Manual" : "Auto") { + state.lsvManualPeaks.toggle() + if state.lsvManualPeaks { + state.lsvPeaks.removeAll() + } else { + state.lsvPeaks = detectLsvPeaks(state.lsvPoints) + } + } + .font(.caption) + + Divider().frame(height: 24) + LabeledField("Cond mV", text: $state.clCondV, width: 70) LabeledField("Cond ms", text: $state.clCondT, width: 70) LabeledField("Free mV", text: $state.clFreeV, width: 70) @@ -88,7 +106,102 @@ struct ChlorineView: View { } } - // MARK: - Plot + // MARK: - Peak labels + + @ViewBuilder + private var clPeakLabels: some View { + if !state.lsvPeaks.isEmpty { + HStack(spacing: 12) { + ForEach(Array(state.lsvPeaks.enumerated()), id: \.offset) { _, peak in + let label: String = { + switch peak.kind { + case .freeCl: return String(format: "Free: %.0fmV %.2fuA", peak.vMv, peak.iUa) + case .totalCl: return String(format: "Total: %.0fmV %.2fuA", peak.vMv, peak.iUa) + case .crossover: return String(format: "X-over: %.0fmV", peak.vMv) + } + }() + Text(label) + .font(.caption) + .foregroundStyle(clPeakColor(peak.kind)) + } + } + .padding(.horizontal, 8) + .padding(.vertical, 4) + } + } + + private func clPeakColor(_ kind: PeakKind) -> Color { + switch kind { + case .freeCl: .green + case .totalCl: .orange + case .crossover: .purple + } + } + + // MARK: - Voltammogram + + private var voltammogramPlot: some View { + Group { + if state.lsvPoints.isEmpty { + Text("No LSV data") + .foregroundStyle(Color(white: 0.4)) + .frame(maxWidth: .infinity, maxHeight: .infinity) + .background(Color.black.opacity(0.3)) + } else { + PlotContainer(title: "") { + Chart { + if let ref = state.lsvRef { + ForEach(Array(ref.enumerated()), id: \.offset) { _, pt in + LineMark(x: .value("V", Double(pt.vMv)), y: .value("I", Double(pt.iUa))) + .foregroundStyle(Color.gray.opacity(0.5)) + .lineStyle(StrokeStyle(lineWidth: 1.5)) + } + } + ForEach(Array(state.lsvPoints.enumerated()), id: \.offset) { _, pt in + LineMark(x: .value("V", Double(pt.vMv)), y: .value("I", Double(pt.iUa))) + .foregroundStyle(Color.yellow) + .lineStyle(StrokeStyle(lineWidth: 2)) + } + ForEach(Array(state.lsvPoints.enumerated()), id: \.offset) { _, pt in + PointMark(x: .value("V", Double(pt.vMv)), y: .value("I", Double(pt.iUa))) + .foregroundStyle(Color.yellow) + .symbolSize(16) + } + ForEach(Array(state.lsvPeaks.enumerated()), id: \.offset) { _, peak in + PointMark(x: .value("V", Double(peak.vMv)), y: .value("I", Double(peak.iUa))) + .foregroundStyle(clPeakColor(peak.kind)) + .symbolSize(100) + .symbol(.diamond) + RuleMark(x: .value("V", Double(peak.vMv))) + .foregroundStyle(clPeakColor(peak.kind).opacity(0.3)) + .lineStyle(StrokeStyle(lineWidth: 1, dash: [4, 4])) + } + } + .chartXAxisLabel("V (mV)") + .chartYAxisLabel("I (uA)", position: .leading) + .chartXAxis { + AxisMarks { _ in + AxisGridLine(stroke: StrokeStyle(lineWidth: 0.5)) + .foregroundStyle(Color.gray.opacity(0.3)) + AxisValueLabel().font(.caption2).foregroundStyle(.secondary) + } + } + .chartYAxis { + AxisMarks(position: .leading) { _ in + AxisGridLine(stroke: StrokeStyle(lineWidth: 0.5)) + .foregroundStyle(Color.gray.opacity(0.3)) + AxisValueLabel().font(.caption2).foregroundStyle(Color.yellow) + } + } + .padding(8) + } + } + } + .background(Color.black.opacity(0.3)) + .clipShape(RoundedRectangle(cornerRadius: 8)) + } + + // MARK: - Chlorine plot private var chlorinePlot: some View { Group { diff --git a/cue/Cargo.lock b/cue/Cargo.lock index 74a4326..bcf301b 100644 --- a/cue/Cargo.lock +++ b/cue/Cargo.lock @@ -132,6 +132,28 @@ dependencies = [ "libloading 0.7.4", ] +[[package]] +name = "ashpd" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2f3f79755c74fd155000314eb349864caa787c6592eace6c6882dad873d9c39" +dependencies = [ + "async-fs", + "async-net", + "enumflags2", + "futures-channel", + "futures-util", + "rand 0.9.2", + "raw-window-handle", + "serde", + "serde_repr", + "url", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "zbus 5.14.0", +] + [[package]] name = "async-broadcast" version = "0.7.2" @@ -210,6 +232,17 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "async-net" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b948000fad4873c1c9339d60f2623323a0cfd3816e5181033c6a5cb68b2accf7" +dependencies = [ + "async-io", + "blocking", + "futures-lite", +] + [[package]] name = "async-process" version = "2.5.0" @@ -340,6 +373,15 @@ dependencies = [ "objc2 0.5.2", ] +[[package]] +name = "block2" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5" +dependencies = [ + "objc2 0.6.4", +] + [[package]] name = "blocking" version = "1.6.2" @@ -722,6 +764,7 @@ dependencies = [ "futures", "iced", "muda", + "rfd", "rusqlite", "serde", "serde_json", @@ -760,7 +803,7 @@ dependencies = [ "rust-ini", "web-sys", "winreg", - "zbus", + "zbus 4.4.0", ] [[package]] @@ -839,9 +882,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" dependencies = [ "bitflags 2.11.0", + "block2 0.6.2", + "libc", "objc2 0.6.4", ] +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "dlib" version = "0.5.3" @@ -1125,6 +1181,15 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + [[package]] name = "futures" version = "0.3.32" @@ -1656,12 +1721,115 @@ dependencies = [ "winit", ] +[[package]] +name = "icu_collections" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" +dependencies = [ + "displaydoc", + "potential_utf", + "utf8_iter", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" + +[[package]] +name = "icu_properties" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" + +[[package]] +name = "icu_provider" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + [[package]] name = "id-arena" version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + [[package]] name = "indexmap" version = "2.13.0" @@ -1848,6 +2016,12 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" +[[package]] +name = "litemap" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" + [[package]] name = "lock_api" version = "0.4.14" @@ -2155,7 +2329,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" dependencies = [ "bitflags 2.11.0", - "block2", + "block2 0.5.1", "libc", "objc2 0.5.2", "objc2-core-data", @@ -2171,6 +2345,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c" dependencies = [ "bitflags 2.11.0", + "block2 0.6.2", "objc2 0.6.4", "objc2-core-foundation", "objc2-foundation 0.3.2", @@ -2183,7 +2358,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009" dependencies = [ "bitflags 2.11.0", - "block2", + "block2 0.5.1", "objc2 0.5.2", "objc2-core-location", "objc2-foundation 0.2.2", @@ -2195,7 +2370,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a5ff520e9c33812fd374d8deecef01d4a840e7b41862d849513de77e44aa4889" dependencies = [ - "block2", + "block2 0.5.1", "objc2 0.5.2", "objc2-foundation 0.2.2", ] @@ -2207,7 +2382,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" dependencies = [ "bitflags 2.11.0", - "block2", + "block2 0.5.1", "objc2 0.5.2", "objc2-foundation 0.2.2", ] @@ -2242,7 +2417,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80" dependencies = [ - "block2", + "block2 0.5.1", "objc2 0.5.2", "objc2-foundation 0.2.2", "objc2-metal", @@ -2254,7 +2429,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "000cfee34e683244f284252ee206a27953279d370e309649dc3ee317b37e5781" dependencies = [ - "block2", + "block2 0.5.1", "objc2 0.5.2", "objc2-contacts", "objc2-foundation 0.2.2", @@ -2273,7 +2448,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" dependencies = [ "bitflags 2.11.0", - "block2", + "block2 0.5.1", "dispatch", "libc", "objc2 0.5.2", @@ -2307,7 +2482,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1a1ae721c5e35be65f01a03b6d2ac13a54cb4fa70d8a5da293d7b0020261398" dependencies = [ - "block2", + "block2 0.5.1", "objc2 0.5.2", "objc2-app-kit 0.2.2", "objc2-foundation 0.2.2", @@ -2320,7 +2495,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" dependencies = [ "bitflags 2.11.0", - "block2", + "block2 0.5.1", "objc2 0.5.2", "objc2-foundation 0.2.2", ] @@ -2332,7 +2507,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" dependencies = [ "bitflags 2.11.0", - "block2", + "block2 0.5.1", "objc2 0.5.2", "objc2-foundation 0.2.2", "objc2-metal", @@ -2367,7 +2542,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f" dependencies = [ "bitflags 2.11.0", - "block2", + "block2 0.5.1", "objc2 0.5.2", "objc2-cloud-kit", "objc2-core-data", @@ -2387,7 +2562,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44fa5f9748dbfe1ca6c0b79ad20725a11eca7c2218bceb4b005cb1be26273bfe" dependencies = [ - "block2", + "block2 0.5.1", "objc2 0.5.2", "objc2-foundation 0.2.2", ] @@ -2399,7 +2574,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3" dependencies = [ "bitflags 2.11.0", - "block2", + "block2 0.5.1", "objc2 0.5.2", "objc2-core-location", "objc2-foundation 0.2.2", @@ -2566,7 +2741,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" dependencies = [ "phf_shared", - "rand", + "rand 0.8.5", ] [[package]] @@ -2673,6 +2848,21 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "pollster" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f3a9f18d041e6d0e102a0a46750538147e5e8992d3b4873aaafee2520b00ce3" + +[[package]] +name = "potential_utf" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" +dependencies = [ + "zerovec", +] + [[package]] name = "ppv-lite86" version = "0.2.21" @@ -2759,8 +2949,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha", - "rand_core", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.5", ] [[package]] @@ -2770,7 +2970,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.5", ] [[package]] @@ -2782,6 +2992,15 @@ dependencies = [ "getrandom 0.2.17", ] +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.4", +] + [[package]] name = "range-alloc" version = "0.1.5" @@ -2883,6 +3102,30 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832" +[[package]] +name = "rfd" +version = "0.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef2bee61e6cffa4635c72d7d81a84294e28f0930db0ddcb0f66d10244674ebed" +dependencies = [ + "ashpd", + "block2 0.6.2", + "dispatch2", + "js-sys", + "log", + "objc2 0.6.4", + "objc2-app-kit 0.3.2", + "objc2-core-foundation", + "objc2-foundation 0.3.2", + "pollster", + "raw-window-handle", + "urlencoding", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "windows-sys 0.59.0", +] + [[package]] name = "roxmltree" version = "0.20.0" @@ -3276,6 +3519,12 @@ dependencies = [ "bitflags 2.11.0", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + [[package]] name = "static_assertions" version = "1.1.0" @@ -3327,6 +3576,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "sys-locale" version = "0.3.2" @@ -3437,6 +3697,16 @@ dependencies = [ "tracing", ] +[[package]] +name = "tinystr" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" +dependencies = [ + "displaydoc", + "zerovec", +] + [[package]] name = "tinyvec" version = "1.10.0" @@ -3688,6 +3958,42 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", + "serde_derive", +] + +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "uuid" +version = "1.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ac8b6f42ead25368cf5b098aeb3dc8a1a2c05a3eee8a9a1a68c640edbfc79d9" +dependencies = [ + "js-sys", + "serde_core", + "wasm-bindgen", +] + [[package]] name = "vcpkg" version = "0.2.15" @@ -4421,7 +4727,7 @@ dependencies = [ "android-activity", "atomic-waker", "bitflags 2.11.0", - "block2", + "block2 0.5.1", "bytemuck", "calloop 0.13.0", "cfg_aliases 0.2.1", @@ -4578,6 +4884,12 @@ dependencies = [ "wasmparser", ] +[[package]] +name = "writeable" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" + [[package]] name = "x11-dl" version = "2.21.0" @@ -4657,6 +4969,29 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c94451ac9513335b5e23d7a8a2b61a7102398b8cca5160829d313e84c9d98be1" +[[package]] +name = "yoke" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", + "synstructure", +] + [[package]] name = "zbus" version = "4.4.0" @@ -4681,7 +5016,7 @@ dependencies = [ "hex", "nix", "ordered-stream", - "rand", + "rand 0.8.5", "serde", "serde_repr", "sha1", @@ -4690,9 +5025,44 @@ dependencies = [ "uds_windows", "windows-sys 0.52.0", "xdg-home", - "zbus_macros", - "zbus_names", - "zvariant", + "zbus_macros 4.4.0", + "zbus_names 3.0.0", + "zvariant 4.2.0", +] + +[[package]] +name = "zbus" +version = "5.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca82f95dbd3943a40a53cfded6c2d0a2ca26192011846a1810c4256ef92c60bc" +dependencies = [ + "async-broadcast", + "async-executor", + "async-io", + "async-lock", + "async-process", + "async-recursion", + "async-task", + "async-trait", + "blocking", + "enumflags2", + "event-listener", + "futures-core", + "futures-lite", + "hex", + "libc", + "ordered-stream", + "rustix 1.1.4", + "serde", + "serde_repr", + "tracing", + "uds_windows", + "uuid", + "windows-sys 0.61.2", + "winnow", + "zbus_macros 5.14.0", + "zbus_names 4.3.1", + "zvariant 5.10.0", ] [[package]] @@ -4705,7 +5075,22 @@ dependencies = [ "proc-macro2", "quote", "syn 2.0.117", - "zvariant_utils", + "zvariant_utils 2.1.0", +] + +[[package]] +name = "zbus_macros" +version = "5.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897e79616e84aac4b2c46e9132a4f63b93105d54fe8c0e8f6bffc21fa8d49222" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.117", + "zbus_names 4.3.1", + "zvariant 5.10.0", + "zvariant_utils 3.3.0", ] [[package]] @@ -4716,7 +5101,18 @@ checksum = "4b9b1fef7d021261cc16cba64c351d291b715febe0fa10dc3a443ac5a5022e6c" dependencies = [ "serde", "static_assertions", - "zvariant", + "zvariant 4.2.0", +] + +[[package]] +name = "zbus_names" +version = "4.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffd8af6d5b78619bab301ff3c560a5bd22426150253db278f164d6cf3b72c50f" +dependencies = [ + "serde", + "winnow", + "zvariant 5.10.0", ] [[package]] @@ -4745,6 +5141,60 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "zerofrom" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", + "synstructure", +] + +[[package]] +name = "zerotrie" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "zmij" version = "1.0.21" @@ -4761,7 +5211,22 @@ dependencies = [ "enumflags2", "serde", "static_assertions", - "zvariant_derive", + "zvariant_derive 4.2.0", +] + +[[package]] +name = "zvariant" +version = "5.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5708299b21903bbe348e94729f22c49c55d04720a004aa350f1f9c122fd2540b" +dependencies = [ + "endi", + "enumflags2", + "serde", + "url", + "winnow", + "zvariant_derive 5.10.0", + "zvariant_utils 3.3.0", ] [[package]] @@ -4774,7 +5239,20 @@ dependencies = [ "proc-macro2", "quote", "syn 2.0.117", - "zvariant_utils", + "zvariant_utils 2.1.0", +] + +[[package]] +name = "zvariant_derive" +version = "5.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b59b012ebe9c46656f9cc08d8da8b4c726510aef12559da3e5f1bf72780752c" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.117", + "zvariant_utils 3.3.0", ] [[package]] @@ -4787,3 +5265,16 @@ dependencies = [ "quote", "syn 2.0.117", ] + +[[package]] +name = "zvariant_utils" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f75c23a64ef8f40f13a6989991e643554d9bef1d682a281160cf0c1bc389c5e9" +dependencies = [ + "proc-macro2", + "quote", + "serde", + "syn 2.0.117", + "winnow", +] diff --git a/cue/src/app.rs b/cue/src/app.rs index 760c32c..3468790 100644 --- a/cue/src/app.rs +++ b/cue/src/app.rs @@ -1,7 +1,7 @@ use futures::SinkExt; use iced::widget::{ - button, canvas, column, container, pane_grid, pick_list, row, scrollable, text, text_editor, - text_input, + button, canvas, column, container, pane_grid, pick_list, row, rule, scrollable, text, + text_editor, text_input, }; use iced::widget::button::Style as ButtonStyle; use iced::{Border, Color, Element, Length, Subscription, Task, Theme}; @@ -1651,6 +1651,14 @@ impl App { .into(), Tab::Chlorine => row![ + button(text("Start LSV").size(13)) + .style(style_action()) + .padding([6, 16]) + .on_press(Message::StartLsv), + button(text(if self.lsv_manual_peaks { "Manual" } else { "Auto" }).size(13)) + .padding([6, 12]) + .on_press(Message::LsvToggleManual), + rule::Rule::vertical(1), column![ text("Cond mV").size(12), text_input("800", &self.cl_cond_v).on_input(Message::ClCondVChanged).width(70), @@ -1750,12 +1758,28 @@ impl App { }) .width(Length::Fill).height(Length::Fill).into(), Tab::Chlorine => { - let ref_pts = self.cl_ref.as_ref().map(|(pts, _)| pts.as_slice()); - let plot = canvas(crate::plot::ChlorinePlot { - points: &self.cl_points, - reference: ref_pts, + let mut col = column![].spacing(4).height(Length::Fill); + + if !self.lsv_peaks.is_empty() { + let info: Vec = self.lsv_peaks.iter().map(|p| { + use crate::lsv_analysis::PeakKind; + match p.kind { + PeakKind::FreeCl => format!("Free: {:.0}mV {:.2}uA", p.v_mv, p.i_ua), + PeakKind::TotalCl => format!("Total: {:.0}mV {:.2}uA", p.v_mv, p.i_ua), + PeakKind::Crossover => format!("X-over: {:.0}mV", p.v_mv), + } + }).collect(); + col = col.push(text(info.join(" | ")).size(14)); + } + + let voltammogram = canvas(crate::plot::VoltammogramPlot { + points: &self.lsv_points, + reference: self.lsv_ref.as_deref(), + peaks: &self.lsv_peaks, }) - .width(Length::Fill).height(Length::Fill); + .width(Length::Fill).height(Length::FillPortion(1)); + col = col.push(voltammogram); + let mut result_parts: Vec = Vec::new(); if let Some(r) = &self.cl_result { result_parts.push(format!( @@ -1775,12 +1799,19 @@ impl App { )); } } - if result_parts.is_empty() { - plot.into() - } else { - let result_text = text(result_parts.join(" ")).size(14); - column![result_text, plot].spacing(4).height(Length::Fill).into() + if !result_parts.is_empty() { + col = col.push(text(result_parts.join(" ")).size(14)); } + + let ref_pts = self.cl_ref.as_ref().map(|(pts, _)| pts.as_slice()); + let cl_plot = canvas(crate::plot::ChlorinePlot { + points: &self.cl_points, + reference: ref_pts, + }) + .width(Length::Fill).height(Length::FillPortion(1)); + col = col.push(cl_plot); + + col.into() } Tab::Ph | Tab::Calibrate | Tab::Browse => text("").into(), }