JUCE-7.0.12-0-g4f43011b96 JUCE-7.0.12-0-g4f43011b96
JUCE — C++ application framework with suport for VST, VST3, LV2 audio plug-ins

« « « Anklang Documentation
Loading...
Searching...
No Matches
juce_KeyMappingEditorComponent.cpp
Go to the documentation of this file.
1 /*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 By using JUCE, you agree to the terms of both the JUCE 7 End-User License
11 Agreement and JUCE Privacy Policy.
12
13 End User License Agreement: www.juce.com/juce-7-licence
14 Privacy Policy: www.juce.com/juce-privacy-policy
15
16 Or: You may also use this code under the terms of the GPL v3 (see
17 www.gnu.org/licenses).
18
19 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
20 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
21 DISCLAIMED.
22
23 ==============================================================================
24*/
25
26namespace juce
27{
28
30{
31public:
33 const String& keyName, int keyIndex)
34 : Button (keyName),
35 owner (kec),
36 commandID (command),
37 keyNum (keyIndex)
38 {
40 setTriggeredOnMouseDown (keyNum >= 0);
41
42 setTooltip (keyIndex < 0 ? TRANS ("Adds a new key-mapping")
43 : TRANS ("Click to change this key-mapping"));
44 }
45
46 void paintButton (Graphics& g, bool /*isOver*/, bool /*isDown*/) override
47 {
48 getLookAndFeel().drawKeymapChangeButton (g, getWidth(), getHeight(), *this,
49 keyNum >= 0 ? getName() : String());
50 }
51
52 void clicked() override
53 {
54 if (keyNum >= 0)
55 {
57 PopupMenu m;
58
59 m.addItem (TRANS ("Change this key-mapping"),
60 [button]
61 {
62 if (button != nullptr)
63 button.getComponent()->assignNewKey();
64 });
65
66 m.addSeparator();
67
68 m.addItem (TRANS ("Remove this key-mapping"),
69 [button]
70 {
71 if (button != nullptr)
72 button->owner.getMappings().removeKeyPress (button->commandID,
73 button->keyNum);
74 });
75
77 }
78 else
79 {
80 assignNewKey(); // + button pressed..
81 }
82 }
83
84 using Button::clicked;
85
86 void fitToContent (const int h) noexcept
87 {
88 if (keyNum < 0)
89 setSize (h, h);
90 else
91 setSize (jlimit (h * 4, h * 8, 6 + Font ((float) h * 0.6f).getStringWidth (getName())), h);
92 }
93
94 //==============================================================================
96 {
97 public:
99 : AlertWindow (TRANS ("New key-mapping"),
100 TRANS ("Please press a key combination now..."),
102 owner (kec)
103 {
104 addButton (TRANS ("OK"), 1);
105 addButton (TRANS ("Cancel"), 0);
106
107 // (avoid return + escape keys getting processed by the buttons..)
108 for (auto* child : getChildren())
109 child->setWantsKeyboardFocus (false);
110
113 }
114
115 bool keyPressed (const KeyPress& key) override
116 {
117 lastPress = key;
118 String message (TRANS ("Key") + ": " + owner.getDescriptionForKeyPress (key));
119
121
122 if (previousCommand != 0)
123 message << "\n\n("
124 << TRANS ("Currently assigned to \"CMDN\"")
126 << ')';
127
128 setMessage (message);
129 return true;
130 }
131
132 bool keyStateChanged (bool) override
133 {
134 return true;
135 }
136
137 KeyPress lastPress;
138
139 private:
141
143 };
144
145 void setNewKey (const KeyPress& newKey, bool dontAskUser)
146 {
147 if (newKey.isValid())
148 {
150
151 if (previousCommand == 0 || dontAskUser)
152 {
154
155 if (keyNum >= 0)
156 owner.getMappings().removeKeyPress (commandID, keyNum);
157
158 owner.getMappings().addKeyPress (commandID, newKey, keyNum);
159 }
160 else
161 {
163 TRANS ("Change key-mapping"),
164 TRANS ("This key is already assigned to the command \"CMDN\"")
165 .replace ("CMDN", owner.getCommandManager().getNameOfCommand (previousCommand))
166 + "\n\n"
167 + TRANS ("Do you want to re-assign it to this new command instead?"),
168 TRANS ("Re-assign"),
169 TRANS ("Cancel"),
170 this);
171 messageBox = AlertWindow::showScopedAsync (options, [this, newKey] (int result)
172 {
173 if (result != 0)
174 setNewKey (newKey, true);
175 });
176 }
177 }
178 }
179
180 static void keyChosen (int result, ChangeKeyButton* button)
181 {
182 if (button != nullptr && button->currentKeyEntryWindow != nullptr)
183 {
184 if (result != 0)
185 {
186 button->currentKeyEntryWindow->setVisible (false);
187 button->setNewKey (button->currentKeyEntryWindow->lastPress, false);
188 }
189
190 button->currentKeyEntryWindow.reset();
191 }
192 }
193
194 void assignNewKey()
195 {
196 currentKeyEntryWindow.reset (new KeyEntryWindow (owner));
197 currentKeyEntryWindow->enterModalState (true, ModalCallbackFunction::forComponent (keyChosen, this));
198 }
199
200private:
201 KeyMappingEditorComponent& owner;
202 const CommandID commandID;
203 const int keyNum;
204 std::unique_ptr<KeyEntryWindow> currentKeyEntryWindow;
205 ScopedMessageBox messageBox;
206
208};
209
210//==============================================================================
212{
213public:
215 : owner (kec), commandID (command)
216 {
217 setInterceptsMouseClicks (false, true);
218
219 const bool isReadOnly = owner.isCommandReadOnly (commandID);
220
221 auto keyPresses = owner.getMappings().getKeyPressesAssignedToCommand (commandID);
222
223 for (int i = 0; i < jmin ((int) maxNumAssignments, keyPresses.size()); ++i)
224 addKeyPressButton (owner.getDescriptionForKeyPress (keyPresses.getReference (i)), i, isReadOnly);
225
226 addKeyPressButton ("Change Key Mapping", -1, isReadOnly);
227 }
228
229 void addKeyPressButton (const String& desc, const int index, const bool isReadOnly)
230 {
231 auto* b = new ChangeKeyButton (owner, commandID, desc, index);
232 keyChangeButtons.add (b);
233
234 b->setEnabled (! isReadOnly);
235 b->setVisible (keyChangeButtons.size() <= (int) maxNumAssignments);
237 }
238
239 void paint (Graphics& g) override
240 {
241 g.setFont ((float) getHeight() * 0.7f);
243
245 4, 0, jmax (40, getChildComponent (0)->getX() - 5), getHeight(),
247 }
248
249 void resized() override
250 {
251 int x = getWidth() - 4;
252
253 for (int i = keyChangeButtons.size(); --i >= 0;)
254 {
255 auto* b = keyChangeButtons.getUnchecked (i);
256
257 b->fitToContent (getHeight() - 2);
258 b->setTopRightPosition (x, 1);
259 x = b->getX() - 5;
260 }
261 }
262
263private:
264 std::unique_ptr<AccessibilityHandler> createAccessibilityHandler() override
265 {
267 }
268
270 OwnedArray<ChangeKeyButton> keyChangeButtons;
271 const CommandID commandID;
272
273 enum { maxNumAssignments = 3 };
274
276};
277
278//==============================================================================
280{
281public:
283 : owner (kec), commandID (command)
284 {}
285
286 String getUniqueName() const override { return String ((int) commandID) + "_id"; }
287 bool mightContainSubItems() override { return false; }
288 int getItemHeight() const override { return 20; }
289 std::unique_ptr<Component> createItemComponent() override { return std::make_unique<ItemComponent> (owner, commandID); }
290 String getAccessibilityName() override { return TRANS (owner.getCommandManager().getNameOfCommand (commandID)); }
291
292private:
294 const CommandID commandID;
295
297};
298
299
300//==============================================================================
302{
303public:
305 : owner (kec), categoryName (name)
306 {}
307
308 String getUniqueName() const override { return categoryName + "_cat"; }
309 bool mightContainSubItems() override { return true; }
310 int getItemHeight() const override { return 22; }
311 String getAccessibilityName() override { return categoryName; }
312
313 void paintItem (Graphics& g, int width, int height) override
314 {
315 g.setFont (Font ((float) height * 0.7f, Font::bold));
317
318 g.drawText (TRANS (categoryName), 2, 0, width - 2, height, Justification::centredLeft, true);
319 }
320
321 void itemOpennessChanged (bool isNowOpen) override
322 {
323 if (isNowOpen)
324 {
325 if (getNumSubItems() == 0)
326 for (auto command : owner.getCommandManager().getCommandsInCategory (categoryName))
327 if (owner.shouldCommandBeIncluded (command))
328 addSubItem (new MappingItem (owner, command));
329 }
330 else
331 {
333 }
334 }
335
336private:
338 String categoryName;
339
341};
342
343//==============================================================================
345 private ChangeListener
346{
347public:
349 {
351 owner.getMappings().addChangeListener (this);
352 }
353
354 ~TopLevelItem() override
355 {
356 owner.getMappings().removeChangeListener (this);
357 }
358
359 bool mightContainSubItems() override { return true; }
360 String getUniqueName() const override { return "keys"; }
361
363 {
366
367 for (auto category : owner.getCommandManager().getCommandCategories())
368 {
369 int count = 0;
370
371 for (auto command : owner.getCommandManager().getCommandsInCategory (category))
372 if (owner.shouldCommandBeIncluded (command))
373 ++count;
374
375 if (count > 0)
376 addSubItem (new CategoryItem (owner, category));
377 }
378 }
379
380private:
382};
383
384//==============================================================================
386 const bool showResetToDefaultButton)
387 : mappings (mappingManager),
388 resetButton (TRANS ("reset to defaults"))
389{
390 treeItem.reset (new TopLevelItem (*this));
391
393 {
394 addAndMakeVisible (resetButton);
395
396 resetButton.onClick = [this]
397 {
399 TRANS ("Reset to defaults"),
400 TRANS ("Are you sure you want to reset all the key-mappings to their default state?"),
401 TRANS ("Reset"),
402 {},
403 this);
404 messageBox = AlertWindow::showScopedAsync (options, [this] (int result)
405 {
406 if (result != 0)
407 getMappings().resetToDefaultMappings();
408 });
409 };
410 }
411
412 addAndMakeVisible (tree);
413 tree.setTitle ("Key Mappings");
415 tree.setRootItemVisible (false);
416 tree.setDefaultOpenness (true);
417 tree.setRootItem (treeItem.get());
418 tree.setIndentSize (12);
419}
420
425
426//==============================================================================
434
436{
437 treeItem->changeListenerCallback (nullptr);
438}
439
441{
442 int h = getHeight();
443
444 if (resetButton.isVisible())
445 {
446 const int buttonHeight = 20;
447 h -= buttonHeight + 8;
448 int x = getWidth() - 8;
449
450 resetButton.changeWidthToFitText (buttonHeight);
451 resetButton.setTopRightPosition (x, h + 6);
452 }
453
454 tree.setBounds (0, 0, getWidth(), h);
455}
456
457//==============================================================================
459{
460 auto* ci = mappings.getCommandManager().getCommandForID (commandID);
461
462 return ci != nullptr && (ci->flags & ApplicationCommandInfo::hiddenFromKeyEditor) == 0;
463}
464
466{
467 auto* ci = mappings.getCommandManager().getCommandForID (commandID);
468
469 return ci != nullptr && (ci->flags & ApplicationCommandInfo::readOnlyInKeyEditor) != 0;
470}
471
476
477} // namespace juce
A window that displays a message and has buttons for the user to react to it.
void addButton(const String &name, int returnValue, const KeyPress &shortcutKey1=KeyPress(), const KeyPress &shortcutKey2=KeyPress())
Adds a button to the window.
void setMessage(const String &message)
Changes the dialog box's message.
static ScopedMessageBox showScopedAsync(const MessageBoxOptions &options, std::function< void(int)> callback)
Shows an alert window using the specified options.
Array< CommandID > getCommandsInCategory(const String &categoryName) const
Returns a list of all the command UIDs in a particular category.
String getNameOfCommand(CommandID commandID) const noexcept
Returns the name field for a command.
StringArray getCommandCategories() const
Returns the list of categories.
const ApplicationCommandInfo * getCommandForID(CommandID commandID) const noexcept
Returns the details about a given command ID.
A base class for buttons.
Definition juce_Button.h:43
virtual void clicked()
This method is called when the button has been clicked.
void setTriggeredOnMouseDown(bool isTriggeredOnMouseDown) noexcept
Sets whether the button click should happen when the mouse is pressed or released.
std::function< void()> onClick
You can assign a lambda to this callback object to have it called when the button is clicked.
void setTooltip(const String &newTooltip) override
Sets the tooltip for this button.
Holds a list of ChangeListeners, and sends messages to them when instructed.
void addChangeListener(ChangeListener *listener)
Registers a listener to receive change callbacks from this broadcaster.
void removeChangeListener(ChangeListener *listener)
Unregisters a listener from the list.
Receives change event callbacks that are sent out by a ChangeBroadcaster.
Represents a colour, also including a transparency value.
Definition juce_Colour.h:38
Holds a pointer to some type of Component, which automatically becomes null if the component is delet...
The base class for all JUCE user-interface objects.
void setInterceptsMouseClicks(bool allowClicksOnThisComponent, bool allowClicksOnChildComponents) noexcept
Changes the default return value for the hitTest() method.
bool isVisible() const noexcept
Tests whether the component is visible or not.
void setTitle(const String &newTitle)
Sets the title for this component.
int getHeight() const noexcept
Returns the component's height in pixels.
void grabKeyboardFocus()
Tries to give keyboard focus to this component.
int getX() const noexcept
Returns the x coordinate of the component's left edge.
void setTopRightPosition(int x, int y)
Moves the component to a new position.
void addAndMakeVisible(Component *child, int zOrder=-1)
Adds a child component to this one, and also makes the child visible if it isn't already.
Component * getChildComponent(int index) const noexcept
Returns one of this component's child components, by it index.
void setBounds(int x, int y, int width, int height)
Changes the component's position and size.
void setSize(int newWidth, int newHeight)
Changes the size of the component.
void setColour(int colourID, Colour newColour)
Registers a colour to be used for a particular purpose.
void setWantsKeyboardFocus(bool wantsFocus) noexcept
Sets a flag to indicate whether this component wants keyboard focus or not.
Colour findColour(int colourID, bool inheritFromParent=false) const
Looks for a colour that has been registered with the given colour ID number.
int getWidth() const noexcept
Returns the component's width in pixels.
LookAndFeel & getLookAndFeel() const noexcept
Finds the appropriate look-and-feel to use for this component.
void addChildComponent(Component *child, int zOrder=-1)
Adds a child component to this one.
const Array< Component * > & getChildren() const noexcept
Provides access to the underlying array of child components.
String getName() const noexcept
Returns the name of this component.
Represents a particular font, including its size, style, etc.
Definition juce_Font.h:42
@ bold
boldens the font.
Definition juce_Font.h:51
A graphics context, used for drawing a component or image.
void drawText(const String &text, int x, int y, int width, int height, Justification justificationType, bool useEllipsesIfTooBig=true) const
Draws a line of text within a specified rectangle.
void drawFittedText(const String &text, int x, int y, int width, int height, Justification justificationFlags, int maximumNumberOfLines, float minimumHorizontalScale=0.0f) const
Tries to draw a text string inside a given space.
void setFont(const Font &newFont)
Changes the font to use for subsequent text-drawing functions.
void setColour(Colour newColour)
Changes the current drawing colour.
@ centredLeft
Indicates that the item should be centred vertically but placed on the left hand side.
void itemOpennessChanged(bool isNowOpen) override
Called when an item is opened or closed.
String getAccessibilityName() override
Use this to set the name for this item that will be read out by accessibility clients.
int getItemHeight() const override
Must return the height required by this item.
bool mightContainSubItems() override
Tells the tree whether this item can potentially be opened.
void paintItem(Graphics &g, int width, int height) override
Draws the item's contents.
String getUniqueName() const override
Returns a string to uniquely identify this item.
bool keyStateChanged(bool) override
Called when a key is pressed or released.
bool keyPressed(const KeyPress &key) override
Called when a key is pressed.
void clicked() override
This method is called when the button has been clicked.
void paintButton(Graphics &g, bool, bool) override
Subclasses should override this to actually paint the button's contents.
void resized() override
Called when this component's size has been changed.
void paint(Graphics &g) override
Components can override this method to draw their content.
String getUniqueName() const override
Returns a string to uniquely identify this item.
std::unique_ptr< Component > createItemComponent() override
Creates a component that will be used to represent this item.
String getAccessibilityName() override
Use this to set the name for this item that will be read out by accessibility clients.
bool mightContainSubItems() override
Tells the tree whether this item can potentially be opened.
int getItemHeight() const override
Must return the height required by this item.
String getUniqueName() const override
Returns a string to uniquely identify this item.
void changeListenerCallback(ChangeBroadcaster *) override
Your subclass should implement this method to receive the callback.
bool mightContainSubItems() override
Tells the tree whether this item can potentially be opened.
A component to allow editing of the keymaps stored by a KeyPressMappingSet object.
@ backgroundColourId
The background colour to fill the editor background.
void setColours(Colour mainBackground, Colour textColour)
Sets up the colours to use for parts of the component.
virtual bool isCommandReadOnly(CommandID commandID)
Can be overridden to indicate that some commands are shown as read-only.
virtual bool shouldCommandBeIncluded(CommandID commandID)
Can be overridden if some commands need to be excluded from the list.
void parentHierarchyChanged() override
Called to indicate that the component's parents have changed.
ApplicationCommandManager & getCommandManager() const noexcept
Returns the ApplicationCommandManager that this component is connected to.
void resized() override
Called when this component's size has been changed.
virtual String getDescriptionForKeyPress(const KeyPress &key)
This can be overridden to let you change the format of the string used to describe a keypress.
KeyPressMappingSet & getMappings() const noexcept
Returns the KeyPressMappingSet that this component is acting upon.
KeyMappingEditorComponent(KeyPressMappingSet &mappingSet, bool showResetToDefaultButton)
Creates a KeyMappingEditorComponent.
Manages and edits a list of keypresses, which it uses to invoke the appropriate command in an Applica...
void addKeyPress(CommandID commandID, const KeyPress &newKeyPress, int insertIndex=-1)
Assigns a keypress to a command.
Array< KeyPress > getKeyPressesAssignedToCommand(CommandID commandID) const
Returns a list of keypresses that are assigned to a particular command.
void removeKeyPress(CommandID commandID, int keyPressIndex)
Removes one of the keypresses that are assigned to a command.
CommandID findCommandForKeyPress(const KeyPress &keyPress) const noexcept
Looks for a command that corresponds to a keypress.
Represents a key press, including any modifier keys that are needed.
String getTextDescription() const
Creates a textual description of the key combination.
static MessageBoxOptions makeOptionsOkCancel(MessageBoxIconType iconType, const String &title, const String &message, const String &button1Text=String(), const String &button2Text=String(), Component *associatedComponent=nullptr)
Creates options suitable for a message box with two buttons.
static ModalComponentManager::Callback * forComponent(void(*functionToCall)(int, ComponentType *), ComponentType *component)
This is a utility function to create a ModalComponentManager::Callback that will call a static functi...
An array designed for holding objects.
Class used to create a set of options to pass to the show() method.
Options withTargetComponent(Component *targetComponent) const
Sets the target component to use when displaying the menu.
Creates and displays a popup-menu.
void addSeparator()
Appends a separator to the menu, to help break it up into sections.
void showMenuAsync(const Options &options)
Runs the menu asynchronously.
void addItem(Item newItem)
Adds an item to the menu.
The JUCE String class!
Definition juce_String.h:53
String replace(StringRef stringToReplace, StringRef stringToInsertInstead, bool ignoreCase=false) const
Replaces all occurrences of a substring with another string.
void changeWidthToFitText()
Changes this button's width to fit neatly around its current text, without changing its height.
This handy class takes a copy of a TreeViewItem's openness when you create it, and restores that open...
An item in a TreeView.
void clearSubItems()
Removes any sub-items.
int getNumSubItems() const noexcept
Returns the number of sub-items that have been added to this item.
void setLinesDrawnForSubItems(bool shouldDrawLines) noexcept
Changes whether lines are drawn to connect any sub-items to this item.
void addSubItem(TreeViewItem *newItem, int insertPosition=-1)
Adds a sub-item.
@ backgroundColourId
A background colour to fill the component with.
void setDefaultOpenness(bool isOpenByDefault)
Sets whether items are open or closed by default.
void setIndentSize(int newIndentSize)
Changes the distance by which each nested level of the tree is indented.
void setRootItem(TreeViewItem *newRootItem)
Sets the item that is displayed in the TreeView.
void setRootItemVisible(bool shouldBeVisible)
Changes whether the tree's root item is shown or not.
#define TRANS(stringLiteral)
Uses the LocalisedStrings class to translate the given string literal.
#define JUCE_DECLARE_NON_COPYABLE(className)
This is a shorthand macro for deleting a class's copy constructor and copy assignment operator.
#define JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(className)
This is a shorthand way of writing both a JUCE_DECLARE_NON_COPYABLE and JUCE_LEAK_DETECTOR macro for ...
JUCE Namespace.
constexpr Type jmin(Type a, Type b)
Returns the smaller of two values.
constexpr Type jmax(Type a, Type b)
Returns the larger of two values.
@ WarningIcon
An exclamation mark to indicate that the dialog is a warning about something and shouldn't be ignored...
@ QuestionIcon
A question-mark icon, for dialog boxes that need the user to answer a question.
@ NoIcon
No icon will be shown on the dialog box.
Type jlimit(Type lowerLimit, Type upperLimit, Type valueToConstrain) noexcept
Constrains a value to keep it within a given range.
Type unalignedPointerCast(void *ptr) noexcept
Casts a pointer to another type via void*, which suppresses the cast-align warning which sometimes ar...
Definition juce_Memory.h:88
int CommandID
A type used to hold the unique ID for an application command.
@ readOnlyInKeyEditor
If this flag is present, then a KeyMappingEditorComponent will display the command in its list,...
@ hiddenFromKeyEditor
If this flag is present, then a KeyMappingEditorComponent will not display the command in its list.