Browse Source

Added vertical justification support to TextEditor

tags/2021-05-28
ed 4 years ago
parent
commit
12bff68e34
3 changed files with 259 additions and 110 deletions
  1. +81
    -18
      examples/GUI/FontsDemo.h
  2. +168
    -86
      modules/juce_gui_basics/widgets/juce_TextEditor.cpp
  3. +10
    -6
      modules/juce_gui_basics/widgets/juce_TextEditor.h

+ 81
- 18
examples/GUI/FontsDemo.h View File

@@ -65,15 +65,22 @@ public:
addAndMakeVisible (kerningLabel);
addAndMakeVisible (kerningSlider);
addAndMakeVisible (scaleLabel);
addAndMakeVisible (horizontalJustificationLabel);
addAndMakeVisible (verticalJustificationLabel);
addAndMakeVisible (scaleSlider);
addAndMakeVisible (boldToggle);
addAndMakeVisible (italicToggle);
addAndMakeVisible (styleBox);
addAndMakeVisible (horizontalJustificationBox);
addAndMakeVisible (verticalJustificationBox);
addAndMakeVisible (resetButton);
kerningLabel.attachToComponent (&kerningSlider, true);
heightLabel .attachToComponent (&heightSlider, true);
scaleLabel .attachToComponent (&scaleSlider, true);
styleLabel .attachToComponent (&styleBox, true);
kerningLabel .attachToComponent (&kerningSlider, true);
heightLabel .attachToComponent (&heightSlider, true);
scaleLabel .attachToComponent (&scaleSlider, true);
styleLabel .attachToComponent (&styleBox, true);
horizontalJustificationLabel.attachToComponent (&horizontalJustificationBox, true);
verticalJustificationLabel .attachToComponent (&verticalJustificationBox, true);
heightSlider .addListener (this);
kerningSlider.addListener (this);
@@ -94,10 +101,6 @@ public:
scaleSlider .setRange (0.2, 3.0, 0.01);
kerningSlider.setRange (-2.0, 2.0, 0.01);
scaleSlider .setValue (1.0); // Set some initial values for the sliders.
heightSlider .setValue (20.0);
kerningSlider.setValue (0);
// set up the layout and resizer bars..
verticalLayout.setItemLayout (0, -0.2, -0.8, -0.35); // width of the font list must be
// between 20% and 80%, preferably 50%
@@ -127,6 +130,11 @@ public:
demoTextBox.setColour (TextEditor::textColourId, Colours::black);
demoTextBox.setColour (TextEditor::backgroundColourId, Colours::white);
resetButton.onClick = [this] { resetToDefaultParameters(); };
setupJustificationOptions();
resetToDefaultParameters();
setSize (750, 750);
}
@@ -151,7 +159,10 @@ public:
r.removeFromLeft (verticalDividerBar->getRight());
int labelWidth = 60;
resetButton.setBounds (r.removeFromBottom (30).reduced (jmax (20, r.getWidth() / 5), 0));
r.removeFromBottom (8);
const int labelWidth = 60;
auto styleArea = r.removeFromBottom (26);
styleArea.removeFromLeft (labelWidth);
@@ -163,6 +174,10 @@ public:
boldToggle.setBounds (row.removeFromLeft (row.getWidth() / 2));
italicToggle.setBounds (row);
r.removeFromBottom (8);
horizontalJustificationBox.setBounds (r.removeFromBottom (30).withTrimmedLeft (labelWidth * 3));
r.removeFromBottom (8);
verticalJustificationBox.setBounds (r.removeFromBottom (30).withTrimmedLeft (labelWidth * 3));
r.removeFromBottom (8);
scaleSlider.setBounds (r.removeFromBottom (30).withTrimmedLeft (labelWidth));
r.removeFromBottom (8);
@@ -175,9 +190,9 @@ public:
void sliderValueChanged (Slider* sliderThatWasMoved) override
{
if (sliderThatWasMoved == &heightSlider) refreshPreviewBoxFont();
else if (sliderThatWasMoved == &kerningSlider) refreshPreviewBoxFont();
else if (sliderThatWasMoved == &scaleSlider) refreshPreviewBoxFont();
if (sliderThatWasMoved == &heightSlider) refreshPreviewBoxFont();
else if (sliderThatWasMoved == &kerningSlider) refreshPreviewBoxFont();
else if (sliderThatWasMoved == &scaleSlider) refreshPreviewBoxFont();
}
// The following methods implement the ListBoxModel virtual methods:
@@ -215,21 +230,69 @@ private:
ListBox listBox;
TextEditor demoTextBox;
Label heightLabel { {}, "Height:" },
kerningLabel { {}, "Kerning:" },
scaleLabel { {}, "Scale:" },
styleLabel { {}, "Style:" };
const double defaultScale = 1.0, defaultHeight = 20.0, defaultKerning = 0.0;
const bool defaultBold = false, defaultItalic = false;
const int defaultStyle = 0, defaultHorizontalJustification = 0, defaultVerticalJustification = 0;
Label heightLabel { {}, "Height:" },
kerningLabel { {}, "Kerning:" },
scaleLabel { {}, "Scale:" },
styleLabel { {}, "Style:" },
horizontalJustificationLabel { {}, "Justification (horizontal):" },
verticalJustificationLabel { {}, "Justification (vertical):" };
ToggleButton boldToggle { "Bold" },
italicToggle { "Italic" };
TextButton resetButton { "Reset" };
Slider heightSlider, kerningSlider, scaleSlider;
ComboBox styleBox;
ComboBox styleBox, horizontalJustificationBox, verticalJustificationBox;
StretchableLayoutManager verticalLayout;
std::unique_ptr<StretchableLayoutResizerBar> verticalDividerBar;
StringArray horizontalJustificationStrings { "Left", "Centred", "Right" },
verticalJustificationStrings { "Top", "Centred", "Bottom" };
Array<int> horizontalJustificationFlags { Justification::left, Justification::horizontallyCentred, Justification::right },
verticalJustificationFlags { Justification::top, Justification::verticallyCentred, Justification::bottom};
//==============================================================================
void resetToDefaultParameters()
{
scaleSlider .setValue (defaultScale);
heightSlider .setValue (defaultHeight);
kerningSlider.setValue (defaultKerning);
boldToggle .setToggleState (defaultBold, sendNotificationSync);
italicToggle.setToggleState (defaultItalic, sendNotificationSync);
styleBox.setSelectedItemIndex (defaultStyle);
horizontalJustificationBox.setSelectedItemIndex (defaultHorizontalJustification);
verticalJustificationBox .setSelectedItemIndex (defaultVerticalJustification);
}
void setupJustificationOptions()
{
horizontalJustificationBox.addItemList (horizontalJustificationStrings, 1);
verticalJustificationBox .addItemList (verticalJustificationStrings, 1);
auto updateJustification = [this]()
{
auto horizontalIndex = horizontalJustificationBox.getSelectedItemIndex();
auto verticalIndex = verticalJustificationBox.getSelectedItemIndex();
auto horizontalJustification = horizontalJustificationFlags[horizontalIndex];
auto verticalJustification = verticalJustificationFlags[verticalIndex];
demoTextBox.setJustification (horizontalJustification | verticalJustification);
};
horizontalJustificationBox.onChange = updateJustification;
verticalJustificationBox .onChange = updateJustification;
}
void refreshPreviewBoxFont()
{
auto bold = boldToggle .getToggleState();
@@ -265,7 +328,7 @@ private:
styleBox.clear();
styleBox.addItemList (newStyles, 1);
styleBox.setSelectedItemIndex (0);
styleBox.setSelectedItemIndex (defaultStyle);
}
}


