Exit Full View

Glok

A GUI Toolkit written in Kotlin using OpenGL, inspired by JavaFX.

sceenshot

The name Glok is a combination of GL (from OpenGL), and the first two letters of Kotlin (backwards).

I often want to mix JavaFX and OpenGL, but the result is slow, because you have to render the OpenGL to a Texture (stored on the GPU), then copy it to the CPU's RAM as a JavaFX WritableImage. JavaFX will then copy it straight back into the GPU. This round trip is slow - especially with high DPI screens where the Textures are large.

I realise I'm reinventing the wheel. Does the world really need another GUI toolkit? None of the existing wheels fit my needs :-(

Building from Source

./gradlew # Build
./gradlew glok-demo:run # Run the demo applications 
./gradlew dokkaHtmlMultiModule # Build a local copy of the dokka API documentation

Adding Glok dependencies to your project

Glok's maven artifacts are hosted on gitlab.com. To add this repository to a gradle build.gradle.kts script :

repositories {
    maven {
        name = "glok"
        url = uri("https://gitlab.com/api/v4/projects/46354938/packages/maven")
    }
}

FYI, the large number is GitLab's project id for Glok.

Then add the dependencies :

dependencies {
    implementation("uk.co.nickthecoder:glok-model:0.4")
    implementation("uk.co.nickthecoder:glok-core:0.4")
    implementation("uk.co.nickthecoder:glok-dock:0.4")
}
  • glok-model contains ObservableValue, Property, ObservableList ObservableSet and other non-gui classes. This is small, and has no other dependencies. It is a separate artifact for those who wish to use it in a non-gui setting.
  • glok-core contains the bulk of Glok. It depends on LWJGL` for rendering with OpenGL.
  • glok-dock is optional, and can be excluded if you don't use Dock / Harbour.

Initial Goal

To provide a GUI Toolkit, similar to JavaFX, but rendered with OpenGL such that your application can also make direct use of OpenGL.

Those familiar with JavaFX should feel at home quickly.

All controls use JavaFX inspired Properties, as I've found this pattern to be very clean. This was one of the main reason for creating Glok, rather than using one of the many other OpenGL GUI toolkits.

Using Glok within the context of an OpenGL based game is secondary, and isn't support yet. Glok currently assumes it is in full control of the Window, and the events emanating from it. In a game context, your game will own the Window, and would need to pass events to Glok.

Secondary Goal

Make writing GUIs pleasant and easy, and for the code to be highly readable.

A typical JavaFX application takes one of three routes :

  1. Hand-code each control, and their layout in Java. This gets messy really quickly, and the code is far from readable.
  2. Design the layout in a GUI, saved as FXML, and then write glue to stitch the pieces together. I personally don't like this approach, for reasons too numerous to list here. For plain form filling dialogs, this might be acceptable, but for the kind of applications I write, it isn't a good fit.
  3. Write it in Kotlin, using a DSL (Domain Specific Language), such as KotlinFX and Ktfx. Yes, this is the way to go IMHO.

So Glok includes a DSL.

  • The structure of the code matches the structure of the scene-graph.
  • It is very readable.
  • No glue is needed.
  • No need to mess around with XML (yuck!)

Here's an example :

scene {
    root = borderPane {
       top = toolBar {
           + button( "Hello" ) { onAction{ println( "Hi" ) } }
           + toggleButton( "Foo" ) { ... }
       }
       center = vBox {
           + label( "Above the main content" )
           + mainContent()
       }
       bottom = statusBar() { ... }
    }
}

Every Node class has a function, which starts with a lower case letter. These are all very simple, they create the Node, apply a block of to the Node.

For more examples, look at the demos - there are quite a few (35 at the last count).

Dependencies

  1. Kotlin runtime
  2. LWJGL for OpenGL access
  3. JOML for matrix multiplication
  4. Java's runtime including AWT for the clipboard and fonts (AWT fonts are converted to OpenGL textures)

Status

Summary (TLDR;)

Glok is fairly feature rich, and IMHO, nicer than JavaFX in many places, but lacking in other places.

I've ported several of my projects from JavaFX to Glok I'm very happy with them, and prefer Glok to JavaFX :-)

Glok looks better, and is easier to code.

There are many weird behaviours in JavaFX, which Glok has avoided. e.g. Node.scene isn't set in a timely manner in JavaFX.

There are still quite a few loose ends, but nothing holding me back from writing a complete, feature rich application.

Browse a snapshot of the API.

Controls

The following controls are functionally equivalent (or very close) to their JavaFX counterparts :

Text, Label, TextField, TextArea, Button, ToggleButton, RadioButton, CheckBox, ChoiceBox, Separator, Ruler (broken in JavaFX 8), Slider, Spinners (IntSpinner, FloatSpinner, DoubleSpinner), ListView, TreeView, FlowPane.

Layout Controls

ButtonBar, HBox, VBox, BorderPane, TabPane, TitledPane, ToolBar, ScrollBar, ScrollPane

Glok has no Accordian, but if you place a TitledPanes in a ToggleGroup you get exactly the same behaviour.

Menus

Menu, MenuBar, PopupMenu, MenuItem, CheckMenuItem, RadioMenuItem, ChoiceMenuItem, SubMenu.

Dialogs

  • FileDialog : for save/load and choosing a directory. BEWARE. I think this has a critical bug (in the library that Glok uses), which causes hanging. I haven't investigated yet.
  • AlertDialog : for simple messages, with a customisable choice of buttons.
  • ColorPicker : There are two implementations PaletteColorPicker and CustomColorPicker. The latter is similar to Photoshop's color picker. Uses HSV or RBG color models.

Addition Glok controls, which have no JavaFX equivalents

  • Box : Like HBox / VBox, but with an orientation property.
  • FormGrid : A grid specifically designed for simple forms. The labels and fields line up. Above and below each label/field is a place for a full-width Node to display information and/or error messages.
  • ThreeRow : Contains three Nodes in a row, where the middle Node is guaranteed to be centered. The other two are at the far left / right.
  • SingleContainer : A BorderPane without the edges ;-) A container for a single Node, which is a lot more useful than it sounds.
  • Rotation : Rotates the child node in multiples of 90°. There are some issues with this still. e.g. PopupMenus use the un-rotated bounds when positioning next to a rotated Node. Much less flexible than JavaFX's transformations, but easier to use.
  • MixedTreeView : Very similar to TreeView, but designed for trees where each item can hold a different type.

Docks / Harbour

Glok has an additional subproject called glok-dock, which adds support for dockable panels. The look and feel is shamelessly copied from IntelliJ. Each side of the Harbour can show two sets of buttons. In each set, a single Dock can be opened. If another dock in the same set was open, then it is hidden. i.e. each side of the Harbour can have zero, one or two Docks open. The state of the Harbour can be saved/restored to Java Preferences (AKA the registry on Windows).

An example Dock is included : NodeInspectorDock. This is incredibly useful to track down GUI bugs. I wish I had it earlier in Glok's development.

You may also use NodeInspector without placing it in a Dock, but it lacks features.

Missing Features

  • Controls : GridPane, TableView, WebView...
  • Word-wrap in TextArea.
  • Multi-line text in Labelled
  • Underlined text
  • Alt shortcuts for menus/menu items. e.g. _File would make Alt+F a shortcut for the File menu.
  • Font rendering is poor quality (it's fine on high-DPI devices though).
  • Support for drag & drop of files.
  • I18N (Glok has very little text, but it is hard-coded as English at the moment) I have no plans for right-to-left text, nor other tricky parts of "plain text", such as combining-characters.
  • Animations

Known Issues

  1. There's one critical bug related to FileDialog. I suspect it is a bug in the library I'm using. (just from the API I can tell the author isn't a great programmer).

  2. The order in which properties are updated. For example, SingleSelection has two properties, selectedItem and selectedIndex. From the outside, these should be updated atomically, but currently they aren't. First, one property is changed, and issues change events, then the other property is changed and issues change event. So if you listen to one property, and check the value of the other, the result may be wrong (depending on whether you are listening to the first, or second property).

  3. Other timing issues. For example, when a PopupMenu closes and another opens is surprisingly non-trivial. Will PopupMenus continue to work if I refactor some code in Stage? I hope so, but I'm not 100% sure, there may be some timing dependency that it relies on, that I'm not aware of. FYI, I often had problems with JavaFX, related to timing issues. For example, a Node's scene property is not update in a timely manner. AFAIK, the API says nothing about this delay, so I consider this a bug in JavaFX.

  4. Property / ObservableValue are a little ugly due to limitations with the JVM's type system. I've auto-generated a lot of boilerplate, which gets round some issues, but not all. See uk.co.nickthecoder.glok.documentation.Boilerplate.

Test Coverage

Test coverage is virtually non-existent.

However, Glok has been designed so that it's possible to write unit tests for everything without any weird hacks. You don't even need to use OpenGL for the vast majority.

Use the built-in DummyBackend, and LoggingBackend, with an InMemoryLog, and you can test how scenes are drawn (without actually drawing them).

Simulate raw mouse and keyboard events from the DummyBackend, and you can test interactivity, even in a headless environment.

The unit tests for GLBackend will need to use OpenGL. This code base is small though. Each test could compare the display buffer with an expected result.

Performance

There is quite a bit of optimisation that could be done, but I'm happy with the performance as it stands. Applications run smoothly on my crusty old laptop (A Thinkpad T400 circa 2008).

The Future

There's still plenty to do. See above and todo.txt in the source's root directory.

While writing Glok, I've kept in mind that I'd like to use Glok from within a browser window too. All drawing goes through a single Backend interface. So it should be relatively easy to convert Glok into a Kotlin multi-platform project, with just the Backend needing an additional js actual implementation in addition to the current jvm implementation.

However, sending resources, such as images and fonts from the server to the client will be trickier.