The R Project SVN R

Rev

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

Rev Author Line No. Line
28991 murdoch 1
/*
2
 *  R : A Computer Language for Statistical Data Analysis
62583 ripley 3
 *  Copyright (C) 1999-2013  The R Core Team
28991 murdoch 4
 *
5
 *  This program is free software; you can redistribute it and/or modify
6
 *  it under the terms of the GNU General Public License as published by
7
 *  the Free Software Foundation; either version 2 of the License, or
8
 *  (at your option) any later version.
9
 *
10
 *  This program is distributed in the hope that it will be useful,
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 *  GNU General Public License for more details.
14
 *
15
 *  You should have received a copy of the GNU General Public License
42300 ripley 16
 *  along with this program; if not, a copy is available at
17
 *  http://www.r-project.org/Licenses/
28991 murdoch 18
 */
19
 
20
 
21
#ifdef HAVE_CONFIG_H
22
#include <config.h>
23
#endif
33001 ripley 24
#include "win-nls.h"
28991 murdoch 25
 
26
#ifdef Win32
27
#define USE_MDI 1
28
#endif
29
 
40700 ripley 30
#include <Defn.h>
31
#include <Fileio.h>
28991 murdoch 32
#include <stdio.h>
33
#include <Startup.h>
34
extern UImode  CharacterMode;
35
#include "graphapp/ga.h"
36
#include "graphapp/graphapp.h"
37
#include "graphapp/stdimg.h"
38
#include "console.h"
39
#include "consolestructs.h"
36901 ripley 40
#define WIN32_LEAN_AND_MEAN 1
28991 murdoch 41
#include <windows.h>
42
#include "rui.h"
43
#include "editor.h"
44
 
63218 ripley 45
/* from sysutils.c */
46
void reEnc2(const char *x, char *y, int ny,
47
	    cetype_t ce_in, cetype_t ce_out, int subst);
48
 
39274 ripley 49
#define gettext GA_gettext
50
 
28991 murdoch 51
#define MCHECK(a) if (!(a)) {del(c); return NULL;}
44201 ripley 52
RECT *RgetMDIsize(void);
28991 murdoch 53
 
54
/* Pointers to currently open editors */
55
static editor REditors[MAXNEDITORS];
56
static int neditors  = 0;
57
static Rboolean fix_editor_up = FALSE;
58
 
43760 ripley 59
static EditorData neweditordata (int file, const char *filename)
28991 murdoch 60
{
61
    EditorData p;
62
    p = (EditorData) malloc(sizeof(struct structEditorData));
63
    p->file = file;
39498 ripley 64
    /* need space for terminator, and to copy it */
65
    p->filename = (char *) malloc((MAX_PATH+1)*sizeof(char));
28991 murdoch 66
    if (filename)
39498 ripley 67
	strncpy(p->filename, filename, MAX_PATH+1);
29062 murdoch 68
    p->title = (char *) malloc((EDITORMAXTITLE + 1)*sizeof(char));
69
    p->title[EDITORMAXTITLE] = p->title[0] = '\0';
28991 murdoch 70
    return p;
71
}
72
 
39498 ripley 73
void deleditordata(EditorData p)
74
{
28991 murdoch 75
    if (p->stealconsole)
76
	fix_editor_up = FALSE;
77
    free(p->filename);
29051 murdoch 78
    free(p->title);
36258 murdoch 79
    free(p->hmenu);
80
    free(p->pmenu);
28991 murdoch 81
    free(p);
82
}
83
 
43760 ripley 84
static void editor_set_title(editor c, const char *title)
39498 ripley 85
{
28991 murdoch 86
    char wtitle[EDITORMAXTITLE+1];
29051 murdoch 87
    textbox t = getdata(c);
88
    EditorData p = getdata(t);
89
    strncpy(wtitle, title, EDITORMAXTITLE);
29062 murdoch 90
    wtitle[EDITORMAXTITLE] = '\0';
29051 murdoch 91
    strcpy(p->title, wtitle);
43410 murdoch 92
    if (strlen(wtitle) + strlen(G_("R Editor")) + 3 < EDITORMAXTITLE) {
45070 ripley 93
	strcat(wtitle, " - ");
94
	strcat(wtitle, G_("R Editor"));
43410 murdoch 95
    }
28991 murdoch 96
    settext(c, wtitle);
97
}
98
 
99
/*** FILE MANAGEMENT FUNCTIONS ***/
100
 
46842 ripley 101
FILE *R_wfopen(const wchar_t *filename, const wchar_t *mode);
102
 
