diff --git a/Source/MainComponent.cpp b/Source/MainComponent.cpp index 03687f0..8e8b732 100644 --- a/Source/MainComponent.cpp +++ b/Source/MainComponent.cpp @@ -222,6 +222,6 @@ void MainComponent::resized() { auto shiftedBounds = bounds; shiftedBounds.setX(topLeft.getX()); shiftedBounds.setY(topLeft.getY()); - pluginEditor.visualiser.setBounds(shiftedBounds.withSizeKeepingCentre(minDim, minDim)); + pluginEditor.visualiser.setBounds(shiftedBounds.withSizeKeepingCentre(minDim - 25, minDim)); } } diff --git a/Source/PluginEditor.cpp b/Source/PluginEditor.cpp index e57520a..ffb3ea2 100644 --- a/Source/PluginEditor.cpp +++ b/Source/PluginEditor.cpp @@ -104,8 +104,7 @@ OscirenderAudioProcessorEditor::OscirenderAudioProcessorEditor(OscirenderAudioPr addAndMakeVisible(visualiser); visualiser.openSettings = [this] { - visualiserSettingsWindow.setVisible(true); - visualiserSettingsWindow.toFront(true); + openVisualiserSettings(); }; visualiser.closeSettings = [this] { @@ -141,6 +140,15 @@ OscirenderAudioProcessorEditor::~OscirenderAudioProcessorEditor() { #endif } +void OscirenderAudioProcessorEditor::openVisualiserSettings() { + visualiserSettingsWindow.setVisible(true); + visualiserSettingsWindow.toFront(true); +} + +void OscirenderAudioProcessorEditor::closeVisualiserSettings() { + visualiserSettingsWindow.setVisible(false); +} + bool OscirenderAudioProcessorEditor::isBinaryFile(juce::String name) { return name.endsWith(".gpla") || name.endsWith(".gif") || name.endsWith(".png") || name.endsWith(".jpg") || name.endsWith(".jpeg") || name.endsWith(".wav") || name.endsWith(".aiff"); } diff --git a/Source/PluginEditor.h b/Source/PluginEditor.h index f0a8cf5..55013a6 100644 --- a/Source/PluginEditor.h +++ b/Source/PluginEditor.h @@ -27,6 +27,9 @@ public: void handleAsyncUpdate() override; void changeListenerCallback(juce::ChangeBroadcaster* source) override; void toggleLayout(juce::StretchableLayoutManager& layout, double prefSize); + + void openVisualiserSettings(); + void closeVisualiserSettings(); void editCustomFunction(bool enabled); diff --git a/Source/SosciPluginEditor.cpp b/Source/SosciPluginEditor.cpp index a38f565..16f1205 100644 --- a/Source/SosciPluginEditor.cpp +++ b/Source/SosciPluginEditor.cpp @@ -32,26 +32,6 @@ SosciPluginEditor::SosciPluginEditor(SosciAudioProcessor& p) standalone->getMuteInputValue().setValue(false); } } - - addAndMakeVisible(settings); - - settings.onClick = [this] { - openVisualiserSettings(); - }; - - addAndMakeVisible(record); - record.setPulseAnimation(true); - record.onClick = [this] { - visualiser.toggleRecording(); - stopwatch.stop(); - stopwatch.reset(); - if (record.getToggleState()) { - stopwatch.start(); - } - resized(); - }; - - addAndMakeVisible(stopwatch); addAndMakeVisible(visualiser); @@ -62,10 +42,6 @@ SosciPluginEditor::SosciPluginEditor(SosciAudioProcessor& p) visualiser.closeSettings = [this] { visualiserSettingsWindow.setVisible(false); }; - - visualiser.recordingHalted = [this] { - record.setToggleState(false, juce::NotificationType::dontSendNotification); - }; visualiserSettingsWindow.setResizable(false, false); #if JUCE_WINDOWS @@ -78,8 +54,10 @@ SosciPluginEditor::SosciPluginEditor(SosciAudioProcessor& p) visualiserSettings.setSize(550, 340); visualiserSettingsWindow.setContentNonOwned(&visualiserSettings, true); visualiserSettingsWindow.centreWithSize(550, 340); + + menuBar.toFront(true); - setSize(750, 750); + setSize(725, 750); setResizable(true, true); setResizeLimits(250, 250, 999999, 999999); } @@ -96,20 +74,10 @@ void SosciPluginEditor::paint(juce::Graphics& g) { void SosciPluginEditor::resized() { auto area = getLocalBounds(); - auto topBar = area.removeFromTop(25); - settings.setBounds(topBar.removeFromRight(25)); - topBar.removeFromRight(5); - record.setBounds(topBar.removeFromRight(25)); - if (record.getToggleState()) { - stopwatch.setVisible(true); - stopwatch.setBounds(topBar.removeFromRight(100)); - } else { - stopwatch.setVisible(false); - } + auto topBar = area.removeFromTop(25).removeFromLeft(200); menuBar.setBounds(topBar); - - visualiser.setBounds(area); + visualiser.setBounds(getLocalBounds()); } bool SosciPluginEditor::keyPressed(const juce::KeyPress& key) { diff --git a/Source/SosciPluginEditor.h b/Source/SosciPluginEditor.h index 490c187..47b714d 100644 --- a/Source/SosciPluginEditor.h +++ b/Source/SosciPluginEditor.h @@ -7,7 +7,6 @@ #include "components/VisualiserSettings.h" #include "components/SosciMainMenuBarModel.h" #include "components/SvgButton.h" -#include "components/StopwatchComponent.h" class SosciPluginEditor : public juce::AudioProcessorEditor { public: @@ -39,11 +38,6 @@ public: juce::MenuBarComponent menuBar; juce::TooltipWindow tooltipWindow{nullptr, 0}; - - juce::Label recordTimer{"Record Timer"}; - StopwatchComponent stopwatch; - SvgButton record{"Record", BinaryData::record_svg, juce::Colours::red, juce::Colours::red.withAlpha(0.01f)}; - SvgButton settings{"Settings", BinaryData::cog_svg, juce::Colours::white, juce::Colours::white}; bool usingNativeMenuBar = false; diff --git a/Source/components/VisualiserComponent.cpp b/Source/components/VisualiserComponent.cpp index 9545f41..dcf7a3f 100644 --- a/Source/components/VisualiserComponent.cpp +++ b/Source/components/VisualiserComponent.cpp @@ -3,12 +3,25 @@ VisualiserComponent::VisualiserComponent(SampleRateManager& sampleRateManager, ConsumerManager& consumerManager, VisualiserSettings& settings, VisualiserComponent* parent, bool useOldVisualiser, bool visualiserOnly) : settings(settings), backgroundColour(juce::Colours::black), waveformColour(juce::Colour(0xff00ff00)), sampleRateManager(sampleRateManager), consumerManager(consumerManager), oldVisualiser(useOldVisualiser), visualiserOnly(visualiserOnly), juce::Thread("VisualiserComponent"), parent(parent) { resetBuffer(); - if (!oldVisualiser) { - addAndMakeVisible(openGLVisualiser); - } + addChildComponent(openGLVisualiser); + setVisualiserType(oldVisualiser); startTimerHz(60); startThread(); + addAndMakeVisible(record); + record.setPulseAnimation(true); + record.onClick = [this] { + toggleRecording(); + stopwatch.stop(); + stopwatch.reset(); + if (record.getToggleState()) { + stopwatch.start(); + } + resized(); + }; + + addAndMakeVisible(stopwatch); + setMouseCursor(juce::MouseCursor::PointingHandCursor); setWantsKeyboardFocus(true); @@ -21,25 +34,29 @@ VisualiserComponent::VisualiserComponent(SampleRateManager& sampleRateManager, C this->settings.parameters.intensity = intensity.textBox.getValue(); }; - if (parent == nullptr) { - addChildComponent(fullScreenButton); + if (parent == nullptr && !visualiserOnly) { + addAndMakeVisible(fullScreenButton); } - if (child == nullptr && parent == nullptr) { - addChildComponent(popOutButton); + if (child == nullptr && parent == nullptr && !visualiserOnly) { + addAndMakeVisible(popOutButton); } - addChildComponent(settingsButton); + addAndMakeVisible(settingsButton); fullScreenButton.onClick = [this]() { enableFullScreen(); }; settingsButton.onClick = [this]() { - juce::PopupMenu menu; + if (oldVisualiser) { + juce::PopupMenu menu; - menu.addCustomItem(1, roughness, 160, 40, false); - menu.addCustomItem(1, intensity, 160, 40, false); + menu.addCustomItem(1, roughness, 160, 40, false); + menu.addCustomItem(1, intensity, 160, 40, false); - menu.showMenuAsync(juce::PopupMenu::Options(), [this](int result) {}); + menu.showMenuAsync(juce::PopupMenu::Options(), [this](int result) {}); + } else if (openSettings != nullptr) { + openSettings(); + } }; popOutButton.onClick = [this]() { @@ -92,11 +109,13 @@ void VisualiserComponent::setColours(juce::Colour bk, juce::Colour fg) { } void VisualiserComponent::paint(juce::Graphics& g) { + g.fillAll(Colours::veryDark); if (oldVisualiser) { g.setColour(backgroundColour); g.fillRoundedRectangle(getLocalBounds().toFloat(), OscirenderLookAndFeel::RECT_RADIUS); auto r = getLocalBounds().toFloat(); + r.removeFromBottom(25); auto minDim = juce::jmin(r.getWidth(), r.getHeight()); { @@ -111,13 +130,13 @@ void VisualiserComponent::paint(juce::Graphics& g) { if (!active) { // add translucent layer g.setColour(juce::Colours::black.withAlpha(0.5f)); - g.fillRoundedRectangle(getLocalBounds().toFloat(), OscirenderLookAndFeel::RECT_RADIUS); + g.fillRoundedRectangle(r, OscirenderLookAndFeel::RECT_RADIUS); // add text g.setColour(juce::Colours::white); g.setFont(14.0f); auto text = child != nullptr ? "Open in separate window" : "Paused"; - g.drawFittedText(text, getLocalBounds(), juce::Justification::centred, 1); + g.drawFittedText(text, r.toNearestInt(), juce::Justification::centred, 1); } } } @@ -145,6 +164,7 @@ void VisualiserComponent::run() { } void VisualiserComponent::setPaused(bool paused) { + openGLVisualiser.setPaused(paused); active = !paused; if (active) { startTimerHz(60); @@ -161,52 +181,11 @@ void VisualiserComponent::setPaused(bool paused) { } void VisualiserComponent::mouseDown(const juce::MouseEvent& event) { - if (!oldVisualiser) return; if (event.mods.isLeftButtonDown() && child == nullptr) { setPaused(active); } } -void VisualiserComponent::mouseMove(const juce::MouseEvent& event) { - if (!oldVisualiser) return; - if (event.getScreenX() == lastMouseX && event.getScreenY() == lastMouseY) { - return; - } - lastMouseX = event.getScreenX(); - lastMouseY = event.getScreenY(); - - int newTimerId = juce::Random::getSystemRandom().nextInt(); - timerId = newTimerId; - if (parent == nullptr) { - fullScreenButton.setVisible(true); - } - if (child == nullptr && parent == nullptr) { - popOutButton.setVisible(true); - } - settingsButton.setVisible(true); - auto pos = event.getScreenPosition(); - auto parent = this->parent; - - juce::Timer::callAfterDelay(1000, [this, newTimerId, pos, parent]() { - if (parent == nullptr || parent->child == this) { - bool onButtonRow = settingsButton.getScreenBounds().contains(pos); - if (parent == nullptr) { - onButtonRow |= fullScreenButton.getScreenBounds().contains(pos); - } - if (child == nullptr && parent == nullptr) { - onButtonRow |= popOutButton.getScreenBounds().contains(pos); - } - if (timerId == newTimerId && !onButtonRow) { - fullScreenButton.setVisible(false); - popOutButton.setVisible(false); - settingsButton.setVisible(false); - repaint(); - } - } - }); - repaint(); -} - bool VisualiserComponent::keyPressed(const juce::KeyPress& key) { if (key.isKeyCode(juce::KeyPress::escapeKey)) { if (fullScreenCallback) { @@ -230,6 +209,9 @@ void VisualiserComponent::setVisualiserType(bool oldVisualiser) { closeSettings(); } } + openGLVisualiser.setVisible(!oldVisualiser); + resized(); + repaint(); } void VisualiserComponent::paintXY(juce::Graphics& g, juce::Rectangle area) { @@ -272,24 +254,34 @@ void VisualiserComponent::toggleRecording() { } void VisualiserComponent::haltRecording() { - + record.setToggleState(false, juce::NotificationType::dontSendNotification); } void VisualiserComponent::resized() { - if (!oldVisualiser) { - openGLVisualiser.setBounds(getLocalBounds()); - } auto area = getLocalBounds(); - area.removeFromBottom(5); - auto buttonRow = area.removeFromBottom(25); - - if (parent == nullptr) { - fullScreenButton.setBounds(buttonRow.removeFromRight(30)); + juce::Rectangle topRow; + if (visualiserOnly) { + topRow = area.removeFromTop(25); + } else { + topRow = area.removeFromBottom(25); } - if (child == nullptr && parent == nullptr) { - popOutButton.setBounds(buttonRow.removeFromRight(30)); + if (parent == nullptr && !visualiserOnly) { + fullScreenButton.setBounds(topRow.removeFromRight(30)); + } + if (child == nullptr && parent == nullptr && !visualiserOnly) { + popOutButton.setBounds(topRow.removeFromRight(30)); + } + settingsButton.setBounds(topRow.removeFromRight(30)); + record.setBounds(topRow.removeFromRight(25)); + if (record.getToggleState()) { + stopwatch.setVisible(true); + stopwatch.setBounds(topRow.removeFromRight(100)); + } else { + stopwatch.setVisible(false); + } + if (!oldVisualiser) { + openGLVisualiser.setBounds(area); } - settingsButton.setBounds(buttonRow.removeFromRight(30)); } void VisualiserComponent::popoutWindow() { @@ -300,15 +292,18 @@ void VisualiserComponent::popoutWindow() { visualiser->closeSettings = closeSettings; visualiser->recordingHalted = recordingHalted; child = visualiser; - popOutButton.setVisible(false); - visualiser->setSize(300, 300); + childUpdated(); + visualiser->setSize(300, 325); popout = std::make_unique("Software Oscilloscope", this); popout->setContentOwned(visualiser, true); popout->setUsingNativeTitleBar(true); popout->setResizable(true, false); popout->setVisible(true); - popout->centreWithSize(300, 300); + popout->centreWithSize(300, 325); setPaused(true); resized(); - popOutButton.setVisible(false); +} + +void VisualiserComponent::childUpdated() { + popOutButton.setVisible(child == nullptr); } diff --git a/Source/components/VisualiserComponent.h b/Source/components/VisualiserComponent.h index b0f7a83..1534384 100644 --- a/Source/components/VisualiserComponent.h +++ b/Source/components/VisualiserComponent.h @@ -9,6 +9,7 @@ #include "SvgButton.h" #include "VisualiserSettings.h" #include "VisualiserOpenGLComponent.h" +#include "StopwatchComponent.h" enum class FullScreenMode { TOGGLE, @@ -37,12 +38,12 @@ public: void run() override; void setPaused(bool paused); void mouseDown(const juce::MouseEvent& event) override; - void mouseMove(const juce::MouseEvent& event) override; bool keyPressed(const juce::KeyPress& key) override; void setFullScreen(bool fullScreen); void setVisualiserType(bool oldVisualiser); void toggleRecording(); void haltRecording(); + void childUpdated(); VisualiserComponent* parent = nullptr; VisualiserComponent* child = nullptr; @@ -93,6 +94,9 @@ private: std::unique_ptr chooser; juce::File tempVideoFile; + StopwatchComponent stopwatch; + SvgButton record{"Record", BinaryData::record_svg, juce::Colours::red, juce::Colours::red.withAlpha(0.01f)}; + void resetBuffer(); void popoutWindow(); @@ -107,6 +111,7 @@ public: void closeButtonPressed() override { parent->setPaused(wasPaused); parent->child = nullptr; + parent->childUpdated(); parent->resized(); parent->popout.reset(); } diff --git a/Source/components/VisualiserOpenGLComponent.cpp b/Source/components/VisualiserOpenGLComponent.cpp index bd6c715..51b1568 100644 --- a/Source/components/VisualiserOpenGLComponent.cpp +++ b/Source/components/VisualiserOpenGLComponent.cpp @@ -5,6 +5,7 @@ VisualiserOpenGLComponent::VisualiserOpenGLComponent(VisualiserSettings& settings, SampleRateManager& sampleRateManager) : settings(settings), sampleRateManager(sampleRateManager) { openGLContext.setRenderer(this); openGLContext.attachTo(*this); + setInterceptsMouseClicks(false, false); } VisualiserOpenGLComponent::~VisualiserOpenGLComponent() { @@ -782,3 +783,19 @@ void VisualiserOpenGLComponent::checkGLErrors(const juce::String& location) { DBG("OpenGL error at " + location + ": " + errorMessage); } } + +void VisualiserOpenGLComponent::setPaused(bool paused) { + this->paused = paused; + repaint(); +} + +void VisualiserOpenGLComponent::paint(juce::Graphics& g) { + if (paused) { + g.setColour(juce::Colours::black.withAlpha(0.5f)); + g.fillRect(getLocalBounds()); + + g.setColour(juce::Colours::white); + g.setFont(30.0f); + g.drawText("Paused", getLocalBounds(), juce::Justification::centred); + } +} diff --git a/Source/components/VisualiserOpenGLComponent.h b/Source/components/VisualiserOpenGLComponent.h index 3a5020f..60fe30c 100644 --- a/Source/components/VisualiserOpenGLComponent.h +++ b/Source/components/VisualiserOpenGLComponent.h @@ -19,7 +19,9 @@ public: void renderOpenGL() override; void openGLContextClosing() override; void resized() override; + void paint(juce::Graphics& g) override; void updateBuffer(std::vector& buffer); + void setPaused(bool paused); private: juce::OpenGLContext openGLContext; @@ -65,6 +67,8 @@ private: bool smudgesEnabled = settings.getSmudgesEnabled(); bool graticuleEnabled = settings.getGraticuleEnabled(); + bool paused = false; + Texture makeTexture(int width, int height); void setupArrays(int num_points); void setupTextures();