mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-02-05 03:50:07 +00:00
Added a class TextEditor::InputFilter to perform custom filters on text input.
This commit is contained in:
parent
0033491cc8
commit
a180c6c358
2 changed files with 171 additions and 178 deletions
|
|
@ -67,7 +67,7 @@ public:
|
|||
}
|
||||
|
||||
UniformTextSection (const UniformTextSection& other)
|
||||
: font (other.font), colour (other.colour)
|
||||
: font (other.font), colour (other.colour)
|
||||
{
|
||||
atoms.ensureStorageAllocated (other.atoms.size());
|
||||
|
||||
|
|
@ -80,39 +80,28 @@ public:
|
|||
void clear()
|
||||
{
|
||||
for (int i = atoms.size(); --i >= 0;)
|
||||
delete getAtom(i);
|
||||
delete atoms.getUnchecked (i);
|
||||
|
||||
atoms.clear();
|
||||
}
|
||||
|
||||
int getNumAtoms() const
|
||||
{
|
||||
return atoms.size();
|
||||
}
|
||||
|
||||
TextAtom* getAtom (const int index) const noexcept
|
||||
{
|
||||
return atoms.getUnchecked (index);
|
||||
}
|
||||
|
||||
void append (const UniformTextSection& other, const juce_wchar passwordCharacter)
|
||||
void append (const UniformTextSection& other, const juce_wchar passwordChar)
|
||||
{
|
||||
if (other.atoms.size() > 0)
|
||||
{
|
||||
TextAtom* const lastAtom = atoms.getLast();
|
||||
int i = 0;
|
||||
|
||||
if (lastAtom != nullptr)
|
||||
if (TextAtom* const lastAtom = atoms.getLast())
|
||||
{
|
||||
if (! CharacterFunctions::isWhitespace (lastAtom->atomText.getLastCharacter()))
|
||||
{
|
||||
TextAtom* const first = other.getAtom(0);
|
||||
TextAtom* const first = other.atoms.getUnchecked(0);
|
||||
|
||||
if (! CharacterFunctions::isWhitespace (first->atomText[0]))
|
||||
{
|
||||
lastAtom->atomText += first->atomText;
|
||||
lastAtom->numChars = (uint16) (lastAtom->numChars + first->numChars);
|
||||
lastAtom->width = font.getStringWidthFloat (lastAtom->getText (passwordCharacter));
|
||||
lastAtom->width = font.getStringWidthFloat (lastAtom->getText (passwordChar));
|
||||
delete first;
|
||||
++i;
|
||||
}
|
||||
|
|
@ -123,30 +112,27 @@ public:
|
|||
|
||||
while (i < other.atoms.size())
|
||||
{
|
||||
atoms.add (other.getAtom(i));
|
||||
atoms.add (other.atoms.getUnchecked(i));
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UniformTextSection* split (const int indexToBreakAt,
|
||||
const juce_wchar passwordCharacter)
|
||||
UniformTextSection* split (const int indexToBreakAt, const juce_wchar passwordChar)
|
||||
{
|
||||
UniformTextSection* const section2 = new UniformTextSection (String::empty,
|
||||
font, colour,
|
||||
passwordCharacter);
|
||||
UniformTextSection* const section2 = new UniformTextSection (String::empty, font, colour, passwordChar);
|
||||
int index = 0;
|
||||
|
||||
for (int i = 0; i < atoms.size(); ++i)
|
||||
{
|
||||
TextAtom* const atom = getAtom(i);
|
||||
TextAtom* const atom = atoms.getUnchecked(i);
|
||||
|
||||
const int nextIndex = index + atom->numChars;
|
||||
|
||||
if (index == indexToBreakAt)
|
||||
{
|
||||
for (int j = i; j < atoms.size(); ++j)
|
||||
section2->atoms.add (getAtom (j));
|
||||
section2->atoms.add (atoms.getUnchecked (j));
|
||||
|
||||
for (int j = atoms.size(); --j >= i;)
|
||||
atoms.remove (j);
|
||||
|
|
@ -158,17 +144,17 @@ public:
|
|||
TextAtom* const secondAtom = new TextAtom();
|
||||
|
||||
secondAtom->atomText = atom->atomText.substring (indexToBreakAt - index);
|
||||
secondAtom->width = font.getStringWidthFloat (secondAtom->getText (passwordCharacter));
|
||||
secondAtom->width = font.getStringWidthFloat (secondAtom->getText (passwordChar));
|
||||
secondAtom->numChars = (uint16) secondAtom->atomText.length();
|
||||
|
||||
section2->atoms.add (secondAtom);
|
||||
|
||||
atom->atomText = atom->atomText.substring (0, indexToBreakAt - index);
|
||||
atom->width = font.getStringWidthFloat (atom->getText (passwordCharacter));
|
||||
atom->width = font.getStringWidthFloat (atom->getText (passwordChar));
|
||||
atom->numChars = (uint16) (indexToBreakAt - index);
|
||||
|
||||
for (int j = i + 1; j < atoms.size(); ++j)
|
||||
section2->atoms.add (getAtom (j));
|
||||
section2->atoms.add (atoms.getUnchecked (j));
|
||||
|
||||
for (int j = atoms.size(); --j > i;)
|
||||
atoms.remove (j);
|
||||
|
|
@ -185,7 +171,7 @@ public:
|
|||
void appendAllText (MemoryOutputStream& mo) const
|
||||
{
|
||||
for (int i = 0; i < atoms.size(); ++i)
|
||||
mo << getAtom(i)->atomText;
|
||||
mo << atoms.getUnchecked(i)->atomText;
|
||||
}
|
||||
|
||||
void appendSubstring (MemoryOutputStream& mo, const Range<int>& range) const
|
||||
|
|
@ -193,7 +179,7 @@ public:
|
|||
int index = 0;
|
||||
for (int i = 0; i < atoms.size(); ++i)
|
||||
{
|
||||
const TextAtom* const atom = getAtom (i);
|
||||
const TextAtom* const atom = atoms.getUnchecked (i);
|
||||
const int nextIndex = index + atom->numChars;
|
||||
|
||||
if (range.getStart() < nextIndex)
|
||||
|
|
@ -211,18 +197,17 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
int getTotalLength() const
|
||||
int getTotalLength() const noexcept
|
||||
{
|
||||
int total = 0;
|
||||
|
||||
for (int i = atoms.size(); --i >= 0;)
|
||||
total += getAtom(i)->numChars;
|
||||
total += atoms.getUnchecked(i)->numChars;
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
void setFont (const Font& newFont,
|
||||
const juce_wchar passwordCharacter)
|
||||
void setFont (const Font& newFont, const juce_wchar passwordChar)
|
||||
{
|
||||
if (font != newFont)
|
||||
{
|
||||
|
|
@ -231,7 +216,7 @@ public:
|
|||
for (int i = atoms.size(); --i >= 0;)
|
||||
{
|
||||
TextAtom* const atom = atoms.getUnchecked(i);
|
||||
atom->width = newFont.getStringWidthFloat (atom->getText (passwordCharacter));
|
||||
atom->width = newFont.getStringWidthFloat (atom->getText (passwordChar));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -239,13 +224,10 @@ public:
|
|||
//==============================================================================
|
||||
Font font;
|
||||
Colour colour;
|
||||
|
||||
private:
|
||||
Array <TextAtom*> atoms;
|
||||
|
||||
//==============================================================================
|
||||
void initialiseAtoms (const String& textToParse,
|
||||
const juce_wchar passwordCharacter)
|
||||
private:
|
||||
void initialiseAtoms (const String& textToParse, const juce_wchar passwordChar)
|
||||
{
|
||||
String::CharPointerType text (textToParse.getCharPointer());
|
||||
|
||||
|
|
@ -294,8 +276,7 @@ private:
|
|||
|
||||
TextAtom* const atom = new TextAtom();
|
||||
atom->atomText = String (start, numChars);
|
||||
|
||||
atom->width = font.getStringWidthFloat (atom->getText (passwordCharacter));
|
||||
atom->width = font.getStringWidthFloat (atom->getText (passwordChar));
|
||||
atom->numChars = (uint16) numChars;
|
||||
|
||||
atoms.add (atom);
|
||||
|
|
@ -399,9 +380,9 @@ public:
|
|||
moveToEndOfLastAtom();
|
||||
return false;
|
||||
}
|
||||
else if (atomIndex >= currentSection->getNumAtoms() - 1)
|
||||
else if (atomIndex >= currentSection->atoms.size() - 1)
|
||||
{
|
||||
if (atomIndex >= currentSection->getNumAtoms())
|
||||
if (atomIndex >= currentSection->atoms.size())
|
||||
{
|
||||
if (++sectionIndex >= sections.size())
|
||||
{
|
||||
|
|
@ -414,7 +395,7 @@ public:
|
|||
}
|
||||
else
|
||||
{
|
||||
const TextAtom* const lastAtom = currentSection->getAtom (atomIndex);
|
||||
const TextAtom* const lastAtom = currentSection->atoms.getUnchecked (atomIndex);
|
||||
|
||||
if (! lastAtom->isWhitespace())
|
||||
{
|
||||
|
|
@ -428,10 +409,10 @@ public:
|
|||
{
|
||||
const UniformTextSection* const s = sections.getUnchecked (section);
|
||||
|
||||
if (s->getNumAtoms() == 0)
|
||||
if (s->atoms.size() == 0)
|
||||
break;
|
||||
|
||||
const TextAtom* const nextAtom = s->getAtom (0);
|
||||
const TextAtom* const nextAtom = s->atoms.getUnchecked (0);
|
||||
|
||||
if (nextAtom->isWhitespace())
|
||||
break;
|
||||
|
|
@ -450,7 +431,7 @@ public:
|
|||
break;
|
||||
}
|
||||
|
||||
if (s->getNumAtoms() > 1)
|
||||
if (s->atoms.size() > 1)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -466,7 +447,7 @@ public:
|
|||
beginNewLine();
|
||||
}
|
||||
|
||||
atom = currentSection->getAtom (atomIndex);
|
||||
atom = currentSection->atoms.getUnchecked (atomIndex);
|
||||
atomRight = atomX + atom->width;
|
||||
++atomIndex;
|
||||
|
||||
|
|
@ -523,7 +504,7 @@ public:
|
|||
|
||||
bool checkSize = false;
|
||||
|
||||
if (tempAtomIndex >= section->getNumAtoms())
|
||||
if (tempAtomIndex >= section->atoms.size())
|
||||
{
|
||||
if (++tempSectionIndex >= sections.size())
|
||||
break;
|
||||
|
|
@ -533,7 +514,7 @@ public:
|
|||
checkSize = true;
|
||||
}
|
||||
|
||||
const TextAtom* const nextAtom = section->getAtom (tempAtomIndex);
|
||||
const TextAtom* const nextAtom = section->atoms.getUnchecked (tempAtomIndex);
|
||||
|
||||
if (nextAtom == nullptr)
|
||||
break;
|
||||
|
|
@ -570,16 +551,15 @@ public:
|
|||
GlyphArrangement ga;
|
||||
ga.addLineOfText (currentSection->font,
|
||||
atom->getTrimmedText (passwordCharacter),
|
||||
atomX,
|
||||
(float) roundToInt (lineY + lineHeight - maxDescent));
|
||||
atomX, (float) roundToInt (lineY + lineHeight - maxDescent));
|
||||
ga.draw (g);
|
||||
}
|
||||
}
|
||||
|
||||
void drawSelection (Graphics& g, const Range<int>& selection) const
|
||||
void drawSelection (Graphics& g, const Range<int>& selected) const
|
||||
{
|
||||
const int startX = roundToInt (indexToX (selection.getStart()));
|
||||
const int endX = roundToInt (indexToX (selection.getEnd()));
|
||||
const int startX = roundToInt (indexToX (selected.getStart()));
|
||||
const int endX = roundToInt (indexToX (selected.getEnd()));
|
||||
|
||||
const int y = roundToInt (lineY);
|
||||
const int nextY = roundToInt (lineY + lineHeight);
|
||||
|
|
@ -599,7 +579,7 @@ public:
|
|||
}
|
||||
|
||||
void drawSelectedText (Graphics& g,
|
||||
const Range<int>& selection,
|
||||
const Range<int>& selected,
|
||||
const Colour& selectedTextColour) const
|
||||
{
|
||||
if (passwordCharacter != 0 || ! atom->isWhitespace())
|
||||
|
|
@ -607,24 +587,23 @@ public:
|
|||
GlyphArrangement ga;
|
||||
ga.addLineOfText (currentSection->font,
|
||||
atom->getTrimmedText (passwordCharacter),
|
||||
atomX,
|
||||
(float) roundToInt (lineY + lineHeight - maxDescent));
|
||||
atomX, (float) roundToInt (lineY + lineHeight - maxDescent));
|
||||
|
||||
if (selection.getEnd() < indexInText + atom->numChars)
|
||||
if (selected.getEnd() < indexInText + atom->numChars)
|
||||
{
|
||||
GlyphArrangement ga2 (ga);
|
||||
ga2.removeRangeOfGlyphs (0, selection.getEnd() - indexInText);
|
||||
ga.removeRangeOfGlyphs (selection.getEnd() - indexInText, -1);
|
||||
ga2.removeRangeOfGlyphs (0, selected.getEnd() - indexInText);
|
||||
ga.removeRangeOfGlyphs (selected.getEnd() - indexInText, -1);
|
||||
|
||||
g.setColour (currentSection->colour);
|
||||
ga2.draw (g);
|
||||
}
|
||||
|
||||
if (selection.getStart() > indexInText)
|
||||
if (selected.getStart() > indexInText)
|
||||
{
|
||||
GlyphArrangement ga2 (ga);
|
||||
ga2.removeRangeOfGlyphs (selection.getStart() - indexInText, -1);
|
||||
ga.removeRangeOfGlyphs (0, selection.getStart() - indexInText);
|
||||
ga2.removeRangeOfGlyphs (selected.getStart() - indexInText, -1);
|
||||
ga.removeRangeOfGlyphs (0, selected.getStart() - indexInText);
|
||||
|
||||
g.setColour (currentSection->colour);
|
||||
ga2.draw (g);
|
||||
|
|
@ -726,7 +705,7 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
bool shouldWrap (const float x) const
|
||||
bool shouldWrap (const float x) const noexcept
|
||||
{
|
||||
return (x - 0.0001f) >= wordWrapWidth;
|
||||
}
|
||||
|
|
@ -824,12 +803,11 @@ public:
|
|||
|
||||
int getSizeInUnits()
|
||||
{
|
||||
int n = 0;
|
||||
|
||||
int n = 16;
|
||||
for (int i = removedSections.size(); --i >= 0;)
|
||||
n += removedSections.getUnchecked (i)->getTotalLength();
|
||||
|
||||
return n + 16;
|
||||
return n;
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
@ -957,7 +935,6 @@ TextEditor::TextEditor (const String& name,
|
|||
menuActive (false),
|
||||
valueTextNeedsUpdating (false),
|
||||
consumeEscAndReturnKeys (true),
|
||||
maxTextLength (0),
|
||||
leftIndent (4),
|
||||
topIndent (4),
|
||||
lastTransactionTime (0),
|
||||
|
|
@ -982,11 +959,8 @@ TextEditor::TextEditor (const String& name,
|
|||
TextEditor::~TextEditor()
|
||||
{
|
||||
if (wasFocused)
|
||||
{
|
||||
ComponentPeer* const peer = getPeer();
|
||||
if (peer != nullptr)
|
||||
if (ComponentPeer* const peer = getPeer())
|
||||
peer->dismissPendingTextInput();
|
||||
}
|
||||
|
||||
textValue.referTo (Value());
|
||||
clearInternal (0);
|
||||
|
|
@ -1105,7 +1079,6 @@ void TextEditor::setFont (const Font& newFont)
|
|||
void TextEditor::applyFontToAllText (const Font& newFont)
|
||||
{
|
||||
currentFont = newFont;
|
||||
|
||||
const Colour overallColour (findColour (textColourId));
|
||||
|
||||
for (int i = sections.size(); --i >= 0;)
|
||||
|
|
@ -1155,11 +1128,32 @@ void TextEditor::updateCaretPosition()
|
|||
caret->setCaretPosition (getCaretRectangle().translated (leftIndent, topIndent));
|
||||
}
|
||||
|
||||
TextEditor::LengthAndCharacterRestriction::LengthAndCharacterRestriction (int maxLen, const String& chars)
|
||||
: allowedCharacters (chars), maxLength (maxLen)
|
||||
{}
|
||||
|
||||
String TextEditor::LengthAndCharacterRestriction::filterNewText (TextEditor& ed, const String& newInput)
|
||||
{
|
||||
String t (newInput);
|
||||
|
||||
if (allowedCharacters.isNotEmpty())
|
||||
t = t.retainCharacters (allowedCharacters);
|
||||
|
||||
if (maxLength > 0)
|
||||
t = t.substring (0, maxLength - (ed.getTotalNumChars() - ed.getHighlightedRegion().getLength()));
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
void TextEditor::setInputFilter (InputFilter* newFilter, bool takeOwnership)
|
||||
{
|
||||
inputFilter.set (newFilter, takeOwnership);
|
||||
}
|
||||
|
||||
void TextEditor::setInputRestrictions (const int maxLen,
|
||||
const String& chars)
|
||||
{
|
||||
maxTextLength = jmax (0, maxLen);
|
||||
allowedCharacters = chars;
|
||||
setInputFilter (new LengthAndCharacterRestriction (maxLen, chars), true);
|
||||
}
|
||||
|
||||
void TextEditor::setTextToShowWhenEmpty (const String& text, const Colour& colourToUse)
|
||||
|
|
@ -1262,25 +1256,11 @@ void TextEditor::textChanged()
|
|||
}
|
||||
}
|
||||
|
||||
void TextEditor::returnPressed()
|
||||
{
|
||||
postCommandMessage (TextEditorDefs::returnKeyMessageId);
|
||||
}
|
||||
void TextEditor::returnPressed() { postCommandMessage (TextEditorDefs::returnKeyMessageId); }
|
||||
void TextEditor::escapePressed() { postCommandMessage (TextEditorDefs::escapeKeyMessageId); }
|
||||
|
||||
void TextEditor::escapePressed()
|
||||
{
|
||||
postCommandMessage (TextEditorDefs::escapeKeyMessageId);
|
||||
}
|
||||
|
||||
void TextEditor::addListener (TextEditorListener* const newListener)
|
||||
{
|
||||
listeners.add (newListener);
|
||||
}
|
||||
|
||||
void TextEditor::removeListener (TextEditorListener* const listenerToRemove)
|
||||
{
|
||||
listeners.remove (listenerToRemove);
|
||||
}
|
||||
void TextEditor::addListener (TextEditorListener* const l) { listeners.add (l); }
|
||||
void TextEditor::removeListener (TextEditorListener* const l) { listeners.remove (l); }
|
||||
|
||||
//==============================================================================
|
||||
void TextEditor::timerCallbackInt()
|
||||
|
|
@ -1430,21 +1410,13 @@ void TextEditor::updateTextHolderSize()
|
|||
}
|
||||
}
|
||||
|
||||
int TextEditor::getTextWidth() const
|
||||
{
|
||||
return textHolder->getWidth();
|
||||
}
|
||||
int TextEditor::getTextWidth() const { return textHolder->getWidth(); }
|
||||
int TextEditor::getTextHeight() const { return textHolder->getHeight(); }
|
||||
|
||||
int TextEditor::getTextHeight() const
|
||||
{
|
||||
return textHolder->getHeight();
|
||||
}
|
||||
|
||||
void TextEditor::setIndents (const int newLeftIndent,
|
||||
const int newTopIndent)
|
||||
void TextEditor::setIndents (const int newLeftIndent, const int newTopIndent)
|
||||
{
|
||||
leftIndent = newLeftIndent;
|
||||
topIndent = newTopIndent;
|
||||
topIndent = newTopIndent;
|
||||
}
|
||||
|
||||
void TextEditor::setBorder (const BorderSize<int>& border)
|
||||
|
|
@ -1561,32 +1533,21 @@ int TextEditor::getTextIndexAt (const int x, const int y)
|
|||
|
||||
void TextEditor::insertTextAtCaret (const String& t)
|
||||
{
|
||||
String newText (t);
|
||||
String newText (inputFilter != nullptr ? inputFilter->filterNewText (*this, t) : t);
|
||||
|
||||
if (allowedCharacters.isNotEmpty())
|
||||
newText = newText.retainCharacters (allowedCharacters);
|
||||
|
||||
if (! isMultiLine())
|
||||
newText = newText.replaceCharacters ("\r\n", " ");
|
||||
else
|
||||
if (isMultiLine())
|
||||
newText = newText.replace ("\r\n", "\n");
|
||||
else
|
||||
newText = newText.replaceCharacters ("\r\n", " ");
|
||||
|
||||
const int newCaretPos = selection.getStart() + newText.length();
|
||||
const int insertIndex = selection.getStart();
|
||||
const int newCaretPos = insertIndex + newText.length();
|
||||
|
||||
remove (selection, getUndoManager(),
|
||||
newText.isNotEmpty() ? newCaretPos - 1 : newCaretPos);
|
||||
|
||||
if (maxTextLength > 0)
|
||||
newText = newText.substring (0, maxTextLength - getTotalNumChars());
|
||||
|
||||
if (newText.isNotEmpty())
|
||||
insert (newText,
|
||||
insertIndex,
|
||||
currentFont,
|
||||
findColour (textColourId),
|
||||
getUndoManager(),
|
||||
newCaretPos);
|
||||
insert (newText, insertIndex, currentFont, findColour (textColourId),
|
||||
getUndoManager(), newCaretPos);
|
||||
|
||||
textChanged();
|
||||
}
|
||||
|
|
@ -1714,16 +1675,12 @@ void TextEditor::paintOverChildren (Graphics& g)
|
|||
g.setFont (getFont());
|
||||
|
||||
if (isMultiLine())
|
||||
{
|
||||
g.drawText (textToShowWhenEmpty, getLocalBounds(),
|
||||
Justification::centred, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
g.drawText (textToShowWhenEmpty,
|
||||
leftIndent, 0, viewport->getWidth() - leftIndent, getHeight(),
|
||||
Justification::centredLeft, true);
|
||||
}
|
||||
}
|
||||
|
||||
getLookAndFeel().drawTextEditorOutline (g, getWidth(), getHeight(), *this);
|
||||
|
|
@ -1888,7 +1845,7 @@ void TextEditor::mouseWheelMove (const MouseEvent& e, const MouseWheelDetails& w
|
|||
}
|
||||
|
||||
//==============================================================================
|
||||
bool TextEditor::moveCaretWithTransation (const int newPos, const bool selecting)
|
||||
bool TextEditor::moveCaretWithTransaction (const int newPos, const bool selecting)
|
||||
{
|
||||
newTransaction();
|
||||
moveCaretTo (newPos, selecting);
|
||||
|
|
@ -1904,7 +1861,7 @@ bool TextEditor::moveCaretLeft (bool moveInWholeWordSteps, bool selecting)
|
|||
else
|
||||
--pos;
|
||||
|
||||
return moveCaretWithTransation (pos, selecting);
|
||||
return moveCaretWithTransaction (pos, selecting);
|
||||
}
|
||||
|
||||
bool TextEditor::moveCaretRight (bool moveInWholeWordSteps, bool selecting)
|
||||
|
|
@ -1916,7 +1873,7 @@ bool TextEditor::moveCaretRight (bool moveInWholeWordSteps, bool selecting)
|
|||
else
|
||||
++pos;
|
||||
|
||||
return moveCaretWithTransation (pos, selecting);
|
||||
return moveCaretWithTransaction (pos, selecting);
|
||||
}
|
||||
|
||||
bool TextEditor::moveCaretUp (bool selecting)
|
||||
|
|
@ -1925,7 +1882,7 @@ bool TextEditor::moveCaretUp (bool selecting)
|
|||
return moveCaretToStartOfLine (selecting);
|
||||
|
||||
const Rectangle<float> caretPos (getCaretRectangle().toFloat());
|
||||
return moveCaretWithTransation (indexAtPosition (caretPos.getX(), caretPos.getY() - 1.0f), selecting);
|
||||
return moveCaretWithTransaction (indexAtPosition (caretPos.getX(), caretPos.getY() - 1.0f), selecting);
|
||||
}
|
||||
|
||||
bool TextEditor::moveCaretDown (bool selecting)
|
||||
|
|
@ -1934,7 +1891,7 @@ bool TextEditor::moveCaretDown (bool selecting)
|
|||
return moveCaretToEndOfLine (selecting);
|
||||
|
||||
const Rectangle<float> caretPos (getCaretRectangle().toFloat());
|
||||
return moveCaretWithTransation (indexAtPosition (caretPos.getX(), caretPos.getBottom() + 1.0f), selecting);
|
||||
return moveCaretWithTransaction (indexAtPosition (caretPos.getX(), caretPos.getBottom() + 1.0f), selecting);
|
||||
}
|
||||
|
||||
bool TextEditor::pageUp (bool selecting)
|
||||
|
|
@ -1943,7 +1900,7 @@ bool TextEditor::pageUp (bool selecting)
|
|||
return moveCaretToStartOfLine (selecting);
|
||||
|
||||
const Rectangle<float> caretPos (getCaretRectangle().toFloat());
|
||||
return moveCaretWithTransation (indexAtPosition (caretPos.getX(), caretPos.getY() - viewport->getViewHeight()), selecting);
|
||||
return moveCaretWithTransaction (indexAtPosition (caretPos.getX(), caretPos.getY() - viewport->getViewHeight()), selecting);
|
||||
}
|
||||
|
||||
bool TextEditor::pageDown (bool selecting)
|
||||
|
|
@ -1952,14 +1909,12 @@ bool TextEditor::pageDown (bool selecting)
|
|||
return moveCaretToEndOfLine (selecting);
|
||||
|
||||
const Rectangle<float> caretPos (getCaretRectangle().toFloat());
|
||||
return moveCaretWithTransation (indexAtPosition (caretPos.getX(), caretPos.getBottom() + viewport->getViewHeight()), selecting);
|
||||
return moveCaretWithTransaction (indexAtPosition (caretPos.getX(), caretPos.getBottom() + viewport->getViewHeight()), selecting);
|
||||
}
|
||||
|
||||
void TextEditor::scrollByLines (int deltaLines)
|
||||
{
|
||||
ScrollBar* scrollbar = viewport->getVerticalScrollBar();
|
||||
|
||||
if (scrollbar != nullptr)
|
||||
if (ScrollBar* scrollbar = viewport->getVerticalScrollBar())
|
||||
scrollbar->moveScrollbarInSteps (deltaLines);
|
||||
}
|
||||
|
||||
|
|
@ -1977,24 +1932,24 @@ bool TextEditor::scrollUp()
|
|||
|
||||
bool TextEditor::moveCaretToTop (bool selecting)
|
||||
{
|
||||
return moveCaretWithTransation (0, selecting);
|
||||
return moveCaretWithTransaction (0, selecting);
|
||||
}
|
||||
|
||||
bool TextEditor::moveCaretToStartOfLine (bool selecting)
|
||||
{
|
||||
const Rectangle<float> caretPos (getCaretRectangle().toFloat());
|
||||
return moveCaretWithTransation (indexAtPosition (0.0f, caretPos.getY()), selecting);
|
||||
return moveCaretWithTransaction (indexAtPosition (0.0f, caretPos.getY()), selecting);
|
||||
}
|
||||
|
||||
bool TextEditor::moveCaretToEnd (bool selecting)
|
||||
{
|
||||
return moveCaretWithTransation (getTotalNumChars(), selecting);
|
||||
return moveCaretWithTransaction (getTotalNumChars(), selecting);
|
||||
}
|
||||
|
||||
bool TextEditor::moveCaretToEndOfLine (bool selecting)
|
||||
{
|
||||
const Rectangle<float> caretPos (getCaretRectangle().toFloat());
|
||||
return moveCaretWithTransation (indexAtPosition ((float) textHolder->getWidth(), caretPos.getY()), selecting);
|
||||
return moveCaretWithTransaction (indexAtPosition ((float) textHolder->getWidth(), caretPos.getY()), selecting);
|
||||
}
|
||||
|
||||
bool TextEditor::deleteBackwards (bool moveInWholeWordSteps)
|
||||
|
|
@ -2128,9 +2083,9 @@ void TextEditor::focusGained (FocusChangeType)
|
|||
repaint();
|
||||
updateCaretPosition();
|
||||
|
||||
ComponentPeer* const peer = getPeer();
|
||||
if (peer != nullptr && ! isReadOnly())
|
||||
peer->textInputRequired (getScreenPosition() - peer->getScreenPosition());
|
||||
if (ComponentPeer* const peer = getPeer())
|
||||
if (! isReadOnly())
|
||||
peer->textInputRequired (getScreenPosition() - peer->getScreenPosition());
|
||||
}
|
||||
|
||||
void TextEditor::focusLost (FocusChangeType)
|
||||
|
|
@ -2142,8 +2097,7 @@ void TextEditor::focusLost (FocusChangeType)
|
|||
|
||||
underlinedSections.clear();
|
||||
|
||||
ComponentPeer* const peer = getPeer();
|
||||
if (peer != nullptr)
|
||||
if (ComponentPeer* const peer = getPeer())
|
||||
peer->dismissPendingTextInput();
|
||||
|
||||
updateCaretPosition();
|
||||
|
|
@ -2160,14 +2114,10 @@ void TextEditor::resized()
|
|||
|
||||
updateTextHolderSize();
|
||||
|
||||
if (! isMultiLine())
|
||||
{
|
||||
scrollToMakeSureCursorIsVisible();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isMultiLine())
|
||||
updateCaretPosition();
|
||||
}
|
||||
else
|
||||
scrollToMakeSureCursorIsVisible();
|
||||
}
|
||||
|
||||
void TextEditor::handleCommandMessage (const int commandId)
|
||||
|
|
@ -2600,8 +2550,3 @@ void TextEditor::coalesceSimilarSections()
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TextEditor::Listener::textEditorTextChanged (TextEditor&) {}
|
||||
void TextEditor::Listener::textEditorReturnKeyPressed (TextEditor&) {}
|
||||
void TextEditor::Listener::textEditorEscapeKeyPressed (TextEditor&) {}
|
||||
void TextEditor::Listener::textEditorFocusLost (TextEditor&) {}
|
||||
|
|
|
|||
|
|
@ -262,16 +262,6 @@ public:
|
|||
*/
|
||||
void setSelectAllWhenFocused (bool shouldSelectAll);
|
||||
|
||||
/** Sets limits on the characters that can be entered.
|
||||
|
||||
@param maxTextLength if this is > 0, it sets a maximum length limit; if 0, no
|
||||
limit is set
|
||||
@param allowedCharacters if this is non-empty, then only characters that occur in
|
||||
this string are allowed to be entered into the editor.
|
||||
*/
|
||||
void setInputRestrictions (int maxTextLength,
|
||||
const String& allowedCharacters = String::empty);
|
||||
|
||||
/** When the text editor is empty, it can be set to display a message.
|
||||
|
||||
This is handy for things like telling the user what to type in the box - the
|
||||
|
|
@ -292,23 +282,23 @@ public:
|
|||
|
||||
@see TextEditor::addListener
|
||||
*/
|
||||
class JUCE_API Listener
|
||||
class Listener
|
||||
{
|
||||
public:
|
||||
/** Destructor. */
|
||||
virtual ~Listener() {}
|
||||
|
||||
/** Called when the user changes the text in some way. */
|
||||
virtual void textEditorTextChanged (TextEditor& editor);
|
||||
virtual void textEditorTextChanged (TextEditor&) {}
|
||||
|
||||
/** Called when the user presses the return key. */
|
||||
virtual void textEditorReturnKeyPressed (TextEditor& editor);
|
||||
virtual void textEditorReturnKeyPressed (TextEditor&) {}
|
||||
|
||||
/** Called when the user presses the escape key. */
|
||||
virtual void textEditorEscapeKeyPressed (TextEditor& editor);
|
||||
virtual void textEditorEscapeKeyPressed (TextEditor&) {}
|
||||
|
||||
/** Called when the text editor loses focus. */
|
||||
virtual void textEditorFocusLost (TextEditor& editor);
|
||||
virtual void textEditorFocusLost (TextEditor&) {}
|
||||
};
|
||||
|
||||
/** Registers a listener to be told when things happen to the text.
|
||||
|
|
@ -538,6 +528,65 @@ public:
|
|||
*/
|
||||
virtual void performPopupMenuAction (int menuItemID);
|
||||
|
||||
//==============================================================================
|
||||
/** Base class for input filters that can be applied to a TextEditor to restrict
|
||||
the text that can be entered.
|
||||
*/
|
||||
class InputFilter
|
||||
{
|
||||
public:
|
||||
InputFilter() {}
|
||||
virtual ~InputFilter() {}
|
||||
|
||||
/** This method is called whenever text is entered into the editor.
|
||||
An implementation of this class should should check the input string,
|
||||
and return an edited version of it that should be used.
|
||||
*/
|
||||
virtual String filterNewText (TextEditor&, const String& newInput) = 0;
|
||||
};
|
||||
|
||||
/** An input filter for a TextEditor that limits the length of text and/or the
|
||||
characters that it may contain.
|
||||
*/
|
||||
class JUCE_API LengthAndCharacterRestriction : public InputFilter
|
||||
{
|
||||
public:
|
||||
/** Creates a filter that limits the length of text, and/or the characters that it can contain.
|
||||
@param maxTextLength if this is > 0, it sets a maximum length limit; if <= 0, no
|
||||
limit is set
|
||||
@param allowedCharacters if this is non-empty, then only characters that occur in
|
||||
this string are allowed to be entered into the editor.
|
||||
*/
|
||||
LengthAndCharacterRestriction (int maxNumChars, const String& allowedCharacters);
|
||||
|
||||
private:
|
||||
String allowedCharacters;
|
||||
int maxLength;
|
||||
|
||||
String filterNewText (TextEditor&, const String&);
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LengthAndCharacterRestriction);
|
||||
};
|
||||
|
||||
/** Sets an input filter that should be applied to this editor.
|
||||
The filter can be nullptr, to remove any existing filters.
|
||||
If takeOwnership is true, then the filter will be owned and deleted by the editor
|
||||
when no longer needed.
|
||||
*/
|
||||
void setInputFilter (InputFilter* newFilter, bool takeOwnership);
|
||||
|
||||
/** Sets limits on the characters that can be entered.
|
||||
This is just a shortcut that passes an instance of the LengthAndCharacterRestriction
|
||||
class to setInputFilter().
|
||||
|
||||
@param maxTextLength if this is > 0, it sets a maximum length limit; if 0, no
|
||||
limit is set
|
||||
@param allowedCharacters if this is non-empty, then only characters that occur in
|
||||
this string are allowed to be entered into the editor.
|
||||
*/
|
||||
void setInputRestrictions (int maxTextLength,
|
||||
const String& allowedCharacters = String::empty);
|
||||
|
||||
//==============================================================================
|
||||
/** @internal */
|
||||
void paint (Graphics&);
|
||||
|
|
@ -621,7 +670,6 @@ private:
|
|||
|
||||
UndoManager undoManager;
|
||||
ScopedPointer<CaretComponent> caret;
|
||||
int maxTextLength;
|
||||
Range<int> selection;
|
||||
int leftIndent, topIndent;
|
||||
unsigned int lastTransactionTime;
|
||||
|
|
@ -632,6 +680,7 @@ private:
|
|||
String textToShowWhenEmpty;
|
||||
Colour colourForTextWhenEmpty;
|
||||
juce_wchar passwordCharacter;
|
||||
OptionalScopedPointer<InputFilter> inputFilter;
|
||||
Value textValue;
|
||||
|
||||
enum
|
||||
|
|
@ -641,7 +690,6 @@ private:
|
|||
draggingSelectionEnd
|
||||
} dragType;
|
||||
|
||||
String allowedCharacters;
|
||||
ListenerList <Listener> listeners;
|
||||
Array <Range<int> > underlinedSections;
|
||||
|
||||
|
|
@ -661,7 +709,7 @@ private:
|
|||
int indexAtPosition (float x, float y);
|
||||
int findWordBreakAfter (int position) const;
|
||||
int findWordBreakBefore (int position) const;
|
||||
bool moveCaretWithTransation (int newPos, bool selecting);
|
||||
bool moveCaretWithTransaction (int newPos, bool selecting);
|
||||
friend class TextHolderComponent;
|
||||
friend class TextEditorViewport;
|
||||
void drawContent (Graphics&);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue