#include <QAction>
#include <QApplication>
+#include <QClipboard>
#include <QComboBox>
#include <QFileDialog>
#include <QFormLayout>
// Iterate through the rows
int y = get_visual_y();
- pair<uint64_t, uint64_t> sample_range = get_sample_range(pp.left(), pp.right());
+ pair<uint64_t, uint64_t> sample_range = get_view_sample_range(pp.left(), pp.right());
// Just because the view says we see a certain sample range it
// doesn't mean we have this many decoded samples, too, so crop
paint_hover_marker(p);
}
+void DecodeTrace::update_stack_button()
+{
+ const vector< shared_ptr<data::decode::Decoder> > &stack = decode_signal_->decoder_stack();
+
+ // Only show decoders in the menu that can be stacked onto the last one in the stack
+ if (!stack.empty()) {
+ const srd_decoder* d = stack.back()->decoder();
+
+ if (d->outputs) {
+ pv::widgets::DecoderMenu *const decoder_menu =
+ new pv::widgets::DecoderMenu(stack_button_, (const char*)(d->outputs->data));
+ connect(decoder_menu, SIGNAL(decoder_selected(srd_decoder*)),
+ this, SLOT(on_stack_decoder(srd_decoder*)));
+
+ stack_button_->setMenu(decoder_menu);
+ stack_button_->show();
+ return;
+ }
+ }
+
+ // No decoders available for stacking
+ stack_button_->setMenu(nullptr);
+ stack_button_->hide();
+}
+
void DecodeTrace::populate_popup_form(QWidget *parent, QFormLayout *form)
{
using pv::data::decode::Decoder;
}
// Add stacking button
- pv::widgets::DecoderMenu *const decoder_menu =
- new pv::widgets::DecoderMenu(parent);
- connect(decoder_menu, SIGNAL(decoder_selected(srd_decoder*)),
- this, SLOT(on_stack_decoder(srd_decoder*)));
-
- QPushButton *const stack_button =
- new QPushButton(tr("Stack Decoder"), parent);
- stack_button->setMenu(decoder_menu);
- stack_button->setToolTip(tr("Stack a higher-level decoder on top of this one"));
+ stack_button_ = new QPushButton(tr("Stack Decoder"), parent);
+ stack_button_->setToolTip(tr("Stack a higher-level decoder on top of this one"));
+ update_stack_button();
QHBoxLayout *stack_button_box = new QHBoxLayout;
- stack_button_box->addWidget(stack_button, 0, Qt::AlignRight);
+ stack_button_box->addWidget(stack_button_, 0, Qt::AlignRight);
form->addRow(stack_button_box);
}
QMenu* DecodeTrace::create_view_context_menu(QWidget *parent, QPoint &click_pos)
{
+ // Get entries from default menu before adding our own
+ QMenu *const menu = new QMenu(parent);
+
+ QMenu* default_menu = Trace::create_view_context_menu(parent, click_pos);
+ if (default_menu) {
+ for (QAction *action : default_menu->actions()) { // clazy:exclude=range-loop
+ menu->addAction(action);
+ if (action->parent() == default_menu)
+ action->setParent(menu);
+ }
+ delete default_menu;
+
+ // Add separator if needed
+ if (menu->actions().length() > 0)
+ menu->addSeparator();
+ }
+
try {
selected_row_ = &visible_rows_[get_row_at_point(click_pos)];
} catch (out_of_range&) {
selected_row_ = nullptr;
}
+ const View *const view = owner_->view();
+ assert(view);
+ QPoint pos = view->viewport()->mapFrom(parent, click_pos);
+
// Default sample range is "from here"
- const pair<uint64_t, uint64_t> sample_range =
- get_sample_range(click_pos.x(), click_pos.x() + 1);
+ const pair<uint64_t, uint64_t> sample_range = get_view_sample_range(pos.x(), pos.x() + 1);
selected_sample_range_ = make_pair(sample_range.first, numeric_limits<uint64_t>::max());
- QMenu *const menu = new QMenu(parent);
-
if (decode_signal_->is_paused()) {
QAction *const resume =
new QAction(tr("Resume decoding"), this);
menu->addAction(pause);
}
+ QAction *const copy_annotation_to_clipboard =
+ new QAction(tr("Copy annotation text to clipboard"), this);
+ copy_annotation_to_clipboard->setIcon(QIcon::fromTheme("edit-paste",
+ QIcon(":/icons/edit-paste.png")));
+ connect(copy_annotation_to_clipboard, SIGNAL(triggered()), this, SLOT(on_copy_annotation_to_clipboard()));
+ menu->addAction(copy_annotation_to_clipboard);
+
menu->addSeparator();
QAction *const export_all_rows =
connect(export_row_with_cursor, SIGNAL(triggered()), this, SLOT(on_export_row_with_cursor()));
menu->addAction(export_row_with_cursor);
- const View *view = owner_->view();
- assert(view);
-
if (!view->cursors()->enabled()) {
export_all_rows_with_cursor->setEnabled(false);
export_row_with_cursor->setEnabled(false);
return make_pair(pixels_offset, samplerate * scale);
}
-pair<uint64_t, uint64_t> DecodeTrace::get_sample_range(
+pair<uint64_t, uint64_t> DecodeTrace::get_view_sample_range(
int x_start, int x_end) const
{
double samples_per_pixel, pixels_offset;
return QString();
const pair<uint64_t, uint64_t> sample_range =
- get_sample_range(point.x(), point.x() + 1);
+ get_view_sample_range(point.x(), point.x() + 1);
const int row = get_row_at_point(point);
if (row < 0)
return QString();
QString ann = get_annotation_at_point(hp);
- assert(view);
-
if (!row_height_ || ann.isEmpty()) {
QToolTip::hideText();
return;
const vector<DecodeChannel> channels = decode_signal_->get_channels();
// Add the channels
- for (DecodeChannel ch : channels) {
+ for (const DecodeChannel& ch : channels) {
// Ignore channels not part of the decoder we create the form for
if (ch.decoder_ != dec)
continue;
}
QMessageBox msg(owner_->view());
- msg.setText(tr("Error"));
- msg.setInformativeText(tr("File %1 could not be written to.").arg(file_name));
+ msg.setText(tr("Error") + "\n\n" + tr("File %1 could not be written to.").arg(file_name));
msg.setStandardButtons(QMessageBox::Ok);
msg.setIcon(QMessageBox::Warning);
msg.exec();
owner_->row_item_appearance_changed(false, true);
}
+void DecodeTrace::on_copy_annotation_to_clipboard()
+{
+ using namespace pv::data::decode;
+
+ if (!selected_row_)
+ return;
+
+ vector<Annotation> *annotations = new vector<Annotation>();
+
+ decode_signal_->get_annotation_subset(*annotations, *selected_row_,
+ current_segment_, selected_sample_range_.first, selected_sample_range_.first);
+
+ if (annotations->empty())
+ return;
+
+ QClipboard *clipboard = QGuiApplication::clipboard();
+ clipboard->setText(annotations->front().annotations().front());
+
+ delete annotations;
+}
+
void DecodeTrace::on_export_row()
{
selected_sample_range_ = make_pair(0, numeric_limits<uint64_t>::max());