Accessibility: narrate pictureboxes

Pipes the Showdown Set description or object detail dump into the accessible property. When the control Enter event is fired, send an Automation notification so that the Narrator narrates what was just tabbed to.

Closes #3758
This commit is contained in:
Kurt 2023-02-05 00:42:37 -08:00
parent 627965e6ed
commit 79a05caff5
10 changed files with 102 additions and 15 deletions

View file

@ -4,6 +4,7 @@ using System.Windows.Forms;
using PKHeX.Core; using PKHeX.Core;
using PKHeX.Drawing.PokeSprite; using PKHeX.Drawing.PokeSprite;
using PKHeX.WinForms.Controls;
namespace PKHeX.WinForms; namespace PKHeX.WinForms;
@ -64,16 +65,25 @@ public partial class BallBrowser : Form
private PictureBox GetBallView(int ballID, string name, bool valid) private PictureBox GetBallView(int ballID, string name, bool valid)
{ {
var img = SpriteUtil.GetBallSprite(ballID); var img = SpriteUtil.GetBallSprite(ballID);
var pb = new PictureBox var pb = new SelectablePictureBox
{ {
Size = img.Size, Size = img.Size,
Image = img, Image = img,
BackgroundImage = valid ? SpriteUtil.Spriter.Set : SpriteUtil.Spriter.Delete, BackgroundImage = valid ? SpriteUtil.Spriter.Set : SpriteUtil.Spriter.Delete,
BackgroundImageLayout = ImageLayout.Tile, BackgroundImageLayout = ImageLayout.Tile,
Name = name,
AccessibleDescription = name,
AccessibleName = name,
AccessibleRole = AccessibleRole.Graphic,
}; };
pb.MouseEnter += (_, _) => Text = name; pb.MouseEnter += (_, _) => Text = name;
pb.Click += (_, _) => SelectBall(ballID); pb.Click += (_, _) => SelectBall(ballID);
pb.KeyDown += (_, e) =>
{
if (e.KeyCode == Keys.Enter)
SelectBall(ballID);
};
return pb; return pb;
} }

View file

@ -1,5 +1,6 @@
using System; using System;
using System.Windows.Forms; using System.Windows.Forms;
using System.Windows.Forms.Automation;
namespace PKHeX.WinForms.Controls; namespace PKHeX.WinForms.Controls;
@ -16,6 +17,8 @@ public class SelectablePictureBox : PictureBox
{ {
Invalidate(); Invalidate();
base.OnEnter(e); base.OnEnter(e);
AccessibilityObject.RaiseAutomationNotification(AutomationNotificationKind.Other,
AutomationNotificationProcessing.All, AccessibleDescription ?? AccessibleName ?? "");
} }
protected override void OnLeave(EventArgs e) protected override void OnLeave(EventArgs e)
{ {

View file

@ -57,8 +57,9 @@ public partial class PokeGrid : UserControl
var y = padEdge + (row * (rowHeight + border)); var y = padEdge + (row * (rowHeight + border));
for (int column = 0; column < width; column++) for (int column = 0; column < width; column++)
{ {
var name = $"Pokémon Grid Row {row:00} Column {column:00}";
var x = padEdge + (column * (colWidth + border)); var x = padEdge + (column * (colWidth + border));
var pb = GetControl(sizeW, sizeH); var pb = GetControl(sizeW, sizeH, name);
pb.Location = new Point(x, y); pb.Location = new Point(x, y);
Entries.Add(pb); Entries.Add(pb);
} }
@ -74,7 +75,7 @@ public partial class PokeGrid : UserControl
public void SetBackground(Image img) => BackgroundImage = img; public void SetBackground(Image img) => BackgroundImage = img;
public static SelectablePictureBox GetControl(int width, int height) => new() public static SelectablePictureBox GetControl(int width, int height, string name) => new()
{ {
AutoSize = false, AutoSize = false,
SizeMode = PictureBoxSizeMode.CenterImage, SizeMode = PictureBoxSizeMode.CenterImage,
@ -84,5 +85,8 @@ public partial class PokeGrid : UserControl
Padding = Padding.Empty, Padding = Padding.Empty,
Margin = Padding.Empty, Margin = Padding.Empty,
BorderStyle = BorderStyle.FixedSingle, BorderStyle = BorderStyle.FixedSingle,
AccessibleRole = AccessibleRole.Alert,
Name = name,
AccessibleName = name,
}; };
} }

