/*
 * This file is part of lanterna (http://code.google.com/p/lanterna/).
 * 
 * lanterna is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * Copyright (C) 2010-2020 Martin Berglund
 */
package com.googlecode.lanterna.gui2;

import com.googlecode.lanterna.TerminalPosition;
import com.googlecode.lanterna.input.KeyStroke;

Default implementation of Interactable that extends from AbstractComponent. If you want to write your own component that is interactable, i.e. can receive keyboard (and mouse) input, you probably want to extend from this class as it contains some common implementations of the methods from Interactable interface
Author:Martin
Type parameters:
  • <T> – Should always be itself, see AbstractComponent
/** * Default implementation of Interactable that extends from AbstractComponent. If you want to write your own component * that is interactable, i.e. can receive keyboard (and mouse) input, you probably want to extend from this class as * it contains some common implementations of the methods from {@code Interactable} interface * @param <T> Should always be itself, see {@code AbstractComponent} * @author Martin */
public abstract class AbstractInteractableComponent<T extends AbstractInteractableComponent<T>> extends AbstractComponent<T> implements Interactable { private InputFilter inputFilter; private boolean inFocus; private boolean enabled;
Default constructor
/** * Default constructor */
protected AbstractInteractableComponent() { inputFilter = null; inFocus = false; enabled = true; } @Override public T takeFocus() { if(!isEnabled()) { return self(); } BasePane basePane = getBasePane(); if(basePane != null) { basePane.setFocusedInteractable(this); } return self(); }
{@inheritDoc}

This method is final in AbstractInteractableComponent, please override afterEnterFocus instead

/** * {@inheritDoc} * <p> * 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 AbstractInteractableComponent automatically after this component has received input focus. You can override this method if you need to trigger some action based on this.
Params:
  • 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
  • previouslyInFocus – Which interactable component had focus previously
/** * 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 AbstractInteractableComponent, please override afterLeaveFocus instead

/** * {@inheritDoc} * <p> * 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 AbstractInteractableComponent automatically after this component has lost input focus. You can override this method if you need to trigger some action based on this.
Params:
  • 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
  • nextInFocus – Which interactable component is going to receive focus
/** * 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<T> createDefaultRenderer(); @Override public InteractableRenderer<T> getRenderer() { return (InteractableRenderer<T>)super.getRenderer(); } @Override public boolean isFocused() { return inFocus; } @Override public synchronized T setEnabled(boolean enabled) { this.enabled = enabled; if(!enabled && isFocused()) { BasePane basePane = getBasePane(); if(basePane != null) { basePane.setFocusedInteractable(null); } } return self(); } @Override public boolean isEnabled() { return enabled; } @Override public boolean isFocusable() { return true; } @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, handleInput(..) is final in AbstractInteractableComponent to ensure the input filter is properly handled. If the filter decides that this event should be processed, it will call this method.
Params:
  • keyStroke – What input was entered by the user
Returns:Result of processing the key-stroke
/** * 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(); } }