44016 ripley 103
static void editor_load_file(editor c, const char *name, int enc)
28991 murdoch 104
{
105
    textbox t = getdata(c);
106
    EditorData p = getdata(t);
107
    FILE *f;
63219 ripley 108
    char *buffer = NULL, tmp[MAX_PATH+50], tname[MAX_PATH+1];
109
    const char *sname;
39498 ripley 110
    long num = 1, bufsize;
111
 
46842 ripley 112
    if(enc == CE_UTF8) {
113
	wchar_t wname[MAX_PATH+1];
114
	Rf_utf8towcs(wname, name, MAX_PATH+1);
115
	f = R_wfopen(wname, L"r");
63218 ripley 116
	reEnc2(name, tname, MAX_PATH+1, CE_UTF8, CE_NATIVE, 3);
117
	sname = tname;
46842 ripley 118
    } else {
119
	f = R_fopen(name, "r");
120
	sname = name;
121
    }
122
    if (f == NULL) {
123
	snprintf(tmp, MAX_PATH+50, 
124
		 G_("unable to open file %s for reading"), sname);
125
	R_ShowMessage(tmp);
126
	return;
127
    }
28991 murdoch 128
    p->file = 1;
39498 ripley 129
    strncpy(p->filename, name, MAX_PATH+1);
28991 murdoch 130
    bufsize = 0;
131
    while (num > 0) {
39498 ripley 132
	buffer = realloc(buffer, bufsize + 3000 + 1);
133
	num = fread(buffer + bufsize, 1, 3000 - 1, f);
28991 murdoch 134
	if (num >= 0) {
135
	    bufsize += num;
136
	    buffer[bufsize] = '\0';
137
	}
138
	else {
46842 ripley 139
	    snprintf(tmp, MAX_PATH+50, 
140
		     G_("Could not read from file '%s'"), sname);
28991 murdoch 141
	    askok(tmp);
142
	}
143
    }
144
    setlimittext(t, 2 * strlen(buffer));
145
    settext(t, buffer);
146
    gsetmodified(t, 0);
147
    free(buffer);
148
    fclose(f);
149
}
150
 
46842 ripley 151
static void editor_save_file(editor c, const char *name, int enc)
28991 murdoch 152
{
153
    textbox t = getdata(c);
154
    FILE *f;
63219 ripley 155
    char buf[MAX_PATH+30], tname[MAX_PATH+1];
156
    const char *sname;
46842 ripley 157
 
28991 murdoch 158
    if (name == NULL)
159
	return;
160
    else {
46842 ripley 161
	if(enc == CE_UTF8) {
162
	    wchar_t wname[MAX_PATH+1];
163
	    Rf_utf8towcs(wname, name, MAX_PATH+1);
63218 ripley 164
	    reEnc2(name, tname, MAX_PATH+1, CE_UTF8, CE_NATIVE, 3);
165
	    sname = tname;
46842 ripley 166
	    f = R_wfopen(wname, L"w");
167
	} else {
168
	    sname = name;
169
	    f = R_fopen(sname, "w");
170
	}
28991 murdoch 171
	if (f == NULL) {
46842 ripley 172
	    snprintf(buf, MAX_PATH+30, G_("Could not save file '%s'"), sname);
28991 murdoch 173
	    askok(buf);
174
	    return;
175
	}
176
	fprintf(f, "%s", gettext(t));
177
	fclose(f);
178
    }
179
}
180
 
45070 ripley 181
static void editorsaveas(editor c)
182
{
28991 murdoch 183
    textbox t = getdata(c);
184
    EditorData p = getdata(t);
46842 ripley 185
    wchar_t *wname;
186
 
187
    setuserfilterW(L"R files (*.R)\0*.R\0S files (*.q, *.ssc, *.S)\0*.q;*.ssc;*.S\0All files (*.*)\0*.*\0\0");
188
    wname = askfilesaveW(G_("Save script as"), "");
50851 murdoch 189
    if (wname) {
46842 ripley 190
	char name[4*MAX_PATH+1];
191
	wcstoutf8(name, wname, MAX_PATH);
57464 ripley 192
	/* now check if it has an extension */
193
	char *q = strchr(name, '.');
194
	if(!q) strncat(name, ".R", 4*MAX_PATH);
46842 ripley 195
	editor_save_file(c, name, CE_UTF8);
28991 murdoch 196
	p->file = 1;
63218 ripley 197
	reEnc2(name, p->filename, MAX_PATH+1, CE_UTF8, CE_NATIVE, 3);
28991 murdoch 198
	gsetmodified(t, 0);
63219 ripley 199
	editor_set_title(c, p->filename);
28991 murdoch 200
    }
50851 murdoch 201
    show(c);
28991 murdoch 202
}
203
 
