mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-17 00:44:19 +00:00
This commit is contained in:
parent
da26d356d9
commit
5572be0248
15 changed files with 8255 additions and 8255 deletions
|
|
@ -161,7 +161,7 @@ const String AudioDeviceManager::initialise (const int numInputChannelsNeeded,
|
|||
|
||||
if (e->getStringAttribute (T("audioDeviceName")).isNotEmpty())
|
||||
{
|
||||
setup.inputDeviceName = setup.outputDeviceName
|
||||
setup.inputDeviceName = setup.outputDeviceName
|
||||
= e->getStringAttribute (T("audioDeviceName"));
|
||||
}
|
||||
else
|
||||
|
|
@ -425,7 +425,7 @@ const String AudioDeviceManager::setAudioDeviceSetup (const AudioDeviceSetup& ne
|
|||
|
||||
error = currentAudioDevice->open (inputChannels,
|
||||
outputChannels,
|
||||
currentSetup.sampleRate,
|
||||
currentSetup.sampleRate,
|
||||
currentSetup.bufferSize);
|
||||
|
||||
if (error.isEmpty())
|
||||
|
|
@ -511,7 +511,7 @@ void AudioDeviceManager::restartLastAudioDevice()
|
|||
{
|
||||
if (currentAudioDevice == 0)
|
||||
{
|
||||
if (currentSetup.inputDeviceName.isEmpty()
|
||||
if (currentSetup.inputDeviceName.isEmpty()
|
||||
&& currentSetup.outputDeviceName.isEmpty())
|
||||
{
|
||||
// This method will only reload the last device that was running
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@
|
|||
#define __JUCE_MESSAGE_JUCEHEADER__
|
||||
|
||||
class MessageListener;
|
||||
|
||||
class MessageManager;
|
||||
|
||||
//==============================================================================
|
||||
/** The base class for objects that can be delivered to a MessageListener.
|
||||
|
|
|
|||
|
|
@ -1,433 +1,433 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library - "Jules' Utility Class Extensions"
|
||||
Copyright 2004-7 by Raw Material Software ltd.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
JUCE can be redistributed and/or modified under the terms of the
|
||||
GNU General Public License, as published by the Free Software Foundation;
|
||||
either version 2 of the License, or (at your option) any later version.
|
||||
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with JUCE; if not, visit www.gnu.org/licenses or write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
If you'd like to release a closed-source product which uses JUCE, commercial
|
||||
licenses are also available: visit www.rawmaterialsoftware.com/juce for
|
||||
more information.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "../../../../juce_core/basics/juce_StandardHeader.h"
|
||||
|
||||
BEGIN_JUCE_NAMESPACE
|
||||
|
||||
#include "juce_Label.h"
|
||||
#include "../LookAndFeel/juce_LookAndFeel.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
Label::Label (const String& componentName,
|
||||
const String& labelText)
|
||||
: Component (componentName),
|
||||
text (labelText),
|
||||
font (15.0f),
|
||||
justification (Justification::centredLeft),
|
||||
editor (0),
|
||||
listeners (2),
|
||||
ownerComponent (0),
|
||||
deletionWatcher (0),
|
||||
horizontalBorderSize (3),
|
||||
verticalBorderSize (1),
|
||||
minimumHorizontalScale (0.7f),
|
||||
editSingleClick (false),
|
||||
editDoubleClick (false),
|
||||
lossOfFocusDiscardsChanges (false)
|
||||
{
|
||||
setColour (TextEditor::textColourId, Colours::black);
|
||||
setColour (TextEditor::backgroundColourId, Colours::transparentBlack);
|
||||
setColour (TextEditor::outlineColourId, Colours::transparentBlack);
|
||||
}
|
||||
|
||||
Label::~Label()
|
||||
{
|
||||
if (ownerComponent != 0 && ! deletionWatcher->hasBeenDeleted())
|
||||
ownerComponent->removeComponentListener (this);
|
||||
|
||||
deleteAndZero (deletionWatcher);
|
||||
|
||||
if (editor != 0)
|
||||
delete editor;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void Label::setText (const String& newText,
|
||||
const bool broadcastChangeMessage)
|
||||
{
|
||||
hideEditor (true);
|
||||
|
||||
if (text != newText)
|
||||
{
|
||||
text = newText;
|
||||
|
||||
if (broadcastChangeMessage)
|
||||
triggerAsyncUpdate();
|
||||
|
||||
repaint();
|
||||
|
||||
if (ownerComponent != 0 && ! deletionWatcher->hasBeenDeleted())
|
||||
componentMovedOrResized (*ownerComponent, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
const String Label::getText (const bool returnActiveEditorContents) const throw()
|
||||
{
|
||||
return (returnActiveEditorContents && isBeingEdited())
|
||||
? editor->getText()
|
||||
: text;
|
||||
}
|
||||
|
||||
void Label::setFont (const Font& newFont) throw()
|
||||
{
|
||||
font = newFont;
|
||||
repaint();
|
||||
}
|
||||
|
||||
const Font& Label::getFont() const throw()
|
||||
{
|
||||
return font;
|
||||
}
|
||||
|
||||
void Label::setEditable (const bool editOnSingleClick,
|
||||
const bool editOnDoubleClick,
|
||||
const bool lossOfFocusDiscardsChanges_) throw()
|
||||
{
|
||||
editSingleClick = editOnSingleClick;
|
||||
editDoubleClick = editOnDoubleClick;
|
||||
lossOfFocusDiscardsChanges = lossOfFocusDiscardsChanges_;
|
||||
|
||||
setWantsKeyboardFocus (editOnSingleClick || editOnDoubleClick);
|
||||
setFocusContainer (editOnSingleClick || editOnDoubleClick);
|
||||
}
|
||||
|
||||
void Label::setJustificationType (const Justification& justification_) throw()
|
||||
{
|
||||
justification = justification_;
|
||||
repaint();
|
||||
}
|
||||
|
||||
void Label::setBorderSize (int h, int v)
|
||||
{
|
||||
horizontalBorderSize = h;
|
||||
verticalBorderSize = v;
|
||||
repaint();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void Label::attachToComponent (Component* owner,
|
||||
const bool onLeft)
|
||||
{
|
||||
if (ownerComponent != 0 && ! deletionWatcher->hasBeenDeleted())
|
||||
ownerComponent->removeComponentListener (this);
|
||||
|
||||
deleteAndZero (deletionWatcher);
|
||||
ownerComponent = owner;
|
||||
|
||||
leftOfOwnerComp = onLeft;
|
||||
|
||||
if (ownerComponent != 0)
|
||||
{
|
||||
deletionWatcher = new ComponentDeletionWatcher (owner);
|
||||
|
||||
setVisible (owner->isVisible());
|
||||
ownerComponent->addComponentListener (this);
|
||||
componentParentHierarchyChanged (*ownerComponent);
|
||||
componentMovedOrResized (*ownerComponent, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
void Label::componentMovedOrResized (Component& component,
|
||||
bool /*wasMoved*/,
|
||||
bool /*wasResized*/)
|
||||
{
|
||||
if (leftOfOwnerComp)
|
||||
{
|
||||
setSize (jmin (getFont().getStringWidth (text) + 8, component.getX()),
|
||||
component.getHeight());
|
||||
|
||||
setTopRightPosition (component.getX(), component.getY());
|
||||
}
|
||||
else
|
||||
{
|
||||
setSize (component.getWidth(),
|
||||
8 + roundFloatToInt (getFont().getHeight()));
|
||||
|
||||
setTopLeftPosition (component.getX(), component.getY() - getHeight());
|
||||
}
|
||||
}
|
||||
|
||||
void Label::componentParentHierarchyChanged (Component& component)
|
||||
{
|
||||
if (component.getParentComponent() != 0)
|
||||
component.getParentComponent()->addChildComponent (this);
|
||||
}
|
||||
|
||||
void Label::componentVisibilityChanged (Component& component)
|
||||
{
|
||||
setVisible (component.isVisible());
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void Label::textWasEdited()
|
||||
{
|
||||
}
|
||||
|
||||
void Label::showEditor()
|
||||
{
|
||||
if (editor == 0)
|
||||
{
|
||||
addAndMakeVisible (editor = createEditorComponent());
|
||||
editor->setText (getText());
|
||||
editor->addListener (this);
|
||||
editor->grabKeyboardFocus();
|
||||
editor->setHighlightedRegion (0, text.length());
|
||||
editor->addListener (this);
|
||||
|
||||
resized();
|
||||
repaint();
|
||||
|
||||
enterModalState();
|
||||
editor->grabKeyboardFocus();
|
||||
}
|
||||
}
|
||||
|
||||
bool Label::updateFromTextEditorContents()
|
||||
{
|
||||
jassert (editor != 0);
|
||||
const String newText (editor->getText());
|
||||
|
||||
if (text != newText)
|
||||
{
|
||||
text = newText;
|
||||
|
||||
triggerAsyncUpdate();
|
||||
repaint();
|
||||
|
||||
if (ownerComponent != 0 && ! deletionWatcher->hasBeenDeleted())
|
||||
componentMovedOrResized (*ownerComponent, true, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Label::hideEditor (const bool discardCurrentEditorContents)
|
||||
{
|
||||
if (editor != 0)
|
||||
{
|
||||
const bool changed = (! discardCurrentEditorContents)
|
||||
&& updateFromTextEditorContents();
|
||||
|
||||
deleteAndZero (editor);
|
||||
repaint();
|
||||
|
||||
if (changed)
|
||||
textWasEdited();
|
||||
|
||||
exitModalState (0);
|
||||
}
|
||||
}
|
||||
|
||||
void Label::inputAttemptWhenModal()
|
||||
{
|
||||
if (editor != 0)
|
||||
{
|
||||
if (lossOfFocusDiscardsChanges)
|
||||
textEditorEscapeKeyPressed (*editor);
|
||||
else
|
||||
textEditorReturnKeyPressed (*editor);
|
||||
}
|
||||
}
|
||||
|
||||
bool Label::isBeingEdited() const throw()
|
||||
{
|
||||
return editor != 0;
|
||||
}
|
||||
|
||||
TextEditor* Label::createEditorComponent()
|
||||
{
|
||||
TextEditor* const ed = new TextEditor (getName());
|
||||
ed->setFont (font);
|
||||
|
||||
// copy these colours from our own settings..
|
||||
const int cols[] = { TextEditor::backgroundColourId,
|
||||
TextEditor::textColourId,
|
||||
TextEditor::highlightColourId,
|
||||
TextEditor::highlightedTextColourId,
|
||||
TextEditor::caretColourId,
|
||||
TextEditor::outlineColourId,
|
||||
TextEditor::focusedOutlineColourId,
|
||||
TextEditor::shadowColourId };
|
||||
|
||||
for (int i = 0; i < numElementsInArray (cols); ++i)
|
||||
ed->setColour (cols[i], findColour (cols[i]));
|
||||
|
||||
return ed;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void Label::paint (Graphics& g)
|
||||
{
|
||||
getLookAndFeel().drawLabel (g, *this);
|
||||
}
|
||||
|
||||
void Label::mouseUp (const MouseEvent& e)
|
||||
{
|
||||
if (editSingleClick
|
||||
&& e.mouseWasClicked()
|
||||
&& contains (e.x, e.y)
|
||||
&& ! e.mods.isPopupMenu())
|
||||
{
|
||||
showEditor();
|
||||
}
|
||||
}
|
||||
|
||||
void Label::mouseDoubleClick (const MouseEvent& e)
|
||||
{
|
||||
if (editDoubleClick && ! e.mods.isPopupMenu())
|
||||
showEditor();
|
||||
}
|
||||
|
||||
void Label::resized()
|
||||
{
|
||||
if (editor != 0)
|
||||
editor->setBoundsInset (BorderSize (0));
|
||||
}
|
||||
|
||||
void Label::focusGained (FocusChangeType cause)
|
||||
{
|
||||
if (editSingleClick && cause == focusChangedByTabKey)
|
||||
showEditor();
|
||||
}
|
||||
|
||||
void Label::enablementChanged()
|
||||
{
|
||||
repaint();
|
||||
}
|
||||
|
||||
void Label::colourChanged()
|
||||
{
|
||||
repaint();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// We'll use a custom focus traverser here to make sure focus goes from the
|
||||
// text editor to another component rather than back to the label itself.
|
||||
class LabelKeyboardFocusTraverser : public KeyboardFocusTraverser
|
||||
{
|
||||
public:
|
||||
LabelKeyboardFocusTraverser() {}
|
||||
|
||||
Component* getNextComponent (Component* current)
|
||||
{
|
||||
return KeyboardFocusTraverser::getNextComponent (dynamic_cast <TextEditor*> (current) != 0
|
||||
? current->getParentComponent() : current);
|
||||
}
|
||||
|
||||
Component* getPreviousComponent (Component* current)
|
||||
{
|
||||
return KeyboardFocusTraverser::getPreviousComponent (dynamic_cast <TextEditor*> (current) != 0
|
||||
? current->getParentComponent() : current);
|
||||
}
|
||||
};
|
||||
|
||||
KeyboardFocusTraverser* Label::createFocusTraverser()
|
||||
{
|
||||
return new LabelKeyboardFocusTraverser();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void Label::addListener (LabelListener* const listener) throw()
|
||||
{
|
||||
jassert (listener != 0);
|
||||
if (listener != 0)
|
||||
listeners.add (listener);
|
||||
}
|
||||
|
||||
void Label::removeListener (LabelListener* const listener) throw()
|
||||
{
|
||||
listeners.removeValue (listener);
|
||||
}
|
||||
|
||||
void Label::handleAsyncUpdate()
|
||||
{
|
||||
for (int i = listeners.size(); --i >= 0;)
|
||||
{
|
||||
((LabelListener*) listeners.getUnchecked (i))->labelTextChanged (this);
|
||||
i = jmin (i, listeners.size());
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void Label::textEditorTextChanged (TextEditor& ed)
|
||||
{
|
||||
if (editor != 0)
|
||||
{
|
||||
jassert (&ed == editor);
|
||||
|
||||
if (! (hasKeyboardFocus (true) || isCurrentlyBlockedByAnotherModalComponent()))
|
||||
{
|
||||
if (lossOfFocusDiscardsChanges)
|
||||
textEditorEscapeKeyPressed (ed);
|
||||
else
|
||||
textEditorReturnKeyPressed (ed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Label::textEditorReturnKeyPressed (TextEditor& ed)
|
||||
{
|
||||
if (editor != 0)
|
||||
{
|
||||
jassert (&ed == editor);
|
||||
(void) ed;
|
||||
|
||||
const bool changed = updateFromTextEditorContents();
|
||||
hideEditor (true);
|
||||
|
||||
if (changed)
|
||||
textWasEdited();
|
||||
}
|
||||
}
|
||||
|
||||
void Label::textEditorEscapeKeyPressed (TextEditor& ed)
|
||||
{
|
||||
if (editor != 0)
|
||||
{
|
||||
jassert (&ed == editor);
|
||||
(void) ed;
|
||||
|
||||
editor->setText (text, false);
|
||||
hideEditor (true);
|
||||
}
|
||||
}
|
||||
|
||||
void Label::textEditorFocusLost (TextEditor& ed)
|
||||
{
|
||||
textEditorTextChanged (ed);
|
||||
}
|
||||
|
||||
|
||||
END_JUCE_NAMESPACE
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library - "Jules' Utility Class Extensions"
|
||||
Copyright 2004-7 by Raw Material Software ltd.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
JUCE can be redistributed and/or modified under the terms of the
|
||||
GNU General Public License, as published by the Free Software Foundation;
|
||||
either version 2 of the License, or (at your option) any later version.
|
||||
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with JUCE; if not, visit www.gnu.org/licenses or write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
If you'd like to release a closed-source product which uses JUCE, commercial
|
||||
licenses are also available: visit www.rawmaterialsoftware.com/juce for
|
||||
more information.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "../../../../juce_core/basics/juce_StandardHeader.h"
|
||||
|
||||
BEGIN_JUCE_NAMESPACE
|
||||
|
||||
#include "juce_Label.h"
|
||||
#include "../LookAndFeel/juce_LookAndFeel.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
Label::Label (const String& componentName,
|
||||
const String& labelText)
|
||||
: Component (componentName),
|
||||
text (labelText),
|
||||
font (15.0f),
|
||||
justification (Justification::centredLeft),
|
||||
editor (0),
|
||||
listeners (2),
|
||||
ownerComponent (0),
|
||||
deletionWatcher (0),
|
||||
horizontalBorderSize (3),
|
||||
verticalBorderSize (1),
|
||||
minimumHorizontalScale (0.7f),
|
||||
editSingleClick (false),
|
||||
editDoubleClick (false),
|
||||
lossOfFocusDiscardsChanges (false)
|
||||
{
|
||||
setColour (TextEditor::textColourId, Colours::black);
|
||||
setColour (TextEditor::backgroundColourId, Colours::transparentBlack);
|
||||
setColour (TextEditor::outlineColourId, Colours::transparentBlack);
|
||||
}
|
||||
|
||||
Label::~Label()
|
||||
{
|
||||
if (ownerComponent != 0 && ! deletionWatcher->hasBeenDeleted())
|
||||
ownerComponent->removeComponentListener (this);
|
||||
|
||||
deleteAndZero (deletionWatcher);
|
||||
|
||||
if (editor != 0)
|
||||
delete editor;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void Label::setText (const String& newText,
|
||||
const bool broadcastChangeMessage)
|
||||
{
|
||||
hideEditor (true);
|
||||
|
||||
if (text != newText)
|
||||
{
|
||||
text = newText;
|
||||
|
||||
if (broadcastChangeMessage)
|
||||
triggerAsyncUpdate();
|
||||
|
||||
repaint();
|
||||
|
||||
if (ownerComponent != 0 && ! deletionWatcher->hasBeenDeleted())
|
||||
componentMovedOrResized (*ownerComponent, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
const String Label::getText (const bool returnActiveEditorContents) const throw()
|
||||
{
|
||||
return (returnActiveEditorContents && isBeingEdited())
|
||||
? editor->getText()
|
||||
: text;
|
||||
}
|
||||
|
||||
void Label::setFont (const Font& newFont) throw()
|
||||
{
|
||||
font = newFont;
|
||||
repaint();
|
||||
}
|
||||
|
||||
const Font& Label::getFont() const throw()
|
||||
{
|
||||
return font;
|
||||
}
|
||||
|
||||
void Label::setEditable (const bool editOnSingleClick,
|
||||
const bool editOnDoubleClick,
|
||||
const bool lossOfFocusDiscardsChanges_) throw()
|
||||
{
|
||||
editSingleClick = editOnSingleClick;
|
||||
editDoubleClick = editOnDoubleClick;
|
||||
lossOfFocusDiscardsChanges = lossOfFocusDiscardsChanges_;
|
||||
|
||||
setWantsKeyboardFocus (editOnSingleClick || editOnDoubleClick);
|
||||
setFocusContainer (editOnSingleClick || editOnDoubleClick);
|
||||
}
|
||||
|
||||
void Label::setJustificationType (const Justification& justification_) throw()
|
||||
{
|
||||
justification = justification_;
|
||||
repaint();
|
||||
}
|
||||
|
||||
void Label::setBorderSize (int h, int v)
|
||||
{
|
||||
horizontalBorderSize = h;
|
||||
verticalBorderSize = v;
|
||||
repaint();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void Label::attachToComponent (Component* owner,
|
||||
const bool onLeft)
|
||||
{
|
||||
if (ownerComponent != 0 && ! deletionWatcher->hasBeenDeleted())
|
||||
ownerComponent->removeComponentListener (this);
|
||||
|
||||
deleteAndZero (deletionWatcher);
|
||||
ownerComponent = owner;
|
||||
|
||||
leftOfOwnerComp = onLeft;
|
||||
|
||||
if (ownerComponent != 0)
|
||||
{
|
||||
deletionWatcher = new ComponentDeletionWatcher (owner);
|
||||
|
||||
setVisible (owner->isVisible());
|
||||
ownerComponent->addComponentListener (this);
|
||||
componentParentHierarchyChanged (*ownerComponent);
|
||||
componentMovedOrResized (*ownerComponent, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
void Label::componentMovedOrResized (Component& component,
|
||||
bool /*wasMoved*/,
|
||||
bool /*wasResized*/)
|
||||
{
|
||||
if (leftOfOwnerComp)
|
||||
{
|
||||
setSize (jmin (getFont().getStringWidth (text) + 8, component.getX()),
|
||||
component.getHeight());
|
||||
|
||||
setTopRightPosition (component.getX(), component.getY());
|
||||
}
|
||||
else
|
||||
{
|
||||
setSize (component.getWidth(),
|
||||
8 + roundFloatToInt (getFont().getHeight()));
|
||||
|
||||
setTopLeftPosition (component.getX(), component.getY() - getHeight());
|
||||
}
|
||||
}
|
||||
|
||||
void Label::componentParentHierarchyChanged (Component& component)
|
||||
{
|
||||
if (component.getParentComponent() != 0)
|
||||
component.getParentComponent()->addChildComponent (this);
|
||||
}
|
||||
|
||||
void Label::componentVisibilityChanged (Component& component)
|
||||
{
|
||||
setVisible (component.isVisible());
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void Label::textWasEdited()
|
||||
{
|
||||
}
|
||||
|
||||
void Label::showEditor()
|
||||
{
|
||||
if (editor == 0)
|
||||
{
|
||||
addAndMakeVisible (editor = createEditorComponent());
|
||||
editor->setText (getText());
|
||||
editor->addListener (this);
|
||||
editor->grabKeyboardFocus();
|
||||
editor->setHighlightedRegion (0, text.length());
|
||||
editor->addListener (this);
|
||||
|
||||
resized();
|
||||
repaint();
|
||||
|
||||
enterModalState();
|
||||
editor->grabKeyboardFocus();
|
||||
}
|
||||
}
|
||||
|
||||
bool Label::updateFromTextEditorContents()
|
||||
{
|
||||
jassert (editor != 0);
|
||||
const String newText (editor->getText());
|
||||
|
||||
if (text != newText)
|
||||
{
|
||||
text = newText;
|
||||
|
||||
triggerAsyncUpdate();
|
||||
repaint();
|
||||
|
||||
if (ownerComponent != 0 && ! deletionWatcher->hasBeenDeleted())
|
||||
componentMovedOrResized (*ownerComponent, true, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Label::hideEditor (const bool discardCurrentEditorContents)
|
||||
{
|
||||
if (editor != 0)
|
||||
{
|
||||
const bool changed = (! discardCurrentEditorContents)
|
||||
&& updateFromTextEditorContents();
|
||||
|
||||
deleteAndZero (editor);
|
||||
repaint();
|
||||
|
||||
if (changed)
|
||||
textWasEdited();
|
||||
|
||||
exitModalState (0);
|
||||
}
|
||||
}
|
||||
|
||||
void Label::inputAttemptWhenModal()
|
||||
{
|
||||
if (editor != 0)
|
||||
{
|
||||
if (lossOfFocusDiscardsChanges)
|
||||
textEditorEscapeKeyPressed (*editor);
|
||||
else
|
||||
textEditorReturnKeyPressed (*editor);
|
||||
}
|
||||
}
|
||||
|
||||
bool Label::isBeingEdited() const throw()
|
||||
{
|
||||
return editor != 0;
|
||||
}
|
||||
|
||||
TextEditor* Label::createEditorComponent()
|
||||
{
|
||||
TextEditor* const ed = new TextEditor (getName());
|
||||
ed->setFont (font);
|
||||
|
||||
// copy these colours from our own settings..
|
||||
const int cols[] = { TextEditor::backgroundColourId,
|
||||
TextEditor::textColourId,
|
||||
TextEditor::highlightColourId,
|
||||
TextEditor::highlightedTextColourId,
|
||||
TextEditor::caretColourId,
|
||||
TextEditor::outlineColourId,
|
||||
TextEditor::focusedOutlineColourId,
|
||||
TextEditor::shadowColourId };
|
||||
|
||||
for (int i = 0; i < numElementsInArray (cols); ++i)
|
||||
ed->setColour (cols[i], findColour (cols[i]));
|
||||
|
||||
return ed;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void Label::paint (Graphics& g)
|
||||
{
|
||||
getLookAndFeel().drawLabel (g, *this);
|
||||
}
|
||||
|
||||
void Label::mouseUp (const MouseEvent& e)
|
||||
{
|
||||
if (editSingleClick
|
||||
&& e.mouseWasClicked()
|
||||
&& contains (e.x, e.y)
|
||||
&& ! e.mods.isPopupMenu())
|
||||
{
|
||||
showEditor();
|
||||
}
|
||||
}
|
||||
|
||||
void Label::mouseDoubleClick (const MouseEvent& e)
|
||||
{
|
||||
if (editDoubleClick && ! e.mods.isPopupMenu())
|
||||
showEditor();
|
||||
}
|
||||
|
||||
void Label::resized()
|
||||
{
|
||||
if (editor != 0)
|
||||
editor->setBoundsInset (BorderSize (0));
|
||||
}
|
||||
|
||||
void Label::focusGained (FocusChangeType cause)
|
||||
{
|
||||
if (editSingleClick && cause == focusChangedByTabKey)
|
||||
showEditor();
|
||||
}
|
||||
|
||||
void Label::enablementChanged()
|
||||
{
|
||||
repaint();
|
||||
}
|
||||
|
||||
void Label::colourChanged()
|
||||
{
|
||||
repaint();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// We'll use a custom focus traverser here to make sure focus goes from the
|
||||
// text editor to another component rather than back to the label itself.
|
||||
class LabelKeyboardFocusTraverser : public KeyboardFocusTraverser
|
||||
{
|
||||
public:
|
||||
LabelKeyboardFocusTraverser() {}
|
||||
|
||||
Component* getNextComponent (Component* current)
|
||||
{
|
||||
return KeyboardFocusTraverser::getNextComponent (dynamic_cast <TextEditor*> (current) != 0
|
||||
? current->getParentComponent() : current);
|
||||
}
|
||||
|
||||
Component* getPreviousComponent (Component* current)
|
||||
{
|
||||
return KeyboardFocusTraverser::getPreviousComponent (dynamic_cast <TextEditor*> (current) != 0
|
||||
? current->getParentComponent() : current);
|
||||
}
|
||||
};
|
||||
|
||||
KeyboardFocusTraverser* Label::createFocusTraverser()
|
||||
{
|
||||
return new LabelKeyboardFocusTraverser();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void Label::addListener (LabelListener* const listener) throw()
|
||||
{
|
||||
jassert (listener != 0);
|
||||
if (listener != 0)
|
||||
listeners.add (listener);
|
||||
}
|
||||
|
||||
void Label::removeListener (LabelListener* const listener) throw()
|
||||
{
|
||||
listeners.removeValue (listener);
|
||||
}
|
||||
|
||||
void Label::handleAsyncUpdate()
|
||||
{
|
||||
for (int i = listeners.size(); --i >= 0;)
|
||||
{
|
||||
((LabelListener*) listeners.getUnchecked (i))->labelTextChanged (this);
|
||||
i = jmin (i, listeners.size());
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void Label::textEditorTextChanged (TextEditor& ed)
|
||||
{
|
||||
if (editor != 0)
|
||||
{
|
||||
jassert (&ed == editor);
|
||||
|
||||
if (! (hasKeyboardFocus (true) || isCurrentlyBlockedByAnotherModalComponent()))
|
||||
{
|
||||
if (lossOfFocusDiscardsChanges)
|
||||
textEditorEscapeKeyPressed (ed);
|
||||
else
|
||||
textEditorReturnKeyPressed (ed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Label::textEditorReturnKeyPressed (TextEditor& ed)
|
||||
{
|
||||
if (editor != 0)
|
||||
{
|
||||
jassert (&ed == editor);
|
||||
(void) ed;
|
||||
|
||||
const bool changed = updateFromTextEditorContents();
|
||||
hideEditor (true);
|
||||
|
||||
if (changed)
|
||||
textWasEdited();
|
||||
}
|
||||
}
|
||||
|
||||
void Label::textEditorEscapeKeyPressed (TextEditor& ed)
|
||||
{
|
||||
if (editor != 0)
|
||||
{
|
||||
jassert (&ed == editor);
|
||||
(void) ed;
|
||||
|
||||
editor->setText (text, false);
|
||||
hideEditor (true);
|
||||
}
|
||||
}
|
||||
|
||||
void Label::textEditorFocusLost (TextEditor& ed)
|
||||
{
|
||||
textEditorTextChanged (ed);
|
||||
}
|
||||
|
||||
|
||||
END_JUCE_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -154,11 +154,11 @@ public:
|
|||
*/
|
||||
void setBorderSize (int horizontalBorder, int verticalBorder);
|
||||
|
||||
/**
|
||||
/** Returns the size of the horizontal gap being left around the text.
|
||||
*/
|
||||
int getHorizontalBorderSize() const throw() { return horizontalBorderSize; }
|
||||
|
||||
/**
|
||||
/** Returns the size of the vertical gap being left around the text.
|
||||
*/
|
||||
int getVerticalBorderSize() const throw() { return verticalBorderSize; }
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -44,7 +44,7 @@ Image* juce_createIconForFile (const File& file);
|
|||
//==============================================================================
|
||||
FileListComponent::FileListComponent (DirectoryContentsList& listToShow)
|
||||
: ListBox (String::empty, 0),
|
||||
DirectoryContentsDisplayComponent (listToShow)
|
||||
DirectoryContentsDisplayComponent (listToShow)
|
||||
{
|
||||
setModel (this);
|
||||
fileList.addChangeListener (this);
|
||||
|
|
|
|||
|
|
@ -1200,31 +1200,31 @@ void LookAndFeel::positionComboBoxText (ComboBox& box, Label& label)
|
|||
//==============================================================================
|
||||
void LookAndFeel::drawLabel (Graphics& g, Label& label)
|
||||
{
|
||||
g.fillAll (label.findColour (Label::backgroundColourId));
|
||||
|
||||
if (! label.isBeingEdited())
|
||||
{
|
||||
const float alpha = label.isEnabled() ? 1.0f : 0.5f;
|
||||
|
||||
g.setColour (label.findColour (Label::textColourId).withMultipliedAlpha (alpha));
|
||||
g.setFont (label.getFont());
|
||||
g.drawFittedText (label.getText(),
|
||||
label.getHorizontalBorderSize(),
|
||||
label.getVerticalBorderSize(),
|
||||
label.getWidth() - 2 * label.getHorizontalBorderSize(),
|
||||
label.getHeight() - 2 * label.getVerticalBorderSize(),
|
||||
label.getJustificationType(),
|
||||
jmax (1, (int) (label.getHeight() / label.getFont().getHeight())),
|
||||
label.getMinimumHorizontalScale());
|
||||
|
||||
g.setColour (label.findColour (Label::outlineColourId).withMultipliedAlpha (alpha));
|
||||
g.drawRect (0, 0, label.getWidth(), label.getHeight());
|
||||
}
|
||||
else if (label.isEnabled())
|
||||
{
|
||||
g.setColour (label.findColour (Label::outlineColourId));
|
||||
g.drawRect (0, 0, label.getWidth(), label.getHeight());
|
||||
}
|
||||
g.fillAll (label.findColour (Label::backgroundColourId));
|
||||
|
||||
if (! label.isBeingEdited())
|
||||
{
|
||||
const float alpha = label.isEnabled() ? 1.0f : 0.5f;
|
||||
|
||||
g.setColour (label.findColour (Label::textColourId).withMultipliedAlpha (alpha));
|
||||
g.setFont (label.getFont());
|
||||
g.drawFittedText (label.getText(),
|
||||
label.getHorizontalBorderSize(),
|
||||
label.getVerticalBorderSize(),
|
||||
label.getWidth() - 2 * label.getHorizontalBorderSize(),
|
||||
label.getHeight() - 2 * label.getVerticalBorderSize(),
|
||||
label.getJustificationType(),
|
||||
jmax (1, (int) (label.getHeight() / label.getFont().getHeight())),
|
||||
label.getMinimumHorizontalScale());
|
||||
|
||||
g.setColour (label.findColour (Label::outlineColourId).withMultipliedAlpha (alpha));
|
||||
g.drawRect (0, 0, label.getWidth(), label.getHeight());
|
||||
}
|
||||
else if (label.isEnabled())
|
||||
{
|
||||
g.setColour (label.findColour (Label::outlineColourId));
|
||||
g.drawRect (0, 0, label.getWidth(), label.getHeight());
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
|
|||
|
|
@ -1,442 +1,442 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library - "Jules' Utility Class Extensions"
|
||||
Copyright 2004-7 by Raw Material Software ltd.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
JUCE can be redistributed and/or modified under the terms of the
|
||||
GNU General Public License, as published by the Free Software Foundation;
|
||||
either version 2 of the License, or (at your option) any later version.
|
||||
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with JUCE; if not, visit www.gnu.org/licenses or write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
If you'd like to release a closed-source product which uses JUCE, commercial
|
||||
licenses are also available: visit www.rawmaterialsoftware.com/juce for
|
||||
more information.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "../../../../juce_core/basics/juce_StandardHeader.h"
|
||||
|
||||
BEGIN_JUCE_NAMESPACE
|
||||
|
||||
#include "juce_PropertyPanel.h"
|
||||
#include "../lookandfeel/juce_LookAndFeel.h"
|
||||
#include "../../../../juce_core/text/juce_LocalisedStrings.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class PropertyHolderComponent : public Component
|
||||
{
|
||||
public:
|
||||
PropertyHolderComponent()
|
||||
{
|
||||
}
|
||||
|
||||
~PropertyHolderComponent()
|
||||
{
|
||||
deleteAllChildren();
|
||||
}
|
||||
|
||||
void paint (Graphics&)
|
||||
{
|
||||
}
|
||||
|
||||
void updateLayout (const int width);
|
||||
|
||||
void refreshAll() const;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class PropertySectionComponent : public Component
|
||||
{
|
||||
public:
|
||||
PropertySectionComponent (const String& sectionTitle,
|
||||
const Array <PropertyComponent*>& newProperties,
|
||||
const bool open)
|
||||
: Component (sectionTitle),
|
||||
titleHeight (sectionTitle.isNotEmpty() ? 22 : 0),
|
||||
isOpen_ (open)
|
||||
{
|
||||
for (int i = newProperties.size(); --i >= 0;)
|
||||
{
|
||||
addAndMakeVisible (newProperties.getUnchecked(i));
|
||||
newProperties.getUnchecked(i)->refresh();
|
||||
}
|
||||
}
|
||||
|
||||
~PropertySectionComponent()
|
||||
{
|
||||
deleteAllChildren();
|
||||
}
|
||||
|
||||
void paint (Graphics& g)
|
||||
{
|
||||
if (titleHeight > 0)
|
||||
getLookAndFeel().drawPropertyPanelSectionHeader (g, getName(), isOpen(), getWidth(), titleHeight);
|
||||
}
|
||||
|
||||
void resized()
|
||||
{
|
||||
int y = titleHeight;
|
||||
|
||||
for (int i = getNumChildComponents(); --i >= 0;)
|
||||
{
|
||||
PropertyComponent* const pec = dynamic_cast <PropertyComponent*> (getChildComponent (i));
|
||||
|
||||
if (pec != 0)
|
||||
{
|
||||
const int prefH = pec->getPreferredHeight();
|
||||
pec->setBounds (1, y, getWidth() - 2, prefH);
|
||||
y += prefH;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int getPreferredHeight() const
|
||||
{
|
||||
int y = titleHeight;
|
||||
|
||||
if (isOpen())
|
||||
{
|
||||
for (int i = 0; i < getNumChildComponents(); ++i)
|
||||
{
|
||||
PropertyComponent* pec = dynamic_cast <PropertyComponent*> (getChildComponent (i));
|
||||
|
||||
if (pec != 0)
|
||||
y += pec->getPreferredHeight();
|
||||
}
|
||||
}
|
||||
|
||||
return y;
|
||||
}
|
||||
|
||||
void setOpen (const bool open)
|
||||
{
|
||||
if (isOpen_ != open)
|
||||
{
|
||||
isOpen_ = open;
|
||||
|
||||
for (int i = 0; i < getNumChildComponents(); ++i)
|
||||
{
|
||||
PropertyComponent* pec = dynamic_cast <PropertyComponent*> (getChildComponent (i));
|
||||
|
||||
if (pec != 0)
|
||||
pec->setVisible (open);
|
||||
}
|
||||
|
||||
// (unable to use the syntax findParentComponentOfClass <DragAndDropContainer> () because of a VC6 compiler bug)
|
||||
PropertyPanel* const pp = findParentComponentOfClass ((PropertyPanel*) 0);
|
||||
|
||||
if (pp != 0)
|
||||
pp->resized();
|
||||
}
|
||||
}
|
||||
|
||||
bool isOpen() const throw()
|
||||
{
|
||||
return isOpen_;
|
||||
}
|
||||
|
||||
void refreshAll() const
|
||||
{
|
||||
for (int i = 0; i < getNumChildComponents(); ++i)
|
||||
{
|
||||
PropertyComponent* pec = dynamic_cast <PropertyComponent*> (getChildComponent (i));
|
||||
|
||||
if (pec != 0)
|
||||
pec->refresh();
|
||||
}
|
||||
}
|
||||
|
||||
void mouseDown (const MouseEvent&)
|
||||
{
|
||||
}
|
||||
|
||||
void mouseUp (const MouseEvent& e)
|
||||
{
|
||||
if (e.getMouseDownX() < titleHeight
|
||||
&& e.x < titleHeight
|
||||
&& e.y < titleHeight
|
||||
&& e.getNumberOfClicks() != 2)
|
||||
{
|
||||
setOpen (! isOpen());
|
||||
}
|
||||
}
|
||||
|
||||
void mouseDoubleClick (const MouseEvent& e)
|
||||
{
|
||||
if (e.y < titleHeight)
|
||||
setOpen (! isOpen());
|
||||
}
|
||||
|
||||
private:
|
||||
int titleHeight;
|
||||
bool isOpen_;
|
||||
};
|
||||
|
||||
void PropertyHolderComponent::updateLayout (const int width)
|
||||
{
|
||||
int y = 0;
|
||||
|
||||
for (int i = getNumChildComponents(); --i >= 0;)
|
||||
{
|
||||
PropertySectionComponent* const section
|
||||
= dynamic_cast <PropertySectionComponent*> (getChildComponent (i));
|
||||
|
||||
if (section != 0)
|
||||
{
|
||||
const int prefH = section->getPreferredHeight();
|
||||
section->setBounds (0, y, width, prefH);
|
||||
y += prefH;
|
||||
}
|
||||
}
|
||||
|
||||
setSize (width, y);
|
||||
repaint();
|
||||
}
|
||||
|
||||
void PropertyHolderComponent::refreshAll() const
|
||||
{
|
||||
for (int i = getNumChildComponents(); --i >= 0;)
|
||||
{
|
||||
PropertySectionComponent* const section
|
||||
= dynamic_cast <PropertySectionComponent*> (getChildComponent (i));
|
||||
|
||||
if (section != 0)
|
||||
section->refreshAll();
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
PropertyPanel::PropertyPanel()
|
||||
{
|
||||
messageWhenEmpty = TRANS("(nothing selected)");
|
||||
|
||||
addAndMakeVisible (viewport = new Viewport());
|
||||
viewport->setViewedComponent (propertyHolderComponent = new PropertyHolderComponent());
|
||||
viewport->setFocusContainer (true);
|
||||
}
|
||||
|
||||
PropertyPanel::~PropertyPanel()
|
||||
{
|
||||
clear();
|
||||
deleteAllChildren();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void PropertyPanel::paint (Graphics& g)
|
||||
{
|
||||
if (propertyHolderComponent->getNumChildComponents() == 0)
|
||||
{
|
||||
g.setColour (Colours::black.withAlpha (0.5f));
|
||||
g.setFont (14.0f);
|
||||
g.drawText (messageWhenEmpty, 0, 0, getWidth(), 30,
|
||||
Justification::centred, true);
|
||||
}
|
||||
}
|
||||
|
||||
void PropertyPanel::resized()
|
||||
{
|
||||
viewport->setBounds (0, 0, getWidth(), getHeight());
|
||||
updatePropHolderLayout();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void PropertyPanel::clear()
|
||||
{
|
||||
if (propertyHolderComponent->getNumChildComponents() > 0)
|
||||
{
|
||||
propertyHolderComponent->deleteAllChildren();
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
|
||||
void PropertyPanel::addProperties (const Array <PropertyComponent*>& newProperties)
|
||||
{
|
||||
if (propertyHolderComponent->getNumChildComponents() == 0)
|
||||
repaint();
|
||||
|
||||
propertyHolderComponent->addAndMakeVisible (new PropertySectionComponent (String::empty,
|
||||
newProperties,
|
||||
true), 0);
|
||||
updatePropHolderLayout();
|
||||
}
|
||||
|
||||
void PropertyPanel::addSection (const String& sectionTitle,
|
||||
const Array <PropertyComponent*>& newProperties,
|
||||
const bool shouldBeOpen)
|
||||
{
|
||||
jassert (sectionTitle.isNotEmpty());
|
||||
|
||||
if (propertyHolderComponent->getNumChildComponents() == 0)
|
||||
repaint();
|
||||
|
||||
propertyHolderComponent->addAndMakeVisible (new PropertySectionComponent (sectionTitle,
|
||||
newProperties,
|
||||
shouldBeOpen), 0);
|
||||
|
||||
updatePropHolderLayout();
|
||||
}
|
||||
|
||||
void PropertyPanel::updatePropHolderLayout() const
|
||||
{
|
||||
const int maxWidth = viewport->getMaximumVisibleWidth();
|
||||
((PropertyHolderComponent*) propertyHolderComponent)->updateLayout (maxWidth);
|
||||
|
||||
const int newMaxWidth = viewport->getMaximumVisibleWidth();
|
||||
if (maxWidth != newMaxWidth)
|
||||
{
|
||||
// need to do this twice because of scrollbars changing the size, etc.
|
||||
((PropertyHolderComponent*) propertyHolderComponent)->updateLayout (newMaxWidth);
|
||||
}
|
||||
}
|
||||
|
||||
void PropertyPanel::refreshAll() const
|
||||
{
|
||||
((PropertyHolderComponent*) propertyHolderComponent)->refreshAll();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
const StringArray PropertyPanel::getSectionNames() const
|
||||
{
|
||||
StringArray s;
|
||||
|
||||
for (int i = 0; i < propertyHolderComponent->getNumChildComponents(); ++i)
|
||||
{
|
||||
PropertySectionComponent* const section = dynamic_cast <PropertySectionComponent*> (propertyHolderComponent->getChildComponent (i));
|
||||
|
||||
if (section != 0 && section->getName().isNotEmpty())
|
||||
s.add (section->getName());
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
bool PropertyPanel::isSectionOpen (const int sectionIndex) const
|
||||
{
|
||||
int index = 0;
|
||||
|
||||
for (int i = 0; i < propertyHolderComponent->getNumChildComponents(); ++i)
|
||||
{
|
||||
PropertySectionComponent* const section = dynamic_cast <PropertySectionComponent*> (propertyHolderComponent->getChildComponent (i));
|
||||
|
||||
if (section != 0 && section->getName().isNotEmpty())
|
||||
{
|
||||
if (index == sectionIndex)
|
||||
return section->isOpen();
|
||||
|
||||
++index;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void PropertyPanel::setSectionOpen (const int sectionIndex, const bool shouldBeOpen)
|
||||
{
|
||||
int index = 0;
|
||||
|
||||
for (int i = 0; i < propertyHolderComponent->getNumChildComponents(); ++i)
|
||||
{
|
||||
PropertySectionComponent* const section = dynamic_cast <PropertySectionComponent*> (propertyHolderComponent->getChildComponent (i));
|
||||
|
||||
if (section != 0 && section->getName().isNotEmpty())
|
||||
{
|
||||
if (index == sectionIndex)
|
||||
{
|
||||
section->setOpen (shouldBeOpen);
|
||||
break;
|
||||
}
|
||||
|
||||
++index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PropertyPanel::setSectionEnabled (const int sectionIndex, const bool shouldBeEnabled)
|
||||
{
|
||||
int index = 0;
|
||||
|
||||
for (int i = 0; i < propertyHolderComponent->getNumChildComponents(); ++i)
|
||||
{
|
||||
PropertySectionComponent* const section = dynamic_cast <PropertySectionComponent*> (propertyHolderComponent->getChildComponent (i));
|
||||
|
||||
if (section != 0 && section->getName().isNotEmpty())
|
||||
{
|
||||
if (index == sectionIndex)
|
||||
{
|
||||
section->setEnabled (shouldBeEnabled);
|
||||
break;
|
||||
}
|
||||
|
||||
++index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
XmlElement* PropertyPanel::getOpennessState() const
|
||||
{
|
||||
XmlElement* const xml = new XmlElement (T("PROPERTYPANELSTATE"));
|
||||
|
||||
const StringArray sections (getSectionNames());
|
||||
|
||||
for (int i = 0; i < sections.size(); ++i)
|
||||
{
|
||||
if (sections[i].isNotEmpty())
|
||||
{
|
||||
XmlElement* const e = new XmlElement (T("SECTION"));
|
||||
e->setAttribute (T("name"), sections[i]);
|
||||
e->setAttribute (T("open"), isSectionOpen (i) ? 1 : 0);
|
||||
xml->addChildElement (e);
|
||||
}
|
||||
}
|
||||
|
||||
return xml;
|
||||
}
|
||||
|
||||
void PropertyPanel::restoreOpennessState (const XmlElement& xml)
|
||||
{
|
||||
if (xml.hasTagName (T("PROPERTYPANELSTATE")))
|
||||
{
|
||||
const StringArray sections (getSectionNames());
|
||||
|
||||
forEachXmlChildElementWithTagName (xml, e, T("SECTION"))
|
||||
{
|
||||
setSectionOpen (sections.indexOf (e->getStringAttribute (T("name"))),
|
||||
e->getBoolAttribute (T("open")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void PropertyPanel::setMessageWhenEmpty (const String& newMessage)
|
||||
{
|
||||
if (messageWhenEmpty != newMessage)
|
||||
{
|
||||
messageWhenEmpty = newMessage;
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
|
||||
const String& PropertyPanel::getMessageWhenEmpty() const throw()
|
||||
{
|
||||
return messageWhenEmpty;
|
||||
}
|
||||
|
||||
|
||||
END_JUCE_NAMESPACE
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library - "Jules' Utility Class Extensions"
|
||||
Copyright 2004-7 by Raw Material Software ltd.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
JUCE can be redistributed and/or modified under the terms of the
|
||||
GNU General Public License, as published by the Free Software Foundation;
|
||||
either version 2 of the License, or (at your option) any later version.
|
||||
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with JUCE; if not, visit www.gnu.org/licenses or write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
If you'd like to release a closed-source product which uses JUCE, commercial
|
||||
licenses are also available: visit www.rawmaterialsoftware.com/juce for
|
||||
more information.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "../../../../juce_core/basics/juce_StandardHeader.h"
|
||||
|
||||
BEGIN_JUCE_NAMESPACE
|
||||
|
||||
#include "juce_PropertyPanel.h"
|
||||
#include "../lookandfeel/juce_LookAndFeel.h"
|
||||
#include "../../../../juce_core/text/juce_LocalisedStrings.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class PropertyHolderComponent : public Component
|
||||
{
|
||||
public:
|
||||
PropertyHolderComponent()
|
||||
{
|
||||
}
|
||||
|
||||
~PropertyHolderComponent()
|
||||
{
|
||||
deleteAllChildren();
|
||||
}
|
||||
|
||||
void paint (Graphics&)
|
||||
{
|
||||
}
|
||||
|
||||
void updateLayout (const int width);
|
||||
|
||||
void refreshAll() const;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class PropertySectionComponent : public Component
|
||||
{
|
||||
public:
|
||||
PropertySectionComponent (const String& sectionTitle,
|
||||
const Array <PropertyComponent*>& newProperties,
|
||||
const bool open)
|
||||
: Component (sectionTitle),
|
||||
titleHeight (sectionTitle.isNotEmpty() ? 22 : 0),
|
||||
isOpen_ (open)
|
||||
{
|
||||
for (int i = newProperties.size(); --i >= 0;)
|
||||
{
|
||||
addAndMakeVisible (newProperties.getUnchecked(i));
|
||||
newProperties.getUnchecked(i)->refresh();
|
||||
}
|
||||
}
|
||||
|
||||
~PropertySectionComponent()
|
||||
{
|
||||
deleteAllChildren();
|
||||
}
|
||||
|
||||
void paint (Graphics& g)
|
||||
{
|
||||
if (titleHeight > 0)
|
||||
getLookAndFeel().drawPropertyPanelSectionHeader (g, getName(), isOpen(), getWidth(), titleHeight);
|
||||
}
|
||||
|
||||
void resized()
|
||||
{
|
||||
int y = titleHeight;
|
||||
|
||||
for (int i = getNumChildComponents(); --i >= 0;)
|
||||
{
|
||||
PropertyComponent* const pec = dynamic_cast <PropertyComponent*> (getChildComponent (i));
|
||||
|
||||
if (pec != 0)
|
||||
{
|
||||
const int prefH = pec->getPreferredHeight();
|
||||
pec->setBounds (1, y, getWidth() - 2, prefH);
|
||||
y += prefH;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int getPreferredHeight() const
|
||||
{
|
||||
int y = titleHeight;
|
||||
|
||||
if (isOpen())
|
||||
{
|
||||
for (int i = 0; i < getNumChildComponents(); ++i)
|
||||
{
|
||||
PropertyComponent* pec = dynamic_cast <PropertyComponent*> (getChildComponent (i));
|
||||
|
||||
if (pec != 0)
|
||||
y += pec->getPreferredHeight();
|
||||
}
|
||||
}
|
||||
|
||||
return y;
|
||||
}
|
||||
|
||||
void setOpen (const bool open)
|
||||
{
|
||||
if (isOpen_ != open)
|
||||
{
|
||||
isOpen_ = open;
|
||||
|
||||
for (int i = 0; i < getNumChildComponents(); ++i)
|
||||
{
|
||||
PropertyComponent* pec = dynamic_cast <PropertyComponent*> (getChildComponent (i));
|
||||
|
||||
if (pec != 0)
|
||||
pec->setVisible (open);
|
||||
}
|
||||
|
||||
// (unable to use the syntax findParentComponentOfClass <DragAndDropContainer> () because of a VC6 compiler bug)
|
||||
PropertyPanel* const pp = findParentComponentOfClass ((PropertyPanel*) 0);
|
||||
|
||||
if (pp != 0)
|
||||
pp->resized();
|
||||
}
|
||||
}
|
||||
|
||||
bool isOpen() const throw()
|
||||
{
|
||||
return isOpen_;
|
||||
}
|
||||
|
||||
void refreshAll() const
|
||||
{
|
||||
for (int i = 0; i < getNumChildComponents(); ++i)
|
||||
{
|
||||
PropertyComponent* pec = dynamic_cast <PropertyComponent*> (getChildComponent (i));
|
||||
|
||||
if (pec != 0)
|
||||
pec->refresh();
|
||||
}
|
||||
}
|
||||
|
||||
void mouseDown (const MouseEvent&)
|
||||
{
|
||||
}
|
||||
|
||||
void mouseUp (const MouseEvent& e)
|
||||
{
|
||||
if (e.getMouseDownX() < titleHeight
|
||||
&& e.x < titleHeight
|
||||
&& e.y < titleHeight
|
||||
&& e.getNumberOfClicks() != 2)
|
||||
{
|
||||
setOpen (! isOpen());
|
||||
}
|
||||
}
|
||||
|
||||
void mouseDoubleClick (const MouseEvent& e)
|
||||
{
|
||||
if (e.y < titleHeight)
|
||||
setOpen (! isOpen());
|
||||
}
|
||||
|
||||
private:
|
||||
int titleHeight;
|
||||
bool isOpen_;
|
||||
};
|
||||
|
||||
void PropertyHolderComponent::updateLayout (const int width)
|
||||
{
|
||||
int y = 0;
|
||||
|
||||
for (int i = getNumChildComponents(); --i >= 0;)
|
||||
{
|
||||
PropertySectionComponent* const section
|
||||
= dynamic_cast <PropertySectionComponent*> (getChildComponent (i));
|
||||
|
||||
if (section != 0)
|
||||
{
|
||||
const int prefH = section->getPreferredHeight();
|
||||
section->setBounds (0, y, width, prefH);
|
||||
y += prefH;
|
||||
}
|
||||
}
|
||||
|
||||
setSize (width, y);
|
||||
repaint();
|
||||
}
|
||||
|
||||
void PropertyHolderComponent::refreshAll() const
|
||||
{
|
||||
for (int i = getNumChildComponents(); --i >= 0;)
|
||||
{
|
||||
PropertySectionComponent* const section
|
||||
= dynamic_cast <PropertySectionComponent*> (getChildComponent (i));
|
||||
|
||||
if (section != 0)
|
||||
section->refreshAll();
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
PropertyPanel::PropertyPanel()
|
||||
{
|
||||
messageWhenEmpty = TRANS("(nothing selected)");
|
||||
|
||||
addAndMakeVisible (viewport = new Viewport());
|
||||
viewport->setViewedComponent (propertyHolderComponent = new PropertyHolderComponent());
|
||||
viewport->setFocusContainer (true);
|
||||
}
|
||||
|
||||
PropertyPanel::~PropertyPanel()
|
||||
{
|
||||
clear();
|
||||
deleteAllChildren();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void PropertyPanel::paint (Graphics& g)
|
||||
{
|
||||
if (propertyHolderComponent->getNumChildComponents() == 0)
|
||||
{
|
||||
g.setColour (Colours::black.withAlpha (0.5f));
|
||||
g.setFont (14.0f);
|
||||
g.drawText (messageWhenEmpty, 0, 0, getWidth(), 30,
|
||||
Justification::centred, true);
|
||||
}
|
||||
}
|
||||
|
||||
void PropertyPanel::resized()
|
||||
{
|
||||
viewport->setBounds (0, 0, getWidth(), getHeight());
|
||||
updatePropHolderLayout();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void PropertyPanel::clear()
|
||||
{
|
||||
if (propertyHolderComponent->getNumChildComponents() > 0)
|
||||
{
|
||||
propertyHolderComponent->deleteAllChildren();
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
|
||||
void PropertyPanel::addProperties (const Array <PropertyComponent*>& newProperties)
|
||||
{
|
||||
if (propertyHolderComponent->getNumChildComponents() == 0)
|
||||
repaint();
|
||||
|
||||
propertyHolderComponent->addAndMakeVisible (new PropertySectionComponent (String::empty,
|
||||
newProperties,
|
||||
true), 0);
|
||||
updatePropHolderLayout();
|
||||
}
|
||||
|
||||
void PropertyPanel::addSection (const String& sectionTitle,
|
||||
const Array <PropertyComponent*>& newProperties,
|
||||
const bool shouldBeOpen)
|
||||
{
|
||||
jassert (sectionTitle.isNotEmpty());
|
||||
|
||||
if (propertyHolderComponent->getNumChildComponents() == 0)
|
||||
repaint();
|
||||
|
||||
propertyHolderComponent->addAndMakeVisible (new PropertySectionComponent (sectionTitle,
|
||||
newProperties,
|
||||
shouldBeOpen), 0);
|
||||
|
||||
updatePropHolderLayout();
|
||||
}
|
||||
|
||||
void PropertyPanel::updatePropHolderLayout() const
|
||||
{
|
||||
const int maxWidth = viewport->getMaximumVisibleWidth();
|
||||
((PropertyHolderComponent*) propertyHolderComponent)->updateLayout (maxWidth);
|
||||
|
||||
const int newMaxWidth = viewport->getMaximumVisibleWidth();
|
||||
if (maxWidth != newMaxWidth)
|
||||
{
|
||||
// need to do this twice because of scrollbars changing the size, etc.
|
||||
((PropertyHolderComponent*) propertyHolderComponent)->updateLayout (newMaxWidth);
|
||||
}
|
||||
}
|
||||
|
||||
void PropertyPanel::refreshAll() const
|
||||
{
|
||||
((PropertyHolderComponent*) propertyHolderComponent)->refreshAll();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
const StringArray PropertyPanel::getSectionNames() const
|
||||
{
|
||||
StringArray s;
|
||||
|
||||
for (int i = 0; i < propertyHolderComponent->getNumChildComponents(); ++i)
|
||||
{
|
||||
PropertySectionComponent* const section = dynamic_cast <PropertySectionComponent*> (propertyHolderComponent->getChildComponent (i));
|
||||
|
||||
if (section != 0 && section->getName().isNotEmpty())
|
||||
s.add (section->getName());
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
bool PropertyPanel::isSectionOpen (const int sectionIndex) const
|
||||
{
|
||||
int index = 0;
|
||||
|
||||
for (int i = 0; i < propertyHolderComponent->getNumChildComponents(); ++i)
|
||||
{
|
||||
PropertySectionComponent* const section = dynamic_cast <PropertySectionComponent*> (propertyHolderComponent->getChildComponent (i));
|
||||
|
||||
if (section != 0 && section->getName().isNotEmpty())
|
||||
{
|
||||
if (index == sectionIndex)
|
||||
return section->isOpen();
|
||||
|
||||
++index;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void PropertyPanel::setSectionOpen (const int sectionIndex, const bool shouldBeOpen)
|
||||
{
|
||||
int index = 0;
|
||||
|
||||
for (int i = 0; i < propertyHolderComponent->getNumChildComponents(); ++i)
|
||||
{
|
||||
PropertySectionComponent* const section = dynamic_cast <PropertySectionComponent*> (propertyHolderComponent->getChildComponent (i));
|
||||
|
||||
if (section != 0 && section->getName().isNotEmpty())
|
||||
{
|
||||
if (index == sectionIndex)
|
||||
{
|
||||
section->setOpen (shouldBeOpen);
|
||||
break;
|
||||
}
|
||||
|
||||
++index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PropertyPanel::setSectionEnabled (const int sectionIndex, const bool shouldBeEnabled)
|
||||
{
|
||||
int index = 0;
|
||||
|
||||
for (int i = 0; i < propertyHolderComponent->getNumChildComponents(); ++i)
|
||||
{
|
||||
PropertySectionComponent* const section = dynamic_cast <PropertySectionComponent*> (propertyHolderComponent->getChildComponent (i));
|
||||
|
||||
if (section != 0 && section->getName().isNotEmpty())
|
||||
{
|
||||
if (index == sectionIndex)
|
||||
{
|
||||
section->setEnabled (shouldBeEnabled);
|
||||
break;
|
||||
}
|
||||
|
||||
++index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
XmlElement* PropertyPanel::getOpennessState() const
|
||||
{
|
||||
XmlElement* const xml = new XmlElement (T("PROPERTYPANELSTATE"));
|
||||
|
||||
const StringArray sections (getSectionNames());
|
||||
|
||||
for (int i = 0; i < sections.size(); ++i)
|
||||
{
|
||||
if (sections[i].isNotEmpty())
|
||||
{
|
||||
XmlElement* const e = new XmlElement (T("SECTION"));
|
||||
e->setAttribute (T("name"), sections[i]);
|
||||
e->setAttribute (T("open"), isSectionOpen (i) ? 1 : 0);
|
||||
xml->addChildElement (e);
|
||||
}
|
||||
}
|
||||
|
||||
return xml;
|
||||
}
|
||||
|
||||
void PropertyPanel::restoreOpennessState (const XmlElement& xml)
|
||||
{
|
||||
if (xml.hasTagName (T("PROPERTYPANELSTATE")))
|
||||
{
|
||||
const StringArray sections (getSectionNames());
|
||||
|
||||
forEachXmlChildElementWithTagName (xml, e, T("SECTION"))
|
||||
{
|
||||
setSectionOpen (sections.indexOf (e->getStringAttribute (T("name"))),
|
||||
e->getBoolAttribute (T("open")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void PropertyPanel::setMessageWhenEmpty (const String& newMessage)
|
||||
{
|
||||
if (messageWhenEmpty != newMessage)
|
||||
{
|
||||
messageWhenEmpty = newMessage;
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
|
||||
const String& PropertyPanel::getMessageWhenEmpty() const throw()
|
||||
{
|
||||
return messageWhenEmpty;
|
||||
}
|
||||
|
||||
|
||||
END_JUCE_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ BEGIN_JUCE_NAMESPACE
|
|||
|
||||
|
||||
//==============================================================================
|
||||
class SimpleDeviceManagerInputLevelMeter : public Component,
|
||||
class SimpleDeviceManagerInputLevelMeter : public Component,
|
||||
public Timer
|
||||
{
|
||||
public:
|
||||
|
|
@ -214,7 +214,7 @@ class AudioDeviceSettingsPanel : public Component,
|
|||
public ButtonListener
|
||||
{
|
||||
public:
|
||||
AudioDeviceSettingsPanel (AudioIODeviceType* type_,
|
||||
AudioDeviceSettingsPanel (AudioIODeviceType* type_,
|
||||
AudioIODeviceType::DeviceSetupDetails& setup_,
|
||||
const bool hideAdvancedOptionsWithButton)
|
||||
: type (type_),
|
||||
|
|
@ -279,7 +279,7 @@ public:
|
|||
outputDeviceDropDown->setBounds (lx, y, w, h);
|
||||
|
||||
if (testButton != 0)
|
||||
testButton->setBounds (proportionOfWidth (0.77f),
|
||||
testButton->setBounds (proportionOfWidth (0.77f),
|
||||
outputDeviceDropDown->getY(),
|
||||
proportionOfWidth (0.18f),
|
||||
h);
|
||||
|
|
@ -290,7 +290,7 @@ public:
|
|||
{
|
||||
inputDeviceDropDown->setBounds (lx, y, w, h);
|
||||
|
||||
inputLevelMeter->setBounds (proportionOfWidth (0.77f),
|
||||
inputLevelMeter->setBounds (proportionOfWidth (0.77f),
|
||||
inputDeviceDropDown->getY(),
|
||||
proportionOfWidth (0.18f),
|
||||
h);
|
||||
|
|
@ -323,7 +323,7 @@ public:
|
|||
|
||||
if (sampleRateDropDown != 0)
|
||||
{
|
||||
sampleRateDropDown->setVisible (showAdvancedSettingsButton == 0
|
||||
sampleRateDropDown->setVisible (showAdvancedSettingsButton == 0
|
||||
|| ! showAdvancedSettingsButton->isVisible());
|
||||
|
||||
sampleRateDropDown->setBounds (lx, y, w, h);
|
||||
|
|
@ -360,11 +360,11 @@ public:
|
|||
|| comboBoxThatHasChanged == inputDeviceDropDown)
|
||||
{
|
||||
if (outputDeviceDropDown != 0)
|
||||
config.outputDeviceName = outputDeviceDropDown->getSelectedId() < 0 ? String::empty
|
||||
config.outputDeviceName = outputDeviceDropDown->getSelectedId() < 0 ? String::empty
|
||||
: outputDeviceDropDown->getText();
|
||||
|
||||
if (inputDeviceDropDown != 0)
|
||||
config.inputDeviceName = inputDeviceDropDown->getSelectedId() < 0 ? String::empty
|
||||
config.inputDeviceName = inputDeviceDropDown->getSelectedId() < 0 ? String::empty
|
||||
: inputDeviceDropDown->getText();
|
||||
|
||||
if (! type->hasSeparateInputsAndOutputs())
|
||||
|
|
@ -460,7 +460,7 @@ public:
|
|||
outputDeviceDropDown->addListener (this);
|
||||
addAndMakeVisible (outputDeviceDropDown);
|
||||
|
||||
outputDeviceLabel = new Label (String::empty,
|
||||
outputDeviceLabel = new Label (String::empty,
|
||||
type->hasSeparateInputsAndOutputs() ? TRANS ("output:")
|
||||
: TRANS ("device:"));
|
||||
outputDeviceLabel->attachToComponent (outputDeviceDropDown, true);
|
||||
|
|
@ -486,7 +486,7 @@ public:
|
|||
inputDeviceLabel = new Label (String::empty, TRANS ("input:"));
|
||||
inputDeviceLabel->attachToComponent (inputDeviceDropDown, true);
|
||||
|
||||
addAndMakeVisible (inputLevelMeter
|
||||
addAndMakeVisible (inputLevelMeter
|
||||
= new SimpleDeviceManagerInputLevelMeter (setup.manager));
|
||||
}
|
||||
|
||||
|
|
@ -499,13 +499,13 @@ public:
|
|||
|
||||
if (currentDevice != 0)
|
||||
{
|
||||
if (setup.maxNumOutputChannels > 0
|
||||
if (setup.maxNumOutputChannels > 0
|
||||
&& setup.minNumOutputChannels < setup.manager->getCurrentAudioDevice()->getOutputChannelNames().size())
|
||||
{
|
||||
if (outputChanList == 0)
|
||||
{
|
||||
addAndMakeVisible (outputChanList
|
||||
= new ChannelSelectorListBox (setup, ChannelSelectorListBox::audioOutputType,
|
||||
addAndMakeVisible (outputChanList
|
||||
= new ChannelSelectorListBox (setup, ChannelSelectorListBox::audioOutputType,
|
||||
TRANS ("(no audio output channels found)")));
|
||||
outputChanLabel = new Label (String::empty, TRANS ("active output channels:"));
|
||||
outputChanLabel->attachToComponent (outputChanList, true);
|
||||
|
|
@ -525,7 +525,7 @@ public:
|
|||
if (inputChanList == 0)
|
||||
{
|
||||
addAndMakeVisible (inputChanList
|
||||
= new ChannelSelectorListBox (setup, ChannelSelectorListBox::audioInputType,
|
||||
= new ChannelSelectorListBox (setup, ChannelSelectorListBox::audioInputType,
|
||||
TRANS ("(no audio input channels found)")));
|
||||
inputChanLabel = new Label (String::empty, TRANS ("active input channels:"));
|
||||
inputChanLabel->attachToComponent (inputChanList, true);
|
||||
|
|
@ -832,7 +832,7 @@ private:
|
|||
|
||||
int getBestHeight (int maxHeight)
|
||||
{
|
||||
return getRowHeight() * jlimit (2, jmax (2, maxHeight / getRowHeight()),
|
||||
return getRowHeight() * jlimit (2, jmax (2, maxHeight / getRowHeight()),
|
||||
getNumRows())
|
||||
+ getOutlineThickness() * 2;
|
||||
}
|
||||
|
|
@ -974,7 +974,7 @@ AudioDeviceSelectorComponent::AudioDeviceSelectorComponent (AudioDeviceManager&
|
|||
for (int i = 0; i < deviceManager_.getAvailableDeviceTypes().size(); ++i)
|
||||
{
|
||||
deviceTypeDropDown
|
||||
->addItem (deviceManager_.getAvailableDeviceTypes().getUnchecked(i)->getTypeName(),
|
||||
->addItem (deviceManager_.getAvailableDeviceTypes().getUnchecked(i)->getTypeName(),
|
||||
i + 1);
|
||||
}
|
||||
|
||||
|
|
@ -1100,15 +1100,15 @@ void AudioDeviceSelectorComponent::changeListenerCallback (void*)
|
|||
deviceTypeDropDown->setText (deviceManager.getCurrentAudioDeviceType(), false);
|
||||
}
|
||||
|
||||
if (audioDeviceSettingsComp == 0
|
||||
if (audioDeviceSettingsComp == 0
|
||||
|| audioDeviceSettingsCompType != deviceManager.getCurrentAudioDeviceType())
|
||||
{
|
||||
audioDeviceSettingsCompType = deviceManager.getCurrentAudioDeviceType();
|
||||
|
||||
deleteAndZero (audioDeviceSettingsComp);
|
||||
|
||||
AudioIODeviceType* const type
|
||||
= deviceManager.getAvailableDeviceTypes() [deviceTypeDropDown == 0
|
||||
AudioIODeviceType* const type
|
||||
= deviceManager.getAvailableDeviceTypes() [deviceTypeDropDown == 0
|
||||
? 0 : deviceTypeDropDown->getSelectedId() - 1];
|
||||
|
||||
if (type != 0)
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ public:
|
|||
@param maxAudioOutputChannels the maximum number of audio output channels that the application needs
|
||||
@param showMidiInputOptions if true, the component will allow the user to select which midi inputs are enabled
|
||||
@param showMidiOutputSelector if true, the component will let the user choose a default midi output device
|
||||
@param showChannelsAsStereoPairs if true, channels will be treated as pairs; if false, channels will be
|
||||
@param showChannelsAsStereoPairs if true, channels will be treated as pairs; if false, channels will be
|
||||
treated as a set of separate mono channels.
|
||||
@param hideAdvancedOptionsWithButton if true, only the minimum amount of UI components
|
||||
are shown, with an "advanced" button that shows the rest of them
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,378 +1,378 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library - "Jules' Utility Class Extensions"
|
||||
Copyright 2004-7 by Raw Material Software ltd.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
JUCE can be redistributed and/or modified under the terms of the
|
||||
GNU General Public License, as published by the Free Software Foundation;
|
||||
either version 2 of the License, or (at your option) any later version.
|
||||
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with JUCE; if not, visit www.gnu.org/licenses or write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
If you'd like to release a closed-source product which uses JUCE, commercial
|
||||
licenses are also available: visit www.rawmaterialsoftware.com/juce for
|
||||
more information.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "../../../../../juce_core/basics/juce_StandardHeader.h"
|
||||
|
||||
#if JUCE_MSVC
|
||||
#pragma warning (push)
|
||||
#endif
|
||||
|
||||
namespace jpeglibNamespace
|
||||
{
|
||||
extern "C"
|
||||
{
|
||||
#define JPEG_INTERNALS
|
||||
#undef FAR
|
||||
#include "jpglib/jpeglib.h"
|
||||
|
||||
#include "jpglib/jcapimin.c"
|
||||
#include "jpglib/jcapistd.c"
|
||||
#include "jpglib/jccoefct.c"
|
||||
#include "jpglib/jccolor.c"
|
||||
#undef FIX
|
||||
#include "jpglib/jcdctmgr.c"
|
||||
#undef CONST_BITS
|
||||
#include "jpglib/jchuff.c"
|
||||
#undef emit_byte
|
||||
#include "jpglib/jcinit.c"
|
||||
#include "jpglib/jcmainct.c"
|
||||
#include "jpglib/jcmarker.c"
|
||||
#include "jpglib/jcmaster.c"
|
||||
#include "jpglib/jcomapi.c"
|
||||
#include "jpglib/jcparam.c"
|
||||
#include "jpglib/jcphuff.c"
|
||||
#include "jpglib/jcprepct.c"
|
||||
#include "jpglib/jcsample.c"
|
||||
#include "jpglib/jctrans.c"
|
||||
#include "jpglib/jdapistd.c"
|
||||
#include "jpglib/jdapimin.c"
|
||||
#include "jpglib/jdatasrc.c"
|
||||
#include "jpglib/jdcoefct.c"
|
||||
#undef FIX
|
||||
#include "jpglib/jdcolor.c"
|
||||
#undef FIX
|
||||
#include "jpglib/jddctmgr.c"
|
||||
#undef CONST_BITS
|
||||
#undef ASSIGN_STATE
|
||||
#include "jpglib/jdhuff.c"
|
||||
#include "jpglib/jdinput.c"
|
||||
#include "jpglib/jdmainct.c"
|
||||
#include "jpglib/jdmarker.c"
|
||||
#include "jpglib/jdmaster.c"
|
||||
#undef FIX
|
||||
#include "jpglib/jdmerge.c"
|
||||
#undef ASSIGN_STATE
|
||||
#include "jpglib/jdphuff.c"
|
||||
#include "jpglib/jdpostct.c"
|
||||
#undef FIX
|
||||
#include "jpglib/jdsample.c"
|
||||
#include "jpglib/jdtrans.c"
|
||||
#include "jpglib/jfdctflt.c"
|
||||
#include "jpglib/jfdctint.c"
|
||||
#undef CONST_BITS
|
||||
#undef MULTIPLY
|
||||
#undef FIX_0_541196100
|
||||
#include "jpglib/jfdctfst.c"
|
||||
#undef FIX_0_541196100
|
||||
#include "jpglib/jidctflt.c"
|
||||
#undef CONST_BITS
|
||||
#undef FIX_1_847759065
|
||||
#undef MULTIPLY
|
||||
#undef DEQUANTIZE
|
||||
#undef DESCALE
|
||||
#include "jpglib/jidctfst.c"
|
||||
#undef CONST_BITS
|
||||
#undef FIX_1_847759065
|
||||
#undef MULTIPLY
|
||||
#undef DEQUANTIZE
|
||||
#include "jpglib/jidctint.c"
|
||||
#include "jpglib/jidctred.c"
|
||||
#include "jpglib/jmemmgr.c"
|
||||
#include "jpglib/jmemnobs.c"
|
||||
#include "jpglib/jquant1.c"
|
||||
#include "jpglib/jquant2.c"
|
||||
#include "jpglib/jutils.c"
|
||||
#include "jpglib/transupp.c"
|
||||
}
|
||||
}
|
||||
|
||||
#if JUCE_MSVC
|
||||
#pragma warning (pop)
|
||||
#endif
|
||||
|
||||
BEGIN_JUCE_NAMESPACE
|
||||
|
||||
#include "../juce_Image.h"
|
||||
#include "../../../../../juce_core/io/juce_InputStream.h"
|
||||
#include "../../../../../juce_core/io/juce_OutputStream.h"
|
||||
#include "../../colour/juce_PixelFormats.h"
|
||||
|
||||
using namespace jpeglibNamespace;
|
||||
|
||||
//==============================================================================
|
||||
struct JPEGDecodingFailure {};
|
||||
|
||||
static void fatalErrorHandler (j_common_ptr)
|
||||
{
|
||||
throw JPEGDecodingFailure();
|
||||
}
|
||||
|
||||
static void silentErrorCallback1 (j_common_ptr) {}
|
||||
static void silentErrorCallback2 (j_common_ptr, int) {}
|
||||
static void silentErrorCallback3 (j_common_ptr, char*) {}
|
||||
|
||||
static void setupSilentErrorHandler (struct jpeg_error_mgr& err)
|
||||
{
|
||||
zerostruct (err);
|
||||
|
||||
err.error_exit = fatalErrorHandler;
|
||||
err.emit_message = silentErrorCallback2;
|
||||
err.output_message = silentErrorCallback1;
|
||||
err.format_message = silentErrorCallback3;
|
||||
err.reset_error_mgr = silentErrorCallback1;
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
static void dummyCallback1 (j_decompress_ptr) throw()
|
||||
{
|
||||
}
|
||||
|
||||
static void jpegSkip (j_decompress_ptr decompStruct, long num) throw()
|
||||
{
|
||||
decompStruct->src->next_input_byte += num;
|
||||
|
||||
num = jmin (num, (int) decompStruct->src->bytes_in_buffer);
|
||||
decompStruct->src->bytes_in_buffer -= num;
|
||||
}
|
||||
|
||||
static boolean jpegFill (j_decompress_ptr) throw()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
Image* juce_loadJPEGImageFromStream (InputStream& in) throw()
|
||||
{
|
||||
MemoryBlock mb;
|
||||
in.readIntoMemoryBlock (mb);
|
||||
|
||||
Image* image = 0;
|
||||
|
||||
if (mb.getSize() > 16)
|
||||
{
|
||||
struct jpeg_decompress_struct jpegDecompStruct;
|
||||
|
||||
struct jpeg_error_mgr jerr;
|
||||
setupSilentErrorHandler (jerr);
|
||||
jpegDecompStruct.err = &jerr;
|
||||
|
||||
jpeg_create_decompress (&jpegDecompStruct);
|
||||
|
||||
jpegDecompStruct.src = (jpeg_source_mgr*)(jpegDecompStruct.mem->alloc_small)
|
||||
((j_common_ptr)(&jpegDecompStruct), JPOOL_PERMANENT, sizeof (jpeg_source_mgr));
|
||||
|
||||
jpegDecompStruct.src->init_source = dummyCallback1;
|
||||
jpegDecompStruct.src->fill_input_buffer = jpegFill;
|
||||
jpegDecompStruct.src->skip_input_data = jpegSkip;
|
||||
jpegDecompStruct.src->resync_to_restart = jpeg_resync_to_restart;
|
||||
jpegDecompStruct.src->term_source = dummyCallback1;
|
||||
|
||||
jpegDecompStruct.src->next_input_byte = (const unsigned char*) mb.getData();
|
||||
jpegDecompStruct.src->bytes_in_buffer = mb.getSize();
|
||||
|
||||
try
|
||||
{
|
||||
jpeg_read_header (&jpegDecompStruct, TRUE);
|
||||
|
||||
jpeg_calc_output_dimensions (&jpegDecompStruct);
|
||||
|
||||
const int width = jpegDecompStruct.output_width;
|
||||
const int height = jpegDecompStruct.output_height;
|
||||
|
||||
jpegDecompStruct.out_color_space = JCS_RGB;
|
||||
|
||||
JSAMPARRAY buffer
|
||||
= (*jpegDecompStruct.mem->alloc_sarray) ((j_common_ptr) &jpegDecompStruct,
|
||||
JPOOL_IMAGE,
|
||||
width * 3, 1);
|
||||
|
||||
if (jpeg_start_decompress (&jpegDecompStruct))
|
||||
{
|
||||
image = new Image (Image::RGB, width, height, false);
|
||||
|
||||
for (int y = 0; y < height; ++y)
|
||||
{
|
||||
jpeg_read_scanlines (&jpegDecompStruct, buffer, 1);
|
||||
|
||||
int stride, pixelStride;
|
||||
uint8* pixels = image->lockPixelDataReadWrite (0, y, width, 1, stride, pixelStride);
|
||||
const uint8* src = *buffer;
|
||||
uint8* dest = pixels;
|
||||
|
||||
for (int i = width; --i >= 0;)
|
||||
{
|
||||
((PixelRGB*) dest)->setARGB (0, src[0], src[1], src[2]);
|
||||
dest += pixelStride;
|
||||
src += 3;
|
||||
}
|
||||
|
||||
image->releasePixelDataReadWrite (pixels);
|
||||
}
|
||||
|
||||
jpeg_finish_decompress (&jpegDecompStruct);
|
||||
}
|
||||
|
||||
jpeg_destroy_decompress (&jpegDecompStruct);
|
||||
}
|
||||
catch (...)
|
||||
{}
|
||||
|
||||
in.setPosition (((char*) jpegDecompStruct.src->next_input_byte) - (char*) mb.getData());
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
static const int bufferSize = 512;
|
||||
|
||||
struct JuceJpegDest : public jpeg_destination_mgr
|
||||
{
|
||||
OutputStream* output;
|
||||
char* buffer;
|
||||
};
|
||||
|
||||
static void jpegWriteInit (j_compress_ptr) throw()
|
||||
{
|
||||
}
|
||||
|
||||
static void jpegWriteTerminate (j_compress_ptr cinfo) throw()
|
||||
{
|
||||
JuceJpegDest* const dest = (JuceJpegDest*) cinfo->dest;
|
||||
|
||||
const int numToWrite = bufferSize - dest->free_in_buffer;
|
||||
dest->output->write (dest->buffer, numToWrite);
|
||||
}
|
||||
|
||||
static boolean jpegWriteFlush (j_compress_ptr cinfo) throw()
|
||||
{
|
||||
JuceJpegDest* const dest = (JuceJpegDest*) cinfo->dest;
|
||||
|
||||
const int numToWrite = bufferSize;
|
||||
|
||||
dest->next_output_byte = (JOCTET*) dest->buffer;
|
||||
dest->free_in_buffer = bufferSize;
|
||||
|
||||
return dest->output->write (dest->buffer, numToWrite);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool juce_writeJPEGImageToStream (const Image& image,
|
||||
OutputStream& out,
|
||||
float quality) throw()
|
||||
{
|
||||
if (image.hasAlphaChannel())
|
||||
{
|
||||
// this method could fill the background in white and still save the image..
|
||||
jassertfalse
|
||||
return true;
|
||||
}
|
||||
|
||||
struct jpeg_compress_struct jpegCompStruct;
|
||||
|
||||
struct jpeg_error_mgr jerr;
|
||||
setupSilentErrorHandler (jerr);
|
||||
jpegCompStruct.err = &jerr;
|
||||
|
||||
jpeg_create_compress (&jpegCompStruct);
|
||||
|
||||
JuceJpegDest dest;
|
||||
jpegCompStruct.dest = &dest;
|
||||
|
||||
dest.output = &out;
|
||||
dest.buffer = (char*) juce_malloc (bufferSize);
|
||||
dest.next_output_byte = (JOCTET*) dest.buffer;
|
||||
dest.free_in_buffer = bufferSize;
|
||||
dest.init_destination = jpegWriteInit;
|
||||
dest.empty_output_buffer = jpegWriteFlush;
|
||||
dest.term_destination = jpegWriteTerminate;
|
||||
|
||||
jpegCompStruct.image_width = image.getWidth();
|
||||
jpegCompStruct.image_height = image.getHeight();
|
||||
jpegCompStruct.input_components = 3;
|
||||
jpegCompStruct.in_color_space = JCS_RGB;
|
||||
jpegCompStruct.write_JFIF_header = 1;
|
||||
|
||||
jpegCompStruct.X_density = 72;
|
||||
jpegCompStruct.Y_density = 72;
|
||||
|
||||
jpeg_set_defaults (&jpegCompStruct);
|
||||
|
||||
jpegCompStruct.dct_method = JDCT_FLOAT;
|
||||
jpegCompStruct.optimize_coding = 1;
|
||||
// jpegCompStruct.smoothing_factor = 10;
|
||||
|
||||
if (quality < 0.0f)
|
||||
quality = 0.85f;
|
||||
|
||||
jpeg_set_quality (&jpegCompStruct, jlimit (0, 100, roundFloatToInt (quality * 100.0f)), TRUE);
|
||||
|
||||
jpeg_start_compress (&jpegCompStruct, TRUE);
|
||||
|
||||
const int strideBytes = jpegCompStruct.image_width * jpegCompStruct.input_components;
|
||||
|
||||
JSAMPARRAY buffer = (*jpegCompStruct.mem->alloc_sarray) ((j_common_ptr) &jpegCompStruct,
|
||||
JPOOL_IMAGE,
|
||||
strideBytes, 1);
|
||||
|
||||
while (jpegCompStruct.next_scanline < jpegCompStruct.image_height)
|
||||
{
|
||||
int stride, pixelStride;
|
||||
const uint8* pixels = image.lockPixelDataReadOnly (0, jpegCompStruct.next_scanline, jpegCompStruct.image_width, 1, stride, pixelStride);
|
||||
const uint8* src = pixels;
|
||||
uint8* dst = *buffer;
|
||||
|
||||
for (int i = jpegCompStruct.image_width; --i >= 0;)
|
||||
{
|
||||
*dst++ = ((const PixelRGB*) src)->getRed();
|
||||
*dst++ = ((const PixelRGB*) src)->getGreen();
|
||||
*dst++ = ((const PixelRGB*) src)->getBlue();
|
||||
src += pixelStride;
|
||||
}
|
||||
|
||||
jpeg_write_scanlines (&jpegCompStruct, buffer, 1);
|
||||
image.releasePixelDataReadOnly (pixels);
|
||||
}
|
||||
|
||||
jpeg_finish_compress (&jpegCompStruct);
|
||||
jpeg_destroy_compress (&jpegCompStruct);
|
||||
|
||||
juce_free (dest.buffer);
|
||||
|
||||
out.flush();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
END_JUCE_NAMESPACE
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library - "Jules' Utility Class Extensions"
|
||||
Copyright 2004-7 by Raw Material Software ltd.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
JUCE can be redistributed and/or modified under the terms of the
|
||||
GNU General Public License, as published by the Free Software Foundation;
|
||||
either version 2 of the License, or (at your option) any later version.
|
||||
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with JUCE; if not, visit www.gnu.org/licenses or write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
If you'd like to release a closed-source product which uses JUCE, commercial
|
||||
licenses are also available: visit www.rawmaterialsoftware.com/juce for
|
||||
more information.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "../../../../../juce_core/basics/juce_StandardHeader.h"
|
||||
|
||||
#if JUCE_MSVC
|
||||
#pragma warning (push)
|
||||
#endif
|
||||
|
||||
namespace jpeglibNamespace
|
||||
{
|
||||
extern "C"
|
||||
{
|
||||
#define JPEG_INTERNALS
|
||||
#undef FAR
|
||||
#include "jpglib/jpeglib.h"
|
||||
|
||||
#include "jpglib/jcapimin.c"
|
||||
#include "jpglib/jcapistd.c"
|
||||
#include "jpglib/jccoefct.c"
|
||||
#include "jpglib/jccolor.c"
|
||||
#undef FIX
|
||||
#include "jpglib/jcdctmgr.c"
|
||||
#undef CONST_BITS
|
||||
#include "jpglib/jchuff.c"
|
||||
#undef emit_byte
|
||||
#include "jpglib/jcinit.c"
|
||||
#include "jpglib/jcmainct.c"
|
||||
#include "jpglib/jcmarker.c"
|
||||
#include "jpglib/jcmaster.c"
|
||||
#include "jpglib/jcomapi.c"
|
||||
#include "jpglib/jcparam.c"
|
||||
#include "jpglib/jcphuff.c"
|
||||
#include "jpglib/jcprepct.c"
|
||||
#include "jpglib/jcsample.c"
|
||||
#include "jpglib/jctrans.c"
|
||||
#include "jpglib/jdapistd.c"
|
||||
#include "jpglib/jdapimin.c"
|
||||
#include "jpglib/jdatasrc.c"
|
||||
#include "jpglib/jdcoefct.c"
|
||||
#undef FIX
|
||||
#include "jpglib/jdcolor.c"
|
||||
#undef FIX
|
||||
#include "jpglib/jddctmgr.c"
|
||||
#undef CONST_BITS
|
||||
#undef ASSIGN_STATE
|
||||
#include "jpglib/jdhuff.c"
|
||||
#include "jpglib/jdinput.c"
|
||||
#include "jpglib/jdmainct.c"
|
||||
#include "jpglib/jdmarker.c"
|
||||
#include "jpglib/jdmaster.c"
|
||||
#undef FIX
|
||||
#include "jpglib/jdmerge.c"
|
||||
#undef ASSIGN_STATE
|
||||
#include "jpglib/jdphuff.c"
|
||||
#include "jpglib/jdpostct.c"
|
||||
#undef FIX
|
||||
#include "jpglib/jdsample.c"
|
||||
#include "jpglib/jdtrans.c"
|
||||
#include "jpglib/jfdctflt.c"
|
||||
#include "jpglib/jfdctint.c"
|
||||
#undef CONST_BITS
|
||||
#undef MULTIPLY
|
||||
#undef FIX_0_541196100
|
||||
#include "jpglib/jfdctfst.c"
|
||||
#undef FIX_0_541196100
|
||||
#include "jpglib/jidctflt.c"
|
||||
#undef CONST_BITS
|
||||
#undef FIX_1_847759065
|
||||
#undef MULTIPLY
|
||||
#undef DEQUANTIZE
|
||||
#undef DESCALE
|
||||
#include "jpglib/jidctfst.c"
|
||||
#undef CONST_BITS
|
||||
#undef FIX_1_847759065
|
||||
#undef MULTIPLY
|
||||
#undef DEQUANTIZE
|
||||
#include "jpglib/jidctint.c"
|
||||
#include "jpglib/jidctred.c"
|
||||
#include "jpglib/jmemmgr.c"
|
||||
#include "jpglib/jmemnobs.c"
|
||||
#include "jpglib/jquant1.c"
|
||||
#include "jpglib/jquant2.c"
|
||||
#include "jpglib/jutils.c"
|
||||
#include "jpglib/transupp.c"
|
||||
}
|
||||
}
|
||||
|
||||
#if JUCE_MSVC
|
||||
#pragma warning (pop)
|
||||
#endif
|
||||
|
||||
BEGIN_JUCE_NAMESPACE
|
||||
|
||||
#include "../juce_Image.h"
|
||||
#include "../../../../../juce_core/io/juce_InputStream.h"
|
||||
#include "../../../../../juce_core/io/juce_OutputStream.h"
|
||||
#include "../../colour/juce_PixelFormats.h"
|
||||
|
||||
using namespace jpeglibNamespace;
|
||||
|
||||
//==============================================================================
|
||||
struct JPEGDecodingFailure {};
|
||||
|
||||
static void fatalErrorHandler (j_common_ptr)
|
||||
{
|
||||
throw JPEGDecodingFailure();
|
||||
}
|
||||
|
||||
static void silentErrorCallback1 (j_common_ptr) {}
|
||||
static void silentErrorCallback2 (j_common_ptr, int) {}
|
||||
static void silentErrorCallback3 (j_common_ptr, char*) {}
|
||||
|
||||
static void setupSilentErrorHandler (struct jpeg_error_mgr& err)
|
||||
{
|
||||
zerostruct (err);
|
||||
|
||||
err.error_exit = fatalErrorHandler;
|
||||
err.emit_message = silentErrorCallback2;
|
||||
err.output_message = silentErrorCallback1;
|
||||
err.format_message = silentErrorCallback3;
|
||||
err.reset_error_mgr = silentErrorCallback1;
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
static void dummyCallback1 (j_decompress_ptr) throw()
|
||||
{
|
||||
}
|
||||
|
||||
static void jpegSkip (j_decompress_ptr decompStruct, long num) throw()
|
||||
{
|
||||
decompStruct->src->next_input_byte += num;
|
||||
|
||||
num = jmin (num, (int) decompStruct->src->bytes_in_buffer);
|
||||
decompStruct->src->bytes_in_buffer -= num;
|
||||
}
|
||||
|
||||
static boolean jpegFill (j_decompress_ptr) throw()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
Image* juce_loadJPEGImageFromStream (InputStream& in) throw()
|
||||
{
|
||||
MemoryBlock mb;
|
||||
in.readIntoMemoryBlock (mb);
|
||||
|
||||
Image* image = 0;
|
||||
|
||||
if (mb.getSize() > 16)
|
||||
{
|
||||
struct jpeg_decompress_struct jpegDecompStruct;
|
||||
|
||||
struct jpeg_error_mgr jerr;
|
||||
setupSilentErrorHandler (jerr);
|
||||
jpegDecompStruct.err = &jerr;
|
||||
|
||||
jpeg_create_decompress (&jpegDecompStruct);
|
||||
|
||||
jpegDecompStruct.src = (jpeg_source_mgr*)(jpegDecompStruct.mem->alloc_small)
|
||||
((j_common_ptr)(&jpegDecompStruct), JPOOL_PERMANENT, sizeof (jpeg_source_mgr));
|
||||
|
||||
jpegDecompStruct.src->init_source = dummyCallback1;
|
||||
jpegDecompStruct.src->fill_input_buffer = jpegFill;
|
||||
jpegDecompStruct.src->skip_input_data = jpegSkip;
|
||||
jpegDecompStruct.src->resync_to_restart = jpeg_resync_to_restart;
|
||||
jpegDecompStruct.src->term_source = dummyCallback1;
|
||||
|
||||
jpegDecompStruct.src->next_input_byte = (const unsigned char*) mb.getData();
|
||||
jpegDecompStruct.src->bytes_in_buffer = mb.getSize();
|
||||
|
||||
try
|
||||
{
|
||||
jpeg_read_header (&jpegDecompStruct, TRUE);
|
||||
|
||||
jpeg_calc_output_dimensions (&jpegDecompStruct);
|
||||
|
||||
const int width = jpegDecompStruct.output_width;
|
||||
const int height = jpegDecompStruct.output_height;
|
||||
|
||||
jpegDecompStruct.out_color_space = JCS_RGB;
|
||||
|
||||
JSAMPARRAY buffer
|
||||
= (*jpegDecompStruct.mem->alloc_sarray) ((j_common_ptr) &jpegDecompStruct,
|
||||
JPOOL_IMAGE,
|
||||
width * 3, 1);
|
||||
|
||||
if (jpeg_start_decompress (&jpegDecompStruct))
|
||||
{
|
||||
image = new Image (Image::RGB, width, height, false);
|
||||
|
||||
for (int y = 0; y < height; ++y)
|
||||
{
|
||||
jpeg_read_scanlines (&jpegDecompStruct, buffer, 1);
|
||||
|
||||
int stride, pixelStride;
|
||||
uint8* pixels = image->lockPixelDataReadWrite (0, y, width, 1, stride, pixelStride);
|
||||
const uint8* src = *buffer;
|
||||
uint8* dest = pixels;
|
||||
|
||||
for (int i = width; --i >= 0;)
|
||||
{
|
||||
((PixelRGB*) dest)->setARGB (0, src[0], src[1], src[2]);
|
||||
dest += pixelStride;
|
||||
src += 3;
|
||||
}
|
||||
|
||||
image->releasePixelDataReadWrite (pixels);
|
||||
}
|
||||
|
||||
jpeg_finish_decompress (&jpegDecompStruct);
|
||||
}
|
||||
|
||||
jpeg_destroy_decompress (&jpegDecompStruct);
|
||||
}
|
||||
catch (...)
|
||||
{}
|
||||
|
||||
in.setPosition (((char*) jpegDecompStruct.src->next_input_byte) - (char*) mb.getData());
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
static const int bufferSize = 512;
|
||||
|
||||
struct JuceJpegDest : public jpeg_destination_mgr
|
||||
{
|
||||
OutputStream* output;
|
||||
char* buffer;
|
||||
};
|
||||
|
||||
static void jpegWriteInit (j_compress_ptr) throw()
|
||||
{
|
||||
}
|
||||
|
||||
static void jpegWriteTerminate (j_compress_ptr cinfo) throw()
|
||||
{
|
||||
JuceJpegDest* const dest = (JuceJpegDest*) cinfo->dest;
|
||||
|
||||
const int numToWrite = bufferSize - dest->free_in_buffer;
|
||||
dest->output->write (dest->buffer, numToWrite);
|
||||
}
|
||||
|
||||
static boolean jpegWriteFlush (j_compress_ptr cinfo) throw()
|
||||
{
|
||||
JuceJpegDest* const dest = (JuceJpegDest*) cinfo->dest;
|
||||
|
||||
const int numToWrite = bufferSize;
|
||||
|
||||
dest->next_output_byte = (JOCTET*) dest->buffer;
|
||||
dest->free_in_buffer = bufferSize;
|
||||
|
||||
return dest->output->write (dest->buffer, numToWrite);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool juce_writeJPEGImageToStream (const Image& image,
|
||||
OutputStream& out,
|
||||
float quality) throw()
|
||||
{
|
||||
if (image.hasAlphaChannel())
|
||||
{
|
||||
// this method could fill the background in white and still save the image..
|
||||
jassertfalse
|
||||
return true;
|
||||
}
|
||||
|
||||
struct jpeg_compress_struct jpegCompStruct;
|
||||
|
||||
struct jpeg_error_mgr jerr;
|
||||
setupSilentErrorHandler (jerr);
|
||||
jpegCompStruct.err = &jerr;
|
||||
|
||||
jpeg_create_compress (&jpegCompStruct);
|
||||
|
||||
JuceJpegDest dest;
|
||||
jpegCompStruct.dest = &dest;
|
||||
|
||||
dest.output = &out;
|
||||
dest.buffer = (char*) juce_malloc (bufferSize);
|
||||
dest.next_output_byte = (JOCTET*) dest.buffer;
|
||||
dest.free_in_buffer = bufferSize;
|
||||
dest.init_destination = jpegWriteInit;
|
||||
dest.empty_output_buffer = jpegWriteFlush;
|
||||
dest.term_destination = jpegWriteTerminate;
|
||||
|
||||
jpegCompStruct.image_width = image.getWidth();
|
||||
jpegCompStruct.image_height = image.getHeight();
|
||||
jpegCompStruct.input_components = 3;
|
||||
jpegCompStruct.in_color_space = JCS_RGB;
|
||||
jpegCompStruct.write_JFIF_header = 1;
|
||||
|
||||
jpegCompStruct.X_density = 72;
|
||||
jpegCompStruct.Y_density = 72;
|
||||
|
||||
jpeg_set_defaults (&jpegCompStruct);
|
||||
|
||||
jpegCompStruct.dct_method = JDCT_FLOAT;
|
||||
jpegCompStruct.optimize_coding = 1;
|
||||
// jpegCompStruct.smoothing_factor = 10;
|
||||
|
||||
if (quality < 0.0f)
|
||||
quality = 0.85f;
|
||||
|
||||
jpeg_set_quality (&jpegCompStruct, jlimit (0, 100, roundFloatToInt (quality * 100.0f)), TRUE);
|
||||
|
||||
jpeg_start_compress (&jpegCompStruct, TRUE);
|
||||
|
||||
const int strideBytes = jpegCompStruct.image_width * jpegCompStruct.input_components;
|
||||
|
||||
JSAMPARRAY buffer = (*jpegCompStruct.mem->alloc_sarray) ((j_common_ptr) &jpegCompStruct,
|
||||
JPOOL_IMAGE,
|
||||
strideBytes, 1);
|
||||
|
||||
while (jpegCompStruct.next_scanline < jpegCompStruct.image_height)
|
||||
{
|
||||
int stride, pixelStride;
|
||||
const uint8* pixels = image.lockPixelDataReadOnly (0, jpegCompStruct.next_scanline, jpegCompStruct.image_width, 1, stride, pixelStride);
|
||||
const uint8* src = pixels;
|
||||
uint8* dst = *buffer;
|
||||
|
||||
for (int i = jpegCompStruct.image_width; --i >= 0;)
|
||||
{
|
||||
*dst++ = ((const PixelRGB*) src)->getRed();
|
||||
*dst++ = ((const PixelRGB*) src)->getGreen();
|
||||
*dst++ = ((const PixelRGB*) src)->getBlue();
|
||||
src += pixelStride;
|
||||
}
|
||||
|
||||
jpeg_write_scanlines (&jpegCompStruct, buffer, 1);
|
||||
image.releasePixelDataReadOnly (pixels);
|
||||
}
|
||||
|
||||
jpeg_finish_compress (&jpegCompStruct);
|
||||
jpeg_destroy_compress (&jpegCompStruct);
|
||||
|
||||
juce_free (dest.buffer);
|
||||
|
||||
out.flush();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
END_JUCE_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ protected:
|
|||
elements = 0;
|
||||
}
|
||||
|
||||
numAllocated = numElements;
|
||||
numAllocated = numElements;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue