# optionSettings

The optionSettings object provides access to PinballY's option settings system, which the program uses to save and restore the user's option selections and the program's current state (e.g., which game is selected in the UI and which filter is active).

Options are stored in a file called Settings.txt, stored in the program's main install folder. This file uses a simple name/value pair syntax to store arbitrary variables with arbitrary string values. The optionSettings object accesses the in-memory copy of this collection of name/value pairs, which constitutes the basic database of settings data that PinballY uses throughout the program.

optionSettings provides direct access to the raw settings file data. Be aware that some of this information might be available in more processed forms from other system objects, and the processed versions might be easier to use for most purposes. For example, for information on what's currently showing in the wheel UI, you'll probably want to use the gameList object instead of the raw settings data; for information on player systems, GameSysInfo objects are usually easier to use than the raw system setting variables.

The settings system's name/value pair scheme is arbitrarily extensible. There's no pre-defined set of names that you're limited to, so you can define new variables of your own if you want to store additional settings beyond what the system stores. Just be sure to use suitably unique names for any new custom variables you add, to avoid any conflicts with future system variables. It's a good idea to use long names with some kind of prefix that signifies that the variables are custom - use your name as a prefix, perhaps.

## Event target

optionSettings is an event target object, so you can use the standard event methods (on(), off(), etc) to add and remove event listeners. See EventTarget.

This object serves as the event target for the following event types, which represent events related to saving and reloading the settings file:

## Variable names

Every option setting is represented by a name/value pair, which we refer to as a "variable", in the same sense as a program variable in a language like Javascript or C++. Variable names are arbitrary strings of alphanumeric characters and a limited set of punctuation characters, including "." and "_".

All variable names are "global": all of the names share a single namespace with no nesting or hierarchy structure, so every variable's name has to be unique. The system uses a convention of "dotted" prefixes for related variables (e.g., all of the capture-related settings start with "Capture."), but be aware that there's no actual formal structure to this. The "." characters in the dotted names are just parts of the names, not some kind of special namespace qualifiers.

If you add new custom variables of your own, it's a good idea to use some kind of prefix to ensure uniqueness, since all variables have to share a common namespace. A prefix based on your name or the name of the package/feature you're developing can be helpful to keep track of which variable goes with which code.

## Variable types

All settings variables are stored as string values in the file. There are no other "datatypes" besides strings, as far as the file storage is concerned.

However, it's convenient to be able to interpret some variables as numbers, some as boolean values, etc, depending on how they're used. To help with that, the settings system can automatically perform conversions to and from several native types when reading and writing variable values:

- string (the actual storage format)
- boolean
- integer
- floating point number
- RECT (the Windows API rectangle structure)

When reading values, you can use the "get" methods for the various datatypes to read values with specific types. When writing values, you always use the same "set" method, and the system figures out how to format the value as a string for storage in the file.

Be aware the actual value stored in the file is always a string value. When you use the get/set methods to convert to and from native types other than strings, the system performs the conversion with reference to the string stored in the file. Also be aware that the proper type interpretation of a particular variable is up to you when you read or write the variable, since the system doesn't store the original type in the file. If you store a value as a "float" and read it back as an "int", the system will happily comply, but you'll naturally lose any fractional part of the original floating point value.

## Effects of changing a variable

In some cases, changing the value of a system-defined setting variable will have an immediate effect in the UI, because the system refers directly to the in-memory settings variables for some purposes.

In most cases, though, changing a variable won't have any effect until the settings file is saved and reloaded. This is because the system creates a number of objects derived from the settings information when it loads the settings, and then uses those separate objects for ongoing operations. It doesn't refer back to the original settings variables, but rather uses those separate objects, which only have snapshots of the settings data from the time they were created. This separate, derived layer of settings data is needed for efficiency in many cases, because significant processing of the raw settings data is needed before it can be used.

For example, the program creates an internal object to represent each player system at startup, and uses these objects for operations related to the systems, such as launching a game or finding its media files. Changing the settings variables for a player system thus has no immediate effect on things like game launching or media file loading.

Fortunately, the program doesn't require a full "reboot" to get settings changes to take effect. It's not necessary to exit and restart the program. Instead, you can dynamically reload the settings at any time. This deletes and re-creates all of the derived objects, updating their snapshots of the settings data to something more modern.

The procedure to do this is simple: call save() to write out the current in-memory settings, and then call reload() to load the file and re-create all derived objects.

Saving and reloading is usually quite fast (it only takes a few milliseconds), but it has a number of visible side effects in the UI, such as interrupting video playback. So it shouldn't be undertaken lightly. It's best to do this only in response to a suitable, explicit user action, preferably one that's significant enough from a user's perspective to justify a UI refresh. For reference, the only time the program itself reloads the settings is when the user clicks the Apply or OK button in the settings dialog.

## Properties and methods

optionSettings.filename: The name of the settings file, with full directory path.

optionSettings.get(name, defaultValue): Get the value of the settings variable named by the string name. Returns the value as a string; this is the way it's actually stored in the settings file, so this is the most direct, unprocessed way to access the original value. If the variable isn't defined in the settings, defaultValue is returned instead. (If you omit the defaultValue argument, undefined is used instead per the normal Javascript rules.)

optionSettings.getBool(name, defaultValue): Get the value of the settings variable named by the string name, interpreting it as a boolean (true/false) value and returning the result as a Javascript boolean. If the variable isn't defined in the settings, defaultValue is returned instead. (If you omit the defaultValue argument, undefined is used instead per the normal Javascript rules.)

optionSettings.getFloat(name, defaultValue): Get the value of the settings variable named by the string name, interpreting it as a floating point value and returning the result as a Javascript number. If the variable isn't defined in the settings, defaultValue is returned instead. (If you omit the defaultValue argument, undefined is used instead per the normal Javascript rules.)

optionSettings.getInt(name, defaultValue): Get the value of the settings variable named by the string name, interpreting it as an integer value and returning the result as a Javascript number. If the variable isn't defined in the settings, defaultValue is returned instead. (If you omit the defaultValue argument, undefined is used instead per the normal Javascript rules.)

optionSettings.getRect(name, defaultValue): Get the value of the settings variable named by the string name, interpreting it as a Windows RECT (rectangle) structure, and returning the result as a Javascript object, with properties {left: integer, top: integer, right: integer, bottom: integer}. These properties give the of the top/left and bottom/right corners of the rectangle, as integer pixel offsets (the origin of the coordinate system depends on context, since the RECT structure can be used to represent screen coordinates in pixels, window coordinates, etc). If the variable isn't defined in the settings, defaultValue is returned instead. (If you omit the defaultValue argument, undefined is used instead per the normal Javascript rules.)

optionSettings.isDirty(): Returns true if the in-memory settings have any unsaved changes, false if not. Any change made through set() updates the in-memory copy, but doesn't immediately write the changes to the disk file. The same applies to changes made by the system itself that haven't been saved yet. In either case, the internal "dirty" flag is set to indicate that the in-memory copy has unsaved changes. This method lets you test that flag to determine if any changes have been made (from Javascript code or by the system) since the last time the file was saved or loaded.

optionSettings.reload(): Reloads the settings file. Any unsaved changes to the in-memory copy are discarded, and replaced with the values from the file on disk. Note that the system automatically reloads the settings file when the user makes changes through the options dialog. Reloading the settings file has the side effect of reloading the XML game database files and rescanning all system table folders, since changes to the settings can affect which systems are active, which folders are scanned for games, where the database files are located, and where the media files are located. Any media currently being displayed are reloaded, so any playing video will be reloaded and restarted.

If you want to force settings changes that you've made via set() to take effect in the UI, save the updates calling save(), then load the updated file via reload().

optionSettings.save(): Saves the current in-memory settings variables to the disk file, and clears the "dirty" flag. Returns true if the file write operation was successful, false if an error occurred. (The system itself doesn't show any messages if an error occurs; it just returns that information to you via the result value.)

optionSettings.set(name, value): Set the value of the settings variable named by the string name to the value given by value. value can be one of the following types:

- undefined: the variable is erased from the settings
- null: the variable is erased from the settings
- string: the value is stored exactly as given
- number: the value is stored as a string representation of its numeric value, either as a decimal integer (if it has no fractional part and it's in range for a 32-bit signed integer) or a decimal floating point value (if it doesn't qualify for the integer treatment)
- boolean: the value is stored as the string "0" or "1"
- object: if the value looks like a RECT struct (with properties left, top, right, and bottom), it's stored as "left,top,right,bottom", with the decimal integer values of each coordinate; otherwise, an error is thrown

Note that if you want to precisely control the representation stored in the file for a non-string type, you can simply convert the value to a string yourself in Javascript code using whatever formatting rules you want to apply, and pass the resulting string to set() to save in the file. Everything ends up a string anyway, so you don't give up anything by handling the conversion to string yourself; the system's type converters are just there as a convenience so that you don't have to do the conversion yourself in cases where the standard conversion is satisfactory.