summaryrefslogtreecommitdiff
path: root/ipl/gprogs/kaleido.icn
diff options
context:
space:
mode:
Diffstat (limited to 'ipl/gprogs/kaleido.icn')
-rw-r--r--ipl/gprogs/kaleido.icn337
1 files changed, 337 insertions, 0 deletions
diff --git a/ipl/gprogs/kaleido.icn b/ipl/gprogs/kaleido.icn
new file mode 100644
index 0000000..48f1364
--- /dev/null
+++ b/ipl/gprogs/kaleido.icn
@@ -0,0 +1,337 @@
+############################################################################
+#
+# File: kaleido.icn
+#
+# Subject: Program to produce kaleidoscopic display
+#
+# Author: Ralph E. Griswold
+#
+# Date: February 16, 1999
+#
+############################################################################
+#
+# This file is in the public domain.
+#
+############################################################################
+#
+# This program displays kaleidoscopic images. The controls on the
+# user interface are relatively intuitive -- trying them will give
+# a better idea of what's possible than a prose description here.
+#
+# This program is based on an earlier one by Steve Wampler, which in
+# turn was based on a C program by Lorraine Callahan.
+#
+############################################################################
+#
+# Requires: Version 9 graphics
+#
+############################################################################
+#
+# Links: interact, random, vsetup
+#
+############################################################################
+
+link interact
+link random
+link vsetup
+
+# Interface globals
+
+global vidgets # table of vidgets
+global root # root vidget
+global pause # pause vidget
+global size # size of view area (width & height)
+global half # half size of view area
+global pane # graphics context for viewing
+global colors # list of colors
+
+# Parameters that can be set from the interface
+
+global delay # delay between drawing circles
+global density # number of circles in steady state
+global draw_proc # drawing procedure
+global max_off # maximum offset of circle
+global min_off # minimum offset of circle
+global max_radius # maximum radius of circle
+global min_radius # minimum radius of circle
+global scale_radius # radius scale factor
+
+# State information
+
+global draw_list # list of pending drawing parameters
+global reset # nonnull when view area needs resetting
+
+# Record for circle data
+
+record circle(off1, off2, radius, color)
+
+$define DelayFactor 200
+$define DensityMax 100
+
+$define SliderMax 10.0 # shared knowledge
+$define SliderMin 1.0
+
+procedure main()
+
+ init()
+
+ kaleidoscope()
+
+end
+
+procedure init()
+ local s
+
+ randomize()
+
+ vidgets := ui()
+
+ root := vidgets["root"]
+ size := vidgets["region"].uw
+ if vidgets["region"].uh ~= size then stop("*** improper interface layout")
+
+ delay := 0.5
+ density := DensityMax / 2.0
+ max_radius := SliderMax # scaled later
+ min_radius := SliderMin
+ scale_radius := (size / 4) / SliderMax
+
+ draw_proc := FillCircle
+
+ colors := []
+ s := PaletteChars("c3") -- PaletteGrays("c3")
+ every put(colors, PaletteColor("c3", !s))
+
+ pause := vidgets["pause"]
+
+ VSetState(pause, 1)
+ VSetState(vidgets["density"], (density / DensityMax) * SliderMax)
+ VSetState(vidgets["delay"], delay)
+ VSetState(vidgets["min_radius"], min_radius * 2)
+ VSetState(vidgets["max_radius"], max_radius / 2)
+ VSetState(vidgets["shape"], "discs")
+
+# Get graphics context for drawing.
+
+ half := size / 2
+
+ pane := Clone("bg=black", "dx=" || (vidgets["region"].ux + half),
+ "dy=" || (vidgets["region"].uy + half), "drawop=reverse")
+ Clip(pane, -half, -half, size, size)
+
+ return
+
+end
+
+procedure kaleidoscope()
+
+ # Each time through this loop, the display is cleared and a
+ # new drawing is started.
+
+ repeat {
+
+ EraseArea(pane, -half, -half, size, size) # clear display
+ draw_list := [] # new drawing list
+ reset := &null
+
+ # In this loop a new circle is drawn and an old one erased, once the
+ # specified density has been reached. This maintains a steady state.
+
+ repeat {
+ while (*Pending() > 0) | \VGetState(pause) do {
+ ProcessEvent(root, , shortcuts)
+ if \reset then break break next
+ }
+ putcircle()
+ WDelay(delay)
+
+ # Don't start clearing circles until the specified density has
+ # reached. (The drawing list has four elements for each circle.)
+
+ if *draw_list > density then clrcircle()
+ }
+ }
+
+end
+
+procedure putcircle()
+ local off1, off2, radius, color
+
+ # get a random center point and radius
+
+ off1 := ?size % half
+ off2 := ?size % half
+ radius := ((max_radius - min_radius) * ?0 + min_radius) * scale_radius
+ radius <:= 1 # don't let them vanish
+
+ color := ?colors
+
+ put(draw_list, circle(off1, off2, radius, color))
+
+ outcircle(off1, off2, radius, color)
+
+ return
+
+end
+
+procedure clrcircle()
+ local circle
+
+ circle := get(draw_list)
+
+ outcircle(
+ circle.off1,
+ circle.off2,
+ circle.radius,
+ circle.color
+ )
+
+ return
+
+end
+
+procedure outcircle(off1, off2, radius, color)
+
+ Fg(pane, color)
+
+ # Draw in symmetric positions.
+
+ draw_proc(pane, off1, off2, radius)
+ draw_proc(pane, off1, -off2, radius)
+ draw_proc(pane, -off1, off2, radius)
+ draw_proc(pane, -off1,-off2, radius)
+ draw_proc(pane, off2, off1, radius)
+ draw_proc(pane, off2, -off1, radius)
+ draw_proc(pane, -off2, off1, radius)
+ draw_proc(pane, -off2,-off1, radius)
+
+ return
+
+end
+
+procedure density_cb(vidget, value)
+
+ density := (value / SliderMax) * DensityMax
+ density <:= 1
+
+ reset := 1
+
+end
+
+procedure delay_cb(vidget, value)
+
+ delay := value * DelayFactor
+
+ return
+
+end
+
+procedure file_cb(vidget, value)
+
+ case value[1] of {
+ "snapshot @S": snapshot(pane, -half, -half, size, size)
+ "quit @Q": exit()
+ }
+
+ return
+
+end
+
+procedure max_radius_cb(vidget, value)
+
+ max_radius := value
+
+ if max_radius < min_radius then { # if max < min lower min
+ min_radius := max_radius
+ VSetState(vidgets["min_radius"], min_radius)
+ }
+
+ reset := 1
+
+ return
+
+end
+
+procedure min_radius_cb(vidget, value)
+
+ min_radius := value
+
+ if min_radius > max_radius then { # if min > max raise max
+ max_radius := min_radius
+ VSetState(vidgets["max_radius"], max_radius)
+ }
+
+ reset := 1
+
+ return
+
+end
+
+procedure reset_cb(vidget, value)
+
+ reset := 1
+
+ return
+
+end
+
+procedure shape_cb(vidget, value)
+
+ draw_proc := case value of {
+ "discs": FillCircle
+ "rings": DrawCircle
+ }
+
+ reset := 1
+
+ return
+
+end
+
+procedure shortcuts(e)
+
+ if &meta then
+ case map(e) of { # fold case
+ "q": exit()
+ "s": snapshot(pane, -half, -half, size, size)
+ }
+
+ return
+
+end
+
+#===<<vib:begin>>=== modify using vib; do not remove this marker line
+procedure ui_atts()
+ return ["size=600,455", "bg=pale gray", "label=kaleido"]
+end
+
+procedure ui(win, cbk)
+return vsetup(win, cbk,
+ [":Sizer:::0,0,600,455:kaleido",],
+ ["delay:Slider:h:1:42,120,100,15:1.0,0.0,0.5",delay_cb],
+ ["density:Slider:h:1:42,180,100,15:0.0,10.0,10.0",density_cb],
+ ["file:Menu:pull::3,1,36,21:File",file_cb,
+ ["snapshot @S","quit @Q"]],
+ ["label01:Label:::13,180,21,13:min",],
+ ["label02:Label:::152,180,21,13:max",],
+ ["label03:Label:::13,240,21,13:min",],
+ ["label04:Label:::152,240,21,13:max",],
+ ["label05:Label:::13,300,21,13:min",],
+ ["label06:Label:::152,300,21,13:max",],
+ ["label07:Label:::7,120,28,13:slow",],
+ ["label08:Label:::151,120,28,13:fast",],
+ ["lbl_density:Label:::67,160,49,13:density",],
+ ["lbl_max_radius:Label:::43,280,98,13:maximum radius",],
+ ["lbl_min_radius:Label:::44,220,98,13:minimum radius",],
+ ["lbl_speed:Label:::74,100,35,13:speed",],
+ ["line:Line:::0,22,600,22:",],
+ ["max_radius:Slider:h:1:42,300,100,15:0.0,10.0,10.0",max_radius_cb],
+ ["min_radius:Slider:h:1:42,240,100,15:0.0,10.0,1.0",min_radius_cb],
+ ["pause:Button:regular:1:33,55,45,20:pause",],
+ ["reset:Button:regular::111,55,45,20:reset",reset_cb],
+ ["shape:Choice::2:66,359,64,42:",shape_cb,
+ ["discs","rings"]],
+ ["region:Rect:raised::187,40,400,400:",],
+ )
+end
+#===<<vib:end>>=== end of section maintained by vib