1use std::collections::HashMap;
2
3use eyre::{Result, WrapErr};
4use log::{error, info, warn};
5use num::bigint::ToBigInt as _;
6use num::{BigInt, BigUint, Zero};
7use serde::{Deserialize, Serialize};
8use surfer_translation_types::{TranslationPreference, Translator, VariableValue};
9
10use crate::data_container::DataContainer;
11use crate::displayed_item::{
12 DisplayedDivider, DisplayedFieldRef, DisplayedGroup, DisplayedItem, DisplayedItemRef,
13 DisplayedStream, DisplayedTimeLine, DisplayedVariable,
14};
15use crate::displayed_item_tree::{DisplayedItemTree, ItemIndex, TargetPosition, VisibleItemIndex};
16use crate::graphics::{Graphic, GraphicId};
17use crate::transaction_container::{StreamScopeRef, TransactionRef, TransactionStreamRef};
18use crate::translation::{DynTranslator, TranslatorList, VariableInfoExt};
19use crate::variable_name_type::VariableNameType;
20use crate::view::ItemDrawingInfo;
21use crate::viewport::Viewport;
22use crate::wave_container::{ScopeRef, VariableMeta, VariableRef, VariableRefExt, WaveContainer};
23use crate::wave_source::{WaveFormat, WaveSource};
24use crate::wellen::LoadSignalsCmd;
25use ftr_parser::types::Transaction;
26use itertools::Itertools;
27use std::fmt::Formatter;
28use std::ops::Not;
29
30pub const PER_SCROLL_EVENT: f32 = 50.0;
31pub const SCROLL_EVENTS_PER_PAGE: f32 = 20.0;
32
33#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
34pub enum ScopeType {
35 WaveScope(ScopeRef),
36 StreamScope(StreamScopeRef),
37}
38
39impl std::fmt::Display for ScopeType {
40 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
41 match self {
42 ScopeType::WaveScope(w) => w.fmt(f),
43 ScopeType::StreamScope(s) => s.fmt(f),
44 }
45 }
46}
47
48#[derive(Serialize, Deserialize)]
49pub struct WaveData {
50 #[serde(skip, default = "DataContainer::__new_empty")]
51 pub inner: DataContainer,
52 pub source: WaveSource,
53 pub format: WaveFormat,
54 pub active_scope: Option<ScopeType>,
55 pub items_tree: DisplayedItemTree,
57 pub displayed_items: HashMap<DisplayedItemRef, DisplayedItem>,
58 pub display_item_ref_counter: usize,
60 pub viewports: Vec<Viewport>,
61 pub cursor: Option<BigInt>,
62 pub markers: HashMap<u8, BigInt>,
63 pub focused_item: Option<VisibleItemIndex>,
64 pub focused_transaction: (Option<TransactionRef>, Option<Transaction>),
65 pub default_variable_name_type: VariableNameType,
66 pub scroll_offset: f32,
67 pub display_variable_indices: bool,
68 pub graphics: HashMap<GraphicId, Graphic>,
69 #[serde(skip)]
71 pub drawing_infos: Vec<ItemDrawingInfo>,
72 #[serde(skip)]
73 pub top_item_draw_offset: f32,
74 #[serde(skip)]
75 pub total_height: f32,
76 #[serde(skip)]
78 pub old_num_timestamps: Option<BigInt>,
79}
80
81fn select_preferred_translator(var: &VariableMeta, translators: &TranslatorList) -> String {
82 let mut preferred: Vec<_> = translators
83 .all_translators()
84 .iter()
85 .filter_map(|t| match t.translates(var) {
86 Ok(TranslationPreference::Prefer) => Some(t.name()),
87 Ok(TranslationPreference::Yes) => None,
88 Ok(TranslationPreference::No) => None,
89 Err(e) => {
90 error!(
91 "Failed to check if {} translates {}\n{e:#?}",
92 t.name(),
93 var.var.full_path_string()
94 );
95 None
96 }
97 })
98 .collect();
99 if preferred.len() > 1 {
100 let bit = "Bit".to_string();
103 if var.num_bits == Some(1) {
104 preferred.retain(|x| x != &bit);
105 }
106 if preferred.len() > 1 {
107 warn!(
108 "More than one preferred translator for variable {} in scope {}: {}",
109 var.var.name,
110 var.var.path.strs.join("."),
111 preferred.join(", ")
112 );
113 preferred.sort();
114 }
115 }
116 preferred
118 .pop()
119 .unwrap_or_else(|| translators.default.clone())
120}
121
122pub fn variable_translator<'a, F>(
123 translator: Option<&String>,
124 field: &[String],
125 translators: &'a TranslatorList,
126 meta: F,
127) -> &'a DynTranslator
128where
129 F: FnOnce() -> Result<VariableMeta>,
130{
131 let translator_name = translator
132 .cloned()
133 .or_else(|| {
134 Some(if field.is_empty() {
135 meta()
136 .as_ref()
137 .map(|meta| select_preferred_translator(meta, translators).clone())
138 .unwrap_or_else(|e| {
139 warn!("{e:#?}");
140 translators.default.clone()
141 })
142 } else {
143 translators.default.clone()
144 })
145 })
146 .unwrap();
147
148 let translator = translators.get_translator(&translator_name);
149 translator
150}
151
152impl WaveData {
153 pub fn update_with_waves(
154 mut self,
155 new_waves: Box<WaveContainer>,
156 source: WaveSource,
157 format: WaveFormat,
158 translators: &TranslatorList,
159 keep_unavailable: bool,
160 ) -> (WaveData, Option<LoadSignalsCmd>) {
161 let active_scope = self.active_scope.take().filter(|m| {
162 if let ScopeType::WaveScope(w) = m {
163 new_waves.scope_exists(w)
164 } else {
165 false
166 }
167 });
168 let display_items = self.update_displayed_items(
169 &new_waves,
170 &self.displayed_items,
171 keep_unavailable,
172 translators,
173 );
174
175 let old_num_timestamps = self.num_timestamps();
176 let mut new_wavedata = WaveData {
177 inner: DataContainer::Waves(*new_waves),
178 source,
179 format,
180 active_scope,
181 items_tree: self.items_tree,
182 displayed_items: display_items,
183 display_item_ref_counter: self.display_item_ref_counter,
184 viewports: self.viewports,
185 cursor: self.cursor.clone(),
186 markers: self.markers.clone(),
187 focused_item: self.focused_item,
188 focused_transaction: self.focused_transaction,
189 default_variable_name_type: self.default_variable_name_type,
190 display_variable_indices: self.display_variable_indices,
191 scroll_offset: self.scroll_offset,
192 drawing_infos: vec![],
193 top_item_draw_offset: 0.,
194 graphics: HashMap::new(),
195 total_height: 0.,
196 old_num_timestamps,
197 };
198
199 new_wavedata.update_metadata(translators);
200 let load_commands = new_wavedata.load_waves();
201 (new_wavedata, load_commands)
202 }
203
204 pub fn update_with_items(
205 &mut self,
206 new_items: &HashMap<DisplayedItemRef, DisplayedItem>,
207 items_tree: DisplayedItemTree,
208 translators: &TranslatorList,
209 ) -> Option<LoadSignalsCmd> {
210 self.items_tree = items_tree;
211 self.displayed_items = self.update_displayed_items(
212 self.inner.as_waves().unwrap(),
213 new_items,
214 true,
215 translators,
216 );
217 self.display_item_ref_counter = self
218 .displayed_items
219 .keys()
220 .map(|dir| dir.0)
221 .max()
222 .unwrap_or(0);
223
224 self.update_metadata(translators);
225 self.load_waves()
226 }
227
228 fn update_metadata(&mut self, translators: &TranslatorList) {
232 for (_vidx, di) in self.displayed_items.iter_mut() {
233 let DisplayedItem::Variable(displayed_variable) = di else {
234 continue;
235 };
236
237 let meta = self
238 .inner
239 .as_waves()
240 .unwrap()
241 .variable_meta(&displayed_variable.variable_ref.clone())
242 .unwrap();
243 let translator =
244 variable_translator(displayed_variable.get_format(&[]), &[], translators, || {
245 Ok(meta.clone())
246 });
247 let info = translator.variable_info(&meta).ok();
248
249 match info {
250 Some(info) => displayed_variable
251 .field_formats
252 .retain(|ff| info.has_subpath(&ff.field)),
253 _ => displayed_variable.field_formats.clear(),
254 }
255 }
256 }
257
258 fn load_waves(&mut self) -> Option<LoadSignalsCmd> {
262 let variables = self.displayed_items.values().filter_map(|item| match item {
263 DisplayedItem::Variable(r) => Some(&r.variable_ref),
264 _ => None,
265 });
266 self.inner
267 .as_waves_mut()
268 .unwrap()
269 .load_variables(variables)
270 .expect("internal error: failed to load variables")
271 }
272
273 pub fn update_viewports(&mut self) {
276 if let Some(old_num_timestamps) = std::mem::take(&mut self.old_num_timestamps) {
277 let new_num_timestamps = self
280 .inner
281 .max_timestamp()
282 .unwrap_or_else(|| BigUint::from(1u32))
283 .to_bigint()
284 .unwrap();
285 if new_num_timestamps != old_num_timestamps {
286 for viewport in self.viewports.iter_mut() {
287 *viewport = viewport.clip_to(&old_num_timestamps, &new_num_timestamps);
288 }
289 }
290 }
291 }
292
293 fn update_displayed_items(
294 &self,
295 waves: &WaveContainer,
296 items: &HashMap<DisplayedItemRef, DisplayedItem>,
297 keep_unavailable: bool,
298 translators: &TranslatorList,
299 ) -> HashMap<DisplayedItemRef, DisplayedItem> {
300 items
301 .iter()
302 .filter_map(|(id, i)| {
303 match i {
304 DisplayedItem::Divider(_)
306 | DisplayedItem::Marker(_)
307 | DisplayedItem::TimeLine(_)
308 | DisplayedItem::Stream(_)
309 | DisplayedItem::Group(_) => Some((*id, i.clone())),
310 DisplayedItem::Variable(s) => {
311 s.update(waves, keep_unavailable).map(|r| (*id, r))
312 }
313 DisplayedItem::Placeholder(p) => {
314 match waves.update_variable_ref(&p.variable_ref) {
315 None => {
316 if keep_unavailable {
317 Some((*id, DisplayedItem::Placeholder(p.clone())))
318 } else {
319 None
320 }
321 }
322 Some(new_variable_ref) => {
323 let Ok(meta) = waves
324 .variable_meta(&new_variable_ref)
325 .context("When updating")
326 .map_err(|e| error!("{e:#?}"))
327 else {
328 return Some((*id, DisplayedItem::Placeholder(p.clone())));
329 };
330 let translator = variable_translator(
331 p.format.as_ref(),
332 &[],
333 translators,
334 || Ok(meta.clone()),
335 );
336 let info = translator.variable_info(&meta).unwrap();
337 Some((
338 *id,
339 DisplayedItem::Variable(
340 p.clone().into_variable(info, new_variable_ref),
341 ),
342 ))
343 }
344 }
345 }
346 }
347 })
348 .collect()
349 }
350
351 pub fn select_preferred_translator(
352 &self,
353 var: VariableMeta,
354 translators: &TranslatorList,
355 ) -> String {
356 select_preferred_translator(&var, translators)
357 }
358
359 pub fn variable_translator<'a>(
360 &'a self,
361 field: &DisplayedFieldRef,
362 translators: &'a TranslatorList,
363 ) -> &'a DynTranslator {
364 let Some(DisplayedItem::Variable(displayed_variable)) =
365 self.displayed_items.get(&field.item)
366 else {
367 panic!("asking for translator for a non DisplayItem::Variable item")
368 };
369
370 variable_translator(
371 displayed_variable.get_format(&field.field),
372 &field.field,
373 translators,
374 || {
375 self.inner
376 .as_waves()
377 .unwrap()
378 .variable_meta(&displayed_variable.variable_ref)
379 },
380 )
381 }
382
383 pub fn add_variables(
384 &mut self,
385 translators: &TranslatorList,
386 variables: Vec<VariableRef>,
387 target_position: Option<TargetPosition>,
388 update_display_names: bool,
389 ) -> (Option<LoadSignalsCmd>, Vec<DisplayedItemRef>) {
390 let mut indices = vec![];
391 let res = match self
393 .inner
394 .as_waves_mut()
395 .unwrap()
396 .load_variables(variables.iter())
397 {
398 Err(e) => {
399 error!("{e:#?}");
400 return (None, indices);
401 }
402 Ok(res) => res,
403 };
404
405 let mut target_position = target_position
407 .or_else(|| self.focused_insert_position())
408 .unwrap_or(self.end_insert_position());
409 for variable in variables {
410 let Ok(meta) = self
411 .inner
412 .as_waves()
413 .unwrap()
414 .variable_meta(&variable)
415 .context("When adding variable")
416 .map_err(|e| error!("{e:#?}"))
417 else {
418 return (res, indices);
419 };
420
421 let translator = variable_translator(None, &[], translators, || Ok(meta.clone()));
422 let info = translator.variable_info(&meta).unwrap();
423
424 let new_variable = DisplayedItem::Variable(DisplayedVariable {
425 variable_ref: variable.clone(),
426 info,
427 color: None,
428 background_color: None,
429 display_name: variable.name.clone(),
430 display_name_type: self.default_variable_name_type,
431 manual_name: None,
432 format: None,
433 field_formats: vec![],
434 height_scaling_factor: None,
435 });
436
437 indices.push(self.insert_item(new_variable, Some(target_position), true));
438 target_position = TargetPosition {
439 before: ItemIndex(target_position.before.0 + 1),
440 level: target_position.level,
441 }
442 }
443
444 if update_display_names {
445 self.compute_variable_display_names();
446 }
447 (res, indices)
448 }
449
450 pub fn remove_displayed_item(&mut self, id: DisplayedItemRef) {
451 let Some(idx) = self
452 .items_tree
453 .iter()
454 .enumerate()
455 .find(|(_, node)| node.item_ref == id)
456 .map(|(idx, _)| ItemIndex(idx))
457 else {
458 return;
459 };
460
461 let focused_item_ref = self
462 .focused_item
463 .and_then(|vidx| self.items_tree.get_visible(vidx))
464 .map(|node| node.item_ref);
465
466 for removed_ref in self.items_tree.remove_recursive(idx) {
467 if let Some(DisplayedItem::Marker(m)) = self.displayed_items.remove(&removed_ref) {
468 self.markers.remove(&m.idx);
469 }
470 }
471
472 self.focused_item = focused_item_ref.and_then(|focused_item_ref| {
473 match self
474 .items_tree
475 .iter_visible()
476 .find_position(|node| node.item_ref == focused_item_ref)
477 .map(|(vidx, _)| VisibleItemIndex(vidx))
478 {
479 Some(vidx) => Some(vidx),
480 None if self
481 .focused_item
482 .and_then(|focused_vidx| self.items_tree.to_displayed(focused_vidx))
483 .is_some() =>
484 {
485 Some(self.focused_item.unwrap())
486 }
487 None => self
488 .items_tree
489 .iter_visible()
490 .count()
491 .checked_sub(1)
492 .map(VisibleItemIndex),
493 }
494 })
495 }
496
497 pub fn add_divider(&mut self, name: Option<String>, vidx: Option<VisibleItemIndex>) {
498 self.insert_item(
499 DisplayedItem::Divider(DisplayedDivider {
500 color: None,
501 background_color: None,
502 name,
503 }),
504 self.vidx_insert_position(vidx),
505 true,
506 );
507 }
508
509 pub fn add_timeline(&mut self, vidx: Option<VisibleItemIndex>) {
510 self.insert_item(
511 DisplayedItem::TimeLine(DisplayedTimeLine {
512 color: None,
513 background_color: None,
514 name: None,
515 }),
516 self.vidx_insert_position(vidx),
517 true,
518 );
519 }
520
521 pub fn add_group(
522 &mut self,
523 name: String,
524 target_position: Option<TargetPosition>,
525 ) -> DisplayedItemRef {
526 self.insert_item(
527 DisplayedItem::Group(DisplayedGroup {
528 name,
529 color: None,
530 background_color: None,
531 content: vec![],
532 is_open: false,
533 }),
534 target_position,
535 true,
536 )
537 }
538
539 pub fn add_generator(&mut self, gen_ref: TransactionStreamRef) {
540 let Some(gen_id) = gen_ref.gen_id else { return };
541
542 if self
543 .inner
544 .as_transactions()
545 .unwrap()
546 .get_generator(gen_id)
547 .unwrap()
548 .transactions
549 .is_empty()
550 {
551 info!("(Generator {})Loading transactions into memory!", gen_id);
552 match self
553 .inner
554 .as_transactions_mut()
555 .unwrap()
556 .inner
557 .load_stream_into_memory(gen_ref.stream_id)
558 {
559 Ok(_) => info!("(Generator {}) Finished loading transactions!", gen_id),
560 Err(_) => return,
561 }
562 }
563
564 let gen = self
565 .inner
566 .as_transactions()
567 .unwrap()
568 .get_generator(gen_id)
569 .unwrap();
570 let mut last_times_on_row = vec![(BigUint::ZERO, BigUint::ZERO)];
571 calculate_rows_of_stream(&gen.transactions, &mut last_times_on_row);
572
573 let new_gen = DisplayedItem::Stream(DisplayedStream {
574 display_name: gen_ref.name.clone(),
575 transaction_stream_ref: gen_ref,
576 color: None,
577 background_color: None,
578 manual_name: None,
579 rows: last_times_on_row.len(),
580 });
581
582 self.insert_item(new_gen, None, true);
583 }
584
585 pub fn add_stream(&mut self, stream_ref: TransactionStreamRef) {
586 if self
587 .inner
588 .as_transactions_mut()
589 .unwrap()
590 .get_stream(stream_ref.stream_id)
591 .unwrap()
592 .transactions_loaded
593 .not()
594 {
595 info!("(Stream)Loading transactions into memory!");
596 match self
597 .inner
598 .as_transactions_mut()
599 .unwrap()
600 .inner
601 .load_stream_into_memory(stream_ref.stream_id)
602 {
603 Ok(_) => info!(
604 "(Stream {}) Finished loading transactions!",
605 stream_ref.stream_id
606 ),
607 Err(_) => return,
608 }
609 }
610
611 let stream = self
612 .inner
613 .as_transactions()
614 .unwrap()
615 .get_stream(stream_ref.stream_id)
616 .unwrap();
617 let mut last_times_on_row = vec![(BigUint::ZERO, BigUint::ZERO)];
618
619 for gen_id in &stream.generators {
620 let gen = self
621 .inner
622 .as_transactions()
623 .unwrap()
624 .get_generator(*gen_id)
625 .unwrap();
626 calculate_rows_of_stream(&gen.transactions, &mut last_times_on_row);
627 }
628
629 let new_stream = DisplayedItem::Stream(DisplayedStream {
630 display_name: stream_ref.name.clone(),
631 transaction_stream_ref: stream_ref,
632 color: None,
633 background_color: None,
634 manual_name: None,
635 rows: last_times_on_row.len(),
636 });
637
638 self.insert_item(new_stream, None, true);
639 }
640
641 pub fn add_all_streams(&mut self) {
642 let mut streams: Vec<(usize, String)> = vec![];
643 for stream in self.inner.as_transactions().unwrap().get_streams() {
644 streams.push((stream.id, stream.name.clone()));
645 }
646
647 for (id, name) in streams {
648 self.add_stream(TransactionStreamRef::new_stream(id, name));
649 }
650 }
651
652 fn vidx_insert_position(&self, vidx: Option<VisibleItemIndex>) -> Option<TargetPosition> {
653 let vidx = vidx?;
654 let info = self.items_tree.get_visible_extra(vidx)?;
655 let level = match self.displayed_items.get(&info.node.item_ref)? {
656 DisplayedItem::Group(_) if info.node.unfolded => info.node.level + 1,
657 _ => info.node.level,
658 };
659 Some(TargetPosition {
660 before: ItemIndex(info.idx.0 + 1),
661 level,
662 })
663 }
664
665 pub fn focused_insert_position(&self) -> Option<TargetPosition> {
672 let vidx = self.focused_item?;
673 let item_index = self.items_tree.to_displayed(vidx)?;
674 let node = self.items_tree.get(item_index)?;
675 let item = self.displayed_items.get(&node.item_ref)?;
676
677 let (before, level) = match item {
679 DisplayedItem::Group(..) if node.unfolded => (item_index.0 + 1, node.level + 1),
680 DisplayedItem::Group(..) => {
681 let next_idx = self.items_tree.to_displayed(VisibleItemIndex(vidx.0 + 1));
682 match next_idx {
683 Some(idx) => (idx.0, node.level),
684 None => (self.items_tree.len(), node.level),
685 }
686 }
687 _ => (item_index.0 + 1, node.level),
688 };
689 Some(TargetPosition {
690 before: ItemIndex(before),
691 level,
692 })
693 }
694
695 pub fn end_insert_position(&self) -> TargetPosition {
696 TargetPosition {
697 before: ItemIndex(self.items_tree.len()),
698 level: 0,
699 }
700 }
701
702 pub fn index_for_ref_or_focus(&self, item_ref: Option<DisplayedItemRef>) -> Option<ItemIndex> {
703 if let Some(item_ref) = item_ref {
704 self.items_tree
705 .iter()
706 .enumerate()
707 .find_map(|(idx, node)| (node.item_ref == item_ref).then_some(ItemIndex(idx)))
708 } else if let Some(focused_item) = self.focused_item {
709 self.items_tree
710 .get_visible_extra(focused_item)
711 .map(|info| info.idx)
712 } else {
713 None
714 }
715 }
716
717 pub(crate) fn insert_item(
722 &mut self,
723 new_item: DisplayedItem,
724 target_position: Option<TargetPosition>,
725 move_focus: bool,
726 ) -> DisplayedItemRef {
727 let target_position = target_position
728 .or_else(|| self.focused_insert_position())
729 .unwrap_or_else(|| self.end_insert_position());
730
731 let item_ref = self.next_displayed_item_ref();
732 let insert_index = self
733 .items_tree
734 .insert_item(item_ref, target_position)
735 .unwrap();
736 self.displayed_items.insert(item_ref, new_item);
737 if move_focus {
738 self.focused_item = self.focused_item.and_then(|_| {
739 self.items_tree
740 .iter_visible_extra()
741 .find_map(|info| (info.idx == insert_index).then_some(info.vidx))
742 });
743 }
744 self.items_tree.xselect_all_visible(false);
745 item_ref
746 }
747
748 pub fn go_to_cursor_if_not_in_view(&mut self) -> bool {
749 if let Some(cursor) = &self.cursor {
750 let num_timestamps = self.num_timestamps().unwrap_or(1.into());
751 self.viewports[0].go_to_cursor_if_not_in_view(cursor, &num_timestamps)
752 } else {
753 false
754 }
755 }
756
757 #[inline]
758 pub fn numbered_marker_location(&self, idx: u8, viewport: &Viewport, view_width: f32) -> f32 {
759 viewport.pixel_from_time(
760 self.numbered_marker_time(idx),
761 view_width,
762 &self.num_timestamps().unwrap_or(1.into()),
763 )
764 }
765
766 #[inline]
767 pub fn numbered_marker_time(&self, idx: u8) -> &BigInt {
768 self.markers.get(&idx).unwrap()
769 }
770
771 pub fn viewport_all(&self) -> Viewport {
772 Viewport::new()
773 }
774
775 pub fn remove_placeholders(&mut self) {
776 let removed_refs = self.items_tree.drain_recursive_if(|node| {
777 matches!(
778 self.displayed_items.get(&node.item_ref),
779 Some(DisplayedItem::Placeholder(_))
780 )
781 });
782 for removed_ref in removed_refs {
783 self.displayed_items.remove(&removed_ref);
784 }
785 }
786
787 #[inline]
788 pub fn any_displayed(&self) -> bool {
789 !self.displayed_items.is_empty()
790 }
791
792 pub fn get_top_item(&self) -> usize {
794 let default = if self.drawing_infos.is_empty() {
795 0
796 } else {
797 self.drawing_infos.len() - 1
798 };
799 self.drawing_infos
800 .iter()
801 .enumerate()
802 .find(|(_, di)| di.top() >= self.top_item_draw_offset - 1.) .map_or(default, |(idx, _)| idx)
804 }
805
806 pub fn get_item_at_y(&self, y: f32) -> Option<VisibleItemIndex> {
808 if self.drawing_infos.is_empty() {
809 return None;
810 }
811 let first_element_top = self.drawing_infos.first().unwrap().top();
812 let first_element_bottom = self.drawing_infos.last().unwrap().bottom();
813 let threshold = y + first_element_top + self.scroll_offset;
814 if first_element_bottom <= threshold {
815 return None;
816 }
817 self.drawing_infos
818 .iter()
819 .enumerate()
820 .rev()
821 .find(|(_, di)| di.top() <= threshold)
822 .map(|(vidx, _)| VisibleItemIndex(vidx))
823 }
824
825 pub fn scroll_to_item(&mut self, idx: usize) {
826 if self.drawing_infos.is_empty() {
827 return;
828 }
829 let first_element_y = self.drawing_infos.first().unwrap().top();
831 let item_y = self
832 .drawing_infos
833 .get(idx)
834 .unwrap_or_else(|| self.drawing_infos.last().unwrap())
835 .top();
836 if self.scroll_offset > self.total_height {
838 self.scroll_offset = item_y - first_element_y;
839 }
840 }
841
842 pub fn set_cursor_at_transition(
845 &mut self,
846 next: bool,
847 variable: Option<VisibleItemIndex>,
848 skip_zero: bool,
849 ) {
850 if let Some(vidx) = variable.or(self.focused_item) {
851 if let Some(cursor) = &self.cursor {
852 if let Some(DisplayedItem::Variable(variable)) = &self
853 .items_tree
854 .get_visible(vidx)
855 .and_then(|node| self.displayed_items.get(&node.item_ref))
856 {
857 if let Ok(Some(res)) = self.inner.as_waves().unwrap().query_variable(
858 &variable.variable_ref,
859 &cursor.to_biguint().unwrap_or_default(),
860 ) {
861 if next {
862 if let Some(ref time) = res.next {
863 let stime = time.to_bigint();
864 if stime.is_some() {
865 self.cursor.clone_from(&stime);
866 }
867 } else {
868 self.cursor = Some(self.num_timestamps().expect(
870 "No timestamp count even though waveforms should be loaded",
871 ));
872 }
873 } else if let Some(stime) = res.current.unwrap().0.to_bigint() {
874 let bigone = BigInt::from(1);
875 if stime == *cursor && *cursor >= bigone {
877 if let Ok(Some(newres)) =
879 self.inner.as_waves().unwrap().query_variable(
880 &variable.variable_ref,
881 &(cursor - bigone).to_biguint().unwrap_or_default(),
882 )
883 {
884 if let Some(current) = newres.current {
885 let newstime = current.0.to_bigint();
886 if newstime.is_some() {
887 self.cursor.clone_from(&newstime);
888 }
889 }
890 }
891 } else {
892 self.cursor = Some(stime);
893 }
894 }
895
896 if skip_zero {
898 if let Some(time) = &self.cursor {
901 let next_value = self.inner.as_waves().unwrap().query_variable(
902 &variable.variable_ref,
903 &time.to_biguint().unwrap_or_default(),
904 );
905 if next_value.is_ok_and(|r| {
906 r.is_some_and(|r| {
907 r.current.is_some_and(|v| match v.1 {
908 VariableValue::BigUint(v) => v == BigUint::from(0u8),
909 _ => false,
910 })
911 })
912 }) {
913 self.set_cursor_at_transition(next, Some(vidx), false);
914 }
915 }
916 }
917 }
918 }
919 }
920 }
921 }
922
923 pub fn next_displayed_item_ref(&mut self) -> DisplayedItemRef {
924 self.display_item_ref_counter += 1;
925 self.display_item_ref_counter.into()
926 }
927
928 pub fn num_timestamps(&self) -> Option<BigInt> {
932 self.inner
933 .max_timestamp()
934 .and_then(|r| if r == BigUint::zero() { None } else { Some(r) })
935 .and_then(|r| r.to_bigint())
936 }
937
938 pub fn get_displayed_item_index(
939 &self,
940 item_ref: &DisplayedItemRef,
941 ) -> Option<VisibleItemIndex> {
942 self.items_tree
944 .iter_visible()
945 .enumerate()
946 .find_map(|(vidx, node)| {
947 if node.item_ref == *item_ref {
948 Some(VisibleItemIndex(vidx))
949 } else {
950 None
951 }
952 })
953 }
954}
955
956fn calculate_rows_of_stream(
957 transactions: &Vec<Transaction>,
958 last_times_on_row: &mut Vec<(BigUint, BigUint)>,
959) {
960 for transaction in transactions {
961 let mut curr_row = 0;
962 let start_time = transaction.get_start_time();
963 let end_time = transaction.get_end_time();
964
965 while start_time > last_times_on_row[curr_row].0
966 && start_time < last_times_on_row[curr_row].1
967 {
968 curr_row += 1;
969 if last_times_on_row.len() <= curr_row {
970 last_times_on_row.push((BigUint::ZERO, BigUint::ZERO));
971 }
972 }
973 last_times_on_row[curr_row] = (start_time, end_time);
974 }
975}