diff options
Diffstat (limited to 'ipl/gprogs/selectle.icn')
-rw-r--r-- | ipl/gprogs/selectle.icn | 571 |
1 files changed, 571 insertions, 0 deletions
diff --git a/ipl/gprogs/selectle.icn b/ipl/gprogs/selectle.icn new file mode 100644 index 0000000..594c393 --- /dev/null +++ b/ipl/gprogs/selectle.icn @@ -0,0 +1,571 @@ +############################################################################ +# +# File: selectle.icn +# +# Subject: Program to select tile from an image +# +# Author: Ralph E. Griswold +# +# Date: May 2, 2001 +# +############################################################################ +# +# This file is in the public domain. +# +############################################################################ +# +# This program is designed to assist in locating areas within an image +# that, when tiled, produce a desired effect. For example, a background +# may consist of a tiled image; this program can be used to find the +# smallest tile for the repeat (by "eye-balling"). +# +# Another interesting use of this program is to produce striped patterns by +# selecting a row or column of an image to get a tile that is one character +# wide. Sometimes a few rows or columns give an interesting "fabric" +# effect. +# +# The following features are provided through keyboard shortcuts, +# the File menu, and in some cases, on-board buttons: +# +# @D user-drawn selection rectangle +# @O open new source image +# @P pick a source image from GIF files in the current directory +# @Q quit application +# @S save current selection as an image +# @T tile selection into source image window +# +# Buttons provide for setting and adjusting the selection in various +# ways. +# +# In the drawing mode, the mouse can be used to make a selection by +# dragging from one corner to another. When the mouse is released, +# the action depends on the user keypress: +# +# "r" return the selection +# "n" try again +# "q" exit drawing mode +# +# Typing "q" is the only way to get out of the drawing mode. It can be +# done whether or not there is a selection. +# +# Notes: +# +# The selection starts as a single pixel in the upper-left corner. +# The repeat window can be resized by the user. +# +############################################################################ +# +# Features to add/improve: +# +# show current selection +# file-system navigation +# chained selection dialogs for large numbers of files +# *or* scrolling line dialog +# add flips, rotations, and other transformations (using external +# utilities) +# allow images of types other than GIF +# +# Bugs: +# width and height setting should take into account the current +# origin +# edit in system menu is bogus (bug is in interact.icn) +# +# +############################################################################ +# +# Requires: Version 9 graphics, UNIX (for "pick" feature) +# +############################################################################ +# +# Links: grecords, interact, io, select, tile +# +############################################################################ + +link grecords +link interact +link io +link select +link tile + +# To do: alphabetize the following globals + +global pattern # repeat window +global source # source window hidden +global screen # source window visible +global vidgets # table of interface vidgets +global root # root vidget +global controls + +global text # label with respect to which information is written + +global posx # x position relative to interface window +global posy # y position relative to repeat window +global wmax # maximum width of source image +global hmax # maximum height of source image + +global auto # auto-save toggle +global prefix # auto-save prefix +global count # auto-save count +global name # image name +global draw # draw vidget +global current # current selection + +$define PosX "posx=10" +$define PosY "posy=10" + +procedure main() + local atts + + atts := ui_atts() + + # The interface window is opened with a hidden canvas so that it + # can be made the active window later by making it visible. + + put(atts, "canvas=hidden", PosX, PosY) + + controls := (WOpen ! atts) | stop("*** cannot open window") + vidgets := ui() + + init() + + GetEvents(root, , shortcuts) + +end + +# Auto-save callback toggle. + +procedure auto_cb(vidget, value) + + auto := value + + if \auto then { + if OpenDialog("Specify prefix for auto-saving:") == "Cancel" then fail + prefix := dialog_value + count := -1 # initial count less 1 + } + + return + +end + +# Callback that handles all the buttons that change x, y, w, and h. + +procedure change_cb(vidget) + + # Cute code alert. The selected reversible assignment is performed + # and passed to check(). It checks the resulting selection rectangle + # and fails if it's not valid. That failure causes the reversible + # assignment to be undone and the expression fails, leaving the + # selection as it was. + + check( + case vidget.s of { + "h +": current.h <- current.h + 1 + "h -": current.h <- current.h - 1 + "w +": current.w <- current.w + 1 + "w -": current.w <- current.w - 1 + "w + h +": current.h <- current.h + 1 & current.w <- current.w + 1 + "w - h -": current.h <- current.h - 1 & current.w <- current.w - 1 + "h max": current.h <- hmax + "w max": current.w <- wmax + "w h max": current.h <- hmax & current.w <- wmax + "x +": current.x <- current.x + 1 + "x -": current.x <- current.x - 1 + "y +": current.y <- current.y + 1 + "y -": current.y <- current.y - 1 + "x + y +": current.x <- current.x + 1 & current.y <- current.y + 1 + "y - x -": current.y <- current.y - 1 & current.x <- current.x - 1 + "x 1/2": current.x <- wmax / 2 + "y 1/2": current.y <- hmax / 2 + "x y 1/2": current.x <- wmax / 2 & current.y <- hmax / 2 + } + ) | fail + + show() + + return + +end + +# Check validity of selection. + +procedure check() + + if (0 <= current.h <= hmax) & + (0 <= current.w <= wmax) & + (0 <= current.x <= hmax) & + (0 <= current.y <= wmax) + then return else { + Alert() + fail + } + +end + +# Copy hidden source window to a visible window. + +$define Margin 20 + +procedure copy_source(label) + + screen := WOpen("size=" || WAttrib(source, "width") || "," || + WAttrib(source, "height"), "posx=" || posx, "posy=" || posy, + "label=" || label) | ExitNotice("Cannot open image window") + + CopyArea(source, screen) + + expose(controls) + + wmax := WAttrib(source, "width") + hmax := WAttrib(source, "height") + + WAttrib(pattern, "width=" || (WAttrib(screen, "width") + Margin)) + WAttrib(pattern, "height=" || (WAttrib(screen, "height") + Margin)) + + reset_cb() + + return + +end + +# Enable user-drawn selection. + +procedure draw_cb(vidget, value) + local sel + + if /value then return + + if /source then { + Notice("No source image.") + SetVidget(draw, &null) + fail + } + + expose(screen) + + while current := select(screen) do + show() + + SetVidget(draw, &null) + + expose(controls) + + return + +end + +# File menu callback. + +procedure file_cb(vidget, value) + + case value[1] of { + "open @O": get_image() + "pick @P": pick() + "quit @Q": exit() + "save @S": snap() + "tile @T": tile_selection() + } + + return + +end + +# Utility procedure to get new source image. + +procedure get_image() + + WClose(\source) + WClose(\screen) + + repeat { + (OpenDialog("Open image:") == "Okay") | fail + source := WOpen("canvas=hidden", "image=" || dialog_value) | { + Notice("Can't open " || dialog_value || ".") + next + } + copy_source(dialog_value) + wmax := WAttrib(source, "width") + hmax := WAttrib(source, "height") + break + } + + return + +end + +# These values are for Motif; they may need to be changed for other +# window managers. + +$define Offset1 32 +$define Offset2 82 + +# Initialize the program + +$define MinSize 600 + +procedure init() + local iheight + + current := rect(0, 0, 1, 1) + hmax := wmax := 0 + + posx := WAttrib("width") + Offset1 + + iheight := WAttrib("height") + + pattern := WOpen("label=repeat", "resize=on", "size=" || iheight || + "," || iheight, "posx=" || posx, PosY) | + stop("*** cannot open window for repeat ***") + + posy := WAttrib(pattern, "height") + Offset2 + + root := vidgets["root"] + text := vidgets["text"] + draw := vidgets["draw"] + + WAttrib("canvas=normal") + + auto := &null + + return + +end + +# Utility procedure to let user pick an image file in the current directory. + +procedure pick() + local plist, ls + + plist := filelist("*.gif *.GIF") | + return FailNotice("Pick not supported on this platform") + + if *plist = 0 then return FailNotice("No files found.") + + repeat { + if SelectDialog("Select image file:", plist, plist[1]) == "Cancel" + then fail + WClose(\source) + WClose(\screen) + source := WOpen("canvas=hidden", "image=" || dialog_value) | { + Notice("Cannot open " || dialog_value || ".") + next + } + copy_source(dialog_value) + break + } + + return + +end + +# Callback to terminate program execution. + +procedure quit_cb() + + exit() + +end + +# Callback to reset x, y, w, and h to initial values. + +procedure reset_cb() + + current := rect(0, 0, 1, 1) + + show() + + return + +end + +# Callback procedure to save the current selection as an image file. + +procedure save_cb() + + snap() + +end + +# Callback procedure to allow use of standard tile sizes. + +procedure select_cb(vidget, value) + + check(current.w := current.h := case value of { + " 4 x 4": 4 + " 8 x 8": 8 + " 16 x 16": 16 + " 32 x 32": 32 + " 64 x 64": 64 + " 72 x 72": 72 + " 96 x 96": 96 + " 100 x 100": 100 + " 128 x 128": 128 + " 256 x 256": 256 + " 400 x 400": 400 + " 512 x 512": 512 + }) | fail + + show() + + return + +end + +# Callback to allow setting of specific selection rectangle values. + +procedure set_cb() + + repeat { + if TextDialog("Set values:", + ["x", "y", "w", "h"], + [ current.x, + current.y, + current.w, + current.h + ] + ) == "Cancel" then fail + check( + current.x <- integer(dialog_value[1]) & + current.y <- integer(dialog_value[2]) & + current.w <- integer(dialog_value[3]) & + current.h <- integer(dialog_value[4]) + ) | { + Notice("Invalid value") + next + } + show() + return + } + +end + +# Keyboard shortcuts. + +procedure shortcuts(e) + + if &meta then + case map(e) of { # fold case + "d": SetVidget(draw, 1) + "o": get_image() + "p": pick() + "q": exit() + "s": snap() + "t": tile_selection() + } + + return + +end + +# Procedure to handle all that goes with a new selection. + +# These constants are ad hoc. + +$define Width 200 +$define Height 30 +$define YOff 10 + +procedure show() + static sx, sy + + initial { + sx := text.ax + sy := text.ay + } + + if /source then return FailNotice("No source image.") + + tile(source, pattern, current.x, current.y, current.w, current.h) + + if \auto then { + name := prefix || right(count +:= 1, 3, "0") || ".gif" + WriteImage(source, name, current.x, current.y, current.w, current.h) + } + + EraseArea(sx, sy, Width, Height) + + DrawString(sx, sy + YOff, "x=" || current.x || " y=" || current.y || + " w=" || current.w || " h=" || current.h) + + if \auto then DrawString(sx, sy + 30, "last auto-save: " || name) + + return + +end + +# Utility procedure to save current selection. + +procedure snap() + + return snapshot(\source, current.x, current.y, current.w, current.h) | + FailNotice("No source image.") + +end + +# Callback for System menu. + +procedure system_cb(vidget, value) + + case value[1] of { + "edit": edit_file() + "execute": execute() + } + + return + +end + +procedure tile_selection() + + tile(pattern, screen, current.x, current.y, current.w, current.h) + CopyArea(screen, source) + + return + +end + +#===<<vib:begin>>=== modify using vib; do not remove this marker line +procedure ui_atts() + return ["size=397,360", "bg=gray-white"] +end + +procedure ui(win, cbk) +return vsetup(win, cbk, + [":Sizer:::0,0,397,360:",], + ["auto save:Button:regular:1:12,74,70,20:auto save",auto_cb], + ["draw:Button:regular:1:20,172,50,20:draw",draw_cb], + ["file:Menu:pull::0,1,36,21:File",file_cb, + ["open @O","pick @P","save @S ","tile @T","quit @Q"]], + ["hmax:Button:regular::205,54,56,20:h max",change_cb], + ["hminus:Button:regular::169,106,35,20:h -",change_cb], + ["hplus:Button:regular::168,80,35,20:h +",change_cb], + ["line1:Line:::0,25,400,25:",], + ["quit:Button:regular::19,311,50,20:quit",quit_cb], + ["reset_cb:Button:regular::20,116,50,20:reset",reset_cb], + ["save:Button:regular::19,40,50,20:save",save_cb], + ["select:Choice::12:285,29,99,252:",select_cb, + [" 4 x 4"," 8 x 8"," 16 x 16"," 32 x 32"," 64 x 64", + " 72 x 72"," 96 x 96"," 100 x 100"," 128 x 128"," 256 x 256", + " 400 x 400"," 512 x 512"]], + ["set:Button:regular::20,143,50,20:set",set_cb], + ["system:Menu:pull::37,1,50,21:System",system_cb, + ["edit","execute"]], + ["text:Button:regularno::112,290,154,20:current specification",], + ["whmax:Button:regular::206,80,56,20:w h max",change_cb], + ["whminus:Button:regular::108,54,56,20:w - h -",change_cb], + ["whplus:Button:regular::108,30,56,20:w + h +",change_cb], + ["wmax:Button:regular::206,29,56,20:w max",change_cb], + ["wminus:Button:regular::168,54,35,20:w -",change_cb], + ["wplus:Button:regular::168,29,35,20:w +",change_cb], + ["xhalf:Button:regular::213,153,56,20:x 1/2",change_cb], + ["xminus:Button:regular::173,180,35,20:x -",change_cb], + ["xplus:Button:regular::172,153,35,20:x +",change_cb], + ["xyhalf:Button:regular::212,206,56,20:x y 1/2",change_cb], + ["xyminus:Button:regular::109,181,56,20:x - y +",change_cb], + ["xyplus:Button:regular::110,151,56,20:x + y +",change_cb], + ["y minus:Button:regular::172,231,35,20:y -",change_cb], + ["y plus:Button:regular::173,206,35,20:y +",change_cb], + ["yhalf:Button:regular::212,177,56,20:y 1/2",change_cb], + ) +end +#===<<vib:end>>=== end of section maintained by vib |