mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-20 01:14:20 +00:00
added a code-editor demo page to the juce demo and added some comments to the code editor classes
This commit is contained in:
parent
f744dd9062
commit
0b2f0f086c
12 changed files with 823 additions and 311 deletions
|
|
@ -36,6 +36,7 @@
|
|||
849144091064E54800456AFC /* AudioDemoRecordPage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 849144071064E54800456AFC /* AudioDemoRecordPage.cpp */; };
|
||||
849786F3103560630020003B /* DiscRecording.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 849786F2103560630020003B /* DiscRecording.framework */; };
|
||||
84E81551100BAF6200FAE212 /* WebBrowserDemo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84E81550100BAF6200FAE212 /* WebBrowserDemo.cpp */; };
|
||||
84EDCA1F10A19E730079DB17 /* CodeEditorDemo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84EDCA1E10A19E730079DB17 /* CodeEditorDemo.cpp */; };
|
||||
84EE00FA0FF22E390093FACA /* CameraDemo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84EE00F90FF22E390093FACA /* CameraDemo.cpp */; };
|
||||
84EE01200FF23BBE0093FACA /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84EE011F0FF23BBE0093FACA /* QuartzCore.framework */; };
|
||||
84FFCF3B0EDAFE7F007D5302 /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84FFCF3A0EDAFE7F007D5302 /* Carbon.framework */; };
|
||||
|
|
@ -83,6 +84,7 @@
|
|||
849144081064E54800456AFC /* AudioDemoRecordPage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AudioDemoRecordPage.h; path = ../../src/demos/AudioDemoRecordPage.h; sourceTree = SOURCE_ROOT; };
|
||||
849786F2103560630020003B /* DiscRecording.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DiscRecording.framework; path = System/Library/Frameworks/DiscRecording.framework; sourceTree = SDKROOT; };
|
||||
84E81550100BAF6200FAE212 /* WebBrowserDemo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 2; name = WebBrowserDemo.cpp; path = ../../src/demos/WebBrowserDemo.cpp; sourceTree = SOURCE_ROOT; };
|
||||
84EDCA1E10A19E730079DB17 /* CodeEditorDemo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CodeEditorDemo.cpp; path = ../../src/demos/CodeEditorDemo.cpp; sourceTree = SOURCE_ROOT; };
|
||||
84EE00F90FF22E390093FACA /* CameraDemo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CameraDemo.cpp; path = ../../src/demos/CameraDemo.cpp; sourceTree = SOURCE_ROOT; };
|
||||
84EE011F0FF23BBE0093FACA /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
|
||||
84FFCF3A0EDAFE7F007D5302 /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = /System/Library/Frameworks/Carbon.framework; sourceTree = "<absolute>"; };
|
||||
|
|
@ -189,6 +191,7 @@
|
|||
84913FDC1063947900456AFC /* AudioDemoTabComponent.cpp */,
|
||||
84913FDD1063947900456AFC /* AudioDemoTabComponent.h */,
|
||||
84EE00F90FF22E390093FACA /* CameraDemo.cpp */,
|
||||
84EDCA1E10A19E730079DB17 /* CodeEditorDemo.cpp */,
|
||||
847F4E9B0E8BA9C300F64426 /* DragAndDropDemo.cpp */,
|
||||
847F4E9C0E8BA9C300F64426 /* FontsAndTextDemo.cpp */,
|
||||
847F4E9D0E8BA9C300F64426 /* InterprocessCommsDemo.cpp */,
|
||||
|
|
@ -279,6 +282,7 @@
|
|||
84913FE11063947900456AFC /* AudioDemoSynthPage.cpp in Sources */,
|
||||
84913FE21063947900456AFC /* AudioDemoTabComponent.cpp in Sources */,
|
||||
849144091064E54800456AFC /* AudioDemoRecordPage.cpp in Sources */,
|
||||
84EDCA1F10A19E730079DB17 /* CodeEditorDemo.cpp in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -354,6 +354,10 @@
|
|||
RelativePath="..\..\src\demos\CameraDemo.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\demos\CodeEditorDemo.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\demos\DragAndDropDemo.cpp"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ class ContentComp : public Component,
|
|||
showTable = 0x2010,
|
||||
showCamera = 0x2011,
|
||||
showWebBrowser = 0x2012,
|
||||
showCodeEditor = 0x2013,
|
||||
|
||||
setDefaultLookAndFeel = 0x200b,
|
||||
setOldSchoolLookAndFeel = 0x200c,
|
||||
|
|
@ -133,6 +134,7 @@ public:
|
|||
menu.addCommandItem (commandManager, showInterprocessComms);
|
||||
menu.addCommandItem (commandManager, showCamera);
|
||||
menu.addCommandItem (commandManager, showWebBrowser);
|
||||
menu.addCommandItem (commandManager, showCodeEditor);
|
||||
|
||||
menu.addSeparator();
|
||||
menu.addCommandItem (commandManager, StandardApplicationCommandIDs::quit);
|
||||
|
|
@ -190,6 +192,7 @@ public:
|
|||
showQuicktime,
|
||||
showCamera,
|
||||
showWebBrowser,
|
||||
showCodeEditor,
|
||||
showInterprocessComms,
|
||||
setDefaultLookAndFeel,
|
||||
setOldSchoolLookAndFeel,
|
||||
|
|
@ -299,6 +302,12 @@ public:
|
|||
#endif
|
||||
break;
|
||||
|
||||
case showCodeEditor:
|
||||
result.setInfo (T("Code Editor"), T("Shows the code editor demo"), demosCategory, 0);
|
||||
result.addDefaultKeypress (T('e'), ModifierKeys::commandModifier);
|
||||
result.setTicked (currentDemoId == showCodeEditor);
|
||||
break;
|
||||
|
||||
case showInterprocessComms:
|
||||
result.setInfo (T("Interprocess Comms"), T("Shows the interprocess communications demo"), demosCategory, 0);
|
||||
result.addDefaultKeypress (T('0'), ModifierKeys::commandModifier);
|
||||
|
|
@ -412,6 +421,11 @@ public:
|
|||
#endif
|
||||
break;
|
||||
|
||||
case showCodeEditor:
|
||||
showDemo (createCodeEditorDemo());
|
||||
currentDemoId = showCodeEditor;
|
||||
break;
|
||||
|
||||
case showInterprocessComms:
|
||||
showDemo (createInterprocessCommsDemo());
|
||||
currentDemoId = showInterprocessComms;
|
||||
|
|
|
|||
96
extras/juce demo/src/demos/CodeEditorDemo.cpp
Normal file
96
extras/juce demo/src/demos/CodeEditorDemo.cpp
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library - "Jules' Utility Class Extensions"
|
||||
Copyright 2004-9 by Raw Material Software Ltd.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
JUCE can be redistributed and/or modified under the terms of the GNU General
|
||||
Public License (Version 2), as published by the Free Software Foundation.
|
||||
A copy of the license is included in the JUCE distribution, or can be found
|
||||
online at www.gnu.org/licenses.
|
||||
|
||||
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
To release a closed-source product which uses JUCE, commercial licenses are
|
||||
available: visit www.rawmaterialsoftware.com/juce for more information.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "../jucedemo_headers.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class CodeEditorDemo : public Component,
|
||||
public FilenameComponentListener
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
CodeEditorDemo()
|
||||
{
|
||||
setName ("Code Editor");
|
||||
setOpaque (true);
|
||||
|
||||
// Create the editor..
|
||||
addAndMakeVisible (editor = new CodeEditorComponent (codeDocument, &cppTokeniser));
|
||||
|
||||
// Create a file chooser control to load files into it..
|
||||
addAndMakeVisible (fileChooser = new FilenameComponent ("File", File::nonexistent, true, false, false,
|
||||
"*.cpp;*.h;*.hpp;*.c;*.mm;*.m", String::empty,
|
||||
"Choose a C++ file to open it in the editor"));
|
||||
fileChooser->addListener (this);
|
||||
|
||||
|
||||
editor->loadContent ("\n\n/* Code editor demo! Please be gentle, this component is still an alpha version! */\n\n");
|
||||
}
|
||||
|
||||
~CodeEditorDemo()
|
||||
{
|
||||
deleteAllChildren();
|
||||
}
|
||||
|
||||
void filenameComponentChanged (FilenameComponent* fileComponentThatHasChanged)
|
||||
{
|
||||
File f (fileChooser->getCurrentFile());
|
||||
editor->loadContent (f.loadFileAsString());
|
||||
}
|
||||
|
||||
void paint (Graphics& g)
|
||||
{
|
||||
g.fillAll (Colours::lightgrey);
|
||||
}
|
||||
|
||||
void resized()
|
||||
{
|
||||
editor->setBounds (10, 45, getWidth() - 20, getHeight() - 55);
|
||||
fileChooser->setBounds (10, 10, getWidth() - 20, 25);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
juce_UseDebuggingNewOperator
|
||||
|
||||
private:
|
||||
// this is the document that the editor component is showing
|
||||
CodeDocument codeDocument;
|
||||
|
||||
// this is a tokeniser to do the c++ syntax highlighting
|
||||
CPlusPlusCodeTokeniser cppTokeniser;
|
||||
|
||||
// the editor component
|
||||
CodeEditorComponent* editor;
|
||||
|
||||
FilenameComponent* fileChooser;
|
||||
};
|
||||
|
||||
|
||||
//==============================================================================
|
||||
Component* createCodeEditorDemo()
|
||||
{
|
||||
return new CodeEditorDemo();
|
||||
}
|
||||
|
|
@ -50,6 +50,7 @@ Component* createTableDemo();
|
|||
Component* createAudioDemo();
|
||||
Component* createDragAndDropDemo();
|
||||
Component* createInterprocessCommsDemo();
|
||||
Component* createCodeEditorDemo();
|
||||
|
||||
#if JUCE_QUICKTIME && ! JUCE_LINUX
|
||||
Component* createQuickTimeDemo();
|
||||
|
|
|
|||
|
|
@ -43627,18 +43627,14 @@ void CodeDocument::Position::setPosition (const int newPosition) throw()
|
|||
}
|
||||
}
|
||||
|
||||
void CodeDocument::Position::updateLineAndIndexFromPosition() throw()
|
||||
{
|
||||
setPosition (getPosition());
|
||||
}
|
||||
|
||||
void CodeDocument::Position::moveBy (int characterDelta) throw()
|
||||
{
|
||||
jassert (owner != 0);
|
||||
|
||||
updateLineAndIndexFromPosition();
|
||||
if (characterDelta == 1)
|
||||
{
|
||||
setPosition (getPosition());
|
||||
|
||||
// If moving right, make sure we don't get stuck between the \r and \n characters..
|
||||
CodeDocumentLine* const l = owner->lines.getUnchecked (line);
|
||||
if (indexInLine + characterDelta < l->lineLength
|
||||
|
|
@ -43701,7 +43697,8 @@ CodeDocument::CodeDocument()
|
|||
: undoManager (INT_MAX, 10000),
|
||||
currentActionIndex (0),
|
||||
indexOfSavedState (-1),
|
||||
maximumLineLength (-1)
|
||||
maximumLineLength (-1),
|
||||
newLineChars ("\r\n")
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -43807,6 +43804,12 @@ void CodeDocument::replaceAllContent (const String& newContent)
|
|||
insert (newContent, 0, true);
|
||||
}
|
||||
|
||||
void CodeDocument::setNewLineCharacters (const String& newLine) throw()
|
||||
{
|
||||
jassert (newLine == T("\r\n") || newLine == T("\n") || newLine == T("\r"));
|
||||
newLineChars = newLine;
|
||||
}
|
||||
|
||||
void CodeDocument::newTransaction()
|
||||
{
|
||||
undoManager.beginNewTransaction (String::empty);
|
||||
|
|
@ -43823,7 +43826,7 @@ void CodeDocument::redo()
|
|||
undoManager.redo();
|
||||
}
|
||||
|
||||
void CodeDocument::clearUndoManager()
|
||||
void CodeDocument::clearUndoHistory()
|
||||
{
|
||||
undoManager.clearUndoHistory();
|
||||
}
|
||||
|
|
@ -43922,12 +43925,12 @@ const CodeDocument::Position CodeDocument::findWordBreakBefore (const Position&
|
|||
return p;
|
||||
}
|
||||
|
||||
void CodeDocument::addListener (CodeDocument::Listener* const listener)
|
||||
void CodeDocument::addListener (CodeDocument::Listener* const listener) throw()
|
||||
{
|
||||
listeners.addIfNotAlreadyThere (listener);
|
||||
}
|
||||
|
||||
void CodeDocument::removeListener (CodeDocument::Listener* const listener)
|
||||
void CodeDocument::removeListener (CodeDocument::Listener* const listener) throw()
|
||||
{
|
||||
listeners.removeValue (listener);
|
||||
}
|
||||
|
|
@ -44028,11 +44031,12 @@ void CodeDocument::insert (const String& text, const int insertPos, const bool u
|
|||
lastAffectedLine = lines.size();
|
||||
}
|
||||
|
||||
for (int i = firstAffectedLine + 1; i < lines.size(); ++i)
|
||||
int lineStart = newFirstLine->lineStartInFile;
|
||||
for (int i = firstAffectedLine; i < lines.size(); ++i)
|
||||
{
|
||||
CodeDocumentLine* const l = lines.getUnchecked (i);
|
||||
const CodeDocumentLine* const previousLine = lines.getUnchecked (i - 1);
|
||||
l->lineStartInFile = previousLine->lineStartInFile + previousLine->lineLength;
|
||||
l->lineStartInFile = lineStart;
|
||||
lineStart += l->lineLength;
|
||||
}
|
||||
|
||||
const int newTextLength = text.length();
|
||||
|
|
@ -44041,7 +44045,7 @@ void CodeDocument::insert (const String& text, const int insertPos, const bool u
|
|||
CodeDocument::Position* const p = positionsToMaintain.getUnchecked(i);
|
||||
|
||||
if (p->getPosition() >= insertPos)
|
||||
p->moveBy (newTextLength);
|
||||
p->setPosition (p->getPosition() + newTextLength);
|
||||
}
|
||||
|
||||
sendListenerChangeMessage (firstAffectedLine, lastAffectedLine);
|
||||
|
|
@ -44141,7 +44145,7 @@ void CodeDocument::remove (const int startPos, const int endPos, const bool undo
|
|||
CodeDocument::Position* p = positionsToMaintain.getUnchecked(i);
|
||||
|
||||
if (p->getPosition() > startPosition.getPosition())
|
||||
p->setPosition (jmax (startPos, startPos - endPos));
|
||||
p->setPosition (jmax (startPos, p->getPosition() + startPos - endPos));
|
||||
|
||||
if (p->getPosition() > totalChars)
|
||||
p->setPosition (totalChars);
|
||||
|
|
@ -44411,6 +44415,7 @@ CodeEditorComponent::CodeEditorComponent (CodeDocument& document_,
|
|||
gutter (5),
|
||||
spacesPerTab (4),
|
||||
lineHeight (0),
|
||||
firstLineOnScreen (0),
|
||||
linesOnScreen (0),
|
||||
columnsOnScreen (0),
|
||||
scrollbarThickness (16),
|
||||
|
|
@ -44442,7 +44447,7 @@ CodeEditorComponent::CodeEditorComponent (CodeDocument& document_,
|
|||
f.setTypefaceName (Font::getDefaultMonospacedFontName());
|
||||
setFont (f);
|
||||
|
||||
setDefaultColours();
|
||||
resetToDefaultColours();
|
||||
|
||||
verticalScrollBar->addListener (this);
|
||||
horizontalScrollBar->addListener (this);
|
||||
|
|
@ -44459,7 +44464,7 @@ void CodeEditorComponent::loadContent (const String& newContent)
|
|||
{
|
||||
clearCachedIterators (0);
|
||||
document.replaceAllContent (newContent);
|
||||
document.clearUndoManager();
|
||||
document.clearUndoHistory();
|
||||
document.setSavePoint();
|
||||
caretPos.setPosition (0);
|
||||
selectionStart.setPosition (0);
|
||||
|
|
@ -44472,7 +44477,8 @@ void CodeEditorComponent::codeDocumentChanged (const CodeDocument::Position& aff
|
|||
{
|
||||
clearCachedIterators (affectedTextStart.getLineNumber());
|
||||
|
||||
rebuildLineTokens();
|
||||
triggerAsyncUpdate();
|
||||
|
||||
((CaretComponent*) caret)->updatePosition (*this);
|
||||
|
||||
if (affectedTextEnd.getPosition() >= selectionStart.getPosition()
|
||||
|
|
@ -44495,12 +44501,14 @@ void CodeEditorComponent::resized()
|
|||
((CaretComponent*) caret)->updatePosition (*this);
|
||||
|
||||
verticalScrollBar->setBounds (getWidth() - scrollbarThickness, 0, scrollbarThickness, getHeight() - scrollbarThickness);
|
||||
horizontalScrollBar->setBounds (0, getHeight() - scrollbarThickness, getWidth() - scrollbarThickness, scrollbarThickness);
|
||||
horizontalScrollBar->setBounds (gutter, getHeight() - scrollbarThickness, getWidth() - scrollbarThickness - gutter, scrollbarThickness);
|
||||
updateScrollBars();
|
||||
}
|
||||
|
||||
void CodeEditorComponent::paint (Graphics& g)
|
||||
{
|
||||
handleUpdateNowIfNeeded();
|
||||
|
||||
g.fillAll (findColour (CodeEditorComponent::backgroundColourId));
|
||||
|
||||
g.reduceClipRegion (gutter, 0, verticalScrollBar->getX() - gutter, horizontalScrollBar->getY());
|
||||
|
|
@ -44518,8 +44526,14 @@ void CodeEditorComponent::paint (Graphics& g)
|
|||
highlightColour, charWidth);
|
||||
}
|
||||
|
||||
void CodeEditorComponent::handleAsyncUpdate()
|
||||
{
|
||||
rebuildLineTokens();
|
||||
}
|
||||
|
||||
void CodeEditorComponent::rebuildLineTokens()
|
||||
{
|
||||
cancelPendingUpdate();
|
||||
const int numNeeded = linesOnScreen + 1;
|
||||
|
||||
if (numNeeded != lines.size())
|
||||
|
|
@ -44588,7 +44602,7 @@ void CodeEditorComponent::moveCaretTo (const CodeDocument::Position& newPos, con
|
|||
}
|
||||
}
|
||||
|
||||
rebuildLineTokens();
|
||||
triggerAsyncUpdate();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -44602,11 +44616,11 @@ void CodeEditorComponent::moveCaretTo (const CodeDocument::Position& newPos, con
|
|||
|
||||
void CodeEditorComponent::deselectAll()
|
||||
{
|
||||
if (selectionStart != caretPos || selectionEnd != caretPos)
|
||||
{
|
||||
selectionStart = selectionEnd = caretPos;
|
||||
rebuildLineTokens();
|
||||
}
|
||||
if (selectionStart != selectionEnd)
|
||||
triggerAsyncUpdate();
|
||||
|
||||
selectionStart = caretPos;
|
||||
selectionEnd = caretPos;
|
||||
}
|
||||
|
||||
void CodeEditorComponent::updateScrollBars()
|
||||
|
|
@ -44620,13 +44634,17 @@ void CodeEditorComponent::updateScrollBars()
|
|||
|
||||
void CodeEditorComponent::scrollToLineInternal (int newFirstLineOnScreen)
|
||||
{
|
||||
firstLineOnScreen = jlimit (0, jmax (0, document.getNumLines() - 1),
|
||||
newFirstLineOnScreen);
|
||||
newFirstLineOnScreen = jlimit (0, jmax (0, document.getNumLines() - 1),
|
||||
newFirstLineOnScreen);
|
||||
|
||||
((CaretComponent*) caret)->updatePosition (*this);
|
||||
if (newFirstLineOnScreen != firstLineOnScreen)
|
||||
{
|
||||
firstLineOnScreen = newFirstLineOnScreen;
|
||||
((CaretComponent*) caret)->updatePosition (*this);
|
||||
|
||||
updateCachedIterators (firstLineOnScreen);
|
||||
rebuildLineTokens();
|
||||
updateCachedIterators (firstLineOnScreen);
|
||||
triggerAsyncUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
void CodeEditorComponent::scrollToColumnInternal (double column)
|
||||
|
|
@ -44741,7 +44759,7 @@ void CodeEditorComponent::copyThenCut()
|
|||
void CodeEditorComponent::paste()
|
||||
{
|
||||
newTransaction();
|
||||
const String clip (SystemClipboard::getTextFromClipboard()/*.replace (T("\r\n"), T("\n"))*/);
|
||||
const String clip (SystemClipboard::getTextFromClipboard());
|
||||
|
||||
if (clip.isNotEmpty())
|
||||
insertTextAtCaret (clip);
|
||||
|
|
@ -44823,7 +44841,7 @@ void CodeEditorComponent::scrollDown()
|
|||
moveCaretTo (caretPos.movedByLines (-1), false);
|
||||
}
|
||||
|
||||
void CodeEditorComponent::goToStart (const bool selecting)
|
||||
void CodeEditorComponent::goToStartOfDocument (const bool selecting)
|
||||
{
|
||||
newTransaction();
|
||||
moveCaretTo (CodeDocument::Position (&document, 0, 0), selecting);
|
||||
|
|
@ -44852,7 +44870,7 @@ void CodeEditorComponent::goToStartOfLine (const bool selecting)
|
|||
moveCaretTo (CodeDocument::Position (&document, caretPos.getLineNumber(), index), selecting);
|
||||
}
|
||||
|
||||
void CodeEditorComponent::goToEnd (const bool selecting)
|
||||
void CodeEditorComponent::goToEndOfDocument (const bool selecting)
|
||||
{
|
||||
newTransaction();
|
||||
moveCaretTo (CodeDocument::Position (&document, INT_MAX, INT_MAX), selecting);
|
||||
|
|
@ -44947,7 +44965,7 @@ bool CodeEditorComponent::keyPressed (const KeyPress& key)
|
|||
scrollDown();
|
||||
#if JUCE_MAC
|
||||
else if (key.getModifiers().isCommandDown())
|
||||
goToStart (shiftDown);
|
||||
goToStartOfDocument (shiftDown);
|
||||
#endif
|
||||
else
|
||||
cursorUp (shiftDown);
|
||||
|
|
@ -44958,7 +44976,7 @@ bool CodeEditorComponent::keyPressed (const KeyPress& key)
|
|||
scrollUp();
|
||||
#if JUCE_MAC
|
||||
else if (key.getModifiers().isCommandDown())
|
||||
goToEnd (shiftDown);
|
||||
goToEndOfDocument (shiftDown);
|
||||
#endif
|
||||
else
|
||||
cursorDown (shiftDown);
|
||||
|
|
@ -44974,14 +44992,14 @@ bool CodeEditorComponent::keyPressed (const KeyPress& key)
|
|||
else if (key.isKeyCode (KeyPress::homeKey))
|
||||
{
|
||||
if (moveInWholeWordSteps)
|
||||
goToStart (shiftDown);
|
||||
goToStartOfDocument (shiftDown);
|
||||
else
|
||||
goToStartOfLine (shiftDown);
|
||||
}
|
||||
else if (key.isKeyCode (KeyPress::endKey))
|
||||
{
|
||||
if (moveInWholeWordSteps)
|
||||
goToEnd (shiftDown);
|
||||
goToEndOfDocument (shiftDown);
|
||||
else
|
||||
goToEndOfLine (shiftDown);
|
||||
}
|
||||
|
|
@ -45025,7 +45043,7 @@ bool CodeEditorComponent::keyPressed (const KeyPress& key)
|
|||
else if (key == KeyPress::returnKey)
|
||||
{
|
||||
newTransaction();
|
||||
insertTextAtCaret (T("\r\n"));
|
||||
insertTextAtCaret (document.getNewLineCharacters());
|
||||
}
|
||||
else if (key.isKeyCode (KeyPress::escapeKey))
|
||||
{
|
||||
|
|
@ -45119,14 +45137,14 @@ void CodeEditorComponent::scrollBarMoved (ScrollBar* scrollBarThatHasMoved, cons
|
|||
scrollToColumnInternal (newRangeStart);
|
||||
}
|
||||
|
||||
void CodeEditorComponent::setTabSize (const int numSpaces, const bool insertSpaces)
|
||||
void CodeEditorComponent::setTabSize (const int numSpaces, const bool insertSpaces) throw()
|
||||
{
|
||||
useSpacesForTabs = insertSpaces;
|
||||
|
||||
if (spacesPerTab != numSpaces)
|
||||
{
|
||||
spacesPerTab = numSpaces;
|
||||
rebuildLineTokens();
|
||||
triggerAsyncUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -45175,34 +45193,34 @@ void CodeEditorComponent::setFont (const Font& newFont)
|
|||
resized();
|
||||
}
|
||||
|
||||
void CodeEditorComponent::setDefaultColours()
|
||||
void CodeEditorComponent::resetToDefaultColours()
|
||||
{
|
||||
coloursForTokenCategories.clear();
|
||||
|
||||
if (codeTokeniser != 0)
|
||||
{
|
||||
for (int i = codeTokeniser->getTokenTypes().size(); --i >= 0;)
|
||||
setColourForTokenCategory (i, codeTokeniser->getDefaultColour (i));
|
||||
setColourForTokenType (i, codeTokeniser->getDefaultColour (i));
|
||||
}
|
||||
}
|
||||
|
||||
void CodeEditorComponent::setColourForTokenCategory (const int tokenCategory, const Colour& colour)
|
||||
void CodeEditorComponent::setColourForTokenType (const int tokenType, const Colour& colour)
|
||||
{
|
||||
jassert (tokenCategory < 256);
|
||||
jassert (tokenType < 256);
|
||||
|
||||
while (coloursForTokenCategories.size() < tokenCategory)
|
||||
while (coloursForTokenCategories.size() < tokenType)
|
||||
coloursForTokenCategories.add (Colours::black);
|
||||
|
||||
coloursForTokenCategories.set (tokenCategory, colour);
|
||||
coloursForTokenCategories.set (tokenType, colour);
|
||||
repaint();
|
||||
}
|
||||
|
||||
const Colour CodeEditorComponent::getColourForTokenCategory (const int tokenCategory) const
|
||||
const Colour CodeEditorComponent::getColourForTokenType (const int tokenType) const throw()
|
||||
{
|
||||
if (((unsigned int) tokenCategory) >= (unsigned int) coloursForTokenCategories.size())
|
||||
if (((unsigned int) tokenType) >= (unsigned int) coloursForTokenCategories.size())
|
||||
return findColour (CodeEditorComponent::defaultTextColourId);
|
||||
|
||||
return coloursForTokenCategories.getReference (tokenCategory);
|
||||
return coloursForTokenCategories.getReference (tokenType);
|
||||
}
|
||||
|
||||
void CodeEditorComponent::clearCachedIterators (const int firstLineToBeInvalid) throw()
|
||||
|
|
|
|||
|
|
@ -2251,14 +2251,14 @@ public:
|
|||
explicit String (const double doubleValue,
|
||||
const int numberOfDecimalPlaces = 0) throw();
|
||||
|
||||
/** Parses this string to find its numerical value (up to 32 bits in size).
|
||||
/** Reads the value of the string as a decimal number (up to 32 bits in size).
|
||||
|
||||
@returns the value of the string as a 32 bit signed base-10 integer.
|
||||
@see getTrailingIntValue, getHexValue32, getHexValue64
|
||||
*/
|
||||
int getIntValue() const throw();
|
||||
|
||||
/** Parses this string to find its numerical value (up to 64 bits in size).
|
||||
/** Reads the value of the string as a decimal number (up to 64 bits in size).
|
||||
|
||||
@returns the value of the string as a 64 bit signed base-10 integer.
|
||||
*/
|
||||
|
|
@ -44462,12 +44462,11 @@ class CodeDocumentLine;
|
|||
class JUCE_API CodeDocument
|
||||
{
|
||||
public:
|
||||
/**
|
||||
/** Creates a new, empty document.
|
||||
*/
|
||||
CodeDocument();
|
||||
|
||||
/**
|
||||
*/
|
||||
/** Destructor. */
|
||||
~CodeDocument();
|
||||
|
||||
/** A position in a code document.
|
||||
|
|
@ -44480,61 +44479,118 @@ public:
|
|||
class JUCE_API Position
|
||||
{
|
||||
public:
|
||||
/** Creates an uninitialised postion.
|
||||
Don't attempt to call any methods on this until you've given it an owner document
|
||||
to refer to!
|
||||
*/
|
||||
Position() throw();
|
||||
Position (const CodeDocument* const ownerDocument, const int line, const int indexInLine) throw();
|
||||
Position (const CodeDocument* const ownerDocument, const int characterPos) throw();
|
||||
|
||||
/** Creates a position based on a line and index in a document.
|
||||
|
||||
Note that this index is NOT the column number, it's the number of characters from the
|
||||
start of the line. The "column" number isn't quite the same, because if the line
|
||||
contains any tab characters, the relationship of the index to its visual column depends on
|
||||
the number of spaces per tab being used!
|
||||
|
||||
Lines are numbered from zero, and if the line or index are beyond the bounds of the document,
|
||||
they will be adjusted to keep them within its limits.
|
||||
*/
|
||||
Position (const CodeDocument* const ownerDocument,
|
||||
const int line, const int indexInLine) throw();
|
||||
|
||||
/** Creates a position based on a character index in a document.
|
||||
This position is placed at the specified number of characters from the start of the
|
||||
document. The line and column are auto-calculated.
|
||||
|
||||
If the position is beyond the range of the document, it'll be adjusted to keep it
|
||||
inside.
|
||||
*/
|
||||
Position (const CodeDocument* const ownerDocument,
|
||||
const int charactersFromStartOfDocument) throw();
|
||||
|
||||
/** Creates a copy of another position.
|
||||
|
||||
This will copy the position, but the new object will not be set to maintain its position,
|
||||
even if the source object was set to do so.
|
||||
*/
|
||||
Position (const Position& other) throw();
|
||||
|
||||
/** Destructor. */
|
||||
~Position() throw();
|
||||
|
||||
const Position& operator= (const Position& other) throw();
|
||||
bool operator== (const Position& other) const throw();
|
||||
bool operator!= (const Position& other) const throw();
|
||||
|
||||
/**
|
||||
*/
|
||||
void setLineAndIndex (const int newLine, const int newIndexInLine) throw();
|
||||
/** Points this object at a new position within the document.
|
||||
|
||||
/**
|
||||
If the position is beyond the range of the document, it'll be adjusted to keep it
|
||||
inside.
|
||||
@see getPosition, setLineAndIndex
|
||||
*/
|
||||
void setPosition (const int newPosition) throw();
|
||||
void setPosition (const int charactersFromStartOfDocument) throw();
|
||||
|
||||
/**
|
||||
/** Returns the position as the number of characters from the start of the document.
|
||||
@see setPosition, getLineNumber, getIndexInLine
|
||||
*/
|
||||
int getPosition() const throw() { return characterPos; }
|
||||
|
||||
/**
|
||||
/** Moves the position to a new line and index within the line.
|
||||
|
||||
Note that the index is NOT the column at which the position appears in an editor.
|
||||
If the line contains any tab characters, the relationship of the index to its
|
||||
visual position depends on the number of spaces per tab being used!
|
||||
|
||||
Lines are numbered from zero, and if the line or index are beyond the bounds of the document,
|
||||
they will be adjusted to keep them within its limits.
|
||||
*/
|
||||
void setLineAndIndex (const int newLine, const int newIndexInLine) throw();
|
||||
|
||||
/** Returns the line number of this position.
|
||||
The first line in the document is numbered zero, not one!
|
||||
*/
|
||||
int getLineNumber() const throw() { return line; }
|
||||
|
||||
/**
|
||||
/** Returns the number of characters from the start of the line.
|
||||
|
||||
Note that this value is NOT the column at which the position appears in an editor.
|
||||
If the line contains any tab characters, the relationship of the index to its
|
||||
visual position depends on the number of spaces per tab being used!
|
||||
*/
|
||||
int getIndexInLine() const throw() { return indexInLine; }
|
||||
|
||||
/**
|
||||
*/
|
||||
void updateLineAndIndexFromPosition() throw();
|
||||
/** Allows the position to be automatically updated when the document changes.
|
||||
|
||||
/**
|
||||
If this is set to true, the positon will register with its document so that
|
||||
when the document has text inserted or deleted, this position will be automatically
|
||||
moved to keep it at the same position in the text.
|
||||
*/
|
||||
void setPositionMaintained (const bool isMaintained) throw();
|
||||
|
||||
/**
|
||||
/** Moves the position forwards or backwards by the specified number of characters.
|
||||
@see movedBy
|
||||
*/
|
||||
void moveBy (int characterDelta) throw();
|
||||
|
||||
/**
|
||||
/** Returns a position which is the same as this one, moved by the specified number of
|
||||
characters.
|
||||
@see moveBy
|
||||
*/
|
||||
const Position movedBy (const int characterDelta) const throw();
|
||||
|
||||
/**
|
||||
/** Returns a position which is the same as this one, moved up or down by the specified
|
||||
number of lines.
|
||||
@see movedBy
|
||||
*/
|
||||
const Position movedByLines (const int deltaLines) const throw();
|
||||
|
||||
/**
|
||||
/** Returns the character in the document at this position.
|
||||
@see getLineText
|
||||
*/
|
||||
const tchar getCharacter() const throw();
|
||||
|
||||
/**
|
||||
/** Returns the line from the document that this position is within.
|
||||
@see getCharacter, getLineNumber
|
||||
*/
|
||||
const String getLineText() const throw();
|
||||
|
||||
|
|
@ -44544,72 +44600,103 @@ public:
|
|||
bool positionMaintained;
|
||||
};
|
||||
|
||||
/**
|
||||
*/
|
||||
/** Returns the full text of the document. */
|
||||
const String getAllContent() const throw();
|
||||
|
||||
/**
|
||||
*/
|
||||
/** Returns a section of the document's text. */
|
||||
const String getTextBetween (const Position& start, const Position& end) const throw();
|
||||
|
||||
/**
|
||||
*/
|
||||
/** Returns a line from the document. */
|
||||
const String getLine (const int lineIndex) const throw();
|
||||
|
||||
/**
|
||||
*/
|
||||
/** Returns the number of characters in the document. */
|
||||
int getNumCharacters() const throw();
|
||||
|
||||
/**
|
||||
*/
|
||||
/** Returns the number of lines in the document. */
|
||||
int getNumLines() const throw() { return lines.size(); }
|
||||
|
||||
/**
|
||||
*/
|
||||
/** Returns the number of characters in the longest line of the document. */
|
||||
int getMaximumLineLength() throw();
|
||||
|
||||
/**
|
||||
/** Deletes a section of the text.
|
||||
|
||||
This operation is undoable.
|
||||
*/
|
||||
void deleteSection (const Position& startPosition, const Position& endPosition);
|
||||
|
||||
/**
|
||||
/** Inserts some text into the document at a given position.
|
||||
|
||||
This operation is undoable.
|
||||
*/
|
||||
void insertText (const Position& position, const String& text);
|
||||
|
||||
/**
|
||||
/** Clears the document and replaces it with some new text.
|
||||
|
||||
This operation is undoable - if you're trying to completely reset the document, you
|
||||
might want to also call clearUndoHistory() and setSavePoint() after using this method.
|
||||
*/
|
||||
void replaceAllContent (const String& newContent);
|
||||
|
||||
/**
|
||||
/** Returns the preferred new-line characters for the document.
|
||||
This will be either "\n", "\r\n", or (rarely) "\r".
|
||||
@see setNewLineCharacters
|
||||
*/
|
||||
const String getNewLineCharacters() const throw() { return newLineChars; }
|
||||
|
||||
/** Sets the new-line characters that the document should use.
|
||||
The string must be either "\n", "\r\n", or (rarely) "\r".
|
||||
@see getNewLineCharacters
|
||||
*/
|
||||
void setNewLineCharacters (const String& newLine) throw();
|
||||
|
||||
/** Begins a new undo transaction.
|
||||
|
||||
The document itself will not call this internally, so relies on whatever is using the
|
||||
document to periodically call this to break up the undo sequence into sensible chunks.
|
||||
@see UndoManager::beginNewTransaction
|
||||
*/
|
||||
void newTransaction();
|
||||
|
||||
/**
|
||||
/** Undo the last operation.
|
||||
@see UndoManager::undo
|
||||
*/
|
||||
void undo();
|
||||
|
||||
/**
|
||||
/** Redo the last operation.
|
||||
@see UndoManager::redo
|
||||
*/
|
||||
void redo();
|
||||
|
||||
/**
|
||||
/** Clears the undo history.
|
||||
@see UndoManager::clearUndoHistory
|
||||
*/
|
||||
void clearUndoManager();
|
||||
void clearUndoHistory();
|
||||
|
||||
/**
|
||||
/** Returns the document's UndoManager */
|
||||
UndoManager& getUndoManager() throw() { return undoManager; }
|
||||
|
||||
/** Makes a note that the document's current state matches the one that is saved.
|
||||
|
||||
After this has been called, hasChangedSinceSavePoint() will return false until
|
||||
the document has been altered, and then it'll start returning true. If the document is
|
||||
altered, but then undone until it gets back to this state, hasChangedSinceSavePoint()
|
||||
will again return false.
|
||||
|
||||
@see hasChangedSinceSavePoint
|
||||
*/
|
||||
void setSavePoint() throw();
|
||||
|
||||
/**
|
||||
/** Returns true if the state of the document differs from the state it was in when
|
||||
setSavePoint() was last called.
|
||||
|
||||
@see setSavePoint
|
||||
*/
|
||||
bool hasChangedSinceSavePoint() const throw();
|
||||
|
||||
/**
|
||||
*/
|
||||
/** Searches for a word-break. */
|
||||
const Position findWordBreakAfter (const Position& position) const throw();
|
||||
|
||||
/**
|
||||
*/
|
||||
/** Searches for a word-break. */
|
||||
const Position findWordBreakBefore (const Position& position) const throw();
|
||||
|
||||
/** An object that receives callbacks from the CodeDocument when its text changes.
|
||||
|
|
@ -44621,19 +44708,22 @@ public:
|
|||
Listener() {}
|
||||
virtual ~Listener() {}
|
||||
|
||||
/**
|
||||
/** Called by a CodeDocument when it is altered.
|
||||
*/
|
||||
virtual void codeDocumentChanged (const CodeDocument::Position& affectedTextStart,
|
||||
const CodeDocument::Position& affectedTextEnd) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
/** Registers a listener object to receive callbacks when the document changes.
|
||||
If the listener is already registered, this method has no effect.
|
||||
@see removeListener
|
||||
*/
|
||||
void addListener (Listener* const listener);
|
||||
void addListener (Listener* const listener) throw();
|
||||
|
||||
/**
|
||||
/** Deregisters a listener.
|
||||
@see addListener
|
||||
*/
|
||||
void removeListener (Listener* const listener);
|
||||
void removeListener (Listener* const listener) throw();
|
||||
|
||||
/** Iterates the text in a CodeDocument.
|
||||
|
||||
|
|
@ -44650,36 +44740,32 @@ public:
|
|||
const Iterator& operator= (const Iterator& other) throw();
|
||||
~Iterator() throw();
|
||||
|
||||
/**
|
||||
/** Reads the next character and returns it.
|
||||
@see peekNextChar
|
||||
*/
|
||||
juce_wchar nextChar() throw();
|
||||
|
||||
/**
|
||||
*/
|
||||
/** Reads the next character without advancing the current position. */
|
||||
juce_wchar peekNextChar() const throw();
|
||||
|
||||
/**
|
||||
*/
|
||||
/** Advances the position by one character. */
|
||||
void skip() throw();
|
||||
|
||||
/**
|
||||
/** Returns the position of the next character as its position within the
|
||||
whole document.
|
||||
*/
|
||||
int getPosition() const throw() { return position; }
|
||||
|
||||
/**
|
||||
*/
|
||||
/** Skips over any whitespace characters until the next character is non-whitespace. */
|
||||
void skipWhitespace();
|
||||
|
||||
/**
|
||||
*/
|
||||
/** Skips forward until the next character will be the first character on the next line */
|
||||
void skipToEndOfLine();
|
||||
|
||||
/**
|
||||
*/
|
||||
/** Returns the line number of the next character. */
|
||||
int getLine() const throw() { return line; }
|
||||
|
||||
/**
|
||||
*/
|
||||
/** Returns true if the iterator has reached the end of the document. */
|
||||
bool isEOF() const throw();
|
||||
|
||||
private:
|
||||
|
|
@ -44700,6 +44786,7 @@ private:
|
|||
int currentActionIndex, indexOfSavedState;
|
||||
int maximumLineLength;
|
||||
VoidArray listeners;
|
||||
String newLineChars;
|
||||
|
||||
void sendListenerChangeMessage (const int startLine, const int endLine);
|
||||
|
||||
|
|
@ -44765,18 +44852,95 @@ class CodeEditorLine;
|
|||
class JUCE_API CodeEditorComponent : public Component,
|
||||
public Timer,
|
||||
public ScrollBarListener,
|
||||
public CodeDocument::Listener
|
||||
public CodeDocument::Listener,
|
||||
public AsyncUpdater
|
||||
{
|
||||
public:
|
||||
|
||||
CodeEditorComponent (CodeDocument& document, CodeTokeniser* const codeTokeniser);
|
||||
/** Creates an editor for a document.
|
||||
|
||||
The tokeniser object is optional - pass 0 to disable syntax highlighting.
|
||||
The object that you pass in is not owned or deleted by the editor - you must
|
||||
make sure that it doesn't get deleted while this component is still using it.
|
||||
|
||||
@see CodeDocument
|
||||
*/
|
||||
CodeEditorComponent (CodeDocument& document,
|
||||
CodeTokeniser* const codeTokeniser);
|
||||
|
||||
/** Destructor. */
|
||||
~CodeEditorComponent();
|
||||
|
||||
/** Returns the code document that this component is editing. */
|
||||
CodeDocument& getDocument() const throw() { return document; }
|
||||
|
||||
/** Loads the given content into the document.
|
||||
This will completely reset the CodeDocument object, clear its undo history,
|
||||
and fill it with this text.
|
||||
*/
|
||||
void loadContent (const String& newContent);
|
||||
|
||||
void insertTextAtCaret (const String& newText);
|
||||
/** Returns the standard character width. */
|
||||
float getCharWidth() const throw() { return charWidth; }
|
||||
|
||||
/** Returns the height of a line of text, in pixels. */
|
||||
int getLineHeight() const throw() { return lineHeight; }
|
||||
|
||||
/** Returns the number of whole lines visible on the screen,
|
||||
This doesn't include a cut-off line that might be visible at the bottom if the
|
||||
component's height isn't an exact multiple of the line-height.
|
||||
*/
|
||||
int getNumLinesOnScreen() const throw() { return linesOnScreen; }
|
||||
|
||||
/** Returns the number of whole columns visible on the screen.
|
||||
This doesn't include any cut-off columns at the right-hand edge.
|
||||
*/
|
||||
int getNumColumnsOnScreen() const throw() { return columnsOnScreen; }
|
||||
|
||||
/** Returns the current caret position. */
|
||||
const CodeDocument::Position getCaretPos() const { return caretPos; }
|
||||
|
||||
/** Moves the caret.
|
||||
If selecting is true, the section of the document between the current
|
||||
caret position and the new one will become selected. If false, any currently
|
||||
selected region will be deselected.
|
||||
*/
|
||||
void moveCaretTo (const CodeDocument::Position& newPos, const bool selecting);
|
||||
|
||||
/** Returns the on-screen position of a character in the document.
|
||||
The rectangle returned is relative to this component's top-left origin.
|
||||
*/
|
||||
const Rectangle getCharacterBounds (const CodeDocument::Position& pos) const throw();
|
||||
|
||||
/** Finds the character at a given on-screen position.
|
||||
The co-ordinates are relative to this component's top-left origin.
|
||||
*/
|
||||
const CodeDocument::Position getPositionAt (int x, int y);
|
||||
|
||||
void cursorLeft (const bool moveInWholeWordSteps, const bool selecting);
|
||||
void cursorRight (const bool moveInWholeWordSteps, const bool selecting);
|
||||
void cursorDown (const bool selecting);
|
||||
void cursorUp (const bool selecting);
|
||||
|
||||
void pageDown (const bool selecting);
|
||||
void pageUp (const bool selecting);
|
||||
|
||||
void scrollDown();
|
||||
void scrollUp();
|
||||
void scrollToLine (int newFirstLineOnScreen);
|
||||
void scrollBy (int deltaLines);
|
||||
void scrollToColumn (int newFirstColumnOnScreen);
|
||||
void scrollToKeepCaretOnScreen();
|
||||
|
||||
void goToStartOfDocument (const bool selecting);
|
||||
void goToStartOfLine (const bool selecting);
|
||||
void goToEndOfDocument (const bool selecting);
|
||||
void goToEndOfLine (const bool selecting);
|
||||
|
||||
void deselectAll();
|
||||
void selectAll();
|
||||
|
||||
void insertTextAtCaret (const String& textToInsert);
|
||||
void insertTabAtCaret();
|
||||
void cut();
|
||||
void copy();
|
||||
|
|
@ -44785,49 +44949,50 @@ public:
|
|||
void backspace (const bool moveInWholeWordSteps);
|
||||
void deleteForward (const bool moveInWholeWordSteps);
|
||||
|
||||
void cursorLeft (const bool moveInWholeWordSteps, const bool selecting);
|
||||
void cursorRight (const bool moveInWholeWordSteps, const bool selecting);
|
||||
void cursorDown (const bool selecting);
|
||||
void cursorUp (const bool selecting);
|
||||
void pageDown (const bool selecting);
|
||||
void pageUp (const bool selecting);
|
||||
void scrollDown();
|
||||
void scrollUp();
|
||||
void goToStart (const bool selecting);
|
||||
void goToStartOfLine (const bool selecting);
|
||||
void goToEnd (const bool selecting);
|
||||
void goToEndOfLine (const bool selecting);
|
||||
void selectAll();
|
||||
|
||||
void undo();
|
||||
void redo();
|
||||
|
||||
float getCharWidth() const throw() { return charWidth; }
|
||||
int getLineHeight() const throw() { return lineHeight; }
|
||||
int getNumLinesOnScreen() const throw() { return linesOnScreen; }
|
||||
int getNumColumnsOnScreen() const throw() { return columnsOnScreen; }
|
||||
/** Changes the current tab settings.
|
||||
This lets you change the tab size and whether pressing the tab key inserts a
|
||||
tab character, or its equivalent number of spaces.
|
||||
*/
|
||||
void setTabSize (const int numSpacesPerTab,
|
||||
const bool insertSpacesInsteadOfTabCharacters) throw();
|
||||
|
||||
const CodeDocument::Position getCaretPos() const { return caretPos; }
|
||||
void moveCaretTo (const CodeDocument::Position& newPos, const bool highlighting);
|
||||
|
||||
void deselectAll();
|
||||
void scrollToLine (int firstLineOnScreen);
|
||||
void scrollToColumn (int firstColumnOnScreen);
|
||||
void scrollBy (int deltaLines);
|
||||
void scrollToKeepCaretOnScreen();
|
||||
|
||||
const Rectangle getCharacterBounds (const CodeDocument::Position& pos) const throw();
|
||||
const CodeDocument::Position getPositionAt (int x, int y);
|
||||
|
||||
void setTabSize (const int numSpaces, const bool insertSpaces);
|
||||
/** Returns the current number of spaces per tab.
|
||||
@see setTabSize
|
||||
*/
|
||||
int getTabSize() const throw() { return spacesPerTab; }
|
||||
|
||||
/** Returns true if the tab key will insert spaces instead of actual tab characters.
|
||||
@see setTabSize
|
||||
*/
|
||||
bool areSpacesInsertedForTabs() const { return useSpacesForTabs; }
|
||||
|
||||
/** Changes the font.
|
||||
Make sure you only use a fixed-width font, or this component will look pretty nasty!
|
||||
*/
|
||||
void setFont (const Font& newFont);
|
||||
|
||||
void setDefaultColours();
|
||||
void setColourForTokenCategory (const int tokenCategory, const Colour& colour);
|
||||
const Colour getColourForTokenCategory (const int tokenCategory) const;
|
||||
/** Resets the syntax highlighting colours to the default ones provided by the
|
||||
code tokeniser.
|
||||
@see CodeTokeniser::getDefaultColour
|
||||
*/
|
||||
void resetToDefaultColours();
|
||||
|
||||
/** Changes one of the syntax highlighting colours.
|
||||
The token type values are dependent on the tokeniser being used - use
|
||||
CodeTokeniser::getTokenTypes() to get a list of the token types.
|
||||
@see getColourForTokenType
|
||||
*/
|
||||
void setColourForTokenType (const int tokenType, const Colour& colour);
|
||||
|
||||
/** Returns one of the syntax highlighting colours.
|
||||
The token type values are dependent on the tokeniser being used - use
|
||||
CodeTokeniser::getTokenTypes() to get a list of the token types.
|
||||
@see setColourForTokenType
|
||||
*/
|
||||
const Colour getColourForTokenType (const int tokenType) const throw();
|
||||
|
||||
/** A set of colour IDs to use to change the colour of various aspects of the editor.
|
||||
|
||||
|
|
@ -44846,16 +45011,29 @@ public:
|
|||
enabled. */
|
||||
};
|
||||
|
||||
/** @internal */
|
||||
void resized();
|
||||
/** @internal */
|
||||
void paint (Graphics& g);
|
||||
/** @internal */
|
||||
bool keyPressed (const KeyPress& key);
|
||||
/** @internal */
|
||||
void mouseDown (const MouseEvent& e);
|
||||
/** @internal */
|
||||
void mouseDrag (const MouseEvent& e);
|
||||
/** @internal */
|
||||
void mouseUp (const MouseEvent& e);
|
||||
/** @internal */
|
||||
void mouseDoubleClick (const MouseEvent& e);
|
||||
/** @internal */
|
||||
void mouseWheelMove (const MouseEvent& e, float wheelIncrementX, float wheelIncrementY);
|
||||
/** @internal */
|
||||
void timerCallback();
|
||||
/** @internal */
|
||||
void scrollBarMoved (ScrollBar* scrollBarThatHasMoved, const double newRangeStart);
|
||||
/** @internal */
|
||||
void handleAsyncUpdate();
|
||||
/** @internal */
|
||||
void codeDocumentChanged (const CodeDocument::Position& affectedTextStart,
|
||||
const CodeDocument::Position& affectedTextEnd);
|
||||
|
||||
|
|
|
|||
|
|
@ -369,18 +369,14 @@ void CodeDocument::Position::setPosition (const int newPosition) throw()
|
|||
}
|
||||
}
|
||||
|
||||
void CodeDocument::Position::updateLineAndIndexFromPosition() throw()
|
||||
{
|
||||
setPosition (getPosition());
|
||||
}
|
||||
|
||||
void CodeDocument::Position::moveBy (int characterDelta) throw()
|
||||
{
|
||||
jassert (owner != 0);
|
||||
|
||||
updateLineAndIndexFromPosition();
|
||||
if (characterDelta == 1)
|
||||
{
|
||||
setPosition (getPosition());
|
||||
|
||||
// If moving right, make sure we don't get stuck between the \r and \n characters..
|
||||
CodeDocumentLine* const l = owner->lines.getUnchecked (line);
|
||||
if (indexInLine + characterDelta < l->lineLength
|
||||
|
|
@ -444,7 +440,8 @@ CodeDocument::CodeDocument()
|
|||
: undoManager (INT_MAX, 10000),
|
||||
currentActionIndex (0),
|
||||
indexOfSavedState (-1),
|
||||
maximumLineLength (-1)
|
||||
maximumLineLength (-1),
|
||||
newLineChars ("\r\n")
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -550,6 +547,12 @@ void CodeDocument::replaceAllContent (const String& newContent)
|
|||
insert (newContent, 0, true);
|
||||
}
|
||||
|
||||
void CodeDocument::setNewLineCharacters (const String& newLine) throw()
|
||||
{
|
||||
jassert (newLine == T("\r\n") || newLine == T("\n") || newLine == T("\r"));
|
||||
newLineChars = newLine;
|
||||
}
|
||||
|
||||
void CodeDocument::newTransaction()
|
||||
{
|
||||
undoManager.beginNewTransaction (String::empty);
|
||||
|
|
@ -566,7 +569,7 @@ void CodeDocument::redo()
|
|||
undoManager.redo();
|
||||
}
|
||||
|
||||
void CodeDocument::clearUndoManager()
|
||||
void CodeDocument::clearUndoHistory()
|
||||
{
|
||||
undoManager.clearUndoHistory();
|
||||
}
|
||||
|
|
@ -668,12 +671,12 @@ const CodeDocument::Position CodeDocument::findWordBreakBefore (const Position&
|
|||
|
||||
|
||||
//==============================================================================
|
||||
void CodeDocument::addListener (CodeDocument::Listener* const listener)
|
||||
void CodeDocument::addListener (CodeDocument::Listener* const listener) throw()
|
||||
{
|
||||
listeners.addIfNotAlreadyThere (listener);
|
||||
}
|
||||
|
||||
void CodeDocument::removeListener (CodeDocument::Listener* const listener)
|
||||
void CodeDocument::removeListener (CodeDocument::Listener* const listener) throw()
|
||||
{
|
||||
listeners.removeValue (listener);
|
||||
}
|
||||
|
|
@ -775,11 +778,12 @@ void CodeDocument::insert (const String& text, const int insertPos, const bool u
|
|||
lastAffectedLine = lines.size();
|
||||
}
|
||||
|
||||
for (int i = firstAffectedLine + 1; i < lines.size(); ++i)
|
||||
int lineStart = newFirstLine->lineStartInFile;
|
||||
for (int i = firstAffectedLine; i < lines.size(); ++i)
|
||||
{
|
||||
CodeDocumentLine* const l = lines.getUnchecked (i);
|
||||
const CodeDocumentLine* const previousLine = lines.getUnchecked (i - 1);
|
||||
l->lineStartInFile = previousLine->lineStartInFile + previousLine->lineLength;
|
||||
l->lineStartInFile = lineStart;
|
||||
lineStart += l->lineLength;
|
||||
}
|
||||
|
||||
const int newTextLength = text.length();
|
||||
|
|
@ -788,7 +792,7 @@ void CodeDocument::insert (const String& text, const int insertPos, const bool u
|
|||
CodeDocument::Position* const p = positionsToMaintain.getUnchecked(i);
|
||||
|
||||
if (p->getPosition() >= insertPos)
|
||||
p->moveBy (newTextLength);
|
||||
p->setPosition (p->getPosition() + newTextLength);
|
||||
}
|
||||
|
||||
sendListenerChangeMessage (firstAffectedLine, lastAffectedLine);
|
||||
|
|
@ -889,7 +893,7 @@ void CodeDocument::remove (const int startPos, const int endPos, const bool undo
|
|||
CodeDocument::Position* p = positionsToMaintain.getUnchecked(i);
|
||||
|
||||
if (p->getPosition() > startPosition.getPosition())
|
||||
p->setPosition (jmax (startPos, startPos - endPos));
|
||||
p->setPosition (jmax (startPos, p->getPosition() + startPos - endPos));
|
||||
|
||||
if (p->getPosition() > totalChars)
|
||||
p->setPosition (totalChars);
|
||||
|
|
|
|||
|
|
@ -45,12 +45,11 @@ class CodeDocumentLine;
|
|||
class JUCE_API CodeDocument
|
||||
{
|
||||
public:
|
||||
/**
|
||||
/** Creates a new, empty document.
|
||||
*/
|
||||
CodeDocument();
|
||||
|
||||
/**
|
||||
*/
|
||||
/** Destructor. */
|
||||
~CodeDocument();
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -64,62 +63,119 @@ public:
|
|||
class JUCE_API Position
|
||||
{
|
||||
public:
|
||||
/** Creates an uninitialised postion.
|
||||
Don't attempt to call any methods on this until you've given it an owner document
|
||||
to refer to!
|
||||
*/
|
||||
Position() throw();
|
||||
Position (const CodeDocument* const ownerDocument, const int line, const int indexInLine) throw();
|
||||
Position (const CodeDocument* const ownerDocument, const int characterPos) throw();
|
||||
|
||||
/** Creates a position based on a line and index in a document.
|
||||
|
||||
Note that this index is NOT the column number, it's the number of characters from the
|
||||
start of the line. The "column" number isn't quite the same, because if the line
|
||||
contains any tab characters, the relationship of the index to its visual column depends on
|
||||
the number of spaces per tab being used!
|
||||
|
||||
Lines are numbered from zero, and if the line or index are beyond the bounds of the document,
|
||||
they will be adjusted to keep them within its limits.
|
||||
*/
|
||||
Position (const CodeDocument* const ownerDocument,
|
||||
const int line, const int indexInLine) throw();
|
||||
|
||||
/** Creates a position based on a character index in a document.
|
||||
This position is placed at the specified number of characters from the start of the
|
||||
document. The line and column are auto-calculated.
|
||||
|
||||
If the position is beyond the range of the document, it'll be adjusted to keep it
|
||||
inside.
|
||||
*/
|
||||
Position (const CodeDocument* const ownerDocument,
|
||||
const int charactersFromStartOfDocument) throw();
|
||||
|
||||
/** Creates a copy of another position.
|
||||
|
||||
This will copy the position, but the new object will not be set to maintain its position,
|
||||
even if the source object was set to do so.
|
||||
*/
|
||||
Position (const Position& other) throw();
|
||||
|
||||
/** Destructor. */
|
||||
~Position() throw();
|
||||
|
||||
const Position& operator= (const Position& other) throw();
|
||||
bool operator== (const Position& other) const throw();
|
||||
bool operator!= (const Position& other) const throw();
|
||||
|
||||
/**
|
||||
*/
|
||||
void setLineAndIndex (const int newLine, const int newIndexInLine) throw();
|
||||
/** Points this object at a new position within the document.
|
||||
|
||||
/**
|
||||
If the position is beyond the range of the document, it'll be adjusted to keep it
|
||||
inside.
|
||||
@see getPosition, setLineAndIndex
|
||||
*/
|
||||
void setPosition (const int newPosition) throw();
|
||||
void setPosition (const int charactersFromStartOfDocument) throw();
|
||||
|
||||
/**
|
||||
/** Returns the position as the number of characters from the start of the document.
|
||||
@see setPosition, getLineNumber, getIndexInLine
|
||||
*/
|
||||
int getPosition() const throw() { return characterPos; }
|
||||
|
||||
/**
|
||||
/** Moves the position to a new line and index within the line.
|
||||
|
||||
Note that the index is NOT the column at which the position appears in an editor.
|
||||
If the line contains any tab characters, the relationship of the index to its
|
||||
visual position depends on the number of spaces per tab being used!
|
||||
|
||||
Lines are numbered from zero, and if the line or index are beyond the bounds of the document,
|
||||
they will be adjusted to keep them within its limits.
|
||||
*/
|
||||
void setLineAndIndex (const int newLine, const int newIndexInLine) throw();
|
||||
|
||||
/** Returns the line number of this position.
|
||||
The first line in the document is numbered zero, not one!
|
||||
*/
|
||||
int getLineNumber() const throw() { return line; }
|
||||
|
||||
/**
|
||||
/** Returns the number of characters from the start of the line.
|
||||
|
||||
Note that this value is NOT the column at which the position appears in an editor.
|
||||
If the line contains any tab characters, the relationship of the index to its
|
||||
visual position depends on the number of spaces per tab being used!
|
||||
*/
|
||||
int getIndexInLine() const throw() { return indexInLine; }
|
||||
|
||||
/**
|
||||
*/
|
||||
void updateLineAndIndexFromPosition() throw();
|
||||
/** Allows the position to be automatically updated when the document changes.
|
||||
|
||||
/**
|
||||
If this is set to true, the positon will register with its document so that
|
||||
when the document has text inserted or deleted, this position will be automatically
|
||||
moved to keep it at the same position in the text.
|
||||
*/
|
||||
void setPositionMaintained (const bool isMaintained) throw();
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
/** Moves the position forwards or backwards by the specified number of characters.
|
||||
@see movedBy
|
||||
*/
|
||||
void moveBy (int characterDelta) throw();
|
||||
|
||||
/**
|
||||
/** Returns a position which is the same as this one, moved by the specified number of
|
||||
characters.
|
||||
@see moveBy
|
||||
*/
|
||||
const Position movedBy (const int characterDelta) const throw();
|
||||
|
||||
/**
|
||||
/** Returns a position which is the same as this one, moved up or down by the specified
|
||||
number of lines.
|
||||
@see movedBy
|
||||
*/
|
||||
const Position movedByLines (const int deltaLines) const throw();
|
||||
|
||||
/**
|
||||
/** Returns the character in the document at this position.
|
||||
@see getLineText
|
||||
*/
|
||||
const tchar getCharacter() const throw();
|
||||
|
||||
/**
|
||||
/** Returns the line from the document that this position is within.
|
||||
@see getCharacter, getLineNumber
|
||||
*/
|
||||
const String getLineText() const throw();
|
||||
|
||||
|
|
@ -131,75 +187,107 @@ public:
|
|||
};
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
*/
|
||||
/** Returns the full text of the document. */
|
||||
const String getAllContent() const throw();
|
||||
|
||||
/**
|
||||
*/
|
||||
/** Returns a section of the document's text. */
|
||||
const String getTextBetween (const Position& start, const Position& end) const throw();
|
||||
|
||||
/**
|
||||
*/
|
||||
/** Returns a line from the document. */
|
||||
const String getLine (const int lineIndex) const throw();
|
||||
|
||||
/**
|
||||
*/
|
||||
/** Returns the number of characters in the document. */
|
||||
int getNumCharacters() const throw();
|
||||
|
||||
/**
|
||||
*/
|
||||
/** Returns the number of lines in the document. */
|
||||
int getNumLines() const throw() { return lines.size(); }
|
||||
|
||||
/**
|
||||
*/
|
||||
/** Returns the number of characters in the longest line of the document. */
|
||||
int getMaximumLineLength() throw();
|
||||
|
||||
/**
|
||||
/** Deletes a section of the text.
|
||||
|
||||
This operation is undoable.
|
||||
*/
|
||||
void deleteSection (const Position& startPosition, const Position& endPosition);
|
||||
|
||||
/**
|
||||
/** Inserts some text into the document at a given position.
|
||||
|
||||
This operation is undoable.
|
||||
*/
|
||||
void insertText (const Position& position, const String& text);
|
||||
|
||||
/**
|
||||
/** Clears the document and replaces it with some new text.
|
||||
|
||||
This operation is undoable - if you're trying to completely reset the document, you
|
||||
might want to also call clearUndoHistory() and setSavePoint() after using this method.
|
||||
*/
|
||||
void replaceAllContent (const String& newContent);
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
/** Returns the preferred new-line characters for the document.
|
||||
This will be either "\n", "\r\n", or (rarely) "\r".
|
||||
@see setNewLineCharacters
|
||||
*/
|
||||
const String getNewLineCharacters() const throw() { return newLineChars; }
|
||||
|
||||
/** Sets the new-line characters that the document should use.
|
||||
The string must be either "\n", "\r\n", or (rarely) "\r".
|
||||
@see getNewLineCharacters
|
||||
*/
|
||||
void setNewLineCharacters (const String& newLine) throw();
|
||||
|
||||
//==============================================================================
|
||||
/** Begins a new undo transaction.
|
||||
|
||||
The document itself will not call this internally, so relies on whatever is using the
|
||||
document to periodically call this to break up the undo sequence into sensible chunks.
|
||||
@see UndoManager::beginNewTransaction
|
||||
*/
|
||||
void newTransaction();
|
||||
|
||||
/**
|
||||
/** Undo the last operation.
|
||||
@see UndoManager::undo
|
||||
*/
|
||||
void undo();
|
||||
|
||||
/**
|
||||
/** Redo the last operation.
|
||||
@see UndoManager::redo
|
||||
*/
|
||||
void redo();
|
||||
|
||||
/**
|
||||
/** Clears the undo history.
|
||||
@see UndoManager::clearUndoHistory
|
||||
*/
|
||||
void clearUndoManager();
|
||||
void clearUndoHistory();
|
||||
|
||||
/** Returns the document's UndoManager */
|
||||
UndoManager& getUndoManager() throw() { return undoManager; }
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
/** Makes a note that the document's current state matches the one that is saved.
|
||||
|
||||
After this has been called, hasChangedSinceSavePoint() will return false until
|
||||
the document has been altered, and then it'll start returning true. If the document is
|
||||
altered, but then undone until it gets back to this state, hasChangedSinceSavePoint()
|
||||
will again return false.
|
||||
|
||||
@see hasChangedSinceSavePoint
|
||||
*/
|
||||
void setSavePoint() throw();
|
||||
|
||||
/**
|
||||
/** Returns true if the state of the document differs from the state it was in when
|
||||
setSavePoint() was last called.
|
||||
|
||||
@see setSavePoint
|
||||
*/
|
||||
bool hasChangedSinceSavePoint() const throw();
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
*/
|
||||
/** Searches for a word-break. */
|
||||
const Position findWordBreakAfter (const Position& position) const throw();
|
||||
|
||||
/**
|
||||
*/
|
||||
/** Searches for a word-break. */
|
||||
const Position findWordBreakBefore (const Position& position) const throw();
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -212,19 +300,22 @@ public:
|
|||
Listener() {}
|
||||
virtual ~Listener() {}
|
||||
|
||||
/**
|
||||
/** Called by a CodeDocument when it is altered.
|
||||
*/
|
||||
virtual void codeDocumentChanged (const CodeDocument::Position& affectedTextStart,
|
||||
const CodeDocument::Position& affectedTextEnd) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
/** Registers a listener object to receive callbacks when the document changes.
|
||||
If the listener is already registered, this method has no effect.
|
||||
@see removeListener
|
||||
*/
|
||||
void addListener (Listener* const listener);
|
||||
void addListener (Listener* const listener) throw();
|
||||
|
||||
/**
|
||||
/** Deregisters a listener.
|
||||
@see addListener
|
||||
*/
|
||||
void removeListener (Listener* const listener);
|
||||
void removeListener (Listener* const listener) throw();
|
||||
|
||||
//==============================================================================
|
||||
/** Iterates the text in a CodeDocument.
|
||||
|
|
@ -242,36 +333,32 @@ public:
|
|||
const Iterator& operator= (const Iterator& other) throw();
|
||||
~Iterator() throw();
|
||||
|
||||
/**
|
||||
/** Reads the next character and returns it.
|
||||
@see peekNextChar
|
||||
*/
|
||||
juce_wchar nextChar() throw();
|
||||
|
||||
/**
|
||||
*/
|
||||
/** Reads the next character without advancing the current position. */
|
||||
juce_wchar peekNextChar() const throw();
|
||||
|
||||
/**
|
||||
*/
|
||||
/** Advances the position by one character. */
|
||||
void skip() throw();
|
||||
|
||||
/**
|
||||
/** Returns the position of the next character as its position within the
|
||||
whole document.
|
||||
*/
|
||||
int getPosition() const throw() { return position; }
|
||||
|
||||
/**
|
||||
*/
|
||||
/** Skips over any whitespace characters until the next character is non-whitespace. */
|
||||
void skipWhitespace();
|
||||
|
||||
/**
|
||||
*/
|
||||
/** Skips forward until the next character will be the first character on the next line */
|
||||
void skipToEndOfLine();
|
||||
|
||||
/**
|
||||
*/
|
||||
/** Returns the line number of the next character. */
|
||||
int getLine() const throw() { return line; }
|
||||
|
||||
/**
|
||||
*/
|
||||
/** Returns true if the iterator has reached the end of the document. */
|
||||
bool isEOF() const throw();
|
||||
|
||||
private:
|
||||
|
|
@ -293,6 +380,7 @@ private:
|
|||
int currentActionIndex, indexOfSavedState;
|
||||
int maximumLineLength;
|
||||
VoidArray listeners;
|
||||
String newLineChars;
|
||||
|
||||
void sendListenerChangeMessage (const int startLine, const int endLine);
|
||||
|
||||
|
|
|
|||
|
|
@ -288,6 +288,7 @@ CodeEditorComponent::CodeEditorComponent (CodeDocument& document_,
|
|||
gutter (5),
|
||||
spacesPerTab (4),
|
||||
lineHeight (0),
|
||||
firstLineOnScreen (0),
|
||||
linesOnScreen (0),
|
||||
columnsOnScreen (0),
|
||||
scrollbarThickness (16),
|
||||
|
|
@ -319,7 +320,7 @@ CodeEditorComponent::CodeEditorComponent (CodeDocument& document_,
|
|||
f.setTypefaceName (Font::getDefaultMonospacedFontName());
|
||||
setFont (f);
|
||||
|
||||
setDefaultColours();
|
||||
resetToDefaultColours();
|
||||
|
||||
verticalScrollBar->addListener (this);
|
||||
horizontalScrollBar->addListener (this);
|
||||
|
|
@ -336,7 +337,7 @@ void CodeEditorComponent::loadContent (const String& newContent)
|
|||
{
|
||||
clearCachedIterators (0);
|
||||
document.replaceAllContent (newContent);
|
||||
document.clearUndoManager();
|
||||
document.clearUndoHistory();
|
||||
document.setSavePoint();
|
||||
caretPos.setPosition (0);
|
||||
selectionStart.setPosition (0);
|
||||
|
|
@ -350,7 +351,8 @@ void CodeEditorComponent::codeDocumentChanged (const CodeDocument::Position& aff
|
|||
{
|
||||
clearCachedIterators (affectedTextStart.getLineNumber());
|
||||
|
||||
rebuildLineTokens();
|
||||
triggerAsyncUpdate();
|
||||
|
||||
((CaretComponent*) caret)->updatePosition (*this);
|
||||
|
||||
if (affectedTextEnd.getPosition() >= selectionStart.getPosition()
|
||||
|
|
@ -373,12 +375,14 @@ void CodeEditorComponent::resized()
|
|||
((CaretComponent*) caret)->updatePosition (*this);
|
||||
|
||||
verticalScrollBar->setBounds (getWidth() - scrollbarThickness, 0, scrollbarThickness, getHeight() - scrollbarThickness);
|
||||
horizontalScrollBar->setBounds (0, getHeight() - scrollbarThickness, getWidth() - scrollbarThickness, scrollbarThickness);
|
||||
horizontalScrollBar->setBounds (gutter, getHeight() - scrollbarThickness, getWidth() - scrollbarThickness - gutter, scrollbarThickness);
|
||||
updateScrollBars();
|
||||
}
|
||||
|
||||
void CodeEditorComponent::paint (Graphics& g)
|
||||
{
|
||||
handleUpdateNowIfNeeded();
|
||||
|
||||
g.fillAll (findColour (CodeEditorComponent::backgroundColourId));
|
||||
|
||||
g.reduceClipRegion (gutter, 0, verticalScrollBar->getX() - gutter, horizontalScrollBar->getY());
|
||||
|
|
@ -396,8 +400,14 @@ void CodeEditorComponent::paint (Graphics& g)
|
|||
highlightColour, charWidth);
|
||||
}
|
||||
|
||||
void CodeEditorComponent::handleAsyncUpdate()
|
||||
{
|
||||
rebuildLineTokens();
|
||||
}
|
||||
|
||||
void CodeEditorComponent::rebuildLineTokens()
|
||||
{
|
||||
cancelPendingUpdate();
|
||||
const int numNeeded = linesOnScreen + 1;
|
||||
|
||||
if (numNeeded != lines.size())
|
||||
|
|
@ -467,7 +477,7 @@ void CodeEditorComponent::moveCaretTo (const CodeDocument::Position& newPos, con
|
|||
}
|
||||
}
|
||||
|
||||
rebuildLineTokens();
|
||||
triggerAsyncUpdate();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -481,11 +491,11 @@ void CodeEditorComponent::moveCaretTo (const CodeDocument::Position& newPos, con
|
|||
|
||||
void CodeEditorComponent::deselectAll()
|
||||
{
|
||||
if (selectionStart != caretPos || selectionEnd != caretPos)
|
||||
{
|
||||
selectionStart = selectionEnd = caretPos;
|
||||
rebuildLineTokens();
|
||||
}
|
||||
if (selectionStart != selectionEnd)
|
||||
triggerAsyncUpdate();
|
||||
|
||||
selectionStart = caretPos;
|
||||
selectionEnd = caretPos;
|
||||
}
|
||||
|
||||
void CodeEditorComponent::updateScrollBars()
|
||||
|
|
@ -499,13 +509,17 @@ void CodeEditorComponent::updateScrollBars()
|
|||
|
||||
void CodeEditorComponent::scrollToLineInternal (int newFirstLineOnScreen)
|
||||
{
|
||||
firstLineOnScreen = jlimit (0, jmax (0, document.getNumLines() - 1),
|
||||
newFirstLineOnScreen);
|
||||
newFirstLineOnScreen = jlimit (0, jmax (0, document.getNumLines() - 1),
|
||||
newFirstLineOnScreen);
|
||||
|
||||
((CaretComponent*) caret)->updatePosition (*this);
|
||||
if (newFirstLineOnScreen != firstLineOnScreen)
|
||||
{
|
||||
firstLineOnScreen = newFirstLineOnScreen;
|
||||
((CaretComponent*) caret)->updatePosition (*this);
|
||||
|
||||
updateCachedIterators (firstLineOnScreen);
|
||||
rebuildLineTokens();
|
||||
updateCachedIterators (firstLineOnScreen);
|
||||
triggerAsyncUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
void CodeEditorComponent::scrollToColumnInternal (double column)
|
||||
|
|
@ -621,7 +635,7 @@ void CodeEditorComponent::copyThenCut()
|
|||
void CodeEditorComponent::paste()
|
||||
{
|
||||
newTransaction();
|
||||
const String clip (SystemClipboard::getTextFromClipboard()/*.replace (T("\r\n"), T("\n"))*/);
|
||||
const String clip (SystemClipboard::getTextFromClipboard());
|
||||
|
||||
if (clip.isNotEmpty())
|
||||
insertTextAtCaret (clip);
|
||||
|
|
@ -703,7 +717,7 @@ void CodeEditorComponent::scrollDown()
|
|||
moveCaretTo (caretPos.movedByLines (-1), false);
|
||||
}
|
||||
|
||||
void CodeEditorComponent::goToStart (const bool selecting)
|
||||
void CodeEditorComponent::goToStartOfDocument (const bool selecting)
|
||||
{
|
||||
newTransaction();
|
||||
moveCaretTo (CodeDocument::Position (&document, 0, 0), selecting);
|
||||
|
|
@ -732,7 +746,7 @@ void CodeEditorComponent::goToStartOfLine (const bool selecting)
|
|||
moveCaretTo (CodeDocument::Position (&document, caretPos.getLineNumber(), index), selecting);
|
||||
}
|
||||
|
||||
void CodeEditorComponent::goToEnd (const bool selecting)
|
||||
void CodeEditorComponent::goToEndOfDocument (const bool selecting)
|
||||
{
|
||||
newTransaction();
|
||||
moveCaretTo (CodeDocument::Position (&document, INT_MAX, INT_MAX), selecting);
|
||||
|
|
@ -829,7 +843,7 @@ bool CodeEditorComponent::keyPressed (const KeyPress& key)
|
|||
scrollDown();
|
||||
#if JUCE_MAC
|
||||
else if (key.getModifiers().isCommandDown())
|
||||
goToStart (shiftDown);
|
||||
goToStartOfDocument (shiftDown);
|
||||
#endif
|
||||
else
|
||||
cursorUp (shiftDown);
|
||||
|
|
@ -840,7 +854,7 @@ bool CodeEditorComponent::keyPressed (const KeyPress& key)
|
|||
scrollUp();
|
||||
#if JUCE_MAC
|
||||
else if (key.getModifiers().isCommandDown())
|
||||
goToEnd (shiftDown);
|
||||
goToEndOfDocument (shiftDown);
|
||||
#endif
|
||||
else
|
||||
cursorDown (shiftDown);
|
||||
|
|
@ -856,14 +870,14 @@ bool CodeEditorComponent::keyPressed (const KeyPress& key)
|
|||
else if (key.isKeyCode (KeyPress::homeKey))
|
||||
{
|
||||
if (moveInWholeWordSteps)
|
||||
goToStart (shiftDown);
|
||||
goToStartOfDocument (shiftDown);
|
||||
else
|
||||
goToStartOfLine (shiftDown);
|
||||
}
|
||||
else if (key.isKeyCode (KeyPress::endKey))
|
||||
{
|
||||
if (moveInWholeWordSteps)
|
||||
goToEnd (shiftDown);
|
||||
goToEndOfDocument (shiftDown);
|
||||
else
|
||||
goToEndOfLine (shiftDown);
|
||||
}
|
||||
|
|
@ -907,7 +921,7 @@ bool CodeEditorComponent::keyPressed (const KeyPress& key)
|
|||
else if (key == KeyPress::returnKey)
|
||||
{
|
||||
newTransaction();
|
||||
insertTextAtCaret (T("\r\n"));
|
||||
insertTextAtCaret (document.getNewLineCharacters());
|
||||
}
|
||||
else if (key.isKeyCode (KeyPress::escapeKey))
|
||||
{
|
||||
|
|
@ -1002,14 +1016,14 @@ void CodeEditorComponent::scrollBarMoved (ScrollBar* scrollBarThatHasMoved, cons
|
|||
}
|
||||
|
||||
//==============================================================================
|
||||
void CodeEditorComponent::setTabSize (const int numSpaces, const bool insertSpaces)
|
||||
void CodeEditorComponent::setTabSize (const int numSpaces, const bool insertSpaces) throw()
|
||||
{
|
||||
useSpacesForTabs = insertSpaces;
|
||||
|
||||
if (spacesPerTab != numSpaces)
|
||||
{
|
||||
spacesPerTab = numSpaces;
|
||||
rebuildLineTokens();
|
||||
triggerAsyncUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1059,34 +1073,34 @@ void CodeEditorComponent::setFont (const Font& newFont)
|
|||
resized();
|
||||
}
|
||||
|
||||
void CodeEditorComponent::setDefaultColours()
|
||||
void CodeEditorComponent::resetToDefaultColours()
|
||||
{
|
||||
coloursForTokenCategories.clear();
|
||||
|
||||
if (codeTokeniser != 0)
|
||||
{
|
||||
for (int i = codeTokeniser->getTokenTypes().size(); --i >= 0;)
|
||||
setColourForTokenCategory (i, codeTokeniser->getDefaultColour (i));
|
||||
setColourForTokenType (i, codeTokeniser->getDefaultColour (i));
|
||||
}
|
||||
}
|
||||
|
||||
void CodeEditorComponent::setColourForTokenCategory (const int tokenCategory, const Colour& colour)
|
||||
void CodeEditorComponent::setColourForTokenType (const int tokenType, const Colour& colour)
|
||||
{
|
||||
jassert (tokenCategory < 256);
|
||||
jassert (tokenType < 256);
|
||||
|
||||
while (coloursForTokenCategories.size() < tokenCategory)
|
||||
while (coloursForTokenCategories.size() < tokenType)
|
||||
coloursForTokenCategories.add (Colours::black);
|
||||
|
||||
coloursForTokenCategories.set (tokenCategory, colour);
|
||||
coloursForTokenCategories.set (tokenType, colour);
|
||||
repaint();
|
||||
}
|
||||
|
||||
const Colour CodeEditorComponent::getColourForTokenCategory (const int tokenCategory) const
|
||||
const Colour CodeEditorComponent::getColourForTokenType (const int tokenType) const throw()
|
||||
{
|
||||
if (((unsigned int) tokenCategory) >= (unsigned int) coloursForTokenCategories.size())
|
||||
if (((unsigned int) tokenType) >= (unsigned int) coloursForTokenCategories.size())
|
||||
return findColour (CodeEditorComponent::defaultTextColourId);
|
||||
|
||||
return coloursForTokenCategories.getReference (tokenCategory);
|
||||
return coloursForTokenCategories.getReference (tokenType);
|
||||
}
|
||||
|
||||
void CodeEditorComponent::clearCachedIterators (const int firstLineToBeInvalid) throw()
|
||||
|
|
|
|||
|
|
@ -43,20 +43,98 @@ class CodeEditorLine;
|
|||
class JUCE_API CodeEditorComponent : public Component,
|
||||
public Timer,
|
||||
public ScrollBarListener,
|
||||
public CodeDocument::Listener
|
||||
public CodeDocument::Listener,
|
||||
public AsyncUpdater
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
CodeEditorComponent (CodeDocument& document, CodeTokeniser* const codeTokeniser);
|
||||
/** Creates an editor for a document.
|
||||
|
||||
The tokeniser object is optional - pass 0 to disable syntax highlighting.
|
||||
The object that you pass in is not owned or deleted by the editor - you must
|
||||
make sure that it doesn't get deleted while this component is still using it.
|
||||
|
||||
@see CodeDocument
|
||||
*/
|
||||
CodeEditorComponent (CodeDocument& document,
|
||||
CodeTokeniser* const codeTokeniser);
|
||||
|
||||
/** Destructor. */
|
||||
~CodeEditorComponent();
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the code document that this component is editing. */
|
||||
CodeDocument& getDocument() const throw() { return document; }
|
||||
|
||||
/** Loads the given content into the document.
|
||||
This will completely reset the CodeDocument object, clear its undo history,
|
||||
and fill it with this text.
|
||||
*/
|
||||
void loadContent (const String& newContent);
|
||||
|
||||
//==============================================================================
|
||||
void insertTextAtCaret (const String& newText);
|
||||
/** Returns the standard character width. */
|
||||
float getCharWidth() const throw() { return charWidth; }
|
||||
|
||||
/** Returns the height of a line of text, in pixels. */
|
||||
int getLineHeight() const throw() { return lineHeight; }
|
||||
|
||||
/** Returns the number of whole lines visible on the screen,
|
||||
This doesn't include a cut-off line that might be visible at the bottom if the
|
||||
component's height isn't an exact multiple of the line-height.
|
||||
*/
|
||||
int getNumLinesOnScreen() const throw() { return linesOnScreen; }
|
||||
|
||||
/** Returns the number of whole columns visible on the screen.
|
||||
This doesn't include any cut-off columns at the right-hand edge.
|
||||
*/
|
||||
int getNumColumnsOnScreen() const throw() { return columnsOnScreen; }
|
||||
|
||||
/** Returns the current caret position. */
|
||||
const CodeDocument::Position getCaretPos() const { return caretPos; }
|
||||
|
||||
/** Moves the caret.
|
||||
If selecting is true, the section of the document between the current
|
||||
caret position and the new one will become selected. If false, any currently
|
||||
selected region will be deselected.
|
||||
*/
|
||||
void moveCaretTo (const CodeDocument::Position& newPos, const bool selecting);
|
||||
|
||||
/** Returns the on-screen position of a character in the document.
|
||||
The rectangle returned is relative to this component's top-left origin.
|
||||
*/
|
||||
const Rectangle getCharacterBounds (const CodeDocument::Position& pos) const throw();
|
||||
|
||||
/** Finds the character at a given on-screen position.
|
||||
The co-ordinates are relative to this component's top-left origin.
|
||||
*/
|
||||
const CodeDocument::Position getPositionAt (int x, int y);
|
||||
|
||||
//==============================================================================
|
||||
void cursorLeft (const bool moveInWholeWordSteps, const bool selecting);
|
||||
void cursorRight (const bool moveInWholeWordSteps, const bool selecting);
|
||||
void cursorDown (const bool selecting);
|
||||
void cursorUp (const bool selecting);
|
||||
|
||||
void pageDown (const bool selecting);
|
||||
void pageUp (const bool selecting);
|
||||
|
||||
void scrollDown();
|
||||
void scrollUp();
|
||||
void scrollToLine (int newFirstLineOnScreen);
|
||||
void scrollBy (int deltaLines);
|
||||
void scrollToColumn (int newFirstColumnOnScreen);
|
||||
void scrollToKeepCaretOnScreen();
|
||||
|
||||
void goToStartOfDocument (const bool selecting);
|
||||
void goToStartOfLine (const bool selecting);
|
||||
void goToEndOfDocument (const bool selecting);
|
||||
void goToEndOfLine (const bool selecting);
|
||||
|
||||
void deselectAll();
|
||||
void selectAll();
|
||||
|
||||
void insertTextAtCaret (const String& textToInsert);
|
||||
void insertTabAtCaret();
|
||||
void cut();
|
||||
void copy();
|
||||
|
|
@ -65,51 +143,51 @@ public:
|
|||
void backspace (const bool moveInWholeWordSteps);
|
||||
void deleteForward (const bool moveInWholeWordSteps);
|
||||
|
||||
void cursorLeft (const bool moveInWholeWordSteps, const bool selecting);
|
||||
void cursorRight (const bool moveInWholeWordSteps, const bool selecting);
|
||||
void cursorDown (const bool selecting);
|
||||
void cursorUp (const bool selecting);
|
||||
void pageDown (const bool selecting);
|
||||
void pageUp (const bool selecting);
|
||||
void scrollDown();
|
||||
void scrollUp();
|
||||
void goToStart (const bool selecting);
|
||||
void goToStartOfLine (const bool selecting);
|
||||
void goToEnd (const bool selecting);
|
||||
void goToEndOfLine (const bool selecting);
|
||||
void selectAll();
|
||||
|
||||
void undo();
|
||||
void redo();
|
||||
|
||||
//==============================================================================
|
||||
float getCharWidth() const throw() { return charWidth; }
|
||||
int getLineHeight() const throw() { return lineHeight; }
|
||||
int getNumLinesOnScreen() const throw() { return linesOnScreen; }
|
||||
int getNumColumnsOnScreen() const throw() { return columnsOnScreen; }
|
||||
/** Changes the current tab settings.
|
||||
This lets you change the tab size and whether pressing the tab key inserts a
|
||||
tab character, or its equivalent number of spaces.
|
||||
*/
|
||||
void setTabSize (const int numSpacesPerTab,
|
||||
const bool insertSpacesInsteadOfTabCharacters) throw();
|
||||
|
||||
const CodeDocument::Position getCaretPos() const { return caretPos; }
|
||||
void moveCaretTo (const CodeDocument::Position& newPos, const bool highlighting);
|
||||
|
||||
void deselectAll();
|
||||
void scrollToLine (int firstLineOnScreen);
|
||||
void scrollToColumn (int firstColumnOnScreen);
|
||||
void scrollBy (int deltaLines);
|
||||
void scrollToKeepCaretOnScreen();
|
||||
|
||||
const Rectangle getCharacterBounds (const CodeDocument::Position& pos) const throw();
|
||||
const CodeDocument::Position getPositionAt (int x, int y);
|
||||
|
||||
//==============================================================================
|
||||
void setTabSize (const int numSpaces, const bool insertSpaces);
|
||||
/** Returns the current number of spaces per tab.
|
||||
@see setTabSize
|
||||
*/
|
||||
int getTabSize() const throw() { return spacesPerTab; }
|
||||
|
||||
/** Returns true if the tab key will insert spaces instead of actual tab characters.
|
||||
@see setTabSize
|
||||
*/
|
||||
bool areSpacesInsertedForTabs() const { return useSpacesForTabs; }
|
||||
|
||||
/** Changes the font.
|
||||
Make sure you only use a fixed-width font, or this component will look pretty nasty!
|
||||
*/
|
||||
void setFont (const Font& newFont);
|
||||
|
||||
void setDefaultColours();
|
||||
void setColourForTokenCategory (const int tokenCategory, const Colour& colour);
|
||||
const Colour getColourForTokenCategory (const int tokenCategory) const;
|
||||
/** Resets the syntax highlighting colours to the default ones provided by the
|
||||
code tokeniser.
|
||||
@see CodeTokeniser::getDefaultColour
|
||||
*/
|
||||
void resetToDefaultColours();
|
||||
|
||||
/** Changes one of the syntax highlighting colours.
|
||||
The token type values are dependent on the tokeniser being used - use
|
||||
CodeTokeniser::getTokenTypes() to get a list of the token types.
|
||||
@see getColourForTokenType
|
||||
*/
|
||||
void setColourForTokenType (const int tokenType, const Colour& colour);
|
||||
|
||||
/** Returns one of the syntax highlighting colours.
|
||||
The token type values are dependent on the tokeniser being used - use
|
||||
CodeTokeniser::getTokenTypes() to get a list of the token types.
|
||||
@see setColourForTokenType
|
||||
*/
|
||||
const Colour getColourForTokenType (const int tokenType) const throw();
|
||||
|
||||
//==============================================================================
|
||||
/** A set of colour IDs to use to change the colour of various aspects of the editor.
|
||||
|
|
@ -130,16 +208,29 @@ public:
|
|||
};
|
||||
|
||||
//==============================================================================
|
||||
/** @internal */
|
||||
void resized();
|
||||
/** @internal */
|
||||
void paint (Graphics& g);
|
||||
/** @internal */
|
||||
bool keyPressed (const KeyPress& key);
|
||||
/** @internal */
|
||||
void mouseDown (const MouseEvent& e);
|
||||
/** @internal */
|
||||
void mouseDrag (const MouseEvent& e);
|
||||
/** @internal */
|
||||
void mouseUp (const MouseEvent& e);
|
||||
/** @internal */
|
||||
void mouseDoubleClick (const MouseEvent& e);
|
||||
/** @internal */
|
||||
void mouseWheelMove (const MouseEvent& e, float wheelIncrementX, float wheelIncrementY);
|
||||
/** @internal */
|
||||
void timerCallback();
|
||||
/** @internal */
|
||||
void scrollBarMoved (ScrollBar* scrollBarThatHasMoved, const double newRangeStart);
|
||||
/** @internal */
|
||||
void handleAsyncUpdate();
|
||||
/** @internal */
|
||||
void codeDocumentChanged (const CodeDocument::Position& affectedTextStart,
|
||||
const CodeDocument::Position& affectedTextEnd);
|
||||
|
||||
|
|
|
|||
|
|
@ -859,14 +859,14 @@ public:
|
|||
explicit String (const double doubleValue,
|
||||
const int numberOfDecimalPlaces = 0) throw();
|
||||
|
||||
/** Parses this string to find its numerical value (up to 32 bits in size).
|
||||
/** Reads the value of the string as a decimal number (up to 32 bits in size).
|
||||
|
||||
@returns the value of the string as a 32 bit signed base-10 integer.
|
||||
@see getTrailingIntValue, getHexValue32, getHexValue64
|
||||
*/
|
||||
int getIntValue() const throw();
|
||||
|
||||
/** Parses this string to find its numerical value (up to 64 bits in size).
|
||||
/** Reads the value of the string as a decimal number (up to 64 bits in size).
|
||||
|
||||
@returns the value of the string as a 64 bit signed base-10 integer.
|
||||
*/
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue