The R Project SVN R

Rev

Rev 36044 | Rev 36820 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
13974 hornik 1
/*
2
 *  R : A Computer Langage for Statistical Data Analysis
3
 *  Copyright (C) 1995, 1996  Robert Gentleman and Ross Ihaka
32429 ripley 4
 *  Copyright (C) 1998--2005  Robert Gentleman, Ross Ihaka and the
13974 hornik 5
 *                            R Development Core Team
6
 *
7
 *  This program is free software; you can redistribute it and/or modify
8
 *  it under the terms of the GNU General Public License as published by
9
 *  the Free Software Foundation; either version 2 of the License, or
10
 *  (at your option) any later version.
11
 *
12
 *  This program is distributed in the hope that it will be useful,
13
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 *  GNU General Public License for more details.
16
 *
17
 *  You should have received a copy of the GNU General Public License
18
 *  along with this program; if not, write to the Free Software
19
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20
 */
21
 
34639 ripley 22
/* <UTF8>
32555 ripley 23
   Used XTextWidth and XDrawText, so need to use fontsets
32422 ripley 24
 
32555 ripley 25
   Also needed input context.
32432 ripley 26
*/
27
 
34639 ripley 28
/* The version for R 2.1.0 is partly based on patches by
35930 ripley 29
   Ei-ji Nakama <nakama@ki.rim.or.jp> for use with Japanese fonts. */
32429 ripley 30
 
34639 ripley 31
#define DPRINTS(x) printf(#x "=[%s]\n", x)
32
#define DPRINTX(x) printf(#x "=%x\n", x)
33
#define DPRINTD(x) printf(#x "=%d\n", x)
34
 
13974 hornik 35
#ifdef HAVE_CONFIG_H
36
#include <config.h>
37
#endif
38
 
36498 ripley 39
#include <Defn.h>
13974 hornik 40
#include <stdlib.h>
41
 
29066 ripley 42
#ifndef _Xconst
43
#define _Xconst const
44
#endif
13974 hornik 45
#include <X11/X.h>
46
#include <X11/Xlib.h>
47
#include <X11/Xutil.h>
48
#include <X11/keysym.h>
49
#include <X11/cursorfont.h>
36044 ripley 50
#include <X11/Intrinsic.h>
13974 hornik 51
 
28840 ripley 52
#include "Print.h"
53
 
32677 ripley 54
#ifdef SUPPORT_MBCS
55
/* This only uses a FontSet in a MBCS */
56
# define USE_FONTSET 1
35844 ripley 57
/* In theory we should do this, but it works less well
58
# ifdef X_HAVE_UTF8_STRING
59
#  define HAVE_XUTF8TEXTEXTENTS 1
60
#  define HAVE_XUTF8DRAWSTRING 1
61
#  define HAVE_XUTF8DRAWIMAGESTRING 1
62
# endif */
32677 ripley 63
#endif
64
 
29067 ripley 65
#ifndef HAVE_KEYSYM
66
#define KeySym int
67
#endif
28840 ripley 68
 
13974 hornik 69
#define DEEvent XEvent
70
 
71
typedef enum { UP, DOWN, LEFT, RIGHT } DE_DIRECTION;
72
 
73
typedef enum {UNKNOWNN, NUMERIC, CHARACTER} CellType;
74
 
75
/* EXPORTS : */
76
SEXP RX11_dataentry(SEXP call, SEXP op, SEXP args, SEXP rho);
77
 
78
/* Local Function Definitions */
32424 ripley 79
 
13974 hornik 80
static void advancerect(DE_DIRECTION);
81
static int  CheckControl(DEEvent*);
82
static int  CheckShift(DEEvent*);
83
static int  checkquit(int);
84
static void clearrect(void);
85
static void clearwindow(void);
86
static void closerect(void);
87
static void closewin(void);
88
static void copycell(void);
89
static void doControl(DEEvent*);
90
static int  doMouseDown(DEEvent*);
91
static void eventloop(void);
92
static void doSpreadKey(int, DEEvent*);
93
static void downlightrect(void);
94
static void drawwindow(void);
95
static void drawcol(int);
96
static void drawrow(int);
97
static void find_coords(int, int, int*, int*);
98
static int  findcell(void);
32432 ripley 99
static char *GetCharP(DEEvent*);
13974 hornik 100
static KeySym GetKey(DEEvent*);
101
static void handlechar(char*);
102
static void highlightrect(void);
103
static Rboolean initwin(void);
104
static void jumppage(DE_DIRECTION);
105
static void jumpwin(int, int);
106
static void pastecell(int, int);
107
static void popdownmenu(void);
108
static void popupmenu(int, int, int, int);
109
static void printlabs(void);
110
static void printrect(int, int);
111
static void printstring(char*, int, int, int, int);
112
static void printelt(SEXP, int, int, int);
113
static void RefreshKeyboardMapping(DEEvent*);
34639 ripley 114
static void cell_cursor_init(void);
32424 ripley 115
 
13974 hornik 116
/* Functions to hide Xlib calls */
117
static void bell(void);
118
static void cleararea(int, int, int, int);
119
static void copyH(int, int, int);
120
static void copyarea(int, int, int, int);
121
static void doConfigure(DEEvent *ioevent);
122
#if 0
123
static void drawline(int, int, int, int);
124
#endif
125
static void drawrectangle(int, int, int, int, int, int);
126
static void drawtext(int, int, char*, int);
34639 ripley 127
#if 0
13974 hornik 128
static int  NextEvent(DEEvent *ioevent);
34639 ripley 129
#endif
13974 hornik 130
static void RefreshKeyboardMapping(DEEvent *ioevent);
131
static void Rsync(void);
132
static int textwidth(char*, int);
133
static int WhichEvent(DEEvent ioevent);
134
 
34639 ripley 135
static char *get_col_name(int col);
136
static int  get_col_width(int col);
137
static CellType get_col_type(int col);
35415 ripley 138
#ifdef USE_FONTSET
34639 ripley 139
static void calc_pre_edit_pos(void);
35415 ripley 140
#endif
34639 ripley 141
static int last_wchar_bytes(char *);
24274 ripley 142
static SEXP work, names, lens;
143
static PROTECT_INDEX wpi, npi, lpi;
144
static SEXP ssNA_STRING;
145
static double ssNA_REAL;
13974 hornik 146
 
147
/* Global variables needed for the graphics */
32424 ripley 148
 
13974 hornik 149
static int box_w;                       /* width of a box */
32432 ripley 150
static int boxw[100];                   /* widths of cells */
13974 hornik 151
static int box_h;                       /* height of a box */
152
static int windowWidth;                 /* current width of the window */
153
static int fullwindowWidth;
154
static int windowHeight;                /* current height of the window */
155
static int fullwindowHeight;
156
static int currentexp;                  /* boolean: whether an cell is active */
157
static int crow;                        /* current row */
158
static int ccol;                        /* current column */
159
static int nwide, nhigh;
160
static int colmax, colmin, rowmax, rowmin;
161
static int ndecimal;                    /* count decimal points */
162
static int ne;                          /* count exponents */
163
static int nneg;			/* indicate whether its a negative */
164
static int clength;                     /* number of characters currently entered */
34639 ripley 165
 
166
#define BOOSTED_BUF_SIZE    201
167
static char buf[BOOSTED_BUF_SIZE];	/* boosted to allow for MBCS */
13974 hornik 168
static char *bufp;
169
static int bwidth;			/* width of the border */
170
static int hwidth;			/* width of header  */
171
static int text_offset;
32424 ripley 172
 
13974 hornik 173
static SEXP ssNewVector(SEXPTYPE, int);
174
 
175
static Atom _XA_WM_PROTOCOLS, protocol;
176
 
177
static Rboolean newcol, CellModified;
178
static int nboxchars;
179
static int xmaxused, ymaxused;
180
static int box_coords[6];
32424 ripley 181
static char copycontents[sizeof(buf)+1] ;
24271 ripley 182
static int labdigs=4;
183
static char labform[6];
13974 hornik 184
 
185
 
186
/* Xwindows Globals */
32424 ripley 187
 
13974 hornik 188
static Display          *iodisplay;
189
static Window           iowindow, menuwindow, menupanes[4];
190
static GC               iogc;
32424 ripley 191
static XFontStruct      *font_info;
13974 hornik 192
static char             *font_name="9x15";
35415 ripley 193
#ifdef USE_FONTSET
34639 ripley 194
static Status           status;
32424 ripley 195
static XFontSet         font_set;
196
static XFontStruct	**fs_list;
197
static int		font_set_cnt;
34639 ripley 198
static char             *fontset_name="-*-fixed-medium-r-normal--13-*-*-*-*-*-*-*";
32518 ripley 199
static XIM		ioim;
34639 ripley 200
static XIMStyle         ioim_style;
201
static XIMStyles        *ioim_styles;
202
 
203
/*
204
 * XIM:
205
 * OverTheSpot XIMPreeditPosition | XIMStatusArea;
206
 * OffTheSpot  XIMPreeditArea     | XIMStatusArea;
207
 * Root        XIMPreeditNothing  | XIMStatusNothing;
208
 */
209
static XIMStyle         preedit_styles[]={
210
  XIMPreeditPosition,
211
  XIMPreeditArea,
212
  XIMPreeditNothing,
213
  XIMPreeditNone,
214
  (XIMStyle)NULL,
215
};
216
static XIMStyle         status_styles[]={
217
  XIMStatusArea,
218
  XIMStatusNothing,
219
  XIMStatusNone,
220
  (XIMStyle)NULL,
221
};
32472 ripley 222
static XIC		ioic;
32424 ripley 223
#endif
13974 hornik 224
 
225
#define mouseDown 	ButtonPress
226
#define keyDown		KeyPress
227
#define activateEvt	MapNotify
228
#define updateEvt	Expose
32424 ripley 229
 
13974 hornik 230
#ifndef max
231
#define max(a, b) (((a)>(b))?(a):(b))
232
#endif
233
#ifndef min
234
#define min(a, b) (((a)<(b))?(a):(b))
235
#endif
236
#define BOXW(x) (min(((x<100 && nboxchars==0)?boxw[x]:box_w), fullwindowWidth-boxw[0]-2*bwidth-2))
237
 
24274 ripley 238
/*
239
  Underlying assumptions (for this version R >= 1.8.0)
13974 hornik 240
 
24274 ripley 241
  The data are stored in a list `work', with unused columns having
242
  NULL entries.  The names for the list are in `names', which should
32424 ripley 243
  have a name for all displayable columns (up to xmaxused).
24274 ripley 244
  The *used* lengths of the columns are in `lens': this needs only be
245
  set for non-NULL columns.
246
 
32424 ripley 247
  If the list was originally length(0), that should work with
32432 ripley 248
 
24274 ripley 249
 
250
  All row and col numbers are 1-based.
251
 
252
  BDR May 2003
253
 */
254
 
13974 hornik 255
/*
256
   The spreadsheet function returns a list of vectors. The types of
257
   these vectors can be specified by the user as can their names. It
258
   the names are specified they are set during initialization. The
259
   user can change these via a menu interface, they can also change
260
   the type.
261
 
262
   The vectors are created too long and if they need to be increased
263
   this is done by using the next higher power of 2. They start 100
32360 ripley 264
   long.  Vectors are initialized to NA when they are created so that
265
   NA is returned for any cell that was not set by the user.  So that
266
   coercion back and forth maintains values of ssNA_REAL and
267
   ssNA_STRING I have set ssNA_STRING to be coerceVector(ssNA_REAL),
268
   very weird but easy.
13974 hornik 269
 
24733 ripley 270
   In Macintosh we needed to call the main event loop to get
13974 hornik 271
   events. This ensures that the spreadsheet interacts well with the
272
   other windows. Under X windows we let the window manager handle
273
   those sorts of details.
274
 
275
 */
276
 
277
static char *menu_label[] =
278
{
34639 ripley 279
    " Real",
280
    " Character",
281
    "Change Name ",
13974 hornik 282
};
283
 
284
/*
285
   ssNewVector is just an interface to allocVector but it lets us
286
   set the fields to NA. We need to have a special NA for reals and
287
   strings so that we can differentiate between uninitialized elements
288
   in the vectors and user supplied NA's; hence ssNA_REAL and ssNA_STRING
289
 */
290
 
291
static SEXP ssNewVector(SEXPTYPE type, int vlen)
292
{
293
    SEXP tvec;
294
    int j;
295
 
296
    tvec = allocVector(type, vlen);
297
    for (j = 0; j < vlen; j++)
298
	if (type == REALSXP)
299
	    REAL(tvec)[j] = ssNA_REAL;
300
	else if (type == STRSXP)
301
	    SET_STRING_ELT(tvec, j, STRING_ELT(ssNA_STRING, 0));
302
    return (tvec);
303
}
304
 
14561 luke 305
static void closewin_cend(void *data)
306
{
307
    closewin();
308
}
309
 
13974 hornik 310
SEXP RX11_dataentry(SEXP call, SEXP op, SEXP args, SEXP rho)
311
{
24274 ripley 312
    SEXP colmodes, tnames, tvec, tvec2, work2;
13974 hornik 313
    SEXPTYPE type;
24274 ripley 314
    int i, j, cnt, len, nprotect;
13974 hornik 315
    RCNTXT cntxt;
24274 ripley 316
    char clab[25];
13974 hornik 317
 
318
    nprotect = 0;/* count the PROTECT()s */
24274 ripley 319
    PROTECT_WITH_INDEX(work = duplicate(CAR(args)), &wpi); nprotect++;
320
    colmodes = CADR(args);
321
    tnames = getAttrib(work, R_NamesSymbol);
13974 hornik 322
 
24274 ripley 323
    if (TYPEOF(work) != VECSXP || TYPEOF(colmodes) != VECSXP)
13974 hornik 324
	errorcall(call, "invalid argument");
325
 
24274 ripley 326
    /* initialize the constants */
13974 hornik 327
 
328
    bufp = buf;
329
    ne = 0;
330
    currentexp = 0;
331
    nneg = 0;
332
    ndecimal = 0;
333
    clength = 0;
334
    ccol = 1;
335
    crow = 1;
336
    colmin = 1;
337
    rowmin = 1;
338
    ssNA_REAL = -NA_REAL;
339
    tvec = allocVector(REALSXP, 1);
340
    REAL(tvec)[0] = ssNA_REAL;
341
    PROTECT(ssNA_STRING = coerceVector(tvec, STRSXP)); nprotect++;
342
    bwidth = 5;
343
    hwidth = 30;
344
 
24274 ripley 345
    /* setup work, names, lens  */
346
    xmaxused = length(work); ymaxused = 0;
347
    PROTECT_WITH_INDEX(lens = allocVector(INTSXP, xmaxused), &lpi);
348
    nprotect++;
13974 hornik 349
 
24274 ripley 350
    if (isNull(tnames)) {
351
	PROTECT_WITH_INDEX(names = allocVector(STRSXP, xmaxused), &npi);
352
	for(i = 0; i < xmaxused; i++) {
353
	    sprintf(clab, "var%d", i);
354
	    SET_STRING_ELT(names, i, mkChar(clab));
13974 hornik 355
	}
24274 ripley 356
    } else
357
	PROTECT_WITH_INDEX(names = duplicate(tnames), &npi);
358
    nprotect++;
359
    for (i = 0; i < xmaxused; i++) {
360
	int len = LENGTH(VECTOR_ELT(work, i));
361
	INTEGER(lens)[i] = len;
362
	ymaxused = max(len, ymaxused);
363
	type = TYPEOF(VECTOR_ELT(work, i));
25365 ripley 364
	if (LENGTH(colmodes) > 0 && !isNull(VECTOR_ELT(colmodes, i)))
24274 ripley 365
	    type = str2type(CHAR(STRING_ELT(VECTOR_ELT(colmodes, i), 0)));
366
	if (type != STRSXP) type = REALSXP;
367
	if (isNull(VECTOR_ELT(work, i))) {
368
	    if (type == NILSXP) type = REALSXP;
369
	    SET_VECTOR_ELT(work, i, ssNewVector(type, 100));
370
	} else if (!isVector(VECTOR_ELT(work, i)))
371
	    errorcall(call, "invalid type for value");
372
	else {
373
	    if (TYPEOF(VECTOR_ELT(work, i)) != type)
32424 ripley 374
		SET_VECTOR_ELT(work, i,
24274 ripley 375
			       coerceVector(VECTOR_ELT(work, i), type));
376
	}
13974 hornik 377
    }
378
 
379
 
380
    /* start up the window, more initializing in here */
381
    if (initwin())
382
	errorcall(call, "invalid device");
383
 
384
    /* set up a context which will close the window if there is an error */
35450 murdoch 385
    begincontext(&cntxt, CTXT_CCODE, R_NilValue, R_BaseEnv, R_BaseEnv,
23463 luke 386
		 R_NilValue, R_NilValue);
14561 luke 387
    cntxt.cend = &closewin_cend;
388
    cntxt.cenddata = NULL;
13974 hornik 389
 
390
    highlightrect();
391
 
34639 ripley 392
    cell_cursor_init();
393
 
13974 hornik 394
    eventloop();
395
 
396
    endcontext(&cntxt);
397
    closewin();
398
 
399
    /* drop out unused columns */
24274 ripley 400
    for(i = 0, cnt = 0; i < xmaxused; i++)
401
	if(!isNull(VECTOR_ELT(work, i))) cnt++;
402
    if (cnt < xmaxused) {
403
	PROTECT(work2 = allocVector(VECSXP, cnt)); nprotect++;
404
	for(i = 0, j = 0; i < xmaxused; i++) {
405
	    if(!isNull(VECTOR_ELT(work, i))) {
406
		SET_VECTOR_ELT(work2, j, VECTOR_ELT(work, i));
407
		INTEGER(lens)[j] = INTEGER(lens)[i];
408
		SET_STRING_ELT(names, j, STRING_ELT(names, i));
409
		j++;
13974 hornik 410
	    }
411
	}
24274 ripley 412
	REPROTECT(names = lengthgets(names, cnt), npi);
413
    } else work2 = work;
13974 hornik 414
 
24274 ripley 415
    for (i = 0; i < LENGTH(work2); i++) {
416
	len = INTEGER(lens)[i];
417
	tvec = VECTOR_ELT(work2, i);
418
	if (LENGTH(tvec) != len) {
419
	    tvec2 = ssNewVector(TYPEOF(tvec), len);
420
	    for (j = 0; j < len; j++) {
421
		if (TYPEOF(tvec) == REALSXP) {
422
		    if (REAL(tvec)[j] != ssNA_REAL)
423
			REAL(tvec2)[j] = REAL(tvec)[j];
13974 hornik 424
		    else
425
			REAL(tvec2)[j] = NA_REAL;
24274 ripley 426
		} else if (TYPEOF(tvec) == STRSXP) {
427
		    if (!streql(CHAR(STRING_ELT(tvec, j)),
13974 hornik 428
				CHAR(STRING_ELT(ssNA_STRING, 0))))
24274 ripley 429
			SET_STRING_ELT(tvec2, j, STRING_ELT(tvec, j));
13974 hornik 430
		    else
431
			SET_STRING_ELT(tvec2, j, NA_STRING);
432
		} else
433
		    error("dataentry: internal memory problem");
24274 ripley 434
	    }
435
	    SET_VECTOR_ELT(work2, i, tvec2);
13974 hornik 436
	}
437
    }
438
 
32424 ripley 439
    setAttrib(work2, R_NamesSymbol, names);
13974 hornik 440
    UNPROTECT(nprotect);
24274 ripley 441
    return work2;
13974 hornik 442
}
443
 
444
 
445
/* Window Drawing Routines */
446
 
447
static void setcellwidths(void)
448
{
449
    int i, w, dw;
450
 
451
    windowWidth = w = 2*bwidth + boxw[0] + BOXW(colmin);
452
    nwide = 2;
453
    for (i = 2; i < 100; i++) { /* 100 on-screen columns cannot occur */
454
	dw = BOXW(i + colmin - 1);
455
	if((w += dw) > fullwindowWidth) {
456
	    nwide = i;
457
	    windowWidth = w - dw;
458
	    break;
459
	}
460
    }
461
}
462
 
463
static void drawwindow(void)
464
{
465
    int i, st;
466
    XWindowAttributes attribs;
467
 
468
    /* if there is an active cell enter the data in it */
34639 ripley 469
    /*
470
     * case colname input Expose not use.
471
     * closerect();
472
     */
13974 hornik 473
 
474
    /* now set up the window with the new dimensions */
475
    XGetWindowAttributes(iodisplay, iowindow, &attribs);
476
    bwidth = attribs.border_width;
477
    fullwindowWidth = attribs.width;
478
    fullwindowHeight = attribs.height;
479
    setcellwidths();
480
    nhigh = (fullwindowHeight - 2 * bwidth - hwidth) / box_h;
481
    windowHeight = nhigh * box_h + 2 * bwidth;
482
 
483
    clearwindow();
484
 
485
 
486
    for (i = 1; i < nhigh; i++)
487
	drawrectangle(0, hwidth + i * box_h, boxw[0], box_h, 1, 1);
488
     /* so row 0 and col 0 are reserved for labels */
489
    colmax = colmin + (nwide - 2);
490
    rowmax = rowmin + (nhigh - 2);
491
    printlabs();
28786 ripley 492
    for (i = colmin; i <= colmax; i++) drawcol(i);
13974 hornik 493
 
494
    /* draw the quit etc boxes */
495
 
496
    i = textwidth("Quit", 4);
497
    box_coords[0] = st = fullwindowWidth - 6 - bwidth;
498
    box_coords[1] = st - i;
499
    drawrectangle(st - i, 3, i + 4, hwidth - 6, 1, 1);
500
    drawtext(st + 2 - i, hwidth - 7, "Quit", 4);
501
 
502
    box_coords[4] = st = st - 5*i;
503
    i = textwidth("Paste", 5);
504
    box_coords[5] = st - i;
505
    drawrectangle(st - i, 3, i + 4, hwidth - 6, 1, 1);
506
    drawtext(st + 2 - i, hwidth - 7, "Paste", 5);
507
 
508
    box_coords[2] = st = st - 2*i;
509
    i = textwidth("Copy", 4);
510
    box_coords[3] = st - i;
511
    drawrectangle(st - i, 3, i + 4, hwidth - 6, 1, 1);
512
    drawtext(st + 2 - i, hwidth - 7, "Copy", 4);
513
 
514
    highlightrect();
515
 
516
    Rsync();
517
 
518
}
519
 
520
static void doHscroll(int oldcol)
521
{
522
    int i, dw;
523
    int oldnwide = nwide, oldwindowWidth = windowWidth;
524
 
525
    /* horizontal re-position */
526
    setcellwidths();
527
    colmax = colmin + (nwide - 2);
24274 ripley 528
    if (oldcol < colmin) { /* drop oldcol...colmin - 1 */
13974 hornik 529
	dw = boxw[0];
530
	for (i = oldcol; i < colmin; i++) dw += BOXW(i);
531
	copyH(dw, boxw[0], oldwindowWidth - dw + 1);
532
	dw = oldwindowWidth - BOXW(oldcol) + 1;
533
	cleararea(dw, hwidth, fullwindowWidth-dw, fullwindowHeight);
534
	/* oldnwide includes the row labels */
535
	for (i = oldcol+oldnwide-1; i <= colmax; i++) drawcol(i);
536
    } else {
537
	/* move one or more cols left */
538
	dw = BOXW(colmin);
539
	copyH(boxw[0], boxw[0] + dw, windowWidth - dw + 1);
540
	dw = windowWidth + 1;
541
	cleararea(dw, hwidth, fullwindowWidth-dw, fullwindowHeight);
542
	drawcol(colmin);
543
    }
544
 
545
    highlightrect();
34639 ripley 546
    cell_cursor_init();
13974 hornik 547
 
548
    Rsync();
549
}
550
 
551
/* find_coords finds the coordinates of the upper left corner of the
552
   given cell on the screen: row and col are on-screen coords */
553
 
554
static void find_coords(int row, int col, int *xcoord, int *ycoord)
555
{
556
    int i, w;
557
    w = bwidth;
558
    if (col > 0) w += boxw[0];
559
    for(i = 1; i < col; i ++) w += BOXW(i + colmin - 1);
560
    *xcoord = w;
561
    *ycoord = bwidth + hwidth + box_h * row;
562
}
563
 
564
/* draw the window with the top left box at column wcol and row wrow */
565
 
566
static void jumpwin(int wcol, int wrow)
567
{
568
    if (wcol < 0 || wrow < 0) {
569
	bell();
570
	return;
571
    }
572
    closerect();
573
    if (colmin != wcol || rowmin != wrow) {
574
	colmin = wcol;
575
	rowmin = wrow;
34639 ripley 576
	closerect();
13974 hornik 577
	drawwindow();
578
    } else highlightrect();
579
}
580
 
581
static void advancerect(DE_DIRECTION which)
582
{
583
 
584
    /* if we are in the header, changing a name then only down is
585
       allowed */
586
    if (crow < 1 && which != DOWN) {
587
	bell();
588
	return;
589
    }
590
 
591
    closerect();
592
 
593
    switch (which) {
594
    case UP:
595
	if (crow == 1) {
596
	    if (rowmin == 1)
597
		bell();
598
	    else
599
		jumppage(UP);
600
	} else
601
	    crow--;
602
	break;
603
    case DOWN:
604
	if (crow == (nhigh - 1))
605
	    jumppage(DOWN);
606
	else
607
	    crow++;
608
	break;
609
    case RIGHT:
610
	if (ccol == (nwide - 1))
611
	    jumppage(RIGHT);
612
	else
613
	    ccol++;
614
	break;
615
    case LEFT:
616
	if (ccol == 1) {
617
	    if (colmin == 1)
618
		bell();
619
	    else
620
		jumppage(LEFT);
621
	} else
622
	    ccol--;
623
	break;
624
    default:
625
	UNIMPLEMENTED("advancerect");
626
    }
627
 
628
    highlightrect();
34639 ripley 629
 
630
    cell_cursor_init();
13974 hornik 631
}
632
 
