1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
|
############################################################################
#
# File: randweav.icn
#
# Subject: Program to create random weavable patterns
#
# Author: Gregg M. Townsend
#
# Date: April 6, 1999
#
############################################################################
#
# This file is in the public domain.
#
############################################################################
#
# Randweav is an interactive program for generating random
# weavable patterns. The top and left rows of the displayed
# pattern are a "key" to the vertical and horizontal threads
# of an imaginary loom. The colors of the other cells are chosen
# so that each matches either the vertical or horizontal thread
# with which it is aligned.
#
# The interactive controls are as follows:
#
# Colors Specifies the number of different colors from which
# the threads are selected.
#
# If "cycle warp" is checked, the vertical thread colors
# repeat regularly. If "cycle weft" is checked, the
# horizontal thread colors repeat regularly.
#
# RENDER When pressed, generates a new random pattern.
# Pressing the Enter key or space bar does the same thing.
#
# Side Specifies the number of threads along each side
# of the pattern. The pattern is always square.
#
# Bias Specifies as a percentage the probability that the
# vertical thread will determine the color of a pixel.
#
# If "perfect" is checked, vertical and horizontal
# threads alternate perfectly, ignoring the bias value.
#
# Save Brings up a dialog for saving the pattern as an image.
#
# Quit Exits the program.
#
# Note that the mouse must be over a numeric field to type in
# a new value.
#
############################################################################
#
# Requires: Version 9 graphics
#
############################################################################
#
# Links: random, vsetup
#
############################################################################
link random
link vsetup
global vidgets # table of vidgets
global root # root vidget
global region # pattern region
global hidwin # hidden window for saving to file
global allcolors # string of all palette colors
global maxsiz # maximum pattern size
global patsize # pattern size selected
$define PALETTE "c1" # color palette
$define PREFCOLORS "06NBCDFsHIJM?!" # preferred colors
procedure main(args)
randomize()
allcolors := PREFCOLORS || (PaletteChars(PALETTE) -- PREFCOLORS)
Window ! put(ui_atts(), args) # open window
vidgets := ui() # set up vidgets
root := vidgets["root"]
region := vidgets["region"]
VSetState(vidgets["vcyclic"], 1) # default "cycle warp" on
VSetState(vidgets["hcyclic"], 1) # default "cycle weft" on
hidwin := WOpen("canvas=hidden", # open hidden window
"width=" || region.uw, "height=" || region.uh)
maxsiz := region.uw # set maximum size
maxsiz >:= region.uh
render() # draw once without prompting
GetEvents(root, , all) # then wait for events
end
# all(a, x, y) -- process all events, checking for keyboard shortcuts
procedure all(a, x, y)
if a === !" \n\r" then render() # draw new pattern for SPACE, CR, LF
else if &meta then case a of {
!"qQ": exit() # exit for @Q
!"sS": save() # save image for @S
}
return
end
# render() -- draw a new pattern according to current parameters
procedure render()
local ncolors, bias
local s, x, y, w, h, z, k
static prevsize
ncolors := txtval("colors", 1, *allcolors) # retrieve "Colors" setting
patsize := txtval("side", 1, maxsiz) # retrieve "Side" setting
bias := txtval("bias", 0, 100) # retrieve "Bias" setting
k := (shuffle(PREFCOLORS) | allcolors)[1+:ncolors] # pick a color set
s := genpatt(patsize, k, bias / 100.0) # generate a pattern
DrawImage(hidwin, 0, 0, s) # draw on hidden win
z := maxsiz / patsize # calculate scaling
x := region.ux + (region.uw - z * patsize) / 2
y := region.uy + (region.uh - z * patsize) / 2
# copy to main window with enlargement
if prevsize ~===:= patsize then
EraseArea(region.ux, region.uy, region.uw, region.uh) # erase old pattern
Zoom(hidwin, &window, 0, 0, patsize, patsize, x, y, z * patsize, z * patsize)
return
end
# genpatt(size, colors, bias) -- generate a new pattern as DrawImage() string
procedure genpatt(size, colors, bias)
local warp, weft, perfect, s, x, y, w
# choose thread colors
warp := genthreads(size, colors, VGetState(vidgets["vcyclic"]))
weft := genthreads(size, colors, VGetState(vidgets["hcyclic"]))
# initialize output string (including first row)
s := size || "," || PALETTE || "," || warp
perfect := VGetState(vidgets["perfect"])
# fill in remaining rows
every y := 2 to size do {
w := ?weft[y] # get weft color
s ||:= w # put in first column
if \perfect then
every x := 2 to size do # fill the rest (perfect case)
s ||:= if ((x + y) % 2) = 0 then w else warp[x]
else
every x := 2 to size do # fill the rest (random case)
s ||:= if ?0 > bias then w else warp[x]
}
return s
end
# genthreads(n, colors, cyclic) -- generate a set of warp or weft threads
procedure genthreads(n, colors, cyclic)
local s
if \cyclic then
return repl(shuffle(colors), 1 + n / *colors)[1+:n]
s := ""
every 1 to n do s ||:= ?colors
return s
end
# txtval(s, min, max) -- get numeric value from named vidget and clamp to range
procedure txtval(s, min, max)
local v, n
v := vidgets[s] # find the vidget
VEvent(v, "\r", v.ax, v.ay) # set RETURN event to update state
n := integer(VGetState(v)) | min # retrieve int value, else use minimum
n <:= min # limit value by min and max
n >:= max
VSetState(v, n) # update vidget with validated value
return n # return value
end
# save() -- present dialog box and save pattern as image file
procedure save()
local g
g := WAttrib("gamma") # save old gamma value
WAttrib("gamma=1.0") # don't gamma-correct on write
repeat case OpenDialog("Save pattern as:") of {
"Cancel": {
WAttrib("gamma=" || g)
fail
}
"Okay": {
if WriteImage(hidwin, dialog_value, 0, 0, patsize, patsize) then
break
else
Notice("cannot write file:", dialog_value)
}
}
WAttrib("gamma=" || g) # restore gamma value
return
end
procedure quit()
exit()
end
#===<<vib:begin>>=== modify using vib; do not remove this marker line
procedure ui_atts()
return ["size=380,492", "bg=pale gray", "label=weaver"]
end
procedure ui(win, cbk)
return vsetup(win, cbk,
[":Sizer:::0,0,380,492:weaver",],
["bias:Text::3:285,37,87,19:Bias: \\=60",],
["colors:Text::3:10,9,87,19:Colors: \\=6",],
["hcyclic:Button:checkno:1:5,56,97,20:cycle weft",],
["perfect:Button:checkno:1:281,57,76,20:perfect",],
["quit:Button:regular::293,462,78,20:quit @Q",quit],
["render:Button:regular::159,24,72,36:RENDER",render],
["save:Button:regular::8,462,78,20:save @S",save],
["side:Text::3:285,8,87,19:Side: \\=90",],
["vcyclic:Button:checkno:1:5,36,97,17:cycle warp",],
["outline:Rect:sunken::153,18,84,48:",],
["region:Rect:grooved::8,84,364,364:",],
)
end
#===<<vib:end>>=== end of section maintained by vib
|