andrewm@0
|
1 /*
|
andrewm@0
|
2 TouchKeys: multi-touch musical keyboard control software
|
andrewm@0
|
3 Copyright (c) 2013 Andrew McPherson
|
andrewm@0
|
4
|
andrewm@0
|
5 This program is free software: you can redistribute it and/or modify
|
andrewm@0
|
6 it under the terms of the GNU General Public License as published by
|
andrewm@0
|
7 the Free Software Foundation, either version 3 of the License, or
|
andrewm@0
|
8 (at your option) any later version.
|
andrewm@0
|
9
|
andrewm@0
|
10 This program is distributed in the hope that it will be useful,
|
andrewm@0
|
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
andrewm@0
|
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
andrewm@0
|
13 GNU General Public License for more details.
|
andrewm@0
|
14
|
andrewm@0
|
15 You should have received a copy of the GNU General Public License
|
andrewm@0
|
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
|
andrewm@0
|
17
|
andrewm@0
|
18 =====================================================================
|
andrewm@0
|
19
|
andrewm@0
|
20 MappingListComponent.cpp: manages a ListBox to display the current
|
andrewm@0
|
21 mappigns associated with a keyboard segment.
|
andrewm@0
|
22 */
|
andrewm@0
|
23
|
andrewm@0
|
24 #ifndef TOUCHKEYS_NO_GUI
|
andrewm@0
|
25
|
andrewm@0
|
26 #include "../JuceLibraryCode/JuceHeader.h"
|
andrewm@0
|
27 #include "MappingListComponent.h"
|
andrewm@41
|
28 #include "MappingExtendedEditorWindow.h"
|
andrewm@0
|
29
|
andrewm@0
|
30 //==============================================================================
|
andrewm@0
|
31 MappingListComponent::MappingListComponent() : controller_(0), keyboardSegment_(0),
|
andrewm@0
|
32 lastMappingFactoryIdentifier_(-1) {
|
andrewm@0
|
33 // In your constructor, you should add any child components, and
|
andrewm@0
|
34 // initialise any special settings that your component needs.
|
andrewm@0
|
35 addAndMakeVisible(&listBox_);
|
andrewm@0
|
36 listBox_.setModel(this);
|
andrewm@0
|
37 listBox_.setColour(ListBox::outlineColourId, Colours::grey);
|
andrewm@0
|
38 listBox_.setOutlineThickness(1);
|
andrewm@0
|
39 listBox_.setRowHeight(72);
|
andrewm@0
|
40 }
|
andrewm@0
|
41
|
andrewm@41
|
42 MappingListComponent::~MappingListComponent() {
|
andrewm@41
|
43 clearExtendedEditorWindows();
|
andrewm@0
|
44 }
|
andrewm@0
|
45
|
andrewm@0
|
46 void MappingListComponent::resized() {
|
andrewm@0
|
47 // This method is where you should set the bounds of any child
|
andrewm@0
|
48 // components that your component contains..
|
andrewm@0
|
49 listBox_.setBoundsInset (BorderSize<int> (4));
|
andrewm@0
|
50 }
|
andrewm@0
|
51
|
andrewm@0
|
52 // Delete the given factory from the mapping list
|
andrewm@0
|
53 void MappingListComponent::deleteMapping(MappingFactory* factory) {
|
andrewm@0
|
54 if(keyboardSegment_ == 0 || factory == 0)
|
andrewm@0
|
55 return;
|
andrewm@0
|
56 keyboardSegment_->removeMappingFactory(factory);
|
andrewm@0
|
57 }
|
andrewm@0
|
58
|
andrewm@0
|
59 int MappingListComponent::getNumRows() {
|
andrewm@0
|
60 if(controller_ == 0 || keyboardSegment_ == 0)
|
andrewm@0
|
61 return 0;
|
andrewm@0
|
62 return keyboardSegment_->mappingFactories().size();
|
andrewm@0
|
63 }
|
andrewm@0
|
64
|
andrewm@0
|
65 // Given a row number and a possibly an existing component, return the component
|
andrewm@0
|
66 // that should be drawn in this row of the list. Whenever a new component is created,
|
andrewm@0
|
67 // the existing one should be deleted by this method (according to Juce docs).
|
andrewm@0
|
68 Component* MappingListComponent::refreshComponentForRow(int rowNumber, bool isRowSelected, Component *existingComponentToUpdate) {
|
andrewm@0
|
69 if(keyboardSegment_ == 0)
|
andrewm@0
|
70 return 0;
|
andrewm@0
|
71
|
andrewm@0
|
72 //std::cout << "refreshing component for row " << rowNumber << " (given " << existingComponentToUpdate << ")\n";
|
andrewm@0
|
73 if(rowNumber < 0 || rowNumber >= getNumRows()) {
|
andrewm@0
|
74 if(existingComponentToUpdate != 0)
|
andrewm@0
|
75 delete existingComponentToUpdate;
|
andrewm@0
|
76 return 0;
|
andrewm@0
|
77 }
|
andrewm@0
|
78
|
andrewm@0
|
79 // Get the current component for the row, creating it if it doesn't exist
|
andrewm@0
|
80 MappingListItem *listItem = static_cast<MappingListItem*>(existingComponentToUpdate);
|
andrewm@0
|
81 if(listItem == 0) {
|
andrewm@0
|
82 listItem = new MappingListItem(*this);
|
andrewm@0
|
83 listItem->setMappingFactory(keyboardSegment_->mappingFactories()[rowNumber]);
|
andrewm@0
|
84 //std::cout << "item " << listItem << " was updated to factory " << keyboardSegment_->mappingFactories()[rowNumber] << std::endl;
|
andrewm@0
|
85 }
|
andrewm@0
|
86 else {
|
andrewm@0
|
87 // Component exists; does it still point to a factory?
|
andrewm@0
|
88 if(rowNumber >= keyboardSegment_->mappingFactories().size()) {
|
andrewm@0
|
89 //std::cout << "Deleting component " << listItem << std::endl;
|
andrewm@0
|
90 delete listItem;
|
andrewm@0
|
91 return 0;
|
andrewm@0
|
92 }
|
andrewm@0
|
93 else if(keyboardSegment_->mappingFactories()[rowNumber] != listItem->mappingFactory()) {
|
andrewm@0
|
94 //std::cout << "Changing item " << listItem << " to point to factory " << keyboardSegment_->mappingFactories()[rowNumber] << std::endl;
|
andrewm@0
|
95 listItem->setMappingFactory(keyboardSegment_->mappingFactories()[rowNumber]);
|
andrewm@0
|
96 }
|
andrewm@0
|
97 }
|
andrewm@0
|
98
|
andrewm@0
|
99 return listItem;
|
andrewm@0
|
100 }
|
andrewm@0
|
101
|
andrewm@0
|
102 // Return whether a given component is selected or not (called by MappingListItem)
|
andrewm@0
|
103 bool MappingListComponent::isComponentSelected(Component *component) {
|
andrewm@0
|
104 int rowNumber = listBox_.getRowNumberOfComponent(component);
|
andrewm@0
|
105 if(rowNumber < 0)
|
andrewm@0
|
106 return false;
|
andrewm@0
|
107 return listBox_.isRowSelected(rowNumber);
|
andrewm@0
|
108 }
|
andrewm@0
|
109
|
andrewm@0
|
110
|
andrewm@41
|
111 void MappingListComponent::synchronize() {
|
andrewm@0
|
112 if(keyboardSegment_ != 0) {
|
andrewm@0
|
113 if(lastMappingFactoryIdentifier_ != keyboardSegment_->mappingFactoryUniqueIdentifier()) {
|
andrewm@0
|
114 lastMappingFactoryIdentifier_ = keyboardSegment_->mappingFactoryUniqueIdentifier();
|
andrewm@0
|
115 listBox_.updateContent();
|
andrewm@41
|
116 updateExtendedEditorWindows();
|
andrewm@0
|
117 }
|
andrewm@0
|
118 }
|
andrewm@0
|
119
|
andrewm@0
|
120 for(int i = 0; i < getNumRows(); i++) {
|
andrewm@0
|
121 MappingListItem *listItem = static_cast<MappingListItem*>(listBox_.getComponentForRowNumber(i));
|
andrewm@0
|
122 if(listItem != 0)
|
andrewm@0
|
123 listItem->synchronize();
|
andrewm@0
|
124 }
|
andrewm@41
|
125
|
andrewm@41
|
126 synchronizeExtendedEditorWindows();
|
andrewm@41
|
127 }
|
andrewm@41
|
128
|
andrewm@41
|
129 // Open an extended editor window for the given component
|
andrewm@41
|
130 // Store the new window in the list; it is deleted when it is closed
|
andrewm@41
|
131 void MappingListComponent::openExtendedEditorWindow(MappingFactory *factory) {
|
andrewm@41
|
132 if(factory == 0)
|
andrewm@41
|
133 return;
|
andrewm@41
|
134
|
andrewm@41
|
135 ScopedLock sl(extendedEditorWindowsMutex_);
|
andrewm@41
|
136
|
andrewm@41
|
137 MappingExtendedEditorWindow *window = new MappingExtendedEditorWindow(*this,
|
andrewm@41
|
138 *keyboardSegment_, *factory);
|
andrewm@41
|
139 extendedEditorWindows_.push_back(window);
|
andrewm@41
|
140 }
|
andrewm@41
|
141
|
andrewm@41
|
142 // Close an extended editor window and remove it from the list
|
andrewm@41
|
143 void MappingListComponent::closeExtendedEditorWindow(MappingExtendedEditorWindow *window) {
|
andrewm@41
|
144 ScopedLock sl(extendedEditorWindowsMutex_);
|
andrewm@41
|
145
|
andrewm@41
|
146 closeExtendedEditorWindowHelper(window);
|
andrewm@41
|
147 }
|
andrewm@41
|
148
|
andrewm@41
|
149 MappingExtendedEditorWindow* MappingListComponent::extendedEditorWindowForFactory(MappingFactory *factory) {
|
andrewm@41
|
150 ScopedLock sl(extendedEditorWindowsMutex_);
|
andrewm@41
|
151
|
andrewm@41
|
152 list<MappingExtendedEditorWindow*>::iterator it;
|
andrewm@41
|
153 for(it = extendedEditorWindows_.begin(); it != extendedEditorWindows_.end(); ++it) {
|
andrewm@41
|
154 if((*it)->factory() == factory)
|
andrewm@41
|
155 return *it;
|
andrewm@41
|
156 }
|
andrewm@41
|
157
|
andrewm@41
|
158 return 0;
|
andrewm@41
|
159 }
|
andrewm@41
|
160
|
andrewm@41
|
161 // Update extended editor windows
|
andrewm@41
|
162 void MappingListComponent::synchronizeExtendedEditorWindows() {
|
andrewm@41
|
163 // Update extended editor windows
|
andrewm@41
|
164 ScopedLock sl(extendedEditorWindowsMutex_);
|
andrewm@41
|
165
|
andrewm@41
|
166 list<MappingExtendedEditorWindow*>::iterator it;
|
andrewm@41
|
167 for(it = extendedEditorWindows_.begin(); it != extendedEditorWindows_.end(); ++it) {
|
andrewm@41
|
168 (*it)->synchronize();
|
andrewm@41
|
169 }
|
andrewm@41
|
170 }
|
andrewm@41
|
171
|
andrewm@41
|
172 // Close an extended editor window and remove it from the list (interval version without lock)
|
andrewm@41
|
173 void MappingListComponent::closeExtendedEditorWindowHelper(MappingExtendedEditorWindow *window) {
|
andrewm@41
|
174 window->setVisible(false);
|
andrewm@41
|
175
|
andrewm@41
|
176 list<MappingExtendedEditorWindow*>::iterator it;
|
andrewm@41
|
177 bool found = true;
|
andrewm@41
|
178
|
andrewm@41
|
179 // Remove this window from the list (handling multiple entries just in case)
|
andrewm@41
|
180 while(found) {
|
andrewm@41
|
181 found = false;
|
andrewm@41
|
182 for(it = extendedEditorWindows_.begin(); it != extendedEditorWindows_.end(); ++it) {
|
andrewm@41
|
183 if(*it == window) {
|
andrewm@41
|
184 extendedEditorWindows_.erase(it);
|
andrewm@41
|
185 found = true;
|
andrewm@41
|
186 break;
|
andrewm@41
|
187 }
|
andrewm@41
|
188 }
|
andrewm@41
|
189 }
|
andrewm@41
|
190
|
andrewm@41
|
191 // Delete the window which in turn deletes the editor component
|
andrewm@41
|
192 delete window;
|
andrewm@41
|
193 }
|
andrewm@41
|
194
|
andrewm@41
|
195 // Find the invalid extended editor windows and close them
|
andrewm@41
|
196 void MappingListComponent::updateExtendedEditorWindows() {
|
andrewm@41
|
197 ScopedLock sl(extendedEditorWindowsMutex_);
|
andrewm@41
|
198
|
andrewm@41
|
199 list<MappingExtendedEditorWindow*>::iterator it;
|
andrewm@41
|
200 bool found = true;
|
andrewm@41
|
201
|
andrewm@41
|
202 // Remove the window from the list if it is invalid
|
andrewm@41
|
203 while(found) {
|
andrewm@41
|
204 found = false;
|
andrewm@41
|
205 for(it = extendedEditorWindows_.begin(); it != extendedEditorWindows_.end(); ++it) {
|
andrewm@41
|
206 if(!(*it)->isValid()) {
|
andrewm@41
|
207 closeExtendedEditorWindowHelper(*it);
|
andrewm@41
|
208 found = true;
|
andrewm@41
|
209 break;
|
andrewm@41
|
210 }
|
andrewm@41
|
211 }
|
andrewm@41
|
212 }
|
andrewm@41
|
213 }
|
andrewm@41
|
214
|
andrewm@41
|
215 // Remove all extend editor windows
|
andrewm@41
|
216 void MappingListComponent::clearExtendedEditorWindows() {
|
andrewm@41
|
217 ScopedLock sl(extendedEditorWindowsMutex_);
|
andrewm@41
|
218
|
andrewm@41
|
219 list<MappingExtendedEditorWindow*>::iterator it;
|
andrewm@41
|
220 for(it = extendedEditorWindows_.begin(); it != extendedEditorWindows_.end(); ++it) {
|
andrewm@41
|
221 delete *it;
|
andrewm@41
|
222 }
|
andrewm@41
|
223
|
andrewm@41
|
224 extendedEditorWindows_.clear();
|
andrewm@0
|
225 }
|
andrewm@0
|
226
|
andrewm@0
|
227 #endif // TOUCHKEYS_NO_GUI
|