| /* |
| * 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; |
| } |