git subrepo clone --branch=sono6good https://github.com/essej/JUCE.git deps/juce

subrepo:
  subdir:   "deps/juce"
  merged:   "b13f9084e"
upstream:
  origin:   "https://github.com/essej/JUCE.git"
  branch:   "sono6good"
  commit:   "b13f9084e"
git-subrepo:
  version:  "0.4.3"
  origin:   "https://github.com/ingydotnet/git-subrepo.git"
  commit:   "2f68596"
This commit is contained in:
essej
2022-04-18 17:51:22 -04:00
parent 63e175fee6
commit 25bd5d8adb
3210 changed files with 1045392 additions and 0 deletions

View File

@ -0,0 +1,51 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
ArrowButton::ArrowButton (const String& name, float arrowDirectionInRadians, Colour arrowColour)
: Button (name), colour (arrowColour)
{
path.addTriangle (0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.5f);
path.applyTransform (AffineTransform::rotation (MathConstants<float>::twoPi * arrowDirectionInRadians, 0.5f, 0.5f));
}
ArrowButton::~ArrowButton() {}
void ArrowButton::paintButton (Graphics& g, bool /*shouldDrawButtonAsHighlighted*/, bool shouldDrawButtonAsDown)
{
Path p (path);
const float offset = shouldDrawButtonAsDown ? 1.0f : 0.0f;
p.applyTransform (path.getTransformToScaleToFit (offset, offset, (float) getWidth() - 3.0f, (float) getHeight() - 3.0f, false));
DropShadow (Colours::black.withAlpha (0.3f), shouldDrawButtonAsDown ? 2 : 4, Point<int>()).drawForPath (g, p);
g.setColour (colour);
g.fillPath (p);
}
} // namespace juce

View File

@ -0,0 +1,65 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
/**
A button with an arrow in it.
@see Button
@tags{GUI}
*/
class JUCE_API ArrowButton : public Button
{
public:
//==============================================================================
/** Creates an ArrowButton.
@param buttonName the name to give the button
@param arrowDirection the direction the arrow should point in, where 0.0 is
pointing right, 0.25 is down, 0.5 is left, 0.75 is up
@param arrowColour the colour to use for the arrow
*/
ArrowButton (const String& buttonName,
float arrowDirection,
Colour arrowColour);
/** Destructor. */
~ArrowButton() override;
/** @internal */
void paintButton (Graphics&, bool, bool) override;
private:
Colour colour;
Path path;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ArrowButton)
};
} // namespace juce

View File

@ -0,0 +1,792 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
struct Button::CallbackHelper : public Timer,
public ApplicationCommandManagerListener,
public Value::Listener,
public KeyListener
{
CallbackHelper (Button& b) : button (b) {}
void timerCallback() override
{
button.repeatTimerCallback();
}
bool keyStateChanged (bool, Component*) override
{
return button.keyStateChangedCallback();
}
void valueChanged (Value& value) override
{
if (value.refersToSameSourceAs (button.isOn))
button.setToggleState (button.isOn.getValue(), dontSendNotification, sendNotification);
}
bool keyPressed (const KeyPress&, Component*) override
{
// returning true will avoid forwarding events for keys that we're using as shortcuts
return button.isShortcutPressed();
}
void applicationCommandInvoked (const ApplicationCommandTarget::InvocationInfo& info) override
{
if (info.commandID == button.commandID
&& (info.commandFlags & ApplicationCommandInfo::dontTriggerVisualFeedback) == 0)
button.flashButtonState();
}
void applicationCommandListChanged() override
{
button.applicationCommandListChangeCallback();
}
Button& button;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CallbackHelper)
};
//==============================================================================
Button::Button (const String& name) : Component (name), text (name)
{
callbackHelper.reset (new CallbackHelper (*this));
setWantsKeyboardFocus (true);
isOn.addListener (callbackHelper.get());
}
Button::~Button()
{
clearShortcuts();
if (commandManagerToUse != nullptr)
commandManagerToUse->removeListener (callbackHelper.get());
isOn.removeListener (callbackHelper.get());
callbackHelper.reset();
}
//==============================================================================
void Button::setButtonText (const String& newText)
{
if (text != newText)
{
text = newText;
repaint();
}
}
void Button::setTooltip (const String& newTooltip)
{
SettableTooltipClient::setTooltip (newTooltip);
generateTooltip = false;
}
void Button::updateAutomaticTooltip (const ApplicationCommandInfo& info)
{
if (generateTooltip && commandManagerToUse != nullptr)
{
auto tt = info.description.isNotEmpty() ? info.description
: info.shortName;
for (auto& kp : commandManagerToUse->getKeyMappings()->getKeyPressesAssignedToCommand (commandID))
{
auto key = kp.getTextDescription();
tt << " [";
if (key.length() == 1)
tt << TRANS("shortcut") << ": '" << key << "']";
else
tt << key << ']';
}
SettableTooltipClient::setTooltip (tt);
}
}
void Button::setConnectedEdges (int newFlags)
{
if (connectedEdgeFlags != newFlags)
{
connectedEdgeFlags = newFlags;
repaint();
}
}
//==============================================================================
void Button::setToggleState (bool shouldBeOn, NotificationType notification)
{
setToggleState (shouldBeOn, notification, notification);
}
void Button::setToggleState (bool shouldBeOn, NotificationType clickNotification, NotificationType stateNotification)
{
if (shouldBeOn != lastToggleState)
{
WeakReference<Component> deletionWatcher (this);
if (shouldBeOn)
{
turnOffOtherButtonsInGroup (clickNotification, stateNotification);
if (deletionWatcher == nullptr)
return;
}
// This test is done so that if the value is void rather than explicitly set to
// false, the value won't be changed unless the required value is true.
if (getToggleState() != shouldBeOn)
{
isOn = shouldBeOn;
if (deletionWatcher == nullptr)
return;
}
lastToggleState = shouldBeOn;
repaint();
if (clickNotification != dontSendNotification)
{
// async callbacks aren't possible here
jassert (clickNotification != sendNotificationAsync);
sendClickMessage (ModifierKeys::currentModifiers);
if (deletionWatcher == nullptr)
return;
}
if (stateNotification != dontSendNotification)
sendStateMessage();
else
buttonStateChanged();
if (auto* handler = getAccessibilityHandler())
handler->notifyAccessibilityEvent (AccessibilityEvent::valueChanged);
}
}
void Button::setToggleState (bool shouldBeOn, bool sendChange)
{
setToggleState (shouldBeOn, sendChange ? sendNotification : dontSendNotification);
}
void Button::setClickingTogglesState (bool shouldToggle) noexcept
{
clickTogglesState = shouldToggle;
// if you've got clickTogglesState turned on, you shouldn't also connect the button
// up to be a command invoker. Instead, your command handler must flip the state of whatever
// it is that this button represents, and the button will update its state to reflect this
// in the applicationCommandListChanged() method.
jassert (commandManagerToUse == nullptr || ! clickTogglesState);
}
bool Button::getClickingTogglesState() const noexcept
{
return clickTogglesState;
}
void Button::setRadioGroupId (int newGroupId, NotificationType notification)
{
if (radioGroupId != newGroupId)
{
radioGroupId = newGroupId;
if (lastToggleState)
turnOffOtherButtonsInGroup (notification, notification);
invalidateAccessibilityHandler();
}
}
void Button::turnOffOtherButtonsInGroup (NotificationType clickNotification, NotificationType stateNotification)
{
if (auto* p = getParentComponent())
{
if (radioGroupId != 0)
{
WeakReference<Component> deletionWatcher (this);
for (auto* c : p->getChildren())
{
if (c != this)
{
if (auto b = dynamic_cast<Button*> (c))
{
if (b->getRadioGroupId() == radioGroupId)
{
b->setToggleState (false, clickNotification, stateNotification);
if (deletionWatcher == nullptr)
return;
}
}
}
}
}
}
}
//==============================================================================
void Button::enablementChanged()
{
updateState();
repaint();
}
Button::ButtonState Button::updateState()
{
return updateState (isMouseOver (true), isMouseButtonDown());
}
Button::ButtonState Button::updateState (bool over, bool down)
{
ButtonState newState = buttonNormal;
if (isEnabled() && isVisible() && ! isCurrentlyBlockedByAnotherModalComponent())
{
if ((down && (over || (triggerOnMouseDown && buttonState == buttonDown))) || isKeyDown)
newState = buttonDown;
else if (over)
newState = buttonOver;
}
setState (newState);
return newState;
}
void Button::setState (ButtonState newState)
{
if (buttonState != newState)
{
buttonState = newState;
repaint();
if (buttonState == buttonDown)
{
buttonPressTime = Time::getApproximateMillisecondCounter();
lastRepeatTime = 0;
}
sendStateMessage();
}
}
bool Button::isDown() const noexcept { return buttonState == buttonDown; }
bool Button::isOver() const noexcept { return buttonState != buttonNormal; }
void Button::buttonStateChanged() {}
uint32 Button::getMillisecondsSinceButtonDown() const noexcept
{
auto now = Time::getApproximateMillisecondCounter();
return now > buttonPressTime ? now - buttonPressTime : 0;
}
void Button::setTriggeredOnMouseDown (bool isTriggeredOnMouseDown) noexcept
{
triggerOnMouseDown = isTriggeredOnMouseDown;
}
bool Button::getTriggeredOnMouseDown() const noexcept
{
return triggerOnMouseDown;
}
//==============================================================================
void Button::clicked()
{
}
void Button::clicked (const ModifierKeys&)
{
clicked();
}
enum { clickMessageId = 0x2f3f4f99 };
void Button::triggerClick()
{
postCommandMessage (clickMessageId);
}
void Button::internalClickCallback (const ModifierKeys& modifiers)
{
if (clickTogglesState)
{
const bool shouldBeOn = (radioGroupId != 0 || ! lastToggleState);
if (shouldBeOn != getToggleState())
{
setToggleState (shouldBeOn, sendNotification);
return;
}
}
sendClickMessage (modifiers);
}
void Button::flashButtonState()
{
if (isEnabled())
{
needsToRelease = true;
setState (buttonDown);
callbackHelper->startTimer (100);
}
}
void Button::handleCommandMessage (int commandId)
{
if (commandId == clickMessageId)
{
if (isEnabled())
{
flashButtonState();
internalClickCallback (ModifierKeys::currentModifiers);
}
}
else
{
Component::handleCommandMessage (commandId);
}
}
//==============================================================================
void Button::addListener (Listener* l) { buttonListeners.add (l); }
void Button::removeListener (Listener* l) { buttonListeners.remove (l); }
void Button::sendClickMessage (const ModifierKeys& modifiers)
{
Component::BailOutChecker checker (this);
if (commandManagerToUse != nullptr && commandID != 0)
{
ApplicationCommandTarget::InvocationInfo info (commandID);
info.invocationMethod = ApplicationCommandTarget::InvocationInfo::fromButton;
info.originatingComponent = this;
commandManagerToUse->invoke (info, true);
}
clicked (modifiers);
if (checker.shouldBailOut())
return;
buttonListeners.callChecked (checker, [this] (Listener& l) { l.buttonClicked (this); });
if (checker.shouldBailOut())
return;
if (onClick != nullptr)
onClick();
}
void Button::sendStateMessage()
{
Component::BailOutChecker checker (this);
buttonStateChanged();
if (checker.shouldBailOut())
return;
buttonListeners.callChecked (checker, [this] (Listener& l) { l.buttonStateChanged (this); });
if (checker.shouldBailOut())
return;
if (onStateChange != nullptr)
onStateChange();
}
//==============================================================================
void Button::paint (Graphics& g)
{
if (needsToRelease && isEnabled())
{
needsToRelease = false;
needsRepainting = true;
}
paintButton (g, isOver(), isDown());
lastStatePainted = buttonState;
}
//==============================================================================
void Button::mouseEnter (const MouseEvent&) { updateState (true, false); }
void Button::mouseExit (const MouseEvent&) { updateState (false, false); }
bool Button::isInDragToScrollViewport() const noexcept
{
if (auto* vp = findParentComponentOfClass<Viewport>())
return vp->isScrollOnDragEnabled() && (vp->canScrollVertically() || vp->canScrollHorizontally());
return false;
}
void Button::mouseDown (const MouseEvent& e)
{
isInDraggableViewport = isInDragToScrollViewport();
isDraggingToScroll = false;
updateState (true, true);
if (isDown())
{
if (autoRepeatDelay >= 0)
callbackHelper->startTimer (autoRepeatDelay);
if (triggerOnMouseDown)
internalClickCallback (e.mods);
}
}
void Button::mouseUp (const MouseEvent& e)
{
const auto wasDown = isDown();
const auto wasOver = isOver();
updateState (isMouseSourceOver (e), false);
if (wasDown && wasOver && ! triggerOnMouseDown && ! isDraggingToScroll)
{
if (lastStatePainted != buttonDown)
flashButtonState();
WeakReference<Component> deletionWatcher (this);
internalClickCallback (e.mods);
if (deletionWatcher != nullptr)
updateState (isMouseSourceOver (e), false);
}
}
void Button::mouseDrag (const MouseEvent& e)
{
auto oldState = buttonState;
updateState (isMouseSourceOver (e), true);
if (autoRepeatDelay >= 0 && buttonState != oldState && isDown())
callbackHelper->startTimer (autoRepeatSpeed);
if (isInDraggableViewport && ! isDraggingToScroll)
if (auto* vp = findParentComponentOfClass<Viewport>())
isDraggingToScroll = vp->isCurrentlyScrollingOnDrag();
}
bool Button::isMouseSourceOver (const MouseEvent& e)
{
if (e.source.isTouch() || e.source.isPen())
return getLocalBounds().toFloat().contains (e.position);
return isMouseOver();
}
void Button::focusGained (FocusChangeType)
{
updateState();
repaint();
}
void Button::focusLost (FocusChangeType)
{
updateState();
repaint();
}
void Button::visibilityChanged()
{
needsToRelease = false;
updateState();
}
void Button::parentHierarchyChanged()
{
auto* newKeySource = shortcuts.isEmpty() ? nullptr : getTopLevelComponent();
if (newKeySource != keySource.get())
{
if (keySource != nullptr)
keySource->removeKeyListener (callbackHelper.get());
keySource = newKeySource;
if (keySource != nullptr)
keySource->addKeyListener (callbackHelper.get());
}
}
//==============================================================================
void Button::setCommandToTrigger (ApplicationCommandManager* newCommandManager,
CommandID newCommandID, bool generateTip)
{
commandID = newCommandID;
generateTooltip = generateTip;
if (commandManagerToUse != newCommandManager)
{
if (commandManagerToUse != nullptr)
commandManagerToUse->removeListener (callbackHelper.get());
commandManagerToUse = newCommandManager;
if (commandManagerToUse != nullptr)
commandManagerToUse->addListener (callbackHelper.get());
// if you've got clickTogglesState turned on, you shouldn't also connect the button
// up to be a command invoker. Instead, your command handler must flip the state of whatever
// it is that this button represents, and the button will update its state to reflect this
// in the applicationCommandListChanged() method.
jassert (commandManagerToUse == nullptr || ! clickTogglesState);
}
if (commandManagerToUse != nullptr)
applicationCommandListChangeCallback();
else
setEnabled (true);
}
void Button::applicationCommandListChangeCallback()
{
if (commandManagerToUse != nullptr)
{
ApplicationCommandInfo info (0);
if (commandManagerToUse->getTargetForCommand (commandID, info) != nullptr)
{
updateAutomaticTooltip (info);
setEnabled ((info.flags & ApplicationCommandInfo::isDisabled) == 0);
setToggleState ((info.flags & ApplicationCommandInfo::isTicked) != 0, dontSendNotification);
}
else
{
setEnabled (false);
}
}
}
//==============================================================================
void Button::addShortcut (const KeyPress& key)
{
if (key.isValid())
{
jassert (! isRegisteredForShortcut (key)); // already registered!
shortcuts.add (key);
parentHierarchyChanged();
}
}
void Button::clearShortcuts()
{
shortcuts.clear();
parentHierarchyChanged();
}
bool Button::isShortcutPressed() const
{
if (isShowing() && ! isCurrentlyBlockedByAnotherModalComponent())
for (auto& s : shortcuts)
if (s.isCurrentlyDown())
return true;
return false;
}
bool Button::isRegisteredForShortcut (const KeyPress& key) const
{
for (auto& s : shortcuts)
if (key == s)
return true;
return false;
}
bool Button::keyStateChangedCallback()
{
if (! isEnabled())
return false;
const bool wasDown = isKeyDown;
isKeyDown = isShortcutPressed();
if (autoRepeatDelay >= 0 && (isKeyDown && ! wasDown))
callbackHelper->startTimer (autoRepeatDelay);
updateState();
if (isEnabled() && wasDown && ! isKeyDown)
{
internalClickCallback (ModifierKeys::currentModifiers);
// (return immediately - this button may now have been deleted)
return true;
}
return wasDown || isKeyDown;
}
bool Button::keyPressed (const KeyPress& key)
{
if (isEnabled() && key.isKeyCode (KeyPress::returnKey))
{
triggerClick();
return true;
}
return false;
}
//==============================================================================
void Button::setRepeatSpeed (int initialDelayMillisecs,
int repeatMillisecs,
int minimumDelayInMillisecs) noexcept
{
autoRepeatDelay = initialDelayMillisecs;
autoRepeatSpeed = repeatMillisecs;
autoRepeatMinimumDelay = jmin (autoRepeatSpeed, minimumDelayInMillisecs);
}
void Button::repeatTimerCallback()
{
if (needsRepainting)
{
callbackHelper->stopTimer();
updateState();
needsRepainting = false;
}
else if (autoRepeatSpeed > 0 && (isKeyDown || (updateState() == buttonDown)))
{
auto repeatSpeed = autoRepeatSpeed;
if (autoRepeatMinimumDelay >= 0)
{
auto timeHeldDown = jmin (1.0, getMillisecondsSinceButtonDown() / 4000.0);
timeHeldDown *= timeHeldDown;
repeatSpeed = repeatSpeed + (int) (timeHeldDown * (autoRepeatMinimumDelay - repeatSpeed));
}
repeatSpeed = jmax (1, repeatSpeed);
auto now = Time::getMillisecondCounter();
// if we've been blocked from repeating often enough, speed up the repeat timer to compensate..
if (lastRepeatTime != 0 && (int) (now - lastRepeatTime) > repeatSpeed * 2)
repeatSpeed = jmax (1, repeatSpeed / 2);
lastRepeatTime = now;
callbackHelper->startTimer (repeatSpeed);
internalClickCallback (ModifierKeys::currentModifiers);
}
else if (! needsToRelease)
{
callbackHelper->stopTimer();
}
}
//==============================================================================
class ButtonAccessibilityHandler : public AccessibilityHandler
{
public:
explicit ButtonAccessibilityHandler (Button& buttonToWrap, AccessibilityRole roleIn)
: AccessibilityHandler (buttonToWrap,
isRadioButton (buttonToWrap) ? AccessibilityRole::radioButton : buttonToWrap.getClickingTogglesState() ? AccessibilityRole::toggleButton : roleIn,
getAccessibilityActions (buttonToWrap, roleIn)),
button (buttonToWrap)
{
}
AccessibleState getCurrentState() const override
{
auto state = AccessibilityHandler::getCurrentState();
if (isToggleButton (getRole()) || isRadioButton (button) || button.getClickingTogglesState())
{
state = state.withCheckable();
if (button.getToggleState())
state = state.withChecked();
}
return state;
}
String getTitle() const override
{
auto title = AccessibilityHandler::getTitle();
if (title.isEmpty())
return button.getButtonText();
return title;
}
String getHelp() const override { return button.getTooltip(); }
private:
static bool isToggleButton (AccessibilityRole role) noexcept
{
return role == AccessibilityRole::toggleButton;
}
static bool isRadioButton (const Button& button) noexcept
{
return button.getRadioGroupId() != 0;
}
static AccessibilityActions getAccessibilityActions (Button& button, AccessibilityRole role)
{
auto actions = AccessibilityActions().addAction (AccessibilityActionType::press,
[&button] { button.triggerClick(); });
if (isToggleButton (role) || button.getClickingTogglesState())
actions = actions.addAction (AccessibilityActionType::toggle,
[&button] { button.setToggleState (! button.getToggleState(), sendNotification); });
return actions;
}
Button& button;
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ButtonAccessibilityHandler)
};
std::unique_ptr<AccessibilityHandler> Button::createAccessibilityHandler()
{
return std::make_unique<ButtonAccessibilityHandler> (*this, AccessibilityRole::button);
}
} // namespace juce

