Skip to content
Snippets Groups Projects
Commit 40b6a57b authored by Josh Siegle's avatar Josh Siegle
Browse files

Add GraphViewer optimizations from sept-en

parent bcc5ff0a
Branches
Tags
No related merge requests found
/*
------------------------------------------------------------------
This file is part of the Open Ephys GUI
Copyright (C) 2014 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 "GraphViewer.h"
#define PI 3.14159265359
static const Font FONT_LABEL ("Paragraph", 50, Font::plain);
static const Font FONT_VERSION ("Small Text", 14, Font::plain);
GraphViewer::GraphViewer()
{
labelFont = Font("Paragraph", 50, Font::plain);
JUCEApplication* app = JUCEApplication::getInstance();
currentVersionText = "GUI version " + app->getApplicationVersion();
rootNum = 0;
}
GraphViewer::~GraphViewer()
{
}
void GraphViewer::addNode(GenericEditor* editor)
{
GraphNode* gn = new GraphNode(editor, this);
addAndMakeVisible(gn);
availableNodes.add(gn);
gn->setBounds(20, 20, 150, 50);
void GraphViewer::addNode (GenericEditor* editor)
{
GraphNode* gn = new GraphNode (editor, this);
addAndMakeVisible (gn);
availableNodes.add (gn);
gn->setBounds (20, 20, 150, 50);
updateNodeLocations();
}
void GraphViewer::removeNode(GenericEditor* editor)
void GraphViewer::removeNode (GenericEditor* editor)
{
availableNodes.remove(indexOfEditor(editor));
availableNodes.remove (getIndexOfEditor (editor));
updateNodeLocations();
}
void GraphViewer::removeAllNodes()
{
availableNodes.clear();
updateNodeLocations();
}
// void GenericEditor::updateNodeName(GenericEditor* editor)
// {
// GraphNode* n = getNodeForEditor(editor);
// n->repaint();
// }
void GraphViewer::updateNodeLocations()
{
const int numAvailableNodes = availableNodes.size();
// If this was made just for future purpose it would be better to execute this only in debug mode
#if JUCE_DEBUG
// set the initial locations
for (int i = 0; i < availableNodes.size(); i++)
for (int i = 0; i < numAvailableNodes; ++i)
{
}
#endif
rootNum = 0;
// do initial layout
for (int i = 0; i < availableNodes.size(); i++)
for (int i = 0; i < numAvailableNodes; ++i)
{
checkLayout(availableNodes[i]);
checkLayout (availableNodes[i]);
}
// check for overlap
for (int i = 0; i < availableNodes.size(); i++)
for (int i = 0; i < numAvailableNodes; ++i)
{
for (int j = 0; j < availableNodes.size(); j++)
for (int j = 0; j < numAvailableNodes; ++j)
{
if (j != i)
{
if (availableNodes[j]->getLevel() == availableNodes[i]->getLevel() &&
availableNodes[j]->getHorzShift() == availableNodes[i]->getHorzShift())
if (availableNodes[j]->getLevel() == availableNodes[i]->getLevel()
&& availableNodes[j]->getHorzShift() == availableNodes[i]->getHorzShift())
{
availableNodes[j]->setHorzShift(availableNodes[j]->getHorzShift()+1);
availableNodes[j]->setHorzShift (availableNodes[j]->getHorzShift() + 1);
}
}
}
}
repaint();
}
void GraphViewer::checkLayout(GraphNode* gn)
{
void GraphViewer::checkLayout (GraphNode* gn)
{
if (gn != nullptr)
{
GraphNode* sourceNode;
GraphNode* sourceNode = nullptr;
if (gn->isMerger())
{
Array<GenericEditor*> editors = gn->getConnectedEditors();
int level1 = 0;
int level2 = 0;
if (editors[0] != nullptr)
{
level1 = getNodeForEditor(editors[0])->getLevel();
level1 = getNodeForEditor (editors[0])->getLevel();
}
if (editors[1] != nullptr)
{
level2 = getNodeForEditor(editors[1])->getLevel();
level2 = getNodeForEditor (editors[1])->getLevel();
}
// std::cout << "LEVEL1 = " << level1 << " LEVEL2 = " << level2 << std::endl;
sourceNode = level1 > level2 ? getNodeForEditor(editors[0]) :
getNodeForEditor(editors[1]); // choose the higher source
sourceNode = level1 > level2 ? getNodeForEditor (editors[0])
: getNodeForEditor (editors[1]); // choose the higher source
}
else
{
sourceNode = getNodeForEditor(gn->getSource());
sourceNode = getNodeForEditor (gn->getSource());
}
if (sourceNode == nullptr)
if (! sourceNode)
{
gn->setLevel(0);
gn->setHorzShift(rootNum);
rootNum++;
gn->setLevel (0);
gn->setHorzShift (rootNum);
++rootNum;
}
else if (sourceNode->isSplitter())
{
Array<GenericEditor*> editors = sourceNode->getConnectedEditors();
if (gn->hasEditor(editors[1]))
{
gn->setLevel(sourceNode->getLevel()+1); // increase level
gn->setHorzShift(sourceNode->getHorzShift()+1); // increase horz shift
}
else
{
gn->setLevel(sourceNode->getLevel()+1); // increase level
gn->setHorzShift(sourceNode->getHorzShift()); // same horz shift
}
const int newHorizontalShift = gn->hasEditor (editors[1])
? sourceNode->getHorzShift() + 1
: sourceNode->getHorzShift();
// increase level
gn->setLevel (sourceNode->getLevel() + 1);
// increase horizontal shift
gn->setHorzShift (newHorizontalShift);
}
else
{
gn->setLevel(sourceNode->getLevel()+1); // increase level
gn->setHorzShift(sourceNode->getHorzShift()); // same horz shift
// increase level
gn->setLevel (sourceNode->getLevel() + 1);
// use the same horizontal shift
gn->setHorzShift (sourceNode->getHorzShift());
}
checkLayout(getNodeForEditor(gn->getDest()));
checkLayout (getNodeForEditor (gn->getDest()));
}
}
int GraphViewer::indexOfEditor(GenericEditor* editor)
int GraphViewer::getIndexOfEditor (GenericEditor* editor) const
{
int index = -1;
for (int i = 0; i < availableNodes.size(); i++)
const int numAvailableNodes = availableNodes.size();
for (int i = 0; i < numAvailableNodes; ++i)
{
if (availableNodes[i]->hasEditor(editor))
if (availableNodes[i]->hasEditor (editor))
{
return i;
}
}
return index;
}
GraphNode* GraphViewer::getNodeForEditor(GenericEditor* editor)
{
int index = indexOfEditor(editor);
if (index > -1)
return availableNodes[index];
GraphNode* GraphViewer::getNodeForEditor (GenericEditor* editor) const
{
int indexOfEditor = getIndexOfEditor (editor);
if (indexOfEditor > -1)
return availableNodes[indexOfEditor];
else
return nullptr;
}
int GraphViewer::nodesAtLevel(int level)
{
int numNodes=0;
for (int i = 0; i < availableNodes.size(); i++)
int GraphViewer::nodesAtLevel (int level) const
{
int numNodes = 0;
for (auto& node : availableNodes)
{
if (availableNodes[i]->getLevel() == numNodes)
{
numNodes++;
}
// Level value is not used.
// It seems we should check if current level of each node is equal to the passed as param level
// TODO : research this question and either delete this comment or fix the bug
if (node->getLevel() == numNodes)
++numNodes;
}
return numNodes;
}
int GraphViewer::getHorizontalShift(GraphNode* gn)
int GraphViewer::getHorizontalShift (GraphNode* gn) const
{
int shift = 0;
for (int i = 0; i < availableNodes.size(); i++)
for (auto& node : availableNodes)
{
if (availableNodes[i] == gn)
{
if (node == gn)
break;
}
else
{
if (availableNodes[i]->getLevel() == gn->getLevel())
{
shift++;
}
}
if (node->getLevel() == gn->getLevel())
++shift;
}
return shift;
}
void GraphViewer::paint(Graphics& g)
{
g.fillAll(Colours::darkgrey);
g.setFont(labelFont);
g.setFont(50);
g.setColour(Colours::grey);
JUCEApplication* app = JUCEApplication::getInstance();
String text = "GUI version ";
text += app->getApplicationVersion();
g.drawFittedText("open ephys", 40, 40, getWidth()-50, getHeight()-60, Justification::bottomRight, 100);
g.setFont(Font("Small Text", 14, Font::plain));
g.drawFittedText(text, 40, 40, getWidth()-50, getHeight()-45, Justification::bottomRight, 100);
// draw connections
for (int i = 0; i < availableNodes.size(); i++)
void GraphViewer::paint (Graphics& g)
{
g.fillAll (Colours::darkgrey);
g.setFont (FONT_LABEL);
g.setColour (Colours::grey);
g.drawFittedText ("open ephys", 40, 40, getWidth()-50, getHeight()-60, Justification::bottomRight, 100);
g.setFont (FONT_VERSION);
g.drawFittedText (currentVersionText, 40, 40, getWidth()-50, getHeight()-45, Justification::bottomRight, 100);
// Draw connections
const int numAvailableNodes = availableNodes.size();
for (int i = 0; i < numAvailableNodes; ++i)
{
if (!availableNodes[i]->isSplitter())
if (! availableNodes[i]->isSplitter())
{
if (availableNodes[i]->getDest() != nullptr)
{
int indexOfDest = indexOfEditor(availableNodes[i]->getDest());
int indexOfDest = getIndexOfEditor (availableNodes[i]->getDest());
if (indexOfDest > -1)
connectNodes(i, indexOfDest, g);
connectNodes (i, indexOfDest, g);
}
}
else
{
Array<GenericEditor*> editors = availableNodes[i]->getConnectedEditors();
for (int path = 0; path < 2; path++)
for (int path = 0; path < 2; ++path)
{
int indexOfDest = indexOfEditor(editors[path]);
int indexOfDest = getIndexOfEditor (editors[path]);
if (indexOfDest > -1)
connectNodes(i, indexOfDest, g);
connectNodes (i, indexOfDest, g);
}
}
}
}
void GraphViewer::connectNodes(int node1, int node2, Graphics& g)
{
Point<float> start = availableNodes[node1]->getCenterPoint();
Point<float> end = availableNodes[node2]->getCenterPoint();
void GraphViewer::connectNodes (int node1, int node2, Graphics& g)
{
Point<float> start = availableNodes[node1]->getCenterPoint();
Point<float> end = availableNodes[node2]->getCenterPoint();
Path linePath;
float x1 = start.getX();
float y1 = start.getY();
float x2 = end.getX();
float y2 = end.getY();
linePath.startNewSubPath(x1, y1);
linePath.cubicTo(x1, y1 + (y2 - y1) * 0.9f,
x2, y1 + (y2 - y1) * 0.1f,
x2, y2);
PathStrokeType stroke(2.0f);
g.strokePath(linePath, stroke);
linePath.startNewSubPath (x1, y1);
linePath.cubicTo (x1, y1 + (y2 - y1) * 0.9f,
x2, y1 + (y2 - y1) * 0.1f,
x2, y2);
PathStrokeType stroke (2.0f);
g.strokePath (linePath, stroke);
}
/// ------------------------------------------------------
GraphNode::GraphNode(GenericEditor* ed, GraphViewer* g)
GraphNode::GraphNode (GenericEditor* ed, GraphViewer* g)
: editor (ed)
, gv (g)
, isMouseOver (false)
{
editor = ed;
mouseOver = false;
labelFont = Font("Paragraph", 14, Font::plain);
gv = g;
}
GraphNode::~GraphNode()
{
}
int GraphNode::getLevel()
int GraphNode::getLevel() const
{
// int level = -1;
// GenericEditor* ed = editor;
// while (ed != nullptr)
// {
// level += 1;
// ed = ed->getSourceEditor();
// }
return vertShift;
}
void GraphNode::setLevel(int level)
{
setBounds(getX(), 20+level*40, getWidth(), getHeight());
void GraphNode::setLevel (int level)
{
setBounds (getX(), 20 + level * 40, getWidth(), getHeight());
vertShift = level;
}
int GraphNode::getHorzShift()
int GraphNode::getHorzShift() const
{
return horzShift; //gv->getHorizontalShift(this);
}
void GraphNode::setHorzShift(int shift)
void GraphNode::setHorzShift (int shift)
{
setBounds(20+shift*140, getY(), getWidth(), getHeight());
setBounds (20 + shift * 140, getY(), getWidth(), getHeight());
horzShift = shift;
}
void GraphNode::mouseEnter(const MouseEvent& m)
void GraphNode::mouseEnter (const MouseEvent& m)
{
mouseOver = true;
isMouseOver = true;
repaint();
}
void GraphNode::mouseExit(const MouseEvent& m)
void GraphNode::mouseExit (const MouseEvent& m)
{
mouseOver = false;
isMouseOver = false;
repaint();
}
void GraphNode::mouseDown(const MouseEvent& m)
void GraphNode::mouseDown (const MouseEvent& m)
{
editor->makeVisible();
}
bool GraphNode::hasEditor(GenericEditor* ed)
bool GraphNode::hasEditor (GenericEditor* ed) const
{
if (ed == editor)
return true;
......@@ -388,89 +392,86 @@ bool GraphNode::hasEditor(GenericEditor* ed)
return false;
}
bool GraphNode::isSplitter()
bool GraphNode::isSplitter() const
{
return editor->isSplitter();
}
bool GraphNode::isMerger()
bool GraphNode::isMerger() const
{
return editor->isMerger();
}
GenericEditor* GraphNode::getDest()
GenericEditor* GraphNode::getDest() const
{
return editor->getDestEditor();
}
GenericEditor* GraphNode::getSource()
GenericEditor* GraphNode::getSource() const
{
return editor->getSourceEditor();
}
Array<GenericEditor*> GraphNode::getConnectedEditors()
Array<GenericEditor*> GraphNode::getConnectedEditors() const
{
return editor->getConnectedEditors();
}
const String GraphNode::getName()
const String GraphNode::getName() const
{
return editor->getDisplayName();
}
Point<float> GraphNode::getCenterPoint()
{
Point<float> center = Point<float>(getX()+10, getY()+10);
Point<float> GraphNode::getCenterPoint() const
{
Point<float> center = Point<float> (getX() + 10, getY() + 10);
return center;
}
void GraphNode::switchIO(int path)
{
void GraphNode::switchIO (int path)
{
}
void GraphNode::updateBoundaries()
{
int horzShift = gv->getHorizontalShift(this);
setBounds(20+horzShift*140, 20+getLevel()*40, 150, 50);
int horzShift = gv->getHorizontalShift (this);
setBounds (20 + horzShift * 140, 20 + getLevel() * 40, 150, 50);
}
void GraphNode::paint(Graphics& g)
{
void GraphNode::paint (Graphics& g)
{
Array<bool> recordStatuses = editor->getRecordStatusArray();
Path recordPath;
for (int i = 0; i < recordStatuses.size(); i++)
const int numRecordStatuses = recordStatuses.size();
for (int i = 0; i < numRecordStatuses; ++i)
{
float stepSize = 2*PI/recordStatuses.size();
float startRadians = stepSize*i;
float endRadians = startRadians + stepSize;
float stepSize = 2 * float_Pi / numRecordStatuses;
float startRadians = stepSize * i;
float endRadians = startRadians + stepSize;
if (recordStatuses[i])
recordPath.addPieSegment(0,0,20,20,startRadians,endRadians,0.5);
recordPath.addPieSegment (0, 0, 20, 20, startRadians, endRadians, 0.5);
}
g.setColour(Colours::red);
g.fillPath(recordPath);
if (mouseOver)
{
g.setColour(Colours::yellow);
g.fillEllipse(2,2,16,16);
}
else
{
g.setColour(editor->getBackgroundColor());
g.fillEllipse(2,2,16,16);
}
g.drawText(getName(), 25, 0, getWidth()-25, 20, Justification::left, true);
g.setColour (Colours::red);
g.fillPath (recordPath);
g.setColour (isMouseOver ? Colours::yellow : editor->getBackgroundColor());
g.fillEllipse (2, 2, 16, 16);
g.drawText (getName(), 25, 0, getWidth() - 25, 20, Justification::left, true);
}
/*
------------------------------------------------------------------
This file is part of the Open Ephys GUI
Copyright (C) 2014 Open Ephys
Copyright (C) 2016 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 __GRAPHVIEWER_H_4E971BF9__
......@@ -30,60 +30,57 @@
#include "../../JuceLibraryCode/JuceHeader.h"
/**
Displays the full processor graph for a given session.
Inhabits a tab in the DataViewport.
@see UIComponent, DataViewport, ProcessorGraph, EditorViewport
*/
class GraphNode : public Component
{
public:
GraphNode(GenericEditor* editor, GraphViewer* g);
GraphNode (GenericEditor* editor, GraphViewer* g);
~GraphNode();
void mouseEnter(const MouseEvent& m);
void mouseExit(const MouseEvent& m);
void mouseDown(const MouseEvent& m);
bool hasEditor(GenericEditor* editor);
void paint(Graphics& g);
void paint (Graphics& g) override;
void mouseEnter (const MouseEvent& event) override;
void mouseExit (const MouseEvent& event) override;
void mouseDown (const MouseEvent& event) override;
bool hasEditor (GenericEditor* editor) const;
Point<float> getCenterPoint() const;
GenericEditor* getDest() const;
GenericEditor* getSource() const;
Array<GenericEditor*> getConnectedEditors() const;
bool isSplitter() const;
bool isMerger() const;
const String getName() const;
int getLevel() const;
int getHorzShift() const;
void setLevel (int newLevel);
void setHorzShift (int newHorizontalShift);
void updateBoundaries();
Point<float> getCenterPoint();
GenericEditor* getDest();
GenericEditor* getSource();
Array<GenericEditor*> getConnectedEditors();
void switchIO(int path);
bool isSplitter();
bool isMerger();
const String getName();
int getLevel();
void setLevel(int);
int getHorzShift();
void setHorzShift(int);
void switchIO (int path);
int horzShift;
int vertShift;
private:
GenericEditor* editor;
Font labelFont;
bool mouseOver;
GraphViewer* gv;
bool isMouseOver;
};
......@@ -92,34 +89,33 @@ class GraphViewer : public Component
public:
GraphViewer();
~GraphViewer();
/** Draws the GraphViewer.*/
void paint(Graphics& g);
void addNode(GenericEditor* editor);
void removeNode(GenericEditor* editor);
void paint (Graphics& g) override;
void addNode (GenericEditor* editor);
void removeNode (GenericEditor* editor);
void removeAllNodes();
void updateNodeLocations();
int nodesAtLevel(int lvl);
int getHorizontalShift(GraphNode*);
GraphNode* getNodeForEditor(GenericEditor* editor);
int nodesAtLevel (int lvl) const;
int getHorizontalShift (GraphNode*) const;
GraphNode* getNodeForEditor (GenericEditor* editor) const;
private:
void connectNodes(int, int, Graphics&);
void checkLayout(GraphNode*);
int indexOfEditor(GenericEditor* editor);
Font labelFont;
void connectNodes (int, int, Graphics&);
void checkLayout (GraphNode*);
int getIndexOfEditor (GenericEditor* editor) const;
int rootNum;
String currentVersionText;
OwnedArray<GraphNode> availableNodes;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(GraphViewer);
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (GraphViewer);
};
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment