implements Interactable {
private InputFilter inputFilter;
private boolean inFocus;
/**
* Default constructor
*/
protected AbstractInteractableComponent() {
inputFilter = null;
inFocus = false;
}
@Override
public T takeFocus() {
BasePane basePane = getBasePane();
if(basePane != null) {
basePane.setFocusedInteractable(this);
}
return self();
}
/**
* {@inheritDoc}
*
* This method is final in {@code AbstractInteractableComponent}, please override {@code afterEnterFocus} instead
*/
@Override
public final void onEnterFocus(FocusChangeDirection direction, Interactable previouslyInFocus) {
inFocus = true;
afterEnterFocus(direction, previouslyInFocus);
}
/**
* Called by {@code AbstractInteractableComponent} automatically after this component has received input focus. You
* can override this method if you need to trigger some action based on this.
* @param direction How focus was transferred, keep in mind this is from the previous component's point of view so
* if this parameter has value DOWN, focus came in from above
* @param previouslyInFocus Which interactable component had focus previously
*/
@SuppressWarnings("EmptyMethod")
protected void afterEnterFocus(FocusChangeDirection direction, Interactable previouslyInFocus) {
//By default no action
}
/**
* {@inheritDoc}
*
* This method is final in {@code AbstractInteractableComponent}, please override {@code afterLeaveFocus} instead
*/
@Override
public final void onLeaveFocus(FocusChangeDirection direction, Interactable nextInFocus) {
inFocus = false;
afterLeaveFocus(direction, nextInFocus);
}
/**
* Called by {@code AbstractInteractableComponent} automatically after this component has lost input focus. You
* can override this method if you need to trigger some action based on this.
* @param direction How focus was transferred, keep in mind this is from the this component's point of view so
* if this parameter has value DOWN, focus is moving down to a component below
* @param nextInFocus Which interactable component is going to receive focus
*/
@SuppressWarnings("EmptyMethod")
protected void afterLeaveFocus(FocusChangeDirection direction, Interactable nextInFocus) {
//By default no action
}
@Override
protected abstract InteractableRenderer createDefaultRenderer();
@Override
public InteractableRenderer getRenderer() {
return (InteractableRenderer)super.getRenderer();
}
@Override
public boolean isFocused() {
return inFocus;
}
@Override
public final synchronized Result handleInput(KeyStroke keyStroke) {
if(inputFilter == null || inputFilter.onInput(this, keyStroke)) {
return handleKeyStroke(keyStroke);
}
else {
return Result.UNHANDLED;
}
}
/**
* This method can be overridden to handle various user input (mostly from the keyboard) when this component is in
* focus. The input method from the interface, {@code handleInput(..)} is final in
* {@code AbstractInteractableComponent} to ensure the input filter is properly handled. If the filter decides that
* this event should be processed, it will call this method.
* @param keyStroke What input was entered by the user
* @return Result of processing the key-stroke
*/
protected Result handleKeyStroke(KeyStroke keyStroke) {
// Skip the keystroke if ctrl, alt or shift was down
if(!keyStroke.isAltDown() && !keyStroke.isCtrlDown() && !keyStroke.isShiftDown()) {
switch(keyStroke.getKeyType()) {
case ArrowDown:
return Result.MOVE_FOCUS_DOWN;
case ArrowLeft:
return Result.MOVE_FOCUS_LEFT;
case ArrowRight:
return Result.MOVE_FOCUS_RIGHT;
case ArrowUp:
return Result.MOVE_FOCUS_UP;
case Tab:
return Result.MOVE_FOCUS_NEXT;
case ReverseTab:
return Result.MOVE_FOCUS_PREVIOUS;
case MouseEvent:
getBasePane().setFocusedInteractable(this);
return Result.HANDLED;
default:
}
}
return Result.UNHANDLED;
}
@Override
public TerminalPosition getCursorLocation() {
return getRenderer().getCursorLocation(self());
}
@Override
public InputFilter getInputFilter() {
return inputFilter;
}
@Override
public synchronized T setInputFilter(InputFilter inputFilter) {
this.inputFilter = inputFilter;
return self();
}
}