Add effect icons and overhaul draggable list box

pull/307/head
James H Ball 2025-08-10 16:28:22 +01:00
rodzic 559151d8d6
commit bdf46f55f1
24 zmienionych plików z 285 dodań i 38 usunięć

Wyświetl plik

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M18 10V8H20V10H18M18 12V10H16V12H18M18 8V6H16V8H18M16 2.84V4H18C17.37 3.54 16.71 3.15 16 2.84M18 4V6H20C19.42 5.25 18.75 4.58 18 4M20 6V8H21.16C20.85 7.29 20.46 6.63 20 6M22 12C22 11.32 21.93 10.65 21.8 10H20V12H22M16 6V4H14V6H16M16 16H18V14H16V16M18 18H20L20 18V16H18V18M16 20H18L18 20V18H16V20M14 21.8C14.7 21.66 15.36 21.44 16 21.16V20H14V21.8M18 14H20V12H18V14M16 8H14V10H16V8M20 16H21.16C21.44 15.36 21.66 14.7 21.8 14H20V16M16 12H14V14H16V12M12 18V16H14V14H12V12H14V10H12V8H14V6H12V4H14V2.2C13.35 2.07 12.69 2 12 2C6.5 2 2 6.5 2 12S6.5 22 12 22V20H14V18H12M14 18H16V16H14V18Z" /></svg>

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 660 B

Wyświetl plik

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M16,4L20,8V4M20,16L16,20H20M8,20L4,16V20M4,8L8,4H4M16.95,7.05C14.22,4.32 9.78,4.32 7.05,7.05C4.32,9.78 4.32,14.22 7.05,16.95C9.78,19.68 14.22,19.68 16.95,16.95C19.68,14.22 19.68,9.79 16.95,7.05M15.85,15.85C13.72,18 10.28,18 8.15,15.85C6,13.72 6,10.28 8.15,8.15C10.28,6 13.72,6 15.85,8.15C18,10.28 18,13.72 15.85,15.85Z" /></svg>

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 397 B

Wyświetl plik

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M2,4C2,2.89 2.9,2 4,2H7V4H4V7H2V4M22,4V7H20V4H17V2H20A2,2 0 0,1 22,4M20,20V17H22V20C22,21.11 21.1,22 20,22H17V20H20M2,20V17H4V20H7V22H4A2,2 0 0,1 2,20M10,2H14V4H10V2M10,20H14V22H10V20M20,10H22V14H20V10M2,10H4V14H2V10Z" /></svg>

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 296 B

Wyświetl plik

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M6,13H18V11H6M3,6V8H21V6M10,18H14V16H10V18Z" /></svg>

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 122 B

Wyświetl plik

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M8.5 4.5L5.4 9.5L8.5 14.7L5.2 20.5L3.4 19.6L6.1 14.7L3 9.5L6.7 3.6L8.5 4.5M14.7 4.4L11.6 9.5L14.7 14.5L11.4 20.3L9.6 19.4L12.3 14.5L9.2 9.5L12.9 3.5L14.7 4.4M21 4.4L17.9 9.5L21 14.5L17.7 20.3L15.9 19.4L18.6 14.5L15.5 9.5L19.2 3.5L21 4.4" /></svg>

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 315 B

Wyświetl plik

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M10.5,5A8.5,8.5 0 0,0 2,13.5A8.5,8.5 0 0,0 10.5,22A8.5,8.5 0 0,0 19,13.5A8.5,8.5 0 0,0 10.5,5M13.5,13A2.5,2.5 0 0,1 11,10.5A2.5,2.5 0 0,1 13.5,8A2.5,2.5 0 0,1 16,10.5A2.5,2.5 0 0,1 13.5,13M19.5,2A2.5,2.5 0 0,0 17,4.5A2.5,2.5 0 0,0 19.5,7A2.5,2.5 0 0,0 22,4.5A2.5,2.5 0 0,0 19.5,2" /></svg>

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 358 B

Wyświetl plik

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 16C13.1 16 14 16.9 14 18S13.1 20 12 20 10 19.1 10 18 10.9 16 12 16M12 10C13.1 10 14 10.9 14 12S13.1 14 12 14 10 13.1 10 12 10.9 10 12 10M12 4C13.1 4 14 4.9 14 6S13.1 8 12 8 10 7.1 10 6 10.9 4 12 4M6 16C7.1 16 8 16.9 8 18S7.1 20 6 20 4 19.1 4 18 4.9 16 6 16M6 10C7.1 10 8 10.9 8 12S7.1 14 6 14 4 13.1 4 12 4.9 10 6 10M6 4C7.1 4 8 4.9 8 6S7.1 8 6 8 4 7.1 4 6 4.9 4 6 4M18 16C19.1 16 20 16.9 20 18S19.1 20 18 20 16 19.1 16 18 16.9 16 18 16M18 10C19.1 10 20 10.9 20 12S19.1 14 18 14 16 13.1 16 12 16.9 10 18 10M18 4C19.1 4 20 4.9 20 6S19.1 8 18 8 16 7.1 16 6 16.9 4 18 4Z" /></svg>

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 650 B

Wyświetl plik

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12,6A11,11 0 0,0 1,17H3C3,12.04 7.04,8 12,8C16.96,8 21,12.04 21,17H23A11,11 0 0,0 12,6M12,10C8.14,10 5,13.14 5,17H7A5,5 0 0,1 12,12A5,5 0 0,1 17,17H19C19,13.14 15.86,10 12,10Z" /></svg>

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 255 B

Wyświetl plik

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12,2L16,6H13V13.85L19.53,17.61L21,15.03L22.5,20.5L17,21.96L18.53,19.35L12,15.58L5.47,19.35L7,21.96L1.5,20.5L3,15.03L4.47,17.61L11,13.85V6H8L12,2Z" /></svg>

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 225 B

Wyświetl plik

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M8 3H16C18.76 3 21 5.24 21 8V16C21 18.76 18.76 21 16 21H8C5.24 21 3 18.76 3 16V8C3 5.24 5.24 3 8 3M8 5C6.34 5 5 6.34 5 8V16C5 17.66 6.34 19 8 19H16C17.66 19 19 17.66 19 16V8C19 6.34 17.66 5 16 5H8Z" /></svg>

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 276 B

Wyświetl plik

