Graphics

_images/unicon.png

Index Unicon

Unicon graphics

Unicon has graphics built in, well optionally built in, if the operating system supports X11, Win32 and/or OpenGL.

In the case of Unicon, graphics doesn’t just mean colours drawn on a canvas. Unicon includes an entire Graphical User Interface engine as well. Graphics come in 2D and 3D forms.

That means you can draw, and you can work with widgets and event driven programming without changing language or tool.

Much of the callback management normally associated with event driven programming is handled by Unicon for many of the graphic operations. The design of the graphics features of Unicon allow for both procedural and event programming in a seamless way. Using graphics does not dictate an event driven only style of programming in Unicon.


Colours

Unicon uses a pretty nifty colour naming system, as English phrases.

There are base colour names, with attributes for lightness, saturation and transparency levels.

colour := "medium strong bluish green"

Is parsed down to an RGBA (Red Green Blue Alpha) colour value. If the phrase is not understood, Unicon passes the name down to the operating system for another round of lookup. For X11 that means all the Xorg colour names are also valid.

Jafar Al-Gharaibeh was nice enough to extract the pertinent bits from unicon/src/rwindow.r

static colrname colortable[] = {     /* known colors */
   /* color       ish-form     hue  lgt  sat */
   { "black",    "blackish",     0,   0,   0 },
   { "blue",     "bluish",     240,  50, 100 },
   { "brown",    "brownish",    30,  25, 100 },
   { "cyan",     "cyanish",    180,  50, 100 },
   { "gray",     "grayish",      0,  50,   0 },
   { "green",    "greenish",   120,  50, 100 },
   { "grey",     "greyish",      0,  50,   0 },
   { "magenta",  "magentaish", 300,  50, 100 },
   { "orange",   "orangish",    15,  50, 100 },
   { "pink",     "pinkish",    345,  75, 100 },
   { "purple",   "purplish",   270,  50, 100 },
   { "red",      "reddish",      0,  50, 100 },
   { "violet",   "violetish",  270,  75, 100 },
   { "white",    "whitish",      0, 100,   0 },
   { "yellow",   "yellowish",   60,  50, 100 },
   };

static colrmod lighttable[] = {         /* lightness modifiers */
   { "dark",       0 },
   { "deep",       0 },     /* = very dark (see code) */
   { "light",    100 },
   { "medium",    50 },
   { "pale",     100 },     /* = very light (see code) */
   };

static colrmod sattable[] = {           /* saturation levels */
   { "moderate",  50 },
   { "strong",    75 },
   { "vivid",    100 },
   { "weak",      25 },
   };

static colrmod transptable[] = {        /* transparency levels */
   { "dull",  75 },             /* alias for subtranslucent */
   { "opaque",  100 },
   { "subtranslucent",  75 },
   { "subtransparent",  25 },
   { "translucent",  50 },
   { "transparent",  5 },
   };

Along with all those combinations, there are the system names, for things like Teal, and Cornflower, and Dark Khaki, when using X11.

https://en.wikipedia.org/wiki/X11_color_names

With a full list (many hundreds of named colours) in the source code at

https://cgit.freedesktop.org/xorg/xserver/tree/os/oscolor.c

If you look closely, there are more than double the 50 Shades of Grey.

Other specific graphic subsystems will have their own list of available names.

Unicon colour scheme

I’ve asked about an official Unicon project colour scheme, and I’m not sure if there has been an actual choice made. I’ve even asked to put unicon in the list of known colours, for potential branding purposes (and cool code samples). That may never happen though, but it’s worth asking.

From the project home page, from September 2016, the current guess is a form of orange (although the logo on that page uses a professionally laid out gradient, by Serendel Macphereson).

Best (bad)[1] guess (vivid orange) shown below.

#
# colour-sample.icn, a best (bad) guess at a Unicon project colour.
#
procedure main()
    &window := open("colour", "g", "size=70,45", "canvas=hidden")
    colour := "vivid orange"
    Fg(colour)
    FillRectangle(5, 5, 60, 35)
    WSync()
    WriteImage("../images/colour-sample.png")
    close(&window)
end

examples/colour-sample.icn

_images/colour-sample.png

images/colour-sample.png

prompt$ unicon -s colour-sample.icn -x
[1]Do not mistake this author for a graphic designer. There are few design skills in these fingers and little artistic flair hiding behind the eyes.

Drawing

Points, lines, rectangles, circles, spheres, torus and more, are all part and parcel of Unicon graphics. As is text. The write statement can write to a graphical window as readily as it can write to standard output and to files.


Events

Event driven programming was never easier or more adaptable than with Unicon.


Attributes

Unicon windows use a set of attributes to control look, feel and certain features of graphic handling. These attributes can be set during open and with the function WAttrib.

The src/runtime/rwindow.r source file lists the following supported attributes.

