rosaline

package module
v0.0.0-...-ff73208 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 2, 2026 License: LGPL-3.0 Imports: 15 Imported by: 0

README

Rosaline

Rosaline is a small, beginner-friendly graphics and GUI library for Go. It is designed for people who know a little Go and want to make a real graphical program without first learning a large framework.

Rosaline is currently at v0.4.1. The public API is small on purpose and grows through well-documented, tested features.

Goals

  • Beginner-friendly Go API
  • Builds with CGO_ENABLED=0
  • Linux is a first-class platform
  • The same application code runs on Linux, Windows, and macOS
  • Serious 2D drawing alongside normal GUI widgets
  • Small, memorable public API
  • Complete examples and feature-by-feature documentation

Install

Rosaline uses GitHub's normal Go module support:

go get github.com/SeraphinaDX/Rosaline

Rosaline requires Go 1.25 or newer. No C compiler or separately installed GUI toolkit is required. On Linux, a graphical desktop with X11 or XWayland is currently required; native Wayland support is on the roadmap.

Hello, Rosaline

package main

import "github.com/SeraphinaDX/Rosaline"

func main() {
	rosaline.Run(
		rosaline.Column(
			rosaline.Label("Hello, world!"),
			rosaline.Button("Click me", func() {
				rosaline.Message("Rosaline", "It works!")
			}).Primary(),
		),
	)
}

Save that as main.go, then run:

CGO_ENABLED=0 go run .

See docs/QUICK_START.md for a guided first application.

A small form

Form controls update normal Go variables through pointers:

var name string
var subscribed bool

rosaline.Run(
	rosaline.Column(
		rosaline.Label("Your name"),
		rosaline.TextBox(&name).Placeholder("Type your name").Focus(),
		rosaline.CheckBox("Send me updates", &subscribed),
		rosaline.Button("Continue", func() {
			rosaline.Message("Hello", "Welcome, "+name+"!")
		}).Primary(),
	),
)

See docs/TEXT_INPUT.md, docs/CHECKBOX.md, and docs/FORMS.md.

An interactive canvas

Canvas callbacks use the same coordinates as drawing commands:

var x, y float64

canvas := rosaline.Canvas(func(c *rosaline.DrawingCanvas) {
	c.Clear(rosaline.White)
	c.FillCircle(x, y, 12, rosaline.Rose)
})

canvas.OnMouseDown(func(event rosaline.MouseEvent) {
	if event.Button == rosaline.MouseLeft {
		x, y = event.X, event.Y
	}
})

Rosaline redraws automatically after mouse callbacks. See docs/CANVAS_INPUT.md for clicking, dragging, modifier keys, manual redraws, and a complete paint program.

A real image-viewer application

Rosaline v0.4 combines menus, dialogs, images, and scrolling:

viewer := rosaline.Image(nil)

openImage := func() {
	path, ok := rosaline.OpenFileDialog(rosaline.FileDialogOptions{
		Title: "Open Image",
	})
	if !ok {
		return
	}
	picture, err := rosaline.LoadImage(path)
	if err != nil {
		rosaline.Error("Could not open image", err.Error())
		return
	}
	viewer.SetImage(picture)
}

See docs/IMAGE_VIEWER.md for the complete application.

Timers and animation

Timers belong to the application and automatically stop with its event loop:

seconds := 0

clock := rosaline.Every(time.Second, func() {
	seconds++
})

rosaline.RunApp(rosaline.App{
	Timers: []*rosaline.Timer{clock},
	Content: rosaline.LabelFunc(func() string {
		return fmt.Sprintf("Running for %d seconds", seconds)
	}),
})

Use After for one delayed callback and Animate for a frame-rate-based canvas loop. See docs/TIMERS.md and docs/ANIMATION.md.

Included in v0.4.1

  • Application windows
  • Labels and dynamic labels
  • Buttons and message dialogs
  • Rows, columns, spacing, padding, and expansion
  • Simple state values
  • Single-line and multiline text input
  • Password display, placeholders, change events, and Enter submission
  • Checkboxes bound to Go Boolean variables
  • Tab and Shift+Tab keyboard navigation
  • A first-class canvas with lines, rectangles, circles, and text
  • Canvas clicks, pointer movement, dragging, and button-release events
  • Automatic and manually requested canvas redraws
  • Pure-Go loading and display of common image formats
  • Horizontal and vertical scroll areas
  • Native open, save, message, error, and confirmation dialogs
  • Menu bars with working keyboard shortcuts
  • Repeating and one-shot application timers
  • Start, stop, restart, and running-state timer controls
  • Frame-rate-based canvas animation
  • Semantic colors and themes
  • Runnable hello, counter, canvas, forms, paint, image-viewer, and animation examples
  • Unit tests for non-visual core behavior

Run the examples

From the extracted project root:

CGO_ENABLED=0 go run ./examples/hello
CGO_ENABLED=0 go run ./examples/counter
CGO_ENABLED=0 go run ./examples/canvas
CGO_ENABLED=0 go run ./examples/forms
CGO_ENABLED=0 go run ./examples/paint
CGO_ENABLED=0 go run ./examples/imageviewer
CGO_ENABLED=0 go run ./examples/animation

Project status

The API is experimental until v1.0. The next milestones add paths, Bézier curves, transforms, clipping, image export, radio buttons, and general keyboard events.

Rosaline's backend is intentionally private. Application code only imports the rosaline package, so the backend can improve without forcing beginners to rewrite their programs.

License

Rosaline is free software licensed under the GNU Lesser General Public License v3.0 or later.

Applications may use and link to Rosaline without being required to adopt the LGPL. Modifications to Rosaline itself must remain available under the LGPL, and distribution must follow the license's relinking and source-availability requirements. The incorporated GNU GPL v3 text is included in LICENSE.GPL.

Copyright (C) 2026 Britney Lozza and Rosaline contributors.

Documentation

Overview

Package rosaline makes small graphical Go applications easy to build.

The package deliberately keeps window setup, the event loop, layout, and the platform backend out of beginner programs. A complete application can be as small as:

rosaline.Run(rosaline.Label("Hello, world!"))

Use RunApp when you want to set the title, initial window size, or theme. TextBox, TextArea, and CheckBox bind directly to ordinary Go variables. Canvas mouse callbacks make drawing programs interactive without exposing platform event types. Images, scroll areas, menus, and file dialogs provide the groundwork for complete desktop applications while ordinary file I/O remains normal Go. App-owned timers support delayed work, repeating updates, and canvas animation without exposing the private event loop.

Index

Constants

This section is empty.

Variables

View Source
var (
	Black       = RGB(0, 0, 0)
	White       = RGB(255, 255, 255)
	Rose        = Hex("#d64f8c")
	SoftRose    = Hex("#f4a6c8")
	Transparent = RGBA(0, 0, 0, 0)
)
View Source
var DefaultTheme = Theme{
	Background: Hex("#fff8fc"),
	Surface:    Hex("#ffffff"),
	Primary:    Hex("#c43f7a"),
	Text:       Hex("#2a1722"),
	Muted:      Hex("#7d6874"),
	Border:     Hex("#d9b8ca"),
	Danger:     Hex("#b4234d"),
	Success:    Hex("#267a50"),
}

DefaultTheme is Rosaline's light rose theme.

Functions

func Confirm

func Confirm(title, text string) bool

Confirm asks a yes-or-no question and reports whether the user chose Yes.

func Error

func Error(title, text string)

Error displays an error dialog.

func Message

func Message(title, text string)

Message displays a simple informational dialog.

func OpenFileDialog

func OpenFileDialog(options FileDialogOptions) (path string, ok bool)

OpenFileDialog asks the user to choose one existing file. ok is false when the user cancels the dialog.

func Quit

func Quit()

Quit closes the Rosaline application.

func Run

func Run(content Widget)

Run opens a window containing content using beginner-friendly defaults.

func RunApp

func RunApp(app App)

RunApp opens an application window and runs its event loop.

func SaveFileDialog

