From 563a2b0277d4f874b176e9f33a9fa7b27c3be021 Mon Sep 17 00:00:00 2001
From: jsiegle <jsiegle@mit.edu>
Date: Wed, 3 Apr 2013 16:24:44 -0400
Subject: [PATCH] Outline OpenGL-free code for SpikeDisplayCanvas

---
 .../Visualization/SpikeDisplayCanvas.cpp      | 513 +++++++-----------
 .../Visualization/SpikeDisplayCanvas.h        |  96 ++--
 .../Processors/Visualization/SpikeObject.cpp  |   2 +-
 Source/Processors/Visualization/SpikeObject.h |   2 +-
 4 files changed, 275 insertions(+), 338 deletions(-)

diff --git a/Source/Processors/Visualization/SpikeDisplayCanvas.cpp b/Source/Processors/Visualization/SpikeDisplayCanvas.cpp
index 032b6ab9b..e5567d696 100755
--- a/Source/Processors/Visualization/SpikeDisplayCanvas.cpp
+++ b/Source/Processors/Visualization/SpikeDisplayCanvas.cpp
@@ -24,23 +24,22 @@
 #include "SpikeDisplayCanvas.h"
 
 SpikeDisplayCanvas::SpikeDisplayCanvas(SpikeDisplayNode* n) :
-        xBuffer(18), yBuffer(18),
-	 	plotsInitialized(false), newSpike(false),
-        processor(n), totalScrollPix(0)
+	 	newSpike(false), processor(n)
 {
-    nCols = 6;
     
 	update();
 	
 	spikeBuffer = processor->getSpikeBufferAddress();
-	// std::cout<<"SpikeDisplayNode has :"<<nPlots<<" outputs!"<<std::endl;
-	
-	// // for (int i=0; i<nPlots; i++)
-	// // 	nChannels[i] = processor->getNumberOfChannelsForElectrode(i);
 
-	// std::cout << "Setting num inputs on SpikeDisplayCanvas to " << nPlots << std::endl;
-	
-	//refreshMs = 100; // override 5 s refresh rate
+	viewport = new Viewport();
+	spikeDisplay = new SpikeDisplay(this, viewport);
+
+	viewport->setViewedComponent(spikeDisplay, false);
+	viewport->setScrollBarsShown(true, false);
+
+	scrollBarThickness = viewport->getScrollBarThickness();
+
+	addAndMakeVisible(viewport);
 	
 }
 
@@ -49,147 +48,147 @@ SpikeDisplayCanvas::~SpikeDisplayCanvas()
 	
 }
 
-void SpikeDisplayCanvas::initializeSpikePlots(){
+// void SpikeDisplayCanvas::initializeSpikePlots(){
 
-	std::cout<<"Initializing Plots"<<std::endl;
+// 	std::cout<<"Initializing Plots"<<std::endl;
     
-    // This layout system really only works if plot types are aggregated together.
-    // It might be worthwhile to investigate the merits of using a grid system
-    // The canvas is defined as N grid widths wide. Each SpikePlot defines its
-    // dimensions in grid widths.
-    //
-    // Plots are added from left to right, top to bottom.  A plot is put into place
-    // if it can fit into the next grid location w/o its top going above the current
-    // row and w/o its bottom going below the current row
-    //
-    // This would lead to dead space but it would allow the plots to all scale accoring
-    // to how much space they need.  The current system of deciding plot sizes, isn't going
-    // to scale well.... this needs more thought
-
-// 	if (plots.size() != nPlots)
-// 	{
-
-// 	int totalWidth = getWidth(); 
-
-// 	int plotWidth =  (totalWidth - yBuffer * ( nCols+1)) / nCols + .99;
-// 	int plotHeight = plotWidth / 2 + .5;
-// 	int rowCount = 0;
-
-// 	plots.clear();
-
-// 	for (int i = 0; i < nPlots; i++)
-// 	{
-//         int pType;
-// 		switch (processor->getNumberOfChannelsForElectrode(i)){
-// 			case 1:
-//                 pType = SINGLE_PLOT;
-//                 break;
-// 			case 2:
-//                 pType = STEREO_PLOT;
-//                 break;
-// 			case 4:
-//                 pType = TETRODE_PLOT;
-//                 break;
-//             default:
-//                 pType = SINGLE_PLOT;
-//                 break;
-//         }
+//     // This layout system really only works if plot types are aggregated together.
+//     // It might be worthwhile to investigate the merits of using a grid system
+//     // The canvas is defined as N grid widths wide. Each SpikePlot defines its
+//     // dimensions in grid widths.
+//     //
+//     // Plots are added from left to right, top to bottom.  A plot is put into place
+//     // if it can fit into the next grid location w/o its top going above the current
+//     // row and w/o its bottom going below the current row
+//     //
+//     // This would lead to dead space but it would allow the plots to all scale accoring
+//     // to how much space they need.  The current system of deciding plot sizes, isn't going
+//     // to scale well.... this needs more thought
+
+// // 	if (plots.size() != nPlots)
+// // 	{
+
+// // 	int totalWidth = getWidth(); 
+
+// // 	int plotWidth =  (totalWidth - yBuffer * ( nCols+1)) / nCols + .99;
+// // 	int plotHeight = plotWidth / 2 + .5;
+// // 	int rowCount = 0;
+
+// // 	plots.clear();
+
+// // 	for (int i = 0; i < nPlots; i++)
+// // 	{
+// //         int pType;
+// // 		switch (processor->getNumberOfChannelsForElectrode(i)){
+// // 			case 1:
+// //                 pType = SINGLE_PLOT;
+// //                 break;
+// // 			case 2:
+// //                 pType = STEREO_PLOT;
+// //                 break;
+// // 			case 4:
+// //                 pType = TETRODE_PLOT;
+// //                 break;
+// //             default:
+// //                 pType = SINGLE_PLOT;
+// //                 break;
+// //         }
         
-// //        bool use_generic_plots_flag = true;
+// // //        bool use_generic_plots_flag = true;
         
-// //        BaseUIElement *sp;
+// // //        BaseUIElement *sp;
         
-//   //      if (use_generic_plots_flag)
-//         SpikePlot *sp = new SpikePlot(xBuffer + i%nCols * (plotWidth + xBuffer) ,
-//                                yBuffer + rowCount * (plotHeight + yBuffer),
-//                                plotWidth, plotHeight, pType);
+// //   //      if (use_generic_plots_flag)
+// //         SpikePlot *sp = new SpikePlot(xBuffer + i%nCols * (plotWidth + xBuffer) ,
+// //                                yBuffer + rowCount * (plotHeight + yBuffer),
+// //                                plotWidth, plotHeight, pType);
         
-// //        else
-// //            sp = new StereotrodePlot(xBuffer + i%nCols * (plotWidth + xBuffer) ,
-// //                                      yBuffer + rowCount * (plotHeight + yBuffer),
-// //                                      plotWidth, plotHeight);
-//         plots.add(sp);
-
-// 		if (i%nCols == nCols-1)
-// 			rowCount++;
-// 	}
-// 	//totalHeight = rowCount * (plotHeight + yBuffer) + yBuffer * 2;
-// 	// Set the total height of the Canvas to the top of the top most plot
-
-//     plotsInitialized = true;
-// 	repositionSpikePlots();
-// 	}
-}
+// // //        else
+// // //            sp = new StereotrodePlot(xBuffer + i%nCols * (plotWidth + xBuffer) ,
+// // //                                      yBuffer + rowCount * (plotHeight + yBuffer),
+// // //                                      plotWidth, plotHeight);
+// //         plots.add(sp);
+
+// // 		if (i%nCols == nCols-1)
+// // 			rowCount++;
+// // 	}
+// // 	//totalHeight = rowCount * (plotHeight + yBuffer) + yBuffer * 2;
+// // 	// Set the total height of the Canvas to the top of the top most plot
+
+// //     plotsInitialized = true;
+// // 	repositionSpikePlots();
+// // 	}
+// }
 
