CircleLib — Circle Shape Library

Circle shapes for indicators, avatars, buttons, badges, loading dots, traffic lights, and data visualization. Circle is a special case of Ellipse where width equals height. Features fill/stroke styling, opacity, rotation, and a complete mouse event system. 81 functions.

CategoryCountDescription
Error Handling4circle_error, errormsg$, strerror$, clearerror
Creation & Destruction4circle# (3 overloads), circle_free
Fill3fill$ (get), fill# (set), fillnone#
Stroke11stroke$ / stroke# / strokenone#, thickness, dash, cap, join (get/set)
Position & Size14x, 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 & Parent8tag, 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
circle_error()circle_error@Last error code (0 = no error)
circle_errormsg$()circle_errormsg$@Last error message as string
circle_strerror$(code)circle_strerror$@nDescription for a given error code
circle_clearerror()circle_clearerror@Clear the error state

Numeric Values Reference

Control Alignment circle_align#

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

Stroke Dash Style circle_strokedash#

ValueStyle
0Solid
1Dash
2Dot
3DashDot
4DashDotDot

Stroke Cap Style circle_strokecap#

ValueStyle
0Flat
1Round

Stroke Join Style circle_strokejoin#

ValueStyle
0Miter
1Round
2Bevel

Creation & Destruction

FunctionSignatureDescription
circle#(parent#)circle#@#Create with default size
circle#(parent#, w, h)circle#@#nnCreate with specified size
circle#(parent#, x, y, w, h)circle#@#nnnnCreate with position and size
circle_free(c#)circle_free@#Destroy circle shape
╯ plan9basic
' Perfect circle: width = height
let c# = circle#(frm#, 50, 50, 80, 80)
circle_fill#(c#, "#e74c3c")
circle_strokenone#(c#)

' Ring (outline only)
let ring# = circle#(frm#, 150, 50, 80, 80)
circle_fillnone#(ring#)
circle_stroke#(ring#, "#27ae60")
circle_strokethickness#(ring#, 4)
⚠ Warning: For a true circle, always use equal width and height. If width ≠ height, the shape will render as an ellipse. Use EllipseLib if you intentionally want non-uniform dimensions.

Fill Properties

FunctionSignatureDescription
circle_fill$(c#)circle_fill$@#Get fill color as hex string
circle_fill#(c#, color$)circle_fill#@#$Set fill color ("#RRGGBB" or "#AARRGGBB")
circle_fillnone#(c#)circle_fillnone#@#Remove fill (transparent body)
PatternFillStrokeUse Case
Solid circlecircle_fill#(c#, color$)circle_strokenone#(c#)Status indicators, dots, badges
Bordered circlecircle_fill#(c#, color$)circle_stroke#(c#, color$)Avatars, buttons, decorations
Ring (hollow)circle_fillnone#(c#)circle_stroke#(c#, color$)Rings, progress arcs, outlines
ⓘ Note: Use #AARRGGBB format for semi-transparent fills. Alpha ranges from 00 (fully transparent) to FF (fully opaque).

Stroke Properties

FunctionSignatureDescription
circle_stroke$(c#)circle_stroke$@#Get stroke color
circle_stroke#(c#, color$)circle_stroke#@#$Set stroke color
circle_strokenone#(c#)circle_strokenone#@#Remove stroke (no border)
circle_strokethickness(c#)circle_strokethickness@#Get stroke thickness
circle_strokethickness#(c#, n)circle_strokethickness#@#nSet stroke thickness
circle_strokedash(c#)circle_strokedash@#Get dash style (0–4)
circle_strokedash#(c#, n)circle_strokedash#@#nSet dash style
circle_strokecap(c#)circle_strokecap@#Get cap style (0=Flat, 1=Round)
circle_strokecap#(c#, n)circle_strokecap#@#nSet cap style
circle_strokejoin(c#)circle_strokejoin@#Get join style (0=Miter, 1=Round, 2=Bevel)
circle_strokejoin#(c#, n)circle_strokejoin#@#nSet join style

Position & Size

FunctionSignatureDescription
circle_x(c#)circle_x@#Get X position
circle_x#(c#, x)circle_x#@#nSet X position
circle_y(c#)circle_y@#Get Y position
circle_y#(c#, y)circle_y#@#nSet Y position
circle_width(c#)circle_width@#Get width
circle_width#(c#, w)circle_width#@#nSet width
circle_height(c#)circle_height@#Get height
circle_height#(c#, h)circle_height#@#nSet height
circle_bounds#(c#, x, y, w, h)circle_bounds#@#nnnnSet position and size
circle_move#(c#, x, y)circle_move#@#nnSet position only
circle_size#(c#, w, h)circle_size#@#nnSet size only
ⓘ Note: The X/Y coordinates specify the top-left corner of the bounding box, not the center. A circle at (50, 50) with size (80, 80) has its center at (90, 90).

Alignment & Margins

FunctionSignatureDescription
circle_align(c#)circle_align@#Get alignment
circle_align#(c#, n)circle_align#@#nSet alignment
circle_margin#(c#, n)circle_margin#@#nSet uniform margin on all four sides
circle_margins#(c#, l, t, r, b)circle_margins#@#nnnnSet individual margins
circle_marginleft(c#)circle_marginleft@#Get left margin
circle_marginleft#(c#, n)circle_marginleft#@#nSet left margin
circle_margintop(c#)circle_margintop@#Get top margin
circle_margintop#(c#, n)circle_margintop#@#nSet top margin
circle_marginright(c#)circle_marginright@#Get right margin
circle_marginright#(c#, n)circle_marginright#@#nSet right margin
circle_marginbottom(c#)circle_marginbottom@#Get bottom margin
circle_marginbottom#(c#, n)circle_marginbottom#@#nSet bottom margin

Visibility & State

FunctionSignatureDescription
circle_visible(c#)circle_visible@#Get visibility (0/1)
circle_visible#(c#, n)circle_visible#@#nSet visibility
circle_enabled(c#)circle_enabled@#Get enabled state (0/1)
circle_enabled#(c#, n)circle_enabled#@#nSet enabled state
circle_opacity(c#)circle_opacity@#Get opacity (0.0–1.0)
circle_opacity#(c#, n)circle_opacity#@#nSet opacity
circle_hittest(c#)circle_hittest@#Get hit-test state (0/1)
circle_hittest#(c#, n)circle_hittest#@#nEnable/disable mouse hit testing
⚠ Warning: Set circle_hittest#(c#, 1) before assigning mouse event handlers. Without hit testing, the shape will not receive mouse events.

Tag, Rotation & Parent

FunctionSignatureDescription
circle_tag(c#)circle_tag@#Get user-defined integer tag
circle_tag#(c#, n)circle_tag#@#nSet user-defined integer tag
circle_rotation(c#)circle_rotation@#Get rotation angle in degrees
circle_rotation#(c#, angle)circle_rotation#@#nSet rotation angle
circle_parent#(c#)circle_parent#@#Get parent control pointer
circle_parent#(c#, parent#)circle_parent#@##Move to a different parent
circle_bringtofront#(c#)circle_bringtofront#@#Bring to front of Z-order
circle_sendtoback#(c#)circle_sendtoback#@#Send to back of Z-order
circle_invalidate#(c#)circle_invalidate#@#Force the shape to redraw
ⓘ Note: Rotation has no visible effect on a perfect circle, but it does affect the coordinate system if child controls are present.

Events

Each event has a setter (circle_onXXX#) and a getter (circle_onXXX$). Use circle_clearcallbacks#(c#) to disconnect all callbacks at once.

Mouse Events

Event SetterGetterCallback Signature
circle_onclick#(c#, func$)circle_onclick$(c#)function name(sender#)
circle_ondblclick#(c#, func$)circle_ondblclick$(c#)function name(sender#)
circle_onmousedown#(c#, func$)circle_onmousedown$(c#)function name(sender#, button, x, y, shift$)
circle_onmouseup#(c#, func$)circle_onmouseup$(c#)function name(sender#, button, x, y, shift$)
circle_onmousemove#(c#, func$)circle_onmousemove$(c#)function name(sender#, x, y, shift$)
circle_onmouseenter#(c#, func$)circle_onmouseenter$(c#)function name(sender#)
circle_onmouseleave#(c#, func$)circle_onmouseleave$(c#)function name(sender#)
circle_onmousewheel#(c#, func$)circle_onmousewheel$(c#)function name(sender#, delta)

Other Events

Event SetterGetterCallback Signature
circle_onresize#(c#, func$)circle_onresize$(c#)function name(sender#)
circle_clearcallbacks#(c#)Disconnect all event callbacks

Circle vs Ellipse vs Arc vs Pie

ShapeLibraryKey DifferenceBest For
CircleCircleLibWidth = Height for true circleStatus indicators, avatars, dots, buttons
EllipseEllipseLibWidth ≠ Height supportedOvals, decorative shapes
ArcArcLibPartial circle (start/end angles)Progress rings, gauges, dials
PiePieLibWedge shape (filled sector)Charts, progress, segmented displays

Complete Examples

Status Indicators

╯ status.bas
let frm# = form#("Status", 300, 150)
form_position#(frm#, 4)

' Online indicator (green)
let indOn# = circle#(frm#, 30, 30, 20, 20)
circle_fill#(indOn#, "#27ae60")
circle_strokenone#(indOn#)

let lblOn# = label#(frm#, "Online")
label_move#(lblOn#, 60, 33)

' Away indicator (yellow)
let indAway# = circle#(frm#, 30, 60, 20, 20)
circle_fill#(indAway#, "#f1c40f")
circle_strokenone#(indAway#)

let lblAway# = label#(frm#, "Away")
label_move#(lblAway#, 60, 63)

' Offline indicator (gray)
let indOff# = circle#(frm#, 30, 90, 20, 20)
circle_fill#(indOff#, "#95a5a6")
circle_strokenone#(indOff#)

let lblOff# = label#(frm#, "Offline")
label_move#(lblOff#, 60, 93)

form_show(frm#)

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

Traffic Light

╯ traffic.bas
let frm# = form#("Traffic Light", 150, 350)
form_position#(frm#, 4)

let state = 1

' Background
let bg# = roundrect#(frm#, 35, 20, 80, 220)
roundrect_fill#(bg#, "#2c3e50")
roundrect_corners#(bg#, 10)

' Red light (starts active)
let red# = circle#(frm#, 45, 30, 60, 60)
circle_fill#(red#, "#c0392b")
circle_stroke#(red#, "#922b21")
circle_strokethickness#(red#, 2)

' Yellow light
let yellow# = circle#(frm#, 45, 100, 60, 60)
circle_fill#(yellow#, "#7f8c8d")
circle_stroke#(yellow#, "#5d6d7e")
circle_strokethickness#(yellow#, 2)

' Green light
let green# = circle#(frm#, 45, 170, 60, 60)
circle_fill#(green#, "#7f8c8d")
circle_stroke#(green#, "#5d6d7e")
circle_strokethickness#(green#, 2)

let btnNext# = button#(frm#, "Next")
button_bounds#(btnNext#, 35, 270, 80, 30)
button_onclick#(btnNext#, "OnNext")

form_show(frm#)

function OnNext(sender#)
    ' Reset all to gray
    circle_fill#(red#, "#7f8c8d")
    circle_fill#(yellow#, "#7f8c8d")
    circle_fill#(green#, "#7f8c8d")

    state = state + 1
    if state > 3 then state = 1

    ' Activate current light
    if state = 1 then
        circle_fill#(red#, "#c0392b")
    elseif state = 2 then
        circle_fill#(yellow#, "#f1c40f")
    elseif state = 3 then
        circle_fill#(green#, "#27ae60")
    endif
endfunction

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

Clickable Color Buttons

╯ buttons.bas
let frm# = form#("Circle Buttons", 400, 150)
form_position#(frm#, 4)

colors# = sdim#(4)
colors#$[1] = "#e74c3c" : colors#$[2] = "#3498db"
colors#$[3] = "#2ecc71" : colors#$[4] = "#9b59b6"

for i = 1 to 4
    let c# = circle#(frm#, 30 + i * 80, 30, 60, 60)
    circle_fill#(c#, colors#$[i])
    circle_strokenone#(c#)
    circle_hittest#(c#, 1)
    circle_tag#(c#, i)
    circle_onclick#(c#, "OnCircleClick")
    circle_onmouseenter#(c#, "OnEnter")
    circle_onmouseleave#(c#, "OnLeave")
next

let lblSel# = label#(frm#, "Click a circle")
label_move#(lblSel#, 20, 110)

form_show(frm#)

function OnCircleClick(sender#)
    label_text#(lblSel#, "Clicked: " + colors#$[circle_tag(sender#)])
endfunction

function OnEnter(sender#)
    circle_opacity#(sender#, 0.7)
endfunction

function OnLeave(sender#)
    circle_opacity#(sender#, 1.0)
endfunction

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

Animated Loading Dots

╯ loading.bas
let frm# = form#("Loading", 250, 100)
form_position#(frm#, 4)

let dot1# = circle#(frm#, 70, 35, 25, 25)
circle_fill#(dot1#, "#3498db")
circle_strokenone#(dot1#)

let dot2# = circle#(frm#, 110, 35, 25, 25)
circle_fill#(dot2#, "#3498db")
circle_strokenone#(dot2#)
circle_opacity#(dot2#, 0.25)

let dot3# = circle#(frm#, 150, 35, 25, 25)
circle_fill#(dot3#, "#3498db")
circle_strokenone#(dot3#)
circle_opacity#(dot3#, 0.25)

let dotStep = 0

let tmr# = timer#()
timer_interval#(tmr#, 300)
timer_ontimer#(tmr#, "OnAnimate")
timer_start#(tmr#)

form_show(frm#)

function OnAnimate(sender#)
    dotStep = dotStep + 1
    if dotStep > 2 then dotStep = 0

    ' Reset all to dim
    circle_opacity#(dot1#, 0.25)
    circle_opacity#(dot2#, 0.25)
    circle_opacity#(dot3#, 0.25)

    ' Highlight current dot
    if dotStep = 0 then
        circle_opacity#(dot1#, 1.0)
    elseif dotStep = 1 then
        circle_opacity#(dot2#, 1.0)
    elseif dotStep = 2 then
        circle_opacity#(dot3#, 1.0)
    endif
endfunction

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

Bouncing Ball

╯ bounce.bas
let frm# = form#("Bouncing Ball", 400, 300)
form_position#(frm#, 4)

let ball# = circle#(frm#, 50, 130, 40, 40)
circle_fill#(ball#, "#e74c3c")
circle_strokenone#(ball#)

let posX = 50
let posY = 130
let dx = 4
let dy = 3

let tmr# = timer#()
timer_interval#(tmr#, 16)
timer_ontimer#(tmr#, "OnFrame")
timer_start#(tmr#)

form_show(frm#)

function OnFrame(sender#)
    posX = posX + dx
    posY = posY + dy

    if posX >= 360 then dx = -4
    if posX <= 0 then dx = 4
    if posY >= 260 then dy = -3
    if posY <= 0 then dy = 3

    circle_move#(ball#, posX, posY)
endfunction

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

Best Practices

PracticeWhy
Use equal width and height for true circlesUnequal dimensions render as an ellipse
Set hittest = 1 for interactive circlesRequired for mouse events to fire on shapes
Use fillnone# for ringsTransparent body with visible stroke creates hollow circles
Use opacity for hover feedbackChange opacity on mouse enter/leave for subtle interaction
Use tag to identify circles in shared callbacksRetrieve with circle_tag(sender#) inside the handler
Use circle_move# for animationMore efficient than setting x and y separately
Use strokenone# for clean indicatorsFlat color dots without borders look modern

Quick Reference

FunctionSignatureDescription
circle_error / errormsg$ / strerror$ / clearerrorvariousError handling (4)
circle#(parent#[, w, h] | [, x, y, w, h])variousCreate (3 overloads)
circle_free(c#)circle_free@#Destroy
circle_fill$ / fill# / fillnone#variousFill (3)
circle_stroke$ / stroke# / strokenone# / strokethickness / strokedash / strokecap / strokejoinvariousStroke (11)
circle_x/y/width/height (get/set) / bounds# / move# / size#variousPosition & size (14)
circle_align / margin# / margins# / margin[left/top/right/bottom]variousAlignment & margins (12)
circle_visible / enabled / opacity / hittestvariousVisibility & state (8)
circle_tag / rotation / parent# / bringtofront# / sendtoback# / invalidate#variousTag, rotation & parent (8)
circle_onclick/ondblclick/onmousedown/up/move/enter/leave/onmousewheel/onresizevariousEvents set+get (18)
circle_clearcallbacks#circle_clearcallbacks#@#Disconnect all events

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