204
static void menueditorsaveas(control m)
205
{
206
    editor c = getdata(m);
207
    editorsaveas(c);
208
}
209
 
210
static void editorsave(editor c)
211
{
212
    textbox t = getdata(c);
213
    EditorData p = getdata(t);
214
    if (p->file) {  /* save existing file without prompt */
46842 ripley 215
	editor_save_file(c, p->filename, CE_UTF8);
28991 murdoch 216
	gsetmodified(t, 0);
217
    }
218
    /* if new file then prompt for name to save as */
219
    else editorsaveas(c);
220
}
221
 
222
static void menueditorsave(control m)
223
{
224
    editor c = getdata(m);
225
    editorsave(c);
226
    show(c); /* steal focus back from tool button */
227
}
228
 
229
/* global console configuration variables */
230
char fontname[LF_FACESIZE+1];
231
int fontsty, pointsize;
232
 
233
static void editorprint(control m)
234
{
235
    printer lpr;
236
    font f;
237
    textbox t = getdata(m);
43800 ripley 238
    const char *contents = gettext(t);
28991 murdoch 239
    char msg[LF_FACESIZE + 128];
240
    char *linebuf = NULL;
241
    int cc, rr, fh, page, linep, i, j, istartline;
242
    int top, left;
243
 
244
    if (!(lpr = newprinter(0.0, 0.0, ""))) return;
245
    f = gnewfont(lpr, strcmp(fontname, "FixedFont") ? fontname : "Courier New",
44575 ripley 246
		 fontsty, pointsize, 0.0, 1);
28991 murdoch 247
    top = devicepixelsy(lpr) / 5;
248
    left = devicepixelsx(lpr) / 5;
249
    fh = fontheight(f);
250
    rr = getheight(lpr) - top;
251
    cc = getwidth(lpr) - 2*left;
252
 
253
    linep = rr; /* line in printer page */
254
    page = 1;
255
    i = 0;
256
    while (i < strlen(contents)) {
257
	if ( linep + fh >= rr ) { /* new page */
258
	    if (page > 1) nextpage(lpr);
62583 ripley 259
	    snprintf(msg, LF_FACESIZE + 128, "Page %d", page++);
45070 ripley 260
	    gdrawstr(lpr, f, Black, pt(cc - gstrwidth(lpr, f, msg) - 1, top),
39498 ripley 261
		     msg);
28991 murdoch 262
	    linep = top + 2*fh;
263
	}
264
	j = 0;
265
	istartline = i;
266
	while (contents[i] != '\n' && contents[i] != '\0') {
267
	    ++i; ++j;
268
	}
269
	linebuf = realloc(linebuf, (j+1)*sizeof(char));
270
	strncpy(linebuf, &contents[istartline], j);
271
	linebuf[j] = '\0';
45070 ripley 272
	gdrawstr(lpr, f, Black, pt(left, linep), linebuf);
28991 murdoch 273
	linep += fh;
274
	++i;
275
    }
276
    free(linebuf);
277
    if (f != FixedFont) del(f);
278
    del(lpr);
279
}
280
 
281
static void editorconsole(editor c)
282
{
283
    show(RConsole);
284
}
285
 
39498 ripley 286
/* Remove global pointer to editor when closing an editor. Fill the
287
 * gap in the array with the last editor in the list */
28991 murdoch 288
 
39498 ripley 289
static void editorupdateglobals(editor c)
290
{
291
    int i = 0;
28991 murdoch 292
    if (neditors > 1) {
293
	while (REditors[i] != c) ++i;
294
	if (i < neditors - 1)
295
	    REditors[i] = REditors[neditors-1];
296
    }
297
    --neditors;
298
}
299
 
29062 murdoch 300
/* Hooks called when editor window is destroyed */
28991 murdoch 301
 
39498 ripley 302
static void editordel(editor c)
303
{
29062 murdoch 304
    editorupdateglobals(c);
305
}
306
 
39498 ripley 307
static void textboxdel(textbox t)
308
{
28991 murdoch 309
    EditorData p = getdata(t);
310
    deleditordata(p);
311
}
312
 
39498 ripley 313
int editorchecksave(editor c)
314
{
28991 murdoch 315
    textbox t = getdata(c);
316
    EditorData p = getdata(t);
317
    int save;
318
    char buf[EDITORMAXTITLE + 100];
319
    if (ggetmodified(t)) {
33756 ripley 320
	snprintf(buf, EDITORMAXTITLE + 100,
32604 ripley 321
		 "\"%s\" has been modified.  Do you want to save the changes?",
29051 murdoch 322
		 (p->title ? p->title : "Untitled"));
28991 murdoch 323
	save = askyesnocancel(buf);
324
	switch (save) {
325
	case YES:
326
	    editorsave(c);
327
	    break;
328
	case NO:
329
	    break;
330
	case CANCEL:
61963 ripley 331
	    return 1;
28991 murdoch 332
	}
333
    }
334
    return 0;
335
}
336
 