View File

@ -0,0 +1,528 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
/**
A base class for buttons.
This contains all the logic for button behaviours such as enabling/disabling,
responding to shortcut keystrokes, auto-repeating when held down, toggle-buttons
and radio groups, etc.
@see TextButton, DrawableButton, ToggleButton
@tags{GUI}
*/
class JUCE_API Button : public Component,
public SettableTooltipClient
{
protected:
//==============================================================================
/** Creates a button.
@param buttonName the text to put in the button (the component's name is also
initially set to this string, but these can be changed later
using the setName() and setButtonText() methods)
*/
explicit Button (const String& buttonName);
public:
/** Destructor. */
~Button() override;
//==============================================================================
/** Changes the button's text.
@see getButtonText
*/
void setButtonText (const String& newText);
/** Returns the text displayed in the button.
@see setButtonText
*/
const String& getButtonText() const { return text; }
//==============================================================================
/** Returns true if the button is currently being held down.
@see isOver
*/
bool isDown() const noexcept;
/** Returns true if the mouse is currently over the button.
This will be also be true if the button is being held down.
@see isDown
*/
bool isOver() const noexcept;
//==============================================================================
/** A button has an on/off state associated with it, and this changes that.
By default buttons are 'off' and for simple buttons that you click to perform
an action you won't change this. Toggle buttons, however will want to
change their state when turned on or off.
@param shouldBeOn whether to set the button's toggle state to be on or
off. If it's a member of a button group, this will
always try to turn it on, and to turn off any other
buttons in the group
@param notification determines the behaviour if the value changes - this
can invoke a synchronous call to clicked(), but
sendNotificationAsync is not supported
@see getToggleState, setRadioGroupId
*/
void setToggleState (bool shouldBeOn, NotificationType notification);
/** Returns true if the button is 'on'.
By default buttons are 'off' and for simple buttons that you click to perform
an action you won't change this. Toggle buttons, however will want to
change their state when turned on or off.
@see setToggleState
*/
bool getToggleState() const noexcept { return isOn.getValue(); }
/** Returns the Value object that represents the button's toggle state.
You can use this Value object to connect the button's state to external values or setters,
either by taking a copy of the Value, or by using Value::referTo() to make it point to
your own Value object.
@see getToggleState, Value
*/
Value& getToggleStateValue() noexcept { return isOn; }
/** This tells the button to automatically flip the toggle state when
the button is clicked.
If set to true, then before the clicked() callback occurs, the toggle-state
of the button is flipped.
*/
void setClickingTogglesState (bool shouldAutoToggleOnClick) noexcept;
/** Returns true if this button is set to be an automatic toggle-button.
This returns the last value that was passed to setClickingTogglesState().
*/
bool getClickingTogglesState() const noexcept;
//==============================================================================
/** Enables the button to act as a member of a mutually-exclusive group
of 'radio buttons'.
If the group ID is set to a non-zero number, then this button will
act as part of a group of buttons with the same ID, only one of
which can be 'on' at the same time. Note that when it's part of
a group, clicking a toggle-button that's 'on' won't turn it off.
To find other buttons with the same ID, this button will search through
its sibling components for ToggleButtons, so all the buttons for a
particular group must be placed inside the same parent component.
Set the group ID back to zero if you want it to act as a normal toggle
button again.
The notification argument lets you specify how other buttons should react
to being turned on or off in response to this call.
@see getRadioGroupId
*/
void setRadioGroupId (int newGroupId, NotificationType notification = sendNotification);
/** Returns the ID of the group to which this button belongs.
(See setRadioGroupId() for an explanation of this).
*/
int getRadioGroupId() const noexcept { return radioGroupId; }
//==============================================================================
/**
Used to receive callbacks when a button is clicked.
@see Button::addListener, Button::removeListener
*/
class JUCE_API Listener
{
public:
/** Destructor. */
virtual ~Listener() = default;
/** Called when the button is clicked. */
virtual void buttonClicked (Button*) = 0;
/** Called when the button's state changes. */
virtual void buttonStateChanged (Button*) {}
};
/** Registers a listener to receive events when this button's state changes.
If the listener is already registered, this will not register it again.
@see removeListener
*/
void addListener (Listener* newListener);
/** Removes a previously-registered button listener
@see addListener
*/
void removeListener (Listener* listener);
//==============================================================================
/** You can assign a lambda to this callback object to have it called when the button is clicked. */
std::function<void()> onClick;
/** You can assign a lambda to this callback object to have it called when the button's state changes. */
std::function<void()> onStateChange;
//==============================================================================
/** Causes the button to act as if it's been clicked.
This will asynchronously make the button draw itself going down and up, and
will then call back the clicked() method as if mouse was clicked on it.
@see clicked
*/
virtual void triggerClick();
//==============================================================================
/** Sets a command ID for this button to automatically invoke when it's clicked.
When the button is pressed, it will use the given manager to trigger the
command ID.
Obviously be careful that the ApplicationCommandManager doesn't get deleted
before this button is. To disable the command triggering, call this method and
pass nullptr as the command manager.
If generateTooltip is true, then the button's tooltip will be automatically
generated based on the name of this command and its current shortcut key.
@see addShortcut, getCommandID
*/
void setCommandToTrigger (ApplicationCommandManager* commandManagerToUse,
CommandID commandID,
bool generateTooltip);
/** Returns the command ID that was set by setCommandToTrigger(). */
CommandID getCommandID() const noexcept { return commandID; }
//==============================================================================
/** Assigns a shortcut key to trigger the button.
The button registers itself with its top-level parent component for keypresses.
Note that a different way of linking buttons to keypresses is by using the
setCommandToTrigger() method to invoke a command.
@see clearShortcuts
*/
void addShortcut (const KeyPress&);
/** Removes all key shortcuts that had been set for this button.
@see addShortcut
*/
void clearShortcuts();
/** Returns true if the given keypress is a shortcut for this button.
@see addShortcut
*/
bool isRegisteredForShortcut (const KeyPress&) const;
//==============================================================================
/** Sets an auto-repeat speed for the button when it is held down.
(Auto-repeat is disabled by default).
@param initialDelayInMillisecs how long to wait after the mouse is pressed before
triggering the next click. If this is zero, auto-repeat
is disabled
@param repeatDelayInMillisecs the frequently subsequent repeated clicks should be
triggered
@param minimumDelayInMillisecs if this is greater than 0, the auto-repeat speed will
get faster, the longer the button is held down, up to the
minimum interval specified here
*/
void setRepeatSpeed (int initialDelayInMillisecs,
int repeatDelayInMillisecs,
int minimumDelayInMillisecs = -1) noexcept;
/** Sets whether the button click should happen when the mouse is pressed or released.
By default the button is only considered to have been clicked when the mouse is
released, but setting this to true will make it call the clicked() method as soon
as the button is pressed.
This is useful if the button is being used to show a pop-up menu, as it allows
the click to be used as a drag onto the menu.
*/
void setTriggeredOnMouseDown (bool isTriggeredOnMouseDown) noexcept;
/** Returns whether the button click happens when the mouse is pressed or released.
@see setTriggeredOnMouseDown
*/
bool getTriggeredOnMouseDown() const noexcept;
/** Returns the number of milliseconds since the last time the button
went into the 'down' state.
*/
uint32 getMillisecondsSinceButtonDown() const noexcept;
//==============================================================================
/** Sets the tooltip for this button.
@see TooltipClient, TooltipWindow
*/
void setTooltip (const String& newTooltip) override;
//==============================================================================
/** A combination of these flags are used by setConnectedEdges(). */
enum ConnectedEdgeFlags
{
ConnectedOnLeft = 1,
ConnectedOnRight = 2,
ConnectedOnTop = 4,
ConnectedOnBottom = 8
};
/** Hints about which edges of the button might be connected to adjoining buttons.
The value passed in is a bitwise combination of any of the values in the
ConnectedEdgeFlags enum.
E.g. if you are placing two buttons adjacent to each other, you could use this to
indicate which edges are touching, and the LookAndFeel might choose to drawn them
without rounded corners on the edges that connect. It's only a hint, so the
LookAndFeel can choose to ignore it if it's not relevant for this type of
button.
*/
void setConnectedEdges (int connectedEdgeFlags);
/** Returns the set of flags passed into setConnectedEdges(). */
int getConnectedEdgeFlags() const noexcept { return connectedEdgeFlags; }
/** Indicates whether the button adjoins another one on its left edge.
@see setConnectedEdges
*/
bool isConnectedOnLeft() const noexcept { return (connectedEdgeFlags & ConnectedOnLeft) != 0; }
/** Indicates whether the button adjoins another one on its right edge.
@see setConnectedEdges
*/
bool isConnectedOnRight() const noexcept { return (connectedEdgeFlags & ConnectedOnRight) != 0; }
/** Indicates whether the button adjoins another one on its top edge.
@see setConnectedEdges
*/
bool isConnectedOnTop() const noexcept { return (connectedEdgeFlags & ConnectedOnTop) != 0; }
/** Indicates whether the button adjoins another one on its bottom edge.
@see setConnectedEdges
*/
bool isConnectedOnBottom() const noexcept { return (connectedEdgeFlags & ConnectedOnBottom) != 0; }
//==============================================================================
/** Used by setState(). */
enum ButtonState
{
buttonNormal,
buttonOver,
buttonDown
};
/** Can be used to force the button into a particular state.
This only changes the button's appearance, it won't trigger a click, or stop any mouse-clicks
from happening.
The state that you set here will only last until it is automatically changed when the mouse
enters or exits the button, or the mouse-button is pressed or released.
*/
void setState (ButtonState newState);
/** Returns the button's current over/down/up state. */
ButtonState getState() const noexcept { return buttonState; }
//==============================================================================
/** This abstract base class is implemented by LookAndFeel classes to provide
button-drawing functionality.
*/
struct JUCE_API LookAndFeelMethods
{
virtual ~LookAndFeelMethods() = default;
virtual void drawButtonBackground (Graphics&, Button&, const Colour& backgroundColour,
bool shouldDrawButtonAsHighlighted, bool shouldDrawButtonAsDown) = 0;
virtual Font getTextButtonFont (TextButton&, int buttonHeight) = 0;
virtual int getTextButtonWidthToFitText (TextButton&, int buttonHeight) = 0;
/** Draws the text for a TextButton. */
virtual void drawButtonText (Graphics&, TextButton&,
bool shouldDrawButtonAsHighlighted, bool shouldDrawButtonAsDown) = 0;
/** Draws the contents of a standard ToggleButton. */
virtual void drawToggleButton (Graphics&, ToggleButton&,
bool shouldDrawButtonAsHighlighted, bool shouldDrawButtonAsDown) = 0;
virtual void changeToggleButtonWidthToFitText (ToggleButton&) = 0;
virtual void drawTickBox (Graphics&, Component&, float x, float y, float w, float h,
bool ticked, bool isEnabled,
bool shouldDrawButtonAsHighlighted, bool shouldDrawButtonAsDown) = 0;
virtual void drawDrawableButton (Graphics&, DrawableButton&,
bool shouldDrawButtonAsHighlighted, bool shouldDrawButtonAsDown) = 0;
};
//==============================================================================
#ifndef DOXYGEN
[[deprecated ("This method's parameters have changed.")]]
void setToggleState (bool, bool);
#endif
protected:
//==============================================================================
/** This method is called when the button has been clicked.
Subclasses can override this to perform whatever actions they need to do.
In general, you wouldn't use this method to receive clicks, but should get your callbacks
by attaching a std::function to the onClick callback, or adding a Button::Listener.
@see triggerClick, onClick
*/
virtual void clicked();
/** This method is called when the button has been clicked.
By default it just calls clicked(), but you might want to override it to handle
things like clicking when a modifier key is pressed, etc.
@see ModifierKeys
*/
virtual void clicked (const ModifierKeys& modifiers);
/** Subclasses should override this to actually paint the button's contents.
It's better to use this than the paint method, because it gives you information
about the over/down state of the button.
@param g the graphics context to use
@param shouldDrawButtonAsHighlighted true if the button is either in the 'over' or 'down' state
@param shouldDrawButtonAsDown true if the button should be drawn in the 'down' position
*/
virtual void paintButton (Graphics& g,
bool shouldDrawButtonAsHighlighted,
bool shouldDrawButtonAsDown) = 0;
/** Called when the button's up/down/over state changes.
Subclasses can override this if they need to do something special when the button
goes up or down.
@see isDown, isOver
*/
virtual void buttonStateChanged();
//==============================================================================
/** @internal */
virtual void internalClickCallback (const ModifierKeys&);
/** @internal */
void handleCommandMessage (int commandId) override;
/** @internal */
void mouseEnter (const MouseEvent&) override;
/** @internal */
void mouseExit (const MouseEvent&) override;
/** @internal */
void mouseDown (const MouseEvent&) override;
/** @internal */
void mouseDrag (const MouseEvent&) override;
/** @internal */
void mouseUp (const MouseEvent&) override;
/** @internal */
bool keyPressed (const KeyPress&) override;
/** @internal */
using Component::keyStateChanged;
/** @internal */
void paint (Graphics&) override;
/** @internal */
void parentHierarchyChanged() override;
/** @internal */
void visibilityChanged() override;
/** @internal */
void focusGained (FocusChangeType) override;
/** @internal */
void focusLost (FocusChangeType) override;
/** @internal */
void enablementChanged() override;
private:
//==============================================================================
Array<KeyPress> shortcuts;
WeakReference<Component> keySource;
String text;
ListenerList<Listener> buttonListeners;
struct CallbackHelper;
std::unique_ptr<CallbackHelper> callbackHelper;
uint32 buttonPressTime = 0, lastRepeatTime = 0;
ApplicationCommandManager* commandManagerToUse = nullptr;
int autoRepeatDelay = -1, autoRepeatSpeed = 0, autoRepeatMinimumDelay = -1;
int radioGroupId = 0, connectedEdgeFlags = 0;
CommandID commandID = {};
ButtonState buttonState = buttonNormal, lastStatePainted = buttonNormal;
Value isOn;
bool lastToggleState = false;
bool clickTogglesState = false;
bool needsToRelease = false;
bool needsRepainting = false;
bool isKeyDown = false;
bool triggerOnMouseDown = false;
bool generateTooltip = false;
bool isInDraggableViewport = false ,isDraggingToScroll = false;
std::unique_ptr<AccessibilityHandler> createAccessibilityHandler() override;
void repeatTimerCallback();
bool keyStateChangedCallback();
void applicationCommandListChangeCallback();
void updateAutomaticTooltip (const ApplicationCommandInfo&);
ButtonState updateState();
ButtonState updateState (bool isOver, bool isDown);
bool isShortcutPressed() const;
void turnOffOtherButtonsInGroup (NotificationType click, NotificationType state);
void flashButtonState();
void sendClickMessage (const ModifierKeys&);
void sendStateMessage();
void setToggleState (bool shouldBeOn, NotificationType click, NotificationType state);
bool isMouseSourceOver (const MouseEvent& e);
bool isInDragToScrollViewport() const noexcept;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Button)
};
} // namespace juce

