1 
2 #include "state.hpp"
3 
4 #include <stdexcept>
5 #include <algorithm>
6 #include <sstream>
7 
8 #include "intsetting.hpp"
9 #include "doublesetting.hpp"
10 #include "boolsetting.hpp"
11 #include "coloursetting.hpp"
12 #include "shortcutsetting.hpp"
13 #include "modifiersetting.hpp"
14 
15 CSMPrefs::State *CSMPrefs::State::sThis = nullptr;
16 
load()17 void CSMPrefs::State::load()
18 {
19     // default settings file
20     boost::filesystem::path local = mConfigurationManager.getLocalPath() / mDefaultConfigFile;
21     boost::filesystem::path global = mConfigurationManager.getGlobalPath() / mDefaultConfigFile;
22 
23     if (boost::filesystem::exists (local))
24         mSettings.loadDefault (local.string());
25     else if (boost::filesystem::exists (global))
26         mSettings.loadDefault (global.string());
27     else
28         throw std::runtime_error ("No default settings file found! Make sure the file \"" + mDefaultConfigFile + "\" was properly installed.");
29 
30     // user settings file
31     boost::filesystem::path user = mConfigurationManager.getUserConfigPath() / mConfigFile;
32 
33     if (boost::filesystem::exists (user))
34         mSettings.loadUser (user.string());
35 }
36 
declare()37 void CSMPrefs::State::declare()
38 {
39     declareCategory ("Windows");
40     declareInt ("default-width", "Default window width", 800).
41         setTooltip ("Newly opened top-level windows will open with this width.").
42         setMin (80);
43     declareInt ("default-height", "Default window height", 600).
44         setTooltip ("Newly opened top-level windows will open with this height.").
45         setMin (80);
46     declareBool ("show-statusbar", "Show Status Bar", true).
47         setTooltip ("If a newly open top level window is showing status bars or not. "
48         " Note that this does not affect existing windows.");
49     declareSeparator();
50     declareBool ("reuse", "Reuse Subviews", true).
51         setTooltip ("When a new subview is requested and a matching subview already "
52         " exist, do not open a new subview and use the existing one instead.");
53     declareInt ("max-subviews", "Maximum number of subviews per top-level window", 256).
54         setTooltip ("If the maximum number is reached and a new subview is opened "
55             "it will be placed into a new top-level window.").
56         setRange (1, 256);
57     declareBool ("hide-subview", "Hide single subview", false).
58         setTooltip ("When a view contains only a single subview, hide the subview title "
59         "bar and if this subview is closed also close the view (unless it is the last "
60         "view for this document)");
61     declareInt ("minimum-width", "Minimum subview width", 325).
62         setTooltip ("Minimum width of subviews.").
63         setRange (50, 10000);
64     declareSeparator();
65     EnumValue scrollbarOnly ("Scrollbar Only", "Simple addition of scrollbars, the view window "
66         "does not grow automatically.");
67     declareEnum ("mainwindow-scrollbar", "Horizontal scrollbar mode for main window.", scrollbarOnly).
68         addValue (scrollbarOnly).
69         addValue ("Grow Only", "The view window grows as subviews are added. No scrollbars.").
70         addValue ("Grow then Scroll", "The view window grows. The scrollbar appears once it cannot grow any further.");
71     declareBool ("grow-limit", "Grow Limit Screen", false).
72         setTooltip ("When \"Grow then Scroll\" option is selected, the window size grows to"
73         " the width of the virtual desktop. \nIf this option is selected the the window growth"
74         "is limited to the current screen.");
75 
76     declareCategory ("Records");
77     EnumValue iconAndText ("Icon and Text");
78     EnumValues recordValues;
79     recordValues.add (iconAndText).add ("Icon Only").add ("Text Only");
80     declareEnum ("status-format", "Modification status display format", iconAndText).
81         addValues (recordValues);
82     declareEnum ("type-format", "ID type display format", iconAndText).
83         addValues (recordValues);
84 
85     declareCategory ("ID Tables");
86     EnumValue inPlaceEdit ("Edit in Place", "Edit the clicked cell");
87     EnumValue editRecord ("Edit Record", "Open a dialogue subview for the clicked record");
88     EnumValue view ("View", "Open a scene subview for the clicked record (not available everywhere)");
89     EnumValue editRecordAndClose ("Edit Record and Close");
90     EnumValues doubleClickValues;
91     doubleClickValues.add (inPlaceEdit).add (editRecord).add (view).add ("Revert").
92         add ("Delete").add (editRecordAndClose).
93         add ("View and Close", "Open a scene subview for the clicked record and close the table subview");
94     declareEnum ("double", "Double Click", inPlaceEdit).addValues (doubleClickValues);
95     declareEnum ("double-s", "Shift Double Click", editRecord).addValues (doubleClickValues);
96     declareEnum ("double-c", "Control Double Click", view).addValues (doubleClickValues);
97     declareEnum ("double-sc", "Shift Control Double Click", editRecordAndClose).addValues (doubleClickValues);
98     declareSeparator();
99     EnumValue jumpAndSelect ("Jump and Select", "Scroll new record into view and make it the selection");
100     declareEnum ("jump-to-added", "Action on adding or cloning a record", jumpAndSelect).
101         addValue (jumpAndSelect).
102         addValue ("Jump Only", "Scroll new record into view").
103         addValue ("No Jump", "No special action");
104     declareBool ("extended-config",
105         "Manually specify affected record types for an extended delete/revert", false).
106         setTooltip ("Delete and revert commands have an extended form that also affects "
107         "associated records.\n\n"
108         "If this option is enabled, types of affected records are selected "
109         "manually before a command execution.\nOtherwise, all associated "
110         "records are deleted/reverted immediately.");
111 
112     declareCategory ("ID Dialogues");
113     declareBool ("toolbar", "Show toolbar", true);
114 
115     declareCategory ("Reports");
116     EnumValue actionNone ("None");
117     EnumValue actionEdit ("Edit", "Open a table or dialogue suitable for addressing the listed report");
118     EnumValue actionRemove ("Remove", "Remove the report from the report table");
119     EnumValue actionEditAndRemove ("Edit And Remove", "Open a table or dialogue suitable for addressing the listed report, then remove the report from the report table");
120     EnumValues reportValues;
121     reportValues.add (actionNone).add (actionEdit).add (actionRemove).add (actionEditAndRemove);
122     declareEnum ("double", "Double Click", actionEdit).addValues (reportValues);
123     declareEnum ("double-s", "Shift Double Click", actionRemove).addValues (reportValues);
124     declareEnum ("double-c", "Control Double Click", actionEditAndRemove).addValues (reportValues);
125     declareEnum ("double-sc", "Shift Control Double Click", actionNone).addValues (reportValues);
126     declareBool("ignore-base-records", "Ignore base records in verifier", false);
127 
128     declareCategory ("Search & Replace");
129     declareInt ("char-before", "Characters before search string", 10).
130         setTooltip ("Maximum number of character to display in search result before the searched text");
131     declareInt ("char-after", "Characters after search string", 10).
132         setTooltip ("Maximum number of character to display in search result after the searched text");
133     declareBool ("auto-delete", "Delete row from result table after a successful replace", true);
134 
135     declareCategory ("Scripts");
136     declareBool ("show-linenum", "Show Line Numbers", true).
137         setTooltip ("Show line numbers to the left of the script editor window."
138         "The current row and column numbers of the text cursor are shown at the bottom.");
139     declareBool ("wrap-lines", "Wrap Lines", false).
140         setTooltip ("Wrap lines longer than width of script editor.");
141     declareBool ("mono-font", "Use monospace font", true);
142     declareInt ("tab-width", "Tab Width", 4).
143         setTooltip ("Number of characters for tab width").
144         setRange (1, 10);
145     EnumValue warningsNormal ("Normal", "Report warnings as warning");
146     declareEnum ("warnings", "Warning Mode", warningsNormal).
147         addValue ("Ignore", "Do not report warning").
148         addValue (warningsNormal).
149         addValue ("Strict", "Promote warning to an error");
150     declareBool ("toolbar", "Show toolbar", true);
151     declareInt ("compile-delay", "Delay between updating of source errors", 100).
152         setTooltip ("Delay in milliseconds").
153         setRange (0, 10000);
154     declareInt ("error-height", "Initial height of the error panel", 100).
155         setRange (100, 10000);
156     declareBool ("highlight-occurrences", "Highlight other occurrences of selected names", true);
157     declareColour ("colour-highlight", "Colour of highlighted occurrences", QColor("lightcyan"));
158     declareSeparator();
159     declareColour ("colour-int", "Highlight Colour: Integer Literals", QColor ("darkmagenta"));
160     declareColour ("colour-float", "Highlight Colour: Float Literals", QColor ("magenta"));
161     declareColour ("colour-name", "Highlight Colour: Names", QColor ("grey"));
162     declareColour ("colour-keyword", "Highlight Colour: Keywords", QColor ("red"));
163     declareColour ("colour-special", "Highlight Colour: Special Characters", QColor ("darkorange"));
164     declareColour ("colour-comment", "Highlight Colour: Comments", QColor ("green"));
165     declareColour ("colour-id", "Highlight Colour: IDs", QColor ("blue"));
166 
167     declareCategory ("General Input");
168     declareBool ("cycle", "Cyclic next/previous", false).
169         setTooltip ("When using next/previous functions at the last/first item of a "
170         "list go to the first/last item");
171 
172     declareCategory ("3D Scene Input");
173 
174     declareDouble ("navi-wheel-factor", "Camera Zoom Sensitivity", 8).setRange(-100.0, 100.0);
175     declareDouble ("s-navi-sensitivity", "Secondary Camera Movement Sensitivity", 50.0).setRange(-1000.0, 1000.0);
176     declareSeparator();
177 
178     declareDouble ("p-navi-free-sensitivity", "Free Camera Sensitivity", 1/650.).setPrecision(5).setRange(0.0, 1.0);
179     declareBool ("p-navi-free-invert", "Invert Free Camera Mouse Input", false);
180     declareDouble ("navi-free-lin-speed", "Free Camera Linear Speed", 1000.0).setRange(1.0, 10000.0);
181     declareDouble ("navi-free-rot-speed", "Free Camera Rotational Speed", 3.14 / 2).setRange(0.001, 6.28);
182     declareDouble ("navi-free-speed-mult", "Free Camera Speed Multiplier (from Modifier)", 8).setRange(0.001, 1000.0);
183     declareSeparator();
184 
185     declareDouble ("p-navi-orbit-sensitivity", "Orbit Camera Sensitivity", 1/650.).setPrecision(5).setRange(0.0, 1.0);
186     declareBool ("p-navi-orbit-invert", "Invert Orbit Camera Mouse Input", false);
187     declareDouble ("navi-orbit-rot-speed", "Orbital Camera Rotational Speed", 3.14 / 4).setRange(0.001, 6.28);
188     declareDouble ("navi-orbit-speed-mult", "Orbital Camera Speed Multiplier (from Modifier)", 4).setRange(0.001, 1000.0);
189     declareBool ("navi-orbit-const-roll", "Keep camera roll constant for orbital camera", true);
190     declareSeparator();
191 
192     declareBool ("context-select", "Context Sensitive Selection", false);
193     declareDouble ("drag-factor", "Mouse sensitivity during drag operations", 1.0).
194         setRange (0.001, 100.0);
195     declareDouble ("drag-wheel-factor", "Mouse wheel sensitivity during drag operations", 1.0).
196         setRange (0.001, 100.0);
197     declareDouble ("drag-shift-factor",
198             "Shift-acceleration factor during drag operations", 4.0).
199         setTooltip ("Acceleration factor during drag operations while holding down shift").
200         setRange (0.001, 100.0);
201     declareDouble ("rotate-factor", "Free rotation factor", 0.007).setPrecision(4).setRange(0.0001, 0.1);
202 
203     declareCategory ("Rendering");
204     declareInt ("framerate-limit", "FPS limit", 60).
205         setTooltip("Framerate limit in 3D preview windows. Zero value means \"unlimited\".").
206         setRange(0, 10000);
207     declareInt ("camera-fov", "Camera FOV", 90).setRange(10, 170);
208     declareBool ("camera-ortho", "Orthographic projection for camera", false);
209     declareInt ("camera-ortho-size", "Orthographic projection size parameter", 100).
210         setTooltip("Size of the orthographic frustum, greater value will allow the camera to see more of the world.").
211         setRange(10, 10000);
212     declareDouble ("object-marker-alpha", "Object Marker Transparency", 0.5).setPrecision(2).setRange(0,1);
213     declareBool("scene-use-gradient", "Use Gradient Background", true);
214     declareColour ("scene-day-background-colour", "Day Background Colour", QColor (110, 120, 128, 255));
215     declareColour ("scene-day-gradient-colour", "Day Gradient  Colour", QColor (47, 51, 51, 255)).
216         setTooltip("Sets the gradient color to use in conjunction with the day background color. Ignored if "
217                    "the gradient option is disabled.");
218     declareColour ("scene-bright-background-colour", "Scene Bright Background Colour", QColor (79, 87, 92, 255));
219     declareColour ("scene-bright-gradient-colour", "Scene Bright Gradient Colour", QColor (47, 51, 51, 255)).
220         setTooltip("Sets the gradient color to use in conjunction with the bright background color. Ignored if "
221             "the gradient option is disabled.");
222     declareColour ("scene-night-background-colour", "Scene Night Background Colour", QColor (64, 77, 79, 255));
223     declareColour ("scene-night-gradient-colour", "Scene Night Gradient Colour", QColor (47, 51, 51, 255)).
224         setTooltip("Sets the gradient color to use in conjunction with the night background color. Ignored if "
225             "the gradient option is disabled.");
226 
227     declareCategory ("Tooltips");
228     declareBool ("scene", "Show Tooltips in 3D scenes", true);
229     declareBool ("scene-hide-basic", "Hide basic  3D scenes tooltips", false);
230     declareInt ("scene-delay", "Tooltip delay in milliseconds", 500).
231         setMin (1);
232 
233     EnumValue createAndInsert ("Create cell and insert");
234     EnumValue showAndInsert ("Show cell and insert");
235     EnumValue dontInsert ("Discard");
236     EnumValue insertAnyway ("Insert anyway");
237     EnumValues insertOutsideCell;
238     insertOutsideCell.add (createAndInsert).add (dontInsert).add (insertAnyway);
239     EnumValues insertOutsideVisibleCell;
240     insertOutsideVisibleCell.add (showAndInsert).add (dontInsert).add (insertAnyway);
241 
242     EnumValue createAndLandEdit ("Create cell and land, then edit");
243     EnumValue showAndLandEdit ("Show cell and edit");
244     EnumValue dontLandEdit ("Discard");
245     EnumValues landeditOutsideCell;
246     landeditOutsideCell.add (createAndLandEdit).add (dontLandEdit);
247     EnumValues landeditOutsideVisibleCell;
248     landeditOutsideVisibleCell.add (showAndLandEdit).add (dontLandEdit);
249 
250     EnumValue SelectOnly ("Select only");
251     EnumValue SelectAdd ("Add to selection");
252     EnumValue SelectRemove ("Remove from selection");
253     EnumValue selectInvert ("Invert selection");
254     EnumValues primarySelectAction;
255     primarySelectAction.add (SelectOnly).add (SelectAdd).add (SelectRemove).add (selectInvert);
256     EnumValues secondarySelectAction;
257     secondarySelectAction.add (SelectOnly).add (SelectAdd).add (SelectRemove).add (selectInvert);
258 
259     declareCategory ("3D Scene Editing");
260     declareInt ("distance", "Drop Distance", 50).
261         setTooltip ("If an instance drop can not be placed against another object at the "
262             "insert point, it will be placed by this distance from the insert point instead");
263     declareEnum ("outside-drop", "Handling drops outside of cells", createAndInsert).
264         addValues (insertOutsideCell);
265     declareEnum ("outside-visible-drop", "Handling drops outside of visible cells", showAndInsert).
266         addValues (insertOutsideVisibleCell);
267     declareEnum ("outside-landedit", "Handling terrain edit outside of cells", createAndLandEdit).
268         setTooltip("Behavior of terrain editing, if land editing brush reaches an area without cell record.").
269         addValues (landeditOutsideCell);
270     declareEnum ("outside-visible-landedit", "Handling terrain edit outside of visible cells", showAndLandEdit).
271         setTooltip("Behavior of terrain editing, if land editing brush reaches an area that is not currently visible.").
272         addValues (landeditOutsideVisibleCell);
273     declareInt ("texturebrush-maximumsize", "Maximum texture brush size", 50).
274         setMin (1);
275     declareInt ("shapebrush-maximumsize", "Maximum height edit brush size", 100).
276         setTooltip("Setting for the slider range of brush size in terrain height editing.").
277         setMin (1);
278     declareBool ("landedit-post-smoothpainting", "Smooth land after painting height", false).
279         setTooltip("Raise and lower tools will leave bumpy finish without this option");
280     declareDouble ("landedit-post-smoothstrength", "Smoothing strength (post-edit)", 0.25).
281         setTooltip("If smoothing land after painting height is used, this is the percentage of smooth applied afterwards. "
282         "Negative values may be used to roughen instead of smooth.").
283         setMin (-1).
284         setMax (1);
285     declareBool ("open-list-view", "Open displays list view", false).
286         setTooltip ("When opening a reference from the scene view, it will open the"
287         " instance list view instead of the individual instance record view.");
288     declareEnum ("primary-select-action", "Action for primary select", SelectOnly).
289         setTooltip("Selection can be chosen between select only, add to selection, remove from selection and invert selection.").
290         addValues (primarySelectAction);
291     declareEnum ("secondary-select-action", "Action for secondary select", SelectAdd).
292         setTooltip("Selection can be chosen between select only, add to selection, remove from selection and invert selection.").
293         addValues (secondarySelectAction);
294 
295     declareCategory ("Key Bindings");
296 
297     declareSubcategory ("Document");
298     declareShortcut ("document-file-newgame", "New Game", QKeySequence(Qt::ControlModifier | Qt::Key_N));
299     declareShortcut ("document-file-newaddon", "New Addon", QKeySequence());
300     declareShortcut ("document-file-open", "Open", QKeySequence(Qt::ControlModifier | Qt::Key_O));
301     declareShortcut ("document-file-save", "Save", QKeySequence(Qt::ControlModifier | Qt::Key_S));
302     declareShortcut ("document-help-help", "Help", QKeySequence(Qt::Key_F1));
303     declareShortcut ("document-help-tutorial", "Tutorial", QKeySequence());
304     declareShortcut ("document-file-verify", "Verify", QKeySequence());
305     declareShortcut ("document-file-merge", "Merge", QKeySequence());
306     declareShortcut ("document-file-errorlog", "Open Load Error Log", QKeySequence());
307     declareShortcut ("document-file-metadata", "Meta Data", QKeySequence());
308     declareShortcut ("document-file-close", "Close Document", QKeySequence(Qt::ControlModifier | Qt::Key_W));
309     declareShortcut ("document-file-exit", "Exit Application", QKeySequence(Qt::ControlModifier | Qt::Key_Q));
310     declareShortcut ("document-edit-undo", "Undo", QKeySequence(Qt::ControlModifier | Qt::Key_Z));
311     declareShortcut ("document-edit-redo", "Redo", QKeySequence(Qt::ControlModifier | Qt::ShiftModifier | Qt::Key_Z));
312     declareShortcut ("document-edit-preferences", "Open Preferences", QKeySequence());
313     declareShortcut ("document-edit-search", "Search", QKeySequence(Qt::ControlModifier | Qt::Key_F));
314     declareShortcut ("document-view-newview", "New View", QKeySequence());
315     declareShortcut ("document-view-statusbar", "Toggle Status Bar", QKeySequence());
316     declareShortcut ("document-view-filters", "Open Filter List", QKeySequence());
317     declareShortcut ("document-world-regions", "Open Region List", QKeySequence());
318     declareShortcut ("document-world-cells", "Open Cell List", QKeySequence());
319     declareShortcut ("document-world-referencables", "Open Object List", QKeySequence());
320     declareShortcut ("document-world-references", "Open Instance List", QKeySequence());
321     declareShortcut ("document-world-lands", "Open Lands List", QKeySequence());
322     declareShortcut ("document-world-landtextures", "Open Land Textures List", QKeySequence());
323     declareShortcut ("document-world-pathgrid", "Open Pathgrid List", QKeySequence());
324     declareShortcut ("document-world-regionmap", "Open Region Map", QKeySequence());
325     declareShortcut ("document-mechanics-globals", "Open Global List", QKeySequence());
326     declareShortcut ("document-mechanics-gamesettings", "Open Game Settings", QKeySequence());
327     declareShortcut ("document-mechanics-scripts", "Open Script List", QKeySequence());
328     declareShortcut ("document-mechanics-spells", "Open Spell List", QKeySequence());
329     declareShortcut ("document-mechanics-enchantments", "Open Enchantment List", QKeySequence());
330     declareShortcut ("document-mechanics-magiceffects", "Open Magic Effect List", QKeySequence());
331     declareShortcut ("document-mechanics-startscripts", "Open Start Script List", QKeySequence());
332     declareShortcut ("document-character-skills", "Open Skill List", QKeySequence());
333     declareShortcut ("document-character-classes", "Open Class List", QKeySequence());
334     declareShortcut ("document-character-factions", "Open Faction List", QKeySequence());
335     declareShortcut ("document-character-races", "Open Race List", QKeySequence());
336     declareShortcut ("document-character-birthsigns", "Open Birthsign List", QKeySequence());
337     declareShortcut ("document-character-topics", "Open Topic List", QKeySequence());
338     declareShortcut ("document-character-journals", "Open Journal List", QKeySequence());
339     declareShortcut ("document-character-topicinfos", "Open Topic Info List", QKeySequence());
340     declareShortcut ("document-character-journalinfos", "Open Journal Info List", QKeySequence());
341     declareShortcut ("document-character-bodyparts", "Open Body Part List", QKeySequence());
342     declareShortcut ("document-assets-reload", "Reload Assets", QKeySequence(Qt::Key_F5));
343     declareShortcut ("document-assets-sounds", "Open Sound Asset List", QKeySequence());
344     declareShortcut ("document-assets-soundgens", "Open Sound Generator List", QKeySequence());
345     declareShortcut ("document-assets-meshes", "Open Mesh Asset List", QKeySequence());
346     declareShortcut ("document-assets-icons", "Open Icon Asset List", QKeySequence());
347     declareShortcut ("document-assets-music", "Open Music Asset List", QKeySequence());
348     declareShortcut ("document-assets-soundres", "Open Sound File List", QKeySequence());
349     declareShortcut ("document-assets-textures", "Open Texture Asset List", QKeySequence());
350     declareShortcut ("document-assets-videos", "Open Video Asset List", QKeySequence());
351     declareShortcut ("document-debug-run", "Run Debug", QKeySequence());
352     declareShortcut ("document-debug-shutdown", "Stop Debug", QKeySequence());
353     declareShortcut ("document-debug-profiles", "Debug Profiles", QKeySequence());
354     declareShortcut ("document-debug-runlog", "Open Run Log", QKeySequence());
355 
356     declareSubcategory ("Table");
357     declareShortcut ("table-edit", "Edit Record", QKeySequence());
358     declareShortcut ("table-add", "Add Row/Record", QKeySequence(Qt::ShiftModifier | Qt::Key_A));
359     declareShortcut ("table-clone", "Clone Record", QKeySequence(Qt::ShiftModifier | Qt::Key_D));
360     declareShortcut ("touch-record", "Touch Record", QKeySequence());
361     declareShortcut ("table-revert", "Revert Record", QKeySequence());
362     declareShortcut ("table-remove", "Remove Row/Record", QKeySequence(Qt::Key_Delete));
363     declareShortcut ("table-moveup", "Move Record Up", QKeySequence());
364     declareShortcut ("table-movedown", "Move Record Down", QKeySequence());
365     declareShortcut ("table-view", "View Record", QKeySequence(Qt::ShiftModifier | Qt::Key_C));
366     declareShortcut ("table-preview", "Preview Record", QKeySequence(Qt::ShiftModifier | Qt::Key_V));
367     declareShortcut ("table-extendeddelete", "Extended Record Deletion", QKeySequence());
368     declareShortcut ("table-extendedrevert", "Extended Record Revertion", QKeySequence());
369 
370     declareSubcategory ("Report Table");
371     declareShortcut ("reporttable-show", "Show Report", QKeySequence());
372     declareShortcut ("reporttable-remove", "Remove Report", QKeySequence(Qt::Key_Delete));
373     declareShortcut ("reporttable-replace", "Replace Report", QKeySequence());
374     declareShortcut ("reporttable-refresh", "Refresh Report", QKeySequence());
375 
376     declareSubcategory ("Scene");
377     declareShortcut ("scene-navi-primary", "Camera Rotation From Mouse Movement", QKeySequence(Qt::LeftButton));
378     declareShortcut ("scene-navi-secondary", "Camera Translation From Mouse Movement",
379         QKeySequence(Qt::ControlModifier | (int)Qt::LeftButton));
380     declareShortcut ("scene-open-primary", "Primary Open", QKeySequence(Qt::ShiftModifier | (int)Qt::LeftButton));
381     declareShortcut ("scene-edit-primary", "Primary Edit", QKeySequence(Qt::RightButton));
382     declareShortcut ("scene-edit-secondary", "Secondary Edit",
383         QKeySequence(Qt::ControlModifier | (int)Qt::RightButton));
384     declareShortcut ("scene-select-primary", "Primary Select", QKeySequence(Qt::MiddleButton));
385     declareShortcut ("scene-select-secondary", "Secondary Select",
386         QKeySequence(Qt::ControlModifier | (int)Qt::MiddleButton));
387     declareModifier ("scene-speed-modifier", "Speed Modifier", Qt::Key_Shift);
388     declareShortcut ("scene-delete", "Delete Instance", QKeySequence(Qt::Key_Delete));
389     declareShortcut ("scene-instance-drop-terrain", "Drop to terrain level", QKeySequence(Qt::Key_G));
390     declareShortcut ("scene-instance-drop-collision", "Drop to collision", QKeySequence(Qt::Key_H));
391     declareShortcut ("scene-instance-drop-terrain-separately", "Drop to terrain level separately", QKeySequence());
392     declareShortcut ("scene-instance-drop-collision-separately", "Drop to collision separately", QKeySequence());
393     declareShortcut ("scene-load-cam-cell", "Load Camera Cell", QKeySequence(Qt::KeypadModifier | Qt::Key_5));
394     declareShortcut ("scene-load-cam-eastcell", "Load East Cell", QKeySequence(Qt::KeypadModifier | Qt::Key_6));
395     declareShortcut ("scene-load-cam-northcell", "Load North Cell", QKeySequence(Qt::KeypadModifier | Qt::Key_8));
396     declareShortcut ("scene-load-cam-westcell", "Load West Cell", QKeySequence(Qt::KeypadModifier | Qt::Key_4));
397     declareShortcut ("scene-load-cam-southcell", "Load South Cell", QKeySequence(Qt::KeypadModifier | Qt::Key_2));
398     declareShortcut ("scene-edit-abort", "Abort", QKeySequence(Qt::Key_Escape));
399     declareShortcut ("scene-focus-toolbar", "Toggle Toolbar Focus", QKeySequence(Qt::Key_T));
400     declareShortcut ("scene-render-stats", "Debug Rendering Stats", QKeySequence(Qt::Key_F3));
401 
402     declareSubcategory ("1st/Free Camera");
403     declareShortcut ("free-forward", "Forward", QKeySequence(Qt::Key_W));
404     declareShortcut ("free-backward", "Backward", QKeySequence(Qt::Key_S));
405     declareShortcut ("free-left", "Left", QKeySequence(Qt::Key_A));
406     declareShortcut ("free-right", "Right", QKeySequence(Qt::Key_D));
407     declareShortcut ("free-roll-left", "Roll Left", QKeySequence(Qt::Key_Q));
408     declareShortcut ("free-roll-right", "Roll Right", QKeySequence(Qt::Key_E));
409     declareShortcut ("free-speed-mode", "Toggle Speed Mode", QKeySequence(Qt::Key_F));
410 
411     declareSubcategory ("Orbit Camera");
412     declareShortcut ("orbit-up", "Up", QKeySequence(Qt::Key_W));
413     declareShortcut ("orbit-down", "Down", QKeySequence(Qt::Key_S));
414     declareShortcut ("orbit-left", "Left", QKeySequence(Qt::Key_A));
415     declareShortcut ("orbit-right", "Right", QKeySequence(Qt::Key_D));
416     declareShortcut ("orbit-roll-left", "Roll Left", QKeySequence(Qt::Key_Q));
417     declareShortcut ("orbit-roll-right", "Roll Right", QKeySequence(Qt::Key_E));
418     declareShortcut ("orbit-speed-mode", "Toggle Speed Mode", QKeySequence(Qt::Key_F));
419     declareShortcut ("orbit-center-selection", "Center On Selected", QKeySequence(Qt::Key_C));
420 
421     declareSubcategory ("Script Editor");
422     declareShortcut ("script-editor-comment", "Comment Selection", QKeySequence());
423     declareShortcut ("script-editor-uncomment", "Uncomment Selection", QKeySequence());
424 
425     declareCategory ("Models");
426     declareString ("baseanim", "base animations", "meshes/base_anim.nif").
427         setTooltip("3rd person base model with textkeys-data");
428     declareString ("baseanimkna", "base animations, kna", "meshes/base_animkna.nif").
429         setTooltip("3rd person beast race base model with textkeys-data");
430     declareString ("baseanimfemale", "base animations, female", "meshes/base_anim_female.nif").
431         setTooltip("3rd person female base model with textkeys-data");
432     declareString ("wolfskin", "base animations, wolf", "meshes/wolf/skin.nif").
433         setTooltip("3rd person werewolf skin");
434 }
435 
declareCategory(const std::string & key)436 void CSMPrefs::State::declareCategory (const std::string& key)
437 {
438     std::map<std::string, Category>::iterator iter = mCategories.find (key);
439 
440     if (iter!=mCategories.end())
441     {
442         mCurrentCategory = iter;
443     }
444     else
445     {
446         mCurrentCategory =
447             mCategories.insert (std::make_pair (key, Category (this, key))).first;
448     }
449 }
450 
declareInt(const std::string & key,const std::string & label,int default_)451 CSMPrefs::IntSetting& CSMPrefs::State::declareInt (const std::string& key,
452     const std::string& label, int default_)
453 {
454     if (mCurrentCategory==mCategories.end())
455         throw std::logic_error ("no category for setting");
456 
457     setDefault(key, std::to_string(default_));
458 
459     default_ = mSettings.getInt (key, mCurrentCategory->second.getKey());
460 
461     CSMPrefs::IntSetting *setting =
462         new CSMPrefs::IntSetting (&mCurrentCategory->second, &mSettings, &mMutex, key, label,
463         default_);
464 
465     mCurrentCategory->second.addSetting (setting);
466 
467     return *setting;
468 }
469 
declareDouble(const std::string & key,const std::string & label,double default_)470 CSMPrefs::DoubleSetting& CSMPrefs::State::declareDouble (const std::string& key,
471     const std::string& label, double default_)
472 {
473     if (mCurrentCategory==mCategories.end())
474         throw std::logic_error ("no category for setting");
475 
476     std::ostringstream stream;
477     stream << default_;
478     setDefault(key, stream.str());
479 
480     default_ = mSettings.getFloat (key, mCurrentCategory->second.getKey());
481 
482     CSMPrefs::DoubleSetting *setting =
483         new CSMPrefs::DoubleSetting (&mCurrentCategory->second, &mSettings, &mMutex,
484         key, label, default_);
485 
486     mCurrentCategory->second.addSetting (setting);
487 
488     return *setting;
489 }
490 
declareBool(const std::string & key,const std::string & label,bool default_)491 CSMPrefs::BoolSetting& CSMPrefs::State::declareBool (const std::string& key,
492     const std::string& label, bool default_)
493 {
494     if (mCurrentCategory==mCategories.end())
495         throw std::logic_error ("no category for setting");
496 
497     setDefault (key, default_ ? "true" : "false");
498 
499     default_ = mSettings.getBool (key, mCurrentCategory->second.getKey());
500 
501     CSMPrefs::BoolSetting *setting =
502         new CSMPrefs::BoolSetting (&mCurrentCategory->second, &mSettings, &mMutex, key, label,
503         default_);
504 
505     mCurrentCategory->second.addSetting (setting);
506 
507     return *setting;
508 }
509 
declareEnum(const std::string & key,const std::string & label,EnumValue default_)510 CSMPrefs::EnumSetting& CSMPrefs::State::declareEnum (const std::string& key,
511     const std::string& label, EnumValue default_)
512 {
513     if (mCurrentCategory==mCategories.end())
514         throw std::logic_error ("no category for setting");
515 
516     setDefault (key, default_.mValue);
517 
518     default_.mValue = mSettings.getString (key, mCurrentCategory->second.getKey());
519 
520     CSMPrefs::EnumSetting *setting =
521         new CSMPrefs::EnumSetting (&mCurrentCategory->second, &mSettings, &mMutex, key, label,
522         default_);
523 
524     mCurrentCategory->second.addSetting (setting);
525 
526     return *setting;
527 }
528 
declareColour(const std::string & key,const std::string & label,QColor default_)529 CSMPrefs::ColourSetting& CSMPrefs::State::declareColour (const std::string& key,
530     const std::string& label, QColor default_)
531 {
532     if (mCurrentCategory==mCategories.end())
533         throw std::logic_error ("no category for setting");
534 
535     setDefault (key, default_.name().toUtf8().data());
536 
537     default_.setNamedColor (QString::fromUtf8 (mSettings.getString (key, mCurrentCategory->second.getKey()).c_str()));
538 
539     CSMPrefs::ColourSetting *setting =
540         new CSMPrefs::ColourSetting (&mCurrentCategory->second, &mSettings, &mMutex, key, label,
541         default_);
542 
543     mCurrentCategory->second.addSetting (setting);
544 
545     return *setting;
546 }
547 
declareShortcut(const std::string & key,const std::string & label,const QKeySequence & default_)548 CSMPrefs::ShortcutSetting& CSMPrefs::State::declareShortcut (const std::string& key, const std::string& label,
549     const QKeySequence& default_)
550 {
551     if (mCurrentCategory==mCategories.end())
552         throw std::logic_error ("no category for setting");
553 
554     std::string seqStr = getShortcutManager().convertToString(default_);
555     setDefault (key, seqStr);
556 
557     // Setup with actual data
558     QKeySequence sequence;
559 
560     getShortcutManager().convertFromString(mSettings.getString(key, mCurrentCategory->second.getKey()), sequence);
561     getShortcutManager().setSequence(key, sequence);
562 
563     CSMPrefs::ShortcutSetting *setting = new CSMPrefs::ShortcutSetting (&mCurrentCategory->second, &mSettings, &mMutex,
564         key, label);
565     mCurrentCategory->second.addSetting (setting);
566 
567     return *setting;
568 }
569 
declareString(const std::string & key,const std::string & label,std::string default_)570 CSMPrefs::StringSetting& CSMPrefs::State::declareString (const std::string& key, const std::string& label, std::string default_)
571 {
572     if (mCurrentCategory==mCategories.end())
573         throw std::logic_error ("no category for setting");
574 
575     setDefault (key, default_);
576 
577     default_ = mSettings.getString (key, mCurrentCategory->second.getKey());
578 
579     CSMPrefs::StringSetting *setting =
580         new CSMPrefs::StringSetting (&mCurrentCategory->second, &mSettings, &mMutex, key, label,
581         default_);
582 
583     mCurrentCategory->second.addSetting (setting);
584 
585     return *setting;
586 }
587 
declareModifier(const std::string & key,const std::string & label,int default_)588 CSMPrefs::ModifierSetting& CSMPrefs::State::declareModifier(const std::string& key, const std::string& label,
589     int default_)
590 {
591     if (mCurrentCategory==mCategories.end())
592         throw std::logic_error ("no category for setting");
593 
594     std::string modStr = getShortcutManager().convertToString(default_);
595     setDefault (key, modStr);
596 
597     // Setup with actual data
598     int modifier;
599 
600     getShortcutManager().convertFromString(mSettings.getString(key, mCurrentCategory->second.getKey()), modifier);
601     getShortcutManager().setModifier(key, modifier);
602 
603     CSMPrefs::ModifierSetting *setting = new CSMPrefs::ModifierSetting (&mCurrentCategory->second, &mSettings, &mMutex,
604         key, label);
605     mCurrentCategory->second.addSetting (setting);
606 
607     return *setting;
608 }
609 
declareSeparator()610 void CSMPrefs::State::declareSeparator()
611 {
612     if (mCurrentCategory==mCategories.end())
613         throw std::logic_error ("no category for setting");
614 
615     CSMPrefs::Setting *setting =
616         new CSMPrefs::Setting (&mCurrentCategory->second, &mSettings, &mMutex, "", "");
617 
618     mCurrentCategory->second.addSetting (setting);
619 }
620 
declareSubcategory(const std::string & label)621 void CSMPrefs::State::declareSubcategory(const std::string& label)
622 {
623     if (mCurrentCategory==mCategories.end())
624         throw std::logic_error ("no category for setting");
625 
626     CSMPrefs::Setting *setting =
627         new CSMPrefs::Setting (&mCurrentCategory->second, &mSettings, &mMutex, "", label);
628 
629     mCurrentCategory->second.addSetting (setting);
630 }
631 
setDefault(const std::string & key,const std::string & default_)632 void CSMPrefs::State::setDefault (const std::string& key, const std::string& default_)
633 {
634     Settings::CategorySetting fullKey (mCurrentCategory->second.getKey(), key);
635 
636     Settings::CategorySettingValueMap::iterator iter =
637         mSettings.mDefaultSettings.find (fullKey);
638 
639     if (iter==mSettings.mDefaultSettings.end())
640         mSettings.mDefaultSettings.insert (std::make_pair (fullKey, default_));
641 }
642 
State(const Files::ConfigurationManager & configurationManager)643 CSMPrefs::State::State (const Files::ConfigurationManager& configurationManager)
644 : mConfigFile ("openmw-cs.cfg"), mDefaultConfigFile("defaults-cs.bin"), mConfigurationManager (configurationManager),
645   mCurrentCategory (mCategories.end())
646 {
647     if (sThis)
648         throw std::logic_error ("An instance of CSMPRefs::State already exists");
649 
650     sThis = this;
651 
652     load();
653     declare();
654 }
655 
~State()656 CSMPrefs::State::~State()
657 {
658     sThis = nullptr;
659 }
660 
save()661 void CSMPrefs::State::save()
662 {
663     boost::filesystem::path user = mConfigurationManager.getUserConfigPath() / mConfigFile;
664     mSettings.saveUser (user.string());
665 }
666 
begin()667 CSMPrefs::State::Iterator CSMPrefs::State::begin()
668 {
669     return mCategories.begin();
670 }
671 
end()672 CSMPrefs::State::Iterator CSMPrefs::State::end()
673 {
674     return mCategories.end();
675 }
676 
getShortcutManager()677 CSMPrefs::ShortcutManager& CSMPrefs::State::getShortcutManager()
678 {
679     return mShortcutManager;
680 }
681 
operator [](const std::string & key)682 CSMPrefs::Category& CSMPrefs::State::operator[] (const std::string& key)
683 {
684     Iterator iter = mCategories.find (key);
685 
686     if (iter==mCategories.end())
687         throw std::logic_error ("Invalid user settings category: " + key);
688 
689     return iter->second;
690 }
691 
update(const Setting & setting)692 void CSMPrefs::State::update (const Setting& setting)
693 {
694     emit (settingChanged (&setting));
695 }
696 
get()697 CSMPrefs::State& CSMPrefs::State::get()
698 {
699     if (!sThis)
700         throw std::logic_error ("No instance of CSMPrefs::State");
701 
702     return *sThis;
703 }
704 
resetCategory(const std::string & category)705 void CSMPrefs::State::resetCategory(const std::string& category)
706 {
707     for (Settings::CategorySettingValueMap::iterator i = mSettings.mUserSettings.begin();
708          i != mSettings.mUserSettings.end(); ++i)
709     {
710         // if the category matches
711         if (i->first.first == category)
712         {
713             // mark the setting as changed
714             mSettings.mChangedSettings.insert(std::make_pair(i->first.first, i->first.second));
715             // reset the value to the default
716             i->second = mSettings.mDefaultSettings[i->first];
717         }
718     }
719 
720     Collection::iterator container = mCategories.find(category);
721     if (container != mCategories.end())
722     {
723         Category settings = container->second;
724         for (Category::Iterator i = settings.begin(); i != settings.end(); ++i)
725         {
726             (*i)->updateWidget();
727             update(**i);
728         }
729     }
730 }
731 
resetAll()732 void CSMPrefs::State::resetAll()
733 {
734     for (Collection::iterator iter = mCategories.begin(); iter != mCategories.end(); ++iter)
735     {
736         resetCategory(iter->first);
737     }
738 }
739 
740 
get()741 CSMPrefs::State& CSMPrefs::get()
742 {
743     return State::get();
744 }
745