-void SpikeDisplayCanvas::repositionSpikePlots(){
+// void SpikeDisplayCanvas::repositionSpikePlots(){
 	
-// 	int canvasWidth = getWidth();
-// 	int gridSize = canvasWidth / nCols;
+// // 	int canvasWidth = getWidth();
+// // 	int gridSize = canvasWidth / nCols;
     
-//     gridSize = (gridSize > MIN_GRID_SIZE) ? gridSize : MIN_GRID_SIZE;
-//     gridSize = (gridSize < MAX_GRID_SIZE) ? gridSize : MAX_GRID_SIZE;
+// //     gridSize = (gridSize > MIN_GRID_SIZE) ? gridSize : MIN_GRID_SIZE;
+// //     gridSize = (gridSize < MAX_GRID_SIZE) ? gridSize : MAX_GRID_SIZE;
         
     
     
-//     int x = xBuffer;
-//     int y = getHeight() - yBuffer;
-//     int p = 0;
-//     int w,h;
-//     int yIncrement = 0;
-//     bool loopCheck = false;
-//     //std::cout<<"Positioning Spike Plots"<<std::endl;
-//     while (p < plots.size()){
+// //     int x = xBuffer;
+// //     int y = getHeight() - yBuffer;
+// //     int p = 0;
+// //     int w,h;
+// //     int yIncrement = 0;
+// //     bool loopCheck = false;
+// //     //std::cout<<"Positioning Spike Plots"<<std::endl;
+// //     while (p < plots.size()){
         
-//         // Ask the current plot for its desired dims
-//         plots[p]->getBestDimensions(&w, &h);
-//         w *= gridSize;
-//         h *= gridSize;
+// //         // Ask the current plot for its desired dims
+// //         plots[p]->getBestDimensions(&w, &h);
+// //         w *= gridSize;
+// //         h *= gridSize;
         
-//         // Check to see if plot exceeds width of canvas, if yes, set x back to 0 and go to the bottom most plot on the canvas
-//         if ( (x + w + xBuffer > canvasWidth - xBuffer) && !loopCheck){
-//             //std::cout<<"Collision with the edge of the canvas, going down a row"<<std::endl;
-//             x = xBuffer;
-//             y = y - yIncrement - yBuffer;
-//             yIncrement = 0;
-//             loopCheck = true;
-//             continue;
-//         }
-//         // else place the plot
-//         else{
-//             //std::cout<<"Positioning p:"<<p<<" at "<<x<<","<<y - h<<"  "<<w<<","<<h<<std::endl;
-//            // plots[p]->setPosition(x, y - h + getScrollAmount(), w, h);
-//             x = x + w + xBuffer;
-
-//             // set a new minimum
-//             if (h > yIncrement)
-//                 yIncrement = h;
+// //         // Check to see if plot exceeds width of canvas, if yes, set x back to 0 and go to the bottom most plot on the canvas
+// //         if ( (x + w + xBuffer > canvasWidth - xBuffer) && !loopCheck){
+// //             //std::cout<<"Collision with the edge of the canvas, going down a row"<<std::endl;
+// //             x = xBuffer;
+// //             y = y - yIncrement - yBuffer;
+// //             yIncrement = 0;
+// //             loopCheck = true;
+// //             continue;
+// //         }
+// //         // else place the plot
+// //         else{
+// //             //std::cout<<"Positioning p:"<<p<<" at "<<x<<","<<y - h<<"  "<<w<<","<<h<<std::endl;
+// //            // plots[p]->setPosition(x, y - h + getScrollAmount(), w, h);
+// //             x = x + w + xBuffer;
+
+// //             // set a new minimum
+// //             if (h > yIncrement)
+// //                 yIncrement = h;
             
-//             // increment p
-//             p++;
-//             loopCheck = false;
-//         }
-//     }
-
-// //  int plotWidth =  (totalWidth - yBuffer * ( nCols+1)) / nCols + .99;
-// //	int plotHeight = plotWidth / 2 + .5;
-// //	int rowCount = 0;
-
-// //	for (int i=0; i < plots.size(); i++)
-// //	{
-// //
-// //		plots[i]->setPosition(	xBuffer + i%nCols * (plotWidth + xBuffer) , 
-// //								getHeight() - ( yBuffer + plotHeight + rowCount * (plotHeight + yBuffer)) + getScrollAmount(), 
-// //								plotWidth, 
-// //								plotHeight); // deprecated conversion from string constant to char
-// //
-// //		if (i%nCols == nCols-1)
-// //			rowCount++;	
-// //	 }
-
-// 	// Set the total height of the Canvas to the top of the top most plot
-// //	totalHeight = (rowCount + 1) * (plotHeight + yBuffer) + yBuffer;
-//     totalHeight = getHeight() + (y + yIncrement);
-}
+// //             // increment p
+// //             p++;
+// //             loopCheck = false;
+// //         }
+// //     }
+
+// // //  int plotWidth =  (totalWidth - yBuffer * ( nCols+1)) / nCols + .99;
+// // //	int plotHeight = plotWidth / 2 + .5;
+// // //	int rowCount = 0;
+
+// // //	for (int i=0; i < plots.size(); i++)
+// // //	{
+// // //
+// // //		plots[i]->setPosition(	xBuffer + i%nCols * (plotWidth + xBuffer) , 
+// // //								getHeight() - ( yBuffer + plotHeight + rowCount * (plotHeight + yBuffer)) + getScrollAmount(), 
+// // //								plotWidth, 
+// // //								plotHeight); // deprecated conversion from string constant to char
+// // //
+// // //		if (i%nCols == nCols-1)
+// // //			rowCount++;	
+// // //	 }
+
+// // 	// Set the total height of the Canvas to the top of the top most plot
+// // //	totalHeight = (rowCount + 1) * (plotHeight + yBuffer) + yBuffer;
+// //     totalHeight = getHeight() + (y + yIncrement);
+// }
 
 // void SpikeDisplayCanvas::newOpenGLContextCreated()
 // {
