class CheckBox extends AbstractInteractableComponent<CheckBox> {

    /**
     * Listener interface that can be used to catch user events on the check box
     */
    public interface Listener {
        /**
         * This is fired when the user has altered the checked state of this {@code CheckBox}
         * @param checked If the {@code CheckBox} is now toggled on, this is set to {@code true}, otherwise
         * {@code false}
         */
        void onStatusChanged(boolean checked);
    }

    private final List<Listener> listeners;
    private String label;
    private boolean checked;

    /**
     * Creates a new checkbox with no label, initially set to un-checked
     */
    public CheckBox() {
        this("");
    }

    /**
     * Creates a new checkbox with a specific label, initially set to un-checked
     * @param label Label to assign to the check box
     */
    public CheckBox(String label) {
        if(label == null) {
            throw new IllegalArgumentException("Cannot create a CheckBox with null label");
        }
        else if(label.contains("\n") || label.contains("\r")) {
            throw new IllegalArgumentException("Multiline checkbox labels are not supported");
        }
        this.listeners = new CopyOnWriteArrayList<>();
        this.label = label;
        this.checked = false;
    }

    /**
     * Programmatically updated the check box to a particular checked state
     * @param checked If {@code true}, the check box will be set to toggled on, otherwise {@code false}
     * @return Itself
     */
    public synchronized CheckBox setChecked(final boolean checked) {
        this.checked = checked;
        runOnGUIThreadIfExistsOtherwiseRunDirect(() -> {
            for(Listener listener : listeners) {
                listener.onStatusChanged(checked);
            }
        });
        invalidate();
        return this;
    }

    /**
     * Returns the checked state of this check box
     * @return {@code true} if the check box is toggled on, otherwise {@code false}
     */
    public boolean isChecked() {
        return checked;
    }

    @Override
    public Result handleKeyStroke(KeyStroke keyStroke) {<FILL_FUNCTION_BODY>}

    /**
     * Updates the label of the checkbox
     * @param label New label to assign to the check box
     * @return Itself
     */
    public synchronized CheckBox setLabel(String label) {
        if(label == null) {
            throw new IllegalArgumentException("Cannot set CheckBox label to null");
        }
        this.label = label;
        invalidate();
        return this;
    }

    /**
     * Returns the label of check box
     * @return Label currently assigned to the check box
     */
    public String getLabel() {
        return label;
    }

    /**
     * Adds a listener to this check box so that it will be notificed on certain user actions
     * @param listener Listener to fire events on
     * @return Itself
     */
    public CheckBox addListener(Listener listener) {
        if(listener != null && !listeners.contains(listener)) {
            listeners.add(listener);
        }
        return this;
    }

    /**
     * Removes a listener from this check box so that, if it was previously added, it will no long receive any events
     * @param listener Listener to remove from the check box
     * @return Itself
     */
    public CheckBox removeListener(Listener listener) {
        listeners.remove(listener);
        return this;
    }

    @Override
    protected CheckBoxRenderer createDefaultRenderer() {
        return new DefaultCheckBoxRenderer();
    }

    /**
     * Helper interface that doesn't add any new methods but makes coding new check box renderers a little bit more clear
     */
    public static abstract class CheckBoxRenderer implements InteractableRenderer<CheckBox> {
    }

    /**
     * The default renderer that is used unless overridden. This renderer will draw the checkbox label on the right side
     * of a "[ ]" block which will contain a "X" inside it if the check box has toggle status on
     */
    public static class DefaultCheckBoxRenderer extends CheckBoxRenderer {
        private static final TerminalPosition CURSOR_LOCATION = new TerminalPosition(1, 0);
        @Override
        public TerminalPosition getCursorLocation(CheckBox component) {
            if(component.getThemeDefinition().isCursorVisible()) {
                return CURSOR_LOCATION;
            }
            else {
                return null;
            }
        }

        @Override
        public TerminalSize getPreferredSize(CheckBox component) {
            int width = 3;
            if(!component.label.isEmpty()) {
                width += 1 + TerminalTextUtils.getColumnWidth(component.label);
            }
            return new TerminalSize(width, 1);
        }

        @Override
        public void drawComponent(TextGUIGraphics graphics, CheckBox component) {
            ThemeDefinition themeDefinition = component.getThemeDefinition();
            if(component.isFocused()) {
                graphics.applyThemeStyle(themeDefinition.getActive());
            }
            else {
                graphics.applyThemeStyle(themeDefinition.getNormal());
            }

            graphics.fill(' ');
            graphics.putString(4, 0, component.label);

            if(component.isFocused()) {
                graphics.applyThemeStyle(themeDefinition.getPreLight());
            }
            else {
                graphics.applyThemeStyle(themeDefinition.getInsensitive());
            }
            graphics.setCharacter(0, 0, themeDefinition.getCharacter("LEFT_BRACKET", '['));
            graphics.setCharacter(2, 0, themeDefinition.getCharacter("RIGHT_BRACKET", ']'));
            graphics.setCharacter(3, 0, ' ');

            if(component.isFocused()) {
                graphics.applyThemeStyle(themeDefinition.getSelected());
            }
            else {
                graphics.applyThemeStyle(themeDefinition.getNormal());
            }
            graphics.setCharacter(1, 0, (component.isChecked() ? themeDefinition.getCharacter("MARKER", 'x') : ' '));
        }
    }
}

        if (isKeyboardActivationStroke(keyStroke)) {
            setChecked(!isChecked());
            return Result.HANDLED;
        } else if (isMouseActivationStroke(keyStroke)) {
            getBasePane().setFocusedInteractable(this);
            setChecked(!isChecked());
            return Result.HANDLED;
        }
        return super.handleKeyStroke(keyStroke);
    
<methods>public com.googlecode.lanterna.TerminalPosition getCursorLocation() ,public com.googlecode.lanterna.gui2.InputFilter getInputFilter() ,public InteractableRenderer<com.googlecode.lanterna.gui2.CheckBox> getRenderer() ,public final synchronized com.googlecode.lanterna.gui2.Interactable.Result handleInput(com.googlecode.lanterna.input.KeyStroke) ,public boolean isActivationStroke(com.googlecode.lanterna.input.KeyStroke) ,public boolean isEnabled() ,public boolean isFocusable() ,public boolean isFocused() ,public boolean isKeyboardActivationStroke(com.googlecode.lanterna.input.KeyStroke) ,public boolean isMouseActivationStroke(com.googlecode.lanterna.input.KeyStroke) ,public boolean isMouseDown(com.googlecode.lanterna.input.KeyStroke) ,public boolean isMouseDrag(com.googlecode.lanterna.input.KeyStroke) ,public boolean isMouseMove(com.googlecode.lanterna.input.KeyStroke) ,public boolean isMouseUp(com.googlecode.lanterna.input.KeyStroke) ,public final void onEnterFocus(com.googlecode.lanterna.gui2.Interactable.FocusChangeDirection, com.googlecode.lanterna.gui2.Interactable) ,public final void onLeaveFocus(com.googlecode.lanterna.gui2.Interactable.FocusChangeDirection, com.googlecode.lanterna.gui2.Interactable) ,public synchronized com.googlecode.lanterna.gui2.CheckBox setEnabled(boolean) ,public synchronized com.googlecode.lanterna.gui2.CheckBox setInputFilter(com.googlecode.lanterna.gui2.InputFilter) ,public com.googlecode.lanterna.gui2.CheckBox takeFocus() <variables>private boolean enabled,private boolean inFocus,private com.googlecode.lanterna.gui2.InputFilter inputFilter