Merge pull request #10 from cjcliffe/canvas_interaction

Canvas interaction
This commit is contained in:
Charles J. Cliffe 2014-11-26 00:38:21 -05:00
commit d33ef25a79
12 changed files with 329 additions and 52 deletions

View File

@ -95,6 +95,7 @@ SET (cubicsdr_sources
src/audio/AudioThread.cpp
src/util/Gradient.cpp
src/util/Timer.cpp
src/util/MouseTracker.cpp
src/visual/PrimaryGLContext.cpp
src/visual/ScopeCanvas.cpp
src/visual/ScopeContext.cpp
@ -115,6 +116,7 @@ SET (cubicsdr_headers
src/util/Gradient.h
src/util/Timer.h
src/util/ThreadQueue.h
src/util/MouseTracker.h
src/visual/PrimaryGLContext.h
src/visual/ScopeCanvas.h
src/visual/ScopeContext.h

View File

@ -36,6 +36,10 @@ public:
return iqVisualQueue;
}
DemodulatorInstance *getDemodTest() {
return demodulatorTest;
}
private:
PrimaryGLContext *m_glContext;

118
src/util/MouseTracker.cpp Normal file
View File

@ -0,0 +1,118 @@
#include "MouseTracker.h"
#include <iostream>
void MouseTracker::OnMouseMoved(wxMouseEvent& event) {
if (target == NULL) {
return;
}
const wxSize ClientSize = target->GetClientSize();
mouseX = (float) event.m_x / (float) ClientSize.x;
mouseY = (float) event.m_y / (float) ClientSize.y;
deltaMouseX = mouseX - lastMouseX;
deltaMouseY = mouseY - lastMouseY;
if (isMouseDown) {
lastMouseX = mouseX;
if (vertDragLock && mouseY != lastMouseY) {
target->WarpPointer(event.m_x, lastMouseY * ClientSize.y);
} else {
lastMouseY = mouseY;
}
} else {
lastMouseY = mouseY;
lastMouseX = mouseX;
}
}
void MouseTracker::OnMouseDown(wxMouseEvent& event) {
if (target == NULL) {
return;
}
const wxSize ClientSize = target->GetClientSize();
mouseX = lastMouseX = (float) event.m_x / (float) ClientSize.x;
mouseY = lastMouseY = (float) event.m_y / (float) ClientSize.y;
originMouseX = mouseX;
originMouseY = mouseY;
isMouseDown = true;
}
void MouseTracker::OnMouseWheelMoved(wxMouseEvent& event) {
// std::cout << "wheel?" << std::endl;
}
void MouseTracker::OnMouseReleased(wxMouseEvent& event) {
isMouseDown = false;
}
void MouseTracker::OnMouseEnterWindow(wxMouseEvent& event) {
isMouseInView = true;
}
void MouseTracker::OnMouseLeftWindow(wxMouseEvent& event) {
isMouseDown = false;
isMouseInView = false;
}
float MouseTracker::getOriginMouseX() {
return originMouseX;
}
float MouseTracker::getOriginMouseY() {
return originMouseY;
}
float MouseTracker::getOriginDeltaMouseX() {
return mouseX - originMouseX;
}
float MouseTracker::getOriginDeltaMouseY() {
return mouseY - originMouseY;
}
float MouseTracker::getDeltaMouseX() {
return deltaMouseX;
}
float MouseTracker::getDeltaMouseY() {
return deltaMouseY;
}
float MouseTracker::getLastMouseX() {
return lastMouseX;
}
float MouseTracker::getLastMouseY() {
return lastMouseY;
}
float MouseTracker::getMouseX() {
return mouseX;
}
float MouseTracker::getMouseY() {
return mouseY;
}
void MouseTracker::setVertDragLock(bool dragLock) {
vertDragLock = dragLock;
}
bool MouseTracker::mouseDown() {
return isMouseDown;
}
bool MouseTracker::mouseInView() {
return isMouseInView;
}
void MouseTracker::setTarget(wxWindow *target_in) {
target = target_in;
}

51
src/util/MouseTracker.h Normal file
View File

@ -0,0 +1,51 @@
#pragma once
#include "wx/window.h"
class MouseTracker {
public:
MouseTracker(wxWindow *target) :
target(target), mouseX(0), mouseY(0), lastMouseX(0), lastMouseY(0), originMouseX(0), originMouseY(0), deltaMouseX(0), deltaMouseY(0), isMouseDown(
false), vertDragLock(false), isMouseInView(false) {
}
MouseTracker() :
target(NULL), mouseX(0), mouseY(0), lastMouseX(0), lastMouseY(0), originMouseX(0), originMouseY(0), deltaMouseX(0), deltaMouseY(0), isMouseDown(
false), vertDragLock(false), isMouseInView(false) {
}
void OnMouseMoved(wxMouseEvent& event);
void OnMouseDown(wxMouseEvent& event);
void OnMouseWheelMoved(wxMouseEvent& event);
void OnMouseReleased(wxMouseEvent& event);
void OnMouseEnterWindow(wxMouseEvent& event);
void OnMouseLeftWindow(wxMouseEvent& event);
float getOriginMouseX();
float getOriginMouseY();
float getOriginDeltaMouseX();
float getOriginDeltaMouseY();
float getDeltaMouseX();
float getDeltaMouseY();
float getLastMouseX();
float getLastMouseY();
float getMouseX();
float getMouseY();
void setVertDragLock(bool dragLock);
bool mouseDown();
bool mouseInView();
void setTarget(wxWindow *target_in);
private:
float mouseX, mouseY;
float lastMouseX, lastMouseY;
float deltaMouseX, deltaMouseY;
float originMouseX, originMouseY;
bool isMouseDown, isMouseInView;
bool vertDragLock;
wxWindow *target;
};

View File

@ -29,7 +29,7 @@ wxEND_EVENT_TABLE()
SpectrumCanvas::SpectrumCanvas(wxWindow *parent, int *attribList) :
wxGLCanvas(parent, wxID_ANY, attribList, wxDefaultPosition, wxDefaultSize,
wxFULL_REPAINT_ON_RESIZE), parent(parent), frameTimer(0), isMouseDown(false) {
wxFULL_REPAINT_ON_RESIZE), parent(parent), frameTimer(0) {
int in_block_size = BUF_SIZE / 2;
int out_block_size = FFT_SIZE;
@ -44,6 +44,9 @@ SpectrumCanvas::SpectrumCanvas(wxWindow *parent, int *attribList) :
glContext = new SpectrumContext(this, &wxGetApp().GetContext(this));
timer.start();
mTracker.setTarget(this);
mTracker.setVertDragLock(true);
SetCursor(wxCURSOR_SIZEWE);
}
@ -172,57 +175,39 @@ void SpectrumCanvas::OnIdle(wxIdleEvent &event) {
// }
}
void SpectrumCanvas::mouseMoved(wxMouseEvent& event) {
if (isMouseDown) {
const wxSize ClientSize = GetClientSize();
float mouseX = (float)event.m_x/(float)ClientSize.x;
float mouseY = (float)event.m_y/(float)ClientSize.y;
deltaMouseX = mouseX-lastMouseX;
deltaMouseY = mouseY-lastMouseY;
lastMouseX = mouseX;
// lastMouseY = mouseY;
int freqChange = deltaMouseX*SRATE;
mTracker.OnMouseMoved(event);
if (mTracker.mouseDown()) {
int freqChange = mTracker.getDeltaMouseX() * SRATE;
if (freqChange != 0) {
int freq = wxGetApp().getFrequency();
freq -= freqChange;
wxGetApp().setFrequency(freq);
((wxFrame*)parent)->GetStatusBar()->SetStatusText(wxString::Format(wxT("Set center frequency: %s"),wxNumberFormatter::ToString((long)freq,wxNumberFormatter::Style_WithThousandsSep)));
if (mouseY != lastMouseY) {
WarpPointer(event.m_x,lastMouseY*ClientSize.y);
((wxFrame*) parent)->GetStatusBar()->SetStatusText(
wxString::Format(wxT("Set center frequency: %s"),
wxNumberFormatter::ToString((long) freq, wxNumberFormatter::Style_WithThousandsSep)));
}
}
}
void SpectrumCanvas::mouseDown(wxMouseEvent& event) {
const wxSize ClientSize = GetClientSize();
lastMouseX = (float)event.m_x/(float)ClientSize.x;
lastMouseY = (float)event.m_y/(float)ClientSize.y;
isMouseDown = true;
mTracker.OnMouseDown(event);
SetCursor(wxCURSOR_CROSS);
}
void SpectrumCanvas::mouseWheelMoved(wxMouseEvent& event) {
std::cout << "wheel?" << std::endl;
mTracker.OnMouseWheelMoved(event);
}
void SpectrumCanvas::mouseReleased(wxMouseEvent& event) {
isMouseDown = false;
mTracker.OnMouseReleased(event);
SetCursor(wxCURSOR_SIZEWE);
}
void SpectrumCanvas::mouseLeftWindow(wxMouseEvent& event) {
isMouseDown = false;
mTracker.OnMouseLeftWindow(event);
SetCursor(wxCURSOR_SIZEWE);
}

View File

@ -10,6 +10,7 @@
#include "fftw3.h"
#include "Timer.h"
#include "MouseTracker.h"
class SpectrumCanvas: public wxGLCanvas {
public:
@ -48,9 +49,7 @@ private:
Timer timer;
float frameTimer;
float lastMouseX, lastMouseY;
float deltaMouseX, deltaMouseY;
bool isMouseDown;
MouseTracker mTracker;
// event table
wxDECLARE_EVENT_TABLE();
};

View File

@ -15,9 +15,16 @@
#include "AppFrame.h"
#include <algorithm>
#include <wx/numformatter.h>
wxBEGIN_EVENT_TABLE(WaterfallCanvas, wxGLCanvas) EVT_PAINT(WaterfallCanvas::OnPaint)
EVT_KEY_DOWN(WaterfallCanvas::OnKeyDown)
EVT_IDLE(WaterfallCanvas::OnIdle)
EVT_MOTION(WaterfallCanvas::mouseMoved)
EVT_LEFT_DOWN(WaterfallCanvas::mouseDown)
EVT_LEFT_UP(WaterfallCanvas::mouseReleased)
EVT_LEAVE_WINDOW(WaterfallCanvas::mouseLeftWindow)
EVT_ENTER_WINDOW(WaterfallCanvas::mouseEnterWindow)
wxEND_EVENT_TABLE()
WaterfallCanvas::WaterfallCanvas(wxWindow *parent, int *attribList) :
@ -37,6 +44,8 @@ WaterfallCanvas::WaterfallCanvas(wxWindow *parent, int *attribList) :
glContext = new WaterfallContext(this, &wxGetApp().GetContext(this));
timer.start();
mTracker.setTarget(this);
SetCursor(wxCURSOR_CROSS);
}
@ -51,8 +60,14 @@ void WaterfallCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
glContext->SetCurrent(*this);
glViewport(0, 0, ClientSize.x, ClientSize.y);
glContext->BeginDraw();
glContext->Draw(spectrum_points);
if (mTracker.mouseInView()) {
glContext->DrawFreqSelector(mTracker.getMouseX());
}
glContext->EndDraw();
SwapBuffers();
}
@ -162,3 +177,60 @@ void WaterfallCanvas::OnIdle(wxIdleEvent &event) {
// frameTimer = 0;
// }
}
void WaterfallCanvas::mouseMoved(wxMouseEvent& event) {
mTracker.OnMouseMoved(event);
if (mTracker.mouseDown()) {
int freqChange = mTracker.getDeltaMouseX() * SRATE;
if (freqChange != 0) {
int freq = wxGetApp().getFrequency();
freq -= freqChange;
wxGetApp().setFrequency(freq);
((wxFrame*) parent)->GetStatusBar()->SetStatusText(
wxString::Format(wxT("Set center frequency: %s"),
wxNumberFormatter::ToString((long) freq, wxNumberFormatter::Style_WithThousandsSep)));
}
}
}
void WaterfallCanvas::mouseDown(wxMouseEvent& event) {
mTracker.OnMouseDown(event);
SetCursor(wxCURSOR_CROSS);
}
void WaterfallCanvas::mouseWheelMoved(wxMouseEvent& event) {
mTracker.OnMouseWheelMoved(event);
}
void WaterfallCanvas::mouseReleased(wxMouseEvent& event) {
mTracker.OnMouseReleased(event);
if (mTracker.getOriginDeltaMouseX() == 0 && mTracker.getOriginDeltaMouseX() == 0) {
float pos = mTracker.getMouseX();
int freq = wxGetApp().getFrequency();
freq += (pos - 0.5) * SRATE;
wxGetApp().setFrequency(freq);
((wxFrame*) parent)->GetStatusBar()->SetStatusText(
wxString::Format(wxT("Set center frequency: %s"),
wxNumberFormatter::ToString((long) freq, wxNumberFormatter::Style_WithThousandsSep)));
}
SetCursor(wxCURSOR_SIZEWE);
}
void WaterfallCanvas::mouseLeftWindow(wxMouseEvent& event) {
mTracker.OnMouseLeftWindow(event);
SetCursor(wxCURSOR_SIZEWE);
}
void WaterfallCanvas::mouseEnterWindow(wxMouseEvent& event) {
mTracker.OnMouseEnterWindow(event);
SetCursor(wxCURSOR_SIZEWE);
}

View File

@ -7,6 +7,7 @@
#include <queue>
#include "WaterfallContext.h"
#include "MouseTracker.h"
#include "fftw3.h"
#include "Timer.h"
@ -23,6 +24,13 @@ private:
void OnIdle(wxIdleEvent &event);
void mouseMoved(wxMouseEvent& event);
void mouseDown(wxMouseEvent& event);
void mouseWheelMoved(wxMouseEvent& event);
void mouseReleased(wxMouseEvent& event);
void mouseEnterWindow(wxMouseEvent& event);
void mouseLeftWindow(wxMouseEvent& event);
wxWindow *parent;
std::vector<float> spectrum_points;
@ -39,6 +47,8 @@ private:
WaterfallContext *glContext;
Timer timer;
float frameTimer;
MouseTracker mTracker;
// event table
wxDECLARE_EVENT_TABLE();
};