34639 ripley 633
static void cell_cursor_init(void)
634
{
635
    int i, whichrow = crow + rowmin - 1, whichcol = ccol + colmin -1;
636
    SEXP tmp;
637
 
638
    memset(buf,0,sizeof(buf));
639
 
640
    if (crow == 0 ){
641
	strncpy(buf,
642
		get_col_name(whichcol),
643
		BOOSTED_BUF_SIZE-1);
644
    } else {
645
	if (length(work) >= whichcol) {
646
	    tmp = VECTOR_ELT(work, whichcol - 1);
647
	    if (tmp != R_NilValue &&
648
		(i = whichrow - 1) < LENGTH(tmp) ) {
649
		PrintDefaults(R_NilValue);
650
		if (TYPEOF(tmp) == REALSXP) {
651
		    if (REAL(tmp)[i] != ssNA_REAL)
652
			strncpy(buf, EncodeElement(tmp, i, 0, '.'),
653
				BOOSTED_BUF_SIZE-1);
654
		} else if (TYPEOF(tmp) == STRSXP) {
655
		    if (!streql(CHAR(STRING_ELT(tmp, i)),
656
				CHAR(STRING_ELT(ssNA_STRING, 0))))
657
			strncpy(buf, EncodeElement(tmp, i, 0, '.'),
658
				BOOSTED_BUF_SIZE-1);
659
		}
660
	    }
661
	}
662
    }
663
    buf[BOOSTED_BUF_SIZE-1] = '\0';
664
    clength = strlen(buf);
665
    bufp = buf + clength;
666
}
667
 
13974 hornik 668
static char *get_col_name(int col)
669
{
24274 ripley 670
    static char clab[25];
671
    if (col <= xmaxused) {
672
	/* don't use NA labels */
673
	SEXP tmp = STRING_ELT(names, col - 1);
674
	if(tmp != NA_STRING) return(CHAR(tmp));
13974 hornik 675
    }
676
    sprintf(clab, "var%d", col);
677
    return clab;
678
}
679
 
680
static int get_col_width(int col)
681
{
682
    int i, w = 0, w1;
683
    char *strp;
24274 ripley 684
    SEXP tmp, lab;
13974 hornik 685
 
686
    if (nboxchars > 0) return box_w;
24274 ripley 687
    if (col <= xmaxused) {
688
	tmp = VECTOR_ELT(work, col - 1);
689
	if (isNull(tmp)) return box_w;
690
	/* don't use NA labels */
691
	lab = STRING_ELT(names, col - 1);
692
	if(lab != NA_STRING) strp = CHAR(lab); else strp = "var12";
13974 hornik 693
	PrintDefaults(R_NilValue);
34639 ripley 694
 
13974 hornik 695
	w = textwidth(strp, strlen(strp));
24274 ripley 696
	for (i = 0; i < INTEGER(lens)[col - 1]; i++) {
34294 ripley 697
	    strp = EncodeElement(tmp, i, 0, '.');
13974 hornik 698
	    w1 = textwidth(strp, strlen(strp));
699
	    if (w1 > w) w = w1;
700
	}
701
	if(w < 0.5*box_w) w = 0.5*box_w;
702
	if(w < 0.8*box_w) w+= 0.1*box_w;
703
	if(w > 600) w = 600;
704
	return w+8;
705
    }
706
    return box_w;
707
}
708
 
709
static CellType get_col_type(int col)
710
{
711
    SEXP tmp;
712
    CellType res = UNKNOWNN;
713
 
24274 ripley 714
    if (col <= xmaxused) {
715
	tmp = VECTOR_ELT(work, col - 1);
13974 hornik 716
	if(TYPEOF(tmp) == REALSXP) res = NUMERIC;
717
	if(TYPEOF(tmp) == STRSXP) res = CHARACTER;
718
    }
719
    return res;
720
}
721
 
722
 
723
/* whichcol is absolute col no, col is position on screen */
724
static void drawcol(int whichcol)
725
{
726
    int i, src_x, src_y, len, col = whichcol - colmin + 1, bw = BOXW(whichcol);
727
    char *clab;
728
    SEXP tmp;
729
 
730
    find_coords(0, col, &src_x, &src_y);
731
    cleararea(src_x, src_y, bw, windowHeight);
732
    for (i = 0; i < nhigh; i++)
733
	drawrectangle(src_x, hwidth + i * box_h, bw, box_h, 1, 1);
734
 
735
    /* now fill it in if it is active */
736
    clab = get_col_name(whichcol);
737
    printstring(clab, strlen(clab), 0, col, 0);
738
 
24274 ripley 739
   if (xmaxused >= whichcol) {
740
	tmp = VECTOR_ELT(work, whichcol - 1);
741
	if (!isNull(tmp)) {
742
	    len = min(rowmax, INTEGER(lens)[whichcol - 1]);
13974 hornik 743
	    for (i = (rowmin - 1); i < len; i++)
24274 ripley 744
		printelt(tmp, i, i - rowmin + 2, col);
13974 hornik 745
	}
746
    }
747
    Rsync();
748
}
749
 
750
 
751
/* whichrow is absolute row no */
752
static void drawrow(int whichrow)
753
{
24274 ripley 754
    int i, src_x, src_y, row = whichrow - rowmin + 1, w;
13974 hornik 755
    char rlab[15];
756
    SEXP tvec;
757
 
758
    find_coords(row, 0, &src_x, &src_y);
759
    cleararea(src_x, src_y, windowWidth, box_h);
760
    drawrectangle(src_x, src_y, boxw[0], box_h, 1, 1);
761
 
24271 ripley 762
    sprintf(rlab, labform, whichrow);
13974 hornik 763
    printstring(rlab, strlen(rlab), row, 0, 0);
764
 
765
    w = bwidth + boxw[0];
766
    for (i = colmin; i <= colmax; i++) {
767
	drawrectangle(w, src_y, BOXW(i), box_h, 1, 1);
768
	w += BOXW(i);
769
    }
770
 
771
    for (i = colmin; i <= colmax; i++) {
24274 ripley 772
	if (i > xmaxused) break;
773
	if (!isNull(tvec = VECTOR_ELT(work, i - 1)))
774
	    if (whichrow <= INTEGER(lens)[i - 1])
775
		printelt(tvec, whichrow - 1, row, i - colmin + 1);
13974 hornik 776
    }
777
 
778
    Rsync();
779
}
780
 
781
/* printelt: print the correct value from vector[vrow] into the
782
   spreadsheet in row ssrow and col sscol */
783
 
784
/* WARNING: This has no check that you're not beyond the end of the
785
   vector. Caller must check. */
786
 
787
static void printelt(SEXP invec, int vrow, int ssrow, int sscol)
788
{
789
    char *strp;
790
    PrintDefaults(R_NilValue);
791
    if (TYPEOF(invec) == REALSXP) {
792
	if (REAL(invec)[vrow] != ssNA_REAL) {
34294 ripley 793
	    strp = EncodeElement(invec, vrow, 0, '.');
13974 hornik 794
	    printstring(strp, strlen(strp), ssrow, sscol, 0);
795
	}
796
    }
797
    else if (TYPEOF(invec) == STRSXP) {
798
	if (!streql(CHAR(STRING_ELT(invec, vrow)),
799
		    CHAR(STRING_ELT(ssNA_STRING, 0)))) {
34294 ripley 800
	    strp = EncodeElement(invec, vrow, 0, '.');
13974 hornik 801
	    printstring(strp, strlen(strp), ssrow, sscol, 0);
802
	}
803
    }
804
    else
805
	error("dataentry: internal memory error");
806
}
807
 
808
 
809
static void drawelt(int whichrow, int whichcol)
810
{
811
    int i;
812
    char *clab;
813
    SEXP tmp;
814
 
815
    if (whichrow == 0) {
816
	clab = get_col_name(whichcol + colmin - 1);
817
	printstring(clab, strlen(clab), 0, whichcol, 0);
818
    } else {
24274 ripley 819
	if (xmaxused >= whichcol + colmin - 1) {
820
	    tmp = VECTOR_ELT(work, whichcol + colmin - 2);
32424 ripley 821
	    if (!isNull(tmp) && (i = rowmin + whichrow - 2) <
24274 ripley 822
		INTEGER(lens)[whichcol + colmin - 2] )
823
		printelt(tmp, i, whichrow, whichcol);
13974 hornik 824
	} else
825
	    printstring("", 0, whichrow,  whichcol, 0);
826
    }
827
 
828
    Rsync();
829
}
830
 
831
static void jumppage(DE_DIRECTION dir)
832
{
833
    int i, w, oldcol, wcol;
834
 
835
    switch (dir) {
836
    case UP:
837
	rowmin--;
838
	rowmax--;
839
	copyarea(0, hwidth + box_h, 0, hwidth + 2 * box_h);
840
	drawrow(rowmin);
841
	break;
842
    case DOWN:
24255 ripley 843
	if (rowmax >= 65535) return;
13974 hornik 844
	rowmin++;
845
	rowmax++;
846
	copyarea(0, hwidth + 2 * box_h, 0, hwidth + box_h);
847
	drawrow(rowmax);
848
	break;
849
    case LEFT:
850
	colmin--;
851
	doHscroll(colmin+1);
852
	break;
853
    case RIGHT:
854
	oldcol = colmin;
855
	wcol = colmin + ccol + 1; /* column to be selected */
856
        /* There may not be room to fit the next column in */
857
	w = fullwindowWidth - boxw[0] - BOXW(colmax + 1);
858
	for (i = colmax; i >= oldcol; i--) {
859
	    w -= BOXW(i);
860
	    if(w < 0) {
861
		colmin = i + 1;
862
		break;
863
	    }
864
	}
865
	ccol = wcol - colmin;
866
	doHscroll(oldcol);
867
	break;
868
    }
869
}
870
/* draw a rectangle, used to highlight/downlight the current box */
871
 
872
static void printrect(int lwd, int fore)
873
{
874
    int x, y;
875
    find_coords(crow, ccol, &x, &y);
24274 ripley 876
    drawrectangle(x + lwd - 1, y + lwd - 1,
13974 hornik 877
		  BOXW(ccol+colmin-1) - lwd + 1,
878
		  box_h - lwd + 1, lwd, fore);
879
    Rsync();
880
}
881
 
882
static void downlightrect(void)
883
{
884
    printrect(2, 0);
885
    printrect(1, 1);
886
}
887
 
888
static void highlightrect(void)
889
{
890
    printrect(2, 1);
891
}
892
 
24274 ripley 893
 
894
static void getccol()
13974 hornik 895
{
896
    SEXP tmp, tmp2;
897
    int i, len, newlen, wcol, wrow;
898
    SEXPTYPE type;
24274 ripley 899
    char clab[25];
13974 hornik 900
 
901
    wcol = ccol + colmin - 1;
902
    wrow = crow + rowmin - 1;
24274 ripley 903
    if (wcol > xmaxused) {
904
	/* extend work, names and lens */
905
	REPROTECT(work = lengthgets(work, wcol), wpi);
906
	REPROTECT(names = lengthgets(names, wcol), npi);
907
	for (i = xmaxused; i < wcol; i++) {
908
	    sprintf(clab, "var%d", i + 1);
909
	    SET_STRING_ELT(names, i, mkChar(clab));
910
	}
911
	REPROTECT(lens = lengthgets(lens, wcol), lpi);
912
	xmaxused = wcol;
913
    }
13974 hornik 914
    newcol = FALSE;
24274 ripley 915
    if (isNull(VECTOR_ELT(work, wcol - 1))) {
13974 hornik 916
	newcol = TRUE;
24274 ripley 917
	SET_VECTOR_ELT(work, wcol - 1, ssNewVector(REALSXP, max(100, wrow)));
918
	INTEGER(lens)[wcol - 1] = 0;
13974 hornik 919
    }
24274 ripley 920
    if (!isVector(tmp = VECTOR_ELT(work, wcol - 1)))
13974 hornik 921
	error("internal type error in dataentry");
24274 ripley 922
    len = INTEGER(lens)[wcol - 1];
923
    type = TYPEOF(tmp);
13974 hornik 924
    if (len < wrow) {
925
	for (newlen = max(len * 2, 10) ; newlen < wrow ; newlen *= 2)
926
	    ;
927
	tmp2 = ssNewVector(type, newlen);
928
	for (i = 0; i < len; i++)
929
	    if (type == REALSXP)
24274 ripley 930
		REAL(tmp2)[i] = REAL(tmp)[i];
13974 hornik 931
	    else if (type == STRSXP)
24274 ripley 932
		SET_STRING_ELT(tmp2, i, STRING_ELT(tmp, i));
13974 hornik 933
	    else
934
		error("internal type error in dataentry");
24274 ripley 935
	SET_VECTOR_ELT(work, wcol - 1, tmp2);
13974 hornik 936
    }
937
}
938
 
939
/* close up the entry to a cell, put the value that has been entered
940
   into the correct place and as the correct type */
941
 
942
static void closerect(void)
943
{
24274 ripley 944
    SEXP cvec;
945
    int i, wcol = ccol + colmin - 1, wrow = rowmin + crow - 1, wrow0;
946
    char clab[25];
13974 hornik 947
 
948
    *bufp = '\0';
949
 
950
    /* first check to see if anything has been entered */
951
    if (CellModified) {
952
	if (crow == 0) {
953
	    if (clength != 0) {
954
		/* then we are entering a new column name */
24274 ripley 955
		if (xmaxused < wcol) {
956
		    /* extend work, names and lens */
957
		    REPROTECT(work = lengthgets(work, wcol), wpi);
958
		    REPROTECT(names = lengthgets(names, wcol), npi);
959
		    for (i = xmaxused; i < wcol - 1; i++) {
960
			sprintf(clab, "var%d", i + 1);
961
			SET_STRING_ELT(names, i, mkChar(clab));
962
		    }
963
		    REPROTECT(lens = lengthgets(lens, wcol), lpi);
964
		    xmaxused = wcol;
965
		}
966
		SET_STRING_ELT(names, wcol - 1, mkChar(buf));
13974 hornik 967
		printstring(buf, strlen(buf), 0, wcol, 0);
968
	    } else {
969
		sprintf(buf, "var%d", ccol);
970
		printstring(buf, strlen(buf), 0, wcol, 0);
971
	    }
972
	} else {
24274 ripley 973
	    getccol();
974
	    cvec = VECTOR_ELT(work, wcol - 1);
975
	    wrow0 = INTEGER(lens)[wcol - 1];
976
	    if (wrow > wrow0) INTEGER(lens)[wcol - 1] = wrow;
977
	    ymaxused = max(ymaxused, wrow);
978
	    if (clength != 0) {
979
		/* do it this way to ensure NA, Inf, ...  can get set */
980
		char *endp;
981
		double new = R_strtod(buf, &endp);
982
		Rboolean warn = !isBlankString(endp);
983
		if (TYPEOF(cvec) == STRSXP)
984
		    SET_STRING_ELT(cvec, wrow - 1, mkChar(buf));
985
		else
986
		    REAL(cvec)[wrow - 1] = new;
987
		if (newcol & warn) {
988
		    /* change mode to character */
989
		    SET_VECTOR_ELT(work, wcol - 1, coerceVector(cvec, STRSXP));
32424 ripley 990
		    SET_STRING_ELT(VECTOR_ELT(work, wcol - 1), wrow - 1,
24274 ripley 991
				   mkChar(buf));
992
		}
993
	    } else {
994
		if (TYPEOF(cvec) == STRSXP)
995
		    SET_STRING_ELT(cvec, wrow - 1, NA_STRING);
996
		else
997
		    REAL(cvec)[wrow - 1] = NA_REAL;
24255 ripley 998
	    }
24274 ripley 999
	    drawelt(crow, ccol);  /* to get the cell scrolling right */
1000
	    if(wrow > wrow0) drawcol(wcol); /* to fill in NAs */
24255 ripley 1001
	}
13974 hornik 1002
    }
1003
    CellModified = FALSE;
1004
 
1005
    downlightrect();
1006
 
1007
    ndecimal = 0;
1008
    nneg = 0;
1009
    ne = 0;
1010
    currentexp = 0;
1011
    clength = 0;
1012
    bufp = buf;
1013
}
1014
 
1015
/* print a null terminated string, check to see if it is longer than
1016
   the print area and print it, left adjusted if necessary; clear the
1017
   area of previous text; */
1018
 
1019
/* This version will only display 200 chars, but the maximum col width
1020
   will not allow that many */
1021
static void printstring(char *ibuf, int buflen, int row, int col, int left)
1022
{
1023
    int i, x_pos, y_pos, bw, bufw;
34639 ripley 1024
    char pbuf[BOOSTED_BUF_SIZE];
1025
#ifdef USE_FONTSET
1026
    int wcsbufw,j;
1027
    wchar_t wcspbuf[BOOSTED_BUF_SIZE], *wcspc = wcspbuf;
1028
    wchar_t wcs[BOOSTED_BUF_SIZE];
1029
    char    s[BOOSTED_BUF_SIZE];
1030
    wchar_t *w_p;
1031
    char    *p;
1032
    int cnt;
13974 hornik 1033
 
1034
    find_coords(row, col, &x_pos, &y_pos);
1035
    if (col == 0) bw = boxw[0]; else bw = BOXW(col+colmin-1);
1036
    cleararea(x_pos + 2, y_pos + 2, bw - 3, box_h - 3);
34639 ripley 1037
    bufw = (buflen > BOOSTED_BUF_SIZE-1) ? BOOSTED_BUF_SIZE-1 : buflen;
1038
    strncpy(pbuf, ibuf, bufw);
1039
    pbuf[bufw] = '\0';
1040
 
1041
    p = pbuf;
1042
    wcsbufw = mbsrtowcs(wcspbuf, (const char **)&p, bufw, NULL);
1043
    wcspbuf[wcsbufw]=L'\0';
1044
    if(left) {
1045
        for (i = wcsbufw; i > 1; i--) {
1046
	    for(j=0;*(wcspc+j)!=L'\0';j++)wcs[j]=*(wcspc+j);
1047
	    wcs[j]=L'\0';
1048
	    w_p=wcs;
1049
	    cnt=wcsrtombs(s,(const wchar_t **)&w_p,sizeof(wcs),NULL);
1050
	    s[cnt]='\0';
1051
            if (textwidth(s, strlen(s)) < (bw - text_offset)) break;
1052
            *(++wcspc) = L'<';
1053
        }
1054
    } else {
1055
        for (i = wcsbufw; i > 1; i--) {
1056
	    for(j=0;*(wcspc+j)!=L'\0';j++)wcs[j]=*(wcspc+j);
1057
	    wcs[j]=L'\0';
1058
	    w_p=wcs;
1059
	    cnt=wcsrtombs(s,(const wchar_t **)&w_p,sizeof(wcs),NULL);
1060
	    s[cnt]='\0';
1061
            if (textwidth(s, strlen(s)) < (bw - text_offset)) break;
1062
            *(wcspbuf + i - 2) = L'>';
1063
            *(wcspbuf + i - 1) = L'\0';
1064
        }
1065
    }
1066
    for(j=0;*(wcspc+j)!=L'\0';j++) wcs[j]=*(wcspc+j);
1067
    wcs[j]=L'\0';
1068
    w_p=wcs;
1069
    cnt=wcsrtombs(s,(const wchar_t **)&w_p,sizeof(wcs),NULL);
1070
 
1071
    drawtext(x_pos + text_offset, y_pos + box_h - text_offset, s, cnt);
1072
 
1073
#else  /* USE_FONTSET */
1074
    char *pc = pbuf;
1075
    find_coords(row, col, &x_pos, &y_pos);
1076
    if (col == 0) bw = boxw[0]; else bw = BOXW(col+colmin-1);
1077
    cleararea(x_pos + 2, y_pos + 2, bw - 3, box_h - 3);
13974 hornik 1078
    bufw = (buflen > 200) ? 200 : buflen;
1079
    strncpy(pbuf, ibuf, bufw);
1080
    if(left) {
34639 ripley 1081
        for (i = bufw; i > 1; i--) {
1082
            if (textwidth(pc, i) < (bw - text_offset)) break;
1083
            *(++pc) = '<';
1084
        }
13974 hornik 1085
    } else {
34639 ripley 1086
        for (i = bufw; i > 1; i--) {
1087
            if (textwidth(pbuf, i) < (bw - text_offset)) break;
1088
            *(pbuf + i - 2) = '>';
1089
        }
13974 hornik 1090
    }
1091
    drawtext(x_pos + text_offset, y_pos + box_h - text_offset, pc, i);
34639 ripley 1092
#endif /* USE_FONTSET */
1093
 
13974 hornik 1094
    Rsync();
1095
}
1096
 
1097
static void clearrect(void)
1098
{
1099
    int x_pos, y_pos;
1100
 
1101
    find_coords(crow, ccol, &x_pos, &y_pos);
1102
    cleararea(x_pos, y_pos, BOXW(ccol+colmin-1), box_h);
1103
    Rsync();
1104
}
1105
 
1106
/* handlechar has to be able to parse decimal numbers and strings,
1107
   depending on the current column type, only printing characters
1108
   should get this far */
1109
 
1110
/* --- Not true! E.g. ESC ends up in here... */
32677 ripley 1111
#ifdef USE_FONTSET
35776 ripley 1112
#include <R_ext/rlocale.h>
32432 ripley 1113
#include <wchar.h>
1114
#include <wctype.h>
1115
#endif
13974 hornik 1116
 
34639 ripley 1117
/* <FIXME> This is not correct for stateful MBCSs, but that's hard to
32677 ripley 1118
   do as we get a char at a time */
13974 hornik 1119
static void handlechar(char *text)
1120
{
32432 ripley 1121
    int i, c = text[0];
32677 ripley 1122
#ifdef USE_FONTSET
34639 ripley 1123
    wchar_t wcs[BOOSTED_BUF_SIZE];
13974 hornik 1124
 
34639 ripley 1125
    memset(wcs,0,sizeof(wcs));
35415 ripley 1126
#endif
34639 ripley 1127
 
32432 ripley 1128
    if ( c == '\033' ) { /* ESC */
13974 hornik 1129
	CellModified = FALSE;
1130
	clength = 0;
26830 ripley 1131
        bufp = buf;
13974 hornik 1132
	drawelt(crow, ccol);
34639 ripley 1133
	cell_cursor_init();
13974 hornik 1134
	return;
1135
    } else
1136
	CellModified = TRUE;
1137
 
1138
    if (clength == 0) {
1139
 
1140
	if (crow == 0)	                        /* variable name */
1141
	    currentexp = 3;
1142
	else
1143
	    switch(get_col_type(ccol + colmin - 1)) {
1144
	    case NUMERIC:
1145
		currentexp = 1;
1146
		break;
1147
	    default:
1148
		currentexp = 2;
1149
	    }
1150
	clearrect();
1151
	highlightrect();
1152
    }
1153
 
34639 ripley 1154
    /* NA number? */
1155
    if (1 == get_col_type(ccol + colmin - 1)) {
1156
	/* input numeric for NA of buffer , suppress NA.*/
1157
	if(strcmp(buf, CHAR(STRING_ELT(ssNA_STRING, 0))) == 0) {
1158
	    buf[0] = '\0';
1159
	    clength = 0;
1160
	    bufp = buf;
1161
	}
1162
    }
1163
 
32518 ripley 1164
    if (currentexp == 1) {	/* we are parsing a number */
34639 ripley 1165
 
32677 ripley 1166
#ifdef USE_FONTSET
34639 ripley 1167
      char *mbs = text;
1168
      int cnt = mbsrtowcs(wcs, (const char **)&mbs, strlen(text)+1, NULL);
1169
 
1170
      for(i = 0; i < cnt; i++) {
1171
	  switch (wcs[i]) {
1172
	  case L'-':
1173
	      if (nneg == 0) nneg++; else goto donehc;
1174
	      break;
1175
	  case L'.':
1176
	      if (ndecimal == 0) ndecimal++; else goto donehc;
1177
	      break;
1178
	  case L'e':
1179
	  case L'E':
1180
	      if (ne == 0) {
1181
		  nneg = ndecimal = 0;	/* might have decimal in exponent */
1182
		  ne++;
1183
	      } else goto donehc;
1184
	      break;
1185
	  default:
1186
	      if (!iswdigit(wcs[i])) goto donehc;
1187
	      break;
1188
	  }
1189
      }
32432 ripley 1190
#else
34639 ripley 1191
        switch (c) {
13974 hornik 1192
	case '-':
32432 ripley 1193
	    if (nneg == 0) nneg++; else goto donehc;
13974 hornik 1194
	    break;
1195
	case '.':
32432 ripley 1196
	    if (ndecimal == 0) ndecimal++; else goto donehc;
13974 hornik 1197
	    break;
1198
	case 'e':
1199
	case 'E':
1200
	    if (ne == 0) {
1201
		nneg = ndecimal = 0;	/* might have decimal in exponent */
1202
		ne++;
32432 ripley 1203
	    } else goto donehc;
13974 hornik 1204
	    break;
1205
	default:
32432 ripley 1206
	    if (!isdigit(c)) goto donehc;
13974 hornik 1207
	    break;
1208
	}
32432 ripley 1209
#endif
32518 ripley 1210
    }
13974 hornik 1211
    if (currentexp == 3) {
32677 ripley 1212
#ifdef USE_FONTSET
34639 ripley 1213
      char *mbs = text;
1214
      int cnt = mbsrtowcs(wcs, (const char **)&mbs, strlen(text)+1, NULL);
1215
      for(i = 0; i < cnt; i++) {
1216
	  if (iswspace(wcs[i])) goto donehc;
1217
	  if (clength == 0 && wcs[i] != L'.' && !iswalpha(wcs[i])) goto donehc;
1218
	  else if (wcs[i] != L'.' && !iswalnum(wcs[i])) goto donehc;
1219
      }
32432 ripley 1220
#else
1221
	if (isspace(c)) goto donehc;
1222
	if (clength == 0  && c != '.' && !isalpha(c)) goto donehc;
1223
	else if (c != '.' && !isalnum(c)) goto donehc;
1224
#endif
13974 hornik 1225
    }
1226
 
34639 ripley 1227
    if (clength+strlen(text) > BOOSTED_BUF_SIZE - MB_CUR_MAX - 1) {
13974 hornik 1228
	warning("dataentry: expression too long");
1229
	goto donehc;
1230
    }
1231
 
32432 ripley 1232
    for(i = 0; i < strlen(text); i++) *bufp++ = text[i];
34639 ripley 1233
    *(bufp+1) = '\0';
1234
    clength += strlen(text);
13974 hornik 1235
    printstring(buf, clength, crow, ccol, 1);
1236
    return;
1237
 
1238
 donehc:
1239
    bell();
1240
}
1241
 
1242
static void printlabs(void)
1243
{
24274 ripley 1244
    char clab[15], *p;
13974 hornik 1245
    int i;
1246
 
1247
    for (i = colmin; i <= colmax; i++) {
1248
	p = get_col_name(i);
1249
	printstring(p, strlen(p), 0, i - colmin + 1, 0);
1250
    }
1251
    for (i = rowmin; i <= rowmax; i++) {
24271 ripley 1252
	sprintf(clab, labform, i);
13974 hornik 1253
	printstring(clab, strlen(clab), i - rowmin + 1, 0, 0);
1254
    }
1255
}
1256
 
1257
               /* ================ X11-specific ================ */
1258
 
1259
/* find out whether the button click was in the quit box */
1260
static int checkquit(int xw)
1261
{
1262
    if (xw > box_coords[1] && xw < box_coords[0]) return 1;
1263
    if (xw > box_coords[3] && xw < box_coords[2]) return 2;
1264
    if (xw > box_coords[5] && xw < box_coords[4]) return 3;
1265
    return 0;
1266
}
1267
 
1268
/* when a buttonpress event happens find the square that is being
1269
   pointed to if the pointer is in the header we need to see if the
1270
   quit button was pressed and if so quit. This is done by having
32432 ripley 1271
   findcell return an int which is one if we should quit and zero
13974 hornik 1272
   otherwise */
1273
 
1274
static int findcell(void)
1275
{
1276
 
1277
    int xw, yw, xr, yr, wcol=0, wrow, i, w;
1278
    unsigned int keys;
1279
    Window root, child;
1280
 
1281
    closerect();
1282
    XQueryPointer(iodisplay, iowindow, &root, &child,
1283
		  &xr, &yr, &xw, &yw, &keys);
1284
 
1285
    if (keys & Button1Mask) { /* left click */
1286
 
1287
	/* check to see if the click was in the header */
1288
 
1289
	if (yw < hwidth + bwidth) {
1290
	    i =  checkquit(xw);
1291
	    if (i == 1) return 1;
1292
	    else if (i == 2) copycell();
1293
	    else if (i == 3) pastecell(crow, ccol);
1294
	    return 0;
1295
	}
1296
 
32424 ripley 1297
 
13974 hornik 1298
	/* see if it is in the row labels */
1299
	if (xw < bwidth + boxw[0]) {
1300
	    bell();
1301
	    highlightrect();
1302
	    return 0;
1303
	}
1304
	/* translate to box coordinates */
1305
	wrow = (yw - bwidth - hwidth) / box_h;
1306
	w = bwidth + boxw[0];
1307
	for (i = 1; i <= nwide; i++)
1308
	    if((w += BOXW(i+colmin-1)) > xw) {
1309
		wcol = i;
1310
		break;
1311
	    }
1312
 
1313
	/* next check to see if it is in the column labels */
1314
 
1315
	if (yw < hwidth + bwidth + box_h) {
1316
	    if (xw > bwidth + boxw[0])
1317
		popupmenu(xr, yr, wcol, wrow);
1318
	    else {
1319
		highlightrect();
1320
		bell();
1321
	    }
1322
	} else if (wrow > nhigh - 1 || wcol > nwide -1) {
1323
		/* off the grid */
1324
		highlightrect();
1325
		bell();
1326
	} else if (wcol != ccol || wrow != crow) {
1327
	    ccol = wcol;
1328
	    crow = wrow;
1329
	}
1330
    }
1331
    if (keys & Button2Mask) { /* Paste */
1332
	int row, col = 0;
32424 ripley 1333
 
13974 hornik 1334
	if (yw < hwidth + bwidth || xw < bwidth + boxw[0]) return 0;
1335
 
1336
	/* translate to box coordinates */
1337
	row = (yw - bwidth - hwidth) / box_h;
1338
	w = bwidth + boxw[0];
1339
	for (i = 1; i <= nwide; i++)
1340
	    if ((w += BOXW(i+colmin-1)) > xw) {
1341
		col = i;
1342
		break;
1343
	    }
1344
	pastecell(row, col);
1345
    }
1346
    highlightrect();
1347
    return 0;
1348
}
1349
 
1350
 
1351
/* Event Loop Functions */
1352
 
1353
static void eventloop(void)
1354
{
1355
    int done;
1356
    DEEvent ioevent;
1357
 
1358
    done = 0;
1359
    while (done == 0) {
34639 ripley 1360
        /*
13974 hornik 1361
	if (NextEvent(&ioevent)) {
34639 ripley 1362
        */
1363
        XNextEvent(iodisplay, &ioevent);
1364
        {
1365
#ifdef USE_FONTSET
1366
            if (XFilterEvent(&ioevent, None)){
1367
	      if(ioic){
1368
		XSetICFocus(ioic);
1369
		if (ioim_style & XIMPreeditPosition)
1370
		  calc_pre_edit_pos();
1371
	      }
1372
	      continue;
1373
	    }
1374
#endif
1375
 
13974 hornik 1376
	    switch (WhichEvent(ioevent)) {
34639 ripley 1377
	    case keyDown:/* KeyPress */
1378
		doSpreadKey(0, &ioevent);
1379
		break;
1380
            case Expose:
1381
	      /*
1382
	       * XIM on  - KeyPress - Expose
1383
               * XIM off - KeyPress - KeyRelease
1384
	       * colname change XIM on mode. type Backspace.
1385
	       */
1386
	        if(crow == 0){
1387
		  drawwindow();
1388
		  printstring(buf, clength, crow, ccol, 1);
1389
		}else{
1390
		  closerect();
1391
	          drawwindow();
1392
		  cell_cursor_init();
1393
		}
1394
		break;
1395
	    case activateEvt:/* MapNotify */
1396
	      	closerect();
13974 hornik 1397
		drawwindow();
34639 ripley 1398
		cell_cursor_init();
13974 hornik 1399
 		break;
34639 ripley 1400
	    case mouseDown:/* ButtonPress */
13974 hornik 1401
		done  = doMouseDown(&ioevent);
34639 ripley 1402
		cell_cursor_init();
13974 hornik 1403
		break;
1404
	    case MappingNotify:
1405
		RefreshKeyboardMapping(&ioevent);
1406
		break;
1407
	    case ConfigureNotify:
1408
		doConfigure(&ioevent);
34639 ripley 1409
		cell_cursor_init();
13974 hornik 1410
		break;
1411
	    case ClientMessage:
1412
		if(ioevent.xclient.message_type == _XA_WM_PROTOCOLS
1413
		   && ioevent.xclient.data.l[0] == protocol) {
1414
		    /* user clicked on `close' aka `destroy' */
1415
		       done = 1;
1416
		}
1417
		break;
1418
	    }
1419
	}
1420
    }
1421
}
1422
 
1423
static int doMouseDown(DEEvent * event)
1424
{
1425
    return findcell();
1426
}
1427
 
1428
static void doSpreadKey(int key, DEEvent * event)
1429
{
1430
    KeySym iokey;
32432 ripley 1431
    char *text;
13974 hornik 1432
 
1433
    iokey = GetKey(event);
32432 ripley 1434
    text = GetCharP(event);
13974 hornik 1435
 
1436
    if (CheckControl(event))
1437
	doControl(event);
32424 ripley 1438
    else if ((iokey == XK_Return)  || (iokey == XK_KP_Enter) ||
13974 hornik 1439
	     (iokey == XK_Linefeed)|| (iokey == XK_Down))
1440
	advancerect(DOWN);
1441
    else if (iokey == XK_Left)
1442
	advancerect(LEFT);
1443
    else if (iokey == XK_Right)
1444
	advancerect(RIGHT);
1445
    else if (iokey == XK_Up)
1446
	advancerect(UP);
22718 ripley 1447
#ifdef XK_Page_Up
1448
    else if (iokey == XK_Page_Up) {
13974 hornik 1449
	int i = rowmin - nhigh + 2;
1450
	jumpwin(colmin, max(1, i));
34639 ripley 1451
	cell_cursor_init();
13974 hornik 1452
    }
22718 ripley 1453
#elif defined(XK_Prior)
1454
    else if (iokey == XK_Prior) {
13974 hornik 1455
	int i = rowmin - nhigh + 2;
1456
	jumpwin(colmin, max(1, i));
34639 ripley 1457
	cell_cursor_init();
13974 hornik 1458
    }
22718 ripley 1459
#endif
1460
#ifdef XK_Page_Down
34639 ripley 1461
    else if (iokey == XK_Page_Down) {
13974 hornik 1462
	jumpwin(colmin, rowmax);
34639 ripley 1463
	cell_cursor_init();
1464
    }
22718 ripley 1465
#elif defined(XK_Next)
34639 ripley 1466
    else if (iokey == XK_Next) {
22718 ripley 1467
	jumpwin(colmin, rowmax);
34639 ripley 1468
	cell_cursor_init();
1469
    }
13974 hornik 1470
#endif
1471
    else if ((iokey == XK_BackSpace) || (iokey == XK_Delete)) {
1472
	if (clength > 0) {
34639 ripley 1473
	    int last_w ;
1474
	    last_w = last_wchar_bytes(NULL);
1475
	    clength -= last_w;
1476
	    bufp -= last_w;
1477
	    *bufp = '\0';
1478
	    CellModified = TRUE;
13974 hornik 1479
	    printstring(buf, clength, crow, ccol, 1);
1480
	} else bell();
1481
    }
1482
    else if (iokey == XK_Tab) {
1483
	if(CheckShift(event)) advancerect(LEFT);
1484
	else advancerect(RIGHT);
1485
    }
1486
    else if (iokey == XK_Home) {
1487
	jumpwin(1, 1);
1488
	downlightrect();
1489
	crow = ccol = 1;
1490
	highlightrect();
34639 ripley 1491
	cell_cursor_init();
13974 hornik 1492
    }
1493
    else if (iokey == XK_End) {
1494
	int i = ymaxused - nhigh + 2;
1495
	jumpwin(xmaxused, max(i, 1));
1496
	downlightrect();
1497
	crow = ymaxused - rowmin + 1;
1498
	ccol = 1;
1499
	highlightrect();
34639 ripley 1500
	cell_cursor_init();
13974 hornik 1501
    }
1502
    else if (IsModifierKey(iokey)) {
34639 ripley 1503
    } 
1504
    else {
1505
      handlechar(text);
13974 hornik 1506
    }
1507
}
1508
 
34639 ripley 1509
#if 0
13974 hornik 1510
static int NextEvent(DEEvent * ioevent)
1511
{
1512
    XNextEvent(iodisplay, ioevent);
1513
    return 1;
1514
}
34639 ripley 1515
#endif
13974 hornik 1516
 
1517
static int WhichEvent(DEEvent ioevent)
1518
{
1519
    return ioevent.type;
1520
}
1521
 
1522
static KeySym GetKey(DEEvent * event)
1523
{
1524
    char text[1];
1525
    KeySym iokey;
1526
 
31990 ripley 1527
    XLookupString((XKeyEvent *)event, text, 1, &iokey, NULL);
13974 hornik 1528
    return iokey;
1529
}
1530
 
