/*ScianPreferences.c Eric Pepke June 15, 1991 Preferences in SciAn */ #include "Scian.h" #include "ScianTypes.h" #include "ScianMethods.h" #include "ScianLists.h" #include "ScianIDs.h" #include "ScianStyle.h" #include "ScianWindows.h" #include "ScianObjWindows.h" #include "ScianDialogs.h" #include "ScianControls.h" #include "ScianButtons.h" #include "ScianTextBoxes.h" #include "ScianErrors.h" #include "ScianPreferences.h" #include "ScianScripts.h" typedef union pv { char *string; /*String value*/ Bool truth; /*Expression true or false*/ long integer; /*Numeric value*/ } PrefValue; typedef struct { char *shortName; /*Short name of the preference*/ char *longName; /*Long name of the preference*/ int type; /*Type of the preference*/ char *helpString; /*String of the help*/ } PrefInfo; typedef struct { Bool exists; /*True iff the preference exists*/ Bool changed; /*True iff the preference has been changed*/ PrefValue value; /*Value of the preference*/ } PrefState; PrefInfo prefInfo[NPREFERENCES] = { {"DEFDIR", "Data File Directory", PT_STRING, "This controls the default directory that will be used when you choose NewFileWindow from the File menu. \ Edit the string in the text box to change it."}, {"ROTINERTIA", "Rotation Inertia", PT_YNBOOL, "This controls the inertia when you rotate objects within a space. \ If Yes is selected, the space will continue to rotate it when you give it a spin and release the mouse button while moving the mouse. \ You can stop the rotation by clicking in the space again."}, {"NEWWINPLACE", "New Window Placement", PT_AMBOOL, "This controls how new windows will be placed on the screen. If Automatic is \ selected, windows will be created with a fixed size and automatically staggered. \ If Manual is selected, you will need to drag out the outline of new windows \ before they appear on the screen."}, {"DRAWMOVING", "Interactive Drawing", PT_AFFINT, "This controls how visualization objects are drawn when you are interactively \ changing them. If Full Quality is selected, objects will always be drawn in full \ quality. If Faster is selected, objects will be drawn with only a skeleton while you are \ interactively moving them, which is much faster. This can provide better feedback \ on slower computers. If Automatic is selected, SciAn will automatically choose whether \ objects are to be drawn fully or faster depending on how much time they take to draw."}, {"STAGGERICONS", "Stagger Icons", PT_YNBOOL, "This controls whether icons will be staggered in icon corrals. If Yes is selected, \ the vertical position of the icons will be staggered so that long icon names have \ less chance of overlapping. If No is selected, icons will not be staggered."} , {"SCREENSAVE", "Screen Save", PT_RPINT, "This controls whether screen snapshots are saved as IRIS rgb files or as PostScript files. \ If PostScript is selected they will be saved as embedded PostScript files with a file extension \ of .eps. If IRIS RGB is selected, they will be saved as IRIS RGB files with a file \ extension of .rgb. Screen saving is done using the recorder drivers, and the \ parameters are set within the recorder driver control panels."}, {"IDLENAP", "Nap When Idle", PT_YNBOOL, "This controls whether SciAn naps when it is idle. When No is checked, SciAn will \ constantly run housekeeping functions. This will ensure that interaction is quick, but \ it may slow down other processes running on the computer. When Yes is checked, SciAn will \ nap for one-second intervals five seconds after the last window change. This will \ release time for use by other processes, but the first interaction when it is napping \ may take up to a second to respond."}, {"GARBAGECOLLECT", "Garbage Collection", PT_SFBOOL, "This controls whether garbage collection is absolutely safe or a little bit \ faster."} }; PrefState prefState[NPREFERENCES]; #define PREFCELLHEIGHT 40 /*Height of a cell in preferences*/ #define PREFNAMEWIDTH 200 /*Width of the name of a preference*/ #define PREFFIELDWIDTH 400 /*Width of a field of a preference*/ Bool PrefExists(whichPref) int whichPref; /*Returns true iff whichPref exists*/ { return prefState[whichPref] . exists; } char *GetPrefString(whichPref) int whichPref; /*Gets the string for preference whichPref*/ { if (prefInfo[whichPref] . type != PT_STRING) return 0; return prefState[whichPref] . value . string; } Bool GetPrefTruth(whichPref) int whichPref; /*Gets the truth for preference whichPref*/ { if (prefInfo[whichPref] . type != PT_YNBOOL && prefInfo[whichPref] . type != PT_AMBOOL && prefInfo[whichPref] . type != PT_SFBOOL) { return false; } return prefState[whichPref] . value . truth; } long GetPrefInteger(whichPref) int whichPref; /*Gets the integer for preference whichPref*/ { if (prefInfo[whichPref] . type != PT_AFFINT && prefInfo[whichPref] . type != PT_RPINT) { return false; } return prefState[whichPref] . value . integer; } static void MakePrefFromString(whichPref, string) int whichPref; char *string; /*Makes a preference whichPref from string*/ { prefState[whichPref] . exists = true; switch(prefInfo[whichPref] . type) { case PT_STRING: prefState[whichPref] . value . string = Alloc(strlen(string) + 1); strcpy(prefState[whichPref] . value . string, string); break; case PT_YNBOOL: if (strcmp2(string, "yes") == 0 || strcmp2(string, "true") == 0) { prefState[whichPref] . value . truth = true; } else { prefState[whichPref] . value . truth = false; } break; case PT_AMBOOL: if (strcmp2(string, "auto") == 0 || strcmp2(string, "automatic") == 0) { prefState[whichPref] . value . truth = true; } else { prefState[whichPref] . value . truth = false; } break; case PT_SFBOOL: if (strcmp2(string, "fast") == 0 || strcmp2(string, "reckless") == 0) { prefState[whichPref] . value . truth = true; } else { prefState[whichPref] . value . truth = false; } break; case PT_AFFINT: if (strcmp2(string, "auto") == 0 || strcmp2(string, "automatic") == 0) { prefState[whichPref] . value . integer = 2; } else if (strcmp2(string, "fast") == 0 || strcmp2(string, "faster") == 0) { prefState[whichPref] . value . integer = 1; } else { prefState[whichPref] . value . integer = 0; } break; case PT_RPINT: if (strcmp2(string, "post") == 0 || strcmp2(string, "postscript") == 0) { prefState[whichPref] . value . integer = 1; } else { prefState[whichPref] . value . integer = 0; } break; } } static ObjPtr ChangePrefString(object) ObjPtr object; /*Changed value for a text box object that controls a string preference*/ { ObjPtr var, value; int whichPref; var = GetIntVar("ChangePrefString", object, WHICHPREF); if (!var) { return ObjFalse; } whichPref = GetInt(var); value = GetValue(object); if (!value || !IsString(value)) { return ObjFalse; } if (prefState[whichPref] . value . string) { Free(prefState[whichPref] . value . string); } prefState[whichPref] . value . string = Alloc(strlen(GetString(value)) + 1); strcpy(prefState[whichPref] . value . string, GetString(value)); prefState[whichPref] . changed = true; prefState[whichPref] . exists = true; return ObjTrue; } static ObjPtr ChangePrefBoolean(object) ObjPtr object; /*Changed value for a text box object that controls a boolean preference*/ { ObjPtr var, value; int whichPref; var = GetIntVar("ChangePrefBoolean", object, WHICHPREF); if (!var) { return ObjFalse; } whichPref = GetInt(var); value = GetValue(object); if (!value || !IsInt(value)) { return ObjFalse; } prefState[whichPref] . value . truth = GetInt(value); prefState[whichPref] . changed = true; prefState[whichPref] . exists = true; return ObjTrue; } static ObjPtr ChangePrefInteger(object) ObjPtr object; /*Changed value for a text box object that controls an integer preference*/ { ObjPtr var, value; int whichPref; var = GetIntVar("ChangePrefInteger", object, WHICHPREF); if (!var) { return ObjFalse; } whichPref = GetInt(var); value = GetValue(object); if (!value || !IsInt(value)) { return ObjFalse; } prefState[whichPref] . value . integer = GetInt(value); prefState[whichPref] . changed = true; prefState[whichPref] . exists = true; return ObjTrue; } void DoShowPreferences() /*Shows the preferences dialog*/ { WinInfoPtr dialogExists, newDialog; ObjPtr whichDialog; int nPreferences; if (logging) { Log("show preferences\n"); InhibitLogging(true); } whichDialog = NewString("Preferences"); #ifdef RELEASE nPreferences = NRELEASEPREFERENCES; #else nPreferences = NPREFERENCES; #endif dialogExists = DialogExists(0, whichDialog); newDialog = GetDialog(0, whichDialog, "Preferences", PREFNAMEWIDTH + PREFFIELDWIDTH + 3 * MAJORBORDER, PREFCELLHEIGHT * nPreferences + MAJORBORDER * 2, PREFNAMEWIDTH + PREFFIELDWIDTH + 3 * MAJORBORDER, PREFCELLHEIGHT * nPreferences + MAJORBORDER * 2, WINUI + WINFIXEDSIZE); if (!dialogExists) { /*Fill the dialog with stuff*/ ObjPtr contents, panel, radio, button, textBox; int left, right, bottom, top; int k; /*Set the help string*/ SetVar((ObjPtr) newDialog, HELPSTRING, NewString("This window shows your personal preferences for using \ SciAn. The preferences are saved in a file named \".scianPrefs\" in your home \ directory when you exit SciAn normally. \ Use Help In Context and click on the various controls to find out what they do.")); contents = GetListVar("DoShowPreferences", (ObjPtr) newDialog, CONTENTS); if (!contents) return; panel = NewPanel(greyPanelClass, 0, PREFNAMEWIDTH + PREFFIELDWIDTH + 3 * MAJORBORDER, 0, PREFCELLHEIGHT * nPreferences + MAJORBORDER * 2 ); if (!panel) { return; } PrefixList(contents, panel); contents = GetListVar("DoShowPreferences", panel, CONTENTS); if (!contents) return; SetVar(panel, PARENT, (ObjPtr) newDialog); for (k = 0; k < nPreferences; ++k) { char objName[200], longName[300]; int median; /*Calculate a median line*/ median = MAJORBORDER + PREFCELLHEIGHT / 2 + PREFCELLHEIGHT * (nPreferences - 1 - k); /*Add a text box for this preference*/ sprintf(objName, "%s name", prefInfo[k] . shortName); if (prefInfo[k] . type == PT_YNBOOL) { sprintf(longName, "%s?", prefInfo[k] . longName); } else { sprintf(longName, "%s:", prefInfo[k] . longName); } textBox = NewTextBox(MAJORBORDER, MAJORBORDER + PREFNAMEWIDTH, median - TEXTBOXHEIGHT / 2, median + TEXTBOXHEIGHT / 2, 0, objName, longName); PrefixList(contents, textBox); SetVar(textBox, PARENT, panel); SetVar(textBox, HELPSTRING, NewString(prefInfo[k] . helpString)); SetTextFont(textBox, "Helvetica-Bold"); /*Add the field based on the type of preference*/ switch(prefInfo[k] . type) { case PT_STRING: sprintf(objName, "%s field", prefInfo[k] . shortName); textBox = NewTextBox( MAJORBORDER * 2 + PREFNAMEWIDTH, MAJORBORDER * 2 + PREFNAMEWIDTH + PREFFIELDWIDTH, median - PITBOXHEIGHT / 2, median + PITBOXHEIGHT / 2, EDITABLE + WITH_PIT + ONE_LINE, objName, prefState[k] . value . string); PrefixList(contents, textBox); SetVar(textBox, HELPSTRING, NewString(prefInfo[k] . helpString)); SetVar(textBox, PARENT, panel); SetVar(textBox, WHICHPREF, NewInt(k)); SetMethod(textBox, CHANGEDVALUE, ChangePrefString); break; case PT_YNBOOL: sprintf(objName, "%s radio", prefInfo[k] . shortName); radio = NewRadioButtonGroup(objName); PrefixList(contents, radio); SetVar(radio, PARENT, panel); SetVar(radio, HELPSTRING, NewString(prefInfo[k] . helpString)); button = NewRadioButton( MAJORBORDER * 2 + PREFNAMEWIDTH, MAJORBORDER * 2 + PREFNAMEWIDTH + PREFFIELDWIDTH / 3, median - CHECKBOXHEIGHT / 2, median + CHECKBOXHEIGHT / 2, "No"); AddRadioButton(radio, button); button = NewRadioButton( MAJORBORDER * 2 + PREFNAMEWIDTH + PREFFIELDWIDTH / 3, MAJORBORDER * 2 + PREFNAMEWIDTH + 2 * PREFFIELDWIDTH / 3, median - CHECKBOXHEIGHT / 2, median + CHECKBOXHEIGHT / 2, "Yes"); AddRadioButton(radio, button); SetValue(radio, NewInt(prefState[k] . value . truth)); SetVar(radio, WHICHPREF, NewInt(k)); SetMethod(radio, CHANGEDVALUE, ChangePrefBoolean); break; case PT_AMBOOL: sprintf(objName, "%s radio", prefInfo[k] . shortName); radio = NewRadioButtonGroup(objName); PrefixList(contents, radio); SetVar(radio, PARENT, panel); SetVar(radio, HELPSTRING, NewString(prefInfo[k] . helpString)); button = NewRadioButton( MAJORBORDER * 2 + PREFNAMEWIDTH, MAJORBORDER * 2 + PREFNAMEWIDTH + PREFFIELDWIDTH / 3, median - CHECKBOXHEIGHT / 2, median + CHECKBOXHEIGHT / 2, "Manual"); AddRadioButton(radio, button); button = NewRadioButton( MAJORBORDER * 2 + PREFNAMEWIDTH + PREFFIELDWIDTH / 3, MAJORBORDER * 2 + PREFNAMEWIDTH + 2 * PREFFIELDWIDTH / 3, median - CHECKBOXHEIGHT / 2, median + CHECKBOXHEIGHT / 2, "Automatic"); AddRadioButton(radio, button); SetValue(radio, NewInt(prefState[k] . value . truth)); SetVar(radio, WHICHPREF, NewInt(k)); SetMethod(radio, CHANGEDVALUE, ChangePrefBoolean); break; case PT_SFBOOL: sprintf(objName, "%s radio", prefInfo[k] . shortName); radio = NewRadioButtonGroup(objName); PrefixList(contents, radio); SetVar(radio, PARENT, panel); SetVar(radio, HELPSTRING, NewString(prefInfo[k] . helpString)); button = NewRadioButton( MAJORBORDER * 2 + PREFNAMEWIDTH, MAJORBORDER * 2 + PREFNAMEWIDTH + PREFFIELDWIDTH / 3, median - CHECKBOXHEIGHT / 2, median + CHECKBOXHEIGHT / 2, "Safer"); AddRadioButton(radio, button); button = NewRadioButton( MAJORBORDER * 2 + PREFNAMEWIDTH + PREFFIELDWIDTH / 3, MAJORBORDER * 2 + PREFNAMEWIDTH + 2 * PREFFIELDWIDTH / 3, median - CHECKBOXHEIGHT / 2, median + CHECKBOXHEIGHT / 2, "Faster"); AddRadioButton(radio, button); SetValue(radio, NewInt(prefState[k] . value . truth)); SetVar(radio, WHICHPREF, NewInt(k)); SetMethod(radio, CHANGEDVALUE, ChangePrefBoolean); break; case PT_AFFINT: sprintf(objName, "%s radio", prefInfo[k] . shortName); radio = NewRadioButtonGroup(objName); PrefixList(contents, radio); SetVar(radio, PARENT, panel); SetVar(radio, HELPSTRING, NewString(prefInfo[k] . helpString)); button = NewRadioButton( MAJORBORDER * 2 + PREFNAMEWIDTH, MAJORBORDER * 2 + PREFNAMEWIDTH + PREFFIELDWIDTH / 3, median - CHECKBOXHEIGHT / 2, median + CHECKBOXHEIGHT / 2, "Full Quality"); AddRadioButton(radio, button); button = NewRadioButton( MAJORBORDER * 2 + PREFNAMEWIDTH + PREFFIELDWIDTH / 3, MAJORBORDER * 2 + PREFNAMEWIDTH + 2 * PREFFIELDWIDTH / 3, median - CHECKBOXHEIGHT / 2, median + CHECKBOXHEIGHT / 2, "Faster"); AddRadioButton(radio, button); button = NewRadioButton( MAJORBORDER * 2 + PREFNAMEWIDTH + 2 * PREFFIELDWIDTH / 3, MAJORBORDER * 2 + PREFNAMEWIDTH + PREFFIELDWIDTH, median - CHECKBOXHEIGHT / 2, median + CHECKBOXHEIGHT / 2, "Automatic"); AddRadioButton(radio, button); SetValue(radio, NewInt(prefState[k] . value . integer)); SetVar(radio, WHICHPREF, NewInt(k)); SetMethod(radio, CHANGEDVALUE, ChangePrefInteger); break; case PT_RPINT: sprintf(objName, "%s radio", prefInfo[k] . shortName); radio = NewRadioButtonGroup(objName); PrefixList(contents, radio); SetVar(radio, PARENT, panel); SetVar(radio, HELPSTRING, NewString(prefInfo[k] . helpString)); button = NewRadioButton( MAJORBORDER * 2 + PREFNAMEWIDTH, MAJORBORDER * 2 + PREFNAMEWIDTH + PREFFIELDWIDTH / 3, median - CHECKBOXHEIGHT / 2, median + CHECKBOXHEIGHT / 2, "IRIS RGB"); AddRadioButton(radio, button); button = NewRadioButton( MAJORBORDER * 2 + PREFNAMEWIDTH + PREFFIELDWIDTH / 3, MAJORBORDER * 2 + PREFNAMEWIDTH + 2 * PREFFIELDWIDTH / 3, median - CHECKBOXHEIGHT / 2, median + CHECKBOXHEIGHT / 2, "PostScript"); AddRadioButton(radio, button); SetValue(radio, NewInt(prefState[k] . value . integer)); SetVar(radio, WHICHPREF, NewInt(k)); SetMethod(radio, CHANGEDVALUE, ChangePrefInteger); break; } } } if (logging) { InhibitLogging(false); } } void InitPreferences() /*Initialize the preferences*/ { int k; FILE *prefFile; /*Avoid a core dump if I forget to handle all preferences*/ for (k = 0; k < NPREFERENCES; ++k) { prefState[k] . value . string = 0; prefState[k] . changed = false; } /*Set up default values for all preferences*/ prefState[PREF_DEFDIR] . value . string = Alloc(2); strcpy(prefState[PREF_DEFDIR] . value . string, "."); prefState[PREF_ROTINERTIA] . value . truth = true; prefState[PREF_NEWWINPLACE] . value . truth = true; prefState[PREF_DRAWMOVING] . value . integer = DM_FULL; /*Try to read all preferences from environment variables*/ for (k = 0; k < NPREFERENCES; ++k) { char *envString; prefState[k] . exists = false; /*See if it can be read from an environment variable*/ strcpy(tempStr, "SCIAN_"); strcat(tempStr, prefInfo[k] . shortName); envString = getenv(tempStr); if (envString) { MakePrefFromString(k, envString); } } /*If a preferences file exists, open it and read it*/ sprintf(tempStr, "%s/%s", getenv("HOME"), ".scianPrefs"); prefFile = fopen(tempStr, "r"); if (prefFile) { char *s1, *s2, *s3; while (fgets(tempStr, TEMPSTRSIZE, prefFile)) { s1 = tempStr; while (*s1 && *s1 == ' ') ++s1; s2 = s1; while (*s2 && *s2 != ' ') ++s2; *s2++ = 0; while (*s2 && *s2 == ' ') ++s2; s3 = s2; while (*s3 && *s3 != '\n') ++s3; *s3 = 0; for (k = 0; k < NPREFERENCES; ++k) { if (0 == strcmp2(s1, prefInfo[k] . shortName)) { MakePrefFromString(k, s2); break; } } } fclose(prefFile); } } void KillPreferences() /*Kills the preferences*/ { int k; Bool savePreferences; savePreferences = false; /*Determine if preferences should be saved*/ for (k = 0; k < NPREFERENCES; ++k) { if (prefState[k] . changed) { savePreferences = true; } } if (savePreferences) { /*Save the preferences*/ FILE *prefFile; sprintf(tempStr, "%s/%s", getenv("HOME"), ".scianPrefs"); prefFile = fopen(tempStr, "w"); if (prefFile) { for (k = 0; k < NPREFERENCES; ++k) { if (prefState[k] . exists) { fprintf(prefFile, "%s ", prefInfo[k] . shortName); switch (prefInfo[k] . type) { case PT_STRING: fprintf(prefFile, "%s\n", prefState[k] . value . string); break; case PT_YNBOOL: fprintf(prefFile, "%s\n", prefState[k] . value . truth ? "yes" : "no"); break; case PT_AMBOOL: fprintf(prefFile, "%s\n", prefState[k] . value . truth ? "auto" : "manual"); break; case PT_SFBOOL: fprintf(prefFile, "%s\n", prefState[k] . value . truth ? "fast" : "safe"); break; case PT_AFFINT: fprintf(prefFile, "%s\n", prefState[k] . value . integer ? (prefState[k] . value . integer == 2 ? "auto" : "faster") : "full"); break; case PT_RPINT: fprintf(prefFile, "%s\n", prefState[k] . value . integer ? "PostScript" : "RGB"); break; } } } fclose(prefFile); } } /*Get rid of the preferences*/ for (k = 0; k < NPREFERENCES; ++k) { if ((prefInfo[k] . type == PT_STRING) && (prefState[k] . value . string)) { Free(prefState[k] . value . string); prefState[k] . value . string = 0; } } }