diff --git a/Source/Processors/Editors/ChannelSelector.cpp b/Source/Processors/Editors/ChannelSelector.cpp index f9fca0de3223322ca88133c2b873a6b1e4eb2c3d..6caf21b16e690bfc83dfc596f8cbe530dbd5e9a6 100755 --- a/Source/Processors/Editors/ChannelSelector.cpp +++ b/Source/Processors/Editors/ChannelSelector.cpp @@ -1,25 +1,25 @@ /* - ------------------------------------------------------------------ - - 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/>. - - */ +------------------------------------------------------------------ + +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 "ChannelSelector.h" #include <math.h> @@ -31,93 +31,121 @@ #include "../../UI/GraphViewer.h" ChannelSelector::ChannelSelector(bool createButtons, Font& titleFont_) : -eventsOnly(false), paramsToggled(true), paramsActive(true), -recActive(true), radioStatus(false), isNotSink(createButtons), -moveRight(false), moveLeft(false), offsetLR(0), offsetUD(0), desiredOffset(0), titleFont(titleFont_), acquisitionIsActive(false) + eventsOnly(false), paramsToggled(true), paramsActive(true), + recActive(true), radioStatus(false), isNotSink(createButtons), + moveRight(false), moveLeft(false), offsetLR(0), offsetUD(0), desiredOffset(0), titleFont(titleFont_), acquisitionIsActive(false) { - + // initialize buttons audioButton = new EditorButton("AUDIO", titleFont); audioButton->addListener(this); addAndMakeVisible(audioButton); if (!createButtons) audioButton->setState(false); - + recordButton = new EditorButton("REC", titleFont); recordButton->addListener(this); addAndMakeVisible(recordButton); if (!createButtons) recordButton->setState(false); - + paramsButton = new EditorButton("PARAM", titleFont); paramsButton->addListener(this); addAndMakeVisible(paramsButton); - + paramsButton->setToggleState(true, dontSendNotification); - + audioButtons.clear(); recordButtons.clear(); - + // set button layout parameters parameterOffset = 0; recordOffset = getDesiredWidth(); - audioOffset = getDesiredWidth()*2; - + audioOffset = getDesiredWidth() * 2; + parameterButtons.clear(); - + allButton = new EditorButton("all", titleFont); allButton->addListener(this); addAndMakeVisible(allButton); - + noneButton = new EditorButton("none", titleFont); noneButton->addListener(this); addAndMakeVisible(noneButton); - + + selectButtonParam = new EditorButton("+", titleFont); + selectButtonParam->addListener(this); + addAndMakeVisible(selectButtonParam); + + deselectButtonParam = new EditorButton("-", titleFont); + deselectButtonParam->addListener(this); + addAndMakeVisible(deselectButtonParam); + + selectButtonRecord = new EditorButton("+", titleFont); + selectButtonRecord->addListener(this); + addAndMakeVisible(selectButtonRecord); + + deselectButtonRecord = new EditorButton("-", titleFont); + deselectButtonRecord->addListener(this); + addAndMakeVisible(deselectButtonRecord); + + selectButtonAudio = new EditorButton("+", titleFont); + selectButtonAudio->addListener(this); + addAndMakeVisible(selectButtonAudio); + + deselectButtonAudio = new EditorButton("-", titleFont); + deselectButtonAudio->addListener(this); + addAndMakeVisible(deselectButtonAudio); + channelSelectorRegion = new ChannelSelectorRegion(this); //channelSelectorRegion->setBounds(0,20,0,getHeight()-35); addAndMakeVisible(channelSelectorRegion); channelSelectorRegion->toBack(); - + + paramBox = new ChannelSelectorBox(); + recordBox = new ChannelSelectorBox(); + audioBox = new ChannelSelectorBox(); + numColumnsLessThan100 = 8; numColumnsGreaterThan100 = 6; - + } ChannelSelector::~ChannelSelector() { deleteAllChildren(); - + } void ChannelSelector::paint(Graphics& g) { - ColourGradient grad1 = ColourGradient(Colours::black.withAlpha(0.8f),0.0,0.0, - Colours::black.withAlpha(0.1f),0.0,25.0f, + ColourGradient grad1 = ColourGradient(Colours::black.withAlpha(0.8f), 0.0, 0.0, + Colours::black.withAlpha(0.1f), 0.0, 25.0f, false); g.setGradientFill(grad1); - g.fillRect(0, 15, getWidth(), getHeight()-30); - - ColourGradient grad2 = ColourGradient(Colours::black.withAlpha(0.2f),0.0,0.0, - Colours::black.withAlpha(0.0f),5.0f,0.0f, + g.fillRect(0, 15, getWidth(), getHeight() - 30); + + ColourGradient grad2 = ColourGradient(Colours::black.withAlpha(0.2f), 0.0, 0.0, + Colours::black.withAlpha(0.0f), 5.0f, 0.0f, false); g.setGradientFill(grad2); - g.fillRect(0, 15, getWidth(), getHeight()-30); - - ColourGradient grad3 = ColourGradient(Colours::black.withAlpha(0.2f),(float) getDesiredWidth(),0.0, - Colours::black.withAlpha(0.0f),(float) getDesiredWidth()-5.0f,0.0f, + g.fillRect(0, 15, getWidth(), getHeight() - 30); + + ColourGradient grad3 = ColourGradient(Colours::black.withAlpha(0.2f), (float)getDesiredWidth(), 0.0, + Colours::black.withAlpha(0.0f), (float)getDesiredWidth() - 5.0f, 0.0f, false); g.setGradientFill(grad3); - g.fillRect(0, 15, getWidth(), getHeight()-30); + g.fillRect(0, 15, getWidth(), getHeight() - 30); } void ChannelSelector::setNumChannels(int numChans) { - + int difference = numChans - parameterButtons.size(); - + // std::cout << difference << " buttons needed." << std::endl; - + if (difference > 0) { for (int n = 0; n < difference; n++) @@ -132,21 +160,21 @@ void ChannelSelector::setNumChannels(int numChans) removeButton(); } } - + //Reassign numbers according to the actual channels (useful for channel mapper) for (int n = 0; n < parameterButtons.size(); n++) { int num = ((GenericEditor*)getParentComponent())->getChannel(n)->nodeIndex; - parameterButtons[n]->setChannel(n+1, num+1); + parameterButtons[n]->setChannel(n + 1, num + 1); if (isNotSink) { - recordButtons[n]->setChannel(n+1, num+1); - audioButtons[n]->setChannel(n+1, num+1); + recordButtons[n]->setChannel(n + 1, num + 1); + audioButtons[n]->setChannel(n + 1, num + 1); } } - + refreshButtonBoundaries(); - + } int ChannelSelector::getNumChannels() @@ -156,72 +184,108 @@ int ChannelSelector::getNumChannels() void ChannelSelector::shiftChannelsVertical(float amount) { - - if (parameterButtons.size() > 32) + + if (parameterButtons.size() > 16) { - offsetUD -= amount*10; + offsetUD -= amount * 10; offsetUD = jmin(offsetUD, 0.0f); - offsetUD = jmax(offsetUD, (float) -overallHeight); + offsetUD = jmax(offsetUD, (float)-overallHeight); } - + //std::cout << "offsetUD = " << offsetUD << std::endl; - + refreshButtonBoundaries(); - + } void ChannelSelector::refreshButtonBoundaries() { - - channelSelectorRegion->setBounds(0,20,getWidth(),getHeight()-35); - - int rowHeight = 14; + + channelSelectorRegion->setBounds(0, 20, getWidth(), getHeight() - 35); + + int rowHeight = 14,px,py,rx,ry,ax,ay; int column = 0; int row = 0; int nColumns; - + for (int i = 0; i < parameterButtons.size(); i++) { - + if (i < 96) nColumns = numColumnsLessThan100; else nColumns = numColumnsGreaterThan100; - + int columnWidth = getDesiredWidth() / (nColumns + 1) + 1; - + int xLoc = columnWidth / 2 + offsetLR + columnWidth*column; - int yLoc = row * rowHeight + offsetUD; - + int yLoc = row * rowHeight + offsetUD + 25; + if (i == 0) + { + px = xLoc; + py = yLoc - 25; + rx = xLoc - getDesiredWidth(); + ry = yLoc - 25; + ax = xLoc - getDesiredWidth() * 2; + ay = yLoc - 25; + } parameterButtons[i]->setBounds(xLoc, yLoc, columnWidth, rowHeight); - + if (isNotSink) { recordButtons[i]->setBounds(xLoc - getDesiredWidth(), yLoc, columnWidth, rowHeight); - audioButtons[i]->setBounds(xLoc - getDesiredWidth()*2, yLoc, columnWidth, rowHeight); + audioButtons[i]->setBounds(xLoc - getDesiredWidth() * 2, yLoc, columnWidth, rowHeight); } - + column++; - + if (column >= nColumns) { column = 0; row++; overallHeight = row * rowHeight; } - + } - - int w = getWidth()/3; + + int w = getWidth() / 3; int h = 15; - + + + /* + definition of textbox + */ + paramBox->setBounds(px, py+20, 90, 20); + addAndMakeVisible(paramBox); + recordBox->setBounds(rx, ry+20, 90, 20); + addAndMakeVisible(recordBox); + audioBox->setBounds(ax, ay+20, 90, 20); + addAndMakeVisible(audioBox); + + /* + audio,record and param tabs + */ audioButton->setBounds(0, 0, w, h); recordButton->setBounds(w, 0, w, h); - paramsButton->setBounds(w*2, 0, w, h); - - allButton->setBounds(0, getHeight()-15, getWidth()/2, 15); - noneButton->setBounds(getWidth()/2, getHeight()-15, getWidth()/2, 15); - + paramsButton->setBounds(w * 2, 0, w, h); + + /* + select and deselect button under each tab + */ + selectButtonParam->setBounds(px + 95, py + 20, 20, 20); + deselectButtonParam->setBounds(px + 117, py + 20, 20, 20); + + selectButtonRecord->setBounds(rx + 95, ry + 20, 20, 20); + deselectButtonRecord->setBounds(rx + 117, ry + 20, 20, 20); + + selectButtonAudio->setBounds(ax + 95, ay + 20, 20, 20); + deselectButtonAudio->setBounds(ax + 117, ay + 20, 20, 20); + /* + All and None buttons + */ + allButton->setBounds(0, getHeight() - 15, getWidth() / 2, 15); + noneButton->setBounds(getWidth() / 2, getHeight() - 15, getWidth() / 2, 15); + } void ChannelSelector::resized() @@ -231,9 +295,9 @@ void ChannelSelector::resized() void ChannelSelector::timerCallback() { - + //std::cout << desiredOffset - offsetLR << std::endl; - + if (offsetLR != desiredOffset) { if (desiredOffset - offsetLR > 0) @@ -246,44 +310,44 @@ void ChannelSelector::timerCallback() { offsetLR -= 25; } - + } else { stopTimer(); } - + refreshButtonBoundaries(); - + } void ChannelSelector::addButton() { - + int size = parameterButtons.size(); - - ChannelSelectorButton* b = new ChannelSelectorButton(size+1, PARAMETER, titleFont); + + ChannelSelectorButton* b = new ChannelSelectorButton(size + 1, PARAMETER, titleFont); parameterButtons.add(b); channelSelectorRegion->addAndMakeVisible(b); - + if (paramsToggled) b->setToggleState(true, dontSendNotification); else b->setToggleState(false, dontSendNotification); - + if (!paramsActive) b->setActive(false); - + b->addListener(this); - + if (isNotSink) { - ChannelSelectorButton* br = new ChannelSelectorButton(size+1, RECORD, titleFont); + ChannelSelectorButton* br = new ChannelSelectorButton(size + 1, RECORD, titleFont); recordButtons.add(br); channelSelectorRegion->addAndMakeVisible(br); br->addListener(this); - - ChannelSelectorButton* ba = new ChannelSelectorButton(size+1, AUDIO, titleFont); + + ChannelSelectorButton* ba = new ChannelSelectorButton(size + 1, AUDIO, titleFont); audioButtons.add(ba); channelSelectorRegion->addAndMakeVisible(ba); ba->addListener(this); @@ -293,18 +357,18 @@ void ChannelSelector::addButton() void ChannelSelector::removeButton() { int size = parameterButtons.size(); - - ChannelSelectorButton* b = parameterButtons.remove(size-1); + + ChannelSelectorButton* b = parameterButtons.remove(size - 1); channelSelectorRegion->removeChildComponent(b); deleteAndZero(b); - + if (isNotSink) { - ChannelSelectorButton* br = recordButtons.remove(size-1); + ChannelSelectorButton* br = recordButtons.remove(size - 1); channelSelectorRegion->removeChildComponent(br); deleteAndZero(br); - - ChannelSelectorButton* ba = audioButtons.remove(size-1); + + ChannelSelectorButton* ba = audioButtons.remove(size - 1); channelSelectorRegion->removeChildComponent(ba); deleteAndZero(ba); } @@ -313,7 +377,7 @@ void ChannelSelector::removeButton() Array<int> ChannelSelector::getActiveChannels() { Array<int> a; - + if (!eventsOnly) { for (int i = 0; i < parameterButtons.size(); i++) @@ -326,13 +390,15 @@ Array<int> ChannelSelector::getActiveChannels() { a.add(0); } - + return a; } void ChannelSelector::setActiveChannels(Array<int> a) { + //std::cout << "Setting active channels!" << std::endl; + for (int i = 0; i < parameterButtons.size(); i++) { parameterButtons[i]->setToggleState(false, dontSendNotification); @@ -349,9 +415,9 @@ void ChannelSelector::setActiveChannels(Array<int> a) void ChannelSelector::inactivateButtons() { - + paramsActive = false; - + for (int i = 0; i < parameterButtons.size(); i++) { parameterButtons[i]->setActive(false); @@ -361,22 +427,22 @@ void ChannelSelector::inactivateButtons() void ChannelSelector::activateButtons() { - + paramsActive = true; - + for (int i = 0; i < parameterButtons.size(); i++) { parameterButtons[i]->setActive(true); parameterButtons[i]->repaint(); } - + } void ChannelSelector::inactivateRecButtons() { - + recActive = false; - + for (int i = 0; i < recordButtons.size(); i++) { recordButtons[i]->setActive(false); @@ -386,15 +452,15 @@ void ChannelSelector::inactivateRecButtons() void ChannelSelector::activateRecButtons() { - + recActive = true; - + for (int i = 0; i < recordButtons.size(); i++) { recordButtons[i]->setActive(true); recordButtons[i]->repaint(); } - + } void ChannelSelector::refreshParameterColors() @@ -420,12 +486,12 @@ void ChannelSelector::stopAcquisition() void ChannelSelector::setRadioStatus(bool radioOn) { - + if (radioStatus != radioOn) { - + radioStatus = radioOn; - + for (int i = 0; i < parameterButtons.size(); i++) { if (radioOn) @@ -439,65 +505,65 @@ void ChannelSelector::setRadioStatus(bool radioOn) parameterButtons[i]->setRadioGroupId(0); } } - + } - - - + + + } bool ChannelSelector::getParamStatus(int chan) { - + if (chan >= 0 && chan < parameterButtons.size()) return parameterButtons[chan]->getToggleState(); else return false; - + } bool ChannelSelector::getRecordStatus(int chan) { - + if (chan >= 0 && chan < recordButtons.size()) return recordButtons[chan]->getToggleState(); else return false; - + } bool ChannelSelector::getAudioStatus(int chan) { - + if (chan >= 0 && chan < audioButtons.size()) return audioButtons[chan]->getToggleState(); else return false; - + } void ChannelSelector::setParamStatus(int chan, bool b) { - + if (chan >= 0 && chan < parameterButtons.size()) parameterButtons[chan]->setToggleState(b, sendNotification); - + } void ChannelSelector::setRecordStatus(int chan, bool b) { - + if (chan >= 0 && chan < recordButtons.size()) recordButtons[chan]->setToggleState(b, sendNotification); - + } void ChannelSelector::setAudioStatus(int chan, bool b) { - + if (chan >= 0 && chan < audioButtons.size()) audioButtons[chan]->setToggleState(b, sendNotification); - + } void ChannelSelector::clearAudio() @@ -525,11 +591,11 @@ void ChannelSelector::buttonClicked(Button* button) else if (button == audioButton) { // make sure audio buttons are visible - + if (audioButton->getState()) { allButton->setState(false); - + desiredOffset = audioOffset; startTimer(20); } @@ -559,18 +625,18 @@ void ChannelSelector::buttonClicked(Button* button) // select all active buttons if (offsetLR == recordOffset) { - - + + for (int i = 0; i < recordButtons.size(); i++) { recordButtons[i]->setToggleState(true, sendNotification); } - + } else if (offsetLR == parameterOffset) { - - + + for (int i = 0; i < parameterButtons.size(); i++) { parameterButtons[i]->setToggleState(true, sendNotification); @@ -605,7 +671,7 @@ void ChannelSelector::buttonClicked(Button* button) audioButtons[i]->setToggleState(false, sendNotification); } } - + if (radioStatus) // if radio buttons are active { // send a message to parent @@ -613,22 +679,190 @@ void ChannelSelector::buttonClicked(Button* button) editor->channelChanged (-1, false); } } + else if (button == selectButtonParam) + { // select channels in parameter tab + selectButtonParam->removeListener(this); + deselectButtonParam->removeListener(this); + std::vector<int> getBoxList; + int fa, lim, comd, i, j; + getBoxList = paramBox->getBoxInfo(parameterButtons.size()); + if (getBoxList.size() < 3) + { + selectButtonParam->addListener(this); + deselectButtonParam->addListener(this); + return; + } + i = 0; + while (i <= getBoxList.size() - 3) + { + fa = getBoxList[i]; + lim = getBoxList[i + 1]; + comd = getBoxList[i + 2]; + for (; fa <= lim; fa += comd) + { + parameterButtons[fa]->setToggleState(true, sendNotification); + } + i += 3; + } + selectButtonParam->addListener(this); + deselectButtonParam->addListener(this); + } + else if (button == selectButtonRecord) + { // select channels in record tab + selectButtonRecord->removeListener(this); + deselectButtonRecord->removeListener(this); + std::vector<int> getBoxList; + int fa, lim, comd, i, j; + getBoxList = recordBox->getBoxInfo(recordButtons.size()); + if (getBoxList.size() < 3) + { + selectButtonRecord->addListener(this); + deselectButtonRecord->addListener(this); + return; + } + i = 0; + while (i <= getBoxList.size() - 3) + { + fa = getBoxList[i]; + lim = getBoxList[i + 1]; + comd = getBoxList[i + 2]; + for (; fa <= lim; fa += comd) + { + recordButtons[fa]->setToggleState(true, sendNotification); + } + i += 3; + } + selectButtonRecord->addListener(this); + deselectButtonRecord->addListener(this); + } + else if (button == selectButtonAudio) + { // select channels in audio tab + selectButtonAudio->removeListener(this); + deselectButtonAudio->removeListener(this); + std::vector<int> getBoxList; + int fa, lim, comd, i, j; + getBoxList = audioBox->getBoxInfo(audioButtons.size()); + if (getBoxList.size() < 3) + { + selectButtonAudio->addListener(this); + deselectButtonAudio->addListener(this); + return; + } + i = 0; + while (i <= getBoxList.size() - 3) + { + fa = getBoxList[i]; + lim = getBoxList[i + 1]; + comd = getBoxList[i + 2]; + for (; fa <= lim; fa += comd) + { + audioButtons[fa]->setToggleState(true, sendNotification); + } + i += 3; + } + selectButtonAudio->addListener(this); + deselectButtonAudio->addListener(this); + } + else if (button == deselectButtonParam) + { // deselect channels in param tab + selectButtonParam->removeListener(this); + deselectButtonParam->removeListener(this); + std::vector<int> getBoxList; + int fa, lim, comd, i, j; + getBoxList = paramBox->getBoxInfo(parameterButtons.size()); + if (getBoxList.size() < 3) + { + selectButtonParam->addListener(this); + deselectButtonParam->addListener(this); + return; + } + i = 0; + while (i <= getBoxList.size() - 3) + { + fa = getBoxList[i]; + lim = getBoxList[i + 1]; + comd = getBoxList[i + 2]; + for (; fa <= lim; fa += comd) + { + parameterButtons[fa]->setToggleState(false, sendNotification); + } + i += 3; + } + selectButtonParam->addListener(this); + deselectButtonParam->addListener(this); + } + else if (button == deselectButtonRecord) + { // deselect channels in record tab + selectButtonRecord->removeListener(this); + deselectButtonRecord->removeListener(this); + std::vector<int> getBoxList; + int fa, lim, comd, i, j; + getBoxList = recordBox->getBoxInfo(recordButtons.size()); + if (getBoxList.size() < 3) + { + selectButtonRecord->addListener(this); + deselectButtonRecord->addListener(this); + return; + } + i = 0; + while (i <= getBoxList.size() - 3) + { + fa = getBoxList[i]; + lim = getBoxList[i + 1]; + comd = getBoxList[i + 2]; + for (; fa <= lim; fa += comd) + { + recordButtons[fa]->setToggleState(false, sendNotification); + } + i += 3; + } + selectButtonRecord->addListener(this); + deselectButtonRecord->addListener(this); + } + else if (button == deselectButtonAudio) + { // deselect channels in audio tab + selectButtonAudio->removeListener(this); + deselectButtonAudio->removeListener(this); + std::vector<int> getBoxList; + int fa, lim, comd, i, j; + getBoxList = audioBox->getBoxInfo(audioButtons.size()); + if (getBoxList.size() < 3) + { + selectButtonAudio->addListener(this); + deselectButtonAudio->addListener(this); + return; + } + i = 0; + while (i <= getBoxList.size() - 3) + { + fa = getBoxList[i]; + lim = getBoxList[i + 1]; + comd = getBoxList[i + 2]; + for (; fa <= lim; fa += comd) + { + audioButtons[fa]->setToggleState(false, sendNotification); + } + i += 3; + } + selectButtonAudio->addListener(this); + deselectButtonAudio->addListener(this); + } else { - - ChannelSelectorButton* b = (ChannelSelectorButton*) button; - + + ChannelSelectorButton* b = (ChannelSelectorButton*)button; + if (b->getType() == AUDIO) { // get audio node, and inform it of the change - GenericEditor* editor = (GenericEditor*) getParentComponent(); - - Channel* ch = editor->getChannel(b->getChannel()-1); + GenericEditor* editor = (GenericEditor*)getParentComponent(); + + Channel* ch = editor->getChannel(b->getChannel() - 1); //int channelNum = editor->getStartChannel() + b->getChannel() - 1; bool status = b->getToggleState(); - - std::cout << "Requesting audio monitor for channel " << ch->nodeIndex+1 << std::endl; - + + std::cout << "Requesting audio monitor for channel " << ch->nodeIndex + 1 << std::endl; + if (acquisitionIsActive) // use setParameter to change parameter safely { AccessClass::getProcessorGraph()-> @@ -638,18 +872,18 @@ void ChannelSelector::buttonClicked(Button* button) { ch->isMonitored = status; } - - + + } else if (b->getType() == RECORD) { // get record node, and inform it of the change - GenericEditor* editor = (GenericEditor*) getParentComponent(); - - Channel* ch = editor->getChannel(b->getChannel()-1); + GenericEditor* editor = (GenericEditor*)getParentComponent(); + + Channel* ch = editor->getChannel(b->getChannel() - 1); //int channelNum = editor->getStartChannel() + b->getChannel() - 1; bool status = b->getToggleState(); - + if (acquisitionIsActive) // use setParameter to change parameter safely { AccessClass::getProcessorGraph()-> @@ -661,9 +895,9 @@ void ChannelSelector::buttonClicked(Button* button) //std::cout << "Setting record status for channel " << b->getChannel() << std::endl; ch->setRecordState(status); } - + AccessClass::getGraphViewer()->repaint(); - + } else // parameter type { @@ -678,6 +912,7 @@ void ChannelSelector::buttonClicked(Button* button) editor->channelChanged (b->getChannel(), b->getToggleState()); } } + } refreshParameterColors(); } @@ -688,32 +923,33 @@ void ChannelSelector::buttonClicked(Button* button) EditorButton::EditorButton(const String& name, Font& f) : Button(name) { - + isEnabled = true; - + buttonFont = f; - buttonFont.setHeight (11); - + + buttonFont.setHeight(10); + if (!getName().equalsIgnoreCase("all") && !getName().equalsIgnoreCase("none")) { setRadioGroupId(999); setClickingTogglesState(true); } - - selectedGrad = ColourGradient(Colour(240,179,12),0.0,0.0, - Colour(207,160,33),0.0, 20.0f, + + selectedGrad = ColourGradient(Colour(240, 179, 12), 0.0, 0.0, + Colour(207, 160, 33), 0.0, 20.0f, false); - selectedOverGrad = ColourGradient(Colour(209,162,33),0.0, 5.0f, - Colour(190,150,25),0.0, 0.0f, + selectedOverGrad = ColourGradient(Colour(209, 162, 33), 0.0, 5.0f, + Colour(190, 150, 25), 0.0, 0.0f, false); - neutralGrad = ColourGradient(Colour(220,220,220),0.0,0.0, - Colour(170,170,170),0.0, 20.0f, + neutralGrad = ColourGradient(Colour(220, 220, 220), 0.0, 0.0, + Colour(170, 170, 170), 0.0, 20.0f, false); - neutralOverGrad = ColourGradient(Colour(180,180,180),0.0,5.0f, - Colour(150,150,150),0.0, 0.0, + neutralOverGrad = ColourGradient(Colour(180, 180, 180), 0.0, 5.0f, + Colour(150, 150, 150), 0.0, 0.0, false); - - + + } EditorButton::~EditorButton() {} @@ -726,7 +962,7 @@ bool EditorButton::getState() void EditorButton::setState(bool state) { isEnabled = state; - + if (!state) { removeListener((Button::Listener*) getParentComponent()); @@ -735,96 +971,110 @@ void EditorButton::setState(bool state) { addListener((Button::Listener*) getParentComponent()); } - + repaint(); } void EditorButton::resized() { // float radius = 5.0f; - float width = (float) getWidth(); - float height = (float) getHeight(); - + float width = (float)getWidth(); + float height = (float)getHeight(); + if (getName().equalsIgnoreCase("AUDIO")) { //outlinePath.startNewSubPath(0, height); outlinePath.lineTo(0, 0);//radius); //outlinePath.addArc(0, 0, radius*2, radius*2, 1.5*double_Pi, 2.0*double_Pi ); - + outlinePath.lineTo(width, 0);//getHeight()); - + outlinePath.lineTo(width, height); - + outlinePath.lineTo(0, height); //outlinePath.addArc(0, getHeight()-radius*2, radius*2, radius*2, double_Pi, 1.5*double_Pi); //outlinePath.lineTo(0, radius); outlinePath.closeSubPath(); - + } else if (getName().equalsIgnoreCase("PARAM")) { //outlinePath.startNewSubPath(0, 0); - + outlinePath.lineTo(width, 0); - + //outlinePath.addArc(width-radius*2, 0, radius*2, radius*2, 0, 0.5*double_Pi); - + outlinePath.lineTo(getWidth(), height); - + //outlinePath.addArc(getWidth()-radius*2, getHeight()-radius*2, radius*2, radius*2, 0.5*double_Pi, double_Pi); - + outlinePath.lineTo(0, height); outlinePath.lineTo(0, 0); //outlinePath.closeSubPath(); - - + + } else if (getName().equalsIgnoreCase("REC")) { - - outlinePath.addRectangle(0,0,getWidth(),getHeight()); - + + outlinePath.addRectangle(0, 0, getWidth(), getHeight()); + } else if (getName().equalsIgnoreCase("all")) { - + //outlinePath.startNewSubPath(0, 0); - + outlinePath.lineTo(width, 0); - + //outlinePath.addArc(width-radius*2, 0, radius*2, radius*2, 0, 0.5*double_Pi); - + outlinePath.lineTo(width, height); - + //outlinePath.addArc(getWidth()-radius*2, getHeight()-radius*2, radius*2, radius*2, 0.5*double_Pi, double_Pi); - + outlinePath.lineTo(0, height); //outlinePath.addArc(0, height-radius*2, radius*2, radius*2, double_Pi, 1.5*double_Pi); - + outlinePath.lineTo(0, 0); //outlinePath.closeSubPath(); - + } else if (getName().equalsIgnoreCase("none")) { - + //outlinePath.startNewSubPath(0, 0); - + outlinePath.lineTo(width, 0); - + //outlinePath.addArc(width-radius*2, 0, radius*2, radius*2, 0, 0.5*double_Pi); - + outlinePath.lineTo(width, height); - + //outlinePath.addArc(width-radius*2, height-radius*2, radius*2, radius*2, 0.5*double_Pi, double_Pi); - + outlinePath.lineTo(0, height); - + outlinePath.lineTo(0, 0); //outlinePath.closeSubPath(); - + + } + else if (getName().equalsIgnoreCase("+") ) + { + outlinePath.lineTo(width, 0); + outlinePath.lineTo(width, height); + outlinePath.lineTo(0, height); + outlinePath.lineTo(0, 0); } - + else if (getName().equalsIgnoreCase("-") ) + { + outlinePath.lineTo(width, 0); + outlinePath.lineTo(width, height); + outlinePath.lineTo(0, height); + outlinePath.lineTo(0, 0); + } + } @@ -849,21 +1099,24 @@ void EditorButton::paintButton(Graphics& g, bool isMouseOver, bool isButtonDown) g.setGradientFill(neutralGrad); } - AffineTransform a = AffineTransform::scale(0.98f, 0.94f, float(getWidth())/2.0f, - float(getHeight())/2.0f); + + AffineTransform a = AffineTransform::scale(0.98f, 0.94f, float(getWidth()) / 2.0f, + float(getHeight()) / 2.0f); g.fillPath(outlinePath, a); - auto buttonName = getName().toUpperCase(); - int stringWidth = buttonFont.getStringWidth (buttonName); + buttonFont.setHeight(10.0f); + int stringWidth = buttonFont.getStringWidth(getName()); - g.setFont (buttonFont); + g.setFont(buttonFont); if (isEnabled) g.setColour(Colours::darkgrey); else g.setColour(Colours::lightgrey); - g.drawSingleLineText (buttonName, getWidth() / 2 - stringWidth / 2, 11); + + g.drawSingleLineText(getName(), getWidth() / 2 - stringWidth / 2, 11); + } @@ -911,7 +1164,7 @@ void ChannelSelectorButton::paintButton(Graphics& g, bool isMouseOver, bool isBu g.setColour(Colours::orange); else g.setColour(Colours::darkgrey); - + if (isMouseOver) g.setColour(Colours::white); } @@ -922,14 +1175,14 @@ void ChannelSelectorButton::paintButton(Graphics& g, bool isMouseOver, bool isBu else g.setColour(Colours::lightgrey); } - + // g.fillRect(0,0,getWidth(),getHeight()); - + g.setFont(buttonFont); - + // g.drawRect(0,0,getWidth(),getHeight(),1.0); - - g.drawText(String(displayNum),0,0,getWidth(),getHeight(),Justification::centred,true); + + g.drawText(String(displayNum), 0, 0, getWidth(), getHeight(), Justification::centred, true); } void ChannelSelectorButton::setActive(bool t) @@ -941,7 +1194,7 @@ void ChannelSelectorButton::setActive(bool t) ChannelSelectorRegion::ChannelSelectorRegion(ChannelSelector* cs) { channelSelector = cs; - + addMouseListener((MouseListener*) this, true); } @@ -951,14 +1204,192 @@ ChannelSelectorRegion::~ChannelSelectorRegion() } void ChannelSelectorRegion::mouseWheelMove(const MouseEvent& event, - const MouseWheelDetails& wheel) + const MouseWheelDetails& wheel) { - + // std::cout << "Got wheel move: " << wheel.deltaY << std::endl; channelSelector->shiftChannelsVertical(-wheel.deltaY); } void ChannelSelectorRegion::paint(Graphics& g) { - // g.fillAll(Colours::white; + // g.fillAll(Colours::white); +} + + +/* + Constructor and Destructor of ChannelSelectorBox. +*/ +ChannelSelectorBox::ChannelSelectorBox() +{ + setMultiLine(false, true); // No multi lines. + setReturnKeyStartsNewLine(false); // Return key donot start a new line. + setTabKeyUsedAsCharacter(false); + setTooltip("General Format: [a:b:c]->to select all channels from a to c at intervals of b"); +} + +ChannelSelectorBox::~ChannelSelectorBox() +{ + +} + +/* + convert a string to integer. +*/ +int ChannelSelectorBox::convertToInteger(std::string s) +{ + char ar[20]; + int i, j, k = 0; + for (i = 0; i < s.size(); i++) + { + if (s[i] >= 48 && s[i] <= 57) + { + ar[k] = s[i]; + k++; + } + } + if (k>7) + { + return 1000000; + } + ar[k] = '\0'; + k = atoi(ar); + return k; } + + +/* + TextBox to take input. Valid formats: + 1. [ : ] -> select/deselect all channels + 2. [ a : b] -> select/deselect all channels from a to b. + 3. [ a : c : b] -> select/deselect all channels from a to b such that the difference between in each consecutive selected channel is c. +*/ +std::vector<int> ChannelSelectorBox::getBoxInfo(int len) +{ + std::string s = ","; + s += getText().toStdString(); + std::vector<int> finalList,separator,rangeseparator; + int i, j, a, b, k, openb, closeb, otherchar,x,y; + s += ","; + for (i = 0; i < s.size(); i++) //split string by ' , ' or ' ; ' + { + if (s[i] == ';' || s[i] == ',') + { + separator.push_back(i); + } + } + for (i = 0; i < separator.size()-1; i++) // split ranges by ' : ' or ' - ' + { + j = k = separator[i] + 1; + openb = closeb = otherchar = 0; + rangeseparator.clear(); + for (; j < separator[i + 1]; j++) + { + if (s[j] == '-' || s[j] == ':') + { + rangeseparator.push_back(j); + } + else if (((int)s[j] == 32)) + { + continue; + } + else if (s[j] == '[' || s[j] == '{' || s[j] == '(') + { + openb++; + } + else if (s[j] == ']' || s[j] == '}' || s[j] == ')') + { + closeb++; + } + else if ( (int)s[j] > 57 || (int)s[j] < 48) + { + otherchar++; + } + } + + if (openb != closeb || openb > 1 || closeb > 1 || otherchar > 0) //Invalid input + { + continue; + } + + + for (x = separator[i] + 1; x < separator[i + 1]; x++) //trim whitespace and brackets from front + { + if (((int)s[x] >= 48 && (int)s[x] <= 57) || s[x] == ':' || s[x] == '-') + { + break; + } + } + for (y = separator[i + 1] - 1; y > separator[i]; y--) //trim whitespace and brackets from end + { + if (((int)s[y] >= 48 && (int)s[y] <= 57) || s[y] == ':' || s[y] == '-') + { + break; + } + } + if (x > y) + { + continue; + } + + + if (rangeseparator.size() == 0) //syntax of form - x or [x] + { + a = convertToInteger(s.substr(x, y - x + 1)); + if (a == 0||a>len) + { + continue; + } + finalList.push_back(a - 1); + finalList.push_back(a - 1); + finalList.push_back(1); + } + else if (rangeseparator.size() == 1) // syntax of type - x-y or [x-y] + { + a = convertToInteger(s.substr(x, rangeseparator[0] - x + 1)); + b = convertToInteger(s.substr(rangeseparator[0], y - rangeseparator[0] + 1)); + if (a == 0) + { + a = 1; + } + if (b == 0) + { + b = len; + } + if (a > b || a > len || b > len) + { + continue; + } + finalList.push_back(a - 1); + finalList.push_back(b - 1); + finalList.push_back(1); + } + else if (rangeseparator.size() == 2) // syntax of type [x:y:z] or x-y-z + { + a = convertToInteger(s.substr(x, rangeseparator[0] - x + 1)); + k = convertToInteger(s.substr(rangeseparator[0], rangeseparator[1] - rangeseparator[0] + 1)); + b = convertToInteger(s.substr(rangeseparator[1], y - rangeseparator[1] + 1)); + if (a == 0) + { + a = 1; + } + if (b == 0) + { + b = len; + } + if (k == 0) + { + k = 1; + } + if (a > b || a > len || b > len) + { + continue; + } + finalList.push_back(a - 1); + finalList.push_back(b - 1); + finalList.push_back(k); + } + } + return finalList; +} + diff --git a/Source/Processors/Editors/ChannelSelector.h b/Source/Processors/Editors/ChannelSelector.h index ad7bd399220ac3ee47901128944c664413506cc3..e4372826c2b51aad2c07c1d87a998591a7e7bfd5 100644 --- a/Source/Processors/Editors/ChannelSelector.h +++ b/Source/Processors/Editors/ChannelSelector.h @@ -1,25 +1,25 @@ /* - ------------------------------------------------------------------ - - 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/>. - - */ +------------------------------------------------------------------ + +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/>. + +*/ #ifndef __CHANNELSELECTOR_H_68124E35__ #define __CHANNELSELECTOR_H_68124E35__ @@ -34,248 +34,267 @@ class ChannelSelectorRegion; class ChannelSelectorButton; class EditorButton; +class ChannelSelectorBox; +class ShowAlertMessage; /** - - Automatically creates an interactive editor for selecting channels. - - Contains tabs for "Params", "Audio", and "Record", which allow - channels to be selected for different purposes. - - @see GenericEditor - - */ - - -class PLUGIN_API ChannelSelector : public Component - , public Button::Listener - , public Timer +Automatically creates an interactive editor for selecting channels. + +Contains tabs for "Params", "Audio", and "Record", which allow +channels to be selected for different purposes. + +@see GenericEditor + +*/ + + +class PLUGIN_API ChannelSelector : public Component, + public Button::Listener, + public Timer { public: + + /** constructor */ ChannelSelector(bool createButtons, Font& titleFont); + + /** destructor */ ~ChannelSelector(); /** button callback */ void buttonClicked(Button* button); - + /** Return an array of selected channels. */ Array<int> getActiveChannels(); - + /** Set the selected channels. */ void setActiveChannels(Array<int>); - + /** Set the total number of channels. */ void setNumChannels(int); - + /** get the total number of channels. */ int getNumChannels(); - + /** Return whether a particular channel should be recording. */ bool getRecordStatus(int chan); - + /** Return whether a particular channel should be monitored. */ bool getAudioStatus(int chan); - + /** Return whether a particular channel is selected for editing parameters. */ bool getParamStatus(int chan); - + /** Set whether a particular channel should be recording. */ void setRecordStatus(int, bool); - + /** Set whether a particular channel should be monitored. */ void setAudioStatus(int, bool); - + /** Sets all audio monitors to 'false' */ void clearAudio(); - + /** Set whether a particular channel is selected for editing parameters. */ void setParamStatus(int, bool); - + /** Return component's desired width. */ int getDesiredWidth(); - + /** Called prior to the start of data acquisition.*/ void startAcquisition(); - + /** Called immediately after data acquisition ends.*/ void stopAcquisition(); - + /** Inactivates all the ChannelSelectorButtons under the "param" tab.*/ void inactivateButtons(); - + /** Activates all the ChannelSelectorButtons under the "param" tab.*/ void activateButtons(); - + /** Inactivates all the ChannelSelectorButtons under the "rec" tab.*/ void inactivateRecButtons(); - + /** Activates all the ChannelSelectorButtons under the "rec" tab.*/ void activateRecButtons(); - + /** Refreshes Parameter Colors on change*/ void refreshParameterColors(); - + /** Controls the behavior of ChannelSelectorButtons; they can either behave - like radio buttons (only one selected at a time) or like toggle buttons (an - arbitrary number can be selected at once).*/ + like radio buttons (only one selected at a time) or like toggle buttons (an + arbitrary number can be selected at once).*/ void setRadioStatus(bool); - + void paramButtonsToggledByDefault(bool t); //void paramButtonsActiveByDefault(bool t) {paramsActive = t;} - + /** Used to scroll channels */ void shiftChannelsVertical(float amount); - + bool eventsOnly; - + private: - + EditorButton* audioButton; EditorButton* recordButton; EditorButton* paramsButton; EditorButton* allButton; EditorButton* noneButton; - + EditorButton* selectButtonParam; //Select Channels in parameter tab + EditorButton* deselectButtonParam; //Deselect Channels in parameter tab + EditorButton* selectButtonRecord; //Select Channels in record tab + EditorButton* deselectButtonRecord;//Deselect Channels in record tab + EditorButton* selectButtonAudio; //Select Channels in audio tab + EditorButton* deselectButtonAudio; //Deselect Channels in audio tab + /** An array of ChannelSelectorButtons used to select the channels that - will be updated when a parameter is changed. */ + will be updated when a parameter is changed. + paramBox: TextBox where user input is taken for param tab. + */ Array<ChannelSelectorButton*> parameterButtons; - + ChannelSelectorBox* paramBox; + /** An array of ChannelSelectorButtons used to select the channels that - are sent to the audio monitor. */ + are sent to the audio monitor. + audioBox: TextBox where user input is taken for audio tab + */ Array<ChannelSelectorButton*> audioButtons; - + ChannelSelectorBox* audioBox; + /** An array of ChannelSelectorButtons used to select the channels that - will be written to disk when the record button is pressed. */ + will be written to disk when the record button is pressed. + recordBox: TextBox where user input is taken for record tab + */ Array<ChannelSelectorButton*> recordButtons; + ChannelSelectorBox* recordBox; bool paramsToggled; bool paramsActive; bool recActive; bool radioStatus; - + bool isNotSink; bool moveRight; bool moveLeft; - + int offsetLR; float offsetUD; - + int numColumnsLessThan100; int numColumnsGreaterThan100; int overallHeight; - + int parameterOffset; int audioOffset; int recordOffset; - + int desiredOffset; - + void resized(); - + void addButton(); void removeButton(); void refreshButtonBoundaries(); - + /** Controls the speed of animations. */ void timerCallback(); - + /** Draws the ChannelSelector. */ void paint(Graphics& g); - + Font& titleFont; - - enum {AUDIO, RECORD, PARAMETER}; - + + enum { AUDIO, RECORD, PARAMETER }; + bool acquisitionIsActive; - + ChannelSelectorRegion* channelSelectorRegion; - + }; /** - - A button within the ChannelSelector that allows the user to switch - between tabs of all the channels. - - @see ChannelSelector - - */ + +A button within the ChannelSelector that allows the user to switch +between tabs of all the channels. + +@see ChannelSelector + +*/ class EditorButton : public Button { public: EditorButton(const String& name, Font& f); ~EditorButton(); - + bool getState(); - + void setState(bool state); - + private: void paintButton(Graphics& g, bool isMouseOver, bool isButtonDown); - + void resized(); - + Path outlinePath; - + int type; Font buttonFont; - + bool isEnabled; - + ColourGradient selectedGrad, selectedOverGrad, neutralGrad, neutralOverGrad; }; /** - - Holds the ChannelSelector buttons. - - @see ChannelSelector - - */ + +Holds the ChannelSelector buttons. + +@see ChannelSelector + +*/ class ChannelSelectorRegion : public Component { - public: ChannelSelectorRegion(ChannelSelector* cs); ~ChannelSelectorRegion(); - + /** Allows the user to scroll the channels if they are not all visible.*/ void mouseWheelMove(const MouseEvent& event, const MouseWheelDetails& wheel); void paint(Graphics& g); - + private: ChannelSelector* channelSelector; - + }; /** - - A button within the ChannelSelector representing an individual channel. - - @see ChannelSelector - - */ + +A button within the ChannelSelector representing an individual channel. + +@see ChannelSelector + +*/ class ChannelSelectorButton : public Button { public: ChannelSelectorButton(int num, int type, Font& f); ~ChannelSelectorButton(); - + int getType(); int getChannel(); //Channel* getChannel() {return ch;} void setActive(bool t); void setChannel(int n); void setChannel(int n, int d); - + private: void paintButton(Graphics& g, bool isMouseOver, bool isButtonDown); - + //Channel* ch; - + int type; int num; int displayNum; @@ -283,5 +302,18 @@ private: bool isActive; }; +/* + A textbox within the channelSelector to select multiple channels at a time. +*/ +class ChannelSelectorBox :public TextEditor +{ +public: + ChannelSelectorBox(); + ~ChannelSelectorBox(); + + + std::vector<int> getBoxInfo(int len); // Extract Information from the box. + int convertToInteger(std::string s); // Conversion of string to integer. +}; #endif // __CHANNELSELECTOR_H_68124E35__