Skip to content

Commit

Permalink
examples: Add example for custom AccessibleText implementations
Browse files Browse the repository at this point in the history
  • Loading branch information
felinira authored and bilelmoussaoui committed Oct 31, 2024
1 parent e3a4199 commit 3909afb
Show file tree
Hide file tree
Showing 5 changed files with 144 additions and 1 deletion.
11 changes: 10 additions & 1 deletion examples/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ libloading = { version = "0.8.5", optional = true }
im-rc = { version = "15", optional = true }
async-channel = { version = "2.3", optional = true }
tokio = { version = "1", features = ["full"], optional = true }
reqwest = { version = "0.12", features = ["json", "rustls-tls"], default-features = false, optional = true }
reqwest = { version = "0.12", features = [
"json",
"rustls-tls",
], default-features = false, optional = true }
serde = { version = "1.0", features = ["derive"], optional = true }

gtk.workspace = true
Expand All @@ -36,12 +39,18 @@ v4_6 = ["gtk/v4_6"]
v4_10 = ["gtk/v4_10"]
v4_12 = ["gtk/v4_12"]
v4_14 = ["gtk/v4_14"]
v4_16 = ["gtk/v4_16"]

[[bin]]
name = "about_dialog"
path = "about_dialog/main.rs"
required-features = ["v4_6"]

[[bin]]
name = "accessible_text"
path = "accessible_text/main.rs"
required-features = ["v4_16"]

[[bin]]
name = "basics"
path = "basics/main.rs"
Expand Down
1 change: 1 addition & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ cargo run --bin basics

- [Basic example](./basics/)
- [About Dialog](./about_dialog/)
- [Implementing the Accessible Text Interface](./accessible_text/)
- [Using the Builder pattern](./builder_pattern/)
- [Clipboard](./clipboard/)
- [Clock example](./clock/)
Expand Down
7 changes: 7 additions & 0 deletions examples/accessible_text/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Implementing the Accessible Text Interface

This example creates a custom text editing widget that implements the Accessible Text Interface. This interface is used for providing screen reader accessibility to custom widgets.

To test this implementation, enable the screen reader (Orca is enabled via Super+Alt+S) and edit / navigate the text.

The widget mostly just delegates its implementation to the parent `TextView`.
24 changes: 24 additions & 0 deletions examples/accessible_text/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
mod text_view;

use gtk::{glib, prelude::*};
use text_view::AccessibleTextView;

fn main() -> glib::ExitCode {
let application = gtk::Application::builder()
.application_id("com.github.gtk-rs.examples.accessible_text")
.build();
application.connect_activate(build_ui);
application.run()
}

fn build_ui(application: &gtk::Application) {
let window = gtk::ApplicationWindow::new(application);

window.set_title(Some("Accessible Text Example"));
window.set_default_size(260, 140);

let text_view = glib::Object::new::<AccessibleTextView>();
window.set_child(Some(&text_view));

window.present();
}
102 changes: 102 additions & 0 deletions examples/accessible_text/text_view.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
use gtk::glib;
use gtk::subclass::prelude::*;

mod imp {
use gtk::{graphene, ACCESSIBLE_ATTRIBUTE_OVERLINE, ACCESSIBLE_ATTRIBUTE_OVERLINE_SINGLE};

use super::*;

#[derive(Default)]
pub struct AccessibleTextView {}

#[glib::object_subclass]
impl ObjectSubclass for AccessibleTextView {
const NAME: &'static str = "AccessibleTextView";
type Type = super::AccessibleTextView;
type ParentType = gtk::TextView;
type Interfaces = (gtk::AccessibleText,);
}

impl ObjectImpl for AccessibleTextView {}
impl WidgetImpl for AccessibleTextView {}
impl AccessibleTextImpl for AccessibleTextView {
fn attributes(
&self,
offset: u32,
) -> Vec<(gtk::AccessibleTextRange, glib::GString, glib::GString)> {
let attributes = self.parent_attributes(offset);
println!("attributes({offset}) -> {attributes:?}");
attributes
}

fn caret_position(&self) -> u32 {
let pos = self.parent_caret_position();
println!("caret_position() -> {pos}");
pos
}

fn contents(&self, start: u32, end: u32) -> Option<glib::Bytes> {
let content = self.parent_contents(start, end);
println!(
"contents({start}, {end}) -> {:?}",
content
.as_ref()
.map(|c| std::str::from_utf8(c.as_ref()).unwrap())
);
content
}

fn contents_at(
&self,
offset: u32,
granularity: gtk::AccessibleTextGranularity,
) -> Option<(u32, u32, glib::Bytes)> {
let contents = self.parent_contents_at(offset, granularity);
println!(
"contents_at offset({offset}, {granularity:?}) -> {:?}",
contents
.as_ref()
.map(|(s, e, c)| (s, e, std::str::from_utf8(c.as_ref()).unwrap()))
);
contents
}

fn default_attributes(&self) -> Vec<(glib::GString, glib::GString)> {
let mut attrs = self.parent_default_attributes();

// Attributes can be added and removed
attrs.push((
ACCESSIBLE_ATTRIBUTE_OVERLINE.to_owned(),
ACCESSIBLE_ATTRIBUTE_OVERLINE_SINGLE.to_owned(),
));
println!("default_attributes() -> {attrs:?}");
attrs
}

fn selection(&self) -> Vec<gtk::AccessibleTextRange> {
let selection = self.parent_selection();
println!("selection() -> {selection:?}");
selection
}

fn extents(&self, start: u32, end: u32) -> Option<graphene::Rect> {
let extents = self.parent_extents(start, end);
println!("extents({start}, {end}) -> {extents:?}");
extents
}

fn offset(&self, point: &graphene::Point) -> Option<u32> {
let offset = self.parent_offset(point);
println!("offset({:?}) -> {offset:?}", point);
offset
}
}

impl TextViewImpl for AccessibleTextView {}
}

glib::wrapper! {
pub struct AccessibleTextView(ObjectSubclass<imp::AccessibleTextView>)
@extends gtk::Widget, gtk::TextView,
@implements gtk::Accessible, gtk::AccessibleText, gtk::Buildable, gtk::ConstraintTarget, gtk::Scrollable;
}

0 comments on commit 3909afb

Please sign in to comment.