39 bool isNewLine()
const noexcept {
return atomText[0] ==
'\r' || atomText[0] ==
'\n'; }
43 if (passwordCharacter == 0)
52 if (passwordCharacter == 0)
72 initialiseAtoms (text);
82 if (!
other.atoms.isEmpty())
86 if (! atoms.isEmpty())
88 auto&
lastAtom = atoms.getReference (atoms.size() - 1);
92 auto& first =
other.atoms.getReference (0);
104 atoms.ensureStorageAllocated (atoms.size() +
other.atoms.size() - i);
106 while (i <
other.atoms.size())
108 atoms.add (
other.atoms.getReference (i));
119 for (
int i = 0; i < atoms.size(); ++i)
121 auto& atom = atoms.getReference (i);
122 auto nextIndex = index + atom.numChars;
126 for (
int j = i;
j < atoms.size(); ++
j)
127 section2->atoms.add (atoms.getUnchecked (
j));
129 atoms.removeRange (i, atoms.size());
142 atom.atomText = atom.atomText.substring (0,
indexToBreakAt - index);
146 for (
int j = i + 1;
j < atoms.size(); ++
j)
147 section2->atoms.add (atoms.getUnchecked (
j));
149 atoms.removeRange (i + 1, atoms.size());
161 for (
auto& atom : atoms)
169 for (
auto& atom : atoms)
171 auto nextIndex = index + atom.numChars;
175 if (range.
getEnd() <= index)
178 auto r = (range - index).getIntersectionWith ({ 0, (
int) atom.numChars });
181 mo << atom.atomText.substring (r.getStart(), r.getEnd());
188 int getTotalLength()
const noexcept
192 for (
auto& atom : atoms)
193 total += atom.numChars;
205 for (
auto& atom : atoms)
206 atom.width =
newFont.getStringWidthFloat (atom.getText (passwordChar));
227 if (text.isWhitespace() && *text !=
'\r' && *text !=
'\n')
234 while (text.isWhitespace() && *text !=
'\r' && *text !=
'\n');
249 else if (*text ==
'\n')
256 while (! (text.
isEmpty() || text.isWhitespace()))
265 atom.atomText =
String (start, numChars);
266 atom.width = (atom.isNewLine() ? 0.0f : font.
getStringWidthFloat (atom.getText (passwordChar)));
267 atom.numChars = (
uint16) numChars;
279 : sections (ed.sections),
280 justification (ed.justification),
281 bottomRight ((
float) ed.getMaximumTextWidth(), (
float) ed.getMaximumTextHeight()),
282 wordWrapWidth ((
float) ed.getWordWrapWidth()),
283 passwordCharacter (ed.passwordCharacter),
284 lineSpacing (ed.lineSpacing),
285 underlineWhitespace (ed.underlineWhitespace)
289 if (! sections.isEmpty())
291 currentSection = sections.getUnchecked (sectionIndex);
293 if (currentSection !=
nullptr)
306 if (atom == &longAtom && chunkLongAtom (
true))
309 if (sectionIndex >= sections.size())
311 moveToEndOfLastAtom();
317 if (atomIndex >= currentSection->atoms.size() - 1)
319 if (atomIndex >= currentSection->atoms.size())
321 if (++sectionIndex >= sections.size())
323 moveToEndOfLastAtom();
328 currentSection = sections.getUnchecked (sectionIndex);
332 auto&
lastAtom = currentSection->atoms.getReference (atomIndex);
338 float right = atomRight +
lastAtom.width;
344 auto* s = sections.getUnchecked (
section);
346 if (s->atoms.size() == 0)
349 auto&
nextAtom = s->atoms.getReference (0);
359 if (shouldWrap (right))
368 if (s->atoms.size() > 1)
380 indexInText += atom->numChars;
382 if (atom->isNewLine())
388 atom = &(currentSection->atoms.getReference (atomIndex));
389 atomRight = atomX + atom->width;
394 if (atom->isWhitespace())
397 atomRight =
jmin (atomRight, wordWrapWidth);
399 else if (shouldWrap (atom->width))
402 longAtom.numChars = 0;
409 atomRight = atomX + atom->width;
418 lineY += lineHeight * lineSpacing;
425 lineHeight =
section->font.getHeight();
426 maxDescent =
section->font.getDescent();
428 float nextLineWidth = (atom !=
nullptr) ? atom->width : 0.0f;
460 lineHeight =
jmax (lineHeight,
section->font.getHeight());
461 maxDescent =
jmax (maxDescent,
section->font.getDescent());
467 atomX = getJustificationOffsetX (
lineWidth);
470 float getJustificationOffsetX (
float lineWidth)
const
484 if (passwordCharacter != 0 || (underlineWhitespace || ! atom->isWhitespace()))
490 g.
setFont (currentSection->font);
497 atom->getTrimmedText (passwordCharacter),
498 atomX, (
float)
roundToInt (lineY + lineHeight - maxDescent));
499 ga.draw (g, transform);
520 if (passwordCharacter != 0 || ! atom->isWhitespace())
524 atom->getTrimmedText (passwordCharacter),
525 atomX, (
float)
roundToInt (lineY + lineHeight - maxDescent));
527 if (selected.
getEnd() < indexInText + atom->numChars)
530 ga2.removeRangeOfGlyphs (0, selected.
getEnd() - indexInText);
531 ga.removeRangeOfGlyphs (selected.
getEnd() - indexInText, -1);
534 ga2.draw (g, transform);
537 if (selected.
getStart() > indexInText)
540 ga2.removeRangeOfGlyphs (selected.
getStart() - indexInText, -1);
541 ga.removeRangeOfGlyphs (0, selected.
getStart() - indexInText);
544 ga2.draw (g, transform);
548 ga.draw (g, transform);
563 atom->getText (passwordCharacter),
572 int xToIndex (
float xToFind)
const
578 return indexInText + atom->numChars;
582 atom->getText (passwordCharacter),
596 return indexInText +
j;
604 if (indexInText + atom->numChars > index)
606 anchor = { indexToX (index), lineY };
612 anchor = { atomX, lineY };
624 if (lineY >= bottomRight.
y)
628 auto bottom =
jmax (0.0f, bottomRight.
y - lineY - lineHeight);
633 return bottom * 0.5f;
636 int getTotalTextHeight()
640 auto height = lineY + lineHeight + getYOffset();
642 if (atom !=
nullptr && atom->isNewLine())
643 height += lineHeight;
650 float maxWidth = 0.0f;
653 maxWidth =
jmax (maxWidth, atomRight);
668 float lineY = 0, lineHeight = 0, maxDescent = 0;
669 float atomX = 0, atomRight = 0;
675 int sectionIndex = 0, atomIndex = 0;
678 const float wordWrapWidth;
680 const float lineSpacing;
681 const bool underlineWhitespace;
691 longAtom.atomText = longAtom.atomText.
substring (longAtom.numChars);
692 indexInText += longAtom.numChars;
695 g.
addLineOfText (currentSection->font, atom->getText (passwordCharacter), 0.0f, 0.0f);
702 const auto numChars =
jmax (1, split);
703 longAtom.numChars = (
uint16) numChars;
706 atomX = getJustificationOffsetX (longAtom.width);
713 lineY += lineHeight * lineSpacing;
716 atomRight = atomX + longAtom.width;
720 void moveToEndOfLastAtom()
726 if (atom->isNewLine())
728 atomX = getJustificationOffsetX (0);
729 lineY += lineHeight * lineSpacing;
734 bool shouldWrap (
const float x)
const noexcept
736 return (x - 0.0001f) >= wordWrapWidth;
750 insertIndex (insertPos),
760 owner.insert (text, insertIndex, font, colour,
nullptr, newCaretPos);
766 owner.remove ({ insertIndex, insertIndex + text.
length() },
nullptr, oldCaretPos);
772 return text.
length() + 16;
778 const int insertIndex, oldCaretPos, newCaretPos;
800 owner.remove (range,
nullptr, newCaretPos);
806 owner.reinsert (range.
getStart(), removedSections);
807 owner.moveCaretTo (oldCaretPos,
false);
815 for (
auto* s : removedSections)
816 n += s->getTotalLength();
824 const int oldCaretPos, newCaretPos;
851 owner.drawContent (g);
861 owner.timerCallbackInt();
866 owner.textWasChangedByValue();
890 auto wordWrapWidth = owner.getWordWrapWidth();
892 if (wordWrapWidth != lastWordWrapWidth)
894 lastWordWrapWidth = wordWrapWidth;
909 int lastWordWrapWidth = 0;
910 bool reentrant =
false;
916namespace TextEditorDefs
918 const int textChangeMessageId = 0x10003001;
919 const int returnKeyMessageId = 0x10003002;
920 const int escapeKeyMessageId = 0x10003003;
921 const int focusLossMessageId = 0x10003004;
923 const int maxActionsPerTransaction = 100;
925 static int getCharacterCategory (
juce_wchar character)
noexcept
935 passwordCharacter (passwordChar)
942 viewport->setWantsKeyboardFocus (
false);
943 viewport->setScrollBarsShown (
false,
false);
952 peer->refreshTextInputTarget();
958 textHolder =
nullptr;
968bool TextEditor::undoOrRedo (
const bool shouldUndo)
975 : undoManager.redo())
988bool TextEditor::undo() {
return undoOrRedo (
true); }
989bool TextEditor::redo() {
return undoOrRedo (
false); }
1003 viewport->setViewPosition (0, 0);
1016 if (scrollbarVisible !=
shown)
1018 scrollbarVisible =
shown;
1032 peer->refreshTextInputTarget();
1038 clicksOutsideDismissVirtualKeyboard = newValue;
1048 return !
isReadOnly() && (! clicksOutsideDismissVirtualKeyboard || globalMouseListener.lastMouseDownInEditor());
1063 popupMenuEnabled = b;
1068 selectAllTextWhenFocused = b;
1073 if (justification !=
j)
1096 for (
auto*
uts : sections)
1102 coalesceSimilarSections();
1110 for (
auto*
uts : sections)
1145void TextEditor::recreateCaret()
1149 if (caret ==
nullptr)
1153 updateCaretPosition();
1162void TextEditor::updateCaretPosition()
1164 if (caret !=
nullptr
1169 topIndent +
roundToInt (i.getYOffset())) - getTextOffset());
1185 if (allowedCharacters.isNotEmpty())
1206 textToShowWhenEmpty = text;
1227 clearInternal (
nullptr);
1247 clearInternal (
nullptr);
1273void TextEditor::updateValueFromText()
1275 if (valueTextNeedsUpdating)
1277 valueTextNeedsUpdating =
false;
1284 updateValueFromText();
1288void TextEditor::textWasChangedByValue()
1304 valueTextNeedsUpdating =
false;
1330void TextEditor::timerCallbackInt()
1336 if (now > lastTransactionTime + 200)
1340void TextEditor::checkFocus()
1346void TextEditor::repaintText (Range<int> range)
1348 if (! range.isEmpty())
1358 Point<float> anchor;
1360 i.getCharPosition (range.getStart(), anchor,
lh);
1371 i.getCharPosition (range.getEnd(), anchor,
lh);
1372 y2 = (
int) (anchor.y +
lh * 2.0f);
1375 auto offset = i.getYOffset();
1381void TextEditor::moveCaret (
const int newCaretPos)
1391 textHolder->restartTimer();
1394 updateCaretPosition();
1402 return caretPosition;
1410void TextEditor::moveCaretToEnd()
1419 updateCaretPosition();
1427 else if (
desiredCaretX >
jmax (0, viewport->getMaximumVisibleWidth() - (wordWrap ? 2 : 10)))
1434 vy = viewport->getViewPositionY();
1446 viewport->setViewPosition (
vx,
vy);
1461 auto yOffset = i.getYOffset();
1474 if (
textRange.intersects ({ i.indexInText,
1475 i.indexInText + i.atom->numChars }))
1487constexpr int rightEdgeSpace = 2;
1489int TextEditor::getWordWrapWidth()
const
1491 return wordWrap ? getMaximumTextWidth()
1492 :
std::numeric_limits<
int>::max();
1495int TextEditor::getMaximumTextWidth()
const
1497 return jmax (1, viewport->getMaximumVisibleWidth() - leftIndent - rightEdgeSpace);
1500int TextEditor::getMaximumTextHeight()
const
1502 return jmax (1, viewport->getMaximumVisibleHeight() - topIndent);
1505void TextEditor::checkLayout()
1507 if (getWordWrapWidth() > 0)
1509 const auto textBottom = Iterator (*this).getTotalTextHeight() + topIndent;
1510 const auto textRight =
jmax (viewport->getMaximumVisibleWidth(),
1511 Iterator (*this).getTextRight() + leftIndent + rightEdgeSpace);
1514 viewport->setScrollBarsShown (scrollbarVisible && multiline &&
textBottom > viewport->getMaximumVisibleHeight(),
1515 scrollbarVisible && multiline && ! wordWrap &&
textRight > viewport->getMaximumVisibleWidth());
1536 borderSize = border;
1552 updateCaretPosition();
1554 if (keepCaretOnScreen)
1556 auto viewPos = viewport->getViewPosition();
1564 else if (
relativeCursor.x >
jmax (0, viewport->getMaximumVisibleWidth() - (wordWrap ? 2 : 10)))
1584 viewport->setViewPosition (
viewPos);
1596 if (dragType == notDragging)
1599 dragType = draggingSelectionStart;
1601 dragType = draggingSelectionEnd;
1604 if (dragType == draggingSelectionStart)
1607 dragType = draggingSelectionEnd;
1614 dragType = draggingSelectionStart;
1623 dragType = notDragging;
1625 repaintText (selection);
1634 const auto offset = getTextOffset();
1636 return indexAtPosition ((
float) (x - offset.x),
1637 (
float) (y - offset.y));
1652 const auto filtered = inputFilter !=
nullptr ? inputFilter->filterNewText (*
this, t) : t;
1654 :
filtered.replaceCharacters (
"\r\n",
" ");
1655 const auto insertIndex = selection.
getStart();
1656 const auto newCaretPos = insertIndex +
newText.length();
1658 remove (selection, getUndoManager(),
1659 newText.isNotEmpty() ? newCaretPos - 1 : newCaretPos);
1662 getUndoManager(), newCaretPos);
1681 if (passwordCharacter == 0)
1696 if (clip.isNotEmpty())
1705 moveCaret (selection.
getEnd());
1711void TextEditor::drawContent (
Graphics& g)
1713 if (getWordWrapWidth() > 0)
1718 auto yOffset = Iterator (*this).getYOffset();
1725 clip.setY (
roundToInt ((
float) clip.getY() - yOffset));
1745 while (i.next() && i.lineY < (
float) clip.getBottom())
1747 if (i.lineY + i.lineHeight >= (
float) clip.getY())
1749 if (selection.
intersects ({ i.indexInText, i.indexInText + i.atom->numChars }))
1763 Iterator
i2 (*
this);
1765 while (
i2.next() &&
i2.lineY < (
float) clip.getBottom())
1767 if (
i2.lineY +
i2.lineHeight >= (
float) clip.getY()
1768 &&
underlinedSection.intersects ({ i2.indexInText, i2.indexInText + i2.atom->numChars }))
1793 viewport->getWidth() - leftIndent,
1808 if (passwordCharacter == 0)
1820 if (getUndoManager() !=
nullptr)
1848 if (wasFocused || ! selectAllTextWhenFocused)
1855 peer->closeInputMethodContext();
1868 if (
auto* editor =
safeThis.getComponent())
1870 editor->menuActive =
false;
1882 if (wasFocused || ! selectAllTextWhenFocused)
1890 textHolder->restartTimer();
1892 if (wasFocused || ! selectAllTextWhenFocused)
1943 if (c !=
'\r' && c !=
'\n')
1953 if (c !=
'\r' && c !=
'\n')
1967 if (! viewport->useMouseWheelMoveIfNeeded (e,
wheel))
1972bool TextEditor::moveCaretWithTransaction (
const int newPos,
const bool selecting)
1978 peer->closeInputMethodContext();
1988 pos = findWordBreakBefore (pos);
1992 return moveCaretWithTransaction (pos,
selecting);
2000 pos = findWordBreakAfter (pos);
2004 return moveCaretWithTransaction (pos,
selecting);
2007bool TextEditor::moveCaretUp (
bool selecting)
2010 return moveCaretToStartOfLine (
selecting);
2014 const auto newY = caretPos.getY() - 1.0f;
2017 return moveCaretToStartOfLine (
selecting);
2019 return moveCaretWithTransaction (indexAtPosition (caretPos.getX(),
newY),
selecting);
2022bool TextEditor::moveCaretDown (
bool selecting)
2025 return moveCaretToEndOfLine (
selecting);
2028 return moveCaretWithTransaction (indexAtPosition (caretPos.getX(), caretPos.getBottom() + 1.0f),
selecting);
2034 return moveCaretToStartOfLine (
selecting);
2037 return moveCaretWithTransaction (indexAtPosition (caretPos.getX(), caretPos.getY() - (
float) viewport->getViewHeight()),
selecting);
2040bool TextEditor::pageDown (
bool selecting)
2043 return moveCaretToEndOfLine (
selecting);
2046 return moveCaretWithTransaction (indexAtPosition (caretPos.getX(), caretPos.getBottom() + (
float) viewport->getViewHeight()),
selecting);
2049void TextEditor::scrollByLines (
int deltaLines)
2051 viewport->getVerticalScrollBar().moveScrollbarInSteps (
deltaLines);
2054bool TextEditor::scrollDown()
2060bool TextEditor::scrollUp()
2066bool TextEditor::moveCaretToTop (
bool selecting)
2068 return moveCaretWithTransaction (0,
selecting);
2071bool TextEditor::moveCaretToStartOfLine (
bool selecting)
2074 return moveCaretWithTransaction (indexAtPosition (0.0f, caretPos.getCentreY()),
selecting);
2077bool TextEditor::moveCaretToEnd (
bool selecting)
2082bool TextEditor::moveCaretToEndOfLine (
bool selecting)
2085 return moveCaretWithTransaction (indexAtPosition ((
float) textHolder->
getWidth(), caretPos.getCentreY()),
selecting);
2093 setSelection ({ selection.
getEnd() - 1, selection.
getEnd() });
2099bool TextEditor::deleteForwards (
bool )
2108bool TextEditor::copyToClipboard()
2115bool TextEditor::cutToClipboard()
2123bool TextEditor::pasteFromClipboard()
2130bool TextEditor::selectAll()
2134 moveCaretTo (0,
true);
2156 if (returnKeyStartsNewLine)
2163 return consumeEscAndReturnKeys;
2171 return consumeEscAndReturnKeys;
2199 if ((! consumeEscAndReturnKeys)
2213 if (selectAllTextWhenFocused)
2215 moveCaretTo (0,
false);
2225 updateCaretPosition();
2235 underlinedSections.clear();
2237 updateCaretPosition();
2246 viewport->setBoundsInset (borderSize);
2252 updateCaretPosition();
2257void TextEditor::handleCommandMessage (
const int commandId)
2263 case TextEditorDefs::textChangeMessageId:
2264 listeners.callChecked (
checker, [
this] (Listener&
l) {
l.textEditorTextChanged (*
this); });
2266 if (!
checker.shouldBailOut())
2271 case TextEditorDefs::returnKeyMessageId:
2272 listeners.callChecked (
checker, [
this] (Listener&
l) {
l.textEditorReturnKeyPressed (*
this); });
2274 if (!
checker.shouldBailOut())
2279 case TextEditorDefs::escapeKeyMessageId:
2280 listeners.callChecked (
checker, [
this] (Listener&
l) {
l.textEditorEscapeKeyPressed (*
this); });
2282 if (!
checker.shouldBailOut())
2287 case TextEditorDefs::focusLossMessageId:
2288 updateValueFromText();
2289 listeners.callChecked (
checker, [
this] (Listener&
l) {
l.textEditorFocusLost (*
this); });
2291 if (!
checker.shouldBailOut())
2310 return passwordCharacter != 0 ? passwordKeyboard : keyboardType;
2316 return readOnly ?
nullptr : &undoManager;
2319void TextEditor::clearInternal (UndoManager*
const um)
2324void TextEditor::insert (
const String& text,
int insertIndex,
const Font& font,
2327 if (text.isNotEmpty())
2331 if (
um->getNumActionsInCurrentTransaction() > TextEditorDefs::maxActionsPerTransaction)
2334 um->perform (
new InsertAction (*
this, text, insertIndex, font, colour,
2345 for (
int i = 0; i < sections.size(); ++i)
2347 nextIndex = index + sections.getUnchecked (i)->getTotalLength();
2349 if (insertIndex == index)
2351 sections.insert (i,
new UniformTextSection (text, font, colour, passwordCharacter));
2355 if (insertIndex > index && insertIndex < nextIndex)
2357 splitSection (i, insertIndex - index);
2358 sections.insert (i + 1,
new UniformTextSection (text, font, colour, passwordCharacter));
2365 if (nextIndex == insertIndex)
2366 sections.add (
new UniformTextSection (text, font, colour, passwordCharacter));
2368 coalesceSimilarSections();
2370 valueTextNeedsUpdating =
true;
2385 for (
int i = 0; i < sections.size(); ++i)
2387 nextIndex = index + sections.getUnchecked (i)->getTotalLength();
2389 if (insertIndex == index)
2392 sections.insert (i,
new UniformTextSection (*
sectionsToInsert.getUnchecked (
j)));
2397 if (insertIndex > index && insertIndex < nextIndex)
2399 splitSection (i, insertIndex - index);
2402 sections.insert (i + 1,
new UniformTextSection (*
sectionsToInsert.getUnchecked (
j)));
2410 if (nextIndex == insertIndex)
2412 sections.add (new UniformTextSection (*s));
2414 coalesceSimilarSections();
2416 valueTextNeedsUpdating =
true;
2421 if (! range.isEmpty())
2425 for (
int i = 0; i < sections.size(); ++i)
2427 auto nextIndex = index + sections.getUnchecked (i)->getTotalLength();
2429 if (range.getStart() > index && range.getStart() < nextIndex)
2431 splitSection (i, range.getStart() - index);
2434 else if (range.getEnd() > index && range.getEnd() < nextIndex)
2436 splitSection (i, range.getEnd() - index);
2443 if (index > range.getEnd())
2454 for (
auto*
section : sections)
2456 if (range.getEnd() <= range.getStart())
2459 auto nextIndex = index +
section->getTotalLength();
2461 if (range.getStart() <= index && range.getEnd() >= nextIndex)
2462 removedSections.add (
new UniformTextSection (*
section));
2467 if (
um->getNumActionsInCurrentTransaction() > TextEditorDefs::maxActionsPerTransaction)
2470 um->perform (
new RemoveAction (*
this, range, caretPosition,
2477 for (
int i = 0; i < sections.size(); ++i)
2479 auto*
section = sections.getUnchecked (i);
2480 auto nextIndex = index +
section->getTotalLength();
2484 sections.remove (i);
2498 coalesceSimilarSections();
2500 valueTextNeedsUpdating =
true;
2516 for (
auto* s : sections)
2517 s->appendAllText (
mo);
2532 for (
auto* s : sections)
2534 auto nextIndex = index + s->getTotalLength();
2538 if (range.
getEnd() <= index)
2541 s->appendSubstring (
mo, range - index);
2557 if (totalNumChars < 0)
2561 for (
auto* s : sections)
2562 totalNumChars += s->getTotalLength();
2565 return totalNumChars;
2573void TextEditor::getCharPosition (
int index,
Point<float>& anchor,
float& lineHeight)
const
2575 if (getWordWrapWidth() <= 0)
2584 if (sections.isEmpty())
2586 anchor = { i.getJustificationOffsetX (0), 0 };
2591 i.getCharPosition (index, anchor, lineHeight);
2596int TextEditor::indexAtPosition (
const float x,
const float y)
const
2598 if (getWordWrapWidth() > 0)
2600 for (Iterator i (*
this); i.next();)
2602 if (y < i.lineY + (i.lineHeight * lineSpacing))
2604 if (
jmax (0.0f, y) < i.lineY)
2605 return jmax (0, i.indexInText - 1);
2608 return i.indexInText;
2610 if (x < i.atomRight)
2611 return i.xToIndex (x);
2620int TextEditor::findWordBreakAfter (
const int position)
const
2623 auto totalLength = t.
length();
2629 auto type = TextEditorDefs::getCharacterCategory (t[i]);
2631 while (i < totalLength && type == TextEditorDefs::getCharacterCategory (t[i]))
2637 return position + i;
2640int TextEditor::findWordBreakBefore (
const int position)
const
2655 auto type = TextEditorDefs::getCharacterCategory (t [i - 1]);
2657 while (i > 0 && type == TextEditorDefs::getCharacterCategory (t [i - 1]))
2667void TextEditor::splitSection (
const int sectionIndex,
const int charToSplitAt)
2669 jassert (sections[sectionIndex] !=
nullptr);
2671 sections.insert (sectionIndex + 1,
2672 sections.getUnchecked (sectionIndex)->split (
charToSplitAt));
2675void TextEditor::coalesceSimilarSections()
2677 for (
int i = 0; i < sections.size() - 1; ++i)
2679 auto* s1 = sections.getUnchecked (i);
2680 auto* s2 = sections.getUnchecked (i + 1);
2682 if (s1->font == s2->font
2683 && s1->colour == s2->colour)
2686 sections.remove (i + 1);
2698 textEditorToWrap.
isReadOnly() ? AccessibilityRole::staticText : AccessibilityRole::editableText,
2700 { std::make_unique<TextEditorTextInterface> (textEditorToWrap) }),
2701 textEditor (textEditorToWrap)
2711 explicit TextEditorTextInterface (
TextEditor& editor)
2712 : textEditor (editor)
2716 bool isDisplayingProtectedText()
const override {
return textEditor.getPasswordCharacter() != 0; }
2717 bool isReadOnly()
const override {
return textEditor.isReadOnly(); }
2719 int getTotalNumCharacters()
const override {
return textEditor.getText().length(); }
2720 Range<int> getSelection()
const override {
return textEditor.getHighlightedRegion(); }
2722 void setSelection (Range<int> r)
override
2724 textEditor.setHighlightedRegion (r);
2727 String getText (Range<int> r)
const override
2729 if (isDisplayingProtectedText())
2730 return String::repeatedString (String::charToString (textEditor.getPasswordCharacter()),
2731 getTotalNumCharacters());
2733 return textEditor.getTextInRange (r);
2736 void setText (
const String& newText)
override
2738 textEditor.setText (newText);
2741 int getTextInsertionOffset()
const override {
return textEditor.getCaretPosition(); }
2743 RectangleList<int> getTextBounds (Range<int> textRange)
const override
2745 auto localRects = textEditor.getTextBounds (textRange);
2746 RectangleList<int> globalRects;
2749 [&] (
const Rectangle<int>& r) { globalRects.add (textEditor.localAreaToGlobal (r)); });
2754 int getOffsetAtPoint (Point<int> point)
const override
2756 return textEditor.getTextIndexAt (textEditor.getLocalPoint (
nullptr, point));
2760 TextEditor& textEditor;
2766 TextEditor& textEditor;
2774 return std::make_unique<EditorAccessibilityHandler> (*
this);
Base class for accessible Components.
An abstract interface which represents a UI element that supports a text interface.
Holds a resizable array of primitive or copy-by-value objects.
void add(const ElementType &newElement)
Appends a new element at the end of the array.
Specifies a set of gaps to be left around the sides of a rectangle.
ValueType getTop() const noexcept
Returns the gap that should be left at the top of the region.
ValueType getLeft() const noexcept
Returns the gap that should be left at the left of the region.
static bool isWhitespace(char character) noexcept
Checks whether a character is whitespace.
static bool isLetterOrDigit(char character) noexcept
Checks whether a character is alphabetic or numeric.
Represents a colour, also including a transparency value.
A class to keep an eye on a component and check for it being deleted.
Holds a pointer to some type of Component, which automatically becomes null if the component is delet...
The base class for all JUCE user-interface objects.
int proportionOfWidth(float proportion) const noexcept
Returns a proportion of the component's width.
void setInterceptsMouseClicks(bool allowClicksOnThisComponent, bool allowClicksOnChildComponents) noexcept
Changes the default return value for the hitTest() method.
int getHeight() const noexcept
Returns the component's height in pixels.
void addAndMakeVisible(Component *child, int zOrder=-1)
Adds a child component to this one, and also makes the child visible if it isn't already.
FocusChangeType
Enumeration used by the focusGained() and focusLost() methods.
@ focusChangedByMouseClick
Means that the user clicked the mouse to change focus.
bool hasKeyboardFocus(bool trueIfChildIsFocused) const
Returns true if this component currently has the keyboard focus.
bool isCurrentlyBlockedByAnotherModalComponent() const
Checks whether there's a modal component somewhere that's stopping this one from receiving messages.
AccessibilityHandler * getAccessibilityHandler()
Returns the accessibility handler for this component, or nullptr if this component is not accessible.
void setMouseCursor(const MouseCursor &cursorType)
Changes the mouse cursor shape to use when the mouse is over this component.
void postCommandMessage(int commandId)
Dispatches a numbered message to this component.
Rectangle< int > getBounds() const noexcept
Returns this component's bounding box.
void repaint()
Marks the whole component as needing to be redrawn.
void setSize(int newWidth, int newHeight)
Changes the size of the component.
void setColour(int colourID, Colour newColour)
Registers a colour to be used for a particular purpose.
void setWantsKeyboardFocus(bool wantsFocus) noexcept
Sets a flag to indicate whether this component wants keyboard focus or not.
Colour findColour(int colourID, bool inheritFromParent=false) const
Looks for a colour that has been registered with the given colour ID number.
int getWidth() const noexcept
Returns the component's width in pixels.
void mouseWheelMove(const MouseEvent &event, const MouseWheelDetails &wheel) override
Called when the mouse-wheel is moved.
static void JUCE_CALLTYPE beginDragAutoRepeat(int millisecondsBetweenCallbacks)
Ensures that a non-stop stream of mouse-drag events will be sent during the current mouse-drag operat...
bool isEnabled() const noexcept
Returns true if the component (and all its parents) are enabled.
ComponentPeer * getPeer() const
Returns the heavyweight window that contains this component.
LookAndFeel & getLookAndFeel() const noexcept
Finds the appropriate look-and-feel to use for this component.
void addChildComponent(Component *child, int zOrder=-1)
Adds a child component to this one.
void invalidateAccessibilityHandler()
Invalidates the AccessibilityHandler that is currently being used for this component.
Represents a particular font, including its size, style, etc.
float getHeight() const noexcept
Returns the total height of this font, in pixels.
float getStringWidthFloat(const String &text) const
Returns the total width of a string as it would be drawn using this font.
float getAscent() const
Returns the height of the font above its baseline, in pixels.
A set of glyphs, each with a position.
void addLineOfText(const Font &font, const String &text, float x, float y)
Appends a line of text to the arrangement.
int getNumGlyphs() const noexcept
Returns the total number of glyphs in the arrangement.
PositionedGlyph & getGlyph(int index) noexcept
Returns one of the glyphs from the arrangement.
Uses RAII to save and restore the state of a graphics context.
A graphics context, used for drawing a component or image.
void drawText(const String &text, int x, int y, int width, int height, Justification justificationType, bool useEllipsesIfTooBig=true) const
Draws a line of text within a specified rectangle.
void setFont(const Font &newFont)
Changes the font to use for subsequent text-drawing functions.
void addTransform(const AffineTransform &transform)
Adds a transformation which will be performed on all the graphics operations that the context subsequ...
void fillPath(const Path &path) const
Fills a path using the currently selected colour or brush.
bool reduceClipRegion(int x, int y, int width, int height)
Intersects the current clipping region with another region.
void fillCheckerBoard(Rectangle< float > area, float checkWidth, float checkHeight, Colour colour1, Colour colour2) const
Fills a rectangle with a checkerboard pattern, alternating between two colours.
Rectangle< int > getClipBounds() const
Returns the position of the bounding box for the current clipping region.
void setColour(Colour newColour)
Changes the current drawing colour.
void setOrigin(Point< int > newOrigin)
Moves the position of the context's origin.
Represents a type of justification to be used when positioning graphical items.
@ horizontallyCentred
Indicates that the item should be placed in the centre between the left and right sides of the availa...
@ bottom
Indicates that the item should be aligned against the bottom edge of the available space.
@ top
Indicates that the item should be aligned against the top edge of the available space.
@ right
Indicates that the item should be aligned against the right edge of the available space.
bool testFlags(int flagsToTest) const noexcept
Tests a set of flags for this object.
Represents a key press, including any modifier keys that are needed.
juce_wchar getTextCharacter() const noexcept
Returns the character that is associated with this keypress.
bool isKeyCode(int keyCodeToCompare) const noexcept
Checks whether the KeyPress's key is the same as the one provided, without checking the modifiers.
static const int F4Key
key-code for the F4 key
static const int escapeKey
key-code for the escape key
static const int returnKey
key-code for the return key
Writes data to an internal memory buffer, which grows as required.
void preallocate(size_t bytesToPreallocate)
Increases the internal storage capacity to be able to contain at least the specified amount of data w...
static ModifierKeys currentModifiers
This object represents the last-known state of the keyboard and mouse buttons.
bool isCommandDown() const noexcept
Checks whether the 'command' key flag is set (or 'ctrl' on Windows/Linux).
bool isPopupMenu() const noexcept
Checks whether the user is trying to launch a pop-up menu.
bool isShiftDown() const noexcept
Checks whether the shift key's flag is set.
@ commandModifier
Command key flag - on windows this is the same as the CTRL key flag.
@ altModifier
ALT key flag.
@ IBeamCursor
A vertical I-beam for positioning within text.
@ ParentCursor
Indicates that the component's parent's cursor should be used.
Contains position and status information about a mouse event.
const ModifierKeys mods
The key modifiers associated with the event.
Point< int > getPosition() const noexcept
The position of the mouse when the event occurred.
int getNumberOfClicks() const noexcept
For a click event, the number of times the mouse was clicked in succession.
bool mouseWasClicked() const noexcept
Returns true if the mouse event is part of a click gesture rather than a drag.
An array designed for holding objects.
A pair of (x, y) coordinates.
ValueType y
The point's Y coordinate.
ValueType x
The point's X coordinate.
float getRight() const noexcept
Returns the position of the glyph's right-hand edge.
float getLeft() const noexcept
Returns the position of the glyph's left-hand edge.
A general-purpose range object, that simply represents any linear range with a start and end point.
constexpr ValueType getStart() const noexcept
Returns the start of the range.
constexpr bool isEmpty() const noexcept
Returns true if the range has a length of zero.
constexpr bool intersects(Range other) const noexcept
Returns true if the given range intersects this one.
constexpr ValueType getEnd() const noexcept
Returns the end of the range.
constexpr Range getUnionWith(Range other) const noexcept
Returns the smallest range that contains both this one and the other one.
constexpr ValueType getLength() const noexcept
Returns the length of the range.
Maintains a set of rectangles as a complex region.
Manages a rectangle and allows geometric operations to be performed on it.
ValueType getX() const noexcept
Returns the x coordinate of the rectangle's left-hand-side.
Rectangle< int > getSmallestIntegerContainer() const noexcept
Returns the smallest integer-aligned rectangle that completely contains this one.
Rectangle translated(ValueType deltaX, ValueType deltaY) const noexcept
Returns a rectangle which is the same as this one moved by a given amount.
Point< ValueType > getConstrainedPoint(Point< ValueType > point) const noexcept
Returns the nearest point to the specified point that lies within this rectangle.
int getReferenceCount() const noexcept
Returns the object's current reference count.
Helper class providing an RAII-based mechanism for temporarily setting and then re-setting a value.
CharPointerType getCharPointer() const noexcept
Returns the character pointer currently being used to store this string.
static String repeatedString(StringRef stringToRepeat, int numberOfTimesToRepeat)
Creates a string which is a version of a string repeated and joined together.
int length() const noexcept
Returns the number of characters in the string.
bool isEmpty() const noexcept
Returns true if the string contains no characters.
String retainCharacters(StringRef charactersToRetain) const
Returns a version of this string that only retains a fixed set of characters.
static String charToString(juce_wchar character)
Creates a string from a single character.
String substring(int startIndex, int endIndex) const
Returns a subsection of the string.
bool isNotEmpty() const noexcept
Returns true if the string contains at least one character.
static String getTextFromClipboard()
Gets the current clipboard's contents.
static void copyTextToClipboard(const String &text)
Copies a string of text onto the clipboard.
String getHelp() const override
Some help text for the UI element (if required).
Base class for input filters that can be applied to a TextEditor to restrict the text that can be ent...
An input filter for a TextEditor that limits the length of text and/or the characters that it may con...
LengthAndCharacterRestriction(int maxNumChars, const String &allowedCharacters)
Creates a filter that limits the length of text, and/or the characters that it can contain.
String filterNewText(TextEditor &, const String &) override
This method is called whenever text is entered into the editor.
Receives callbacks from a TextEditor component when it changes.
void paint(Graphics &) override
Components can override this method to draw their content.
void scrollEditorToPositionCaret(int desiredCaretX, int desiredCaretY)
Attempts to scroll the text editor so that the caret ends up at a specified position.
int getCaretPosition() const override
Returns the current index of the caret.
bool isTextInputActive() const override
Returns true if this input target is currently accepting input.
void setScrollbarsShown(bool shouldBeEnabled)
Enables or disables scrollbars (this only applies when in multi-line mode).
void setMultiLine(bool shouldBeMultiLine, bool shouldWordWrap=true)
Puts the editor into either multi- or single-line mode.
@ highlightColourId
The colour with which to fill the background of highlighted sections of the text - this can be transp...
@ textColourId
The colour that will be used when text is added to the editor.
@ highlightedTextColourId
The colour with which to draw the text in highlighted sections.
void setCaretPosition(int newIndex)
Moves the caret to be in front of a given character.
bool isEmpty() const
Returns true if there are no characters in the editor.
bool keyStateChanged(bool) override
Called when a key is pressed or released.
void setBorder(BorderSize< int > border)
Changes the size of border left around the edge of the component.
void mouseWheelMove(const MouseEvent &, const MouseWheelDetails &) override
Called when the mouse-wheel is moved.
void applyColourToAllText(const Colour &newColour, bool changeCurrentTextColour=true)
Applies a colour to all the text in the editor.
RectangleList< int > getTextBounds(Range< int > textRange) const override
Returns the bounding box for a range of text in the editor.
int getTextWidth() const
Returns the total width of the text, as it is currently laid-out.
std::unique_ptr< AccessibilityHandler > createAccessibilityHandler() override
Override this method to return a custom AccessibilityHandler for this component.
void setIndents(int newLeftIndent, int newTopIndent)
Changes the size of the gap at the top and left-edge of the editor.
void insertTextAtCaret(const String &textToInsert) override
Inserts some text at the current caret position.
VirtualKeyboardType getKeyboardType() override
Returns the target's preference for the type of keyboard that would be most appropriate.
virtual void escapePressed()
Can be overridden to intercept escape key presses directly.
void mouseDown(const MouseEvent &) override
Called when a mouse button is pressed.
~TextEditor() override
Destructor.
void setPasswordCharacter(juce_wchar passwordCharacter)
Changes the password character used to disguise the text.
void newTransaction()
Begins a new transaction in the UndoManager.
bool isReadOnly() const noexcept
Returns true if the editor is in read-only mode.
void setTemporaryUnderlining(const Array< Range< int > > &) override
Sets a number of temporarily underlined sections.
const Font & getFont() const noexcept
Returns the font that's currently being used for new text.
std::function< void()> onFocusLost
You can assign a lambda to this callback object to have it called when the editor loses key focus.
std::function< void()> onEscapeKey
You can assign a lambda to this callback object to have it called when the escape key is pressed.
void setFont(const Font &newFont)
Sets the font to use for newly added text.
void focusGained(FocusChangeType) override
Called to indicate that this component has just acquired the keyboard focus.
void clear()
Deletes all the text from the editor.
void copy()
Copies the currently selected region to the clipboard.
int getTotalNumChars() const override
Counts the number of characters in the text.
String getHighlightedText() const
Returns the section of text that is currently selected.
void enablementChanged() override
Callback to indicate that this component has been enabled or disabled.
std::function< void()> onReturnKey
You can assign a lambda to this callback object to have it called when the return key is pressed.
int getLeftIndent() const noexcept
Returns the gap at the left edge of the editor.
Rectangle< int > getCaretRectangleForCharIndex(int index) const override
Get the graphical position of the caret for a particular index in the text.
void setText(const String &newText, bool sendTextChangeMessage=true)
Sets the entire content of the editor.
int getTextHeight() const
Returns the maximum height of the text, as it is currently laid-out.
void paintOverChildren(Graphics &) override
Components can override this method to draw over the top of their children.
void addListener(Listener *newListener)
Registers a listener to be told when things happen to the text.
void mouseDrag(const MouseEvent &) override
Called when the mouse is moved while a button is held down.
void setReadOnly(bool shouldBeReadOnly)
Changes the editor to read-only mode.
int getTextIndexAt(int x, int y) const
Finds the index of the character at a given position.
void setEscapeAndReturnKeysConsumed(bool shouldBeConsumed) noexcept
This can be used to change whether escape and return keypress events are propagated up to the parent ...
int getCharIndexForPoint(Point< int > point) const override
Like getTextIndexAt, but doesn't snap to the beginning/end of the range for points vertically outside...
void setClicksOutsideDismissVirtualKeyboard(bool)
Sets the behaviour of mouse/touch interactions outside this component.
String getTextInRange(const Range< int > &textRange) const override
Returns a section of the contents of the editor.
int getTopIndent() const noexcept
Returns the gap at the top edge of the editor.
void lookAndFeelChanged() override
Called to let the component react to a change in the look-and-feel setting.
virtual void addPopupMenuItems(PopupMenu &menuToAddTo, const MouseEvent *mouseClickEvent)
This adds the items to the popup menu.
Range< int > getHighlightedRegion() const override
Returns the range of characters that are selected.
virtual void returnPressed()
Can be overridden to intercept return key presses directly.
void resized() override
Called when this component's size has been changed.
void setJustification(Justification newJustification)
Modifies the justification of the text within the editor window.
void scrollToMakeSureCursorIsVisible()
Scrolls the minimum distance needed to get the caret into view.
void mouseDoubleClick(const MouseEvent &) override
Called when a mouse button has been double-clicked on a component.
void textChanged()
Used internally to dispatch a text-change message.
void setTextToShowWhenEmpty(const String &text, Colour colourToUse)
When the text editor is empty, it can be set to display a message.
void setInputFilter(InputFilter *newFilter, bool takeOwnership)
Sets an input filter that should be applied to this editor.
virtual void performPopupMenuAction(int menuItemID)
This is called to perform one of the items that was shown on the popup menu.
void focusLost(FocusChangeType) override
Called to indicate that this component has just lost the keyboard focus.
void setInputRestrictions(int maxTextLength, const String &allowedCharacters=String())
Sets limits on the characters that can be entered.
Value & getTextValue()
Returns a Value object that can be used to get or set the text.
bool isCaretVisible() const noexcept
Returns true if the caret is enabled.
void setHighlightedRegion(const Range< int > &newSelection) override
Selects a section of the text.
std::function< void()> onTextChange
You can assign a lambda to this callback object to have it called when the text is changed.
void setCaretVisible(bool shouldBeVisible)
Makes the caret visible or invisible.
void setPopupMenuEnabled(bool menuEnabled)
Allows a right-click menu to appear for the editor.
TextEditor(const String &componentName=String(), juce_wchar passwordCharacter=0)
Creates a new, empty text editor.
void cut()
Deletes the currently selected region.
void setTabKeyUsedAsCharacter(bool shouldTabKeyBeUsed)
Indicates whether the tab key should be accepted and used to input a tab character,...
bool keyPressed(const KeyPress &) override
Called when a key is pressed.
void setReturnKeyStartsNewLine(bool shouldStartNewLine)
Changes the behaviour of the return key.
void mouseUp(const MouseEvent &) override
Called when a mouse button is released.
bool isMultiLine() const
Returns true if the editor is in multi-line mode.
String getText() const
Returns the entire contents of the editor.
void parentHierarchyChanged() override
Called to indicate that the component's parents have changed.
BorderSize< int > getBorder() const
Returns the size of border around the edge of the component.
void removeListener(Listener *listenerToRemove)
Deregisters a listener.
void paste()
Pastes the contents of the clipboard into the editor at the caret position.
void setSelectAllWhenFocused(bool shouldSelectAll)
If set to true, focusing on the editor will highlight all its text.
void applyFontToAllText(const Font &newFont, bool changeCurrentFont=true)
Applies a font to all the text in the editor.
void setScrollBarThickness(int newThicknessPixels)
Changes the size of the scrollbars that are used.
void setScrollToShowCursor(bool shouldScrollToShowCaret)
Used to disable the auto-scrolling which keeps the caret visible.
VirtualKeyboardType
A set of possible on-screen keyboard types, for use in the getKeyboardType() method.
Rectangle< int > getCaretRectangle() const
Returns the position of the caret, relative to the component's origin.
static uint32 getApproximateMillisecondCounter() noexcept
Less-accurate but faster version of getMillisecondCounter().
Makes repeated callbacks to a virtual method at a specified time interval.
void stopTimer() noexcept
Stops the timer.
void startTimer(int intervalInMilliseconds) noexcept
Starts the timer and sets the length of interval required.
Manages a list of undo/redo commands.
void beginNewTransaction()
Starts a new group of actions that together will be treated as a single transaction.
bool undo()
Tries to roll-back the last transaction.
void clearUndoHistory()
Deletes all stored actions in the list.
bool canUndo() const
Returns true if there's at least one action in the list to undo.
bool canRedo() const
Returns true if there's at least one action in the list to redo.
Used by the UndoManager class to store an action which can be done and undone.
Receives callbacks when a Value object changes.
Represents a shared variant value.
void addListener(Listener *listener)
Adds a listener to receive callbacks when the value changes.
void removeListener(Listener *listener)
Removes a listener that was previously added with addListener().
ValueSource & getValueSource() noexcept
Returns the ValueSource that this value is referring to.
void referTo(const Value &valueToReferTo)
Makes this object refer to the same underlying ValueSource as another one.
var getValue() const
Returns the current value.
A Viewport is used to contain a larger child component, and allows the child to be automatically scro...
#define JUCE_LEAK_DETECTOR(OwnerClass)
This macro lets you embed a leak-detecting object inside a class.
#define TRANS(stringLiteral)
Uses the LocalisedStrings class to translate the given string literal.
@ paste
The command ID that should be used to send a "Paste from clipboard" command.
@ del
The command ID that should be used to send a "Delete" command.
@ redo
The command ID that should be used to send a "redo" command.
@ undo
The command ID that should be used to send a "undo" command.
@ cut
The command ID that should be used to send a "Cut" command.
@ copy
The command ID that should be used to send a "Copy to clipboard" command.
@ selectAll
The command ID that should be used to send a "Select all" command.
unsigned short uint16
A platform-independent 16-bit unsigned integer type.
wchar_t juce_wchar
A platform-independent 32-bit unicode character type.
constexpr Type jmin(Type a, Type b)
Returns the smaller of two values.
constexpr Type jmax(Type a, Type b)
Returns the larger of two values.
Type jlimit(Type lowerLimit, Type upperLimit, Type valueToConstrain) noexcept
Constrains a value to keep it within a given range.
@ textChanged
Indicates that the visible text of a text element has changed.
@ textSelectionChanged
Indicates that the selection of a text element has changed.
Type unalignedPointerCast(void *ptr) noexcept
Casts a pointer to another type via void*, which suppresses the cast-align warning which sometimes ar...
bool isPositiveAndBelow(Type1 valueToTest, Type2 upperLimit) noexcept
Returns true if a value is at least zero, and also below a specified upper limit.
int roundToInt(const FloatType value) noexcept
Fast floating-point-to-integer conversion.
Contains status information about a mouse wheel event.
This class is used to invoke a range of text-editor navigation methods on an object,...
int getSizeInUnits() override
Returns a value to indicate how much memory this object takes up.
bool undo() override
Overridden by a subclass to undo the action.
bool perform() override
Overridden by a subclass to perform the action.
bool perform() override
Overridden by a subclass to perform the action.
int getSizeInUnits() override
Returns a value to indicate how much memory this object takes up.
bool undo() override
Overridden by a subclass to undo the action.
void visibleAreaChanged(const Rectangle< int > &) override
Callback method that is called when the visible area changes.
void paint(Graphics &g) override
Components can override this method to draw their content.
void timerCallback() override
The user-defined callback routine that actually gets called periodically.
void valueChanged(Value &) override
Called when a Value object is changed.