32432 ripley 1531
static char *GetCharP(DEEvent * event)
13974 hornik 1532
{
34639 ripley 1533
    static char text[BOOSTED_BUF_SIZE];
13974 hornik 1534
    KeySym iokey;
1535
 
34639 ripley 1536
    memset(text,0,sizeof(text));
1537
 
32677 ripley 1538
#ifdef USE_FONTSET
1539
    if(mbcslocale) {
32471 ripley 1540
#ifdef HAVE_XUTF8LOOKUPSTRING
34639 ripley 1541
        if(utf8locale)
1542
	    Xutf8LookupString(ioic, (XKeyEvent *)event,
1543
			      text, sizeof(text) - clength,
1544
			      &iokey, &status);
1545
	else
32471 ripley 1546
#endif
34639 ripley 1547
	    XmbLookupString(ioic, (XKeyEvent *)event,
1548
			    text, sizeof(text) - clength,
1549
			    &iokey, &status);
32432 ripley 1550
	/* FIXME check the return code */
34639 ripley 1551
	if(status == XBufferOverflow)
1552
	    warning("dataentry: expression too long");
32432 ripley 1553
    } else
1554
#endif
34639 ripley 1555
	XLookupString((XKeyEvent *)event,
1556
		      text, sizeof(text) - clength,
1557
		      &iokey, NULL);
32432 ripley 1558
    return text;
13974 hornik 1559
}
1560
 
1561
static int CheckControl(DEEvent * event)
1562
{
1563
    return (*event).xkey.state & ControlMask;
1564
}
1565
 
1566
static int CheckShift(DEEvent * event)
1567
{
1568
    return (*event).xkey.state & ShiftMask;
1569
}
1570
 
1571
static void doControl(DEEvent * event)
1572
{
1573
    int i;
1574
    char text[1];
1575
    KeySym iokey;
1576
 
1577
    (*event).xkey.state = 0;
31990 ripley 1578
    XLookupString((XKeyEvent *)event, text, 1, &iokey, NULL);
13974 hornik 1579
    /* one row overlap when scrolling: top line <--> bottom line */
1580
    switch (text[0]) {
1581
	case 'b':
1582
	    i = rowmin - nhigh + 2;
1583
	    jumpwin(colmin, max(1, i));
1584
	    break;
1585
	case 'f':
1586
	    jumpwin(colmin, rowmax);
1587
	    break;
1588
	case 'l':
1589
	    closerect();
1590
	    for (i = 1 ; i <= min(100, xmaxused); i++)
1591
		boxw[i] = get_col_width(i);
34639 ripley 1592
	    closerect();
13974 hornik 1593
	    drawwindow();
1594
	    break;
1595
    }
34639 ripley 1596
    cell_cursor_init();
13974 hornik 1597
}
1598
 
1599
 
1600
static void doConfigure(DEEvent * event)
1601
{
1602
    if ((fullwindowWidth != (*event).xconfigure.width) ||
34639 ripley 1603
	(fullwindowHeight != (*event).xconfigure.height)) {
1604
	closerect();
13974 hornik 1605
	drawwindow();
34639 ripley 1606
    }
13974 hornik 1607
}
1608
 
1609
static void RefreshKeyboardMapping(DEEvent * event)
1610
{
28840 ripley 1611
    XRefreshKeyboardMapping((XMappingEvent *)event);
13974 hornik 1612
}
1613
 
1614
/* Initialize/Close Windows */
1615
 
1616
void closewin(void)
1617
{
1618
    XFreeGC(iodisplay, iogc);
32677 ripley 1619
#ifdef USE_FONTSET
1620
    if(mbcslocale) {
32518 ripley 1621
	XDestroyIC(ioic);
1622
	XCloseIM(ioim);
1623
    }
1624
#endif
13974 hornik 1625
    XDestroyWindow(iodisplay, iowindow);
1626
    XCloseDisplay(iodisplay);
1627
}
1628
 
36044 ripley 1629
#define USE_Xt 1
1630
 
1631
#ifdef USE_Xt
1632
#include <X11/StringDefs.h>
1633
#include <X11/Intrinsic.h>
1634
#include <X11/Shell.h>
1635
typedef struct gx_device_X_s {
1636
    Pixel background, foreground, borderColor;
1637
    Dimension borderWidth;
1638
    String geometry;
1639
} gx_device_X;
1640
 
1641
/* (String) casts are here to suppress warnings about discarding `const' */
1642
#define RINIT(a,b,t,s,o,it,n)\
1643
  {(String)(a), (String)(b), (String)t, sizeof(s),\
1644
   XtOffsetOf(gx_device_X, o), (String)it, (n)}
1645
#define rpix(a,b,o,n)\
1646
  RINIT(a,b,XtRPixel,Pixel,o,XtRString,(XtPointer)(n))
1647
#define rdim(a,b,o,n)\
1648
  RINIT(a,b,XtRDimension,Dimension,o,XtRImmediate,(XtPointer)(n))
1649
#define rstr(a,b,o,n)\
1650
  RINIT(a,b,XtRString,String,o,XtRString,(char*)(n))
1651
 
1652
static XtResource x_resources[] = {
1653
    rpix(XtNforeground, XtCForeground, foreground, "XtDefaultForeground"),
1654
    rpix(XtNbackground, XtCBackground, background, "XtDefaultBackground"),
1655
    rstr(XtNgeometry, XtCGeometry, geometry, NULL),
1656
};
1657
 
1658
static const int x_resource_count = XtNumber(x_resources);
1659
static gx_device_X xdev;
1660
#endif
1661
 
13974 hornik 1662
static int R_X11Err(Display *dsp, XErrorEvent *event)
1663
{
1664
    char buff[1000];
1665
    XGetErrorText(dsp, event->error_code, buff, 1000);
1666
    warning("X11 protocol error: %s", buff);
1667
    return 0;
1668
}
1669
 
1670
static int R_X11IOErr(Display *dsp)
1671
{
1672
    error("X11 fatal IO error: please save work and shut down R");
1673
    return 0; /* but should never get here */
1674
}
1675
 
1676
/* set up the window, print the grid and column/row labels */
1677
 
