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

UIComponent::UIComponent(MainWindow* mainWindow_, ProcessorGraph* pgraph, AudioComponent* audio_)
    : mainWindow(mainWindow_), processorGraph(pgraph), audio(audio_)

{

    processorGraph->setUIComponent(this);

    infoLabel = new InfoLabel();
    std::cout << "Created info label." << std::endl;

    graphViewer = new GraphViewer();
    std::cout << "Created graph viewer." << std::endl;

    dataViewport = new DataViewport();
    addChildComponent(dataViewport);
    dataViewport->addTabToDataViewport("Info", infoLabel,0);
    dataViewport->addTabToDataViewport("Graph", graphViewer,0);

    std::cout << "Created data viewport." << std::endl;

    editorViewport = new EditorViewport();

    addAndMakeVisible(editorViewport);

    std::cout << "Created filter viewport." << std::endl;

    editorViewportButton = new EditorViewportButton(this);
    addAndMakeVisible(editorViewportButton);

    controlPanel = new ControlPanel(processorGraph, audio);
    addAndMakeVisible(controlPanel);

    std::cout << "Created control panel." << std::endl;

    processorList = new ProcessorList();
    addAndMakeVisible(processorList);

    std::cout << "Created filter list." << std::endl;

    messageCenter = new MessageCenter();
    addActionListener(messageCenter);
    addAndMakeVisible(messageCenter);

    std::cout << "Created message center." << std::endl;

    setBounds(0,0,500,400);

   // std::cout << "Component width = " << getWidth() << std::endl;
  //  std::cout << "Component height = " << getHeight() << std::endl;

   // std::cout << "UI component data viewport: " << dataViewport << std::endl;

   // std::cout << "Finished UI stuff." << std::endl << std::endl << std::endl;

    processorGraph->setUIComponent(this);
    
    processorList->setUIComponent(this);
    editorViewport->setUIComponent(this);
    dataViewport->setUIComponent(this);
    controlPanel->getAudioEditor()->setUIComponent(this);
    controlPanel->setUIComponent(this);
    
    processorGraph->updatePointers(); // needs to happen after processorGraph gets the right pointers

    //processorGraph->sendActionMessage("Test.");

    //processorGraph->loadState();

#if JUCE_MAC
    MenuBarModel::setMacMainMenu(this);
    mainWindow->setMenuBar(0);
#else
    mainWindow->setMenuBar(this);
#endif

    //getEditorViewport()->loadState(File("/home/jsiegle/Programming/GUI/Builds/Linux/build/test.xml"));
    
    //Check and see where file is being executed
    //File executable = File::getSpecialLocation(File::currentExecutableFile);
    //const String executableDirectory = executable.getParentDirectory().getFullPathName();
    //sendActionMessage(executableDirectory);

}

UIComponent::~UIComponent()
{
    dataViewport->destroyTab(0); // get rid of tab for InfoLabel
}

