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

View file

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

View file

@ -57,8 +57,9 @@ public partial class PokeGrid : UserControl
var y = padEdge + (row * (rowHeight + border));
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 pb = GetControl(sizeW, sizeH);
var pb = GetControl(sizeW, sizeH, name);
pb.Location = new Point(x, y);
Entries.Add(pb);
}
@ -74,7 +75,7 @@ public partial class PokeGrid : UserControl
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,
SizeMode = PictureBoxSizeMode.CenterImage,
@ -84,5 +85,8 @@ public partial class PokeGrid : UserControl
Padding = Padding.Empty,
Margin = Padding.Empty,
BorderStyle = BorderStyle.FixedSingle,
AccessibleRole = AccessibleRole.Alert,
Name = name,
AccessibleName = name,
};
}

View file

@ -126,7 +126,8 @@ public partial class SlotList : UserControl, ISlotViewer<PictureBox>
return;
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);
slots.Add(slot);
}
@ -134,7 +135,7 @@ public partial class SlotList : UserControl, ISlotViewer<PictureBox>
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,
Width = s.Width + 2,
@ -143,7 +144,9 @@ public partial class SlotList : UserControl, ISlotViewer<PictureBox>
Margin = new Padding(PadPixels),
Padding = Padding.Empty,
SizeMode = PictureBoxSizeMode.CenterImage,
Name = $"bpkm{index}",
Name = name,
AccessibleName = name,
AccessibleRole = AccessibleRole.Graphic,
};
private void AddLabels()

View file

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

View file

@ -5,6 +5,7 @@ using System.Linq;
using System.Windows.Forms;
using PKHeX.Core;
using PKHeX.Drawing.Misc;
using PKHeX.WinForms.Controls;
namespace PKHeX.WinForms;
@ -141,7 +142,17 @@ public partial class RibbonEditor : Form
private void AddRibbonSprite(RibbonInfo rib)
{
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);
pb.BackgroundImage = img;

View file

@ -78,6 +78,20 @@ public partial class SAV_Database : Form
slot.ContextMenuStrip = mnu;
if (Main.Settings.Hover.HoverSlotShowText)
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;

View file

@ -68,6 +68,20 @@ public partial class SAV_Encounters : Form
if (ModifierKeys == Keys.Control)
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;
if (Main.Settings.Hover.HoverSlotShowText)
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);
for (int i = 0; i < end; i++)
{
var pb = boxes[i];
var enc = Results[i + begin];
boxes[i].Image = enc.Sprite();
pb.Image = enc.Sprite();
}
// Clear empty slots

View file

@ -71,6 +71,20 @@ public partial class SAV_MysteryGiftDB : Form
slot.ContextMenuStrip = mnu;
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;

View file

@ -41,6 +41,15 @@ public partial class SAV_Wondercard : Form
pb.MouseDown += BoxSlot_MouseDown;
pb.ContextMenuStrip = mnuVSD;
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();
@ -590,7 +599,7 @@ public partial class SAV_Wondercard : Form
f1.Controls.Add(GetLabel($"{nameof(PGT)} 1-6"));
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);
pb.Add(p);
}
@ -599,7 +608,7 @@ public partial class SAV_Wondercard : Form
f2.Controls.Add(GetLabel($"{nameof(PGT)} 7-8"));
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);
pb.Add(p);
}
@ -609,7 +618,7 @@ public partial class SAV_Wondercard : Form
f3.Controls.Add(GetLabel($"{nameof(PCD)} 1-3"));
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);
pb.Add(p);
}
@ -624,7 +633,7 @@ public partial class SAV_Wondercard : Form
var f4 = GetFlowLayoutPanel();
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);
pb.Add(p);
}
@ -651,7 +660,7 @@ public partial class SAV_Wondercard : Form
row.Controls.Add(GetLabel($"{start}-{start + count - 1}"));
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);
pb.Add(p);
}
@ -678,7 +687,7 @@ public partial class SAV_Wondercard : Form
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
SizeMode = PictureBoxSizeMode.CenterImage,
@ -686,6 +695,9 @@ public partial class SAV_Wondercard : Form
BackColor = SlotUtil.GoodDataColor,
Padding = new Padding(0),
Margin = new Padding(1),
Name = name,
AccessibleName = name,
AccessibleRole = AccessibleRole.Graphic,
};
private void B_ModifyAll_Click(object sender, EventArgs e)