The R Project SVN R

Rev

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

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