@@ -162,8 +162,8 @@ void WavesPanel::FindEdge(bool forward, bool *time_changed, bool *range_changed)
162162void WavesPanel::SnapToValue () {
163163 const auto *item = visible_items_[line_idx_];
164164 if (item->signal == nullptr ) return ;
165- auto time_per_char = TimePerChar ();
166- auto &wave = wave_data_->Wave (item->signal );
165+ const double time_per_char = TimePerChar ();
166+ const std::vector<WaveData::Sample> &wave = wave_data_->Wave (item->signal );
167167 // See if there is an edge within the current cursor's character span
168168 const uint64_t left_time = left_time_ + cursor_pos_ * time_per_char;
169169 const uint64_t right_time = left_time_ + (cursor_pos_ + 1 ) * time_per_char;
@@ -416,7 +416,7 @@ void WavesPanel::Draw() {
416416 int left_sample_idx = wave_data_->FindSampleIndex (left_time_, item->signal );
417417 // Save the locations of transitions and times to fill in values.
418418 struct WaveValueInfo {
419- int xpos;
419+ int xpos = 0 ;
420420 int size;
421421 uint64_t time;
422422 std::string value;
@@ -441,14 +441,27 @@ void WavesPanel::Draw() {
441441 const int num_rows = item->analog_rows > 1 ? item->analog_rows : 1 ;
442442 std::optional<WaveImage> analog_image;
443443 if (analog) {
444- // TODO
444+ const WaveImageConfig cfg = {
445+ .char_w = max_w - wave_x,
446+ .char_h = item->analog_rows ,
447+ .left_idx = left_sample_idx,
448+ .left_time = left_time_,
449+ .right_time = right_time_,
450+ .radix = item->radix ,
451+ .analog_type = item->analog_type ,
452+ };
453+ analog_image.emplace (RenderWaves (cfg, wave));
445454 }
446455 for (int render_row = 0 ; render_row < num_rows && row < max_h; render_row++, row++) {
447456 // Draw charachter by charachter
448457 wmove (w_, row, wave_x);
449458 for (int x = 0 ; x < max_w - wave_x; ++x) {
450459 if (analog) {
451- // TODO
460+ if (unicode_) {
461+ AddUnicodeChar (w_, analog_image->GetBrailleChar (x, render_row));
462+ } else {
463+ waddch (w_, BraillePatternToAscii (analog_image->GetBrailleChar (x, render_row)));
464+ }
452465 } else {
453466 // Find what sample index corresponds to the right edge of this character.
454467 const int right_sample_idx = wave_data_->FindSampleIndex (
@@ -486,7 +499,8 @@ void WavesPanel::Draw() {
486499 } else {
487500 waddch (w_, ' |' );
488501 }
489- // Only save value locations if they are at least 3 characters.
502+ // Only save value locations if they are at least 3 characters, comparing against the
503+ // previous one.
490504 if (x - wvi.xpos >= 3 ) {
491505 wvi.size = x - wvi.xpos ;
492506 wvi.value = FormatValue (wave[wave_value_idx].value , item->radix , leading_zeroes_,
@@ -546,17 +560,17 @@ void WavesPanel::Draw() {
546560 if (!analog) {
547561 // Draw waveform values inline where possible.
548562 SetColor (w_, kWavesInlineValuePair + highlight);
549- for (const auto &wv : wave_value_list) {
563+ for (const WaveValueInfo &wv : wave_value_list) {
550564 int start_pos, char_offset;
551565 if (wv.size - 1 < wv.value .size ()) {
552566 start_pos = wv.xpos + 1 ;
553567 char_offset = wv.value .size () - wv.size + 1 ;
554568 } else {
555- start_pos = wv.xpos + wv.size / 2 - wv.value .size () / 2 ;
569+ start_pos = wv.xpos + 1 + ( wv.size - 1 ) / 2 - wv.value .size () / 2 ;
556570 char_offset = 0 ;
557571 }
558572 // Draw on row-1, since row was already incremented after rendering the wave.
559- wmove (w_, row- 1 , start_pos + wave_x);
573+ wmove (w_, row - 1 , start_pos + wave_x);
560574 for (int i = char_offset; i < wv.value .size (); ++i) {
561575 waddch (w_, (i == char_offset && char_offset != 0 ) ? ' .' : wv.value [i]);
562576 }
@@ -568,19 +582,23 @@ void WavesPanel::Draw() {
568582 // Draw the cursor and markers.
569583 const auto draw_vline = [&](int row, int col) {
570584 const int current_line = 1 + line_idx_ - scroll_row_;
571- if (visible_items_[line_idx_]->signal != nullptr ) {
585+ if (visible_items_[line_idx_]->signal != nullptr &&
586+ visible_items_[line_idx_]->analog_rows == 0 ) {
572587 // Draw the line in two sections, above and below the current line to
573- // avoid overwriting the drawn wave.
588+ // avoid overwriting the drawn wave. Draw over analog waves though.
574589 if (current_line > row) {
575590 mvwvline (w_, row, col, ACS_VLINE, current_line - row);
576591 }
577- if (current_line < max_h - 1 ) {
578- mvwvline (w_, current_line + 1 , col, ACS_VLINE, max_h - current_line - 1 );
592+ const int next_line_start =
593+ current_line + std::max (1 , visible_items_[line_idx_]->analog_rows );
594+ if (next_line_start < max_h) {
595+ mvwvline (w_, next_line_start, col, ACS_VLINE, max_h - next_line_start);
579596 }
580597 } else {
581598 mvwvline (w_, row, col, ACS_VLINE, max_h - row);
582599 }
583600 };
601+ // Helper to see if the marker should start under the current time, to avoid covering it.
584602 auto vline_row = [&](int col) { return col >= time_width ? 0 : 1 ; };
585603 for (int i = -1 ; i < 10 ; ++i) {
586604 const uint64_t time = i < 0 ? marker_time_ : numbered_marker_times_[i];
@@ -590,17 +608,17 @@ void WavesPanel::Draw() {
590608 std::string marker_label = " m" ;
591609 if (i >= 0 ) marker_label += ' 0' + i;
592610 SetColor (w_, kWavesMarkerPair );
593- const int col = wave_x + marker_pos;
594- const int row = vline_row (wave_x + marker_pos);
595- draw_vline (row, col );
611+ const int marker_col = wave_x + marker_pos;
612+ const int marker_row = vline_row (wave_x + marker_pos);
613+ draw_vline (marker_row, marker_col );
596614 if (marker_pos + marker_label.size () < max_w) {
597- mvwaddstr (w_, row, col , marker_label.c_str ());
615+ mvwaddstr (w_, marker_row, marker_col , marker_label.c_str ());
598616 }
599617 }
600618 }
601619 // Also the interactive cursor.
602- int cursor_col = wave_x + cursor_pos_;
603- int cursor_row = vline_row (cursor_col);
620+ const int cursor_col = wave_x + cursor_pos_;
621+ const int cursor_row = vline_row (cursor_col);
604622 SetColor (w_, kWavesCursorPair );
605623 draw_vline (cursor_row, cursor_col);
606624
@@ -636,6 +654,7 @@ void WavesPanel::UIChar(int ch) {
636654
637655 bool time_changed = false ;
638656 bool range_changed = false ;
657+ bool edge_search = false ;
639658 // Most actions cancel multi-line.
640659 bool cancel_multi_line = true ;
641660 if (showing_path_) {
@@ -846,7 +865,10 @@ void WavesPanel::UIChar(int ch) {
846865 }
847866 break ;
848867 case ' e' :
849- case ' E' : FindEdge (ch == ' e' , &time_changed, &range_changed); break ;
868+ case ' E' :
869+ FindEdge (ch == ' e' , &time_changed, &range_changed);
870+ edge_search = true ;
871+ break ;
850872 case ' r' :
851873 if (item->signal != nullptr ) {
852874 item->CycleRadix ();
@@ -890,11 +912,14 @@ void WavesPanel::UIChar(int ch) {
890912 case ' A' :
891913 if (item->analog_rows > 0 ) item->analog_rows --;
892914 break ;
915+ case 0x1 : // Ctrl-a
916+ item->CycleAnalogType ();
917+ break ;
893918 default : Panel::UIChar (ch);
894919 }
895920 }
896921 if (time_changed) {
897- SnapToValue ();
922+ if (!edge_search) SnapToValue ();
898923 UpdateValues ();
899924 }
900925 if (range_changed) UpdateWaves ();
@@ -1168,9 +1193,6 @@ std::vector<Tooltip> WavesPanel::Tooltips() const {
11681193 {" -" , " default color" },
11691194 };
11701195 }
1171- // TODO: Missing features
1172- // "C-r": "Reload",
1173- // "aA" : "Adjust analog height",
11741196 std::vector<Tooltip> tt{
11751197 {" zZ" , " Zoom" },
11761198 {" F" , " Zoom full" },
@@ -1179,25 +1201,26 @@ std::vector<Tooltip> WavesPanel::Tooltips() const {
11791201 {" eE" , " Prev/next edge" },
11801202 {" sS" , " Adjust size" },
11811203 {" aA" , " Analog size" },
1182- {" 0" , " Show leading zeroes" },
1183- {" c" , " Change signal color" },
1184- {" p" , " Show full signal path" },
1204+ {" C-a" , " Analog type" },
1205+ {" 0" , " Leading zeroes" },
1206+ {" c" , " Signal color" },
1207+ {" p" , " Show path" },
11851208 {" T" , " Go to time" },
11861209 {" t" , " Cycle time units" },
11871210 {" m" , " Place marker" },
1188- {" M" , " Place numbered marker" },
1211+ {" M" , " Place # marker" },
11891212 {" C-g" , " Create group" },
11901213 {" R" , " Rename group" },
1191- {" UD" , " Move signal up / down " },
1192- {" b" , " Insert blank signal " },
1193- {" x" , " Delete highlighted signal " },
1194- {" r" , " Cycle signal radix" },
1214+ {" UD" , " Move signal up/dn " },
1215+ {" b" , " Insert blank" },
1216+ {" x" , " Delete" },
1217+ {" r" , " Cycle radix" },
11951218 {" C-u" , " Toggle Unicode" },
11961219 {" C-o" , " Open list file" },
11971220 {" C-s" , " Save list file" },
11981221 };
11991222 if (Workspace::Get ().Design () != nullptr ) {
1200- tt.push_back ({" d" , " Show signal declaration in source " });
1223+ tt.push_back ({" d" , " Declaration " });
12011224 }
12021225 return tt;
12031226}
@@ -1218,6 +1241,13 @@ void WavesPanel::ListItem::CycleRadix() {
12181241 }
12191242}
12201243
1244+ void WavesPanel::ListItem::CycleAnalogType () {
1245+ switch (analog_type) {
1246+ case AnalogWaveType::kLinear : analog_type = AnalogWaveType::kSampleAndHold ; break ;
1247+ case AnalogWaveType::kSampleAndHold : analog_type = AnalogWaveType::kLinear ; break ;
1248+ }
1249+ }
1250+
12211251std::optional<const WaveData::Signal *> WavesPanel::SignalForSource () {
12221252 if (signal_for_source_ == nullptr ) return std::nullopt ;
12231253 auto s = signal_for_source_;
0 commit comments