@ -0,0 +1,7 @@
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" id="Laravelnova--Streamline-Simple-Icons" height="24" width="24">
<desc>
Laravelnova Streamline Icon: https://streamlinehq.com
</desc>
<title>Laravel Nova</title>
<path d="M21.333 4.319C16.56 0.386 9.453 0.632 4.973 5.057a7.571 7.571 0 0 0 0 10.8c3.018 2.982 7.912 2.982 10.931 0a3.245 3.245 0 0 0 0 -4.628 3.342 3.342 0 0 0 -4.685 0 1.114 1.114 0 0 1 -1.561 0 1.082 1.082 0 0 1 0 -1.543 5.57 5.57 0 0 1 7.808 0 5.408 5.408 0 0 1 0 7.714c-3.881 3.834 -10.174 3.834 -14.055 0a9.734 9.734 0 0 1 -0.015 -13.87C5.596 1.35 8.638 0 12 0c3.75 0 7.105 1.68 9.333 4.319zm-0.714 16.136A12.184 12.184 0 0 1 12 24a12.18 12.18 0 0 1 -9.333 -4.319c4.772 3.933 11.88 3.687 16.36 -0.738a7.571 7.571 0 0 0 0 -10.8c-3.018 -2.982 -7.912 -2.982 -10.931 0a3.245 3.245 0 0 0 0 4.628 3.342 3.342 0 0 0 4.685 0 1.114 1.114 0 0 1 1.561 0 1.082 1.082 0 0 1 0 1.543 5.57 5.57 0 0 1 -7.808 0 5.408 5.408 0 0 1 0 -7.714c3.881 -3.834 10.174 -3.834 14.055 0a9.734 9.734 0 0 1 0.03 13.855z" fill="#000000" stroke-width="1"></path>
</svg>

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 1.1 KiB

Wyświetl plik

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.75 20.85C11.53 20.15 11.14 18.22 10.24 17C9.35 15.75 8.12 14.89 6.88 14.06C6 13.5 5.19 12.8 4.54 12C4.26 11.67 3.69 11.06 4.27 10.94C4.86 10.82 5.88 11.4 6.4 11.62C7.31 12 8.21 12.44 9.05 12.96L10.06 11.26C8.5 10.23 6.5 9.32 4.64 9.05C3.58 8.89 2.46 9.11 2.1 10.26C1.78 11.25 2.29 12.25 2.87 13.03C4.24 14.86 6.37 15.74 7.96 17.32C8.3 17.65 8.71 18.04 8.91 18.5C9.12 18.94 9.07 18.97 8.6 18.97C7.36 18.97 5.81 18 4.8 17.36L3.79 19.06C5.32 20 7.88 21.47 9.75 20.85M20.84 5.25C21.06 5.03 21.06 4.67 20.84 4.46L19.54 3.16C19.33 2.95 18.97 2.95 18.76 3.16L17.74 4.18L19.82 6.26M11 10.92V13H13.08L19.23 6.85L17.15 4.77L11 10.92Z" /></svg>

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 705 B

Wyświetl plik

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M6.45,17.45L1,12L6.45,6.55L7.86,7.96L4.83,11H19.17L16.14,7.96L17.55,6.55L23,12L17.55,17.45L16.14,16.04L19.17,13H4.83L7.86,16.04L6.45,17.45Z" /></svg>

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 218 B

Wyświetl plik

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M6 14H9L5 18L1 14H4C4 11.3 5.7 6.6 11 6.1V8.1C7.6 8.6 6 11.9 6 14M20 14C20 11.3 18.3 6.6 13 6.1V8.1C16.4 8.7 18 11.9 18 14H15L19 18L23 14H20Z" /></svg>

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 220 B

Wyświetl plik

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M16.5,21C13.5,21 12.31,16.76 11.05,12.28C10.14,9.04 9,5 7.5,5C4.11,5 4,11.93 4,12H2C2,11.63 2.06,3 7.5,3C10.5,3 11.71,7.25 12.97,11.74C13.83,14.8 15,19 16.5,19C19.94,19 20.03,12.07 20.03,12H22.03C22.03,12.37 21.97,21 16.5,21Z" /></svg>

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 304 B

Wyświetl plik

@ -60,7 +60,7 @@ CommonPluginEditor::CommonPluginEditor(CommonAudioProcessor& p, juce::String app
setResizeLimits(250, 250, 999999, 999999); setResizeLimits(250, 250, 999999, 999999);
tooltipDropShadow.setOwner(&tooltipWindow.get()); tooltipDropShadow.setOwner(&tooltipWindow.get());
tooltipWindow->setMillisecondsBeforeTipAppears(0); tooltipWindow->setMillisecondsBeforeTipAppears(100);
updateTitle(); updateTitle();

Wyświetl plik

@ -32,7 +32,7 @@ EffectPluginEditor::EffectPluginEditor(EffectAudioProcessor& p)
setResizable(false, false); setResizable(false, false);
tooltipDropShadow.setOwner(&tooltipWindow.get()); tooltipDropShadow.setOwner(&tooltipWindow.get());
tooltipWindow->setMillisecondsBeforeTipAppears(0); tooltipWindow->setMillisecondsBeforeTipAppears(100);
audioProcessor.bitCrush->addListener(0, this); audioProcessor.bitCrush->addListener(0, this);
} }

Wyświetl plik

