zng/access.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
//! Accessibility service, events and properties.
//!
//! The accessibility API helps external tools to query the state of a widget and issue programmatic commands to it.
//! This API is mainly used by accessibility assistants like [`NVDA`] to narrate and operate the current screen, but
//! usage is not limited to accessibility, the access provided to widgets also enables external automation tools and
//! internal operations such as programmatically clicking a button.
//!
//! [`NVDA`]: https://en.wikipedia.org/wiki/NonVisual_Desktop_Access
//!
//! # Metadata
//!
//! Metadata is collected on demand during info build, there is a small performance impact to this so the access
//! builder is only available after accessibility was requested at least once for the window.
//!
//! ```
//! use zng::prelude_wgt::*;
//!
//! # let _ =
//! match_node_leaf(|op| match op {
//! UiNodeOp::Info { info } => {
//! if let Some(mut a) = info.access() {
//! // accessibility requested for this window
//! a.set_label("label");
//! }
//! }
//! _ => {}
//! })
//! # ;
//! ```
//!
//! You can also enables access info programmatically using [`WINDOW.enable_access()`], if the view-process did not
//! request accessibility the window still skips sending the access tree, so the performance impact is minimal.
//!
//! ```
//! use zng::prelude::*;
//!
//! # let mut app = APP.defaults().run_headless(false);
//! # app.doc_test_window(async {
//! WINDOW.enable_access();
//!
//! Window! {
//! child = Button! { id = "btn-1"; child = Text!("Button 1") };
//!
//! widget::on_info_init = hn!(|_| {
//! let btn_info = WINDOW.info().get("btn-1").unwrap().access().unwrap();
//! let txt_info = btn_info.info().children().next().unwrap().access().unwrap();
//!
//! assert_eq!(None, btn_info.label());
//! assert!(btn_info.labelled_by_child());
//! assert_eq!(Some(Txt::from("Button 1")), txt_info.label());
//! # WINDOW.close();
//! });
//! }
//! # });
//! ```
//!
//! When accessibility info is build you it can be accessed using [`WidgetInfo::access`]. Note that this is a low level
//! access info, provided as it was set by the widgets, in the example above the *label* value is only found on the text widget,
//! accessibility tools will use the text label for the button.
//!
//! [`WINDOW.enable_access()`]: crate::window::WINDOW_Ext::enable_access
//! [`WidgetInfo::access`]: crate::widget::info::WidgetInfo::access
//!
//! ## Properties
//!
//! Properties of this module only define metadata that indicate that the widget implements a certain UI pattern, by
//! setting a property you must make sure that the widget actually implements said pattern, for this reason most
//! of the accessibility definitions are provided by the widget implementations.
//!
//! In the example below a `TextInput!` widget instance changes its role to [`AccessRole::SearchBox`], the default
//! role is set by the widget itself to [`AccessRole::TextInput`], this usage of the widget has a more specific role
//! so it can be changed, in this case it is up to the app developer to actually implement the search.
//!
//! ```
//! use zng::prelude::*;
//! use zng::access::{access_role, AccessRole};
//!
//! # let _scope = APP.defaults();
//! let search_txt = var(Txt::from(""));
//! # let _ =
//! TextInput! {
//! access_role = AccessRole::SearchBox;
//! placeholder_txt = "search";
//! txt = search_txt;
//! }
//! # ;
//! ```
//!
//! # Service & Events
//!
//! The [`ACCESS`] service provides methods that control widgets by notifying accessibility events. Access events
//! are handled by widgets even when accessibility is disabled.
//!
//! In the example below the button shows and hides the tooltip of a different widget using [`ACCESS.show_tooltip`]
//! and [`ACCESS.hide_tooltip`].
//!
//! ```
//! use zng::prelude::*;
//!
//! let mut show_tooltip = false;
//! # let _scope = APP.defaults(); let _ =
//! Window! {
//! child_align = Align::CENTER;
//! child = Stack!(top_to_bottom, 50, ui_vec![
//! Button! {
//! on_click = hn!(|_| {
//! use zng::access::ACCESS;
//!
//! show_tooltip = !show_tooltip;
//! if show_tooltip {
//! ACCESS.show_tooltip(WINDOW.id(), "tooltip-anchor");
//! } else {
//! ACCESS.hide_tooltip(WINDOW.id(), "tooltip-anchor");
//! }
//! });
//! child = Text!("Toggle Tooltip");
//! },
//! Text! {
//! id = "tooltip-anchor";
//! txt = "tooltip anchor";
//! tooltip = Tip!(Text!("Tooltip"));
//! }
//! ])
//! }
//! # ;
//! ```
//!
//! [`ACCESS.show_tooltip`]: ACCESS::show_tooltip
//! [`ACCESS.hide_tooltip`]: ACCESS::hide_tooltip
//!
//! # Full API
//!
//! See [`zng_app::access`] and [`zng_wgt_access`] for the full API.
pub use zng_app::access::{
AccessClickArgs, AccessExpanderArgs, AccessIncrementArgs, AccessInitedArgs, AccessNumberArgs, AccessScrollArgs, AccessSelectionArgs,
AccessTextArgs, AccessToolTipArgs, ScrollCmd, ACCESS, ACCESS_CLICK_EVENT, ACCESS_EXPANDER_EVENT, ACCESS_INCREMENT_EVENT,
ACCESS_INITED_EVENT, ACCESS_NUMBER_EVENT, ACCESS_SCROLL_EVENT, ACCESS_SELECTION_EVENT, ACCESS_TEXT_EVENT, ACCESS_TOOLTIP_EVENT,
};
pub use zng_wgt_access::{
access_commands, access_role, accessible, active_descendant, auto_complete, checked, col_count, col_index, col_span, controls, current,
described_by, details, error_message, expanded, flows_to, invalid, item_count, item_index, label, labelled_by, labelled_by_child,
level, live, modal, multi_selectable, on_access_click, on_access_expander, on_access_increment, on_access_number, on_access_scroll,
on_access_selection, on_access_text, on_access_tooltip, on_pre_access_click, on_pre_access_expander, on_pre_access_increment,
on_pre_access_number, on_pre_access_scroll, on_pre_access_selection, on_pre_access_text, on_pre_access_tooltip, orientation, owns,
placeholder, popup, read_only, required, row_count, row_index, row_span, scroll_horizontal, scroll_vertical, selected, sort, value,
value_max, value_min, AccessCmdName, AccessRole, AutoComplete, CurrentKind, Invalid, LiveIndicator, Orientation, Popup, SortDirection,
};