The R Project SVN R

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4394 ripley 1
/*
2
 *  R : A Computer Langage for Statistical Data Analysis
3
 *  Copyright (C) 1995, 1996  Robert Gentleman and Ross Ihaka
32578 ripley 4
 *  Copyright (C) 1998--2005  Robert Gentleman, Ross Ihaka and the
9044 ripley 5
 *                            R Development Core Team
4394 ripley 6
 *
7
 *  This program is free software; you can redistribute it and/or modify
8
 *  it under the terms of the GNU General Public License as published by
9
 *  the Free Software Foundation; either version 2 of the License, or
10
 *  (at your option) any later version.
11
 *
12
 *  This program is distributed in the hope that it will be useful,
13
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 *  GNU General Public License for more details.
16
 *
17
 *  You should have received a copy of the GNU General Public License
18
 *  along with this program; if not, write to the Free Software
5458 ripley 19
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
4394 ripley 20
 */
21
 
9044 ripley 22
/* TODO
9095 ripley 23
   - spreadsheet copy and paste?
9044 ripley 24
 */
25
 
32704 ripley 26
/* Use of strchr here is MBCS-safe */
27
 
5222 ripley 28
#ifdef HAVE_CONFIG_H
7701 hornik 29
#include <config.h>
5222 ripley 30
#endif
33001 ripley 31
#include "win-nls.h"
5222 ripley 32
 
32578 ripley 33
#include <wchar.h>
34
 
4394 ripley 35
#include "Defn.h"
36
#include "Print.h"
37
 
9044 ripley 38
#include "graphapp/ga.h"
39
#include "console.h"
40
#include "consolestructs.h"
9079 ripley 41
#include "rui.h"
4394 ripley 42
 
9044 ripley 43
static dataeditor de;
44
static ConsoleData p;
45
 
24276 ripley 46
typedef enum {UNKNOWNN, NUMERIC, CHARACTER} CellType;
9044 ripley 47
 
24276 ripley 48
static Rboolean R_de_up;
49
 
9095 ripley 50
#ifndef max
51
#define max(a, b) (((a)>(b))?(a):(b))
52
#endif
53
#ifndef min
54
#define min(a, b) (((a)<(b))?(a):(b))
55
#endif
9837 ripley 56
#define BOXW(x) (min(((x<100 && nboxchars==0)?boxw[x]:box_w),WIDTH-boxw[0]-2*bwidth-2))
9095 ripley 57
 
9044 ripley 58
#define FIELDWIDTH 10
59
 
60
/* Local Function Definitions */
9095 ripley 61
 
9044 ripley 62
static void advancerect(int);
63
static void bell();
64
static void cleararea(int, int, int, int, rgb);
24276 ripley 65
static void clearrect(void);
66
static void closerect(void);
67
static void clearwindow(void);
68
static void de_closewin(void);
9095 ripley 69
static void copyarea(int, int, int, int);
70
static void copyH(int, int, int);
24276 ripley 71
static void deredraw(void);
72
static void eventloop(void);
73
static void downlightrect(void);
74
static void drawwindow(void);
9044 ripley 75
static void drawcol(int);
9095 ripley 76
/* static void de_drawline(int, int, int, int);*/
9044 ripley 77
static void de_drawtext(int, int, char *);
78
static void drawrectangle(int, int, int, int, int, int);
9048 ripley 79
static void drawrow(int);
9044 ripley 80
static void find_coords(int, int, int*, int*);
81
static void handlechar(char*);
24276 ripley 82
static void highlightrect(void);
83
static Rboolean initwin(void);
9044 ripley 84
static void jumppage(int);
85
static void jumpwin(int, int);
86
static void de_popupmenu(int, int, int);
24276 ripley 87
static void printlabs(void);
9044 ripley 88
static void printrect(int, int);
9048 ripley 89
static void printstring(char*, int, int, int, int);
9044 ripley 90
static void printelt(SEXP, int, int, int);
24276 ripley 91
static void setcellwidths(void);
9044 ripley 92
 
9212 ripley 93
static dataeditor newdataeditor();
94
static void de_copy(control c);
95
static void de_paste(control c);
96
static void de_delete(control c);
97
static menuitem de_mvw;
98
 
24272 ripley 99
static SEXP work, names, lens;
100
static PROTECT_INDEX wpi, npi, lpi;
9044 ripley 101
static SEXP ssNA_STRING;
102
static double ssNA_REAL;
103
 
104
/* Global variables needed for the graphics */
9095 ripley 105
 
9044 ripley 106
static int box_w;                       /* width of a box */
24276 ripley 107
static int boxw[100];                   /* widths of cells */
9044 ripley 108
static int box_h;                       /* height of a box */
109
static int windowWidth;                 /* current width of the window */
110
static int windowHeight;                /* current height of the window */
111
static int currentexp;                  /* boolean: whether an cell is active */
112
static int crow;                        /* current row */
113
static int ccol;                        /* current column */
114
static int nwide, nhigh;
115
static int colmax, colmin, rowmax, rowmin;
116
static int ndecimal;                    /* count decimal points */
117
static int ne;                          /* count exponents */
118
static int nneg;			/* indicate whether its a negative */
119
static int clength;                     /* number of characters currently entered */
32888 ripley 120
static char buf[200];
9044 ripley 121
static char *bufp;
122
static int bwidth;			/* width of the border */
123
static int hwidth;			/* width of header  */
124
static int text_xoffset, text_yoffset;
9053 ripley 125
static field celledit;
24272 ripley 126
static Rboolean newcol, CellModified, CellEditable;
9079 ripley 127
static int xmaxused, ymaxused;
9095 ripley 128
static int oldWIDTH=0, oldHEIGHT=0;
9205 ripley 129
static int nboxchars=0;
24272 ripley 130
static int labdigs=4;
131
static char labform[6];
24259 ripley 132
static int xScrollbarScale=1, yScrollbarScale=1;
9044 ripley 133
 
24259 ripley 134
#include <windows.h> /* for Sleep */
9044 ripley 135
 
32589 ripley 136
int mb_char_len(char *buf, int clength, wchar_t *wc); /* from console.c */
32578 ripley 137
 
138
static void moveback()
139
{
140
    int mb_len;
32589 ripley 141
    wchar_t wc;
32578 ripley 142
 
143
    if (clength > 0) {
32589 ripley 144
	mb_len = mb_char_len(buf, clength-1, &wc);
32578 ripley 145
	clength -= mb_len;
146
	bufp -= mb_len;
147
	printstring(buf, clength, crow, ccol, 1);
148
    } else bell();
149
}
150
 
151
 
24276 ripley 152
 /*
24272 ripley 153
  Underlying assumptions (for this version R >= 1.8.0)
154
 
155
  The data are stored in a list `work', with unused columns having
156
  NULL entries.  The names for the list are in `names', which should
27357 murdoch 157
  have a name for all displayable columns (up to xmaxused).
24272 ripley 158
  The *used* lengths of the columns are in `lens': this needs only be
159
  set for non-NULL columns.
160
 
27357 murdoch 161
  If the list was originally length(0), that should work with
24276 ripley 162
 
24272 ripley 163
 
164
  All row and col numbers are 1-based.
165
 
166
  BDR May 2003
167
 */
168
 
24276 ripley 169
/*
170
   ssNewVector is just an interface to allocVector but it lets us
171
   set the fields to NA. We need to have a special NA for reals and
172
   strings so that we can differentiate between uninitialized elements
173
   in the vectors and user supplied NA's; hence ssNA_REAL and ssNA_STRING
174
 */
175
 
176
static SEXP ssNewVector(SEXPTYPE type, int vlen)
177
{
178
    SEXP tvec;
179
    int j;
180
 
181
    tvec = allocVector(type, vlen);
182
    for (j = 0; j < vlen; j++)
183
	if (type == REALSXP)
184
	    REAL(tvec)[j] = ssNA_REAL;
185
	else if (type == STRSXP)
186
	    SET_STRING_ELT(tvec, j, STRING_ELT(ssNA_STRING, 0));
187
    return (tvec);
188
}
189
static void eventloop()
190
{
191
    while (R_de_up) {
192
	/* avoid consuming 100% CPU time here */
193
	Sleep(10);
194
	R_ProcessEvents();
195
    }
196
}
197
 
198
static void de_closewin_cend(void *data)
199
{
200
    de_closewin();
201
}
202
 
