Skip to content
Snippets Groups Projects
ProcessorList.cpp 16.60 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 "ProcessorList.h"
#include <stdio.h>

#include "UIComponent.h"

enum colorIds
{
    PROCESSOR_COLOR = 801,
    FILTER_COLOR = 802,
    SINK_COLOR = 803,
    SOURCE_COLOR = 804,
    UTILITY_COLOR = 805,
};

ProcessorList::ProcessorList()
    : isDragging(false), totalHeight(800), itemHeight(32), subItemHeight(22),
      xBuffer(1), yBuffer(1)
{

    listFontLight = Font("Default Light", 25, Font::plain);
    listFontPlain = Font("Default", 20, Font::plain);

    // MemoryInputStream mis1(BinaryData::cpmonolightserialized,
    //                        BinaryData::cpmonolightserializedSize,
    //                        false);
    // Typeface::Ptr tp1 = new CustomTypeface(mis1);
    // listFontLight = Font(tp1);
    // listFontLight.setHeight(25);

    // MemoryInputStream mis2(BinaryData::cpmonoplainserialized,
    //                        BinaryData::cpmonoplainserializedSize,
    //                        false);
    // Typeface::Ptr tp2 = new CustomTypeface(mis2);
    // listFontPlain = Font(tp2);
    // listFontPlain.setHeight(20);

    setColour(PROCESSOR_COLOR, Colour(59, 59, 59));
    setColour(FILTER_COLOR, Colour(41, 76, 158));//Colour(255, 89, 0));
    setColour(SINK_COLOR, Colour(93, 125, 199));//Colour(255, 149, 0));
    setColour(SOURCE_COLOR, Colour(48, 67, 112)); //Colour(255, 0, 0));
    setColour(UTILITY_COLOR, Colour(90, 80, 80));

    ProcessorListItem* sources = new ProcessorListItem("Sources");
    sources->addSubItem(new ProcessorListItem("RHA2000-EVAL"));
    //sources->addSubItem(new ProcessorListItem("Signal Generator"));
    //sources->addSubItem(new ProcessorListItem("Custom FPGA"));
    sources->addSubItem(new ProcessorListItem("Rhythm FPGA"));
    sources->addSubItem(new ProcessorListItem("File Reader"));
    //sources->addSubItem(new ProcessorListItem("Event Generator"));

    ProcessorListItem* filters = new ProcessorListItem("Filters");
    filters->addSubItem(new ProcessorListItem("Bandpass Filter"));
    //filters->addSubItem(new ProcessorListItem("Event Detector"));
    filters->addSubItem(new ProcessorListItem("Spike Detector"));
    //filters->addSubItem(new ProcessorListItem("Resampler"));
    filters->addSubItem(new ProcessorListItem("Phase Detector"));
    filters->addSubItem(new ProcessorListItem("Digital Ref"));

    ProcessorListItem* sinks = new ProcessorListItem("Sinks");
    sinks->addSubItem(new ProcessorListItem("LFP Viewer"));
    sinks->addSubItem(new ProcessorListItem("Spike Viewer"));
    //sinks->addSubItem(new ProcessorListItem("WiFi Output"));
    //sinks->addSubItem(new ProcessorListItem("Arduino Output"));
   // sinks->addSubItem(new ProcessorListItem("FPGA Output"));
    sinks->addSubItem(new ProcessorListItem("Pulse Pal"));

    ProcessorListItem* utilities = new ProcessorListItem("Utilities");
    utilities->addSubItem(new ProcessorListItem("Splitter"));
    utilities->addSubItem(new ProcessorListItem("Merger"));
    utilities->addSubItem(new ProcessorListItem("Record Control"));

    baseItem = new ProcessorListItem("Processors");
    baseItem->addSubItem(sources);
    baseItem->addSubItem(filters);
    baseItem->addSubItem(sinks);
    baseItem->addSubItem(utilities);

    // set parent names / colors
    baseItem->setParentName("Processors");

    for (int n = 0; n < baseItem->getNumSubItems(); n++)
    {

        const String category = baseItem->getSubItem(n)->getName();
        baseItem->getSubItem(n)->setParentName(category);

        for (int m = 0; m < baseItem->getSubItem(n)->getNumSubItems(); m++)
        {

            baseItem->getSubItem(n)->getSubItem(m)->setParentName(category);// = category;

        }

    }

}

