Ontology in PennController

Previous page: Sample trial: Text+Key Response

Next page: Sample trial: Picture Selection & Audio Playback

Elements

Note: all the element categories are listed and described on the reference documentation.

So far, we have seen two categories of elements:

  • the text elements
  • the key elements

There are many more categories of elements, and we are about to introduce some of them:

  • the image elements
  • the canvas elements
  • the selector elements
  • the audio elements
  • the scale elements

All the commands that start with a period . within a PennController trial relate to an element: either to a newly created element through a command of the form newX("id", ...) or to a previously created element through a command of the form getX("id") (where X is the category of the element and “id” is a trial-internal unique identifier name).

Not all the PennController elements add some visible content to the screen: for instance, key elements do not add any visual information. Actually, if you don’t use any .print(), no element ever adds anything to the screen. Which brings us to the discussion of the different categories of commands.

Categories of commands

Note: all the commands are listed and described on the reference documentation.

Actions

Again, anything that you do in a PennController trial, you do in relation to an element. This is why you have to create and refer back to elements using commands of the form newX and getX. But if you don’t use commands starting with a . onto them, you won’t get far: indeed, you’ll stay at your starting point.

So far we have seen two types of action commands:

  • .print
  • .wait

These commands have a direct effect where they are called. The .print command adds the content of the element (if any) to the screen at the moment when it is called. This is why the two codes below have different effects.

This prints the instruction text below the test sentence:

PennController.ResetPrefix(null);

PennController(
    newText("test sentence", "A is colder than B, though A is not cold yet.")
        .print()
    ,
    newText("instruction", "Press F if this is a coherent statement, press J otherwise.")
        .print()
    ,
    newKey("answer", "FJ")
        .wait() // This waits for a key press before validation
);

But this prints the test sentence below the instruction text:

PennController.ResetPrefix(null);

PennController(
    // We don't call '.print' yet
    newText("test sentence", "A is colder than B, though A is not cold yet.")
        //.print()
    ,
    newText("instruction", "Press F if this is a coherent statement, press J otherwise.")
        .print()
    ,
    // We refer back to our 'test sentence' element and print it now
    getText("test sentence")
        .print()
    ,
    newKey("answer", "FJ")
        .wait() // This waits for a key press before validation
);

The .wait command also has an immediate effect, though it does not add any content to the screen. It prevents all the commands below it from being evaluated as long as the relevant event has not happened. In the case of a key element, the participant has to press a key for the subsequent commands to be evaluated and executed. This is why the code below has the same effect as the code above, despite the key element being created before the instruction text element gets printed.

PennController.ResetPrefix(null);

PennController(
    newText("test sentence", "A is colder than B, though A is not cold yet.")
        .print()
    ,
    newKey("answer", "FJ")
    ,
    newText("instruction", "Press F if this is a coherent statement, press J otherwise.")
        .print()
    ,
    // We refer back to the 'answer' key element and wait only now
    getKey("answer")
        .wait()
);

Each category of element has its own set of actions, but some of them are very common, like .print for any element that has some content, or .wait for any interactive element.

Settings

Any command that starts with .settings modifies an attribute of an element in a way that makes sense even before any action is called. This is why you can call .settings.bold() on a text element even before it is added to the screen by the action command .print. You can call action and settings commands in arbitrary series, but remember that you always have to add the .settings prefix to any settings command that you call (even if the preceding command in the series is also a settings command).

Some settings commands, like .settings.bold(), have immediate effects on the properties of the element (though these can be unnoticeable if .print hasn’t been called yet) but others do not. For instance, the settings command .settings.log() (which you can call on a key element for instance) will have the effect of adding a line to the results file when the relevant event happens, even if the event happens after subsequent commands were evaluated and executed (in the case of a key element, .settings.log() will have the effect of adding a line to the results file at the end of the trial, reporting a key press event).
We will come back to the .settings.log() command later.

The settings commands will generally not delay the execution of subsequent commands (contrary to the action .wait command for instance). That being said, they themselves are affected by any preceding action command that can put the evaluation on hold. For instance, you would probably want to rewrite the script below, as it will make the text of the button element appear bold only after the button is clicked (because the .settings.bold() settings command comes after, rather than before, the .wait() action command) and the trial ends immediately after that, making the change unnoticeable.

PennController.ResetPrefix(null);

PennController(
    newText("test sentence", "A is colder than B, though A is not cold yet.")
        .print()
    ,
    newButton("continue", "Continue")
        .print()
        .wait()
        .settings.bold()
);

Test

There is a third category of commands than can be called on an element, which start with the prefix .test (or .testNot). While you can call an arbitrary series of action and settings commands on any element, you cannot insert a test command in a series: they should be called in isolation. Test commands are useful when you need to have different consequences depending on whether a condition is satisfied.

For instance, you can call the test command .test.pressed on key elements to inquire which key was pressed and act consistently, by using .success and .failure:

PennController.ResetPrefix(null);

PennController(
    newText("test sentence", "A is colder than B, though A is not cold yet.")
        .print()
    ,
    newKey("answer", "FJ")
        .wait()
    ,
    newText("positive feedback", "Correct!")    // Creation...
    ,
    newText("negative feedback", "Wrong...")    // ... but no print (yet)
    ,
    getKey("answer")    // We check that the key that was pressed is F
        .test.pressed("F")
        .success( // If it was 'F' then we print the positive feedback
            getText("positive feedback")
                .print()
        )
        .failure( // If it wasn't 'F' (then it was 'J') we print the negative feedback
            getText("negative feedback")
                .print()
        )
    ,
    newText("press to finish", "Press any key to finish")
        .print()
    ,
    // This is a new, independent key element
    newKey("finish", "")
        .wait()
);

Defaults

As we saw before, you can add default commands to be executed upon the creation of any element of a certain category. You can pass action as well as settings commands as defaults, but not test commands (it wouldn’t make sense anyway).

To add defaults, use defaultX and apply commands to it the same way you would to newX("id", ...) or getX("id"). You can type a series of default commands. The rules for the defaults commands are the same as for commands called on specific instances of elements: the settings default commands should all start with the .settings prefix, and the order in which you type them matters.


OK that’s enough ontology for today, let’s go the next Sample trial: Picture Selection & Audio Playback.