The R Project SVN R

Rev

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

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