ProcessorList::~ProcessorList()
{

}

bool ProcessorList::isOpen()
{
    return baseItem->isOpen();
}

void ProcessorList::paintCanvas(Graphics& g)
{

    drawItems(g);

    ///drawButton(g, true);

}

void ProcessorList::drawItems(Graphics& g)
{
    totalHeight = yBuffer;

    category = baseItem->getName();

    drawItem(g, baseItem);

    if (baseItem->isOpen())
    {
        for (int n = 0; n < baseItem->getNumSubItems(); n++)
        {
            setViewport(g, baseItem->hasSubItems());
            category = baseItem->getSubItem(n)->getName();
            drawItem(g, baseItem->getSubItem(n));

            if (baseItem->getSubItem(n)->isOpen())
            {
                for (int m = 0; m < baseItem->getSubItem(n)->getNumSubItems(); m++)
                {

                    setViewport(g, baseItem->
                                getSubItem(n)->
                                getSubItem(m)->
                                hasSubItems());
                    drawItem(g, baseItem->getSubItem(n)->getSubItem(m));

                }
            }
        }
    }

}

void ProcessorList::drawItem(Graphics& g, ProcessorListItem* item)
{

    Colour c = findColour(item->colorId);

    g.setColour(c);

    if (item->hasSubItems())
        g.fillRect(1.0, 0.0, getWidth()-2, itemHeight);
    else
        g.fillRect(1.0, 10.0, getWidth()-2, subItemHeight);

    drawItemName(g,item);

    if (item->hasSubItems())
    {
        drawButton(g, item->isOpen());
    }
}

void ProcessorList::drawItemName(Graphics& g, ProcessorListItem* item)
{

    String name;

    g.setColour(Colours::white);
    g.setFont(listFontPlain);

    float offsetX, offsetY;

    if (item->getNumSubItems() == 0)
    {
        if (item->isSelected())
        {
            g.drawText(">", 5, 5, getWidth()-9, itemHeight, Justification::left, false);
            // glRasterPos2f(9.0/getWidth(),0.72);
            // getFont(cpmono_plain)->FaceSize(15);
            // getFont(cpmono_plain)->Render(">");
        }

        name = item->getName();

        offsetX = 20.0f;

        offsetY = 0.72f;
    }
    else
    {
        name = item->getName().toUpperCase();
        offsetX = 5.0f;
        offsetY = 0.75f;
    }

    if (item->getNumSubItems() == 0)
    {
        g.setFont(listFontPlain);
        g.drawText(name, offsetX, 5, getWidth()-offsetX, itemHeight, Justification::left, false);

    }
    else
    {
        g.setFont(listFontLight);
        g.drawText(name, offsetX, 0, getWidth()-offsetX, itemHeight, Justification::left, false);
    }


}

void ProcessorList::drawButton(Graphics& g, bool isOpen)
{



    // glColor4f(1.0f,1.0f,1.0f,1.0f);
    // glLineWidth(1.0f);
    // glBegin(GL_LINE_LOOP);

    // if (isOpen)
    // {
    // 	glVertex2f(0.875,0.35);
    // 	glVertex2f(0.9,0.65);
    // } else {
    // 	glVertex2f(0.925,0.65);
    // 	glVertex2f(0.875,0.5);
    // }
    // glVertex2f(0.925,0.35);
    // glEnd();

}

