From 6217fdd9eb3316d437af47cbf8862ccea7c4822c Mon Sep 17 00:00:00 2001 From: Septen <gammerxpower@gmail.com> Date: Sun, 27 Mar 2016 03:10:41 +0300 Subject: [PATCH] Implemented TiledButtonGroupManager. * This class position buttons inside itself as tiles and has feature which gives us fuzzy button selection possibility via mouse drag (or SHIFT+mouse drag for deselection). --- Source/UI/Utils/ButtonGroupManager.cpp | 1 - Source/UI/Utils/TiledButtonGroupManager.cpp | 194 ++++++++++++++++++++ Source/UI/Utils/TiledButtonGroupManager.h | 96 ++++++++++ 3 files changed, 290 insertions(+), 1 deletion(-) create mode 100644 Source/UI/Utils/TiledButtonGroupManager.cpp create mode 100644 Source/UI/Utils/TiledButtonGroupManager.h diff --git a/Source/UI/Utils/ButtonGroupManager.cpp b/Source/UI/Utils/ButtonGroupManager.cpp index 3b64682a6..5e8f931db 100644 --- a/Source/UI/Utils/ButtonGroupManager.cpp +++ b/Source/UI/Utils/ButtonGroupManager.cpp @@ -91,7 +91,6 @@ void ButtonGroupManager::addButton (Button* newButton) if (m_isRadioButtonMode) { - newButton->setClickingTogglesState (true); newButton->setRadioGroupId (1); } diff --git a/Source/UI/Utils/TiledButtonGroupManager.cpp b/Source/UI/Utils/TiledButtonGroupManager.cpp new file mode 100644 index 000000000..4b011c8c6 --- /dev/null +++ b/Source/UI/Utils/TiledButtonGroupManager.cpp @@ -0,0 +1,194 @@ +/* + ------------------------------------------------------------------ + + This file is part of the Open Ephys GUI + Copyright (C) 2016 Open Ephys + + ------------------------------------------------------------------ + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#include "TiledButtonGroupManager.h" +#include "../MaterialButtonLookAndFeel.h" + +#include <algorithm> + + +TiledButtonGroupManager::TiledButtonGroupManager() + : m_firstSelectedButtonIdx (-1) + , m_lastSelectedButtonIdx (-1) + , m_isToggleOnMode (true) + , m_isDraggingMouseNow (false) + , m_isSelectButtonsByDragging (false) + , m_buttonWidth (0) + , m_buttonHeight (0) +{ + setRadioButtonMode (false); + setButtonsLookAndFeel (new MaterialButtonLookAndFeel); +} + + +void TiledButtonGroupManager::resized() +{ + const int width = getWidth(); + + if (! width) + return; + + const int minPadding = 5; + const int numButtonsInTheRow = width / (m_buttonWidth + minPadding); + const int padding = jmax (minPadding, (width - numButtonsInTheRow * m_buttonWidth) / (numButtonsInTheRow - 1)); + + juce::Rectangle<int> buttonBounds (0, 0, m_buttonWidth, m_buttonHeight); + const int numButtons = m_buttons.size(); + for (int i = 0; i < numButtons; ++i) + { + m_buttons[i]->setBounds (buttonBounds); + + // Go to the next row + if ( (i + 1) % numButtonsInTheRow == 0) + { + buttonBounds.setX (0); + buttonBounds.translate (0, m_buttonHeight + padding); + } + // Go to the next column + else + { + buttonBounds.translate (m_buttonWidth + padding, 0); + } + } +} + + +void TiledButtonGroupManager::mouseDown (const MouseEvent& e) +{ +} + + +void TiledButtonGroupManager::mouseUp (const MouseEvent& e) +{ + m_isDraggingMouseNow = false; + + m_firstSelectedButtonIdx = -1; + m_lastSelectedButtonIdx = -1; +} + + +void TiledButtonGroupManager::mouseDrag (const MouseEvent& e) +{ + if (! m_isSelectButtonsByDragging) + return; + + m_isDraggingMouseNow = true; + + // Is shift + drag mouse action occurs, then we should toggle on buttons; + // Otherwise - toggle off. + m_isToggleOnMode = ! e.mods.isShiftDown(); + + const int currentButtonIdx = getIndexOfButtonAtPosition (e.getEventRelativeTo (this).getPosition()); + + // Remember the first button on which we started dragging + if (m_firstSelectedButtonIdx == -1 + && m_lastSelectedButtonIdx == -1 + && currentButtonIdx >= 0) + { + m_firstSelectedButtonIdx = currentButtonIdx; + } + + + if (currentButtonIdx != -1 + && currentButtonIdx != m_lastSelectedButtonIdx) + { + m_lastSelectedButtonIdx = currentButtonIdx; + + // Get the indices of range which we should to select (get FROM index and TO index) + const int fromIndex = jmin (m_firstSelectedButtonIdx, m_lastSelectedButtonIdx); + const int toIndex = jmax (m_firstSelectedButtonIdx, m_lastSelectedButtonIdx); + + for (int i = fromIndex; i <= toIndex; ++i) + { + // Trigger click only if the button still isn't selected/deselected (according to the SHIFT holds) + if (m_buttons[i]->getToggleState() != m_isToggleOnMode) + // Trigger click in the button, this will call buttonClicked() method, where we will + m_buttons[i]->triggerClick(); + } + } +} + + +void TiledButtonGroupManager::buttonClicked (Button* buttonThatWasClicked) +{ + // Fast selection enabled and we dragging mouse now to select + if (m_isSelectButtonsByDragging + && m_isDraggingMouseNow) + { + buttonThatWasClicked->setToggleState (m_isToggleOnMode, dontSendNotification); + } + // Default selection + else + { + buttonThatWasClicked->setToggleState (! buttonThatWasClicked->getToggleState(), dontSendNotification); + } + + // Notify the listener + ButtonGroupManager::buttonClicked (buttonThatWasClicked); +} + + +void TiledButtonGroupManager::addButton (Button* newButton) +{ + ButtonGroupManager::addButton (newButton); + + // Disable default clicking on button + newButton->addMouseListener (this, false); +} + + +int TiledButtonGroupManager::getIndexOfButtonAtPosition (Point<int> position) +{ + const int numButtons = m_buttons.size(); + for (int i = 0; i < numButtons; ++i) + { + if (m_buttons[i]->getBounds().contains (position)) + return i; + } + + return -1; +} + + +bool TiledButtonGroupManager::isFastSelectionModeEnabled() +{ + return m_isSelectButtonsByDragging; +} + + +void TiledButtonGroupManager::setFastSelectionModeEnabled (bool isFastSelectionMode) +{ + m_isSelectButtonsByDragging = isFastSelectionMode; +} + + +void TiledButtonGroupManager::setButtonSize (int buttonWidth, int buttonHeight) +{ + m_buttonWidth = buttonWidth; + m_buttonHeight = buttonHeight; + + std::for_each (m_buttons.begin(), m_buttons.end(), + [=] (Button* button) { button->setSize (buttonWidth, buttonHeight); }); + + resized(); +} diff --git a/Source/UI/Utils/TiledButtonGroupManager.h b/Source/UI/Utils/TiledButtonGroupManager.h new file mode 100644 index 000000000..7de5e1dbc --- /dev/null +++ b/Source/UI/Utils/TiledButtonGroupManager.h @@ -0,0 +1,96 @@ +/* + ------------------------------------------------------------------ + + This file is part of the Open Ephys GUI + Copyright (C) 2016 Open Ephys + + ------------------------------------------------------------------ + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#ifndef TILEDBUTTONGROUPMANAGER_H_INCLUDED +#define TILEDBUTTONGROUPMANAGER_H_INCLUDED + +#include "../../../JuceLibraryCode/JuceHeader.h" +#include "../../Processors/PluginManager/OpenEphysPlugin.h" +#include "ButtonGroupManager.h" + + +/** + + This class provides possibility to store buttons in several rows having tile-structure. + It is responsible for positioning of buttons, any animations during resizing. + It also have "Fast select" feature which allows as to quickly select many buttons + using mouse drag selection. (mouse drag - to select, shift+mouse drag to deselect) + +*/ + + +class PLUGIN_API TiledButtonGroupManager : public ButtonGroupManager +{ +public: + TiledButtonGroupManager(); + + // Component methods + // =========================================================== + void resized() override; + + void mouseDown (const MouseEvent& e) override; + void mouseUp (const MouseEvent& e) override; + void mouseDrag (const MouseEvent& e) override; + // =========================================================== + + // Button::Listener methods + // =========================================================== + void buttonClicked (Button* buttonThatWasClicked); + + /** Returns whether fast selection mode (toggle on or off buttons by dragging mouse) is enabled or not */ + bool isFastSelectionModeEnabled(); + + /** Sets whether fast selection mode (toggle on or off buttons by dragging mouse) will be enabled */ + void setFastSelectionModeEnabled (bool isFastSelectionMode); + + /** Sets the size of each button */ + void setButtonSize (int buttonWidth, int buttonHeight); + + /** Add button to the array of buttons to manage it. + + This class controls ownership of buttons. + */ + void addButton (Button* newButton); + + +private: + // Returns the index of button at given position. + // If nothing found at this position - returns -1. + int getIndexOfButtonAtPosition (Point<int> position); + + int m_buttonWidth; + int m_buttonHeight; + + int m_firstSelectedButtonIdx; + int m_lastSelectedButtonIdx; + bool m_isToggleOnMode; + bool m_isDraggingMouseNow; + bool m_isSelectButtonsByDragging; + + // =========================================================== + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TiledButtonGroupManager) +}; + + + +#endif //TILEDBUTTONGROUPMANAGER_H_INCLUDED -- GitLab