summaryrefslogtreecommitdiff
path: root/gr-qtgui/lib/edit_box_msg_impl.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gr-qtgui/lib/edit_box_msg_impl.cc')
-rw-r--r--gr-qtgui/lib/edit_box_msg_impl.cc571
1 files changed, 571 insertions, 0 deletions
diff --git a/gr-qtgui/lib/edit_box_msg_impl.cc b/gr-qtgui/lib/edit_box_msg_impl.cc
new file mode 100644
index 0000000000..e0c5f64b3d
--- /dev/null
+++ b/gr-qtgui/lib/edit_box_msg_impl.cc
@@ -0,0 +1,571 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2016 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "edit_box_msg_impl.h"
+#include <gnuradio/io_signature.h>
+#include <gnuradio/prefs.h>
+#include <gnuradio/qtgui/utils.h>
+#include <boost/lexical_cast.hpp>
+
+namespace gr {
+ namespace qtgui {
+
+ edit_box_msg::sptr
+ edit_box_msg::make(data_type_t type, const std::string &label,
+ const std::string &value,
+ bool is_pair, bool is_static,
+ const std::string &key, QWidget* parent)
+ {
+ return gnuradio::get_initial_sptr
+ (new edit_box_msg_impl(type, value, label, is_pair,
+ is_static, key, parent));
+ }
+
+ edit_box_msg_impl::edit_box_msg_impl(data_type_t type, const std::string &label,
+ const std::string &value,
+ bool is_pair, bool is_static,
+ const std::string &key, QWidget* parent)
+ : block("edit_box_msg",
+ io_signature::make(0, 0, 0),
+ io_signature::make(0, 0, 0)),
+ QObject(parent)
+ {
+ // Required now for Qt; argc must be greater than 0 and argv
+ // must have at least one valid character. Must be valid through
+ // life of the qApplication:
+ // http://harmattan-dev.nokia.com/docs/library/html/qt4/qapplication.html
+ d_argc = 1;
+ d_argv = new char;
+ d_argv[0] = '\0';
+
+ if(qApp != NULL) {
+ d_qApplication = qApp;
+ }
+ else {
+#if QT_VERSION >= 0x040500
+ std::string style = prefs::singleton()->get_string("qtgui", "style", "raster");
+ QApplication::setGraphicsSystem(QString(style.c_str()));
+#endif
+ d_qApplication = new QApplication(d_argc, &d_argv);
+ }
+
+ // If a style sheet is set in the prefs file, enable it here.
+ std::string qssfile = prefs::singleton()->get_string("qtgui","qss","");
+ if(qssfile.size() > 0) {
+ QString sstext = get_qt_style_sheet(QString(qssfile.c_str()));
+ d_qApplication->setStyleSheet(sstext);
+ }
+
+ d_is_pair = is_pair;
+ d_is_static = is_static;
+
+ d_val = new QLineEdit();
+ d_val->setObjectName("qtgui_editboxmsg_val"); // used to set background color
+ d_val->setText(QString(value.c_str()));
+
+ set_type(type);
+
+ d_group = new QGroupBox();
+ d_vlayout = new QVBoxLayout(parent);
+ d_hlayout = new QHBoxLayout(parent);
+
+ if(d_is_pair) {
+ d_key = new QLineEdit();
+
+ QString key_text = QString(key.c_str());
+ d_key->setText(key_text);
+
+ // If static, we create the d_key object, which we use later
+ // to be consistent about getting the key string. But we do
+ // not add it to the layout.
+ if(d_is_static) {
+ d_key->setEnabled(false);
+
+ QFontMetrics fm = d_key->fontMetrics();
+ int width = 15 + fm.width(key_text);
+
+ d_key->setFixedWidth(width);
+
+ // Verify that a default key has been set or emit an error
+ if(key.size() == 0) {
+ throw std::runtime_error("When using static + pair mode, please set a default key.");
+ }
+ }
+ else {
+ // Adding it to the layout if in non-static mode so users
+ // can see and update the key.
+ d_hlayout->addWidget(d_key);
+ }
+ }
+
+ d_label = NULL;
+ if(label != "") {
+ d_label = new QLabel(QString(label.c_str()));
+ d_vlayout->addWidget(d_label);
+ }
+
+ d_hlayout->addWidget(d_val);
+
+ if(!d_is_static) {
+ // If not static, we can change the key and the data type of
+ // the value box.
+ d_type_box = new QComboBox();
+ d_type_box->setEditable(false);
+
+ // Items listed in order of enum data_type_t
+ d_type_box->addItem("Int");
+ d_type_box->addItem("Float");
+ d_type_box->addItem("Double");
+ d_type_box->addItem("Complex");
+ d_type_box->addItem("String");
+ d_type_box->addItem("Int (vec)");
+ d_type_box->addItem("Float (vec)");
+ d_type_box->addItem("Double (vec)");
+ d_type_box->addItem("Complex (vec)");
+ d_type_box->setCurrentIndex(d_type);
+ d_hlayout->addWidget(d_type_box);
+
+ QObject::connect(d_type_box, SIGNAL(currentIndexChanged(int)),
+ this, SLOT(set_type(int)));
+ }
+
+ d_vlayout->addItem(d_hlayout);
+ d_group->setLayout(d_vlayout);
+
+ QObject::connect(d_val, SIGNAL(editingFinished()),
+ this, SLOT(edit_finished()));
+
+ d_msg = pmt::PMT_NIL;
+
+ message_port_register_out(pmt::mp("msg"));
+ message_port_register_in(pmt::mp("val"));
+
+ set_msg_handler(pmt::mp("val"),
+ boost::bind(&edit_box_msg_impl::set_value, this, _1));
+ }
+
+ edit_box_msg_impl::~edit_box_msg_impl()
+ {
+ delete d_argv;
+ delete d_group;
+ delete d_hlayout;
+ delete d_vlayout;
+ delete d_val;
+ if(d_is_pair)
+ delete d_key;
+ if(d_label)
+ delete d_label;
+ }
+
+ bool
+ edit_box_msg_impl::start()
+ {
+ QString text = d_val->text();
+ if(!text.isEmpty()) {
+ edit_finished();
+ }
+
+ return block::start();
+ }
+
+ void
+ edit_box_msg_impl::exec_()
+ {
+ d_qApplication->exec();
+ }
+
+ QWidget*
+ edit_box_msg_impl::qwidget()
+ {
+ return (QWidget*)d_group;
+ }
+
+#ifdef ENABLE_PYTHON
+ PyObject*
+ edit_box_msg_impl::pyqwidget()
+ {
+ PyObject *w = PyLong_FromVoidPtr((void*)d_group);
+ PyObject *retarg = Py_BuildValue("N", w);
+ return retarg;
+ }
+#else
+ void *
+ edit_box_msg_impl::pyqwidget()
+ {
+ return NULL;
+ }
+#endif
+
+ void
+ edit_box_msg_impl::set_type(int type)
+ {
+ set_type(static_cast<data_type_t>(type));
+ }
+
+ void
+ edit_box_msg_impl::set_type(gr::qtgui::data_type_t type)
+ {
+ d_type = type;
+
+ switch(d_type) {
+ case INT:
+ case INT_VEC:
+ d_val->setStyleSheet("QLineEdit#qtgui_editboxmsg_val {background-color: #4CAF50;}");
+ break;
+ case FLOAT:
+ case FLOAT_VEC:
+ d_val->setStyleSheet("QLineEdit#qtgui_editboxmsg_val {background-color: #F57C00;}");
+ break;
+ case DOUBLE:
+ case DOUBLE_VEC:
+ d_val->setStyleSheet("QLineEdit#qtgui_editboxmsg_val {background-color: #00BCD4;}");
+ break;
+ case COMPLEX:
+ case COMPLEX_VEC:
+ d_val->setStyleSheet("QLineEdit#qtgui_editboxmsg_val {background-color: #2196F3;}");
+ break;
+ case STRING:
+ d_val->setStyleSheet("QLineEdit#qtgui_editboxmsg_val {background-color: #FFFFFF; color: #000000;}");
+ break;
+ }
+ }
+
+ void
+ edit_box_msg_impl::set_value(pmt::pmt_t val)
+ {
+ // If the contents of the new value are the same as we already
+ // had, don't update anything, just exit and move on.
+ if(pmt::eqv(val, d_msg)) {
+ return;
+ }
+
+ int xi;
+ float xf;
+ double xd;
+ std::string xs;
+ gr_complex xc;
+
+ d_msg = val;
+
+ // Only update key if we're expecting a pair
+ if(d_is_pair) {
+ // If we are, make sure that the PMT is actually a pair
+ if(pmt::is_pair(val)) {
+ pmt::pmt_t key = pmt::car(val);
+ std::string skey = pmt::symbol_to_string(key);
+
+ // If static, check to make sure that the key of the
+ // incoming message matches our key. If it doesn't, emit a
+ // warning and exit without changing anything.
+ if(d_is_static) {
+ std::string cur_key = d_key->text().toStdString();
+ if(skey != cur_key) {
+ GR_LOG_WARN(d_logger, boost::format("Got key '%1%' but expected '%2%'") \
+ % skey % cur_key);
+ return;
+ }
+ }
+ val = pmt::cdr(val);
+ d_key->setText(QString(skey.c_str()));
+ }
+ else {
+ GR_LOG_WARN(d_logger, "Did not find PMT pair");
+ return;
+ }
+ }
+
+ switch(d_type) {
+ case INT:
+ if(pmt::is_integer(val)) {
+ xi = pmt::to_long(val);
+ d_val->setText(QString::number(xi));
+ }
+ else {
+ GR_LOG_WARN(d_logger, "Conversion from integer failed");
+ return;
+ }
+ break;
+ case INT_VEC:
+ if(pmt::is_s32vector(val)) {
+ QStringList text_list;
+ const std::vector<int32_t> xv = pmt::s32vector_elements(val);
+ for(size_t i = 0; i < xv.size(); i++) {
+ text_list.append(QString::number(xv[i]));
+ }
+ d_val->setText(text_list.join(", "));
+ }
+ else {
+ GR_LOG_WARN(d_logger, "Conversion from integer vector failed");
+ return;
+ }
+ break;
+ case FLOAT:
+ if(pmt::is_real(val)) {
+ xf = pmt::to_float(val);
+ d_val->setText(QString::number(xf));
+ }
+ else {
+ GR_LOG_WARN(d_logger, "Conversion from float failed");
+ return;
+ }
+ break;
+ case FLOAT_VEC:
+ if(pmt::is_f32vector(val)) {
+ QStringList text_list;
+ const std::vector<float> xv = pmt::f32vector_elements(val);
+ for(size_t i = 0; i < xv.size(); i++) {
+ text_list.append(QString::number(xv[i]));
+ }
+ d_val->setText(text_list.join(", "));
+ }
+ else {
+ GR_LOG_WARN(d_logger, "Conversion from float vector failed");
+ return;
+ }
+ break;
+ case DOUBLE:
+ if(pmt::is_real(val)) {
+ xd = pmt::to_double(val);
+ d_val->setText(QString::number(xd));
+ }
+ else {
+ GR_LOG_WARN(d_logger, "Conversion from double failed");
+ return;
+ }
+ break;
+ case DOUBLE_VEC:
+ if(pmt::is_f64vector(val)) {
+ QStringList text_list;
+ const std::vector<double> xv = pmt::f64vector_elements(val);
+ for(size_t i = 0; i < xv.size(); i++) {
+ text_list.append(QString::number(xv[i]));
+ }
+ d_val->setText(text_list.join(", "));
+ }
+ else {
+ GR_LOG_WARN(d_logger, "Conversion from double vector failed");
+ return;
+ }
+ break;
+ case COMPLEX:
+ if(pmt::is_complex(val)) {
+ xc = pmt::to_complex(val);
+ d_val->setText(QString("(%1,%2)").arg(xc.real()).arg(xc.imag()));
+ }
+ else {
+ GR_LOG_WARN(d_logger, "Conversion from complex failed");
+ return;
+ }
+ break;
+ case COMPLEX_VEC:
+ if(pmt::is_c32vector(val)) {
+ QStringList text_list;
+ const std::vector<gr_complex> xv = pmt::c32vector_elements(val);
+ for(size_t i = 0; i < xv.size(); i++) {
+ text_list.append(QString("(%1,%2)").arg(xv[i].real()).arg(xv[i].imag()));
+ }
+ d_val->setText(text_list.join(", "));
+ }
+ else {
+ GR_LOG_WARN(d_logger, "Conversion from complex vector failed");
+ return;
+ }
+ break;
+ case STRING:
+ if(pmt::is_symbol(val)) {
+ xs = pmt::symbol_to_string(val);
+ d_val->setText(QString(xs.c_str()));
+ }
+ else {
+ GR_LOG_WARN(d_logger, "Conversion from string failed");
+ return;
+ }
+ break;
+ }
+
+ // Emit the new message to pass updates downstream.
+ // Loops are prevented by the early exit if d_msg == val.
+ message_port_pub(pmt::mp("msg"), d_msg);
+ }
+
+ void
+ edit_box_msg_impl::edit_finished()
+ {
+ QString text = d_val->text();
+ bool conv_ok = true;
+ int xi;
+ float xf;
+ double xd;
+ std::string xs;
+ gr_complex xc;
+
+ switch(d_type) {
+ case INT:
+ xi = text.toInt(&conv_ok);
+ if(conv_ok) {
+ d_msg = pmt::from_long(xi);
+ }
+ else {
+ GR_LOG_WARN(d_logger, "Conversion to integer failed");
+ return;
+ }
+ break;
+ case INT_VEC:
+ {
+ std::vector<int32_t> xv;
+ QStringList text_list = text.split(",");
+ for(int i = 0; i < text_list.size(); ++i) {
+ QString s = text_list.at(i);
+ s = s.remove(QChar(' '));
+ int t = s.toInt(&conv_ok);
+ if(conv_ok) {
+ xv.push_back(t);
+ }
+ else {
+ GR_LOG_WARN(d_logger, "Conversion to integer vector failed");
+ return;
+ }
+ }
+ d_msg = pmt::init_s32vector(xv.size(), xv);
+ }
+ break;
+ case FLOAT:
+ xf = text.toFloat(&conv_ok);
+ if(conv_ok) {
+ d_msg = pmt::from_float(xf);
+ }
+ else {
+ GR_LOG_WARN(d_logger, "Conversion to float failed");
+ return;
+ }
+ break;
+ case FLOAT_VEC:
+ {
+ std::vector<float> xv;
+ QStringList text_list = text.split(",");
+ for(int i = 0; i < text_list.size(); ++i) {
+ QString s = text_list.at(i);
+ s = s.remove(QChar(' '));
+ float t = s.toFloat(&conv_ok);
+ if(conv_ok) {
+ xv.push_back(t);
+ }
+ else {
+ GR_LOG_WARN(d_logger, "Conversion to float vector failed");
+ return;
+ }
+ }
+ d_msg = pmt::init_f32vector(xv.size(), xv);
+ }
+ break;
+ case DOUBLE:
+ xd = text.toDouble(&conv_ok);
+ if(conv_ok) {
+ d_msg = pmt::from_double(xd);
+ }
+ else {
+ GR_LOG_WARN(d_logger, "Conversion to double failed");
+ return;
+ }
+ break;
+ case DOUBLE_VEC:
+ {
+ std::vector<double> xv;
+ QStringList text_list = text.split(",");
+ for(int i = 0; i < text_list.size(); ++i) {
+ QString s = text_list.at(i);
+ s = s.remove(QChar(' '));
+ double t = s.toDouble(&conv_ok);
+ if(conv_ok) {
+ xv.push_back(t);
+ }
+ else {
+ GR_LOG_WARN(d_logger, "Conversion to double vector failed");
+ return;
+ }
+ }
+ d_msg = pmt::init_f64vector(xv.size(), xv);
+ }
+ break;
+ case COMPLEX:
+ try {
+ xc = boost::lexical_cast<gr_complex>(text.toStdString());
+ }
+ catch(boost::bad_lexical_cast const & e) {
+ GR_LOG_WARN(d_logger, boost::format("Conversion to complex failed (%1%)") \
+ % e.what());
+ return;
+ }
+ d_msg = pmt::from_complex(xc.real(), xc.imag());
+ break;
+ case COMPLEX_VEC:
+ {
+ std::vector<gr_complex> xv;
+ QStringList text_list = text.split(",");
+ bool even = false;
+ gr_complex c;
+ float re, im;
+ for(int i = 0; i < text_list.size(); ++i) {
+ QString s = text_list.at(i);
+ s = s.remove(QChar(' '));
+ s = s.remove(QChar(')'));
+ s = s.remove(QChar('('));
+ float t = s.toFloat(&conv_ok);
+ if(conv_ok) {
+ if(even) {
+ im = t;
+ xv.push_back(gr_complex(re, im));
+ even = false;
+ }
+ else {
+ re = t;
+ even = true;
+ }
+ }
+ else {
+ GR_LOG_WARN(d_logger, "Conversion to complex vector failed");
+ return;
+ }
+ }
+ d_msg = pmt::init_c32vector(xv.size(), xv);
+ }
+ break;
+ case STRING:
+ xs = text.toStdString();
+ d_msg = pmt::intern(xs);
+ break;
+ }
+
+ if(d_is_pair) {
+ std::string key = d_key->text().toStdString();
+ d_msg = pmt::cons(pmt::intern(key), d_msg);
+ }
+
+ message_port_pub(pmt::mp("msg"), d_msg);
+ }
+
+ } /* namespace qtgui */
+} /* namespace gr */