platform::load_file_with_selected_vars, simple_vcd.fw.js
This commit is contained in:
parent
26a8250220
commit
1160efe0e3
|
@ -79,7 +79,7 @@ impl HeaderPanel {
|
||||||
let (hovered, hovered_signal) = Mutable::new_and_signal(false);
|
let (hovered, hovered_signal) = Mutable::new_and_signal(false);
|
||||||
let hierarchy = self.hierarchy.clone();
|
let hierarchy = self.hierarchy.clone();
|
||||||
let loaded_filename = self.loaded_filename.clone();
|
let loaded_filename = self.loaded_filename.clone();
|
||||||
let file_input_id = "file_input";
|
let file_input_id = "file_input_for_load_waveform_button";
|
||||||
Row::new()
|
Row::new()
|
||||||
.item(
|
.item(
|
||||||
Label::new()
|
Label::new()
|
||||||
|
|
|
@ -14,6 +14,7 @@ mod browser;
|
||||||
use browser as platform;
|
use browser as platform;
|
||||||
|
|
||||||
type Filename = String;
|
type Filename = String;
|
||||||
|
type JavascriptCode = String;
|
||||||
|
|
||||||
pub async fn show_window() {
|
pub async fn show_window() {
|
||||||
platform::show_window().await
|
platform::show_window().await
|
||||||
|
@ -25,6 +26,12 @@ pub async fn pick_and_load_waveform(file: Option<gloo_file::File>) -> Option<Fil
|
||||||
platform::pick_and_load_waveform(file).await
|
platform::pick_and_load_waveform(file).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @TODO allow only supported file type (*.fw.js)
|
||||||
|
// @TODO remove the `file` parameter once we don't have to use FileInput element
|
||||||
|
pub async fn load_file_with_selected_vars(file: Option<gloo_file::File>) -> Option<JavascriptCode> {
|
||||||
|
platform::load_file_with_selected_vars(file).await
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn get_hierarchy() -> wellen::Hierarchy {
|
pub async fn get_hierarchy() -> wellen::Hierarchy {
|
||||||
platform::get_hierarchy().await
|
platform::get_hierarchy().await
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,6 +67,22 @@ pub(super) async fn pick_and_load_waveform(
|
||||||
// Some(file.name())
|
// Some(file.name())
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
// @TODO allow only supported file type (*.fw.js)
|
||||||
|
// @TODO remove the `file` parameter once we don't have to use FileInput element
|
||||||
|
pub async fn load_file_with_selected_vars(
|
||||||
|
file: Option<gloo_file::File>,
|
||||||
|
) -> Option<super::JavascriptCode> {
|
||||||
|
let file = file.unwrap_throw();
|
||||||
|
|
||||||
|
let javascript_code = gloo_file::futures::read_as_text(&file).await.unwrap_throw();
|
||||||
|
|
||||||
|
Some(javascript_code)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @TODO Use alternative `load_file_with_selected_vars` version once `showOpenFilePicker` is supported by Safari and Firefox
|
||||||
|
// https://caniuse.com/mdn-api_window_showopenfilepicker
|
||||||
|
// (see the `pick_and_load_waveform` method above)
|
||||||
|
|
||||||
pub(super) async fn get_hierarchy() -> wellen::Hierarchy {
|
pub(super) async fn get_hierarchy() -> wellen::Hierarchy {
|
||||||
let waveform = BROWSER_PLATFORM_STORE.waveform.lock().unwrap_throw();
|
let waveform = BROWSER_PLATFORM_STORE.waveform.lock().unwrap_throw();
|
||||||
let hierarchy = waveform.as_ref().unwrap_throw().hierarchy();
|
let hierarchy = waveform.as_ref().unwrap_throw().hierarchy();
|
||||||
|
|
|
@ -13,6 +13,15 @@ pub(super) async fn pick_and_load_waveform(
|
||||||
.as_string()
|
.as_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) async fn load_file_with_selected_vars(
|
||||||
|
_file: Option<gloo_file::File>,
|
||||||
|
) -> Option<super::JavascriptCode> {
|
||||||
|
tauri_glue::load_file_with_selected_vars()
|
||||||
|
.await
|
||||||
|
.unwrap_throw()
|
||||||
|
.as_string()
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) async fn get_hierarchy() -> wellen::Hierarchy {
|
pub(super) async fn get_hierarchy() -> wellen::Hierarchy {
|
||||||
serde_wasm_bindgen::from_value(tauri_glue::get_hierarchy().await.unwrap_throw()).unwrap_throw()
|
serde_wasm_bindgen::from_value(tauri_glue::get_hierarchy().await.unwrap_throw()).unwrap_throw()
|
||||||
}
|
}
|
||||||
|
@ -59,6 +68,9 @@ mod tauri_glue {
|
||||||
#[wasm_bindgen(catch)]
|
#[wasm_bindgen(catch)]
|
||||||
pub async fn pick_and_load_waveform() -> Result<JsValue, JsValue>;
|
pub async fn pick_and_load_waveform() -> Result<JsValue, JsValue>;
|
||||||
|
|
||||||
|
#[wasm_bindgen(catch)]
|
||||||
|
pub async fn load_file_with_selected_vars() -> Result<JsValue, JsValue>;
|
||||||
|
|
||||||
#[wasm_bindgen(catch)]
|
#[wasm_bindgen(catch)]
|
||||||
pub async fn get_hierarchy() -> Result<JsValue, JsValue>;
|
pub async fn get_hierarchy() -> Result<JsValue, JsValue>;
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::platform;
|
use crate::{platform, script_bridge};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use wellen::GetItem;
|
use wellen::GetItem;
|
||||||
use zoon::*;
|
use zoon::*;
|
||||||
|
@ -46,7 +46,7 @@ impl WaveformPanel {
|
||||||
.s(Gap::new().x(20))
|
.s(Gap::new().x(20))
|
||||||
.s(Width::fill())
|
.s(Width::fill())
|
||||||
.item(Spacer::fill())
|
.item(Spacer::fill())
|
||||||
.item(self.save_load_selected_vars_buttons())
|
.item(self.load_save_selected_vars_buttons())
|
||||||
.item(self.keys_info())
|
.item(self.keys_info())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@ impl WaveformPanel {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn save_load_selected_vars_buttons(&self) -> impl Element {
|
fn load_save_selected_vars_buttons(&self) -> impl Element {
|
||||||
Row::new()
|
Row::new()
|
||||||
.s(Gap::new().x(20))
|
.s(Gap::new().x(20))
|
||||||
.item(self.load_selected_vars_button())
|
.item(self.load_selected_vars_button())
|
||||||
|
@ -76,6 +76,7 @@ impl WaveformPanel {
|
||||||
.item(self.save_selected_vars_button())
|
.item(self.save_selected_vars_button())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(FASTWAVE_PLATFORM = "TAURI")]
|
||||||
fn load_selected_vars_button(&self) -> impl Element {
|
fn load_selected_vars_button(&self) -> impl Element {
|
||||||
let (hovered, hovered_signal) = Mutable::new_and_signal(false);
|
let (hovered, hovered_signal) = Mutable::new_and_signal(false);
|
||||||
Button::new()
|
Button::new()
|
||||||
|
@ -83,10 +84,85 @@ impl WaveformPanel {
|
||||||
.s(Background::new().color_signal(
|
.s(Background::new().color_signal(
|
||||||
hovered_signal.map_bool(|| color!("MediumSlateBlue"), || color!("SlateBlue")),
|
hovered_signal.map_bool(|| color!("MediumSlateBlue"), || color!("SlateBlue")),
|
||||||
))
|
))
|
||||||
|
.s(Align::new().left())
|
||||||
.s(RoundedCorners::all(15))
|
.s(RoundedCorners::all(15))
|
||||||
.label("Load")
|
.label("Load")
|
||||||
.on_hovered_change(move |is_hovered| hovered.set_neq(is_hovered))
|
.on_hovered_change(move |is_hovered| hovered.set_neq(is_hovered))
|
||||||
.on_press(move || zoon::println!("LOAD!"))
|
.on_press(|| {
|
||||||
|
Task::start(async move {
|
||||||
|
if let Some(javascript_code) =
|
||||||
|
platform::load_file_with_selected_vars(None).await
|
||||||
|
{
|
||||||
|
match script_bridge::strict_eval(&javascript_code) {
|
||||||
|
Ok(js_value) => {
|
||||||
|
zoon::println!("File with selected vars loaded: {js_value:?}")
|
||||||
|
}
|
||||||
|
Err(js_value) => {
|
||||||
|
zoon::eprintln!(
|
||||||
|
"Failed to load file with selected vars: {js_value:?}"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(FASTWAVE_PLATFORM = "BROWSER")]
|
||||||
|
fn load_selected_vars_button(&self) -> impl Element {
|
||||||
|
let (hovered, hovered_signal) = Mutable::new_and_signal(false);
|
||||||
|
let file_input_id = "file_input_for_load_selected_vars_button";
|
||||||
|
Row::new()
|
||||||
|
.item(
|
||||||
|
Label::new()
|
||||||
|
.s(Padding::new().x(20).y(10))
|
||||||
|
.s(Background::new().color_signal(
|
||||||
|
hovered_signal
|
||||||
|
.map_bool(|| color!("MediumSlateBlue"), || color!("SlateBlue")),
|
||||||
|
))
|
||||||
|
.s(Align::new().left())
|
||||||
|
.s(RoundedCorners::all(15))
|
||||||
|
.s(Cursor::new(CursorIcon::Pointer))
|
||||||
|
.label("Load")
|
||||||
|
.on_hovered_change(move |is_hovered| hovered.set_neq(is_hovered))
|
||||||
|
.for_input(file_input_id),
|
||||||
|
)
|
||||||
|
.item(
|
||||||
|
// @TODO https://github.com/MoonZoon/MoonZoon/issues/39
|
||||||
|
// + https://developer.mozilla.org/en-US/docs/Web/API/File_API/Using_files_from_web_applications#using_hidden_file_input_elements_using_the_click_method
|
||||||
|
TextInput::new().id(file_input_id).update_raw_el(|raw_el| {
|
||||||
|
let dom_element = raw_el.dom_element();
|
||||||
|
raw_el
|
||||||
|
.style("display", "none")
|
||||||
|
.attr("type", "file")
|
||||||
|
.event_handler(move |_: events::Input| {
|
||||||
|
let Some(file_list) =
|
||||||
|
dom_element.files().map(gloo_file::FileList::from)
|
||||||
|
else {
|
||||||
|
zoon::println!("file list is `None`");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let Some(file) = file_list.first().cloned() else {
|
||||||
|
zoon::println!("file list is empty");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
Task::start(async move {
|
||||||
|
if let Some(javascript_code) =
|
||||||
|
platform::load_file_with_selected_vars(Some(file)).await
|
||||||
|
{
|
||||||
|
match script_bridge::strict_eval(&javascript_code) {
|
||||||
|
Ok(js_value) => zoon::println!(
|
||||||
|
"File with selected vars loaded: {js_value:?}"
|
||||||
|
),
|
||||||
|
Err(js_value) => zoon::eprintln!(
|
||||||
|
"Failed to load file with selected vars: {js_value:?}"
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn save_selected_vars_button(&self) -> impl Element {
|
fn save_selected_vars_button(&self) -> impl Element {
|
||||||
|
|
|
@ -2517,6 +2517,9 @@ async function show_window() {
|
||||||
async function pick_and_load_waveform() {
|
async function pick_and_load_waveform() {
|
||||||
return await invoke2("pick_and_load_waveform");
|
return await invoke2("pick_and_load_waveform");
|
||||||
}
|
}
|
||||||
|
async function load_file_with_selected_vars() {
|
||||||
|
return await invoke2("load_file_with_selected_vars");
|
||||||
|
}
|
||||||
async function get_hierarchy() {
|
async function get_hierarchy() {
|
||||||
return await invoke2("get_hierarchy");
|
return await invoke2("get_hierarchy");
|
||||||
}
|
}
|
||||||
|
@ -2535,6 +2538,7 @@ async function unload_signal(signal_ref_index) {
|
||||||
}
|
}
|
||||||
export {
|
export {
|
||||||
get_hierarchy,
|
get_hierarchy,
|
||||||
|
load_file_with_selected_vars,
|
||||||
load_signal_and_get_timeline,
|
load_signal_and_get_timeline,
|
||||||
pick_and_load_waveform,
|
pick_and_load_waveform,
|
||||||
show_window,
|
show_window,
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { core } from '@tauri-apps/api'
|
||||||
const invoke = core.invoke;
|
const invoke = core.invoke;
|
||||||
|
|
||||||
type Filename = string;
|
type Filename = string;
|
||||||
|
type JavascriptCode = string;
|
||||||
type WellenHierarchy = unknown;
|
type WellenHierarchy = unknown;
|
||||||
type Timeline = unknown;
|
type Timeline = unknown;
|
||||||
type VarFormat = unknown;
|
type VarFormat = unknown;
|
||||||
|
@ -17,6 +18,10 @@ export async function pick_and_load_waveform(): Promise<Filename | undefined> {
|
||||||
return await invoke("pick_and_load_waveform");
|
return await invoke("pick_and_load_waveform");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function load_file_with_selected_vars(): Promise<JavascriptCode | undefined> {
|
||||||
|
return await invoke("load_file_with_selected_vars");
|
||||||
|
}
|
||||||
|
|
||||||
export async function get_hierarchy(): Promise<WellenHierarchy> {
|
export async function get_hierarchy(): Promise<WellenHierarchy> {
|
||||||
return await invoke("get_hierarchy");
|
return await invoke("get_hierarchy");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
|
use std::fs;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
use tauri_plugin_dialog::DialogExt;
|
use tauri_plugin_dialog::DialogExt;
|
||||||
use wellen::simple::Waveform;
|
use wellen::simple::Waveform;
|
||||||
|
|
||||||
type Filename = String;
|
type Filename = String;
|
||||||
|
type JavascriptCode = String;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct Store {
|
struct Store {
|
||||||
|
@ -32,6 +34,18 @@ async fn pick_and_load_waveform(
|
||||||
Ok(Some(file_response.name.unwrap()))
|
Ok(Some(file_response.name.unwrap()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tauri::command(rename_all = "snake_case")]
|
||||||
|
async fn load_file_with_selected_vars(app: tauri::AppHandle) -> Result<Option<JavascriptCode>, ()> {
|
||||||
|
let Some(file_response) = app.dialog().file().blocking_pick_file() else {
|
||||||
|
return Ok(None);
|
||||||
|
};
|
||||||
|
// @TODO Tokio's `fs` or a Tauri `fs`?
|
||||||
|
let Ok(javascript_code) = fs::read_to_string(file_response.path) else {
|
||||||
|
panic!("Selected vars file reading failed")
|
||||||
|
};
|
||||||
|
Ok(Some(javascript_code))
|
||||||
|
}
|
||||||
|
|
||||||
#[tauri::command(rename_all = "snake_case")]
|
#[tauri::command(rename_all = "snake_case")]
|
||||||
async fn get_hierarchy(store: tauri::State<'_, Store>) -> Result<serde_json::Value, ()> {
|
async fn get_hierarchy(store: tauri::State<'_, Store>) -> Result<serde_json::Value, ()> {
|
||||||
let waveform = store.waveform.lock().unwrap();
|
let waveform = store.waveform.lock().unwrap();
|
||||||
|
@ -91,6 +105,7 @@ pub fn run() {
|
||||||
.invoke_handler(tauri::generate_handler![
|
.invoke_handler(tauri::generate_handler![
|
||||||
show_window,
|
show_window,
|
||||||
pick_and_load_waveform,
|
pick_and_load_waveform,
|
||||||
|
load_file_with_selected_vars,
|
||||||
get_hierarchy,
|
get_hierarchy,
|
||||||
load_signal_and_get_timeline,
|
load_signal_and_get_timeline,
|
||||||
unload_signal,
|
unload_signal,
|
||||||
|
|
7
test_files/simple_vcd.fw.js
Normal file
7
test_files/simple_vcd.fw.js
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
if (FW.loaded_filename() === "simple.vcd") {
|
||||||
|
FW.select_vars([
|
||||||
|
"simple_tb.s.A",
|
||||||
|
"simple_tb.s.A",
|
||||||
|
"simple_tb.s.B"
|
||||||
|
])
|
||||||
|
}
|
Loading…
Reference in a new issue