com.github.ykrasik.jerminal.libgdx.ConsoleBuilder.java Source code

Java tutorial

Introduction

Here is the source code for com.github.ykrasik.jerminal.libgdx.ConsoleBuilder.java

Source

/******************************************************************************
 * Copyright (C) 2014 Yevgeny Krasik                                          *
 *                                                                            *
 * Licensed under the Apache License, Version 2.0 (the "License");            *
 * you may not use this file except in compliance with the License.           *
 * You may obtain a copy of the License at                                    *
 *                                                                            *
 * http://www.apache.org/licenses/LICENSE-2.0                                 *
 *                                                                            *
 * Unless required by applicable law or agreed to in writing, software        *
 * distributed under the License is distributed on an "AS IS" BASIS,          *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
 * See the License for the specific language governing permissions and        *
 * limitations under the License.                                             *
 ******************************************************************************/

package com.github.ykrasik.jerminal.libgdx;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.InputListener;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.ui.*;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
import com.github.ykrasik.jerminal.api.Console;
import com.github.ykrasik.jerminal.api.ConsoleImpl;
import com.github.ykrasik.jerminal.api.Shell;
import com.github.ykrasik.jerminal.api.display.DisplayDriver;
import com.github.ykrasik.jerminal.api.display.terminal.TerminalConfiguration;
import com.github.ykrasik.jerminal.api.display.terminal.TerminalDisplayDriver;
import com.github.ykrasik.jerminal.api.display.terminal.TerminalGuiController;
import com.github.ykrasik.jerminal.api.filesystem.ShellFileSystem;
import com.github.ykrasik.jerminal.libgdx.impl.LibGdxCommandLineDriver;
import com.github.ykrasik.jerminal.libgdx.impl.LibGdxTerminal;
import com.github.ykrasik.jerminal.libgdx.impl.LibGdxTerminalGuiController;

import java.util.Objects;

/**
 * A builder for a LibGdx console.<br>
 * The console contains a {@link com.github.ykrasik.jerminal.api.display.terminal.Terminal}
 * and a {@link com.github.ykrasik.jerminal.api.CommandLineDriver}.<br>
 * <br>
 * Will use a default skin if built with the default constructor, but can be built with a custom
 * skin through other constructors.<br>
 * Custom skins must provide:<br>
 *   A {@link com.badlogic.gdx.scenes.scene2d.utils.Drawable} called 'bottomRowBackground'
 *     that will be used as the background of the 'bottom row' (current path area, command line, close button).<br>
 *   A {@link com.badlogic.gdx.scenes.scene2d.utils.Drawable} called 'consoleBackground'
 *     that will be used as the background of the console.<br>
 *   A {@link com.badlogic.gdx.scenes.scene2d.utils.Drawable} called 'currentPathBackground'
 *     that will be used as the background of the 'current path' area.<br>
 *   A {@link com.badlogic.gdx.scenes.scene2d.ui.TextButton.TextButtonStyle} called 'closeConsoleButton'
 *     that will be used to style the close button.<br>
 *   A {@link com.badlogic.gdx.scenes.scene2d.ui.Label.LabelStyle} called 'currentPath'
 *     that will be used to style the 'current path' label.<br>
 *   A {@link com.badlogic.gdx.scenes.scene2d.ui.Label.LabelStyle} called 'terminalEntry'
 *     that will be used to style every entry in the terminal.<br>
 *   A {@link com.badlogic.gdx.scenes.scene2d.ui.TextField.TextFieldStyle} called 'commandLine'
 *     that will be used to style the command line.<br>
 * <br>
 *
 * @author Yevgeny Krasik
 */
public class ConsoleBuilder {
    private final ShellFileSystem fileSystem;
    private final Skin skin;

    private TerminalConfiguration configuration = TerminalConfiguration.DEFAULT_WHITE;
    private int maxTerminalEntries = 100;
    private int maxCommandHistory = 30;
    private String welcomeMessage = "Welcome to Jerminal!\n";

    /**
     * Constructs a console from the fileSystem using the default skin.
     *
     * @param fileSystem FileSystem to use.
     */
    public ConsoleBuilder(ShellFileSystem fileSystem) {
        this(fileSystem, new Skin(Gdx.files.classpath("com/github/ykrasik/jerminal/libgdx/console.cfg")));
    }

    /**
     * Constructs a console from the fileSystem using the provided skin.
     *
     * @param fileSystem FileSystem to use.
     * @param skin Skin to use.
     */
    public ConsoleBuilder(ShellFileSystem fileSystem, Skin skin) {
        this.fileSystem = Objects.requireNonNull(fileSystem);
        this.skin = Objects.requireNonNull(skin);
    }

    /**
     * Builds a {@link LibGdxConsole} that is the console. Will load the .fxml file passed by the constructor.
     * The console can be set toggle-able by attaching a {@link ConsoleToggler} to the {@link com.badlogic.gdx.scenes.scene2d.Stage}
     * it is added to.
     *
     * @return A console.
     */
    public LibGdxConsole build() {
        // Create the terminal.
        final LibGdxTerminal terminal = new LibGdxTerminal(skin, maxTerminalEntries);
        terminal.setName("terminal");
        terminal.bottom().left();

        // Create the current path label.
        final Label currentPath = new Label("", skin, "currentPath");
        currentPath.setName("currentPath");
        final TerminalGuiController guiController = new LibGdxTerminalGuiController(currentPath);

        // Create the shell.
        final DisplayDriver displayDriver = new TerminalDisplayDriver(terminal, guiController, configuration);
        final Shell shell = new Shell(fileSystem, displayDriver, welcomeMessage);

        // Create the command line.
        final TextField commandLine = new TextField("", skin, "commandLine");
        commandLine.setName("commandLine");
        final LibGdxCommandLineDriver commandLineDriver = new LibGdxCommandLineDriver(commandLine);

        // Create the console.
        final Console console = new ConsoleImpl(shell, commandLineDriver, maxCommandHistory);

        // Hook the commandLine to the console.
        commandLine.addListener(new LibGdxConsoleDriver(console));

        return createConsoleTable(terminal, currentPath, commandLine);
    }

    private LibGdxConsole createConsoleTable(LibGdxTerminal terminal, Label currentPath,
            final TextField commandLine) {
        final LibGdxConsole consoleTable = new LibGdxConsole(skin);
        consoleTable.setName("consoleTable");
        consoleTable.setBackground("consoleBackground");
        consoleTable.addVisibleListener(new VisibleListener() {
            @Override
            public void onVisibleChange(boolean wasVisible, boolean isVisible) {
                if (!wasVisible && isVisible) {
                    final Stage stage = consoleTable.getStage();
                    if (stage != null) {
                        stage.setKeyboardFocus(commandLine);
                    }
                }
            }
        });

        // A close console button.
        // TODO: This should be a button, not a text button.
        final Button closeButton = new TextButton("X", skin, "closeConsoleButton");
        closeButton.padRight(15).padLeft(15);
        closeButton.setName("closeButton");
        closeButton.addListener(new ClickListener() {
            @Override
            public void clicked(InputEvent event, float x, float y) {
                consoleTable.setVisible(false);
            }
        });

        // Some layout.

        final Table currentPathTable = new Table(skin);
        currentPathTable.setName("currentPathTable");
        currentPathTable.setBackground("currentPathBackground");
        currentPathTable.add(currentPath).fill().padLeft(3).padRight(5);

        // The bottom row contains the current path, command line and a close button.
        final Table bottomRow = new Table(skin);
        bottomRow.setName("bottomRow");
        bottomRow.setBackground("bottomRowBackground");
        bottomRow.add(currentPathTable).fill();
        bottomRow.add(commandLine).fill().expandX();
        bottomRow.add(closeButton).fill();

        consoleTable.pad(0);
        consoleTable.add(terminal).fill().expand();
        consoleTable.row();
        consoleTable.add(bottomRow).fill();
        consoleTable.top().left();

        return consoleTable;
    }

    /**
     * @param configuration Configuration to use.
     * @return this, for chained execution.
     */
    public ConsoleBuilder setConfiguration(TerminalConfiguration configuration) {
        this.configuration = Objects.requireNonNull(configuration);
        return this;
    }

    /**
     * Sets the maximum amount of terminal lines to keep.
     *
     * @param maxTerminalEntries Max terminal entries to set.
     * @return this, for chained execution.
     */
    public ConsoleBuilder setMaxTerminalEntries(int maxTerminalEntries) {
        this.maxTerminalEntries = maxTerminalEntries;
        return this;
    }

    /**
     * @param maxCommandHistory Max command history to set.
     * @return this, for chained execution.
     */
    public ConsoleBuilder setMaxCommandHistory(int maxCommandHistory) {
        this.maxCommandHistory = maxCommandHistory;
        return this;
    }

    /**
     * @param welcomeMessage Welcome message to set.
     * @return this, for chained execution.
     */
    public ConsoleBuilder setWelcomeMessage(String welcomeMessage) {
        this.welcomeMessage = Objects.requireNonNull(welcomeMessage);
        return this;
    }

    /**
     * Links input events to {@link com.github.ykrasik.jerminal.api.Console} events.
     *
     * @author Yevgeny Krasik
     */
    private static class LibGdxConsoleDriver extends InputListener {
        private final Console console;

        private LibGdxConsoleDriver(Console console) {
            this.console = Objects.requireNonNull(console);
        }

        @Override
        public boolean keyDown(InputEvent event, int keycode) {
            switch (keycode) {
            case Keys.ENTER:
                console.execute();
                return true;

            case Keys.TAB:
                console.assist();
                return true;

            case Keys.DPAD_UP:
                console.setPrevCommandLineFromHistory();
                return true;

            case Keys.DPAD_DOWN:
                console.setNextCommandLineFromHistory();
                return true;

            case Keys.Z:
                if (Gdx.input.isKeyPressed(Keys.CONTROL_LEFT)) {
                    console.clearCommandLine();
                    return true;
                }
            }

            return false;
        }
    }
}