The R Project SVN R

Rev

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

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