commit 80deab7e4dfd39f4113d183baae1110b8c58badc
parent ed4d96390ad00b47eacd109e464c6aef99720524
Author: dsp56300 <dsp56300@users.noreply.github.com>
Date: Sun, 14 Jul 2024 14:43:28 +0200
add keyboard controls
Diffstat:
3 files changed, 113 insertions(+), 8 deletions(-)
diff --git a/source/jucePluginEditorLib/patchmanager/grid.cpp b/source/jucePluginEditorLib/patchmanager/grid.cpp
@@ -4,10 +4,12 @@
#include "list.h"
#include "patchmanager.h"
-#include "../../juceUiLib/uiObjectStyle.h"
#include "../../juceUiLib/uiObject.h"
+
#include "../pluginEditor.h"
+#include "dsp56kEmu/fastmath.h"
+
namespace jucePluginEditorLib::patchManager
{
Grid::Grid(PatchManager& _pm) : ListModel(_pm), m_viewport(*this), m_itemContainer(*this)
@@ -21,6 +23,8 @@ namespace jucePluginEditorLib::patchManager
t->apply(_pm.getEditor(), *this);
List::applyStyleToViewport(_pm, m_viewport);
+
+ setWantsKeyboardFocus(true);
}
void Grid::paint(juce::Graphics& g)
@@ -79,22 +83,19 @@ namespace jucePluginEditorLib::patchManager
m_items.insert({i, std::move(item)});
}
- const auto visibleRowCount = m_viewport.getVisibleRowCount();
-
for (const auto& it : m_items)
{
const auto index = it.first;
const auto& item = it.second;
- const auto x = index / visibleRowCount;
- const auto y = index - x * visibleRowCount;
+ const auto [x,y] = getXY(index);
item->setTopLeftPosition(static_cast<int>(m_itemWidth * x), static_cast<int>(m_itemHeight * y));
item->setSize(m_itemWidth, m_itemHeight);
}
}
- void Grid::selectItem(uint32_t _index, bool _deselectOthers)
+ void Grid::selectItem(const uint32_t _index, const bool _deselectOthers)
{
if(_deselectOthers)
{
@@ -103,10 +104,12 @@ namespace jucePluginEditorLib::patchManager
m_selectedItems.clear();
m_selectedItems.insert(_index);
+ m_lastSelectedItem = _index;
}
else if(!m_selectedItems.insert(_index).second)
return;
+ m_lastSelectedItem = _index;
selectedRowsChanged(static_cast<int>(_index));
repaint();
}
@@ -116,6 +119,9 @@ namespace jucePluginEditorLib::patchManager
if(!m_selectedItems.erase(_index))
return;
+ if(_index == m_lastSelectedItem)
+ m_lastSelectedItem = m_selectedItems.empty() ? InvalidItem : *m_selectedItems.begin();
+
repaint();
}
@@ -125,6 +131,38 @@ namespace jucePluginEditorLib::patchManager
return it == m_items.end() ? nullptr : it->second.get();
}
+ void Grid::selectRange(const uint32_t _newIndex)
+ {
+ const auto oldIndex = m_lastSelectedItem;
+ const auto dir = _newIndex > oldIndex ? 1 : -1;
+
+ for(auto i=oldIndex; ; i += dir)
+ {
+ selectItem(i, false);
+ if(i == _newIndex)
+ {
+ break;
+ }
+ }
+ }
+
+ bool Grid::keyPressed(const juce::KeyPress& _key)
+ {
+ const auto shift = _key.getModifiers().isShiftDown();
+
+ if(_key.isKeyCode(juce::KeyPress::upKey))
+ handleKeySelection(0, -1, shift);
+ else if(_key.isKeyCode(juce::KeyPress::downKey))
+ handleKeySelection(0, 1, shift);
+ else if(_key.isKeyCode(juce::KeyPress::leftKey))
+ handleKeySelection(-1, 0, shift);
+ else if(_key.isKeyCode(juce::KeyPress::rightKey))
+ handleKeySelection(1, 0, shift);
+ else
+ return Component::keyPressed(_key);
+ return true;
+ }
+
void Grid::resized()
{
updateViewportSize();
@@ -149,6 +187,66 @@ namespace jucePluginEditorLib::patchManager
m_viewport.setSize(getWidth(), getHeight());
}
+ void Grid::handleKeySelection(const int _offsetX, const int _offsetY, bool _shift)
+ {
+ const auto oldXY = getXY(m_lastSelectedItem);
+
+ const auto rows = m_viewport.getVisibleRowCount();
+ const auto columns = getNeededColumnCount();
+
+ auto [newX, newY] = oldXY;
+
+ newX += _offsetX;
+ newY += _offsetY;
+
+ if(newY < 0)
+ {
+ if(newX > 0)
+ {
+ newY += rows;
+ --newX;
+ }
+ else
+ {
+ newX = 0;
+ }
+ }
+ if(newY >= rows)
+ {
+ if(newX < (columns - 1))
+ {
+ newY -= rows;
+ ++newX;
+ }
+ }
+
+ if(newX >= columns)
+ newX = columns - 1;
+ if(newX < 0)
+ newX = 0;
+
+ const uint32_t newIndex = dsp56k::clamp(newX * rows + newY, 0, getNumRows() - 1);
+
+ if(_shift)
+ {
+ selectRange(newIndex);
+ ensureVisible(static_cast<int>(newIndex));
+ }
+ else
+ {
+ selectItem(newIndex, true);
+ ensureVisible(static_cast<int>(newIndex));
+ }
+ }
+
+ std::pair<int, int> Grid::getXY(const uint32_t _index) const
+ {
+ const auto c = m_viewport.getVisibleRowCount();
+ const auto x = _index / c;
+ const auto y = _index - x * c;
+ return {static_cast<int>(x),static_cast<int>(y)};
+ }
+
juce::Colour Grid::findColor(const int _colorId)
{
return findColour(_colorId);
@@ -209,8 +307,7 @@ namespace jucePluginEditorLib::patchManager
juce::Rectangle<int> result;
result.setSize(m_itemWidth, m_itemHeight);
- const auto x = _row / m_viewport.getVisibleRowCount();
- const auto y = _row - x * m_viewport.getVisibleRowCount();
+ const auto [x,y] = getXY(static_cast<uint32_t>(_row));
result.setPosition(x * m_itemWidth - m_viewport.getViewArea().getX(), y * m_itemHeight - m_viewport.getViewArea().getY());
diff --git a/source/jucePluginEditorLib/patchmanager/grid.h b/source/jucePluginEditorLib/patchmanager/grid.h
@@ -13,6 +13,8 @@ namespace jucePluginEditorLib::patchManager
class Grid : public ListModel, public juce::Component
{
public:
+ static constexpr uint32_t InvalidItem = ~0;
+
Grid(PatchManager& _pm);
void paint(juce::Graphics& g) override;
@@ -32,12 +34,16 @@ namespace jucePluginEditorLib::patchManager
void selectItem(uint32_t _index, bool _deselectOthers);
void deselectItem(uint32_t _index);
GridItem* getItem(uint32_t _index) const;
+ void selectRange(uint32_t _newIndex);
+ bool keyPressed(const juce::KeyPress& _key) override;
private:
void resized() override;
int getNeededColumnCount();
int getVisibleRowCount() const;
void updateViewportSize();
+ void handleKeySelection(int _offsetX, int _offsetY, bool _shift);
+ std::pair<int, int> getXY(uint32_t _index) const;
public:
// ListModel
@@ -62,5 +68,6 @@ namespace jucePluginEditorLib::patchManager
std::map<uint32_t, std::unique_ptr<GridItem>> m_items;
std::list<std::unique_ptr<GridItem>> m_itemPool;
std::set<uint32_t> m_selectedItems;
+ uint32_t m_lastSelectedItem = InvalidItem;
};
}
diff --git a/source/jucePluginEditorLib/patchmanager/gridviewport.cpp b/source/jucePluginEditorLib/patchmanager/gridviewport.cpp
@@ -6,6 +6,7 @@ namespace jucePluginEditorLib::patchManager
{
GridViewport::GridViewport(Grid& _grid) : m_grid(_grid)
{
+ setWantsKeyboardFocus(false);
}
void GridViewport::visibleAreaChanged(const juce::Rectangle<int>& _area)