337
static void editorclose(editor c)
338
{
339
    if (!editorchecksave(c))
340
	del(c);
341
}
342
 
343
static void menueditorclose(control m)
344
{
345
    editor c = getdata(m);
346
    editorclose(c);
347
}
348
 
349
/* Called when exiting Rgui, check if any open editors need saving */
350
 
44201 ripley 351
void editorcleanall(void)
28991 murdoch 352
{
353
    int i;
354
    for (i = neditors-1;  i >= 0; --i) {
61963 ripley 355
	if (editorchecksave(REditors[i])) {
356
	    R_ProcessEvents();  // see R_CleanUp
357
	    jump_to_toplevel();
358
	}
28991 murdoch 359
	del(REditors[i]);
360
    }
361
}
362
 
44201 ripley 363
static void editornew(void)
28991 murdoch 364
{
44016 ripley 365
    Rgui_Edit("", CE_NATIVE, "", 0);
28991 murdoch 366
}
367
 
368
void menueditornew(control m)
369
{
370
    editornew();
371
}
372
 
43760 ripley 373
static void editoropen(const char *default_name)
28991 murdoch 374
{
46842 ripley 375
    wchar_t *wname;
63219 ripley 376
    char name[4*MAX_PATH], title[4*MAX_PATH];
46842 ripley 377
 
28991 murdoch 378
    int i; textbox t; EditorData p;
46842 ripley 379
    setuserfilterW(L"R files (*.R)\0*.R\0S files (*.q, *.ssc, *.S)\0*.q;*.ssc;*.S\0All files (*.*)\0*.*\0\0");
380
    wname = askfilenameW(G_("Open script"), default_name); /* returns NULL if open dialog cancelled */
381
    if (wname) {
382
	wcstoutf8(name, wname, MAX_PATH);
28991 murdoch 383
	/* check if file is already open in an editor. If so, close and open again */
39498 ripley 384
	for (i = 0; i < neditors; ++i) {
28991 murdoch 385
	    t = getdata(REditors[i]);
386
	    p = getdata(t);
387
	    if (!strcmp (name, p->filename)) {
388
		editorclose(REditors[i]);
389
		break;
390
	    }
391
	}
63218 ripley 392
	reEnc2(name, title, MAX_PATH+1, CE_UTF8, CE_NATIVE, 3);
46842 ripley 393
	Rgui_Edit(name, CE_UTF8, title, 0);
50851 murdoch 394
    } else show(RConsole);
28991 murdoch 395
}
396
 
397
void menueditoropen(control m)
398
{
399
    editor c = getdata(m);
400
    char *default_name = "";
45070 ripley 401
    /* It really is not clear what is meant here: seems to assume an
402
       editor window but is called from elsewhere, hopefully with NULL
35234 ripley 403
       (since 2.1.1 patched). */
28991 murdoch 404
    if (c) {
405
	textbox t = getdata(c);
406
	EditorData p = getdata(t);
407
	if (p->file) default_name = p->filename;  /* name of currently-open file, if there is one */
408
    }
409
    editoropen(default_name);
410
}
411
 
412
 
413
/*** EDITING FUNCTIONS ***/
414
 
415
static void editorundo(control m)
416
{
417
    textbox t = getdata(m);
418
    undotext(t);
419
}
420
 
421
static void editorcut(control m)
422
{
423
    textbox t = getdata(m);
424
    cuttext(t);
425
}
426
 
427
static void editorcopy(control m)
428
{
429
    textbox t = getdata(m);
430
    copytext(t);
431
}
432
 
433
static void editorpaste(control m)
434
{
435
    textbox t = getdata(m);
39498 ripley 436
    /* check whether the widget text limit needs to be increased
437
     * before doing the paste */
28991 murdoch 438
    int pastelen = getpastelength();
439
    checklimittext(t, pastelen + 1);
440
    pastetext(t);
441
}
442
 
443
static void editordelete(control m)
444
{
445
    textbox t = getdata(m);
446
    cleartext(t);
447
}
448
 
449
static void editorselectall(control m)
450
{
451
    textbox t = getdata(m);
452
    selecttextex(t, 0, -1);
453
}
454
 
455
static void editorfind(control m)
456
{
457
    textbox t = getdata(m);
458
    finddialog(t);  /* actual find/replace work is in graphapp/dialogs.c */
459
}
460
 
