arcade icon indicating copy to clipboard operation
arcade copied to clipboard

Sections Rework

Open benjamin-kirkbride opened this issue 3 weeks ago • 2 comments

See https://discord.com/channels/458662222697070613/1254980545780125776 for some additional context.

The Section Docs are Misleading, Confusing and Sparse

  • The purpose of sections is not really described in detail anywhere.
    • I would say at a high level, the relationship/hierarchy between windows, views, and sections could use an explainer
  • The API docs/docstrings need work

Events Are Somewhat Opaque

  • maybe I'm ignorant, but we don't have any docs explaining all of the events (I know technically Pyglet probably does? but that doesn't seem like a great solution to this)
  • there is no built-in way to see what happens to your events as they traverse the stack. it would be cool if there was a way to debug, perhaps a flag or something to enable logging all events as they traverse the stack and where they are captured/accepted? could use segment names for this to help

The Section Dispatch API is Needs Work

  • the accept_* args are delineated based on keyboard or mouse, but the prevent_* args are based on the section stack or the view.
  • the accept_* args have a type signature of Union[bool, Iterable], but the prevent_* type signature is Optional[Iterable]. In addition, the prevent_ iterables have special behavior if the iterable contains a single boolean (unclear/undefined what happens if it contains multiple booleans, or booleans and events...)
  • a section has two distinct decisions to make for each event: do I listen/react to it or not, and do I propagate it down the stack or not. It is very unclear if and how to make each of those decisions currently. In fact, I'm not even sure that the full range of decisions can be made.
    • the "do I listen to/react" decision can be handled in the event function (the on_* functions), so in general it makes sense to be liberal with accepting events. Dispatch is different though. To my knowledge there is no way (no sane way?) to dispatch an event up or down the stack (or to the view); you have to have set that up ahead of time. Is this what we want?
  • the prevent_dispatch_view arg is weird; if it is set to {False} (disabled) it doesn't actually dispatch to the view UNLESS all other Segment's down the stack also have disabled preventing dispatch to the view. Is this intended? Is this what we want?

accept_keyboard_keys is broken (?)

Kind of hard to say for sure given the somewhat confusing docs, but see: https://discord.com/channels/458662222697070613/1254980545780125776/1254995360330416138

accept_mouse_events appears to work.

We Need More, Better Section Tests

Self explanatory.

Snippet for Testing

import arcade

WIDTH = 800
HEIGHT = 600


class Window(arcade.Window):

    def __init__(self) -> None:
        super().__init__(WIDTH, HEIGHT, "Section Issues Demo")


class FirstSection(arcade.Section):
    def on_mouse_press(self, x: float, y: float, button: int, modifiers: int) -> None:
        print(f"Pressed {button} at {x}, {y} in FirstSection")

    def on_key_press(self, symbol: int, modifiers: int) -> None:
        print(f"Pressed {symbol} in FirstSection")


class SecondSection(arcade.Section):
    def on_mouse_press(self, x: float, y: float, button: int, modifiers: int) -> None:
        print(f"Pressed {button} at {x}, {y} in SecondSection")

    def on_key_press(self, symbol: int, modifiers: int) -> None:
        print(f"Pressed {symbol} in FirstSection")


class View(arcade.View):

    def __init__(self) -> None:
        super().__init__()

        first_section = FirstSection(
            left=0,
            bottom=0,
            width=WIDTH,
            height=HEIGHT,
            accept_keyboard_keys=False,
        )
        self.add_section(first_section)

        second_section = SecondSection(
            left=0,
            bottom=0,
            width=WIDTH,
            height=HEIGHT,
        )
        self.add_section(second_section)

    def on_mouse_press(self, x: float, y: float, button: int, modifiers: int) -> None:
        print(f"Pressed {button} at {x}, {y} in View")


if __name__ == "__main__":
    window = Window()
    window.show_view(View())
    arcade.run()

benjamin-kirkbride avatar Jun 25 '24 03:06 benjamin-kirkbride