void UIComponent::resized()
{

    int w = getWidth();
    int h = getHeight();

    if (editorViewportButton != 0)
    {
        editorViewportButton->setBounds(w-230, h-40, 225, 35);

        if (h < 300 && editorViewportButton->isOpen())
            editorViewportButton->toggleState();

        if (h < 200)
            editorViewportButton->setBounds(w-230,h-40+200-h,225,35);
        //else
        //    editorViewportButton->setVisible(true);
    }

    if (editorViewport != 0)
    {
        //if (h < 400)
        //    editorViewport->setVisible(false);
        //else
        //    editorViewport->setVisible(true);

        if (editorViewportButton->isOpen() && !editorViewport->isVisible())
            editorViewport->setVisible(true);
        else if (!editorViewportButton->isOpen() && editorViewport->isVisible())
            editorViewport->setVisible(false);

        editorViewport->setBounds(6,h-190,w-11,150);

        
    }

    if (controlPanel != 0)
    {

        int controlPanelWidth = w-210;
        int addHeight = 0;
        int leftBound;

        if (w >= 460){
            leftBound = 202;
        }
        else {
            leftBound = w-258;
            controlPanelWidth = w-leftBound;
        }

        if (controlPanelWidth < 750)
        {
            addHeight = 750-controlPanelWidth;

            if (addHeight > 32)
                addHeight = 32;
        }

        if (controlPanelWidth < 570)
        {
            addHeight = 32 + 570-controlPanelWidth;

            if (addHeight > 64)
                addHeight = 64;
        }

        if (controlPanel->isOpen())
            controlPanel->setBounds(leftBound,6,controlPanelWidth,64+addHeight);
        else
            controlPanel->setBounds(leftBound,6,controlPanelWidth,32+addHeight);
    }

    if (processorList != 0)
    {
        if (processorList->isOpen())
            if (editorViewportButton->isOpen())
                processorList->setBounds(5,5,195,h-200);
            else
                processorList->setBounds(5,5,195,h-50);
        else
            processorList->setBounds(5,5,195,34);

        if (w < 460)
            processorList->setBounds(5-460+getWidth(),5,195,processorList->getHeight());
    }

    if (dataViewport != 0)
    {
        int left, top, width, height;
        left = 6;
        top = 40;

        if (processorList->isOpen())
            left = processorList->getX()+processorList->getWidth()+2;
        else
            left = 6;

        top = controlPanel->getHeight()+8;

        if (editorViewportButton->isOpen())
            height = h - top - 195;
        else
            height = h - top - 45;

        width = w - left - 5;

        dataViewport->setBounds(left, top, width, height);

         if (h < 200)
            dataViewport->setVisible(false);
        else
            dataViewport->setVisible(true);

    }

    

    if (messageCenter != 0)
    {
        messageCenter->setBounds(6,h-35,w-241,30);
        if (h < 200)
            messageCenter->setBounds(6,h-35+200-h,w-241,30);
      //  else
      //      messageCenter->setVisible(true);
    }

    // for debugging qpurposes:
    if (false)
    {
        dataViewport->setVisible(false);
        editorViewport->setVisible(false);
        processorList->setVisible(false);
        messageCenter->setVisible(false);
        controlPanel->setVisible(false);
        editorViewportButton->setVisible(false);
    }

}

void UIComponent::disableCallbacks()
{
    //sendActionMessage("Data acquisition terminated.");
    controlPanel->disableCallbacks();
}

void UIComponent::disableDataViewport()
{
    dataViewport->disableConnectionToEditorViewport();
}

void UIComponent::childComponentChanged()
{
    resized();
}




//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

// MENU BAR METHODS

StringArray UIComponent::getMenuBarNames()
{

    // StringArray names;
    // names.add("File");
    // names.add("Edit");
    // names.add("Help");

    const char* const names[] = { "File", "Edit", "View", "Help", 0 };

    return StringArray(names);

}

PopupMenu UIComponent::getMenuForIndex(int menuIndex, const String& menuName)
{
    ApplicationCommandManager* commandManager = &(mainWindow->commandManager);

    PopupMenu menu;

    if (menuIndex == 0)
    {
        menu.addCommandItem(commandManager, openConfiguration);
        menu.addCommandItem(commandManager, saveConfiguration);

#if !JUCE_MAC
        menu.addSeparator();
        menu.addCommandItem(commandManager, StandardApplicationCommandIDs::quit);
#endif

    }
    else if (menuIndex == 1)
    {
        menu.addCommandItem(commandManager, undo);
        menu.addCommandItem(commandManager, redo);
        menu.addSeparator();
        menu.addCommandItem(commandManager, copySignalChain);
        menu.addCommandItem(commandManager, pasteSignalChain);
        menu.addSeparator();
        menu.addCommandItem(commandManager, clearSignalChain);

    }
    else if (menuIndex == 2)
    {

        menu.addCommandItem(commandManager, toggleProcessorList);
        menu.addCommandItem(commandManager, toggleSignalChain);
        menu.addCommandItem(commandManager, toggleFileInfo);
        menu.addSeparator();
        menu.addCommandItem(commandManager, resizeWindow);

    }
    else if (menuIndex == 3)
    {
        menu.addCommandItem(commandManager, showHelp);
    }

    return menu;

}