9044 ripley 203
SEXP do_dataentry(SEXP call, SEXP op, SEXP args, SEXP rho)
204
{
24272 ripley 205
    SEXP colmodes, tnames, tvec, tvec2, work2;
9044 ripley 206
    SEXPTYPE type;
24272 ripley 207
    int i, j, cnt, len, nprotect;
9044 ripley 208
    RCNTXT cntxt;
24272 ripley 209
    char clab[25];
9044 ripley 210
 
211
    nprotect = 0;/* count the PROTECT()s */
24272 ripley 212
    PROTECT_WITH_INDEX(work = duplicate(CAR(args)), &wpi); nprotect++;
213
    colmodes = CADR(args);
214
    tnames = getAttrib(work, R_NamesSymbol);
9044 ripley 215
 
24272 ripley 216
    if (TYPEOF(work) != VECSXP || TYPEOF(colmodes) != VECSXP)
33001 ripley 217
	errorcall(call, G_("invalid argument"));
9044 ripley 218
 
219
    /* initialize the constants */
220
 
221
    bufp = buf;
222
    ne = 0;
223
    currentexp = 0;
224
    nneg = 0;
225
    ndecimal = 0;
226
    clength = 0;
227
    ccol = 1;
228
    crow = 1;
229
    colmin = 1;
230
    rowmin = 1;
231
    ssNA_REAL = -NA_REAL;
232
    tvec = allocVector(REALSXP, 1);
233
    REAL(tvec)[0] = ssNA_REAL;
234
    PROTECT(ssNA_STRING = coerceVector(tvec, STRSXP)); nprotect++;
235
    bwidth = 0;
9212 ripley 236
    hwidth = 5;
9044 ripley 237
 
24272 ripley 238
    /* setup work, names, lens  */
239
    xmaxused = length(work); ymaxused = 0;
240
    PROTECT_WITH_INDEX(lens = allocVector(INTSXP, xmaxused), &lpi);
241
    nprotect++;
9044 ripley 242
 
24272 ripley 243
    if (isNull(tnames)) {
244
	PROTECT_WITH_INDEX(names = allocVector(STRSXP, xmaxused), &npi);
245
	for(i = 0; i < xmaxused; i++) {
246
	    sprintf(clab, "var%d", i);
247
	    SET_STRING_ELT(names, i, mkChar(clab));
9044 ripley 248
	}
24272 ripley 249
    } else
250
	PROTECT_WITH_INDEX(names = duplicate(tnames), &npi);
251
    nprotect++;
252
    for (i = 0; i < xmaxused; i++) {
253
	int len = LENGTH(VECTOR_ELT(work, i));
254
	INTEGER(lens)[i] = len;
255
	ymaxused = max(len, ymaxused);
256
	type = TYPEOF(VECTOR_ELT(work, i));
25365 ripley 257
	if (LENGTH(colmodes) > 0 && !isNull(VECTOR_ELT(colmodes, i)))
24272 ripley 258
	    type = str2type(CHAR(STRING_ELT(VECTOR_ELT(colmodes, i), 0)));
259
	if (type != STRSXP) type = REALSXP;
260
	if (isNull(VECTOR_ELT(work, i))) {
261
	    if (type == NILSXP) type = REALSXP;
262
	    SET_VECTOR_ELT(work, i, ssNewVector(type, 100));
263
	} else if (!isVector(VECTOR_ELT(work, i)))
33001 ripley 264
	    errorcall(call, G_("invalid type for value"));
24272 ripley 265
	else {
266
	    if (TYPEOF(VECTOR_ELT(work, i)) != type)
27357 murdoch 267
		SET_VECTOR_ELT(work, i,
24272 ripley 268
			       coerceVector(VECTOR_ELT(work, i), type));
269
	}
9044 ripley 270
    }
271
 
24259 ripley 272
    /* scale scrollbars as needed */
273
    if (xmaxused > 10000) xScrollbarScale = xmaxused/1000;
274
    if (ymaxused > 10000) yScrollbarScale = ymaxused/1000;
9044 ripley 275
 
276
    /* start up the window, more initializing in here */
277
    if (initwin())
33001 ripley 278
	errorcall(call, G_("invalid device"));
9044 ripley 279
 
280
    /* set up a context which will close the window if there is an error */
14560 luke 281
    begincontext(&cntxt, CTXT_CCODE, R_NilValue, R_NilValue, R_NilValue,
23463 luke 282
		 R_NilValue, R_NilValue);
14561 luke 283
    cntxt.cend = &de_closewin_cend;
284
    cntxt.cenddata = NULL;
9044 ripley 285
 
286
    highlightrect();
287
 
288
    eventloop();
289
 
290
    endcontext(&cntxt);
291
 
292
    /* drop out unused columns */
24272 ripley 293
    for(i = 0, cnt = 0; i < xmaxused; i++)
294
	if(!isNull(VECTOR_ELT(work, i))) cnt++;
295
    if (cnt < xmaxused) {
296
	PROTECT(work2 = allocVector(VECSXP, cnt)); nprotect++;
297
	for(i = 0, j = 0; i < xmaxused; i++) {
298
	    if(!isNull(VECTOR_ELT(work, i))) {
299
		SET_VECTOR_ELT(work2, j, VECTOR_ELT(work, i));
300
		INTEGER(lens)[j] = INTEGER(lens)[i];
301
		SET_STRING_ELT(names, j, STRING_ELT(names, i));
302
		j++;
9044 ripley 303
	    }
304
	}
24272 ripley 305
	REPROTECT(names = lengthgets(names, cnt), npi);
306
    } else work2 = work;
9044 ripley 307
 
24272 ripley 308
    for (i = 0; i < LENGTH(work2); i++) {
309
	len = INTEGER(lens)[i];
310
	tvec = VECTOR_ELT(work2, i);
311
	if (LENGTH(tvec) != len) {
312
	    tvec2 = ssNewVector(TYPEOF(tvec), len);
313
	    for (j = 0; j < len; j++) {
314
		if (TYPEOF(tvec) == REALSXP) {
315
		    if (REAL(tvec)[j] != ssNA_REAL)
316
			REAL(tvec2)[j] = REAL(tvec)[j];
9044 ripley 317
		    else
318
			REAL(tvec2)[j] = NA_REAL;
24272 ripley 319
		} else if (TYPEOF(tvec) == STRSXP) {
320
		    if (!streql(CHAR(STRING_ELT(tvec, j)),
10172 luke 321
				CHAR(STRING_ELT(ssNA_STRING, 0))))
24272 ripley 322
			SET_STRING_ELT(tvec2, j, STRING_ELT(tvec, j));
9044 ripley 323
		    else
10172 luke 324
			SET_STRING_ELT(tvec2, j, NA_STRING);
9044 ripley 325
		} else
33001 ripley 326
		    error(G_("dataentry: internal memory problem"));
24272 ripley 327
	    }
328
	    SET_VECTOR_ELT(work2, i, tvec2);
9044 ripley 329
	}
330
    }
331
 
27357 murdoch 332
    setAttrib(work2, R_NamesSymbol, names);
9044 ripley 333
    UNPROTECT(nprotect);
24272 ripley 334
    return work2;
9044 ripley 335
}
336
 
337
/* Window Drawing Routines */
338
 
9079 ripley 339
static rgb bbg;
9044 ripley 340
 
24276 ripley 341
static void setcellwidths(void)
9044 ripley 342
{
9079 ripley 343
    int i, w, dw;
9095 ripley 344
 
345
    windowWidth = w = 2*bwidth + boxw[0] + BOXW(colmin);
9079 ripley 346
    nwide = 2;
9095 ripley 347
    for (i = 2; i < 100; i++) { /* 100 on-screen columns cannot occur */
348
	dw = BOXW(i + colmin - 1);
9079 ripley 349
	if((w += dw) > WIDTH) {
350
	    nwide = i;
351
	    windowWidth = w - dw;
352
	    break;
353
	}
354
    }
9212 ripley 355
}
356
 
357
 
24276 ripley 358
static void drawwindow(void)
9212 ripley 359
{
360
    /* might have resized */
361
    setcellwidths();
9229 ripley 362
    nhigh = (HEIGHT - 2 * bwidth - hwidth - 3) / box_h;
9212 ripley 363
    windowHeight = nhigh * box_h + 2 * bwidth + hwidth;
9095 ripley 364
    oldWIDTH = WIDTH;
365
    oldHEIGHT = HEIGHT;
27357 murdoch 366
 
9044 ripley 367
    clearwindow();
9229 ripley 368
    deredraw();
9079 ripley 369
    /* row/col 1 = pos 0 */
24272 ripley 370
    gchangescrollbar(de, VWINSB, (rowmin - 1)/yScrollbarScale,
27357 murdoch 371
		     ymaxused/yScrollbarScale,
24259 ripley 372
		     max(nhigh/yScrollbarScale, 1), 0);
24272 ripley 373
    gchangescrollbar(de, HWINSB, (colmin - 1)/xScrollbarScale,
27357 murdoch 374
		     xmaxused/xScrollbarScale,
24259 ripley 375
		     max(nwide/xScrollbarScale, 1), 0);
9044 ripley 376
}
377
 
9212 ripley 378
static void doHscroll(int oldcol)
9095 ripley 379
{
9212 ripley 380
    int i, dw;
9095 ripley 381
    int oldnwide = nwide, oldwindowWidth = windowWidth;
382
 
383
    /* horizontal re-position */
9212 ripley 384
    setcellwidths();
9095 ripley 385
    colmax = colmin + (nwide - 2);
24272 ripley 386
    if (oldcol < colmin) { /* drop oldcol...colmin - 1 */
9095 ripley 387
	dw = boxw[0];
388
	for (i = oldcol; i < colmin; i++) dw += BOXW(i);
389
	copyH(dw, boxw[0], oldwindowWidth - dw + 1);
390
	dw = oldwindowWidth - BOXW(oldcol) + 1;
391
	cleararea(dw, hwidth, WIDTH-dw, HEIGHT, p->bg);
392
	/* oldnwide includes the row labels */
393
	for (i = oldcol+oldnwide-1; i <= colmax; i++) drawcol(i);
394
    } else {
395
	/* move one or more cols left */
396
	dw = BOXW(colmin);
397
	copyH(boxw[0], boxw[0] + dw, windowWidth - dw + 1);
398
	dw = windowWidth + 1;
399
	cleararea(dw, hwidth, WIDTH-dw, HEIGHT, p->bg);
400
	drawcol(colmin);
401
    }
24272 ripley 402
    gchangescrollbar(de, HWINSB, (colmin - 1)/xScrollbarScale,
27357 murdoch 403
		     xmaxused/xScrollbarScale,
24259 ripley 404
		     max(nwide/xScrollbarScale, 1), 0);
9095 ripley 405
    highlightrect();
406
}
407
 