@ -93,6 +93,12 @@ EffectsComponent::EffectsComponent(OscirenderAudioProcessor& p, OscirenderAudioP
listBox.setModel(&listBoxModel); listBox.setModel(&listBoxModel);
addAndMakeVisible(listBox); addAndMakeVisible(listBox);
// Add a small top spacer so the drop indicator can be visible above the first row
{
auto spacer = std::make_unique<juce::Component>();
spacer->setSize(1, LIST_SPACER); // top padding
listBox.setHeaderComponent(std::move(spacer));
}
// Setup scroll fade mixin // Setup scroll fade mixin
initScrollFade(*this); initScrollFade(*this);
attachToListBox(listBox); attachToListBox(listBox);
@ -140,10 +146,9 @@ void EffectsComponent::resized() {
auto addBtnHeight = 44; auto addBtnHeight = 44;
auto listArea = area; auto listArea = area;
auto buttonArea = listArea.removeFromBottom(addBtnHeight); auto buttonArea = listArea.removeFromBottom(addBtnHeight);
listArea.removeFromTop(6);
listBox.setBounds(listArea); listBox.setBounds(listArea);
// Layout bottom fade overlay; visible if list is scrollable // Layout bottom fade overlay; visible if list is scrollable
layoutScrollFade(listArea, true, 48); layoutScrollFade(listArea.withTrimmedTop(LIST_SPACER), true, 48);
if (addEffectButton) { if (addEffectButton) {
addEffectButton->setVisible(true); addEffectButton->setVisible(true);
addEffectButton->setBounds(buttonArea.reduced(0, 4)); addEffectButton->setBounds(buttonArea.reduced(0, 4));
@ -156,5 +161,5 @@ void EffectsComponent::changeListenerCallback(juce::ChangeBroadcaster* source) {
listBox.updateContent(); listBox.updateContent();
// Re-layout scroll fades after content changes // Re-layout scroll fades after content changes
if (! showingGrid) if (! showingGrid)
layoutScrollFade(listBox.getBounds(), true, 48); layoutScrollFade(listBox.getBounds().withTrimmedTop(LIST_SPACER), true, 48);
} }

Wyświetl plik

@ -31,6 +31,8 @@ private:
std::unique_ptr<juce::TextButton> addEffectButton; // Separate button under the list std::unique_ptr<juce::TextButton> addEffectButton; // Separate button under the list
std::unique_ptr<EffectTypeGridComponent> grid; std::unique_ptr<EffectTypeGridComponent> grid;
bool showingGrid = true; // show grid by default bool showingGrid = true; // show grid by default
const int LIST_SPACER = 4; // Space above the list to show drop indicator
EffectComponent frequency = EffectComponent(*audioProcessor.frequencyEffect, false); EffectComponent frequency = EffectComponent(*audioProcessor.frequencyEffect, false);

Wyświetl plik

@ -26,12 +26,17 @@
OscirenderAudioProcessor::OscirenderAudioProcessor() : CommonAudioProcessor(BusesProperties().withInput("Input", juce::AudioChannelSet::namedChannelSet(2), true).withOutput("Output", juce::AudioChannelSet::stereo(), true)) { OscirenderAudioProcessor::OscirenderAudioProcessor() : CommonAudioProcessor(BusesProperties().withInput("Input", juce::AudioChannelSet::namedChannelSet(2), true).withOutput("Output", juce::AudioChannelSet::stereo(), true)) {
// locking isn't necessary here because we are in the constructor // locking isn't necessary here because we are in the constructor
toggleableEffects.push_back(std::make_shared<osci::Effect>( auto bitCrushEffect = std::make_shared<osci::Effect>(
std::make_shared<BitCrushEffect>(), std::make_shared<BitCrushEffect>(),
new osci::EffectParameter("Bit Crush", "Limits the resolution of points drawn to the screen, making the object look pixelated, and making the audio sound more 'digital' and distorted.", "bitCrush", VERSION_HINT, 0.6, 0.0, 1.0))); new osci::EffectParameter("Bit Crush", "Limits the resolution of points drawn to the screen, making the object look pixelated, and making the audio sound more 'digital' and distorted.", "bitCrush", VERSION_HINT, 0.6, 0.0, 1.0));
toggleableEffects.push_back(std::make_shared<osci::Effect>( bitCrushEffect->setIcon(BinaryData::bitcrush_svg);
toggleableEffects.push_back(bitCrushEffect);
auto bulgeEffect = std::make_shared<osci::Effect>(
std::make_shared<BulgeEffect>(), std::make_shared<BulgeEffect>(),
new osci::EffectParameter("Bulge", "Applies a bulge that makes the centre of the image larger, and squishes the edges of the image. This applies a distortion to the audio.", "bulge", VERSION_HINT, 0.5, 0.0, 1.0))); new osci::EffectParameter("Bulge", "Applies a bulge that makes the centre of the image larger, and squishes the edges of the image. This applies a distortion to the audio.", "bulge", VERSION_HINT, 0.5, 0.0, 1.0));
bulgeEffect->setIcon(BinaryData::bulge_svg);
toggleableEffects.push_back(bulgeEffect);
auto multiplexEffect = std::make_shared<osci::Effect>( auto multiplexEffect = std::make_shared<osci::Effect>(
std::make_shared<MultiplexEffect>(), std::make_shared<MultiplexEffect>(),
std::vector<osci::EffectParameter*>{ std::vector<osci::EffectParameter*>{
@ -43,23 +48,26 @@ OscirenderAudioProcessor::OscirenderAudioProcessor() : CommonAudioProcessor(Buse
new osci::EffectParameter("Multiplex Delay", "Controls the delay of the audio samples used in the multiplex effect.", "gridDelay", VERSION_HINT, 0.0, 0.0, 1.0), new osci::EffectParameter("Multiplex Delay", "Controls the delay of the audio samples used in the multiplex effect.", "gridDelay", VERSION_HINT, 0.0, 0.0, 1.0),
}); });
multiplexEffect->setName("Multiplex"); multiplexEffect->setName("Multiplex");
// Set up the Grid Phase parameter with sawtooth LFO at 100Hz multiplexEffect->setIcon(BinaryData::multiplex_svg);
multiplexEffect->getParameter("gridPhase")->lfo->setUnnormalisedValueNotifyingHost((int)osci::LfoType::Sawtooth); multiplexEffect->getParameter("gridPhase")->lfo->setUnnormalisedValueNotifyingHost((int)osci::LfoType::Sawtooth);
multiplexEffect->getParameter("gridPhase")->lfoRate->setUnnormalisedValueNotifyingHost(100.0); multiplexEffect->getParameter("gridPhase")->lfoRate->setUnnormalisedValueNotifyingHost(100.0);
toggleableEffects.push_back(multiplexEffect); toggleableEffects.push_back(multiplexEffect);
toggleableEffects.push_back(std::make_shared<osci::Effect>( auto vectorCancellingEffect = std::make_shared<osci::Effect>(
std::make_shared<VectorCancellingEffect>(), std::make_shared<VectorCancellingEffect>(),
new osci::EffectParameter("Vector Cancelling", "Inverts the audio and image every few samples to 'cancel out' the audio, making the audio quiet, and distorting the image.", "vectorCancelling", VERSION_HINT, 0.1111111, 0.0, 1.0))); new osci::EffectParameter("Vector Cancelling", "Inverts the audio and image every few samples to 'cancel out' the audio, making the audio quiet, and distorting the image.", "vectorCancelling", VERSION_HINT, 0.1111111, 0.0, 1.0));
vectorCancellingEffect->setIcon(BinaryData::vectorcancelling_svg);
toggleableEffects.push_back(vectorCancellingEffect);
auto scaleEffect = std::make_shared<osci::Effect>( auto scaleEffect = std::make_shared<osci::Effect>(
[this](int index, osci::Point input, const std::vector<std::atomic<double>>& values, double sampleRate) { [this](int index, osci::Point input, const std::vector<std::atomic<double>>& values, double sampleRate) {
return input * osci::Point(values[0], values[1], values[2]); return input * osci::Point(values[0], values[1], values[2]);
}, },
std::vector<osci::EffectParameter*>{ std::vector<osci::EffectParameter*>{
new osci::EffectParameter("Scale X", "Scales the object in the horizontal direction.", "scaleX", VERSION_HINT, 1.0, -3.0, 3.0), new osci::EffectParameter("Scale X", "Scales the object in the horizontal direction.", "scaleX", VERSION_HINT, 1.0, -3.0, 3.0),
new osci::EffectParameter("Scale Y", "Scales the object in the vertical direction.", "scaleY", VERSION_HINT, 1.0, -3.0, 3.0), new osci::EffectParameter("Scale Y", "Scales the object in the vertical direction.", "scaleY", VERSION_HINT, 1.0, -3.0, 3.0),
new osci::EffectParameter("Scale Z", "Scales the depth of the object.", "scaleZ", VERSION_HINT, 1.0, -3.0, 3.0), new osci::EffectParameter("Scale Z", "Scales the depth of the object.", "scaleZ", VERSION_HINT, 1.0, -3.0, 3.0),
}); });
scaleEffect->setName("Scale"); scaleEffect->setName("Scale");
scaleEffect->setIcon(BinaryData::scale_svg);
scaleEffect->markLockable(true); scaleEffect->markLockable(true);
booleanParameters.push_back(scaleEffect->linked); booleanParameters.push_back(scaleEffect->linked);
toggleableEffects.push_back(scaleEffect); toggleableEffects.push_back(scaleEffect);
@ -75,6 +83,7 @@ OscirenderAudioProcessor::OscirenderAudioProcessor() : CommonAudioProcessor(Buse
new osci::EffectParameter("Distort Z", "Distorts the depth of the image by jittering the audio sample being drawn.", "distortZ", VERSION_HINT, 0.1, 0.0, 1.0), new osci::EffectParameter("Distort Z", "Distorts the depth of the image by jittering the audio sample being drawn.", "distortZ", VERSION_HINT, 0.1, 0.0, 1.0),
}); });
distortEffect->setName("Distort"); distortEffect->setName("Distort");
distortEffect->setIcon(BinaryData::distort_svg);
distortEffect->markLockable(false); distortEffect->markLockable(false);
booleanParameters.push_back(distortEffect->linked); booleanParameters.push_back(distortEffect->linked);
toggleableEffects.push_back(distortEffect); toggleableEffects.push_back(distortEffect);
@ -91,6 +100,7 @@ OscirenderAudioProcessor::OscirenderAudioProcessor() : CommonAudioProcessor(Buse
new osci::EffectParameter("Ripple Amount", "Controls how many ripples are applied to the image.", "rippleAmount", VERSION_HINT, 0.1, 0.0, 1.0), new osci::EffectParameter("Ripple Amount", "Controls how many ripples are applied to the image.", "rippleAmount", VERSION_HINT, 0.1, 0.0, 1.0),
}); });
rippleEffect->setName("Ripple"); rippleEffect->setName("Ripple");
rippleEffect->setIcon(BinaryData::ripple_svg);
rippleEffect->getParameter("ripplePhase")->lfo->setUnnormalisedValueNotifyingHost((int)osci::LfoType::Sawtooth); rippleEffect->getParameter("ripplePhase")->lfo->setUnnormalisedValueNotifyingHost((int)osci::LfoType::Sawtooth);
toggleableEffects.push_back(rippleEffect); toggleableEffects.push_back(rippleEffect);
auto rotateEffect = std::make_shared<osci::Effect>( auto rotateEffect = std::make_shared<osci::Effect>(
@ -118,8 +128,9 @@ OscirenderAudioProcessor::OscirenderAudioProcessor() : CommonAudioProcessor(Buse
new osci::EffectParameter("Translate Z", "Moves the object away from the camera.", "translateZ", VERSION_HINT, 0.0, -1.0, 1.0), new osci::EffectParameter("Translate Z", "Moves the object away from the camera.", "translateZ", VERSION_HINT, 0.0, -1.0, 1.0),
}); });
translateEffect->setName("Translate"); translateEffect->setName("Translate");
translateEffect->setIcon(BinaryData::translate_svg);
toggleableEffects.push_back(translateEffect); toggleableEffects.push_back(translateEffect);
toggleableEffects.push_back(std::make_shared<osci::Effect>( auto swirlEffect = std::make_shared<osci::Effect>(
[this](int index, osci::Point input, const std::vector<std::atomic<double>>& values, double sampleRate) { [this](int index, osci::Point input, const std::vector<std::atomic<double>>& values, double sampleRate) {
double length = 10 * values[0] * input.magnitude(); double length = 10 * values[0] * input.magnitude();
double newX = input.x * std::cos(length) - input.y * std::sin(length); double newX = input.x * std::cos(length) - input.y * std::sin(length);
@ -128,10 +139,15 @@ OscirenderAudioProcessor::OscirenderAudioProcessor() : CommonAudioProcessor(Buse
}, },
std::vector<osci::EffectParameter*>{ std::vector<osci::EffectParameter*>{
new osci::EffectParameter("Swirl", "Swirls the image in a spiral pattern.", "swirl", VERSION_HINT, 0.3, -1.0, 1.0), new osci::EffectParameter("Swirl", "Swirls the image in a spiral pattern.", "swirl", VERSION_HINT, 0.3, -1.0, 1.0),
})); });
toggleableEffects.push_back(std::make_shared<osci::Effect>( swirlEffect->setIcon(BinaryData::swirl_svg);
toggleableEffects.push_back(swirlEffect);
auto smoothingEffect = std::make_shared<osci::Effect>(
std::make_shared<SmoothEffect>(), std::make_shared<SmoothEffect>(),
new osci::EffectParameter("Smoothing", "This works as a low-pass frequency filter that removes high frequencies, making the image look smoother, and audio sound less harsh.", "smoothing", VERSION_HINT, 0.75, 0.0, 1.0))); new osci::EffectParameter("Smoothing", "This works as a low-pass frequency filter that removes high frequencies, making the image look smoother, and audio sound less harsh.", "smoothing", VERSION_HINT, 0.75, 0.0, 1.0));
smoothingEffect->setIcon(BinaryData::smoothing_svg);
toggleableEffects.push_back(smoothingEffect);
std::shared_ptr<osci::Effect> wobble = std::make_shared<osci::Effect>( std::shared_ptr<osci::Effect> wobble = std::make_shared<osci::Effect>(
wobbleEffect, wobbleEffect,
std::vector<osci::EffectParameter*>{ std::vector<osci::EffectParameter*>{
@ -139,6 +155,7 @@ OscirenderAudioProcessor::OscirenderAudioProcessor() : CommonAudioProcessor(Buse
new osci::EffectParameter("Wobble Phase", "Controls the phase of the wobble.", "wobblePhase", VERSION_HINT, 0.0, -1.0, 1.0), new osci::EffectParameter("Wobble Phase", "Controls the phase of the wobble.", "wobblePhase", VERSION_HINT, 0.0, -1.0, 1.0),
}); });
wobble->setName("Wobble"); wobble->setName("Wobble");
wobble->setIcon(BinaryData::wobble_svg);
wobble->getParameter("wobblePhase")->lfo->setUnnormalisedValueNotifyingHost((int)osci::LfoType::Sawtooth); wobble->getParameter("wobblePhase")->lfo->setUnnormalisedValueNotifyingHost((int)osci::LfoType::Sawtooth);
toggleableEffects.push_back(wobble); toggleableEffects.push_back(wobble);
auto delay = std::make_shared<osci::Effect>( auto delay = std::make_shared<osci::Effect>(
@ -148,6 +165,7 @@ OscirenderAudioProcessor::OscirenderAudioProcessor() : CommonAudioProcessor(Buse
new osci::EffectParameter("Delay Length", "Controls the time in seconds between echos.", "delayLength", VERSION_HINT, 0.5, 0.0, 1.0) new osci::EffectParameter("Delay Length", "Controls the time in seconds between echos.", "delayLength", VERSION_HINT, 0.5, 0.0, 1.0)
}); });
delay->setName("Delay"); delay->setName("Delay");
delay->setIcon(BinaryData::delay_svg);
toggleableEffects.push_back(delay); toggleableEffects.push_back(delay);
auto dashEffect = std::make_shared<osci::Effect>( auto dashEffect = std::make_shared<osci::Effect>(
dashedLineEffect, dashedLineEffect,
@ -155,8 +173,14 @@ OscirenderAudioProcessor::OscirenderAudioProcessor() : CommonAudioProcessor(Buse
new osci::EffectParameter("Dash Length", "Controls the length of the dashed line.", "dashLength", VERSION_HINT, 0.2, 0.0, 1.0), new osci::EffectParameter("Dash Length", "Controls the length of the dashed line.", "dashLength", VERSION_HINT, 0.2, 0.0, 1.0),
}); });
dashEffect->setName("Dash"); dashEffect->setName("Dash");
dashEffect->setIcon(BinaryData::dash_svg);
toggleableEffects.push_back(dashEffect); toggleableEffects.push_back(dashEffect);
custom->setIcon(BinaryData::lua_svg);
toggleableEffects.push_back(custom); toggleableEffects.push_back(custom);
trace->setName("Trace");
trace->setIcon(BinaryData::trace_svg);
toggleableEffects.push_back(trace); toggleableEffects.push_back(trace);
trace->getParameter("traceLength")->lfo->setUnnormalisedValueNotifyingHost((int)osci::LfoType::Sawtooth); trace->getParameter("traceLength")->lfo->setUnnormalisedValueNotifyingHost((int)osci::LfoType::Sawtooth);
@ -179,6 +203,9 @@ OscirenderAudioProcessor::OscirenderAudioProcessor() : CommonAudioProcessor(Buse
for (int i = 0; i < 26; i++) { for (int i = 0; i < 26; i++) {
addLuaSlider(); addLuaSlider();
if (i < luaEffects.size()) {
luaEffects[i]->setIcon(BinaryData::lua_svg);
}
} }
effects.insert(effects.end(), toggleableEffects.begin(), toggleableEffects.end()); effects.insert(effects.end(), toggleableEffects.begin(), toggleableEffects.end());

Wyświetl plik

@ -5,16 +5,8 @@ DraggableListBoxItemData::~DraggableListBoxItemData() {};
void DraggableListBoxItem::paint(juce::Graphics& g) void DraggableListBoxItem::paint(juce::Graphics& g)
{ {
if (insertAfter) // Per-item insertion lines are suppressed in favour of a single overlay drawn by DraggableListBox.
{ juce::ignoreUnused(g);
g.setColour(juce::Colour(0xff00ff00));
g.fillRect(0, getHeight() - 4, getWidth(), 4);
}
else if (insertBefore)
{
g.setColour(juce::Colour(0xff00ff00));
g.fillRect(0, 0, getWidth(), 4);
}
} }
void DraggableListBoxItem::mouseEnter(const juce::MouseEvent&) void DraggableListBoxItem::mouseEnter(const juce::MouseEvent&)
@ -32,7 +24,10 @@ void DraggableListBoxItem::mouseDrag(const juce::MouseEvent&)
{ {
if (juce::DragAndDropContainer* container = juce::DragAndDropContainer::findParentDragContainerFor(this)) if (juce::DragAndDropContainer* container = juce::DragAndDropContainer::findParentDragContainerFor(this))
{ {
container->startDragging("DraggableListBoxItem", this); auto* obj = new juce::DynamicObject();
obj->setProperty("type", juce::var("DraggableListBoxItem"));
obj->setProperty("row", juce::var(rowNum));
container->startDragging(juce::var(obj), this);
} }
} }
@ -62,30 +57,58 @@ void DraggableListBoxItem::itemDragEnter(const SourceDetails& dragSourceDetails)
{ {
updateInsertLines(dragSourceDetails); updateInsertLines(dragSourceDetails);
updateAutoScroll(dragSourceDetails); updateAutoScroll(dragSourceDetails);
// Update the global overlay on the parent list box
auto ptGlobal = localPointToGlobal(dragSourceDetails.localPosition);
auto ptInLB = listBox.getLocalPoint(nullptr, ptGlobal);
listBox.updateDropIndicatorAt(ptInLB);
} }
void DraggableListBoxItem::itemDragMove(const SourceDetails& dragSourceDetails) void DraggableListBoxItem::itemDragMove(const SourceDetails& dragSourceDetails)
{ {
updateInsertLines(dragSourceDetails); updateInsertLines(dragSourceDetails);
updateAutoScroll(dragSourceDetails); updateAutoScroll(dragSourceDetails);
auto ptGlobal = localPointToGlobal(dragSourceDetails.localPosition);
auto ptInLB = listBox.getLocalPoint(nullptr, ptGlobal);
listBox.updateDropIndicatorAt(ptInLB);
} }
void DraggableListBoxItem::itemDragExit(const SourceDetails& /*dragSourceDetails*/) void DraggableListBoxItem::itemDragExit(const SourceDetails& /*dragSourceDetails*/)
{ {
hideInsertLines(); hideInsertLines();
stopAutoScroll(); stopAutoScroll();
listBox.clearDropIndicator();
} }
void DraggableListBoxItem::itemDropped(const juce::DragAndDropTarget::SourceDetails &dragSourceDetails) void DraggableListBoxItem::itemDropped(const juce::DragAndDropTarget::SourceDetails &dragSourceDetails)
{ {
hideInsertLines(); hideInsertLines();
stopAutoScroll(); stopAutoScroll();
listBox.clearDropIndicator();
if (DraggableListBoxItem* item = dynamic_cast<DraggableListBoxItem*>(dragSourceDetails.sourceComponent.get())) if (DraggableListBoxItem* item = dynamic_cast<DraggableListBoxItem*>(dragSourceDetails.sourceComponent.get()))
{ {
if (dragSourceDetails.localPosition.y < getHeight() / 2) if (auto* vp = listBox.getViewport())
modelData.moveBefore(item->rowNum, rowNum); {
else // Compute the global insertion index using the list box, not the item local midpoint
modelData.moveAfter(item->rowNum, rowNum); auto ptInThis = dragSourceDetails.localPosition;
auto ptGlobal = localPointToGlobal(ptInThis);
auto ptInLB = listBox.getLocalPoint(nullptr, ptGlobal);
int insertIndex = listBox.getInsertionIndexForPosition(ptInLB.x, ptInLB.y);
insertIndex = juce::jlimit(0, modelData.getNumItems(), insertIndex);
// If dragging an item that appears before the insertion point and we're moving it down,
// account for the removal shifting indices.
const int fromIndex = item->rowNum;
int toIndex = insertIndex;
if (toIndex > fromIndex) toIndex -= 1;
if (toIndex < 0) toIndex = 0;
if (toIndex >= modelData.getNumItems())
modelData.moveAfter(fromIndex, modelData.getNumItems() - 1);
else if (toIndex <= 0)
modelData.moveBefore(fromIndex, 0);
else
modelData.moveBefore(fromIndex, toIndex);
}
listBox.updateContent(); listBox.updateContent();
} }
} }
@ -164,9 +187,116 @@ void DraggableListBoxItem::timerCallback()
{ {
vp->setViewPosition(current.x, newY); vp->setViewPosition(current.x, newY);
} }
// Update the global drop indicator position based on current mouse position (even if the mouse isn't moving)
auto screenPos = juce::Desktop::getInstance().getMainMouseSource().getScreenPosition();
auto posInLB = listBox.getLocalPoint(nullptr, screenPos.toInt());
listBox.updateDropIndicatorAt(posInLB);
} }
} }
// ===================== DraggableListBox overlay indicator =====================
void DraggableListBox::updateDropIndicator(const SourceDetails& details)
{
// localPosition is already in this component's coordinate space
const auto pt = details.localPosition;
int index = getInsertionIndexForPosition(pt.x, pt.y);
if (index < 0) index = 0; // allow showing at very top (over header spacer)
dropInsertIndex = index;
showDropIndicator = true;
repaint();
}
void DraggableListBox::clearDropIndicator()
{
showDropIndicator = false;
dropInsertIndex = -1;
repaint();
}
void DraggableListBox::updateDropIndicatorAt(const juce::Point<int>& listLocalPos)
{
int index = getInsertionIndexForPosition(listLocalPos.x, listLocalPos.y);
if (index < 0) index = 0; // allow showing at very top (over header spacer)
dropInsertIndex = index;
showDropIndicator = true;
repaint();
}
void DraggableListBox::paintOverChildren(juce::Graphics& g)
{
VListBox::paintOverChildren(g);
if (!showDropIndicator) return;
const int numRows = getModel() != nullptr ? getModel()->getNumRows() : 0;
if (dropInsertIndex < 0 || dropInsertIndex > numRows) return;
auto* vp = getViewport();
if (vp == nullptr) return;
// Determine the y position between rows to draw the indicator line
int y = 0;
if (dropInsertIndex == 0)
{
// Top of first row (below header)
if (numRows > 0)
y = getRowPosition(0, true).getY();
else
y = 0;
}
else if (dropInsertIndex >= numRows)
{
auto lastRowBounds = getRowPosition(numRows - 1, true);
y = lastRowBounds.getBottom();
}
else
{
auto prevBounds = getRowPosition(dropInsertIndex - 1, true);
y = prevBounds.getBottom();
}
// Draw a prominent indicator spanning the visible row width
const int x = 0;
const int w = getVisibleRowWidth();
const int thickness = 3;
const juce::Colour colour = juce::Colours::lime.withAlpha(0.9f);
const float yOffset = -2.5f; // Offset to center the line visually
g.setColour(colour);
g.fillRoundedRectangle(x, y - thickness / 2 + yOffset, w, thickness, 2.0f);
}
void DraggableListBox::itemDropped(const SourceDetails& details)
{
// Background drop: compute insertion index and use model to move
int insertIndex = -1;
// localPosition is already relative to this list
insertIndex = getInsertionIndexForPosition(details.localPosition.x, details.localPosition.y);
if (insertIndex < 0) insertIndex = 0; // clamp to top when over header spacer
if (auto* m = dynamic_cast<DraggableListBoxModel*>(getModel()))
{
int fromIndex = -1;
const juce::var& desc = details.description;
if (desc.isObject())
{
auto* obj = desc.getDynamicObject();
if (obj != nullptr)
{
auto v = obj->getProperty("row");
if (v.isInt()) fromIndex = (int)v;
}
}
if (fromIndex >= 0 && insertIndex >= 0)
m->moveByInsertIndex(fromIndex, insertIndex);
}
clearDropIndicator();
}
juce::Component* DraggableListBoxModel::refreshComponentForRow(int rowNumber, bool isRowSelected, juce::Component *existingComponentToUpdate) juce::Component* DraggableListBoxModel::refreshComponentForRow(int rowNumber, bool isRowSelected, juce::Component *existingComponentToUpdate)
{ {
std::unique_ptr<DraggableListBoxItem> item(dynamic_cast<DraggableListBoxItem*>(existingComponentToUpdate)); std::unique_ptr<DraggableListBoxItem> item(dynamic_cast<DraggableListBoxItem*>(existingComponentToUpdate));

Wyświetl plik

@ -18,10 +18,35 @@ struct DraggableListBoxItemData
virtual void addItemAtEnd() {}; virtual void addItemAtEnd() {};
}; };
// DraggableListBox is basically just a VListBox, that inherits from DragAndDropContainer. // DraggableListBox extends VListBox to both initiate drags and act as a target, so
// Declare your list box using this type. // it can paint a clean, consistent drop indicator between row components.
class DraggableListBox : public VListBox, public juce::DragAndDropContainer class DraggableListBox : public VListBox,
public juce::DragAndDropContainer,
public juce::DragAndDropTarget
{ {
public:
using VListBox::VListBox;
// DragAndDropTarget
bool isInterestedInDragSource(const SourceDetails&) override { return true; }
void itemDragEnter(const SourceDetails& details) override { updateDropIndicator(details); }
void itemDragMove(const SourceDetails& details) override { updateDropIndicator(details); }
void itemDragExit(const SourceDetails&) override { clearDropIndicator(); }
void itemDropped(const SourceDetails& details) override;
bool shouldDrawDragImageWhenOver() override { return true; }
// Paint a global drop indicator between rows
void paintOverChildren(juce::Graphics& g) override;
// Allow children to drive indicator positioning
void updateDropIndicatorAt(const juce::Point<int>& listLocalPos);
void clearDropIndicator();
private:
void updateDropIndicator(const SourceDetails& details);
bool showDropIndicator = false;
int dropInsertIndex = -1; // index to insert before; may be getNumRows() for end
}; };
// Everything below this point should be generic. // Everything below this point should be generic.
@ -77,6 +102,27 @@ public:
juce::Component* refreshComponentForRow(int, bool, juce::Component*) override; juce::Component* refreshComponentForRow(int, bool, juce::Component*) override;
// Convenience: move an item using an insertion index (before position). Handles index shifting.
void moveByInsertIndex(int fromIndex, int insertIndex)
{
const int count = modelData.getNumItems();
if (count <= 0) return;
insertIndex = juce::jlimit(0, count, insertIndex);
int toIndex = insertIndex;
if (toIndex > fromIndex) toIndex -= 1;
if (count == 1 || fromIndex == toIndex) return;
if (toIndex <= 0)
modelData.moveBefore(fromIndex, 0);
else if (toIndex >= count)
modelData.moveAfter(fromIndex, count - 1);
else
modelData.moveBefore(fromIndex, toIndex);
listBox.updateContent();
}
protected: protected:
// Draggable model has a reference to its owner ListBox, so it can tell it to update after DnD. // Draggable model has a reference to its owner ListBox, so it can tell it to update after DnD.
DraggableListBox &listBox; DraggableListBox &listBox;