@@ -222,7 +221,7 @@ void SpikeDisplayCanvas::update()
 
 	std::cout << "UPDATING SpikeDisplayCanvas" << std::endl;
 
-	nPlots = processor->getNumElectrodes();
+	//nPlots = processor->getNumElectrodes();
 	// numChannelsPerPlot.clear();
 
 	// for (int i = 0; i < nPlots; i++)
@@ -230,46 +229,12 @@ void SpikeDisplayCanvas::update()
 	// 	numChannelsPerPlot.add(processor->getNumberOfChannelsForElectrode(i));
 	// }
 
-	initializeSpikePlots();
+	//initializeSpikePlots();
 
 	repaint();
 }
 
 
-// Used for Plot specific commands, this commands target a specific PLOT and have
-// no additional information, IE PARAM-> CLEAR  val->plot6  
-// for more complex messages use the other version of setParameter
-void SpikeDisplayCanvas::setParameter(int param, float val)
-{
-	// std::cout<<"Got Param:"<< param<< " with value:"<<val<<std::endl;
-	// switch (param)
-	// {
-	// 	case SPIKE_CMD_CLEAR_ALL :
-	// 		for (int i=0; i < plots.size(); i++)
-	// 			plots[i]->clear();
-	// 		break;
-	
-	// 	case SPIKE_CMD_CLEAR_SEL:
-	// 	//clear plot number val
-	// 		break;
-	// 	default:
-	// 		std::cout<<"Unknown command specified! "<<param<<std::endl;
-	// }
-}
-
-void SpikeDisplayCanvas::setParameter(int param, int p2, int p3, float value){
-	// std::cout<<"Got Parameter:"<<param<<" p2:"<<p2<<" p3:"<<p3<<" value:"<<value<<std::endl;
-	// switch (param){
-	// 	case SPIKE_CMD_PAN_AXES:
-	// 		panPlot(p2, p3, value<=0);
-	// 		break;
-	// 	case SPIKE_CMD_ZOOM_AXES:
-	// 		zoomPlot(p2, p3, value<=0);
-	// 		break;
-	// }
-}
-
-
 void SpikeDisplayCanvas::refreshState()
 {
 	// called when the component's tab becomes visible again
@@ -280,13 +245,16 @@ void SpikeDisplayCanvas::refreshState()
 	//totalScrollPix = 0;
 }
 
