Skip to content

Commit

Permalink
Patch Selector Favorites/Find button Accessible; Focusable
Browse files Browse the repository at this point in the history
The favorites and find button were funky - drawn in place.
They are still a bit funky - drawn in place with a focusable
accessible overlay - but that's just to avoid reworking the draw
code. This makes them accessible, focusable, and so on. Moreover
the accessible name of the favorites button indicates whether a
patch is a favorite or not.

Closes surge-synthesizer#7399
  • Loading branch information
baconpaul committed Jan 22, 2024
1 parent 7c10c9d commit ea7830a
Show file tree
Hide file tree
Showing 2 changed files with 179 additions and 48 deletions.
214 changes: 171 additions & 43 deletions src/surge-xt/gui/widgets/PatchSelector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,64 @@ struct PatchDBTypeAheadProvider : public TypeAheadDataProvider,
}
};

struct PatchSelector::TB : juce::Component
{
SurgeStorage *storage{nullptr};
TB(const std::string &s)
{
setAccessible(true);
setWantsKeyboardFocus(true);
setTitle(s);
setDescription(s);
}
void paint(juce::Graphics &g) override
{
/* Useful for debugging
g.setColour(juce::Colours::blue);
g.drawRect(getLocalBounds(), 1);
*/
}

void mouseDown(const juce::MouseEvent &e) override
{
if (e.mods.isPopupMenu() && onMenu())
{
return;
}
onPress();
}

void mouseEnter(const juce::MouseEvent &e) override { onEnterExit(true); }

void mouseExit(const juce::MouseEvent &e) override { onEnterExit(false); }

bool keyPressed(const juce::KeyPress &e) override
{
auto [action, mod] = Surge::Widgets::accessibleEditAction(e, storage);
if (action == OpenMenu)
{
return onMenu();
}
if (action == Return)
{
return onPress();
}
return false;
}

std::function<void(bool)> onEnterExit = [](auto b) {};
std::function<bool()> onMenu = []() { return false; }, onPress = []() { return false; };

std::unique_ptr<juce::AccessibilityHandler> createAccessibilityHandler() override
{
return std::make_unique<juce::AccessibilityHandler>(
*this, juce::AccessibilityRole::button,
juce::AccessibilityActions().addAction(juce::AccessibilityActionType::press, [this]() {
std::cout << "PRESS EVENT" << std::endl;
}));
}
};

PatchSelector::PatchSelector() : juce::Component(), WidgetBaseMixin<PatchSelector>(this)
{
patchDbProvider = std::make_unique<PatchDBTypeAheadProvider>(this);
Expand All @@ -163,6 +221,49 @@ PatchSelector::PatchSelector() : juce::Component(), WidgetBaseMixin<PatchSelecto

addChildComponent(*typeAhead);

searchButton = std::make_unique<TB>("Open Search DB");
searchButton->onEnterExit = [w = juce::Component::SafePointer(this)](bool b) {
if (w)
{
w->searchHover = b;
w->favoritesHover = false;
w->repaint();
}
};
searchButton->onPress = [w = juce::Component::SafePointer(this)]() {
if (w)
{
w->typeaheadButtonPressed();
}
return true;
};
addAndMakeVisible(*searchButton);

favoriteButton = std::make_unique<TB>("Favorites");
addAndMakeVisible(*favoriteButton);
favoriteButton->onEnterExit = [w = juce::Component::SafePointer(this)](bool b) {
if (w)
{
w->searchHover = false;
w->favoritesHover = b;
w->repaint();
}
};
favoriteButton->onPress = [w = juce::Component::SafePointer(this)]() {
if (w)
{
w->toggleFavoriteStatus();
}
return true;
};
favoriteButton->onMenu = [w = juce::Component::SafePointer(this)]() {
if (w)
{
w->showFavoritesMenu();
}
return true;
};

setWantsKeyboardFocus(true);
};
PatchSelector::~PatchSelector() { typeAhead->removeTypeAheadListener(this); };
Expand All @@ -172,6 +273,8 @@ void PatchSelector::setStorage(SurgeStorage *s)
storage = s;
storage->patchDB->initialize();
patchDbProvider->storage = s;
searchButton.get()->storage = s;
favoriteButton.get()->storage = s;
}

void PatchSelector::paint(juce::Graphics &g)
Expand Down Expand Up @@ -296,11 +399,13 @@ void PatchSelector::resized()
.withTrimmedLeft(getWidth() - fsize)
.reduced(1, 1)
.translated(-2, 1);
favoriteButton->setBounds(favoritesRect);
searchRect = getLocalBounds()
.withTrimmedBottom(getHeight() - fsize)
.withWidth(fsize)
.reduced(1, 1)
.translated(2, 1);
searchButton->setBounds(searchRect);

auto tad = getLocalBounds().reduced(fsize + 4, 0).translated(0, -2);