Wyświetl plik

@ -393,7 +393,7 @@ int VListBoxModel::getRowForPosition (int yPos)
return r; return r;
} }
return numRows; return numRows - 1;
} }
int VListBoxModel::getPositionForRow (int rowNumber) int VListBoxModel::getPositionForRow (int rowNumber)
@ -1067,4 +1067,4 @@ juce::String VListBoxModel::getTooltipForRow (int)
juce::MouseCursor VListBoxModel::getMouseCursorForRow (int) juce::MouseCursor VListBoxModel::getMouseCursorForRow (int)
{ {
return juce::MouseCursor::NormalCursor; return juce::MouseCursor::NormalCursor;
} }

Wyświetl plik

@ -46,16 +46,23 @@
resource="1" file="Resources/oscilloscope/vector_display_reflection.png"/> resource="1" file="Resources/oscilloscope/vector_display_reflection.png"/>
</GROUP> </GROUP>
<GROUP id="{82BCD6F1-A8BF-F30B-5587-81EE70168883}" name="svg"> <GROUP id="{82BCD6F1-A8BF-F30B-5587-81EE70168883}" name="svg">
<FILE id="laB1fX" name="bit-crush.svg" compile="0" resource="1" file="Resources/svg/bit-crush.svg"/>
<FILE id="rQlbqP" name="bulge.svg" compile="0" resource="1" file="Resources/svg/bulge.svg"/>
<FILE id="jYG5GY" name="close.svg" compile="0" resource="1" file="Resources/svg/close.svg"/> <FILE id="jYG5GY" name="close.svg" compile="0" resource="1" file="Resources/svg/close.svg"/>
<FILE id="rl17ZK" name="cog.svg" compile="0" resource="1" file="Resources/svg/cog.svg"/> <FILE id="rl17ZK" name="cog.svg" compile="0" resource="1" file="Resources/svg/cog.svg"/>
<FILE id="toeDbG" name="dash.svg" compile="0" resource="1" file="Resources/svg/dash.svg"/>
<FILE id="bH7fkX" name="delay.svg" compile="0" resource="1" file="Resources/svg/delay.svg"/>
<FILE id="sDajXu" name="delete.svg" compile="0" resource="1" file="Resources/svg/delete.svg"/> <FILE id="sDajXu" name="delete.svg" compile="0" resource="1" file="Resources/svg/delete.svg"/>
<FILE id="IqXIZW" name="demo.svg" compile="0" resource="1" file="Resources/svg/demo.svg"/> <FILE id="IqXIZW" name="demo.svg" compile="0" resource="1" file="Resources/svg/demo.svg"/>
<FILE id="ATrDxb" name="distort.svg" compile="0" resource="1" file="Resources/svg/distort.svg"/>
<FILE id="YwkQpy" name="fixed_rotate.svg" compile="0" resource="1" <FILE id="YwkQpy" name="fixed_rotate.svg" compile="0" resource="1"
file="Resources/svg/fixed_rotate.svg"/> file="Resources/svg/fixed_rotate.svg"/>
<FILE id="WIkl6l" name="fullscreen.svg" compile="0" resource="1" file="Resources/svg/fullscreen.svg"/> <FILE id="WIkl6l" name="fullscreen.svg" compile="0" resource="1" file="Resources/svg/fullscreen.svg"/>
<FILE id="n1esUp" name="left_arrow.svg" compile="0" resource="1" file="Resources/svg/left_arrow.svg"/> <FILE id="n1esUp" name="left_arrow.svg" compile="0" resource="1" file="Resources/svg/left_arrow.svg"/>
<FILE id="WdfE7J" name="link.svg" compile="0" resource="1" file="Resources/svg/link.svg"/> <FILE id="WdfE7J" name="link.svg" compile="0" resource="1" file="Resources/svg/link.svg"/>
<FILE id="rGSPBN" name="lua.svg" compile="0" resource="1" file="Resources/svg/lua.svg"/>
<FILE id="PxYKbt" name="microphone.svg" compile="0" resource="1" file="Resources/svg/microphone.svg"/> <FILE id="PxYKbt" name="microphone.svg" compile="0" resource="1" file="Resources/svg/microphone.svg"/>
<FILE id="YuYfcJ" name="multiplex.svg" compile="0" resource="1" file="Resources/svg/multiplex.svg"/>
<FILE id="eGMxwy" name="mute.svg" compile="0" resource="1" file="Resources/svg/mute.svg"/> <FILE id="eGMxwy" name="mute.svg" compile="0" resource="1" file="Resources/svg/mute.svg"/>
<FILE id="hJHxFY" name="open_in_new.svg" compile="0" resource="1" file="Resources/svg/open_in_new.svg"/> <FILE id="hJHxFY" name="open_in_new.svg" compile="0" resource="1" file="Resources/svg/open_in_new.svg"/>
<FILE id="pSc1mq" name="osci.svg" compile="0" resource="1" file="Resources/svg/osci.svg"/> <FILE id="pSc1mq" name="osci.svg" compile="0" resource="1" file="Resources/svg/osci.svg"/>
@ -67,12 +74,21 @@
<FILE id="n79IAy" name="record.svg" compile="0" resource="1" file="Resources/svg/record.svg"/> <FILE id="n79IAy" name="record.svg" compile="0" resource="1" file="Resources/svg/record.svg"/>
<FILE id="vOGcgi" name="repeat.svg" compile="0" resource="1" file="Resources/svg/repeat.svg"/> <FILE id="vOGcgi" name="repeat.svg" compile="0" resource="1" file="Resources/svg/repeat.svg"/>
<FILE id="OaqZb1" name="right_arrow.svg" compile="0" resource="1" file="Resources/svg/right_arrow.svg"/> <FILE id="OaqZb1" name="right_arrow.svg" compile="0" resource="1" file="Resources/svg/right_arrow.svg"/>
<FILE id="Knzo1H" name="ripple.svg" compile="0" resource="1" file="Resources/svg/ripple.svg"/>
<FILE id="Gxscyd" name="rotate.svg" compile="0" resource="1" file="Resources/svg/rotate.svg"/> <FILE id="Gxscyd" name="rotate.svg" compile="0" resource="1" file="Resources/svg/rotate.svg"/>
<FILE id="cUDYOM" name="scale.svg" compile="0" resource="1" file="Resources/svg/scale.svg"/>
<FILE id="ZPUNcg" name="smoothing.svg" compile="0" resource="1" file="Resources/svg/smoothing.svg"/>
<FILE id="yiDo4s" name="spout.svg" compile="0" resource="1" file="Resources/svg/spout.svg"/> <FILE id="yiDo4s" name="spout.svg" compile="0" resource="1" file="Resources/svg/spout.svg"/>
<FILE id="EOWhGi" name="stop.svg" compile="0" resource="1" file="Resources/svg/stop.svg"/> <FILE id="EOWhGi" name="stop.svg" compile="0" resource="1" file="Resources/svg/stop.svg"/>
<FILE id="Z3yYJU" name="swirl.svg" compile="0" resource="1" file="Resources/svg/swirl.svg"/>
<FILE id="rXjNlx" name="threshold.svg" compile="0" resource="1" file="Resources/svg/threshold.svg"/> <FILE id="rXjNlx" name="threshold.svg" compile="0" resource="1" file="Resources/svg/threshold.svg"/>
<FILE id="rFYmV8" name="timer.svg" compile="0" resource="1" file="Resources/svg/timer.svg"/> <FILE id="rFYmV8" name="timer.svg" compile="0" resource="1" file="Resources/svg/timer.svg"/>
<FILE id="ESR7bv" name="trace.svg" compile="0" resource="1" file="Resources/svg/trace.svg"/>
<FILE id="ID1vTS" name="translate.svg" compile="0" resource="1" file="Resources/svg/translate.svg"/>
<FILE id="praXUY" name="vector-cancelling.svg" compile="0" resource="1"
file="Resources/svg/vector-cancelling.svg"/>
<FILE id="qC6QiP" name="volume.svg" compile="0" resource="1" file="Resources/svg/volume.svg"/> <FILE id="qC6QiP" name="volume.svg" compile="0" resource="1" file="Resources/svg/volume.svg"/>
<FILE id="SkgUSk" name="wobble.svg" compile="0" resource="1" file="Resources/svg/wobble.svg"/>
</GROUP> </GROUP>
<GROUP id="{F8A3D32C-4187-9A2F-5D78-040259957E9B}" name="text"> <GROUP id="{F8A3D32C-4187-9A2F-5D78-040259957E9B}" name="text">
<FILE id="N9Q6Zg" name="greek.txt" compile="0" resource="1" file="Resources/text/greek.txt"/> <FILE id="N9Q6Zg" name="greek.txt" compile="0" resource="1" file="Resources/text/greek.txt"/>