stringint attribs[] = {
   { 0,             NUMATTRIBS},
   {"ascent",       A_ASCENT},
   {"bg",           A_BG},
   {"buffer",       A_BUFFERMODE},
   {"canvas",       A_CANVAS},
   {"ceol",         A_CEOL},
   {"cliph",        A_CLIPH},
   {"clipw",        A_CLIPW},
   {"clipx",        A_CLIPX},
   {"clipy",        A_CLIPY},
   {"col",          A_COL},
   {"columns",      A_COLUMNS},
   {"cursor",       A_CURSOR},
   {"depth",        A_DEPTH},
   {"descent",      A_DESCENT},
   {"dim",          A_DIM},
   {"display",      A_DISPLAY},
   {"displayheight",    A_DISPLAYHEIGHT},
   {"displaywidth", A_DISPLAYWIDTH},
   {"drawop",       A_DRAWOP},
   {"dx",           A_DX},
   {"dy",           A_DY},
   {"echo",         A_ECHO},
   {"eye",          A_EYE},
   {"eyedir",       A_EYEDIR},
   {"eyepos",       A_EYEPOS},
   {"eyeup",        A_EYEUP},
   {"fg",           A_FG},
   {"fheight",      A_FHEIGHT},
   {"fillstyle",    A_FILLSTYLE},
   {"font",         A_FONT},
   {"fovangle",     A_FOV},
   {"fwidth",       A_FWIDTH},
   {"gamma",        A_GAMMA},
   {"geometry",     A_GEOMETRY},
   {"glrenderer",   A_GLRENDERER},
   {"glvendor",     A_GLVENDOR},
   {"glversion",    A_GLVERSION},
   {"height",       A_HEIGHT},
   {"iconic",       A_ICONIC},
   {"iconimage",    A_ICONIMAGE},
   {"iconlabel",    A_ICONLABEL},
   {"iconpos",      A_ICONPOS},
   {"image",        A_IMAGE},
   {"inputmask",    A_INPUTMASK},
   {"label",        A_LABEL},
   {"leading",      A_LEADING},
   {"light",        A_LIGHT},
   {"light0",       A_LIGHT0},
   {"light1",       A_LIGHT1},
   {"light2",       A_LIGHT2},
   {"light3",       A_LIGHT3},
   {"light4",       A_LIGHT4},
   {"light5",       A_LIGHT5},
   {"light6",       A_LIGHT6},
   {"light7",       A_LIGHT7},
   {"lines",        A_LINES},
   {"linestyle",    A_LINESTYLE},
   {"linewidth",    A_LINEWIDTH},
   {"meshmode",     A_MESHMODE},
   {"normode",      A_NORMODE},
   {"pattern",      A_PATTERN},
   {"pick",         A_PICK},
   {"pointer",      A_POINTER},
   {"pointercol",   A_POINTERCOL},
   {"pointerrow",   A_POINTERROW},
   {"pointerx",     A_POINTERX},
   {"pointery",     A_POINTERY},
   {"pos",          A_POS},
   {"posx",         A_POSX},
   {"posy",         A_POSY},
   {"resize",       A_RESIZE},
   {"reverse",      A_REVERSE},
   {"rgbmode",      A_RGBMODE},
   {"rings",        A_RINGS},
   {"row",          A_ROW},
   {"rows",         A_ROWS},
   {"selection",    A_SELECTION},
   {"size",         A_SIZE},
   {"slices",       A_SLICES},
   {"texcoord",     A_TEXCOORD},
   {"texmode",      A_TEXMODE},
   {"texture",      A_TEXTURE},
   {"titlebar",     A_TITLEBAR},
   {"visual",       A_VISUAL},
   {"width",        A_WIDTH},
   {"windowlabel",  A_WINDOWLABEL},
   {"x",            A_X},
   {"y",            A_Y},
};

Vidgets

For lack of a better term for Graphical User Interface (GUI) elements, Unicon includes a rich set of ready to go widgets. Some few built in, many as part of the IPL as vidgets and with the Unicon gui classes.

#
# vidget-button.icn, button demo
#
link evmux
link button
link enqueue

procedure main()
    &window := open("vidget", "g", "size=70,45", "canvas=hidden")
    b := button(&window, "Hello", hello, -3, 10, 10, 50, 25)
    WriteImage("../images/vidget-button.png")
    
    Enqueue(&window, &lpress, 11, 14, "", 2)
    Enqueue(&window, &lrelease, 11, 14, "", 3)
    evhandle(&window)
end

procedure hello()
    write("Hello, button")
end

examples/vidget-button.icn

_images/vidget-button.png

images/vidget-button.png

The sample simulates a mouse click, invoking the hello procedure.

prompt$ unicon -s vidget-button.icn -x
Hello, button

On names

Icon was developed long before modern graphical desktops were mainstream. There is still no ubiquitous term for graphic elements, but widget seems to be well understood. When Clint Jeffery was working with Ralph Griswold on the early graphics features of Icon, even the term widget was not in common use. The Icon (now Unicon) team went with a portmanteau of Visual Gadget, vidget. Things change, but history stays the same.

