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 miscellaneous 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_frames.hpp"
43 #include "animation_keyframes.hpp"
44 #include "cimage.hpp"
45 #include "global_data.hpp"
46 #include "image_scale.hpp"
47 #include "initparameters.hpp"
48 #include "interface.hpp"
49 #include "keyframes.hpp"
50 #include "material_item_model.h"
51 #include "render_window.hpp"
52 #include "settings.hpp"
53 #include "system_data.hpp"
54 #include "system_directories.hpp"
55 #include "write_log.hpp"
56
57 #include "qt/detached_window.h"
58 #include "qt/material_editor.h"
59 #include "qt/mesh_export_dialog.h"
60 #include "qt/preferences_dialog.h"
61 #include "qt/thumbnail_widget.h"
62 #include "qt/voxel_export_dialog.h"
63
slotResizedScrolledAreaImage(int width,int height) const64 void RenderWindow::slotResizedScrolledAreaImage(int width, int height) const
65 {
66 if (gMainInterface->mainImage)
67 {
68 int selectedScale = ui->comboBox_image_preview_scale->currentIndex();
69
70 if (selectedScale == 0)
71 {
72 double scale = CalcMainImageScale(0.0, width, height, gMainInterface->mainImage);
73 gMainInterface->mainImage->CreatePreview(scale, width, height, gMainInterface->renderedImage);
74 gMainInterface->mainImage->UpdatePreview();
75 gMainInterface->renderedImage->setMinimumSize(gMainInterface->mainImage->GetPreviewWidth(),
76 gMainInterface->mainImage->GetPreviewHeight());
77 }
78 }
79 }
80
slotChangedComboImageScale(int index) const81 void RenderWindow::slotChangedComboImageScale(int index) const
82 {
83 if (gMainInterface->mainImage)
84 {
85 double scale = ImageScaleComboSelection2Double(index);
86 int areaWidth = ui->scrollAreaForImage->VisibleAreaWidth();
87 int areaHeight = ui->scrollAreaForImage->VisibleAreaHeight();
88 scale = CalcMainImageScale(scale, areaWidth, areaHeight, gMainInterface->mainImage);
89
90 gMainInterface->mainImage->CreatePreview(
91 scale, areaWidth, areaHeight, gMainInterface->renderedImage);
92 gMainInterface->mainImage->UpdatePreview();
93 gMainInterface->renderedImage->setMinimumSize(
94 gMainInterface->mainImage->GetPreviewWidth(), gMainInterface->mainImage->GetPreviewHeight());
95
96 gPar->Set("image_preview_scale", index);
97 }
98 }
99
slotMouseMovedOnImage(int x,int y)100 void RenderWindow::slotMouseMovedOnImage(int x, int y)
101 {
102 (void)x;
103 (void)y;
104 // qDebug() << "mouse move event";
105 // CVector2<int> point(x, y);
106 }
107
slotMouseClickOnImage(int x,int y,Qt::MouseButton button) const108 void RenderWindow::slotMouseClickOnImage(int x, int y, Qt::MouseButton button) const
109 {
110 int index = ui->comboBox_mouse_click_function->currentIndex();
111 QList<QVariant> mode = ui->comboBox_mouse_click_function->itemData(index).toList();
112 RenderedImage::enumClickMode clickMode = RenderedImage::enumClickMode(mode.at(0).toInt());
113
114 switch (clickMode)
115 {
116 case RenderedImage::clickMoveCamera:
117 case RenderedImage::clickFogVisibility:
118 case RenderedImage::clickDOFFocus:
119 case RenderedImage::clickPlaceLight:
120 case RenderedImage::clickGetJuliaConstant:
121 case RenderedImage::clickPlacePrimitive:
122 case RenderedImage::clickPlaceRandomLightCenter:
123 case RenderedImage::clickGetPoint:
124 case RenderedImage::clickWrapLimitsAroundObject:
125 {
126 if (gMainInterface->renderedImage->GetEnableClickModes())
127 {
128 gMainInterface->SetByMouse(CVector2<double>(x, y), button, mode);
129 }
130 break;
131 }
132 case RenderedImage::clickDoNothing:
133 case RenderedImage::clickFlightSpeedControl:
134 // nothing
135 break;
136 }
137 }
138
slotMouseDragStart(int x,int y,Qt::MouseButtons buttons)139 void RenderWindow::slotMouseDragStart(int x, int y, Qt::MouseButtons buttons)
140 {
141 int index = ui->comboBox_mouse_click_function->currentIndex();
142 QList<QVariant> mode = ui->comboBox_mouse_click_function->itemData(index).toList();
143 RenderedImage::enumClickMode clickMode = RenderedImage::enumClickMode(mode.at(0).toInt());
144
145 switch (clickMode)
146 {
147 case RenderedImage::clickMoveCamera:
148 case RenderedImage::clickPlaceLight:
149 {
150 if (gMainInterface->renderedImage->GetEnableClickModes())
151 {
152 gMainInterface->MouseDragStart(CVector2<double>(x, y), buttons, mode);
153 }
154 break;
155 }
156 default:
157 // nothing
158 break;
159 }
160 }
161
slotMouseDragFinish()162 void RenderWindow::slotMouseDragFinish()
163 {
164 gMainInterface->MouseDragFinish();
165 }
166
slotMouseDragDelta(int dx,int dy)167 void RenderWindow::slotMouseDragDelta(int dx, int dy)
168 {
169 gMainInterface->MouseDragDelta(dx, dy);
170 }
171
slotChangedComboMouseClickFunction(int index) const172 void RenderWindow::slotChangedComboMouseClickFunction(int index) const
173 {
174 if (index >= 0) // if list is empty, then index = -1
175 {
176 QComboBox *comboBox = static_cast<QComboBox *>(sender());
177 QList<QVariant> item = comboBox->itemData(index).toList();
178 gMainInterface->renderedImage->setClickMode(item);
179 }
180 }
181
slotKeyPressOnImage(QKeyEvent * event)182 void RenderWindow::slotKeyPressOnImage(QKeyEvent *event)
183 {
184 currentKeyEvents.append(event->key());
185 lastKeyEventModifiers = event->modifiers();
186 slotKeyHandle();
187 buttonPressTimer->start();
188 }
189
slotKeyReleaseOnImage(QKeyEvent * event)190 void RenderWindow::slotKeyReleaseOnImage(QKeyEvent *event)
191 {
192 currentKeyEvents.removeOne(event->key());
193 lastKeyEventModifiers = event->modifiers();
194 slotKeyHandle();
195 buttonPressTimer->stop();
196 }
197
slotButtonLongPress()198 void RenderWindow::slotButtonLongPress()
199 {
200 slotKeyHandle();
201 }
202
slotKeyHandle()203 void RenderWindow::slotKeyHandle()
204 {
205 if (currentKeyEvents.size() == 0) return;
206
207 gMainInterface->SynchronizeInterface(gPar, gParFractal, qInterface::read);
208
209 bool render = false;
210
211 for (int i = 0; i < currentKeyEvents.size(); i++)
212 {
213 int key = currentKeyEvents.at(i);
214 Qt::KeyboardModifiers modifiers = lastKeyEventModifiers;
215 if (modifiers & Qt::ShiftModifier)
216 { // Shift pressed
217 switch (key)
218 {
219 case Qt::Key_Up:
220 gMainInterface->MoveCamera("bu_move_forward");
221 render = true;
222 break;
223 case Qt::Key_Down:
224 gMainInterface->MoveCamera("bu_move_backward");
225 render = true;
226 break;
227 case Qt::Key_Left:
228 gMainInterface->MoveCamera("bu_move_left");
229 render = true;
230 break;
231 case Qt::Key_Right:
232 gMainInterface->MoveCamera("bu_move_right");
233 render = true;
234 break;
235 default: break;
236 }
237 }
238 else if (modifiers & Qt::ControlModifier)
239 { // Ctrl pressed
240 switch (key)
241 {
242 case Qt::Key_Up:
243 gMainInterface->MoveCamera("bu_move_forward");
244 render = true;
245 break;
246 case Qt::Key_Down:
247 gMainInterface->MoveCamera("bu_move_backward");
248 render = true;
249 break;
250 case Qt::Key_Left:
251 gMainInterface->RotateCamera("bu_rotate_roll_left");
252 render = true;
253 break;
254 case Qt::Key_Right:
255 gMainInterface->RotateCamera("bu_rotate_roll_right");
256 render = true;
257 break;
258 default: break;
259 }
260 }
261 else
262 {
263 // No keyboard modifiers
264 switch (key)
265 {
266 case Qt::Key_W:
267 gMainInterface->MoveCamera("bu_move_up");
268 render = true;
269 break;
270 case Qt::Key_S:
271 gMainInterface->MoveCamera("bu_move_down");
272 render = true;
273 break;
274 case Qt::Key_A:
275 gMainInterface->MoveCamera("bu_move_left");
276 render = true;
277 break;
278 case Qt::Key_D:
279 gMainInterface->MoveCamera("bu_move_right");
280 render = true;
281 break;
282 case Qt::Key_Q:
283 gMainInterface->MoveCamera("bu_move_forward");
284 render = true;
285 break;
286 case Qt::Key_Z:
287 gMainInterface->MoveCamera("bu_move_backward");
288 render = true;
289 break;
290 case Qt::Key_Up:
291 gMainInterface->RotateCamera("bu_rotate_up");
292 render = true;
293 break;
294 case Qt::Key_Down:
295 gMainInterface->RotateCamera("bu_rotate_down");
296 render = true;
297 break;
298 case Qt::Key_Left:
299 gMainInterface->RotateCamera("bu_rotate_left");
300 render = true;
301 break;
302 case Qt::Key_Right:
303 gMainInterface->RotateCamera("bu_rotate_right");
304 render = true;
305 break;
306
307 case Qt::Key_I:
308 currentKeyEvents.removeOne(key); // long press not allowed
309 gKeyframeAnimation->slotAddKeyframe();
310 break;
311 case Qt::Key_M:
312 currentKeyEvents.removeOne(key); // long press not allowed
313 gKeyframeAnimation->slotModifyKeyframe();
314 break;
315 /*case Qt::Key_D:
316 * currentKeyEvents.removeOne(key); // long press not allowed
317 * gKeyframeAnimation->slotDeleteKeyframe();
318 * break;*/
319 case Qt::Key_N:
320 currentKeyEvents.removeOne(key); // long press not allowed
321 gKeyframeAnimation->slotIncreaseCurrentTableIndex();
322 break;
323 case Qt::Key_P:
324 currentKeyEvents.removeOne(key); // long press not allowed
325 gKeyframeAnimation->slotDecreaseCurrentTableIndex();
326 break;
327 default: break;
328 }
329 }
330 }
331 gMainInterface->SynchronizeInterface(gPar, gParFractal, qInterface::write);
332
333 if (render)
334 {
335 gMainInterface->StartRender();
336 }
337 }
338
339 // global shortcuts
keyPressEvent(QKeyEvent * event)340 void RenderWindow::keyPressEvent(QKeyEvent *event)
341 {
342 int key = event->key();
343 Qt::KeyboardModifiers modifiers = event->modifiers();
344
345 if (modifiers & Qt::ShiftModifier)
346 {
347 switch (key)
348 {
349 case Qt::Key_Escape: gMainInterface->GlobalStopRequest(); break;
350 default: break;
351 }
352 }
353 }
354
slotMouseWheelRotatedWithKeyOnImage(int x,int y,int delta,Qt::KeyboardModifiers keyModifiers) const355 void RenderWindow::slotMouseWheelRotatedWithKeyOnImage(
356 int x, int y, int delta, Qt::KeyboardModifiers keyModifiers) const
357 {
358 if (gMainInterface->renderedImage->GetEnableClickModes())
359 {
360 int index = ui->comboBox_mouse_click_function->currentIndex();
361 QList<QVariant> mode = ui->comboBox_mouse_click_function->itemData(index).toList();
362 RenderedImage::enumClickMode clickMode = RenderedImage::enumClickMode(mode.at(0).toInt());
363 switch (clickMode)
364 {
365 case RenderedImage::clickPlaceLight:
366 {
367 if (keyModifiers & Qt::AltModifier)
368 {
369 double deltaLog = exp(delta * 0.001);
370 double dist = ui->widgetEffects->GetAuxLightManualPlacementDistance();
371 dist *= deltaLog;
372 ui->widgetEffects->slotSetAuxLightManualPlacementDistance(dist);
373 }
374 else if (keyModifiers & Qt::ControlModifier)
375 {
376 gMainInterface->MoveLightByWheel(delta);
377 }
378 break;
379 }
380 case RenderedImage::clickMoveCamera:
381 {
382 Qt::MouseButton button = (delta > 0) ? Qt::LeftButton : Qt::RightButton;
383 mode.append(QVariant(delta));
384 gMainInterface->SetByMouse(CVector2<double>(x, y), button, mode);
385 break;
386 }
387 default: break;
388 }
389 }
390 }
391
slotChangedCheckBoxCursorVisibility(int state)392 void RenderWindow::slotChangedCheckBoxCursorVisibility(int state)
393 {
394 gMainInterface->renderedImage->SetCursorVisibility(state);
395 }
396
397 // adds dynamic actions to the toolbar (example settings)
slotPopulateToolbar(bool completeRefresh)398 void RenderWindow::slotPopulateToolbar(bool completeRefresh)
399 {
400 WriteLog("cInterface::PopulateToolbar(QWidget *window, QToolBar *toolBar) started", 2);
401 QDir toolbarDir = QDir(gPar->Get<QString>("toolbar_path"));
402 toolbarDir.setSorting(QDir::Time);
403 QStringList toolbarFiles = toolbarDir.entryList(QDir::NoDotAndDotDot | QDir::Files);
404 QSignalMapper *mapPresetsFromExamplesLoad = new QSignalMapper(this);
405 QSignalMapper *mapPresetsFromExamplesRemove = new QSignalMapper(this);
406 ui->toolBar->setIconSize(
407 QSize(gPar->Get<int>("toolbar_icon_size"), gPar->Get<int>("toolbar_icon_size")));
408
409 QList<QAction *> actions = ui->toolBar->actions();
410 QStringList toolbarInActions;
411
412 QApplication::connect(
413 mapPresetsFromExamplesLoad, SIGNAL(mapped(QString)), this, SLOT(slotMenuLoadPreset(QString)));
414
415 for (auto action : actions)
416 {
417 if (action->objectName() == "actionAdd_Settings_to_Toolbar") continue;
418 if (!toolbarFiles.contains(action->objectName()) || completeRefresh)
419 {
420 // preset has been removed
421 ui->toolBar->removeAction(action);
422 }
423 else
424 {
425 toolbarInActions << action->objectName();
426 }
427 }
428
429 for (int i = 0; i < toolbarFiles.size(); i++)
430 {
431 if (systemData.globalStopRequest) break;
432
433 if (toolbarInActions.contains(toolbarFiles.at(i)))
434 {
435 // already present
436 continue;
437 }
438 QString filename = gPar->Get<QString>("toolbar_path") + QDir::separator() + toolbarFiles.at(i);
439 cThumbnailWidget *thumbWidget = nullptr;
440
441 if (QFileInfo(filename).suffix() == QString("fract"))
442 {
443 WriteLogString("Generating thumbnail for preset", filename, 2);
444 cSettings parSettings(cSettings::formatFullText);
445 parSettings.BeQuiet(true);
446
447 if (parSettings.LoadFromFile(filename))
448 {
449 std::shared_ptr<cParameterContainer> par(new cParameterContainer);
450 std::shared_ptr<cFractalContainer> parFractal(new cFractalContainer);
451 InitParams(par);
452 for (int j = 0; j < NUMBER_OF_FRACTALS; j++)
453 InitFractalParams(parFractal->at(j));
454
455 /****************** TEMPORARY CODE FOR MATERIALS *******************/
456
457 InitMaterialParams(1, par);
458
459 /*******************************************************************/
460
461 if (parSettings.Decode(par, parFractal))
462 {
463 thumbWidget = new cThumbnailWidget(
464 gPar->Get<int>("toolbar_icon_size"), gPar->Get<int>("toolbar_icon_size"), 2, this);
465 thumbWidget->UseOneCPUCore(true);
466 par->Set("opencl_mode", gPar->Get<int>("opencl_mode"));
467 par->Set("opencl_enabled", gPar->Get<bool>("opencl_enabled"));
468 if (!gPar->Get<bool>("thumbnails_with_opencl")) par->Set("opencl_enabled", false);
469 thumbWidget->AssignParameters(par, parFractal);
470 }
471 }
472 }
473
474 if (thumbWidget)
475 {
476 QWidgetAction *action = new QWidgetAction(this);
477 QToolButton *buttonLoad = new QToolButton;
478 QVBoxLayout *tooltipLayout = new QVBoxLayout;
479 QToolButton *buttonRemove = new QToolButton;
480
481 tooltipLayout->setContentsMargins(3, 3, 3, 3);
482 tooltipLayout->addWidget(thumbWidget);
483 QIcon iconDelete = QIcon::fromTheme("list-remove", QIcon(":system/icons/list-remove.svg"));
484 buttonRemove->setIcon(iconDelete);
485 buttonRemove->setMaximumSize(QSize(15, 15));
486 buttonRemove->setStyleSheet("margin-bottom: -2px; margin-left: -2px;");
487 tooltipLayout->addWidget(buttonRemove);
488 buttonLoad->setToolTip(QObject::tr("Toolbar settings: ") + filename);
489 buttonLoad->setLayout(tooltipLayout);
490 action->setDefaultWidget(buttonLoad);
491 action->setObjectName(toolbarFiles.at(i));
492 ui->toolBar->addAction(action);
493
494 mapPresetsFromExamplesLoad->setMapping(buttonLoad, filename);
495 mapPresetsFromExamplesRemove->setMapping(buttonRemove, filename);
496 QApplication::connect(buttonLoad, SIGNAL(clicked()), mapPresetsFromExamplesLoad, SLOT(map()));
497 QApplication::connect(
498 buttonRemove, SIGNAL(clicked()), mapPresetsFromExamplesRemove, SLOT(map()));
499 }
500 QApplication::processEvents();
501 }
502
503 QApplication::connect(mapPresetsFromExamplesRemove, SIGNAL(mapped(QString)), this,
504 SLOT(slotMenuRemovePreset(QString)));
505
506 WriteLog("cInterface::PopulateToolbar(QWidget *window, QToolBar *toolBar) finished", 2);
507 }
508
slotPresetAddToToolbar()509 void RenderWindow::slotPresetAddToToolbar()
510 {
511 cSettings parSettings(cSettings::formatCondensedText);
512 gMainInterface->SynchronizeInterface(gPar, gParFractal, qInterface::read);
513 parSettings.CreateText(gPar, gParFractal, gAnimFrames, gKeyframes);
514 QString filename =
515 systemDirectories.GetToolbarFolder() + QDir::separator() + parSettings.GetHashCode() + ".fract";
516 parSettings.SaveToFile(filename);
517 slotPopulateToolbar();
518 }
519
slotMenuLoadPreset(QString filename)520 void RenderWindow::slotMenuLoadPreset(QString filename)
521 {
522 cSettings parSettings(cSettings::formatFullText);
523 gMainInterface->DisablePeriodicRefresh();
524 parSettings.LoadFromFile(filename);
525 gInterfaceReadyForSynchronization = false;
526 parSettings.Decode(gPar, gParFractal, gAnimFrames, gKeyframes);
527 gMainInterface->RebuildPrimitives(gPar);
528 gMainInterface->materialListModel->Regenerate();
529 ui->widgetEffects->RegenerateLights();
530
531 gMainInterface->SynchronizeInterface(gPar, gParFractal, qInterface::write);
532 gInterfaceReadyForSynchronization = true;
533
534 gMainInterface->ComboMouseClickUpdate();
535 systemData.lastSettingsFile = gPar->Get<QString>("default_settings_path") + QDir::separator()
536 + QFileInfo(filename).fileName();
537
538 gFlightAnimation->RefreshTable();
539 gKeyframeAnimation->RefreshTable();
540 showDescriptionPopup();
541 setWindowTitle(QString("Mandelbulber (") + systemData.lastSettingsFile + ")");
542 }
543
slotMenuRemovePreset(QString filename)544 void RenderWindow::slotMenuRemovePreset(QString filename)
545 {
546 QFile::remove(filename);
547 slotPopulateToolbar();
548 }
549
550 // adds dynamic actions to the view > window states
slotPopulateCustomWindowStates(bool completeRefresh)551 void RenderWindow::slotPopulateCustomWindowStates(bool completeRefresh)
552 {
553 WriteLog("cInterface::slotPopulateCustomWindowStates() started", 2);
554 QDir customWindowStateDir = QDir(systemDirectories.GetCustomWindowStateFolder());
555 customWindowStateDir.setSorting(QDir::Time);
556 QStringList geometryFileExtension("*.geometry");
557 customWindowStateDir.setNameFilters(geometryFileExtension);
558 QStringList customWindowStateFiles =
559 customWindowStateDir.entryList(QDir::NoDotAndDotDot | QDir::Files);
560 QSignalMapper *mapCustomWindowLoad = new QSignalMapper(this);
561 // QSignalMapper *mapCustomWindowRemove = new QSignalMapper(this);
562
563 QList<QAction *> actions = ui->menuSaved_window_layouts->actions();
564 QStringList customWindowActions;
565 for (auto action : actions)
566 {
567 if (!action->objectName().startsWith("window_")) continue;
568 if (!customWindowStateFiles.contains(action->objectName()) || completeRefresh)
569 {
570 // preset has been removed
571 ui->menuSaved_window_layouts->removeAction(action);
572 }
573 else
574 {
575 customWindowActions << action->objectName();
576 }
577 }
578
579 for (int i = 0; i < customWindowStateFiles.size(); i++)
580 {
581 QString customWindowStateGeometryFile = customWindowStateFiles.at(i);
582 QString customWindowStateFile = customWindowStateGeometryFile.replace(".geometry", "");
583 if (customWindowActions.contains("window_" + customWindowStateFile))
584 {
585 // already present
586 continue;
587 }
588 QString filename =
589 systemDirectories.GetCustomWindowStateFolder() + QDir::separator() + customWindowStateFile;
590
591 /*
592 QWidgetAction *action = new QWidgetAction(this);
593 QLabel *buttonLoad = new QLabel;
594 QHBoxLayout *tooltipLayout = new QHBoxLayout;
595 QToolButton *buttonRemove = new QToolButton;
596 QLabel *label = new QLabel;
597
598 buttonLoad->setStyleSheet("QLabel{ border: none; margin: 2px; padding: 1px; }");
599 label->setText(QByteArray().fromBase64(QByteArray().append(customWindowStateFile)));
600 tooltipLayout->setContentsMargins(5, 0, 0, 0);
601 QIcon iconDelete = QIcon::fromTheme("list-remove", QIcon(":system/icons/list-remove.svg"));
602 buttonRemove->setIcon(iconDelete);
603 buttonRemove->setMaximumSize(QSize(15, 15));
604 tooltipLayout->addWidget(buttonRemove);
605 tooltipLayout->addWidget(label);
606 buttonLoad->setLayout(tooltipLayout);
607 // FIXME - when minimum width is not specified the widget is very small
608 buttonLoad->setMinimumWidth(300);
609 action->setDefaultWidget(buttonLoad);*/
610
611 QAction *action = new QAction(this);
612 action->setText(QByteArray().fromBase64(QByteArray().append(customWindowStateFile.toUtf8())));
613 action->setObjectName("window_" + customWindowStateFile);
614
615 ui->menuSaved_window_layouts->addAction(action);
616
617 mapCustomWindowLoad->setMapping(action, filename);
618 QApplication::connect(action, SIGNAL(triggered()), mapCustomWindowLoad, SLOT(map()));
619 QApplication::processEvents();
620 }
621 QApplication::connect(mapCustomWindowLoad, SIGNAL(mapped(QString)), this,
622 SLOT(slotMenuLoadCustomWindowState(QString)));
623
624 /*QApplication::connect(mapCustomWindowRemove, SIGNAL(mapped(QString)), this,
625 SLOT(slotMenuRemoveCustomWindowState(QString)));*/
626
627 WriteLog("cInterface::slotPopulateCustomWindowStates() finished", 2);
628 }
629
slotCustomWindowStateAddToMenu()630 void RenderWindow::slotCustomWindowStateAddToMenu()
631 {
632 bool ok;
633 QString text = QInputDialog::getText(this, tr("Add window settings"),
634 tr("Enter a name for the new window settings"), QLineEdit::Normal, "", &ok);
635 if (!ok || text.isEmpty())
636 {
637 WriteLogCout("Cancelled window saving", 2);
638 return;
639 }
640 QString textEncoded = QByteArray().append(text.toUtf8()).toBase64();
641 QString basePath = systemDirectories.GetCustomWindowStateFolder() + QDir::separator();
642 QString filename = basePath + textEncoded;
643 QString filenameGeometry = filename + ".geometry";
644 QString filenameState = filename + ".state";
645 QFile fileGeometry(filenameGeometry);
646 QFile fileState(filenameState);
647 if (!fileGeometry.open(QIODevice::WriteOnly) || !fileState.open(QIODevice::WriteOnly))
648 {
649 qWarning() << "Could not open output files: " << filename << ".[geometry,state]";
650 return;
651 }
652 fileGeometry.write(saveGeometry());
653 fileState.write(saveState());
654 fileGeometry.close();
655 fileState.close();
656
657 slotPopulateCustomWindowStates();
658 }
659
slotMenuLoadCustomWindowState(QString filename)660 void RenderWindow::slotMenuLoadCustomWindowState(QString filename)
661 {
662 QFile fileGeometry(filename + ".geometry");
663 QFile fileState(filename + ".state");
664 if (!fileGeometry.open(QIODevice::ReadOnly) || !fileState.open(QIODevice::ReadOnly))
665 {
666 qWarning() << "Could not open input files: " << filename << ".[geometry,state]";
667 return;
668 }
669 // restoreGeometry(fileGeometry.readAll());
670 restoreState(fileState.readAll());
671 }
672
slotCustomWindowRemovePopup()673 void RenderWindow::slotCustomWindowRemovePopup()
674 {
675 QDir customWindowStateDir = QDir(systemDirectories.GetCustomWindowStateFolder());
676 customWindowStateDir.setSorting(QDir::Time);
677 QStringList geometryFileExtension("*.geometry");
678 customWindowStateDir.setNameFilters(geometryFileExtension);
679 QStringList customWindowStateFiles =
680 customWindowStateDir.entryList(QDir::NoDotAndDotDot | QDir::Files);
681 QStringList itemsEscaped;
682 if (customWindowStateFiles.size() == 0)
683 {
684 WriteLogCout("Nothing to remove", 2);
685 return;
686 }
687 for (int i = 0; i < customWindowStateFiles.size(); i++)
688 {
689 QString customWindowStateFile = customWindowStateFiles[i].replace(".geometry", "");
690 itemsEscaped.append(
691 QByteArray().fromBase64(QByteArray().append(customWindowStateFile.toUtf8())));
692 }
693 bool ok;
694
695 QString itemEscaped = QInputDialog::getItem(this, tr("Remove window settings"),
696 tr("Select window setting to remove"), itemsEscaped, 0, false, &ok);
697 if (!ok || itemEscaped.isEmpty())
698 {
699 WriteLogCout("Cancelled window removing", 2);
700 return;
701 }
702 int index = itemsEscaped.indexOf(itemEscaped);
703 QString filename = systemDirectories.GetCustomWindowStateFolder() + QDir::separator()
704 + customWindowStateFiles.at(index);
705 slotMenuRemoveCustomWindowState(filename.replace(".geometry", ""));
706 }
707
slotMenuRemoveCustomWindowState(QString filename)708 void RenderWindow::slotMenuRemoveCustomWindowState(QString filename)
709 {
710 QFile::remove(filename + ".geometry");
711 QFile::remove(filename + ".state");
712 slotPopulateCustomWindowStates();
713 }
714
slotPopulateRecentSettings(bool completeRefresh)715 void RenderWindow::slotPopulateRecentSettings(bool completeRefresh)
716 {
717 WriteLog("cInterface::slotPopulateRecentSettings() started", 2);
718 QFile recentFilesFile(systemDirectories.GetRecentFilesListFile());
719 if (!recentFilesFile.open(QFile::ReadOnly | QFile::Text))
720 {
721 // qDebug() << "cannot open recent file";
722 return;
723 }
724 QTextStream in(&recentFilesFile);
725 QString recentFilesFileContent = in.readAll();
726
727 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
728 QStringList recentFiles =
729 recentFilesFileContent.split(QRegExp("\n|\r\n|\r"), QString::KeepEmptyParts);
730 #else
731 QStringList recentFiles = recentFilesFileContent.split(QRegExp("\n|\r\n|\r"), Qt::KeepEmptyParts);
732 #endif
733
734 QSignalMapper *mapRecentFileLoad = new QSignalMapper(this);
735 QList<QAction *> actions = ui->menuRecent_Settings_list->actions();
736 QStringList recentFileInActions;
737 for (auto action : actions)
738 {
739 if (!action->objectName().startsWith("recent_")) continue;
740 if (!recentFileInActions.contains(action->objectName()) || completeRefresh)
741 {
742 // preset has been removed
743 ui->menuRecent_Settings_list->removeAction(action);
744 }
745 else
746 {
747 recentFileInActions << action->objectName();
748 }
749 }
750
751 for (int i = 0; i < recentFiles.size(); i++)
752 {
753 QString settingsFile = recentFiles.at(i);
754 if (recentFileInActions.contains("recent_" + settingsFile))
755 {
756 // already present
757 continue;
758 }
759
760 QAction *action = new QAction(this);
761 action->setText(QFileInfo(settingsFile).baseName());
762 action->setObjectName("recent_" + settingsFile);
763
764 ui->menuRecent_Settings_list->addAction(action);
765
766 mapRecentFileLoad->setMapping(action, settingsFile);
767 QApplication::connect(action, SIGNAL(triggered()), mapRecentFileLoad, SLOT(map()));
768 QApplication::processEvents();
769 }
770 QApplication::connect(
771 mapRecentFileLoad, SIGNAL(mapped(QString)), this, SLOT(slotMenuLoadSettingsFromFile(QString)));
772
773 WriteLog("cInterface::slotPopulateRecentSettings() finished", 2);
774 }
775
slotQuit()776 void RenderWindow::slotQuit()
777 {
778 gMainInterface->QuitApplicationDialog();
779 }
780
closeEvent(QCloseEvent * event)781 void RenderWindow::closeEvent(QCloseEvent *event)
782 {
783 if (gMainInterface->QuitApplicationDialog())
784 {
785 event->accept();
786 }
787 else
788 {
789 event->ignore();
790 }
791 }
792
changeEvent(QEvent * event)793 void RenderWindow::changeEvent(QEvent *event)
794 {
795 if (event->type() == QEvent::LanguageChange)
796 {
797 // retranslate designer form (single inheritance approach)
798 // ui->retranslateUi(this);
799 }
800
801 // remember to call base class implementation
802 QMainWindow::changeEvent(event);
803 }
804
slotUpdateProgressAndStatus(const QString & text,const QString & progressText,double progress,cProgressText::enumProgressType progressType) const805 void RenderWindow::slotUpdateProgressAndStatus(const QString &text, const QString &progressText,
806 double progress, cProgressText::enumProgressType progressType) const
807 {
808 ui->statusbar->showMessage(text, 0);
809 MyProgressBar *progressBar = nullptr;
810 bool isQueue = false;
811
812 // FIXME: sender can be deleted by another thread (e.g. ImageFileSave exists very short time)
813 // if (sender())
814 // {
815 // isQueue = sender()->objectName() == "Queue";
816 // }
817
818 switch (progressType)
819 {
820 case cProgressText::progress_IMAGE:
821 if (isQueue)
822 progressBar = gMainInterface->progressBarQueueImage;
823 else
824 progressBar = gMainInterface->progressBar;
825 break;
826 case cProgressText::progress_ANIMATION:
827 if (isQueue)
828 progressBar = gMainInterface->progressBarQueueAnimation;
829 else
830 progressBar = gMainInterface->progressBarAnimation;
831 break;
832 case cProgressText::progress_QUEUE:
833 // nothing to be done, no progress bar for queue in GUI
834 break;
835 }
836
837 if (progressBar)
838 {
839 if (!progressBar->isVisible())
840 {
841 progressBar->setVisible(true);
842 }
843 progressBar->setValue(progress * 1000.0);
844 progressBar->setTextVisible(true);
845 progressBar->setFormat(progressText);
846 }
847 }
848
slotUpdateProgressHide(cProgressText::enumProgressType progressType)849 void RenderWindow::slotUpdateProgressHide(cProgressText::enumProgressType progressType)
850 {
851 MyProgressBar *progressBar = nullptr;
852 switch (progressType)
853 {
854 case cProgressText::progress_IMAGE: progressBar = gMainInterface->progressBar; break;
855 case cProgressText::progress_ANIMATION:
856 progressBar = gMainInterface->progressBarAnimation;
857 break;
858 case cProgressText::progress_QUEUE:
859 // nothing to be done, no progress bar for queue in GUI
860 break;
861 }
862
863 if (progressBar)
864 {
865 if (progressBar->isVisible()) progressBar->setVisible(false);
866 }
867 }
868
slotMenuProgramPreferences()869 void RenderWindow::slotMenuProgramPreferences()
870 {
871 if (!preferencesDialog)
872 {
873 preferencesDialog = new cPreferencesDialog;
874 }
875
876 preferencesDialog->show();
877 preferencesDialog->raise();
878 preferencesDialog->activateWindow();
879 }
880
slotExportVoxelLayers()881 void RenderWindow::slotExportVoxelLayers()
882 {
883 if (!voxelExportDialog)
884 {
885 voxelExportDialog = new cVoxelExportDialog;
886 }
887
888 voxelExportDialog->show();
889 voxelExportDialog->raise();
890 voxelExportDialog->activateWindow();
891 }
892
slotExportMesh()893 void RenderWindow::slotExportMesh()
894 {
895 if (!meshExportDialog)
896 {
897 meshExportDialog = new cMeshExportDialog;
898 }
899
900 meshExportDialog->show();
901 meshExportDialog->raise();
902 meshExportDialog->activateWindow();
903 }
904
slotQuestionMessage(const QString & questionTitle,const QString & questionText,QMessageBox::StandardButtons buttons,QMessageBox::StandardButton * reply) const905 void RenderWindow::slotQuestionMessage(const QString &questionTitle, const QString &questionText,
906 QMessageBox::StandardButtons buttons, QMessageBox::StandardButton *reply) const
907 {
908 *reply = QMessageBox::question(ui->centralwidget, questionTitle, questionText, buttons);
909 }
910
slotAutoRefresh()911 void RenderWindow::slotAutoRefresh()
912 {
913 gMainInterface->PeriodicRefresh();
914 }
915
slotMaterialSelected(int matIndex) const916 void RenderWindow::slotMaterialSelected(int matIndex) const
917 {
918 gMainInterface->MaterialSelected(matIndex);
919 }
920
slotMaterialEdited()921 void RenderWindow::slotMaterialEdited()
922 {
923 SynchronizeInterfaceWindow(gMainInterface->materialEditor, gPar, qInterface::write);
924 }
925
slotChangedComboGridType(int index)926 void RenderWindow::slotChangedComboGridType(int index)
927 {
928 gMainInterface->renderedImage->SetGridType(RenderedImage::enumGridType(index));
929 }
930
ResetGlobalStopRequest()931 void RenderWindow::ResetGlobalStopRequest()
932 {
933 gMainInterface->ResetGlobalStopRequest();
934 }
935
eventFilter(QObject * obj,QEvent * event)936 bool RenderWindow::eventFilter(QObject *obj, QEvent *event)
937 {
938
939 if (event->type() == QEvent::ToolTip && !gPar->Get<bool>("display_tooltips"))
940 {
941 {
942 return true;
943 }
944 }
945 else if (event->type() == QEvent::ShortcutOverride)
946 {
947 buttonPressTimer->stop();
948 return QMainWindow::eventFilter(obj, event);
949 }
950 else
951 {
952 return QMainWindow::eventFilter(obj, event);
953 }
954 }
955
ToggleFullScreen()956 void RenderWindow::ToggleFullScreen()
957 {
958 if (!ui->actionDetach_image_from_main_window->isChecked())
959 {
960 gMainInterface->DetachMainImageWidget();
961 gMainInterface->detachedWindow->showFullScreen();
962 ui->actionDetach_image_from_main_window->setChecked(true);
963 }
964 else
965 {
966 gMainInterface->AttachMainImageWidget();
967 ui->actionDetach_image_from_main_window->setChecked(false);
968 }
969 }
970