diff --git a/CMakeLists.txt b/CMakeLists.txt index 575d146de..5ee7bcb46 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,6 +49,7 @@ set (PROJECT_MANUAL "http://www.physics.princeton.edu/pulsar/K1JT/wsjtx-doc/wsjt # set (wsjt_qt_CXXSRCS NetworkServerLookup.cpp + WFPalette.cpp Radio.cpp Bands.cpp FrequencyList.cpp @@ -241,6 +242,10 @@ set (ConfigTest_UISRCS Configuration.ui ) +set (wsjt_qt_UISRCS + wf_palette_design_dialog.ui + ) + set (wsjtx_UISRCS mainwindow.ui about.ui @@ -455,12 +460,12 @@ if (NOT hamlib_FOUND) endif (NOT hamlib_FOUND) include_directories (${hamlib_INCLUDE_DIRS}) -if (WIN32) - find_library (hamlib_RUNTIME NAMES hamlib hamlib-2 PATH_SUFFIXES bin) - get_filename_component (_hamlib_runtime_path "${hamlib_RUNTIME}" PATH) - file (GLOB hamlib_BACKENDS ${_hamlib_runtime_path}/hamlib*.dll) - find_library (usb_RUNTIME NAMES usb0 PATH_SUFFIXES bin) -endif (WIN32) +# if (WIN32) +# find_library (hamlib_RUNTIME NAMES hamlib hamlib-2 PATH_SUFFIXES bin) +# get_filename_component (_hamlib_runtime_path "${hamlib_RUNTIME}" PATH) +# file (GLOB hamlib_BACKENDS ${_hamlib_runtime_path}/hamlib*.dll) +# find_library (usb_RUNTIME NAMES usb0 PATH_SUFFIXES bin) +# endif (WIN32) # @@ -535,7 +540,9 @@ add_custom_target (kvasd DEPENDS contrib/kvasd${CMAKE_EXECUTABLE_SUFFIX}) # UI generation -qt5_wrap_ui (GENUISRCS ${ConfigTest_UISRCS} ${wsjtx_UISRCS}) +qt5_wrap_ui (wsjt_qt_GENUISRCS ${wsjt_qt_UISRCS}) +qt5_wrap_ui (ConfigTest_GENUISRCS ${ConfigTest_UISRCS}) +qt5_wrap_ui (wsjtx_GENUISRCS ${wsjtx_UISRCS}) # Resource generation qt5_add_resources (wsjtx_RESOURCES_RCC wsjtx.qrc) @@ -555,7 +562,7 @@ endif (WIN32) add_library (wsjt STATIC ${wsjt_CSRCS} ${wsjt_CXXSRCS} ${wsjt_FSRCS}) # build a library of package Qt functionality -add_library (wsjt_qt STATIC ${wsjt_qt_CXXSRCS} ${GENAXSRCS}) +add_library (wsjt_qt STATIC ${wsjt_qt_CXXSRCS} ${wsjt_qt_GENUISRCS} ${GENAXSRCS}) qt5_use_modules (wsjt_qt Widgets OpenGL Network) if (WIN32) qt5_use_modules (wsjt_qt AxContainer AxBase) @@ -572,12 +579,12 @@ target_link_libraries (jt9 wsjt ${FFTW3F_LIBRARY}) qt5_use_modules (jt9 Core) # build configuration dialog and transceiver interface test application -#add_executable (ConfigTest ${ConfigTest_CXXSRCS} ${ConfigTest_UISRCS} wsjtx.rc) +#add_executable (ConfigTest ${ConfigTest_CXXSRCS} ${ConfigTest_GENUISRCS} wsjtx.rc) #target_link_libraries (ConfigTest wsjt wsjt_qt ${hamlib_LIBRARIES}) #qt5_use_modules (ConfigTest Widgets OpenGL Network Multimedia) # build the main application -add_executable (wsjtx WIN32 MACOSX_BUNDLE ${wsjtx_CXXSRCS} ${wsjtx_UISRCS} wsjtx.rc ${WSJTX_ICON_FILE} ${wsjtx_RESOURCES_RCC}) +add_executable (wsjtx WIN32 MACOSX_BUNDLE ${wsjtx_CXXSRCS} ${wsjtx_GENUISRCS} wsjtx.rc ${WSJTX_ICON_FILE} ${wsjtx_RESOURCES_RCC}) qt5_use_modules (wsjtx Widgets OpenGL Network Multimedia) set_target_properties (wsjtx PROPERTIES diff --git a/WFPalette.cpp b/WFPalette.cpp new file mode 100644 index 000000000..f39b42d9f --- /dev/null +++ b/WFPalette.cpp @@ -0,0 +1,307 @@ +#include "WFPalette.hpp" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "qt_helpers.hpp" + +#include "ui_wf_palette_design_dialog.h" + +namespace +{ + int constexpr points {256}; + + struct init + { + init () + { + qRegisterMetaTypeStreamOperators ("Colours"); + } + } static_initaializer; + + using Colours = WFPalette::Colours; + + // ensure that palette colours are useable for interpolation + Colours make_valid (Colours colours) + { + if (colours.size () < 2) + { + // allow single element by starting at black + colours.prepend (QColor {0, 0, 0}); + } + + if (1 == colours.size ()) + { + // allow empty list by using black to white + colours.append (QColor {255,255,255}); + } + + if (colours.size () > points) + { + throw_qstring (tr ("Too many colours in palette.")); + } + + return colours; + } + + // load palette colours from a file + Colours load_palette (QString const& file_name) + { + Colours colours; + QFile file {file_name}; + if (file.open (QIODevice::ReadOnly)) + { + unsigned count {0}; + QTextStream in (&file); + int line_counter {0}; + while (!in.atEnd ()) + { + auto line = in.readLine(); + ++line_counter; + + if (++count >= points) + { + throw_qstring (QObject::tr ("Error reading waterfall palette file \"%1:%2\" too many colors.") + .arg (file.fileName ().arg (line_counter)); + } + auto items = line.split (';'); + if (items.size () != 3) + { + throw_qstring (QObject::tr ("Error reading waterfall palette file \"%1:%2\" invalid triplet.") + .arg (file.fileName ()).arg (line_counter)); + } + bool r_ok, g_ok, b_ok; + auto r = items[0].toInt (&r_ok); + auto g = items[1].toInt (&g_ok); + auto b = items[2].toInt (&b_ok); + if (!r_ok || !g_ok || !b_ok + || r < 0 || r > 255 + || g < 0 || g > 255 + || b < 0 || b > 255) + { + throw_qstring (QObject::tr ("Error reading waterfall palette file \"%1:%2\" invalid color.") + .arg (file.fileName ()).arg (line_counter)); + } + colours.append (QColor {r, g, b}); + } + } + else + { + throw_qstring (QObject::tr ("Error opening waterfall palette file \"%1\".").arg (file.fileName ())); + } + + return colours; + } + + // GUI to design and manage waterfall palettes + class Designer + : public QDialog + { + Q_OBJECT; + + public: + explicit Designer (Colours const& current, QWidget * parent = nullptr) + : QDialog {parent} + , colours_ {current} + { + ui_.setupUi (this); + + // context menu actions + auto import_button = ui_.button_box->addButton ("&Import...", QDialogButtonBox::ActionRole); + connect (import_button, &QPushButton::clicked, this, &Designer::import_palette); + + auto export_button = ui_.button_box->addButton ("&Export...", QDialogButtonBox::ActionRole); + connect (export_button, &QPushButton::clicked, this, &Designer::export_palette); + + // load the table items + ui_.colour_table_widget->setRowCount (colours_.size ()); + for (int i {0}; i < colours_.size (); ++i) + { + insert_item (i); + } + + // hookup the context menu handler + connect (ui_.colour_table_widget, &QWidget::customContextMenuRequested, this, &Designer::context_menu); + } + + Colours colours () const + { + return colours_; + } + + // invoke the colour editor + Q_SLOT void on_colour_table_widget_itemDoubleClicked (QTableWidgetItem * item) + { + auto new_colour = QColorDialog::getColor (item->background ().color (), this); + if (new_colour.isValid ()) + { + item->setBackground (QBrush {new_colour}); + colours_[item->row ()] = new_colour; + } + } + + private: + void insert_item (int row) + { + std::unique_ptr item {new QTableWidgetItem {""}}; + item->setBackground (QBrush {colours_[row]}); + item->setFlags (Qt::ItemIsEnabled); + ui_.colour_table_widget->setItem (row, 0, item.release ()); + } + + void context_menu (QPoint const& p) + { + context_menu_.clear (); + if (ui_.colour_table_widget->itemAt (p)) + { + auto delete_action = context_menu_.addAction (tr ("&Delete")); + connect (delete_action, &QAction::triggered, [this] () + { + auto row = ui_.colour_table_widget->currentRow (); + ui_.colour_table_widget->removeRow (row); + colours_.removeAt (row); + }); + } + + auto insert_action = context_menu_.addAction (tr ("&Insert ...")); + connect (insert_action, &QAction::triggered, [this] () + { + auto item = ui_.colour_table_widget->itemAt (menu_pos_); + int row = item ? item->row () : colours_.size (); + + auto default_colour = QColor {0, 0, 0}; + if (row > 0) + { + // use the prior row colour + default_colour = colours_[row - 1]; + } + + auto new_colour = QColorDialog::getColor (default_colour, this); + if (new_colour.isValid ()) + { + ui_.colour_table_widget->insertRow (row); + colours_.insert (row, new_colour); + insert_item (row); + } + }); + + menu_pos_ = p; // save for context menu action handlers + context_menu_.popup (ui_.colour_table_widget->mapToGlobal (p)); + } + + void import_palette () + { + auto docs = QStandardPaths::writableLocation (QStandardPaths::DocumentsLocation); + auto file_name = QFileDialog::getOpenFileName (this, tr ("Import Palette"), docs, tr ("Palettes (*.pal)")); + if (!file_name.isEmpty ()) + { + colours_ = load_palette (file_name); + } + } + + void export_palette () + { + auto docs = QStandardPaths::writableLocation (QStandardPaths::DocumentsLocation); + auto file_name = QFileDialog::getSaveFileName (this, tr ("Export Palette"), docs, tr ("Palettes (*.pal)")); + if (!file_name.isEmpty ()) + { + if (!QFile::exists (file_name) && !file_name.contains ('.')) + { + file_name += ".pal"; + } + QFile file {file_name}; + if (file.open (QFile::WriteOnly | QFile::Truncate | QFile::Text)) + { + QTextStream stream {&file}; + Q_FOREACH (auto colour, colours_) + { + stream << colour.red () << ';' << colour.green () << ';' << colour.blue () << endl; + } + } + else + { + throw_qstring (QObject::tr ("Error writing waterfall palette file \"%1\".").arg (file.fileName ())); + } + } + } + + Ui::wf_palette_design_dialog ui_; + Colours colours_; + QMenu context_menu_; + QPoint menu_pos_; + }; +} + +#include "WFPalette.moc" + +WFPalette::WFPalette (QString const& file_path) + : colours_ {load_palette (file_path)} +{ +} + +WFPalette::WFPalette (QList const& colour_list) + : colours_ {colour_list} +{ +} + + // generate an array of colours suitable for the waterfall plotter +QVector WFPalette::interpolate () const +{ + Colours colours {make_valid (colours_)}; + QVector result; + result.reserve (points); + + // do a linear gradient between each supplied colour point + int interval = points / (colours.size () - 1); + for (int i {0}; i < points; ++i) + { + int prior {i / interval}; + + int next {prior + 1}; + if (next >= colours.size ()) + { + --next; + --prior; + } + + int increment {i - interval * prior}; + int r {colours[prior].red () + int((increment * (colours[next].red () - colours[prior].red ()))/interval)}; + int g {colours[prior].green () + int((increment * (colours[next].green () - colours[prior].green ()))/interval)}; + int b {colours[prior].blue () + int((increment * (colours[next].blue () - colours[prior].blue ()))/interval)}; + result.append (QColor {r, g, b}); + } + + return result; +} + + // invoke the palette designer +bool WFPalette::design () +{ + Designer designer {colours_}; + if (QDialog::Accepted == designer.exec ()) + { + colours_ = designer.colours (); + return true; + } + return false; +} diff --git a/WFPalette.hpp b/WFPalette.hpp new file mode 100644 index 000000000..271ca5357 --- /dev/null +++ b/WFPalette.hpp @@ -0,0 +1,55 @@ +#ifndef W_F_PALETTE_HPP__ +#define W_F_PALETTE_HPP__ + +#include +#include +#include + +class QString; + +// +// Class WFPalette +// +// Encapulates a waterfall palette description. A colour gradient +// over 256 intervals is described by a list of RGB colour triplets. +// The list of colours are use to interpolate the full 256 interval +// waterfall colour gradient. +// +// Responsibilities +// +// Construction from a string which is a path to a file containing +// colour descriptions in the form rrr;ggg;bbb on up to 256 +// consecutive lines, where rrr, ggg and, bbb are integral numbers in +// the range 0<=n<256. +// +// Construction from a list of QColor instances. Up to the first 256 +// list elements are used. +// +// Includes a design GUI to create or adjust a WFPalette. +// +class WFPalette +{ +public: + using Colours = QList; + + WFPalette () = default; + explicit WFPalette (Colours const&); + explicit WFPalette (QString const& file_path); + WFPalette (WFPalette const&) = default; + WFPalette& operator = (WFPalette const&) = default; + + Colours colours () const {return colours_;} + + // interpolate a gradient over 256 steps + QVector interpolate () const; + + // returns true if colours have been modified + bool design (); + +private: + Colours colours_; +}; + +Q_DECLARE_METATYPE (WFPalette::Colours); + +#endif diff --git a/plotter.h b/plotter.h index 64b7cb8ca..99aa8b31d 100644 --- a/plotter.h +++ b/plotter.h @@ -14,6 +14,7 @@ #endif #include #include +#include #include #include "commons.h" @@ -22,28 +23,14 @@ class CPlotter : public QFrame { - Q_OBJECT + Q_OBJECT; + public: explicit CPlotter(QWidget *parent = 0); ~CPlotter(); QSize minimumSizeHint() const; QSize sizeHint() const; - QColor m_ColorTbl[256]; - - bool m_bCurrent; - bool m_bCumulative; - bool m_bLinearAvg; - bool m_lockTxFreq; - - float m_fSpan; - - qint32 m_plotZero; - qint32 m_plotGain; - qint32 m_nSpan; - qint32 m_binsPerPixel; - qint32 m_w; - void draw(float sw[]); //Update the waterfall void SetRunningState(bool running); void setPlotZero(int plotZero); @@ -54,6 +41,7 @@ public: int startFreq(); int plotWidth(); void setNSpan(int n); + int nSpan() const {return m_nSpan;} void UpdateOverlay(); void setDataFromDisk(bool b); void setRxRange(int fMin); @@ -72,6 +60,24 @@ public: int getFmax(); void setDialFreq(double d); + void setCurrent(bool b) {m_bCurrent = b;} + bool current() const {return m_bCurrent;} + + void setCumulative(bool b) {m_bCumulative = b;} + bool cumulative() const {return m_bCumulative;} + + void setLinearAvg(bool b) {m_bLinearAvg = b;} + bool linearAvg() const {return m_bLinearAvg;} + + void setBreadth(qint32 w) {m_w = w;} + qint32 breadth() const {return m_w;} + + float fSpan() const {return m_fSpan;} + + void setLockTxFreq(bool b) {m_lockTxFreq = b;} + + void setColours(QVector const& cl) {m_ColorTbl = cl;} + signals: void freezeDecode1(int n); void setFreq1(int rxFreq, int txFreq); @@ -88,6 +94,21 @@ private: int XfromFreq(float f); float FreqfromX(int x); + QVector m_ColorTbl; + + bool m_bCurrent; + bool m_bCumulative; + bool m_bLinearAvg; + bool m_lockTxFreq; + + float m_fSpan; + + qint32 m_plotZero; + qint32 m_plotGain; + qint32 m_nSpan; + qint32 m_binsPerPixel; + qint32 m_w; + QPixmap m_WaterfallPixmap; QPixmap m_2DPixmap; QPixmap m_ScalePixmap; diff --git a/qt_helpers.hpp b/qt_helpers.hpp index f910ce6ce..670f8c423 100644 --- a/qt_helpers.hpp +++ b/qt_helpers.hpp @@ -1,9 +1,13 @@ #ifndef QT_HELPERS_HPP_ #define QT_HELPERS_HPP_ +#include + #include #include #include +#include +#include #include #define ENUM_QDATASTREAM_OPS_DECL(CLASS, ENUM) \ @@ -56,4 +60,10 @@ return QString {mo.enumerator (mo.indexOfEnumerator (#ENUM)).valueToKey (m)}; \ } +inline +void throw_qstring (QString const& qs) +{ + throw std::runtime_error (qs.toLocal8Bit ().data ()); +} + #endif diff --git a/wf_palette_design_dialog.ui b/wf_palette_design_dialog.ui new file mode 100644 index 000000000..f53e583a6 --- /dev/null +++ b/wf_palette_design_dialog.ui @@ -0,0 +1,87 @@ + + + wf_palette_design_dialog + + + + 0 + 0 + 181 + 209 + + + + Dialog + + + + + + Qt::CustomContextMenu + + + Right click to insert or delete colors. +Colors at the top represent weak signals +and colors at the bottom represent strong +signals. You can have up to 256 colors. + + + QAbstractItemView::NoSelection + + + 1 + + + true + + + + + + + + Qt::Vertical + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + button_box + accepted() + wf_palette_design_dialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + button_box + rejected() + wf_palette_design_dialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/widegraph.cpp b/widegraph.cpp index e79bd1895..3212bc37b 100644 --- a/widegraph.cpp +++ b/widegraph.cpp @@ -11,6 +11,11 @@ #define MAX_SCREENSIZE 2048 +namespace +{ + auto user_defined = QObject::tr ("User Defined"); +} + WideGraph::WideGraph(QSettings * settings, QWidget *parent) : QDialog(parent), ui(new Ui::WideGraph), @@ -26,7 +31,7 @@ WideGraph::WideGraph(QSettings * settings, QWidget *parent) : ui->widePlot->setCursor(Qt::CrossCursor); ui->widePlot->setMaximumHeight(800); - ui->widePlot->m_bCurrent=false; + ui->widePlot->setCurrent(false); connect(ui->widePlot, SIGNAL(freezeDecode1(int)),this, SLOT(wideFreezeDecode(int))); @@ -42,25 +47,25 @@ WideGraph::WideGraph(QSettings * settings, QWidget *parent) : ui->zeroSpinBox->setValue(ui->widePlot->getPlotZero()); ui->gainSpinBox->setValue(ui->widePlot->getPlotGain()); int n = m_settings->value("FreqSpan",2).toInt(); - int w = m_settings->value("PlotWidth",1000).toInt(); m_bFlatten=m_settings->value("Flatten",true).toBool(); ui->cbFlatten->setChecked(m_bFlatten); - ui->widePlot->m_w=w; + ui->widePlot->setBreadth(m_settings->value("PlotWidth",1000).toInt()); ui->freqSpanSpinBox->setValue(n); ui->widePlot->setNSpan(n); m_waterfallAvg = m_settings->value("WaterfallAvg",5).toInt(); ui->waterfallAvgSpinBox->setValue(m_waterfallAvg); - ui->widePlot->m_bCurrent=m_settings->value("Current",false).toBool(); - ui->widePlot->m_bCumulative=m_settings->value("Cumulative",true).toBool(); - ui->widePlot->m_bLinearAvg=m_settings->value("LinearAvg",false).toBool(); - if(ui->widePlot->m_bCurrent) ui->spec2dComboBox->setCurrentIndex(0); - if(ui->widePlot->m_bCumulative) ui->spec2dComboBox->setCurrentIndex(1); - if(ui->widePlot->m_bLinearAvg) ui->spec2dComboBox->setCurrentIndex(2); + ui->widePlot->setCurrent(m_settings->value("Current",false).toBool()); + ui->widePlot->setCumulative(m_settings->value("Cumulative",true).toBool()); + ui->widePlot->setLinearAvg(m_settings->value("LinearAvg",false).toBool()); + if(ui->widePlot->current()) ui->spec2dComboBox->setCurrentIndex(0); + if(ui->widePlot->cumulative()) ui->spec2dComboBox->setCurrentIndex(1); + if(ui->widePlot->linearAvg()) ui->spec2dComboBox->setCurrentIndex(2); int nbpp=m_settings->value("BinsPerPixel",2).toInt(); ui->widePlot->setBinsPerPixel(nbpp); ui->widePlot->setStartFreq(m_settings->value("StartFreq",0).toInt()); ui->fStartSpinBox->setValue(ui->widePlot->startFreq()); m_waterfallPalette=m_settings->value("WaterfallPalette","Default").toString(); + m_userPalette = WFPalette {m_settings->value("UserPalette").value ()}; int m_fMin = m_settings->value ("fMin", 2500).toInt (); ui->fMinSpinBox->setValue (m_fMin); setRxRange (m_fMin); @@ -68,10 +73,6 @@ WideGraph::WideGraph(QSettings * settings, QWidget *parent) : saveSettings (); // update config with defaults - //m_palettes_path = configuration->resources_path (); - //QString palettes_dir {":/Palettes"}; - //m_palettes_path.cd (palettes_dir); - QStringList allFiles = m_palettes_path.entryList(QDir::NoDotAndDotDot | QDir::System | QDir::Hidden | QDir::AllDirs | QDir::Files, QDir::DirsFirst); @@ -84,8 +85,14 @@ WideGraph::WideGraph(QSettings * settings, QWidget *parent) : } index++; } -// ui->paletteComboBox->lineEdit()->setAlignment(Qt::AlignHCenter); - readPalette(m_palettes_path.absoluteFilePath (m_waterfallPalette + ".pal")); + ui->paletteComboBox->addItem (user_defined); + if (user_defined == m_waterfallPalette) + { + ui->paletteComboBox->setCurrentIndex(index); + } + readPalette (); + + // ui->paletteComboBox->lineEdit()->setAlignment(Qt::AlignHCenter); } WideGraph::~WideGraph () @@ -102,17 +109,18 @@ void WideGraph::saveSettings() { m_settings->beginGroup ("WideGraph"); m_settings->setValue ("geometry", saveGeometry ()); - m_settings->setValue ("PlotZero", ui->widePlot->m_plotZero); - m_settings->setValue ("PlotGain", ui->widePlot->m_plotGain); + m_settings->setValue ("PlotZero", ui->widePlot->getPlotZero()); + m_settings->setValue ("PlotGain", ui->widePlot->getPlotGain()); m_settings->setValue ("PlotWidth", ui->widePlot->plotWidth ()); m_settings->setValue ("FreqSpan", ui->freqSpanSpinBox->value ()); m_settings->setValue ("WaterfallAvg", ui->waterfallAvgSpinBox->value ()); - m_settings->setValue ("Current", ui->widePlot->m_bCurrent); - m_settings->setValue ("Cumulative", ui->widePlot->m_bCumulative); - m_settings->setValue ("LinearAvg", ui->widePlot->m_bLinearAvg); + m_settings->setValue ("Current", ui->widePlot->current()); + m_settings->setValue ("Cumulative", ui->widePlot->cumulative()); + m_settings->setValue ("LinearAvg", ui->widePlot->linearAvg()); m_settings->setValue ("BinsPerPixel", ui->widePlot->binsPerPixel ()); m_settings->setValue ("StartFreq", ui->widePlot->startFreq ()); m_settings->setValue ("WaterfallPalette", m_waterfallPalette); + m_settings->setValue ("UserPalette", QVariant::fromValue (m_userPalette.colours ())); m_settings->setValue ("Fmin", m_fMin); m_settings->setValue("Flatten",m_bFlatten); m_settings->endGroup (); @@ -218,12 +226,12 @@ int WideGraph::rxFreq() int WideGraph::nSpan() { - return ui->widePlot->m_nSpan; + return ui->widePlot->nSpan(); } float WideGraph::fSpan() { - return ui->widePlot->m_fSpan; + return ui->widePlot->fSpan(); } int WideGraph::nStartFreq() @@ -292,12 +300,12 @@ void WideGraph::setModeTx(QString modeTx) void WideGraph::on_spec2dComboBox_currentIndexChanged(const QString &arg1) { - ui->widePlot->m_bCurrent=false; - ui->widePlot->m_bCumulative=false; - ui->widePlot->m_bLinearAvg=false; - if(arg1=="Current") ui->widePlot->m_bCurrent=true; - if(arg1=="Cumulative") ui->widePlot->m_bCumulative=true; - if(arg1=="Linear Avg") ui->widePlot->m_bLinearAvg=true; + ui->widePlot->setCurrent(false); + ui->widePlot->setCumulative(false); + ui->widePlot->setLinearAvg(false); + if(arg1=="Current") ui->widePlot->setCurrent(true); + if(arg1=="Cumulative") ui->widePlot->setCumulative(true); + if(arg1=="Linear Avg") ui->widePlot->setLinearAvg(true); } void WideGraph::on_fMinSpinBox_valueChanged(int n) @@ -309,7 +317,7 @@ void WideGraph::on_fMinSpinBox_valueChanged(int n) void WideGraph::setLockTxFreq(bool b) { m_lockTxFreq=b; - ui->widePlot->m_lockTxFreq=b; + ui->widePlot->setLockTxFreq(b); } void WideGraph::setFreq2(int rxFreq, int txFreq) @@ -330,42 +338,31 @@ void WideGraph::on_fStartSpinBox_valueChanged(int n) ui->widePlot->setStartFreq(n); } -void WideGraph::readPalette(QString fileName) +void WideGraph::readPalette () { - QFile f; - f.setFileName(fileName); - if(f.open(QIODevice::ReadOnly)) { - QTextStream in(&f); - int r[9],g[9],b[9]; - QString t; - for(int i=0; i<9; i++) { - t=in.readLine(); - r[i]=t.mid(0,3).toInt(); - g[i]=t.mid(4,3).toInt(); - b[i]=t.mid(8,3).toInt(); + try + { + if (user_defined == m_waterfallPalette) + { + ui->widePlot->setColours (WFPalette {m_userPalette}.interpolate ()); + } + else + { + ui->widePlot->setColours (WFPalette {m_palettes_path.absoluteFilePath (m_waterfallPalette + ".pal")}.interpolate()); + } } - f.close(); - for(int i=0; i<256; i++) { - int j0=i/32; - int j1=j0+1; - int k=i-32*j0; - int rr=r[j0] + int((k*(r[j1]-r[j0]))/31 + 0.5); - int gg=g[j0] + int((k*(g[j1]-g[j0]))/31 + 0.5); - int bb=b[j0] + int((k*(b[j1]-b[j0]))/31 + 0.5); - ui->widePlot->m_ColorTbl[i].setRgb(rr,gg,bb); + catch (std::exception const& e) + { + QMessageBox msgBox0; + msgBox0.setText(e.what()); + msgBox0.exec(); } - } else { - QMessageBox msgBox0; - QString t="Error: Cannot find requested palette file " + fileName; - msgBox0.setText(t); - msgBox0.exec(); - } } -void WideGraph::on_paletteComboBox_activated(const QString &palette) +void WideGraph::on_paletteComboBox_activated (QString const& palette) { - m_waterfallPalette=palette; - readPalette(m_palettes_path.absoluteFilePath(palette + ".pal")); + m_waterfallPalette = palette; + readPalette(); } void WideGraph::on_cbFlatten_toggled(bool b) @@ -373,6 +370,25 @@ void WideGraph::on_cbFlatten_toggled(bool b) m_bFlatten=b; } +void WideGraph::on_adjust_palette_push_button_clicked (bool) +{ + try + { + if (m_userPalette.design ()) + { + m_waterfallPalette = user_defined; + ui->paletteComboBox->setCurrentText (m_waterfallPalette); + readPalette (); + } + } + catch (std::exception const& e) + { + QMessageBox msgBox0; + msgBox0.setText(e.what()); + msgBox0.exec(); + } +} + bool WideGraph::flatten() { return m_bFlatten; diff --git a/widegraph.h b/widegraph.h index b571f3b1f..909d28830 100644 --- a/widegraph.h +++ b/widegraph.h @@ -5,6 +5,8 @@ #include #include +#include "WFPalette.hpp" + namespace Ui { class WideGraph; } @@ -37,7 +39,6 @@ public: void setModeTx(QString modeTx); void setLockTxFreq(bool b); double fGreen(); - void readPalette(QString fileName); bool flatten(); signals: @@ -65,11 +66,15 @@ private slots: void on_fStartSpinBox_valueChanged(int n); void on_paletteComboBox_activated(const QString &palette); void on_cbFlatten_toggled(bool b); + void on_adjust_palette_push_button_clicked (bool); private: + void readPalette(); + QScopedPointer ui; QSettings * m_settings; QDir m_palettes_path; + WFPalette m_userPalette; qint32 m_rxFreq; qint32 m_txFreq; diff --git a/widegraph.ui b/widegraph.ui index b167559dc..18e590e48 100644 --- a/widegraph.ui +++ b/widegraph.ui @@ -1,362 +1,387 @@ - - - WideGraph - - - - 0 - 0 - 799 - 395 - - - - - 0 - 0 - - - - Dialog - - - - - - - - true - - - - 0 - 0 - - - - - 400 - 100 - - - - QFrame::StyledPanel - - - QFrame::Sunken - - - 1 - - - - - - - - - <html><head/><body><p>Select data for spectral display</p></body></html> - - - 1 - - - - Current - - - - - Cumulative - - - - - Linear Avg - - - - - - - - - 0 - 0 - - - - - 80 - 0 - - - - - 38 - 16777215 - - - - Number of FFTs averaged (controls waterfall scrolling rate) - - - N Avg - - - 1 - - - 20 - - - - - - - - 0 - 0 - - - - - 80 - 0 - - - - Select waterfall palette - - - - - - - Palette - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - - 0 - 0 - - - - - 110 - 0 - - - - Decode JT65 below this frequency, JT9 above - - - JT9 - - - JT65 - - - 0 - - - 5000 - - - 100 - - - 3000 - - - - - - - - 0 - 0 - - - - - 110 - 0 - - - - - 38 - 16777215 - - - - Compression factor for frequency scale - - - - - - Bins/Pixel - - - 1 - - - 1000 - - - 1 - - - 2 - - - - - - - - 0 - 0 - - - - - 80 - 0 - - - - Frequency (Hz) at left edge of waterfall - - - Hz - - - Start - - - 5000 - - - 100 - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 80 - 0 - - - - - 38 - 16777215 - - - - <html><head/><body><p>Gain (dB) applied to spectra before display</p></body></html> - - - Gain - - - -20 - - - 20 - - - - - - - - 80 - 0 - - - - - 38 - 16777215 - - - - <html><head/><body><p>Constant offset applied to spectra</p></body></html> - - - - - - Zero - - - -100 - - - 100 - - - - - - - Flatten - - - - - - - - - - - - CPlotter - QFrame -
plotter.h
- 1 -
-
- - -
+ + + WideGraph + + + + 0 + 0 + 799 + 395 + + + + + 0 + 0 + + + + Dialog + + + + + + + + true + + + + 0 + 0 + + + + + 400 + 100 + + + + QFrame::StyledPanel + + + QFrame::Sunken + + + 1 + + + + + + + + + <html><head/><body><p>Select data for spectral display</p></body></html> + + + 1 + + + + Current + + + + + Cumulative + + + + + Linear Avg + + + + + + + + + 0 + 0 + + + + + 80 + 0 + + + + + 38 + 16777215 + + + + Number of FFTs averaged (controls waterfall scrolling rate) + + + N Avg + + + 1 + + + 20 + + + + + + + + 0 + 0 + + + + + 80 + 0 + + + + Select waterfall palette + + + + + + + + 0 + 0 + + + + + 110 + 0 + + + + Decode JT65 below this frequency, JT9 above + + + JT9 + + + JT65 + + + 0 + + + 5000 + + + 100 + + + 3000 + + + + + + + + 0 + 0 + + + + + 110 + 0 + + + + + 38 + 16777215 + + + + Compression factor for frequency scale + + + + + + Bins/Pixel + + + 1 + + + 1000 + + + 1 + + + 2 + + + + + + + + 0 + 0 + + + + + 80 + 0 + + + + Frequency (Hz) at left edge of waterfall + + + Hz + + + Start + + + 5000 + + + 100 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 80 + 0 + + + + + 38 + 16777215 + + + + <html><head/><body><p>Gain (dB) applied to spectra before display</p></body></html> + + + Gain + + + -20 + + + 20 + + + + + + + Flatten + + + + + + + + 80 + 0 + + + + + 38 + 16777215 + + + + <html><head/><body><p>Constant offset applied to spectra</p></body></html> + + + + + + Zero + + + -100 + + + 100 + + + + + + + + + Palette + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + Adjust... + + + + + + + + + Qt::Vertical + + + + + + + Qt::Vertical + + + + + + + + + + + + CPlotter + QFrame +
plotter.h
+ 1 +
+
+ + +
diff --git a/wsjtx.qrc b/wsjtx.qrc index 160ca21c6..600d44db3 100644 --- a/wsjtx.qrc +++ b/wsjtx.qrc @@ -1,39 +1,39 @@ - - - shortcuts.txt - mouse_commands.txt - prefixes.txt - cty.dat - kvasd.dat - Palettes/Banana.pal - Palettes/Blue1.pal - Palettes/Blue2.pal - Palettes/Blue3.pal - Palettes/Brown.pal - Palettes/Cyan1.pal - Palettes/Cyan2.pal - Palettes/Cyan3.pal - Palettes/Default.pal - Palettes/Digipan.pal - Palettes/Fldigi.pal - Palettes/Gray1.pal - Palettes/Gray2.pal - Palettes/Green1.pal - Palettes/Green2.pal - Palettes/Jungle.pal - Palettes/Linrad.pal - Palettes/Negative.pal - Palettes/Orange.pal - Palettes/Pink.pal - Palettes/Rainbow.pal - Palettes/Scope.pal - Palettes/Sunburst.pal - Palettes/VK4BDJ.pal - Palettes/YL2KF.pal - Palettes/Yellow1.pal - Palettes/Yellow2.pal - Palettes/ZL2FZ.pal - samples/130418_1742.wav - samples/130610_2343.wav - - \ No newline at end of file + + + shortcuts.txt + mouse_commands.txt + prefixes.txt + cty.dat + kvasd.dat + Palettes/Banana.pal + Palettes/Blue1.pal + Palettes/Blue2.pal + Palettes/Blue3.pal + Palettes/Brown.pal + Palettes/Cyan1.pal + Palettes/Cyan2.pal + Palettes/Cyan3.pal + Palettes/Default.pal + Palettes/Digipan.pal + Palettes/Fldigi.pal + Palettes/Gray1.pal + Palettes/Gray2.pal + Palettes/Green1.pal + Palettes/Green2.pal + Palettes/Jungle.pal + Palettes/Linrad.pal + Palettes/Negative.pal + Palettes/Orange.pal + Palettes/Pink.pal + Palettes/Rainbow.pal + Palettes/Scope.pal + Palettes/Sunburst.pal + Palettes/VK4BDJ.pal + Palettes/YL2KF.pal + Palettes/Yellow1.pal + Palettes/Yellow2.pal + Palettes/ZL2FZ.pal + samples/130418_1742.wav + samples/130610_2343.wav + +