View File

@ -1,5 +1,6 @@
#include "WaterfallContext.h"
#include "WaterfallCanvas.h"
#include "CubicSDR.h"
WaterfallContext::WaterfallContext(WaterfallCanvas *canvas, wxGLContext *sharedContext) :
PrimaryGLContext(canvas, sharedContext) {
@ -36,11 +37,14 @@ WaterfallContext::WaterfallContext(WaterfallCanvas *canvas, wxGLContext *sharedC
glPixelMapfv(GL_PIXEL_MAP_I_TO_B, 256, &(grad.getBlue())[0]);
}
void WaterfallContext::Draw(std::vector<float> &points) {
void WaterfallContext::BeginDraw() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void WaterfallContext::Draw(std::vector<float> &points) {
if (points.size()) {
memmove(waterfall_tex + FFT_SIZE, waterfall_tex, (NUM_WATERFALL_LINES - 1) * FFT_SIZE);
@ -57,15 +61,13 @@ void WaterfallContext::Draw(std::vector<float> &points) {
}
}
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, waterfall);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, FFT_SIZE, NUM_WATERFALL_LINES, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, (GLvoid *) waterfall_tex);
glDisable(GL_TEXTURE_2D);
glColor3f(1.0, 1.0, 1.0);
glEnable(GL_TEXTURE_2D);
// glEnable(GL_COLOR_TABLE);
glBindTexture(GL_TEXTURE_2D, waterfall);
glBegin(GL_QUADS);
glTexCoord2f(0.0, 1.0);
@ -78,6 +80,37 @@ void WaterfallContext::Draw(std::vector<float> &points) {
glVertex3f(-1.0, 1.0, 0.0);
glEnd();
}
void WaterfallContext::DrawFreqSelector(float uxPos) {
DemodulatorInstance *demod = wxGetApp().getDemodTest();
if (!demod) {
return;
}
glClear(GL_DEPTH_BUFFER_BIT);
glDisable(GL_TEXTURE_2D);
glColor3f(1.0, 1.0, 1.0);
glBegin(GL_LINES);
glVertex3f((uxPos - 0.5) * 2.0, 1.0, 0.0);
glVertex3f((uxPos - 0.5) * 2.0, -1.0, 0.0);
float ofs = ((float) demod->params.inputResampleRate) / (float) SRATE;
glVertex3f((uxPos - 0.5) * 2.0 - ofs, 1.0, 0.0);
glVertex3f((uxPos - 0.5) * 2.0 - ofs, -1.0, 0.0);
glVertex3f((uxPos - 0.5) * 2.0 + ofs, 1.0, 0.0);
glVertex3f((uxPos - 0.5) * 2.0 + ofs, -1.0, 0.0);
glEnd();
}
void WaterfallContext::EndDraw() {
glFlush();
CheckGLError();

View File

@ -11,7 +11,10 @@ class WaterfallContext: public PrimaryGLContext {
public:
WaterfallContext(WaterfallCanvas *canvas, wxGLContext *sharedContext);
void BeginDraw();
void Draw(std::vector<float> &points);
void DrawFreqSelector(float uxPos);
void EndDraw();
private:
Gradient grad;