clear_selected_vars, select_vars, selected_vars
This commit is contained in:
parent
d078f3a470
commit
0cd6dce47c
|
@ -3,6 +3,7 @@ use std::cell::Cell;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ops::Not;
|
use std::ops::Not;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
use std::sync::Arc;
|
||||||
use wellen::GetItem;
|
use wellen::GetItem;
|
||||||
use zoon::*;
|
use zoon::*;
|
||||||
|
|
||||||
|
@ -32,7 +33,7 @@ struct ScopeForUI {
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ControlsPanel {
|
pub struct ControlsPanel {
|
||||||
selected_scope_ref: Mutable<Option<wellen::ScopeRef>>,
|
selected_scope_ref: Mutable<Option<wellen::ScopeRef>>,
|
||||||
hierarchy: Mutable<Option<Rc<wellen::Hierarchy>>>,
|
hierarchy: Mutable<Option<Arc<wellen::Hierarchy>>>,
|
||||||
selected_var_refs: MutableVec<wellen::VarRef>,
|
selected_var_refs: MutableVec<wellen::VarRef>,
|
||||||
layout: Mutable<Layout>,
|
layout: Mutable<Layout>,
|
||||||
loaded_filename: Mutable<Option<Filename>>,
|
loaded_filename: Mutable<Option<Filename>>,
|
||||||
|
@ -40,7 +41,7 @@ pub struct ControlsPanel {
|
||||||
|
|
||||||
impl ControlsPanel {
|
impl ControlsPanel {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
hierarchy: Mutable<Option<Rc<wellen::Hierarchy>>>,
|
hierarchy: Mutable<Option<Arc<wellen::Hierarchy>>>,
|
||||||
selected_var_refs: MutableVec<wellen::VarRef>,
|
selected_var_refs: MutableVec<wellen::VarRef>,
|
||||||
layout: Mutable<Layout>,
|
layout: Mutable<Layout>,
|
||||||
loaded_filename: Mutable<Option<Filename>>,
|
loaded_filename: Mutable<Option<Filename>>,
|
||||||
|
@ -114,7 +115,7 @@ impl ControlsPanel {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn scopes_panel(&self, hierarchy: Rc<wellen::Hierarchy>) -> impl Element {
|
fn scopes_panel(&self, hierarchy: Arc<wellen::Hierarchy>) -> impl Element {
|
||||||
Column::new()
|
Column::new()
|
||||||
.s(Height::fill())
|
.s(Height::fill())
|
||||||
.s(Scrollbars::y_and_clip_x())
|
.s(Scrollbars::y_and_clip_x())
|
||||||
|
@ -129,7 +130,7 @@ impl ControlsPanel {
|
||||||
.item(self.scopes_list(hierarchy))
|
.item(self.scopes_list(hierarchy))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn scopes_list(&self, hierarchy: Rc<wellen::Hierarchy>) -> impl Element {
|
fn scopes_list(&self, hierarchy: Arc<wellen::Hierarchy>) -> impl Element {
|
||||||
let layout = self.layout.clone();
|
let layout = self.layout.clone();
|
||||||
let mut scopes_for_ui = Vec::new();
|
let mut scopes_for_ui = Vec::new();
|
||||||
let mut max_level_index: usize = 0;
|
let mut max_level_index: usize = 0;
|
||||||
|
@ -379,7 +380,7 @@ impl ControlsPanel {
|
||||||
.label(scope_for_ui.name)
|
.label(scope_for_ui.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn vars_panel(&self, hierarchy: Rc<wellen::Hierarchy>) -> impl Element {
|
fn vars_panel(&self, hierarchy: Arc<wellen::Hierarchy>) -> impl Element {
|
||||||
let selected_scope_ref = self.selected_scope_ref.clone();
|
let selected_scope_ref = self.selected_scope_ref.clone();
|
||||||
Column::new()
|
Column::new()
|
||||||
.s(Align::new().top())
|
.s(Align::new().top())
|
||||||
|
@ -401,7 +402,7 @@ impl ControlsPanel {
|
||||||
fn vars_list(
|
fn vars_list(
|
||||||
&self,
|
&self,
|
||||||
selected_scope_ref: wellen::ScopeRef,
|
selected_scope_ref: wellen::ScopeRef,
|
||||||
hierarchy: Rc<wellen::Hierarchy>,
|
hierarchy: Arc<wellen::Hierarchy>,
|
||||||
) -> impl Element {
|
) -> impl Element {
|
||||||
let vars_for_ui = hierarchy
|
let vars_for_ui = hierarchy
|
||||||
.get(selected_scope_ref)
|
.get(selected_scope_ref)
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
use crate::{platform, script_bridge, Filename, Layout};
|
use crate::{platform, script_bridge, Filename, Layout};
|
||||||
use std::rc::Rc;
|
use std::sync::Arc;
|
||||||
use zoon::*;
|
use zoon::*;
|
||||||
|
|
||||||
pub struct HeaderPanel {
|
pub struct HeaderPanel {
|
||||||
hierarchy: Mutable<Option<Rc<wellen::Hierarchy>>>,
|
hierarchy: Mutable<Option<Arc<wellen::Hierarchy>>>,
|
||||||
layout: Mutable<Layout>,
|
layout: Mutable<Layout>,
|
||||||
loaded_filename: Mutable<Option<Filename>>,
|
loaded_filename: Mutable<Option<Filename>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HeaderPanel {
|
impl HeaderPanel {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
hierarchy: Mutable<Option<Rc<wellen::Hierarchy>>>,
|
hierarchy: Mutable<Option<Arc<wellen::Hierarchy>>>,
|
||||||
layout: Mutable<Layout>,
|
layout: Mutable<Layout>,
|
||||||
loaded_filename: Mutable<Option<Filename>>,
|
loaded_filename: Mutable<Option<Filename>>,
|
||||||
) -> impl Element {
|
) -> impl Element {
|
||||||
|
@ -68,7 +68,7 @@ impl HeaderPanel {
|
||||||
Task::start(async move {
|
Task::start(async move {
|
||||||
if let Some(filename) = platform::pick_and_load_waveform(None).await {
|
if let Some(filename) = platform::pick_and_load_waveform(None).await {
|
||||||
loaded_filename.set_neq(Some(filename));
|
loaded_filename.set_neq(Some(filename));
|
||||||
hierarchy.set(Some(Rc::new(platform::get_hierarchy().await)))
|
hierarchy.set(Some(Arc::new(platform::get_hierarchy().await)))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -267,22 +267,30 @@ impl HeaderPanel {
|
||||||
.family([FontFamily::new("Courier New"), FontFamily::Monospace]))
|
.family([FontFamily::new("Courier New"), FontFamily::Monospace]))
|
||||||
.s(Scrollbars::both())
|
.s(Scrollbars::both())
|
||||||
.s(Height::default().max(100))
|
.s(Height::default().max(100))
|
||||||
.child_signal(command_result.signal_ref(|result| match result {
|
.child_signal(command_result.signal_ref(|result| {
|
||||||
Some(Ok(js_value)) => {
|
fn format_complex_js_value(js_value: &JsValue) -> String {
|
||||||
if let Some(string_value) = js_value.as_string() {
|
let value = format!("{js_value:?}");
|
||||||
string_value
|
let value = value.strip_prefix("JsValue(").unwrap_throw();
|
||||||
} else if let Some(number_value) = js_value.as_f64() {
|
let value = value.strip_suffix(')').unwrap_throw();
|
||||||
number_value.to_string()
|
value.to_owned()
|
||||||
} else if let Some(bool_value) = js_value.as_bool() {
|
}
|
||||||
bool_value.to_string()
|
match result {
|
||||||
} else {
|
Some(Ok(js_value)) => {
|
||||||
format!("{js_value:?}")
|
if let Some(string_value) = js_value.as_string() {
|
||||||
|
string_value
|
||||||
|
} else if let Some(number_value) = js_value.as_f64() {
|
||||||
|
number_value.to_string()
|
||||||
|
} else if let Some(bool_value) = js_value.as_bool() {
|
||||||
|
bool_value.to_string()
|
||||||
|
} else {
|
||||||
|
format_complex_js_value(js_value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Some(Err(js_value)) => {
|
||||||
|
format!("ERROR: {}", format_complex_js_value(js_value))
|
||||||
|
}
|
||||||
|
None => "-".to_owned(),
|
||||||
}
|
}
|
||||||
Some(Err(js_value)) => {
|
|
||||||
format!("Error: {js_value:?}")
|
|
||||||
}
|
|
||||||
None => "-".to_owned(),
|
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use std::rc::Rc;
|
use std::sync::Arc;
|
||||||
use zoon::*;
|
use zoon::*;
|
||||||
|
|
||||||
mod platform;
|
mod platform;
|
||||||
|
@ -25,6 +25,7 @@ type Filename = String;
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct Store {
|
struct Store {
|
||||||
selected_var_refs: MutableVec<wellen::VarRef>,
|
selected_var_refs: MutableVec<wellen::VarRef>,
|
||||||
|
hierarchy: Mutable<Option<Arc<wellen::Hierarchy>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
static STORE: Lazy<Store> = lazy::default();
|
static STORE: Lazy<Store> = lazy::default();
|
||||||
|
@ -39,7 +40,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn root() -> impl Element {
|
fn root() -> impl Element {
|
||||||
let hierarchy: Mutable<Option<Rc<wellen::Hierarchy>>> = <_>::default();
|
let hierarchy = STORE.hierarchy.clone();
|
||||||
let selected_var_refs = STORE.selected_var_refs.clone();
|
let selected_var_refs = STORE.selected_var_refs.clone();
|
||||||
let layout: Mutable<Layout> = <_>::default();
|
let layout: Mutable<Layout> = <_>::default();
|
||||||
let loaded_filename: Mutable<Option<Filename>> = <_>::default();
|
let loaded_filename: Mutable<Option<Filename>> = <_>::default();
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
use crate::STORE;
|
use crate::STORE;
|
||||||
|
use wellen::GetItem;
|
||||||
use zoon::*;
|
use zoon::*;
|
||||||
|
|
||||||
|
type FullVarName = String;
|
||||||
|
|
||||||
#[wasm_bindgen(
|
#[wasm_bindgen(
|
||||||
inline_js = r#"export function strict_eval(code) { "use strict"; return eval?.(`${code}`) }"#
|
inline_js = r#"export function strict_eval(code) { "use strict"; return eval?.(`${code}`) }"#
|
||||||
)]
|
)]
|
||||||
|
@ -14,14 +17,53 @@ pub struct FW;
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
impl FW {
|
impl FW {
|
||||||
|
/// JS: `FW.say_hello()` -> `Hello!`
|
||||||
pub fn say_hello() -> String {
|
pub fn say_hello() -> String {
|
||||||
"Hello!".to_owned()
|
"Hello!".to_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear_variables() -> String {
|
/// JS: `FW.clear_selected_vars()` -> `4`
|
||||||
|
pub fn clear_selected_vars() -> usize {
|
||||||
let mut vars = STORE.selected_var_refs.lock_mut();
|
let mut vars = STORE.selected_var_refs.lock_mut();
|
||||||
let var_count = vars.len();
|
let var_count = vars.len();
|
||||||
vars.clear();
|
vars.clear();
|
||||||
format!("{var_count} variables cleared")
|
var_count
|
||||||
|
}
|
||||||
|
|
||||||
|
/// JS: `FW.select_vars(["simple_tb.s.A", "simple_tb.s.B"])` -> `2`
|
||||||
|
pub fn select_vars(full_var_names: Vec<FullVarName>) -> usize {
|
||||||
|
if let Some(hierarchy) = STORE.hierarchy.get_cloned() {
|
||||||
|
let mut new_var_refs = Vec::new();
|
||||||
|
for full_var_name in full_var_names {
|
||||||
|
let path_with_name = full_var_name.split_terminator('.').collect::<Vec<_>>();
|
||||||
|
if let Some((name, path)) = path_with_name.split_last() {
|
||||||
|
if let Some(var_ref) = hierarchy.lookup_var(path, name) {
|
||||||
|
new_var_refs.push(var_ref);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let var_ref_count = new_var_refs.len();
|
||||||
|
STORE.selected_var_refs.lock_mut().replace(new_var_refs);
|
||||||
|
return var_ref_count;
|
||||||
|
}
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn loaded_filename() -> String {
|
||||||
|
format!("todo loaded filename")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// JS: `FW.selected_vars()` -> `["simple_tb.s.A", "simple_tb.s.B"]`
|
||||||
|
pub fn selected_vars() -> Vec<FullVarName> {
|
||||||
|
if let Some(hierarchy) = STORE.hierarchy.get_cloned() {
|
||||||
|
let mut full_var_names = Vec::new();
|
||||||
|
for var_ref in STORE.selected_var_refs.lock_ref().as_slice() {
|
||||||
|
let var = hierarchy.get(*var_ref);
|
||||||
|
let var_name = var.full_name(&hierarchy);
|
||||||
|
full_var_names.push(var_name);
|
||||||
|
}
|
||||||
|
return full_var_names;
|
||||||
|
}
|
||||||
|
Vec::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::platform;
|
use crate::platform;
|
||||||
use std::rc::Rc;
|
use std::sync::Arc;
|
||||||
use wellen::GetItem;
|
use wellen::GetItem;
|
||||||
use zoon::*;
|
use zoon::*;
|
||||||
|
|
||||||
|
@ -12,13 +12,13 @@ const ROW_GAP: u32 = 4;
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct WaveformPanel {
|
pub struct WaveformPanel {
|
||||||
selected_var_refs: MutableVec<wellen::VarRef>,
|
selected_var_refs: MutableVec<wellen::VarRef>,
|
||||||
hierarchy: Mutable<Option<Rc<wellen::Hierarchy>>>,
|
hierarchy: Mutable<Option<Arc<wellen::Hierarchy>>>,
|
||||||
canvas_controller: Mutable<ReadOnlyMutable<Option<PixiController>>>,
|
canvas_controller: Mutable<ReadOnlyMutable<Option<PixiController>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WaveformPanel {
|
impl WaveformPanel {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
hierarchy: Mutable<Option<Rc<wellen::Hierarchy>>>,
|
hierarchy: Mutable<Option<Arc<wellen::Hierarchy>>>,
|
||||||
selected_var_refs: MutableVec<wellen::VarRef>,
|
selected_var_refs: MutableVec<wellen::VarRef>,
|
||||||
) -> impl Element {
|
) -> impl Element {
|
||||||
Self {
|
Self {
|
||||||
|
@ -111,7 +111,7 @@ impl WaveformPanel {
|
||||||
|
|
||||||
async fn push_var(
|
async fn push_var(
|
||||||
controller: &PixiController,
|
controller: &PixiController,
|
||||||
hierarchy: &Mutable<Option<Rc<wellen::Hierarchy>>>,
|
hierarchy: &Mutable<Option<Arc<wellen::Hierarchy>>>,
|
||||||
var_ref: wellen::VarRef,
|
var_ref: wellen::VarRef,
|
||||||
) {
|
) {
|
||||||
let hierarchy = hierarchy.get_cloned().unwrap();
|
let hierarchy = hierarchy.get_cloned().unwrap();
|
||||||
|
|
|
@ -35316,10 +35316,12 @@ var VarSignalRow = class {
|
||||||
this.draw();
|
this.draw();
|
||||||
}
|
}
|
||||||
draw() {
|
draw() {
|
||||||
if (this.app === null || this.app.screen === null) {
|
if (this?.app?.screen?.width === void 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.row_container_background.width = this.app.screen.width;
|
if (this?.row_container_background?._texture?.orig?.width !== void 0) {
|
||||||
|
this.row_container_background.width = this.app.screen.width;
|
||||||
|
}
|
||||||
this.signal_blocks_container.removeChildren();
|
this.signal_blocks_container.removeChildren();
|
||||||
this.timeline.blocks.forEach((timeline_block) => {
|
this.timeline.blocks.forEach((timeline_block) => {
|
||||||
const signal_block = new Container();
|
const signal_block = new Container();
|
||||||
|
|
|
@ -275,12 +275,14 @@ class VarSignalRow {
|
||||||
|
|
||||||
draw() {
|
draw() {
|
||||||
// Screen can be null when we are, for instance, switching between miller columns and tree layout
|
// Screen can be null when we are, for instance, switching between miller columns and tree layout
|
||||||
// and then the canvas has to be recreated
|
// and then the canvas has to be recreated.
|
||||||
if (this.app === null || this.app.screen === null) {
|
if (this?.app?.screen?.width === undefined) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// Workaround for "TypeError: Cannot read properties of null (reading 'orig')"
|
||||||
this.row_container_background.width = this.app.screen.width;
|
if (this?.row_container_background?._texture?.orig?.width !== undefined) {
|
||||||
|
this.row_container_background.width = this.app.screen.width;
|
||||||
|
}
|
||||||
|
|
||||||
// @TODO optimize by reusing a pool of blocks instead or removing all children on every redraw?
|
// @TODO optimize by reusing a pool of blocks instead or removing all children on every redraw?
|
||||||
this.signal_blocks_container.removeChildren();
|
this.signal_blocks_container.removeChildren();
|
||||||
|
|
Loading…
Reference in a new issue