461
static void editorreplace(control m)
462
{
463
    textbox t = getdata(m);
464
    replacedialog(t);
465
}
466
 
467
 
468
/*** FUNCTIONS FOR RUNNING R CODE FROM THE EDITOR ***/
469
 
470
static void editorrunline(textbox t)
471
{
38972 ripley 472
    int length = getlinelength(t); /* return character num */
473
    char *line = malloc(length * sizeof(WCHAR) + 2); /* Extra space for null and word length in getcurrentline */
474
    memset(line, 0, length * sizeof(WCHAR) + 2);
28991 murdoch 475
    getcurrentline(t, line, length);
476
    consolecmd(RConsole, line);
477
    free(line);
478
    scrollcaret(t, 1);
479
    show(t);
480
}
481
 
482
/* For the moment, send the selected text to the console via the
483
   clipboard. Wasteful, but currently consolecmd only allows a maximum
484
   of 8K of text */
485
 
486
static void editorrunselection(textbox t, long start, long end)
487
{
488
    copytext(t);
489
    if (consolecanpaste(RConsole)) {
490
	consolepaste(RConsole);
491
	if (gettext(t)[end-1] != '\n')
492
	    consolenewline(RConsole);
493
    }
494
}
495
 
29001 murdoch 496
static Rboolean busy_running = FALSE;
497
 
28991 murdoch 498
static void editorrun(textbox t)
499
{
29001 murdoch 500
    if (!busy_running) {
45070 ripley 501
	long start=0, end=0;
502
	if (CharacterMode != RGui) {
503
	    R_ShowMessage(G_("No RGui console to paste to"));
504
	    return;
505
	}
506
	busy_running = TRUE;
507
	textselectionex(t, &start, &end);
508
	if (start >= end)
29001 murdoch 509
	    editorrunline(t);
45070 ripley 510
	else {
29001 murdoch 511
	    editorrunselection(t, start, end);
512
	    selecttextex(t, end, end); /* move insertion point to end of selection after running */
45070 ripley 513
	}
514
	busy_running = FALSE;
28991 murdoch 515
    }
516
}
517
 
518
static void menueditorrun(control m)
519
{
520
    textbox t = getdata(m);
521
    editorrun(t);
522
}
523
 
524
static void editorrunall(control m)
525
{
526
    textbox t = getdata(m);
527
    long start=0, end=0;
528
    textselectionex(t, &start, &end); /* save current selection state */
529
    selecttextex(t, 0, -1);
29001 murdoch 530
    editorrun(t);
28991 murdoch 531
    selecttextex(t, start, end);  /* return to original selection state */
532
}
533
 
534
/* Grey out menu buttons as appropriate */
535
 
536
static void editormenuact(control m)
537
{
538
    long start, end;
539
    textbox t = getdata(m);
540
    EditorData p = getdata(t);
541
    textselectionex(t, &start, &end);
542
    if (start < end) {
45070 ripley 543
	enable(p->mcut);
544
	enable(p->mcopy);
545
	enable(p->mdelete);
546
	enable(p->mpopcut);
547
	enable(p->mpopcopy);
548
	enable(p->mpopdelete);
28991 murdoch 549
    }
550
    else {
551
	disable(p->mcut);
552
	disable(p->mcopy);
553
	disable(p->mdelete);
554
	disable(p->mpopcut);
555
	disable(p->mpopcopy);
556
	disable(p->mpopdelete);
557
    }
558
    if (modeless_active()){
559
	disable(p->mfind);
560
	disable(p->mreplace);
561
    }
562
    else {
563
	enable(p->mfind);
564
	enable(p->mreplace);
565
    }
36258 murdoch 566
    helpmenuact(p->hmenu);
567
    pkgmenuact(p->pmenu);
28991 murdoch 568
}
569
 
570
static void editorresize(editor c, rect r)
571
{
572
    resize(getdata(c), r);
573
    resize(c, r);
574
}
575
 
576
static void editorcontrolkeydown(textbox t, int key)
577
{
578
    switch (key) {
579
    case F5:
580
	editorrun(t);
581
	break;
582
    }
583
}
584
 
585
static void editorasciikeydown(textbox t, int key)
586
{
587
    /* check whether the text limit is about to be exceeded and
45070 ripley 588
       increase it if necessary.  Ugh - this callback is called after
589
       the text is inserted, so we make space for two characters */
28991 murdoch 590
    checklimittext(t, 2);
591
}
592
 
593
/* Set keyboard focus to the text editing area when the editor window receives focus */
594
 
595
static void editorfocus(editor c)
596
{
597
    textbox t = getdata(c);
598
    show(t);
599
}
600
 