1678
static Rboolean initwin(void) /* TRUE = Error */
1679
{
1680
    int i, twidth, w, minwidth;
1681
    int ioscreen;
1682
    unsigned long iowhite, ioblack;
34639 ripley 1683
    /* char ioname[] = "R DataEntryWindow"; */
13974 hornik 1684
    char digits[] = "123456789.0";
1685
    Window root;
1686
    XEvent ioevent;
1687
    XSetWindowAttributes winattr;
1688
    XWindowAttributes attribs;
34639 ripley 1689
    XSizeHints *hint;
35415 ripley 1690
    unsigned long fevent=0UL;
34639 ripley 1691
#ifdef USE_FONTSET
1692
    int j,k;
1693
    XVaNestedList   xva_nlist;
1694
    XPoint xpoint;
1695
#endif
13974 hornik 1696
 
32424 ripley 1697
    strcpy(copycontents, "");
1698
 
32677 ripley 1699
#ifdef USE_FONTSET
34639 ripley 1700
    if (!XSupportsLocale ())
32424 ripley 1701
	warning("locale not supported by Xlib: some X ops will operate in C locale");
1702
    if (!XSetLocaleModifiers ("")) warning("X cannot set locale modifiers");
1703
#endif
1704
 
1705
    if ((iodisplay = XOpenDisplay(NULL)) == NULL) {
1706
	warning("unable to open display");
13974 hornik 1707
	return TRUE;
32424 ripley 1708
    }
13974 hornik 1709
    XSetErrorHandler(R_X11Err);
1710
    XSetIOErrorHandler(R_X11IOErr);
1711
 
1712
    /* Get Font Loaded if we can */
1713
 
32677 ripley 1714
#ifdef USE_FONTSET
1715
    if(mbcslocale) {
32424 ripley 1716
	int  missing_charset_count;
1717
	char **missing_charset_list;
1718
	char *def_string;
34639 ripley 1719
 
1720
	char opt_fontset_name[512];
1721
 
1722
	/*
1723
	  options("X11fonts")[1] read font name
1724
	*/
1725
	char *s = CHAR(STRING_ELT(GetOption(install("X11fonts"),
1726
					    R_NilValue), 0));
1727
 
1728
	if (s == NULL) {
1729
	    strcpy(opt_fontset_name,fontset_name);
1730
	} else {
1731
	    sprintf(opt_fontset_name,s,"medium","r",12);
1732
	}
1733
 
1734
	font_set = XCreateFontSet(iodisplay, opt_fontset_name,
1735
				  &missing_charset_list,
32424 ripley 1736
				  &missing_charset_count, &def_string);
1737
	if (missing_charset_count) XFreeStringList(missing_charset_list);
1738
	if (font_set == NULL) {
1739
	    warning("unable to create fontset %s", fontset_name);
1740
	    return TRUE; /* ERROR */
1741
	}
1742
    } else
1743
#endif
1744
    {
1745
	font_info = XLoadQueryFont(iodisplay, font_name);
1746
	if (font_info == NULL) {
1747
	    warning("unable to losd font %s", font_name);
1748
	    return TRUE; /* ERROR */
1749
	}
1750
    }
13974 hornik 1751
 
1752
    /* find out how wide the input boxes should be and set up the
1753
       window size defaults */
1754
 
1755
    nboxchars = asInteger(GetOption(install("de.cellwidth"), R_GlobalEnv));
1756
    if (nboxchars == NA_INTEGER || nboxchars < 0) nboxchars = 0;
1757
 
1758
    twidth = textwidth(digits, strlen(digits));
34639 ripley 1759
 
13974 hornik 1760
    if (nboxchars > 0) twidth = (twidth * nboxchars)/10;
1761
    box_w = twidth + 4;
32677 ripley 1762
#ifdef USE_FONTSET
1763
    if(mbcslocale) {
32424 ripley 1764
	XFontSetExtents *extent = XExtentsOfFontSet(font_set);
1765
	char **ml;
1766
	box_h = (extent->max_logical_extent.height)
1767
	    + (extent->max_logical_extent.height / 5) + 4;
1768
	font_set_cnt = XFontsOfFontSet(font_set, &fs_list, &ml);
1769
	text_offset = 2 + fs_list[0]->max_bounds.descent;
1770
    } else
1771
#endif
1772
    {
1773
	box_h = font_info->max_bounds.ascent
1774
	    + font_info->max_bounds.descent + 4;
1775
	text_offset = 2 + font_info->max_bounds.descent;
1776
    }
13974 hornik 1777
    windowHeight = 26 * box_h + hwidth + 2;
24271 ripley 1778
    /* this used to presume 4 chars sufficed for row numbering */
1779
    labdigs = max(3, 1+floor(log10((double)ymaxused)));
1780
    sprintf(labform, "%%%dd", labdigs);
1781
    boxw[0] = 0.1*labdigs*textwidth("0123456789", 10) + textwidth(" ", 1) + 8;
13974 hornik 1782
    for(i = 1; i < 100; i++) boxw[i] = get_col_width(i);
34639 ripley 1783
 
13974 hornik 1784
    /* try for a window width that covers all the columns, or is around
1785
       800 pixels */
1786
    w = windowWidth = 0;
1787
    for(i = 0; i <= xmaxused; i++) {
1788
	w += boxw[i];
1789
	if(w > 800) {
1790
	    windowWidth = w - boxw[i];
1791
	    break;
1792
	}
1793
    }
1794
    if(windowWidth == 0) windowWidth = w;
1795
    windowWidth += 2;
1796
    /* allow enough width for buttons */
1797
    minwidth = 7.5 * textwidth("Paste", 5);
1798
    if(windowWidth < minwidth) windowWidth = minwidth;
1799
 
1800
    ioscreen = DefaultScreen(iodisplay);
1801
    iowhite = WhitePixel(iodisplay, ioscreen);
1802
    ioblack = BlackPixel(iodisplay, ioscreen);
1803
 
1804
 
36044 ripley 1805
    hint = XAllocSizeHints();
34639 ripley 1806
 
1807
    hint->x = 0;
1808
    hint->y = 0;
1809
    hint->width = windowWidth;
1810
    hint->height = windowHeight;
1811
    hint->flags = PPosition | PSize;
1812
    /*
1813
     * not necessary?
32518 ripley 1814
    hints.flags = InputHint;
1815
    hints.input = True;
34639 ripley 1816
    */
13974 hornik 1817
    root = DefaultRootWindow(iodisplay);
1818
 
36044 ripley 1819
#ifdef USE_Xt
1820
    {
1821
	XtAppContext app_con;
1822
	Widget toplevel;
1823
	Display *xtdpy;
1824
        int zero = 0;
1825
 
1826
	XtToolkitInitialize();
1827
	app_con = XtCreateApplicationContext();
1828
	/* XtAppSetFallbackResources(app_con, x_fallback_resources);*/
1829
	xtdpy = XtOpenDisplay(app_con, NULL, "r_dataentry", "R_dataentry",
1830
			      NULL, 0, &zero, NULL);
1831
	toplevel = XtAppCreateShell(NULL, "R_dataentry",
1832
				    applicationShellWidgetClass, 
1833
				    xtdpy, NULL, 0);
1834
	XtGetApplicationResources(toplevel, (XtPointer) &xdev,
1835
				  x_resources, 
1836
				  x_resource_count,
1837
				  NULL, 0);
1838
	XtDestroyWidget(toplevel);
1839
	XtCloseDisplay(xtdpy);
1840
	XtDestroyApplicationContext(app_con);
1841
	if (xdev.geometry != NULL) {
1842
	    char gstr[40];
1843
	    int bitmask;
1844
 
1845
	    sprintf(gstr, "%dx%d+%d+%d", hint->width,
1846
		    hint->height, hint->x, hint->y);
1847
	    bitmask = XWMGeometry(iodisplay, DefaultScreen(iodisplay),
1848
				  xdev.geometry, gstr, 
1849
				  1,
1850
				  hint,
1851
				  &hint->x, &hint->y,
1852
				  &hint->width, &hint->height,
1853
				  &hint->win_gravity);
1854
 
1855
	    if (bitmask & (XValue | YValue))
1856
		hint->flags |= USPosition;
1857
	    if (bitmask & (WidthValue | HeightValue)) 
1858
		hint->flags |= USSize;
1859
	}
1860
	ioblack = xdev.foreground;
1861
	iowhite = xdev.background;
1862
    }
1863
#endif
13974 hornik 1864
    if ((iowindow = XCreateSimpleWindow(
32518 ripley 1865
	     iodisplay,
1866
	     root,
34639 ripley 1867
	     hint->x,
1868
	     hint->y,
1869
	     hint->width,
1870
	     hint->height,
32518 ripley 1871
	     bwidth,
1872
	     ioblack,
1873
	     iowhite)) == 0) {
32424 ripley 1874
	warning("unable to open window for data editor");
13974 hornik 1875
	return TRUE;
32424 ripley 1876
    }
13974 hornik 1877
 
34639 ripley 1878
    /*
13974 hornik 1879
    XSetStandardProperties(iodisplay, iowindow, ioname, ioname, None,
34639 ripley 1880
			   (char **)NULL, 0, iohint);
1881
    */
1882
    XSetWMNormalHints(iodisplay, iowindow, hint);
1883
    XFree(hint);
13974 hornik 1884
 
34639 ripley 1885
 
1886
    winattr.backing_store = WhenMapped;
13974 hornik 1887
    XChangeWindowAttributes(iodisplay, iowindow, CWBackingStore, &winattr);
1888
 
1889
    /* set up protocols so that window manager sends */
1890
    /* me an event when user "destroys" window */
1891
    _XA_WM_PROTOCOLS = XInternAtom(iodisplay, "WM_PROTOCOLS", 0);
1892
    protocol = XInternAtom(iodisplay, "WM_DELETE_WINDOW", 0);
1893
    XSetWMProtocols(iodisplay, iowindow, &protocol, 1);
34639 ripley 1894
    /*
1895
     * not necessary
32518 ripley 1896
    XSetWMHints(iodisplay, iowindow, &hints);
34639 ripley 1897
     */
1898
 
1899
    iogc = XCreateGC(iodisplay, iowindow, 0, 0);
1900
 
32677 ripley 1901
#ifdef USE_FONTSET
1902
    if(mbcslocale) {
32518 ripley 1903
	ioim = XOpenIM(iodisplay, NULL, NULL, NULL);
32527 ripley 1904
	if(!ioim) {
1905
	    XDestroyWindow(iodisplay, iowindow);
1906
	    XCloseDisplay(iodisplay);
34639 ripley 1907
	    warning("unable to open X Input Method");
1908
	    return TRUE;
32527 ripley 1909
	}
32555 ripley 1910
 
34639 ripley 1911
	/* search supported input style */
1912
	XGetIMValues(ioim, XNQueryInputStyle, &ioim_styles,NULL);
1913
	for(i = 0; i < ioim_styles->count_styles; i++) {
1914
	    for(j = 0; preedit_styles[j]; j++){
1915
		for(k = 0; status_styles[k]; k++){
1916
		    ioim_style = (preedit_styles[j] | status_styles[k]);
1917
		    if( ioim_styles->supported_styles[i] == ioim_style) {
1918
			goto loop_out;
1919
		    }
1920
		}
1921
	    }
1922
	}
1923
    loop_out:
1924
 
1925
	/* create input context */
1926
	xpoint.x = 0; xpoint.y=0;
1927
	xva_nlist = XVaCreateNestedList(0, XNFontSet, font_set,
1928
					XNSpotLocation, &xpoint, NULL);
1929
 
1930
	ioic = XCreateIC(ioim,
1931
 			 XNInputStyle, ioim_style,
1932
			 XNClientWindow,iowindow,
1933
			 XNFocusWindow,iowindow,
1934
			 XNPreeditAttributes, xva_nlist,
1935
			 XNStatusAttributes, xva_nlist,
32518 ripley 1936
			 NULL);
34639 ripley 1937
	XFree(xva_nlist);
32518 ripley 1938
	if(!ioic) {
1939
	    XCloseIM(ioim);
1940
	    XDestroyWindow(iodisplay, iowindow);
1941
	    XCloseDisplay(iodisplay);
34639 ripley 1942
	    warning("unable to open X Input Context");
1943
	    return TRUE;
32518 ripley 1944
	}
34639 ripley 1945
 
1946
	/* get XIM processes event. */
1947
	XGetICValues(ioic, XNFilterEvents, &fevent, NULL);
32518 ripley 1948
    }
32432 ripley 1949
#endif
13974 hornik 1950
 
32677 ripley 1951
#ifdef USE_FONTSET
1952
    if(!mbcslocale)
32555 ripley 1953
#endif
1954
	XSetFont(iodisplay, iogc, font_info->fid);
1955
    XSetBackground(iodisplay, iogc, iowhite);
36044 ripley 1956
    XSetForeground(iodisplay, iogc, ioblack);
32555 ripley 1957
    XSetLineAttributes(iodisplay, iogc, 1, LineSolid, CapRound, JoinRound);
1958
 
34639 ripley 1959
    /*
32555 ripley 1960
    XSelectInput(iodisplay, iowindow,
1961
		 ButtonPressMask | KeyPressMask
34639 ripley 1962
		 | ExposureMask | StructureNotifyMask | fevent);
1963
    */
1964
 
1965
    XSelectInput(iodisplay, iowindow,
1966
		 ButtonPressMask
1967
		 | KeyPressMask
1968
		 | StructureNotifyMask
1969
		 | ExposureMask
1970
		 | EnterWindowMask
1971
		 | LeaveWindowMask
1972
		 | fevent);
32555 ripley 1973
    XMapRaised(iodisplay, iowindow);
1974
 
13974 hornik 1975
    /* now set up the menu-window, for now use the same text
1976
       dimensions as above */
1977
 
34639 ripley 1978
    /* font size consideration */
1979
    for(i = 0; i < (sizeof(menu_label)/sizeof(char *)); i++)
1980
	twidth = (twidth<textwidth(menu_label[i],strlen(menu_label[i]))) ?
1981
	    textwidth(menu_label[i],strlen(menu_label[i])) : twidth;
1982
 
13974 hornik 1983
    menuwindow = XCreateSimpleWindow(iodisplay, root, 0, 0, twidth,
1984
				     4 * box_h, 2, ioblack, iowhite);
1985
    for (i = 0; i < 4; i++) {
1986
	menupanes[i] = XCreateSimpleWindow(iodisplay, menuwindow, 0,
1987
					   box_h * i, twidth, box_h,
1988
					   1, ioblack, iowhite);
1989
	XSelectInput(iodisplay, menupanes[i],
34639 ripley 1990
		     ButtonPressMask | ButtonReleaseMask | ExposureMask
1991
		     );
13974 hornik 1992
    }
1993
 
1994
    /* XMapSubwindows(iodisplay, menuwindow); */
1995
 
1996
 
1997
    winattr.override_redirect = True;
1998
    XChangeWindowAttributes(iodisplay, menuwindow,
1999
			    CWBackingStore | CWOverrideRedirect, &winattr);
2000
    Rsync();
2001
 
2002
    /* this next sequence makes sure the window is up and ready before
2003
       you start drawing in it */
2004
 
2005
    XNextEvent(iodisplay, &ioevent);
2006
    if (ioevent.xany.type == Expose) {
2007
	while (ioevent.xexpose.count)
2008
	    XNextEvent(iodisplay, &ioevent);
2009
    }
2010
    XGetWindowAttributes(iodisplay, iowindow, &attribs);
2011
    bwidth = attribs.border_width;
2012
    fullwindowWidth = attribs.width;
2013
    fullwindowHeight = attribs.height;
2014
 
2015
 
2016
    /* set the active rectangle to be the upper left one */
2017
    crow = 1;
2018
    ccol = 1;
2019
    CellModified = FALSE;
2020
    return FALSE;/* success */
2021
}
2022
 
2023
/* MAC/X11 BASICS */
2024
 
2025
static void bell(void)
2026
{
2027
    XBell(iodisplay, 20);
2028
}
2029
 
2030
static void cleararea(int xpos, int ypos, int width, int height)
2031
{
2032
    XClearArea(iodisplay, iowindow, xpos, ypos, width, height, 0);
2033
}
2034
 
2035
static void clearwindow(void)
2036
{
2037
    XClearWindow(iodisplay, iowindow);
2038
}
2039
 
2040
static void copyarea(int src_x, int src_y, int dest_x, int dest_y)
2041
{
2042
    int mx = max(src_x, dest_x), my = max(src_y, dest_y);
2043
    XCopyArea(iodisplay, iowindow, iowindow, iogc, src_x, src_y,
2044
	      fullwindowWidth - mx, fullwindowHeight - my,
2045
	      dest_x, dest_y);
2046
    Rsync();
2047
}
2048
 
2049
static void copyH(int src_x, int dest_x, int width)
2050
{
2051
    XCopyArea(iodisplay, iowindow, iowindow, iogc, src_x+bwidth, hwidth,
2052
	      width, windowHeight+1, dest_x+bwidth, hwidth);
2053
}
2054
 
2055
#if 0
2056
static void drawline(int fromx, int fromy, int tox, int toy)
2057
{
2058
    XDrawLine(iodisplay, iowindow, iogc, fromx, fromy, tox, toy);
2059
}
2060
#endif
2061
 
2062
static void drawrectangle(int xpos, int ypos, int width, int height,
2063
			  int lwd, int fore)
2064
{
36044 ripley 2065
#ifdef USE_Xt
13974 hornik 2066
    if (fore == 0)
36044 ripley 2067
	XSetForeground(iodisplay, iogc, xdev.background);
2068
    else
2069
	XSetForeground(iodisplay, iogc, xdev.foreground);
2070
#else
2071
    if (fore == 0)
13974 hornik 2072
	XSetForeground(iodisplay, iogc, WhitePixel(iodisplay,
2073
						   DefaultScreen(iodisplay)));
2074
    else
2075
	XSetForeground(iodisplay, iogc, BlackPixel(iodisplay,
2076
						   DefaultScreen(iodisplay)));
36044 ripley 2077
#endif
13974 hornik 2078
    XSetLineAttributes(iodisplay, iogc, lwd, LineSolid, CapRound, JoinRound);
2079
    XDrawRectangle(iodisplay, iowindow, iogc, xpos, ypos, width, height);
2080
}
2081
 
2082
static void drawtext(int xpos, int ypos, char *text, int len)
2083
{
32677 ripley 2084
#ifdef USE_FONTSET
2085
    if(mbcslocale)
32471 ripley 2086
#ifdef HAVE_XUTF8DRAWIMAGESTRING
34639 ripley 2087
        if(utf8locale)
2088
	    Xutf8DrawImageString(iodisplay, iowindow, font_set,
2089
				 iogc, xpos, ypos,text, len);
2090
        else
32471 ripley 2091
#endif
34639 ripley 2092
	    XmbDrawImageString(iodisplay, iowindow, font_set,
2093
			       iogc, xpos, ypos,text, len);
32424 ripley 2094
    else
2095
#endif
2096
	XDrawImageString(iodisplay, iowindow, iogc, xpos, ypos, text, len);
13974 hornik 2097
    Rsync();
2098
}
2099
 
2100
static void Rsync()
2101
{
2102
    XSync(iodisplay, 0);
2103
}
2104
 
2105
static int textwidth(char *text, int nchar)
2106
{
34639 ripley 2107
 
32677 ripley 2108
#ifdef USE_FONTSET
35844 ripley 2109
    if(mbcslocale) {
32471 ripley 2110
#ifdef HAVE_XUTF8TEXTESCAPEMENT
34639 ripley 2111
        if (utf8locale)
2112
	    return Xutf8TextEscapement(font_set, text, nchar);
2113
        else
32424 ripley 2114
#endif
34639 ripley 2115
	    return XmbTextEscapement(font_set, text, nchar);
35844 ripley 2116
    }
32471 ripley 2117
#endif
32424 ripley 2118
    return XTextWidth(font_info, text, nchar);
13974 hornik 2119
}
2120
 
