############################################################################
#
#	File:     colrbook.icn
#
#	Subject:  Program to show the named colors
#
#	Author:   Gregg M. Townsend
#
#	Date:     December 1, 1997
#
############################################################################
#
#   This file is in the public domain.
#
############################################################################
#
#     colrbook is a mouse-driven program for choosing named colors.
#  Along the left are 24 equally spaced hues plus black, gray, white,
#  brown, violet, and pink.  Click on any of these to see the twenty
#  colors that are possible by adding lightness and saturation
#  modifiers to the particular hue.
#
############################################################################
#
#  Requires:  Version 9 graphics
#
############################################################################
#
#  Links: button, evmux, graphics
#
############################################################################

link button
link evmux
link graphics

$define BevelWidth 2
$define WindowMargin 10

$define HEADER 20	# height of header area (not incl. margin)
$define FOOTER 20	# height of footer area (not incl. margin)

$define TSIZ 12		# hue triangle size
$define HUEW 20		# hue width
$define HGAP 1		# hue gap

$define LEFT (m+TSIZ+HUEW+labw)	# total space to left of grid and its margin


global cwin, huelist, sats, lgts, colrs, fillargs
global labw, leftx, w, h, m

procedure main(args)
   local x, y, dx, dy, cw, ch
   local i, j, ij, hue, r

   lgts := ["pale", "light", "medium", "dark", "deep"]
   sats := ["weak", "moderate", "strong", "vivid"]
   colrs := table()
   fillargs := table()

   Window("size=500,350", "font=Helvetica,bold,12", args)
   cwin := Clone()
   m := WindowMargin
   w := WAttrib("width") - 2 * m
   h := WAttrib("height") - 2 * m
   labw := TextWidth("medium") + 3 * m	# label area width
   leftx := m + TSIZ + HUEW + labw	# space to left of grid and its margin

   dx := (w - leftx + m) / *sats
   dy := (h - HEADER - FOOTER + m) / *lgts
   cw := dx - m
   ch := dy - m

   inithues()

   every i := 1 to *sats do
      every j := 1 to *lgts do {
         ij := i || j
         x := leftx + dx * i - cw
         y := HEADER + dy * j - ch
         BevelRectangle(x, y, cw, ch, -BevelWidth)
         fillargs[ij] := [cwin, x + BevelWidth, y + BevelWidth,
            cw - 2 * BevelWidth, ch - 2 * BevelWidth]
         if Fg(cwin, colrs[ij] := NewColor("gray")) then	# may fail
            FillRectangle ! fillargs[ij]
         }
   every i := 1 to *sats do {
      GrooveRectangle(leftx + m + dx * (i - 1), m / 2, dx - m, HEADER)
      CenterString(leftx + dx * i - cw / 2, m / 2 + HEADER / 2, sats[i])
      }
   every j := 1 to *lgts do {
      GrooveRectangle(leftx, HEADER + dy*j - ch/2 - HEADER/2, -labw + m, HEADER)
      RightString(leftx - m, HEADER + dy*j - ch/2, lgts[j])
      }

   # define sensors
   button(&window, "QUIT", argless, exit, m+TSIZ+HUEW+m, m, labw-2*m, HEADER)
   sensor(&window, &lpress, hueclick, r, m, m, TSIZ + HUEW, h)
   quitsensor(&window)

   # initialize to "gray" hues using an artificial event
   Enqueue(&lrelease)
   hueclick(&window, 0, m, m + integer((*huelist - 4.5) / *huelist * h))

   # enter event loop
   evmux(&window)
end

procedure hueclick(win, arg, x, y)
   local hue, e, n, i, j

   e := &ldrag
   while e ~=== &lrelease do {
      if e === &ldrag then {
         n := (*huelist * (y - m + HGAP / 2)) / h + 1
         if 0 < n <= *huelist then {
            hue := huelist[n]
            EraseArea(m, m - TSIZ / 2, TSIZ + 1, h + TSIZ)
            y := m - HGAP + integer((n - 0.5) * (h + HGAP) / *huelist)
            BevelTriangle(m + TSIZ / 2, y, TSIZ / 2, "e")
            setcolor(hue)
            EraseArea(LEFT, m + h - FOOTER, w, FOOTER + m)
            CenterString(LEFT + (w - LEFT + m)/2, m + h + m/2 - FOOTER/2, hue)
            }
         }
      e := Event(win)
      y := &y
      }
   return
end

procedure setcolor(hue)
   local i, j, ij, prefix
   static prev

   every i := 1 to *sats do
      every j := 1 to *lgts do {
         ij := i || j
         prefix := lgts[j] || " " || sats[i] || " "
         if not Color(cwin, \colrs[ij], prefix || hue) then {
            # no mutable color was allocated;
            # free old static color, preserving grays (used for decoration)
            # also preserving labeling colors ("medium vivid")
            if \prev ~== "black" & \prev ~== "gray" & \prev ~== "white" then
               FreeColor(cwin, ("medium vivid " ~== prefix) || \prev)
            Fg(cwin, prefix || hue)
            FillRectangle ! fillargs[ij]
            }
         }

   prev := hue
   return
end

procedure inithues()
   local i, y1, y2, dy, win

   huelist := [
      "red", "orange", "red-yellow", "reddish yellow",
      "yellow", "greenish yellow", "yellow-green", "yellowish green",
      "green", "cyanish green", "cyan-green", "greenish cyan",
      "cyan", "bluish cyan", "blue-cyan", "cyanish blue",
      "blue", "blue-purple", "purple", "purple-magenta",
      "magenta", "reddish magenta", "magenta-red", "magentaish red",
      "black", "gray", "white",
      "brown", "violet", "pink"
      ]
   dy := real(h + HGAP) / *huelist
   win := Clone(&window)
   every i := 1 to *huelist do {
      y1 := integer(dy * (i - 1))
      y2 := integer(dy * i)
      Fg(win, huelist[i])
      FillRectangle(win, m + TSIZ + 1, m + y1, HUEW - 1, y2 - y1 - HGAP)
      }
   Uncouple(win)
   return
end