9044 ripley 408
/* find_coords finds the coordinates of the upper left corner of the
9079 ripley 409
   given cell on the screen: row and col are on-screen coords */
9044 ripley 410
 
9212 ripley 411
static void find_coords(int row, int col, int *xcoord, int *ycoord)
9044 ripley 412
{
9079 ripley 413
    int i, w;
414
    w = bwidth;
415
    if (col > 0) w += boxw[0];
9095 ripley 416
    for(i = 1; i < col; i ++) w += BOXW(i + colmin - 1);
9079 ripley 417
    *xcoord = w;
9044 ripley 418
    *ycoord = bwidth + hwidth + box_h * row;
419
}
420
 
421
/* draw the window with the top left box at column wcol and row wrow */
422
 
9212 ripley 423
static void jumpwin(int wcol, int wrow)
9044 ripley 424
{
425
    if (wcol < 0 || wrow < 0) {
426
	bell();
427
	return;
428
    }
429
    closerect();
9095 ripley 430
    if (colmin != wcol || rowmin != wrow) {
431
	colmin = wcol;
432
	rowmin = wrow;
433
	deredraw();
434
    } else highlightrect();
9044 ripley 435
}
436
 
9212 ripley 437
static void advancerect(int which)
9044 ripley 438
{
439
 
440
    /* if we are in the header, changing a name then only down is
441
       allowed */
442
    if (crow < 1 && which != DOWN) {
443
	bell();
444
	return;
445
    }
446
 
447
    closerect();
448
 
449
    switch (which) {
450
    case UP:
451
	if (crow == 1) {
452
	    if (rowmin == 1)
453
		bell();
454
	    else
455
		jumppage(UP);
456
	} else
457
	    crow--;
458
	break;
459
    case DOWN:
460
	if (crow == (nhigh - 1))
461
	    jumppage(DOWN);
462
	else
463
	    crow++;
464
	break;
465
    case RIGHT:
466
	if (ccol == (nwide - 1))
467
	    jumppage(RIGHT);
468
	else
469
	    ccol++;
470
	break;
471
    case LEFT:
472
	if (ccol == 1) {
473
	    if (colmin == 1)
474
		bell();
475
	    else
476
		jumppage(LEFT);
477
	} else
478
	    ccol--;
479
	break;
480
    default:
481
	UNIMPLEMENTED("advancerect");
482
    }
483
 
484
    highlightrect();
485
}
486
 
9079 ripley 487
static char *get_col_name(int col)
488
{
24272 ripley 489
    static char clab[25];
490
    if (col <= xmaxused) {
491
	/* don't use NA labels */
492
	SEXP tmp = STRING_ELT(names, col - 1);
493
	if(tmp != NA_STRING) return(CHAR(tmp));
9079 ripley 494
    }
495
    sprintf(clab, "var%d", col);
496
    return clab;
497
}
498
 
499
static int get_col_width(int col)
500
{
9205 ripley 501
    int i, w = 0, w1, fw = FIELDWIDTH;
9079 ripley 502
    char *strp;
24272 ripley 503
    SEXP tmp, lab;
9205 ripley 504
 
505
    if (nboxchars > 0) return nboxchars;
24272 ripley 506
    if (col <= xmaxused) {
507
	tmp = VECTOR_ELT(work, col - 1);
508
	if (isNull(tmp)) return fw;
509
	/* don't use NA labels */
510
	lab = STRING_ELT(names, col - 1);
511
	if(lab != NA_STRING) w = strlen(CHAR(lab)); else w = fw;
9079 ripley 512
	PrintDefaults(R_NilValue);
24272 ripley 513
	for (i = 0; i < INTEGER(lens)[col - 1]; i++) {
34294 ripley 514
	    strp = EncodeElement(tmp, i, 0, '.');
9079 ripley 515
	    w1 = strlen(strp);
516
	    if (w1 > w) w = w1;
517
	}
518
	if(w < 5) w = 5;
519
	if(w < 8) w++;
9837 ripley 520
	if(w > 50) w = 50;
9079 ripley 521
	return w;
522
    }
9205 ripley 523
    return fw;
9079 ripley 524
}
525
 
526
static CellType get_col_type(int col)
527
{
528
    SEXP tmp;
529
    CellType res = UNKNOWNN;
9095 ripley 530
 
24272 ripley 531
    if (col <= xmaxused) {
532
	tmp = VECTOR_ELT(work, col - 1);
9079 ripley 533
	if(TYPEOF(tmp) == REALSXP) res = NUMERIC;
534
	if(TYPEOF(tmp) == STRSXP) res = CHARACTER;
535
    }
536
    return res;
537
}
538
 
539
 
9044 ripley 540
/* whichcol is absolute col no, col is position on screen */
9212 ripley 541
static void drawcol(int whichcol)
9044 ripley 542
{
9095 ripley 543
    int i, src_x, src_y, len, col = whichcol - colmin + 1, bw = BOXW(whichcol);
9079 ripley 544
    char *clab;
9044 ripley 545
    SEXP tmp;
546
 
547
    find_coords(0, col, &src_x, &src_y);
9095 ripley 548
    cleararea(src_x, src_y, bw, windowHeight, p->bg);
549
    cleararea(src_x, src_y, bw, box_h, bbg);
9044 ripley 550
    for (i = 0; i < nhigh; i++)
9095 ripley 551
	drawrectangle(src_x, hwidth + i * box_h, bw, box_h, 1, 1);
9044 ripley 552
 
553
    /* now fill it in if it is active */
9079 ripley 554
    clab = get_col_name(whichcol);
555
    printstring(clab, strlen(clab), 0, col, 0);
9095 ripley 556
 
24272 ripley 557
   if (xmaxused >= whichcol) {
558
	tmp = VECTOR_ELT(work, whichcol - 1);
559
	if (!isNull(tmp)) {
560
	    len = min(rowmax, INTEGER(lens)[whichcol - 1]);
9044 ripley 561
	    for (i = (rowmin - 1); i < len; i++)
24272 ripley 562
		printelt(tmp, i, i - rowmin + 2, col);
9044 ripley 563
	}
564
    }
565
}
566
 
9048 ripley 567
 
568
/* whichrow is absolute row no */
9212 ripley 569
static void drawrow(int whichrow)
9044 ripley 570
{
24272 ripley 571
    int i, src_x, src_y, row = whichrow - rowmin + 1, w;
9044 ripley 572
    char rlab[15];
573
    SEXP tvec;
574
 
9048 ripley 575
    find_coords(row, 0, &src_x, &src_y);
9044 ripley 576
    cleararea(src_x, src_y, windowWidth, box_h, (whichrow > 0)?p->bg:bbg);
9079 ripley 577
    drawrectangle(src_x, src_y, boxw[0], box_h, 1, 1);
9095 ripley 578
 
24272 ripley 579
    sprintf(rlab, labform, whichrow);
9048 ripley 580
    printstring(rlab, strlen(rlab), row, 0, 0);
9044 ripley 581
 
9079 ripley 582
    w = bwidth + boxw[0];
583
    for (i = colmin; i <= colmax; i++) {
9095 ripley 584
	drawrectangle(w, src_y, BOXW(i), box_h, 1, 1);
585
	w += BOXW(i);
9079 ripley 586
    }
587
 
9044 ripley 588
    for (i = colmin; i <= colmax; i++) {
24272 ripley 589
	if (i > xmaxused) break;
590
	if (!isNull(tvec = VECTOR_ELT(work, i - 1)))
591
	    if (whichrow <= INTEGER(lens)[i - 1])
592
		printelt(tvec, whichrow - 1, row, i - colmin + 1);
9044 ripley 593
    }
594
}
595
 
596
/* printelt: print the correct value from vector[vrow] into the
597
   spreadsheet in row ssrow and col sscol */
598
 
599
/* WARNING: This has no check that you're not beyond the end of the
600
   vector. Caller must check. */
601
 
9212 ripley 602
static void printelt(SEXP invec, int vrow, int ssrow, int sscol)
9044 ripley 603
{
604
    char *strp;
605
    PrintDefaults(R_NilValue);
606
    if (TYPEOF(invec) == REALSXP) {
607
	if (REAL(invec)[vrow] != ssNA_REAL) {
34294 ripley 608
	    strp = EncodeElement(invec, vrow, 0, '.');
9048 ripley 609
	    printstring(strp, strlen(strp), ssrow, sscol, 0);
9044 ripley 610
	}
611
    }
612
    else if (TYPEOF(invec) == STRSXP) {
10172 luke 613
	if (!streql(CHAR(STRING_ELT(invec, vrow)),
614
		    CHAR(STRING_ELT(ssNA_STRING, 0)))) {
34294 ripley 615
	    strp = EncodeElement(invec, vrow, 0, '.');
9048 ripley 616
	    printstring(strp, strlen(strp), ssrow, sscol, 0);
9044 ripley 617
	}
618
    }
619
    else
33001 ripley 620
	error(G_("dataentry: internal memory error"));
9044 ripley 621
}
622
 
623
 
624
static void drawelt(int whichrow, int whichcol)
625
{
626
    int i;
9079 ripley 627
    char *clab;
9044 ripley 628
    SEXP tmp;
629
 
9079 ripley 630
    if (whichrow == 0) {
631
	clab = get_col_name(whichcol + colmin - 1);
9095 ripley 632
	printstring(clab, strlen(clab), 0, whichcol, 0);
9079 ripley 633
    } else {
24272 ripley 634
	if (xmaxused >= whichcol + colmin - 1) {
635
	    tmp = VECTOR_ELT(work, whichcol + colmin - 2);
27357 murdoch 636
	    if (!isNull(tmp) && (i = rowmin + whichrow - 2) <
24272 ripley 637
		INTEGER(lens)[whichcol + colmin - 2] )
638
		printelt(tmp, i, whichrow, whichcol);
9079 ripley 639
	} else
24265 ripley 640
	    printstring("", 0, whichrow,  whichcol, 0);
9044 ripley 641
    }
642
}
643
 
9212 ripley 644
static void jumppage(int dir)
9044 ripley 645
{
9095 ripley 646
    int i, w, oldcol, wcol;
647
 
9044 ripley 648
    switch (dir) {
649
    case UP:
650
	rowmin--;
651
	rowmax--;
652
	copyarea(0, hwidth + box_h, 0, hwidth + 2 * box_h);
9048 ripley 653
	drawrow(rowmin);
27357 murdoch 654
	gchangescrollbar(de, VWINSB, (rowmin - 1)/yScrollbarScale,
655
			 ymaxused/yScrollbarScale,
24259 ripley 656
			 max(nhigh/yScrollbarScale, 1), 0);
9044 ripley 657
	break;
658
    case DOWN:
24255 ripley 659
	if (rowmax >= 65535) return;
9044 ripley 660
	rowmin++;
661
	rowmax++;
662
	copyarea(0, hwidth + 2 * box_h, 0, hwidth + box_h);
9048 ripley 663
	drawrow(rowmax);
27357 murdoch 664
	gchangescrollbar(de, VWINSB, (rowmin - 1)/yScrollbarScale,
665
			 ymaxused/yScrollbarScale,
24259 ripley 666
			 max(nhigh/yScrollbarScale, 1), 0);
9044 ripley 667
	break;
668
    case LEFT:
669
	colmin--;
9095 ripley 670
	doHscroll(colmin+1);
9044 ripley 671
	break;
672
    case RIGHT:
9095 ripley 673
	oldcol = colmin;
674
	wcol = colmin + ccol + 1; /* column to be selected */
675
        /* There may not be room to fit the next column in */
676
	w = WIDTH - boxw[0] - BOXW(colmax + 1);
677
	for (i = colmax; i >= oldcol; i--) {
678
	    w -= BOXW(i);
679
	    if(w < 0) {
680
		colmin = i + 1;
681
		break;
27357 murdoch 682
	    }
9095 ripley 683
	}
684
	ccol = wcol - colmin;
685
	doHscroll(oldcol);
9044 ripley 686
	break;
9048 ripley 687
    }
9044 ripley 688
}
689
/* draw a rectangle, used to highlight/downlight the current box */
690
 
9212 ripley 691
static void printrect(int lwd, int fore)
9044 ripley 692
{
9079 ripley 693
    int x, y;
694
    find_coords(crow, ccol, &x, &y);
24265 ripley 695
    drawrectangle(x + lwd - 1, y + lwd - 1,
9095 ripley 696
		  BOXW(ccol+colmin-1) - lwd + 1,
9079 ripley 697
		  box_h - lwd + 1, lwd, fore);
9044 ripley 698
}
699
 
24276 ripley 700
static void downlightrect(void)
9044 ripley 701
{
702
    printrect(2, 0);
703
    printrect(1, 1);
704
}
705
 
24276 ripley 706
static void highlightrect(void)
9044 ripley 707
{
708
    printrect(2, 1);
709
}
710
 
711
 
24272 ripley 712
static void getccol()
9044 ripley 713
{
714
    SEXP tmp, tmp2;
715
    int i, len, newlen, wcol, wrow;
716
    SEXPTYPE type;
24272 ripley 717
    char clab[25];
9044 ripley 718
 
719
    wcol = ccol + colmin - 1;
720
    wrow = crow + rowmin - 1;
24272 ripley 721
    if (wcol > xmaxused) {
722
	/* extend work, names and lens */
723
	REPROTECT(work = lengthgets(work, wcol), wpi);
724
	REPROTECT(names = lengthgets(names, wcol), npi);
725
	for (i = xmaxused; i < wcol; i++) {
726
	    sprintf(clab, "var%d", i + 1);
727
	    SET_STRING_ELT(names, i, mkChar(clab));
728
	}
729
	REPROTECT(lens = lengthgets(lens, wcol), lpi);
9095 ripley 730
	xmaxused = wcol;
9044 ripley 731
    }
24272 ripley 732
    newcol = FALSE;
733
    if (isNull(VECTOR_ELT(work, wcol - 1))) {
734
	newcol = TRUE;
735
	SET_VECTOR_ELT(work, wcol - 1, ssNewVector(REALSXP, max(100, wrow)));
736
	INTEGER(lens)[wcol - 1] = 0;
737
    }
738
    if (!isVector(tmp = VECTOR_ELT(work, wcol - 1)))
33001 ripley 739
	error(G_("internal type error in dataentry"));
24272 ripley 740
    len = INTEGER(lens)[wcol - 1];
741
    type = TYPEOF(tmp);
9044 ripley 742
    if (len < wrow) {
10217 pd 743
	for (newlen = max(len * 2, 10) ; newlen < wrow ; newlen *= 2)
9044 ripley 744
	    ;
745
	tmp2 = ssNewVector(type, newlen);
746
	for (i = 0; i < len; i++)
747
	    if (type == REALSXP)
24272 ripley 748
		REAL(tmp2)[i] = REAL(tmp)[i];
9044 ripley 749
	    else if (type == STRSXP)
24272 ripley 750
		SET_STRING_ELT(tmp2, i, STRING_ELT(tmp, i));
9044 ripley 751
	    else
33001 ripley 752
		error(G_("internal type error in dataentry"));
24272 ripley 753
	SET_VECTOR_ELT(work, wcol - 1, tmp2);
9044 ripley 754
    }
755
}
756
 
757
/* close up the entry to a cell, put the value that has been entered
758
   into the correct place and as the correct type */
759
 
24276 ripley 760
static void closerect(void)
9044 ripley 761
{
24272 ripley 762
    SEXP cvec;
9079 ripley 763
    int wcol = ccol + colmin - 1, wrow = rowmin + crow - 1, wrow0;
9095 ripley 764
 
9044 ripley 765
    *bufp = '\0';
766
 
9053 ripley 767
    if (CellModified || CellEditable) {
768
	if (CellEditable) {
769
	    strcpy(buf, gettext(celledit));
770
	    clength = strlen(buf);
771
	    hide(celledit);
772
	    del(celledit);
773
	}
24272 ripley 774
	getccol();
775
	cvec = VECTOR_ELT(work, wcol - 1);
776
	wrow0 = INTEGER(lens)[wcol - 1];
777
	if (wrow > wrow0) INTEGER(lens)[wcol - 1] = wrow;
9095 ripley 778
	ymaxused = max(ymaxused, wrow);
9044 ripley 779
	if (clength != 0) {
9095 ripley 780
	    /* do it this way to ensure NA, Inf, ...  can get set */
9053 ripley 781
	    char *endp;
9095 ripley 782
	    double new = R_strtod(buf, &endp);
783
	    int warn = !isBlankString(endp);
24272 ripley 784
	    if (TYPEOF(cvec) == STRSXP)
785
		SET_STRING_ELT(cvec, wrow - 1, mkChar(buf));
786
	    else
9053 ripley 787
		REAL(cvec)[wrow - 1] = new;
788
	    if (newcol & warn) {
789
		/* change mode to character */
24272 ripley 790
		SET_VECTOR_ELT(work, wcol - 1, coerceVector(cvec, STRSXP));
27357 murdoch 791
		SET_STRING_ELT(VECTOR_ELT(work, wcol - 1), wrow - 1,
24272 ripley 792
			       mkChar(buf));
9053 ripley 793
	    }
9044 ripley 794
	} else {
9095 ripley 795
	    if (TYPEOF(cvec) == STRSXP)
10172 luke 796
		SET_STRING_ELT(cvec, wrow - 1, NA_STRING);
9095 ripley 797
	    else
9053 ripley 798
		REAL(cvec)[wrow - 1] = NA_REAL;
9044 ripley 799
	}
9079 ripley 800
	drawelt(crow, ccol);  /* to get the cell scrolling right */
801
	if(wrow > wrow0) drawcol(wcol); /* to fill in NAs */
9044 ripley 802
    }
24272 ripley 803
    CellEditable = CellModified = FALSE;
9044 ripley 804
 
805
    downlightrect();
806
    gsetcursor(de, ArrowCursor);
807
 
808
    ndecimal = 0;
809
    nneg = 0;
810
    ne = 0;
811
    currentexp = 0;
812
    clength = 0;
813
    bufp = buf;
814
}
815
 
816
/* print a null terminated string, check to see if it is longer than
817
   the print area and print it, left adjusted if necessary; clear the
818
   area of previous text; */
819
 
24276 ripley 820
/* This version will only display 200 chars, but the maximum col width
821
   will not allow that many */
