PathLib — Vector Path Shape Library

Paths are complex shapes defined by a series of drawing commands — move, line, curve, arc — using SVG-like path data syntax or programmatic construction. Paths are ideal for custom shapes, icons, logos, diagrams, and complex vector graphics. Supports cubic and quadratic Bézier curves, elliptical arcs, predefined shape helpers, and path transformations. 107 functions.

CategoryCountDescription
Error Handling4path_error, errormsg$, strerror$, clearerror
Creation & Destruction4path# (3 overloads), path_free
Path Data (String)2path_data$ (get), path_data# (set from SVG string)
Drawing Commands9moveto, lineto, hlineto, vlineto, curveto, smoothcurveto, quadcurveto, closepath, clear
Predefined Shapes3addrectangle#, addellipse#, addarc#
Transformations3scale#, translate#, rotate#
Path Information7pointcount, lastx, lasty, boundsx, boundsy, boundswidth, boundsheight
Wrap Mode2wrapmode (get/set)
Fill3fill$ (get), fill# (set), fillnone#
Stroke11stroke$ / stroke# / strokenone#, thickness, dash, cap, join (get/set)
Position & Size11x, y, width, height (get/set), bounds#, move#, size#
Alignment & Margins12align (get/set), margin#, margins#, marginleft/top/right/bottom (get/set)
Visibility & State8visible, enabled, opacity, hittest (get/set)
Tag, Rotation & Parent9tag, rotation (get/set), parent# (get/set), bringtofront#, sendtoback#, invalidate#
Events199 event types × set/get + clearcallbacks#

Cross-Platform Support

PlatformStatusNotes
Windows✅ Full SupportWin32/Win64
Linux✅ Full SupportGTK-based
Android✅ Full SupportHardware-accelerated

Error Handling

FunctionSignatureDescription
path_error()path_error@Last error code (0 = no error)
path_errormsg$()path_errormsg$@Last error message as string
path_strerror$(code)path_strerror$@nDescription for a given error code
path_clearerror()path_clearerror@Clear the error state

SVG Path Data Syntax

The path_data#() function accepts SVG-like path data strings. Each command is a letter followed by coordinates:

CommandParametersDescription
M x,yMove toStart a new subpath at (x, y)
L x,yLine toDraw a straight line to (x, y)
H xHorizontal lineDraw horizontal line to x
V yVertical lineDraw vertical line to y
C x1,y1 x2,y2 x,yCubic bézierCurve with two control points
S x2,y2 x,ySmooth cubicSmooth continuation of previous curve
Q x1,y1 x,yQuadratic bézierCurve with single control point
T x,ySmooth quadraticSmooth continuation of previous quadratic
A rx,ry rot large,sweep x,yElliptical arcArc segment of an ellipse
ZClose pathClose current subpath back to last M
╯ plan9basic
' Square using SVG path data
path_data#(pth#, "M 10,10 L 190,10 L 190,190 L 10,190 Z")

' Triangle
path_data#(pth#, "M 100,0 L 200,173 L 0,173 Z")

' Smooth curve
path_data#(pth#, "M 0,100 C 50,0 100,0 150,100 S 250,200 300,100")

Path Data (String-Based)