void ProcessorList::clearSelectionState()
{
    baseItem->setSelected(false);

    for (int n = 0; n < baseItem->getNumSubItems(); n++)
    {
        baseItem->getSubItem(n)->setSelected(false);

        for (int m = 0; m < baseItem->getSubItem(n)->getNumSubItems(); m++)
        {
            baseItem->getSubItem(n)->getSubItem(m)->setSelected(false);
        }
    }
}
ProcessorListItem* ProcessorList::getListItemForYPos(int y)
{
    int bottom = (yBuffer + itemHeight) - getScrollAmount();

    //std::cout << "Bottom: " << bottom << std::endl;
    //std::cout << "Y coordinate: " << y << std::endl;

    if (y < bottom)
    {
        return baseItem;

    }
    else
    {

        if (baseItem->isOpen())
        {
            for (int n = 0; n < baseItem->getNumSubItems(); n++)
            {
                bottom += (yBuffer + itemHeight);

                if (y < bottom)
                {
                    return baseItem->getSubItem(n);
                }

                if (baseItem->getSubItem(n)->isOpen())
                {
                    for (int m = 0; m < baseItem->getSubItem(n)->getNumSubItems(); m++)
                    {
                        bottom += (yBuffer + subItemHeight);

                        if (y < bottom)
                        {
                            return baseItem->getSubItem(n)->getSubItem(m);
                        }

                    }
                }
            }
        }

    }

    return 0;

}

void ProcessorList::setViewport(Graphics& g, bool hasSubItems)
{

    int height;

    if (hasSubItems)
    {
        height = itemHeight;
    }
    else
    {
        height = subItemHeight;
    }

    g.setOrigin(0, yBuffer + height); //xBuffer, getHeight()-(totalHeight) - height + getScrollAmount());


    totalHeight += yBuffer + height;

    //std::cout << totalHeight << std::endl;
}
int ProcessorList::getTotalHeight()
{
    return totalHeight;
}

void ProcessorList::toggleState()
{
    ProcessorListItem* fli = getListItemForYPos(0);
    fli->reverseOpenState();
    getUIComponent()->childComponentChanged();
    repaint();
}

void ProcessorList::mouseDownInCanvas(const MouseEvent& e)
{

    isDragging = false;

    Point<int> pos = e.getPosition();
    int xcoord = pos.getX();
    int ycoord = pos.getY();

    //std::cout << xcoord << " " << ycoord << std::endl;

    ProcessorListItem* fli = getListItemForYPos(ycoord);

    if (fli != 0)
    {
        //std::cout << "Selecting: " << fli->getName() << std::endl;
        if (!fli->hasSubItems())
        {
            clearSelectionState();
            fli->setSelected(true);
        }

    }
    else
    {
        //std::cout << "No selection." << std::endl;
    }

    if (fli != 0)
    {
        if (xcoord < getWidth() - getScrollBarWidth())
        {
            if (e.mods.isRightButtonDown() || e.mods.isCtrlDown())
            {

                if (fli->getName().equalsIgnoreCase("Sources"))
                {
                    currentColor = SOURCE_COLOR;
                }
                else if (fli->getName().equalsIgnoreCase("Filters"))
                {
                    currentColor = FILTER_COLOR;
                }
                else if (fli->getName().equalsIgnoreCase("Utilities"))
                {
                    currentColor = UTILITY_COLOR;
                }
                else if (fli->getName().equalsIgnoreCase("Sinks"))
                {
                    currentColor = SINK_COLOR;
                }
                else
                {
                    return;
                }

                int options=0;
                options += (0 << 0); // showAlpha
                options += (0 << 1); // showColorAtTop
                options += (0 << 2); // showSliders
                options += (1 << 3); // showColourSpace

                ColourSelector colourSelector(options);
                colourSelector.setName("background");
                colourSelector.setCurrentColour(findColour(currentColor));
                colourSelector.addChangeListener(this);
                colourSelector.addChangeListener(getProcessorGraph());
                colourSelector.setColour(ColourSelector::backgroundColourId, Colours::transparentBlack);
                colourSelector.setSize(300, 275);

                Rectangle<int> rect = Rectangle<int>(0,0,10,10);

                CallOutBox callOut(colourSelector, rect, nullptr);
                callOut.setTopLeftPosition(e.getScreenX(), e.getScreenY());
                callOut.setArrowSize(0.0f);

                callOut.runModalLoop();

            }
            else
            {
                fli->reverseOpenState();
            }
        }

        if (fli == baseItem)
        {
            if (fli->isOpen())
            {
                getUIComponent()->childComponentChanged();
            }
            else
            {
                getUIComponent()->childComponentChanged();
                totalHeight = itemHeight + 2*yBuffer;
            }

        }
    }

    repaint();
}

