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 MainWindow.cpp: the control window, plus menu bar and Juce application methods
|
andrewm@0
|
21 */
|
andrewm@0
|
22
|
andrewm@0
|
23 #include "../../JuceLibraryCode/JuceHeader.h"
|
andrewm@0
|
24 #include "MainWindow.h"
|
andrewm@0
|
25
|
andrewm@0
|
26 //==============================================================================
|
andrewm@0
|
27 MainWindow::MainWindow(MainApplicationController& controller)
|
andrewm@0
|
28 : DocumentWindow ("TouchKeys", Colours::lightgrey, DocumentWindow::allButtons),
|
andrewm@0
|
29 controller_(controller)
|
andrewm@0
|
30 {
|
andrewm@0
|
31 commandManager_.registerAllCommandsForTarget(this);
|
andrewm@0
|
32 commandManager_.registerAllCommandsForTarget(JUCEApplication::getInstance());
|
andrewm@0
|
33
|
andrewm@0
|
34 // This lets the command manager use keypresses that arrive in our window to send
|
andrewm@0
|
35 // out commands
|
andrewm@0
|
36 addKeyListener(commandManager_.getKeyMappings());
|
andrewm@0
|
37
|
andrewm@0
|
38 // Create the menu bar, either in the window or at the top of the screen
|
andrewm@0
|
39 #if JUCE_MAC
|
andrewm@0
|
40 MenuBarModel::setMacMainMenu(this);
|
andrewm@0
|
41 #else
|
andrewm@0
|
42 // Menu bar goes at the top of the window
|
andrewm@0
|
43 setMenuBar(this);
|
andrewm@0
|
44
|
andrewm@0
|
45 // Window height should change to accommodate it
|
andrewm@0
|
46 Component *actualMenuBar = getMenuBarComponent();
|
andrewm@0
|
47 if(actualMenuBar != 0) {
|
andrewm@20
|
48 juce::Rectangle<int> r = actualMenuBar->getBounds();
|
andrewm@0
|
49 setSize(getWidth(), getHeight() + r.getHeight());
|
andrewm@0
|
50 }
|
andrewm@0
|
51 #endif /* JUCE_MAC */
|
andrewm@0
|
52
|
andrewm@0
|
53 // Tells our menu bar model that it should watch this command manager for
|
andrewm@0
|
54 // changes, and send change messages accordingly.
|
andrewm@0
|
55 setApplicationCommandManagerToWatch(&commandManager_);
|
andrewm@0
|
56
|
andrewm@0
|
57 mainComponent_.setMainApplicationController(&controller_);
|
andrewm@0
|
58 setContentNonOwned(&mainComponent_, true);
|
andrewm@0
|
59
|
andrewm@0
|
60 commandManager_.setFirstCommandTarget(this);
|
andrewm@0
|
61
|
andrewm@0
|
62 // Start a timer that will keep the interface in sync with the application
|
andrewm@0
|
63 startTimer(50);
|
andrewm@0
|
64
|
andrewm@0
|
65 centreWithSize (getWidth(), getHeight());
|
andrewm@0
|
66 setUsingNativeTitleBar(true);
|
andrewm@31
|
67
|
andrewm@31
|
68 // Allow resizing to be larger vertically
|
andrewm@31
|
69 setResizable(true, true);
|
andrewm@31
|
70 setResizeLimits(getWidth(), getHeight(), getWidth(), 2048);
|
andrewm@31
|
71
|
andrewm@0
|
72 setVisible (true);
|
andrewm@0
|
73 }
|
andrewm@0
|
74
|
andrewm@0
|
75 MainWindow::~MainWindow() {
|
andrewm@0
|
76 // Delete the menu bar before exiting
|
andrewm@0
|
77 #if JUCE_MAC
|
andrewm@0
|
78 MenuBarModel::setMacMainMenu(nullptr);
|
andrewm@0
|
79 #else
|
andrewm@0
|
80 setMenuBar(nullptr);
|
andrewm@0
|
81 #endif /* JUCE_MAC */
|
andrewm@0
|
82 }
|
andrewm@0
|
83
|
andrewm@0
|
84 // Handle periodic GUI updates, keeping the GUI in sync with the underlying system
|
andrewm@0
|
85 void MainWindow::timerCallback() {
|
andrewm@0
|
86 mainComponent_.synchronize();
|
andrewm@0
|
87 }
|
andrewm@0
|
88
|
andrewm@0
|
89 // ***** Juce menu bar methods ****
|
andrewm@0
|
90 StringArray MainWindow::getMenuBarNames() {
|
andrewm@0
|
91 const char* const names[] = { "File", "Edit", "Control", "Window", nullptr };
|
andrewm@0
|
92
|
andrewm@0
|
93 return StringArray (names);
|
andrewm@0
|
94 }
|
andrewm@0
|
95
|
andrewm@0
|
96 PopupMenu MainWindow::getMenuForIndex(int menuIndex, const String& menuName) {
|
andrewm@0
|
97 PopupMenu menu;
|
andrewm@0
|
98
|
andrewm@0
|
99 if(menuIndex == 0) { // File
|
andrewm@33
|
100 menu.addCommandItem(&commandManager_, kCommandClearPreset);
|
andrewm@0
|
101 menu.addSeparator();
|
andrewm@0
|
102 menu.addCommandItem(&commandManager_, kCommandOpenPreset);
|
andrewm@0
|
103 menu.addCommandItem(&commandManager_, kCommandSavePreset);
|
andrewm@0
|
104 #ifndef JUCE_MAC
|
andrewm@0
|
105 menu.addSeparator();
|
andrewm@0
|
106 menu.addCommandItem(&commandManager_, StandardApplicationCommandIDs::quit);
|
andrewm@0
|
107 #endif
|
andrewm@0
|
108 }
|
andrewm@0
|
109 else if(menuIndex == 1) { // Edit
|
andrewm@0
|
110 menu.addCommandItem(&commandManager_, StandardApplicationCommandIDs::undo);
|
andrewm@0
|
111 menu.addCommandItem(&commandManager_, StandardApplicationCommandIDs::redo);
|
andrewm@0
|
112 menu.addSeparator();
|
andrewm@0
|
113 menu.addCommandItem(&commandManager_, StandardApplicationCommandIDs::cut);
|
andrewm@0
|
114 menu.addCommandItem(&commandManager_, StandardApplicationCommandIDs::copy);
|
andrewm@0
|
115 menu.addCommandItem(&commandManager_, StandardApplicationCommandIDs::paste);
|
andrewm@0
|
116 menu.addCommandItem(&commandManager_, StandardApplicationCommandIDs::del);
|
andrewm@0
|
117 menu.addSeparator();
|
andrewm@0
|
118 menu.addCommandItem(&commandManager_, StandardApplicationCommandIDs::selectAll);
|
andrewm@0
|
119 }
|
andrewm@0
|
120 else if(menuIndex == 2) { // Control
|
andrewm@0
|
121 menu.addCommandItem(&commandManager_, kCommandRescanDevices);
|
andrewm@0
|
122 menu.addSeparator();
|
andrewm@31
|
123 menu.addCommandItem(&commandManager_, kCommandLoggingStartStop);
|
andrewm@31
|
124 menu.addCommandItem(&commandManager_, kCommandLoggingPlay);
|
andrewm@31
|
125 menu.addSeparator();
|
andrewm@0
|
126 menu.addCommandItem(&commandManager_, kCommandEnableExperimentalMappings);
|
andrewm@17
|
127 #ifdef ENABLE_TOUCHKEYS_SENSOR_TEST
|
andrewm@17
|
128 menu.addCommandItem(&commandManager_, kCommandTestTouchkeySensors);
|
andrewm@17
|
129 #endif
|
andrewm@41
|
130 menu.addSeparator();
|
andrewm@41
|
131 menu.addCommandItem(&commandManager_, kCommandPreferences);
|
andrewm@0
|
132 }
|
andrewm@0
|
133 else if(menuIndex == 3) { // Window
|
andrewm@0
|
134 menu.addCommandItem(&commandManager_, kCommandShowControlWindow);
|
andrewm@0
|
135 menu.addCommandItem(&commandManager_, kCommandShowKeyboardWindow);
|
andrewm@0
|
136 }
|
andrewm@0
|
137
|
andrewm@0
|
138 return menu;
|
andrewm@0
|
139 }
|
andrewm@0
|
140
|
andrewm@0
|
141 void MainWindow::menuItemSelected(int menuItemID, int topLevelMenuIndex) {
|
andrewm@0
|
142 // TODO
|
andrewm@0
|
143 }
|
andrewm@0
|
144
|
andrewm@0
|
145 // **** Command Manager methods *****
|
andrewm@0
|
146
|
andrewm@0
|
147 ApplicationCommandTarget* MainWindow::getNextCommandTarget() {
|
andrewm@0
|
148 return findFirstTargetParentComponent();
|
andrewm@0
|
149 }
|
andrewm@0
|
150
|
andrewm@0
|
151 // this returns the set of all commands that this target can perform..
|
andrewm@0
|
152 void MainWindow::getAllCommands(Array <CommandID>& commands) {
|
andrewm@0
|
153 // this returns the set of all commands that this target can perform..
|
andrewm@0
|
154 const CommandID ids[] = {
|
andrewm@0
|
155 // File
|
andrewm@33
|
156 kCommandClearPreset,
|
andrewm@33
|
157 kCommandOpenPreset,
|
andrewm@33
|
158 kCommandSavePreset,
|
andrewm@0
|
159 // Edit
|
andrewm@0
|
160 StandardApplicationCommandIDs::undo,
|
andrewm@0
|
161 StandardApplicationCommandIDs::redo,
|
andrewm@0
|
162 StandardApplicationCommandIDs::cut,
|
andrewm@0
|
163 StandardApplicationCommandIDs::copy,
|
andrewm@0
|
164 StandardApplicationCommandIDs::paste,
|
andrewm@0
|
165 StandardApplicationCommandIDs::del,
|
andrewm@0
|
166 StandardApplicationCommandIDs::selectAll,
|
andrewm@0
|
167 // Control
|
andrewm@0
|
168 kCommandRescanDevices,
|
andrewm@31
|
169 kCommandLoggingStartStop,
|
andrewm@31
|
170 kCommandLoggingPlay,
|
andrewm@0
|
171 kCommandEnableExperimentalMappings,
|
andrewm@17
|
172 #ifdef ENABLE_TOUCHKEYS_SENSOR_TEST
|
andrewm@17
|
173 kCommandTestTouchkeySensors,
|
andrewm@17
|
174 #endif
|
andrewm@41
|
175 kCommandPreferences,
|
andrewm@41
|
176
|
andrewm@0
|
177 // Window
|
andrewm@0
|
178 kCommandShowControlWindow,
|
andrewm@0
|
179 kCommandShowKeyboardWindow
|
andrewm@0
|
180 };
|
andrewm@0
|
181
|
andrewm@0
|
182 commands.addArray (ids, numElementsInArray(ids));
|
andrewm@0
|
183 }
|
andrewm@0
|
184
|
andrewm@0
|
185 // This method is used when something needs to find out the details about one of the commands
|
andrewm@0
|
186 // that this object can perform..
|
andrewm@0
|
187 void MainWindow::getCommandInfo(CommandID commandID, ApplicationCommandInfo& result) {
|
andrewm@0
|
188 const String presetsCategory("Presets");
|
andrewm@0
|
189 const String editsCategory("Editing");
|
andrewm@0
|
190 const String controlCategory("Control");
|
andrewm@0
|
191 const String windowCategory("Window");
|
andrewm@0
|
192
|
andrewm@0
|
193 switch (commandID) {
|
andrewm@0
|
194
|
andrewm@0
|
195 // *** File Menu ***
|
andrewm@33
|
196 case kCommandClearPreset:
|
andrewm@33
|
197 result.setInfo("Clear Settings", "Clears the current settings", presetsCategory, 0);
|
andrewm@0
|
198 result.setTicked(false);
|
andrewm@37
|
199 result.setActive(true);
|
andrewm@0
|
200 break;
|
andrewm@0
|
201 case kCommandOpenPreset:
|
andrewm@0
|
202 result.setInfo("Open Preset...", "Opens an existing preset", presetsCategory, 0);
|
andrewm@0
|
203 result.setTicked(false);
|
andrewm@33
|
204 result.setActive(true);
|
andrewm@0
|
205 result.addDefaultKeypress ('O', ModifierKeys::commandModifier);
|
andrewm@0
|
206 break;
|
andrewm@0
|
207 case kCommandSavePreset:
|
andrewm@33
|
208 result.setInfo("Save Preset...", "Saves the current preset", presetsCategory, 0);
|
andrewm@0
|
209 result.setTicked(false);
|
andrewm@33
|
210 result.setActive(true);
|
andrewm@0
|
211 result.addDefaultKeypress ('S', ModifierKeys::commandModifier);
|
andrewm@0
|
212 break;
|
andrewm@0
|
213 // Quit command is handled by JuceApplication
|
andrewm@0
|
214
|
andrewm@0
|
215 // *** Edit Menu ***
|
andrewm@0
|
216 case StandardApplicationCommandIDs::undo:
|
andrewm@0
|
217 result.setInfo("Undo", "Undo", editsCategory, 0);
|
andrewm@0
|
218 result.setTicked(false);
|
andrewm@0
|
219 result.setActive(false);
|
andrewm@0
|
220 result.addDefaultKeypress ('Z', ModifierKeys::commandModifier);
|
andrewm@0
|
221 break;
|
andrewm@0
|
222 case StandardApplicationCommandIDs::redo:
|
andrewm@0
|
223 result.setInfo("Redo", "Redo", editsCategory, 0);
|
andrewm@0
|
224 result.setTicked(false);
|
andrewm@0
|
225 result.setActive(false);
|
andrewm@0
|
226 result.addDefaultKeypress ('Z', ModifierKeys::commandModifier | ModifierKeys::shiftModifier);
|
andrewm@0
|
227 break;
|
andrewm@0
|
228 case StandardApplicationCommandIDs::cut:
|
andrewm@0
|
229 result.setInfo("Cut", "Cut", editsCategory, 0);
|
andrewm@0
|
230 result.setTicked(false);
|
andrewm@0
|
231 result.setActive(false);
|
andrewm@0
|
232 result.addDefaultKeypress ('X', ModifierKeys::commandModifier);
|
andrewm@0
|
233 break;
|
andrewm@0
|
234 case StandardApplicationCommandIDs::copy:
|
andrewm@0
|
235 result.setInfo("Copy", "Copy", editsCategory, 0);
|
andrewm@0
|
236 result.setTicked(false);
|
andrewm@0
|
237 result.setActive(false);
|
andrewm@0
|
238 result.addDefaultKeypress ('C', ModifierKeys::commandModifier);
|
andrewm@0
|
239 break;
|
andrewm@0
|
240 case StandardApplicationCommandIDs::paste:
|
andrewm@0
|
241 result.setInfo("Paste", "Paste", editsCategory, 0);
|
andrewm@0
|
242 result.setTicked(false);
|
andrewm@0
|
243 result.setActive(false);
|
andrewm@0
|
244 result.addDefaultKeypress ('V', ModifierKeys::commandModifier);
|
andrewm@0
|
245 break;
|
andrewm@0
|
246 case StandardApplicationCommandIDs::del:
|
andrewm@0
|
247 result.setInfo("Delete", "Delete", editsCategory, 0);
|
andrewm@0
|
248 result.setTicked(false);
|
andrewm@0
|
249 result.setActive(false);
|
andrewm@0
|
250 break;
|
andrewm@0
|
251 case StandardApplicationCommandIDs::selectAll:
|
andrewm@0
|
252 result.setInfo("Select All", "Select All", editsCategory, 0);
|
andrewm@0
|
253 result.setTicked(false);
|
andrewm@0
|
254 result.setActive(false);
|
andrewm@0
|
255 result.addDefaultKeypress ('A', ModifierKeys::commandModifier);
|
andrewm@0
|
256 break;
|
andrewm@0
|
257
|
andrewm@0
|
258 // *** Control Menu ***
|
andrewm@0
|
259 case kCommandRescanDevices:
|
andrewm@0
|
260 result.setInfo("Rescan Devices", "Rescans available TouchKeys and MIDI devices", controlCategory, 0);
|
andrewm@0
|
261 result.setTicked(false);
|
andrewm@28
|
262 result.setActive(true);
|
andrewm@0
|
263 result.addDefaultKeypress ('R', ModifierKeys::commandModifier);
|
andrewm@0
|
264 break;
|
andrewm@31
|
265 case kCommandLoggingStartStop:
|
andrewm@31
|
266 result.setInfo("Record Log File", "Records TouchKeys and MIDI data to file", controlCategory, 0);
|
andrewm@31
|
267 result.setTicked(controller_.isLogging());
|
andrewm@31
|
268 result.setActive(true);
|
andrewm@31
|
269 break;
|
andrewm@31
|
270 case kCommandLoggingPlay:
|
andrewm@31
|
271 result.setInfo("Play Log...", "Plays TouchKeys and MIDI from file", controlCategory, 0);
|
andrewm@31
|
272 result.setTicked(false);
|
andrewm@31
|
273 result.setActive(false);
|
andrewm@31
|
274 break;
|
andrewm@0
|
275 case kCommandEnableExperimentalMappings:
|
andrewm@0
|
276 result.setInfo("Enable Experimental Mappings", "Enables mappings which are still experimental", controlCategory, 0);
|
andrewm@0
|
277 result.setTicked(controller_.experimentalMappingsEnabled());
|
andrewm@0
|
278 break;
|
andrewm@17
|
279 #ifdef ENABLE_TOUCHKEYS_SENSOR_TEST
|
andrewm@17
|
280 case kCommandTestTouchkeySensors:
|
andrewm@17
|
281 result.setInfo("Test TouchKeys Sensors", "Enables a test of individual TouchKeys sensors", controlCategory, 0);
|
andrewm@17
|
282 result.setActive(controller_.availableTouchkeyDevices().size() > 0);
|
andrewm@17
|
283 result.setTicked(controller_.touchkeySensorTestIsRunning());
|
andrewm@17
|
284 break;
|
andrewm@17
|
285 #endif
|
andrewm@41
|
286 case kCommandPreferences:
|
andrewm@41
|
287 result.setInfo("Preferences...", "General application preferences", controlCategory, 0);
|
andrewm@41
|
288 result.setTicked(false);
|
andrewm@41
|
289 result.setActive(true);
|
andrewm@41
|
290 break;
|
andrewm@0
|
291
|
andrewm@0
|
292 // *** Window Menu ***
|
andrewm@0
|
293 case kCommandShowControlWindow:
|
andrewm@0
|
294 result.setInfo("TouchKeys Controls", "Show control and mapping window", windowCategory, 0);
|
andrewm@0
|
295 result.setTicked(false);
|
andrewm@12
|
296 result.addDefaultKeypress ('1', ModifierKeys::commandModifier);
|
andrewm@0
|
297 break;
|
andrewm@0
|
298 case kCommandShowKeyboardWindow:
|
andrewm@0
|
299 result.setInfo("Keyboard Display", "Show keyboard display", windowCategory, 0);
|
andrewm@0
|
300 result.setTicked(false);
|
andrewm@12
|
301 result.addDefaultKeypress ('2', ModifierKeys::commandModifier);
|
andrewm@0
|
302 break;
|
andrewm@0
|
303
|
andrewm@0
|
304 default:
|
andrewm@0
|
305 break;
|
andrewm@0
|
306 };
|
andrewm@0
|
307 }
|
andrewm@0
|
308
|
andrewm@0
|
309 bool MainWindow::perform(const InvocationInfo& info) {
|
andrewm@0
|
310 switch (info.commandID)
|
andrewm@0
|
311 {
|
andrewm@33
|
312 case kCommandClearPreset:
|
andrewm@37
|
313 // Display an alert to confirm the user wants to delete this mapping
|
andrewm@37
|
314 AlertWindow::showOkCancelBox (AlertWindow::QuestionIcon,
|
andrewm@37
|
315 "Clear settings",
|
andrewm@37
|
316 "Are you sure you want to clear all zones and mappings?",
|
andrewm@37
|
317 String::empty,
|
andrewm@37
|
318 String::empty,
|
andrewm@37
|
319 0,
|
andrewm@37
|
320 ModalCallbackFunction::forComponent(alertBoxResultChosen, this));
|
andrewm@33
|
321 break;
|
andrewm@33
|
322 case kCommandOpenPreset:
|
andrewm@33
|
323 controller_.loadPresetWithDialog();
|
andrewm@33
|
324 break;
|
andrewm@33
|
325 case kCommandSavePreset:
|
andrewm@33
|
326 controller_.savePresetWithDialog();
|
andrewm@0
|
327 break;
|
andrewm@0
|
328 case kCommandRescanDevices:
|
andrewm@28
|
329 controller_.tellDevicesToUpdate();
|
andrewm@0
|
330 break;
|
andrewm@31
|
331 case kCommandLoggingStartStop:
|
andrewm@31
|
332 if(controller_.isLogging())
|
andrewm@31
|
333 controller_.stopLogging();
|
andrewm@31
|
334 else
|
andrewm@31
|
335 controller_.startLogging();
|
andrewm@31
|
336 break;
|
andrewm@31
|
337 case kCommandLoggingPlay:
|
andrewm@31
|
338 // TODO
|
andrewm@31
|
339 break;
|
andrewm@0
|
340 case kCommandEnableExperimentalMappings:
|
andrewm@0
|
341 controller_.setExperimentalMappingsEnabled(!controller_.experimentalMappingsEnabled());
|
andrewm@0
|
342 break;
|
andrewm@17
|
343 #ifdef ENABLE_TOUCHKEYS_SENSOR_TEST
|
andrewm@17
|
344 case kCommandTestTouchkeySensors:
|
andrewm@17
|
345 if(!controller_.touchkeySensorTestIsRunning())
|
andrewm@17
|
346 controller_.touchkeySensorTestStart(mainComponent_.currentTouchkeysSelectedPath().toUTF8(), controller_.touchkeyDeviceLowestMidiNote());
|
andrewm@17
|
347 else
|
andrewm@17
|
348 controller_.touchkeySensorTestStop();
|
andrewm@17
|
349 break;
|
andrewm@17
|
350 #endif
|
andrewm@41
|
351 case kCommandPreferences:
|
andrewm@41
|
352 controller_.showPreferencesWindow();
|
andrewm@41
|
353 break;
|
andrewm@0
|
354 case kCommandShowControlWindow:
|
andrewm@0
|
355 toFront(true);
|
andrewm@0
|
356 break;
|
andrewm@0
|
357 case kCommandShowKeyboardWindow:
|
andrewm@0
|
358 controller_.showKeyboardDisplayWindow();
|
andrewm@0
|
359 break;
|
andrewm@0
|
360
|
andrewm@0
|
361 default:
|
andrewm@0
|
362 return false;
|
andrewm@0
|
363 };
|
andrewm@0
|
364
|
andrewm@0
|
365 return true;
|
andrewm@0
|
366 }
|
andrewm@37
|
367
|
andrewm@37
|
368 // Called when user clicks a result in the alert box to confirm deletion
|
andrewm@37
|
369 void MainWindow::alertBoxResultChosen(int result, MainWindow *item) {
|
andrewm@37
|
370 if(result != 0) {
|
andrewm@37
|
371 item->clearPreset();
|
andrewm@37
|
372 }
|
andrewm@37
|
373 }
|