SelectedRowPropertiesComponent.cpp (13938B)
1 /*---------------------------------------------------------------------------------------- 2 3 Copyright (c) 2023 AUDIOKINETIC Inc. 4 5 This file is licensed to use under the license available at: 6 https://github.com/audiokinetic/ReaWwise/blob/main/License.txt (the "License"). 7 You may not use this file except in compliance with the License. 8 9 Unless required by applicable law or agreed to in writing, software distributed 10 under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 11 CONDITIONS OF ANY KIND, either express or implied. See the License for the 12 specific language governing permissions and limitations under the License. 13 14 ----------------------------------------------------------------------------------------*/ 15 16 #include "SelectedRowPropertiesComponent.h" 17 18 #include "BinaryData.h" 19 #include "Helpers/ImportHelper.h" 20 #include "Helpers/WwiseHelper.h" 21 #include "Model/IDs.h" 22 #include "Model/Wwise.h" 23 #include "Theme/CustomLookAndFeel.h" 24 25 namespace AK::WwiseTransfer 26 { 27 namespace SelectedRowPropertiesComponentConstants 28 { 29 constexpr int margin = 10; 30 constexpr int spacing = 4; 31 constexpr int bottomMargin = 14; 32 constexpr int labelHeight = 26; 33 constexpr int labelWidth = 170; 34 constexpr int wildcardsButtonWidth = 100; 35 constexpr int syncButtonWidth = 36; 36 constexpr int propertyTemplateToggleButtonWidth = 22; 37 constexpr int lineThickness = 2; 38 constexpr std::initializer_list<Wwise::ObjectType> objectTypes{Wwise::ObjectType::ActorMixer, Wwise::ObjectType::BlendContainer, 39 Wwise::ObjectType::PhysicalFolder, Wwise::ObjectType::RandomContainer, Wwise::ObjectType::SequenceContainer, Wwise::ObjectType::SoundSFX, 40 Wwise::ObjectType::SoundVoice, Wwise::ObjectType::SwitchContainer, Wwise::ObjectType::VirtualFolder, Wwise::ObjectType::WorkUnit}; 41 const juce::String pastePropertiesToolTip = "Paste properties are only available when connected to Wwise 2022+"; 42 } // namespace SelectedRowPropertiesComponentConstants 43 44 SelectedRowPropertiesComponent::SelectedRowPropertiesComponent(juce::ValueTree appState, WaapiClient& waapiClient) 45 : applicationState(appState) 46 , hierarchyMapping(applicationState.getChildWithName(IDs::hierarchyMapping)) 47 , languages(applicationState.getChildWithName(IDs::languages)) 48 , selectedRow(hierarchyMapping, IDs::selectedRow, nullptr) 49 , emptyHierarchyMappingNode(ImportHelper::hierarchyMappingNodeToValueTree(Import::HierarchyMappingNode("", Wwise::ObjectType::Unknown))) 50 , waapiClient(waapiClient) 51 , propertyTemplatePathSyncButton("PropertyTemplatePathSyncButton", juce::Drawable::createFromImageData(BinaryData::General_GetFromWwise_Normal_svg, BinaryData::General_GetFromWwise_Normal_svgSize)) 52 { 53 using namespace SelectedRowPropertiesComponentConstants; 54 55 setText("Selected Row Properties"); 56 57 auto featureSupport = applicationState.getChildWithName(IDs::featureSupport); 58 applyTemplateFeatureEnabled.referTo(featureSupport, IDs::applyTemplateFeatureEnabled, nullptr); 59 60 objectTypeLabel.setText("Object Type", juce::dontSendNotification); 61 objectTypeLabel.setBorderSize(juce::BorderSize(0)); 62 objectTypeLabel.setMinimumHorizontalScale(1.0f); 63 objectTypeLabel.setJustificationType(juce::Justification::right); 64 65 objectNameLabel.setText("Object Name", juce::dontSendNotification); 66 objectNameLabel.setBorderSize(juce::BorderSize(0)); 67 objectNameLabel.setMinimumHorizontalScale(1.0f); 68 objectNameLabel.setJustificationType(juce::Justification::right); 69 70 propertyTemplatePathLabel.setText("Use Property Template", juce::dontSendNotification); 71 propertyTemplatePathLabel.setBorderSize(juce::BorderSize(0)); 72 propertyTemplatePathLabel.setMinimumHorizontalScale(1.0f); 73 propertyTemplatePathLabel.setJustificationType(juce::Justification::right); 74 75 propertyTemplatePathSyncButton.setTooltip("Sync with selected object in Wwise"); 76 77 objectNameEditor.setFont(CustomLookAndFeelConstants::smallFontSize); 78 propertyTemplatePathEditor.setFont(CustomLookAndFeelConstants::smallFontSize); 79 80 objectTypeComboBox.setTextWhenNothingSelected("Select Object Type"); 81 82 for(auto& objectType : objectTypes) 83 objectTypeComboBox.addItem(WwiseHelper::objectTypeToReadableString(objectType), static_cast<int>(objectType)); 84 85 objectLanguageComboBox.setTextWhenNothingSelected("Language"); 86 objectLanguageComboBox.setTextWhenNoChoicesAvailable("No Languages loaded"); 87 88 addAndMakeVisible(objectTypeLabel); 89 addAndMakeVisible(objectNameLabel); 90 addAndMakeVisible(propertyTemplatePathLabel); 91 addAndMakeVisible(objectTypeComboBox); 92 addAndMakeVisible(objectNameEditor); 93 addAndMakeVisible(propertyTemplatePathEditor); 94 addAndMakeVisible(propertyTemplateToggleButton); 95 addAndMakeVisible(wildcardSelector); 96 addAndMakeVisible(propertyTemplatePathSyncButton); 97 addChildComponent(objectLanguageComboBox); 98 99 refreshComponent(); 100 101 objectTypeComboBox.onChange = [this] 102 { 103 objectType = static_cast<Wwise::ObjectType>(objectTypeComboBox.getSelectedId()); 104 }; 105 106 wildcardSelector.onItemSelected = [this](const juce::String& wildcard) 107 { 108 objectName = objectName + wildcard; 109 }; 110 111 propertyTemplatePathSyncButton.onClick = [this] 112 { 113 updatePropertyTemplatePath(); 114 }; 115 116 objectLanguageComboBox.onChange = [this] 117 { 118 objectLanguage = objectLanguageComboBox.getText(); 119 }; 120 121 applicationState.addListener(this); 122 } 123 124 SelectedRowPropertiesComponent::~SelectedRowPropertiesComponent() 125 { 126 applicationState.removeListener(this); 127 } 128 129 void SelectedRowPropertiesComponent::refreshComponent() 130 { 131 hierarchyMappingNode = selectedRow >= 0 ? hierarchyMapping.getChild(selectedRow) : emptyHierarchyMappingNode; 132 133 objectName.referTo(hierarchyMappingNode, IDs::objectName, nullptr); 134 objectNameValid.referTo(hierarchyMappingNode, IDs::objectNameValid, nullptr); 135 objectNameErrorMessage.referTo(hierarchyMappingNode, IDs::objectNameErrorMessage, nullptr); 136 objectType.referTo(hierarchyMappingNode, IDs::objectType, nullptr); 137 138 objectLanguage.referTo(hierarchyMappingNode, IDs::objectLanguage, nullptr); 139 140 propertyTemplatePath.referTo(hierarchyMappingNode, IDs::propertyTemplatePath, nullptr); 141 propertyTemplatePathEnabled.referTo(hierarchyMappingNode, IDs::propertyTemplatePathEnabled, nullptr); 142 propertyTemplatePathValid.referTo(hierarchyMappingNode, IDs::propertyTemplatePathValid, nullptr); 143 propertyTemplatePathType.referTo(hierarchyMappingNode, IDs::propertyTemplatePathType, nullptr); 144 145 // Bind components that support cached value binding 146 objectNameEditor.getTextValue().referTo(objectName.getPropertyAsValue()); 147 objectNameEditor.getValidationValue().referTo(objectNameValid.getPropertyAsValue()); 148 objectNameEditor.getErrorMessageValue().referTo(objectNameErrorMessage.getPropertyAsValue()); 149 objectTypeComboBox.getSelectedIdAsValue().referTo(objectType.getPropertyAsValue()); 150 propertyTemplatePathEditor.getTextValue().referTo(propertyTemplatePath.getPropertyAsValue()); 151 propertyTemplatePathEditor.getValidationValue().referTo(propertyTemplatePathValid.getPropertyAsValue()); 152 propertyTemplatePathEditor.getErrorMessageValue().referTo(hierarchyMappingNode.getPropertyAsValue(IDs::propertyTemplatePathErrorMessage, nullptr)); 153 propertyTemplateToggleButton.getToggleStateValue().referTo(propertyTemplatePathEnabled.getPropertyAsValue()); 154 155 updatePropertyTemplateSection(); 156 157 objectLanguageComboBox.setVisible(objectType == Wwise::ObjectType::SoundVoice); 158 objectLanguageComboBox.clear(); 159 160 auto languageList = WwiseHelper::valueTreeToLanguages(languages); 161 for(int i = 0; i < languageList.size(); ++i) 162 { 163 objectLanguageComboBox.addItem(languageList[i], i + 1); 164 if(languageList[i] == objectLanguage) 165 objectLanguageComboBox.setSelectedId(i + 1); 166 } 167 } 168 169 void SelectedRowPropertiesComponent::updatePropertyTemplatePath() 170 { 171 // TODO: show loading state 172 auto onGetSelectedObject = [this](const Waapi::Response<Waapi::ObjectResponse>& response) 173 { 174 if(response.result.path.isEmpty()) 175 return juce::AlertWindow::showMessageBoxAsync(juce::MessageBoxIconType::InfoIcon, "Property Template Path", "No object is selected in Wwise. Please select one and try again."); 176 177 propertyTemplatePath = response.result.path; 178 propertyTemplatePathType = response.result.type; 179 180 // TODO: end loading state 181 }; 182 183 waapiClient.getSelectedObjectAsync(onGetSelectedObject); 184 } 185 186 void SelectedRowPropertiesComponent::updatePropertyTemplateSection() 187 { 188 using namespace SelectedRowPropertiesComponentConstants; 189 190 auto isEnabled = propertyTemplatePathEnabled && applyTemplateFeatureEnabled; 191 192 propertyTemplatePathSyncButton.setEnabled(isEnabled); 193 propertyTemplatePathEditor.setEnabled(isEnabled); 194 propertyTemplatePathEditor.setAlpha(isEnabled ? 1 : 0.5f); 195 propertyTemplatePathEditor.setMouseCursor(isEnabled ? juce::MouseCursor::IBeamCursor : juce::MouseCursor::NormalCursor); 196 197 // Not using isEnabled because these fields depend on propertyTemplatePathEnabled. 198 propertyTemplateToggleButton.setEnabled(applyTemplateFeatureEnabled); 199 propertyTemplatePathLabel.setEnabled(applyTemplateFeatureEnabled); 200 201 propertyTemplatePathEditor.setTooltip(applyTemplateFeatureEnabled ? "" : pastePropertiesToolTip); 202 propertyTemplatePathSyncButton.setTooltip(applyTemplateFeatureEnabled ? "Sync with selected object in Wwise" : pastePropertiesToolTip); 203 propertyTemplateToggleButton.setTooltip(applyTemplateFeatureEnabled ? "" : pastePropertiesToolTip); 204 propertyTemplatePathLabel.setTooltip(applyTemplateFeatureEnabled ? "" : pastePropertiesToolTip); 205 } 206 207 void SelectedRowPropertiesComponent::paint(juce::Graphics& g) 208 { 209 juce::Font f(CustomLookAndFeelConstants::regularFontSize); 210 211 const float textH = f.getHeight(); 212 const float indent = 3.0f; 213 const float textEdgeGap = 4.0f; 214 auto constant = 5.0f; 215 216 auto x = indent; 217 auto y = f.getAscent() - 3.0f; 218 auto w = juce::jmax(0.0f, (float)getWidth() - x * 2.0f); 219 auto h = juce::jmax(0.0f, (float)getHeight() - y - indent); 220 constant = juce::jmin(constant, w * 0.5f, h * 0.5f); 221 auto constant2 = 2.0f * constant; 222 223 auto textW = getText().isEmpty() ? 0 224 : juce::jlimit(0.0f, 225 juce::jmax(0.0f, w - constant2 - textEdgeGap * 2), 226 (float)f.getStringWidth(getText()) + textEdgeGap * 2.0f); 227 auto textX = constant + textEdgeGap; 228 229 juce::Path p; 230 p.startNewSubPath(0, y); 231 p.lineTo(constant2, y); 232 233 p.startNewSubPath(x + textX + textW, y); 234 p.lineTo(x + w, y); 235 236 auto alpha = 1.0f; 237 238 g.setColour(findColour(juce::GroupComponent::outlineColourId) 239 .withMultipliedAlpha(alpha)); 240 241 g.strokePath(p, juce::PathStrokeType(2.0f)); 242 243 g.setColour(findColour(juce::GroupComponent::textColourId) 244 .withMultipliedAlpha(alpha)); 245 246 g.setFont(f); 247 248 g.drawText(getText(), 249 juce::roundToInt(x + textX), 0, 250 juce::roundToInt(textW), 251 juce::roundToInt(textH), 252 juce::Justification::centred, true); 253 } 254 255 void SelectedRowPropertiesComponent::resized() 256 { 257 using namespace SelectedRowPropertiesComponentConstants; 258 259 auto area = getLocalBounds(); 260 area.removeFromTop(labelHeight); 261 262 auto objectTypeArea = area.removeFromTop(labelHeight); 263 { 264 objectTypeLabel.setBounds(objectTypeArea.removeFromLeft(labelWidth)); 265 266 objectLanguageComboBox.setBounds(objectTypeArea.removeFromRight(wildcardsButtonWidth)); 267 268 objectTypeArea.removeFromRight(spacing); 269 270 objectTypeArea.removeFromLeft(margin); 271 objectTypeComboBox.setBounds(objectTypeArea); 272 } 273 274 area.removeFromTop(margin); 275 276 auto objectNameArea = area.removeFromTop(labelHeight); 277 { 278 objectNameLabel.setBounds(objectNameArea.removeFromLeft(labelWidth)); 279 280 wildcardSelector.setBounds(objectNameArea.removeFromRight(wildcardsButtonWidth)); 281 objectNameArea.removeFromRight(spacing); 282 283 objectNameArea.removeFromLeft(margin); 284 objectNameEditor.setBounds(objectNameArea); 285 } 286 287 area.removeFromTop(margin); 288 289 auto propertyTemplatePathArea = area.removeFromTop(labelHeight); 290 { 291 propertyTemplateToggleButton.setBounds(propertyTemplatePathArea.removeFromLeft(propertyTemplateToggleButtonWidth)); 292 propertyTemplatePathLabel.setBounds(propertyTemplatePathArea.removeFromLeft(labelWidth - propertyTemplateToggleButtonWidth)); 293 294 propertyTemplatePathArea.removeFromRight(wildcardsButtonWidth - syncButtonWidth); 295 propertyTemplatePathSyncButton.setBounds(propertyTemplatePathArea.removeFromRight(syncButtonWidth)); 296 propertyTemplatePathArea.removeFromRight(spacing); 297 298 propertyTemplatePathArea.removeFromLeft(margin); 299 propertyTemplatePathEditor.setBounds(propertyTemplatePathArea); 300 } 301 } 302 303 void SelectedRowPropertiesComponent::valueTreePropertyChanged(juce::ValueTree& treeWhosePropertyHasChanged, const juce::Identifier& property) 304 { 305 auto treeType = treeWhosePropertyHasChanged.getType(); 306 307 if(treeType == IDs::hierarchyMapping && property == IDs::selectedRow || 308 treeType == IDs::hierarchyMappingNode && (property == IDs::objectType || property == IDs::propertyTemplatePathEnabled) || 309 treeType == IDs::featureSupport && property == IDs::applyTemplateFeatureEnabled) 310 { 311 triggerAsyncUpdate(); 312 } 313 } 314 315 void SelectedRowPropertiesComponent::valueTreeChildAdded(juce::ValueTree& parentTree, juce::ValueTree& childWhichHasBeenAdded) 316 { 317 auto treeType = parentTree.getType(); 318 319 if(treeType == IDs::hierarchyMapping || treeType == IDs::languages) 320 { 321 triggerAsyncUpdate(); 322 } 323 } 324 325 void SelectedRowPropertiesComponent::valueTreeChildRemoved(juce::ValueTree& parentTree, juce::ValueTree& childWhichHasBeenRemoved, int indexFromWhichChildWasRemoved) 326 { 327 if(parentTree.getType() == IDs::hierarchyMapping) 328 { 329 triggerAsyncUpdate(); 330 } 331 } 332 333 void SelectedRowPropertiesComponent::valueTreeChildOrderChanged(juce::ValueTree& parentTreeWhoseChildrenHaveMoved, int oldIndex, int newIndex) 334 { 335 if(parentTreeWhoseChildrenHaveMoved.getType() == IDs::hierarchyMapping) 336 { 337 triggerAsyncUpdate(); 338 } 339 } 340 341 void SelectedRowPropertiesComponent::handleAsyncUpdate() 342 { 343 refreshComponent(); 344 } 345 } // namespace AK::WwiseTransfer