migrating to the latest JUCE version
This commit is contained in:
@ -1,224 +1,224 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
//==============================================================================
|
||||
struct ColourPropertyComponent : public PropertyComponent
|
||||
{
|
||||
ColourPropertyComponent (UndoManager* undoManager, const String& name, const Value& colour,
|
||||
Colour defaultColour, bool canResetToDefault)
|
||||
: PropertyComponent (name),
|
||||
colourEditor (undoManager, colour, defaultColour, canResetToDefault)
|
||||
{
|
||||
addAndMakeVisible (colourEditor);
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
colourEditor.setBounds (getLookAndFeel().getPropertyComponentContentPosition (*this));
|
||||
}
|
||||
|
||||
void refresh() override {}
|
||||
|
||||
private:
|
||||
/**
|
||||
A component that shows a colour swatch with hex ARGB value, and which pops up
|
||||
a colour selector when you click it.
|
||||
*/
|
||||
struct ColourEditorComponent : public Component,
|
||||
private Value::Listener
|
||||
{
|
||||
ColourEditorComponent (UndoManager* um, const Value& colour,
|
||||
Colour defaultCol, const bool canReset)
|
||||
: undoManager (um), colourValue (colour), defaultColour (defaultCol),
|
||||
canResetToDefault (canReset)
|
||||
{
|
||||
colourValue.addListener (this);
|
||||
}
|
||||
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
const Colour colour (getColour());
|
||||
|
||||
g.fillAll (Colours::grey);
|
||||
g.fillCheckerBoard (getLocalBounds().reduced (2).toFloat(),
|
||||
10.0f, 10.0f,
|
||||
Colour (0xffdddddd).overlaidWith (colour),
|
||||
Colour (0xffffffff).overlaidWith (colour));
|
||||
|
||||
g.setColour (Colours::white.overlaidWith (colour).contrasting());
|
||||
g.setFont (Font ((float) getHeight() * 0.6f, Font::bold));
|
||||
g.drawFittedText (colour.toDisplayString (true), getLocalBounds().reduced (2, 1),
|
||||
Justification::centred, 1);
|
||||
}
|
||||
|
||||
Colour getColour() const
|
||||
{
|
||||
if (colourValue.toString().isEmpty())
|
||||
return defaultColour;
|
||||
|
||||
return Colour::fromString (colourValue.toString());
|
||||
}
|
||||
|
||||
void setColour (Colour newColour)
|
||||
{
|
||||
if (getColour() != newColour)
|
||||
{
|
||||
if (newColour == defaultColour && canResetToDefault)
|
||||
colourValue = var();
|
||||
else
|
||||
colourValue = newColour.toDisplayString (true);
|
||||
}
|
||||
}
|
||||
|
||||
void resetToDefault()
|
||||
{
|
||||
setColour (defaultColour);
|
||||
}
|
||||
|
||||
void refresh()
|
||||
{
|
||||
const Colour col (getColour());
|
||||
|
||||
if (col != lastColour)
|
||||
{
|
||||
lastColour = col;
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
|
||||
void mouseDown (const MouseEvent&) override
|
||||
{
|
||||
if (undoManager != nullptr)
|
||||
undoManager->beginNewTransaction();
|
||||
|
||||
CallOutBox::launchAsynchronously (std::make_unique<PopupColourSelector> (colourValue,
|
||||
defaultColour,
|
||||
canResetToDefault),
|
||||
getScreenBounds(),
|
||||
nullptr);
|
||||
}
|
||||
|
||||
private:
|
||||
void valueChanged (Value&) override
|
||||
{
|
||||
refresh();
|
||||
}
|
||||
|
||||
UndoManager* undoManager;
|
||||
Value colourValue;
|
||||
Colour lastColour;
|
||||
const Colour defaultColour;
|
||||
const bool canResetToDefault;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ColourEditorComponent)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
struct PopupColourSelector : public Component,
|
||||
private ChangeListener,
|
||||
private Value::Listener
|
||||
{
|
||||
PopupColourSelector (const Value& colour,
|
||||
Colour defaultCol,
|
||||
const bool canResetToDefault)
|
||||
: defaultButton ("Reset to Default"),
|
||||
colourValue (colour),
|
||||
defaultColour (defaultCol)
|
||||
{
|
||||
addAndMakeVisible (selector);
|
||||
selector.setName ("Colour");
|
||||
selector.setCurrentColour (getColour());
|
||||
selector.addChangeListener (this);
|
||||
|
||||
if (canResetToDefault)
|
||||
{
|
||||
addAndMakeVisible (defaultButton);
|
||||
defaultButton.onClick = [this]
|
||||
{
|
||||
setColour (defaultColour);
|
||||
selector.setCurrentColour (defaultColour);
|
||||
};
|
||||
}
|
||||
|
||||
colourValue.addListener (this);
|
||||
setSize (300, 400);
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
if (defaultButton.isVisible())
|
||||
{
|
||||
selector.setBounds (0, 0, getWidth(), getHeight() - 30);
|
||||
defaultButton.changeWidthToFitText (22);
|
||||
defaultButton.setTopLeftPosition (10, getHeight() - 26);
|
||||
}
|
||||
else
|
||||
{
|
||||
selector.setBounds (getLocalBounds());
|
||||
}
|
||||
}
|
||||
|
||||
Colour getColour() const
|
||||
{
|
||||
if (colourValue.toString().isEmpty())
|
||||
return defaultColour;
|
||||
|
||||
return Colour::fromString (colourValue.toString());
|
||||
}
|
||||
|
||||
void setColour (Colour newColour)
|
||||
{
|
||||
if (getColour() != newColour)
|
||||
{
|
||||
if (newColour == defaultColour && defaultButton.isVisible())
|
||||
colourValue = var();
|
||||
else
|
||||
colourValue = newColour.toDisplayString (true);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void changeListenerCallback (ChangeBroadcaster*) override
|
||||
{
|
||||
if (selector.getCurrentColour() != getColour())
|
||||
setColour (selector.getCurrentColour());
|
||||
}
|
||||
|
||||
void valueChanged (Value&) override
|
||||
{
|
||||
selector.setCurrentColour (getColour());
|
||||
}
|
||||
|
||||
StoredSettings::ColourSelectorWithSwatches selector;
|
||||
TextButton defaultButton;
|
||||
Value colourValue;
|
||||
Colour defaultColour;
|
||||
};
|
||||
|
||||
ColourEditorComponent colourEditor;
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
//==============================================================================
|
||||
struct ColourPropertyComponent : public PropertyComponent
|
||||
{
|
||||
ColourPropertyComponent (UndoManager* undoManager, const String& name, const Value& colour,
|
||||
Colour defaultColour, bool canResetToDefault)
|
||||
: PropertyComponent (name),
|
||||
colourEditor (undoManager, colour, defaultColour, canResetToDefault)
|
||||
{
|
||||
addAndMakeVisible (colourEditor);
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
colourEditor.setBounds (getLookAndFeel().getPropertyComponentContentPosition (*this));
|
||||
}
|
||||
|
||||
void refresh() override {}
|
||||
|
||||
private:
|
||||
/**
|
||||
A component that shows a colour swatch with hex ARGB value, and which pops up
|
||||
a colour selector when you click it.
|
||||
*/
|
||||
struct ColourEditorComponent : public Component,
|
||||
private Value::Listener
|
||||
{
|
||||
ColourEditorComponent (UndoManager* um, const Value& colour,
|
||||
Colour defaultCol, const bool canReset)
|
||||
: undoManager (um), colourValue (colour), defaultColour (defaultCol),
|
||||
canResetToDefault (canReset)
|
||||
{
|
||||
colourValue.addListener (this);
|
||||
}
|
||||
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
const Colour colour (getColour());
|
||||
|
||||
g.fillAll (Colours::grey);
|
||||
g.fillCheckerBoard (getLocalBounds().reduced (2).toFloat(),
|
||||
10.0f, 10.0f,
|
||||
Colour (0xffdddddd).overlaidWith (colour),
|
||||
Colour (0xffffffff).overlaidWith (colour));
|
||||
|
||||
g.setColour (Colours::white.overlaidWith (colour).contrasting());
|
||||
g.setFont (Font ((float) getHeight() * 0.6f, Font::bold));
|
||||
g.drawFittedText (colour.toDisplayString (true), getLocalBounds().reduced (2, 1),
|
||||
Justification::centred, 1);
|
||||
}
|
||||
|
||||
Colour getColour() const
|
||||
{
|
||||
if (colourValue.toString().isEmpty())
|
||||
return defaultColour;
|
||||
|
||||
return Colour::fromString (colourValue.toString());
|
||||
}
|
||||
|
||||
void setColour (Colour newColour)
|
||||
{
|
||||
if (getColour() != newColour)
|
||||
{
|
||||
if (newColour == defaultColour && canResetToDefault)
|
||||
colourValue = var();
|
||||
else
|
||||
colourValue = newColour.toDisplayString (true);
|
||||
}
|
||||
}
|
||||
|
||||
void resetToDefault()
|
||||
{
|
||||
setColour (defaultColour);
|
||||
}
|
||||
|
||||
void refresh()
|
||||
{
|
||||
const Colour col (getColour());
|
||||
|
||||
if (col != lastColour)
|
||||
{
|
||||
lastColour = col;
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
|
||||
void mouseDown (const MouseEvent&) override
|
||||
{
|
||||
if (undoManager != nullptr)
|
||||
undoManager->beginNewTransaction();
|
||||
|
||||
CallOutBox::launchAsynchronously (std::make_unique<PopupColourSelector> (colourValue,
|
||||
defaultColour,
|
||||
canResetToDefault),
|
||||
getScreenBounds(),
|
||||
nullptr);
|
||||
}
|
||||
|
||||
private:
|
||||
void valueChanged (Value&) override
|
||||
{
|
||||
refresh();
|
||||
}
|
||||
|
||||
UndoManager* undoManager;
|
||||
Value colourValue;
|
||||
Colour lastColour;
|
||||
const Colour defaultColour;
|
||||
const bool canResetToDefault;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ColourEditorComponent)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
struct PopupColourSelector : public Component,
|
||||
private ChangeListener,
|
||||
private Value::Listener
|
||||
{
|
||||
PopupColourSelector (const Value& colour,
|
||||
Colour defaultCol,
|
||||
const bool canResetToDefault)
|
||||
: defaultButton ("Reset to Default"),
|
||||
colourValue (colour),
|
||||
defaultColour (defaultCol)
|
||||
{
|
||||
addAndMakeVisible (selector);
|
||||
selector.setName ("Colour");
|
||||
selector.setCurrentColour (getColour());
|
||||
selector.addChangeListener (this);
|
||||
|
||||
if (canResetToDefault)
|
||||
{
|
||||
addAndMakeVisible (defaultButton);
|
||||
defaultButton.onClick = [this]
|
||||
{
|
||||
setColour (defaultColour);
|
||||
selector.setCurrentColour (defaultColour);
|
||||
};
|
||||
}
|
||||
|
||||
colourValue.addListener (this);
|
||||
setSize (300, 400);
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
if (defaultButton.isVisible())
|
||||
{
|
||||
selector.setBounds (0, 0, getWidth(), getHeight() - 30);
|
||||
defaultButton.changeWidthToFitText (22);
|
||||
defaultButton.setTopLeftPosition (10, getHeight() - 26);
|
||||
}
|
||||
else
|
||||
{
|
||||
selector.setBounds (getLocalBounds());
|
||||
}
|
||||
}
|
||||
|
||||
Colour getColour() const
|
||||
{
|
||||
if (colourValue.toString().isEmpty())
|
||||
return defaultColour;
|
||||
|
||||
return Colour::fromString (colourValue.toString());
|
||||
}
|
||||
|
||||
void setColour (Colour newColour)
|
||||
{
|
||||
if (getColour() != newColour)
|
||||
{
|
||||
if (newColour == defaultColour && defaultButton.isVisible())
|
||||
colourValue = var();
|
||||
else
|
||||
colourValue = newColour.toDisplayString (true);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void changeListenerCallback (ChangeBroadcaster*) override
|
||||
{
|
||||
if (selector.getCurrentColour() != getColour())
|
||||
setColour (selector.getCurrentColour());
|
||||
}
|
||||
|
||||
void valueChanged (Value&) override
|
||||
{
|
||||
selector.setCurrentColour (getColour());
|
||||
}
|
||||
|
||||
StoredSettings::ColourSelectorWithSwatches selector;
|
||||
TextButton defaultButton;
|
||||
Value colourValue;
|
||||
Colour defaultColour;
|
||||
};
|
||||
|
||||
ColourEditorComponent colourEditor;
|
||||
};
|
||||
|
@ -1,245 +1,249 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/** A PropertyComponent for selecting files or folders.
|
||||
|
||||
The user may drag files over the property box, enter the path manually and/or click
|
||||
the '...' button to open a file selection dialog box.
|
||||
*/
|
||||
class FilePathPropertyComponent : public PropertyComponent,
|
||||
public FileDragAndDropTarget,
|
||||
protected Value::Listener
|
||||
{
|
||||
public:
|
||||
FilePathPropertyComponent (Value valueToControl, const String& propertyName, bool isDir, bool thisOS = true,
|
||||
const String& wildcardsToUse = "*", const File& relativeRoot = File())
|
||||
: PropertyComponent (propertyName),
|
||||
text (valueToControl, propertyName, 1024, false),
|
||||
isDirectory (isDir), isThisOS (thisOS), wildcards (wildcardsToUse), root (relativeRoot)
|
||||
{
|
||||
textValue.referTo (valueToControl);
|
||||
init();
|
||||
}
|
||||
|
||||
/** Displays a default value when no value is specified by the user. */
|
||||
FilePathPropertyComponent (ValueWithDefault& valueToControl, const String& propertyName, bool isDir, bool thisOS = true,
|
||||
const String& wildcardsToUse = "*", const File& relativeRoot = File())
|
||||
: PropertyComponent (propertyName),
|
||||
text (valueToControl, propertyName, 1024, false),
|
||||
isDirectory (isDir), isThisOS (thisOS), wildcards (wildcardsToUse), root (relativeRoot)
|
||||
{
|
||||
textValue = valueToControl.getPropertyAsValue();
|
||||
init();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void refresh() override {}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
auto bounds = getLocalBounds();
|
||||
|
||||
text.setBounds (bounds.removeFromLeft (jmax (400, bounds.getWidth() - 55)));
|
||||
bounds.removeFromLeft (5);
|
||||
browseButton.setBounds (bounds);
|
||||
}
|
||||
|
||||
void paintOverChildren (Graphics& g) override
|
||||
{
|
||||
if (highlightForDragAndDrop)
|
||||
{
|
||||
g.setColour (findColour (defaultHighlightColourId).withAlpha (0.5f));
|
||||
g.fillRect (getLookAndFeel().getPropertyComponentContentPosition (text));
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool isInterestedInFileDrag (const StringArray&) override { return true; }
|
||||
void fileDragEnter (const StringArray&, int, int) override { highlightForDragAndDrop = true; repaint(); }
|
||||
void fileDragExit (const StringArray&) override { highlightForDragAndDrop = false; repaint(); }
|
||||
|
||||
void filesDropped (const StringArray& selectedFiles, int, int) override
|
||||
{
|
||||
setTo (selectedFiles[0]);
|
||||
|
||||
highlightForDragAndDrop = false;
|
||||
repaint();
|
||||
}
|
||||
|
||||
protected:
|
||||
void valueChanged (Value&) override
|
||||
{
|
||||
updateEditorColour();
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
void init()
|
||||
{
|
||||
textValue.addListener (this);
|
||||
|
||||
text.setInterestedInFileDrag (false);
|
||||
addAndMakeVisible (text);
|
||||
|
||||
browseButton.onClick = [this] { browse(); };
|
||||
addAndMakeVisible (browseButton);
|
||||
|
||||
lookAndFeelChanged();
|
||||
}
|
||||
|
||||
void setTo (File f)
|
||||
{
|
||||
if (isDirectory && ! f.isDirectory())
|
||||
f = f.getParentDirectory();
|
||||
|
||||
auto pathName = (root == File()) ? f.getFullPathName()
|
||||
: f.getRelativePathFrom (root);
|
||||
|
||||
text.setText (pathName);
|
||||
updateEditorColour();
|
||||
}
|
||||
|
||||
void browse()
|
||||
{
|
||||
File currentFile = {};
|
||||
|
||||
if (text.getText().isNotEmpty())
|
||||
currentFile = root.getChildFile (text.getText());
|
||||
|
||||
if (isDirectory)
|
||||
{
|
||||
chooser = std::make_unique<FileChooser> ("Select directory", currentFile);
|
||||
auto chooserFlags = FileBrowserComponent::openMode | FileBrowserComponent::canSelectDirectories;
|
||||
|
||||
chooser->launchAsync (chooserFlags, [this] (const FileChooser& fc)
|
||||
{
|
||||
if (fc.getResult() == File{})
|
||||
return;
|
||||
|
||||
setTo (fc.getResult());
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
chooser = std::make_unique<FileChooser> ("Select file", currentFile, wildcards);
|
||||
auto chooserFlags = FileBrowserComponent::openMode | FileBrowserComponent::canSelectFiles;
|
||||
|
||||
chooser->launchAsync (chooserFlags, [this] (const FileChooser& fc)
|
||||
{
|
||||
if (fc.getResult() == File{})
|
||||
return;
|
||||
|
||||
setTo (fc.getResult());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void updateEditorColour()
|
||||
{
|
||||
if (isThisOS)
|
||||
{
|
||||
text.setColour (TextPropertyComponent::textColourId, findColour (widgetTextColourId));
|
||||
|
||||
auto pathToCheck = text.getText();
|
||||
|
||||
if (pathToCheck.isNotEmpty())
|
||||
{
|
||||
pathToCheck.replace ("${user.home}", "~");
|
||||
|
||||
#if JUCE_WINDOWS
|
||||
if (pathToCheck.startsWith ("~"))
|
||||
pathToCheck = pathToCheck.replace ("~", File::getSpecialLocation (File::userHomeDirectory).getFullPathName());
|
||||
#endif
|
||||
|
||||
if (! root.getChildFile (pathToCheck).exists())
|
||||
text.setColour (TextPropertyComponent::textColourId, Colours::red);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void lookAndFeelChanged() override
|
||||
{
|
||||
browseButton.setColour (TextButton::buttonColourId, findColour (secondaryButtonBackgroundColourId));
|
||||
browseButton.setColour (TextButton::textColourOffId, Colours::white);
|
||||
|
||||
updateEditorColour();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
Value textValue;
|
||||
|
||||
TextPropertyComponent text;
|
||||
TextButton browseButton { "..." };
|
||||
|
||||
bool isDirectory, isThisOS, highlightForDragAndDrop = false;
|
||||
String wildcards;
|
||||
File root;
|
||||
|
||||
std::unique_ptr<FileChooser> chooser;
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FilePathPropertyComponent)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class FilePathPropertyComponentWithEnablement : public FilePathPropertyComponent
|
||||
{
|
||||
public:
|
||||
FilePathPropertyComponentWithEnablement (ValueWithDefault& valueToControl,
|
||||
ValueWithDefault valueToListenTo,
|
||||
const String& propertyName,
|
||||
bool isDir,
|
||||
bool thisOS = true,
|
||||
const String& wildcardsToUse = "*",
|
||||
const File& relativeRoot = File())
|
||||
: FilePathPropertyComponent (valueToControl,
|
||||
propertyName,
|
||||
isDir,
|
||||
thisOS,
|
||||
wildcardsToUse,
|
||||
relativeRoot),
|
||||
valueWithDefault (valueToListenTo),
|
||||
value (valueToListenTo.getPropertyAsValue())
|
||||
{
|
||||
value.addListener (this);
|
||||
valueChanged (value);
|
||||
}
|
||||
|
||||
~FilePathPropertyComponentWithEnablement() override { value.removeListener (this); }
|
||||
|
||||
private:
|
||||
void valueChanged (Value& v) override
|
||||
{
|
||||
FilePathPropertyComponent::valueChanged (v);
|
||||
setEnabled (valueWithDefault.get());
|
||||
}
|
||||
|
||||
ValueWithDefault valueWithDefault;
|
||||
Value value;
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/** A PropertyComponent for selecting files or folders.
|
||||
|
||||
The user may drag files over the property box, enter the path manually and/or click
|
||||
the '...' button to open a file selection dialog box.
|
||||
*/
|
||||
class FilePathPropertyComponent : public PropertyComponent,
|
||||
public FileDragAndDropTarget,
|
||||
protected Value::Listener
|
||||
{
|
||||
public:
|
||||
FilePathPropertyComponent (Value valueToControl, const String& propertyName, bool isDir, bool thisOS = true,
|
||||
const String& wildcardsToUse = "*", const File& relativeRoot = File())
|
||||
: PropertyComponent (propertyName),
|
||||
text (valueToControl, propertyName, 1024, false),
|
||||
isDirectory (isDir), isThisOS (thisOS), wildcards (wildcardsToUse), root (relativeRoot)
|
||||
{
|
||||
textValue.referTo (valueToControl);
|
||||
init();
|
||||
}
|
||||
|
||||
/** Displays a default value when no value is specified by the user. */
|
||||
FilePathPropertyComponent (ValueTreePropertyWithDefault valueToControl,
|
||||
const String& propertyName,
|
||||
bool isDir,
|
||||
bool thisOS = true,
|
||||
const String& wildcardsToUse = "*",
|
||||
const File& relativeRoot = File())
|
||||
: PropertyComponent (propertyName),
|
||||
text (valueToControl, propertyName, 1024, false),
|
||||
isDirectory (isDir), isThisOS (thisOS), wildcards (wildcardsToUse), root (relativeRoot)
|
||||
{
|
||||
textValue = valueToControl.getPropertyAsValue();
|
||||
init();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void refresh() override {}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
auto bounds = getLocalBounds();
|
||||
|
||||
text.setBounds (bounds.removeFromLeft (jmax (400, bounds.getWidth() - 55)));
|
||||
bounds.removeFromLeft (5);
|
||||
browseButton.setBounds (bounds);
|
||||
}
|
||||
|
||||
void paintOverChildren (Graphics& g) override
|
||||
{
|
||||
if (highlightForDragAndDrop)
|
||||
{
|
||||
g.setColour (findColour (defaultHighlightColourId).withAlpha (0.5f));
|
||||
g.fillRect (getLookAndFeel().getPropertyComponentContentPosition (text));
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool isInterestedInFileDrag (const StringArray&) override { return true; }
|
||||
void fileDragEnter (const StringArray&, int, int) override { highlightForDragAndDrop = true; repaint(); }
|
||||
void fileDragExit (const StringArray&) override { highlightForDragAndDrop = false; repaint(); }
|
||||
|
||||
void filesDropped (const StringArray& selectedFiles, int, int) override
|
||||
{
|
||||
setTo (selectedFiles[0]);
|
||||
|
||||
highlightForDragAndDrop = false;
|
||||
repaint();
|
||||
}
|
||||
|
||||
protected:
|
||||
void valueChanged (Value&) override
|
||||
{
|
||||
updateEditorColour();
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
void init()
|
||||
{
|
||||
textValue.addListener (this);
|
||||
|
||||
text.setInterestedInFileDrag (false);
|
||||
addAndMakeVisible (text);
|
||||
|
||||
browseButton.onClick = [this] { browse(); };
|
||||
addAndMakeVisible (browseButton);
|
||||
|
||||
lookAndFeelChanged();
|
||||
}
|
||||
|
||||
void setTo (File f)
|
||||
{
|
||||
if (isDirectory && ! f.isDirectory())
|
||||
f = f.getParentDirectory();
|
||||
|
||||
auto pathName = (root == File()) ? f.getFullPathName()
|
||||
: f.getRelativePathFrom (root);
|
||||
|
||||
text.setText (pathName);
|
||||
updateEditorColour();
|
||||
}
|
||||
|
||||
void browse()
|
||||
{
|
||||
File currentFile = {};
|
||||
|
||||
if (text.getText().isNotEmpty())
|
||||
currentFile = root.getChildFile (text.getText());
|
||||
|
||||
if (isDirectory)
|
||||
{
|
||||
chooser = std::make_unique<FileChooser> ("Select directory", currentFile);
|
||||
auto chooserFlags = FileBrowserComponent::openMode | FileBrowserComponent::canSelectDirectories;
|
||||
|
||||
chooser->launchAsync (chooserFlags, [this] (const FileChooser& fc)
|
||||
{
|
||||
if (fc.getResult() == File{})
|
||||
return;
|
||||
|
||||
setTo (fc.getResult());
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
chooser = std::make_unique<FileChooser> ("Select file", currentFile, wildcards);
|
||||
auto chooserFlags = FileBrowserComponent::openMode | FileBrowserComponent::canSelectFiles;
|
||||
|
||||
chooser->launchAsync (chooserFlags, [this] (const FileChooser& fc)
|
||||
{
|
||||
if (fc.getResult() == File{})
|
||||
return;
|
||||
|
||||
setTo (fc.getResult());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void updateEditorColour()
|
||||
{
|
||||
if (isThisOS)
|
||||
{
|
||||
text.setColour (TextPropertyComponent::textColourId, findColour (widgetTextColourId));
|
||||
|
||||
auto pathToCheck = text.getText();
|
||||
|
||||
if (pathToCheck.isNotEmpty())
|
||||
{
|
||||
pathToCheck.replace ("${user.home}", "~");
|
||||
|
||||
#if JUCE_WINDOWS
|
||||
if (pathToCheck.startsWith ("~"))
|
||||
pathToCheck = pathToCheck.replace ("~", File::getSpecialLocation (File::userHomeDirectory).getFullPathName());
|
||||
#endif
|
||||
|
||||
if (! root.getChildFile (pathToCheck).exists())
|
||||
text.setColour (TextPropertyComponent::textColourId, Colours::red);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void lookAndFeelChanged() override
|
||||
{
|
||||
browseButton.setColour (TextButton::buttonColourId, findColour (secondaryButtonBackgroundColourId));
|
||||
browseButton.setColour (TextButton::textColourOffId, Colours::white);
|
||||
|
||||
updateEditorColour();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
Value textValue;
|
||||
|
||||
TextPropertyComponent text;
|
||||
TextButton browseButton { "..." };
|
||||
|
||||
bool isDirectory, isThisOS, highlightForDragAndDrop = false;
|
||||
String wildcards;
|
||||
File root;
|
||||
|
||||
std::unique_ptr<FileChooser> chooser;
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FilePathPropertyComponent)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class FilePathPropertyComponentWithEnablement : public FilePathPropertyComponent
|
||||
{
|
||||
public:
|
||||
FilePathPropertyComponentWithEnablement (const ValueTreePropertyWithDefault& valueToControl,
|
||||
ValueTreePropertyWithDefault valueToListenTo,
|
||||
const String& propertyName,
|
||||
bool isDir,
|
||||
bool thisOS = true,
|
||||
const String& wildcardsToUse = "*",
|
||||
const File& relativeRoot = File())
|
||||
: FilePathPropertyComponent (valueToControl,
|
||||
propertyName,
|
||||
isDir,
|
||||
thisOS,
|
||||
wildcardsToUse,
|
||||
relativeRoot),
|
||||
propertyWithDefault (valueToListenTo),
|
||||
value (valueToListenTo.getPropertyAsValue())
|
||||
{
|
||||
value.addListener (this);
|
||||
valueChanged (value);
|
||||
}
|
||||
|
||||
~FilePathPropertyComponentWithEnablement() override { value.removeListener (this); }
|
||||
|
||||
private:
|
||||
void valueChanged (Value& v) override
|
||||
{
|
||||
FilePathPropertyComponent::valueChanged (v);
|
||||
setEnabled (propertyWithDefault.get());
|
||||
}
|
||||
|
||||
ValueTreePropertyWithDefault propertyWithDefault;
|
||||
Value value;
|
||||
};
|
||||
|
@ -1,73 +1,73 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class LabelPropertyComponent : public PropertyComponent
|
||||
{
|
||||
public:
|
||||
LabelPropertyComponent (const String& labelText, int propertyHeight = 25,
|
||||
Font labelFont = Font (16.0f, Font::bold),
|
||||
Justification labelJustification = Justification::centred)
|
||||
: PropertyComponent (labelText),
|
||||
labelToDisplay ({}, labelText)
|
||||
{
|
||||
setPreferredHeight (propertyHeight);
|
||||
|
||||
labelToDisplay.setJustificationType (labelJustification);
|
||||
labelToDisplay.setFont (labelFont);
|
||||
|
||||
addAndMakeVisible (labelToDisplay);
|
||||
setLookAndFeel (&lf);
|
||||
}
|
||||
|
||||
~LabelPropertyComponent() override { setLookAndFeel (nullptr); }
|
||||
|
||||
//==============================================================================
|
||||
void refresh() override {}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
labelToDisplay.setBounds (getLocalBounds());
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
struct LabelLookAndFeel : public ProjucerLookAndFeel
|
||||
{
|
||||
void drawPropertyComponentLabel (Graphics&, int, int, PropertyComponent&) {}
|
||||
};
|
||||
|
||||
void lookAndFeelChanged() override
|
||||
{
|
||||
labelToDisplay.setColour (Label::textColourId, ProjucerApplication::getApp().lookAndFeel.findColour (defaultTextColourId));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
LabelLookAndFeel lf;
|
||||
Label labelToDisplay;
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class LabelPropertyComponent : public PropertyComponent
|
||||
{
|
||||
public:
|
||||
LabelPropertyComponent (const String& labelText, int propertyHeight = 25,
|
||||
Font labelFont = Font (16.0f, Font::bold),
|
||||
Justification labelJustification = Justification::centred)
|
||||
: PropertyComponent (labelText),
|
||||
labelToDisplay ({}, labelText)
|
||||
{
|
||||
setPreferredHeight (propertyHeight);
|
||||
|
||||
labelToDisplay.setJustificationType (labelJustification);
|
||||
labelToDisplay.setFont (labelFont);
|
||||
|
||||
addAndMakeVisible (labelToDisplay);
|
||||
setLookAndFeel (&lf);
|
||||
}
|
||||
|
||||
~LabelPropertyComponent() override { setLookAndFeel (nullptr); }
|
||||
|
||||
//==============================================================================
|
||||
void refresh() override {}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
labelToDisplay.setBounds (getLocalBounds());
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
struct LabelLookAndFeel : public ProjucerLookAndFeel
|
||||
{
|
||||
void drawPropertyComponentLabel (Graphics&, int, int, PropertyComponent&) {}
|
||||
};
|
||||
|
||||
void lookAndFeelChanged() override
|
||||
{
|
||||
labelToDisplay.setColour (Label::textColourId, ProjucerApplication::getApp().lookAndFeel.findColour (defaultTextColourId));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
LabelLookAndFeel lf;
|
||||
Label labelToDisplay;
|
||||
};
|
||||
|
@ -1,160 +1,160 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class TextPropertyComponentWithEnablement : public TextPropertyComponent,
|
||||
private Value::Listener
|
||||
{
|
||||
public:
|
||||
TextPropertyComponentWithEnablement (ValueWithDefault& valueToControl,
|
||||
ValueWithDefault valueToListenTo,
|
||||
const String& propertyName,
|
||||
int maxNumChars,
|
||||
bool multiLine)
|
||||
: TextPropertyComponent (valueToControl, propertyName, maxNumChars, multiLine),
|
||||
valueWithDefault (valueToListenTo),
|
||||
value (valueWithDefault.getPropertyAsValue())
|
||||
{
|
||||
value.addListener (this);
|
||||
setEnabled (valueWithDefault.get());
|
||||
}
|
||||
|
||||
~TextPropertyComponentWithEnablement() override { value.removeListener (this); }
|
||||
|
||||
private:
|
||||
ValueWithDefault valueWithDefault;
|
||||
Value value;
|
||||
|
||||
void valueChanged (Value&) override { setEnabled (valueWithDefault.get()); }
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class ChoicePropertyComponentWithEnablement : public ChoicePropertyComponent,
|
||||
private Value::Listener
|
||||
{
|
||||
public:
|
||||
ChoicePropertyComponentWithEnablement (ValueWithDefault& valueToControl,
|
||||
ValueWithDefault valueToListenTo,
|
||||
const String& propertyName,
|
||||
const StringArray& choiceToUse,
|
||||
const Array<var>& correspondingValues)
|
||||
: ChoicePropertyComponent (valueToControl, propertyName, choiceToUse, correspondingValues),
|
||||
valueWithDefault (valueToListenTo),
|
||||
value (valueToListenTo.getPropertyAsValue())
|
||||
{
|
||||
value.addListener (this);
|
||||
valueChanged (value);
|
||||
}
|
||||
|
||||
ChoicePropertyComponentWithEnablement (ValueWithDefault& valueToControl,
|
||||
ValueWithDefault valueToListenTo,
|
||||
const Identifier& multiChoiceID,
|
||||
const String& propertyName,
|
||||
const StringArray& choicesToUse,
|
||||
const Array<var>& correspondingValues)
|
||||
: ChoicePropertyComponentWithEnablement (valueToControl, valueToListenTo, propertyName, choicesToUse, correspondingValues)
|
||||
{
|
||||
jassert (valueToListenTo.get().getArray() != nullptr);
|
||||
|
||||
isMultiChoice = true;
|
||||
idToCheck = multiChoiceID;
|
||||
|
||||
valueChanged (value);
|
||||
}
|
||||
|
||||
ChoicePropertyComponentWithEnablement (ValueWithDefault& valueToControl,
|
||||
ValueWithDefault valueToListenTo,
|
||||
const String& propertyName)
|
||||
: ChoicePropertyComponent (valueToControl, propertyName),
|
||||
valueWithDefault (valueToListenTo),
|
||||
value (valueToListenTo.getPropertyAsValue())
|
||||
{
|
||||
value.addListener (this);
|
||||
valueChanged (value);
|
||||
}
|
||||
|
||||
~ChoicePropertyComponentWithEnablement() override { value.removeListener (this); }
|
||||
|
||||
private:
|
||||
ValueWithDefault valueWithDefault;
|
||||
Value value;
|
||||
|
||||
bool isMultiChoice = false;
|
||||
Identifier idToCheck;
|
||||
|
||||
bool checkMultiChoiceVar() const
|
||||
{
|
||||
jassert (isMultiChoice);
|
||||
|
||||
auto v = valueWithDefault.get();
|
||||
|
||||
if (auto* varArray = v.getArray())
|
||||
return varArray->contains (idToCheck.toString());
|
||||
|
||||
jassertfalse;
|
||||
return false;
|
||||
}
|
||||
|
||||
void valueChanged (Value&) override
|
||||
{
|
||||
if (isMultiChoice)
|
||||
setEnabled (checkMultiChoiceVar());
|
||||
else
|
||||
setEnabled (valueWithDefault.get());
|
||||
}
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class MultiChoicePropertyComponentWithEnablement : public MultiChoicePropertyComponent,
|
||||
private Value::Listener
|
||||
{
|
||||
public:
|
||||
MultiChoicePropertyComponentWithEnablement (ValueWithDefault& valueToControl,
|
||||
ValueWithDefault valueToListenTo,
|
||||
const String& propertyName,
|
||||
const StringArray& choices,
|
||||
const Array<var>& correspondingValues)
|
||||
: MultiChoicePropertyComponent (valueToControl,
|
||||
propertyName,
|
||||
choices,
|
||||
correspondingValues),
|
||||
valueWithDefault (valueToListenTo),
|
||||
value (valueToListenTo.getPropertyAsValue())
|
||||
{
|
||||
value.addListener (this);
|
||||
valueChanged (value);
|
||||
}
|
||||
|
||||
~MultiChoicePropertyComponentWithEnablement() override { value.removeListener (this); }
|
||||
|
||||
private:
|
||||
void valueChanged (Value&) override { setEnabled (valueWithDefault.get()); }
|
||||
|
||||
ValueWithDefault valueWithDefault;
|
||||
Value value;
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class TextPropertyComponentWithEnablement : public TextPropertyComponent,
|
||||
private Value::Listener
|
||||
{
|
||||
public:
|
||||
TextPropertyComponentWithEnablement (const ValueTreePropertyWithDefault& valueToControl,
|
||||
ValueTreePropertyWithDefault valueToListenTo,
|
||||
const String& propertyName,
|
||||
int maxNumChars,
|
||||
bool multiLine)
|
||||
: TextPropertyComponent (valueToControl, propertyName, maxNumChars, multiLine),
|
||||
propertyWithDefault (valueToListenTo),
|
||||
value (propertyWithDefault.getPropertyAsValue())
|
||||
{
|
||||
value.addListener (this);
|
||||
setEnabled (propertyWithDefault.get());
|
||||
}
|
||||
|
||||
~TextPropertyComponentWithEnablement() override { value.removeListener (this); }
|
||||
|
||||
private:
|
||||
ValueTreePropertyWithDefault propertyWithDefault;
|
||||
Value value;
|
||||
|
||||
void valueChanged (Value&) override { setEnabled (propertyWithDefault.get()); }
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class ChoicePropertyComponentWithEnablement : public ChoicePropertyComponent,
|
||||
private Value::Listener
|
||||
{
|
||||
public:
|
||||
ChoicePropertyComponentWithEnablement (const ValueTreePropertyWithDefault& valueToControl,
|
||||
ValueTreePropertyWithDefault valueToListenTo,
|
||||
const String& propertyName,
|
||||
const StringArray& choiceToUse,
|
||||
const Array<var>& correspondingValues)
|
||||
: ChoicePropertyComponent (valueToControl, propertyName, choiceToUse, correspondingValues),
|
||||
propertyWithDefault (valueToListenTo),
|
||||
value (valueToListenTo.getPropertyAsValue())
|
||||
{
|
||||
value.addListener (this);
|
||||
valueChanged (value);
|
||||
}
|
||||
|
||||
ChoicePropertyComponentWithEnablement (const ValueTreePropertyWithDefault& valueToControl,
|
||||
ValueTreePropertyWithDefault valueToListenTo,
|
||||
const Identifier& multiChoiceID,
|
||||
const String& propertyName,
|
||||
const StringArray& choicesToUse,
|
||||
const Array<var>& correspondingValues)
|
||||
: ChoicePropertyComponentWithEnablement (valueToControl, valueToListenTo, propertyName, choicesToUse, correspondingValues)
|
||||
{
|
||||
jassert (valueToListenTo.get().getArray() != nullptr);
|
||||
|
||||
isMultiChoice = true;
|
||||
idToCheck = multiChoiceID;
|
||||
|
||||
valueChanged (value);
|
||||
}
|
||||
|
||||
ChoicePropertyComponentWithEnablement (const ValueTreePropertyWithDefault& valueToControl,
|
||||
ValueTreePropertyWithDefault valueToListenTo,
|
||||
const String& propertyName)
|
||||
: ChoicePropertyComponent (valueToControl, propertyName),
|
||||
propertyWithDefault (valueToListenTo),
|
||||
value (valueToListenTo.getPropertyAsValue())
|
||||
{
|
||||
value.addListener (this);
|
||||
valueChanged (value);
|
||||
}
|
||||
|
||||
~ChoicePropertyComponentWithEnablement() override { value.removeListener (this); }
|
||||
|
||||
private:
|
||||
ValueTreePropertyWithDefault propertyWithDefault;
|
||||
Value value;
|
||||
|
||||
bool isMultiChoice = false;
|
||||
Identifier idToCheck;
|
||||
|
||||
bool checkMultiChoiceVar() const
|
||||
{
|
||||
jassert (isMultiChoice);
|
||||
|
||||
auto v = propertyWithDefault.get();
|
||||
|
||||
if (auto* varArray = v.getArray())
|
||||
return varArray->contains (idToCheck.toString());
|
||||
|
||||
jassertfalse;
|
||||
return false;
|
||||
}
|
||||
|
||||
void valueChanged (Value&) override
|
||||
{
|
||||
if (isMultiChoice)
|
||||
setEnabled (checkMultiChoiceVar());
|
||||
else
|
||||
setEnabled (propertyWithDefault.get());
|
||||
}
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class MultiChoicePropertyComponentWithEnablement : public MultiChoicePropertyComponent,
|
||||
private Value::Listener
|
||||
{
|
||||
public:
|
||||
MultiChoicePropertyComponentWithEnablement (const ValueTreePropertyWithDefault& valueToControl,
|
||||
ValueTreePropertyWithDefault valueToListenTo,
|
||||
const String& propertyName,
|
||||
const StringArray& choices,
|
||||
const Array<var>& correspondingValues)
|
||||
: MultiChoicePropertyComponent (valueToControl,
|
||||
propertyName,
|
||||
choices,
|
||||
correspondingValues),
|
||||
propertyWithDefault (valueToListenTo),
|
||||
value (valueToListenTo.getPropertyAsValue())
|
||||
{
|
||||
value.addListener (this);
|
||||
valueChanged (value);
|
||||
}
|
||||
|
||||
~MultiChoicePropertyComponentWithEnablement() override { value.removeListener (this); }
|
||||
|
||||
private:
|
||||
void valueChanged (Value&) override { setEnabled (propertyWithDefault.get()); }
|
||||
|
||||
ValueTreePropertyWithDefault propertyWithDefault;
|
||||
Value value;
|
||||
};
|
||||
|
@ -1,136 +1,136 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class IconButton : public Button
|
||||
{
|
||||
public:
|
||||
IconButton (String buttonName, Image imageToDisplay)
|
||||
: Button (buttonName),
|
||||
iconImage (imageToDisplay)
|
||||
{
|
||||
setTooltip (buttonName);
|
||||
}
|
||||
|
||||
IconButton (String buttonName, Path pathToDisplay)
|
||||
: Button (buttonName),
|
||||
iconPath (pathToDisplay),
|
||||
iconImage (createImageFromPath (iconPath))
|
||||
{
|
||||
setTooltip (buttonName);
|
||||
}
|
||||
|
||||
void setImage (Image newImage)
|
||||
{
|
||||
iconImage = newImage;
|
||||
repaint();
|
||||
}
|
||||
|
||||
void setPath (Path newPath)
|
||||
{
|
||||
iconImage = createImageFromPath (newPath);
|
||||
repaint();
|
||||
}
|
||||
|
||||
void setBackgroundColour (Colour backgroundColourToUse)
|
||||
{
|
||||
backgroundColour = backgroundColourToUse;
|
||||
usingNonDefaultBackgroundColour = true;
|
||||
}
|
||||
|
||||
void setIconInset (int newIconInset)
|
||||
{
|
||||
iconInset = newIconInset;
|
||||
repaint();
|
||||
}
|
||||
|
||||
void paintButton (Graphics& g, bool isMouseOverButton, bool isButtonDown) override
|
||||
{
|
||||
float alpha = 1.0f;
|
||||
|
||||
if (! isEnabled())
|
||||
{
|
||||
isMouseOverButton = false;
|
||||
isButtonDown = false;
|
||||
|
||||
alpha = 0.2f;
|
||||
}
|
||||
|
||||
auto fill = isButtonDown ? backgroundColour.darker (0.5f)
|
||||
: isMouseOverButton ? backgroundColour.darker (0.2f)
|
||||
: backgroundColour;
|
||||
|
||||
auto bounds = getLocalBounds();
|
||||
|
||||
if (isButtonDown)
|
||||
bounds.reduce (2, 2);
|
||||
|
||||
Path ellipse;
|
||||
ellipse.addEllipse (bounds.toFloat());
|
||||
g.reduceClipRegion (ellipse);
|
||||
|
||||
g.setColour (fill.withAlpha (alpha));
|
||||
g.fillAll();
|
||||
|
||||
g.setOpacity (alpha);
|
||||
g.drawImage (iconImage, bounds.reduced (iconInset).toFloat(), RectanglePlacement::fillDestination, false);
|
||||
}
|
||||
|
||||
private:
|
||||
void lookAndFeelChanged() override
|
||||
{
|
||||
if (! usingNonDefaultBackgroundColour)
|
||||
backgroundColour = findColour (defaultButtonBackgroundColourId);
|
||||
|
||||
if (iconPath != Path())
|
||||
iconImage = createImageFromPath (iconPath);
|
||||
|
||||
repaint();
|
||||
}
|
||||
|
||||
Image createImageFromPath (Path path)
|
||||
{
|
||||
Image image (Image::ARGB, 250, 250, true);
|
||||
Graphics g (image);
|
||||
|
||||
g.setColour (findColour (defaultIconColourId));
|
||||
|
||||
g.fillPath (path, RectanglePlacement (RectanglePlacement::centred)
|
||||
.getTransformToFit (path.getBounds(), image.getBounds().toFloat()));
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
Path iconPath;
|
||||
Image iconImage;
|
||||
Colour backgroundColour { findColour (defaultButtonBackgroundColourId) };
|
||||
bool usingNonDefaultBackgroundColour = false;
|
||||
int iconInset = 2;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (IconButton)
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class IconButton : public Button
|
||||
{
|
||||
public:
|
||||
IconButton (String buttonName, Image imageToDisplay)
|
||||
: Button (buttonName),
|
||||
iconImage (imageToDisplay)
|
||||
{
|
||||
setTooltip (buttonName);
|
||||
}
|
||||
|
||||
IconButton (String buttonName, Path pathToDisplay)
|
||||
: Button (buttonName),
|
||||
iconPath (pathToDisplay),
|
||||
iconImage (createImageFromPath (iconPath))
|
||||
{
|
||||
setTooltip (buttonName);
|
||||
}
|
||||
|
||||
void setImage (Image newImage)
|
||||
{
|
||||
iconImage = newImage;
|
||||
repaint();
|
||||
}
|
||||
|
||||
void setPath (Path newPath)
|
||||
{
|
||||
iconImage = createImageFromPath (newPath);
|
||||
repaint();
|
||||
}
|
||||
|
||||
void setBackgroundColour (Colour backgroundColourToUse)
|
||||
{
|
||||
backgroundColour = backgroundColourToUse;
|
||||
usingNonDefaultBackgroundColour = true;
|
||||
}
|
||||
|
||||
void setIconInset (int newIconInset)
|
||||
{
|
||||
iconInset = newIconInset;
|
||||
repaint();
|
||||
}
|
||||
|
||||
void paintButton (Graphics& g, bool isMouseOverButton, bool isButtonDown) override
|
||||
{
|
||||
float alpha = 1.0f;
|
||||
|
||||
if (! isEnabled())
|
||||
{
|
||||
isMouseOverButton = false;
|
||||
isButtonDown = false;
|
||||
|
||||
alpha = 0.2f;
|
||||
}
|
||||
|
||||
auto fill = isButtonDown ? backgroundColour.darker (0.5f)
|
||||
: isMouseOverButton ? backgroundColour.darker (0.2f)
|
||||
: backgroundColour;
|
||||
|
||||
auto bounds = getLocalBounds();
|
||||
|
||||
if (isButtonDown)
|
||||
bounds.reduce (2, 2);
|
||||
|
||||
Path ellipse;
|
||||
ellipse.addEllipse (bounds.toFloat());
|
||||
g.reduceClipRegion (ellipse);
|
||||
|
||||
g.setColour (fill.withAlpha (alpha));
|
||||
g.fillAll();
|
||||
|
||||
g.setOpacity (alpha);
|
||||
g.drawImage (iconImage, bounds.reduced (iconInset).toFloat(), RectanglePlacement::fillDestination, false);
|
||||
}
|
||||
|
||||
private:
|
||||
void lookAndFeelChanged() override
|
||||
{
|
||||
if (! usingNonDefaultBackgroundColour)
|
||||
backgroundColour = findColour (defaultButtonBackgroundColourId);
|
||||
|
||||
if (iconPath != Path())
|
||||
iconImage = createImageFromPath (iconPath);
|
||||
|
||||
repaint();
|
||||
}
|
||||
|
||||
Image createImageFromPath (Path path)
|
||||
{
|
||||
Image image (Image::ARGB, 250, 250, true);
|
||||
Graphics g (image);
|
||||
|
||||
g.setColour (findColour (defaultIconColourId));
|
||||
|
||||
g.fillPath (path, RectanglePlacement (RectanglePlacement::centred)
|
||||
.getTransformToFit (path.getBounds(), image.getBounds().toFloat()));
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
Path iconPath;
|
||||
Image iconImage;
|
||||
Colour backgroundColour { findColour (defaultButtonBackgroundColourId) };
|
||||
bool usingNonDefaultBackgroundColour = false;
|
||||
int iconInset = 2;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (IconButton)
|
||||
};
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,86 +1,86 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
//==============================================================================
|
||||
struct Icon
|
||||
{
|
||||
Icon() = default;
|
||||
|
||||
Icon (const Path& pathToUse, Colour pathColour)
|
||||
: path (pathToUse),
|
||||
colour (pathColour)
|
||||
{
|
||||
}
|
||||
|
||||
void draw (Graphics& g, const juce::Rectangle<float>& area, bool isCrossedOut) const
|
||||
{
|
||||
if (! path.isEmpty())
|
||||
{
|
||||
g.setColour (colour);
|
||||
|
||||
const RectanglePlacement placement (RectanglePlacement::centred | RectanglePlacement::onlyReduceInSize);
|
||||
g.fillPath (path, placement.getTransformToFit (path.getBounds(), area));
|
||||
|
||||
if (isCrossedOut)
|
||||
{
|
||||
g.setColour (Colours::red.withAlpha (0.8f));
|
||||
g.drawLine ((float) area.getX(), area.getY() + area.getHeight() * 0.2f,
|
||||
(float) area.getRight(), area.getY() + area.getHeight() * 0.8f, 3.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Icon withContrastingColourTo (Colour background) const
|
||||
{
|
||||
return Icon (path, background.contrasting (colour, 0.6f));
|
||||
}
|
||||
|
||||
Icon withColour (Colour newColour)
|
||||
{
|
||||
return Icon (path, newColour);
|
||||
}
|
||||
|
||||
Path path;
|
||||
Colour colour;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class Icons
|
||||
{
|
||||
public:
|
||||
Icons();
|
||||
|
||||
Path imageDoc, config, graph, info, warning, user, closedFolder, exporter, fileExplorer, file,
|
||||
modules, openFolder, settings, singleModule, plus, android, codeBlocks,
|
||||
linux, xcode, visualStudio, clion;
|
||||
|
||||
private:
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Icons)
|
||||
};
|
||||
|
||||
const Icons& getIcons();
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
//==============================================================================
|
||||
struct Icon
|
||||
{
|
||||
Icon() = default;
|
||||
|
||||
Icon (const Path& pathToUse, Colour pathColour)
|
||||
: path (pathToUse),
|
||||
colour (pathColour)
|
||||
{
|
||||
}
|
||||
|
||||
void draw (Graphics& g, const juce::Rectangle<float>& area, bool isCrossedOut) const
|
||||
{
|
||||
if (! path.isEmpty())
|
||||
{
|
||||
g.setColour (colour);
|
||||
|
||||
const RectanglePlacement placement (RectanglePlacement::centred | RectanglePlacement::onlyReduceInSize);
|
||||
g.fillPath (path, placement.getTransformToFit (path.getBounds(), area));
|
||||
|
||||
if (isCrossedOut)
|
||||
{
|
||||
g.setColour (Colours::red.withAlpha (0.8f));
|
||||
g.drawLine ((float) area.getX(), area.getY() + area.getHeight() * 0.2f,
|
||||
(float) area.getRight(), area.getY() + area.getHeight() * 0.8f, 3.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Icon withContrastingColourTo (Colour background) const
|
||||
{
|
||||
return Icon (path, background.contrasting (colour, 0.6f));
|
||||
}
|
||||
|
||||
Icon withColour (Colour newColour)
|
||||
{
|
||||
return Icon (path, newColour);
|
||||
}
|
||||
|
||||
Path path;
|
||||
Colour colour;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class Icons
|
||||
{
|
||||
public:
|
||||
Icons();
|
||||
|
||||
Path imageDoc, config, graph, info, warning, user, closedFolder, exporter, fileExplorer, file,
|
||||
modules, openFolder, settings, singleModule, plus, android, codeBlocks,
|
||||
linux, xcode, visualStudio;
|
||||
|
||||
private:
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Icons)
|
||||
};
|
||||
|
||||
const Icons& getIcons();
|
||||
|
@ -1,251 +1,251 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "../../Application/jucer_Headers.h"
|
||||
#include "jucer_JucerTreeViewBase.h"
|
||||
#include "../../Project/UI/jucer_ProjectContentComponent.h"
|
||||
|
||||
//==============================================================================
|
||||
void TreePanelBase::setRoot (std::unique_ptr<JucerTreeViewBase> root)
|
||||
{
|
||||
rootItem = std::move (root);
|
||||
tree.setRootItem (rootItem.get());
|
||||
tree.getRootItem()->setOpen (true);
|
||||
|
||||
if (project != nullptr)
|
||||
{
|
||||
if (auto treeOpenness = project->getStoredProperties().getXmlValue (opennessStateKey))
|
||||
{
|
||||
tree.restoreOpennessState (*treeOpenness, true);
|
||||
|
||||
for (int i = tree.getNumSelectedItems(); --i >= 0;)
|
||||
if (auto item = dynamic_cast<JucerTreeViewBase*> (tree.getSelectedItem (i)))
|
||||
item->cancelDelayedSelectionTimer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TreePanelBase::saveOpenness()
|
||||
{
|
||||
if (project != nullptr)
|
||||
{
|
||||
std::unique_ptr<XmlElement> opennessState (tree.getOpennessState (true));
|
||||
|
||||
if (opennessState != nullptr)
|
||||
project->getStoredProperties().setValue (opennessStateKey, opennessState.get());
|
||||
else
|
||||
project->getStoredProperties().removeValue (opennessStateKey);
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
JucerTreeViewBase::JucerTreeViewBase()
|
||||
{
|
||||
setLinesDrawnForSubItems (false);
|
||||
setDrawsInLeftMargin (true);
|
||||
}
|
||||
|
||||
void JucerTreeViewBase::refreshSubItems()
|
||||
{
|
||||
WholeTreeOpennessRestorer wtor (*this);
|
||||
clearSubItems();
|
||||
addSubItems();
|
||||
}
|
||||
|
||||
Font JucerTreeViewBase::getFont() const
|
||||
{
|
||||
return Font ((float) getItemHeight() * 0.6f);
|
||||
}
|
||||
|
||||
void JucerTreeViewBase::paintOpenCloseButton (Graphics& g, const Rectangle<float>& area, Colour /*backgroundColour*/, bool isMouseOver)
|
||||
{
|
||||
g.setColour (getOwnerView()->findColour (isSelected() ? defaultHighlightedTextColourId : treeIconColourId));
|
||||
TreeViewItem::paintOpenCloseButton (g, area, getOwnerView()->findColour (defaultIconColourId), isMouseOver);
|
||||
}
|
||||
|
||||
void JucerTreeViewBase::paintIcon (Graphics& g, Rectangle<float> area)
|
||||
{
|
||||
g.setColour (getContentColour (true));
|
||||
getIcon().draw (g, area, isIconCrossedOut());
|
||||
textX = roundToInt (area.getRight()) + 7;
|
||||
}
|
||||
|
||||
void JucerTreeViewBase::paintItem (Graphics& g, int width, int height)
|
||||
{
|
||||
ignoreUnused (width, height);
|
||||
|
||||
auto bounds = g.getClipBounds().withY (0).withHeight (height).toFloat();
|
||||
|
||||
g.setColour (getOwnerView()->findColour (treeIconColourId).withMultipliedAlpha (0.4f));
|
||||
g.fillRect (bounds.removeFromBottom (0.5f).reduced (5, 0));
|
||||
}
|
||||
|
||||
Colour JucerTreeViewBase::getContentColour (bool isIcon) const
|
||||
{
|
||||
if (isMissing()) return Colours::red;
|
||||
if (isSelected()) return getOwnerView()->findColour (defaultHighlightedTextColourId);
|
||||
if (hasWarnings()) return getOwnerView()->findColour (defaultHighlightColourId);
|
||||
|
||||
return getOwnerView()->findColour (isIcon ? treeIconColourId : defaultTextColourId);
|
||||
}
|
||||
|
||||
void JucerTreeViewBase::paintContent (Graphics& g, Rectangle<int> area)
|
||||
{
|
||||
g.setFont (getFont());
|
||||
g.setColour (getContentColour (false));
|
||||
|
||||
g.drawFittedText (getDisplayName(), area, Justification::centredLeft, 1, 1.0f);
|
||||
}
|
||||
|
||||
std::unique_ptr<Component> JucerTreeViewBase::createItemComponent()
|
||||
{
|
||||
return std::make_unique<TreeItemComponent> (*this);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class RenameTreeItemCallback : public ModalComponentManager::Callback
|
||||
{
|
||||
public:
|
||||
RenameTreeItemCallback (JucerTreeViewBase& ti, Component& parent, const Rectangle<int>& bounds)
|
||||
: item (ti)
|
||||
{
|
||||
ed.setMultiLine (false, false);
|
||||
ed.setPopupMenuEnabled (false);
|
||||
ed.setSelectAllWhenFocused (true);
|
||||
ed.setFont (item.getFont());
|
||||
ed.onReturnKey = [this] { ed.exitModalState (1); };
|
||||
ed.onEscapeKey = [this] { ed.exitModalState (0); };
|
||||
ed.onFocusLost = [this] { ed.exitModalState (0); };
|
||||
ed.setText (item.getRenamingName());
|
||||
ed.setBounds (bounds);
|
||||
|
||||
parent.addAndMakeVisible (ed);
|
||||
ed.enterModalState (true, this);
|
||||
}
|
||||
|
||||
void modalStateFinished (int resultCode) override
|
||||
{
|
||||
if (resultCode != 0)
|
||||
item.setName (ed.getText());
|
||||
}
|
||||
|
||||
private:
|
||||
struct RenameEditor : public TextEditor
|
||||
{
|
||||
void inputAttemptWhenModal() override { exitModalState (0); }
|
||||
};
|
||||
|
||||
RenameEditor ed;
|
||||
JucerTreeViewBase& item;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE (RenameTreeItemCallback)
|
||||
};
|
||||
|
||||
void JucerTreeViewBase::showRenameBox()
|
||||
{
|
||||
Rectangle<int> r (getItemPosition (true));
|
||||
r.setLeft (r.getX() + textX);
|
||||
r.setHeight (getItemHeight());
|
||||
|
||||
new RenameTreeItemCallback (*this, *getOwnerView(), r);
|
||||
}
|
||||
|
||||
void JucerTreeViewBase::itemClicked (const MouseEvent& e)
|
||||
{
|
||||
if (e.mods.isPopupMenu())
|
||||
{
|
||||
if (getOwnerView()->getNumSelectedItems() > 1)
|
||||
showMultiSelectionPopupMenu (e.getMouseDownScreenPosition());
|
||||
else
|
||||
showPopupMenu (e.getMouseDownScreenPosition());
|
||||
}
|
||||
else if (isSelected())
|
||||
{
|
||||
itemSelectionChanged (true);
|
||||
}
|
||||
}
|
||||
|
||||
static void treeViewMenuItemChosen (int resultCode, WeakReference<JucerTreeViewBase> item)
|
||||
{
|
||||
if (item != nullptr)
|
||||
item->handlePopupMenuResult (resultCode);
|
||||
}
|
||||
|
||||
void JucerTreeViewBase::launchPopupMenu (PopupMenu& m, Point<int> p)
|
||||
{
|
||||
m.showMenuAsync (PopupMenu::Options().withTargetScreenArea ({ p.x, p.y, 1, 1 }),
|
||||
ModalCallbackFunction::create (treeViewMenuItemChosen, WeakReference<JucerTreeViewBase> (this)));
|
||||
}
|
||||
|
||||
ProjectContentComponent* JucerTreeViewBase::getProjectContentComponent() const
|
||||
{
|
||||
for (Component* c = getOwnerView(); c != nullptr; c = c->getParentComponent())
|
||||
if (ProjectContentComponent* pcc = dynamic_cast<ProjectContentComponent*> (c))
|
||||
return pcc;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class JucerTreeViewBase::ItemSelectionTimer : public Timer
|
||||
{
|
||||
public:
|
||||
explicit ItemSelectionTimer (JucerTreeViewBase& tvb) : owner (tvb) {}
|
||||
|
||||
void timerCallback() override { owner.invokeShowDocument(); }
|
||||
|
||||
private:
|
||||
JucerTreeViewBase& owner;
|
||||
JUCE_DECLARE_NON_COPYABLE (ItemSelectionTimer)
|
||||
};
|
||||
|
||||
void JucerTreeViewBase::itemSelectionChanged (bool isNowSelected)
|
||||
{
|
||||
if (isNowSelected)
|
||||
{
|
||||
delayedSelectionTimer.reset (new ItemSelectionTimer (*this));
|
||||
delayedSelectionTimer->startTimer (getMillisecsAllowedForDragGesture());
|
||||
}
|
||||
else
|
||||
{
|
||||
cancelDelayedSelectionTimer();
|
||||
}
|
||||
}
|
||||
|
||||
void JucerTreeViewBase::invokeShowDocument()
|
||||
{
|
||||
cancelDelayedSelectionTimer();
|
||||
showDocument();
|
||||
}
|
||||
|
||||
void JucerTreeViewBase::itemDoubleClicked (const MouseEvent&)
|
||||
{
|
||||
invokeShowDocument();
|
||||
}
|
||||
|
||||
void JucerTreeViewBase::cancelDelayedSelectionTimer()
|
||||
{
|
||||
delayedSelectionTimer.reset();
|
||||
}
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "../../Application/jucer_Headers.h"
|
||||
#include "jucer_JucerTreeViewBase.h"
|
||||
#include "../../Project/UI/jucer_ProjectContentComponent.h"
|
||||
|
||||
//==============================================================================
|
||||
void TreePanelBase::setRoot (std::unique_ptr<JucerTreeViewBase> root)
|
||||
{
|
||||
rootItem = std::move (root);
|
||||
tree.setRootItem (rootItem.get());
|
||||
tree.getRootItem()->setOpen (true);
|
||||
|
||||
if (project != nullptr)
|
||||
{
|
||||
if (auto treeOpenness = project->getStoredProperties().getXmlValue (opennessStateKey))
|
||||
{
|
||||
tree.restoreOpennessState (*treeOpenness, true);
|
||||
|
||||
for (int i = tree.getNumSelectedItems(); --i >= 0;)
|
||||
if (auto item = dynamic_cast<JucerTreeViewBase*> (tree.getSelectedItem (i)))
|
||||
item->cancelDelayedSelectionTimer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TreePanelBase::saveOpenness()
|
||||
{
|
||||
if (project != nullptr)
|
||||
{
|
||||
std::unique_ptr<XmlElement> opennessState (tree.getOpennessState (true));
|
||||
|
||||
if (opennessState != nullptr)
|
||||
project->getStoredProperties().setValue (opennessStateKey, opennessState.get());
|
||||
else
|
||||
project->getStoredProperties().removeValue (opennessStateKey);
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
JucerTreeViewBase::JucerTreeViewBase()
|
||||
{
|
||||
setLinesDrawnForSubItems (false);
|
||||
setDrawsInLeftMargin (true);
|
||||
}
|
||||
|
||||
void JucerTreeViewBase::refreshSubItems()
|
||||
{
|
||||
WholeTreeOpennessRestorer wtor (*this);
|
||||
clearSubItems();
|
||||
addSubItems();
|
||||
}
|
||||
|
||||
Font JucerTreeViewBase::getFont() const
|
||||
{
|
||||
return Font ((float) getItemHeight() * 0.6f);
|
||||
}
|
||||
|
||||
void JucerTreeViewBase::paintOpenCloseButton (Graphics& g, const Rectangle<float>& area, Colour /*backgroundColour*/, bool isMouseOver)
|
||||
{
|
||||
g.setColour (getOwnerView()->findColour (isSelected() ? defaultHighlightedTextColourId : treeIconColourId));
|
||||
TreeViewItem::paintOpenCloseButton (g, area, getOwnerView()->findColour (defaultIconColourId), isMouseOver);
|
||||
}
|
||||
|
||||
void JucerTreeViewBase::paintIcon (Graphics& g, Rectangle<float> area)
|
||||
{
|
||||
g.setColour (getContentColour (true));
|
||||
getIcon().draw (g, area, isIconCrossedOut());
|
||||
textX = roundToInt (area.getRight()) + 7;
|
||||
}
|
||||
|
||||
void JucerTreeViewBase::paintItem (Graphics& g, int width, int height)
|
||||
{
|
||||
ignoreUnused (width, height);
|
||||
|
||||
auto bounds = g.getClipBounds().withY (0).withHeight (height).toFloat();
|
||||
|
||||
g.setColour (getOwnerView()->findColour (treeIconColourId).withMultipliedAlpha (0.4f));
|
||||
g.fillRect (bounds.removeFromBottom (0.5f).reduced (5, 0));
|
||||
}
|
||||
|
||||
Colour JucerTreeViewBase::getContentColour (bool isIcon) const
|
||||
{
|
||||
if (isMissing()) return Colours::red;
|
||||
if (isSelected()) return getOwnerView()->findColour (defaultHighlightedTextColourId);
|
||||
if (hasWarnings()) return getOwnerView()->findColour (defaultHighlightColourId);
|
||||
|
||||
return getOwnerView()->findColour (isIcon ? treeIconColourId : defaultTextColourId);
|
||||
}
|
||||
|
||||
void JucerTreeViewBase::paintContent (Graphics& g, Rectangle<int> area)
|
||||
{
|
||||
g.setFont (getFont());
|
||||
g.setColour (getContentColour (false));
|
||||
|
||||
g.drawFittedText (getDisplayName(), area, Justification::centredLeft, 1, 1.0f);
|
||||
}
|
||||
|
||||
std::unique_ptr<Component> JucerTreeViewBase::createItemComponent()
|
||||
{
|
||||
return std::make_unique<TreeItemComponent> (*this);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class RenameTreeItemCallback : public ModalComponentManager::Callback
|
||||
{
|
||||
public:
|
||||
RenameTreeItemCallback (JucerTreeViewBase& ti, Component& parent, const Rectangle<int>& bounds)
|
||||
: item (ti)
|
||||
{
|
||||
ed.setMultiLine (false, false);
|
||||
ed.setPopupMenuEnabled (false);
|
||||
ed.setSelectAllWhenFocused (true);
|
||||
ed.setFont (item.getFont());
|
||||
ed.onReturnKey = [this] { ed.exitModalState (1); };
|
||||
ed.onEscapeKey = [this] { ed.exitModalState (0); };
|
||||
ed.onFocusLost = [this] { ed.exitModalState (0); };
|
||||
ed.setText (item.getRenamingName());
|
||||
ed.setBounds (bounds);
|
||||
|
||||
parent.addAndMakeVisible (ed);
|
||||
ed.enterModalState (true, this);
|
||||
}
|
||||
|
||||
void modalStateFinished (int resultCode) override
|
||||
{
|
||||
if (resultCode != 0)
|
||||
item.setName (ed.getText());
|
||||
}
|
||||
|
||||
private:
|
||||
struct RenameEditor : public TextEditor
|
||||
{
|
||||
void inputAttemptWhenModal() override { exitModalState (0); }
|
||||
};
|
||||
|
||||
RenameEditor ed;
|
||||
JucerTreeViewBase& item;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE (RenameTreeItemCallback)
|
||||
};
|
||||
|
||||
void JucerTreeViewBase::showRenameBox()
|
||||
{
|
||||
Rectangle<int> r (getItemPosition (true));
|
||||
r.setLeft (r.getX() + textX);
|
||||
r.setHeight (getItemHeight());
|
||||
|
||||
new RenameTreeItemCallback (*this, *getOwnerView(), r);
|
||||
}
|
||||
|
||||
void JucerTreeViewBase::itemClicked (const MouseEvent& e)
|
||||
{
|
||||
if (e.mods.isPopupMenu())
|
||||
{
|
||||
if (getOwnerView()->getNumSelectedItems() > 1)
|
||||
showMultiSelectionPopupMenu (e.getMouseDownScreenPosition());
|
||||
else
|
||||
showPopupMenu (e.getMouseDownScreenPosition());
|
||||
}
|
||||
else if (isSelected())
|
||||
{
|
||||
itemSelectionChanged (true);
|
||||
}
|
||||
}
|
||||
|
||||
static void treeViewMenuItemChosen (int resultCode, WeakReference<JucerTreeViewBase> item)
|
||||
{
|
||||
if (item != nullptr)
|
||||
item->handlePopupMenuResult (resultCode);
|
||||
}
|
||||
|
||||
void JucerTreeViewBase::launchPopupMenu (PopupMenu& m, Point<int> p)
|
||||
{
|
||||
m.showMenuAsync (PopupMenu::Options().withTargetScreenArea ({ p.x, p.y, 1, 1 }),
|
||||
ModalCallbackFunction::create (treeViewMenuItemChosen, WeakReference<JucerTreeViewBase> (this)));
|
||||
}
|
||||
|
||||
ProjectContentComponent* JucerTreeViewBase::getProjectContentComponent() const
|
||||
{
|
||||
for (Component* c = getOwnerView(); c != nullptr; c = c->getParentComponent())
|
||||
if (ProjectContentComponent* pcc = dynamic_cast<ProjectContentComponent*> (c))
|
||||
return pcc;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class JucerTreeViewBase::ItemSelectionTimer : public Timer
|
||||
{
|
||||
public:
|
||||
explicit ItemSelectionTimer (JucerTreeViewBase& tvb) : owner (tvb) {}
|
||||
|
||||
void timerCallback() override { owner.invokeShowDocument(); }
|
||||
|
||||
private:
|
||||
JucerTreeViewBase& owner;
|
||||
JUCE_DECLARE_NON_COPYABLE (ItemSelectionTimer)
|
||||
};
|
||||
|
||||
void JucerTreeViewBase::itemSelectionChanged (bool isNowSelected)
|
||||
{
|
||||
if (isNowSelected)
|
||||
{
|
||||
delayedSelectionTimer.reset (new ItemSelectionTimer (*this));
|
||||
delayedSelectionTimer->startTimer (getMillisecsAllowedForDragGesture());
|
||||
}
|
||||
else
|
||||
{
|
||||
cancelDelayedSelectionTimer();
|
||||
}
|
||||
}
|
||||
|
||||
void JucerTreeViewBase::invokeShowDocument()
|
||||
{
|
||||
cancelDelayedSelectionTimer();
|
||||
showDocument();
|
||||
}
|
||||
|
||||
void JucerTreeViewBase::itemDoubleClicked (const MouseEvent&)
|
||||
{
|
||||
invokeShowDocument();
|
||||
}
|
||||
|
||||
void JucerTreeViewBase::cancelDelayedSelectionTimer()
|
||||
{
|
||||
delayedSelectionTimer.reset();
|
||||
}
|
||||
|
@ -1,249 +1,249 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
class ProjectContentComponent;
|
||||
class Project;
|
||||
|
||||
//==============================================================================
|
||||
class JucerTreeViewBase : public TreeViewItem,
|
||||
public TooltipClient
|
||||
{
|
||||
public:
|
||||
JucerTreeViewBase();
|
||||
~JucerTreeViewBase() override = default;
|
||||
|
||||
int getItemWidth() const override { return -1; }
|
||||
int getItemHeight() const override { return 25; }
|
||||
|
||||
void paintOpenCloseButton (Graphics&, const Rectangle<float>& area, Colour backgroundColour, bool isMouseOver) override;
|
||||
void paintItem (Graphics& g, int width, int height) override;
|
||||
void itemClicked (const MouseEvent& e) override;
|
||||
void itemSelectionChanged (bool isNowSelected) override;
|
||||
void itemDoubleClicked (const MouseEvent&) override;
|
||||
std::unique_ptr<Component> createItemComponent() override;
|
||||
String getTooltip() override { return {}; }
|
||||
String getAccessibilityName() override { return getDisplayName(); }
|
||||
|
||||
void cancelDelayedSelectionTimer();
|
||||
|
||||
//==============================================================================
|
||||
virtual bool isRoot() const { return false; }
|
||||
virtual Font getFont() const;
|
||||
virtual String getRenamingName() const = 0;
|
||||
virtual String getDisplayName() const = 0;
|
||||
virtual void setName (const String& newName) = 0;
|
||||
virtual bool isMissing() const = 0;
|
||||
virtual bool hasWarnings() const { return false; }
|
||||
virtual Icon getIcon() const = 0;
|
||||
virtual bool isIconCrossedOut() const { return false; }
|
||||
virtual void paintIcon (Graphics& g, Rectangle<float> area);
|
||||
virtual void paintContent (Graphics& g, Rectangle<int> area);
|
||||
virtual int getRightHandButtonSpace() { return 0; }
|
||||
virtual Colour getContentColour (bool isIcon) const;
|
||||
virtual int getMillisecsAllowedForDragGesture() { return 120; }
|
||||
virtual File getDraggableFile() const { return {}; }
|
||||
|
||||
void refreshSubItems();
|
||||
void showRenameBox();
|
||||
|
||||
virtual void deleteItem() {}
|
||||
virtual void deleteAllSelectedItems() {}
|
||||
virtual void showDocument() {}
|
||||
virtual void showMultiSelectionPopupMenu (Point<int>) {}
|
||||
virtual void showPopupMenu (Point<int>) {}
|
||||
virtual void showAddMenu (Point<int>) {}
|
||||
virtual void handlePopupMenuResult (int) {}
|
||||
virtual void setSearchFilter (const String&) {}
|
||||
|
||||
void launchPopupMenu (PopupMenu&, Point<int>); // runs asynchronously, and produces a callback to handlePopupMenuResult().
|
||||
|
||||
//==============================================================================
|
||||
// To handle situations where an item gets deleted before openness is
|
||||
// restored for it, this OpennessRestorer keeps only a pointer to the
|
||||
// topmost tree item.
|
||||
struct WholeTreeOpennessRestorer : public OpennessRestorer
|
||||
{
|
||||
WholeTreeOpennessRestorer (TreeViewItem& item) : OpennessRestorer (getTopLevelItem (item))
|
||||
{}
|
||||
|
||||
private:
|
||||
static TreeViewItem& getTopLevelItem (TreeViewItem& item)
|
||||
{
|
||||
if (TreeViewItem* const p = item.getParentItem())
|
||||
return getTopLevelItem (*p);
|
||||
|
||||
return item;
|
||||
}
|
||||
};
|
||||
|
||||
int textX = 0;
|
||||
|
||||
protected:
|
||||
ProjectContentComponent* getProjectContentComponent() const;
|
||||
virtual void addSubItems() {}
|
||||
|
||||
private:
|
||||
class ItemSelectionTimer;
|
||||
friend class ItemSelectionTimer;
|
||||
std::unique_ptr<Timer> delayedSelectionTimer;
|
||||
|
||||
void invokeShowDocument();
|
||||
|
||||
JUCE_DECLARE_WEAK_REFERENCEABLE (JucerTreeViewBase)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class TreePanelBase : public Component
|
||||
{
|
||||
public:
|
||||
TreePanelBase (const Project* p, const String& treeviewID)
|
||||
: project (p), opennessStateKey (treeviewID)
|
||||
{
|
||||
addAndMakeVisible (tree);
|
||||
|
||||
tree.setRootItemVisible (true);
|
||||
tree.setDefaultOpenness (true);
|
||||
tree.setColour (TreeView::backgroundColourId, Colours::transparentBlack);
|
||||
tree.setIndentSize (14);
|
||||
tree.getViewport()->setScrollBarThickness (6);
|
||||
|
||||
tree.addMouseListener (this, true);
|
||||
}
|
||||
|
||||
~TreePanelBase() override
|
||||
{
|
||||
tree.setRootItem (nullptr);
|
||||
}
|
||||
|
||||
void setRoot (std::unique_ptr<JucerTreeViewBase>);
|
||||
void saveOpenness();
|
||||
|
||||
virtual void deleteSelectedItems()
|
||||
{
|
||||
if (rootItem != nullptr)
|
||||
rootItem->deleteAllSelectedItems();
|
||||
}
|
||||
|
||||
void setEmptyTreeMessage (const String& newMessage)
|
||||
{
|
||||
if (emptyTreeMessage != newMessage)
|
||||
{
|
||||
emptyTreeMessage = newMessage;
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
|
||||
static void drawEmptyPanelMessage (Component& comp, Graphics& g, const String& message)
|
||||
{
|
||||
const int fontHeight = 13;
|
||||
const Rectangle<int> area (comp.getLocalBounds());
|
||||
g.setColour (comp.findColour (defaultTextColourId));
|
||||
g.setFont ((float) fontHeight);
|
||||
g.drawFittedText (message, area.reduced (4, 2), Justification::centred, area.getHeight() / fontHeight);
|
||||
}
|
||||
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
if (emptyTreeMessage.isNotEmpty() && (rootItem == nullptr || rootItem->getNumSubItems() == 0))
|
||||
drawEmptyPanelMessage (*this, g, emptyTreeMessage);
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
tree.setBounds (getAvailableBounds());
|
||||
}
|
||||
|
||||
Rectangle<int> getAvailableBounds() const
|
||||
{
|
||||
return Rectangle<int> (0, 2, getWidth() - 2, getHeight() - 2);
|
||||
}
|
||||
|
||||
void mouseDown (const MouseEvent& e) override
|
||||
{
|
||||
if (e.eventComponent == &tree)
|
||||
{
|
||||
tree.clearSelectedItems();
|
||||
|
||||
if (e.mods.isRightButtonDown())
|
||||
rootItem->showPopupMenu (e.getMouseDownScreenPosition());
|
||||
}
|
||||
}
|
||||
|
||||
const Project* project;
|
||||
TreeView tree;
|
||||
std::unique_ptr<JucerTreeViewBase> rootItem;
|
||||
|
||||
private:
|
||||
String opennessStateKey, emptyTreeMessage;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class TreeItemComponent : public Component
|
||||
{
|
||||
public:
|
||||
TreeItemComponent (JucerTreeViewBase& i) : item (&i)
|
||||
{
|
||||
setAccessible (false);
|
||||
setInterceptsMouseClicks (false, true);
|
||||
item->textX = iconWidth;
|
||||
}
|
||||
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
if (item == nullptr)
|
||||
return;
|
||||
|
||||
auto bounds = getLocalBounds().toFloat();
|
||||
auto iconBounds = bounds.removeFromLeft ((float) iconWidth).reduced (7, 5);
|
||||
|
||||
bounds.removeFromRight ((float) buttons.size() * bounds.getHeight());
|
||||
|
||||
item->paintIcon (g, iconBounds);
|
||||
item->paintContent (g, bounds.toNearestInt());
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
auto r = getLocalBounds();
|
||||
|
||||
for (int i = buttons.size(); --i >= 0;)
|
||||
buttons.getUnchecked (i)->setBounds (r.removeFromRight (r.getHeight()));
|
||||
}
|
||||
|
||||
void addRightHandButton (Component* button)
|
||||
{
|
||||
buttons.add (button);
|
||||
addAndMakeVisible (button);
|
||||
}
|
||||
|
||||
WeakReference<JucerTreeViewBase> item;
|
||||
OwnedArray<Component> buttons;
|
||||
|
||||
const int iconWidth = 25;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TreeItemComponent)
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
class ProjectContentComponent;
|
||||
class Project;
|
||||
|
||||
//==============================================================================
|
||||
class JucerTreeViewBase : public TreeViewItem,
|
||||
public TooltipClient
|
||||
{
|
||||
public:
|
||||
JucerTreeViewBase();
|
||||
~JucerTreeViewBase() override = default;
|
||||
|
||||
int getItemWidth() const override { return -1; }
|
||||
int getItemHeight() const override { return 25; }
|
||||
|
||||
void paintOpenCloseButton (Graphics&, const Rectangle<float>& area, Colour backgroundColour, bool isMouseOver) override;
|
||||
void paintItem (Graphics& g, int width, int height) override;
|
||||
void itemClicked (const MouseEvent& e) override;
|
||||
void itemSelectionChanged (bool isNowSelected) override;
|
||||
void itemDoubleClicked (const MouseEvent&) override;
|
||||
std::unique_ptr<Component> createItemComponent() override;
|
||||
String getTooltip() override { return {}; }
|
||||
String getAccessibilityName() override { return getDisplayName(); }
|
||||
|
||||
void cancelDelayedSelectionTimer();
|
||||
|
||||
//==============================================================================
|
||||
virtual bool isRoot() const { return false; }
|
||||
virtual Font getFont() const;
|
||||
virtual String getRenamingName() const = 0;
|
||||
virtual String getDisplayName() const = 0;
|
||||
virtual void setName (const String& newName) = 0;
|
||||
virtual bool isMissing() const = 0;
|
||||
virtual bool hasWarnings() const { return false; }
|
||||
virtual Icon getIcon() const = 0;
|
||||
virtual bool isIconCrossedOut() const { return false; }
|
||||
virtual void paintIcon (Graphics& g, Rectangle<float> area);
|
||||
virtual void paintContent (Graphics& g, Rectangle<int> area);
|
||||
virtual int getRightHandButtonSpace() { return 0; }
|
||||
virtual Colour getContentColour (bool isIcon) const;
|
||||
virtual int getMillisecsAllowedForDragGesture() { return 120; }
|
||||
virtual File getDraggableFile() const { return {}; }
|
||||
|
||||
void refreshSubItems();
|
||||
void showRenameBox();
|
||||
|
||||
virtual void deleteItem() {}
|
||||
virtual void deleteAllSelectedItems() {}
|
||||
virtual void showDocument() {}
|
||||
virtual void showMultiSelectionPopupMenu (Point<int>) {}
|
||||
virtual void showPopupMenu (Point<int>) {}
|
||||
virtual void showAddMenu (Point<int>) {}
|
||||
virtual void handlePopupMenuResult (int) {}
|
||||
virtual void setSearchFilter (const String&) {}
|
||||
|
||||
void launchPopupMenu (PopupMenu&, Point<int>); // runs asynchronously, and produces a callback to handlePopupMenuResult().
|
||||
|
||||
//==============================================================================
|
||||
// To handle situations where an item gets deleted before openness is
|
||||
// restored for it, this OpennessRestorer keeps only a pointer to the
|
||||
// topmost tree item.
|
||||
struct WholeTreeOpennessRestorer : public OpennessRestorer
|
||||
{
|
||||
WholeTreeOpennessRestorer (TreeViewItem& item) : OpennessRestorer (getTopLevelItem (item))
|
||||
{}
|
||||
|
||||
private:
|
||||
static TreeViewItem& getTopLevelItem (TreeViewItem& item)
|
||||
{
|
||||
if (TreeViewItem* const p = item.getParentItem())
|
||||
return getTopLevelItem (*p);
|
||||
|
||||
return item;
|
||||
}
|
||||
};
|
||||
|
||||
int textX = 0;
|
||||
|
||||
protected:
|
||||
ProjectContentComponent* getProjectContentComponent() const;
|
||||
virtual void addSubItems() {}
|
||||
|
||||
private:
|
||||
class ItemSelectionTimer;
|
||||
friend class ItemSelectionTimer;
|
||||
std::unique_ptr<Timer> delayedSelectionTimer;
|
||||
|
||||
void invokeShowDocument();
|
||||
|
||||
JUCE_DECLARE_WEAK_REFERENCEABLE (JucerTreeViewBase)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class TreePanelBase : public Component
|
||||
{
|
||||
public:
|
||||
TreePanelBase (const Project* p, const String& treeviewID)
|
||||
: project (p), opennessStateKey (treeviewID)
|
||||
{
|
||||
addAndMakeVisible (tree);
|
||||
|
||||
tree.setRootItemVisible (true);
|
||||
tree.setDefaultOpenness (true);
|
||||
tree.setColour (TreeView::backgroundColourId, Colours::transparentBlack);
|
||||
tree.setIndentSize (14);
|
||||
tree.getViewport()->setScrollBarThickness (6);
|
||||
|
||||
tree.addMouseListener (this, true);
|
||||
}
|
||||
|
||||
~TreePanelBase() override
|
||||
{
|
||||
tree.setRootItem (nullptr);
|
||||
}
|
||||
|
||||
void setRoot (std::unique_ptr<JucerTreeViewBase>);
|
||||
void saveOpenness();
|
||||
|
||||
virtual void deleteSelectedItems()
|
||||
{
|
||||
if (rootItem != nullptr)
|
||||
rootItem->deleteAllSelectedItems();
|
||||
}
|
||||
|
||||
void setEmptyTreeMessage (const String& newMessage)
|
||||
{
|
||||
if (emptyTreeMessage != newMessage)
|
||||
{
|
||||
emptyTreeMessage = newMessage;
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
|
||||
static void drawEmptyPanelMessage (Component& comp, Graphics& g, const String& message)
|
||||
{
|
||||
const int fontHeight = 13;
|
||||
const Rectangle<int> area (comp.getLocalBounds());
|
||||
g.setColour (comp.findColour (defaultTextColourId));
|
||||
g.setFont ((float) fontHeight);
|
||||
g.drawFittedText (message, area.reduced (4, 2), Justification::centred, area.getHeight() / fontHeight);
|
||||
}
|
||||
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
if (emptyTreeMessage.isNotEmpty() && (rootItem == nullptr || rootItem->getNumSubItems() == 0))
|
||||
drawEmptyPanelMessage (*this, g, emptyTreeMessage);
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
tree.setBounds (getAvailableBounds());
|
||||
}
|
||||
|
||||
Rectangle<int> getAvailableBounds() const
|
||||
{
|
||||
return Rectangle<int> (0, 2, getWidth() - 2, getHeight() - 2);
|
||||
}
|
||||
|
||||
void mouseDown (const MouseEvent& e) override
|
||||
{
|
||||
if (e.eventComponent == &tree)
|
||||
{
|
||||
tree.clearSelectedItems();
|
||||
|
||||
if (e.mods.isRightButtonDown())
|
||||
rootItem->showPopupMenu (e.getMouseDownScreenPosition());
|
||||
}
|
||||
}
|
||||
|
||||
const Project* project;
|
||||
TreeView tree;
|
||||
std::unique_ptr<JucerTreeViewBase> rootItem;
|
||||
|
||||
private:
|
||||
String opennessStateKey, emptyTreeMessage;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class TreeItemComponent : public Component
|
||||
{
|
||||
public:
|
||||
TreeItemComponent (JucerTreeViewBase& i) : item (&i)
|
||||
{
|
||||
setAccessible (false);
|
||||
setInterceptsMouseClicks (false, true);
|
||||
item->textX = iconWidth;
|
||||
}
|
||||
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
if (item == nullptr)
|
||||
return;
|
||||
|
||||
auto bounds = getLocalBounds().toFloat();
|
||||
auto iconBounds = bounds.removeFromLeft ((float) iconWidth).reduced (7, 5);
|
||||
|
||||
bounds.removeFromRight ((float) buttons.size() * bounds.getHeight());
|
||||
|
||||
item->paintIcon (g, iconBounds);
|
||||
item->paintContent (g, bounds.toNearestInt());
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
auto r = getLocalBounds();
|
||||
|
||||
for (int i = buttons.size(); --i >= 0;)
|
||||
buttons.getUnchecked (i)->setBounds (r.removeFromRight (r.getHeight()));
|
||||
}
|
||||
|
||||
void addRightHandButton (Component* button)
|
||||
{
|
||||
buttons.add (button);
|
||||
addAndMakeVisible (button);
|
||||
}
|
||||
|
||||
WeakReference<JucerTreeViewBase> item;
|
||||
OwnedArray<Component> buttons;
|
||||
|
||||
const int iconWidth = 25;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TreeItemComponent)
|
||||
};
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,100 +1,100 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class ProjucerLookAndFeel : public LookAndFeel_V4
|
||||
{
|
||||
public:
|
||||
ProjucerLookAndFeel();
|
||||
~ProjucerLookAndFeel() override;
|
||||
|
||||
void drawTabButton (TabBarButton& button, Graphics&, bool isMouseOver, bool isMouseDown) override;
|
||||
int getTabButtonBestWidth (TabBarButton&, int tabDepth) override;
|
||||
void drawTabAreaBehindFrontButton (TabbedButtonBar&, Graphics&, int, int) override {}
|
||||
|
||||
void drawPropertyComponentBackground (Graphics&, int, int, PropertyComponent&) override {}
|
||||
void drawPropertyComponentLabel (Graphics&, int width, int height, PropertyComponent&) override;
|
||||
Rectangle<int> getPropertyComponentContentPosition (PropertyComponent&) override;
|
||||
|
||||
void drawButtonBackground (Graphics&, Button&, const Colour& backgroundColour,
|
||||
bool isMouseOverButton, bool isButtonDown) override;
|
||||
void drawButtonText (Graphics&, TextButton&, bool isMouseOverButton, bool isButtonDown) override;
|
||||
void drawToggleButton (Graphics&, ToggleButton&, bool isMouseOverButton, bool isButtonDown) override;
|
||||
|
||||
void drawTextEditorOutline (Graphics&, int, int, TextEditor&) override {}
|
||||
void fillTextEditorBackground (Graphics&, int width, int height, TextEditor&) override;
|
||||
|
||||
void layoutFileBrowserComponent (FileBrowserComponent&, DirectoryContentsDisplayComponent*,
|
||||
FilePreviewComponent*, ComboBox* currentPathBox,
|
||||
TextEditor* filenameBox,Button* goUpButton) override;
|
||||
void drawFileBrowserRow (Graphics&, int width, int height, const File&, const String& filename, Image* icon,
|
||||
const String& fileSizeDescription, const String& fileTimeDescription,
|
||||
bool isDirectory, bool isItemSelected, int itemIndex, DirectoryContentsDisplayComponent&) override;
|
||||
|
||||
void drawCallOutBoxBackground (CallOutBox&, Graphics&, const Path&, Image&) override;
|
||||
|
||||
void drawMenuBarBackground (Graphics&, int width, int height, bool isMouseOverBar, MenuBarComponent&) override;
|
||||
|
||||
void drawMenuBarItem (Graphics&, int width, int height,
|
||||
int itemIndex, const String& itemText,
|
||||
bool isMouseOverItem, bool isMenuOpen, bool isMouseOverBar,
|
||||
MenuBarComponent&) override;
|
||||
|
||||
void drawResizableFrame (Graphics&, int w, int h, const BorderSize<int>&) override;
|
||||
|
||||
void drawComboBox (Graphics&, int width, int height, bool isButtonDown,
|
||||
int buttonX, int buttonY, int buttonW, int buttonH,
|
||||
ComboBox&) override;
|
||||
|
||||
void drawTreeviewPlusMinusBox (Graphics&, const Rectangle<float>& area,
|
||||
Colour backgroundColour, bool isItemOpen, bool isMouseOver) override;
|
||||
|
||||
void drawProgressBar (Graphics&, ProgressBar&, int width, int height, double progress, const String& textToShow) override;
|
||||
|
||||
//==============================================================================
|
||||
static Path getArrowPath (Rectangle<float> arrowZone, const int direction,
|
||||
const bool filled, const Justification justification);
|
||||
static Path getChoiceComponentArrowPath (Rectangle<float> arrowZone);
|
||||
|
||||
static Font getPropertyComponentFont() { return { 14.0f, Font::FontStyleFlags::bold }; }
|
||||
static int getTextWidthForPropertyComponent (PropertyComponent* pp) { return jmin (200, pp->getWidth() / 2); }
|
||||
|
||||
static ColourScheme getProjucerDarkColourScheme()
|
||||
{
|
||||
return { 0xff323e44, 0xff263238, 0xff323e44,
|
||||
0xff8e989b, 0xffffffff, 0xffa45c94,
|
||||
0xffffffff, 0xff181f22, 0xffffffff };
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void setupColours();
|
||||
|
||||
private:
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ProjucerLookAndFeel)
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class ProjucerLookAndFeel : public LookAndFeel_V4
|
||||
{
|
||||
public:
|
||||
ProjucerLookAndFeel();
|
||||
~ProjucerLookAndFeel() override;
|
||||
|
||||
void drawTabButton (TabBarButton& button, Graphics&, bool isMouseOver, bool isMouseDown) override;
|
||||
int getTabButtonBestWidth (TabBarButton&, int tabDepth) override;
|
||||
void drawTabAreaBehindFrontButton (TabbedButtonBar&, Graphics&, int, int) override {}
|
||||
|
||||
void drawPropertyComponentBackground (Graphics&, int, int, PropertyComponent&) override {}
|
||||
void drawPropertyComponentLabel (Graphics&, int width, int height, PropertyComponent&) override;
|
||||
Rectangle<int> getPropertyComponentContentPosition (PropertyComponent&) override;
|
||||
|
||||
void drawButtonBackground (Graphics&, Button&, const Colour& backgroundColour,
|
||||
bool isMouseOverButton, bool isButtonDown) override;
|
||||
void drawButtonText (Graphics&, TextButton&, bool isMouseOverButton, bool isButtonDown) override;
|
||||
void drawToggleButton (Graphics&, ToggleButton&, bool isMouseOverButton, bool isButtonDown) override;
|
||||
|
||||
void drawTextEditorOutline (Graphics&, int, int, TextEditor&) override {}
|
||||
void fillTextEditorBackground (Graphics&, int width, int height, TextEditor&) override;
|
||||
|
||||
void layoutFileBrowserComponent (FileBrowserComponent&, DirectoryContentsDisplayComponent*,
|
||||
FilePreviewComponent*, ComboBox* currentPathBox,
|
||||
TextEditor* filenameBox,Button* goUpButton) override;
|
||||
void drawFileBrowserRow (Graphics&, int width, int height, const File&, const String& filename, Image* icon,
|
||||
const String& fileSizeDescription, const String& fileTimeDescription,
|
||||
bool isDirectory, bool isItemSelected, int itemIndex, DirectoryContentsDisplayComponent&) override;
|
||||
|
||||
void drawCallOutBoxBackground (CallOutBox&, Graphics&, const Path&, Image&) override;
|
||||
|
||||
void drawMenuBarBackground (Graphics&, int width, int height, bool isMouseOverBar, MenuBarComponent&) override;
|
||||
|
||||
void drawMenuBarItem (Graphics&, int width, int height,
|
||||
int itemIndex, const String& itemText,
|
||||
bool isMouseOverItem, bool isMenuOpen, bool isMouseOverBar,
|
||||
MenuBarComponent&) override;
|
||||
|
||||
void drawResizableFrame (Graphics&, int w, int h, const BorderSize<int>&) override;
|
||||
|
||||
void drawComboBox (Graphics&, int width, int height, bool isButtonDown,
|
||||
int buttonX, int buttonY, int buttonW, int buttonH,
|
||||
ComboBox&) override;
|
||||
|
||||
void drawTreeviewPlusMinusBox (Graphics&, const Rectangle<float>& area,
|
||||
Colour backgroundColour, bool isItemOpen, bool isMouseOver) override;
|
||||
|
||||
void drawProgressBar (Graphics&, ProgressBar&, int width, int height, double progress, const String& textToShow) override;
|
||||
|
||||
//==============================================================================
|
||||
static Path getArrowPath (Rectangle<float> arrowZone, const int direction,
|
||||
const bool filled, const Justification justification);
|
||||
static Path getChoiceComponentArrowPath (Rectangle<float> arrowZone);
|
||||
|
||||
static Font getPropertyComponentFont() { return { 14.0f, Font::FontStyleFlags::bold }; }
|
||||
static int getTextWidthForPropertyComponent (const PropertyComponent& pc) { return jmin (200, pc.getWidth() / 2); }
|
||||
|
||||
static ColourScheme getProjucerDarkColourScheme()
|
||||
{
|
||||
return { 0xff323e44, 0xff263238, 0xff323e44,
|
||||
0xff8e989b, 0xffffffff, 0xffa45c94,
|
||||
0xffffffff, 0xff181f22, 0xffffffff };
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void setupColours();
|
||||
|
||||
private:
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ProjucerLookAndFeel)
|
||||
};
|
||||
|
@ -1,118 +1,118 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "../../Application/jucer_Headers.h"
|
||||
#include "jucer_SlidingPanelComponent.h"
|
||||
|
||||
//==============================================================================
|
||||
struct SlidingPanelComponent::DotButton : public Button
|
||||
{
|
||||
DotButton (SlidingPanelComponent& sp, int pageIndex)
|
||||
: Button (String()), owner (sp), index (pageIndex) {}
|
||||
|
||||
void paintButton (Graphics& g, bool /*isMouseOverButton*/, bool /*isButtonDown*/) override
|
||||
{
|
||||
g.setColour (findColour (defaultButtonBackgroundColourId));
|
||||
const auto r = getLocalBounds().reduced (getWidth() / 4).toFloat();
|
||||
|
||||
if (index == owner.getCurrentTabIndex())
|
||||
g.fillEllipse (r);
|
||||
else
|
||||
g.drawEllipse (r, 1.0f);
|
||||
}
|
||||
|
||||
void clicked() override
|
||||
{
|
||||
owner.goToTab (index);
|
||||
}
|
||||
|
||||
using Button::clicked;
|
||||
|
||||
SlidingPanelComponent& owner;
|
||||
int index;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
SlidingPanelComponent::SlidingPanelComponent()
|
||||
: currentIndex (0), dotSize (20)
|
||||
{
|
||||
addAndMakeVisible (pageHolder);
|
||||
}
|
||||
|
||||
SlidingPanelComponent::~SlidingPanelComponent()
|
||||
{
|
||||
}
|
||||
|
||||
SlidingPanelComponent::PageInfo::~PageInfo()
|
||||
{
|
||||
if (shouldDelete)
|
||||
content.deleteAndZero();
|
||||
}
|
||||
|
||||
void SlidingPanelComponent::addTab (const String& tabName,
|
||||
Component* const contentComponent,
|
||||
const bool deleteComponentWhenNotNeeded,
|
||||
const int insertIndex)
|
||||
{
|
||||
PageInfo* page = new PageInfo();
|
||||
pages.insert (insertIndex, page);
|
||||
page->content = contentComponent;
|
||||
page->dotButton.reset (new DotButton (*this, pages.indexOf (page)));
|
||||
addAndMakeVisible (page->dotButton.get());
|
||||
page->name = tabName;
|
||||
page->shouldDelete = deleteComponentWhenNotNeeded;
|
||||
|
||||
pageHolder.addAndMakeVisible (contentComponent);
|
||||
resized();
|
||||
}
|
||||
|
||||
void SlidingPanelComponent::goToTab (int targetTabIndex)
|
||||
{
|
||||
currentIndex = targetTabIndex;
|
||||
|
||||
Desktop::getInstance().getAnimator()
|
||||
.animateComponent (&pageHolder, pageHolder.getBounds().withX (-targetTabIndex * getWidth()),
|
||||
1.0f, 600, false, 0.0, 0.0);
|
||||
|
||||
repaint();
|
||||
}
|
||||
|
||||
void SlidingPanelComponent::resized()
|
||||
{
|
||||
pageHolder.setBounds (-currentIndex * getWidth(), pageHolder.getPosition().y,
|
||||
getNumTabs() * getWidth(), getHeight());
|
||||
|
||||
Rectangle<int> content (getLocalBounds());
|
||||
|
||||
Rectangle<int> dotHolder = content.removeFromBottom (20 + dotSize)
|
||||
.reduced ((content.getWidth() - dotSize * getNumTabs()) / 2, 10);
|
||||
|
||||
for (int i = 0; i < getNumTabs(); ++i)
|
||||
pages.getUnchecked(i)->dotButton->setBounds (dotHolder.removeFromLeft (dotSize));
|
||||
|
||||
for (int i = pages.size(); --i >= 0;)
|
||||
if (Component* c = pages.getUnchecked(i)->content)
|
||||
c->setBounds (content.translated (i * content.getWidth(), 0));
|
||||
}
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "../../Application/jucer_Headers.h"
|
||||
#include "jucer_SlidingPanelComponent.h"
|
||||
|
||||
//==============================================================================
|
||||
struct SlidingPanelComponent::DotButton : public Button
|
||||
{
|
||||
DotButton (SlidingPanelComponent& sp, int pageIndex)
|
||||
: Button (String()), owner (sp), index (pageIndex) {}
|
||||
|
||||
void paintButton (Graphics& g, bool /*isMouseOverButton*/, bool /*isButtonDown*/) override
|
||||
{
|
||||
g.setColour (findColour (defaultButtonBackgroundColourId));
|
||||
const auto r = getLocalBounds().reduced (getWidth() / 4).toFloat();
|
||||
|
||||
if (index == owner.getCurrentTabIndex())
|
||||
g.fillEllipse (r);
|
||||
else
|
||||
g.drawEllipse (r, 1.0f);
|
||||
}
|
||||
|
||||
void clicked() override
|
||||
{
|
||||
owner.goToTab (index);
|
||||
}
|
||||
|
||||
using Button::clicked;
|
||||
|
||||
SlidingPanelComponent& owner;
|
||||
int index;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
SlidingPanelComponent::SlidingPanelComponent()
|
||||
: currentIndex (0), dotSize (20)
|
||||
{
|
||||
addAndMakeVisible (pageHolder);
|
||||
}
|
||||
|
||||
SlidingPanelComponent::~SlidingPanelComponent()
|
||||
{
|
||||
}
|
||||
|
||||
SlidingPanelComponent::PageInfo::~PageInfo()
|
||||
{
|
||||
if (shouldDelete)
|
||||
content.deleteAndZero();
|
||||
}
|
||||
|
||||
void SlidingPanelComponent::addTab (const String& tabName,
|
||||
Component* const contentComponent,
|
||||
const bool deleteComponentWhenNotNeeded,
|
||||
const int insertIndex)
|
||||
{
|
||||
PageInfo* page = new PageInfo();
|
||||
pages.insert (insertIndex, page);
|
||||
page->content = contentComponent;
|
||||
page->dotButton.reset (new DotButton (*this, pages.indexOf (page)));
|
||||
addAndMakeVisible (page->dotButton.get());
|
||||
page->name = tabName;
|
||||
page->shouldDelete = deleteComponentWhenNotNeeded;
|
||||
|
||||
pageHolder.addAndMakeVisible (contentComponent);
|
||||
resized();
|
||||
}
|
||||
|
||||
void SlidingPanelComponent::goToTab (int targetTabIndex)
|
||||
{
|
||||
currentIndex = targetTabIndex;
|
||||
|
||||
Desktop::getInstance().getAnimator()
|
||||
.animateComponent (&pageHolder, pageHolder.getBounds().withX (-targetTabIndex * getWidth()),
|
||||
1.0f, 600, false, 0.0, 0.0);
|
||||
|
||||
repaint();
|
||||
}
|
||||
|
||||
void SlidingPanelComponent::resized()
|
||||
{
|
||||
pageHolder.setBounds (-currentIndex * getWidth(), pageHolder.getPosition().y,
|
||||
getNumTabs() * getWidth(), getHeight());
|
||||
|
||||
Rectangle<int> content (getLocalBounds());
|
||||
|
||||
Rectangle<int> dotHolder = content.removeFromBottom (20 + dotSize)
|
||||
.reduced ((content.getWidth() - dotSize * getNumTabs()) / 2, 10);
|
||||
|
||||
for (int i = 0; i < getNumTabs(); ++i)
|
||||
pages.getUnchecked(i)->dotButton->setBounds (dotHolder.removeFromLeft (dotSize));
|
||||
|
||||
for (int i = pages.size(); --i >= 0;)
|
||||
if (Component* c = pages.getUnchecked(i)->content)
|
||||
c->setBounds (content.translated (i * content.getWidth(), 0));
|
||||
}
|
||||
|
@ -1,79 +1,79 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../Application/jucer_Application.h"
|
||||
|
||||
//==============================================================================
|
||||
class SlidingPanelComponent : public Component
|
||||
{
|
||||
public:
|
||||
SlidingPanelComponent();
|
||||
~SlidingPanelComponent() override;
|
||||
|
||||
/** Adds a new tab to the panel slider. */
|
||||
void addTab (const String& tabName,
|
||||
Component* contentComponent,
|
||||
bool deleteComponentWhenNotNeeded,
|
||||
int insertIndex = -1);
|
||||
|
||||
/** Gets rid of one of the tabs. */
|
||||
void removeTab (int tabIndex);
|
||||
|
||||
/** Gets index of current tab. */
|
||||
int getCurrentTabIndex() const noexcept { return currentIndex; }
|
||||
|
||||
/** Returns the number of tabs. */
|
||||
int getNumTabs() const noexcept { return pages.size(); }
|
||||
|
||||
/** Animates the window to the desired tab. */
|
||||
void goToTab (int targetTabIndex);
|
||||
|
||||
//==============================================================================
|
||||
/** @internal */
|
||||
void resized() override;
|
||||
|
||||
private:
|
||||
struct DotButton;
|
||||
friend struct DotButton;
|
||||
|
||||
struct PageInfo
|
||||
{
|
||||
~PageInfo();
|
||||
|
||||
Component::SafePointer<Component> content;
|
||||
std::unique_ptr<DotButton> dotButton;
|
||||
String name;
|
||||
bool shouldDelete;
|
||||
};
|
||||
|
||||
OwnedArray<PageInfo> pages;
|
||||
|
||||
Component pageHolder;
|
||||
int currentIndex, dotSize;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SlidingPanelComponent)
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../Application/jucer_Application.h"
|
||||
|
||||
//==============================================================================
|
||||
class SlidingPanelComponent : public Component
|
||||
{
|
||||
public:
|
||||
SlidingPanelComponent();
|
||||
~SlidingPanelComponent() override;
|
||||
|
||||
/** Adds a new tab to the panel slider. */
|
||||
void addTab (const String& tabName,
|
||||
Component* contentComponent,
|
||||
bool deleteComponentWhenNotNeeded,
|
||||
int insertIndex = -1);
|
||||
|
||||
/** Gets rid of one of the tabs. */
|
||||
void removeTab (int tabIndex);
|
||||
|
||||
/** Gets index of current tab. */
|
||||
int getCurrentTabIndex() const noexcept { return currentIndex; }
|
||||
|
||||
/** Returns the number of tabs. */
|
||||
int getNumTabs() const noexcept { return pages.size(); }
|
||||
|
||||
/** Animates the window to the desired tab. */
|
||||
void goToTab (int targetTabIndex);
|
||||
|
||||
//==============================================================================
|
||||
/** @internal */
|
||||
void resized() override;
|
||||
|
||||
private:
|
||||
struct DotButton;
|
||||
friend struct DotButton;
|
||||
|
||||
struct PageInfo
|
||||
{
|
||||
~PageInfo();
|
||||
|
||||
Component::SafePointer<Component> content;
|
||||
std::unique_ptr<DotButton> dotButton;
|
||||
String name;
|
||||
bool shouldDelete;
|
||||
};
|
||||
|
||||
OwnedArray<PageInfo> pages;
|
||||
|
||||
Component pageHolder;
|
||||
int currentIndex, dotSize;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SlidingPanelComponent)
|
||||
};
|
||||
|
Reference in New Issue
Block a user