Expand Down Expand Up @@ -379,59 +484,19 @@ void PatchSelector::mouseDown(const juce::MouseEvent &e)
{
if (e.mods.isPopupMenu())
{
juce::PopupMenu menu;

tooltipCountdown = -1;
toggleCommentTooltip(false);

Surge::Widgets::MenuCenteredBoldLabel::addToMenuAsSectionHeader(menu, "FAVORITES");

auto haveFavs = optionallyAddFavorites(menu, false, false);

if (haveFavs)
{
auto sge = firstListenerOfType<SurgeGUIEditor>();

stuckHover = true;
menu.showMenuAsync(sge->popupMenuOptions(favoritesRect.getBottomLeft()),
[that = juce::Component::SafePointer(this)](int) {
if (that)
{
that->stuckHover = false;
that->endHover();
}
});
}

showFavoritesMenu();
return;
}
else
{
isFavorite = !isFavorite;
auto sge = firstListenerOfType<SurgeGUIEditor>();

if (sge)
{
sge->setPatchAsFavorite(pname, isFavorite);
repaint();
}
toggleFavoriteStatus();
}
return;
}

if (e.mods.isShiftDown() || searchRect.contains(e.position.toInt()))
{
tooltipCountdown = -1;
toggleCommentTooltip(false);

if (wasTypeaheadCanceledSinceLastIdle)
{
toggleTypeAheadSearch(false);
}
else
{
toggleTypeAheadSearch(!isTypeaheadSearchOn);
}
typeaheadButtonPressed();
return;
}

Expand Down Expand Up @@ -1529,5 +1594,68 @@ void PatchSelector::searchUpdated()
juce::Timer::callAfterDelay(1.0 * 1000, cb);
}

void PatchSelector::typeaheadButtonPressed()
{
tooltipCountdown = -1;
toggleCommentTooltip(false);

if (wasTypeaheadCanceledSinceLastIdle)
{
toggleTypeAheadSearch(false);
}
else
{
toggleTypeAheadSearch(!isTypeaheadSearchOn);
}
}

void PatchSelector::setIsFavorite(bool b)
{
isFavorite = b;
favoriteButton->setTitle(b ? "Remove from Favorites" : "Add to Favorites");
favoriteButton->setDescription(b ? "Remove from Favorites" : "Add to Favorites");
favoriteButton->getAccessibilityHandler()->notifyAccessibilityEvent(
juce::AccessibilityEvent::titleChanged);
repaint();
}

void PatchSelector::showFavoritesMenu()
{
juce::PopupMenu menu;

tooltipCountdown = -1;
toggleCommentTooltip(false);

Surge::Widgets::MenuCenteredBoldLabel::addToMenuAsSectionHeader(menu, "FAVORITES");

auto haveFavs = optionallyAddFavorites(menu, false, false);

if (haveFavs)
{
auto sge = firstListenerOfType<SurgeGUIEditor>();

stuckHover = true;
menu.showMenuAsync(sge->popupMenuOptions(favoritesRect.getBottomLeft()),
[that = juce::Component::SafePointer(this)](int) {
if (that)
{
that->stuckHover = false;
that->endHover();
}
});
}
}

void PatchSelector::toggleFavoriteStatus()
{
setIsFavorite(!isFavorite);
auto sge = firstListenerOfType<SurgeGUIEditor>();

if (sge)
{
sge->setPatchAsFavorite(pname, isFavorite);
repaint();
}
}
} // namespace Widgets
} // namespace Surge
13 changes: 8 additions & 5 deletions src/surge-xt/gui/widgets/PatchSelector.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,7 @@ struct PatchSelector : public juce::Component,
}

bool isFavorite{false};
void setIsFavorite(bool b)
{
isFavorite = b;
repaint();
}
void setIsFavorite(bool b);

bool isUser{false};
void setIsUser(bool b)
Expand Down Expand Up @@ -163,6 +159,7 @@ struct PatchSelector : public juce::Component,
void toggleTypeAheadSearch(bool);
void enableTypeAheadIfReady();
void searchUpdated();
void typeaheadButtonPressed();
uint32_t outstandingSearches{0};
std::unique_ptr<Surge::Widgets::TypeAhead> typeAhead;
std::unique_ptr<PatchDBTypeAheadProvider> patchDbProvider;
Expand Down Expand Up @@ -197,6 +194,12 @@ struct PatchSelector : public juce::Component,
bool populatePatchMenuForCategory(int index, juce::PopupMenu &contextMenu, bool single_category,
int &main_e, bool rootCall);

// a little transparent button to alow ally and focus over find and fav
struct TB;
std::unique_ptr<TB> searchButton, favoriteButton;
void showFavoritesMenu();
void toggleFavoriteStatus();

private:
std::unique_ptr<juce::AccessibilityHandler> createAccessibilityHandler() override;

Expand Down

0 comments on commit ea7830a

Please sign in to comment.