The R Project SVN R

Rev

Rev 27662 | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

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