gui.paint
A pure Salam 2D painter for CSS boxes: rounded rectangles, borders, gradients, shadows, images, paths, clipping and layers, with the same pixels on every system.
import gui.paint
This package is the drawing layer of the native user interface: it paints everything a CSS box can look like into a pixel buffer, in pure Salam, with the same pixels on every operating system. A Canvas holds premultiplied 32-bit pixels (0xAARRGGBB, so B, G, R, A bytes in memory), which X11, Win32, Cocoa and Wayland windows can show without a copy. Colours in the API are ordinary straight RGBA, as in CSS.
A box is painted in the CSS order: DrawShadow, then the background with FillRoundedRect, FillGradient or DrawImage, then DrawBorder, the content, and DrawOutline. Rounded corners take a horizontal and a vertical radius per corner and are scaled down the way CSS does when they do not fit. Edges are anti-aliased with exact coverage computed line by line in fixed point, borders have a width, colour and style (solid, dashed, dotted) per side, and shadows are Gaussian blurs computed analytically, outside or inside the box.
Clips (PushClip, PushRoundedClip), transforms and offscreen layers with group opacity (BeginLayer, EndLayer) are stacks. SetRegion limits drawing to a damage region of at most three rectangles, and drawing a scene in parts gives exactly the same pixels as drawing it at once. FillPath and StrokePath draw vector paths with lines, curves, arcs, caps, joins and dashes, and DrawMask draws text glyphs from a coverage mask.
Things to know
- Coordinates are logical pixels as
f64. Fractional edges are anti-aliased; images, clips and layers snap to whole pixels. - Rasterization uses integers and fixed point only, so a picture is meant to have the same hash on every system and backend. Tests compare
Hash()and a few pixels. - Every drawing call follows the whole transform, rotation and skew included. Borders, gradients, shadows and tiled images under a rotation or skew are drawn upright in a scratch layer and then resampled, and a clip under a rotation becomes a coverage mask.
- Dashed and dotted sides are patterned along their rounded corners too, with the pattern spaced so that each corner gets a whole dash or dot.
- Filters work on layers:
BeginFilterLayerandEndLayerFilteredgive CSSfilter, andBackdropFiltergivesbackdrop-filter, compared with Chromium on opaque, translucent and nested backdrops. Colour filters work on straight colours in sRGB, as browsers do, and blurs use three box blurs, as the filter specification describes. DrawNineSlicedraws an image cut into nine parts around a rectangle, the way CSSborder-imagedoes, with stretched, repeated, rounded or spaced edges.- Free every canvas, path and gradient you make. A canvas from
WrapCanvasorSubstill needsFreefor its scratch memory, but leaves the pixels alone. - The benchmark in
tools/bench/paint_frame.salamdraws 200 rounded boxes with a shadow, a background and a border over a full screen gradient at 1920x1080.
Painting a CSS box
A box is painted in the order CSS uses: the shadow first, then the background, then the border, and the outline last. All of them take the same rectangle and radii, so the shadow, the gradient and the border line up exactly. The outer shadow is cut out under the box, so a translucent background does not show it.
import gui.paint
func main:
mut cv := paint.NewCanvas(160, 100)
cv.Clear(paint.Rgb(240, 242, 247))
box := paint.RectOf(20.0, 20.0, 120.0, 60.0)
radii := paint.Corners(16.0, 16.0, 4.0, 4.0)
cv.DrawShadow(box, radii, paint.Shadow { offset_y = 4.0, blur = 12.0, color = paint.Rgba(20, 30, 60, 80) })
mut bg := paint.LinearGradient(180.0)
bg.AddStop(0.0, paint.Rgb(255, 255, 255))
bg.AddStop(1.0, paint.Rgb(226, 234, 252))
cv.FillGradient(box, radii, bg)
bg.Free()
cv.DrawBorder(box, radii, paint.SolidBorder(1.5, paint.Rgb(150, 170, 220)))
cv.DrawOutline(box, radii, 2.0, 2.0, paint.Rgba(60, 110, 230, 160))
top := cv.Pixel(80, 24)
bottom := cv.Pixel(80, 75)
println "top of the card:", top.r, top.g, top.b
println "bottom of the card:", bottom.r, bottom.g, bottom.b
println "hash:", cv.Hash()
cv.Free()
endRepainting only what changed
When something moves, only its old and new places need painting. Put both rectangles in a Region, set it with SetRegion and draw the whole scene as usual: everything outside the region is left alone. Coverage is computed for the whole shape and only then clipped, so the result is the same, pixel for pixel, as painting everything again.
import gui.paint
func draw(cv &: paint.Canvas, x: f64):
cv.Clear(paint.Rgb(255, 255, 255))
cv.FillRoundedRect(paint.RectOf(x, 10.0, 30.0, 30.0), paint.Uniform(8.0), paint.Rgb(230, 80, 40))
end
func main:
mut screen := paint.NewCanvas(100, 50)
draw(screen, 10.0)
mut damage := paint.Region {}
damage.Add(paint.IntRectOf(10, 10, 30, 30))
damage.Add(paint.IntRectOf(50, 10, 30, 30))
screen.SetRegion(damage)
draw(screen, 50.0)
screen.ClearRegion()
mut fresh := paint.NewCanvas(100, 50)
draw(fresh, 50.0)
println "rectangles repainted:", damage.Count()
println "same as a full repaint:", screen.Hash() == fresh.Hash()
fresh.Free()
screen.Free()
endTypes
BorderStyle
enum BorderStyle| Name | Type | Description |
|---|---|---|
None | | No line on this side. |
Solid | | A solid line. |
Dashed | | Dashes as Chromium draws them: twice the side width long with gaps as wide as the side when the side is 3 pixels or wider, and three times long with gaps twice as wide when it is thinner. The gap is stretched or shrunk so that both ends of the side get a whole dash. |
Dotted | | Round dots as wide as the side, spaced so that both ends get a dot. On straight sides the dots snap to whole pixels, so thin dotted lines stay crisp. |
import gui.paint
func main:
mut cv := paint.NewCanvas(120, 80)
cv.Clear(paint.Rgb(245, 246, 250))
card := paint.RectOf(20.0, 15.0, 80.0, 50.0)
radii := paint.Uniform(10.0)
cv.DrawShadow(card, radii, paint.Shadow { offset_y = 3.0, blur = 8.0, color = paint.Rgba(0, 0, 0, 90) })
cv.FillRoundedRect(card, radii, paint.Rgb(255, 255, 255))
mut border := paint.SolidBorder(2.0, paint.Rgb(60, 110, 220))
border.left_width = 6.0
border.left_color = paint.Rgb(230, 80, 40)
cv.DrawBorder(card, radii, border)
cv.DrawOutline(card, radii, 1.0, 3.0, paint.Rgba(60, 110, 220, 120))
c := cv.Pixel(60, 40)
println "inside:", c.r, c.g, c.b
e := cv.Pixel(22, 40)
println "left border:", e.r, e.g, e.b
println "hash:", cv.Hash()
cv.Free()
endGradientKind
enum GradientKind| Name | Type | Description |
|---|---|---|
Linear | | Colours change along a line, like CSS linear-gradient. |
Radial | | Colours change from a centre outwards in an ellipse, like CSS radial-gradient. |
Conic | | Colours change around a centre, like CSS conic-gradient. |
import gui.paint
func main:
mut cv := paint.NewCanvas(120, 40)
mut sky := paint.LinearGradient(90.0)
sky.AddStop(0.0, paint.Rgb(255, 120, 0))
sky.AddStop(-1.0, paint.Rgb(255, 0, 120))
sky.AddStop(1.0, paint.Rgb(60, 0, 200))
cv.FillGradient(paint.RectOf(0.0, 0.0, 60.0, 40.0), paint.Corners(12.0, 0.0, 0.0, 12.0), sky)
sky.Free()
size := paint.RadialSize(60.0, 40.0, 30.0, 20.0, true, paint.RadialExtent.ClosestSide)
mut glow := paint.RadialGradient(30.0, 20.0, size.x, size.y)
glow.AddStop(0.0, paint.Rgb(255, 255, 255))
glow.AddStop(1.0, paint.Rgba(0, 160, 120, 255))
cv.FillGradient(paint.RectOf(60.0, 0.0, 60.0, 40.0), paint.Uniform(0.0), glow)
glow.Free()
println "radius:", size.x
left := cv.Pixel(2, 20)
right := cv.Pixel(57, 20)
println "left:", left.r, left.g, left.b
println "right:", right.r, right.g, right.b
println "centre:", cv.Pixel(90, 20).r
cv.Free()
endRadialExtent
enum RadialExtentRadialSize.| Name | Type | Description |
|---|---|---|
ClosestSide | | The ending shape touches the side nearest to the centre. |
FarthestSide | | The ending shape touches the side farthest from the centre. |
ClosestCorner | | The ending shape passes through the nearest corner. |
FarthestCorner | | The ending shape passes through the farthest corner (the CSS default). |
The example for this item is shown with the ones above: gui-paint-Gradient.salam
ObjectFit
enum ObjectFitobject-fit modes, used by FitImage.| Name | Type | Description |
|---|---|---|
Fill | | Stretch the image to the box. |
Contain | | Scale the image to fit inside the box, keeping its shape. |
Cover | | Scale the image to cover the whole box, keeping its shape. |
None | | Keep the natural size. |
ScaleDown | | Like Contain, but never larger than the natural size. |
import gui.paint
import os
import filepath
func main:
mut tile := paint.NewCanvas(2, 2)
tile.Clear(paint.Rgb(230, 230, 230))
tile.FillRect(paint.RectOf(0.0, 0.0, 1.0, 1.0), paint.Rgb(90, 90, 90))
tile.FillRect(paint.RectOf(1.0, 1.0, 1.0, 1.0), paint.Rgb(90, 90, 90))
mut cv := paint.NewCanvas(80, 60)
cv.DrawImageTiled(tile, paint.RectOf(0.0, 0.0, 80.0, 60.0), paint.RectOf(0.0, 0.0, 8.0, 8.0), 1.0)
photo := paint.FitImage(paint.ObjectFit.Contain, 4, 2, paint.RectOf(10.0, 10.0, 60.0, 40.0), 0.5, 0.5)
println "photo box:", photo.x, photo.y, photo.width, photo.height
cv.PushRoundedClip(photo, paint.Uniform(6.0))
cv.BeginLayer(photo)
cv.FillRect(photo, paint.Rgb(0, 120, 255))
cv.FillRect(paint.RectOf(30.0, 20.0, 20.0, 20.0), paint.Rgb(255, 60, 60))
cv.EndLayer(0.8)
cv.PopClip()
path := filepath.Join(os.TempDir(), "salam_paint_example.png")
println "saved:", paint.SavePNG(cv, path)
mut ok := false
mut back := paint.LoadPNG(path, ok)
println "loaded:", ok, back.width, back.height, back.Hash() == cv.Hash()
os.Remove(path)
back.Free()
tile.Free()
cv.Free()
endFillRule
enum FillRule| Name | Type | Description |
|---|---|---|
NonZero | | Inside where the winding number is not zero. |
EvenOdd | | Inside where a ray crosses the outline an odd number of times. |
import gui.paint
func main:
mut cv := paint.NewCanvas(100, 60)
cv.Clear(paint.Rgb(255, 255, 255))
mut star := paint.NewPath()
star.MoveTo(30.0, 5.0)
star.LineTo(42.0, 52.0)
star.LineTo(5.0, 22.0)
star.LineTo(55.0, 22.0)
star.LineTo(18.0, 52.0)
star.Close()
cv.FillPath(star, paint.FillRule.EvenOdd, paint.Rgb(250, 190, 0))
cv.StrokePath(star, paint.Stroke { width = 2.0, join = paint.LineJoin.Round }, paint.Rgb(120, 60, 0))
star.Free()
mut wave := paint.NewPath()
wave.MoveTo(0.0, 0.0)
wave.CubicTo(10.0, -15.0, 20.0, 15.0, 30.0, 0.0)
cv.Translate(62.0, 30.0)
cv.StrokePath(wave, paint.Stroke { width = 3.0, cap = paint.LineCap.Round, dash = 6.0, gap = 4.0 }, paint.Rgb(0, 100, 200))
cv.PopTransform()
wave.Free()
println "middle of the star is a hole:", cv.Pixel(30, 30).b == 255
println "point of the star:", cv.Pixel(30, 12).g
println "hash:", cv.Hash()
cv.Free()
endLineCap
enum LineCap| Name | Type | Description |
|---|---|---|
Butt | | The line stops at its end point. |
Round | | A half circle past the end point. |
Square | | A half square past the end point. |
The example for this item is shown with the ones above: gui-paint-Path.salam
LineJoin
enum LineJoin| Name | Type | Description |
|---|---|---|
Miter | | A sharp corner, cut to a bevel past miter_limit. |
Round | | A round corner. |
Bevel | | A cut corner. |
The example for this item is shown with the ones above: gui-paint-Path.salam
FilterKind
enum FilterKindFilter.| Name | Type | Description |
|---|---|---|
Blur | | A Gaussian blur; amount is the standard deviation, as in CSS blur(). |
Brightness | | Multiplies the colour channels by amount. |
Contrast | | Moves the channels away from or towards middle grey by amount. |
Grayscale | | Turns the colours grey; 1 is fully grey. |
Sepia | | Turns the colours sepia; 1 is fully sepia. |
Saturate | | Changes the saturation; 0 is grey, 1 leaves the colours alone. |
HueRotate | | Turns the hue by amount degrees. |
Invert | | Inverts the colours; 1 is fully inverted. |
Opacity | | Multiplies the alpha by amount. |
DropShadow | | A blurred, offset copy of the shape drawn under it, as in CSS drop-shadow(). |
import gui.paint
func main:
mut cv := paint.NewCanvas(120, 60)
cv.Clear(paint.Rgb(255, 255, 255))
repeat 6 in i:
cv.FillRect(paint.RectOf((i * 20) as f64, 0.0, 10.0, 60.0), paint.Rgb(30, 30, 30))
end
mut glass := paint.FilterChain {}
glass.Add(paint.NewFilter(paint.FilterKind.Blur, 3.0))
glass.Add(paint.NewFilter(paint.FilterKind.Brightness, 1.3))
cv.BackdropFilter(paint.RectOf(4.0, 4.0, 50.0, 30.0), paint.Uniform(6.0), glass)
glass.Free()
mut look := paint.FilterChain {}
look.Add(paint.NewFilter(paint.FilterKind.Sepia, 1.0))
look.Add(paint.DropShadowFilter(3.0, 3.0, 2.0, paint.Rgba(0, 0, 0, 160)))
println "room around the layer:", look.Extent(), "empty:", look.IsEmpty()
tile := paint.RectOf(70.0, 10.0, 30.0, 30.0)
cv.BeginFilterLayer(tile, look)
cv.FillRoundedRect(tile, paint.Uniform(6.0), paint.Rgb(40, 120, 220))
cv.EndLayerFiltered(look, 1.0)
look.Free()
println "frosted glass is grey:", cv.Pixel(14, 20).r > 60
println "sepia tile:", cv.Pixel(85, 25).r > cv.Pixel(85, 25).b
println "hash:", cv.Hash()
cv.Free()
endColor
struct Color| Name | Type | Description |
|---|---|---|
r | int = 0 | Red, 0 to 255. |
g | int = 0 | Green, 0 to 255. |
b | int = 0 | Blue, 0 to 255. |
a | int = 255 | Alpha (opacity), 0 to 255. The default is 255. |
The example for this item is shown with the ones above: gui-paint-Box.salam
Point
struct Point| Name | Type | Description |
|---|---|---|
x | f64 = 0 | The x coordinate. |
y | f64 = 0 | The y coordinate. |
The example for this item is shown with the ones above: gui-paint-Path.salam
Rect
struct Rect| Name | Type | Description |
|---|---|---|
x | f64 = 0 | The left edge. |
y | f64 = 0 | The top edge. |
width | f64 = 0 | The width. |
height | f64 = 0 | The height. |
The example for this item is shown with the ones above: gui-paint-Box.salam
IntRect
struct IntRect| Name | Type | Description |
|---|---|---|
x | int = 0 | The left column. |
y | int = 0 | The top row. |
width | int = 0 | The number of columns. |
height | int = 0 | The number of rows. |
The example for this item is shown with the ones above: gui-paint-Image.salam
Radii
struct Radiiborder-radius.| Name | Type | Description |
|---|---|---|
top_left_x | f64 = 0 | The horizontal radius of the top left corner. |
top_left_y | f64 = 0 | The vertical radius of the top left corner. |
top_right_x | f64 = 0 | The horizontal radius of the top right corner. |
top_right_y | f64 = 0 | The vertical radius of the top right corner. |
bottom_right_x | f64 = 0 | The horizontal radius of the bottom right corner. |
bottom_right_y | f64 = 0 | The vertical radius of the bottom right corner. |
bottom_left_x | f64 = 0 | The horizontal radius of the bottom left corner. |
bottom_left_y | f64 = 0 | The vertical radius of the bottom left corner. |
The example for this item is shown with the ones above: gui-paint-Box.salam
Border
struct Border| Name | Type | Description |
|---|---|---|
top_width | f64 = 0 | The width of the top side. |
right_width | f64 = 0 | The width of the right side. |
bottom_width | f64 = 0 | The width of the bottom side. |
left_width | f64 = 0 | The width of the left side. |
top_color | Color | The colour of the top side. |
right_color | Color | The colour of the right side. |
bottom_color | Color | The colour of the bottom side. |
left_color | Color | The colour of the left side. |
top_style | BorderStyle | The style of the top side. The default is Solid. |
right_style | BorderStyle | The style of the right side. |
bottom_style | BorderStyle | The style of the bottom side. |
left_style | BorderStyle | The style of the left side. |
The example for this item is shown with the ones above: gui-paint-Box.salam
GradientStop
struct GradientStop| Name | Type | Description |
|---|---|---|
pos | f64 = -1 | The position from 0 to 1 along the gradient. A negative value means automatic, spread evenly between its neighbours as in CSS. |
color | Color | The colour at this stop. |
The example for this item is shown with the ones above: gui-paint-Gradient.salam
Gradient
struct Gradient| Name | Type | Description |
|---|---|---|
kind | GradientKind | Linear, radial or conic. |
angle | f64 = 180 | For linear: the CSS angle in degrees (0 points up, 90 right, 180 down). For conic: the start angle. |
cx | f64 = 0 | The centre x of a radial or conic gradient, from the left edge of the filled rectangle. |
cy | f64 = 0 | The centre y of a radial or conic gradient, from the top edge of the filled rectangle. |
rx | f64 = 0 | The horizontal radius of a radial gradient. |
ry | f64 = 0 | The vertical radius of a radial gradient. |
repeating | bool = false | Repeat the stops, like repeating-linear-gradient. |
stops | Vector | The colour stops in order. |
The example for this item is shown with the ones above: gui-paint-Gradient.salam
AddStop
func AddStop(pos: f64, color: Color)The example for this item is shown with the ones above: gui-paint-Gradient.salam
Free
func Free()The example for this item is shown with the ones above: gui-paint-Gradient.salam
Shadow
struct Shadowbox-shadow.| Name | Type | Description |
|---|---|---|
offset_x | f64 = 0 | The horizontal offset. |
offset_y | f64 = 0 | The vertical offset. |
blur | f64 = 0 | The blur radius. The blur is a Gaussian with a standard deviation of half this value, as in CSS. |
spread | f64 = 0 | Grows (or with a negative value shrinks) the shadow shape before blurring. |
color | Color | The shadow colour. |
inset | bool = false | An inner shadow, drawn inside the box instead of around it. |
The example for this item is shown with the ones above: gui-paint-Box.salam
Mask
struct Mask| Name | Type | Description |
|---|---|---|
data | void* | The coverage bytes, one per pixel, row by row. |
width | int = 0 | The width in pixels. |
height | int = 0 | The height in pixels. |
stride | int = 0 | The number of bytes from one row to the next. |
left | int = 0 | For glyphs: the distance from the pen position to the left edge of the mask. |
top | int = 0 | For glyphs: the distance from the baseline up to the top of the mask. |
The example for this item is shown with the ones above: gui-paint-Image.salam
Transform
struct Transform| Name | Type | Description |
|---|---|---|
a | f64 = 1 | The x scale part. |
b | f64 = 0 | The y shear part. |
c | f64 = 0 | The x shear part. |
d | f64 = 1 | The y scale part. |
e | f64 = 0 | The x translation. |
f | f64 = 0 | The y translation. |
The example for this item is shown with the ones above: gui-paint-Path.salam
Then
func Then(o: Transform): TransformThe example for this item is shown with the ones above: gui-paint-Path.salam
Apply
func Apply(p: Point): PointThe example for this item is shown with the ones above: gui-paint-Path.salam
Invert
func Invert(): Transformimport gui.paint
func main:
mut cv := paint.NewCanvas(120, 80)
cv.Clear(paint.Rgb(255, 255, 255))
turn := paint.Translation(-30.0, -20.0).Then(paint.Rotation(20.0)).Then(paint.Skewing(10.0, 0.0)).Then(paint.Translation(45.0, 40.0))
cv.PushTransform(turn)
card := paint.RectOf(0.0, 0.0, 60.0, 40.0)
cv.DrawShadow(card, paint.Uniform(8.0), paint.Shadow { offset_y = 3.0, blur = 6.0, color = paint.Rgba(0, 0, 0, 90) })
cv.FillRoundedRect(card, paint.Uniform(8.0), paint.Rgb(250, 240, 200))
mut b := paint.SolidBorder(3.0, paint.Rgb(200, 60, 0))
b.top_style = paint.BorderStyle.Dashed
b.bottom_style = paint.BorderStyle.Dotted
cv.DrawBorder(card, paint.Uniform(8.0), b)
cv.PushRoundedClip(paint.RectOf(10.0, 10.0, 40.0, 20.0), paint.Uniform(6.0))
cv.FillRect(paint.RectOf(0.0, 0.0, 60.0, 40.0), paint.Rgba(0, 90, 200, 120))
cv.PopClip()
cv.PopTransform()
cv.DrawOutlineStyled(paint.RectOf(90.0, 20.0, 20.0, 40.0), paint.Uniform(4.0), 2.0, 3.0, paint.Rgb(0, 0, 0), paint.BorderStyle.Dotted)
corner := turn.Apply(paint.Point { x = 0.0, y = 0.0 })
back := turn.Invert().Apply(corner)
box := turn.MapRect(card)
println "card corner on screen:", corner.x > 10.0, corner.y < 20.0
println "back to the card:", back.x > -0.001 and back.x < 0.001
println "screen box wider than the card:", box.width > 60.0
println "identity:", paint.Identity().IsIdentity(), turn.IsIdentity()
println "hash:", cv.Hash()
cv.Free()
endMapRect
func MapRect(r: Rect): RectThe example for this item is shown with the ones above: gui-paint-Transform.salam
IsIdentity
func IsIdentity(): boolThe example for this item is shown with the ones above: gui-paint-Transform.salam
Filter
struct Filter| Name | Type | Description |
|---|---|---|
kind | FilterKind | Which filter. |
amount | f64 = 0 | The filter amount: a blur standard deviation in pixels, an angle in degrees for HueRotate, or a factor. |
offset_x | f64 = 0 | For DropShadow, how far the shadow moves to the right. |
offset_y | f64 = 0 | For DropShadow, how far the shadow moves down. |
color | Color | For DropShadow, the shadow colour. |
The example for this item is shown with the ones above: gui-paint-Filter.salam
FilterChain
struct FilterChainfilter and backdrop-filter lists.| Name | Type | Description |
|---|---|---|
items | Vector | The filters, in order. |
The example for this item is shown with the ones above: gui-paint-Filter.salam
Add
func Add(f: Filter)The example for this item is shown with the ones above: gui-paint-Filter.salam
Extent
func Extent(): f64The example for this item is shown with the ones above: gui-paint-Filter.salam
IsEmpty
func IsEmpty(): boolThe example for this item is shown with the ones above: gui-paint-Filter.salam
Free
func Free()The example for this item is shown with the ones above: gui-paint-Filter.salam
Stroke
struct Stroke| Name | Type | Description |
|---|---|---|
width | f64 = 1 | The line width. |
cap | LineCap | The ends of open lines. |
join | LineJoin | The corners. |
miter_limit | f64 = 4 | The longest miter, as a multiple of half the width, before a corner is bevelled. |
dash | f64 = 0 | The length of a dash. Zero draws a solid line. |
gap | f64 = 0 | The gap between dashes. |
dash_offset | f64 = 0 | How far into the dash pattern the line starts. |
The example for this item is shown with the ones above: gui-paint-Path.salam
Path
struct Path| Name | Type | Description |
|---|---|---|
verbs | Vector | The commands of the path (move, line, quadratic, cubic, close). |
points | Vector | The coordinates the commands use. |
The example for this item is shown with the ones above: gui-paint-Path.salam
MoveTo
func MoveTo(x: f64, y: f64)The example for this item is shown with the ones above: gui-paint-Path.salam
LineTo
func LineTo(x: f64, y: f64)The example for this item is shown with the ones above: gui-paint-Path.salam
QuadTo
func QuadTo(cx: f64, cy: f64, x: f64, y: f64)The example for this item is shown with the ones above: gui-paint-Path.salam
CubicTo
func CubicTo(c1x: f64, c1y: f64, c2x: f64, c2y: f64, x: f64, y: f64)The example for this item is shown with the ones above: gui-paint-Path.salam
Close
func Close()The example for this item is shown with the ones above: gui-paint-Path.salam
Arc
func Arc(cx: f64, cy: f64, rx: f64, ry: f64, start: f64, sweep: f64)The example for this item is shown with the ones above: gui-paint-Path.salam
AddRect
func AddRect(r: Rect)The example for this item is shown with the ones above: gui-paint-Path.salam
AddRoundedRect
func AddRoundedRect(r: Rect, radii: Radii)The example for this item is shown with the ones above: gui-paint-Path.salam
AddEllipse
func AddEllipse(cx: f64, cy: f64, rx: f64, ry: f64)The example for this item is shown with the ones above: gui-paint-Path.salam
Clear
func Clear()The example for this item is shown with the ones above: gui-paint-Path.salam
Free
func Free()The example for this item is shown with the ones above: gui-paint-Path.salam
Region
struct RegionThe example for this item is shown with the ones above: gui-paint-Image.salam
Count
func Count(): intThe example for this item is shown with the ones above: gui-paint-Image.salam
At
func At(i: int): IntRectThe example for this item is shown with the ones above: gui-paint-Image.salam
IsEmpty
func IsEmpty(): boolThe example for this item is shown with the ones above: gui-paint-Image.salam
Clear
func Clear()The example for this item is shown with the ones above: gui-paint-Image.salam
Bounds
func Bounds(): IntRectThe example for this item is shown with the ones above: gui-paint-Image.salam
Add
func Add(r: IntRect)The example for this item is shown with the ones above: gui-paint-Image.salam
Union
func Union(o: Region)The example for this item is shown with the ones above: gui-paint-Image.salam
Canvas
struct Canvas| Name | Type | Description |
|---|---|---|
pixels | void* | The pixels: one premultiplied 0xAARRGGBB word each, so B, G, R, A bytes in memory. |
width | int = 0 | The width in pixels. |
height | int = 0 | The height in pixels. |
stride | int = 0 | The number of bytes from one row to the next. |
owned | bool = false | Whether Free releases the pixels too. |
state | _State | The drawing state (clips, transforms, layers and scratch memory). Do not change it directly. |
The example for this item is shown with the ones above: gui-paint-Box.salam
Free
func Free()The example for this item is shown with the ones above: gui-paint-Box.salam
Clear
func Clear(c: Color)The example for this item is shown with the ones above: gui-paint-Box.salam
Pixel
func Pixel(x: int, y: int): ColorThe example for this item is shown with the ones above: gui-paint-Box.salam
RawPixel
func RawPixel(x: int, y: int): u32The example for this item is shown with the ones above: gui-paint-Image.salam
Hash
func Hash(): strThe example for this item is shown with the ones above: gui-paint-Box.salam
Sub
func Sub(r: IntRect): CanvasThe example for this item is shown with the ones above: gui-paint-Image.salam
PushClip
func PushClip(r: Rect)The example for this item is shown with the ones above: gui-paint-Image.salam
PushRoundedClip
func PushRoundedClip(r: Rect, radii: Radii)The example for this item is shown with the ones above: gui-paint-Image.salam
PopClip
func PopClip()The example for this item is shown with the ones above: gui-paint-Image.salam
ClipBounds
func ClipBounds(): IntRectThe example for this item is shown with the ones above: gui-paint-Image.salam
PushTransform
func PushTransform(t: Transform)The example for this item is shown with the ones above: gui-paint-Path.salam
Translate
func Translate(dx: f64, dy: f64)The example for this item is shown with the ones above: gui-paint-Path.salam
PopTransform
func PopTransform()The example for this item is shown with the ones above: gui-paint-Path.salam
SetRegion
func SetRegion(r: Region)The example for this item is shown with the ones above: gui-paint-Image.salam
ClearRegion
func ClearRegion()The example for this item is shown with the ones above: gui-paint-Image.salam
FillRect
func FillRect(r: Rect, c: Color)The example for this item is shown with the ones above: gui-paint-Box.salam
FillRoundedRect
func FillRoundedRect(r: Rect, radii: Radii, c: Color)The example for this item is shown with the ones above: gui-paint-Box.salam
DrawBorder
func DrawBorder(r: Rect, radii: Radii, b: Border)The example for this item is shown with the ones above: gui-paint-Box.salam
DrawOutline
func DrawOutline(r: Rect, radii: Radii, width: f64, offset: f64, c: Color)The example for this item is shown with the ones above: gui-paint-Box.salam
FillGradient
func FillGradient(r: Rect, radii: Radii, g: Gradient)The example for this item is shown with the ones above: gui-paint-Gradient.salam
DrawShadow
func DrawShadow(r: Rect, radii: Radii, s: Shadow)The example for this item is shown with the ones above: gui-paint-Box.salam
DrawImage
func DrawImage(src: Canvas, dst: Rect, opacity: f64)The example for this item is shown with the ones above: gui-paint-Image.salam
DrawImagePart
func DrawImagePart(src: Canvas, part: IntRect, dst: Rect, opacity: f64)The example for this item is shown with the ones above: gui-paint-Image.salam
DrawImageTiled
func DrawImageTiled(src: Canvas, area: Rect, tile: Rect, opacity: f64)tile is the position and size of one copy (CSS background-repeat).The example for this item is shown with the ones above: gui-paint-Image.salam
DrawMask
func DrawMask(m: Mask, x: int, y: int, c: Color)The example for this item is shown with the ones above: gui-paint-Image.salam
DrawGlyph
func DrawGlyph(m: Mask, x: int, baseline: int, c: Color)left and top bearings.The example for this item is shown with the ones above: gui-paint-Image.salam
FillPath
func FillPath(p: Path, rule: FillRule, c: Color)The example for this item is shown with the ones above: gui-paint-Path.salam
StrokePath
func StrokePath(p: Path, s: Stroke, c: Color)The example for this item is shown with the ones above: gui-paint-Path.salam
BeginLayer
func BeginLayer(r: Rect)The example for this item is shown with the ones above: gui-paint-Image.salam
EndLayer
func EndLayer(opacity: f64)opacity).The example for this item is shown with the ones above: gui-paint-Image.salam
EndLayerMasked
func EndLayerMasked(opacity: f64)background-clip: text paints a background through the glyphs.The example for this item is shown with the ones above: gui-paint-Image.salam
BeginFilterLayer
func BeginFilterLayer(r: Rect, chain: FilterChain)The example for this item is shown with the ones above: gui-paint-Filter.salam
EndLayerFiltered
func EndLayerFiltered(chain: FilterChain, opacity: f64)filter).The example for this item is shown with the ones above: gui-paint-Filter.salam
DrawNineSlice
func DrawNineSlice(src: Canvas, area: Rect, ns: NineSlice, opacity: f64)src cut into nine parts around area: the corners are scaled into the corners, the edges fill the sides as repeat_x and repeat_y say, and the middle is drawn when fill is set. This is how CSS border-image is painted.import gui.paint
func main:
mut frame := paint.NewCanvas(30, 30)
frame.Clear(paint.Rgb(40, 90, 200))
frame.FillRect(paint.RectOf(10.0, 10.0, 10.0, 10.0), paint.Rgb(240, 240, 240))
frame.FillRect(paint.RectOf(0.0, 0.0, 10.0, 10.0), paint.Rgb(220, 50, 50))
mut ns := paint.NineSlice { slice_top = 10.0, slice_right = 10.0, slice_bottom = 10.0, slice_left = 10.0 }
ns.width_top = 6.0
ns.width_right = 6.0
ns.width_bottom = 6.0
ns.width_left = 6.0
ns.repeat_x = paint.ImageRepeat.Round
ns.repeat_y = paint.ImageRepeat.Stretch
ns.fill = true
mut cv := paint.NewCanvas(100, 60)
cv.Clear(paint.Rgb(255, 255, 255))
cv.DrawNineSlice(frame, paint.RectOf(4.0, 4.0, 92.0, 52.0), ns, 1.0)
c := cv.Pixel(6, 6)
println "corner:", c.r, c.g, c.b
m := cv.Pixel(50, 30)
println "middle:", m.r, m.g, m.b
println "hash:", cv.Hash()
cv.Free()
frame.Free()
endBackdropFilter
func BackdropFilter(r: Rect, radii: Radii, chain: FilterChain, opacity: f64 = 1)backdrop-filter: the pixels under the rectangle are read with mirrored edges, filtered, clipped to the rounded rectangle and drawn back with opacity (1 when left out) over what was there, the way Chromium composites a backdrop. Inside a layer the backdrop is only what the layer holds.The example for this item is shown with the ones above: gui-paint-Filter.salam
DrawOutlineStyled
func DrawOutlineStyled(r: Rect, radii: Radii, width: f64, offset: f64, c: Color, style: BorderStyle)The example for this item is shown with the ones above: gui-paint-Transform.salam
ImageRepeat
enum ImageRepeatborder-image-repeat.| Name | Type | Description |
|---|---|---|
Stretch | | Scale the part to fill the space. |
Repeat | | Tile the part at its scaled size, centred, cutting the tiles at both ends. |
Round | | Tile the part, scaled so that a whole number of tiles fits. |
Space | | Tile only whole tiles and spread the space left over evenly between and around them. |
The example for this item is shown with the ones above: gui-paint-NineSlice.salam
NineSlice
struct NineSliceDrawNineSlice cuts the source image and where the parts go.| Name | Type | Description |
|---|---|---|
slice_top | f64 = 0 | How far from the top of the source the top slice ends, in source pixels. |
slice_right | f64 = 0 | How far from the right of the source the right slice starts, in source pixels. |
slice_bottom | f64 = 0 | How far from the bottom of the source the bottom slice starts, in source pixels. |
slice_left | f64 = 0 | How far from the left of the source the left slice ends, in source pixels. |
width_top | f64 = 0 | How tall the top edge is drawn, in canvas pixels. |
width_right | f64 = 0 | How wide the right edge is drawn. |
width_bottom | f64 = 0 | How tall the bottom edge is drawn. |
width_left | f64 = 0 | How wide the left edge is drawn. Widths that do not fit are all scaled down by the same factor, as CSS does. |
repeat_x | ImageRepeat | How the top and bottom edges and the middle fill the width. |
repeat_y | ImageRepeat | How the left and right edges and the middle fill the height. |
fill | bool = false | Whether the middle part is drawn too, like the fill keyword of border-image-slice. |
The example for this item is shown with the ones above: gui-paint-NineSlice.salam
Functions
LinearGradient
func LinearGradient(angle: f64): GradientAddStop.The example for this item is shown with the ones above: gui-paint-Gradient.salam
RadialGradient
func RadialGradient(cx: f64, cy: f64, rx: f64, ry: f64): GradientThe example for this item is shown with the ones above: gui-paint-Gradient.salam
ConicGradient
func ConicGradient(cx: f64, cy: f64, angle: f64): GradientThe example for this item is shown with the ones above: gui-paint-Gradient.salam
RadialSize
func RadialSize(width: f64, height: f64, cx: f64, cy: f64, circle: bool, extent: RadialExtent): PointThe example for this item is shown with the ones above: gui-paint-Gradient.salam
NewCanvas
func NewCanvas(width: int, height: int): CanvasThe example for this item is shown with the ones above: gui-paint-Box.salam
WrapCanvas
func WrapCanvas(pixels: void*, width: int, height: int, stride: int): CanvasThe example for this item is shown with the ones above: gui-paint-Image.salam
RectOf
func RectOf(x: f64, y: f64, width: f64, height: f64): RectRect.The example for this item is shown with the ones above: gui-paint-Box.salam
IntRectOf
func IntRectOf(x: int, y: int, width: int, height: int): IntRectIntRect.The example for this item is shown with the ones above: gui-paint-Image.salam
Uniform
func Uniform(r: f64): RadiiThe example for this item is shown with the ones above: gui-paint-Box.salam
Corners
func Corners(top_left: f64, top_right: f64, bottom_right: f64, bottom_left: f64): RadiiThe example for this item is shown with the ones above: gui-paint-Gradient.salam
FitRadii
func FitRadii(r: Rect, radii: Radii): RadiiThe example for this item is shown with the ones above: gui-paint-Gradient.salam
SolidBorder
func SolidBorder(width: f64, c: Color): BorderThe example for this item is shown with the ones above: gui-paint-Box.salam
NewPath
func NewPath(): PathThe example for this item is shown with the ones above: gui-paint-Path.salam
Identity
func Identity(): TransformThe example for this item is shown with the ones above: gui-paint-Path.salam
Translation
func Translation(dx: f64, dy: f64): TransformThe example for this item is shown with the ones above: gui-paint-Path.salam
Scaling
func Scaling(sx: f64, sy: f64): TransformThe example for this item is shown with the ones above: gui-paint-Path.salam
Skewing
func Skewing(x_degrees: f64, y_degrees: f64): Transformskew().The example for this item is shown with the ones above: gui-paint-Transform.salam
NewFilter
func NewFilter(kind: FilterKind, amount: f64): FilterThe example for this item is shown with the ones above: gui-paint-Filter.salam
DropShadowFilter
func DropShadowFilter(offset_x: f64, offset_y: f64, blur: f64, c: Color): Filterdrop-shadow filter from an offset, a blur standard deviation and a colour.The example for this item is shown with the ones above: gui-paint-Filter.salam
Rotation
func Rotation(degrees: f64): TransformThe example for this item is shown with the ones above: gui-paint-Path.salam
FromImage
func FromImage(img: image.Image): Canvasai.image image (straight RGBA).The example for this item is shown with the ones above: gui-paint-Image.salam
ToImage
func ToImage(cv: Canvas): image.Imageai.image image (straight RGBA) from a canvas.The example for this item is shown with the ones above: gui-paint-Image.salam
SavePNG
func SavePNG(cv: Canvas, path: str): boolThe example for this item is shown with the ones above: gui-paint-Image.salam
LoadPNG
func LoadPNG(path: str, ok &: bool): Canvasok reports success.The example for this item is shown with the ones above: gui-paint-Image.salam
FitImage
func FitImage(fit: ObjectFit, image_width: int, image_height: int, box: Rect, pos_x: f64, pos_y: f64): Rectobject-fit mode; pos_x and pos_y are the CSS object-position as fractions (0.5 is centred).The example for this item is shown with the ones above: gui-paint-Image.salam
ScaleImage
func ScaleImage(src: Canvas, width: int, height: int): CanvasThe example for this item is shown with the ones above: gui-paint-Image.salam
Rgb
func Rgb(r: int, g: int, b: int): ColorThe example for this item is shown with the ones above: gui-paint-Box.salam
Rgba
func Rgba(r: int, g: int, b: int, a: int): ColorThe example for this item is shown with the ones above: gui-paint-Box.salam
Premultiply
func Premultiply(c: Color): u32The example for this item is shown with the ones above: gui-paint-Image.salam
Unpremultiply
func Unpremultiply(v: u32): ColorThe example for this item is shown with the ones above: gui-paint-Image.salam