Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose the is_required property #497

Merged
merged 2 commits into from
Dec 15, 2024
Merged

Expose the is_required property #497

merged 2 commits into from
Dec 15, 2024

Conversation

DataTriny
Copy link
Member

This property is also used on Windows to indicate that an item must be selected from a listbox. This will come in a future PR.

Directly merging the two commits should properly update the version of the affected crates.

Tested with the following test program:

Test program source code
use accesskit::{Action, Node, NodeId, Rect, Role, Tree, TreeUpdate};
use accesskit_winit::{Adapter, Event as AccessKitEvent, WindowEvent as AccessKitWindowEvent};
use std::error::Error;
use winit::{
    application::ApplicationHandler,
    event::WindowEvent,
    event_loop::{ActiveEventLoop, EventLoop, EventLoopProxy},
    window::{Window, WindowId},
};

const WINDOW_TITLE: &str = "Test App";

const WINDOW_ID: NodeId = NodeId(0);
const TEXT_INPUT_ID: NodeId = NodeId(1);
const INITIAL_FOCUS: NodeId = TEXT_INPUT_ID;

const TEXT_INPUT_RECT: Rect = Rect {
    x0: 20.0,
    y0: 20.0,
    x1: 200.0,
    y1: 60.0,
};

fn build_text_input(label: &str) -> Node {
    let mut node = Node::new(Role::TextInput);
    node.set_bounds(TEXT_INPUT_RECT);
    node.set_label(label);
    node.set_required();
    node.add_action(Action::Focus);
    node
}

struct UiState {
    focus: NodeId,
}

impl UiState {
    fn new() -> Self {
        Self {
            focus: INITIAL_FOCUS,
        }
    }

    fn build_root(&mut self) -> Node {
        let mut node = Node::new(Role::Window);
        node.set_children(vec![TEXT_INPUT_ID]);
        node.set_label(WINDOW_TITLE);
        node
    }

    fn build_initial_tree(&mut self) -> TreeUpdate {
        let root = self.build_root();
        let text_input = build_text_input("Your name");
        let tree = Tree::new(WINDOW_ID);
        TreeUpdate {
            nodes: vec![(WINDOW_ID, root), (TEXT_INPUT_ID, text_input)],
            tree: Some(tree),
            focus: self.focus,
        }
    }
}

struct WindowState {
    window: Window,
    adapter: Adapter,
    ui: UiState,
}

impl WindowState {
    fn new(window: Window, adapter: Adapter, ui: UiState) -> Self {
        Self {
            window,
            adapter,
            ui,
        }
    }
}

struct Application {
    event_loop_proxy: EventLoopProxy<AccessKitEvent>,
    window: Option<WindowState>,
}

impl Application {
    fn new(event_loop_proxy: EventLoopProxy<AccessKitEvent>) -> Self {
        Self {
            event_loop_proxy,
            window: None,
        }
    }

    fn create_window(&mut self, event_loop: &ActiveEventLoop) -> Result<(), Box<dyn Error>> {
        let window_attributes = Window::default_attributes()
            .with_title(WINDOW_TITLE)
            .with_visible(false);

        let window = event_loop.create_window(window_attributes)?;
        let adapter = Adapter::with_event_loop_proxy(&window, self.event_loop_proxy.clone());
        window.set_visible(true);

        self.window = Some(WindowState::new(window, adapter, UiState::new()));
        Ok(())
    }
}

impl ApplicationHandler<AccessKitEvent> for Application {
    fn window_event(&mut self, _: &ActiveEventLoop, _: WindowId, event: WindowEvent) {
        let window = match &mut self.window {
            Some(window) => window,
            None => return,
        };
        let adapter = &mut window.adapter;

        adapter.process_event(&window.window, &event);
        match event {
            WindowEvent::CloseRequested => {
                self.window = None;
            }
            _ => (),
        }
    }

    fn user_event(&mut self, _: &ActiveEventLoop, user_event: AccessKitEvent) {
        let window = match &mut self.window {
            Some(window) => window,
            None => return,
        };
        let adapter = &mut window.adapter;
        let state = &mut window.ui;

        match user_event.window_event {
            AccessKitWindowEvent::InitialTreeRequested => {
                adapter.update_if_active(|| state.build_initial_tree());
            }
            _ => (),
        }
    }

    fn resumed(&mut self, event_loop: &ActiveEventLoop) {
        self.create_window(event_loop)
            .expect("failed to create initial window");
    }

    fn about_to_wait(&mut self, event_loop: &ActiveEventLoop) {
        if self.window.is_none() {
            event_loop.exit();
        }
    }
}

fn main() -> Result<(), Box<dyn Error>> {
    let event_loop = EventLoop::with_user_event().build()?;
    let mut state = Application::new(event_loop.create_proxy());
    event_loop.run_app(&mut state).map_err(Into::into)
}

@mwcampbell mwcampbell merged commit 46ed99b into main Dec 15, 2024
9 checks passed
@mwcampbell mwcampbell deleted the is_required branch December 15, 2024 20:43
@github-actions github-actions bot mentioned this pull request Dec 15, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants