summaryrefslogtreecommitdiff
path: root/src/runtime/fwindow.r
diff options
context:
space:
mode:
Diffstat (limited to 'src/runtime/fwindow.r')
-rw-r--r--src/runtime/fwindow.r2720
1 files changed, 2720 insertions, 0 deletions
diff --git a/src/runtime/fwindow.r b/src/runtime/fwindow.r
new file mode 100644
index 0000000..010286f
--- /dev/null
+++ b/src/runtime/fwindow.r
@@ -0,0 +1,2720 @@
+/*
+ * File: fwindow.r - Icon graphics interface
+ *
+ * Contents: Active, Bg, Color, CopyArea, Couple,
+ * DrawArc, DrawCircle, DrawCurve, DrawImage, DrawLine,
+ * DrawSegment, DrawPoint, DrawPolygon, DrawString,
+ * DrawRectangle, EraseArea, Event, Fg, FillArc, FillCircle,
+ * FillRectangle, FillPolygon, Font, FreeColor, GotoRC, GotoXY,
+ * NewColor, Pattern, PaletteChars, PaletteColor, PaletteKey,
+ * Pending, QueryPointer, ReadImage, TextWidth, Uncouple,
+ * WAttrib, WDefault, WFlush, WSync, WriteImage
+ */
+
+#ifdef Graphics
+
+/*
+ * Global variables.
+ * A poll counter for use in interp.c,
+ * the binding for the console window - FILE * for simplicity,
+ * &col, &row, &x, &y, &interval, timestamp, and modifier keys.
+ */
+int pollctr;
+FILE *ConsoleBinding = NULL;
+/*
+ * the global buffer used as work space for printing string, etc
+ */
+char ConsoleStringBuf[MaxReadStr * 48];
+char *ConsoleStringBufPtr = ConsoleStringBuf;
+unsigned long ConsoleFlags = 0; /* Console flags */
+
+
+
+"Active() - produce the next active window"
+
+function{0,1} Active()
+ abstract {
+ return file
+ }
+ body {
+ wsp ws;
+ if (!wstates || !(ws = getactivewindow())) fail;
+ return ws->filep;
+ }
+end
+
+
+"Alert(w,volume) - Alert the user"
+
+function{1} Alert(argv[argc])
+ abstract {
+ return file
+ }
+ body {
+ wbp w;
+ int warg = 0;
+ C_integer volume;
+ OptWindow(w);
+
+ if (argc == warg) volume = 0;
+ else if (!def:C_integer(argv[warg], 0, volume))
+ runerr(101, argv[warg]);
+ walert(w, volume);
+ ReturnWindow;
+ }
+end
+
+"Bg(w,s) - background color"
+
+function{0,1} Bg(argv[argc])
+ abstract {
+ return string
+ }
+ body {
+ wbp w;
+ char sbuf1[MaxCvtLen];
+ int len;
+ tended char *tmp;
+ int warg = 0;
+ OptWindow(w);
+
+ /*
+ * If there is a (non-window) argument we are setting by
+ * either a mutable color (negative int) or a string name.
+ */
+ if (argc - warg > 0) {
+ if (is:integer(argv[warg])) { /* mutable color or packed RGB */
+ if (isetbg(w, IntVal(argv[warg])) == Failed) fail;
+ }
+ else {
+ if (!cnv:C_string(argv[warg], tmp))
+ runerr(103,argv[warg]);
+ if(setbg(w, tmp) == Failed) fail;
+ }
+ }
+
+ /*
+ * In any event, this function returns the current background color.
+ */
+ getbg(w, sbuf1);
+ len = strlen(sbuf1);
+ Protect(tmp = alcstr(sbuf1, len), runerr(0));
+ return string(len, tmp);
+ }
+end
+
+
+"Clip(w, x, y, w, h) - set context clip rectangle"
+
+function{1} Clip(argv[argc])
+ abstract {
+ return file
+ }
+ body {
+ wbp w;
+ int warg = 0, r;
+ C_integer x, y, width, height;
+ wcp wc;
+ OptWindow(w);
+
+ wc = w->context;
+
+ if (argc <= warg) {
+ wc->clipx = wc->clipy = 0;
+ wc->clipw = wc->cliph = -1;
+ unsetclip(w);
+ }
+ else {
+ r = rectargs(w, argc, argv, warg, &x, &y, &width, &height);
+ if (r >= 0)
+ runerr(101, argv[r]);
+ wc->clipx = x;
+ wc->clipy = y;
+ wc->clipw = width;
+ wc->cliph = height;
+ setclip(w);
+ }
+
+ ReturnWindow;
+ }
+end
+
+
+"Clone(w, attribs...) - create a new context bound to w's canvas"
+
+function{1} Clone(argv[argc])
+ abstract {
+ return file
+ }
+ body {
+ wbp w, w2;
+ int warg = 0, n;
+ tended struct descrip sbuf, sbuf2;
+ char answer[128];
+ OptWindow(w);
+
+ Protect(w2 = alc_wbinding(), runerr(0));
+ w2->window = w->window;
+ w2->window->refcount++;
+
+ if (argc>warg && is:file(argv[warg])) {
+ if ((BlkLoc(argv[warg])->file.status & Fs_Window) == 0)
+ runerr(140,argv[warg]);
+ if ((BlkLoc(argv[warg])->file.status & (Fs_Read|Fs_Write)) == 0)
+ runerr(142,argv[warg]);
+ if (ISCLOSED((wbp)BlkLoc(argv[warg])->file.fd))
+ runerr(142,argv[warg]);
+ Protect(w2->context =
+ clone_context((wbp)BlkLoc(argv[warg])->file.fd), runerr(0));
+ warg++;
+ }
+ else {
+ Protect(w2->context = clone_context(w), runerr(0));
+ }
+
+ for (n = warg; n < argc; n++) {
+ if (!is:null(argv[n])) {
+ if (!cnv:tmp_string(argv[n], sbuf))
+ runerr(109, argv[n]);
+ switch (wattrib(w2, StrLoc(argv[n]), StrLen(argv[n]), &sbuf2, answer)) {
+ case Failed: fail;
+ case Error: runerr(0, argv[n]);
+ }
+ }
+ }
+
+ Protect(BlkLoc(result) =
+ (union block *)alcfile((FILE *)w2, Fs_Window|Fs_Read|Fs_Write,
+ &emptystr),runerr(0));
+ result.dword = D_File;
+ return result;
+ }
+end
+
+
+
+"Color(argv[]) - return or set color map entries"
+
+function{0,1} Color(argv[argc])
+ abstract {
+ return file ++ string
+ }
+ body {
+ wbp w;
+ int warg = 0;
+ int i, len;
+ C_integer n;
+ char *colorname, *srcname;
+ tended char *tmp;
+
+ OptWindow(w);
+ if (argc - warg == 0) runerr(101);
+
+ if (argc - warg == 1) { /* if this is a query */
+ CnvCInteger(argv[warg], n)
+ if ((colorname = get_mutable_name(w, n)) == NULL)
+ fail;
+ len = strlen(colorname);
+ Protect(tmp = alcstr(colorname, len), runerr(0));
+ return string(len, tmp);
+ }
+
+ CheckArgMultiple(2);
+
+ for (i = warg; i < argc; i += 2) {
+ CnvCInteger(argv[i], n)
+ if ((colorname = get_mutable_name(w, n)) == NULL)
+ fail;
+
+ if (is:integer(argv[i+1])) { /* copy another mutable */
+ if (IntVal(argv[i+1]) >= 0)
+ runerr(205, argv[i+1]); /* must be negative */
+ if ((srcname = get_mutable_name(w, IntVal(argv[i+1]))) == NULL)
+ fail;
+ if (set_mutable(w, n, srcname) == Failed) fail;
+ strcpy(colorname, srcname);
+ }
+
+ else { /* specified by name */
+ tended char *tmp;
+ if (!cnv:C_string(argv[i+1],tmp))
+ runerr(103,argv[i+1]);
+
+ if (set_mutable(w, n, tmp) == Failed) fail;
+ strcpy(colorname, tmp);
+ }
+ }
+
+ ReturnWindow;
+ }
+end
+
+
+"ColorValue(w,s) - produce RGB components from string color name"
+
+function{0,1} ColorValue(argv[argc])
+ abstract {
+ return string
+ }
+ body {
+ wbp w;
+ C_integer n;
+ int warg = 0, len;
+ long r, g, b;
+ tended char *s;
+ char tmp[24], *t;
+
+ if (is:file(argv[0]) && (BlkLoc(argv[0])->file.status & Fs_Window)) {
+ w = (wbp)BlkLoc(argv[0])->file.fd; /* explicit window */
+ warg = 1;
+ }
+ else if (is:file(kywd_xwin[XKey_Window]) &&
+ (BlkLoc(kywd_xwin[XKey_Window])->file.status & Fs_Window))
+ w = (wbp)BlkLoc(kywd_xwin[XKey_Window])->file.fd; /* &window */
+ else
+ w = NULL; /* no window (but proceed anyway) */
+
+ if (!(warg < argc))
+ runerr(103);
+
+ if (cnv:C_integer(argv[warg], n)) {
+ if (w != NULL && (t = get_mutable_name(w, n)))
+ Protect(s = alcstr(t, (word)strlen(t)+1), runerr(306));
+ else
+ fail;
+ }
+ else if (!cnv:C_string(argv[warg], s))
+ runerr(103,argv[warg]);
+
+ if (parsecolor(w, s, &r, &g, &b) == Succeeded) {
+ sprintf(tmp,"%ld,%ld,%ld", r, g, b);
+ len = strlen(tmp);
+ Protect(s = alcstr(tmp,len), runerr(306));
+ return string(len, s);
+ }
+ fail;
+ }
+end
+
+
+"CopyArea(w,w2,x,y,width,height,x2,y2) - copy area"
+
+function{0,1} CopyArea(argv[argc]) /* w,w2,x,y,width,height,x2,y2 */
+ abstract {
+ return file
+ }
+ body {
+ int warg = 0, n, r;
+ C_integer x, y, width, height, x2, y2, width2, height2;
+ wbp w, w2;
+ OptWindow(w);
+
+ /*
+ * 2nd window defaults to value of first window
+ */
+ if (argc>warg && is:file(argv[warg])) {
+ if ((BlkLoc(argv[warg])->file.status & Fs_Window) == 0)
+ runerr(140,argv[warg]);
+ if ((BlkLoc(argv[warg])->file.status & (Fs_Read|Fs_Write)) == 0)
+ runerr(142,argv[warg]);
+ w2 = (wbp)BlkLoc(argv[warg])->file.fd;
+ if (ISCLOSED(w2))
+ runerr(142,argv[warg]);
+ warg++;
+ }
+ else {
+ w2 = w;
+ }
+
+ /*
+ * x1, y1, width, and height follow standard conventions.
+ */
+ r = rectargs(w, argc, argv, warg, &x, &y, &width, &height);
+ if (r >= 0)
+ runerr(101, argv[r]);
+
+ /*
+ * get x2 and y2, ignoring width and height.
+ */
+ n = argc;
+ if (n > warg + 6)
+ n = warg + 6;
+ r = rectargs(w2, n, argv, warg + 4, &x2, &y2, &width2, &height2);
+ if (r >= 0)
+ runerr(101, argv[r]);
+
+ if (copyArea(w, w2, x, y, width, height, x2, y2) == Failed)
+ fail;
+ ReturnWindow;
+ }
+end
+
+/*
+ * Bind the canvas associated with w to the context
+ * associated with w2. If w2 is omitted, create a new context.
+ * Produces a new window variable.
+ */
+"Couple(w,w2) - couple canvas to context"
+
+function{0,1} Couple(w,w2)
+ abstract {
+ return file
+ }
+ body {
+ tended struct descrip sbuf, sbuf2;
+ wbp wb, wb_new;
+ wsp ws;
+
+ /*
+ * make the new binding
+ */
+ Protect(wb_new = alc_wbinding(), runerr(0));
+
+ /*
+ * if w is a file, then we bind to an existing window
+ */
+ if (is:file(w) && (BlkLoc(w)->file.status & Fs_Window)) {
+ wb = (wbp)(BlkLoc(w)->file.fd);
+ wb_new->window = ws = wb->window;
+ if (is:file(w2) && (BlkLoc(w2)->file.status & Fs_Window)) {
+ /*
+ * Bind an existing window to an existing context,
+ * and up the context's reference count.
+ */
+ if (rebind(wb_new, (wbp)(BlkLoc(w2)->file.fd)) == Failed) fail;
+ wb_new->context->refcount++;
+ }
+ else
+ runerr(140, w2);
+
+ /* bump up refcount to ws */
+ ws->refcount++;
+ }
+ else
+ runerr(140, w);
+
+ Protect(BlkLoc(result) =
+ (union block *)alcfile((FILE *)wb_new, Fs_Window|Fs_Read|Fs_Write,
+ &emptystr),runerr(0));
+ result.dword = D_File;
+ return result;
+ }
+end
+
+/*
+ * DrawArc(w, x1, y1, width1, height1, angle11, angle21,...)
+ */
+"DrawArc(argv[]){1} - draw arc"
+
+function{1} DrawArc(argv[argc])
+ abstract {
+ return file
+ }
+ body {
+ wbp w;
+ int i, j, r, warg = 0;
+ XArc arcs[MAXXOBJS];
+ C_integer x, y, width, height;
+ double a1, a2;
+
+ OptWindow(w);
+ j = 0;
+ for (i = warg; i < argc || i == warg; i += 6) {
+ if (j == MAXXOBJS) {
+ drawarcs(w, arcs, MAXXOBJS);
+ j = 0;
+ }
+ r = rectargs(w, argc, argv, i, &x, &y, &width, &height);
+ if (r >= 0)
+ runerr(101, argv[r]);
+
+ arcs[j].x = x;
+ arcs[j].y = y;
+ ARCWIDTH(arcs[j]) = width;
+ ARCHEIGHT(arcs[j]) = height;
+
+ /*
+ * Angle 1 processing. Computes in radians and 64'ths of a degree,
+ * bounds checks, and handles wraparound.
+ */
+ if (i + 4 >= argc || is:null(argv[i + 4]))
+ a1 = 0.0;
+ else {
+ if (!cnv:C_double(argv[i + 4], a1))
+ runerr(102, argv[i + 4]);
+ if (a1 >= 0.0)
+ a1 = fmod(a1, 2 * Pi);
+ else
+ a1 = -fmod(-a1, 2 * Pi);
+ }
+ /*
+ * Angle 2 processing
+ */
+ if (i + 5 >= argc || is:null(argv[i + 5]))
+ a2 = 2 * Pi;
+ else {
+ if (!cnv:C_double(argv[i + 5], a2))
+ runerr(102, argv[i + 5]);
+ if (fabs(a2) > 3 * Pi)
+ runerr(101, argv[i + 5]);
+ }
+ if (fabs(a2) >= 2 * Pi) {
+ a2 = 2 * Pi;
+ }
+ else {
+ if (a2 < 0.0) {
+ a1 += a2;
+ a2 = fabs(a2);
+ }
+ }
+ if (a1 < 0.0)
+ a1 = 2 * Pi - fmod(fabs(a1), 2 * Pi);
+ else
+ a1 = fmod(a1, 2 * Pi);
+ arcs[j].angle1 = ANGLE(a1);
+ arcs[j].angle2 = EXTENT(a2);
+
+ j++;
+ }
+
+ drawarcs(w, arcs, j);
+ ReturnWindow;
+ }
+end
+
+/*
+ * DrawCircle(w, x1, y1, r1, angle11, angle21, ...)
+ */
+"DrawCircle(argv[]){1} - draw circle"
+
+function{1} DrawCircle(argv[argc])
+ abstract {
+ return file
+ }
+ body {
+ wbp w;
+ int warg = 0, r;
+
+ OptWindow(w);
+ r = docircles(w, argc - warg, argv + warg, 0);
+ if (r < 0)
+ ReturnWindow;
+ else if (r >= argc - warg)
+ runerr(146);
+ else
+ runerr(102, argv[warg + r]);
+ }
+end
+
+/*
+ * DrawCurve(w,x1,y1,...xN,yN)
+ * Draw a smooth curve through the given points.
+ */
+"DrawCurve(argv[]){1} - draw curve"
+
+function{1} DrawCurve(argv[argc])
+ abstract {
+ return file
+ }
+ body {
+ wbp w;
+ int i, n, closed = 0, warg = 0;
+ C_integer dx, dy, x0, y0, xN, yN;
+ XPoint *points;
+
+ OptWindow(w);
+ CheckArgMultiple(2);
+
+ dx = w->context->dx;
+ dy = w->context->dy;
+
+ Protect(points = (XPoint *)malloc(sizeof(XPoint) * (n+2)), runerr(305));
+
+ if (n > 1) {
+ CnvCInteger(argv[warg], x0)
+ CnvCInteger(argv[warg + 1], y0)
+ CnvCInteger(argv[argc - 2], xN)
+ CnvCInteger(argv[argc - 1], yN)
+ if ((x0 == xN) && (y0 == yN)) {
+ closed = 1; /* duplicate the next to last point */
+ CnvCShort(argv[argc-4], points[0].x);
+ CnvCShort(argv[argc-3], points[0].y);
+ points[0].x += w->context->dx;
+ points[0].y += w->context->dy;
+ }
+ else { /* duplicate the first point */
+ CnvCShort(argv[warg], points[0].x);
+ CnvCShort(argv[warg + 1], points[0].y);
+ points[0].x += w->context->dx;
+ points[0].y += w->context->dy;
+ }
+ for (i = 1; i <= n; i++) {
+ int base = warg + (i-1) * 2;
+ CnvCShort(argv[base], points[i].x);
+ CnvCShort(argv[base + 1], points[i].y);
+ points[i].x += dx;
+ points[i].y += dy;
+ }
+ if (closed) { /* duplicate the second point */
+ points[i] = points[2];
+ }
+ else { /* duplicate the last point */
+ points[i] = points[i-1];
+ }
+ if (n < 3) {
+ drawlines(w, points+1, n);
+ }
+ else {
+ drawCurve(w, points, n+2);
+ }
+ }
+ free(points);
+ ReturnWindow;
+ }
+end
+
+
+"DrawImage(w,x,y,s) - draw bitmapped figure"
+
+function{0,1} DrawImage(argv[argc])
+ abstract {
+ return null++integer
+ }
+ body {
+ wbp w;
+ int warg = 0;
+ int c, i, width, height, row, p;
+ C_integer x, y;
+ word nchars;
+ unsigned char *s, *t, *z;
+ struct descrip d;
+ struct palentry *e;
+ OptWindow(w);
+
+ /*
+ * X or y can be defaulted but s is required.
+ * Validate x/y first so that the error message makes more sense.
+ */
+ if (argc - warg >= 1 && !def:C_integer(argv[warg], -w->context->dx, x))
+ runerr(101, argv[warg]);
+ if (argc - warg >= 2 && !def:C_integer(argv[warg + 1], -w->context->dy, y))
+ runerr(101, argv[warg + 1]);
+ if (argc - warg < 3)
+ runerr(103); /* missing s */
+ if (!cnv:tmp_string(argv[warg+2], d))
+ runerr(103, argv[warg + 2]);
+
+ x += w->context->dx;
+ y += w->context->dy;
+ /*
+ * Extract the Width and skip the following comma.
+ */
+ s = (unsigned char *)StrLoc(d);
+ z = s + StrLen(d); /* end+1 of string */
+ width = 0;
+ while (s < z && *s == ' ') /* skip blanks */
+ s++;
+ while (s < z && isdigit(*s)) /* scan number */
+ width = 10 * width + *s++ - '0';
+ while (s < z && *s == ' ') /* skip blanks */
+ s++;
+ if (width == 0 || *s++ != ',') /* skip comma */
+ fail;
+ while (s < z && *s == ' ') /* skip blanks */
+ s++;
+ if (s >= z) /* if end of string */
+ fail;
+
+ /*
+ * Check for a bilevel format.
+ */
+ if ((c = *s) == '#' || c == '~') {
+ s++;
+ nchars = 0;
+ for (t = s; t < z; t++)
+ if (isxdigit(*t))
+ nchars++; /* count hex digits */
+ else if (*t != PCH1 && *t != PCH2)
+ fail; /* illegal punctuation */
+ if (nchars == 0)
+ fail;
+ row = (width + 3) / 4; /* digits per row */
+ if (nchars % row != 0)
+ fail;
+ height = nchars / row;
+ if (blimage(w, x, y, width, height, c, s, (word)(z - s)) == Error)
+ runerr(305);
+ else
+ return nulldesc;
+ }
+
+ /*
+ * Extract the palette name and skip its comma.
+ */
+ c = *s++; /* save initial character */
+ p = 0;
+ while (s < z && isdigit(*s)) /* scan digits */
+ p = 10 * p + *s++ - '0';
+ while (s < z && *s == ' ') /* skip blanks */
+ s++;
+ if (s >= z || p == 0 || *s++ != ',') /* skip comma */
+ fail;
+ if (c == 'g' && p >= 2 && p <= 256) /* validate grayscale number */
+ p = -p;
+ else if (c != 'c' || p < 1 || p > 6) /* validate color number */
+ fail;
+
+ /*
+ * Scan the image to see which colors are needed.
+ */
+ e = palsetup(p);
+ if (e == NULL)
+ runerr(305);
+ for (i = 0; i < 256; i++)
+ e[i].used = 0;
+ nchars = 0;
+ for (t = s; t < z; t++) {
+ c = *t;
+ e[c].used = 1;
+ if (e[c].valid || e[c].transpt)
+ nchars++; /* valid color, or transparent */
+ else if (c != PCH1 && c != PCH2)
+ fail;
+ }
+ if (nchars == 0)
+ fail; /* empty image */
+ if (nchars % width != 0)
+ fail; /* not rectangular */
+
+ /*
+ * Call platform-dependent code to draw the image.
+ */
+ height = nchars / width;
+ i = strimage(w, x, y, width, height, e, s, (word)(z - s), 0);
+ if (i == 0)
+ return nulldesc;
+ else if (i < 0)
+ runerr(305);
+ else
+ return C_integer i;
+ }
+end
+
+/*
+ * DrawLine(w,x1,y1,...xN,yN)
+ */
+"DrawLine(argv[]){1} - draw line"
+
+function{1} DrawLine(argv[argc])
+ abstract {
+ return file
+ }
+ body {
+ wbp w;
+ int i, j, n, warg = 0;
+ XPoint points[MAXXOBJS];
+ int dx, dy;
+
+ OptWindow(w);
+ CheckArgMultiple(2);
+
+ dx = w->context->dx;
+ dy = w->context->dy;
+ for(i=0, j=0;i<n;i++, j++) {
+ int base = warg + i * 2;
+ if (j==MAXXOBJS) {
+ drawlines(w, points, MAXXOBJS);
+ points[0] = points[MAXXOBJS-1];
+ j = 1;
+ }
+ CnvCShort(argv[base], points[j].x);
+ CnvCShort(argv[base + 1], points[j].y);
+ points[j].x += dx;
+ points[j].y += dy;
+ }
+ drawlines(w, points, j);
+ ReturnWindow;
+ }
+end
+
+/*
+ * DrawPoint(w, x1, y1, ...xN, yN)
+ */
+"DrawPoint(argv[]){1} - draw point"
+
+function{1} DrawPoint(argv[argc])
+ abstract {
+ return file
+ }
+ body {
+ wbp w;
+ int i, j, n, warg = 0;
+ XPoint points[MAXXOBJS];
+ int dx, dy;
+
+ OptWindow(w);
+ CheckArgMultiple(2);
+
+ dx = w->context->dx;
+ dy = w->context->dy;
+ for(i=0, j=0; i < n; i++, j++) {
+ int base = warg + i * 2;
+ if (j == MAXXOBJS) {
+ drawpoints(w, points, MAXXOBJS);
+ j = 0;
+ }
+ CnvCShort(argv[base], points[j].x);
+ CnvCShort(argv[base + 1], points[j].y);
+ points[j].x += dx;
+ points[j].y += dy;
+ }
+ drawpoints(w, points, j);
+ ReturnWindow;
+ }
+end
+
+/*
+ * DrawPolygon(w,x1,y1,...xN,yN)
+ */
+"DrawPolygon(argv[]){1} - draw polygon"
+
+function{1} DrawPolygon(argv[argc])
+ abstract {
+ return file
+ }
+ body {
+ wbp w;
+ int i, j, n, base, dx, dy, warg = 0;
+ XPoint points[MAXXOBJS];
+
+ OptWindow(w);
+ CheckArgMultiple(2);
+
+ dx = w->context->dx;
+ dy = w->context->dy;
+
+ /*
+ * To make a closed polygon, start with the *last* point.
+ */
+ CnvCShort(argv[argc - 2], points[0].x);
+ CnvCShort(argv[argc - 1], points[0].y);
+ points[0].x += dx;
+ points[0].y += dy;
+
+ /*
+ * Now add all points from beginning to end, including last point again.
+ */
+ for(i = 0, j = 1; i < n; i++, j++) {
+ base = warg + i * 2;
+ if (j == MAXXOBJS) {
+ drawlines(w, points, MAXXOBJS);
+ points[0] = points[MAXXOBJS-1];
+ j = 1;
+ }
+ CnvCShort(argv[base], points[j].x);
+ CnvCShort(argv[base + 1], points[j].y);
+ points[j].x += dx;
+ points[j].y += dy;
+ }
+ drawlines(w, points, j);
+ ReturnWindow;
+ }
+end
+
+/*
+ * DrawRectangle(w, x1, y1, width1, height1, ..., xN, yN, widthN,heightN)
+ */
+"DrawRectangle(argv[]){1} - draw rectangle"
+
+function{1} DrawRectangle(argv[argc])
+ abstract {
+ return file
+ }
+ body {
+ wbp w;
+ int i, j, r, warg = 0;
+ XRectangle recs[MAXXOBJS];
+ C_integer x, y, width, height;
+
+ OptWindow(w);
+ j = 0;
+
+ for (i = warg; i < argc || i == warg; i += 4) {
+ r = rectargs(w, argc, argv, i, &x, &y, &width, &height);
+ if (r >= 0)
+ runerr(101, argv[r]);
+ if (j == MAXXOBJS) {
+ drawrectangles(w,recs,MAXXOBJS);
+ j = 0;
+ }
+ RECX(recs[j]) = x;
+ RECY(recs[j]) = y;
+ RECWIDTH(recs[j]) = width;
+ RECHEIGHT(recs[j]) = height;
+ j++;
+ }
+
+ drawrectangles(w, recs, j);
+ ReturnWindow;
+ }
+end
+
+/*
+ * DrawSegment(x11,y11,x12,y12,...,xN1,yN1,xN2,yN2)
+ */
+"DrawSegment(argv[]){1} - draw line segment"
+
+function{1} DrawSegment(argv[argc])
+ abstract {
+ return file
+ }
+ body {
+ wbp w;
+ int i, j, n, warg = 0, dx, dy;
+ XSegment segs[MAXXOBJS];
+
+ OptWindow(w);
+ CheckArgMultiple(4);
+
+ dx = w->context->dx;
+ dy = w->context->dy;
+ for(i=0, j=0; i < n; i++, j++) {
+ int base = warg + i * 4;
+ if (j == MAXXOBJS) {
+ drawsegments(w, segs, MAXXOBJS);
+ j = 0;
+ }
+ CnvCShort(argv[base], segs[j].x1);
+ CnvCShort(argv[base + 1], segs[j].y1);
+ CnvCShort(argv[base + 2], segs[j].x2);
+ CnvCShort(argv[base + 3], segs[j].y2);
+ segs[j].x1 += dx;
+ segs[j].x2 += dx;
+ segs[j].y1 += dy;
+ segs[j].y2 += dy;
+ }
+ drawsegments(w, segs, j);
+ ReturnWindow;
+ }
+end
+
+/*
+ * DrawString(w, x1, y1, s1, ..., xN, yN, sN)
+ */
+"DrawString(argv[]){1} - draw text"
+
+function{1} DrawString(argv[argc])
+ abstract {
+ return file
+ }
+ body {
+ wbp w;
+ int i, n, len, warg = 0;
+ char *s;
+
+ OptWindow(w);
+ CheckArgMultiple(3);
+
+ for(i=0; i < n; i++) {
+ C_integer x, y;
+ int base = warg + i * 3;
+ CnvCInteger(argv[base], x);
+ CnvCInteger(argv[base + 1], y);
+ x += w->context->dx;
+ y += w->context->dy;
+ CnvTmpString(argv[base + 2], argv[base + 2]);
+ s = StrLoc(argv[base + 2]);
+ len = StrLen(argv[base + 2]);
+ drawstrng(w, x, y, s, len);
+ }
+ ReturnWindow;
+ }
+end
+
+
+"EraseArea(w,x,y,width,height) - clear an area of the window"
+
+function{1} EraseArea(argv[argc])
+ abstract {
+ return file
+ }
+ body {
+ wbp w;
+ int warg = 0, i, r;
+ C_integer x, y, width, height;
+ OptWindow(w);
+
+ for (i = warg; i < argc || i == warg; i += 4) {
+ r = rectargs(w, argc, argv, i, &x, &y, &width, &height);
+ if (r >= 0)
+ runerr(101, argv[r]);
+ eraseArea(w, x, y, width, height);
+ }
+
+ ReturnWindow;
+ }
+end
+
+
+"Event(w) - return an event from a window"
+
+function{1} Event(argv[argc])
+ abstract {
+ return string ++ integer
+ }
+ body {
+ wbp w;
+ C_integer i;
+ tended struct descrip d;
+ int warg = 0;
+ OptWindow(w);
+
+ d = nulldesc;
+ i = wgetevent(w, &d);
+ if (i == 0) {
+ if (is:file(kywd_xwin[XKey_Window]) &&
+ w == (wbp)BlkLoc(kywd_xwin[XKey_Window])->file.fd)
+ lastEventWin = kywd_xwin[XKey_Window];
+ else
+ lastEventWin = argv[warg-1];
+ lastEvFWidth = FWIDTH((wbp)BlkLoc(lastEventWin)->file.fd);
+ lastEvLeading = LEADING((wbp)BlkLoc(lastEventWin)->file.fd);
+ lastEvAscent = ASCENT((wbp)BlkLoc(lastEventWin)->file.fd);
+ return d;
+ }
+ else if (i == -1)
+ runerr(141);
+ else
+ runerr(143);
+ }
+end
+
+
+"Fg(w,s) - foreground color"
+
+function{0,1} Fg(argv[argc])
+ abstract {
+ return string
+ }
+ body {
+ wbp w;
+ char sbuf1[MaxCvtLen];
+ int len;
+ tended char *tmp;
+ int warg = 0;
+ OptWindow(w);
+
+ /*
+ * If there is a (non-window) argument we are setting by
+ * either a mutable color (negative int) or a string name.
+ */
+ if (argc - warg > 0) {
+ if (is:integer(argv[warg])) { /* mutable color or packed RGB */
+ if (isetfg(w, IntVal(argv[warg])) == Failed) fail;
+ }
+ else {
+ if (!cnv:C_string(argv[warg], tmp))
+ runerr(103,argv[warg]);
+ if(setfg(w, tmp) == Failed) fail;
+ }
+ }
+
+ /*
+ * In any case, this function returns the current foreground color.
+ */
+ getfg(w, sbuf1);
+ len = strlen(sbuf1);
+ Protect(tmp = alcstr(sbuf1, len), runerr(0));
+ return string(len, tmp);
+ }
+end
+
+/*
+ * FillArc(w, x1, y1, width1, height1, angle11, angle21,...)
+ */
+"FillArc(argv[]){1} - fill arc"
+
+function{1} FillArc(argv[argc])
+ abstract {
+ return file
+ }
+ body {
+ wbp w;
+ int i, j, r, warg = 0;
+ XArc arcs[MAXXOBJS];
+ C_integer x, y, width, height;
+ double a1, a2;
+
+ OptWindow(w);
+ j = 0;
+ for (i = warg; i < argc || i == warg; i += 6) {
+ if (j == MAXXOBJS) {
+ fillarcs(w, arcs, MAXXOBJS);
+ j = 0;
+ }
+ r = rectargs(w, argc, argv, i, &x, &y, &width, &height);
+ if (r >= 0)
+ runerr(101, argv[r]);
+
+ arcs[j].x = x;
+ arcs[j].y = y;
+ ARCWIDTH(arcs[j]) = width;
+ ARCHEIGHT(arcs[j]) = height;
+
+ if (i + 4 >= argc || is:null(argv[i + 4])) {
+ a1 = 0.0;
+ }
+ else {
+ if (!cnv:C_double(argv[i + 4], a1))
+ runerr(102, argv[i + 4]);
+ if (a1 >= 0.0)
+ a1 = fmod(a1, 2 * Pi);
+ else
+ a1 = -fmod(-a1, 2 * Pi);
+ }
+ if (i + 5 >= argc || is:null(argv[i + 5]))
+ a2 = 2 * Pi;
+ else {
+ if (!cnv:C_double(argv[i + 5], a2))
+ runerr(102, argv[i + 5]);
+ if (fabs(a2) > 3 * Pi)
+ runerr(101, argv[i + 5]);
+ }
+ if (fabs(a2) >= 2 * Pi) {
+ a2 = 2 * Pi;
+ }
+ else {
+ if (a2 < 0.0) {
+ a1 += a2;
+ a2 = fabs(a2);
+ }
+ }
+ arcs[j].angle2 = EXTENT(a2);
+ if (a1 < 0.0)
+ a1 = 2 * Pi - fmod(fabs(a1), 2 * Pi);
+ else
+ a1 = fmod(a1, 2 * Pi);
+ arcs[j].angle1 = ANGLE(a1);
+
+ j++;
+ }
+
+ fillarcs(w, arcs, j);
+ ReturnWindow;
+ }
+end
+
+/*
+ * FillCircle(w, x1, y1, r1, angle11, angle21, ...)
+ */
+"FillCircle(argv[]){1} - draw filled circle"
+
+function{1} FillCircle(argv[argc])
+ abstract {
+ return file
+ }
+ body {
+ wbp w;
+ int warg = 0, r;
+
+ OptWindow(w);
+ r = docircles(w, argc - warg, argv + warg, 1);
+ if (r < 0)
+ ReturnWindow;
+ else if (r >= argc - warg)
+ runerr(146);
+ else
+ runerr(102, argv[warg + r]);
+ }
+end
+
+/*
+ * FillPolygon(w, x1, y1, ...xN, yN)
+ */
+"FillPolygon(argv[]){1} - fill polygon"
+
+function{1} FillPolygon(argv[argc])
+ abstract {
+ return file
+ }
+ body {
+ wbp w;
+ int i, n, warg = 0;
+ XPoint *points;
+ int dx, dy;
+
+ OptWindow(w);
+
+ CheckArgMultiple(2)
+
+ /*
+ * Allocate space for all the points in a contiguous array,
+ * because a FillPolygon must be performed in a single call.
+ */
+ n = argc>>1;
+ Protect(points = (XPoint *)malloc(sizeof(XPoint) * n), runerr(305));
+ dx = w->context->dx;
+ dy = w->context->dy;
+ for(i=0; i < n; i++) {
+ int base = warg + i * 2;
+ CnvCShort(argv[base], points[i].x);
+ CnvCShort(argv[base + 1], points[i].y);
+ points[i].x += dx;
+ points[i].y += dy;
+ }
+ fillpolygon(w, points, n);
+ free(points);
+ ReturnWindow;
+ }
+end
+
+/*
+ * FillRectangle(w, x1, y1, width1, height1,...,xN, yN, widthN, heightN)
+ */
+"FillRectangle(argv[]){1} - draw filled rectangle"
+
+function{1} FillRectangle(argv[argc])
+ abstract {
+ return file
+ }
+ body {
+ wbp w;
+ int i, j, r, warg = 0;
+ XRectangle recs[MAXXOBJS];
+ C_integer x, y, width, height;
+
+ OptWindow(w);
+ j = 0;
+
+ for (i = warg; i < argc || i == warg; i += 4) {
+ r = rectargs(w, argc, argv, i, &x, &y, &width, &height);
+ if (r >= 0)
+ runerr(101, argv[r]);
+ if (j == MAXXOBJS) {
+ fillrectangles(w,recs,MAXXOBJS);
+ j = 0;
+ }
+ RECX(recs[j]) = x;
+ RECY(recs[j]) = y;
+ RECWIDTH(recs[j]) = width;
+ RECHEIGHT(recs[j]) = height;
+ j++;
+ }
+
+ fillrectangles(w, recs, j);
+ ReturnWindow;
+ }
+end
+
+
+
+"Font(w,s) - get/set font"
+
+function{0,1} Font(argv[argc])
+ abstract {
+ return string
+ }
+ body {
+ tended char *tmp;
+ int len;
+ wbp w;
+ int warg = 0;
+ char buf[MaxCvtLen];
+ OptWindow(w);
+
+ if (warg < argc) {
+ if (!cnv:C_string(argv[warg],tmp))
+ runerr(103,argv[warg]);
+ if (setfont(w,&tmp) == Failed) fail;
+ }
+ getfntnam(w, buf);
+ len = strlen(buf);
+ Protect(tmp = alcstr(buf, len), runerr(0));
+ return string(len,tmp);
+ }
+end
+
+
+"FreeColor(argv[]) - free colors"
+
+function{1} FreeColor(argv[argc])
+ abstract {
+ return file
+ }
+ body {
+ wbp w;
+ int warg = 0;
+ int i;
+ C_integer n;
+ tended char *s;
+
+ OptWindow(w);
+ if (argc - warg == 0) runerr(103);
+
+ for (i = warg; i < argc; i++) {
+ if (is:integer(argv[i])) {
+ CnvCInteger(argv[i], n)
+ if (n < 0)
+ free_mutable(w, n);
+ }
+ else {
+ if (!cnv:C_string(argv[i], s))
+ runerr(103,argv[i]);
+ freecolor(w, s);
+ }
+ }
+
+ ReturnWindow;
+ }
+
+end
+
+
+"GotoRC(w,r,c) - move cursor to a particular text row and column"
+
+function{1} GotoRC(argv[argc])
+ abstract {
+ return file
+ }
+ body {
+ C_integer r, c;
+ wbp w;
+ int warg = 0;
+ OptWindow(w);
+
+ if (argc - warg < 1)
+ r = 1;
+ else
+ CnvCInteger(argv[warg], r)
+ if (argc - warg < 2)
+ c = 1;
+ else
+ CnvCInteger(argv[warg + 1], c)
+
+ /*
+ * turn the cursor off
+ */
+ hidecrsr(w->window);
+
+ w->window->y = ROWTOY(w, r);
+ w->window->x = COLTOX(w, c);
+ w->window->x += w->context->dx;
+ w->window->y += w->context->dy;
+
+ /*
+ * turn it back on at new location
+ */
+ UpdateCursorPos(w->window, w->context);
+ showcrsr(w->window);
+
+ ReturnWindow;
+ }
+end
+
+
+"GotoXY(w,x,y) - move cursor to a particular pixel location"
+
+function{1} GotoXY(argv[argc])
+ abstract {
+ return file
+ }
+ body {
+ wbp w;
+ C_integer x, y;
+ int warg = 0;
+ OptWindow(w);
+
+ if (argc - warg < 1)
+ x = 0;
+ else
+ CnvCInteger(argv[warg], x)
+ if (argc - warg < 2)
+ y = 0;
+ else
+ CnvCInteger(argv[warg + 1], y)
+
+ x += w->context->dx;
+ y += w->context->dy;
+
+ hidecrsr(w->window);
+
+ w->window->x = x;
+ w->window->y = y;
+
+ UpdateCursorPos(w->window, w->context);
+ showcrsr(w->window);
+
+ ReturnWindow;
+ }
+end
+
+
+"Lower(w) - lower w to the bottom of the window stack"
+
+function{1} Lower(argv[argc])
+ abstract {
+ return file
+ }
+ body {
+ wbp w;
+ int warg = 0;
+ OptWindow(w);
+ lowerWindow(w);
+ ReturnWindow;
+ }
+end
+
+
+"NewColor(w,s) - allocate an entry in the color map"
+
+function{0,1} NewColor(argv[argc])
+ abstract {
+ return integer
+ }
+ body {
+ wbp w;
+ int rv;
+ int warg = 0;
+ OptWindow(w);
+
+ if (mutable_color(w, argv+warg, argc-warg, &rv) == Failed) fail;
+ return C_integer rv;
+ }
+end
+
+
+
+"PaletteChars(w,p) - return the characters forming keys to palette p"
+
+function{0,1} PaletteChars(argv[argc])
+ abstract {
+ return string
+ }
+ body {
+ int n, warg;
+ extern char c1list[], c2list[], c3list[], c4list[];
+
+ if (is:file(argv[0]) && (BlkLoc(argv[0])->file.status & Fs_Window))
+ warg = 1;
+ else
+ warg = 0; /* window not required */
+ if (argc - warg < 1)
+ n = 1;
+ else
+ n = palnum(&argv[warg]);
+ switch (n) {
+ case -1: runerr(103, argv[warg]); /* not a string */
+ case 0: fail; /* unrecognized */
+ case 1: return string(90, c1list); /* c1 */
+ case 2: return string(9, c2list); /* c2 */
+ case 3: return string(31, c3list); /* c3 */
+ case 4: return string(73, c4list); /* c4 */
+ case 5: return string(141, (char *)allchars); /* c5 */
+ case 6: return string(241, (char *)allchars); /* c6 */
+ default: /* gn */
+ if (n >= -64)
+ return string(-n, c4list);
+ else
+ return string(-n, (char *)allchars);
+ }
+ }
+end
+
+
+"PaletteColor(w,p,s) - return color of key s in palette p"
+
+function{0,1} PaletteColor(argv[argc])
+ abstract {
+ return string
+ }
+ body {
+ int p, warg, len;
+ char tmp[24], *s;
+ struct palentry *e;
+ tended struct descrip d;
+
+ if (is:file(argv[0]) && (BlkLoc(argv[0])->file.status & Fs_Window))
+ warg = 1;
+ else
+ warg = 0; /* window not required */
+ if (argc - warg < 2)
+ runerr(103);
+ p = palnum(&argv[warg]);
+ if (p == -1)
+ runerr(103, argv[warg]);
+ if (p == 0)
+ fail;
+ if (!cnv:tmp_string(argv[warg + 1], d))
+ runerr(103, argv[warg + 1]);
+ if (StrLen(d) != 1)
+ runerr(205, d);
+ e = palsetup(p);
+ if (e == NULL)
+ runerr(305);
+ e += *StrLoc(d) & 0xFF;
+ if (!e->valid)
+ fail;
+ sprintf(tmp, "%ld,%ld,%ld", e->clr.red, e->clr.green, e->clr.blue);
+ len = strlen(tmp);
+ Protect(s = alcstr(tmp, len), runerr(306));
+ return string(len, s);
+ }
+end
+
+
+"PaletteKey(w,p,s) - return key of closest color to s in palette p"
+
+function{0,1} PaletteKey(argv[argc])
+ abstract {
+ return string
+ }
+ body {
+ wbp w;
+ int warg = 0, p;
+ C_integer n;
+ tended char *s;
+ long r, g, b;
+
+ if (is:file(argv[0]) && (BlkLoc(argv[0])->file.status & Fs_Window)) {
+ w = (wbp)BlkLoc(argv[0])->file.fd; /* explicit window */
+ warg = 1;
+ }
+ else if (is:file(kywd_xwin[XKey_Window]) &&
+ (BlkLoc(kywd_xwin[XKey_Window])->file.status & Fs_Window))
+ w = (wbp)BlkLoc(kywd_xwin[XKey_Window])->file.fd; /* &window */
+ else
+ w = NULL; /* no window (but proceed anyway) */
+
+ if (argc - warg < 2)
+ runerr(103);
+ p = palnum(&argv[warg]);
+ if (p == -1)
+ runerr(103, argv[warg]);
+ if (p == 0)
+ fail;
+
+ if (cnv:C_integer(argv[warg + 1], n)) {
+ if (w == NULL || (s = get_mutable_name(w, n)) == NULL)
+ fail;
+ }
+ else if (!cnv:C_string(argv[warg + 1], s))
+ runerr(103, argv[warg + 1]);
+
+ if (parsecolor(w, s, &r, &g, &b) == Succeeded)
+ return string(1, rgbkey(p, r / 65535.0, g / 65535.0, b / 65535.0));
+ else
+ fail;
+ }
+end
+
+
+"Pattern(w,s) - sets the context fill pattern by string name"
+
+function{1} Pattern(argv[argc])
+ abstract {
+ return file
+ }
+ body {
+ int warg = 0;
+ wbp w;
+ OptWindow(w);
+
+ if (argc - warg == 0)
+ runerr(103, nulldesc);
+
+ if (! cnv:string(argv[warg], argv[warg]))
+ runerr(103, nulldesc);
+
+ switch (SetPattern(w, StrLoc(argv[warg]), StrLen(argv[warg]))) {
+ case Error:
+ runerr(0, argv[warg]);
+ case Failed:
+ fail;
+ }
+
+ ReturnWindow;
+ }
+end
+
+
+"Pending(w,x[]) - produce a list of events pending on window"
+
+function{0,1} Pending(argv[argc])
+ abstract {
+ return list
+ }
+ body {
+ wbp w;
+ int warg = 0;
+ wsp ws;
+ int i;
+ OptWindow(w);
+
+ ws = w->window;
+ wsync(w);
+
+ /*
+ * put additional arguments to Pending on the pending list in
+ * guaranteed consecutive order.
+ */
+ for (i = warg; i < argc; i++) {
+ c_put(&(ws->listp), &argv[i]);
+ }
+
+ /*
+ * retrieve any events that might be relevant before returning the
+ * pending queue.
+ */
+ switch (pollevent()) {
+ case -1: runerr(141);
+ case 0: fail;
+ }
+ return ws->listp;
+ }
+end
+
+
+
+"Pixel(w,x,y,width,height) - produce the contents of some pixels"
+
+function{3} Pixel(argv[argc])
+ abstract {
+ return integer ++ string
+ }
+ body {
+ struct imgmem imem;
+ C_integer x, y, width, height;
+ wbp w;
+ int warg = 0, slen, r;
+ tended struct descrip lastval;
+ char strout[50];
+ OptWindow(w);
+
+ r = rectargs(w, argc, argv, warg, &x, &y, &width, &height);
+ if (r >= 0)
+ runerr(101, argv[r]);
+
+ {
+ int i, j;
+ long rv;
+ wsp ws = w->window;
+
+#ifndef max
+#define max(x,y) (((x)<(y))?(y):(x))
+#define min(x,y) (((x)>(y))?(y):(x))
+#endif
+
+ imem.x = max(x,0);
+ imem.y = max(y,0);
+ imem.width = min(width, (int)ws->width - imem.x);
+ imem.height = min(height, (int)ws->height - imem.y);
+
+ if (getpixel_init(w, &imem) == Failed) fail;
+
+ lastval = emptystr;
+
+ for (j=y; j < y + height; j++) {
+ for (i=x; i < x + width; i++) {
+ getpixel(w, i, j, &rv, strout, &imem);
+ slen = strlen(strout);
+ if (rv >= 0) {
+ int signal;
+ if (slen != StrLen(lastval) ||
+ strncmp(strout, StrLoc(lastval), slen)) {
+ Protect((StrLoc(lastval) = alcstr(strout, slen)), runerr(0));
+ StrLen(lastval) = slen;
+ }
+#if COMPILER
+ suspend lastval; /* memory leak on vanquish */
+#else /* COMPILER */
+ /*
+ * suspend, but free up imem if vanquished; RTL workaround
+ * Needs implementing under the compiler.
+ */
+ r_args[0] = lastval;
+#ifdef EventMon
+ if ((signal = interp(G_Fsusp, r_args)) != A_Resume) {
+#else /* EventMon */
+ if ((signal = interp(G_Csusp, r_args)) != A_Resume) {
+#endif /* EventMon */
+ tend = r_tend.previous;
+ getpixel_term(w, &imem);
+ VanquishReturn(signal);
+ }
+#endif /* COMPILER */
+ }
+ else {
+#if COMPILER
+ suspend C_integer rv; /* memory leak on vanquish */
+#else /* COMPILER */
+ int signal;
+ /*
+ * suspend, but free up imem if vanquished; RTL workaround
+ * Needs implementing under the compiler.
+ */
+ r_args[0].dword = D_Integer;
+ r_args[0].vword.integr = rv;
+#ifdef EventMon
+ if ((signal = interp(G_Fsusp, r_args)) != A_Resume) {
+#else /* EventMon */
+ if ((signal = interp(G_Csusp, r_args)) != A_Resume) {
+#endif /* EventMon */
+ tend = r_tend.previous;
+ getpixel_term(w, &imem);
+ VanquishReturn(signal);
+ }
+#endif /* COMPILER */
+ }
+ }
+ }
+ getpixel_term(w, &imem);
+ fail;
+ }
+ }
+end
+
+
+"QueryPointer(w) - produce mouse position"
+
+function{0,2} QueryPointer(w)
+
+ declare {
+ XPoint xp;
+ }
+ abstract {
+ return integer
+ }
+ body {
+ pollevent();
+ if (is:null(w)) {
+ query_rootpointer(&xp);
+ }
+ else {
+ if (!is:file(w) || !(BlkLoc(w)->file.status & Fs_Window))
+ runerr(140, w);
+ query_pointer((wbp)BlkLoc(w)->file.fd, &xp);
+ }
+ suspend C_integer xp.x;
+ suspend C_integer xp.y;
+ fail;
+ }
+end
+
+
+"Raise(w) - raise w to the top of the window stack"
+
+function{1} Raise(argv[argc])
+ abstract {
+ return file
+ }
+ body {
+ wbp w;
+ int warg = 0;
+ OptWindow(w);
+ raiseWindow(w);
+ ReturnWindow;
+ }
+end
+
+
+"ReadImage(w, s, x, y, p) - load image file"
+
+function{0,1} ReadImage(argv[argc])
+ abstract {
+ return integer
+ }
+ body {
+ wbp w;
+ char filename[MaxPath + 1];
+ tended char *tmp;
+ int status, warg = 0;
+ C_integer x, y;
+ int p, r;
+ struct imgdata imd;
+ OptWindow(w);
+
+ if (argc - warg == 0)
+ runerr(103,nulldesc);
+ if (!cnv:C_string(argv[warg], tmp))
+ runerr(103,argv[warg]);
+
+ /*
+ * x and y must be integers; they default to the upper left pixel.
+ */
+ if (argc - warg < 2) x = -w->context->dx;
+ else if (!def:C_integer(argv[warg+1], -w->context->dx, x))
+ runerr(101, argv[warg+1]);
+ if (argc - warg < 3) y = -w->context->dy;
+ else if (!def:C_integer(argv[warg+2], -w->context->dy, y))
+ runerr(101, argv[warg+2]);
+
+ /*
+ * p is an optional palette name.
+ */
+ if (argc - warg < 4 || is:null(argv[warg+3])) p = 0;
+ else {
+ p = palnum(&argv[warg+3]);
+ if (p == -1)
+ runerr(103, argv[warg+3]);
+ if (p == 0)
+ fail;
+ }
+
+ x += w->context->dx;
+ y += w->context->dy;
+ strncpy(filename, tmp, MaxPath); /* copy to loc that won't move */
+ filename[MaxPath] = '\0';
+
+ /*
+ * First try to read as a GIF file.
+ * If that doesn't work, try platform-dependent image reading code.
+ */
+ r = readGIF(filename, p, &imd);
+ if (r == Succeeded) {
+ status = strimage(w, x, y, imd.width, imd.height, imd.paltbl,
+ imd.data, (word)imd.width * (word)imd.height, 0);
+ if (status < 0)
+ r = Error;
+ free((pointer)imd.paltbl);
+ free((pointer)imd.data);
+ }
+ else if (r == Failed)
+ r = readimage(w, filename, x, y, &status);
+ if (r == Error)
+ runerr(305);
+ if (r == Failed)
+ fail;
+ if (status == 0)
+ return nulldesc;
+ else
+ return C_integer (word)status;
+ }
+end
+
+
+
+"WSync(w) - synchronize with server"
+
+function{1} WSync(w)
+ abstract {
+ return file++null
+ }
+ body {
+ wbp _w_;
+
+ if (is:null(w)) {
+ _w_ = NULL;
+ }
+ else if (!is:file(w)) runerr(140,w);
+ else {
+ if (!(BlkLoc(w)->file.status & Fs_Window))
+ runerr(140,w);
+ _w_ = (wbp)BlkLoc(w)->file.fd;
+ }
+
+ wsync(_w_);
+ pollevent();
+ return w;
+ }
+end
+
+
+"TextWidth(w,s) - compute text pixel width"
+
+function{1} TextWidth(argv[argc])
+ abstract {
+ return integer
+ }
+ body {
+ wbp w;
+ int warg=0;
+ C_integer i;
+ OptWindow(w);
+
+ if (warg == argc) runerr(103,nulldesc);
+ else if (!cnv:tmp_string(argv[warg],argv[warg]))
+ runerr(103,argv[warg]);
+
+ i = TEXTWIDTH(w, StrLoc(argv[warg]), StrLen(argv[warg]));
+ return C_integer i;
+ }
+end
+
+
+"Uncouple(w) - uncouple window"
+
+function{1} Uncouple(w)
+ abstract {
+ return file
+ }
+ body {
+ wbp _w_;
+ if (!is:file(w)) runerr(140,w);
+ if ((BlkLoc(w)->file.status & Fs_Window) == 0) runerr(140,w);
+ if ((BlkLoc(w)->file.status & (Fs_Read|Fs_Write)) == 0) runerr(142,w);
+ _w_ = (wbp)BlkLoc(w)->file.fd;
+ BlkLoc(w)->file.status = Fs_Window; /* no longer open for read/write */
+ free_binding(_w_);
+ return w;
+ }
+end
+
+"WAttrib(argv[]) - read/write window attributes"
+
+function{*} WAttrib(argv[argc])
+ abstract {
+ return file++string++integer
+ }
+ body {
+ wbp w, wsave;
+ word n;
+ tended struct descrip sbuf, sbuf2;
+ char answer[128];
+ int pass, config = 0;
+ int warg = 0;
+ OptWindow(w);
+
+ wsave = w;
+ /*
+ * Loop through the arguments.
+ */
+ for (pass = 1; pass <= 2; pass++) {
+ w = wsave;
+ if (config && pass == 2) {
+ if (do_config(w, config) == Failed) fail;
+ }
+ for (n = warg; n < argc; n++) {
+ if (is:file(argv[n])) {/* Current argument is a file */
+ /*
+ * Switch the current file to the file named by the
+ * current argument providing it is a file. argv[n]
+ * is made to be a empty string to avoid a special case.
+ */
+ if (!(BlkLoc(argv[n])->file.status & Fs_Window))
+ runerr(140,argv[n]);
+ w = (wbp)BlkLoc(argv[n])->file.fd;
+ if (config && pass == 2) {
+ if (do_config(w, config) == Failed) fail;
+ }
+ }
+ else { /* Current argument should be a string */
+ /*
+ * In pass 1, a null argument is an error; failed attribute
+ * assignments are turned into null descriptors for pass 2
+ * and are ignored.
+ */
+ if (is:null(argv[n])) {
+ if (pass == 2)
+ continue;
+ else runerr(109, argv[n]);
+ }
+ /*
+ * If its an integer or real, it can't be a valid attribute.
+ */
+ if (is:integer(argv[n]) || is:real(argv[n])) {
+ runerr(145, argv[n]);
+ }
+ /*
+ * Convert the argument to a string
+ */
+ if (!cnv:tmp_string(argv[n], sbuf))
+ runerr(109, argv[n]);
+ /*
+ * Various parts of the code can't handle long attributes.
+ * (ugh.)
+ */
+ if (StrLen(sbuf) > 127)
+ runerr(145, argv[n]);
+ /*
+ * Read/write the attribute
+ */
+ if (pass == 1) {
+ char *tmp_s = StrLoc(sbuf);
+ char *tmp_s2 = StrLoc(sbuf) + StrLen(sbuf);
+ for ( ; tmp_s < tmp_s2; tmp_s++)
+ if (*tmp_s == '=') break;
+ if (tmp_s < tmp_s2) {
+ /*
+ * pass 1: perform attribute assignments
+ */
+ switch (wattrib(w, StrLoc(sbuf), StrLen(sbuf),
+ &sbuf2, answer)) {
+ case Failed:
+ /*
+ * Mark the attribute so we don't produce a result
+ */
+ argv[n] = nulldesc;
+ continue;
+ case Error: runerr(0, argv[n]);
+ }
+ if (StrLen(sbuf) > 4) {
+ if (!strncmp(StrLoc(sbuf), "pos=", 4)) config |= 1;
+ if (StrLen(sbuf) > 5) {
+ if (!strncmp(StrLoc(sbuf), "posx=", 5)) config |= 1;
+ if (!strncmp(StrLoc(sbuf), "posy=", 5)) config |= 1;
+ if (!strncmp(StrLoc(sbuf), "rows=", 5)) config |= 2;
+ if (!strncmp(StrLoc(sbuf), "size=", 5)) config |= 2;
+ if (StrLen(sbuf) > 6) {
+ if (!strncmp(StrLoc(sbuf), "width=", 6))
+ config |= 2;
+ if (!strncmp(StrLoc(sbuf), "lines=", 6))
+ config |= 2;
+ if (StrLen(sbuf) > 7) {
+ if (!strncmp(StrLoc(sbuf), "height=", 7))
+ config |= 2;
+ if (!strncmp(StrLoc(sbuf), "resize=", 7))
+ config |= 2;
+ if (StrLen(sbuf) > 8) {
+ if (!strncmp(StrLoc(sbuf), "columns=", 8))
+ config |= 2;
+ if (StrLen(sbuf) > 9) {
+ if (!strncmp(StrLoc(sbuf),
+ "geometry=", 9))
+ config |= 3;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ /*
+ * pass 2: perform attribute queries, suspend result(s)
+ */
+ else if (pass==2) {
+ char *stmp, *stmp2;
+ /*
+ * Turn assignments into queries.
+ */
+ for( stmp = StrLoc(sbuf),
+ stmp2 = stmp + StrLen(sbuf); stmp < stmp2; stmp++)
+ if (*stmp == '=') break;
+ if (stmp < stmp2)
+ StrLen(sbuf) = stmp - StrLoc(sbuf);
+
+ switch (wattrib(w, StrLoc(sbuf), StrLen(sbuf),
+ &sbuf2, answer)) {
+ case Failed: continue;
+ case Error: runerr(0, argv[n]);
+ }
+ if (is:string(sbuf2))
+ Protect(StrLoc(sbuf2) = alcstr(StrLoc(sbuf2),StrLen(sbuf2)), runerr(0));
+ suspend sbuf2;
+ }
+ }
+ }
+ }
+ fail;
+ }
+end
+
+
+"WDefault(w,program,option) - get a default value from the environment"
+
+function{0,1} WDefault(argv[argc])
+ abstract {
+ return string
+ }
+ body {
+ wbp w;
+ int warg = 0;
+ long l;
+ tended char *prog, *opt;
+ char sbuf1[MaxCvtLen];
+ OptWindow(w);
+
+ if (argc-warg < 2)
+ runerr(103);
+ if (!cnv:C_string(argv[warg],prog))
+ runerr(103,argv[warg]);
+ if (!cnv:C_string(argv[warg+1],opt))
+ runerr(103,argv[warg+1]);
+
+ if (getdefault(w, prog, opt, sbuf1) == Failed) fail;
+ l = strlen(sbuf1);
+ Protect(prog = alcstr(sbuf1,l),runerr(0));
+ return string(l,prog);
+ }
+end
+
+
+"WFlush(w) - flush all output to window w"
+
+function{1} WFlush(argv[argc])
+ abstract {
+ return file
+ }
+ body {
+ wbp w;
+ int warg = 0;
+ OptWindow(w);
+ wflush(w);
+ ReturnWindow;
+ }
+end
+
+
+"WriteImage(w,filename,x,y,width,height) - write an image to a file"
+
+function{0,1} WriteImage(argv[argc])
+ abstract {
+ return file
+ }
+ body {
+ wbp w;
+ int r;
+ C_integer x, y, width, height, warg = 0;
+ tended char *s;
+ OptWindow(w);
+
+ if (argc - warg == 0)
+ runerr(103, nulldesc);
+ else if (!cnv:C_string(argv[warg], s))
+ runerr(103, argv[warg]);
+
+ r = rectargs(w, argc, argv, warg + 1, &x, &y, &width, &height);
+ if (r >= 0)
+ runerr(101, argv[r]);
+
+ /*
+ * clip image to window, and fail if zero-sized.
+ * (the casts to long are necessary to avoid unsigned comparison.)
+ */
+ if (x < 0) {
+ width += x;
+ x = 0;
+ }
+ if (y < 0) {
+ height += y;
+ y = 0;
+ }
+ if (x + width > (long) w->window->width)
+ width = w->window->width - x;
+ if (y + height > (long) w->window->height)
+ height = w->window->height - y;
+ if (width <= 0 || height <= 0)
+ fail;
+
+ /*
+ * try platform-dependent code first; it will reject the call
+ * if the file name s does not specify a platform-dependent format.
+ */
+ r = dumpimage(w, s, x, y, width, height);
+ if (r == NoCvt)
+ r = writeGIF(w, s, x, y, width, height);
+ if (r != Succeeded)
+ fail;
+ ReturnWindow;
+ }
+end
+
+#ifdef WinExtns
+
+"WinPlayMedia(w,x[]) - play a multimedia resource"
+
+function{0,1} WinPlayMedia(argv[argc])
+ abstract {
+ return null
+ }
+ body {
+ wbp w;
+ tended char *tmp;
+ int warg = 0;
+ int i;
+ wsp ws;
+ word n;
+ OptWindow(w);
+
+ ws = w->window;
+ for (n = warg; n < argc; n++) {
+ if (!cnv:C_string(argv[n], tmp))
+ runerr(103,argv[warg]);
+ if (playmedia(w, tmp) == Failed) fail;
+ }
+ return nulldesc;
+ }
+end
+
+
+
+/*
+ * Simple Windows-native pushbutton
+ */
+"WinButton(w, s, x, y, wd, ht) - install a pushbutton with label s on window w"
+
+function{0,1} WinButton(argv[argc])
+ abstract {
+ return file
+ }
+ body {
+ wbp w;
+ wsp ws;
+ int i, ii, i2, r, total = 0;
+ C_integer x, y, width, height, warg = 0;
+ tended char *s, *s2;
+ tended struct descrip d;
+ tended struct b_list *hp;
+ OptWindow(w);
+ ws = w->window;
+ if (warg == argc) fail;
+ if (!cnv:C_string(argv[warg], s)) runerr(103, argv[warg]);
+ warg++;
+ /*
+ * look for an existing button with this id.
+ */
+ for(i = 0; i < ws->nChildren; i++) {
+ if (!strcmp(s, ws->child[i].id) && ws->child[i].type==CHILD_BUTTON)
+ break;
+ }
+ /*
+ * create a new button if none is found
+ */
+ if (i == ws->nChildren) {
+ ws->nChildren++;
+ ws->child = realloc(ws->child,
+ ws->nChildren * sizeof(childcontrol));
+ makebutton(ws, ws->child + i, s);
+ }
+
+ if (warg >= argc) x = 0;
+ else if (!def:C_integer(argv[warg], 0, x))
+ runerr(101, argv[warg]);
+ warg++;
+ if (warg >= argc) y = 0;
+ else if (!def:C_integer(argv[warg], 0, y))
+ runerr(101, argv[warg]);
+ warg++;
+ /*
+ * default width is width of text in system font + 2 chars
+ */
+ ii = sysTextWidth(w, s, strlen(s)) + 10;
+ if (warg >= argc) width = i2;
+ else if (!def:C_integer(argv[warg], i2, width))
+ runerr(101, argv[warg]);
+ warg++;
+ /*
+ * default height is height of text in system font * 7/4
+ */
+ i2 = sysFontHeight(w) * 7 / 4;
+ if (warg >= argc) height = i2;
+ else if (!def:C_integer(argv[warg], i2, height))
+ runerr(101, argv[warg]);
+
+ movechild(ws->child + i, x, y, width, height);
+ ReturnWindow;
+ }
+end
+
+"WinScrollBar(w, s, i1, i2, i3, x, y, wd, ht) - install a scrollbar"
+
+function{0,1} WinScrollBar(argv[argc])
+ abstract {
+ return file
+ }
+ body {
+ wbp w;
+ wsp ws;
+ C_integer x, y, width, height, warg = 0, i1, i2, i3, i, ii;
+ tended char *s, *s2;
+ tended struct descrip d;
+ tended struct b_list *hp;
+
+ OptWindow(w);
+ ws = w->window;
+ if (warg == argc) fail;
+ if (!cnv:C_string(argv[warg], s)) runerr(103, argv[warg]);
+ warg++;
+ /*
+ * look for an existing scrollbar with this id.
+ */
+ for(i = 0; i < ws->nChildren; i++) {
+ if (!strcmp(s, ws->child[i].id) && ws->child[i].type==CHILD_EDIT)
+ break;
+ }
+ /*
+ * i1, the min of the scrollbar range, defaults to 0
+ */
+ if (warg >= argc) i1 = 0;
+ else if (!def:C_integer(argv[warg], 0, i1)) runerr(101, argv[warg]);
+ warg++;
+ /*
+ * i2, the max of the scrollbar range, defaults to 100
+ */
+ if (warg >= argc) i2 = 100;
+ else if (!def:C_integer(argv[warg], 100, i2)) runerr(101, argv[warg]);
+ warg++;
+ /*
+ * create a new scrollbar at end of array if none was found
+ */
+ if (i == ws->nChildren) {
+ ws->nChildren++;
+ ws->child = realloc(ws->child, ws->nChildren * sizeof(childcontrol));
+ makescrollbar(ws, ws->child + i, s, i1, i2);
+ }
+ /*
+ * i3, the interval, defaults to 10
+ */
+ if (warg >= argc) i3 = 10;
+ else if (!def:C_integer(argv[warg], 10, i3))
+ runerr(101, argv[warg]);
+ warg++;
+ /*
+ * x defaults to the right edge of the window - system scrollbar width
+ */
+ ii = ws->width - sysScrollWidth();
+ if (warg >= argc) x = ii;
+ else if (!def:C_integer(argv[warg], ii, x))
+ runerr(101, argv[warg]);
+ warg++;
+ /*
+ * y defaults to 0
+ */
+ if (warg >= argc) y = 0;
+ else if (!def:C_integer(argv[warg], 0, y))
+ runerr(101, argv[warg]);
+ warg++;
+ /*
+ * width defaults to system scrollbar width
+ */
+ ii = sysScrollWidth();
+ if (warg >= argc) width = ii;
+ else if (!def:C_integer(argv[warg], ii, width))
+ runerr(101, argv[warg]);
+ warg++;
+ /*
+ * height defaults to height of the client window
+ */
+ if (warg >= argc) height = ws->height;
+ else if (!def:C_integer(argv[warg], ws->height, height))
+ runerr(101, argv[warg]);
+
+ movechild(ws->child + i, x, y, width, height);
+ ReturnWindow;
+ }
+end
+
+/*
+ * Simple Windows-native menu bar
+ */
+"WinMenuBar(w,L1,L2,...) - install a set of top-level menus"
+
+function{0,1} WinMenuBar(argv[argc])
+ abstract {
+ return file
+ }
+ body {
+ wbp w;
+ wsp ws;
+ int i, total = 0;
+ C_integer x, y, warg = 0;
+ tended char *s;
+ tended struct descrip d;
+ OptWindow(w);
+ ws = w->window;
+
+ if (warg == argc) fail;
+ for (i = warg; i < argc; i++) {
+ if (!is:list(argv[i])) runerr(108, argv[i]);
+ total += BlkLoc(argv[i])->list.size;
+ }
+ /*
+ * free up memory for the old menu map
+ */
+ if (ws->nmMapElems) {
+ for (i=0; i<ws->nmMapElems; i++) free(ws->menuMap[i]);
+ free(ws->menuMap);
+ }
+ ws->menuMap = (char **)calloc(total, sizeof(char *));
+
+ if (nativemenubar(w, total, argc, argv, warg, &d) == Error)
+ runerr(103, d);
+ ReturnWindow;
+ }
+end
+
+/*
+ * Windows-native editor
+ */
+"WinEditRegion(w, s, s2, x, y, wd, ht) = install an edit box with label s"
+
+function{0, 1} WinEditRegion(argv[argc])
+ abstract {
+ return file ++ string
+ }
+ body {
+ wbp w;
+ wsp ws;
+ tended char *s, *s2;
+ C_integer i, x, y, width, height, warg = 0;
+ OptWindow(w);
+ ws = w->window;
+ if (warg == argc) fail;
+ if (!cnv:C_string(argv[warg], s))
+ runerr(103, argv[warg]);
+ warg++;
+ /*
+ * look for an existing edit region with this id.
+ */
+ for(i = 0; i < ws->nChildren; i++) {
+ if (!strcmp(s, ws->child[i].id) && ws->child[i].type==CHILD_EDIT)
+ break;
+ }
+ /*
+ * create a new edit region if none is found
+ */
+ if (i == ws->nChildren) {
+ ws->nChildren++;
+ ws->child = realloc(ws->child, ws->nChildren * sizeof(childcontrol));
+ makeeditregion(w, ws->child + i, s);
+ }
+ /*
+ * Invoked with no value, return the current value of an existing
+ * edit region (entire buffer is one gigantic string).
+ */
+ else if (warg == argc) {
+ geteditregion(ws->child + i, &result);
+ return result;
+ }
+ /*
+ * Assign a value (s2 string contents) or perform editing command
+ */
+ if (is:null(argv[warg])) s2 = NULL;
+ else if (!cnv:C_string(argv[warg], s2)) runerr(103, argv[warg]);
+ warg++;
+
+ if (warg >= argc) x = 0;
+ else if (!def:C_integer(argv[warg], 0, x)) runerr(101, argv[warg]);
+ warg++;
+ if (warg >= argc) y = 0;
+ else if (!def:C_integer(argv[warg], 0, y)) runerr(101, argv[warg]);
+ warg++;
+ if (warg >= argc) width = ws->width - x;
+ else if (!def:C_integer(argv[warg], ws->width -x, width))
+ runerr(101, argv[warg]);
+ warg++;
+ if (warg >= argc) height = ws->height - y;
+ else if (!def:C_integer(argv[warg], ws->height - y, height))
+ runerr(101, argv[warg]);
+
+ if (s2 && !strcmp("!clear", s2)) {
+ cleareditregion(ws->child + i);
+ s2 = NULL;
+ }
+ else if (s2 && !strcmp("!copy", s2)) {
+ copyeditregion(ws->child + i);
+ s2 = NULL;
+ }
+ else if (s2 && !strcmp("!cut", s2)) {
+ cuteditregion(ws->child + i);
+ s2 = NULL;
+ }
+ else if (s2 && !strcmp("!paste", s2)) {
+ pasteeditregion(ws->child + i);
+ s2 = NULL;
+ }
+ else if (s2 && !strcmp("!undo", s2)) {
+ if (undoeditregion(ws->child + i) == Failed) fail;
+ s2 = NULL;
+ }
+ else if (s2 && !strncmp("!modified=", s2, 10)) {
+ setmodifiededitregion(ws->child + i, atoi(s2+10));
+ s2 = NULL;
+ }
+ else if (s2 && !strcmp("!modified", s2)) {
+ if (modifiededitregion(ws->child + i) == Failed) fail;
+ s2 = NULL;
+ }
+ else if (s2 && !strncmp("!font=", s2, 6)) {
+ if (setchildfont(ws->child + i, s2 + 6) == Succeeded) {
+ ReturnWindow;
+ }
+ else fail;
+ }
+ else if (s2 && !strcmp("!setsel", s2)) {
+ setchildselection(ws, ws->child + i, x, y);
+ ReturnWindow;
+ }
+
+ if (s2) {
+ seteditregion(ws->child + i, s2);
+ }
+ movechild(ws->child + i, x, y, width, height);
+ setfocusonchild(ws, ws->child + i, width, height);
+ ReturnWindow;
+ }
+end
+
+
+/*
+ * common dialog functions
+ */
+
+"WinColorDialog(w,s) - choose a color for a window's context"
+
+function{0,1} WinColorDialog(argv[argc])
+ abstract {
+ return string
+ }
+ body {
+ wbp w;
+ C_integer x, y, width, height, warg = 0;
+ long r, g, b;
+ tended char *s;
+ char buf[64], *tmp = buf;
+ OptWindow(w);
+
+ if (warg < argc) {
+ if (is:null(argv[warg])) s = "white";
+ else if (!cnv:C_string(argv[warg], s)) runerr(103, argv[warg]);
+ }
+ else s = "white";
+ if (parsecolor(w, s, &r, &g, &b) == Failed) fail;
+
+ if (nativecolordialog(w, r, g, b, buf) == NULL) fail;
+ StrLoc(result) = alcstr(buf, strlen(buf));
+ StrLen(result) = strlen(buf);
+ return result;
+ }
+end
+
+"WinFontDialog(w,s) - choose a font for a window's context"
+
+function{0,1} WinFontDialog(argv[argc])
+ abstract {
+ return string
+ }
+ body {
+ wbp w;
+ int r;
+ C_integer x, y, width, height, warg = 0, fheight;
+ int flags;
+ tended char *s;
+ char buf[64], *tmp = buf;
+ OptWindow(w);
+
+ if (warg < argc) {
+ if (is:null(argv[warg])) s = "fixed";
+ else if (!cnv:C_string(argv[warg], s)) runerr(103, argv[warg]);
+ }
+ else s = "fixed";
+
+ parsefont(s, buf, &flags, &fheight);
+
+ if (nativefontdialog(w, buf, flags, fheight) == Failed) fail;
+ StrLoc(result) = alcstr(buf, strlen(buf));
+ StrLen(result) = strlen(buf);
+ return result;
+ }
+end
+
+
+"WinOpenDialog(w,s1,s2,i,s3,j) - choose a file to open"
+
+function{0,1} WinOpenDialog(argv[argc])
+ abstract {
+ return string
+ }
+ body {
+ wbp w;
+ int len, slen;
+ C_integer i, j, x, y, width, height, warg = 0;
+ char buf2[64], buf3[256], chReplace;
+ char *tmpstr;
+ tended char *s1, *s2, *s3;
+ OptWindow(w);
+
+ if (warg >= argc || is:null(argv[warg])) {
+ s1 = "Open:";
+ }
+ else if (!cnv:C_string(argv[warg], s1)) {
+ runerr(103, argv[warg]);
+ }
+ warg++;
+
+ if (warg >= argc || is:null(argv[warg])) {
+ s2 = "";
+ }
+ else if (!cnv:C_string(argv[warg], s2)) {
+ runerr(103, argv[warg]);
+ }
+ warg++;
+
+ if (warg >= argc) {
+ i = 50;
+ }
+ else if (!def:C_integer(argv[warg], 50, i)) {
+ runerr(101, argv[warg]);
+ }
+ warg++;
+
+ if (warg >= argc || is:null(argv[warg])) {
+ strcpy(buf3,"All Files(*.*)|*.*|");
+ s3 = buf3;
+ }
+ else if (!cnv:C_string(argv[warg], s3)) {
+ runerr(103, argv[warg]);
+ }
+ else {
+ strncpy(buf3, s3, 255);
+ buf3[255] = '\0';
+ s3 = buf3;
+ }
+ chReplace = s3[strlen(s3)-1];
+ slen = strlen(s3);
+ for(j=0; j < slen; j++)
+ if(s3[j] == chReplace) s3[j] = '\0';
+ warg++;
+
+ if (warg >= argc) {
+ j = 1;
+ }
+ else if (!def:C_integer(argv[warg], 1, j)) {
+ runerr(101, argv[warg]);
+ }
+ warg++;
+
+ if ((tmpstr = nativeopendialog(w,s1,s2,s3,i,j)) == NULL) fail;
+ len = strlen(tmpstr);
+ StrLoc(result) = alcstr(tmpstr, len);
+ StrLen(result) = len;
+ return result;
+ }
+end
+
+
+"WinSelectDialog(w, s1, buttons) - select from a set of choices"
+
+function{0,1} WinSelectDialog(argv[argc])
+ abstract {
+ return string
+ }
+ body {
+ wbp w;
+ C_integer i, j, warg = 0, len;
+ tended char *s1;
+ char *s2 = NULL, *tmpstr;
+ tended struct descrip d;
+ tended struct b_list *hp;
+ int lsize;
+ OptWindow(w);
+
+ /*
+ * look for list of text for the message. concatenate text strings.
+ */
+ if (warg == argc)
+ fail;
+ if (!is:list(argv[warg])) runerr(108, argv[warg]);
+ hp = (struct b_list *)BlkLoc(argv[warg]);
+ lsize = hp->size;
+ for(i=0; i < lsize; i++) {
+ c_get(hp, &d);
+ if (!cnv:C_string(d, s1)) runerr(103, d);
+ len += strlen(s1)+2;
+ if (s2) {
+ s2 = realloc(s2, len);
+ if (!s2) fail;
+ strcat(s2, "\r\n");
+ strcat(s2, s1);
+ }
+ else s2 = salloc(s1);
+ c_put(&(argv[warg]), &d);
+ }
+ warg++;
+
+ if (warg >= argc) {
+ hp = NULL;
+ }
+ else {
+ if (!is:list(argv[warg])) runerr(108, argv[warg]);
+ hp = (struct b_list *)BlkLoc(argv[warg]);
+ lsize = hp->size;
+ for(i=0; i < lsize; i++) {
+ c_get(hp, &d);
+ if (!cnv:C_string(d, s1)) runerr(103, d);
+ c_put(&(argv[warg]), &d);
+ }
+ }
+ tmpstr = nativeselectdialog(w, hp, s2);
+ if (tmpstr == NULL) fail;
+ free(s2);
+ len = strlen(tmpstr);
+ StrLoc(result) = alcstr(tmpstr, len);
+ StrLen(result) = len;
+ return result;
+ }
+end
+
+"WinSaveDialog(w,s1,s2,i,s3,j) - choose a file to save"
+
+function{0,1} WinSaveDialog(argv[argc])
+ abstract {
+ return string
+ }
+ body {
+ wbp w;
+ int len;
+ C_integer i, j, warg = 0, slen;
+ char buf3[128], chReplace;
+ tended char *tmpstr;
+ tended char *s1, *s2, *s3;
+ OptWindow(w);
+
+ if (warg >= argc || is:null(argv[warg])) {
+ s1 = "Save:";
+ }
+ else if (!cnv:C_string(argv[warg], s1)) {
+ runerr(103, argv[warg]);
+ }
+ warg++;
+
+ if (warg >= argc || is:null(argv[warg])) {
+ s2 = "";
+ }
+ else if (!cnv:C_string(argv[warg], s2)) {
+ runerr(103, argv[warg]);
+ }
+ warg++;
+
+ if (warg >= argc) {
+ i = 50;
+ }
+ else if (!def:C_integer(argv[warg], 50, i)) {
+ runerr(101, argv[warg]);
+ }
+ warg++;
+
+ if (warg >= argc || is:null(argv[warg])) {
+ strcpy(buf3,"All Files(*.*)|*.*|");
+ s3 = buf3;
+ }
+ else if (!cnv:C_string(argv[warg], s3)) {
+ runerr(103, argv[warg]);
+ }
+ else {
+ strcpy(buf3, s3);
+ s3 = buf3;
+ }
+ chReplace = s3[strlen(s3)-1];
+ slen = strlen(s3);
+ for(j=0; j < slen; j++)
+ if(s3[j] == chReplace) s3[j] = '\0';
+ warg++;
+
+ if (warg >= argc) {
+ j = 1;
+ }
+ else if (!def:C_integer(argv[warg], 1, j)) {
+ runerr(101, argv[warg]);
+ }
+ warg++;
+ if ((tmpstr = nativesavedialog(w, s1, s2, s3, i, j)) == NULL) fail;
+ len = strlen(tmpstr);
+ StrLoc(result) = alcstr(tmpstr, len);
+ StrLen(result) = len;
+ return result;
+ }
+end
+#endif /* WinExtns */
+
+#endif /* Graphics */