1 #include "lc_global.h"
2 #include "lc_mainwindow.h"
3 #include <QPrintDialog>
4 #include <QPrintPreviewDialog>
5 #include "lc_partselectionwidget.h"
6 #include "lc_timelinewidget.h"
7 #include "lc_viewwidget.h"
8 #include "lc_qcolorlist.h"
9 #include "lc_qpropertiestree.h"
10 #include "lc_qutils.h"
11 #include "lc_qupdatedialog.h"
12 #include "lc_qaboutdialog.h"
13 #include "lc_setsdatabasedialog.h"
14 #include "lc_qhtmldialog.h"
15 #include "lc_renderdialog.h"
16 #include "lc_instructionsdialog.h"
17 #include "lc_profile.h"
18 #include "lc_view.h"
19 #include "project.h"
20 #include "piece.h"
21 #include "camera.h"
22 #include "group.h"
23 #include "pieceinf.h"
24 #include "lc_library.h"
25 #include "lc_colors.h"
26 #include "lc_previewwidget.h"
27 
28 #if LC_ENABLE_GAMEPAD
29 #include <QtGamepad/QGamepad>
30 #endif
31 
32 lcMainWindow* gMainWindow;
33 #define LC_TAB_LAYOUT_VERSION 0x0001
34 
mousePressEvent(QMouseEvent * Event)35 void lcTabBar::mousePressEvent(QMouseEvent* Event)
36 {
37 	if (Event->button() == Qt::MiddleButton)
38 		mMousePressTab = tabAt(Event->pos());
39 	else
40 		QTabBar::mousePressEvent(Event);
41 }
42 
mouseReleaseEvent(QMouseEvent * Event)43 void lcTabBar::mouseReleaseEvent(QMouseEvent* Event)
44 {
45 	if (Event->button() == Qt::MiddleButton && tabAt(Event->pos()) == mMousePressTab)
46 		tabCloseRequested(mMousePressTab);
47 	else
48 		QTabBar::mouseReleaseEvent(Event);
49 }
50 
lcMainWindow()51 lcMainWindow::lcMainWindow()
52 {
53 	memset(mActions, 0, sizeof(mActions));
54 
55 	mTransformType = lcTransformType::RelativeTranslation;
56 
57 	mColorIndex = lcGetColorIndex(7);
58 	mTool = lcTool::Select;
59 	mAddKeys = false;
60 	mMoveSnapEnabled = true;
61 	mAngleSnapEnabled = true;
62 	mMoveXYSnapIndex = 4;
63 	mMoveZSnapIndex = 3;
64 	mAngleSnapIndex = 5;
65 	mRelativeTransform = true;
66 	mLocalTransform = false;
67 	mCurrentPieceInfo = nullptr;
68 	mSelectionMode = lcSelectionMode::Single;
69 	mModelTabWidget = nullptr;
70 	mPreviewToolBar = nullptr;
71 	mPreviewWidget = nullptr;
72 
73 	for (int FileIdx = 0; FileIdx < LC_MAX_RECENT_FILES; FileIdx++)
74 		mRecentFiles[FileIdx] = lcGetProfileString((LC_PROFILE_KEY)(LC_PROFILE_RECENT_FILE1 + FileIdx));
75 
76 #if (QT_VERSION >= QT_VERSION_CHECK(5, 8, 0))
77 	connect(&mGamepadTimer, &QTimer::timeout, this, &lcMainWindow::UpdateGamepads);
78 	mLastGamepadUpdate = QDateTime::currentDateTime();
79 	mGamepadTimer.start(33);
80 #endif
81 
82 	gMainWindow = this;
83 }
84 
~lcMainWindow()85 lcMainWindow::~lcMainWindow()
86 {
87 	if (mCurrentPieceInfo)
88 	{
89 		lcPiecesLibrary* Library = lcGetPiecesLibrary();
90 		Library->ReleasePieceInfo(mCurrentPieceInfo);
91 		mCurrentPieceInfo = nullptr;
92 	}
93 
94 	for (int FileIdx = 0; FileIdx < LC_MAX_RECENT_FILES; FileIdx++)
95 		lcSetProfileString((LC_PROFILE_KEY)(LC_PROFILE_RECENT_FILE1 + FileIdx), mRecentFiles[FileIdx]);
96 
97 	gMainWindow = nullptr;
98 }
99 
CreateWidgets()100 void lcMainWindow::CreateWidgets()
101 {
102 	setAcceptDrops(true);
103 	setWindowIcon(QIcon(":/resources/leocad.png"));
104 	setWindowFilePath(QString());
105 
106 	CreateActions();
107 	CreateToolBars();
108 	CreateMenus();
109 	CreateStatusBar();
110 
111 	mModelTabWidget = new QTabWidget();
112 	mModelTabWidget->tabBar()->setMovable(true);
113 	mModelTabWidget->tabBar()->setTabsClosable(true);
114 	mModelTabWidget->tabBar()->setContextMenuPolicy(Qt::CustomContextMenu);
115 	setCentralWidget(mModelTabWidget);
116 
117 	connect(mModelTabWidget->tabBar(), SIGNAL(tabCloseRequested(int)), this, SLOT(ModelTabClosed(int)));
118 	connect(mModelTabWidget->tabBar(), SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(ModelTabContextMenuRequested(const QPoint&)));
119 	connect(mModelTabWidget, SIGNAL(currentChanged(int)), this, SLOT(ModelTabChanged(int)));
120 
121 	connect(QApplication::clipboard(), SIGNAL(dataChanged()), this, SLOT(ClipboardChanged()));
122 	ClipboardChanged();
123 
124 	QSettings Settings;
125 	Settings.beginGroup("MainWindow");
126 	resize(QSize(800, 600));
127 	move(QPoint(200, 200));
128 	restoreGeometry(Settings.value("Geometry").toByteArray());
129 	restoreState(Settings.value("State").toByteArray());
130 	mPartSelectionWidget->LoadState(Settings);
131 	Settings.endGroup();
132 }
133 
CreateActions()134 void lcMainWindow::CreateActions()
135 {
136 	for (int CommandIdx = 0; CommandIdx < LC_NUM_COMMANDS; CommandIdx++)
137 	{
138 		QAction* Action = new QAction(qApp->translate("Menu", gCommands[CommandIdx].MenuName), this);
139 		Action->setStatusTip(qApp->translate("Status", gCommands[CommandIdx].StatusText));
140 		connect(Action, SIGNAL(triggered()), this, SLOT(ActionTriggered()));
141 		addAction(Action);
142 		mActions[CommandIdx] = Action;
143 	}
144 
145 	mActions[LC_FILE_NEW]->setToolTip(tr("New Model"));
146 	mActions[LC_FILE_OPEN]->setToolTip(tr("Open Model"));
147 	mActions[LC_FILE_SAVE]->setToolTip(tr("Save Model"));
148 
149 	QIcon FileNewIcon;
150 	FileNewIcon.addFile(":/resources/file_new.png");
151 	FileNewIcon.addFile(":/resources/file_new_16.png");
152 	mActions[LC_FILE_NEW]->setIcon(FileNewIcon);
153 
154 	QIcon FileSaveIcon;
155 	FileSaveIcon.addFile(":/resources/file_save.png");
156 	FileSaveIcon.addFile(":/resources/file_save_16.png");
157 	mActions[LC_FILE_SAVE]->setIcon(FileSaveIcon);
158 
159 	QIcon FileOpenIcon;
160 	FileOpenIcon.addFile(":/resources/file_open.png");
161 	FileOpenIcon.addFile(":/resources/file_open_16.png");
162 	mActions[LC_FILE_OPEN]->setIcon(FileOpenIcon);
163 
164 	QIcon FilePrintIcon;
165 	FilePrintIcon.addFile(":/resources/file_print.png");
166 	FilePrintIcon.addFile(":/resources/file_print_16.png");
167 	mActions[LC_FILE_PRINT]->setIcon(FilePrintIcon);
168 
169 	QIcon FilePrintPreviewIcon;
170 	FilePrintPreviewIcon.addFile(":/resources/file_print_preview.png");
171 	FilePrintPreviewIcon.addFile(":/resources/file_print_preview_16.png");
172 	mActions[LC_FILE_PRINT_PREVIEW]->setIcon(FilePrintPreviewIcon);
173 
174 	QIcon EditUndoIcon;
175 	EditUndoIcon.addFile(":/resources/edit_undo.png");
176 	EditUndoIcon.addFile(":/resources/edit_undo_16.png");
177 	mActions[LC_EDIT_UNDO]->setIcon(EditUndoIcon);
178 
179 	QIcon EditRedoIcon;
180 	EditRedoIcon.addFile(":/resources/edit_redo.png");
181 	EditRedoIcon.addFile(":/resources/edit_redo_16.png");
182 	mActions[LC_EDIT_REDO]->setIcon(EditRedoIcon);
183 
184 	QIcon EditCutIcon;
185 	EditCutIcon.addFile(":/resources/edit_cut.png");
186 	EditCutIcon.addFile(":/resources/edit_cut_16.png");
187 	mActions[LC_EDIT_CUT]->setIcon(EditCutIcon);
188 
189 	QIcon EditCopyIcon;
190 	EditCopyIcon.addFile(":/resources/edit_copy.png");
191 	EditCopyIcon.addFile(":/resources/edit_copy_16.png");
192 	mActions[LC_EDIT_COPY]->setIcon(EditCopyIcon);
193 
194 	QIcon EditPasteIcon;
195 	EditPasteIcon.addFile(":/resources/edit_paste.png");
196 	EditPasteIcon.addFile(":/resources/edit_paste_16.png");
197 	mActions[LC_EDIT_PASTE]->setIcon(EditPasteIcon);
198 
199 	QIcon EditActionInsertIcon;
200 	EditActionInsertIcon.addFile(":/resources/action_insert.png");
201 	EditActionInsertIcon.addFile(":/resources/action_insert_16.png");
202 	mActions[LC_EDIT_ACTION_INSERT]->setIcon(EditActionInsertIcon);
203 
204 	QIcon EditActionLightIcon;
205 	EditActionLightIcon.addFile(":/resources/action_light.png");
206 	EditActionLightIcon.addFile(":/resources/action_light_16.png");
207 	mActions[LC_EDIT_ACTION_LIGHT]->setIcon(EditActionLightIcon);
208 
209 	QIcon EditActionSpotLightIcon;
210 	EditActionSpotLightIcon.addFile(":/resources/action_spotlight.png");
211 	EditActionSpotLightIcon.addFile(":/resources/action_spotlight_16.png");
212 	mActions[LC_EDIT_ACTION_SPOTLIGHT]->setIcon(EditActionSpotLightIcon);
213 
214 	QIcon EditActionSelectIcon;
215 	EditActionSelectIcon.addFile(":/resources/action_select.png");
216 	EditActionSelectIcon.addFile(":/resources/action_select_16.png");
217 	mActions[LC_EDIT_ACTION_SELECT]->setIcon(EditActionSelectIcon);
218 
219 	QIcon EditActionMoveIcon;
220 	EditActionMoveIcon.addFile(":/resources/action_move.png");
221 	EditActionMoveIcon.addFile(":/resources/action_move_16.png");
222 	mActions[LC_EDIT_ACTION_MOVE]->setIcon(EditActionMoveIcon);
223 
224 	QIcon EditActionRotateIcon;
225 	EditActionRotateIcon.addFile(":/resources/action_rotate.png");
226 	EditActionRotateIcon.addFile(":/resources/action_rotate_16.png");
227 	mActions[LC_EDIT_ACTION_ROTATE]->setIcon(EditActionRotateIcon);
228 
229 	QIcon EditActionDeleteIcon;
230 	EditActionDeleteIcon.addFile(":/resources/action_delete.png");
231 	EditActionDeleteIcon.addFile(":/resources/action_delete_16.png");
232 	mActions[LC_EDIT_ACTION_DELETE]->setIcon(EditActionDeleteIcon);
233 
234 	QIcon EditActionPaintIcon;
235 	EditActionPaintIcon.addFile(":/resources/action_paint.png");
236 	EditActionPaintIcon.addFile(":/resources/action_paint_16.png");
237 	mActions[LC_EDIT_ACTION_PAINT]->setIcon(EditActionPaintIcon);
238 
239 	QIcon EditActionColorPickerIcon;
240 	EditActionColorPickerIcon.addFile(":/resources/action_color_picker.png");
241 	EditActionColorPickerIcon.addFile(":/resources/action_color_picker_16.png");
242 	mActions[LC_EDIT_ACTION_COLOR_PICKER]->setIcon(EditActionColorPickerIcon);
243 
244 	QIcon EditActionZoomIcon;
245 	EditActionZoomIcon.addFile(":/resources/action_zoom.png");
246 	EditActionZoomIcon.addFile(":/resources/action_zoom_16.png");
247 	mActions[LC_EDIT_ACTION_ZOOM]->setIcon(EditActionZoomIcon);
248 
249 	QIcon EditActionPanIcon;
250 	EditActionPanIcon.addFile(":/resources/action_pan.png");
251 	EditActionPanIcon.addFile(":/resources/action_pan_16.png");
252 	mActions[LC_EDIT_ACTION_PAN]->setIcon(EditActionPanIcon);
253 
254 	mActions[LC_EDIT_ACTION_CAMERA]->setIcon(QIcon(":/resources/action_camera.png"));
255 	mActions[LC_EDIT_ACTION_ROTATE_VIEW]->setIcon(QIcon(":/resources/action_rotate_view.png"));
256 	mActions[LC_EDIT_ACTION_ROLL]->setIcon(QIcon(":/resources/action_roll.png"));
257 	mActions[LC_EDIT_ACTION_ZOOM_REGION]->setIcon(QIcon(":/resources/action_zoom_region.png"));
258 	mActions[LC_EDIT_FIND]->setIcon(QIcon(":/resources/edit_find.png"));
259 	mActions[LC_EDIT_FIND_NEXT]->setIcon(QIcon(":/resources/edit_find_next.png"));
260 	mActions[LC_EDIT_FIND_PREVIOUS]->setIcon(QIcon(":/resources/edit_find_previous.png"));
261 	mActions[LC_EDIT_FIND_ALL]->setIcon(QIcon(":/resources/edit_find_all.png"));
262 	mActions[LC_EDIT_REPLACE_NEXT]->setIcon(QIcon(":/resources/edit_replace_next.png"));
263 	mActions[LC_EDIT_REPLACE_ALL]->setIcon(QIcon(":/resources/edit_replace_all.png"));
264 	mActions[LC_PIECE_SHOW_EARLIER]->setIcon(QIcon(":/resources/piece_show_earlier.png"));
265 	mActions[LC_PIECE_SHOW_LATER]->setIcon(QIcon(":/resources/piece_show_later.png"));
266 	mActions[LC_VIEW_SPLIT_HORIZONTAL]->setIcon(QIcon(":/resources/view_split_horizontal.png"));
267 	mActions[LC_VIEW_SPLIT_VERTICAL]->setIcon(QIcon(":/resources/view_split_vertical.png"));
268 	mActions[LC_VIEW_ZOOM_IN]->setIcon(QIcon(":/resources/view_zoomin.png"));
269 	mActions[LC_VIEW_ZOOM_OUT]->setIcon(QIcon(":/resources/view_zoomout.png"));
270 	mActions[LC_VIEW_ZOOM_EXTENTS]->setIcon(QIcon(":/resources/view_zoomextents.png"));
271 	mActions[LC_VIEW_TIME_FIRST]->setIcon(QIcon(":/resources/time_first.png"));
272 	mActions[LC_VIEW_TIME_PREVIOUS]->setIcon(QIcon(":/resources/time_previous.png"));
273 	mActions[LC_VIEW_TIME_NEXT]->setIcon(QIcon(":/resources/time_next.png"));
274 	mActions[LC_VIEW_TIME_LAST]->setIcon(QIcon(":/resources/time_last.png"));
275 	mActions[LC_VIEW_TIME_ADD_KEYS]->setIcon(QIcon(":/resources/time_add_keys.png"));
276 	mActions[LC_HELP_HOMEPAGE]->setIcon(QIcon(":/resources/help_homepage.png"));
277 
278 	mActions[LC_EDIT_SNAP_MOVE_TOGGLE]->setCheckable(true);
279 	mActions[LC_EDIT_SNAP_ANGLE_TOGGLE]->setCheckable(true);
280 	mActions[LC_VIEW_CAMERA_NONE]->setCheckable(true);
281 	mActions[LC_VIEW_TIME_ADD_KEYS]->setCheckable(true);
282 
283 	for (int ActionIndex = LC_VIEW_TOOLBAR_FIRST; ActionIndex <= LC_VIEW_TOOLBAR_LAST; ActionIndex++)
284 		mActions[ActionIndex]->setCheckable(true);
285 
286 	QActionGroup* ActionRelativeGroup = new QActionGroup(this);
287 	for (int ActionIdx = LC_EDIT_TRANSFORM_RELATIVE; ActionIdx <= LC_EDIT_TRANSFORM_ABSOLUTE; ActionIdx++)
288 	{
289 		mActions[ActionIdx]->setCheckable(true);
290 		ActionRelativeGroup->addAction(mActions[ActionIdx]);
291 	}
292 
293 	QActionGroup* ActionSeparateGroup = new QActionGroup(this);
294 	for (int ActionIdx = LC_EDIT_TRANSFORM_SEPARATELY; ActionIdx <= LC_EDIT_TRANSFORM_TOGETHER; ActionIdx++)
295 	{
296 		mActions[ActionIdx]->setCheckable(true);
297 		ActionSeparateGroup->addAction(mActions[ActionIdx]);
298 	}
299 
300 	QActionGroup* ActionSnapXYGroup = new QActionGroup(this);
301 	for (int ActionIdx = LC_EDIT_SNAP_MOVE_XY0; ActionIdx <= LC_EDIT_SNAP_MOVE_XY9; ActionIdx++)
302 	{
303 		mActions[ActionIdx]->setCheckable(true);
304 		ActionSnapXYGroup->addAction(mActions[ActionIdx]);
305 	}
306 
307 	QActionGroup* ActionSnapZGroup = new QActionGroup(this);
308 	for (int ActionIdx = LC_EDIT_SNAP_MOVE_Z0; ActionIdx <= LC_EDIT_SNAP_MOVE_Z9; ActionIdx++)
309 	{
310 		mActions[ActionIdx]->setCheckable(true);
311 		ActionSnapZGroup->addAction(mActions[ActionIdx]);
312 	}
313 
314 	QActionGroup* ActionSnapAngleGroup = new QActionGroup(this);
315 	for (int ActionIdx = LC_EDIT_SNAP_ANGLE0; ActionIdx <= LC_EDIT_SNAP_ANGLE9; ActionIdx++)
316 	{
317 		mActions[ActionIdx]->setCheckable(true);
318 		ActionSnapAngleGroup->addAction(mActions[ActionIdx]);
319 	}
320 
321 	QActionGroup* ActionTransformTypeGroup = new QActionGroup(this);
322 	for (int ActionIdx = LC_EDIT_TRANSFORM_ABSOLUTE_TRANSLATION; ActionIdx <= LC_EDIT_TRANSFORM_RELATIVE_ROTATION; ActionIdx++)
323 	{
324 		mActions[ActionIdx]->setCheckable(true);
325 		ActionTransformTypeGroup->addAction(mActions[ActionIdx]);
326 	}
327 
328 	QActionGroup* ActionToolGroup = new QActionGroup(this);
329 	for (int ActionIdx = LC_EDIT_ACTION_FIRST; ActionIdx <= LC_EDIT_ACTION_LAST; ActionIdx++)
330 	{
331 		mActions[ActionIdx]->setCheckable(true);
332 		ActionToolGroup->addAction(mActions[ActionIdx]);
333 	}
334 
335 	QActionGroup* ActionCameraGroup = new QActionGroup(this);
336 	ActionCameraGroup->addAction(mActions[LC_VIEW_CAMERA_NONE]);
337 	for (int ActionIdx = LC_VIEW_CAMERA_FIRST; ActionIdx <= LC_VIEW_CAMERA_LAST; ActionIdx++)
338 	{
339 		mActions[ActionIdx]->setCheckable(true);
340 		ActionCameraGroup->addAction(mActions[ActionIdx]);
341 	}
342 
343 	QActionGroup* ActionPerspectiveGroup = new QActionGroup(this);
344 	for (int ActionIdx = LC_VIEW_PROJECTION_FIRST; ActionIdx <= LC_VIEW_PROJECTION_LAST; ActionIdx++)
345 	{
346 		mActions[ActionIdx]->setCheckable(true);
347 		ActionPerspectiveGroup->addAction(mActions[ActionIdx]);
348 	}
349 
350 	QActionGroup* ActionShadingGroup = new QActionGroup(this);
351 	for (int ActionIdx = LC_VIEW_SHADING_FIRST; ActionIdx <= LC_VIEW_SHADING_LAST; ActionIdx++)
352 	{
353 		mActions[ActionIdx]->setCheckable(true);
354 		ActionShadingGroup->addAction(mActions[ActionIdx]);
355 	}
356 
357 	QActionGroup* SelectionModeGroup = new QActionGroup(this);
358 	for (int ActionIdx = LC_EDIT_SELECTION_MODE_FIRST; ActionIdx <= LC_EDIT_SELECTION_MODE_LAST; ActionIdx++)
359 	{
360 		mActions[ActionIdx]->setCheckable(true);
361 		SelectionModeGroup->addAction(mActions[ActionIdx]);
362 	}
363 
364 	QActionGroup* ModelGroup = new QActionGroup(this);
365 	for (int ActionIdx = LC_MODEL_FIRST; ActionIdx <= LC_MODEL_LAST; ActionIdx++)
366 	{
367 		mActions[ActionIdx]->setCheckable(true);
368 		ModelGroup->addAction(mActions[ActionIdx]);
369 	}
370 
371 	UpdateShortcuts();
372 }
373 
CreateMenus()374 void lcMainWindow::CreateMenus()
375 {
376 	QMenu* TransformMenu = new QMenu(tr("Transform"), this);
377 	TransformMenu->addAction(mActions[LC_EDIT_TRANSFORM_RELATIVE_TRANSLATION]);
378 	TransformMenu->addAction(mActions[LC_EDIT_TRANSFORM_ABSOLUTE_TRANSLATION]);
379 	TransformMenu->addAction(mActions[LC_EDIT_TRANSFORM_RELATIVE_ROTATION]);
380 	TransformMenu->addAction(mActions[LC_EDIT_TRANSFORM_ABSOLUTE_ROTATION]);
381 	mActions[LC_EDIT_TRANSFORM]->setMenu(TransformMenu);
382 
383 	mCameraMenu = new QMenu(tr("C&ameras"), this);
384 	mCameraMenu->addAction(mActions[LC_VIEW_CAMERA_NONE]);
385 
386 	for (int actionIdx = LC_VIEW_CAMERA_FIRST; actionIdx <= LC_VIEW_CAMERA_LAST; actionIdx++)
387 		mCameraMenu->addAction(mActions[actionIdx]);
388 
389 	mViewpointMenu = new QMenu(tr("&Viewpoints"), this);
390 	mViewpointMenu->addAction(mActions[LC_VIEW_VIEWPOINT_FRONT]);
391 	mViewpointMenu->addAction(mActions[LC_VIEW_VIEWPOINT_BACK]);
392 	mViewpointMenu->addAction(mActions[LC_VIEW_VIEWPOINT_LEFT]);
393 	mViewpointMenu->addAction(mActions[LC_VIEW_VIEWPOINT_RIGHT]);
394 	mViewpointMenu->addAction(mActions[LC_VIEW_VIEWPOINT_TOP]);
395 	mViewpointMenu->addAction(mActions[LC_VIEW_VIEWPOINT_BOTTOM]);
396 	mViewpointMenu->addAction(mActions[LC_VIEW_VIEWPOINT_HOME]);
397 
398 	mProjectionMenu = new QMenu(tr("Projection"), this);
399 	mProjectionMenu->addAction(mActions[LC_VIEW_PROJECTION_PERSPECTIVE]);
400 	mProjectionMenu->addAction(mActions[LC_VIEW_PROJECTION_ORTHO]);
401 
402 	mShadingMenu = new QMenu(tr("Sh&ading"), this);
403 	mShadingMenu->addAction(mActions[LC_VIEW_SHADING_WIREFRAME]);
404 	mShadingMenu->addAction(mActions[LC_VIEW_SHADING_FLAT]);
405 	mShadingMenu->addAction(mActions[LC_VIEW_SHADING_DEFAULT_LIGHTS]);
406 
407 	mToolsMenu = new QMenu(tr("Tools"), this);
408 	mToolsMenu->addAction(mActions[LC_EDIT_ACTION_INSERT]);
409 	mToolsMenu->addAction(mActions[LC_EDIT_ACTION_LIGHT]);
410 	mToolsMenu->addAction(mActions[LC_EDIT_ACTION_SPOTLIGHT]);
411 	mToolsMenu->addAction(mActions[LC_EDIT_ACTION_CAMERA]);
412 	mToolsMenu->addSeparator();
413 	mToolsMenu->addAction(mActions[LC_EDIT_ACTION_SELECT]);
414 	mToolsMenu->addAction(mActions[LC_EDIT_ACTION_MOVE]);
415 	mToolsMenu->addAction(mActions[LC_EDIT_ACTION_ROTATE]);
416 	mToolsMenu->addAction(mActions[LC_EDIT_ACTION_DELETE]);
417 	mToolsMenu->addAction(mActions[LC_EDIT_ACTION_PAINT]);
418 	mToolsMenu->addAction(mActions[LC_EDIT_ACTION_COLOR_PICKER]);
419 	mToolsMenu->addSeparator();
420 	mToolsMenu->addAction(mActions[LC_EDIT_ACTION_ZOOM]);
421 	mToolsMenu->addAction(mActions[LC_EDIT_ACTION_PAN]);
422 	mToolsMenu->addAction(mActions[LC_EDIT_ACTION_ROTATE_VIEW]);
423 	mToolsMenu->addAction(mActions[LC_EDIT_ACTION_ROLL]);
424 	mToolsMenu->addAction(mActions[LC_EDIT_ACTION_ZOOM_REGION]);
425 
426 	QMenu* FileMenu = menuBar()->addMenu(tr("&File"));
427 	FileMenu->addAction(mActions[LC_FILE_NEW]);
428 	FileMenu->addAction(mActions[LC_FILE_OPEN]);
429 	FileMenu->addAction(mActions[LC_FILE_MERGE]);
430 	FileMenu->addSeparator();
431 	FileMenu->addAction(mActions[LC_FILE_SAVE]);
432 	FileMenu->addAction(mActions[LC_FILE_SAVEAS]);
433 	FileMenu->addAction(mActions[LC_FILE_SAVE_IMAGE]);
434 	QMenu* ImportMenu = FileMenu->addMenu(tr("&Import"));
435 	ImportMenu->addAction(mActions[LC_FILE_IMPORT_LDD]);
436 	ImportMenu->addAction(mActions[LC_FILE_IMPORT_INVENTORY]);
437 	QMenu* ExportMenu = FileMenu->addMenu(tr("&Export"));
438 	ExportMenu->addAction(mActions[LC_FILE_EXPORT_3DS]);
439 	ExportMenu->addAction(mActions[LC_FILE_EXPORT_BRICKLINK]);
440 	ExportMenu->addAction(mActions[LC_FILE_EXPORT_COLLADA]);
441 	ExportMenu->addAction(mActions[LC_FILE_EXPORT_CSV]);
442 	ExportMenu->addAction(mActions[LC_FILE_EXPORT_HTML]);
443 	ExportMenu->addAction(mActions[LC_FILE_EXPORT_POVRAY]);
444 	ExportMenu->addAction(mActions[LC_FILE_EXPORT_WAVEFRONT]);
445 	FileMenu->addSeparator();
446 	FileMenu->addAction(mActions[LC_FILE_RENDER]);
447 	FileMenu->addAction(mActions[LC_FILE_INSTRUCTIONS]);
448 	FileMenu->addAction(mActions[LC_FILE_PRINT]);
449 	FileMenu->addAction(mActions[LC_FILE_PRINT_PREVIEW]);
450 	FileMenu->addSeparator();
451 	FileMenu->addAction(mActions[LC_FILE_RECENT1]);
452 	FileMenu->addAction(mActions[LC_FILE_RECENT2]);
453 	FileMenu->addAction(mActions[LC_FILE_RECENT3]);
454 	FileMenu->addAction(mActions[LC_FILE_RECENT4]);
455 	mActionFileRecentSeparator = FileMenu->addSeparator();
456 	FileMenu->addAction(mActions[LC_FILE_EXIT]);
457 
458 	QMenu* EditMenu = menuBar()->addMenu(tr("&Edit"));
459 	EditMenu->addAction(mActions[LC_EDIT_UNDO]);
460 	EditMenu->addAction(mActions[LC_EDIT_REDO]);
461 	EditMenu->addSeparator();
462 	EditMenu->addAction(mActions[LC_EDIT_CUT]);
463 	EditMenu->addAction(mActions[LC_EDIT_COPY]);
464 	EditMenu->addAction(mActions[LC_EDIT_PASTE]);
465 	EditMenu->addAction(mActions[LC_EDIT_PASTE_STEPS]);
466 	EditMenu->addSeparator();
467 	EditMenu->addAction(mActions[LC_EDIT_FIND]);
468 	EditMenu->addAction(mActions[LC_EDIT_FIND_NEXT]);
469 	EditMenu->addAction(mActions[LC_EDIT_FIND_PREVIOUS]);
470 	EditMenu->addAction(mActions[LC_EDIT_REPLACE]);
471 	EditMenu->addAction(mActions[LC_EDIT_REPLACE_NEXT]);
472 	EditMenu->addSeparator();
473 	EditMenu->addAction(mActions[LC_EDIT_SELECT_ALL]);
474 	EditMenu->addAction(mActions[LC_EDIT_SELECT_NONE]);
475 	EditMenu->addAction(mActions[LC_EDIT_SELECT_INVERT]);
476 	EditMenu->addAction(mActions[LC_EDIT_SELECT_BY_NAME]);
477 	EditMenu->addMenu(mSelectionModeMenu);
478 	EditMenu->addSeparator();
479 	EditMenu->addMenu(mTransformMenu);
480 	EditMenu->addMenu(mToolsMenu);
481 
482 	QMenu* ViewMenu = menuBar()->addMenu(tr("&View"));
483 	ViewMenu->addAction(mActions[LC_VIEW_PREFERENCES]);
484 	ViewMenu->addSeparator();
485 	ViewMenu->addAction(mActions[LC_VIEW_ZOOM_EXTENTS]);
486 	ViewMenu->addAction(mActions[LC_VIEW_LOOK_AT]);
487 	ViewMenu->addMenu(mViewpointMenu);
488 	ViewMenu->addMenu(mCameraMenu);
489 	ViewMenu->addMenu(mProjectionMenu);
490 	ViewMenu->addMenu(mShadingMenu);
491 	QMenu* StepMenu = ViewMenu->addMenu(tr("Ste&p"));
492 	StepMenu->addAction(mActions[LC_VIEW_TIME_FIRST]);
493 	StepMenu->addAction(mActions[LC_VIEW_TIME_PREVIOUS]);
494 	StepMenu->addAction(mActions[LC_VIEW_TIME_NEXT]);
495 	StepMenu->addAction(mActions[LC_VIEW_TIME_LAST]);
496 	StepMenu->addSeparator();
497 	StepMenu->addAction(mActions[LC_VIEW_TIME_INSERT_BEFORE]);
498 	StepMenu->addAction(mActions[LC_VIEW_TIME_INSERT_AFTER]);
499 	StepMenu->addAction(mActions[LC_VIEW_TIME_DELETE]);
500 	ViewMenu->addSeparator();
501 	ViewMenu->addAction(mActions[LC_VIEW_SPLIT_HORIZONTAL]);
502 	ViewMenu->addAction(mActions[LC_VIEW_SPLIT_VERTICAL]);
503 	ViewMenu->addAction(mActions[LC_VIEW_REMOVE_VIEW]);
504 	ViewMenu->addAction(mActions[LC_VIEW_RESET_VIEWS]);
505 	ViewMenu->addSeparator();
506 	QMenu* ToolBarsMenu = ViewMenu->addMenu(tr("T&oolbars"));
507 	connect(ToolBarsMenu, SIGNAL(aboutToShow()), this, SLOT(UpdateDockWidgetActions()));
508 	ToolBarsMenu->addAction(mActions[LC_VIEW_TOOLBAR_PARTS]);
509 	ToolBarsMenu->addAction(mActions[LC_VIEW_TOOLBAR_COLORS]);
510 	ToolBarsMenu->addAction(mActions[LC_VIEW_TOOLBAR_PROPERTIES]);
511 	ToolBarsMenu->addAction(mActions[LC_VIEW_TOOLBAR_TIMELINE]);
512 	ToolBarsMenu->addAction(mActions[LC_VIEW_TOOLBAR_PREVIEW]);
513 	ToolBarsMenu->addSeparator();
514 	ToolBarsMenu->addAction(mActions[LC_VIEW_TOOLBAR_STANDARD]);
515 	ToolBarsMenu->addAction(mActions[LC_VIEW_TOOLBAR_TOOLS]);
516 	ToolBarsMenu->addAction(mActions[LC_VIEW_TOOLBAR_TIME]);
517 	ViewMenu->addAction(mActions[LC_VIEW_FULLSCREEN]);
518 
519 	QMenu* PieceMenu = menuBar()->addMenu(tr("&Piece"));
520 	PieceMenu->addAction(mActions[LC_PIECE_INSERT]);
521 	PieceMenu->addAction(mActions[LC_PIECE_DELETE]);
522 	PieceMenu->addAction(mActions[LC_PIECE_DUPLICATE]);
523 	PieceMenu->addAction(mActions[LC_PIECE_PAINT_SELECTED]);
524 	PieceMenu->addAction(mActions[LC_PIECE_ARRAY]);
525 	PieceMenu->addAction(mActions[LC_PIECE_MINIFIG_WIZARD]);
526 	PieceMenu->addAction(mActions[LC_PIECE_RESET_PIVOT_POINT]);
527 	PieceMenu->addAction(mActions[LC_PIECE_REMOVE_KEY_FRAMES]);
528 	PieceMenu->addSeparator();
529 	PieceMenu->addAction(mActions[LC_PIECE_EDIT_SELECTED_SUBMODEL]);
530 	PieceMenu->addAction(mActions[LC_PIECE_EDIT_END_SUBMODEL]);
531 	PieceMenu->addAction(mActions[LC_PIECE_VIEW_SELECTED_MODEL]);
532 	PieceMenu->addAction(mActions[LC_PIECE_INLINE_SELECTED_MODELS]);
533 	PieceMenu->addAction(mActions[LC_PIECE_MOVE_SELECTION_TO_MODEL]);
534 	PieceMenu->addSeparator();
535 	PieceMenu->addAction(mActions[LC_PIECE_GROUP]);
536 	PieceMenu->addAction(mActions[LC_PIECE_UNGROUP]);
537 	PieceMenu->addAction(mActions[LC_PIECE_GROUP_REMOVE]);
538 	PieceMenu->addAction(mActions[LC_PIECE_GROUP_ADD]);
539 	PieceMenu->addAction(mActions[LC_PIECE_GROUP_EDIT]);
540 	PieceMenu->addSeparator();
541 	PieceMenu->addAction(mActions[LC_PIECE_HIDE_SELECTED]);
542 	PieceMenu->addAction(mActions[LC_PIECE_HIDE_UNSELECTED]);
543 	PieceMenu->addAction(mActions[LC_PIECE_UNHIDE_SELECTED]);
544 	PieceMenu->addAction(mActions[LC_PIECE_UNHIDE_ALL]);
545 
546 	QMenu* ModelMenu = menuBar()->addMenu(tr("Sub&model"));
547 	ModelMenu->addAction(mActions[LC_MODEL_PROPERTIES]);
548 	ModelMenu->addAction(mActions[LC_MODEL_NEW]);
549 	ModelMenu->addAction(mActions[LC_MODEL_LIST]);
550 	ModelMenu->addSeparator();
551 	for (int ModelIdx = LC_MODEL_FIRST; ModelIdx <= LC_MODEL_LAST; ModelIdx++)
552 		ModelMenu->addAction(mActions[ModelIdx]);
553 
554 	QMenu* HelpMenu = menuBar()->addMenu(tr("&Help"));
555 	HelpMenu->addAction(mActions[LC_HELP_HOMEPAGE]);
556 	HelpMenu->addAction(mActions[LC_HELP_BUG_REPORT]);
557 #if !LC_DISABLE_UPDATE_CHECK
558 	HelpMenu->addAction(mActions[LC_HELP_UPDATES]);
559 #endif
560 #ifndef Q_OS_MACOS
561 	HelpMenu->addSeparator();
562 #endif
563 	HelpMenu->addAction(mActions[LC_HELP_ABOUT]);
564 }
565 
CreateToolBars()566 void lcMainWindow::CreateToolBars()
567 {
568 	mSelectionModeMenu = new QMenu(tr("Selection Mode"), this);
569 	for (int ModeIdx = LC_EDIT_SELECTION_MODE_FIRST; ModeIdx <= LC_EDIT_SELECTION_MODE_LAST; ModeIdx++)
570 		mSelectionModeMenu->addAction(mActions[ModeIdx]);
571 
572 	QAction* SelectionModeAction = new QAction(tr("Selection Mode"), this);
573 	SelectionModeAction->setStatusTip(tr("Change selection mode"));
574 	SelectionModeAction->setIcon(QIcon(":/resources/action_select.png"));
575 	SelectionModeAction->setMenu(mSelectionModeMenu);
576 
577 	mTransformMenu = new QMenu(tr("Transform"), this);
578 	mTransformMenu->addAction(mActions[LC_EDIT_TRANSFORM_RELATIVE]);
579 	mTransformMenu->addAction(mActions[LC_EDIT_TRANSFORM_ABSOLUTE]);
580 	mTransformMenu->addSeparator();
581 	mTransformMenu->addAction(mActions[LC_EDIT_TRANSFORM_TOGETHER]);
582 	mTransformMenu->addAction(mActions[LC_EDIT_TRANSFORM_SEPARATELY]);
583 
584 	QAction* TransformAction = new QAction(tr("Transform"), this);
585 	TransformAction->setStatusTip(tr("Transform Options"));
586 	TransformAction->setIcon(QIcon(":/resources/edit_transform_relative.png"));
587 	TransformAction->setMenu(mTransformMenu);
588 
589 	QMenu* SnapXYMenu = new QMenu(tr("Snap XY"), this);
590 	for (int actionIdx = LC_EDIT_SNAP_MOVE_XY0; actionIdx <= LC_EDIT_SNAP_MOVE_XY9; actionIdx++)
591 		SnapXYMenu->addAction(mActions[actionIdx]);
592 
593 	QMenu* SnapZMenu = new QMenu(tr("Snap Z"), this);
594 	for (int actionIdx = LC_EDIT_SNAP_MOVE_Z0; actionIdx <= LC_EDIT_SNAP_MOVE_Z9; actionIdx++)
595 		SnapZMenu->addAction(mActions[actionIdx]);
596 
597 	QMenu* SnapMenu = new QMenu(tr("Snap Menu"), this);
598 	SnapMenu->addAction(mActions[LC_EDIT_SNAP_MOVE_TOGGLE]);
599 	SnapMenu->addSeparator();
600 	SnapMenu->addMenu(SnapXYMenu);
601 	SnapMenu->addMenu(SnapZMenu);
602 
603 	QAction* MoveAction = new QAction(tr("Movement Snap"), this);
604 	MoveAction->setStatusTip(tr("Snap translations to fixed intervals"));
605 	MoveAction->setIcon(QIcon(":/resources/edit_snap_move.png"));
606 	MoveAction->setMenu(SnapMenu);
607 
608 	QMenu* SnapAngleMenu = new QMenu(tr("Snap Angle Menu"), this);
609 	SnapAngleMenu->addAction(mActions[LC_EDIT_SNAP_ANGLE_TOGGLE]);
610 	SnapAngleMenu->addSeparator();
611 	for (int actionIdx = LC_EDIT_SNAP_ANGLE0; actionIdx <= LC_EDIT_SNAP_ANGLE9; actionIdx++)
612 		SnapAngleMenu->addAction(mActions[actionIdx]);
613 
614 	QAction* AngleAction = new QAction(tr("Rotation Snap"), this);
615 	AngleAction->setStatusTip(tr("Snap rotations to fixed intervals"));
616 	AngleAction->setIcon(QIcon(":/resources/edit_snap_angle.png"));
617 	AngleAction->setMenu(SnapAngleMenu);
618 
619 	mStandardToolBar = addToolBar(tr("Standard"));
620 	mStandardToolBar->setObjectName("StandardToolbar");
621 	mStandardToolBar->addAction(mActions[LC_FILE_NEW]);
622 	mStandardToolBar->addAction(mActions[LC_FILE_OPEN]);
623 	mStandardToolBar->addAction(mActions[LC_FILE_SAVE]);
624 	mStandardToolBar->addSeparator();
625 	mStandardToolBar->addAction(mActions[LC_EDIT_UNDO]);
626 	mStandardToolBar->addAction(mActions[LC_EDIT_REDO]);
627 	mStandardToolBar->addSeparator();
628 	mStandardToolBar->addAction(SelectionModeAction);
629 	mStandardToolBar->addAction(TransformAction);
630 	mStandardToolBar->addAction(MoveAction);
631 	mStandardToolBar->addAction(AngleAction);
632 	((QToolButton*)mStandardToolBar->widgetForAction(SelectionModeAction))->setPopupMode(QToolButton::InstantPopup);
633 	((QToolButton*)mStandardToolBar->widgetForAction(TransformAction))->setPopupMode(QToolButton::InstantPopup);
634 	((QToolButton*)mStandardToolBar->widgetForAction(MoveAction))->setPopupMode(QToolButton::InstantPopup);
635 	((QToolButton*)mStandardToolBar->widgetForAction(AngleAction))->setPopupMode(QToolButton::InstantPopup);
636 
637 	mTimeToolBar = addToolBar(tr("Time"));
638 	mTimeToolBar->setObjectName("TimeToolbar");
639 	mTimeToolBar->addAction(mActions[LC_VIEW_TIME_FIRST]);
640 	mTimeToolBar->addAction(mActions[LC_VIEW_TIME_PREVIOUS]);
641 	mTimeToolBar->addAction(mActions[LC_VIEW_TIME_NEXT]);
642 	mTimeToolBar->addAction(mActions[LC_VIEW_TIME_LAST]);
643 	mTimeToolBar->addAction(mActions[LC_VIEW_TIME_ADD_KEYS]);
644 
645 	mToolsToolBar = addToolBar(tr("Tools"));
646 	mToolsToolBar->setObjectName("ToolsToolbar");
647 	insertToolBarBreak(mToolsToolBar);
648 	mToolsToolBar->addAction(mActions[LC_EDIT_ACTION_INSERT]);
649 	mToolsToolBar->addAction(mActions[LC_EDIT_ACTION_LIGHT]);
650 	mToolsToolBar->addAction(mActions[LC_EDIT_ACTION_SPOTLIGHT]);
651 	mToolsToolBar->addAction(mActions[LC_EDIT_ACTION_CAMERA]);
652 	mToolsToolBar->addSeparator();
653 	mToolsToolBar->addAction(mActions[LC_EDIT_ACTION_SELECT]);
654 	mToolsToolBar->addAction(mActions[LC_EDIT_ACTION_MOVE]);
655 	mToolsToolBar->addAction(mActions[LC_EDIT_ACTION_ROTATE]);
656 	mToolsToolBar->addAction(mActions[LC_EDIT_ACTION_DELETE]);
657 	mToolsToolBar->addAction(mActions[LC_EDIT_ACTION_PAINT]);
658 	mToolsToolBar->addAction(mActions[LC_EDIT_ACTION_COLOR_PICKER]);
659 	mToolsToolBar->addSeparator();
660 	mToolsToolBar->addAction(mActions[LC_EDIT_ACTION_ZOOM]);
661 	mToolsToolBar->addAction(mActions[LC_EDIT_ACTION_PAN]);
662 	mToolsToolBar->addAction(mActions[LC_EDIT_ACTION_ROTATE_VIEW]);
663 	mToolsToolBar->addAction(mActions[LC_EDIT_ACTION_ROLL]);
664 	mToolsToolBar->addAction(mActions[LC_EDIT_ACTION_ZOOM_REGION]);
665 	mToolsToolBar->hide();
666 
667 	mPartsToolBar = new QDockWidget(tr("Parts"), this);
668 	mPartsToolBar->setObjectName("PartsToolbar");
669 	mPartSelectionWidget = new lcPartSelectionWidget(mPartsToolBar);
670 	mPartsToolBar->setWidget(mPartSelectionWidget);
671 	addDockWidget(Qt::RightDockWidgetArea, mPartsToolBar);
672 
673 	mColorsToolBar = new QDockWidget(tr("Colors"), this);
674 	mColorsToolBar->setObjectName("ColorsToolbar");
675 	mColorsToolBar->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
676 
677 	mColorList = new lcQColorList();
678 	connect(mColorList, SIGNAL(colorChanged(int)), this, SLOT(ColorChanged(int)));
679 
680 	QWidget* ColorWidget = new QWidget(mColorsToolBar);
681 
682 	QVBoxLayout* ColorLayout = new QVBoxLayout(ColorWidget);
683 	ColorLayout->setContentsMargins(0, 0, 0, 0);
684 
685 	QHBoxLayout* ColorButtonLayout = new QHBoxLayout();
686 	ColorButtonLayout->setContentsMargins(0, 0, 0, 0);
687 	ColorLayout->addLayout(ColorButtonLayout);
688 
689 	mColorButton = new QToolButton(ColorWidget);
690 	mColorButton->setAutoRaise(true);
691 	mColorButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
692 	mColorButton->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Maximum);
693 	ColorButtonLayout->addWidget(mColorButton);
694 
695 	connect(mColorButton, SIGNAL(clicked()), this, SLOT(ColorButtonClicked()));
696 
697 	ColorLayout->addWidget(mColorList);
698 
699 	mColorsToolBar->setWidget(ColorWidget);
700 	addDockWidget(Qt::RightDockWidgetArea, mColorsToolBar);
701 
702 	mPropertiesToolBar = new QDockWidget(tr("Properties"), this);
703 	mPropertiesToolBar->setObjectName("PropertiesToolbar");
704 
705 	QWidget* PropertiesWidget = new QWidget(mPropertiesToolBar);
706 	QVBoxLayout* PropertiesLayout = new QVBoxLayout(PropertiesWidget);
707 	PropertiesLayout->setContentsMargins(0, 0, 0, 0);
708 
709 	mPropertiesWidget = new lcQPropertiesTree(PropertiesWidget);
710 	PropertiesLayout->addWidget(mPropertiesWidget);
711 
712 	QHBoxLayout* TransformLayout = new QHBoxLayout;
713 	QWidget* TransformWidget = new QWidget();
714 	TransformWidget->setLayout(TransformLayout);
715 
716 	QToolButton* TransformButton = new QToolButton(TransformWidget);
717 	TransformButton->setDefaultAction(mActions[LC_EDIT_TRANSFORM]);
718 	TransformButton->setPopupMode(QToolButton::InstantPopup);
719 	TransformLayout->addWidget(TransformButton);
720 
721 	mTransformXEdit = new lcTransformLineEdit();
722 	TransformLayout->addWidget(mTransformXEdit);
723 	mTransformYEdit = new lcTransformLineEdit();
724 	TransformLayout->addWidget(mTransformYEdit);
725 	mTransformZEdit = new lcTransformLineEdit();
726 	TransformLayout->addWidget(mTransformZEdit);
727 
728 	PropertiesLayout->addWidget(TransformWidget);
729 
730 	connect(mTransformXEdit, SIGNAL(returnPressed()), mActions[LC_EDIT_TRANSFORM], SIGNAL(triggered()));
731 	connect(mTransformYEdit, SIGNAL(returnPressed()), mActions[LC_EDIT_TRANSFORM], SIGNAL(triggered()));
732 	connect(mTransformZEdit, SIGNAL(returnPressed()), mActions[LC_EDIT_TRANSFORM], SIGNAL(triggered()));
733 
734 	mPropertiesToolBar->setWidget(PropertiesWidget);
735 	addDockWidget(Qt::RightDockWidgetArea, mPropertiesToolBar);
736 
737 	mTimelineToolBar = new QDockWidget(tr("Timeline"), this);
738 	mTimelineToolBar->setObjectName("TimelineToolbar");
739 	mTimelineToolBar->setAcceptDrops(true);
740 
741 	mTimelineWidget = new lcTimelineWidget(mTimelineToolBar);
742 
743 	mTimelineToolBar->setWidget(mTimelineWidget);
744 	addDockWidget(Qt::RightDockWidgetArea, mTimelineToolBar);
745 
746 	CreatePreviewWidget();
747 
748 	tabifyDockWidget(mPartsToolBar, mPropertiesToolBar);
749 	tabifyDockWidget(mPropertiesToolBar, mTimelineToolBar);
750 	tabifyDockWidget(mTimelineToolBar, mPreviewToolBar);
751 
752 	connect(mPropertiesToolBar, SIGNAL(topLevelChanged(bool)), this, SLOT(EnableWindowFlags(bool)));
753 	connect(mTimelineToolBar,   SIGNAL(topLevelChanged(bool)), this, SLOT(EnableWindowFlags(bool)));
754 	connect(mPartsToolBar,      SIGNAL(topLevelChanged(bool)), this, SLOT(EnableWindowFlags(bool)));
755 	connect(mColorsToolBar,     SIGNAL(topLevelChanged(bool)), this, SLOT(EnableWindowFlags(bool)));
756 
757 	mPartsToolBar->raise();
758 }
759 
CreateView(lcModel * Model)760 lcView* lcMainWindow::CreateView(lcModel* Model)
761 {
762 	lcView* NewView = new lcView(lcViewType::View, Model);
763 
764 	connect(NewView, SIGNAL(CameraChanged()), this, SLOT(ViewCameraChanged()));
765 	connect(NewView, SIGNAL(FocusReceived()), this, SLOT(ViewFocusReceived()));
766 
767 	AddView(NewView);
768 
769 	return NewView;
770 }
771 
PreviewPiece(const QString & PartId,int ColorCode,bool ShowPreview)772 void lcMainWindow::PreviewPiece(const QString& PartId, int ColorCode, bool ShowPreview)
773 {
774 	if (ShowPreview)
775 		mPreviewToolBar->show();
776 
777 	mPreviewWidget->SetCurrentPiece(PartId, ColorCode);
778 }
779 
CreatePreviewWidget()780 void lcMainWindow::CreatePreviewWidget()
781 {
782 	mPreviewWidget  = new lcPreviewDockWidget();
783 
784 	mPreviewToolBar = new QDockWidget(tr("Preview"), this);
785 	mPreviewToolBar->setWindowTitle(tr("Preview"));
786 	mPreviewToolBar->setObjectName("PreviewToolBar");
787 	mPreviewToolBar->setWidget(mPreviewWidget);
788 	addDockWidget(Qt::RightDockWidgetArea, mPreviewToolBar);
789 
790 	connect(mPreviewToolBar, SIGNAL(topLevelChanged(bool)), this, SLOT(EnableWindowFlags(bool)));
791 }
792 
TogglePreviewWidget(bool Visible)793 void lcMainWindow::TogglePreviewWidget(bool Visible)
794 {
795 	if (mPreviewToolBar)
796 	{
797 		if (Visible)
798 			mPreviewToolBar->show();
799 		else
800 			mPreviewToolBar->hide();
801 	}
802 	else if (Visible)
803 	{
804 		CreatePreviewWidget();
805 	}
806 }
807 
EnableWindowFlags(bool Detached)808 void lcMainWindow::EnableWindowFlags(bool Detached)
809 {
810 	if (Detached)
811 	{
812 		QDockWidget* DockWidget = qobject_cast<QDockWidget*>(sender());
813 
814 		DockWidget->setWindowFlags(Qt::CustomizeWindowHint | Qt::Window | Qt::WindowMinimizeButtonHint | Qt::WindowMaximizeButtonHint | Qt::WindowCloseButtonHint);
815 
816 		if (isVisible())
817 			DockWidget->show();
818 	}
819 }
820 
821 class lcElidedLabel : public QFrame
822 {
823 public:
lcElidedLabel(QWidget * Parent=nullptr)824 	explicit lcElidedLabel(QWidget* Parent = nullptr)
825 		: QFrame(Parent)
826 	{
827 		setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
828 	}
829 
setText(const QString & Text)830 	void setText(const QString& Text)
831 	{
832 		mText = Text;
833 		update();
834 	}
835 
836 protected:
837 	void paintEvent(QPaintEvent* event) override;
838 
839 	QString mText;
840 };
841 
paintEvent(QPaintEvent * event)842 void lcElidedLabel::paintEvent(QPaintEvent* event)
843 {
844 	QFrame::paintEvent(event);
845 
846 	QPainter Painter(this);
847 	QFontMetrics FontMetrics = Painter.fontMetrics();
848 
849 	int LineSpacing = FontMetrics.lineSpacing();
850 	int y = 0;
851 
852 	QTextLayout TextLayout(mText, Painter.font());
853 	TextLayout.beginLayout();
854 
855 	for (;;)
856 	{
857 		QTextLine Line = TextLayout.createLine();
858 
859 		if (!Line.isValid())
860 			break;
861 
862 		Line.setLineWidth(width());
863 		int NextLineY = y + LineSpacing;
864 
865 		if (height() >= NextLineY + LineSpacing)
866 		{
867 			Line.draw(&Painter, QPoint(0, y));
868 			y = NextLineY;
869 		}
870 		else
871 		{
872 			QString LastLine = mText.mid(Line.textStart());
873 			QString ElidedLastLine = FontMetrics.elidedText(LastLine, Qt::ElideRight, width());
874 			Painter.drawText(QPoint(0, y + FontMetrics.ascent()), ElidedLastLine);
875 			Line = TextLayout.createLine();
876 			break;
877 		}
878 	}
879 
880 	TextLayout.endLayout();
881 }
882 
CreateStatusBar()883 void lcMainWindow::CreateStatusBar()
884 {
885 	QStatusBar* StatusBar = new QStatusBar(this);
886 	setStatusBar(StatusBar);
887 
888 	mStatusBarLabel = new lcElidedLabel();
889 	StatusBar->addWidget(mStatusBarLabel, 1);
890 
891 	mStatusPositionLabel = new QLabel();
892 	StatusBar->addPermanentWidget(mStatusPositionLabel);
893 
894 	mStatusSnapLabel = new QLabel();
895 	StatusBar->addPermanentWidget(mStatusSnapLabel);
896 
897 	mStatusTimeLabel = new QLabel();
898 	StatusBar->addPermanentWidget(mStatusTimeLabel);
899 }
900 
closeEvent(QCloseEvent * Event)901 void lcMainWindow::closeEvent(QCloseEvent* Event)
902 {
903 	if (SaveProjectIfModified())
904 	{
905 		Event->accept();
906 
907 		QSettings Settings;
908 		Settings.beginGroup("MainWindow");
909 		Settings.setValue("Geometry", saveGeometry());
910 		Settings.setValue("State", saveState());
911 		mPartSelectionWidget->SaveState(Settings);
912 		Settings.endGroup();
913 
914 		gApplication->SaveTabLayout();
915 	}
916 	else
917 		Event->ignore();
918 }
919 
dragEnterEvent(QDragEnterEvent * Event)920 void lcMainWindow::dragEnterEvent(QDragEnterEvent* Event)
921 {
922 	if (Event->mimeData()->hasUrls())
923 		Event->acceptProposedAction();
924 }
925 
dropEvent(QDropEvent * Event)926 void lcMainWindow::dropEvent(QDropEvent* Event)
927 {
928 	const QMimeData* MimeData = Event->mimeData();
929 	const QList<QUrl> Urls = MimeData->urls();
930 	for (const QUrl& Url : Urls)
931 		if (OpenProject(Url.toLocalFile()))
932 			break;
933 }
934 
createPopupMenu()935 QMenu* lcMainWindow::createPopupMenu()
936 {
937 	QMenu* Menu = new QMenu(this);
938 
939 	UpdateDockWidgetActions();
940 
941 	Menu->addAction(mActions[LC_VIEW_TOOLBAR_PARTS]);
942 	Menu->addAction(mActions[LC_VIEW_TOOLBAR_COLORS]);
943 	Menu->addAction(mActions[LC_VIEW_TOOLBAR_PROPERTIES]);
944 	Menu->addAction(mActions[LC_VIEW_TOOLBAR_TIMELINE]);
945 	Menu->addAction(mActions[LC_VIEW_TOOLBAR_PREVIEW]);
946 	Menu->addSeparator();
947 	Menu->addAction(mActions[LC_VIEW_TOOLBAR_STANDARD]);
948 	Menu->addAction(mActions[LC_VIEW_TOOLBAR_TOOLS]);
949 	Menu->addAction(mActions[LC_VIEW_TOOLBAR_TIME]);
950 
951 	return Menu;
952 }
953 
UpdateDockWidgetActions()954 void lcMainWindow::UpdateDockWidgetActions()
955 {
956 	mActions[LC_VIEW_TOOLBAR_PARTS]->setChecked(mPartsToolBar->isVisible());
957 	mActions[LC_VIEW_TOOLBAR_COLORS]->setChecked(mColorsToolBar->isVisible());
958 	mActions[LC_VIEW_TOOLBAR_PROPERTIES]->setChecked(mPropertiesToolBar->isVisible());
959 	mActions[LC_VIEW_TOOLBAR_TIMELINE]->setChecked(mTimelineToolBar->isVisible());
960 	mActions[LC_VIEW_TOOLBAR_STANDARD]->setChecked(mStandardToolBar->isVisible());
961 	mActions[LC_VIEW_TOOLBAR_TOOLS]->setChecked(mToolsToolBar->isVisible());
962 	mActions[LC_VIEW_TOOLBAR_TIME]->setChecked(mTimeToolBar->isVisible());
963 	mActions[LC_VIEW_TOOLBAR_PREVIEW]->setChecked(mPreviewToolBar->isVisible());
964 }
965 
UpdateGamepads()966 void lcMainWindow::UpdateGamepads()
967 {
968 #if LC_ENABLE_GAMEPAD
969 	QDateTime Now = QDateTime::currentDateTime();
970 	quint64 Elapsed = mLastGamepadUpdate.msecsTo(Now);
971 	mLastGamepadUpdate = Now;
972 
973 	if (!gMainWindow)
974 		return;
975 
976 	lcView* ActiveView = GetActiveView();
977 	if (!ActiveView)
978 		return;
979 
980 	const QList<int> Gamepads = QGamepadManager::instance()->connectedGamepads();
981 	if (Gamepads.isEmpty())
982 		return;
983 
984 	QGamepad Gamepad(Gamepads[0]);
985 
986 	float Scale = (float)Elapsed / 20.0f;
987 	lcVector3 Distance(Scale * Gamepad.axisLeftX(), 0.0f, -Scale * Gamepad.axisLeftY());
988 
989 	if (fabsf(Distance.LengthSquared()) > 0.01f)
990 		ActiveView->MoveCamera(Distance);
991 #endif
992 }
993 
ModelTabContextMenuRequested(const QPoint & Point)994 void lcMainWindow::ModelTabContextMenuRequested(const QPoint& Point)
995 {
996 	QMenu* Menu = new QMenu;
997 
998 	mModelTabWidgetContextMenuIndex = mModelTabWidget->tabBar()->tabAt(Point);
999 
1000 	if (mModelTabWidget->count() > 1)
1001 		Menu->addAction(tr("Close Other Tabs"), this, SLOT(ModelTabCloseOtherTabs()));
1002 	if (mModelTabWidgetContextMenuIndex == mModelTabWidget->currentIndex())
1003 		Menu->addAction(mActions[LC_VIEW_RESET_VIEWS]);
1004 
1005 	Menu->exec(QCursor::pos());
1006 	delete Menu;
1007 }
1008 
ModelTabCloseOtherTabs()1009 void lcMainWindow::ModelTabCloseOtherTabs()
1010 {
1011 	if (mModelTabWidgetContextMenuIndex == -1)
1012 		return;
1013 
1014 	while (mModelTabWidget->count() - 1 > mModelTabWidgetContextMenuIndex)
1015 		delete mModelTabWidget->widget(mModelTabWidgetContextMenuIndex + 1);
1016 
1017 	while (mModelTabWidget->count() > 1)
1018 		delete mModelTabWidget->widget(0);
1019 }
1020 
ModelTabClosed(int Index)1021 void lcMainWindow::ModelTabClosed(int Index)
1022 {
1023 	if (mModelTabWidget->count() != 1)
1024 		delete mModelTabWidget->widget(Index);
1025 	else
1026 		NewProject();
1027 }
1028 
ModelTabChanged(int Index)1029 void lcMainWindow::ModelTabChanged(int Index)
1030 {
1031 	Project* Project = lcGetActiveProject();
1032 	lcModelTabWidget* CurrentTab = (lcModelTabWidget*)mModelTabWidget->widget(Index);
1033 
1034 	Project->SetActiveModel(Project->GetModels().FindIndex(CurrentTab ? CurrentTab->GetModel() : nullptr));
1035 }
1036 
ClipboardChanged()1037 void lcMainWindow::ClipboardChanged()
1038 {
1039 	const QString MimeType = QLatin1String("application/vnd.leocad-clipboard");
1040 	const QMimeData* MimeData = QApplication::clipboard()->mimeData();
1041 	QByteArray ClipboardData;
1042 
1043 	if (MimeData && MimeData->hasFormat(MimeType))
1044 		ClipboardData = MimeData->data(MimeType);
1045 
1046 	gApplication->SetClipboard(ClipboardData);
1047 }
1048 
ActionTriggered()1049 void lcMainWindow::ActionTriggered()
1050 {
1051 	QObject* Action = sender();
1052 
1053 	for (int CommandIdx = 0; CommandIdx < LC_NUM_COMMANDS; CommandIdx++)
1054 	{
1055 		if (Action == mActions[CommandIdx])
1056 		{
1057 			HandleCommand((lcCommandId)CommandIdx);
1058 			break;
1059 		}
1060 	}
1061 }
1062 
ColorChanged(int ColorIndex)1063 void lcMainWindow::ColorChanged(int ColorIndex)
1064 {
1065 	SetColorIndex(ColorIndex);
1066 }
1067 
ColorButtonClicked()1068 void lcMainWindow::ColorButtonClicked()
1069 {
1070 	lcModel* ActiveModel = GetActiveModel();
1071 
1072 	if (ActiveModel)
1073 		ActiveModel->PaintSelectedPieces();
1074 }
1075 
ProjectFileChanged(const QString & Path)1076 void lcMainWindow::ProjectFileChanged(const QString& Path)
1077 {
1078 	static bool Ignore;
1079 
1080 	if (Ignore)
1081 		return;
1082 
1083 	QString Text = tr("The file '%1' has been modified by another application, do you want to reload it?").arg(QDir::toNativeSeparators(Path));
1084 
1085 	Project* CurrentProject = lcGetActiveProject();
1086 
1087 	Ignore = true;
1088 
1089 	if (QMessageBox::question(this, tr("File Changed"), Text, QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes)
1090 	{
1091 		Ignore = false;
1092 		CurrentProject->MarkAsModified();
1093 		UpdateTitle();
1094 		return;
1095 	}
1096 
1097 	Ignore = false;
1098 
1099 	QFileInfo FileInfo(Path);
1100 
1101 	if (FileInfo == QFileInfo(CurrentProject->GetFileName()))
1102 	{
1103 		Project* NewProject = new Project;
1104 
1105 		if (NewProject->Load(Path, true))
1106 		{
1107 			QByteArray TabLayout = GetTabLayout();
1108 			gApplication->SetProject(NewProject);
1109 			RestoreTabLayout(TabLayout);
1110 			lcView::UpdateAllViews();
1111 		}
1112 	}
1113 	else
1114 	{
1115 		PieceInfo* Info = lcGetPiecesLibrary()->FindPiece(FileInfo.fileName().toLatin1(), CurrentProject, false, true);
1116 
1117 		if (Info && Info->IsProject())
1118 			Info->GetProject()->Load(Path, true);
1119 	}
1120 }
1121 
Print(QPrinter * Printer)1122 void lcMainWindow::Print(QPrinter* Printer)
1123 {
1124 #ifndef QT_NO_PRINTER
1125 	int DocCopies;
1126 	int PageCopies;
1127 
1128 	lcInstructions* Instructions = lcGetActiveProject()->GetInstructions();
1129 	const int PageCount = static_cast<int>(Instructions->mPages.size());
1130 
1131 	if (Printer->collateCopies())
1132 	{
1133 		DocCopies = 1;
1134 		PageCopies = Printer->supportsMultipleCopies() ? 1 : Printer->copyCount();
1135 	}
1136 	else
1137 	{
1138 		DocCopies = Printer->supportsMultipleCopies() ? 1 : Printer->copyCount();
1139 		PageCopies = 1;
1140 	}
1141 
1142 	int FromPage = Printer->fromPage();
1143 	int ToPage = Printer->toPage();
1144 	bool Ascending = true;
1145 
1146 	if (FromPage == 0 && ToPage == 0)
1147 	{
1148 		FromPage = 1;
1149 		ToPage = PageCount;
1150 	}
1151 
1152 	FromPage = qMax(1, FromPage);
1153 	ToPage = qMin(PageCount, ToPage);
1154 
1155 	if (ToPage < FromPage)
1156 		return;
1157 
1158 	if (Printer->pageOrder() == QPrinter::LastPageFirst)
1159 	{
1160 		int Tmp = FromPage;
1161 		FromPage = ToPage;
1162 		ToPage = Tmp;
1163 		Ascending = false;
1164 	}
1165 
1166 	QRect PageRect = Printer->pageLayout().paintRectPixels(Printer->resolution());
1167 	const int Resolution = Printer->resolution();
1168 	const int Margin = Resolution / 2; // todo: user setting
1169 	QRect MarginRect = QRect(PageRect.left() + Margin, PageRect.top() + Margin, PageRect.width() - Margin * 2, PageRect.height() - Margin * 2);
1170 
1171 	QPainter Painter(Printer);
1172 	bool FirstPage = true;
1173 	// TODO: option to print background
1174 
1175 	for (int DocCopy = 0; DocCopy < DocCopies; DocCopy++)
1176 	{
1177 		int Page = FromPage;
1178 
1179 		for (;;)
1180 		{
1181 			for (int PageCopy = 0; PageCopy < PageCopies; PageCopy++)
1182 			{
1183 				if (Printer->printerState() == QPrinter::Aborted || Printer->printerState() == QPrinter::Error)
1184 					return;
1185 
1186 				if (!FirstPage)
1187 					Printer->newPage();
1188 				else
1189 					FirstPage = false;
1190 
1191 				int StepWidth = MarginRect.width();
1192 				int StepHeight = MarginRect.height();
1193 
1194 				const lcInstructionsPage& PageLayout = Instructions->mPages[Page - 1];
1195 				lcModel* Model = PageLayout.Steps[0].Model;
1196 				lcStep Step = PageLayout.Steps[0].Step;
1197 				QImage Image = Model->GetStepImage(false, StepWidth, StepHeight, Step);
1198 
1199 				Painter.drawImage(MarginRect.left(), MarginRect.top(), Image);
1200 
1201 				// TODO: add print options somewhere but Qt doesn't allow changes to the page setup dialog
1202 //				DWORD dwPrint = theApp.GetProfileInt("Settings","Print", PRINT_NUMBERS|PRINT_BORDER);
1203 
1204 //				if (print text)
1205 				{
1206 					QFont Font("Helvetica", 96);
1207 					Painter.setFont(Font);
1208 
1209 					QFontMetrics FontMetrics(Font);
1210 
1211 					int TextMargin = Resolution / 2;
1212 					QRect TextRect = QRect(MarginRect.left() + TextMargin, MarginRect.top() + TextMargin, MarginRect.width() - TextMargin * 2, MarginRect.height() - TextMargin * 2);
1213 
1214 					Painter.drawText(TextRect, Qt::AlignTop | Qt::AlignLeft, QString::number(Step));
1215 				}
1216 /*
1217 //				if (print border)
1218 				{
1219 					QPen BlackPen(Qt::black, 2);
1220 					Painter.setPen(BlackPen);
1221 
1222 					Painter.drawLine(MarginRect.left(), MarginRect.top(), MarginRect.right(), MarginRect.top());
1223 					Painter.drawLine(MarginRect.left(), MarginRect.bottom(), MarginRect.right(), MarginRect.bottom());
1224 					Painter.drawLine(MarginRect.left(), MarginRect.top(), MarginRect.left(), MarginRect.bottom());
1225 					Painter.drawLine(MarginRect.right(), MarginRect.top(), MarginRect.right(), MarginRect.bottom());
1226 				}
1227 */
1228 				// TODO: print header and footer
1229 			}
1230 
1231 			if (Page == ToPage)
1232 				break;
1233 
1234 			if (Ascending)
1235 				Page++;
1236 			else
1237 				Page--;
1238 		}
1239 	}
1240 #endif
1241 }
1242 
ShowUpdatesDialog()1243 void lcMainWindow::ShowUpdatesDialog()
1244 {
1245 	lcQUpdateDialog Dialog(this, false);
1246 	Dialog.exec();
1247 }
1248 
ShowAboutDialog()1249 void lcMainWindow::ShowAboutDialog()
1250 {
1251 	lcQAboutDialog Dialog(this);
1252 	Dialog.exec();
1253 }
1254 
ShowHTMLDialog()1255 void lcMainWindow::ShowHTMLDialog()
1256 {
1257 	lcHTMLExportOptions Options(lcGetActiveProject());
1258 
1259 	lcQHTMLDialog Dialog(this, &Options);
1260 	if (Dialog.exec() != QDialog::Accepted)
1261 		return;
1262 
1263 	Options.SaveDefaults();
1264 	lcGetActiveProject()->ExportHTML(Options);
1265 }
1266 
ShowRenderDialog()1267 void lcMainWindow::ShowRenderDialog()
1268 {
1269 	lcRenderDialog Dialog(this);
1270 	Dialog.exec();
1271 }
1272 
ShowInstructionsDialog()1273 void lcMainWindow::ShowInstructionsDialog()
1274 {
1275 	lcInstructionsDialog* Dialog = new lcInstructionsDialog(this, lcGetActiveProject());
1276 	Dialog->setWindowModality(Qt::ApplicationModal);
1277 	Dialog->setAttribute(Qt::WA_DeleteOnClose);
1278 	Dialog->show();
1279 }
1280 
ShowPrintDialog()1281 void lcMainWindow::ShowPrintDialog()
1282 {
1283 #ifndef QT_NO_PRINTER
1284 	int PageCount = static_cast<int>(lcGetActiveProject()->GetInstructions()->mPages.size());
1285 
1286 	QPrinter Printer(QPrinter::HighResolution);
1287 	Printer.setFromTo(1, PageCount + 1);
1288 
1289 	QPrintDialog PrintDialog(&Printer, this);
1290 
1291 	if (PrintDialog.exec() == QDialog::Accepted)
1292 		Print(&Printer);
1293 #endif
1294 }
1295 
SetShadingMode(lcShadingMode ShadingMode)1296 void lcMainWindow::SetShadingMode(lcShadingMode ShadingMode)
1297 {
1298 	lcGetPreferences().mShadingMode = ShadingMode;
1299 
1300 	UpdateShadingMode();
1301 
1302 	lcView::UpdateAllViews();
1303 
1304 	if (mPartSelectionWidget)
1305 		mPartSelectionWidget->Redraw();
1306 }
1307 
SetSelectionMode(lcSelectionMode SelectionMode)1308 void lcMainWindow::SetSelectionMode(lcSelectionMode SelectionMode)
1309 {
1310 	mSelectionMode = SelectionMode;
1311 
1312 	UpdateSelectionMode();
1313 }
1314 
ToggleViewSphere()1315 void lcMainWindow::ToggleViewSphere()
1316 {
1317 	lcGetPreferences().mViewSphereEnabled = !lcGetPreferences().mViewSphereEnabled;
1318 
1319 	lcView::UpdateAllViews();
1320 }
1321 
ToggleAxisIcon()1322 void lcMainWindow::ToggleAxisIcon()
1323 {
1324 	lcGetPreferences().mDrawAxes = !lcGetPreferences().mDrawAxes;
1325 
1326 	lcView::UpdateAllViews();
1327 }
1328 
ToggleGrid()1329 void lcMainWindow::ToggleGrid()
1330 {
1331 	lcGetPreferences().mGridEnabled = !lcGetPreferences().mGridEnabled;
1332 
1333 	lcView::UpdateAllViews();
1334 }
1335 
ToggleFadePreviousSteps()1336 void lcMainWindow::ToggleFadePreviousSteps()
1337 {
1338 	lcGetPreferences().mFadeSteps = !lcGetPreferences().mFadeSteps;
1339 
1340 	lcView::UpdateAllViews();
1341 }
1342 
GetTabLayout()1343 QByteArray lcMainWindow::GetTabLayout()
1344 {
1345 	QByteArray TabLayoutData;
1346 	QDataStream DataStream(&TabLayoutData, QIODevice::WriteOnly);
1347 
1348 	DataStream << (quint32)LC_TAB_LAYOUT_VERSION;
1349 	qint32 NumTabs = mModelTabWidget->count();
1350 	DataStream << NumTabs;
1351 	DataStream << ((lcModelTabWidget*)mModelTabWidget->currentWidget())->GetModel()->GetProperties().mFileName;
1352 
1353 	for (int TabIdx = 0; TabIdx < NumTabs; TabIdx++)
1354 	{
1355 		lcModelTabWidget* TabWidget = (lcModelTabWidget*)mModelTabWidget->widget(TabIdx);
1356 
1357 		DataStream << TabWidget->GetModel()->GetProperties().mFileName;
1358 
1359 		std::function<void (QWidget*)> SaveWidget = [&DataStream, &SaveWidget, &TabWidget](QWidget* Widget)
1360 		{
1361 			if (Widget->metaObject() == &lcViewWidget::staticMetaObject)
1362 			{
1363 				lcView* CurrentView = ((lcViewWidget*)Widget)->GetView();
1364 
1365 				DataStream << (qint32)0;
1366 				DataStream << (qint32)(TabWidget->GetActiveView() == CurrentView ? 1 : 0);
1367 
1368 				const lcCamera* Camera = CurrentView->GetCamera();
1369 
1370 				if (Camera->IsSimple())
1371 				{
1372 					DataStream << (qint32)0;
1373 					DataStream << Camera->m_fovy;
1374 					DataStream << Camera->m_zNear;
1375 					DataStream << Camera->m_zFar;
1376 					DataStream << Camera->mPosition;
1377 					DataStream << Camera->mTargetPosition;
1378 					DataStream << Camera->mUpVector;
1379 				}
1380 				else
1381 				{
1382 					DataStream << (qint32)1;
1383 					DataStream << Camera->GetName();
1384 				}
1385 			}
1386 			else
1387 			{
1388 				QSplitter* Splitter = (QSplitter*)Widget;
1389 
1390 				DataStream << (qint32)(Splitter->orientation() == Qt::Horizontal ? 1 : 2);
1391 				DataStream << Splitter->sizes();
1392 
1393 				SaveWidget(Splitter->widget(0));
1394 				SaveWidget(Splitter->widget(1));
1395 			}
1396 		};
1397 
1398 		QLayout* TabLayout = TabWidget->layout();
1399 		SaveWidget(TabLayout->itemAt(0)->widget());
1400 	}
1401 
1402 	return TabLayoutData;
1403 }
1404 
RestoreTabLayout(const QByteArray & TabLayout)1405 void lcMainWindow::RestoreTabLayout(const QByteArray& TabLayout)
1406 {
1407 	if (TabLayout.isEmpty())
1408 		return;
1409 
1410 	QDataStream DataStream(TabLayout);
1411 
1412 	quint32 Version;
1413 	DataStream >> Version;
1414 
1415 	if (Version != LC_TAB_LAYOUT_VERSION)
1416 		return;
1417 
1418 	qint32 NumTabs;
1419 	DataStream >> NumTabs;
1420 	QString CurrentTabName;
1421 	DataStream >> CurrentTabName;
1422 
1423 	RemoveAllModelTabs();
1424 
1425 	for (int TabIdx = 0; TabIdx < NumTabs; TabIdx++)
1426 	{
1427 		QString ModelName;
1428 		DataStream >> ModelName;
1429 
1430 		lcModel* Model = lcGetActiveProject()->GetModel(ModelName);
1431 		lcModelTabWidget* TabWidget = nullptr;
1432 
1433 		if (Model)
1434 		{
1435 			SetCurrentModelTab(Model);
1436 			TabWidget = (lcModelTabWidget*)mModelTabWidget->widget(mModelTabWidget->count() - 1);
1437 		}
1438 
1439 		QWidget* ActiveWidget = nullptr;
1440 
1441 		std::function<void(QWidget*)> LoadWidget = [&DataStream, &LoadWidget, &ActiveWidget, this](QWidget* ParentWidget)
1442 		{
1443 			qint32 WidgetType;
1444 			DataStream >> WidgetType;
1445 
1446 			if (WidgetType == 0)
1447 			{
1448 				qint32 IsActive;
1449 				DataStream >> IsActive;
1450 
1451 				if (IsActive)
1452 					ActiveWidget = ParentWidget;
1453 
1454 				qint32 CameraType;
1455 				DataStream >> CameraType;
1456 
1457 				lcView* CurrentView = nullptr;
1458 
1459 				if (ParentWidget)
1460 					CurrentView = ((lcViewWidget*)ParentWidget)->GetView();
1461 
1462 				if (CameraType == 0)
1463 				{
1464 					float FoV, ZNear, ZFar;
1465 					lcVector3 Position, TargetPosition, UpVector;
1466 
1467 					DataStream >> FoV;
1468 					DataStream >> ZNear;
1469 					DataStream >> ZFar;
1470 					DataStream >> Position;
1471 					DataStream >> TargetPosition;
1472 					DataStream >> UpVector;
1473 
1474 					if (CurrentView)
1475 					{
1476 						lcCamera* Camera = CurrentView->GetCamera();
1477 						if (!std::isnan(FoV))
1478 							Camera->m_fovy = FoV;
1479 						if (!std::isnan(ZNear))
1480 							Camera->m_zNear = ZNear;
1481 						if (!std::isnan(ZFar))
1482 							Camera->m_zFar = ZFar;
1483 						if (!Position.IsNan() && !TargetPosition.IsNan() && !UpVector.IsNan())
1484 						{
1485 							Camera->mPosition = Position;
1486 							Camera->mTargetPosition = TargetPosition;
1487 							Camera->mUpVector = UpVector;
1488 						}
1489 						Camera->UpdatePosition(1);
1490 					}
1491 				}
1492 				else
1493 				{
1494 					QByteArray CameraName;
1495 					DataStream >> CameraName;
1496 
1497 					if (CurrentView)
1498 						CurrentView->SetCamera(CameraName);
1499 				}
1500 			}
1501 			else
1502 			{
1503 				QList<int> Sizes;
1504 				DataStream >> Sizes;
1505 
1506 				if (ParentWidget)
1507 				{
1508 					ParentWidget->setFocus();
1509 
1510 					if (WidgetType == 1)
1511 						SplitVertical();
1512 					else
1513 						SplitHorizontal();
1514 
1515 					QSplitter* Splitter = (QSplitter*)ParentWidget->parentWidget();
1516 					Splitter->setSizes(Sizes);
1517 
1518 					LoadWidget(Splitter->widget(0));
1519 					LoadWidget(Splitter->widget(1));
1520 				}
1521 				else
1522 				{
1523 					LoadWidget(nullptr);
1524 					LoadWidget(nullptr);
1525 				}
1526 			}
1527 		};
1528 
1529 		LoadWidget(TabWidget ? TabWidget->layout()->itemAt(0)->widget() : nullptr);
1530 
1531 		if (ActiveWidget && TabWidget)
1532 			ActiveWidget->setFocus();
1533 	}
1534 
1535 	if (!mModelTabWidget->count())
1536 		lcGetActiveProject()->SetActiveModel(0);
1537 	else
1538 		lcGetActiveProject()->SetActiveModel(CurrentTabName);
1539 }
1540 
RemoveAllModelTabs()1541 void lcMainWindow::RemoveAllModelTabs()
1542 {
1543 	while (mModelTabWidget->count())
1544 		delete mModelTabWidget->widget(0);
1545 }
1546 
CloseCurrentModelTab()1547 void lcMainWindow::CloseCurrentModelTab()
1548 {
1549 	if (mModelTabWidget->count() > 1)
1550 		delete mModelTabWidget->currentWidget();
1551 	else
1552 		NewProject();
1553 }
1554 
SetCurrentModelTab(lcModel * Model)1555 void lcMainWindow::SetCurrentModelTab(lcModel* Model)
1556 {
1557 	for (int TabIdx = 0; TabIdx < mModelTabWidget->count(); TabIdx++)
1558 	{
1559 		lcModelTabWidget* TabWidget = (lcModelTabWidget*)mModelTabWidget->widget(TabIdx);
1560 
1561 		if (TabWidget->GetModel() == Model)
1562 		{
1563 			mModelTabWidget->setCurrentIndex(TabIdx);
1564 			return;
1565 		}
1566 	}
1567 
1568 	lcModelTabWidget* TabWidget = new lcModelTabWidget(Model);
1569 	mModelTabWidget->addTab(TabWidget, Model->GetProperties().mFileName);
1570 
1571 	QVBoxLayout* CentralLayout = new QVBoxLayout(TabWidget);
1572 	CentralLayout->setContentsMargins(0, 0, 0, 0);
1573 
1574 	lcView* NewView = CreateView(Model);
1575 	lcViewWidget* ViewWidget = new lcViewWidget(TabWidget, NewView);
1576 	CentralLayout->addWidget(ViewWidget);
1577 
1578 	mModelTabWidget->setCurrentWidget(TabWidget);
1579 
1580 	ViewWidget->show();
1581 	ViewWidget->setFocus();
1582 	NewView->ZoomExtents();
1583 }
1584 
AddView(lcView * View)1585 void lcMainWindow::AddView(lcView* View)
1586 {
1587 	lcModelTabWidget* TabWidget = GetTabWidgetForModel(View->GetModel());
1588 
1589 	if (!TabWidget)
1590 		return;
1591 
1592 	if (!TabWidget->GetActiveView())
1593 	{
1594 		TabWidget->SetActiveView(View);
1595 		UpdatePerspective();
1596 	}
1597 }
1598 
RemoveView(lcView * View)1599 void lcMainWindow::RemoveView(lcView* View)
1600 {
1601 	lcModelTabWidget* TabWidget = GetTabForView(View);
1602 
1603 	if (TabWidget)
1604 		TabWidget->RemoveView(View);
1605 }
1606 
SetActiveView(lcView * ActiveView)1607 void lcMainWindow::SetActiveView(lcView* ActiveView)
1608 {
1609 	lcModelTabWidget* TabWidget = GetTabForView(ActiveView);
1610 
1611 	if (!TabWidget)
1612 		return;
1613 
1614 	lcView* CurrentActiveView = TabWidget->GetActiveView();
1615 
1616 	if (CurrentActiveView == ActiveView)
1617 		return;
1618 
1619 	if (CurrentActiveView)
1620 		CurrentActiveView->SetTopSubmodelActive();
1621 
1622 	TabWidget->SetActiveView(ActiveView);
1623 
1624 	UpdateCameraMenu();
1625 	UpdatePerspective();
1626 }
1627 
SetTool(lcTool Tool)1628 void lcMainWindow::SetTool(lcTool Tool)
1629 {
1630 	mTool = Tool;
1631 
1632 	QAction* Action = mActions[LC_EDIT_ACTION_FIRST + static_cast<int>(mTool)];
1633 
1634 	if (Action)
1635 		Action->setChecked(true);
1636 
1637 	lcView::UpdateAllViews();
1638 }
1639 
SetColorIndex(int ColorIndex)1640 void lcMainWindow::SetColorIndex(int ColorIndex)
1641 {
1642 	mColorIndex = ColorIndex;
1643 
1644 	if (mPartSelectionWidget)
1645 		mPartSelectionWidget->SetColorIndex(ColorIndex);
1646 
1647 	UpdateColor();
1648 }
1649 
SetMoveSnapEnabled(bool Enabled)1650 void lcMainWindow::SetMoveSnapEnabled(bool Enabled)
1651 {
1652 	mMoveSnapEnabled = Enabled;
1653 	UpdateSnap();
1654 }
1655 
SetAngleSnapEnabled(bool Enabled)1656 void lcMainWindow::SetAngleSnapEnabled(bool Enabled)
1657 {
1658 	mAngleSnapEnabled = Enabled;
1659 	UpdateSnap();
1660 }
1661 
SetMoveXYSnapIndex(int Index)1662 void lcMainWindow::SetMoveXYSnapIndex(int Index)
1663 {
1664 	mMoveXYSnapIndex = Index;
1665 	UpdateSnap();
1666 }
1667 
SetMoveZSnapIndex(int Index)1668 void lcMainWindow::SetMoveZSnapIndex(int Index)
1669 {
1670 	mMoveZSnapIndex = Index;
1671 	UpdateSnap();
1672 }
1673 
SetAngleSnapIndex(int Index)1674 void lcMainWindow::SetAngleSnapIndex(int Index)
1675 {
1676 	mAngleSnapIndex = Index;
1677 	UpdateSnap();
1678 }
1679 
SetRelativeTransform(bool RelativeTransform)1680 void lcMainWindow::SetRelativeTransform(bool RelativeTransform)
1681 {
1682 	mRelativeTransform = RelativeTransform;
1683 
1684 	UpdateLockSnap();
1685 	lcView::UpdateAllViews();
1686 }
1687 
SetSeparateTransform(bool SelectionTransform)1688 void lcMainWindow::SetSeparateTransform(bool SelectionTransform)
1689 {
1690 	mLocalTransform = SelectionTransform;
1691 
1692 	UpdateLockSnap();
1693 }
1694 
SetTransformType(lcTransformType TransformType)1695 void lcMainWindow::SetTransformType(lcTransformType TransformType)
1696 {
1697 	if (TransformType < lcTransformType::First || TransformType >= lcTransformType::Count)
1698 		return;
1699 
1700 	mTransformType = TransformType;
1701 
1702 	constexpr const char* IconNames[] =
1703 	{
1704 		":/resources/edit_transform_absolute_translation.png",
1705 		":/resources/edit_transform_relative_translation.png",
1706 		":/resources/edit_transform_absolute_rotation.png",
1707 		":/resources/edit_transform_relative_rotation.png"
1708 	};
1709 
1710 	LC_ARRAY_SIZE_CHECK(IconNames, lcTransformType::Count);
1711 
1712 	int TransformIndex = static_cast<int>(TransformType);
1713 	mActions[LC_EDIT_TRANSFORM_ABSOLUTE_TRANSLATION + TransformIndex]->setChecked(true);
1714 	mActions[LC_EDIT_TRANSFORM]->setIcon(QIcon(IconNames[TransformIndex]));
1715 }
1716 
SetCurrentPieceInfo(PieceInfo * Info)1717 void lcMainWindow::SetCurrentPieceInfo(PieceInfo* Info)
1718 {
1719 	lcPiecesLibrary* Library = lcGetPiecesLibrary();
1720 
1721 	if (mCurrentPieceInfo)
1722 		Library->ReleasePieceInfo(mCurrentPieceInfo);
1723 
1724 	mCurrentPieceInfo = Info;
1725 
1726 	if (mCurrentPieceInfo)
1727 		Library->LoadPieceInfo(mCurrentPieceInfo, true, true);
1728 }
1729 
GetTransformAmount()1730 lcVector3 lcMainWindow::GetTransformAmount()
1731 {
1732 	lcVector3 Transform;
1733 
1734 	Transform.x = lcParseValueLocalized(mTransformXEdit->text());
1735 	Transform.y = lcParseValueLocalized(mTransformYEdit->text());
1736 	Transform.z = lcParseValueLocalized(mTransformZEdit->text());
1737 
1738 	return Transform;
1739 }
1740 
SplitView(Qt::Orientation Orientation)1741 void lcMainWindow::SplitView(Qt::Orientation Orientation)
1742 {
1743 	QWidget* Focus = focusWidget();
1744 
1745 	if (Focus->metaObject() != &lcViewWidget::staticMetaObject)
1746 		return;
1747 
1748 	QWidget* Parent = Focus->parentWidget();
1749 	QSplitter* Splitter;
1750 	QList<int> Sizes;
1751 
1752 	if (Parent->metaObject() == &lcModelTabWidget::staticMetaObject)
1753 	{
1754 		Splitter = new QSplitter(Orientation, Parent);
1755 		Parent->layout()->addWidget(Splitter);
1756 		Splitter->addWidget(Focus);
1757 		Splitter->addWidget(new lcViewWidget(mModelTabWidget->currentWidget(), CreateView(GetCurrentTabModel())));
1758 	}
1759 	else
1760 	{
1761 		QSplitter* ParentSplitter = (QSplitter*)Parent;
1762 		Sizes = ParentSplitter->sizes();
1763 		int FocusIndex = ParentSplitter->indexOf(Focus);
1764 
1765 		Splitter = new QSplitter(Orientation, Parent);
1766 		ParentSplitter->insertWidget(FocusIndex, Splitter);
1767 		Splitter->addWidget(Focus);
1768 		Splitter->addWidget(new lcViewWidget(mModelTabWidget->currentWidget(), CreateView(GetCurrentTabModel())));
1769 
1770 		ParentSplitter->setSizes(Sizes);
1771 	}
1772 
1773 	Sizes.clear();
1774 	Sizes.append(10);
1775 	Sizes.append(10);
1776 	Splitter->setSizes(Sizes);
1777 	Focus->setFocus();
1778 }
1779 
SplitHorizontal()1780 void lcMainWindow::SplitHorizontal()
1781 {
1782 	SplitView(Qt::Vertical);
1783 }
1784 
SplitVertical()1785 void lcMainWindow::SplitVertical()
1786 {
1787 	SplitView(Qt::Horizontal);
1788 }
1789 
RemoveActiveView()1790 void lcMainWindow::RemoveActiveView()
1791 {
1792 	QWidget* Focus = focusWidget();
1793 
1794 	if (Focus->metaObject() != &lcViewWidget::staticMetaObject)
1795 		return;
1796 
1797 	QWidget* Parent = Focus->parentWidget();
1798 
1799 	if (Parent->metaObject() == &lcModelTabWidget::staticMetaObject)
1800 		return;
1801 
1802 	QWidget* ParentParentWidget = Parent->parentWidget();
1803 	QSplitter* ParentSplitter = (QSplitter*)Parent;
1804 	int FocusIndex = ParentSplitter->indexOf(Focus);
1805 	QWidget* OtherWidget = ParentSplitter->widget(!FocusIndex);
1806 
1807 	if (ParentParentWidget->metaObject() == &lcModelTabWidget::staticMetaObject)
1808 	{
1809 		QLayout* CentralLayout = ParentParentWidget->layout();
1810 
1811 		CentralLayout->addWidget(OtherWidget);
1812 		CentralLayout->removeWidget(Parent);
1813 	}
1814 	else
1815 	{
1816 		QSplitter* ParentParentSplitter = (QSplitter*)ParentParentWidget;
1817 		QList<int> Sizes = ParentParentSplitter->sizes();
1818 
1819 		int ParentIndex = ParentParentSplitter->indexOf(Parent);
1820 		Parent->setParent(nullptr);
1821 		ParentParentSplitter->insertWidget(ParentIndex, OtherWidget);
1822 
1823 		ParentParentSplitter->setSizes(Sizes);
1824 	}
1825 
1826 	Parent->deleteLater();
1827 
1828 	if (OtherWidget->metaObject() != &lcViewWidget::staticMetaObject)
1829 	{
1830 		lcModelTabWidget* TabWidget = (lcModelTabWidget*)mModelTabWidget->currentWidget();
1831 
1832 		if (TabWidget)
1833 			OtherWidget = TabWidget->GetAnyViewWidget();
1834 	}
1835 
1836 	OtherWidget->setFocus();
1837 }
1838 
ResetViews()1839 void lcMainWindow::ResetViews()
1840 {
1841 	lcModelTabWidget* TabWidget = (lcModelTabWidget*)mModelTabWidget->currentWidget();
1842 
1843 	if (!TabWidget)
1844 		return;
1845 
1846 	QLayout* TabLayout = TabWidget->layout();
1847 	QWidget* TopWidget = TabLayout->itemAt(0)->widget();
1848 	TopWidget->deleteLater();
1849 
1850 	lcView* NewView = CreateView(TabWidget->GetModel());
1851 	lcViewWidget* ViewWidget = new lcViewWidget(TabWidget, NewView);
1852 	TabLayout->addWidget(ViewWidget);
1853 
1854 	ViewWidget->show();
1855 	ViewWidget->setFocus();
1856 	NewView->ZoomExtents();
1857 }
1858 
ToggleDockWidget(QWidget * DockWidget)1859 void lcMainWindow::ToggleDockWidget(QWidget* DockWidget)
1860 {
1861 	if (DockWidget->isHidden())
1862 		DockWidget->show();
1863 	else
1864 		DockWidget->hide();
1865 }
1866 
TogglePrintPreview()1867 void lcMainWindow::TogglePrintPreview()
1868 {
1869 #ifndef QT_NO_PRINTER
1870 	// todo: print preview inside main window
1871 
1872 	int PageCount = static_cast<int>(lcGetActiveProject()->GetInstructions()->mPages.size());
1873 
1874 	QPrinter Printer(QPrinter::ScreenResolution);
1875 	Printer.setFromTo(1, PageCount + 1);
1876 
1877 	QPrintPreviewDialog Preview(&Printer, this);
1878 	connect(&Preview, SIGNAL(paintRequested(QPrinter*)), SLOT(Print(QPrinter*)));
1879 	Preview.exec();
1880 #endif
1881 }
1882 
ToggleFullScreen()1883 void lcMainWindow::ToggleFullScreen()
1884 {
1885 	// todo: hide toolbars and menu
1886 	// todo: create fullscreen toolbar or support esc key to go back
1887 	if (isFullScreen())
1888 		showNormal();
1889 	else
1890 		showFullScreen();
1891 }
1892 
AddRecentFile(const QString & FileName)1893 void lcMainWindow::AddRecentFile(const QString& FileName)
1894 {
1895 	QString SavedName = FileName;
1896 	int FileIdx;
1897 
1898 	QFileInfo FileInfo(FileName);
1899 
1900 	for (FileIdx = 0; FileIdx < LC_MAX_RECENT_FILES; FileIdx++)
1901 		if (QFileInfo(mRecentFiles[FileIdx]) == FileInfo)
1902 			break;
1903 
1904 	for (FileIdx = lcMin(FileIdx, LC_MAX_RECENT_FILES - 1); FileIdx > 0; FileIdx--)
1905 		mRecentFiles[FileIdx] = mRecentFiles[FileIdx - 1];
1906 
1907 	mRecentFiles[0] = SavedName;
1908 
1909 	UpdateRecentFiles();
1910 }
1911 
RemoveRecentFile(int FileIndex)1912 void lcMainWindow::RemoveRecentFile(int FileIndex)
1913 {
1914 	for (int FileIdx = FileIndex; FileIdx < LC_MAX_RECENT_FILES - 1; FileIdx++)
1915 		mRecentFiles[FileIdx] = mRecentFiles[FileIdx + 1];
1916 
1917 	mRecentFiles[LC_MAX_RECENT_FILES - 1].clear();
1918 
1919 	UpdateRecentFiles();
1920 }
1921 
UpdateSelectedObjects(bool SelectionChanged)1922 void lcMainWindow::UpdateSelectedObjects(bool SelectionChanged)
1923 {
1924 	int Flags = 0;
1925 	lcArray<lcObject*> Selection;
1926 	lcObject* Focus = nullptr;
1927 
1928 	lcModel* ActiveModel = GetActiveModel();
1929 	if (ActiveModel)
1930 		ActiveModel->GetSelectionInformation(&Flags, Selection, &Focus);
1931 
1932 	if (SelectionChanged)
1933 	{
1934 		mTimelineWidget->UpdateSelection();
1935 
1936 		mActions[LC_EDIT_CUT]->setEnabled(Flags & LC_SEL_SELECTED);
1937 		mActions[LC_EDIT_COPY]->setEnabled(Flags & LC_SEL_SELECTED);
1938 		mActions[LC_EDIT_FIND]->setEnabled((Flags & LC_SEL_NO_PIECES) == 0);
1939 		mActions[LC_EDIT_FIND_NEXT]->setEnabled((Flags & LC_SEL_NO_PIECES) == 0);
1940 		mActions[LC_EDIT_FIND_PREVIOUS]->setEnabled((Flags & LC_SEL_NO_PIECES) == 0);
1941 		mActions[LC_EDIT_FIND_ALL]->setEnabled((Flags & LC_SEL_NO_PIECES) == 0);
1942 		mActions[LC_EDIT_REPLACE]->setEnabled((Flags & LC_SEL_NO_PIECES) == 0);
1943 		mActions[LC_EDIT_REPLACE_NEXT]->setEnabled((Flags & LC_SEL_NO_PIECES) == 0);
1944 		mActions[LC_EDIT_REPLACE_ALL]->setEnabled((Flags & LC_SEL_NO_PIECES) == 0);
1945 		mActions[LC_EDIT_SELECT_INVERT]->setEnabled((Flags & LC_SEL_NO_PIECES) == 0);
1946 		mActions[LC_EDIT_SELECT_BY_NAME]->setEnabled((Flags & LC_SEL_NO_PIECES) == 0);
1947 		mActions[LC_EDIT_SELECT_NONE]->setEnabled(Flags & LC_SEL_SELECTED);
1948 		mActions[LC_EDIT_SELECT_ALL]->setEnabled(Flags & LC_SEL_UNSELECTED);
1949 
1950 		mActions[LC_PIECE_DELETE]->setEnabled(Flags & LC_SEL_SELECTED);
1951 		mActions[LC_PIECE_DUPLICATE]->setEnabled(Flags & LC_SEL_SELECTED);
1952 		mActions[LC_PIECE_PAINT_SELECTED]->setEnabled(Flags & LC_SEL_PIECE);
1953 		mActions[LC_PIECE_RESET_PIVOT_POINT]->setEnabled(Flags & LC_SEL_SELECTED);
1954 		mActions[LC_PIECE_REMOVE_KEY_FRAMES]->setEnabled(Flags & LC_SEL_SELECTED);
1955 		mActions[LC_PIECE_ARRAY]->setEnabled(Flags & LC_SEL_PIECE);
1956 		mActions[LC_PIECE_CONTROL_POINT_INSERT]->setEnabled(Flags & LC_SEL_CAN_ADD_CONTROL_POINT);
1957 		mActions[LC_PIECE_CONTROL_POINT_REMOVE]->setEnabled(Flags & LC_SEL_CAN_REMOVE_CONTROL_POINT);
1958 		mActions[LC_PIECE_HIDE_SELECTED]->setEnabled(Flags & LC_SEL_VISIBLE_SELECTED);
1959 		mActions[LC_PIECE_HIDE_UNSELECTED]->setEnabled(Flags & LC_SEL_UNSELECTED);
1960 		mActions[LC_PIECE_UNHIDE_SELECTED]->setEnabled(Flags & LC_SEL_HIDDEN_SELECTED);
1961 		mActions[LC_PIECE_UNHIDE_ALL]->setEnabled(Flags & LC_SEL_HIDDEN);
1962 		mActions[LC_PIECE_VIEW_SELECTED_MODEL]->setEnabled(Flags & LC_SEL_MODEL_SELECTED);
1963 		mActions[LC_PIECE_MOVE_SELECTION_TO_MODEL]->setEnabled(Flags & LC_SEL_PIECE);
1964 		mActions[LC_PIECE_INLINE_SELECTED_MODELS]->setEnabled(Flags & LC_SEL_MODEL_SELECTED);
1965 		mActions[LC_PIECE_EDIT_SELECTED_SUBMODEL]->setEnabled(Flags & LC_SEL_MODEL_SELECTED);
1966 		mActions[LC_PIECE_GROUP]->setEnabled(Flags & LC_SEL_CAN_GROUP);
1967 		mActions[LC_PIECE_UNGROUP]->setEnabled(Flags & LC_SEL_GROUPED);
1968 		mActions[LC_PIECE_GROUP_ADD]->setEnabled((Flags & (LC_SEL_GROUPED | LC_SEL_FOCUS_GROUPED)) == LC_SEL_GROUPED);
1969 		mActions[LC_PIECE_GROUP_REMOVE]->setEnabled(Flags & LC_SEL_FOCUS_GROUPED);
1970 		mActions[LC_PIECE_GROUP_EDIT]->setEnabled((Flags & LC_SEL_NO_PIECES) == 0);
1971 		mActions[LC_PIECE_SHOW_EARLIER]->setEnabled(Flags & LC_SEL_PIECE); // FIXME: disable if current step is 1
1972 		mActions[LC_PIECE_SHOW_LATER]->setEnabled(Flags & LC_SEL_PIECE);
1973 		mActions[LC_TIMELINE_MOVE_SELECTION]->setEnabled(Flags & LC_SEL_PIECE);
1974 
1975 		mActions[LC_PIECE_EDIT_END_SUBMODEL]->setEnabled(GetCurrentTabModel() != ActiveModel);
1976 	}
1977 
1978 	mPropertiesWidget->Update(Selection, Focus);
1979 
1980 	QString Message;
1981 
1982 	if ((Selection.GetSize() == 1) && Focus)
1983 	{
1984 		if (Focus->IsPiece())
1985 			Message = tr("%1 (ID: %2)").arg(Focus->GetName(), ((lcPiece*)Focus)->GetID());
1986 		else
1987 			Message = Focus->GetName();
1988 	}
1989 	else if (Selection.GetSize() > 0)
1990 	{
1991 		Message = tr("%n Object(s) selected", "", Selection.GetSize());
1992 
1993 		if (Focus && Focus->IsPiece())
1994 		{
1995 			Message.append(tr(" - %1 (ID: %2)").arg(Focus->GetName(), ((lcPiece*)Focus)->GetID()));
1996 
1997 			const lcGroup* Group = ((lcPiece*)Focus)->GetGroup();
1998 			if (Group && !Group->mName.isEmpty())
1999 				Message.append(tr(" in group '%1'").arg(Group->mName));
2000 		}
2001 	}
2002 
2003 	mStatusBarLabel->setText(Message);
2004 	lcVector3 Position;
2005 	lcGetActiveModel()->GetFocusPosition(Position);
2006 
2007 	QString Label("X: %1 Y: %2 Z: %3");
2008 	Label = Label.arg(QLocale::system().toString(Position[0], 'f', 2), QLocale::system().toString(Position[1], 'f', 2), QLocale::system().toString(Position[2], 'f', 2));
2009 	mStatusPositionLabel->setText(Label);
2010 }
2011 
UpdateTimeline(bool Clear,bool UpdateItems)2012 void lcMainWindow::UpdateTimeline(bool Clear, bool UpdateItems)
2013 {
2014 	mTimelineWidget->Update(Clear, UpdateItems);
2015 }
2016 
UpdatePaste(bool Enabled)2017 void lcMainWindow::UpdatePaste(bool Enabled)
2018 {
2019 	if (mActions[LC_EDIT_PASTE])
2020 		mActions[LC_EDIT_PASTE]->setEnabled(Enabled);
2021 
2022 	if (mActions[LC_EDIT_PASTE_STEPS])
2023 		mActions[LC_EDIT_PASTE_STEPS]->setEnabled(Enabled);
2024 }
2025 
UpdateCurrentStep()2026 void lcMainWindow::UpdateCurrentStep()
2027 {
2028 	lcModel* Model = lcGetActiveModel();
2029 	lcStep CurrentStep = Model->GetCurrentStep();
2030 	lcStep LastStep = Model->GetLastStep();
2031 
2032 	mActions[LC_VIEW_TIME_FIRST]->setEnabled(CurrentStep != 1);
2033 	mActions[LC_VIEW_TIME_PREVIOUS]->setEnabled(CurrentStep > 1);
2034 	mActions[LC_VIEW_TIME_NEXT]->setEnabled(CurrentStep < LC_STEP_MAX);
2035 	mActions[LC_VIEW_TIME_LAST]->setEnabled(CurrentStep != LastStep);
2036 
2037 	mStatusTimeLabel->setText(QString(tr("Step %1")).arg(QString::number(CurrentStep)));
2038 }
2039 
SetAddKeys(bool AddKeys)2040 void lcMainWindow::SetAddKeys(bool AddKeys)
2041 {
2042 	QAction* Action = mActions[LC_VIEW_TIME_ADD_KEYS];
2043 
2044 	if (Action)
2045 		Action->setChecked(AddKeys);
2046 
2047 	mAddKeys = AddKeys;
2048 }
2049 
UpdateLockSnap()2050 void lcMainWindow::UpdateLockSnap()
2051 {
2052 	if (GetRelativeTransform())
2053 		mActions[LC_EDIT_TRANSFORM_RELATIVE]->setChecked(true);
2054 	else
2055 		mActions[LC_EDIT_TRANSFORM_ABSOLUTE]->setChecked(true);
2056 
2057 	if (GetSeparateTransform())
2058 		mActions[LC_EDIT_TRANSFORM_SEPARATELY]->setChecked(true);
2059 	else
2060 		mActions[LC_EDIT_TRANSFORM_TOGETHER]->setChecked(true);
2061 
2062 	UpdateSnap();
2063 }
2064 
UpdateSnap()2065 void lcMainWindow::UpdateSnap()
2066 {
2067 	mActions[LC_EDIT_SNAP_MOVE_TOGGLE]->setChecked(mMoveSnapEnabled);
2068 	mActions[LC_EDIT_SNAP_ANGLE_TOGGLE]->setChecked(mAngleSnapEnabled);
2069 	mActions[LC_EDIT_SNAP_MOVE_XY0 + mMoveXYSnapIndex]->setChecked(true);
2070 	mActions[LC_EDIT_SNAP_MOVE_Z0 + mMoveZSnapIndex]->setChecked(true);
2071 	mActions[LC_EDIT_SNAP_ANGLE0 + mAngleSnapIndex]->setChecked(true);
2072 
2073 	QString Relative = mRelativeTransform ? tr("Rel") : tr("Abs");
2074 	mStatusSnapLabel->setText(QString(tr(" M: %1 %2 R: %3 %4 ")).arg(GetMoveXYSnapText(), GetMoveZSnapText(), GetAngleSnapText(), Relative));
2075 }
2076 
UpdateColor()2077 void lcMainWindow::UpdateColor()
2078 {
2079 	QPixmap Pixmap(14, 14);
2080 	Pixmap.fill(QColor::fromRgbF(gColorList[mColorIndex].Value[0], gColorList[mColorIndex].Value[1], gColorList[mColorIndex].Value[2]));
2081 
2082 	mColorButton->setIcon(Pixmap);
2083 	mColorButton->setText(QString("  ") + gColorList[mColorIndex].Name);
2084 	mColorList->setCurrentColor(mColorIndex);
2085 }
2086 
UpdateUndoRedo(const QString & UndoText,const QString & RedoText)2087 void lcMainWindow::UpdateUndoRedo(const QString& UndoText, const QString& RedoText)
2088 {
2089 	QAction* UndoAction = mActions[LC_EDIT_UNDO];
2090 	QAction* RedoAction = mActions[LC_EDIT_REDO];
2091 
2092 	if (!UndoText.isEmpty())
2093 	{
2094 		UndoAction->setEnabled(true);
2095 		UndoAction->setText(QString(tr("&Undo %1")).arg(UndoText));
2096 	}
2097 	else
2098 	{
2099 		UndoAction->setEnabled(false);
2100 		UndoAction->setText(tr("&Undo"));
2101 	}
2102 
2103 	if (!RedoText.isEmpty())
2104 	{
2105 		RedoAction->setEnabled(true);
2106 		RedoAction->setText(QString(tr("&Redo %1")).arg(RedoText));
2107 	}
2108 	else
2109 	{
2110 		RedoAction->setEnabled(false);
2111 		RedoAction->setText(tr("&Redo"));
2112 	}
2113 }
2114 
ViewFocusReceived()2115 void lcMainWindow::ViewFocusReceived()
2116 {
2117 	SetActiveView(qobject_cast<lcView*>(sender()));
2118 }
2119 
ViewCameraChanged()2120 void lcMainWindow::ViewCameraChanged()
2121 {
2122 	lcView* View = qobject_cast<lcView*>(sender());
2123 
2124 	if (!View || !View->IsLastFocused())
2125 		return;
2126 
2127 	UpdateCameraMenu();
2128 }
2129 
UpdateCameraMenu()2130 void lcMainWindow::UpdateCameraMenu()
2131 {
2132 	const lcArray<lcCamera*>& Cameras = lcGetActiveModel()->GetCameras();
2133 	lcView* ActiveView = GetActiveView();
2134 	const lcCamera* CurrentCamera = ActiveView ? ActiveView->GetCamera() : nullptr;
2135 	bool CurrentSet = false;
2136 
2137 	for (int ActionIdx = LC_VIEW_CAMERA_FIRST; ActionIdx <= LC_VIEW_CAMERA_LAST; ActionIdx++)
2138 	{
2139 		QAction* Action = mActions[ActionIdx];
2140 		int CameraIdx = ActionIdx - LC_VIEW_CAMERA_FIRST;
2141 
2142 		if (CameraIdx < Cameras.GetSize())
2143 		{
2144 			if (CurrentCamera == Cameras[CameraIdx])
2145 			{
2146 				Action->setChecked(true);
2147 				CurrentSet = true;
2148 			}
2149 
2150 			Action->setText(Cameras[CameraIdx]->GetName());
2151 			Action->setVisible(true);
2152 		}
2153 		else
2154 			Action->setVisible(false);
2155 	}
2156 
2157 	if (!CurrentSet)
2158 		mActions[LC_VIEW_CAMERA_NONE]->setChecked(true);
2159 
2160 	UpdatePerspective();
2161 }
2162 
UpdatePerspective()2163 void lcMainWindow::UpdatePerspective()
2164 {
2165 	lcView* ActiveView = GetActiveView();
2166 
2167 	if (ActiveView)
2168 	{
2169 		if (ActiveView->GetCamera()->IsOrtho())
2170 			mActions[LC_VIEW_PROJECTION_ORTHO]->setChecked(true);
2171 		else
2172 			mActions[LC_VIEW_PROJECTION_PERSPECTIVE]->setChecked(true);
2173 	}
2174 }
2175 
UpdateShadingMode()2176 void lcMainWindow::UpdateShadingMode()
2177 {
2178 	mActions[LC_VIEW_SHADING_FIRST + static_cast<int>(lcGetPreferences().mShadingMode)]->setChecked(true);
2179 }
2180 
UpdateSelectionMode()2181 void lcMainWindow::UpdateSelectionMode()
2182 {
2183 	switch (mSelectionMode)
2184 	{
2185 	case lcSelectionMode::Single:
2186 		mActions[LC_EDIT_SELECTION_SINGLE]->setChecked(true);
2187 		break;
2188 
2189 	case lcSelectionMode::Piece:
2190 		mActions[LC_EDIT_SELECTION_PIECE]->setChecked(true);
2191 		break;
2192 
2193 	case lcSelectionMode::Color:
2194 		mActions[LC_EDIT_SELECTION_COLOR]->setChecked(true);
2195 		break;
2196 
2197 	case lcSelectionMode::PieceColor:
2198 		mActions[LC_EDIT_SELECTION_PIECE_COLOR]->setChecked(true);
2199 		break;
2200 	}
2201 }
2202 
UpdateModels()2203 void lcMainWindow::UpdateModels()
2204 {
2205 	const lcArray<lcModel*>& Models = lcGetActiveProject()->GetModels();
2206 	lcModel* CurrentModel = lcGetActiveModel();
2207 
2208 	for (int ActionIdx = LC_MODEL_FIRST; ActionIdx <= LC_MODEL_LAST; ActionIdx++)
2209 	{
2210 		QAction* Action = mActions[ActionIdx];
2211 		int ModelIdx = ActionIdx - LC_MODEL_FIRST;
2212 
2213 		if (ModelIdx < Models.GetSize())
2214 		{
2215 			Action->setChecked(CurrentModel == Models[ModelIdx]);
2216 			Action->setText(QString::fromLatin1("%1%2 %3").arg(ModelIdx < 9 ? QString("&") : QString(), QString::number(ModelIdx + 1), Models[ModelIdx]->GetProperties().mFileName));
2217 			Action->setVisible(true);
2218 		}
2219 		else
2220 			Action->setVisible(false);
2221 	}
2222 
2223 	for (int TabIdx = 0; TabIdx < mModelTabWidget->count(); )
2224 	{
2225 		lcModelTabWidget* TabWidget = (lcModelTabWidget*)mModelTabWidget->widget(TabIdx);
2226 		lcModel* Model = TabWidget->GetModel();
2227 
2228 		if (!Model)
2229 			TabIdx++;
2230 		else if (Models.FindIndex(Model) != -1)
2231 		{
2232 			mModelTabWidget->setTabText(TabIdx, Model->GetProperties().mFileName);
2233 			TabIdx++;
2234 		}
2235 		else
2236 			delete TabWidget;
2237 	}
2238 
2239 	mPartSelectionWidget->UpdateModels();
2240 
2241 	if (mCurrentPieceInfo && mCurrentPieceInfo->IsModel())
2242 		if (Models.FindIndex(mCurrentPieceInfo->GetModel()) == -1)
2243 			SetCurrentPieceInfo(nullptr);
2244 }
2245 
UpdateCategories()2246 void lcMainWindow::UpdateCategories()
2247 {
2248 	mPartSelectionWidget->UpdateCategories();
2249 }
2250 
UpdateTitle()2251 void lcMainWindow::UpdateTitle()
2252 {
2253 	setWindowModified(lcGetActiveProject()->IsModified());
2254 	setWindowFilePath(lcGetActiveProject()->GetTitle());
2255 }
2256 
UpdateModified(bool Modified)2257 void lcMainWindow::UpdateModified(bool Modified)
2258 {
2259 	setWindowModified(Modified);
2260 }
2261 
UpdateRecentFiles()2262 void lcMainWindow::UpdateRecentFiles()
2263 {
2264 	for (int ActionIdx = LC_FILE_RECENT_FIRST; ActionIdx <= LC_FILE_RECENT_LAST; ActionIdx++)
2265 	{
2266 		int FileIdx = ActionIdx - LC_FILE_RECENT_FIRST;
2267 		QAction* Action = mActions[ActionIdx];
2268 
2269 		if (!mRecentFiles[FileIdx].isEmpty())
2270 		{
2271 			Action->setText(QString("&%1 %2").arg(QString::number(FileIdx + 1), QDir::toNativeSeparators(mRecentFiles[FileIdx])));
2272 			Action->setVisible(true);
2273 		}
2274 		else
2275 			Action->setVisible(false);
2276 	}
2277 
2278 	mActionFileRecentSeparator->setVisible(!mRecentFiles[0].isEmpty());
2279 }
2280 
UpdateShortcuts()2281 void lcMainWindow::UpdateShortcuts()
2282 {
2283 	for (int ActionIdx = 0; ActionIdx < LC_NUM_COMMANDS; ActionIdx++)
2284 		mActions[ActionIdx]->setShortcut(QKeySequence(gKeyboardShortcuts.mShortcuts[ActionIdx]));
2285 }
2286 
NewProject()2287 void lcMainWindow::NewProject()
2288 {
2289 	if (!SaveProjectIfModified())
2290 		return;
2291 
2292 	Project* NewProject = new Project();
2293 	gApplication->SetProject(NewProject);
2294 	lcGetPiecesLibrary()->UnloadUnusedParts();
2295 }
2296 
OpenProject(const QString & FileName)2297 bool lcMainWindow::OpenProject(const QString& FileName)
2298 {
2299 	if (!SaveProjectIfModified())
2300 		return false;
2301 
2302 	QString LoadFileName = FileName;
2303 
2304 	if (LoadFileName.isEmpty())
2305 	{
2306 		LoadFileName = lcGetActiveProject()->GetFileName();
2307 
2308 		if (LoadFileName.isEmpty())
2309 			LoadFileName = lcGetProfileString(LC_PROFILE_PROJECTS_PATH);
2310 
2311 		LoadFileName = QFileDialog::getOpenFileName(this, tr("Open Model"), LoadFileName, tr("Supported Files (*.lcd *.ldr *.dat *.mpd);;All Files (*.*)"));
2312 
2313 		if (LoadFileName.isEmpty())
2314 			return false;
2315 
2316 		lcSetProfileString(LC_PROFILE_PROJECTS_PATH, QFileInfo(LoadFileName).absolutePath());
2317 	}
2318 
2319 	return OpenProjectFile(LoadFileName);
2320 }
2321 
OpenRecentProject(int RecentFileIndex)2322 void lcMainWindow::OpenRecentProject(int RecentFileIndex)
2323 {
2324 	if (!SaveProjectIfModified())
2325 		return;
2326 
2327 	if (!OpenProjectFile(mRecentFiles[RecentFileIndex]))
2328 		RemoveRecentFile(RecentFileIndex);
2329 }
2330 
OpenProjectFile(const QString & FileName)2331 bool lcMainWindow::OpenProjectFile(const QString& FileName)
2332 {
2333 	Project* NewProject = new Project();
2334 
2335 	if (NewProject->Load(FileName, true))
2336 	{
2337 		gApplication->SetProject(NewProject);
2338 		AddRecentFile(FileName);
2339 		lcView::UpdateProjectViews(NewProject);
2340 
2341 		return true;
2342 	}
2343 
2344 	delete NewProject;
2345 	return false;
2346 }
2347 
MergeProject()2348 void lcMainWindow::MergeProject()
2349 {
2350 	QString LoadFileName = lcGetActiveProject()->GetFileName();
2351 
2352 	if (LoadFileName.isEmpty())
2353 		LoadFileName = lcGetProfileString(LC_PROFILE_PROJECTS_PATH);
2354 
2355 	LoadFileName = QFileDialog::getOpenFileName(this, tr("Merge Model"), LoadFileName, tr("Supported Files (*.lcd *.ldr *.dat *.mpd);;All Files (*.*)"));
2356 
2357 	if (LoadFileName.isEmpty())
2358 		return;
2359 
2360 	lcSetProfileString(LC_PROFILE_PROJECTS_PATH, QFileInfo(LoadFileName).absolutePath());
2361 
2362 	Project* NewProject = new Project();
2363 
2364 	if (NewProject->Load(LoadFileName, true))
2365 	{
2366 		int NumModels = NewProject->GetModels().GetSize();
2367 
2368 		lcGetActiveProject()->Merge(NewProject);
2369 
2370 		if (NumModels == 1)
2371 			QMessageBox::information(this, tr("LeoCAD"), tr("Merged 1 submodel."));
2372 		else
2373 			QMessageBox::information(this, tr("LeoCAD"), tr("Merged %1 submodels.").arg(NumModels));
2374 
2375 		UpdateModels();
2376 	}
2377 
2378 	delete NewProject;
2379 }
2380 
ImportLDD()2381 void lcMainWindow::ImportLDD()
2382 {
2383 	if (!SaveProjectIfModified())
2384 		return;
2385 
2386 	QString LoadFileName = QFileDialog::getOpenFileName(this, tr("Import"), QString(), tr("LEGO Diginal Designer Files (*.lxf);;All Files (*.*)"));
2387 	if (LoadFileName.isEmpty())
2388 		return;
2389 
2390 	Project* NewProject = new Project();
2391 
2392 	if (NewProject->ImportLDD(LoadFileName))
2393 	{
2394 		gApplication->SetProject(NewProject);
2395 		lcView::UpdateProjectViews(NewProject);
2396 	}
2397 	else
2398 		delete NewProject;
2399 }
2400 
ImportInventory()2401 void lcMainWindow::ImportInventory()
2402 {
2403 	if (!SaveProjectIfModified())
2404 		return;
2405 
2406 	lcSetsDatabaseDialog Dialog(this);
2407 	if (Dialog.exec() != QDialog::Accepted)
2408 		return;
2409 
2410 	Project* NewProject = new Project();
2411 
2412 	if (NewProject->ImportInventory(Dialog.GetSetInventory(), Dialog.GetSetName(), Dialog.GetSetDescription()))
2413 	{
2414 		gApplication->SetProject(NewProject);
2415 		lcView::UpdateProjectViews(NewProject);
2416 	}
2417 	else
2418 		delete NewProject;
2419 }
SaveProject(const QString & FileName)2420 bool lcMainWindow::SaveProject(const QString& FileName)
2421 {
2422 	QString SaveFileName = FileName;
2423 	Project* Project = lcGetActiveProject();
2424 
2425 	if (SaveFileName.isEmpty())
2426 	{
2427 		SaveFileName = Project->GetFileName();
2428 
2429 		if (SaveFileName.isEmpty())
2430 			SaveFileName = QFileInfo(QDir(lcGetProfileString(LC_PROFILE_PROJECTS_PATH)), Project->GetTitle()).absoluteFilePath();
2431 
2432 		QString Filter = (Project->GetModels().GetSize() > 1) ? tr("Supported Files (*.mpd);;All Files (*.*)") : tr("Supported Files (*.ldr *.dat *.mpd);;All Files (*.*)");
2433 
2434 		SaveFileName = QFileDialog::getSaveFileName(this, tr("Save Model"), SaveFileName, Filter);
2435 
2436 		if (SaveFileName.isEmpty())
2437 			return false;
2438 
2439 		lcSetProfileString(LC_PROFILE_PROJECTS_PATH, QFileInfo(SaveFileName).absolutePath());
2440 	}
2441 
2442 	if (QFileInfo(SaveFileName).suffix().toLower() == QLatin1String("lcd"))
2443 	{
2444 		QMessageBox::warning(this, tr("Error"), tr("Saving files in LCD format is no longer supported, please use the LDR or MPD formats instead."));
2445 		return false;
2446 	}
2447 
2448 	if (!Project->Save(SaveFileName))
2449 		return false;
2450 
2451 	AddRecentFile(SaveFileName);
2452 	UpdateTitle();
2453 
2454 	return true;
2455 }
2456 
SaveProjectIfModified()2457 bool lcMainWindow::SaveProjectIfModified()
2458 {
2459 	Project* Project = lcGetActiveProject();
2460 	if (!Project->IsModified())
2461 		return true;
2462 
2463 	switch (QMessageBox::question(this, tr("Save Model"), tr("Save changes to '%1'?").arg(Project->GetTitle()), QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel))
2464 	{
2465 	default:
2466 	case QMessageBox::Cancel:
2467 		return false;
2468 
2469 	case QMessageBox::Yes:
2470 		if (!SaveProject(Project->GetFileName()))
2471 			return false;
2472 		break;
2473 
2474 	case QMessageBox::No:
2475 		break;
2476 	}
2477 
2478 	return true;
2479 }
2480 
SetModelFromFocus()2481 bool lcMainWindow::SetModelFromFocus()
2482 {
2483 	lcObject* FocusObject = GetActiveModel()->GetFocusObject();
2484 
2485 	if (!FocusObject || !FocusObject->IsPiece())
2486 		return false;
2487 
2488 	lcModel* Model = ((lcPiece*)FocusObject)->mPieceInfo->GetModel();
2489 
2490 	if (Model)
2491 	{
2492 		Project* Project = lcGetActiveProject();
2493 		Project->SetActiveModel(Project->GetModels().FindIndex(Model));
2494 		return true;
2495 	}
2496 
2497 	return false;
2498 }
2499 
SetModelFromSelection()2500 void lcMainWindow::SetModelFromSelection()
2501 {
2502 	if (SetModelFromFocus())
2503 		return;
2504 
2505 	lcModel* Model = GetActiveModel()->GetFirstSelectedSubmodel();
2506 
2507 	if (Model)
2508 	{
2509 		Project* Project = lcGetActiveProject();
2510 		Project->SetActiveModel(Project->GetModels().FindIndex(Model));
2511 	}
2512 }
2513 
GetActiveModel() const2514 lcModel* lcMainWindow::GetActiveModel() const
2515 {
2516 	lcView* ActiveView = GetActiveView();
2517 	return ActiveView ? ActiveView->GetActiveModel() : nullptr;
2518 }
2519 
GetTabForView(lcView * View) const2520 lcModelTabWidget* lcMainWindow::GetTabForView(lcView* View) const
2521 {
2522 	QWidget* Widget = View->GetWidget();
2523 
2524 	while (Widget)
2525 	{
2526 		lcModelTabWidget* TabWidget = qobject_cast<lcModelTabWidget*>(Widget);
2527 
2528 		if (TabWidget)
2529 			return TabWidget;
2530 		else
2531 			Widget = Widget->parentWidget();
2532 	}
2533 
2534 	return nullptr;
2535 }
2536 
HandleCommand(lcCommandId CommandId)2537 void lcMainWindow::HandleCommand(lcCommandId CommandId)
2538 {
2539 	lcView* ActiveView = GetActiveView();
2540 	lcModel* ActiveModel = ActiveView ? ActiveView->GetActiveModel() : nullptr;
2541 
2542 	switch (CommandId)
2543 	{
2544 	case LC_FILE_NEW:
2545 		NewProject();
2546 		break;
2547 
2548 	case LC_FILE_OPEN:
2549 		OpenProject(QString());
2550 		break;
2551 
2552 	case LC_FILE_MERGE:
2553 		MergeProject();
2554 		break;
2555 
2556 	case LC_FILE_SAVE:
2557 		SaveProject(lcGetActiveProject()->GetFileName());
2558 		break;
2559 
2560 	case LC_FILE_SAVEAS:
2561 		SaveProject(QString());
2562 		break;
2563 
2564 	case LC_FILE_SAVE_IMAGE:
2565 		lcGetActiveProject()->SaveImage();
2566 		break;
2567 
2568 	case LC_FILE_IMPORT_LDD:
2569 		ImportLDD();
2570 		break;
2571 
2572 	case LC_FILE_IMPORT_INVENTORY:
2573 		ImportInventory();
2574 		break;
2575 
2576 	case LC_FILE_EXPORT_3DS:
2577 		lcGetActiveProject()->Export3DStudio(QString());
2578 		break;
2579 
2580 	case LC_FILE_EXPORT_COLLADA:
2581 		lcGetActiveProject()->ExportCOLLADA(QString());
2582 		break;
2583 
2584 	case LC_FILE_EXPORT_HTML:
2585 		ShowHTMLDialog();
2586 		break;
2587 
2588 	case LC_FILE_EXPORT_BRICKLINK:
2589 		lcGetActiveProject()->ExportBrickLink();
2590 		break;
2591 
2592 	case LC_FILE_EXPORT_CSV:
2593 		lcGetActiveProject()->ExportCSV();
2594 		break;
2595 
2596 	case LC_FILE_EXPORT_POVRAY:
2597 		lcGetActiveProject()->ExportPOVRay(QString());
2598 		break;
2599 
2600 	case LC_FILE_EXPORT_WAVEFRONT:
2601 		lcGetActiveProject()->ExportWavefront(QString());
2602 		break;
2603 
2604 	case LC_FILE_RENDER:
2605 		ShowRenderDialog();
2606 		break;
2607 
2608 	case LC_FILE_INSTRUCTIONS:
2609 		ShowInstructionsDialog();
2610 		break;
2611 
2612 	case LC_FILE_PRINT_PREVIEW:
2613 		TogglePrintPreview();
2614 		break;
2615 
2616 	case LC_FILE_PRINT:
2617 		ShowPrintDialog();
2618 		break;
2619 
2620 	case LC_FILE_RECENT1:
2621 	case LC_FILE_RECENT2:
2622 	case LC_FILE_RECENT3:
2623 	case LC_FILE_RECENT4:
2624 		OpenRecentProject(CommandId - LC_FILE_RECENT1);
2625 		break;
2626 
2627 	case LC_FILE_EXIT:
2628 		close();
2629 		break;
2630 
2631 	case LC_EDIT_UNDO:
2632 		if (ActiveModel)
2633 			ActiveModel->UndoAction();
2634 		break;
2635 
2636 	case LC_EDIT_REDO:
2637 		if (ActiveModel)
2638 			ActiveModel->RedoAction();
2639 		break;
2640 
2641 	case LC_EDIT_CUT:
2642 		if (ActiveModel)
2643 			ActiveModel->Cut();
2644 		break;
2645 
2646 	case LC_EDIT_COPY:
2647 		if (ActiveModel)
2648 			ActiveModel->Copy();
2649 		break;
2650 
2651 	case LC_EDIT_PASTE:
2652 		if (ActiveModel)
2653 			ActiveModel->Paste(true);
2654 		break;
2655 
2656 	case LC_EDIT_PASTE_STEPS:
2657 		if (ActiveModel)
2658 			ActiveModel->Paste(false);
2659 		break;
2660 
2661 	case LC_EDIT_FIND:
2662 		if (ActiveView)
2663 			ActiveView->ShowFindReplaceWidget(false);
2664 		break;
2665 
2666 	case LC_EDIT_FIND_NEXT:
2667 		if (ActiveModel)
2668 			ActiveModel->FindReplacePiece(true, false);
2669 		break;
2670 
2671 	case LC_EDIT_FIND_PREVIOUS:
2672 		if (ActiveModel)
2673 			ActiveModel->FindReplacePiece(false, false);
2674 		break;
2675 
2676 	case LC_EDIT_FIND_ALL:
2677 		if (ActiveModel)
2678 			ActiveModel->FindReplacePiece(true, true);
2679 		break;
2680 
2681 	case LC_EDIT_REPLACE:
2682 		if (ActiveView)
2683 			ActiveView->ShowFindReplaceWidget(true);
2684 		break;
2685 
2686 	case LC_EDIT_REPLACE_ALL:
2687 		if (ActiveModel)
2688 			ActiveModel->FindReplacePiece(true, true);
2689 		break;
2690 
2691 	case LC_EDIT_REPLACE_NEXT:
2692 		if (ActiveModel)
2693 			ActiveModel->FindReplacePiece(true, false);
2694 		break;
2695 
2696 	case LC_EDIT_SELECT_ALL:
2697 		if (ActiveModel)
2698 			ActiveModel->SelectAllPieces();
2699 		break;
2700 
2701 	case LC_EDIT_SELECT_NONE:
2702 		if (ActiveModel)
2703 			ActiveModel->ClearSelection(true);
2704 		break;
2705 
2706 	case LC_EDIT_SELECT_INVERT:
2707 		if (ActiveModel)
2708 			ActiveModel->InvertSelection();
2709 		break;
2710 
2711 	case LC_EDIT_SELECT_BY_NAME:
2712 		if (ActiveModel)
2713 			ActiveModel->ShowSelectByNameDialog();
2714 		break;
2715 
2716 	case LC_EDIT_SELECTION_SINGLE:
2717 		SetSelectionMode(lcSelectionMode::Single);
2718 		break;
2719 
2720 	case LC_EDIT_SELECTION_PIECE:
2721 		SetSelectionMode(lcSelectionMode::Piece);
2722 		break;
2723 
2724 	case LC_EDIT_SELECTION_COLOR:
2725 		SetSelectionMode(lcSelectionMode::Color);
2726 		break;
2727 
2728 	case LC_EDIT_SELECTION_PIECE_COLOR:
2729 		SetSelectionMode(lcSelectionMode::PieceColor);
2730 		break;
2731 
2732 	case LC_VIEW_SPLIT_HORIZONTAL:
2733 		SplitHorizontal();
2734 		break;
2735 
2736 	case LC_VIEW_SPLIT_VERTICAL:
2737 		SplitVertical();
2738 		break;
2739 
2740 	case LC_VIEW_REMOVE_VIEW:
2741 		RemoveActiveView();
2742 		break;
2743 
2744 	case LC_VIEW_RESET_VIEWS:
2745 		ResetViews();
2746 		break;
2747 
2748 	case LC_VIEW_TOOLBAR_STANDARD:
2749 		ToggleDockWidget(mStandardToolBar);
2750 		break;
2751 
2752 	case LC_VIEW_TOOLBAR_TOOLS:
2753 		ToggleDockWidget(mToolsToolBar);
2754 		break;
2755 
2756 	case LC_VIEW_TOOLBAR_TIME:
2757 		ToggleDockWidget(mTimeToolBar);
2758 		break;
2759 
2760 	case LC_VIEW_TOOLBAR_PARTS:
2761 		ToggleDockWidget(mPartsToolBar);
2762 		break;
2763 
2764 	case LC_VIEW_TOOLBAR_COLORS:
2765 		ToggleDockWidget(mColorsToolBar);
2766 		break;
2767 
2768 	case LC_VIEW_TOOLBAR_PROPERTIES:
2769 		ToggleDockWidget(mPropertiesToolBar);
2770 		break;
2771 
2772 	case LC_VIEW_TOOLBAR_TIMELINE:
2773 		ToggleDockWidget(mTimelineToolBar);
2774 		break;
2775 
2776 	case LC_VIEW_TOOLBAR_PREVIEW:
2777 		ToggleDockWidget(mPreviewToolBar);
2778 		break;
2779 
2780 	case LC_VIEW_FULLSCREEN:
2781 		ToggleFullScreen();
2782 		break;
2783 
2784 	case LC_VIEW_CLOSE_CURRENT_TAB:
2785 		CloseCurrentModelTab();
2786 		break;
2787 
2788 	case LC_VIEW_SHADING_WIREFRAME:
2789 		SetShadingMode(lcShadingMode::Wireframe);
2790 		break;
2791 
2792 	case LC_VIEW_SHADING_FLAT:
2793 		SetShadingMode(lcShadingMode::Flat);
2794 		break;
2795 
2796 	case LC_VIEW_SHADING_DEFAULT_LIGHTS:
2797 		SetShadingMode(lcShadingMode::DefaultLights);
2798 		break;
2799 
2800 	case LC_VIEW_PROJECTION_PERSPECTIVE:
2801 		if (ActiveView)
2802 			ActiveView->SetProjection(false);
2803 		break;
2804 
2805 	case LC_VIEW_PROJECTION_ORTHO:
2806 		if (ActiveView)
2807 			ActiveView->SetProjection(true);
2808 		break;
2809 
2810 	case LC_VIEW_TOGGLE_VIEW_SPHERE:
2811 		ToggleViewSphere();
2812 		break;
2813 
2814 	case LC_VIEW_TOGGLE_AXIS_ICON:
2815 		ToggleAxisIcon();
2816 		break;
2817 
2818 	case LC_VIEW_TOGGLE_GRID:
2819 		ToggleGrid();
2820 		break;
2821 
2822 	case LC_VIEW_FADE_PREVIOUS_STEPS:
2823 		ToggleFadePreviousSteps();
2824 		break;
2825 
2826 	case LC_PIECE_INSERT:
2827 		if (ActiveModel)
2828 			ActiveModel->AddPiece();
2829 		break;
2830 
2831 	case LC_PIECE_DELETE:
2832 		if (ActiveModel)
2833 			ActiveModel->DeleteSelectedObjects();
2834 		break;
2835 
2836 	case LC_PIECE_DUPLICATE:
2837 		if (ActiveModel)
2838 			ActiveModel->DuplicateSelectedPieces();
2839 		break;
2840 
2841 	case LC_PIECE_PAINT_SELECTED:
2842 		if (ActiveModel)
2843 			ActiveModel->PaintSelectedPieces();
2844 		break;
2845 
2846 	case LC_PIECE_RESET_PIVOT_POINT:
2847 		if (ActiveModel)
2848 			ActiveModel->ResetSelectedPiecesPivotPoint();
2849 		break;
2850 
2851 	case LC_PIECE_REMOVE_KEY_FRAMES:
2852 		if (ActiveModel)
2853 			ActiveModel->RemoveSelectedPiecesKeyFrames();
2854 		break;
2855 
2856 	case LC_PIECE_CONTROL_POINT_INSERT:
2857 		if (ActiveModel)
2858 			ActiveModel->InsertControlPoint();
2859 		break;
2860 
2861 	case LC_PIECE_CONTROL_POINT_REMOVE:
2862 		if (ActiveModel)
2863 			ActiveModel->RemoveFocusedControlPoint();
2864 		break;
2865 
2866 	case LC_PIECE_MOVE_PLUSX:
2867 		if (ActiveModel)
2868 			ActiveModel->MoveSelectedObjects(ActiveView->GetMoveDirection(lcVector3(lcMax(GetMoveXYSnap(), 0.1f), 0.0f, 0.0f)), true, false, true, true);
2869 		break;
2870 
2871 	case LC_PIECE_MOVE_MINUSX:
2872 		if (ActiveModel)
2873 			ActiveModel->MoveSelectedObjects(ActiveView->GetMoveDirection(lcVector3(-lcMax(GetMoveXYSnap(), 0.1f), 0.0f, 0.0f)), true, false, true, true);
2874 		break;
2875 
2876 	case LC_PIECE_MOVE_PLUSY:
2877 		if (ActiveModel)
2878 			ActiveModel->MoveSelectedObjects(ActiveView->GetMoveDirection(lcVector3(0.0f, lcMax(GetMoveXYSnap(), 0.1f), 0.0f)), true, false, true, true);
2879 		break;
2880 
2881 	case LC_PIECE_MOVE_MINUSY:
2882 		if (ActiveModel)
2883 			ActiveModel->MoveSelectedObjects(ActiveView->GetMoveDirection(lcVector3(0.0f, -lcMax(GetMoveXYSnap(), 0.1f), 0.0f)), true, false, true, true);
2884 		break;
2885 
2886 	case LC_PIECE_MOVE_PLUSZ:
2887 		if (ActiveModel)
2888 			ActiveModel->MoveSelectedObjects(ActiveView->GetMoveDirection(lcVector3(0.0f, 0.0f, lcMax(GetMoveZSnap(), 0.1f))), true, false, true, true);
2889 		break;
2890 
2891 	case LC_PIECE_MOVE_MINUSZ:
2892 		if (ActiveModel)
2893 			ActiveModel->MoveSelectedObjects(ActiveView->GetMoveDirection(lcVector3(0.0f, 0.0f, -lcMax(GetMoveZSnap(), 0.1f))), true, false, true, true);
2894 		break;
2895 
2896 	case LC_PIECE_ROTATE_PLUSX:
2897 		if (ActiveModel)
2898 			ActiveModel->RotateSelectedPieces(ActiveView->GetMoveDirection(lcVector3(lcMax(GetAngleSnap(), 1.0f), 0.0f, 0.0f)), true, false, true, true);
2899 		break;
2900 
2901 	case LC_PIECE_ROTATE_MINUSX:
2902 		if (ActiveModel)
2903 			ActiveModel->RotateSelectedPieces(ActiveView->GetMoveDirection(-lcVector3(lcMax(GetAngleSnap(), 1.0f), 0.0f, 0.0f)), true, false, true, true);
2904 		break;
2905 
2906 	case LC_PIECE_ROTATE_PLUSY:
2907 		if (ActiveModel)
2908 			ActiveModel->RotateSelectedPieces(ActiveView->GetMoveDirection(lcVector3(0.0f, lcMax(GetAngleSnap(), 1.0f), 0.0f)), true, false, true, true);
2909 		break;
2910 
2911 	case LC_PIECE_ROTATE_MINUSY:
2912 		if (ActiveModel)
2913 			ActiveModel->RotateSelectedPieces(ActiveView->GetMoveDirection(lcVector3(0.0f, -lcMax(GetAngleSnap(), 1.0f), 0.0f)), true, false, true, true);
2914 		break;
2915 
2916 	case LC_PIECE_ROTATE_PLUSZ:
2917 		if (ActiveModel)
2918 			ActiveModel->RotateSelectedPieces(ActiveView->GetMoveDirection(lcVector3(0.0f, 0.0f, lcMax(GetAngleSnap(), 1.0f))), true, false, true, true);
2919 		break;
2920 
2921 	case LC_PIECE_ROTATE_MINUSZ:
2922 		if (ActiveModel)
2923 			ActiveModel->RotateSelectedPieces(ActiveView->GetMoveDirection(lcVector3(0.0f, 0.0f, -lcMax(GetAngleSnap(), 1.0f))), true, false, true, true);
2924 		break;
2925 
2926 	case LC_PIECE_MINIFIG_WIZARD:
2927 		if (ActiveModel)
2928 			ActiveModel->ShowMinifigDialog();
2929 		break;
2930 
2931 	case LC_PIECE_ARRAY:
2932 		if (ActiveModel)
2933 			ActiveModel->ShowArrayDialog();
2934 		break;
2935 
2936 	case LC_PIECE_VIEW_SELECTED_MODEL:
2937 		SetModelFromSelection();
2938 		break;
2939 
2940 	case LC_PIECE_MOVE_SELECTION_TO_MODEL:
2941 		if (ActiveModel)
2942 			ActiveModel->MoveSelectionToModel(lcGetActiveProject()->CreateNewModel(false));
2943 		break;
2944 
2945 	case LC_PIECE_INLINE_SELECTED_MODELS:
2946 		if (ActiveModel)
2947 			ActiveModel->InlineSelectedModels();
2948 		break;
2949 
2950 	case LC_PIECE_EDIT_END_SUBMODEL:
2951 		if (ActiveView)
2952 		{
2953 			ActiveView->SetTopSubmodelActive();
2954 			if (ActiveModel)
2955 			{
2956 				std::vector<lcModel*> UpdatedModels;
2957 				ActiveModel->UpdatePieceInfo(UpdatedModels);
2958 			}
2959 		}
2960 		break;
2961 
2962 	case LC_PIECE_EDIT_SELECTED_SUBMODEL:
2963 		if (ActiveView)
2964 			ActiveView->SetSelectedSubmodelActive();
2965 		break;
2966 
2967 	case LC_PIECE_GROUP:
2968 		if (ActiveModel)
2969 			ActiveModel->GroupSelection();
2970 		break;
2971 
2972 	case LC_PIECE_UNGROUP:
2973 		if (ActiveModel)
2974 			ActiveModel->UngroupSelection();
2975 		break;
2976 
2977 	case LC_PIECE_GROUP_ADD:
2978 		if (ActiveModel)
2979 			ActiveModel->AddSelectedPiecesToGroup();
2980 		break;
2981 
2982 	case LC_PIECE_GROUP_REMOVE:
2983 		if (ActiveModel)
2984 			ActiveModel->RemoveFocusPieceFromGroup();
2985 		break;
2986 
2987 	case LC_PIECE_GROUP_EDIT:
2988 		if (ActiveModel)
2989 			ActiveModel->ShowEditGroupsDialog();
2990 		break;
2991 
2992 	case LC_PIECE_HIDE_SELECTED:
2993 		if (ActiveModel)
2994 			ActiveModel->HideSelectedPieces();
2995 		break;
2996 
2997 	case LC_PIECE_HIDE_UNSELECTED:
2998 		if (ActiveModel)
2999 			ActiveModel->HideUnselectedPieces();
3000 		break;
3001 
3002 	case LC_PIECE_UNHIDE_SELECTED:
3003 		if (ActiveModel)
3004 			ActiveModel->UnhideSelectedPieces();
3005 		break;
3006 
3007 	case LC_PIECE_UNHIDE_ALL:
3008 		if (ActiveModel)
3009 			ActiveModel->UnhideAllPieces();
3010 		break;
3011 
3012 	case LC_PIECE_SHOW_EARLIER:
3013 		if (ActiveModel)
3014 			ActiveModel->ShowSelectedPiecesEarlier();
3015 		break;
3016 
3017 	case LC_PIECE_SHOW_LATER:
3018 		if (ActiveModel)
3019 			ActiveModel->ShowSelectedPiecesLater();
3020 		break;
3021 
3022 	case LC_VIEW_PREFERENCES:
3023 		gApplication->ShowPreferencesDialog();
3024 		break;
3025 
3026 	case LC_VIEW_ZOOM_IN:
3027 		if (ActiveView)
3028 			ActiveView->Zoom(10.0f);
3029 		break;
3030 
3031 	case LC_VIEW_ZOOM_OUT:
3032 		if (ActiveView)
3033 			ActiveView->Zoom(-10.0f);
3034 		break;
3035 
3036 	case LC_VIEW_ZOOM_EXTENTS:
3037 		if (ActiveView)
3038 			ActiveView->ZoomExtents();
3039 		break;
3040 
3041 	case LC_VIEW_LOOK_AT:
3042 		if (ActiveView)
3043 			ActiveView->LookAt();
3044 		break;
3045 
3046 	case LC_VIEW_MOVE_FORWARD:
3047 		if (ActiveView)
3048 			ActiveView->MoveCamera(lcVector3(0.0f, 0.0f, -1.0f));
3049 		break;
3050 
3051 	case LC_VIEW_MOVE_BACKWARD:
3052 		if (ActiveView)
3053 			ActiveView->MoveCamera(lcVector3(0.0f, 0.0f, 1.0f));
3054 		break;
3055 
3056 	case LC_VIEW_MOVE_LEFT:
3057 		if (ActiveView)
3058 			ActiveView->MoveCamera(lcVector3(-1.0f, 0.0f, 0.0f));
3059 		break;
3060 
3061 	case LC_VIEW_MOVE_RIGHT:
3062 		if (ActiveView)
3063 			ActiveView->MoveCamera(lcVector3(1.0f, 0.0f, 0.0f));
3064 		break;
3065 
3066 	case LC_VIEW_MOVE_UP:
3067 		if (ActiveView)
3068 			ActiveView->MoveCamera(lcVector3(0.0f, 1.0f, 0.0f));
3069 		break;
3070 
3071 	case LC_VIEW_MOVE_DOWN:
3072 		if (ActiveView)
3073 			ActiveView->MoveCamera(lcVector3(0.0f, -1.0f, 0.0f));
3074 		break;
3075 
3076 	case LC_VIEW_TIME_NEXT:
3077 		if (ActiveModel)
3078 			ActiveModel->ShowNextStep();
3079 		break;
3080 
3081 	case LC_VIEW_TIME_PREVIOUS:
3082 		if (ActiveModel)
3083 			ActiveModel->ShowPreviousStep();
3084 		break;
3085 
3086 	case LC_VIEW_TIME_FIRST:
3087 		if (ActiveModel)
3088 			ActiveModel->ShowFirstStep();
3089 		break;
3090 
3091 	case LC_VIEW_TIME_LAST:
3092 		if (ActiveModel)
3093 			ActiveModel->ShowLastStep();
3094 		break;
3095 
3096 	case LC_VIEW_TIME_INSERT_BEFORE:
3097 		lcGetActiveModel()->InsertStep(lcGetActiveModel()->GetCurrentStep());
3098 		break;
3099 
3100 	case LC_VIEW_TIME_INSERT_AFTER:
3101 		lcGetActiveModel()->InsertStep(lcGetActiveModel()->GetCurrentStep() + 1);
3102 		break;
3103 
3104 	case LC_VIEW_TIME_DELETE:
3105 		lcGetActiveModel()->RemoveStep(lcGetActiveModel()->GetCurrentStep());
3106 		break;
3107 
3108 	case LC_VIEW_VIEWPOINT_FRONT:
3109 		if (ActiveView)
3110 			ActiveView->SetViewpoint(lcViewpoint::Front);
3111 		break;
3112 
3113 	case LC_VIEW_VIEWPOINT_BACK:
3114 		if (ActiveView)
3115 			ActiveView->SetViewpoint(lcViewpoint::Back);
3116 		break;
3117 
3118 	case LC_VIEW_VIEWPOINT_TOP:
3119 		if (ActiveView)
3120 			ActiveView->SetViewpoint(lcViewpoint::Top);
3121 		break;
3122 
3123 	case LC_VIEW_VIEWPOINT_BOTTOM:
3124 		if (ActiveView)
3125 			ActiveView->SetViewpoint(lcViewpoint::Bottom);
3126 		break;
3127 
3128 	case LC_VIEW_VIEWPOINT_LEFT:
3129 		if (ActiveView)
3130 			ActiveView->SetViewpoint(lcViewpoint::Left);
3131 		break;
3132 
3133 	case LC_VIEW_VIEWPOINT_RIGHT:
3134 		if (ActiveView)
3135 			ActiveView->SetViewpoint(lcViewpoint::Right);
3136 		break;
3137 
3138 	case LC_VIEW_VIEWPOINT_HOME:
3139 		if (ActiveView)
3140 			ActiveView->SetViewpoint(lcViewpoint::Home);
3141 		break;
3142 
3143 	case LC_VIEW_CAMERA_NONE:
3144 		if (ActiveView)
3145 			ActiveView->RemoveCamera();
3146 		break;
3147 
3148 	case LC_VIEW_CAMERA1:
3149 	case LC_VIEW_CAMERA2:
3150 	case LC_VIEW_CAMERA3:
3151 	case LC_VIEW_CAMERA4:
3152 	case LC_VIEW_CAMERA5:
3153 	case LC_VIEW_CAMERA6:
3154 	case LC_VIEW_CAMERA7:
3155 	case LC_VIEW_CAMERA8:
3156 	case LC_VIEW_CAMERA9:
3157 	case LC_VIEW_CAMERA10:
3158 	case LC_VIEW_CAMERA11:
3159 	case LC_VIEW_CAMERA12:
3160 	case LC_VIEW_CAMERA13:
3161 	case LC_VIEW_CAMERA14:
3162 	case LC_VIEW_CAMERA15:
3163 	case LC_VIEW_CAMERA16:
3164 		if (ActiveView)
3165 			ActiveView->SetCameraIndex(CommandId - LC_VIEW_CAMERA1);
3166 		break;
3167 
3168 	case LC_MODEL_NEW:
3169 		lcGetActiveProject()->CreateNewModel(true);
3170 		break;
3171 
3172 	case LC_MODEL_PROPERTIES:
3173 		lcGetActiveModel()->ShowPropertiesDialog();
3174 		break;
3175 
3176 	case LC_MODEL_LIST:
3177 		lcGetActiveProject()->ShowModelListDialog();
3178 		break;
3179 
3180 	case LC_MODEL_01:
3181 	case LC_MODEL_02:
3182 	case LC_MODEL_03:
3183 	case LC_MODEL_04:
3184 	case LC_MODEL_05:
3185 	case LC_MODEL_06:
3186 	case LC_MODEL_07:
3187 	case LC_MODEL_08:
3188 	case LC_MODEL_09:
3189 	case LC_MODEL_10:
3190 	case LC_MODEL_11:
3191 	case LC_MODEL_12:
3192 	case LC_MODEL_13:
3193 	case LC_MODEL_14:
3194 	case LC_MODEL_15:
3195 	case LC_MODEL_16:
3196 	case LC_MODEL_17:
3197 	case LC_MODEL_18:
3198 	case LC_MODEL_19:
3199 	case LC_MODEL_20:
3200 	case LC_MODEL_21:
3201 	case LC_MODEL_22:
3202 	case LC_MODEL_23:
3203 	case LC_MODEL_24:
3204 	case LC_MODEL_25:
3205 	case LC_MODEL_26:
3206 	case LC_MODEL_27:
3207 	case LC_MODEL_28:
3208 	case LC_MODEL_29:
3209 	case LC_MODEL_30:
3210 	case LC_MODEL_31:
3211 	case LC_MODEL_32:
3212 	case LC_MODEL_33:
3213 	case LC_MODEL_34:
3214 	case LC_MODEL_35:
3215 	case LC_MODEL_36:
3216 	case LC_MODEL_37:
3217 	case LC_MODEL_38:
3218 	case LC_MODEL_39:
3219 	case LC_MODEL_40:
3220 		lcGetActiveProject()->SetActiveModel(CommandId - LC_MODEL_01);
3221 		break;
3222 
3223 	case LC_HELP_HOMEPAGE:
3224 		QDesktopServices::openUrl(QUrl("https://www.leocad.org/"));
3225 		break;
3226 
3227 	case LC_HELP_BUG_REPORT:
3228 		QDesktopServices::openUrl(QUrl("https://github.com/leozide/leocad/issues"));
3229 		break;
3230 
3231 	case LC_HELP_UPDATES:
3232 		ShowUpdatesDialog();
3233 		break;
3234 
3235 	case LC_HELP_ABOUT:
3236 		ShowAboutDialog();
3237 		break;
3238 
3239 	case LC_VIEW_TIME_ADD_KEYS:
3240 		SetAddKeys(!GetAddKeys());
3241 		break;
3242 
3243 	case LC_EDIT_TRANSFORM_RELATIVE:
3244 		SetRelativeTransform(true);
3245 		break;
3246 
3247 	case LC_EDIT_TRANSFORM_ABSOLUTE:
3248 		SetRelativeTransform(false);
3249 		break;
3250 
3251 	case LC_EDIT_TRANSFORM_TOGGLE_RELATIVE:
3252 		SetRelativeTransform(!GetRelativeTransform());
3253 		break;
3254 
3255 	case LC_EDIT_TRANSFORM_SEPARATELY:
3256 		SetSeparateTransform(true);
3257 		break;
3258 
3259 	case LC_EDIT_TRANSFORM_TOGETHER:
3260 		SetSeparateTransform(false);
3261 		break;
3262 
3263 	case LC_EDIT_TRANSFORM_TOGGLE_SEPARATE:
3264 		SetSeparateTransform(!GetSeparateTransform());
3265 		break;
3266 
3267 	case LC_EDIT_SNAP_MOVE_TOGGLE:
3268 		SetMoveSnapEnabled(!mMoveSnapEnabled);
3269 		break;
3270 
3271 	case LC_EDIT_SNAP_MOVE_XY0:
3272 	case LC_EDIT_SNAP_MOVE_XY1:
3273 	case LC_EDIT_SNAP_MOVE_XY2:
3274 	case LC_EDIT_SNAP_MOVE_XY3:
3275 	case LC_EDIT_SNAP_MOVE_XY4:
3276 	case LC_EDIT_SNAP_MOVE_XY5:
3277 	case LC_EDIT_SNAP_MOVE_XY6:
3278 	case LC_EDIT_SNAP_MOVE_XY7:
3279 	case LC_EDIT_SNAP_MOVE_XY8:
3280 	case LC_EDIT_SNAP_MOVE_XY9:
3281 		SetMoveXYSnapIndex(CommandId - LC_EDIT_SNAP_MOVE_XY0);
3282 		break;
3283 
3284 	case LC_EDIT_SNAP_MOVE_Z0:
3285 	case LC_EDIT_SNAP_MOVE_Z1:
3286 	case LC_EDIT_SNAP_MOVE_Z2:
3287 	case LC_EDIT_SNAP_MOVE_Z3:
3288 	case LC_EDIT_SNAP_MOVE_Z4:
3289 	case LC_EDIT_SNAP_MOVE_Z5:
3290 	case LC_EDIT_SNAP_MOVE_Z6:
3291 	case LC_EDIT_SNAP_MOVE_Z7:
3292 	case LC_EDIT_SNAP_MOVE_Z8:
3293 	case LC_EDIT_SNAP_MOVE_Z9:
3294 		SetMoveZSnapIndex(CommandId - LC_EDIT_SNAP_MOVE_Z0);
3295 		break;
3296 
3297 	case LC_EDIT_SNAP_ANGLE_TOGGLE:
3298 		SetAngleSnapEnabled(!mAngleSnapEnabled);
3299 		break;
3300 
3301 	case LC_EDIT_SNAP_ANGLE0:
3302 	case LC_EDIT_SNAP_ANGLE1:
3303 	case LC_EDIT_SNAP_ANGLE2:
3304 	case LC_EDIT_SNAP_ANGLE3:
3305 	case LC_EDIT_SNAP_ANGLE4:
3306 	case LC_EDIT_SNAP_ANGLE5:
3307 	case LC_EDIT_SNAP_ANGLE6:
3308 	case LC_EDIT_SNAP_ANGLE7:
3309 	case LC_EDIT_SNAP_ANGLE8:
3310 	case LC_EDIT_SNAP_ANGLE9:
3311 		SetAngleSnapIndex(CommandId - LC_EDIT_SNAP_ANGLE0);
3312 		break;
3313 
3314 	case LC_EDIT_TRANSFORM:
3315 		if (ActiveModel)
3316 			ActiveModel->TransformSelectedObjects(GetTransformType(), GetTransformAmount());
3317 		break;
3318 
3319 	case LC_EDIT_TRANSFORM_ABSOLUTE_TRANSLATION:
3320 		SetTransformType(lcTransformType::AbsoluteTranslation);
3321 		break;
3322 
3323 	case LC_EDIT_TRANSFORM_RELATIVE_TRANSLATION:
3324 		SetTransformType(lcTransformType::RelativeTranslation);
3325 		break;
3326 
3327 	case LC_EDIT_TRANSFORM_ABSOLUTE_ROTATION:
3328 		SetTransformType(lcTransformType::AbsoluteRotation);
3329 		break;
3330 
3331 	case LC_EDIT_TRANSFORM_RELATIVE_ROTATION:
3332 		SetTransformType(lcTransformType::RelativeRotation);
3333 		break;
3334 
3335 	case LC_EDIT_ACTION_SELECT:
3336 		SetTool(lcTool::Select);
3337 		break;
3338 
3339 	case LC_EDIT_ACTION_INSERT:
3340 		SetTool(lcTool::Insert);
3341 		break;
3342 
3343 	case LC_EDIT_ACTION_LIGHT:
3344 		SetTool(lcTool::Light);
3345 		break;
3346 
3347 	case LC_EDIT_ACTION_SPOTLIGHT:
3348 		SetTool(lcTool::SpotLight);
3349 		break;
3350 
3351 	case LC_EDIT_ACTION_CAMERA:
3352 		SetTool(lcTool::Camera);
3353 		break;
3354 
3355 	case LC_EDIT_ACTION_MOVE:
3356 		SetTool(lcTool::Move);
3357 		break;
3358 
3359 	case LC_EDIT_ACTION_ROTATE:
3360 		SetTool(lcTool::Rotate);
3361 		break;
3362 
3363 	case LC_EDIT_ACTION_DELETE:
3364 		SetTool(lcTool::Eraser);
3365 		break;
3366 
3367 	case LC_EDIT_ACTION_PAINT:
3368 		SetTool(lcTool::Paint);
3369 		break;
3370 
3371 	case LC_EDIT_ACTION_COLOR_PICKER:
3372 		SetTool(lcTool::ColorPicker);
3373 		break;
3374 
3375 	case LC_EDIT_ACTION_ZOOM:
3376 		SetTool(lcTool::Zoom);
3377 		break;
3378 
3379 	case LC_EDIT_ACTION_ZOOM_REGION:
3380 		SetTool(lcTool::ZoomRegion);
3381 		break;
3382 
3383 	case LC_EDIT_ACTION_PAN:
3384 		SetTool(lcTool::Pan);
3385 		break;
3386 
3387 	case LC_EDIT_ACTION_ROTATE_VIEW:
3388 		SetTool(lcTool::RotateView);
3389 		break;
3390 
3391 	case LC_EDIT_ACTION_ROLL:
3392 		SetTool(lcTool::Roll);
3393 		break;
3394 
3395 	case LC_EDIT_CANCEL:
3396 		if (ActiveView && !ActiveView->CloseFindReplaceDialog())
3397 			ActiveView->CancelTrackingOrClearSelection();
3398 		break;
3399 
3400 	case LC_TIMELINE_INSERT_BEFORE:
3401 		mTimelineWidget->InsertStepBefore();
3402 		break;
3403 
3404 	case LC_TIMELINE_INSERT_AFTER:
3405 		mTimelineWidget->InsertStepAfter();
3406 		break;
3407 
3408 	case LC_TIMELINE_DELETE:
3409 		mTimelineWidget->RemoveStep();
3410 		break;
3411 
3412 	case LC_TIMELINE_MOVE_SELECTION:
3413 		mTimelineWidget->MoveSelection();
3414 		break;
3415 
3416 	case LC_TIMELINE_SET_CURRENT:
3417 		mTimelineWidget->SetCurrentStep();
3418 		break;
3419 
3420 	case LC_NUM_COMMANDS:
3421 		break;
3422 	}
3423 }
3424