clear_selected_vars, select_vars, selected_vars

This commit is contained in:
Martin Kavík 2024-06-17 18:06:36 +02:00
parent d078f3a470
commit 0cd6dce47c
7 changed files with 94 additions and 38 deletions

View file

@ -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)

View file

@ -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(),
})) }))
} }
} }

View file

@ -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();

View file

@ -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()
} }
} }

View file

@ -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();

View file

@ -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();

View file

@ -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();