Recommended way to customize a widget

Composing a widget from elements

Widgets must implement conflicting requirements:

In the tile library, widgets are a composition of primitive elements to achieve the desired style.

For example, a simple button contains a text label element included within a padding element that is enclosed within a border element.

Sounds complicated, but the code chain looks simple:

    label := fieldview.New(...)
    margin := margin.New(label).Margin(...)
    button := box.New(margin, ...)
    return button

To be part of a composition, each chain element must implement a Viewer interface:

type Viewer interface {
	Size() image.Point
	Draw(w *impress.Window, from image.Point)
	Select(pt image.Point, from image.Point) (any, image.Rectangle)
}

Size returns an estimate of the element's size. Draw draws an element in the specified window, starting at the specified offset. Select returns the element's model and its visible rectangle, found at the mouse point, if the element was drawn with the specified offset.

module shadow

type Shadow struct {
    view.Viewer
    ... // any custom parameters
}

func New(viewer view.Viewer, ...) *Shadow {
    return &Shadow{
        Viewer: viewer,
        ...
    }
}

func (v *Shadow) Draw(w *impress.Window, from image.Point) {
    v.Viewer.Draw(w, from)
    ... // any extra drawing
}

And extend the code chain to create a new button:

    var button view.Viewer
    button = fieldview.New(...)
    button = margin.New(button).Margin(...)
    button = box.New(button, ...)
    button = shadow.New(button, ...)
    return button

The new element can be used to customize the style of any other widgets.

The widget composition code must be part of the application, not the widget library.

See a collection of widget element as a starting point.