2121
/* Menus */
2122
 
2123
void popupmenu(int x_pos, int y_pos, int col, int row)
2124
{
24274 ripley 2125
    int i, button, popupcol = col + colmin - 1;
2126
    char *name, clab[20];
13974 hornik 2127
    XEvent event;
2128
    Window selected_pane;
2129
    SEXP tvec;
2130
 
34639 ripley 2131
    XMoveWindow(iodisplay, menuwindow, x_pos, y_pos);
13974 hornik 2132
    XMapSubwindows(iodisplay, menuwindow);
2133
    XMapRaised(iodisplay, menuwindow);
2134
 
2135
    /* now fill in the menu panes with the correct information */
2136
 
24274 ripley 2137
    if (popupcol > xmaxused) {
2138
	/* extend work, names and lens */
2139
	REPROTECT(work = lengthgets(work, popupcol), wpi);
2140
	REPROTECT(names = lengthgets(names, popupcol), npi);
2141
	for (i = xmaxused+1; i < popupcol; i++) {
2142
	    sprintf(clab, "var%d", i + 1);
2143
	    SET_STRING_ELT(names, i, mkChar(clab));
2144
	}
2145
	REPROTECT(lens = lengthgets(lens, popupcol), lpi);
2146
	xmaxused = popupcol;
2147
    }
2148
    tvec = VECTOR_ELT(work, popupcol - 1);
2149
    name = CHAR(STRING_ELT(names, popupcol - 1));
34639 ripley 2150
#ifdef USE_FONTSET
2151
    if(mbcslocale)
2152
#ifdef HAVE_XUTF8DRAWSTRING
2153
        if(utf8locale)
2154
	    Xutf8DrawString(iodisplay,
2155
			    menupanes[0],
2156
			    font_set, iogc, 3, box_h - 3, name, strlen(name));
2157
	else
2158
#endif
2159
	    XmbDrawString(iodisplay,
2160
			  menupanes[0],
2161
			  font_set, iogc, 3, box_h - 3, name, strlen(name));
2162
    else
2163
#endif
2164
        XDrawString(iodisplay,
2165
		    menupanes[0], iogc, 3, box_h - 3, name, strlen(name));
13974 hornik 2166
    for (i = 1; i < 4; i++)
34639 ripley 2167
#ifdef USE_FONTSET
2168
      if(mbcslocale)
2169
#ifdef HAVE_XUTF8DRAWSTRING
2170
        if(utf8locale)
2171
	  Xutf8DrawString(iodisplay,
2172
			  menupanes[i],
2173
			  font_set, iogc, 3, box_h - 3,
2174
			  menu_label[i - 1], strlen(menu_label[i - 1]));
2175
	else
2176
#endif
2177
	  XmbDrawString(iodisplay,
2178
			menupanes[i],
2179
			font_set, iogc, 3, box_h - 3,
2180
			menu_label[i - 1], strlen(menu_label[i - 1]));
2181
      else
2182
#endif
13974 hornik 2183
	XDrawString(iodisplay,
2184
		    menupanes[i], iogc, 3, box_h - 3,
2185
		    menu_label[i - 1], strlen(menu_label[i - 1]));
34639 ripley 2186
 
24274 ripley 2187
    if (isNull(tvec) || TYPEOF(tvec) == REALSXP)
34639 ripley 2188
#ifdef USE_FONTSET
2189
      if(mbcslocale)
2190
#ifdef HAVE_XUTF8DRAWSTRING
2191
        if(utf8locale)
2192
	  Xutf8DrawString(iodisplay,
2193
			  menupanes[1],
2194
			  font_set, iogc, 0, box_h - 3,
2195
			  "*", 1);
2196
	else
2197
#endif
2198
	  XmbDrawString(iodisplay,
2199
			menupanes[1],
2200
			font_set, iogc, 0, box_h - 3,
2201
			"*", 1);
2202
      else
2203
#endif
2204
	XDrawString(iodisplay, menupanes[1], iogc, 0, box_h - 3,
2205
		    "*", 1);
13974 hornik 2206
    else
34639 ripley 2207
#ifdef USE_FONTSET
2208
      if(mbcslocale)
2209
#ifdef HAVE_XUTF8DRAWSTRING
2210
        if(utf8locale)
2211
	  Xutf8DrawString(iodisplay,
2212
			  menupanes[2],
2213
			  font_set, iogc, 0, box_h - 3,
2214
			  "*", 1);
2215
	else
2216
#endif
2217
	  XmbDrawString(iodisplay,
2218
			menupanes[2],
2219
			font_set, iogc, 0, box_h - 3,
2220
			"*", 1);
2221
      else
2222
#endif
2223
	XDrawString(iodisplay, menupanes[2], iogc, 0, box_h - 3,
2224
		    "*", 1);
13974 hornik 2225
 
2226
/*
2227
  start an event loop; we're looking for a button press and a button
2228
  release in the same window
2229
*/
2230
 
2231
    while (1) {
2232
	XNextEvent(iodisplay, &event);
34639 ripley 2233
 
2234
	/* event is processed with input method */
2235
 
13974 hornik 2236
	if (event.type == ButtonPress) {
2237
	    button = event.xbutton.button;
2238
	    selected_pane = event.xbutton.window;
2239
	    for (i = 0; selected_pane != menupanes[i]; i++)
2240
		if (i >= 4) goto done;
2241
	    while (1) {
2242
		while (XCheckTypedEvent(iodisplay, ButtonPress, &event));
2243
		XMaskEvent(iodisplay, ButtonReleaseMask, &event);
2244
		if (event.xbutton.button == button)
2245
		    break;
2246
	    }
2247
	    if (selected_pane == event.xbutton.window) {
2248
		for (i = 0; selected_pane != menupanes[i]; i++);
2249
		switch (i) {
2250
		case 0:
2251
		    bell();
2252
		    break;
2253
		case 1:
32424 ripley 2254
		    if (isNull(tvec))
2255
			SET_VECTOR_ELT(work, popupcol - 1,
24274 ripley 2256
				       ssNewVector(REALSXP, 100));
2257
		    else
2258
			SET_VECTOR_ELT(work, popupcol - 1,
2259
				       coerceVector(tvec, REALSXP));
13974 hornik 2260
		    goto done;
2261
		case 2:
32424 ripley 2262
		    if (isNull(tvec))
2263
			SET_VECTOR_ELT(work, popupcol - 1,
24274 ripley 2264
				       ssNewVector(STRSXP, 100));
2265
		    else
32424 ripley 2266
			SET_VECTOR_ELT(work, popupcol - 1,
24274 ripley 2267
				       coerceVector(tvec, STRSXP));
13974 hornik 2268
		    goto done;
2269
		case 3:
2270
		    closerect();
2271
		    ccol = col;
2272
		    crow = 0;
2273
		    clearrect();
2274
		    goto done;
2275
		}
2276
	    }
2277
	}
2278
        /* this doesn't work and perhaps I should move it up to the
2279
           main control loop */
2280
	else if (event.type == Expose) {
2281
	    if (event.xexpose.window == menuwindow) {
2282
		XDrawString(iodisplay, menupanes[0], iogc, 3, box_h - 3,
2283
			    name, strlen(name));
2284
		for (i = 1; i < 4; i++)
2285
		    XDrawString(iodisplay, menupanes[i], iogc, 3, box_h - 3,
2286
				menu_label[i - 1], strlen(menu_label[i - 1]));
2287
	    }
2288
	}
2289
    }
2290
 done:
2291
    popdownmenu();
2292
    highlightrect();
2293
}
2294
 
2295
void popdownmenu(void)
2296
{
2297
    XUnmapWindow(iodisplay, menuwindow);
2298
    XUnmapSubwindows(iodisplay, menuwindow);
2299
}
2300
 
2301
static void copycell(void)
2302
{
34639 ripley 2303
  /*
2304
   * whichrow = crow + colmin - 1 => whichrow = crow + rowmin - 1
2305
   *                   ^^^                             ^^^
2306
   */
2307
    int i, whichrow = crow + rowmin - 1, whichcol = ccol + colmin -1;
13974 hornik 2308
    SEXP tmp;
32424 ripley 2309
 
13974 hornik 2310
    if (whichrow == 0) {
2311
	/* won't have  cell here */
2312
    } else {
2313
	strcpy(copycontents, "");
28786 ripley 2314
	if (length(work) >= whichcol) {
2315
	    tmp = VECTOR_ELT(work, whichcol - 1);
13974 hornik 2316
	    if (tmp != R_NilValue &&
28786 ripley 2317
		(i = whichrow - 1) < LENGTH(tmp) ) {
13974 hornik 2318
		PrintDefaults(R_NilValue);
34639 ripley 2319
                if (TYPEOF(tmp) == REALSXP) {
2320
		    if (REAL(tmp)[i] != ssNA_REAL){
2321
			strncpy(copycontents, EncodeElement(tmp, i, 0, '.'),
2322
				BOOSTED_BUF_SIZE-1);
2323
			copycontents[BOOSTED_BUF_SIZE-1]='\0';
2324
		    }
2325
                } else if (TYPEOF(tmp) == STRSXP) {
2326
                    if (!streql(CHAR(STRING_ELT(tmp, i)),
2327
				CHAR(STRING_ELT(ssNA_STRING, 0)))){
2328
			strncpy(copycontents, EncodeElement(tmp, i, 0, '.'),
2329
				BOOSTED_BUF_SIZE-1);
2330
			copycontents[BOOSTED_BUF_SIZE-1]='\0';
2331
		    }
13974 hornik 2332
		}
2333
	    }
2334
	}
2335
    }
2336
    highlightrect();
2337
}
2338
 
2339
static void pastecell(int row, int col)
2340
{
2341
    downlightrect();
2342
    crow = row; ccol = col;
2343
    if (strlen(copycontents)) {
2344
	strcpy(buf, copycontents);
2345
	clength = strlen(copycontents);
2346
	bufp = buf + clength;
2347
	CellModified = TRUE;
2348
    }
2349
    closerect();
2350
    highlightrect();
2351
}
34639 ripley 2352
 
35415 ripley 2353
#ifdef USE_FONTSET
34639 ripley 2354
static void calc_pre_edit_pos(void)
2355
{
2356
    XVaNestedList   xva_nlist;
2357
    XPoint          xpoint;
2358
    int i;
2359
    int w;
2360
 
2361
    xpoint.x = boxw[0];
2362
    for (i = 1; i < ccol; i++)
2363
	xpoint.x += BOXW(colmin + i - 1);
2364
#ifdef HAVE_XUTF8TEXTESCAPEMENT
2365
    if(utf8locale)
2366
	w = Xutf8TextEscapement(font_set, buf, clength);
2367
    else
2368
#endif
2369
	w = XmbTextEscapement(font_set, buf, clength);
2370
    xpoint.x += (w > BOXW(colmin + ccol - 1)) ? BOXW(colmin + ccol - 1) : w;
2371
    xpoint.x += text_offset;
2372
    xpoint.y = hwidth + (crow+1) * box_h - text_offset ;
2373
 
2374
    /*
2375
      <FIXME>
2376
      I may depend on implementation of XIM, but I do not obey,
2377
      setting value, and investigation in various implementation
2378
      system is need.
2379
      It is only a problem in an appearance.
2380
    */
2381
    xva_nlist = XVaCreateNestedList(0,
2382
				    XNSpotLocation, &xpoint,
2383
				    XNFontSet, font_set,
2384
				    NULL);
2385
    XSetICValues(ioic, XNPreeditAttributes, xva_nlist, NULL);
2386
 
2387
    XFree(xva_nlist);
2388
    return;
2389
}
35415 ripley 2390
#endif
34639 ripley 2391
 
2392
/* last character bytes */
2393
static int last_wchar_bytes(char *str)
2394
{
2395
#ifdef USE_FONTSET
2396
    wchar_t   wcs[BOOSTED_BUF_SIZE];
2397
    mbstate_t mb_st;
2398
    int cnt;
2399
    char last_mbs[8];
2400
    char *mbs;
2401
 
2402
    mbs = (str == NULL) ? buf : str;
2403
 
2404
    memset(wcs, 0 ,sizeof(wcs));
2405
    memset(&mb_st,0, sizeof(mbstate_t));
2406
 
2407
    if((size_t)-1 == (cnt = mbsrtowcs(wcs, (const char **)&mbs,
2408
				      strlen(mbs), &mb_st))) {
2409
        return 0;
2410
    }
2411
    if(wcs[0] == L'\0') return 0;
2412
 
2413
    memset(last_mbs, 0, sizeof(last_mbs));
2414
    wcrtomb(last_mbs, wcs[cnt-1], &mb_st);
2415
    return(strlen(last_mbs));
2416
#else
2417
    return(1);
2418
#endif
2419
}