View File

@ -0,0 +1,253 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
DrawableButton::DrawableButton (const String& name, const DrawableButton::ButtonStyle buttonStyle)
: Button (name), style (buttonStyle)
{
}
DrawableButton::~DrawableButton()
{
}
//==============================================================================
static std::unique_ptr<Drawable> copyDrawableIfNotNull (const Drawable* const d)
{
if (d != nullptr)
return d->createCopy();
return {};
}
void DrawableButton::setImages (const Drawable* normal,
const Drawable* over,
const Drawable* down,
const Drawable* disabled,
const Drawable* normalOn,
const Drawable* overOn,
const Drawable* downOn,
const Drawable* disabledOn)
{
jassert (normal != nullptr); // you really need to give it at least a normal image..
normalImage = copyDrawableIfNotNull (normal);
overImage = copyDrawableIfNotNull (over);
downImage = copyDrawableIfNotNull (down);
disabledImage = copyDrawableIfNotNull (disabled);
normalImageOn = copyDrawableIfNotNull (normalOn);
overImageOn = copyDrawableIfNotNull (overOn);
downImageOn = copyDrawableIfNotNull (downOn);
disabledImageOn = copyDrawableIfNotNull (disabledOn);
currentImage = nullptr;
buttonStateChanged();
}
//==============================================================================
void DrawableButton::setButtonStyle (const DrawableButton::ButtonStyle newStyle)
{
if (style != newStyle)
{
style = newStyle;
buttonStateChanged();
}
}
void DrawableButton::setEdgeIndent (const int numPixelsIndent)
{
edgeIndent = numPixelsIndent;
repaint();
resized();
}
Rectangle<float> DrawableButton::getImageBounds() const
{
auto r = getLocalBounds();
if (style != ImageStretched)
{
auto indentX = jmin (edgeIndent, proportionOfWidth (0.3f));
auto indentY = jmin (edgeIndent, proportionOfHeight (0.3f));
if (shouldDrawButtonBackground())
{
indentX = jmax (getWidth() / 4, indentX);
indentY = jmax (getHeight() / 4, indentY);
}
else if (style == ImageAboveTextLabel)
{
r = r.withTrimmedBottom (jmin (16, proportionOfHeight (0.25f)));
}
else if (getStyle() == ImageBelowTextLabel)
{
r = r.withTrimmedTop (jmin (14, proportionOfHeight (0.25f)));
}
else if (getStyle() == ImageLeftOfTextLabel)
{
r = r.withTrimmedRight (proportionOfWidth (0.5f));
}
else if (getStyle() == ImageRightOfTextLabel)
{
r = r.withTrimmedLeft (proportionOfWidth (0.5f));
}
r = r.reduced (indentX, indentY);
}
return r.toFloat();
}
void DrawableButton::resized()
{
Button::resized();
if (currentImage != nullptr)
{
if (style != ImageRaw)
{
int transformFlags = 0;
if (style == ImageStretched)
{
transformFlags |= RectanglePlacement::stretchToFit;
}
else
{
transformFlags |= RectanglePlacement::centred;
if (style == ImageOnButtonBackgroundOriginalSize)
transformFlags |= RectanglePlacement::doNotResize;
}
currentImage->setTransformToFit (getImageBounds(), transformFlags);
}
}
}
void DrawableButton::buttonStateChanged()
{
repaint();
Drawable* imageToDraw = nullptr;
float opacity = 1.0f;
if (isEnabled())
{
imageToDraw = getCurrentImage();
}
else
{
imageToDraw = getToggleState() ? disabledImageOn.get()
: disabledImage.get();
if (imageToDraw == nullptr)
{
opacity = 0.4f;
imageToDraw = getNormalImage();
}
}
if (imageToDraw != currentImage)
{
removeChildComponent (currentImage);
currentImage = imageToDraw;
if (currentImage != nullptr)
{
currentImage->setInterceptsMouseClicks (false, false);
currentImage->setAccessible(false);
addAndMakeVisible (currentImage);
resized();
}
}
if (currentImage != nullptr)
currentImage->setAlpha (opacity);
}
void DrawableButton::enablementChanged()
{
Button::enablementChanged();
buttonStateChanged();
}
void DrawableButton::colourChanged()
{
repaint();
}
void DrawableButton::paintButton (Graphics& g,
const bool shouldDrawButtonAsHighlighted,
const bool shouldDrawButtonAsDown)
{
auto& lf = getLookAndFeel();
if (shouldDrawButtonBackground())
lf.drawButtonBackground (g, *this,
findColour (getToggleState() ? TextButton::buttonOnColourId
: TextButton::buttonColourId),
shouldDrawButtonAsHighlighted, shouldDrawButtonAsDown);
else
lf.drawDrawableButton (g, *this, shouldDrawButtonAsHighlighted, shouldDrawButtonAsDown);
}
//==============================================================================
Drawable* DrawableButton::getCurrentImage() const noexcept
{
if (isDown()) return getDownImage();
if (isOver()) return getOverImage();
return getNormalImage();
}
Drawable* DrawableButton::getNormalImage() const noexcept
{
return (getToggleState() && normalImageOn != nullptr) ? normalImageOn.get()
: normalImage.get();
}
Drawable* DrawableButton::getOverImage() const noexcept
{
if (getToggleState())
{
if (overImageOn != nullptr) return overImageOn.get();
if (normalImageOn != nullptr) return normalImageOn.get();
}
return overImage != nullptr ? overImage.get() : normalImage.get();
}
Drawable* DrawableButton::getDownImage() const noexcept
{
if (auto* d = getToggleState() ? downImageOn.get() : downImage.get())
return d;
return getOverImage();
}
} // namespace juce

