1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00

Examples/DemoRunner: Accessibility updates

This commit is contained in:
ed 2021-05-10 09:39:36 +01:00
parent 69085b2a61
commit f28acdb48c
10 changed files with 232 additions and 125 deletions

View file

@ -296,6 +296,7 @@ public:
directoryList.setDirectory (File::getSpecialLocation (File::userHomeDirectory), true, true); directoryList.setDirectory (File::getSpecialLocation (File::userHomeDirectory), true, true);
fileTreeComp.setTitle ("Files");
fileTreeComp.setColour (FileTreeComponent::backgroundColourId, Colours::lightgrey.withAlpha (0.6f)); fileTreeComp.setColour (FileTreeComponent::backgroundColourId, Colours::lightgrey.withAlpha (0.6f));
fileTreeComp.addListener (this); fileTreeComp.addListener (this);

View file

@ -44,6 +44,9 @@ public:
dontSendNotification); dontSendNotification);
linkButton.setColour (HyperlinkButton::textColourId, Colours::lightblue); linkButton.setColour (HyperlinkButton::textColourId, Colours::lightblue);
setTitle ("Home");
setFocusContainerType (FocusContainerType::focusContainer);
} }
void paint (Graphics& g) override void paint (Graphics& g) override
@ -72,6 +75,7 @@ private:
{ {
LogoDrawComponent() LogoDrawComponent()
{ {
setTitle ("JUCE Logo");
startTimerHz (30); // repaint at 30 fps startTimerHz (30); // repaint at 30 fps
} }
@ -110,6 +114,11 @@ private:
elapsed += 0.02f; elapsed += 0.02f;
} }
std::unique_ptr<AccessibilityHandler> createAccessibilityHandler() override
{
return std::make_unique<AccessibilityHandler> (*this, AccessibilityRole::image);
}
Path logoPath { getJUCELogoPath() }; Path logoPath { getJUCELogoPath() };
float elapsed = 0.0f; float elapsed = 0.0f;
}; };

View file

