Files
leocad/common/lc_mainwindow.cpp
T
Leonardo Zide 513e556ce9 Standardize model terminology and command descriptions
Use model and submodel terminology in user-facing help, errors, and the Windows file-type description. Standardize keyframe and spotlight text across menus, properties, undo history, and default light names while preserving internal identifiers and file-format tokens.

Correct the directional-light and movement-snapping descriptions, remove obsolete Ctrl advice from Zoom Extents, and fix deselection and rotation wording. Leave translation catalogs unchanged for the deferred catalog update.

Validation: debug build passes without warnings; UI XML and string-only diff checks pass.
2026-10-22 22:08:53 -07:00

3857 lines
115 KiB
C++

#include "lc_global.h"
#include "lc_mainwindow.h"
#include <QPrintDialog>
#include <QPrintPreviewDialog>
#include "lc_partselectionwidget.h"
#include "lc_propertieswidget.h"
#include "lc_timelinewidget.h"
#include "lc_viewwidget.h"
#include "lc_colorlist.h"
#include "lc_qutils.h"
#include "lc_updatedialog.h"
#include "lc_aboutdialog.h"
#include "lc_selectdialog.h"
#include "lc_setsdatabasedialog.h"
#include "lc_htmldialog.h"
#include "lc_renderdialog.h"
#include "lc_instructionsdialog.h"
#include "lc_imagedialog.h"
#include "lc_profile.h"
#include "lc_view.h"
#include "project.h"
#include "piece.h"
#include "camera.h"
#include "group.h"
#include "lc_piecedata.h"
#include "lc_library.h"
#include "lc_colors.h"
#include "lc_previewwidget.h"
#include "lc_modelhistory.h"
#include "lc_spinnerwidget.h"
#if LC_ENABLE_GAMEPAD
#include <QtGamepad/QGamepad>
#endif
lcMainWindow* gMainWindow;
#define LC_TAB_LAYOUT_VERSION 0x0001
lcMainWindow::lcMainWindow()
{
mTransformType = lcTransformType::RelativeTranslation;
mColorIndex = lcGetColorIndex(7);
mTool = lcTool::Select;
mMoveXYSnapIndex = 4;
mMoveZSnapIndex = 3;
mAngleSnapIndex = 5;
mSelectionMode = lcSelectionMode::Single;
for (size_t FileIndex = 0; FileIndex < mRecentFiles.size(); FileIndex++)
mRecentFiles[FileIndex] = lcGetProfileString((LC_PROFILE_KEY)(LC_PROFILE_RECENT_FILE1 + FileIndex));
#if (QT_VERSION >= QT_VERSION_CHECK(5, 8, 0))
connect(&mGamepadTimer, &QTimer::timeout, this, &lcMainWindow::UpdateGamepads);
mLastGamepadUpdate = QDateTime::currentDateTime();
mGamepadTimer.start(33);
#endif
gMainWindow = this;
}
lcMainWindow::~lcMainWindow()
{
lcPiecesLibrary* Library = lcGetPiecesLibrary();
disconnect(Library, nullptr, this, nullptr);
mInsertPieceData.Reset();
for (size_t FileIndex = 0; FileIndex < mRecentFiles.size(); FileIndex++)
lcSetProfileString((LC_PROFILE_KEY)(LC_PROFILE_RECENT_FILE1 + FileIndex), mRecentFiles[FileIndex]);
gMainWindow = nullptr;
}
void lcMainWindow::CreateWidgets()
{
setAcceptDrops(true);
setWindowIcon(QIcon(":/resources/leocad.png"));
setWindowFilePath(QString());
CreateActions();
CreateToolBars();
CreateMenus();
CreateStatusBar();
mModelTabWidget = new QTabWidget();
mModelTabWidget->tabBar()->installEventFilter(this);
mModelTabWidget->tabBar()->setMovable(true);
mModelTabWidget->tabBar()->setTabsClosable(true);
mModelTabWidget->tabBar()->setContextMenuPolicy(Qt::CustomContextMenu);
setCentralWidget(mModelTabWidget);
connect(mModelTabWidget->tabBar(), &QTabBar::tabCloseRequested, this, &lcMainWindow::ModelTabClosed);
connect(mModelTabWidget->tabBar(), &QTabBar::customContextMenuRequested, this, &lcMainWindow::ModelTabContextMenuRequested);
connect(mModelTabWidget, &QTabWidget::currentChanged, this, &lcMainWindow::ModelTabChanged);
connect(QApplication::clipboard(), &QClipboard::dataChanged, this, &lcMainWindow::ClipboardChanged);
ClipboardChanged();
QSettings Settings;
Settings.beginGroup("MainWindow");
resize(QSize(800, 600));
move(QPoint(200, 200));
restoreGeometry(Settings.value("Geometry").toByteArray());
restoreState(Settings.value("State").toByteArray());
mPartSelectionWidget->LoadState(Settings);
Settings.endGroup();
}
void lcMainWindow::CreateActions()
{
for (int CommandIdx = 0; CommandIdx < LC_NUM_COMMANDS; CommandIdx++)
{
QAction* Action = new QAction(qApp->translate("Menu", gCommands[CommandIdx].MenuName), this);
Action->setStatusTip(qApp->translate("Status", gCommands[CommandIdx].StatusText));
if (gCommands[CommandIdx].WhatsThis[0])
Action->setWhatsThis(qApp->translate("WhatsThis", gCommands[CommandIdx].WhatsThis));
connect(Action, &QAction::triggered, this, &lcMainWindow::ActionTriggered);
addAction(Action);
mActions[CommandIdx] = Action;
}
mActions[LC_HELP_WHATS_THIS]->setToolTip(mActions[LC_HELP_WHATS_THIS]->statusTip());
mActions[LC_FILE_NEW]->setToolTip(tr("New Model"));
mActions[LC_FILE_OPEN]->setToolTip(tr("Open Model"));
mActions[LC_FILE_SAVE]->setToolTip(tr("Save Model"));
QIcon FileNewIcon;
FileNewIcon.addFile(":/resources/file_new.png");
FileNewIcon.addFile(":/resources/file_new_16.png");
mActions[LC_FILE_NEW]->setIcon(FileNewIcon);
QIcon FileSaveIcon;
FileSaveIcon.addFile(":/resources/file_save.png");
FileSaveIcon.addFile(":/resources/file_save_16.png");
mActions[LC_FILE_SAVE]->setIcon(FileSaveIcon);
QIcon FileOpenIcon;
FileOpenIcon.addFile(":/resources/file_open.png");
FileOpenIcon.addFile(":/resources/file_open_16.png");
mActions[LC_FILE_OPEN]->setIcon(FileOpenIcon);
QIcon FilePrintIcon;
FilePrintIcon.addFile(":/resources/file_print.png");
FilePrintIcon.addFile(":/resources/file_print_16.png");
mActions[LC_FILE_PRINT]->setIcon(FilePrintIcon);
QIcon FilePrintPreviewIcon;
FilePrintPreviewIcon.addFile(":/resources/file_print_preview.png");
FilePrintPreviewIcon.addFile(":/resources/file_print_preview_16.png");
mActions[LC_FILE_PRINT_PREVIEW]->setIcon(FilePrintPreviewIcon);
QIcon EditUndoIcon;
EditUndoIcon.addFile(":/resources/edit_undo.png");
EditUndoIcon.addFile(":/resources/edit_undo_16.png");
mActions[LC_EDIT_UNDO]->setIcon(EditUndoIcon);
QIcon EditRedoIcon;
EditRedoIcon.addFile(":/resources/edit_redo.png");
EditRedoIcon.addFile(":/resources/edit_redo_16.png");
mActions[LC_EDIT_REDO]->setIcon(EditRedoIcon);
QIcon EditCutIcon;
EditCutIcon.addFile(":/resources/edit_cut.png");
EditCutIcon.addFile(":/resources/edit_cut_16.png");
mActions[LC_EDIT_CUT]->setIcon(EditCutIcon);
QIcon EditCopyIcon;
EditCopyIcon.addFile(":/resources/edit_copy.png");
EditCopyIcon.addFile(":/resources/edit_copy_16.png");
mActions[LC_EDIT_COPY]->setIcon(EditCopyIcon);
QIcon EditPasteIcon;
EditPasteIcon.addFile(":/resources/edit_paste.png");
EditPasteIcon.addFile(":/resources/edit_paste_16.png");
mActions[LC_EDIT_PASTE]->setIcon(EditPasteIcon);
QIcon EditActionInsertIcon;
EditActionInsertIcon.addFile(":/resources/action_insert.png");
EditActionInsertIcon.addFile(":/resources/action_insert_16.png");
mActions[LC_EDIT_ACTION_INSERT]->setIcon(EditActionInsertIcon);
QIcon EditActionLightIcon;
EditActionLightIcon.addFile(":/resources/action_light.png");
EditActionLightIcon.addFile(":/resources/action_light_16.png");
mActions[LC_EDIT_ACTION_POINT_LIGHT]->setIcon(EditActionLightIcon);
QIcon EditActionSpotLightIcon;
EditActionSpotLightIcon.addFile(":/resources/action_spotlight.png");
EditActionSpotLightIcon.addFile(":/resources/action_spotlight_16.png");
mActions[LC_EDIT_ACTION_SPOTLIGHT]->setIcon(EditActionSpotLightIcon);
QIcon EditActionSunlightIcon;
EditActionSunlightIcon.addFile(":/resources/action_sunlight.png");
EditActionSunlightIcon.addFile(":/resources/action_sunlight_16.png");
mActions[LC_EDIT_ACTION_DIRECTIONAL_LIGHT]->setIcon(EditActionSunlightIcon);
QIcon EditActionArealightIcon;
EditActionArealightIcon.addFile(":/resources/action_arealight.png");
EditActionArealightIcon.addFile(":/resources/action_arealight_16.png");
mActions[LC_EDIT_ACTION_AREA_LIGHT]->setIcon(EditActionArealightIcon);
QIcon EditActionSelectIcon;
EditActionSelectIcon.addFile(":/resources/action_select.png");
EditActionSelectIcon.addFile(":/resources/action_select_16.png");
mActions[LC_EDIT_ACTION_SELECT]->setIcon(EditActionSelectIcon);
QIcon EditActionMoveIcon;
EditActionMoveIcon.addFile(":/resources/action_move.png");
EditActionMoveIcon.addFile(":/resources/action_move_16.png");
mActions[LC_EDIT_ACTION_MOVE]->setIcon(EditActionMoveIcon);
QIcon EditActionRotateIcon;
EditActionRotateIcon.addFile(":/resources/action_rotate.png");
EditActionRotateIcon.addFile(":/resources/action_rotate_16.png");
mActions[LC_EDIT_ACTION_ROTATE]->setIcon(EditActionRotateIcon);
QIcon EditActionDeleteIcon;
EditActionDeleteIcon.addFile(":/resources/action_delete.png");
EditActionDeleteIcon.addFile(":/resources/action_delete_16.png");
mActions[LC_EDIT_ACTION_DELETE]->setIcon(EditActionDeleteIcon);
QIcon EditActionPaintIcon;
EditActionPaintIcon.addFile(":/resources/action_paint.png");
EditActionPaintIcon.addFile(":/resources/action_paint_16.png");
mActions[LC_EDIT_ACTION_PAINT]->setIcon(EditActionPaintIcon);
QIcon EditActionColorPickerIcon;
EditActionColorPickerIcon.addFile(":/resources/action_color_picker.png");
EditActionColorPickerIcon.addFile(":/resources/action_color_picker_16.png");
mActions[LC_EDIT_ACTION_COLOR_PICKER]->setIcon(EditActionColorPickerIcon);
QIcon EditActionZoomIcon;
EditActionZoomIcon.addFile(":/resources/action_zoom.png");
EditActionZoomIcon.addFile(":/resources/action_zoom_16.png");
mActions[LC_EDIT_ACTION_ZOOM]->setIcon(EditActionZoomIcon);
QIcon EditActionPanIcon;
EditActionPanIcon.addFile(":/resources/action_pan.png");
EditActionPanIcon.addFile(":/resources/action_pan_16.png");
mActions[LC_EDIT_ACTION_PAN]->setIcon(EditActionPanIcon);
QIcon FileRenderPOVRayIcon;
FileRenderPOVRayIcon.addFile(":/resources/file_render_povray.png");
FileRenderPOVRayIcon.addFile(":/resources/file_render_povray_16.png");
mActions[LC_FILE_RENDER_POVRAY]->setIcon(FileRenderPOVRayIcon);
QIcon FileRenderBlenderIcon;
FileRenderBlenderIcon.addFile(":/resources/file_render_blender.png");
FileRenderBlenderIcon.addFile(":/resources/file_render_blender_16.png");
mActions[LC_FILE_RENDER_BLENDER]->setIcon(FileRenderBlenderIcon);
QIcon FileOpenInBlenderIcon;
FileOpenInBlenderIcon.addFile(":/resources/file_render_open_in_blender.png");
FileOpenInBlenderIcon.addFile(":/resources/file_render_open_in_blender_16.png");
mActions[LC_FILE_RENDER_OPEN_IN_BLENDER]->setIcon(FileOpenInBlenderIcon);
mActions[LC_EDIT_ACTION_CAMERA]->setIcon(QIcon(":/resources/action_camera.png"));
mActions[LC_EDIT_ACTION_ROTATE_VIEW]->setIcon(QIcon(":/resources/action_rotate_view.png"));
mActions[LC_EDIT_ACTION_ROLL]->setIcon(QIcon(":/resources/action_roll.png"));
mActions[LC_EDIT_ACTION_ZOOM_REGION]->setIcon(QIcon(":/resources/action_zoom_region.png"));
mActions[LC_EDIT_FIND]->setIcon(QIcon(":/resources/edit_find.png"));
mActions[LC_EDIT_FIND_NEXT]->setIcon(QIcon(":/resources/edit_find_next.png"));
mActions[LC_EDIT_FIND_PREVIOUS]->setIcon(QIcon(":/resources/edit_find_previous.png"));
mActions[LC_EDIT_FIND_ALL]->setIcon(QIcon(":/resources/edit_find_all.png"));
mActions[LC_EDIT_REPLACE_NEXT]->setIcon(QIcon(":/resources/edit_replace_next.png"));
mActions[LC_EDIT_REPLACE_ALL]->setIcon(QIcon(":/resources/edit_replace_all.png"));
mActions[LC_PIECE_SHOW_EARLIER]->setIcon(QIcon(":/resources/piece_show_earlier.png"));
mActions[LC_PIECE_SHOW_LATER]->setIcon(QIcon(":/resources/piece_show_later.png"));
mActions[LC_VIEW_SPLIT_HORIZONTAL]->setIcon(QIcon(":/resources/view_split_horizontal.png"));
mActions[LC_VIEW_SPLIT_VERTICAL]->setIcon(QIcon(":/resources/view_split_vertical.png"));
mActions[LC_VIEW_ZOOM_IN]->setIcon(QIcon(":/resources/view_zoomin.png"));
mActions[LC_VIEW_ZOOM_OUT]->setIcon(QIcon(":/resources/view_zoomout.png"));
mActions[LC_VIEW_ZOOM_EXTENTS]->setIcon(QIcon(":/resources/view_zoomextents.png"));
mActions[LC_VIEW_TIME_FIRST]->setIcon(QIcon(":/resources/time_first.png"));
mActions[LC_VIEW_TIME_PREVIOUS]->setIcon(QIcon(":/resources/time_previous.png"));
mActions[LC_VIEW_TIME_NEXT]->setIcon(QIcon(":/resources/time_next.png"));
mActions[LC_VIEW_TIME_LAST]->setIcon(QIcon(":/resources/time_last.png"));
mActions[LC_VIEW_TIME_ADD_KEYS]->setIcon(QIcon(":/resources/time_add_keys.png"));
mActions[LC_HELP_HOMEPAGE]->setIcon(QIcon(":/resources/help_homepage.png"));
mActions[LC_EDIT_SNAP_MOVE_TOGGLE]->setCheckable(true);
mActions[LC_EDIT_SNAP_ANGLE_TOGGLE]->setCheckable(true);
mActions[LC_VIEW_CAMERA_NONE]->setCheckable(true);
mActions[LC_VIEW_TIME_ADD_KEYS]->setCheckable(true);
for (int ActionIndex = LC_VIEW_TOOLBAR_FIRST; ActionIndex <= LC_VIEW_TOOLBAR_LAST; ActionIndex++)
mActions[ActionIndex]->setCheckable(true);
QActionGroup* ActionRelativeGroup = new QActionGroup(this);
for (int ActionIdx = LC_EDIT_TRANSFORM_RELATIVE; ActionIdx <= LC_EDIT_TRANSFORM_ABSOLUTE; ActionIdx++)
{
mActions[ActionIdx]->setCheckable(true);
ActionRelativeGroup->addAction(mActions[ActionIdx]);
}
QActionGroup* ActionSeparateGroup = new QActionGroup(this);
for (int ActionIdx = LC_EDIT_TRANSFORM_SEPARATELY; ActionIdx <= LC_EDIT_TRANSFORM_TOGETHER; ActionIdx++)
{
mActions[ActionIdx]->setCheckable(true);
ActionSeparateGroup->addAction(mActions[ActionIdx]);
}
QActionGroup* ActionSnapXYGroup = new QActionGroup(this);
for (int ActionIdx = LC_EDIT_SNAP_MOVE_XY0; ActionIdx <= LC_EDIT_SNAP_MOVE_XY9; ActionIdx++)
{
mActions[ActionIdx]->setCheckable(true);
ActionSnapXYGroup->addAction(mActions[ActionIdx]);
}
QActionGroup* ActionSnapZGroup = new QActionGroup(this);
for (int ActionIdx = LC_EDIT_SNAP_MOVE_Z0; ActionIdx <= LC_EDIT_SNAP_MOVE_Z9; ActionIdx++)
{
mActions[ActionIdx]->setCheckable(true);
ActionSnapZGroup->addAction(mActions[ActionIdx]);
}
QActionGroup* ActionSnapAngleGroup = new QActionGroup(this);
for (int ActionIdx = LC_EDIT_SNAP_ANGLE0; ActionIdx <= LC_EDIT_SNAP_ANGLE9; ActionIdx++)
{
mActions[ActionIdx]->setCheckable(true);
ActionSnapAngleGroup->addAction(mActions[ActionIdx]);
}
QActionGroup* ActionTransformTypeGroup = new QActionGroup(this);
for (int ActionIdx = LC_EDIT_TRANSFORM_ABSOLUTE_TRANSLATION; ActionIdx <= LC_EDIT_TRANSFORM_RELATIVE_ROTATION; ActionIdx++)
{
mActions[ActionIdx]->setCheckable(true);
ActionTransformTypeGroup->addAction(mActions[ActionIdx]);
}
QActionGroup* ActionToolGroup = new QActionGroup(this);
for (int ActionIdx = LC_EDIT_ACTION_FIRST; ActionIdx <= LC_EDIT_ACTION_LAST; ActionIdx++)
{
mActions[ActionIdx]->setCheckable(true);
ActionToolGroup->addAction(mActions[ActionIdx]);
}
QActionGroup* ActionCameraGroup = new QActionGroup(this);
ActionCameraGroup->addAction(mActions[LC_VIEW_CAMERA_NONE]);
for (int ActionIdx = LC_VIEW_CAMERA_FIRST; ActionIdx <= LC_VIEW_CAMERA_LAST; ActionIdx++)
{
mActions[ActionIdx]->setCheckable(true);
ActionCameraGroup->addAction(mActions[ActionIdx]);
}
QActionGroup* ActionPerspectiveGroup = new QActionGroup(this);
for (int ActionIdx = LC_VIEW_PROJECTION_FIRST; ActionIdx <= LC_VIEW_PROJECTION_LAST; ActionIdx++)
{
mActions[ActionIdx]->setCheckable(true);
ActionPerspectiveGroup->addAction(mActions[ActionIdx]);
}
QActionGroup* ActionShadingGroup = new QActionGroup(this);
for (int ActionIdx = LC_VIEW_SHADING_FIRST; ActionIdx <= LC_VIEW_SHADING_LAST; ActionIdx++)
{
mActions[ActionIdx]->setCheckable(true);
ActionShadingGroup->addAction(mActions[ActionIdx]);
}
QActionGroup* SelectionModeGroup = new QActionGroup(this);
for (int ActionIdx = LC_EDIT_SELECTION_MODE_FIRST; ActionIdx <= LC_EDIT_SELECTION_MODE_LAST; ActionIdx++)
{
mActions[ActionIdx]->setCheckable(true);
SelectionModeGroup->addAction(mActions[ActionIdx]);
}
QActionGroup* ModelGroup = new QActionGroup(this);
for (int ActionIdx = LC_MODEL_FIRST; ActionIdx <= LC_MODEL_LAST; ActionIdx++)
{
mActions[ActionIdx]->setCheckable(true);
ModelGroup->addAction(mActions[ActionIdx]);
}
UpdateShortcuts();
}
void lcMainWindow::CreateMenus()
{
QMenu* TransformMenu = new QMenu(tr("Transform"), this);
TransformMenu->addAction(mActions[LC_EDIT_TRANSFORM_RELATIVE_TRANSLATION]);
TransformMenu->addAction(mActions[LC_EDIT_TRANSFORM_ABSOLUTE_TRANSLATION]);
TransformMenu->addAction(mActions[LC_EDIT_TRANSFORM_RELATIVE_ROTATION]);
TransformMenu->addAction(mActions[LC_EDIT_TRANSFORM_ABSOLUTE_ROTATION]);
mActions[LC_EDIT_TRANSFORM]->setMenu(TransformMenu);
mCameraMenu = new QMenu(tr("C&ameras"), this);
mCameraMenu->addAction(mActions[LC_VIEW_CAMERA_NONE]);
for (int actionIdx = LC_VIEW_CAMERA_FIRST; actionIdx <= LC_VIEW_CAMERA_LAST; actionIdx++)
mCameraMenu->addAction(mActions[actionIdx]);
connect(mCameraMenu, &QMenu::aboutToShow, this, &lcMainWindow::CameraMenuAboutToShow);
mViewpointMenu = new QMenu(tr("&Viewpoints"), this);
mViewpointMenu->addAction(mActions[LC_VIEW_VIEWPOINT_FRONT]);
mViewpointMenu->addAction(mActions[LC_VIEW_VIEWPOINT_BACK]);
mViewpointMenu->addAction(mActions[LC_VIEW_VIEWPOINT_LEFT]);
mViewpointMenu->addAction(mActions[LC_VIEW_VIEWPOINT_RIGHT]);
mViewpointMenu->addAction(mActions[LC_VIEW_VIEWPOINT_TOP]);
mViewpointMenu->addAction(mActions[LC_VIEW_VIEWPOINT_BOTTOM]);
mViewpointMenu->addAction(mActions[LC_VIEW_VIEWPOINT_HOME]);
mProjectionMenu = new QMenu(tr("Projection"), this);
mProjectionMenu->addAction(mActions[LC_VIEW_PROJECTION_PERSPECTIVE]);
mProjectionMenu->addAction(mActions[LC_VIEW_PROJECTION_ORTHO]);
connect(mProjectionMenu, &QMenu::aboutToShow, this, &lcMainWindow::ProjectionMenuAboutToShow);
mShadingMenu = new QMenu(tr("Sh&ading"), this);
mShadingMenu->addAction(mActions[LC_VIEW_SHADING_WIREFRAME]);
mShadingMenu->addAction(mActions[LC_VIEW_SHADING_FLAT]);
mShadingMenu->addAction(mActions[LC_VIEW_SHADING_DEFAULT_LIGHTS]);
mToolsMenu = new QMenu(tr("Tools"), this);
mToolsMenu->addAction(mActions[LC_EDIT_ACTION_INSERT]);
mToolsMenu->addAction(mActions[LC_EDIT_ACTION_POINT_LIGHT]);
mToolsMenu->addAction(mActions[LC_EDIT_ACTION_SPOTLIGHT]);
mToolsMenu->addAction(mActions[LC_EDIT_ACTION_DIRECTIONAL_LIGHT]);
mToolsMenu->addAction(mActions[LC_EDIT_ACTION_AREA_LIGHT]);
mToolsMenu->addAction(mActions[LC_EDIT_ACTION_CAMERA]);
mToolsMenu->addSeparator();
mToolsMenu->addAction(mActions[LC_EDIT_ACTION_SELECT]);
mToolsMenu->addAction(mActions[LC_EDIT_ACTION_MOVE]);
mToolsMenu->addAction(mActions[LC_EDIT_ACTION_ROTATE]);
mToolsMenu->addAction(mActions[LC_EDIT_ACTION_DELETE]);
mToolsMenu->addAction(mActions[LC_EDIT_ACTION_PAINT]);
mToolsMenu->addAction(mActions[LC_EDIT_ACTION_COLOR_PICKER]);
mToolsMenu->addSeparator();
mToolsMenu->addAction(mActions[LC_EDIT_ACTION_ZOOM]);
mToolsMenu->addAction(mActions[LC_EDIT_ACTION_PAN]);
mToolsMenu->addAction(mActions[LC_EDIT_ACTION_ROTATE_VIEW]);
mToolsMenu->addAction(mActions[LC_EDIT_ACTION_ROLL]);
mToolsMenu->addAction(mActions[LC_EDIT_ACTION_ZOOM_REGION]);
QMenu* FileMenu = menuBar()->addMenu(tr("&File"));
connect(FileMenu, &QMenu::aboutToShow, this, &lcMainWindow::FileMenuAboutToShow);
FileMenu->addAction(mActions[LC_FILE_NEW]);
FileMenu->addAction(mActions[LC_FILE_OPEN]);
FileMenu->addAction(mActions[LC_FILE_MERGE]);
FileMenu->addSeparator();
FileMenu->addAction(mActions[LC_FILE_SAVE]);
FileMenu->addAction(mActions[LC_FILE_SAVEAS]);
FileMenu->addAction(mActions[LC_FILE_SAVE_IMAGE]);
QMenu* ImportMenu = FileMenu->addMenu(tr("&Import"));
ImportMenu->addAction(mActions[LC_FILE_IMPORT_LDD]);
ImportMenu->addAction(mActions[LC_FILE_IMPORT_INVENTORY]);
QMenu* ExportMenu = FileMenu->addMenu(tr("&Export"));
ExportMenu->addAction(mActions[LC_FILE_EXPORT_3DS]);
ExportMenu->addAction(mActions[LC_FILE_EXPORT_BRICKLINK]);
ExportMenu->addAction(mActions[LC_FILE_EXPORT_COLLADA]);
ExportMenu->addAction(mActions[LC_FILE_EXPORT_CSV]);
ExportMenu->addAction(mActions[LC_FILE_EXPORT_HTML]);
ExportMenu->addAction(mActions[LC_FILE_EXPORT_POVRAY]);
ExportMenu->addAction(mActions[LC_FILE_EXPORT_WAVEFRONT]);
FileMenu->addSeparator();
#ifndef LC_DISABLE_RENDER_DIALOG
QMenu* RenderMenu = FileMenu->addMenu(tr("&Render"));
RenderMenu->addAction(mActions[LC_FILE_RENDER_POVRAY]);
RenderMenu->addAction(mActions[LC_FILE_RENDER_BLENDER]);
RenderMenu->addAction(mActions[LC_FILE_RENDER_OPEN_IN_BLENDER]);
#endif
FileMenu->addAction(mActions[LC_FILE_INSTRUCTIONS]);
FileMenu->addAction(mActions[LC_FILE_PRINT]);
FileMenu->addAction(mActions[LC_FILE_PRINT_PREVIEW]);
FileMenu->addSeparator();
FileMenu->addAction(mActions[LC_FILE_RECENT1]);
FileMenu->addAction(mActions[LC_FILE_RECENT2]);
FileMenu->addAction(mActions[LC_FILE_RECENT3]);
FileMenu->addAction(mActions[LC_FILE_RECENT4]);
mActionFileRecentSeparator = FileMenu->addSeparator();
FileMenu->addAction(mActions[LC_FILE_EXIT]);
QMenu* EditMenu = menuBar()->addMenu(tr("&Edit"));
EditMenu->addAction(mActions[LC_EDIT_UNDO]);
EditMenu->addAction(mActions[LC_EDIT_REDO]);
EditMenu->addSeparator();
EditMenu->addAction(mActions[LC_EDIT_CUT]);
EditMenu->addAction(mActions[LC_EDIT_COPY]);
EditMenu->addAction(mActions[LC_EDIT_PASTE]);
EditMenu->addAction(mActions[LC_EDIT_PASTE_STEPS]);
EditMenu->addSeparator();
EditMenu->addAction(mActions[LC_EDIT_FIND]);
EditMenu->addAction(mActions[LC_EDIT_FIND_NEXT]);
EditMenu->addAction(mActions[LC_EDIT_FIND_PREVIOUS]);
EditMenu->addAction(mActions[LC_EDIT_REPLACE]);
EditMenu->addAction(mActions[LC_EDIT_REPLACE_NEXT]);
EditMenu->addSeparator();
EditMenu->addAction(mActions[LC_EDIT_SELECT_ALL]);
EditMenu->addAction(mActions[LC_EDIT_SELECT_NONE]);
EditMenu->addAction(mActions[LC_EDIT_SELECT_INVERT]);
EditMenu->addAction(mActions[LC_EDIT_SELECT_BY_NAME]);
EditMenu->addMenu(mSelectionModeMenu);
EditMenu->addSeparator();
EditMenu->addMenu(mTransformMenu);
EditMenu->addMenu(mToolsMenu);
QMenu* ViewMenu = menuBar()->addMenu(tr("&View"));
ViewMenu->addAction(mActions[LC_VIEW_PREFERENCES]);
ViewMenu->addSeparator();
ViewMenu->addAction(mActions[LC_VIEW_ZOOM_EXTENTS]);
ViewMenu->addAction(mActions[LC_VIEW_LOOK_AT]);
ViewMenu->addMenu(mViewpointMenu);
ViewMenu->addMenu(mCameraMenu);
ViewMenu->addMenu(mProjectionMenu);
ViewMenu->addMenu(mShadingMenu);
QMenu* StepMenu = ViewMenu->addMenu(tr("Ste&p"));
StepMenu->addAction(mActions[LC_VIEW_TIME_FIRST]);
StepMenu->addAction(mActions[LC_VIEW_TIME_PREVIOUS]);
StepMenu->addAction(mActions[LC_VIEW_TIME_NEXT]);
StepMenu->addAction(mActions[LC_VIEW_TIME_LAST]);
StepMenu->addSeparator();
StepMenu->addAction(mActions[LC_VIEW_TIME_INSERT_BEFORE]);
StepMenu->addAction(mActions[LC_VIEW_TIME_INSERT_AFTER]);
StepMenu->addAction(mActions[LC_VIEW_TIME_DELETE]);
ViewMenu->addSeparator();
ViewMenu->addAction(mActions[LC_VIEW_SPLIT_HORIZONTAL]);
ViewMenu->addAction(mActions[LC_VIEW_SPLIT_VERTICAL]);
ViewMenu->addAction(mActions[LC_VIEW_REMOVE_VIEW]);
ViewMenu->addAction(mActions[LC_VIEW_RESET_VIEWS]);
ViewMenu->addSeparator();
QMenu* ToolBarsMenu = ViewMenu->addMenu(tr("T&oolbars"));
connect(ToolBarsMenu, &QMenu::aboutToShow, this, &lcMainWindow::UpdateDockWidgetActions);
ToolBarsMenu->addAction(mActions[LC_VIEW_TOOLBAR_PARTS]);
ToolBarsMenu->addAction(mActions[LC_VIEW_TOOLBAR_COLORS]);
ToolBarsMenu->addAction(mActions[LC_VIEW_TOOLBAR_PROPERTIES]);
ToolBarsMenu->addAction(mActions[LC_VIEW_TOOLBAR_TIMELINE]);
ToolBarsMenu->addAction(mActions[LC_VIEW_TOOLBAR_PREVIEW]);
ToolBarsMenu->addSeparator();
ToolBarsMenu->addAction(mActions[LC_VIEW_TOOLBAR_STANDARD]);
ToolBarsMenu->addAction(mActions[LC_VIEW_TOOLBAR_TOOLS]);
ToolBarsMenu->addAction(mActions[LC_VIEW_TOOLBAR_TIME]);
ViewMenu->addAction(mActions[LC_VIEW_FULLSCREEN]);
QMenu* PieceMenu = menuBar()->addMenu(tr("&Piece"));
PieceMenu->addAction(mActions[LC_PIECE_INSERT]);
PieceMenu->addAction(mActions[LC_PIECE_DELETE]);
PieceMenu->addAction(mActions[LC_PIECE_DUPLICATE]);
PieceMenu->addAction(mActions[LC_PIECE_PAINT_SELECTED]);
PieceMenu->addAction(mActions[LC_PIECE_ARRAY]);
PieceMenu->addAction(mActions[LC_PIECE_MINIFIG_WIZARD]);
PieceMenu->addAction(mActions[LC_PIECE_RESET_PIVOT_POINT]);
PieceMenu->addAction(mActions[LC_PIECE_REMOVE_KEY_FRAMES]);
PieceMenu->addSeparator();
PieceMenu->addAction(mActions[LC_PIECE_EDIT_SELECTED_SUBMODEL]);
PieceMenu->addAction(mActions[LC_PIECE_EDIT_END_SUBMODEL]);
PieceMenu->addAction(mActions[LC_PIECE_VIEW_SELECTED_MODEL]);
PieceMenu->addAction(mActions[LC_PIECE_INLINE_SELECTED_MODELS]);
PieceMenu->addAction(mActions[LC_PIECE_MOVE_SELECTION_TO_MODEL]);
PieceMenu->addSeparator();
PieceMenu->addAction(mActions[LC_PIECE_GROUP]);
PieceMenu->addAction(mActions[LC_PIECE_UNGROUP]);
PieceMenu->addAction(mActions[LC_PIECE_GROUP_REMOVE]);
PieceMenu->addAction(mActions[LC_PIECE_GROUP_ADD]);
PieceMenu->addAction(mActions[LC_PIECE_GROUP_EDIT]);
PieceMenu->addSeparator();
PieceMenu->addAction(mActions[LC_PIECE_HIDE_SELECTED]);
PieceMenu->addAction(mActions[LC_PIECE_HIDE_UNSELECTED]);
PieceMenu->addAction(mActions[LC_PIECE_UNHIDE_SELECTED]);
PieceMenu->addAction(mActions[LC_PIECE_UNHIDE_ALL]);
QMenu* ModelMenu = menuBar()->addMenu(tr("Sub&model"));
ModelMenu->addAction(mActions[LC_MODEL_PROPERTIES]);
ModelMenu->addAction(mActions[LC_MODEL_NEW]);
ModelMenu->addAction(mActions[LC_MODEL_LIST]);
ModelMenu->addSeparator();
for (int ModelIdx = LC_MODEL_FIRST; ModelIdx <= LC_MODEL_LAST; ModelIdx++)
ModelMenu->addAction(mActions[ModelIdx]);
QMenu* HelpMenu = menuBar()->addMenu(tr("&Help"));
HelpMenu->addAction(mActions[LC_HELP_WHATS_THIS]);
HelpMenu->addAction(mActions[LC_HELP_HOMEPAGE]);
HelpMenu->addAction(mActions[LC_HELP_BUG_REPORT]);
#if !LC_DISABLE_UPDATE_CHECK
HelpMenu->addAction(mActions[LC_HELP_UPDATES]);
#endif
#ifndef Q_OS_MACOS
HelpMenu->addSeparator();
#endif
HelpMenu->addAction(mActions[LC_HELP_ABOUT]);
}
void lcMainWindow::CreateToolBars()
{
mSelectionModeMenu = new QMenu(tr("Selection Mode"), this);
for (int ModeIdx = LC_EDIT_SELECTION_MODE_FIRST; ModeIdx <= LC_EDIT_SELECTION_MODE_LAST; ModeIdx++)
mSelectionModeMenu->addAction(mActions[ModeIdx]);
QAction* SelectionModeAction = new QAction(tr("Selection Mode"), this);
SelectionModeAction->setStatusTip(tr("Change selection mode"));
SelectionModeAction->setToolTip(tr("Choose which related pieces are included when selecting a piece."));
SelectionModeAction->setWhatsThis(tr("<p><b>Selection Mode</b></p><p>Choose the rule applied when you pick a piece in the model view. Single selects that piece; the other modes include matching piece types, matching colors, or both. For example, color selection lets you pick matching red pieces without selecting each one separately.</p>"));
SelectionModeAction->setIcon(QIcon(":/resources/action_select.png"));
SelectionModeAction->setMenu(mSelectionModeMenu);
mTransformMenu = new QMenu(tr("Transform"), this);
mTransformMenu->addAction(mActions[LC_EDIT_TRANSFORM_RELATIVE]);
mTransformMenu->addAction(mActions[LC_EDIT_TRANSFORM_ABSOLUTE]);
mTransformMenu->addSeparator();
mTransformMenu->addAction(mActions[LC_EDIT_TRANSFORM_TOGETHER]);
mTransformMenu->addAction(mActions[LC_EDIT_TRANSFORM_SEPARATELY]);
QAction* TransformAction = new QAction(tr("Transform"), this);
TransformAction->setStatusTip(tr("Transform Options"));
TransformAction->setToolTip(tr("Choose coordinate axes and whether selected pieces rotate together."));
TransformAction->setWhatsThis(tr("<p><b>Transform Options</b></p><p>Choose the axes and pivot used for interactive transforms. Relative Transforms uses the focused object's orientation, so movement along X follows that object's local X axis. Absolute Transforms uses the model axes. Rotate Together rotates the selection around a shared pivot; Rotate Separately rotates each piece around its own origin.</p>"));
TransformAction->setIcon(QIcon(":/resources/edit_transform_relative.png"));
TransformAction->setMenu(mTransformMenu);
QMenu* SnapXYMenu = new QMenu(tr("Snap XY"), this);
for (int actionIdx = LC_EDIT_SNAP_MOVE_XY0; actionIdx <= LC_EDIT_SNAP_MOVE_XY9; actionIdx++)
SnapXYMenu->addAction(mActions[actionIdx]);
QMenu* SnapZMenu = new QMenu(tr("Snap Z"), this);
for (int actionIdx = LC_EDIT_SNAP_MOVE_Z0; actionIdx <= LC_EDIT_SNAP_MOVE_Z9; actionIdx++)
SnapZMenu->addAction(mActions[actionIdx]);
QMenu* SnapMenu = new QMenu(tr("Snap Menu"), this);
SnapMenu->addAction(mActions[LC_EDIT_SNAP_MOVE_TOGGLE]);
SnapMenu->addSeparator();
SnapMenu->addMenu(SnapXYMenu);
SnapMenu->addMenu(SnapZMenu);
QAction* MoveAction = new QAction(tr("Movement Snap"), this);
MoveAction->setStatusTip(tr("Snap translations to fixed intervals"));
MoveAction->setToolTip(tr("Choose movement snapping intervals for XY and Z."));
MoveAction->setWhatsThis(tr("<p><b>Movement Snap</b></p><p>Choose how far objects move in each snapped increment. XY controls movement across the base plane; Z controls vertical movement, so they can use different intervals. Turn snapping off for free placement, then enable it again when you need consistent spacing.</p>"));
MoveAction->setIcon(QIcon(":/resources/edit_snap_move.png"));
MoveAction->setMenu(SnapMenu);
QMenu* SnapAngleMenu = new QMenu(tr("Snap Angle Menu"), this);
SnapAngleMenu->addAction(mActions[LC_EDIT_SNAP_ANGLE_TOGGLE]);
SnapAngleMenu->addSeparator();
for (int actionIdx = LC_EDIT_SNAP_ANGLE0; actionIdx <= LC_EDIT_SNAP_ANGLE9; actionIdx++)
SnapAngleMenu->addAction(mActions[actionIdx]);
QAction* AngleAction = new QAction(tr("Rotation Snap"), this);
AngleAction->setStatusTip(tr("Snap rotations to fixed intervals"));
AngleAction->setToolTip(tr("Choose the rotation snapping interval."));
AngleAction->setWhatsThis(tr("<p><b>Rotation Snap</b></p><p>Choose an angle increment for interactive rotation. For example, a 90-degree increment is useful for quarter turns, while smaller increments allow finer alignment. Turn snapping off for free rotation without fixed angle increments.</p>"));
AngleAction->setIcon(QIcon(":/resources/edit_snap_angle.png"));
AngleAction->setMenu(SnapAngleMenu);
mStandardToolBar = addToolBar(tr("Standard"));
mStandardToolBar->setObjectName("StandardToolbar");
mStandardToolBar->setWhatsThis(tr("<p><b>Standard Toolbar</b></p><p>Use file controls to create, open, and save models, and Undo or Redo to navigate edit history. Before moving or rotating objects, choose the selection rule, coordinate reference, and snapping increments from the four drop-down controls. Help > What's This? explains individual controls.</p>"));
mStandardToolBar->addAction(mActions[LC_FILE_NEW]);
mStandardToolBar->addAction(mActions[LC_FILE_OPEN]);
mStandardToolBar->addAction(mActions[LC_FILE_SAVE]);
mStandardToolBar->addSeparator();
mStandardToolBar->addAction(mActions[LC_EDIT_UNDO]);
mStandardToolBar->addAction(mActions[LC_EDIT_REDO]);
mStandardToolBar->addSeparator();
mStandardToolBar->addAction(SelectionModeAction);
mStandardToolBar->addAction(TransformAction);
mStandardToolBar->addAction(MoveAction);
mStandardToolBar->addAction(AngleAction);
((QToolButton*)mStandardToolBar->widgetForAction(SelectionModeAction))->setPopupMode(QToolButton::InstantPopup);
((QToolButton*)mStandardToolBar->widgetForAction(TransformAction))->setPopupMode(QToolButton::InstantPopup);
((QToolButton*)mStandardToolBar->widgetForAction(MoveAction))->setPopupMode(QToolButton::InstantPopup);
((QToolButton*)mStandardToolBar->widgetForAction(AngleAction))->setPopupMode(QToolButton::InstantPopup);
mTimeToolBar = addToolBar(tr("Time"));
mTimeToolBar->setObjectName("TimeToolbar");
mTimeToolBar->setWhatsThis(tr("<p><b>Time Toolbar</b></p><p>The arrow buttons move through building steps so you can inspect how the model is assembled. They do not change the step assigned to a piece; use the Timeline for that. Add Keys controls whether edits create animation keys at the current step, allowing properties such as position to vary between steps.</p>"));
mTimeToolBar->addAction(mActions[LC_VIEW_TIME_FIRST]);
mTimeToolBar->addAction(mActions[LC_VIEW_TIME_PREVIOUS]);
mTimeToolBar->addAction(mActions[LC_VIEW_TIME_NEXT]);
mTimeToolBar->addAction(mActions[LC_VIEW_TIME_LAST]);
mTimeToolBar->addAction(mActions[LC_VIEW_TIME_ADD_KEYS]);
mToolsToolBar = addToolBar(tr("Tools"));
mToolsToolBar->setObjectName("ToolsToolbar");
mToolsToolBar->setWhatsThis(tr("<p><b>Tools Toolbar</b></p><p>Choose a tool, then use it in the model view. Insertion tools create pieces, lights, or cameras. Editing tools select, transform, remove, or recolor objects. Navigation tools change the viewpoint without changing model geometry. Mouse assignments can be customized in Preferences.</p>"));
insertToolBarBreak(mToolsToolBar);
mToolsToolBar->addAction(mActions[LC_EDIT_ACTION_INSERT]);
mToolsToolBar->addAction(mActions[LC_EDIT_ACTION_POINT_LIGHT]);
mToolsToolBar->addAction(mActions[LC_EDIT_ACTION_SPOTLIGHT]);
mToolsToolBar->addAction(mActions[LC_EDIT_ACTION_DIRECTIONAL_LIGHT]);
mToolsToolBar->addAction(mActions[LC_EDIT_ACTION_AREA_LIGHT]);
mToolsToolBar->addAction(mActions[LC_EDIT_ACTION_CAMERA]);
mToolsToolBar->addSeparator();
mToolsToolBar->addAction(mActions[LC_EDIT_ACTION_SELECT]);
mToolsToolBar->addAction(mActions[LC_EDIT_ACTION_MOVE]);
mToolsToolBar->addAction(mActions[LC_EDIT_ACTION_ROTATE]);
mToolsToolBar->addAction(mActions[LC_EDIT_ACTION_DELETE]);
mToolsToolBar->addAction(mActions[LC_EDIT_ACTION_PAINT]);
mToolsToolBar->addAction(mActions[LC_EDIT_ACTION_COLOR_PICKER]);
mToolsToolBar->addSeparator();
mToolsToolBar->addAction(mActions[LC_EDIT_ACTION_ZOOM]);
mToolsToolBar->addAction(mActions[LC_EDIT_ACTION_PAN]);
mToolsToolBar->addAction(mActions[LC_EDIT_ACTION_ROTATE_VIEW]);
mToolsToolBar->addAction(mActions[LC_EDIT_ACTION_ROLL]);
mToolsToolBar->addAction(mActions[LC_EDIT_ACTION_ZOOM_REGION]);
mToolsToolBar->hide();
for (QToolBar* ToolBar : { mStandardToolBar, mTimeToolBar, mToolsToolBar })
{
lcSetupWidgetHelp(ToolBar, nullptr);
for (QAction* Action : ToolBar->actions())
{
if (Action->isSeparator())
continue;
if (QWidget* Button = ToolBar->widgetForAction(Action))
{
Button->setWhatsThis(Action->whatsThis());
Button->setAccessibleName(Action->text().remove('&'));
}
}
}
mPartsToolBar = new QDockWidget(tr("Pieces"), this);
mPartsToolBar->setObjectName("PartsToolbar");
mPartsToolBar->setWhatsThis(tr("<p><b>Pieces</b></p><p>Choose a category or palette and filter its pieces. Selecting a piece prepares it for insertion; drag it into the model view to place it. Double-click a piece to open its preview. Options controls filtering, thumbnails, and list display.</p>"));
lcSetupWidgetHelp(mPartsToolBar, nullptr);
mPartSelectionWidget = new lcPartSelectionWidget(false, mPartsToolBar);
mPartsToolBar->setWidget(mPartSelectionWidget);
addDockWidget(Qt::RightDockWidgetArea, mPartsToolBar);
connect(mPartsToolBar, &QDockWidget::dockLocationChanged, mPartSelectionWidget, &lcPartSelectionWidget::DockLocationChanged);
connect(mPartSelectionWidget, &lcPartSelectionWidget::PartPicked, this, &lcMainWindow::PartListPicked);
connect(mPartSelectionWidget, &lcPartSelectionWidget::CurrentPartChanged, this, &lcMainWindow::SetInsertPieceData);
mColorsToolBar = new QDockWidget(tr("Colors"), this);
mColorsToolBar->setObjectName("ColorsToolbar");
mColorsToolBar->setWhatsThis(tr("<p><b>Colors</b></p><p>Choose the current LDraw color from the swatches. This color is used when inserting or painting pieces. To recolor selected pieces, use the color button above the swatches. Hover over a swatch for its name and color code.</p>"));
lcSetupWidgetHelp(mColorsToolBar, nullptr);
mColorsToolBar->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
mColorList = new lcColorList();
connect(mColorList, &lcColorList::ColorChanged, this, &lcMainWindow::ColorChanged);
QWidget* ColorWidget = new QWidget(mColorsToolBar);
QVBoxLayout* ColorLayout = new QVBoxLayout(ColorWidget);
ColorLayout->setContentsMargins(0, 0, 0, 0);
QHBoxLayout* ColorButtonLayout = new QHBoxLayout();
ColorButtonLayout->setContentsMargins(0, 0, 0, 0);
ColorLayout->addLayout(ColorButtonLayout);
mColorButton = new QToolButton(ColorWidget);
mColorButton->setAutoRaise(true);
mColorButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
mColorButton->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Maximum);
mColorButton->setToolTip(tr("Apply the current color to selected pieces."));
mColorButton->setAccessibleName(tr("Change Selection Color"));
mColorButton->setWhatsThis(tr("<p><b>Change Selection Color</b></p><p>Apply the current color to selected pieces. Choosing a swatch sets the current color; this button applies that color to the selection.</p>"));
ColorButtonLayout->addWidget(mColorButton);
connect(mColorButton, &QToolButton::clicked, this, &lcMainWindow::ColorButtonClicked);
ColorLayout->addWidget(mColorList);
mColorList->setAccessibleName(tr("LDraw Colors"));
mColorsToolBar->setWidget(ColorWidget);
addDockWidget(Qt::RightDockWidgetArea, mColorsToolBar);
mPropertiesToolBar = new QDockWidget(tr("Properties"), this);
mPropertiesToolBar->setObjectName("PropertiesToolbar");
mPropertiesToolBar->setWhatsThis(tr("<p><b>Properties</b></p><p>Edit properties of the focused object or selection. Available fields depend on whether you select pieces, a camera, or a light. Expand a section to see its fields. Keyframe controls mark properties at the current building step.</p><p>The transform fields at the bottom apply an X/Y/Z translation or rotation using the chosen transform mode. Press Enter to apply the values.</p>"));
lcSetupWidgetHelp(mPropertiesToolBar, nullptr);
QWidget* PropertiesWidget = new QWidget(mPropertiesToolBar);
QVBoxLayout* PropertiesLayout = new QVBoxLayout(PropertiesWidget);
PropertiesLayout->setContentsMargins(0, 0, 0, 0);
QScrollArea* PropertiesScrollArea = new QScrollArea(PropertiesWidget);
PropertiesScrollArea->setWidgetResizable(true);
PropertiesLayout->addWidget(PropertiesScrollArea);
mPropertiesWidget = new lcPropertiesWidget(PropertiesScrollArea);
PropertiesScrollArea->setWidget(mPropertiesWidget);
QHBoxLayout* TransformLayout = new QHBoxLayout;
QWidget* TransformWidget = new QWidget();
TransformWidget->setLayout(TransformLayout);
QToolButton* TransformButton = new QToolButton(TransformWidget);
TransformButton->setDefaultAction(mActions[LC_EDIT_TRANSFORM]);
TransformButton->setPopupMode(QToolButton::InstantPopup);
TransformButton->setToolTip(tr("Choose absolute or relative translation or rotation."));
TransformButton->setWhatsThis(tr("<p><b>Apply Transform</b></p><p>Choose the translation or rotation mode, enter X/Y/Z values, and press Enter to apply them. Translation values use LDraw units; rotation values use degrees.</p>"));
TransformLayout->addWidget(TransformButton);
mTransformXEdit = new lcTransformLineEdit();
mTransformXEdit->setAccessibleName(tr("Transform X"));
mTransformXEdit->setToolTip(tr("Enter the X translation in LDraw units or rotation in degrees."));
TransformLayout->addWidget(mTransformXEdit);
mTransformYEdit = new lcTransformLineEdit();
mTransformYEdit->setAccessibleName(tr("Transform Y"));
mTransformYEdit->setToolTip(tr("Enter the Y translation in LDraw units or rotation in degrees."));
TransformLayout->addWidget(mTransformYEdit);
mTransformZEdit = new lcTransformLineEdit();
mTransformZEdit->setAccessibleName(tr("Transform Z"));
mTransformZEdit->setToolTip(tr("Enter the Z translation in LDraw units or rotation in degrees."));
TransformLayout->addWidget(mTransformZEdit);
PropertiesLayout->addWidget(TransformWidget);
connect(mTransformXEdit, &QLineEdit::returnPressed, mActions[LC_EDIT_TRANSFORM], &QAction::trigger);
connect(mTransformYEdit, &QLineEdit::returnPressed, mActions[LC_EDIT_TRANSFORM], &QAction::trigger);
connect(mTransformZEdit, &QLineEdit::returnPressed, mActions[LC_EDIT_TRANSFORM], &QAction::trigger);
mPropertiesToolBar->setWidget(PropertiesWidget);
addDockWidget(Qt::RightDockWidgetArea, mPropertiesToolBar);
mTimelineToolBar = new QDockWidget(tr("Timeline"), this);
mTimelineToolBar->setObjectName("TimelineToolbar");
mTimelineToolBar->setWhatsThis(tr("<p><b>Timeline</b></p><p>Select a step to make it current, or select piece rows to select those pieces in the model. Drag pieces between steps or reorder them within a step. Right-click for step insertion, removal, movement, and visibility commands.</p>"));
lcSetupWidgetHelp(mTimelineToolBar, nullptr);
mTimelineToolBar->setAcceptDrops(true);
mTimelineWidget = new lcTimelineWidget(mTimelineToolBar);
mTimelineToolBar->setWidget(mTimelineWidget);
addDockWidget(Qt::RightDockWidgetArea, mTimelineToolBar);
CreatePreviewWidget();
tabifyDockWidget(mPartsToolBar, mPropertiesToolBar);
tabifyDockWidget(mPropertiesToolBar, mTimelineToolBar);
tabifyDockWidget(mTimelineToolBar, mPreviewToolBar);
connect(mPropertiesToolBar, &QDockWidget::topLevelChanged, this, &lcMainWindow::EnableWindowFlags);
connect(mTimelineToolBar, &QDockWidget::topLevelChanged, this, &lcMainWindow::EnableWindowFlags);
connect(mPartsToolBar, &QDockWidget::topLevelChanged, this, &lcMainWindow::EnableWindowFlags);
connect(mColorsToolBar, &QDockWidget::topLevelChanged, this, &lcMainWindow::EnableWindowFlags);
mPartsToolBar->raise();
}
lcView* lcMainWindow::CreateView(lcModel* Model)
{
lcView* NewView = new lcView(lcViewType::View, Model);
connect(NewView, &lcView::FocusReceived, this, &lcMainWindow::ViewFocusReceived);
AddView(NewView);
return NewView;
}
void lcMainWindow::PreviewPiece(lcPieceData* PieceData, int ColorCode, bool ShowPreview)
{
if (ShowPreview)
mPreviewToolBar->show();
mPreviewWidget->SetCurrentPiece(PieceData, ColorCode);
}
void lcMainWindow::CreatePreviewWidget()
{
mPreviewWidget = new lcPreviewDockWidget(this);
mPreviewToolBar = new QDockWidget(tr("Preview"), this);
mPreviewToolBar->setWindowTitle(tr("Preview"));
mPreviewToolBar->setObjectName("PreviewToolBar");
mPreviewToolBar->setWhatsThis(tr("<p><b>Preview</b></p><p>Inspect a piece without placing it in the model. Double-click a piece in the Pieces dock to preview it. Lock Preview keeps the current preview when the source selection changes; unlock it to allow updates.</p>"));
lcSetupWidgetHelp(mPreviewToolBar, nullptr);
mPreviewToolBar->setWidget(mPreviewWidget);
addDockWidget(Qt::RightDockWidgetArea, mPreviewToolBar);
connect(mPreviewToolBar, &QDockWidget::topLevelChanged, this, &lcMainWindow::EnableWindowFlags);
}
bool lcMainWindow::eventFilter(QObject* Object, QEvent* Event)
{
QTabBar* TabBar = mModelTabWidget->tabBar();
if (Object == TabBar)
{
if (Event->type() == QEvent::MouseButtonPress)
{
QMouseEvent* MouseEvent = static_cast<QMouseEvent*>(Event);
mMousePressTabIndex = -1;
if (MouseEvent->button() == Qt::MiddleButton)
mMousePressTabIndex = TabBar->tabAt(MouseEvent->pos());
}
else if (Event->type() == QEvent::MouseButtonRelease)
{
QMouseEvent* MouseEvent = static_cast<QMouseEvent*>(Event);
if (MouseEvent->button() == Qt::MiddleButton && TabBar->tabAt(MouseEvent->pos()) == mMousePressTabIndex)
TabBar->tabCloseRequested(mMousePressTabIndex);
}
}
return QMainWindow::eventFilter(Object, Event);
}
void lcMainWindow::TogglePreviewWidget(bool Visible)
{
if (mPreviewToolBar)
{
if (Visible)
mPreviewToolBar->show();
else
mPreviewToolBar->hide();
}
else if (Visible)
{
CreatePreviewWidget();
}
}
void lcMainWindow::EnableWindowFlags(bool Detached)
{
if (Detached)
{
QDockWidget* DockWidget = qobject_cast<QDockWidget*>(sender());
DockWidget->setWindowFlags(Qt::CustomizeWindowHint | Qt::Window | Qt::WindowMinimizeButtonHint | Qt::WindowMaximizeButtonHint | Qt::WindowCloseButtonHint);
if (isVisible())
DockWidget->show();
}
}
class lcElidedLabel : public QFrame
{
public:
explicit lcElidedLabel(QWidget* Parent = nullptr)
: QFrame(Parent)
{
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
}
void setText(const QString& Text)
{
mText = Text;
update();
}
protected:
void paintEvent(QPaintEvent* event) override;
QString mText;
};
void lcElidedLabel::paintEvent(QPaintEvent* event)
{
QFrame::paintEvent(event);
QPainter Painter(this);
QFontMetrics FontMetrics = Painter.fontMetrics();
int LineSpacing = FontMetrics.lineSpacing();
int y = 0;
QTextLayout TextLayout(mText, Painter.font());
TextLayout.beginLayout();
for (;;)
{
QTextLine Line = TextLayout.createLine();
if (!Line.isValid())
break;
Line.setLineWidth(width());
int NextLineY = y + LineSpacing;
if (height() >= NextLineY + LineSpacing)
{
Line.draw(&Painter, QPoint(0, y));
y = NextLineY;
}
else
{
QString LastLine = mText.mid(Line.textStart());
QString ElidedLastLine = FontMetrics.elidedText(LastLine, Qt::ElideRight, width());
Painter.drawText(QPoint(0, y + FontMetrics.ascent()), ElidedLastLine);
Line = TextLayout.createLine();
break;
}
}
TextLayout.endLayout();
}
void lcMainWindow::CreateStatusBar()
{
QStatusBar* StatusBar = new QStatusBar(this);
setStatusBar(StatusBar);
mStatusBarLabel = new lcElidedLabel();
StatusBar->addWidget(mStatusBarLabel, 1);
mStatusLoadSpinner = new lcSpinnerWidget();
StatusBar->addPermanentWidget(mStatusLoadSpinner);
mStatusLoadSpinner->hide();
mStatusLoadFailureLabel = new QLabel();
constexpr int WarningIconSize = 14;
const QSize WarningPixelSize = QSize(WarningIconSize, WarningIconSize) * devicePixelRatioF();
QPixmap WarningPixmap = QIcon(QStringLiteral(":/resources/warning.svg")).pixmap(WarningPixelSize);
WarningPixmap = WarningPixmap.scaled(WarningPixelSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
WarningPixmap.setDevicePixelRatio(devicePixelRatioF());
mStatusLoadFailureLabel->setPixmap(WarningPixmap);
mStatusLoadFailureLabel->setAccessibleName(tr("Asset loading failed"));
StatusBar->addPermanentWidget(mStatusLoadFailureLabel);
mStatusLoadFailureLabel->hide();
mStatusPositionLabel = new QLabel();
StatusBar->addPermanentWidget(mStatusPositionLabel);
mStatusSnapLabel = new QLabel();
StatusBar->addPermanentWidget(mStatusSnapLabel);
mStatusTimeLabel = new QLabel();
StatusBar->addPermanentWidget(mStatusTimeLabel);
lcPiecesLibrary* Library = lcGetPiecesLibrary();
connect(Library, &lcPiecesLibrary::AssetStatusChanged, this, &lcMainWindow::ScheduleAssetUpdate);
connect(Library, &lcPiecesLibrary::PartLoaded, this, [this](lcPieceData* PieceData)
{
if (mStatusRequiredAssets.find(PieceData) != mStatusRequiredAssets.end())
ScheduleAssetUpdate();
});
connect(Library, &lcPiecesLibrary::PartLoadFailed, this, [this](lcPieceData* PieceData, const QString&)
{
if (mStatusRequiredAssets.find(PieceData) != mStatusRequiredAssets.end())
ScheduleAssetUpdate();
});
}
void lcMainWindow::ScheduleAssetUpdate()
{
if (mAssetUpdateScheduled)
return;
mAssetUpdateScheduled = true;
QTimer::singleShot(0, this, [this]()
{
mAssetUpdateScheduled = false;
UpdateAssets();
});
}
void lcMainWindow::UpdateAssets()
{
Project* Project = lcGetActiveProject();
mStatusLoadSpinner->setToolTip(QString());
if (mStatusProject != Project)
{
mStatusProject = Project;
mStatusRequiredAssets.clear();
mStatusLoadFailureLabel->hide();
mStatusLoadFailureLabel->setToolTip(QString());
mStatusLoadFailureLabel->setAccessibleDescription(QString());
}
if (!Project || !Project->GetMainModel())
{
mStatusLoadSpinner->hide();
mStatusLoadFailureLabel->hide();
return;
}
std::vector<lcModel*> UpdatedModels;
for (const std::unique_ptr<lcModel>& Model : Project->GetModels())
Model->UpdatePieceData(UpdatedModels);
UpdateTimeline(false, true);
lcView::UpdateProjectViews(Project);
const std::vector<lcPieceDataRef> RequiredPieceData = Project->GetRequiredPieceData();
const std::vector<lcPiece*> GeneratedPieces = Project->GetRequiredSynthPieces();
mStatusRequiredAssets.clear();
for (const lcPieceDataRef& RequiredData : RequiredPieceData)
mStatusRequiredAssets.insert(RequiredData.Get());
int PendingParts = 0;
int PendingSynths = 0;
int Failed = 0;
QString FailureDetails;
for (const QString& Warning : Project->GetLoadWarningDetails())
{
if (!FailureDetails.isEmpty())
FailureDetails += QLatin1Char('\n');
FailureDetails += Warning;
}
for (const lcPieceDataRef& RequiredData : RequiredPieceData)
{
const lcPieceData* PieceData = RequiredData.Get();
if (PieceData->mState == lcAssetState::Failed)
{
Failed++;
QString Error = lcGetPiecesLibrary()->GetPieceDataLoadError(PieceData);
if (Error.isEmpty())
Error = tr("Could not load piece.");
if (!FailureDetails.isEmpty())
FailureDetails += QLatin1Char('\n');
FailureDetails += QStringLiteral("'%1': %2").arg(QString::fromLatin1(PieceData->mFileName), Error);
}
else if (PieceData->mState != lcAssetState::Loaded)
PendingParts++;
}
for (const lcPiece* Piece : GeneratedPieces)
{
if (Piece->IsGeneratedMeshPending())
PendingSynths++;
else if (!Piece->HasGeneratedMesh())
{
Failed++;
QString Error = lcGetPiecesLibrary()->GetSynthMeshError(Piece);
if (Error.isEmpty())
Error = tr("Could not generate geometry.");
if (!FailureDetails.isEmpty())
FailureDetails += QLatin1Char('\n');
FailureDetails += QStringLiteral("'%1': %2").arg(QString::fromLatin1(Piece->mPieceData->mFileName), Error);
}
}
const int Total = static_cast<int>(RequiredPieceData.size() + GeneratedPieces.size());
const int Pending = PendingParts + PendingSynths;
QString LoadingText;
if (!PendingParts && PendingSynths)
LoadingText = tr("Regenerating synthesized piece geometry.");
else
LoadingText = tr("Loading model pieces (%1 / %2).").arg(Total - Pending - Failed).arg(Total);
mStatusLoadSpinner->setToolTip(LoadingText);
mStatusLoadSpinner->setAccessibleDescription(LoadingText);
if (!FailureDetails.isEmpty())
{
QString FailureText = tr("The model could not be fully loaded. Some pieces may be missing.\n\n%1").arg(FailureDetails);
mStatusLoadFailureLabel->setToolTip(FailureText);
mStatusLoadFailureLabel->setAccessibleDescription(FailureText);
mStatusLoadFailureLabel->show();
}
else
{
mStatusLoadFailureLabel->hide();
mStatusLoadFailureLabel->setToolTip(QString());
mStatusLoadFailureLabel->setAccessibleDescription(QString());
}
mStatusLoadSpinner->setVisible(Pending > 0);
}
void lcMainWindow::closeEvent(QCloseEvent* Event)
{
if (SaveProjectIfModified())
{
Event->accept();
QSettings Settings;
Settings.beginGroup("MainWindow");
Settings.setValue("Geometry", saveGeometry());
Settings.setValue("State", saveState());
mPartSelectionWidget->SaveState(Settings);
Settings.endGroup();
gApplication->SaveTabLayout();
}
else
Event->ignore();
}
void lcMainWindow::dragEnterEvent(QDragEnterEvent* Event)
{
if (Event->mimeData()->hasUrls())
Event->acceptProposedAction();
}
void lcMainWindow::dropEvent(QDropEvent* Event)
{
const QMimeData* MimeData = Event->mimeData();
const QList<QUrl> Urls = MimeData->urls();
for (const QUrl& Url : Urls)
if (OpenProject(Url.toLocalFile()))
break;
}
QMenu* lcMainWindow::createPopupMenu()
{
QMenu* Menu = new QMenu(this);
UpdateDockWidgetActions();
Menu->addAction(mActions[LC_VIEW_TOOLBAR_PARTS]);
Menu->addAction(mActions[LC_VIEW_TOOLBAR_COLORS]);
Menu->addAction(mActions[LC_VIEW_TOOLBAR_PROPERTIES]);
Menu->addAction(mActions[LC_VIEW_TOOLBAR_TIMELINE]);
Menu->addAction(mActions[LC_VIEW_TOOLBAR_PREVIEW]);
Menu->addSeparator();
Menu->addAction(mActions[LC_VIEW_TOOLBAR_STANDARD]);
Menu->addAction(mActions[LC_VIEW_TOOLBAR_TOOLS]);
Menu->addAction(mActions[LC_VIEW_TOOLBAR_TIME]);
return Menu;
}
void lcMainWindow::UpdateDockWidgetActions()
{
mActions[LC_VIEW_TOOLBAR_PARTS]->setChecked(mPartsToolBar->isVisible());
mActions[LC_VIEW_TOOLBAR_COLORS]->setChecked(mColorsToolBar->isVisible());
mActions[LC_VIEW_TOOLBAR_PROPERTIES]->setChecked(mPropertiesToolBar->isVisible());
mActions[LC_VIEW_TOOLBAR_TIMELINE]->setChecked(mTimelineToolBar->isVisible());
mActions[LC_VIEW_TOOLBAR_STANDARD]->setChecked(mStandardToolBar->isVisible());
mActions[LC_VIEW_TOOLBAR_TOOLS]->setChecked(mToolsToolBar->isVisible());
mActions[LC_VIEW_TOOLBAR_TIME]->setChecked(mTimeToolBar->isVisible());
mActions[LC_VIEW_TOOLBAR_PREVIEW]->setChecked(mPreviewToolBar->isVisible());
}
void lcMainWindow::UpdateGamepads()
{
#if LC_ENABLE_GAMEPAD
QDateTime Now = QDateTime::currentDateTime();
quint64 Elapsed = mLastGamepadUpdate.msecsTo(Now);
mLastGamepadUpdate = Now;
if (!gMainWindow)
return;
lcView* ActiveView = GetActiveView();
if (!ActiveView)
return;
const QList<int> Gamepads = QGamepadManager::instance()->connectedGamepads();
if (Gamepads.isEmpty())
return;
QGamepad Gamepad(Gamepads[0]);
float Scale = (float)Elapsed / 20.0f;
lcVector3 Distance(Scale * Gamepad.axisLeftX(), 0.0f, -Scale * Gamepad.axisLeftY());
if (fabsf(Distance.LengthSquared()) > 0.01f)
ActiveView->MoveCamera(Distance);
#endif
}
void lcMainWindow::ModelTabContextMenuRequested(const QPoint& Point)
{
QMenu* Menu = new QMenu;
mMousePressTabIndex = mModelTabWidget->tabBar()->tabAt(Point);
if (mModelTabWidget->count() > 1)
Menu->addAction(tr("Close Other Tabs"), this, &lcMainWindow::ModelTabCloseOtherTabs);
if (mMousePressTabIndex == mModelTabWidget->currentIndex())
Menu->addAction(mActions[LC_VIEW_RESET_VIEWS]);
Menu->exec(QCursor::pos());
delete Menu;
}
void lcMainWindow::ModelTabCloseOtherTabs()
{
if (mMousePressTabIndex == -1)
return;
while (mModelTabWidget->count() - 1 > mMousePressTabIndex)
delete mModelTabWidget->widget(mMousePressTabIndex + 1);
while (mModelTabWidget->count() > 1)
delete mModelTabWidget->widget(0);
}
void lcMainWindow::ModelTabClosed(int Index)
{
if (mModelTabWidget->count() != 1)
delete mModelTabWidget->widget(Index);
else
NewProject();
}
void lcMainWindow::ModelTabChanged(int Index)
{
Project* Project = lcGetActiveProject();
lcModelTabWidget* CurrentTab = (lcModelTabWidget*)mModelTabWidget->widget(Index);
Project->SetActiveModel(CurrentTab ? CurrentTab->GetModel() : nullptr, true);
}
void lcMainWindow::ClipboardChanged()
{
const QString MimeType = QLatin1String("application/vnd.leocad-clipboard");
const QMimeData* MimeData = QApplication::clipboard()->mimeData();
QByteArray ClipboardData;
if (MimeData && MimeData->hasFormat(MimeType))
ClipboardData = MimeData->data(MimeType);
gApplication->SetClipboard(ClipboardData);
}
void lcMainWindow::ActionTriggered()
{
QObject* Action = sender();
for (int CommandIdx = 0; CommandIdx < LC_NUM_COMMANDS; CommandIdx++)
{
if (Action == mActions[CommandIdx])
{
HandleCommand((lcCommandId)CommandIdx);
break;
}
}
}
void lcMainWindow::ColorChanged(int ColorIndex)
{
SetColorIndex(ColorIndex);
}
void lcMainWindow::PartListPicked(lcPieceData* PieceData)
{
if (!PieceData)
return;
quint32 ColorCode = lcGetColorCode(mPartSelectionWidget->GetColorIndex());
PreviewPiece(PieceData, ColorCode, true);
}
void lcMainWindow::ColorButtonClicked()
{
lcModel* ActiveModel = GetActiveModel();
if (ActiveModel)
ActiveModel->PaintSelectedPieces();
}
void lcMainWindow::ProjectFileChanged(const QString& Path)
{
static bool Ignore;
Project* CurrentProject = lcGetActiveProject();
if (Ignore || !CurrentProject || Path.isEmpty() || QFileInfo(Path) != QFileInfo(CurrentProject->GetFileName()))
return;
QString Text = tr("The file '%1' has been modified by another application. Do you want to reload it?").arg(QDir::toNativeSeparators(Path));
const QString CurrentFileName = CurrentProject->GetFileName();
Ignore = true;
if (QMessageBox::question(this, tr("File Changed"), Text, QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes)
{
Ignore = false;
if (CurrentProject == lcGetActiveProject() && CurrentFileName == CurrentProject->GetFileName())
{
CurrentProject->MarkAsModified();
UpdateTitle();
}
return;
}
if (CurrentProject != lcGetActiveProject() || CurrentFileName != CurrentProject->GetFileName())
{
Ignore = false;
return;
}
std::unique_ptr<Project> NewProject = std::make_unique<Project>();
if (NewProject->Load(Path, true))
{
QByteArray TabLayout = GetTabLayout();
gApplication->SetProject(NewProject.release());
RestoreTabLayout(TabLayout);
lcView::UpdateAllViews();
}
Ignore = false;
}
void lcMainWindow::Print(QPrinter* Printer)
{
#ifndef QT_NO_PRINTER
lcGetActiveProject()->GetMainModel()->WaitForAssets();
int DocCopies;
int PageCopies;
lcInstructions* Instructions = lcGetActiveProject()->GetInstructions();
const int PageCount = static_cast<int>(Instructions->mPages.size());
if (Printer->collateCopies())
{
DocCopies = 1;
PageCopies = Printer->supportsMultipleCopies() ? 1 : Printer->copyCount();
}
else
{
DocCopies = Printer->supportsMultipleCopies() ? 1 : Printer->copyCount();
PageCopies = 1;
}
int FromPage = Printer->fromPage();
int ToPage = Printer->toPage();
bool Ascending = true;
if (FromPage == 0 && ToPage == 0)
{
FromPage = 1;
ToPage = PageCount;
}
FromPage = qMax(1, FromPage);
ToPage = qMin(PageCount, ToPage);
if (ToPage < FromPage)
return;
if (Printer->pageOrder() == QPrinter::LastPageFirst)
{
int Tmp = FromPage;
FromPage = ToPage;
ToPage = Tmp;
Ascending = false;
}
QRect PageRect = Printer->pageLayout().paintRectPixels(Printer->resolution());
const int Resolution = Printer->resolution();
const int Margin = Resolution / 2; // todo: user setting
QRect MarginRect = QRect(PageRect.left() + Margin, PageRect.top() + Margin, PageRect.width() - Margin * 2, PageRect.height() - Margin * 2);
QPainter Painter(Printer);
bool FirstPage = true;
// TODO: option to print background
for (int DocCopy = 0; DocCopy < DocCopies; DocCopy++)
{
int Page = FromPage;
for (;;)
{
for (int PageCopy = 0; PageCopy < PageCopies; PageCopy++)
{
if (Printer->printerState() == QPrinter::Aborted || Printer->printerState() == QPrinter::Error)
return;
if (!FirstPage)
Printer->newPage();
else
FirstPage = false;
int StepWidth = MarginRect.width();
int StepHeight = MarginRect.height();
const lcInstructionsPage& PageLayout = Instructions->mPages[Page - 1];
lcModel* Model = PageLayout.Steps[0].Model;
lcStep Step = PageLayout.Steps[0].Step;
QImage Image = Model->GetStepImage(false, StepWidth, StepHeight, Step);
if (Image.isNull())
{
Printer->abort();
return;
}
Painter.drawImage(MarginRect.left(), MarginRect.top(), Image);
// TODO: add print options somewhere but Qt doesn't allow changes to the page setup dialog
// DWORD dwPrint = theApp.GetProfileInt("Settings","Print", PRINT_NUMBERS|PRINT_BORDER);
// if (print text)
{
QFont Font("Helvetica", 96);
Painter.setFont(Font);
QFontMetrics FontMetrics(Font);
int TextMargin = Resolution / 2;
QRect TextRect = QRect(MarginRect.left() + TextMargin, MarginRect.top() + TextMargin, MarginRect.width() - TextMargin * 2, MarginRect.height() - TextMargin * 2);
Painter.drawText(TextRect, Qt::AlignTop | Qt::AlignLeft, QString::number(Step));
}
/*
// if (print border)
{
QPen BlackPen(Qt::black, 2);
Painter.setPen(BlackPen);
Painter.drawLine(MarginRect.left(), MarginRect.top(), MarginRect.right(), MarginRect.top());
Painter.drawLine(MarginRect.left(), MarginRect.bottom(), MarginRect.right(), MarginRect.bottom());
Painter.drawLine(MarginRect.left(), MarginRect.top(), MarginRect.left(), MarginRect.bottom());
Painter.drawLine(MarginRect.right(), MarginRect.top(), MarginRect.right(), MarginRect.bottom());
}
*/
// TODO: print header and footer
}
if (Page == ToPage)
break;
if (Ascending)
Page++;
else
Page--;
}
}
#endif
}
void lcMainWindow::ShowUpdatesDialog()
{
lcUpdateDialog Dialog(this, false);
Dialog.exec();
}
void lcMainWindow::ShowAboutDialog()
{
lcAboutDialog Dialog(this);
Dialog.exec();
}
void lcMainWindow::ShowHTMLDialog()
{
lcHTMLExportOptions Options(lcGetActiveProject());
lcHTMLDialog Dialog(this, &Options);
if (Dialog.exec() != QDialog::Accepted)
return;
Options.SaveDefaults();
ShowResultError(lcGetActiveProject()->ExportHTML(Options), tr("Export HTML"));
}
void lcMainWindow::ShowExportPOVRayDialog()
{
lcResult<void> ExportResult = lcGetActiveProject()->ExportPOVRay(QString());
if (!ExportResult && !ExportResult.error().isEmpty())
QMessageBox::warning(this, tr("POV-Ray Export" ), ExportResult.error());
}
void lcMainWindow::ShowRenderDialog(lcRenderDialogMode RenderDialogMode)
{
#ifndef LC_DISABLE_RENDER_DIALOG
lcRenderDialog Dialog(this, RenderDialogMode);
Dialog.exec();
#endif
}
void lcMainWindow::ShowInstructionsDialog()
{
lcGetActiveProject()->GetMainModel()->WaitForAssets();
lcInstructionsDialog* Dialog = new lcInstructionsDialog(this, lcGetActiveProject());
Dialog->setWindowModality(Qt::ApplicationModal);
Dialog->setAttribute(Qt::WA_DeleteOnClose);
Dialog->show();
}
void lcMainWindow::ShowPrintDialog()
{
lcGetActiveProject()->GetMainModel()->WaitForAssets();
#ifndef QT_NO_PRINTER
int PageCount = static_cast<int>(lcGetActiveProject()->GetInstructions()->mPages.size());
QPrinter Printer(QPrinter::HighResolution);
Printer.setFromTo(1, PageCount + 1);
QPrintDialog PrintDialog(&Printer, this);
if (PrintDialog.exec() == QDialog::Accepted)
Print(&Printer);
#endif
}
void lcMainWindow::ShowImageDialog()
{
lcImageDialogOptions Options;
Project* Project = lcGetActiveProject();
lcModel* Model = Project->GetActiveModel();
Options.Width = lcGetProfileInt(LC_PROFILE_IMAGE_WIDTH);
Options.Height = lcGetProfileInt(LC_PROFILE_IMAGE_HEIGHT);
Options.Start = Model->GetCurrentStep();
Options.End = Model->GetLastStep();
Options.FilePath = Project->GetImageFileName(false);
lcImageDialog Dialog(this, &Options);
if (Dialog.exec() != QDialog::Accepted)
return;
lcSetProfileInt(LC_PROFILE_IMAGE_WIDTH, Options.Width);
lcSetProfileInt(LC_PROFILE_IMAGE_HEIGHT, Options.Height);
const lcResult<void> Saved = lcGetActiveProject()->SaveImage(Options);
if (!Saved)
QMessageBox::warning(this, tr("Save Image"), Saved.error());
}
void lcMainWindow::ShowSelectDialog()
{
lcModel* ActiveModel = GetActiveModel();
if (!ActiveModel)
return;
if (ActiveModel->GetPieces().empty() && ActiveModel->GetCameras().empty() && ActiveModel->GetLights().empty())
{
QMessageBox::information(this, tr("Select Objects"), tr("Nothing to select."));
return;
}
lcSelectDialog Dialog(this, ActiveModel);
if (Dialog.exec() != QDialog::Accepted)
return;
ActiveModel->SetSelectionAndFocusAction(Dialog.mObjects, nullptr, 0, lcSelectionMode::Single);
}
void lcMainWindow::ShowResultError(const lcResult<void>& Result, const QString& Title)
{
if (!Result && !Result.error().isEmpty())
QMessageBox::warning(this, Title, Result.error());
}
void lcMainWindow::SetShadingMode(lcShadingMode ShadingMode)
{
lcGetPreferences().mShadingMode = ShadingMode;
lcSetProfileShadingMode(ShadingMode);
UpdateShadingMode();
lcView::UpdateAllViews();
if (mPartSelectionWidget)
mPartSelectionWidget->UpdateThumbnails();
}
void lcMainWindow::SetSelectionMode(lcSelectionMode SelectionMode)
{
mSelectionMode = SelectionMode;
UpdateSelectionMode();
}
void lcMainWindow::ToggleViewSphere()
{
lcGetPreferences().mViewSphereEnabled = !lcGetPreferences().mViewSphereEnabled;
lcSetProfileInt(LC_PROFILE_VIEW_SPHERE_ENABLED, lcGetPreferences().mViewSphereEnabled);
lcView::UpdateAllViews();
}
void lcMainWindow::ToggleAxisIcon()
{
lcGetPreferences().mDrawAxes = !lcGetPreferences().mDrawAxes;
lcSetProfileInt(LC_PROFILE_DRAW_AXES, lcGetPreferences().mDrawAxes);
lcView::UpdateAllViews();
}
void lcMainWindow::ToggleGrid()
{
lcGetPreferences().mGridEnabled = !lcGetPreferences().mGridEnabled;
lcView::UpdateAllViews();
}
void lcMainWindow::ToggleFadePreviousSteps()
{
lcGetPreferences().mFadeSteps = !lcGetPreferences().mFadeSteps;
lcSetProfileInt(LC_PROFILE_FADE_STEPS, lcGetPreferences().mFadeSteps);
lcView::UpdateAllViews();
}
QByteArray lcMainWindow::GetTabLayout()
{
QByteArray TabLayoutData;
QDataStream DataStream(&TabLayoutData, QIODevice::WriteOnly);
DataStream << (quint32)LC_TAB_LAYOUT_VERSION;
qint32 NumTabs = mModelTabWidget->count();
DataStream << NumTabs;
DataStream << ((lcModelTabWidget*)mModelTabWidget->currentWidget())->GetModel()->GetProperties().mFileName;
for (int TabIdx = 0; TabIdx < NumTabs; TabIdx++)
{
lcModelTabWidget* TabWidget = (lcModelTabWidget*)mModelTabWidget->widget(TabIdx);
DataStream << TabWidget->GetModel()->GetProperties().mFileName;
std::function<void (QWidget*)> SaveWidget = [&DataStream, &SaveWidget, &TabWidget](QWidget* Widget)
{
if (Widget->metaObject() == &lcViewWidget::staticMetaObject)
{
lcView* CurrentView = ((lcViewWidget*)Widget)->GetView();
DataStream << (qint32)0;
DataStream << (qint32)(TabWidget->GetActiveView() == CurrentView ? 1 : 0);
const lcCamera* Camera = CurrentView->GetCamera();
if (Camera->IsSimple())
{
DataStream << (qint32)0;
DataStream << Camera->m_fovy;
DataStream << Camera->m_zNear;
DataStream << Camera->m_zFar;
DataStream << Camera->mPosition;
DataStream << Camera->mTargetPosition;
DataStream << Camera->mUpVector;
}
else
{
DataStream << (qint32)1;
DataStream << Camera->GetName();
}
}
else
{
QSplitter* Splitter = (QSplitter*)Widget;
DataStream << (qint32)(Splitter->orientation() == Qt::Horizontal ? 1 : 2);
DataStream << Splitter->sizes();
SaveWidget(Splitter->widget(0));
SaveWidget(Splitter->widget(1));
}
};
QLayout* TabLayout = TabWidget->layout();
SaveWidget(TabLayout->itemAt(0)->widget());
}
return TabLayoutData;
}
void lcMainWindow::RestoreTabLayout(const QByteArray& TabLayout)
{
if (TabLayout.isEmpty())
return;
QDataStream DataStream(TabLayout);
quint32 Version;
DataStream >> Version;
if (Version != LC_TAB_LAYOUT_VERSION)
return;
qint32 NumTabs;
DataStream >> NumTabs;
QString CurrentTabName;
DataStream >> CurrentTabName;
RemoveAllModelTabs();
for (int TabIdx = 0; TabIdx < NumTabs; TabIdx++)
{
QString ModelName;
DataStream >> ModelName;
lcModel* Model = lcGetActiveProject()->GetModel(ModelName);
lcModelTabWidget* TabWidget = nullptr;
if (Model)
{
SetCurrentModelTab(Model, false);
TabWidget = (lcModelTabWidget*)mModelTabWidget->widget(mModelTabWidget->count() - 1);
}
QWidget* ActiveWidget = nullptr;
std::function<void(QWidget*)> LoadWidget = [&DataStream, &LoadWidget, &ActiveWidget, this](QWidget* ParentWidget)
{
qint32 WidgetType;
DataStream >> WidgetType;
if (WidgetType == 0)
{
qint32 IsActive;
DataStream >> IsActive;
if (IsActive)
ActiveWidget = ParentWidget;
qint32 CameraType;
DataStream >> CameraType;
lcView* CurrentView = nullptr;
if (ParentWidget)
CurrentView = ((lcViewWidget*)ParentWidget)->GetView();
if (CameraType == 0)
{
float FoV, ZNear, ZFar;
lcVector3 Position, TargetPosition, UpVector;
DataStream >> FoV;
DataStream >> ZNear;
DataStream >> ZFar;
DataStream >> Position;
DataStream >> TargetPosition;
DataStream >> UpVector;
if (CurrentView)
{
lcCamera* Camera = CurrentView->GetCamera();
if (!std::isnan(FoV))
Camera->m_fovy = FoV;
if (!std::isnan(ZNear))
Camera->m_zNear = ZNear;
if (!std::isnan(ZFar))
Camera->m_zFar = ZFar;
if (!Position.IsNan() && !TargetPosition.IsNan() && !UpVector.IsNan())
{
Camera->SetPosition(Position, 1, false);
Camera->SetTargetPosition(TargetPosition, 1, false);
Camera->SetUpVector(UpVector, 1, false);
}
Camera->UpdatePosition(1);
Camera->ExpandFarPlane(CurrentView->GetModel()->GetPiecesBoundingBoxPoints(lcGeometryBoundsMode::IncludeFallback));
}
}
else
{
QByteArray CameraName;
DataStream >> CameraName;
if (CurrentView)
CurrentView->SetCamera(CameraName);
}
}
else
{
QList<int> Sizes;
DataStream >> Sizes;
if (ParentWidget)
{
ParentWidget->setFocus();
if (WidgetType == 1)
SplitVertical();
else
SplitHorizontal();
QSplitter* Splitter = (QSplitter*)ParentWidget->parentWidget();
Splitter->setSizes(Sizes);
LoadWidget(Splitter->widget(0));
LoadWidget(Splitter->widget(1));
}
else
{
LoadWidget(nullptr);
LoadWidget(nullptr);
}
}
};
LoadWidget(TabWidget ? TabWidget->layout()->itemAt(0)->widget() : nullptr);
if (ActiveWidget && TabWidget)
ActiveWidget->setFocus();
}
if (!mModelTabWidget->count())
lcGetActiveProject()->SetActiveModel(0, true);
else
lcGetActiveProject()->SetActiveModel(CurrentTabName, true);
}
void lcMainWindow::RemoveAllModelTabs()
{
while (mModelTabWidget->count())
delete mModelTabWidget->widget(0);
}
void lcMainWindow::CloseCurrentModelTab()
{
if (mModelTabWidget->count() > 1)
delete mModelTabWidget->currentWidget();
else
NewProject();
}
void lcMainWindow::SetCurrentModelTab(lcModel* Model, bool AdjustFarPlane)
{
for (int TabIdx = 0; TabIdx < mModelTabWidget->count(); TabIdx++)
{
lcModelTabWidget* TabWidget = (lcModelTabWidget*)mModelTabWidget->widget(TabIdx);
if (TabWidget->GetModel() == Model)
{
mModelTabWidget->setCurrentIndex(TabIdx);
return;
}
}
lcModelTabWidget* TabWidget = new lcModelTabWidget(Model);
mModelTabWidget->addTab(TabWidget, Model->GetProperties().mFileName);
QVBoxLayout* CentralLayout = new QVBoxLayout(TabWidget);
CentralLayout->setContentsMargins(0, 0, 0, 0);
lcView* NewView = CreateView(Model);
lcViewWidget* ViewWidget = new lcViewWidget(TabWidget, NewView);
CentralLayout->addWidget(ViewWidget);
mModelTabWidget->setCurrentWidget(TabWidget);
ViewWidget->show();
ViewWidget->setFocus();
NewView->ZoomExtents(lcGeometryBoundsMode::IncludeFallback, AdjustFarPlane);
}
void lcMainWindow::AddView(lcView* View)
{
lcModelTabWidget* TabWidget = GetTabWidgetForModel(View->GetModel());
if (!TabWidget)
return;
if (!TabWidget->GetActiveView())
TabWidget->SetActiveView(View);
}
void lcMainWindow::RemoveView(lcView* View)
{
lcModelTabWidget* TabWidget = GetTabForView(View);
if (TabWidget)
TabWidget->RemoveView(View);
}
void lcMainWindow::SetActiveView(lcView* ActiveView)
{
lcModelTabWidget* TabWidget = GetTabForView(ActiveView);
if (!TabWidget)
return;
lcView* CurrentActiveView = TabWidget->GetActiveView();
if (CurrentActiveView == ActiveView)
return;
if (CurrentActiveView)
CurrentActiveView->SetTopSubmodelActive();
TabWidget->SetActiveView(ActiveView);
}
void lcMainWindow::SetTool(lcTool Tool)
{
mTool = Tool;
QAction* Action = mActions[LC_EDIT_ACTION_FIRST + static_cast<int>(mTool)];
if (Action)
Action->setChecked(true);
lcView::UpdateAllViews();
}
void lcMainWindow::SetColorIndex(int ColorIndex)
{
mColorIndex = ColorIndex;
if (mPartSelectionWidget)
mPartSelectionWidget->SetColorIndex(ColorIndex);
UpdateColor();
}
void lcMainWindow::SetMoveSnapEnabled(bool Enabled)
{
mMoveSnapEnabled = Enabled;
UpdateSnap();
}
void lcMainWindow::SetAngleSnapEnabled(bool Enabled)
{
mAngleSnapEnabled = Enabled;
UpdateSnap();
}
void lcMainWindow::SetMoveXYSnapIndex(int Index)
{
mMoveXYSnapIndex = Index;
UpdateSnap();
}
void lcMainWindow::SetMoveZSnapIndex(int Index)
{
mMoveZSnapIndex = Index;
UpdateSnap();
}
void lcMainWindow::SetAngleSnapIndex(int Index)
{
mAngleSnapIndex = Index;
UpdateSnap();
}
void lcMainWindow::SetRelativeTransform(bool RelativeTransform)
{
mRelativeTransform = RelativeTransform;
UpdateLockSnap();
lcView::UpdateAllViews();
}
void lcMainWindow::SetSeparateTransform(bool SelectionTransform)
{
mLocalTransform = SelectionTransform;
UpdateLockSnap();
}
void lcMainWindow::SetTransformType(lcTransformType TransformType)
{
if (TransformType < lcTransformType::First || TransformType >= lcTransformType::Count)
return;
mTransformType = TransformType;
constexpr const char* IconNames[] =
{
":/resources/edit_transform_absolute_translation.png",
":/resources/edit_transform_relative_translation.png",
":/resources/edit_transform_absolute_rotation.png",
":/resources/edit_transform_relative_rotation.png"
};
LC_ARRAY_SIZE_CHECK(IconNames, lcTransformType::Count);
int TransformIndex = static_cast<int>(TransformType);
mActions[LC_EDIT_TRANSFORM_ABSOLUTE_TRANSLATION + TransformIndex]->setChecked(true);
mActions[LC_EDIT_TRANSFORM]->setIcon(QIcon(IconNames[TransformIndex]));
}
void lcMainWindow::SetInsertPieceData(lcPieceData* PieceData)
{
mInsertPieceData = lcPieceDataRef(PieceData);
if (mInsertPieceData)
lcGetPiecesLibrary()->RequestPieceDataLoad(mInsertPieceData.Get(), lcLoadPriority::Normal);
}
lcVector3 lcMainWindow::GetTransformAmount()
{
lcVector3 Transform;
Transform.x = lcParseValueLocalized(mTransformXEdit->text());
Transform.y = lcParseValueLocalized(mTransformYEdit->text());
Transform.z = lcParseValueLocalized(mTransformZEdit->text());
return Transform;
}
void lcMainWindow::SplitView(Qt::Orientation Orientation)
{
QWidget* Focus = focusWidget();
if (Focus->metaObject() != &lcViewWidget::staticMetaObject)
return;
QWidget* Parent = Focus->parentWidget();
QSplitter* Splitter;
QList<int> Sizes;
if (Parent->metaObject() == &lcModelTabWidget::staticMetaObject)
{
Splitter = new QSplitter(Orientation, Parent);
Parent->layout()->addWidget(Splitter);
Splitter->addWidget(Focus);
Splitter->addWidget(new lcViewWidget(mModelTabWidget->currentWidget(), CreateView(GetCurrentTabModel())));
}
else
{
QSplitter* ParentSplitter = (QSplitter*)Parent;
Sizes = ParentSplitter->sizes();
int FocusIndex = ParentSplitter->indexOf(Focus);
Splitter = new QSplitter(Orientation, Parent);
ParentSplitter->insertWidget(FocusIndex, Splitter);
Splitter->addWidget(Focus);
Splitter->addWidget(new lcViewWidget(mModelTabWidget->currentWidget(), CreateView(GetCurrentTabModel())));
ParentSplitter->setSizes(Sizes);
}
Sizes.clear();
Sizes.append(10);
Sizes.append(10);
Splitter->setSizes(Sizes);
Focus->setFocus();
}
void lcMainWindow::SplitHorizontal()
{
SplitView(Qt::Vertical);
}
void lcMainWindow::SplitVertical()
{
SplitView(Qt::Horizontal);
}
void lcMainWindow::RemoveActiveView()
{
QWidget* Focus = focusWidget();
if (Focus->metaObject() != &lcViewWidget::staticMetaObject)
return;
QWidget* Parent = Focus->parentWidget();
if (Parent->metaObject() == &lcModelTabWidget::staticMetaObject)
return;
QWidget* ParentParentWidget = Parent->parentWidget();
QSplitter* ParentSplitter = (QSplitter*)Parent;
int FocusIndex = ParentSplitter->indexOf(Focus);
QWidget* OtherWidget = ParentSplitter->widget(!FocusIndex);
if (ParentParentWidget->metaObject() == &lcModelTabWidget::staticMetaObject)
{
QLayout* CentralLayout = ParentParentWidget->layout();
CentralLayout->addWidget(OtherWidget);
CentralLayout->removeWidget(Parent);
}
else
{
QSplitter* ParentParentSplitter = (QSplitter*)ParentParentWidget;
QList<int> Sizes = ParentParentSplitter->sizes();
int ParentIndex = ParentParentSplitter->indexOf(Parent);
Parent->setParent(nullptr);
ParentParentSplitter->insertWidget(ParentIndex, OtherWidget);
ParentParentSplitter->setSizes(Sizes);
}
Parent->deleteLater();
if (OtherWidget->metaObject() != &lcViewWidget::staticMetaObject)
{
lcModelTabWidget* TabWidget = (lcModelTabWidget*)mModelTabWidget->currentWidget();
if (TabWidget)
OtherWidget = TabWidget->GetAnyViewWidget();
}
OtherWidget->setFocus();
}
void lcMainWindow::ResetViews()
{
lcModelTabWidget* TabWidget = (lcModelTabWidget*)mModelTabWidget->currentWidget();
if (!TabWidget)
return;
QLayout* TabLayout = TabWidget->layout();
QWidget* TopWidget = TabLayout->itemAt(0)->widget();
TopWidget->deleteLater();
lcView* NewView = CreateView(TabWidget->GetModel());
lcViewWidget* ViewWidget = new lcViewWidget(TabWidget, NewView);
TabLayout->addWidget(ViewWidget);
ViewWidget->show();
ViewWidget->setFocus();
NewView->ZoomExtents(lcGeometryBoundsMode::IncludeFallback, true);
}
void lcMainWindow::ToggleDockWidget(QWidget* DockWidget)
{
if (DockWidget->isHidden())
{
DockWidget->show();
DockWidget->raise();
}
else
DockWidget->close();
}
void lcMainWindow::TogglePrintPreview()
{
#ifndef QT_NO_PRINTER
// todo: print preview inside main window
int PageCount = static_cast<int>(lcGetActiveProject()->GetInstructions()->mPages.size());
QPrinter Printer(QPrinter::ScreenResolution);
Printer.setFromTo(1, PageCount + 1);
QPrintPreviewDialog Preview(&Printer, this);
connect(&Preview, &QPrintPreviewDialog::paintRequested, this, &lcMainWindow::Print);
Preview.exec();
#endif
}
void lcMainWindow::ToggleFullScreen()
{
// todo: hide toolbars and menu
// todo: create fullscreen toolbar or support esc key to go back
if (isFullScreen())
showNormal();
else
showFullScreen();
}
void lcMainWindow::AddRecentFile(const QString& FileName)
{
QString SavedName = FileName;
int MaxRecentFiles = static_cast<int>(mRecentFiles.size());
int FileIndex;
QFileInfo FileInfo(FileName);
for (FileIndex = 0; FileIndex < MaxRecentFiles; FileIndex++)
if (QFileInfo(mRecentFiles[FileIndex]) == FileInfo)
break;
for (FileIndex = lcMin(FileIndex, MaxRecentFiles - 1); FileIndex > 0; FileIndex--)
mRecentFiles[FileIndex] = mRecentFiles[FileIndex - 1];
mRecentFiles[0] = SavedName;
}
void lcMainWindow::RemoveRecentFile(size_t FileIndex)
{
for (; FileIndex < mRecentFiles.size() - 1; FileIndex++)
mRecentFiles[FileIndex] = mRecentFiles[FileIndex + 1];
mRecentFiles[mRecentFiles.size() - 1].clear();
}
void lcMainWindow::UpdateSelectedObjects(bool SelectionChanged)
{
int Flags = 0;
std::vector<lcObject*> Selection;
lcObject* Focus = nullptr;
lcModel* ActiveModel = GetActiveModel();
if (ActiveModel)
ActiveModel->GetSelectionInformation(&Flags, Selection, &Focus);
if (SelectionChanged)
{
mTimelineWidget->UpdateSelection();
mActions[LC_EDIT_CUT]->setEnabled(Flags & LC_SEL_SELECTED);
mActions[LC_EDIT_COPY]->setEnabled(Flags & LC_SEL_SELECTED);
mActions[LC_EDIT_FIND]->setEnabled((Flags & LC_SEL_NO_PIECES) == 0);
mActions[LC_EDIT_FIND_NEXT]->setEnabled((Flags & LC_SEL_NO_PIECES) == 0);
mActions[LC_EDIT_FIND_PREVIOUS]->setEnabled((Flags & LC_SEL_NO_PIECES) == 0);
mActions[LC_EDIT_FIND_ALL]->setEnabled((Flags & LC_SEL_NO_PIECES) == 0);
mActions[LC_EDIT_REPLACE]->setEnabled((Flags & LC_SEL_NO_PIECES) == 0);
mActions[LC_EDIT_REPLACE_NEXT]->setEnabled((Flags & LC_SEL_NO_PIECES) == 0);
mActions[LC_EDIT_REPLACE_ALL]->setEnabled((Flags & LC_SEL_NO_PIECES) == 0);
mActions[LC_EDIT_SELECT_INVERT]->setEnabled((Flags & LC_SEL_NO_PIECES) == 0);
mActions[LC_EDIT_SELECT_BY_NAME]->setEnabled((Flags & LC_SEL_NO_PIECES) == 0);
mActions[LC_EDIT_SELECT_NONE]->setEnabled(Flags & LC_SEL_SELECTED);
mActions[LC_EDIT_SELECT_ALL]->setEnabled(Flags & LC_SEL_UNSELECTED);
mActions[LC_PIECE_DELETE]->setEnabled(Flags & LC_SEL_SELECTED);
mActions[LC_PIECE_DUPLICATE]->setEnabled(Flags & LC_SEL_SELECTED);
mActions[LC_PIECE_PAINT_SELECTED]->setEnabled(Flags & LC_SEL_PIECE);
mActions[LC_PIECE_RESET_PIVOT_POINT]->setEnabled(Flags & LC_SEL_SELECTED);
mActions[LC_PIECE_REMOVE_KEY_FRAMES]->setEnabled(Flags & LC_SEL_SELECTED);
mActions[LC_PIECE_ARRAY]->setEnabled(Flags & LC_SEL_PIECE);
mActions[LC_PIECE_CONTROL_POINT_INSERT]->setEnabled(Flags & LC_SEL_CAN_ADD_CONTROL_POINT);
mActions[LC_PIECE_CONTROL_POINT_REMOVE]->setEnabled(Flags & LC_SEL_CAN_REMOVE_CONTROL_POINT);
mActions[LC_PIECE_TRAIN_TRACK_FOCUS_NEXT]->setEnabled(Flags & LC_SEL_TRAIN_TRACK_VISIBLE);
mActions[LC_PIECE_TRAIN_TRACK_FOCUS_PREVIOUS]->setEnabled(Flags & LC_SEL_TRAIN_TRACK_VISIBLE);
mActions[LC_PIECE_TRAIN_TRACK_ROTATE]->setEnabled(Flags & LC_SEL_TRAIN_TRACK_VISIBLE);
mActions[LC_PIECE_HIDE_SELECTED]->setEnabled(Flags & LC_SEL_VISIBLE_SELECTED);
mActions[LC_PIECE_HIDE_UNSELECTED]->setEnabled(Flags & LC_SEL_UNSELECTED);
mActions[LC_PIECE_UNHIDE_SELECTED]->setEnabled(Flags & LC_SEL_HIDDEN_SELECTED);
mActions[LC_PIECE_UNHIDE_ALL]->setEnabled(Flags & LC_SEL_HIDDEN);
mActions[LC_PIECE_VIEW_SELECTED_MODEL]->setEnabled(Flags & LC_SEL_MODEL_SELECTED);
mActions[LC_PIECE_MOVE_SELECTION_TO_MODEL]->setEnabled(Flags & LC_SEL_PIECE);
mActions[LC_PIECE_INLINE_SELECTED_MODELS]->setEnabled(Flags & LC_SEL_MODEL_SELECTED);
mActions[LC_PIECE_EDIT_SELECTED_SUBMODEL]->setEnabled(Flags & LC_SEL_MODEL_SELECTED);
mActions[LC_PIECE_GROUP]->setEnabled(Flags & LC_SEL_CAN_GROUP);
mActions[LC_PIECE_UNGROUP]->setEnabled(Flags & LC_SEL_GROUPED);
mActions[LC_PIECE_GROUP_ADD]->setEnabled((Flags & (LC_SEL_GROUPED | LC_SEL_FOCUS_GROUPED)) == LC_SEL_GROUPED);
mActions[LC_PIECE_GROUP_REMOVE]->setEnabled(Flags & LC_SEL_FOCUS_GROUPED);
mActions[LC_PIECE_GROUP_EDIT]->setEnabled((Flags & LC_SEL_NO_PIECES) == 0);
mActions[LC_PIECE_SHOW_EARLIER]->setEnabled(Flags & LC_SEL_PIECE); // FIXME: disable if current step is 1
mActions[LC_PIECE_SHOW_LATER]->setEnabled(Flags & LC_SEL_PIECE);
mActions[LC_TIMELINE_MOVE_SELECTION]->setEnabled(Flags & LC_SEL_PIECE);
mActions[LC_TIMELINE_MOVE_SELECTION_BEFORE]->setEnabled(Flags & LC_SEL_PIECE);
mActions[LC_TIMELINE_MOVE_SELECTION_AFTER]->setEnabled(Flags & LC_SEL_PIECE);
mActions[LC_PIECE_EDIT_END_SUBMODEL]->setEnabled(GetCurrentTabModel() != ActiveModel);
}
mPropertiesWidget->Update(Selection, Focus);
if (Focus && Focus->IsPiece())
{
lcPiece* Piece = (lcPiece*)Focus;
int ColorIndex = Piece->GetColorIndex();
quint32 ColorCode = lcGetColorCode(ColorIndex);
PreviewPiece(Piece->mPieceData.Get(), ColorCode, false);
}
QString Message;
if ((Selection.size() == 1) && Focus)
{
if (Focus->IsPiece())
Message = tr("%1 (ID: %2)").arg(Focus->GetName(), ((lcPiece*)Focus)->GetID());
else
Message = Focus->GetName();
}
else if (Selection.size() > 0)
{
Message = tr("%n objects selected", nullptr, static_cast<int>(Selection.size()));
if (Focus && Focus->IsPiece())
{
Message.append(tr(" - %1 (ID: %2)").arg(Focus->GetName(), ((lcPiece*)Focus)->GetID()));
const lcGroup* Group = ((lcPiece*)Focus)->GetGroup();
if (Group && !Group->mName.isEmpty())
Message.append(tr(" in group '%1'").arg(Group->mName));
}
}
mStatusBarLabel->setText(Message);
lcVector3 Position;
lcGetActiveModel()->GetFocusPosition(Position);
QString Label("X: %1 Y: %2 Z: %3");
Label = Label.arg(QLocale::system().toString(Position[0], 'f', 2), QLocale::system().toString(Position[1], 'f', 2), QLocale::system().toString(Position[2], 'f', 2));
mStatusPositionLabel->setText(Label);
}
void lcMainWindow::UpdateTimeline(bool Clear, bool UpdateItems)
{
mTimelineWidget->Update(Clear, UpdateItems);
}
void lcMainWindow::UpdatePaste(bool Enabled)
{
if (mActions[LC_EDIT_PASTE])
mActions[LC_EDIT_PASTE]->setEnabled(Enabled);
if (mActions[LC_EDIT_PASTE_STEPS])
mActions[LC_EDIT_PASTE_STEPS]->setEnabled(Enabled);
}
void lcMainWindow::UpdateCurrentStep()
{
lcModel* Model = lcGetActiveModel();
lcStep CurrentStep = Model->GetCurrentStep();
lcStep LastStep = Model->GetLastStep();
mActions[LC_VIEW_TIME_FIRST]->setEnabled(CurrentStep != 1);
mActions[LC_VIEW_TIME_PREVIOUS]->setEnabled(CurrentStep > 1);
mActions[LC_VIEW_TIME_NEXT]->setEnabled(CurrentStep < LC_STEP_MAX);
mActions[LC_VIEW_TIME_LAST]->setEnabled(CurrentStep != LastStep);
mStatusTimeLabel->setText(QString(tr("Step %1")).arg(QString::number(CurrentStep)));
}
void lcMainWindow::SetAddKeys(bool AddKeys)
{
QAction* Action = mActions[LC_VIEW_TIME_ADD_KEYS];
if (Action)
Action->setChecked(AddKeys);
mAddKeys = AddKeys;
}
void lcMainWindow::UpdateLockSnap()
{
if (GetRelativeTransform())
mActions[LC_EDIT_TRANSFORM_RELATIVE]->setChecked(true);
else
mActions[LC_EDIT_TRANSFORM_ABSOLUTE]->setChecked(true);
if (GetSeparateTransform())
mActions[LC_EDIT_TRANSFORM_SEPARATELY]->setChecked(true);
else
mActions[LC_EDIT_TRANSFORM_TOGETHER]->setChecked(true);
UpdateSnap();
}
void lcMainWindow::UpdateSnap()
{
mActions[LC_EDIT_SNAP_MOVE_TOGGLE]->setChecked(mMoveSnapEnabled);
mActions[LC_EDIT_SNAP_ANGLE_TOGGLE]->setChecked(mAngleSnapEnabled);
mActions[LC_EDIT_SNAP_MOVE_XY0 + mMoveXYSnapIndex]->setChecked(true);
mActions[LC_EDIT_SNAP_MOVE_Z0 + mMoveZSnapIndex]->setChecked(true);
mActions[LC_EDIT_SNAP_ANGLE0 + mAngleSnapIndex]->setChecked(true);
QString Relative = mRelativeTransform ? tr("Rel") : tr("Abs");
mStatusSnapLabel->setText(QString(tr(" M: %1 %2 R: %3 %4 ")).arg(GetMoveXYSnapText(), GetMoveZSnapText(), GetAngleSnapText(), Relative));
}
void lcMainWindow::UpdateColor()
{
QPixmap Pixmap(14, 14);
Pixmap.fill(QColor::fromRgbF(gColorList[mColorIndex].Value[0], gColorList[mColorIndex].Value[1], gColorList[mColorIndex].Value[2]));
mColorButton->setIcon(Pixmap);
mColorButton->setText(QString(" ") + gColorList[mColorIndex].Name);
mColorList->SetCurrentColor(mColorIndex);
}
void lcMainWindow::UpdateUndoRedo(const QString& UndoText, const QString& RedoText)
{
QAction* UndoAction = mActions[LC_EDIT_UNDO];
QAction* RedoAction = mActions[LC_EDIT_REDO];
if (!UndoText.isEmpty())
{
UndoAction->setEnabled(true);
UndoAction->setText(QString(tr("&Undo %1")).arg(UndoText));
}
else
{
UndoAction->setEnabled(false);
UndoAction->setText(tr("&Undo"));
}
if (!RedoText.isEmpty())
{
RedoAction->setEnabled(true);
RedoAction->setText(QString(tr("&Redo %1")).arg(RedoText));
}
else
{
RedoAction->setEnabled(false);
RedoAction->setText(tr("&Redo"));
}
}
void lcMainWindow::ViewFocusReceived()
{
SetActiveView(qobject_cast<lcView*>(sender()));
}
void lcMainWindow::FileMenuAboutToShow()
{
for (int ActionIdx = LC_FILE_RECENT_FIRST; ActionIdx <= LC_FILE_RECENT_LAST; ActionIdx++)
{
int FileIdx = ActionIdx - LC_FILE_RECENT_FIRST;
QAction* Action = mActions[ActionIdx];
if (!mRecentFiles[FileIdx].isEmpty())
{
Action->setText(QString("&%1 %2").arg(QString::number(FileIdx + 1), QDir::toNativeSeparators(mRecentFiles[FileIdx])));
Action->setVisible(true);
}
else
Action->setVisible(false);
}
mActionFileRecentSeparator->setVisible(!mRecentFiles[0].isEmpty());
}
void lcMainWindow::CameraMenuAboutToShow()
{
const std::vector<std::unique_ptr<lcCamera>>& Cameras = lcGetActiveModel()->GetCameras();
lcView* ActiveView = GetActiveView();
const lcCamera* CurrentCamera = ActiveView ? ActiveView->GetCamera() : nullptr;
bool CurrentSet = false;
for (size_t ActionIndex = LC_VIEW_CAMERA_FIRST; ActionIndex <= LC_VIEW_CAMERA_LAST; ActionIndex++)
{
QAction* Action = mActions[ActionIndex];
size_t CameraIndex = ActionIndex - LC_VIEW_CAMERA_FIRST;
if (CameraIndex < Cameras.size())
{
if (CurrentCamera == Cameras[CameraIndex].get())
{
Action->setChecked(true);
CurrentSet = true;
}
Action->setText(Cameras[CameraIndex]->GetName());
Action->setVisible(true);
}
else
Action->setVisible(false);
}
if (!CurrentSet)
mActions[LC_VIEW_CAMERA_NONE]->setChecked(true);
}
void lcMainWindow::ProjectionMenuAboutToShow()
{
lcView* ActiveView = GetActiveView();
if (ActiveView)
{
if (ActiveView->GetCamera()->GetProjection() == lcCameraProjection::Orthographic)
mActions[LC_VIEW_PROJECTION_ORTHO]->setChecked(true);
else
mActions[LC_VIEW_PROJECTION_PERSPECTIVE]->setChecked(true);
}
}
void lcMainWindow::UpdateShadingMode()
{
mActions[LC_VIEW_SHADING_FIRST + static_cast<int>(lcGetPreferences().mShadingMode)]->setChecked(true);
}
void lcMainWindow::UpdateSelectionMode()
{
switch (mSelectionMode)
{
case lcSelectionMode::Single:
mActions[LC_EDIT_SELECTION_SINGLE]->setChecked(true);
break;
case lcSelectionMode::Piece:
mActions[LC_EDIT_SELECTION_PIECE]->setChecked(true);
break;
case lcSelectionMode::Color:
mActions[LC_EDIT_SELECTION_COLOR]->setChecked(true);
break;
case lcSelectionMode::PieceColor:
mActions[LC_EDIT_SELECTION_PIECE_COLOR]->setChecked(true);
break;
}
}
void lcMainWindow::UpdateModels()
{
const std::vector<std::unique_ptr<lcModel>>& Models = lcGetActiveProject()->GetModels();
lcModel* CurrentModel = lcGetActiveModel();
for (size_t ActionIndex = LC_MODEL_FIRST; ActionIndex <= LC_MODEL_LAST; ActionIndex++)
{
QAction* Action = mActions[ActionIndex];
size_t ModelIndex = ActionIndex - LC_MODEL_FIRST;
if (ModelIndex < Models.size())
{
Action->setChecked(CurrentModel == Models[ModelIndex].get());
Action->setText(QString::fromLatin1("%1%2 %3").arg(ModelIndex < 9 ? QString("&") : QString(), QString::number(ModelIndex + 1), Models[ModelIndex]->GetProperties().mFileName));
Action->setVisible(true);
}
else
Action->setVisible(false);
}
auto HasModel = [&Models](lcModel* Model)
{
return std::find_if(Models.begin(), Models.end(), [Model](const std::unique_ptr<lcModel>& CheckModel) { return CheckModel.get() == Model; }) != Models.end();
};
for (int TabIdx = 0; TabIdx < mModelTabWidget->count(); )
{
lcModelTabWidget* TabWidget = (lcModelTabWidget*)mModelTabWidget->widget(TabIdx);
lcModel* Model = TabWidget->GetModel();
if (!Model)
TabIdx++;
else if (HasModel(Model))
{
mModelTabWidget->setTabText(TabIdx, Model->GetProperties().mFileName);
TabIdx++;
}
else
delete TabWidget;
}
mPartSelectionWidget->UpdateModels();
if (mInsertPieceData && mInsertPieceData->IsModel())
if (!HasModel(mInsertPieceData->GetModel()))
SetInsertPieceData(nullptr);
}
void lcMainWindow::UpdateInUseCategory()
{
mPartSelectionWidget->UpdateInUseCategory();
}
void lcMainWindow::UpdateCategories()
{
mPartSelectionWidget->UpdateCategories();
}
void lcMainWindow::UpdateTitle()
{
setWindowModified(lcGetActiveProject()->IsModified());
setWindowFilePath(lcGetActiveProject()->GetTitle());
}
void lcMainWindow::UpdateModified(bool Modified)
{
setWindowModified(Modified);
}
void lcMainWindow::UpdateShortcuts()
{
for (int ActionIdx = 0; ActionIdx < LC_NUM_COMMANDS; ActionIdx++)
mActions[ActionIdx]->setShortcut(QKeySequence(gKeyboardShortcuts.mShortcuts[ActionIdx]));
}
void lcMainWindow::NewProject()
{
if (!SaveProjectIfModified())
return;
Project* NewProject = new Project();
gApplication->SetProject(NewProject);
}
bool lcMainWindow::OpenProject(const QString& FileName)
{
if (!SaveProjectIfModified())
return false;
QString LoadFileName = FileName;
if (LoadFileName.isEmpty())
{
LoadFileName = lcGetActiveProject()->GetFileName();
if (LoadFileName.isEmpty())
LoadFileName = lcGetProfileString(LC_PROFILE_PROJECTS_PATH);
LoadFileName = QFileDialog::getOpenFileName(this, tr("Open Model"), LoadFileName, tr("Supported Files (*.lcd *.ldr *.dat *.mpd);;All Files (*.*)"));
if (LoadFileName.isEmpty())
return false;
lcSetProfileString(LC_PROFILE_PROJECTS_PATH, QFileInfo(LoadFileName).absolutePath());
}
return OpenProjectFile(LoadFileName);
}
void lcMainWindow::OpenRecentProject(int RecentFileIndex)
{
if (!SaveProjectIfModified())
return;
if (!OpenProjectFile(mRecentFiles[RecentFileIndex]))
RemoveRecentFile(RecentFileIndex);
}
bool lcMainWindow::OpenProjectFile(const QString& FileName)
{
Project* NewProject = new Project();
if (NewProject->Load(FileName, true))
{
gApplication->SetProject(NewProject);
AddRecentFile(FileName);
lcView::UpdateProjectViews(NewProject);
return true;
}
delete NewProject;
lcGetPiecesLibrary()->RemoveTemporaryPieceData();
return false;
}
void lcMainWindow::ShowMergeDialog()
{
QString InitialFolder = lcGetActiveProject()->GetFileName();
if (InitialFolder.isEmpty())
InitialFolder = lcGetProfileString(LC_PROFILE_PROJECTS_PATH);
else
InitialFolder = QFileInfo(InitialFolder).absolutePath();
QStringList LoadFileNames = QFileDialog::getOpenFileNames(this, tr("Merge Model"), InitialFolder, tr("Supported Files (*.lcd *.ldr *.dat *.mpd);;All Files (*.*)"));
if (LoadFileNames.isEmpty())
return;
lcSetProfileString(LC_PROFILE_PROJECTS_PATH, QFileInfo(LoadFileNames.first()).absolutePath());
std::vector<std::unique_ptr<Project>> ProjectsToMerge;
for (const QString& LoadFileName : std::as_const(LoadFileNames))
{
std::unique_ptr<Project>& NewProject = ProjectsToMerge.emplace_back(std::make_unique<Project>());
if (!NewProject->Load(LoadFileName, true))
return;
}
size_t ModelCount = 0;
std::vector<Project*> Sources;
Sources.reserve(ProjectsToMerge.size());
for (const std::unique_ptr<Project>& ProjectToMerge : ProjectsToMerge)
{
ModelCount += ProjectToMerge->GetModels().size();
Sources.push_back(ProjectToMerge.get());
}
const lcResult<void> MergeResult = lcGetActiveProject()->Merge(Sources);
if (!MergeResult)
{
QMessageBox::warning(this, tr("Cannot Merge Model"), MergeResult.error());
return;
}
QMessageBox::information(this, tr("Merge Model"), tr("Merged %n submodels.", nullptr, static_cast<int>(ModelCount)));
UpdateModels();
}
void lcMainWindow::ImportLDD()
{
if (!SaveProjectIfModified())
return;
QString LoadFileName = QFileDialog::getOpenFileName(this, tr("Import"), QString(), tr("LEGO Digital Designer Files (*.lxf);;All Files (*.*)"));
if (LoadFileName.isEmpty())
return;
Project* NewProject = new Project();
if (NewProject->ImportLDD(LoadFileName))
{
gApplication->SetProject(NewProject);
lcView::UpdateProjectViews(NewProject);
}
else
{
delete NewProject;
lcGetPiecesLibrary()->RemoveTemporaryPieceData();
}
}
void lcMainWindow::ImportInventory()
{
if (!SaveProjectIfModified())
return;
lcSetsDatabaseDialog Dialog(this);
if (Dialog.exec() != QDialog::Accepted)
return;
Project* NewProject = new Project();
std::vector<lcSetInventoryItem> SetInventory = Dialog.GetSetInventory();
if (NewProject->ImportInventory(SetInventory, Dialog.GetSetName(), Dialog.GetSetDescription()))
{
gApplication->SetProject(NewProject);
lcView::UpdateProjectViews(NewProject);
}
else
delete NewProject;
}
bool lcMainWindow::SaveProject(const QString& FileName)
{
QString SaveFileName = FileName;
Project* Project = lcGetActiveProject();
if (SaveFileName.isEmpty())
{
SaveFileName = Project->GetFileName();
if (SaveFileName.isEmpty())
SaveFileName = QFileInfo(QDir(lcGetProfileString(LC_PROFILE_PROJECTS_PATH)), Project->GetTitle()).absoluteFilePath();
QString Filter = (Project->GetModels().size() > 1) ? tr("Supported Files (*.mpd);;All Files (*.*)") : tr("Supported Files (*.ldr *.dat *.mpd);;All Files (*.*)");
SaveFileName = QFileDialog::getSaveFileName(this, tr("Save Model"), SaveFileName, Filter);
if (SaveFileName.isEmpty())
return false;
lcSetProfileString(LC_PROFILE_PROJECTS_PATH, QFileInfo(SaveFileName).absolutePath());
}
if (QFileInfo(SaveFileName).suffix().toLower() == QLatin1String("lcd"))
{
QMessageBox::warning(this, tr("Save Model"), tr("Saving files in LCD format is no longer supported. Please use the LDR or MPD formats instead."));
return false;
}
lcResult<void> SaveResult = Project->Save(SaveFileName);
if (!SaveResult)
{
QMessageBox::warning(this, tr("Save Model"), SaveResult.error());
return false;
}
AddRecentFile(SaveFileName);
UpdateTitle();
return true;
}
bool lcMainWindow::SaveProjectIfModified()
{
Project* Project = lcGetActiveProject();
if (!Project->IsModified())
return true;
switch (QMessageBox::question(this, tr("Save Model"), tr("Save changes to '%1'?").arg(Project->GetTitle()), QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel))
{
default:
case QMessageBox::Cancel:
return false;
case QMessageBox::Yes:
if (!SaveProject(Project->GetFileName()))
return false;
break;
case QMessageBox::No:
break;
}
return true;
}
bool lcMainWindow::SetModelFromFocus()
{
lcObject* FocusObject = GetActiveModel()->GetFocusObject();
if (!FocusObject || !FocusObject->IsPiece())
return false;
lcModel* Model = ((lcPiece*)FocusObject)->mPieceData->GetModel();
if (Model)
{
Project* Project = lcGetActiveProject();
Project->SetActiveModel(Model, true);
return true;
}
return false;
}
void lcMainWindow::SetModelFromSelection()
{
if (SetModelFromFocus())
return;
lcModel* Model = GetActiveModel()->GetFirstSelectedSubmodel();
if (Model)
{
Project* Project = lcGetActiveProject();
Project->SetActiveModel(Model, true);
}
}
lcModel* lcMainWindow::GetActiveModel() const
{
lcView* ActiveView = GetActiveView();
return ActiveView ? ActiveView->GetActiveModel() : nullptr;
}
lcModelTabWidget* lcMainWindow::GetTabForView(lcView* View) const
{
QWidget* Widget = View->GetWidget();
while (Widget)
{
lcModelTabWidget* TabWidget = qobject_cast<lcModelTabWidget*>(Widget);
if (TabWidget)
return TabWidget;
else
Widget = Widget->parentWidget();
}
return nullptr;
}
void lcMainWindow::HandleCommand(lcCommandId CommandId)
{
lcView* ActiveView = GetActiveView();
if (ActiveView && CommandId != LC_EDIT_CANCEL)
ActiveView->StopTracking(true);
lcModel* ActiveModel = ActiveView ? ActiveView->GetActiveModel() : nullptr;
switch (CommandId)
{
case LC_FILE_NEW:
NewProject();
break;
case LC_FILE_OPEN:
OpenProject(QString());
break;
case LC_FILE_MERGE:
ShowMergeDialog();
break;
case LC_FILE_SAVE:
SaveProject(lcGetActiveProject()->GetFileName());
break;
case LC_FILE_SAVEAS:
SaveProject(QString());
break;
case LC_FILE_SAVE_IMAGE:
ShowImageDialog();
break;
case LC_FILE_IMPORT_LDD:
ImportLDD();
break;
case LC_FILE_IMPORT_INVENTORY:
ImportInventory();
break;
case LC_FILE_EXPORT_3DS:
ShowResultError(lcGetActiveProject()->Export3DStudio(QString()), tr("Export 3DS"));
break;
case LC_FILE_EXPORT_COLLADA:
ShowResultError(lcGetActiveProject()->ExportCOLLADA(QString()), tr("Export COLLADA"));
break;
case LC_FILE_EXPORT_HTML:
ShowHTMLDialog();
break;
case LC_FILE_EXPORT_BRICKLINK:
ShowResultError(lcGetActiveProject()->ExportBrickLink(), tr("Export BrickLink"));
break;
case LC_FILE_EXPORT_CSV:
ShowResultError(lcGetActiveProject()->ExportCSV(QString()), tr("Export CSV"));
break;
case LC_FILE_EXPORT_POVRAY:
ShowExportPOVRayDialog();
break;
case LC_FILE_EXPORT_WAVEFRONT:
ShowResultError(lcGetActiveProject()->ExportWavefront(QString()), tr("Export Wavefront"));
break;
case LC_FILE_RENDER_POVRAY:
ShowRenderDialog(lcRenderDialogMode::RenderPOVRay);
break;
case LC_FILE_RENDER_BLENDER:
ShowRenderDialog(lcRenderDialogMode::RenderBlender);
break;
case LC_FILE_RENDER_OPEN_IN_BLENDER:
ShowRenderDialog(lcRenderDialogMode::OpenInBlender);
break;
case LC_FILE_INSTRUCTIONS:
ShowInstructionsDialog();
break;
case LC_FILE_PRINT_PREVIEW:
TogglePrintPreview();
break;
case LC_FILE_PRINT:
ShowPrintDialog();
break;
case LC_FILE_RECENT1:
case LC_FILE_RECENT2:
case LC_FILE_RECENT3:
case LC_FILE_RECENT4:
OpenRecentProject(CommandId - LC_FILE_RECENT1);
break;
case LC_FILE_EXIT:
close();
break;
case LC_EDIT_UNDO:
if (ActiveModel)
ActiveModel->UndoAction();
break;
case LC_EDIT_REDO:
if (ActiveModel)
ActiveModel->RedoAction();
break;
case LC_EDIT_CUT:
if (ActiveModel)
ShowResultError(ActiveModel->Cut(), tr("Cannot Cut Model"));
break;
case LC_EDIT_COPY:
if (ActiveModel)
ShowResultError(ActiveModel->Copy(), tr("Cannot Copy Model"));
break;
case LC_EDIT_PASTE:
if (ActiveModel)
ShowResultError(ActiveModel->Paste(true), tr("Cannot Paste Model"));
break;
case LC_EDIT_PASTE_STEPS:
if (ActiveModel)
ShowResultError(ActiveModel->Paste(false), tr("Cannot Paste Model"));
break;
case LC_EDIT_FIND:
if (ActiveView)
ActiveView->ShowFindReplaceWidget(false);
break;
case LC_EDIT_FIND_NEXT:
if (ActiveModel)
ActiveModel->FindReplacePiece(true, false, false);
break;
case LC_EDIT_FIND_PREVIOUS:
if (ActiveModel)
ActiveModel->FindReplacePiece(false, false, false);
break;
case LC_EDIT_FIND_ALL:
if (ActiveModel)
ActiveModel->FindReplacePiece(true, true, false);
break;
case LC_EDIT_REPLACE:
if (ActiveView)
ActiveView->ShowFindReplaceWidget(true);
break;
case LC_EDIT_REPLACE_ALL:
if (ActiveModel)
ActiveModel->FindReplacePiece(true, true, true);
break;
case LC_EDIT_REPLACE_NEXT:
if (ActiveModel)
ActiveModel->FindReplacePiece(true, false, true);
break;
case LC_EDIT_SELECT_ALL:
if (ActiveModel)
ActiveModel->SelectAllPiecesAction();
break;
case LC_EDIT_SELECT_NONE:
if (ActiveModel)
ActiveModel->ClearSelectionAction();
break;
case LC_EDIT_SELECT_INVERT:
if (ActiveModel)
ActiveModel->InvertPieceSelectionAction();
break;
case LC_EDIT_SELECT_BY_NAME:
ShowSelectDialog();
break;
case LC_EDIT_SELECTION_SINGLE:
SetSelectionMode(lcSelectionMode::Single);
break;
case LC_EDIT_SELECTION_PIECE:
SetSelectionMode(lcSelectionMode::Piece);
break;
case LC_EDIT_SELECTION_COLOR:
SetSelectionMode(lcSelectionMode::Color);
break;
case LC_EDIT_SELECTION_PIECE_COLOR:
SetSelectionMode(lcSelectionMode::PieceColor);
break;
case LC_VIEW_SPLIT_HORIZONTAL:
SplitHorizontal();
break;
case LC_VIEW_SPLIT_VERTICAL:
SplitVertical();
break;
case LC_VIEW_REMOVE_VIEW:
RemoveActiveView();
break;
case LC_VIEW_RESET_VIEWS:
ResetViews();
break;
case LC_VIEW_TOOLBAR_STANDARD:
ToggleDockWidget(mStandardToolBar);
break;
case LC_VIEW_TOOLBAR_TOOLS:
ToggleDockWidget(mToolsToolBar);
break;
case LC_VIEW_TOOLBAR_TIME:
ToggleDockWidget(mTimeToolBar);
break;
case LC_VIEW_TOOLBAR_PARTS:
ToggleDockWidget(mPartsToolBar);
if (mPartsToolBar->isVisible())
mPartSelectionWidget->FocusPartFilterWidget();
break;
case LC_VIEW_TOOLBAR_COLORS:
ToggleDockWidget(mColorsToolBar);
break;
case LC_VIEW_TOOLBAR_PROPERTIES:
ToggleDockWidget(mPropertiesToolBar);
break;
case LC_VIEW_TOOLBAR_TIMELINE:
ToggleDockWidget(mTimelineToolBar);
break;
case LC_VIEW_TOOLBAR_PREVIEW:
ToggleDockWidget(mPreviewToolBar);
break;
case LC_VIEW_FULLSCREEN:
ToggleFullScreen();
break;
case LC_VIEW_CLOSE_CURRENT_TAB:
CloseCurrentModelTab();
break;
case LC_VIEW_SHADING_WIREFRAME:
SetShadingMode(lcShadingMode::Wireframe);
break;
case LC_VIEW_SHADING_FLAT:
SetShadingMode(lcShadingMode::Flat);
break;
case LC_VIEW_SHADING_DEFAULT_LIGHTS:
SetShadingMode(lcShadingMode::DefaultLights);
break;
case LC_VIEW_PROJECTION_PERSPECTIVE:
if (ActiveView)
ActiveView->SetCameraProjection(lcCameraProjection::Perspective);
break;
case LC_VIEW_PROJECTION_ORTHO:
if (ActiveView)
ActiveView->SetCameraProjection(lcCameraProjection::Orthographic);
break;
case LC_VIEW_TOGGLE_VIEW_SPHERE:
ToggleViewSphere();
break;
case LC_VIEW_TOGGLE_AXIS_ICON:
ToggleAxisIcon();
break;
case LC_VIEW_TOGGLE_GRID:
ToggleGrid();
break;
case LC_VIEW_FADE_PREVIOUS_STEPS:
ToggleFadePreviousSteps();
break;
case LC_PIECE_INSERT:
if (ActiveModel)
ActiveModel->AddPiece(nullptr, LC_PIECE_SECTION_INVALID);
break;
case LC_PIECE_DELETE:
if (ActiveModel)
ActiveModel->DeleteSelectedObjects();
break;
case LC_PIECE_DUPLICATE:
if (ActiveModel)
ActiveModel->DuplicateSelectedPieces();
break;
case LC_PIECE_PAINT_SELECTED:
if (ActiveModel)
ActiveModel->PaintSelectedPieces();
break;
case LC_PIECE_RESET_PIVOT_POINT:
if (ActiveModel)
ActiveModel->ResetSelectedPiecesPivotPoint();
break;
case LC_PIECE_REMOVE_KEY_FRAMES:
if (ActiveModel)
ActiveModel->RemoveSelectedObjectsKeyFrames();
break;
case LC_PIECE_CONTROL_POINT_INSERT:
if (ActiveModel)
ActiveModel->InsertControlPoint();
break;
case LC_PIECE_CONTROL_POINT_REMOVE:
if (ActiveModel)
ActiveModel->RemoveFocusedControlPoint();
break;
case LC_PIECE_TRAIN_TRACK_FOCUS_NEXT:
if (ActiveModel)
ActiveModel->FocusNextTrainTrack();
break;
case LC_PIECE_TRAIN_TRACK_FOCUS_PREVIOUS:
if (ActiveModel)
ActiveModel->FocusPreviousTrainTrack();
break;
case LC_PIECE_TRAIN_TRACK_ROTATE:
if (ActiveModel)
ActiveModel->RotateFocusedTrainTrack(1);
break;
case LC_PIECE_MOVE_PLUSX:
if (ActiveModel)
ActiveModel->MoveSelectedObjects(ActiveView->GetMoveDirection(lcVector3(lcMax(GetMoveXYSnap(), 0.1f), 0.0f, 0.0f)), lcModelTransformFlag::Relative | lcModelTransformFlag::Checkpoint | lcModelTransformFlag::FirstMove, lcModelHistoryEditMerge::KeyboardMove);
break;
case LC_PIECE_MOVE_MINUSX:
if (ActiveModel)
ActiveModel->MoveSelectedObjects(ActiveView->GetMoveDirection(lcVector3(-lcMax(GetMoveXYSnap(), 0.1f), 0.0f, 0.0f)), lcModelTransformFlag::Relative | lcModelTransformFlag::Checkpoint | lcModelTransformFlag::FirstMove, lcModelHistoryEditMerge::KeyboardMove);
break;
case LC_PIECE_MOVE_PLUSY:
if (ActiveModel)
ActiveModel->MoveSelectedObjects(ActiveView->GetMoveDirection(lcVector3(0.0f, lcMax(GetMoveXYSnap(), 0.1f), 0.0f)), lcModelTransformFlag::Relative | lcModelTransformFlag::Checkpoint | lcModelTransformFlag::FirstMove, lcModelHistoryEditMerge::KeyboardMove);
break;
case LC_PIECE_MOVE_MINUSY:
if (ActiveModel)
ActiveModel->MoveSelectedObjects(ActiveView->GetMoveDirection(lcVector3(0.0f, -lcMax(GetMoveXYSnap(), 0.1f), 0.0f)), lcModelTransformFlag::Relative | lcModelTransformFlag::Checkpoint | lcModelTransformFlag::FirstMove, lcModelHistoryEditMerge::KeyboardMove);
break;
case LC_PIECE_MOVE_PLUSZ:
if (ActiveModel)
ActiveModel->MoveSelectedObjects(ActiveView->GetMoveDirection(lcVector3(0.0f, 0.0f, lcMax(GetMoveZSnap(), 0.1f))), lcModelTransformFlag::Relative | lcModelTransformFlag::Checkpoint | lcModelTransformFlag::FirstMove, lcModelHistoryEditMerge::KeyboardMove);
break;
case LC_PIECE_MOVE_MINUSZ:
if (ActiveModel)
ActiveModel->MoveSelectedObjects(ActiveView->GetMoveDirection(lcVector3(0.0f, 0.0f, -lcMax(GetMoveZSnap(), 0.1f))), lcModelTransformFlag::Relative | lcModelTransformFlag::Checkpoint | lcModelTransformFlag::FirstMove, lcModelHistoryEditMerge::KeyboardMove);
break;
case LC_PIECE_ROTATE_PLUSX:
if (ActiveModel)
ActiveModel->RotateSelectedObjects(ActiveView->GetMoveDirection(lcVector3(lcMax(GetAngleSnap(), 1.0f), 0.0f, 0.0f)), lcModelTransformFlag::Relative | lcModelTransformFlag::Checkpoint, lcModelHistoryEditMerge::KeyboardRotate);
break;
case LC_PIECE_ROTATE_MINUSX:
if (ActiveModel)
ActiveModel->RotateSelectedObjects(ActiveView->GetMoveDirection(lcVector3(-lcMax(GetAngleSnap(), 1.0f), 0.0f, 0.0f)), lcModelTransformFlag::Relative | lcModelTransformFlag::Checkpoint, lcModelHistoryEditMerge::KeyboardRotate);
break;
case LC_PIECE_ROTATE_PLUSY:
if (ActiveModel)
ActiveModel->RotateSelectedObjects(ActiveView->GetMoveDirection(lcVector3(0.0f, lcMax(GetAngleSnap(), 1.0f), 0.0f)), lcModelTransformFlag::Relative | lcModelTransformFlag::Checkpoint, lcModelHistoryEditMerge::KeyboardRotate);
break;
case LC_PIECE_ROTATE_MINUSY:
if (ActiveModel)
ActiveModel->RotateSelectedObjects(ActiveView->GetMoveDirection(lcVector3(0.0f, -lcMax(GetAngleSnap(), 1.0f), 0.0f)), lcModelTransformFlag::Relative | lcModelTransformFlag::Checkpoint, lcModelHistoryEditMerge::KeyboardRotate);
break;
case LC_PIECE_ROTATE_PLUSZ:
if (ActiveModel)
ActiveModel->RotateSelectedObjects(ActiveView->GetMoveDirection(lcVector3(0.0f, 0.0f, lcMax(GetAngleSnap(), 1.0f))), lcModelTransformFlag::Relative | lcModelTransformFlag::Checkpoint, lcModelHistoryEditMerge::KeyboardRotate);
break;
case LC_PIECE_ROTATE_MINUSZ:
if (ActiveModel)
ActiveModel->RotateSelectedObjects(ActiveView->GetMoveDirection(lcVector3(0.0f, 0.0f, -lcMax(GetAngleSnap(), 1.0f))), lcModelTransformFlag::Relative | lcModelTransformFlag::Checkpoint, lcModelHistoryEditMerge::KeyboardRotate);
break;
case LC_PIECE_MINIFIG_WIZARD:
if (ActiveModel)
ActiveModel->ShowMinifigDialog();
break;
case LC_PIECE_ARRAY:
if (ActiveModel)
ActiveModel->ShowArrayDialog();
break;
case LC_PIECE_VIEW_SELECTED_MODEL:
SetModelFromSelection();
break;
case LC_PIECE_MOVE_SELECTION_TO_MODEL:
if (ActiveModel)
ActiveModel->MoveSelectionToModel(lcGetActiveProject()->CreateNewModel(false));
break;
case LC_PIECE_INLINE_SELECTED_MODELS:
if (ActiveModel)
ActiveModel->InlineSelectedModels();
break;
case LC_PIECE_EDIT_END_SUBMODEL:
if (ActiveView)
{
ActiveView->SetTopSubmodelActive();
if (ActiveModel)
{
std::vector<lcModel*> UpdatedModels;
ActiveModel->UpdatePieceData(UpdatedModels);
}
}
break;
case LC_PIECE_EDIT_SELECTED_SUBMODEL:
if (ActiveView)
ActiveView->SetSelectedSubmodelActive();
break;
case LC_PIECE_GROUP:
if (ActiveModel)
ActiveModel->GroupSelection();
break;
case LC_PIECE_UNGROUP:
if (ActiveModel)
ActiveModel->UngroupSelection();
break;
case LC_PIECE_GROUP_ADD:
if (ActiveModel)
ActiveModel->AddSelectedPiecesToGroup();
break;
case LC_PIECE_GROUP_REMOVE:
if (ActiveModel)
ActiveModel->RemoveFocusPieceFromGroup();
break;
case LC_PIECE_GROUP_EDIT:
if (ActiveModel)
ActiveModel->ShowEditGroupsDialog();
break;
case LC_PIECE_HIDE_SELECTED:
if (ActiveModel)
ActiveModel->HideSelectedPieces();
break;
case LC_PIECE_HIDE_UNSELECTED:
if (ActiveModel)
ActiveModel->HideUnselectedPieces();
break;
case LC_PIECE_UNHIDE_SELECTED:
if (ActiveModel)
ActiveModel->UnhideSelectedPieces();
break;
case LC_PIECE_UNHIDE_ALL:
if (ActiveModel)
ActiveModel->UnhideAllPieces();
break;
case LC_PIECE_SHOW_EARLIER:
if (ActiveModel)
ActiveModel->ShowSelectedPiecesEarlier();
break;
case LC_PIECE_SHOW_LATER:
if (ActiveModel)
ActiveModel->ShowSelectedPiecesLater();
break;
case LC_VIEW_PREFERENCES:
gApplication->ShowPreferencesDialog();
break;
case LC_VIEW_ZOOM_IN:
if (ActiveView)
ActiveView->Zoom(10.0f);
break;
case LC_VIEW_ZOOM_OUT:
if (ActiveView)
ActiveView->Zoom(-10.0f);
break;
case LC_VIEW_ZOOM_EXTENTS:
if (ActiveView)
ActiveView->ZoomExtents(lcGeometryBoundsMode::IncludeFallback, false);
break;
case LC_VIEW_LOOK_AT:
if (ActiveView)
ActiveView->LookAt();
break;
case LC_VIEW_MOVE_FORWARD:
if (ActiveView)
ActiveView->MoveCamera(lcVector3(0.0f, 0.0f, -1.0f));
break;
case LC_VIEW_MOVE_BACKWARD:
if (ActiveView)
ActiveView->MoveCamera(lcVector3(0.0f, 0.0f, 1.0f));
break;
case LC_VIEW_MOVE_LEFT:
if (ActiveView)
ActiveView->MoveCamera(lcVector3(-1.0f, 0.0f, 0.0f));
break;
case LC_VIEW_MOVE_RIGHT:
if (ActiveView)
ActiveView->MoveCamera(lcVector3(1.0f, 0.0f, 0.0f));
break;
case LC_VIEW_MOVE_UP:
if (ActiveView)
ActiveView->MoveCamera(lcVector3(0.0f, 1.0f, 0.0f));
break;
case LC_VIEW_MOVE_DOWN:
if (ActiveView)
ActiveView->MoveCamera(lcVector3(0.0f, -1.0f, 0.0f));
break;
case LC_VIEW_TIME_NEXT:
if (ActiveModel)
ActiveModel->ShowNextStep();
break;
case LC_VIEW_TIME_PREVIOUS:
if (ActiveModel)
ActiveModel->ShowPreviousStep();
break;
case LC_VIEW_TIME_FIRST:
if (ActiveModel)
ActiveModel->ShowFirstStep();
break;
case LC_VIEW_TIME_LAST:
if (ActiveModel)
ActiveModel->ShowLastStep();
break;
case LC_VIEW_TIME_INSERT_BEFORE:
lcGetActiveModel()->InsertStepAction(lcGetActiveModel()->GetCurrentStep());
break;
case LC_VIEW_TIME_INSERT_AFTER:
lcGetActiveModel()->InsertStepAction(lcGetActiveModel()->GetCurrentStep() + 1);
break;
case LC_VIEW_TIME_DELETE:
lcGetActiveModel()->RemoveStepAction(lcGetActiveModel()->GetCurrentStep());
break;
case LC_VIEW_VIEWPOINT_FRONT:
if (ActiveView)
ActiveView->SetViewpoint(lcViewpoint::Front);
break;
case LC_VIEW_VIEWPOINT_BACK:
if (ActiveView)
ActiveView->SetViewpoint(lcViewpoint::Back);
break;
case LC_VIEW_VIEWPOINT_TOP:
if (ActiveView)
ActiveView->SetViewpoint(lcViewpoint::Top);
break;
case LC_VIEW_VIEWPOINT_BOTTOM:
if (ActiveView)
ActiveView->SetViewpoint(lcViewpoint::Bottom);
break;
case LC_VIEW_VIEWPOINT_LEFT:
if (ActiveView)
ActiveView->SetViewpoint(lcViewpoint::Left);
break;
case LC_VIEW_VIEWPOINT_RIGHT:
if (ActiveView)
ActiveView->SetViewpoint(lcViewpoint::Right);
break;
case LC_VIEW_VIEWPOINT_HOME:
if (ActiveView)
ActiveView->SetViewpoint(lcViewpoint::Home);
break;
case LC_VIEW_CAMERA_NONE:
if (ActiveView)
ActiveView->RemoveCamera();
break;
case LC_VIEW_CAMERA1:
case LC_VIEW_CAMERA2:
case LC_VIEW_CAMERA3:
case LC_VIEW_CAMERA4:
case LC_VIEW_CAMERA5:
case LC_VIEW_CAMERA6:
case LC_VIEW_CAMERA7:
case LC_VIEW_CAMERA8:
case LC_VIEW_CAMERA9:
case LC_VIEW_CAMERA10:
case LC_VIEW_CAMERA11:
case LC_VIEW_CAMERA12:
case LC_VIEW_CAMERA13:
case LC_VIEW_CAMERA14:
case LC_VIEW_CAMERA15:
case LC_VIEW_CAMERA16:
if (ActiveView)
ActiveView->SetCameraIndex(CommandId - LC_VIEW_CAMERA1);
break;
case LC_MODEL_NEW:
lcGetActiveProject()->CreateNewModel(true);
break;
case LC_MODEL_PROPERTIES:
lcGetActiveModel()->ShowPropertiesDialog();
break;
case LC_MODEL_LIST:
lcGetActiveProject()->ShowModelListDialog();
break;
case LC_MODEL_01:
case LC_MODEL_02:
case LC_MODEL_03:
case LC_MODEL_04:
case LC_MODEL_05:
case LC_MODEL_06:
case LC_MODEL_07:
case LC_MODEL_08:
case LC_MODEL_09:
case LC_MODEL_10:
case LC_MODEL_11:
case LC_MODEL_12:
case LC_MODEL_13:
case LC_MODEL_14:
case LC_MODEL_15:
case LC_MODEL_16:
case LC_MODEL_17:
case LC_MODEL_18:
case LC_MODEL_19:
case LC_MODEL_20:
case LC_MODEL_21:
case LC_MODEL_22:
case LC_MODEL_23:
case LC_MODEL_24:
case LC_MODEL_25:
case LC_MODEL_26:
case LC_MODEL_27:
case LC_MODEL_28:
case LC_MODEL_29:
case LC_MODEL_30:
case LC_MODEL_31:
case LC_MODEL_32:
case LC_MODEL_33:
case LC_MODEL_34:
case LC_MODEL_35:
case LC_MODEL_36:
case LC_MODEL_37:
case LC_MODEL_38:
case LC_MODEL_39:
case LC_MODEL_40:
lcGetActiveProject()->SetActiveModel(CommandId - LC_MODEL_01, true);
break;
case LC_HELP_WHATS_THIS:
QWhatsThis::enterWhatsThisMode();
break;
case LC_HELP_HOMEPAGE:
QDesktopServices::openUrl(QUrl("https://www.leocad.org/"));
break;
case LC_HELP_BUG_REPORT:
QDesktopServices::openUrl(QUrl("https://github.com/leozide/leocad/issues"));
break;
case LC_HELP_UPDATES:
ShowUpdatesDialog();
break;
case LC_HELP_ABOUT:
ShowAboutDialog();
break;
case LC_VIEW_TIME_ADD_KEYS:
SetAddKeys(!GetAddKeys());
break;
case LC_EDIT_TRANSFORM_RELATIVE:
SetRelativeTransform(true);
break;
case LC_EDIT_TRANSFORM_ABSOLUTE:
SetRelativeTransform(false);
break;
case LC_EDIT_TRANSFORM_TOGGLE_RELATIVE:
SetRelativeTransform(!GetRelativeTransform());
break;
case LC_EDIT_TRANSFORM_SEPARATELY:
SetSeparateTransform(true);
break;
case LC_EDIT_TRANSFORM_TOGETHER:
SetSeparateTransform(false);
break;
case LC_EDIT_TRANSFORM_TOGGLE_SEPARATE:
SetSeparateTransform(!GetSeparateTransform());
break;
case LC_EDIT_SNAP_MOVE_TOGGLE:
SetMoveSnapEnabled(!mMoveSnapEnabled);
break;
case LC_EDIT_SNAP_MOVE_XY0:
case LC_EDIT_SNAP_MOVE_XY1:
case LC_EDIT_SNAP_MOVE_XY2:
case LC_EDIT_SNAP_MOVE_XY3:
case LC_EDIT_SNAP_MOVE_XY4:
case LC_EDIT_SNAP_MOVE_XY5:
case LC_EDIT_SNAP_MOVE_XY6:
case LC_EDIT_SNAP_MOVE_XY7:
case LC_EDIT_SNAP_MOVE_XY8:
case LC_EDIT_SNAP_MOVE_XY9:
SetMoveXYSnapIndex(CommandId - LC_EDIT_SNAP_MOVE_XY0);
break;
case LC_EDIT_SNAP_MOVE_Z0:
case LC_EDIT_SNAP_MOVE_Z1:
case LC_EDIT_SNAP_MOVE_Z2:
case LC_EDIT_SNAP_MOVE_Z3:
case LC_EDIT_SNAP_MOVE_Z4:
case LC_EDIT_SNAP_MOVE_Z5:
case LC_EDIT_SNAP_MOVE_Z6:
case LC_EDIT_SNAP_MOVE_Z7:
case LC_EDIT_SNAP_MOVE_Z8:
case LC_EDIT_SNAP_MOVE_Z9:
SetMoveZSnapIndex(CommandId - LC_EDIT_SNAP_MOVE_Z0);
break;
case LC_EDIT_SNAP_ANGLE_TOGGLE:
SetAngleSnapEnabled(!mAngleSnapEnabled);
break;
case LC_EDIT_SNAP_ANGLE0:
case LC_EDIT_SNAP_ANGLE1:
case LC_EDIT_SNAP_ANGLE2:
case LC_EDIT_SNAP_ANGLE3:
case LC_EDIT_SNAP_ANGLE4:
case LC_EDIT_SNAP_ANGLE5:
case LC_EDIT_SNAP_ANGLE6:
case LC_EDIT_SNAP_ANGLE7:
case LC_EDIT_SNAP_ANGLE8:
case LC_EDIT_SNAP_ANGLE9:
SetAngleSnapIndex(CommandId - LC_EDIT_SNAP_ANGLE0);
break;
case LC_EDIT_TRANSFORM:
if (ActiveModel)
ActiveModel->TransformSelectedObjects(GetTransformType(), GetTransformAmount());
break;
case LC_EDIT_TRANSFORM_ABSOLUTE_TRANSLATION:
SetTransformType(lcTransformType::AbsoluteTranslation);
break;
case LC_EDIT_TRANSFORM_RELATIVE_TRANSLATION:
SetTransformType(lcTransformType::RelativeTranslation);
break;
case LC_EDIT_TRANSFORM_ABSOLUTE_ROTATION:
SetTransformType(lcTransformType::AbsoluteRotation);
break;
case LC_EDIT_TRANSFORM_RELATIVE_ROTATION:
SetTransformType(lcTransformType::RelativeRotation);
break;
case LC_EDIT_ACTION_SELECT:
SetTool(lcTool::Select);
break;
case LC_EDIT_ACTION_INSERT:
SetTool(lcTool::Insert);
break;
case LC_EDIT_ACTION_POINT_LIGHT:
SetTool(lcTool::PointLight);
break;
case LC_EDIT_ACTION_AREA_LIGHT:
SetTool(lcTool::AreaLight);
break;
case LC_EDIT_ACTION_DIRECTIONAL_LIGHT:
SetTool(lcTool::DirectionalLight);
break;
case LC_EDIT_ACTION_SPOTLIGHT:
SetTool(lcTool::SpotLight);
break;
case LC_EDIT_ACTION_CAMERA:
SetTool(lcTool::Camera);
break;
case LC_EDIT_ACTION_MOVE:
SetTool(lcTool::Move);
break;
case LC_EDIT_ACTION_ROTATE:
SetTool(lcTool::Rotate);
break;
case LC_EDIT_ACTION_DELETE:
SetTool(lcTool::Eraser);
break;
case LC_EDIT_ACTION_PAINT:
SetTool(lcTool::Paint);
break;
case LC_EDIT_ACTION_COLOR_PICKER:
SetTool(lcTool::ColorPicker);
break;
case LC_EDIT_ACTION_ZOOM:
SetTool(lcTool::Zoom);
break;
case LC_EDIT_ACTION_ZOOM_REGION:
SetTool(lcTool::ZoomRegion);
break;
case LC_EDIT_ACTION_PAN:
SetTool(lcTool::Pan);
break;
case LC_EDIT_ACTION_ROTATE_VIEW:
SetTool(lcTool::RotateView);
break;
case LC_EDIT_ACTION_ROLL:
SetTool(lcTool::Roll);
break;
case LC_EDIT_CANCEL:
if (ActiveView && !ActiveView->CloseFindReplaceDialog())
ActiveView->CancelTrackingOrClearSelectionAction();
break;
case LC_TIMELINE_INSERT_BEFORE:
mTimelineWidget->InsertStepBefore();
break;
case LC_TIMELINE_INSERT_AFTER:
mTimelineWidget->InsertStepAfter();
break;
case LC_TIMELINE_DELETE:
mTimelineWidget->RemoveStep();
break;
case LC_TIMELINE_MOVE_SELECTION:
mTimelineWidget->MoveSelection();
break;
case LC_TIMELINE_MOVE_SELECTION_BEFORE:
mTimelineWidget->MoveSelectionBefore();
break;
case LC_TIMELINE_MOVE_SELECTION_AFTER:
mTimelineWidget->MoveSelectionAfter();
break;
case LC_TIMELINE_SET_CURRENT:
mTimelineWidget->SetCurrentStep();
break;
case LC_NUM_COMMANDS:
break;
}
}