| @@ -57,7 +57,7 @@ public: | |||
| area.removeFromTop (10); | |||
| area.reduce (5, 5); | |||
| Rectangle<int> topArea (area.removeFromTop (34)); | |||
| auto topArea = area.removeFromTop (34); | |||
| topArea.removeFromLeft (110); | |||
| bitSize.setBounds (topArea.removeFromLeft (topArea.getWidth() / 2).reduced (5)); | |||
| generateRSAButton.setBounds (topArea.reduced (5)); | |||
| @@ -123,8 +123,7 @@ private: | |||
| }; | |||
| //============================================================================== | |||
| class HashesComponent : public Component, | |||
| private TextEditor::Listener | |||
| class HashesComponent : public Component | |||
| { | |||
| public: | |||
| HashesComponent() | |||
| @@ -137,7 +136,17 @@ public: | |||
| hashEntryBox.setReturnKeyStartsNewLine (true); | |||
| hashEntryBox.setText ("Type some text in this box and the resulting MD5, SHA and Whirlpool hashes will update below"); | |||
| hashEntryBox.addListener (this); | |||
| auto updateHashes = [this]() | |||
| { | |||
| auto text = hashEntryBox.getText(); | |||
| updateMD5Result (text.toUTF8()); | |||
| updateSHA256Result (text.toUTF8()); | |||
| updateWhirlpoolResult (text.toUTF8()); | |||
| }; | |||
| hashEntryBox.onTextChange = updateHashes; | |||
| hashEntryBox.onReturnKey = updateHashes; | |||
| hashLabel1.setText ("Text to Hash:", dontSendNotification); | |||
| hashLabel2.setText ("MD5 Result:", dontSendNotification); | |||
| @@ -156,14 +165,6 @@ public: | |||
| updateHashes(); | |||
| } | |||
| void updateHashes() | |||
| { | |||
| String text = hashEntryBox.getText(); | |||
| updateMD5Result (text.toUTF8()); | |||
| updateSHA256Result (text.toUTF8()); | |||
| updateWhirlpoolResult (text.toUTF8()); | |||
| } | |||
| void updateMD5Result (CharPointer_UTF8 text) | |||
| { | |||
| md5Result.setText (MD5 (text).toHexString(), dontSendNotification); | |||
| @@ -181,7 +182,7 @@ public: | |||
| void resized() override | |||
| { | |||
| Rectangle<int> area (getLocalBounds()); | |||
| auto area = getLocalBounds(); | |||
| hashGroup.setBounds (area); | |||
| area.removeFromLeft (120); | |||
| area.removeFromTop (10); | |||
| @@ -198,11 +199,6 @@ private: | |||
| Label md5Result, shaResult, whirlpoolResult; | |||
| Label hashLabel1, hashLabel2, hashLabel3, hashLabel4; | |||
| void textEditorTextChanged (TextEditor&) override { updateHashes(); } | |||
| void textEditorReturnKeyPressed (TextEditor&) override { updateHashes(); } | |||
| void textEditorEscapeKeyPressed (TextEditor&) override { updateHashes(); } | |||
| void textEditorFocusLost (TextEditor&) override { updateHashes(); } | |||
| void lookAndFeelChanged() override | |||
| { | |||
| hashGroup.setColour (GroupComponent::outlineColourId, | |||
| @@ -29,27 +29,26 @@ | |||
| // these classes are C++11-only | |||
| #if JUCE_COMPILER_SUPPORTS_INITIALIZER_LISTS | |||
| struct DemoFlexPanel : public juce::Component, | |||
| private juce::TextEditor::Listener | |||
| struct DemoFlexPanel : public juce::Component | |||
| { | |||
| DemoFlexPanel (juce::Colour col, FlexItem& item) : flexItem (item), colour (col) | |||
| { | |||
| int x = 70; | |||
| int y = 3; | |||
| setupTextEditor (flexOrderEditor, { x, y, 20, 18 }, "0"); | |||
| setupTextEditor (flexOrderEditor, { x, y, 20, 18 }, "0", [this]() { flexItem.order = (int) flexOrderEditor.getText().getFloatValue(); }); | |||
| addLabel ("order", flexOrderEditor); | |||
| y += 20; | |||
| setupTextEditor (flexGrowEditor, { x, y, 20, 18 }, "0"); | |||
| setupTextEditor (flexGrowEditor, { x, y, 20, 18 }, "0", [this]() { flexItem.flexGrow = flexGrowEditor.getText().getFloatValue(); }); | |||
| addLabel ("flex-grow", flexGrowEditor); | |||
| y += 20; | |||
| setupTextEditor (flexShrinkEditor, { x, y, 20, 18 }, "1"); | |||
| setupTextEditor (flexShrinkEditor, { x, y, 20, 18 }, "1", [this]() { flexItem.flexShrink = flexShrinkEditor.getText().getFloatValue(); }); | |||
| addLabel ("flex-shrink", flexShrinkEditor); | |||
| y += 20; | |||
| setupTextEditor (flexBasisEditor, { x, y, 33, 18 }, "100"); | |||
| setupTextEditor (flexBasisEditor, { x, y, 33, 18 }, "100", [this]() { flexItem.flexBasis = flexBasisEditor.getText().getFloatValue(); }); | |||
| addLabel ("flex-basis", flexBasisEditor); | |||
| y += 20; | |||
| @@ -67,11 +66,18 @@ struct DemoFlexPanel : public juce::Component, | |||
| addLabel ("align-self", alignSelfCombo); | |||
| } | |||
| void setupTextEditor (TextEditor& te, Rectangle<int> b, StringRef initialText) | |||
| void setupTextEditor (TextEditor& te, Rectangle<int> b, StringRef initialText, std::function<void()> updateFn) | |||
| { | |||
| te.setBounds (b); | |||
| te.setText (initialText); | |||
| te.addListener (this); | |||
| te.onTextChange = [this, updateFn]() | |||
| { | |||
| updateFn(); | |||
| if (auto parent = getParentComponent()) | |||
| parent->resized(); | |||
| }; | |||
| addAndMakeVisible (te); | |||
| } | |||
| @@ -99,19 +105,6 @@ struct DemoFlexPanel : public juce::Component, | |||
| parent->resized(); | |||
| } | |||
| void textEditorTextChanged (TextEditor& textEditor) override | |||
| { | |||
| auto textIntValue = textEditor.getText().getFloatValue(); | |||
| if (&textEditor == &flexOrderEditor) flexItem.order = (int) textIntValue; | |||
| if (&textEditor == &flexGrowEditor) flexItem.flexGrow = textIntValue; | |||
| if (&textEditor == &flexBasisEditor) flexItem.flexBasis = textIntValue; | |||
| if (&textEditor == &flexShrinkEditor) flexItem.flexShrink = textIntValue; | |||
| if (auto parent = getParentComponent()) | |||
| parent->resized(); | |||
| } | |||
| void paint (Graphics& g) override | |||
| { | |||
| auto r = getLocalBounds(); | |||
| @@ -32,8 +32,7 @@ | |||
| flag is used to promt the user to save the note when it is closed. | |||
| */ | |||
| class Note : public Component, | |||
| public FileBasedDocument, | |||
| private TextEditor::Listener | |||
| public FileBasedDocument | |||
| { | |||
| public: | |||
| Note (const String& name, const String& contents) | |||
| @@ -50,12 +49,7 @@ public: | |||
| editor.setReturnKeyStartsNewLine (true); | |||
| editor.getTextValue().referTo (textValueObject); | |||
| addAndMakeVisible (editor); | |||
| editor.addListener (this); | |||
| } | |||
| ~Note() | |||
| { | |||
| editor.removeListener (this); | |||
| editor.onTextChange = [this]() { changed(); }; | |||
| } | |||
| void resized() override | |||
| @@ -107,22 +101,11 @@ private: | |||
| Value textValueObject; | |||
| TextEditor editor; | |||
| void textEditorTextChanged (TextEditor& ed) override | |||
| { | |||
| // let our FileBasedDocument know we've changed | |||
| if (&ed == &editor) | |||
| changed(); | |||
| } | |||
| void lookAndFeelChanged() override | |||
| { | |||
| editor.applyFontToAllText (editor.getFont()); | |||
| } | |||
| void textEditorReturnKeyPressed (TextEditor&) override {} | |||
| void textEditorEscapeKeyPressed (TextEditor&) override {} | |||
| void textEditorFocusLost (TextEditor&) override {} | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Note) | |||
| }; | |||
| @@ -29,7 +29,6 @@ | |||
| //============================================================================== | |||
| class NetworkingDemo : public Component, | |||
| private TextEditor::Listener, | |||
| private Thread | |||
| { | |||
| public: | |||
| @@ -41,7 +40,7 @@ public: | |||
| addAndMakeVisible (urlBox); | |||
| urlBox.setText ("https://www.google.com"); | |||
| urlBox.addListener (this); | |||
| urlBox.onReturnKey = [this]() { fetchButton.triggerClick(); }; | |||
| addAndMakeVisible (fetchButton); | |||
| fetchButton.setButtonText ("Download URL Contents"); | |||
| @@ -106,11 +105,6 @@ private: | |||
| CodeDocument resultsDocument; | |||
| CodeEditorComponent resultsBox; | |||
| void textEditorReturnKeyPressed (TextEditor&) override | |||
| { | |||
| fetchButton.triggerClick(); | |||
| } | |||
| void lookAndFeelChanged() override | |||
| { | |||
| urlBox.applyFontToAllText (urlBox.getFont()); | |||
| @@ -68,21 +68,17 @@ private: | |||
| //============================================================================== | |||
| class WebBrowserDemo : public Component, | |||
| private TextEditor::Listener | |||
| class WebBrowserDemo : public Component | |||
| { | |||
| public: | |||
| WebBrowserDemo() | |||
| : goButton ("Go", "Go to URL"), | |||
| backButton ("<<", "Back"), | |||
| forwardButton (">>", "Forward") | |||
| { | |||
| setOpaque (true); | |||
| // Create an address box.. | |||
| addAndMakeVisible (addressTextBox); | |||
| addressTextBox.setTextToShowWhenEmpty ("Enter a web address, e.g. https://www.juce.com", Colours::grey); | |||
| addressTextBox.addListener (this); | |||
| addressTextBox.onReturnKey = [this]() { webView->goToURL (addressTextBox.getText()); }; | |||
| // create the actual browser component | |||
| addAndMakeVisible (webView = new DemoBrowserComponent (addressTextBox)); | |||
| @@ -118,16 +114,10 @@ private: | |||
| ScopedPointer<DemoBrowserComponent> webView; | |||
| TextEditor addressTextBox; | |||
| TextButton goButton, backButton, forwardButton; | |||
| void textEditorTextChanged (TextEditor&) override {} | |||
| void textEditorEscapeKeyPressed (TextEditor&) override {} | |||
| void textEditorFocusLost (TextEditor&) override {} | |||
| void textEditorReturnKeyPressed (TextEditor&) override | |||
| { | |||
| webView->goToURL (addressTextBox.getText()); | |||
| } | |||
| TextButton goButton { "Go", "Go to URL" }, | |||
| backButton { "<<", "Back" }, | |||
| forwardButton { ">>", "Forward" }; | |||
| void lookAndFeelChanged() override | |||
| { | |||
| @@ -198,8 +198,7 @@ static String getNoDeviceString() { return "<< " + TRANS("none") + " >>"; } | |||
| //============================================================================== | |||
| class AudioDeviceSettingsPanel : public Component, | |||
| private ChangeListener, | |||
| private ComboBox::Listener | |||
| private ChangeListener | |||
| { | |||
| public: | |||
| AudioDeviceSettingsPanel (AudioIODeviceType& t, AudioDeviceSetupDetails& setupDetails, | |||
| @@ -328,17 +327,13 @@ public: | |||
| } | |||
| } | |||
| void comboBoxChanged (ComboBox* comboBoxThatHasChanged) override | |||
| void updateConfig (bool updateOutputDevice, bool updateInputDevice, bool updateSampleRate, bool updateBufferSize) | |||
| { | |||
| if (comboBoxThatHasChanged == nullptr) | |||
| return; | |||
| AudioDeviceManager::AudioDeviceSetup config; | |||
| setup.manager->getAudioDeviceSetup (config); | |||
| String error; | |||
| if (comboBoxThatHasChanged == outputDeviceDropDown | |||
| || comboBoxThatHasChanged == inputDeviceDropDown) | |||
| if (updateOutputDevice || updateInputDevice) | |||
| { | |||
| if (outputDeviceDropDown != nullptr) | |||
| config.outputDeviceName = outputDeviceDropDown->getSelectedId() < 0 ? String() | |||
| @@ -351,7 +346,7 @@ public: | |||
| if (! type.hasSeparateInputsAndOutputs()) | |||
| config.inputDeviceName = config.outputDeviceName; | |||
| if (comboBoxThatHasChanged == inputDeviceDropDown) | |||
| if (updateInputDevice) | |||
| config.useDefaultInputChannels = true; | |||
| else | |||
| config.useDefaultOutputChannels = true; | |||
| @@ -364,7 +359,7 @@ public: | |||
| updateControlPanelButton(); | |||
| resized(); | |||
| } | |||
| else if (comboBoxThatHasChanged == sampleRateDropDown) | |||
| else if (updateSampleRate) | |||
| { | |||
| if (sampleRateDropDown->getSelectedId() > 0) | |||
| { | |||
| @@ -372,7 +367,7 @@ public: | |||
| error = setup.manager->setAudioDeviceSetup (config, true); | |||
| } | |||
| } | |||
| else if (comboBoxThatHasChanged == bufferSizeDropDown) | |||
| else if (updateBufferSize) | |||
| { | |||
| if (bufferSizeDropDown->getSelectedId() > 0) | |||
| { | |||
| @@ -606,7 +601,8 @@ private: | |||
| if (outputDeviceDropDown == nullptr) | |||
| { | |||
| outputDeviceDropDown = new ComboBox(); | |||
| outputDeviceDropDown->addListener (this); | |||
| outputDeviceDropDown->onChange = [this]() { updateConfig (true, false, false, false); }; | |||
| addAndMakeVisible (outputDeviceDropDown); | |||
| outputDeviceLabel = new Label ({}, type.hasSeparateInputsAndOutputs() ? TRANS("Output:") | |||
| @@ -634,7 +630,7 @@ private: | |||
| if (inputDeviceDropDown == nullptr) | |||
| { | |||
| inputDeviceDropDown = new ComboBox(); | |||
| inputDeviceDropDown->addListener (this); | |||
| inputDeviceDropDown->onChange = [this]() { updateConfig (false, true, false, false); }; | |||
| addAndMakeVisible (inputDeviceDropDown); | |||
| inputDeviceLabel = new Label ({}, TRANS("Input:")); | |||
| @@ -662,7 +658,7 @@ private: | |||
| else | |||
| { | |||
| sampleRateDropDown->clear(); | |||
| sampleRateDropDown->removeListener (this); | |||
| sampleRateDropDown->onChange = {}; | |||
| } | |||
| for (auto rate : currentDevice->getAvailableSampleRates()) | |||
| @@ -672,7 +668,7 @@ private: | |||
| } | |||
| sampleRateDropDown->setSelectedId (roundToInt (currentDevice->getCurrentSampleRate()), dontSendNotification); | |||
| sampleRateDropDown->addListener (this); | |||
| sampleRateDropDown->onChange = [this]() { updateConfig (false, false, true, false); }; | |||
| } | |||
| void updateBufferSizeComboBox (AudioIODevice* currentDevice) | |||
| @@ -687,7 +683,7 @@ private: | |||
| else | |||
| { | |||
| bufferSizeDropDown->clear(); | |||
| bufferSizeDropDown->removeListener (this); | |||
| bufferSizeDropDown->onChange = {}; | |||
| } | |||
| auto currentRate = currentDevice->getCurrentSampleRate(); | |||
| @@ -699,7 +695,7 @@ private: | |||
| bufferSizeDropDown->addItem (String (bs) + " samples (" + String (bs * 1000.0 / currentRate, 1) + " ms)", bs); | |||
| bufferSizeDropDown->setSelectedId (currentDevice->getCurrentBufferSizeSamples(), dontSendNotification); | |||
| bufferSizeDropDown->addListener (this); | |||
| bufferSizeDropDown->onChange = [this]() { updateConfig (false, false, false, true); }; | |||
| } | |||
| public: | |||
| @@ -31,7 +31,7 @@ FileBrowserComponent::FileBrowserComponent (int flags_, | |||
| const File& initialFileOrDirectory, | |||
| const FileFilter* fileFilter_, | |||
| FilePreviewComponent* previewComp_) | |||
| : FileFilter (String()), | |||
| : FileFilter ({}), | |||
| fileFilter (fileFilter_), | |||
| flags (flags_), | |||
| previewComp (previewComp_), | |||
| @@ -93,7 +93,7 @@ FileBrowserComponent::FileBrowserComponent (int flags_, | |||
| addAndMakeVisible (currentPathBox); | |||
| currentPathBox.setEditableText (true); | |||
| resetRecentPaths(); | |||
| currentPathBox.addListener (this); | |||
| currentPathBox.onChange = [this]() { updateSelectedPath(); }; | |||
| addAndMakeVisible (filenameBox); | |||
| filenameBox.setMultiLine (false); | |||
| @@ -410,7 +410,7 @@ void FileBrowserComponent::fileDoubleClicked (const File& f) | |||
| setRoot (f); | |||
| if ((flags & canSelectDirectories) != 0 && (flags & doNotClearFileNameOnRootChange) == 0) | |||
| filenameBox.setText (String()); | |||
| filenameBox.setText ({}); | |||
| } | |||
| else | |||
| { | |||
| @@ -455,7 +455,7 @@ void FileBrowserComponent::textEditorReturnKeyPressed (TextEditor&) | |||
| chosenFiles.clear(); | |||
| if ((flags & doNotClearFileNameOnRootChange) == 0) | |||
| filenameBox.setText (String()); | |||
| filenameBox.setText ({}); | |||
| } | |||
| else | |||
| { | |||
| @@ -482,7 +482,7 @@ void FileBrowserComponent::textEditorFocusLost (TextEditor&) | |||
| } | |||
| //============================================================================== | |||
| void FileBrowserComponent::comboBoxChanged (ComboBox*) | |||
| void FileBrowserComponent::updateSelectedPath() | |||
| { | |||
| auto newText = currentPathBox.getText().trim().unquoted(); | |||
| @@ -493,9 +493,9 @@ void FileBrowserComponent::comboBoxChanged (ComboBox*) | |||
| StringArray rootNames, rootPaths; | |||
| getRoots (rootNames, rootPaths); | |||
| if (rootPaths [index].isNotEmpty()) | |||
| if (rootPaths[index].isNotEmpty()) | |||
| { | |||
| setRoot (File (rootPaths [index])); | |||
| setRoot (File (rootPaths[index])); | |||
| } | |||
| else | |||
| { | |||
| @@ -549,8 +549,8 @@ void FileBrowserComponent::getDefaultRoots (StringArray& rootNames, StringArray& | |||
| rootNames.add (name); | |||
| } | |||
| rootPaths.add (String()); | |||
| rootNames.add (String()); | |||
| rootPaths.add ({}); | |||
| rootNames.add ({}); | |||
| rootPaths.add (File::getSpecialLocation (File::userDocumentsDirectory).getFullPathName()); | |||
| rootNames.add (TRANS("Documents")); | |||
| @@ -573,8 +573,8 @@ void FileBrowserComponent::getDefaultRoots (StringArray& rootNames, StringArray& | |||
| rootPaths.add (File::getSpecialLocation (File::userDesktopDirectory).getFullPathName()); | |||
| rootNames.add (TRANS("Desktop")); | |||
| rootPaths.add (String()); | |||
| rootNames.add (String()); | |||
| rootPaths.add ({}); | |||
| rootNames.add ({}); | |||
| Array<File> volumes; | |||
| File vol ("/Volumes"); | |||
| @@ -40,7 +40,6 @@ namespace juce | |||
| class JUCE_API FileBrowserComponent : public Component, | |||
| private FileBrowserListener, | |||
| private TextEditor::Listener, | |||
| private ComboBox::Listener, | |||
| private FileFilter, | |||
| private Timer | |||
| { | |||
| @@ -236,8 +235,6 @@ public: | |||
| /** @internal */ | |||
| void lookAndFeelChanged() override; | |||
| /** @internal */ | |||
| void comboBoxChanged (ComboBox*) override; | |||
| /** @internal */ | |||
| void textEditorTextChanged (TextEditor&) override; | |||
| /** @internal */ | |||
| void textEditorReturnKeyPressed (TextEditor&) override; | |||
| @@ -297,6 +294,7 @@ private: | |||
| void timerCallback() override; | |||
| void sendListenerChangeMessage(); | |||
| bool isFileOrDirSuitable (const File&) const; | |||
| void updateSelectedPath(); | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FileBrowserComponent) | |||
| }; | |||
| @@ -38,9 +38,8 @@ namespace juce | |||
| either be read-only text, or editable. | |||
| To find out when the user selects a different item or edits the text, you | |||
| can register a ComboBox::Listener to receive callbacks. | |||
| @see ComboBox::Listener | |||
| can assign a lambda to the onChange member, or register a ComboBox::Listener | |||
| to receive callbacks. | |||
| */ | |||
| class JUCE_API ComboBox : public Component, | |||
| public SettableTooltipClient, | |||
| @@ -1220,7 +1220,7 @@ void TextEditor::textChanged() | |||
| { | |||
| updateTextHolderSize(); | |||
| if (listeners.size() > 0) | |||
| if (listeners.size() != 0 || onTextChange != nullptr) | |||
| postCommandMessage (TextEditorDefs::textChangeMessageId); | |||
| if (textValue.getValueSource().getReferenceCount() > 1) | |||
| @@ -2099,19 +2099,35 @@ void TextEditor::handleCommandMessage (const int commandId) | |||
| { | |||
| case TextEditorDefs::textChangeMessageId: | |||
| listeners.callChecked (checker, [this] (Listener& l) { l.textEditorTextChanged (*this); }); | |||
| if (! checker.shouldBailOut() && onTextChange != nullptr) | |||
| onTextChange(); | |||
| break; | |||
| case TextEditorDefs::returnKeyMessageId: | |||
| listeners.callChecked (checker, [this] (Listener& l) { l.textEditorReturnKeyPressed (*this); }); | |||
| if (! checker.shouldBailOut() && onReturnKey != nullptr) | |||
| onReturnKey(); | |||
| break; | |||
| case TextEditorDefs::escapeKeyMessageId: | |||
| listeners.callChecked (checker, [this] (Listener& l) { l.textEditorEscapeKeyPressed (*this); }); | |||
| if (! checker.shouldBailOut() && onEscapeKey != nullptr) | |||
| onEscapeKey(); | |||
| break; | |||
| case TextEditorDefs::focusLossMessageId: | |||
| updateValueFromText(); | |||
| listeners.callChecked (checker, [this] (Listener& l) { l.textEditorFocusLost (*this); }); | |||
| if (! checker.shouldBailOut() && onFocusLost != nullptr) | |||
| onFocusLost(); | |||
| break; | |||
| default: | |||
| @@ -318,6 +318,19 @@ public: | |||
| */ | |||
| void removeListener (Listener* listenerToRemove); | |||
| //============================================================================== | |||
| /** You can assign a lambda to this callback object to have it called when the text is changed. */ | |||
| std::function<void()> onTextChange; | |||
| /** You can assign a lambda to this callback object to have it called when the return key is pressed. */ | |||
| std::function<void()> onReturnKey; | |||
| /** You can assign a lambda to this callback object to have it called when the escape key is pressed. */ | |||
| std::function<void()> onEscapeKey; | |||
| /** You can assign a lambda to this callback object to have it called when the editor loses key focus. */ | |||
| std::function<void()> onFocusLost; | |||
| //============================================================================== | |||
| /** Returns the entire contents of the editor. */ | |||
| String getText() const; | |||