LineLib — Line Shape Library

Lines connect two points within a bounding rectangle and can be styled with different colors, thicknesses, dash patterns, and end caps. Lines are ideal for diagrams, connectors, separators, crosshairs, grids, and decorative elements. Unlike other shape controls, lines have no fill property — they are drawn using only stroke properties. 80 functions.

CategoryCountDescription
Error Handling4line_error, errormsg$, strerror$, clearerror
Creation & Destruction4line# (3 overloads), line_free
Line Type2linetype (get/set)
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
line_error()line_error@Last error code (0 = no error)
line_errormsg$()line_errormsg$@Last error message as string
line_strerror$(code)line_strerror$@nDescription for a given error code
line_clearerror()line_clearerror@Clear the error state

Line Type

The line_linetype property determines how the line is drawn within its bounding rectangle:

ValueTypeDescription
0DiagonalLine from top-left to bottom-right corner (default)
1TopHorizontal line along the top edge of bounding box
2LeftVertical line along the left edge of bounding box
╯ plan9basic
' Diagonal line (default, type 0)
let diag# = line#(frm#, 10, 10, 200, 100)

' Horizontal separator (type 1 = Top)
let hLine# = line#(frm#, 10, 50, 300, 1)
line_linetype#(hLine#, 1)

' Vertical separator (type 2 = Left)
let vLine# = line#(frm#, 50, 10, 1, 200)
line_linetype#(vLine#, 2)
ⓘ Note: For horizontal lines, use line type 1 (Top) with a small height. For vertical lines, use line type 2 (Left) with a small width, or use the default diagonal type with width=1.

Numeric Values Reference

Control Alignment line_align#

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

Stroke Dash Style line_strokedash#

ValueStyle
0Solid
1Dash
2Dot
3DashDot
4DashDotDot

Stroke Cap Style line_strokecap#

ValueStyle
0Flat
1Round

Stroke Join Style line_strokejoin#

ValueStyle
0Miter
1Round
2Bevel

Line Type line_linetype#

ValueType
0Diagonal (top-left to bottom-right)
1Top (horizontal along top edge)
2Left (vertical along left edge)

Creation & Destruction

