Permalink
Cannot retrieve contributors at this time
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
1528 lines (1324 sloc)
38.1 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| * R : A Computer Language for Statistical Data Analysis | |
| * Copyright (C) 1998--2005 Guido Masarotto and Brian Ripley | |
| * Copyright (C) 2004--2018 The R Foundation | |
| * | |
| * This program is free software; you can redistribute it and/or modify | |
| * it under the terms of the GNU General Public License as published by | |
| * the Free Software Foundation; either version 2 of the License, or | |
| * (at your option) any later version. | |
| * | |
| * This program is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| * GNU General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU General Public License | |
| * along with this program; if not, a copy is available at | |
| * https://www.R-project.org/Licenses/ | |
| */ | |
| #ifdef HAVE_CONFIG_H | |
| #include <config.h> | |
| #endif | |
| #include "win-nls.h" | |
| #include <Defn.h> | |
| /* R user interface based on GraphApp */ | |
| #include "Defn.h" | |
| #undef append /* defined by graphapp/internal.h */ | |
| #include <stdio.h> | |
| #undef DEBUG /* needed for mingw-runtime 2.0 */ | |
| /* the user menu code looks at the internal structure */ | |
| #define GA_EXTERN | |
| #include "graphapp/internal.h" | |
| #include "graphapp/ga.h" | |
| #include "graphapp/stdimg.h" | |
| #include "console.h" | |
| #include "rui.h" | |
| #include "preferences.h" | |
| #include <Rversion.h> | |
| #include "getline/wc_history.h" /* for wgl_load/savehistory */ | |
| #include <Startup.h> /* for SA_DEFAULT */ | |
| #define TRACERUI(a) | |
| extern Rboolean UserBreak; | |
| console RConsole = NULL; | |
| int RguiMDI = RW_MDI | RW_TOOLBAR | RW_STATUSBAR; | |
| int MDIset = 0; | |
| window RFrame = NULL; /* some compilers want initialized for export */ | |
| rect MDIsize; | |
| extern int ConsoleAcceptCmd, R_is_running; | |
| extern Rboolean DebugMenuitem; | |
| Rboolean R_LoadRconsole = TRUE; /* used in commandLineArgs */ | |
| static menubar RMenuBar; | |
| static popup RConsolePopup; | |
| static menuitem msource, mdisplay, mload, msave, mloadhistory, | |
| msavehistory, mpaste, mpastecmds, mcopy, mcopypaste, mlazy, mcomplete, | |
| mfncomplete, mconfig, mls, mrm, msearch, mde, mtools, mstatus; | |
| static int lmanintro, lmanref, lmandata, lmanlang, lmanext, lmanint, | |
| lmanadmin, lmanSweave; | |
| static menu m; | |
| static char cmd[1024]; | |
| static HelpMenuItems hmenu; | |
| static PkgMenuItems pmenu; | |
| #include "editor.h" | |
| /* menu callbacks */ | |
| /* We need to handle \ in paths which are to be passed to R code. | |
| Since these can include \\ for network drives, we cannot just use /, | |
| although we did prior to R 2.4.0. | |
| MBCS-aware since 2.4.0. | |
| */ | |
| static void double_backslashes(char *s, char *out) | |
| { | |
| char *p = s; | |
| int i; | |
| if(mbcslocale) { | |
| mbstate_t mb_st; int used; | |
| mbs_init(&mb_st); | |
| while((used = Mbrtowc(NULL, p, MB_CUR_MAX, &mb_st))) { | |
| if(*p == '\\') *out++ = '\\'; | |
| for(i = 0; i < used; i++) *out++ = *p++; | |
| } | |
| } else | |
| for (; *p; p++) | |
| if (*p == '\\') {*out++ = *p; *out++ = *p;} else *out++ = *p; | |
| *out = '\0'; | |
| } | |
| void Rconsolecmd(char *cmd) | |
| { | |
| consolecmd(RConsole, cmd); | |
| } | |
| static void closeconsole(control m) | |
| { | |
| consolecmd(RConsole, "q()"); | |
| // R_CleanUp(SA_DEFAULT, 0, 1); | |
| } | |
| static void quote_fn(wchar_t *fn, char *s) | |
| { | |
| char *p = s; | |
| wchar_t *w; | |
| int used; | |
| for (w = fn; *w; w++) { | |
| if(*w == L'\\') { | |
| *p++ = '\\'; | |
| *p++ = '\\'; | |
| } else { | |
| used = wctomb(p, *w); | |
| if(used > 0) p += used; | |
| else { | |
| sprintf(p, "\\u%04x", (unsigned int) *w); | |
| p += 6; | |
| } | |
| } | |
| } | |
| *p = '\0'; | |
| } | |
| static void menusource(control m) | |
| { | |
| wchar_t *fn; | |
| char local[MAX_PATH]; | |
| if (!ConsoleAcceptCmd) return; | |
| setuserfilterW(L"R files (*.R)\0*.R\0S files (*.q, *.ssc, *.S)\0*.q;*.ssc;*.S\0All files (*.*)\0*.*\0\0"); | |
| fn = askfilenameW(G_("Select file to source"), ""); | |
| if (fn) { | |
| quote_fn(fn, local); | |
| snprintf(cmd, 1024, "source(\"%s\")", local); | |
| consolecmd(RConsole, cmd); | |
| } else show(RConsole); | |
| } | |
| static void menudisplay(control m) | |
| { | |
| if (!ConsoleAcceptCmd) return; | |
| consolecmd(RConsole,"local({fn<-choose.files(filters=Filters[c('R','txt','All'),],index=4)\nfile.show(fn,header=fn,title='')})"); | |
| } | |
| static void menuloadimage(control m) | |
| { | |
| wchar_t *fn; | |
| char s[MAX_PATH]; | |
| if (!ConsoleAcceptCmd) return; | |
| setuserfilterW(L"R images (*.RData)\0*.RData\0R images - old extension (*.rda)\0*.rda\0All files (*.*)\0*.*\0\0"); | |
| fn = askfilenameW(G_("Select image to load"), ""); | |
| if (fn) { | |
| quote_fn(fn, s); | |
| snprintf(cmd, 1024, "load(\"%s\")", s); | |
| consolecmd(RConsole, cmd); | |
| } else show(RConsole); | |
| } | |
| static void menusaveimage(control m) | |
| { | |
| wchar_t *fn; | |
| char s[MAX_PATH]; | |
| if (!ConsoleAcceptCmd) return; | |
| setuserfilterW(L"R images (*.RData)\0*.RData\0All files (*.*)\0*.*\0\0"); | |
| fn = askfilesaveW(G_("Save image in"), ".RData"); | |
| if (fn) { | |
| quote_fn(fn, s); | |
| if (!strcmp(&s[strlen(s) - 2], ".*")) s[strlen(s) - 2] = '\0'; | |
| snprintf(cmd, 1024, "save.image(\"%s\")", s); | |
| consolecmd(RConsole, cmd); | |
| } else show(RConsole); | |
| } | |
| static void menuloadhistory(control m) | |
| { | |
| char *fn; | |
| setuserfilter("All files (*.*)\0*.*\0\0"); | |
| fn = askfilename(G_("Load history from"), R_HistoryFile); | |
| if (fn) wgl_loadhistory(fn); | |
| } | |
| static void menusavehistory(control m) | |
| { | |
| char *s; | |
| setuserfilter("All files (*.*)\0*.*\0\0"); | |
| s = askfilesave(G_("Save history in"), R_HistoryFile); | |
| if (s) { | |
| R_setupHistory(); /* re-read the history size */ | |
| wgl_savehistory(s, R_HistorySize); | |
| } | |
| } | |
| static void menuchangedir(control m) | |
| { | |
| askchangedir(); | |
| } | |
| static void menuprint(control m) | |
| { | |
| consoleprint(RConsole); | |
| } | |
| static void menusavefile(control m) | |
| { | |
| consolesavefile(RConsole, 0); | |
| } | |
| static void menuexit(control m) | |
| { | |
| closeconsole(m); | |
| } | |
| static void menuselectall(control m) | |
| { | |
| consoleselectall(RConsole); | |
| /* show(RConsole); */ | |
| } | |
| static void menucopy(control m) | |
| { | |
| if (consolecancopy(RConsole)) | |
| consolecopy(RConsole); | |
| else | |
| askok(G_("No selection")); | |
| /* show(RConsole); */ | |
| } | |
| static void menupaste(control m) | |
| { | |
| if (consolecanpaste(RConsole)) | |
| consolepaste(RConsole); | |
| else | |
| askok(G_("No text available")); | |
| /* show(RConsole); */ | |
| } | |
| static void menupastecmds(control m) | |
| { | |
| if (consolecanpaste(RConsole)) | |
| consolepastecmds(RConsole); | |
| else | |
| askok(G_("No text available")); | |
| } | |
| static void menucopypaste(control m) | |
| { | |
| if (consolecancopy(RConsole)) { | |
| consolecopy(RConsole); | |
| consolepaste(RConsole); | |
| } else | |
| askok(G_("No selection")); | |
| /* show(RConsole); */ | |
| } | |
| /* button* versions force focus back to the console: needed for PR#3285 */ | |
| static void buttoncopy(control m) | |
| { | |
| menucopy(m); | |
| show(RConsole); | |
| } | |
| static void buttonpaste(control m) | |
| { | |
| menupaste(m); | |
| show(RConsole); | |
| } | |
| static void buttoncopypaste(control m) | |
| { | |
| menucopypaste(m); | |
| show(RConsole); | |
| } | |
| static void buttonkill(control m) | |
| { | |
| show(RConsole); | |
| UserBreak = TRUE; | |
| } | |
| void menuclear(control m) | |
| { | |
| consoleclear(RConsole); | |
| } | |
| static void menude(control m) | |
| { | |
| char *s; | |
| SEXP var; | |
| if (!ConsoleAcceptCmd) return; | |
| s = askstring(G_("Name of data frame or matrix"), ""); | |
| if(s) { | |
| var = findVar(install(s), R_GlobalEnv); | |
| if (var != R_UnboundValue) { | |
| snprintf(cmd, 1024,"fix(%s)", s); | |
| consolecmd(RConsole, cmd); | |
| } else { | |
| snprintf(cmd, 1024, G_("'%s' cannot be found"), s); | |
| askok(cmd); | |
| } | |
| } | |
| /* show(RConsole); */ | |
| } | |
| void menuconfig(control m) | |
| { | |
| Rgui_configure(); | |
| /* show(RConsole); */ | |
| } | |
| static void menutools(control m) | |
| { | |
| if(ischecked(mtools)) { | |
| toolbar_hide(); | |
| uncheck(mtools); | |
| } else { | |
| toolbar_show(); | |
| check(mtools); | |
| } | |
| } | |
| void showstatusbar() | |
| { | |
| if(ismdi() && !ischecked(mstatus)) { | |
| addstatusbar(); | |
| check(mstatus); | |
| } | |
| } | |
| static void menustatus(control m) | |
| { | |
| if(ischecked(mstatus)) { | |
| delstatusbar(); | |
| uncheck(mstatus); | |
| } else { | |
| addstatusbar(); | |
| check(mstatus); | |
| } | |
| } | |
| static void menulazy(control m) | |
| { | |
| consoletogglelazy(RConsole); | |
| /* show(RConsole); */ | |
| } | |
| extern void set_completion_available(int x); | |
| static int filename_completion_on = 1; | |
| static int check_file_completion(void) | |
| { | |
| /* ought really to ask utils */ | |
| return filename_completion_on; | |
| } | |
| static void menucomplete(control m) | |
| { | |
| if(ischecked(mcomplete)) { | |
| set_completion_available(0); | |
| uncheck(mcomplete); | |
| uncheck(mfncomplete); | |
| } else { | |
| set_completion_available(-1); | |
| check(mcomplete); | |
| if(check_file_completion()) check(mfncomplete); | |
| else uncheck(mfncomplete); | |
| } | |
| } | |
| static void menufncomplete(control m) | |
| { | |
| char cmd[200], *c0; | |
| if(ischecked(mfncomplete)) { | |
| c0 = "FALSE"; | |
| uncheck(mfncomplete); | |
| filename_completion_on = 0; | |
| } else { | |
| c0 = "TRUE"; | |
| check(mfncomplete); | |
| filename_completion_on = 1; | |
| } | |
| snprintf(cmd, 200, "utils::rc.settings(files=%s)", c0); | |
| consolecmd(RConsole, cmd); | |
| } | |
| static void menuconsolestayontop(control m) | |
| { | |
| BringToTop(RConsole, 2); | |
| } | |
| static void menukill(control m) | |
| { | |
| UserBreak = TRUE; | |
| } | |
| static void menukillall(control m) | |
| { | |
| consolenewline(RConsole); | |
| Rf_jump_to_toplevel(); | |
| } | |
| static Rboolean isdebuggerpresent(void) | |
| { | |
| typedef BOOL (*R_CheckDebugger)(void); | |
| R_CheckDebugger entry; | |
| /* XP or later */ | |
| entry = | |
| (R_CheckDebugger) GetProcAddress((HMODULE)GetModuleHandle("KERNEL32"), | |
| "IsDebuggerPresent"); | |
| if (entry == NULL) return(FALSE); | |
| else return (Rboolean) entry(); | |
| } | |
| void breaktodebugger(void) | |
| { | |
| asm("int $3"); | |
| } | |
| static void menudebug(control m) | |
| { | |
| breaktodebugger(); | |
| } | |
| static void menuls(control m) | |
| { | |
| if (!ConsoleAcceptCmd) return; | |
| consolecmd(RConsole,"ls()"); | |
| /* show(RConsole); */ | |
| } | |
| static void menurm(control m) | |
| { | |
| if (!ConsoleAcceptCmd) return; | |
| if (askyesno(G_("Are you sure?")) == YES) | |
| consolecmd(RConsole, "rm(list=ls(all=TRUE))"); | |
| else show(RConsole); | |
| } | |
| static void menusearch(control m) | |
| { | |
| if (!ConsoleAcceptCmd) return; | |
| consolecmd(RConsole, "search()"); | |
| /* show(RConsole); */ | |
| } | |
| static void menupkgload(control m) | |
| { | |
| if (!ConsoleAcceptCmd) return; | |
| consolecmd(RConsole, | |
| "local({pkg <- select.list(sort(.packages(all.available = TRUE)),graphics=TRUE)\nif(nchar(pkg)) library(pkg, character.only=TRUE)})"); | |
| /* show(RConsole); */ | |
| } | |
| static void menupkgupdate(control m) | |
| { | |
| if (!ConsoleAcceptCmd) return; | |
| consolecmd(RConsole, "update.packages(ask='graphics',checkBuilt=TRUE)"); | |
| /* show(RConsole); */ | |
| } | |
| static void menupkgcranmirror(control m) | |
| { | |
| if (!ConsoleAcceptCmd) return; | |
| consolecmd(RConsole, "chooseCRANmirror()"); | |
| } | |
| static void menupkgrepos(control m) | |
| { | |
| if (!ConsoleAcceptCmd) return; | |
| consolecmd(RConsole, "setRepositories()"); | |
| } | |
| static void menupkginstallpkgs(control m) | |
| { | |
| if (!ConsoleAcceptCmd) return; | |
| consolecmd(RConsole, "utils:::menuInstallPkgs()"); | |
| /* show(RConsole); */ | |
| } | |
| static void menupkginstalllocal(control m) | |
| { | |
| if (!ConsoleAcceptCmd) return; | |
| consolecmd(RConsole, "utils:::menuInstallLocal()"); | |
| } | |
| static void menucascade(control m) | |
| { | |
| if (!ConsoleAcceptCmd) return; | |
| consolecmd(RConsole, "utils::arrangeWindows(action='cascade')"); | |
| } | |
| static void menutilehoriz(control m) | |
| { | |
| if (!ConsoleAcceptCmd) return; | |
| consolecmd(RConsole, "utils::arrangeWindows(action='horizontal')"); | |
| } | |
| static void menutilevert(control m) | |
| { | |
| if (!ConsoleAcceptCmd) return; | |
| consolecmd(RConsole, "utils::arrangeWindows(action='vertical')"); | |
| } | |
| static void menuminimizegroup(control m) | |
| { | |
| if (!ConsoleAcceptCmd) return; | |
| consolecmd(RConsole, "utils::arrangeWindows(action='minimize')"); | |
| } | |
| static void menurestoregroup(control m) | |
| { | |
| if (!ConsoleAcceptCmd) return; | |
| consolecmd(RConsole, "utils::arrangeWindows(action='restore')"); | |
| } | |
| static void menuconsolehelp(control m) | |
| { | |
| consolehelp(); | |
| /* show(RConsole); */ | |
| } | |
| static void menuhelp(control m) | |
| { | |
| char *s; | |
| static char olds[256] = ""; | |
| if (!ConsoleAcceptCmd) return; | |
| s = askstring(G_("Help on"), olds); | |
| /* show(RConsole); */ | |
| if (s) { | |
| snprintf(cmd, 1024, "help(\"%s\")", s); | |
| if (strlen(s) > 255) s[255] = '\0'; | |
| strcpy(olds, s); | |
| consolecmd(RConsole, cmd); | |
| } else show(RConsole); | |
| } | |
| static void menumainman(control m) | |
| { | |
| internal_shellexec("doc\\manual\\R-intro.pdf"); | |
| } | |
| static void menumainref(control m) | |
| { | |
| internal_shellexec("doc\\manual\\fullrefman.pdf"); | |
| } | |
| static void menumaindata(control m) | |
| { | |
| internal_shellexec("doc\\manual\\R-data.pdf"); | |
| } | |
| static void menumainext(control m) | |
| { | |
| internal_shellexec("doc\\manual\\R-exts.pdf"); | |
| } | |
| static void menumainint(control m) | |
| { | |
| internal_shellexec("doc\\manual\\R-ints.pdf"); | |
| } | |
| static void menumainlang(control m) | |
| { | |
| internal_shellexec("doc\\manual\\R-lang.pdf"); | |
| } | |
| static void menumainadmin(control m) | |
| { | |
| internal_shellexec("doc\\manual\\R-admin.pdf"); | |
| } | |
| static void menumainSweave(control m) | |
| { | |
| internal_shellexec("library\\utils\\doc\\Sweave.pdf"); | |
| } | |
| static void menuhelpsearch(control m) | |
| { | |
| char *s; | |
| static char olds[256] = ""; | |
| if (!ConsoleAcceptCmd) return; | |
| s = askstring(G_("Search help"), olds); | |
| if (s && strlen(s)) { | |
| snprintf(cmd, 1024, "help.search(\"%s\")", s); | |
| if (strlen(s) > 255) s[255] = '\0'; | |
| strcpy(olds, s); | |
| consolecmd(RConsole, cmd); | |
| } else show(RConsole); | |
| } | |
| static void menusearchRsite(control m) | |
| { | |
| char *s; | |
| static char olds[256] = ""; | |
| if (!ConsoleAcceptCmd) return; | |
| s = askstring(G_("Search for words in help list archives and documentation"), olds); | |
| if (s && strlen(s)) { | |
| snprintf(cmd, 1024, "RSiteSearch(\"%s\")", s); | |
| if (strlen(s) > 255) s[255] = '\0'; | |
| strcpy(olds, s); | |
| consolecmd(RConsole, cmd); | |
| } else show(RConsole); | |
| } | |
| static void menuapropos(control m) | |
| { | |
| char *s; | |
| static char olds[256] = ""; | |
| if (!ConsoleAcceptCmd) return; | |
| s = askstring(G_("Apropos"), olds); | |
| /* show(RConsole); */ | |
| if (s) { | |
| snprintf(cmd, 1024, "apropos(\"%s\")", s); | |
| if (strlen(s) > 255) s[255] = '\0'; | |
| strcpy(olds, s); | |
| consolecmd(RConsole, cmd); | |
| } else show(RConsole); | |
| } | |
| static void menuhelpstart(control m) | |
| { | |
| if (!ConsoleAcceptCmd) return; | |
| consolecmd(RConsole, "help.start()"); | |
| /* show(RConsole); | |
| internal_shellexec("doc\\html\\index.html"); */ | |
| } | |
| static void menuFAQ(control m) | |
| { | |
| internal_shellexec("doc\\manual\\R-FAQ.html"); | |
| } | |
| static void menurwFAQ(control m) | |
| { | |
| internal_shellexec("doc\\html\\rw-FAQ.html"); | |
| } | |
| static void menuabout(control m) | |
| { | |
| char s[256], s2[256]; | |
| PrintVersionString(s2, 256); | |
| snprintf(s, 256, "%s\n%s %s %s", | |
| s2, | |
| "Copyright (C)", R_YEAR, | |
| "The R Foundation for Statistical Computing"); | |
| askok(s); | |
| /* show(RConsole); */ | |
| } | |
| static void menuRhome(control m) | |
| { | |
| ShellExecute(NULL, "open", "http://www.r-project.org", NULL, NULL, SW_SHOW); | |
| } | |
| static void menuCRAN(control m) | |
| { | |
| if (!ConsoleAcceptCmd) return; | |
| consolecmd(RConsole, "utils:::menuShowCRAN()"); | |
| } | |
| /* some menu commands can be issued only if R is waiting for input */ | |
| void helpmenuact(HelpMenuItems hmenu) | |
| { | |
| if (ConsoleAcceptCmd) { | |
| enable(hmenu->mhelp); | |
| enable(hmenu->mhelpstart); | |
| enable(hmenu->mhelpsearch); | |
| enable(hmenu->msearchRsite); | |
| enable(hmenu->mapropos); | |
| enable(hmenu->mCRAN); | |
| } else { | |
| disable(hmenu->mhelp); | |
| disable(hmenu->mhelpstart); | |
| disable(hmenu->mhelpsearch); | |
| disable(hmenu->msearchRsite); | |
| disable(hmenu->mapropos); | |
| disable(hmenu->mCRAN); | |
| } | |
| } | |
| void pkgmenuact(PkgMenuItems pmenu) | |
| { | |
| if (ConsoleAcceptCmd) { | |
| enable(pmenu->mpkgl); | |
| enable(pmenu->mpkgm); | |
| enable(pmenu->mpkgi); | |
| enable(pmenu->mpkgil); | |
| enable(pmenu->mpkgu); | |
| enable(pmenu->mrepos); | |
| } else { | |
| disable(pmenu->mpkgl); | |
| disable(pmenu->mpkgm); | |
| disable(pmenu->mpkgi); | |
| disable(pmenu->mpkgil); | |
| disable(pmenu->mpkgu); | |
| disable(pmenu->mrepos); | |
| } | |
| } | |
| static void menuact(control m) | |
| { | |
| if (consolegetlazy(RConsole)) check(mlazy); else uncheck(mlazy); | |
| /* display needs pager set */ | |
| if (R_is_running) enable(mdisplay); else disable(mdisplay); | |
| if (ConsoleAcceptCmd) { | |
| enable(msource); | |
| enable(mload); | |
| enable(msave); | |
| enable(mls); | |
| enable(mrm); | |
| enable(msearch); | |
| } else { | |
| disable(msource); | |
| disable(mload); | |
| disable(msave); | |
| disable(mls); | |
| disable(mrm); | |
| disable(msearch); | |
| } | |
| if (consolecancopy(RConsole)) { | |
| enable(mcopy); | |
| enable(mcopypaste); | |
| } else { | |
| disable(mcopy); | |
| disable(mcopypaste); | |
| } | |
| if (consolecanpaste(RConsole)) { | |
| enable(mpaste); | |
| enable(mpastecmds); | |
| } | |
| else { | |
| disable(mpaste); | |
| disable(mpastecmds); | |
| } | |
| helpmenuact(hmenu); | |
| pkgmenuact(pmenu); | |
| draw(RMenuBar); | |
| } | |
| #define MCHECK(m) {if(!(m)) {del(RConsole); return 0;}} | |
| void readconsolecfg() | |
| { | |
| char fn[128]; | |
| int sty = Plain; | |
| char optf[PATH_MAX+1]; | |
| struct structGUI gui; | |
| getDefaults(&gui); | |
| if (R_LoadRconsole) { | |
| snprintf(optf, PATH_MAX+1, "%s/Rconsole", getenv("R_USER")); | |
| if (!loadRconsole(&gui, optf)) { | |
| snprintf(optf, PATH_MAX+1, "%s/etc/Rconsole", getenv("R_HOME")); | |
| if (!loadRconsole(&gui, optf)) { | |
| app_cleanup(); | |
| RConsole = NULL; | |
| exit(10); | |
| } | |
| } | |
| } | |
| if (gui.tt_font) { | |
| strcpy(fn, "TT "); | |
| strcpy(fn+3, gui.font); | |
| } else strcpy(fn, gui.font); | |
| MDIsize = gui.MDIsize; | |
| if (gui.MDI) RguiMDI |= RW_MDI; | |
| else RguiMDI &= ~RW_MDI; | |
| if (MDIset == 1) RguiMDI |= RW_MDI; | |
| if (MDIset == -1) RguiMDI &= ~RW_MDI; | |
| if (gui.toolbar) RguiMDI |= RW_TOOLBAR; | |
| else RguiMDI &= ~RW_TOOLBAR; | |
| if (gui.statusbar) RguiMDI |= RW_STATUSBAR; | |
| else RguiMDI &= ~RW_STATUSBAR; | |
| if (!strcmp(gui.style, "normal")) sty = Plain; | |
| if (!strcmp(gui.style, "bold")) sty = Bold; | |
| if (!strcmp(gui.style, "italic")) sty = Italic; | |
| Rwin_graphicsx = gui.grx; | |
| Rwin_graphicsy = gui.gry; | |
| if(strlen(gui.language)) { | |
| char *buf = malloc(50); | |
| snprintf(buf, 50, "LANGUAGE=%s", gui.language); | |
| putenv(buf); | |
| } | |
| setconsoleoptions(fn, sty, gui.pointsize, gui.crows, gui.ccols, | |
| gui.cx, gui.cy, | |
| gui.guiColors, | |
| gui.prows, gui.pcols, gui.pagerMultiple, gui.setWidthOnResize, | |
| gui.cbb, gui.cbl, gui.buffered, gui.cursor_blink); | |
| } | |
| static void dropconsole(control m, char *fn) | |
| { | |
| char *p, local[MAX_PATH]; | |
| p = Rf_strrchr(fn, '.'); | |
| if(p) { | |
| /* OK even in MBCS */ | |
| if(stricmp(p+1, "R") == 0) { | |
| if(ConsoleAcceptCmd) { | |
| double_backslashes(fn, local); | |
| snprintf(cmd, 1024, "source(\"%s\")", local); | |
| consolecmd(RConsole, cmd); | |
| } | |
| /* OK even in MBCS */ | |
| } else if(stricmp(p+1, "RData") == 0 || stricmp(p+1, "rda")) { | |
| if(ConsoleAcceptCmd) { | |
| double_backslashes(fn, local); | |
| snprintf(cmd, 1024, "load(\"%s\")", local); | |
| consolecmd(RConsole, cmd); | |
| } | |
| } | |
| return; | |
| } | |
| askok(G_("Can only drag-and-drop .R, .RData and .rda files")); | |
| } | |
| static MenuItem ConsolePopup[] = { /* Numbers used below */ | |
| {GN_("Copy"), menucopy, 'C', 0}, /* 0 */ | |
| {GN_("Paste"), menupaste, 'V', 0}, /* 1 */ | |
| {GN_("Paste commands only"), menupastecmds, 0, 0}, /* 2 */ | |
| {GN_("Copy and paste"), menucopypaste, 'X', 0}, /* 3 */ | |
| {"-", 0, 0, 0}, | |
| {GN_("Clear window"), menuclear, 'L', 0}, /* 5 */ | |
| {"-", 0, 0, 0}, | |
| {GN_("Select all"), menuselectall, 0, 0}, /* 7 */ | |
| {"-", 0, 0}, | |
| {GN_("Buffered output"), menulazy, 'W', 0}, /* 9 */ | |
| {GN_("Stay on top"), menuconsolestayontop, 0, 0}, /* 10 */ | |
| LASTMENUITEM | |
| }; | |
| static void popupact(control m) | |
| { | |
| if (consolegetlazy(RConsole)) | |
| check(ConsolePopup[9].m); | |
| else | |
| uncheck(ConsolePopup[9].m); | |
| if (consolecancopy(RConsole)) { | |
| enable(ConsolePopup[0].m); | |
| enable(ConsolePopup[3].m); | |
| } else { | |
| disable(ConsolePopup[0].m); | |
| disable(ConsolePopup[3].m); | |
| } | |
| if (consolecanpaste(RConsole)) { | |
| enable(ConsolePopup[1].m); | |
| enable(ConsolePopup[2].m); | |
| } else { | |
| disable(ConsolePopup[1].m); | |
| disable(ConsolePopup[2].m); | |
| } | |
| if (ismdi()) | |
| disable(ConsolePopup[10].m); | |
| else { | |
| if (isTopmost(RConsole)) | |
| check(ConsolePopup[10].m); | |
| else | |
| uncheck(ConsolePopup[10].m); | |
| } | |
| } | |
| /* Package management menu is common to all R windows */ | |
| int RguiPackageMenu(PkgMenuItems pmenu) | |
| { | |
| MCHECK(newmenu(G_("Packages"))); | |
| MCHECK(pmenu->mpkgl = newmenuitem(G_("Load package..."), 0, menupkgload)); | |
| MCHECK(newmenuitem("-", 0, NULL)); | |
| MCHECK(pmenu->mpkgm = newmenuitem(G_("Set CRAN mirror..."), 0, | |
| menupkgcranmirror)); | |
| MCHECK(pmenu->mrepos = newmenuitem(G_("Select repositories..."), 0, | |
| menupkgrepos)); | |
| MCHECK(pmenu->mpkgi = newmenuitem(G_("Install package(s)..."), 0, | |
| menupkginstallpkgs)); | |
| MCHECK(pmenu->mpkgu = newmenuitem(G_("Update packages..."), 0, | |
| menupkgupdate)); | |
| MCHECK(newmenuitem("-", 0, NULL)); | |
| MCHECK(pmenu->mpkgil = newmenuitem(G_("Install package(s) from local files..."), | |
| 0, menupkginstalllocal)); | |
| return 0; | |
| } | |
| static void CheckForManuals(void) | |
| { | |
| lmanintro = check_doc_file("doc\\manual\\R-intro.pdf"); | |
| lmanref = check_doc_file("doc\\manual\\fullrefman.pdf"); | |
| lmandata = check_doc_file("doc\\manual\\R-data.pdf"); | |
| lmanlang = check_doc_file("doc\\manual\\R-lang.pdf"); | |
| lmanext = check_doc_file("doc\\manual\\R-exts.pdf"); | |
| lmanint = check_doc_file("doc\\manual\\R-ints.pdf"); | |
| lmanadmin = check_doc_file("doc\\manual\\R-admin.pdf"); | |
| lmanSweave = check_doc_file("library\\utils\\doc\\Sweave.pdf"); | |
| } | |
| /* Help functions common to all R windows. | |
| These should be appended to each context-specific help menu */ | |
| int RguiCommonHelp(menu m, HelpMenuItems hmenu) | |
| { | |
| addto(m); | |
| MCHECK(hmenu->mFAQ = newmenuitem(G_("FAQ on R"), 0, menuFAQ)); | |
| if (!check_doc_file("doc\\manual\\R-FAQ.html")) disable(hmenu->mFAQ); | |
| MCHECK(hmenu->mrwFAQ = newmenuitem(G_("FAQ on R for &Windows"), 0, menurwFAQ)); | |
| if (!check_doc_file("doc\\html\\rw-FAQ.html")) disable(hmenu->mrwFAQ); | |
| if (!lmanintro && !lmanref && !lmandata && !lmanlang && !lmanext | |
| && !lmanint && !lmanadmin && !lmanSweave) { | |
| MCHECK(hmenu->mman0 = newmenuitem(G_("Manuals (in PDF)"), 0, NULL)); | |
| disable(hmenu->mman0); | |
| } else { | |
| MCHECK(hmenu->mman = newsubmenu(m, G_("Manuals (in PDF)"))); | |
| MCHECK(hmenu->mmanintro = newmenuitem("An &Introduction to R", 0, | |
| menumainman)); | |
| if (!lmanintro) disable(hmenu->mmanintro); | |
| MCHECK(hmenu->mmanref = newmenuitem("R &Reference", 0, | |
| menumainref)); | |
| if (!lmanref) disable(hmenu->mmanref); | |
| MCHECK(hmenu->mmandata = newmenuitem("R Data Import/Export", 0, | |
| menumaindata)); | |
| if (!lmandata) disable(hmenu->mmandata); | |
| MCHECK(hmenu->mmanlang = newmenuitem("R Language Definition", 0, | |
| menumainlang)); | |
| if (!lmanlang) disable(hmenu->mmanlang); | |
| MCHECK(hmenu->mmanext = newmenuitem("Writing R Extensions", 0, | |
| menumainext)); | |
| if (!lmanext) disable(hmenu->mmanext); | |
| MCHECK(hmenu->mmanint = newmenuitem("R Internals", 0, | |
| menumainint)); | |
| if (!lmanint) disable(hmenu->mmanint); | |
| MCHECK(hmenu->mmanadmin = newmenuitem("R Installation and Administration", 0, | |
| menumainadmin)); | |
| if (!lmanadmin) disable(hmenu->mmanadmin); | |
| MCHECK(hmenu->mmanSweave = newmenuitem("Sweave User", 0, | |
| menumainSweave)); | |
| if (!lmanSweave) disable(hmenu->mmanSweave); | |
| } | |
| addto(m); | |
| MCHECK(newmenuitem("-", 0, NULL)); | |
| MCHECK(hmenu->mhelp = newmenuitem(G_("R functions (text)..."), 0, | |
| menuhelp)); | |
| MCHECK(hmenu->mhelpstart = newmenuitem(G_("Html help"), 0, menuhelpstart)); | |
| if (!check_doc_file("doc\\html\\index.html")) disable(hmenu->mhelpstart); | |
| MCHECK(hmenu->mhelpsearch = newmenuitem(G_("Search help..."), 0, | |
| menuhelpsearch)); | |
| MCHECK(hmenu->msearchRsite = newmenuitem("search.r-project.org ...", 0, | |
| menusearchRsite)); | |
| MCHECK(newmenuitem("-", 0, NULL)); | |
| MCHECK(hmenu->mapropos = newmenuitem(G_("Apropos..."), 0, menuapropos)); | |
| MCHECK(newmenuitem("-", 0, NULL)); | |
| MCHECK(newmenuitem(G_("R Project home page"), 0, menuRhome)); | |
| MCHECK(hmenu->mCRAN = newmenuitem(G_("CRAN home page"), 0, menuCRAN)); | |
| MCHECK(newmenuitem("-", 0, NULL)); | |
| MCHECK(newmenuitem(G_("About"), 0, menuabout)); | |
| return 0; | |
| } | |
| static int RguiWindowMenu() | |
| { | |
| if (ismdi()) | |
| newmdimenu(); | |
| else { | |
| MCHECK(newmenu(G_("Windows"))); | |
| MCHECK(newmenuitem(G_("Cascade"), 0, menucascade)); | |
| MCHECK(newmenuitem(G_("Tile &Horizontally"), 0, menutilehoriz)); | |
| MCHECK(newmenuitem(G_("Tile &Vertically"), 0, menutilevert)); | |
| MCHECK(newmenuitem(G_("Minimize group"), 0, menuminimizegroup)); | |
| MCHECK(newmenuitem(G_("Restore group"), 0, menurestoregroup)); | |
| } | |
| return 0; | |
| } | |
| #include <locale.h> | |
| int setupui(void) | |
| { | |
| char *p, *ctype, Rlocale[1000] = ""; /* Windows' locales can be very long */ | |
| initapp(0, 0); | |
| /* set locale before doing anything with menus */ | |
| setlocale(LC_CTYPE, ""); /* necessary in case next fails to set | |
| a valid locale */ | |
| if((p = getenv("LC_ALL"))) strncpy(Rlocale, p, sizeof(Rlocale)-1); | |
| if((p = getenv("LC_CTYPE"))) strncpy(Rlocale, p, sizeof(Rlocale)-1); | |
| if (strcmp(Rlocale, "C") == 0) strcpy(Rlocale, "en"); | |
| setlocale(LC_CTYPE, Rlocale); | |
| mbcslocale = MB_CUR_MAX > 1; | |
| ctype = setlocale(LC_CTYPE, NULL); | |
| p = strrchr(ctype, '.'); | |
| if(p && isdigit(p[1])) localeCP = atoi(p+1); else localeCP = 1252; | |
| readconsolecfg(); | |
| int flags = StandardWindow | Document | Menubar; | |
| if(mbcslocale) flags |= UseUnicode; | |
| if (RguiMDI & RW_MDI) { | |
| TRACERUI("Rgui"); | |
| RFrame = newwindow( | |
| #ifdef _WIN64 | |
| "RGui (64-bit)", | |
| #else | |
| "RGui (32-bit)", | |
| #endif | |
| MDIsize, | |
| StandardWindow | Menubar | Workspace); | |
| setclose(RFrame, closeconsole); | |
| show(RFrame); | |
| TRACERUI("Rgui done"); | |
| TRACERUI("Console"); | |
| if (!(RConsole = newconsole("R Console", flags ))) return 0; | |
| TRACERUI("Console done"); | |
| } else { | |
| TRACERUI("Console"); | |
| #ifdef _WIN64 | |
| if (!(RConsole = newconsole("R Console (64-bit)", flags ))) return 0; | |
| #else | |
| if (!(RConsole = newconsole("R Console (32-bit)", flags ))) return 0; | |
| #endif | |
| TRACERUI("Console done"); | |
| } | |
| if (ismdi()) { | |
| int btsize = 24; | |
| rect r = rect(2, 2, btsize, btsize); | |
| control tb, bt; | |
| MCHECK(tb = newtoolbar(btsize + 4)); | |
| addto(tb); | |
| MCHECK(bt = newtoolbutton(open_image, r, menueditoropen)); | |
| MCHECK(addtooltip(bt, G_("Open script"))); | |
| r.x += (btsize + 1) ; | |
| MCHECK(bt = newtoolbutton(open1_image, r, menuloadimage)); | |
| MCHECK(addtooltip(bt, G_("Load workspace"))); | |
| r.x += (btsize + 1) ; | |
| MCHECK(bt = newtoolbutton(save_image, r, menusaveimage)); | |
| MCHECK(addtooltip(bt, G_("Save workspace"))); | |
| r.x += (btsize + 6); | |
| MCHECK(bt = newtoolbutton(copy_image, r, buttoncopy)); | |
| MCHECK(addtooltip(bt, G_("Copy"))); | |
| r.x += (btsize + 1); | |
| MCHECK(bt = newtoolbutton(paste_image, r, buttonpaste)); | |
| MCHECK(addtooltip(bt, G_("Paste"))); | |
| r.x += (btsize + 1); | |
| MCHECK(bt = newtoolbutton(copypaste_image, r, buttoncopypaste)); | |
| MCHECK(addtooltip(bt, G_("Copy and paste"))); | |
| r.x += (btsize + 6); | |
| MCHECK(bt = newtoolbutton(stop_image, r, buttonkill)); | |
| MCHECK(addtooltip(bt, G_("Stop current computation"))); | |
| r.x += (btsize + 6) ; | |
| MCHECK(bt = newtoolbutton(print_image, r, menuprint)); | |
| MCHECK(addtooltip(bt, G_("Print"))); | |
| } | |
| if (ismdi() && (RguiMDI & RW_STATUSBAR)) { | |
| TRACERUI("status bar"); | |
| addstatusbar(); | |
| addto(RConsole); | |
| TRACERUI("status bar done"); | |
| } | |
| if (ismdi()) { | |
| char s[256]; | |
| PrintVersionString(s, 256); | |
| setstatus(s); | |
| } | |
| addto(RConsole); | |
| setclose(RConsole, closeconsole); | |
| setdrop(RConsole, dropconsole); | |
| MCHECK(RConsolePopup = gpopup(popupact, ConsolePopup)); | |
| MCHECK(RMenuBar = newmenubar(menuact)); | |
| MCHECK(newmenu(G_("File"))); | |
| MCHECK(msource = newmenuitem(G_("Source R code..."), 0, menusource)); | |
| MCHECK(newmenuitem(G_("New script"), 0, menueditornew)); | |
| MCHECK(newmenuitem(G_("Open script..."), 0, menueditoropen)); | |
| MCHECK(mdisplay = newmenuitem(G_("Display file(s)..."), 0, menudisplay)); | |
| MCHECK(newmenuitem("-", 0, NULL)); | |
| MCHECK(mload = newmenuitem(G_("Load Workspace..."), 0, menuloadimage)); | |
| MCHECK(msave = newmenuitem(G_("Save Workspace..."), 'S', menusaveimage)); | |
| MCHECK(newmenuitem("-", 0, NULL)); | |
| MCHECK(mloadhistory = newmenuitem(G_("Load History..."), 0, | |
| menuloadhistory)); | |
| MCHECK(msavehistory = newmenuitem(G_("Save History..."), 0, | |
| menusavehistory)); | |
| MCHECK(newmenuitem("-", 0, NULL)); | |
| MCHECK(newmenuitem(G_("Change dir..."), 0, menuchangedir)); | |
| MCHECK(newmenuitem("-", 0, NULL)); | |
| MCHECK(newmenuitem(G_("Print..."), 'P', menuprint)); | |
| MCHECK(newmenuitem(G_("Save to File..."), 0, menusavefile)); | |
| MCHECK(newmenuitem("-", 0, NULL)); | |
| MCHECK(newmenuitem(G_("Exit"), 0, menuexit)); | |
| MCHECK(newmenu(G_("Edit"))); | |
| MCHECK(mcopy = newmenuitem(G_("Copy"), 'C', menucopy)); | |
| MCHECK(mpaste = newmenuitem(G_("Paste"), 'V', menupaste)); | |
| MCHECK(mpastecmds = newmenuitem(G_("Paste commands only"), 0, | |
| menupastecmds)); | |
| MCHECK(mcopypaste = newmenuitem(G_("Copy and Paste"), 'X', menucopypaste)); | |
| MCHECK(newmenuitem(G_("Select all"), 0, menuselectall)); | |
| MCHECK(newmenuitem(G_("Clear console"), 'L', menuclear)); | |
| MCHECK(newmenuitem("-", 0, NULL)); | |
| MCHECK(mde = newmenuitem(G_("Data editor..."), 0, menude)); | |
| MCHECK(newmenuitem("-", 0, NULL)); | |
| MCHECK(mconfig = newmenuitem(G_("GUI preferences..."), 0, menuconfig)); | |
| if (ismdi()) { | |
| MCHECK(newmenu(G_("View"))); | |
| MCHECK(mtools = newmenuitem(G_("Toolbar"), 0, menutools)); | |
| MCHECK(mstatus = newmenuitem(G_("Statusbar"), 0, menustatus)); | |
| if(RguiMDI & RW_TOOLBAR) check(mtools); | |
| if(RguiMDI & RW_STATUSBAR) check(mstatus); | |
| } | |
| MCHECK(newmenu(G_("Misc"))); | |
| MCHECK(newmenuitem(G_("Stop current computation \tESC"), 0, | |
| menukill)); | |
| MCHECK(newmenuitem(G_("Stop all computations"), 0, menukillall)); | |
| if (DebugMenuitem || isdebuggerpresent()) | |
| MCHECK(newmenuitem(G_("Break to debugger"), 0, menudebug)); | |
| MCHECK(newmenuitem("-", 0, NULL)); | |
| MCHECK(mlazy = newmenuitem(G_("Buffered output"), 'W', menulazy)); | |
| MCHECK(mcomplete = newmenuitem(G_("Word completion"), 0, menucomplete)); | |
| check(mcomplete); | |
| MCHECK(mfncomplete = newmenuitem(G_("Filename completion"), 0, | |
| menufncomplete)); | |
| if(check_file_completion()) | |
| check(mfncomplete); | |
| else | |
| uncheck(mfncomplete); | |
| MCHECK(newmenuitem("-", 0, NULL)); | |
| MCHECK(mls = newmenuitem(G_("List objects"), 0, menuls)); | |
| MCHECK(mrm = newmenuitem(G_("Remove all objects"), 0, menurm)); | |
| MCHECK(msearch = newmenuitem(G_("List search &path"), 0, menusearch)); | |
| pmenu = (PkgMenuItems) malloc(sizeof(struct structPkgMenuItems)); | |
| RguiPackageMenu(pmenu); | |
| RguiWindowMenu(); | |
| MCHECK(m = newmenu(G_("Help"))); | |
| MCHECK(newmenuitem(G_("Console"), 0, menuconsolehelp)); | |
| MCHECK(newmenuitem("-", 0, NULL)); | |
| CheckForManuals(); | |
| hmenu = (HelpMenuItems) malloc(sizeof(struct structHelpMenuItems)); | |
| RguiCommonHelp(m, hmenu); | |
| consolesetbrk(RConsole, menukill, ESC, 0); | |
| wgl_hist_init(R_HistorySize, 0); | |
| if (R_RestoreHistory) wgl_loadhistory(R_HistoryFile); | |
| if (ismdi() && !(RguiMDI & RW_TOOLBAR)) toolbar_hide(); | |
| show(RConsole); | |
| return 1; | |
| } | |
| static RECT RframeRect; /* for use by pagercreate */ | |
| RECT *RgetMDIsize(void) | |
| { | |
| GetClientRect(hwndClient, &RframeRect); | |
| return &RframeRect; | |
| } | |
| int RgetMDIwidth(void) | |
| { | |
| return RgetMDIsize()->right; | |
| } | |
| int RgetMDIheight(void) | |
| { | |
| return RgetMDIsize()->bottom; | |
| } | |
| static menu *usermenus; | |
| static char **usermenunames; | |
| static Uitem *umitems; | |
| static int nmenus=0, nitems=0, alloc_menus=-1, alloc_items=-1; | |
| static void menuuser(control m) | |
| { | |
| int item = m->max; | |
| char *p = umitems[item]->action; | |
| if (strcmp(p, "none") == 0) return; | |
| Rconsolecmd(p); | |
| } | |
| int numwinmenus(void) { | |
| return(nmenus); | |
| } | |
| char *getusermenuname(int pos) { | |
| return(usermenunames[pos]); | |
| } | |
| menuItems *wingetmenuitems(const char *mname, char *errmsg) { | |
| menuItems *items; | |
| char mitem[1002], *p, *q, *r; | |
| int i,j = 0; | |
| if (strlen(mname) > 1000) { | |
| strcpy(errmsg, G_("'mname' is limited to 1000 bytes")); | |
| return NULL; | |
| } | |
| q = (char *)malloc(1000 * sizeof(char)); | |
| r = (char *)malloc(1000 * sizeof(char)); | |
| items = (menuItems *)malloc(sizeof(menuItems)); | |
| if(nitems > 0) | |
| items->mItems = (Uitem *)malloc(alloc_items * sizeof(Uitem)); | |
| strcpy(mitem, mname); strcat(mitem, "/"); | |
| for (i = 0; i < nitems; i++) { | |
| p = strstr(umitems[i]->name, mitem); | |
| if (p == NULL) | |
| continue; | |
| /* the 'mitem' pattern might be showing up */ | |
| /* as a substring in another valid name. Make sure */ | |
| /* this isn't the case */ | |
| if (strlen(p) != strlen(umitems[i]->name)) | |
| continue; | |
| strcpy(q, p+strlen(mitem)); | |
| /* Due to the way menu items are stored, it can't be */ | |
| /* determined if this is say item 'foo' from menu 'Blah/bar' */ | |
| /* or item 'bar/foo' from menu 'Blah'. Check this manually */ | |
| /* by adding the item label to the menu we're looking for. */ | |
| snprintf(r, 1000, "%s%s", mitem, umitems[i]->m->text); | |
| if (strcmp(r, p) != 0) | |
| continue; | |
| items->mItems[j] = (Uitem)malloc(sizeof(uitem)); | |
| items->mItems[j]->name = (char *)malloc((strlen(q) + 1) * sizeof(char)); | |
| items->mItems[j]->action = (char *)malloc((strlen(umitems[i]->action) + 1) * sizeof(char)); | |
| strcpy(items->mItems[j]->name, q); | |
| strcpy(items->mItems[j]->action, umitems[i]->action); | |
| j++; | |
| } | |
| free(q); | |
| free(r); | |
| items->numItems = j; | |
| if (j == 0) sprintf(errmsg, G_("menu %s does not exist"), mname); | |
| return(items); | |
| } | |
| void freemenuitems(menuItems *items) { | |
| int j; | |
| for (j = 0; j < items->numItems; j++) { | |
| free(items->mItems[j]->name); | |
| free(items->mItems[j]->action); | |
| free(items->mItems[j]); | |
| } | |
| free(items->mItems); | |
| free(items); | |
| } | |
| static menu getMenu(const char * name) | |
| { | |
| int i; | |
| for (i = 0; i < nmenus; i++) | |
| if (strcmp(name, usermenunames[i]) == 0) return(usermenus[i]); | |
| if (strcmp(name, "$ConsolePopup") == 0) | |
| return(RConsolePopup); | |
| else if (strcmp(name, "$ConsoleMain") == 0) | |
| return(RMenuBar); | |
| else if (strncmp(name, "$Graph", 6) == 0) | |
| return(getGraphMenu(name)); | |
| else return(NULL); | |
| } | |
| int winaddmenu(const char *name, char *errmsg) | |
| { | |
| const char *submenu = name; | |
| char *p, start[501]; | |
| menu parent; | |
| if (getMenu(name)) | |
| return 0; /* Don't add repeats */ | |
| if (nmenus >= alloc_menus) { | |
| if(alloc_menus <= 0) { | |
| alloc_menus = 10; | |
| usermenus = (menu *) malloc(sizeof(menu) * alloc_menus); | |
| usermenunames = (char **) malloc(sizeof(char *) * alloc_menus); | |
| } else { | |
| alloc_menus += 10; | |
| usermenus = (menu *) realloc(usermenus, sizeof(menu) * alloc_menus); | |
| usermenunames = (char **) realloc(usermenunames, | |
| sizeof(char *) * alloc_menus); | |
| } | |
| } | |
| if (strlen(name) > 500) { | |
| strcpy(errmsg, G_("'menu' is limited to 500 bytes")); | |
| return 5; | |
| } | |
| p = Rf_strrchr(name, '/'); | |
| if (p) { | |
| submenu = p + 1; | |
| strcpy(start, name); | |
| *Rf_strrchr(start, '/') = '\0'; | |
| parent = getMenu(start); | |
| if (!parent) { | |
| strcpy(errmsg, G_("base menu does not exist")); | |
| return 3; | |
| } | |
| m = newsubmenu(parent, submenu); | |
| } else { | |
| addto(RMenuBar); | |
| m = newmenu(submenu); | |
| } | |
| if (m) { | |
| usermenus[nmenus] = m; | |
| usermenunames[nmenus] = strdup(name); | |
| nmenus++; | |
| show(RConsole); | |
| return 0; | |
| } else { | |
| strcpy(errmsg, G_("failed to allocate menu")); | |
| return 1; | |
| } | |
| } | |
| int winaddmenuitem(const char * item, const char * menu, | |
| const char * action, char *errmsg) | |
| { | |
| int i, im; | |
| menuitem m; | |
| char mitem[1002], *p; | |
| /* if (nitems > 499) { | |
| strcpy(errmsg, G_("too many menu items have been created")); | |
| return 2; | |
| } */ | |
| if (strlen(item) + strlen(menu) > 1000) { | |
| strcpy(errmsg, G_("menu + item is limited to 1000 bytes")); | |
| return 5; | |
| } | |
| for (im = 0; im < nmenus; im++) { | |
| if (strcmp(menu, usermenunames[im]) == 0) break; | |
| } | |
| if (im == nmenus) { | |
| strcpy(errmsg, G_("menu does not exist")); | |
| return 3; | |
| } | |
| strcpy(mitem, menu); strcat(mitem, "/"); strcat(mitem, item); | |
| for (i = 0; i < nitems; i++) { | |
| if (strcmp(mitem, umitems[i]->name) == 0) break; | |
| } | |
| if (i < nitems) { /* existing item */ | |
| if (strcmp(action, "enable") == 0) { | |
| enable(umitems[i]->m); | |
| } else if (strcmp(action, "disable") == 0) { | |
| disable(umitems[i]->m); | |
| } else { | |
| p = umitems[i]->action; | |
| p = realloc(p, strlen(action) + 1); | |
| if(!p) { | |
| strcpy(errmsg, G_("failed to allocate char storage")); | |
| return 4; | |
| } | |
| strcpy(p, action); | |
| } | |
| } else { | |
| addto(usermenus[im]); | |
| m = newmenuitem(item, 0, menuuser); | |
| if (m) { | |
| if(alloc_items <= nitems) { | |
| if(alloc_items <= 0) { | |
| alloc_items = 100; | |
| umitems = (Uitem *) malloc(sizeof(Uitem) * alloc_items); | |
| } else { | |
| alloc_items += 100; | |
| umitems = (Uitem *) realloc(umitems, | |
| sizeof(Uitem) * alloc_items); | |
| } | |
| } | |
| umitems[nitems] = (Uitem) malloc(sizeof(uitem)); | |
| umitems[nitems]->m = m; | |
| umitems[nitems]->name = p = (char *) malloc(strlen(mitem) + 1); | |
| if(!p) { | |
| strcpy(errmsg, G_("failed to allocate char storage")); | |
| return 4; | |
| } | |
| strcpy(p, mitem); | |
| if(!p) { | |
| strcpy(errmsg, G_("failed to allocate char storage")); | |
| return 4; | |
| } | |
| umitems[nitems]->action = p = (char *) malloc(strlen(action) + 1); | |
| strcpy(p, action); | |
| m->max = nitems; | |
| nitems++; | |
| } else { | |
| strcpy(errmsg, G_("failed to allocate menuitem")); | |
| return 1; | |
| } | |
| } | |
| show(RConsole); | |
| return 0; | |
| } | |
| int windelmenu(const char * menu, char *errmsg) | |
| { | |
| int i, j, count = 0, len = strlen(menu); | |
| j = 0; | |
| for (i = 0; i < nmenus; i++) { | |
| if (strcmp(menu, usermenunames[i]) == 0 | |
| || (strncmp(menu, usermenunames[i], len) == 0 && | |
| usermenunames[i][len] == '/')) { | |
| remove_menu_item(usermenus[i]); | |
| count++; | |
| } else { | |
| if (j < i) { | |
| strcpy(usermenunames[j], usermenunames[i]); | |
| usermenus[j] = usermenus[i]; | |
| } | |
| j++; | |
| } | |
| } | |
| nmenus -= count; | |
| if (!count) { | |
| strcpy(errmsg, G_("menu does not exist")); | |
| return 3; | |
| } | |
| /* Delete any menu items in this menu */ | |
| for (j = nitems - 1; j >= 0; j--) { | |
| if (strncmp(menu, umitems[j]->name, len) == 0 && | |
| umitems[j]->name[len] == '/') | |
| windelmenuitem(umitems[j]->name + len + 1, menu, errmsg); | |
| } | |
| show(RConsole); | |
| return 0; | |
| } | |
| void windelmenus(const char * prefix) | |
| { | |
| int i, len = strlen(prefix); | |
| for (i = nmenus-1; i >=0; i--) { | |
| if (strncmp(prefix, usermenunames[i], len) == 0) | |
| windelmenu(usermenunames[i], G_("menu not found")); | |
| } | |
| } | |
| int windelmenuitem(const char * item, const char * menu, char *errmsg) | |
| { | |
| int i; | |
| char mitem[1002]; | |
| if (strlen(item) + strlen(menu) > 1000) { | |
| strcpy(errmsg, G_("menu + item is limited to 1000 bytes")); | |
| return 5; | |
| } | |
| strcpy(mitem, menu); strcat(mitem, "/"); strcat(mitem, item); | |
| for (i = 0; i < nitems; i++) { | |
| if (strcmp(mitem, umitems[i]->name) == 0) break; | |
| } | |
| if (i == nitems) { | |
| strcpy(errmsg, G_("menu or item does not exist")); | |
| return 3; | |
| } | |
| delobj(umitems[i]->m); | |
| strcpy(umitems[i]->name, "invalid"); | |
| free(umitems[i]->action); | |
| show(RConsole); | |
| return 0; | |
| } |