44201 ripley 601
static void editorhelp(void)
28991 murdoch 602
{
603
    char s[4096];
604
 
39498 ripley 605
    strcpy(s, G_("R EDITOR\n"));
606
    strcat(s, "\n");
607
    strcat(s, G_("A standard text editor for editing and running R code.\n"));
608
    strcat(s, "\n");
609
    strcat(s, G_("RUNNING COMMANDS\n"));
610
    strcat(s, G_("To run a line or section of R code, select the code and either\n"));
611
    strcat(s, G_("     Press Ctrl-R\n"));
612
    strcat(s, G_("     Select \"Run line or selection\" from the \"Edit\" menu\n"));
613
    strcat(s, G_("     Press the \"Run line or selection\" icon on the toolbar\n"));
614
    strcat(s, G_("This will copy the selected commands to the console and evaluate them.\n"));
615
    strcat(s, G_("If there is no selection, this will just run the current line and advance\n"));
616
    strcat(s, G_("the cursor by one line.\n"));
28991 murdoch 617
 
618
    askok(s);
619
}
620
 
621
 
622
static void menueditorhelp(control m)
623
{
624
    editorhelp();
625
}
626
 
627
static MenuItem EditorPopup[] = {                /* Numbers used below */
33001 ripley 628
    {GN_("Run line or selection"), menueditorrun, 'R', 0}, /* 0 */
28991 murdoch 629
    {"-", 0, 0, 0},
33001 ripley 630
    {GN_("Undo"), editorundo, 'Z', 0},                     /* 2 */
28991 murdoch 631
    {"-", 0, 0, 0},
33001 ripley 632
    {GN_("Cut"), editorcut, 'X', 0},                       /* 4 */
633
    {GN_("Copy"), editorcopy, 'C', 0},                     /* 5 */
634
    {GN_("Paste"), editorpaste, 'V', 0},                   /* 6 */
635
    {GN_("Delete"), editordelete, 0, 0},                   /* 7 */
28991 murdoch 636
    {"-", 0, 0, 0},
33001 ripley 637
    {GN_("Select all"), editorselectall, 'A', 0},          /* 9 */
28991 murdoch 638
    LASTMENUITEM
639
};
640
 
