2 ==============================================================================
4 This file is part of the JUCE library - "Jules' Utility Class Extensions"
5 Copyright 2004-11 by Raw Material Software Ltd.
7 ------------------------------------------------------------------------------
9 JUCE can be redistributed and/or modified under the terms of the GNU General
10 Public License (Version 2), as published by the Free Software Foundation.
11 A copy of the license is included in the JUCE distribution, or can be found
12 online at www.gnu.org/licenses.
14 JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 ------------------------------------------------------------------------------
20 To release a closed-source product which uses JUCE, commercial licenses are
21 available: visit www.rawmaterialsoftware.com/juce for more information.
23 ==============================================================================
26 #include "../../../core/juce_StandardHeader.h"
30 #include "juce_Label.h"
31 #include "../lookandfeel/juce_LookAndFeel.h"
32 #include "../windows/juce_ComponentPeer.h"
33 #include "../keyboard/juce_CaretComponent.h"
36 //==============================================================================
37 Label::Label (const String
& name
,
38 const String
& labelText
)
40 textValue (labelText
),
41 lastTextValue (labelText
),
43 justification (Justification::centredLeft
),
44 horizontalBorderSize (5),
45 verticalBorderSize (1),
46 minimumHorizontalScale (0.7f
),
47 editSingleClick (false),
48 editDoubleClick (false),
49 lossOfFocusDiscardsChanges (false)
51 setColour (TextEditor::textColourId
, Colours::black
);
52 setColour (TextEditor::backgroundColourId
, Colours::transparentBlack
);
53 setColour (TextEditor::outlineColourId
, Colours::transparentBlack
);
55 textValue
.addListener (this);
60 textValue
.removeListener (this);
62 if (ownerComponent
!= nullptr)
63 ownerComponent
->removeComponentListener (this);
68 //==============================================================================
69 void Label::setText (const String
& newText
,
70 const bool broadcastChangeMessage
)
74 if (lastTextValue
!= newText
)
76 lastTextValue
= newText
;
82 if (ownerComponent
!= nullptr)
83 componentMovedOrResized (*ownerComponent
, true, true);
85 if (broadcastChangeMessage
)
86 callChangeListeners();
90 String
Label::getText (const bool returnActiveEditorContents
) const
92 return (returnActiveEditorContents
&& isBeingEdited())
94 : textValue
.toString();
97 void Label::valueChanged (Value
&)
99 if (lastTextValue
!= textValue
.toString())
100 setText (textValue
.toString(), true);
103 //==============================================================================
104 void Label::setFont (const Font
& newFont
)
113 const Font
& Label::getFont() const noexcept
118 void Label::setEditable (const bool editOnSingleClick
,
119 const bool editOnDoubleClick
,
120 const bool lossOfFocusDiscardsChanges_
)
122 editSingleClick
= editOnSingleClick
;
123 editDoubleClick
= editOnDoubleClick
;
124 lossOfFocusDiscardsChanges
= lossOfFocusDiscardsChanges_
;
126 setWantsKeyboardFocus (editOnSingleClick
|| editOnDoubleClick
);
127 setFocusContainer (editOnSingleClick
|| editOnDoubleClick
);
130 void Label::setJustificationType (const Justification
& newJustification
)
132 if (justification
!= newJustification
)
134 justification
= newJustification
;
139 void Label::setBorderSize (int h
, int v
)
141 if (horizontalBorderSize
!= h
|| verticalBorderSize
!= v
)
143 horizontalBorderSize
= h
;
144 verticalBorderSize
= v
;
149 //==============================================================================
150 Component
* Label::getAttachedComponent() const
152 return static_cast<Component
*> (ownerComponent
);
155 void Label::attachToComponent (Component
* owner
,
158 if (ownerComponent
!= nullptr)
159 ownerComponent
->removeComponentListener (this);
161 ownerComponent
= owner
;
163 leftOfOwnerComp
= onLeft
;
165 if (ownerComponent
!= nullptr)
167 setVisible (owner
->isVisible());
168 ownerComponent
->addComponentListener (this);
169 componentParentHierarchyChanged (*ownerComponent
);
170 componentMovedOrResized (*ownerComponent
, true, true);
174 void Label::componentMovedOrResized (Component
& component
, bool /*wasMoved*/, bool /*wasResized*/)
178 setSize (jmin (getFont().getStringWidth (textValue
.toString()) + 8, component
.getX()),
179 component
.getHeight());
181 setTopRightPosition (component
.getX(), component
.getY());
185 setSize (component
.getWidth(),
186 8 + roundToInt (getFont().getHeight()));
188 setTopLeftPosition (component
.getX(), component
.getY() - getHeight());
192 void Label::componentParentHierarchyChanged (Component
& component
)
194 if (component
.getParentComponent() != nullptr)
195 component
.getParentComponent()->addChildComponent (this);
198 void Label::componentVisibilityChanged (Component
& component
)
200 setVisible (component
.isVisible());
203 //==============================================================================
204 void Label::textWasEdited()
208 void Label::textWasChanged()
212 void Label::showEditor()
214 if (editor
== nullptr)
216 addAndMakeVisible (editor
= createEditorComponent());
217 editor
->setText (getText(), false);
218 editor
->addListener (this);
219 editor
->grabKeyboardFocus();
220 editor
->setHighlightedRegion (Range
<int> (0, textValue
.toString().length()));
221 editor
->addListener (this);
226 editorShown (editor
);
228 enterModalState (false);
229 editor
->grabKeyboardFocus();
233 void Label::editorShown (TextEditor
*)
237 void Label::editorAboutToBeHidden (TextEditor
*)
241 bool Label::updateFromTextEditorContents (TextEditor
& ed
)
243 const String
newText (ed
.getText());
245 if (textValue
.toString() != newText
)
247 lastTextValue
= newText
;
253 if (ownerComponent
!= nullptr)
254 componentMovedOrResized (*ownerComponent
, true, true);
262 void Label::hideEditor (const bool discardCurrentEditorContents
)
264 if (editor
!= nullptr)
266 WeakReference
<Component
> deletionChecker (this);
268 ScopedPointer
<TextEditor
> outgoingEditor (editor
);
270 editorAboutToBeHidden (outgoingEditor
);
272 const bool changed
= (! discardCurrentEditorContents
)
273 && updateFromTextEditorContents (*outgoingEditor
);
274 outgoingEditor
= nullptr;
280 if (deletionChecker
!= nullptr)
283 if (changed
&& deletionChecker
!= nullptr)
284 callChangeListeners();
288 void Label::inputAttemptWhenModal()
290 if (editor
!= nullptr)
292 if (lossOfFocusDiscardsChanges
)
293 textEditorEscapeKeyPressed (*editor
);
295 textEditorReturnKeyPressed (*editor
);
299 bool Label::isBeingEdited() const noexcept
301 return editor
!= nullptr;
304 TextEditor
* Label::createEditorComponent()
306 TextEditor
* const ed
= new TextEditor (getName());
309 // copy these colours from our own settings..
310 const int cols
[] = { TextEditor::backgroundColourId
,
311 TextEditor::textColourId
,
312 TextEditor::highlightColourId
,
313 TextEditor::highlightedTextColourId
,
314 TextEditor::outlineColourId
,
315 TextEditor::focusedOutlineColourId
,
316 TextEditor::shadowColourId
,
317 CaretComponent::caretColourId
};
319 for (int i
= 0; i
< numElementsInArray (cols
); ++i
)
320 ed
->setColour (cols
[i
], findColour (cols
[i
]));
325 //==============================================================================
326 void Label::paint (Graphics
& g
)
328 getLookAndFeel().drawLabel (g
, *this);
331 void Label::mouseUp (const MouseEvent
& e
)
334 && e
.mouseWasClicked()
335 && contains (e
.getPosition())
336 && ! e
.mods
.isPopupMenu())
342 void Label::mouseDoubleClick (const MouseEvent
& e
)
344 if (editDoubleClick
&& ! e
.mods
.isPopupMenu())
348 void Label::resized()
350 if (editor
!= nullptr)
351 editor
->setBoundsInset (BorderSize
<int> (0));
354 void Label::focusGained (FocusChangeType cause
)
356 if (editSingleClick
&& cause
== focusChangedByTabKey
)
360 void Label::enablementChanged()
365 void Label::colourChanged()
370 void Label::setMinimumHorizontalScale (const float newScale
)
372 if (minimumHorizontalScale
!= newScale
)
374 minimumHorizontalScale
= newScale
;
379 //==============================================================================
380 // We'll use a custom focus traverser here to make sure focus goes from the
381 // text editor to another component rather than back to the label itself.
382 class LabelKeyboardFocusTraverser
: public KeyboardFocusTraverser
385 LabelKeyboardFocusTraverser() {}
387 Component
* getNextComponent (Component
* current
)
389 return KeyboardFocusTraverser::getNextComponent (dynamic_cast <TextEditor
*> (current
) != nullptr
390 ? current
->getParentComponent() : current
);
393 Component
* getPreviousComponent (Component
* current
)
395 return KeyboardFocusTraverser::getPreviousComponent (dynamic_cast <TextEditor
*> (current
) != nullptr
396 ? current
->getParentComponent() : current
);
400 KeyboardFocusTraverser
* Label::createFocusTraverser()
402 return new LabelKeyboardFocusTraverser();
405 //==============================================================================
406 void Label::addListener (LabelListener
* const listener
)
408 listeners
.add (listener
);
411 void Label::removeListener (LabelListener
* const listener
)
413 listeners
.remove (listener
);
416 void Label::callChangeListeners()
418 Component::BailOutChecker
checker (this);
419 listeners
.callChecked (checker
, &LabelListener::labelTextChanged
, this); // (can't use Label::Listener due to idiotic VC2005 bug)
422 //==============================================================================
423 void Label::textEditorTextChanged (TextEditor
& ed
)
425 if (editor
!= nullptr)
427 jassert (&ed
== editor
);
429 if (! (hasKeyboardFocus (true) || isCurrentlyBlockedByAnotherModalComponent()))
431 if (lossOfFocusDiscardsChanges
)
432 textEditorEscapeKeyPressed (ed
);
434 textEditorReturnKeyPressed (ed
);
439 void Label::textEditorReturnKeyPressed (TextEditor
& ed
)
441 if (editor
!= nullptr)
443 jassert (&ed
== editor
);
445 const bool changed
= updateFromTextEditorContents (ed
);
450 WeakReference
<Component
> deletionChecker (this);
453 if (deletionChecker
!= nullptr)
454 callChangeListeners();
459 void Label::textEditorEscapeKeyPressed (TextEditor
& ed
)
461 if (editor
!= nullptr)
463 jassert (&ed
== editor
);
466 editor
->setText (textValue
.toString(), false);
471 void Label::textEditorFocusLost (TextEditor
& ed
)
473 textEditorTextChanged (ed
);