View File

@ -0,0 +1,200 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
/**
A button that displays a Drawable.
Up to three Drawable objects can be given to this button, to represent the
'normal', 'over' and 'down' states.
@see Button
@tags{GUI}
*/
class JUCE_API DrawableButton : public Button
{
public:
//==============================================================================
enum ButtonStyle
{
ImageFitted, /**< The button will just display the images, but will resize and centre them to fit inside it. */
ImageRaw, /**< The button will just display the images in their normal size and position.
This leaves it up to the caller to make sure the images are the correct size and position for the button. */
ImageAboveTextLabel, /**< Draws the button as a text label across the bottom with the image resized and scaled to fit above it. */
ImageOnButtonBackground, /**< Draws the button as a standard rounded-rectangle button with the image on top. The image will be resized
to match the button's proportions.
Note that if you use this style, the colour IDs that control the button colour are
TextButton::buttonColourId and TextButton::buttonOnColourId. */
ImageOnButtonBackgroundOriginalSize, /** Same as ImageOnButtonBackground, but keeps the original image size. */
ImageStretched, /**< Fills the button with a stretched version of the image. */
ImageBelowTextLabel, /**< Draws the button as a text label across the top with the image resized and scaled to fit below it. */
ImageLeftOfTextLabel, /**< Draws the button as a text label on the right with the image resized and scaled to fit beside it. */
ImageRightOfTextLabel /**< Draws the button as a text label on the left with the image resized and scaled to fit beside it. */
};
//==============================================================================
/** Creates a DrawableButton.
After creating one of these, use setImages() to specify the drawables to use.
@param buttonName the name to give the component
@param buttonStyle the layout to use
@see ButtonStyle, setButtonStyle, setImages
*/
DrawableButton (const String& buttonName,
ButtonStyle buttonStyle);
/** Destructor. */
~DrawableButton() override;
//==============================================================================
/** Sets up the images to draw for the various button states.
The button will keep its own internal copies of these drawables.
@param normalImage the thing to draw for the button's 'normal' state. An internal copy
will be made of the object passed-in if it is non-null.
@param overImage the thing to draw for the button's 'over' state - if this is
null, the button's normal image will be used when the mouse is
over it. An internal copy will be made of the object passed-in
if it is non-null.
@param downImage the thing to draw for the button's 'down' state - if this is
null, the 'over' image will be used instead (or the normal image
as a last resort). An internal copy will be made of the object
passed-in if it is non-null.
@param disabledImage an image to draw when the button is disabled. If this is null,
the normal image will be drawn with a reduced opacity instead.
An internal copy will be made of the object passed-in if it is
non-null.
@param normalImageOn same as the normalImage, but this is used when the button's toggle
state is 'on'. If this is nullptr, the normal image is used instead
@param overImageOn same as the overImage, but this is used when the button's toggle
state is 'on'. If this is nullptr, the normalImageOn is drawn instead
@param downImageOn same as the downImage, but this is used when the button's toggle
state is 'on'. If this is nullptr, the overImageOn is drawn instead
@param disabledImageOn same as the disabledImage, but this is used when the button's toggle
state is 'on'. If this is nullptr, the normal image will be drawn instead
with a reduced opacity
*/
void setImages (const Drawable* normalImage,
const Drawable* overImage = nullptr,
const Drawable* downImage = nullptr,
const Drawable* disabledImage = nullptr,
const Drawable* normalImageOn = nullptr,
const Drawable* overImageOn = nullptr,
const Drawable* downImageOn = nullptr,
const Drawable* disabledImageOn = nullptr);
//==============================================================================
/** Changes the button's style.
@see ButtonStyle
*/
void setButtonStyle (ButtonStyle newStyle);
/** Returns the current style. */
ButtonStyle getStyle() const noexcept { return style; }
//==============================================================================
/** Gives the button an optional amount of space around the edge of the drawable.
By default there's a gap of about 3 pixels.
*/
void setEdgeIndent (int numPixelsIndent);
/** Returns the current edge indent size. */
int getEdgeIndent() const noexcept { return edgeIndent; }
//==============================================================================
/** Returns the image that the button is currently displaying. */
Drawable* getCurrentImage() const noexcept;
/** Returns the image that the button will use for its normal state. */
Drawable* getNormalImage() const noexcept;
/** Returns the image that the button will use when the mouse is over it. */
Drawable* getOverImage() const noexcept;
/** Returns the image that the button will use when the mouse is held down on it. */
Drawable* getDownImage() const noexcept;
/** Can be overridden to specify a custom position for the image within the button. */
virtual Rectangle<float> getImageBounds() const;
//==============================================================================
/** A set of colour IDs to use to change the colour of various aspects of the link.
These constants can be used either via the Component::setColour(), or LookAndFeel::setColour()
methods.
Note that when the ImageOnButtonBackground style is used, the colour IDs that control
the button colour are TextButton::buttonColourId and TextButton::buttonOnColourId.
@see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour
*/
enum ColourIds
{
textColourId = 0x1004010, /**< The colour to use for the button's text label. */
textColourOnId = 0x1004013, /**< The colour to use for the button's text when the button's toggle state is "on". */
backgroundColourId = 0x1004011, /**< The colour used to fill the button's background (when
the button is toggled 'off'). Note that if you use the
ImageOnButtonBackground style, you should use TextButton::buttonColourId
to change the button's colour. */
backgroundOnColourId = 0x1004012, /**< The colour used to fill the button's background (when
the button is toggled 'on'). Note that if you use the
ImageOnButtonBackground style, you should use TextButton::buttonOnColourId
to change the button's colour. */
};
//==============================================================================
/** @internal */
void paintButton (Graphics&, bool, bool) override;
/** @internal */
void buttonStateChanged() override;
/** @internal */
void resized() override;
/** @internal */
void enablementChanged() override;
/** @internal */
void colourChanged() override;
private:
//==============================================================================
bool shouldDrawButtonBackground() const { return style == ImageOnButtonBackground || style == ImageOnButtonBackgroundOriginalSize; }
//==============================================================================
ButtonStyle style;
std::unique_ptr<Drawable> normalImage, overImage, downImage, disabledImage,
normalImageOn, overImageOn, downImageOn, disabledImageOn;
Drawable* currentImage = nullptr;
int edgeIndent = 3;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DrawableButton)
};
} // namespace juce

View File

@ -0,0 +1,124 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
HyperlinkButton::HyperlinkButton (const String& linkText,
const URL& linkURL)
: Button (linkText),
url (linkURL),
font (14.0f, Font::underlined),
resizeFont (true),
justification (Justification::centred)
{
setMouseCursor (MouseCursor::PointingHandCursor);
setTooltip (linkURL.toString (false));
}
HyperlinkButton::HyperlinkButton()
: Button (String()),
font (14.0f, Font::underlined),
resizeFont (true),
justification (Justification::centred)
{
setMouseCursor (MouseCursor::PointingHandCursor);
}
HyperlinkButton::~HyperlinkButton()
{
}
//==============================================================================
void HyperlinkButton::setFont (const Font& newFont,
const bool resizeToMatchComponentHeight,
Justification justificationType)
{
font = newFont;
resizeFont = resizeToMatchComponentHeight;
justification = justificationType;
repaint();
}
void HyperlinkButton::setURL (const URL& newURL) noexcept
{
url = newURL;
setTooltip (newURL.toString (false));
}
Font HyperlinkButton::getFontToUse() const
{
if (resizeFont)
return font.withHeight ((float) getHeight() * 0.7f);
return font;
}
void HyperlinkButton::changeWidthToFitText()
{
setSize (getFontToUse().getStringWidth (getButtonText()) + 6, getHeight());
}
void HyperlinkButton::setJustificationType (Justification newJustification)
{
if (justification != newJustification)
{
justification = newJustification;
repaint();
}
}
void HyperlinkButton::colourChanged()
{
repaint();
}
//==============================================================================
void HyperlinkButton::clicked()
{
if (url.isWellFormed())
url.launchInDefaultBrowser();
}
void HyperlinkButton::paintButton (Graphics& g,
bool shouldDrawButtonAsHighlighted,
bool shouldDrawButtonAsDown)
{
const Colour textColour (findColour (textColourId));
if (isEnabled())
g.setColour ((shouldDrawButtonAsHighlighted) ? textColour.darker ((shouldDrawButtonAsDown) ? 1.3f : 0.4f)
: textColour);
else
g.setColour (textColour.withMultipliedAlpha (0.4f));
g.setFont (getFontToUse());
g.drawText (getButtonText(), getLocalBounds().reduced (1, 0),
justification.getOnlyHorizontalFlags() | Justification::verticallyCentred,
true);
}
} // namespace juce

View File

@ -0,0 +1,127 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
/**
A button showing an underlined weblink, that will launch the link
when it's clicked.
@see Button
@tags{GUI}
*/
class JUCE_API HyperlinkButton : public Button
{
public:
//==============================================================================
/** Creates a HyperlinkButton.
@param linkText the text that will be displayed in the button - this is
also set as the Component's name, but the text can be
changed later with the Button::setButtonText() method
@param linkURL the URL to launch when the user clicks the button
*/
HyperlinkButton (const String& linkText,
const URL& linkURL);
/** Creates a HyperlinkButton. */
HyperlinkButton();
/** Destructor. */
~HyperlinkButton() override;
//==============================================================================
/** Changes the font to use for the text.
If resizeToMatchComponentHeight is true, the font's height will be adjusted
to match the size of the component.
*/
void setFont (const Font& newFont,
bool resizeToMatchComponentHeight,
Justification justificationType = Justification::horizontallyCentred);
//==============================================================================
/** A set of colour IDs to use to change the colour of various aspects of the link.
These constants can be used either via the Component::setColour(), or LookAndFeel::setColour()
methods.
@see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour
*/
enum ColourIds
{
textColourId = 0x1001f00, /**< The colour to use for the URL text. */
};
//==============================================================================
/** Changes the URL that the button will trigger. */
void setURL (const URL& newURL) noexcept;
/** Returns the URL that the button will trigger. */
const URL& getURL() const noexcept { return url; }
//==============================================================================
/** Resizes the button horizontally to fit snugly around the text.
This won't affect the button's height.
*/
void changeWidthToFitText();
//==============================================================================
/** Sets the style of justification to be used for positioning the text.
(The default is Justification::centred)
*/
void setJustificationType (Justification justification);
/** Returns the type of justification, as set in setJustificationType(). */
Justification getJustificationType() const noexcept { return justification; }
protected:
//==============================================================================
/** @internal */
void clicked() override;
/** @internal */
void colourChanged() override;
/** @internal */
void paintButton (Graphics&, bool, bool) override;
private:
//==============================================================================
using Button::clicked;
Font getFontToUse() const;
//==============================================================================
URL url;
Font font;
bool resizeFont;
Justification justification;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (HyperlinkButton)
};
} // namespace juce

View File

@ -0,0 +1,208 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
ImageButton::ImageButton (const String& text_)
: Button (text_),
scaleImageToFit (true),
preserveProportions (true),
alphaThreshold (0)
{
}
ImageButton::~ImageButton()
{
}
void ImageButton::setImages (const bool resizeButtonNowToFitThisImage,
const bool rescaleImagesWhenButtonSizeChanges,
const bool preserveImageProportions,
const Image& normalImage_,
const float imageOpacityWhenNormal,
Colour overlayColourWhenNormal,
const Image& overImage_,
const float imageOpacityWhenOver,
Colour overlayColourWhenOver,
const Image& downImage_,
const float imageOpacityWhenDown,
Colour overlayColourWhenDown,
const float hitTestAlphaThreshold)
{
normalImage = normalImage_;
overImage = overImage_;
downImage = downImage_;
if (resizeButtonNowToFitThisImage && normalImage.isValid())
{
imageBounds.setSize (normalImage.getWidth(),
normalImage.getHeight());
setSize (imageBounds.getWidth(), imageBounds.getHeight());
}
scaleImageToFit = rescaleImagesWhenButtonSizeChanges;
preserveProportions = preserveImageProportions;
normalOpacity = imageOpacityWhenNormal;
normalOverlay = overlayColourWhenNormal;
overOpacity = imageOpacityWhenOver;
overOverlay = overlayColourWhenOver;
downOpacity = imageOpacityWhenDown;
downOverlay = overlayColourWhenDown;
alphaThreshold = (uint8) jlimit (0, 0xff, roundToInt (255.0f * hitTestAlphaThreshold));
repaint();
}
void ImageButton::setHitTestAlphaThreshold(float thresh)
{
alphaThreshold = (uint8) jlimit (0, 0xff, roundToInt (255.0f * thresh));
}
float ImageButton::getHitTestAlphaThreshold() const
{
return alphaThreshold / 255.0f;
}
Image ImageButton::getCurrentImage() const
{
if (isDown() || getToggleState())
return getDownImage();
if (isOver())
return getOverImage();
return getNormalImage();
}
Image ImageButton::getNormalImage() const
{
return normalImage;
}
Image ImageButton::getOverImage() const
{
return overImage.isValid() ? overImage
: normalImage;
}
Image ImageButton::getDownImage() const
{
return downImage.isValid() ? downImage
: getOverImage();
}
void ImageButton::paintButton (Graphics& g,
bool shouldDrawButtonAsHighlighted,
bool shouldDrawButtonAsDown)
{
if (! isEnabled())
{
shouldDrawButtonAsHighlighted = false;
shouldDrawButtonAsDown = false;
}
Image im (getCurrentImage());
if (im.isValid())
{
const int iw = im.getWidth();
const int ih = im.getHeight();
int w = getWidth();
int h = getHeight();
int x = (w - iw) / 2;
int y = (h - ih) / 2;
if (scaleImageToFit)
{
if (preserveProportions)
{
int newW, newH;
const float imRatio = (float) ih / (float) iw;
const float destRatio = (float) h / (float) w;
if (imRatio > destRatio)
{
newW = roundToInt ((float) h / imRatio);
newH = h;
}
else
{
newW = w;
newH = roundToInt ((float) w * imRatio);
}
x = (w - newW) / 2;
y = (h - newH) / 2;
w = newW;
h = newH;
}
else
{
x = 0;
y = 0;
}
}
if (! scaleImageToFit)
{
w = iw;
h = ih;
}
imageBounds.setBounds (x, y, w, h);
const bool useDownImage = shouldDrawButtonAsDown || getToggleState();
getLookAndFeel().drawImageButton (g, &im, x, y, w, h,
useDownImage ? downOverlay
: (shouldDrawButtonAsHighlighted ? overOverlay
: normalOverlay),
useDownImage ? downOpacity
: (shouldDrawButtonAsHighlighted ? overOpacity
: normalOpacity),
*this);
}
}
bool ImageButton::hitTest (int x, int y)
{
if (! Component::hitTest (x, y)) // handle setInterceptsMouseClicks
return false;
if (alphaThreshold == 0)
return true;
Image im (getCurrentImage());
return im.isNull() || ((! imageBounds.isEmpty())
&& alphaThreshold < im.getPixelAt (((x - imageBounds.getX()) * im.getWidth()) / imageBounds.getWidth(),
((y - imageBounds.getY()) * im.getHeight()) / imageBounds.getHeight()).getAlpha());
}
} // namespace juce

View File

