1 /**
2  * Mandelbulber v2, a 3D fractal generator       ,=#MKNmMMKmmßMNWy,
3  *                                             ,B" ]L,,p%%%,,,§;, "K
4  * Copyright (C) 2016-21 Mandelbulber Team     §R-==%w["'~5]m%=L.=~5N
5  *                                        ,=mm=§M ]=4 yJKA"/-Nsaj  "Bw,==,,
6  * This file is part of Mandelbulber.    §R.r= jw",M  Km .mM  FW ",§=ß., ,TN
7  *                                     ,4R =%["w[N=7]J '"5=],""]]M,w,-; T=]M
8  * Mandelbulber is free software:     §R.ß~-Q/M=,=5"v"]=Qf,'§"M= =,M.§ Rz]M"Kw
9  * you can redistribute it and/or     §w "xDY.J ' -"m=====WeC=\ ""%""y=%"]"" §
10  * modify it under the terms of the    "§M=M =D=4"N #"%==A%p M§ M6  R' #"=~.4M
11  * GNU General Public License as        §W =, ][T"]C  §  § '§ e===~ U  !§[Z ]N
12  * published by the                    4M",,Jm=,"=e~  §  §  j]]""N  BmM"py=ßM
13  * Free Software Foundation,          ]§ T,M=& 'YmMMpM9MMM%=w=,,=MT]M m§;'§,
14  * either version 3 of the License,    TWw [.j"5=~N[=§%=%W,T ]R,"=="Y[LFT ]N
15  * or (at your option)                   TW=,-#"%=;[  =Q:["V""  ],,M.m == ]N
16  * any later version.                      J§"mr"] ,=,," =="""J]= M"M"]==ß"
17  *                                          §= "=C=4 §"eM "=B:m|4"]#F,§~
18  * Mandelbulber is distributed in            "9w=,,]w em%wJ '"~" ,=,,ß"
19  * the hope that it will be useful,                 . "K=  ,=RMMMßM"""
20  * but WITHOUT ANY WARRANTY;                            .'''
21  * without even the implied warranty
22  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
23  *
24  * See the GNU General Public License for more details.
25  * You should have received a copy of the GNU General Public License
26  * along with Mandelbulber. If not, see <http://www.gnu.org/licenses/>.
27  *
28  * ###########################################################################
29  *
30  * Authors: Krzysztof Marczak (buddhi1980@gmail.com)
31  *
32  * RenderWindow class - main program window
33  *
34  * This file contains implementation of the menu slots in RenderWindow class.
35  * See also header render_window.hpp and whole implementation of class
36  * spread over render_window_*.cpp
37  */
38 
39 #include "ui_render_window.h"
40 
41 #include "animation_flight.hpp"
42 #include "animation_keyframes.hpp"
43 #include "file_image.hpp"
44 #include "files.h"
45 #include "global_data.hpp"
46 #include "initparameters.hpp"
47 #include "interface.hpp"
48 #include "mandelbulb3d_settings.hpp"
49 #include "material_item_model.h"
50 #include "old_settings.hpp"
51 #include "render_window.hpp"
52 #include "settings.hpp"
53 #include "system.hpp"
54 #include "system_data.hpp"
55 #include "system_directories.hpp"
56 
57 #include "qt/image_save_dialog.h"
58 #include "qt/preview_file_dialog.h"
59 
slotImportOldSettings()60 void RenderWindow::slotImportOldSettings()
61 {
62 	QFileDialog dialog(this);
63 	dialog.setOption(QFileDialog::DontUseNativeDialog);
64 	dialog.setFileMode(QFileDialog::ExistingFile);
65 	dialog.setNameFilter(tr("Fractals (*.txt *.fract)"));
66 	dialog.setDirectory(
67 		QDir::toNativeSeparators(QFileInfo(systemData.lastSettingsFile).absolutePath()));
68 	dialog.selectFile(QDir::toNativeSeparators(systemData.lastSettingsFile));
69 	dialog.setAcceptMode(QFileDialog::AcceptOpen);
70 	dialog.setWindowTitle(tr("Import settings from old Mandelbulber (v1.21)..."));
71 	QStringList filenames;
72 	if (dialog.exec())
73 	{
74 		filenames = dialog.selectedFiles();
75 		QString filename = QDir::toNativeSeparators(filenames.first());
76 		oldSettings::cOldSettings oldSettings;
77 		oldSettings.LoadSettings(filename);
78 		oldSettings.ConvertToNewContainer(gPar, gParFractal);
79 		gMainInterface->RebuildPrimitives(gPar);
80 		gMainInterface->SynchronizeInterface(gPar, gParFractal, qInterface::write);
81 		gMainInterface->ComboMouseClickUpdate();
82 		systemData.lastSettingsFile = filename;
83 		setWindowTitle(QString("Mandelbulber (") + filename + ")");
84 	}
85 }
86 
slotImportMandelbulb3dSettings()87 void RenderWindow::slotImportMandelbulb3dSettings()
88 {
89 	QFileDialog dialog(this);
90 	dialog.setOption(QFileDialog::DontUseNativeDialog);
91 	dialog.setFileMode(QFileDialog::ExistingFile);
92 	dialog.setNameFilter(tr("Fractals (*.m3d *.fract)"));
93 	dialog.setDirectory(
94 		QDir::toNativeSeparators(QFileInfo(systemData.lastSettingsFile).absolutePath()));
95 	dialog.selectFile(QDir::toNativeSeparators(systemData.lastSettingsFile));
96 	dialog.setAcceptMode(QFileDialog::AcceptOpen);
97 	dialog.setWindowTitle(tr("Import settings from Mandelbulb3d settings file ..."));
98 	QStringList filenames;
99 	if (dialog.exec())
100 	{
101 		filenames = dialog.selectedFiles();
102 		QString filename = QDir::toNativeSeparators(filenames.first());
103 		cMandelbulb3dSettings m3dSettings;
104 		m3dSettings.LoadSettings(filename);
105 		m3dSettings.ConvertToNewContainer(gPar, gParFractal);
106 		gMainInterface->RebuildPrimitives(gPar);
107 		gMainInterface->SynchronizeInterface(gPar, gParFractal, qInterface::write);
108 		gMainInterface->ComboMouseClickUpdate();
109 		systemData.lastSettingsFile = filename;
110 		setWindowTitle(QString("Mandelbulber (") + filename + ")");
111 	}
112 }
113 
slotMenuAboutMandelbulber()114 void RenderWindow::slotMenuAboutMandelbulber()
115 {
116 	QString text = "<h2>Mandelbulber</h2>";
117 	text += "version: <b>" + QString(MANDELBULBER_VERSION_STRING) + "</b>" + "<br>";
118 	text += "<br>";
119 	text += "Licence: GNU GPL version 3.0<br>";
120 	text += "Copyright Ⓒ 2021<br>";
121 	text += "project leader: Krzysztof Marczak<br>";
122 	text += "Project contributors:<br>";
123 	text += "Sebastian Jennen, Graeme McLaren, Bernardo Martelli,<br>";
124 	text += "Robert Pancoast, knighty, makemeunsee, Marius Schilder,<br>";
125 	text += "Ryan Hitchman, Jeff Epler, Martin Reinecke, Quazgaa, Adrian Meyer<br>";
126 	text += "github:rikardfalkeborn, github:orbitcowboy, github:brunetton,<br>";
127 	text += "github:biberino, github:luchansky, github:jeroenrijckaert,<br>";
128 	text += "github:KoviRobi, github:psyriccio, github:valera-rozuvan,<br>";
129 	text += "github:probonopd, github:mia-0, github:gitter-badger, <br>";
130 	text += "github:danuni, github:Starmute<br>";
131 	text += "<br>";
132 	text += "Thanks to many friends from Mandelbulber community<br>";
133 	text +=
134 		"<a "
135 		"href=\"https://www.facebook.com/groups/mandelbulber/\">https://www.facebook.com/groups/"
136 		"mandelbulber/</a>";
137 	text += "<br>for help<br>";
138 	text += "<br>";
139 	text += "<a href=\"http://www.mandelbulber.com\">www.mandelbulber.com</a>";
140 
141 	QMessageBox::about(this, "About Mandelbulber", text);
142 }
143 
slotMenuAboutQt()144 void RenderWindow::slotMenuAboutQt()
145 {
146 	QMessageBox::aboutQt(this);
147 }
148 
slotMenuAboutManual()149 void RenderWindow::slotMenuAboutManual()
150 {
151 	// qDebug() << systemDirectories.docDir;
152 	QString filename = systemDirectories.docDir + "Mandelbulber_Manual.pdf";
153 	QDesktopServices::openUrl(QUrl::fromLocalFile(filename));
154 }
155 
slotMenuAboutNews()156 void RenderWindow::slotMenuAboutNews()
157 {
158 	QString filename = systemDirectories.docDir + "NEWS";
159 
160 	QFile f(filename);
161 	QString text = "";
162 	if (f.open(QIODevice::ReadOnly | QIODevice::Text))
163 	{
164 		text = f.readAll();
165 	}
166 
167 	QLabel *label = new QLabel;
168 	label->setText(text);
169 	label->setWordWrap(true);
170 	label->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
171 
172 	QScrollArea *scroll = new QScrollArea();
173 	scroll->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
174 	scroll->setWidget(label);
175 	scroll->setWidgetResizable(true);
176 
177 	QHBoxLayout *layout = new QHBoxLayout();
178 	layout->addWidget(scroll);
179 	QDialog *dialog = new QDialog();
180 	dialog->setLayout(layout);
181 	dialog->setWindowTitle(QObject::tr("News"));
182 	dialog->show();
183 }
184 
slotMenuAboutHotKeys()185 void RenderWindow::slotMenuAboutHotKeys()
186 {
187 	QString ctrlBadge =
188 		"<span style='background-color: #222; color: #FFF; padding: 3px;'>" + tr("Ctrl") + "</span>";
189 	QString altBadge =
190 		"<span style='background-color: #222; color: #FFF; padding: 3px;'>" + tr("Alt") + "</span>";
191 	QString shiftBadge =
192 		"<span style='background-color: #222; color: #FFF; padding: 3px;'>" + tr("Shift") + "</span>";
193 
194 	// Main program hotkeys
195 	QString style = "<style>td { padding: 2px; color: black;}</style>";
196 	QString text = "<table><tr>";
197 	text += "<td style='padding: 5px; background-color: #DDF'>";
198 	text += "<h3>" + tr("Main Program Hotkeys") + "</h3>";
199 	text += "<table border='1'>";
200 
201 	// File
202 	text += " <tr><th colspan='2'>" + tr("File") + "</th></tr>";
203 	text += " <tr><th>" + ctrlBadge + " + O</th><td>" + tr("Load settings...") + "</td></tr>";
204 	text +=
205 		" <tr><th>" + altBadge + " + O</th><td>" + tr("Load settings from clipboard...") + "</td></tr>";
206 	text += " <tr><th>" + ctrlBadge + " + " + altBadge + " + O</th><td>" + tr("Load example...")
207 					+ "</td></tr>";
208 	text += " <tr><th>" + ctrlBadge + " + S</th><td>" + tr("Save settings...") + "</td></tr>";
209 	text +=
210 		" <tr><th>" + altBadge + " + S</th><td>" + tr("Save settings to clipboard...") + "</td></tr>";
211 	text +=
212 		" <tr><th>" + ctrlBadge + " + I</th><td>" + tr("Import legacy settings...") + "</td></tr>";
213 
214 	text += " <tr><th>" + ctrlBadge + " + M</th><td>" + tr("Export Mesh") + "</td></tr>";
215 	text += " <tr><th>" + ctrlBadge + " + " + altBadge + " + S</th><td>" + tr("Save as Image...")
216 					+ "</td></tr>";
217 	text += " <tr><th>" + ctrlBadge + " + P</th><td>" + tr("Program Preferences") + "</td></tr>";
218 	text += " <tr><th>" + ctrlBadge + " + Q</th><td>" + tr("Quit") + "</td></tr>";
219 	text += " <tr><th>F11</th><td>" + tr("Full screen") + "</td></tr>";
220 	text += "</table>";
221 
222 	// Other
223 	text += "<table style='margin-top: 10px;' border='1'>";
224 	text += " <tr><th colspan='2'>" + tr("Other") + "</th></tr>";
225 	text += " <tr><th>" + ctrlBadge + " + Z</th><td>" + tr("Undo") + "</td></tr>";
226 	text += " <tr><th>" + ctrlBadge + " + Y</th><td>" + tr("Redo") + "</td></tr>";
227 	text += " <tr><th>" + ctrlBadge + " + H</th><td>" + tr("Show User Manual") + "</td></tr>";
228 	text += " <tr><th>" + altBadge + " + H</th><td>" + tr("Show (these) Hotkeys") + "</td></tr>";
229 	text +=
230 		" <tr><th>" + shiftBadge + " + ESC</th><td>" + tr("Terminate all calculations") + "</td></tr>";
231 	text += "</table>";
232 	text += "</td>";
233 
234 	// Render window hotkeys
235 	text += "<td style='padding: 5px; background-color: #DFD'>";
236 	text += "<h3>" + tr("Render Window Hotkeys") + "</h3>";
237 
238 	// Movement
239 	text += "<table border='1'>";
240 	text += " <tr><th colspan='2'>" + tr("Movement") + "</th></tr>";
241 	text +=
242 		" <tr><th>" + tr("Mouse left button click") + "</th><td>" + tr("jump forward") + "</td></tr>";
243 	text +=
244 		" <tr><th>" + tr("Mouse right button click") + "</th><td>" + tr("jump backward") + "</td></tr>";
245 	text += " <tr><th>" + ctrlBadge + " + " + tr("Mouse Wheel") + "</th><td>"
246 					+ tr("forward / backward") + "</td></tr>";
247 	text += " <tr><th>" + tr("Mouse left+right buttons drag") + "</th><td>" + tr("Move camera")
248 					+ "</td></tr>";
249 
250 	text += " <tr><th>W</th><td>" + tr("up") + "</td></tr>";
251 	text += " <tr><th>S</th><td>" + tr("down") + "</td></tr>";
252 	text += " <tr><th>A</th><td>" + tr("left") + "</td></tr>";
253 	text +=
254 		" <tr><th>" + shiftBadge + " + " + tr("Arrow left") + "</th><td>" + tr("left") + "</td></tr>";
255 	text += " <tr><th>D</th><td>" + tr("right") + "</td></tr>";
256 	text +=
257 		" <tr><th>" + shiftBadge + " + " + tr("Arrow right") + "</th><td>" + tr("right") + "</td></tr>";
258 	text += " <tr><th>Q</th><td>" + tr("forward") + "</td></tr>";
259 	text +=
260 		" <tr><th>" + ctrlBadge + " + " + tr("Arrow up") + "</th><td>" + tr("forward") + "</td></tr>";
261 	text +=
262 		" <tr><th>" + shiftBadge + " + " + tr("Arrow up") + "</th><td>" + tr("forward") + "</td></tr>";
263 	text += " <tr><th>Z</th><td>" + tr("backward") + "</td></tr>";
264 	text += " <tr><th>" + ctrlBadge + " + " + tr("Arrow down") + "</th><td>" + tr("backward")
265 					+ "</td></tr>";
266 	text += " <tr><th>" + shiftBadge + " + " + tr("Arrow down") + "</th><td>" + tr("backward")
267 					+ "</td></tr>";
268 	text += "</table>";
269 
270 	// Rotation
271 	text += "<table style='margin-top: 10px;' border='1'>";
272 	text += " <tr><th colspan='2'>" + tr("Rotation") + "</th></tr>";
273 	text +=
274 		" <tr><th>" + tr("Mouse left button drag") + "</th><td>" + tr("Rotate camera") + "</td></tr>";
275 	text += " <tr><th>" + tr("Mouse right button drag") + "</th><td>"
276 					+ tr("Rotate camera around point") + "</td></tr>";
277 	text +=
278 		" <tr><th>" + tr("Mouse middle button drag") + "</th><td>" + tr("Roll camera") + "</td></tr>";
279 	text += " <tr><th>" + tr("Arrow up") + "</th><td>" + tr("up") + "</td></tr>";
280 	text += " <tr><th>" + tr("Arrow down") + "</th><td>" + tr("down") + "</td></tr>";
281 	text += " <tr><th>" + tr("Arrow left") + "</th><td>" + tr("left") + "</td></tr>";
282 	text += " <tr><th>" + tr("Arrow right") + "</th><td>" + tr("right") + "</td></tr>";
283 	text += " <tr><th>" + ctrlBadge + " + " + tr("Arrow left") + "</th><td>" + tr("Roll left")
284 					+ "</td></tr>";
285 	text += " <tr><th>" + ctrlBadge + " + " + tr("Arrow right") + "</th><td>" + tr("Roll right")
286 					+ "</td></tr>";
287 	text += "</table>";
288 
289 	// Render Window, Keyframe, Flight
290 	text += "<td style='padding: 5px; background-color: #FDD'>";
291 	text += "<h3>" + tr("Render Window Keyframe / Flight") + "</h3>";
292 
293 	// Flight
294 	text += "<table border='1'>";
295 	text += " <tr><th colspan='2'>" + tr("Flight") + "</th></tr>";
296 	text += " <tr><th>" + tr("Left mouse click") + "</th><td>" + tr("Increase speed") + "</td></tr>";
297 	text += " <tr><th>" + tr("Right mouse click") + "</th><td>" + tr("Decrease speed") + "</td></tr>";
298 	text +=
299 		" <tr><th>" + tr("Arrow keys") + "</th><td>" + tr("Move forward and sideward") + "</td></tr>";
300 	text += " <tr><th>" + shiftBadge + "+" + tr("Arrow keys") + "</th><td>" + tr("Move sideward only")
301 					+ "</td></tr>";
302 	text += " <tr><th>" + tr("Spacebar") + "</th><td>" + tr("Pause / Unpause") + "</td></tr>";
303 	text += " <tr><th>Z, X</th><td>" + tr("Roll rotation") + "</td></tr>";
304 	text += "</table>";
305 
306 	// Keyframe
307 	text += "<table style='margin-top: 10px;' border='1'>";
308 	text += " <tr><th colspan='2'>" + tr("Keyframe") + "</th></tr>";
309 	text += " <tr><th>I</th><td>" + tr("Add Keyframe") + "</td></tr>";
310 	text += " <tr><th>M</th><td>" + tr("Modify current Keyframe") + "</td></tr>";
311 	text += " <tr><th>N</th><td>" + tr("Move to next Keyframe") + "</td></tr>";
312 	text += " <tr><th>P</th><td>" + tr("Move to previous Keyframe") + "</td></tr>";
313 	text += "</table>";
314 
315 	text += "</td>";
316 	text += "</tr></table>";
317 
318 	QLabel *label = new QLabel;
319 	label->setText(style + text);
320 	QVBoxLayout *layout = new QVBoxLayout();
321 	layout->addWidget(label);
322 	QDialog *dialog = new QDialog(this);
323 	dialog->setLayout(layout);
324 	dialog->setWindowTitle(QObject::tr("HotKeys Cheatsheet"));
325 	dialog->show();
326 }
327 
slotMenuAboutThirdParty()328 void RenderWindow::slotMenuAboutThirdParty()
329 {
330 	QString text = "<h2>Third Party</h2>";
331 	text += "<ul>";
332 	text += " <li><b>Dark Skin</b> based on <br>";
333 	text +=
334 		"		<a "
335 		"href=\"https://gist.github.com/QuantumCD/6245215\">gist.github.com/QuantumCD/6245215</"
336 		"a><br>thanks to QuantumCD</li>";
337 	text += " <li><b>Code highlighting in ui files</b><br>generated with<br>";
338 	text +=
339 		"		<a "
340 		"href=\"http://www.andre-simon.de/doku/highlight/highlight.php\">highlight</a><br>thanks to "
341 		"André Simon</li>";
342 	text += " <li><b>Export Mesh </b><br>generated with<br>";
343 	text +=
344 		"		<a "
345 		"href=\"https://github.com/pmneila/PyMCubes/\">PyMCubes</a><br>thanks to "
346 		"P. M. Neila</li>";
347 	text += " <li><b>Export Mesh </b><br>Designed with<br>";
348 	text +=
349 		"		<a "
350 		"href=\"http://algoholic.eu/export-meshes-from-mandelbulber/\">Stanford (PLY) mesh format "
351 		"Support</a><br>thanks to "
352 		"Stanislaw Adaszewski</li>";
353 	text += " <li><b>Fonts</b><br>";
354 	text +=
355 		"		<a href=\"http://typodermicfonts.com/\">Nasalization</a><br>"
356 		"thanks to Typodermic Fonts Inc.<br>";
357 	text += " For more information about font licenses, see README in fonts folder.</li>";
358 	text += "</ul>";
359 	QMessageBox::about(this, "About Third Party", text);
360 }
361 
showDescriptionPopup()362 void RenderWindow::showDescriptionPopup()
363 {
364 	if (gPar->Get<bool>("description_popup_do_not_show_again")) return;
365 	if (gPar->Get<QString>("description") == "") return;
366 
367 	QMessageBox *messageBox = new QMessageBox(this);
368 	messageBox->setText(gPar->Get<QString>("description"));
369 	messageBox->setWindowTitle(QObject::tr("Description"));
370 	messageBox->setIcon(QMessageBox::Information);
371 	messageBox->addButton(QMessageBox::Ok);
372 	QAbstractButton *btnOkDoNotShowAgain =
373 		messageBox->addButton(QObject::tr("Ok, don't show again"), QMessageBox::YesRole);
374 	messageBox->setDefaultButton(QMessageBox::Ok);
375 	int result = messageBox->exec();
376 	Q_UNUSED(result);
377 	if (messageBox->clickedButton() == btnOkDoNotShowAgain)
378 	{
379 		gPar->Set("description_popup_do_not_show_again", true);
380 	}
381 }
382 
SaveSettingsToRecent(QString fileName)383 void RenderWindow::SaveSettingsToRecent(QString fileName)
384 {
385 	QFile recentFilesFile(systemDirectories.GetRecentFilesListFile());
386 	QStringList recentFiles;
387 	if (recentFilesFile.open(QFile::ReadOnly | QFile::Text))
388 	{
389 		QTextStream in(&recentFilesFile);
390 		QString recentFilesFileContent = in.readAll();
391 		recentFilesFile.close();
392 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
393 		recentFiles = recentFilesFileContent.split(QRegExp("\n|\r\n|\r"), QString::KeepEmptyParts);
394 #else
395 		recentFiles = recentFilesFileContent.split(QRegExp("\n|\r\n|\r"), Qt::KeepEmptyParts);
396 #endif
397 		recentFiles.removeOne(fileName);
398 	}
399 	recentFiles.prepend(fileName);
400 	if (recentFiles.size() > 15) recentFiles.removeLast();
401 	if (!recentFilesFile.open(QFile::WriteOnly | QFile::Text))
402 	{
403 		qCritical() << "Cannot open file to save as recent!";
404 		return;
405 	}
406 	QTextStream out(&recentFilesFile);
407 	out << recentFiles.join("\n");
408 	recentFilesFile.close();
409 	slotPopulateRecentSettings();
410 }
411 
slotMenuLoadExample()412 void RenderWindow::slotMenuLoadExample()
413 {
414 	PreviewFileDialog dialog(this);
415 	dialog.setOption(QFileDialog::DontUseNativeDialog);
416 	dialog.setFileMode(QFileDialog::ExistingFile);
417 	dialog.setNameFilter(tr("Fractals (*.txt *.fract)"));
418 	dialog.setDirectory(QDir::toNativeSeparators(
419 		systemDirectories.sharedDir + QDir::separator() + "examples" + QDir::separator()));
420 	dialog.selectFile(QDir::toNativeSeparators(QFileInfo(systemData.lastSettingsFile).fileName()));
421 	dialog.setAcceptMode(QFileDialog::AcceptOpen);
422 	dialog.setWindowTitle(tr("Load example settings..."));
423 	QStringList filenames;
424 	if (dialog.exec())
425 	{
426 		filenames = dialog.selectedFiles();
427 		QString filename = QDir::toNativeSeparators(filenames.first());
428 		slotMenuLoadSettingsFromFile(filename);
429 	}
430 }
431 
slotMenuLoadSettings()432 void RenderWindow::slotMenuLoadSettings()
433 {
434 	gMainInterface->SynchronizeInterface(
435 		gPar, gParFractal, qInterface::read); // update appParam before loading new settings
436 
437 	PreviewFileDialog dialog(this);
438 	dialog.setOption(QFileDialog::DontUseNativeDialog);
439 	dialog.setFileMode(QFileDialog::ExistingFile);
440 	dialog.setNameFilter(tr("Fractals (*.txt *.fract)"));
441 	dialog.setDirectory(
442 		QDir::toNativeSeparators(QFileInfo(systemData.lastSettingsFile).absolutePath()));
443 	dialog.selectFile(QDir::toNativeSeparators(systemData.lastSettingsFile));
444 	dialog.setAcceptMode(QFileDialog::AcceptOpen);
445 	dialog.setWindowTitle(tr("Load settings..."));
446 	QStringList filenames;
447 	if (dialog.exec())
448 	{
449 		filenames = dialog.selectedFiles();
450 		QString filename = QDir::toNativeSeparators(filenames.first());
451 		slotMenuLoadSettingsFromFile(filename);
452 	}
453 }
454 
slotMenuLoadSettingsFromFile(QString fileName)455 void RenderWindow::slotMenuLoadSettingsFromFile(QString fileName)
456 {
457 	cSettings parSettings(cSettings::formatFullText);
458 	gMainInterface->DisablePeriodicRefresh();
459 	gInterfaceReadyForSynchronization = false;
460 	parSettings.LoadFromFile(fileName);
461 	parSettings.Decode(gPar, gParFractal, gAnimFrames, gKeyframes);
462 	gMainInterface->RebuildPrimitives(gPar);
463 	gMainInterface->materialListModel->Regenerate();
464 	ui->widgetEffects->RegenerateLights();
465 
466 	gMainInterface->SynchronizeInterface(gPar, gParFractal, qInterface::write);
467 	gInterfaceReadyForSynchronization = true;
468 
469 	gMainInterface->ComboMouseClickUpdate();
470 	systemData.lastSettingsFile = fileName;
471 	SaveSettingsToRecent(fileName);
472 	setWindowTitle(QString("Mandelbulber (") + fileName + ")");
473 	gFlightAnimation->RefreshTable();
474 	gKeyframeAnimation->RefreshTable();
475 	showDescriptionPopup();
476 }
477 
slotMenuLoadSettingsFromClipboard()478 void RenderWindow::slotMenuLoadSettingsFromClipboard()
479 {
480 	gMainInterface->DisablePeriodicRefresh();
481 
482 	gMainInterface->SynchronizeInterface(
483 		gPar, gParFractal, qInterface::read); // update appParam before loading new settings
484 
485 	cSettings parSettings(cSettings::formatFullText);
486 
487 	if (parSettings.LoadFromClipboard())
488 	{
489 		gMainInterface->DisablePeriodicRefresh();
490 		gInterfaceReadyForSynchronization = false;
491 		parSettings.Decode(gPar, gParFractal, gAnimFrames, gKeyframes);
492 		gMainInterface->RebuildPrimitives(gPar);
493 		gMainInterface->materialListModel->Regenerate();
494 		ui->widgetEffects->RegenerateLights();
495 
496 		gMainInterface->SynchronizeInterface(gPar, gParFractal, qInterface::write);
497 		gInterfaceReadyForSynchronization = true;
498 
499 		gMainInterface->ComboMouseClickUpdate();
500 		systemData.lastSettingsFile = "from clipboard";
501 		setWindowTitle(QString("Mandelbulber (") + "from clipboard" + ")");
502 		gFlightAnimation->RefreshTable();
503 		gKeyframeAnimation->RefreshTable();
504 		gMainInterface->ReEnablePeriodicRefresh();
505 		showDescriptionPopup();
506 	}
507 	else
508 	{
509 		cErrorMessage::showMessage(QObject::tr("Cannot load settings from clipboard!"),
510 			cErrorMessage::errorMessage, gMainInterface->mainWindow);
511 	}
512 }
513 
slotMenuRedo()514 void RenderWindow::slotMenuRedo()
515 {
516 	gMainInterface->Redo();
517 }
518 
ResetDocksPositions()519 void RenderWindow::ResetDocksPositions()
520 {
521 	// restoreGeometry(defaultGeometry);
522 	restoreState(defaultState);
523 	setCorner(Qt::TopLeftCorner, Qt::LeftDockWidgetArea);
524 	setCorner(Qt::TopRightCorner, Qt::RightDockWidgetArea);
525 	setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea);
526 	setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea);
527 }
528 
slotMenuResetDocksPositions()529 void RenderWindow::slotMenuResetDocksPositions()
530 {
531 	// restoreState(gMainInterface->settings.value("mainWindowState").toByteArray());
532 	ResetDocksPositions();
533 	ui->dockWidget_histogram->hide();
534 	ui->dockWidget_info->hide();
535 	ui->dockWidget_queue_dock->hide();
536 	ui->dockWidget_animation->hide();
537 	ui->dockWidget_measurement->hide();
538 	ui->dockWidget_gamepad_dock->hide();
539 
540 	tabifyDockWidget(ui->dockWidget_materialEditor, ui->dockWidget_effects);
541 	tabifyDockWidget(ui->dockWidget_effects, ui->dockWidget_image_adjustments);
542 	tabifyDockWidget(ui->dockWidget_image_adjustments, ui->dockWidget_rendering_engine);
543 	tabifyDockWidget(ui->dockWidget_rendering_engine, ui->dockWidget_objects);
544 	tabifyDockWidget(ui->dockWidget_objects, ui->dockWidget_histogram);
545 
546 	addDockWidget(Qt::LeftDockWidgetArea, ui->dockWidget_Materials);
547 }
548 
slotMenuAnimationDocksPositions()549 void RenderWindow::slotMenuAnimationDocksPositions()
550 {
551 	ResetDocksPositions();
552 	ui->dockWidget_histogram->hide();
553 	ui->dockWidget_info->hide();
554 	ui->dockWidget_animation->show();
555 	ui->toolBar->hide();
556 #ifdef USE_GAMEPAD
557 	ui->dockWidget_gamepad_dock->hide();
558 #endif
559 	ui->dockWidget_queue_dock->hide();
560 
561 	tabifyDockWidget(ui->dockWidget_materialEditor, ui->dockWidget_effects);
562 	tabifyDockWidget(ui->dockWidget_effects, ui->dockWidget_image_adjustments);
563 	tabifyDockWidget(ui->dockWidget_image_adjustments, ui->dockWidget_rendering_engine);
564 	tabifyDockWidget(ui->dockWidget_rendering_engine, ui->dockWidget_objects);
565 	tabifyDockWidget(ui->dockWidget_objects, ui->dockWidget_histogram);
566 
567 	addDockWidget(Qt::LeftDockWidgetArea, ui->dockWidget_Materials);
568 }
569 
slotMenuSaveDocksPositions()570 void RenderWindow::slotMenuSaveDocksPositions()
571 {
572 	gMainInterface->settings.setValue("mainWindowGeometry", saveGeometry());
573 	gMainInterface->settings.setValue("mainWindowState", saveState());
574 	// qDebug() << "settings saved";
575 }
576 
slotMenuSaveImageAll()577 void RenderWindow::slotMenuSaveImageAll()
578 {
579 	cImageSaveDialog dialog(this);
580 	dialog.setFileMode(QFileDialog::AnyFile);
581 	QStringList filters;
582 	filters << tr("images (*.jpg *.jpeg *.png *.exr *.tiff)");
583 	dialog.setNameFilters(filters);
584 	dialog.setDirectory(QDir::toNativeSeparators(QFileInfo(systemData.lastImageFile).absolutePath()));
585 	dialog.selectFile(QDir::toNativeSeparators(systemData.GetImageFileNameSuggestion()));
586 	dialog.setAcceptMode(QFileDialog::AcceptSave);
587 	dialog.setWindowTitle(tr("Save image to file..."));
588 	QStringList filenames;
589 	if (dialog.exec())
590 	{
591 		filenames = dialog.selectedFiles();
592 		QString filename = QDir::toNativeSeparators(filenames.first());
593 		ImageFileSave::enumImageFileType imageFileType =
594 			ImageFileSave::ImageFileType(QFileInfo(filename).suffix());
595 		gApplication->processEvents();
596 		SaveImage(filename, imageFileType, gMainInterface->mainImage, gMainInterface->mainWindow);
597 		gApplication->processEvents();
598 		systemData.lastImageFile = filename;
599 	}
600 }
601 
slotMenuSaveImageJPEG()602 void RenderWindow::slotMenuSaveImageJPEG()
603 {
604 	slotMenuSaveImage(
605 		ImageFileSave::IMAGE_FILE_TYPE_JPG, tr("JPEG images (*.jpg *.jpeg)"), "JPEG", "jpeg");
606 }
607 
slotMenuSaveImagePNG()608 void RenderWindow::slotMenuSaveImagePNG()
609 {
610 	slotMenuSaveImage(ImageFileSave::IMAGE_FILE_TYPE_PNG, tr("PNG images (*.png)"), "PNG", "png");
611 }
612 
613 #ifdef USE_EXR
slotMenuSaveImageEXR()614 void RenderWindow::slotMenuSaveImageEXR()
615 {
616 	slotMenuSaveImage(ImageFileSave::IMAGE_FILE_TYPE_EXR, tr("EXR images (*.exr)"), "EXR", "exr");
617 }
618 #endif // USE_EXR
619 
620 #ifdef USE_TIFF
slotMenuSaveImageTIFF()621 void RenderWindow::slotMenuSaveImageTIFF()
622 {
623 	slotMenuSaveImage(
624 		ImageFileSave::IMAGE_FILE_TYPE_TIFF, tr("TIFF images (*.tiff)"), "TIFF", "tiff");
625 }
626 #endif // USE_TIFF
627 
slotMenuSaveImage(ImageFileSave::enumImageFileType imageFileType,QString nameFilter,QString titleType,QString defaultSuffix)628 void RenderWindow::slotMenuSaveImage(ImageFileSave::enumImageFileType imageFileType,
629 	QString nameFilter, QString titleType, QString defaultSuffix)
630 {
631 	cImageSaveDialog dialog(this);
632 	dialog.setFileMode(QFileDialog::AnyFile);
633 	dialog.setNameFilter(nameFilter);
634 	dialog.setDirectory(QDir::toNativeSeparators(QFileInfo(systemData.lastImageFile).absolutePath()));
635 	dialog.selectFile(QDir::toNativeSeparators(systemData.GetImageFileNameSuggestion()));
636 	dialog.setAcceptMode(QFileDialog::AcceptSave);
637 	dialog.setWindowTitle(tr("Save image to %1 file...").arg(titleType));
638 	dialog.setDefaultSuffix(defaultSuffix);
639 	QStringList filenames;
640 	if (dialog.exec())
641 	{
642 		filenames = dialog.selectedFiles();
643 		QString filename = QDir::toNativeSeparators(filenames.first());
644 		gApplication->processEvents();
645 		SaveImage(filename, imageFileType, gMainInterface->mainImage, gMainInterface->mainWindow);
646 		gApplication->processEvents();
647 		systemData.lastImageFile = filename;
648 	}
649 }
650 
slotMenuSaveImagePNG16()651 void RenderWindow::slotMenuSaveImagePNG16()
652 {
653 	QFileDialog dialog(this);
654 	dialog.setFileMode(QFileDialog::AnyFile);
655 	dialog.setNameFilter(tr("PNG images (*.png)"));
656 	dialog.setDirectory(QDir::toNativeSeparators(QFileInfo(systemData.lastImageFile).absolutePath()));
657 	dialog.selectFile(QDir::toNativeSeparators(systemData.GetImageFileNameSuggestion()));
658 	dialog.setAcceptMode(QFileDialog::AcceptSave);
659 	dialog.setWindowTitle(tr("Save image to %1 file...").arg("16-bit PNG"));
660 	dialog.setDefaultSuffix("png");
661 	QStringList filenames;
662 	if (dialog.exec())
663 	{
664 		filenames = dialog.selectedFiles();
665 		QString filename = QDir::toNativeSeparators(filenames.first());
666 		cProgressText::ProgressStatusText(tr("Saving %1 image").arg("16-bit PNG"),
667 			tr("Saving image started"), 0.0, cProgressText::progress_IMAGE);
668 		gApplication->processEvents();
669 		ImageFileSave::structSaveImageChannel saveImageChannel(
670 			ImageFileSave::IMAGE_CONTENT_COLOR, ImageFileSave::IMAGE_CHANNEL_QUALITY_16, "");
671 		ImageFileSave::ImageConfig imageConfig;
672 		imageConfig.insert(ImageFileSave::IMAGE_CONTENT_COLOR, saveImageChannel);
673 		ImageFileSavePNG imageSaver(
674 			ImageFileSave::ImageNameWithoutExtension(filename), gMainInterface->mainImage, imageConfig);
675 		imageSaver.SetAppendAlphaCustom(false);
676 		imageSaver.SaveImage();
677 		cProgressText::ProgressStatusText(tr("Saving %1 image").arg("16-bit PNG"),
678 			tr("Saving image finished"), 1.0, cProgressText::progress_IMAGE);
679 		gApplication->processEvents();
680 		systemData.lastImageFile = filename;
681 	}
682 }
683 
slotMenuSaveImagePNG16Alpha()684 void RenderWindow::slotMenuSaveImagePNG16Alpha()
685 {
686 	QFileDialog dialog(this);
687 	dialog.setFileMode(QFileDialog::AnyFile);
688 	dialog.setNameFilter(tr("PNG images (*.png)"));
689 	dialog.setDirectory(QDir::toNativeSeparators(QFileInfo(systemData.lastImageFile).absolutePath()));
690 	dialog.selectFile(QDir::toNativeSeparators(systemData.GetImageFileNameSuggestion()));
691 	dialog.setAcceptMode(QFileDialog::AcceptSave);
692 	dialog.setWindowTitle(tr("Save image to %1 file...").arg("16-bit PNG + alpha channel"));
693 	dialog.setDefaultSuffix("png");
694 	QStringList filenames;
695 	if (dialog.exec())
696 	{
697 		filenames = dialog.selectedFiles();
698 		QString filename = QDir::toNativeSeparators(filenames.first());
699 		cProgressText::ProgressStatusText(tr("Saving %1 image").arg("16-bit PNG + alpha channel"),
700 			tr("Saving image started"), 0.0, cProgressText::progress_IMAGE);
701 		gApplication->processEvents();
702 		ImageFileSave::structSaveImageChannel saveImageChannel(
703 			ImageFileSave::IMAGE_CONTENT_COLOR, ImageFileSave::IMAGE_CHANNEL_QUALITY_16, "");
704 		ImageFileSave::ImageConfig imageConfig;
705 		imageConfig.insert(ImageFileSave::IMAGE_CONTENT_COLOR, saveImageChannel);
706 		ImageFileSavePNG imageSaver(
707 			ImageFileSave::ImageNameWithoutExtension(filename), gMainInterface->mainImage, imageConfig);
708 		imageSaver.SetAppendAlphaCustom(true);
709 		imageSaver.SaveImage();
710 		cProgressText::ProgressStatusText(tr("Saving %1 image").arg("16-bit PNG + alpha channel"),
711 			tr("Saving image finished"), 1.0, cProgressText::progress_IMAGE);
712 		gApplication->processEvents();
713 		systemData.lastImageFile = filename;
714 	}
715 }
716 
slotMenuSaveSettings()717 void RenderWindow::slotMenuSaveSettings()
718 {
719 	cSettings parSettings(cSettings::formatCondensedText);
720 	gMainInterface->SynchronizeInterface(gPar, gParFractal, qInterface::read);
721 	parSettings.CreateText(gPar, gParFractal, gAnimFrames, gKeyframes);
722 
723 	QFileDialog dialog(this);
724 	dialog.setOption(QFileDialog::DontUseNativeDialog);
725 	dialog.setFileMode(QFileDialog::AnyFile);
726 	dialog.setNameFilter(tr("Fractals (*.txt *.fract)"));
727 	dialog.setDirectory(
728 		QDir::toNativeSeparators(QFileInfo(systemData.lastSettingsFile).absolutePath()));
729 	dialog.selectFile(
730 		QDir::toNativeSeparators(QFileInfo(systemData.lastSettingsFile).completeBaseName()));
731 	dialog.setAcceptMode(QFileDialog::AcceptSave);
732 	dialog.setWindowTitle(tr("Save settings..."));
733 	dialog.setDefaultSuffix("fract");
734 	QStringList filenames;
735 	if (dialog.exec())
736 	{
737 		filenames = dialog.selectedFiles();
738 		QString filename = QDir::toNativeSeparators(filenames.first());
739 		parSettings.SaveToFile(filename);
740 		systemData.lastSettingsFile = filename;
741 		SaveSettingsToRecent(filename);
742 		setWindowTitle(QString("Mandelbulber (") + filename + ")");
743 
744 		// QString hash = parSettings.GetHashCode();
745 		// cThumbnail thumbnail(gPar, gParFractal, 200, 200);
746 		// thumbnail.Render();
747 		// thumbnail.Save(systemData.thumbnailDir + hash);
748 	}
749 }
750 
slotMenuSaveSettingsToClipboard()751 void RenderWindow::slotMenuSaveSettingsToClipboard()
752 {
753 	cSettings parSettings(cSettings::formatCondensedText);
754 	gMainInterface->SynchronizeInterface(gPar, gParFractal, qInterface::read);
755 	parSettings.CreateText(gPar, gParFractal, gAnimFrames, gKeyframes);
756 	parSettings.SaveToClipboard();
757 	cErrorMessage::showMessage(
758 		QObject::tr("Settings saved to clipboard"), cErrorMessage::infoMessage);
759 }
760 
slotMenuUndo()761 void RenderWindow::slotMenuUndo()
762 {
763 	gMainInterface->Undo();
764 }
765 
slotMenuRenderImage()766 void RenderWindow::slotMenuRenderImage()
767 {
768 	gMainInterface->StartRender();
769 }
770 
slotMenuStopRendering()771 void RenderWindow::slotMenuStopRendering()
772 {
773 	gMainInterface->stopRequest = true;
774 }
775 
slotUpdateDocksAndToolbarByAction()776 void RenderWindow::slotUpdateDocksAndToolbarByAction()
777 {
778 	// Animation dock
779 	if (ui->actionShow_animation_dock->isChecked() != ui->dockWidget_animation->isVisible())
780 	{
781 		if (ui->actionShow_animation_dock->isChecked())
782 		{
783 			addDockWidget(Qt::BottomDockWidgetArea, ui->dockWidget_animation);
784 		}
785 		else
786 		{
787 			removeDockWidget(ui->dockWidget_animation);
788 		}
789 		ui->dockWidget_animation->setVisible(ui->actionShow_animation_dock->isChecked());
790 	}
791 
792 	// Information dock
793 	if (ui->actionShow_info_dock->isChecked() != ui->dockWidget_info->isVisible())
794 	{
795 		if (ui->actionShow_info_dock->isChecked())
796 		{
797 			addDockWidget(Qt::LeftDockWidgetArea, ui->dockWidget_info);
798 		}
799 		else
800 		{
801 			removeDockWidget(ui->dockWidget_info);
802 		}
803 		ui->dockWidget_info->setVisible(ui->actionShow_info_dock->isChecked());
804 	}
805 
806 	// Histogram dock
807 	if (ui->actionShow_statistics_dock->isChecked() != ui->dockWidget_histogram->isVisible())
808 	{
809 		if (ui->actionShow_statistics_dock->isChecked())
810 		{
811 			addDockWidget(Qt::LeftDockWidgetArea, ui->dockWidget_histogram);
812 		}
813 		else
814 		{
815 			removeDockWidget(ui->dockWidget_histogram);
816 		}
817 		ui->dockWidget_histogram->setVisible(ui->actionShow_statistics_dock->isChecked());
818 	}
819 
820 	// Toolbar
821 	if (ui->actionShow_toolbar->isChecked() != ui->toolBar->isVisible())
822 	{
823 		ui->toolBar->setVisible(ui->actionShow_toolbar->isChecked());
824 	}
825 
826 // Gamepad dock
827 #ifdef USE_GAMEPAD
828 	if (ui->actionShow_gamepad_dock->isChecked() != ui->dockWidget_gamepad_dock->isVisible())
829 	{
830 		if (ui->actionShow_gamepad_dock->isChecked())
831 		{
832 			addDockWidget(Qt::RightDockWidgetArea, ui->dockWidget_gamepad_dock);
833 		}
834 		else
835 		{
836 			removeDockWidget(ui->dockWidget_gamepad_dock);
837 		}
838 		ui->dockWidget_gamepad_dock->setVisible(ui->actionShow_gamepad_dock->isChecked());
839 	}
840 #endif
841 
842 	// Queue dock
843 	if (ui->actionShow_queue_dock->isChecked() != ui->dockWidget_queue_dock->isVisible())
844 	{
845 		if (ui->actionShow_queue_dock->isChecked())
846 		{
847 			addDockWidget(Qt::RightDockWidgetArea, ui->dockWidget_queue_dock);
848 		}
849 		else
850 		{
851 			removeDockWidget(ui->dockWidget_queue_dock);
852 		}
853 		ui->dockWidget_queue_dock->setVisible(ui->actionShow_queue_dock->isChecked());
854 	}
855 
856 	// Queue dock
857 	if (ui->actionShow_measurement_dock->isChecked() != ui->dockWidget_measurement->isVisible())
858 	{
859 		if (ui->actionShow_measurement_dock->isChecked())
860 		{
861 			addDockWidget(Qt::RightDockWidgetArea, ui->dockWidget_measurement);
862 		}
863 		else
864 		{
865 			removeDockWidget(ui->dockWidget_measurement);
866 		}
867 		ui->dockWidget_measurement->setVisible(ui->actionShow_measurement_dock->isChecked());
868 	}
869 }
870 
slotUpdateDocksAndToolbarByView() const871 void RenderWindow::slotUpdateDocksAndToolbarByView() const
872 {
873 	// Animation dock
874 	if (ui->actionShow_animation_dock->isChecked() != ui->dockWidget_animation->isVisible())
875 	{
876 		ui->actionShow_animation_dock->setChecked(ui->dockWidget_animation->isVisible());
877 	}
878 
879 	// Log dock
880 	if (ui->actionShow_info_dock->isChecked() != ui->dockWidget_info->isVisible())
881 	{
882 		ui->actionShow_info_dock->setChecked(ui->dockWidget_info->isVisible());
883 	}
884 
885 	// Histogram dock
886 	if (ui->actionShow_statistics_dock->isChecked() != ui->dockWidget_histogram->isVisible())
887 	{
888 		ui->actionShow_statistics_dock->setChecked(ui->dockWidget_histogram->isVisible());
889 	}
890 
891 	// Toolbar
892 	if (ui->actionShow_toolbar->isChecked() != ui->toolBar->isVisible())
893 	{
894 		ui->actionShow_toolbar->setChecked(ui->toolBar->isVisible());
895 	}
896 
897 #ifdef USE_GAMEPAD
898 	// Gamepad dock
899 	if (ui->actionShow_gamepad_dock->isChecked() != ui->dockWidget_gamepad_dock->isVisible())
900 	{
901 		ui->actionShow_gamepad_dock->setChecked(ui->dockWidget_gamepad_dock->isVisible());
902 	}
903 #endif
904 
905 	// Queue dock
906 	if (ui->actionShow_queue_dock->isChecked() != ui->dockWidget_queue_dock->isVisible())
907 	{
908 		ui->actionShow_queue_dock->setChecked(ui->dockWidget_queue_dock->isVisible());
909 	}
910 
911 	// Queue dock
912 	if (ui->actionShow_measurement_dock->isChecked() != ui->dockWidget_measurement->isVisible())
913 	{
914 		ui->actionShow_measurement_dock->setChecked(ui->dockWidget_measurement->isVisible());
915 	}
916 }
917 
slotStackAllDocks()918 void RenderWindow::slotStackAllDocks()
919 {
920 	tabifyDockWidget(ui->dockWidget_materialEditor, ui->dockWidget_effects);
921 	tabifyDockWidget(ui->dockWidget_effects, ui->dockWidget_image_adjustments);
922 	tabifyDockWidget(ui->dockWidget_image_adjustments, ui->dockWidget_rendering_engine);
923 	tabifyDockWidget(ui->dockWidget_rendering_engine, ui->dockWidget_objects);
924 	tabifyDockWidget(ui->dockWidget_objects, ui->dockWidget_histogram);
925 	tabifyDockWidget(ui->dockWidget_histogram, ui->dockWidget_info);
926 }
927 
slotDetachMainImage()928 void RenderWindow::slotDetachMainImage()
929 {
930 	if (ui->actionDetach_image_from_main_window->isChecked())
931 	{
932 		gMainInterface->DetachMainImageWidget();
933 	}
934 	else
935 	{
936 		gMainInterface->AttachMainImageWidget();
937 	}
938 }
939 
slotMenuRandomizeAll()940 void RenderWindow::slotMenuRandomizeAll()
941 {
942 	gMainInterface->RandomizeLocalSettings(this);
943 }
944 
slotCleanSettings()945 void RenderWindow::slotCleanSettings()
946 {
947 	gMainInterface->CleanSettings();
948 }
949