diff --git a/src/WeatherEditor/Weather/WeatherWidget.cpp b/src/WeatherEditor/Weather/WeatherWidget.cpp index ef2d57da7e..cf97c1f16c 100644 --- a/src/WeatherEditor/Weather/WeatherWidget.cpp +++ b/src/WeatherEditor/Weather/WeatherWidget.cpp @@ -1,6 +1,7 @@ #include "WeatherWidget.h" #include +#include #include "imgui_internal.h" @@ -277,9 +278,9 @@ void WeatherWidget::DrawWidget() } Util::AddTooltip(tooltip); }; - auto drawInheritCheckbox = [&](const std::string& inheritKey, auto& recordRef, auto& parentRef) { + auto drawInheritCheckbox = [&](const std::string& inheritKey, auto& recordRef, auto& parentRef) -> bool { if (!hasParent) - return; + return false; bool& inheritFlag = settings.inheritFlags[inheritKey]; ImGui::Checkbox(("##inherit_" + inheritKey).c_str(), &inheritFlag); if (inheritFlag && parentWidget && recordRef != parentRef) { @@ -288,6 +289,7 @@ void WeatherWidget::DrawWidget() } Util::AddTooltip(inheritFlag ? "Inheriting from parent" : "Inherit from parent"); ImGui::SameLine(); + return inheritFlag; }; auto drawTimeRecordSection = [&](const char* sectionLabel, int idOffset, const char* inheritPrefix, auto& recordRefs, auto& parentRefs, auto& widgets, const char* pickerId, const char* openTooltip) { if (!anyTimeRecordMatches(sectionLabel)) @@ -306,12 +308,15 @@ void WeatherWidget::DrawWidget() std::string inheritKey = std::format("{}_{}", inheritPrefix, i); const bool recordHighlighted = pushRecordHighlight(rowId); - drawInheritCheckbox(inheritKey, recordRefs[i], parentRefs[i]); + const bool isInherited = drawInheritCheckbox(inheritKey, recordRefs[i], parentRefs[i]); ImGui::Text("%s:", label.c_str()); ImGui::SameLine(todLabelOffset); + if (isInherited) PushInheritedStyle(); if (WeatherUtils::DrawFormPickerCached(pickerId, recordRefs[i], widgets, false, true, pickerWidth)) { pendingReinit = true; + if (isInherited) settings.inheritFlags[inheritKey] = false; } + if (isInherited) { Util::AddTooltip("Inherited from parent weather"); PopInheritedStyle(); } drawOpenButton(recordRefs[i], widgets, std::format("Open##{}", i), openTooltip); if (recordHighlighted) @@ -329,12 +334,15 @@ void WeatherWidget::DrawWidget() return; const bool recordHighlighted = pushRecordHighlight(recordId); - drawInheritCheckbox(inheritKey, recordRef, parentRef); + const bool isInherited = drawInheritCheckbox(inheritKey, recordRef, parentRef); ImGui::Text("%s:", valueLabel); ImGui::SameLine(formLabelOffset); + if (isInherited) PushInheritedStyle(); if (WeatherUtils::DrawFormPickerCached(pickerId, recordRef, widgets, false, true, pickerWidth)) { pendingReinit = true; + if (isInherited) settings.inheritFlags[inheritKey] = false; } + if (isInherited) { Util::AddTooltip("Inherited from parent weather"); PopInheritedStyle(); } drawOpenButton(recordRef, widgets, buttonId, openTooltip); if (recordHighlighted) @@ -1190,35 +1198,6 @@ void WeatherWidget::DrawFogSettings() if (!anyFogMatches) return; - auto pushFogRowHighlight = [&](const char* dayId, const char* nightId) -> const char* { - if (PushHighlightIfNeeded(dayId)) { - return dayId; - } - if (PushHighlightIfNeeded(nightId)) { - return nightId; - } - return nullptr; - }; - auto popFogRowHighlight = [&](const char* highlightId) { - if (highlightId) - PopHighlightIfNeeded(highlightId, true); - }; - auto inheritFogPair = [&](const char* inheritKey, const char* dayKey, const char* nightKey) { - if (!parentWidget) - return; - if (!settings.inheritFlags[inheritKey]) - return; - - const float parentDay = parentWidget->settings.fogProperties[dayKey]; - const float parentNight = parentWidget->settings.fogProperties[nightKey]; - if (settings.fogProperties[dayKey] == parentDay && settings.fogProperties[nightKey] == parentNight) - return; - - settings.fogProperties[dayKey] = parentDay; - settings.fogProperties[nightKey] = parentNight; - changed = true; - }; - const float scale = Util::GetUIScale(); if (ImGui::BeginTable("FogTable", 3, ImGuiTableFlags_BordersInnerV | ImGuiTableFlags_SizingStretchSame)) { ImGui::TableSetupColumn("Parameter", ImGuiTableColumnFlags_WidthFixed, 80.0f * scale); @@ -1243,117 +1222,10 @@ void WeatherWidget::DrawFogSettings() ImGui::TableSetColumnIndex(2); ImGui::Separator(); - // Near - if (nearMatches) { - const char* highlightId = pushFogRowHighlight(WeatherSetting::kDayNear, WeatherSetting::kNightNear); - ImGui::TableNextRow(); - ImGui::TableSetColumnIndex(0); - if (hasParent) { - ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.15f, 0.15f, 0.15f, 1.0f)); - ImGui::PushStyleColor(ImGuiCol_CheckMark, ImVec4(0.5f, 0.5f, 0.5f, 1.0f)); - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2.0f * scale, 2.0f * scale)); - ImGui::Checkbox("##FogNear", &settings.inheritFlags[WeatherInherit::kFogNear]); - inheritFogPair(WeatherInherit::kFogNear, WeatherSetting::kDayNear, WeatherSetting::kNightNear); - ImGui::PopStyleVar(); - ImGui::PopStyleColor(2); - ImGui::SameLine(); - } - ImGui::AlignTextToFramePadding(); - ImGui::Text("Near"); - ImGui::TableSetColumnIndex(1); - ImGui::SetNextItemWidth(-1); - if (WeatherUtils::DrawSliderFloat("##Day Near", settings.fogProperties[WeatherSetting::kDayNear], 0.0f, 1000000.0f, nullptr, "%.0f")) - changed = true; - ImGui::TableSetColumnIndex(2); - ImGui::SetNextItemWidth(-1); - if (WeatherUtils::DrawSliderFloat("##Night Near", settings.fogProperties[WeatherSetting::kNightNear], 0.0f, 1000000.0f, nullptr, "%.0f")) - changed = true; - popFogRowHighlight(highlightId); - } - - // Far - if (farMatches) { - const char* highlightId = pushFogRowHighlight(WeatherSetting::kDayFar, WeatherSetting::kNightFar); - ImGui::TableNextRow(); - ImGui::TableSetColumnIndex(0); - if (hasParent) { - ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.15f, 0.15f, 0.15f, 1.0f)); - ImGui::PushStyleColor(ImGuiCol_CheckMark, ImVec4(0.5f, 0.5f, 0.5f, 1.0f)); - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2.0f * scale, 2.0f * scale)); - ImGui::Checkbox("##FogFar", &settings.inheritFlags[WeatherInherit::kFogFar]); - inheritFogPair(WeatherInherit::kFogFar, WeatherSetting::kDayFar, WeatherSetting::kNightFar); - ImGui::PopStyleVar(); - ImGui::PopStyleColor(2); - ImGui::SameLine(); - } - ImGui::AlignTextToFramePadding(); - ImGui::Text("Far"); - ImGui::TableSetColumnIndex(1); - ImGui::SetNextItemWidth(-1); - if (WeatherUtils::DrawSliderFloat("##Day Far", settings.fogProperties[WeatherSetting::kDayFar], 0.0f, 1000000.0f, nullptr, "%.0f")) - changed = true; - ImGui::TableSetColumnIndex(2); - ImGui::SetNextItemWidth(-1); - if (WeatherUtils::DrawSliderFloat("##Night Far", settings.fogProperties[WeatherSetting::kNightFar], 0.0f, 1000000.0f, nullptr, "%.0f")) - changed = true; - popFogRowHighlight(highlightId); - } - - // Power - if (powerMatches) { - const char* highlightId = pushFogRowHighlight(WeatherSetting::kDayPower, WeatherSetting::kNightPower); - ImGui::TableNextRow(); - ImGui::TableSetColumnIndex(0); - if (hasParent) { - ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.15f, 0.15f, 0.15f, 1.0f)); - ImGui::PushStyleColor(ImGuiCol_CheckMark, ImVec4(0.5f, 0.5f, 0.5f, 1.0f)); - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2.0f * scale, 2.0f * scale)); - ImGui::Checkbox("##FogPower", &settings.inheritFlags[WeatherInherit::kFogPower]); - inheritFogPair(WeatherInherit::kFogPower, WeatherSetting::kDayPower, WeatherSetting::kNightPower); - ImGui::PopStyleVar(); - ImGui::PopStyleColor(2); - ImGui::SameLine(); - } - ImGui::AlignTextToFramePadding(); - ImGui::Text("Power"); - ImGui::TableSetColumnIndex(1); - ImGui::SetNextItemWidth(-1); - if (WeatherUtils::DrawSliderFloat("##Day Power", settings.fogProperties[WeatherSetting::kDayPower], 0.0f, 10.0f, nullptr, "%.3f")) - changed = true; - ImGui::TableSetColumnIndex(2); - ImGui::SetNextItemWidth(-1); - if (WeatherUtils::DrawSliderFloat("##Night Power", settings.fogProperties[WeatherSetting::kNightPower], 0.0f, 10.0f, nullptr, "%.3f")) - changed = true; - popFogRowHighlight(highlightId); - } - - // Max - if (maxMatches) { - const char* highlightId = pushFogRowHighlight(WeatherSetting::kDayMax, WeatherSetting::kNightMax); - ImGui::TableNextRow(); - ImGui::TableSetColumnIndex(0); - if (hasParent) { - ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.15f, 0.15f, 0.15f, 1.0f)); - ImGui::PushStyleColor(ImGuiCol_CheckMark, ImVec4(0.5f, 0.5f, 0.5f, 1.0f)); - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2.0f * scale, 2.0f * scale)); - ImGui::Checkbox("##FogMax", &settings.inheritFlags[WeatherInherit::kFogMax]); - inheritFogPair(WeatherInherit::kFogMax, WeatherSetting::kDayMax, WeatherSetting::kNightMax); - ImGui::PopStyleVar(); - ImGui::PopStyleColor(2); - ImGui::SameLine(); - } - ImGui::AlignTextToFramePadding(); - ImGui::Text("Max"); - ImGui::TableSetColumnIndex(1); - ImGui::SetNextItemWidth(-1); - if (WeatherUtils::DrawSliderFloat("##Day Max", settings.fogProperties[WeatherSetting::kDayMax], 0.0f, 1.0f, nullptr, "%.3f")) - changed = true; - ImGui::TableSetColumnIndex(2); - ImGui::SetNextItemWidth(-1); - if (WeatherUtils::DrawSliderFloat("##Night Max", settings.fogProperties[WeatherSetting::kNightMax], 0.0f, 1.0f, nullptr, "%.3f")) - changed = true; - popFogRowHighlight(highlightId); - } + DrawFogRow(nearMatches, WeatherInherit::kFogNear, "Near", WeatherSetting::kDayNear, WeatherSetting::kNightNear, 0.0f, 1000000.0f, "%.0f", hasParent, parentWidget, changed); + DrawFogRow(farMatches, WeatherInherit::kFogFar, "Far", WeatherSetting::kDayFar, WeatherSetting::kNightFar, 0.0f, 1000000.0f, "%.0f", hasParent, parentWidget, changed); + DrawFogRow(powerMatches, WeatherInherit::kFogPower, "Power", WeatherSetting::kDayPower, WeatherSetting::kNightPower, 0.0f, 10.0f, "%.3f", hasParent, parentWidget, changed); + DrawFogRow(maxMatches, WeatherInherit::kFogMax, "Max", WeatherSetting::kDayMax, WeatherSetting::kNightMax, 0.0f, 1.0f, "%.3f", hasParent, parentWidget, changed); ImGui::EndTable(); } @@ -1363,6 +1235,64 @@ void WeatherWidget::DrawFogSettings() } } +void WeatherWidget::DrawFogSlider(const char* id, float& prop, float min, float max, const char* fmt, bool& inheritRef, bool isInherited, bool& changed) +{ + ImGui::SetNextItemWidth(-1); + if (isInherited) PushInheritedStyle(); + if (WeatherUtils::DrawSliderFloat(id, prop, min, max, nullptr, fmt)) { + changed = true; + inheritRef = false; + } + if (isInherited) { Util::AddTooltip("Inherited from parent weather"); PopInheritedStyle(); } +} + +void WeatherWidget::DrawFogRow(bool matches, const char* inheritKey, const char* label, + const char* dayPropKey, const char* nightPropKey, float min, float max, const char* fmt, + bool hasParent, WeatherWidget* parentWidget, bool& changed) +{ + if (!matches) + return; + + const float scale = Util::GetUIScale(); + + const char* highlightId = nullptr; + if (PushHighlightIfNeeded(dayPropKey)) + highlightId = dayPropKey; + else if (PushHighlightIfNeeded(nightPropKey)) + highlightId = nightPropKey; + + ImGui::TableNextRow(); + ImGui::TableSetColumnIndex(0); + if (hasParent) { + ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.15f, 0.15f, 0.15f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_CheckMark, ImVec4(0.5f, 0.5f, 0.5f, 1.0f)); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2.0f * scale, 2.0f * scale)); + ImGui::Checkbox(std::format("##Fog{}", label).c_str(), &settings.inheritFlags[inheritKey]); + if (parentWidget && settings.inheritFlags[inheritKey]) { + const float parentDay = parentWidget->settings.fogProperties[dayPropKey]; + const float parentNight = parentWidget->settings.fogProperties[nightPropKey]; + if (settings.fogProperties[dayPropKey] != parentDay || settings.fogProperties[nightPropKey] != parentNight) { + settings.fogProperties[dayPropKey] = parentDay; + settings.fogProperties[nightPropKey] = parentNight; + changed = true; + } + } + ImGui::PopStyleVar(); + ImGui::PopStyleColor(2); + ImGui::SameLine(); + } + ImGui::AlignTextToFramePadding(); + ImGui::Text("%s", label); + bool& inheritRef = settings.inheritFlags[inheritKey]; + const bool isInherited = hasParent && inheritRef; + ImGui::TableSetColumnIndex(1); + DrawFogSlider(std::format("##Day {}", label).c_str(), settings.fogProperties[dayPropKey], min, max, fmt, inheritRef, isInherited, changed); + ImGui::TableSetColumnIndex(2); + DrawFogSlider(std::format("##Night {}", label).c_str(), settings.fogProperties[nightPropKey], min, max, fmt, inheritRef, isInherited, changed); + + if (highlightId) PopHighlightIfNeeded(highlightId, true); +} + void WeatherWidget::DrawProperties(std::string category, std::map properties) { // Only show category if any property matches search @@ -1379,9 +1309,10 @@ void WeatherWidget::DrawProperties(std::string category, std::mapsecond; + }; + auto syncFogPair = [&](const char* flagKey, const char* dayKey, const char* nightKey) { + if (inherited(flagKey)) { + settings.fogProperties[dayKey] = parentWidget->settings.fogProperties[dayKey]; + settings.fogProperties[nightKey] = parentWidget->settings.fogProperties[nightKey]; + } + }; + auto syncDalcTOD = [&](const char* flagKey, auto accessor) { + if (inherited(flagKey)) + for (int i = 0; i < ColorTimes::kTotal; i++) + accessor(settings.dalc[i]) = accessor(parentWidget->settings.dalc[i]); + }; + auto syncRecord = [&](const std::string& flagKey, auto& ref, const auto& parentRef) { + if (inherited(flagKey) && ref != parentRef) { + ref = parentRef; + pendingReinit = true; + } + }; + + for (auto& [key, value] : settings.weatherProperties) + if (inherited(key)) + value = parentWidget->settings.weatherProperties[key]; + for (auto& [key, value] : settings.weatherColors) + if (inherited(key)) + value = parentWidget->settings.weatherColors[key]; + + syncFogPair(WeatherInherit::kFogNear, WeatherSetting::kDayNear, WeatherSetting::kNightNear); + syncFogPair(WeatherInherit::kFogFar, WeatherSetting::kDayFar, WeatherSetting::kNightFar); + syncFogPair(WeatherInherit::kFogPower, WeatherSetting::kDayPower, WeatherSetting::kNightPower); + syncFogPair(WeatherInherit::kFogMax, WeatherSetting::kDayMax, WeatherSetting::kNightMax); + + for (int i = 0; i < ColorTypes::kTotal; i++) + if (inherited("Atmosphere_" + ColorTypeLabel(i))) + settings.atmosphereColors[i] = parentWidget->settings.atmosphereColors[i]; + + syncDalcTOD(WeatherInherit::kDalcSpecular, [](DALC& d) -> auto& { return d.specular; }); + syncDalcTOD(WeatherInherit::kDalcFresnel, [](DALC& d) -> auto& { return d.fresnelPower; }); + syncDalcTOD(WeatherInherit::kDalcDirXMax, [](DALC& d) -> auto& { return d.directional[0].max; }); + syncDalcTOD(WeatherInherit::kDalcDirXMin, [](DALC& d) -> auto& { return d.directional[0].min; }); + syncDalcTOD(WeatherInherit::kDalcDirYMax, [](DALC& d) -> auto& { return d.directional[1].max; }); + syncDalcTOD(WeatherInherit::kDalcDirYMin, [](DALC& d) -> auto& { return d.directional[1].min; }); + syncDalcTOD(WeatherInherit::kDalcDirZMax, [](DALC& d) -> auto& { return d.directional[2].max; }); + syncDalcTOD(WeatherInherit::kDalcDirZMin, [](DALC& d) -> auto& { return d.directional[2].min; }); + + for (int i = 0; i < TESWeather::kTotalLayers; i++) { + if (inherited(std::format("Cloud{}_Color", i))) + for (int j = 0; j < ColorTimes::kTotal; j++) + settings.clouds[i].color[j] = parentWidget->settings.clouds[i].color[j]; + if (inherited(std::format("Cloud{}_Alpha", i))) + for (int j = 0; j < ColorTimes::kTotal; j++) + settings.clouds[i].cloudAlpha[j] = parentWidget->settings.clouds[i].cloudAlpha[j]; + } + + for (size_t i = 0; i < ColorTimes::kTotal; i++) { + syncRecord("ImageSpace_" + std::to_string(i), settings.imageSpaceRefs[i], parentWidget->settings.imageSpaceRefs[i]); + syncRecord("VolumetricLighting_" + std::to_string(i), settings.volumetricLightingRefs[i], parentWidget->settings.volumetricLightingRefs[i]); + } + syncRecord("Precipitation", settings.precipitationData, parentWidget->settings.precipitationData); + syncRecord("ReferenceEffect", settings.referenceEffect, parentWidget->settings.referenceEffect); + + ApplyChanges(); +} + +void WeatherWidget::PropagateToChildren() +{ + if (!EditorWindow::GetSingleton()->settings.enableInheritFromParent) + return; + + static thread_local std::unordered_set visiting; + if (!visiting.insert(this).second) + return; + + const std::string myId = GetEditorID(); + for (auto& widget : EditorWindow::GetSingleton()->weatherWidgets) { + auto* child = static_cast(widget.get()); + if (child != this && child->settings.parent == myId) { + bool hasAnyInherit = false; + for (const auto& [key, val] : child->settings.inheritFlags) + if (val) { hasAnyInherit = true; break; } + if (hasAnyInherit && !visiting.contains(child)) + child->SyncInheritedValuesFromParent(); + } + } + + visiting.erase(this); +} + void WeatherWidget::InheritFromParent(const std::string& property) { if (!HasParent()) @@ -1454,86 +1476,66 @@ void WeatherWidget::InheritAllFromParent() if (!parentWidget) return; - // Copy all weather properties + // Basic tab — weatherProperties and weatherColors (e.g. Lightning Color) for (const auto& [key, value] : parentWidget->settings.weatherProperties) { settings.weatherProperties[key] = value; + settings.inheritFlags[key] = true; } - - // Copy all weather colors for (const auto& [key, value] : parentWidget->settings.weatherColors) { settings.weatherColors[key] = value; + settings.inheritFlags[key] = true; } - // Copy all fog properties - for (const auto& [key, value] : parentWidget->settings.fogProperties) { - settings.fogProperties[key] = value; - } + // DALC tab + static constexpr const char* kDalcFlags[] = { + WeatherInherit::kDalcSpecular, WeatherInherit::kDalcFresnel, + WeatherInherit::kDalcDirXMax, WeatherInherit::kDalcDirXMin, + WeatherInherit::kDalcDirYMax, WeatherInherit::kDalcDirYMin, + WeatherInherit::kDalcDirZMax, WeatherInherit::kDalcDirZMin, + }; + for (int i = 0; i < ColorTimes::kTotal; i++) + settings.dalc[i] = parentWidget->settings.dalc[i]; + for (const auto* key : kDalcFlags) + settings.inheritFlags[key] = true; - // Copy atmosphere colors + // Atmosphere tab for (int i = 0; i < ColorTypes::kTotal; i++) { settings.atmosphereColors[i] = parentWidget->settings.atmosphereColors[i]; + settings.inheritFlags["Atmosphere_" + ColorTypeLabel(i)] = true; } - // Copy DALC settings - for (int i = 0; i < ColorTimes::kTotal; i++) { - settings.dalc[i] = parentWidget->settings.dalc[i]; - } - - // Copy cloud settings + // Clouds tab for (int i = 0; i < TESWeather::kTotalLayers; i++) { settings.clouds[i] = parentWidget->settings.clouds[i]; - } - - // Copy records (form references) - for (size_t i = 0; i < ColorTimes::kTotal; i++) { - settings.imageSpaceRefs[i] = parentWidget->settings.imageSpaceRefs[i]; - settings.volumetricLightingRefs[i] = parentWidget->settings.volumetricLightingRefs[i]; - } - settings.precipitationData = parentWidget->settings.precipitationData; - settings.referenceEffect = parentWidget->settings.referenceEffect; - - // Set all inherit flags to true - settings.inheritFlags[WeatherInherit::kDalcSpecular] = true; - settings.inheritFlags[WeatherInherit::kDalcFresnel] = true; - settings.inheritFlags[WeatherInherit::kDalcDirXMax] = true; - settings.inheritFlags[WeatherInherit::kDalcDirXMin] = true; - settings.inheritFlags[WeatherInherit::kDalcDirYMax] = true; - settings.inheritFlags[WeatherInherit::kDalcDirYMin] = true; - settings.inheritFlags[WeatherInherit::kDalcDirZMax] = true; - settings.inheritFlags[WeatherInherit::kDalcDirZMin] = true; - - settings.inheritFlags[WeatherInherit::kFogNear] = true; - settings.inheritFlags[WeatherInherit::kFogFar] = true; - settings.inheritFlags[WeatherInherit::kFogPower] = true; - settings.inheritFlags[WeatherInherit::kFogMax] = true; - - // Atmosphere colors - static const int displayOrder[] = { 0, 7, 8, 1, 12, 3, 4, 5, 6, 9, 10, 11, 13, 14, 15, 16, 2 }; - for (int idx = 0; idx < ColorTypes::kTotal; idx++) { - int i = displayOrder[idx]; - std::string colorTypeLabel = ColorTypeLabel(i); - settings.inheritFlags["Atmosphere_" + colorTypeLabel] = true; - } - - // Cloud settings - for (int i = 0; i < TESWeather::kTotalLayers; i++) { settings.inheritFlags[std::format("Cloud{}_Color", i)] = true; settings.inheritFlags[std::format("Cloud{}_Alpha", i)] = true; } - // Records + // Fog tab + settings.fogProperties = parentWidget->settings.fogProperties; + static constexpr const char* kFogFlags[] = { + WeatherInherit::kFogNear, WeatherInherit::kFogFar, + WeatherInherit::kFogPower, WeatherInherit::kFogMax, + }; + for (const auto* key : kFogFlags) + settings.inheritFlags[key] = true; + + // Records tab for (size_t i = 0; i < ColorTimes::kTotal; i++) { + settings.imageSpaceRefs[i] = parentWidget->settings.imageSpaceRefs[i]; + settings.volumetricLightingRefs[i] = parentWidget->settings.volumetricLightingRefs[i]; settings.inheritFlags["ImageSpace_" + std::to_string(i)] = true; settings.inheritFlags["VolumetricLighting_" + std::to_string(i)] = true; } + settings.precipitationData = parentWidget->settings.precipitationData; + settings.referenceEffect = parentWidget->settings.referenceEffect; settings.inheritFlags["Precipitation"] = true; settings.inheritFlags["ReferenceEffect"] = true; - // Apply the changes — form references require a weather reinit to propagate + // Form references require a weather reinit to propagate pendingReinit = true; - if (EditorWindow::GetSingleton()->settings.autoApplyChanges) { + if (EditorWindow::GetSingleton()->settings.autoApplyChanges) ApplyChanges(); - } EditorWindow::GetSingleton()->ShowNotification( std::format("Inherited all settings from {}", parentWidget->GetEditorID()), @@ -1656,6 +1658,7 @@ void WeatherWidget::ApplyChanges() Widget::ForceWeatherReinit(weather); pendingReinit = false; } + PropagateToChildren(); } void WeatherWidget::RevertChanges() diff --git a/src/WeatherEditor/Weather/WeatherWidget.h b/src/WeatherEditor/Weather/WeatherWidget.h index e7f4c944b6..64946c5dbb 100644 --- a/src/WeatherEditor/Weather/WeatherWidget.h +++ b/src/WeatherEditor/Weather/WeatherWidget.h @@ -130,6 +130,8 @@ class WeatherWidget : public Widget void DrawWeatherColorSettings(); void DrawCloudSettings(); void DrawFogSettings(); + void DrawFogSlider(const char* id, float& prop, float min, float max, const char* fmt, bool& inheritRef, bool isInherited, bool& changed); + void DrawFogRow(bool matches, const char* inheritKey, const char* label, const char* dayPropKey, const char* nightPropKey, float min, float max, const char* fmt, bool hasParent, WeatherWidget* parentWidget, bool& changed); void DrawFeatureSettings(); // Cloud texture loading @@ -140,5 +142,7 @@ class WeatherWidget : public Widget void DrawProperties(std::string category, std::map properties); void InheritFromParent(const std::string& property); void InheritAllFromParent(); + void SyncInheritedValuesFromParent(); + void PropagateToChildren(); bool pendingReinit = false; }; \ No newline at end of file diff --git a/src/WeatherEditor/WeatherUtils.cpp b/src/WeatherEditor/WeatherUtils.cpp index 9b2b7c5f16..c954f939b9 100644 --- a/src/WeatherEditor/WeatherUtils.cpp +++ b/src/WeatherEditor/WeatherUtils.cpp @@ -147,6 +147,22 @@ void SetWidgetTypeSizesFromJson(const json& j) } } +void PushInheritedStyle() +{ + const auto w = Util::Colors::GetWarning(); + ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(w.x, w.y, w.z, 0.25f)); + ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(w.x, w.y, w.z, 0.35f)); + ImGui::PushStyleColor(ImGuiCol_FrameBgActive, ImVec4(w.x, w.y, w.z, 0.45f)); + ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f); + ImGui::PushStyleColor(ImGuiCol_Border, w); +} + +void PopInheritedStyle() +{ + ImGui::PopStyleColor(4); + ImGui::PopStyleVar(); +} + bool ContainsStringIgnoreCase(const std::string_view a_string, const std::string_view a_substring) { if (a_substring.empty()) @@ -839,11 +855,15 @@ namespace TOD values[i] = parentValues[i]; } + const bool isInherited = inheritFlags && inheritFlags[i]; + if (isInherited) + PushInheritedStyle(); + ImGui::PushItemWidth(sliderWidth); std::string id = std::string("##") + label + std::to_string(i); std::string itemKey = ScopedKey(std::string(label) + "_slider_" + std::to_string(i)); - ImGui::BeginDisabled(inheritFlags && inheritFlags[i]); + ImGui::BeginDisabled(isInherited); if (ImGui::SliderFloat(id.c_str(), &values[i], minValue, maxValue, format)) { changed = true; if (inheritFlags) @@ -862,9 +882,12 @@ namespace TOD ImGui::EndDisabled(); - Util::AddTooltip(std::format("{:.0f}%", factors[i] * 100.0f).c_str()); + Util::AddTooltip(isInherited ? "Inherited from parent weather" : std::format("{:.0f}%", factors[i] * 100.0f).c_str()); ImGui::PopItemWidth(); + if (isInherited) + PopInheritedStyle(); + if (!isActive || (inheritFlags && inheritFlags[i])) ImGui::PopStyleVar(); @@ -963,6 +986,9 @@ namespace TOD static std::map originalColorCache; static std::string activeColorId; + if (inheritFlag) + PushInheritedStyle(); + // Disable editing when inherited ImGui::BeginDisabled(inheritFlag); if (ImGui::ColorButton(id.c_str(), color, ImGuiColorEditFlags_NoAlpha, ImVec2(buttonSize, buttonSize))) { @@ -1034,6 +1060,11 @@ namespace TOD wasPopupOpenInherit[scopedId] = isPopupOpen; ImGui::EndDisabled(); + if (inheritFlag) { + Util::AddTooltip("Inherited from parent weather"); + PopInheritedStyle(); + } + ImGui::EndChild(); } @@ -1127,6 +1158,9 @@ namespace TOD float spacing = ImGui::GetStyle().ItemSpacing.x; float columnWidth = (totalWidth - 3 * spacing) / 4.0f; + if (inheritFlag) + PushInheritedStyle(); + ImGui::BeginDisabled(inheritFlag); for (int i = 0; i < Count; ++i) { if (i > 0) @@ -1142,10 +1176,15 @@ namespace TOD if (ImGui::SliderFloat("##value", &values[i], minValue, maxValue, format)) { changed = true; } + if (inheritFlag) + Util::AddTooltip("Inherited from parent weather"); ImGui::PopID(); } ImGui::EndDisabled(); + if (inheritFlag) + PopInheritedStyle(); + PopTODHighlight(label, highlighted); return changed; } diff --git a/src/WeatherEditor/WeatherUtils.h b/src/WeatherEditor/WeatherUtils.h index 23862a7120..8b238a9a16 100644 --- a/src/WeatherEditor/WeatherUtils.h +++ b/src/WeatherEditor/WeatherUtils.h @@ -285,6 +285,11 @@ enum ControlType FLOAT_SLIDER }; +// Push/pop warning-colored FrameBg + border to mark a control as inherited from a parent. +// Call Push before drawing the control; Pop after. Always balanced (4 colors + 1 style var). +void PushInheritedStyle(); +void PopInheritedStyle(); + // Time of Day (TOD) helper functions namespace TOD {