summaryrefslogtreecommitdiff
path: root/ipl/gprogs/cameleon.icn
blob: e616d207feb5a73046f10e6fae022f88ff2d4e99 (plain)
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
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
############################################################################
#
#	File:     cameleon.icn
#
#	Subject:  Program to allow user to change colors in an image
#
#	Author:   Ralph E. Griswold
#
#	Date:     May 19, 1999
#
############################################################################
#
#  This file is in the public domain.
#
############################################################################
#
#  This application allows the user to change selected color in an image.
#  The colors are displayed in a palette on the application window.
#  Clicking on one brings up a color dialog in which the color can be
#  adjusted.
#
#  The keyboard shortcuts are:
#
#	@O	open image			File menu
#	@Q	quit the application		File menu
#	@R	revert to original colors	Colors menu  
#	@S	save image			File menu
#
#  Note:  "cameleon" is a variant spelling of "chameleon".
#
############################################################################
#
#  Requires:  Version 9 graphics and mutable colors.
#
############################################################################
#
#  Links:  graphics, interact, numbers, tables
#
############################################################################

link graphics
link interact
link numbers
link tables

global cellsize		# size of palette cell
global colors		# mutable color list
global count		# table of pixel counts
global image_window	# window for user image
global mutant		# image with mutable colors
global orig_colors	# list of original colors
global palette		# color selection palette
global panel		# palette window
global pixels		# number of pixels in image window
global x_pos		# target location for mutant window
global y_pos


$define ColorRows	 8	# number of palette rows
$define ColorCols	16	# number of palette columns

procedure main()
   local atts, vidgets

   atts := ui_atts()
   put(atts, "posx=0", "posy=0")

   (WOpen ! atts) | stop("*** cannot open application window")

   vidgets := ui()

   x_pos := WAttrib("width") + 3 * WAttrib("posx")
   y_pos := WAttrib("posy")

   palette := vidgets["palette"]

   cellsize := palette.uw / ColorCols

   panel := Clone("bg=black", "dx=" || palette.ux, "dy=" || palette.uy)
   Clip(panel, 0, 0,  palette.uw, palette.uh)

   clear_palette()

   GetEvents(vidgets["root"], , shortcuts)

end

#  Set up empty palette grid

procedure clear_palette()
   local x, y

   Fg(panel, "black")
   EraseArea(panel)
   WAttrib(panel, "fillstyle=textured")
   Pattern(panel, "checkers")
   Bg(panel, "very dark gray")

   every x := 1 + (0 to ColorCols) * cellsize do
      every y := 1 + (0 to ColorRows) * cellsize do
         FillRectangle(panel, x, y, cellsize - 1, cellsize - 1)

   WAttrib(panel, "fillstyle=solid")
   Bg(panel, "black")

   return
 
end

# Handle File menu

procedure file_cb(vidget, value)

   case value[1] of {
      "open   @O"  :  image_open()
      "quit   @Q"  :  quit()
      "revert @R"  :  image_revert()
      "save   @S"  :  snapshot(mutant)
      }

   return

end

# Open new image

procedure image_open()
   local i, x, y

   WClose(\image_window)

   repeat {
      if OpenDialog("Open image:") == "Cancel" then fail
      image_window := WOpen("canvas=hidden", "image=" || dialog_value) | {
         Notice("Cannot open image.")
         next
         }
      break
      }

   mutate(image_window) | fail

   Raise()			# bring application window to front

   colors := vallist(copy(orig_colors))

   clear_palette()

   i := 0

   every y := 1 + (0 to ColorRows - 1) * cellsize do
      every x := 1 + (0 to ColorCols - 1) * cellsize do {
         Fg(panel, colors[i +:= 1]) | break break
         FillRectangle(panel, x, y, cellsize - 1, cellsize - 1)
         }

   return

end 

#  Save current image

procedure image_save()

   snapshot(\mutant)

   return

end

#  Restore original image colors

procedure image_revert()
   local old, color

   every old := key(orig_colors) do {
      color := orig_colors[old]
      Color(panel, color, old)
      }

   return

end

# Get mutable colors and window from image

procedure mutate()
   local c, width, height, n, x, y

   WClose(\mutant)

   orig_colors := table()
   count := table(0)

   width := WAttrib(image_window, "width")
   height := WAttrib(image_window, "height")

   pixels := width * height

   mutant := WOpen("width=" || width, "height=" || height,
      "posx=" || x_pos, "posy=" || y_pos) | {
         Notice("Cannot open image_window for mutant colors.")
         fail
         }

   every y := 0 to height - 1 do {
      x := 0
      every c := Pixel(image_window, 0, y, width, 1) do {
         if not(n := \orig_colors[c]) then {
            orig_colors[c] := n := NewColor(c) | {
               Notice("Cannot get mutable color.")
               WClose(mutant)
               fail
               }
            }
         count[n] +:= 1
         Fg(mutant, n)
         DrawPoint(mutant, x, y)
         x +:= 1
         }
      }

   return

end

# Handle callbacks on palette

procedure palette_cb(vidget, e, x, y)
   local color, new

   if e === (&lpress | &mpress | &rpress) then {
      color := Pixel(x, y, 1, 1)		# get pixel color
      if not integer(color) then fail		# not a mutable color
      new := Color(panel, color)		# get color specification
      if ColorDialog(
         "Adjust color (" || count[color] || " pixels, " ||
            frn((100.0 * count[color]) / pixels, , 2) || "%):",
          Color(panel, color),
          track,
          color
          ) == "Okay" then new := dialog_value
      Color(panel, color, new)
      Color(mutant, color, new)
      }

   return

end

#  Quit the application

procedure quit()

   snapshot(\mutant)

   exit()

end

#  Handle keyboard shortcuts

procedure shortcuts(e)

   if &meta then case(map(e)) of {
      "o"  :  image_open()
      "q"  :  quit()
      "r"  :  image_revert()
      "s"  :  image_save()
      }

   return

end

#  Track the color in the color dialog

procedure track(color, s)

   Color(panel, color, s)

   return

end

#===<<vib:begin>>===	modify using vib; do not remove this marker line
procedure ui_atts()
   return ["size=355,225", "bg=pale gray", "label=chameleon"]
end

procedure ui(win, cbk)
return vsetup(win, cbk,
   [":Sizer:::0,0,355,225:chameleon",],
   ["file:Menu:pull::1,0,36,21:File",file_cb,
      ["open   @O","save   @S","revert @R","quit   @Q"]],
   ["menubar:Line:::0,21,357,21:",],
   ["palette:Rect:invisible::19,41,320,160:",palette_cb],
   )
end
#===<<vib:end>>===	end of section maintained by vib