@ -165,21 +165,7 @@ public:
} }
g.setColour (textColour); g.setColour (textColour);
g.drawFittedText (getNameForRow (rowNumber), bounds, Justification::centred, 1);
if (selectedCategory.isEmpty())
{
if (isPositiveAndBelow (rowNumber, JUCEDemos::getCategories().size()))
g.drawFittedText (JUCEDemos::getCategories()[(size_t) rowNumber].name,
bounds, Justification::centred, 1);
}
else
{
auto& category = JUCEDemos::getCategory (selectedCategory);
if (isPositiveAndBelow (rowNumber, category.demos.size()))
g.drawFittedText (category.demos[(size_t) rowNumber].demoFile.getFileName(),
bounds, Justification::centred, 1);
}
} }
int getNumRows() override int getNumRows() override
@ -188,17 +174,27 @@ public:
: JUCEDemos::getCategory (selectedCategory).demos.size()); : JUCEDemos::getCategory (selectedCategory).demos.size());
} }
void selectedRowsChanged (int row) override String getNameForRow (int rowNumber) override
{ {
if (row < 0)
return;
if (selectedCategory.isEmpty()) if (selectedCategory.isEmpty())
showCategory (JUCEDemos::getCategories()[(size_t) row].name); {
if (isPositiveAndBelow (rowNumber, JUCEDemos::getCategories().size()))
return JUCEDemos::getCategories()[(size_t) rowNumber].name;
}
else else
demoHolder.setDemo (selectedCategory, row); {
auto& category = JUCEDemos::getCategory (selectedCategory);
if (isPositiveAndBelow (rowNumber, category.demos.size()))
return category.demos[(size_t) rowNumber].demoFile.getFileName();
}
return {};
} }
void returnKeyPressed (int row) override { selectRow (row); }
void listBoxItemClicked (int row, const MouseEvent&) override { selectRow (row); }
//============================================================================== //==============================================================================
void showCategory (const String& categoryName) noexcept void showCategory (const String& categoryName) noexcept
{ {
@ -206,37 +202,75 @@ public:
demos.deselectAllRows(); demos.deselectAllRows();
demos.setHeaderComponent (categoryName.isEmpty() ? nullptr demos.setHeaderComponent (categoryName.isEmpty() ? nullptr
: std::make_unique<Header> (*this)); : std::make_unique<CategoryListHeaderComponent> (*this));
demos.updateContent(); demos.updateContent();
} }
private: private:
String selectedCategory; //==============================================================================
class CategoryListHeaderComponent : public Button
DemoContentComponent& demoHolder;
ListBox demos;
struct Header : public Component
{ {
Header (DemoList& o) public:
: owner (o) explicit CategoryListHeaderComponent (DemoList& o)
: Button ({}),
owner (o)
{ {
setTitle ("Previous");
setSize (0, 30); setSize (0, 30);
} }
void paint (Graphics& g) override void paintButton (Graphics& g, bool, bool) override
{ {
g.setColour (findColour (Label::textColourId)); g.setColour (findColour (Label::textColourId));
g.drawFittedText ("<", getLocalBounds().reduced (20, 0), Justification::centredLeft, 1); g.drawFittedText ("<", getLocalBounds().reduced (20, 0), Justification::centredLeft, 1);
} }
void mouseDown (const MouseEvent&) override
void clicked() override
{ {
owner.showCategory ({}); owner.showCategory ({});
} }
using Button::clicked;
private:
DemoList& owner; DemoList& owner;
}; };
//==============================================================================
void selectRow (int row)
{
if (row < 0)
return;
if (selectedCategory.isEmpty())
showCategory (JUCEDemos::getCategories()[(size_t) row].name);
else
demoHolder.setDemo (selectedCategory, row);
selectFirstRow();
}
void selectFirstRow()
{
if (auto* handler = demos.getAccessibilityHandler())
{
for (auto* child : handler->getChildren())
{
if (child->getRole() == AccessibilityRole::listItem)
{
child->grabFocus();
break;
}
}
}
}
//==============================================================================
String selectedCategory;
DemoContentComponent& demoHolder;
ListBox demos;
}; };
//============================================================================== //==============================================================================
@ -266,6 +300,9 @@ MainComponent::MainComponent()
addAndMakeVisible (showDemosButton); addAndMakeVisible (showDemosButton);
addAndMakeVisible (demosPanel); addAndMakeVisible (demosPanel);
demosPanel.setTitle ("Demos");
demosPanel.setFocusContainerType (FocusContainerType::focusContainer);
showDemosButton.onClick = [this] { demosPanel.showOrHide (true); }; showDemosButton.onClick = [this] { demosPanel.showOrHide (true); };
demosPanel.onPanelMove = [this] demosPanel.onPanelMove = [this]
@ -284,6 +321,9 @@ MainComponent::MainComponent()
if (isShowingHeavyweightDemo) if (isShowingHeavyweightDemo)
resized(); resized();
if (auto* handler = demosPanel.getAccessibilityHandler())
handler->grabFocus();
} }
else else
{ {

View file

@ -37,6 +37,9 @@ public:
settingsViewport.setViewedComponent (&innerContent, false); settingsViewport.setViewedComponent (&innerContent, false);
addAndMakeVisible (settingsViewport); addAndMakeVisible (settingsViewport);
setFocusContainerType (FocusContainerType::focusContainer);
setTitle ("DemoRunner Settings");
setOpaque (true); setOpaque (true);
} }
@ -47,39 +50,43 @@ public:
void resized() override void resized() override
{ {
auto r = getLocalBounds(); constexpr int minimumWidth = 350;
auto scrollBarWidth = getLookAndFeel().getDefaultScrollbarWidth(); constexpr int minimumHeight = 550;
innerContent.setSize (jmax (r.getWidth() - scrollBarWidth, innerContent.getMinimumWidth()), auto r = getLocalBounds();
jmax (r.getHeight(), innerContent.getMinimumHeight())); const auto scrollBarWidth = getLookAndFeel().getDefaultScrollbarWidth();
innerContent.setSize (jmax (r.getWidth() - scrollBarWidth, minimumWidth),
jmax (r.getHeight(), minimumHeight));
settingsViewport.setBounds (r); settingsViewport.setBounds (r);
} }
private: private:
Viewport settingsViewport; static constexpr float titleLabelFontHeight = 18.0f;
static constexpr int itemHeight = 30;
static constexpr int itemSpacing = 7;
//============================================================================== class GraphicsSettingsGroup : public Component,
class InnerContent : public Component, private ComponentMovementWatcher
public ComponentMovementWatcher
{ {
public: public:
InnerContent (MainComponent& topLevelComponent) GraphicsSettingsGroup (MainComponent& comp)
: ComponentMovementWatcher (this), mainComponent (topLevelComponent) : ComponentMovementWatcher (&comp),
mainComponent (comp)
{ {
addAndMakeVisible (graphicsTitleLabel); addAndMakeVisible (titleLabel);
graphicsTitleLabel.setFont (18.0f); titleLabel.setFont (titleLabelFontHeight);
addAndMakeVisible (audioTitleLabel);
audioTitleLabel.setFont (18.0f);
addLookAndFeels(); addLookAndFeels();
addAndMakeVisible (lookAndFeelSelector); addAndMakeVisible (lookAndFeelSelector);
for (int i = 0; i < lookAndFeelNames.size(); ++i) for (int i = 0; i < lookAndFeelNames.size(); ++i)
lookAndFeelSelector.addItem (lookAndFeelNames.getReference (i), i + 1); lookAndFeelSelector.addItem (lookAndFeelNames.getReference (i), i + 1);
lookAndFeelSelector.setSelectedItemIndex (lookAndFeelNames.indexOf ("LookAndFeel_V4 (Dark)")); lookAndFeelSelector.setSelectedItemIndex (lookAndFeelNames.indexOf ("LookAndFeel_V4 (Dark)"));
lookAndFeelSelector.onChange = [this] lookAndFeelSelector.onChange = [this]
{ {
auto* lf = lookAndFeels.getUnchecked (lookAndFeelSelector.getSelectedItemIndex()); auto* lf = lookAndFeels.getUnchecked (lookAndFeelSelector.getSelectedItemIndex());
@ -97,87 +104,37 @@ private:
rendererLabel.setJustificationType (Justification::centredRight); rendererLabel.setJustificationType (Justification::centredRight);
rendererLabel.attachToComponent (&rendererSelector, true); rendererLabel.attachToComponent (&rendererSelector, true);
audioSettings.reset (new AudioDeviceSelectorComponent (getSharedAudioDeviceManager(), setFocusContainerType (FocusContainerType::focusContainer);
0, 256, 0, 256, true, true, true, false)); setTitle ("Graphics Settings");
addAndMakeVisible (audioSettings.get());
audioSettings->setItemHeight (itemHeight);
setOpaque (true);
}
void paint (Graphics& g) override
{
g.fillAll (findColour (ResizableWindow::backgroundColourId).contrasting (0.2f));
} }
void resized() override void resized() override
{ {
auto bounds = getLocalBounds(); auto bounds = getLocalBounds();
auto space = itemHeight / 4; titleLabel.setBounds (bounds.removeFromTop (itemHeight));
bounds.removeFromTop (itemSpacing);
graphicsTitleLabel.setBounds (bounds.removeFromTop (30)); const auto xPos = roundToInt ((float) bounds.getX() + ((float) bounds.getWidth() * 0.35f));
bounds.removeFromTop (space); const auto width = roundToInt ((float) bounds.getWidth() * 0.6f);
auto xPos = (float) bounds.getX() + ((float) bounds.getWidth() * 0.35f); lookAndFeelSelector.setBounds (bounds.removeFromTop (itemHeight).withWidth (width).withX (xPos));
auto width = (float) bounds.getWidth() * 0.6f; bounds.removeFromTop (itemSpacing);
lookAndFeelSelector.setBounds (bounds.removeFromTop (itemHeight).withWidth ((int) width).withX ((int) xPos)); rendererSelector.setBounds (bounds.removeFromTop (itemHeight).withWidth (width).withX (xPos));
bounds.removeFromTop (space);
rendererSelector.setBounds (bounds.removeFromTop (itemHeight).withWidth ((int) width).withX ((int) xPos));
bounds.removeFromTop (space);
audioTitleLabel.setBounds (bounds.removeFromTop (30));
bounds.removeFromTop (space);
audioSettings->setBounds (bounds);
} }
//==============================================================================
int getMinimumHeight() const noexcept { return 550; }
int getMinimumWidth() const noexcept { return 350; }
private: private:
MainComponent& mainComponent;
ComponentPeer* peer = nullptr;
const int itemHeight = 30;
Label graphicsTitleLabel { {}, "Graphics" },
audioTitleLabel { {}, "Audio" },
lookAndFeelLabel { {}, "LookAndFeel:" },
rendererLabel { {}, "Renderer:" };
ComboBox lookAndFeelSelector, rendererSelector;
StringArray lookAndFeelNames;
OwnedArray<LookAndFeel> lookAndFeels;
std::unique_ptr<AudioDeviceSelectorComponent> audioSettings;
//==============================================================================
void refreshRenderingEngineSelector()
{
StringArray renderingEngines (mainComponent.getRenderingEngines());
rendererSelector.clear (NotificationType::dontSendNotification);
for (int i = 0; i < renderingEngines.size(); ++i)
rendererSelector.addItem (renderingEngines.getReference (i), i + 1);
rendererSelector.setSelectedItemIndex (mainComponent.getCurrentRenderingEngine());
}
//==============================================================================
void componentMovedOrResized (bool, bool) override {} void componentMovedOrResized (bool, bool) override {}
using ComponentListener::componentMovedOrResized; using ComponentListener::componentMovedOrResized;
void componentVisibilityChanged() override {} void componentVisibilityChanged() override {}
using ComponentListener::componentVisibilityChanged; using ComponentListener::componentVisibilityChanged;
void componentPeerChanged() override void componentPeerChanged() override
{ {
auto* newPeer = getPeer(); auto* newPeer = mainComponent.getPeer();
if (peer != newPeer) if (peer != newPeer)
{ {
peer = newPeer; peer = newPeer;
@ -187,7 +144,14 @@ private:
} }
} }
//============================================================================== void refreshRenderingEngineSelector()
{
rendererSelector.clear (NotificationType::dontSendNotification);
rendererSelector.addItemList (mainComponent.getRenderingEngines(), 1);
rendererSelector.setSelectedItemIndex (mainComponent.getCurrentRenderingEngine());
}
void addLookAndFeels() void addLookAndFeels()
{ {
lookAndFeelNames.addArray ({ "LookAndFeel_V1", "LookAndFeel_V2", "LookAndFeel_V3", lookAndFeelNames.addArray ({ "LookAndFeel_V1", "LookAndFeel_V2", "LookAndFeel_V3",
@ -202,7 +166,81 @@ private:
lookAndFeels.add (new LookAndFeel_V4 (LookAndFeel_V4::getGreyColourScheme())); lookAndFeels.add (new LookAndFeel_V4 (LookAndFeel_V4::getGreyColourScheme()));
lookAndFeels.add (new LookAndFeel_V4 (LookAndFeel_V4::getLightColourScheme())); lookAndFeels.add (new LookAndFeel_V4 (LookAndFeel_V4::getLightColourScheme()));
} }
MainComponent& mainComponent;
ComponentPeer* peer = nullptr;
Label titleLabel { {}, "Graphics" },
lookAndFeelLabel { {}, "LookAndFeel:" },
rendererLabel { {}, "Renderer:" };
ComboBox lookAndFeelSelector, rendererSelector;
StringArray lookAndFeelNames;
OwnedArray<LookAndFeel> lookAndFeels;
}; };
class AudioSettingsGroup : public Component
{
public:
AudioSettingsGroup()
: deviceSelectorComp (getSharedAudioDeviceManager(), 0, 256, 0, 256, true, true, true, false)
{
addAndMakeVisible (titleLabel);
titleLabel.setFont (titleLabelFontHeight);
addAndMakeVisible (deviceSelectorComp);
deviceSelectorComp.setItemHeight (itemHeight);
setFocusContainerType (FocusContainerType::focusContainer);
setTitle ("Audio Settings");
}
void resized() override
{
auto bounds = getLocalBounds();
titleLabel.setBounds (bounds.removeFromTop (itemHeight));
bounds.removeFromTop (itemSpacing);
deviceSelectorComp.setBounds (bounds);
}
private:
Label titleLabel { {}, "Audio" };
AudioDeviceSelectorComponent deviceSelectorComp;
};
//==============================================================================
class InnerContent : public Component
{
public:
InnerContent (MainComponent& mainComponent)
: graphicsSettings (mainComponent)
{
addAndMakeVisible (graphicsSettings);
addAndMakeVisible (audioSettings);
setOpaque (true);
}
void paint (Graphics& g) override
{
g.fillAll (findColour (ResizableWindow::backgroundColourId).contrasting (0.2f));
}
void resized() override
{
auto bounds = getLocalBounds();
graphicsSettings.setBounds (bounds.removeFromTop (150));
audioSettings.setBounds (bounds);
}
private:
GraphicsSettingsGroup graphicsSettings;
AudioSettingsGroup audioSettings;
};
Viewport settingsViewport;
InnerContent innerContent; InnerContent innerContent;
}; };

View file

@ -94,6 +94,7 @@ public:
Font::findFonts (fonts); // Generate the list of fonts Font::findFonts (fonts); // Generate the list of fonts
listBox.setTitle ("Fonts");
listBox.setRowHeight (20); listBox.setRowHeight (20);
listBox.setModel (this); // Tell the listbox where to get its data model listBox.setModel (this); // Tell the listbox where to get its data model
listBox.setColour (ListBox::textColourId, Colours::black); listBox.setColour (ListBox::textColourId, Colours::black);
@ -218,12 +219,17 @@ public:
AttributedString s; AttributedString s;
s.setWordWrap (AttributedString::none); s.setWordWrap (AttributedString::none);
s.setJustification (Justification::centredLeft); s.setJustification (Justification::centredLeft);
s.append (font.getTypefaceName(), font.withHeight ((float) height * 0.7f), Colours::black); s.append (getNameForRow (rowNumber), font.withHeight ((float) height * 0.7f), Colours::black);
s.append (" " + font.getTypefaceName(), Font ((float) height * 0.5f, Font::italic), Colours::grey); s.append (" " + font.getTypefaceName(), Font ((float) height * 0.5f, Font::italic), Colours::grey);
s.draw (g, Rectangle<int> (width, height).expanded (-4, 50).toFloat()); s.draw (g, Rectangle<int> (width, height).expanded (-4, 50).toFloat());
} }
String getNameForRow (int rowNumber) override
{
return fonts[rowNumber].getTypefaceName();
}
void selectedRowsChanged (int /*lastRowselected*/) override void selectedRowsChanged (int /*lastRowselected*/) override
{ {
refreshPreviewBoxFont(); refreshPreviewBoxFont();

View file

@ -644,35 +644,44 @@ public:
demos.add (new LinesDemo (controls)); demos.add (new LinesDemo (controls));
addAndMakeVisible (listBox); addAndMakeVisible (listBox);
listBox.setTitle ("Test List");
listBox.setModel (this); listBox.setModel (this);
listBox.selectRow (0); listBox.selectRow (0);
} }
void resized() void resized() override
{ {
listBox.setBounds (getLocalBounds()); listBox.setBounds (getLocalBounds());
} }
int getNumRows() int getNumRows() override
{ {
return demos.size(); return demos.size();
} }
void paintListBoxItem (int rowNumber, Graphics& g, int width, int height, bool rowIsSelected) void paintListBoxItem (int rowNumber, Graphics& g, int width, int height, bool rowIsSelected) override
{ {
if (auto* demo = demos[rowNumber]) if (demos[rowNumber] == nullptr)
{ return;
if (rowIsSelected)
g.fillAll (Colour::contrasting (findColour (ListBox::textColourId),
findColour (ListBox::backgroundColourId)));
g.setColour (findColour (ListBox::textColourId)); if (rowIsSelected)
g.setFont (14.0f); g.fillAll (Colour::contrasting (findColour (ListBox::textColourId),
g.drawFittedText (demo->getName(), 8, 0, width - 10, height, Justification::centredLeft, 2); findColour (ListBox::backgroundColourId)));
}
g.setColour (findColour (ListBox::textColourId));
g.setFont (14.0f);
g.drawFittedText (getNameForRow (rowNumber), 8, 0, width - 10, height, Justification::centredLeft, 2);
} }
void selectedRowsChanged (int lastRowSelected) String getNameForRow (int rowNumber) override
{
if (auto* demo = demos[rowNumber])
return demo->getName();
return {};
}
void selectedRowsChanged (int lastRowSelected) override
{ {
demoHolder.setDemo (demos [lastRowSelected]); demoHolder.setDemo (demos [lastRowSelected]);
} }

View file

@ -59,6 +59,7 @@ public:
imageList.setDirectory (File::getSpecialLocation (File::userPicturesDirectory), true, true); imageList.setDirectory (File::getSpecialLocation (File::userPicturesDirectory), true, true);
directoryThread.startThread (1); directoryThread.startThread (1);
fileTree.setTitle ("Files");
fileTree.addListener (this); fileTree.addListener (this);
fileTree.setColour (TreeView::backgroundColourId, Colours::grey); fileTree.setColour (TreeView::backgroundColourId, Colours::grey);
addAndMakeVisible (fileTree); addAndMakeVisible (fileTree);

View file

@ -156,6 +156,7 @@ public:
movieList.setDirectory (File::getSpecialLocation (File::userMoviesDirectory), true, true); movieList.setDirectory (File::getSpecialLocation (File::userMoviesDirectory), true, true);
directoryThread.startThread (1); directoryThread.startThread (1);
fileTree.setTitle ("Files");
fileTree.addListener (this); fileTree.addListener (this);
fileTree.setColour (FileTreeComponent::backgroundColourId, Colours::lightgrey.withAlpha (0.6f)); fileTree.setColour (FileTreeComponent::backgroundColourId, Colours::lightgrey.withAlpha (0.6f));
addAndMakeVisible (fileTree); addAndMakeVisible (fileTree);

View file

@ -188,6 +188,7 @@ public:
{ {
addAndMakeVisible (tree); addAndMakeVisible (tree);
tree.setTitle ("ValueTree");
tree.setDefaultOpenness (true); tree.setDefaultOpenness (true);
tree.setMultiSelectEnabled (true); tree.setMultiSelectEnabled (true);
rootItem.reset (new ValueTreeItem (createRootValueTree(), undoManager)); rootItem.reset (new ValueTreeItem (createRootValueTree(), undoManager));

View file

@ -262,6 +262,7 @@ public:
addAndMakeVisible (codeDocumentComponent); addAndMakeVisible (codeDocumentComponent);
codeDocument.addListener (this); codeDocument.addListener (this);
resultsTree.setTitle ("Results");
addAndMakeVisible (resultsTree); addAndMakeVisible (resultsTree);
resultsTree.setColour (TreeView::backgroundColourId, Colours::white); resultsTree.setColour (TreeView::backgroundColourId, Colours::white);
resultsTree.setDefaultOpenness (true); resultsTree.setDefaultOpenness (true);