1
0
Fork 0
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:
Julian Storer 2009-11-04 13:23:42 +00:00
parent f744dd9062
commit 0b2f0f086c
12 changed files with 823 additions and 311 deletions

View file

@ -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;
};

View file

@ -354,6 +354,10 @@
RelativePath="..\..\src\demos\CameraDemo.cpp"
>
</File>
<File
RelativePath="..\..\src\demos\CodeEditorDemo.cpp"
>
</File>
<File
RelativePath="..\..\src\demos\DragAndDropDemo.cpp"
>

View file

@ -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;

View 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();
}

View file

@ -50,6 +50,7 @@ Component* createTableDemo();
Component* createAudioDemo();
Component* createDragAndDropDemo();
Component* createInterprocessCommsDemo();
Component* createCodeEditorDemo();
#if JUCE_QUICKTIME && ! JUCE_LINUX
Component* createQuickTimeDemo();

View file

@ -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()

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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()

View file

@ -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);

View file

@ -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.
*/