ArcLib — Arc Shape Library
Curved segments of an ellipse defined by start and end angles. Arcs are ideal for gauges, progress rings, speedometers, pie chart segments, clock faces, and decorative curved elements. The arc is drawn clockwise from start angle to end angle within the bounding ellipse. 86 functions.
| Category | Count | Description |
|---|---|---|
| Error Handling | 4 | arc_error, errormsg$, strerror$, clearerror |
| Creation & Destruction | 4 | arc# (3 overloads), arc_free |
| Arc Angles | 5 | startangle, endangle (get/set), angles# (set both) |
| Fill | 3 | fill$ (get), fill# (set), fillnone# |
| Stroke | 11 | stroke$ / stroke# / strokenone#, thickness, dash, cap, join (get/set) |
| Position & Size | 14 | x, y, width, height (get/set), bounds#, move#, size# |
| Alignment & Margins | 12 | align (get/set), margin#, margins#, marginleft/top/right/bottom (get/set) |
| Visibility & State | 8 | visible, enabled, opacity, hittest (get/set) |
| Tag, Rotation & Parent | 8 | tag, rotation (get/set), parent# (get/set), bringtofront#, sendtoback#, invalidate# |
| Events | 19 | 9 event types × set/get + clearcallbacks# |
Cross-Platform Support
| Platform | Status | Notes |
|---|---|---|
| Windows | ✅ Full Support | Win32/Win64 |
| macOS | ✅ Full Support | Intel/ARM (Apple Silicon) |
| Linux | ✅ Full Support | GTK-based |
| Android | ✅ Full Support | Hardware-accelerated |
| iOS | ✅ Full Support | Hardware-accelerated |
Error Handling
| Function | Signature | Description |
|---|---|---|
arc_error() | arc_error@ | Last error code (0 = no error) |
arc_errormsg$() | arc_errormsg$@ | Last error message as string |
arc_strerror$(code) | arc_strerror$@n | Description for a given error code |
arc_clearerror() | arc_clearerror@ | Clear the error state |
Angle System
Angles are measured in degrees, starting from the right (3 o'clock position) and increasing clockwise:
| Degrees | Position | Clock Analogy |
|---|---|---|
| 0° | Right | 3 o’clock |
| 90° | Bottom | 6 o’clock |
| 180° | Left | 9 o’clock |
| 270° | Top | 12 o’clock |
| 360° | Full circle (back to right) | Complete revolution |
Common Arc Ranges
| Start | End | Span | Shape |
|---|---|---|---|
| 0° | 90° | 90° | Quarter circle (bottom-right) |
| 0° | 180° | 180° | Half circle (bottom) |
| 180° | 360° | 180° | Half circle (top) — great for gauges |
| 0° | 270° | 270° | Three-quarter circle |
| 0° | 360° | 360° | Full circle |
| 270° | 360° | 90° | Quarter circle (top-right) |
| 135° | 405° | 270° | 270° gauge arc (bottom-open) |
ⓘ Note: The arc is drawn clockwise from start angle to end angle. The end angle can exceed 360° (e.g., start=270, end=630 draws a full circle starting from the top).
⚠ Warning: If start angle equals end angle, no arc is visible. The end angle must be greater than the start angle for the arc to render.
Numeric Values Reference
Control Alignment arc_align#
| Value | Description |
|---|---|
| 0 | None (absolute positioning) |
| 1 | Top |
| 2 | Left |
| 3 | Right |
| 4 | Bottom |
| 9 | Client (fill parent) |
Stroke Dash Style arc_strokedash#
| Value | Style |
|---|---|
| 0 | Solid |
| 1 | Dash |
| 2 | Dot |
| 3 | DashDot |
| 4 | DashDotDot |
Stroke Cap Style arc_strokecap#
| Value | Style |
|---|---|
| 0 | Flat |
| 1 | Round |
Stroke Join Style arc_strokejoin#
| Value | Style |
|---|---|
| 0 | Miter |
| 1 | Round |
| 2 | Bevel |
Creation & Destruction
| Function | Signature | Description |
|---|---|---|
arc#(parent#) | arc#@# | Create with default size |
arc#(parent#, w, h) | arc#@#nn | Create with specified size |
arc#(parent#, x, y, w, h) | arc#@#nnnn | Create with position and size |
arc_free(arc#) | arc_free@# | Destroy arc shape |
' Quarter circle arc let a# = arc#(frm#, 50, 50, 200, 200) arc_startangle#(a#, 0) arc_endangle#(a#, 90) arc_fill#(a#, "#3498db") arc_stroke#(a#, "#2c3e50") arc_strokethickness#(a#, 2)
ⓘ Note: Use equal width and height for circular arcs. Different width/height creates elliptical arcs.
Arc Angle Properties
| Function | Signature | Description |
|---|---|---|
arc_startangle(arc#) | arc_startangle@# | Get start angle in degrees |
arc_startangle#(arc#, angle) | arc_startangle#@#n | Set start angle in degrees |
arc_endangle(arc#) | arc_endangle@# | Get end angle in degrees |
arc_endangle#(arc#, angle) | arc_endangle#@#n | Set end angle in degrees |
arc_angles#(arc#, start, end) | arc_angles#@#nn | Set both angles at once |
' Semi-circle gauge (top half) arc_angles#(a#, 180, 360) ' Full ring arc_angles#(a#, 0, 360) ' 270-degree gauge (bottom-open) arc_angles#(a#, 135, 405) ' Animated: set end angle dynamically arc_endangle#(a#, 180 + progress * 1.8)
Fill Properties
| Function | Signature | Description |
|---|---|---|
arc_fill$(arc#) | arc_fill$@# | Get fill color as hex string |
arc_fill#(arc#, color$) | arc_fill#@#$ | Set fill color ("#RRGGBB" or "#AARRGGBB") |
arc_fillnone#(arc#) | arc_fillnone#@# | Remove fill (transparent) |
| Pattern | Fill | Stroke | Use Case |
|---|---|---|---|
| Filled wedge | arc_fill# | arc_strokenone# | Pie chart segments, colored gauges |
| Bordered wedge | arc_fill# | arc_stroke# | Progress indicators with borders |
| Stroke-only arc | arc_fillnone# | arc_stroke# | Progress rings, loading spinners, gauge outlines |
ⓘ Note: For progress rings and loading spinners, use
arc_fillnone# with a thick stroke and round caps. This creates the modern circular progress indicator look.Stroke Properties
| Function | Signature | Description |
|---|---|---|
arc_stroke$(arc#) | arc_stroke$@# | Get stroke color |
arc_stroke#(arc#, color$) | arc_stroke#@#$ | Set stroke color |
arc_strokenone#(arc#) | arc_strokenone#@# | Remove stroke (no border) |
arc_strokethickness(arc#) | arc_strokethickness@# | Get stroke thickness |
arc_strokethickness#(arc#, n) | arc_strokethickness#@#n | Set stroke thickness |
arc_strokedash(arc#) | arc_strokedash@# | Get dash style (0–4) |
arc_strokedash#(arc#, n) | arc_strokedash#@#n | Set dash style |
arc_strokecap(arc#) | arc_strokecap@# | Get cap style (0=Flat, 1=Round) |
arc_strokecap#(arc#, n) | arc_strokecap#@#n | Set cap style |
arc_strokejoin(arc#) | arc_strokejoin@# | Get join style (0=Miter, 1=Round, 2=Bevel) |
arc_strokejoin#(arc#, n) | arc_strokejoin#@#n | Set join style |
ⓘ Note: Round stroke caps (
arc_strokecap#(arc#, 1)) look significantly better on thick stroke-only arcs. They round off the ends of the arc curve instead of cutting them flat.Position & Size
| Function | Signature | Description |
|---|---|---|
arc_x(arc#) | arc_x@# | Get X position |
arc_x#(arc#, x) | arc_x#@#n | Set X position |
arc_y(arc#) | arc_y@# | Get Y position |
arc_y#(arc#, y) | arc_y#@#n | Set Y position |
arc_width(arc#) | arc_width@# | Get width |
arc_width#(arc#, w) | arc_width#@#n | Set width |
arc_height(arc#) | arc_height@# | Get height |
arc_height#(arc#, h) | arc_height#@#n | Set height |
arc_bounds#(arc#, x, y, w, h) | arc_bounds#@#nnnn | Set position and size |
arc_move#(arc#, x, y) | arc_move#@#nn | Set position only |
arc_size#(arc#, w, h) | arc_size#@#nn | Set size only |
Alignment & Margins
| Function | Signature | Description |
|---|---|---|
arc_align(arc#) | arc_align@# | Get alignment |
arc_align#(arc#, n) | arc_align#@#n | Set alignment |
arc_margin#(arc#, n) | arc_margin#@#n | Set uniform margin on all four sides |
arc_margins#(arc#, l, t, r, b) | arc_margins#@#nnnn | Set individual margins |
arc_marginleft(arc#) | arc_marginleft@# | Get left margin |
arc_marginleft#(arc#, n) | arc_marginleft#@#n | Set left margin |
arc_margintop(arc#) | arc_margintop@# | Get top margin |
arc_margintop#(arc#, n) | arc_margintop#@#n | Set top margin |
arc_marginright(arc#) | arc_marginright@# | Get right margin |
arc_marginright#(arc#, n) | arc_marginright#@#n | Set right margin |
arc_marginbottom(arc#) | arc_marginbottom@# | Get bottom margin |
arc_marginbottom#(arc#, n) | arc_marginbottom#@#n | Set bottom margin |
Visibility & State
| Function | Signature | Description |
|---|---|---|
arc_visible(arc#) | arc_visible@# | Get visibility (0/1) |
arc_visible#(arc#, n) | arc_visible#@#n | Set visibility |
arc_enabled(arc#) | arc_enabled@# | Get enabled state (0/1) |
arc_enabled#(arc#, n) | arc_enabled#@#n | Set enabled state |
arc_opacity(arc#) | arc_opacity@# | Get opacity (0.0–1.0) |
arc_opacity#(arc#, n) | arc_opacity#@#n | Set opacity |
arc_hittest(arc#) | arc_hittest@# | Get hit-test state (0/1) |
arc_hittest#(arc#, n) | arc_hittest#@#n | Enable/disable mouse hit testing |
⚠ Warning: Set
arc_hittest#(arc#, 1) before assigning mouse event handlers. Without hit testing, the shape will not receive mouse events.Tag, Rotation & Parent
| Function | Signature | Description |
|---|---|---|
arc_tag(arc#) | arc_tag@# | Get user-defined integer tag |
arc_tag#(arc#, n) | arc_tag#@#n | Set user-defined integer tag |
arc_rotation(arc#) | arc_rotation@# | Get rotation angle in degrees |
arc_rotation#(arc#, angle) | arc_rotation#@#n | Set rotation angle |
arc_parent#(arc#) | arc_parent#@# | Get parent control pointer |
arc_parent#(arc#, parent#) | arc_parent#@## | Move to a different parent |
arc_bringtofront#(arc#) | arc_bringtofront#@# | Bring to front of Z-order |
arc_sendtoback#(arc#) | arc_sendtoback#@# | Send to back of Z-order |
arc_invalidate#(arc#) | arc_invalidate#@# | Force the shape to redraw |
ⓘ Note:
arc_rotation# rotates the entire shape around its center, which is different from changing arc_startangle#/arc_endangle#. Rotation shifts the visual orientation; angles control which segment of the ellipse is drawn.Events
Each event has a setter (arc_onXXX#) and a getter (arc_onXXX$). Use arc_clearcallbacks#(arc#) to disconnect all callbacks at once.
Mouse Events
| Event Setter | Getter | Callback Signature |
|---|---|---|
arc_onclick#(arc#, func$) | arc_onclick$(arc#) | function name(sender#) |
arc_ondblclick#(arc#, func$) | arc_ondblclick$(arc#) | function name(sender#) |
arc_onmousedown#(arc#, func$) | arc_onmousedown$(arc#) | function name(sender#, button, x, y, shift$) |
arc_onmouseup#(arc#, func$) | arc_onmouseup$(arc#) | function name(sender#, button, x, y, shift$) |
arc_onmousemove#(arc#, func$) | arc_onmousemove$(arc#) | function name(sender#, x, y, shift$) |
arc_onmouseenter#(arc#, func$) | arc_onmouseenter$(arc#) | function name(sender#) |
arc_onmouseleave#(arc#, func$) | arc_onmouseleave$(arc#) | function name(sender#) |
arc_onmousewheel#(arc#, func$) | arc_onmousewheel$(arc#) | function name(sender#, delta) |
Other Events
| Event Setter | Getter | Callback Signature |
|---|---|---|
arc_onresize#(arc#, func$) | arc_onresize$(arc#) | function name(sender#) |
arc_clearcallbacks#(arc#) | — | Disconnect all event callbacks |
Arc vs Pie
| Feature | Arc (ArcLib) | Pie (PieLib) |
|---|---|---|
| Shape | Curved segment — follows the ellipse edge | Wedge/sector — fills from center to edge |
| Typical stroke-only use | Progress rings, loading spinners, gauges | Not typical (wedges are usually filled) |
| Typical filled use | Gauge needles, colored arc segments | Pie charts, segmented displays |
| Angle properties | startangle, endangle, angles# | startangle, endangle, angles# |
| Visual difference | Looks like a curved line or partial ring | Looks like a pizza slice |
| Function count | 86 | 86 |
ⓘ Note: Both ArcLib and PieLib use the same angle system (0° = right, clockwise). The key difference is visual: arcs trace the edge of the ellipse, while pies fill the interior wedge from the center.
Complete Examples
Progress Gauge
let frm# = form#("Progress Gauge", 300, 300) form_position#(frm#, 4) ' Background arc (full semi-circle, top half) let bgArc# = arc#(frm#, 50, 75, 200, 200) arc_startangle#(bgArc#, 180) arc_endangle#(bgArc#, 360) arc_fill#(bgArc#, "#ecf0f1") arc_stroke#(bgArc#, "#bdc3c7") arc_strokethickness#(bgArc#, 2) ' Progress arc (75% of 180 degrees = 135 degrees) let progArc# = arc#(frm#, 50, 75, 200, 200) arc_startangle#(progArc#, 180) arc_endangle#(progArc#, 315) arc_fill#(progArc#, "#3498db") arc_stroke#(progArc#, "#2980b9") arc_strokethickness#(progArc#, 2) let lblPct# = label#(frm#, "75%") label_bounds#(lblPct#, 100, 140, 100, 30) label_textalign#(lblPct#, 0) label_fontsize#(lblPct#, 24) form_show(frm#) while form_visible(frm#) = 1 processmessages() end while
Loading Spinner
let frm# = form#("Loading", 250, 250) form_position#(frm#, 4) ' Spinning arc (stroke-only with round caps) let spinner# = arc#(frm#, 50, 50, 150, 150) arc_fillnone#(spinner#) arc_stroke#(spinner#, "#e74c3c") arc_strokethickness#(spinner#, 8) arc_strokecap#(spinner#, 1) arc_startangle#(spinner#, 0) arc_endangle#(spinner#, 90) let spinAngle = 0 let tmr# = timer#() timer_interval#(tmr#, 30) timer_ontimer#(tmr#, "OnSpin") timer_start#(tmr#) form_show(frm#) function OnSpin(sender#) spinAngle = spinAngle + 8 if spinAngle >= 360 then spinAngle = 0 arc_startangle#(spinner#, spinAngle) arc_endangle#(spinner#, spinAngle + 90) endfunction while form_visible(frm#) = 1 processmessages() end while
Interactive Progress Ring
let frm# = form#("Progress Ring", 300, 350) form_position#(frm#, 4) let progress = 0 ' Background ring let bgRing# = arc#(frm#, 50, 30, 200, 200) arc_fillnone#(bgRing#) arc_stroke#(bgRing#, "#ecf0f1") arc_strokethickness#(bgRing#, 12) arc_angles#(bgRing#, 0, 360) ' Progress ring let ring# = arc#(frm#, 50, 30, 200, 200) arc_fillnone#(ring#) arc_stroke#(ring#, "#2ecc71") arc_strokethickness#(ring#, 12) arc_strokecap#(ring#, 1) arc_angles#(ring#, 270, 270) let lblPct# = label#(frm#, "0%") label_bounds#(lblPct#, 100, 110, 100, 30) label_textalign#(lblPct#, 0) label_fontsize#(lblPct#, 22) let btnAdd# = button#(frm#, "+10%") button_bounds#(btnAdd#, 50, 270, 90, 35) button_onclick#(btnAdd#, "OnAdd") let btnReset# = button#(frm#, "Reset") button_bounds#(btnReset#, 160, 270, 90, 35) button_onclick#(btnReset#, "OnReset") form_show(frm#) function OnAdd(sender#) progress = progress + 10 if progress > 100 then progress = 100 ' Map 0-100% to 270..630 (starting from top) arc_endangle#(ring#, 270 + progress * 3.6) label_text#(lblPct#, str$(progress) + "%") endfunction function OnReset(sender#) progress = 0 arc_endangle#(ring#, 270) label_text#(lblPct#, "0%") endfunction while form_visible(frm#) = 1 processmessages() end while
Speedometer
let frm# = form#("Speedometer", 320, 300) form_position#(frm#, 4) let speed = 0 ' Background gauge arc (270 degrees, bottom-open) let bgGauge# = arc#(frm#, 35, 30, 250, 250) arc_fillnone#(bgGauge#) arc_stroke#(bgGauge#, "#ddd") arc_strokethickness#(bgGauge#, 16) arc_angles#(bgGauge#, 135, 405) ' Speed arc let speedArc# = arc#(frm#, 35, 30, 250, 250) arc_fillnone#(speedArc#) arc_stroke#(speedArc#, "#27ae60") arc_strokethickness#(speedArc#, 16) arc_strokecap#(speedArc#, 1) arc_angles#(speedArc#, 135, 135) let lblSpeed# = label#(frm#, "0") label_bounds#(lblSpeed#, 110, 120, 100, 40) label_textalign#(lblSpeed#, 0) label_fontsize#(lblSpeed#, 32) let lblUnit# = label#(frm#, "km/h") label_bounds#(lblUnit#, 110, 160, 100, 20) label_textalign#(lblUnit#, 0) let btnUp# = button#(frm#, "Accelerate") button_bounds#(btnUp#, 30, 260, 120, 30) button_onclick#(btnUp#, "OnAccel") let btnDown# = button#(frm#, "Brake") button_bounds#(btnDown#, 170, 260, 120, 30) button_onclick#(btnDown#, "OnBrake") form_show(frm#) function OnAccel(sender#) local speed, endA speed = speed + 20 if speed > 200 then speed = 200 ' Map 0-200 to 135..405 (270 degree range) let endA = 135 + speed / 200 * 270 arc_endangle#(speedArc#, endA) label_text#(lblSpeed#, str$(speed)) ' Color: green -> yellow -> red if speed < 80 then arc_stroke#(speedArc#, "#27ae60") else if speed < 140 then arc_stroke#(speedArc#, "#f39c12") else arc_stroke#(speedArc#, "#e74c3c") endif endfunction function OnBrake(sender#) local speed, endA speed = speed - 20 if speed < 0 then speed = 0 let endA = 135 + speed / 200 * 270 arc_endangle#(speedArc#, endA) label_text#(lblSpeed#, str$(speed)) if speed < 80 then arc_stroke#(speedArc#, "#27ae60") else if speed < 140 then arc_stroke#(speedArc#, "#f39c12") else arc_stroke#(speedArc#, "#e74c3c") endif endfunction while form_visible(frm#) = 1 processmessages() end while
Best Practices
| Practice | Why |
|---|---|
Use arc_fillnone# + thick stroke for progress rings | Creates the modern circular progress indicator look |
Use arc_strokecap#(arc#, 1) for round ends | Much better visual on thick stroke-only arcs |
Use arc_angles# to set both angles at once | More efficient than two separate calls |
| Start gauge arcs at 135° or 180° | 135°–405° = 270° bottom-open gauge; 180°–360° = top semi-circle |
Set hittest = 1 for interactive arcs | Required for mouse events to fire |
| Use equal width/height for circular arcs | Different dimensions create elliptical arcs |
| Layer background + foreground arcs | Stack a gray background arc under a colored progress arc |
Map percentage to angle: start + pct * span / 100 | Standard formula for progress indicators |
Quick Reference
| Function | Signature | Description |
|---|---|---|
arc_error / errormsg$ / strerror$ / clearerror | various | Error handling (4) |
arc#(parent#[, w, h] | [, x, y, w, h]) | various | Create (3 overloads) |
arc_free(arc#) | arc_free@# | Destroy |
arc_startangle / endangle / angles# | various | Arc angles (5) |
arc_fill$ / fill# / fillnone# | various | Fill (3) |
arc_stroke$ / stroke# / strokenone# / strokethickness / strokedash / strokecap / strokejoin | various | Stroke (11) |
arc_x/y/width/height (get/set) / bounds# / move# / size# | various | Position & size (14) |
arc_align / margin# / margins# / margin[left/top/right/bottom] | various | Alignment & margins (12) |
arc_visible / enabled / opacity / hittest | various | Visibility & state (8) |
arc_tag / rotation / parent# / bringtofront# / sendtoback# / invalidate# | various | Tag, rotation & parent (8) |
arc_onclick/ondblclick/onmousedown/up/move/enter/leave/onmousewheel/onresize | various | Events set+get (18) |
arc_clearcallbacks# | arc_clearcallbacks#@# | Disconnect all events |
86 functions. Part of the Plan9Basic GUI shape library system.