JUCE-7.0.12-0-g4f43011b96 JUCE-7.0.12-0-g4f43011b96
JUCE — C++ application framework with suport for VST, VST3, LV2 audio plug-ins

« « « Anklang Documentation
Loading...
Searching...
No Matches
juce_Component.cpp
Go to the documentation of this file.
1 /*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 By using JUCE, you agree to the terms of both the JUCE 7 End-User License
11 Agreement and JUCE Privacy Policy.
12
13 End User License Agreement: www.juce.com/juce-7-licence
14 Privacy Policy: www.juce.com/juce-privacy-policy
15
16 Or: You may also use this code under the terms of the GPL v3 (see
17 www.gnu.org/licenses).
18
19 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
20 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
21 DISCLAIMED.
22
23 ==============================================================================
24*/
25
26#define JUCE_ASSERT_MESSAGE_MANAGER_IS_LOCKED_OR_OFFSCREEN \
27 jassert ((MessageManager::getInstanceWithoutCreating() != nullptr \
28 && MessageManager::getInstanceWithoutCreating()->currentThreadHasLockedMessageManager()) \
29 || getPeer() == nullptr);
30
31namespace juce
32{
33
34static Component* findFirstEnabledAncestor (Component* in)
35{
36 if (in == nullptr)
37 return nullptr;
38
39 if (in->isEnabled())
40 return in;
41
42 return findFirstEnabledAncestor (in->getParentComponent());
43}
44
45Component* Component::currentlyFocusedComponent = nullptr;
46
47//==============================================================================
49{
50public:
52 : me (originalEvent)
53 {
54 for (; comp != nullptr; comp = comp->getParentComponent())
55 hierarchy.emplace_back (comp);
56 }
57
58 Component* nearestNonNullParent() const
59 {
60 for (auto& comp : hierarchy)
61 if (comp != nullptr)
62 return comp;
63
64 return nullptr;
65 }
66
67 bool shouldBailOut() const
68 {
69 return nearestNonNullParent() == nullptr;
70 }
71
72 MouseEvent eventWithNearestParent() const
73 {
74 auto* comp = nearestNonNullParent();
75 return { me.source,
76 me.position.toFloat(),
77 me.mods,
78 me.pressure, me.orientation, me.rotation,
79 me.tiltX, me.tiltY,
80 comp, comp,
81 me.eventTime,
86 }
87
88private:
90 const MouseEvent me;
91};
92
93//==============================================================================
95{
96public:
97 MouseListenerList() noexcept {}
98
100 {
101 if (! listeners.contains (newListener))
102 {
104 {
105 listeners.insert (0, newListener);
106 ++numDeepMouseListeners;
107 }
108 else
109 {
110 listeners.add (newListener);
111 }
112 }
113 }
114
115 void removeListener (MouseListener* listenerToRemove)
116 {
117 auto index = listeners.indexOf (listenerToRemove);
118
119 if (index >= 0)
120 {
121 if (index < numDeepMouseListeners)
122 --numDeepMouseListeners;
123
124 listeners.remove (index);
125 }
126 }
127
128 template <typename EventMethod, typename... Params>
129 static void sendMouseEvent (HierarchyChecker& checker, EventMethod&& eventMethod, Params&&... params)
130 {
131 const auto callListeners = [&] (auto& parentComp, const auto findNumListeners)
132 {
133 if (auto* list = parentComp.mouseListeners.get())
134 {
135 const WeakReference safePointer { &parentComp };
136
137 for (int i = findNumListeners (*list); --i >= 0; i = jmin (i, findNumListeners (*list)))
138 {
139 (list->listeners.getUnchecked (i)->*eventMethod) (checker.eventWithNearestParent(), params...);
140
141 if (checker.shouldBailOut() || safePointer == nullptr)
142 return false;
143 }
144 }
145
146 return true;
147 };
148
149 if (auto* parent = checker.nearestNonNullParent())
150 if (! callListeners (*parent, [] (auto& list) { return list.listeners.size(); }))
151 return;
152
153 if (auto* parent = checker.nearestNonNullParent())
154 for (Component* p = parent->parentComponent; p != nullptr; p = p->parentComponent)
155 if (! callListeners (*p, [] (auto& list) { return list.numDeepMouseListeners; }))
156 return;
157 }
158
159private:
160 Array<MouseListener*> listeners;
161 int numDeepMouseListeners = 0;
162
164};
165
166//==============================================================================
168 : componentFlags (0)
169{
170}
171
172Component::Component (const String& name) noexcept
173 : componentName (name), componentFlags (0)
174{
175}
176
178{
179 static_assert (sizeof (flags) <= sizeof (componentFlags), "componentFlags has too many bits!");
180
181 componentListeners.call ([this] (ComponentListener& l) { l.componentBeingDeleted (*this); });
182
183 while (childComponentList.size() > 0)
184 removeChildComponent (childComponentList.size() - 1, false, true);
185
186 masterReference.clear();
187
188 if (parentComponent != nullptr)
189 parentComponent->removeChildComponent (parentComponent->childComponentList.indexOf (this), true, false);
190 else
192
193 if (flags.hasHeavyweightPeerFlag)
195
196 // Something has added some children to this component during its destructor! Not a smart idea!
197 jassert (childComponentList.size() == 0);
198}
199
200//==============================================================================
201void Component::setName (const String& name)
202{
203 // if component methods are being called from threads other than the message
204 // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
205 JUCE_ASSERT_MESSAGE_MANAGER_IS_LOCKED_OR_OFFSCREEN
206
207 if (componentName != name)
208 {
209 componentName = name;
210
211 if (flags.hasHeavyweightPeerFlag)
212 if (auto* peer = getPeer())
213 peer->setTitle (name);
214
215 BailOutChecker checker (this);
216 componentListeners.callChecked (checker, [this] (ComponentListener& l) { l.componentNameChanged (*this); });
217 }
218}
219
224
226{
227 if (flags.visibleFlag != shouldBeVisible)
228 {
229 // if component methods are being called from threads other than the message
230 // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
231 JUCE_ASSERT_MESSAGE_MANAGER_IS_LOCKED_OR_OFFSCREEN
232
233 const WeakReference<Component> safePointer (this);
234 flags.visibleFlag = shouldBeVisible;
235
236 if (shouldBeVisible)
237 repaint();
238 else
240
242
243 if (! shouldBeVisible)
244 {
245 detail::ComponentHelpers::releaseAllCachedImageResources (*this);
246
247 if (hasKeyboardFocus (true))
248 {
249 if (parentComponent != nullptr)
250 parentComponent->grabKeyboardFocus();
251
252 // ensure that keyboard focus is given away if it wasn't taken by parent
254 }
255 }
256
257 if (safePointer != nullptr)
258 {
260
261 if (safePointer != nullptr && flags.hasHeavyweightPeerFlag)
262 {
263 if (auto* peer = getPeer())
264 {
265 peer->setVisible (shouldBeVisible);
267 }
268 }
269 }
270 }
271}
272
274
275void Component::sendVisibilityChangeMessage()
276{
277 BailOutChecker checker (this);
279
280 if (! checker.shouldBailOut())
281 componentListeners.callChecked (checker, [this] (ComponentListener& l) { l.componentVisibilityChanged (*this); });
282}
283
285{
286 if (! flags.visibleFlag)
287 return false;
288
289 if (parentComponent != nullptr)
290 return parentComponent->isShowing();
291
292 if (auto* peer = getPeer())
293 return ! peer->isMinimised();
294
295 return false;
296}
297
298//==============================================================================
300{
301 if (auto* peer = getPeer())
302 return peer->getNativeHandle();
303
304 return nullptr;
305}
306
307//==============================================================================
309{
310 // if component methods are being called from threads other than the message
311 // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
313
314 if (isOpaque())
315 styleWanted &= ~ComponentPeer::windowIsSemiTransparent;
316 else
318
319 // don't use getPeer(), so that we only get the peer that's specifically
320 // for this comp, and not for one of its parents.
321 auto* peer = ComponentPeer::getPeerFor (this);
322
323 if (peer == nullptr || styleWanted != peer->getStyleFlags())
324 {
325 const WeakReference<Component> safePointer (this);
326
327 #if JUCE_LINUX || JUCE_BSD
328 // it's wise to give the component a non-zero size before
329 // putting it on the desktop, as X windows get confused by this, and
330 // a (1, 1) minimum size is enforced here.
331 setSize (jmax (1, getWidth()),
332 jmax (1, getHeight()));
333 #endif
334
335 const auto unscaledPosition = detail::ScalingHelpers::scaledScreenPosToUnscaled (getScreenPosition());
336 const auto topLeft = detail::ScalingHelpers::unscaledScreenPosToScaled (*this, unscaledPosition);
337
338 bool wasFullscreen = false;
339 bool wasMinimised = false;
342 int oldRenderingEngine = -1;
343
344 if (peer != nullptr)
345 {
347
348 wasFullscreen = peer->isFullScreen();
349 wasMinimised = peer->isMinimised();
350 currentConstrainer = peer->getConstrainer();
351 oldNonFullScreenBounds = peer->getNonFullScreenBounds();
352 oldRenderingEngine = peer->getCurrentRenderingEngine();
353
354 flags.hasHeavyweightPeerFlag = false;
355 Desktop::getInstance().removeDesktopComponent (this);
356 internalHierarchyChanged(); // give comps a chance to react to the peer change before the old peer is deleted.
357
358 if (safePointer == nullptr)
359 return;
360
361 setTopLeftPosition (topLeft);
362 }
363
364 if (parentComponent != nullptr)
365 parentComponent->removeChildComponent (this);
366
367 if (safePointer != nullptr)
368 {
369 flags.hasHeavyweightPeerFlag = true;
370
371 peer = createNewPeer (styleWanted, nativeWindowToAttachTo);
372
373 Desktop::getInstance().addDesktopComponent (this);
374
375 boundsRelativeToParent.setPosition (topLeft);
376 peer->updateBounds();
377
378 if (oldRenderingEngine >= 0)
379 peer->setCurrentRenderingEngine (oldRenderingEngine);
380
381 peer->setVisible (isVisible());
382
383 peer = ComponentPeer::getPeerFor (this);
384
385 if (peer == nullptr)
386 return;
387
388 if (wasFullscreen)
389 {
390 peer->setFullScreen (true);
391 peer->setNonFullScreenBounds (oldNonFullScreenBounds);
392 }
393
394 if (wasMinimised)
395 peer->setMinimised (true);
396
397 #if JUCE_WINDOWS
398 if (isAlwaysOnTop())
399 peer->setAlwaysOnTop (true);
400 #endif
401
402 peer->setConstrainer (currentConstrainer);
403
404 repaint();
405
406 #if JUCE_LINUX
407 // Creating the peer Image on Linux will change the reported position of the window. If
408 // the Image creation is interleaved with the coming configureNotifyEvents the window
409 // will appear in the wrong position. To avoid this, we force the Image creation here,
410 // before handling any of the configureNotifyEvents. The Linux implementation of
411 // performAnyPendingRepaintsNow() will force update the peer position if necessary.
412 peer->performAnyPendingRepaintsNow();
413 #endif
414
416
417 if (auto* handler = getAccessibilityHandler())
418 detail::AccessibilityHelpers::notifyAccessibilityEvent (*handler, detail::AccessibilityHelpers::Event::windowOpened);
419 }
420 }
421}
422
424{
425 // if component methods are being called from threads other than the message
426 // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
427 JUCE_ASSERT_MESSAGE_MANAGER_IS_LOCKED_OR_OFFSCREEN
428
429 if (flags.hasHeavyweightPeerFlag)
430 {
431 if (auto* handler = getAccessibilityHandler())
432 detail::AccessibilityHelpers::notifyAccessibilityEvent (*handler, detail::AccessibilityHelpers::Event::windowClosed);
433
434 detail::ComponentHelpers::releaseAllCachedImageResources (*this);
435
436 auto* peer = ComponentPeer::getPeerFor (this);
437 jassert (peer != nullptr);
438
439 flags.hasHeavyweightPeerFlag = false;
440 delete peer;
441
442 Desktop::getInstance().removeDesktopComponent (this);
443 }
444}
445
447{
448 return flags.hasHeavyweightPeerFlag;
449}
450
452{
453 if (flags.hasHeavyweightPeerFlag)
454 return ComponentPeer::getPeerFor (this);
455
456 if (parentComponent == nullptr)
457 return nullptr;
458
459 return parentComponent->getPeer();
460}
461
463{
464 /* This means that the user's trying to get rid of your window with the 'close window' system
465 menu option (on windows) or possibly the task manager - you should really handle this
466 and delete or hide your component in an appropriate way.
467
468 If you want to ignore the event and don't want to trigger this assertion, just override
469 this method and do nothing.
470 */
472}
473
475
477
478//==============================================================================
480{
481 if (shouldBeOpaque != flags.opaqueFlag)
482 {
483 flags.opaqueFlag = shouldBeOpaque;
484
485 if (flags.hasHeavyweightPeerFlag)
486 if (auto* peer = ComponentPeer::getPeerFor (this))
487 addToDesktop (peer->getStyleFlags()); // recreates the heavyweight window
488
489 repaint();
490 }
491}
492
494{
495 return flags.opaqueFlag;
496}
497
498//==============================================================================
500{
501 StandardCachedComponentImage (Component& c) noexcept : owner (c) {}
502
503 void paint (Graphics& g) override
504 {
505 scale = g.getInternalContext().getPhysicalPixelScaleFactor();
506 auto compBounds = owner.getLocalBounds();
507 auto imageBounds = compBounds * scale;
508
509 if (image.isNull() || image.getBounds() != imageBounds)
510 {
511 image = Image (owner.isOpaque() ? Image::RGB
512 : Image::ARGB,
513 jmax (1, imageBounds.getWidth()),
514 jmax (1, imageBounds.getHeight()),
515 ! owner.isOpaque());
516
517 validArea.clear();
518 }
519
520 if (! validArea.containsRectangle (compBounds))
521 {
522 Graphics imG (image);
523 auto& lg = imG.getInternalContext();
524
525 lg.addTransform (AffineTransform::scale (scale));
526
527 for (auto& i : validArea)
528 lg.excludeClipRectangle (i);
529
530 if (! owner.isOpaque())
531 {
532 lg.setFill (Colours::transparentBlack);
533 lg.fillRect (compBounds, true);
534 lg.setFill (Colours::black);
535 }
536
537 owner.paintEntireComponent (imG, true);
538 }
539
540 validArea = compBounds;
541
542 g.setColour (Colours::black.withAlpha (owner.getAlpha()));
543 g.drawImageTransformed (image, AffineTransform::scale ((float) compBounds.getWidth() / (float) imageBounds.getWidth(),
544 (float) compBounds.getHeight() / (float) imageBounds.getHeight()), false);
545 }
546
547 bool invalidateAll() override { validArea.clear(); return true; }
548 bool invalidate (const Rectangle<int>& area) override { validArea.subtract (area); return true; }
549 void releaseResources() override { image = Image(); }
550
551private:
552 Image image;
553 RectangleList<int> validArea;
554 Component& owner;
555 float scale = 1.0f;
556
558};
559
568
570{
571 // This assertion means that this component is already using a custom CachedComponentImage,
572 // so by calling setBufferedToImage, you'll be deleting the custom one - this is almost certainly
573 // not what you wanted to happen... If you really do know what you're doing here, and want to
574 // avoid this assertion, just call setCachedComponentImage (nullptr) before setBufferedToImage().
575 jassert (cachedImage == nullptr || dynamic_cast<StandardCachedComponentImage*> (cachedImage.get()) != nullptr);
576
578 {
579 if (cachedImage == nullptr)
580 cachedImage.reset (new StandardCachedComponentImage (*this));
581 }
582 else
583 {
584 cachedImage.reset();
585 }
586}
587
588//==============================================================================
589void Component::reorderChildInternal (int sourceIndex, int destIndex)
590{
591 if (sourceIndex != destIndex)
592 {
593 auto* c = childComponentList.getUnchecked (sourceIndex);
594 jassert (c != nullptr);
595 c->repaintParent();
596
598
601 }
602}
603
605{
606 // if component methods are being called from threads other than the message
607 // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
608 JUCE_ASSERT_MESSAGE_MANAGER_IS_LOCKED_OR_OFFSCREEN
609
610 if (flags.hasHeavyweightPeerFlag)
611 {
612 if (auto* peer = getPeer())
613 {
614 peer->toFront (shouldGrabKeyboardFocus);
615
618 }
619 }
620 else if (parentComponent != nullptr)
621 {
622 auto& childList = parentComponent->childComponentList;
623
624 if (childList.getLast() != this)
625 {
626 auto index = childList.indexOf (this);
627
628 if (index >= 0)
629 {
630 int insertIndex = -1;
631
632 if (! flags.alwaysOnTopFlag)
633 {
634 insertIndex = childList.size() - 1;
635
636 while (insertIndex > 0 && childList.getUnchecked (insertIndex)->isAlwaysOnTop())
637 --insertIndex;
638 }
639
640 parentComponent->reorderChildInternal (index, insertIndex);
641 }
642 }
643
645 {
647
648 if (isShowing())
650 }
651 }
652}
653
655{
656 if (other != nullptr && other != this)
657 {
658 // the two components must belong to the same parent..
659 jassert (parentComponent == other->parentComponent);
660
661 if (parentComponent != nullptr)
662 {
663 auto& childList = parentComponent->childComponentList;
664 auto index = childList.indexOf (this);
665
666 if (index >= 0 && childList [index + 1] != other)
667 {
668 auto otherIndex = childList.indexOf (other);
669
670 if (otherIndex >= 0)
671 {
672 if (index < otherIndex)
673 --otherIndex;
674
675 parentComponent->reorderChildInternal (index, otherIndex);
676 }
677 }
678 }
679 else if (isOnDesktop())
680 {
681 jassert (other->isOnDesktop());
682
683 if (other->isOnDesktop())
684 {
685 auto* us = getPeer();
686 auto* them = other->getPeer();
687 jassert (us != nullptr && them != nullptr);
688
689 if (us != nullptr && them != nullptr)
690 us->toBehind (them);
691 }
692 }
693 }
694}
695
697{
698 if (isOnDesktop())
699 {
700 jassertfalse; //xxx need to add this to native window
701 }
702 else if (parentComponent != nullptr)
703 {
704 auto& childList = parentComponent->childComponentList;
705
706 if (childList.getFirst() != this)
707 {
708 auto index = childList.indexOf (this);
709
710 if (index > 0)
711 {
712 int insertIndex = 0;
713
714 if (flags.alwaysOnTopFlag)
715 while (insertIndex < childList.size() && ! childList.getUnchecked (insertIndex)->isAlwaysOnTop())
716 ++insertIndex;
717
718 parentComponent->reorderChildInternal (index, insertIndex);
719 }
720 }
721 }
722}
723
725{
726 if (shouldStayOnTop != flags.alwaysOnTopFlag)
727 {
728 BailOutChecker checker (this);
729
730 flags.alwaysOnTopFlag = shouldStayOnTop;
731
732 if (isOnDesktop())
733 {
734 if (auto* peer = getPeer())
735 {
736 if (! peer->setAlwaysOnTop (shouldStayOnTop))
737 {
738 // some kinds of peer can't change their always-on-top status, so
739 // for these, we'll need to create a new window
740 auto oldFlags = peer->getStyleFlags();
743 }
744 }
745 }
746
747 if (shouldStayOnTop && ! checker.shouldBailOut())
748 toFront (false);
749
750 if (! checker.shouldBailOut())
752 }
753}
754
756{
757 return flags.alwaysOnTopFlag;
758}
759
760//==============================================================================
761int Component::proportionOfWidth (float proportion) const noexcept { return roundToInt (proportion * (float) boundsRelativeToParent.getWidth()); }
762int Component::proportionOfHeight (float proportion) const noexcept { return roundToInt (proportion * (float) boundsRelativeToParent.getHeight()); }
763
765{
766 return parentComponent != nullptr ? parentComponent->getWidth()
768}
769
771{
772 return parentComponent != nullptr ? parentComponent->getHeight()
774}
775
780
785
786Point<int> Component::getLocalPoint (const Component* source, Point<int> point) const { return detail::ComponentHelpers::convertCoordinate (this, source, point); }
787Point<float> Component::getLocalPoint (const Component* source, Point<float> point) const { return detail::ComponentHelpers::convertCoordinate (this, source, point); }
788Rectangle<int> Component::getLocalArea (const Component* source, Rectangle<int> area) const { return detail::ComponentHelpers::convertCoordinate (this, source, area); }
789Rectangle<float> Component::getLocalArea (const Component* source, Rectangle<float> area) const { return detail::ComponentHelpers::convertCoordinate (this, source, area); }
790
791Point<int> Component::localPointToGlobal (Point<int> point) const { return detail::ComponentHelpers::convertCoordinate (nullptr, this, point); }
792Point<float> Component::localPointToGlobal (Point<float> point) const { return detail::ComponentHelpers::convertCoordinate (nullptr, this, point); }
793Rectangle<int> Component::localAreaToGlobal (Rectangle<int> area) const { return detail::ComponentHelpers::convertCoordinate (nullptr, this, area); }
794Rectangle<float> Component::localAreaToGlobal (Rectangle<float> area) const { return detail::ComponentHelpers::convertCoordinate (nullptr, this, area); }
795
796//==============================================================================
797void Component::setBounds (int x, int y, int w, int h)
798{
799 // if component methods are being called from threads other than the message
800 // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
801 JUCE_ASSERT_MESSAGE_MANAGER_IS_LOCKED_OR_OFFSCREEN
802
803 if (w < 0) w = 0;
804 if (h < 0) h = 0;
805
806 const bool wasResized = (getWidth() != w || getHeight() != h);
807 const bool wasMoved = (getX() != x || getY() != y);
808
809 #if JUCE_DEBUG
810 // It's a very bad idea to try to resize a window during its paint() method!
811 jassert (! (flags.isInsidePaintCall && wasResized && isOnDesktop()));
812 #endif
813
814 if (wasMoved || wasResized)
815 {
816 const bool showing = isShowing();
817
818 if (showing)
819 {
820 // send a fake mouse move to trigger enter/exit messages if needed..
822
823 if (! flags.hasHeavyweightPeerFlag)
825 }
826
827 boundsRelativeToParent.setBounds (x, y, w, h);
828
829 if (showing)
830 {
831 if (wasResized)
832 repaint();
833 else if (! flags.hasHeavyweightPeerFlag)
835 }
836 else if (cachedImage != nullptr)
837 {
838 cachedImage->invalidateAll();
839 }
840
841 flags.isMoveCallbackPending = wasMoved;
842 flags.isResizeCallbackPending = wasResized;
843
844 if (flags.hasHeavyweightPeerFlag)
845 if (auto* peer = getPeer())
846 peer->updateBounds();
847
849 }
850}
851
852void Component::sendMovedResizedMessagesIfPending()
853{
854 const bool wasMoved = flags.isMoveCallbackPending;
855 const bool wasResized = flags.isResizeCallbackPending;
856
857 if (wasMoved || wasResized)
858 {
859 flags.isMoveCallbackPending = false;
860 flags.isResizeCallbackPending = false;
861
863 }
864}
865
866void Component::sendMovedResizedMessages (bool wasMoved, bool wasResized)
867{
868 BailOutChecker checker (this);
869
870 if (wasMoved)
871 {
872 moved();
873
874 if (checker.shouldBailOut())
875 return;
876 }
877
878 if (wasResized)
879 {
880 resized();
881
882 if (checker.shouldBailOut())
883 return;
884
885 for (int i = childComponentList.size(); --i >= 0;)
886 {
887 childComponentList.getUnchecked (i)->parentSizeChanged();
888
889 if (checker.shouldBailOut())
890 return;
891
892 i = jmin (i, childComponentList.size());
893 }
894 }
895
896 if (parentComponent != nullptr)
897 parentComponent->childBoundsChanged (this);
898
899 if (! checker.shouldBailOut())
900 {
901 componentListeners.callChecked (checker, [this, wasMoved, wasResized] (ComponentListener& l)
902 {
903 l.componentMovedOrResized (*this, wasMoved, wasResized);
904 });
905 }
906
907 if ((wasMoved || wasResized) && ! checker.shouldBailOut())
908 if (auto* handler = getAccessibilityHandler())
909 detail::AccessibilityHelpers::notifyAccessibilityEvent (*handler, detail::AccessibilityHelpers::Event::elementMovedOrResized);
910}
911
912void Component::setSize (int w, int h) { setBounds (getX(), getY(), w, h); }
913
914void Component::setTopLeftPosition (int x, int y) { setTopLeftPosition ({ x, y }); }
916
919
921void Component::setCentrePosition (int x, int y) { setCentrePosition ({ x, y }); }
922
923void Component::setCentreRelative (float x, float y)
924{
926 roundToInt ((float) getParentHeight() * y));
927}
928
930{
931 setBounds ((target * Point<float> ((float) getParentWidth(),
932 (float) getParentHeight())).toNearestInt());
933}
934
935void Component::setBoundsRelative (float x, float y, float w, float h)
936{
937 setBoundsRelative ({ x, y, w, h });
938}
939
940void Component::centreWithSize (int width, int height)
941{
942 auto parentArea = detail::ComponentHelpers::getParentOrMainMonitorBounds (*this)
943 .transformedBy (getTransform().inverted());
944
945 setBounds (parentArea.getCentreX() - width / 2,
946 parentArea.getCentreY() - height / 2,
947 width, height);
948}
949
951{
952 setBounds (borders.subtractedFrom (detail::ComponentHelpers::getParentOrMainMonitorBounds (*this)));
953}
954
955void Component::setBoundsToFit (Rectangle<int> targetArea, Justification justification, bool onlyReduceInSize)
956{
957 if (getLocalBounds().isEmpty() || targetArea.isEmpty())
958 {
959 // it's no good calling this method unless both the component and
960 // target rectangle have a finite size.
962 return;
963 }
964
965 auto sourceArea = targetArea.withZeroOrigin();
966
967 if (onlyReduceInSize
968 && getWidth() <= targetArea.getWidth()
969 && getHeight() <= targetArea.getHeight())
970 {
972 }
973 else
974 {
975 auto sourceRatio = getHeight() / (double) getWidth();
976 auto targetRatio = targetArea.getHeight() / (double) targetArea.getWidth();
977
979 sourceArea.setHeight (jmin (targetArea.getHeight(),
980 roundToInt (targetArea.getWidth() * sourceRatio)));
981 else
982 sourceArea.setWidth (jmin (targetArea.getWidth(),
983 roundToInt (targetArea.getHeight() / sourceRatio)));
984 }
985
986 if (! sourceArea.isEmpty())
987 setBounds (justification.appliedToRectangle (sourceArea, targetArea));
988}
989
990//==============================================================================
992{
993 // If you pass in a transform with no inverse, the component will have no dimensions,
994 // and there will be all sorts of maths errors when converting coordinates.
995 jassert (! newTransform.isSingularity());
996
997 if (newTransform.isIdentity())
998 {
999 if (affineTransform != nullptr)
1000 {
1001 repaint();
1002 affineTransform.reset();
1003 repaint();
1004 sendMovedResizedMessages (false, false);
1005 }
1006 }
1007 else if (affineTransform == nullptr)
1008 {
1009 repaint();
1011 repaint();
1012 sendMovedResizedMessages (false, false);
1013 }
1014 else if (*affineTransform != newTransform)
1015 {
1016 repaint();
1018 repaint();
1019 sendMovedResizedMessages (false, false);
1020 }
1021}
1022
1024{
1025 return affineTransform != nullptr;
1026}
1027
1032
1034{
1035 AffineTransform transform;
1036
1037 for (auto* target = targetComponent; target != nullptr; target = target->getParentComponent())
1038 {
1039 transform = transform.followedBy (target->getTransform());
1040
1041 if (target->isOnDesktop())
1042 transform = transform.scaled (target->getDesktopScaleFactor());
1043 }
1044
1045 auto transformScale = std::sqrt (std::abs (transform.getDeterminant()));
1047}
1048
1049//==============================================================================
1050bool Component::hitTest (int x, int y)
1051{
1052 if (! flags.ignoresMouseClicksFlag)
1053 return true;
1054
1055 if (flags.allowChildMouseClicksFlag)
1056 {
1057 for (int i = childComponentList.size(); --i >= 0;)
1058 {
1059 auto& child = *childComponentList.getUnchecked (i);
1060
1061 if (child.isVisible()
1062 && detail::ComponentHelpers::hitTest (child, detail::ComponentHelpers::convertFromParentSpace (child, Point<int> (x, y).toFloat())))
1063 return true;
1064 }
1065 }
1066
1067 return false;
1068}
1069
1071 bool allowClicksOnChildComponents) noexcept
1072{
1073 flags.ignoresMouseClicksFlag = ! allowClicks;
1074 flags.allowChildMouseClicksFlag = allowClicksOnChildComponents;
1075}
1076
1078 bool& allowsClicksOnChildComponents) const noexcept
1079{
1080 allowsClicksOnThisComponent = ! flags.ignoresMouseClicksFlag;
1081 allowsClicksOnChildComponents = flags.allowChildMouseClicksFlag;
1082}
1083
1085{
1086 return contains (point.toFloat());
1087}
1088
1090{
1091 if (detail::ComponentHelpers::hitTest (*this, point))
1092 {
1093 if (parentComponent != nullptr)
1094 return parentComponent->contains (detail::ComponentHelpers::convertToParentSpace (*this, point));
1095
1096 if (flags.hasHeavyweightPeerFlag)
1097 if (auto* peer = getPeer())
1098 return peer->contains (detail::ComponentHelpers::localPositionToRawPeerPos (*this, point).roundToInt(), true);
1099 }
1100
1101 return false;
1102}
1103
1108
1110{
1111 if (! contains (point))
1112 return false;
1113
1114 auto* top = getTopLevelComponent();
1115 auto* compAtPosition = top->getComponentAt (top->getLocalPoint (this, point));
1116
1118}
1119
1121{
1122 return getComponentAt (position.toFloat());
1123}
1124
1126{
1127 if (flags.visibleFlag && detail::ComponentHelpers::hitTest (*this, position))
1128 {
1129 for (int i = childComponentList.size(); --i >= 0;)
1130 {
1131 auto* child = childComponentList.getUnchecked (i);
1132
1133 child = child->getComponentAt (detail::ComponentHelpers::convertFromParentSpace (*child, position));
1134
1135 if (child != nullptr)
1136 return child;
1137 }
1138
1139 return this;
1140 }
1141
1142 return nullptr;
1143}
1144
1146{
1147 return getComponentAt (Point<int> { x, y });
1148}
1149
1150//==============================================================================
1152{
1153 // if component methods are being called from threads other than the message
1154 // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
1155 JUCE_ASSERT_MESSAGE_MANAGER_IS_LOCKED_OR_OFFSCREEN
1156
1157 jassert (this != &child); // adding a component to itself!?
1158
1159 if (child.parentComponent != this)
1160 {
1161 if (child.parentComponent != nullptr)
1162 child.parentComponent->removeChildComponent (&child);
1163 else
1164 child.removeFromDesktop();
1165
1166 child.parentComponent = this;
1167
1168 if (child.isVisible())
1169 child.repaintParent();
1170
1171 if (! child.isAlwaysOnTop())
1172 {
1174 zOrder = childComponentList.size();
1175
1176 while (zOrder > 0)
1177 {
1178 if (! childComponentList.getUnchecked (zOrder - 1)->isAlwaysOnTop())
1179 break;
1180
1181 --zOrder;
1182 }
1183 }
1184
1185 childComponentList.insert (zOrder, &child);
1186
1187 child.internalHierarchyChanged();
1189 }
1190}
1191
1193{
1194 child.setVisible (true);
1195 addChildComponent (child, zOrder);
1196}
1197
1199{
1200 if (child != nullptr)
1201 addChildComponent (*child, zOrder);
1202}
1203
1205{
1206 if (child != nullptr)
1207 addAndMakeVisible (*child, zOrder);
1208}
1209
1211{
1212 if (child != nullptr)
1213 {
1214 child->setComponentID (childID);
1215 addAndMakeVisible (child);
1216 }
1217}
1218
1220{
1221 removeChildComponent (childComponentList.indexOf (child), true, true);
1222}
1223
1225{
1226 return removeChildComponent (index, true, true);
1227}
1228
1230{
1231 // if component methods are being called from threads other than the message
1232 // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
1233 JUCE_ASSERT_MESSAGE_MANAGER_IS_LOCKED_OR_OFFSCREEN
1234
1235 if (auto* child = childComponentList [index])
1236 {
1237 sendParentEvents = sendParentEvents && child->isShowing();
1238
1239 if (sendParentEvents)
1240 {
1242
1243 if (child->isVisible())
1244 child->repaintParent();
1245 }
1246
1247 childComponentList.remove (index);
1248 child->parentComponent = nullptr;
1249
1250 detail::ComponentHelpers::releaseAllCachedImageResources (*child);
1251
1252 // (NB: there are obscure situations where child->isShowing() = false, but it still has the focus)
1253 if (child->hasKeyboardFocus (true))
1254 {
1256
1257 child->giveAwayKeyboardFocusInternal (sendChildEvents || currentlyFocusedComponent != child);
1258
1259 if (sendParentEvents)
1260 {
1261 if (safeThis == nullptr)
1262 return child;
1263
1265 }
1266 }
1267
1268 if (sendChildEvents)
1269 child->internalHierarchyChanged();
1270
1271 if (sendParentEvents)
1273
1274 return child;
1275 }
1276
1277 return nullptr;
1278}
1279
1280//==============================================================================
1282{
1283 while (! childComponentList.isEmpty())
1285}
1286
1288{
1289 while (! childComponentList.isEmpty())
1290 delete (removeChildComponent (childComponentList.size() - 1));
1291}
1292
1294{
1295 return childComponentList.size();
1296}
1297
1298Component* Component::getChildComponent (int index) const noexcept
1299{
1300 return childComponentList[index];
1301}
1302
1303int Component::getIndexOfChildComponent (const Component* child) const noexcept
1304{
1305 return childComponentList.indexOf (const_cast<Component*> (child));
1306}
1307
1309{
1310 for (auto* c : childComponentList)
1311 if (c->componentID == targetID)
1312 return c;
1313
1314 return nullptr;
1315}
1316
1318{
1319 auto* comp = this;
1320
1321 while (comp->parentComponent != nullptr)
1322 comp = comp->parentComponent;
1323
1324 return const_cast<Component*> (comp);
1325}
1326
1328{
1329 while (possibleChild != nullptr)
1330 {
1331 possibleChild = possibleChild->parentComponent;
1332
1333 if (possibleChild == this)
1334 return true;
1335 }
1336
1337 return false;
1338}
1339
1340//==============================================================================
1343
1344void Component::internalChildrenChanged()
1345{
1346 if (componentListeners.isEmpty())
1347 {
1349 }
1350 else
1351 {
1352 BailOutChecker checker (this);
1353
1355
1356 if (! checker.shouldBailOut())
1357 componentListeners.callChecked (checker, [this] (ComponentListener& l) { l.componentChildrenChanged (*this); });
1358 }
1359}
1360
1361void Component::internalHierarchyChanged()
1362{
1363 BailOutChecker checker (this);
1364
1366
1367 if (checker.shouldBailOut())
1368 return;
1369
1370 componentListeners.callChecked (checker, [this] (ComponentListener& l) { l.componentParentHierarchyChanged (*this); });
1371
1372 if (checker.shouldBailOut())
1373 return;
1374
1375 for (int i = childComponentList.size(); --i >= 0;)
1376 {
1377 childComponentList.getUnchecked (i)->internalHierarchyChanged();
1378
1379 if (checker.shouldBailOut())
1380 {
1381 // you really shouldn't delete the parent component during a callback telling you
1382 // that it's changed..
1384 return;
1385 }
1386
1387 i = jmin (i, childComponentList.size());
1388 }
1389
1390 if (flags.hasHeavyweightPeerFlag)
1391 if (auto* handler = getAccessibilityHandler())
1392 handler->notifyAccessibilityEvent (AccessibilityEvent::structureChanged);
1393}
1394
1395//==============================================================================
1396#if JUCE_MODAL_LOOPS_PERMITTED
1397int Component::runModalLoop()
1398{
1399 if (! MessageManager::getInstance()->isThisTheMessageThread())
1400 {
1401 // use a callback so this can be called from non-gui threads
1403 ->callFunctionOnMessageThread (&detail::ComponentHelpers::runModalLoopCallback, this);
1404 }
1405
1406 if (! isCurrentlyModal (false))
1407 enterModalState (true);
1408
1409 return ModalComponentManager::getInstance()->runEventLoopForCurrentComponent();
1410}
1411#endif
1412
1413//==============================================================================
1417{
1418 // if component methods are being called from threads other than the message
1419 // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
1421
1422 SafePointer safeReference { this };
1423
1424 if (! isCurrentlyModal (false))
1425 {
1426 // While this component is in modal state it may block other components from receiving
1427 // mouseExit events. To keep mouseEnter and mouseExit calls balanced on these components,
1428 // we must manually force the mouse to "leave" blocked components.
1429 detail::ComponentHelpers::sendMouseEventToComponentsThatAreBlockedByModal (*this, &Component::internalMouseExit);
1430
1431 if (safeReference == nullptr)
1432 {
1433 // If you hit this assertion, the mouse-exit event above has caused the modal component to be deleted.
1435 return;
1436 }
1437
1438 auto& mcm = *ModalComponentManager::getInstance();
1439 mcm.startModal (this, deleteWhenDismissed);
1440 mcm.attachCallback (this, callback);
1441
1442 setVisible (true);
1443
1446 }
1447 else
1448 {
1449 // Probably a bad idea to try to make a component modal twice!
1451 }
1452}
1453
1454void Component::exitModalState (int returnValue)
1455{
1457
1458 if (isCurrentlyModal (false))
1459 {
1460 if (MessageManager::getInstance()->isThisTheMessageThread())
1461 {
1462 auto& mcm = *ModalComponentManager::getInstance();
1463 mcm.endModal (this, returnValue);
1464 mcm.bringModalComponentsToFront();
1465
1466 // While this component is in modal state it may block other components from receiving
1467 // mouseEnter events. To keep mouseEnter and mouseExit calls balanced on these components,
1468 // we must manually force the mouse to "enter" blocked components.
1469 if (deletionChecker != nullptr)
1470 detail::ComponentHelpers::sendMouseEventToComponentsThatAreBlockedByModal (*deletionChecker, &Component::internalMouseEnter);
1471 }
1472 else
1473 {
1474 MessageManager::callAsync ([target = WeakReference<Component> { this }, returnValue]
1475 {
1476 if (target != nullptr)
1477 target->exitModalState (returnValue);
1478 });
1479 }
1480 }
1481}
1482
1484{
1485 auto& mcm = *ModalComponentManager::getInstance();
1486
1487 return onlyConsiderForemostModalComponent ? mcm.isFrontModalComponent (this)
1488 : mcm.isModal (this);
1489}
1490
1492{
1493 return detail::ComponentHelpers::modalWouldBlockComponent (*this, getCurrentlyModalComponent());
1494}
1495
1497{
1498 return ModalComponentManager::getInstance()->getNumModalComponents();
1499}
1500
1502{
1503 return ModalComponentManager::getInstance()->getModalComponent (index);
1504}
1505
1506//==============================================================================
1508{
1509 flags.bringToFrontOnClickFlag = shouldBeBroughtToFront;
1510}
1511
1513{
1514 return flags.bringToFrontOnClickFlag;
1515}
1516
1517//==============================================================================
1519{
1520 if (cursor != newCursor)
1521 {
1522 cursor = newCursor;
1523
1524 if (flags.visibleFlag)
1526 }
1527}
1528
1530{
1531 return cursor;
1532}
1533
1538
1539//==============================================================================
1541{
1542 flags.repaintOnMouseActivityFlag = shouldRepaint;
1543}
1544
1545//==============================================================================
1547{
1548 return (255 - componentTransparency) / 255.0f;
1549}
1550
1552{
1553 auto newIntAlpha = (uint8) (255 - jlimit (0, 255, roundToInt (newAlpha * 255.0)));
1554
1556 {
1558 alphaChanged();
1559 }
1560}
1561
1563{
1564 if (flags.hasHeavyweightPeerFlag)
1565 {
1566 if (auto* peer = getPeer())
1567 peer->setAlpha (getAlpha());
1568 }
1569 else
1570 {
1571 repaint();
1572 }
1573}
1574
1575//==============================================================================
1580
1581void Component::repaint (int x, int y, int w, int h)
1582{
1583 internalRepaint ({ x, y, w, h });
1584}
1585
1587{
1588 internalRepaint (area);
1589}
1590
1591void Component::repaintParent()
1592{
1593 if (parentComponent != nullptr)
1594 parentComponent->internalRepaint (detail::ComponentHelpers::convertToParentSpace (*this, getLocalBounds()));
1595}
1596
1597void Component::internalRepaint (Rectangle<int> area)
1598{
1599 area = area.getIntersection (getLocalBounds());
1600
1601 if (! area.isEmpty())
1602 internalRepaintUnchecked (area, false);
1603}
1604
1605void Component::internalRepaintUnchecked (Rectangle<int> area, bool isEntireComponent)
1606{
1607 // if component methods are being called from threads other than the message
1608 // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
1610
1611 if (flags.visibleFlag)
1612 {
1613 if (cachedImage != nullptr)
1614 if (! (isEntireComponent ? cachedImage->invalidateAll()
1615 : cachedImage->invalidate (area)))
1616 return;
1617
1618 if (area.isEmpty())
1619 return;
1620
1621 if (flags.hasHeavyweightPeerFlag)
1622 {
1623 if (auto* peer = getPeer())
1624 {
1625 // Tweak the scaling so that the component's integer size exactly aligns with the peer's scaled size
1626 auto peerBounds = peer->getBounds();
1627 auto scaled = area * Point<float> ((float) peerBounds.getWidth() / (float) getWidth(),
1628 (float) peerBounds.getHeight() / (float) getHeight());
1629
1630 peer->repaint (affineTransform != nullptr ? scaled.transformedBy (*affineTransform) : scaled);
1631 }
1632 }
1633 else
1634 {
1635 if (parentComponent != nullptr)
1636 parentComponent->internalRepaint (detail::ComponentHelpers::convertToParentSpace (*this, area));
1637 }
1638 }
1639}
1640
1641//==============================================================================
1643{
1644 // if your component is marked as opaque, you must implement a paint
1645 // method and ensure that its entire area is completely painted.
1646 jassert (getBounds().isEmpty() || ! isOpaque());
1647}
1648
1650{
1651 // all painting is done in the subclasses
1652}
1653
1654//==============================================================================
1655void Component::paintWithinParentContext (Graphics& g)
1656{
1657 g.setOrigin (getPosition());
1658
1659 if (cachedImage != nullptr)
1660 cachedImage->paint (g);
1661 else
1662 paintEntireComponent (g, false);
1663}
1664
1665void Component::paintComponentAndChildren (Graphics& g)
1666{
1667 auto clipBounds = g.getClipBounds();
1668
1669 if (flags.dontClipGraphicsFlag && getNumChildComponents() == 0)
1670 {
1671 paint (g);
1672 }
1673 else
1674 {
1675 Graphics::ScopedSaveState ss (g);
1676
1677 if (! (detail::ComponentHelpers::clipObscuredRegions (*this, g, clipBounds, {}) && g.isClipEmpty()))
1678 paint (g);
1679 }
1680
1681 for (int i = 0; i < childComponentList.size(); ++i)
1682 {
1683 auto& child = *childComponentList.getUnchecked (i);
1684
1685 if (child.isVisible())
1686 {
1687 if (child.affineTransform != nullptr)
1688 {
1689 Graphics::ScopedSaveState ss (g);
1690
1691 g.addTransform (*child.affineTransform);
1692
1693 if ((child.flags.dontClipGraphicsFlag && ! g.isClipEmpty()) || g.reduceClipRegion (child.getBounds()))
1694 child.paintWithinParentContext (g);
1695 }
1696 else if (clipBounds.intersects (child.getBounds()))
1697 {
1698 Graphics::ScopedSaveState ss (g);
1699
1700 if (child.flags.dontClipGraphicsFlag)
1701 {
1702 child.paintWithinParentContext (g);
1703 }
1704 else if (g.reduceClipRegion (child.getBounds()))
1705 {
1706 bool nothingClipped = true;
1707
1708 for (int j = i + 1; j < childComponentList.size(); ++j)
1709 {
1710 auto& sibling = *childComponentList.getUnchecked (j);
1711
1712 if (sibling.flags.opaqueFlag && sibling.isVisible() && sibling.affineTransform == nullptr)
1713 {
1714 nothingClipped = false;
1715 g.excludeClipRegion (sibling.getBounds());
1716 }
1717 }
1718
1719 if (nothingClipped || ! g.isClipEmpty())
1720 child.paintWithinParentContext (g);
1721 }
1722 }
1723 }
1724 }
1725
1726 Graphics::ScopedSaveState ss (g);
1728}
1729
1731{
1732 // If sizing a top-level-window and the OS paint message is delivered synchronously
1733 // before resized() is called, then we'll invoke the callback here, to make sure
1734 // the components inside have had a chance to sort their sizes out..
1735 #if JUCE_DEBUG
1736 if (! flags.isInsidePaintCall) // (avoids an assertion in plugins hosted in WaveLab)
1737 #endif
1739
1740 #if JUCE_DEBUG
1741 flags.isInsidePaintCall = true;
1742 #endif
1743
1744 if (effect != nullptr)
1745 {
1746 auto scale = g.getInternalContext().getPhysicalPixelScaleFactor();
1747
1748 auto scaledBounds = getLocalBounds() * scale;
1749
1750 Image effectImage (flags.opaqueFlag ? Image::RGB : Image::ARGB,
1751 scaledBounds.getWidth(), scaledBounds.getHeight(), ! flags.opaqueFlag);
1752 {
1754 g2.addTransform (AffineTransform::scale ((float) scaledBounds.getWidth() / (float) getWidth(),
1755 (float) scaledBounds.getHeight() / (float) getHeight()));
1757 }
1758
1760
1761 g.addTransform (AffineTransform::scale (1.0f / scale));
1762 effect->applyEffect (effectImage, g, scale, ignoreAlphaLevel ? 1.0f : getAlpha());
1763 }
1764 else if (componentTransparency > 0 && ! ignoreAlphaLevel)
1765 {
1766 if (componentTransparency < 255)
1767 {
1771 }
1772 }
1773 else
1774 {
1776 }
1777
1778 #if JUCE_DEBUG
1779 flags.isInsidePaintCall = false;
1780 #endif
1781}
1782
1784{
1785 flags.dontClipGraphicsFlag = shouldPaintWithoutClipping;
1786}
1787
1789{
1790 return flags.dontClipGraphicsFlag;
1791}
1792
1793//==============================================================================
1795 bool clipImageToComponentBounds, float scaleFactor)
1796{
1797 auto r = areaToGrab;
1798
1800 r = r.getIntersection (getLocalBounds());
1801
1802 if (r.isEmpty())
1803 return {};
1804
1805 auto w = roundToInt (scaleFactor * (float) r.getWidth());
1806 auto h = roundToInt (scaleFactor * (float) r.getHeight());
1807
1808 Image image (flags.opaqueFlag ? Image::RGB : Image::ARGB, w, h, true);
1809
1810 Graphics g (image);
1811
1812 if (w != getWidth() || h != getHeight())
1813 g.addTransform (AffineTransform::scale ((float) w / (float) r.getWidth(),
1814 (float) h / (float) r.getHeight()));
1815 g.setOrigin (-r.getPosition());
1816
1817 paintEntireComponent (g, true);
1818
1819 return image;
1820}
1821
1823{
1824 if (effect != newEffect)
1825 {
1826 effect = newEffect;
1827 repaint();
1828 }
1829}
1830
1831//==============================================================================
1833{
1834 for (auto* c = this; c != nullptr; c = c->parentComponent)
1835 if (auto lf = c->lookAndFeel.get())
1836 return *lf;
1837
1839}
1840
1842{
1843 if (lookAndFeel != newLookAndFeel)
1844 {
1845 lookAndFeel = newLookAndFeel;
1847 }
1848}
1849
1852
1854{
1855 const WeakReference<Component> safePointer (this);
1856 repaint();
1858
1859 if (safePointer != nullptr)
1860 {
1861 colourChanged();
1862
1863 if (safePointer != nullptr)
1864 {
1865 for (int i = childComponentList.size(); --i >= 0;)
1866 {
1867 childComponentList.getUnchecked (i)->sendLookAndFeelChange();
1868
1869 if (safePointer == nullptr)
1870 return;
1871
1872 i = jmin (i, childComponentList.size());
1873 }
1874 }
1875 }
1876}
1877
1879{
1880 if (auto* v = properties.getVarPointer (detail::ComponentHelpers::getColourPropertyID (colourID)))
1881 return Colour ((uint32) static_cast<int> (*v));
1882
1883 if (inheritFromParent && parentComponent != nullptr
1884 && (lookAndFeel == nullptr || ! lookAndFeel->isColourSpecified (colourID)))
1885 return parentComponent->findColour (colourID, true);
1886
1887 return getLookAndFeel().findColour (colourID);
1888}
1889
1890bool Component::isColourSpecified (int colourID) const
1891{
1892 return properties.contains (detail::ComponentHelpers::getColourPropertyID (colourID));
1893}
1894
1895void Component::removeColour (int colourID)
1896{
1897 if (properties.remove (detail::ComponentHelpers::getColourPropertyID (colourID)))
1898 colourChanged();
1899}
1900
1901void Component::setColour (int colourID, Colour colour)
1902{
1903 if (properties.set (detail::ComponentHelpers::getColourPropertyID (colourID), (int) colour.getARGB()))
1904 colourChanged();
1905}
1906
1908{
1909 bool changed = false;
1910
1911 for (int i = properties.size(); --i >= 0;)
1912 {
1913 auto name = properties.getName (i);
1914
1915 if (name.toString().startsWith (detail::colourPropertyPrefix))
1916 if (target.properties.set (name, properties [name]))
1917 changed = true;
1918 }
1919
1920 if (changed)
1921 target.colourChanged();
1922}
1923
1924//==============================================================================
1926{
1927}
1928
1930{
1931 return positioner.get();
1932}
1933
1935{
1936 // You can only assign a positioner to the component that it was created for!
1937 jassert (newPositioner == nullptr || this == &(newPositioner->getComponent()));
1938 positioner.reset (newPositioner);
1939}
1940
1941//==============================================================================
1946
1952
1953//==============================================================================
1961
1963{
1964 // the base class just passes this event up to the nearest enabled ancestor
1965 if (auto* enabledComponent = findFirstEnabledAncestor (getParentComponent()))
1967}
1968
1970{
1971 // the base class just passes this event up to the nearest enabled ancestor
1972 if (auto* enabledComponent = findFirstEnabledAncestor (getParentComponent()))
1974}
1975
1976//==============================================================================
1981
1983{
1984 // if component methods are being called from threads other than the message
1985 // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
1986 #if JUCE_DEBUG || JUCE_LOG_ASSERTIONS
1987 if (getParentComponent() != nullptr)
1988 {
1990 }
1991 #endif
1992
1994}
1995
2000
2001//==============================================================================
2003{
2004 ModalComponentManager::getInstance()->bringModalComponentsToFront();
2006}
2007
2009{
2010 return false;
2011}
2012
2013void Component::internalModalInputAttempt()
2014{
2015 if (auto* current = getCurrentlyModalComponent())
2016 current->inputAttemptWhenModal();
2017}
2018
2019//==============================================================================
2021{
2022 MessageManager::callAsync ([target = WeakReference<Component> { this }, commandID]
2023 {
2024 if (target != nullptr)
2025 target->handleCommandMessage (commandID);
2026 });
2027}
2028
2030{
2031 // used by subclasses
2032}
2033
2034//==============================================================================
2037{
2038 // if component methods are being called from threads other than the message
2039 // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
2041
2042 // If you register a component as a mouselistener for itself, it'll receive all the events
2043 // twice - once via the direct callback that all components get anyway, and then again as a listener!
2045
2046 if (mouseListeners == nullptr)
2047 mouseListeners.reset (new MouseListenerList());
2048
2049 mouseListeners->addListener (newListener, wantsEventsForAllNestedChildComponents);
2050}
2051
2053{
2054 // if component methods are being called from threads other than the message
2055 // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
2057
2058 if (mouseListeners != nullptr)
2059 mouseListeners->removeListener (listenerToRemove);
2060}
2061
2062//==============================================================================
2063void Component::internalMouseEnter (MouseInputSource source, Point<float> relativePos, Time time)
2064{
2066 {
2067 // if something else is modal, always just show a normal mouse cursor
2069 return;
2070 }
2071
2072 if (flags.repaintOnMouseActivityFlag)
2073 repaint();
2074
2075 const auto me = makeMouseEvent (source,
2076 detail::PointerState().withPosition (relativePos),
2077 source.getCurrentModifiers(),
2078 this,
2079 this,
2080 time,
2082 time,
2083 0,
2084 false);
2085
2086 HierarchyChecker checker (this, me);
2087 mouseEnter (me);
2088
2089 flags.cachedMouseInsideComponent = true;
2090
2091 if (checker.shouldBailOut())
2092 return;
2093
2094 Desktop::getInstance().getMouseListeners().callChecked (checker, [&] (MouseListener& l) { l.mouseEnter (me); });
2095 MouseListenerList::sendMouseEvent (checker, &MouseListener::mouseEnter);
2096}
2097
2098void Component::internalMouseExit (MouseInputSource source, Point<float> relativePos, Time time)
2099{
2101 {
2102 // if something else is modal, always just show a normal mouse cursor
2103 source.showMouseCursor (MouseCursor::NormalCursor);
2104 return;
2105 }
2106
2107 if (flags.repaintOnMouseActivityFlag)
2108 repaint();
2109
2110 flags.cachedMouseInsideComponent = false;
2111
2112 const auto me = makeMouseEvent (source,
2113 detail::PointerState().withPosition (relativePos),
2114 source.getCurrentModifiers(),
2115 this,
2116 this,
2117 time,
2119 time,
2120 0,
2121 false);
2122
2123 HierarchyChecker checker (this, me);
2124 mouseExit (me);
2125
2126 if (checker.shouldBailOut())
2127 return;
2128
2129 Desktop::getInstance().getMouseListeners().callChecked (checker, [&] (MouseListener& l) { l.mouseExit (me); });
2130 MouseListenerList::sendMouseEvent (checker, &MouseListener::mouseExit);
2131}
2132
2133void Component::internalMouseDown (MouseInputSource source,
2134 const detail::PointerState& relativePointerState,
2135 Time time)
2136{
2137 auto& desktop = Desktop::getInstance();
2138
2139 const auto me = makeMouseEvent (source,
2141 source.getCurrentModifiers(),
2142 this,
2143 this,
2144 time,
2145 relativePointerState.position,
2146 time,
2147 source.getNumberOfMultipleClicks(),
2148 false);
2149
2150 HierarchyChecker checker (this, me);
2151
2153 {
2154 flags.mouseDownWasBlocked = true;
2156
2157 if (checker.shouldBailOut())
2158 return;
2159
2160 // If processing the input attempt has exited the modal loop, we'll allow the event
2161 // to be delivered..
2163 {
2164 // allow blocked mouse-events to go to global listeners..
2165 desktop.getMouseListeners().callChecked (checker, [&] (MouseListener& l) { l.mouseDown (checker.eventWithNearestParent()); });
2166 return;
2167 }
2168 }
2169
2170 flags.mouseDownWasBlocked = false;
2171
2172 for (auto* c = this; c != nullptr; c = c->parentComponent)
2173 {
2174 if (c->isBroughtToFrontOnMouseClick())
2175 {
2176 c->toFront (true);
2177
2178 if (checker.shouldBailOut())
2179 return;
2180 }
2181 }
2182
2183 grabKeyboardFocusInternal (focusChangedByMouseClick, true, FocusChangeDirection::unknown);
2184
2185 if (checker.shouldBailOut())
2186 return;
2187
2188 if (flags.repaintOnMouseActivityFlag)
2189 repaint();
2190
2191 mouseDown (me);
2192
2193 if (checker.shouldBailOut())
2194 return;
2195
2196 desktop.getMouseListeners().callChecked (checker, [&] (MouseListener& l) { l.mouseDown (checker.eventWithNearestParent()); });
2197
2198 MouseListenerList::sendMouseEvent (checker, &MouseListener::mouseDown);
2199}
2200
2201void Component::internalMouseUp (MouseInputSource source,
2202 const detail::PointerState& relativePointerState,
2203 Time time,
2204 const ModifierKeys oldModifiers)
2205{
2206 if (flags.mouseDownWasBlocked && isCurrentlyBlockedByAnotherModalComponent())
2207 return;
2208
2209 const auto me = makeMouseEvent (source,
2212 this,
2213 this,
2214 time,
2215 getLocalPoint (nullptr, source.getLastMouseDownPosition()),
2216 source.getLastMouseDownTime(),
2217 source.getNumberOfMultipleClicks(),
2218 source.isLongPressOrDrag());
2219
2220 HierarchyChecker checker (this, me);
2221
2222 if (flags.repaintOnMouseActivityFlag)
2223 repaint();
2224
2225 mouseUp (me);
2226
2227 if (checker.shouldBailOut())
2228 return;
2229
2230 auto& desktop = Desktop::getInstance();
2231 desktop.getMouseListeners().callChecked (checker, [&] (MouseListener& l) { l.mouseUp (checker.eventWithNearestParent()); });
2232
2233 MouseListenerList::sendMouseEvent (checker, &MouseListener::mouseUp);
2234
2235 if (checker.shouldBailOut())
2236 return;
2237
2238 // check for double-click
2239 if (me.getNumberOfClicks() >= 2)
2240 {
2241 if (checker.nearestNonNullParent() == this)
2242 mouseDoubleClick (checker.eventWithNearestParent());
2243
2244 if (checker.shouldBailOut())
2245 return;
2246
2247 desktop.mouseListeners.callChecked (checker, [&] (MouseListener& l) { l.mouseDoubleClick (checker.eventWithNearestParent()); });
2248 MouseListenerList::sendMouseEvent (checker, &MouseListener::mouseDoubleClick);
2249 }
2250}
2251
2252void Component::internalMouseDrag (MouseInputSource source, const detail::PointerState& relativePointerState, Time time)
2253{
2255 {
2256 const auto me = makeMouseEvent (source,
2258 source.getCurrentModifiers(),
2259 this,
2260 this,
2261 time,
2262 getLocalPoint (nullptr, source.getLastMouseDownPosition()),
2263 source.getLastMouseDownTime(),
2264 source.getNumberOfMultipleClicks(),
2265 source.isLongPressOrDrag());
2266
2267 HierarchyChecker checker (this, me);
2268
2269 mouseDrag (me);
2270
2271 if (checker.shouldBailOut())
2272 return;
2273
2274 Desktop::getInstance().getMouseListeners().callChecked (checker, [&] (MouseListener& l) { l.mouseDrag (checker.eventWithNearestParent()); });
2275 MouseListenerList::sendMouseEvent (checker, &MouseListener::mouseDrag);
2276 }
2277}
2278
2279void Component::internalMouseMove (MouseInputSource source, Point<float> relativePos, Time time)
2280{
2281 auto& desktop = Desktop::getInstance();
2282
2284 {
2285 // allow blocked mouse-events to go to global listeners..
2286 desktop.sendMouseMove();
2287 }
2288 else
2289 {
2290 const auto me = makeMouseEvent (source,
2291 detail::PointerState().withPosition (relativePos),
2292 source.getCurrentModifiers(),
2293 this,
2294 this,
2295 time,
2297 time,
2298 0,
2299 false);
2300
2301 HierarchyChecker checker (this, me);
2302
2303 mouseMove (me);
2304
2305 if (checker.shouldBailOut())
2306 return;
2307
2308 desktop.getMouseListeners().callChecked (checker, [&] (MouseListener& l) { l.mouseMove (checker.eventWithNearestParent()); });
2309 MouseListenerList::sendMouseEvent (checker, &MouseListener::mouseMove);
2310 }
2311}
2312
2313void Component::internalMouseWheel (MouseInputSource source, Point<float> relativePos,
2314 Time time, const MouseWheelDetails& wheel)
2315{
2316 auto& desktop = Desktop::getInstance();
2317
2318 const auto me = makeMouseEvent (source,
2319 detail::PointerState().withPosition (relativePos),
2320 source.getCurrentModifiers(),
2321 this,
2322 this,
2323 time,
2325 time,
2326 0,
2327 false);
2328
2329 HierarchyChecker checker (this, me);
2330
2332 {
2333 // allow blocked mouse-events to go to global listeners..
2334 desktop.mouseListeners.callChecked (checker, [&] (MouseListener& l) { l.mouseWheelMove (me, wheel); });
2335 }
2336 else
2337 {
2338 mouseWheelMove (me, wheel);
2339
2340 if (checker.shouldBailOut())
2341 return;
2342
2343 desktop.mouseListeners.callChecked (checker, [&] (MouseListener& l) { l.mouseWheelMove (checker.eventWithNearestParent(), wheel); });
2344
2345 if (! checker.shouldBailOut())
2346 MouseListenerList::sendMouseEvent (checker, &MouseListener::mouseWheelMove, wheel);
2347 }
2348}
2349
2350void Component::internalMagnifyGesture (MouseInputSource source, Point<float> relativePos,
2351 Time time, float amount)
2352{
2353 auto& desktop = Desktop::getInstance();
2354
2355 const auto me = makeMouseEvent (source,
2356 detail::PointerState().withPosition (relativePos),
2357 source.getCurrentModifiers(),
2358 this,
2359 this,
2360 time,
2362 time,
2363 0,
2364 false);
2365
2366 HierarchyChecker checker (this, me);
2367
2369 {
2370 // allow blocked mouse-events to go to global listeners..
2371 desktop.mouseListeners.callChecked (checker, [&] (MouseListener& l) { l.mouseMagnify (me, amount); });
2372 }
2373 else
2374 {
2375 mouseMagnify (me, amount);
2376
2377 if (checker.shouldBailOut())
2378 return;
2379
2380 desktop.mouseListeners.callChecked (checker, [&] (MouseListener& l) { l.mouseMagnify (checker.eventWithNearestParent(), amount); });
2381
2382 if (! checker.shouldBailOut())
2383 MouseListenerList::sendMouseEvent (checker, &MouseListener::mouseMagnify, amount);
2384 }
2385}
2386
2387void Component::sendFakeMouseMove() const
2388{
2389 if (flags.ignoresMouseClicksFlag && ! flags.allowChildMouseClicksFlag)
2390 return;
2391
2393
2394 if (! mainMouse.isDragging())
2396}
2397
2402
2403//==============================================================================
2405{
2406}
2407
2408void Component::internalBroughtToFront()
2409{
2410 if (flags.hasHeavyweightPeerFlag)
2411 Desktop::getInstance().componentBroughtToFront (this);
2412
2413 BailOutChecker checker (this);
2415
2416 if (checker.shouldBailOut())
2417 return;
2418
2419 componentListeners.callChecked (checker, [this] (ComponentListener& l) { l.componentBroughtToFront (*this); });
2420
2421 if (checker.shouldBailOut())
2422 return;
2423
2424 // When brought to the front and there's a modal component blocking this one,
2425 // we need to bring the modal one to the front instead..
2426 if (auto* cm = getCurrentlyModalComponent())
2427 if (cm->getTopLevelComponent() != getTopLevelComponent())
2428 ModalComponentManager::getInstance()->bringModalComponentsToFront (false); // very important that this is false, otherwise in Windows,
2429 // non-front components can't get focus when another modal comp is
2430 // active, and therefore can't receive mouse-clicks
2431}
2432
2433//==============================================================================
2438
2439void Component::internalKeyboardFocusGain (FocusChangeType cause)
2440{
2441 internalKeyboardFocusGain (cause, WeakReference<Component> (this), FocusChangeDirection::unknown);
2442}
2443
2444void Component::internalKeyboardFocusGain (FocusChangeType cause,
2445 const WeakReference<Component>& safePointer,
2446 FocusChangeDirection direction)
2447{
2448 focusGainedWithDirection (cause, direction);
2450
2451 if (safePointer == nullptr)
2452 return;
2453
2454 if (hasKeyboardFocus (false))
2455 if (auto* handler = getAccessibilityHandler())
2456 handler->grabFocus();
2457
2458 if (safePointer == nullptr)
2459 return;
2460
2462}
2463
2464void Component::internalKeyboardFocusLoss (FocusChangeType cause)
2465{
2466 const WeakReference<Component> safePointer (this);
2467
2468 focusLost (cause);
2469
2470 if (safePointer != nullptr)
2471 {
2472 if (auto* handler = getAccessibilityHandler())
2473 handler->giveAwayFocus();
2474
2476 }
2477}
2478
2479void Component::internalChildKeyboardFocusChange (FocusChangeType cause,
2480 const WeakReference<Component>& safePointer)
2481{
2482 const bool childIsNowKeyboardFocused = hasKeyboardFocus (true);
2483
2484 if (flags.childKeyboardFocusedFlag != childIsNowKeyboardFocused)
2485 {
2486 flags.childKeyboardFocusedFlag = childIsNowKeyboardFocused;
2487
2489
2490 if (safePointer == nullptr)
2491 return;
2492 }
2493
2494 if (parentComponent != nullptr)
2495 parentComponent->internalChildKeyboardFocusChange (cause, parentComponent);
2496}
2497
2498void Component::setWantsKeyboardFocus (bool wantsFocus) noexcept
2499{
2500 flags.wantsKeyboardFocusFlag = wantsFocus;
2501}
2502
2504{
2505 flags.dontFocusOnMouseClickFlag = ! shouldGrabFocus;
2506}
2507
2509{
2510 return ! flags.dontFocusOnMouseClickFlag;
2511}
2512
2514{
2515 return flags.wantsKeyboardFocusFlag && ! flags.isDisabledFlag;
2516}
2517
2519{
2520 flags.isFocusContainerFlag = (containerType == FocusContainerType::focusContainer
2521 || containerType == FocusContainerType::keyboardFocusContainer);
2522
2523 flags.isKeyboardFocusContainerFlag = (containerType == FocusContainerType::keyboardFocusContainer);
2524}
2525
2527{
2528 return flags.isFocusContainerFlag;
2529}
2530
2532{
2533 return flags.isKeyboardFocusContainerFlag;
2534}
2535
2536template <typename FocusContainerFn>
2537static Component* findContainer (const Component* child, FocusContainerFn isFocusContainer)
2538{
2539 if (auto* parent = child->getParentComponent())
2540 {
2541 if ((parent->*isFocusContainer)() || parent->getParentComponent() == nullptr)
2542 return parent;
2543
2544 return findContainer (parent, isFocusContainer);
2545 }
2546
2547 return nullptr;
2548}
2549
2551{
2552 return findContainer (this, &Component::isFocusContainer);
2553}
2554
2556{
2557 return findContainer (this, &Component::isKeyboardFocusContainer);
2558}
2559
2560static const Identifier explicitFocusOrderId ("_jexfo");
2561
2563{
2564 return properties [explicitFocusOrderId];
2565}
2566
2568{
2569 properties.set (explicitFocusOrderId, newFocusOrderIndex);
2570}
2571
2573{
2574 if (flags.isFocusContainerFlag || parentComponent == nullptr)
2575 return std::make_unique<FocusTraverser>();
2576
2577 return parentComponent->createFocusTraverser();
2578}
2579
2581{
2582 if (flags.isKeyboardFocusContainerFlag || parentComponent == nullptr)
2583 return std::make_unique<KeyboardFocusTraverser>();
2584
2585 return parentComponent->createKeyboardFocusTraverser();
2586}
2587
2588void Component::takeKeyboardFocus (FocusChangeType cause, FocusChangeDirection direction)
2589{
2590 if (currentlyFocusedComponent == this)
2591 return;
2592
2593 if (auto* peer = getPeer())
2594 {
2595 const WeakReference<Component> safePointer (this);
2596 peer->grabFocus();
2597
2598 if (! peer->isFocused() || currentlyFocusedComponent == this)
2599 return;
2600
2602
2603 if (auto* losingFocus = componentLosingFocus.get())
2604 if (auto* otherPeer = losingFocus->getPeer())
2605 otherPeer->closeInputMethodContext();
2606
2608
2609 Desktop::getInstance().triggerFocusCallback();
2610
2611 // call this after setting currentlyFocusedComponent so that the one that's
2612 // losing it has a chance to see where focus is going
2613 if (componentLosingFocus != nullptr)
2614 componentLosingFocus->internalKeyboardFocusLoss (cause);
2615
2616 if (currentlyFocusedComponent == this)
2617 internalKeyboardFocusGain (cause, safePointer, direction);
2618 }
2619}
2620
2621void Component::grabKeyboardFocusInternal (FocusChangeType cause, bool canTryParent, FocusChangeDirection direction)
2622{
2623 if (flags.dontFocusOnMouseClickFlag && cause == FocusChangeType::focusChangedByMouseClick)
2624 return;
2625
2626 if (! isShowing())
2627 return;
2628
2629 if (flags.wantsKeyboardFocusFlag
2630 && (isEnabled() || parentComponent == nullptr))
2631 {
2632 takeKeyboardFocus (cause, direction);
2633 return;
2634 }
2635
2637 return;
2638
2640 {
2641 if (auto* defaultComp = traverser->getDefaultComponent (this))
2642 {
2643 defaultComp->grabKeyboardFocusInternal (cause, false, direction);
2644 return;
2645 }
2646 }
2647
2648 // if no children want it and we're allowed to try our parent comp,
2649 // then pass up to parent, which will try our siblings.
2650 if (canTryParent && parentComponent != nullptr)
2651 parentComponent->grabKeyboardFocusInternal (cause, true, direction);
2652}
2653
2655{
2656 // if component methods are being called from threads other than the message
2657 // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
2659
2660 grabKeyboardFocusInternal (focusChangedDirectly, true, FocusChangeDirection::unknown);
2661
2662 // A component can only be focused when it's actually on the screen!
2663 // If this fails then you're probably trying to grab the focus before you've
2664 // added the component to a parent or made it visible. Or maybe one of its parent
2665 // components isn't yet visible.
2666 jassert (isShowing() || isOnDesktop());
2667}
2668
2669void Component::giveAwayKeyboardFocusInternal (bool sendFocusLossEvent)
2670{
2671 if (hasKeyboardFocus (true))
2672 {
2674 {
2675 if (auto* otherPeer = componentLosingFocus->getPeer())
2676 otherPeer->closeInputMethodContext();
2677
2678 currentlyFocusedComponent = nullptr;
2679
2680 if (sendFocusLossEvent && componentLosingFocus != nullptr)
2681 componentLosingFocus->internalKeyboardFocusLoss (focusChangedDirectly);
2682
2683 Desktop::getInstance().triggerFocusCallback();
2684 }
2685 }
2686}
2687
2689{
2690 // if component methods are being called from threads other than the message
2691 // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
2693
2695}
2696
2698{
2699 // if component methods are being called from threads other than the message
2700 // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
2702
2703 if (parentComponent != nullptr)
2704 {
2706 {
2707 auto findComponentToFocus = [&]() -> Component*
2708 {
2709 if (auto* comp = (moveToNext ? traverser->getNextComponent (this)
2710 : traverser->getPreviousComponent (this)))
2711 return comp;
2712
2714 {
2715 auto allFocusableComponents = traverser->getAllComponents (focusContainer);
2716
2717 if (! allFocusableComponents.empty())
2718 return moveToNext ? allFocusableComponents.front()
2719 : allFocusableComponents.back();
2720 }
2721
2722 return nullptr;
2723 };
2724
2725 if (auto* nextComp = findComponentToFocus())
2726 {
2727 if (nextComp->isCurrentlyBlockedByAnotherModalComponent())
2728 {
2731
2732 if (nextCompPointer == nullptr || nextComp->isCurrentlyBlockedByAnotherModalComponent())
2733 return;
2734 }
2735
2736 nextComp->grabKeyboardFocusInternal (focusChangedByTabKey,
2737 true,
2738 moveToNext ? FocusChangeDirection::forward
2739 : FocusChangeDirection::backward);
2740 return;
2741 }
2742 }
2743
2744 parentComponent->moveKeyboardFocusToSibling (moveToNext);
2745 }
2746}
2747
2753
2758
2764
2765//==============================================================================
2767{
2768 return (! flags.isDisabledFlag)
2769 && (parentComponent == nullptr || parentComponent->isEnabled());
2770}
2771
2773{
2774 if (flags.isDisabledFlag == shouldBeEnabled)
2775 {
2776 flags.isDisabledFlag = ! shouldBeEnabled;
2777
2778 // if any parent components are disabled, setting our flag won't make a difference,
2779 // so no need to send a change message
2780 if (parentComponent == nullptr || parentComponent->isEnabled())
2782
2783 BailOutChecker checker (this);
2784 componentListeners.callChecked (checker, [this] (ComponentListener& l) { l.componentEnablementChanged (*this); });
2785
2786 if (! shouldBeEnabled && hasKeyboardFocus (true))
2787 {
2788 if (parentComponent != nullptr)
2789 parentComponent->grabKeyboardFocus();
2790
2791 // ensure that keyboard focus is given away if it wasn't taken by parent
2793 }
2794 }
2795}
2796
2798
2799void Component::sendEnablementChangeMessage()
2800{
2801 const WeakReference<Component> safePointer (this);
2802
2804
2805 if (safePointer == nullptr)
2806 return;
2807
2808 for (int i = getNumChildComponents(); --i >= 0;)
2809 {
2810 if (auto* c = getChildComponent (i))
2811 {
2812 c->sendEnablementChangeMessage();
2813
2814 if (safePointer == nullptr)
2815 return;
2816 }
2817 }
2818}
2819
2820//==============================================================================
2822{
2823 if (! MessageManager::getInstance()->isThisTheMessageThread())
2824 return flags.cachedMouseInsideComponent;
2825
2826 for (auto& ms : Desktop::getInstance().getMouseSources())
2827 {
2828 auto* c = ms.getComponentUnderMouse();
2829
2830 if (c != nullptr && (c == this || (includeChildren && isParentOf (c))))
2831 if (ms.isDragging() || ! (ms.isTouch() || ms.isPen()))
2832 if (c->reallyContains (c->getLocalPoint (nullptr, ms.getScreenPosition()), false))
2833 return true;
2834 }
2835
2836 return false;
2837}
2838
2840{
2841 for (auto& ms : Desktop::getInstance().getMouseSources())
2842 {
2843 auto* c = ms.getComponentUnderMouse();
2844
2845 if (c == this || (includeChildren && isParentOf (c)))
2846 if (ms.isDragging())
2847 return true;
2848 }
2849
2850 return false;
2851}
2852
2854{
2855 for (auto& ms : Desktop::getInstance().getMouseSources())
2856 {
2857 auto* c = ms.getComponentUnderMouse();
2858
2859 if (c == this || (includeChildren && isParentOf (c)))
2860 if (ms.isDragging() || ! ms.isTouch())
2861 return true;
2862 }
2863
2864 return false;
2865}
2866
2871
2873{
2874 return getLocalPoint (nullptr, Desktop::getMousePositionFloat()).roundToInt();
2875}
2876
2877//==============================================================================
2879{
2880 if (keyListeners == nullptr)
2881 keyListeners.reset (new Array<KeyListener*>());
2882
2883 keyListeners->addIfNotAlreadyThere (newListener);
2884}
2885
2887{
2888 if (keyListeners != nullptr)
2889 keyListeners->removeFirstMatchingValue (listenerToRemove);
2890}
2891
2892bool Component::keyPressed (const KeyPress&) { return false; }
2893bool Component::keyStateChanged (bool /*isKeyDown*/) { return false; }
2894
2896{
2897 if (parentComponent != nullptr)
2898 parentComponent->modifierKeysChanged (modifiers);
2899}
2900
2901void Component::internalModifierKeysChanged()
2902{
2905}
2906
2907//==============================================================================
2909 : safePointer (component)
2910{
2911 jassert (component != nullptr);
2912}
2913
2915{
2916 return safePointer == nullptr;
2917}
2918
2919//==============================================================================
2924
2929
2934
2936{
2937 flags.accessibilityIgnoredFlag = ! shouldBeAccessible;
2938
2939 if (flags.accessibilityIgnoredFlag)
2941}
2942
2944{
2945 return (! flags.accessibilityIgnoredFlag
2946 && (parentComponent == nullptr || parentComponent->isAccessible()));
2947}
2948
2950{
2951 return std::make_unique<AccessibilityHandler> (*this, AccessibilityRole::unspecified);
2952}
2953
2954std::unique_ptr<AccessibilityHandler> Component::createIgnoredAccessibilityHandler (Component& comp)
2955{
2956 return std::make_unique<AccessibilityHandler> (comp, AccessibilityRole::ignored);
2957}
2958
2963
2965{
2966 if (! isAccessible() || getWindowHandle() == nullptr)
2967 return nullptr;
2968
2969 if (accessibilityHandler == nullptr
2970 || accessibilityHandler->getTypeIndex() != std::type_index (typeid (*this)))
2971 {
2973
2974 // On Android, notifying that an element was created can cause the system to request
2975 // the accessibility node info for the new element. If we're not careful, this will lead
2976 // to recursive calls, as each time an element is created, new node info will be requested,
2977 // causing an element to be created, causing a new info request...
2978 // By assigning the accessibility handler before notifying the system that an element was
2979 // created, the if() predicate above should evaluate to false on recursive calls,
2980 // terminating the recursion.
2981 if (accessibilityHandler != nullptr)
2982 detail::AccessibilityHelpers::notifyAccessibilityEvent (*accessibilityHandler, detail::AccessibilityHelpers::Event::elementCreated);
2983 else
2984 jassertfalse; // createAccessibilityHandler must return non-null
2985 }
2986
2987 return accessibilityHandler.get();
2988}
2989
2990} // namespace juce
Base class for accessible Components.
Represents a 2D affine-transformation matrix.
static AffineTransform scale(float factorX, float factorY) noexcept
Returns a new transform which is a re-scale about the origin.
Holds a resizable array of primitive or copy-by-value objects.
Definition juce_Array.h:56
void clear()
Removes all elements from the array.
Definition juce_Array.h:188
Specifies a set of gaps to be left around the sides of a rectangle.
Base class used internally for structures that can store cached images of component state.
Represents a colour, also including a transparency value.
Definition juce_Colour.h:38
uint32 getARGB() const noexcept
Returns a 32-bit integer that represents this colour.
A class that imposes restrictions on a Component's size or position.
Gets informed about changes to a component's hierarchy or position.
The Component class uses a ComponentPeer internally to create and manage a real operating-system wind...
@ windowIsSemiTransparent
Not intended for public use - makes a window transparent.
static ComponentPeer * getPeerFor(const Component *) noexcept
Returns the peer that's attached to the given component, or nullptr if there isn't one.
A class to keep an eye on a component and check for it being deleted.
bool shouldBailOut() const noexcept
Returns true if either of the two components have been deleted since this object was created.
BailOutChecker(Component *component)
Creates a checker that watches one component.
Base class for objects that can be used to automatically position a component according to some kind ...
Positioner(Component &component) noexcept
Creates a Positioner which can control the specified component.
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.
bool contains(Point< int > localPoint)
Returns true if a given point lies within this component or one of its children.
virtual void focusLost(FocusChangeType cause)
Called to indicate that this component has just lost the keyboard focus.
void moveKeyboardFocusToSibling(bool moveToNext)
Tries to move the keyboard focus to one of this component's siblings.
void mouseMagnify(const MouseEvent &event, float scaleFactor) override
Called when a pinch-to-zoom mouse-gesture is used.
bool isColourSpecified(int colourID) const
Returns true if the specified colour ID has been explicitly set for this component using the setColou...
void paintEntireComponent(Graphics &context, bool ignoreAlphaLevel)
Draws this component and all its subcomponents onto the specified graphics context.
int proportionOfWidth(float proportion) const noexcept
Returns a proportion of the component's width.
static int JUCE_CALLTYPE getNumCurrentlyModalComponents() noexcept
Returns the number of components that are currently in a modal state.
void setLookAndFeel(LookAndFeel *newLookAndFeel)
Sets the look and feel to use for this component.
Rectangle< int > getBoundsInParent() const noexcept
Returns the area of this component's parent which this component covers.
AffineTransform getTransform() const
Returns the transform that is currently being applied to this component.
void deleteAllChildren()
Removes and deletes all of this component's children.
Component * findChildWithID(StringRef componentID) const noexcept
Looks for a child component with the specified ID.
void mouseDrag(const MouseEvent &event) override
Called when the mouse is moved while a button is held down.
void setTransform(const AffineTransform &transform)
Sets a transform matrix to be applied to this component.
bool isMouseButtonDown(bool includeChildren=false) const
Returns true if the mouse button is currently held down in this component.
static void JUCE_CALLTYPE unfocusAllComponents()
If any component has keyboard focus, this will defocus it.
void removeComponentListener(ComponentListener *listenerToRemove)
Removes a component listener.
void setRepaintsOnMouseActivity(bool shouldRepaint) noexcept
Causes automatic repaints when the mouse enters or exits this component.
bool isAccessible() const noexcept
Returns true if this component and its children are visible to accessibility clients.
virtual void childBoundsChanged(Component *child)
Called when one of this component's children is moved or resized.
void copyAllExplicitColoursTo(Component &target) const
This looks for any colours that have been specified for this component, and copies them to the specif...
void setComponentID(const String &newID)
Sets the component's ID string.
Component * getTopLevelComponent() const noexcept
Returns the highest-level component which contains this one or its parents.
virtual void inputAttemptWhenModal()
Called when the user tries to click on a component that is blocked by another modal component.
virtual void paintOverChildren(Graphics &g)
Components can override this method to draw over the top of their children.
void mouseMove(const MouseEvent &event) override
Called when the mouse moves inside a component.
virtual std::unique_ptr< AccessibilityHandler > createAccessibilityHandler()
Override this method to return a custom AccessibilityHandler for this component.
static Component *JUCE_CALLTYPE getCurrentlyModalComponent(int index=0) noexcept
Returns one of the components that are currently modal.
void setBroughtToFrontOnMouseClick(bool shouldBeBroughtToFront) noexcept
Indicates whether the component should be brought to the front when clicked.
void giveAwayKeyboardFocus()
If this component or any of its children currently have the keyboard focus, this will defocus it,...
void toBehind(Component *other)
Changes this component's z-order so that it's just behind another component.
void setAccessible(bool shouldBeAccessible)
Sets whether this component and its children are visible to accessibility clients.
void setBoundsInset(BorderSize< int > borders)
Changes the component's position and size based on the amount of space to leave around it.
void setInterceptsMouseClicks(bool allowClicksOnThisComponent, bool allowClicksOnChildComponents) noexcept
Changes the default return value for the hitTest() method.
bool isMouseOverOrDragging(bool includeChildren=false) const
True if the mouse is over this component, or if it's being dragged in this component.
void setCentreRelative(float x, float y)
Changes the position of the component's centre.
static bool JUCE_CALLTYPE isMouseButtonDownAnywhere() noexcept
Returns true if a mouse button is currently down.
virtual MouseCursor getMouseCursor()
Returns the mouse cursor shape to use when the mouse is over this component.
bool isVisible() const noexcept
Tests whether the component is visible or not.
void removeFromDesktop()
If the component is currently showing on the desktop, this will hide it.
int getScreenY() const
Returns this component's y coordinate relative the screen's top-left origin.
Component * getParentComponent() const noexcept
Returns the component which this component is inside.
void * getWindowHandle() const
Returns the underlying native window handle for this component.
int getNumChildComponents() const noexcept
Returns the number of child components that this component contains.
virtual void childrenChanged()
Subclasses can use this callback to be told when children are added or removed, or when their z-order...
int proportionOfHeight(float proportion) const noexcept
Returns a proportion of the component's height.
void exitModalState(int returnValue=0)
Ends a component's modal state.
virtual void parentHierarchyChanged()
Called to indicate that the component's parents have changed.
Image createComponentSnapshot(Rectangle< int > areaToGrab, bool clipImageToComponentBounds=true, float scaleFactor=1.0f)
Generates a snapshot of part of this component.
int getScreenX() const
Returns this component's x coordinate relative the screen's top-left origin.
void setPositioner(Positioner *newPositioner)
Sets a new Positioner object for this component.
virtual void focusGained(FocusChangeType cause)
Called to indicate that this component has just acquired the keyboard focus.
void setTitle(const String &newTitle)
Sets the title for this component.
bool reallyContains(Point< int > localPoint, bool returnTrueIfWithinAChild)
Returns true if a given point lies in this component, taking any overlapping siblings into account.
int getIndexOfChildComponent(const Component *child) const noexcept
Returns the index of this component in the list of child components.
bool isAlwaysOnTop() const noexcept
Returns true if this component is set to always stay in front of its siblings.
bool isOpaque() const noexcept
Returns true if no parts of this component are transparent.
void setFocusContainerType(FocusContainerType containerType) noexcept
Sets whether this component is a container for components that can have their focus traversed,...
virtual void minimisationStateChanged(bool isNowMinimised)
Called for a desktop component which has just been minimised or un-minimised.
Point< int > getPosition() const noexcept
Returns the component's top-left position as a Point.
int getHeight() const noexcept
Returns the component's height in pixels.
void grabKeyboardFocus()
Tries to give keyboard focus to this component.
Component * findFocusContainer() const
Returns the focus container for this component.
Rectangle< int > getLocalArea(const Component *sourceComponent, Rectangle< int > areaRelativeToSourceComponent) const
Converts a rectangle to be relative to this component's coordinate space.
bool isTransformed() const noexcept
Returns true if a non-identity transform is being applied to this component.
virtual void userTriedToCloseWindow()
For components on the desktop, this is called if the system wants to close the window.
int getX() const noexcept
Returns the x coordinate of the component's left edge.
int getExplicitFocusOrder() const
Returns the focus order of this component, if one has been specified.
void toBack()
Changes this component's z-order to be at the back of all its siblings.
void toFront(bool shouldAlsoGainKeyboardFocus)
Brings the component to the front of its siblings.
Point< int > getLocalPoint(const Component *sourceComponent, Point< int > pointRelativeToSourceComponent) const
Converts a point to be relative to this component's coordinate space.
static Component *JUCE_CALLTYPE getCurrentlyFocusedComponent() noexcept
Returns the component that currently has the keyboard focus.
bool isShowing() const
Tests whether this component and all its parents are visible.
virtual std::unique_ptr< ComponentTraverser > createKeyboardFocusTraverser()
Creates a ComponentTraverser object to use to determine the logic by which keyboard focus should be p...
void sendLookAndFeelChange()
Calls the methods repaint(), lookAndFeelChanged(), and colourChanged() in this component and all its ...
virtual void focusGainedWithDirection(FocusChangeType cause, FocusChangeDirection direction)
Called to indicate that this component has just acquired the keyboard focus.
void setTopRightPosition(int x, int y)
Moves the component to a new position.
static float JUCE_CALLTYPE getApproximateScaleFactorForComponent(const Component *targetComponent)
Returns the approximate scale factor for a given component by traversing its parent hierarchy and app...
void setAlpha(float newAlpha)
Changes the transparency of this component.
void addComponentListener(ComponentListener *newListener)
Adds a listener to be told about changes to the component hierarchy or position.
void mouseUp(const MouseEvent &event) override
Called when a mouse button is released.
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.
virtual bool canModalEventBeSentToComponent(const Component *targetComponent)
When a component is modal, this callback allows it to choose which other components can still receive...
FocusChangeType
Enumeration used by the focusGained() and focusLost() methods.
@ focusChangedByTabKey
Means that the user pressed the tab key to move the focus.
@ focusChangedDirectly
Means that the focus was changed by a call to grabKeyboardFocus().
@ focusChangedByMouseClick
Means that the user clicked the mouse to change focus.
void mouseExit(const MouseEvent &event) override
Called when the mouse moves out of a component.
void setPaintingIsUnclipped(bool shouldPaintWithoutClipping) noexcept
This allows you to indicate that this component doesn't require its graphics context to be clipped wh...
void setAlwaysOnTop(bool shouldStayOnTop)
Sets whether the component should always be kept at the front of its siblings.
Positioner * getPositioner() const noexcept
Returns the Positioner object that has been set for this component.
float getAlpha() const noexcept
Returns the component's current transparency level.
bool hasKeyboardFocus(bool trueIfChildIsFocused) const
Returns true if this component currently has the keyboard focus.
virtual void alphaChanged()
Called when setAlpha() is used to change the alpha value of this component.
bool isCurrentlyBlockedByAnotherModalComponent() const
Checks whether there's a modal component somewhere that's stopping this one from receiving messages.
void addMouseListener(MouseListener *newListener, bool wantsEventsForAllNestedChildComponents)
Registers a listener to be told when mouse events occur in this component.
void setDescription(const String &newDescription)
Sets the description for this component.
bool isBroughtToFrontOnMouseClick() const noexcept
Indicates whether the component should be brought to the front when clicked-on.
AccessibilityHandler * getAccessibilityHandler()
Returns the accessibility handler for this component, or nullptr if this component is not accessible.
void setOpaque(bool shouldBeOpaque)
Indicates whether any parts of the component might be transparent.
void setMouseCursor(const MouseCursor &cursorType)
Changes the mouse cursor shape to use when the mouse is over this component.
void setCentrePosition(int x, int y)
Changes the position of the component's centre.
void postCommandMessage(int commandId)
Dispatches a numbered message to this component.
virtual void enablementChanged()
Callback to indicate that this component has been enabled or disabled.
virtual void modifierKeysChanged(const ModifierKeys &modifiers)
Called when a modifier key is pressed or released.
void mouseEnter(const MouseEvent &event) override
Called when the mouse first enters a component.
void setEnabled(bool shouldBeEnabled)
Enables or disables 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 addKeyListener(KeyListener *newListener)
Adds a listener that wants to hear about keypresses that this component receives.
Component() noexcept
Creates a component.
FocusContainerType
A focus container type that can be passed to setFocusContainerType().
@ focusContainer
The component will act as a top-level component within which focus is passed around.
Rectangle< int > getScreenBounds() const
Returns the bounds of this component, relative to the screen's top-left.
void getInterceptsMouseClicks(bool &allowsClicksOnThisComponent, bool &allowsClicksOnChildComponents) const noexcept
Retrieves the current state of the mouse-click interception flags.
Point< int > getMouseXYRelative() const
Returns the mouse's current position, relative to this component.
void removeMouseListener(MouseListener *listenerToRemove)
Deregisters a mouse listener.
bool isOnDesktop() const noexcept
Returns true if this component is currently showing on the desktop.
virtual bool hitTest(int x, int y)
Tests whether a given point is inside the component.
void setBoundsToFit(Rectangle< int > targetArea, Justification justification, bool onlyReduceInSize)
Positions the component within a given rectangle, keeping its proportions unchanged.
bool getMouseClickGrabsKeyboardFocus() const noexcept
Returns the last value set with setMouseClickGrabsKeyboardFocus().
virtual void resized()
Called when this component's size has been changed.
Rectangle< int > localAreaToGlobal(Rectangle< int > localArea) const
Converts a rectangle from this component's coordinate space to a screen coordinate.
bool isKeyboardFocusContainer() const noexcept
Returns true if this component has been marked as a keyboard focus container.
int getY() const noexcept
Returns the y coordinate of the top of this component.
virtual void setName(const String &newName)
Sets the name of this component.
void removeChildComponent(Component *childToRemove)
Removes one of this component's child-components.
Component * getChildComponent(int index) const noexcept
Returns one of this component's child components, by it index.
FocusChangeDirection
Enumeration used by the focusGainedWithDirection() method.
bool isParentOf(const Component *possibleChild) const noexcept
Checks whether a component is anywhere inside this component or its children.
void removeColour(int colourID)
If a colour has been set with setColour(), this will remove it.
void removeAllChildren()
Removes all this component's children.
virtual void addToDesktop(int windowStyleFlags, void *nativeWindowToAttachTo=nullptr)
Makes this component appear as a window on the desktop.
void setBufferedToImage(bool shouldBeBuffered)
Makes the component use an internal buffer to optimise its redrawing.
void setBounds(int x, int y, int width, int height)
Changes the component's position and size.
void setSize(int newWidth, int newHeight)
Changes the size of the component.
virtual bool keyStateChanged(bool isKeyDown)
Called when a key is pressed or released.
void setColour(int colourID, Colour newColour)
Registers a colour to be used for a particular purpose.
void enterModalState(bool takeKeyboardFocus=true, ModalComponentManager::Callback *callback=nullptr, bool deleteWhenDismissed=false)
Puts the component into a modal state.
bool isPaintingUnclipped() const noexcept
Returns true if this component doesn't require its graphics context to be clipped when it is being pa...
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.
bool isMouseOver(bool includeChildren=false) const
Returns true if the mouse is currently over this component.
void setMouseClickGrabsKeyboardFocus(bool shouldGrabFocus)
Chooses whether a click on this component automatically grabs the focus.
void mouseDoubleClick(const MouseEvent &event) override
Called when a mouse button has been double-clicked on a component.
virtual void parentSizeChanged()
Called when this component's immediate parent has been resized.
Rectangle< int > getParentMonitorArea() const
Returns the screen coordinates of the monitor that contains this component.
int getWidth() const noexcept
Returns the component's width in pixels.
~Component() override
Destructor.
void mouseWheelMove(const MouseEvent &event, const MouseWheelDetails &wheel) override
Called when the mouse-wheel is moved.
bool isFocusContainer() const noexcept
Returns true if this component has been marked as a focus container.
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.
virtual std::unique_ptr< ComponentTraverser > createFocusTraverser()
Creates a ComponentTraverser object to determine the logic by which focus should be passed from this ...
Point< int > localPointToGlobal(Point< int > localPoint) const
Converts a point relative to this component's top-left into a screen coordinate.
bool getWantsKeyboardFocus() const noexcept
Returns true if the component is interested in getting keyboard focus.
void updateMouseCursor() const
Forces the current mouse cursor to be updated.
void addChildAndSetID(Component *child, const String &componentID)
Adds a child component to this one, makes it visible, and sets its component ID.
ComponentPeer * getPeer() const
Returns the heavyweight window that contains this component.
virtual void focusOfChildComponentChanged(FocusChangeType cause)
Called to indicate a change in whether or not this component is the parent of the currently-focused c...
LookAndFeel & getLookAndFeel() const noexcept
Finds the appropriate look-and-feel to use for this component.
virtual bool keyPressed(const KeyPress &key)
Called when a key is pressed.
void setExplicitFocusOrder(int newFocusOrderIndex)
Sets the focus order of this component.
void setHelpText(const String &newHelpText)
Sets the help text for this component.
Rectangle< int > getLocalBounds() const noexcept
Returns the component's bounds, relative to its own origin.
int getParentWidth() const noexcept
Returns the width of the component's parent.
Point< int > getScreenPosition() const
Returns the position of this component's top-left corner relative to the screen's top-left.
void setComponentEffect(ImageEffectFilter *newEffect)
Adds an effect filter to alter the component's appearance.
void setTopLeftPosition(int x, int y)
Moves the component to a new position.
virtual void broughtToFront()
Called when this component has been moved to the front of its siblings.
void centreWithSize(int width, int height)
Changes the component's size and centres it within its parent.
virtual void lookAndFeelChanged()
Called to let the component react to a change in the look-and-feel setting.
virtual void colourChanged()
This method is called when a colour is changed by the setColour() method, or when the look-and-feel i...
Component * findKeyboardFocusContainer() const
Returns the keyboard focus container for this component.
void addChildComponent(Component *child, int zOrder=-1)
Adds a child component to this one.
virtual void paint(Graphics &g)
Components can override this method to draw their content.
bool isCurrentlyModal(bool onlyConsiderForemostModalComponent=true) const noexcept
Returns true if this component is the modal one.
void mouseDown(const MouseEvent &event) override
Called when a mouse button is pressed.
virtual void setVisible(bool shouldBeVisible)
Makes the component visible or invisible.
void invalidateAccessibilityHandler()
Invalidates the AccessibilityHandler that is currently being used for this component.
virtual void visibilityChanged()
Called when this component's visibility changes.
void removeKeyListener(KeyListener *listenerToRemove)
Removes a previously-registered key listener.
Component * getComponentAt(int x, int y)
Returns the component at a certain point within this one.
virtual float getDesktopScaleFactor() const
Returns the default scale factor to use for this component when it is placed on the desktop.
int getParentHeight() const noexcept
Returns the height of the component's parent.
void setCachedComponentImage(CachedComponentImage *newCachedImage)
Gives the component a CachedComponentImage that should be used to buffer its painting.
virtual void moved()
Called when this component's position has been changed.
void setBoundsRelative(float proportionalX, float proportionalY, float proportionalWidth, float proportionalHeight)
Changes the component's position and size in terms of fractions of its parent's size.
virtual void handleCommandMessage(int commandId)
Called to handle a command that was sent by postCommandMessage().
float getGlobalScaleFactor() const noexcept
Returns the current global scale factor, as set by setGlobalScaleFactor().
const Displays & getDisplays() const noexcept
Returns the Displays object representing the connected displays.
MouseInputSource getMainMouseSource() const noexcept
Returns the main mouse input device that the system is using.
void beginDragAutoRepeat(int millisecondsBetweenCallbacks)
Ensures that a non-stop stream of mouse-drag events will be sent during the current mouse-drag operat...
static Desktop &JUCE_CALLTYPE getInstance()
There's only one desktop object, and this method will return it.
const Array< MouseInputSource > & getMouseSources() const noexcept
Provides access to the array of mouse sources, for iteration.
Rectangle< int > userArea
The total area of this display in logical pixels which isn't covered by OS-dependent objects like the...
const Display * getDisplayForRect(Rectangle< int > rect, bool isPhysical=false) const noexcept
Returns the Display object representing the display containing a given Rectangle (either in logical o...
Uses RAII to save and restore the state of a graphics context.
A graphics context, used for drawing a component or image.
void endTransparencyLayer()
Completes a drawing operation to a temporary semi-transparent buffer.
void drawImageTransformed(const Image &imageToDraw, const AffineTransform &transform, bool fillAlphaChannelWithCurrentBrush=false) const
Draws an image, having applied an affine transform to it.
void addTransform(const AffineTransform &transform)
Adds a transformation which will be performed on all the graphics operations that the context subsequ...
void beginTransparencyLayer(float layerOpacity)
Begins rendering to an off-screen bitmap which will later be flattened onto the current context with ...
void setColour(Colour newColour)
Changes the current drawing colour.
void setOrigin(Point< int > newOrigin)
Moves the position of the context's origin.
Represents a string identifier, designed for accessing properties by name.
A graphical effect filter that can be applied to components.
Holds a fixed-size bitmap.
Definition juce_Image.h:58
Rectangle< int > getBounds() const noexcept
Returns a rectangle with the same size as this image.
bool isNull() const noexcept
Returns true if this image is not valid.
Definition juce_Image.h:155
@ ARGB
< each pixel is a 4-byte ARGB premultiplied colour value.
Definition juce_Image.h:67
@ RGB
< each pixel is a 3-byte packed RGB colour value.
Definition juce_Image.h:66
Represents a type of justification to be used when positioning graphical items.
const Rectangle< ValueType > appliedToRectangle(const Rectangle< ValueType > &areaToAdjust, const Rectangle< ValueType > &targetSpace) const noexcept
Returns the new position of a rectangle that has been justified to fit within a given space.
Receives callbacks when keys are pressed.
Represents a key press, including any modifier keys that are needed.
LookAndFeel objects define the appearance of all the JUCE widgets, and subclasses can be used to appl...
static LookAndFeel & getDefaultLookAndFeel() noexcept
Returns the current default look-and-feel for a component to use when it hasn't got one explicitly se...
virtual void playAlertSound()
Plays the system's default 'beep' noise, to alert the user about something very important.
Colour findColour(int colourId) const noexcept
Looks for a colour that has been registered with the given colour ID number.
static bool callAsync(std::function< void()> functionToCall)
Asynchronously invokes a function or C++11 lambda on the message thread.
void * callFunctionOnMessageThread(MessageCallbackFunction *callback, void *userData)
Calls a function using the message-thread.
static MessageManager * getInstance()
Returns the global instance of the MessageManager.
Receives callbacks when a modal component is dismissed.
Represents the state of the mouse buttons and modifier keys.
static ModifierKeys currentModifiers
This object represents the last-known state of the keyboard and mouse buttons.
bool isAnyMouseButtonDown() const noexcept
Tests for any of the mouse-button flags.
Represents a mouse cursor image.
@ NormalCursor
The standard arrow cursor.
Contains position and status information about a mouse event.
const float tiltY
The tilt of the pen device along the y-axis between -1.0 and 1.0.
const Point< float > mouseDownPosition
The coordinates of the last place that a mouse button was pressed.
const ModifierKeys mods
The key modifiers associated with the event.
MouseInputSource source
The source device that generated this event.
const Time mouseDownTime
The time that the corresponding mouse-down event occurred.
MouseEvent getEventRelativeTo(Component *newComponent) const noexcept
Creates a version of this event that is relative to a different component.
const float orientation
The orientation of the touch input for this event in radians where 0 indicates a touch aligned with t...
const float pressure
The pressure of the touch or stylus for this event.
const Point< float > position
The position of the mouse when the event occurred.
bool mouseWasDraggedSinceMouseDown() const noexcept
Returns true if the user seems to be performing a drag gesture.
const float rotation
The rotation of the pen device for this event in radians.
const Time eventTime
The time that this mouse-event occurred.
int getNumberOfClicks() const noexcept
For a click event, the number of times the mouse was clicked in succession.
const float tiltX
The tilt of the pen device along the x-axis between -1.0 and 1.0.
Represents a linear source of mouse events from a mouse device or individual finger in a multi-touch ...
void triggerFakeMove() const
Tells the device to dispatch a mouse-move or mouse-drag event.
ModifierKeys getCurrentModifiers() const noexcept
Returns a set of modifiers that indicate which buttons are currently held down on this device.
void forceMouseCursorUpdate()
Forces an update of the mouse cursor for whatever component it's currently over.
void showMouseCursor(const MouseCursor &cursor)
Changes the mouse cursor, (if there is one).
A MouseListener can be registered with a component to receive callbacks about mouse events that happe...
virtual void mouseEnter(const MouseEvent &event)
Called when the mouse first enters a component.
virtual void mouseMagnify(const MouseEvent &event, float scaleFactor)
Called when a pinch-to-zoom mouse-gesture is used.
virtual void mouseMove(const MouseEvent &event)
Called when the mouse moves inside a component.
virtual void mouseUp(const MouseEvent &event)
Called when a mouse button is released.
virtual void mouseDrag(const MouseEvent &event)
Called when the mouse is moved while a button is held down.
virtual void mouseDoubleClick(const MouseEvent &event)
Called when a mouse button has been double-clicked on a component.
virtual void mouseDown(const MouseEvent &event)
Called when a mouse button is pressed.
virtual void mouseExit(const MouseEvent &event)
Called when the mouse moves out of a component.
virtual void mouseWheelMove(const MouseEvent &event, const MouseWheelDetails &wheel)
Called when the mouse-wheel is moved.
A pair of (x, y) coordinates.
Definition juce_Point.h:42
constexpr Point< float > toFloat() const noexcept
Casts this point to a Point<float> object.
Definition juce_Point.h:239
constexpr Point< int > roundToInt() const noexcept
Casts this point to a Point<int> object using roundToInt() to convert the values.
Definition juce_Point.h:245
ValueType y
The point's Y coordinate.
Definition juce_Point.h:252
Point transformedBy(const AffineTransform &transform) const noexcept
Returns the position of this point, if it is transformed by a given AffineTransform.
Definition juce_Point.h:228
ValueType x
The point's X coordinate.
Definition juce_Point.h:251
Maintains a set of rectangles as a complex region.
void clear()
Removes all rectangles to leave an empty region.
bool containsRectangle(RectangleType rectangleToCheck) const
Checks whether the region contains the whole of a given rectangle.
void subtract(const RectangleType rect)
Removes a rectangular region from the list.
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.
ValueType getWidth() const noexcept
Returns the width of the rectangle.
ValueType getY() const noexcept
Returns the y coordinate of the rectangle's top edge.
bool isEmpty() const noexcept
Returns true if the rectangle's width or height are zero or less.
Rectangle withZeroOrigin() const noexcept
Returns a rectangle whose size is the same as this one, but whose top-left position is (0,...
Rectangle transformedBy(const AffineTransform &transform) const noexcept
Returns the smallest rectangle that can contain the shape created by applying a transform to this rec...
ValueType getHeight() const noexcept
Returns the height of the rectangle.
A simple class for holding temporary references to a string literal or String.
The JUCE String class!
Definition juce_String.h:53
Holds an absolute date and time.
Definition juce_Time.h:37
This class acts as a pointer which will automatically become null if the object to which it points is...
#define JUCE_ASSERT_MESSAGE_MANAGER_IS_LOCKED
This macro is used to catch unsafe use of functions which expect to only be called on the message thr...
#define jassert(expression)
Platform-independent assertion macro.
#define JUCE_DECLARE_NON_COPYABLE(className)
This is a shorthand macro for deleting a class's copy constructor and copy assignment operator.
#define JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(className)
This is a shorthand way of writing both a JUCE_DECLARE_NON_COPYABLE and JUCE_LEAK_DETECTOR macro for ...
#define jassertfalse
This will always cause an assertion failure.
#define JUCE_CALLTYPE
This macro defines the C calling convention used as the standard for JUCE calls.
typedef double
JUCE Namespace.
int pointer_sized_int
A signed integer type that's guaranteed to be large enough to hold a pointer without truncating it.
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.
@ structureChanged
Indicates that the structure of the UI elements has changed in a significant way.
Type unalignedPointerCast(void *ptr) noexcept
Casts a pointer to another type via void*, which suppresses the cast-align warning which sometimes ar...
Definition juce_Memory.h:88
unsigned int uint32
A platform-independent 32-bit unsigned integer type.
unsigned char uint8
A platform-independent 8-bit unsigned integer type.
int roundToInt(const FloatType value) noexcept
Fast floating-point-to-integer conversion.
Contains status information about a mouse wheel event.
T sqrt(T... args)
bool invalidate(const Rectangle< int > &area) override
Invalidates a section of the cached image data.
void releaseResources() override
Called to indicate that the component is no longer active, so any cached data should be released if p...
bool invalidateAll() override
Invalidates all cached image data.
void paint(Graphics &g) override
Called as part of the parent component's paint method, this must draw the given component into the ta...