44201 ripley 641
static editor neweditor(void)
28991 murdoch 642
{
643
    int x, y, w, h, w0, h0;
644
    editor c;
645
    menuitem m;
646
    textbox t;
647
    long flags;
648
    font editorfn = (consolefn ? consolefn : FixedFont);
649
    EditorData p = neweditordata(0, NULL);
650
    DWORD rand;
651
 
652
    w = (pagercol + 1)*fontwidth(editorfn);
653
    h = (pagerrow + 1)*fontheight(editorfn) + 1;
654
#ifdef USE_MDI
655
    if(ismdi()) {
656
	RECT *pR = RgetMDIsize();
657
	w0 = pR->right;
658
	h0 = pR->bottom;
659
    } else {
660
#endif
661
	w0 = devicewidth(NULL);
662
	h0 = deviceheight(NULL);
663
#ifdef USE_MDI
664
    }
665
#endif
666
    x = (w0 - w) / 2; x = x > 20 ? x : 20;
667
    y = (h0 - h) / 2; y = y > 20 ? y : 20;
668
    rand = GetTickCount();
669
    w0 = 0.4*x; h0 = 0.4*y;
670
    w0 = w0 > 20 ? w0 : 20;
671
    h0 = h0 > 20 ? h0 : 20;
672
    x += (rand % w0) - w0/2;
673
    y += ((rand/w0) % h0) - h0/2;
674
    flags = StandardWindow | Menubar;
675
#ifdef USE_MDI
676
    if (ismdi()) flags |= Document;
677
#endif
678
    c = (editor) newwindow("", rect(x, y, w, h), flags);
679
    t = newrichtextarea(NULL, rect(0, 0, w, h));
680
    setdata(c, t);
681
    setdata(t, p);
682
 
683
    gsetcursor(c, ArrowCursor);
46784 murdoch 684
    setforeground(c, guiColors[editorfg]);
685
    setbackground(c, guiColors[editorbg]);
686
    setbackground(t, guiColors[editorbg]);
46774 murdoch 687
 
28991 murdoch 688
#ifdef USE_MDI
689
    if (ismdi() && (RguiMDI & RW_TOOLBAR)) {
690
	int btsize = 24;
691
	rect r = rect(2, 2, btsize, btsize);
692
	control tb, bt;
693
	addto(c);
694
	MCHECK(tb = newtoolbar(btsize + 4));
695
	addto(tb);
696
	MCHECK(bt = newtoolbutton(open_image, r, menueditoropen));
33001 ripley 697
	MCHECK(addtooltip(bt, G_("Open script")));
28991 murdoch 698
	setdata(bt, c);
699
	r.x += (btsize + 1) ;
700
	MCHECK(bt = newtoolbutton(save_image, r, menueditorsave));
33001 ripley 701
	MCHECK(addtooltip(bt,  G_("Save script")));
28991 murdoch 702
	setdata(bt, c);
703
	r.x += (btsize + 6);
704
	MCHECK(bt = newtoolbutton(copy1_image, r, menueditorrun));
33001 ripley 705
	MCHECK(addtooltip(bt, G_("Run line or selection")));
28991 murdoch 706
	setdata(bt, t);
707
	r.x += (btsize + 6);
708
	MCHECK(bt = newtoolbutton(console_image, r, editorconsole));
33001 ripley 709
	MCHECK(addtooltip(bt, G_("Return focus to Console")));
28991 murdoch 710
	r.x += (btsize + 6);
711
	MCHECK(bt = newtoolbutton(print_image, r, editorprint));
33001 ripley 712
	MCHECK(addtooltip(bt, G_("Print script")));
28991 murdoch 713
	setdata(bt, t);
33001 ripley 714
	MCHECK(addtooltip(bt, G_("Print")));
28991 murdoch 715
    }
716
#endif
717
    addto(c);
718
    /* Right-click context menu */
719
    MCHECK(m = gpopup(editormenuact, EditorPopup));
720
    setdata(m, t);
721
    setdata(EditorPopup[0].m, t);
722
    setdata(EditorPopup[2].m, t);
723
    setdata(p->mpopcut = EditorPopup[4].m, t);
724
    setdata(p->mpopcopy = EditorPopup[5].m, t);
725
    setdata(EditorPopup[6].m, t);
726
    setdata(p->mpopdelete = EditorPopup[7].m, t);
727
    setdata(EditorPopup[9].m, t);
728
 
729
    addto(c);
730
    MCHECK(m = newmenubar(editormenuact));
731
    setdata(m, t);
33001 ripley 732
    MCHECK(newmenu(G_("File")));
733
    MCHECK(m = newmenuitem(G_("New script"), 'N', menueditornew));
28991 murdoch 734
    setdata(m, c);
33001 ripley 735
    MCHECK(m = newmenuitem(G_("Open script..."), 'O', menueditoropen));
28991 murdoch 736
    setdata(m, c);
33001 ripley 737
    MCHECK(m = newmenuitem(G_("Save"), 'S', menueditorsave));
28991 murdoch 738
    setdata(m, c);
33001 ripley 739
    MCHECK(m = newmenuitem(G_("Save as..."), 0, menueditorsaveas));
28991 murdoch 740
    setdata(m, c);
741
    MCHECK(m = newmenuitem("-", 0, NULL));
33001 ripley 742
    MCHECK(m = newmenuitem(G_("Print..."), 0, editorprint));
28991 murdoch 743
    setdata(m, t);
744
    MCHECK(m = newmenuitem("-", 0, NULL));
33001 ripley 745
    MCHECK(m = newmenuitem(G_("Close script"), 0, menueditorclose));
28991 murdoch 746
    setdata(m, c);
33001 ripley 747
    MCHECK(newmenu(G_("Edit")));
748
    MCHECK(m = newmenuitem(G_("Undo"), 'Z', editorundo));
28991 murdoch 749
    setdata(m, t);
750
    MCHECK(m = newmenuitem("-", 0, NULL));
33001 ripley 751
    MCHECK(p->mcut = newmenuitem(G_("Cut"), 'X', editorcut));
28991 murdoch 752
    setdata(p->mcut, t);
33001 ripley 753
    MCHECK(p->mcopy = newmenuitem(G_("Copy"), 'C', editorcopy));
28991 murdoch 754
    setdata(p->mcopy, t);
33001 ripley 755
    MCHECK(m = newmenuitem(G_("Paste"), 'V', editorpaste));
28991 murdoch 756
    setdata(m, t);
33001 ripley 757
    MCHECK(p->mdelete = newmenuitem(G_("Delete"), 0, editordelete));
28991 murdoch 758
    setdata(p->mdelete, t);
33001 ripley 759
    MCHECK(m = newmenuitem(G_("Select all"), 'A', editorselectall));
28991 murdoch 760
    setdata(m, t);
33001 ripley 761
    MCHECK(newmenuitem(G_("Clear console"), 'L', menuclear));
28991 murdoch 762
    MCHECK(m = newmenuitem("-", 0, NULL));
33001 ripley 763
    MCHECK(m = newmenuitem(G_("Run line or selection"), 'R', menueditorrun));
28991 murdoch 764
    setdata(m, t);
33001 ripley 765
    MCHECK(m = newmenuitem(G_("Run all"), 0, editorrunall));
28991 murdoch 766
    setdata(m, t);
767
    MCHECK(m = newmenuitem("-", 0, NULL));
33001 ripley 768
    MCHECK(p->mfind = newmenuitem(G_("Find..."), 'F', editorfind));
28991 murdoch 769
    setdata(p->mfind, t);
33001 ripley 770
    MCHECK(p->mreplace = newmenuitem(G_("Replace..."), 'H', editorreplace));
28991 murdoch 771
    setdata(p->mreplace, t);
772
    MCHECK(m = newmenuitem("-", 0, NULL));
33001 ripley 773
    MCHECK(newmenuitem(G_("GUI preferences..."), 0, menuconfig));
28991 murdoch 774
 
775
    /* Packages menu should go here */
36258 murdoch 776
    p->pmenu = (PkgMenuItems) malloc(sizeof(struct structPkgMenuItems));
777
    RguiPackageMenu(p->pmenu);
778
 
28991 murdoch 779
#ifdef USE_MDI
780
    newmdimenu(); /* Create and fill the 'Window' menu */
781
#endif
782
 
33001 ripley 783
    MCHECK(m = newmenu(G_("Help")));
784
    MCHECK(newmenuitem(G_("Editor"), 0, menueditorhelp));
28991 murdoch 785
    MCHECK(newmenuitem("-", 0, NULL));
36258 murdoch 786
    p->hmenu = (HelpMenuItems) malloc(sizeof(struct structHelpMenuItems));
787
    RguiCommonHelp(m, p->hmenu);
28991 murdoch 788
 
789
    settextfont(t, editorfn);
46784 murdoch 790
    setforeground(t, guiColors[editorfg]);    
28991 murdoch 791
    setresize(c, editorresize);
792
    setclose(c, editorclose);
793
    setdel(c, editordel);
29062 murdoch 794
    setdel(t, textboxdel);
28991 murdoch 795
    setonfocus(c, editorfocus);
796
    setkeyaction(t, editorcontrolkeydown);
797
    setkeydown(t, editorasciikeydown);
798
 
799
    /* Store pointer to new editor in global array */
800
    REditors[neditors] = c;
801
    ++neditors;
802
    return c;
803
}
804
 
