Package limn.testing

Class SceneDriver

java.lang.Object
limn.testing.SceneDriver
All Implemented Interfaces:
WindowInput

public final class SceneDriver extends Object implements WindowInput
Drives a scene as a window would: pointer, keys, text, focus, fullscreen, resizes and the close, delivered to the input the scene hands its window and dispatched when the batch ends. What a test of an application's own UI uses in place of a display, and what the toolkit's own tests use, which is what keeps it honest.

Two levels. The WindowInput methods are the raw calls a backend makes, one event each, queued until inputBatchEnded() dispatches them, exactly as a frame's input arrives. The gestures — click(Widget), press(int), type(java.lang.String), moveTo(float, float), scroll(float, float, float, float) — are a whole user action each, batch included, and return the driver so they can be chained.


 Scene scene = new Scene(form);
 scene.layoutPass(400, 300);
 drive(scene).click(nameField).type("Ada").press(Keys.ENTER);
 

The scene's input is not on Scene itself, because an application never calls it: a window does. A driver is cheap, and drive(scene) may be called per event.

  • Method Summary

    Modifier and Type
    Method
    Description
    void
    charTyped(int codepoint)
    Committed text input, one code point (IME/layout-aware, after key events).
    click(float x, float y)
    A left click at a point: the pointer moves there, the button goes down and up, the batch ends.
    A left click at the centre of the widget with this id.
    click(Widget<?> widget)
    A left click at the centre of a widget, where the last layout pass placed it.
    drive(Scene scene)
     
    void
    filesDropped(List<Path> paths, float x, float y)
    Files dragged from the OS and dropped on the window, at a point of its content area in logical points: the widget under that point receives them.
    void
    End of one native poll: dispatch the accumulated batch now.
    void
    keyEvent(int key, int layoutCodePoint, boolean pressed, boolean repeat, int modifiers)
    A key went down, repeated or came up.
    void
    mouseButton(int button, boolean pressed, int modifiers, float x, float y, int clickCount)
    Button press/release at the given cursor position, with how many presses in a row this is, counted by the backend with the platform's own double-click interval and distance: 1 for a single press, 2 for the second of a double click.
    void
    mouseDelta(float dx, float dy)
    Relative pointer motion while the window is in PointerMode.RELATIVE: unbounded deltas in logical points (raw/unaccelerated where the platform supports it), replacing WindowInput.mouseMoved(float, float) for the duration of the capture.
    void
    mouseMoved(float x, float y)
     
    moveTo(float x, float y)
    Moves the pointer and ends the batch: a hover.
    void
    pointerEntered(boolean entered)
    Cursor entered (true) or left the window's content area.
    void
    preeditChanged(String text, int caret, int targetStart, int targetLength)
    In-progress IME composition ("preedit") for the focused text input: the still-composing text, its caret, and the stretch of it the input method is converting now (the target the user is choosing a candidate for), shown inline but not yet committed (the commit arrives later via WindowInput.charTyped(int)).
    press(int key)
    A key pressed and released with no modifier.
    press(int key, int modifiers)
    A key pressed and released with modifiers held.
     
    scroll(float deltaX, float deltaY, float x, float y)
    A wheel or trackpad scroll over a point.
    void
    scrolled(float deltaX, float deltaY, float x, float y)
    Wheel/trackpad scroll; deltas in native notches (positive = up/left).
    void
    scrolled(float deltaX, float deltaY, float x, float y, boolean gestureBegins)
    A scroll the platform says begins a new gesture: the fingers came down on a trackpad or on a mouse whose surface scrolls, inertia from the gesture before still running or not.
    type(String text)
    Text typed into whatever has the keyboard, one code point at a time, as the platform delivers committed characters.
    void
    The bound window was destroyed.
    void
    windowFocusChanged(boolean focused)
    The window gained or lost OS input focus.
    void
    windowFullscreenChanged(boolean fullscreen)
    The window entered (true) or left fullscreen: NativeWindow.isFullscreen() changed its answer.
    void
    windowResized(float logicalWidth, float logicalHeight)
    Window content resized (logical points).
    void
    zoomed(float scale, float x, float y, boolean gestureBegins)
    A pinch on a trackpad: a request to zoom around the point by a factor.

    Methods inherited from class java.lang.Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

    Methods inherited from interface limn.backend.spi.WindowInput

    canEditFocused, dragLeft, dragOver, dropped, editFocused, keyEvent, mouseButton
  • Method Details

    • drive

      public static SceneDriver drive(Scene scene)
      Parameters:
      scene - the scene to drive
      Returns:
      a driver delivering to that scene's window input
    • scene

      public Scene scene()
      Returns:
      the scene this driver delivers to
    • click

      public SceneDriver click(float x, float y)
      A left click at a point: the pointer moves there, the button goes down and up, the batch ends.
      Parameters:
      x - logical x in the scene
      y - logical y in the scene
      Returns:
      this driver
    • click

      public SceneDriver click(Widget<?> widget)
      A left click at the centre of a widget, where the last layout pass placed it.
      Parameters:
      widget - a widget in this driver's scene, laid out
      Returns:
      this driver
      Throws:
      IllegalArgumentException - when the widget is not in this scene
    • click

      public SceneDriver click(String id)
      A left click at the centre of the widget with this id.
      Parameters:
      id - the id, as Scene.find(String) looks it up
      Returns:
      this driver
      Throws:
      IllegalArgumentException - when no widget in the scene has that id
    • moveTo

      public SceneDriver moveTo(float x, float y)
      Moves the pointer and ends the batch: a hover.
      Parameters:
      x - logical x in the scene
      y - logical y in the scene
      Returns:
      this driver
    • scroll

      public SceneDriver scroll(float deltaX, float deltaY, float x, float y)
      A wheel or trackpad scroll over a point.

      A scroll can be dropped as the tail of a gesture. A fresh key press that a widget acts on ends the wheel stream still arriving, which is what stops a trackpad's inertia from scrolling away what an arrow key just revealed. So a scroll that arrives within 150 ms of the previous one, on the scene's clock, after such a key press, is dropped, and with the wall clock a test's calls are microseconds apart. A test that scrolls, presses a key and scrolls again builds its scene with a clock it advances (new Scene(root, clock)) and moves that clock past 150 ms before the second scroll.

      Parameters:
      deltaX - horizontal amount, in wheel notches
      deltaY - vertical amount, in wheel notches; positive scrolls up, as the platforms report
      x - logical x of the pointer
      y - logical y of the pointer
      Returns:
      this driver
    • press

      public SceneDriver press(int key)
      A key pressed and released with no modifier.
      Parameters:
      key - the key code, from Keys
      Returns:
      this driver
    • press

      public SceneDriver press(int key, int modifiers)
      A key pressed and released with modifiers held.
      Parameters:
      key - the key code, from Keys
      modifiers - the Keys.MOD_* bits held
      Returns:
      this driver
    • type

      public SceneDriver type(String text)
      Text typed into whatever has the keyboard, one code point at a time, as the platform delivers committed characters. Keys that are not text (Enter, Tab, arrows) are press(int).
      Parameters:
      text - the text
      Returns:
      this driver
    • mouseMoved

      public void mouseMoved(float x, float y)
      Specified by:
      mouseMoved in interface WindowInput
    • mouseDelta

      public void mouseDelta(float dx, float dy)
      Description copied from interface: WindowInput
      Relative pointer motion while the window is in PointerMode.RELATIVE: unbounded deltas in logical points (raw/unaccelerated where the platform supports it), replacing WindowInput.mouseMoved(float, float) for the duration of the capture. The receiver may coalesce by summing. Default: ignored.
      Specified by:
      mouseDelta in interface WindowInput
    • mouseButton

      public void mouseButton(int button, boolean pressed, int modifiers, float x, float y, int clickCount)
      Description copied from interface: WindowInput
      Button press/release at the given cursor position, with how many presses in a row this is, counted by the backend with the platform's own double-click interval and distance: 1 for a single press, 2 for the second of a double click. 0 means the backend does not count, and the receiver counts with its own clock.
      Specified by:
      mouseButton in interface WindowInput
    • scrolled

      public void scrolled(float deltaX, float deltaY, float x, float y)
      Description copied from interface: WindowInput
      Wheel/trackpad scroll; deltas in native notches (positive = up/left).
      Specified by:
      scrolled in interface WindowInput
    • scrolled

      public void scrolled(float deltaX, float deltaY, float x, float y, boolean gestureBegins)
      Description copied from interface: WindowInput
      A scroll the platform says begins a new gesture: the fingers came down on a trackpad or on a mouse whose surface scrolls, inertia from the gesture before still running or not. A receiver keeps a gesture with the scroller it moved, and only the platform can say where one gesture ends and the next begins while inertia keeps the events coming; a backend that cannot say calls WindowInput.scrolled(float, float, float, float), and the receiver tells gestures apart by the pauses between them.
      Specified by:
      scrolled in interface WindowInput
      Parameters:
      gestureBegins - whether this event is the first of a new gesture
    • zoomed

      public void zoomed(float scale, float x, float y, boolean gestureBegins)
      Description copied from interface: WindowInput
      A pinch on a trackpad: a request to zoom around the point by a factor. The backend turns its system's measure into the factor since its previous event: a magnification added to 1, or this event's scale since the gesture began over the previous one's. A system that sends the pinch as the wheel with Control held needs nothing here; the receiver offers that wheel as a zoom itself. A receiver that takes no zoom ignores it.
      Specified by:
      zoomed in interface WindowInput
      Parameters:
      scale - what to multiply the present size by, positive: above 1 zooms in
      gestureBegins - whether this event is the first of a new pinch
    • keyEvent

      public void keyEvent(int key, int layoutCodePoint, boolean pressed, boolean repeat, int modifiers)
      Description copied from interface: WindowInput
      A key went down, repeated or came up.
      Specified by:
      keyEvent in interface WindowInput
      Parameters:
      key - the physical key, a Keys constant
      layoutCodePoint - what the active layout types at that key with no modifier held, as a code point, or 0 for a key that types nothing; shortcuts are read from it
      pressed - a press or an auto-repeat rather than a release
      repeat - an auto-repeat
      modifiers - the Keys.MOD_* bits held
    • charTyped

      public void charTyped(int codepoint)
      Description copied from interface: WindowInput
      Committed text input, one code point (IME/layout-aware, after key events).
      Specified by:
      charTyped in interface WindowInput
    • preeditChanged

      public void preeditChanged(String text, int caret, int targetStart, int targetLength)
      Description copied from interface: WindowInput
      In-progress IME composition ("preedit") for the focused text input: the still-composing text, its caret, and the stretch of it the input method is converting now (the target the user is choosing a candidate for), shown inline but not yet committed (the commit arrives later via WindowInput.charTyped(int)). An empty text clears the composition. Every index is in code points. Default: ignored.

      What it means, rather than one platform's shape of it: GLFW reports styled blocks and the focused one, SDL a string and a selection; a backend turns either into the target's start and length.

      Specified by:
      preeditChanged in interface WindowInput
      Parameters:
      text - the composing text ("" clears it)
      caret - caret position within text
      targetStart - where the stretch being converted starts within text
      targetLength - how long it is; 0 when nothing is being converted
    • pointerEntered

      public void pointerEntered(boolean entered)
      Description copied from interface: WindowInput
      Cursor entered (true) or left the window's content area.
      Specified by:
      pointerEntered in interface WindowInput
    • windowResized

      public void windowResized(float logicalWidth, float logicalHeight)
      Description copied from interface: WindowInput
      Window content resized (logical points). May be coalesced by the receiver.
      Specified by:
      windowResized in interface WindowInput
    • filesDropped

      public void filesDropped(List<Path> paths, float x, float y)
      Description copied from interface: WindowInput
      Files dragged from the OS and dropped on the window, at a point of its content area in logical points: the widget under that point receives them. The point is the platform's where it says one (SDL does), and the pointer's at the drop where it does not (GLFW). Default: ignored.
      Specified by:
      filesDropped in interface WindowInput
      Parameters:
      paths - the files, in the order the platform listed them
      x - where they were dropped, in logical points
      y - where they were dropped, in logical points
    • windowFocusChanged

      public void windowFocusChanged(boolean focused)
      Description copied from interface: WindowInput
      The window gained or lost OS input focus. On loss the scene cancels any in-flight press/drag/hover; the matching RELEASE will never arrive (it happens in another app), so it is synthesized. Default: ignored.
      Specified by:
      windowFocusChanged in interface WindowInput
    • windowFullscreenChanged

      public void windowFullscreenChanged(boolean fullscreen)
      Description copied from interface: WindowInput
      The window entered (true) or left fullscreen: NativeWindow.isFullscreen() changed its answer. Every change is told once, whoever made it: the application's enterFullscreen and exitFullscreen, and on macOS the person's green button, Control-Command-F or menu item. It is told when the answer changes, which for macOS native fullscreen is when the animation starts rather than when it ends. On the scene it closes a menu, a drop-down list or a calendar that is open in a window of its own, placed against the geometry the change is taking away, and moves a modal dialog's window into the scene.

      Told even while a modal blocks the window, as a focus change is: the dialog that blocks it is one of the surfaces that has to hear it. Arrives during the native poll, or from inside the call that changed fullscreen, and like the rest of the batch it is acted on when the batch ends. Default: ignored.

      Specified by:
      windowFullscreenChanged in interface WindowInput
    • inputBatchEnded

      public void inputBatchEnded()
      Description copied from interface: WindowInput
      End of one native poll: dispatch the accumulated batch now.
      Specified by:
      inputBatchEnded in interface WindowInput
    • windowClosed

      public void windowClosed()
      Description copied from interface: WindowInput
      The bound window was destroyed. Lets the receiver flush any work that was waiting on a future frame which will now never come, chiefly a window-fade arrival callback (e.g. a dialog completing its result after fading out), since a destroyed window never ticks again. UI thread.
      Specified by:
      windowClosed in interface WindowInput