|
- /*
- ==============================================================================
-
- This file is part of the JUCE library - "Jules' Utility Class Extensions"
- Copyright 2004-9 by Raw Material Software Ltd.
-
- ------------------------------------------------------------------------------
-
- JUCE can be redistributed and/or modified under the terms of the GNU General
- Public License (Version 2), as published by the Free Software Foundation.
- A copy of the license is included in the JUCE distribution, or can be found
- online at www.gnu.org/licenses.
-
- JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- ------------------------------------------------------------------------------
-
- To release a closed-source product which uses JUCE, commercial licenses are
- available: visit www.rawmaterialsoftware.com/juce for more information.
-
- ==============================================================================
- */
-
- #include "../../../core/juce_StandardHeader.h"
-
- BEGIN_JUCE_NAMESPACE
-
- // N.B. these two includes are put here deliberately to avoid problems with
- // old GCCs failing on long include paths
- #include "../../../containers/juce_VoidArray.h"
- #include "../../../containers/juce_OwnedArray.h"
-
- #include "juce_KeyMappingEditorComponent.h"
- #include "../menus/juce_PopupMenu.h"
- #include "../windows/juce_AlertWindow.h"
- #include "../../../text/juce_LocalisedStrings.h"
-
- const int maxKeys = 3;
-
- //==============================================================================
- class KeyMappingChangeButton : public Button
- {
- public:
- KeyMappingChangeButton (KeyMappingEditorComponent* const owner_,
- const CommandID commandID_,
- const String& keyName,
- const int keyNum_)
- : Button (keyName),
- owner (owner_),
- commandID (commandID_),
- keyNum (keyNum_)
- {
- setWantsKeyboardFocus (false);
- setTriggeredOnMouseDown (keyNum >= 0);
-
- if (keyNum_ < 0)
- setTooltip (TRANS("adds a new key-mapping"));
- else
- setTooltip (TRANS("click to change this key-mapping"));
- }
-
- ~KeyMappingChangeButton()
- {
- }
-
- void paintButton (Graphics& g, bool isOver, bool isDown)
- {
- if (keyNum >= 0)
- {
- if (isEnabled())
- {
- const float alpha = isDown ? 0.3f : (isOver ? 0.15f : 0.08f);
- g.fillAll (owner->textColour.withAlpha (alpha));
-
- g.setOpacity (0.3f);
- g.drawBevel (0, 0, getWidth(), getHeight(), 2);
- }
-
- g.setColour (owner->textColour);
- g.setFont (getHeight() * 0.6f);
- g.drawFittedText (getName(),
- 3, 0, getWidth() - 6, getHeight(),
- Justification::centred, 1);
- }
- else
- {
- const float thickness = 7.0f;
- const float indent = 22.0f;
-
- Path p;
- p.addEllipse (0.0f, 0.0f, 100.0f, 100.0f);
- p.addRectangle (indent, 50.0f - thickness, 100.0f - indent * 2.0f, thickness * 2.0f);
- p.addRectangle (50.0f - thickness, indent, thickness * 2.0f, 50.0f - indent - thickness);
- p.addRectangle (50.0f - thickness, 50.0f + thickness, thickness * 2.0f, 50.0f - indent - thickness);
- p.setUsingNonZeroWinding (false);
-
- g.setColour (owner->textColour.withAlpha (isDown ? 0.7f : (isOver ? 0.5f : 0.3f)));
- g.fillPath (p, p.getTransformToScaleToFit (2.0f, 2.0f, getWidth() - 4.0f, getHeight() - 4.0f, true));
- }
-
- if (hasKeyboardFocus (false))
- {
- g.setColour (owner->textColour.withAlpha (0.4f));
- g.drawRect (0, 0, getWidth(), getHeight());
- }
- }
-
- void clicked()
- {
- if (keyNum >= 0)
- {
- // existing key clicked..
- PopupMenu m;
- m.addItem (1, TRANS("change this key-mapping"));
- m.addSeparator();
- m.addItem (2, TRANS("remove this key-mapping"));
-
- const int res = m.show();
-
- if (res == 1)
- {
- owner->assignNewKey (commandID, keyNum);
- }
- else if (res == 2)
- {
- owner->getMappings()->removeKeyPress (commandID, keyNum);
- }
- }
- else
- {
- // + button pressed..
- owner->assignNewKey (commandID, -1);
- }
- }
-
- void fitToContent (const int h) throw()
- {
- if (keyNum < 0)
- {
- setSize (h, h);
- }
- else
- {
- Font f (h * 0.6f);
- setSize (jlimit (h * 4, h * 8, 6 + f.getStringWidth (getName())), h);
- }
- }
-
- juce_UseDebuggingNewOperator
-
- private:
- KeyMappingEditorComponent* const owner;
- const CommandID commandID;
- const int keyNum;
-
- KeyMappingChangeButton (const KeyMappingChangeButton&);
- const KeyMappingChangeButton& operator= (const KeyMappingChangeButton&);
- };
-
- //==============================================================================
- class KeyMappingItemComponent : public Component
- {
- public:
- KeyMappingItemComponent (KeyMappingEditorComponent* const owner_,
- const CommandID commandID_)
- : owner (owner_),
- commandID (commandID_)
- {
- setInterceptsMouseClicks (false, true);
-
- const bool isReadOnly = owner_->isCommandReadOnly (commandID);
-
- const Array <KeyPress> keyPresses (owner_->getMappings()->getKeyPressesAssignedToCommand (commandID));
-
- for (int i = 0; i < jmin (maxKeys, keyPresses.size()); ++i)
- {
- KeyMappingChangeButton* const kb
- = new KeyMappingChangeButton (owner_, commandID,
- owner_->getDescriptionForKeyPress (keyPresses.getReference (i)), i);
-
- kb->setEnabled (! isReadOnly);
- addAndMakeVisible (kb);
- }
-
- KeyMappingChangeButton* const kb
- = new KeyMappingChangeButton (owner_, commandID, String::empty, -1);
-
- addChildComponent (kb);
- kb->setVisible (keyPresses.size() < maxKeys && ! isReadOnly);
- }
-
- ~KeyMappingItemComponent()
- {
- deleteAllChildren();
- }
-
- void paint (Graphics& g)
- {
- g.setFont (getHeight() * 0.7f);
- g.setColour (owner->textColour);
-
- g.drawFittedText (owner->getMappings()->getCommandManager()->getNameOfCommand (commandID),
- 4, 0, jmax (40, getChildComponent (0)->getX() - 5), getHeight(),
- Justification::centredLeft, true);
- }
-
- void resized()
- {
- int x = getWidth() - 4;
-
- for (int i = getNumChildComponents(); --i >= 0;)
- {
- KeyMappingChangeButton* const kb = dynamic_cast <KeyMappingChangeButton*> (getChildComponent (i));
-
- kb->fitToContent (getHeight() - 2);
- kb->setTopRightPosition (x, 1);
- x -= kb->getWidth() + 5;
- }
- }
-
- juce_UseDebuggingNewOperator
-
- private:
- KeyMappingEditorComponent* const owner;
- const CommandID commandID;
-
- KeyMappingItemComponent (const KeyMappingItemComponent&);
- const KeyMappingItemComponent& operator= (const KeyMappingItemComponent&);
- };
-
- //==============================================================================
- class KeyMappingTreeViewItem : public TreeViewItem
- {
- public:
- KeyMappingTreeViewItem (KeyMappingEditorComponent* const owner_,
- const CommandID commandID_)
- : owner (owner_),
- commandID (commandID_)
- {
- }
-
- ~KeyMappingTreeViewItem()
- {
- }
-
- const String getUniqueName() const { return String ((int) commandID) + "_id"; }
- bool mightContainSubItems() { return false; }
- int getItemHeight() const { return 20; }
-
- Component* createItemComponent()
- {
- return new KeyMappingItemComponent (owner, commandID);
- }
-
- juce_UseDebuggingNewOperator
-
- private:
- KeyMappingEditorComponent* const owner;
- const CommandID commandID;
-
- KeyMappingTreeViewItem (const KeyMappingTreeViewItem&);
- const KeyMappingTreeViewItem& operator= (const KeyMappingTreeViewItem&);
- };
-
-
- //==============================================================================
- class KeyCategoryTreeViewItem : public TreeViewItem
- {
- public:
- KeyCategoryTreeViewItem (KeyMappingEditorComponent* const owner_,
- const String& name)
- : owner (owner_),
- categoryName (name)
- {
- }
-
- ~KeyCategoryTreeViewItem()
- {
- }
-
- const String getUniqueName() const { return categoryName + "_cat"; }
- bool mightContainSubItems() { return true; }
- int getItemHeight() const { return 28; }
-
- void paintItem (Graphics& g, int width, int height)
- {
- g.setFont (height * 0.6f, Font::bold);
- g.setColour (owner->textColour);
-
- g.drawText (categoryName,
- 2, 0, width - 2, height,
- Justification::centredLeft, true);
- }
-
- void itemOpennessChanged (bool isNowOpen)
- {
- if (isNowOpen)
- {
- if (getNumSubItems() == 0)
- {
- Array <CommandID> commands (owner->getMappings()->getCommandManager()->getCommandsInCategory (categoryName));
-
- for (int i = 0; i < commands.size(); ++i)
- {
- if (owner->shouldCommandBeIncluded (commands[i]))
- addSubItem (new KeyMappingTreeViewItem (owner, commands[i]));
- }
- }
- }
- else
- {
- clearSubItems();
- }
- }
-
- juce_UseDebuggingNewOperator
-
- private:
- KeyMappingEditorComponent* owner;
- String categoryName;
-
- KeyCategoryTreeViewItem (const KeyCategoryTreeViewItem&);
- const KeyCategoryTreeViewItem& operator= (const KeyCategoryTreeViewItem&);
- };
-
-
- //==============================================================================
- KeyMappingEditorComponent::KeyMappingEditorComponent (KeyPressMappingSet* const mappingManager,
- const bool showResetToDefaultButton)
- : mappings (mappingManager),
- textColour (Colours::black)
- {
- jassert (mappingManager != 0); // can't be null!
-
- mappingManager->addChangeListener (this);
-
- setLinesDrawnForSubItems (false);
-
- resetButton = 0;
-
- if (showResetToDefaultButton)
- {
- addAndMakeVisible (resetButton = new TextButton (TRANS("reset to defaults")));
- resetButton->addButtonListener (this);
- }
-
- addAndMakeVisible (tree = new TreeView());
- tree->setColour (TreeView::backgroundColourId, backgroundColour);
- tree->setRootItemVisible (false);
- tree->setDefaultOpenness (true);
- tree->setRootItem (this);
- }
-
- KeyMappingEditorComponent::~KeyMappingEditorComponent()
- {
- mappings->removeChangeListener (this);
- deleteAllChildren();
- }
-
- //==============================================================================
- bool KeyMappingEditorComponent::mightContainSubItems()
- {
- return true;
- }
-
- const String KeyMappingEditorComponent::getUniqueName() const
- {
- return T("keys");
- }
-
- void KeyMappingEditorComponent::setColours (const Colour& mainBackground,
- const Colour& textColour_)
- {
- backgroundColour = mainBackground;
- textColour = textColour_;
- tree->setColour (TreeView::backgroundColourId, backgroundColour);
- }
-
- void KeyMappingEditorComponent::parentHierarchyChanged()
- {
- changeListenerCallback (0);
- }
-
- void KeyMappingEditorComponent::resized()
- {
- int h = getHeight();
-
- if (resetButton != 0)
- {
- const int buttonHeight = 20;
- h -= buttonHeight + 8;
- int x = getWidth() - 8;
- const int y = h + 6;
-
- resetButton->changeWidthToFitText (buttonHeight);
- resetButton->setTopRightPosition (x, y);
- }
-
- tree->setBounds (0, 0, getWidth(), h);
- }
-
- void KeyMappingEditorComponent::buttonClicked (Button* button)
- {
- if (button == resetButton)
- {
- if (AlertWindow::showOkCancelBox (AlertWindow::QuestionIcon,
- TRANS("Reset to defaults"),
- TRANS("Are you sure you want to reset all the key-mappings to their default state?"),
- TRANS("Reset")))
- {
- mappings->resetToDefaultMappings();
- }
- }
- }
-
- void KeyMappingEditorComponent::changeListenerCallback (void*)
- {
- XmlElement* openness = tree->getOpennessState (true);
-
- clearSubItems();
-
- const StringArray categories (mappings->getCommandManager()->getCommandCategories());
-
- for (int i = 0; i < categories.size(); ++i)
- {
- const Array <CommandID> commands (mappings->getCommandManager()->getCommandsInCategory (categories[i]));
- int count = 0;
-
- for (int j = 0; j < commands.size(); ++j)
- if (shouldCommandBeIncluded (commands[j]))
- ++count;
-
- if (count > 0)
- addSubItem (new KeyCategoryTreeViewItem (this, categories[i]));
- }
-
- if (openness != 0)
- {
- tree->restoreOpennessState (*openness);
- delete openness;
- }
- }
-
- //==============================================================================
- class KeyEntryWindow : public AlertWindow
- {
- public:
- KeyEntryWindow (KeyMappingEditorComponent* const owner_)
- : AlertWindow (TRANS("New key-mapping"),
- TRANS("Please press a key combination now..."),
- AlertWindow::NoIcon),
- owner (owner_)
- {
- addButton (TRANS("ok"), 1);
- addButton (TRANS("cancel"), 0);
-
- // (avoid return + escape keys getting processed by the buttons..)
- for (int i = getNumChildComponents(); --i >= 0;)
- getChildComponent (i)->setWantsKeyboardFocus (false);
-
- setWantsKeyboardFocus (true);
- grabKeyboardFocus();
- }
-
- ~KeyEntryWindow()
- {
- }
-
- bool keyPressed (const KeyPress& key)
- {
- lastPress = key;
- String message (TRANS("Key: ") + owner->getDescriptionForKeyPress (key));
-
- const CommandID previousCommand = owner->getMappings()->findCommandForKeyPress (key);
-
- if (previousCommand != 0)
- {
- message << "\n\n"
- << TRANS("(Currently assigned to \"")
- << owner->getMappings()->getCommandManager()->getNameOfCommand (previousCommand)
- << "\")";
- }
-
- setMessage (message);
-
- return true;
- }
-
- bool keyStateChanged (const bool)
- {
- return true;
- }
-
- KeyPress lastPress;
-
- juce_UseDebuggingNewOperator
-
- private:
- KeyMappingEditorComponent* owner;
-
- KeyEntryWindow (const KeyEntryWindow&);
- const KeyEntryWindow& operator= (const KeyEntryWindow&);
- };
-
-
- void KeyMappingEditorComponent::assignNewKey (const CommandID commandID, const int index)
- {
- KeyEntryWindow entryWindow (this);
-
- if (entryWindow.runModalLoop() != 0)
- {
- entryWindow.setVisible (false);
-
- if (entryWindow.lastPress.isValid())
- {
- const CommandID previousCommand = mappings->findCommandForKeyPress (entryWindow.lastPress);
-
- if (previousCommand != 0)
- {
- if (! AlertWindow::showOkCancelBox (AlertWindow::WarningIcon,
- TRANS("Change key-mapping"),
- TRANS("This key is already assigned to the command \"")
- + mappings->getCommandManager()->getNameOfCommand (previousCommand)
- + TRANS("\"\n\nDo you want to re-assign it to this new command instead?"),
- TRANS("re-assign"),
- TRANS("cancel")))
- {
- return;
- }
- }
-
- mappings->removeKeyPress (entryWindow.lastPress);
-
- if (index >= 0)
- mappings->removeKeyPress (commandID, index);
-
- mappings->addKeyPress (commandID, entryWindow.lastPress, index);
- }
- }
- }
-
-
- //==============================================================================
- bool KeyMappingEditorComponent::shouldCommandBeIncluded (const CommandID commandID)
- {
- const ApplicationCommandInfo* const ci = mappings->getCommandManager()->getCommandForID (commandID);
-
- return (ci != 0) && ((ci->flags & ApplicationCommandInfo::hiddenFromKeyEditor) == 0);
- }
-
- bool KeyMappingEditorComponent::isCommandReadOnly (const CommandID commandID)
- {
- const ApplicationCommandInfo* const ci = mappings->getCommandManager()->getCommandForID (commandID);
-
- return (ci != 0) && ((ci->flags & ApplicationCommandInfo::readOnlyInKeyEditor) != 0);
- }
-
- const String KeyMappingEditorComponent::getDescriptionForKeyPress (const KeyPress& key)
- {
- return key.getTextDescription();
- }
-
- END_JUCE_NAMESPACE
|