Merge pull request #839 from mono/more-wpf-accessibility
More WPF accessibility changes
This commit is contained in:
Коммит
e30a4a39dc
|
@ -62,6 +62,11 @@ namespace Xwt.GtkBackend
|
|||
Initialize (backend?.Widget, eventSink);
|
||||
}
|
||||
|
||||
public void Initialize (IPopoverBackend parentPopover, IAccessibleEventSink eventSink)
|
||||
{
|
||||
// Not currently supported
|
||||
}
|
||||
|
||||
public void Initialize (object parentWidget, IAccessibleEventSink eventSink)
|
||||
{
|
||||
this.eventSink = eventSink;
|
||||
|
|
|
@ -74,6 +74,15 @@ namespace Xwt.GtkBackend
|
|||
ApplicationContext.InvokeUserCode (EventSink.OnColorChanged);
|
||||
}
|
||||
|
||||
public Xwt.Drawing.Color TextColor {
|
||||
get {
|
||||
throw new NotImplementedException ("Gtk ColorSelector doesn't currently support the TextColor property");
|
||||
}
|
||||
set {
|
||||
throw new NotImplementedException ("Gtk ColorSelector doesn't currently support the TextColor property");
|
||||
}
|
||||
}
|
||||
|
||||
public Xwt.Drawing.Color Color {
|
||||
get {
|
||||
var xwtColor = Widget.CurrentColor.ToXwtValue ();
|
||||
|
|
|
@ -5,6 +5,8 @@ using System.Text;
|
|||
using System.Windows;
|
||||
using System.Windows.Automation;
|
||||
using System.Windows.Automation.Peers;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Media;
|
||||
using Xwt.Accessibility;
|
||||
using Xwt.Backends;
|
||||
|
||||
|
@ -18,24 +20,59 @@ namespace Xwt.WPFBackend
|
|||
|
||||
public bool IsAccessible { get; set; }
|
||||
|
||||
private string identifier;
|
||||
public string Identifier {
|
||||
get { return AutomationProperties.GetAutomationId (element); }
|
||||
set { AutomationProperties.SetAutomationId (element, value); }
|
||||
set {
|
||||
identifier = value;
|
||||
AutomationProperties.SetAutomationId (element, value);
|
||||
}
|
||||
}
|
||||
|
||||
private string label;
|
||||
public string Label {
|
||||
get { return AutomationProperties.GetName (element); }
|
||||
set { AutomationProperties.SetName (element, value); }
|
||||
set {
|
||||
label = value;
|
||||
AutomationProperties.SetName (element, value);
|
||||
}
|
||||
}
|
||||
|
||||
private string description;
|
||||
public string Description {
|
||||
get { return AutomationProperties.GetHelpText (element); }
|
||||
set { AutomationProperties.SetHelpText (element, value); }
|
||||
set {
|
||||
description = value;
|
||||
AutomationProperties.SetHelpText (element, value);
|
||||
}
|
||||
}
|
||||
|
||||
private Widget labelWidget;
|
||||
public Widget LabelWidget {
|
||||
set {
|
||||
labelWidget = value;
|
||||
AutomationProperties.SetLabeledBy (element, (Toolkit.GetBackend (value) as WidgetBackend)?.Widget);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// In some cases (just Popovers currently) we need to wait to set the automation properties until the element
|
||||
/// that needs them comes into existence (a PopoverRoot in the case of a Popover, when it's shown). This is
|
||||
/// used for that delayed initialization.
|
||||
/// </summary>
|
||||
/// <param name="element">UIElement on which to set the properties</param>
|
||||
public void InitAutomationProperties (UIElement element)
|
||||
{
|
||||
if (identifier != null)
|
||||
AutomationProperties.SetAutomationId (element, identifier);
|
||||
if (label != null)
|
||||
AutomationProperties.SetName (element, label);
|
||||
if (description != null)
|
||||
AutomationProperties.SetHelpText (element, description);
|
||||
if (labelWidget != null)
|
||||
AutomationProperties.SetLabeledBy (element, (Toolkit.GetBackend (labelWidget) as WidgetBackend)?.Widget);
|
||||
}
|
||||
|
||||
public string Title { get; set; }
|
||||
public string Value { get; set; }
|
||||
public Role Role { get; set; } = Role.Custom;
|
||||
|
@ -59,6 +96,13 @@ namespace Xwt.WPFBackend
|
|||
wpfBackend.HasAccessibleObject = true;
|
||||
}
|
||||
|
||||
public void Initialize (IPopoverBackend parentPopover, IAccessibleEventSink eventSink)
|
||||
{
|
||||
var popoverBackend = (PopoverBackend) parentPopover;
|
||||
Popup popup = popoverBackend.NativeWidget;
|
||||
Initialize (popup, eventSink);
|
||||
}
|
||||
|
||||
public void Initialize (object parentWidget, IAccessibleEventSink eventSink)
|
||||
{
|
||||
this.element = parentWidget as UIElement;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//
|
||||
//
|
||||
// BoxBackend.cs
|
||||
//
|
||||
// Author:
|
||||
|
@ -139,9 +139,13 @@ namespace Xwt.WPFBackend
|
|||
}
|
||||
}
|
||||
|
||||
public AutomationPeer AutomationPeerOverride { get; set; }
|
||||
|
||||
protected override AutomationPeer OnCreateAutomationPeer ()
|
||||
{
|
||||
return new CustomPanelAutomationPeer (this);
|
||||
if (AutomationPeerOverride != null)
|
||||
return AutomationPeerOverride;
|
||||
else return new CustomPanelAutomationPeer (this);
|
||||
}
|
||||
|
||||
class CustomPanelAutomationPeer : FrameworkElementAutomationPeer
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//
|
||||
//
|
||||
// DropDownButton.cs
|
||||
//
|
||||
// Author:
|
||||
|
@ -28,7 +28,9 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Automation;
|
||||
using System.Windows.Automation.Peers;
|
||||
using System.Windows.Automation.Provider;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using SWC = System.Windows.Controls;
|
||||
|
||||
|
@ -117,10 +119,13 @@ namespace Xwt.WPFBackend
|
|||
return new DropDownButtonAutomationPeer (this);
|
||||
}
|
||||
|
||||
class DropDownButtonAutomationPeer : ToggleButtonAutomationPeer
|
||||
class DropDownButtonAutomationPeer : ButtonBaseAutomationPeer, IExpandCollapseProvider
|
||||
{
|
||||
public DropDownButtonAutomationPeer (DropDownButton owner) : base (owner)
|
||||
DropDownButton owner;
|
||||
|
||||
public DropDownButtonAutomationPeer (DropDownButton owner) : base(owner)
|
||||
{
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
// Don't go into the children of this element
|
||||
|
@ -128,6 +133,44 @@ namespace Xwt.WPFBackend
|
|||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
protected override string GetClassNameCore ()
|
||||
{
|
||||
return nameof(DropDownButton);
|
||||
}
|
||||
|
||||
///
|
||||
override protected AutomationControlType GetAutomationControlTypeCore ()
|
||||
{
|
||||
return AutomationControlType.Button;
|
||||
}
|
||||
|
||||
///
|
||||
override public object GetPattern (PatternInterface patternInterface)
|
||||
{
|
||||
if (patternInterface == PatternInterface.ExpandCollapse)
|
||||
return this;
|
||||
else
|
||||
return base.GetPattern (patternInterface);
|
||||
}
|
||||
|
||||
public void Expand ()
|
||||
{
|
||||
owner.IsChecked = true;
|
||||
}
|
||||
|
||||
public void Collapse ()
|
||||
{
|
||||
owner.IsChecked = false;
|
||||
}
|
||||
|
||||
public ExpandCollapseState ExpandCollapseState {
|
||||
get {
|
||||
if (owner.IsChecked == null)
|
||||
return ExpandCollapseState.Collapsed;
|
||||
else return (bool)owner.IsChecked ? ExpandCollapseState.Expanded : ExpandCollapseState.Collapsed;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
//
|
||||
//
|
||||
// ExTreeViewItem.cs
|
||||
//
|
||||
// Author:
|
||||
|
@ -26,7 +26,10 @@
|
|||
// THE SOFTWARE.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Automation.Peers;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using SWC = System.Windows.Controls;
|
||||
|
@ -230,12 +233,38 @@ namespace Xwt.WPFBackend
|
|||
//We can't allow TreeViewItem(our base class) to get this message(OnGotFocus) because it will also select this item which we don't want
|
||||
}
|
||||
|
||||
private bool CtrlPressed
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keyboard.IsKeyDown (WKey.RightCtrl) || Keyboard.IsKeyDown (WKey.LeftCtrl);
|
||||
}
|
||||
}
|
||||
private bool CtrlPressed
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keyboard.IsKeyDown (WKey.RightCtrl) || Keyboard.IsKeyDown (WKey.LeftCtrl);
|
||||
}
|
||||
}
|
||||
|
||||
protected override AutomationPeer OnCreateAutomationPeer ()
|
||||
{
|
||||
return new ExTreeViewItemAutomationPeer (this);
|
||||
}
|
||||
|
||||
class ExTreeViewItemAutomationPeer : TreeViewItemAutomationPeer
|
||||
{
|
||||
public ExTreeViewItemAutomationPeer (ExTreeViewItem owner) : base (owner)
|
||||
{
|
||||
}
|
||||
|
||||
protected override List<AutomationPeer> GetChildrenCore ()
|
||||
{
|
||||
List<AutomationPeer> defaultChildren = base.GetChildrenCore ();
|
||||
if (defaultChildren == null)
|
||||
return null;
|
||||
|
||||
// We only want to include TreeView items in the a11y tree, not their constituent image/text/etc controls -
|
||||
// for one thing including all controls messes up the "item 3 of 5" style counts announced by the
|
||||
// narrator, as those controls would be include
|
||||
List<AutomationPeer> children = defaultChildren.Where (
|
||||
child => child is TreeViewItemAutomationPeer || child is TreeViewDataItemAutomationPeer).ToList ();
|
||||
return children;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//
|
||||
//
|
||||
// PopoverBackend.cs
|
||||
//
|
||||
// Author:
|
||||
|
@ -28,6 +28,7 @@ using System;
|
|||
using Xwt.Backends;
|
||||
using System.Windows.Media;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace Xwt.WPFBackend
|
||||
{
|
||||
|
@ -54,14 +55,46 @@ namespace Xwt.WPFBackend
|
|||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Control, if any, that should get the initial keyboard focus when the popover is shown.
|
||||
/// The control should be inside the popover, but it doesn't necessarily have to be an Xwt
|
||||
/// managed widget.
|
||||
/// </summary>
|
||||
public UIElement InitialFocus { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If set to true, then the arrow keys can't be used to move focus between controls.
|
||||
/// Regardless of this setting, tab still works to change focus and the arrow keys still
|
||||
/// work inside of controls that use them.
|
||||
/// </summary>
|
||||
public bool DisableArrowKeyNavigation { get; set; }
|
||||
|
||||
new Popover Frontend {
|
||||
get { return (Popover)base.frontend; }
|
||||
}
|
||||
|
||||
System.Windows.Controls.Primitives.Popup NativeWidget {
|
||||
public System.Windows.Controls.Primitives.Popup NativeWidget {
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Search up the visual tree, finding the PopupRoot for the popup.
|
||||
/// </summary>
|
||||
/// <returns>PopupRoot or null if not found for some reason</returns>
|
||||
public FrameworkElement GetPopupRoot ()
|
||||
{
|
||||
FrameworkElement element = Border;
|
||||
|
||||
do {
|
||||
element = (FrameworkElement) VisualTreeHelper.GetParent (element);
|
||||
if (element == null)
|
||||
return null;
|
||||
|
||||
if (element.GetType ().Name == "PopupRoot")
|
||||
return element;
|
||||
} while (true);
|
||||
}
|
||||
|
||||
public PopoverBackend ()
|
||||
{
|
||||
Border = new System.Windows.Controls.Border {
|
||||
|
@ -86,7 +119,9 @@ namespace Xwt.WPFBackend
|
|||
Placement = System.Windows.Controls.Primitives.PlacementMode.Custom,
|
||||
StaysOpen = false,
|
||||
};
|
||||
NativeWidget.Opened += NativeWidget_Opened;
|
||||
NativeWidget.Closed += NativeWidget_Closed;
|
||||
NativeWidget.PreviewKeyDown += NativeWidget_PreviewKeyDown;
|
||||
}
|
||||
|
||||
public void Initialize (IPopoverEventSink sink)
|
||||
|
@ -113,6 +148,27 @@ namespace Xwt.WPFBackend
|
|||
};
|
||||
NativeWidget.PlacementTarget = (System.Windows.FrameworkElement)Context.Toolkit.GetNativeWidget (reference);
|
||||
NativeWidget.IsOpen = true;
|
||||
|
||||
// Popups are special in that the automation properties need to be set on the PopupRoot, which only exists when the popup is shown
|
||||
// See https://social.msdn.microsoft.com/Forums/vstudio/en-US/d4ba12c8-7a87-478e-b064-5620f929a0cf/how-to-set-automationid-and-name-for-popup?forum=wpf
|
||||
var accessibleBackend = (AccessibleBackend)Toolkit.GetBackend (Frontend.Accessible);
|
||||
if (accessibleBackend != null) {
|
||||
FrameworkElement popupRoot = GetPopupRoot ();
|
||||
if (popupRoot != null)
|
||||
accessibleBackend.InitAutomationProperties (popupRoot);
|
||||
}
|
||||
}
|
||||
|
||||
void NativeWidget_Opened (object sender, EventArgs e)
|
||||
{
|
||||
if (DisableArrowKeyNavigation) {
|
||||
FrameworkElement popupRoot = GetPopupRoot ();
|
||||
if (popupRoot != null)
|
||||
KeyboardNavigation.SetDirectionalNavigation (popupRoot, KeyboardNavigationMode.Once);
|
||||
}
|
||||
|
||||
if (InitialFocus != null)
|
||||
InitialFocus.Focus ();
|
||||
}
|
||||
|
||||
void NativeWidget_Closed (object sender, EventArgs e)
|
||||
|
@ -121,6 +177,15 @@ namespace Xwt.WPFBackend
|
|||
EventSink.OnClosed ();
|
||||
}
|
||||
|
||||
void NativeWidget_PreviewKeyDown (object sender, System.Windows.Input.KeyEventArgs e)
|
||||
{
|
||||
// Close the popup when Escape is hit
|
||||
if (e.Key == System.Windows.Input.Key.Escape) {
|
||||
NativeWidget.IsOpen = false;
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void Hide ()
|
||||
{
|
||||
NativeWidget.IsOpen = false;
|
||||
|
@ -129,8 +194,10 @@ namespace Xwt.WPFBackend
|
|||
|
||||
public void Dispose ()
|
||||
{
|
||||
if (NativeWidget != null)
|
||||
if (NativeWidget != null) {
|
||||
NativeWidget.Opened -= NativeWidget_Opened;
|
||||
NativeWidget.Closed -= NativeWidget_Closed;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
//
|
||||
//
|
||||
// ValuesContainer.cs
|
||||
//
|
||||
// Author:
|
||||
|
@ -67,5 +67,16 @@ namespace Xwt.WPFBackend
|
|||
if (handler != null)
|
||||
handler (this, e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ToString is used by the default ComboBoxItem automation peer to get the automation Name for the item.
|
||||
/// Normally, we want to be the same as the text in the combo, the first value.
|
||||
/// </summary>
|
||||
public override string ToString ()
|
||||
{
|
||||
if (values.Length > 0 && values[0] is string)
|
||||
return (string) values[0];
|
||||
else return base.ToString ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//
|
||||
//
|
||||
// WindowsSpinButton.cs
|
||||
//
|
||||
// Author:
|
||||
|
@ -157,7 +157,7 @@ namespace Xwt.WPFBackend
|
|||
|
||||
#region General
|
||||
Grid mainGrid;
|
||||
TextBox textBox;
|
||||
SpinButtonTextBox textBox;
|
||||
RepeatButton buttonUp;
|
||||
RepeatButton buttonDown;
|
||||
public WindowsSpinButton()
|
||||
|
@ -169,7 +169,7 @@ namespace Xwt.WPFBackend
|
|||
mainGrid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(16) });
|
||||
|
||||
//Textbox
|
||||
textBox = new TextBox();
|
||||
textBox = new SpinButtonTextBox (this);
|
||||
textBox.Text = "0";
|
||||
textBox.HorizontalAlignment = HorizontalAlignment.Stretch;
|
||||
textBox.MinWidth = 25;
|
||||
|
@ -247,6 +247,7 @@ namespace Xwt.WPFBackend
|
|||
}
|
||||
}
|
||||
|
||||
public TextBox TextBox => textBox;
|
||||
|
||||
private void UserControl_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
|
@ -458,11 +459,27 @@ namespace Xwt.WPFBackend
|
|||
#endregion
|
||||
|
||||
#region Accessibility
|
||||
|
||||
protected override AutomationPeer OnCreateAutomationPeer ()
|
||||
{
|
||||
return new WindowsSpinButtonAutomationPeer (this);
|
||||
}
|
||||
|
||||
class SpinButtonTextBox : TextBox
|
||||
{
|
||||
WindowsSpinButton spinButton;
|
||||
|
||||
public SpinButtonTextBox (WindowsSpinButton spinButton)
|
||||
{
|
||||
this.spinButton = spinButton;
|
||||
}
|
||||
|
||||
protected override AutomationPeer OnCreateAutomationPeer ()
|
||||
{
|
||||
return UIElementAutomationPeer.FromElement (spinButton);
|
||||
}
|
||||
}
|
||||
|
||||
class WindowsSpinButtonAutomationPeer : UserControlAutomationPeer, IRangeValueProvider
|
||||
{
|
||||
public WindowsSpinButtonAutomationPeer (WindowsSpinButton owner) : base (owner)
|
||||
|
@ -486,6 +503,21 @@ namespace Xwt.WPFBackend
|
|||
return AutomationControlType.Spinner;
|
||||
}
|
||||
|
||||
protected override bool IsKeyboardFocusableCore ()
|
||||
{
|
||||
return Button.IsEnabled;
|
||||
}
|
||||
|
||||
protected override bool HasKeyboardFocusCore ()
|
||||
{
|
||||
return Button.IsKeyboardFocusWithin;
|
||||
}
|
||||
|
||||
protected override void SetFocusCore ()
|
||||
{
|
||||
Button.TextBox.Focus ();
|
||||
}
|
||||
|
||||
public override object GetPattern (PatternInterface patternInterface)
|
||||
{
|
||||
if (patternInterface == PatternInterface.RangeValue) {
|
||||
|
|
|
@ -49,6 +49,11 @@ namespace Xwt.Mac
|
|||
Initialize (parentBackend?.Widget, eventSink);
|
||||
}
|
||||
|
||||
public void Initialize (IPopoverBackend parentPopover, IAccessibleEventSink eventSink)
|
||||
{
|
||||
// Not currently supported
|
||||
}
|
||||
|
||||
public void Initialize (object parentWidget, IAccessibleEventSink eventSink)
|
||||
{
|
||||
this.eventSink = eventSink;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//
|
||||
//
|
||||
// Accessible.cs
|
||||
//
|
||||
// Author:
|
||||
|
@ -50,9 +50,12 @@ namespace Xwt.Accessibility
|
|||
|
||||
protected override void OnBackendCreated ()
|
||||
{
|
||||
var parentBackend = Parent.parentComponent?.GetBackend () as IWidgetBackend;
|
||||
if (parentBackend != null)
|
||||
Backend.Initialize (parentBackend, this);
|
||||
object parentBackend = Parent.parentComponent?.GetBackend ();
|
||||
|
||||
if (parentBackend is IWidgetBackend)
|
||||
Backend.Initialize ((IWidgetBackend) parentBackend, this);
|
||||
else if (parentBackend is IPopoverBackend)
|
||||
Backend.Initialize ((IPopoverBackend) parentBackend, this);
|
||||
else
|
||||
Backend.Initialize (Parent.parentNativeObject, this);
|
||||
}
|
||||
|
@ -72,6 +75,15 @@ namespace Xwt.Accessibility
|
|||
backendHost.Parent = this;
|
||||
}
|
||||
|
||||
internal Accessible (Popover parent)
|
||||
{
|
||||
if (parent == null)
|
||||
throw new ArgumentNullException (nameof (parent));
|
||||
parentComponent = parent;
|
||||
backendHost = new AccessibleBackendHost ();
|
||||
backendHost.Parent = this;
|
||||
}
|
||||
|
||||
internal Accessible (object nativeParent)
|
||||
{
|
||||
if (nativeParent == null)
|
||||
|
@ -276,6 +288,10 @@ namespace Xwt.Accessibility
|
|||
{
|
||||
}
|
||||
|
||||
public void Initialize (IPopoverBackend parentPopover, IAccessibleEventSink eventSink)
|
||||
{
|
||||
}
|
||||
|
||||
public void Initialize (object parentWidget, IAccessibleEventSink eventSink)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//
|
||||
//
|
||||
// AccessibleBackendHandler.cs
|
||||
//
|
||||
// Author:
|
||||
|
@ -32,6 +32,8 @@ namespace Xwt.Backends
|
|||
{
|
||||
void Initialize (IWidgetBackend parentWidget, IAccessibleEventSink eventSink);
|
||||
|
||||
void Initialize (IPopoverBackend parentPopover, IAccessibleEventSink eventSink);
|
||||
|
||||
void Initialize (object parentWidget, IAccessibleEventSink eventSink);
|
||||
|
||||
bool IsAccessible { get; set; }
|
||||
|
|
|
@ -30,6 +30,7 @@ namespace Xwt.Backends
|
|||
{
|
||||
public interface IColorSelectorBackend: IWidgetBackend
|
||||
{
|
||||
Color TextColor { get; set; }
|
||||
Color Color { get; set; }
|
||||
bool SupportsAlpha { get; set; }
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//
|
||||
//
|
||||
// ColorPicker.cs
|
||||
//
|
||||
// Author:
|
||||
|
@ -120,7 +120,7 @@ namespace Xwt
|
|||
}
|
||||
}
|
||||
|
||||
class DefaultColorPickerBackend: XwtWidgetBackend, IColorPickerBackend
|
||||
public class DefaultColorPickerBackend: XwtWidgetBackend, IColorPickerBackend
|
||||
{
|
||||
readonly Button colorButton;
|
||||
readonly ColorImage colorImage;
|
||||
|
@ -182,6 +182,8 @@ namespace Xwt
|
|||
get { return (IColorPickerEventSink)base.EventSink; }
|
||||
}
|
||||
|
||||
public Button ColorButton => colorButton;
|
||||
|
||||
public Color Color {
|
||||
get {
|
||||
return colorImage.Color;
|
||||
|
|
|
@ -27,6 +27,7 @@ using System;
|
|||
using Xwt.Drawing;
|
||||
using Xwt.Backends;
|
||||
using System.Collections.Generic;
|
||||
using Xwt.Accessibility;
|
||||
|
||||
|
||||
namespace Xwt
|
||||
|
@ -62,7 +63,15 @@ namespace Xwt
|
|||
IColorSelectorBackend Backend {
|
||||
get { return (IColorSelectorBackend) BackendHost.Backend; }
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the color to be used for labels and other UI text
|
||||
/// </summary>
|
||||
public Color TextColor {
|
||||
get { return Backend.TextColor; }
|
||||
set { Backend.TextColor = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the selected color
|
||||
/// </summary>
|
||||
|
@ -114,6 +123,7 @@ namespace Xwt
|
|||
bool loadingEntries;
|
||||
List<Widget> alphaControls = new List<Widget> ();
|
||||
bool enableColorChangedEvent;
|
||||
List<Label> labelWidgets = new List<Label> ();
|
||||
|
||||
public DefaultColorSelectorBackend ()
|
||||
{
|
||||
|
@ -137,49 +147,67 @@ namespace Xwt
|
|||
const int entryWidth = 40;
|
||||
VBox entryBox = new VBox ();
|
||||
Table entryTable = new Table ();
|
||||
|
||||
entryTable.Add (new Label (Application.TranslationCatalog.GetString("Color:")), 0, 0);
|
||||
|
||||
entryTable.Add (CreateLabel (Application.TranslationCatalog.GetString("Color:")), 0, 0);
|
||||
entryTable.Add (colorBox, 1, 0, colspan:4);
|
||||
entryTable.Add (new HSeparator (), 0, 1, colspan:5);
|
||||
|
||||
int r = 2;
|
||||
entryTable.Add (new Label (Application.TranslationCatalog.GetString("Hue:")), 0, r);
|
||||
var hueLabel = CreateLabel ();
|
||||
entryTable.Add (hueLabel, 0, r);
|
||||
entryTable.Add (hueEntry = new SpinButton () {
|
||||
MinWidth = entryWidth, MinimumValue = 0, MaximumValue = 360, Digits = 0, IncrementValue = 1 }, 1, r++);
|
||||
|
||||
entryTable.Add (new Label (Application.TranslationCatalog.GetString("Saturation:")), 0, r);
|
||||
SetupEntry (hueEntry, hueLabel, Application.TranslationCatalog.GetString ("Hue"));
|
||||
|
||||
var satLabel = CreateLabel ();
|
||||
entryTable.Add (satLabel, 0, r);
|
||||
entryTable.Add (satEntry = new SpinButton () {
|
||||
MinWidth = entryWidth, MinimumValue = 0, MaximumValue = 100, Digits = 0, IncrementValue = 1 }, 1, r++);
|
||||
|
||||
entryTable.Add (new Label (Application.TranslationCatalog.GetString("Light:")), 0, r);
|
||||
SetupEntry (satEntry, satLabel, Application.TranslationCatalog.GetString ("Saturation"));
|
||||
|
||||
var lightLabel = CreateLabel ();
|
||||
entryTable.Add (lightLabel, 0, r);
|
||||
entryTable.Add (lightEntry = new SpinButton () {
|
||||
MinWidth = entryWidth, MinimumValue = 0, MaximumValue = 100, Digits = 0, IncrementValue = 1 }, 1, r++);
|
||||
|
||||
SetupEntry (lightEntry, lightLabel, Application.TranslationCatalog.GetString ("Light"));
|
||||
|
||||
r = 2;
|
||||
entryTable.Add (new Label (Application.TranslationCatalog.GetString("Red:")), 3, r);
|
||||
var redLabel = CreateLabel ();
|
||||
entryTable.Add (redLabel, 3, r);
|
||||
entryTable.Add (redEntry = new SpinButton () {
|
||||
MinWidth = entryWidth, MinimumValue = 0, MaximumValue = 255, Digits = 0, IncrementValue = 1 }, 4, r++);
|
||||
|
||||
entryTable.Add (new Label (Application.TranslationCatalog.GetString("Green:")), 3, r);
|
||||
SetupEntry (redEntry, redLabel, Application.TranslationCatalog.GetString ("Red"));
|
||||
|
||||
var greenLabel = CreateLabel ();
|
||||
entryTable.Add (greenLabel, 3, r);
|
||||
entryTable.Add (greenEntry = new SpinButton () {
|
||||
MinWidth = entryWidth, MinimumValue = 0, MaximumValue = 255, Digits = 0, IncrementValue = 1 }, 4, r++);
|
||||
|
||||
entryTable.Add (new Label (Application.TranslationCatalog.GetString("Blue:")), 3, r);
|
||||
SetupEntry (greenEntry, greenLabel, Application.TranslationCatalog.GetString ("Green"));
|
||||
|
||||
var blueLabel = CreateLabel ();
|
||||
entryTable.Add (blueLabel, 3, r);
|
||||
entryTable.Add (blueEntry = new SpinButton () {
|
||||
MinWidth = entryWidth, MinimumValue = 0, MaximumValue = 255, Digits = 0, IncrementValue = 1 }, 4, r++);
|
||||
|
||||
Label label;
|
||||
SetupEntry (blueEntry, blueLabel, Application.TranslationCatalog.GetString ("Blue"));
|
||||
|
||||
entryTable.Add (alphaSeparator = new HSeparator (), 0, r++, colspan:5);
|
||||
entryTable.Add (label = new Label (Application.TranslationCatalog.GetString("Opacity:")), 0, r);
|
||||
var alphaLabel = CreateLabel ();
|
||||
entryTable.Add (alphaLabel, 0, r);
|
||||
entryTable.Add (alphaSlider = new HSlider () {
|
||||
MinimumValue = 0, MaximumValue = 255, }, 1, r, colspan: 3);
|
||||
entryTable.Add (alphaEntry = new SpinButton () {
|
||||
MinWidth = entryWidth, MinimumValue = 0, MaximumValue = 255, Digits = 0, IncrementValue = 1 }, 4, r);
|
||||
|
||||
SetupEntry (alphaEntry, alphaLabel, Application.TranslationCatalog.GetString ("Opacity"));
|
||||
|
||||
// Don't allow the slider to get keyboard focus, as it doesn't really work with the keyboard and the opacity
|
||||
// spin button takes its place
|
||||
alphaSlider.CanGetFocus = false;
|
||||
alphaSlider.Accessible.Label = Application.TranslationCatalog.GetString ("Opacity");
|
||||
|
||||
alphaControls.Add (alphaSeparator);
|
||||
alphaControls.Add (label);
|
||||
alphaControls.Add (alphaLabel);
|
||||
alphaControls.Add (alphaEntry);
|
||||
|
||||
|
||||
entryBox.PackStart (entryTable);
|
||||
box.PackStart (entryBox);
|
||||
Content = box;
|
||||
|
@ -199,6 +227,37 @@ namespace Xwt
|
|||
Color = Colors.White;
|
||||
}
|
||||
|
||||
public Color TextColor {
|
||||
get {
|
||||
return labelWidgets[0].TextColor;
|
||||
}
|
||||
set {
|
||||
foreach (Label labelWidget in labelWidgets)
|
||||
labelWidget.TextColor = value;
|
||||
}
|
||||
}
|
||||
|
||||
static void SetupEntry (SpinButton spinButton, Label labelWidget, string labelText)
|
||||
{
|
||||
labelWidget.Text = GetLabelWithColon (labelText);
|
||||
|
||||
spinButton.Accessible.Label = labelText;
|
||||
spinButton.Accessible.LabelWidget = labelWidget;
|
||||
}
|
||||
|
||||
Label CreateLabel (string text = null)
|
||||
{
|
||||
Label label = text == null ? new Label () : new Label (text);
|
||||
labelWidgets.Add (label);
|
||||
return label;
|
||||
}
|
||||
|
||||
static string GetLabelWithColon (string labelText)
|
||||
{
|
||||
string labelFormat = Application.TranslationCatalog.GetString ("{0}:");
|
||||
return string.Format (labelFormat, labelText);
|
||||
}
|
||||
|
||||
void HandleAlphaChanged (object sender, EventArgs e)
|
||||
{
|
||||
if (loadingEntries)
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
// THE SOFTWARE.
|
||||
|
||||
using System;
|
||||
using Xwt.Accessibility;
|
||||
using Xwt.Drawing;
|
||||
|
||||
using Xwt.Backends;
|
||||
|
@ -44,6 +45,7 @@ namespace Xwt
|
|||
WidgetSpacing padding;
|
||||
Widget content;
|
||||
bool shown;
|
||||
Accessible accessible;
|
||||
|
||||
EventHandler closedEvent;
|
||||
|
||||
|
@ -84,7 +86,16 @@ namespace Xwt
|
|||
VerifyConstructorCall (this);
|
||||
Content = content;
|
||||
}
|
||||
|
||||
|
||||
public Accessible Accessible {
|
||||
get {
|
||||
if (accessible == null) {
|
||||
accessible = new Accessible (this);
|
||||
}
|
||||
return accessible;
|
||||
}
|
||||
}
|
||||
|
||||
public Widget Content {
|
||||
get { return content; }
|
||||
set {
|
||||
|
|
|
@ -64,6 +64,7 @@ namespace Xwt
|
|||
WidgetPlacement alignHorizontal = WidgetPlacement.Fill;
|
||||
bool expandVertical;
|
||||
bool expandHorizontal;
|
||||
Accessible accessible;
|
||||
|
||||
EventHandler<DragOverCheckEventArgs> dragOverCheck;
|
||||
EventHandler<DragOverEventArgs> dragOver;
|
||||
|
@ -323,7 +324,6 @@ namespace Xwt
|
|||
}
|
||||
}
|
||||
|
||||
Accessible accessible;
|
||||
public Accessible Accessible {
|
||||
get {
|
||||
if (accessible == null) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче