mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-09 23:34:20 +00:00
SidePanel: Add an option to restrict content to the safe screen area
A major benefit of this change is that the menu in the DemoRunner will now display reasonably on mobile devices with notches or other decorations.
This commit is contained in:
parent
f30d70049c
commit
cfc006aaf9
4 changed files with 70 additions and 8 deletions
|
|
@ -308,6 +308,7 @@ MainComponent::MainComponent()
|
|||
|
||||
demosPanel.setTitle ("Demos");
|
||||
demosPanel.setFocusContainerType (FocusContainerType::focusContainer);
|
||||
demosPanel.setContentRestrictedToSafeArea (true);
|
||||
|
||||
showDemosButton.onClick = [this] { demosPanel.showOrHide (true); };
|
||||
|
||||
|
|
|
|||
|
|
@ -56,19 +56,41 @@ public:
|
|||
|
||||
/** The total area of this display in logical pixels including any OS-dependent objects
|
||||
like the taskbar, menu bar, etc.
|
||||
|
||||
On mobile (Android, iOS) this is the full area of the display.
|
||||
*/
|
||||
Rectangle<int> totalArea;
|
||||
|
||||
/** The total area of this display in logical pixels which isn't covered by OS-dependent
|
||||
objects like the taskbar, menu bar, etc.
|
||||
|
||||
On mobile (iOS, Android), the system UI will be made transparent whenever possible, and
|
||||
the JUCE app may draw behind these bars. Therefore, on these platforms, the userArea
|
||||
is *not* restricted by the system UI. Instead, potentially-obscured areas of the
|
||||
display can be found by querying the safeAreaInsets and keyboardInsets.
|
||||
|
||||
Mobile platforms that support multiple windows (e.g. Android in split screen) will
|
||||
return the screen area currently available to the application here. The resulting
|
||||
area may be significantly smaller than the total screen area, but may overlap the
|
||||
system decorations.
|
||||
*/
|
||||
Rectangle<int> userArea;
|
||||
|
||||
/** Represents the area of this display in logical pixels that is not functional for
|
||||
displaying content.
|
||||
|
||||
These insets are applied relative to the userArea.
|
||||
|
||||
On mobile devices this may be the area covered by display cutouts and notches, where
|
||||
you still want to draw a background but should not position important content.
|
||||
|
||||
Note that these insets may change depending on the current state of the system.
|
||||
As a simple example, entering/leaving kiosk mode may cause the system UI visibility
|
||||
to change, which may affect the safe areas.
|
||||
A more complex example would be split-screen state on Android, where an activity
|
||||
occupying the top portion of the screen is likely to have insets for the status bar but
|
||||
not the navigation bar, whereas an activity on the bottom may have navigation insets
|
||||
but not status insets.
|
||||
*/
|
||||
BorderSize<int> safeAreaInsets;
|
||||
|
||||
|
|
|
|||
|
|
@ -131,6 +131,24 @@ void SidePanel::resized()
|
|||
|
||||
calculateAndRemoveShadowBounds (bounds);
|
||||
|
||||
const auto fullScreen = std::invoke ([&]
|
||||
{
|
||||
if (auto* peer = getPeer())
|
||||
return peer->isFullScreen();
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
if (fullScreen && isContentRestrictedToSafeArea() && parent != nullptr)
|
||||
{
|
||||
if (auto* display = Desktop::getInstance().getDisplays().getDisplayForRect (parent->getScreenBounds()))
|
||||
{
|
||||
const auto safeArea = display->safeAreaInsets.subtractedFrom (display->keyboardInsets.subtractedFrom (display->userArea));
|
||||
const auto safeAreaInLocalSpace = getLocalArea (nullptr, safeArea) + getCurrentOffset();
|
||||
bounds = bounds.getIntersection (safeAreaInLocalSpace);
|
||||
}
|
||||
}
|
||||
|
||||
auto titleBounds = bounds.removeFromTop (titleBarHeight);
|
||||
|
||||
if (titleBarComponent != nullptr)
|
||||
|
|
@ -268,18 +286,25 @@ void SidePanel::changeListenerCallback (ChangeBroadcaster*)
|
|||
}
|
||||
}
|
||||
|
||||
Rectangle<int> SidePanel::calculateBoundsInParent (Component& parentComp) const
|
||||
Rectangle<int> SidePanel::calculateShowingBoundsInParent (Component& parentComp) const
|
||||
{
|
||||
auto parentBounds = parentComp.getLocalBounds();
|
||||
|
||||
if (isOnLeft)
|
||||
{
|
||||
return isShowing ? parentBounds.removeFromLeft (panelWidth)
|
||||
: parentBounds.withX (parentBounds.getX() - panelWidth).withWidth (panelWidth);
|
||||
}
|
||||
return isOnLeft ? parentBounds.removeFromLeft (panelWidth)
|
||||
: parentBounds.removeFromRight (panelWidth);
|
||||
}
|
||||
|
||||
return isShowing ? parentBounds.removeFromRight (panelWidth)
|
||||
: parentBounds.withX (parentBounds.getRight()).withWidth (panelWidth);
|
||||
Point<int> SidePanel::getCurrentOffset() const
|
||||
{
|
||||
if (isShowing)
|
||||
return {};
|
||||
|
||||
return { isOnLeft ? -panelWidth : panelWidth, 0 };
|
||||
}
|
||||
|
||||
Rectangle<int> SidePanel::calculateBoundsInParent (Component& parentComp) const
|
||||
{
|
||||
return calculateShowingBoundsInParent (parentComp) + getCurrentOffset();
|
||||
}
|
||||
|
||||
void SidePanel::calculateAndRemoveShadowBounds (Rectangle<int>& bounds)
|
||||
|
|
|
|||
|
|
@ -154,6 +154,17 @@ public:
|
|||
/** Returns the text that is displayed in the title bar at the top of the SidePanel. */
|
||||
String getTitleText() const noexcept { return titleLabel.getText(); }
|
||||
|
||||
/** @see isContentRestrictedToSafeArea() */
|
||||
void setContentRestrictedToSafeArea (bool x) noexcept { restrictToSafeArea = x; }
|
||||
|
||||
/** When true, will avoid displaying menu content within areas of the screen that may be
|
||||
obscured by display cutouts or operating system decorations. When false, the menu's
|
||||
content will entirely fill the menu bounds. True by default.
|
||||
|
||||
@see setContentRestrictedToSafeArea()
|
||||
*/
|
||||
bool isContentRestrictedToSafeArea() const noexcept { return restrictToSafeArea; }
|
||||
|
||||
//==============================================================================
|
||||
/** This abstract base class is implemented by LookAndFeel classes to provide
|
||||
SidePanel drawing functionality.
|
||||
|
|
@ -230,12 +241,15 @@ private:
|
|||
int amountMoved = 0;
|
||||
|
||||
bool shouldShowDismissButton = true;
|
||||
bool restrictToSafeArea = true;
|
||||
|
||||
//==============================================================================
|
||||
void lookAndFeelChanged() override;
|
||||
void componentMovedOrResized (Component&, bool wasMoved, bool wasResized) override;
|
||||
void changeListenerCallback (ChangeBroadcaster*) override;
|
||||
|
||||
Rectangle<int> calculateShowingBoundsInParent (Component&) const;
|
||||
Point<int> getCurrentOffset() const;
|
||||
Rectangle<int> calculateBoundsInParent (Component&) const;
|
||||
void calculateAndRemoveShadowBounds (Rectangle<int>& bounds);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue