1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-13 00:04:19 +00:00

Added Animated App template and examples

This commit is contained in:
Felix Faire 2014-10-29 15:55:23 +00:00
parent fefcf7aca6
commit ff6520a89a
1141 changed files with 438491 additions and 94 deletions

View file

@ -0,0 +1,48 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
AnimatedAppComponent::AnimatedAppComponent()
: lastUpdateTime (Time::getCurrentTime()), totalUpdates (0)
{
setOpaque (true);
}
void AnimatedAppComponent::setFramesPerSecond (int framesPerSecond)
{
jassert (framesPerSecond > 0 && framesPerSecond < 1000);
startTimer (1000 / framesPerSecond);
}
int AnimatedAppComponent::getMillisecondsSinceLastUpdate() const noexcept
{
return (int) (Time::getCurrentTime() - lastUpdateTime).inMilliseconds();
}
void AnimatedAppComponent::timerCallback()
{
++totalUpdates;
update();
repaint();
lastUpdateTime = Time::getCurrentTime();
}

View file

@ -0,0 +1,77 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
#ifndef JUCE_ANIMATEDAPPCOMPONENT_H_INCLUDED
#define JUCE_ANIMATEDAPPCOMPONENT_H_INCLUDED
//==============================================================================
/**
A base class for writing simple one-page graphical apps.
A subclass can inherit from this and implement just a few methods such as
paint() and mouse-handling. The base class provides some simple abstractions
to take care of continuously repainting itself.
*/
class AnimatedAppComponent : public Component,
private Timer
{
public:
AnimatedAppComponent();
/** Your subclass can call this to start a timer running which will
call update() and repaint the component at the given frequency.
*/
void setFramesPerSecond (int framesPerSecond);
/** Called periodically, at the frequency specified by setFramesPerSecond().
This is a the best place to do things like advancing animation parameters,
checking the mouse position, etc.
*/
virtual void update() = 0;
/** Returns the number of times that update() has been called since the component
started running.
*/
int getFrameCounter() const noexcept { return totalUpdates; }
/** When called from update(), this returns the number of milliseconds since the
last update call.
This might be useful for accurately timing animations, etc.
*/
int getMillisecondsSinceLastUpdate() const noexcept;
private:
//==============================================================================
Time lastUpdateTime;
int totalUpdates;
void timerCallback() override;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AnimatedAppComponent)
};
#endif // JUCE_ANIMATEDAPPCOMPONENT_H_INCLUDED

View file

@ -0,0 +1,114 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
#ifndef JUCE_APPLEREMOTE_H_INCLUDED
#define JUCE_APPLEREMOTE_H_INCLUDED
//==============================================================================
#if JUCE_MAC || DOXYGEN
/**
Receives events from an Apple IR remote control device (Only available in OSX!).
To use it, just create a subclass of this class, implementing the buttonPressed()
callback, then call start() and stop() to start or stop receiving events.
*/
class JUCE_API AppleRemoteDevice
{
public:
//==============================================================================
AppleRemoteDevice();
virtual ~AppleRemoteDevice();
//==============================================================================
/** The set of buttons that may be pressed.
@see buttonPressed
*/
enum ButtonType
{
menuButton = 0, /**< The menu button (if it's held for a short time). */
playButton, /**< The play button. */
plusButton, /**< The plus or volume-up button. */
minusButton, /**< The minus or volume-down button. */
rightButton, /**< The right button (if it's held for a short time). */
leftButton, /**< The left button (if it's held for a short time). */
rightButton_Long, /**< The right button (if it's held for a long time). */
leftButton_Long, /**< The menu button (if it's held for a long time). */
menuButton_Long, /**< The menu button (if it's held for a long time). */
playButtonSleepMode,
switched
};
//==============================================================================
/** Override this method to receive the callback about a button press.
The callback will happen on the application's message thread.
Some buttons trigger matching up and down events, in which the isDown parameter
will be true and then false. Others only send a single event when the
button is pressed.
*/
virtual void buttonPressed (ButtonType buttonId, bool isDown) = 0;
//==============================================================================
/** Starts the device running and responding to events.
Returns true if it managed to open the device.
@param inExclusiveMode if true, the remote will be grabbed exclusively for this app,
and will not be available to any other part of the system. If
false, it will be shared with other apps.
@see stop
*/
bool start (bool inExclusiveMode);
/** Stops the device running.
@see start
*/
void stop();
/** Returns true if the device has been started successfully.
*/
bool isActive() const;
/** Returns the ID number of the remote, if it has sent one.
*/
int getRemoteId() const { return remoteId; }
//==============================================================================
/** @internal */
void handleCallbackInternal();
private:
void* device;
void* queue;
int remoteId;
bool open (bool openInExclusiveMode);
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AppleRemoteDevice)
};
#endif
#endif // JUCE_APPLEREMOTE_H_INCLUDED

View file

@ -0,0 +1,118 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
BubbleMessageComponent::BubbleMessageComponent (int fadeOutLengthMs)
: fadeOutLength (fadeOutLengthMs), mouseClickCounter (0),
expiryTime (0), deleteAfterUse (false)
{
}
BubbleMessageComponent::~BubbleMessageComponent()
{
}
void BubbleMessageComponent::showAt (const Rectangle<int>& pos,
const AttributedString& text,
const int numMillisecondsBeforeRemoving,
const bool removeWhenMouseClicked,
const bool deleteSelfAfterUse)
{
createLayout (text);
setPosition (pos);
init (numMillisecondsBeforeRemoving, removeWhenMouseClicked, deleteSelfAfterUse);
}
void BubbleMessageComponent::showAt (Component* const component,
const AttributedString& text,
const int numMillisecondsBeforeRemoving,
const bool removeWhenMouseClicked,
const bool deleteSelfAfterUse)
{
createLayout (text);
setPosition (component);
init (numMillisecondsBeforeRemoving, removeWhenMouseClicked, deleteSelfAfterUse);
}
void BubbleMessageComponent::createLayout (const AttributedString& text)
{
textLayout.createLayoutWithBalancedLineLengths (text, 256);
}
void BubbleMessageComponent::init (const int numMillisecondsBeforeRemoving,
const bool removeWhenMouseClicked,
const bool deleteSelfAfterUse)
{
setAlpha (1.0f);
setVisible (true);
deleteAfterUse = deleteSelfAfterUse;
expiryTime = numMillisecondsBeforeRemoving > 0
? (Time::getMillisecondCounter() + (uint32) numMillisecondsBeforeRemoving) : 0;
mouseClickCounter = Desktop::getInstance().getMouseButtonClickCounter();
if (! (removeWhenMouseClicked && isShowing()))
mouseClickCounter += 0xfffff;
startTimer (77);
repaint();
}
const float bubblePaddingX = 20.0f;
const float bubblePaddingY = 14.0f;
void BubbleMessageComponent::getContentSize (int& w, int& h)
{
w = (int) (bubblePaddingX + textLayout.getWidth());
h = (int) (bubblePaddingY + textLayout.getHeight());
}
void BubbleMessageComponent::paintContent (Graphics& g, int w, int h)
{
g.setColour (findColour (TooltipWindow::textColourId));
textLayout.draw (g, Rectangle<float> (bubblePaddingX / 2.0f, bubblePaddingY / 2.0f,
w - bubblePaddingX, h - bubblePaddingY));
}
void BubbleMessageComponent::timerCallback()
{
if (Desktop::getInstance().getMouseButtonClickCounter() > mouseClickCounter)
hide (false);
else if (expiryTime != 0 && Time::getMillisecondCounter() > expiryTime)
hide (true);
}
void BubbleMessageComponent::hide (const bool fadeOut)
{
stopTimer();
if (fadeOut)
Desktop::getInstance().getAnimator().fadeOut (this, fadeOutLength);
else
setVisible (false);
if (deleteAfterUse)
delete this;
}

View file

@ -0,0 +1,132 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
#ifndef JUCE_BUBBLEMESSAGECOMPONENT_H_INCLUDED
#define JUCE_BUBBLEMESSAGECOMPONENT_H_INCLUDED
//==============================================================================
/**
A speech-bubble component that displays a short message.
This can be used to show a message with the tail of the speech bubble
pointing to a particular component or location on the screen.
@see BubbleComponent
*/
class JUCE_API BubbleMessageComponent : public BubbleComponent,
private Timer
{
public:
//==============================================================================
/** Creates a bubble component.
After creating one a BubbleComponent, do the following:
- add it to an appropriate parent component, or put it on the
desktop with Component::addToDesktop (0).
- use the showAt() method to show a message.
- it will make itself invisible after it times-out (and can optionally
also delete itself), or you can reuse it somewhere else by calling
showAt() again.
*/
BubbleMessageComponent (int fadeOutLengthMs = 150);
/** Destructor. */
~BubbleMessageComponent();
//==============================================================================
/** Shows a message bubble at a particular position.
This shows the bubble with its stem pointing to the given location
(coordinates being relative to its parent component).
For details about exactly how it decides where to position itself, see
BubbleComponent::updatePosition().
@param position the coords of the object to point to
@param message the text to display
@param numMillisecondsBeforeRemoving how long to leave it on the screen before removing itself
from its parent compnent. If this is 0 or less, it
will stay there until manually removed.
@param removeWhenMouseClicked if this is true, the bubble will disappear as soon as a
mouse button is pressed (anywhere on the screen)
@param deleteSelfAfterUse if true, then the component will delete itself after
it becomes invisible
*/
void showAt (const Rectangle<int>& position,
const AttributedString& message,
int numMillisecondsBeforeRemoving,
bool removeWhenMouseClicked = true,
bool deleteSelfAfterUse = false);
/** Shows a message bubble next to a particular component.
This shows the bubble with its stem pointing at the given component.
For details about exactly how it decides where to position itself, see
BubbleComponent::updatePosition().
@param component the component that you want to point at
@param message the text to display
@param numMillisecondsBeforeRemoving how long to leave it on the screen before removing itself
from its parent compnent. If this is 0 or less, it
will stay there until manually removed.
@param removeWhenMouseClicked if this is true, the bubble will disappear as soon as a
mouse button is pressed (anywhere on the screen)
@param deleteSelfAfterUse if true, then the component will delete itself after
it becomes invisible
*/
void showAt (Component* component,
const AttributedString& message,
int numMillisecondsBeforeRemoving,
bool removeWhenMouseClicked = true,
bool deleteSelfAfterUse = false);
//==============================================================================
/** @internal */
void getContentSize (int& w, int& h);
/** @internal */
void paintContent (Graphics& g, int w, int h);
/** @internal */
void timerCallback();
private:
//==============================================================================
int fadeOutLength, mouseClickCounter;
TextLayout textLayout;
int64 expiryTime;
bool deleteAfterUse;
void createLayout (const AttributedString&);
void init (int numMillisecondsBeforeRemoving,
bool removeWhenMouseClicked,
bool deleteSelfAfterUse);
void hide (bool fadeOut);
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (BubbleMessageComponent)
};
#endif // JUCE_BUBBLEMESSAGECOMPONENT_H_INCLUDED

View file

