Skip to content

Commit

Permalink
Accessibility, Part one
Browse files Browse the repository at this point in the history
- Tab order
- Names on things starting to be ther
- Read the doc

Still

- No edit
- No typein control
  • Loading branch information
baconpaul committed Apr 26, 2024
1 parent 01ef373 commit 3d8a8a6
Show file tree
Hide file tree
Showing 2 changed files with 168 additions and 14 deletions.
173 changes: 161 additions & 12 deletions src-juce/AWConsolidatedEditor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,18 @@ struct AWLookAndFeel : public juce::LookAndFeel_V4

struct Picker : public juce::Component
{
struct Jog : public juce::Component
struct Jog : public juce::Button
{
Picker *picker;
int dir;
Jog(Picker *p, int d) : picker(p), dir(d) {}
void paint(juce::Graphics &g) override
Jog(Picker *p, int d)
: juce::Button(juce::String("Jog ") + (d > 0 ? "Next" : "Previous")), picker(p), dir(d)
{
setAccessible(true);
}
void paintButton (juce:: Graphics& g,
bool shouldDrawButtonAsHighlighted,
bool shouldDrawButtonAsDown) override
{
auto p = juce::Path();
auto jd = getLocalBounds().reduced(3, 5);
Expand Down Expand Up @@ -79,12 +85,14 @@ struct Picker : public juce::Component
};
std::unique_ptr<Jog> up, down;

struct Hamburger : juce::Component
struct Hamburger : juce::Button
{
Picker *picker;
Hamburger(Picker *p) : picker(p) {}
Hamburger(Picker *p) : juce::Button("Menu"), picker(p) { setAccessible(true); }

void paint(juce::Graphics &g) override
void paintButton (juce:: Graphics& g,
bool shouldDrawButtonAsHighlighted,
bool shouldDrawButtonAsDown) override
{
auto r = getLocalBounds().withHeight(getHeight() / 5);
for (int i = 0; i < 3; ++i)
Expand Down Expand Up @@ -310,7 +318,10 @@ struct AWLink : public juce::Component
struct DocPanel : juce::Component
{
AWConsolidatedAudioProcessorEditor *editor{nullptr};
DocPanel(AWConsolidatedAudioProcessorEditor *ed) : editor(ed) {}
DocPanel(AWConsolidatedAudioProcessorEditor *ed) : editor(ed) {
setAccessible(true);
setWantsKeyboardFocus(true);
}
void rebuild()
{
auto r = juce::Rectangle<int>(0, 0, targetWidth, 10000);
Expand All @@ -331,11 +342,26 @@ struct DocPanel : juce::Component
r = r.withHeight(bodyBounds.getBottom());

setSize(r.getWidth(), r.getHeight());

setTitle(AirwinRegistry::registry[editor->processor.curentProcessorIndex].name + " Documentation. Control R to read");
if (getAccessibilityHandler())
getAccessibilityHandler()->notifyAccessibilityEvent(juce::AccessibilityEvent::titleChanged);
}

float targetWidth{10};

void paint(juce::Graphics &g)
bool keyPressed(const juce::KeyPress &key) override {
if ((key.getKeyCode() == 'r' ||
key.getKeyCode() == 'R') && (key.getModifiers().isCommandDown() || key.getModifiers().isCtrlDown()))
{
getAccessibilityHandler()->postAnnouncement(editor->docHeader.substring(2) + "." + editor->docString,
juce::AccessibilityHandler::AnnouncementPriority::medium);
return true;
}
return false;
}

void paint(juce::Graphics &g) override
{
g.setColour(juce::Colours::white);
auto r = getLocalBounds();
Expand Down Expand Up @@ -369,6 +395,15 @@ struct ParamKnob : juce::Component
ParamKnob(const juce::String &cn, juce::AudioParameterFloat *param, const std::atomic<bool> &a)
: juce::Component(cn), weakParam{param}, active{a}
{
refreshModel();
}

void refreshModel()
{
setAccessible(active);
setWantsKeyboardFocus(active);
if (active && weakParam)
setTitle(weakParam->getName(64));
}

float getValue() const { return weakParam ? weakParam->get() : 0.f; }
Expand Down Expand Up @@ -453,6 +488,49 @@ struct ParamKnob : juce::Component
isHovered = false;
repaint();
}

struct AHValue : public juce::AccessibilityValueInterface
{
explicit AHValue(ParamKnob *s) : slider(s) {}

ParamKnob *slider;

bool isReadOnly() const override { return false; }
double getCurrentValue() const override { return slider->getValue(); }
void setValue(double newValue) override
{
slider->setValue(newValue);

slider->repaint();
}
virtual juce::String getCurrentValueAsString() const override
{
if (slider->weakParam)
{
return slider->weakParam->getCurrentValueAsText();
}
return "";
}
void setValueAsString(const juce::String &) {}

AccessibleValueRange getRange() const override { return {{0, 1}, 0.01}; }

JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(AHValue);
};
struct AH : juce::AccessibilityHandler
{
AH(ParamKnob *c)
: juce::AccessibilityHandler(
*c, juce::AccessibilityRole::slider, juce::AccessibilityActions(),
AccessibilityHandler::Interfaces{std::make_unique<AHValue>(c)})
{
}
};

std::unique_ptr<juce::AccessibilityHandler> createAccessibilityHandler() override
{
return std::make_unique<AH>(this);
}
};

struct ParamDisp : juce::Component
Expand Down Expand Up @@ -482,10 +560,6 @@ struct ParamDisp : juce::Component
g.setFont(juce::Font(editor->jakartaSansSemi).withHeight(20));
g.drawText("No Parameters", b, juce::Justification::centredTop);
}
// g.setColour(juce::Colours::black.withAlpha(0.1f));
// g.fillRoundedRectangle(getLocalBounds().toFloat(), 3);
// g.setColour(juce::Colours::white.withAlpha(0.2f));
// g.drawRoundedRectangle(getLocalBounds().toFloat(), 3, 1);
return;
}
g.setColour(juce::Colours::black);
Expand All @@ -511,6 +585,7 @@ AWConsolidatedAudioProcessorEditor::AWConsolidatedAudioProcessorEditor(
juce::LookAndFeel::setDefaultLookAndFeel(lnf.get());
setAccessible(true);
setFocusContainerType(juce::Component::FocusContainerType::keyboardFocusContainer);
setWantsKeyboardFocus(true);

setSize(baseHeight, baseHeight);

Expand Down Expand Up @@ -599,6 +674,14 @@ AWConsolidatedAudioProcessorEditor::AWConsolidatedAudioProcessorEditor(
awTag->setBounds(fa);
addAndMakeVisible(*awTag);

accessibleOrderWeakRefs.push_back(menuPicker.get());
accessibleOrderWeakRefs.push_back(menuPicker->hamburger.get());
accessibleOrderWeakRefs.push_back(menuPicker->up.get());
accessibleOrderWeakRefs.push_back(menuPicker->down.get());
for (auto &k : knobs)
accessibleOrderWeakRefs.push_back(k.get());
accessibleOrderWeakRefs.push_back(docArea.get());

juce::PropertiesFile::Options options;
options.applicationName = "AirwindowsConsolidated";
options.folderName = "AirwindowsConsolidated";
Expand All @@ -622,6 +705,9 @@ void AWConsolidatedAudioProcessorEditor::idle()
if (docArea)
docArea->rebuild();

for (auto &k : knobs)
k->refreshModel();

repaint();
}
}
Expand Down Expand Up @@ -715,3 +801,66 @@ void AWConsolidatedAudioProcessorEditor::showMenu()

p.showMenuAsync(juce::PopupMenu::Options().withMaximumNumColumns(1));
}

struct FxFocusTrav : public juce::ComponentTraverser
{
FxFocusTrav(AWConsolidatedAudioProcessorEditor *ed) : editor(ed) {}
juce::Component *getDefaultComponent(juce::Component *parentComponent) override
{
return editor->menuPicker.get();
}
juce::Component *searchDir(juce::Component *from, int dir)
{
const auto iter = std::find(editor->accessibleOrderWeakRefs.cbegin(),
editor->accessibleOrderWeakRefs.cend(), from);
if (iter == editor->accessibleOrderWeakRefs.cend())
return nullptr;

switch (dir)
{
case 1:
{
auto res = std::next(iter);

while (res != editor->accessibleOrderWeakRefs.cend() && !(*res)->isAccessible())
{
res = std::next(res);
}
if (res != editor->accessibleOrderWeakRefs.cend())
return *res;
}
break;
case -1:
{
auto res = iter;

while (res != editor->accessibleOrderWeakRefs.cbegin() && !(*std::prev(res))->isAccessible())
{
res = std::prev(res);
}
if (res != editor->accessibleOrderWeakRefs.cbegin())
return *std::prev(res);
}
break;
}
return nullptr;
}
juce::Component *getNextComponent(juce::Component *current) override
{
return searchDir(current, 1);
}
juce::Component *getPreviousComponent(juce::Component *current) override
{
return searchDir(current, -1);
}
std::vector<juce::Component *> getAllComponents(juce::Component *parentComponent) override
{
return editor->accessibleOrderWeakRefs;
}
AWConsolidatedAudioProcessorEditor *editor{nullptr};
};

std::unique_ptr<juce::ComponentTraverser> AWConsolidatedAudioProcessorEditor::createKeyboardFocusTraverser()
{
return std::make_unique<FxFocusTrav>(this);
}
9 changes: 7 additions & 2 deletions src-juce/AWConsolidatedEditor.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
/**
*/
struct DocPanel;
struct ParamKnob;
struct Picker;
class AWConsolidatedAudioProcessorEditor : public juce::AudioProcessorEditor, juce::AsyncUpdater
{
public:
Expand Down Expand Up @@ -38,8 +40,8 @@ class AWConsolidatedAudioProcessorEditor : public juce::AudioProcessorEditor, ju
};
void idle();
std::unique_ptr<IdleTimer> idleTimer;
std::unique_ptr<juce::Component> menuPicker;
std::array<std::unique_ptr<juce::Component>, AWConsolidatedAudioProcessor::nAWParams> knobs;
std::unique_ptr<Picker> menuPicker;
std::array<std::unique_ptr<ParamKnob>, AWConsolidatedAudioProcessor::nAWParams> knobs;
std::array<std::unique_ptr<juce::Component>, AWConsolidatedAudioProcessor::nAWParams> labels;

std::unique_ptr<juce::Drawable> clipperIcon;
Expand All @@ -55,6 +57,9 @@ class AWConsolidatedAudioProcessorEditor : public juce::AudioProcessorEditor, ju
std::unique_ptr<juce::LookAndFeel_V4> lnf;
std::unique_ptr<juce::PropertiesFile> properties;

std::vector<juce::Component *> accessibleOrderWeakRefs;
std::unique_ptr<juce::ComponentTraverser> createKeyboardFocusTraverser() override;

// debugging
int gv{0}, bv{0};
#if 0
Expand Down

0 comments on commit 3d8a8a6

Please sign in to comment.