andrewm@0: /*
andrewm@0: TouchKeys: multi-touch musical keyboard control software
andrewm@0: Copyright (c) 2013 Andrew McPherson
andrewm@0:
andrewm@0: This program is free software: you can redistribute it and/or modify
andrewm@0: it under the terms of the GNU General Public License as published by
andrewm@0: the Free Software Foundation, either version 3 of the License, or
andrewm@0: (at your option) any later version.
andrewm@0:
andrewm@0: This program is distributed in the hope that it will be useful,
andrewm@0: but WITHOUT ANY WARRANTY; without even the implied warranty of
andrewm@0: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
andrewm@0: GNU General Public License for more details.
andrewm@0:
andrewm@0: You should have received a copy of the GNU General Public License
andrewm@0: along with this program. If not, see .
andrewm@0:
andrewm@0: =====================================================================
andrewm@0:
andrewm@0: MappingListComponent.cpp: manages a ListBox to display the current
andrewm@0: mappigns associated with a keyboard segment.
andrewm@0: */
andrewm@0:
andrewm@0: #ifndef TOUCHKEYS_NO_GUI
andrewm@0:
andrewm@0: #include "../JuceLibraryCode/JuceHeader.h"
andrewm@0: #include "MappingListComponent.h"
andrewm@41: #include "MappingExtendedEditorWindow.h"
andrewm@0:
andrewm@0: //==============================================================================
andrewm@0: MappingListComponent::MappingListComponent() : controller_(0), keyboardSegment_(0),
andrewm@0: lastMappingFactoryIdentifier_(-1) {
andrewm@0: // In your constructor, you should add any child components, and
andrewm@0: // initialise any special settings that your component needs.
andrewm@0: addAndMakeVisible(&listBox_);
andrewm@0: listBox_.setModel(this);
andrewm@0: listBox_.setColour(ListBox::outlineColourId, Colours::grey);
andrewm@0: listBox_.setOutlineThickness(1);
andrewm@0: listBox_.setRowHeight(72);
andrewm@0: }
andrewm@0:
andrewm@41: MappingListComponent::~MappingListComponent() {
andrewm@41: clearExtendedEditorWindows();
andrewm@0: }
andrewm@0:
andrewm@0: void MappingListComponent::resized() {
andrewm@0: // This method is where you should set the bounds of any child
andrewm@0: // components that your component contains..
andrewm@0: listBox_.setBoundsInset (BorderSize (4));
andrewm@0: }
andrewm@0:
andrewm@0: // Delete the given factory from the mapping list
andrewm@0: void MappingListComponent::deleteMapping(MappingFactory* factory) {
andrewm@0: if(keyboardSegment_ == 0 || factory == 0)
andrewm@0: return;
andrewm@0: keyboardSegment_->removeMappingFactory(factory);
andrewm@0: }
andrewm@0:
andrewm@0: int MappingListComponent::getNumRows() {
andrewm@0: if(controller_ == 0 || keyboardSegment_ == 0)
andrewm@0: return 0;
andrewm@0: return keyboardSegment_->mappingFactories().size();
andrewm@0: }
andrewm@0:
andrewm@0: // Given a row number and a possibly an existing component, return the component
andrewm@0: // that should be drawn in this row of the list. Whenever a new component is created,
andrewm@0: // the existing one should be deleted by this method (according to Juce docs).
andrewm@0: Component* MappingListComponent::refreshComponentForRow(int rowNumber, bool isRowSelected, Component *existingComponentToUpdate) {
andrewm@0: if(keyboardSegment_ == 0)
andrewm@0: return 0;
andrewm@0:
andrewm@0: //std::cout << "refreshing component for row " << rowNumber << " (given " << existingComponentToUpdate << ")\n";
andrewm@0: if(rowNumber < 0 || rowNumber >= getNumRows()) {
andrewm@0: if(existingComponentToUpdate != 0)
andrewm@0: delete existingComponentToUpdate;
andrewm@0: return 0;
andrewm@0: }
andrewm@0:
andrewm@0: // Get the current component for the row, creating it if it doesn't exist
andrewm@0: MappingListItem *listItem = static_cast(existingComponentToUpdate);
andrewm@0: if(listItem == 0) {
andrewm@0: listItem = new MappingListItem(*this);
andrewm@0: listItem->setMappingFactory(keyboardSegment_->mappingFactories()[rowNumber]);
andrewm@0: //std::cout << "item " << listItem << " was updated to factory " << keyboardSegment_->mappingFactories()[rowNumber] << std::endl;
andrewm@0: }
andrewm@0: else {
andrewm@0: // Component exists; does it still point to a factory?
andrewm@0: if(rowNumber >= keyboardSegment_->mappingFactories().size()) {
andrewm@0: //std::cout << "Deleting component " << listItem << std::endl;
andrewm@0: delete listItem;
andrewm@0: return 0;
andrewm@0: }
andrewm@0: else if(keyboardSegment_->mappingFactories()[rowNumber] != listItem->mappingFactory()) {
andrewm@0: //std::cout << "Changing item " << listItem << " to point to factory " << keyboardSegment_->mappingFactories()[rowNumber] << std::endl;
andrewm@0: listItem->setMappingFactory(keyboardSegment_->mappingFactories()[rowNumber]);
andrewm@0: }
andrewm@0: }
andrewm@0:
andrewm@0: return listItem;
andrewm@0: }
andrewm@0:
andrewm@0: // Return whether a given component is selected or not (called by MappingListItem)
andrewm@0: bool MappingListComponent::isComponentSelected(Component *component) {
andrewm@0: int rowNumber = listBox_.getRowNumberOfComponent(component);
andrewm@0: if(rowNumber < 0)
andrewm@0: return false;
andrewm@0: return listBox_.isRowSelected(rowNumber);
andrewm@0: }
andrewm@0:
andrewm@0:
andrewm@41: void MappingListComponent::synchronize() {
andrewm@0: if(keyboardSegment_ != 0) {
andrewm@0: if(lastMappingFactoryIdentifier_ != keyboardSegment_->mappingFactoryUniqueIdentifier()) {
andrewm@0: lastMappingFactoryIdentifier_ = keyboardSegment_->mappingFactoryUniqueIdentifier();
andrewm@0: listBox_.updateContent();
andrewm@41: updateExtendedEditorWindows();
andrewm@0: }
andrewm@0: }
andrewm@0:
andrewm@0: for(int i = 0; i < getNumRows(); i++) {
andrewm@0: MappingListItem *listItem = static_cast(listBox_.getComponentForRowNumber(i));
andrewm@0: if(listItem != 0)
andrewm@0: listItem->synchronize();
andrewm@0: }
andrewm@41:
andrewm@41: synchronizeExtendedEditorWindows();
andrewm@41: }
andrewm@41:
andrewm@41: // Open an extended editor window for the given component
andrewm@41: // Store the new window in the list; it is deleted when it is closed
andrewm@41: void MappingListComponent::openExtendedEditorWindow(MappingFactory *factory) {
andrewm@41: if(factory == 0)
andrewm@41: return;
andrewm@41:
andrewm@41: ScopedLock sl(extendedEditorWindowsMutex_);
andrewm@41:
andrewm@41: MappingExtendedEditorWindow *window = new MappingExtendedEditorWindow(*this,
andrewm@41: *keyboardSegment_, *factory);
andrewm@41: extendedEditorWindows_.push_back(window);
andrewm@41: }
andrewm@41:
andrewm@41: // Close an extended editor window and remove it from the list
andrewm@41: void MappingListComponent::closeExtendedEditorWindow(MappingExtendedEditorWindow *window) {
andrewm@41: ScopedLock sl(extendedEditorWindowsMutex_);
andrewm@41:
andrewm@41: closeExtendedEditorWindowHelper(window);
andrewm@41: }
andrewm@41:
andrewm@41: MappingExtendedEditorWindow* MappingListComponent::extendedEditorWindowForFactory(MappingFactory *factory) {
andrewm@41: ScopedLock sl(extendedEditorWindowsMutex_);
andrewm@41:
andrewm@41: list::iterator it;
andrewm@41: for(it = extendedEditorWindows_.begin(); it != extendedEditorWindows_.end(); ++it) {
andrewm@41: if((*it)->factory() == factory)
andrewm@41: return *it;
andrewm@41: }
andrewm@41:
andrewm@41: return 0;
andrewm@41: }
andrewm@41:
andrewm@41: // Update extended editor windows
andrewm@41: void MappingListComponent::synchronizeExtendedEditorWindows() {
andrewm@41: // Update extended editor windows
andrewm@41: ScopedLock sl(extendedEditorWindowsMutex_);
andrewm@41:
andrewm@41: list::iterator it;
andrewm@41: for(it = extendedEditorWindows_.begin(); it != extendedEditorWindows_.end(); ++it) {
andrewm@41: (*it)->synchronize();
andrewm@41: }
andrewm@41: }
andrewm@41:
andrewm@41: // Close an extended editor window and remove it from the list (interval version without lock)
andrewm@41: void MappingListComponent::closeExtendedEditorWindowHelper(MappingExtendedEditorWindow *window) {
andrewm@41: window->setVisible(false);
andrewm@41:
andrewm@41: list::iterator it;
andrewm@41: bool found = true;
andrewm@41:
andrewm@41: // Remove this window from the list (handling multiple entries just in case)
andrewm@41: while(found) {
andrewm@41: found = false;
andrewm@41: for(it = extendedEditorWindows_.begin(); it != extendedEditorWindows_.end(); ++it) {
andrewm@41: if(*it == window) {
andrewm@41: extendedEditorWindows_.erase(it);
andrewm@41: found = true;
andrewm@41: break;
andrewm@41: }
andrewm@41: }
andrewm@41: }
andrewm@41:
andrewm@41: // Delete the window which in turn deletes the editor component
andrewm@41: delete window;
andrewm@41: }
andrewm@41:
andrewm@41: // Find the invalid extended editor windows and close them
andrewm@41: void MappingListComponent::updateExtendedEditorWindows() {
andrewm@41: ScopedLock sl(extendedEditorWindowsMutex_);
andrewm@41:
andrewm@41: list::iterator it;
andrewm@41: bool found = true;
andrewm@41:
andrewm@41: // Remove the window from the list if it is invalid
andrewm@41: while(found) {
andrewm@41: found = false;
andrewm@41: for(it = extendedEditorWindows_.begin(); it != extendedEditorWindows_.end(); ++it) {
andrewm@41: if(!(*it)->isValid()) {
andrewm@41: closeExtendedEditorWindowHelper(*it);
andrewm@41: found = true;
andrewm@41: break;
andrewm@41: }
andrewm@41: }
andrewm@41: }
andrewm@41: }
andrewm@41:
andrewm@41: // Remove all extend editor windows
andrewm@41: void MappingListComponent::clearExtendedEditorWindows() {
andrewm@41: ScopedLock sl(extendedEditorWindowsMutex_);
andrewm@41:
andrewm@41: list::iterator it;
andrewm@41: for(it = extendedEditorWindows_.begin(); it != extendedEditorWindows_.end(); ++it) {
andrewm@41: delete *it;
andrewm@41: }
andrewm@41:
andrewm@41: extendedEditorWindows_.clear();
andrewm@0: }
andrewm@0:
andrewm@0: #endif // TOUCHKEYS_NO_GUI