diff options
Diffstat (limited to 'ipl/gprocs/dialog.icn')
-rw-r--r-- | ipl/gprocs/dialog.icn | 735 |
1 files changed, 735 insertions, 0 deletions
diff --git a/ipl/gprocs/dialog.icn b/ipl/gprocs/dialog.icn new file mode 100644 index 0000000..d10648c --- /dev/null +++ b/ipl/gprocs/dialog.icn @@ -0,0 +1,735 @@ +############################################################################ +# +# File: dialog.icn +# +# Subject: Procedures for dialogs +# +# Authors: Ralph E. Griswold and Gregg M. Townsend +# +# Date: December 14, 1999 +# +############################################################################ +# +# This file is in the public domain. +# +############################################################################ +# +# This file contains several procedures for posting dialog boxes: +# +# AskDialog() -- TextDialog() with only caption and "No" instead of "Cancel" +# Notice(win, captions) -- notice dialog (a simple text dialog) +# TextDialog(win, captions, labels, defaults...) -- text dialog +# ToggleDialog(win, captions, labels, defaults...) -- toggle dialog +# SelectDialog(win, captions, labels, defaults...) -- selection dialog +# SaveDialog(win, caption, filename, len) -- save file dialog +# OpenDialog(win, caption, filename, len) -- open file dialog +# ColorDialog(win, captions, refcolor, callback, id) -- color dialog +# +# In all cases, the first or only caption is used as a dialog box ID, +# used to remember the dialog box location when it is closed. A later +# posting using the same ID places the new box at the same location. +# +############################################################################ +# +# ColorDialog(win, captions, color, callback, id) -- display color dialog +# +# captions list of dialog box captions; default is ["Select color:"] +# color reference color setting; none displayed if not supplied +# callback procedure to call when the setting is changed +# id arbitrary value passed to callback +# +# ColorDialog displays a dialog window with R/G/B and H/S/V sliders for +# color selection. When the "Okay" or "Cancel" button is pressed, +# ColorDialog returns the button name, with the ColorValue of the final +# settings stored in the global variable dialog_value. +# +# If a callback procedure is specified, callback(id, k) is called whenever +# the settings are changed; k is the ColorValue of the settings. +# +############################################################################ +# +# Popup(x, y, w, h, proc, args...) creates a subwindow of the specified +# size, calls proc(args), and awaits its success or failure. Then, the +# overlaid area is restored and the result of proc is produced. &window, +# as seen by proc, is a new binding of win in which dx, dy, and clipping +# have been set. The usable area begins at (0,0); its size is +# (WAttrib(win, "clipw"), WAttrib(win, "cliph")). Defaults are: +# x, y positioned to center the subwindow +# w, h 250, 150 +# proc Event +# +############################################################################ +# +# Requires: Version 9 graphics +# +############################################################################ +# +# Links: graphics, vbuttons, vdialog, vradio, vslider, vidgets +# +############################################################################ + +link graphics +link vbuttons +link vdialog +link vradio +link vslider +link vidgets + +$include "vdefns.icn" + +global dialog_button +global dialog_value + +$define ButtonWidth 50 # minimum button width +$define ButtonHeight 30 # button height +$define FieldWidth 10 # default field width +$define OpenWidth 50 # default field width for Open/SaveDialog + +$define XOff 0 # offset for text vidgets +$define XOffButton 85 # initial x offset for buttons +$define XOffIncr 15 # space between buttons + +procedure Dialog(win, captions, labels, defaults, widths, buttons, index) + Dialog := TextDialog + return Dialog(win, captions, labels, defaults, widths, buttons, index) +end + +procedure AskDialog(win, caption) + + return TextDialog(win, caption, , , , , ["Okay", "No"]) + +end + +procedure TextDialog( #: text dialog + win, captions, labels, defaults, widths, buttons, index + ) + local maxl, lead, pad, default_button, i, maxw, cwidth, id, label_width + local button, maxb, dialog, x, y, button_space, default_width, box_id + local temp_win + static type + + initial type := proc("type", 0) # protect attractive name + + if type(win) ~== "window" then { + win :=: captions :=: labels :=: defaults :=: widths :=: buttons :=: + index + win := &window + /win := temp_win := WOpen("canvas=hidden", "bg=" || VBackground) + } + + /captions := [] + /labels := [] + /defaults := [] + /widths := [] + /buttons := ["Okay", "Cancel"] + /index := 1 + + if type(captions) ~== "list" then captions := [captions] + if type(labels) ~== "list" then labels := [labels] + if type(defaults) ~== "list" then defaults := [defaults] + if type(widths) ~== "list" then widths := [widths] + if type(buttons) ~== "list" then buttons := [buttons] + + default_button := buttons[index] # null if out of bounds + default_width := widths[-1] | FieldWidth + + maxl := 0 + every maxl <:= *(labels | defaults | widths) + until *labels = maxl do put(labels, labels[-1] | "") + until *defaults = maxl do put(defaults, defaults[-1] | "") + until *widths = maxl do put(widths, widths[-1] | 10) + + id := 0 + + label_width := 0 + every label_width <:= TextWidth(win, !labels) + if label_width > 0 then label_width +:= 15 + + maxb := 0 + every maxb <:= TextWidth(win, !buttons) + maxb +:= 10 + maxb <:= ButtonWidth + + lead := WAttrib(win, "leading") + pad := 2 * lead + cwidth := WAttrib(win, "fwidth") + + dialog := Vdialog(win, pad, pad) + + maxw := 0 + every maxw <:= TextWidth(win, !captions) + + y := -lead + + every VInsert(dialog, Vmessage(win, !captions), 0, y +:= lead) + every i := 1 to maxl do { + y +:= pad + if *labels[i] > 0 then + VInsert(dialog, Vmessage(win, labels[i]), 0, y) + VRegister(dialog, Vtext(win, "", , id +:= 1, + widths[i]), label_width, y) + maxw <:= label_width + widths[i] * cwidth + } + + y +:= (3 * pad) / 2 + + button_space := maxb * *buttons + XOffIncr * (*buttons - 1) + maxw <:= button_space + + x := ((maxw - button_space) / 2) + + every button := !buttons do { + VInsert(dialog, Vbutton(win, button, dialog_cb, V_OK, , maxb, + ButtonHeight), x, y) + x +:= maxb + XOffIncr + } + + VFormat(dialog) + + box_id := captions[1] | "TextDialog" + dialog_value := VOpenDialog(dialog, , box_id, defaults, default_button) + + WClose(\temp_win) + + return dialog_button + +end + +procedure ToggleDialog( #: toggle dialog + win, captions, labels, defaults, buttons, index + ) + local maxl, lead, pad, default_button, i, maxw, cwidth, id, label_width + local button, maxb, dialog, x, y, button_space, default_width, box_id + local temp_win + static type + + initial type := proc("type", 0) # protect attractive name + + if type(win) ~== "window" then { + win :=: captions :=: labels :=: defaults :=: buttons :=: index + win := &window + /win := temp_win := WOpen("canvas=hidden", "bg=" || VBackground) + } + + /captions := [] + /labels := [] + /defaults := [] + /buttons := ["Okay", "Cancel"] + /index := 1 + + if type(captions) ~== "list" then captions := [captions] + if type(labels) ~== "list" then labels := [labels] + if type(defaults) ~== "list" then defaults := [defaults] + if type(buttons) ~== "list" then buttons := [buttons] + + default_button := buttons[index] # null if out of bounds + + maxl := 0 + every maxl <:= *(labels | defaults) + every maxl <:= *labels + until *labels = maxl do put(labels, labels[-1] | "") + until *defaults = maxl do put(defaults, defaults[-1] | &null) + + id := 0 + + label_width := 0 + every label_width <:= TextWidth(win, !labels) + if label_width > 0 then label_width +:= 30 + + maxb := 0 + every maxb <:= TextWidth(win, !buttons) + maxb +:= 10 + maxb <:= ButtonWidth + + lead := WAttrib(win, "leading") + pad := 2 * lead + cwidth := WAttrib(win, "fwidth") + + dialog := Vdialog(win, pad, pad) + + maxw := 0 + every maxw <:= TextWidth(win, !captions) + + y := -lead + + every VInsert(dialog, Vmessage(win, !captions), 0, y +:= lead) + every i := 1 to maxl do { + y +:= pad + VRegister(dialog, Vtoggle(win, labels[i], , id +:= 1, V_CHECK_NO, + label_width), 0, y) + maxw <:= label_width + } + + y +:= (3 * pad) / 2 + + button_space := maxb * *buttons + XOffIncr * (*buttons - 1) + maxw <:= button_space + + x := ((maxw - button_space) / 2) + + every button := !buttons do { + VInsert(dialog, Vbutton(win, button, dialog_cb, V_OK, , maxb, + ButtonHeight), x, y) + x +:= maxb + XOffIncr + } + + VFormat(dialog) + + box_id := captions[1] | "ToggleDialog" + dialog_value := VOpenDialog(dialog, , box_id, defaults, default_button) + + WClose(\temp_win) + + return dialog_button + +end + +procedure SelectDialog( #: selection dialog + win, captions, labels, deflt, buttons, index + ) + local maxl, lead, pad, default_button, i, maxw, cwidth, label_width + local button, maxb, dialog, x, y, button_space, box_id + local temp_win + static type + + initial type := proc("type", 0) # protect attractive name + + if type(win) ~== "window" then { + win :=: captions :=: labels :=: deflt :=: buttons :=: index + win := &window + /win := temp_win := WOpen("canvas=hidden", "bg=" || VBackground) + } + + /captions := [] + /labels := [] + /buttons := ["Okay", "Cancel"] + /index := 1 + + if type(captions) ~== "list" then captions := [captions] + if type(labels) ~== "list" then labels := [labels] + if type(buttons) ~== "list" then buttons := [buttons] + + default_button := buttons[index] # null if out of bounds + + maxl := 0 + every maxl <:= *labels + until *labels = maxl do put(labels, labels[-1] | "") + + label_width := 0 + every label_width <:= TextWidth(win, !labels) + if label_width > 0 then label_width +:= 15 + + maxb := 0 + every maxb <:= TextWidth(win, !buttons) + maxb +:= 10 + maxb <:= ButtonWidth + + lead := WAttrib(win, "leading") + pad := 2 * lead + cwidth := WAttrib(win, "fwidth") + + dialog := Vdialog(win, pad, pad) + + maxw := 0 + every maxw <:= TextWidth(win, !captions) + + y := -lead + + every VInsert(dialog, Vmessage(win, !captions), 0, y +:= lead) + y +:= 2 * lead + VRegister(dialog, Vvert_radio_buttons(win, labels, , 1, V_DIAMOND_NO), 0, y) + + y +:= integer(0.83 * (pad * (*labels - 1)) + 1.5 * pad) + + button_space := maxb * *buttons + XOffIncr * (*buttons - 1) + maxw <:= button_space + + x := ((maxw - button_space) / 2) + + every button := !buttons do { + VInsert(dialog, Vbutton(win, button, dialog_cb, V_OK, , maxb, + ButtonHeight), x, y) + x +:= maxb + XOffIncr + } + + VFormat(dialog) + + box_id := captions[1] | "ToggleDialog" + dialog_value := VOpenDialog(dialog, , box_id, [deflt], default_button)[1] + + WClose(\temp_win) + + return dialog_button + +end + +procedure Notice(captions[]) #: notice dialog + local win, temp_win + static type + + initial type := proc("type", 0) # protect attractive name + + if type(captions[1]) == "window" then + win := get(captions) + else { + win := &window + /win := temp_win := WOpen("canvas=hidden", "bg=" || VBackground) + } + + TextDialog(win, captions, , , , "Okay") + + dialog_value := &null + + WClose(\temp_win) + + return dialog_button + +end + +procedure SaveDialog(win, caption, filename, len) #: save dialog + local temp_win + static type + + initial type := proc("type", 0) # protect attractive name + + if type(win) ~== "window" then { + win :=: caption :=: filename :=: len + win := &window + /win := temp_win := WOpen("canvas=hidden", "bg=" || VBackground) + } + + /caption := "Save:" + /filename := "" + /len := OpenWidth + + TextDialog(win, caption, , filename, len, ["Yes", "No", "Cancel"]) + + dialog_value := dialog_value[1] + + WClose(\temp_win) + + return dialog_button + +end + +procedure OpenDialog(win, caption, filename, len) #: open dialog + local temp_win + static type + + initial type := proc("type", 0) # protect attractive name + + if type(win) ~== "window" then { + win :=: caption :=: filename :=: len + win := &window + /win := temp_win := WOpen("canvas=hidden", "bg=" || VBackground) + } + + /caption := "Open:" + /filename := "" + /len := OpenWidth + + TextDialog(win, caption, , filename, len) + + dialog_value := dialog_value[1] + + WClose(\temp_win) + + return dialog_button + +end + +procedure dialog_cb(vidget, s) + + dialog_button := vidget.s + + return + +end + +# ColorDialog(win, captions, color, callback, id) -- display color dialog + +record cdl_rec(rect, orgcolor, refcolor, mutable, callback, id, + r, g, b, h, s, v, rv, gv, bv, hv, sv, vv, fg, fillargs, dialog, nc) + +global cdl_data # data for current color dialog + +$define PickerWidth 300 # overall color picker width +$define SliderHeight 200 # height of a slider +$define SliderWidth 15 # width of one slider +$define SliderPad 5 # distance between sliders +$define MaxStaticCol 200 # maximum colors before recycling + +procedure ColorDialog( #: color dialog + win, captions, refcolor, callback, id + ) + local x1, x2, dx, y, bw, lead, pad, dialog, box_id, temp_win + static type + + initial type := proc("type", 0) # protect attractive name + + if type(win) ~== "window" then { + win :=: captions :=: refcolor :=: callback :=: id + win := &window + /win := temp_win := WOpen("canvas=hidden", "bg=" || VBackground) + } + + /captions := "Select color:" + if type(captions) ~== "list" then captions := [captions] + + cdl_data := cdl_rec() + cdl_data.callback := callback + cdl_data.id := id + cdl_data.refcolor := refcolor + cdl_data.orgcolor := ColorValue(win, \refcolor | Fg(win) | "gray") + + cdl_data.orgcolor ? { + cdl_data.r := integer(tab(many(&digits))) + move(1) + cdl_data.g := integer(tab(many(&digits))) + move(1) + cdl_data.b := integer(tab(many(&digits))) + } + HSV(cdl_data.orgcolor) ? { + cdl_data.h := integer(tab(many(&digits))) + move(1) + cdl_data.s := integer(tab(many(&digits))) + move(1) + cdl_data.v := integer(tab(many(&digits))) + } + + lead := WAttrib(win, "leading") + pad := 2 * lead + + y := -lead + + dialog := Vdialog(win, pad, pad, cdl_init) + every VInsert(dialog, Vmessage(win, !captions), 0, y +:= lead) + + dx := SliderWidth + SliderPad + x1 := 0 - dx + x2 := PickerWidth + SliderPad + y +:= pad + + cdl_data.dialog := dialog + cdl_data.rv := cdl_slider(dialog, "r", x1 +:= dx, y, 0, 65535, cdl_data.r) + cdl_data.gv := cdl_slider(dialog, "g", x1 +:= dx, y, 0, 65535, cdl_data.g) + cdl_data.bv := cdl_slider(dialog, "b", x1 +:= dx, y, 0, 65535, cdl_data.b) + cdl_data.vv := cdl_slider(dialog, "v", x2 -:= dx, y, 0, 100, cdl_data.v) + cdl_data.sv := cdl_slider(dialog, "s", x2 -:= dx, y, 0, 100, cdl_data.s) + cdl_data.hv := cdl_slider(dialog, "h", x2 -:= dx, y, 0, 360, cdl_data.h) + + x1 +:= dx + SliderPad + x2 -:= 2 * SliderPad + cdl_data.rect := Vpane(win, , , "sunken", + x2 - x1, SliderHeight - 3 * lead - SliderPad) + VInsert(dialog, cdl_data.rect, x1, y) + + y +:= SliderHeight + pad + bw := TextWidth(win, "Cancel") + 10 + VInsert(dialog, Vbutton(win, "Okay", cdl_exit, V_OK, , + bw, ButtonHeight), PickerWidth / 2 - bw - 10, y) + VInsert(dialog, Vbutton(win, "Cancel", cdl_exit, V_OK, , + bw, ButtonHeight), PickerWidth / 2 + 10, y) + + VFormat(dialog) + box_id := captions[1] | "ColorDialog" + VOpenDialog(dialog, , box_id, , "Okay") + + dialog_value := cdl_data.r || "," || cdl_data.g || "," || cdl_data.b + + WClose(\temp_win) + + return dialog_button + +end + +procedure cdl_slider(dialog, id, x, y, low, high, init) # place a slider + local v + + v := Vvert_slider(dialog.win, cdl_setval, id, + SliderHeight, SliderWidth, low, high, init) + VInsert(dialog, v, x, y) + return v +end + +procedure cdl_init() # initialize non-vidget part of dialog + local r + + r := cdl_data.rect + cdl_data.fg := Fg(r.win) + cdl_data.fillargs := [r.win, r.ux, r.uy, r.uw, r.uh] + if cdl_data.mutable := NewColor(cdl_data.rect.win, cdl_data.orgcolor) then { + Fg(r.win, cdl_data.mutable) + FillRectangle ! cdl_data.fillargs + } + else + cdl_data.nc := 0 + if Fg(r.win, \cdl_data.refcolor) then { + cdl_data.fillargs[-1] -:= r.uh / 8 + FillRectangle(r.win, r.ux, r.uy + r.uh, r.uw, -r.uh / 8) + } + Fg(r.win, cdl_data.fg) + cdl_sethsv() + return +end + +procedure cdl_exit(vidget, s) # save position and button name on exit + dialog_button := vidget.s + FreeColor(cdl_data.rect.win, \cdl_data.mutable) + EraseArea(cdl_data.rect.win) + return +end + +procedure cdl_setval(v, x) # set value in response to slider motion + static recurse + + if /recurse then { # if not a recursive call + recurse := 1 # note to prevent recursion + case v.id of { + "r": { cdl_data.r := x; cdl_sethsv(); } + "g": { cdl_data.g := x; cdl_sethsv(); } + "b": { cdl_data.b := x; cdl_sethsv(); } + "h": { cdl_data.h := x; cdl_setrgb(); } + "s": { cdl_data.s := x; cdl_setrgb(); } + "v": { cdl_data.v := x; cdl_setrgb(); } + } + recurse := &null + } + return +end + +procedure cdl_sethsv() # set h/s/v values from r/g/b + local c + + HSV(c := cdl_data.r || "," || cdl_data.g || "," || cdl_data.b) ? { + VSetState(cdl_data.hv, cdl_data.h := integer(tab(many(&digits)))) + move(1) + VSetState(cdl_data.sv, cdl_data.s := integer(tab(many(&digits)))) + move(1) + VSetState(cdl_data.vv, cdl_data.v := integer(tab(many(&digits)))) + } + cdl_setcolor(c) + return +end + +procedure cdl_setrgb() # set r/g/b values from h/s/v + local c + + (c := HSVValue(cdl_data.h || "/" || cdl_data.s || "/" || cdl_data.v)) ? { + VSetState(cdl_data.rv, cdl_data.r := integer(tab(many(&digits)))) + move(1) + VSetState(cdl_data.gv, cdl_data.g := integer(tab(many(&digits)))) + move(1) + VSetState(cdl_data.bv, cdl_data.b := integer(tab(many(&digits)))) + } + cdl_setcolor(c) + return +end + +procedure cdl_setcolor(c) # display new color and invoke callback + local r, win, x1, x2, y, dy + + r := cdl_data.rect + win := r.win + if \cdl_data.mutable then + Color(win, cdl_data.mutable, c) # set the mutable color + else { + if ((cdl_data.nc +:= 1) > MaxStaticCol) | (not Fg(win, c)) then { + EraseArea(win) # free allocated colors + VDraw(cdl_data.dialog) # redraw vidget + if Fg(r.win, \cdl_data.refcolor) then # redraw reference color + FillRectangle(r.win, r.ux, r.uy + r.uh, r.uw, -r.uh / 8) + Fg(win, c) # set new foreground + cdl_data.nc := 1 + } + FillRectangle ! cdl_data.fillargs + Fg(win, cdl_data.fg) + } + + x1 := cdl_data.rect.ax + x2 := x1 + cdl_data.rect.aw + y := cdl_data.rect.ay + cdl_data.rect.ah + SliderPad + dy := WAttrib(win, "leading") + + EraseArea(win, x1, y, x2 - x1, 3 * dy) # erase and redraw text area + y +:= WAttrib(win, "ascent") + x2 -:= TextWidth(win, "h: 360") + + DrawString(win, x1, y, "r: " || right(cdl_data.r, 5)) + DrawString(win, x2, y, "h: " || right(cdl_data.h, 3)) + y +:= dy + DrawString(win, x1, y, "g: " || right(cdl_data.g, 5)) + DrawString(win, x2, y, "s: " || right(cdl_data.s, 3)) + y +:= dy + DrawString(win, x1, y, "b: " || right(cdl_data.b, 5)) + DrawString(win, x2, y, "v: " || right(cdl_data.v, 3)) + + (\cdl_data.callback)(cdl_data.id, c) # invoke user callback, if any + return +end + +# Popup(win, x, y, w, h, proc, args[]) + +$define BorderWidth 4 +$define ShadowWidth 4 + +procedure Popup(args[]) #: create popup subwindow + local win, x, y, w, h, xx, yy, ww, hh, dx, dy, s, proc, retv, ampwin, save + + # Get parameters. + PushWin(args) + win := get(args) + x := get(args); integer(x) | runerr(101, \x) + y := get(args); integer(y) | runerr(101, \y) + w := \get(args) | 250; integer(w) | runerr(101, w) + h := \get(args) | 150; integer(h) | runerr(101, h) + proc := \get(args) | Event + + # Handle defaults + dx := WAttrib(win, "dx") + dy := WAttrib(win, "dy") + w >:= WAttrib(win, "width") # limit to size of full win + h >:= WAttrib(win, "height") + /x := (WAttrib(win, "width") - w) / 2 - dx # center the subwindow + /y := (WAttrib(win, "height") - h) / 2 - dy + + # Adjust subwindow configuration parameters. + xx := x - BorderWidth + yy := y - BorderWidth + ww := w + 2 * BorderWidth + ShadowWidth + hh := h + 2 * BorderWidth + ShadowWidth + + # Save original window contents. + save := ScratchCanvas(ww, hh, "__Popup__") | + stop("can't get ScratchCanvas in Popup()") + CopyArea(win, save, xx, yy, ww, hh) + + # Save &window and create subwindow. + ampwin := &window + &window := Clone(win) | stop("can't Clone in Popup()") + WAttrib("drawop=copy", "fillstyle=solid", "linestyle=solid", "linewidth=1", + "dx=" || (dx + x), "dy=" || (dy + y)) + DrawRectangle(-BorderWidth, -BorderWidth, ww-ShadowWidth-1, hh-ShadowWidth-1) + BevelRectangle(-BorderWidth + 1, -BorderWidth + 1, + ww - ShadowWidth - 2, hh - ShadowWidth - 2, BorderWidth) + FillRectangle(-BorderWidth + ShadowWidth, h + BorderWidth, + ww - ShadowWidth, ShadowWidth) + FillRectangle(w + BorderWidth, -BorderWidth + ShadowWidth, + ShadowWidth, hh - ShadowWidth) + Clip(0, 0, w, h) + EraseArea() + + # Flush any previously entered events on the window + while *Pending(win) > 0 do + Event(win) + + # Call proc; save result, if any, or use args as flag if none. + retv := (proc ! args) | args + + # Restore window and return result. Use &window to ensure drawop=copy. + Clip(-BorderWidth, -BorderWidth, ww, hh) + CopyArea(save, &window, 0, 0, ww, hh, -BorderWidth, -BorderWidth) + EraseArea(save) + &window := ampwin + return args ~=== retv +end |