@ -0,0 +1,566 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
class ColourSelector::ColourComponentSlider : public Slider
{
public:
ColourComponentSlider (const String& name)
: Slider (name)
{
setRange (0.0, 255.0, 1.0);
}
String getTextFromValue (double value)
{
return String::toHexString ((int) value).toUpperCase().paddedLeft ('0', 2);
}
double getValueFromText (const String& text)
{
return (double) text.getHexValue32();
}
private:
JUCE_DECLARE_NON_COPYABLE (ColourComponentSlider)
};
//==============================================================================
class ColourSelector::ColourSpaceMarker : public Component
{
public:
ColourSpaceMarker()
{
setInterceptsMouseClicks (false, false);
}
void paint (Graphics& g) override
{
g.setColour (Colour::greyLevel (0.1f));
g.drawEllipse (1.0f, 1.0f, getWidth() - 2.0f, getHeight() - 2.0f, 1.0f);
g.setColour (Colour::greyLevel (0.9f));
g.drawEllipse (2.0f, 2.0f, getWidth() - 4.0f, getHeight() - 4.0f, 1.0f);
}
private:
JUCE_DECLARE_NON_COPYABLE (ColourSpaceMarker)
};
//==============================================================================
class ColourSelector::ColourSpaceView : public Component
{
public:
ColourSpaceView (ColourSelector& cs, float& hue, float& sat, float& val, const int edgeSize)
: owner (cs), h (hue), s (sat), v (val), lastHue (0.0f), edge (edgeSize)
{
addAndMakeVisible (marker);
setMouseCursor (MouseCursor::CrosshairCursor);
}
void paint (Graphics& g) override
{
if (colours.isNull())
{
const int width = getWidth() / 2;
const int height = getHeight() / 2;
colours = Image (Image::RGB, width, height, false);
Image::BitmapData pixels (colours, Image::BitmapData::writeOnly);
for (int y = 0; y < height; ++y)
{
const float val = 1.0f - y / (float) height;
for (int x = 0; x < width; ++x)
{
const float sat = x / (float) width;
pixels.setPixelColour (x, y, Colour (h, sat, val, 1.0f));
}
}
}
g.setOpacity (1.0f);
g.drawImageTransformed (colours,
RectanglePlacement (RectanglePlacement::stretchToFit)
.getTransformToFit (colours.getBounds().toFloat(),
getLocalBounds().reduced (edge).toFloat()),
false);
}
void mouseDown (const MouseEvent& e) override
{
mouseDrag (e);
}
void mouseDrag (const MouseEvent& e) override
{
const float sat = (e.x - edge) / (float) (getWidth() - edge * 2);
const float val = 1.0f - (e.y - edge) / (float) (getHeight() - edge * 2);
owner.setSV (sat, val);
}
void updateIfNeeded()
{
if (lastHue != h)
{
lastHue = h;
colours = Image::null;
repaint();
}
updateMarker();
}
void resized() override
{
colours = Image::null;
updateMarker();
}
private:
ColourSelector& owner;
float& h;
float& s;
float& v;
float lastHue;
ColourSpaceMarker marker;
const int edge;
Image colours;
void updateMarker()
{
marker.setBounds (roundToInt ((getWidth() - edge * 2) * s),
roundToInt ((getHeight() - edge * 2) * (1.0f - v)),
edge * 2, edge * 2);
}
JUCE_DECLARE_NON_COPYABLE (ColourSpaceView)
};
//==============================================================================
class ColourSelector::HueSelectorMarker : public Component
{
public:
HueSelectorMarker()
{
setInterceptsMouseClicks (false, false);
}
void paint (Graphics& g) override
{
const float cw = (float) getWidth();
const float ch = (float) getHeight();
Path p;
p.addTriangle (1.0f, 1.0f,
cw * 0.3f, ch * 0.5f,
1.0f, ch - 1.0f);
p.addTriangle (cw - 1.0f, 1.0f,
cw * 0.7f, ch * 0.5f,
cw - 1.0f, ch - 1.0f);
g.setColour (Colours::white.withAlpha (0.75f));
g.fillPath (p);
g.setColour (Colours::black.withAlpha (0.75f));
g.strokePath (p, PathStrokeType (1.2f));
}
private:
JUCE_DECLARE_NON_COPYABLE (HueSelectorMarker)
};
//==============================================================================
class ColourSelector::HueSelectorComp : public Component
{
public:
HueSelectorComp (ColourSelector& cs, float& hue, const int edgeSize)
: owner (cs), h (hue), edge (edgeSize)
{
addAndMakeVisible (marker);
}
void paint (Graphics& g) override
{
ColourGradient cg;
cg.isRadial = false;
cg.point1.setXY (0.0f, (float) edge);
cg.point2.setXY (0.0f, (float) (getHeight() - edge));
for (float i = 0.0f; i <= 1.0f; i += 0.02f)
cg.addColour (i, Colour (i, 1.0f, 1.0f, 1.0f));
g.setGradientFill (cg);
g.fillRect (getLocalBounds().reduced (edge));
}
void resized() override
{
marker.setBounds (0, roundToInt ((getHeight() - edge * 2) * h), getWidth(), edge * 2);
}
void mouseDown (const MouseEvent& e) override
{
mouseDrag (e);
}
void mouseDrag (const MouseEvent& e) override
{
owner.setHue ((e.y - edge) / (float) (getHeight() - edge * 2));
}
void updateIfNeeded()
{
resized();
}
private:
ColourSelector& owner;
float& h;
HueSelectorMarker marker;
const int edge;
JUCE_DECLARE_NON_COPYABLE (HueSelectorComp)
};
//==============================================================================
class ColourSelector::SwatchComponent : public Component
{
public:
SwatchComponent (ColourSelector& cs, int itemIndex)
: owner (cs), index (itemIndex)
{
}
void paint (Graphics& g) override
{
const Colour c (owner.getSwatchColour (index));
g.fillCheckerBoard (getLocalBounds(), 6, 6,
Colour (0xffdddddd).overlaidWith (c),
Colour (0xffffffff).overlaidWith (c));
}
void mouseDown (const MouseEvent&) override
{
PopupMenu m;
m.addItem (1, TRANS("Use this swatch as the current colour"));
m.addSeparator();
m.addItem (2, TRANS("Set this swatch to the current colour"));
m.showMenuAsync (PopupMenu::Options().withTargetComponent (this),
ModalCallbackFunction::forComponent (menuStaticCallback, this));
}
private:
ColourSelector& owner;
const int index;
static void menuStaticCallback (int result, SwatchComponent* comp)
{
if (comp != nullptr)
{
if (result == 1)
comp->setColourFromSwatch();
else if (result == 2)
comp->setSwatchFromColour();
}
}
void setColourFromSwatch()
{
owner.setCurrentColour (owner.getSwatchColour (index));
}
void setSwatchFromColour()
{
if (owner.getSwatchColour (index) != owner.getCurrentColour())
{
owner.setSwatchColour (index, owner.getCurrentColour());
repaint();
}
}
JUCE_DECLARE_NON_COPYABLE (SwatchComponent)
};
//==============================================================================
ColourSelector::ColourSelector (const int sectionsToShow, const int edge, const int gapAroundColourSpaceComponent)
: colour (Colours::white),
flags (sectionsToShow),
edgeGap (edge)
{
// not much point having a selector with no components in it!
jassert ((flags & (showColourAtTop | showSliders | showColourspace)) != 0);
updateHSV();
if ((flags & showSliders) != 0)
{
addAndMakeVisible (sliders[0] = new ColourComponentSlider (TRANS ("red")));
addAndMakeVisible (sliders[1] = new ColourComponentSlider (TRANS ("green")));
addAndMakeVisible (sliders[2] = new ColourComponentSlider (TRANS ("blue")));
addChildComponent (sliders[3] = new ColourComponentSlider (TRANS ("alpha")));
sliders[3]->setVisible ((flags & showAlphaChannel) != 0);
for (int i = 4; --i >= 0;)
sliders[i]->addListener (this);
}
if ((flags & showColourspace) != 0)
{
addAndMakeVisible (colourSpace = new ColourSpaceView (*this, h, s, v, gapAroundColourSpaceComponent));
addAndMakeVisible (hueSelector = new HueSelectorComp (*this, h, gapAroundColourSpaceComponent));
}
update();
}
ColourSelector::~ColourSelector()
{
dispatchPendingMessages();
swatchComponents.clear();
}
//==============================================================================
Colour ColourSelector::getCurrentColour() const
{
return ((flags & showAlphaChannel) != 0) ? colour : colour.withAlpha ((uint8) 0xff);
}
void ColourSelector::setCurrentColour (Colour c)
{
if (c != colour)
{
colour = ((flags & showAlphaChannel) != 0) ? c : c.withAlpha ((uint8) 0xff);
updateHSV();
update();
}
}
void ColourSelector::setHue (float newH)
{
newH = jlimit (0.0f, 1.0f, newH);
if (h != newH)
{
h = newH;
colour = Colour (h, s, v, colour.getFloatAlpha());
update();
}
}
void ColourSelector::setSV (float newS, float newV)
{
newS = jlimit (0.0f, 1.0f, newS);
newV = jlimit (0.0f, 1.0f, newV);
if (s != newS || v != newV)
{
s = newS;
v = newV;
colour = Colour (h, s, v, colour.getFloatAlpha());
update();
}
}
//==============================================================================
void ColourSelector::updateHSV()
{
colour.getHSB (h, s, v);
}
void ColourSelector::update()
{
if (sliders[0] != nullptr)
{
sliders[0]->setValue ((int) colour.getRed());
sliders[1]->setValue ((int) colour.getGreen());
sliders[2]->setValue ((int) colour.getBlue());
sliders[3]->setValue ((int) colour.getAlpha());
}
if (colourSpace != nullptr)
{
colourSpace->updateIfNeeded();
hueSelector->updateIfNeeded();
}
if ((flags & showColourAtTop) != 0)
repaint (previewArea);
sendChangeMessage();
}
//==============================================================================
void ColourSelector::paint (Graphics& g)
{
g.fillAll (findColour (backgroundColourId));
if ((flags & showColourAtTop) != 0)
{
const Colour currentColour (getCurrentColour());
g.fillCheckerBoard (previewArea, 10, 10,
Colour (0xffdddddd).overlaidWith (currentColour),
Colour (0xffffffff).overlaidWith (currentColour));
g.setColour (Colours::white.overlaidWith (currentColour).contrasting());
g.setFont (Font (14.0f, Font::bold));
g.drawText (currentColour.toDisplayString ((flags & showAlphaChannel) != 0),
previewArea, Justification::centred, false);
}
if ((flags & showSliders) != 0)
{
g.setColour (findColour (labelTextColourId));
g.setFont (11.0f);
for (int i = 4; --i >= 0;)
{
if (sliders[i]->isVisible())
g.drawText (sliders[i]->getName() + ":",
0, sliders[i]->getY(),
sliders[i]->getX() - 8, sliders[i]->getHeight(),
Justification::centredRight, false);
}
}
}
void ColourSelector::resized()
{
const int swatchesPerRow = 8;
const int swatchHeight = 22;
const int numSliders = ((flags & showAlphaChannel) != 0) ? 4 : 3;
const int numSwatches = getNumSwatches();
const int swatchSpace = numSwatches > 0 ? edgeGap + swatchHeight * ((numSwatches + 7) / swatchesPerRow) : 0;
const int sliderSpace = ((flags & showSliders) != 0) ? jmin (22 * numSliders + edgeGap, proportionOfHeight (0.3f)) : 0;
const int topSpace = ((flags & showColourAtTop) != 0) ? jmin (30 + edgeGap * 2, proportionOfHeight (0.2f)) : edgeGap;
previewArea.setBounds (edgeGap, edgeGap, getWidth() - edgeGap * 2, topSpace - edgeGap * 2);
int y = topSpace;
if ((flags & showColourspace) != 0)
{
const int hueWidth = jmin (50, proportionOfWidth (0.15f));
colourSpace->setBounds (edgeGap, y,
getWidth() - hueWidth - edgeGap - 4,
getHeight() - topSpace - sliderSpace - swatchSpace - edgeGap);
hueSelector->setBounds (colourSpace->getRight() + 4, y,
getWidth() - edgeGap - (colourSpace->getRight() + 4),
colourSpace->getHeight());
y = getHeight() - sliderSpace - swatchSpace - edgeGap;
}
if ((flags & showSliders) != 0)
{
const int sliderHeight = jmax (4, sliderSpace / numSliders);
for (int i = 0; i < numSliders; ++i)
{
sliders[i]->setBounds (proportionOfWidth (0.2f), y,
proportionOfWidth (0.72f), sliderHeight - 2);
y += sliderHeight;
}
}
if (numSwatches > 0)
{
const int startX = 8;
const int xGap = 4;
const int yGap = 4;
const int swatchWidth = (getWidth() - startX * 2) / swatchesPerRow;
y += edgeGap;
if (swatchComponents.size() != numSwatches)
{
swatchComponents.clear();
for (int i = 0; i < numSwatches; ++i)
{
SwatchComponent* const sc = new SwatchComponent (*this, i);
swatchComponents.add (sc);
addAndMakeVisible (sc);
}
}
int x = startX;
for (int i = 0; i < swatchComponents.size(); ++i)
{
SwatchComponent* const sc = swatchComponents.getUnchecked(i);
sc->setBounds (x + xGap / 2,
y + yGap / 2,
swatchWidth - xGap,
swatchHeight - yGap);
if (((i + 1) % swatchesPerRow) == 0)
{
x = startX;
y += swatchHeight;
}
else
{
x += swatchWidth;
}
}
}
}
void ColourSelector::sliderValueChanged (Slider*)
{
if (sliders[0] != nullptr)
setCurrentColour (Colour ((uint8) sliders[0]->getValue(),
(uint8) sliders[1]->getValue(),
(uint8) sliders[2]->getValue(),
(uint8) sliders[3]->getValue()));
}
//==============================================================================
int ColourSelector::getNumSwatches() const
{
return 0;
}
Colour ColourSelector::getSwatchColour (const int) const
{
jassertfalse; // if you've overridden getNumSwatches(), you also need to implement this method
return Colours::black;
}
void ColourSelector::setSwatchColour (const int, const Colour&) const
{
jassertfalse; // if you've overridden getNumSwatches(), you also need to implement this method
}

