diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp index 93869c0..7030e00 100644 --- a/src/AppFrame.cpp +++ b/src/AppFrame.cpp @@ -158,6 +158,20 @@ AppFrame::AppFrame() : menuBar->Append(menu, wxT("Active Demodulator &Output")); + + menu = new wxMenu; + + menu->Append(wxID_THEME_DEFAULT, "Default"); + menu->Append(wxID_THEME_RADAR, "RADAR"); + menu->Append(wxID_THEME_BW, "Black & White"); + menu->Append(wxID_THEME_SHARP, "Sharp"); + menu->Append(wxID_THEME_RAD, "Rad"); + menu->Append(wxID_THEME_TOUCH, "Touch"); + menu->Append(wxID_THEME_HD, "HD"); + + menuBar->Append(menu, wxT("&Color Scheme")); + + SetMenuBar(menuBar); CreateStatusBar(); @@ -226,6 +240,27 @@ void AppFrame::OnMenu(wxCommandEvent& event) { currentSessionFile = ""; } else if (event.GetId() == wxID_EXIT) { Close(false); + } else if (event.GetId() == wxID_THEME_DEFAULT) { + waterfallCanvas->setTheme(COLOR_THEME_DEFAULT); + demodWaterfallCanvas->setTheme(COLOR_THEME_DEFAULT); + } else if (event.GetId() == wxID_THEME_SHARP) { + waterfallCanvas->setTheme(COLOR_THEME_SHARP); + demodWaterfallCanvas->setTheme(COLOR_THEME_SHARP); + } else if (event.GetId() == wxID_THEME_BW) { + waterfallCanvas->setTheme(COLOR_THEME_BW); + demodWaterfallCanvas->setTheme(COLOR_THEME_BW); + } else if (event.GetId() == wxID_THEME_RAD) { + waterfallCanvas->setTheme(COLOR_THEME_RAD); + demodWaterfallCanvas->setTheme(COLOR_THEME_RAD); + } else if (event.GetId() == wxID_THEME_TOUCH) { + waterfallCanvas->setTheme(COLOR_THEME_TOUCH); + demodWaterfallCanvas->setTheme(COLOR_THEME_TOUCH); + } else if (event.GetId() == wxID_THEME_HD) { + waterfallCanvas->setTheme(COLOR_THEME_HD); + demodWaterfallCanvas->setTheme(COLOR_THEME_HD); + } else if (event.GetId() == wxID_THEME_RADAR) { + waterfallCanvas->setTheme(COLOR_THEME_RADAR); + demodWaterfallCanvas->setTheme(COLOR_THEME_RADAR); } } diff --git a/src/AppFrame.h b/src/AppFrame.h index d773b94..893cb31 100644 --- a/src/AppFrame.h +++ b/src/AppFrame.h @@ -16,6 +16,14 @@ #define wxID_SET_FREQ_OFFSET 2001 #define wxID_RESET 2002 +#define wxID_THEME_DEFAULT 2100 +#define wxID_THEME_SHARP 2101 +#define wxID_THEME_BW 2102 +#define wxID_THEME_RAD 2103 +#define wxID_THEME_TOUCH 2104 +#define wxID_THEME_HD 2105 +#define wxID_THEME_RADAR 2106 + // Define a new frame type class AppFrame: public wxFrame { public: diff --git a/src/demod/DemodulatorInstance.cpp b/src/demod/DemodulatorInstance.cpp index 5645948..3981658 100644 --- a/src/demod/DemodulatorInstance.cpp +++ b/src/demod/DemodulatorInstance.cpp @@ -183,7 +183,7 @@ void DemodulatorInstance::squelchAuto() { } bool DemodulatorInstance::isSquelchEnabled() { - return squelch; + return (demodulatorThread->getSquelchLevel() != 0.0); } void DemodulatorInstance::setSquelchEnabled(bool state) { diff --git a/src/util/Gradient.cpp b/src/util/Gradient.cpp index 0dba7ca..fed05ac 100644 --- a/src/util/Gradient.cpp +++ b/src/util/Gradient.cpp @@ -29,8 +29,8 @@ void Gradient::generate(unsigned int len) { b_val.resize(len); for (unsigned int j = 0, jMax = colors.size() - 1; j < jMax; j++) { - if (chunk_size * (jMax + 1) < len && j == jMax - 1) { - chunk_size += len - chunk_size * (jMax + 1); + if ((chunk_size * (jMax)) < len && (j == jMax - 1)) { + chunk_size += len - chunk_size * (jMax); } for (unsigned int i = 0; i < chunk_size; i++) { diff --git a/src/visual/WaterfallCanvas.cpp b/src/visual/WaterfallCanvas.cpp index 50238f3..f2540cd 100644 --- a/src/visual/WaterfallCanvas.cpp +++ b/src/visual/WaterfallCanvas.cpp @@ -36,7 +36,7 @@ wxEND_EVENT_TABLE() WaterfallCanvas::WaterfallCanvas(wxWindow *parent, int *attribList) : InteractiveCanvas(parent, attribList), spectrumCanvas(NULL), dragState(WF_DRAG_NONE), nextDragState(WF_DRAG_NONE), fft_size(0), waterfall_lines( 0), plan( - NULL), in(NULL), out(NULL), resampler(NULL), resamplerRatio(0), lastInputBandwidth(0), zoom(1), mouseZoom(1) { + NULL), in(NULL), out(NULL), resampler(NULL), resamplerRatio(0), lastInputBandwidth(0), zoom(1), mouseZoom(1), theme(0) { glContext = new WaterfallContext(this, &wxGetApp().GetContext(this)); @@ -95,6 +95,11 @@ void WaterfallCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { glContext->SetCurrent(*this); glViewport(0, 0, ClientSize.x, ClientSize.y); + if (theme != glContext->getTheme()) { + glContext->setTheme(theme); + theme = glContext->getTheme(); + } + glContext->BeginDraw(); glContext->Draw(spectrum_points); @@ -824,3 +829,11 @@ void WaterfallCanvas::OnMouseRightReleased(wxMouseEvent& event) { mouseTracker.setHorizDragLock(false); mouseZoom = 1.0; } + +void WaterfallCanvas::setTheme(int theme_id) { + theme = theme_id; +} + +int WaterfallCanvas::getTheme() { + return glContext->getTheme(); +} diff --git a/src/visual/WaterfallCanvas.h b/src/visual/WaterfallCanvas.h index 7ab97e9..c8c8933 100644 --- a/src/visual/WaterfallCanvas.h +++ b/src/visual/WaterfallCanvas.h @@ -29,6 +29,8 @@ public: DragState getNextDragState(); void attachSpectrumCanvas(SpectrumCanvas *canvas_in); + void setTheme(int theme_id); + int getTheme(); private: void OnPaint(wxPaintEvent& event); @@ -75,6 +77,8 @@ private: int lastInputBandwidth; float mouseZoom, zoom; + int theme; + std::vector shiftBuffer; std::vector resampleBuffer; // event table diff --git a/src/visual/WaterfallContext.cpp b/src/visual/WaterfallContext.cpp index c8a732c..4284d69 100644 --- a/src/visual/WaterfallContext.cpp +++ b/src/visual/WaterfallContext.cpp @@ -3,14 +3,83 @@ #include "CubicSDR.h" WaterfallContext::WaterfallContext(WaterfallCanvas *canvas, wxGLContext *sharedContext) : - PrimaryGLContext(canvas, sharedContext), waterfall(0), waterfall_tex(NULL) { - grad.addColor(GradientColor(0, 0, 0)); - grad.addColor(GradientColor(0, 0, 1.0)); - grad.addColor(GradientColor(0, 1.0, 0)); - grad.addColor(GradientColor(1.0, 1.0, 0)); - grad.addColor(GradientColor(1.0, 0.2, 0.0)); + PrimaryGLContext(canvas, sharedContext), waterfall(0), waterfall_tex(NULL), waterfall_lines(0), fft_size(0), theme(COLOR_THEME_DEFAULT) { + Gradient *grad = new Gradient(); + grad->addColor(GradientColor(0, 0, 0)); + grad->addColor(GradientColor(0, 0, 1.0)); + grad->addColor(GradientColor(0, 1.0, 0)); + grad->addColor(GradientColor(1.0, 1.0, 0)); + grad->addColor(GradientColor(1.0, 0.2, 0.0)); + grad->generate(256); + gradients[COLOR_THEME_DEFAULT] = grad; - grad.generate(256); + grad = new Gradient(); + grad->addColor(GradientColor(0, 0, 0)); + grad->addColor(GradientColor(0.0, 0, 0.5)); + grad->addColor(GradientColor(0.0, 0.0, 1.0)); + grad->addColor(GradientColor(65.0 / 255.0, 161.0 / 255.0, 1.0)); + grad->addColor(GradientColor(1.0, 1.0, 1.0)); + grad->addColor(GradientColor(1.0, 1.0, 1.0)); + grad->addColor(GradientColor(1.0, 1.0, 0.5)); + grad->addColor(GradientColor(1.0, 1.0, 0.0)); + grad->addColor(GradientColor(1.0, 0.5, 0.0)); + grad->addColor(GradientColor(1.0, 0.25, 0.0)); + grad->addColor(GradientColor(0.5, 0.1, 0.0)); + grad->generate(256); + gradients[COLOR_THEME_SHARP] = grad; + + grad = new Gradient(); + grad->addColor(GradientColor(0, 0, 0)); + grad->addColor(GradientColor(0.75, 0.75, 0.75)); + grad->addColor(GradientColor(1.0, 1.0, 1.0)); + grad->generate(256); + gradients[COLOR_THEME_BW] = grad; + + grad = new Gradient(); + grad->addColor(GradientColor(0, 0, 0.5)); + grad->addColor(GradientColor(25.0/255.0, 154.0/255.0, 0.0)); + grad->addColor(GradientColor(201.0/255.0, 115.0/255.0, 0.0)); + grad->addColor(GradientColor(1.0, 40.0/255.0, 40.0/255.0)); + grad->addColor(GradientColor(1.0, 1.0, 1.0)); + grad->generate(256); + gradients[COLOR_THEME_RAD] = grad; + + + grad = new Gradient(); + grad->addColor(GradientColor(0, 0, 0)); + grad->addColor(GradientColor(55.0/255.0, 40.0/255.0, 55.0/255.0)); + grad->addColor(GradientColor(60.0/255.0, 60.0/255.0, 90.0/255.0)); + grad->addColor(GradientColor(0.0/255.0, 255.0/255.0, 255.0/255.0)); + grad->addColor(GradientColor(10.0/255.0, 255.0/255.0, 85.0/255.0)); + grad->addColor(GradientColor(255.0/255.0, 255.0/255.0, 75.0/255.0)); + grad->addColor(GradientColor(255.0/255.0, 0.0/255.0, 0.0/255.0)); + grad->addColor(GradientColor(255.0/255.0, 255.0/255.0, 255.0/255.0)); + grad->generate(256); + gradients[COLOR_THEME_TOUCH] = grad; + + + grad = new Gradient(); + grad->addColor(GradientColor(5.0/255.0, 5.0/255.0, 60.0/255.0)); + grad->addColor(GradientColor(5.0/255.0, 20.0/255.0, 120.0/255.0)); + grad->addColor(GradientColor(50.0/255.0, 100.0/255.0, 200.0/255.0)); + grad->addColor(GradientColor(75.0/255.0, 190.0/255.0, 100.0/255.0)); + grad->addColor(GradientColor(240.0/255.0, 55.0/255.0, 5.0/255.0)); + grad->addColor(GradientColor(255.0/255.0, 55.0/255.0, 100.0/255.0)); + grad->addColor(GradientColor(255.0/255.0, 235.0/255.0, 100.0/255.0)); + grad->addColor(GradientColor(250.0/255.0, 250.0/255.0, 250.0/255.0)); + grad->generate(256); + gradients[COLOR_THEME_HD] = grad; + + + + + grad = new Gradient(); + grad->addColor(GradientColor(5.0/255.0, 45.0/255.0, 10.0/255.0)); + grad->addColor(GradientColor(30.0/255.0, 150.0/255.0, 40.0/255.0)); + grad->addColor(GradientColor(40.0/255.0, 240.0/255.0, 60.0/255.0)); + grad->addColor(GradientColor(250.0/255.0, 250.0/255.0, 250.0/255.0)); + grad->generate(256); + gradients[COLOR_THEME_RADAR] = grad; } void WaterfallContext::Setup(int fft_size_in, int num_waterfall_lines_in) { @@ -26,7 +95,7 @@ void WaterfallContext::Setup(int fft_size_in, int num_waterfall_lines_in) { fft_size = fft_size_in; waterfall_tex = new unsigned char[fft_size * waterfall_lines]; - memset(waterfall_tex,0,fft_size * waterfall_lines); + memset(waterfall_tex, 0, fft_size * waterfall_lines); glDisable(GL_CULL_FACE); glDisable(GL_DEPTH_TEST); @@ -46,12 +115,30 @@ void WaterfallContext::Setup(int fft_size_in, int num_waterfall_lines_in) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glPixelTransferi(GL_MAP_COLOR, GL_TRUE); - glPixelMapfv(GL_PIXEL_MAP_I_TO_R, 256, &(grad.getRed())[0]); - glPixelMapfv(GL_PIXEL_MAP_I_TO_G, 256, &(grad.getGreen())[0]); - glPixelMapfv(GL_PIXEL_MAP_I_TO_B, 256, &(grad.getBlue())[0]); + glPixelMapfv(GL_PIXEL_MAP_I_TO_R, 256, &(gradients[theme]->getRed())[0]); + glPixelMapfv(GL_PIXEL_MAP_I_TO_G, 256, &(gradients[theme]->getGreen())[0]); + glPixelMapfv(GL_PIXEL_MAP_I_TO_B, 256, &(gradients[theme]->getBlue())[0]); } +void WaterfallContext::setTheme(int theme_id) { + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, waterfall); + + if (theme >= COLOR_THEME_MAX) { + theme = COLOR_THEME_MAX - 1; + } + if (theme < 0) { + theme = 0; + } + theme = theme_id; + + glPixelTransferi(GL_MAP_COLOR, GL_TRUE); + glPixelMapfv(GL_PIXEL_MAP_I_TO_R, 256, &(gradients[theme]->getRed())[0]); + glPixelMapfv(GL_PIXEL_MAP_I_TO_G, 256, &(gradients[theme]->getGreen())[0]); + glPixelMapfv(GL_PIXEL_MAP_I_TO_B, 256, &(gradients[theme]->getBlue())[0]); +} + void WaterfallContext::Draw(std::vector &points) { glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); @@ -65,8 +152,8 @@ void WaterfallContext::Draw(std::vector &points) { float wv = v; if (wv < 0.0) wv = 0.0; - if (wv > 1.0) - wv = 1.0; + if (wv > 0.99) + wv = 0.99; waterfall_tex[i] = (unsigned char) floor(wv * 255.0); } } @@ -94,3 +181,6 @@ void WaterfallContext::Draw(std::vector &points) { } +int WaterfallContext::getTheme() { + return theme; +} diff --git a/src/visual/WaterfallContext.h b/src/visual/WaterfallContext.h index 535b254..5677b93 100644 --- a/src/visual/WaterfallContext.h +++ b/src/visual/WaterfallContext.h @@ -3,6 +3,16 @@ #include "PrimaryGLContext.h" #include "Gradient.h" + +#define COLOR_THEME_DEFAULT 0 +#define COLOR_THEME_BW 1 +#define COLOR_THEME_SHARP 2 +#define COLOR_THEME_RAD 3 +#define COLOR_THEME_TOUCH 4 +#define COLOR_THEME_HD 5 +#define COLOR_THEME_RADAR 6 +#define COLOR_THEME_MAX 7 + class WaterfallCanvas; class WaterfallContext: public PrimaryGLContext { @@ -11,10 +21,13 @@ public: void Draw(std::vector &points); void Setup(int fft_size_in, int num_waterfall_lines_in); + void setTheme(int theme_id); + int getTheme(); private: - Gradient grad; + Gradient *gradients[COLOR_THEME_MAX]; GLuint waterfall; + int theme; unsigned char *waterfall_tex; int fft_size; int waterfall_lines;