leocad/common/lc_application.cpp

1330 lines
46 KiB
C++
Raw Normal View History

2013-08-09 06:57:18 +02:00
#include "lc_global.h"
#include <stdio.h>
#include "lc_application.h"
#include "lc_library.h"
#include "lc_profile.h"
#include "project.h"
2013-08-16 03:25:51 +02:00
#include "lc_mainwindow.h"
2017-12-11 03:12:31 +01:00
#include "lc_qpreferencesdialog.h"
#include "lc_partselectionwidget.h"
2013-08-09 06:57:18 +02:00
#include "lc_shortcuts.h"
2020-12-25 19:43:22 +01:00
#include "lc_view.h"
#include "camera.h"
#include "lc_previewwidget.h"
2013-08-09 06:57:18 +02:00
lcApplication* gApplication;
2013-08-09 06:57:18 +02:00
void lcPreferences::LoadDefaults()
{
2014-10-05 07:21:51 +02:00
mFixedAxes = lcGetProfileInt(LC_PROFILE_FIXED_AXES);
mMouseSensitivity = lcGetProfileInt(LC_PROFILE_MOUSE_SENSITIVITY);
2020-03-22 21:44:20 +01:00
mShadingMode = static_cast<lcShadingMode>(lcGetProfileInt(LC_PROFILE_SHADING_MODE));
mBackgroundGradient = lcGetProfileInt(LC_PROFILE_BACKGROUND_GRADIENT);
mBackgroundSolidColor = lcGetProfileInt(LC_PROFILE_BACKGROUND_COLOR);
mBackgroundGradientColorTop = lcGetProfileInt(LC_PROFILE_GRADIENT_COLOR_TOP);
mBackgroundGradientColorBottom = lcGetProfileInt(LC_PROFILE_GRADIENT_COLOR_BOTTOM);
mDrawAxes = lcGetProfileInt(LC_PROFILE_DRAW_AXES);
mAxesColor = lcGetProfileInt(LC_PROFILE_AXES_COLOR);
2020-12-30 22:44:08 +01:00
mTextColor = lcGetProfileInt(LC_PROFILE_TEXT_COLOR);
mMarqueeBorderColor = lcGetProfileInt(LC_PROFILE_MARQUEE_BORDER_COLOR);
mMarqueeFillColor = lcGetProfileInt(LC_PROFILE_MARQUEE_FILL_COLOR);
mOverlayColor = lcGetProfileInt(LC_PROFILE_OVERLAY_COLOR);
2020-07-25 22:21:22 +02:00
mActiveViewColor = lcGetProfileInt(LC_PROFILE_ACTIVE_VIEW_COLOR);
2020-12-12 03:01:04 +01:00
mInactiveViewColor = lcGetProfileInt(LC_PROFILE_INACTIVE_VIEW_COLOR);
mDrawEdgeLines = lcGetProfileInt(LC_PROFILE_DRAW_EDGE_LINES);
2021-03-07 18:53:35 +01:00
mDrawConditionalLines = lcGetProfileInt(LC_PROFILE_DRAW_CONDITIONAL_LINES);
mLineWidth = lcGetProfileFloat(LC_PROFILE_LINE_WIDTH);
2019-11-28 22:52:06 +01:00
mAllowLOD = lcGetProfileInt(LC_PROFILE_ALLOW_LOD);
2020-08-16 01:16:26 +02:00
mMeshLODDistance = lcGetProfileFloat(LC_PROFILE_LOD_DISTANCE);
2020-01-02 02:06:17 +01:00
mFadeSteps = lcGetProfileInt(LC_PROFILE_FADE_STEPS);
2020-04-25 21:16:37 +02:00
mFadeStepsColor = lcGetProfileInt(LC_PROFILE_FADE_STEPS_COLOR);
mHighlightNewParts = lcGetProfileInt(LC_PROFILE_HIGHLIGHT_NEW_PARTS);
mHighlightNewPartsColor = lcGetProfileInt(LC_PROFILE_HIGHLIGHT_NEW_PARTS_COLOR);
mDrawGridStuds = lcGetProfileInt(LC_PROFILE_GRID_STUDS);
mGridStudColor = lcGetProfileInt(LC_PROFILE_GRID_STUD_COLOR);
mDrawGridLines = lcGetProfileInt(LC_PROFILE_GRID_LINES);
mGridLineSpacing = lcGetProfileInt(LC_PROFILE_GRID_LINE_SPACING);
mGridLineColor = lcGetProfileInt(LC_PROFILE_GRID_LINE_COLOR);
mDrawGridOrigin = lcGetProfileInt(LC_PROFILE_GRID_ORIGIN);
2020-01-05 20:38:24 +01:00
mViewSphereEnabled = lcGetProfileInt(LC_PROFILE_VIEW_SPHERE_ENABLED);
2020-03-22 21:44:20 +01:00
mViewSphereLocation = static_cast<lcViewSphereLocation>(lcGetProfileInt(LC_PROFILE_VIEW_SPHERE_LOCATION));
2018-10-29 01:59:01 +01:00
mViewSphereSize = lcGetProfileInt(LC_PROFILE_VIEW_SPHERE_SIZE);
2019-01-20 20:59:18 +01:00
mViewSphereColor = lcGetProfileInt(LC_PROFILE_VIEW_SPHERE_COLOR);
mViewSphereTextColor = lcGetProfileInt(LC_PROFILE_VIEW_SPHERE_TEXT_COLOR);
mViewSphereHighlightColor = lcGetProfileInt(LC_PROFILE_VIEW_SPHERE_HIGHLIGHT_COLOR);
2019-03-10 01:38:54 +01:00
mAutoLoadMostRecent = lcGetProfileInt(LC_PROFILE_AUTOLOAD_MOSTRECENT);
2020-01-02 02:06:17 +01:00
mRestoreTabLayout = lcGetProfileInt(LC_PROFILE_RESTORE_TAB_LAYOUT);
2020-07-25 22:21:22 +02:00
mColorTheme = static_cast<lcColorTheme>(lcGetProfileInt(LC_PROFILE_COLOR_THEME));
mPreviewViewSphereEnabled = lcGetProfileInt(LC_PROFILE_PREVIEW_VIEW_SPHERE_ENABLED);
mPreviewViewSphereSize = lcGetProfileInt(LC_PROFILE_PREVIEW_VIEW_SPHERE_SIZE);
mPreviewViewSphereLocation = static_cast<lcViewSphereLocation>(lcGetProfileInt(LC_PROFILE_PREVIEW_VIEW_SPHERE_LOCATION));
mDrawPreviewAxis = lcGetProfileInt(LC_PROFILE_PREVIEW_DRAW_AXES);
2021-01-26 16:42:19 +01:00
mStudCylinderColor = lcGetProfileInt(LC_PROFILE_STUD_CYLINDER_COLOR);
mPartEdgeColor = lcGetProfileInt(LC_PROFILE_PART_EDGE_COLOR);
mBlackEdgeColor = lcGetProfileInt(LC_PROFILE_BLACK_EDGE_COLOR);
mDarkEdgeColor = lcGetProfileInt(LC_PROFILE_DARK_EDGE_COLOR);
2021-01-24 12:53:02 +01:00
mPartEdgeContrast = lcGetProfileFloat(LC_PROFILE_PART_EDGE_CONTRAST);
2021-01-25 08:34:22 +01:00
mPartColorValueLDIndex = lcGetProfileFloat(LC_PROFILE_PART_COLOR_VALUE_LD_INDEX);
2021-01-24 12:53:02 +01:00
mAutomateEdgeColor = lcGetProfileInt(LC_PROFILE_AUTOMATE_EDGE_COLOR);
}
void lcPreferences::SaveDefaults()
{
2014-10-05 07:21:51 +02:00
lcSetProfileInt(LC_PROFILE_FIXED_AXES, mFixedAxes);
lcSetProfileInt(LC_PROFILE_MOUSE_SENSITIVITY, mMouseSensitivity);
2020-03-22 21:44:20 +01:00
lcSetProfileInt(LC_PROFILE_SHADING_MODE, static_cast<int>(mShadingMode));
lcSetProfileInt(LC_PROFILE_DRAW_AXES, mDrawAxes);
lcSetProfileInt(LC_PROFILE_AXES_COLOR, mAxesColor);
2020-12-30 22:44:08 +01:00
lcSetProfileInt(LC_PROFILE_TEXT_COLOR, mTextColor);
lcSetProfileInt(LC_PROFILE_BACKGROUND_GRADIENT, mBackgroundGradient);
lcSetProfileInt(LC_PROFILE_BACKGROUND_COLOR, mBackgroundSolidColor);
lcSetProfileInt(LC_PROFILE_GRADIENT_COLOR_TOP, mBackgroundGradientColorTop);
lcSetProfileInt(LC_PROFILE_GRADIENT_COLOR_BOTTOM, mBackgroundGradientColorBottom);
lcSetProfileInt(LC_PROFILE_MARQUEE_BORDER_COLOR, mMarqueeBorderColor);
lcSetProfileInt(LC_PROFILE_MARQUEE_FILL_COLOR, mMarqueeFillColor);
lcSetProfileInt(LC_PROFILE_OVERLAY_COLOR, mOverlayColor);
2020-07-25 22:21:22 +02:00
lcSetProfileInt(LC_PROFILE_ACTIVE_VIEW_COLOR, mActiveViewColor);
2020-12-12 03:01:04 +01:00
lcSetProfileInt(LC_PROFILE_INACTIVE_VIEW_COLOR, mInactiveViewColor);
lcSetProfileInt(LC_PROFILE_DRAW_EDGE_LINES, mDrawEdgeLines);
2021-03-07 18:53:35 +01:00
lcSetProfileInt(LC_PROFILE_DRAW_CONDITIONAL_LINES, mDrawConditionalLines);
lcSetProfileFloat(LC_PROFILE_LINE_WIDTH, mLineWidth);
lcSetProfileInt(LC_PROFILE_ALLOW_LOD, mAllowLOD);
2020-08-16 01:16:26 +02:00
lcSetProfileFloat(LC_PROFILE_LOD_DISTANCE, mMeshLODDistance);
2020-01-02 02:06:17 +01:00
lcSetProfileInt(LC_PROFILE_FADE_STEPS, mFadeSteps);
2020-04-25 21:16:37 +02:00
lcSetProfileInt(LC_PROFILE_FADE_STEPS_COLOR, mFadeStepsColor);
lcSetProfileInt(LC_PROFILE_HIGHLIGHT_NEW_PARTS, mHighlightNewParts);
lcSetProfileInt(LC_PROFILE_HIGHLIGHT_NEW_PARTS_COLOR, mHighlightNewPartsColor);
lcSetProfileInt(LC_PROFILE_GRID_STUDS, mDrawGridStuds);
lcSetProfileInt(LC_PROFILE_GRID_STUD_COLOR, mGridStudColor);
lcSetProfileInt(LC_PROFILE_GRID_LINES, mDrawGridLines);
lcSetProfileInt(LC_PROFILE_GRID_LINE_SPACING, mGridLineSpacing);
lcSetProfileInt(LC_PROFILE_GRID_LINE_COLOR, mGridLineColor);
2021-01-14 19:09:49 +01:00
lcSetProfileInt(LC_PROFILE_GRID_ORIGIN, mDrawGridOrigin);
2020-01-05 20:38:24 +01:00
lcSetProfileInt(LC_PROFILE_VIEW_SPHERE_ENABLED, mViewSphereSize ? 1 : 0);
2020-07-25 22:21:22 +02:00
lcSetProfileInt(LC_PROFILE_VIEW_SPHERE_LOCATION, static_cast<int>(mViewSphereLocation));
2018-10-29 01:59:01 +01:00
lcSetProfileInt(LC_PROFILE_VIEW_SPHERE_SIZE, mViewSphereSize);
2019-01-20 20:59:18 +01:00
lcSetProfileInt(LC_PROFILE_VIEW_SPHERE_COLOR, mViewSphereColor);
lcSetProfileInt(LC_PROFILE_VIEW_SPHERE_TEXT_COLOR, mViewSphereTextColor);
lcSetProfileInt(LC_PROFILE_VIEW_SPHERE_HIGHLIGHT_COLOR, mViewSphereHighlightColor);
2019-03-10 01:38:54 +01:00
lcSetProfileInt(LC_PROFILE_AUTOLOAD_MOSTRECENT, mAutoLoadMostRecent);
2020-01-02 02:06:17 +01:00
lcSetProfileInt(LC_PROFILE_RESTORE_TAB_LAYOUT, mRestoreTabLayout);
2020-07-25 22:21:22 +02:00
lcSetProfileInt(LC_PROFILE_COLOR_THEME, static_cast<int>(mColorTheme));
lcSetProfileInt(LC_PROFILE_PREVIEW_VIEW_SPHERE_SIZE, mPreviewViewSphereSize);
lcSetProfileInt(LC_PROFILE_PREVIEW_VIEW_SPHERE_LOCATION, static_cast<int>(mPreviewViewSphereLocation));
lcSetProfileInt(LC_PROFILE_PREVIEW_DRAW_AXES, mDrawPreviewAxis);
2021-01-26 16:42:19 +01:00
lcSetProfileInt(LC_PROFILE_STUD_CYLINDER_COLOR, mStudCylinderColor);
lcSetProfileInt(LC_PROFILE_PART_EDGE_COLOR, mPartEdgeColor);
lcSetProfileInt(LC_PROFILE_BLACK_EDGE_COLOR, mBlackEdgeColor);
lcSetProfileInt(LC_PROFILE_DARK_EDGE_COLOR, mDarkEdgeColor);
2021-01-24 12:53:02 +01:00
lcSetProfileFloat(LC_PROFILE_PART_EDGE_CONTRAST, mPartEdgeContrast);
2021-01-25 08:34:22 +01:00
lcSetProfileFloat(LC_PROFILE_PART_COLOR_VALUE_LD_INDEX, mPartColorValueLDIndex);
2021-01-24 12:53:02 +01:00
lcSetProfileInt(LC_PROFILE_AUTOMATE_EDGE_COLOR, mAutomateEdgeColor);
2020-07-25 22:21:22 +02:00
}
void lcPreferences::SetInterfaceColors(lcColorTheme ColorTheme)
{
if (ColorTheme == lcColorTheme::Dark)
{
2020-12-30 22:44:08 +01:00
mAxesColor = LC_RGBA(160, 160, 160, 255);
mTextColor = LC_RGBA(160, 160, 160, 255);
mBackgroundSolidColor = LC_RGB(49, 52, 55);
mBackgroundGradientColorTop = LC_RGB(0, 0, 191);
mBackgroundGradientColorBottom = LC_RGB(255, 255, 255);
2020-07-25 22:21:22 +02:00
mOverlayColor = lcGetProfileInt(LC_PROFILE_OVERLAY_COLOR);
mActiveViewColor = LC_RGBA(41, 128, 185, 255);
mGridStudColor = LC_RGBA(24, 24, 24, 192);
mGridLineColor = LC_RGBA(24, 24, 24, 255);
mViewSphereColor = LC_RGBA(35, 38, 41, 255);
mViewSphereTextColor = LC_RGBA(224, 224, 224, 255);
mViewSphereHighlightColor = LC_RGBA(41, 128, 185, 255);
}
else
{
mAxesColor = LC_RGBA(0, 0, 0, 255);
2020-12-30 22:44:08 +01:00
mTextColor = LC_RGBA(0, 0, 0, 255);
mBackgroundSolidColor = LC_RGB(255, 255, 255);
mBackgroundGradientColorTop = LC_RGB(54, 72, 95);
mBackgroundGradientColorBottom = LC_RGB(49, 52, 55);
2020-07-25 22:21:22 +02:00
mOverlayColor = LC_RGBA(0, 0, 0, 255);
mActiveViewColor = LC_RGBA(255, 0, 0, 255);
mGridStudColor = LC_RGBA(64, 64, 64, 192);
mGridLineColor = LC_RGBA(0, 0, 0, 255);
mViewSphereColor = LC_RGBA(255, 255, 255, 255);
mViewSphereTextColor = LC_RGBA(0, 0, 0, 255);
mViewSphereHighlightColor = LC_RGBA(255, 0, 0, 255);
}
}
lcApplication::lcApplication(int& Argc, char** Argv)
: QApplication(Argc, Argv)
2013-08-09 06:57:18 +02:00
{
setApplicationDisplayName(QLatin1String("LeoCAD"));
gApplication = this;
2020-07-25 22:21:22 +02:00
mDefaultStyle = style()->objectName();
mPreferences.LoadDefaults();
2013-08-09 06:57:18 +02:00
}
lcApplication::~lcApplication()
{
gApplication = nullptr;
2013-08-09 06:57:18 +02:00
}
2020-07-25 22:21:22 +02:00
void lcApplication::UpdateStyle()
{
if (mPreferences.mColorTheme == lcColorTheme::Dark)
{
if (!QApplication::setStyle("fusion"))
return;
QPalette Palette = QApplication::palette();
Palette.setColor(QPalette::Window, QColor(49, 52, 55));
Palette.setColor(QPalette::WindowText, QColor(240, 240, 240));
Palette.setColor(QPalette::Base, QColor(35, 38, 41));
Palette.setColor(QPalette::AlternateBase, QColor(44, 47, 50));
Palette.setColor(QPalette::ToolTipBase, QColor(224, 224, 244));
Palette.setColor(QPalette::ToolTipText, QColor(58, 58, 58));
2020-07-25 22:25:45 +02:00
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
2020-07-25 22:21:22 +02:00
Palette.setColor(QPalette::PlaceholderText, QColor(100, 100, 100));
2020-07-25 22:25:45 +02:00
#endif
2020-07-25 22:21:22 +02:00
Palette.setColor(QPalette::Text, QColor(224, 224, 224));
Palette.setColor(QPalette::Button, QColor(45, 48, 51));
Palette.setColor(QPalette::ButtonText, QColor(224, 224, 244));
Palette.setColor(QPalette::Light, QColor(65, 65, 65));
Palette.setColor(QPalette::Midlight, QColor(62, 62, 62));
Palette.setColor(QPalette::Dark, QColor(35, 35, 35));
Palette.setColor(QPalette::Mid, QColor(50, 50, 50));
Palette.setColor(QPalette::Shadow, QColor(20, 20, 20));
// Palette.setColor(QPalette::Highlight, QColor(46, 108, 219));
Palette.setColor(QPalette::Highlight, QColor(41, 128, 185));
Palette.setColor(QPalette::HighlightedText, QColor(232, 232, 232));
Palette.setColor(QPalette::Link, QColor(41, 128, 185));
Palette.setColor(QPalette::Disabled, QPalette::Text, QColor(128, 128, 128));
Palette.setColor(QPalette::Disabled, QPalette::WindowText, QColor(128, 128, 128));
Palette.setColor(QPalette::Disabled, QPalette::ButtonText, QColor(128, 128, 128));
QApplication::setPalette(Palette);
2020-07-26 02:48:48 +02:00
QFile StylesheetFile(QLatin1String(":/stylesheet/stylesheet.qss"));
2020-07-25 22:21:22 +02:00
if (StylesheetFile.open(QIODevice::ReadOnly))
{
QString Stylesheet = QString::fromLatin1(StylesheetFile.readAll());
qApp->setStyleSheet(Stylesheet);
}
}
else
{
QApplication::setStyle(mDefaultStyle);
QApplication::setPalette(qApp->style()->standardPalette());
qApp->setStyleSheet(QString());
}
}
void lcApplication::SaveTabLayout() const
{
if (!mProject || mProject->GetFileName().isEmpty())
return;
QSettings Settings;
QByteArray TabLayout = gMainWindow->GetTabLayout();
Settings.setValue(GetTabLayoutKey(), TabLayout);
}
QString lcApplication::GetTabLayoutKey() const
{
if (mProject)
{
QString FileName = mProject->GetFileName();
if (!FileName.isEmpty())
{
FileName.replace('\\', '?');
FileName.replace('/', '?');
return QString("TabLayouts/%1").arg(FileName);
}
}
return QString();
}
2014-12-04 02:47:28 +01:00
void lcApplication::SetProject(Project* Project)
{
SaveTabLayout();
if (gMainWindow)
{
gMainWindow->RemoveAllModelTabs();
if (gMainWindow->GetPreviewWidget())
gMainWindow->GetPreviewWidget()->ClearPreview();
}
2014-12-04 02:47:28 +01:00
delete mProject;
mProject = Project;
2015-03-14 20:07:07 +01:00
Project->SetActiveModel(0);
lcGetPiecesLibrary()->RemoveTemporaryPieces();
if (mProject && !mProject->GetFileName().isEmpty() && mPreferences.mRestoreTabLayout)
{
QSettings Settings;
QByteArray TabLayout = Settings.value(GetTabLayoutKey()).toByteArray();
if (gMainWindow)
gMainWindow->RestoreTabLayout(TabLayout);
}
2014-12-04 02:47:28 +01:00
}
2014-12-16 00:55:17 +01:00
void lcApplication::SetClipboard(const QByteArray& Clipboard)
2013-08-09 06:57:18 +02:00
{
mClipboard = Clipboard;
2014-12-16 00:55:17 +01:00
gMainWindow->UpdatePaste(!mClipboard.isEmpty());
2013-08-09 06:57:18 +02:00
}
2015-01-31 21:38:53 +01:00
void lcApplication::ExportClipboard(const QByteArray& Clipboard)
{
QMimeData* MimeData = new QMimeData();
MimeData->setData("application/vnd.leocad-clipboard", Clipboard);
QApplication::clipboard()->setMimeData(MimeData);
SetClipboard(Clipboard);
}
bool lcApplication::LoadPartsLibrary(const QList<QPair<QString, bool>>& LibraryPaths, bool OnlyUsePaths)
2013-08-09 06:57:18 +02:00
{
if (mLibrary == nullptr)
mLibrary = new lcPiecesLibrary();
2013-08-09 06:57:18 +02:00
const bool ShowProgress = gMainWindow != nullptr;
if (!OnlyUsePaths)
{
char* EnvPath = getenv("LEOCAD_LIB");
if (EnvPath && EnvPath[0])
return mLibrary->Load(EnvPath, ShowProgress);
2013-08-09 06:57:18 +02:00
QString CustomPath = lcGetProfileString(LC_PROFILE_PARTS_LIBRARY);
2013-08-09 06:57:18 +02:00
if (!CustomPath.isEmpty())
return mLibrary->Load(CustomPath, ShowProgress);
}
2013-08-09 06:57:18 +02:00
2017-08-29 04:13:17 +02:00
for (const QPair<QString, bool>& LibraryPathEntry : LibraryPaths)
{
if (mLibrary->Load(LibraryPathEntry.first, ShowProgress))
{
2017-08-29 04:13:17 +02:00
if (LibraryPathEntry.second)
mLibrary->SetOfficialPieces();
return true;
2017-08-29 04:13:17 +02:00
}
}
2013-08-09 06:57:18 +02:00
return false;
}
2021-01-11 02:45:28 +01:00
lcCommandLineOptions lcApplication::ParseCommandLineOptions()
2013-08-09 06:57:18 +02:00
{
lcPreferences Preferences;
Preferences.LoadDefaults();
2021-01-11 02:45:28 +01:00
lcCommandLineOptions Options;
Options.ParseOK = true;
Options.Exit = false;
Options.SaveImage = false;
Options.SaveWavefront = false;
Options.Save3DS = false;
Options.SaveCOLLADA = false;
Options.SaveHTML = false;
Options.SetCameraAngles = false;
Options.SetCameraPosition = false;
Options.Orthographic = false;
Options.SetFoV = false;
Options.SetZPlanes = false;
Options.SetFadeStepsColor = false;
Options.SetHighlightColor = false;
Options.FadeSteps = Preferences.mFadeSteps;
Options.ImageHighlight = Preferences.mHighlightNewParts;
2021-01-11 02:45:28 +01:00
Options.ImageWidth = lcGetProfileInt(LC_PROFILE_IMAGE_WIDTH);
Options.ImageHeight = lcGetProfileInt(LC_PROFILE_IMAGE_HEIGHT);
Options.ShadingMode = Preferences.mShadingMode;
Options.LineWidth = Preferences.mLineWidth;
2021-01-11 02:45:28 +01:00
Options.AASamples = lcGetProfileInt(LC_PROFILE_ANTIALIASING_SAMPLES);
Options.StudStyle = static_cast<lcStudStyle>(lcGetProfileInt(LC_PROFILE_STUD_STYLE));
2021-01-11 02:45:28 +01:00
Options.ImageStart = 0;
Options.ImageEnd = 0;
Options.CameraPosition[0] = lcVector3(0.0f, 0.0f, 0.0f);
Options.CameraPosition[1] = lcVector3(0.0f, 0.0f, 0.0f);
Options.CameraPosition[2] = lcVector3(0.0f, 0.0f, 0.0f);
Options.CameraLatLon = lcVector2(0.0f, 0.0f);
Options.FoV = 0.0f;
Options.ZPlanes = lcVector2(0.0f, 0.0f);
Options.Viewpoint = lcViewpoint::Count;
Options.FadeStepsColor = Preferences.mFadeStepsColor;
Options.HighlightColor = Preferences.mHighlightNewPartsColor;
Options.StudCylinderColor = Preferences.mStudCylinderColor;
Options.PartEdgeColor = Preferences.mPartEdgeColor;
Options.BlackEdgeColor = Preferences.mBlackEdgeColor;
Options.DarkEdgeColor = Preferences.mDarkEdgeColor;
Options.PartEdgeContrast = Preferences.mPartEdgeContrast;
Options.PartColorValueLDIndex = Preferences.mPartColorValueLDIndex;
Options.AutomateEdgeColor = Preferences.mAutomateEdgeColor;
QStringList Arguments = arguments();
2021-01-11 02:45:28 +01:00
if (Arguments.isEmpty())
return Options;
2013-08-09 06:57:18 +02:00
2021-01-11 02:45:28 +01:00
Arguments.removeFirst();
2021-01-11 02:45:28 +01:00
while (!Arguments.isEmpty())
{
QString Option = Arguments.takeFirst();
if (Option.isEmpty())
continue;
2013-08-09 06:57:18 +02:00
2021-01-11 02:45:28 +01:00
auto ParseString = [&Option, &Arguments, &Options](QString& Value, bool Required)
{
2021-01-11 02:45:28 +01:00
if (!Arguments.isEmpty() && Arguments.front()[0] != '-')
{
2021-01-11 02:45:28 +01:00
QString Parameter = Arguments.takeFirst();
Value = Parameter;
}
else if (Required)
{
Options.StdErr += tr("Not enough parameters for the '%1' option.\n").arg(Option);
2021-01-11 02:45:28 +01:00
Options.ParseOK = false;
2020-12-14 21:45:01 +01:00
return false;
}
return true;
};
2013-08-09 06:57:18 +02:00
2021-01-11 02:45:28 +01:00
auto ParseInteger = [&Option, &Arguments, &Options](int& Value, int Min, int Max)
{
2021-01-11 02:45:28 +01:00
if (!Arguments.isEmpty() && Arguments.front()[0] != '-')
{
bool Ok = false;
2021-01-11 02:45:28 +01:00
QString Parameter = Arguments.takeFirst();
int NewValue = Parameter.toInt(&Ok);
2021-01-11 02:45:28 +01:00
if (Ok && NewValue >= Min && NewValue <= Max)
2020-12-13 00:03:06 +01:00
{
Value = NewValue;
2020-12-13 00:03:06 +01:00
return true;
}
else
Options.StdErr += tr("Invalid parameter value specified for the '%1' option: '%2'.\n").arg(Option, Parameter);
}
else
Options.StdErr += tr("Not enough parameters for the '%1' option.\n").arg(Option);
2020-12-13 00:03:06 +01:00
2021-01-11 02:45:28 +01:00
Options.ParseOK = false;
2020-12-13 00:03:06 +01:00
return false;
};
2021-01-13 20:39:55 +01:00
auto ParseUnsigned = [&Option, &Arguments, &Options](uint& Value, uint Min, uint Max)
{
if (!Arguments.isEmpty() && Arguments.front()[0] != '-')
{
bool Ok = false;
QString Parameter = Arguments.takeFirst();
uint NewValue = Parameter.toUInt(&Ok);
if (Ok && NewValue >= Min && NewValue <= Max)
{
Value = NewValue;
return true;
}
else
Options.StdErr += tr("Invalid parameter value specified for the '%1' option: '%2'.\n").arg(Option, Parameter);
}
else
Options.StdErr += tr("Not enough parameters for the '%1' option.\n").arg(Option);
Options.ParseOK = false;
return false;
};
2021-01-11 02:45:28 +01:00
auto ParseFloat = [&Option, &Arguments, &Options](float& Value, float Min, float Max)
{
2021-01-11 02:45:28 +01:00
if (!Arguments.isEmpty() && Arguments.front()[0] != '-')
{
2020-12-14 21:45:01 +01:00
bool Ok = false;
2021-01-11 02:45:28 +01:00
QString Parameter = Arguments.takeFirst();
float NewValue = Parameter.toFloat(&Ok);
2021-01-11 02:45:28 +01:00
if (Ok && NewValue >= Min && NewValue <= Max)
{
2020-12-14 21:45:01 +01:00
Value = NewValue;
return true;
}
else
Options.StdErr += tr("Invalid parameter value specified for the '%1' option: '%2'.\n").arg(Option, Parameter);
}
else
Options.StdErr += tr("Not enough parameters for the '%1' option.\n").arg(Option);
2021-01-11 02:45:28 +01:00
Options.ParseOK = false;
return false;
};
2021-01-11 02:45:28 +01:00
auto ParseFloatArray = [&Option, &Arguments, &Options](int Count, float* ValueArray, bool NegativesValid)
2020-12-13 00:03:06 +01:00
{
2021-01-11 02:45:28 +01:00
if (Arguments.size() < Count)
2020-12-13 00:03:06 +01:00
{
Options.StdErr += tr("Not enough parameters for the '%1' option.\n").arg(Option);
2021-01-11 02:45:28 +01:00
Arguments.clear();
Options.ParseOK = false;
2020-12-13 00:03:06 +01:00
return false;
}
for (int ParseIndex = 0; ParseIndex < Count; ParseIndex++)
{
2021-01-11 02:45:28 +01:00
if (NegativesValid || Arguments.front()[0] != '-')
2020-12-13 00:03:06 +01:00
{
2020-12-14 21:45:01 +01:00
bool Ok = false;
2021-01-11 02:45:28 +01:00
QString Parameter = Arguments.takeFirst();
float NewValue = Parameter.toFloat(&Ok);
2020-12-14 21:45:01 +01:00
if (Ok)
{
*(ValueArray++) = NewValue;
continue;
}
Options.StdErr += tr("Invalid parameter value specified for the '%1' option: '%2'.\n").arg(Option, Parameter);
2020-12-13 00:03:06 +01:00
}
2020-12-14 21:45:01 +01:00
else
Options.StdErr += tr("Not enough parameters for the '%1' option.\n").arg(Option);
2020-12-14 21:45:01 +01:00
2021-01-11 02:45:28 +01:00
Options.ParseOK = false;
2020-12-14 21:45:01 +01:00
return false;
2020-12-13 00:03:06 +01:00
}
return true;
};
2021-01-11 02:45:28 +01:00
auto ParseColor = [&Option, &Arguments, &Options](quint32& Color)
2020-12-12 20:27:06 +01:00
{
2021-01-11 02:45:28 +01:00
if (!Arguments.isEmpty() && Arguments.front()[0] != '-')
2020-12-12 20:27:06 +01:00
{
2021-01-11 02:45:28 +01:00
QString Parameter = Arguments.takeFirst();
QColor ParsedColor = QColor(Parameter);
2020-12-14 21:45:01 +01:00
if (ParsedColor.isValid())
{
Color = LC_RGBA(ParsedColor.red(), ParsedColor.green(), ParsedColor.blue(), ParsedColor.alpha());
return true;
}
else
Options.StdErr += tr("Invalid parameter value specified for the '%1' option: '%2'.\n").arg(Option, Parameter);
2020-12-12 20:27:06 +01:00
}
2020-12-14 21:45:01 +01:00
else
Options.StdErr += tr("Not enough parameters for the '%1' option.\n").arg(Option);
2020-12-12 20:27:06 +01:00
2021-01-11 02:45:28 +01:00
Options.ParseOK = false;
2020-12-14 21:45:01 +01:00
return false;
2020-12-12 20:27:06 +01:00
};
2021-01-11 02:45:28 +01:00
if (Option[0] != '-')
{
2021-01-11 02:45:28 +01:00
if (QFileInfo(Option).isReadable())
Options.ProjectName = Option;
else
Options.StdErr += tr("The file '%1' is not readable.\n").arg(Option);
2021-01-11 02:45:28 +01:00
continue;
2020-12-16 22:51:02 +01:00
}
2021-01-11 02:45:28 +01:00
if (Option == QLatin1String("-l") || Option == QLatin1String("--libpath"))
2020-12-16 22:51:02 +01:00
{
2021-01-11 02:45:28 +01:00
QString LibPath;
if (ParseString(LibPath, true))
Options.LibraryPaths += qMakePair<QString, bool>(LibPath, false);
2020-12-16 22:51:02 +01:00
}
2021-01-11 02:45:28 +01:00
else if (Option == QLatin1String("-i") || Option == QLatin1String("--image"))
2020-12-16 22:51:02 +01:00
{
2021-01-11 02:45:28 +01:00
Options.SaveImage = true;
ParseString(Options.ImageName, false);
2020-12-16 22:51:02 +01:00
}
2021-01-11 02:45:28 +01:00
else if (Option == QLatin1String("-w") || Option == QLatin1String("--width"))
ParseInteger(Options.ImageWidth, 1, INT_MAX);
else if (Option == QLatin1String("-h") || Option == QLatin1String("--height"))
ParseInteger(Options.ImageHeight, 1, INT_MAX);
else if (Option == QLatin1String("-f") || Option == QLatin1String("--from"))
2021-01-13 20:39:55 +01:00
ParseUnsigned(Options.ImageStart, 1, LC_STEP_MAX);
2021-01-11 02:45:28 +01:00
else if (Option == QLatin1String("-t") || Option == QLatin1String("--to"))
2021-01-13 20:39:55 +01:00
ParseUnsigned(Options.ImageEnd, 1, LC_STEP_MAX);
2021-01-11 02:45:28 +01:00
else if (Option == QLatin1String("-s") || Option == QLatin1String("--submodel"))
ParseString(Options.ModelName, true);
else if (Option == QLatin1String("-c") || Option == QLatin1String("--camera"))
ParseString(Options.CameraName, true);
else if (Option == QLatin1String("--viewpoint"))
2020-12-16 22:51:02 +01:00
{
2021-01-02 00:04:27 +01:00
QString ViewpointName;
if (ParseString(ViewpointName, true))
2020-12-16 22:51:02 +01:00
{
2021-01-11 02:45:28 +01:00
Options.Viewpoint = lcCamera::GetViewpoint(ViewpointName);
2021-01-02 00:04:27 +01:00
2021-01-11 02:45:28 +01:00
if (Options.Viewpoint == lcViewpoint::Count)
2021-01-02 00:04:27 +01:00
{
Options.StdErr += tr("Invalid parameter value specified for the '%1' option: '%2'.\n").arg(Option, ViewpointName);
2021-01-11 02:45:28 +01:00
Options.ParseOK = false;
2021-01-02 00:04:27 +01:00
}
2020-12-16 22:51:02 +01:00
}
}
2021-01-11 02:45:28 +01:00
else if (Option == QLatin1String("--camera-angles"))
2020-12-14 03:23:52 +01:00
{
2021-01-11 02:45:28 +01:00
if ((Options.SetCameraAngles = ParseFloatArray(2, Options.CameraLatLon, true)) && (fabsf(Options.CameraLatLon[0]) > 360.0f || fabsf(Options.CameraLatLon[1]) > 360.0f))
2020-12-14 03:23:52 +01:00
{
Options.StdErr += tr("Invalid parameter value(s) specified for the '%1' option: limits are +/- 360.\n").arg(Option);
2021-01-11 02:45:28 +01:00
Options.ParseOK = false;
2020-12-16 22:51:02 +01:00
}
}
2021-01-11 02:45:28 +01:00
else if (Option == QLatin1String("--camera-position") || Option == QLatin1String("--camera-position-ldraw"))
2020-12-16 22:51:02 +01:00
{
2021-01-11 02:45:28 +01:00
if ((Options.SetCameraPosition = ParseFloatArray(9, Options.CameraPosition[0], true)))
2020-12-16 22:51:02 +01:00
{
2021-01-11 02:45:28 +01:00
lcVector3 Front = Options.CameraPosition[1] - Options.CameraPosition[0];
2020-12-16 22:51:02 +01:00
2021-01-11 02:45:28 +01:00
if (Front.LengthSquared() < 1.0f || Options.CameraPosition[2].LengthSquared() < 1.0f || fabsf(lcDot(lcNormalize(Front), lcNormalize(Options.CameraPosition[2]))) > 0.99f)
2020-12-16 22:51:02 +01:00
{
Options.StdErr += tr("Invalid parameter value(s) specified for the '%1' option.\n").arg(Option);
2021-01-11 02:45:28 +01:00
Options.ParseOK = false;
2020-12-16 22:51:02 +01:00
}
2021-01-11 02:45:28 +01:00
else if (Option == QLatin1String("--camera-position-ldraw"))
2020-12-16 22:51:02 +01:00
{
2021-01-11 02:45:28 +01:00
Options.CameraPosition[0] = lcVector3LDrawToLeoCAD(Options.CameraPosition[0]);
Options.CameraPosition[1] = lcVector3LDrawToLeoCAD(Options.CameraPosition[1]);
Options.CameraPosition[2] = lcVector3LDrawToLeoCAD(Options.CameraPosition[2]);
2020-12-16 22:51:02 +01:00
}
2020-12-14 03:23:52 +01:00
}
}
2021-01-11 02:45:28 +01:00
else if (Option == QLatin1String("--orthographic"))
Options.Orthographic = true;
else if (Option == QLatin1String("--fov"))
Options.SetFoV = ParseFloat(Options.FoV, 1.0f, 180.0f);
else if (Option == QLatin1String("--zplanes"))
2020-12-16 22:51:02 +01:00
{
2021-01-11 02:45:28 +01:00
if ((Options.SetZPlanes = ParseFloatArray(2, Options.ZPlanes, false)) && (Options.ZPlanes[0] < 1.0 || Options.ZPlanes[0] >= Options.ZPlanes[1]))
2020-12-16 22:51:02 +01:00
{
Options.StdErr += tr("Invalid parameter value(s) specified for the '%1' option: requirements are: 1 <= <near> < <far>.\n").arg(Option);
2021-01-11 02:45:28 +01:00
Options.ParseOK = false;
2020-12-16 22:51:02 +01:00
}
}
else if (Option == QLatin1String("-scc") || Option == QLatin1String("--stud-cylinder-color"))
{
if (ParseColor(Options.StudCylinderColor))
{
2021-01-26 23:58:02 +01:00
if (!lcIsHighContrast(Options.StudStyle))
{
Options.StdErr += tr("High contrast stud style is required for the '%1' option but is not enabled.\n").arg(Option);
Options.ParseOK = false;
}
}
}
else if (Option == QLatin1String("-ec") || Option == QLatin1String("--edge-color"))
{
if (ParseColor(Options.PartEdgeColor))
{
2021-01-26 23:58:02 +01:00
if (!lcIsHighContrast(Options.StudStyle))
{
Options.StdErr += tr("High contrast stud style is required for the '%1' option but is not enabled.\n").arg(Option);
Options.ParseOK = false;
}
}
}
else if (Option == QLatin1String("-bec") || Option == QLatin1String("--black-edge-color"))
{
if (ParseColor(Options.BlackEdgeColor))
{
2021-01-26 23:58:02 +01:00
if (!lcIsHighContrast(Options.StudStyle))
{
Options.StdErr += tr("High contrast stud style is required for the '%1' option but is not enabled.\n").arg(Option);
Options.ParseOK = false;
}
}
}
else if (Option == QLatin1String("-dec") || Option == QLatin1String("--dark-edge-color"))
{
if (ParseColor(Options.DarkEdgeColor))
{
2021-01-26 23:58:02 +01:00
if (!lcIsHighContrast(Options.StudStyle))
{
Options.StdErr += tr("High contrast stud style is required for the '%1' option but is not enabled.\n").arg(Option);
Options.ParseOK = false;
}
}
}
else if (Option == QLatin1String("-aec") || Option == QLatin1String("--automate-edge-color"))
{
Options.AutomateEdgeColor = true;
}
else if (Option == QLatin1String("-cc") || Option == QLatin1String("--color-contrast"))
{
if (ParseFloat(Options.PartEdgeContrast, 0.0f, 1.0f))
{
if (!Options.AutomateEdgeColor)
{
Options.StdErr += tr("Automate edge color is required for the '%1' option but is not enabled.\n").arg(Option);
Options.ParseOK = false;
}
}
}
else if (Option == QLatin1String("-ldv") || Option == QLatin1String("--light-dark-value"))
{
if (ParseFloat(Options.PartColorValueLDIndex, 0.0f, 1.0f))
{
if (!Options.AutomateEdgeColor)
{
Options.StdErr += tr("Automate edge color is required for the '%1' option but is not enabled.\n").arg(Option);
Options.ParseOK = false;
}
}
}
2021-01-11 02:45:28 +01:00
else if (Option == QLatin1String("--fade-steps"))
Options.FadeSteps = true;
else if (Option == QLatin1String("--no-fade-steps"))
Options.FadeSteps = false;
else if (Option == QLatin1String("--fade-steps-color"))
2020-12-12 20:27:06 +01:00
{
2021-01-11 02:45:28 +01:00
if (ParseColor(Options.FadeStepsColor))
2020-12-12 20:27:06 +01:00
{
2021-01-11 02:45:28 +01:00
Options.SetFadeStepsColor = true;
Options.FadeSteps = true;
2020-12-12 20:27:06 +01:00
}
}
2021-01-11 02:45:28 +01:00
else if (Option == QLatin1String("--highlight"))
Options.ImageHighlight = true;
else if (Option == QLatin1String("--no-highlight"))
Options.ImageHighlight = false;
else if (Option == QLatin1String("--highlight-color"))
2020-12-12 20:27:06 +01:00
{
2021-01-11 02:45:28 +01:00
if (ParseColor(Options.HighlightColor))
2020-12-12 20:27:06 +01:00
{
2021-01-11 02:45:28 +01:00
Options.SetHighlightColor = true;
Options.ImageHighlight = true;
2020-12-12 20:27:06 +01:00
}
}
2021-01-11 02:45:28 +01:00
else if (Option == QLatin1String("--shading"))
{
QString ShadingString;
2021-01-11 02:45:28 +01:00
2020-12-16 22:51:02 +01:00
if (ParseString(ShadingString, true))
{
if (ShadingString == QLatin1String("wireframe"))
Options.ShadingMode = lcShadingMode::Wireframe;
2020-12-16 22:51:02 +01:00
else if (ShadingString == QLatin1String("flat"))
Options.ShadingMode = lcShadingMode::Flat;
2020-12-16 22:51:02 +01:00
else if (ShadingString == QLatin1String("default"))
Options.ShadingMode = lcShadingMode::DefaultLights;
2020-12-16 22:51:02 +01:00
else if (ShadingString == QLatin1String("full"))
Options.ShadingMode = lcShadingMode::Full;
2020-12-16 22:51:02 +01:00
else
{
Options.StdErr += tr("Invalid parameter value specified for the '%1' option: '%2'.\n").arg(Option, ShadingString);
2021-01-11 02:45:28 +01:00
Options.ParseOK = false;
2020-12-16 22:51:02 +01:00
}
}
}
2021-01-11 02:45:28 +01:00
else if (Option == QLatin1String("--line-width"))
ParseFloat(Options.LineWidth, 0.0f, 10.0f);
2021-01-11 02:45:28 +01:00
else if (Option == QLatin1String("--aa-samples"))
2020-12-16 22:51:02 +01:00
{
2021-01-11 02:45:28 +01:00
if (ParseInteger(Options.AASamples, 1, 8) && Options.AASamples != 1 && Options.AASamples != 2 && Options.AASamples != 4 && Options.AASamples != 8)
2020-12-16 22:51:02 +01:00
{
Options.StdErr += tr("Invalid parameter value specified for the '%1' option: '%2'.\n").arg(Option, QString::number(Options.AASamples));
2021-01-11 02:45:28 +01:00
Options.ParseOK = false;
2020-12-16 22:51:02 +01:00
}
}
2021-01-20 13:19:29 +01:00
else if (Option == QLatin1String("-ss") || Option == QLatin1String("--stud-style"))
{
int StudStyle;
if (ParseInteger(StudStyle, 0, static_cast<int>(lcStudStyle::Count) - 1))
Options.StudStyle = static_cast<lcStudStyle>(StudStyle);
}
2021-01-11 02:45:28 +01:00
else if (Option == QLatin1String("-obj") || Option == QLatin1String("--export-wavefront"))
{
2021-01-11 02:45:28 +01:00
Options.SaveWavefront = true;
ParseString(Options.SaveWavefrontName, false);
}
2021-01-11 02:45:28 +01:00
else if (Option == QLatin1String("-3ds") || Option == QLatin1String("--export-3ds"))
{
2021-01-11 02:45:28 +01:00
Options.Save3DS = true;
ParseString(Options.Save3DSName, false);
}
2021-01-11 02:45:28 +01:00
else if (Option == QLatin1String("-dae") || Option == QLatin1String("--export-collada"))
{
2021-01-11 02:45:28 +01:00
Options.SaveCOLLADA = true;
ParseString(Options.SaveCOLLADAName, false);
2013-08-09 06:57:18 +02:00
}
2021-01-11 02:45:28 +01:00
else if (Option == QLatin1String("-html") || Option == QLatin1String("--export-html"))
{
2021-01-11 02:45:28 +01:00
Options.SaveHTML = true;
ParseString(Options.SaveHTMLName, false);
}
2021-01-11 02:45:28 +01:00
else if (Option == QLatin1String("-v") || Option == QLatin1String("--version"))
{
#ifdef LC_CONTINUOUS_BUILD
Options.StdOut += tr("LeoCAD Continuous Build %1\n").arg(QT_STRINGIFY(LC_CONTINUOUS_BUILD));
#else
Options.StdOut += tr("LeoCAD Version %1\n").arg(LC_VERSION_TEXT);
#endif
Options.StdOut += tr("Compiled %1\n").arg(__DATE__);
2021-01-11 02:45:28 +01:00
Options.Exit = true;
}
2021-01-11 02:45:28 +01:00
else if (Option == QLatin1String("-?") || Option == QLatin1String("--help"))
{
Options.StdOut += tr("Usage: leocad [options] [file]\n");
Options.StdOut += tr(" [options] can be:\n");
Options.StdOut += tr(" -l, --libpath <path>: Set the Parts Library location to path.\n");
Options.StdOut += tr(" -i, --image <outfile.ext>: Save a picture in the format specified by ext and exit.\n");
Options.StdOut += tr(" -w, --width <width>: Set the picture width.\n");
Options.StdOut += tr(" -h, --height <height>: Set the picture height.\n");
Options.StdOut += tr(" -f, --from <step>: Set the first step to save pictures.\n");
Options.StdOut += tr(" -t, --to <step>: Set the last step to save pictures.\n");
Options.StdOut += tr(" -s, --submodel <submodel>: Set the active submodel.\n");
Options.StdOut += tr(" -c, --camera <camera>: Set the active camera.\n");
2021-01-20 13:19:29 +01:00
Options.StdOut += tr(" -ss, --stud-style <id>: Set the stud style 0=No style, 1=LDraw single wire, 2=LDraw double wire, 3=LDraw raised floating, 4=LDraw raised rounded, 5=LDraw subtle rounded, 6=LEGO no logo, 7=LEGO single wire.\n");
Options.StdOut += tr(" --viewpoint <front|back|left|right|top|bottom|home>: Set the viewpoint.\n");
Options.StdOut += tr(" --camera-angles <latitude> <longitude>: Set the camera angles in degrees around the model.\n");
Options.StdOut += tr(" --camera-position <x> <y> <z> <tx> <ty> <tz> <ux> <uy> <uz>: Set the camera position, target and up vector.\n");
Options.StdOut += tr(" --camera-position-ldraw <x> <y> <z> <tx> <ty> <tz> <ux> <uy> <uz>: Set the camera position, target and up vector using LDraw coordinates.\n");
Options.StdOut += tr(" --orthographic: Render images using an orthographic projection.\n");
Options.StdOut += tr(" --fov <degrees>: Set the vertical field of view used to render images (< 180).\n");
Options.StdOut += tr(" --zplanes <near> <far>: Set the near and far clipping planes used to render images (1 <= <near> < <far>).\n");
Options.StdOut += tr(" --fade-steps: Render parts from prior steps faded.\n");
Options.StdOut += tr(" --no-fade-steps: Do not render parts from prior steps faded.\n");
Options.StdOut += tr(" --fade-steps-color <rgba>: Renderinng color for prior step parts (#AARRGGBB).\n");
Options.StdOut += tr(" --highlight: Highlight parts in the steps they appear.\n");
Options.StdOut += tr(" --no-highlight: Do not highlight parts in the steps they appear.\n");
Options.StdOut += tr(" --highlight-color: Renderinng color for highlighted parts (#AARRGGBB).\n");
Options.StdOut += tr(" --shading <wireframe|flat|default|full>: Select shading mode for rendering.\n");
Options.StdOut += tr(" --line-width <width>: Set the with of the edge lines.\n");
Options.StdOut += tr(" --aa-samples <count>: AntiAliasing sample size (1, 2, 4, or 8).\n");
Options.StdOut += tr(" -scc, --stud-cylinder-color <#AARRGGBB>: High contrast stud cylinder color.\n");
Options.StdOut += tr(" -ec, --edge-color <#AARRGGBB>: High contrast edge color.\n");
Options.StdOut += tr(" -bec, --black-edge-color <#AARRGGBB>: High contrast edge color for black parts.\n");
Options.StdOut += tr(" -dec, --dark-edge-color <#AARRGGBB>: High contrast edge color for dark color parts.\n");
Options.StdOut += tr(" -aec, --automate-edge-color: Enable automatically adjusted edge colors.\n");
Options.StdOut += tr(" -cc, --color-contrast <float>: Color contrast value between 0.0 and 1.0.\n");
Options.StdOut += tr(" -ldv, --light-dark-value <float>: Light/Dark color value between 0.0 and 1.0.\n");
Options.StdOut += tr(" -obj, --export-wavefront <outfile.obj>: Export the model to Wavefront OBJ format.\n");
Options.StdOut += tr(" -3ds, --export-3ds <outfile.3ds>: Export the model to 3D Studio 3DS format.\n");
Options.StdOut += tr(" -dae, --export-collada <outfile.dae>: Export the model to COLLADA DAE format.\n");
Options.StdOut += tr(" -html, --export-html <folder>: Create an HTML page for the model.\n");
Options.StdOut += tr(" -v, --version: Output version information and exit.\n");
Options.StdOut += tr(" -?, --help: Display this help message and exit.\n");
Options.StdOut += QLatin1String("\n");
2021-01-11 02:45:28 +01:00
Options.Exit = true;
}
else
2020-12-14 21:45:01 +01:00
{
Options.StdErr += tr("Unknown option: '%1'.\n").arg(Option);
2021-01-11 02:45:28 +01:00
Options.ParseOK = false;
2020-12-14 21:45:01 +01:00
}
}
2021-01-26 23:58:02 +01:00
if (Options.AutomateEdgeColor && lcIsHighContrast(Options.StudStyle))
{
Options.StdErr += tr("High contrast stud and edge color settings are ignored when -aec or --automate-edge-color is set.\n");
}
if (!Options.CameraName.isEmpty())
{
if (Options.Viewpoint != lcViewpoint::Count)
Options.StdErr += tr("--viewpoint is ignored when --camera is set.\n");
if (Options.Orthographic)
Options.StdErr += tr("--orthographic is ignored when --camera is set.\n");
if (Options.SetCameraAngles)
Options.StdErr += tr("--camera-angles is ignored when --camera is set.\n");
if (Options.SetCameraPosition)
Options.StdErr += tr("--camera-position is ignored when --camera is set.\n");
}
else if (Options.Viewpoint != lcViewpoint::Count)
{
if (Options.SetCameraAngles)
Options.StdErr += tr("--camera-angles is ignored when --viewpoint is set.\n");
if (Options.SetCameraPosition)
Options.StdErr += tr("--camera-position is ignored when --viewpoint is set.\n");
}
else if (Options.SetCameraAngles)
{
if (Options.SetCameraPosition)
Options.StdErr += tr("--camera-position is ignored when --camera-angles is set.\n");
}
const bool SaveAndExit = (Options.SaveImage || Options.SaveWavefront || Options.Save3DS || Options.SaveCOLLADA || Options.SaveHTML);
if (SaveAndExit && Options.ProjectName.isEmpty())
{
Options.StdErr += tr("No file name specified.\n");
Options.ParseOK = false;
}
2021-01-11 02:45:28 +01:00
return Options;
}
lcStartupMode lcApplication::Initialize(const QList<QPair<QString, bool>>& LibraryPaths)
{
lcCommandLineOptions Options = ParseCommandLineOptions();
QTextStream StdErr(stderr, QIODevice::WriteOnly);
QTextStream StdOut(stdout, QIODevice::WriteOnly);
2021-01-11 02:45:28 +01:00
if (!Options.StdErr.isEmpty())
{
StdErr << Options.StdErr;
StdErr.flush();
}
2021-01-11 02:45:28 +01:00
if (!Options.StdOut.isEmpty())
{
StdOut << Options.StdOut;
StdOut.flush();
}
2021-01-11 02:45:28 +01:00
if (!Options.ParseOK)
2020-12-31 03:22:02 +01:00
return lcStartupMode::Error;
if (Options.Exit)
return lcStartupMode::Success;
2020-12-31 03:22:02 +01:00
if (!lcContext::InitializeRenderer())
2020-12-14 21:45:01 +01:00
{
StdErr << tr("Error creating OpenGL context.\n");
2020-12-31 03:22:02 +01:00
return lcStartupMode::Error;
2013-08-09 06:57:18 +02:00
}
const bool SaveAndExit = (Options.SaveImage || Options.SaveWavefront || Options.Save3DS || Options.SaveCOLLADA || Options.SaveHTML);
if (!SaveAndExit)
{
UpdateStyle();
gMainWindow = new lcMainWindow();
lcLoadDefaultKeyboardShortcuts();
lcLoadDefaultMouseShortcuts();
}
if (!LoadPartsLibrary(Options.LibraryPaths.isEmpty() ? LibraryPaths : Options.LibraryPaths, !Options.LibraryPaths.isEmpty()))
2013-08-09 06:57:18 +02:00
{
QString Message;
2013-08-09 06:57:18 +02:00
2014-09-11 21:55:34 +02:00
if (mLibrary->LoadBuiltinPieces())
2018-03-22 00:47:00 +01:00
Message = tr("LeoCAD could not find a compatible Parts Library so only a small number of parts will be available.\n\nPlease visit https://www.leocad.org for information on how to download and install a library.");
2014-09-11 21:55:34 +02:00
else
2018-03-22 00:47:00 +01:00
Message = tr("LeoCAD could not load Parts Library.\n\nPlease visit https://www.leocad.org for information on how to download and install a library.");
if (gMainWindow)
QMessageBox::information(gMainWindow, tr("LeoCAD"), Message);
else
2021-01-13 20:11:31 +01:00
{
StdErr << Message << "\n";
StdErr.flush();
}
2013-08-09 06:57:18 +02:00
}
mPreferences.mShadingMode = Options.ShadingMode;
mPreferences.mLineWidth = Options.LineWidth;
mPreferences.mStudCylinderColor = Options.StudCylinderColor;
mPreferences.mPartEdgeColor = Options.PartEdgeColor;
mPreferences.mBlackEdgeColor = Options.BlackEdgeColor;
mPreferences.mDarkEdgeColor = Options.DarkEdgeColor;
mPreferences.mPartEdgeContrast = Options.PartEdgeContrast;
mPreferences.mPartColorValueLDIndex = Options.PartColorValueLDIndex;
mPreferences.mAutomateEdgeColor = Options.AutomateEdgeColor;
lcGetPiecesLibrary()->SetStudStyle(Options.StudStyle, false);
if (!SaveAndExit)
gMainWindow->CreateWidgets();
Project* NewProject = new Project();
SetProject(NewProject);
2013-08-09 06:57:18 +02:00
2021-01-11 02:45:28 +01:00
if (!SaveAndExit && Options.ProjectName.isEmpty() && lcGetProfileInt(LC_PROFILE_AUTOLOAD_MOSTRECENT))
Options.ProjectName = lcGetProfileString(LC_PROFILE_RECENT_FILE1);
2019-03-10 21:41:21 +01:00
bool ProjectLoaded = false;
2021-01-11 02:45:28 +01:00
if (!Options.ProjectName.isEmpty())
{
if (gMainWindow)
2021-01-11 02:45:28 +01:00
gMainWindow->OpenProject(Options.ProjectName);
else
{
Project* LoadedProject = new Project();
2021-01-11 02:45:28 +01:00
if (LoadedProject->Load(Options.ProjectName))
{
SetProject(LoadedProject);
ProjectLoaded = true;
}
else
{
delete LoadedProject;
}
}
}
if (ProjectLoaded)
2013-08-09 06:57:18 +02:00
{
2021-01-11 02:45:28 +01:00
if (!Options.ModelName.isEmpty())
mProject->SetActiveModel(Options.ModelName);
std::unique_ptr<lcView> ActiveView;
2021-01-11 02:45:28 +01:00
if (Options.SaveImage)
{
lcModel* Model;
2021-01-11 02:45:28 +01:00
if (!Options.ModelName.isEmpty())
{
2021-01-11 02:45:28 +01:00
Model = mProject->GetModel(Options.ModelName);
if (!Model)
{
StdErr << tr("Error: model '%1' does not exist.\n").arg(Options.ModelName);
return lcStartupMode::Error;
}
}
else
Model = mProject->GetMainModel();
ActiveView = std::unique_ptr<lcView>(new lcView(lcViewType::View, Model));
2020-12-13 00:03:06 +01:00
ActiveView->SetOffscreenContext();
ActiveView->MakeCurrent();
}
2021-01-11 02:45:28 +01:00
if (Options.SaveImage)
ActiveView->SetSize(Options.ImageWidth, Options.ImageHeight);
if (ActiveView)
{
2021-01-11 02:45:28 +01:00
if (!Options.CameraName.isEmpty())
ActiveView->SetCamera(Options.CameraName);
else
2020-12-13 00:03:06 +01:00
{
2021-01-11 02:45:28 +01:00
ActiveView->SetProjection(Options.Orthographic);
2021-01-11 02:45:28 +01:00
if (Options.SetFoV)
ActiveView->GetCamera()->m_fovy = Options.FoV;
2021-01-11 02:45:28 +01:00
if (Options.SetZPlanes)
{
lcCamera* Camera = ActiveView->GetCamera();
2021-01-11 02:45:28 +01:00
Camera->m_zNear = Options.ZPlanes[0];
Camera->m_zFar = Options.ZPlanes[1];
}
2021-01-11 02:45:28 +01:00
if (Options.Viewpoint != lcViewpoint::Count)
ActiveView->SetViewpoint(Options.Viewpoint);
else if (Options.SetCameraAngles)
ActiveView->SetCameraAngles(Options.CameraLatLon[0], Options.CameraLatLon[1]);
else if (Options.SetCameraPosition)
ActiveView->SetViewpoint(Options.CameraPosition[0], Options.CameraPosition[1], Options.CameraPosition[2]);
2020-12-13 00:03:06 +01:00
}
}
2021-01-11 02:45:28 +01:00
if (Options.SaveImage)
{
2021-01-08 20:25:24 +01:00
lcModel* ActiveModel = ActiveView->GetModel();
2021-01-11 02:45:28 +01:00
if (Options.ImageName.isEmpty())
Options.ImageName = mProject->GetImageFileName(true);
2013-08-09 06:57:18 +02:00
2021-01-11 02:45:28 +01:00
if (Options.ImageEnd < Options.ImageStart)
Options.ImageEnd = Options.ImageStart;
else if (Options.ImageStart > Options.ImageEnd)
Options.ImageStart = Options.ImageEnd;
2021-01-11 02:45:28 +01:00
if ((Options.ImageStart == 0) && (Options.ImageEnd == 0))
Options.ImageStart = Options.ImageEnd = ActiveModel->GetCurrentStep();
else if ((Options.ImageStart == 0) && (Options.ImageEnd != 0))
Options.ImageStart = Options.ImageEnd;
else if ((Options.ImageStart != 0) && (Options.ImageEnd == 0))
Options.ImageEnd = Options.ImageStart;
2013-08-09 06:57:18 +02:00
2021-01-11 02:45:28 +01:00
if (Options.ImageStart > 255)
Options.ImageStart = 255;
2013-08-09 06:57:18 +02:00
2021-01-11 02:45:28 +01:00
if (Options.ImageEnd > 255)
Options.ImageEnd = 255;
2013-08-09 06:57:18 +02:00
QString Frame;
2013-08-09 06:57:18 +02:00
2021-01-11 02:45:28 +01:00
if (Options.ImageStart != Options.ImageEnd)
{
2021-01-11 02:45:28 +01:00
QString Extension = QFileInfo(Options.ImageName).suffix();
Frame = Options.ImageName.left(Options.ImageName.length() - Extension.length() - 1) + QLatin1String("%1.") + Extension;
}
else
2021-01-11 02:45:28 +01:00
Frame = Options.ImageName;
2013-08-09 06:57:18 +02:00
2021-01-11 02:45:28 +01:00
mPreferences.mFadeSteps = Options.FadeSteps;
if (Options.SetFadeStepsColor)
mPreferences.mFadeStepsColor = Options.FadeStepsColor;
mPreferences.mHighlightNewParts = Options.ImageHighlight;
if (Options.SetHighlightColor)
mPreferences.mHighlightNewPartsColor = Options.HighlightColor;
2021-01-11 02:45:28 +01:00
if (Options.CameraName.isEmpty() && !Options.SetCameraPosition)
ActiveView->ZoomExtents();
auto ProgressCallback = [&StdOut](const QString& FileName)
{
StdOut << tr("Saved '%1'.\n").arg(FileName);
};
ActiveView->SaveStepImages(Frame, Options.ImageStart != Options.ImageEnd, Options.ImageStart, Options.ImageEnd, ProgressCallback);
}
2013-08-09 06:57:18 +02:00
2021-01-11 02:45:28 +01:00
if (Options.SaveWavefront)
2013-08-09 06:57:18 +02:00
{
QString FileName;
2021-01-11 02:45:28 +01:00
if (!Options.SaveWavefrontName.isEmpty())
FileName = Options.SaveWavefrontName;
else
2021-01-11 02:45:28 +01:00
FileName = Options.ProjectName;
2013-08-09 06:57:18 +02:00
QString Extension = QFileInfo(FileName).suffix().toLower();
2013-08-09 06:57:18 +02:00
if (Extension.isEmpty())
{
FileName += ".obj";
}
else if (Extension != "obj")
{
FileName = FileName.left(FileName.length() - Extension.length() - 1);
FileName += ".obj";
}
if (mProject->ExportWavefront(FileName))
StdOut << tr("Saved '%1'.\n").arg(FileName);
}
2021-01-11 02:45:28 +01:00
if (Options.Save3DS)
{
QString FileName;
2021-01-11 02:45:28 +01:00
if (!Options.Save3DSName.isEmpty())
FileName = Options.Save3DSName;
else
2021-01-11 02:45:28 +01:00
FileName = Options.ProjectName;
QString Extension = QFileInfo(FileName).suffix().toLower();
if (Extension.isEmpty())
{
FileName += ".3ds";
}
else if (Extension != "3ds")
{
FileName = FileName.left(FileName.length() - Extension.length() - 1);
FileName += ".3ds";
}
if (mProject->Export3DStudio(FileName))
StdOut << tr("Saved '%1'.\n").arg(FileName);
}
2021-01-11 02:45:28 +01:00
if (Options.SaveCOLLADA)
{
QString FileName;
2021-01-11 02:45:28 +01:00
if (!Options.SaveCOLLADAName.isEmpty())
FileName = Options.SaveCOLLADAName;
else
2021-01-11 02:45:28 +01:00
FileName = Options.ProjectName;
QString Extension = QFileInfo(FileName).suffix().toLower();
if (Extension.isEmpty())
{
FileName += ".dae";
}
else if (Extension != "dae")
{
FileName = FileName.left(FileName.length() - Extension.length() - 1);
FileName += ".dae";
}
if (mProject->ExportCOLLADA(FileName))
StdOut << tr("Saved '%1'.\n").arg(FileName);
}
2021-01-11 02:45:28 +01:00
if (Options.SaveHTML)
{
2021-01-11 02:45:28 +01:00
lcHTMLExportOptions HTMLOptions(mProject);
2021-01-11 02:45:28 +01:00
if (!Options.SaveHTMLName.isEmpty())
HTMLOptions.PathName = Options.SaveHTMLName;
2021-01-11 02:45:28 +01:00
mProject->ExportHTML(HTMLOptions);
}
2013-08-09 06:57:18 +02:00
}
2020-12-31 03:22:02 +01:00
if (!SaveAndExit)
{
2020-07-25 22:21:22 +02:00
gMainWindow->SetColorIndex(lcGetColorIndex(7));
gMainWindow->GetPartSelectionWidget()->SetDefaultPart();
gMainWindow->UpdateRecentFiles();
gMainWindow->show();
}
2020-12-31 03:22:02 +01:00
return SaveAndExit ? lcStartupMode::Success : lcStartupMode::ShowWindow;
2013-08-09 06:57:18 +02:00
}
void lcApplication::Shutdown()
{
2021-01-02 19:23:51 +01:00
delete gMainWindow;
gMainWindow = nullptr;
delete mProject;
mProject = nullptr;
delete mLibrary;
mLibrary = nullptr;
2021-01-02 19:23:51 +01:00
lcContext::ShutdownRenderer();
2013-08-09 06:57:18 +02:00
}
void lcApplication::ShowPreferencesDialog()
{
lcPreferencesDialogOptions Options;
int CurrentAASamples = lcGetProfileInt(LC_PROFILE_ANTIALIASING_SAMPLES);
lcStudStyle CurrentStudStyle = lcGetPiecesLibrary()->GetStudStyle();
Options.Preferences = mPreferences;
2015-01-31 22:44:57 +01:00
Options.LibraryPath = lcGetProfileString(LC_PROFILE_PARTS_LIBRARY);
Options.MinifigSettingsPath = lcGetProfileString(LC_PROFILE_MINIFIG_SETTINGS);
Options.ColorConfigPath = lcGetProfileString(LC_PROFILE_COLOR_CONFIG);
2015-01-31 22:44:57 +01:00
Options.POVRayPath = lcGetProfileString(LC_PROFILE_POVRAY_PATH);
Options.LGEOPath = lcGetProfileString(LC_PROFILE_POVRAY_LGEO_PATH);
Options.DefaultAuthor = lcGetProfileString(LC_PROFILE_DEFAULT_AUTHOR_NAME);
2019-11-28 22:52:06 +01:00
Options.Language = lcGetProfileString(LC_PROFILE_LANGUAGE);
Options.CheckForUpdates = lcGetProfileInt(LC_PROFILE_CHECK_UPDATES);
Options.AASamples = CurrentAASamples;
2021-01-20 13:19:29 +01:00
Options.StudStyle = CurrentStudStyle;
Options.Categories = gCategories;
Options.CategoriesModified = false;
Options.CategoriesDefault = false;
Options.KeyboardShortcuts = gKeyboardShortcuts;
2016-04-25 07:26:34 +02:00
Options.KeyboardShortcutsModified = false;
Options.KeyboardShortcutsDefault = false;
Options.MouseShortcuts = gMouseShortcuts;
Options.MouseShortcutsModified = false;
Options.MouseShortcutsDefault = false;
2017-12-11 03:12:31 +01:00
lcQPreferencesDialog Dialog(gMainWindow, &Options);
if (Dialog.exec() != QDialog::Accepted)
return;
2019-11-28 22:52:06 +01:00
bool LanguageChanged = Options.Language != lcGetProfileString(LC_PROFILE_LANGUAGE);
2015-01-31 22:44:57 +01:00
bool LibraryChanged = Options.LibraryPath != lcGetProfileString(LC_PROFILE_PARTS_LIBRARY);
bool ColorsChanged = Options.ColorConfigPath != lcGetProfileString(LC_PROFILE_COLOR_CONFIG);
bool AAChanged = CurrentAASamples != Options.AASamples;
2021-01-20 13:19:29 +01:00
bool StudStyleChanged = CurrentStudStyle != Options.StudStyle;
2021-01-26 02:50:00 +01:00
bool AutomateEdgeColorChanged = Options.Preferences.mAutomateEdgeColor != mPreferences.mAutomateEdgeColor;
2021-01-26 16:42:19 +01:00
AutomateEdgeColorChanged |= Options.Preferences.mStudCylinderColor != mPreferences.mStudCylinderColor;
AutomateEdgeColorChanged |= Options.Preferences.mPartEdgeColor != mPreferences.mPartEdgeColor;
2021-01-26 02:50:00 +01:00
AutomateEdgeColorChanged |= Options.Preferences.mBlackEdgeColor != mPreferences.mBlackEdgeColor;
AutomateEdgeColorChanged |= Options.Preferences.mDarkEdgeColor != mPreferences.mDarkEdgeColor;
AutomateEdgeColorChanged |= Options.Preferences.mPartEdgeContrast != mPreferences.mPartEdgeContrast;
AutomateEdgeColorChanged |= Options.Preferences.mPartColorValueLDIndex != mPreferences.mPartColorValueLDIndex;
2021-01-25 08:34:22 +01:00
mPreferences = Options.Preferences;
mPreferences.SaveDefaults();
2020-07-25 22:21:22 +02:00
UpdateStyle();
lcSetProfileString(LC_PROFILE_DEFAULT_AUTHOR_NAME, Options.DefaultAuthor);
lcSetProfileString(LC_PROFILE_PARTS_LIBRARY, Options.LibraryPath);
lcSetProfileString(LC_PROFILE_MINIFIG_SETTINGS, Options.MinifigSettingsPath);
lcSetProfileString(LC_PROFILE_POVRAY_PATH, Options.POVRayPath);
lcSetProfileString(LC_PROFILE_POVRAY_LGEO_PATH, Options.LGEOPath);
2019-11-28 22:52:06 +01:00
lcSetProfileString(LC_PROFILE_LANGUAGE, Options.Language);
lcSetProfileInt(LC_PROFILE_CHECK_UPDATES, Options.CheckForUpdates);
lcSetProfileInt(LC_PROFILE_ANTIALIASING_SAMPLES, Options.AASamples);
lcSetProfileInt(LC_PROFILE_STUD_STYLE, static_cast<int>(Options.StudStyle));
if (LanguageChanged || LibraryChanged || AAChanged)
QMessageBox::information(gMainWindow, tr("LeoCAD"), tr("Some changes will only take effect the next time you start LeoCAD."));
if (Options.CategoriesModified)
{
if (Options.CategoriesDefault)
lcResetDefaultCategories();
else
{
gCategories = Options.Categories;
lcSaveDefaultCategories();
}
gMainWindow->UpdateCategories();
}
2016-04-25 07:26:34 +02:00
if (Options.KeyboardShortcutsModified)
{
2016-04-25 07:26:34 +02:00
if (Options.KeyboardShortcutsDefault)
lcResetDefaultKeyboardShortcuts();
else
{
gKeyboardShortcuts = Options.KeyboardShortcuts;
lcSaveDefaultKeyboardShortcuts();
}
gMainWindow->UpdateShortcuts();
}
2016-04-25 07:26:34 +02:00
if (Options.MouseShortcutsModified)
{
if (Options.MouseShortcutsDefault)
lcResetDefaultMouseShortcuts();
else
{
gMouseShortcuts = Options.MouseShortcuts;
lcSaveDefaultMouseShortcuts();
}
}
2021-01-20 13:19:29 +01:00
if (StudStyleChanged)
{
lcSetProfileInt(LC_PROFILE_STUD_STYLE, static_cast<int>(Options.StudStyle));
2021-01-20 13:19:29 +01:00
lcGetPiecesLibrary()->SetStudStyle(Options.StudStyle, true);
}
2021-01-24 12:53:02 +01:00
else if (ColorsChanged || AutomateEdgeColorChanged)
{
2021-01-24 12:53:02 +01:00
if (ColorsChanged)
lcSetProfileString(LC_PROFILE_COLOR_CONFIG, Options.ColorConfigPath);
lcGetPiecesLibrary()->LoadColors();
}
gMainWindow->SetShadingMode(Options.Preferences.mShadingMode);
2020-12-25 19:54:33 +01:00
lcView::UpdateAllViews();
}