Unicon classes allow for a modernized approach to GUI development.


Unicon GUI

Todo

samples of Robert Parlett’s GUI classes


Plot coordinate pairs

A nice example of Unicon graphics can be found at Rosetta Code under the Plot coordinate pairs task. Duplicated here from a copy taken in August of 2016 with some slight modifications to captured image name, and not waiting for a mouse click to end the run.

#
# From http://rosettacode.org/wiki/Plot_coordinate_pairs#Icon_and_Unicon
#
link printf,numbers

procedure main()
x := [0., 1., 2., 3., 4., 5., 6., 7., 8., 9.]
y := [2.7, 2.8, 31.4, 38.1, 58.0, 76.2, 100.5, 130.0, 149.3, 180.0]
Plot(x,y,600,400)
end

$define POINTR 2                       # Point Radius
$define POINTC "red"                   # Point Colour
$define GRIDC  "grey"                  # grid colour
$define AXISC  "black"                 # axis/label colour
$define BORDER 60                      # per side border
$define TICKS  5.                      # grid ticks per axis
$define AXISFH 20                      # font height for axis labels

procedure Plot(x,y,cw,ch)

   /cw := 700                           # default dimensions
   /ch := 400
   uw := cw-BORDER*2                    # usable dimensions
   uh := ch-BORDER*2

   wparms  := ["Plot","g", "canvas=hidden",
               sprintf("size=%d,%d",cw,ch),
               "bg=white"]             # base window parms

   dx := sprintf("dx=%d",BORDER)       # grid origin
   dy := sprintf("dy=%d",BORDER)

   &window := open!wparms | stop("Unable to open window")
   X := scale(x,uw)                    # scale data to usable space
   Y := scale(y,uh,"invert")

   WAttrib(dx,dy)                      # set origin=grid & draw grid
   every x := (X.tickfrom to X.tickto by X.tick) * X.tickscale do {
      if x = 0 then Fg(AXISC) else Fg(GRIDC)
      DrawLine(x,Y.tickfrom*Y.tickscale,x,Y.tickto*Y.tickscale)
      }
   every y := (Y.tickfrom to Y.tickto by Y.tick) * Y.tickscale do {
      if y = uh then Fg(AXISC) else Fg(GRIDC)
      DrawLine(X.tickfrom*X.tickscale,y,X.tickto*X.tickscale,y)
      }

   Fg(POINTC)                          # draw data points ....
   every i := 1 to *X.scaled do 
      FillCircle(X.scaled[i],Y.scaled[i],POINTR) 

   Fg(AXISC)                           # label grid
   WAttrib(dx,"dy=0")                  # label X axis
   Font(sprintf("Helvetica,%d",AXISFH))
   ytxt := ch-BORDER+1+(WAttrib("ascent") - WAttrib("descent"))/2

   every x := X.tickscale * (xv := X.tickfrom to X.tickto by X.tick) do 
      DrawString(x - TextWidth(xv)/2, ytxt + integer(AXISFH*1.5),xv)

   WAttrib("dx=0",dy)                  # label Y axis
   every y := Y.tickscale * (yv := Y.tickfrom to Y.tickto by Y.tick) do
      DrawString(BORDER/2 - TextWidth(yv)/2, ytxt - BORDER - y,yv)

   WriteImage("../images/PlotPairs.png")         # save image

   WAttrib("dx=0","dy=0")              # close off nicely
   Font("Helvetica,10")
   #DrawString(10,ch-5,"click to exit")
   #until Event() == &lpress            # wait for left mouse button
   close(&window)
end

record scaledata(low,high,range,pix,raw,scaled,tick,tickfrom,tickto,tickscale)

procedure scale(data,pix,opts[])
   P := scaledata( pmin := min!data, pmax := max!data,
                   prange := real(pmax-pmin), pix,
                   data,q :=[])

   /ticks := TICKS
   P.tick := ceil(prange/(10^(k:=floor(log(prange,10))))*(10^k)/ticks)
   P.tickfrom  := P.tick*floor(pmin/P.tick)
   P.tickto    := P.tick*ceil(pmax/P.tick)
   P.tickscale := real(pix)/(P.tickto-P.tickfrom)
   every put(q,integer((!data-P.tickfrom)*P.tickscale))
   if !opts == "invert" then           # invert is for y
      every q[i := 1 to *q] := pix - q[i]
   return P
end

examples/plotpairs.icn

A nice feature of Unicon is the WriteImage graphics function. It saves a canvas image in GIF, JPG, BMP or PNG format (depending on given filename extension, including system specific types like XBM, XPM). That handy function is used to generate PlotPairs.png (and most of the other images) during builds of this documentation.

prompt$ unicon -s plotpairs.icn -x
_images/PlotPairs.png

images/PlotPairs.png


Index | Previous: Objects | Next: Database