+ 168
- 86
modules/juce_gui_basics/widgets/juce_TextEditor.cpp View File

@@ -278,7 +278,7 @@ struct TextEditor::Iterator
Iterator (const TextEditor& ed)
: sections (ed.sections),
justification (ed.justification),
justificationWidth (ed.getJustificationWidth()),
bottomRight (ed.getMaximumWidth(), ed.getMaximumHeight()),
wordWrapWidth (ed.getWordWrapWidth()),
passwordCharacter (ed.passwordCharacter),
lineSpacing (ed.lineSpacing)
@@ -292,6 +292,8 @@ struct TextEditor::Iterator
if (currentSection != nullptr)
beginNewLine();
}
lineHeight = ed.currentFont.getHeight();
}
Iterator (const Iterator&) = default;
@@ -325,7 +327,7 @@ struct TextEditor::Iterator
{
tempAtom.numChars = (uint16) split;
tempAtom.width = g.getGlyph (split - 1).getRight();
atomX = getJustificationOffset (tempAtom.width);
atomX = getJustificationOffsetX (tempAtom.width);
atomRight = atomX + tempAtom.width;
return true;
}
@@ -427,14 +429,14 @@ struct TextEditor::Iterator
tempAtom.numChars = 0;
atom = &tempAtom;
if (atomX > justificationOffset)
if (atomX > justificationOffsetX)
beginNewLine();
return next();
}
beginNewLine();
atomX = justificationOffset;
atomX = justificationOffsetX;
atomRight = atomX + atom->width;
return true;
}
@@ -494,23 +496,20 @@ struct TextEditor::Iterator
++tempAtomIndex;
}
justificationOffset = getJustificationOffset (lineWidth);
atomX = justificationOffset;
justificationOffsetX = getJustificationOffsetX (lineWidth);
atomX = justificationOffsetX;
}
float getJustificationOffset (float lineWidth) const
float getJustificationOffsetX (float lineWidth) const
{
if (justification.getOnlyHorizontalFlags() == Justification::horizontallyCentred)
return jmax (0.0f, (justificationWidth - lineWidth) * 0.5f);
if (justification.getOnlyHorizontalFlags() == Justification::right)
return jmax (0.0f, justificationWidth - lineWidth);
if (justification.testFlags (Justification::horizontallyCentred)) return jmax (0.0f, (bottomRight.x - lineWidth) * 0.5f);
if (justification.testFlags (Justification::right)) return jmax (0.0f, bottomRight.x - lineWidth);
return 0;
}
//==============================================================================
void draw (Graphics& g, const UniformTextSection*& lastSection) const
void draw (Graphics& g, const UniformTextSection*& lastSection, AffineTransform transform) const
{
if (passwordCharacter != 0 || ! atom->isWhitespace())
{
@@ -527,7 +526,7 @@ struct TextEditor::Iterator
ga.addLineOfText (currentSection->font,
atom->getTrimmedText (passwordCharacter),
atomX, (float) roundToInt (lineY + lineHeight - maxDescent));
ga.draw (g);
ga.draw (g, transform);
}
}
@@ -539,18 +538,19 @@ struct TextEditor::Iterator
area.add (startX, lineY, endX - startX, lineHeight * lineSpacing);
}
void drawUnderline (Graphics& g, Range<int> underline, Colour colour) const
void drawUnderline (Graphics& g, Range<int> underline, Colour colour, AffineTransform transform) const
{
auto startX = roundToInt (indexToX (underline.getStart()));
auto endX = roundToInt (indexToX (underline.getEnd()));
auto baselineY = roundToInt (lineY + currentSection->font.getAscent() + 0.5f);
Graphics::ScopedSaveState state (g);
g.addTransform (transform);
g.reduceClipRegion ({ startX, baselineY, endX - startX, 1 });
g.fillCheckerBoard ({ (float) endX, (float) baselineY + 1.0f }, 3.0f, 1.0f, colour, Colours::transparentBlack);
}
void drawSelectedText (Graphics& g, Range<int> selected, Colour selectedTextColour) const
void drawSelectedText (Graphics& g, Range<int> selected, Colour selectedTextColour, AffineTransform transform) const
{
if (passwordCharacter != 0 || ! atom->isWhitespace())
{
@@ -566,7 +566,7 @@ struct TextEditor::Iterator
ga.removeRangeOfGlyphs (selected.getEnd() - indexInText, -1);
g.setColour (currentSection->colour);
ga2.draw (g);
ga2.draw (g, transform);
}
if (selected.getStart() > indexInText)
@@ -576,11 +576,11 @@ struct TextEditor::Iterator
ga.removeRangeOfGlyphs (0, selected.getStart() - indexInText);
g.setColour (currentSection->colour);
ga2.draw (g);
ga2.draw (g, transform);
}
g.setColour (selectedTextColour);
ga.draw (g);
ga.draw (g, transform);
}
}
@@ -649,18 +649,39 @@ struct TextEditor::Iterator
return false;
}
float getYOffset()
{
if (justification.testFlags (Justification::top) || lineY >= bottomRight.y)
return 0;
while (next())
{
if (lineY >= bottomRight.y)
return 0;
}
auto bottom = jmax (0.0f, bottomRight.y - lineY - lineHeight);
if (justification.testFlags (Justification::bottom))
return bottom;
return bottom * 0.5f;
}
//==============================================================================
int indexInText = 0;
float lineY = 0, justificationOffset = 0, lineHeight = 0, maxDescent = 0;
float lineY = 0, lineHeight = 0, maxDescent = 0;
float atomX = 0, atomRight = 0;
const TextAtom* atom = nullptr;
const UniformTextSection* currentSection = nullptr;
private:
const OwnedArray<UniformTextSection>& sections;
const UniformTextSection* currentSection = nullptr;
int sectionIndex = 0, atomIndex = 0;
Justification justification;
const float justificationWidth, wordWrapWidth;
float justificationOffsetX = 0;
const Point<float> bottomRight;
const float wordWrapWidth;
const juce_wchar passwordCharacter;
const float lineSpacing;
TextAtom tempAtom;
@@ -673,7 +694,7 @@ private:
if (atom->isNewLine())
{
atomX = 0.0f;
atomX = getJustificationOffsetX (0);
lineY += lineHeight * lineSpacing;
}
}
@@ -826,8 +847,8 @@ struct TextEditor::TextEditorViewport : public Viewport
void visibleAreaChanged (const Rectangle<int>&) override
{
if (! rentrant) // it's rare, but possible to get into a feedback loop as the viewport's scrollbars
// appear and disappear, causing the wrap width to change.
if (! reentrant) // it's rare, but possible to get into a feedback loop as the viewport's scrollbars
// appear and disappear, causing the wrap width to change.
{
auto wordWrapWidth = owner.getWordWrapWidth();
@@ -835,9 +856,8 @@ struct TextEditor::TextEditorViewport : public Viewport
{
lastWordWrapWidth = wordWrapWidth;
rentrant = true;
owner.updateTextHolderSize();
rentrant = false;
ScopedValueSetter<bool> svs (reentrant, true);
owner.checkLayout();
}
}
}
@@ -845,7 +865,7 @@ struct TextEditor::TextEditorViewport : public Viewport
private:
TextEditor& owner;
float lastWordWrapWidth = 0;
bool rentrant = false;
bool reentrant = false;
JUCE_DECLARE_NON_COPYABLE (TextEditorViewport)
};
@@ -936,8 +956,8 @@ void TextEditor::setMultiLine (const bool shouldBeMultiLine,
multiline = shouldBeMultiLine;
wordWrap = shouldWordWrap && shouldBeMultiLine;
viewport->setScrollBarsShown (scrollbarVisible && multiline,
scrollbarVisible && multiline);
checkLayout();
viewport->setViewPosition (0, 0);
resized();
scrollToMakeSureCursorIsVisible();
@@ -954,8 +974,7 @@ void TextEditor::setScrollbarsShown (bool shown)
if (scrollbarVisible != shown)
{
scrollbarVisible = shown;
shown = shown && isMultiLine();
viewport->setScrollBarsShown (shown, shown);
checkLayout();
}
}
@@ -1003,7 +1022,9 @@ void TextEditor::setJustification (Justification j)
if (justification != j)
{
justification = j;
resized();
repaint();
}
}
@@ -1028,7 +1049,7 @@ void TextEditor::applyFontToAllText (const Font& newFont, bool changeCurrentFont
}
coalesceSimilarSections();
updateTextHolderSize();
checkLayout();
scrollToMakeSureCursorIsVisible();
repaint();
}
@@ -1090,8 +1111,13 @@ void TextEditor::recreateCaret()
void TextEditor::updateCaretPosition()
{
if (caret != nullptr)
caret->setCaretPosition (getCaretRectangle().translated (leftIndent, topIndent));
if (caret != nullptr
&& getWidth() > 0 && getHeight() > 0)
{
Iterator i (*this);
caret->setCaretPosition (getCaretRectangle().translated (leftIndent,
topIndent + roundToInt (i.getYOffset())));
}
}
TextEditor::LengthAndCharacterRestriction::LengthAndCharacterRestriction (int maxLen, const String& chars)
@@ -1146,7 +1172,7 @@ void TextEditor::setScrollBarThickness (int newThicknessPixels)
void TextEditor::clear()
{
clearInternal (nullptr);
updateTextHolderSize();
checkLayout();
undoManager.clearUndoHistory();
}
@@ -1181,7 +1207,7 @@ void TextEditor::setText (const String& newText, bool sendTextChangeMessage)
else
textValue.addListener (textHolder);
updateTextHolderSize();
checkLayout();
scrollToMakeSureCursorIsVisible();
undoManager.clearUndoHistory();
@@ -1214,7 +1240,7 @@ void TextEditor::textWasChangedByValue()
//==============================================================================
void TextEditor::textChanged()
{
updateTextHolderSize();
checkLayout();
if (listeners.size() != 0 || onTextChange != nullptr)
postCommandMessage (TextEditorDefs::textChangeMessageId);
@@ -1259,30 +1285,33 @@ void TextEditor::repaintText (Range<int> range)
{
if (! range.isEmpty())
{
auto lh = currentFont.getHeight();
auto wordWrapWidth = getWordWrapWidth();
if (wordWrapWidth > 0)
if (range.getEnd() >= getTotalNumChars())
{
Point<float> anchor;
Iterator i (*this);
i.getCharPosition (range.getStart(), anchor, lh);
textHolder->repaint();
return;
}
auto y1 = (int) anchor.y;
int y2;
Iterator i (*this);
if (range.getEnd() >= getTotalNumChars())
{
y2 = textHolder->getHeight();
}
else
{
i.getCharPosition (range.getEnd(), anchor, lh);
y2 = (int) (anchor.y + lh * 2.0f);
}
Point<float> anchor;
auto lh = currentFont.getHeight();
i.getCharPosition (range.getStart(), anchor, lh);
auto y1 = (int) anchor.y;
int y2;
textHolder->repaint (0, y1, textHolder->getWidth(), y2 - y1);
if (range.getEnd() >= getTotalNumChars())
{
y2 = textHolder->getHeight();
}
else
{
i.getCharPosition (range.getEnd(), anchor, lh);
y2 = (int) (anchor.y + lh * 2.0f);
}
auto offset = i.getYOffset();
textHolder->repaint (0, roundToInt (y1 + offset), textHolder->getWidth(), roundToInt (y2 - y1 + offset));
}
}
@@ -1367,33 +1396,66 @@ Rectangle<float> TextEditor::getCaretRectangleFloat() const
}
//==============================================================================
enum { rightEdgeSpace = 2 };
// Extra space for the cursor at the right-hand-edge
constexpr int rightEdgeSpace = 2;
float TextEditor::getWordWrapWidth() const
{
return wordWrap ? getJustificationWidth()
return wordWrap ? getMaximumWidth()
: std::numeric_limits<float>::max();
}
float TextEditor::getJustificationWidth() const
float TextEditor::getMaximumWidth() const
{
return (float) (viewport->getMaximumVisibleWidth() - (leftIndent + rightEdgeSpace + 1));
}
void TextEditor::updateTextHolderSize()
float TextEditor::getMaximumHeight() const
{
return (float) (viewport->getMaximumVisibleHeight() - topIndent);
}
void TextEditor::checkLayout()
{
if (getWordWrapWidth() > 0)
{
float maxWidth = getJustificationWidth();
auto maxWidth = getMaximumWidth();
Iterator i (*this);
while (i.next())
maxWidth = jmax (maxWidth, i.atomRight);
auto w = leftIndent + roundToInt (maxWidth);
auto h = topIndent + roundToInt (jmax (i.lineY + i.lineHeight, currentFont.getHeight()));
auto textRight = roundToInt (maxWidth);
auto textBottom = roundToInt (i.lineY + i.lineHeight + i.getYOffset());
if (i.atom != nullptr && i.atom->isNewLine())
textBottom += (int) i.lineHeight;
textHolder->setSize (w + rightEdgeSpace, h + 1); // (allows a bit of space for the cursor to be at the right-hand-edge)
updateTextHolderSize (textRight, textBottom);
updateScrollbarVisibility (textRight, textBottom);
}
}
void TextEditor::updateTextHolderSize (int textRight, int textBottom)
{
auto w = leftIndent + jmax (roundToInt (getMaximumWidth()), textRight);
auto h = topIndent + textBottom;
textHolder->setSize (w + rightEdgeSpace, h + 1);
}
void TextEditor::updateScrollbarVisibility (int textRight, int textBottom)
{
if (scrollbarVisible && multiline)
{
auto horizontalVisible = (leftIndent + textRight) > (viewport->getMaximumVisibleWidth() - viewport->getScrollBarThickness());
auto verticalVisible = (topIndent + textBottom) > (viewport->getMaximumVisibleHeight() + 1);
viewport->setScrollBarsShown (verticalVisible, horizontalVisible);
}
else
{
viewport->setScrollBarsShown (false, false);
}
}
@@ -1402,8 +1464,14 @@ int TextEditor::getTextHeight() const { return textHolder->getHeight(); }
void TextEditor::setIndents (int newLeftIndent, int newTopIndent)
{
leftIndent = newLeftIndent;
topIndent = newTopIndent;
if (leftIndent != newLeftIndent || topIndent != newTopIndent)
{
leftIndent = newLeftIndent;
topIndent = newTopIndent;
resized();
repaint();
}
}
void TextEditor::setBorder (BorderSize<int> border)
@@ -1506,8 +1574,10 @@ void TextEditor::moveCaretTo (const int newPosition, const bool isSelecting)
int TextEditor::getTextIndexAt (const int x, const int y)
{
Iterator i (*this);
return indexAtPosition ((float) (x + viewport->getViewPositionX() - leftIndent - borderSize.getLeft()),
(float) (y + viewport->getViewPositionY() - topIndent - borderSize.getTop()));
(float) (y + viewport->getViewPositionY() - topIndent - borderSize.getTop() - i.getYOffset()));
}
void TextEditor::insertTextAtCaret (const String& t)
@@ -1576,8 +1646,23 @@ void TextEditor::drawContent (Graphics& g)
{
g.setOrigin (leftIndent, topIndent);
auto clip = g.getClipBounds();
Colour selectedTextColour;
auto yOffset = [this]()
{
Iterator i (*this);
return i.getYOffset();
}();
AffineTransform transform;
if (yOffset > 0)
{
transform = AffineTransform::translation (0.0f, yOffset);
clip.setY (roundToInt (clip.getY() - yOffset));
}
Iterator i (*this);
Colour selectedTextColour;
if (! selection.isEmpty())
{
@@ -1593,10 +1678,10 @@ void TextEditor::drawContent (Graphics& g)
}
}
g.setColour (findColour (highlightColourId).withMultipliedAlpha (hasKeyboardFocus (true) ? 1.0f : 0.5f));
g.fillRectList (selectionArea);
selectedTextColour = findColour (highlightedTextColourId);
g.setColour (findColour (highlightColourId).withMultipliedAlpha (hasKeyboardFocus (true) ? 1.0f : 0.5f));
g.fillPath (selectionArea.toPath(), transform);
}
const UniformTextSection* lastSection = nullptr;
@@ -1607,12 +1692,12 @@ void TextEditor::drawContent (Graphics& g)
{
if (selection.intersects ({ i.indexInText, i.indexInText + i.atom->numChars }))
{
i.drawSelectedText (g, selection, selectedTextColour);
i.drawSelectedText (g, selection, selectedTextColour, transform);
lastSection = nullptr;
}
else
{
i.draw (g, lastSection);
i.draw (g, lastSection, transform);
}
}
}
@@ -1626,7 +1711,7 @@ void TextEditor::drawContent (Graphics& g)
if (i2.lineY + i2.lineHeight >= (float) clip.getY()
&& underlinedSection.intersects ({ i2.indexInText, i2.indexInText + i2.atom->numChars }))
{
i2.drawUnderline (g, underlinedSection, findColour (textColourId));
i2.drawUnderline (g, underlinedSection, findColour (textColourId), transform);
}
}
}
@@ -1647,13 +1732,10 @@ void TextEditor::paintOverChildren (Graphics& g)
g.setColour (colourForTextWhenEmpty);
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);
g.drawText (textToShowWhenEmpty,
leftIndent, topIndent,
viewport->getWidth() - leftIndent, getHeight() - topIndent,
justification, true);
}
getLookAndFeel().drawTextEditorOutline (g, getWidth(), getHeight(), *this);
@@ -2095,7 +2177,7 @@ void TextEditor::resized()
viewport->setBoundsInset (borderSize);
viewport->setSingleStepSizes (16, roundToInt (currentFont.getHeight()));
updateTextHolderSize();
checkLayout();
if (isMultiLine())
updateCaretPosition();
@@ -2213,7 +2295,7 @@ void TextEditor::insert (const String& text, int insertIndex, const Font& font,
totalNumChars = -1;
valueTextNeedsUpdating = true;
updateTextHolderSize();
checkLayout();
moveCaretTo (caretPositionToMoveTo, false);
repaintText ({ insertIndex, getTotalNumChars() });
@@ -2426,7 +2508,7 @@ void TextEditor::getCharPosition (int index, Point<float>& anchor, float& lineHe
if (sections.isEmpty())
{
anchor = { i.getJustificationOffset (0), 0 };
anchor = { i.getJustificationOffsetX (0), 0 };
lineHeight = currentFont.getHeight();
}
else


+ 10
- 6
modules/juce_gui_basics/widgets/juce_TextEditor.h View File

@@ -155,7 +155,6 @@ public:
*/
bool areScrollbarsShown() const noexcept { return scrollbarVisible; }
/** Changes the password character used to disguise the text.
@param passwordCharacter if this is not zero, this character will be used as a replacement
@@ -172,7 +171,6 @@ public:
*/
juce_wchar getPasswordCharacter() const noexcept { return passwordCharacter; }
//==============================================================================
/** Allows a right-click menu to appear for the editor.
@@ -495,9 +493,12 @@ public:
*/
void setScrollToShowCursor (bool shouldScrollToShowCaret);
/** Modifies the horizontal justification of the text within the editor window. */
/** Modifies the justification of the text within the editor window. */
void setJustification (Justification newJustification);
/** Returns the type of justification, as set in setJustification(). */
Justification getJustificationType() const noexcept { return justification; }
/** Sets the line spacing of the TextEditor.
The default (and minimum) value is 1.0 and values > 1.0 will increase the line spacing as a
multiple of the line height e.g. for double-spacing call this method with an argument of 2.0.
@@ -712,7 +713,7 @@ private:
std::unique_ptr<Viewport> viewport;
TextHolderComponent* textHolder;
BorderSize<int> borderSize { 1, 1, 1, 3 };
Justification justification { Justification::left };
Justification justification { Justification::topLeft };
bool readOnly = false;
bool caretVisible = true;
@@ -778,9 +779,12 @@ private:
int findWordBreakBefore (int position) const;
bool moveCaretWithTransaction (int newPos, bool selecting);
void drawContent (Graphics&);
void updateTextHolderSize();
void checkLayout();
void updateTextHolderSize (int, int);
void updateScrollbarVisibility (int, int);
float getWordWrapWidth() const;
float getJustificationWidth() const;
float getMaximumWidth() const;
float getMaximumHeight() const;
void timerCallbackInt();
void checkFocus();
void repaintText (Range<int>);


Loading…
Cancel
Save