-void SpikeDisplayCanvas::canvasWasResized()
+void SpikeDisplayCanvas::resized()
 {
-	repositionSpikePlots();
+	viewport->setBounds(0,0,getWidth(),getHeight()-90);
+
+	spikeDisplay->setBounds(0,0,getWidth()-scrollBarThickness, spikeDisplay->getTotalHeight());
 }
 
 void SpikeDisplayCanvas::paint(Graphics& g)
 {
+	processSpikeEvents();
 
 	g.fillAll(Colours::cyan);
 
@@ -294,190 +262,127 @@ void SpikeDisplayCanvas::paint(Graphics& g)
 
 	g.drawLine(0,0, getWidth(), getHeight());
 	g.drawLine(0,getHeight(),getWidth(), 0);
-
-	// //if(!plotsInitialized)
-	// //	initializeSpikePlots();
-
-	// glClearColor (0.667, 0.698, 0.718, 1.0);
-	// glClear(GL_COLOR_BUFFER_BIT); // clear buffers to preset values
-
-	// // Get Spikes from the processor
-	// // Iterate through each spike, passing them individually to the appropriate plots and calling redraw before moving on to the next spike
-	//  processSpikeEvents();
-
-	//  for (int i = 0; i < plots.size(); i++)
-	//  {
-	//  	plots[i]->redraw();
-	//  	drawPlotTitle(i);
-	//  }
-
-	// drawScrollBars();
  	
 }
 
 void SpikeDisplayCanvas::processSpikeEvents()
 {
 
+	if (spikeBuffer->getNumEvents() > 0) 
+	{
+	
+		MidiBuffer::Iterator i (*spikeBuffer);
+	 	MidiMessage message(0xf4);
 
-	// if (spikeBuffer->getNumEvents() > 0) 
-	// {
-		
-	// 	//int m = spikeBuffer->getNumEvents();
+	 	int samplePosition = 0;
 
-	// 	//std::cout << "Received " << m << " events." << std::endl;
+	 	i.setNextSamplePosition(samplePosition);
 			
-	// 	//std::cout << m << " events received by node " << getNodeId() << std::endl;
-	// 	MidiBuffer::Iterator i (*spikeBuffer);
-	// 	MidiMessage message(0xf4);
-
-	// 	int samplePosition = 0;
-
-	// 	i.setNextSamplePosition(samplePosition);
-		
-	// 	//int eventCount = 0;
-		
-	// 	while (i.getNextEvent (message, samplePosition)) {
-	// 		//eventCount++;
-	// 		 const uint8* dataptr = message.getRawData();
-	// 		 int bufferSize = message.getRawDataSize();
-	// 		// int nSamples = (bufferSize-4)/2;
-
-	// 		SpikeObject newSpike;
-	// 		SpikeObject simSpike;
+	 	while (i.getNextEvent (message, samplePosition)) {
 
-	// 		//unpackSpike(&newSpike, dataptr, bufferSize);
+	 		 const uint8_t* dataptr = message.getRawData();
+	 		 int bufferSize = message.getRawDataSize();
+	 		 int nSamples = (bufferSize-4)/2;
 
-	// 		//
+	 		SpikeObject newSpike;
+	 		SpikeObject simSpike;
 
-	// 		int chan = newSpike.source;
+	 		unpackSpike(&newSpike, dataptr, bufferSize);
 
-	// 		generateSimulatedSpike(&simSpike, 0, 0);
+	 		int chan = newSpike.source;
 
+	 		generateSimulatedSpike(&simSpike, 0, 0);
 
-	// 		for (int i = 0; i < newSpike.nChannels * newSpike.nSamples; i++)
-	// 		{
- //                    simSpike.data[i] = newSpike.data[i%80] + 5000;// * 3 - 10000;
-	// 		}
+	 		for (int i = 0; i < newSpike.nChannels * newSpike.nSamples; i++)
+	 		{
+                     simSpike.data[i] = newSpike.data[i%80] + 5000;// * 3 - 10000;
+	 		}
 
-	// 		simSpike.nSamples = 40;
+	 		simSpike.nSamples = 40;
 
-			
+			//spikeDisplay->plotSpike(simSpike);
 
-	// 		// std::cout << "Received spike on electrode " << chan << std::endl;
+		}
 
-	// 		// std::cout << "Spike has " << newSpike.nChannels << " channels and " <<
-	// 		//              newSpike.nSamples << " samples." << std::endl;
+	}
 
-	// 		// std::cout << "Data: ";
+	spikeBuffer->clear();
 
-	// 		// for (int n = 0; n < newSpike.nSamples; n++)
-	// 		// {
-	// 		// 	std::cout << newSpike.data[n] << " ";
-	// 		// }
+}
 
-	// 		//	std::cout << std::endl;
 
-	// 		plots[chan]->processSpikeObject(simSpike);
+// ----------------------------------------------------------------
 
-	// 	}
+SpikeDisplay::SpikeDisplay(SpikeDisplayCanvas* sdc, Viewport* v) :
+	canvas(sdc), viewport(v)
+{
+	totalHeight = 1000;
 
-	// }
+}
 
-	// spikeBuffer->clear();
+SpikeDisplay::~SpikeDisplay()
+{
 
 }
 
-void SpikeDisplayCanvas::drawPlotTitle(int chan){
+void SpikeDisplay::addSpikePlot(int numChannels)
+{
 
-// 	glViewport(0,0,getWidth(), getHeight());
-// 	setViewportRange(0, 0, getWidth(), getHeight());
+}
 
-// 	int x, y;
-// 	double w,h;
-//  	plots[chan]->getPosition(&x,&y,&w,&h);
+void SpikeDisplay::paint(Graphics& g)
+{
 
-// 	float alpha = 0.50f;
+	g.fillAll(Colours::blue);
+}
 
-// 	glColor4f(0.0f,0.0f,0.0f,alpha);
-// 	glRasterPos2f(x, y+h+2);
-	
-// 	String s = "Source:";//String("Channel ");
-// 	s += (chan+1);
+void SpikeDisplay::resized()
+{
 
-// //	getFont(cpmono_bold)->FaceSize(15);
-// 	//getFont(cpmono_bold)->Render(s);
 }
 
-int SpikeDisplayCanvas::getTotalHeight() 
+void SpikeDisplay::mouseDown(const MouseEvent& event)
 {
-	//std::cout << "TOTAL HEIGHT = " << totalHeight << std::endl;
-	return totalHeight;
+
 }
 
 
-void SpikeDisplayCanvas::mouseDownInCanvas(const MouseEvent& e) 
-{
 
-	/*
-	Point<int> pos = e.getPosition();
-	int xcoord = pos.getX();
 
-	if (xcoord < getWidth()-getScrollBarWidth())
-	{
-		int chan = (e.getMouseDownY() + getScrollAmount())/(yBuffer+plotHeight);
+// ----------------------------------------------------------------
 
-			selectedChan = chan;
+SpikePlot::SpikePlot(SpikeDisplayCanvas* sdc, int elecNum, int numChans) :
+	canvas(sdc), electrodeNumber(elecNum), numChannels(numChans)
 
-		repaint();
-	}*/
+{
+	isSelected = false;
 
 }
 
-// void SpikeDisplayCanvas::mouseDrag(const MouseEvent& e) {mouseDragInCanvas(e);}
-// void SpikeDisplayCanvas::mouseMove(const MouseEvent& e) {mouseMoveInCanvas(e);}
-void SpikeDisplayCanvas::mouseUpInCanvas(const MouseEvent& e) 	{
-	// std::cout<<"Mouse Event!"<<std::endl;
-
-	// bool inout = false;
-
-	// if (e.getMouseDownX() < getWidth()/2)
-	// 	inout = false;
-	// else
-	// 	inout = true;
+SpikePlot::~SpikePlot()
+{
 
-	// if (e.getMouseDownY() < getHeight()/2)
-	// 	zoomPlot(0,0, inout);
-	// else
-	// 	panPlot(0,0,inout);
 }
-void SpikeDisplayCanvas::mouseWheelMoveInCanvas(const MouseEvent& e, float wheelIncrementX, float wheelIncrementY)
-{
 
-	// repositionSpikePlots();
+void SpikePlot::paint(Graphics& g)
+{
 
-	// repaint();
-	//repaint();
+	g.fillAll(Colours::yellow);
+}
 
-	// mouseWheelMoveInCanvas(e, wheelIncrementX, wheelIncrementY);
+void SpikePlot::select()
+{
+	isSelected = true;
 }
 
-// void SpikeDisplayCanvas::panPlot(int p, int c, bool up){
+void SpikePlot::deselect()
+{
+	isSelected = false;
+}
 
-// 	// std::cout << "SpikeDisplayCanvas::panPlot()" << std::endl;
-// 	// if (p < 0 || p > plots.size())
-// 	// 	return;
-// 	// plots[p]->pan(c, up);
+void SpikePlot::resized()
+{
 
-// }
-// void SpikeDisplayCanvas::zoomPlot(int p, int c, bool in){
+}
 
-// 	// std::cout << "SpikeDisplayCanvas::panPlot()" << std::endl;
-// 	// if (p < 0 || p > plots.size())
-// 	// 	return;
-// 	// plots[p]->zoom(c, in);
-// }
 
-void SpikeDisplayCanvas::disablePointSmoothing()
-{
-	// glDisable(GL_POINT_SMOOTH); // needed to make projections visible
-}
diff --git a/Source/Processors/Visualization/SpikeDisplayCanvas.h b/Source/Processors/Visualization/SpikeDisplayCanvas.h
index ccf8597fc..1dba9b42c 100755
--- a/Source/Processors/Visualization/SpikeDisplayCanvas.h
+++ b/Source/Processors/Visualization/SpikeDisplayCanvas.h
@@ -40,6 +40,7 @@
 
 class SpikeDisplayNode;
 
+class SpikeDisplay;
 class SpikePlot;
 
 /**
@@ -66,59 +67,90 @@ public:
 
 	void refreshState();
 
+	void setParameter(int, float) {}
+	void setParameter(int, int, int, float){}
+
 	void update();
 
-	void setParameter(int, float);
-	void setParameter(int, int, int, float);
+	void resized();
 
 private:
 
-
+	SpikeDisplayNode* processor;
 	MidiBuffer* spikeBuffer;
 
-	int xBuffer, yBuffer;
-
-	bool plotsInitialized;
+	ScopedPointer<SpikeDisplay> spikeDisplay;
+	ScopedPointer<Viewport> viewport;
 
 	bool newSpike;
 	SpikeObject spike;
-	SpikeDisplayNode* processor;
 
-	Array<SpikePlot*> plots;
-	Array<int> numChannelsPerPlot;
+	int scrollBarThickness;
 
-	int totalScrollPix;
-
-	void drawPlotTitle(int chan);
+	JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SpikeDisplayCanvas);
 	
-	int totalHeight;
+};
 
-	int getTotalHeight();
+class SpikeDisplay : public Component
+{
+public:
+	SpikeDisplay(SpikeDisplayCanvas*, Viewport*);
+	~SpikeDisplay();
 
-	int nPlots;
+	void addSpikePlot(int numChannels);
 
-    int nCols;
-    static const int MIN_GRID_SIZE = 10;
-    static const int MAX_GRID_SIZE = 125;
-  
-	int nChannels[MAX_NUMBER_OF_SPIKE_CHANNELS];
+	void paint(Graphics& g);
 
-    void computeColumnLayout();
-	void initializeSpikePlots();
-	void repositionSpikePlots();
+	void resized();
 
-	void disablePointSmoothing();
-	void canvasWasResized();
-	void mouseDownInCanvas(const MouseEvent& e);
-	//void mouseDragInCanvas(const MouseEvent& e);
-	//void mouseMoveInCanvas(const MouseEvent& e);
-	void mouseUpInCanvas(const MouseEvent& e);
-	void mouseWheelMoveInCanvas(const MouseEvent&, float, float);
+	void mouseDown(const MouseEvent& event);
+
+	//void plotSpike(const SpikeObject& spike);
+
+
+	int getTotalHeight() {return totalHeight;}
+
+private:
+
+	//void computeColumnLayout();
+	//void initializeSpikePlots();
+	//void repositionSpikePlots();
+
+	int numColumns;
+
+	int totalHeight;
+
+	SpikeDisplayCanvas* canvas;
+	Viewport* viewport;
+
+	Array<SpikePlot*> spikePlots;
 
-	JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SpikeDisplayCanvas);
-	
 };
 
+class SpikePlot : public Component
+{
+public:
+	SpikePlot(SpikeDisplayCanvas*, int elecNum, int numChans);
+	~SpikePlot();
+
+	void paint(Graphics& g);
+
+	void select();
+	void deselect();
+
+	void resized();
+
+private:
+
+	SpikeDisplayCanvas* canvas;
+
+	bool isSelected;
+
+	int electrodeNumber;
+
+	int numChannels;
+
+};
 
 
 #endif  // SPIKEDISPLAYCANVAS_H_
diff --git a/Source/Processors/Visualization/SpikeObject.cpp b/Source/Processors/Visualization/SpikeObject.cpp
index 5346b7601..483de0387 100755
--- a/Source/Processors/Visualization/SpikeObject.cpp
+++ b/Source/Processors/Visualization/SpikeObject.cpp
@@ -73,7 +73,7 @@ int packSpike(SpikeObject *s, uint8_t* buffer, int bufferSize){
 }
 
 // Simple method for deserializing a string of bytes into a Spike object
-bool unpackSpike(SpikeObject *s, uint8_t* buffer, int bufferSize){
+bool unpackSpike(SpikeObject *s, const uint8_t* buffer, int bufferSize){
 	// if !(isBufferValid(buffer, bufferSize));
 	// 	return false;
 
diff --git a/Source/Processors/Visualization/SpikeObject.h b/Source/Processors/Visualization/SpikeObject.h
index f2cf8076b..b7f9e73fa 100755
--- a/Source/Processors/Visualization/SpikeObject.h
+++ b/Source/Processors/Visualization/SpikeObject.h
@@ -70,7 +70,7 @@ struct SpikeObject{
 int packSpike(SpikeObject *s, uint8_t* buffer, int bufferLength);
 
 /** Simple method for deserializing a string of bytes into a Spike object, returns true is the provided spike buffer is valid */
-bool unpackSpike(SpikeObject *s, uint8_t* buffer, int bufferLength);
+bool unpackSpike(SpikeObject *s, const uint8_t* buffer, int bufferLength);
 
 /** Checks the validity of the buffer, this should be run before unpacking the buffer */
 bool isBufferValid(uint8_t *buffer, int bufferLength);
-- 
GitLab