diff options
Diffstat (limited to 'ipl/gprocs/window.icn')
-rw-r--r-- | ipl/gprocs/window.icn | 380 |
1 files changed, 380 insertions, 0 deletions
diff --git a/ipl/gprocs/window.icn b/ipl/gprocs/window.icn new file mode 100644 index 0000000..9526060 --- /dev/null +++ b/ipl/gprocs/window.icn @@ -0,0 +1,380 @@ +############################################################################ +# +# File: window.icn +# +# Subject: Procedure for opening window +# +# Author: Gregg M. Townsend +# +# Date: October 10, 1997 +# +############################################################################ +# +# This file is in the public domain. +# +############################################################################ +# +# Window() opens a window with provisions for option processing and +# error handling. The returned window is assigned to &window if +# &window is null. If the window cannot be opened, the program is +# aborted. +# +# The characteristics of the window are set from several sources: +# Window's arguments, optionally including the program argument list; +# user defaults; and built-in defaults. These built-in defaults are +# the same as for optwindow(): bg=pale gray, fg=black, size=500,300. +# +############################################################################ +# +# With one exception, arguments to Window() are attribute specifications +# such as those used with open() and WAttrib(). Order is significant, +# with later attributes overriding earlier ones. +# +# Additionally, the program argument list -- the single argument passed +# to the main procedure -- can be passed as an argument to Window(). +# Options specified with a capital letter are removed from the list and +# interpreted as attribute specifications, again in a manner consistent +# with optwindow(). +# +# Because the Window() arguments are processed in order, attributes that +# appear before the program arglist can be overridden by command-line +# options when the program is executed. If attributes appear after the +# program arglist, they cannot be overridden. For example, with +# +# procedure main(args) +# Window("size=600,400", "fg=yellow", args, "bg=black") +# +# the program user can change the size and foreground color +# but not the background color. +# +# User defaults are applied at the point where the program arglist appears +# (and before processing the arglist). If no arglist is supplied, no +# defaults are applied. Defaults are obtained by calling WDefault(). +# Icon attribute names are used as option names; &progname is used +# as the program name after trimming directories and extensions. +# +# The following table lists the options recognized in the program arglist, +# the corresponding attribute (and WDefault()) names, the default values +# if any, and the meanings. All legal attributes are allowed in the +# Window() call, but only these are set from the command line or +# environment: +# +# arg attribute default meaning +# --- --------- ------- -------------------------- +# -B bg pale gray background color +# -F fg black foreground color +# -T font - text font +# -L label &progname window title +# (trimmed) +# +# -D display - window device +# -X posx - horizontal position +# -Y posy - vertical position +# -W width 500 window width +# -H height 300 window height +# +# -S size 500,300 size +# -P pos - position +# -G geometry - window size and/or position +# +# -A <any> - use "-A name=value" +# to set arbitrary attribute +# +# -! - - write open() params to &error +# (for debugging) +# +############################################################################ +# +# Includes: vdefns +# +############################################################################ +# +# Requires: Version 9 graphics +# +############################################################################ + + +$include "vdefns.icn" + +global wdw_debug # non-null if to trace open call + + +# Window(att, ..., arglist, ..., att) -- open window and set &window + +procedure Window(args[]) + local cs, pname, att, omit1, omit2, name, val, a, win + static type + + initial type := proc("type", 0) # protect attractive name + + wdw_debug := &null + att := table() + + # Trim &progname for use as option index and window label. + cs := &cset -- &letters -- &digits -- '.$_' + &progname ? { + while tab(upto(cs)) do + move(1) + pname := tab(upto('.') | 0) + } + if pname == "" then + pname := &progname + + # Process arguments. + every a := !args do + case type(a) of { + "string": a ? { + name := tab(upto("=")) | runerr(205, a) + move(1) + val := tab(0) + wdw_register(att, name, val) + } + "list": { + wdw_defaults(att, a, pname) + wdw_options(att, a) + } + default: + runerr(110, a) + } + + # Set defaults for certain attributes if not set earlier. + /att["fg"] := "black" + /att["bg"] := VBackground + /att["label"] := pname + + if /att["image"] & not (att["canvas"] === "maximal") then { # don't override + /att["width"] := 500 + /att["height"] := 300 + } + + # Open the window. Defer "font" and "fg" until later because they can + # cause failure. Don't defer "bg", because it affects the initial + # window appearance, but try again without it if the open fails. + omit1 := set(["fg", "font"]) + omit2 := set(["fg", "font", "bg"]) + win := wdw_open(att, omit1 | omit2) | stop(&progname, ": can't open window") + + # Set foreground, background, and font, giving a nonfatal message if + # the value is unacceptable. Then return the window. + wdw_attrib(win, att, "fg") + wdw_attrib(win, att, "bg") + wdw_attrib(win, att, "font") + GotoRC(win, 1, 1) # now that font has been set + /&window := win + return win +end + + +# wdw_defaults(att, arglist, pname) -- find defaults and store in att table +# +# arglist is checked for "-D displayname", which is honored if present. +# pname is the program name for calling xdefault. +# A list of several attribute names (see code) is checked. + +procedure wdw_defaults(att, arglist, pname) + local w, oname, dpy + + # We need to have a window in order to read defaults, and unless we honor + # the -D option from the command line here it becomes pretty useless. + dpy := ("display=" || wdw_peekopt(arglist, "D")) | "fg=black" + + # Open an offscreen window. + w := open("Window()", "g", "canvas=hidden", "size=32,32", dpy) | + stop(&progname, ": can't open display") + + # Set attributes from environment. Order is significant here: + # pos & size override geometry, and posx/posy/width/height override both. + every oname := "display" | "bg" | "fg" | "font" | "windowlabel" | "label" | + "geometry" | "size" | "pos" | "posx" | "posy" | "width" | "height" do + wdw_register(att, oname, WDefault(w, pname, oname)) + + # Delete the offscreen window, and return. + Uncouple(w) + return +end + + +# wdw_peekopt(arglist, ch) -- return value of option 'ch' from arglist +# +# Option cracking rules are identical with wdw_options(). +# Fails if the option does not appear. + +procedure wdw_peekopt(arglist, ch) + local a, opt, val + + arglist := copy(arglist) + while a := get(arglist) do a ? { + if ="-" & (opt := tab(any(&ucase))) then { + if pos(0) then + val := get(arglist) | fail + else + val := tab(0) + if opt == ch then + return val + } + } + fail +end + + +# wdw_options(att, arglist) - move options from arglist into att table +# +# Upper-case options in the argument list are stored in the table "att" +# under their attribute names (see code for list). An "option" is a list +# entry beginning with "-" and an option letter; its value follows in the +# same string (if more characters remain) or in the next entry. +# +# This procedure can be "fooled" if a non-upper-case option is followed +# in the next entry by a value that looks like the start of an option. +# +# Options and values are removed from arglist, leaving only the unprocessed +# entries. +# +# The special option "-!" takes no value and causes wdw_debug to be set. + +procedure wdw_options(att, arglist) + local a, opt, name, val, rejects + + rejects := [] + while a := get(arglist) do a ? { + if ="-" & (opt := tab(any(&ucase))) then { + if pos(0) then + val := get(arglist) | stop(&progname, ": missing value for ", a) + else + val := tab(0) + case opt of { + "B": wdw_register(att, "bg", val) + "F": wdw_register(att, "fg", val) + "T": wdw_register(att, "font", val) + "L": wdw_register(att, "label", val) + "D": wdw_register(att, "display", val) + "X": wdw_register(att, "posx", val) + "Y": wdw_register(att, "posy", val) + "W": wdw_register(att, "width", val) + "H": wdw_register(att, "height", val) + "P": wdw_register(att, "pos", val) + "S": wdw_register(att, "size", val) + "G": wdw_register(att, "geometry", val) + "A": val ? { + name := tab(upto("=")) | + stop(&progname, ": malformed -A option: ", val) + move(1) + wdw_register(att, name, tab(0)) + } + default: stop(&progname, ": unrecognized option -", opt) + } + } + else if ="-!" & pos(0) then + wdw_debug := 1 + else + put(rejects, a) + } + + # Arglist is now empty; put back args that we didn't use. + while put(arglist, get(rejects)) + return +end + + + +# wdw_register(att, name, val) -- store attribute val in att[name] +# +# The compound attributes "pos", "size", and "geometry" are broken down +# into their component parts and stored as multiple values. A runtime +# error occurs if any of these is malformed. Interactions with +# "canvas=maximal" are also handled. + +procedure wdw_register(att, name, val) + wdw_reg(att, name, val) | runerr(205, name || "=" || val) + return +end + +procedure wdw_reg(att, name, val) + case name of { + "size": val ? { # size=www,hhh + att["width"] := tab(many(&digits)) | fail + ="," | fail + att["height"] := tab(many(&digits)) | fail + pos(0) | fail + if \att["canvas"] == "maximal" then + delete(att, "canvas") + } + "pos": val ? { # pos=xxx,yyy + att["posx"] := tab(many(&digits)) | fail + ="," | fail + att["posy"] := tab(many(&digits)) | fail + pos(0) | fail + } + "geometry": val ? { # geometry=[wwwxhhh][+xxx+yyy] + if att["width"] := tab(many(&digits)) + then { + ="x" | fail + att["height"] := tab(many(&digits)) | fail + if \att["canvas"] == "maximal" then + delete(att, "canvas") + } + if ="+" then { + att["posx"] := tab(many(&digits)) | fail + ="+" | fail + att["posy"] := tab(many(&digits)) | fail + } + pos(0) | fail + } + "canvas": { + att[name] := val + if val == "maximal" then + every delete(att, "width" | "height") + } + default: { + att[name] := val + } + } + return +end + + +# wdw_open(att, omit) -- open window with attributes from att table +# +# Ignore null or empty attributes and those in the "omit" set. +# Trace open call if wdw_debug is set. Set &window. + +procedure wdw_open(att, omit) + local args, name + static image + + initial image := proc("image", 0) # protect attractive name + + args := [&progname, "g"] + every name := key(att) do + if not member(omit, name) then + put(args, name || "=" || ("" ~== \att[name])) + + if \wdw_debug then { + writes(&errout, "Window: open(", image(args[1])) + every writes(&errout, ",", image(args[2 to *args])) + write(&errout, ")") + } + + return open ! args +end + + +# wdw_attrib(win, att, name) -- call WAttrib(win, name=att[name]) +# +# Null and empty values are ignored. +# Failure is diagnosed on stderr. +# The call is traced if wdw_debug is set. + +procedure wdw_attrib(win, att, name) + local val, s + static image + + initial image := proc("image", 0) # protect attractive name + + val := ("" ~== \att[name]) | return + s := name || "=" || val + if \wdw_debug then + write(&errout, "Window: WAttrib(", image(s), ")") + WAttrib(win, s) | write(&errout, &progname, ": can't set ", s) + return +end |