void ProcessorList::changeListenerCallback(ChangeBroadcaster* source)
{
    ColourSelector* cs = dynamic_cast <ColourSelector*>(source);

    setColour(currentColor, cs->getCurrentColour());

    repaint();

}

void ProcessorList::mouseDragInCanvas(const MouseEvent& e)
{

    if (e.getMouseDownX() < getWidth()-getScrollBarWidth() && !(isDragging))
    {

        ProcessorListItem* fli = getListItemForYPos(e.getMouseDownY());

        if (fli != 0)
        {

            if (!fli->hasSubItems())
            {
                isDragging = true;

                String b = fli->getParentName();
                b += "/";
                b += fli->getName();

                const String dragDescription = b;

                //std::cout << dragDescription << std::endl;

                if (dragDescription.isNotEmpty())
                {
                    DragAndDropContainer* const dragContainer
                    = DragAndDropContainer::findParentDragContainerFor(this);

                    if (dragContainer != 0)
                    {
                        //pos.setSize (pos.getWidth(), 10);

                        Image dragImage(Image::ARGB, 100, 15, true);

                        Graphics g(dragImage);
                        g.setColour(findColour(fli->colorId));
                        g.fillAll();
                        g.setColour(Colours::white);
                        g.setFont(14);
                        g.drawSingleLineText(fli->getName(),10,12);//,75,15,Justification::centredRight,true);

                        dragImage.multiplyAllAlphas(0.6f);

                        Point<int> imageOffset(20,10);
                        dragContainer->startDragging(dragDescription, this,
                                                     dragImage, true, &imageOffset);
                    }
                }
            }
        }
    }

}

ProcessorListItem::ProcessorListItem(const String& name_)
    : selected(false), open(true), name(name_)
{
}

ProcessorListItem::~ProcessorListItem()
{ }

bool ProcessorListItem::hasSubItems()
{
    if (subItems.size() > 0)
    {
        return true;
    }
    else
    {
        return false;
    }
}

int ProcessorListItem::getNumSubItems()
{
    return subItems.size();
}

ProcessorListItem* ProcessorListItem::getSubItem(int index)
{
    return subItems[index];
}
void ProcessorListItem::clearSubItems()
{
    subItems.clear();
}

void ProcessorListItem::addSubItem(ProcessorListItem* newItem)
{
    subItems.add(newItem);
}

void ProcessorListItem::removeSubItem(int index)
{
    subItems.remove(index);
}

bool ProcessorListItem::isOpen()
{
    return open;
}

void ProcessorListItem::setOpen(bool t)
{
    open = t;
}

const String& ProcessorListItem::getName()
{
    return name;
}


const String& ProcessorListItem::getParentName()
{
    return parentName;
}

void ProcessorListItem::setParentName(const String& name)
{
    parentName = name;

    if (parentName.equalsIgnoreCase("Processors"))
    {
        colorId = PROCESSOR_COLOR;
    }
    else if (parentName.equalsIgnoreCase("Filters"))
    {
        colorId = FILTER_COLOR;
    }
    else if (parentName.equalsIgnoreCase("Sinks"))
    {
        colorId = SINK_COLOR;
    }
    else if (parentName.equalsIgnoreCase("Sources"))
    {
        colorId = SOURCE_COLOR;
    }
    else
    {
        colorId = UTILITY_COLOR;
    }
}

// Blue slate:
// if (parentName.equalsIgnoreCase("Processors"))
// {
// 	color = Colour(59, 59, 59);
// } else if (parentName.equalsIgnoreCase("Filters"))
// {
// 	color = Colour(82, 101, 163);
// } else if (parentName.equalsIgnoreCase("Sinks"))
// {
// 	color = Colour(48, 61, 102);
// } else if (parentName.equalsIgnoreCase("Sources"))
// {
// 	color = Colour(151, 170, 230);

// } else {
// 	color = Colour(20, 37, 92);
// }