9212 ripley 822
static void printstring(char *ibuf, int buflen, int row, int col, int left)
9044 ripley 823
{
9837 ripley 824
    int x_pos, y_pos, bw, fw, bufw;
825
    char buf[201];
9044 ripley 826
 
827
    find_coords(row, col, &x_pos, &y_pos);
9095 ripley 828
    if (col == 0) bw = boxw[0]; else bw = BOXW(col+colmin-1);
9212 ripley 829
    cleararea(x_pos + 1, y_pos + 1, bw - 1, box_h - 1,
9079 ripley 830
	      (row==0 || col==0) ? bbg:p->bg);
9837 ripley 831
    fw = min(200, (bw - 8)/FW);
832
    bufw = min(fw, buflen);
833
    strncpy(buf, ibuf, bufw);
834
    buf[bufw] = '\0';
9079 ripley 835
    if (buflen > fw) {
9048 ripley 836
	if(left) {
9837 ripley 837
	    strncpy(buf, ibuf + buflen - fw, fw);
29162 ripley 838
	    buf[fw] = '\0';
9837 ripley 839
	    *buf = '<';
9048 ripley 840
	} else {
9837 ripley 841
	    *(buf + fw - 1) = '>';
842
	    *(buf + fw) = '\0';
9048 ripley 843
	}
9044 ripley 844
    }
9837 ripley 845
    de_drawtext(x_pos + text_xoffset, y_pos - text_yoffset, buf);
9044 ripley 846
}
847
 
24276 ripley 848
static void clearrect(void)
9044 ripley 849
{
9079 ripley 850
    int x_pos, y_pos;
24276 ripley 851
 
9079 ripley 852
    find_coords(crow, ccol, &x_pos, &y_pos);
9095 ripley 853
    cleararea(x_pos, y_pos, BOXW(ccol+colmin-1), box_h, p->bg);
9044 ripley 854
}
855
 
856
/* handlechar has to be able to parse decimal numbers and strings,
857
   depending on the current column type, only printing characters
858
   should get this far */
859
 
860
/* --- Not true! E.g. ESC ends up in here... */
861
 
9212 ripley 862
static void handlechar(char *text)
9044 ripley 863
{
9079 ripley 864
    int c = text[0];
9044 ripley 865
 
866
    if ( c == '\033' ) {
24272 ripley 867
	CellModified = FALSE;
9044 ripley 868
	clength = 0;
869
	drawelt(crow, ccol);
870
	gsetcursor(de, ArrowCursor);
871
	return;
9079 ripley 872
    } else {
24272 ripley 873
	CellModified = TRUE;
9044 ripley 874
	gsetcursor(de, TextCursor);
875
    }
9095 ripley 876
 
9044 ripley 877
    if (clength == 0) {
9079 ripley 878
	switch(get_col_type(ccol + colmin - 1)) {
879
	case NUMERIC:
9053 ripley 880
	    currentexp = 1;
9079 ripley 881
	    break;
882
	default:
9044 ripley 883
	    currentexp = 2;
9079 ripley 884
	}
9044 ripley 885
	clearrect();
886
	highlightrect();
887
    }
888
 
889
    if (currentexp == 1)	/* we are parsing a number */
890
	switch (c) {
891
	case '-':
892
	    if (nneg == 0)
893
		nneg++;
894
	    else
895
		goto donehc;
896
	    break;
897
	case '.':
898
	    if (ndecimal == 0)
899
		ndecimal++;
900
	    else
901
		goto donehc;
902
	    break;
903
	case 'e':
904
	case 'E':
905
	    if (ne == 0) {
906
		nneg = ndecimal = 0;	/* might have decimal in exponent */
907
		ne++;
908
	    }
909
	    else
910
		goto donehc;
911
	    break;
912
	default:
9048 ripley 913
	    if (!isdigit((int)text[0]))
9044 ripley 914
		goto donehc;
915
	    break;
916
	}
917
 
32888 ripley 918
    if (clength++ > 199) {
33001 ripley 919
	warning(G_("dataentry: expression too long"));
9044 ripley 920
	clength--;
921
	goto donehc;
922
    }
923
 
924
    *bufp++ = text[0];
9048 ripley 925
    printstring(buf, clength, crow, ccol, 1);
9044 ripley 926
    return;
927
 
9095 ripley 928
 donehc:
9044 ripley 929
    bell();
930
}
931
 
24276 ripley 932
static void printlabs(void)
9044 ripley 933
{
24272 ripley 934
    char clab[15], *p;
9044 ripley 935
    int i;
936
 
9079 ripley 937
    for (i = colmin; i <= colmax; i++) {
938
	p = get_col_name(i);
939
	printstring(p, strlen(p), 0, i - colmin + 1, 0);
940
    }
9044 ripley 941
    for (i = rowmin; i <= rowmax; i++) {
24272 ripley 942
	sprintf(clab, labform, i);
9048 ripley 943
	printstring(clab, strlen(clab), i - rowmin + 1, 0, 0);
9044 ripley 944
    }
945
}
946
 
9212 ripley 947
              /* ================ GraphApp-specific ================ */
9095 ripley 948
 
24276 ripley 949
static void bell(void)
9044 ripley 950
{
951
    gabeep();
952
}
953
 
954
static void cleararea(int xpos, int ypos, int width, int height, rgb col)
955
{
956
    gfillrect(de, col, rect(xpos, ypos, width, height));
957
}
958
 
24276 ripley 959
static void clearwindow(void)
9044 ripley 960
{
9079 ripley 961
    gfillrect(de, p->bg, rect(0, 0, WIDTH, HEIGHT));
9044 ripley 962
}
963
 
964
 
9095 ripley 965
static void drawrectangle(int xpos, int ypos, int width, int height,
9044 ripley 966
			  int lwd, int fore)
967
{
12778 pd 968
    /* only used on screen, so always fast */
9095 ripley 969
    gdrawrect(de, lwd, 0, (fore==1)? p->ufg: p->bg,
31630 ripley 970
	      rect(xpos, ypos, width, height), 1, PS_ENDCAP_SQUARE, 
971
	      PS_JOIN_BEVEL, 10);
9044 ripley 972
}
973
 
974
static void de_drawtext(int xpos, int ypos, char *text)
975
{
976
    gdrawstr(de, p->f, p->fg, pt(xpos, ypos), text);
977
}
978
 
979
/* Keypress callbacks */
980
 
9212 ripley 981
static void de_normalkeyin(control c, int k)
9044 ripley 982
{
983
    int i, st;
984
    char text[1];
985
 
986
    st = ggetkeystate();
987
    if ((p->chbrk) && (k == p->chbrk) &&
988
	((!p->modbrk) || ((p->modbrk) && (st == p->modbrk)))) {
989
	p->fbrk(c);
990
	return;
991
    }
9079 ripley 992
    if (st & CtrlKey) {
9044 ripley 993
	switch (k + 'A' - 1) {
994
	case 'B':
995
	    i = rowmin - nhigh + 2;
9095 ripley 996
	    jumpwin(colmin, max(i, 1));
9044 ripley 997
	    break;
998
	case 'F':
999
	    jumpwin(colmin, rowmax);
1000
	    break;
1001
	case 'H':
32578 ripley 1002
	    moveback();
9044 ripley 1003
	    break;
1004
	case 'I':
9079 ripley 1005
	    if (st & ShiftKey) advancerect(LEFT);
1006
	    else advancerect(RIGHT);
9044 ripley 1007
	    break;
1008
	case 'N':
1009
	case 'J':
1010
	    advancerect(DOWN);
1011
	    break;
9079 ripley 1012
	case 'C':
1013
	    de_copy(de);
1014
	    break;
1015
	case 'V':
1016
	    de_paste(de);
1017
	    break;
1018
	case 'L':
9095 ripley 1019
	    for (i = colmin; i < colmax; i++)
1020
		if (i < 100) boxw[i] = get_col_width(i)*FW + 8;
9079 ripley 1021
	    drawwindow();
1022
	    break;
9044 ripley 1023
	default:
1024
	    bell();
1025
	}
1026
    } else if(k == '\b') {
32578 ripley 1027
	moveback();
9044 ripley 1028
    } else if(k == '\n' || k == '\r') {
9095 ripley 1029
	    advancerect(DOWN);
9044 ripley 1030
    } else if(k == '\t') {
9079 ripley 1031
	if (st & ShiftKey) advancerect(LEFT);
1032
	else advancerect(RIGHT);
9044 ripley 1033
    } else {
1034
	text[0] = k;
1035
	handlechar(text);
1036
    }
1037
 
1038
}
1039
 
9212 ripley 1040
static void de_ctrlkeyin(control c, int key)
9044 ripley 1041
{
1042
    int st, i;
1043
 
1044
    st = ggetkeystate();
1045
    if ((p->chbrk) && (key == p->chbrk) &&
1046
	((!p->modbrk) || ((p->modbrk) && (st == p->modbrk)))) {
1047
	p->fbrk(c);
1048
	return;
1049
    }
1050
    switch (key) {
1051
    case HOME:
1052
	jumpwin(1, 1);
9124 ripley 1053
	downlightrect();
1054
	crow = ccol = 1;
1055
	highlightrect();
9044 ripley 1056
	break;
1057
    case END:
9079 ripley 1058
	i = ymaxused - nhigh + 2;
9095 ripley 1059
	jumpwin(xmaxused, max(i, 1));
9124 ripley 1060
	downlightrect();
1061
	crow = ymaxused - rowmin + 1;
1062
	ccol = 1;
1063
	highlightrect();
9044 ripley 1064
	break;
1065
    case PGUP:
1066
	i = rowmin - nhigh + 2;
9124 ripley 1067
	jumpwin(colmin, max(i, 1));
9044 ripley 1068
	break;
1069
    case PGDN:
1070
	jumpwin(colmin, rowmax);
1071
	break;
1072
    case LEFT:
1073
	advancerect(LEFT);
1074
	break;
1075
    case RIGHT:
1076
	advancerect(RIGHT);
1077
	break;
1078
    case UP:
1079
	advancerect(UP);
1080
	break;
1081
    case DOWN:
1082
	advancerect(DOWN);
1083
	break;
1084
    case DEL:
32578 ripley 1085
	moveback();
9044 ripley 1086
	break;
1087
     case ENTER:
1088
	 advancerect(DOWN);
1089
	 break;
1090
    default:
1091
	;
1092
    }
1093
}
1094
 
