############################################################################ # # File: gpxop.icn # # Subject: Procedures for graphics operations # # Author: Gregg M. Townsend # # Date: May 26, 1999 # ############################################################################ # # This file is in the public domain. # ############################################################################ # # This file contains some graphics procedures. # # LeftString(x, y, s) draws a string left-aligned at (x, y). # # CenterString(x, y, s) draws a string centered at (x, y). # # RightString(x, y, s) draws a string right-aligned at (x, y). # # ClearOutline(x, y, w, h) draws a rectangle, erasing its interior. # # Translate(dx, dy, w, h) moves the window origin and optionally # sets the clipping region. # # Zoom(x1, y1, w1, h1, x2, y2, w2, h2) # copies and distorts a rectangle. # # Capture(p, x, y, w, h) converts a window area to an image string. # # Sweep() lets the user select a rectangular area. # ############################################################################ # # LeftString(x, y, s), CenterString(x, y, s), and RightString(x, y, s) # draw a string centered vertically about y and left-justified, # centered, or right-justified about x. # # ClearOutline(x, y, w, h) draws a rectangle in the foreground color # and fills it with the background color. # # Translate(dx, dy, w, h) adjusts a window's dx and dy attributes by # the values given. Note that the resulting attribute values are the # sums of the existing values with the parameters, so that successive # translations accumulate. If w and h are supplied, the clipping # region is set to a rectangle of size (w, h) at the new origin. # # Zoom(x1, y1, w1, h1, x2, y2, w2, h2) is a distorting variation of # CopyArea that can be used to shrink or enlarge a rectangular area. # Zero, one, or two window arguments can be supplied. Rectangle 1 is # copied to fill rectangle 2 using simple pixel sampling and replication. # The rectangles can overlap. The usual defaults apply for both rectangles. # # Sweep() lets the user select a rectangular area using the mouse. # Called when a mouse button is pressed, Sweep handles all subsequent # events until a mouse button is released. As the mouse moves, a # reverse-mode outline rectangle indicates the selected area. The # pixels underneath the rectangle outline are considered part of this # rectangle, implying a minimum width/height of 1, and the rectangle # is clipped to the window boundary. Sweep returns a list of four # integers [x,y,w,h] giving the rectangle bounds in canonical form # (w and h always positive). Note that w and h give the width as # measured in FillRectangle terms (number of pixels included) rather # than DrawRectangle terms (coordinate difference). # # Capture(palette, x, y, w, h) converts a window region into an # image string using the specified palette, and returns the string. # # These procedures all accept an optional initial window argument. # ############################################################################ # # Links: gpxlib # ############################################################################ # # Requires: Version 9 graphics # ############################################################################ link gpxlib # LeftString(x, y, s) -- draw string left-justified at (x,y). procedure LeftString(win, x, y, s) #: draw left-justified string static type initial type := proc("type", 0) # protect attractive name if type(win) ~== "window" then { win :=: x :=: y :=: s win := &window } y +:= (WAttrib(win, "ascent") - WAttrib(win, "descent")) / 2 + 1 return DrawString(win, x, y, s) end # CenterString(x, y, s) -- draw string centered about (x,y). procedure CenterString(win, x, y, s) #: draw centered string static type initial type := proc("type", 0) # protect attractive name if type(win) ~== "window" then { win :=: x :=: y :=: s win := &window } x -:= TextWidth(win, s) / 2 y +:= (WAttrib(win, "ascent") - WAttrib(win, "descent")) / 2 + 1 return DrawString(win, x, y, s) end # RightString(x, y, s) -- draw string right-justified at (x,y). procedure RightString(win, x, y, s) #: draw right-justified string static type initial type := proc("type", 0) # protect attractive name if type(win) ~== "window" then { win :=: x :=: y :=: s win := &window } x -:= TextWidth(win, s) y +:= (WAttrib(win, "ascent") - WAttrib(win, "descent")) / 2 + 1 return DrawString(win, x, y, s) end # ClearOutline(x, y, w, h) -- draw rectangle and fill background. procedure ClearOutline(win, x, y, w, h) #: draw and clear rectangle static type initial type := proc("type", 0) # protect attractive name if type(win) ~== "window" then { win :=: x :=: y :=: w :=: h win := &window } /x := -WAttrib(win, "dx") /y := -WAttrib(win, "dy") /w := WAttrib(win, "width") - (x + WAttrib(win, "dx")) /h := WAttrib(win, "height") - (y + WAttrib(win, "dy")) if w < 0 then x -:= (w := -w) if h < 0 then y -:= (h := -h) DrawRectangle(win, x, y, w, h) EraseArea(win, x+1, y+1, w-1, h-1) return win end # Translate(dx, dy, w, h) -- add translation and possibly clipping. procedure Translate(win, dx, dy, w, h) #: add translation static type initial type := proc("type", 0) # protect attractive name if type(win) ~== "window" then { win :=: dx :=: dy :=: w :=: h win := &window } WAttrib(win, "dx=" || WAttrib(win,"dx")+dx, "dy=" || WAttrib(win,"dy")+dy) Clip(win, 0, 0, \w, \h) return win end # Sweep() -- sweep out area with mouse, return bounds procedure Sweep(win) #: sweep area with mouse local x, y, w, h, wmin, wmax, hmin, hmax /win := &window win := Clone(win, "drawop=reverse") x := &x # set initial rect bounds y := &y w := h := 0 wmin := -WAttrib(win, "dx") - x # calc coordinate limits hmin := -WAttrib(win, "dy") - y wmax := wmin + WAttrib(win, "width") - 1 hmax := hmin + WAttrib(win, "height") - 1 DrawRectangle(win, x, y, w, h) # draw initial bounding rect until Event(win) === (&lrelease | &mrelease | &rrelease) do { DrawRectangle(win, x, y, w, h) # erase old bounds w := &x - x # calc new width & height h := &y - y w <:= wmin # clip to stay on window w >:= wmax h <:= hmin h >:= hmax DrawRectangle(win, x, y, w, h) # draw new bounds } DrawRectangle(win, x, y, w, h) # erase bounding rectangle if w < 0 then x -:= (w := -w) # ensure nonnegative sizes if h < 0 then y -:= (h := -h) Uncouple(win) return [x, y, w + 1, h + 1] # return FillRectangle bounds end # Zoom(win1, win2, x1, y1, w1, h1, x2, y2, w2, h2) -- copy and distort. procedure Zoom(args[]) #: zoom image local win1, x1, y1, w1, h1 local win2, x2, y2, w2, h2 local x, y, scr static type initial type := proc("type", 0) # protect attractive name if type(args[1]) == "window" then win1 := get(args) else win1 := \&window | runerr(140, &window) if type(args[1]) == "window" then win2 := get(args) else win2 := win1 x1 := \get(args) | -WAttrib(win1, "dx") y1 := \get(args) | -WAttrib(win1, "dy") w1 := \get(args) | WAttrib(win1, "width") - (x1 + WAttrib(win1, "dx")) h1 := \get(args) | WAttrib(win1, "height") - (y1 + WAttrib(win1, "dy")) if w1 < 0 then x1 -:= (w1 := -w1) if h1 < 0 then y1 -:= (h1 := -h1) x2 := \get(args) | -WAttrib(win2, "dx") y2 := \get(args) | -WAttrib(win2, "dy") w2 := \get(args) | WAttrib(win2, "width") - (x2 + WAttrib(win2, "dx")) h2 := \get(args) | WAttrib(win2, "height") - (y2 + WAttrib(win2, "dy")) if w2 < 0 then x2 -:= (w2 := -w2) if h2 < 0 then y2 -:= (h2 := -h2) if w1 = 0 | w2 = 0 | h1 = 0 | h2 = 0 then return scr := ScratchCanvas(win2, w2, h1, "__Zoom__") | fail every x := 0 to w2 - 1 do CopyArea(win1, scr, x1 + w1 * ((x + 0.5) / w2), y1, 1, h1, x, 0) every y := 0 to h2 - 1 do CopyArea(scr, win2, 0, h1 * ((y + 0.5) / h2), w2, 1, x2, y2 + y) EraseArea(scr) # release colors return win1 end # Capture(win, pal, x, y, w, h) -- capture screen region as image string $define CaptureChunk 100 procedure Capture(win, pal, x, y, w, h) #: capture image as string local a, c, k, s, t, cmap static type initial type := proc("type", 0) # protect attractive name if type(win) ~== "window" then { win :=: pal :=: x :=: y :=: w :=: h win := \&window | runerr(140, &window) } /pal := "c1" /x := -WAttrib(win, "dx") /y := -WAttrib(win, "dy") /w := WAttrib(win, "width") - (x + WAttrib(win, "dx")) /h := WAttrib(win, "height") - (y + WAttrib(win, "dy")) if w < 0 then x -:= (w := -w) if h < 0 then y -:= (h := -h) PaletteChars(win, pal) | runerr(205, pal) cmap := table() # accumulate the image in chunks and then concatenate # (much faster than concatenating single chars on a very long string) s := "" a := [] every k := Pixel(win, x, y, w, h) do { c := \cmap[k] | (cmap[k] := PaletteKey(win, pal, k)) if *(s ||:= c) >= CaptureChunk then { put(a, s) s := "" } } put(a, s) s := w || "," || pal || "," while s ||:= get(a) return s end