FunctionSignatureDescription
path_data$(path#)path_data$@#Get current path data as SVG string
path_data#(path#, data$)path_data#@#$Set path data from SVG string
ⓘ Note: Setting path data with path_data# replaces all existing path data. To append to existing data, use the programmatic drawing commands instead.

Drawing Commands (Programmatic)

Build paths step by step using programmatic commands. These commands append to the current path data.

FunctionSignatureDescription
path_moveto#(path#, x, y)path_moveto#@#nnMove pen to point (M command)
path_lineto#(path#, x, y)path_lineto#@#nnDraw line to point (L command)
path_hlineto#(path#, x)path_hlineto#@#nHorizontal line to x (H command)
path_vlineto#(path#, y)path_vlineto#@#nVertical line to y (V command)
path_curveto#(path#, x1, y1, x2, y2, x, y)path_curveto#@#nnnnnnCubic bézier curve (C command)
path_smoothcurveto#(path#, x2, y2, x, y)path_smoothcurveto#@#nnnnSmooth cubic bézier (S command)
path_quadcurveto#(path#, x1, y1, x, y)path_quadcurveto#@#nnnnQuadratic bézier curve (Q command)
path_closepath#(path#)path_closepath#@#Close current subpath (Z command)
path_clear#(path#)path_clear#@#Clear all path data
╯ plan9basic
' Build a house shape programmatically
path_moveto#(pth#, 150, 0)
path_lineto#(pth#, 300, 100)
path_lineto#(pth#, 300, 200)
path_lineto#(pth#, 0, 200)
path_lineto#(pth#, 0, 100)
path_closepath#(pth#)

Predefined Shapes

Helper functions that add common shapes to the current path. These append to existing path data, allowing multiple shapes in one path.

FunctionSignatureDescription
path_addrectangle#(path#, x, y, w, h, rx, ry)path_addrectangle#@#nnnnnnAdd rounded rectangle (rx, ry = corner radii)
path_addellipse#(path#, x, y, w, h)path_addellipse#@#nnnnAdd ellipse at position with size
path_addarc#(path#, x, y, w, h, start, sweep)path_addarc#@#nnnnnnAdd arc (start/sweep in degrees)
╯ plan9basic
' Rounded rectangle with 10px radius corners
path_addrectangle#(pth#, 0, 0, 150, 100, 10, 10)

' Ellipse
path_addellipse#(pth#, 200, 0, 100, 80)

' Arc: 90-degree sweep starting at 0 degrees
path_addarc#(pth#, 50, 150, 100, 100, 0, 90)

Path Transformations

Transform the path data itself (not the control bounds). These modify the actual point coordinates in the path.

FunctionSignatureDescription
path_scale#(path#, scaleX, scaleY)path_scale#@#nnScale path data by factors
path_translate#(path#, dx, dy)path_translate#@#nnTranslate (shift) path data
path_rotate#(path#, angle)path_rotate#@#nRotate path data in degrees
ⓘ Note: Path transformations modify the path geometry itself, not the control’s position. Use path_x#/path_y# or path_rotation# to transform the control’s visual position on screen.

Path Information

FunctionSignatureDescription
path_pointcount(path#)path_pointcount@#Number of points in the path
path_lastx(path#)path_lastx@#X coordinate of the last point
path_lasty(path#)path_lasty@#Y coordinate of the last point
path_boundsx(path#)path_boundsx@#X of path data bounding box
path_boundsy(path#)path_boundsy@#Y of path data bounding box
path_boundswidth(path#)path_boundswidth@#Width of path data bounding box
path_boundsheight(path#)path_boundsheight@#Height of path data bounding box

Wrap Mode

Controls how the path data is rendered within the control’s bounds:

ValueModeDescription
0OriginalRender at original path size, positioned at top-left
1FitScale to fit within bounds, maintaining aspect ratio
2StretchStretch to fill bounds (default)
3TileRepeat path to fill the area
FunctionSignatureDescription
path_wrapmode(path#)path_wrapmode@#Get current wrap mode
path_wrapmode#(path#, mode)path_wrapmode#@#nSet wrap mode (0–3)
╯ plan9basic
' Fit path within bounds keeping aspect ratio
path_wrapmode#(pth#, 1)

' Use original size (no scaling)
path_wrapmode#(pth#, 0)

Numeric Values Reference

Control Alignment path_align#

ValueDescription
0None (absolute positioning)
1Top
2Left
3Right
4Bottom
9Client (fill parent)

Stroke Dash Style path_strokedash#

ValueStyle
0Solid
1Dash
2Dot
3DashDot
4DashDotDot

Stroke Cap Style path_strokecap#

ValueStyle
0Flat
1Round

Stroke Join Style path_strokejoin#

ValueStyle
0Miter
1Round
2Bevel

Creation & Destruction

FunctionSignatureDescription
path#(parent#)path#@#Create with default size
path#(parent#, w, h)path#@#nnCreate with specified size
path#(parent#, x, y, w, h)path#@#nnnnCreate with position and size
path_free(path#)path_free@#Destroy path shape
╯ plan9basic
' Triangle using SVG path data
let pth# = path#(frm#, 50, 50, 200, 200)
path_data#(pth#, "M 100,0 L 200,173 L 0,173 Z")
path_fill#(pth#, "#3498db")
path_stroke#(pth#, "#2c3e50")
path_strokethickness#(pth#, 2)

Fill Properties

FunctionSignatureDescription
path_fill$(path#)path_fill$@#Get fill color as hex string
path_fill#(path#, color$)path_fill#@#$Set fill color ("#RRGGBB" or "#AARRGGBB")
path_fillnone#(path#)path_fillnone#@#Remove fill (transparent)
ⓘ Note: Use path_fillnone# for stroke-only outlines. This is common for icons, wireframe shapes, and decorative curves.

Stroke Properties

FunctionSignatureDescription
path_stroke$(path#)path_stroke$@#Get stroke color
path_stroke#(path#, color$)path_stroke#@#$Set stroke color
path_strokenone#(path#)path_strokenone#@#Remove stroke (no border)
path_strokethickness(path#)path_strokethickness@#Get stroke thickness
path_strokethickness#(path#, n)path_strokethickness#@#nSet stroke thickness
path_strokedash(path#)path_strokedash@#Get dash style (0–4)
path_strokedash#(path#, n)path_strokedash#@#nSet dash style
path_strokecap(path#)path_strokecap@#Get cap style (0=Flat, 1=Round)
path_strokecap#(path#, n)path_strokecap#@#nSet cap style
path_strokejoin(path#)path_strokejoin@#Get join style (0=Miter, 1=Round, 2=Bevel)
path_strokejoin#(path#, n)path_strokejoin#@#nSet join style
ⓘ Note: Round stroke joins (path_strokejoin#(pth#, 1)) look significantly better on paths with sharp angles. For smooth curves, round stroke caps (path_strokecap#(pth#, 1)) improve the visual endpoints.

Position & Size

FunctionSignatureDescription
path_x(path#)path_x@#Get X position
path_x#(path#, x)path_x#@#nSet X position
path_y(path#)path_y@#Get Y position
path_y#(path#, y)path_y#@#nSet Y position
path_width(path#)path_width@#Get width
path_width#(path#, w)path_width#@#nSet width
path_height(path#)path_height@#Get height
path_height#(path#, h)path_height#@#nSet height
path_bounds#(path#, x, y, w, h)path_bounds#@#nnnnSet position and size
path_move#(path#, x, y)path_move#@#nnSet position only
path_size#(path#, w, h)path_size#@#nnSet size only

Alignment & Margins

FunctionSignatureDescription
path_align(path#)path_align@#Get alignment
path_align#(path#, n)path_align#@#nSet alignment
path_margin#(path#, n)path_margin#@#nSet uniform margin on all four sides
path_margins#(path#, l, t, r, b)path_margins#@#nnnnSet individual margins
path_marginleft(path#)path_marginleft@#Get left margin
path_marginleft#(path#, n)path_marginleft#@#nSet left margin
path_margintop(path#)path_margintop@#Get top margin
path_margintop#(path#, n)path_margintop#@#nSet top margin
path_marginright(path#)path_marginright@#Get right margin
path_marginright#(path#, n)path_marginright#@#nSet right margin
path_marginbottom(path#)path_marginbottom@#Get bottom margin
path_marginbottom#(path#, n)path_marginbottom#@#nSet bottom margin

Visibility & State

FunctionSignatureDescription
path_visible(path#)path_visible@#Get visibility (0/1)
path_visible#(path#, n)path_visible#@#nSet visibility
path_enabled(path#)path_enabled@#Get enabled state (0/1)
path_enabled#(path#, n)path_enabled#@#nSet enabled state
path_opacity(path#)path_opacity@#Get opacity (0.0–1.0)
path_opacity#(path#, n)path_opacity#@#nSet opacity
path_hittest(path#)path_hittest@#Get hit-test state (0/1)
path_hittest#(path#, n)path_hittest#@#nEnable/disable mouse hit testing
⚠ Warning: Set path_hittest#(path#, 1) before assigning mouse event handlers. Without hit testing, the path will not receive mouse events.

Tag, Rotation & Parent

FunctionSignatureDescription
path_tag(path#)path_tag@#Get user-defined integer tag
path_tag#(path#, n)path_tag#@#nSet user-defined integer tag
path_rotation(path#)path_rotation@#Get rotation angle in degrees
path_rotation#(path#, angle)path_rotation#@#nSet rotation angle
path_parent#(path#)path_parent#@#Get parent control pointer
path_parent#(path#, parent#)path_parent#@##Move to a different parent
path_bringtofront#(path#)path_bringtofront#@#Bring to front of Z-order
path_sendtoback#(path#)path_sendtoback#@#Send to back of Z-order
path_invalidate#(path#)path_invalidate#@#Force the path to redraw
ⓘ Note: path_rotation# rotates the entire control visually around its center. This is different from path_rotate#, which transforms the path data geometry itself. Use path_rotation# for visual rotation and path_rotate# to permanently modify path coordinates.

Events

Each event has a setter (path_onXXX#) and a getter (path_onXXX$). Use path_clearcallbacks#(path#) to disconnect all callbacks at once.

Mouse Events

Event SetterGetterCallback Signature
path_onclick#(path#, func$)path_onclick$(path#)function name(sender#)
path_ondblclick#(path#, func$)path_ondblclick$(path#)function name(sender#)
path_onmousedown#(path#, func$)path_onmousedown$(path#)function name(sender#, button, x, y, shift$)
path_onmouseup#(path#, func$)path_onmouseup$(path#)function name(sender#, button, x, y, shift$)
path_onmousemove#(path#, func$)path_onmousemove$(path#)function name(sender#, x, y, shift$)
path_onmouseenter#(path#, func$)path_onmouseenter$(path#)function name(sender#)
path_onmouseleave#(path#, func$)path_onmouseleave$(path#)function name(sender#)
path_onmousewheel#(path#, func$)path_onmousewheel$(path#)function name(sender#, delta)

Other Events

Event SetterGetterCallback Signature
path_onresize#(path#, func$)path_onresize$(path#)function name(sender#)
path_clearcallbacks#(path#)Disconnect all event callbacks

Complete Examples

Triangle

╯ triangle.bas
let frm# = form#("Triangle", 300, 300)
form_position#(frm#, 4)

let pth# = path#(frm#, 50, 50, 200, 200)
path_data#(pth#, "M 100,0 L 200,173 L 0,173 Z")
path_fill#(pth#, "#e74c3c")
path_stroke#(pth#, "#c0392b")
path_strokethickness#(pth#, 2)

form_show(frm#)

while form_visible(frm#) = 1
    processmessages()
end while

Star Shape

╯ star.bas
let frm# = form#("Star", 300, 300)
form_position#(frm#, 4)

let pth# = path#(frm#, 50, 50, 200, 200)
path_data#(pth#, "M 100,0 L 130,70 L 200,70 L 145,115 L 165,190 L 100,145 L 35,190 L 55,115 L 0,70 L 70,70 Z")
path_fill#(pth#, "#f1c40f")
path_stroke#(pth#, "#f39c12")
path_strokethickness#(pth#, 2)

form_show(frm#)

while form_visible(frm#) = 1
    processmessages()
end while

Programmatic House Shape

╯ house.bas
let frm# = form#("House", 400, 300)
form_position#(frm#, 4)

let pth# = path#(frm#, 50, 30, 300, 230)

' Build house shape step by step
path_moveto#(pth#, 150, 0)
path_lineto#(pth#, 300, 100)
path_lineto#(pth#, 300, 230)
path_lineto#(pth#, 0, 230)
path_lineto#(pth#, 0, 100)
path_closepath#(pth#)

path_fill#(pth#, "#3498db")
path_stroke#(pth#, "#2980b9")
path_strokethickness#(pth#, 3)

form_show(frm#)

while form_visible(frm#) = 1
    processmessages()
end while

Bézier Curves

╯ bezier.bas
let frm# = form#("Bezier Curves", 400, 300)
form_position#(frm#, 4)

let pth# = path#(frm#, 50, 50, 300, 200)
path_data#(pth#, "M 0,100 C 50,0 100,0 150,100 S 250,200 300,100")
path_fillnone#(pth#)
path_stroke#(pth#, "#9b59b6")
path_strokethickness#(pth#, 4)
path_strokecap#(pth#, 1)

form_show(frm#)

while form_visible(frm#) = 1
    processmessages()
end while

Combined Shapes

╯ combined.bas
let frm# = form#("Combined Shapes", 400, 350)
form_position#(frm#, 4)

let pth# = path#(frm#, 20, 20, 360, 300)

' Rounded rectangle
path_addrectangle#(pth#, 0, 0, 150, 100, 10, 10)

' Ellipse
path_addellipse#(pth#, 200, 0, 100, 80)

' Custom triangle
path_moveto#(pth#, 50, 150)
path_lineto#(pth#, 150, 150)
path_lineto#(pth#, 100, 230)
path_closepath#(pth#)

path_fill#(pth#, "#2ecc71")
path_stroke#(pth#, "#27ae60")
path_strokethickness#(pth#, 2)

form_show(frm#)

while form_visible(frm#) = 1
    processmessages()
end while

Interactive Path with Click Events

╯ clickpath.bas
let frm# = form#("Click the Star", 300, 350)
form_position#(frm#, 4)

let clicks = 0

let star# = path#(frm#, 50, 30, 200, 200)
path_data#(star#, "M 100,0 L 130,70 L 200,70 L 145,115 L 165,190 L 100,145 L 35,190 L 55,115 L 0,70 L 70,70 Z")
path_fill#(star#, "#f1c40f")
path_stroke#(star#, "#f39c12")
path_strokethickness#(star#, 2)
path_hittest#(star#, 1)
path_onclick#(star#, "OnStarClick")

let lbl# = label#(frm#, "Clicks: 0")
label_bounds#(lbl#, 100, 260, 100, 25)
label_textalign#(lbl#, 0)

form_show(frm#)

function OnStarClick(sender#)
    clicks = clicks + 1
    label_text#(lbl#, "Clicks: " + str$(clicks))
    ' Rotate star on each click
    path_rotation#(star#, clicks * 15)
endfunction

while form_visible(frm#) = 1
    processmessages()
end while

Best Practices

PracticeWhy
Use path_data# for static shapesSVG strings are compact and easy to copy from design tools
Use programmatic commands for dynamic shapesmoveto/lineto allow building paths from computed data
Call path_clear# before rebuilding a pathProgrammatic commands append; clear first to avoid accumulation
Use path_strokejoin#(pth#, 1) for round joinsMuch better visual on sharp-angled paths (stars, arrows)
Use path_fillnone# for stroke-only outlinesCommon for icons, wireframes, and decorative curves
Set hittest = 1 for interactive pathsRequired for mouse events to fire on the path
Prefer wrapmode = 1 (Fit) for scalable iconsMaintains aspect ratio when control bounds change
Use path_rotation# for visual rotationRotates the control visually; path_rotate# modifies geometry permanently
Combine shapes with addrectangle#/addellipse#Multiple sub-shapes in one path are more efficient than separate controls

Quick Reference

FunctionSignatureDescription
path_error / errormsg$ / strerror$ / clearerrorvariousError handling (4)
path#(parent#[, w, h] | [, x, y, w, h])variousCreate (3 overloads)
path_free(path#)path_free@#Destroy
path_data$ / path_data#variousPath data string (get/set) (2)
path_moveto# / lineto# / hlineto# / vlineto# / curveto# / smoothcurveto# / quadcurveto# / closepath# / clear#variousProgrammatic drawing (9)
path_addrectangle# / addellipse# / addarc#variousPredefined shapes (3)
path_scale# / translate# / rotate#variousTransformations (3)
path_pointcount / lastx / lasty / boundsx / boundsy / boundswidth / boundsheightvariousPath info (7)
path_wrapmode (get/set)variousWrap mode (2)
path_fill$ / fill# / fillnone#variousFill (3)
path_stroke$ / stroke# / strokenone# / strokethickness / strokedash / strokecap / strokejoinvariousStroke (11)
path_x/y/width/height (get/set) / bounds# / move# / size#variousPosition & size (11)
path_align / margin# / margins# / margin[left/top/right/bottom]variousAlignment & margins (12)
path_visible / enabled / opacity / hittestvariousVisibility & state (8)
path_tag / rotation / parent# / bringtofront# / sendtoback# / invalidate#variousTag, rotation & parent (9)
path_onclick/ondblclick/onmousedown/up/move/enter/leave/onmousewheel/onresizevariousEvents set+get (18)
path_clearcallbacks#path_clearcallbacks#@#Disconnect all events

107 functions. Part of the Plan9Basic GUI shape library system.