View file

@ -0,0 +1,171 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
#ifndef JUCE_COLOURSELECTOR_H_INCLUDED
#define JUCE_COLOURSELECTOR_H_INCLUDED
//==============================================================================
/**
A component that lets the user choose a colour.
This shows RGB sliders and a colourspace that the user can pick colours from.
This class is also a ChangeBroadcaster, so listeners can register to be told
when the colour changes.
*/
class JUCE_API ColourSelector : public Component,
public ChangeBroadcaster,
protected SliderListener
{
public:
//==============================================================================
/** Options for the type of selector to show. These are passed into the constructor. */
enum ColourSelectorOptions
{
showAlphaChannel = 1 << 0, /**< if set, the colour's alpha channel can be changed as well as its RGB. */
showColourAtTop = 1 << 1, /**< if set, a swatch of the colour is shown at the top of the component. */
showSliders = 1 << 2, /**< if set, RGB sliders are shown at the bottom of the component. */
showColourspace = 1 << 3 /**< if set, a big HSV selector is shown. */
};
//==============================================================================
/** Creates a ColourSelector object.
The flags are a combination of values from the ColourSelectorOptions enum, specifying
which of the selector's features should be visible.
The edgeGap value specifies the amount of space to leave around the edge.
gapAroundColourSpaceComponent indicates how much of a gap to put around the
colourspace and hue selector components.
*/
ColourSelector (int flags = (showAlphaChannel | showColourAtTop | showSliders | showColourspace),
int edgeGap = 4,
int gapAroundColourSpaceComponent = 7);
/** Destructor. */
~ColourSelector();
//==============================================================================
/** Returns the colour that the user has currently selected.
The ColourSelector class is also a ChangeBroadcaster, so listeners can
register to be told when the colour changes.
@see setCurrentColour
*/
Colour getCurrentColour() const;
/** Changes the colour that is currently being shown. */
void setCurrentColour (Colour newColour);
//==============================================================================
/** Tells the selector how many preset colour swatches you want to have on the component.
To enable swatches, you'll need to override getNumSwatches(), getSwatchColour(), and
setSwatchColour(), to return the number of colours you want, and to set and retrieve
their values.
*/
virtual int getNumSwatches() const;
/** Called by the selector to find out the colour of one of the swatches.
Your subclass should return the colour of the swatch with the given index.
To enable swatches, you'll need to override getNumSwatches(), getSwatchColour(), and
setSwatchColour(), to return the number of colours you want, and to set and retrieve
their values.
*/
virtual Colour getSwatchColour (int index) const;
/** Called by the selector when the user puts a new colour into one of the swatches.
Your subclass should change the colour of the swatch with the given index.
To enable swatches, you'll need to override getNumSwatches(), getSwatchColour(), and
setSwatchColour(), to return the number of colours you want, and to set and retrieve
their values.
*/
virtual void setSwatchColour (int index, const Colour& newColour) const;
//==============================================================================
/** A set of colour IDs to use to change the colour of various aspects of the keyboard.
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
{
backgroundColourId = 0x1007000, /**< the colour used to fill the component's background. */
labelTextColourId = 0x1007001 /**< the colour used for the labels next to the sliders. */
};
private:
//==============================================================================
class ColourSpaceView;
class HueSelectorComp;
class SwatchComponent;
class ColourComponentSlider;
class ColourSpaceMarker;
class HueSelectorMarker;
friend class ColourSpaceView;
friend struct ContainerDeletePolicy<ColourSpaceView>;
friend class HueSelectorComp;
friend struct ContainerDeletePolicy<HueSelectorComp>;
Colour colour;
float h, s, v;
ScopedPointer<Slider> sliders[4];
ScopedPointer<ColourSpaceView> colourSpace;
ScopedPointer<HueSelectorComp> hueSelector;
OwnedArray<SwatchComponent> swatchComponents;
const int flags;
int edgeGap;
Rectangle<int> previewArea;
void setHue (float newH);
void setSV (float newS, float newV);
void updateHSV();
void update();
void sliderValueChanged (Slider*);
void paint (Graphics&) override;
void resized() override;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ColourSelector)
#if JUCE_CATCH_DEPRECATED_CODE_MISUSE
// This constructor is here temporarily to prevent old code compiling, because the parameters
// have changed - if you get an error here, update your code to use the new constructor instead..
ColourSelector (bool);
#endif
};
#endif // JUCE_COLOURSELECTOR_H_INCLUDED

View file

@ -0,0 +1,472 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
class KeyMappingEditorComponent::ChangeKeyButton : public Button
{
public:
ChangeKeyButton (KeyMappingEditorComponent& kec, const CommandID command,
const String& keyName, const int keyIndex)
: Button (keyName),
owner (kec),
commandID (command),
keyNum (keyIndex)
{
setWantsKeyboardFocus (false);
setTriggeredOnMouseDown (keyNum >= 0);
setTooltip (keyIndex < 0 ? TRANS("Adds a new key-mapping")
: TRANS("Click to change this key-mapping"));
}
void paintButton (Graphics& g, bool /*isOver*/, bool /*isDown*/) override
{
getLookAndFeel().drawKeymapChangeButton (g, getWidth(), getHeight(), *this,
keyNum >= 0 ? getName() : String::empty);
}
static void menuCallback (int result, ChangeKeyButton* button)
{
if (button != nullptr)
{
switch (result)
{
case 1: button->assignNewKey(); break;
case 2: button->owner.getMappings().removeKeyPress (button->commandID, button->keyNum); break;
default: break;
}
}
}
void clicked() override
{
if (keyNum >= 0)
{
// existing key clicked..
PopupMenu m;
m.addItem (1, TRANS("Change this key-mapping"));
m.addSeparator();
m.addItem (2, TRANS("Remove this key-mapping"));
m.showMenuAsync (PopupMenu::Options(),
ModalCallbackFunction::forComponent (menuCallback, this));
}
else
{
assignNewKey(); // + button pressed..
}
}
void fitToContent (const int h) noexcept
{
if (keyNum < 0)
setSize (h, h);
else
setSize (jlimit (h * 4, h * 8, 6 + Font (h * 0.6f).getStringWidth (getName())), h);
}
//==============================================================================
class KeyEntryWindow : public AlertWindow
{
public:
KeyEntryWindow (KeyMappingEditorComponent& kec)
: AlertWindow (TRANS("New key-mapping"),
TRANS("Please press a key combination now..."),
AlertWindow::NoIcon),
owner (kec)
{
addButton (TRANS("OK"), 1);
addButton (TRANS("Cancel"), 0);
// (avoid return + escape keys getting processed by the buttons..)
for (int i = getNumChildComponents(); --i >= 0;)
getChildComponent (i)->setWantsKeyboardFocus (false);
setWantsKeyboardFocus (true);
grabKeyboardFocus();
}
bool keyPressed (const KeyPress& key) override
{
lastPress = key;
String message (TRANS("Key") + ": " + owner.getDescriptionForKeyPress (key));
const CommandID previousCommand = owner.getMappings().findCommandForKeyPress (key);
if (previousCommand != 0)
message << "\n\n("
<< TRANS("Currently assigned to \"CMDN\"")
.replace ("CMDN", TRANS (owner.getCommandManager().getNameOfCommand (previousCommand)))
<< ')';
setMessage (message);
return true;
}
bool keyStateChanged (bool) override
{
return true;
}
KeyPress lastPress;
private:
KeyMappingEditorComponent& owner;
JUCE_DECLARE_NON_COPYABLE (KeyEntryWindow)
};
static void assignNewKeyCallback (int result, ChangeKeyButton* button, KeyPress newKey)
{
if (result != 0 && button != nullptr)
button->setNewKey (newKey, true);
}
void setNewKey (const KeyPress& newKey, bool dontAskUser)
{
if (newKey.isValid())
{
const CommandID previousCommand = owner.getMappings().findCommandForKeyPress (newKey);
if (previousCommand == 0 || dontAskUser)
{
owner.getMappings().removeKeyPress (newKey);
if (keyNum >= 0)
owner.getMappings().removeKeyPress (commandID, keyNum);
owner.getMappings().addKeyPress (commandID, newKey, keyNum);
}
else
{
AlertWindow::showOkCancelBox (AlertWindow::WarningIcon,
TRANS("Change key-mapping"),
TRANS("This key is already assigned to the command \"CMDN\"")
.replace ("CMDN", owner.getCommandManager().getNameOfCommand (previousCommand))
+ "\n\n"
+ TRANS("Do you want to re-assign it to this new command instead?"),
TRANS("Re-assign"),
TRANS("Cancel"),
this,
ModalCallbackFunction::forComponent (assignNewKeyCallback,
this, KeyPress (newKey)));
}
}
}
static void keyChosen (int result, ChangeKeyButton* button)
{
if (result != 0 && button != nullptr && button->currentKeyEntryWindow != nullptr)
{
button->currentKeyEntryWindow->setVisible (false);
button->setNewKey (button->currentKeyEntryWindow->lastPress, false);
}
button->currentKeyEntryWindow = nullptr;
}
void assignNewKey()
{
currentKeyEntryWindow = new KeyEntryWindow (owner);
currentKeyEntryWindow->enterModalState (true, ModalCallbackFunction::forComponent (keyChosen, this));
}
private:
KeyMappingEditorComponent& owner;
const CommandID commandID;
const int keyNum;
ScopedPointer<KeyEntryWindow> currentKeyEntryWindow;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ChangeKeyButton)
};
//==============================================================================
class KeyMappingEditorComponent::ItemComponent : public Component
{
public:
ItemComponent (KeyMappingEditorComponent& kec, const CommandID command)
: owner (kec), commandID (command)
{
setInterceptsMouseClicks (false, true);
const bool isReadOnly = owner.isCommandReadOnly (commandID);
const Array<KeyPress> keyPresses (owner.getMappings().getKeyPressesAssignedToCommand (commandID));
for (int i = 0; i < jmin ((int) maxNumAssignments, keyPresses.size()); ++i)
addKeyPressButton (owner.getDescriptionForKeyPress (keyPresses.getReference (i)), i, isReadOnly);
addKeyPressButton (String::empty, -1, isReadOnly);
}
void addKeyPressButton (const String& desc, const int index, const bool isReadOnly)
{
ChangeKeyButton* const b = new ChangeKeyButton (owner, commandID, desc, index);
keyChangeButtons.add (b);
b->setEnabled (! isReadOnly);
b->setVisible (keyChangeButtons.size() <= (int) maxNumAssignments);
addChildComponent (b);
}
void paint (Graphics& g) override
{
g.setFont (getHeight() * 0.7f);
g.setColour (owner.findColour (KeyMappingEditorComponent::textColourId));
g.drawFittedText (TRANS (owner.getCommandManager().getNameOfCommand (commandID)),
4, 0, jmax (40, getChildComponent (0)->getX() - 5), getHeight(),
Justification::centredLeft, true);
}
void resized() override
{
int x = getWidth() - 4;
for (int i = keyChangeButtons.size(); --i >= 0;)
{
ChangeKeyButton* const b = keyChangeButtons.getUnchecked(i);
b->fitToContent (getHeight() - 2);
b->setTopRightPosition (x, 1);
x = b->getX() - 5;
}
}
private:
KeyMappingEditorComponent& owner;
OwnedArray<ChangeKeyButton> keyChangeButtons;
const CommandID commandID;
enum { maxNumAssignments = 3 };
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ItemComponent)
};
//==============================================================================
class KeyMappingEditorComponent::MappingItem : public TreeViewItem
{
public:
MappingItem (KeyMappingEditorComponent& kec, const CommandID command)
: owner (kec), commandID (command)
{}
String getUniqueName() const override { return String ((int) commandID) + "_id"; }
bool mightContainSubItems() override { return false; }
int getItemHeight() const override { return 20; }
Component* createItemComponent() override { return new ItemComponent (owner, commandID); }
private:
KeyMappingEditorComponent& owner;
const CommandID commandID;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MappingItem)
};
//==============================================================================
class KeyMappingEditorComponent::CategoryItem : public TreeViewItem
{
public:
CategoryItem (KeyMappingEditorComponent& kec, const String& name)
: owner (kec), categoryName (name)
{}
String getUniqueName() const override { return categoryName + "_cat"; }
bool mightContainSubItems() override { return true; }
int getItemHeight() const override { return 22; }
void paintItem (Graphics& g, int width, int height) override
{
g.setFont (Font (height * 0.7f, Font::bold));
g.setColour (owner.findColour (KeyMappingEditorComponent::textColourId));
g.drawText (TRANS (categoryName), 2, 0, width - 2, height, Justification::centredLeft, true);
}
void itemOpennessChanged (bool isNowOpen) override
{
if (isNowOpen)
{
if (getNumSubItems() == 0)
{
const Array<CommandID> commands (owner.getCommandManager().getCommandsInCategory (categoryName));
for (int i = 0; i < commands.size(); ++i)
if (owner.shouldCommandBeIncluded (commands.getUnchecked(i)))
addSubItem (new MappingItem (owner, commands.getUnchecked(i)));
}
}
else
{
clearSubItems();
}
}
private:
KeyMappingEditorComponent& owner;
String categoryName;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CategoryItem)
};
//==============================================================================
class KeyMappingEditorComponent::TopLevelItem : public TreeViewItem,
public ButtonListener,
private ChangeListener
{
public:
TopLevelItem (KeyMappingEditorComponent& kec) : owner (kec)
{
setLinesDrawnForSubItems (false);
owner.getMappings().addChangeListener (this);
}
~TopLevelItem()
{
owner.getMappings().removeChangeListener (this);
}
bool mightContainSubItems() { return true; }
String getUniqueName() const { return "keys"; }
void changeListenerCallback (ChangeBroadcaster*) override
{
const OpennessRestorer opennessRestorer (*this);
clearSubItems();
const StringArray categories (owner.getCommandManager().getCommandCategories());
for (int i = 0; i < categories.size(); ++i)
{
const Array<CommandID> commands (owner.getCommandManager().getCommandsInCategory (categories[i]));
int count = 0;
for (int j = 0; j < commands.size(); ++j)
if (owner.shouldCommandBeIncluded (commands.getUnchecked(j)))
++count;
if (count > 0)
addSubItem (new CategoryItem (owner, categories[i]));
}
}
static void resetToDefaultsCallback (int result, KeyMappingEditorComponent* owner)
{
if (result != 0 && owner != nullptr)
owner->getMappings().resetToDefaultMappings();
}
void buttonClicked (Button*) override
{
AlertWindow::showOkCancelBox (AlertWindow::QuestionIcon,
TRANS("Reset to defaults"),
TRANS("Are you sure you want to reset all the key-mappings to their default state?"),
TRANS("Reset"),
String::empty,
&owner,
ModalCallbackFunction::forComponent (resetToDefaultsCallback, &owner));
}
private:
KeyMappingEditorComponent& owner;
};
//==============================================================================
KeyMappingEditorComponent::KeyMappingEditorComponent (KeyPressMappingSet& mappingManager,
const bool showResetToDefaultButton)
: mappings (mappingManager),
resetButton (TRANS ("reset to defaults"))
{
treeItem = new TopLevelItem (*this);
if (showResetToDefaultButton)
{
addAndMakeVisible (resetButton);
resetButton.addListener (treeItem);
}
addAndMakeVisible (tree);
tree.setColour (TreeView::backgroundColourId, findColour (backgroundColourId));
tree.setRootItemVisible (false);
tree.setDefaultOpenness (true);
tree.setRootItem (treeItem);
tree.setIndentSize (12);
}
KeyMappingEditorComponent::~KeyMappingEditorComponent()
{
tree.setRootItem (nullptr);
}
//==============================================================================
void KeyMappingEditorComponent::setColours (Colour mainBackground,
Colour textColour)
{
setColour (backgroundColourId, mainBackground);
setColour (textColourId, textColour);
tree.setColour (TreeView::backgroundColourId, mainBackground);
}
void KeyMappingEditorComponent::parentHierarchyChanged()
{
treeItem->changeListenerCallback (nullptr);
}
void KeyMappingEditorComponent::resized()
{
int h = getHeight();
if (resetButton.isVisible())
{
const int buttonHeight = 20;
h -= buttonHeight + 8;
int x = getWidth() - 8;
resetButton.changeWidthToFitText (buttonHeight);
resetButton.setTopRightPosition (x, h + 6);
}
tree.setBounds (0, 0, getWidth(), h);
}
//==============================================================================
bool KeyMappingEditorComponent::shouldCommandBeIncluded (const CommandID commandID)
{
const ApplicationCommandInfo* const ci = mappings.getCommandManager().getCommandForID (commandID);
return ci != nullptr && (ci->flags & ApplicationCommandInfo::hiddenFromKeyEditor) == 0;
}
bool KeyMappingEditorComponent::isCommandReadOnly (const CommandID commandID)
{
const ApplicationCommandInfo* const ci = mappings.getCommandManager().getCommandForID (commandID);
return ci != nullptr && (ci->flags & ApplicationCommandInfo::readOnlyInKeyEditor) != 0;
}
String KeyMappingEditorComponent::getDescriptionForKeyPress (const KeyPress& key)
{
return key.getTextDescription();
}

View file

@ -0,0 +1,136 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
#ifndef JUCE_KEYMAPPINGEDITORCOMPONENT_H_INCLUDED
#define JUCE_KEYMAPPINGEDITORCOMPONENT_H_INCLUDED
//==============================================================================
/**
A component to allow editing of the keymaps stored by a KeyPressMappingSet
object.
@see KeyPressMappingSet
*/
class JUCE_API KeyMappingEditorComponent : public Component
{
public:
//==============================================================================
/** Creates a KeyMappingEditorComponent.
@param mappingSet this is the set of mappings to display and edit. Make sure the
mappings object is not deleted before this component!
@param showResetToDefaultButton if true, then at the bottom of the list, the
component will include a 'reset to defaults' button.
*/
KeyMappingEditorComponent (KeyPressMappingSet& mappingSet,
bool showResetToDefaultButton);
/** Destructor. */
~KeyMappingEditorComponent();
//==============================================================================
/** Sets up the colours to use for parts of the component.
@param mainBackground colour to use for most of the background
@param textColour colour to use for the text
*/
void setColours (Colour mainBackground,
Colour textColour);
/** Returns the KeyPressMappingSet that this component is acting upon. */
KeyPressMappingSet& getMappings() const noexcept { return mappings; }
/** Returns the ApplicationCommandManager that this component is connected to. */
ApplicationCommandManager& getCommandManager() const noexcept { return mappings.getCommandManager(); }
//==============================================================================
/** Can be overridden if some commands need to be excluded from the list.
By default this will use the KeyPressMappingSet's shouldCommandBeVisibleInEditor()
method to decide what to return, but you can override it to handle special cases.
*/
virtual bool shouldCommandBeIncluded (CommandID commandID);
/** Can be overridden to indicate that some commands are shown as read-only.
By default this will use the KeyPressMappingSet's shouldCommandBeReadOnlyInEditor()
method to decide what to return, but you can override it to handle special cases.
*/
virtual bool isCommandReadOnly (CommandID commandID);
/** This can be overridden to let you change the format of the string used
to describe a keypress.
This is handy if you're using non-standard KeyPress objects, e.g. for custom
keys that are triggered by something else externally. If you override the
method, be sure to let the base class's method handle keys you're not
interested in.
*/
virtual String getDescriptionForKeyPress (const KeyPress& key);
//==============================================================================
/** A set of colour IDs to use to change the colour of various aspects of the editor.
These constants can be used either via the Component::setColour(), or LookAndFeel::setColour()
methods.
To change the colours of the menu that pops up
@see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour
*/
enum ColourIds
{
backgroundColourId = 0x100ad00, /**< The background colour to fill the editor background. */
textColourId = 0x100ad01, /**< The colour for the text. */
};
//==============================================================================
/** @internal */
void parentHierarchyChanged() override;
/** @internal */
void resized() override;
private:
//==============================================================================
KeyPressMappingSet& mappings;
TreeView tree;
TextButton resetButton;
class TopLevelItem;
class ChangeKeyButton;
class MappingItem;
class CategoryItem;
class ItemComponent;
friend class TopLevelItem;
friend struct ContainerDeletePolicy<ChangeKeyButton>;
friend struct ContainerDeletePolicy<TopLevelItem>;
ScopedPointer<TopLevelItem> treeItem;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (KeyMappingEditorComponent)
};
#endif // JUCE_KEYMAPPINGEDITORCOMPONENT_H_INCLUDED

View file