805
/* Change the font used in all running editors */
806
 
807
void editorsetfont(font f)
808
{
809
    int i, ismod;
810
    textbox t;
33756 ripley 811
    for (i = 0; i < neditors; i++) {
28991 murdoch 812
	t = getdata(REditors[i]);
45070 ripley 813
	ismod = ggetmodified(t);
33756 ripley 814
	/* Don't change the modification flag when changing font  */
28991 murdoch 815
	settextfont(t, f);
816
	gsetmodified(t, ismod);
817
	show(t);
818
    }
819
}
820
 
821
static void eventloop(editor c)
822
{
823
    while (fix_editor_up) {
824
	/* avoid consuming 100% CPU time here */
825
	Sleep(10);
826
	R_ProcessEvents();
827
    }
828
}
829
 
830
/* Open existing file for editing or open blank editor for a new
831
   file. If calling from fix() or edit(), then don't send events to
832
   the console until editor is closed.  */
833
 
29219 ripley 834
#include <unistd.h>
835
 
44016 ripley 836
int Rgui_Edit(const char *filename, int enc, const char *title,
837
	      int modal)
28991 murdoch 838
{
839
    editor c;
840
    EditorData p;
29219 ripley 841
 
28991 murdoch 842
    if (neditors == MAXNEDITORS) {
33001 ripley 843
	R_ShowMessage(G_("Maximum number of editors reached"));
28991 murdoch 844
	return 1;
845
    }
846
    c = neweditor();
847
    if (!c) {
33001 ripley 848
	R_ShowMessage(G_("Unable to create editor window"));
28991 murdoch 849
	return 1;
850
    }
851
    if (strlen(filename) > 0) {
46842 ripley 852
	editor_load_file(c, filename, enc);
29051 murdoch 853
	editor_set_title(c, title);
28991 murdoch 854
    }
855
    else {
33001 ripley 856
	editor_set_title(c, G_("Untitled"));
28991 murdoch 857
    }
858
    show(c);
45070 ripley 859
 
36252 murdoch 860
    p = getdata(getdata(c));
44016 ripley 861
    p->stealconsole = modal;
862
    if (modal) {
45070 ripley 863
	fix_editor_up = TRUE;
864
	eventloop(c);
36258 murdoch 865
    }
28991 murdoch 866
    return 0;
867
}