FunctionSignatureDescription
line#(parent#)line#@#Create with default size
line#(parent#, w, h)line#@#nnCreate with specified size
line#(parent#, x, y, w, h)line#@#nnnnCreate with position and size
line_free(line#)line_free@#Destroy line shape
╯ plan9basic
' Simple diagonal line
let ln# = line#(frm#, 50, 50, 200, 100)
line_stroke#(ln#, "#e74c3c")
line_strokethickness#(ln#, 3)
ⓘ Note: Lines have no fill property. All visual styling is done through stroke properties (color, thickness, dash, cap, join).

Stroke Properties

FunctionSignatureDescription
line_stroke$(line#)line_stroke$@#Get stroke color
line_stroke#(line#, color$)line_stroke#@#$Set stroke color
line_strokenone#(line#)line_strokenone#@#Remove stroke (invisible line)
line_strokethickness(line#)line_strokethickness@#Get stroke thickness
line_strokethickness#(line#, n)line_strokethickness#@#nSet stroke thickness
line_strokedash(line#)line_strokedash@#Get dash style (0–4)
line_strokedash#(line#, n)line_strokedash#@#nSet dash style
line_strokecap(line#)line_strokecap@#Get cap style (0=Flat, 1=Round)
line_strokecap#(line#, n)line_strokecap#@#nSet cap style
line_strokejoin(line#)line_strokejoin@#Get join style (0=Miter, 1=Round, 2=Bevel)
line_strokejoin#(line#, n)line_strokejoin#@#nSet join style
╯ plan9basic
' Thick dashed line with round caps
line_stroke#(ln#, "#3498db")
line_strokethickness#(ln#, 4)
line_strokedash#(ln#, 1)
line_strokecap#(ln#, 1)
ⓘ Note: Round stroke caps (line_strokecap#(ln#, 1)) round off the endpoints of the line instead of cutting them flat. This looks significantly better on thicker lines.

Position & Size

FunctionSignatureDescription
line_x(line#)line_x@#Get X position
line_x#(line#, x)line_x#@#nSet X position
line_y(line#)line_y@#Get Y position
line_y#(line#, y)line_y#@#nSet Y position
line_width(line#)line_width@#Get width (horizontal extent)
line_width#(line#, w)line_width#@#nSet width
line_height(line#)line_height@#Get height (vertical extent)
line_height#(line#, h)line_height#@#nSet height
line_bounds#(line#, x, y, w, h)line_bounds#@#nnnnSet position and size
line_move#(line#, x, y)line_move#@#nnSet position only
line_size#(line#, w, h)line_size#@#nnSet size only

Alignment & Margins

FunctionSignatureDescription
line_align(line#)line_align@#Get alignment
line_align#(line#, n)line_align#@#nSet alignment
line_margin#(line#, n)line_margin#@#nSet uniform margin on all four sides
line_margins#(line#, l, t, r, b)line_margins#@#nnnnSet individual margins
line_marginleft(line#)line_marginleft@#Get left margin
line_marginleft#(line#, n)line_marginleft#@#nSet left margin
line_margintop(line#)line_margintop@#Get top margin
line_margintop#(line#, n)line_margintop#@#nSet top margin
line_marginright(line#)line_marginright@#Get right margin
line_marginright#(line#, n)line_marginright#@#nSet right margin
line_marginbottom(line#)line_marginbottom@#Get bottom margin
line_marginbottom#(line#, n)line_marginbottom#@#nSet bottom margin

Visibility & State

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

Tag, Rotation & Parent

FunctionSignatureDescription
line_tag(line#)line_tag@#Get user-defined integer tag
line_tag#(line#, n)line_tag#@#nSet user-defined integer tag
line_rotation(line#)line_rotation@#Get rotation angle in degrees
line_rotation#(line#, angle)line_rotation#@#nSet rotation angle
line_parent#(line#)line_parent#@#Get parent control pointer
line_parent#(line#, parent#)line_parent#@##Move to a different parent
line_bringtofront#(line#)line_bringtofront#@#Bring to front of Z-order
line_sendtoback#(line#)line_sendtoback#@#Send to back of Z-order
line_invalidate#(line#)line_invalidate#@#Force the line to redraw
ⓘ Note: line_rotation# rotates the entire bounding box around the line’s center. This is different from changing line_linetype# — rotation applies a visual transform, while line type controls which path the line follows within its bounds.

Events

Each event has a setter (line_onXXX#) and a getter (line_onXXX$). Use line_clearcallbacks#(line#) to disconnect all callbacks at once.

Mouse Events

Event SetterGetterCallback Signature
line_onclick#(line#, func$)line_onclick$(line#)function name(sender#)
line_ondblclick#(line#, func$)line_ondblclick$(line#)function name(sender#)
line_onmousedown#(line#, func$)line_onmousedown$(line#)function name(sender#, button, x, y, shift$)
line_onmouseup#(line#, func$)line_onmouseup$(line#)function name(sender#, button, x, y, shift$)
line_onmousemove#(line#, func$)line_onmousemove$(line#)function name(sender#, x, y, shift$)
line_onmouseenter#(line#, func$)line_onmouseenter$(line#)function name(sender#)
line_onmouseleave#(line#, func$)line_onmouseleave$(line#)function name(sender#)
line_onmousewheel#(line#, func$)line_onmousewheel$(line#)function name(sender#, delta)

Other Events

Event SetterGetterCallback Signature
line_onresize#(line#, func$)line_onresize$(line#)function name(sender#)
line_clearcallbacks#(line#)Disconnect all event callbacks

Complete Examples

Diagonal Line

╯ diagonal.bas
let frm# = form#("Diagonal Line", 300, 300)
form_position#(frm#, 4)

let ln# = line#(frm#, 50, 50, 200, 150)
line_stroke#(ln#, "#3498db")
line_strokethickness#(ln#, 3)

form_show(frm#)

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

Horizontal Separator

╯ separator.bas
let frm# = form#("Separator", 400, 200)
form_position#(frm#, 4)

let lbl1# = label#(frm#, "Section 1")
label_bounds#(lbl1#, 20, 30, 200, 25)

' Horizontal separator line (type 1 = Top)
let sep# = line#(frm#, 20, 70, 360, 1)
line_linetype#(sep#, 1)
line_stroke#(sep#, "#bdc3c7")
line_strokethickness#(sep#, 1)

let lbl2# = label#(frm#, "Section 2")
label_bounds#(lbl2#, 20, 90, 200, 25)

form_show(frm#)

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

Dash Styles Showcase

╯ dashstyles.bas
let frm# = form#("Dash Styles", 400, 300)
form_position#(frm#, 4)

' Solid (dash = 0)
let ln1# = line#(frm#, 50, 40, 300, 1)
line_linetype#(ln1#, 1)
line_stroke#(ln1#, "#2c3e50")
line_strokethickness#(ln1#, 2)
line_strokedash#(ln1#, 0)

let lbl1# = label#(frm#, "Solid")
label_bounds#(lbl1#, 50, 45, 100, 20)

' Dash (dash = 1)
let ln2# = line#(frm#, 50, 90, 300, 1)
line_linetype#(ln2#, 1)
line_stroke#(ln2#, "#2c3e50")
line_strokethickness#(ln2#, 2)
line_strokedash#(ln2#, 1)

let lbl2# = label#(frm#, "Dash")
label_bounds#(lbl2#, 50, 95, 100, 20)

' Dot (dash = 2)
let ln3# = line#(frm#, 50, 140, 300, 1)
line_linetype#(ln3#, 1)
line_stroke#(ln3#, "#2c3e50")
line_strokethickness#(ln3#, 2)
line_strokedash#(ln3#, 2)

let lbl3# = label#(frm#, "Dot")
label_bounds#(lbl3#, 50, 145, 100, 20)

' DashDot (dash = 3)
let ln4# = line#(frm#, 50, 190, 300, 1)
line_linetype#(ln4#, 1)
line_stroke#(ln4#, "#2c3e50")
line_strokethickness#(ln4#, 2)
line_strokedash#(ln4#, 3)

let lbl4# = label#(frm#, "DashDot")
label_bounds#(lbl4#, 50, 195, 100, 20)

' DashDotDot (dash = 4)
let ln5# = line#(frm#, 50, 240, 300, 1)
line_linetype#(ln5#, 1)
line_stroke#(ln5#, "#2c3e50")
line_strokethickness#(ln5#, 2)
line_strokedash#(ln5#, 4)

let lbl5# = label#(frm#, "DashDotDot")
label_bounds#(lbl5#, 50, 245, 100, 20)

form_show(frm#)

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

Crosshairs

╯ crosshairs.bas
let frm# = form#("Crosshairs", 300, 300)
form_position#(frm#, 4)

' Horizontal crosshair
let hLine# = line#(frm#, 0, 150, 300, 1)
line_linetype#(hLine#, 1)
line_stroke#(hLine#, "#e74c3c")
line_strokethickness#(hLine#, 1)

' Vertical crosshair
let vLine# = line#(frm#, 150, 0, 1, 300)
line_linetype#(vLine#, 2)
line_stroke#(vLine#, "#e74c3c")
line_strokethickness#(vLine#, 1)

form_show(frm#)

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

Grid Pattern

╯ grid.bas
let frm# = form#("Grid", 320, 320)
form_position#(frm#, 4)

let spacing = 40
let gridSize = 280
let startX = 20
let startY = 20

' Draw horizontal grid lines
for i = 0 to 7
    let ln# = line#(frm#, startX, startY + i * spacing, gridSize, 1)
    line_linetype#(ln#, 1)
    line_stroke#(ln#, "#bdc3c7")
    line_strokethickness#(ln#, 1)
next i

' Draw vertical grid lines
for i = 0 to 7
    let ln# = line#(frm#, startX + i * spacing, startY, 1, gridSize)
    line_linetype#(ln#, 2)
    line_stroke#(ln#, "#bdc3c7")
    line_strokethickness#(ln#, 1)
next i

form_show(frm#)

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

Interactive Connector

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

' Two boxes connected by a line
let box1# = rectangle#(frm#, 30, 100, 100, 60)
rectangle_fill#(box1#, "#3498db")

let box2# = rectangle#(frm#, 270, 100, 100, 60)
rectangle_fill#(box2#, "#e74c3c")

' Connecting line between boxes
let conn# = line#(frm#, 130, 130, 140, 1)
line_linetype#(conn#, 1)
line_stroke#(conn#, "#2c3e50")
line_strokethickness#(conn#, 2)
line_strokedash#(conn#, 1)
line_strokecap#(conn#, 1)

let lbl1# = label#(frm#, "Start")
label_bounds#(lbl1#, 55, 115, 50, 25)

let lbl2# = label#(frm#, "End")
label_bounds#(lbl2#, 303, 115, 50, 25)

form_show(frm#)

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

Best Practices

PracticeWhy
Use line_linetype#(ln#, 1) for horizontal linesDraws along the top edge — clean horizontal separator
Use line_linetype#(ln#, 2) for vertical linesDraws along the left edge — clean vertical separator
Use line_strokecap#(ln#, 1) for round endsMuch better visual on thicker lines
Set hittest = 1 for interactive linesRequired for mouse events to fire on the line
Use line_bounds# to set position and size at onceMore efficient than four separate property calls
Use line_strokedash# for visual varietyDashed and dotted lines distinguish connector types in diagrams
Keep stroke thickness ≥ 2 for dashed patternsDash patterns look best at thicknesses of 2 or more
Use line_opacity# for subtle grid linesSemi-transparent lines make effective background grids

Quick Reference

FunctionSignatureDescription
line_error / errormsg$ / strerror$ / clearerrorvariousError handling (4)
line#(parent#[, w, h] | [, x, y, w, h])variousCreate (3 overloads)
line_free(line#)line_free@#Destroy
line_linetype (get/set)variousLine type: 0=Diagonal, 1=Top, 2=Left (2)
line_stroke$ / stroke# / strokenone# / strokethickness / strokedash / strokecap / strokejoinvariousStroke (11)
line_x/y/width/height (get/set) / bounds# / move# / size#variousPosition & size (11)
line_align / margin# / margins# / margin[left/top/right/bottom]variousAlignment & margins (12)
line_visible / enabled / opacity / hittestvariousVisibility & state (8)
line_tag / rotation / parent# / bringtofront# / sendtoback# / invalidate#variousTag, rotation & parent (9)
line_onclick/ondblclick/onmousedown/up/move/enter/leave/onmousewheel/onresizevariousEvents set+get (18)
line_clearcallbacks#line_clearcallbacks#@#Disconnect all events

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