@ -0,0 +1,474 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
#if JUCE_ENABLE_LIVE_CONSTANT_EDITOR
namespace LiveConstantEditor
{
//==============================================================================
class AllComponentRepainter : private Timer,
private DeletedAtShutdown
{
public:
AllComponentRepainter() {}
static AllComponentRepainter& getInstance()
{
static AllComponentRepainter* instance = new AllComponentRepainter();
return *instance;
}
void trigger()
{
if (! isTimerRunning())
startTimer (100);
}
private:
void timerCallback() override
{
stopTimer();
for (int i = TopLevelWindow::getNumTopLevelWindows(); --i >= 0;)
if (Component* c = TopLevelWindow::getTopLevelWindow(i))
repaintAndResizeAllComps (c);
}
static void repaintAndResizeAllComps (Component::SafePointer<Component> c)
{
if (c->isVisible())
{
c->repaint();
c->resized();
for (int i = c->getNumChildComponents(); --i >= 0;)
if (c != nullptr)
if (Component* child = c->getChildComponent(i))
repaintAndResizeAllComps (child);
}
}
};
//==============================================================================
int64 parseInt (String s)
{
s = s.retainCharacters ("0123456789abcdefABCDEFx");
if (s.startsWith ("0x"))
return s.substring(2).getHexValue64();
return s.getLargeIntValue();
}
double parseDouble (const String& s)
{
return s.retainCharacters ("0123456789.eE-").getDoubleValue();
}
String intToString (int v, bool preferHex) { return preferHex ? "0x" + String::toHexString (v) : String (v); }
String intToString (int64 v, bool preferHex) { return preferHex ? "0x" + String::toHexString (v) : String (v); }
//==============================================================================
LiveValueBase::LiveValueBase (const char* file, int line)
: sourceFile (file), sourceLine (line)
{
name = File (sourceFile).getFileName() + " : " + String (sourceLine);
}
LiveValueBase::~LiveValueBase()
{
}
//==============================================================================
LivePropertyEditorBase::LivePropertyEditorBase (LiveValueBase& v, CodeDocument& d)
: value (v), resetButton ("reset"), document (d), sourceEditor (document, &tokeniser), wasHex (false)
{
setSize (600, 100);
addAndMakeVisible (name);
addAndMakeVisible (resetButton);
addAndMakeVisible (valueEditor);
addAndMakeVisible (sourceEditor);
findOriginalValueInCode();
selectOriginalValue();
name.setFont (13.0f);
name.setText (v.name, dontSendNotification);
valueEditor.setMultiLine (v.isString());
valueEditor.setReturnKeyStartsNewLine (v.isString());
valueEditor.setText (v.getStringValue (wasHex), dontSendNotification);
valueEditor.addListener (this);
sourceEditor.setReadOnly (true);
resetButton.addListener (this);
}
void LivePropertyEditorBase::paint (Graphics& g)
{
g.setColour (Colours::white);
g.fillRect (getLocalBounds().removeFromBottom (1));
}
void LivePropertyEditorBase::resized()
{
Rectangle<int> r (getLocalBounds().reduced (0, 3).withTrimmedBottom (1));
Rectangle<int> left (r.removeFromLeft (jmax (200, r.getWidth() / 3)));
Rectangle<int> top (left.removeFromTop (25));
resetButton.setBounds (top.removeFromRight (35).reduced (0, 3));
name.setBounds (top);
if (customComp != nullptr)
{
valueEditor.setBounds (left.removeFromTop (25));
left.removeFromTop (2);
customComp->setBounds (left);
}
else
{
valueEditor.setBounds (left);
}
r.removeFromLeft (4);
sourceEditor.setBounds (r);
}
void LivePropertyEditorBase::textEditorTextChanged (TextEditor&)
{
applyNewValue (valueEditor.getText());
}
void LivePropertyEditorBase::buttonClicked (Button*)
{
applyNewValue (value.getOriginalStringValue (wasHex));
}
void LivePropertyEditorBase::applyNewValue (const String& s)
{
value.setStringValue (s);
document.replaceSection (valueStart.getPosition(), valueEnd.getPosition(), value.getCodeValue (wasHex));
document.clearUndoHistory();
selectOriginalValue();
valueEditor.setText (s, dontSendNotification);
AllComponentRepainter::getInstance().trigger();
}
void LivePropertyEditorBase::selectOriginalValue()
{
sourceEditor.selectRegion (valueStart, valueEnd);
}
void LivePropertyEditorBase::findOriginalValueInCode()
{
CodeDocument::Position pos (document, value.sourceLine, 0);
String line (pos.getLineText());
String::CharPointerType p (line.getCharPointer());
p = CharacterFunctions::find (p, CharPointer_ASCII ("JUCE_LIVE_CONSTANT"));
if (p.isEmpty())
{
// Not sure how this would happen - some kind of mix-up between source code and line numbers..
jassertfalse;
return;
}
p += (int) (sizeof ("JUCE_LIVE_CONSTANT") - 1);
p = p.findEndOfWhitespace();
if (! CharacterFunctions::find (p, CharPointer_ASCII ("JUCE_LIVE_CONSTANT")).isEmpty())
{
// Aargh! You've added two JUCE_LIVE_CONSTANT macros on the same line!
// They're identified by their line number, so you must make sure each
// one goes on a separate line!
jassertfalse;
}
if (p.getAndAdvance() == '(')
{
String::CharPointerType start (p), end (p);
int depth = 1;
while (! end.isEmpty())
{
const juce_wchar c = end.getAndAdvance();
if (c == '(') ++depth;
if (c == ')') --depth;
if (depth == 0)
{
--end;
break;
}
}
if (end > start)
{
valueStart = CodeDocument::Position (document, value.sourceLine, (int) (start - line.getCharPointer()));
valueEnd = CodeDocument::Position (document, value.sourceLine, (int) (end - line.getCharPointer()));
valueStart.setPositionMaintained (true);
valueEnd.setPositionMaintained (true);
wasHex = String (start, end).containsIgnoreCase ("0x");
}
}
}
//==============================================================================
class ValueListHolderComponent : public Component
{
public:
ValueListHolderComponent (ValueList& l) : valueList (l)
{
setVisible (true);
}
void addItem (int width, LiveValueBase& v, CodeDocument& doc)
{
addAndMakeVisible (editors.add (v.createPropertyComponent (doc)));
layout (width);
}
void layout (int width)
{
setSize (width, editors.size() * itemHeight);
resized();
}
void resized() override
{
Rectangle<int> r (getLocalBounds().reduced (2, 0));
for (int i = 0; i < editors.size(); ++i)
editors.getUnchecked(i)->setBounds (r.removeFromTop (itemHeight));
}
enum { itemHeight = 120 };
ValueList& valueList;
OwnedArray<LivePropertyEditorBase> editors;
};
//==============================================================================
class ValueList::EditorWindow : public DocumentWindow,
private DeletedAtShutdown
{
public:
EditorWindow (ValueList& list)
: DocumentWindow ("Live Values", Colours::lightgrey, DocumentWindow::closeButton)
{
setLookAndFeel (&lookAndFeel);
setUsingNativeTitleBar (true);
viewport.setViewedComponent (new ValueListHolderComponent (list), true);
viewport.setSize (700, 600);
viewport.setScrollBarsShown (true, false);
setContentNonOwned (&viewport, true);
setResizable (true, false);
setResizeLimits (500, 400, 10000, 10000);
centreWithSize (getWidth(), getHeight());
setVisible (true);
}
void closeButtonPressed() override
{
setVisible (false);
}
void updateItems (ValueList& list)
{
if (ValueListHolderComponent* l = dynamic_cast<ValueListHolderComponent*> (viewport.getViewedComponent()))
{
while (l->getNumChildComponents() < list.values.size())
{
if (LiveValueBase* v = list.values [l->getNumChildComponents()])
l->addItem (viewport.getMaximumVisibleWidth(), *v, list.getDocument (v->sourceFile));
else
break;
}
setVisible (true);
}
}
void resized() override
{
DocumentWindow::resized();
if (ValueListHolderComponent* l = dynamic_cast<ValueListHolderComponent*> (viewport.getViewedComponent()))
l->layout (viewport.getMaximumVisibleWidth());
}
Viewport viewport;
LookAndFeel_V3 lookAndFeel;
};
//==============================================================================
ValueList::ValueList() {}
ValueList::~ValueList() {}
ValueList& ValueList::getInstance()
{
static ValueList* i = new ValueList();
return *i;
}
void ValueList::addValue (LiveValueBase* v)
{
values.add (v);
triggerAsyncUpdate();
}
void ValueList::handleAsyncUpdate()
{
if (editorWindow == nullptr)
editorWindow = new EditorWindow (*this);
editorWindow->updateItems (*this);
}
CodeDocument& ValueList::getDocument (const File& file)
{
const int index = documentFiles.indexOf (file.getFullPathName());
if (index >= 0)
return *documents.getUnchecked (index);
CodeDocument* doc = documents.add (new CodeDocument());
documentFiles.add (file);
doc->replaceAllContent (file.loadFileAsString());
doc->clearUndoHistory();
return *doc;
}
//==============================================================================
struct ColourEditorComp : public Component,
private ChangeListener
{
ColourEditorComp (LivePropertyEditorBase& e) : editor (e)
{
setMouseCursor (MouseCursor::PointingHandCursor);
}
Colour getColour() const
{
return Colour ((uint32) parseInt (editor.value.getStringValue (false)));
}
void paint (Graphics& g) override
{
g.fillCheckerBoard (getLocalBounds(), 6, 6,
Colour (0xffdddddd).overlaidWith (getColour()),
Colour (0xffffffff).overlaidWith (getColour()));
}
void mouseDown (const MouseEvent&) override
{
ColourSelector* colourSelector = new ColourSelector();
colourSelector->setName ("Colour");
colourSelector->setCurrentColour (getColour());
colourSelector->addChangeListener (this);
colourSelector->setColour (ColourSelector::backgroundColourId, Colours::transparentBlack);
colourSelector->setSize (300, 400);
CallOutBox::launchAsynchronously (colourSelector, getScreenBounds(), nullptr);
}
void changeListenerCallback (ChangeBroadcaster* source) override
{
if (ColourSelector* cs = dynamic_cast<ColourSelector*> (source))
editor.applyNewValue (getAsString (cs->getCurrentColour(), true));
repaint();
}
LivePropertyEditorBase& editor;
};
Component* createColourEditor (LivePropertyEditorBase& editor)
{
return new ColourEditorComp (editor);
}
//==============================================================================
class SliderComp : public Component,
private Slider::Listener
{
public:
SliderComp (LivePropertyEditorBase& e, bool useFloat)
: editor (e), isFloat (useFloat)
{
slider.setTextBoxStyle (Slider::NoTextBox, true, 0, 0);
addAndMakeVisible (slider);
updateRange();
slider.addListener (this);
}
void updateRange()
{
double v = isFloat ? parseDouble (editor.value.getStringValue (false))
: (double) parseInt (editor.value.getStringValue (false));
double range = isFloat ? 10 : 100;
slider.setRange (v - range, v + range);
slider.setValue (v, dontSendNotification);
}
private:
LivePropertyEditorBase& editor;
Slider slider;
bool isFloat;
void sliderValueChanged (Slider*)
{
editor.applyNewValue (isFloat ? getAsString ((double) slider.getValue(), editor.wasHex)
: getAsString ((int64) slider.getValue(), editor.wasHex));
}
void sliderDragStarted (Slider*) {}
void sliderDragEnded (Slider*) { updateRange(); }
void resized()
{
slider.setBounds (getLocalBounds().removeFromTop (25));
}
};
Component* createIntegerSlider (LivePropertyEditorBase& editor) { return new SliderComp (editor, false); }
Component* createFloatSlider (LivePropertyEditorBase& editor) { return new SliderComp (editor, true); }
}
#endif

View file