func SaveFileDialog(options FileDialogOptions) (path string, ok bool)

SaveFileDialog asks the user where to save a file. ok is false when the user cancels. Existing files require confirmation before they are returned.

Types

type App

type App struct {
	Title   string
	Width   int
	Height  int
	Padding int
	Theme   Theme
	Menu    *AppMenuBar
	Timers  []*Timer
	Content Widget
}

App describes a Rosaline application window.

type AppMenu

type AppMenu struct {
	// contains filtered or unexported fields
}

AppMenu is one named drop-down menu in a menu bar.

func Menu(text string, entries ...MenuEntry) *AppMenu

Menu creates one named drop-down menu.

type AppMenuBar

type AppMenuBar struct {
	// contains filtered or unexported fields
}

AppMenuBar is a window's top-level menu bar.

func MenuBar(menus ...*AppMenu) *AppMenuBar

MenuBar creates a top-level menu bar.

type Box

type Box struct {
	// contains filtered or unexported fields
}

Box arranges child widgets in a row or column.

func Column

func Column(children ...Widget) *Box

Column arranges widgets from top to bottom.

func Row

func Row(children ...Widget) *Box

Row arranges widgets from left to right.

func (*Box) Expand

func (b *Box) Expand() *Box

Expand asks the layout to use available window space.

func (*Box) Gap

func (b *Box) Gap(pixels int) *Box

Gap sets the space between children in pixels.

func (*Box) Padding

func (b *Box) Padding(pixels int) *Box

Padding sets the space inside the layout in pixels.

type ButtonWidget

type ButtonWidget struct {
	// contains filtered or unexported fields
}

ButtonWidget is a clickable button.

func Button

func Button(text string, onClick func()) *ButtonWidget

Button creates a button. onClick runs when the user activates it.

func (*ButtonWidget) Primary

func (b *ButtonWidget) Primary() *ButtonWidget

Primary gives a button the theme's primary color.

type CanvasWidget

type CanvasWidget struct {
	// contains filtered or unexported fields
}

CanvasWidget is a custom 2D drawing surface.

func Canvas

func Canvas(draw func(*DrawingCanvas)) *CanvasWidget

Canvas creates a 2D drawing surface.

func (*CanvasWidget) Background

func (c *CanvasWidget) Background(color Color) *CanvasWidget

Background sets the canvas background.

func (*CanvasWidget) Expand

func (c *CanvasWidget) Expand() *CanvasWidget

Expand asks the canvas to use available layout space.

func (*CanvasWidget) OnMouseDown

func (c *CanvasWidget) OnMouseDown(handler func(MouseEvent)) *CanvasWidget

OnMouseDown runs when a mouse button is pressed over the canvas.

func (*CanvasWidget) OnMouseMove

func (c *CanvasWidget) OnMouseMove(handler func(MouseEvent)) *CanvasWidget

OnMouseMove runs when the pointer moves over the canvas. Event Button is MouseNone for normal movement and identifies the held button while dragging.

func (*CanvasWidget) OnMouseUp

func (c *CanvasWidget) OnMouseUp(handler func(MouseEvent)) *CanvasWidget

OnMouseUp runs when a mouse button is released over the canvas.

func (*CanvasWidget) Redraw

func (c *CanvasWidget) Redraw()

Redraw clears the canvas and runs its drawing function again. Call Redraw from Rosaline callbacks after changing drawing state. Mouse callbacks redraw automatically, so they normally do not need to call it themselves.

func (*CanvasWidget) Size

func (c *CanvasWidget) Size(width, height int) *CanvasWidget

Size sets the canvas's initial size in pixels.

type CheckBoxWidget

type CheckBoxWidget struct {
	// contains filtered or unexported fields
}

CheckBoxWidget is a labeled checkbox bound to a Go bool.

func CheckBox

func CheckBox(text string, value *bool) *CheckBoxWidget

CheckBox creates a checkbox. It updates value when the user toggles it. Pass a pointer with &, as in CheckBox("Updates", &updates).

func (*CheckBoxWidget) Focus

func (c *CheckBoxWidget) Focus() *CheckBoxWidget

Focus asks Rosaline to give this checkbox focus when the window opens. If several widgets request focus, the first one wins.

func (*CheckBoxWidget) OnChange

func (c *CheckBoxWidget) OnChange(handler func(bool)) *CheckBoxWidget

OnChange runs after the user toggles the checkbox.

type Color

type Color struct {
	R, G, B, A uint8
}

Color stores a red, green, blue, and alpha component.

func Hex

func Hex(value string) Color

Hex parses #RGB, #RRGGBB, or #RRGGBBAA. Invalid values return black. Use ParseHex when an invalid value should be reported as an error.

func ParseHex

func ParseHex(value string) (Color, error)

ParseHex parses #RGB, #RRGGBB, or #RRGGBBAA.

func RGB

func RGB(r, g, b uint8) Color

RGB creates an opaque color.

func RGBA

func RGBA(r, g, b, a uint8) Color

RGBA creates a color with an alpha component.

func (Color) String

func (c Color) String() string

type DrawingCanvas

type DrawingCanvas struct {
	// contains filtered or unexported fields
}

DrawingCanvas provides Rosaline's beginner-friendly 2D drawing operations.

func (*DrawingCanvas) Circle

func (c *DrawingCanvas) Circle(x, y, radius, stroke float64, color Color)

Circle draws the outline of a circle.

func (*DrawingCanvas) Clear

func (c *DrawingCanvas) Clear(color Color)

Clear removes existing shapes and changes the canvas background.

func (*DrawingCanvas) FillCircle

func (c *DrawingCanvas) FillCircle(x, y, radius float64, color Color)

FillCircle draws a filled circle.

func (*DrawingCanvas) FillRect

func (c *DrawingCanvas) FillRect(x, y, width, height float64, color Color)

FillRect draws a filled rectangle.

func (*DrawingCanvas) Line

func (c *DrawingCanvas) Line(x1, y1, x2, y2, stroke float64, color Color)

Line draws a line.

func (*DrawingCanvas) Rect

func (c *DrawingCanvas) Rect(x, y, width, height, stroke float64, color Color)

Rect draws the outline of a rectangle.

func (*DrawingCanvas) Text

func (c *DrawingCanvas) Text(text string, x, y float64, style TextStyle)

Text draws text from its top-left corner.

type FileDialogOptions

type FileDialogOptions struct {
	Title            string
	InitialDirectory string
	InitialFile      string
	DefaultExtension string
	Filters          []FileFilter
}

FileDialogOptions customizes an open or save dialog. Every field is optional; Rosaline supplies beginner-friendly defaults.

type FileFilter

type FileFilter struct {
	Name       string
	Extensions []string
}

FileFilter describes one group of files in an open or save dialog.

type ImageWidget

type ImageWidget struct {
	// contains filtered or unexported fields
}

ImageWidget displays a Picture.

func Image

func Image(picture *Picture) *ImageWidget

Image creates a widget that displays picture. A nil picture is allowed and shows a friendly placeholder until SetImage is called.

func (*ImageWidget) Expand

func (i *ImageWidget) Expand() *ImageWidget

Expand asks the image widget to use available layout space.

func (*ImageWidget) Picture

func (i *ImageWidget) Picture() *Picture

Picture returns the picture currently displayed by the widget.

func (*ImageWidget) Placeholder

func (i *ImageWidget) Placeholder(text string) *ImageWidget

Placeholder changes the text shown when no picture is loaded.

func (*ImageWidget) SetImage

func (i *ImageWidget) SetImage(picture *Picture)

SetImage changes the displayed picture. It can be called from Rosaline callbacks after the widget has been mounted.

type LabelWidget

type LabelWidget struct {
	// contains filtered or unexported fields
}

LabelWidget displays text.

func Label

func Label(text string) *LabelWidget

Label creates a label with fixed text.

func LabelFunc

func LabelFunc(text func() string) *LabelWidget

LabelFunc creates a label whose text is recalculated after Rosaline events. It is useful for counters and other small pieces of changing text.

func (*LabelWidget) Color