1095
/* mouse callbacks */
1096
 
24276 ripley 1097
static char *get_cell_text(void)
9079 ripley 1098
{
9837 ripley 1099
    int  wrow = rowmin + crow - 2, wcol = colmin + ccol - 1;
9079 ripley 1100
    char *prev = "";
1101
    SEXP tvec;
1102
 
24272 ripley 1103
    if (wcol <= xmaxused) {
1104
	tvec = VECTOR_ELT(work, wcol - 1);
1105
	if (!isNull(tvec) && wrow < INTEGER(lens)[wcol - 1]) {
9079 ripley 1106
	    PrintDefaults(R_NilValue);
1107
	    if (TYPEOF(tvec) == REALSXP) {
1108
		if (REAL(tvec)[wrow] != ssNA_REAL)
34294 ripley 1109
		    prev = EncodeElement(tvec, wrow, 0, '.');
9079 ripley 1110
	    } else if (TYPEOF(tvec) == STRSXP) {
10172 luke 1111
		if (!streql(CHAR(STRING_ELT(tvec, wrow)),
1112
			    CHAR(STRING_ELT(ssNA_STRING, 0))))
34294 ripley 1113
		    prev = EncodeElement(tvec, wrow, 0, '.');
33001 ripley 1114
	    } else error(G_("dataentry: internal memory error"));
9079 ripley 1115
	}
1116
    }
1117
    return prev;
1118
}
1119
 
1120
static int online, clickline;
1121
 
9212 ripley 1122
static void de_mousedown(control c, int buttons, point xy)
9044 ripley 1123
{
9079 ripley 1124
    int xw, yw, wcol=0, wrow, i, w;
9095 ripley 1125
 
9079 ripley 1126
    if (buttons & LeftButton) {
9044 ripley 1127
	xw = xy.x;
1128
	yw = xy.y;
9095 ripley 1129
 
9044 ripley 1130
	closerect();
9095 ripley 1131
 
9044 ripley 1132
	/* check to see if the click was in the header */
1133
 
1134
	if (yw < hwidth + bwidth) {
1135
	    /* too high */
1136
	    return;
1137
	}
1138
	/* translate to box coordinates */
1139
 
1140
	wrow = (yw - bwidth - hwidth) / box_h;
1141
 
1142
	/* see if it is in the row labels */
9079 ripley 1143
	if (xw < bwidth + boxw[0]) {
9044 ripley 1144
	    bell();
1145
	    highlightrect();
1146
	    return;
1147
	}
9079 ripley 1148
	w = bwidth + boxw[0];
1149
	for (i = 1; i <= nwide; i++)
9095 ripley 1150
	    if((w += BOXW(i+colmin-1)) > xw) {
9079 ripley 1151
		wcol = i;
1152
		break;
1153
	}
9095 ripley 1154
 
1155
	/* see if we selected a line */
9079 ripley 1156
	w = bwidth;
1157
	online = 0;
1158
	for (i = 0; i <= nwide; i++) {
9095 ripley 1159
	    if(i == 0) w += boxw[0]; else w += BOXW(i+colmin-1);
9079 ripley 1160
	    if (abs(w - xw) <= 2) {
1161
		online = 1;
1162
		clickline = i; /* between cols i and i+1 */
1163
		highlightrect();
9095 ripley 1164
		gsetcursor(de, HandCursor);
9079 ripley 1165
		return;
1166
	    }
1167
	}
9044 ripley 1168
 
1169
	/* next check to see if it is in the column labels */
1170
 
1171
	if (yw < hwidth + bwidth + box_h) {
9095 ripley 1172
	    if (xw > bwidth + boxw[0]) {
9323 ripley 1173
		highlightrect();
9044 ripley 1174
		de_popupmenu(xw, yw, wcol);
9095 ripley 1175
		return;
1176
	    } else {
9044 ripley 1177
		/* in 0th column */
1178
		highlightrect();
1179
		bell();
1180
	    }
24265 ripley 1181
	} else if (wrow > nhigh - 1 || wcol > nwide - 1) {
9229 ripley 1182
		/* off the grid */
1183
		highlightrect();
1184
		bell();
1185
		return;
9067 ripley 1186
	} else if (buttons & DblClick) {
9095 ripley 1187
	    int x, y, bw;
9079 ripley 1188
	    char *prev;
9053 ripley 1189
	    rect rr;
9095 ripley 1190
 
9053 ripley 1191
	    ccol = wcol;
9079 ripley 1192
	    crow = wrow;
9053 ripley 1193
	    highlightrect();
1194
	    find_coords(crow, ccol, &x, &y);
9181 ripley 1195
	    bw = BOXW(ccol + colmin - 1);
9095 ripley 1196
	    rr = rect(x + text_xoffset, y - text_yoffset - 1,
1197
		      bw - text_xoffset - 2,
9079 ripley 1198
		      box_h - text_yoffset - 2);
1199
	    prev = get_cell_text();
9095 ripley 1200
	    if (strlen(prev) * FW > bw)
9053 ripley 1201
		rr.width = (strlen(prev) + 2) * FW;
9323 ripley 1202
	    addto(de);
9053 ripley 1203
	    celledit = newfield_no_border(prev, rr);
1204
	    setbackground(celledit, p->bg);
1205
	    setforeground(celledit, p->ufg);
1206
	    settextfont(celledit, p->f);
1207
	    show(celledit);
24272 ripley 1208
	    CellEditable = TRUE;
9067 ripley 1209
	} else if (buttons & LeftButton) {
1210
	    ccol = wcol;
1211
	    crow = wrow;
9044 ripley 1212
	}
1213
	highlightrect();
1214
	return;
1215
    }
1216
}
1217
 
9212 ripley 1218
static void de_mouseup(control c, int buttons, point xy)
9079 ripley 1219
{
1220
    int xw, bw, i, w;
9095 ripley 1221
 
9079 ripley 1222
    if (online) {
1223
	xw = xy.x;
1224
	w = bwidth + boxw[0];
9095 ripley 1225
	for(i = 1; i < clickline; i++) w+= BOXW(i+colmin-1);
9079 ripley 1226
	bw = xw - w;
1227
	if (bw < FW*4 + 8) bw = FW*4 + 8;
1228
	if (bw > FW*50) bw = FW*50;
9095 ripley 1229
	if(clickline < 100) boxw[clickline] = bw;
9079 ripley 1230
	gsetcursor(de, ArrowCursor);
9095 ripley 1231
	deredraw();
9079 ripley 1232
    }
1233
}
1234
 
9212 ripley 1235
static void de_redraw(control c, rect r)
9044 ripley 1236
{
9229 ripley 1237
    if (WIDTH != oldWIDTH || HEIGHT != oldHEIGHT) drawwindow();
1238
    else deredraw();
9044 ripley 1239
}
1240
 
24276 ripley 1241
static void deredraw(void)
9095 ripley 1242
{
9212 ripley 1243
    int i;
9095 ripley 1244
 
9212 ripley 1245
    setcellwidths();
9124 ripley 1246
 
9229 ripley 1247
    if(hwidth > 0) gfillrect(de, bbg, rect(0, 0, WIDTH, hwidth));
9095 ripley 1248
    gfillrect(de, bbg, rect(0, 0, boxw[0], windowHeight));
1249
 
1250
    for (i = 1; i < nhigh; i++)
1251
	drawrectangle(0, hwidth + i * box_h, boxw[0], box_h, 1, 1);
9124 ripley 1252
    colmax = colmin + (nwide - 2);
1253
    rowmax = rowmin + (nhigh - 2);
9095 ripley 1254
    printlabs();
24272 ripley 1255
    /* if (!isNull(work) I don't think it can be null */
1256
    for (i = colmin; i <= colmax; i++) drawcol(i);
27357 murdoch 1257
    gfillrect(de, p->bg, rect(windowWidth+1, hwidth, WIDTH-windowWidth-1,
9229 ripley 1258
			      HEIGHT - hwidth));
9095 ripley 1259
    highlightrect();
1260
}
1261
 
24276 ripley 1262
static void de_closewin(void)
9044 ripley 1263
{
1264
    closerect();
1265
    hide(de);
1266
    del(de);
1267
}
1268
 
9048 ripley 1269
static void copyarea(int src_x, int src_y, int dest_x, int dest_y)
1270
{
9095 ripley 1271
    int mx = max(src_x, dest_x), my = max(src_y, dest_y);
9212 ripley 1272
    copyrect(de, pt(dest_x, dest_y),
1273
	     rect(src_x, src_y, windowWidth - mx, windowHeight - my));
9048 ripley 1274
}
1275
 
9095 ripley 1276
static void copyH(int src_x, int dest_x, int width)
1277
{
27357 murdoch 1278
    copyrect(de, pt(dest_x, hwidth),
9212 ripley 1279
	     rect(src_x, hwidth, width, windowHeight - hwidth));
9095 ripley 1280
}
1281
 
