X-Git-Url: https://sigrok.org/gitweb/?a=blobdiff_plain;ds=sidebyside;f=pv%2Fviews%2Fdecoder_binary%2FQHexView.cpp;h=2c893e366d6d65cdafb8eaca9d3e021eb22f0a44;hb=HEAD;hp=ccd50f87bccc1291195d2b515a4ee70418e422f0;hpb=121307b3c50d981638cbe1e33ba5410bb2b11dd1;p=pulseview.git diff --git a/pv/views/decoder_binary/QHexView.cpp b/pv/views/decoder_binary/QHexView.cpp index ccd50f87..0badadc7 100644 --- a/pv/views/decoder_binary/QHexView.cpp +++ b/pv/views/decoder_binary/QHexView.cpp @@ -27,6 +27,8 @@ * SOFTWARE. */ +#include + #include #include #include @@ -34,11 +36,14 @@ #include #include #include +#include #include #include #include "QHexView.hpp" +using std::make_pair; + const unsigned int BYTES_PER_LINE = 16; const unsigned int HEXCHARS_IN_LINE = BYTES_PER_LINE * 3 - 1; const unsigned int GAP_ADR_HEX = 10; @@ -52,18 +57,15 @@ QHexView::QHexView(QWidget *parent): data_(nullptr), selectBegin_(0), selectEnd_(0), - cursorPos_(0) + cursorPos_(0), + visible_range_(0, 0), + highlighted_sample_(std::numeric_limits::max()) { setFont(QFont("Courier", 10)); charWidth_ = fontMetrics().boundingRect('X').width(); charHeight_ = fontMetrics().height(); - // Determine X coordinates of the three sub-areas - posAddr_ = 0; - posHex_ = 10 * charWidth_ + GAP_ADR_HEX; - posAscii_ = posHex_ + HEXCHARS_IN_LINE * charWidth_ + GAP_HEX_ASCII; - setFocusPolicy(Qt::StrongFocus); if (palette().color(QPalette::ButtonText).toHsv().value() > 127) { @@ -71,11 +73,13 @@ QHexView::QHexView(QWidget *parent): chunk_colors_.emplace_back(100, 149, 237); // QColorConstants::Svg::cornflowerblue chunk_colors_.emplace_back(60, 179, 113); // QColorConstants::Svg::mediumseagreen chunk_colors_.emplace_back(210, 180, 140); // QColorConstants::Svg::tan + visible_range_color_ = QColor("#fff5ee"); // QColorConstants::Svg::seashell } else { // Color is dark - chunk_colors_.emplace_back(0, 0, 139); // QColorConstants::Svg::darkblue - chunk_colors_.emplace_back(34, 139, 34); // QColorConstants::Svg::forestgreen - chunk_colors_.emplace_back(160, 82, 45); // QColorConstants::Svg::sienna + chunk_colors_.emplace_back(0, 0, 139); // QColorConstants::Svg::darkblue + chunk_colors_.emplace_back(34, 139, 34); // QColorConstants::Svg::forestgreen + chunk_colors_.emplace_back(160, 82, 45); // QColorConstants::Svg::sienna + visible_range_color_ = QColor("#fff5ee"); // QColorConstants::Svg::seashell } } @@ -99,6 +103,27 @@ void QHexView::set_data(const DecodeBinaryClass* data) } data_size_ = size; + address_digits_ = (uint8_t)QString::number(data_size_, 16).length(); + + // Calculate X coordinates of the three sub-areas + posAddr_ = 0; + posHex_ = address_digits_ * charWidth_ + GAP_ADR_HEX; + posAscii_ = posHex_ + HEXCHARS_IN_LINE * charWidth_ + GAP_HEX_ASCII; + + viewport()->update(); +} + +void QHexView::set_visible_sample_range(uint64_t start, uint64_t end) +{ + visible_range_ = make_pair(start, end); + + viewport()->update(); +} + +void QHexView::set_highlighted_data_sample(uint64_t sample) +{ + highlighted_sample_ = sample; + viewport()->update(); } @@ -113,6 +138,8 @@ void QHexView::clear() data_ = nullptr; data_size_ = 0; + highlighted_sample_ = std::numeric_limits::max(); + viewport()->update(); } @@ -159,7 +186,7 @@ size_t QHexView::create_hex_line(size_t start, size_t end, QString* dest, end = std::min((uint64_t)end, offset + BYTES_PER_LINE); if (with_offset) - dest->append(QString("%1 ").arg(row * BYTES_PER_LINE, 10, 16, QChar('0')).toUpper()); + dest->append(QString("%1 ").arg(row * BYTES_PER_LINE, address_digits_, 16, QChar('0')).toUpper()); initialize_byte_iterator(offset); for (size_t i = offset; i < offset + BYTES_PER_LINE; i++) { @@ -213,17 +240,35 @@ void QHexView::initialize_byte_iterator(size_t offset) if (current_chunk_id_ < data_->chunks.size()) current_chunk_ = data_->chunks[current_chunk_id_]; + + current_chunk_sample_ = current_chunk_.sample; + + // Obtain sample of next chunk if there is one + if ((current_chunk_id_ + 1) < data_->chunks.size()) + next_chunk_sample_ = data_->chunks[current_chunk_id_ + 1].sample; + else + next_chunk_sample_ = std::numeric_limits::max(); } -uint8_t QHexView::get_next_byte(bool* is_next_chunk) +uint8_t QHexView::get_next_byte(bool* is_new_chunk) { - if (is_next_chunk != nullptr) - *is_next_chunk = (current_chunk_offset_ == 0); + if (is_new_chunk != nullptr) + *is_new_chunk = (current_chunk_offset_ == 0); uint8_t v = 0; if (current_chunk_offset_ < current_chunk_.data.size()) v = current_chunk_.data[current_chunk_offset_]; + current_chunk_sample_ = current_chunk_.sample; + + if (is_new_chunk) { + // Obtain sample of next chunk if there is one + if ((current_chunk_id_ + 1) < data_->chunks.size()) + next_chunk_sample_ = data_->chunks[current_chunk_id_ + 1].sample; + else + next_chunk_sample_ = std::numeric_limits::max(); + } + current_offset_++; current_chunk_offset_++; @@ -266,6 +311,12 @@ void QHexView::paintEvent(QPaintEvent *event) { QPainter painter(viewport()); + QFont normal_font = painter.font(); + QFont bold_font = painter.font(); + bold_font.setWeight(QFont::Bold); + + bool bold_font_was_used = false; + // Calculate and update the widget and paint area sizes QSize widgetSize = getFullSize(); setMinimumWidth(widgetSize.width()); @@ -283,7 +334,7 @@ void QHexView::paintEvent(QPaintEvent *event) // Fill widget background painter.fillRect(event->rect(), palette().color(QPalette::Base)); - if (!data_ || (data_size_ == 0)) { + if (!data_ || (data_size_ == 0) || (data_->chunks.empty())) { painter.setPen(palette().color(QPalette::Text)); QString s = tr("No data available"); int x = (areaSize.width() - fontMetrics().boundingRect(s).width()) / 2; @@ -319,7 +370,7 @@ void QHexView::paintEvent(QPaintEvent *event) int yStart = 2 * charHeight_; for (size_t lineIdx = firstLineIdx, y = yStart; lineIdx < lastLineIdx; lineIdx++) { - QString address = QString("%1").arg(lineIdx * 16, 10, 16, QChar('0')).toUpper(); + QString address = QString("%1").arg(lineIdx * 16, address_digits_, 16, QChar('0')).toUpper(); painter.drawText(posAddr_, y, address); y += charHeight_; } @@ -331,13 +382,15 @@ void QHexView::paintEvent(QPaintEvent *event) charHeight_ - 3, QString::number(offset, 16).toUpper()); // Paint hex values - QBrush regular = palette().buttonText(); - QBrush selected = palette().highlight(); + QBrush regular_brush = palette().buttonText(); + QBrush selected_brush = palette().highlight(); + QBrush visible_range_brush = QBrush(visible_range_color_); bool multiple_chunks = (data_->chunks.size() > 1); unsigned int chunk_color = 0; initialize_byte_iterator(firstLineIdx * BYTES_PER_LINE); + yStart = 2 * charHeight_; for (size_t lineIdx = firstLineIdx, y = yStart; lineIdx < lastLineIdx; lineIdx++) { @@ -346,26 +399,42 @@ void QHexView::paintEvent(QPaintEvent *event) size_t pos = (lineIdx * BYTES_PER_LINE + i) * 2; // Fetch byte - bool is_next_chunk; - uint8_t byte_value = get_next_byte(&is_next_chunk); + bool is_new_chunk; + uint8_t byte_value = get_next_byte(&is_new_chunk); - if (is_next_chunk) { + if (is_new_chunk) { chunk_color++; if (chunk_color == chunk_colors_.size()) chunk_color = 0; + + // New chunk means also new chunk sample, so check for required changes + if (bold_font_was_used) + painter.setFont(normal_font); + if ((highlighted_sample_ >= current_chunk_sample_) && (highlighted_sample_ < next_chunk_sample_)) { + painter.setFont(bold_font); + bold_font_was_used = true; + } + } + + // Restore default paint style + painter.setBackground(regular_brush); + painter.setBackgroundMode(Qt::TransparentMode); + if (!multiple_chunks) + painter.setPen(palette().color(QPalette::Text)); + else + painter.setPen(chunk_colors_[chunk_color]); + + // Highlight needed because it's the range visible in main view? + if ((current_chunk_sample_ >= visible_range_.first) && (current_chunk_sample_ < visible_range_.second)) { + painter.setBackgroundMode(Qt::OpaqueMode); + painter.setBackground(visible_range_brush); } + // Highlight for selection range needed? (takes priority over visible range highlight) if ((pos >= selectBegin_) && (pos < selectEnd_)) { painter.setBackgroundMode(Qt::OpaqueMode); - painter.setBackground(selected); + painter.setBackground(selected_brush); painter.setPen(palette().color(QPalette::HighlightedText)); - } else { - painter.setBackground(regular); - painter.setBackgroundMode(Qt::TransparentMode); - if (!multiple_chunks) - painter.setPen(palette().color(QPalette::Text)); - else - painter.setPen(chunk_colors_[chunk_color]); } // First nibble @@ -376,7 +445,7 @@ void QHexView::paintEvent(QPaintEvent *event) val = QString::number((byte_value & 0xF), 16).toUpper(); painter.drawText(x + charWidth_, y, val); - if ((pos >= selectBegin_) && (pos < selectEnd_ - 1) && (i < BYTES_PER_LINE - 1)) + if ((i < BYTES_PER_LINE - 1) && (current_offset_ < data_size_)) painter.drawText(x + 2 * charWidth_, y, QString(' ')); x += 3 * charWidth_; @@ -393,29 +462,56 @@ void QHexView::paintEvent(QPaintEvent *event) int x = posAscii_; for (size_t i = 0; (i < BYTES_PER_LINE) && (current_offset_ < data_size_); i++) { // Fetch byte - uint8_t ch = get_next_byte(); + bool is_new_chunk; + uint8_t ch = get_next_byte(&is_new_chunk); + + if (is_new_chunk) { + // New chunk means also new chunk sample, so check for required changes + if (bold_font_was_used) + painter.setFont(normal_font); + if ((highlighted_sample_ >= current_chunk_sample_) && (highlighted_sample_ < next_chunk_sample_)) { + painter.setFont(bold_font); + bold_font_was_used = true; + } + } if ((ch < 0x20) || (ch > 0x7E)) ch = '.'; + // Restore default paint style + painter.setBackgroundMode(Qt::TransparentMode); + painter.setBackground(regular_brush); + painter.setPen(palette().color(QPalette::Text)); + + // Highlight needed because it's the range visible in main view? + if ((current_chunk_sample_ >= visible_range_.first) && (current_chunk_sample_ < visible_range_.second)) { + painter.setBackgroundMode(Qt::OpaqueMode); + painter.setBackground(visible_range_brush); + } + + // Highlight for selection range needed? (takes priority over visible range highlight) size_t pos = (lineIdx * BYTES_PER_LINE + i) * 2; if ((pos >= selectBegin_) && (pos < selectEnd_)) { painter.setBackgroundMode(Qt::OpaqueMode); - painter.setBackground(selected); + painter.setBackground(selected_brush); painter.setPen(palette().color(QPalette::HighlightedText)); - } else { - painter.setBackgroundMode(Qt::TransparentMode); - painter.setBackground(regular); - painter.setPen(palette().color(QPalette::Text)); } +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + painter.drawText(x, y, QString(QChar(ch))); +#else painter.drawText(x, y, QString(ch)); +#endif x += charWidth_; } y += charHeight_; } + // Restore painter defaults + painter.setBackgroundMode(Qt::TransparentMode); + painter.setBackground(regular_brush); + // Paint cursor if (hasFocus()) { int x = (cursorPos_ % (2 * BYTES_PER_LINE));