diff --git a/Source/Processors/Editors/VisualizerEditor.cpp b/Source/Processors/Editors/VisualizerEditor.cpp index ccabfae1da3a11ca47ecb5e13d1803a8a358fc15..49f00c6d761f84ca0eb01a253cabb53de5320c31 100755 --- a/Source/Processors/Editors/VisualizerEditor.cpp +++ b/Source/Processors/Editors/VisualizerEditor.cpp @@ -114,8 +114,10 @@ VisualizerEditor::~VisualizerEditor() if (tabIndex > -1) { - AccessClass::getDataViewport()->destroyTab(tabIndex); + AccessClass::getDataViewport()->destroyTab(tabIndex); } + if (dataWindow != nullptr) + dataWindow->removeListener(this); deleteAllChildren(); @@ -149,13 +151,18 @@ void VisualizerEditor::updateVisualizer() } +void VisualizerEditor::windowClosed() +{ + +} + void VisualizerEditor::editorWasClicked() { if (tabIndex > -1) { std::cout << "Setting tab index to " << tabIndex << std::endl; - AccessClass::getDataViewport()->selectTab(tabIndex); + AccessClass::getDataViewport()->selectTab(tabIndex); } } @@ -184,16 +191,18 @@ void VisualizerEditor::buttonClicked(Button* button) if (tabSelector->getToggleState() && windowSelector->getToggleState()) { tabSelector->setToggleState(false, dontSendNotification); - AccessClass::getDataViewport()->destroyTab(tabIndex); - tabIndex = -1; + // AccessClass::getDataViewport()->destroyTab(tabIndex); + // tabIndex = -1; + removeTab(tabIndex); } if (dataWindow == nullptr) // have we created a window already? { - - dataWindow = new DataWindow(windowSelector, tabText); + makeNewWindow(); dataWindow->setContentNonOwned(canvas, false); dataWindow->setVisible(true); + // enable windowClosed() callback + dataWindow->addListener(this); //canvas->refreshState(); } @@ -228,15 +237,15 @@ void VisualizerEditor::buttonClicked(Button* button) dataWindow->setVisible(false); } - tabIndex = AccessClass::getDataViewport()->addTabToDataViewport(tabText, canvas, this); - + // tabIndex = AccessClass::getDataViewport()->addTabToDataViewport(tabText, canvas, this); + addTab(tabText, canvas); } else if (!tabSelector->getToggleState() && tabIndex > -1) { - AccessClass::getDataViewport()->destroyTab(tabIndex); - tabIndex = -1; - + // AccessClass::getDataViewport()->destroyTab(tabIndex); + // tabIndex = -1; + removeTab(tabIndex); } } @@ -313,6 +322,47 @@ void VisualizerEditor::loadCustomParameters(XmlElement* xml) } } +void VisualizerEditor::makeNewWindow() +{ + dataWindow = new DataWindow(windowSelector, tabText); +} + +void VisualizerEditor::addWindowListener(DataWindow* dw, DataWindow::Listener* newListener) /* static method */ +{ + if (dw != nullptr && newListener != nullptr){ + dw->addListener(newListener); + } +} + +void VisualizerEditor::removeWindowListener(DataWindow* dw, DataWindow::Listener* oldListener) /* static method */ +{ + if (dw != nullptr && oldListener != nullptr){ + dw->removeListener(oldListener); + } +} + +Component* VisualizerEditor::getActiveTabContentComponent() const +{ + return AccessClass::getDataViewport()->getCurrentContentComponent(); +} + +void VisualizerEditor::setActiveTabId(int tindex) +{ + AccessClass::getDataViewport()->selectTab(tindex); +} + +void VisualizerEditor::removeTab(int tindex) +{ + AccessClass::getDataViewport()->destroyTab(tindex); + tabIndex = -1; +} + +int VisualizerEditor::addTab(String tab_text, Visualizer* vis_canvas) +{ + tabText = tab_text; + tabIndex = AccessClass::getDataViewport()->addTabToDataViewport(tab_text, vis_canvas, this); + return tabIndex; +} void VisualizerEditor::saveVisualizerParameters(XmlElement* xml) { diff --git a/Source/Processors/Editors/VisualizerEditor.h b/Source/Processors/Editors/VisualizerEditor.h index dbf876746d515fc7bca0388db260331e6fba27d3..fab530133803f9ce957d557bb75d73bed440e964 100755 --- a/Source/Processors/Editors/VisualizerEditor.h +++ b/Source/Processors/Editors/VisualizerEditor.h @@ -65,6 +65,7 @@ private: */ class PLUGIN_API VisualizerEditor : public GenericEditor + , public DataWindow::Listener { public: /** @@ -84,17 +85,17 @@ public: VisualizerEditor(GenericProcessor* processor, bool useDefaultParameterEditors); ~VisualizerEditor(); - /** + /** * @brief This method handles the button evnets which open visualizer in a tab or window. * @warning Do not override this function unless you call ``VisualizerEditor::buttonClicked`` * somewhere! */ void buttonClicked(Button* button); - - /** + + /** * @brief All additional buttons that you create _for the editor_ should be handled here. */ - virtual void buttonEvent(Button* button); + virtual void buttonEvent(Button* button); /** * @brief Creates a new canvas. This is like a factory method and must be defined in your sub-class. @@ -107,6 +108,7 @@ public: void editorWasClicked(); void updateVisualizer(); + virtual void windowClosed(); void saveCustomParameters(XmlElement* xml); void loadCustomParameters(XmlElement* xml); @@ -120,17 +122,84 @@ public: String tabText; -private: +protected: // these should be available to sub-classes if needed. + + /** + * @brief Creates a new DataWindow using the windowSelector (button) + * and ``tabText``. The new object is stored in (and owned by) + * VisualizerEditor::dataWindow. + * @details Use this to make a new DataWindow. If needed, you can + * transfer ownership of the new object from + * VisualizerEditor::dataWindow to _your_ own ScopedPointer. + * @note This method provides an interface to DataWindow, DataWindow + * methods cannot be defined in derivations (ie, plugins). + */ + void makeNewWindow(); - void initializeSelectors(); - bool isPlaying; + /** + * @brief Adds a closeWindow listener for dw. + * + * @param dw The datawindow + * @param newListener The new listener + * + * @note This method provides an interface to DataWindow, DataWindow + * methods cannot be defined in derivations (ie, plugins). + */ + static void addWindowListener(DataWindow* dw, DataWindow::Listener* newListener); + + /** + * @brief Removes a closeWindow listener for dw. + * + * @param dw The datawindow + * @param oldListener The old listener + * + * @note This method provides an interface to DataWindow, DataWindow + * methods cannot be defined in derivations (ie, plugins). + */ + static void removeWindowListener(DataWindow* dw, DataWindow::Listener* oldListener); + + /** + * @brief Use this to efficiently compare or find what is on the + * currently active tab. + * + * @return The active tab content Component. + */ + Component* getActiveTabContentComponent() const; + /** + * @brief Selects the specified _tab_ in the DataViewport. + * + * @param[in] tindex The index which was returned by VisualizerEditor::addTab + */ + void setActiveTabId(int tindex); + + /** + * @brief Remove the specified tab from DataViewport. + * + * @param[in] tindex The index which was returned by VisualizerEditor::addTab + */ + void removeTab(int tindex); + + /** + * @brief Adds a new tab to the DataViewport. + * + * @param[in] tab_text The tab text + * @param vis_canvas The content Visualizer (Canvas) Component for this tab. + * + * @return The identifier token for this tab. You must provide this + * identifier to access/remove this tab. + */ + int addTab(String tab_text, Visualizer* vis_canvas); + + bool isPlaying; /**< Acquisition status flag */ + + // So that we can override buttonClick. That's not possible if these are private. SelectorButton* windowSelector; SelectorButton* tabSelector; - int tabIndex; - +private: + void initializeSelectors(); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(VisualizerEditor); diff --git a/Source/Processors/Visualization/DataWindow.cpp b/Source/Processors/Visualization/DataWindow.cpp index 62746822919dc2cb4d4895621c1ed21912e3c8f7..59099227ed83d34b933003cd6d5347070b30af7b 100755 --- a/Source/Processors/Visualization/DataWindow.cpp +++ b/Source/Processors/Visualization/DataWindow.cpp @@ -27,8 +27,8 @@ DataWindow::DataWindow(Button* cButton, String name) : DocumentWindow(name, Colours::black, - DocumentWindow::allButtons), - controlButton(cButton) + DocumentWindow::allButtons) + , controlButton(cButton) { centreWithSize(800,500); @@ -46,4 +46,23 @@ void DataWindow::closeButtonPressed() setContentNonOwned(0,false); setVisible(false); controlButton->setToggleState(false,dontSendNotification); + // with the BailOutChecker, it is safe to "delete" a DataWindow instance + // from this callback/listener. This would (typically) not be done, because instances + // of DataWindow are (typically) "owned" by Editors, and will be deleted + // when the Editor dies. + // + Component::BailOutChecker checker (this); + if (! checker.shouldBailOut()){ + closeWindowListeners.callChecked (checker, &DataWindow::Listener::windowClosed); + } +} + +void DataWindow::addListener (DataWindow::Listener* const newListener) +{ + closeWindowListeners.add (newListener); +} + +void DataWindow::removeListener (DataWindow::Listener* const listener) +{ + closeWindowListeners.remove (listener); } diff --git a/Source/Processors/Visualization/DataWindow.h b/Source/Processors/Visualization/DataWindow.h index e068e54118f0d38130bd8ec3d7a990bde1e1896b..6a4f7890de49b18ba72e306dea9178870c9e78c7 100755 --- a/Source/Processors/Visualization/DataWindow.h +++ b/Source/Processors/Visualization/DataWindow.h @@ -39,14 +39,36 @@ class DataWindow : public DocumentWindow public: DataWindow(Button* button, String name); ~DataWindow(); - + void closeButtonPressed(); + + class Listener + { + public: + /** Destructor. */ + virtual ~Listener() {} + + /** Called when the window is closed. */ + virtual void windowClosed () = 0; + }; + + /** + * @brief Registers a listener to receive event when this is closed. If + * the listener is already registered, this will not register it + * again. + */ + void addListener (Listener* newListener); + + /** + * @brief Removes a previously-registered DataWindow listener + */ + void removeListener (Listener* listener); private: JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(DataWindow); Button* controlButton; - + ListenerList<Listener> closeWindowListeners; };