24276 ripley 1282
static Rboolean initwin(void)
9095 ripley 1283
{
9212 ripley 1284
    int i;
9044 ripley 1285
    rect r;
9079 ripley 1286
 
9044 ripley 1287
    de = newdataeditor();
24276 ripley 1288
    if(!de) return TRUE;
9044 ripley 1289
    p = getdata(de);
9079 ripley 1290
 
9205 ripley 1291
    nboxchars = asInteger(GetOption(install("de.cellwidth"), R_GlobalEnv));
1292
    if (nboxchars == NA_INTEGER || nboxchars < 0) nboxchars = 0;
1293
    if (nboxchars > 0) check(de_mvw);
1294
    box_w = ((nboxchars >0)?nboxchars:FIELDWIDTH)*FW + 8;
24272 ripley 1295
    /* this used to presume 4 chars sufficed for row numbering */
1296
    labdigs = max(3, 1+floor(log10((double)ymaxused)));
1297
    boxw[0] = (1+labdigs)*FW + 8;
1298
    sprintf(labform, "%%%dd", labdigs);
9079 ripley 1299
    for(i = 1; i < 100; i++) boxw[i] = get_col_width(i)*FW + 8;
9044 ripley 1300
    box_h = FH + 4;
1301
    text_xoffset = 5;
9053 ripley 1302
    text_yoffset = -3;
9212 ripley 1303
    setcellwidths();
9229 ripley 1304
    nhigh = (HEIGHT - 2 * bwidth - hwidth - 3) / box_h;
9212 ripley 1305
    windowHeight = nhigh * box_h + 2 * bwidth + hwidth;
9044 ripley 1306
    r = getrect(de);
1307
    r.width = windowWidth + 3;
1308
    r.height = windowHeight + 3;
9079 ripley 1309
    resize(de, r);
1310
 
24272 ripley 1311
    CellModified = CellEditable = FALSE;
9229 ripley 1312
    bbg = dialog_bg();
9044 ripley 1313
    /* set the active cell to be the upper left one */
1314
    crow = 1;
1315
    ccol = 1;
9095 ripley 1316
    /* drawwindow(); done as repaint but
1317
       decide if we need scrollbars here to avoid flashing*/
1318
    nhigh = (HEIGHT - 2 * bwidth - hwidth) / box_h;
27357 murdoch 1319
    gchangescrollbar(de, VWINSB, 0, ymaxused/yScrollbarScale,
24259 ripley 1320
		     max(nhigh/yScrollbarScale, 1), 0);
9212 ripley 1321
    setcellwidths();
24259 ripley 1322
    gchangescrollbar(de, HWINSB, 0, xmaxused/xScrollbarScale,
27357 murdoch 1323
		     max(nwide/xScrollbarScale, 1), 0);
9044 ripley 1324
    show(de);
12256 pd 1325
    show(de); /* a precaution, as PD reports transparent windows */
27357 murdoch 1326
    BringToTop(de, 0);
24276 ripley 1327
    R_de_up = TRUE;
1328
    return FALSE;
9044 ripley 1329
}
1330
 
1331
/* Menus */
1332
 
9205 ripley 1333
static window wconf, devw;
9044 ripley 1334
static radiobutton rb_num, rb_char;
1335
static label lwhat, lrb;
1336
static field varname;
1337
static int isnumeric, popupcol;
1338
 
1339
static void popupclose(control c)
1340
{
1341
    SEXP tvec;
24272 ripley 1342
    char buf[30], clab[25];
1343
    int i;
9044 ripley 1344
 
9323 ripley 1345
    strcpy(buf, gettext(varname));
1346
    if(!strlen(buf)) {
33093 ripley 1347
	askok(G_("column names cannot be blank"));
9044 ripley 1348
	return;
1349
    }
24272 ripley 1350
    if (popupcol > xmaxused) {
1351
	/* extend work, names and lens */
1352
	REPROTECT(work = lengthgets(work, popupcol), wpi);
1353
	REPROTECT(names = lengthgets(names, popupcol), npi);
1354
	/* Last col name is set later */
1355
	for (i = xmaxused+1; i < popupcol - 1; i++) {
1356
	    sprintf(clab, "var%d", i + 1);
1357
	    SET_STRING_ELT(names, i, mkChar(clab));
1358
	}
1359
	REPROTECT(lens = lengthgets(lens, popupcol), lpi);
1360
	xmaxused = popupcol;
9044 ripley 1361
    }
24272 ripley 1362
    tvec = VECTOR_ELT(work, popupcol - 1);
9044 ripley 1363
    if(ischecked(rb_num) && !isnumeric) {
27357 murdoch 1364
	if (isNull(tvec))
24276 ripley 1365
	    SET_VECTOR_ELT(work, popupcol - 1, ssNewVector(REALSXP, 100));
24272 ripley 1366
	else
1367
	    SET_VECTOR_ELT(work, popupcol - 1, coerceVector(tvec, REALSXP));
9044 ripley 1368
    } else if(ischecked(rb_char) && isnumeric) {
27357 murdoch 1369
	if (isNull(tvec))
24276 ripley 1370
	    SET_VECTOR_ELT(work, popupcol - 1, ssNewVector(STRSXP, 100));
24272 ripley 1371
	else
1372
	    SET_VECTOR_ELT(work, popupcol - 1, coerceVector(tvec, STRSXP));
9044 ripley 1373
    }
24272 ripley 1374
    SET_STRING_ELT(names, popupcol - 1, mkChar(buf));
9044 ripley 1375
    hide(wconf);
1376
    del(wconf);
1377
}
1378
 
9205 ripley 1379
static void nm_hit_key(window w, int key)
1380
{
1381
    if(key == '\n') popupclose(wconf);
1382
}
1383
 
9044 ripley 1384
static void de_popupmenu(int x_pos, int y_pos, int col)
1385
{
9079 ripley 1386
    char *blah;
9236 ripley 1387
    rect r = screen_coords(de);
9044 ripley 1388
 
1389
    popupcol = colmin + col - 1;
9079 ripley 1390
    blah = get_col_name(popupcol);
33093 ripley 1391
    wconf = newwindow(G_("Variable editor"),
9044 ripley 1392
		      rect(x_pos + r.x-150, y_pos + r.y-50, 300, 100),
11073 ripley 1393
		      Titlebar | Closebox | Modal);
9044 ripley 1394
    setclose(wconf, popupclose);
9212 ripley 1395
    setbackground(wconf, bbg);
33093 ripley 1396
    lwhat = newlabel(G_("variable name"), rect(10, 22, 90, 20), AlignLeft);
9044 ripley 1397
    varname = newfield(blah, rect(100, 20, 120, 20));
33093 ripley 1398
    lrb = newlabel(G_("type"), rect(50, 62, 50, 20), AlignLeft);
9044 ripley 1399
    rb_num = newradiobutton("numeric", rect(100, 60 , 80, 20), NULL);
1400
    rb_char = newradiobutton("character", rect(180, 60 , 80, 20), NULL);
9095 ripley 1401
    isnumeric = (get_col_type(popupcol) == NUMERIC);
9044 ripley 1402
    if (isnumeric) check(rb_num); else check(rb_char);
9205 ripley 1403
    setkeydown(wconf, nm_hit_key);
9044 ripley 1404
    show(wconf);
1405
}
9079 ripley 1406
 
9212 ripley 1407
static void de_copy(control c)
9079 ripley 1408
{
9212 ripley 1409
    copystringtoclipboard(get_cell_text());
9079 ripley 1410
}
1411
 
9212 ripley 1412
static void de_paste(control c)
9079 ripley 1413
{
9212 ripley 1414
    char *p;
9079 ripley 1415
 
1416
    closerect();
9212 ripley 1417
    if ( clipboardhastext() &&
32888 ripley 1418
	 !getstringfromclipboard(buf, 1999) ) {
9212 ripley 1419
	/* set current cell to first line of clipboard */
24272 ripley 1420
	CellModified = TRUE;
9079 ripley 1421
	if ((p = strchr(buf, '\n'))) *p = '\0';
1422
	clength = strlen(buf);
1423
	bufp = buf + clength;
1424
	closerect();
1425
    }
9205 ripley 1426
    highlightrect();
9079 ripley 1427
}
1428
 
9212 ripley 1429
static void de_delete(control c)
9205 ripley 1430
{
24272 ripley 1431
    CellModified = TRUE;
9205 ripley 1432
    buf[0] = '\0';
1433
    clength = -1;
1434
    bufp = buf + clength;
1435
    closerect();
1436
    highlightrect();
1437
}
1438
 
9212 ripley 1439
static void de_autosize(control c)
9079 ripley 1440
{
1441
    int col = ccol + colmin - 1;
9837 ripley 1442
 
1443
    closerect();
9095 ripley 1444
    if(col < 100) {
1445
	boxw[col] = get_col_width(col)*FW + 8;
1446
	deredraw();
1447
    }
9079 ripley 1448
}
1449
 
27662 murdoch 1450
static void de_stayontop(control c)
1451
{
27686 murdoch 1452
    BringToTop(de, 2);
27662 murdoch 1453
}
1454
 
9212 ripley 1455
static void de_sbf(control c, int pos)
9079 ripley 1456
{
1457
    if (pos < 0) { /* horizontal */
24259 ripley 1458
	colmin = 1 + (-pos*xScrollbarScale - 1);
9079 ripley 1459
    } else {
24259 ripley 1460
	rowmin = 1 + pos*yScrollbarScale;
34200 murdoch 1461
	if(rowmin > ymaxused - nhigh + 2) rowmin = max(1,ymaxused - nhigh + 2);
9079 ripley 1462
    }
1463
    drawwindow();
1464
}
9205 ripley 1465
 
1466
static checkbox varwidths;
1467
 
1468
static void vw_close(control c)
1469
{
1470
    int x;
1471
    if (ischecked(varwidths)) x = 0;
1472
    else x = atoi(gettext(varname)); /* 0 if error */
9837 ripley 1473
    x = min(x, 50);
9205 ripley 1474
    if (x != nboxchars) {
1475
	nboxchars = x;
9837 ripley 1476
	box_w = ((nboxchars >0)?nboxchars:FIELDWIDTH)*FW + 8;
9205 ripley 1477
	deredraw();
1478
    }
1479
    hide(devw);
1480
    del(devw);
1481
    if (nboxchars > 0) check(de_mvw);
9837 ripley 1482
    else uncheck(de_mvw);
9323 ripley 1483
    addto(de);
9205 ripley 1484
}
1485
 
1486
static void vw_hit_key(window w, int key)
1487
{
1488
    if(key == '\n') vw_close(w);
1489
}
1490
 
1491
static void vw_callback(control c)
1492
{
1493
    if (ischecked(varwidths)) disable(varname);
1494
    else enable(varname);
1495
}
1496
 
1497
 
24276 ripley 1498
static void de_popup_vw(void)
9205 ripley 1499
{
1500
    char blah[25];
1501
 
33001 ripley 1502
    devw = newwindow(G_("Cell width(s)"),
9205 ripley 1503
		      rect(0, 0, 250, 60),
11073 ripley 1504
		      Titlebar | Centered | Closebox | Modal);
9205 ripley 1505
    setclose(devw, vw_close);
9212 ripley 1506
    setbackground(devw, bbg);
33001 ripley 1507
    lwhat = newlabel(G_("Cell width"), rect(10, 20, 70, 20), AlignLeft);
9205 ripley 1508
    sprintf(blah, "%d", nboxchars);
1509
    varname = newfield(blah, rect(80, 20, 40, 20));
33001 ripley 1510
    varwidths = newcheckbox(G_("variable"), rect(150, 20, 80, 20), vw_callback);
9205 ripley 1511
    if (nboxchars == 0) {
1512
	check(varwidths);
1513
	disable(varname);
1514
    }
1515
    setkeydown(devw, vw_hit_key);
1516
    show(devw);
1517
}
1518
 
9212 ripley 1519
static void menudecellwidth(control m)
9205 ripley 1520
{
1521
    de_popup_vw();
1522
}
9212 ripley 1523
 
1524
static void deldataeditor(control m)
1525
{
1526
    freeConsoleData(getdata(m));
1527
}
1528
 
1529
static void declose(control m)
1530
{
1531
    de_closewin();
1532
    show(RConsole);
24276 ripley 1533
    R_de_up = FALSE;
9212 ripley 1534
}
1535
 
1536
static void deresize(console c, rect r)
32606 ripley 1537
{
9212 ripley 1538
    if (((WIDTH  == r.width) &&
1539
	 (HEIGHT == r.height)) ||
1540
	(r.width == 0) || (r.height == 0) ) /* minimize */
32606 ripley 1541
        return;;
9212 ripley 1542
    WIDTH = r.width;
1543
    HEIGHT = r.height;
32606 ripley 1544
}
9212 ripley 1545
 
32606 ripley 1546
 
9212 ripley 1547
static void menudehelp(control m)
1548
{
33001 ripley 1549
    char s[] = GN_("Navigation.\n  Keyboard: cursor keys move selection\n\tTab move right, Shift+Tab moves left\n\tPgDn or Ctrl+F: move down one screenful\n\tPgUp or Ctrl+B: move up one screenful\n\tHome: move to (1,1) cell\n\tEnd: show last rows of last column.\n   Mouse: left-click in a cell, use the scrollbar(s).\n\nEditing.\n  Type in the currently hightlighted cell\n  Double-click in a cell for an editable field\n\nMisc.\n  Ctrl-L redraws the screen, auto-resizing the columns\n  Ctrl-C copies selected cell\n  Ctrl-V pastes to selected cell\n  Right-click menu for copy, paste, autosize currently selected column\n\n");
1550
    askok(G_(s));
9212 ripley 1551
}
1552
 
1553
 
1554
static MenuItem DePopup[28] = {
33001 ripley 1555
    {GN_("Help"), menudehelp, 0},
9212 ripley 1556
    {"-", 0, 0},
33001 ripley 1557
    {GN_("Copy selected cell"), de_copy, 0},
1558
    {GN_("Paste to selected cell"), de_paste, 0},
1559
    {GN_("Autosize column"), de_autosize, 0},
9212 ripley 1560
    {"-", 0, 0},
33001 ripley 1561
    {GN_("Stay on top"), de_stayontop, 0},
27662 murdoch 1562
    {"-", 0, 0},
33001 ripley 1563
    {GN_("Close"), declose, 0},
9212 ripley 1564
    LASTMENUITEM
1565
};
1566
 
1567
static void demenuact(control m)
1568
{
1569
    /* use this to customize the menu */
1570
}
1571
 
1572
static void depopupact(control m)
1573
{
1574
    /* use this to customize the menu */
27662 murdoch 1575
    if (ismdi())
1576
    	disable(DePopup[6].m);
27686 murdoch 1577
    else {
1578
    	if (isTopmost(de))
1579
    	    check(DePopup[6].m);
1580
    	else
1581
    	    uncheck(DePopup[6].m);
1582
    }
9212 ripley 1583
}
1584
 
1585
 
1586
#define MCHECK(a) if (!(a)) {del(c);return NULL;}
1587
 
24283 ripley 1588
RECT *RgetMDIsize(); /* in rui.c */
1589
 
24276 ripley 1590
static dataeditor newdataeditor(void)
9212 ripley 1591
{
1592
    ConsoleData p;
1593
    int w, h, x, y;
1594
    dataeditor c;
1595
    menuitem m;
27357 murdoch 1596
 
9212 ripley 1597
    p = newconsoledata((consolefn) ? consolefn : FixedFont,
11588 ripley 1598
		       pagerrow, pagercol, 0, 0,
9212 ripley 1599
		       consolefg, consoleuser, consolebg,
1600
		       DATAEDITOR);
1601
    if (!p) return NULL;
1602
 
1603
    w = WIDTH ;
1604
    h = HEIGHT;
1605
    if (ismdi()) {
1606
	RECT *pR = RgetMDIsize();
1607
	x = (pR->right - w) / 3; x = x > 20 ? x:20;
1608
	y = (pR->bottom - h) / 3; y = y > 20 ? y:20;
1609
    } else {
1610
	x = (devicewidth(NULL) - w) / 3;
1611
	y = (deviceheight(NULL) - h) / 3 ;
1612
    }
33001 ripley 1613
    c = (dataeditor) newwindow(G_("Data Editor"), rect(x, y, w, h),
24265 ripley 1614
			       Document | StandardWindow | Menubar |
1615
			       VScrollbar | HScrollbar | TrackMouse);
9212 ripley 1616
    if (!c) {
1617
         freeConsoleData(p);
1618
         return NULL;
1619
    }
1620
    setdata(c, p);
1621
    if(h == 0) HEIGHT = getheight(c);
1622
    if(w == 0) WIDTH  = getwidth(c);
1623
    COLS = WIDTH / FW - 1;
1624
    ROWS = HEIGHT / FH - 1;
1625
    BORDERX = (WIDTH - COLS*FW) / 2;
1626
    BORDERY = (HEIGHT - ROWS*FH) / 2;
1627
    gsetcursor(c, ArrowCursor);
1628
    setbackground(c, consolebg);
1629
    if (ismdi() && (RguiMDI & RW_TOOLBAR)) {
1630
	/* blank toolbar to stop windows jumping around */
1631
        int btsize = 24;
1632
        control tb;
1633
        addto(c);
1634
        MCHECK(tb = newtoolbar(btsize + 4));
1635
	gsetcursor(tb, ArrowCursor);
1636
    }
1637
    MCHECK(gpopup(depopupact, DePopup));
1638
    MCHECK(m = newmenubar(demenuact));
33001 ripley 1639
    MCHECK(newmenu(G_("File")));
9212 ripley 1640
/*    MCHECK(m = newmenuitem("-", 0, NULL));*/
33001 ripley 1641
    MCHECK(m = newmenuitem(G_("Close"), 0, declose));
9212 ripley 1642
    newmdimenu();
33001 ripley 1643
    MCHECK(newmenu(G_("Edit")));
1644
    MCHECK(m = newmenuitem(G_("Copy  \tCTRL+C"), 0, de_copy));
1645
    MCHECK(m = newmenuitem(G_("Paste \tCTRL+V"), 0, de_paste));
1646
    MCHECK(m = newmenuitem(G_("Delete\tDEL"), 0, de_delete));
9212 ripley 1647
    MCHECK(m = newmenuitem("-", 0, NULL));
33001 ripley 1648
    MCHECK(de_mvw = newmenuitem(G_("Cell widths ..."), 0, menudecellwidth));
1649
    MCHECK(m = newmenu(G_("Help")));
1650
    MCHECK(newmenuitem(G_("Data editor"), 0, menudehelp));
27357 murdoch 1651
 
9212 ripley 1652
    setdata(c, p);
1653
    setresize(c, deresize);
1654
    setredraw(c, de_redraw);
1655
    setdel(c, deldataeditor);
1656
    setclose(c, declose);
1657
    sethit(c, de_sbf);
1658
    setkeyaction(c, de_ctrlkeyin);
1659
    setkeydown(c, de_normalkeyin);
1660
    setmousedown(c, de_mousedown);
1661
    setmouseup(c, de_mouseup);
1662
    return(c);
1663
}