-
Josh Siegle authoredJosh Siegle authored
ControlPanel.cpp 18.25 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 "ControlPanel.h"
#include "UIComponent.h"
#include <stdio.h>
#include <math.h>
PlayButton::PlayButton()
: DrawableButton("PlayButton", DrawableButton::ImageFitted)
{
DrawablePath normal, over, down;
Path p;
p.addTriangle(0.0f, 0.0f, 0.0f, 20.0f, 18.0f, 10.0f);
normal.setPath(p);
normal.setFill(Colours::lightgrey);
normal.setStrokeThickness(0.0f);
over.setPath(p);
over.setFill(Colours::black);
over.setStrokeFill(Colours::black);
over.setStrokeThickness(5.0f);
down.setPath(p);
down.setFill(Colours::pink);
down.setStrokeFill(Colours::pink);
down.setStrokeThickness(5.0f);
setImages(&normal, &over, &over);
// setBackgroundColours(Colours::darkgrey, Colours::yellow);
setClickingTogglesState(true);
setTooltip("Start/stop acquisition");
}
PlayButton::~PlayButton()
{
}
RecordButton::RecordButton()
: DrawableButton("RecordButton", DrawableButton::ImageFitted)
{
DrawablePath normal, over, down;
Path p;
p.addEllipse(0.0,0.0,20.0,20.0);
normal.setPath(p);
normal.setFill(Colours::lightgrey);
normal.setStrokeThickness(0.0f);
over.setPath(p);
over.setFill(Colours::black);
over.setStrokeFill(Colours::black);
over.setStrokeThickness(5.0f);
setImages(&normal, &over, &over);
//setBackgroundColours(Colours::darkgrey, Colours::red);
setClickingTogglesState(true);
setTooltip("Start/stop writing to disk");
}
RecordButton::~RecordButton()
{
}
CPUMeter::CPUMeter() : Label("CPU Meter","0.0"), cpu(0.0f), lastCpu(0.0f)
{
font = Font("Small Text", 12, Font::plain);
// MemoryInputStream mis(BinaryData::silkscreenserialized, BinaryData::silkscreenserializedSize, false);
// Typeface::Ptr typeface = new CustomTypeface(mis);
// font = Font(typeface);
// font.setHeight(12);
}
CPUMeter::~CPUMeter()
{
}
void CPUMeter::updateCPU(float usage)
{
lastCpu = cpu;
cpu = usage;
}
void CPUMeter::paint(Graphics& g)
{
g.fillAll(Colours::grey);
g.setColour(Colours::yellow);
g.fillRect(0.0f,0.0f,getWidth()*cpu,float(getHeight()));
g.setColour(Colours::black);
g.drawRect(0,0,getWidth(),getHeight(),1);
g.setFont(font);
g.drawSingleLineText("CPU",65,12);
}
DiskSpaceMeter::DiskSpaceMeter()
{
font = Font("Small Text", 12, Font::plain);
// MemoryInputStream mis(BinaryData::silkscreenserialized, BinaryData::silkscreenserializedSize, false);
// Typeface::Ptr typeface = new CustomTypeface(mis);
// font = Font(typeface);
// font.setHeight(12);
}
DiskSpaceMeter::~DiskSpaceMeter()
{
}
void DiskSpaceMeter::updateDiskSpace(float percent)
{
diskFree = percent;
}
void DiskSpaceMeter::paint(Graphics& g)
{
g.fillAll(Colours::grey);
g.setColour(Colours::lightgrey);
if (diskFree > 0)
g.fillRect(0.0f,0.0f,getWidth()*diskFree,float(getHeight()));
g.setColour(Colours::black);
g.drawRect(0,0,getWidth(),getHeight(),1);
g.setFont(font);
g.drawSingleLineText("DF",75,12);
}
Clock::Clock() : isRunning(false), isRecording(false)
{
clockFont = Font("Default Light", 30, Font::plain);
// MemoryInputStream mis(BinaryData::cpmonolightserialized, BinaryData::cpmonolightserializedSize, false);
// Typeface::Ptr typeface = new CustomTypeface(mis);
// clockFont = Font(typeface);
// clockFont.setHeight(30);
totalTime = 0;
totalRecordTime = 0;
}
Clock::~Clock()
{
}
void Clock::paint(Graphics& g)
{
g.fillAll(Colour(58,58,58));
drawTime(g);
}
void Clock::drawTime(Graphics& g)
{
if (isRunning)
{
int64 now = Time::currentTimeMillis();
int64 diff = now - lastTime;
totalTime += diff;
if (isRecording)
{
totalRecordTime += diff;
}
lastTime = Time::currentTimeMillis();
}
int m;
int s;
if (isRecording)
{
g.setColour(Colours::red);
m = floor(totalRecordTime/60000.0);
s = floor((totalRecordTime - m*60000.0)/1000.0);
}
else
{
if (isRunning)
g.setColour(Colours::yellow);
else
g.setColour(Colours::white);
m = floor(totalTime/60000.0);
s = floor((totalTime - m*60000.0)/1000.0);
}
String timeString = "";
timeString += m;
timeString += " min ";
timeString += s;
timeString += " s";
g.setFont(clockFont);
//g.setFont(30);
g.drawText(timeString, 0, 0, getWidth(), getHeight(), Justification::left, false);
}
void Clock::start()
{
if (!isRunning)
{
isRunning = true;
lastTime = Time::currentTimeMillis();
}
}
void Clock::resetRecordTime()
{
totalRecordTime = 0;
}
void Clock::startRecording()
{
if (!isRecording)
{
isRecording = true;
start();
}
}
void Clock::stop()
{
if (isRunning)
{
isRunning = false;
isRecording = false;
}
}
void Clock::stopRecording()
{
if (isRecording)
{
isRecording = false;
}
}
ControlPanelButton::ControlPanelButton(ControlPanel* cp_) : cp(cp_)
{
open = false;
}
ControlPanelButton::~ControlPanelButton()
{
}
void ControlPanelButton::paint(Graphics& g)
{
g.fillAll(Colour(58,58,58));
g.setColour(Colours::white);
Path p;
float h = getHeight();
float w = getWidth();
if (open)
{
p.addTriangle(0.5f*w, 0.8f*h,
0.2f*w, 0.2f*h,
0.8f*w, 0.2f*h);
}
else
{
p.addTriangle(0.8f*w, 0.8f*h,
0.2f*w, 0.5f*h,
0.8f*w, 0.2f*h);
}
PathStrokeType pst = PathStrokeType(1.0f, PathStrokeType::curved, PathStrokeType::rounded);
g.strokePath(p, pst);
}
void ControlPanelButton::mouseDown(const MouseEvent& e)
{
open = !open;
cp->openState(open);
repaint();
}
void ControlPanelButton::toggleState()
{
open = !open;
repaint();
}
void ControlPanelButton::setState(bool b)
{
open = b;
repaint();
}
ControlPanel::ControlPanel(ProcessorGraph* graph_, AudioComponent* audio_)
: graph(graph_), audio(audio_), initialize(true), open(false)
{
if (1)
{
font = Font("Paragraph", 13, Font::plain);
// MemoryInputStream mis(BinaryData::misoserialized, BinaryData::misoserializedSize, false);
// Typeface::Ptr typeface = new CustomTypeface(mis);
// font = Font(typeface);
// font.setHeight(15);
}
audioEditor = (AudioEditor*) graph->getAudioNode()->createEditor();
addAndMakeVisible(audioEditor);
playButton = new PlayButton();
playButton->addListener(this);
addAndMakeVisible(playButton);
recordButton = new RecordButton();
recordButton->addListener(this);
addAndMakeVisible(recordButton);
masterClock = new Clock();
addAndMakeVisible(masterClock);
cpuMeter = new CPUMeter();
addAndMakeVisible(cpuMeter);
diskMeter = new DiskSpaceMeter();
addAndMakeVisible(diskMeter);
cpb = new ControlPanelButton(this);
addAndMakeVisible(cpb);
newDirectoryButton = new UtilityButton("+", Font("Small Text", 15, Font::plain));
newDirectoryButton->setEnabledState(false);
newDirectoryButton->addListener(this);
addChildComponent(newDirectoryButton);
filenameComponent = new FilenameComponent("folder selector",
File::getCurrentWorkingDirectory().getFullPathName(),
true,
true,
true,
"*",
"",
"");
addChildComponent(filenameComponent);
prependText = new Label("Prepend","");
prependText->setEditable(true);
prependText->addListener(this);
prependText->setColour(Label::backgroundColourId, Colours::lightgrey);
addChildComponent(prependText);
dateText = new Label("Date","YY-MM-DD_HH-MM-SS");
dateText->setColour(Label::backgroundColourId, Colours::lightgrey);
addChildComponent(dateText);
appendText = new Label("Append","");
appendText->setEditable(true);
appendText->addListener(this);
appendText->setColour(Label::backgroundColourId, Colours::lightgrey);
addChildComponent(appendText);
//diskMeter->updateDiskSpace(graph->getRecordNode()->getFreeSpace());
//diskMeter->repaint();
//refreshMeters();
startTimer(10);
setWantsKeyboardFocus(true);
}
ControlPanel::~ControlPanel()
{
}
void ControlPanel::setRecordState(bool t)
{
//MessageManager* mm = MessageManager::getInstance();
recordButton->setToggleState(t, true);
}
void ControlPanel::updateChildComponents()
{
filenameComponent->addListener(getProcessorGraph()->getRecordNode());
getProcessorGraph()->getRecordNode()->filenameComponentChanged(filenameComponent);
}
void ControlPanel::createPaths()
{
int w = 150;
int h1 = 32;
int h2 = 64;
int indent = 5;
p1.clear();
p1.startNewSubPath(0, h1);
p1.lineTo(w, h1);
p1.lineTo(w + indent, h1 + indent);
p1.lineTo(w + indent, h2 - indent);
p1.lineTo(w + indent*2, h2);
p1.lineTo(0, h2);
p1.closeSubPath();
p2.clear();
p2.startNewSubPath(getWidth(), h2-indent);
p2.lineTo(getWidth(), h2);
p2.lineTo(getWidth()-indent, h2);
p2.closeSubPath();
}
void ControlPanel::paint(Graphics& g)
{
g.setColour(Colour(58,58,58));
g.fillRect(0,0,getWidth(),getHeight());
if (open)
{
g.setColour(Colours::black);
g.fillPath(p1);
g.fillPath(p2);
}
}
void ControlPanel::resized()
{
int w = getWidth();
int h = 32; //getHeight();
if (playButton != 0)
playButton->setBounds(w-h*9,5,h-5,h-10);
if (recordButton != 0)
recordButton->setBounds(w-h*8,5,h-5,h-10);
if (masterClock != 0)
masterClock->setBounds(w-h*6-15,0,h*6-15,h);
if (cpuMeter != 0)
cpuMeter->setBounds(8,h/4,h*3,h/2);
if (diskMeter != 0)
diskMeter->setBounds(16+h*3,h/4,h*3,h/2);
if (audioEditor != 0)
audioEditor->setBounds(h*7,5,h*8,h-10);
if (cpb != 0)
cpb->setBounds(w-28,5,h-10,h-10);
createPaths();
if (open)
{
filenameComponent->setBounds(165, h+5, w-500, h-10);
filenameComponent->setVisible(true);
newDirectoryButton->setBounds(w-h+4, h+5, h-10, h-10);
newDirectoryButton->setVisible(true);
prependText->setBounds(165+w-490, h+5, 50, h-10);
prependText->setVisible(true);
dateText->setBounds(165+w-435, h+5, 175, h-10);
dateText->setVisible(true);
appendText->setBounds(165+w-255, h+5, 50, h-10);
appendText->setVisible(true);
}
else
{
filenameComponent->setVisible(false);
newDirectoryButton->setVisible(false);
prependText->setVisible(false);
dateText->setVisible(false);
appendText->setVisible(false);
}
repaint();
}
void ControlPanel::openState(bool os)
{
open = os;
cpb->setState(os);
getUIComponent()->childComponentChanged();
}
void ControlPanel::labelTextChanged(Label* label)
{
}
void ControlPanel::buttonClicked(Button* button)
{
//const MessageManagerLock mmLock;
if (button == recordButton)
{
std::cout << "Record button pressed." << std::endl;
if (recordButton->getToggleState())
{
playButton->setToggleState(true,false);
masterClock->startRecording(); // turn on recording
}
else
{
graph->setRecordState(false); // turn off recording in processor graph
//graph->getRecordNode()->setParameter(0,10.0f); // turn off recording
masterClock->stopRecording();
newDirectoryButton->setEnabledState(true);
}
}
else if (button == playButton)
{
std::cout << "Play button pressed." << std::endl;
if (!playButton->getToggleState())
{
if (recordButton->getToggleState())
{
recordButton->setToggleState(false,false);
newDirectoryButton->setEnabledState(true);
}
}
}
else if (button == newDirectoryButton && newDirectoryButton->getEnabledState())
{
graph->getRecordNode()->newDirectoryNeeded = true;
newDirectoryButton->setEnabledState(false);
masterClock->resetRecordTime();
return;
}
if (playButton->getToggleState())
{
if (!audio->callbacksAreActive())
{
if (graph->enableProcessors())
{
if (recordButton->getToggleState())
graph->setRecordState(true);
//graph->getRecordNode()->setParameter(1,10.0f);
stopTimer();
startTimer(250); // refresh every 250 ms
audio->beginCallbacks();
masterClock->start();
}
}
else
{
if (recordButton->getToggleState())
{
graph->setRecordState(true); //getRecordNode()->setParameter(1,10.0f);
}
}
}
else
{
if (audio->callbacksAreActive())
{
audio->endCallbacks();
graph->disableProcessors();
refreshMeters();
masterClock->stop();
stopTimer();
startTimer(10000); // back to refresh every 10 seconds
}
}
}
void ControlPanel::disableCallbacks()
{
std::cout << "Control panel received signal to disable callbacks." << std::endl;
if (audio->callbacksAreActive())
{
std::cout << "Stopping audio." << std::endl;
audio->endCallbacks();
std::cout << "Disabling processors." << std::endl;
graph->disableProcessors();
std::cout << "Updating control panel." << std::endl;
refreshMeters();
stopTimer();
startTimer(10000); // back to refresh every 10 seconds
}
playButton->setToggleState(false,false);
recordButton->setToggleState(false,false);
masterClock->stopRecording();
masterClock->stop();
}
// void ControlPanel::actionListenerCallback(const String & msg)
// {
// //std::cout << "Message Received." << std::endl;
// if (playButton->getToggleState()) {
// cpuMeter->updateCPU(audio->deviceManager.getCpuUsage());
// }
// cpuMeter->repaint();
// diskMeter->updateDiskSpace(graph->getRecordNode()->getFreeSpace());
// diskMeter->repaint();
// }
void ControlPanel::timerCallback()
{
//std::cout << "Message Received." << std::endl;
refreshMeters();
}
void ControlPanel::refreshMeters()
{
if (playButton->getToggleState())
{
cpuMeter->updateCPU(audio->deviceManager.getCpuUsage());
}
else
{
cpuMeter->updateCPU(0.0f);
}
cpuMeter->repaint();
masterClock->repaint();
diskMeter->updateDiskSpace(graph->getRecordNode()->getFreeSpace());
diskMeter->repaint();
if (initialize)
{
stopTimer();
startTimer(5000); // check for disk updates every 5 seconds
initialize = false;
}
}
bool ControlPanel::keyPressed(const KeyPress& key)
{
std::cout << "Control panel received" << key.getKeyCode() << std::endl;
return false;
}
void ControlPanel::toggleState()
{
open = !open;
cpb->toggleState();
getUIComponent()->childComponentChanged();
}
String ControlPanel::getTextToAppend()
{
String t = appendText->getText();
if (t.length() > 0)
{
return "_" + t;
}
else
{
return t;
}
}
String ControlPanel::getTextToPrepend()
{
String t = prependText->getText();
if (t.length() > 0)
{
return t + "_";
}
else
{
return t;
}
}
void ControlPanel::setDateText(String t)
{
dateText->setText(t, dontSendNotification);
}
void ControlPanel::saveStateToXml(XmlElement* xml)
{
XmlElement* controlPanelState = xml->createNewChildElement("CONTROLPANEL");
controlPanelState->setAttribute("isOpen",open);
controlPanelState->setAttribute("prependText",prependText->getText());
controlPanelState->setAttribute("appendText",appendText->getText());
}
void ControlPanel::loadStateFromXml(XmlElement* xml)
{
forEachXmlChildElement(*xml, xmlNode)
{
if (xmlNode->hasTagName("CONTROLPANEL"))
{
appendText->setText(xmlNode->getStringAttribute("appendText", ""), dontSendNotification);
prependText->setText(xmlNode->getStringAttribute("prependText", ""), dontSendNotification);
bool isOpen = xmlNode->getBoolAttribute("isOpen");
openState(isOpen);
}
}
}