From 31ebdc96187fcce349fa32432a43fd6bdb053fa5 Mon Sep 17 00:00:00 2001 From: Bill Somerville Date: Mon, 31 Mar 2014 00:03:44 +0000 Subject: [PATCH] Add user defined waterfall palette. The new class WFPalette encapsulates waterfall palettes including exporting and importing to disk files and interpolation for use in the waterfall plotter. A special entry in the palette list "User Defined" is now available along with a button to invoke a colour palette designer. The user defined palette definition is persistent across runs as it is saved in the application settings file. Palettes can now have any number of colours up to 256. The export function may be used to save user designed palettes; to be added to the built in resource palettes that are shipped with the application. git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@3964 ab8295b8-cf94-4d9e-aec4-7959e3be5d79 --- CMakeLists.txt | 27 +- WFPalette.cpp | 307 +++++++++++++++ WFPalette.hpp | 55 +++ plotter.h | 53 ++- qt_helpers.hpp | 10 + wf_palette_design_dialog.ui | 87 +++++ widegraph.cpp | 134 ++++--- widegraph.h | 7 +- widegraph.ui | 749 +++++++++++++++++++----------------- wsjtx.qrc | 78 ++-- 10 files changed, 1020 insertions(+), 487 deletions(-) create mode 100644 WFPalette.cpp create mode 100644 WFPalette.hpp create mode 100644 wf_palette_design_dialog.ui 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 + +