void UIComponent::menuItemSelected(int menuItemID, int topLevelMenuIndex)
{

    //
}

// ApplicationCommandTarget methods

ApplicationCommandTarget* UIComponent::getNextCommandTarget()
{
    // this will return the next parent component that is an ApplicationCommandTarget (in this
    // case, there probably isn't one, but it's best to use this method anyway).
    return findFirstTargetParentComponent();
}

void UIComponent::getAllCommands(Array <CommandID>& commands)
{
    const CommandID ids[] = {openConfiguration,
                             saveConfiguration,
                             undo,
                             redo,
                             copySignalChain,
                             pasteSignalChain,
                             clearSignalChain,
                             toggleProcessorList,
                             toggleSignalChain,
                             toggleFileInfo,
                             showHelp,
                             resizeWindow
                            };

    commands.addArray(ids, numElementsInArray(ids));

}

void UIComponent::getCommandInfo(CommandID commandID, ApplicationCommandInfo& result)
{

    bool acquisitionStarted = getAudioComponent()->callbacksAreActive();

    switch (commandID)
    {
        case openConfiguration:
            result.setInfo("Open configuration", "Load a saved processor graph.", "General", 0);
            result.addDefaultKeypress('O', ModifierKeys::commandModifier);
            result.setActive(!acquisitionStarted);
            break;

        case saveConfiguration:
            result.setInfo("Save configuration", "Save the current processor graph.", "General", 0);
            result.addDefaultKeypress('S', ModifierKeys::commandModifier);
            result.setActive(!acquisitionStarted);
            break;

        case undo:
            result.setInfo("Undo", "Undo the last action.", "General", 0);
            result.addDefaultKeypress('Z', ModifierKeys::commandModifier);
            result.setActive(false);
            break;

        case redo:
            result.setInfo("Redo", "Undo the last action.", "General", 0);
            result.addDefaultKeypress('Y', ModifierKeys::commandModifier);
            result.setActive(false);
            break;

        case copySignalChain:
            result.setInfo("Copy", "Copy a portion of the signal chain.", "General", 0);
            result.addDefaultKeypress('C', ModifierKeys::commandModifier);
            result.setActive(false);
            break;

        case pasteSignalChain:
            result.setInfo("Paste", "Paste a portion of the signal chain.", "General", 0);
            result.addDefaultKeypress('V', ModifierKeys::commandModifier);
            result.setActive(false);
            break;

        case clearSignalChain:
            result.setInfo("Clear signal chain", "Clear the current signal chain.", "General", 0);
            result.addDefaultKeypress(KeyPress::backspaceKey, ModifierKeys::commandModifier);
            result.setActive(!getEditorViewport()->isSignalChainEmpty() && !acquisitionStarted);
            break;

        case toggleProcessorList:
            result.setInfo("Processor List", "Show/hide Processor List.", "General", 0);
            result.addDefaultKeypress('P', ModifierKeys::shiftModifier);
            result.setTicked(processorList->isOpen());
            break;

        case toggleSignalChain:
            result.setInfo("Signal Chain", "Show/hide Signal Chain.", "General", 0);
            result.addDefaultKeypress('S', ModifierKeys::shiftModifier);
            result.setTicked(editorViewportButton->isOpen());
            break;

        case toggleFileInfo:
            result.setInfo("File Info", "Show/hide File Info.", "General", 0);
            result.addDefaultKeypress('F', ModifierKeys::shiftModifier);
            result.setTicked(controlPanel->isOpen());
            break;

        case showHelp:
            result.setInfo("Show help...", "Show some freakin' help.", "General", 0);
            result.setActive(false);
            break;
            
        case resizeWindow:
            result.setInfo("Reset window bounds", "Reset window bounds", "General", 0);
            break;

        default:
            break;
    };

}

