| @@ -682,6 +682,7 @@ | |||
| 15C6FD019B274AA51B4E2D76 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_KeyPressMappingSet.h; path = ../../src/gui/components/keyboard/juce_KeyPressMappingSet.h; sourceTree = SOURCE_ROOT; }; | |||
| B1E8FF009812F29C2620E6BB = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_ModifierKeys.cpp; path = ../../src/gui/components/keyboard/juce_ModifierKeys.cpp; sourceTree = SOURCE_ROOT; }; | |||
| FAEEA3536AD17B2667A1BB94 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_ModifierKeys.h; path = ../../src/gui/components/keyboard/juce_ModifierKeys.h; sourceTree = SOURCE_ROOT; }; | |||
| D64DD9F41E4598606855DFCF = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_TextEditorKeyMapper.h; path = ../../src/gui/components/keyboard/juce_TextEditorKeyMapper.h; sourceTree = SOURCE_ROOT; }; | |||
| 7356F5E93CEA4D472D83D8E5 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_TextInputTarget.h; path = ../../src/gui/components/keyboard/juce_TextInputTarget.h; sourceTree = SOURCE_ROOT; }; | |||
| 921B616E2229AEB6390D2B57 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_ComponentAnimator.cpp; path = ../../src/gui/components/layout/juce_ComponentAnimator.cpp; sourceTree = SOURCE_ROOT; }; | |||
| FE1072B5FB77E8FEE1BEBDFE = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_ComponentAnimator.h; path = ../../src/gui/components/layout/juce_ComponentAnimator.h; sourceTree = SOURCE_ROOT; }; | |||
| @@ -1447,6 +1448,7 @@ | |||
| 15C6FD019B274AA51B4E2D76, | |||
| B1E8FF009812F29C2620E6BB, | |||
| FAEEA3536AD17B2667A1BB94, | |||
| D64DD9F41E4598606855DFCF, | |||
| 7356F5E93CEA4D472D83D8E5 ); name = keyboard; sourceTree = "<group>"; }; | |||
| D75AAB3AB61247E962C00692 = { isa = PBXGroup; children = ( | |||
| 921B616E2229AEB6390D2B57, | |||
| @@ -532,6 +532,7 @@ | |||
| <File RelativePath="..\..\src\gui\components\keyboard\juce_KeyPressMappingSet.h"/> | |||
| <File RelativePath="..\..\src\gui\components\keyboard\juce_ModifierKeys.cpp"/> | |||
| <File RelativePath="..\..\src\gui\components\keyboard\juce_ModifierKeys.h"/> | |||
| <File RelativePath="..\..\src\gui\components\keyboard\juce_TextEditorKeyMapper.h"/> | |||
| <File RelativePath="..\..\src\gui\components\keyboard\juce_TextInputTarget.h"/> | |||
| </Filter> | |||
| <Filter Name="layout"> | |||
| @@ -532,6 +532,7 @@ | |||
| <File RelativePath="..\..\src\gui\components\keyboard\juce_KeyPressMappingSet.h"/> | |||
| <File RelativePath="..\..\src\gui\components\keyboard\juce_ModifierKeys.cpp"/> | |||
| <File RelativePath="..\..\src\gui\components\keyboard\juce_ModifierKeys.h"/> | |||
| <File RelativePath="..\..\src\gui\components\keyboard\juce_TextEditorKeyMapper.h"/> | |||
| <File RelativePath="..\..\src\gui\components\keyboard\juce_TextInputTarget.h"/> | |||
| </Filter> | |||
| <Filter Name="layout"> | |||
| @@ -534,6 +534,7 @@ | |||
| <File RelativePath="..\..\src\gui\components\keyboard\juce_KeyPressMappingSet.h"/> | |||
| <File RelativePath="..\..\src\gui\components\keyboard\juce_ModifierKeys.cpp"/> | |||
| <File RelativePath="..\..\src\gui\components\keyboard\juce_ModifierKeys.h"/> | |||
| <File RelativePath="..\..\src\gui\components\keyboard\juce_TextEditorKeyMapper.h"/> | |||
| <File RelativePath="..\..\src\gui\components\keyboard\juce_TextInputTarget.h"/> | |||
| </Filter> | |||
| <Filter Name="layout"> | |||
| @@ -626,6 +626,7 @@ | |||
| <ClInclude Include="..\..\src\gui\components\keyboard\juce_KeyPress.h"/> | |||
| <ClInclude Include="..\..\src\gui\components\keyboard\juce_KeyPressMappingSet.h"/> | |||
| <ClInclude Include="..\..\src\gui\components\keyboard\juce_ModifierKeys.h"/> | |||
| <ClInclude Include="..\..\src\gui\components\keyboard\juce_TextEditorKeyMapper.h"/> | |||
| <ClInclude Include="..\..\src\gui\components\keyboard\juce_TextInputTarget.h"/> | |||
| <ClInclude Include="..\..\src\gui\components\layout\juce_ComponentAnimator.h"/> | |||
| <ClInclude Include="..\..\src\gui\components\layout\juce_ComponentBoundsConstrainer.h"/> | |||
| @@ -1809,6 +1809,9 @@ | |||
| <ClInclude Include="..\..\src\gui\components\keyboard\juce_ModifierKeys.h"> | |||
| <Filter>Juce\Source\gui\components\keyboard</Filter> | |||
| </ClInclude> | |||
| <ClInclude Include="..\..\src\gui\components\keyboard\juce_TextEditorKeyMapper.h"> | |||
| <Filter>Juce\Source\gui\components\keyboard</Filter> | |||
| </ClInclude> | |||
| <ClInclude Include="..\..\src\gui\components\keyboard\juce_TextInputTarget.h"> | |||
| <Filter>Juce\Source\gui\components\keyboard</Filter> | |||
| </ClInclude> | |||
| @@ -682,6 +682,7 @@ | |||
| 15C6FD019B274AA51B4E2D76 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_KeyPressMappingSet.h; path = ../../src/gui/components/keyboard/juce_KeyPressMappingSet.h; sourceTree = SOURCE_ROOT; }; | |||
| B1E8FF009812F29C2620E6BB = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_ModifierKeys.cpp; path = ../../src/gui/components/keyboard/juce_ModifierKeys.cpp; sourceTree = SOURCE_ROOT; }; | |||
| FAEEA3536AD17B2667A1BB94 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_ModifierKeys.h; path = ../../src/gui/components/keyboard/juce_ModifierKeys.h; sourceTree = SOURCE_ROOT; }; | |||
| D64DD9F41E4598606855DFCF = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_TextEditorKeyMapper.h; path = ../../src/gui/components/keyboard/juce_TextEditorKeyMapper.h; sourceTree = SOURCE_ROOT; }; | |||
| 7356F5E93CEA4D472D83D8E5 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_TextInputTarget.h; path = ../../src/gui/components/keyboard/juce_TextInputTarget.h; sourceTree = SOURCE_ROOT; }; | |||
| 921B616E2229AEB6390D2B57 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_ComponentAnimator.cpp; path = ../../src/gui/components/layout/juce_ComponentAnimator.cpp; sourceTree = SOURCE_ROOT; }; | |||
| FE1072B5FB77E8FEE1BEBDFE = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_ComponentAnimator.h; path = ../../src/gui/components/layout/juce_ComponentAnimator.h; sourceTree = SOURCE_ROOT; }; | |||
| @@ -1447,6 +1448,7 @@ | |||
| 15C6FD019B274AA51B4E2D76, | |||
| B1E8FF009812F29C2620E6BB, | |||
| FAEEA3536AD17B2667A1BB94, | |||
| D64DD9F41E4598606855DFCF, | |||
| 7356F5E93CEA4D472D83D8E5 ); name = keyboard; sourceTree = "<group>"; }; | |||
| D75AAB3AB61247E962C00692 = { isa = PBXGroup; children = ( | |||
| 921B616E2229AEB6390D2B57, | |||
| @@ -713,6 +713,8 @@ | |||
| file="src/gui/components/keyboard/juce_ModifierKeys.cpp"/> | |||
| <FILE id="sEv20iWws" name="juce_ModifierKeys.h" compile="0" resource="0" | |||
| file="src/gui/components/keyboard/juce_ModifierKeys.h"/> | |||
| <FILE id="ohA4B9" name="juce_TextEditorKeyMapper.h" compile="0" resource="0" | |||
| file="src/gui/components/keyboard/juce_TextEditorKeyMapper.h"/> | |||
| <FILE id="xafOvZlQw" name="juce_TextInputTarget.h" compile="0" resource="0" | |||
| file="src/gui/components/keyboard/juce_TextInputTarget.h"/> | |||
| </GROUP> | |||
| @@ -73,7 +73,7 @@ namespace JuceDummyNamespace {} | |||
| */ | |||
| #define JUCE_MAJOR_VERSION 1 | |||
| #define JUCE_MINOR_VERSION 53 | |||
| #define JUCE_BUILDNUMBER 89 | |||
| #define JUCE_BUILDNUMBER 90 | |||
| /** Current Juce version number. | |||
| @@ -1647,8 +1647,8 @@ public: | |||
| template <typename CharPointerType> | |||
| static double readDoubleValue (CharPointerType& text) noexcept | |||
| { | |||
| double result[3] = { 0, 0, 0 }, accumulator[2] = { 0, 0 }; | |||
| int exponentAdjustment[2] = { 0, 0 }, exponentAccumulator[2] = { -1, -1 }; | |||
| double result[3] = { 0 }, accumulator[2] = { 0 }; | |||
| int exponentAdjustment[2] = { 0 }, exponentAccumulator[2] = { -1, -1 }; | |||
| int exponent = 0, decPointIndex = 0, digit = 0; | |||
| int lastDigit = 0, numSignificantDigits = 0; | |||
| bool isNegative = false, digitsFound = false; | |||
| @@ -8734,16 +8734,16 @@ public: | |||
| var (ReferenceCountedObject* object); | |||
| var (MethodFunction method) noexcept; | |||
| var& operator= (const var& valueToCopy); | |||
| var& operator= (int value); | |||
| var& operator= (int64 value); | |||
| var& operator= (bool value); | |||
| var& operator= (double value); | |||
| var& operator= (const char* value); | |||
| var& operator= (const wchar_t* value); | |||
| var& operator= (const String& value); | |||
| var& operator= (ReferenceCountedObject* object); | |||
| var& operator= (MethodFunction method); | |||
| const var& operator= (const var& valueToCopy); | |||
| const var& operator= (int value); | |||
| const var& operator= (int64 value); | |||
| const var& operator= (bool value); | |||
| const var& operator= (double value); | |||
| const var& operator= (const char* value); | |||
| const var& operator= (const wchar_t* value); | |||
| const var& operator= (const String& value); | |||
| const var& operator= (ReferenceCountedObject* object); | |||
| const var& operator= (MethodFunction method); | |||
| void swapWith (var& other) noexcept; | |||
| @@ -18835,6 +18835,8 @@ private: | |||
| bool negative; | |||
| void ensureSize (int numVals); | |||
| void shiftLeft (int bits, int startBit); | |||
| void shiftRight (int bits, int startBit); | |||
| static const BigInteger simpleGCD (BigInteger* m, BigInteger* n); | |||
| static inline int bitToIndex (const int bit) noexcept { return bit >> 5; } | |||
| @@ -19258,6 +19260,7 @@ private: | |||
| void openHandle(); | |||
| void closeHandle(); | |||
| void flushInternal(); | |||
| bool flushBuffer(); | |||
| int64 setPositionInternal (int64 newPosition); | |||
| int writeInternal (const void* data, int numBytes); | |||
| @@ -20835,6 +20838,7 @@ private: | |||
| friend class ScopedPointer <GZIPCompressorHelper>; | |||
| ScopedPointer <GZIPCompressorHelper> helper; | |||
| bool doNextBlock(); | |||
| void flushInternal(); | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (GZIPCompressorOutputStream); | |||
| }; | |||
| @@ -21077,6 +21081,8 @@ private: | |||
| MemoryBlock internalBlock; | |||
| size_t position, size; | |||
| void trimExternalBlockSize(); | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MemoryOutputStream); | |||
| }; | |||
| @@ -38124,9 +38130,14 @@ public: | |||
| */ | |||
| virtual void audioDeviceAboutToStart (AudioIODevice* device) = 0; | |||
| /** Called to indicate that the device has stopped. | |||
| */ | |||
| /** Called to indicate that the device has stopped. */ | |||
| virtual void audioDeviceStopped() = 0; | |||
| /** This can be overridden to be told if the device generates an error while operating. | |||
| Be aware that this could be called by any thread! And not all devices perform | |||
| this callback. | |||
| */ | |||
| virtual void audioDeviceError (const String& errorMessage); | |||
| }; | |||
| /** | |||
| @@ -38728,6 +38739,8 @@ private: | |||
| int blockSize, readAheadBufferSize; | |||
| bool isPrepared, inputStreamEOF; | |||
| void releaseMasterResources(); | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioTransportSource); | |||
| }; | |||
| @@ -42920,6 +42933,27 @@ public: | |||
| /** @internal */ | |||
| void setTemporaryUnderlining (const Array <Range<int> >&); | |||
| bool moveCaretLeft (bool moveInWholeWordSteps, bool selecting); | |||
| bool moveCaretRight (bool moveInWholeWordSteps, bool selecting); | |||
| bool moveCaretUp (bool selecting); | |||
| bool moveCaretDown (bool selecting); | |||
| bool pageUp (bool selecting); | |||
| bool pageDown (bool selecting); | |||
| bool scrollDown(); | |||
| bool scrollUp(); | |||
| bool moveCaretToTop (bool selecting); | |||
| bool moveCaretToStartOfLine (bool selecting); | |||
| bool moveCaretToEnd (bool selecting); | |||
| bool moveCaretToEndOfLine (bool selecting); | |||
| bool deleteBackwards (bool moveInWholeWordSteps); | |||
| bool deleteForwards (bool moveInWholeWordSteps); | |||
| bool copyToClipboard(); | |||
| bool cutToClipboard(); | |||
| bool pasteFromClipboard(); | |||
| bool selectAll(); | |||
| bool undo(); | |||
| bool redo(); | |||
| /** This adds the items to the popup menu. | |||
| By default it adds the cut/copy/paste items, but you can override this if | |||
| @@ -43052,7 +43086,7 @@ private: | |||
| int indexAtPosition (float x, float y); | |||
| int findWordBreakAfter (int position) const; | |||
| int findWordBreakBefore (int position) const; | |||
| bool moveCaretWithTransation (int newPos, bool selecting); | |||
| friend class TextHolderComponent; | |||
| friend class TextEditorViewport; | |||
| void drawContent (Graphics& g); | |||
| @@ -43060,6 +43094,8 @@ private: | |||
| float getWordWrapWidth() const; | |||
| void timerCallbackInt(); | |||
| void repaintText (const Range<int>& range); | |||
| void scrollByLines (int deltaLines); | |||
| bool undoOrRedo (bool shouldUndo); | |||
| UndoManager* getUndoManager() noexcept; | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TextEditor); | |||
| @@ -47364,6 +47400,7 @@ private: | |||
| void scanFor (AudioPluginFormat* format); | |||
| static void optionsMenuStaticCallback (int result, PluginListComponent*); | |||
| void optionsMenuCallback (int result); | |||
| void updateList(); | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PluginListComponent); | |||
| }; | |||
| @@ -49522,6 +49559,8 @@ private: | |||
| Path path; | |||
| int offset; | |||
| void updateShadowAndOffset(); | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ArrowButton); | |||
| }; | |||
| @@ -52238,40 +52277,36 @@ public: | |||
| */ | |||
| const CodeDocument::Position getPositionAt (int x, int y); | |||
| void cursorLeft (bool moveInWholeWordSteps, bool selecting); | |||
| void cursorRight (bool moveInWholeWordSteps, bool selecting); | |||
| void cursorDown (bool selecting); | |||
| void cursorUp (bool selecting); | |||
| bool moveCaretLeft (bool moveInWholeWordSteps, bool selecting); | |||
| bool moveCaretRight (bool moveInWholeWordSteps, bool selecting); | |||
| bool moveCaretUp (bool selecting); | |||
| bool moveCaretDown (bool selecting); | |||
| bool scrollDown(); | |||
| bool scrollUp(); | |||
| bool pageUp (bool selecting); | |||
| bool pageDown (bool selecting); | |||
| bool moveCaretToTop (bool selecting); | |||
| bool moveCaretToStartOfLine (bool selecting); | |||
| bool moveCaretToEnd (bool selecting); | |||
| bool moveCaretToEndOfLine (bool selecting); | |||
| bool deleteBackwards (bool moveInWholeWordSteps); | |||
| bool deleteForwards (bool moveInWholeWordSteps); | |||
| bool copyToClipboard(); | |||
| bool cutToClipboard(); | |||
| bool pasteFromClipboard(); | |||
| bool undo(); | |||
| bool redo(); | |||
| void pageDown (bool selecting); | |||
| void pageUp (bool selecting); | |||
| bool selectAll(); | |||
| void deselectAll(); | |||
| void scrollDown(); | |||
| void scrollUp(); | |||
| void scrollToLine (int newFirstLineOnScreen); | |||
| void scrollBy (int deltaLines); | |||
| void scrollToColumn (int newFirstColumnOnScreen); | |||
| void scrollToKeepCaretOnScreen(); | |||
| void goToStartOfDocument (bool selecting); | |||
| void goToStartOfLine (bool selecting); | |||
| void goToEndOfDocument (bool selecting); | |||
| void goToEndOfLine (bool selecting); | |||
| void deselectAll(); | |||
| void selectAll(); | |||
| void insertTextAtCaret (const String& textToInsert); | |||
| void insertTabAtCaret(); | |||
| void cut(); | |||
| void copy(); | |||
| void copyThenCut(); | |||
| void paste(); | |||
| void backspace (bool moveInWholeWordSteps); | |||
| void deleteForward (bool moveInWholeWordSteps); | |||
| void undo(); | |||
| void redo(); | |||
| const Range<int> getHighlightedRegion() const; | |||
| void setHighlightedRegion (const Range<int>& newRange); | |||
| @@ -52422,6 +52457,7 @@ private: | |||
| void scrollToLineInternal (int line); | |||
| void scrollToColumnInternal (double column); | |||
| void newTransaction(); | |||
| void cut(); | |||
| int indexToColumn (int line, int index) const noexcept; | |||
| int columnToIndex (int line, int column) const noexcept; | |||
| @@ -53426,7 +53462,8 @@ private: | |||
| double velocityModeSensitivity, velocityModeOffset, minMaxDiff; | |||
| int velocityModeThreshold; | |||
| float rotaryStart, rotaryEnd; | |||
| int numDecimalPlaces, mouseXWhenLastDragged, mouseYWhenLastDragged; | |||
| int numDecimalPlaces; | |||
| Point<int> mousePosWhenLastDragged; | |||
| int mouseDragStartX, mouseDragStartY; | |||
| int sliderRegionStart, sliderRegionSize; | |||
| int sliderBeingDragged; | |||
| @@ -55763,6 +55800,9 @@ protected: | |||
| */ | |||
| virtual void getRoots (StringArray& rootNames, StringArray& rootPaths); | |||
| /** Updates the items in the dropdown list of recent paths with the values from getRoots(). */ | |||
| void resetRecentPaths(); | |||
| private: | |||
| ScopedPointer <DirectoryContentsList> fileList; | |||
| @@ -56995,6 +57035,7 @@ private: | |||
| bool hasBeenResized; | |||
| #endif | |||
| void initialise (bool addToDesktop); | |||
| void updateLastPos(); | |||
| void setContent (Component* newComp, bool takeOwnership, bool resizeToFit); | |||
| @@ -58863,6 +58904,340 @@ private: | |||
| #endif | |||
| #ifndef __JUCE_MODIFIERKEYS_JUCEHEADER__ | |||
| #endif | |||
| #ifndef __JUCE_TEXTEDITORKEYMAPPER_JUCEHEADER__ | |||
| /*** Start of inlined file: juce_TextEditorKeyMapper.h ***/ | |||
| #ifndef __JUCE_TEXTEDITORKEYMAPPER_JUCEHEADER__ | |||
| #define __JUCE_TEXTEDITORKEYMAPPER_JUCEHEADER__ | |||
| /*** Start of inlined file: juce_Keypress.h ***/ | |||
| #ifndef __JUCE_KEYPRESS_JUCEHEADER__ | |||
| #define __JUCE_KEYPRESS_JUCEHEADER__ | |||
| /** | |||
| Represents a key press, including any modifier keys that are needed. | |||
| E.g. a KeyPress might represent CTRL+C, SHIFT+ALT+H, Spacebar, Escape, etc. | |||
| @see Component, KeyListener, Button::addShortcut, KeyPressMappingManager | |||
| */ | |||
| class JUCE_API KeyPress | |||
| { | |||
| public: | |||
| /** Creates an (invalid) KeyPress. | |||
| @see isValid | |||
| */ | |||
| KeyPress() noexcept; | |||
| /** Creates a KeyPress for a key and some modifiers. | |||
| e.g. | |||
| CTRL+C would be: KeyPress ('c', ModifierKeys::ctrlModifier) | |||
| SHIFT+Escape would be: KeyPress (KeyPress::escapeKey, ModifierKeys::shiftModifier) | |||
| @param keyCode a code that represents the key - this value must be | |||
| one of special constants listed in this class, or an | |||
| 8-bit character code such as a letter (case is ignored), | |||
| digit or a simple key like "," or ".". Note that this | |||
| isn't the same as the textCharacter parameter, so for example | |||
| a keyCode of 'a' and a shift-key modifier should have a | |||
| textCharacter value of 'A'. | |||
| @param modifiers the modifiers to associate with the keystroke | |||
| @param textCharacter the character that would be printed if someone typed | |||
| this keypress into a text editor. This value may be | |||
| null if the keypress is a non-printing character | |||
| @see getKeyCode, isKeyCode, getModifiers | |||
| */ | |||
| KeyPress (int keyCode, | |||
| const ModifierKeys& modifiers, | |||
| juce_wchar textCharacter) noexcept; | |||
| /** Creates a keypress with a keyCode but no modifiers or text character. | |||
| */ | |||
| KeyPress (int keyCode) noexcept; | |||
| /** Creates a copy of another KeyPress. */ | |||
| KeyPress (const KeyPress& other) noexcept; | |||
| /** Copies this KeyPress from another one. */ | |||
| KeyPress& operator= (const KeyPress& other) noexcept; | |||
| /** Compares two KeyPress objects. */ | |||
| bool operator== (const KeyPress& other) const noexcept; | |||
| /** Compares two KeyPress objects. */ | |||
| bool operator!= (const KeyPress& other) const noexcept; | |||
| /** Returns true if this is a valid KeyPress. | |||
| A null keypress can be created by the default constructor, in case it's | |||
| needed. | |||
| */ | |||
| bool isValid() const noexcept { return keyCode != 0; } | |||
| /** Returns the key code itself. | |||
| This will either be one of the special constants defined in this class, | |||
| or an 8-bit character code. | |||
| */ | |||
| int getKeyCode() const noexcept { return keyCode; } | |||
| /** Returns the key modifiers. | |||
| @see ModifierKeys | |||
| */ | |||
| const ModifierKeys getModifiers() const noexcept { return mods; } | |||
| /** Returns the character that is associated with this keypress. | |||
| This is the character that you'd expect to see printed if you press this | |||
| keypress in a text editor or similar component. | |||
| */ | |||
| juce_wchar getTextCharacter() const noexcept { return textCharacter; } | |||
| /** Checks whether the KeyPress's key is the same as the one provided, without checking | |||
| the modifiers. | |||
| The values for key codes can either be one of the special constants defined in | |||
| this class, or an 8-bit character code. | |||
| @see getKeyCode | |||
| */ | |||
| bool isKeyCode (int keyCodeToCompare) const noexcept { return keyCode == keyCodeToCompare; } | |||
| /** Converts a textual key description to a KeyPress. | |||
| This attempts to decode a textual version of a keypress, e.g. "CTRL + C" or "SPACE". | |||
| This isn't designed to cope with any kind of input, but should be given the | |||
| strings that are created by the getTextDescription() method. | |||
| If the string can't be parsed, the object returned will be invalid. | |||
| @see getTextDescription | |||
| */ | |||
| static const KeyPress createFromDescription (const String& textVersion); | |||
| /** Creates a textual description of the key combination. | |||
| e.g. "CTRL + C" or "DELETE". | |||
| To store a keypress in a file, use this method, along with createFromDescription() | |||
| to retrieve it later. | |||
| */ | |||
| const String getTextDescription() const; | |||
| /** Creates a textual description of the key combination, using unicode icon symbols if possible. | |||
| On OSX, this uses the Apple symbols for command, option, shift, etc, instead of the textual | |||
| modifier key descriptions that are returned by getTextDescription() | |||
| */ | |||
| const String getTextDescriptionWithIcons() const; | |||
| /** Checks whether the user is currently holding down the keys that make up this | |||
| KeyPress. | |||
| Note that this will return false if any extra modifier keys are | |||
| down - e.g. if the keypress is CTRL+X and the user is actually holding CTRL+ALT+x | |||
| then it will be false. | |||
| */ | |||
| bool isCurrentlyDown() const; | |||
| /** Checks whether a particular key is held down, irrespective of modifiers. | |||
| The values for key codes can either be one of the special constants defined in | |||
| this class, or an 8-bit character code. | |||
| */ | |||
| static bool isKeyCurrentlyDown (int keyCode); | |||
| // Key codes | |||
| // | |||
| // Note that the actual values of these are platform-specific and may change | |||
| // without warning, so don't store them anywhere as constants. For persisting/retrieving | |||
| // KeyPress objects, use getTextDescription() and createFromDescription() instead. | |||
| // | |||
| static const int spaceKey; /**< key-code for the space bar */ | |||
| static const int escapeKey; /**< key-code for the escape key */ | |||
| static const int returnKey; /**< key-code for the return key*/ | |||
| static const int tabKey; /**< key-code for the tab key*/ | |||
| static const int deleteKey; /**< key-code for the delete key (not backspace) */ | |||
| static const int backspaceKey; /**< key-code for the backspace key */ | |||
| static const int insertKey; /**< key-code for the insert key */ | |||
| static const int upKey; /**< key-code for the cursor-up key */ | |||
| static const int downKey; /**< key-code for the cursor-down key */ | |||
| static const int leftKey; /**< key-code for the cursor-left key */ | |||
| static const int rightKey; /**< key-code for the cursor-right key */ | |||
| static const int pageUpKey; /**< key-code for the page-up key */ | |||
| static const int pageDownKey; /**< key-code for the page-down key */ | |||
| static const int homeKey; /**< key-code for the home key */ | |||
| static const int endKey; /**< key-code for the end key */ | |||
| static const int F1Key; /**< key-code for the F1 key */ | |||
| static const int F2Key; /**< key-code for the F2 key */ | |||
| static const int F3Key; /**< key-code for the F3 key */ | |||
| static const int F4Key; /**< key-code for the F4 key */ | |||
| static const int F5Key; /**< key-code for the F5 key */ | |||
| static const int F6Key; /**< key-code for the F6 key */ | |||
| static const int F7Key; /**< key-code for the F7 key */ | |||
| static const int F8Key; /**< key-code for the F8 key */ | |||
| static const int F9Key; /**< key-code for the F9 key */ | |||
| static const int F10Key; /**< key-code for the F10 key */ | |||
| static const int F11Key; /**< key-code for the F11 key */ | |||
| static const int F12Key; /**< key-code for the F12 key */ | |||
| static const int F13Key; /**< key-code for the F13 key */ | |||
| static const int F14Key; /**< key-code for the F14 key */ | |||
| static const int F15Key; /**< key-code for the F15 key */ | |||
| static const int F16Key; /**< key-code for the F16 key */ | |||
| static const int numberPad0; /**< key-code for the 0 on the numeric keypad. */ | |||
| static const int numberPad1; /**< key-code for the 1 on the numeric keypad. */ | |||
| static const int numberPad2; /**< key-code for the 2 on the numeric keypad. */ | |||
| static const int numberPad3; /**< key-code for the 3 on the numeric keypad. */ | |||
| static const int numberPad4; /**< key-code for the 4 on the numeric keypad. */ | |||
| static const int numberPad5; /**< key-code for the 5 on the numeric keypad. */ | |||
| static const int numberPad6; /**< key-code for the 6 on the numeric keypad. */ | |||
| static const int numberPad7; /**< key-code for the 7 on the numeric keypad. */ | |||
| static const int numberPad8; /**< key-code for the 8 on the numeric keypad. */ | |||
| static const int numberPad9; /**< key-code for the 9 on the numeric keypad. */ | |||
| static const int numberPadAdd; /**< key-code for the add sign on the numeric keypad. */ | |||
| static const int numberPadSubtract; /**< key-code for the subtract sign on the numeric keypad. */ | |||
| static const int numberPadMultiply; /**< key-code for the multiply sign on the numeric keypad. */ | |||
| static const int numberPadDivide; /**< key-code for the divide sign on the numeric keypad. */ | |||
| static const int numberPadSeparator; /**< key-code for the comma on the numeric keypad. */ | |||
| static const int numberPadDecimalPoint; /**< key-code for the decimal point sign on the numeric keypad. */ | |||
| static const int numberPadEquals; /**< key-code for the equals key on the numeric keypad. */ | |||
| static const int numberPadDelete; /**< key-code for the delete key on the numeric keypad. */ | |||
| static const int playKey; /**< key-code for a multimedia 'play' key, (not all keyboards will have one) */ | |||
| static const int stopKey; /**< key-code for a multimedia 'stop' key, (not all keyboards will have one) */ | |||
| static const int fastForwardKey; /**< key-code for a multimedia 'fast-forward' key, (not all keyboards will have one) */ | |||
| static const int rewindKey; /**< key-code for a multimedia 'rewind' key, (not all keyboards will have one) */ | |||
| private: | |||
| int keyCode; | |||
| ModifierKeys mods; | |||
| juce_wchar textCharacter; | |||
| JUCE_LEAK_DETECTOR (KeyPress); | |||
| }; | |||
| #endif // __JUCE_KEYPRESS_JUCEHEADER__ | |||
| /*** End of inlined file: juce_Keypress.h ***/ | |||
| /** This class is used to invoke a range of text-editor navigation methods on | |||
| an object, based upon a keypress event. | |||
| It's currently used internally by the TextEditor and CodeEditorComponent. | |||
| */ | |||
| template <class CallbackClass> | |||
| struct TextEditorKeyMapper | |||
| { | |||
| /** Checks the keypress and invokes one of a range of navigation functions that | |||
| the target class must implement, based on the key event. | |||
| */ | |||
| static bool invokeKeyFunction (CallbackClass& target, const KeyPress& key) | |||
| { | |||
| const bool isShiftDown = key.getModifiers().isShiftDown(); | |||
| const bool ctrlOrAltDown = key.getModifiers().isCtrlDown() || key.getModifiers().isAltDown(); | |||
| if (key == KeyPress (KeyPress::downKey, ModifierKeys::ctrlModifier, 0) | |||
| && target.scrollUp()) | |||
| return true; | |||
| if (key == KeyPress (KeyPress::upKey, ModifierKeys::ctrlModifier, 0) | |||
| && target.scrollDown()) | |||
| return true; | |||
| #if JUCE_MAC | |||
| if (key.getModifiers().isCommandDown()) | |||
| { | |||
| if (key.isKeyCode (KeyPress::upKey)) | |||
| return target.moveCaretToTop (isShiftDown); | |||
| if (key.isKeyCode (KeyPress::downKey)) | |||
| return target.moveCaretToEnd (isShiftDown); | |||
| if (key.isKeyCode (KeyPress::leftKey)) | |||
| return target.moveCaretToStartOfLine (isShiftDown); | |||
| if (key.isKeyCode (KeyPress::rightKey)) | |||
| return target.moveCaretToEndOfLine (isShiftDown); | |||
| } | |||
| #endif | |||
| if (key.isKeyCode (KeyPress::upKey)) | |||
| return target.moveCaretUp (isShiftDown); | |||
| if (key.isKeyCode (KeyPress::downKey)) | |||
| return target.moveCaretDown (isShiftDown); | |||
| if (key.isKeyCode (KeyPress::leftKey)) | |||
| return target.moveCaretLeft (ctrlOrAltDown, isShiftDown); | |||
| if (key.isKeyCode (KeyPress::rightKey)) | |||
| return target.moveCaretRight (ctrlOrAltDown, isShiftDown); | |||
| if (key.isKeyCode (KeyPress::pageUpKey)) | |||
| return target.pageUp (isShiftDown); | |||
| if (key.isKeyCode (KeyPress::pageDownKey)) | |||
| return target.pageDown (isShiftDown); | |||
| if (key.isKeyCode (KeyPress::homeKey)) | |||
| return ctrlOrAltDown ? target.moveCaretToTop (isShiftDown) | |||
| : target.moveCaretToStartOfLine (isShiftDown); | |||
| if (key.isKeyCode (KeyPress::endKey)) | |||
| return ctrlOrAltDown ? target.moveCaretToEnd (isShiftDown) | |||
| : target.moveCaretToEndOfLine (isShiftDown); | |||
| if (key == KeyPress ('c', ModifierKeys::commandModifier, 0) | |||
| || key == KeyPress (KeyPress::insertKey, ModifierKeys::ctrlModifier, 0)) | |||
| return target.copyToClipboard(); | |||
| if (key == KeyPress ('x', ModifierKeys::commandModifier, 0) | |||
| || key == KeyPress (KeyPress::deleteKey, ModifierKeys::shiftModifier, 0)) | |||
| return target.cutToClipboard(); | |||
| if (key == KeyPress ('v', ModifierKeys::commandModifier, 0) | |||
| || key == KeyPress (KeyPress::insertKey, ModifierKeys::shiftModifier, 0)) | |||
| return target.pasteFromClipboard(); | |||
| if (key.isKeyCode (KeyPress::backspaceKey)) | |||
| return target.deleteBackwards (ctrlOrAltDown); | |||
| if (key.isKeyCode (KeyPress::deleteKey)) | |||
| return target.deleteForwards (ctrlOrAltDown); | |||
| if (key == KeyPress ('a', ModifierKeys::commandModifier, 0)) | |||
| return target.selectAll(); | |||
| if (key == KeyPress ('z', ModifierKeys::commandModifier, 0)) | |||
| return target.undo(); | |||
| if (key == KeyPress ('y', ModifierKeys::commandModifier, 0) | |||
| || key == KeyPress ('z', ModifierKeys::commandModifier | ModifierKeys::shiftModifier, 0)) | |||
| return target.redo(); | |||
| return false; | |||
| } | |||
| }; | |||
| #endif // __JUCE_TEXTEDITORKEYMAPPER_JUCEHEADER__ | |||
| /*** End of inlined file: juce_TextEditorKeyMapper.h ***/ | |||
| #endif | |||
| #ifndef __JUCE_TEXTINPUTTARGET_JUCEHEADER__ | |||
| @@ -63088,6 +63463,8 @@ private: | |||
| ScopedPointer<ComboBox> midiOutputSelector; | |||
| ScopedPointer<Label> midiInputsLabel, midiOutputLabel; | |||
| void updateAllControls(); | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioDeviceSelectorComponent); | |||
| }; | |||
| @@ -53,6 +53,8 @@ bool AudioIODevice::showControlPanel() | |||
| return false; | |||
| } | |||
| //============================================================================== | |||
| void AudioIODeviceCallback::audioDeviceError (const String&) {} | |||
| END_JUCE_NAMESPACE | |||
| @@ -107,9 +107,14 @@ public: | |||
| */ | |||
| virtual void audioDeviceAboutToStart (AudioIODevice* device) = 0; | |||
| /** Called to indicate that the device has stopped. | |||
| */ | |||
| /** Called to indicate that the device has stopped. */ | |||
| virtual void audioDeviceStopped() = 0; | |||
| /** This can be overridden to be told if the device generates an error while operating. | |||
| Be aware that this could be called by any thread! And not all devices perform | |||
| this callback. | |||
| */ | |||
| virtual void audioDeviceError (const String& errorMessage); | |||
| }; | |||
| @@ -33,7 +33,7 @@ | |||
| */ | |||
| #define JUCE_MAJOR_VERSION 1 | |||
| #define JUCE_MINOR_VERSION 53 | |||
| #define JUCE_BUILDNUMBER 89 | |||
| #define JUCE_BUILDNUMBER 90 | |||
| /** Current Juce version number. | |||
| @@ -44,7 +44,7 @@ class InternalTimerThread : private Thread, | |||
| private AsyncUpdater | |||
| { | |||
| public: | |||
| typedef SpinLock LockType; | |||
| typedef CriticalSection LockType; // (mysteriously, using a SpinLock here causes problems on some XP machines..) | |||
| InternalTimerThread() | |||
| : Thread ("Juce Timer"), | |||
| @@ -146,7 +146,7 @@ public: | |||
| /* This is needed as a memory barrier to make sure all processing of current timers is done | |||
| before the boolean is set. This set should never fail since if it was false in the first place, | |||
| we wouldn't get a message (so it can't be changed from false to true from under us), and if we | |||
| get a message then the value is true and the other thread can only set it to true again and | |||
| get a message then the value is true and the other thread can only set it to true again and | |||
| we will get another callback to set it to false. | |||
| */ | |||
| callbackNeeded.set (0); | |||
| @@ -29,6 +29,7 @@ BEGIN_JUCE_NAMESPACE | |||
| #include "juce_CodeEditorComponent.h" | |||
| #include "../lookandfeel/juce_LookAndFeel.h" | |||
| #include "../keyboard/juce_TextEditorKeyMapper.h" | |||
| #include "../../../utilities/juce_SystemClipboard.h" | |||
| @@ -628,7 +629,7 @@ void CodeEditorComponent::cut() | |||
| insertTextAtCaret (String::empty); | |||
| } | |||
| void CodeEditorComponent::copy() | |||
| bool CodeEditorComponent::copyToClipboard() | |||
| { | |||
| newTransaction(); | |||
| @@ -636,16 +637,19 @@ void CodeEditorComponent::copy() | |||
| if (selection.isNotEmpty()) | |||
| SystemClipboard::copyTextToClipboard (selection); | |||
| return true; | |||
| } | |||
| void CodeEditorComponent::copyThenCut() | |||
| bool CodeEditorComponent::cutToClipboard() | |||
| { | |||
| copy(); | |||
| copyToClipboard(); | |||
| cut(); | |||
| newTransaction(); | |||
| return true; | |||
| } | |||
| void CodeEditorComponent::paste() | |||
| bool CodeEditorComponent::pasteFromClipboard() | |||
| { | |||
| newTransaction(); | |||
| const String clip (SystemClipboard::getTextFromClipboard()); | |||
| @@ -654,9 +658,10 @@ void CodeEditorComponent::paste() | |||
| insertTextAtCaret (clip); | |||
| newTransaction(); | |||
| return true; | |||
| } | |||
| void CodeEditorComponent::cursorLeft (const bool moveInWholeWordSteps, const bool selecting) | |||
| bool CodeEditorComponent::moveCaretLeft (const bool moveInWholeWordSteps, const bool selecting) | |||
| { | |||
| newTransaction(); | |||
| @@ -664,9 +669,11 @@ void CodeEditorComponent::cursorLeft (const bool moveInWholeWordSteps, const boo | |||
| moveCaretTo (document.findWordBreakBefore (caretPos), selecting); | |||
| else | |||
| moveCaretTo (caretPos.movedBy (-1), selecting); | |||
| return true; | |||
| } | |||
| void CodeEditorComponent::cursorRight (const bool moveInWholeWordSteps, const bool selecting) | |||
| bool CodeEditorComponent::moveCaretRight (const bool moveInWholeWordSteps, const bool selecting) | |||
| { | |||
| newTransaction(); | |||
| @@ -674,6 +681,8 @@ void CodeEditorComponent::cursorRight (const bool moveInWholeWordSteps, const bo | |||
| moveCaretTo (document.findWordBreakAfter (caretPos), selecting); | |||
| else | |||
| moveCaretTo (caretPos.movedBy (1), selecting); | |||
| return true; | |||
| } | |||
| void CodeEditorComponent::moveLineDelta (const int delta, const bool selecting) | |||
| @@ -691,7 +700,7 @@ void CodeEditorComponent::moveLineDelta (const int delta, const bool selecting) | |||
| columnToTryToMaintain = colToMaintain; | |||
| } | |||
| void CodeEditorComponent::cursorDown (const bool selecting) | |||
| bool CodeEditorComponent::moveCaretDown (const bool selecting) | |||
| { | |||
| newTransaction(); | |||
| @@ -699,9 +708,11 @@ void CodeEditorComponent::cursorDown (const bool selecting) | |||
| moveCaretTo (CodeDocument::Position (&document, std::numeric_limits<int>::max(), std::numeric_limits<int>::max()), selecting); | |||
| else | |||
| moveLineDelta (1, selecting); | |||
| return true; | |||
| } | |||
| void CodeEditorComponent::cursorUp (const bool selecting) | |||
| bool CodeEditorComponent::moveCaretUp (const bool selecting) | |||
| { | |||
| newTransaction(); | |||
| @@ -709,46 +720,53 @@ void CodeEditorComponent::cursorUp (const bool selecting) | |||
| moveCaretTo (CodeDocument::Position (&document, 0, 0), selecting); | |||
| else | |||
| moveLineDelta (-1, selecting); | |||
| return true; | |||
| } | |||
| void CodeEditorComponent::pageDown (const bool selecting) | |||
| bool CodeEditorComponent::pageDown (const bool selecting) | |||
| { | |||
| newTransaction(); | |||
| scrollBy (jlimit (0, linesOnScreen, 1 + document.getNumLines() - firstLineOnScreen - linesOnScreen)); | |||
| moveLineDelta (linesOnScreen, selecting); | |||
| return true; | |||
| } | |||
| void CodeEditorComponent::pageUp (const bool selecting) | |||
| bool CodeEditorComponent::pageUp (const bool selecting) | |||
| { | |||
| newTransaction(); | |||
| scrollBy (-linesOnScreen); | |||
| moveLineDelta (-linesOnScreen, selecting); | |||
| return true; | |||
| } | |||
| void CodeEditorComponent::scrollUp() | |||
| bool CodeEditorComponent::scrollUp() | |||
| { | |||
| newTransaction(); | |||
| scrollBy (1); | |||
| if (caretPos.getLineNumber() < firstLineOnScreen) | |||
| moveLineDelta (1, false); | |||
| return true; | |||
| } | |||
| void CodeEditorComponent::scrollDown() | |||
| bool CodeEditorComponent::scrollDown() | |||
| { | |||
| newTransaction(); | |||
| scrollBy (-1); | |||
| if (caretPos.getLineNumber() >= firstLineOnScreen + linesOnScreen) | |||
| moveLineDelta (-1, false); | |||
| return true; | |||
| } | |||
| void CodeEditorComponent::goToStartOfDocument (const bool selecting) | |||
| bool CodeEditorComponent::moveCaretToTop (const bool selecting) | |||
| { | |||
| newTransaction(); | |||
| moveCaretTo (CodeDocument::Position (&document, 0, 0), selecting); | |||
| return true; | |||
| } | |||
| namespace CodeEditorHelpers | |||
| @@ -771,7 +789,7 @@ namespace CodeEditorHelpers | |||
| } | |||
| } | |||
| void CodeEditorComponent::goToStartOfLine (const bool selecting) | |||
| bool CodeEditorComponent::moveCaretToStartOfLine (const bool selecting) | |||
| { | |||
| newTransaction(); | |||
| @@ -781,21 +799,24 @@ void CodeEditorComponent::goToStartOfLine (const bool selecting) | |||
| index = 0; | |||
| moveCaretTo (CodeDocument::Position (&document, caretPos.getLineNumber(), index), selecting); | |||
| return true; | |||
| } | |||
| void CodeEditorComponent::goToEndOfDocument (const bool selecting) | |||
| bool CodeEditorComponent::moveCaretToEnd (const bool selecting) | |||
| { | |||
| newTransaction(); | |||
| moveCaretTo (CodeDocument::Position (&document, std::numeric_limits<int>::max(), std::numeric_limits<int>::max()), selecting); | |||
| return true; | |||
| } | |||
| void CodeEditorComponent::goToEndOfLine (const bool selecting) | |||
| bool CodeEditorComponent::moveCaretToEndOfLine (const bool selecting) | |||
| { | |||
| newTransaction(); | |||
| moveCaretTo (CodeDocument::Position (&document, caretPos.getLineNumber(), std::numeric_limits<int>::max()), selecting); | |||
| return true; | |||
| } | |||
| void CodeEditorComponent::backspace (const bool moveInWholeWordSteps) | |||
| bool CodeEditorComponent::deleteBackwards (const bool moveInWholeWordSteps) | |||
| { | |||
| if (moveInWholeWordSteps) | |||
| { | |||
| @@ -809,9 +830,10 @@ void CodeEditorComponent::backspace (const bool moveInWholeWordSteps) | |||
| } | |||
| cut(); | |||
| return true; | |||
| } | |||
| void CodeEditorComponent::deleteForward (const bool moveInWholeWordSteps) | |||
| bool CodeEditorComponent::deleteForwards (const bool moveInWholeWordSteps) | |||
| { | |||
| if (moveInWholeWordSteps) | |||
| { | |||
| @@ -827,26 +849,30 @@ void CodeEditorComponent::deleteForward (const bool moveInWholeWordSteps) | |||
| } | |||
| cut(); | |||
| return true; | |||
| } | |||
| void CodeEditorComponent::selectAll() | |||
| bool CodeEditorComponent::selectAll() | |||
| { | |||
| newTransaction(); | |||
| moveCaretTo (CodeDocument::Position (&document, std::numeric_limits<int>::max(), std::numeric_limits<int>::max()), false); | |||
| moveCaretTo (CodeDocument::Position (&document, 0, 0), true); | |||
| return true; | |||
| } | |||
| //============================================================================== | |||
| void CodeEditorComponent::undo() | |||
| bool CodeEditorComponent::undo() | |||
| { | |||
| document.undo(); | |||
| scrollToKeepCaretOnScreen(); | |||
| return true; | |||
| } | |||
| void CodeEditorComponent::redo() | |||
| bool CodeEditorComponent::redo() | |||
| { | |||
| document.redo(); | |||
| scrollToKeepCaretOnScreen(); | |||
| return true; | |||
| } | |||
| void CodeEditorComponent::newTransaction() | |||
| @@ -881,114 +907,29 @@ const String CodeEditorComponent::getTextInRange (const Range<int>& range) const | |||
| //============================================================================== | |||
| bool CodeEditorComponent::keyPressed (const KeyPress& key) | |||
| { | |||
| const bool moveInWholeWordSteps = key.getModifiers().isCtrlDown() || key.getModifiers().isAltDown(); | |||
| const bool shiftDown = key.getModifiers().isShiftDown(); | |||
| if (key.isKeyCode (KeyPress::leftKey)) | |||
| { | |||
| cursorLeft (moveInWholeWordSteps, shiftDown); | |||
| } | |||
| else if (key.isKeyCode (KeyPress::rightKey)) | |||
| { | |||
| cursorRight (moveInWholeWordSteps, shiftDown); | |||
| } | |||
| else if (key.isKeyCode (KeyPress::upKey)) | |||
| { | |||
| if (key.getModifiers().isCtrlDown() && ! shiftDown) | |||
| scrollDown(); | |||
| #if JUCE_MAC | |||
| else if (key.getModifiers().isCommandDown()) | |||
| goToStartOfDocument (shiftDown); | |||
| #endif | |||
| else | |||
| cursorUp (shiftDown); | |||
| } | |||
| else if (key.isKeyCode (KeyPress::downKey)) | |||
| { | |||
| if (key.getModifiers().isCtrlDown() && ! shiftDown) | |||
| scrollUp(); | |||
| #if JUCE_MAC | |||
| else if (key.getModifiers().isCommandDown()) | |||
| goToEndOfDocument (shiftDown); | |||
| #endif | |||
| else | |||
| cursorDown (shiftDown); | |||
| } | |||
| else if (key.isKeyCode (KeyPress::pageDownKey)) | |||
| { | |||
| pageDown (shiftDown); | |||
| } | |||
| else if (key.isKeyCode (KeyPress::pageUpKey)) | |||
| { | |||
| pageUp (shiftDown); | |||
| } | |||
| else if (key.isKeyCode (KeyPress::homeKey)) | |||
| { | |||
| if (moveInWholeWordSteps) | |||
| goToStartOfDocument (shiftDown); | |||
| else | |||
| goToStartOfLine (shiftDown); | |||
| } | |||
| else if (key.isKeyCode (KeyPress::endKey)) | |||
| if (! TextEditorKeyMapper<CodeEditorComponent>::invokeKeyFunction (*this, key)) | |||
| { | |||
| if (moveInWholeWordSteps) | |||
| goToEndOfDocument (shiftDown); | |||
| if (key == KeyPress::tabKey || key.getTextCharacter() == '\t') | |||
| { | |||
| insertTabAtCaret(); | |||
| } | |||
| else if (key == KeyPress::returnKey) | |||
| { | |||
| newTransaction(); | |||
| insertTextAtCaret (document.getNewLineCharacters()); | |||
| } | |||
| else if (key.isKeyCode (KeyPress::escapeKey)) | |||
| { | |||
| newTransaction(); | |||
| } | |||
| else if (key.getTextCharacter() >= ' ') | |||
| { | |||
| insertTextAtCaret (String::charToString (key.getTextCharacter())); | |||
| } | |||
| else | |||
| goToEndOfLine (shiftDown); | |||
| } | |||
| else if (key.isKeyCode (KeyPress::backspaceKey)) | |||
| { | |||
| backspace (moveInWholeWordSteps); | |||
| } | |||
| else if (key.isKeyCode (KeyPress::deleteKey)) | |||
| { | |||
| deleteForward (moveInWholeWordSteps); | |||
| } | |||
| else if (key == KeyPress ('c', ModifierKeys::commandModifier, 0)) | |||
| { | |||
| copy(); | |||
| } | |||
| else if (key == KeyPress ('x', ModifierKeys::commandModifier, 0)) | |||
| { | |||
| copyThenCut(); | |||
| } | |||
| else if (key == KeyPress ('v', ModifierKeys::commandModifier, 0)) | |||
| { | |||
| paste(); | |||
| } | |||
| else if (key == KeyPress ('z', ModifierKeys::commandModifier, 0)) | |||
| { | |||
| undo(); | |||
| } | |||
| else if (key == KeyPress ('y', ModifierKeys::commandModifier, 0) | |||
| || key == KeyPress ('z', ModifierKeys::commandModifier | ModifierKeys::shiftModifier, 0)) | |||
| { | |||
| redo(); | |||
| } | |||
| else if (key == KeyPress ('a', ModifierKeys::commandModifier, 0)) | |||
| { | |||
| selectAll(); | |||
| } | |||
| else if (key == KeyPress::tabKey || key.getTextCharacter() == '\t') | |||
| { | |||
| insertTabAtCaret(); | |||
| } | |||
| else if (key == KeyPress::returnKey) | |||
| { | |||
| newTransaction(); | |||
| insertTextAtCaret (document.getNewLineCharacters()); | |||
| } | |||
| else if (key.isKeyCode (KeyPress::escapeKey)) | |||
| { | |||
| newTransaction(); | |||
| } | |||
| else if (key.getTextCharacter() >= ' ') | |||
| { | |||
| insertTextAtCaret (String::charToString (key.getTextCharacter())); | |||
| } | |||
| else | |||
| { | |||
| return false; | |||
| { | |||
| return false; | |||
| } | |||
| } | |||
| return true; | |||
| @@ -116,40 +116,36 @@ public: | |||
| const CodeDocument::Position getPositionAt (int x, int y); | |||
| //============================================================================== | |||
| void cursorLeft (bool moveInWholeWordSteps, bool selecting); | |||
| void cursorRight (bool moveInWholeWordSteps, bool selecting); | |||
| void cursorDown (bool selecting); | |||
| void cursorUp (bool selecting); | |||
| void pageDown (bool selecting); | |||
| void pageUp (bool selecting); | |||
| bool moveCaretLeft (bool moveInWholeWordSteps, bool selecting); | |||
| bool moveCaretRight (bool moveInWholeWordSteps, bool selecting); | |||
| bool moveCaretUp (bool selecting); | |||
| bool moveCaretDown (bool selecting); | |||
| bool scrollDown(); | |||
| bool scrollUp(); | |||
| bool pageUp (bool selecting); | |||
| bool pageDown (bool selecting); | |||
| bool moveCaretToTop (bool selecting); | |||
| bool moveCaretToStartOfLine (bool selecting); | |||
| bool moveCaretToEnd (bool selecting); | |||
| bool moveCaretToEndOfLine (bool selecting); | |||
| bool deleteBackwards (bool moveInWholeWordSteps); | |||
| bool deleteForwards (bool moveInWholeWordSteps); | |||
| bool copyToClipboard(); | |||
| bool cutToClipboard(); | |||
| bool pasteFromClipboard(); | |||
| bool undo(); | |||
| bool redo(); | |||
| bool selectAll(); | |||
| void deselectAll(); | |||
| void scrollDown(); | |||
| void scrollUp(); | |||
| void scrollToLine (int newFirstLineOnScreen); | |||
| void scrollBy (int deltaLines); | |||
| void scrollToColumn (int newFirstColumnOnScreen); | |||
| void scrollToKeepCaretOnScreen(); | |||
| void goToStartOfDocument (bool selecting); | |||
| void goToStartOfLine (bool selecting); | |||
| void goToEndOfDocument (bool selecting); | |||
| void goToEndOfLine (bool selecting); | |||
| void deselectAll(); | |||
| void selectAll(); | |||
| void insertTextAtCaret (const String& textToInsert); | |||
| void insertTabAtCaret(); | |||
| void cut(); | |||
| void copy(); | |||
| void copyThenCut(); | |||
| void paste(); | |||
| void backspace (bool moveInWholeWordSteps); | |||
| void deleteForward (bool moveInWholeWordSteps); | |||
| void undo(); | |||
| void redo(); | |||
| //============================================================================== | |||
| const Range<int> getHighlightedRegion() const; | |||
| @@ -307,6 +303,7 @@ private: | |||
| void scrollToLineInternal (int line); | |||
| void scrollToColumnInternal (double column); | |||
| void newTransaction(); | |||
| void cut(); | |||
| int indexToColumn (int line, int index) const noexcept; | |||
| int columnToIndex (int line, int column) const noexcept; | |||
| @@ -35,6 +35,7 @@ BEGIN_JUCE_NAMESPACE | |||
| #include "../../../text/juce_LocalisedStrings.h" | |||
| #include "../../../io/streams/juce_MemoryOutputStream.h" | |||
| #include "../lookandfeel/juce_LookAndFeel.h" | |||
| #include "../keyboard/juce_TextEditorKeyMapper.h" | |||
| //============================================================================== | |||
| @@ -1032,20 +1033,28 @@ void TextEditor::newTransaction() | |||
| undoManager.beginNewTransaction(); | |||
| } | |||
| void TextEditor::doUndoRedo (const bool isRedo) | |||
| bool TextEditor::undoOrRedo (const bool shouldUndo) | |||
| { | |||
| if (! isReadOnly()) | |||
| { | |||
| if (isRedo ? undoManager.redo() | |||
| : undoManager.undo()) | |||
| newTransaction(); | |||
| if (shouldUndo ? undoManager.undo() | |||
| : undoManager.redo()) | |||
| { | |||
| scrollToMakeSureCursorIsVisible(); | |||
| repaint(); | |||
| textChanged(); | |||
| return true; | |||
| } | |||
| } | |||
| return false; | |||
| } | |||
| bool TextEditor::undo() { return undoOrRedo (true); } | |||
| bool TextEditor::redo() { return undoOrRedo (false); } | |||
| //============================================================================== | |||
| void TextEditor::setMultiLine (const bool shouldBeMultiLine, | |||
| const bool shouldWordWrap) | |||
| @@ -1885,163 +1894,199 @@ void TextEditor::mouseWheelMove (const MouseEvent& e, float wheelIncrementX, flo | |||
| } | |||
| //============================================================================== | |||
| bool TextEditor::keyPressed (const KeyPress& key) | |||
| bool TextEditor::moveCaretWithTransation (const int newPos, const bool selecting) | |||
| { | |||
| if (isReadOnly() && key != KeyPress ('c', ModifierKeys::commandModifier, 0)) | |||
| return false; | |||
| newTransaction(); | |||
| moveCaretTo (newPos, selecting); | |||
| return true; | |||
| } | |||
| bool TextEditor::moveCaretLeft (bool moveInWholeWordSteps, bool selecting) | |||
| { | |||
| int pos = getCaretPosition(); | |||
| if (moveInWholeWordSteps) | |||
| pos = findWordBreakBefore (pos); | |||
| else | |||
| --pos; | |||
| return moveCaretWithTransation (pos, selecting); | |||
| } | |||
| bool TextEditor::moveCaretRight (bool moveInWholeWordSteps, bool selecting) | |||
| { | |||
| int pos = getCaretPosition(); | |||
| if (moveInWholeWordSteps) | |||
| pos = findWordBreakAfter (pos); | |||
| else | |||
| ++pos; | |||
| return moveCaretWithTransation (pos, selecting); | |||
| } | |||
| bool TextEditor::moveCaretUp (bool selecting) | |||
| { | |||
| if (! isMultiLine()) | |||
| return moveCaretToStartOfLine (selecting); | |||
| const bool moveInWholeWordSteps = key.getModifiers().isCtrlDown() || key.getModifiers().isAltDown(); | |||
| const Rectangle<float> caretPos (getCaretRectangle().toFloat()); | |||
| return moveCaretWithTransation (indexAtPosition (caretPos.getX(), caretPos.getY() - 1.0f), selecting); | |||
| } | |||
| if (key.isKeyCode (KeyPress::leftKey) | |||
| || key.isKeyCode (KeyPress::upKey)) | |||
| { | |||
| newTransaction(); | |||
| bool TextEditor::moveCaretDown (bool selecting) | |||
| { | |||
| if (! isMultiLine()) | |||
| return moveCaretToEndOfLine (selecting); | |||
| int newPos; | |||
| const Rectangle<float> caretPos (getCaretRectangle().toFloat()); | |||
| return moveCaretWithTransation (indexAtPosition (caretPos.getX(), caretPos.getBottom() + 1.0f), selecting); | |||
| } | |||
| if (isMultiLine() && key.isKeyCode (KeyPress::upKey)) | |||
| newPos = indexAtPosition (caretPos.getX(), caretPos.getY() - 1.0f); | |||
| else if (moveInWholeWordSteps) | |||
| newPos = findWordBreakBefore (getCaretPosition()); | |||
| else | |||
| newPos = getCaretPosition() - 1; | |||
| bool TextEditor::pageUp (bool selecting) | |||
| { | |||
| if (! isMultiLine()) | |||
| return moveCaretToStartOfLine (selecting); | |||
| moveCaretTo (newPos, key.getModifiers().isShiftDown()); | |||
| } | |||
| else if (key.isKeyCode (KeyPress::rightKey) | |||
| || key.isKeyCode (KeyPress::downKey)) | |||
| { | |||
| newTransaction(); | |||
| const Rectangle<float> caretPos (getCaretRectangle().toFloat()); | |||
| return moveCaretWithTransation (indexAtPosition (caretPos.getX(), caretPos.getY() - viewport->getViewHeight()), selecting); | |||
| } | |||
| int newPos; | |||
| bool TextEditor::pageDown (bool selecting) | |||
| { | |||
| if (! isMultiLine()) | |||
| return moveCaretToEndOfLine (selecting); | |||
| if (isMultiLine() && key.isKeyCode (KeyPress::downKey)) | |||
| newPos = indexAtPosition (caretPos.getX(), caretPos.getBottom() + 1.0f); | |||
| else if (moveInWholeWordSteps) | |||
| newPos = findWordBreakAfter (getCaretPosition()); | |||
| else | |||
| newPos = getCaretPosition() + 1; | |||
| const Rectangle<float> caretPos (getCaretRectangle().toFloat()); | |||
| return moveCaretWithTransation (indexAtPosition (caretPos.getX(), caretPos.getBottom() + viewport->getViewHeight()), selecting); | |||
| } | |||
| moveCaretTo (newPos, key.getModifiers().isShiftDown()); | |||
| } | |||
| else if (key.isKeyCode (KeyPress::pageDownKey) && isMultiLine()) | |||
| { | |||
| newTransaction(); | |||
| void TextEditor::scrollByLines (int deltaLines) | |||
| { | |||
| ScrollBar* scrollbar = viewport->getVerticalScrollBar(); | |||
| moveCaretTo (indexAtPosition (caretPos.getX(), caretPos.getBottom() + viewport->getViewHeight()), | |||
| key.getModifiers().isShiftDown()); | |||
| } | |||
| else if (key.isKeyCode (KeyPress::pageUpKey) && isMultiLine()) | |||
| { | |||
| newTransaction(); | |||
| if (scrollbar != nullptr) | |||
| scrollbar->moveScrollbarInSteps (deltaLines); | |||
| } | |||
| moveCaretTo (indexAtPosition (caretPos.getX(), caretPos.getY() - viewport->getViewHeight()), | |||
| key.getModifiers().isShiftDown()); | |||
| } | |||
| else if (key.isKeyCode (KeyPress::homeKey)) | |||
| { | |||
| newTransaction(); | |||
| bool TextEditor::scrollDown() | |||
| { | |||
| scrollByLines (-1); | |||
| return true; | |||
| } | |||
| if (isMultiLine() && ! moveInWholeWordSteps) | |||
| moveCaretTo (indexAtPosition (0.0f, caretPos.getY()), | |||
| key.getModifiers().isShiftDown()); | |||
| else | |||
| moveCaretTo (0, key.getModifiers().isShiftDown()); | |||
| } | |||
| else if (key.isKeyCode (KeyPress::endKey)) | |||
| { | |||
| newTransaction(); | |||
| bool TextEditor::scrollUp() | |||
| { | |||
| scrollByLines (1); | |||
| return true; | |||
| } | |||
| if (isMultiLine() && ! moveInWholeWordSteps) | |||
| moveCaretTo (indexAtPosition ((float) textHolder->getWidth(), caretPos.getY()), | |||
| key.getModifiers().isShiftDown()); | |||
| else | |||
| moveCaretTo (getTotalNumChars(), key.getModifiers().isShiftDown()); | |||
| } | |||
| else if (key.isKeyCode (KeyPress::backspaceKey)) | |||
| bool TextEditor::moveCaretToTop (bool selecting) | |||
| { | |||
| return moveCaretWithTransation (0, selecting); | |||
| } | |||
| bool TextEditor::moveCaretToStartOfLine (bool selecting) | |||
| { | |||
| const Rectangle<float> caretPos (getCaretRectangle().toFloat()); | |||
| return moveCaretWithTransation (indexAtPosition (0.0f, caretPos.getY()), selecting); | |||
| } | |||
| bool TextEditor::moveCaretToEnd (bool selecting) | |||
| { | |||
| return moveCaretWithTransation (getTotalNumChars(), selecting); | |||
| } | |||
| bool TextEditor::moveCaretToEndOfLine (bool selecting) | |||
| { | |||
| const Rectangle<float> caretPos (getCaretRectangle().toFloat()); | |||
| return moveCaretWithTransation (indexAtPosition ((float) textHolder->getWidth(), caretPos.getY()), selecting); | |||
| } | |||
| bool TextEditor::deleteBackwards (bool moveInWholeWordSteps) | |||
| { | |||
| if (moveInWholeWordSteps) | |||
| moveCaretTo (findWordBreakBefore (getCaretPosition()), true); | |||
| else if (selection.isEmpty() && selection.getStart() > 0) | |||
| selection.setStart (selection.getEnd() - 1); | |||
| cut(); | |||
| return true; | |||
| } | |||
| bool TextEditor::deleteForwards (bool /*moveInWholeWordSteps*/) | |||
| { | |||
| if (selection.isEmpty() && selection.getStart() < getTotalNumChars()) | |||
| selection.setEnd (selection.getStart() + 1); | |||
| cut(); | |||
| return true; | |||
| } | |||
| bool TextEditor::copyToClipboard() | |||
| { | |||
| newTransaction(); | |||
| copy(); | |||
| return true; | |||
| } | |||
| bool TextEditor::cutToClipboard() | |||
| { | |||
| newTransaction(); | |||
| copy(); | |||
| cut(); | |||
| return true; | |||
| } | |||
| bool TextEditor::pasteFromClipboard() | |||
| { | |||
| newTransaction(); | |||
| paste(); | |||
| return true; | |||
| } | |||
| bool TextEditor::selectAll() | |||
| { | |||
| newTransaction(); | |||
| moveCaretTo (getTotalNumChars(), false); | |||
| moveCaretTo (0, true); | |||
| return true; | |||
| } | |||
| //============================================================================== | |||
| bool TextEditor::keyPressed (const KeyPress& key) | |||
| { | |||
| if (isReadOnly() && key != KeyPress ('c', ModifierKeys::commandModifier, 0)) | |||
| return false; | |||
| if (! TextEditorKeyMapper<TextEditor>::invokeKeyFunction (*this, key)) | |||
| { | |||
| if (moveInWholeWordSteps) | |||
| if (key == KeyPress::returnKey) | |||
| { | |||
| moveCaretTo (findWordBreakBefore (getCaretPosition()), true); | |||
| newTransaction(); | |||
| if (returnKeyStartsNewLine) | |||
| insertTextAtCaret ("\n"); | |||
| else | |||
| returnPressed(); | |||
| } | |||
| else | |||
| else if (key.isKeyCode (KeyPress::escapeKey)) | |||
| { | |||
| if (selection.isEmpty() && selection.getStart() > 0) | |||
| selection.setStart (selection.getEnd() - 1); | |||
| newTransaction(); | |||
| moveCaretTo (getCaretPosition(), false); | |||
| escapePressed(); | |||
| } | |||
| else if (key.getTextCharacter() >= ' ' | |||
| || (tabKeyUsed && (key.getTextCharacter() == '\t'))) | |||
| { | |||
| insertTextAtCaret (String::charToString (key.getTextCharacter())); | |||
| cut(); | |||
| } | |||
| else if (key.isKeyCode (KeyPress::deleteKey)) | |||
| { | |||
| if (key.getModifiers().isShiftDown()) | |||
| copy(); | |||
| if (selection.isEmpty() && selection.getStart() < getTotalNumChars()) | |||
| selection.setEnd (selection.getStart() + 1); | |||
| cut(); | |||
| } | |||
| else if (key == KeyPress ('c', ModifierKeys::commandModifier, 0) | |||
| || key == KeyPress (KeyPress::insertKey, ModifierKeys::ctrlModifier, 0)) | |||
| { | |||
| newTransaction(); | |||
| copy(); | |||
| } | |||
| else if (key == KeyPress ('x', ModifierKeys::commandModifier, 0)) | |||
| { | |||
| newTransaction(); | |||
| copy(); | |||
| cut(); | |||
| } | |||
| else if (key == KeyPress ('v', ModifierKeys::commandModifier, 0) | |||
| || key == KeyPress (KeyPress::insertKey, ModifierKeys::shiftModifier, 0)) | |||
| { | |||
| newTransaction(); | |||
| paste(); | |||
| } | |||
| else if (key == KeyPress ('z', ModifierKeys::commandModifier, 0)) | |||
| { | |||
| newTransaction(); | |||
| doUndoRedo (false); | |||
| } | |||
| else if (key == KeyPress ('y', ModifierKeys::commandModifier, 0)) | |||
| { | |||
| newTransaction(); | |||
| doUndoRedo (true); | |||
| } | |||
| else if (key == KeyPress ('a', ModifierKeys::commandModifier, 0)) | |||
| { | |||
| newTransaction(); | |||
| moveCaretTo (getTotalNumChars(), false); | |||
| moveCaretTo (0, true); | |||
| } | |||
| else if (key == KeyPress::returnKey) | |||
| { | |||
| newTransaction(); | |||
| if (returnKeyStartsNewLine) | |||
| insertTextAtCaret ("\n"); | |||
| lastTransactionTime = Time::getApproximateMillisecondCounter(); | |||
| } | |||
| else | |||
| returnPressed(); | |||
| } | |||
| else if (key.isKeyCode (KeyPress::escapeKey)) | |||
| { | |||
| newTransaction(); | |||
| moveCaretTo (getCaretPosition(), false); | |||
| escapePressed(); | |||
| } | |||
| else if (key.getTextCharacter() >= ' ' | |||
| || (tabKeyUsed && (key.getTextCharacter() == '\t'))) | |||
| { | |||
| insertTextAtCaret (String::charToString (key.getTextCharacter())); | |||
| lastTransactionTime = Time::getApproximateMillisecondCounter(); | |||
| } | |||
| else | |||
| { | |||
| return false; | |||
| { | |||
| return false; | |||
| } | |||
| } | |||
| return true; | |||
| @@ -2052,10 +2097,10 @@ bool TextEditor::keyStateChanged (const bool isKeyDown) | |||
| if (! isKeyDown) | |||
| return false; | |||
| #if JUCE_WINDOWS | |||
| #if JUCE_WINDOWS | |||
| if (KeyPress (KeyPress::F4Key, ModifierKeys::altModifier, 0).isCurrentlyDown()) | |||
| return false; // We need to explicitly allow alt-F4 to pass through on Windows | |||
| #endif | |||
| #endif | |||
| // (overridden to avoid forwarding key events to the parent) | |||
| return ! ModifierKeys::getCurrentModifiers().isCommandDown(); | |||
| @@ -2091,38 +2136,14 @@ void TextEditor::performPopupMenuAction (const int menuItemID) | |||
| { | |||
| switch (menuItemID) | |||
| { | |||
| case baseMenuItemID + 1: | |||
| copy(); | |||
| cut(); | |||
| break; | |||
| case baseMenuItemID + 2: | |||
| copy(); | |||
| break; | |||
| case baseMenuItemID + 3: | |||
| paste(); | |||
| break; | |||
| case baseMenuItemID + 4: | |||
| cut(); | |||
| break; | |||
| case baseMenuItemID + 5: | |||
| moveCaretTo (getTotalNumChars(), false); | |||
| moveCaretTo (0, true); | |||
| break; | |||
| case baseMenuItemID + 6: | |||
| doUndoRedo (false); | |||
| break; | |||
| case baseMenuItemID + 7: | |||
| doUndoRedo (true); | |||
| break; | |||
| default: | |||
| break; | |||
| case baseMenuItemID + 1: cutToClipboard(); break; | |||
| case baseMenuItemID + 2: copyToClipboard(); break; | |||
| case baseMenuItemID + 3: pasteFromClipboard(); break; | |||
| case baseMenuItemID + 4: cut(); break; | |||
| case baseMenuItemID + 5: selectAll(); break; | |||
| case baseMenuItemID + 6: undo(); break; | |||
| case baseMenuItemID + 7: redo(); break; | |||
| default: break; | |||
| } | |||
| } | |||
| @@ -534,6 +534,27 @@ public: | |||
| /** @internal */ | |||
| void setTemporaryUnderlining (const Array <Range<int> >&); | |||
| bool moveCaretLeft (bool moveInWholeWordSteps, bool selecting); | |||
| bool moveCaretRight (bool moveInWholeWordSteps, bool selecting); | |||
| bool moveCaretUp (bool selecting); | |||
| bool moveCaretDown (bool selecting); | |||
| bool pageUp (bool selecting); | |||
| bool pageDown (bool selecting); | |||
| bool scrollDown(); | |||
| bool scrollUp(); | |||
| bool moveCaretToTop (bool selecting); | |||
| bool moveCaretToStartOfLine (bool selecting); | |||
| bool moveCaretToEnd (bool selecting); | |||
| bool moveCaretToEndOfLine (bool selecting); | |||
| bool deleteBackwards (bool moveInWholeWordSteps); | |||
| bool deleteForwards (bool moveInWholeWordSteps); | |||
| bool copyToClipboard(); | |||
| bool cutToClipboard(); | |||
| bool pasteFromClipboard(); | |||
| bool selectAll(); | |||
| bool undo(); | |||
| bool redo(); | |||
| //============================================================================== | |||
| /** This adds the items to the popup menu. | |||
| @@ -668,7 +689,7 @@ private: | |||
| int indexAtPosition (float x, float y); | |||
| int findWordBreakAfter (int position) const; | |||
| int findWordBreakBefore (int position) const; | |||
| bool moveCaretWithTransation (int newPos, bool selecting); | |||
| friend class TextHolderComponent; | |||
| friend class TextEditorViewport; | |||
| void drawContent (Graphics& g); | |||
| @@ -676,6 +697,8 @@ private: | |||
| float getWordWrapWidth() const; | |||
| void timerCallbackInt(); | |||
| void repaintText (const Range<int>& range); | |||
| void scrollByLines (int deltaLines); | |||
| bool undoOrRedo (bool shouldUndo); | |||
| UndoManager* getUndoManager() noexcept; | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TextEditor); | |||
| @@ -0,0 +1,132 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||
| Copyright 2004-11 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. | |||
| ============================================================================== | |||
| */ | |||
| #ifndef __JUCE_TEXTEDITORKEYMAPPER_JUCEHEADER__ | |||
| #define __JUCE_TEXTEDITORKEYMAPPER_JUCEHEADER__ | |||
| #include "juce_Keypress.h" | |||
| //============================================================================== | |||
| /** This class is used to invoke a range of text-editor navigation methods on | |||
| an object, based upon a keypress event. | |||
| It's currently used internally by the TextEditor and CodeEditorComponent. | |||
| */ | |||
| template <class CallbackClass> | |||
| struct TextEditorKeyMapper | |||
| { | |||
| /** Checks the keypress and invokes one of a range of navigation functions that | |||
| the target class must implement, based on the key event. | |||
| */ | |||
| static bool invokeKeyFunction (CallbackClass& target, const KeyPress& key) | |||
| { | |||
| const bool isShiftDown = key.getModifiers().isShiftDown(); | |||
| const bool ctrlOrAltDown = key.getModifiers().isCtrlDown() || key.getModifiers().isAltDown(); | |||
| if (key == KeyPress (KeyPress::downKey, ModifierKeys::ctrlModifier, 0) | |||
| && target.scrollUp()) | |||
| return true; | |||
| if (key == KeyPress (KeyPress::upKey, ModifierKeys::ctrlModifier, 0) | |||
| && target.scrollDown()) | |||
| return true; | |||
| #if JUCE_MAC | |||
| if (key.getModifiers().isCommandDown()) | |||
| { | |||
| if (key.isKeyCode (KeyPress::upKey)) | |||
| return target.moveCaretToTop (isShiftDown); | |||
| if (key.isKeyCode (KeyPress::downKey)) | |||
| return target.moveCaretToEnd (isShiftDown); | |||
| if (key.isKeyCode (KeyPress::leftKey)) | |||
| return target.moveCaretToStartOfLine (isShiftDown); | |||
| if (key.isKeyCode (KeyPress::rightKey)) | |||
| return target.moveCaretToEndOfLine (isShiftDown); | |||
| } | |||
| #endif | |||
| if (key.isKeyCode (KeyPress::upKey)) | |||
| return target.moveCaretUp (isShiftDown); | |||
| if (key.isKeyCode (KeyPress::downKey)) | |||
| return target.moveCaretDown (isShiftDown); | |||
| if (key.isKeyCode (KeyPress::leftKey)) | |||
| return target.moveCaretLeft (ctrlOrAltDown, isShiftDown); | |||
| if (key.isKeyCode (KeyPress::rightKey)) | |||
| return target.moveCaretRight (ctrlOrAltDown, isShiftDown); | |||
| if (key.isKeyCode (KeyPress::pageUpKey)) | |||
| return target.pageUp (isShiftDown); | |||
| if (key.isKeyCode (KeyPress::pageDownKey)) | |||
| return target.pageDown (isShiftDown); | |||
| if (key.isKeyCode (KeyPress::homeKey)) | |||
| return ctrlOrAltDown ? target.moveCaretToTop (isShiftDown) | |||
| : target.moveCaretToStartOfLine (isShiftDown); | |||
| if (key.isKeyCode (KeyPress::endKey)) | |||
| return ctrlOrAltDown ? target.moveCaretToEnd (isShiftDown) | |||
| : target.moveCaretToEndOfLine (isShiftDown); | |||
| if (key == KeyPress ('c', ModifierKeys::commandModifier, 0) | |||
| || key == KeyPress (KeyPress::insertKey, ModifierKeys::ctrlModifier, 0)) | |||
| return target.copyToClipboard(); | |||
| if (key == KeyPress ('x', ModifierKeys::commandModifier, 0) | |||
| || key == KeyPress (KeyPress::deleteKey, ModifierKeys::shiftModifier, 0)) | |||
| return target.cutToClipboard(); | |||
| if (key == KeyPress ('v', ModifierKeys::commandModifier, 0) | |||
| || key == KeyPress (KeyPress::insertKey, ModifierKeys::shiftModifier, 0)) | |||
| return target.pasteFromClipboard(); | |||
| if (key.isKeyCode (KeyPress::backspaceKey)) | |||
| return target.deleteBackwards (ctrlOrAltDown); | |||
| if (key.isKeyCode (KeyPress::deleteKey)) | |||
| return target.deleteForwards (ctrlOrAltDown); | |||
| if (key == KeyPress ('a', ModifierKeys::commandModifier, 0)) | |||
| return target.selectAll(); | |||
| if (key == KeyPress ('z', ModifierKeys::commandModifier, 0)) | |||
| return target.undo(); | |||
| if (key == KeyPress ('y', ModifierKeys::commandModifier, 0) | |||
| || key == KeyPress ('z', ModifierKeys::commandModifier | ModifierKeys::shiftModifier, 0)) | |||
| return target.redo(); | |||
| return false; | |||
| } | |||
| }; | |||
| #endif // __JUCE_TEXTEDITORKEYMAPPER_JUCEHEADER__ | |||
| @@ -233,7 +233,7 @@ private: | |||
| sp = stack; | |||
| } | |||
| int readLZWByte (const int inputCodeSize) | |||
| int readLZWByte() | |||
| { | |||
| if (fresh) | |||
| { | |||
| @@ -367,12 +367,13 @@ private: | |||
| bool readImage (const int interlace, const int transparent) | |||
| { | |||
| unsigned char c; | |||
| if (input.read (&c, 1) != 1) | |||
| return false; | |||
| { | |||
| unsigned char c; | |||
| if (input.read (&c, 1) != 1) | |||
| return false; | |||
| initialise (c); | |||
| initialise (c); | |||
| } | |||
| if (transparent >= 0) | |||
| { | |||
| @@ -389,7 +390,7 @@ private: | |||
| uint8* p = destData.data; | |||
| const bool hasAlpha = image.hasAlphaChannel(); | |||
| while ((index = readLZWByte (c)) >= 0) | |||
| while ((index = readLZWByte()) >= 0) | |||
| { | |||
| const uint8* const paletteEntry = palette [index]; | |||
| @@ -74,7 +74,7 @@ bool FileOutputStream::flushBuffer() | |||
| if (bytesInBuffer > 0) | |||
| { | |||
| ok = writeInternal (buffer, bytesInBuffer); | |||
| ok = (writeInternal (buffer, bytesInBuffer) == bytesInBuffer); | |||
| bytesInBuffer = 0; | |||
| } | |||
| @@ -425,6 +425,9 @@ | |||
| #ifndef __JUCE_MODIFIERKEYS_JUCEHEADER__ | |||
| #include "gui/components/keyboard/juce_ModifierKeys.h" | |||
| #endif | |||
| #ifndef __JUCE_TEXTEDITORKEYMAPPER_JUCEHEADER__ | |||
| #include "gui/components/keyboard/juce_TextEditorKeyMapper.h" | |||
| #endif | |||
| #ifndef __JUCE_TEXTINPUTTARGET_JUCEHEADER__ | |||
| #include "gui/components/keyboard/juce_TextInputTarget.h" | |||
| #endif | |||
| @@ -29,35 +29,12 @@ | |||
| //============================================================================== | |||
| #ifndef JUCE_COREAUDIO_ERROR_LOGGING_ENABLED | |||
| #define JUCE_COREAUDIO_ERROR_LOGGING_ENABLED 1 | |||
| #endif | |||
| //============================================================================== | |||
| #undef log | |||
| #if JUCE_COREAUDIO_LOGGING_ENABLED | |||
| #define log(a) Logger::writeToLog (a) | |||
| #else | |||
| #define log(a) | |||
| #endif | |||
| #undef OK | |||
| #if JUCE_COREAUDIO_ERROR_LOGGING_ENABLED | |||
| static bool logAnyErrors_CoreAudio (const OSStatus err, const int lineNum) | |||
| { | |||
| if (err == noErr) | |||
| return true; | |||
| Logger::writeToLog ("CoreAudio error: " + String (lineNum) + " - " + String::toHexString ((int) err)); | |||
| return false; | |||
| } | |||
| #define OK(a) logAnyErrors_CoreAudio (a, __LINE__) | |||
| #if JUCE_COREAUDIO_LOGGING_ENABLED //|| ! defined (JUCE_COREAUDIO_LOGGING_ENABLED) | |||
| #define JUCE_COREAUDIOLOG(a) Logger::writeToLog (a) | |||
| #else | |||
| #define OK(a) (a == noErr) | |||
| #define JUCE_COREAUDIOLOG(a) | |||
| #endif | |||
| //============================================================================== | |||
| class CoreAudioInternal : public Timer | |||
| { | |||
| @@ -296,7 +273,7 @@ public: | |||
| rates << sampleRate; | |||
| } | |||
| log ("sr: " + rates); | |||
| JUCE_COREAUDIOLOG ("sr: " + rates); | |||
| inputLatency = 0; | |||
| outputLatency = 0; | |||
| @@ -313,7 +290,7 @@ public: | |||
| if (AudioObjectGetPropertyData (deviceID, &pa, 0, 0, &size, &lat) == noErr) | |||
| outputLatency = (int) lat; | |||
| log ("lat: " + String (inputLatency) + " " + String (outputLatency)); | |||
| JUCE_COREAUDIOLOG ("lat: " + String (inputLatency) + " " + String (outputLatency)); | |||
| inChanNames.clear(); | |||
| outChanNames.clear(); | |||
| @@ -422,7 +399,7 @@ public: | |||
| int bufferSizeSamples) | |||
| { | |||
| String error; | |||
| log ("CoreAudio reopen"); | |||
| JUCE_COREAUDIOLOG ("CoreAudio reopen"); | |||
| callbacksAllowed = false; | |||
| stopTimer(); | |||
| @@ -496,11 +473,11 @@ public: | |||
| if (deviceID != 0) | |||
| { | |||
| #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 | |||
| #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 | |||
| if (OK (AudioDeviceAddIOProc (deviceID, audioIOProc, this))) | |||
| #else | |||
| #else | |||
| if (OK (AudioDeviceCreateIOProcID (deviceID, audioIOProc, this, &audioProcID))) | |||
| #endif | |||
| #endif | |||
| { | |||
| if (OK (AudioDeviceStart (deviceID, audioIOProc))) | |||
| { | |||
| @@ -508,12 +485,12 @@ public: | |||
| } | |||
| else | |||
| { | |||
| #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 | |||
| #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 | |||
| OK (AudioDeviceRemoveIOProc (deviceID, audioIOProc)); | |||
| #else | |||
| #else | |||
| OK (AudioDeviceDestroyIOProcID (deviceID, audioProcID)); | |||
| audioProcID = 0; | |||
| #endif | |||
| #endif | |||
| } | |||
| } | |||
| } | |||
| @@ -525,10 +502,7 @@ public: | |||
| callback = cb; | |||
| } | |||
| if (inputDevice != nullptr) | |||
| return started && inputDevice->start (cb); | |||
| else | |||
| return started; | |||
| return started && (inputDevice == nullptr || inputDevice->start (cb)); | |||
| } | |||
| void stop (bool leaveInterruptRunning) | |||
| @@ -544,12 +518,13 @@ public: | |||
| { | |||
| OK (AudioDeviceStop (deviceID, audioIOProc)); | |||
| #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 | |||
| #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 | |||
| OK (AudioDeviceRemoveIOProc (deviceID, audioIOProc)); | |||
| #else | |||
| #else | |||
| OK (AudioDeviceDestroyIOProcID (deviceID, audioProcID)); | |||
| audioProcID = 0; | |||
| #endif | |||
| #endif | |||
| started = false; | |||
| { const ScopedLock sl (callbackLock); } | |||
| @@ -580,15 +555,8 @@ public: | |||
| inputDevice->stop (leaveInterruptRunning); | |||
| } | |||
| double getSampleRate() const | |||
| { | |||
| return sampleRate; | |||
| } | |||
| int getBufferSize() const | |||
| { | |||
| return bufferSize; | |||
| } | |||
| double getSampleRate() const { return sampleRate; } | |||
| int getBufferSize() const { return bufferSize; } | |||
| void audioCallback (const AudioBufferList* inInputData, | |||
| AudioBufferList* outOutputData) | |||
| @@ -695,7 +663,7 @@ public: | |||
| void timerCallback() | |||
| { | |||
| stopTimer(); | |||
| log ("CoreAudio device changed callback"); | |||
| JUCE_COREAUDIOLOG ("CoreAudio device changed callback"); | |||
| const double oldSampleRate = sampleRate; | |||
| const int oldBufferSize = bufferSize; | |||
| @@ -759,9 +727,9 @@ public: | |||
| Array <double> sampleRates; | |||
| Array <int> bufferSizes; | |||
| AudioIODeviceCallback* callback; | |||
| #if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 | |||
| #if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 | |||
| AudioDeviceIOProcID audioProcID; | |||
| #endif | |||
| #endif | |||
| ScopedPointer<CoreAudioInternal> inputDevice; | |||
| bool isSlaveDevice; | |||
| @@ -836,17 +804,31 @@ private: | |||
| UInt32 size = 0; | |||
| if (deviceID != 0 | |||
| && OK (AudioObjectGetPropertyDataSize (deviceID, &pa, 0, 0, &size))) | |||
| && AudioObjectGetPropertyDataSize (deviceID, &pa, 0, 0, &size) == noErr) | |||
| { | |||
| types.calloc (size, 1); | |||
| if (OK (AudioObjectGetPropertyData (deviceID, &pa, 0, 0, &size, types))) | |||
| if (AudioObjectGetPropertyData (deviceID, &pa, 0, 0, &size, types) == noErr) | |||
| return size / (int) sizeof (OSType); | |||
| } | |||
| return 0; | |||
| } | |||
| bool OK (const OSStatus errorCode) const | |||
| { | |||
| if (errorCode == noErr) | |||
| return true; | |||
| const String errorMessage ("CoreAudio error: " + String::toHexString ((int) errorCode)); | |||
| JUCE_COREAUDIOLOG (errorMessage); | |||
| if (callback != nullptr) | |||
| callback->audioDeviceError (errorMessage); | |||
| return false; | |||
| } | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CoreAudioInternal); | |||
| }; | |||
| @@ -888,6 +870,7 @@ public: | |||
| } | |||
| internal = device; | |||
| jassert (device != nullptr); | |||
| AudioObjectPropertyAddress pa; | |||
| pa.mSelector = kAudioObjectPropertySelectorWildcard; | |||
| @@ -922,25 +905,17 @@ public: | |||
| return internal->inChanNames; | |||
| } | |||
| int getNumSampleRates() | |||
| { | |||
| return internal->sampleRates.size(); | |||
| } | |||
| bool isOpen() { return isOpen_; } | |||
| double getSampleRate (int index) | |||
| { | |||
| return internal->sampleRates [index]; | |||
| } | |||
| int getNumSampleRates() { return internal->sampleRates.size(); } | |||
| double getSampleRate (int index) { return internal->sampleRates [index]; } | |||
| double getCurrentSampleRate() { return internal->getSampleRate(); } | |||
| int getNumBufferSizesAvailable() | |||
| { | |||
| return internal->bufferSizes.size(); | |||
| } | |||
| int getCurrentBitDepth() { return 32; } // no way to find out, so just assume it's high.. | |||
| int getBufferSizeSamples (int index) | |||
| { | |||
| return internal->bufferSizes [index]; | |||
| } | |||
| int getNumBufferSizesAvailable() { return internal->bufferSizes.size(); } | |||
| int getBufferSizeSamples (int index) { return internal->bufferSizes [index]; } | |||
| int getCurrentBufferSizeSamples() { return internal->getBufferSize(); } | |||
| int getDefaultBufferSize() | |||
| { | |||
| @@ -972,51 +947,23 @@ public: | |||
| internal->stop (false); | |||
| } | |||
| bool isOpen() | |||
| { | |||
| return isOpen_; | |||
| } | |||
| int getCurrentBufferSizeSamples() | |||
| { | |||
| return internal != nullptr ? internal->getBufferSize() : 512; | |||
| } | |||
| double getCurrentSampleRate() | |||
| { | |||
| return internal != nullptr ? internal->getSampleRate() : 0; | |||
| } | |||
| int getCurrentBitDepth() | |||
| { | |||
| return 32; // no way to find out, so just assume it's high.. | |||
| } | |||
| const BigInteger getActiveOutputChannels() const | |||
| { | |||
| return internal != nullptr ? internal->activeOutputChans : BigInteger(); | |||
| return internal->activeOutputChans; | |||
| } | |||
| const BigInteger getActiveInputChannels() const | |||
| { | |||
| BigInteger chans; | |||
| BigInteger chans (internal->activeInputChans); | |||
| if (internal != nullptr) | |||
| { | |||
| chans = internal->activeInputChans; | |||
| if (internal->inputDevice != 0) | |||
| chans |= internal->inputDevice->activeInputChans; | |||
| } | |||
| if (internal->inputDevice != nullptr) | |||
| chans |= internal->inputDevice->activeInputChans; | |||
| return chans; | |||
| } | |||
| int getOutputLatencyInSamples() | |||
| { | |||
| if (internal == nullptr) | |||
| return 0; | |||
| // this seems like a good guess at getting the latency right - comparing | |||
| // this with a round-trip measurement, it gets it to within a few millisecs | |||
| // for the built-in mac soundcard | |||
| @@ -1025,15 +972,12 @@ public: | |||
| int getInputLatencyInSamples() | |||
| { | |||
| if (internal == nullptr) | |||
| return 0; | |||
| return internal->inputLatency + internal->getBufferSize() * 2; | |||
| } | |||
| void start (AudioIODeviceCallback* callback) | |||
| { | |||
| if (internal != nullptr && ! isStarted) | |||
| if (! isStarted) | |||
| { | |||
| if (callback != nullptr) | |||
| callback->audioDeviceAboutToStart (this); | |||
| @@ -1045,7 +989,7 @@ public: | |||
| void stop() | |||
| { | |||
| if (isStarted && internal != nullptr) | |||
| if (isStarted) | |||
| { | |||
| AudioIODeviceCallback* const lastCallback = internal->callback; | |||
| @@ -1110,10 +1054,6 @@ public: | |||
| { | |||
| } | |||
| ~CoreAudioIODeviceType() | |||
| { | |||
| } | |||
| //============================================================================== | |||
| void scanForDevices() | |||
| { | |||
| @@ -1131,12 +1071,12 @@ public: | |||
| pa.mScope = kAudioObjectPropertyScopeWildcard; | |||
| pa.mElement = kAudioObjectPropertyElementMaster; | |||
| if (OK (AudioObjectGetPropertyDataSize (kAudioObjectSystemObject, &pa, 0, 0, &size))) | |||
| if (AudioObjectGetPropertyDataSize (kAudioObjectSystemObject, &pa, 0, 0, &size) == noErr) | |||
| { | |||
| HeapBlock <AudioDeviceID> devs; | |||
| devs.calloc (size, 1); | |||
| if (OK (AudioObjectGetPropertyData (kAudioObjectSystemObject, &pa, 0, 0, &size, devs))) | |||
| if (AudioObjectGetPropertyData (kAudioObjectSystemObject, &pa, 0, 0, &size, devs) == noErr) | |||
| { | |||
| const int num = size / (int) sizeof (AudioDeviceID); | |||
| for (int i = 0; i < num; ++i) | |||
| @@ -1145,7 +1085,7 @@ public: | |||
| size = sizeof (name); | |||
| pa.mSelector = kAudioDevicePropertyDeviceName; | |||
| if (OK (AudioObjectGetPropertyData (devs[i], &pa, 0, 0, &size, name))) | |||
| if (AudioObjectGetPropertyData (devs[i], &pa, 0, 0, &size, name) == noErr) | |||
| { | |||
| const String nameString (String::fromUTF8 (name, (int) strlen (name))); | |||
| const int numIns = getNumChannels (devs[i], true); | |||
| @@ -1175,10 +1115,8 @@ public: | |||
| { | |||
| jassert (hasScanned); // need to call scanForDevices() before doing this | |||
| if (wantInputNames) | |||
| return inputDeviceNames; | |||
| else | |||
| return outputDeviceNames; | |||
| return wantInputNames ? inputDeviceNames | |||
| : outputDeviceNames; | |||
| } | |||
| int getDefaultDeviceIndex (bool forInput) const | |||
| @@ -1268,12 +1206,12 @@ private: | |||
| pa.mScope = input ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput; | |||
| pa.mElement = kAudioObjectPropertyElementMaster; | |||
| if (OK (AudioObjectGetPropertyDataSize (deviceID, &pa, 0, 0, &size))) | |||
| if (AudioObjectGetPropertyDataSize (deviceID, &pa, 0, 0, &size) == noErr) | |||
| { | |||
| HeapBlock <AudioBufferList> bufList; | |||
| bufList.calloc (size, 1); | |||
| if (OK (AudioObjectGetPropertyData (deviceID, &pa, 0, 0, &size, bufList))) | |||
| if (AudioObjectGetPropertyData (deviceID, &pa, 0, 0, &size, bufList) == noErr) | |||
| { | |||
| const int numStreams = bufList->mNumberBuffers; | |||
| @@ -1297,6 +1235,6 @@ AudioIODeviceType* AudioIODeviceType::createAudioIODeviceType_CoreAudio() | |||
| return new CoreAudioIODeviceType(); | |||
| } | |||
| #undef log | |||
| #undef JUCE_COREAUDIOLOG | |||
| #endif | |||