@ -0,0 +1,164 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
/**
As the title suggests, this is a button containing an image.
The colour and transparency of the image can be set to vary when the
button state changes.
@see Button, ShapeButton, TextButton
@tags{GUI}
*/
class JUCE_API ImageButton : public Button
{
public:
//==============================================================================
/** Creates an ImageButton.
Use setImage() to specify the image to use. The colours and opacities that
are specified here can be changed later using setImages().
@param name the name to give the component
*/
explicit ImageButton (const String& name = String());
/** Destructor. */
~ImageButton() override;
//==============================================================================
/** Sets up the images to draw in various states.
@param resizeButtonNowToFitThisImage if true, the button will be immediately
resized to the same dimensions as the normal image
@param rescaleImagesWhenButtonSizeChanges if true, the image will be rescaled to fit the
button when the button's size changes
@param preserveImageProportions if true then any rescaling of the image to fit
the button will keep the image's x and y proportions
correct - i.e. it won't distort its shape, although
this might create gaps around the edges
@param normalImage the image to use when the button is in its normal state.
button no longer needs it.
@param imageOpacityWhenNormal the opacity to use when drawing the normal image.
@param overlayColourWhenNormal an overlay colour to use to fill the alpha channel of the
normal image - if this colour is transparent, no overlay
will be drawn. The overlay will be drawn over the top of the
image, so you can basically add a solid or semi-transparent
colour to the image to brighten or darken it
@param overImage the image to use when the mouse is over the button. If
you want to use the same image as was set in the normalImage
parameter, this value can be a null image.
@param imageOpacityWhenOver the opacity to use when drawing the image when the mouse
is over the button
@param overlayColourWhenOver an overlay colour to use to fill the alpha channel of the
image when the mouse is over - if this colour is transparent,
no overlay will be drawn
@param downImage an image to use when the button is pressed down. If set
to a null image, the 'over' image will be drawn instead (or the
normal image if there isn't an 'over' image either).
@param imageOpacityWhenDown the opacity to use when drawing the image when the button
is pressed
@param overlayColourWhenDown an overlay colour to use to fill the alpha channel of the
image when the button is pressed down - if this colour is
transparent, no overlay will be drawn
@param hitTestAlphaThreshold if set to zero, the mouse is considered to be over the button
whenever it's inside the button's bounding rectangle. If
set to values higher than 0, the mouse will only be
considered to be over the image when the value of the
image's alpha channel at that position is greater than
this level.
*/
void setImages (bool resizeButtonNowToFitThisImage,
bool rescaleImagesWhenButtonSizeChanges,
bool preserveImageProportions,
const Image& normalImage,
float imageOpacityWhenNormal,
Colour overlayColourWhenNormal,
const Image& overImage,
float imageOpacityWhenOver,
Colour overlayColourWhenOver,
const Image& downImage,
float imageOpacityWhenDown,
Colour overlayColourWhenDown,
float hitTestAlphaThreshold = 0.0f);
/** Returns the currently set 'normal' image. */
Image getNormalImage() const;
/** Returns the image that's drawn when the mouse is over the button.
If a valid 'over' image has been set, this will return it; otherwise it'll
just return the normal image.
*/
Image getOverImage() const;
/** Returns the image that's drawn when the button is held down.
If a valid 'down' image has been set, this will return it; otherwise it'll
return the 'over' image or normal image, depending on what's available.
*/
Image getDownImage() const;
void setHitTestAlphaThreshold(float thresh);
float getHitTestAlphaThreshold() const;
//==============================================================================
/** This abstract base class is implemented by LookAndFeel classes. */
struct JUCE_API LookAndFeelMethods
{
virtual ~LookAndFeelMethods() = default;
virtual void drawImageButton (Graphics&, Image*,
int imageX, int imageY, int imageW, int imageH,
const Colour& overlayColour, float imageOpacity, ImageButton&) = 0;
};
protected:
//==============================================================================
/** @internal */
bool hitTest (int x, int y) override;
/** @internal */
void paintButton (Graphics&, bool, bool) override;
private:
//==============================================================================
bool scaleImageToFit, preserveProportions;
uint8 alphaThreshold;
Rectangle<int> imageBounds;
Image normalImage, overImage, downImage;
float normalOpacity, overOpacity, downOpacity;
Colour normalOverlay, overOverlay, downOverlay;
Image getCurrentImage() const;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ImageButton)
};
} // namespace juce

View File

@ -0,0 +1,137 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
ShapeButton::ShapeButton (const String& t, Colour n, Colour o, Colour d)
: Button (t),
normalColour (n), overColour (o), downColour (d),
normalColourOn (n), overColourOn (o), downColourOn (d),
useOnColours(false),
maintainShapeProportions (false),
outlineWidth (0.0f)
{
}
ShapeButton::~ShapeButton() {}
void ShapeButton::setColours (Colour newNormalColour, Colour newOverColour, Colour newDownColour)
{
normalColour = newNormalColour;
overColour = newOverColour;
downColour = newDownColour;
}
void ShapeButton::setOnColours (Colour newNormalColourOn, Colour newOverColourOn, Colour newDownColourOn)
{
normalColourOn = newNormalColourOn;
overColourOn = newOverColourOn;
downColourOn = newDownColourOn;
}
void ShapeButton::shouldUseOnColours (bool shouldUse)
{
useOnColours = shouldUse;
}
void ShapeButton::setOutline (Colour newOutlineColour, const float newOutlineWidth)
{
outlineColour = newOutlineColour;
outlineWidth = newOutlineWidth;
}
void ShapeButton::setBorderSize (BorderSize<int> newBorder)
{
border = newBorder;
}
void ShapeButton::setShape (const Path& newShape,
const bool resizeNowToFitThisShape,
const bool maintainShapeProportions_,
const bool hasShadow)
{
shape = newShape;
maintainShapeProportions = maintainShapeProportions_;
shadow.setShadowProperties (DropShadow (Colours::black.withAlpha (0.5f), 3, Point<int>()));
setComponentEffect (hasShadow ? &shadow : nullptr);
if (resizeNowToFitThisShape)
{
auto newBounds = shape.getBounds();
if (hasShadow)
newBounds = newBounds.expanded (4.0f);
shape.applyTransform (AffineTransform::translation (-newBounds.getX(),
-newBounds.getY()));
setSize (1 + (int) (newBounds.getWidth() + outlineWidth) + border.getLeftAndRight(),
1 + (int) (newBounds.getHeight() + outlineWidth) + border.getTopAndBottom());
}
repaint();
}
void ShapeButton::paintButton (Graphics& g, bool shouldDrawButtonAsHighlighted, bool shouldDrawButtonAsDown)
{
if (! isEnabled())
{
shouldDrawButtonAsHighlighted = false;
shouldDrawButtonAsDown = false;
}
auto r = border.subtractedFrom (getLocalBounds())
.toFloat()
.reduced (outlineWidth * 0.5f);
if (getComponentEffect() != nullptr)
r = r.reduced (2.0f);
if (shouldDrawButtonAsDown)
{
const float sizeReductionWhenPressed = 0.04f;
r = r.reduced (sizeReductionWhenPressed * r.getWidth(),
sizeReductionWhenPressed * r.getHeight());
}
auto trans = shape.getTransformToScaleToFit (r, maintainShapeProportions);
if (shouldDrawButtonAsDown) g.setColour (getToggleState() && useOnColours ? downColourOn : downColour);
else if (shouldDrawButtonAsHighlighted) g.setColour (getToggleState() && useOnColours ? overColourOn : overColour);
else g.setColour (getToggleState() && useOnColours ? normalColourOn : normalColour);
g.fillPath (shape, trans);
if (outlineWidth > 0.0f)
{
g.setColour (outlineColour);
g.strokePath (shape, PathStrokeType (outlineWidth), trans);
}
}
} // namespace juce

View File

@ -0,0 +1,126 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
/**
A button that contains a filled shape.
@see Button, ImageButton, TextButton, ArrowButton
@tags{GUI}
*/
class JUCE_API ShapeButton : public Button
{
public:
//==============================================================================
/** Creates a ShapeButton.
@param name a name to give the component - see Component::setName()
@param normalColour the colour to fill the shape with when the mouse isn't over
@param overColour the colour to use when the mouse is over the shape
@param downColour the colour to use when the button is in the pressed-down state
*/
ShapeButton (const String& name,
Colour normalColour,
Colour overColour,
Colour downColour);
/** Destructor. */
~ShapeButton() override;
//==============================================================================
/** Sets the shape to use.
@param newShape the shape to use
@param resizeNowToFitThisShape if true, the button will be resized to fit the shape's bounds
@param maintainShapeProportions if true, the shape's proportions will be kept fixed when
the button is resized
@param hasDropShadow if true, the button will be given a drop-shadow effect
*/
void setShape (const Path& newShape,
bool resizeNowToFitThisShape,
bool maintainShapeProportions,
bool hasDropShadow);
/** Set the colours to use for drawing the shape.
@param normalColour the colour to fill the shape with when the mouse isn't over
@param overColour the colour to use when the mouse is over the shape
@param downColour the colour to use when the button is in the pressed-down state
*/
void setColours (Colour normalColour,
Colour overColour,
Colour downColour);
/** Sets the colours to use for drawing the shape when the button's toggle state is 'on'. To enable this behaviour, use the
shouldUseOnColours() method.
@param normalColourOn the colour to fill the shape with when the mouse isn't over and the button's toggle state is 'on'
@param overColourOn the colour to use when the mouse is over the shape and the button's toggle state is 'on'
@param downColourOn the colour to use when the button is in the pressed-down state and the button's toggle state is 'on'
*/
void setOnColours (Colour normalColourOn,
Colour overColourOn,
Colour downColourOn);
/** Set whether the button should use the 'on' set of colours when its toggle state is 'on'.
By default these will be the same as the normal colours but the setOnColours method can be
used to provide a different set of colours.
*/
void shouldUseOnColours (bool shouldUse);
/** Sets up an outline to draw around the shape.
@param outlineColour the colour to use
@param outlineStrokeWidth the thickness of line to draw
*/
void setOutline (Colour outlineColour, float outlineStrokeWidth);
/** This lets you specify a border to be left around the edge of the button when
drawing the shape.
*/
void setBorderSize (BorderSize<int> border);
/** @internal */
void paintButton (Graphics&, bool, bool) override;
private:
//==============================================================================
Colour normalColour, overColour, downColour,
normalColourOn, overColourOn, downColourOn, outlineColour;
bool useOnColours;
DropShadowEffect shadow;
Path shape;
BorderSize<int> border;
bool maintainShapeProportions;
float outlineWidth;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ShapeButton)
};
} // namespace juce

View File

