git mv Code\Sandbox\Plugins Code/Editor/Plugins
Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
#
|
||||
# Copyright (c) Contributors to the Open 3D Engine Project
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
#
|
||||
#
|
||||
|
||||
if(NOT PAL_TRAIT_BUILD_HOST_TOOLS)
|
||||
return()
|
||||
endif()
|
||||
|
||||
ly_add_target(
|
||||
NAME ProjectSettingsTool MODULE
|
||||
NAMESPACE Legacy
|
||||
OUTPUT_SUBDIRECTORY EditorPlugins
|
||||
AUTOMOC
|
||||
AUTOUIC
|
||||
FILES_CMAKE
|
||||
projectsettingstool_files.cmake
|
||||
COMPILE_DEFINITIONS
|
||||
PRIVATE
|
||||
PLUGIN_EXPORTS
|
||||
SANDBOX_IMPORTS
|
||||
EDITOR_COMMON_IMPORTS
|
||||
BUILD_DEPENDENCIES
|
||||
PRIVATE
|
||||
3rdParty::Qt::Core
|
||||
3rdParty::Qt::Gui
|
||||
3rdParty::Qt::Widgets
|
||||
AZ::AzCore
|
||||
AZ::AzToolsFramework
|
||||
Legacy::CryCommon
|
||||
Legacy::EditorLib
|
||||
Legacy::EditorCommon
|
||||
)
|
||||
|
||||
ly_add_dependencies(Editor ProjectSettingsTool)
|
||||
set_property(GLOBAL APPEND PROPERTY LY_EDITOR_PLUGINS $<TARGET_FILE_NAME:Legacy::ProjectSettingsTool>)
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ProjectSettingsTool_precompiled.h"
|
||||
#include "DefaultImageValidator.h"
|
||||
|
||||
#include "PropertyImagePreview.h"
|
||||
|
||||
// Error for no default image set in overrides
|
||||
const static char* noDefaultImageError = "Default must be set if not all dpi overrides are set";
|
||||
|
||||
namespace ProjectSettingsTool
|
||||
{
|
||||
DefaultImageValidator::DefaultImageValidator(const FunctorValidator& validator)
|
||||
: FunctorValidator(validator.Functor())
|
||||
{
|
||||
}
|
||||
|
||||
QValidator::State DefaultImageValidator::validate(QString& input, [[maybe_unused]] int& pos) const
|
||||
{
|
||||
return ValidateWithErrors(input).first;
|
||||
}
|
||||
|
||||
FunctorValidator::ReturnType DefaultImageValidator::ValidateWithErrors(const QString& input) const
|
||||
{
|
||||
ReturnType result = m_functor(input);
|
||||
if (result.first == QValidator::Acceptable)
|
||||
{
|
||||
if (input.isEmpty())
|
||||
{
|
||||
int numCustoms = 0;
|
||||
// Check all specific overrides to see if any are set
|
||||
for (const PropertyImagePreviewCtrl* preview : m_specificOverrides)
|
||||
{
|
||||
if (!preview->GetValue().isEmpty())
|
||||
{
|
||||
++numCustoms;
|
||||
}
|
||||
}
|
||||
if (numCustoms != 0 && numCustoms != m_specificOverrides.size())
|
||||
{
|
||||
return FunctorValidator::ReturnType(QValidator::Intermediate, tr(noDefaultImageError));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void DefaultImageValidator::AddOverride(PropertyImagePreviewCtrl* preview)
|
||||
{
|
||||
m_specificOverrides.push_back(preview);
|
||||
}
|
||||
} // namespace ProjectSettingsTool
|
||||
#include <moc_DefaultImageValidator.cpp>
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include "FunctorValidator.h"
|
||||
|
||||
#include <AzCore/std/containers/list.h>
|
||||
#endif
|
||||
|
||||
namespace ProjectSettingsTool
|
||||
{
|
||||
// Forward Declaration
|
||||
class PropertyImagePreviewCtrl;
|
||||
|
||||
class DefaultImageValidator
|
||||
: public FunctorValidator
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
DefaultImageValidator(const FunctorValidator& validator);
|
||||
|
||||
QValidator::State validate(QString& input, int& pos) const override;
|
||||
ReturnType ValidateWithErrors(const QString& input) const override;
|
||||
// Adds a specific override to the list for this default override
|
||||
void AddOverride(PropertyImagePreviewCtrl* preview);
|
||||
|
||||
protected:
|
||||
AZStd::list<const PropertyImagePreviewCtrl*> m_specificOverrides;
|
||||
};
|
||||
} // namespace ProjectSettingsTool
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ProjectSettingsTool_precompiled.h"
|
||||
#include "FunctorValidator.h"
|
||||
|
||||
namespace ProjectSettingsTool
|
||||
{
|
||||
FunctorValidator::FunctorValidator(FunctorType functor)
|
||||
: QValidator()
|
||||
, m_functor(functor)
|
||||
{
|
||||
}
|
||||
|
||||
FunctorValidator::FunctorValidator()
|
||||
: QValidator()
|
||||
, m_functor(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
QValidator::State FunctorValidator::validate(QString& input, [[maybe_unused]] int& pos) const
|
||||
{
|
||||
return m_functor(input).first;
|
||||
}
|
||||
|
||||
FunctorValidator::ReturnType FunctorValidator::ValidateWithErrors(const QString& input) const
|
||||
{
|
||||
return m_functor(input);
|
||||
}
|
||||
|
||||
FunctorValidator::FunctorType FunctorValidator::Functor() const
|
||||
{
|
||||
return m_functor;
|
||||
}
|
||||
} // namespace ProjectSettingsTool
|
||||
|
||||
#include <moc_FunctorValidator.cpp>
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <AzCore/std/utils.h>
|
||||
|
||||
#include <QValidator>
|
||||
#endif
|
||||
|
||||
|
||||
namespace ProjectSettingsTool
|
||||
{
|
||||
class FunctorValidator
|
||||
: public QValidator
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
typedef AZStd::pair<QValidator::State, const QString> ReturnType;
|
||||
typedef ReturnType(* FunctorType)(const QString&);
|
||||
|
||||
FunctorValidator(FunctorType functor);
|
||||
|
||||
// Validates using QValidates api
|
||||
QValidator::State validate(QString& input, int& pos) const override;
|
||||
// Validates and returns the result with an error string if one occurred
|
||||
virtual ReturnType ValidateWithErrors(const QString& input) const;
|
||||
// Returns the function used to validate
|
||||
FunctorType Functor() const;
|
||||
|
||||
protected:
|
||||
FunctorValidator();
|
||||
|
||||
// The function to use for validating
|
||||
FunctorType m_functor;
|
||||
};
|
||||
} // namespace ProjectSettingsTool
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/EBus/EBus.h>
|
||||
|
||||
|
||||
namespace ProjectSettingsTool
|
||||
{
|
||||
class LastPathTraits
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
using Bus = AZ::EBus<LastPathTraits>;
|
||||
|
||||
// Bus Configuration
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
|
||||
|
||||
virtual QString GetLastImagePath() = 0;
|
||||
virtual void SetLastImagePath(const QString& path) = 0;
|
||||
};
|
||||
|
||||
typedef AZ::EBus<LastPathTraits> LastPathBus;
|
||||
} // namespace ProjectSettingsTool
|
||||
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "PlatformSettings_Android.h"
|
||||
#include "PlatformSettings_Base.h"
|
||||
#include "PlatformSettings_Ios.h"
|
||||
@@ -0,0 +1,262 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ProjectSettingsTool_precompiled.h"
|
||||
#include "PlatformSettings_Android.h"
|
||||
|
||||
#include "PlatformSettings_common.h"
|
||||
#include "Validators.h"
|
||||
|
||||
namespace ProjectSettingsTool
|
||||
{
|
||||
static const char* defaultImageTooltip = "Default image used if a specific DPI override is not given.";
|
||||
static void* xmlFunctor = reinterpret_cast<void*>(&SelectXmlFromFileDialog);
|
||||
|
||||
void AndroidIcons::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
|
||||
if (serialize)
|
||||
{
|
||||
serialize->Class<AndroidIcons>()
|
||||
->Version(1)
|
||||
->Field("default", &AndroidIcons::m_default)
|
||||
->Field("mdpi", &AndroidIcons::m_mdpi)
|
||||
->Field("hdpi", &AndroidIcons::m_hdpi)
|
||||
->Field("xhdpi", &AndroidIcons::m_xhdpi)
|
||||
->Field("xxhdpi", &AndroidIcons::m_xxhdpi)
|
||||
->Field("xxxhdpi", &AndroidIcons::m_xxxhdpi)
|
||||
;
|
||||
|
||||
AZ::EditContext* editContext = serialize->GetEditContext();
|
||||
if (editContext)
|
||||
{
|
||||
editContext->Class<AndroidIcons>("Icons", "All icon overrides for android.")
|
||||
->DataElement(Handlers::ImagePreview, &AndroidIcons::m_default, "Default", defaultImageTooltip)
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::ValidPngOrEmpty))
|
||||
->Attribute(Attributes::PropertyIdentfier, Identfiers::AndroidIconDefault)
|
||||
->DataElement(Handlers::ImagePreview, &AndroidIcons::m_mdpi, "Medium Dpi (48px)", "")
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::PngImageSetSizeOrEmpty<48>))
|
||||
->Attribute(Attributes::DefaultPath, GenDefaultImagePath(ImageGroup::AndroidIcons, "mdpi"))
|
||||
->Attribute(Attributes::DefaultImagePreview, Identfiers::AndroidIconDefault)
|
||||
->DataElement(Handlers::ImagePreview, &AndroidIcons::m_hdpi, "High Dpi (72px)", "")
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::PngImageSetSizeOrEmpty<72>))
|
||||
->Attribute(Attributes::DefaultPath, GenDefaultImagePath(ImageGroup::AndroidIcons, "hdpi"))
|
||||
->Attribute(Attributes::DefaultImagePreview, Identfiers::AndroidIconDefault)
|
||||
->DataElement(Handlers::ImagePreview, &AndroidIcons::m_xhdpi, "XHigh Dpi (96px)", "")
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::PngImageSetSizeOrEmpty<96>))
|
||||
->Attribute(Attributes::DefaultPath, GenDefaultImagePath(ImageGroup::AndroidIcons, "xhdpi"))
|
||||
->Attribute(Attributes::DefaultImagePreview, Identfiers::AndroidIconDefault)
|
||||
->DataElement(Handlers::ImagePreview, &AndroidIcons::m_xxhdpi, "XXHigh Dpi (144px)", "")
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::PngImageSetSizeOrEmpty<144>))
|
||||
->Attribute(Attributes::DefaultPath, GenDefaultImagePath(ImageGroup::AndroidIcons, "xxhdpi"))
|
||||
->Attribute(Attributes::DefaultImagePreview, Identfiers::AndroidIconDefault)
|
||||
->DataElement(Handlers::ImagePreview, &AndroidIcons::m_xxxhdpi, "XXXHigh Dpi (192px)", "")
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::PngImageSetSizeOrEmpty<192>))
|
||||
->Attribute(Attributes::DefaultPath, GenDefaultImagePath(ImageGroup::AndroidIcons, "xxxhdpi"))
|
||||
->Attribute(Attributes::DefaultImagePreview, Identfiers::AndroidIconDefault)
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AndroidLandscapeSplashscreens::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
|
||||
if (serialize)
|
||||
{
|
||||
serialize->Class<AndroidLandscapeSplashscreens>()
|
||||
->Version(1)
|
||||
->Field("default", &AndroidLandscapeSplashscreens::m_default)
|
||||
->Field("mdpi", &AndroidLandscapeSplashscreens::m_mdpi)
|
||||
->Field("hdpi", &AndroidLandscapeSplashscreens::m_hdpi)
|
||||
->Field("xhdpi", &AndroidLandscapeSplashscreens::m_xhdpi)
|
||||
->Field("xxhdpi", &AndroidLandscapeSplashscreens::m_xxhdpi)
|
||||
;
|
||||
|
||||
AZ::EditContext* editContext = serialize->GetEditContext();
|
||||
if (editContext)
|
||||
{
|
||||
editContext->Class<AndroidLandscapeSplashscreens>("Landscape", "All landscape splashscreen overrides for Android.")
|
||||
->DataElement(Handlers::ImagePreview, &AndroidLandscapeSplashscreens::m_default, "Default", defaultImageTooltip)
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::ValidPngOrEmpty))
|
||||
->Attribute(Attributes::PropertyIdentfier, Identfiers::AndroidLandDefault)
|
||||
->DataElement(Handlers::ImagePreview, &AndroidLandscapeSplashscreens::m_mdpi, "Medium Dpi", "Suggested 1024 x 640 png.")
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::ValidPngOrEmpty))
|
||||
->Attribute(Attributes::DefaultPath, GenDefaultImagePath(ImageGroup::AndroidLandscape, "mdpi"))
|
||||
->Attribute(Attributes::DefaultImagePreview, Identfiers::AndroidLandDefault)
|
||||
->DataElement(Handlers::ImagePreview, &AndroidLandscapeSplashscreens::m_hdpi, "High Dpi", "Suggested 1280 x 800 png.")
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::ValidPngOrEmpty))
|
||||
->Attribute(Attributes::DefaultPath, GenDefaultImagePath(ImageGroup::AndroidLandscape, "hdpi"))
|
||||
->Attribute(Attributes::DefaultImagePreview, Identfiers::AndroidLandDefault)
|
||||
->DataElement(Handlers::ImagePreview, &AndroidLandscapeSplashscreens::m_xhdpi, "XHigh Dpi", "Suggested 1920 x 1200 png.")
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::ValidPngOrEmpty))
|
||||
->Attribute(Attributes::DefaultPath, GenDefaultImagePath(ImageGroup::AndroidLandscape, "xhdpi"))
|
||||
->Attribute(Attributes::DefaultImagePreview, Identfiers::AndroidLandDefault)
|
||||
->DataElement(Handlers::ImagePreview, &AndroidLandscapeSplashscreens::m_xxhdpi, "XXHigh Dpi", "Suggested 2560 x 1600 png.")
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::ValidPngOrEmpty))
|
||||
->Attribute(Attributes::DefaultPath, GenDefaultImagePath(ImageGroup::AndroidLandscape, "xxhdpi"))
|
||||
->Attribute(Attributes::DefaultImagePreview, Identfiers::AndroidLandDefault)
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AndroidPortraitSplashscreens::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
|
||||
if (serialize)
|
||||
{
|
||||
serialize->Class<AndroidPortraitSplashscreens>()
|
||||
->Version(1)
|
||||
->Field("default", &AndroidPortraitSplashscreens::m_default)
|
||||
->Field("mdpi", &AndroidPortraitSplashscreens::m_mdpi)
|
||||
->Field("hdpi", &AndroidPortraitSplashscreens::m_hdpi)
|
||||
->Field("xhdpi", &AndroidPortraitSplashscreens::m_xhdpi)
|
||||
->Field("xxhdpi", &AndroidPortraitSplashscreens::m_xxhdpi)
|
||||
;
|
||||
|
||||
AZ::EditContext* editContext = serialize->GetEditContext();
|
||||
if (editContext)
|
||||
{
|
||||
editContext->Class<AndroidPortraitSplashscreens>("Portrait", "All portrait splashscreen overrides for Android.")
|
||||
->DataElement(Handlers::ImagePreview, &AndroidPortraitSplashscreens::m_default, "Default", defaultImageTooltip)
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::ValidPngOrEmpty))
|
||||
->Attribute(Attributes::PropertyIdentfier, Identfiers::AndroidPortDefault)
|
||||
->DataElement(Handlers::ImagePreview, &AndroidPortraitSplashscreens::m_mdpi, "Medium Dpi", "Suggested 640 x 1024 png.")
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::ValidPngOrEmpty))
|
||||
->Attribute(Attributes::DefaultPath, GenDefaultImagePath(ImageGroup::AndroidPortrait, "mdpi"))
|
||||
->Attribute(Attributes::DefaultImagePreview, Identfiers::AndroidPortDefault)
|
||||
->DataElement(Handlers::ImagePreview, &AndroidPortraitSplashscreens::m_hdpi, "High Dpi", "Suggested 800 x 1280 png.")
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::ValidPngOrEmpty))
|
||||
->Attribute(Attributes::DefaultPath, GenDefaultImagePath(ImageGroup::AndroidPortrait, "hdpi"))
|
||||
->Attribute(Attributes::DefaultImagePreview, Identfiers::AndroidPortDefault)
|
||||
->DataElement(Handlers::ImagePreview, &AndroidPortraitSplashscreens::m_xhdpi, "XHigh Dpi", "Suggested 1200 x 1920 png.")
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::ValidPngOrEmpty))
|
||||
->Attribute(Attributes::DefaultPath, GenDefaultImagePath(ImageGroup::AndroidPortrait, "xhdpi"))
|
||||
->Attribute(Attributes::DefaultImagePreview, Identfiers::AndroidPortDefault)
|
||||
->DataElement(Handlers::ImagePreview, &AndroidPortraitSplashscreens::m_xxhdpi, "XXHigh Dpi", "Suggested 1600 x 2560 png.")
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::ValidPngOrEmpty))
|
||||
->Attribute(Attributes::DefaultPath, GenDefaultImagePath(ImageGroup::AndroidPortrait, "xxhdpi"))
|
||||
->Attribute(Attributes::DefaultImagePreview, Identfiers::AndroidPortDefault)
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AndroidSplashscreens::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
|
||||
if (serialize)
|
||||
{
|
||||
AndroidLandscapeSplashscreens::Reflect(context);
|
||||
AndroidPortraitSplashscreens::Reflect(context);
|
||||
|
||||
serialize->Class<AndroidSplashscreens>()
|
||||
->Version(1)
|
||||
->Field("land", &AndroidSplashscreens::m_landscapeSplashscreens)
|
||||
->Field("port", &AndroidSplashscreens::m_portraitSplashscreens)
|
||||
;
|
||||
|
||||
AZ::EditContext* editContext = serialize->GetEditContext();
|
||||
if (editContext)
|
||||
{
|
||||
editContext->Class<AndroidSplashscreens>("Splashscreens", "All splashscreen overrides for Android.")
|
||||
->DataElement(0, &AndroidSplashscreens::m_landscapeSplashscreens)
|
||||
->DataElement(0, &AndroidSplashscreens::m_portraitSplashscreens)
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AndroidSettings::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
|
||||
if (serialize)
|
||||
{
|
||||
AndroidIcons::Reflect(context);
|
||||
AndroidSplashscreens::Reflect(context);
|
||||
|
||||
serialize->Class<AndroidSettings>()
|
||||
->Version(1)
|
||||
->Field("package_name", &AndroidSettings::m_packageName)
|
||||
->Field("version_name", &AndroidSettings::m_versionName)
|
||||
->Field("version_number", &AndroidSettings::m_versionNumber)
|
||||
->Field("orientation", &AndroidSettings::m_orientation)
|
||||
->Field("app_public_key", &AndroidSettings::m_appPublicKey)
|
||||
->Field("app_obfuscator_salt", &AndroidSettings::m_appObfuscatorSalt)
|
||||
->Field("rc_pak_job", &AndroidSettings::m_rcPakJob)
|
||||
->Field("rc_obb_job", &AndroidSettings::m_rcObbJob)
|
||||
->Field("use_main_obb", &AndroidSettings::m_useMainObb)
|
||||
->Field("use_patch_obb", &AndroidSettings::m_usePatchObb)
|
||||
->Field("enable_key_screen_on", &AndroidSettings::m_enableKeyScreenOn)
|
||||
->Field("disable_immersive_mode", &AndroidSettings::m_disableImmersiveMode)
|
||||
->Field("icons", &AndroidSettings::m_icons)
|
||||
->Field("splash_screen", &AndroidSettings::m_splashscreens)
|
||||
;
|
||||
|
||||
AZ::EditContext* editContext = serialize->GetEditContext();
|
||||
if (editContext)
|
||||
{
|
||||
editContext->Class<AndroidSettings>("Android Settings", "All settings related to Android not already defined by base settings.")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
|
||||
->DataElement(Handlers::LinkedLineEdit, &AndroidSettings::m_packageName, "Package Name", "Android application package identifier. Used for generating the project specific Java activity class and in the AndroidManifest.xml. Must be in dot separated format.")
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::PackageName))
|
||||
->Attribute(Attributes::LinkOptional, true)
|
||||
->Attribute(Attributes::PropertyIdentfier, Identfiers::AndroidPackageName)
|
||||
->Attribute(Attributes::LinkedProperty, Identfiers::IosBundleIdentifer)
|
||||
->DataElement(Handlers::LinkedLineEdit, &AndroidSettings::m_versionName, "Version Name", "Human readable version number. Used to set the \"android: versionName\" tag in the AndroidManifest.xml and ultimately what will be displayed in the App Store.")
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::IOSVersionNumber))
|
||||
->Attribute(Attributes::LinkOptional, true)
|
||||
->Attribute(Attributes::PropertyIdentfier, Identfiers::AndroidVersionName)
|
||||
->Attribute(Attributes::LinkedProperty, Identfiers::IosVersionName)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &AndroidSettings::m_versionNumber, "Version Number", "Internal application version number. Used to set the \"android:versionCode\" tag in the AndroidManifest.xml.")
|
||||
->Attribute(AZ::Edit::Attributes::Min, 1)
|
||||
->Attribute(AZ::Edit::Attributes::Max, Validators::maxAndroidVersion)
|
||||
->DataElement(AZ::Edit::UIHandlers::ComboBox, &AndroidSettings::m_orientation, "Orientation", "Desired orientation of the Android application. Used to set the \"android:screenOrientation\" tag in the AndroidManifest.xml.")
|
||||
->Attribute(AZ::Edit::Attributes::StringList, AZStd::vector<AZStd::string>
|
||||
{
|
||||
"landscape",
|
||||
"portrait",
|
||||
"reverseLandscape",
|
||||
"reversePortrait",
|
||||
"sensorLandscape",
|
||||
"sensorPortrait",
|
||||
"sensor",
|
||||
"fullSensor",
|
||||
"noSensor",
|
||||
"userLandscape",
|
||||
"userPortrait",
|
||||
"user",
|
||||
"fullUser",
|
||||
"locked",
|
||||
"behind",
|
||||
"unspecified"
|
||||
})
|
||||
->DataElement(Handlers::LinkedLineEdit, &AndroidSettings::m_appPublicKey, "Public App Key", "The application license key provided by Google Play. Required for using APK expansion files or other Google Play Services.")
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::PublicAppKeyOrEmpty))
|
||||
->Attribute(Attributes::Obfuscated, true)
|
||||
->DataElement(Handlers::LinkedLineEdit, &AndroidSettings::m_appObfuscatorSalt, "App Obfuscation Salt", "Application specific salt value for (un)obfuscation when using APK expansion files.")
|
||||
->Attribute(Attributes::Obfuscated, true)
|
||||
->DataElement(Handlers::FileSelect, &AndroidSettings::m_rcPakJob, "Rc Job PAK Override", "Path to the RC job XML file used to override the normal PAK files generation used in release builds. Path must be relative to <build dir>.")
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::ValidXmlOrEmpty))
|
||||
->Attribute(Attributes::SelectFunction, xmlFunctor)
|
||||
->DataElement(Handlers::FileSelect, &AndroidSettings::m_rcObbJob, "Rc Job APK Override", "Path to the RC job XML file used to override the normal APK Expansion file(s) generation used in release builds. Path must be relative to <build dir>.")
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::ValidXmlOrEmpty))
|
||||
->Attribute(Attributes::SelectFunction, xmlFunctor)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &AndroidSettings::m_useMainObb, "Use Main APK", "Specify if the \"Main\" APK Expansion file should be used.")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &AndroidSettings::m_usePatchObb, "Use Patch APK", "Specify if the \"Patch\" APK Expansion file should be used.")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &AndroidSettings::m_enableKeyScreenOn, "Enable Screen Wake Lock", "Enabled or disable the screen wake lock (device won't go to sleep while the application is running).")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &AndroidSettings::m_disableImmersiveMode, "Disable Immersive Mode", "Disable hiding of top and bottom system bars.")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &AndroidSettings::m_icons)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &AndroidSettings::m_splashscreens)
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace ProjectSettingsTool
|
||||
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Serialization/EditContext.h>
|
||||
|
||||
namespace ProjectSettingsTool
|
||||
{
|
||||
class AndroidIcons
|
||||
{
|
||||
public:
|
||||
AZ_TYPE_INFO(AndroidIcons, "{D807ABEA-9C79-4EDD-B418-9A823E812C9A}");
|
||||
AZ_CLASS_ALLOCATOR(AndroidIcons, AZ::SystemAllocator, 0);
|
||||
|
||||
AndroidIcons()
|
||||
: m_default("")
|
||||
, m_mdpi("")
|
||||
, m_hdpi("")
|
||||
, m_xhdpi("")
|
||||
, m_xxhdpi("")
|
||||
, m_xxxhdpi("")
|
||||
{}
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
AZStd::string m_default;
|
||||
AZStd::string m_mdpi;
|
||||
AZStd::string m_hdpi;
|
||||
AZStd::string m_xhdpi;
|
||||
AZStd::string m_xxhdpi;
|
||||
AZStd::string m_xxxhdpi;
|
||||
};
|
||||
|
||||
class AndroidLandscapeSplashscreens
|
||||
{
|
||||
public:
|
||||
AZ_TYPE_INFO(AndroidLandscapeSplashscreens, "{37888881-5050-47B6-9EB4-A408FD27D397}");
|
||||
AZ_CLASS_ALLOCATOR(AndroidIcons, AZ::SystemAllocator, 0);
|
||||
|
||||
AndroidLandscapeSplashscreens()
|
||||
: m_default("")
|
||||
, m_mdpi("")
|
||||
, m_hdpi("")
|
||||
, m_xhdpi("")
|
||||
, m_xxhdpi("")
|
||||
{}
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
AZStd::string m_default;
|
||||
AZStd::string m_mdpi;
|
||||
AZStd::string m_hdpi;
|
||||
AZStd::string m_xhdpi;
|
||||
AZStd::string m_xxhdpi;
|
||||
};
|
||||
|
||||
class AndroidPortraitSplashscreens
|
||||
{
|
||||
public:
|
||||
AZ_TYPE_INFO(AndroidPortraitSplashscreens, "{2AADA22F-B5A3-440C-A592-FB923BC66878}");
|
||||
AZ_CLASS_ALLOCATOR(AndroidPortraitSplashscreens, AZ::SystemAllocator, 0);
|
||||
|
||||
AndroidPortraitSplashscreens()
|
||||
: m_default("")
|
||||
, m_mdpi("")
|
||||
, m_hdpi("")
|
||||
, m_xhdpi("")
|
||||
, m_xxhdpi("")
|
||||
{}
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
AZStd::string m_default;
|
||||
AZStd::string m_mdpi;
|
||||
AZStd::string m_hdpi;
|
||||
AZStd::string m_xhdpi;
|
||||
AZStd::string m_xxhdpi;
|
||||
};
|
||||
|
||||
class AndroidSplashscreens
|
||||
{
|
||||
public:
|
||||
AZ_TYPE_INFO(AndroidSplashscreens, "{95985732-F45B-436A-86BC-7AE5249FF520}");
|
||||
AZ_CLASS_ALLOCATOR(AndroidSplashscreens, AZ::SystemAllocator, 0);
|
||||
|
||||
AndroidSplashscreens()
|
||||
: m_landscapeSplashscreens()
|
||||
, m_portraitSplashscreens()
|
||||
{}
|
||||
|
||||
AndroidLandscapeSplashscreens m_landscapeSplashscreens;
|
||||
AndroidPortraitSplashscreens m_portraitSplashscreens;
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
};
|
||||
|
||||
class AndroidSettings
|
||||
{
|
||||
public:
|
||||
AZ_TYPE_INFO(AndroidSettings, "{5D57D014-4939-4D86-B862-AF35BAC705DC}");
|
||||
AZ_CLASS_ALLOCATOR(AndroidSettings, AZ::SystemAllocator, 0);
|
||||
|
||||
AndroidSettings()
|
||||
: m_packageName("")
|
||||
, m_versionName("")
|
||||
, m_versionNumber(1)
|
||||
, m_orientation("landscape")
|
||||
, m_appPublicKey("")
|
||||
, m_appObfuscatorSalt("")
|
||||
, m_rcPakJob("")
|
||||
, m_rcObbJob("")
|
||||
, m_useMainObb(false)
|
||||
, m_usePatchObb(false)
|
||||
, m_enableKeyScreenOn(false)
|
||||
, m_disableImmersiveMode(false)
|
||||
, m_icons()
|
||||
, m_splashscreens()
|
||||
{}
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
AZStd::string m_packageName;
|
||||
AZStd::string m_versionName;
|
||||
int m_versionNumber;
|
||||
AZStd::string m_orientation;
|
||||
AZStd::string m_appPublicKey;
|
||||
AZStd::string m_appObfuscatorSalt;
|
||||
AZStd::string m_rcPakJob;
|
||||
AZStd::string m_rcObbJob;
|
||||
bool m_useMainObb;
|
||||
bool m_usePatchObb;
|
||||
bool m_enableKeyScreenOn;
|
||||
bool m_disableImmersiveMode;
|
||||
AndroidIcons m_icons;
|
||||
AndroidSplashscreens m_splashscreens;
|
||||
};
|
||||
} // namespace ProjectSettingsTool
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ProjectSettingsTool_precompiled.h"
|
||||
#include "PlatformSettings_Base.h"
|
||||
|
||||
#include "PlatformSettings_common.h"
|
||||
#include "Validators.h"
|
||||
|
||||
namespace ProjectSettingsTool
|
||||
{
|
||||
void BaseSettings::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
|
||||
if (serialize)
|
||||
{
|
||||
serialize->Class<BaseSettings>()
|
||||
->Version(2)
|
||||
->Field("project_name", &BaseSettings::m_projectName)
|
||||
->Field("product_name", &BaseSettings::m_productName)
|
||||
->Field("executable_name", &BaseSettings::m_executableName)
|
||||
->Field("project_path", &BaseSettings::m_projectPath)
|
||||
->Field("project_output_folder", &BaseSettings::m_projectOutputFolder)
|
||||
->Field("code_folder", &BaseSettings::m_codeFolder)
|
||||
;
|
||||
|
||||
AZ::EditContext* editContext = serialize->GetEditContext();
|
||||
if (editContext)
|
||||
{
|
||||
editContext->Class<BaseSettings>("Project Settings", "All core settings for the game project and package and deployment.")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
|
||||
->DataElement(Handlers::LinkedLineEdit, &BaseSettings::m_projectName, "Project Name", "The name of the project.")
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::FileName))
|
||||
->Attribute(Attributes::PropertyIdentfier, Identfiers::ProjectName)
|
||||
->Attribute(Attributes::LinkedProperty, Identfiers::IosBundleName)
|
||||
->DataElement(Handlers::LinkedLineEdit, &BaseSettings::m_productName, "Product Name", "The project's user facing name.")
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::IsNotEmpty))
|
||||
->Attribute(Attributes::PropertyIdentfier, Identfiers::ProductName)
|
||||
->Attribute(Attributes::LinkedProperty, Identfiers::IosDisplayName)
|
||||
->DataElement(Handlers::LinkedLineEdit, &BaseSettings::m_executableName, "Executable Name", "The project launcher's name.")
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::FileName))
|
||||
->Attribute(Attributes::PropertyIdentfier, Identfiers::ExecutableName)
|
||||
->Attribute(Attributes::LinkedProperty, Identfiers::IosExecutableName)
|
||||
->DataElement(Handlers::QValidatedLineEdit, &BaseSettings::m_projectPath, "Project Path", "The project root folder path .")
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::FileNameOrEmpty))
|
||||
->Attribute(Attributes::PropertyIdentfier, Identfiers::ProductName)
|
||||
->Attribute(Attributes::LinkedProperty, Identfiers::ExecutableName)
|
||||
->DataElement(Handlers::QValidatedLineEdit, &BaseSettings::m_projectOutputFolder, "Output Folder", "The folder the packed project will be exported to.")
|
||||
->DataElement(Handlers::QValidatedLineEdit, &BaseSettings::m_codeFolder, "Code Folder (legacy)", "A legacy setting specifing the folder for this project's code.")
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace ProjectSettingsTool
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Serialization/EditContext.h>
|
||||
|
||||
namespace ProjectSettingsTool
|
||||
{
|
||||
class BaseSettings
|
||||
{
|
||||
public:
|
||||
AZ_TYPE_INFO(BaseSettings, "{3202E013-46EC-4E97-989A-84934CA15C59}");
|
||||
AZ_CLASS_ALLOCATOR(BaseSettings, AZ::SystemAllocator, 0);
|
||||
|
||||
BaseSettings()
|
||||
: m_projectName("")
|
||||
, m_productName("")
|
||||
, m_executableName("")
|
||||
, m_projectPath("")
|
||||
, m_sysDllGame("")
|
||||
, m_projectOutputFolder("")
|
||||
, m_codeFolder("")
|
||||
{}
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
AZStd::string m_projectName;
|
||||
AZStd::string m_productName;
|
||||
AZStd::string m_executableName;
|
||||
AZStd::string m_projectPath;
|
||||
AZStd::string m_sysDllGame;
|
||||
AZStd::string m_projectOutputFolder;
|
||||
AZStd::string m_codeFolder;
|
||||
};
|
||||
} // namespace ProjectSettingsTool
|
||||
@@ -0,0 +1,313 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ProjectSettingsTool_precompiled.h"
|
||||
#include "PlatformSettings_Ios.h"
|
||||
|
||||
#include "PlatformSettings_common.h"
|
||||
#include "Validators.h"
|
||||
|
||||
namespace ProjectSettingsTool
|
||||
{
|
||||
namespace Icons
|
||||
{
|
||||
static const char* appStore = "iOSAppStoreIcon1024x1024";
|
||||
static const char* iphoneApp120 = "iPhoneAppIcon120x120";
|
||||
static const char* iphoneApp180 = "iPhoneAppIcon180x180";
|
||||
static const char* iphoneNotification40 = "iPhoneNotificationIcon40x40";
|
||||
static const char* iphoneNotification60 = "iPhoneNotificationIcon60x60";
|
||||
static const char* iphoneSettings58 = "iPhoneSettingsIcon58x58";
|
||||
static const char* iphoneSettings87 = "iPhoneSettingsIcon87x87";
|
||||
static const char* iphoneSpotlight80 = "iPhoneSpotlightIcon80x80";
|
||||
static const char* iphoneSpotlight120 = "iPhoneSpotlightIcon120x120";
|
||||
static const char* ipadApp76 = "iPadAppIcon76x76";
|
||||
static const char* ipadApp152 = "iPadAppIcon152x152";
|
||||
static const char* ipadProApp = "iPadProAppIcon167x167";
|
||||
static const char* ipadNotification20 = "iPadNotificationIcon20x20";
|
||||
static const char* ipadNotification40 = "iPadNotificationIcon40x40";
|
||||
static const char* ipadSettings29 = "iPadSettingsIcon29x29";
|
||||
static const char* ipadSettings58 = "iPadSettingsIcon58x58";
|
||||
static const char* ipadSpotlight40 = "iPadSpotlightIcon40x40";
|
||||
static const char* ipadSpotlight80 = "iPadSpotlightIcon80x80";
|
||||
};
|
||||
|
||||
void IosIcons::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
|
||||
if (serialize)
|
||||
{
|
||||
serialize->Class<IosIcons>()
|
||||
->Version(1)
|
||||
->Field(Icons::appStore, &IosIcons::m_appStore)
|
||||
->Field(Icons::iphoneApp120, &IosIcons::m_iphoneApp120)
|
||||
->Field(Icons::iphoneApp180, &IosIcons::m_iphoneApp180)
|
||||
->Field(Icons::iphoneNotification40, &IosIcons::m_iphoneNotification40)
|
||||
->Field(Icons::iphoneNotification60, &IosIcons::m_iphoneNotification60)
|
||||
->Field(Icons::iphoneSettings58, &IosIcons::m_iphoneSettings58)
|
||||
->Field(Icons::iphoneSettings87, &IosIcons::m_iphoneSettings87)
|
||||
->Field(Icons::iphoneSpotlight80, &IosIcons::m_iphoneSpotlight80)
|
||||
->Field(Icons::iphoneSpotlight120, &IosIcons::m_iphoneSpotlight120)
|
||||
->Field(Icons::ipadApp76, &IosIcons::m_ipadApp76)
|
||||
->Field(Icons::ipadApp152, &IosIcons::m_ipadApp152)
|
||||
->Field(Icons::ipadProApp, &IosIcons::m_ipadProApp)
|
||||
->Field(Icons::ipadNotification20, &IosIcons::m_ipadNotification20)
|
||||
->Field(Icons::ipadNotification40, &IosIcons::m_ipadNotification40)
|
||||
->Field(Icons::ipadSettings29, &IosIcons::m_ipadSettings29)
|
||||
->Field(Icons::ipadSettings58, &IosIcons::m_ipadSettings58)
|
||||
->Field(Icons::ipadSpotlight40, &IosIcons::m_ipadSpotlight40)
|
||||
->Field(Icons::ipadSpotlight80, &IosIcons::m_ipadSpotlight80)
|
||||
;
|
||||
|
||||
AZ::EditContext* editContext = serialize->GetEditContext();
|
||||
if (editContext)
|
||||
{
|
||||
editContext->Class<IosIcons>("Icons", "All png icon overrides for iOS.")
|
||||
->DataElement(Handlers::ImagePreview, &IosIcons::m_appStore, "App Store (1024px)", "")
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::PngImageSetSizeOrEmpty<1024>))
|
||||
->Attribute(Attributes::DefaultPath, GenDefaultImagePath(ImageGroup::IosIcons, Icons::appStore))
|
||||
->DataElement(Handlers::ImagePreview, &IosIcons::m_iphoneApp120, "iPhone App (120px)", "")
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::PngImageSetSizeOrEmpty<120>))
|
||||
->Attribute(Attributes::DefaultPath, GenDefaultImagePath(ImageGroup::IosIcons, Icons::iphoneApp120))
|
||||
->DataElement(Handlers::ImagePreview, &IosIcons::m_iphoneApp180, "iPhone App (180px)", "")
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::PngImageSetSizeOrEmpty<180>))
|
||||
->Attribute(Attributes::DefaultPath, GenDefaultImagePath(ImageGroup::IosIcons, Icons::iphoneApp180))
|
||||
->DataElement(Handlers::ImagePreview, &IosIcons::m_iphoneNotification40, "iPhone Notification (40px)", "")
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::PngImageSetSizeOrEmpty<40>))
|
||||
->Attribute(Attributes::DefaultPath, GenDefaultImagePath(ImageGroup::IosIcons, Icons::iphoneNotification40))
|
||||
->DataElement(Handlers::ImagePreview, &IosIcons::m_iphoneNotification60, "iPhone Notification (60px)", "")
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::PngImageSetSizeOrEmpty<60>))
|
||||
->Attribute(Attributes::DefaultPath, GenDefaultImagePath(ImageGroup::IosIcons, Icons::iphoneNotification60))
|
||||
->DataElement(Handlers::ImagePreview, &IosIcons::m_iphoneSettings58, "iPhone Settings (58px)", "")
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::PngImageSetSizeOrEmpty<58>))
|
||||
->Attribute(Attributes::DefaultPath, GenDefaultImagePath(ImageGroup::IosIcons, Icons::iphoneSettings58))
|
||||
->DataElement(Handlers::ImagePreview, &IosIcons::m_iphoneSettings87, "iPhone Settings (87px)", "")
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::PngImageSetSizeOrEmpty<87>))
|
||||
->Attribute(Attributes::DefaultPath, GenDefaultImagePath(ImageGroup::IosIcons, Icons::iphoneSettings87))
|
||||
->DataElement(Handlers::ImagePreview, &IosIcons::m_iphoneSpotlight80, "iPhone Spotlight (80px)", "")
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::PngImageSetSizeOrEmpty<80>))
|
||||
->Attribute(Attributes::DefaultPath, GenDefaultImagePath(ImageGroup::IosIcons, Icons::iphoneSpotlight80))
|
||||
->DataElement(Handlers::ImagePreview, &IosIcons::m_iphoneSpotlight120, "iPhone Spotlight (120px)", "")
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::PngImageSetSizeOrEmpty<120>))
|
||||
->Attribute(Attributes::DefaultPath, GenDefaultImagePath(ImageGroup::IosIcons, Icons::iphoneSpotlight120))
|
||||
->DataElement(Handlers::ImagePreview, &IosIcons::m_ipadApp76, "iPad App (76px)", "")
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::PngImageSetSizeOrEmpty<76>))
|
||||
->Attribute(Attributes::DefaultPath, GenDefaultImagePath(ImageGroup::IosIcons, Icons::ipadApp76))
|
||||
->DataElement(Handlers::ImagePreview, &IosIcons::m_ipadApp152, "iPad App (152px)", "")
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::PngImageSetSizeOrEmpty<152>))
|
||||
->Attribute(Attributes::DefaultPath, GenDefaultImagePath(ImageGroup::IosIcons, Icons::ipadApp152))
|
||||
->DataElement(Handlers::ImagePreview, &IosIcons::m_ipadProApp, "iPad Pro App (167px)", "")
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::PngImageSetSizeOrEmpty<167>))
|
||||
->Attribute(Attributes::DefaultPath, GenDefaultImagePath(ImageGroup::IosIcons, Icons::ipadProApp))
|
||||
->DataElement(Handlers::ImagePreview, &IosIcons::m_ipadNotification20, "iPad Notification (20px)", "")
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::PngImageSetSizeOrEmpty<20>))
|
||||
->Attribute(Attributes::DefaultPath, GenDefaultImagePath(ImageGroup::IosIcons, Icons::ipadNotification20))
|
||||
->DataElement(Handlers::ImagePreview, &IosIcons::m_ipadNotification40, "iPad Notification (40px)", "")
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::PngImageSetSizeOrEmpty<40>))
|
||||
->Attribute(Attributes::DefaultPath, GenDefaultImagePath(ImageGroup::IosIcons, Icons::ipadNotification40))
|
||||
->DataElement(Handlers::ImagePreview, &IosIcons::m_ipadSettings29, "iPad Settings (29px)", "")
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::PngImageSetSizeOrEmpty<29>))
|
||||
->Attribute(Attributes::DefaultPath, GenDefaultImagePath(ImageGroup::IosIcons, Icons::ipadSettings29))
|
||||
->DataElement(Handlers::ImagePreview, &IosIcons::m_ipadSettings58, "iPad Settings (58px)", "")
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::PngImageSetSizeOrEmpty<58>))
|
||||
->Attribute(Attributes::DefaultPath, GenDefaultImagePath(ImageGroup::IosIcons, Icons::ipadSettings58))
|
||||
->DataElement(Handlers::ImagePreview, &IosIcons::m_ipadSpotlight40, "iPad Spotlight (40px)", "")
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::PngImageSetSizeOrEmpty<40>))
|
||||
->Attribute(Attributes::DefaultPath, GenDefaultImagePath(ImageGroup::IosIcons, Icons::ipadSpotlight40))
|
||||
->DataElement(Handlers::ImagePreview, &IosIcons::m_ipadSpotlight80, "iPad Spotlight (80px)", "")
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::PngImageSetSizeOrEmpty<80>))
|
||||
->Attribute(Attributes::DefaultPath, GenDefaultImagePath(ImageGroup::IosIcons, Icons::ipadSpotlight80))
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace Launchscreens
|
||||
{
|
||||
static const char* iphone640x960 = "iPhoneLaunchImage640x960";
|
||||
static const char* iphone640x1136 = "iPhoneLaunchImage640x1136";
|
||||
static const char* iphone750x1334 = "iPhoneLaunchImage750x1334";
|
||||
static const char* iphone1125x2436 = "iPhoneLaunchImage1125x2436";
|
||||
static const char* iphone2436x1125 = "iPhoneLaunchImage2436x1125";
|
||||
static const char* iphone1242x2208 = "iPhoneLaunchImage1242x2208";
|
||||
static const char* iphone2208x1242 = "iPhoneLaunchImage2208x1242";
|
||||
static const char* ipad768x1024 = "iPadLaunchImage768x1024";
|
||||
static const char* ipad1024x768 = "iPadLaunchImage1024x768";
|
||||
static const char* ipad1536x2048 = "iPadLaunchImage1536x2048";
|
||||
static const char* ipad2048x1536 = "iPadLaunchImage2048x1536";
|
||||
} // namespace Launchscreens
|
||||
|
||||
void IosLaunchscreens::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
|
||||
if (serialize)
|
||||
{
|
||||
serialize->Class<IosLaunchscreens>()
|
||||
->Version(1)
|
||||
->Field(Launchscreens::iphone640x960, &IosLaunchscreens::m_iphone640x960)
|
||||
->Field(Launchscreens::iphone640x1136, &IosLaunchscreens::m_iphone640x1136)
|
||||
->Field(Launchscreens::iphone750x1334, &IosLaunchscreens::m_iphone750x1334)
|
||||
->Field(Launchscreens::iphone1125x2436, &IosLaunchscreens::m_iphone1125x2436)
|
||||
->Field(Launchscreens::iphone2436x1125, &IosLaunchscreens::m_iphone2436x1125)
|
||||
->Field(Launchscreens::iphone1242x2208, &IosLaunchscreens::m_iphone1242x2208)
|
||||
->Field(Launchscreens::iphone2208x1242, &IosLaunchscreens::m_iphone2208x1242)
|
||||
->Field(Launchscreens::ipad768x1024, &IosLaunchscreens::m_ipad768x1024)
|
||||
->Field(Launchscreens::ipad1024x768, &IosLaunchscreens::m_ipad1024x768)
|
||||
->Field(Launchscreens::ipad1536x2048, &IosLaunchscreens::m_ipad1536x2048)
|
||||
->Field(Launchscreens::ipad2048x1536, &IosLaunchscreens::m_ipad2048x1536)
|
||||
;
|
||||
|
||||
AZ::EditContext* editContext = serialize->GetEditContext();
|
||||
if (editContext)
|
||||
{
|
||||
editContext->Class<IosLaunchscreens>("Launchscreens", "All png launchscreen overrides for iOS.")
|
||||
->DataElement(Handlers::ImagePreview, &IosLaunchscreens::m_iphone640x960, "iPhone (640x960px)", "")
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::PngImageSetSizeOrEmpty<640, 960>))
|
||||
->Attribute(Attributes::DefaultPath, GenDefaultImagePath(ImageGroup::IosLaunchScreens, Launchscreens::iphone640x960))
|
||||
->DataElement(Handlers::ImagePreview, &IosLaunchscreens::m_iphone640x1136, "iPhone (640x1136px)", "")
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::PngImageSetSizeOrEmpty<640, 1136>))
|
||||
->Attribute(Attributes::DefaultPath, GenDefaultImagePath(ImageGroup::IosLaunchScreens, Launchscreens::iphone640x1136))
|
||||
->DataElement(Handlers::ImagePreview, &IosLaunchscreens::m_iphone750x1334, "iPhone (750x1334px)", "")
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::PngImageSetSizeOrEmpty<750, 1334>))
|
||||
->Attribute(Attributes::DefaultPath, GenDefaultImagePath(ImageGroup::IosLaunchScreens, Launchscreens::iphone750x1334))
|
||||
->DataElement(Handlers::ImagePreview, &IosLaunchscreens::m_iphone1125x2436, "iPhone (1125x2436px)", "")
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::PngImageSetSizeOrEmpty<1125, 2436>))
|
||||
->Attribute(Attributes::DefaultPath, GenDefaultImagePath(ImageGroup::IosLaunchScreens, Launchscreens::iphone1125x2436))
|
||||
->DataElement(Handlers::ImagePreview, &IosLaunchscreens::m_iphone2436x1125, "iPhone (2436x1125px)", "")
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::PngImageSetSizeOrEmpty<2436, 1125>))
|
||||
->Attribute(Attributes::DefaultPath, GenDefaultImagePath(ImageGroup::IosLaunchScreens, Launchscreens::iphone2436x1125))
|
||||
->DataElement(Handlers::ImagePreview, &IosLaunchscreens::m_iphone1242x2208, "iPhone (1242x2208px)", "")
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::PngImageSetSizeOrEmpty<1242, 2208>))
|
||||
->Attribute(Attributes::DefaultPath, GenDefaultImagePath(ImageGroup::IosLaunchScreens, Launchscreens::iphone1242x2208))
|
||||
->DataElement(Handlers::ImagePreview, &IosLaunchscreens::m_iphone2208x1242, "iPhone (2208x1242px)", "")
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::PngImageSetSizeOrEmpty<2208, 1242>))
|
||||
->Attribute(Attributes::DefaultPath, GenDefaultImagePath(ImageGroup::IosLaunchScreens, Launchscreens::iphone2208x1242))
|
||||
->DataElement(Handlers::ImagePreview, &IosLaunchscreens::m_ipad768x1024, "iPad (768x1024px)", "")
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::PngImageSetSizeOrEmpty<768, 1024>))
|
||||
->Attribute(Attributes::DefaultPath, GenDefaultImagePath(ImageGroup::IosLaunchScreens, Launchscreens::ipad768x1024))
|
||||
->DataElement(Handlers::ImagePreview, &IosLaunchscreens::m_ipad1024x768, "iPad (1024x768px)", "")
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::PngImageSetSizeOrEmpty<1024, 768>))
|
||||
->Attribute(Attributes::DefaultPath, GenDefaultImagePath(ImageGroup::IosLaunchScreens, Launchscreens::ipad1024x768))
|
||||
->DataElement(Handlers::ImagePreview, &IosLaunchscreens::m_ipad1536x2048, "iPad (1536x2048px)", "")
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::PngImageSetSizeOrEmpty<1536, 2048>))
|
||||
->Attribute(Attributes::DefaultPath, GenDefaultImagePath(ImageGroup::IosLaunchScreens, Launchscreens::ipad1536x2048))
|
||||
->DataElement(Handlers::ImagePreview, &IosLaunchscreens::m_ipad2048x1536, "iPad (2048x1536px)", "")
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::PngImageSetSizeOrEmpty<2048, 1536>))
|
||||
->Attribute(Attributes::DefaultPath, GenDefaultImagePath(ImageGroup::IosLaunchScreens, Launchscreens::ipad2048x1536))
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IosOrientations::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
|
||||
if (serialize)
|
||||
{
|
||||
serialize->Class<IosOrientations>()
|
||||
->Version(1)
|
||||
->Field("UIInterfaceOrientationLandscapeRight", &IosOrientations::m_landscapeRight)
|
||||
->Field("UIInterfaceOrientationLandscapeLeft", &IosOrientations::m_landscapeLeft)
|
||||
->Field("UIInterfaceOrientationPortrait", &IosOrientations::m_portraitBottom)
|
||||
->Field("UIInterfaceOrientationPortraitUpsideDown", &IosOrientations::m_portraitTop)
|
||||
;
|
||||
|
||||
AZ::EditContext* editContext = serialize->GetEditContext();
|
||||
if (editContext)
|
||||
{
|
||||
editContext->Class<IosOrientations>("Orientations", "All supported orientations for iOS.")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &IosOrientations::m_landscapeRight, "Landscape (right home button)", "Enable landscape orientation with home button on right side of device.")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &IosOrientations::m_landscapeLeft, "Landscape (left home button)", "Enable landscape orientation with home button on left side of device.")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &IosOrientations::m_portraitBottom, "Portrait (bottom home button)", "Enable portrait orientation with home button on bottom of device.")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &IosOrientations::m_portraitTop, "Portrait (top home button)", "Enable portrait orientation with home button on top of device.")
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IosSettings::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
|
||||
if (serialize)
|
||||
{
|
||||
IosOrientations::Reflect(context);
|
||||
IosIcons::Reflect(context);
|
||||
IosLaunchscreens::Reflect(context);
|
||||
|
||||
serialize->Class<IosSettings>()
|
||||
->Version(1)
|
||||
->Field("CFBundleName", &IosSettings::m_bundleName)
|
||||
->Field("CFBundleDisplayName", &IosSettings::m_bundleDisplayName)
|
||||
->Field("CFBundleExecutable", &IosSettings::m_executableName)
|
||||
->Field("CFBundleIdentifier", &IosSettings::m_bundleIdentifier)
|
||||
->Field("CFBundleShortVersionString", &IosSettings::m_versionName)
|
||||
->Field("CFBundleVersion", &IosSettings::m_versionNumber)
|
||||
->Field("CFBundleDevelopmentRegion", &IosSettings::m_developmentRegion)
|
||||
->Field("UIRequiresFullScreen", &IosSettings::m_requiresFullscreen)
|
||||
->Field("UIStatusBarHidden", &IosSettings::m_hideStatusBar)
|
||||
->Field("UISupportedInterfaceOrientations", &IosSettings::m_iphoneOrientations)
|
||||
->Field("UISupportedInterfaceOrientations~ipad", &IosSettings::m_ipadOrientations)
|
||||
->Field("icons", &IosSettings::m_icons)
|
||||
->Field("launchscreens", &IosSettings::m_launchscreens)
|
||||
;
|
||||
|
||||
AZ::EditContext* editContext = serialize->GetEditContext();
|
||||
if (editContext)
|
||||
{
|
||||
editContext->Class<IosSettings>("Ios Settings", "All settings iOS settings.")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
|
||||
->DataElement(Handlers::LinkedLineEdit, &IosSettings::m_bundleName, "Bundle Name", "The name of the bundle.")
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::FileName))
|
||||
->Attribute(Attributes::PropertyIdentfier, Identfiers::IosBundleName)
|
||||
->Attribute(Attributes::LinkedProperty, Identfiers::ProjectName)
|
||||
->DataElement(Handlers::LinkedLineEdit, &IosSettings::m_bundleDisplayName, "Display Name", "The user visible name of the bundle.")
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::IsNotEmpty))
|
||||
->Attribute(Attributes::PropertyIdentfier, Identfiers::IosDisplayName)
|
||||
->Attribute(Attributes::LinkedProperty, Identfiers::ProductName)
|
||||
->DataElement(Handlers::LinkedLineEdit, &IosSettings::m_executableName, "Executable Name", "Name of the bundle's executable file.")
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::FileName))
|
||||
->Attribute(Attributes::PropertyIdentfier, Identfiers::IosExecutableName)
|
||||
->Attribute(Attributes::LinkedProperty, Identfiers::ExecutableName)
|
||||
->DataElement(Handlers::LinkedLineEdit, &IosSettings::m_bundleIdentifier, "Bundle Identifier", "Uniquely identifies the bundle. Should be in reverse-DNS format.")
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::PackageName))
|
||||
->Attribute(Attributes::LinkOptional, true)
|
||||
->Attribute(Attributes::PropertyIdentfier, Identfiers::IosBundleIdentifer)
|
||||
->Attribute(Attributes::LinkedProperty, Identfiers::AndroidPackageName)
|
||||
->DataElement(Handlers::LinkedLineEdit, &IosSettings::m_versionName, "Version Name", "The release version number string for the app. Displayed in the app store.")
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::IOSVersionNumber))
|
||||
->Attribute(Attributes::LinkOptional, true)
|
||||
->Attribute(Attributes::PropertyIdentfier, Identfiers::IosVersionName)
|
||||
->Attribute(Attributes::LinkedProperty, Identfiers::AndroidVersionName)
|
||||
->DataElement(Handlers::QValidatedLineEdit, &IosSettings::m_versionNumber, "Version Number", "The build version number string for the bundle.")
|
||||
->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::IOSVersionNumber))
|
||||
->DataElement(AZ::Edit::UIHandlers::ComboBox, &IosSettings::m_developmentRegion, "Development Region", "The default language and region for the app.")
|
||||
->Attribute(AZ::Edit::Attributes::StringList, AZStd::vector<AZStd::string>
|
||||
{
|
||||
"en_US",
|
||||
"en_CA",
|
||||
"fr_CA",
|
||||
"zh_CN",
|
||||
"fr_FR",
|
||||
"de_DE",
|
||||
"it_IT",
|
||||
"ja_JP",
|
||||
"ko_KR",
|
||||
"zh_TW",
|
||||
"en_GB"
|
||||
})
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &IosSettings::m_requiresFullscreen, "Requires Fullscreen", "Specifies whether the app is required to run in fullscreen mode.")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &IosSettings::m_hideStatusBar, "Hide Status Bar", "Specifies whether the status bar is initially hidden when the app launches.")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &IosSettings::m_iphoneOrientations, "iPhone Orientations", "Enable support for iPhone orientations.")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &IosSettings::m_ipadOrientations, "iPad Orientations", "Enable support for iPad orientations.")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &IosSettings::m_icons)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &IosSettings::m_launchscreens)
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace ProjectSettingsTool
|
||||
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Serialization/EditContext.h>
|
||||
|
||||
namespace ProjectSettingsTool
|
||||
{
|
||||
class IosIcons
|
||||
{
|
||||
public:
|
||||
AZ_TYPE_INFO(IosIcons, "{A57F9F23-36F5-4425-B40A-56D60119E5C9}");
|
||||
AZ_CLASS_ALLOCATOR(IosIcons, AZ::SystemAllocator, 0);
|
||||
|
||||
IosIcons()
|
||||
: m_appStore("")
|
||||
, m_iphoneApp120("")
|
||||
, m_iphoneApp180("")
|
||||
, m_iphoneNotification40("")
|
||||
, m_iphoneNotification60("")
|
||||
, m_iphoneSettings58("")
|
||||
, m_iphoneSettings87("")
|
||||
, m_iphoneSpotlight80("")
|
||||
, m_iphoneSpotlight120("")
|
||||
, m_ipadApp76("")
|
||||
, m_ipadApp152("")
|
||||
, m_ipadProApp("")
|
||||
, m_ipadNotification20("")
|
||||
, m_ipadNotification40("")
|
||||
, m_ipadSettings29("")
|
||||
, m_ipadSettings58("")
|
||||
, m_ipadSpotlight40("")
|
||||
, m_ipadSpotlight80("")
|
||||
{}
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
AZStd::string m_appStore;
|
||||
AZStd::string m_iphoneApp120;
|
||||
AZStd::string m_iphoneApp180;
|
||||
AZStd::string m_iphoneNotification40;
|
||||
AZStd::string m_iphoneNotification60;
|
||||
AZStd::string m_iphoneSettings58;
|
||||
AZStd::string m_iphoneSettings87;
|
||||
AZStd::string m_iphoneSpotlight80;
|
||||
AZStd::string m_iphoneSpotlight120;
|
||||
AZStd::string m_ipadApp76;
|
||||
AZStd::string m_ipadApp152;
|
||||
AZStd::string m_ipadProApp;
|
||||
AZStd::string m_ipadNotification20;
|
||||
AZStd::string m_ipadNotification40;
|
||||
AZStd::string m_ipadSettings29;
|
||||
AZStd::string m_ipadSettings58;
|
||||
AZStd::string m_ipadSpotlight40;
|
||||
AZStd::string m_ipadSpotlight80;
|
||||
};
|
||||
|
||||
class IosLaunchscreens
|
||||
{
|
||||
public:
|
||||
AZ_TYPE_INFO(IosLaunchscreens, "{1A34706F-9558-4081-9898-33758B026629}");
|
||||
AZ_CLASS_ALLOCATOR(IosLaunchscreens, AZ::SystemAllocator, 0);
|
||||
|
||||
IosLaunchscreens()
|
||||
: m_iphone640x960("")
|
||||
, m_iphone640x1136("")
|
||||
, m_iphone750x1334("")
|
||||
, m_iphone1125x2436("")
|
||||
, m_iphone2436x1125("")
|
||||
, m_iphone1242x2208("")
|
||||
, m_iphone2208x1242("")
|
||||
, m_ipad768x1024("")
|
||||
, m_ipad1024x768("")
|
||||
, m_ipad1536x2048("")
|
||||
, m_ipad2048x1536("")
|
||||
{}
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
AZStd::string m_iphone640x960;
|
||||
AZStd::string m_iphone640x1136;
|
||||
AZStd::string m_iphone750x1334;
|
||||
AZStd::string m_iphone1125x2436;
|
||||
AZStd::string m_iphone2436x1125;
|
||||
AZStd::string m_iphone1242x2208;
|
||||
AZStd::string m_iphone2208x1242;
|
||||
AZStd::string m_ipad768x1024;
|
||||
AZStd::string m_ipad1024x768;
|
||||
AZStd::string m_ipad1536x2048;
|
||||
AZStd::string m_ipad2048x1536;
|
||||
};
|
||||
|
||||
class IosOrientations
|
||||
{
|
||||
public:
|
||||
AZ_TYPE_INFO(IosOrientations, "{A42CDF2E-CCE1-4D93-9D4E-2270CFC0F2ED}");
|
||||
AZ_CLASS_ALLOCATOR(IosOrientations, AZ::SystemAllocator, 0);
|
||||
|
||||
IosOrientations()
|
||||
: m_landscapeRight(false)
|
||||
, m_landscapeLeft(false)
|
||||
, m_portraitBottom(false)
|
||||
, m_portraitTop(false)
|
||||
{}
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
bool m_landscapeRight;
|
||||
bool m_landscapeLeft;
|
||||
bool m_portraitBottom;
|
||||
bool m_portraitTop;
|
||||
};
|
||||
|
||||
class IosSettings
|
||||
{
|
||||
public:
|
||||
AZ_TYPE_INFO(IosSettings, "{9EDF051E-0158-4ADE-92A3-B7AC230E0114}");
|
||||
AZ_CLASS_ALLOCATOR(IosSettings, AZ::SystemAllocator, 0);
|
||||
|
||||
IosSettings()
|
||||
: m_bundleName("")
|
||||
, m_bundleDisplayName("")
|
||||
, m_executableName("")
|
||||
, m_bundleIdentifier("com.amazon.o3de.UnknownProject")
|
||||
, m_versionName("1.0.0")
|
||||
, m_versionNumber("1.0.0")
|
||||
, m_developmentRegion("en_US")
|
||||
, m_requiresFullscreen(false)
|
||||
, m_hideStatusBar(false)
|
||||
, m_iphoneOrientations()
|
||||
, m_ipadOrientations()
|
||||
, m_icons()
|
||||
, m_launchscreens()
|
||||
{}
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
AZStd::string m_bundleName;
|
||||
AZStd::string m_bundleDisplayName;
|
||||
AZStd::string m_executableName;
|
||||
AZStd::string m_bundleIdentifier;
|
||||
AZStd::string m_versionName;
|
||||
AZStd::string m_versionNumber;
|
||||
AZStd::string m_developmentRegion;
|
||||
bool m_requiresFullscreen;
|
||||
bool m_hideStatusBar;
|
||||
IosOrientations m_iphoneOrientations;
|
||||
IosOrientations m_ipadOrientations;
|
||||
IosIcons m_icons;
|
||||
IosLaunchscreens m_launchscreens;
|
||||
};
|
||||
} // namespace ProjectSettingsTool
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Math/Crc.h>
|
||||
|
||||
#include "Utils.h"
|
||||
|
||||
namespace ProjectSettingsTool
|
||||
{
|
||||
namespace Attributes
|
||||
{
|
||||
static const AZ::Crc32 FuncValidator = AZ_CRC("FuncValidator");
|
||||
static const AZ::Crc32 SelectFunction = AZ_CRC("SelectFunction");
|
||||
static const AZ::Crc32 LinkOptional = AZ_CRC("LinkOptional");
|
||||
static const AZ::Crc32 Obfuscated = AZ_CRC("ObfuscatedText");
|
||||
// Used as a tooltip and for distinguising linked properties
|
||||
static const AZ::Crc32 PropertyIdentfier = AZ_CRC("PropertyIdentfier");
|
||||
static const AZ::Crc32 LinkedProperty = AZ_CRC("LinkedProperty");
|
||||
static const AZ::Crc32 DefaultPath = AZ_CRC("DefaultPath");
|
||||
static const AZ::Crc32 DefaultImagePreview = AZ_CRC("DefaultImagePreview");
|
||||
static const AZ::Crc32 ObfuscatedText = AZ_CRC("ObfuscatedText");
|
||||
static const AZ::Crc32 ClearButton = AZ_CRC("ClearButton");
|
||||
static const AZ::Crc32 RemovableReadOnly = AZ_CRC("RemovableReadOnly");
|
||||
} // namespace Attributes
|
||||
|
||||
namespace Handlers
|
||||
{
|
||||
static const AZ::Crc32 ImagePreview = AZ_CRC("ImagePreview");
|
||||
static const AZ::Crc32 LinkedLineEdit = AZ_CRC("LinkedLineEdit");
|
||||
static const AZ::Crc32 FileSelect = AZ_CRC("FileSelect");
|
||||
static const AZ::Crc32 QValidatedLineEdit = AZ_CRC("QValLineEdit");
|
||||
static const AZ::Crc32 QValidatedBrowseEdit = AZ_CRC("QValBrowseEdit");
|
||||
} // namespace Handlers
|
||||
|
||||
namespace Identfiers
|
||||
{
|
||||
static const char* ProjectName = "Base - Project Name";
|
||||
static const char* ProductName = "Base - Product Name";
|
||||
static const char* ExecutableName = "Base - Executable Name";
|
||||
|
||||
static const char* AndroidPackageName = "Android - Package Name";
|
||||
static const char* AndroidVersionName = "Android - Version Name";
|
||||
static const char* AndroidIconDefault = "Android - Icon Default";
|
||||
static const char* AndroidLandDefault = "Android - Land Default";
|
||||
static const char* AndroidPortDefault = "Android - Port Default";
|
||||
|
||||
static const char* IosBundleName = "iOS - Bundle Name";
|
||||
static const char* IosDisplayName = "iOS - Display Name";
|
||||
static const char* IosExecutableName = "iOS - Executable Name";
|
||||
static const char* IosBundleIdentifer = "iOS - Bundle Identifer";
|
||||
static const char* IosVersionName = "iOS - Version Name";
|
||||
} // namespace Identfiers
|
||||
} // namespace ProjectSettingsTool
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace ProjectSettingsTool
|
||||
{
|
||||
enum class PlatformId
|
||||
{
|
||||
Base,
|
||||
Android,
|
||||
Ios,
|
||||
|
||||
NumPlatformIds
|
||||
};
|
||||
|
||||
enum class PlatformDataType
|
||||
{
|
||||
ProjectJson,
|
||||
Plist,
|
||||
|
||||
NumPlatformDataTypes
|
||||
};
|
||||
|
||||
struct Platform
|
||||
{
|
||||
PlatformId m_id;
|
||||
PlatformDataType m_type;
|
||||
};
|
||||
|
||||
const Platform Platforms[static_cast<unsigned>(PlatformId::NumPlatformIds)]
|
||||
{
|
||||
Platform{ PlatformId::Base, PlatformDataType::ProjectJson },
|
||||
Platform{ PlatformId::Android, PlatformDataType::ProjectJson },
|
||||
Platform{ PlatformId::Ios, PlatformDataType::Plist }
|
||||
};
|
||||
|
||||
} // namespace ProjectSettingsTool
|
||||
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ProjectSettingsTool_precompiled.h"
|
||||
#include "PlistDictionary.h"
|
||||
|
||||
|
||||
namespace ProjectSettingsTool
|
||||
{
|
||||
using namespace AZ;
|
||||
using XmlDocument = rapidxml::xml_document<char>;
|
||||
using XmlNode = rapidxml::xml_node<char>;
|
||||
|
||||
PlistDictionary::PlistDictionary(XmlDocument* plist)
|
||||
: m_document(plist)
|
||||
, m_dict(plist->first_node("plist")->first_node("dict"))
|
||||
{
|
||||
}
|
||||
|
||||
XmlNode* PlistDictionary::MakeNode(const char* name, const char* value)
|
||||
{
|
||||
return m_document->allocate_node
|
||||
(
|
||||
rapidxml::node_element,
|
||||
m_document->allocate_string(name),
|
||||
m_document->allocate_string(value)
|
||||
);
|
||||
}
|
||||
|
||||
XmlNode* PlistDictionary::MakeNode()
|
||||
{
|
||||
return m_document->allocate_node(rapidxml::node_element);
|
||||
}
|
||||
|
||||
XmlNode* PlistDictionary::GetPropertyKeyNode(const char* key)
|
||||
{
|
||||
XmlNode* keyNode = m_dict->first_node("key");
|
||||
// Look for the key in pList's interesting structure
|
||||
while (keyNode)
|
||||
{
|
||||
if (strcmp(keyNode->value(), key) == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
keyNode = keyNode->next_sibling("key");
|
||||
}
|
||||
|
||||
// Returns key if found otherwise nullptr
|
||||
return keyNode;
|
||||
}
|
||||
|
||||
XmlNode* PlistDictionary::GetPropertyValueNode(const char* key)
|
||||
{
|
||||
XmlNode* keyNode = GetPropertyKeyNode(key);
|
||||
|
||||
// Key found return data node
|
||||
if (keyNode != nullptr)
|
||||
{
|
||||
return keyNode->next_sibling();
|
||||
}
|
||||
// Failed to find key return nullptr
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
XmlNode* PlistDictionary::AddProperty(const char* key)
|
||||
{
|
||||
m_dict->append_node(MakeNode("key", key));
|
||||
XmlNode* data = MakeNode();
|
||||
m_dict->append_node(data);
|
||||
return data;
|
||||
}
|
||||
|
||||
void PlistDictionary::RemoveProperty(const char* key)
|
||||
{
|
||||
XmlNode* keyNode = GetPropertyKeyNode(key);
|
||||
|
||||
if (keyNode != nullptr)
|
||||
{
|
||||
XmlNode* dataNode = keyNode->next_sibling();
|
||||
|
||||
m_dict->remove_node(keyNode);
|
||||
m_dict->remove_node(dataNode);
|
||||
}
|
||||
}
|
||||
|
||||
const char* PlistDictionary::GetPropertyValue(const char* key)
|
||||
{
|
||||
XmlNode* valueNode = GetPropertyValueNode(key);
|
||||
return valueNode != nullptr ? GetPropertyValue(valueNode) : nullptr;
|
||||
}
|
||||
|
||||
const char* PlistDictionary::GetPropertyValue(XmlNode* node)
|
||||
{
|
||||
return node->value_size() > 0 ? node->value() : nullptr;
|
||||
}
|
||||
|
||||
const char* PlistDictionary::GetPropertyValueName(const char* key)
|
||||
{
|
||||
XmlNode* valueNode = GetPropertyValueNode(key);
|
||||
return valueNode != nullptr ? GetPropertyValueName(valueNode) : nullptr;
|
||||
}
|
||||
|
||||
const char* PlistDictionary::GetPropertyValueName(XmlNode* node)
|
||||
{
|
||||
return node->name_size() > 0 ? node->name() : nullptr;
|
||||
}
|
||||
|
||||
XmlNode* PlistDictionary::SetPropertyValue(const char* key, const char* newValue)
|
||||
{
|
||||
XmlNode* dataNode = GetPropertyValueNode(key);
|
||||
if (dataNode == nullptr)
|
||||
{
|
||||
dataNode = AddProperty(key);
|
||||
SetPropertyValueName(dataNode, "string");
|
||||
}
|
||||
SetPropertyValue(dataNode, newValue);
|
||||
|
||||
return dataNode;
|
||||
}
|
||||
|
||||
void PlistDictionary::SetPropertyValue(XmlNode* node, const char* newValue)
|
||||
{
|
||||
node->value(m_document->allocate_string(newValue));
|
||||
}
|
||||
|
||||
XmlNode* PlistDictionary::SetPropertyValueName(const char* key, const char* newName)
|
||||
{
|
||||
XmlNode* dataNode = GetPropertyValueNode(key);
|
||||
if (dataNode == nullptr)
|
||||
{
|
||||
dataNode = AddProperty(key);
|
||||
}
|
||||
SetPropertyValueName(dataNode, newName);
|
||||
|
||||
return dataNode;
|
||||
}
|
||||
|
||||
void PlistDictionary::SetPropertyValueName(XmlNode* node, const char* newName)
|
||||
{
|
||||
node->name(m_document->allocate_string(newName));
|
||||
}
|
||||
|
||||
bool PlistDictionary::ContainsValidDict(XmlDocument* plist)
|
||||
{
|
||||
XmlNode* node = plist->first_node("plist");
|
||||
if (node != nullptr)
|
||||
{
|
||||
node = node->first_node("dict");
|
||||
if (node != nullptr)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
} // namespace ProjectSettingsTool
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/XML/rapidxml.h>
|
||||
|
||||
namespace ProjectSettingsTool
|
||||
{
|
||||
// Wraps a plist dict node with a friendly api to allow lookups and other actions in it
|
||||
class PlistDictionary
|
||||
{
|
||||
public:
|
||||
// Constructs the dictionary wrapper
|
||||
PlistDictionary(AZ::rapidxml::xml_document<char>* plist);
|
||||
|
||||
// Allocates a new node with given name and value
|
||||
AZ::rapidxml::xml_node<char>* MakeNode(const char* name, const char* value);
|
||||
AZ::rapidxml::xml_node<char>* MakeNode();
|
||||
|
||||
// Returns pointer to property data node
|
||||
AZ::rapidxml::xml_node<char>* GetPropertyValueNode(const char* key);
|
||||
|
||||
// Creates a new property and returns pointer to its value node
|
||||
AZ::rapidxml::xml_node<char>* AddProperty(const char* key);
|
||||
// Removes property from dictionary
|
||||
void RemoveProperty(const char* key);
|
||||
|
||||
// Returns pointer to property data value or nullptr if it is empty
|
||||
const char* GetPropertyValue(const char* key);
|
||||
const char* GetPropertyValue(AZ::rapidxml::xml_node<char>* node);
|
||||
|
||||
// Returns pointer to property data name or nullptr if it is empty
|
||||
const char* GetPropertyValueName(const char* key);
|
||||
const char* GetPropertyValueName(AZ::rapidxml::xml_node<char>* node);
|
||||
|
||||
// Changes value of property data and creates it if it doesn't exist
|
||||
AZ::rapidxml::xml_node<char>* SetPropertyValue(const char* key, const char* newValue);
|
||||
void SetPropertyValue(AZ::rapidxml::xml_node<char>* node, const char* newValue);
|
||||
|
||||
// Changes name of property data and creates it if it doesn't exist
|
||||
AZ::rapidxml::xml_node<char>* SetPropertyValueName(const char* key, const char* newName);
|
||||
void SetPropertyValueName(AZ::rapidxml::xml_node<char>* node, const char* newName);
|
||||
|
||||
// Checks to make sure a plist file has a valid dictionary
|
||||
static bool ContainsValidDict(AZ::rapidxml::xml_document<char>* plist);
|
||||
|
||||
protected:
|
||||
// Returns pointer to property key node
|
||||
AZ::rapidxml::xml_node<char>* GetPropertyKeyNode(const char* key);
|
||||
|
||||
|
||||
// pList dictionary is found in
|
||||
AZ::rapidxml::xml_document<char>* m_document;
|
||||
// The dictionary of properties
|
||||
AZ::rapidxml::xml_node<char>* m_dict;
|
||||
};
|
||||
} // namespace ProjectSettingsTool
|
||||
@@ -0,0 +1,324 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ProjectSettingsTool_precompiled.h"
|
||||
#include "ProjectSettingsContainer.h"
|
||||
|
||||
#include <AzCore/JSON/prettywriter.h>
|
||||
#include <AzCore/JSON/stringbuffer.h>
|
||||
#include <AzCore/XML/rapidxml_print.h>
|
||||
|
||||
#include <Util/FileUtil.h>
|
||||
|
||||
namespace ProjectSettingsTool
|
||||
{
|
||||
using namespace AZ;
|
||||
using StringOutcome = Outcome<void, AZStd::string>;
|
||||
using XmlDocument = rapidxml::xml_document<char>;
|
||||
using XmlNode = rapidxml::xml_node<char>;
|
||||
|
||||
const int xmlFlags = rapidxml::parse_doctype_node | rapidxml::parse_declaration_node | rapidxml::parse_no_data_nodes;
|
||||
|
||||
SettingsError::SettingsError(const AZStd::string& error, const AZStd::string& reason)
|
||||
{
|
||||
m_error = error;
|
||||
m_reason = reason;
|
||||
}
|
||||
|
||||
StringOutcome WriteConfigFile(const AZStd::string& fileName, const AZStd::string& fileContents)
|
||||
{
|
||||
using AZ::IO::SystemFile;
|
||||
const char* filePath = fileName.c_str();
|
||||
|
||||
// Attempt to make file writable or check it out in source control
|
||||
if (CFileUtil::OverwriteFile(filePath))
|
||||
{
|
||||
if (!CFileUtil::CreateDirectory(fileName.substr(0, fileName.find_last_of('/')).data()))
|
||||
{
|
||||
return AZ::Failure(AZStd::string::format("Could not create the directory for file \"%s\".", filePath));
|
||||
}
|
||||
|
||||
SystemFile settingsFile;
|
||||
if (!settingsFile.Open(filePath, SystemFile::SF_OPEN_WRITE_ONLY | SystemFile::SF_OPEN_CREATE))
|
||||
{
|
||||
return AZ::Failure(AZStd::string::format("Failed to open settings file %s for write.", filePath));
|
||||
}
|
||||
|
||||
if (settingsFile.Write(fileContents.c_str(), fileContents.size()) != fileContents.size())
|
||||
{
|
||||
return AZ::Failure(AZStd::string::format("Failed to write to file %s.", filePath));
|
||||
}
|
||||
|
||||
|
||||
settingsFile.Close();
|
||||
return AZ::Success();
|
||||
}
|
||||
|
||||
return AZ::Failure(AZStd::string::format("Could not check out or make file writable: \"%s\".", filePath));
|
||||
}
|
||||
|
||||
StringOutcome ReadConfigFile(const AZStd::string& fileName, AZStd::string& fileContents)
|
||||
{
|
||||
using AZ::IO::SystemFile;
|
||||
const char* filePath = fileName.c_str();
|
||||
|
||||
if (!SystemFile::Exists(filePath))
|
||||
{
|
||||
return AZ::Failure(AZStd::string::format("%s file doesn't exist.", filePath));
|
||||
}
|
||||
|
||||
SystemFile settingsFile;
|
||||
if (!settingsFile.Open(filePath, SystemFile::SF_OPEN_READ_ONLY))
|
||||
{
|
||||
return AZ::Failure(AZStd::string::format("Failed to open settings file %s.", filePath));
|
||||
}
|
||||
|
||||
fileContents = AZStd::string(settingsFile.Length(), '\0');
|
||||
settingsFile.Read(fileContents.size(), fileContents.data());
|
||||
|
||||
settingsFile.Close();
|
||||
return AZ::Success();
|
||||
}
|
||||
|
||||
|
||||
ProjectSettingsContainer::ProjectSettingsContainer(const AZStd::string& projectJsonFileName, PlistInitVector& plistPaths)
|
||||
: m_projectJson(JsonSettings{ projectJsonFileName, "", AZStd::make_unique<rapidjson::Document>() })
|
||||
{
|
||||
LoadProjectJsonData();
|
||||
|
||||
for (PlatformAndPath& plistInfo : plistPaths)
|
||||
{
|
||||
m_pListsMap.insert(AZStd::pair<PlatformId, PlistSettings>(
|
||||
plistInfo.first,
|
||||
PlistSettings{ plistInfo.second, "", AZStd::make_unique<XmlDocument>() }));
|
||||
|
||||
// We will have to find it then because unique_ptrs are not copy constructible
|
||||
// And a move constructor would copy large strings
|
||||
LoadPlist(m_pListsMap.find(plistInfo.first)->second);
|
||||
}
|
||||
}
|
||||
|
||||
ProjectSettingsContainer::~ProjectSettingsContainer()
|
||||
{
|
||||
}
|
||||
|
||||
ProjectSettingsContainer::PlistSettings* ProjectSettingsContainer::GetPlistSettingsForPlatform(const Platform& plat)
|
||||
{
|
||||
PlistSettings* result = nullptr;
|
||||
|
||||
if (plat.m_type == PlatformDataType::Plist)
|
||||
{
|
||||
auto iter = m_pListsMap.find(plat.m_id);
|
||||
|
||||
if (iter != m_pListsMap.end())
|
||||
{
|
||||
result = &iter->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Assert(false, "Failed to find pList for platform.");
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool ProjectSettingsContainer::IsPlistPlatform(const Platform& plat)
|
||||
{
|
||||
if (plat.m_type == PlatformDataType::Plist)
|
||||
{
|
||||
auto iter = m_pListsMap.find(plat.m_id);
|
||||
|
||||
if (iter != m_pListsMap.end())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
AZ::Outcome<void, SettingsError> ProjectSettingsContainer::GetError()
|
||||
{
|
||||
if (!m_errors.empty())
|
||||
{
|
||||
SettingsError error = m_errors.front();
|
||||
m_errors.pop();
|
||||
|
||||
return AZ::Failure(error);
|
||||
}
|
||||
return AZ::Success();
|
||||
}
|
||||
|
||||
void ProjectSettingsContainer::SavePlatformData(const Platform& plat)
|
||||
{
|
||||
PlistSettings* plistSettings = GetPlistSettingsForPlatform(plat);
|
||||
if (plistSettings != nullptr)
|
||||
{
|
||||
SavePlist(*plistSettings);
|
||||
}
|
||||
else
|
||||
{
|
||||
SaveProjectJsonData();
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectSettingsContainer::SaveProjectJsonData()
|
||||
{
|
||||
// Needed to write a document out to a string
|
||||
rapidjson::StringBuffer jsonDataBuffer;
|
||||
// Use pretty writer so it can be read easier
|
||||
rapidjson::PrettyWriter<rapidjson::StringBuffer> jsonDatawriter(jsonDataBuffer);
|
||||
|
||||
m_projectJson.m_document->Accept(jsonDatawriter);
|
||||
const AZStd::string jsonDataString = jsonDataBuffer.GetString();
|
||||
|
||||
StringOutcome outcome = WriteConfigFile(m_projectJson.m_path, jsonDataString);
|
||||
|
||||
if (!outcome.IsSuccess())
|
||||
{
|
||||
m_errors.push(SettingsError("Failed to save project.json", outcome.GetError()));
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectSettingsContainer::ReloadProjectJsonData()
|
||||
{
|
||||
m_projectJson.m_document.reset(new rapidjson::Document);
|
||||
LoadProjectJsonData();
|
||||
}
|
||||
|
||||
void ProjectSettingsContainer::SavePlistsData()
|
||||
{
|
||||
for (AZStd::pair<PlatformId, PlistSettings>& plist : m_pListsMap)
|
||||
{
|
||||
LoadPlist(plist.second);
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectSettingsContainer::SavePlistData(const Platform& plat)
|
||||
{
|
||||
PlistSettings* settings = GetPlistSettingsForPlatform(plat);
|
||||
if (settings != nullptr)
|
||||
{
|
||||
SavePlist(*settings);
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectSettingsContainer::ReloadPlistData()
|
||||
{
|
||||
for (AZStd::pair<PlatformId, PlistSettings>& plist : m_pListsMap)
|
||||
{
|
||||
PlistSettings& plistSettings = plist.second;
|
||||
|
||||
plistSettings.m_document.reset(new XmlDocument());
|
||||
LoadPlist(plistSettings);
|
||||
}
|
||||
}
|
||||
|
||||
rapidjson::Document& ProjectSettingsContainer::GetProjectJsonDocument()
|
||||
{
|
||||
return *m_projectJson.m_document.get();
|
||||
}
|
||||
|
||||
AZ::Outcome<rapidjson::Value*, void> ProjectSettingsContainer::GetProjectJsonValue(const char* key)
|
||||
{
|
||||
// Try to find member
|
||||
rapidjson::Document& settings = *m_projectJson.m_document;
|
||||
rapidjson::Value::MemberIterator memberIterator = settings.FindMember(key);
|
||||
if (memberIterator != settings.MemberEnd())
|
||||
{
|
||||
return AZ::Success(&memberIterator->value);
|
||||
}
|
||||
else
|
||||
{
|
||||
settings.AddMember(rapidjson::Value(key, settings.GetAllocator()),
|
||||
rapidjson::Value(rapidjson::kNullType), settings.GetAllocator());
|
||||
return AZ::Success(&settings.FindMember(key)->value);
|
||||
}
|
||||
}
|
||||
|
||||
AZStd::unique_ptr<PlistDictionary> ProjectSettingsContainer::GetPlistDictionary(const Platform& plat)
|
||||
{
|
||||
if (plat.m_type == PlatformDataType::Plist)
|
||||
{
|
||||
PlistSettings* settings = GetPlistSettingsForPlatform(plat);
|
||||
if (settings != nullptr)
|
||||
{
|
||||
|
||||
if (PlistDictionary::ContainsValidDict(settings->m_document.get()))
|
||||
{
|
||||
return AZStd::make_unique<PlistDictionary>(settings->m_document.get());
|
||||
}
|
||||
else
|
||||
{
|
||||
//TODO: Query user if they would like to remake a valid plist then do it
|
||||
AZStd::string platformName;
|
||||
switch (plat.m_id)
|
||||
{
|
||||
case PlatformId::Ios:
|
||||
platformName = "iOS";
|
||||
break;
|
||||
default:
|
||||
platformName = "unknown";
|
||||
break;
|
||||
}
|
||||
AZ_Assert(false, "%s pList is in invalid state.", platformName.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AZ_Assert(false, "This platform does not use pLists to store data.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>& ProjectSettingsContainer::GetProjectJsonAllocator()
|
||||
{
|
||||
return m_projectJson.m_document->GetAllocator();
|
||||
}
|
||||
|
||||
const char* ProjectSettingsContainer::GetFailedLoadingPlistText()
|
||||
{
|
||||
return "Failed to load info.plist";
|
||||
}
|
||||
|
||||
void ProjectSettingsContainer::LoadProjectJsonData()
|
||||
{
|
||||
StringOutcome outcome = ReadConfigFile(m_projectJson.m_path, m_projectJson.m_rawData);
|
||||
if (!outcome.IsSuccess())
|
||||
{
|
||||
m_errors.push(SettingsError("Failed to load project.json", outcome.GetError()));
|
||||
}
|
||||
|
||||
m_projectJson.m_document->Parse(m_projectJson.m_rawData.c_str());
|
||||
}
|
||||
|
||||
// Loads info.plist for iOS from disk
|
||||
void ProjectSettingsContainer::LoadPlist(PlistSettings& plistSettings)
|
||||
{
|
||||
StringOutcome outcome = ReadConfigFile(plistSettings.m_path, plistSettings.m_rawData);
|
||||
if (!outcome.IsSuccess())
|
||||
{
|
||||
m_errors.push(SettingsError(GetFailedLoadingPlistText(), outcome.GetError()));
|
||||
}
|
||||
|
||||
plistSettings.m_document->parse<xmlFlags>(plistSettings.m_rawData.data());
|
||||
}
|
||||
|
||||
void ProjectSettingsContainer::SavePlist(PlistSettings& plistSettings)
|
||||
{
|
||||
// Needed to write a document out to a string
|
||||
AZStd::string xmlDocString;
|
||||
rapidxml::print(std::back_inserter(xmlDocString), *plistSettings.m_document);
|
||||
|
||||
StringOutcome outcome = WriteConfigFile(plistSettings.m_path, xmlDocString);
|
||||
|
||||
if (!outcome.IsSuccess())
|
||||
{
|
||||
m_errors.push(SettingsError("Failed to save info.pList", outcome.GetError()));
|
||||
}
|
||||
}
|
||||
} // namespace ProjectSettingsTool
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Platforms.h"
|
||||
#include "PlistDictionary.h"
|
||||
|
||||
#include <AzCore/JSON/document.h>
|
||||
#include <AzCore/Outcome/Outcome.h>
|
||||
#include <AzCore/std/smart_ptr/unique_ptr.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
#include <AzFramework/StringFunc/StringFunc.h>
|
||||
|
||||
|
||||
namespace ProjectSettingsTool
|
||||
{
|
||||
|
||||
struct SettingsError
|
||||
{
|
||||
SettingsError(const AZStd::string& error, const AZStd::string& reason);
|
||||
|
||||
// The error that occurred
|
||||
AZStd::string m_error;
|
||||
// The reason the error occurred
|
||||
AZStd::string m_reason;
|
||||
};
|
||||
|
||||
// Loads, saves, and provides access to all of the project settings files
|
||||
class ProjectSettingsContainer
|
||||
{
|
||||
public:
|
||||
typedef AZStd::pair<PlatformId, AZStd::string> PlatformAndPath;
|
||||
typedef AZStd::vector<PlatformAndPath> PlistInitVector;
|
||||
|
||||
template<class DocType>
|
||||
struct PlatformSettings
|
||||
{
|
||||
// File path to document
|
||||
AZStd::string m_path;
|
||||
// Raw string loaded from file
|
||||
AZStd::string m_rawData;
|
||||
// The document itself
|
||||
AZStd::unique_ptr<DocType> m_document;
|
||||
|
||||
};
|
||||
|
||||
using JsonSettings = PlatformSettings<rapidjson::Document>;
|
||||
using PlistSettings = PlatformSettings<AZ::rapidxml::xml_document<char>>;
|
||||
|
||||
// Constructs the main manager of a document
|
||||
ProjectSettingsContainer(const AZStd::string& projectJsonFileName, PlistInitVector& plistPaths);
|
||||
|
||||
// Used to destroy valueDoesNotExist
|
||||
~ProjectSettingsContainer();
|
||||
|
||||
// Returns the PlistSettings for given platform
|
||||
PlistSettings* GetPlistSettingsForPlatform(const Platform& plat);
|
||||
// Returns true if PlistSettings are found for platform
|
||||
bool IsPlistPlatform(const Platform& plat);
|
||||
|
||||
// Gets the earliest error not seen
|
||||
AZ::Outcome<void, SettingsError> GetError();
|
||||
// Save settings for given platform
|
||||
void SavePlatformData(const Platform& plat);
|
||||
// Saves project.json to disk
|
||||
void SaveProjectJsonData();
|
||||
// Reloads Project.json from disk
|
||||
void ReloadProjectJsonData();
|
||||
// Save all pLists back to disk
|
||||
void SavePlistsData();
|
||||
// Save platform's plist data back to disk
|
||||
void SavePlistData(const Platform& plat);
|
||||
// Reloads all plists from disk
|
||||
void ReloadPlistData();
|
||||
// Returns a reference to the project.json Document
|
||||
rapidjson::Document& GetProjectJsonDocument();
|
||||
// Gets reference to value in project.json
|
||||
// returns null type if not found
|
||||
AZ::Outcome<rapidjson::Value*, void> GetProjectJsonValue(const char* key);
|
||||
|
||||
AZStd::unique_ptr<PlistDictionary> GetPlistDictionary(const Platform& plat);
|
||||
|
||||
// Returns the allocator used by ProjectJson
|
||||
rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>& GetProjectJsonAllocator();
|
||||
|
||||
static const char* GetFailedLoadingPlistText();
|
||||
|
||||
|
||||
protected:
|
||||
// Loads project.json from disk
|
||||
void LoadProjectJsonData();
|
||||
// Loads info.plist from filePath into given document
|
||||
void LoadPlist(PlistSettings& plistSettings);
|
||||
void SavePlist(PlistSettings& plistSettings);
|
||||
|
||||
// Errors that have occurred
|
||||
AZStd::queue<SettingsError> m_errors;
|
||||
// The project.json document
|
||||
JsonSettings m_projectJson;
|
||||
// A map to all of the loaded pLists
|
||||
AZStd::unordered_map<PlatformId, PlistSettings> m_pListsMap;
|
||||
|
||||
|
||||
private:
|
||||
AZ_DISABLE_COPY_MOVE(ProjectSettingsContainer);
|
||||
};
|
||||
} // namespace ProjectSettingsTool
|
||||
@@ -0,0 +1,919 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ProjectSettingsTool_precompiled.h"
|
||||
#include "ProjectSettingsSerialization.h"
|
||||
|
||||
#include "PlatformSettings_common.h"
|
||||
|
||||
#include <AzToolsFramework/UI/PropertyEditor/InstanceDataHierarchy.h>
|
||||
#include <AzToolsFramework/UI/PropertyEditor/PropertyEditorAPI.h>
|
||||
|
||||
// Needed to overwrite ios icons and launchscreens
|
||||
#include <Util/FileUtil.h>
|
||||
|
||||
namespace ProjectSettingsTool
|
||||
{
|
||||
using XmlNode = AZ::rapidxml::xml_node<char>;
|
||||
|
||||
const char* stringStr = "string";
|
||||
const char* arrayStr = "array";
|
||||
const char* trueStr = "true";
|
||||
const char* noDocumentError = "No json or xml document to use for Project Settings Tool serialization.";
|
||||
|
||||
Serializer::Serializer(AzToolsFramework::InstanceDataNode* root)
|
||||
: m_root(root)
|
||||
, m_jsonDoc(nullptr)
|
||||
, m_jsonRoot(nullptr)
|
||||
, m_idString(AZ::SerializeTypeInfo<AZStd::string>::GetUuid())
|
||||
, m_idInt(AZ::SerializeTypeInfo<int>::GetUuid())
|
||||
, m_idBool(AZ::SerializeTypeInfo<bool>::GetUuid())
|
||||
{}
|
||||
|
||||
Serializer::Serializer(AzToolsFramework::InstanceDataNode* root, rapidjson::Document* doc, rapidjson::Value* jsonRoot)
|
||||
: Serializer(root)
|
||||
{
|
||||
SetDocumentRoot(doc);
|
||||
if (jsonRoot != nullptr)
|
||||
{
|
||||
SetJsonRoot(jsonRoot);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetJsonRoot(doc);
|
||||
}
|
||||
}
|
||||
|
||||
Serializer::Serializer(AzToolsFramework::InstanceDataNode* root, AZStd::unique_ptr<PlistDictionary> dict)
|
||||
: Serializer(root)
|
||||
{
|
||||
SetDocumentRoot(AZStd::move(dict));
|
||||
}
|
||||
|
||||
void Serializer::SetDocumentRoot(rapidjson::Document* doc)
|
||||
{
|
||||
m_jsonDoc = doc;
|
||||
}
|
||||
|
||||
void Serializer::SetJsonRoot(rapidjson::Value* jsonRoot)
|
||||
{
|
||||
m_jsonRoot = jsonRoot;
|
||||
}
|
||||
|
||||
void Serializer::SetDocumentRoot(AZStd::unique_ptr<PlistDictionary> dict)
|
||||
{
|
||||
m_plistDict = AZStd::move(dict);
|
||||
}
|
||||
|
||||
bool Serializer::UiEqualToSettings() const
|
||||
{
|
||||
if (m_jsonRoot != nullptr)
|
||||
{
|
||||
return UiEqualToJson(m_jsonRoot);
|
||||
}
|
||||
else if (m_plistDict)
|
||||
{
|
||||
return UiEqualToPlist(m_root);
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Assert(false, noDocumentError);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void Serializer::LoadFromSettings()
|
||||
{
|
||||
if (m_jsonRoot != nullptr)
|
||||
{
|
||||
LoadFromSettings(m_jsonRoot);
|
||||
}
|
||||
else if (m_plistDict)
|
||||
{
|
||||
LoadFromSettings(m_root);
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Assert(false, noDocumentError);
|
||||
}
|
||||
}
|
||||
|
||||
void Serializer::SaveToSettings()
|
||||
{
|
||||
if (m_jsonRoot != nullptr)
|
||||
{
|
||||
SaveToSettings(m_jsonRoot);
|
||||
}
|
||||
else if (m_plistDict)
|
||||
{
|
||||
SaveToSettings(m_root);
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Assert(false, noDocumentError);
|
||||
}
|
||||
}
|
||||
|
||||
bool Serializer::UiEqualToJson(rapidjson::Value* root) const
|
||||
{
|
||||
return UiEqualToJson(root, m_root);
|
||||
}
|
||||
|
||||
void Serializer::LoadFromSettings(rapidjson::Value* root)
|
||||
{
|
||||
LoadFromSettings(root, m_root);
|
||||
}
|
||||
|
||||
void Serializer::SaveToSettings(rapidjson::Value* root)
|
||||
{
|
||||
// This value needs to be an object to add members
|
||||
if (!root->IsObject())
|
||||
{
|
||||
root->SetObject();
|
||||
}
|
||||
SaveToSettings(root, m_root);
|
||||
}
|
||||
|
||||
bool Serializer::UiEqualToJson(rapidjson::Value* root, AzToolsFramework::InstanceDataNode* node) const
|
||||
{
|
||||
const AZ::SerializeContext::ClassData* baseMeta = node->GetClassMetadata();
|
||||
if (baseMeta)
|
||||
{
|
||||
for (AzToolsFramework::InstanceDataNode& childNode : node->GetChildren())
|
||||
{
|
||||
auto childMeta = childNode.GetElementMetadata();
|
||||
if (childMeta)
|
||||
{
|
||||
bool noDocElement = true;
|
||||
rapidjson::Value::MemberIterator jsonMember;
|
||||
const char* propertyName = childMeta->m_name;
|
||||
|
||||
// If there is a json object try to find the member
|
||||
if (root != nullptr)
|
||||
{
|
||||
jsonMember = root->FindMember(propertyName);
|
||||
|
||||
if (jsonMember != root->MemberEnd())
|
||||
{
|
||||
noDocElement = false;
|
||||
}
|
||||
}
|
||||
|
||||
AZ::Uuid type = childMeta->m_typeId;
|
||||
if (m_idString == type)
|
||||
{
|
||||
AZStd::string uiValue;
|
||||
childNode.Read(uiValue);
|
||||
|
||||
if (!uiValue.empty() && !noDocElement)
|
||||
{
|
||||
if (jsonMember->value.IsString())
|
||||
{
|
||||
if (uiValue != jsonMember->value.GetString())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (uiValue.empty() != noDocElement)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (m_idInt == type)
|
||||
{
|
||||
int uiValue;
|
||||
childNode.Read(uiValue);
|
||||
|
||||
if (!noDocElement)
|
||||
{
|
||||
if (jsonMember->value.IsInt())
|
||||
{
|
||||
if (uiValue != jsonMember->value.GetInt())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (m_idBool == type)
|
||||
{
|
||||
bool uiValue;
|
||||
childNode.Read(uiValue);
|
||||
|
||||
if (uiValue)
|
||||
{
|
||||
if (!noDocElement)
|
||||
{
|
||||
if (jsonMember->value.IsString())
|
||||
{
|
||||
AZStd::string expectedJsonValue = trueStr;
|
||||
if (expectedJsonValue != jsonMember->value.GetString())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (!noDocElement)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Should be a class with members instead of base data type
|
||||
else
|
||||
{
|
||||
rapidjson::Value* jsonNode = nullptr;
|
||||
if (!noDocElement)
|
||||
{
|
||||
jsonNode = &jsonMember->value;
|
||||
}
|
||||
// Drill into class
|
||||
if (!UiEqualToJson(jsonNode, &childNode))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Serializer::UiEqualToPlist(AzToolsFramework::InstanceDataNode* node) const
|
||||
{
|
||||
const AZ::SerializeContext::ClassData* baseMeta = node->GetClassMetadata();
|
||||
if (baseMeta)
|
||||
{
|
||||
for (AzToolsFramework::InstanceDataNode& childNode : node->GetChildren())
|
||||
{
|
||||
auto childMeta = childNode.GetElementMetadata();
|
||||
if (childMeta)
|
||||
{
|
||||
bool noDocElement = true;
|
||||
const char* propertyName = childMeta->m_name;
|
||||
XmlNode* plistNode = m_plistDict->GetPropertyValueNode(propertyName);
|
||||
|
||||
if (plistNode != nullptr)
|
||||
{
|
||||
noDocElement = false;
|
||||
}
|
||||
|
||||
AZ::Uuid type = childMeta->m_typeId;
|
||||
if (m_idString == type)
|
||||
{
|
||||
AZStd::string uiValue;
|
||||
childNode.Read(uiValue);
|
||||
|
||||
if (!uiValue.empty() && !noDocElement)
|
||||
{
|
||||
if (AZStd::string(plistNode->name()) == stringStr)
|
||||
{
|
||||
if (uiValue != plistNode->value())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (uiValue.empty() != noDocElement)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (m_idBool == type)
|
||||
{
|
||||
bool uiValue;
|
||||
childNode.Read(uiValue);
|
||||
|
||||
if (uiValue)
|
||||
{
|
||||
if (!noDocElement)
|
||||
{
|
||||
if (AZStd::string(plistNode->name()) != trueStr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (!noDocElement)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (AZStd::string(childNode.GetClassMetadata()->m_name) == "IosOrientations")
|
||||
{
|
||||
// Enter even if nullptr to make sure all values should be false
|
||||
if (plistNode == nullptr || AZStd::string(plistNode->name()) == arrayStr)
|
||||
{
|
||||
if (!UiEqualToPlistArray(plistNode, &childNode))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!UiEqualToPlistImages(&childNode))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Serializer::UiEqualToPlistArray(AZ::rapidxml::xml_node<char>* array, AzToolsFramework::InstanceDataNode* node) const
|
||||
{
|
||||
const AZ::SerializeContext::ClassData* baseMeta = node->GetClassMetadata();
|
||||
if (baseMeta)
|
||||
{
|
||||
for (AzToolsFramework::InstanceDataNode& childNode : node->GetChildren())
|
||||
{
|
||||
const AZ::SerializeContext::ClassElement* childMeta = childNode.GetElementMetadata();
|
||||
if (childMeta)
|
||||
{
|
||||
AZ::Uuid type = childMeta->m_typeId;
|
||||
if (m_idBool == type)
|
||||
{
|
||||
const char* propertyName = childMeta->m_name;
|
||||
bool uiValue;
|
||||
childNode.Read(uiValue);
|
||||
|
||||
bool found = false;
|
||||
if (array != nullptr)
|
||||
{
|
||||
for (XmlNode* plistNode = array->first_node(); plistNode != nullptr; plistNode = plistNode->next_sibling())
|
||||
{
|
||||
if (AZStd::string(plistNode->value()) == propertyName)
|
||||
{
|
||||
if (!uiValue)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
found = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (uiValue && !found)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Serializer::UiEqualToPlistImages(AzToolsFramework::InstanceDataNode* node) const
|
||||
{
|
||||
const AZ::SerializeContext::ClassData* baseMeta = node->GetClassMetadata();
|
||||
if (baseMeta)
|
||||
{
|
||||
for (AzToolsFramework::InstanceDataNode& childNode : node->GetChildren())
|
||||
{
|
||||
auto childMeta = childNode.GetElementMetadata();
|
||||
if (childMeta)
|
||||
{
|
||||
AZ::Uuid type = childMeta->m_typeId;
|
||||
|
||||
if (m_idString == type)
|
||||
{
|
||||
AZStd::string uiValue;
|
||||
childNode.Read(uiValue);
|
||||
|
||||
if (!uiValue.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Serializer::LoadFromSettings(rapidjson::Value* root, AzToolsFramework::InstanceDataNode* node)
|
||||
{
|
||||
const AZ::SerializeContext::ClassData* baseMeta = node->GetClassMetadata();
|
||||
if (baseMeta)
|
||||
{
|
||||
for (AzToolsFramework::InstanceDataNode& childNode : node->GetChildren())
|
||||
{
|
||||
auto childMeta = childNode.GetElementMetadata();
|
||||
if (childMeta)
|
||||
{
|
||||
const char* propertyName = childMeta->m_name;
|
||||
AZ::Uuid type = childMeta->m_typeId;
|
||||
|
||||
if (root != nullptr)
|
||||
{
|
||||
rapidjson::Value::MemberIterator jsonMember = root->FindMember(propertyName);
|
||||
|
||||
if (jsonMember != root->MemberEnd())
|
||||
{
|
||||
rapidjson::Value& jsonNode = jsonMember->value;
|
||||
|
||||
if (m_idString == type)
|
||||
{
|
||||
if (jsonNode.IsString())
|
||||
{
|
||||
AZStd::string jsonValue = jsonNode.GetString();
|
||||
childNode.Write(jsonValue);
|
||||
}
|
||||
}
|
||||
else if (m_idInt == type)
|
||||
{
|
||||
if (jsonNode.IsInt())
|
||||
{
|
||||
int jsonValue = jsonNode.GetInt();
|
||||
childNode.Write(jsonValue);
|
||||
}
|
||||
}
|
||||
else if (m_idBool == type)
|
||||
{
|
||||
if (jsonNode.IsString())
|
||||
{
|
||||
bool value = false;
|
||||
AZStd::string jsonValue = jsonNode.GetString();
|
||||
|
||||
if (jsonValue == trueStr)
|
||||
{
|
||||
value = true;
|
||||
}
|
||||
childNode.Write(value);
|
||||
}
|
||||
}
|
||||
// Should be a class with members instead of base data type
|
||||
else
|
||||
{
|
||||
if (jsonNode.IsObject())
|
||||
{
|
||||
// Drill into class
|
||||
LoadFromSettings(&jsonNode, &childNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SetDefaults(childNode, type);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SetDefaults(childNode, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Serializer::SaveToSettings(rapidjson::Value* root, AzToolsFramework::InstanceDataNode* node)
|
||||
{
|
||||
const AZ::SerializeContext::ClassData* baseMeta = node->GetClassMetadata();
|
||||
if (baseMeta)
|
||||
{
|
||||
for (AzToolsFramework::InstanceDataNode& childNode : node->GetChildren())
|
||||
{
|
||||
auto childMeta = childNode.GetElementMetadata();
|
||||
if (childMeta)
|
||||
{
|
||||
const char* propertyName = childMeta->m_name;
|
||||
rapidjson::Value::MemberIterator jsonMember = root->FindMember(propertyName);
|
||||
|
||||
if (jsonMember == root->MemberEnd())
|
||||
{
|
||||
root->AddMember(rapidjson::Value(propertyName, m_jsonDoc->GetAllocator())
|
||||
, rapidjson::Value(rapidjson::Type::kNullType)
|
||||
, m_jsonDoc->GetAllocator());
|
||||
jsonMember = root->FindMember(propertyName);
|
||||
}
|
||||
rapidjson::Value& jsonNode = jsonMember->value;
|
||||
|
||||
AZ::Uuid type = childMeta->m_typeId;
|
||||
if (m_idString == type)
|
||||
{
|
||||
AZStd::string uiValue;
|
||||
childNode.Read(uiValue);
|
||||
|
||||
if (!uiValue.empty())
|
||||
{
|
||||
jsonNode.SetString(uiValue.data(), m_jsonDoc->GetAllocator());
|
||||
}
|
||||
else
|
||||
{
|
||||
root->RemoveMember(propertyName);
|
||||
}
|
||||
}
|
||||
else if (m_idInt == type)
|
||||
{
|
||||
int uiValue;
|
||||
childNode.Read(uiValue);
|
||||
jsonNode.SetInt(uiValue);
|
||||
}
|
||||
else if (m_idBool == type)
|
||||
{
|
||||
bool uiValue;
|
||||
childNode.Read(uiValue);
|
||||
|
||||
if (uiValue)
|
||||
{
|
||||
jsonNode.SetString(trueStr, m_jsonDoc->GetAllocator());
|
||||
}
|
||||
else
|
||||
{
|
||||
root->RemoveMember(propertyName);
|
||||
}
|
||||
}
|
||||
// Should be a class with members instead of base data type
|
||||
else
|
||||
{
|
||||
// This value needs to be an object to add members
|
||||
if (!jsonNode.IsObject())
|
||||
{
|
||||
jsonNode.SetObject();
|
||||
}
|
||||
// Drill into class
|
||||
SaveToSettings(&jsonNode, &childNode);
|
||||
|
||||
if (jsonNode.ObjectEmpty())
|
||||
{
|
||||
root->RemoveMember(propertyName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Serializer::LoadFromSettings(AzToolsFramework::InstanceDataNode* node)
|
||||
{
|
||||
const AZ::SerializeContext::ClassData* baseMeta = node->GetClassMetadata();
|
||||
if (baseMeta)
|
||||
{
|
||||
for (AzToolsFramework::InstanceDataNode& childNode : node->GetChildren())
|
||||
{
|
||||
const AZ::SerializeContext::ClassElement* childMeta = childNode.GetElementMetadata();
|
||||
if (childMeta)
|
||||
{
|
||||
const char* propertyName = childMeta->m_name;
|
||||
XmlNode* plistNode = m_plistDict->GetPropertyValueNode(propertyName);
|
||||
AZ::Uuid type = childMeta->m_typeId;
|
||||
|
||||
if (plistNode != nullptr)
|
||||
{
|
||||
if (m_idString == type)
|
||||
{
|
||||
if (AZStd::string(plistNode->name()) == stringStr)
|
||||
{
|
||||
AZStd::string plistValue = plistNode->value();
|
||||
childNode.Write(plistValue);
|
||||
}
|
||||
}
|
||||
else if (m_idBool == type)
|
||||
{
|
||||
if (AZStd::string(plistNode->name()) == trueStr)
|
||||
{
|
||||
childNode.Write(true);
|
||||
}
|
||||
}
|
||||
else if (AZStd::string(childNode.GetClassMetadata()->m_name) == "IosOrientations")
|
||||
{
|
||||
// Make sure it seems like an array in plist as well
|
||||
if (AZStd::string(plistNode->name()) == arrayStr)
|
||||
{
|
||||
LoadOrientations(plistNode, &childNode);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SetClassToDefaults(&childNode);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SetDefaults(childNode, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Serializer::LoadOrientations(XmlNode* array, AzToolsFramework::InstanceDataNode* node)
|
||||
{
|
||||
const AZ::SerializeContext::ClassData* baseMeta = node->GetClassMetadata();
|
||||
if (baseMeta)
|
||||
{
|
||||
for (AzToolsFramework::InstanceDataNode& childNode : node->GetChildren())
|
||||
{
|
||||
const AZ::SerializeContext::ClassElement* childMeta = childNode.GetElementMetadata();
|
||||
if (childMeta)
|
||||
{
|
||||
const char* propertyName = childMeta->m_name;
|
||||
|
||||
bool found = false;
|
||||
if (array != nullptr)
|
||||
{
|
||||
for (XmlNode* plistNode = array->first_node(); plistNode != nullptr; plistNode = plistNode->next_sibling())
|
||||
{
|
||||
if (AZStd::string(plistNode->value()) == propertyName)
|
||||
{
|
||||
AZ::Uuid type = childMeta->m_typeId;
|
||||
|
||||
if (m_idBool == type)
|
||||
{
|
||||
if (AZStd::string(plistNode->name()) == stringStr)
|
||||
{
|
||||
childNode.Write(true);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Assert(false, "Unsupported type \"%s\" found in array.", childMeta->m_editData->m_name)
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
childNode.Write(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Serializer::SetClassToDefaults(AzToolsFramework::InstanceDataNode* node)
|
||||
{
|
||||
const AZ::SerializeContext::ClassData* baseMeta = node->GetClassMetadata();
|
||||
if (baseMeta)
|
||||
{
|
||||
for (AzToolsFramework::InstanceDataNode& childNode : node->GetChildren())
|
||||
{
|
||||
auto childMeta = childNode.GetElementMetadata();
|
||||
if (childMeta)
|
||||
{
|
||||
AZ::Uuid type = childMeta->m_typeId;
|
||||
|
||||
SetDefaults(childNode, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Serializer::SetDefaults(AzToolsFramework::InstanceDataNode& node, const AZ::Uuid& type)
|
||||
{
|
||||
if (m_idString == type)
|
||||
{
|
||||
node.Write(AZStd::string(""));
|
||||
return;
|
||||
}
|
||||
else if (m_idBool == type)
|
||||
{
|
||||
node.Write(false);
|
||||
return;
|
||||
}
|
||||
else if (m_idInt == type)
|
||||
{
|
||||
node.Write(0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (AZStd::string(node.GetClassMetadata()->m_name) == "IosOrientations")
|
||||
{
|
||||
LoadOrientations(nullptr, &node);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetClassToDefaults(&node);
|
||||
}
|
||||
}
|
||||
|
||||
void Serializer::SaveToSettings(AzToolsFramework::InstanceDataNode* node)
|
||||
{
|
||||
const AZ::SerializeContext::ClassData* baseMeta = node->GetClassMetadata();
|
||||
if (baseMeta)
|
||||
{
|
||||
for (AzToolsFramework::InstanceDataNode& childNode : node->GetChildren())
|
||||
{
|
||||
auto childMeta = childNode.GetElementMetadata();
|
||||
if (childMeta)
|
||||
{
|
||||
const char* propertyName = childMeta->m_name;
|
||||
|
||||
AZ::Uuid type = childMeta->m_typeId;
|
||||
|
||||
if (m_idString == type)
|
||||
{
|
||||
AZStd::string uiValue;
|
||||
childNode.Read(uiValue);
|
||||
|
||||
if (!uiValue.empty())
|
||||
{
|
||||
m_plistDict->SetPropertyValue(propertyName, uiValue.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_plistDict->RemoveProperty(propertyName);
|
||||
}
|
||||
}
|
||||
else if (m_idBool == type)
|
||||
{
|
||||
bool uiValue;
|
||||
childNode.Read(uiValue);
|
||||
|
||||
if (uiValue)
|
||||
{
|
||||
m_plistDict->SetPropertyValueName(propertyName, trueStr);
|
||||
m_plistDict->SetPropertyValue(propertyName, "");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_plistDict->RemoveProperty(propertyName);
|
||||
}
|
||||
}
|
||||
else if (AZStd::string(childNode.GetClassMetadata()->m_name) == "IosOrientations")
|
||||
{
|
||||
XmlNode* plistNode = m_plistDict->GetPropertyValueNode(propertyName);
|
||||
if (plistNode == nullptr)
|
||||
{
|
||||
plistNode = m_plistDict->SetPropertyValueName(propertyName, arrayStr);
|
||||
}
|
||||
// Make sure the plist says this is an array type
|
||||
if (AZStd::string(plistNode->name()) == arrayStr)
|
||||
{
|
||||
if (!SaveOrientations(plistNode, &childNode))
|
||||
{
|
||||
m_plistDict->RemoveProperty(propertyName);
|
||||
}
|
||||
}
|
||||
}
|
||||
//Assume this is a class with image overrides
|
||||
else
|
||||
{
|
||||
OverwriteImages(&childNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Serializer::SaveOrientations(XmlNode* array, AzToolsFramework::InstanceDataNode* node)
|
||||
{
|
||||
bool anyEnabled = false;
|
||||
|
||||
const AZ::SerializeContext::ClassData* baseMeta = node->GetClassMetadata();
|
||||
if (baseMeta)
|
||||
{
|
||||
for (AzToolsFramework::InstanceDataNode& childNode : node->GetChildren())
|
||||
{
|
||||
const AZ::SerializeContext::ClassElement* childMeta = childNode.GetElementMetadata();
|
||||
if (childMeta)
|
||||
{
|
||||
AZ::Uuid type = childMeta->m_typeId;
|
||||
if (m_idBool == type)
|
||||
{
|
||||
const char* propertyName = childMeta->m_name;
|
||||
bool uiValue;
|
||||
childNode.Read(uiValue);
|
||||
|
||||
if (uiValue)
|
||||
{
|
||||
anyEnabled = true;
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
for (XmlNode* plistNode = array->first_node(); plistNode != nullptr; plistNode = plistNode->next_sibling())
|
||||
{
|
||||
if (AZStd::string(plistNode->value()) == propertyName)
|
||||
{
|
||||
if (!uiValue)
|
||||
{
|
||||
array->remove_node(plistNode);
|
||||
}
|
||||
else
|
||||
{
|
||||
found = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (uiValue && !found)
|
||||
{
|
||||
array->append_node(m_plistDict->MakeNode(stringStr, propertyName));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return anyEnabled;
|
||||
}
|
||||
|
||||
void Serializer::OverwriteImages(AzToolsFramework::InstanceDataNode* node)
|
||||
{
|
||||
const AZ::SerializeContext::ClassData* baseMeta = node->GetClassMetadata();
|
||||
if (baseMeta)
|
||||
{
|
||||
for (AzToolsFramework::InstanceDataNode& childNode : node->GetChildren())
|
||||
{
|
||||
auto childMeta = childNode.GetElementMetadata();
|
||||
if (childMeta)
|
||||
{
|
||||
AZ::Uuid type = childMeta->m_typeId;
|
||||
|
||||
if (m_idString == type)
|
||||
{
|
||||
AZStd::string uiValue;
|
||||
childNode.Read(uiValue);
|
||||
|
||||
if (!uiValue.empty())
|
||||
{
|
||||
AZ::Edit::ElementData* childEditMeta = childMeta->m_editData;
|
||||
|
||||
if (childEditMeta != nullptr)
|
||||
{
|
||||
AZ::AttributeId handlerType = childEditMeta->m_elementId;
|
||||
|
||||
// Special handling for iOS image overrides, the source images must be overwritten.
|
||||
if (handlerType == Handlers::ImagePreview)
|
||||
{
|
||||
AZ::Edit::Attribute* defaultPathAttr = childEditMeta->FindAttribute(Attributes::DefaultPath);
|
||||
if (defaultPathAttr != nullptr)
|
||||
{
|
||||
AzToolsFramework::PropertyAttributeReader reader(defaultPathAttr->GetContextData(), defaultPathAttr);
|
||||
AZStd::string defaultPath;
|
||||
if (reader.Read<AZStd::string>(defaultPath))
|
||||
{
|
||||
QString defaultPathQString = defaultPath.data();
|
||||
CFileUtil::OverwriteFile(defaultPathQString);
|
||||
CFileUtil::CopyFile(QString(uiValue.data()), defaultPathQString);
|
||||
// Clear the property so this isn't overwritten again for no reason
|
||||
childNode.Write(AZStd::string(""));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Assert(false, "Could not find default path for \"%s\". Cannot override image.", childMeta->m_name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Assert(false, "Unsupported type \"%s\" found in what should be image overrides.", childMeta->m_editData->m_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} // ProjectSettingsTool
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "PlistDictionary.h"
|
||||
|
||||
#include <AzCore/JSON/document.h>
|
||||
#include <AzCore/std/smart_ptr/unique_ptr.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
class InstanceDataNode;
|
||||
}
|
||||
|
||||
namespace ProjectSettingsTool
|
||||
{
|
||||
class Serializer
|
||||
{
|
||||
public:
|
||||
Serializer(AzToolsFramework::InstanceDataNode* root, rapidjson::Document* doc, rapidjson::Value* jsonRoot = nullptr);
|
||||
Serializer(AzToolsFramework::InstanceDataNode* root, AZStd::unique_ptr<PlistDictionary> dict);
|
||||
// Sets Json document
|
||||
void SetDocumentRoot(rapidjson::Document* doc);
|
||||
// Sets Json root
|
||||
void SetJsonRoot(rapidjson::Value* jsonRoot);
|
||||
// Sets pList dictionary
|
||||
void SetDocumentRoot(AZStd::unique_ptr<PlistDictionary> dict);
|
||||
// Returns true if all properties in ui are equal to settings
|
||||
bool UiEqualToSettings() const;
|
||||
// Loads properties into the ui from the settings
|
||||
void LoadFromSettings();
|
||||
// Saves properties from the ui to the settings
|
||||
void SaveToSettings();
|
||||
bool UiEqualToJson(rapidjson::Value* root) const;
|
||||
void LoadFromSettings(rapidjson::Value* root);
|
||||
void SaveToSettings(rapidjson::Value* root);
|
||||
|
||||
|
||||
protected:
|
||||
bool UiEqualToJson(rapidjson::Value* root, AzToolsFramework::InstanceDataNode* node) const;
|
||||
bool UiEqualToPlist(AzToolsFramework::InstanceDataNode* node) const;
|
||||
bool UiEqualToPlistArray(AZ::rapidxml::xml_node<char>* array, AzToolsFramework::InstanceDataNode* node) const;
|
||||
bool UiEqualToPlistImages(AzToolsFramework::InstanceDataNode* node) const;
|
||||
void LoadFromSettings(rapidjson::Value* root, AzToolsFramework::InstanceDataNode* node);
|
||||
void LoadFromSettings(AzToolsFramework::InstanceDataNode* node);
|
||||
void LoadOrientations(AZ::rapidxml::xml_node<char>* array, AzToolsFramework::InstanceDataNode* node);
|
||||
void SetDefaults(AzToolsFramework::InstanceDataNode& node, const AZ::Uuid& type);
|
||||
void SetClassToDefaults(AzToolsFramework::InstanceDataNode* node);
|
||||
void SaveToSettings(rapidjson::Value* root, AzToolsFramework::InstanceDataNode* node);
|
||||
void SaveToSettings(AzToolsFramework::InstanceDataNode* node);
|
||||
bool SaveOrientations(AZ::rapidxml::xml_node<char>* array, AzToolsFramework::InstanceDataNode* node);
|
||||
void OverwriteImages(AzToolsFramework::InstanceDataNode* node);
|
||||
|
||||
// The RPE root relative to the document's root
|
||||
AzToolsFramework::InstanceDataNode* m_root;
|
||||
// The Json document if using Json for this RPE
|
||||
rapidjson::Document* m_jsonDoc;
|
||||
// The root of the json for this serializer
|
||||
rapidjson::Value* m_jsonRoot;
|
||||
// The pList Dictionary wrapper if using a pList for this RPE
|
||||
AZStd::unique_ptr<PlistDictionary> m_plistDict;
|
||||
|
||||
private:
|
||||
Serializer(AzToolsFramework::InstanceDataNode* root);
|
||||
|
||||
// Uuid for AZStd::string
|
||||
const AZ::Uuid m_idString;
|
||||
// Uuid for int
|
||||
const AZ::Uuid m_idInt;
|
||||
// Uuid for bool
|
||||
const AZ::Uuid m_idBool;
|
||||
};
|
||||
} // ProjectSettingsTool
|
||||
@@ -0,0 +1,8 @@
|
||||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file alias="group_closed.png">icons/group_closed.png</file>
|
||||
<file alias="group_open.png">icons/group_open.png</file>
|
||||
<file alias="link.svg">icons/link.svg</file>
|
||||
<file alias="broken_link.svg">icons/broken_link.svg</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
@@ -0,0 +1,193 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ProjectSettingsToolWidget</class>
|
||||
<widget class="QWidget" name="ProjectSettingsToolWidget">
|
||||
<property name="modal" stdset="0">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>640</width>
|
||||
<height>853</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>640</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Project Settings Tool</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="mainContentLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout_5">
|
||||
<item row="1" column="0">
|
||||
<widget class="QScrollArea" name="scrollArea">
|
||||
<property name="widgetResizable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<widget class="QWidget" name="scrollAreaWidgetContents">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>616</width>
|
||||
<height>612</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_6">
|
||||
<item row="0" column="0">
|
||||
<layout class="QGridLayout" name="gridLayout_7">
|
||||
<item row="1" column="0">
|
||||
<widget class="QGroupBox" name="verticalGroupBox_3">
|
||||
<property name="title">
|
||||
<string>Platform Settings</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<item>
|
||||
<widget class="AzQtComponents::TabWidget" name="platformTabs">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="usesScrollButtons">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="documentMode">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="tabBarAutoHide">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<widget class="QWidget" name="androidTab">
|
||||
<attribute name="title">
|
||||
<string>Android</string>
|
||||
</attribute>
|
||||
<layout class="QGridLayout" name="gridLayout_8"/>
|
||||
</widget>
|
||||
<widget class="QWidget" name="iosTab">
|
||||
<attribute name="title">
|
||||
<string> iOS </string>
|
||||
</attribute>
|
||||
<layout class="QGridLayout" name="gridLayout_9"/>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QGroupBox" name="baseSettingsGroupBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Base Settings</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout"/>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="saveButton">
|
||||
<property name="text">
|
||||
<string>Save</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="reloadButton">
|
||||
<property name="text">
|
||||
<string>Reload</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTextBrowser" name="reconfigureLog">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>AzQtComponents::TabWidget</class>
|
||||
<extends>QTabWidget</extends>
|
||||
<header location="global">AzQtComponents/Components/Widgets/TabWidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="ProjectSettingsTool.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -0,0 +1,700 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ProjectSettingsTool_precompiled.h"
|
||||
#include "ProjectSettingsToolWindow.h"
|
||||
#include "ui_ProjectSettingsToolWidget.h"
|
||||
|
||||
#include "DefaultImageValidator.h"
|
||||
#include "PlatformSettings.h"
|
||||
#include "ProjectSettingsContainer.h"
|
||||
#include "ProjectSettingsValidator.h"
|
||||
#include "PropertyImagePreview.h"
|
||||
#include "PropertyFileSelect.h"
|
||||
#include "PropertyLinked.h"
|
||||
#include "Utils.h"
|
||||
#include "ValidationHandler.h"
|
||||
|
||||
#include <AzCore/Component/ComponentApplicationBus.h>
|
||||
|
||||
#include "AzToolsFramework/UI/PropertyEditor/InstanceDataHierarchy.h"
|
||||
#include <AzToolsFramework/UI/PropertyEditor/PropertyManagerComponent.h>
|
||||
#include <AzToolsFramework/UI/PropertyEditor/ReflectedPropertyEditor.hxx>
|
||||
#include <AzToolsFramework/UI/UICore/WidgetHelpers.h>
|
||||
#include <Util/FileUtil.h>
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <QCloseEvent>
|
||||
#include <QScrollBar>
|
||||
#include <QTimer>
|
||||
|
||||
// The object name in json for android
|
||||
const static char* androidSettings = "android_settings";
|
||||
static bool g_serializeRegistered = false;
|
||||
|
||||
namespace ProjectSettingsTool
|
||||
{
|
||||
using XmlNode = AZ::rapidxml::xml_node<char>;
|
||||
|
||||
ProjectSettingsToolWindow::ProjectSettingsToolWindow(QWidget* parent)
|
||||
: QWidget(parent)
|
||||
, LastPathBus::Handler()
|
||||
, m_ui(new Ui::ProjectSettingsToolWidget())
|
||||
, m_reconfigureProcess()
|
||||
, m_devRoot(GetDevRoot())
|
||||
, m_projectRoot(GetProjectRoot())
|
||||
, m_projectName(GetProjectName())
|
||||
, m_plistsInitVector(
|
||||
PlatformEnabled(PlatformId::Ios) ?
|
||||
ProjectSettingsContainer::PlistInitVector({
|
||||
ProjectSettingsContainer::PlatformAndPath
|
||||
{ PlatformId::Ios, m_projectRoot + PlatformResourcesFolder(PlatformId::Ios) }
|
||||
})
|
||||
:
|
||||
ProjectSettingsContainer::PlistInitVector())
|
||||
, m_settingsContainer(AZStd::make_unique<ProjectSettingsContainer>(m_projectRoot + "/project.json", m_plistsInitVector))
|
||||
, m_validator(AZStd::make_unique<Validator>())
|
||||
, m_platformProperties()
|
||||
, m_platformPropertyEditors()
|
||||
, m_propertyHandlers()
|
||||
, m_validationHandler(AZStd::make_unique<ValidationHandler>())
|
||||
, m_linkHandler(nullptr)
|
||||
// The default path to select images at
|
||||
, m_lastImagesPath(QStringLiteral("%1Code%2/Resources")
|
||||
.arg(m_projectRoot.c_str()
|
||||
, m_projectName.c_str()))
|
||||
, m_invalidState(false)
|
||||
{
|
||||
// Shows any and all errors that occurred during serialization with option to quit out on each one.
|
||||
ShowAllErrorsThenExitIfInvalid();
|
||||
|
||||
if (!g_serializeRegistered)
|
||||
{
|
||||
ReflectPlatformClasses();
|
||||
g_serializeRegistered = true;
|
||||
}
|
||||
|
||||
InitializeUi();
|
||||
RegisterHandlersAndBusses();
|
||||
AddAllPlatformsToUi();
|
||||
MakeSerializers();
|
||||
if (m_invalidState)
|
||||
{
|
||||
// Exit for safety
|
||||
return;
|
||||
}
|
||||
|
||||
LoadPropertiesFromSettings();
|
||||
m_linkHandler->LinkAllProperties();
|
||||
|
||||
// Hide the iOS tab if that platform is not enabled.
|
||||
if (!PlatformEnabled(PlatformId::Ios))
|
||||
{
|
||||
m_ui->platformTabs->removeTab(m_ui->platformTabs->indexOf(m_ui->iosTab));
|
||||
}
|
||||
}
|
||||
|
||||
ProjectSettingsToolWindow::~ProjectSettingsToolWindow()
|
||||
{
|
||||
UnregisterHandlersAndBusses();
|
||||
}
|
||||
|
||||
QString ProjectSettingsToolWindow::GetLastImagePath()
|
||||
{
|
||||
return m_lastImagesPath;
|
||||
}
|
||||
|
||||
void ProjectSettingsToolWindow::SetLastImagePath(const QString& path)
|
||||
{
|
||||
m_lastImagesPath = path;
|
||||
}
|
||||
|
||||
FunctorValidator* ProjectSettingsToolWindow::GetValidator(FunctorValidator::FunctorType functor)
|
||||
{
|
||||
return m_validator->GetQValidator(functor);
|
||||
}
|
||||
|
||||
void ProjectSettingsToolWindow::TrackValidator(FunctorValidator* validator)
|
||||
{
|
||||
m_validator->TrackThisValidator(validator);
|
||||
}
|
||||
|
||||
void ProjectSettingsToolWindow::ReflectPlatformClasses()
|
||||
{
|
||||
AZ::SerializeContext* context = nullptr;
|
||||
AZ::ComponentApplicationBus::BroadcastResult(context, &AZ::ComponentApplicationRequests::GetSerializeContext);
|
||||
|
||||
BaseSettings::Reflect(context);
|
||||
AndroidSettings::Reflect(context);
|
||||
IosSettings::Reflect(context);
|
||||
}
|
||||
|
||||
void ProjectSettingsToolWindow::RegisterHandlersAndBusses()
|
||||
{
|
||||
m_propertyHandlers.push_back(PropertyFuncValLineEditHandler::Register(m_validationHandler.get()));
|
||||
m_propertyHandlers.push_back(PropertyFuncValBrowseEditHandler::Register(m_validationHandler.get()));
|
||||
m_propertyHandlers.push_back(PropertyFileSelectHandler::Register(m_validationHandler.get()));
|
||||
m_propertyHandlers.push_back(PropertyImagePreviewHandler::Register(m_validationHandler.get()));
|
||||
m_linkHandler = PropertyLinkedHandler::Register(m_validationHandler.get());
|
||||
m_propertyHandlers.push_back(m_linkHandler);
|
||||
LastPathBus::Handler::BusConnect();
|
||||
ValidatorBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
void ProjectSettingsToolWindow::UnregisterHandlersAndBusses()
|
||||
{
|
||||
ValidatorBus::Handler::BusDisconnect();
|
||||
LastPathBus::Handler::BusDisconnect();
|
||||
|
||||
for (AzToolsFramework::PropertyHandlerBase* handler : m_propertyHandlers)
|
||||
{
|
||||
AzToolsFramework::PropertyTypeRegistrationMessages::Bus::Broadcast(
|
||||
&AzToolsFramework::PropertyTypeRegistrationMessages::Bus::Handler::UnregisterPropertyType,
|
||||
handler);
|
||||
delete handler;
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectSettingsToolWindow::MakeSerializerJson(const Platform& plat, AzToolsFramework::InstanceDataHierarchy& hierarchy, rapidjson::Document* doc)
|
||||
{
|
||||
m_platformSerializers[static_cast<unsigned>(plat.m_id)] = AZStd::make_unique<Serializer>(hierarchy.GetRoot(), doc);
|
||||
}
|
||||
|
||||
void ProjectSettingsToolWindow::MakeSerializerJsonNonRoot(const Platform& plat, AzToolsFramework::InstanceDataHierarchy& hierarchy, rapidjson::Document* doc, rapidjson::Value* jsonRoot)
|
||||
{
|
||||
m_platformSerializers[static_cast<unsigned>(plat.m_id)] = AZStd::make_unique<Serializer>(hierarchy.GetRoot(), doc, jsonRoot);
|
||||
}
|
||||
|
||||
void ProjectSettingsToolWindow::MakeSerializerPlist(const Platform& plat, AzToolsFramework::InstanceDataHierarchy& hierarchy, PlistDictionary* dict)
|
||||
{
|
||||
m_platformSerializers[static_cast<unsigned>(plat.m_id)] = AZStd::make_unique<Serializer>(hierarchy.GetRoot(), AZStd::unique_ptr<PlistDictionary>(dict));
|
||||
}
|
||||
|
||||
void ProjectSettingsToolWindow::closeEvent(QCloseEvent* event)
|
||||
{
|
||||
if (!m_invalidState)
|
||||
{
|
||||
// Check if ui is loaded
|
||||
if (m_ui->saveButton != nullptr)
|
||||
{
|
||||
// Save button is used as an inverse bool to tell if configure is being run or settings are being saved
|
||||
if (m_ui->saveButton->isEnabled())
|
||||
{
|
||||
if (!UiEqualToSettings())
|
||||
{
|
||||
int result = QMessageBox::question
|
||||
(
|
||||
this,
|
||||
tr("Warning"),
|
||||
tr("There are currently unsaved changes. Are you sure you want to cancel?"),
|
||||
QMessageBox::Yes,
|
||||
QMessageBox::No
|
||||
);
|
||||
|
||||
|
||||
if (QMessageBox::Yes == result)
|
||||
{
|
||||
QWidget::closeEvent(event);
|
||||
}
|
||||
else
|
||||
{
|
||||
event->setAccepted(false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QWidget::closeEvent(event);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::information
|
||||
(
|
||||
this,
|
||||
tr("Info"),
|
||||
tr("Cannot close until settings have been reconfigured."),
|
||||
QMessageBox::Ok
|
||||
);
|
||||
|
||||
event->setAccepted(false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QWidget::closeEvent(event);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QWidget::closeEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectSettingsToolWindow::ForceClose()
|
||||
{
|
||||
m_invalidState = true;
|
||||
// Potentially called from the constructor, when the widget/window aren't properly set up, so delay this until after it's all setup
|
||||
QTimer::singleShot(0, this, [this]() {window()->close();} );
|
||||
}
|
||||
|
||||
bool ProjectSettingsToolWindow::IfErrorShowThenExit()
|
||||
{
|
||||
// Grabs the earliest unseen error popping it off the error queue
|
||||
AZ::Outcome<void, SettingsError> error = m_settingsContainer->GetError();
|
||||
if (!error.IsSuccess())
|
||||
{
|
||||
bool shouldAbort = error.GetError().m_error == m_settingsContainer->GetFailedLoadingPlistText();
|
||||
QMessageBox::StandardButton result = QMessageBox::critical
|
||||
(
|
||||
this,
|
||||
error.GetError().m_error.c_str(),
|
||||
error.GetError().m_reason.c_str(),
|
||||
shouldAbort ? QMessageBox::Abort : QMessageBox::StandardButtons(QMessageBox::Ok | QMessageBox::Abort),
|
||||
shouldAbort ? QMessageBox::Abort : QMessageBox::Ok
|
||||
);
|
||||
if (result == QMessageBox::Abort)
|
||||
{
|
||||
ForceClose();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ProjectSettingsToolWindow::ShowAllErrorsThenExitIfInvalid()
|
||||
{
|
||||
while (IfErrorShowThenExit())
|
||||
{
|
||||
if (m_invalidState)
|
||||
{
|
||||
// Exit for safety
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectSettingsToolWindow::InitializeUi()
|
||||
{
|
||||
// setup
|
||||
m_ui->setupUi(this);
|
||||
|
||||
AzQtComponents::TabWidget::applySecondaryStyle(m_ui->platformTabs, false);
|
||||
|
||||
ResizeTabs(m_ui->platformTabs->currentIndex());
|
||||
|
||||
m_ui->reconfigureLog->hide();
|
||||
|
||||
// connects
|
||||
connect
|
||||
(
|
||||
&m_reconfigureProcess,
|
||||
static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
|
||||
this,
|
||||
[this]()
|
||||
{
|
||||
m_ui->saveButton->setEnabled(true);
|
||||
m_ui->reloadButton->setEnabled(true);
|
||||
m_ui->reconfigureLog->insertPlainText(tr("\n Reconfiguration Finished"));
|
||||
QScrollBar* scrollbar = m_ui->reconfigureLog->verticalScrollBar();
|
||||
scrollbar->setValue(scrollbar->maximum());
|
||||
}
|
||||
);
|
||||
|
||||
connect(&m_reconfigureProcess, &QProcess::readyReadStandardOutput, this,
|
||||
[this]()
|
||||
{
|
||||
m_ui->reconfigureLog->insertPlainText(m_reconfigureProcess.readAllStandardOutput());
|
||||
if (!m_ui->reconfigureLog->textCursor().hasSelection())
|
||||
{
|
||||
QScrollBar* scrollbar = m_ui->reconfigureLog->verticalScrollBar();
|
||||
scrollbar->setValue(scrollbar->maximum());
|
||||
}
|
||||
});
|
||||
connect(&m_reconfigureProcess, &QProcess::readyReadStandardError, this,
|
||||
[this]()
|
||||
{
|
||||
m_ui->reconfigureLog->insertPlainText(m_reconfigureProcess.readAllStandardError());
|
||||
if (!m_ui->reconfigureLog->textCursor().hasSelection())
|
||||
{
|
||||
QScrollBar* scrollbar = m_ui->reconfigureLog->verticalScrollBar();
|
||||
scrollbar->setValue(scrollbar->maximum());
|
||||
}
|
||||
});
|
||||
|
||||
connect(m_ui->platformTabs, &QTabWidget::currentChanged,
|
||||
this, &ProjectSettingsToolWindow::ResizeTabs);
|
||||
|
||||
connect(m_ui->saveButton, &QPushButton::clicked, this,
|
||||
&ProjectSettingsToolWindow::SaveSettingsFromUi);
|
||||
connect(m_ui->reloadButton, &QPushButton::clicked, this,
|
||||
&ProjectSettingsToolWindow::ReloadUiFromSettings);
|
||||
}
|
||||
|
||||
void ProjectSettingsToolWindow::ResizeTabs(int index)
|
||||
{
|
||||
for (int i = 0; i < m_ui->platformTabs->count(); i++)
|
||||
{
|
||||
if (i != index)
|
||||
{
|
||||
m_ui->platformTabs->widget(i)->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
|
||||
}
|
||||
}
|
||||
|
||||
// resize for current tab
|
||||
m_ui->platformTabs->widget(index)->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
|
||||
m_ui->platformTabs->widget(index)->resize(m_ui->platformTabs->widget(index)->minimumSizeHint());
|
||||
m_ui->platformTabs->widget(index)->adjustSize();
|
||||
}
|
||||
|
||||
void ProjectSettingsToolWindow::AddAllPlatformsToUi()
|
||||
{
|
||||
for (int plat = 0; plat < static_cast<unsigned long long>(PlatformId::NumPlatformIds); ++plat)
|
||||
{
|
||||
AddPlatformToUi(Platforms[plat]);
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectSettingsToolWindow::AddPlatformToUi(const Platform& plat)
|
||||
{
|
||||
AZ::SerializeContext* context = nullptr;
|
||||
AZ::ComponentApplicationBus::BroadcastResult(context, &AZ::ComponentApplicationRequests::GetSerializeContext);
|
||||
|
||||
QWidget* parent = nullptr;
|
||||
void* dataForPropertyEditor = nullptr;
|
||||
AZ::TypeId dataTypeID;
|
||||
switch (plat.m_id)
|
||||
{
|
||||
case PlatformId::Base:
|
||||
parent = m_ui->baseSettingsGroupBox;
|
||||
dataForPropertyEditor = &m_platformProperties.base;
|
||||
dataTypeID = m_platformProperties.base.TYPEINFO_Uuid();
|
||||
break;
|
||||
case PlatformId::Android:
|
||||
parent = m_ui->androidTab;
|
||||
dataForPropertyEditor = &m_platformProperties.android;
|
||||
dataTypeID = m_platformProperties.android.TYPEINFO_Uuid();
|
||||
break;
|
||||
case PlatformId::Ios:
|
||||
parent = m_ui->iosTab;
|
||||
dataForPropertyEditor = &m_platformProperties.ios;
|
||||
dataTypeID = m_platformProperties.ios.TYPEINFO_Uuid();
|
||||
break;
|
||||
default:
|
||||
AZ_Assert(false, "Cannot add unknown platform to ui.");
|
||||
}
|
||||
|
||||
unsigned platIdValue = static_cast<unsigned>(plat.m_id);
|
||||
|
||||
m_platformPropertyEditors[platIdValue] = aznew AzToolsFramework::ReflectedPropertyEditor(parent);
|
||||
parent->layout()->addWidget(m_platformPropertyEditors[platIdValue]);
|
||||
|
||||
m_platformPropertyEditors[platIdValue]->Setup(context, nullptr, false);
|
||||
m_platformPropertyEditors[platIdValue]->AddInstance(dataForPropertyEditor, dataTypeID);
|
||||
m_platformPropertyEditors[platIdValue]->setVisible(true);
|
||||
m_platformPropertyEditors[platIdValue]->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
|
||||
m_platformPropertyEditors[platIdValue]->SetHideRootProperties(false);
|
||||
m_platformPropertyEditors[platIdValue]->SetDynamicEditDataProvider(nullptr);
|
||||
m_platformPropertyEditors[platIdValue]->ExpandAll();
|
||||
m_platformPropertyEditors[platIdValue]->InvalidateAll();
|
||||
}
|
||||
|
||||
const char* GetPlatformKey(const Platform& plat)
|
||||
{
|
||||
switch (plat.m_id)
|
||||
{
|
||||
case PlatformId::Android:
|
||||
return androidSettings;
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectSettingsToolWindow::MakeSerializers()
|
||||
{
|
||||
for (int plat = 0; plat < static_cast<unsigned long long>(PlatformId::NumPlatformIds); ++plat)
|
||||
{
|
||||
if (PlatformEnabled(static_cast<PlatformId>(plat)))
|
||||
{
|
||||
MakePlatformSerializer(Platforms[plat]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectSettingsToolWindow::MakePlatformSerializer(const Platform& plat)
|
||||
{
|
||||
unsigned platIdValue = static_cast<unsigned>(plat.m_id);
|
||||
|
||||
switch (plat.m_id)
|
||||
{
|
||||
case PlatformId::Base:
|
||||
m_platformPropertyEditors[platIdValue]->EnumerateInstances(AZStd::bind
|
||||
(
|
||||
&ProjectSettingsToolWindow::MakeSerializerJson,
|
||||
this,
|
||||
plat,
|
||||
AZStd::placeholders::_1,
|
||||
&m_settingsContainer->GetProjectJsonDocument()
|
||||
));
|
||||
break;
|
||||
case PlatformId::Android:
|
||||
m_platformPropertyEditors[platIdValue]->EnumerateInstances(AZStd::bind
|
||||
(
|
||||
&ProjectSettingsToolWindow::MakeSerializerJsonNonRoot,
|
||||
this,
|
||||
plat,
|
||||
AZStd::placeholders::_1,
|
||||
&m_settingsContainer->GetProjectJsonDocument(),
|
||||
m_settingsContainer->GetProjectJsonValue(GetPlatformKey(plat)).GetValue()
|
||||
));
|
||||
break;
|
||||
case PlatformId::Ios:
|
||||
{
|
||||
PlistDictionary* dict = m_settingsContainer->GetPlistDictionary(plat).release();
|
||||
if (dict == nullptr)
|
||||
{
|
||||
QMessageBox::critical
|
||||
(
|
||||
this,
|
||||
"Critical",
|
||||
"Ios pList is invalid. Project Settings Tool must close.",
|
||||
QMessageBox::Abort
|
||||
);
|
||||
ForceClose();
|
||||
}
|
||||
|
||||
m_platformPropertyEditors[platIdValue]->EnumerateInstances(AZStd::bind
|
||||
(
|
||||
&ProjectSettingsToolWindow::MakeSerializerPlist,
|
||||
this,
|
||||
plat,
|
||||
AZStd::placeholders::_1,
|
||||
// All arguments must be copy constructible so this must be released
|
||||
dict
|
||||
));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
AZ_Assert(false, "Cannot make serializer for unknown platform.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectSettingsToolWindow::LoadPropertiesFromSettings()
|
||||
{
|
||||
// Disable all fields links
|
||||
|
||||
for (int plat = 0; plat < static_cast<unsigned long long>(PlatformId::NumPlatformIds); ++plat)
|
||||
{
|
||||
if (PlatformEnabled(static_cast<PlatformId>(plat)))
|
||||
{
|
||||
LoadPropertiesFromPlatformSettings(Platforms[plat]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectSettingsToolWindow::LoadPropertiesFromPlatformSettings(const Platform& plat)
|
||||
{
|
||||
unsigned platIdValue = static_cast<unsigned>(plat.m_id);
|
||||
m_platformSerializers[platIdValue]->LoadFromSettings();
|
||||
m_platformPropertyEditors[platIdValue]->InvalidateValues();
|
||||
}
|
||||
|
||||
bool ProjectSettingsToolWindow::UiEqualToSettings()
|
||||
{
|
||||
for (int plat = 0; plat < static_cast<unsigned long long>(PlatformId::NumPlatformIds); ++plat)
|
||||
{
|
||||
if (PlatformEnabled(static_cast<PlatformId>(plat)))
|
||||
{
|
||||
if (!UiEqualToPlatformSettings(Platforms[plat]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ProjectSettingsToolWindow::UiEqualToPlatformSettings(const Platform& plat)
|
||||
{
|
||||
return m_platformSerializers[static_cast<unsigned>(plat.m_id)]->UiEqualToSettings();
|
||||
}
|
||||
|
||||
bool ProjectSettingsToolWindow::ValidateAllProperties()
|
||||
{
|
||||
return m_validationHandler->AllValid();
|
||||
}
|
||||
|
||||
void ProjectSettingsToolWindow::SaveSettingsFromUi()
|
||||
{
|
||||
bool anySaves = false;
|
||||
const unsigned long long numPlatforms = static_cast<unsigned long long>(PlatformId::NumPlatformIds);
|
||||
bool needToSavePlat[numPlatforms] = {false};
|
||||
|
||||
for (int plat = 0; plat < numPlatforms; ++plat)
|
||||
{
|
||||
if (PlatformEnabled(static_cast<PlatformId>(plat)))
|
||||
{
|
||||
const Platform& platform = Platforms[plat];
|
||||
if (!UiEqualToPlatformSettings(platform))
|
||||
{
|
||||
needToSavePlat[plat] = true;
|
||||
anySaves = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (anySaves)
|
||||
{
|
||||
// Keeps queued button presses from getting in
|
||||
if (m_ui->saveButton->isEnabled())
|
||||
{
|
||||
m_ui->saveButton->setEnabled(false);
|
||||
m_ui->reloadButton->setEnabled(false);
|
||||
|
||||
if (ValidateAllProperties())
|
||||
{
|
||||
bool projectJsonChanged = false;
|
||||
|
||||
for (int plat = 0; plat < numPlatforms; ++plat)
|
||||
{
|
||||
const Platform& platform = Platforms[plat];
|
||||
|
||||
if (needToSavePlat[plat])
|
||||
{
|
||||
m_platformSerializers[plat]->SaveToSettings();
|
||||
if (m_settingsContainer->IsPlistPlatform(platform))
|
||||
{
|
||||
m_settingsContainer->SavePlistData(platform);
|
||||
}
|
||||
else
|
||||
{
|
||||
projectJsonChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (projectJsonChanged)
|
||||
{
|
||||
m_settingsContainer->SaveProjectJsonData();
|
||||
}
|
||||
|
||||
ShowAllErrorsThenExitIfInvalid();
|
||||
|
||||
m_ui->reconfigureLog->setText("");
|
||||
int result = QMessageBox::question
|
||||
(
|
||||
this,
|
||||
tr("Reconfigure Project"),
|
||||
tr("For new settings to be applied the project must be reconfigured. Would you like run configure now?"),
|
||||
QMessageBox::Yes,
|
||||
QMessageBox::No
|
||||
);
|
||||
|
||||
if (QMessageBox::Yes == result)
|
||||
{
|
||||
m_ui->reconfigureLog->show();
|
||||
#if defined(AZ_PLATFORM_WINDOWS)
|
||||
m_reconfigureProcess.start("cmd.exe", { QString("/C %1").arg("lmbr_waf.bat configure") });
|
||||
#elif defined(AZ_PLATFORM_MAC) || defined(AZ_PLATFORM_LINUX)
|
||||
m_reconfigureProcess.start("/bin/sh", { QString("%1").arg("lmbr_waf.sh configure") });
|
||||
#else
|
||||
#error "Needs to be implemented"
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ui->reloadButton->setEnabled(true);
|
||||
m_ui->saveButton->setEnabled(true);
|
||||
}
|
||||
}
|
||||
// Show a message box telling user settings failed to save
|
||||
else
|
||||
{
|
||||
QMessageBox::critical(this, tr("Failed To Save"), tr("Failed to save due to invalid settings."));
|
||||
m_ui->reloadButton->setEnabled(true);
|
||||
m_ui->saveButton->setEnabled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectSettingsToolWindow::SaveSettingsFromPlatformUi(const Platform& plat)
|
||||
{
|
||||
m_platformSerializers[static_cast<unsigned>(plat.m_id)]->SaveToSettings();
|
||||
m_settingsContainer->SavePlatformData(plat);
|
||||
ShowAllErrorsThenExitIfInvalid();
|
||||
}
|
||||
|
||||
void ProjectSettingsToolWindow::ReloadUiFromSettings()
|
||||
{
|
||||
if (!UiEqualToSettings())
|
||||
{
|
||||
int result = QMessageBox::warning
|
||||
(
|
||||
this,
|
||||
tr("Reload Settings"),
|
||||
tr("Are you sure you would like to reload settings from file? All changes will be lost."),
|
||||
QMessageBox::Reset,
|
||||
QMessageBox::Cancel);
|
||||
|
||||
if (result == QMessageBox::Reset)
|
||||
{
|
||||
m_settingsContainer->ReloadProjectJsonData();
|
||||
m_settingsContainer->ReloadPlistData();
|
||||
MakeSerializers();
|
||||
|
||||
// Disable links to avoid overwriting values while loading
|
||||
m_linkHandler->DisableAllPropertyLinks();
|
||||
LoadPropertiesFromSettings();
|
||||
|
||||
// Re-enable them then mirror
|
||||
m_linkHandler->EnableAllPropertyLinks();
|
||||
m_linkHandler->EnableOptionalLinksIfAllPropertiesEqual();
|
||||
m_linkHandler->MirrorAllLinkedProperties();
|
||||
|
||||
// Mark any invalid fields loaded from file
|
||||
ValidateAllProperties();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ProjectSettingsToolWindow::PlatformEnabled(PlatformId platformId)
|
||||
{
|
||||
// iOS can be disabled if the plist file is missing
|
||||
if (platformId == PlatformId::Ios)
|
||||
{
|
||||
const AZStd::string filename = m_projectRoot + PlatformResourcesFolder(platformId);
|
||||
return CFileUtil::FileExists(filename.c_str());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const char* ProjectSettingsToolWindow::PlatformResourcesFolder(PlatformId platformId)
|
||||
{
|
||||
if (platformId == PlatformId::Ios)
|
||||
{
|
||||
const AZStd::string firstfilename = m_projectRoot + "/Gem/Resources/Platform/iOS/Info.plist";
|
||||
if (CFileUtil::FileExists(firstfilename.c_str()))
|
||||
{
|
||||
return "/Gem/Resources/Platform/iOS/Info.plist";
|
||||
}
|
||||
else
|
||||
{
|
||||
const AZStd::string filename = m_projectRoot + "/Gem/Resources/IOSLauncher/Info.plist";
|
||||
if (CFileUtil::FileExists(filename.c_str()))
|
||||
{
|
||||
return "/Gem/Resources/IOSLauncher/Info.plist";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#include <moc_ProjectSettingsToolWindow.cpp>
|
||||
} // namespace ProjectSettingsTool
|
||||
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include "LastPathBus.h"
|
||||
#include "Platforms.h"
|
||||
#include "PlatformSettings.h"
|
||||
#include "ProjectSettingsContainer.h"
|
||||
#include "ProjectSettingsSerialization.h"
|
||||
#include "ValidatorBus.h"
|
||||
|
||||
#include <QProcess>
|
||||
#include <QScopedPointer>
|
||||
#include <QWidget>
|
||||
#endif
|
||||
|
||||
// Forward Declares
|
||||
namespace Ui
|
||||
{
|
||||
class ProjectSettingsToolWidget;
|
||||
}
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
class InstanceDataHierarchy;
|
||||
class PropertyHandlerBase;
|
||||
class ReflectedPropertyEditor;
|
||||
}
|
||||
|
||||
namespace ProjectSettingsTool
|
||||
{
|
||||
//Forward Declares
|
||||
class Validator;
|
||||
class ValidationHandler;
|
||||
class PropertyLinkedHandler;
|
||||
|
||||
struct Properties
|
||||
{
|
||||
BaseSettings base;
|
||||
AndroidSettings android;
|
||||
IosSettings ios;
|
||||
};
|
||||
|
||||
// Main window for Project Settings tool
|
||||
class ProjectSettingsToolWindow
|
||||
: public QWidget
|
||||
, public LastPathBus::Handler
|
||||
, public ValidatorBus::Handler
|
||||
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
static const GUID& GetClassID()
|
||||
{
|
||||
// {0DC1B7D9-B660-41C3-91F1-A643EE65AADF}
|
||||
static const GUID guid = {
|
||||
0x0dc1b7d9, 0xb660, 0x41c3, { 0x91, 0xf1, 0xa6, 0x43, 0xee, 0x65, 0xaa, 0xdf }
|
||||
};
|
||||
return guid;
|
||||
}
|
||||
|
||||
ProjectSettingsToolWindow(QWidget* parent = nullptr);
|
||||
~ProjectSettingsToolWindow();
|
||||
|
||||
// Ebuses
|
||||
QString GetLastImagePath() override;
|
||||
void SetLastImagePath(const QString& path) override;
|
||||
|
||||
FunctorValidator* GetValidator(FunctorValidator::FunctorType) override;
|
||||
void TrackValidator(FunctorValidator*) override;
|
||||
|
||||
static void ReflectPlatformClasses();
|
||||
|
||||
private:
|
||||
AZ_DISABLE_COPY_MOVE(ProjectSettingsToolWindow);
|
||||
|
||||
void closeEvent(QCloseEvent* event) override;
|
||||
// Close the window now because an error occurred
|
||||
void ForceClose();
|
||||
|
||||
// Un/Registers and dis/connect handlers and buses
|
||||
void RegisterHandlersAndBusses();
|
||||
void UnregisterHandlersAndBusses();
|
||||
|
||||
void InitializeUi();
|
||||
|
||||
// Used to make the serializers for settings
|
||||
void MakeSerializerJson(const Platform& plat, AzToolsFramework::InstanceDataHierarchy& hierarchy, rapidjson::Document* doc);
|
||||
void MakeSerializerJsonNonRoot(const Platform& plat, AzToolsFramework::InstanceDataHierarchy& hierarchy, rapidjson::Document* doc, rapidjson::Value* jsonRoot);
|
||||
void MakeSerializerPlist(const Platform& plat, AzToolsFramework::InstanceDataHierarchy& hierarchy, PlistDictionary* dict);
|
||||
|
||||
// Shows an error dialog if an error has occurred while loading settings then exits if users chooses
|
||||
// Returns true if there was an error
|
||||
bool IfErrorShowThenExit();
|
||||
// Loop through all errors then exit if the user chooses to abort or window is in invalid state
|
||||
void ShowAllErrorsThenExitIfInvalid();
|
||||
|
||||
// Resizes TabWidget to size of current tab instead of largest tab
|
||||
void ResizeTabs(int index);
|
||||
|
||||
// Add all platforms into the ui
|
||||
void AddAllPlatformsToUi();
|
||||
// Add given platform into the ui
|
||||
void AddPlatformToUi(const Platform& plat);
|
||||
// Makes all serializers
|
||||
void MakeSerializers();
|
||||
// Makes the serializer for specified platform
|
||||
void MakePlatformSerializer(const Platform& plat);
|
||||
|
||||
// Replace values in ui with those read from settings
|
||||
void LoadPropertiesFromSettings();
|
||||
// Load properties for specified platform from file
|
||||
void LoadPropertiesFromPlatformSettings(const Platform& plat);
|
||||
|
||||
// Checks if ui is the same as all settings
|
||||
bool UiEqualToSettings();
|
||||
// Checks if platform is the same as settings
|
||||
bool UiEqualToPlatformSettings(const Platform& plat);
|
||||
|
||||
// Checks if all properties are valid, if any are not returns false, also sets warnings on those properties
|
||||
bool ValidateAllProperties();
|
||||
|
||||
// Replace values in settings with those from ui and save to file
|
||||
void SaveSettingsFromUi();
|
||||
// Saves all properties for specified platform from to file
|
||||
void SaveSettingsFromPlatformUi(const Platform& plat);
|
||||
|
||||
// Reload settings files and replace the values in ui with them
|
||||
void ReloadUiFromSettings();
|
||||
|
||||
// returns true if the platform is enabled
|
||||
bool PlatformEnabled(PlatformId platformId);
|
||||
|
||||
// returns the resource folder
|
||||
const char* PlatformResourcesFolder(PlatformId platformId);
|
||||
|
||||
// The ui for the window
|
||||
QScopedPointer<Ui::ProjectSettingsToolWidget> m_ui;
|
||||
|
||||
// The process used to reconfigure settings
|
||||
QProcess m_reconfigureProcess;
|
||||
|
||||
AZStd::string m_devRoot;
|
||||
AZStd::string m_projectRoot;
|
||||
AZStd::string m_projectName;
|
||||
|
||||
// Used to initialize the settings container's pLists
|
||||
ProjectSettingsContainer::PlistInitVector m_plistsInitVector;
|
||||
|
||||
// Container to manage settings files per platform
|
||||
AZStd::unique_ptr<ProjectSettingsContainer> m_settingsContainer;
|
||||
// Allows lookup and contains all allocated QValidators
|
||||
AZStd::unique_ptr<Validator> m_validator;
|
||||
|
||||
Properties m_platformProperties;
|
||||
AzToolsFramework::ReflectedPropertyEditor* m_platformPropertyEditors[static_cast<unsigned>(PlatformId::NumPlatformIds)];
|
||||
AZStd::unique_ptr<Serializer> m_platformSerializers[static_cast<unsigned>(PlatformId::NumPlatformIds)];
|
||||
|
||||
// Pointers to all handlers to they can be unregistered and deleted
|
||||
AZStd::vector<AzToolsFramework::PropertyHandlerBase*> m_propertyHandlers;
|
||||
AZStd::unique_ptr<ValidationHandler> m_validationHandler;
|
||||
PropertyLinkedHandler* m_linkHandler;
|
||||
|
||||
// Last path used when browsing for images in icons or splash
|
||||
QString m_lastImagesPath;
|
||||
bool m_invalidState;
|
||||
};
|
||||
} // namespace ProjectSettingsTool
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/PlatformDef.h>
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Engine
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#include <ISystem.h>
|
||||
#include <Cry_Math.h>
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ProjectSettingsTool_precompiled.h"
|
||||
#include "ProjectSettingsValidator.h"
|
||||
|
||||
#include "Validators.h"
|
||||
|
||||
namespace ProjectSettingsTool
|
||||
{
|
||||
Validator::Validator()
|
||||
{}
|
||||
|
||||
Validator::~Validator()
|
||||
{
|
||||
for (AZStd::pair<FunctorValidator::FunctorType, FunctorValidator*>& pair : m_validatorToQValidator)
|
||||
{
|
||||
delete pair.second;
|
||||
}
|
||||
for (FunctorValidator* qValidator : m_otherValidators)
|
||||
{
|
||||
delete qValidator;
|
||||
}
|
||||
}
|
||||
|
||||
FunctorValidator* Validator::GetQValidator(FunctorValidator::FunctorType validator)
|
||||
{
|
||||
if (validator != nullptr)
|
||||
{
|
||||
auto iter = m_validatorToQValidator.find(validator);
|
||||
|
||||
if (iter != m_validatorToQValidator.end())
|
||||
{
|
||||
return iter->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
FunctorValidator* qValidator = new FunctorValidator(validator);
|
||||
m_validatorToQValidator.insert(
|
||||
AZStd::pair<FunctorValidator::FunctorType, FunctorValidator*>(validator, qValidator));
|
||||
|
||||
return qValidator;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Validator::TrackThisValidator(FunctorValidator* validator)
|
||||
{
|
||||
m_otherValidators.push_back(validator);
|
||||
}
|
||||
} // namespace ProjectSettingsTool
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "FunctorValidator.h"
|
||||
|
||||
#include <AzCore/std/string/string.h>
|
||||
#include <AzCore/std/containers/unordered_map.h>
|
||||
|
||||
|
||||
namespace ProjectSettingsTool
|
||||
{
|
||||
class Validator
|
||||
{
|
||||
public:
|
||||
typedef FunctorValidator::ReturnType ValidatorReturnType;
|
||||
typedef FunctorValidator::FunctorType ValidatorType;
|
||||
|
||||
Validator();
|
||||
~Validator();
|
||||
|
||||
// Finds the QValidator for a given validator or makes one and returns it
|
||||
FunctorValidator* GetQValidator(FunctorValidator::FunctorType validator);
|
||||
// Tracks this QValidator and deletes it in the destructor
|
||||
void TrackThisValidator(FunctorValidator* validator);
|
||||
|
||||
private:
|
||||
typedef AZStd::unordered_map<FunctorValidator::FunctorType, FunctorValidator*> ValidatorToQValidatorType;
|
||||
typedef AZStd::list<FunctorValidator*> QValidatorList;
|
||||
|
||||
AZ_DISABLE_COPY_MOVE(Validator);
|
||||
|
||||
// Maps validator functions to QValidators
|
||||
ValidatorToQValidatorType m_validatorToQValidator;
|
||||
// Tracks allocations of other QValidators so they don't leak
|
||||
QValidatorList m_otherValidators;
|
||||
};
|
||||
} // namespace ProjectSettingsTool
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ProjectSettingsTool_precompiled.h"
|
||||
#include "PropertyFileSelect.h"
|
||||
|
||||
#include "PlatformSettings_common.h"
|
||||
#include "ValidationHandler.h"
|
||||
|
||||
#include <QLayout>
|
||||
#include <QPushButton>
|
||||
#include <QLineEdit>
|
||||
|
||||
namespace ProjectSettingsTool
|
||||
{
|
||||
PropertyFileSelectCtrl::PropertyFileSelectCtrl(QWidget* pParent)
|
||||
: PropertyFuncValBrowseEditCtrl(pParent)
|
||||
, m_selectFunctor(nullptr)
|
||||
{
|
||||
// Turn on clear button by default
|
||||
browseEdit()->setClearButtonEnabled(true);
|
||||
|
||||
connect(browseEdit(), &AzQtComponents::BrowseEdit::attachedButtonTriggered, this, &PropertyFileSelectCtrl::SelectFile);
|
||||
}
|
||||
|
||||
void PropertyFileSelectCtrl::SelectFile()
|
||||
{
|
||||
if (m_selectFunctor != nullptr)
|
||||
{
|
||||
QString path = m_selectFunctor(browseEdit()->text());
|
||||
if (!path.isEmpty())
|
||||
{
|
||||
SetValueUser(path);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Assert(false, "No file select functor set.");
|
||||
}
|
||||
}
|
||||
|
||||
void PropertyFileSelectCtrl::ConsumeAttribute(AZ::u32 attrib, AzToolsFramework::PropertyAttributeReader* attrValue, const char* debugName)
|
||||
{
|
||||
if (attrib == Attributes::SelectFunction)
|
||||
{
|
||||
void* functor = nullptr;
|
||||
if (attrValue->Read<void*>(functor))
|
||||
{
|
||||
// This is guaranteed type safe elsewhere so this is safe
|
||||
m_selectFunctor = reinterpret_cast<FileSelectFuncType>(functor);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PropertyFuncValBrowseEditCtrl::ConsumeAttribute(attrib, attrValue, debugName);
|
||||
}
|
||||
}
|
||||
|
||||
// Handler ///////////////////////////////////////////////////////////////////
|
||||
|
||||
PropertyFileSelectHandler::PropertyFileSelectHandler(ValidationHandler* valHdlr)
|
||||
: AzToolsFramework::PropertyHandler<AZStd::string, PropertyFileSelectCtrl>()
|
||||
, m_validationHandler(valHdlr)
|
||||
{}
|
||||
|
||||
AZ::u32 PropertyFileSelectHandler::GetHandlerName(void) const
|
||||
{
|
||||
return Handlers::FileSelect;
|
||||
}
|
||||
|
||||
QWidget* PropertyFileSelectHandler::CreateGUI(QWidget* pParent)
|
||||
{
|
||||
PropertyFileSelectCtrl* ctrl = aznew PropertyFileSelectCtrl(pParent);
|
||||
m_validationHandler->AddValidatorCtrl(ctrl);
|
||||
return ctrl;
|
||||
}
|
||||
|
||||
void PropertyFileSelectHandler::ConsumeAttribute(PropertyFileSelectCtrl* GUI, AZ::u32 attrib, AzToolsFramework::PropertyAttributeReader* attrValue, const char* debugName)
|
||||
{
|
||||
GUI->ConsumeAttribute(attrib, attrValue, debugName);
|
||||
}
|
||||
|
||||
void PropertyFileSelectHandler::WriteGUIValuesIntoProperty([[maybe_unused]] size_t index, PropertyFileSelectCtrl* GUI, property_t& instance, [[maybe_unused]] AzToolsFramework::InstanceDataNode* node)
|
||||
{
|
||||
instance = GUI->GetValue().toUtf8().data();
|
||||
}
|
||||
|
||||
bool PropertyFileSelectHandler::ReadValuesIntoGUI([[maybe_unused]] size_t index, PropertyFileSelectCtrl* GUI, const property_t& instance, [[maybe_unused]] AzToolsFramework::InstanceDataNode* node)
|
||||
{
|
||||
GUI->SetValue(instance.data());
|
||||
GUI->ForceValidate();
|
||||
return true;
|
||||
}
|
||||
|
||||
PropertyFileSelectHandler* PropertyFileSelectHandler::Register(ValidationHandler* valHdlr)
|
||||
{
|
||||
PropertyFileSelectHandler* handler = aznew PropertyFileSelectHandler(valHdlr);
|
||||
AzToolsFramework::PropertyTypeRegistrationMessages::Bus::Broadcast(
|
||||
&AzToolsFramework::PropertyTypeRegistrationMessages::Bus::Handler::RegisterPropertyType,
|
||||
handler);
|
||||
return handler;
|
||||
}
|
||||
} // namespace ProjectSettingsTool
|
||||
|
||||
#include <moc_PropertyFileSelect.cpp>
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include "PropertyFuncValBrowseEdit.h"
|
||||
#endif
|
||||
|
||||
// Forward declare
|
||||
class QPushButton;
|
||||
|
||||
namespace ProjectSettingsTool
|
||||
{
|
||||
// Forward declare
|
||||
class ValidationHandler;
|
||||
|
||||
class PropertyFileSelectCtrl
|
||||
: public PropertyFuncValBrowseEditCtrl
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
typedef QString(* FileSelectFuncType)(const QString&);
|
||||
|
||||
PropertyFileSelectCtrl(QWidget* pParent = nullptr);
|
||||
|
||||
virtual void ConsumeAttribute(AZ::u32 attrib, AzToolsFramework::PropertyAttributeReader* attrValue, const char* debugName) override;
|
||||
|
||||
protected:
|
||||
void SelectFile();
|
||||
|
||||
QPushButton* m_selectButton;
|
||||
FileSelectFuncType m_selectFunctor;
|
||||
};
|
||||
|
||||
class PropertyFileSelectHandler
|
||||
: public AzToolsFramework::PropertyHandler<AZStd::string, PropertyFileSelectCtrl>
|
||||
{
|
||||
AZ_CLASS_ALLOCATOR(PropertyFileSelectHandler, AZ::SystemAllocator, 0);
|
||||
|
||||
public:
|
||||
PropertyFileSelectHandler(ValidationHandler* valHdlr);
|
||||
|
||||
AZ::u32 GetHandlerName(void) const override;
|
||||
// Need to unregister ourselves
|
||||
bool AutoDelete() const override { return false; }
|
||||
|
||||
QWidget* CreateGUI(QWidget* pParent) override;
|
||||
void ConsumeAttribute(PropertyFileSelectCtrl* GUI, AZ::u32 attrib, AzToolsFramework::PropertyAttributeReader* attrValue, const char* debugName) override;
|
||||
void WriteGUIValuesIntoProperty(size_t index, PropertyFileSelectCtrl* GUI, property_t& instance, AzToolsFramework::InstanceDataNode* node) override;
|
||||
bool ReadValuesIntoGUI(size_t index, PropertyFileSelectCtrl* GUI, const property_t& instance, AzToolsFramework::InstanceDataNode* node) override;
|
||||
static PropertyFileSelectHandler* Register(ValidationHandler* valHdlr);
|
||||
|
||||
private:
|
||||
ValidationHandler* m_validationHandler;
|
||||
};
|
||||
} // namespace ProjectSettingsTool
|
||||
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ProjectSettingsTool_precompiled.h"
|
||||
#include "PropertyFuncValBrowseEdit.h"
|
||||
#include "PlatformSettings_common.h"
|
||||
#include "ValidationHandler.h"
|
||||
#include "ValidatorBus.h"
|
||||
|
||||
#include <AzToolsFramework/UI/PropertyEditor/PropertyQTConstants.h>
|
||||
|
||||
#include <QLineEdit>
|
||||
#include <QHBoxLayout>
|
||||
|
||||
namespace ProjectSettingsTool
|
||||
{
|
||||
PropertyFuncValBrowseEditCtrl::PropertyFuncValBrowseEditCtrl(QWidget* pParent)
|
||||
: QWidget(pParent)
|
||||
, m_validator(nullptr)
|
||||
{
|
||||
QHBoxLayout* layout = new QHBoxLayout(this);
|
||||
m_browseEdit = new AzQtComponents::BrowseEdit(this);
|
||||
|
||||
layout->setSpacing(4);
|
||||
layout->setContentsMargins(1, 0, 1, 0);
|
||||
layout->addWidget(m_browseEdit);
|
||||
|
||||
browseEdit()->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed);
|
||||
browseEdit()->setMinimumWidth(AzToolsFramework::PropertyQTConstant_MinimumWidth);
|
||||
browseEdit()->setFixedHeight(AzToolsFramework::PropertyQTConstant_DefaultHeight);
|
||||
|
||||
browseEdit()->setFocusPolicy(Qt::StrongFocus);
|
||||
|
||||
setLayout(layout);
|
||||
setFocusProxy(browseEdit());
|
||||
setFocusPolicy(browseEdit()->focusPolicy());
|
||||
|
||||
m_browseEdit->setClearButtonEnabled(true);
|
||||
connect(m_browseEdit, &AzQtComponents::BrowseEdit::textChanged, this, &PropertyFuncValBrowseEditCtrl::ValueChangedByUser);
|
||||
connect(m_browseEdit, &AzQtComponents::BrowseEdit::textChanged, this, &PropertyFuncValBrowseEditCtrl::ValidateAndShowErrors);
|
||||
connect(m_browseEdit, &AzQtComponents::BrowseEdit::textChanged, this, [this]([[maybe_unused]] const QString& text)
|
||||
{
|
||||
EBUS_EVENT(AzToolsFramework::PropertyEditorGUIMessages::Bus, RequestWrite, this);
|
||||
});
|
||||
}
|
||||
|
||||
QString PropertyFuncValBrowseEditCtrl::GetValue() const
|
||||
{
|
||||
return m_browseEdit->text();
|
||||
}
|
||||
|
||||
void PropertyFuncValBrowseEditCtrl::SetValue(const QString& value)
|
||||
{
|
||||
m_browseEdit->setText(value);
|
||||
}
|
||||
|
||||
void PropertyFuncValBrowseEditCtrl::SetValueUser(const QString& value)
|
||||
{
|
||||
SetValue(value);
|
||||
|
||||
emit ValueChangedByUser();
|
||||
}
|
||||
|
||||
FunctorValidator* PropertyFuncValBrowseEditCtrl::GetValidator()
|
||||
{
|
||||
return m_validator;
|
||||
}
|
||||
|
||||
void PropertyFuncValBrowseEditCtrl::SetValidator(FunctorValidator* validator)
|
||||
{
|
||||
m_browseEdit->lineEdit()->setValidator(validator);
|
||||
m_validator = validator;
|
||||
}
|
||||
|
||||
void PropertyFuncValBrowseEditCtrl::SetValidator(FunctorValidator::FunctorType validator)
|
||||
{
|
||||
FunctorValidator* val = nullptr;
|
||||
ValidatorBus::BroadcastResult(
|
||||
val,
|
||||
&ValidatorBus::Handler::GetValidator,
|
||||
validator);
|
||||
|
||||
SetValidator(val);
|
||||
}
|
||||
|
||||
bool PropertyFuncValBrowseEditCtrl::ValidateAndShowErrors()
|
||||
{
|
||||
if (m_validator)
|
||||
{
|
||||
FunctorValidator::ReturnType result = m_validator->ValidateWithErrors(m_browseEdit->text());
|
||||
if (result.first == QValidator::Acceptable)
|
||||
{
|
||||
m_browseEdit->lineEdit()->setToolTip("");
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_browseEdit->lineEdit()->setToolTip(result.second);
|
||||
m_browseEdit->lineEdit()->setReadOnly(false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void PropertyFuncValBrowseEditCtrl::ForceValidate()
|
||||
{
|
||||
// Triggers update for errors
|
||||
m_browseEdit->lineEdit()->textChanged(m_browseEdit->text());
|
||||
}
|
||||
|
||||
void PropertyFuncValBrowseEditCtrl::ConsumeAttribute(AZ::u32 attrib, AzToolsFramework::PropertyAttributeReader* attrValue, [[maybe_unused]] const char* debugName)
|
||||
{
|
||||
if (attrib == Attributes::FuncValidator)
|
||||
{
|
||||
void* validator = nullptr;
|
||||
if (attrValue->Read<void*>(validator))
|
||||
{
|
||||
if (validator != nullptr)
|
||||
{
|
||||
SetValidator(reinterpret_cast<FunctorValidator::FunctorType>(validator));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (attrib == Attributes::ClearButton)
|
||||
{
|
||||
bool enable = false;
|
||||
if (attrValue->Read<bool>(enable))
|
||||
{
|
||||
m_browseEdit->lineEdit()->setClearButtonEnabled(enable);
|
||||
}
|
||||
}
|
||||
else if (attrib == Attributes::RemovableReadOnly)
|
||||
{
|
||||
bool readOnly = false;
|
||||
if (attrValue->Read<bool>(readOnly))
|
||||
{
|
||||
m_browseEdit->lineEdit()->setReadOnly(readOnly);
|
||||
}
|
||||
}
|
||||
else if (attrib == Attributes::ObfuscatedText)
|
||||
{
|
||||
bool obfus = false;
|
||||
if (attrValue->Read<bool>(obfus) && obfus)
|
||||
{
|
||||
m_browseEdit->lineEdit()->setEchoMode(QLineEdit::Password);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AzQtComponents::BrowseEdit* PropertyFuncValBrowseEditCtrl::browseEdit()
|
||||
{
|
||||
return m_browseEdit;
|
||||
}
|
||||
|
||||
// Handler ///////////////////////////////////////////////////////////////////
|
||||
|
||||
PropertyFuncValBrowseEditHandler::PropertyFuncValBrowseEditHandler(ValidationHandler* valHdlr)
|
||||
: AzToolsFramework::PropertyHandler <AZStd::string, PropertyFuncValBrowseEditCtrl>()
|
||||
, m_validationHandler(valHdlr
|
||||
)
|
||||
{}
|
||||
|
||||
AZ::u32 PropertyFuncValBrowseEditHandler::GetHandlerName(void) const
|
||||
{
|
||||
return Handlers::QValidatedBrowseEdit;
|
||||
}
|
||||
|
||||
QWidget* PropertyFuncValBrowseEditHandler::CreateGUI(QWidget* pParent)
|
||||
{
|
||||
PropertyFuncValBrowseEditCtrl* ctrl = aznew PropertyFuncValBrowseEditCtrl(pParent);
|
||||
m_validationHandler->AddValidatorCtrl(ctrl);
|
||||
return ctrl;
|
||||
}
|
||||
|
||||
void PropertyFuncValBrowseEditHandler::ConsumeAttribute(PropertyFuncValBrowseEditCtrl* GUI, AZ::u32 attrib, AzToolsFramework::PropertyAttributeReader* attrValue, const char* debugName)
|
||||
{
|
||||
GUI->ConsumeAttribute(attrib, attrValue, debugName);
|
||||
}
|
||||
|
||||
void PropertyFuncValBrowseEditHandler::WriteGUIValuesIntoProperty([[maybe_unused]] size_t index, PropertyFuncValBrowseEditCtrl* GUI, property_t& instance, [[maybe_unused]] AzToolsFramework::InstanceDataNode* node)
|
||||
{
|
||||
instance = GUI->GetValue().toUtf8().data();
|
||||
}
|
||||
|
||||
bool PropertyFuncValBrowseEditHandler::ReadValuesIntoGUI([[maybe_unused]] size_t index, PropertyFuncValBrowseEditCtrl* GUI, const property_t& instance, [[maybe_unused]] AzToolsFramework::InstanceDataNode* node)
|
||||
{
|
||||
GUI->SetValue(instance.data());
|
||||
GUI->ForceValidate();
|
||||
return true;
|
||||
}
|
||||
|
||||
PropertyFuncValBrowseEditHandler* PropertyFuncValBrowseEditHandler::Register(ValidationHandler* valHdlr)
|
||||
{
|
||||
PropertyFuncValBrowseEditHandler* handler = aznew PropertyFuncValBrowseEditHandler(valHdlr);
|
||||
AzToolsFramework::PropertyTypeRegistrationMessages::Bus::Broadcast(
|
||||
&AzToolsFramework::PropertyTypeRegistrationMessages::Bus::Handler::RegisterPropertyType,
|
||||
handler);
|
||||
return handler;
|
||||
}
|
||||
} // namespace ProjectSettingsTool
|
||||
|
||||
#include <moc_PropertyFuncValBrowseEdit.cpp>
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include "FunctorValidator.h"
|
||||
|
||||
#include <AzToolsFramework/UI/PropertyEditor/PropertyEditorAPI.h>
|
||||
|
||||
#include <AzQtComponents/Components/Widgets/BrowseEdit.h>
|
||||
#endif
|
||||
|
||||
namespace ProjectSettingsTool
|
||||
{
|
||||
// Forward Declare
|
||||
class ValidationHandler;
|
||||
|
||||
class PropertyFuncValBrowseEditCtrl
|
||||
: public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(PropertyFuncValBrowseEditCtrl, AZ::SystemAllocator, 0);
|
||||
|
||||
PropertyFuncValBrowseEditCtrl(QWidget* pParent = nullptr);
|
||||
|
||||
virtual QString GetValue() const;
|
||||
// Sets value programmtically and triggers validation
|
||||
virtual void SetValue(const QString& value);
|
||||
// Sets value as if user set it
|
||||
void SetValueUser(const QString& value);
|
||||
// Returns pointer to the validator used
|
||||
FunctorValidator* GetValidator();
|
||||
// Sets the validator for the lineedit
|
||||
void SetValidator(FunctorValidator* validator);
|
||||
// Sets the validator for the linedit
|
||||
void SetValidator(FunctorValidator::FunctorType validator);
|
||||
// Returns false if invalid and returns shows error as tooltip
|
||||
bool ValidateAndShowErrors();
|
||||
// Forces the values to up validated and style updated
|
||||
void ForceValidate();
|
||||
|
||||
// Returns a pointer to the BrowseEdit object.
|
||||
AzQtComponents::BrowseEdit* browseEdit();
|
||||
|
||||
virtual void ConsumeAttribute(AZ::u32 attrib, AzToolsFramework::PropertyAttributeReader* attrValue, const char* debugName);
|
||||
|
||||
signals:
|
||||
void ValueChangedByUser();
|
||||
|
||||
protected:
|
||||
// Keeps track of the validator so no const_casts must be done
|
||||
FunctorValidator* m_validator;
|
||||
|
||||
AzQtComponents::BrowseEdit* m_browseEdit = nullptr;
|
||||
};
|
||||
|
||||
class PropertyFuncValBrowseEditHandler
|
||||
: public AzToolsFramework::PropertyHandler <AZStd::string, PropertyFuncValBrowseEditCtrl>
|
||||
{
|
||||
AZ_CLASS_ALLOCATOR(PropertyFuncValBrowseEditHandler, AZ::SystemAllocator, 0);
|
||||
|
||||
public:
|
||||
PropertyFuncValBrowseEditHandler(ValidationHandler* valHdlr);
|
||||
|
||||
AZ::u32 GetHandlerName(void) const override;
|
||||
// Need to unregister ourselves
|
||||
bool AutoDelete() const override { return false; }
|
||||
|
||||
QWidget* CreateGUI(QWidget* pParent) override;
|
||||
void ConsumeAttribute(PropertyFuncValBrowseEditCtrl* GUI, AZ::u32 attrib, AzToolsFramework::PropertyAttributeReader* attrValue, const char* debugName) override;
|
||||
void WriteGUIValuesIntoProperty(size_t index, PropertyFuncValBrowseEditCtrl* GUI, property_t& instance, AzToolsFramework::InstanceDataNode* node) override;
|
||||
bool ReadValuesIntoGUI(size_t index, PropertyFuncValBrowseEditCtrl* GUI, const property_t& instance, AzToolsFramework::InstanceDataNode* node) override;
|
||||
static PropertyFuncValBrowseEditHandler* Register(ValidationHandler* valHdlr);
|
||||
|
||||
private:
|
||||
ValidationHandler* m_validationHandler;
|
||||
};
|
||||
} // namespace ProjectSettingsTool
|
||||
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ProjectSettingsTool_precompiled.h"
|
||||
#include "PropertyFuncValLineEdit.h"
|
||||
|
||||
#include "PlatformSettings_common.h"
|
||||
#include "ValidationHandler.h"
|
||||
#include "ValidatorBus.h"
|
||||
|
||||
#include <QLineEdit>
|
||||
|
||||
namespace ProjectSettingsTool
|
||||
{
|
||||
PropertyFuncValLineEditCtrl::PropertyFuncValLineEditCtrl(QWidget* pParent)
|
||||
: AzToolsFramework::PropertyStringLineEditCtrl(pParent)
|
||||
, m_validator(nullptr)
|
||||
{
|
||||
connect(m_pLineEdit, &QLineEdit::textEdited, this, &PropertyFuncValLineEditCtrl::ValueChangedByUser);
|
||||
connect(m_pLineEdit, &QLineEdit::textChanged, this, &PropertyFuncValLineEditCtrl::ValidateAndShowErrors);
|
||||
connect(m_pLineEdit, &QLineEdit::textChanged, this, [this]([[maybe_unused]] const QString& text)
|
||||
{
|
||||
EBUS_EVENT(AzToolsFramework::PropertyEditorGUIMessages::Bus, RequestWrite, this);
|
||||
});
|
||||
}
|
||||
|
||||
QString PropertyFuncValLineEditCtrl::GetValue() const
|
||||
{
|
||||
return m_pLineEdit->text();
|
||||
}
|
||||
|
||||
void PropertyFuncValLineEditCtrl::SetValue(const QString& value)
|
||||
{
|
||||
m_pLineEdit->setText(value);
|
||||
}
|
||||
|
||||
void PropertyFuncValLineEditCtrl::SetValueUser(const QString& value)
|
||||
{
|
||||
SetValue(value);
|
||||
|
||||
emit ValueChangedByUser();
|
||||
}
|
||||
|
||||
FunctorValidator* PropertyFuncValLineEditCtrl::GetValidator()
|
||||
{
|
||||
return m_validator;
|
||||
}
|
||||
|
||||
void PropertyFuncValLineEditCtrl::SetValidator(FunctorValidator* validator)
|
||||
{
|
||||
m_pLineEdit->setValidator(validator);
|
||||
m_validator = validator;
|
||||
}
|
||||
|
||||
void PropertyFuncValLineEditCtrl::SetValidator(FunctorValidator::FunctorType validator)
|
||||
{
|
||||
FunctorValidator* val = nullptr;
|
||||
ValidatorBus::BroadcastResult(
|
||||
val,
|
||||
&ValidatorBus::Handler::GetValidator,
|
||||
validator);
|
||||
|
||||
SetValidator(val);
|
||||
}
|
||||
|
||||
bool PropertyFuncValLineEditCtrl::ValidateAndShowErrors()
|
||||
{
|
||||
if (m_validator)
|
||||
{
|
||||
FunctorValidator::ReturnType result = m_validator->ValidateWithErrors(m_pLineEdit->text());
|
||||
if (result.first == QValidator::Acceptable)
|
||||
{
|
||||
m_pLineEdit->setToolTip("");
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pLineEdit->setToolTip(result.second);
|
||||
m_pLineEdit->setReadOnly(false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void PropertyFuncValLineEditCtrl::ForceValidate()
|
||||
{
|
||||
// Triggers update for errors
|
||||
m_pLineEdit->textChanged(m_pLineEdit->text());
|
||||
}
|
||||
|
||||
void PropertyFuncValLineEditCtrl::ConsumeAttribute(AZ::u32 attrib, AzToolsFramework::PropertyAttributeReader* attrValue, [[maybe_unused]] const char* debugName)
|
||||
{
|
||||
if (attrib == Attributes::FuncValidator)
|
||||
{
|
||||
void* validator = nullptr;
|
||||
if (attrValue->Read<void*>(validator))
|
||||
{
|
||||
if (validator != nullptr)
|
||||
{
|
||||
SetValidator(reinterpret_cast<FunctorValidator::FunctorType>(validator));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (attrib == Attributes::ClearButton)
|
||||
{
|
||||
bool enable = false;
|
||||
if (attrValue->Read<bool>(enable))
|
||||
{
|
||||
m_pLineEdit->setClearButtonEnabled(enable);
|
||||
}
|
||||
}
|
||||
else if (attrib == Attributes::RemovableReadOnly)
|
||||
{
|
||||
bool readOnly = false;
|
||||
if (attrValue->Read<bool>(readOnly))
|
||||
{
|
||||
m_pLineEdit->setReadOnly(readOnly);
|
||||
}
|
||||
}
|
||||
else if (attrib == Attributes::ObfuscatedText)
|
||||
{
|
||||
bool obfus = false;
|
||||
if (attrValue->Read<bool>(obfus) && obfus)
|
||||
{
|
||||
m_pLineEdit->setEchoMode(QLineEdit::Password);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handler ///////////////////////////////////////////////////////////////////
|
||||
|
||||
PropertyFuncValLineEditHandler::PropertyFuncValLineEditHandler(ValidationHandler* valHdlr)
|
||||
: AzToolsFramework::PropertyHandler <AZStd::string, PropertyFuncValLineEditCtrl>()
|
||||
, m_validationHandler(valHdlr
|
||||
)
|
||||
{}
|
||||
|
||||
AZ::u32 PropertyFuncValLineEditHandler::GetHandlerName(void) const
|
||||
{
|
||||
return Handlers::QValidatedLineEdit;
|
||||
}
|
||||
|
||||
QWidget* PropertyFuncValLineEditHandler::CreateGUI(QWidget* pParent)
|
||||
{
|
||||
PropertyFuncValLineEditCtrl* ctrl = aznew PropertyFuncValLineEditCtrl(pParent);
|
||||
m_validationHandler->AddValidatorCtrl(ctrl);
|
||||
return ctrl;
|
||||
}
|
||||
|
||||
void PropertyFuncValLineEditHandler::ConsumeAttribute(PropertyFuncValLineEditCtrl* GUI, AZ::u32 attrib, AzToolsFramework::PropertyAttributeReader* attrValue, const char* debugName)
|
||||
{
|
||||
GUI->ConsumeAttribute(attrib, attrValue, debugName);
|
||||
}
|
||||
|
||||
void PropertyFuncValLineEditHandler::WriteGUIValuesIntoProperty([[maybe_unused]] size_t index, PropertyFuncValLineEditCtrl* GUI, property_t& instance, [[maybe_unused]] AzToolsFramework::InstanceDataNode* node)
|
||||
{
|
||||
instance = GUI->GetValue().toUtf8().data();
|
||||
}
|
||||
|
||||
bool PropertyFuncValLineEditHandler::ReadValuesIntoGUI([[maybe_unused]] size_t index, PropertyFuncValLineEditCtrl* GUI, const property_t& instance, [[maybe_unused]] AzToolsFramework::InstanceDataNode* node)
|
||||
{
|
||||
GUI->SetValue(instance.data());
|
||||
GUI->ForceValidate();
|
||||
return true;
|
||||
}
|
||||
|
||||
PropertyFuncValLineEditHandler* PropertyFuncValLineEditHandler::Register(ValidationHandler* valHdlr)
|
||||
{
|
||||
PropertyFuncValLineEditHandler* handler = aznew PropertyFuncValLineEditHandler(valHdlr);
|
||||
AzToolsFramework::PropertyTypeRegistrationMessages::Bus::Broadcast(
|
||||
&AzToolsFramework::PropertyTypeRegistrationMessages::Bus::Handler::RegisterPropertyType,
|
||||
handler);
|
||||
return handler;
|
||||
}
|
||||
} // namespace ProjectSettingsTool
|
||||
|
||||
#include <moc_PropertyFuncValLineEdit.cpp>
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include "FunctorValidator.h"
|
||||
|
||||
#include <AzToolsFramework/UI/PropertyEditor/PropertyStringLineEditCtrl.hxx>
|
||||
#endif
|
||||
|
||||
namespace ProjectSettingsTool
|
||||
{
|
||||
// Forward Declare
|
||||
class ValidationHandler;
|
||||
|
||||
class PropertyFuncValLineEditCtrl
|
||||
: public AzToolsFramework::PropertyStringLineEditCtrl
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
PropertyFuncValLineEditCtrl(QWidget* pParent = nullptr);
|
||||
|
||||
virtual QString GetValue() const;
|
||||
// Sets value programmtically and triggers validation
|
||||
virtual void SetValue(const QString& value);
|
||||
// Sets value as if user set it
|
||||
void SetValueUser(const QString& value);
|
||||
// Returns pointer to the validator used
|
||||
FunctorValidator* GetValidator();
|
||||
// Sets the validator for the lineedit
|
||||
void SetValidator(FunctorValidator* validator);
|
||||
// Sets the validator for the linedit
|
||||
void SetValidator(FunctorValidator::FunctorType validator);
|
||||
// Returns false if invalid and returns shows error as tooltip
|
||||
bool ValidateAndShowErrors();
|
||||
// Forces the values to up validated and style updated
|
||||
void ForceValidate();
|
||||
|
||||
virtual void ConsumeAttribute(AZ::u32 attrib, AzToolsFramework::PropertyAttributeReader* attrValue, const char* debugName);
|
||||
|
||||
signals:
|
||||
void ValueChangedByUser();
|
||||
|
||||
protected:
|
||||
// Keeps track of the validator so no const_casts must be done
|
||||
FunctorValidator* m_validator;
|
||||
};
|
||||
|
||||
class PropertyFuncValLineEditHandler
|
||||
: public AzToolsFramework::PropertyHandler <AZStd::string, PropertyFuncValLineEditCtrl>
|
||||
{
|
||||
AZ_CLASS_ALLOCATOR(PropertyFuncValLineEditHandler, AZ::SystemAllocator, 0);
|
||||
|
||||
public:
|
||||
PropertyFuncValLineEditHandler(ValidationHandler* valHdlr);
|
||||
|
||||
AZ::u32 GetHandlerName(void) const override;
|
||||
// Need to unregister ourselves
|
||||
bool AutoDelete() const override { return false; }
|
||||
|
||||
QWidget* CreateGUI(QWidget* pParent) override;
|
||||
void ConsumeAttribute(PropertyFuncValLineEditCtrl* GUI, AZ::u32 attrib, AzToolsFramework::PropertyAttributeReader* attrValue, const char* debugName) override;
|
||||
void WriteGUIValuesIntoProperty(size_t index, PropertyFuncValLineEditCtrl* GUI, property_t& instance, AzToolsFramework::InstanceDataNode* node) override;
|
||||
bool ReadValuesIntoGUI(size_t index, PropertyFuncValLineEditCtrl* GUI, const property_t& instance, AzToolsFramework::InstanceDataNode* node) override;
|
||||
static PropertyFuncValLineEditHandler* Register(ValidationHandler* valHdlr);
|
||||
|
||||
private:
|
||||
ValidationHandler* m_validationHandler;
|
||||
};
|
||||
} // namespace ProjectSettingsTool
|
||||
@@ -0,0 +1,271 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ProjectSettingsTool_precompiled.h"
|
||||
#include "PropertyImagePreview.h"
|
||||
|
||||
#include "DefaultImageValidator.h"
|
||||
#include "PlatformSettings_common.h"
|
||||
#include "Utils.h"
|
||||
#include "ValidationHandler.h"
|
||||
#include "ValidatorBus.h"
|
||||
|
||||
#include <QBoxLayout>
|
||||
#include <QDir>
|
||||
#include <QLineEdit>
|
||||
|
||||
namespace ProjectSettingsTool
|
||||
{
|
||||
// Max width/length of preview in pixels
|
||||
static const int maxPreviewDim = 96;
|
||||
|
||||
PropertyImagePreviewCtrl::PropertyImagePreviewCtrl(QWidget* parent)
|
||||
: PropertyFuncValBrowseEditCtrl(parent)
|
||||
, m_defaultImagePreview(nullptr)
|
||||
, m_defaultPath("")
|
||||
{
|
||||
QLayout* myLayout = layout();
|
||||
QBoxLayout* boxLayout = qobject_cast<QBoxLayout*>(myLayout);
|
||||
|
||||
m_preview = new QLabel(this);
|
||||
m_preview->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||
m_preview->setFixedSize(QSize(maxPreviewDim, maxPreviewDim));
|
||||
|
||||
if (boxLayout != nullptr)
|
||||
{
|
||||
boxLayout->insertWidget(0, m_preview);
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Assert(false, "Expected QBoxLayout type not found in lineedit control.");
|
||||
myLayout->addWidget(m_preview);
|
||||
}
|
||||
|
||||
connect(this->m_browseEdit, &AzQtComponents::BrowseEdit::attachedButtonTriggered, this, [this]()
|
||||
{
|
||||
QString path = SelectImageFromFileDialog(browseEdit()->text());
|
||||
if (!path.isEmpty())
|
||||
{
|
||||
SetValueUser(path);
|
||||
}
|
||||
});
|
||||
|
||||
connect(browseEdit(), &AzQtComponents::BrowseEdit::textChanged, this, &PropertyImagePreviewCtrl::LoadPreview);
|
||||
}
|
||||
|
||||
void PropertyImagePreviewCtrl::SetValue(const QString& path)
|
||||
{
|
||||
browseEdit()->setText(path);
|
||||
|
||||
// Preview will not be shown if path is set to empty because it has not changed so call it here
|
||||
LoadPreview();
|
||||
}
|
||||
|
||||
const QString& PropertyImagePreviewCtrl::DefaultImagePath() const
|
||||
{
|
||||
return m_defaultPath;
|
||||
}
|
||||
|
||||
void PropertyImagePreviewCtrl::SetDefaultImagePath(const QString& newPath)
|
||||
{
|
||||
m_defaultPath = newPath;
|
||||
}
|
||||
|
||||
void PropertyImagePreviewCtrl::SetDefaultImagePreview(PropertyImagePreviewCtrl* imageSelect)
|
||||
{
|
||||
if (m_defaultImagePreview == nullptr)
|
||||
{
|
||||
m_defaultImagePreview = imageSelect;
|
||||
connect(imageSelect, &PropertyFuncValBrowseEditCtrl::ValueChangedByUser, this, &PropertyImagePreviewCtrl::LoadPreview);
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Assert(false, "Default image preview already set.");
|
||||
}
|
||||
}
|
||||
|
||||
PropertyImagePreviewCtrl* PropertyImagePreviewCtrl::DefaultImagePreview() const
|
||||
{
|
||||
return m_defaultImagePreview;
|
||||
}
|
||||
|
||||
void PropertyImagePreviewCtrl::AddOverrideToValidator(PropertyImagePreviewCtrl* preview)
|
||||
{
|
||||
qobject_cast<DefaultImageValidator*>(m_validator)->AddOverride(preview);
|
||||
connect(browseEdit(), &AzQtComponents::BrowseEdit::textChanged, this, &PropertyImagePreviewCtrl::ForceValidate);
|
||||
}
|
||||
|
||||
void PropertyImagePreviewCtrl::LoadPreview()
|
||||
{
|
||||
QString currentPath = browseEdit()->text();
|
||||
const QString* imagePath = nullptr;
|
||||
|
||||
if (!currentPath.isEmpty())
|
||||
{
|
||||
imagePath = ¤tPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_defaultImagePreview != nullptr)
|
||||
{
|
||||
currentPath = browseEdit()->text();
|
||||
}
|
||||
if (!currentPath.isEmpty())
|
||||
{
|
||||
imagePath = ¤tPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
imagePath = &m_defaultPath;
|
||||
}
|
||||
}
|
||||
|
||||
QDir dirPath(*imagePath);
|
||||
|
||||
// Keeps image from showing when no extension is given
|
||||
if (!imagePath->isEmpty() && dirPath.isReadable())
|
||||
{
|
||||
// Image loaded from file
|
||||
QImage originalImage;
|
||||
// Scaled image
|
||||
QImage processedImage;
|
||||
// The image to be displayed
|
||||
QImage* finalImage;
|
||||
bool validImage = originalImage.load(*imagePath);
|
||||
|
||||
if (validImage)
|
||||
{
|
||||
//Scale down any images larger than 128 on either dimension
|
||||
if (originalImage.height() > maxPreviewDim || originalImage.width() > maxPreviewDim)
|
||||
{
|
||||
processedImage = originalImage.scaled(maxPreviewDim, maxPreviewDim,
|
||||
Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||
finalImage = &processedImage;
|
||||
}
|
||||
else
|
||||
{
|
||||
finalImage = &originalImage;
|
||||
}
|
||||
|
||||
m_preview->setPixmap(QPixmap::fromImage(*finalImage));
|
||||
}
|
||||
// Failed to load image so set the preview to nothing
|
||||
else
|
||||
{
|
||||
m_preview->setPixmap(QPixmap());
|
||||
}
|
||||
}
|
||||
// Nothing valid set preview to nothing
|
||||
else
|
||||
{
|
||||
m_preview->setPixmap(QPixmap());
|
||||
}
|
||||
}
|
||||
|
||||
void PropertyImagePreviewCtrl::UpgradeToDefaultValidator()
|
||||
{
|
||||
DefaultImageValidator* newValidator = new DefaultImageValidator(*m_validator);
|
||||
SetValidator(newValidator);
|
||||
// Track the memory allocated for this validator so its deleted
|
||||
ValidatorBus::Broadcast(
|
||||
&ValidatorBus::Handler::TrackValidator,
|
||||
newValidator);
|
||||
}
|
||||
|
||||
void PropertyImagePreviewCtrl::ConsumeAttribute(AZ::u32 attrib, AzToolsFramework::PropertyAttributeReader* attrValue, const char* debugName)
|
||||
{
|
||||
if (attrib == Attributes::DefaultPath)
|
||||
{
|
||||
AZStd::string path;
|
||||
if (attrValue->Read<AZStd::string>(path))
|
||||
{
|
||||
m_defaultPath = path.data();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PropertyFuncValBrowseEditCtrl::ConsumeAttribute(attrib, attrValue, debugName);
|
||||
}
|
||||
}
|
||||
|
||||
// Handler ///////////////////////////////////////////////////////////////////
|
||||
|
||||
PropertyImagePreviewHandler::PropertyImagePreviewHandler(ValidationHandler* valHdlr)
|
||||
: AzToolsFramework::PropertyHandler<AZStd::string, PropertyImagePreviewCtrl>()
|
||||
, m_validationHandler(valHdlr)
|
||||
{}
|
||||
|
||||
AZ::u32 PropertyImagePreviewHandler::GetHandlerName(void) const
|
||||
{
|
||||
return Handlers::ImagePreview;
|
||||
}
|
||||
|
||||
QWidget* PropertyImagePreviewHandler::CreateGUI(QWidget* pParent)
|
||||
{
|
||||
PropertyImagePreviewCtrl* ctrl = aznew PropertyImagePreviewCtrl(pParent);
|
||||
m_validationHandler->AddValidatorCtrl(ctrl);
|
||||
return ctrl;
|
||||
}
|
||||
|
||||
void PropertyImagePreviewHandler::ConsumeAttribute(PropertyImagePreviewCtrl* GUI, AZ::u32 attrib, AzToolsFramework::PropertyAttributeReader* attrValue, const char* debugName)
|
||||
{
|
||||
//This means we are using this as a default image preview
|
||||
if (attrib == Attributes::PropertyIdentfier)
|
||||
{
|
||||
AZStd::string ident;
|
||||
if (attrValue->Read<AZStd::string>(ident))
|
||||
{
|
||||
GUI->UpgradeToDefaultValidator();
|
||||
m_identToCtrl.insert(AZStd::pair<AZStd::string, PropertyImagePreviewCtrl*>(ident, GUI));
|
||||
}
|
||||
}
|
||||
else if (attrib == Attributes::DefaultImagePreview)
|
||||
{
|
||||
AZStd::string ident;
|
||||
if (attrValue->Read<AZStd::string>(ident))
|
||||
{
|
||||
auto defaultPreview = m_identToCtrl.find(ident);
|
||||
if (defaultPreview != m_identToCtrl.end())
|
||||
{
|
||||
defaultPreview->second->AddOverrideToValidator(GUI);
|
||||
GUI->SetDefaultImagePreview(defaultPreview->second);
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Assert(false, "Default image select \"%s\" not found.", ident.data());
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GUI->ConsumeAttribute(attrib, attrValue, debugName);
|
||||
}
|
||||
}
|
||||
|
||||
void PropertyImagePreviewHandler::WriteGUIValuesIntoProperty([[maybe_unused]] size_t index, PropertyImagePreviewCtrl* GUI, property_t& instance, [[maybe_unused]] AzToolsFramework::InstanceDataNode* node)
|
||||
{
|
||||
instance = GUI->GetValue().toUtf8().data();
|
||||
}
|
||||
|
||||
bool PropertyImagePreviewHandler::ReadValuesIntoGUI([[maybe_unused]] size_t index, PropertyImagePreviewCtrl* GUI, const property_t& instance, [[maybe_unused]] AzToolsFramework::InstanceDataNode* node)
|
||||
{
|
||||
GUI->SetValue(instance.data());
|
||||
GUI->ForceValidate();
|
||||
return true;
|
||||
}
|
||||
|
||||
PropertyImagePreviewHandler* PropertyImagePreviewHandler::Register(ValidationHandler* valHdlr)
|
||||
{
|
||||
PropertyImagePreviewHandler* handler = aznew PropertyImagePreviewHandler(valHdlr);
|
||||
AzToolsFramework::PropertyTypeRegistrationMessages::Bus::Broadcast(
|
||||
&AzToolsFramework::PropertyTypeRegistrationMessages::Bus::Handler::RegisterPropertyType,
|
||||
handler);
|
||||
return handler;
|
||||
}
|
||||
} // namespace ProjectSettingsTool
|
||||
|
||||
#include <moc_PropertyImagePreview.cpp>
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include "PropertyFileSelect.h"
|
||||
|
||||
#include <AzCore/base.h>
|
||||
#include <AzCore/std/containers/unordered_map.h>
|
||||
#include <QLabel>
|
||||
#endif
|
||||
|
||||
// Forward Declaration
|
||||
class QValidator;
|
||||
|
||||
namespace ProjectSettingsTool
|
||||
{
|
||||
// Forward Declaration
|
||||
class ValidationHandler;
|
||||
|
||||
// Used to select a png image from a file dialog then display it
|
||||
class PropertyImagePreviewCtrl
|
||||
: public PropertyFuncValBrowseEditCtrl
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
PropertyImagePreviewCtrl(QWidget* parent = nullptr);
|
||||
|
||||
// Sets path for the image preview
|
||||
void SetValue(const QString& path) override;
|
||||
// Returns path for the default image preview
|
||||
const QString& DefaultImagePath() const;
|
||||
// Sets path for the default image preview
|
||||
void SetDefaultImagePath(const QString& newPath);
|
||||
// Sets the default image preview control to use for image previews
|
||||
void SetDefaultImagePreview(PropertyImagePreviewCtrl* imageSelect);
|
||||
// Returns current default image select control pointer
|
||||
PropertyImagePreviewCtrl* DefaultImagePreview() const;
|
||||
// Add a specific image override to the default image selects validator
|
||||
void AddOverrideToValidator(PropertyImagePreviewCtrl* preview);
|
||||
// Loads a preview of the image at the current path or default if path isEmpty
|
||||
void LoadPreview();
|
||||
// Upgrades the Validator to a DefaultImageValidator
|
||||
void UpgradeToDefaultValidator();
|
||||
|
||||
virtual void ConsumeAttribute(AZ::u32 attrib, AzToolsFramework::PropertyAttributeReader* attrValue, const char* debugName) override;
|
||||
|
||||
protected:
|
||||
AZ_DISABLE_COPY_MOVE(PropertyImagePreviewCtrl);
|
||||
|
||||
void emitSelectClicked();
|
||||
|
||||
// Default image select to use
|
||||
PropertyImagePreviewCtrl* m_defaultImagePreview;
|
||||
// Full Path to default image preview
|
||||
QString m_defaultPath;
|
||||
// Displays the image preview
|
||||
QLabel* m_preview;
|
||||
};
|
||||
|
||||
class PropertyImagePreviewHandler
|
||||
: public AzToolsFramework::PropertyHandler<AZStd::string, PropertyImagePreviewCtrl>
|
||||
{
|
||||
AZ_CLASS_ALLOCATOR(PropertyImagePreviewHandler, AZ::SystemAllocator, 0);
|
||||
|
||||
public:
|
||||
PropertyImagePreviewHandler(ValidationHandler* valHdlr);
|
||||
|
||||
AZ::u32 GetHandlerName(void) const override;
|
||||
// Need to unregister ourselves
|
||||
bool AutoDelete() const override { return false; }
|
||||
|
||||
QWidget* CreateGUI(QWidget* pParent) override;
|
||||
void ConsumeAttribute(PropertyImagePreviewCtrl* GUI, AZ::u32 attrib, AzToolsFramework::PropertyAttributeReader* attrValue, const char* debugName) override;
|
||||
void WriteGUIValuesIntoProperty(size_t index, PropertyImagePreviewCtrl* GUI, property_t& instance, AzToolsFramework::InstanceDataNode* node) override;
|
||||
bool ReadValuesIntoGUI(size_t index, PropertyImagePreviewCtrl* GUI, const property_t& instance, AzToolsFramework::InstanceDataNode* node) override;
|
||||
static PropertyImagePreviewHandler* Register(ValidationHandler* valHdlr);
|
||||
|
||||
private:
|
||||
AZStd::unordered_map<AZStd::string, PropertyImagePreviewCtrl*> m_identToCtrl;
|
||||
ValidationHandler* m_validationHandler;
|
||||
};
|
||||
} // namespace ProjectSettingsTool
|
||||
|
||||
@@ -0,0 +1,333 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ProjectSettingsTool_precompiled.h"
|
||||
#include "PropertyLinked.h"
|
||||
|
||||
#include "PlatformSettings_common.h"
|
||||
#include "ValidationHandler.h"
|
||||
|
||||
#include <QLayout>
|
||||
#include <QPushButton>
|
||||
#include <QLineEdit>
|
||||
|
||||
namespace ProjectSettingsTool
|
||||
{
|
||||
PropertyLinkedCtrl::PropertyLinkedCtrl(QWidget* pParent)
|
||||
: PropertyFuncValLineEditCtrl(pParent)
|
||||
, m_linkButton(nullptr)
|
||||
, m_linkedProperty(nullptr)
|
||||
, m_linkEnabled(false)
|
||||
{
|
||||
connect(this, &PropertyFuncValLineEditCtrl::ValueChangedByUser, this, &PropertyLinkedCtrl::MirrorToLinkedProperty);
|
||||
}
|
||||
|
||||
void PropertyLinkedCtrl::SetLinkedProperty(PropertyLinkedCtrl* property)
|
||||
{
|
||||
m_linkedProperty = property;
|
||||
m_linkEnabled = true;
|
||||
}
|
||||
|
||||
void PropertyLinkedCtrl::SetLinkTooltip(const QString& tip)
|
||||
{
|
||||
if (m_linkButton != nullptr)
|
||||
{
|
||||
m_linkButton->setToolTip("Linked to " + tip);
|
||||
}
|
||||
}
|
||||
|
||||
void PropertyLinkedCtrl::MakeLinkButton()
|
||||
{
|
||||
QLayout* myLayout = layout();
|
||||
QIcon icon;
|
||||
icon.addFile("://link.svg", QSize(), QIcon::Normal, QIcon::On);
|
||||
icon.addFile("://broken_link.svg", QSize(), QIcon::Normal, QIcon::Off);
|
||||
|
||||
m_linkButton = new QPushButton(this);
|
||||
m_linkButton->setIcon(icon);
|
||||
m_linkButton->setCheckable(true);
|
||||
m_linkButton->setFlat(true);
|
||||
m_linkButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||
m_linkButton->setFixedSize(QSize(16, 16));
|
||||
m_linkButton->setContentsMargins(0, 0, 0, 0);
|
||||
m_linkButton->setToolTip("Linked to...");
|
||||
myLayout->addWidget(m_linkButton);
|
||||
|
||||
connect(m_linkButton, &QPushButton::clicked, this, &PropertyLinkedCtrl::MirrorLinkButtonState);
|
||||
}
|
||||
|
||||
bool PropertyLinkedCtrl::LinkIsOptional()
|
||||
{
|
||||
return m_linkButton;
|
||||
}
|
||||
|
||||
void PropertyLinkedCtrl::SetOptionalLink(bool linked)
|
||||
{
|
||||
m_linkButton->setChecked(linked);
|
||||
}
|
||||
|
||||
void PropertyLinkedCtrl::MirrorToLinkedProperty()
|
||||
{
|
||||
if (m_linkEnabled && m_linkedProperty != nullptr)
|
||||
{
|
||||
m_linkedProperty->MirrorToLinkedPropertyRecursive(this, m_pLineEdit->text());
|
||||
}
|
||||
}
|
||||
|
||||
void PropertyLinkedCtrl::MirrorToLinkedPropertyRecursive(PropertyLinkedCtrl* caller, const QString& value)
|
||||
{
|
||||
if (caller != this)
|
||||
{
|
||||
if (m_linkButton == nullptr || m_linkButton->isChecked())
|
||||
{
|
||||
// Stop Property from mirroring again
|
||||
m_linkEnabled = false;
|
||||
m_pLineEdit->setText(value);
|
||||
m_linkEnabled = true;
|
||||
}
|
||||
if (m_linkedProperty != nullptr)
|
||||
{
|
||||
m_linkedProperty->MirrorToLinkedPropertyRecursive(caller, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PropertyLinkedCtrl::MirrorLinkButtonState(bool checked)
|
||||
{
|
||||
if (m_linkedProperty != nullptr)
|
||||
{
|
||||
m_linkedProperty->MirrorLinkButtonStateRecursive(this, checked);
|
||||
|
||||
// Mirror value of property linked was enabled on to all linked fields
|
||||
if (checked)
|
||||
{
|
||||
MirrorToLinkedProperty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PropertyLinkedCtrl::MirrorLinkButtonStateRecursive(PropertyLinkedCtrl* caller, bool state)
|
||||
{
|
||||
if (caller != this)
|
||||
{
|
||||
if (m_linkButton != nullptr)
|
||||
{
|
||||
m_linkButton->setChecked(state);
|
||||
}
|
||||
if (m_linkedProperty != nullptr)
|
||||
{
|
||||
m_linkedProperty->MirrorLinkButtonStateRecursive(caller, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool PropertyLinkedCtrl::AllLinkedPropertiesEqual()
|
||||
{
|
||||
if (m_linkedProperty != nullptr)
|
||||
{
|
||||
return m_linkedProperty->AllLinkedPropertiesEqual(this, m_pLineEdit->text());
|
||||
}
|
||||
// No linked property so must be equal
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool PropertyLinkedCtrl::AllLinkedPropertiesEqual(PropertyLinkedCtrl* caller, const QString& value)
|
||||
{
|
||||
if (caller != this)
|
||||
{
|
||||
// Not equal
|
||||
if (m_pLineEdit->text() != value)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (m_linkedProperty != nullptr)
|
||||
{
|
||||
return m_linkedProperty->AllLinkedPropertiesEqual(caller, value);
|
||||
}
|
||||
// All checked properties were equal
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// All properties were equal
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void PropertyLinkedCtrl::SetLinkEnabled(bool enabled)
|
||||
{
|
||||
m_linkEnabled = enabled;
|
||||
}
|
||||
|
||||
void PropertyLinkedCtrl::ConsumeAttribute(AZ::u32 attrib, AzToolsFramework::PropertyAttributeReader* attrValue, const char* debugName)
|
||||
{
|
||||
if (attrib == Attributes::LinkOptional && m_linkButton == nullptr)
|
||||
{
|
||||
bool optional = false;
|
||||
if (attrValue->Read<bool>(optional) && optional)
|
||||
{
|
||||
MakeLinkButton();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PropertyFuncValLineEditCtrl::ConsumeAttribute(attrib, attrValue, debugName);
|
||||
}
|
||||
}
|
||||
|
||||
// Handler ///////////////////////////////////////////////////////////////////
|
||||
|
||||
PropertyLinkedHandler::PropertyLinkedHandler(ValidationHandler* valHdlr)
|
||||
: AzToolsFramework::PropertyHandler<AZStd::string, PropertyLinkedCtrl>()
|
||||
, m_validationHandler(valHdlr)
|
||||
{}
|
||||
|
||||
AZ::u32 PropertyLinkedHandler::GetHandlerName(void) const
|
||||
{
|
||||
return Handlers::LinkedLineEdit;
|
||||
}
|
||||
|
||||
QWidget* PropertyLinkedHandler::CreateGUI(QWidget* pParent)
|
||||
{
|
||||
PropertyLinkedCtrl* ctrl = aznew PropertyLinkedCtrl(pParent);
|
||||
m_validationHandler->AddValidatorCtrl(ctrl);
|
||||
return ctrl;
|
||||
}
|
||||
|
||||
void PropertyLinkedHandler::ConsumeAttribute(PropertyLinkedCtrl* GUI, AZ::u32 attrib, AzToolsFramework::PropertyAttributeReader* attrValue, const char* debugName)
|
||||
{
|
||||
if (attrib == Attributes::PropertyIdentfier)
|
||||
{
|
||||
AZStd::string ident;
|
||||
if (attrValue->Read<AZStd::string>(ident))
|
||||
{
|
||||
m_identToCtrl.insert(AZStd::pair<AZStd::string, PropertyLinkedCtrl*>(ident, GUI));
|
||||
|
||||
auto result = m_ctrlToIdentAndLink.find(GUI);
|
||||
if (result != m_ctrlToIdentAndLink.end())
|
||||
{
|
||||
result->second.identifier = ident;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ctrlToIdentAndLink.insert(AZStd::pair<PropertyLinkedCtrl*, IdentAndLink>(GUI, IdentAndLink{ ident, "" }));
|
||||
m_ctrlInitOrder.push_back(GUI);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (attrib == Attributes::LinkedProperty)
|
||||
{
|
||||
AZStd::string linked;
|
||||
if (attrValue->Read<AZStd::string>(linked))
|
||||
{
|
||||
auto result = m_ctrlToIdentAndLink.find(GUI);
|
||||
if (result != m_ctrlToIdentAndLink.end())
|
||||
{
|
||||
result->second.linkedIdentifier = linked;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ctrlToIdentAndLink.insert(AZStd::pair<PropertyLinkedCtrl*, IdentAndLink>(GUI, IdentAndLink{ "", linked }));
|
||||
m_ctrlInitOrder.push_back(GUI);
|
||||
}
|
||||
|
||||
GUI->SetLinkTooltip(linked.data());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GUI->ConsumeAttribute(attrib, attrValue, debugName);
|
||||
}
|
||||
}
|
||||
|
||||
void PropertyLinkedHandler::WriteGUIValuesIntoProperty([[maybe_unused]] size_t index, PropertyLinkedCtrl* GUI, property_t& instance, [[maybe_unused]] AzToolsFramework::InstanceDataNode* node)
|
||||
{
|
||||
instance = GUI->GetValue().toUtf8().data();
|
||||
}
|
||||
|
||||
bool PropertyLinkedHandler::ReadValuesIntoGUI([[maybe_unused]] size_t index, PropertyLinkedCtrl* GUI, const property_t& instance, [[maybe_unused]] AzToolsFramework::InstanceDataNode* node)
|
||||
{
|
||||
GUI->SetValue(instance.data());
|
||||
GUI->ForceValidate();
|
||||
return true;
|
||||
}
|
||||
|
||||
PropertyLinkedHandler* PropertyLinkedHandler::Register(ValidationHandler* valHdlr)
|
||||
{
|
||||
PropertyLinkedHandler* handler = aznew PropertyLinkedHandler(valHdlr);
|
||||
AzToolsFramework::PropertyTypeRegistrationMessages::Bus::Broadcast(
|
||||
&AzToolsFramework::PropertyTypeRegistrationMessages::Bus::Handler::RegisterPropertyType,
|
||||
handler);
|
||||
return handler;
|
||||
}
|
||||
|
||||
void PropertyLinkedHandler::LinkAllProperties()
|
||||
{
|
||||
// Link all the properties
|
||||
for (PropertyLinkedCtrl* ctrlPointer : m_ctrlInitOrder)
|
||||
{
|
||||
auto property = m_ctrlToIdentAndLink.find(ctrlPointer);
|
||||
auto link = m_identToCtrl.find(property->second.linkedIdentifier);
|
||||
if (link != m_identToCtrl.end())
|
||||
{
|
||||
property->first->SetLinkedProperty(link->second);
|
||||
//Force mirror non-optional links.
|
||||
property->first->MirrorToLinkedProperty();
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Assert(false, "Property \"%s\" not found while linking to \"%s\".", property->second.linkedIdentifier.data(), property->second.identifier.data());
|
||||
}
|
||||
}
|
||||
// Enable optional links if all properties in link chain are the same value
|
||||
EnableOptionalLinksIfAllPropertiesEqual();
|
||||
}
|
||||
|
||||
void PropertyLinkedHandler::EnableOptionalLinksIfAllPropertiesEqual()
|
||||
{
|
||||
// Enable optional links if all properties in link chain are the same value
|
||||
for (const AZStd::pair<PropertyLinkedCtrl*, IdentAndLink>& property : m_ctrlToIdentAndLink)
|
||||
{
|
||||
if (property.first->LinkIsOptional())
|
||||
{
|
||||
property.first->SetOptionalLink(property.first->AllLinkedPropertiesEqual());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PropertyLinkedHandler::MirrorAllLinkedProperties()
|
||||
{
|
||||
for (PropertyLinkedCtrl* ctrlPointer : m_ctrlInitOrder)
|
||||
{
|
||||
ctrlPointer->MirrorToLinkedProperty();
|
||||
}
|
||||
}
|
||||
|
||||
void PropertyLinkedHandler::DisableAllPropertyLinks()
|
||||
{
|
||||
for (PropertyLinkedCtrl* ctrlPointer : m_ctrlInitOrder)
|
||||
{
|
||||
ctrlPointer->SetLinkEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
void PropertyLinkedHandler::EnableAllPropertyLinks()
|
||||
{
|
||||
for (PropertyLinkedCtrl* ctrlPointer : m_ctrlInitOrder)
|
||||
{
|
||||
ctrlPointer->SetLinkEnabled(true);
|
||||
}
|
||||
}
|
||||
} // namespace ProjectSettingsTool
|
||||
|
||||
#include <moc_PropertyLinked.cpp>
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include "PropertyFuncValLineEdit.h"
|
||||
|
||||
#include <AzCore/std/containers/unordered_map.h>
|
||||
#endif
|
||||
|
||||
// Forward declares
|
||||
class QPushButton;
|
||||
|
||||
namespace ProjectSettingsTool
|
||||
{
|
||||
// Forward declare
|
||||
class ValidationHandler;
|
||||
|
||||
class PropertyLinkedCtrl
|
||||
: public PropertyFuncValLineEditCtrl
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
typedef QString(* FileSelectFuncType)(const QString&);
|
||||
|
||||
PropertyLinkedCtrl(QWidget* pParent = nullptr);
|
||||
|
||||
// Set property this will mirror its values to
|
||||
void SetLinkedProperty(PropertyLinkedCtrl* property);
|
||||
// Set the tooltip on the link button so the user can see what property this is linked to
|
||||
void SetLinkTooltip(const QString& tip);
|
||||
// Returns true if all linked properties are equal
|
||||
bool AllLinkedPropertiesEqual();
|
||||
// Returns true if links are optional on this
|
||||
bool LinkIsOptional();
|
||||
// Set the option link state to given bool
|
||||
void SetOptionalLink(bool linked);
|
||||
// Tries to mirror the value to all linked properties
|
||||
void MirrorToLinkedProperty();
|
||||
// Enabled/disables link regardless of type
|
||||
void SetLinkEnabled(bool enabled);
|
||||
|
||||
void ConsumeAttribute(AZ::u32 attrib, AzToolsFramework::PropertyAttributeReader* attrValue, const char* debugName) override;
|
||||
|
||||
protected:
|
||||
void MakeLinkButton();
|
||||
void MirrorToLinkedPropertyRecursive(PropertyLinkedCtrl* caller, const QString& value);
|
||||
// Tries to mirror the link button state to all linked properties
|
||||
void MirrorLinkButtonState(bool checked);
|
||||
void MirrorLinkButtonStateRecursive(PropertyLinkedCtrl* caller, bool state);
|
||||
// Returns true if all linked properties are equal
|
||||
bool AllLinkedPropertiesEqual(PropertyLinkedCtrl* caller, const QString& value);
|
||||
|
||||
QPushButton* m_linkButton;
|
||||
PropertyLinkedCtrl* m_linkedProperty;
|
||||
bool m_linkEnabled;
|
||||
};
|
||||
|
||||
class PropertyLinkedHandler
|
||||
: public AzToolsFramework::PropertyHandler<AZStd::string, PropertyLinkedCtrl>
|
||||
{
|
||||
AZ_CLASS_ALLOCATOR(PropertyLinkedHandler, AZ::SystemAllocator, 0);
|
||||
|
||||
public:
|
||||
PropertyLinkedHandler(ValidationHandler* valHdlr);
|
||||
|
||||
AZ::u32 GetHandlerName(void) const override;
|
||||
// Need to unregister ourselves
|
||||
bool AutoDelete() const override { return false; }
|
||||
|
||||
QWidget* CreateGUI(QWidget* pParent) override;
|
||||
void ConsumeAttribute(PropertyLinkedCtrl* GUI, AZ::u32 attrib, AzToolsFramework::PropertyAttributeReader* attrValue, const char* debugName) override;
|
||||
void WriteGUIValuesIntoProperty(size_t index, PropertyLinkedCtrl* GUI, property_t& instance, AzToolsFramework::InstanceDataNode* node) override;
|
||||
bool ReadValuesIntoGUI(size_t index, PropertyLinkedCtrl* GUI, const property_t& instance, AzToolsFramework::InstanceDataNode* node) override;
|
||||
void LinkAllProperties();
|
||||
void EnableOptionalLinksIfAllPropertiesEqual();
|
||||
void MirrorAllLinkedProperties();
|
||||
void DisableAllPropertyLinks();
|
||||
void EnableAllPropertyLinks();
|
||||
static PropertyLinkedHandler* Register(ValidationHandler* valHdlr);
|
||||
|
||||
private:
|
||||
struct IdentAndLink
|
||||
{
|
||||
AZStd::string identifier;
|
||||
AZStd::string linkedIdentifier;
|
||||
};
|
||||
// Map of identifiers to controls
|
||||
AZStd::unordered_map<AZStd::string, PropertyLinkedCtrl*> m_identToCtrl;
|
||||
|
||||
// Map of controls to identifiers and their linked control's identifiers
|
||||
AZStd::unordered_map<PropertyLinkedCtrl*, IdentAndLink> m_ctrlToIdentAndLink;
|
||||
// Keeps track of the order ctrls were initialized
|
||||
AZStd::vector<PropertyLinkedCtrl*> m_ctrlInitOrder;
|
||||
// Tracks all validating properties
|
||||
ValidationHandler* m_validationHandler;
|
||||
};
|
||||
} // namespace ProjectSettingsTool
|
||||
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ProjectSettingsTool_precompiled.h"
|
||||
#include "Utils.h"
|
||||
#include "LastPathBus.h"
|
||||
|
||||
#include <AzCore/IO/SystemFile.h>
|
||||
#include <AzCore/std/algorithm.h>
|
||||
#include <AzCore/Utils/Utils.h>
|
||||
|
||||
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
|
||||
|
||||
#include <QFileDialog>
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
template<typename StringType>
|
||||
void ToUnixPath(StringType& path)
|
||||
{
|
||||
AZStd::replace(path.begin(), path.end(), '\\', '/');
|
||||
}
|
||||
|
||||
template<typename StringType>
|
||||
StringType GetAbsoluteDevRoot()
|
||||
{
|
||||
const char* devRoot = nullptr;
|
||||
AzToolsFramework::AssetSystemRequestBus::BroadcastResult(
|
||||
devRoot,
|
||||
&AzToolsFramework::AssetSystemRequestBus::Handler::GetAbsoluteDevRootFolderPath);
|
||||
|
||||
if (!devRoot)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
StringType devRootString(devRoot);
|
||||
ToUnixPath(devRootString);
|
||||
return devRootString;
|
||||
}
|
||||
|
||||
template<typename StringType>
|
||||
StringType GetAbsoluteProjectRoot()
|
||||
{
|
||||
const char* projectRoot = nullptr;
|
||||
AzToolsFramework::AssetSystemRequestBus::BroadcastResult(
|
||||
projectRoot,
|
||||
&AzToolsFramework::AssetSystemRequestBus::Handler::GetAbsoluteDevGameFolderPath);
|
||||
|
||||
if (!projectRoot)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
StringType projectRootString(projectRoot);
|
||||
ToUnixPath(projectRootString);
|
||||
return projectRootString;
|
||||
}
|
||||
|
||||
template<typename StringType>
|
||||
StringType GetProjectName();
|
||||
|
||||
template<>
|
||||
AZStd::string GetProjectName()
|
||||
{
|
||||
auto projectName = AZ::Utils::GetProjectName();
|
||||
return AZStd::string{projectName.c_str()};
|
||||
}
|
||||
|
||||
template<>
|
||||
QString GetProjectName()
|
||||
{
|
||||
auto projectName = AZ::Utils::GetProjectName();
|
||||
return QString::fromUtf8(projectName.c_str(), aznumeric_cast<int>(projectName.size()));
|
||||
}
|
||||
}
|
||||
|
||||
namespace ProjectSettingsTool
|
||||
{
|
||||
void* ConvertFunctorToVoid(AZStd::pair<QValidator::State, const QString> (*func)(const QString&))
|
||||
{
|
||||
return reinterpret_cast<void*>(func);
|
||||
}
|
||||
|
||||
AZStd::string GetDevRoot()
|
||||
{
|
||||
return GetAbsoluteDevRoot<AZStd::string>();
|
||||
}
|
||||
AZStd::string GetProjectRoot()
|
||||
{
|
||||
return GetAbsoluteProjectRoot<AZStd::string>();
|
||||
}
|
||||
|
||||
AZStd::string GetProjectName()
|
||||
{
|
||||
return ::GetProjectName<AZStd::string>();
|
||||
}
|
||||
|
||||
QString SelectXmlFromFileDialog(const QString& currentFile)
|
||||
{
|
||||
// The selected file must be relative to this path
|
||||
QString defaultPath = GetAbsoluteDevRoot<QString>();
|
||||
QString startPath;
|
||||
|
||||
// Choose the starting path for file dialog
|
||||
if (currentFile != "")
|
||||
{
|
||||
if (currentFile.contains(defaultPath))
|
||||
{
|
||||
startPath = currentFile;
|
||||
}
|
||||
else
|
||||
{
|
||||
startPath = defaultPath + currentFile;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
startPath = defaultPath;
|
||||
}
|
||||
|
||||
QString pickedPath = QFileDialog::getOpenFileName(nullptr, QObject::tr("Select Override"),
|
||||
startPath, QObject::tr("Extensible Markup Language file (*.xml)"));
|
||||
ToUnixPath(pickedPath);
|
||||
|
||||
// Remove the default relative path
|
||||
if (pickedPath.contains(defaultPath))
|
||||
{
|
||||
pickedPath = pickedPath.mid(defaultPath.length());
|
||||
}
|
||||
|
||||
return pickedPath;
|
||||
}
|
||||
|
||||
QString SelectImageFromFileDialog(const QString& currentFile)
|
||||
{
|
||||
QString defaultPath = QStringLiteral("%1Code%2/Resources/").arg(GetAbsoluteDevRoot<QString>(), ::GetProjectName<QString>());
|
||||
|
||||
QString startPath;
|
||||
|
||||
// Choose the starting path for file dialog
|
||||
if (currentFile != "")
|
||||
{
|
||||
if (QDir::isAbsolutePath(currentFile))
|
||||
{
|
||||
startPath = currentFile;
|
||||
}
|
||||
else
|
||||
{
|
||||
startPath = defaultPath + currentFile;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LastPathBus::BroadcastResult(
|
||||
startPath,
|
||||
&LastPathBus::Handler::GetLastImagePath);
|
||||
}
|
||||
|
||||
QString pickedPath = QFileDialog::getOpenFileName(nullptr, QObject::tr("Select Image"),
|
||||
startPath, QObject::tr("Image file (*.png)"));
|
||||
ToUnixPath(pickedPath);
|
||||
|
||||
if (!pickedPath.isEmpty())
|
||||
{
|
||||
LastPathBus::Broadcast(
|
||||
&LastPathBus::Handler::SetLastImagePath,
|
||||
pickedPath.left(pickedPath.lastIndexOf('/')));
|
||||
}
|
||||
|
||||
// Remove the default relative path if it is used
|
||||
if (pickedPath.contains(defaultPath))
|
||||
{
|
||||
pickedPath = pickedPath.mid(defaultPath.length());
|
||||
}
|
||||
|
||||
return pickedPath;
|
||||
}
|
||||
|
||||
AZStd::string GenDefaultImagePath(ImageGroup group, AZStd::string size)
|
||||
{
|
||||
AZStd::string root;
|
||||
// Android
|
||||
if (group <= ImageGroup::AndroidPortrait)
|
||||
{
|
||||
root = GetDevRoot() + "/Code/Tools/Android/ProjectBuilder/app_";
|
||||
}
|
||||
//Ios
|
||||
else
|
||||
{
|
||||
using AZ::IO::SystemFile;
|
||||
root = GetProjectRoot() + "/Gem/Resources/Platform/iOS/Images.xcassets/";
|
||||
if (!SystemFile::Exists(root.c_str()))
|
||||
{
|
||||
root = GetProjectRoot() + "/Gem/Resources/IOSLauncher/Images.xcassets/";
|
||||
}
|
||||
}
|
||||
|
||||
AZStd::string groupStr;
|
||||
switch (group)
|
||||
{
|
||||
case ImageGroup::AndroidIcons:
|
||||
groupStr = "icon-";
|
||||
break;
|
||||
case ImageGroup::AndroidLandscape:
|
||||
groupStr = "splash-land-";
|
||||
break;
|
||||
case ImageGroup::AndroidPortrait:
|
||||
groupStr = "splash-port-";
|
||||
break;
|
||||
case ImageGroup::IosIcons:
|
||||
groupStr = "AppIcon.appiconset/";
|
||||
break;
|
||||
case ImageGroup::IosLaunchScreens:
|
||||
groupStr = "LaunchImage.launchimage/";
|
||||
break;
|
||||
default:
|
||||
AZ_Assert(false, "Unknown ImageGroup.");
|
||||
break;
|
||||
}
|
||||
|
||||
return root + groupStr + size + ".png";
|
||||
}
|
||||
} // namespace ProjectSettingsTool
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
#include <QString>
|
||||
#include <QValidator>
|
||||
|
||||
|
||||
namespace ProjectSettingsTool
|
||||
{
|
||||
void* ConvertFunctorToVoid(AZStd::pair<QValidator::State, const QString>(*func)(const QString&));
|
||||
AZStd::string GetDevRoot();
|
||||
AZStd::string GetProjectRoot();
|
||||
AZStd::string GetProjectName();
|
||||
|
||||
// Open file dialogs for each file type and return the result
|
||||
// CurrentFile is where the dialog opens
|
||||
QString SelectXmlFromFileDialog(const QString& currentFile);
|
||||
QString SelectImageFromFileDialog(const QString& currentFile);
|
||||
|
||||
enum class ImageGroup
|
||||
{
|
||||
AndroidIcons,
|
||||
AndroidLandscape,
|
||||
AndroidPortrait,
|
||||
IosIcons,
|
||||
IosLaunchScreens
|
||||
};
|
||||
|
||||
AZStd::string GenDefaultImagePath(ImageGroup group, AZStd::string size);
|
||||
} // namespace ProjectSettingsTool
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ProjectSettingsTool_precompiled.h"
|
||||
|
||||
#include "ValidationHandler.h"
|
||||
|
||||
#include "PropertyFuncValLineEdit.h"
|
||||
#include "PropertyFuncValBrowseEdit.h"
|
||||
|
||||
namespace ProjectSettingsTool
|
||||
{
|
||||
void ValidationHandler::AddValidatorCtrl(PropertyFuncValLineEditCtrl* ctrl)
|
||||
{
|
||||
m_validators.push_back(ctrl);
|
||||
}
|
||||
|
||||
void ValidationHandler::AddValidatorCtrl(PropertyFuncValBrowseEditCtrl* ctrl)
|
||||
{
|
||||
m_browseEditValidators.push_back(ctrl);
|
||||
}
|
||||
|
||||
bool ValidationHandler::AllValid()
|
||||
{
|
||||
for (PropertyFuncValLineEditCtrl* ctrl : m_validators)
|
||||
{
|
||||
if (!ctrl->ValidateAndShowErrors())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (PropertyFuncValBrowseEditCtrl* ctrl : m_browseEditValidators)
|
||||
{
|
||||
if (!ctrl->ValidateAndShowErrors())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace ProjectSettingsTool
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
|
||||
namespace ProjectSettingsTool
|
||||
{
|
||||
// Forward Declare
|
||||
class PropertyFuncValLineEditCtrl;
|
||||
class PropertyFuncValBrowseEditCtrl;
|
||||
|
||||
class ValidationHandler
|
||||
{
|
||||
public:
|
||||
void AddValidatorCtrl(PropertyFuncValLineEditCtrl* ctrl);
|
||||
void AddValidatorCtrl(PropertyFuncValBrowseEditCtrl* ctrl);
|
||||
bool AllValid();
|
||||
private:
|
||||
AZStd::vector<PropertyFuncValLineEditCtrl*> m_validators;
|
||||
AZStd::vector<PropertyFuncValBrowseEditCtrl*> m_browseEditValidators;
|
||||
};
|
||||
} // namespace ProjectSettingsTool
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "FunctorValidator.h"
|
||||
|
||||
#include <AzCore/EBus/EBus.h>
|
||||
|
||||
namespace ProjectSettingsTool
|
||||
{
|
||||
class ValidatorTraits
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
using Bus = AZ::EBus<ValidatorTraits>;
|
||||
|
||||
// Bus Configuration
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
|
||||
|
||||
virtual FunctorValidator* GetValidator(FunctorValidator::FunctorType) = 0;
|
||||
virtual void TrackValidator(FunctorValidator*) = 0;
|
||||
};
|
||||
|
||||
typedef AZ::EBus<ValidatorTraits> ValidatorBus;
|
||||
} // namespace ProjectSettingsTool
|
||||
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ProjectSettingsTool_precompiled.h"
|
||||
#include "Validators.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QMimeDatabase>
|
||||
#include <QRegularExpression>
|
||||
|
||||
#define STANDARD_SUCCESS ProjectSettingsTool::FunctorValidator::ReturnType(QValidator::Acceptable, "");
|
||||
|
||||
namespace
|
||||
{
|
||||
typedef ProjectSettingsTool::FunctorValidator::ReturnType RetType;
|
||||
|
||||
static const int noMaxLength = -1;
|
||||
static const int maxIosVersionLength = 18;
|
||||
static const int androidPublicAppKeyLength = 392;
|
||||
static const char* xmlRelativePath = "Code/Tools/RC/Config/rc/";
|
||||
static const char* xmlMimeType = "application/xml";
|
||||
static const char* stringEmpty = "String is empty";
|
||||
|
||||
// Returns true if string is valid android package and apple bundle identifier
|
||||
RetType RegularExpressionValidator(const QString& pattern, const QString& name, int maxLength = noMaxLength)
|
||||
{
|
||||
if (maxLength != noMaxLength && name.length() > maxLength)
|
||||
{
|
||||
return RetType(QValidator::Invalid, QObject::tr("Cannot be longer than %1 characters.")
|
||||
.arg(QString::number(maxLength)));
|
||||
}
|
||||
else if (name.isEmpty())
|
||||
{
|
||||
return RetType(QValidator::Intermediate, QObject::tr(stringEmpty));
|
||||
}
|
||||
|
||||
QRegularExpression regex(pattern);
|
||||
|
||||
QRegularExpressionMatch match = regex.match(name, 0, QRegularExpression::PartialPreferCompleteMatch);
|
||||
|
||||
if (match.hasMatch())
|
||||
{
|
||||
if (match.capturedLength(0) == name.length())
|
||||
{
|
||||
return STANDARD_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
return RetType(QValidator::Intermediate, "Input incorrect.");
|
||||
}
|
||||
}
|
||||
if (match.hasPartialMatch())
|
||||
{
|
||||
return RetType(QValidator::Intermediate, QObject::tr("Partially matches requirements."));
|
||||
}
|
||||
else
|
||||
{
|
||||
return RetType(QValidator::Invalid, QObject::tr("Fails to match requirements at all."));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace ProjectSettingsTool
|
||||
{
|
||||
namespace Validators
|
||||
{
|
||||
namespace Internal
|
||||
{
|
||||
// Returns true if file is readable and the correct mime type
|
||||
RetType FileReadableAndCorrectType(const QString& path, const QString& fileType)
|
||||
{
|
||||
QDir dirPath(path);
|
||||
|
||||
if (dirPath.isReadable())
|
||||
{
|
||||
QMimeDatabase mimeDB;
|
||||
QMimeType mimeType = mimeDB.mimeTypeForFile(path);
|
||||
|
||||
if (mimeType.name() == fileType)
|
||||
{
|
||||
return STANDARD_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
return RetType(QValidator::Intermediate, QObject::tr("File type should be %1, but is %2.")
|
||||
.arg(fileType).arg(mimeType.name()));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return RetType(QValidator::Intermediate, QObject::tr("File is not readable."));
|
||||
}
|
||||
}
|
||||
} // namespace Internal
|
||||
|
||||
|
||||
// Returns true if valid cross platform file or directory name
|
||||
RetType FileName(const QString& name)
|
||||
{
|
||||
// There was a known issue on android with '.' used in directory names
|
||||
// causing problems so it has been omitted from use
|
||||
return RegularExpressionValidator("[\\w,-]+", name);
|
||||
}
|
||||
|
||||
RetType FileNameOrEmpty(const QString& name)
|
||||
{
|
||||
if (IsNotEmpty(name).first == QValidator::Acceptable)
|
||||
{
|
||||
return FileName(name);
|
||||
}
|
||||
else
|
||||
{
|
||||
return STANDARD_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
// Returns true if string isn't empty
|
||||
RetType IsNotEmpty(const QString& value)
|
||||
{
|
||||
if (!value.isEmpty())
|
||||
{
|
||||
return STANDARD_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
return RetType(QValidator::Intermediate, QObject::tr(stringEmpty));
|
||||
}
|
||||
}
|
||||
|
||||
// Returns true if string is valid as a boolean
|
||||
RetType BoolString(const QString& value)
|
||||
{
|
||||
if (value == "true" || value == "false")
|
||||
{
|
||||
return STANDARD_SUCCESS;
|
||||
}
|
||||
|
||||
return RetType(QValidator::Invalid, QObject::tr("Invalid bool string."));
|
||||
}
|
||||
|
||||
// Returns true if string is valid android package and apple bundle identifier
|
||||
RetType PackageName(const QString& name)
|
||||
{
|
||||
return RegularExpressionValidator("[a-zA-Z][A-Za-z0-9]*(\\.[a-zA-Z][A-Za-z0-9]*)+", name);
|
||||
}
|
||||
|
||||
// Returns true if valid android version number
|
||||
RetType VersionNumber(const QString& value)
|
||||
{
|
||||
// Error handling built in already
|
||||
int ver = value.toInt();
|
||||
|
||||
if (0 >= ver)
|
||||
{
|
||||
return RetType(QValidator::Invalid, QObject::tr("Version must be greater than 0."));
|
||||
}
|
||||
else if (ver > maxAndroidVersion)
|
||||
{
|
||||
return RetType(QValidator::Invalid, QObject::tr("Version must be less than or equal to %1.")
|
||||
.arg(QString::number(maxAndroidVersion)));
|
||||
}
|
||||
else
|
||||
{
|
||||
return STANDARD_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
// Returns true if valid ios version number
|
||||
RetType IOSVersionNumber(const QString& value)
|
||||
{
|
||||
return RegularExpressionValidator
|
||||
("(0|[1-9][0-9]{0,8}|[1-2][0-1][0-9]{0,8})(\\.(0|[1-9][0-9]{0,8}|[1-2][0-1][0-9]{0,8})){0,2}",
|
||||
value,
|
||||
maxIosVersionLength);
|
||||
}
|
||||
|
||||
// Returns true if Public App Key is valid length
|
||||
RetType PublicAppKeyOrEmpty(const QString& value)
|
||||
{
|
||||
// If anyone knows that public app keys are not always 392 chars long
|
||||
// then this MUST be changed
|
||||
if (value.isEmpty() || value.length() == androidPublicAppKeyLength)
|
||||
{
|
||||
return STANDARD_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
return RetType(QValidator::Intermediate, QObject::tr("App key should be %1 characters long.")
|
||||
.arg(QString::number(androidPublicAppKeyLength)));
|
||||
}
|
||||
}
|
||||
// Returns true if path is empty or a valid xml file relative to <build dir>
|
||||
RetType ValidXmlOrEmpty(const QString& path)
|
||||
{
|
||||
if (IsNotEmpty(path).first == QValidator::Acceptable)
|
||||
{
|
||||
return Internal::FileReadableAndCorrectType(xmlRelativePath + path, xmlMimeType);
|
||||
}
|
||||
else
|
||||
{
|
||||
return STANDARD_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
// Returns true if path is empty or a valid png file
|
||||
RetType ValidPngOrEmpty(const QString& path)
|
||||
{
|
||||
if (IsNotEmpty(path).first == QValidator::Acceptable)
|
||||
{
|
||||
return Internal::FileReadableAndCorrectType(path, pngMimeType);
|
||||
}
|
||||
else
|
||||
{
|
||||
return STANDARD_SUCCESS;
|
||||
}
|
||||
}
|
||||
} // namespace Validators
|
||||
} // namespace ProjectSettingsTool
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "FunctorValidator.h"
|
||||
|
||||
namespace ProjectSettingsTool
|
||||
{
|
||||
namespace Validators
|
||||
{
|
||||
namespace Internal
|
||||
{
|
||||
// Returns true if file is readable and the correct mime type
|
||||
FunctorValidator::ReturnType FileReadableAndCorrectType(const QString& path, const QString& fileType);
|
||||
}
|
||||
|
||||
static const int maxAndroidVersion = 2100000000;
|
||||
|
||||
// Returns true if valid cross platform file or directory name
|
||||
FunctorValidator::ReturnType FileName(const QString& name);
|
||||
// Returns true if valid cross platform file or directory name or empty
|
||||
FunctorValidator::ReturnType FileNameOrEmpty(const QString& name);
|
||||
// Returns true if string isn't empty
|
||||
FunctorValidator::ReturnType IsNotEmpty(const QString& value);
|
||||
// Returns true if string is valid as a boolean
|
||||
FunctorValidator::ReturnType BoolString(const QString& value);
|
||||
// Returns true if string is valid android package and apple bundle identifier
|
||||
FunctorValidator::ReturnType PackageName(const QString& name);
|
||||
// Returns true if valid android version number
|
||||
FunctorValidator::ReturnType VersionNumber(const QString& value);
|
||||
// Returns true if valid ios version number
|
||||
FunctorValidator::ReturnType IOSVersionNumber(const QString& value);
|
||||
// Returns true if Public App Key is valid length
|
||||
FunctorValidator::ReturnType PublicAppKeyOrEmpty(const QString& value);
|
||||
// Returns true if path is empty or a valid xml file relative to <build dir>
|
||||
FunctorValidator::ReturnType ValidXmlOrEmpty(const QString& path);
|
||||
// Returns true if path is empty or a valid png file
|
||||
FunctorValidator::ReturnType ValidPngOrEmpty(const QString& path);
|
||||
// Returns true if path is empty or valid png file with specified dimensions
|
||||
template <int imageWidth, int imageHeight = imageWidth>
|
||||
FunctorValidator::ReturnType PngImageSetSizeOrEmpty(const QString& path);
|
||||
} // namespace Validators
|
||||
} // namespace ProjectSettingsTool
|
||||
|
||||
#include "Validators_impl.h"
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <QImage>
|
||||
|
||||
namespace ProjectSettingsTool
|
||||
{
|
||||
namespace Validators
|
||||
{
|
||||
static const char* pngMimeType = "image/png";
|
||||
|
||||
// Returns true if path is empty or valid png file with specified dimensions
|
||||
template <int imageWidth, int imageHeight>
|
||||
FunctorValidator::ReturnType PngImageSetSizeOrEmpty(const QString& path)
|
||||
{
|
||||
using RetType = FunctorValidator::ReturnType;
|
||||
|
||||
if (IsNotEmpty(path).first != QValidator::Acceptable)
|
||||
{
|
||||
return FunctorValidator::ReturnType(QValidator::Acceptable, "");
|
||||
}
|
||||
else
|
||||
{
|
||||
RetType correct = Internal::FileReadableAndCorrectType(path, pngMimeType);
|
||||
|
||||
if (correct.first)
|
||||
{
|
||||
QImage image(path);
|
||||
|
||||
if (imageWidth == image.width() && imageHeight == image.height())
|
||||
{
|
||||
return FunctorValidator::ReturnType(QValidator::Acceptable, "");
|
||||
}
|
||||
else
|
||||
{
|
||||
return RetType(QValidator::Intermediate, QObject::tr("Image is not %1x%2 pixels.")
|
||||
.arg(QString::number(imageWidth)).arg(QString::number(imageHeight)));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return correct;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace Validators
|
||||
} // namespace ProjectSettingsTool
|
||||
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="24px" height="24px" viewBox="-4, -4, 28, 28" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>Icons / System / Unlink</title>
|
||||
<g id="All-use-case" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="Use-case---Main-page-" transform="translate(-1296.000000, -310.000000)">
|
||||
<g id="Group" transform="translate(1294.000000, 308.240103)">
|
||||
<rect id="Icon-Background" fill-opacity="0" fill="#D8D8D8" x="0" y="0" width="24" height="24"></rect>
|
||||
<path d="M8.5,8.5 L3,8.5 L3,7 L7,7 L7,3 L8.5,3 L8.5,8.5 Z" id="Combined-Shape" fill="#FFFFFF"></path>
|
||||
<path d="M21,21 L15.5,21 L15.5,19.5 L19.5,19.5 L19.5,15.5 L21,15.5 L21,21 Z" id="Combined-Shape" fill="#FFFFFF" transform="translate(18.250000, 18.250000) rotate(180.000000) translate(-18.250000, -18.250000) "></path>
|
||||
<path d="M21,8.75 L21.25,15 L14.75,15.25 L20.75,14.75 L20.75,9.25 L14.75,9.25 L14.75,8.75 L21,8.75 Z M9.25,8.75 L9.25,9.25 L3.25,9.25 L3.25,14.75 L9.25,14.75 L9.25,15.25 L3,15.25 L2.75,9 L9.25,8.75 Z" id="Link" stroke="#FFFFFF" stroke-width="1.5" transform="translate(12.000000, 12.000000) rotate(-45.000000) translate(-12.000000, -12.000000) "></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:403ee8a94ec2f0ff532c70d2f56e18d7d83cb335a0cc444b1ac88f2fadff45f7
|
||||
size 308
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:e4058789615838100562d84345a5b0fdd7ea5416052105ce0ae2e5a1db13b952
|
||||
size 367
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="24px" height="24px" viewBox="-4 -4 28 28" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>Icons / System / Link</title>
|
||||
<g id="All-use-case" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="Use-case---Main-page-" transform="translate(-1261.000000, -310.000000)">
|
||||
<g id="Group" transform="translate(1259.000000, 308.240103)">
|
||||
<rect id="Icon-Background" fill-opacity="0" fill="#D8D8D8" x="0" y="0" width="24" height="24"></rect>
|
||||
<path d="M21,8.75 L21.25,15 L9.75,15.25 L9.75,12.75 L10.25,12.75 L10.25,14.75 L20.75,14.75 L20.75,9.25 L17.75,9.25 L17.75,8.75 L21,8.75 Z M14.25,8.75 L14.25,11.25 L13.75,11.25 L13.75,9.25 L3.25,9.25 L3.25,14.75 L6.25,14.75 L6.25,15.25 L3,15.25 L2.75,9 L14.25,8.75 Z" id="Link" stroke="#FFFFFF" stroke-width="1.5" transform="translate(12.000000, 12.000000) rotate(-45.000000) translate(-12.000000, -12.000000) "></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
#include "ProjectSettingsTool_precompiled.h"
|
||||
|
||||
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
|
||||
#include <AzToolsFramework/API/ViewPaneOptions.h>
|
||||
|
||||
#include <Include/IPlugin.h>
|
||||
|
||||
#include "ProjectSettingsToolWindow.h"
|
||||
#include "../Editor/LyViewPaneNames.h"
|
||||
|
||||
|
||||
class ProjectSettingsToolPlugin
|
||||
: public IPlugin
|
||||
{
|
||||
public:
|
||||
ProjectSettingsToolPlugin([[maybe_unused]] IEditor* editor)
|
||||
{
|
||||
AzToolsFramework::ViewPaneOptions options;
|
||||
options.showInMenu = false;
|
||||
AzToolsFramework::RegisterViewPane<ProjectSettingsTool::ProjectSettingsToolWindow>(LyViewPane::ProjectSettingsTool, LyViewPane::ProjectSettingsTool, options);
|
||||
}
|
||||
|
||||
void Release() override
|
||||
{
|
||||
AzToolsFramework::UnregisterViewPane(LyViewPane::ProjectSettingsTool);
|
||||
delete this;
|
||||
}
|
||||
|
||||
void ShowAbout() override {}
|
||||
|
||||
const char* GetPluginGUID() override { return "{C5B96A1A-036A-46F9-B7F0-5DF93494F988}"; }
|
||||
DWORD GetPluginVersion() override { return 1; }
|
||||
const char* GetPluginName() override { return "ProjectSettingsTool"; }
|
||||
bool CanExitNow() override { return true; }
|
||||
void OnEditorNotify([[maybe_unused]] EEditorNotifyEvent aEventId) override {}
|
||||
};
|
||||
|
||||
PLUGIN_API IPlugin* CreatePluginInstance(PLUGIN_INIT_PARAM* pInitParam)
|
||||
{
|
||||
ISystem* pSystem = pInitParam->pIEditorInterface->GetSystem();
|
||||
ModuleInitISystem(pSystem, "ProjectSettingsTool");
|
||||
// the above line initializes the gEnv global variable if necessary, and also makes GetIEditor() and other similar functions work correctly.
|
||||
|
||||
return new ProjectSettingsToolPlugin(GetIEditor());
|
||||
}
|
||||
|
||||
#if defined(AZ_PLATFORM_WINDOWS)
|
||||
HINSTANCE g_hInstance = 0;
|
||||
BOOL __stdcall DllMain(HINSTANCE hinstDLL, ULONG fdwReason, [[maybe_unused]] LPVOID lpvReserved)
|
||||
{
|
||||
if (fdwReason == DLL_PROCESS_ATTACH)
|
||||
{
|
||||
g_hInstance = hinstDLL;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,55 @@
|
||||
#
|
||||
# Copyright (c) Contributors to the Open 3D Engine Project
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
#
|
||||
#
|
||||
|
||||
set(FILES
|
||||
main.cpp
|
||||
ProjectSettingsTool_precompiled.h
|
||||
DefaultImageValidator.cpp
|
||||
DefaultImageValidator.h
|
||||
FunctorValidator.cpp
|
||||
FunctorValidator.h
|
||||
LastPathBus.h
|
||||
Platforms.h
|
||||
PlatformSettings.h
|
||||
PlatformSettings_Android.cpp
|
||||
PlatformSettings_Android.h
|
||||
PlatformSettings_Base.cpp
|
||||
PlatformSettings_Base.h
|
||||
PlatformSettings_common.h
|
||||
PlatformSettings_Ios.cpp
|
||||
PlatformSettings_Ios.h
|
||||
PlistDictionary.cpp
|
||||
PlistDictionary.h
|
||||
ProjectSettingsContainer.cpp
|
||||
ProjectSettingsContainer.h
|
||||
ProjectSettingsSerialization.cpp
|
||||
ProjectSettingsSerialization.h
|
||||
ProjectSettingsTool.qrc
|
||||
ProjectSettingsToolWidget.ui
|
||||
ProjectSettingsToolWindow.cpp
|
||||
ProjectSettingsToolWindow.h
|
||||
ProjectSettingsValidator.cpp
|
||||
ProjectSettingsValidator.h
|
||||
PropertyFileSelect.cpp
|
||||
PropertyFileSelect.h
|
||||
PropertyFuncValBrowseEdit.cpp
|
||||
PropertyFuncValBrowseEdit.h
|
||||
PropertyFuncValLineEdit.cpp
|
||||
PropertyFuncValLineEdit.h
|
||||
PropertyImagePreview.cpp
|
||||
PropertyImagePreview.h
|
||||
PropertyLinked.cpp
|
||||
PropertyLinked.h
|
||||
Utils.cpp
|
||||
Utils.h
|
||||
ValidationHandler.cpp
|
||||
ValidationHandler.h
|
||||
ValidatorBus.h
|
||||
Validators.cpp
|
||||
Validators.h
|
||||
Validators_impl.h
|
||||
)
|
||||
Reference in New Issue
Block a user