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