/* * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or * its licensors. * * For complete copyright and license terms please see the LICENSE at the root of this * distribution (the "License"). All use of this software is governed by the License, * or, if provided, by the license below or the license accompanying this file. Do not * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ #include "ProjectSettingsTool_precompiled.h" #include "PropertyLinked.h" #include "PlatformSettings_common.h" #include "ValidationHandler.h" #include #include 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(optional) && optional) { MakeLinkButton(); } } else { PropertyFuncValLineEditCtrl::ConsumeAttribute(attrib, attrValue, debugName); } } // Handler /////////////////////////////////////////////////////////////////// PropertyLinkedHandler::PropertyLinkedHandler(ValidationHandler* valHdlr) : AzToolsFramework::PropertyHandler() , 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(ident)) { m_identToCtrl.insert(AZStd::pair(ident, GUI)); auto result = m_ctrlToIdentAndLink.find(GUI); if (result != m_ctrlToIdentAndLink.end()) { result->second.identifier = ident; } else { m_ctrlToIdentAndLink.insert(AZStd::pair(GUI, IdentAndLink{ ident, "" })); m_ctrlInitOrder.push_back(GUI); } } } else if (attrib == Attributes::LinkedProperty) { AZStd::string linked; if (attrValue->Read(linked)) { auto result = m_ctrlToIdentAndLink.find(GUI); if (result != m_ctrlToIdentAndLink.end()) { result->second.linkedIdentifier = linked; } else { m_ctrlToIdentAndLink.insert(AZStd::pair(GUI, IdentAndLink{ "", linked })); m_ctrlInitOrder.push_back(GUI); } GUI->SetLinkTooltip(linked.data()); } } else { GUI->ConsumeAttribute(attrib, attrValue, debugName); } } void PropertyLinkedHandler::WriteGUIValuesIntoProperty(size_t index, PropertyLinkedCtrl* GUI, property_t& instance, AzToolsFramework::InstanceDataNode* node) { instance = GUI->GetValue().toUtf8().data(); } bool PropertyLinkedHandler::ReadValuesIntoGUI(size_t index, PropertyLinkedCtrl* GUI, const property_t& instance, 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& 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