2017-01-02 21:07:43 -05:00
|
|
|
// Copyright (c) Charles J. Cliffe
|
|
|
|
// SPDX-License-Identifier: GPL-2.0+
|
|
|
|
|
2015-10-27 01:56:49 -04:00
|
|
|
#include "GainCanvas.h"
|
|
|
|
|
|
|
|
#include "wx/wxprec.h"
|
|
|
|
|
|
|
|
#ifndef WX_PRECOMP
|
|
|
|
#include "wx/wx.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if !wxUSE_GLCANVAS
|
|
|
|
#error "OpenGL required: set wxUSE_GLCANVAS to 1 and rebuild the library"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "CubicSDR.h"
|
|
|
|
#include "CubicSDRDefs.h"
|
|
|
|
#include "AppFrame.h"
|
|
|
|
#include <algorithm>
|
2017-11-19 19:33:18 -05:00
|
|
|
#include <cmath>
|
2015-10-27 01:56:49 -04:00
|
|
|
|
|
|
|
wxBEGIN_EVENT_TABLE(GainCanvas, wxGLCanvas) EVT_PAINT(GainCanvas::OnPaint)
|
|
|
|
EVT_IDLE(GainCanvas::OnIdle)
|
|
|
|
EVT_MOTION(GainCanvas::OnMouseMoved)
|
|
|
|
EVT_LEFT_DOWN(GainCanvas::OnMouseDown)
|
|
|
|
EVT_LEFT_UP(GainCanvas::OnMouseReleased)
|
|
|
|
EVT_LEAVE_WINDOW(GainCanvas::OnMouseLeftWindow)
|
|
|
|
EVT_ENTER_WINDOW(GainCanvas::OnMouseEnterWindow)
|
2016-05-30 19:14:14 -04:00
|
|
|
EVT_MOUSEWHEEL(GainCanvas::OnMouseWheelMoved)
|
2015-10-27 01:56:49 -04:00
|
|
|
wxEND_EVENT_TABLE()
|
|
|
|
|
2018-03-10 02:34:39 -05:00
|
|
|
GainCanvas::GainCanvas(wxWindow *parent, const wxGLAttributes& dispAttrs) :
|
2016-03-22 20:49:15 -04:00
|
|
|
InteractiveCanvas(parent, dispAttrs) {
|
2015-10-27 01:56:49 -04:00
|
|
|
|
2018-03-10 02:34:39 -05:00
|
|
|
glContext = new PrimaryGLContext(this, &wxGetApp().GetContext(this), wxGetApp().GetContextAttributes());
|
2015-10-27 01:56:49 -04:00
|
|
|
bgPanel.setCoordinateSystem(GLPanel::GLPANEL_Y_UP);
|
|
|
|
bgPanel.setFill(GLPanel::GLPANEL_FILL_GRAD_X);
|
|
|
|
|
|
|
|
numGains = 1;
|
|
|
|
spacing = 2.0/numGains;
|
|
|
|
barWidth = (1.0/numGains)*0.8;
|
|
|
|
startPos = spacing/2.0;
|
2016-06-01 19:42:34 -04:00
|
|
|
barHeight = 0.8f;
|
2016-05-11 22:37:25 -04:00
|
|
|
refreshCounter = 0;
|
2017-11-19 19:33:18 -05:00
|
|
|
|
|
|
|
userGainAsChanged = false;
|
2015-10-27 01:56:49 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
GainCanvas::~GainCanvas() {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void GainCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
|
2019-05-24 00:30:22 -04:00
|
|
|
// wxPaintDC dc(this);
|
2015-10-27 01:56:49 -04:00
|
|
|
const wxSize ClientSize = GetClientSize();
|
|
|
|
|
|
|
|
glContext->SetCurrent(*this);
|
|
|
|
initGLExtensions();
|
|
|
|
|
|
|
|
glViewport(0, 0, ClientSize.x, ClientSize.y);
|
|
|
|
|
2016-07-07 22:37:57 -04:00
|
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
|
|
|
2015-10-27 01:56:49 -04:00
|
|
|
bgPanel.draw();
|
|
|
|
|
|
|
|
SwapBuffers();
|
|
|
|
}
|
|
|
|
|
|
|
|
void GainCanvas::OnIdle(wxIdleEvent &event) {
|
|
|
|
if (mouseTracker.mouseInView()) {
|
|
|
|
Refresh();
|
|
|
|
} else {
|
|
|
|
event.Skip();
|
|
|
|
}
|
2017-11-18 16:38:05 -05:00
|
|
|
|
|
|
|
bool areGainsChangedHere = false;
|
2015-10-27 01:56:49 -04:00
|
|
|
|
2016-07-07 22:37:57 -04:00
|
|
|
for (auto gi : gainPanels) {
|
|
|
|
if (gi->getChanged()) {
|
2017-11-19 19:33:18 -05:00
|
|
|
areGainsChangedHere = true;
|
|
|
|
// Gain only displays integer gain values, so set the applied gain
|
2017-11-19 19:33:18 -05:00
|
|
|
//value to exactly that.
|
|
|
|
wxGetApp().setGain(gi->getName(), (int)(gi->getValue()));
|
2017-11-18 16:38:05 -05:00
|
|
|
//A gain may be exposed as setting also so assure refresh of the menu also.
|
2017-11-19 19:33:18 -05:00
|
|
|
wxGetApp().notifyMainUIOfDeviceChange(false); //do not rebuild the gain UI
|
2017-11-18 16:38:05 -05:00
|
|
|
|
2016-07-07 22:37:57 -04:00
|
|
|
gi->setChanged(false);
|
2015-10-27 01:56:49 -04:00
|
|
|
}
|
|
|
|
}
|
2017-11-18 16:38:05 -05:00
|
|
|
|
2017-11-19 19:33:18 -05:00
|
|
|
//User input has changed the gain, so schedule an update of values
|
|
|
|
//in 150ms in the future, else the device may not have taken the value into account.
|
|
|
|
if (areGainsChangedHere) {
|
|
|
|
userGainAsChanged = true;
|
|
|
|
userGainAsChangedDelayTimer.start();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
userGainAsChangedDelayTimer.update();
|
|
|
|
|
|
|
|
if (!userGainAsChanged || (userGainAsChanged && userGainAsChangedDelayTimer.getMilliseconds() > 150)) {
|
|
|
|
|
|
|
|
if (updateGainValues()) {
|
|
|
|
Refresh();
|
|
|
|
}
|
|
|
|
|
|
|
|
userGainAsChanged = false;
|
2017-11-18 16:38:05 -05:00
|
|
|
}
|
|
|
|
}
|
2015-10-27 01:56:49 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void GainCanvas::SetLevel() {
|
2016-07-07 22:37:57 -04:00
|
|
|
CubicVR::vec2 mpos = mouseTracker.getGLXY();
|
|
|
|
|
|
|
|
for (auto gi : gainPanels) {
|
|
|
|
if (gi->isMeterHit(mpos)) {
|
2017-05-29 14:08:45 -04:00
|
|
|
float value = gi->getMeterHitValue(mpos);
|
2016-07-07 22:37:57 -04:00
|
|
|
|
|
|
|
gi->setValue(value);
|
2017-11-19 19:33:18 -05:00
|
|
|
gi->setChanged(true);
|
2016-07-07 22:37:57 -04:00
|
|
|
break;
|
|
|
|
}
|
2015-10-27 01:56:49 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void GainCanvas::OnMouseMoved(wxMouseEvent& event) {
|
|
|
|
InteractiveCanvas::OnMouseMoved(event);
|
|
|
|
|
2016-07-07 22:37:57 -04:00
|
|
|
CubicVR::vec2 mpos = mouseTracker.getGLXY();
|
2015-10-27 01:56:49 -04:00
|
|
|
|
2016-07-07 22:37:57 -04:00
|
|
|
for (auto gi : gainPanels) {
|
|
|
|
if (gi->isMeterHit(mpos)) {
|
2017-05-29 14:08:45 -04:00
|
|
|
float value = gi->getMeterHitValue(mpos);
|
2016-07-07 22:37:57 -04:00
|
|
|
|
|
|
|
gi->setHighlight(value);
|
|
|
|
gi->setHighlightVisible(true);
|
|
|
|
wxGetApp().setActiveGainEntry(gi->getName());
|
|
|
|
} else {
|
|
|
|
gi->setHighlightVisible(false);
|
2016-02-07 22:19:05 -05:00
|
|
|
}
|
2015-10-27 01:56:49 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (mouseTracker.mouseDown()) {
|
|
|
|
SetLevel();
|
|
|
|
}
|
2017-03-01 16:13:41 -05:00
|
|
|
else {
|
|
|
|
if (!helpTip.empty()) {
|
|
|
|
setStatusText(helpTip);
|
|
|
|
}
|
|
|
|
}
|
2015-10-27 01:56:49 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void GainCanvas::OnMouseDown(wxMouseEvent& event) {
|
|
|
|
InteractiveCanvas::OnMouseDown(event);
|
|
|
|
SetLevel();
|
|
|
|
}
|
|
|
|
|
|
|
|
void GainCanvas::OnMouseWheelMoved(wxMouseEvent& event) {
|
|
|
|
InteractiveCanvas::OnMouseWheelMoved(event);
|
2016-05-30 19:14:14 -04:00
|
|
|
|
|
|
|
CubicVR::vec2 hitResult;
|
2016-07-07 23:47:58 -04:00
|
|
|
|
|
|
|
CubicVR::vec2 mpos = mouseTracker.getGLXY();
|
|
|
|
|
|
|
|
for (auto gi : gainPanels) {
|
|
|
|
if (gi->isMeterHit(mpos)) {
|
|
|
|
float movement = 3.0 * (float)event.GetWheelRotation();
|
|
|
|
gi->setValue(gi->getValue() + ((movement / 100.0) * ((gi->getHigh() - gi->getLow()) / 100.0)));
|
|
|
|
gi->setChanged(true);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2015-10-27 01:56:49 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void GainCanvas::OnMouseReleased(wxMouseEvent& event) {
|
|
|
|
InteractiveCanvas::OnMouseReleased(event);
|
|
|
|
}
|
|
|
|
|
|
|
|
void GainCanvas::OnMouseLeftWindow(wxMouseEvent& event) {
|
|
|
|
InteractiveCanvas::OnMouseLeftWindow(event);
|
|
|
|
SetCursor(wxCURSOR_CROSS);
|
2016-07-07 22:37:57 -04:00
|
|
|
|
|
|
|
for (auto gi : gainPanels) {
|
|
|
|
gi->setHighlightVisible(false);
|
2015-10-27 01:56:49 -04:00
|
|
|
}
|
2016-07-07 22:37:57 -04:00
|
|
|
|
2015-10-27 01:56:49 -04:00
|
|
|
Refresh();
|
|
|
|
}
|
|
|
|
|
|
|
|
void GainCanvas::OnMouseEnterWindow(wxMouseEvent& event) {
|
|
|
|
InteractiveCanvas::mouseTracker.OnMouseEnterWindow(event);
|
|
|
|
SetCursor(wxCURSOR_CROSS);
|
2016-05-31 17:42:44 -04:00
|
|
|
#ifdef _WIN32
|
|
|
|
if (wxGetApp().getAppFrame()->canFocus()) {
|
|
|
|
this->SetFocus();
|
|
|
|
}
|
|
|
|
#endif
|
2015-10-27 01:56:49 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void GainCanvas::setHelpTip(std::string tip) {
|
|
|
|
helpTip = tip;
|
|
|
|
}
|
|
|
|
|
|
|
|
void GainCanvas::updateGainUI() {
|
2017-11-19 19:33:18 -05:00
|
|
|
|
2015-10-27 01:56:49 -04:00
|
|
|
SDRDeviceInfo *devInfo = wxGetApp().getDevice();
|
2017-01-21 05:26:51 -05:00
|
|
|
|
|
|
|
//possible if we 'Refresh Devices' then devInfo becomes null
|
|
|
|
//until a new device is selected.
|
|
|
|
if (devInfo == nullptr) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-05-11 22:37:25 -04:00
|
|
|
DeviceConfig *devConfig = wxGetApp().getConfig()->getDevice(devInfo->getDeviceId());
|
2017-11-19 19:33:18 -05:00
|
|
|
|
|
|
|
//read the gains from the device.
|
|
|
|
//This may be wrong because the device is not started, or has yet
|
|
|
|
//to take into account a user gain change. Doesn't matter,
|
|
|
|
//UpdateGainValues() takes cares of updating the true value realtime.
|
2016-05-11 22:37:25 -04:00
|
|
|
gains = devInfo->getGains(SOAPY_SDR_RX, 0);
|
2017-11-19 19:33:18 -05:00
|
|
|
|
|
|
|
SDRRangeMap::iterator gi;
|
2015-10-27 01:56:49 -04:00
|
|
|
|
|
|
|
numGains = gains.size();
|
|
|
|
float i = 0;
|
|
|
|
|
|
|
|
if (!numGains) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
spacing = 2.0/numGains;
|
|
|
|
barWidth = (1.0/numGains)*0.7;
|
|
|
|
startPos = spacing/2.0;
|
2016-07-07 22:37:57 -04:00
|
|
|
barHeight = 1.0f;
|
2015-10-27 01:56:49 -04:00
|
|
|
|
2016-07-07 22:37:57 -04:00
|
|
|
while (gainPanels.size()) {
|
|
|
|
MeterPanel *mDel = gainPanels.back();
|
|
|
|
gainPanels.pop_back();
|
|
|
|
bgPanel.removeChild(mDel);
|
|
|
|
delete mDel;
|
2015-10-27 01:56:49 -04:00
|
|
|
}
|
2017-11-19 19:33:18 -05:00
|
|
|
|
2016-07-07 22:37:57 -04:00
|
|
|
for (auto gi : gains) {
|
|
|
|
MeterPanel *mPanel = new MeterPanel(gi.first, gi.second.minimum(), gi.second.maximum(), devConfig->getGain(gi.first,wxGetApp().getGain(gi.first)));
|
2015-10-27 01:56:49 -04:00
|
|
|
|
2016-07-07 22:37:57 -04:00
|
|
|
float midPos = -1.0+startPos+spacing*i;
|
|
|
|
mPanel->setPosition(midPos, 0);
|
|
|
|
mPanel->setSize(barWidth, barHeight);
|
|
|
|
bgPanel.addChild(mPanel);
|
2015-10-27 01:56:49 -04:00
|
|
|
|
2016-07-07 22:37:57 -04:00
|
|
|
gainPanels.push_back(mPanel);
|
2015-10-27 01:56:49 -04:00
|
|
|
i++;
|
|
|
|
}
|
2017-11-19 19:33:18 -05:00
|
|
|
|
2015-10-27 01:56:49 -04:00
|
|
|
setThemeColors();
|
|
|
|
}
|
|
|
|
|
2017-11-18 16:38:05 -05:00
|
|
|
// call this to refresh the gain values only, not the whole UI.
|
|
|
|
bool GainCanvas::updateGainValues() {
|
|
|
|
|
|
|
|
bool isRefreshNeeded = false;
|
|
|
|
|
|
|
|
SDRDeviceInfo *devInfo = wxGetApp().getDevice();
|
|
|
|
|
|
|
|
//possible if we 'Refresh Devices' then devInfo becomes null
|
|
|
|
//until a new device is selected.
|
2017-11-19 19:33:18 -05:00
|
|
|
//also, do not attempt an update with the device is not started.
|
|
|
|
if (devInfo == nullptr || !devInfo->isActive()) {
|
2017-11-18 16:38:05 -05:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
DeviceConfig *devConfig = wxGetApp().getConfig()->getDevice(devInfo->getDeviceId());
|
|
|
|
|
|
|
|
gains = devInfo->getGains(SOAPY_SDR_RX, 0);
|
|
|
|
SDRRangeMap::iterator gi;
|
|
|
|
|
|
|
|
size_t numGainsToRefresh = std::min(gains.size(), gainPanels.size());
|
|
|
|
size_t panelIndex = 0;
|
|
|
|
|
|
|
|
//actually the order of gains iteration should be constant because map of string,
|
|
|
|
//and gainPanels were built in that order in updateGainUI()
|
|
|
|
for (auto gi : gains) {
|
|
|
|
|
|
|
|
if (panelIndex >= numGainsToRefresh) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// do not update if a change is already pending.
|
|
|
|
if (!gainPanels[panelIndex]->getChanged()) {
|
|
|
|
|
2017-11-19 19:33:18 -05:00
|
|
|
//read the actual gain from the device, round it
|
|
|
|
float actualRoundedGain = (float)std::round(devInfo->getCurrentGain(SOAPY_SDR_RX, 0, gi.first));
|
2017-11-18 16:38:05 -05:00
|
|
|
|
|
|
|
//do nothing if the difference is less than 1.0, since the panel do not show it anyway.
|
2017-11-19 19:33:18 -05:00
|
|
|
if ((int)actualRoundedGain != (int)(gainPanels[panelIndex]->getValue())) {
|
2017-11-18 16:38:05 -05:00
|
|
|
|
2017-11-19 19:33:18 -05:00
|
|
|
gainPanels[panelIndex]->setValue(actualRoundedGain);
|
2017-11-18 16:38:05 -05:00
|
|
|
|
|
|
|
//update the config with this value :
|
|
|
|
//a consequence of such updates is that the use setting
|
|
|
|
// is overriden by the current one in AGC mode.
|
|
|
|
//TODO: if it not desirable, do not update in AGC mode.
|
2017-11-19 19:33:18 -05:00
|
|
|
devConfig->setGain(gi.first, actualRoundedGain);
|
2017-11-18 16:38:05 -05:00
|
|
|
|
|
|
|
isRefreshNeeded = true;
|
|
|
|
}
|
|
|
|
} //end if no external change pending.
|
|
|
|
|
|
|
|
panelIndex++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return isRefreshNeeded;
|
|
|
|
}
|
|
|
|
|
2015-10-27 01:56:49 -04:00
|
|
|
void GainCanvas::setThemeColors() {
|
2016-07-07 23:47:58 -04:00
|
|
|
RGBA4f c1, c2;
|
|
|
|
|
|
|
|
c1 = ThemeMgr::mgr.currentTheme->generalBackground;
|
|
|
|
c2 = ThemeMgr::mgr.currentTheme->generalBackground * 0.5;
|
|
|
|
c1.a = 1.0;
|
|
|
|
c2.a = 1.0;
|
|
|
|
bgPanel.setFillColor(c1, c2);
|
|
|
|
|
2015-10-27 01:56:49 -04:00
|
|
|
Refresh();
|
|
|
|
}
|
|
|
|
|