GUI Windows

Windows GUI Library

The klyn.gui.windows package provides Klyn's native widget layer for desktop applications. It is built around typed widgets, layout managers, multicast events, and KSS themes so application code stays explicit and statically typed.

Imports and Packages

Only klyn is imported by default. GUI applications must import the widget package and, when needed, the layout, event, and binding packages explicitly.

import klyn.gui.windows
import klyn.gui.windows.layouts
import klyn.gui.event
import klyn.binding

The main classes are MainWindow, Container, Label, TextBox, Button, ComboBox, and the layout managers in klyn.gui.windows.layouts.

Window and Widget Tree

A MainWindow owns a centralWidget. Add widgets to containers and let a layout manager compute bounds. This keeps resize behavior in one place and avoids manual coordinate code in ordinary forms.

import klyn.gui.windows
import klyn.gui.windows.layouts

win = MainWindow("Hello")
win.size = (420, 240)

root = win.centralWidget
root.layout = VBoxLayout(spacing=12)
root.padding = [24, 24, 24, 24]

title = Label("Welcome to Klyn")
root.add(title)

field = TextBox()
field.placeholder = "Your name"
root.add(field)

button = Button("Continue")
root.add(button)

win.centerIn(null)
win.show()
win.run()

Layouts currently include VBoxLayout, HBoxLayout, GridLayout, FormLayout, FlowLayout, and DockLayout. For form-oriented screens, FormLayout is usually a better starting point than absolute positioning.

Events

GUI events are multicast. Use += to subscribe and -= to unsubscribe. A single event can have several handlers, so a widget can notify both application logic and instrumentation code without replacing the previous callback. See Signals vs Events for the precise split between observable state and rich UI actions.

import klyn.gui.windows
import klyn.gui.event

class Controller:

    public onSave(action as ActionEvent) as Void:
        print("save requested")

controller = Controller()
button = Button("Save")
button.clicked += controller::onSave
button.clicked += lambda(e: ActionEvent): print(e.source)

Method references use object::method. Lambdas can capture values from the surrounding scope and should keep an explicit event parameter type when the event payload matters.

Core widgets expose the common GUI event set through klyn.gui.event: clicked, pressed, released, keyPressed, keyReleased, mousePressed, mouseReleased, mouseMoved, resized, closed, and paintRequested. Use these for user actions and lifecycle notifications; keep ordinary mutable state as signal properties.

Signal Properties and Binding

Observable widget state is declared as a signal property. The notification object is intentionally not exposed as a separate member; use Binding.watch, Binding.oneWay, or Binding.twoWay with member references.

import klyn.binding
import klyn.gui.windows

slider = Slider(value=50, minimum=0, maximum=100)
spin = Spinner(value=50, minimum=0, maximum=100)

Binding.twoWay(slider::value, spin::value)
Binding.watch(slider::value, lambda(value: Object): print(value))

Use event clicked as ActionEvent for rich UI actions. Use signal property value as Int for state that should participate in data binding. The dedicated Signals vs Events page explains when to choose each tool.

Timers and Repaint

Use Timer for periodic GUI work such as blinking indicators, clocks, previews, or lightweight polling. Timer callbacks are dispatched by the native event loop, not by an arbitrary worker thread.

import klyn.gui.windows
import klyn.gui.event

canvas = MyCanvas()
timer = Timer(1000)
timer.timeout += lambda(e: ActionEvent): canvas.repaint()
timer.start()

Stop timers when they are no longer needed. samples/gui/ClockSample.kn uses this pattern to repaint an analog clock once per second.

Forms and Text Input

Text fields expose editing state through TextBox. Password fields use echoMode, and buttons can be marked as the default action for Enter-driven forms. The native backend also supports Tab and Shift+Tab focus traversal.

import klyn.gui.windows
import klyn.gui.windows.layouts
import klyn.gui.event

public class LoginWindow extends MainWindow:

    private login as TextBox
    private password as TextBox
    private status as Label

    public LoginWindow():
        super("Login")
        this.size = (420, 260)

        root = this.centralWidget
        root.layout = FormLayout(rowSpacing=12, columnSpacing=16)
        root.padding = [24, 24, 24, 24]

        this.login = TextBox()
        this.login.placeholder = "login"
        root.add(Label("Login"))
        root.add(this.login)

        this.password = TextBox()
        this.password.echoMode = TextBox.ECHO_PASSWORD
        this.password.placeholder = "password"
        root.add(Label("Password"))
        root.add(this.password)

        submit = Button("Connect")
        submit.isDefaultButton = true
        submit.clicked += this::connect
        root.add(Label(""))
        root.add(submit)

        this.status = Label("")
        root.add(Label(""))
        root.add(this.status)

    private connect(action as ActionEvent) as Void:
        if this.login.text.trim() == "":
            this.status.text = "Login is required"
            return
        this.status.text = "Connected"

win = LoginWindow()
win.centerIn(null)
win.show()
win.run()
KSS Themes

The default widget appearance is defined with KSS, a small CSS-like styling layer. Built-in themes live under KLYN_HOME/lib/klyn/gui/windows/themes as light.kss and dark.kss. The default mode is system, so Klyn chooses the light or dark theme from the operating-system appearance when it can.

import klyn.gui.windows
import klyn.gui.windows.themes

ThemeManager.setAppearanceMode(ThemeManager.MODE_DARK)

win = MainWindow("Themed")
win.appearanceMode = ThemeManager.MODE_SYSTEM

KSS currently covers the common surface properties used by the widget set: foreground color, background color, margins, padding, font family, font size, borders, corner radius, placeholder color, selection color, caret color, and slider track fill color. Slider thumbs use the resolved accent-color, while the active track segment can be overridden with track-fill-color. Prefer the built-in theme files for default widget styling; application-specific colors should live in application code or a dedicated app theme. See GUI Themes and KSS for mode control, custom stylesheets, and the supported KSS subset.

Capturing a Window

Window.capture() renders the window client area to a BMP file through Klyn's own painter pipeline. It is useful for documentation, visual regression checks, and tuning layouts without relying on an external screenshot tool.

win = MainWindow("Preview")
win.size = (640, 420)
win.capture("preview.bmp")

Captures do not include operating-system window decorations. They show the same widget tree that Klyn paints inside the client area.

Next Step

Open samples/gui/Calculator.kn for a larger GUI program using layouts, buttons, focus feedback, and event handlers. Continue with Signals vs Events for the event/binding model, GUI Themes and KSS for appearance control, FormLayout for label/field forms, Slider Widget for scale input, then Canvas and Custom Painting when you need a widget that draws its own pixels.