mirror of
https://github.com/ilya-zlobintsev/LACT.git
synced 2025-02-25 18:55:26 -06:00
feat: wip egui plot
This commit is contained in:
222
Cargo.lock
generated
222
Cargo.lock
generated
@@ -2,6 +2,22 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "ab_glyph"
|
||||
version = "0.2.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec3672c180e71eeaaac3a541fbbc5f5ad4def8b747c595ad30d674e43049f7b0"
|
||||
dependencies = [
|
||||
"ab_glyph_rasterizer",
|
||||
"owned_ttf_parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ab_glyph_rasterizer"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046"
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.24.2"
|
||||
@@ -597,12 +613,73 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ecolor"
|
||||
version = "0.31.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "878e9005799dd739e5d5d89ff7480491c12d0af571d44399bcaefa1ee172dd76"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"emath",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "egui"
|
||||
version = "0.31.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d2768eaa6d5c80a6e2a008da1f0e062dff3c83eb2b28605ea2d0732d46e74d6"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"bitflags 2.8.0",
|
||||
"emath",
|
||||
"epaint",
|
||||
"nohash-hasher",
|
||||
"profiling",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "egui_glow"
|
||||
version = "0.31.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a53e2374a964c3c793cb0b8ead81bca631f24974bc0b747d1a5622f4e39fdd0"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"bytemuck",
|
||||
"egui",
|
||||
"glow",
|
||||
"log",
|
||||
"memoffset",
|
||||
"profiling",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "egui_plot"
|
||||
version = "0.31.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1794c66fb727dac28dffed2e4b548e5118d1cccc331d368a35411d68725dde71"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"egui",
|
||||
"emath",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
|
||||
|
||||
[[package]]
|
||||
name = "emath"
|
||||
version = "0.31.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55b7b6be5ad1d247f11738b0e4699d9c20005ed366f2c29f5ec1f8e1de180bc2"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "encode_unicode"
|
||||
version = "1.0.0"
|
||||
@@ -648,6 +725,41 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "epaint"
|
||||
version = "0.31.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "275b665a7b9611d8317485187e5458750850f9e64604d3c58434bb3fc1d22915"
|
||||
dependencies = [
|
||||
"ab_glyph",
|
||||
"ahash",
|
||||
"bytemuck",
|
||||
"ecolor",
|
||||
"emath",
|
||||
"epaint_default_fonts",
|
||||
"nohash-hasher",
|
||||
"parking_lot",
|
||||
"profiling",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "epaint_default_fonts"
|
||||
version = "0.31.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9343d356d7cac894dacafc161b4654e0881301097bdf32a122ed503d97cb94b6"
|
||||
|
||||
[[package]]
|
||||
name = "epoxy"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b96028ce3ff03972312fd8243281858e80fc0f9838b1f035676b6c199214d9e"
|
||||
dependencies = [
|
||||
"gl_generator",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
"shared_library",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.1"
|
||||
@@ -932,6 +1044,27 @@ dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gl_generator"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a795170cbd85b5a7baa58d6d7525cae6a03e486859860c220f7ebbbdd379d0a"
|
||||
dependencies = [
|
||||
"khronos_api",
|
||||
"log",
|
||||
"xml-rs 0.7.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gl_loader"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e32d96dd5f881490e537041d5532320812ba096097f07fccb4626578da0b99d3"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glib"
|
||||
version = "0.20.7"
|
||||
@@ -982,6 +1115,18 @@ version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2"
|
||||
|
||||
[[package]]
|
||||
name = "glow"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c5e5ea60d70410161c8bf5da3fdfeaa1c72ed2c15f8bbb9d19fe3a4fad085f08"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"slotmap",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gobject-sys"
|
||||
version = "0.20.7"
|
||||
@@ -1047,6 +1192,18 @@ dependencies = [
|
||||
"system-deps",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gtk-egui-area"
|
||||
version = "0.1.1"
|
||||
dependencies = [
|
||||
"egui",
|
||||
"egui_glow",
|
||||
"epoxy",
|
||||
"gl_loader",
|
||||
"gtk4",
|
||||
"libloading 0.8.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gtk4"
|
||||
version = "0.9.5"
|
||||
@@ -1257,6 +1414,12 @@ dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "khronos_api"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "037ab472c33f67b5fbd3e9163a2645319e5356fcd355efa6d4eb7fff4bbcb554"
|
||||
|
||||
[[package]]
|
||||
name = "kqueue"
|
||||
version = "1.0.8"
|
||||
@@ -1358,6 +1521,8 @@ dependencies = [
|
||||
"anyhow",
|
||||
"cairo-rs",
|
||||
"chrono",
|
||||
"egui_plot",
|
||||
"gtk-egui-area",
|
||||
"gtk4",
|
||||
"itertools",
|
||||
"lact-client",
|
||||
@@ -1613,6 +1778,12 @@ dependencies = [
|
||||
"memoffset",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nohash-hasher"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451"
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.3"
|
||||
@@ -1751,6 +1922,15 @@ version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
|
||||
|
||||
[[package]]
|
||||
name = "owned_ttf_parser"
|
||||
version = "0.25.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22ec719bbf3b2a81c109a4e20b1f129b5566b7dce654bc3872f6a05abf82b2c4"
|
||||
dependencies = [
|
||||
"ttf-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pango"
|
||||
version = "0.20.7"
|
||||
@@ -1909,6 +2089,12 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "profiling"
|
||||
version = "1.0.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "afbdc74edc00b6f6a218ca6a5364d6226a259d4b8ea1af4a0ea063f27e179f4d"
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.38"
|
||||
@@ -2208,6 +2394,16 @@ dependencies = [
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shared_library"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a9e7e0f2bfae24d8a5b5a66c5b257a83c7412304311512a0c054cd5e619da11"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.3.0"
|
||||
@@ -2248,6 +2444,15 @@ dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slotmap"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a"
|
||||
dependencies = [
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.13.2"
|
||||
@@ -2580,6 +2785,12 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ttf-parser"
|
||||
version = "0.25.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31"
|
||||
|
||||
[[package]]
|
||||
name = "uds_windows"
|
||||
version = "1.1.0"
|
||||
@@ -2645,7 +2856,7 @@ version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81086c28be67a8759cd80cbb3c8f7b520e0874605fc5eb74d5a1c9c2d1878e79"
|
||||
dependencies = [
|
||||
"xml-rs",
|
||||
"xml-rs 0.8.25",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3003,6 +3214,15 @@ dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xml-rs"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c1cb601d29fe2c2ac60a2b2e5e293994d87a1f6fa9687a31a15270f909be9c2"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xml-rs"
|
||||
version = "0.8.25"
|
||||
|
||||
@@ -34,8 +34,10 @@ plotters = { version = "0.3.5", default-features = false, features = [
|
||||
plotters-cairo = "0.7.0"
|
||||
cairo-rs = { version = "0.20", default-features = false }
|
||||
itertools = "0.13.0"
|
||||
gtk-egui-area = { path = "../../gtk-egui-area" }
|
||||
|
||||
thread-priority = "1.1.0"
|
||||
egui_plot = "0.31.0"
|
||||
|
||||
[dev-dependencies]
|
||||
pretty_assertions = "1.4.0"
|
||||
|
||||
@@ -38,6 +38,7 @@ impl relm4::Component for GraphsWindow {
|
||||
set_margin_all: 10,
|
||||
set_row_spacing: 20,
|
||||
set_column_spacing: 20,
|
||||
set_column_homogeneous: true,
|
||||
|
||||
attach[0, 0, 1, 1]: temperature_plot = &Plot {
|
||||
set_title: "Temperature",
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
use chrono::NaiveDateTime;
|
||||
use egui_plot::AxisHints;
|
||||
use egui_plot::PlotBounds;
|
||||
use egui_plot::PlotPoint;
|
||||
use egui_plot::PlotPoints;
|
||||
use glib::Properties;
|
||||
|
||||
use gtk::{glib, prelude::*, subclass::prelude::*};
|
||||
use gtk_egui_area::egui;
|
||||
use gtk_egui_area::EguiArea;
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use super::render_thread::{RenderRequest, RenderThread};
|
||||
|
||||
#[derive(Properties, Default)]
|
||||
#[properties(wrapper_type = super::Plot)]
|
||||
pub struct Plot {
|
||||
@@ -24,7 +28,6 @@ pub struct Plot {
|
||||
secondary_y_label_area_relative_size: Cell<f64>,
|
||||
pub(super) data: RefCell<PlotData>,
|
||||
pub(super) dirty: Cell<bool>,
|
||||
render_thread: RenderThread,
|
||||
#[property(get, set)]
|
||||
time_period_seconds: Cell<i64>,
|
||||
}
|
||||
@@ -33,7 +36,7 @@ pub struct Plot {
|
||||
impl ObjectSubclass for Plot {
|
||||
const NAME: &'static str = "Plot";
|
||||
type Type = super::Plot;
|
||||
type ParentType = gtk::Widget;
|
||||
type ParentType = gtk::Box;
|
||||
}
|
||||
|
||||
#[glib::derived_properties]
|
||||
@@ -41,58 +44,62 @@ impl ObjectImpl for Plot {
|
||||
fn constructed(&self) {
|
||||
self.parent_constructed();
|
||||
|
||||
let obj = self.obj();
|
||||
let obj = self.obj().clone();
|
||||
obj.set_height_request(250);
|
||||
obj.set_hexpand(true);
|
||||
obj.set_vexpand(true);
|
||||
|
||||
let area = EguiArea::new(move |ctx| {
|
||||
egui::CentralPanel::default().show(ctx, |ui| {
|
||||
let data = obj.imp().data.borrow();
|
||||
|
||||
egui_plot::Plot::new(obj.title())
|
||||
.legend(egui_plot::Legend::default().position(egui_plot::Corner::RightBottom))
|
||||
.custom_x_axes(vec![AxisHints::new_x().label("Time").formatter(
|
||||
|point, _| {
|
||||
let time = chrono::DateTime::from_timestamp_millis(point.value as i64)
|
||||
.unwrap()
|
||||
.naive_local()
|
||||
.time();
|
||||
time.to_string()
|
||||
},
|
||||
)])
|
||||
.show(ui, |plot_ui| {
|
||||
let max_x = data
|
||||
.line_series_iter()
|
||||
.next()
|
||||
.and_then(|(_, points)| points.last())
|
||||
.map(|point| point.x)
|
||||
.unwrap_or_default();
|
||||
let min_x = max_x - (obj.time_period_seconds() * 1000) as f64;
|
||||
|
||||
let bounds = PlotBounds::from_min_max(
|
||||
[min_x, -f64::INFINITY],
|
||||
[max_x, f64::INFINITY],
|
||||
);
|
||||
plot_ui.set_plot_bounds(bounds);
|
||||
plot_ui.set_auto_bounds([false, true]);
|
||||
|
||||
for (name, points) in data.line_series_iter() {
|
||||
plot_ui.line(
|
||||
egui_plot::Line::new(PlotPoints::Borrowed(points)).name(name),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl WidgetImpl for Plot {
|
||||
fn snapshot(&self, snapshot: >k::Snapshot) {
|
||||
let width = self.obj().width() as u32;
|
||||
let height = self.obj().height() as u32;
|
||||
|
||||
if width == 0 || height == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
let last_texture = self.render_thread.get_last_texture();
|
||||
let size_changed = last_texture
|
||||
.as_ref()
|
||||
.map(|texture| (texture.width() as u32, texture.height() as u32) != (width, height))
|
||||
.unwrap_or(true);
|
||||
|
||||
if self.dirty.replace(false) || size_changed {
|
||||
self.render_thread.replace_render_request(RenderRequest {
|
||||
data: self.data.borrow().clone(),
|
||||
width,
|
||||
height,
|
||||
title: self.title.borrow().clone(),
|
||||
value_suffix: self.value_suffix.borrow().clone(),
|
||||
secondary_value_suffix: self.secondary_value_suffix.borrow().clone(),
|
||||
y_label_area_relative_size: self.y_label_area_relative_size.get(),
|
||||
secondary_y_label_relative_area_size: self
|
||||
.secondary_y_label_area_relative_size
|
||||
.get(),
|
||||
supersample_factor: 4,
|
||||
time_period_seconds: self.time_period_seconds.get(),
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
// Rendering is always behind by at least one frame, but it's not an issue
|
||||
if let Some(texture) = last_texture {
|
||||
let bounds = gtk::graphene::Rect::new(0.0, 0.0, width as f32, height as f32);
|
||||
// Uses by default Trillinear texture filtering, which is quite good at 4x supersampling
|
||||
snapshot.append_texture(&texture, &bounds);
|
||||
}
|
||||
});
|
||||
self.obj().append(&area);
|
||||
}
|
||||
}
|
||||
|
||||
impl WidgetImpl for Plot {}
|
||||
|
||||
impl BoxImpl for Plot {}
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
pub struct PlotData {
|
||||
pub(super) line_series: BTreeMap<String, Vec<(i64, f64)>>,
|
||||
pub(super) secondary_line_series: BTreeMap<String, Vec<(i64, f64)>>,
|
||||
pub(super) line_series: BTreeMap<String, Vec<PlotPoint>>,
|
||||
pub(super) secondary_line_series: BTreeMap<String, Vec<PlotPoint>>,
|
||||
pub(super) throttling: Vec<(i64, (String, bool))>,
|
||||
}
|
||||
|
||||
@@ -109,7 +116,10 @@ impl PlotData {
|
||||
self.line_series
|
||||
.entry(name.to_owned())
|
||||
.or_default()
|
||||
.push((time.and_utc().timestamp_millis(), point));
|
||||
.push(PlotPoint::new(
|
||||
time.and_utc().timestamp_millis() as f64,
|
||||
point,
|
||||
));
|
||||
}
|
||||
|
||||
pub fn push_secondary_line_series_with_time(
|
||||
@@ -121,7 +131,10 @@ impl PlotData {
|
||||
self.secondary_line_series
|
||||
.entry(name.to_owned())
|
||||
.or_default()
|
||||
.push((time.and_utc().timestamp_millis(), point));
|
||||
.push(PlotPoint::new(
|
||||
time.and_utc().timestamp_millis() as f64,
|
||||
point,
|
||||
));
|
||||
}
|
||||
|
||||
pub fn push_throttling(&mut self, name: &str, point: bool) {
|
||||
@@ -134,11 +147,11 @@ impl PlotData {
|
||||
));
|
||||
}
|
||||
|
||||
pub fn line_series_iter(&self) -> impl Iterator<Item = (&String, &Vec<(i64, f64)>)> {
|
||||
pub fn line_series_iter(&self) -> impl Iterator<Item = (&String, &Vec<PlotPoint>)> {
|
||||
self.line_series.iter()
|
||||
}
|
||||
|
||||
pub fn secondary_line_series_iter(&self) -> impl Iterator<Item = (&String, &Vec<(i64, f64)>)> {
|
||||
pub fn secondary_line_series_iter(&self) -> impl Iterator<Item = (&String, &Vec<PlotPoint>)> {
|
||||
self.secondary_line_series.iter()
|
||||
}
|
||||
|
||||
@@ -151,23 +164,17 @@ impl PlotData {
|
||||
pub fn trim_data(&mut self, last_seconds: i64) {
|
||||
// Limit data to N seconds
|
||||
for data in self.line_series.values_mut() {
|
||||
let maximum_point = data
|
||||
.last()
|
||||
.map(|(date_time, _)| *date_time)
|
||||
.unwrap_or_default();
|
||||
let maximum_point = data.last().map(|point| point.x as i64).unwrap_or_default();
|
||||
|
||||
data.retain(|(time_point, _)| ((maximum_point - *time_point) / 1000) < last_seconds);
|
||||
data.retain(|point| ((maximum_point - point.x as i64) / 1000) < last_seconds);
|
||||
}
|
||||
|
||||
self.line_series.retain(|_, data| !data.is_empty());
|
||||
|
||||
for data in self.secondary_line_series.values_mut() {
|
||||
let maximum_point = data
|
||||
.last()
|
||||
.map(|(date_time, _)| *date_time)
|
||||
.unwrap_or_default();
|
||||
let maximum_point = data.last().map(|point| point.x as i64).unwrap_or_default();
|
||||
|
||||
data.retain(|(time_point, _)| ((maximum_point - *time_point) / 1000) < last_seconds);
|
||||
data.retain(|point| ((maximum_point - point.x as i64) / 1000) < last_seconds);
|
||||
}
|
||||
|
||||
self.secondary_line_series
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
mod cubic_spline;
|
||||
// mod cubic_spline;
|
||||
mod imp;
|
||||
mod render_thread;
|
||||
mod to_texture_ext;
|
||||
|
||||
use std::cell::RefMut;
|
||||
// mod render_thread;
|
||||
// mod to_texture_ext;
|
||||
|
||||
pub use imp::PlotData;
|
||||
use std::cell::RefMut;
|
||||
|
||||
use gtk::glib::{self, subclass::types::ObjectSubclassIsExt, Object};
|
||||
|
||||
glib::wrapper! {
|
||||
pub struct Plot(ObjectSubclass<imp::Plot>)
|
||||
@extends gtk::Widget;
|
||||
@extends gtk::Widget, gtk::Box;
|
||||
}
|
||||
|
||||
impl Default for Plot {
|
||||
|
||||
Reference in New Issue
Block a user