@ -0,0 +1,77 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
TextButton::TextButton() : Button (String())
{
}
TextButton::TextButton (const String& name) : Button (name)
{
}
TextButton::TextButton (const String& name, const String& toolTip) : Button (name)
{
setTooltip (toolTip);
}
TextButton::~TextButton()
{
}
void TextButton::paintButton (Graphics& g, bool shouldDrawButtonAsHighlighted, bool shouldDrawButtonAsDown)
{
auto& lf = getLookAndFeel();
lf.drawButtonBackground (g, *this,
findColour (getToggleState() ? buttonOnColourId : buttonColourId),
shouldDrawButtonAsHighlighted, shouldDrawButtonAsDown);
lf.drawButtonText (g, *this, shouldDrawButtonAsHighlighted, shouldDrawButtonAsDown);
}
void TextButton::colourChanged()
{
repaint();
}
void TextButton::changeWidthToFitText()
{
changeWidthToFitText (getHeight());
}
void TextButton::changeWidthToFitText (const int newHeight)
{
setSize (getBestWidthForHeight (newHeight), newHeight);
}
int TextButton::getBestWidthForHeight (int buttonHeight)
{
return getLookAndFeel().getTextButtonWidthToFitText (*this, buttonHeight);
}
} // namespace juce

View File

@ -0,0 +1,109 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
/**
A button that uses the standard lozenge-shaped background with a line of
text on it.
@see Button, DrawableButton
@tags{GUI}
*/
class JUCE_API TextButton : public Button
{
public:
//==============================================================================
/** Creates a TextButton. */
TextButton();
/** Creates a TextButton.
@param buttonName the text to put in the button (the component's name is also
initially set to this string, but these can be changed later
using the setName() and setButtonText() methods)
*/
explicit TextButton (const String& buttonName);
/** Creates a TextButton.
@param buttonName the text to put in the button (the component's name is also
initially set to this string, but these can be changed later
using the setName() and setButtonText() methods)
@param toolTip an optional string to use as a tooltip
*/
TextButton (const String& buttonName, const String& toolTip);
/** Destructor. */
~TextButton() override;
//==============================================================================
/** A set of colour IDs to use to change the colour of various aspects of the button.
These constants can be used either via the Component::setColour(), or LookAndFeel::setColour()
methods.
@see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour
*/
enum ColourIds
{
buttonColourId = 0x1000100, /**< The colour used to fill the button shape (when the button is toggled
'off'). The look-and-feel class might re-interpret this to add
effects, etc. */
buttonOnColourId = 0x1000101, /**< The colour used to fill the button shape (when the button is toggled
'on'). The look-and-feel class might re-interpret this to add
effects, etc. */
textColourOffId = 0x1000102, /**< The colour to use for the button's text when the button's toggle state is "off". */
textColourOnId = 0x1000103 /**< The colour to use for the button's text.when the button's toggle state is "on". */
};
//==============================================================================
/** Changes this button's width to fit neatly around its current text, without
changing its height.
*/
void changeWidthToFitText();
/** Resizes the button's width to fit neatly around its current text, and gives it
the specified height.
*/
void changeWidthToFitText (int newHeight);
/** Returns the width that the LookAndFeel suggests would be best for this button if it
had the given height.
*/
int getBestWidthForHeight (int buttonHeight);
//==============================================================================
/** @internal */
void paintButton (Graphics&, bool, bool) override;
/** @internal */
void colourChanged() override;
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TextButton)
};
} // namespace juce

View File

@ -0,0 +1,65 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
ToggleButton::ToggleButton()
: Button (String())
{
setClickingTogglesState (true);
}
ToggleButton::ToggleButton (const String& buttonText)
: Button (buttonText)
{
setClickingTogglesState (true);
}
ToggleButton::~ToggleButton()
{
}
void ToggleButton::paintButton (Graphics& g, bool shouldDrawButtonAsHighlighted, bool shouldDrawButtonAsDown)
{
getLookAndFeel().drawToggleButton (g, *this, shouldDrawButtonAsHighlighted, shouldDrawButtonAsDown);
}
void ToggleButton::changeWidthToFitText()
{
getLookAndFeel().changeToggleButtonWidthToFitText (*this);
}
void ToggleButton::colourChanged()
{
repaint();
}
std::unique_ptr<AccessibilityHandler> ToggleButton::createAccessibilityHandler()
{
return std::make_unique<ButtonAccessibilityHandler> (*this, AccessibilityRole::toggleButton);
}
} // namespace juce

View File

@ -0,0 +1,92 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
/**
A button that can be toggled on/off.
All buttons can be toggle buttons, but this lets you create one of the
standard ones which has a tick-box and a text label next to it.
@see Button, DrawableButton, TextButton
@tags{GUI}
*/
class JUCE_API ToggleButton : public Button
{
public:
//==============================================================================
/** Creates a ToggleButton. */
ToggleButton();
/** Creates a ToggleButton.
@param buttonText the text to put in the button (the component's name is also
initially set to this string, but these can be changed later
using the setName() and setButtonText() methods)
*/
explicit ToggleButton (const String& buttonText);
/** Destructor. */
~ToggleButton() override;
//==============================================================================
/** Resizes the button to fit neatly around its current text.
The button's height won't be affected, only its width.
*/
void changeWidthToFitText();
//==============================================================================
/** A set of colour IDs to use to change the colour of various aspects of the button.
These constants can be used either via the Component::setColour(), or LookAndFeel::setColour()
methods.
@see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour
*/
enum ColourIds
{
textColourId = 0x1006501, /**< The colour to use for the button's text. */
tickColourId = 0x1006502, /**< The colour to use for the tick mark. */
tickDisabledColourId = 0x1006503 /**< The colour to use for the disabled tick mark and/or outline. */
};
protected:
//==============================================================================
/** @internal */
void paintButton (Graphics&, bool, bool) override;
/** @internal */
void colourChanged() override;
private:
std::unique_ptr<AccessibilityHandler> createAccessibilityHandler() override;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ToggleButton)
};
} // namespace juce

View File

@ -0,0 +1,113 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
ToolbarButton::ToolbarButton (const int iid, const String& buttonText,
std::unique_ptr<Drawable> normalIm,
std::unique_ptr<Drawable> toggledOnIm)
: ToolbarItemComponent (iid, buttonText, true),
normalImage (std::move (normalIm)),
toggledOnImage (std::move (toggledOnIm))
{
jassert (normalImage != nullptr);
}
ToolbarButton::~ToolbarButton()
{
}
//==============================================================================
bool ToolbarButton::getToolbarItemSizes (int toolbarDepth, bool /*isToolbarVertical*/, int& preferredSize, int& minSize, int& maxSize)
{
preferredSize = minSize = maxSize = toolbarDepth;
return true;
}
void ToolbarButton::paintButtonArea (Graphics&, int /*width*/, int /*height*/, bool /*isMouseOver*/, bool /*isMouseDown*/)
{
}
void ToolbarButton::contentAreaChanged (const Rectangle<int>&)
{
buttonStateChanged();
}
void ToolbarButton::setCurrentImage (Drawable* const newImage)
{
if (newImage != currentImage)
{
removeChildComponent (currentImage);
currentImage = newImage;
if (currentImage != nullptr)
{
enablementChanged();
addAndMakeVisible (currentImage);
updateDrawable();
}
}
}
void ToolbarButton::updateDrawable()
{
if (currentImage != nullptr)
{
currentImage->setInterceptsMouseClicks (false, false);
currentImage->setTransformToFit (getContentArea().toFloat(), RectanglePlacement::centred);
currentImage->setAlpha (isEnabled() ? 1.0f : 0.5f);
}
}
void ToolbarButton::resized()
{
ToolbarItemComponent::resized();
updateDrawable();
}
void ToolbarButton::enablementChanged()
{
ToolbarItemComponent::enablementChanged();
updateDrawable();
}
Drawable* ToolbarButton::getImageToUse() const
{
if (getStyle() == Toolbar::textOnly)
return nullptr;
if (getToggleState() && toggledOnImage != nullptr)
return toggledOnImage.get();
return normalImage.get();
}
void ToolbarButton::buttonStateChanged()
{
setCurrentImage (getImageToUse());
}
} // namespace juce

View File

@ -0,0 +1,98 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
/**
A type of button designed to go on a toolbar.
This simple button can have two Drawable objects specified - one for normal
use and another one (optionally) for the button's "on" state if it's a
toggle button.
@see Toolbar, ToolbarItemFactory, ToolbarItemComponent, Drawable, Button
@tags{GUI}
*/
class JUCE_API ToolbarButton : public ToolbarItemComponent
{
public:
//==============================================================================
/** Creates a ToolbarButton.
@param itemId the ID for this toolbar item type. This is passed through to the
ToolbarItemComponent constructor
@param labelText the text to display on the button (if the toolbar is using a style
that shows text labels). This is passed through to the
ToolbarItemComponent constructor
@param normalImage a drawable object that the button should use as its icon. The object
that is passed-in here will be kept by this object and will be
deleted when no longer needed or when this button is deleted.
@param toggledOnImage a drawable object that the button can use as its icon if the button
is in a toggled-on state (see the Button::getToggleState() method). If
nullptr is passed-in here, then the normal image will be used instead,
regardless of the toggle state. The object that is passed-in here will be
owned by this object and will be deleted when no longer needed or when
this button is deleted.
*/
ToolbarButton (int itemId,
const String& labelText,
std::unique_ptr<Drawable> normalImage,
std::unique_ptr<Drawable> toggledOnImage);
/** Destructor. */
~ToolbarButton() override;
//==============================================================================
/** @internal */
bool getToolbarItemSizes (int toolbarDepth, bool isToolbarVertical, int& preferredSize,
int& minSize, int& maxSize) override;
/** @internal */
void paintButtonArea (Graphics&, int width, int height, bool isMouseOver, bool isMouseDown) override;
/** @internal */
void contentAreaChanged (const Rectangle<int>&) override;
/** @internal */
void buttonStateChanged() override;
/** @internal */
void resized() override;
/** @internal */
void enablementChanged() override;
private:
//==============================================================================
std::unique_ptr<Drawable> normalImage, toggledOnImage;
Drawable* currentImage = nullptr;
void updateDrawable();
Drawable* getImageToUse() const;
void setCurrentImage (Drawable*);
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ToolbarButton)
};
} // namespace juce