func (l *LabelWidget) Color(color Color) *LabelWidget

Color sets this label's text color.

type MenuAction struct {
	// contains filtered or unexported fields
}

MenuAction is a clickable command inside a menu.

func MenuItem(text string, onClick func()) *MenuAction

MenuItem creates a clickable menu command.

func (m *MenuAction) Shortcut(shortcut string) *MenuAction

Shortcut displays and binds a keyboard shortcut such as "Ctrl+O" or "Ctrl+Shift+S".

type MenuEntry interface {
	// contains filtered or unexported methods
}

MenuEntry is an item or separator accepted by Menu.

func MenuSeparator() MenuEntry

MenuSeparator inserts a dividing line between menu commands.

type MouseButton

type MouseButton uint8

MouseButton identifies a mouse button without exposing platform details.

const (
	// MouseNone means that no mouse button is pressed.
	MouseNone MouseButton = iota
	// MouseLeft is the primary mouse button.
	MouseLeft
	// MouseMiddle is the middle mouse button.
	MouseMiddle
	// MouseRight is the secondary mouse button.
	MouseRight
)

type MouseEvent

type MouseEvent struct {
	X        float64
	Y        float64
	Button   MouseButton
	Dragging bool
	Shift    bool
	Control  bool
	Alt      bool
}

MouseEvent describes mouse input on a Canvas. X and Y are measured from the canvas's top-left corner.

type Picture

type Picture struct {
	// contains filtered or unexported fields
}

Picture contains a decoded image that Rosaline can display.

func LoadImage

func LoadImage(path string) (*Picture, error)

LoadImage reads and decodes an image file. PNG, JPEG, GIF, BMP, TIFF, and WebP are supported.

func NewPicture

func NewPicture(pixels image.Image) *Picture

NewPicture creates a Rosaline picture from Go's standard image.Image type.

func (*Picture) Format

func (p *Picture) Format() string

Format returns the decoded format name, such as "png" or "jpeg".

func (*Picture) Height

func (p *Picture) Height() int

Height returns the picture height in pixels.

func (*Picture) Image

func (p *Picture) Image() image.Image

Image returns the underlying standard-library image.Image value.

func (*Picture) Path

func (p *Picture) Path() string

Path returns the filename used by LoadImage. Pictures made with NewPicture have an empty path.

func (*Picture) Width

func (p *Picture) Width() int

Width returns the picture width in pixels.

type ScrollWidget

type ScrollWidget struct {
	// contains filtered or unexported fields
}

ScrollWidget displays content inside a viewport with horizontal and vertical scrollbars.

func Scroll

func Scroll(content Widget) *ScrollWidget

Scroll creates a scrollable viewport around content.

func (*ScrollWidget) Expand

func (s *ScrollWidget) Expand() *ScrollWidget

Expand asks the scroll area to use available layout space.

func (*ScrollWidget) Size

func (s *ScrollWidget) Size(width, height int) *ScrollWidget

Size sets the viewport's preferred size in pixels.

type State

type State[T any] struct {
	// contains filtered or unexported fields
}

State stores a value that can be safely read and changed. LabelFunc and button callbacks are enough for basic reactive interfaces.

func NewState

func NewState[T any](initial T) *State[T]

NewState creates state with an initial value.

func (*State[T]) Get

func (s *State[T]) Get() T

Get returns the current value.

func (*State[T]) Set

func (s *State[T]) Set(value T)

Set replaces the current value.

func (*State[T]) Update

func (s *State[T]) Update(change func(T) T)

Update calculates and stores a new value from the current value.

type TextAreaWidget

type TextAreaWidget struct {
	// contains filtered or unexported fields
}

TextAreaWidget is a multiline text input bound to a Go string.

func TextArea

func TextArea(value *string) *TextAreaWidget

TextArea creates a multiline input. The area updates value as the user types. Pass a pointer with &, as in TextArea(&notes).

func (*TextAreaWidget) Focus

func (t *TextAreaWidget) Focus() *TextAreaWidget