View file

@ -126,7 +126,8 @@ public partial class SlotList : UserControl, ISlotViewer<PictureBox>
return; return;
for (int i = 0; i < diff; i++) for (int i = 0; i < diff; i++)
{ {
var slot = GetPictureBox(i, SpriteUtil.Spriter); var name = $"bpkm{before + i}";
var slot = GetPictureBox(SpriteUtil.Spriter, name);
enableDragDropContext(slot); enableDragDropContext(slot);
slots.Add(slot); slots.Add(slot);
} }
@ -134,7 +135,7 @@ public partial class SlotList : UserControl, ISlotViewer<PictureBox>
private const int PadPixels = 2; private const int PadPixels = 2;
private static PictureBox GetPictureBox(int index, SpriteBuilder s) => new() private static SelectablePictureBox GetPictureBox(SpriteBuilder s, string name) => new()
{ {
BorderStyle = BorderStyle.FixedSingle, BorderStyle = BorderStyle.FixedSingle,
Width = s.Width + 2, Width = s.Width + 2,
@ -143,7 +144,9 @@ public partial class SlotList : UserControl, ISlotViewer<PictureBox>
Margin = new Padding(PadPixels), Margin = new Padding(PadPixels),
Padding = Padding.Empty, Padding = Padding.Empty,
SizeMode = PictureBoxSizeMode.CenterImage, SizeMode = PictureBoxSizeMode.CenterImage,
Name = $"bpkm{index}", Name = name,
AccessibleName = name,
AccessibleRole = AccessibleRole.Graphic,
}; };
private void AddLabels() private void AddLabels()

View file

@ -1,4 +1,4 @@
using System; using System;
using System.Drawing; using System.Drawing;
using System.Windows.Forms; using System.Windows.Forms;
using PKHeX.Core; using PKHeX.Core;
@ -66,5 +66,6 @@ public static class SlotUtil
pb.BackColor = Color.Transparent; pb.BackColor = Color.Transparent;
pb.Image = img; pb.Image = img;
pb.AccessibleDescription = ShowdownParsing.GetLocalizedPreviewText(p, Main.CurrentLanguage);
} }
} }

View file

@ -5,6 +5,7 @@ using System.Linq;
using System.Windows.Forms; using System.Windows.Forms;
using PKHeX.Core; using PKHeX.Core;
using PKHeX.Drawing.Misc; using PKHeX.Drawing.Misc;
using PKHeX.WinForms.Controls;
namespace PKHeX.WinForms; namespace PKHeX.WinForms;
@ -141,7 +142,17 @@ public partial class RibbonEditor : Form
private void AddRibbonSprite(RibbonInfo rib) private void AddRibbonSprite(RibbonInfo rib)
{ {
var name = rib.Name; var name = rib.Name;
var pb = new PictureBox { AutoSize = false, Size = new Size(40,40), BackgroundImageLayout = ImageLayout.Center, Visible = false, Name = PrefixPB + name }; var pb = new SelectablePictureBox
{
AutoSize = false,
Size = new Size(40,40),
BackgroundImageLayout = ImageLayout.Center,
Visible = false,
Name = PrefixPB + name,
AccessibleName = name,
AccessibleDescription = name,
AccessibleRole = AccessibleRole.Graphic,
};
var img = RibbonSpriteUtil.GetRibbonSprite(name); var img = RibbonSpriteUtil.GetRibbonSprite(name);
pb.BackgroundImage = img; pb.BackgroundImage = img;

View file

@ -78,6 +78,20 @@ public partial class SAV_Database : Form
slot.ContextMenuStrip = mnu; slot.ContextMenuStrip = mnu;
if (Main.Settings.Hover.HoverSlotShowText) if (Main.Settings.Hover.HoverSlotShowText)
slot.MouseEnter += (o, args) => ShowHoverTextForSlot(slot, args); slot.MouseEnter += (o, args) => ShowHoverTextForSlot(slot, args);
slot.Enter += (sender, e) =>
{
if (sender is not PictureBox pb)
return;
var index = Array.IndexOf(PKXBOXES, sender);
if (index < 0)
return;
index += (SCR_Box.Value * RES_MIN);
if (index >= Results.Count)
return;
var pk = Results[index];
pb.AccessibleDescription = ShowdownParsing.GetLocalizedPreviewText(pk.Entity, Main.CurrentLanguage);
};
} }
Counter = L_Count.Text; Counter = L_Count.Text;

