GithubHelp home page GithubHelp logo

makus82 / zircon Goto Github PK

View Code? Open in Web Editor NEW

This project forked from hexworks/zircon

0.0 2.0 0.0 3.77 MB

Zircon is an extensible text GUI library which targets multiple platforms and designed specifically for game developers.

License: MIT License

Kotlin 88.53% Java 11.47%

zircon's Introduction

Zircon Tweet

Note that this library is deeply inspired by Lanterna. Check it out if you are looking for a terminal emulator instead.


Need info? Check the Wiki | or Create an issue | Check our project Board | Ask us on Discord

Awesome


Table of Contents

A little Crash Course

In order to work with Zircon you should get familiar with the core concepts. Zircon provides multiple layers of abstractions and it depends on your needs which one you should pick.

Terminal

At the lowest level Zircon provides the Terminal interface. This provides you with a surface on which you can draw TextCharacters. A TextCharacter is basically a character (like an x) with additional metadata like foregroundColor and backgroundColor. This surface sits on top of a GUI layer and completely abstracts away how that layer works. For example the default implementation of the Terminal interface uses Swing under the hood. The main advantage of using Terminals is that by implementing all its methods you can swap Swing with something else (like SWT) and use all higher level abstractions on top of it (like Screens) which depend on Terminal (more on Screens later). Working with Terminals is very simple but somewhat limited. A Terminal is responsible for:

  • drawing characters (by position or by cursor) on the screen
  • handling inputs (keyboard and mouse) which are emitted by the GUI layer
  • handling the cursor which is visible to the user
  • handling Layering
  • storing style information
  • drawing TextImages on top of it

This seems like a lot of things to do at once so you might ask "How is this SOLID?". Zircon solves this problem with composition: All of the above mentioned categories are handled by an object within a Terminal which is responsible for only one thing. For example Terminal implements the Layerable interface and internally all operations defined by it are delegated to an object which implements Layerable only. You can peruse these here. In this sense you can consider a Terminal as a Facade.

Colors and StyleSets

Objects like TextCharacters can have foreground and background colors. You can either use the ANSITextColor enum to pick a pre-defined TextColor or you can create a new one by using TextColorFactory. This class has some useful factory methods for this like: fromAWTColor, fromRGB and fromString. The latter can be called with simple CSS-like strings (eg: #334455).

If you don't want to set all these colors by hand or you want to have a color template and use it to set colors to multiple things you can use a StyleSet which is basically a Value Object which holds fore/background colors and modifiers.

Modifiers

When working with TextCharacters apart from giving them color you might want to apply some special Modifier to them like UNDERLINE or VERTICAL_FLIP. You can do this by picking the right Modifier from the Modifiers class. You can set any number of Modifiers to each TextCharacter individually and when you refresh your Terminal by calling flush on it you will see them applied.

TextImages

An image built from TextCharacters with color and style information. These are completely in memory and not visible, but can be used when drawing on other DrawSurfaces, like a Screen or a Terminal. In other words TextImages are like real images but composed of TextCharacters to create ASCII art and the like.

Screens

Screens are in-memory representations of your Terminal. They are double buffered which means that you write to a back-buffer and when you refresh your Screen only the changes will be written to the backing Terminal instance. Multiple Screens can be attached to the same Terminal object which means that you can have more than one screen in your app and you can switch between them simultaneously by using the display method. Screens also let you use Components like Buttons and Panels.

If you want to read more about the design philosophy behind Zircon check this page on Wiki!

If you are interested in how components work then this Wiki page can help you.

Now that we got the basics covered, let's see how this all works in practice.

Getting Started

If you want to work with Zircon you can add it to your project as a dependency.

from Maven:

<dependency>
    <groupId>org.codetome.zircon</groupId>
    <artifactId>zircon</artifactId>
    <version>2017.3.0</version>
</dependency>

or you can also use Gradle:

compile("org.codetome.zircon:zircon:2017.3.0")

Want to use a SNAPSHOT? Check this Wiki page

Some rules of thumb

Before we start there are some guidelines which can help you if you are stuck:

  • If you want to build something (a TextImage, a Component or anything which is part of the public API) it is almost sure that there is a Builder or a *Factory for it. If you want to build a TextImage you can use the TextImageBuilder to do so. Always look for a Builder or a Factory (in case of TextColors for example) to create the desired object. Your IDE will help you with that
  • If you want to work with external files like tilesets or REXPaint files check the resource package. There are a bunch of built-in tilesets for example which you can choose from but you can also load your own. The rule of thumb is that if you need something external there is probably a *Resource for it (like the REXPaintResource).
  • Anything in the api.beta package is considered a BETA feature and is subject to change.
  • You can use anything you can find in the API package and they will not change (so your code won't break). The internal package however is considered private to Zircon so don't depend on anything in it.
  • Some topics are explained in depth on the Wiki
  • If you want to see some example code look here.
  • If all else fails read the javadoc. API classes are rather well documented.
  • If you have any problems which are not answered here feel free to ask us at the Hexworks Discord server.

Creating a Terminal

In Zircon almost every object you might want to use has a Builder for it. This is the same for Terminals as well so let's create one using a TerminalBuilder:

import org.codetome.zircon.api.Size;
import org.codetome.zircon.api.builder.TerminalBuilder;
import org.codetome.zircon.api.terminal.Terminal;

public class Playground {

    public static void main(String[] args) {

        final Terminal terminal = TerminalBuilder.newBuilder()
                .initialTerminalSize(Size.of(32, 16))
                .build();

        terminal.flush();

    }
}

Running this snippet will result in this screen:

Adding and formatting content is also very simple:

import org.codetome.zircon.api.Modifiers;
import org.codetome.zircon.api.Size;
import org.codetome.zircon.api.builder.TerminalBuilder;
import org.codetome.zircon.api.color.ANSITextColor;
import org.codetome.zircon.api.terminal.Terminal;

public class Playground {

    public static void main(String[] args) {

        final Terminal terminal = TerminalBuilder.newBuilder()
                .initialTerminalSize(Size.of(20, 8))
                .build();

        terminal.enableModifiers(Modifiers.VERTICAL_FLIP);
        terminal.setForegroundColor(ANSITextColor.CYAN);
        terminal.putCharacter('a');
        terminal.resetColorsAndModifiers();

        terminal.setForegroundColor(ANSITextColor.GREEN);
        terminal.enableModifiers(Modifiers.HORIZONTAL_FLIP);
        terminal.putCharacter('b');
        terminal.resetColorsAndModifiers();

        terminal.setForegroundColor(ANSITextColor.RED);
        terminal.enableModifiers(Modifiers.CROSSED_OUT);
        terminal.putCharacter('c');
        terminal.flush();
    }
}

Running the above code will result in something like this:

You can do a lot of fancy stuff with Modifiers, like this:

If interested check out the code examples here.

You might have noticed that the default font is not very nice looking, so let's see what else the TerminalBuilder can do for us:

import org.codetome.zircon.api.Size;
import org.codetome.zircon.api.builder.DeviceConfigurationBuilder;
import org.codetome.zircon.api.builder.TerminalBuilder;
import org.codetome.zircon.api.color.ANSITextColor;
import org.codetome.zircon.api.resource.CP437TilesetResource;
import org.codetome.zircon.api.terminal.Terminal;
import org.codetome.zircon.api.terminal.config.CursorStyle;

public class Playground {

    private static final String TEXT = "Hello Zircon!";

    public static void main(String[] args) {

        final Terminal terminal = TerminalBuilder.newBuilder()
                .initialTerminalSize(Size.of(20, 8))
                .deviceConfiguration(DeviceConfigurationBuilder.newBuilder()
                        .cursorColor(ANSITextColor.RED)
                        .cursorStyle(CursorStyle.VERTICAL_BAR)
                        .cursorBlinking(true)
                        .blinkLengthInMilliSeconds(500)
                        .clipboardAvailable(true)
                        .build())
                .font(CP437TilesetResource.WANDERLUST_16X16.toFont())
                .title(TEXT)
                .build();

        terminal.setForegroundColor(ANSITextColor.GREEN);
        terminal.setCursorVisibility(true);
        TEXT.chars().forEach((c) -> terminal.putCharacter((char)c));

        terminal.flush();
    }
}

Font (and by extension resource) handling in Zircon is very simple and if you are interested in how to load your custom fonts and other resources take a look at the Resource handling wiki page.

Working with Screens

Terminals alone won't suffice if you want to get any serious work done since they are rather rudimentary.

Let's create a Screen and fill it up with some stuff:

import org.codetome.zircon.api.Position;
import org.codetome.zircon.api.Size;
import org.codetome.zircon.api.builder.TerminalBuilder;
import org.codetome.zircon.api.builder.TextCharacterBuilder;
import org.codetome.zircon.api.builder.TextImageBuilder;
import org.codetome.zircon.api.component.ColorTheme;
import org.codetome.zircon.api.graphics.TextImage;
import org.codetome.zircon.api.resource.CP437TilesetResource;
import org.codetome.zircon.api.resource.ColorThemeResource;
import org.codetome.zircon.api.screen.Screen;
import org.codetome.zircon.api.terminal.Terminal;

public class Playground {


    public static void main(String[] args) {

        final Terminal terminal = TerminalBuilder.newBuilder()
                .initialTerminalSize(Size.of(20, 8))
                .font(CP437TilesetResource.WANDERLUST_16X16.toFont())
                .build();
        final Screen screen = TerminalBuilder.createScreenFor(terminal);

        final ColorTheme theme = ColorThemeResource.ADRIFT_IN_DREAMS.getTheme();

        final TextImage image = TextImageBuilder.newBuilder()
                .size(terminal.getBoundableSize())
                .filler(TextCharacterBuilder.newBuilder()
                        .foregroundColor(theme.getBrightForegroundColor())
                        .backgroundColor(theme.getBrightBackgroundColor())
                        .character('~')
                        .build())
                .build();

        screen.draw(image, Position.DEFAULT_POSITION);

        screen.display();
    }
}

and we've got a nice ocean:

What happens here is that we:

  • Create a Screen
  • Fetch a nice ColorTheme which has colors we need
  • Create a TextImage with the colors added and fill it with ~s
  • Draw the image onto the Screen

You can do so much more with Screens. If interested then check out A primer on Screens on the Wiki!

Components

Zircon supports a bunch of Components out of the box:

  • Button: A simple clickable component with corresponding event listeners
  • CheckBox: Like a BUTTON but with checked / unchecked state
  • Label: Simple component with text
  • Header: Like a label but this one has emphasis (useful when using ColorThemes)
  • Panel: A [Container] which can hold multiple Components
  • RadioButtonGroup and RadioButton: Like a CheckBox but only one can be selected at a time
  • TextBox

These components are rather simple and you can expect them to work in a way you might be familiar with:

  • You can click on them (press and release are different events)
  • You can attach event listeners on them
  • Zircon implements focus handling so you can navigate between the components using the [Tab] key (forwards) or the [Shift]+[Tab] key stroke (backwards).
  • Components can be hovered and they can change their styling when you do so

Let's look at an example (notes about how it works are in the comments):

import org.codetome.zircon.api.Position;
import org.codetome.zircon.api.Size;
import org.codetome.zircon.api.builder.TerminalBuilder;
import org.codetome.zircon.api.component.Button;
import org.codetome.zircon.api.component.CheckBox;
import org.codetome.zircon.api.component.Header;
import org.codetome.zircon.api.component.Panel;
import org.codetome.zircon.api.component.builder.ButtonBuilder;
import org.codetome.zircon.api.component.builder.CheckBoxBuilder;
import org.codetome.zircon.api.component.builder.HeaderBuilder;
import org.codetome.zircon.api.component.builder.PanelBuilder;
import org.codetome.zircon.api.resource.CP437TilesetResource;
import org.codetome.zircon.api.resource.ColorThemeResource;
import org.codetome.zircon.api.screen.Screen;
import org.codetome.zircon.api.terminal.Terminal;

public class Playground {


    public static void main(String[] args) {

        final Terminal terminal = TerminalBuilder.newBuilder()
                .initialTerminalSize(Size.of(34, 18))
                .font(CP437TilesetResource.WANDERLUST_16X16.toFont())
                .build();
        final Screen screen = TerminalBuilder.createScreenFor(terminal);

        // We create a Panel which will hold our components
        // Note that you can add components to the screen without a panel as well
        Panel panel = PanelBuilder.newBuilder()
                .wrapWithBox() // panels can be wrapped in a box
                .title("Panel") // if a panel is wrapped in a box a title can be displayed
                .wrapWithShadow() // shadow can be added
                .size(Size.of(32, 16)) // the size must be smaller than the parent's size
                .position(Position.OFFSET_1x1) // position is always relative to the parent
                .build();

        final Header header = HeaderBuilder.newBuilder()
                // this will be 1x1 left and down from the top left
                // corner of the panel
                .position(Position.OFFSET_1x1)
                .text("Header")
                .build();

        final CheckBox checkBox = CheckBoxBuilder.newBuilder()
                .text("Check me!")
                .position(Position.of(0, 1)
                        // the position class has some convenience methods
                        // for you to specify your component's position as
                        // relative to another one
                        .relativeToBottomOf(header))
                .build();

        final Button left = ButtonBuilder.newBuilder()
                .position(Position.of(0, 1) // this means 1 row below the check box
                        .relativeToBottomOf(checkBox))
                .text("Left")
                .build();

        final Button right = ButtonBuilder.newBuilder()
                .position(Position.of(1, 0) // 1 column right relative to the left BUTTON
                        .relativeToRightOf(left))
                .text("Right")
                .build();

        panel.addComponent(header);
        panel.addComponent(checkBox);
        panel.addComponent(left);
        panel.addComponent(right);

        screen.addComponent(panel);

        // we can apply color themes to a screen
        screen.applyColorTheme(ColorThemeResource.TECH_LIGHT.getTheme());

        // this is how you can define interactions with a component
        left.onMouseReleased((mouseAction -> {
            screen.applyColorTheme(ColorThemeResource.ADRIFT_IN_DREAMS.getTheme());
        }));

        right.onMouseReleased((mouseAction -> {
            screen.applyColorTheme(ColorThemeResource.SOLARIZED_DARK_ORANGE.getTheme());
        }));

        // in order to see the changes you need to display your screen.
        screen.display();
    }
}

And the result will look like this:

You can check out more examples here. Here are some screenshots of them:

Tileset example:

Animations:

Components:

Additional features

There are a bunch of other stuff Zircon can do which are not detailed in this README but you can read about them in either the source code or the Wiki:

Layering

Both the Terminal and the Screen interfaces implement Layerable which means that you can add Layers on top of them. Every Layerable can have an arbitrary amount of Layers. Layers are like TextImages and you can also have transparency in them which can be used to create fancy effects. Look at the LayerBuilder to see how to use them. For more details check the layers Wiki page.

Note that when creating Layers you can set its offset from the builder but after attaching it to a Terminal or Screen you can change its position by calling moveTo with a new Position.

Input handling

Both the Terminal and the Screen interfaces implement InputEmitter which means that they re-emit all inputs from your users (key strokes and mouse actions) and you can listen on them. There is a Wiki page with more info.

Shape and box drawing

You can draw Shapes like rectangles and triangles by using one of the ShapeFactory implementations. Check the corresponding Wiki page for more info.

Fonts and tilesets

Zircon comes with a bunch of built-in fonts and tilesets. These come in 3 flavors:

  • Physical fonts (Want to use physical fonts? Check how to use them here)
  • CP437 tilesets (More on using them here)
  • and Graphic tilesets (Usage info here)

Read more about them in the resource handling Wiki page if you want to know more or if you want to use your own tilesets and fonts.

Zircon also comes with its own tileset format (ztf: Zircon Tileset Format) which is very easy to use. Its usage is detailed here.

REXPaint file loading

REXPaint files (.xp) can be loaded into Zircon Layers. Read about this feature here.

Color themes

Zircon comes with a bunch of built-in color themes which you can apply to your components. If interested you can read more about how this works here.

Animations (BETA)

Animations are a beta feature. More info here.

The API

If you just want to peruse the Zircon API just navigate here. Everything which is intented to be the public API is there.

Road map

If you want to see a new feature feel free to create a new Issue or discuss it with us on discord. Here are some features which are either under way or planned:

  • libGDX support
  • Layouts for Components with resizing support
  • Components for games like MapDisplay
  • Multi-Font support
  • Next to ColorThemes we'll introduce ComponentThemes as well (custom look and feel for your components)

License

Zircon is made available under the MIT License.

Credits

Zircon is created and maintained by Adam Arold, Milan Boleradszki and Gergely Lukacsy

We're open to suggestions, feel free to message us on Discord or open an issue. Pull requests are also welcome!

Zircon is powered by:

zircon's People

Contributors

adam-arold avatar coldwarrl avatar geldrin avatar milonoir avatar

Watchers

 avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.