From 27b2fe741ca43c1db8df39814482d844aefce927 Mon Sep 17 00:00:00 2001 From: Robert McRackan Date: Tue, 7 May 2024 10:39:30 -0400 Subject: [PATCH] Add accessibility --- .../AccessibleDataGridViewButtonCell.cs | 49 ++++++++++++++ .../AccessibleDataGridViewTextBoxCell.cs | 49 ++++++++++++++ .../Dialogs/AccountsDialog.cs | 14 ++-- .../Dialogs/EditQuickFilters.cs | 38 +++++++---- .../GridView/DataGridViewImageButtonCell.cs | 9 +-- .../EditTagsDataGridViewImageButtonColumn.cs | 29 ++++++--- .../GridView/LastDownloadedGridViewColumn.cs | 20 +++--- .../LiberateDataGridViewImageButtonColumn.cs | 23 +------ .../GridView/MyRatingGridViewColumn.cs | 25 +++---- .../SeriesView/DownloadButtonColumn.cs | 65 ++++++++++--------- 10 files changed, 220 insertions(+), 101 deletions(-) create mode 100644 Source/LibationWinForms/AccessibleDataGridViewButtonCell.cs create mode 100644 Source/LibationWinForms/AccessibleDataGridViewTextBoxCell.cs diff --git a/Source/LibationWinForms/AccessibleDataGridViewButtonCell.cs b/Source/LibationWinForms/AccessibleDataGridViewButtonCell.cs new file mode 100644 index 00000000..a580f14f --- /dev/null +++ b/Source/LibationWinForms/AccessibleDataGridViewButtonCell.cs @@ -0,0 +1,49 @@ +using System.Windows.Forms; + +namespace LibationWinForms +{ + public class AccessibleDataGridViewButtonCell : DataGridViewButtonCell + { + protected string AccessibilityName + { + get => MyAccessibilityObject.AccessibilityName; + set => MyAccessibilityObject.AccessibilityName = value; + } + + /// + /// Get or set description for accessibility. eg: screen readers. Also sets the ToolTipText + /// + protected string AccessibilityDescription + { + get => MyAccessibilityObject.AccessibilityDescription; + set + { + MyAccessibilityObject.AccessibilityDescription = value; + MyAccessibilityObject.Owner.ToolTipText = value; + } + } + + protected ButtonCellAccessibilityObject MyAccessibilityObject { get; set; } + protected override AccessibleObject CreateAccessibilityInstance() => MyAccessibilityObject; + + public AccessibleDataGridViewButtonCell(string accessibilityName) : base() + { + MyAccessibilityObject = new(this, name: accessibilityName, description: ""); + } + + protected class ButtonCellAccessibilityObject : DataGridViewButtonCellAccessibleObject + { + public string AccessibilityName { get; set; } + public string AccessibilityDescription { get; set; } + + public override string Name => AccessibilityName; + public override string Description => AccessibilityDescription; + + public ButtonCellAccessibilityObject(DataGridViewCell owner, string name, string description) : base(owner) + { + AccessibilityName = name; + AccessibilityDescription = description; + } + } + } +} diff --git a/Source/LibationWinForms/AccessibleDataGridViewTextBoxCell.cs b/Source/LibationWinForms/AccessibleDataGridViewTextBoxCell.cs new file mode 100644 index 00000000..33c0707e --- /dev/null +++ b/Source/LibationWinForms/AccessibleDataGridViewTextBoxCell.cs @@ -0,0 +1,49 @@ +using System.Windows.Forms; + +namespace LibationWinForms +{ + internal class AccessibleDataGridViewTextBoxCell : DataGridViewTextBoxCell + { + protected virtual string AccessibilityName + { + get => MyAccessibilityObject.AccessibilityName; + set => MyAccessibilityObject.AccessibilityName = value; + } + + /// + /// Get or set description for accessibility. eg: screen readers. Also sets the ToolTipText + /// + protected string AccessibilityDescription + { + get => MyAccessibilityObject.AccessibilityDescription; + set + { + MyAccessibilityObject.AccessibilityDescription = value; + MyAccessibilityObject.Owner.ToolTipText = value; + } + } + + protected ButtonCellAccessibilityObject MyAccessibilityObject { get; set; } + protected override AccessibleObject CreateAccessibilityInstance() => MyAccessibilityObject; + + public AccessibleDataGridViewTextBoxCell(string accessibilityName) : base() + { + MyAccessibilityObject = new(this, name: accessibilityName, description: ""); + } + + protected class ButtonCellAccessibilityObject : DataGridViewTextBoxCellAccessibleObject + { + public string AccessibilityName { get; set; } + public string AccessibilityDescription { get; set; } + + public override string Name => AccessibilityName; + public override string Description => AccessibilityDescription; + + public ButtonCellAccessibilityObject(DataGridViewCell owner, string name, string description) : base(owner) + { + AccessibilityName = name; + AccessibilityDescription = description; + } + } + } +} diff --git a/Source/LibationWinForms/Dialogs/AccountsDialog.cs b/Source/LibationWinForms/Dialogs/AccountsDialog.cs index d60c2f1e..4ee571bf 100644 --- a/Source/LibationWinForms/Dialogs/AccountsDialog.cs +++ b/Source/LibationWinForms/Dialogs/AccountsDialog.cs @@ -51,13 +51,13 @@ namespace LibationWinForms.Dialogs private void AddAccountToGrid(Account account) { - int row = dataGridView1.Rows.Add( - "X", - "Export", - account.LibraryScan, - account.AccountId, - account.Locale.Name, - account.AccountName); + var row = dataGridView1.Rows.Add( + "X", + "Export", + account.LibraryScan, + account.AccountId, + account.Locale.Name, + account.AccountName); dataGridView1[COL_Export, row].ToolTipText = "Export account authorization to audible-cli"; } diff --git a/Source/LibationWinForms/Dialogs/EditQuickFilters.cs b/Source/LibationWinForms/Dialogs/EditQuickFilters.cs index a70fb1dc..7d9dd661 100644 --- a/Source/LibationWinForms/Dialogs/EditQuickFilters.cs +++ b/Source/LibationWinForms/Dialogs/EditQuickFilters.cs @@ -24,23 +24,39 @@ namespace LibationWinForms.Dialogs private const string COL_MoveUp = nameof(MoveUp); private const string COL_MoveDown = nameof(MoveDown); - internal class DisableButtonCell : DataGridViewButtonCell - { - protected override void Paint(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewElementStates elementState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts) + internal class DisableButtonCell : AccessibleDataGridViewButtonCell + { + private int LastRowIndex => DataGridView.Rows[^1].IsNewRow ? DataGridView.Rows[^1].Index - 1 : DataGridView.Rows[^1].Index; + + public DisableButtonCell() : base("Edit Filter button") { } + + protected override void Paint(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewElementStates elementState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts) { - if ((OwningColumn.Name == COL_MoveUp && rowIndex == 0) - || (OwningColumn.Name == COL_MoveDown && rowIndex == LastRowIndex) - || OwningRow.IsNewRow) - { + var isMoveUp = OwningColumn.Name == COL_MoveUp; + var isMoveDown = OwningColumn.Name == COL_MoveDown; + var isDelete = OwningColumn.Name == COL_Delete; + var isNewRow = OwningRow.IsNewRow; + + if (isNewRow + || (isMoveUp && rowIndex == 0) + || (isMoveDown && rowIndex == LastRowIndex)) + { base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, null, null, null, cellStyle, advancedBorderStyle, paintParts ^ (DataGridViewPaintParts.ContentBackground | DataGridViewPaintParts.ContentForeground | DataGridViewPaintParts.SelectionBackground)); ButtonRenderer.DrawButton(graphics, cellBounds, value as string, cellStyle.Font, false, System.Windows.Forms.VisualStyles.PushButtonState.Disabled); - } + } else - base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts); - } + { + base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts); - int LastRowIndex => DataGridView.Rows[^1].IsNewRow ? DataGridView.Rows[^1].Index - 1 : DataGridView.Rows[^1].Index; + if (isMoveUp) + AccessibilityDescription = "Move up"; + else if (isMoveDown) + AccessibilityDescription = "Move down"; + else if (isDelete) + AccessibilityDescription = "Delete"; + } + } } public EditQuickFilters() diff --git a/Source/LibationWinForms/GridView/DataGridViewImageButtonCell.cs b/Source/LibationWinForms/GridView/DataGridViewImageButtonCell.cs index a025eece..3f195d4e 100644 --- a/Source/LibationWinForms/GridView/DataGridViewImageButtonCell.cs +++ b/Source/LibationWinForms/GridView/DataGridViewImageButtonCell.cs @@ -1,11 +1,12 @@ using System.Drawing; -using System.Windows.Forms; namespace LibationWinForms.GridView { - public class DataGridViewImageButtonCell : DataGridViewButtonCell - { - protected void DrawButtonImage(Graphics graphics, Image image, Rectangle cellBounds) + public class DataGridViewImageButtonCell : AccessibleDataGridViewButtonCell + { + public DataGridViewImageButtonCell(string accessibilityName) : base(accessibilityName) { } + + protected void DrawButtonImage(Graphics graphics, Image image, Rectangle cellBounds) { var scaleFactor = OwningColumn is IDataGridScaleColumn scCol ? scCol.ScaleFactor : 1f; diff --git a/Source/LibationWinForms/GridView/EditTagsDataGridViewImageButtonColumn.cs b/Source/LibationWinForms/GridView/EditTagsDataGridViewImageButtonColumn.cs index ec704191..29f75c7d 100644 --- a/Source/LibationWinForms/GridView/EditTagsDataGridViewImageButtonColumn.cs +++ b/Source/LibationWinForms/GridView/EditTagsDataGridViewImageButtonColumn.cs @@ -20,20 +20,33 @@ namespace LibationWinForms.GridView } internal class EditTagsDataGridViewImageButtonCell : DataGridViewImageButtonCell - { - private static Image ButtonImage { get; } = Properties.Resources.edit_25x25; + { + public EditTagsDataGridViewImageButtonCell() : base("Edit Tags button") { } + + private static Image ButtonImage { get; } = Properties.Resources.edit_25x25; protected override void Paint(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewElementStates elementState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts) { - if (rowIndex >= 0 && DataGridView.GetBoundItem(rowIndex) is ISeriesEntry) - base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, null, null, null, cellStyle, advancedBorderStyle, DataGridViewPaintParts.Background | DataGridViewPaintParts.Border); - else if (value is string tagStr && tagStr.Length == 0) + // series + if (rowIndex >= 0 && DataGridView.GetBoundItem(rowIndex) is ISeriesEntry) + { + base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, null, null, null, cellStyle, advancedBorderStyle, DataGridViewPaintParts.Background | DataGridViewPaintParts.Border); + } + // tag: empty + else if (value is string tagStr && tagStr.Length == 0) { base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, null, null, null, cellStyle, advancedBorderStyle, paintParts); + DrawButtonImage(graphics, ButtonImage, cellBounds); - } + AccessibilityDescription = "Click to edit tags"; + } + // tag: not empty else - base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts); - } + { + base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts); + + AccessibilityDescription = (string)value; + } + } } } diff --git a/Source/LibationWinForms/GridView/LastDownloadedGridViewColumn.cs b/Source/LibationWinForms/GridView/LastDownloadedGridViewColumn.cs index 0fca8f68..347fe37e 100644 --- a/Source/LibationWinForms/GridView/LastDownloadedGridViewColumn.cs +++ b/Source/LibationWinForms/GridView/LastDownloadedGridViewColumn.cs @@ -1,7 +1,7 @@ -using LibationUiBase.GridView; -using System; +using System; using System.Drawing; using System.Windows.Forms; +using LibationUiBase.GridView; namespace LibationWinForms.GridView { @@ -21,15 +21,19 @@ namespace LibationWinForms.GridView } } - internal class LastDownloadedGridViewCell : DataGridViewTextBoxCell - { + internal class LastDownloadedGridViewCell : AccessibleDataGridViewTextBoxCell + { private LastDownloadStatus LastDownload => (LastDownloadStatus)Value; - protected override void Paint(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewElementStates cellState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts) + + public LastDownloadedGridViewCell() : base("Last Downloaded") { } + + protected override void Paint(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewElementStates cellState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts) { - if (value is LastDownloadStatus lastDl) - ToolTipText = lastDl.ToolTipText; base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts); - } + + if (value is LastDownloadStatus lastDl) + AccessibilityDescription = lastDl.ToolTipText; + } protected override void OnDoubleClick(DataGridViewCellEventArgs e) { diff --git a/Source/LibationWinForms/GridView/LiberateDataGridViewImageButtonColumn.cs b/Source/LibationWinForms/GridView/LiberateDataGridViewImageButtonColumn.cs index 07be9ee0..8cb3007b 100644 --- a/Source/LibationWinForms/GridView/LiberateDataGridViewImageButtonColumn.cs +++ b/Source/LibationWinForms/GridView/LiberateDataGridViewImageButtonColumn.cs @@ -16,25 +16,7 @@ namespace LibationWinForms.GridView internal class LiberateDataGridViewImageButtonCell : DataGridViewImageButtonCell { - #region Accessibility - private string accessibilityName => "Liberate Image Button"; - private string accessibilityDescription = "undefined"; - protected override AccessibleObject CreateAccessibilityInstance() => new MyAccessibilityObject(accessibilityName, accessibilityDescription); - protected class MyAccessibilityObject : DataGridViewCellAccessibleObject - { - public override string Name => _name; - public override string Description => _description; - - private string _name { get; } - private string _description { get; } - - public MyAccessibilityObject(string name, string description) : base() - { - _name = name; - _description = description; - } - } - #endregion + public LiberateDataGridViewImageButtonCell() : base("Liberate button") { } private static readonly Brush DISABLED_GRAY = new SolidBrush(Color.FromArgb(0x60, Color.LightGray)); private static readonly Color HiddenForeColor = Color.LightGray; @@ -51,8 +33,7 @@ namespace LibationWinForms.GridView base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, null, null, null, cellStyle, advancedBorderStyle, paintParts); DrawButtonImage(graphics, (Image)status.ButtonImage, cellBounds); - accessibilityDescription = status.ToolTip; - ToolTipText = status.ToolTip; + AccessibilityDescription = status.ToolTip; if (status.IsUnavailable || status.Opacity < 1) graphics.FillRectangle(DISABLED_GRAY, cellBounds); diff --git a/Source/LibationWinForms/GridView/MyRatingGridViewColumn.cs b/Source/LibationWinForms/GridView/MyRatingGridViewColumn.cs index 67b6f72c..24d694cf 100644 --- a/Source/LibationWinForms/GridView/MyRatingGridViewColumn.cs +++ b/Source/LibationWinForms/GridView/MyRatingGridViewColumn.cs @@ -1,9 +1,9 @@ -using DataLayer; -using System; +using System; using System.ComponentModel; using System.Drawing; using System.Linq; using System.Windows.Forms; +using DataLayer; namespace LibationWinForms.GridView { @@ -24,14 +24,17 @@ namespace LibationWinForms.GridView } } - internal class MyRatingGridViewCell : DataGridViewTextBoxCell - { + internal class MyRatingGridViewCell : AccessibleDataGridViewTextBoxCell + { private static Rating DefaultRating => new Rating(0, 0, 0); public override object DefaultNewRowValue => DefaultRating; public override Type EditType => typeof(MyRatingCellEditor); public override Type ValueType => typeof(Rating); - public MyRatingGridViewCell() { ToolTipText = ReadOnly ? "" : "Click to change ratings"; } + public MyRatingGridViewCell() : base("My Rating") + { + AccessibilityDescription = ReadOnly ? "" : "Click to change ratings"; + } public override void InitializeEditingControl(int rowIndex, object initialFormattedValue, DataGridViewCellStyle dataGridViewCellStyle) { @@ -46,14 +49,14 @@ namespace LibationWinForms.GridView { if (value is Rating rating) { - ToolTipText = ReadOnly ? "" : "Click to change ratings"; - var starString = rating.ToStarString(); base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, starString, starString, errorText, cellStyle, advancedBorderStyle, paintParts); - } - else - base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, string.Empty, string.Empty, errorText, cellStyle, advancedBorderStyle, paintParts); - } + + AccessibilityDescription = ReadOnly ? "" : "Click to change ratings"; + } + else + base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, string.Empty, string.Empty, errorText, cellStyle, advancedBorderStyle, paintParts); + } protected override object GetFormattedValue(object value, int rowIndex, ref DataGridViewCellStyle cellStyle, TypeConverter valueTypeConverter, TypeConverter formattedValueTypeConverter, DataGridViewDataErrorContexts context) => value is Rating rating ? rating.ToStarString() : value?.ToString(); diff --git a/Source/LibationWinForms/SeriesView/DownloadButtonColumn.cs b/Source/LibationWinForms/SeriesView/DownloadButtonColumn.cs index 7936c895..31a88ffa 100644 --- a/Source/LibationWinForms/SeriesView/DownloadButtonColumn.cs +++ b/Source/LibationWinForms/SeriesView/DownloadButtonColumn.cs @@ -13,37 +13,40 @@ namespace LibationWinForms.SeriesView CellTemplate.Style.WrapMode = DataGridViewTriState.True; } } - internal class DownloadButtonColumnCell : DataGridViewButtonCell - { - protected override void Paint(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewElementStates elementState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts) - { - if (value is SeriesButton sentry) - { - string cellValue = sentry.DisplayText; - if (!sentry.Enabled) - { - //Draw disabled button - Rectangle buttonArea = cellBounds; - Rectangle buttonAdjustment = BorderWidths(advancedBorderStyle); - buttonArea.X += buttonAdjustment.X; - buttonArea.Y += buttonAdjustment.Y; - buttonArea.Height -= buttonAdjustment.Height; - buttonArea.Width -= buttonAdjustment.Width; - ButtonRenderer.DrawButton(graphics, buttonArea, cellValue, cellStyle.Font, TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter | TextFormatFlags.WordBreak, focused: false, PushButtonState.Disabled); + internal class DownloadButtonColumnCell : AccessibleDataGridViewButtonCell + { + public DownloadButtonColumnCell() : base("Download Series button") { } - } - else if (sentry.HasButtonAction) - base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, cellValue, cellValue, errorText, cellStyle, advancedBorderStyle, paintParts); - else - { - base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, null, null, null, cellStyle, advancedBorderStyle, DataGridViewPaintParts.Background | DataGridViewPaintParts.Border); - TextRenderer.DrawText(graphics, cellValue, cellStyle.Font, cellBounds, cellStyle.ForeColor); - } - } - else - { - base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, null, null, null, cellStyle, advancedBorderStyle, DataGridViewPaintParts.Background | DataGridViewPaintParts.Border); - } - } + protected override void Paint(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewElementStates elementState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts) + { + if (value is not SeriesButton seriesEntry) + { + base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, null, null, null, cellStyle, advancedBorderStyle, DataGridViewPaintParts.Background | DataGridViewPaintParts.Border); + return; + } + + string cellValue = seriesEntry.DisplayText; + AccessibilityDescription = cellValue; + + if (!seriesEntry.Enabled) + { + //Draw disabled button + Rectangle buttonArea = cellBounds; + Rectangle buttonAdjustment = BorderWidths(advancedBorderStyle); + buttonArea.X += buttonAdjustment.X; + buttonArea.Y += buttonAdjustment.Y; + buttonArea.Height -= buttonAdjustment.Height; + buttonArea.Width -= buttonAdjustment.Width; + + ButtonRenderer.DrawButton(graphics, buttonArea, cellValue, cellStyle.Font, TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter | TextFormatFlags.WordBreak, focused: false, PushButtonState.Disabled); + } + else if (seriesEntry.HasButtonAction) + base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, cellValue, cellValue, errorText, cellStyle, advancedBorderStyle, paintParts); + else + { + base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, null, null, null, cellStyle, advancedBorderStyle, DataGridViewPaintParts.Background | DataGridViewPaintParts.Border); + TextRenderer.DrawText(graphics, cellValue, cellStyle.Font, cellBounds, cellStyle.ForeColor); + } + } } }