@ -0,0 +1,303 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
#ifndef JUCE_LIVECONSTANTEDITOR_H_INCLUDED
#define JUCE_LIVECONSTANTEDITOR_H_INCLUDED
#if JUCE_ENABLE_LIVE_CONSTANT_EDITOR && ! DOXYGEN
//==============================================================================
/** You can safely ignore all the stuff in this namespace - it's a bunch of boilerplate
code used to implement the JUCE_LIVE_CONSTANT functionality.
*/
namespace LiveConstantEditor
{
int64 parseInt (String);
double parseDouble (const String&);
String intToString (int, bool preferHex);
String intToString (int64, bool preferHex);
template <typename Type>
static void setFromString (Type& v, const String& s) { v = static_cast<Type> (s); }
inline void setFromString (char& v, const String& s) { v = (char) parseInt (s); }
inline void setFromString (unsigned char& v, const String& s) { v = (unsigned char) parseInt (s); }
inline void setFromString (short& v, const String& s) { v = (short) parseInt (s); }
inline void setFromString (unsigned short& v, const String& s) { v = (unsigned short) parseInt (s); }
inline void setFromString (int& v, const String& s) { v = (int) parseInt (s); }
inline void setFromString (unsigned int& v, const String& s) { v = (unsigned int) parseInt (s); }
inline void setFromString (long& v, const String& s) { v = (long) parseInt (s); }
inline void setFromString (unsigned long& v, const String& s) { v = (unsigned long) parseInt (s); }
inline void setFromString (int64& v, const String& s) { v = (int64) parseInt (s); }
inline void setFromString (uint64& v, const String& s) { v = (uint64) parseInt (s); }
inline void setFromString (double& v, const String& s) { v = parseDouble (s); }
inline void setFromString (float& v, const String& s) { v = (float) parseDouble (s); }
inline void setFromString (String& v, const String& s) { v = s; }
inline void setFromString (Colour& v, const String& s) { v = Colour ((uint32) parseInt (s)); }
template <typename Type>
inline String getAsString (const Type& v, bool) { return String (v); }
inline String getAsString (char v, bool preferHex) { return intToString ((int) v, preferHex); }
inline String getAsString (unsigned char v, bool preferHex) { return intToString ((int) v, preferHex); }
inline String getAsString (short v, bool preferHex) { return intToString ((int) v, preferHex); }
inline String getAsString (unsigned short v, bool preferHex) { return intToString ((int) v, preferHex); }
inline String getAsString (int v, bool preferHex) { return intToString ((int) v, preferHex); }
inline String getAsString (unsigned int v, bool preferHex) { return intToString ((int) v, preferHex); }
inline String getAsString (int64 v, bool preferHex) { return intToString ((int64) v, preferHex); }
inline String getAsString (uint64 v, bool preferHex) { return intToString ((int64) v, preferHex); }
inline String getAsString (Colour v, bool) { return intToString ((int) v.getARGB(), true); }
template <typename Type> struct isStringType { enum { value = 0 }; };
template <> struct isStringType<String> { enum { value = 1 }; };
template <typename Type>
inline String getAsCode (Type& v, bool preferHex) { return getAsString (v, preferHex); }
inline String getAsCode (Colour v, bool) { return "Colour (0x" + String::toHexString ((int) v.getARGB()).paddedLeft ('0', 8) + ")"; }
inline String getAsCode (const String& v, bool) { return CppTokeniserFunctions::addEscapeChars(v).quoted(); }
inline String getAsCode (const char* v, bool) { return getAsCode (String (v), false); }
template <typename Type>
inline const char* castToCharPointer (const Type&) { return ""; }
inline const char* castToCharPointer (const String& s) { return s.toRawUTF8(); }
struct LivePropertyEditorBase;
//==============================================================================
struct JUCE_API LiveValueBase
{
LiveValueBase (const char* file, int line);
virtual ~LiveValueBase();
virtual LivePropertyEditorBase* createPropertyComponent (CodeDocument&) = 0;
virtual String getStringValue (bool preferHex) const = 0;
virtual String getCodeValue (bool preferHex) const = 0;
virtual void setStringValue (const String&) = 0;
virtual String getOriginalStringValue (bool preferHex) const = 0;
virtual bool isString() const = 0;
String name, sourceFile;
int sourceLine;
JUCE_DECLARE_NON_COPYABLE (LiveValueBase)
};
//==============================================================================
struct JUCE_API LivePropertyEditorBase : public Component,
private TextEditor::Listener,
private ButtonListener
{
LivePropertyEditorBase (LiveValueBase&, CodeDocument&);
void paint (Graphics&) override;
void resized() override;
void textEditorTextChanged (TextEditor&) override;
void buttonClicked (Button*) override;
void applyNewValue (const String&);
void selectOriginalValue();
void findOriginalValueInCode();
LiveValueBase& value;
Label name;
TextEditor valueEditor;
TextButton resetButton;
CodeDocument& document;
CPlusPlusCodeTokeniser tokeniser;
CodeEditorComponent sourceEditor;
CodeDocument::Position valueStart, valueEnd;
ScopedPointer<Component> customComp;
bool wasHex;
JUCE_DECLARE_NON_COPYABLE (LivePropertyEditorBase)
};
//==============================================================================
Component* createColourEditor (LivePropertyEditorBase&);
Component* createIntegerSlider (LivePropertyEditorBase&);
Component* createFloatSlider (LivePropertyEditorBase&);
template <typename Type> struct CustomEditor { static Component* create (LivePropertyEditorBase&) { return nullptr; } };
template<> struct CustomEditor<char> { static Component* create (LivePropertyEditorBase& e) { return createIntegerSlider (e); } };
template<> struct CustomEditor<unsigned char> { static Component* create (LivePropertyEditorBase& e) { return createIntegerSlider (e); } };
template<> struct CustomEditor<int> { static Component* create (LivePropertyEditorBase& e) { return createIntegerSlider (e); } };
template<> struct CustomEditor<unsigned int> { static Component* create (LivePropertyEditorBase& e) { return createIntegerSlider (e); } };
template<> struct CustomEditor<short> { static Component* create (LivePropertyEditorBase& e) { return createIntegerSlider (e); } };
template<> struct CustomEditor<unsigned short> { static Component* create (LivePropertyEditorBase& e) { return createIntegerSlider (e); } };
template<> struct CustomEditor<int64> { static Component* create (LivePropertyEditorBase& e) { return createIntegerSlider (e); } };
template<> struct CustomEditor<uint64> { static Component* create (LivePropertyEditorBase& e) { return createIntegerSlider (e); } };
template<> struct CustomEditor<float> { static Component* create (LivePropertyEditorBase& e) { return createFloatSlider (e); } };
template<> struct CustomEditor<double> { static Component* create (LivePropertyEditorBase& e) { return createFloatSlider (e); } };
template<> struct CustomEditor<Colour> { static Component* create (LivePropertyEditorBase& e) { return createColourEditor (e); } };
template <typename Type>
struct LivePropertyEditor : public LivePropertyEditorBase
{
template <typename ValueType>
LivePropertyEditor (ValueType& v, CodeDocument& d) : LivePropertyEditorBase (v, d)
{
addAndMakeVisible (customComp = CustomEditor<Type>::create (*this));
}
};
//==============================================================================
template <typename Type>
struct LiveValue : public LiveValueBase
{
LiveValue (const char* file, int line, const Type& initialValue)
: LiveValueBase (file, line), value (initialValue), originalValue (initialValue)
{}
operator Type() const noexcept { return value; }
operator const char*() const { return castToCharPointer (value); }
LivePropertyEditorBase* createPropertyComponent (CodeDocument& doc) override
{
return new LivePropertyEditor<Type> (*this, doc);
}
String getStringValue (bool preferHex) const override { return getAsString (value, preferHex); }
String getCodeValue (bool preferHex) const override { return getAsCode (value, preferHex); }
String getOriginalStringValue (bool preferHex) const override { return getAsString (originalValue, preferHex); }
void setStringValue (const String& s) override { setFromString (value, s); }
bool isString() const override { return isStringType<Type>::value; }
Type value, originalValue;
JUCE_DECLARE_NON_COPYABLE (LiveValue)
};
//==============================================================================
class JUCE_API ValueList : private AsyncUpdater,
private DeletedAtShutdown
{
public:
ValueList();
~ValueList();
static ValueList& getInstance();
template <typename Type>
LiveValue<Type>& getValue (const char* file, int line, const Type& initialValue)
{
const ScopedLock sl (lock);
typedef LiveValue<Type> ValueType;
for (int i = 0; i < values.size(); ++i)
{
LiveValueBase* v = values.getUnchecked(i);
if (v->sourceLine == line && v->sourceFile == file)
return *static_cast<ValueType*> (v);
}
ValueType* v = new ValueType (file, line, initialValue);
addValue (v);
return *v;
}
private:
OwnedArray<LiveValueBase> values;
OwnedArray<CodeDocument> documents;
Array<File> documentFiles;
class EditorWindow;
friend class EditorWindow;
friend struct ContainerDeletePolicy<EditorWindow>;
Component::SafePointer<EditorWindow> editorWindow;
CriticalSection lock;
CodeDocument& getDocument (const File&);
void addValue (LiveValueBase*);
void handleAsyncUpdate() override;
};
template <typename Type>
inline LiveValue<Type>& getValue (const char* file, int line, const Type& initialValue)
{
return ValueList::getInstance().getValue (file, line, initialValue);
}
inline LiveValue<String>& getValue (const char* file, int line, const char* initialValue)
{
return getValue (file, line, String (initialValue));
}
}
#endif
//==============================================================================
#if JUCE_ENABLE_LIVE_CONSTANT_EDITOR || DOXYGEN
/**
This macro wraps a primitive constant value in some cunning boilerplate code that allows
its value to be interactively tweaked in a popup window while your application is running.
In a release build, this macro disappears and is replaced by only the constant that it
wraps, but if JUCE_ENABLE_LIVE_CONSTANT_EDITOR is enabled, it injects a class wrapper
that automatically pops-up a window containing an editor that allows the value to be
tweaked at run-time. The editor window will also force all visible components to be
resized and repainted whenever a value is changed, so that if you use this to wrap
a colour or layout parameter, you'll be able to immediately see the effects of changing it.
The editor will also load the original source-file that contains each JUCE_LIVE_CONSTANT
macro, and will display a preview of the modified source code as you adjust the values.
Things to note:
- Only one of these per line! The __FILE__ and __LINE__ macros are used to identify
the value, so things will get confused if you have more than one per line
- Obviously because it needs to load the source code based on the __FILE__ macro,
it'll only work if the source files are stored locally in the same location as they
were when you compiled the program.
- It's only designed to cope with simple types: primitives, string literals, and
the Colour class, so if you try using it for other classes or complex expressions,
good luck!
- The editor window will get popped up whenever a new value is used for the first
time. You can close the window, but there's no way to get it back without restarting
the app!
e.g. in this example the colours, font size, and text used in the paint method can
all be adjusted live:
@code
void MyComp::paint (Graphics& g) override
{
g.fillAll (JUCE_LIVE_CONSTANT (Colour (0xffddddff)));
Colour fontColour = JUCE_LIVE_CONSTANT (Colour (0xff005500));
float fontSize = JUCE_LIVE_CONSTANT (16.0f);
g.setColour (fontColour);
g.setFont (fontSize);
g.drawFittedText (JUCE_LIVE_CONSTANT ("Hello world!"),
getLocalBounds(), Justification::centred, 2);
}
@endcode
*/
#define JUCE_LIVE_CONSTANT(initialValue) \
(juce::LiveConstantEditor::getValue (__FILE__, __LINE__ - 1, initialValue))
#else
#define JUCE_LIVE_CONSTANT(initialValue) \
(initialValue)
#endif
#endif // JUCE_LIVECONSTANTEDITOR_H_INCLUDED

View file

@ -0,0 +1,150 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
PreferencesPanel::PreferencesPanel()
: buttonSize (70)
{
}
PreferencesPanel::~PreferencesPanel()
{
}
int PreferencesPanel::getButtonSize() const noexcept
{
return buttonSize;
}
void PreferencesPanel::setButtonSize (int newSize)
{
buttonSize = newSize;
resized();
}
//==============================================================================
void PreferencesPanel::addSettingsPage (const String& title,
const Drawable* icon,
const Drawable* overIcon,
const Drawable* downIcon)
{
DrawableButton* const button = new DrawableButton (title, DrawableButton::ImageAboveTextLabel);
buttons.add (button);
button->setImages (icon, overIcon, downIcon);
button->setRadioGroupId (1);
button->addListener (this);
button->setClickingTogglesState (true);
button->setWantsKeyboardFocus (false);
addAndMakeVisible (button);
resized();
if (currentPage == nullptr)
setCurrentPage (title);
}
void PreferencesPanel::addSettingsPage (const String& title, const void* imageData, const int imageDataSize)
{
DrawableImage icon, iconOver, iconDown;
icon.setImage (ImageCache::getFromMemory (imageData, imageDataSize));
iconOver.setImage (ImageCache::getFromMemory (imageData, imageDataSize));
iconOver.setOverlayColour (Colours::black.withAlpha (0.12f));
iconDown.setImage (ImageCache::getFromMemory (imageData, imageDataSize));
iconDown.setOverlayColour (Colours::black.withAlpha (0.25f));
addSettingsPage (title, &icon, &iconOver, &iconDown);
}
//==============================================================================
void PreferencesPanel::showInDialogBox (const String& dialogTitle, int dialogWidth, int dialogHeight, Colour backgroundColour)
{
setSize (dialogWidth, dialogHeight);
DialogWindow::LaunchOptions o;
o.content.setNonOwned (this);
o.dialogTitle = dialogTitle;
o.dialogBackgroundColour = backgroundColour;
o.escapeKeyTriggersCloseButton = false;
o.useNativeTitleBar = false;
o.resizable = false;
o.launchAsync();
}
//==============================================================================
void PreferencesPanel::resized()
{
for (int i = 0; i < buttons.size(); ++i)
buttons.getUnchecked(i)->setBounds (i * buttonSize, 0, buttonSize, buttonSize);
if (currentPage != nullptr)
currentPage->setBounds (getLocalBounds().withTop (buttonSize + 5));
}
void PreferencesPanel::paint (Graphics& g)
{
g.setColour (Colours::grey);
g.fillRect (0, buttonSize + 2, getWidth(), 1);
}
void PreferencesPanel::setCurrentPage (const String& pageName)
{
if (currentPageName != pageName)
{
currentPageName = pageName;
currentPage = nullptr;
currentPage = createComponentForPage (pageName);
if (currentPage != nullptr)
{
addAndMakeVisible (currentPage);
currentPage->toBack();
resized();
}
for (int i = 0; i < buttons.size(); ++i)
{
if (buttons.getUnchecked(i)->getName() == pageName)
{
buttons.getUnchecked(i)->setToggleState (true, dontSendNotification);
break;
}
}
}
}
void PreferencesPanel::buttonClicked (Button*)
{
for (int i = 0; i < buttons.size(); ++i)
{
if (buttons.getUnchecked(i)->getToggleState())
{
setCurrentPage (buttons.getUnchecked(i)->getName());
break;
}
}
}

View file

@ -0,0 +1,148 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
#ifndef JUCE_PREFERENCESPANEL_H_INCLUDED
#define JUCE_PREFERENCESPANEL_H_INCLUDED
//==============================================================================
/**
A component with a set of buttons at the top for changing between pages of
preferences.
This is just a handy way of writing a Mac-style preferences panel where you
have a row of buttons along the top for the different preference categories,
each button having an icon above its name. Clicking these will show an
appropriate prefs page below it.
You can either put one of these inside your own component, or just use the
showInDialogBox() method to show it in a window and run it modally.
To use it, just add a set of named pages with the addSettingsPage() method,
and implement the createComponentForPage() method to create suitable components
for each of these pages.
*/
class JUCE_API PreferencesPanel : public Component,
private ButtonListener // (can't use Button::Listener due to idiotic VC2005 bug)
{
public:
//==============================================================================
/** Creates an empty panel.
Use addSettingsPage() to add some pages to it in your constructor.
*/
PreferencesPanel();
/** Destructor. */
~PreferencesPanel();
//==============================================================================
/** Creates a page using a set of drawables to define the page's icon.
Note that the other version of this method is much easier if you're using
an image instead of a custom drawable.
@param pageTitle the name of this preferences page - you'll need to
make sure your createComponentForPage() method creates
a suitable component when it is passed this name
@param normalIcon the drawable to display in the page's button normally
@param overIcon the drawable to display in the page's button when the mouse is over
@param downIcon the drawable to display in the page's button when the button is down
@see DrawableButton
*/
void addSettingsPage (const String& pageTitle,
const Drawable* normalIcon,
const Drawable* overIcon,
const Drawable* downIcon);
/** Creates a page using a set of drawables to define the page's icon.
The other version of this method gives you more control over the icon, but this
one is much easier if you're just loading it from a file.
@param pageTitle the name of this preferences page - you'll need to
make sure your createComponentForPage() method creates
a suitable component when it is passed this name
@param imageData a block of data containing an image file, e.g. a jpeg, png or gif.
For this to look good, you'll probably want to use a nice
transparent png file.
@param imageDataSize the size of the image data, in bytes
*/
void addSettingsPage (const String& pageTitle,
const void* imageData,
int imageDataSize);
/** Utility method to display this panel in a DialogWindow.
Calling this will create a DialogWindow containing this panel with the
given size and title, and will run it modally, returning when the user
closes the dialog box.
*/
void showInDialogBox (const String& dialogTitle,
int dialogWidth,
int dialogHeight,
Colour backgroundColour = Colours::white);
//==============================================================================
/** Subclasses must override this to return a component for each preferences page.
The subclass should return a pointer to a new component representing the named
page, which the panel will then display.
The panel will delete the component later when the user goes to another page
or deletes the panel.
*/
virtual Component* createComponentForPage (const String& pageName) = 0;
//==============================================================================
/** Changes the current page being displayed. */
void setCurrentPage (const String& pageName);
/** Returns the size of the buttons shown along the top. */
int getButtonSize() const noexcept;
/** Changes the size of the buttons shown along the top. */
void setButtonSize (int newSize);
//==============================================================================
/** @internal */
void resized() override;
/** @internal */
void paint (Graphics&) override;
/** @internal */
void buttonClicked (Button*) override;
private:
//==============================================================================
String currentPageName;
ScopedPointer <Component> currentPage;
OwnedArray<DrawableButton> buttons;
int buttonSize;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PreferencesPanel)
};
#endif // JUCE_PREFERENCESPANEL_H_INCLUDED

View file

@ -0,0 +1,146 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
RecentlyOpenedFilesList::RecentlyOpenedFilesList()
: maxNumberOfItems (10)
{
}
RecentlyOpenedFilesList::~RecentlyOpenedFilesList()
{
}
//==============================================================================
void RecentlyOpenedFilesList::setMaxNumberOfItems (const int newMaxNumber)
{
maxNumberOfItems = jmax (1, newMaxNumber);
files.removeRange (maxNumberOfItems, getNumFiles());
}
int RecentlyOpenedFilesList::getNumFiles() const
{
return files.size();
}
File RecentlyOpenedFilesList::getFile (const int index) const
{
return File (files [index]);
}
void RecentlyOpenedFilesList::clear()
{
files.clear();
}
void RecentlyOpenedFilesList::addFile (const File& file)
{
removeFile (file);
files.insert (0, file.getFullPathName());
setMaxNumberOfItems (maxNumberOfItems);
}
void RecentlyOpenedFilesList::removeFile (const File& file)
{
files.removeString (file.getFullPathName());
}
void RecentlyOpenedFilesList::removeNonExistentFiles()
{
for (int i = getNumFiles(); --i >= 0;)
if (! getFile(i).exists())
files.remove (i);
}
//==============================================================================
int RecentlyOpenedFilesList::createPopupMenuItems (PopupMenu& menuToAddTo,
const int baseItemId,
const bool showFullPaths,
const bool dontAddNonExistentFiles,
const File** filesToAvoid)
{
int num = 0;
for (int i = 0; i < getNumFiles(); ++i)
{
const File f (getFile(i));
if ((! dontAddNonExistentFiles) || f.exists())
{
bool needsAvoiding = false;
if (filesToAvoid != nullptr)
{
for (const File** avoid = filesToAvoid; *avoid != nullptr; ++avoid)
{
if (f == **avoid)
{
needsAvoiding = true;
break;
}
}
}
if (! needsAvoiding)
{
menuToAddTo.addItem (baseItemId + i,
showFullPaths ? f.getFullPathName()
: f.getFileName());
++num;
}
}
}
return num;
}
//==============================================================================
String RecentlyOpenedFilesList::toString() const
{
return files.joinIntoString ("\n");
}
void RecentlyOpenedFilesList::restoreFromString (const String& stringifiedVersion)
{
clear();
files.addLines (stringifiedVersion);
setMaxNumberOfItems (maxNumberOfItems);
}
//==============================================================================
void RecentlyOpenedFilesList::registerRecentFileNatively (const File& file)
{
#if JUCE_MAC
JUCE_AUTORELEASEPOOL
{
[[NSDocumentController sharedDocumentController]
noteNewRecentDocumentURL: [NSURL fileURLWithPath: juceStringToNS (file.getFullPathName())]];
}
#else
(void) file;
#endif
}

View file

@ -0,0 +1,164 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
#ifndef JUCE_RECENTLYOPENEDFILESLIST_H_INCLUDED
#define JUCE_RECENTLYOPENEDFILESLIST_H_INCLUDED
//==============================================================================
/**
Manages a set of files for use as a list of recently-opened documents.
This is a handy class for holding your list of recently-opened documents, with
helpful methods for things like purging any non-existent files, automatically
adding them to a menu, and making persistence easy.
@see File, FileBasedDocument
*/
class JUCE_API RecentlyOpenedFilesList
{
public:
//==============================================================================
/** Creates an empty list.
*/
RecentlyOpenedFilesList();
/** Destructor. */
~RecentlyOpenedFilesList();
//==============================================================================
/** Sets a limit for the number of files that will be stored in the list.
When addFile() is called, then if there is no more space in the list, the
least-recently added file will be dropped.
@see getMaxNumberOfItems
*/
void setMaxNumberOfItems (int newMaxNumber);
/** Returns the number of items that this list will store.
@see setMaxNumberOfItems
*/
int getMaxNumberOfItems() const noexcept { return maxNumberOfItems; }
/** Returns the number of files in the list.
The most recently added file is always at index 0.
*/
int getNumFiles() const;
/** Returns one of the files in the list.
The most recently added file is always at index 0.
*/
File getFile (int index) const;
/** Returns an array of all the absolute pathnames in the list.
*/
const StringArray& getAllFilenames() const noexcept { return files; }
/** Clears all the files from the list. */
void clear();
/** Adds a file to the list.
The file will be added at index 0. If this file is already in the list, it will
be moved up to index 0, but a file can only appear once in the list.
If the list already contains the maximum number of items that is permitted, the
least-recently added file will be dropped from the end.
*/
void addFile (const File& file);
/** Removes a file from the list. */
void removeFile (const File& file);
/** Checks each of the files in the list, removing any that don't exist.
You might want to call this after reloading a list of files, or before putting them
on a menu.
*/
void removeNonExistentFiles();
/** Tells the OS to add a file to the OS-managed list of recent documents for this app.
Not all OSes maintain a list of recent files for an application, so this
function will have no effect on some OSes. Currently it's just implemented for OSX.
*/
static void registerRecentFileNatively (const File& file);
//==============================================================================
/** Adds entries to a menu, representing each of the files in the list.
This is handy for creating an "open recent file..." menu in your app. The
menu items are numbered consecutively starting with the baseItemId value,
and can either be added as complete pathnames, or just the last part of the
filename.
If dontAddNonExistentFiles is true, then each file will be checked and only those
that exist will be added.
If filesToAvoid is non-zero, then it is considered to be a zero-terminated array of
pointers to file objects. Any files that appear in this list will not be added to the
menu - the reason for this is that you might have a number of files already open, so
might not want these to be shown in the menu.
It returns the number of items that were added.
*/
int createPopupMenuItems (PopupMenu& menuToAddItemsTo,
int baseItemId,
bool showFullPaths,
bool dontAddNonExistentFiles,
const File** filesToAvoid = nullptr);
//==============================================================================
/** Returns a string that encapsulates all the files in the list.
The string that is returned can later be passed into restoreFromString() in
order to recreate the list. This is handy for persisting your list, e.g. in
a PropertiesFile object.
@see restoreFromString
*/
String toString() const;
/** Restores the list from a previously stringified version of the list.
Pass in a stringified version created with toString() in order to persist/restore
your list.
@see toString
*/
void restoreFromString (const String& stringifiedVersion);
private:
//==============================================================================
StringArray files;
int maxNumberOfItems;
JUCE_LEAK_DETECTOR (RecentlyOpenedFilesList)
};
#endif // JUCE_RECENTLYOPENEDFILESLIST_H_INCLUDED

View file

@ -0,0 +1,83 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
SplashScreen::SplashScreen (const String& title, const Image& image, bool useDropShadow)
: Component (title),
backgroundImage (image),
clickCountToDelete (0)
{
// You must supply a valid image here!
jassert (backgroundImage.isValid());
setOpaque (! backgroundImage.hasAlphaChannel());
makeVisible (image.getWidth(), image.getHeight(), useDropShadow);
}
SplashScreen::SplashScreen (const String& title, int width, int height, bool useDropShadow)
: Component (title),
clickCountToDelete (0)
{
makeVisible (width, height, useDropShadow);
}
void SplashScreen::makeVisible (int w, int h, bool useDropShadow)
{
clickCountToDelete = Desktop::getInstance().getMouseButtonClickCounter();
creationTime = Time::getCurrentTime();
setAlwaysOnTop (true);
setVisible (true);
centreWithSize (w, h);
addToDesktop (useDropShadow ? ComponentPeer::windowHasDropShadow : 0);
toFront (false);
}
SplashScreen::~SplashScreen() {}
void SplashScreen::deleteAfterDelay (RelativeTime timeout, bool removeOnMouseClick)
{
// Note that this method must be safe to call from non-GUI threads
if (! removeOnMouseClick)
clickCountToDelete = std::numeric_limits<int>::max();
minimumVisibleTime = timeout;
startTimer (50);
}
void SplashScreen::paint (Graphics& g)
{
g.setOpacity (1.0f);
g.drawImage (backgroundImage,
0, 0, getWidth(), getHeight(),
0, 0, backgroundImage.getWidth(), backgroundImage.getHeight());
}
void SplashScreen::timerCallback()
{
if (Time::getCurrentTime() > creationTime + minimumVisibleTime
|| Desktop::getInstance().getMouseButtonClickCounter() > clickCountToDelete)
delete this;
}

View file

@ -0,0 +1,155 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
#ifndef JUCE_SPLASHSCREEN_H_INCLUDED
#define JUCE_SPLASHSCREEN_H_INCLUDED
//==============================================================================
/** A component for showing a splash screen while your app starts up.
This will automatically position itself, and can be told to delete itself after
being on-screen for a minimum length of time.
To use it, just create one of these in your JUCEApplicationBase::initialise() method,
and when your initialisation tasks have finished running, call its deleteAfterDelay()
method to make it automatically get rid of itself.
Note that although you could call deleteAfterDelay() as soon as you create the
SplashScreen object, if you've got a long initialisation procedure, you probably
don't want the splash to time-out and disappear before the initialisation has
finished, which is why it makes sense to not call this method until the end of
your init tasks.
E.g. @code
void MyApp::initialise (const String& commandLine)
{
splash = new SplashScreen ("Welcome to my app!",
ImageFileFormat::loadFrom (File ("/foobar/splash.jpg")),
true);
// now kick off your initialisation work on some kind of thread or task, and
launchBackgroundInitialisationThread();
}
void MyApp::myInitialisationWorkFinished()
{
// ..assuming this is some kind of callback method that is triggered when
// your background initialisation threads have finished, and it's time to open
// your main window, etc..
splash->deleteAfterDelay (RelativeTime::seconds (4), false);
...etc...
}
@endcode
*/
class JUCE_API SplashScreen : public Component,
private Timer,
private DeletedAtShutdown
{
public:
//==============================================================================
/** Creates a SplashScreen object.
When called, the constructor will position the SplashScreen in the centre of the
display, and after the time specified, it will automatically delete itself.
Bear in mind that if you call this during your JUCEApplicationBase::initialise()
method and then block the message thread by performing some kind of task, then
obviously neither your splash screen nor any other GUI will appear until you
allow the message thread to resume and do its work. So if you have time-consuming
tasks to do during startup, use a background thread for them.
After creating one of these (or your subclass of it), you should do your app's
initialisation work, and then call the deleteAfterDelay() method to tell this object
to delete itself after the user has had chance to get a good look at it.
If you're writing a custom splash screen class, there's another protected constructor
that your subclass can call, which doesn't take an image.
@param title the name to give the component
@param backgroundImage an image to draw on the component. The component's size
will be set to the size of this image, and if the image is
semi-transparent, the component will be made non-opaque
@param useDropShadow if true, the window will have a drop shadow
*/
SplashScreen (const String& title,
const Image& backgroundImage,
bool useDropShadow);
/** Destructor. */
~SplashScreen();
/** Tells the component to auto-delete itself after a timeout period, or when the
mouse is clicked.
You should call this after finishing your app's initialisation work.
Note that although you could call deleteAfterDelay() as soon as you create the
SplashScreen object, if you've got a long initialisation procedure, you probably
don't want the splash to time-out and disappear before your initialisation has
finished, which is why it makes sense to not call this method and start the
self-delete timer until you're ready.
It's safe to call this method from a non-GUI thread as long as there's no danger that
the object may be being deleted at the same time.
@param minimumTotalTimeToDisplayFor how long the splash screen should stay visible for.
Note that this time is measured from the construction-time of this
object, not from the time that the deleteAfterDelay() method is
called, so if you call this method after a long initialisation
period, it may be deleted without any further delay.
@param removeOnMouseClick if true, the window will be deleted as soon as the user clicks
the mouse (anywhere)
*/
void deleteAfterDelay (RelativeTime minimumTotalTimeToDisplayFor,
bool removeOnMouseClick);
protected:
//==============================================================================
/** This constructor is for use by custom sub-classes that don't want to provide an image. */
SplashScreen (const String& title, int width, int height, bool useDropShadow);
/** @internal */
void paint (Graphics&) override;
private:
//==============================================================================
Image backgroundImage;
Time creationTime;
RelativeTime minimumVisibleTime;
int clickCountToDelete;
void timerCallback() override;
void makeVisible (int w, int h, bool shadow);
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SplashScreen)
};
#endif // JUCE_SPLASHSCREEN_H_INCLUDED

View file

@ -0,0 +1,36 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
#if JUCE_WINDOWS || JUCE_LINUX || JUCE_MAC
SystemTrayIconComponent::SystemTrayIconComponent()
{
addToDesktop (0);
}
SystemTrayIconComponent::~SystemTrayIconComponent()
{
}
#endif

View file

@ -0,0 +1,97 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
#ifndef JUCE_SYSTEMTRAYICONCOMPONENT_H_INCLUDED
#define JUCE_SYSTEMTRAYICONCOMPONENT_H_INCLUDED
#if JUCE_WINDOWS || JUCE_LINUX || JUCE_MAC || DOXYGEN
//==============================================================================
/**
This component sits in the taskbar tray as a small icon.
(NB: The exact behaviour of this class will differ between OSes, and it
isn't fully implemented for all OSes)
To use it, just create one of these components, but don't attempt to make it
visible, add it to a parent, or put it on the desktop.
You can then call setIconImage() to create an icon for it in the taskbar.
To change the icon's tooltip, you can use setIconTooltip().
To respond to mouse-events, you can override the normal mouseDown(),
mouseUp(), mouseDoubleClick() and mouseMove() methods, and although the x, y
position will not be valid, you can use this to respond to clicks. Traditionally
you'd use a left-click to show your application's window, and a right-click
to show a pop-up menu.
*/
class JUCE_API SystemTrayIconComponent : public Component
{
public:
//==============================================================================
SystemTrayIconComponent();
/** Destructor. */
~SystemTrayIconComponent();
//==============================================================================
/** Changes the image shown in the taskbar. */
void setIconImage (const Image& newImage);
/** Changes the icon's tooltip (if the current OS supports this). */
void setIconTooltip (const String& tooltip);
/** Highlights the icon (if the current OS supports this). */
void setHighlighted (bool);
/** Shows a floating text bubble pointing to the icon (if the current OS supports this). */
void showInfoBubble (const String& title, const String& content);
/** Hides the icon's floating text bubble (if the current OS supports this). */
void hideInfoBubble();
/** Returns the raw handle to whatever kind of internal OS structure is
involved in showing this icon.
@see ComponentPeer::getNativeHandle()
*/
void* getNativeHandle() const;
#if JUCE_LINUX
/** @internal */
void paint (Graphics&) override;
#endif
private:
//==============================================================================
JUCE_PUBLIC_IN_DLL_BUILD (class Pimpl)
ScopedPointer<Pimpl> pimpl;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SystemTrayIconComponent)
};
#endif
#endif // JUCE_SYSTEMTRAYICONCOMPONENT_H_INCLUDED

View file

@ -0,0 +1,128 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
#ifndef JUCE_WEBBROWSERCOMPONENT_H_INCLUDED
#define JUCE_WEBBROWSERCOMPONENT_H_INCLUDED
#if JUCE_WEB_BROWSER || DOXYGEN
//==============================================================================
/**
A component that displays an embedded web browser.
The browser itself will be platform-dependent. On the Mac, probably Safari, on
Windows, probably IE.
*/
class JUCE_API WebBrowserComponent : public Component
{
public:
//==============================================================================
/** Creates a WebBrowserComponent.
Once it's created and visible, send the browser to a URL using goToURL().
@param unloadPageWhenBrowserIsHidden if this is true, then when the browser
component is taken offscreen, it'll clear the current page
and replace it with a blank page - this can be handy to stop
the browser using resources in the background when it's not
actually being used.
*/
explicit WebBrowserComponent (bool unloadPageWhenBrowserIsHidden = true);
/** Destructor. */
~WebBrowserComponent();
//==============================================================================
/** Sends the browser to a particular URL.
@param url the URL to go to.
@param headers an optional set of parameters to put in the HTTP header. If
you supply this, it should be a set of string in the form
"HeaderKey: HeaderValue"
@param postData an optional block of data that will be attached to the HTTP
POST request
*/
void goToURL (const String& url,
const StringArray* headers = nullptr,
const MemoryBlock* postData = nullptr);
/** Stops the current page loading. */
void stop();
/** Sends the browser back one page. */
void goBack();
/** Sends the browser forward one page. */
void goForward();
/** Refreshes the browser. */
void refresh();
//==============================================================================
/** This callback is called when the browser is about to navigate
to a new location.
You can override this method to perform some action when the user
tries to go to a particular URL. To allow the operation to carry on,
return true, or return false to stop the navigation happening.
*/
virtual bool pageAboutToLoad (const String& newURL);
/** This callback happens when the browser has finished loading a page. */
virtual void pageFinishedLoading (const String& url);
/** This callback occurs when a script or other activity in the browser asks for
the window to be closed.
*/
virtual void windowCloseRequest();
//==============================================================================
/** @internal */
void paint (Graphics&) override;
/** @internal */
void resized() override;
/** @internal */
void parentHierarchyChanged() override;
/** @internal */
void visibilityChanged() override;
private:
//==============================================================================
class Pimpl;
Pimpl* browser;
bool blankPageShown, unloadPageWhenBrowserIsHidden;
String lastURL;
StringArray lastHeaders;
MemoryBlock lastPostData;
void reloadLastURL();
void checkWindowAssociation();
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WebBrowserComponent)
};
#endif
#endif // JUCE_WEBBROWSERCOMPONENT_H_INCLUDED