bool UIComponent::perform(const InvocationInfo& info)
{

    switch (info.commandID)
    {
        case openConfiguration:
            {
                FileChooser fc("Choose a file to load...",
                               File::getCurrentWorkingDirectory(),
                               "*",
                               true);

                if (fc.browseForFileToOpen())
                {
                    File currentFile = fc.getResult();
                    sendActionMessage(getEditorViewport()->loadState(currentFile));
                }
                else
                {
                    sendActionMessage("No configuration selected.");
                }

                break;
            }
        case saveConfiguration:
            {

                FileChooser fc("Choose the file to save...",
                               File::getCurrentWorkingDirectory(),
                               "*",
                               true);

                if (fc.browseForFileToSave(true))
                {
                    File currentFile = fc.getResult();
                    std::cout << currentFile.getFileName() << std::endl;
                    sendActionMessage(getEditorViewport()->saveState(currentFile));
                }
                else
                {
                    sendActionMessage("No file chosen.");
                }

                break;
            }
        case clearSignalChain:
        {
            getEditorViewport()->clearSignalChain();
            break;
        }

        case showHelp:
            std::cout << "SHOW ME SOME HELP!" << std::endl;
            break;

        case toggleProcessorList:
            processorList->toggleState();
            break;

        case toggleFileInfo:
            controlPanel->toggleState();
            break;

        case toggleSignalChain:
            editorViewportButton->toggleState();
            break;
            
        case resizeWindow:
            mainWindow->centreWithSize(800, 600);
            break;

        default:
            break;

    }

    return true;

}


void UIComponent::saveStateToXml(XmlElement* xml)
{
    XmlElement* uiComponentState = xml->createNewChildElement("UICOMPONENT");
    uiComponentState->setAttribute("isProcessorListOpen",processorList->isOpen());
    uiComponentState->setAttribute("isEditorViewportOpen",editorViewportButton->isOpen());
}

void UIComponent::loadStateFromXml(XmlElement* xml)
{
    forEachXmlChildElement(*xml, xmlNode)
    {
        if (xmlNode->hasTagName("UICOMPONENT"))
        {

            bool isProcessorListOpen = xmlNode->getBoolAttribute("isProcessorListOpen");
            bool isEditorViewportOpen = xmlNode->getBoolAttribute("isEditorViewportOpen");

            if (!isProcessorListOpen)
            {
                processorList->toggleState();
            }

            if (!isEditorViewportOpen)
            {
                editorViewportButton->toggleState();
            }

        }
    }
}

StringArray UIComponent::getRecentlyUsedFilenames()
{
    return controlPanel->getRecentlyUsedFilenames();
}

void UIComponent::setRecentlyUsedFilenames(const StringArray& filenames)
{
    controlPanel->setRecentlyUsedFilenames(filenames);
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

EditorViewportButton::EditorViewportButton(UIComponent* ui) : UI(ui)
{
    open = true;

    buttonFont = Font("Default Light", 25, Font::plain);

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

}

EditorViewportButton::~EditorViewportButton()
{

}


void EditorViewportButton::paint(Graphics& g)
{

    g.fillAll(Colour(58,58,58));

    g.setColour(Colours::white);
    g.setFont(buttonFont);
    g.drawText("SIGNAL CHAIN", 10, 0, getWidth(), getHeight(), Justification::left, false);

    g.setColour(Colours::white);

    Path p;

    float h = getHeight();
    float w = getWidth()-5;

    if (open)
    {
        p.addTriangle(w-h+0.3f*h, 0.7f*h,
                      w-h+0.5f*h, 0.3f*h,
                      w-h+0.7f*h, 0.7f*h);
    }
    else
    {
        p.addTriangle(w-h+0.3f*h, 0.5f*h,
                      w-h+0.7f*h, 0.3f*h,
                      w-h+0.7f*h, 0.7f*h);
    }
    PathStrokeType pst = PathStrokeType(1.0f, PathStrokeType::curved, PathStrokeType::rounded);

    g.strokePath(p, pst);

}


void EditorViewportButton::mouseDown(const MouseEvent& e)
{
    open = !open;
    UI->childComponentChanged();
    repaint();

}

void EditorViewportButton::toggleState()
{
    open = !open;
    UI->childComponentChanged();
    repaint();
}