View file

@ -68,6 +68,20 @@ public partial class SAV_Encounters : Form
if (ModifierKeys == Keys.Control) if (ModifierKeys == Keys.Control)
ClickView(sender, e); ClickView(sender, e);
}; };
slot.Enter += (sender, e) =>
{
if (sender is not PictureBox pb)
return;
var index = Array.IndexOf(PKXBOXES, sender);
if (index < 0)
return;
index += (SCR_Box.Value * RES_MIN);
if (index >= Results.Count)
return;
var enc = Results[index];
pb.AccessibleDescription = string.Join(Environment.NewLine, SummaryPreviewer.GetTextLines(enc));
};
slot.ContextMenuStrip = mnu; slot.ContextMenuStrip = mnu;
if (Main.Settings.Hover.HoverSlotShowText) if (Main.Settings.Hover.HoverSlotShowText)
slot.MouseEnter += (o, args) => ShowHoverTextForSlot(slot, args); slot.MouseEnter += (o, args) => ShowHoverTextForSlot(slot, args);
@ -434,8 +448,9 @@ public partial class SAV_Encounters : Form
int end = Math.Min(RES_MAX, Results.Count - begin); int end = Math.Min(RES_MAX, Results.Count - begin);
for (int i = 0; i < end; i++) for (int i = 0; i < end; i++)
{ {
var pb = boxes[i];
var enc = Results[i + begin]; var enc = Results[i + begin];
boxes[i].Image = enc.Sprite(); pb.Image = enc.Sprite();
} }
// Clear empty slots // Clear empty slots

View file

@ -71,6 +71,20 @@ public partial class SAV_MysteryGiftDB : Form
slot.ContextMenuStrip = mnu; slot.ContextMenuStrip = mnu;
slot.MouseEnter += (o, args) => ShowHoverTextForSlot(slot, args); slot.MouseEnter += (o, args) => ShowHoverTextForSlot(slot, args);
slot.Enter += (sender, e) =>
{
if (sender is not PictureBox pb)
return;
var index = Array.IndexOf(PKXBOXES, sender);
if (index < 0)
return;
index += (SCR_Box.Value * RES_MIN);
if (index >= Results.Count)
return;
var enc = Results[index];
pb.AccessibleDescription = string.Join(Environment.NewLine, SummaryPreviewer.GetTextLines(enc));
};
} }
Counter = L_Count.Text; Counter = L_Count.Text;

View file

@ -41,6 +41,15 @@ public partial class SAV_Wondercard : Form
pb.MouseDown += BoxSlot_MouseDown; pb.MouseDown += BoxSlot_MouseDown;
pb.ContextMenuStrip = mnuVSD; pb.ContextMenuStrip = mnuVSD;
pb.MouseHover += (_, _) => Summary.Show(pb, mga.Gifts[pba.IndexOf(pb)]); pb.MouseHover += (_, _) => Summary.Show(pb, mga.Gifts[pba.IndexOf(pb)]);
pb.Enter += (sender, e) =>
{
var index = pba.IndexOf(pb);
if (index < 0)
return;
var enc = mga.Gifts[index];
pb.AccessibleDescription = string.Join(Environment.NewLine, SummaryPreviewer.GetTextLines(enc));
};
} }
SetGiftBoxes(); SetGiftBoxes();
@ -590,7 +599,7 @@ public partial class SAV_Wondercard : Form
f1.Controls.Add(GetLabel($"{nameof(PGT)} 1-6")); f1.Controls.Add(GetLabel($"{nameof(PGT)} 1-6"));
for (int i = 0; i < 6; i++) for (int i = 0; i < 6; i++)
{ {
var p = GetPictureBox(spriter.Width, spriter.Height); var p = GetPictureBox(spriter.Width, spriter.Height, $"PGT {i + 1}");
f1.Controls.Add(p); f1.Controls.Add(p);
pb.Add(p); pb.Add(p);
} }
@ -599,7 +608,7 @@ public partial class SAV_Wondercard : Form
f2.Controls.Add(GetLabel($"{nameof(PGT)} 7-8")); f2.Controls.Add(GetLabel($"{nameof(PGT)} 7-8"));
for (int i = 6; i < 8; i++) for (int i = 6; i < 8; i++)
{ {
var p = GetPictureBox(spriter.Width, spriter.Height); var p = GetPictureBox(spriter.Width, spriter.Height, $"PGT {i + 1}");
f2.Controls.Add(p); f2.Controls.Add(p);
pb.Add(p); pb.Add(p);
} }
@ -609,7 +618,7 @@ public partial class SAV_Wondercard : Form
f3.Controls.Add(GetLabel($"{nameof(PCD)} 1-3")); f3.Controls.Add(GetLabel($"{nameof(PCD)} 1-3"));
for (int i = 8; i < 11; i++) for (int i = 8; i < 11; i++)
{ {
var p = GetPictureBox(spriter.Width, spriter.Height); var p = GetPictureBox(spriter.Width, spriter.Height, $"PCD {i - 7}");
f3.Controls.Add(p); f3.Controls.Add(p);
pb.Add(p); pb.Add(p);
} }
@ -624,7 +633,7 @@ public partial class SAV_Wondercard : Form
var f4 = GetFlowLayoutPanel(); var f4 = GetFlowLayoutPanel();
f4.Controls.Add(GetLabel(GameInfo.Strings.Item[533])); // Lock Capsule f4.Controls.Add(GetLabel(GameInfo.Strings.Item[533])); // Lock Capsule
{ {
var p = GetPictureBox(spriter.Width, spriter.Height); var p = GetPictureBox(spriter.Width, spriter.Height, "PCD Lock Capsule");
f4.Controls.Add(p); f4.Controls.Add(p);
pb.Add(p); pb.Add(p);
} }
@ -651,7 +660,7 @@ public partial class SAV_Wondercard : Form
row.Controls.Add(GetLabel($"{start}-{start + count - 1}")); row.Controls.Add(GetLabel($"{start}-{start + count - 1}"));
for (int j = 0; j < count; j++) for (int j = 0; j < count; j++)
{ {
var p = GetPictureBox(spriter.Width, spriter.Height); var p = GetPictureBox(spriter.Width, spriter.Height, $"Row {i} Slot {start + j}");
row.Controls.Add(p); row.Controls.Add(p);
pb.Add(p); pb.Add(p);
} }
@ -678,7 +687,7 @@ public partial class SAV_Wondercard : Form
Margin = new Padding(0), Margin = new Padding(0),
}; };
private static SelectablePictureBox GetPictureBox(int width, int height) => new() private static SelectablePictureBox GetPictureBox(int width, int height, string name) => new()
{ {
Size = new Size(width + 2, height + 2), // +1 to each side for the FixedSingle border Size = new Size(width + 2, height + 2), // +1 to each side for the FixedSingle border
SizeMode = PictureBoxSizeMode.CenterImage, SizeMode = PictureBoxSizeMode.CenterImage,
@ -686,6 +695,9 @@ public partial class SAV_Wondercard : Form
BackColor = SlotUtil.GoodDataColor, BackColor = SlotUtil.GoodDataColor,
Padding = new Padding(0), Padding = new Padding(0),
Margin = new Padding(1), Margin = new Padding(1),
Name = name,
AccessibleName = name,
AccessibleRole = AccessibleRole.Graphic,
}; };
private void B_ModifyAll_Click(object sender, EventArgs e) private void B_ModifyAll_Click(object sender, EventArgs e)