Focus asks Rosaline to give this text area focus when the window opens. If several widgets request focus, the first one wins.

func (*TextAreaWidget) OnChange

func (t *TextAreaWidget) OnChange(handler func(string)) *TextAreaWidget

OnChange runs after the user changes the value.

func (*TextAreaWidget) Size

func (t *TextAreaWidget) Size(columns, lines int) *TextAreaWidget

Size sets the preferred width in text columns and height in text lines.

type TextBoxWidget

type TextBoxWidget struct {
	// contains filtered or unexported fields
}

TextBoxWidget is a single-line text input bound to a Go string.

func TextBox

func TextBox(value *string) *TextBoxWidget

TextBox creates a single-line input. The box updates value as the user types. Pass a pointer with &, as in TextBox(&name).

func (*TextBoxWidget) Focus

func (t *TextBoxWidget) Focus() *TextBoxWidget

Focus asks Rosaline to give this text box focus when the window opens. If several widgets request focus, the first one wins.

func (*TextBoxWidget) OnChange

func (t *TextBoxWidget) OnChange(handler func(string)) *TextBoxWidget

OnChange runs after the user changes the value.

func (*TextBoxWidget) OnSubmit

func (t *TextBoxWidget) OnSubmit(handler func(string)) *TextBoxWidget

OnSubmit runs when the user presses Enter while the text box has focus.

func (*TextBoxWidget) Password

func (t *TextBoxWidget) Password() *TextBoxWidget

Password hides typed characters. The bound Go string still contains the real value so the application can validate or submit it.

func (*TextBoxWidget) Placeholder

func (t *TextBoxWidget) Placeholder(text string) *TextBoxWidget

Placeholder shows a hint while the text box is empty.

func (*TextBoxWidget) Width

func (t *TextBoxWidget) Width(columns int) *TextBoxWidget

Width sets the preferred width in text columns.

type TextStyle

type TextStyle struct {
	Color Color
	Size  int
}

TextStyle controls text drawn on a Canvas.

type Theme

type Theme struct {
	Background Color
	Surface    Color
	Primary    Color
	Text       Color
	Muted      Color
	Border     Color
	Danger     Color
	Success    Color
}

Theme contains semantic colors used by Rosaline widgets.

type Timer

type Timer struct {
	// contains filtered or unexported fields
}

Timer runs a callback later or at a regular interval while its App is open. Create timers with Every, After, or Animate, then include them in App.Timers.

func After

func After(delay time.Duration, callback func()) *Timer

After creates a running one-shot timer. It calls callback once after delay, then stops. It begins when its App starts.

func Animate

func Animate(framesPerSecond int, frame func()) *Timer

Animate creates a repeating timer measured in frames per second. Use it to update drawing state, then call CanvasWidget.Redraw from the frame callback. Invalid frame rates use 60 FPS; rates above 1000 FPS are limited to 1000.

func Every

func Every(interval time.Duration, callback func()) *Timer

Every creates a running timer that calls callback repeatedly. It begins when its App starts. Durations shorter than one millisecond use one millisecond.

func (*Timer) Restart

func (t *Timer) Restart()

Restart resets the wait and starts the timer again from the beginning.

func (*Timer) Running

func (t *Timer) Running() bool

Running reports whether the timer is started. Before RunApp, true means the timer is ready to begin as soon as its App opens.

func (*Timer) Start

func (t *Timer) Start()

Start starts a stopped timer. Calling Start on a running timer has no effect. Call timer methods from Rosaline callbacks, not background goroutines.

func (*Timer) Stop

func (t *Timer) Stop()

Stop pauses a timer. A stopped repeating timer can be continued with Start.

type Widget

type Widget interface {
	// contains filtered or unexported methods
}

Widget is anything Rosaline can place in a window or layout. Applications normally use constructor functions such as Label, Button, Column, Row, and Canvas rather than implementing Widget themselves.

func Spacer

func Spacer(width, height int) Widget

Spacer inserts a fixed amount of empty space.

Directories

Path Synopsis
examples
animation command
canvas command
counter command
forms command
hello command
imageviewer command
paint command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL