Skip to content
Snippets Groups Projects
SpikeDisplayCanvas.cpp 10.89 KiB
/*
    ------------------------------------------------------------------

    This file is part of the Open Ephys GUI
    Copyright (C) 2013 Open Ephys

    ------------------------------------------------------------------

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

*/

#include "SpikeDisplayCanvas.h"

SpikeDisplayCanvas::SpikeDisplayCanvas(SpikeDisplayNode* n) :
	 	newSpike(false), processor(n)
{
    
	update();
	
	spikeBuffer = processor->getSpikeBufferAddress();

	viewport = new Viewport();
	spikeDisplay = new SpikeDisplay(this, viewport);

	viewport->setViewedComponent(spikeDisplay, false);
	viewport->setScrollBarsShown(true, false);

	scrollBarThickness = viewport->getScrollBarThickness();

	addAndMakeVisible(viewport);
	
}

SpikeDisplayCanvas::~SpikeDisplayCanvas()
{
	
}

// void SpikeDisplayCanvas::initializeSpikePlots(){

// 	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;
// //         }
        
// // //        bool use_generic_plots_flag = true;
        
// // //        BaseUIElement *sp;
        
// //   //      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();
// // 	}
// }

// void SpikeDisplayCanvas::repositionSpikePlots(){
	
// // 	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;
        
    
    
// //     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;
        
// //         // 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);
// }

// void SpikeDisplayCanvas::newOpenGLContextCreated()
// {
// 	std::cout<<"SpikeDisplayCanvas::newOpenGLContextCreated()"<<std::endl;
// 	setUp2DCanvas();
// 	activateAntiAliasing();
// 	disablePointSmoothing();

// 	glClearColor (0.667, 0.698, 0.718, 1.0);
// 	resized();
// 	//endAnimation();
// }

void SpikeDisplayCanvas::beginAnimation()
{
	std::cout << "Beginning animation." << std::endl;
	
	startCallbacks();
}

void SpikeDisplayCanvas::endAnimation()
{
	std::cout << "Ending animation." << std::endl;
	
	stopCallbacks();
}

void SpikeDisplayCanvas::update()
{

	std::cout << "UPDATING SpikeDisplayCanvas" << std::endl;

	//nPlots = processor->getNumElectrodes();
	// numChannelsPerPlot.clear();

	// for (int i = 0; i < nPlots; i++)
	// {
	// 	numChannelsPerPlot.add(processor->getNumberOfChannelsForElectrode(i));
	// }

	//initializeSpikePlots();

	repaint();
}


void SpikeDisplayCanvas::refreshState()
{
	// called when the component's tab becomes visible again
	// displayBufferIndex = processor->getDisplayBufferIndex();
	// screenBufferIndex = 0;
	resized();
}

void SpikeDisplayCanvas::resized()
{
	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);

	g.setColour(Colours::white);

	g.drawLine(0,0, getWidth(), getHeight());
	g.drawLine(0,getHeight(),getWidth(), 0);
 	
}

void SpikeDisplayCanvas::processSpikeEvents()
{

	if (spikeBuffer->getNumEvents() > 0) 
	{
	
		MidiBuffer::Iterator i (*spikeBuffer);
	 	MidiMessage message(0xf4);

	 	int samplePosition = 0;

	 	i.setNextSamplePosition(samplePosition);
			
	 	while (i.getNextEvent (message, samplePosition)) {
	 		 const uint8_t* dataptr = message.getRawData();
	 		 int bufferSize = message.getRawDataSize();
	 		 int nSamples = (bufferSize-4)/2;

	 		SpikeObject newSpike;
	 		SpikeObject simSpike;

	 		unpackSpike(&newSpike, dataptr, bufferSize);

	 		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;
	 		}

	 		simSpike.nSamples = 40;

			spikeDisplay->plotSpike(simSpike);

		}

	}

	spikeBuffer->clear();

}


// ----------------------------------------------------------------

SpikeDisplay::SpikeDisplay(SpikeDisplayCanvas* sdc, Viewport* v) :
	canvas(sdc), viewport(v)
{

	minWidth = 300; 
	maxWidth = 500;
	minHeight = 100;
	maxHeight = 200;

	totalHeight = 1000;

	for (int i = 0; i < 10; i++)
	{
		SpikePlot* spikePlot = new SpikePlot(canvas, i, 2);
		spikePlots.add(spikePlot);
		addAndMakeVisible(spikePlot);
	}

}

SpikeDisplay::~SpikeDisplay()
{

}

void SpikeDisplay::addSpikePlot(int numChannels)
{

}

void SpikeDisplay::paint(Graphics& g)
{

	g.fillAll(Colours::blue);
}

void SpikeDisplay::resized()
{

	int w = getWidth();

	int numColumns = w / minWidth;
	int column, row;

	float width = (float) w / (float) numColumns;
	float height = width * 0.75;

	for (int i = 0; i < spikePlots.size(); i++)
	{

		column = i % numColumns;
		row = i / numColumns;
		spikePlots[i]->setBounds(width*column,row*height,width,height);

	}

	totalHeight = (int) (height*(float(row)+1));

	if (totalHeight < getHeight())
	{
		canvas->resized();
	}

	//setBounds(0,0,getWidth(), totalHeight);


	 // layoutManagerX.layOutComponents((Component**) spikePlots.getRawDataPointer(), 
	 // 							   spikePlots.size(),
	 // 							   0,
	 // 							   0,
	 // 							   getWidth(),
	 // 							   getHeight(),
	 // 							   false,
	 // 							   false);
}

void SpikeDisplay::mouseDown(const MouseEvent& event)
{

}

void SpikeDisplay::plotSpike(const SpikeObject& spike)
{

}


// ----------------------------------------------------------------

SpikePlot::SpikePlot(SpikeDisplayCanvas* sdc, int elecNum, int numChans) :
	canvas(sdc), electrodeNumber(elecNum), numChannels(numChans)

{
	isSelected = false;

}

SpikePlot::~SpikePlot()
{

}

void SpikePlot::paint(Graphics& g)
{

	g.setColour(Colours::yellow);
	g.fillRect(10, 10, getWidth()-20, getHeight()-20);

	g.setColour(Colours::black);

	g.drawLine(0, 0, getWidth(), getHeight());
	g.drawLine(0, getHeight(), getWidth(), 0);

}

void SpikePlot::select()
{
	isSelected = true;
}

void SpikePlot::deselect()
{
	isSelected = false;
}

void SpikePlot::resized()
{

}