How to turn the Propositional Production System (PPS) for a button into code
The code implementation should spiritually follow the PPS; that is, your code should only take
action when moving from state to state (along the arrows in the PPS). This behavior is best
represented by a switch
statement, where each case
represents a state in our PPS.
Within each case
, there can be nested if
statement to handle transitioning to another state.
Each case
should be broken out of and should properly handle input, propagating input to later
views or stopping the input propagation as necessary. We typically do this through the
onTouchEvent
method. In onTouchEvent
, returning true
will stop the input propagation to
views below it, while returning false
allows views below it to handle the event.
Button Examples
Given the essential geometry for this button is:
- Inside
- Outside
and methods for that will be used are:
-
indentButton()
(when button is pressed, also invalidate() the view) -
normalButton()
(when button is not pressed, also invalidate() the view) -
invokeAction()
(when the user releases in the button) -
cancelAction()
(when the user releases outside the button)
The PPS for this interaction is as follows:
>indentButton() PRESSED --> PRESSED: MOVE/Outside?
>normalButton() PRESSED --> [*]: UP/Outside?
cancelAction() PRESSED --> [*]: UP/Inside?
invokeAction() PRESSED --> PRESSED: MOVE/Inside?
indentButton()
The code is generated thusly
@Override
public boolean onTouch(MotionEvent e) {
EssentialGeometry geometry = essentialGeometry(event);
switch (state) {
case State.START:
if (geometry == Geometry.INSIDE && e.getAction() == MotionEvent.ACTION_DOWN) {
indentButton();
state = State.PRESSED;
return true;
}
break;
case PRESSED
if (e.getAction() == MotionEvent.ACTION_MOVE) {
if (geometry == Geometry.INSIDE) {
indentButton();
} else {
normalButton();
}
return true;
}
else if (e.getAction() == MotionEvent.ACTION_UP) {
state = State.START; // note we don't actually use the END state
if (geometry == Geometry.INSIDE) {
invokeAction();
} else {
cancelAction();
}
return true;
}
break;
default:
break;
}
return false;
}