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 and event packages explicitly.

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

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.

import klyn.gui.windows
import klyn.gui.windows.events

class Controller:

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

controller = Controller()
button = Button("Save")
button.clicked += controller::onSave
button.clicked += lambda(event: ActionEvent): print(event.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.

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.windows.events

canvas = MyCanvas()
timer = Timer(1000)
timer.timeout += lambda(event: 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.windows.events

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(event 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 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.