diff --git a/src/WeatherEditor/EditorWindow.cpp b/src/WeatherEditor/EditorWindow.cpp index 360f4a8234..231e9e5f3d 100644 --- a/src/WeatherEditor/EditorWindow.cpp +++ b/src/WeatherEditor/EditorWindow.cpp @@ -154,277 +154,375 @@ void EditorWindow::ShowObjectsWindow() // Left column: Categories ImGui::TableSetColumnIndex(0); - ImGui::Text("Categories"); - ImGui::Spacing(); - - // List of categories - const char* categories[] = { "Weather", "ImageSpace", "Lighting Template", "Cell Lighting", "Volumetric Lighting", "Shader Particle Geometry", "Lens Flare", "Visual Effect", "Interior Only" }; - for (int i = 0; i < IM_ARRAYSIZE(categories); ++i) { - // Highlight the selected category - if (ImGui::Selectable(categories[i], selectedCategory == categories[i])) { - selectedCategory = categories[i]; // Update selected category - } - } // Right column: Objects - ImGui::TableSetColumnIndex(1); - - // Interior Only category has its own panel - if (selectedCategory == "Interior Only") { - InteriorOnlyPanel::Draw(); - ImGui::EndTable(); - ImGui::End(); - return; - } - - // Display current active weather - auto sky = globals::game::sky; - if (sky && sky->currentWeather) { - auto currentWeather = sky->currentWeather; - ImGui::PushStyleColor(ImGuiCol_Text, Menu::GetSingleton()->GetTheme().StatusPalette.RestartNeeded); - ImGui::Text("Current Active Weather:"); - ImGui::PopStyleColor(); - ImGui::SameLine(); - ImGui::TextColored(Menu::GetSingleton()->GetTheme().Palette.Text, "%s", currentWeather->GetFormEditorID()); - ImGui::SameLine(); - ImGui::TextDisabled("(0x%08X)", currentWeather->GetFormID()); - - // Add button to open the current weather - ImGui::SameLine(); - if (ImGui::SmallButton("Open##CurrentWeather")) { - for (auto& widget : weatherWidgets) { - if (widget->form == currentWeather) { - widget->SetOpen(true); - break; - } - } - } - ImGui::Spacing(); - ImGui::Separator(); + ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f); + ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4()); + if (ImGui::BeginListBox("##CategoriesList", { -FLT_MIN, -FLT_MIN })) { + ImGui::Text("Categories"); ImGui::Spacing(); - } - // Handle Ctrl+F to focus search bar - if (ImGui::IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows)) { - if (ImGui::GetIO().KeyCtrl && ImGui::IsKeyPressed(ImGuiKey_F, false)) { - ImGui::SetKeyboardFocusHere(); + // List of categories + const char* categories[] = { "Weather", "ImageSpace", "Lighting Template", "Cell Lighting", "Volumetric Lighting", "Shader Particle Geometry", "Lens Flare", "Visual Effect", "Interior Only" }; + for (int i = 0; i < IM_ARRAYSIZE(categories); ++i) { + // Highlight the selected category + if (ImGui::Selectable(categories[i], selectedCategory == categories[i])) { + selectedCategory = categories[i]; // Update selected category + } } + ImGui::EndListBox(); } - ImGui::InputTextWithHint("##ObjectFilter", "Filter... (Ctrl+F)", filterBuffer, sizeof(filterBuffer)); - - ImGui::SameLine(); - HelpMarker("Type a part of an object name to filter the list.\nCtrl+F: Focus search\nEnter: Open selected"); + ImGui::PopStyleVar(); + ImGui::PopStyleColor(); - // Quick filter buttons on same row - ImGui::SameLine(); - ImGui::Dummy(ImVec2(10.0f, 0.0f)); // Spacer - ImGui::SameLine(); - if (IconButton("##filterFavorites", showOnlyFavorites, "star")) { - showOnlyFavorites = !showOnlyFavorites; - } - ImGui::SameLine(); - ImGui::Text("Favorites"); + // Right column: Objects + ImGui::TableSetColumnIndex(1); - ImGui::SameLine(); - ImGui::Dummy(ImVec2(10.0f, 0.0f)); // Spacer - ImGui::SameLine(); - if (IconButton("##filterFlagged", showOnlyFlagged, "circle")) { - showOnlyFlagged = !showOnlyFlagged; - } - ImGui::SameLine(); - ImGui::Text("Flagged"); + if (ImGui::BeginChild("##ObjectsContent", { 0, 0 }, ImGuiChildFlags_Border)) { + // Interior Only category has its own panel + if (selectedCategory == "Interior Only") { + InteriorOnlyPanel::Draw(); + ImGui::EndChild(); + ImGui::EndTable(); + ImGui::End(); + return; + } - // Show recent widgets section for current category - auto recentIt = settings.recentWidgets.find(selectedCategory); - if (recentIt != settings.recentWidgets.end() && !recentIt->second.empty()) { - ImGui::Spacing(); - ImGui::TextColored(Menu::GetSingleton()->GetTheme().StatusPalette.InfoColor, "Recent:"); - ImGui::SameLine(); - for (size_t i = 0; i < std::min(size_t(5), recentIt->second.size()); ++i) { - if (i > 0) - ImGui::SameLine(); - if (ImGui::SmallButton(recentIt->second[i].c_str())) { - // Find and open widget in current category's collection - auto& widgets = selectedCategory == "Weather" ? weatherWidgets : - selectedCategory == "Lighting Template" ? lightingTemplateWidgets : - selectedCategory == "ImageSpace" ? imageSpaceWidgets : - selectedCategory == "Volumetric Lighting" ? volumetricLightingWidgets : - selectedCategory == "Shader Particle Geometry" ? precipitationWidgets : - selectedCategory == "Lens Flare" ? lensFlareWidgets : - selectedCategory == "Visual Effect" ? referenceEffectWidgets : - weatherWidgets; - - for (auto& widget : widgets) { - if (widget->GetEditorID() == recentIt->second[i]) { + // Display current active weather + auto sky = globals::game::sky; + if (sky && sky->currentWeather) { + auto currentWeather = sky->currentWeather; + ImGui::PushStyleColor(ImGuiCol_Text, Menu::GetSingleton()->GetTheme().StatusPalette.RestartNeeded); + ImGui::Text("Current Active Weather:"); + ImGui::PopStyleColor(); + ImGui::SameLine(); + ImGui::TextColored(Menu::GetSingleton()->GetTheme().Palette.Text, "%s", currentWeather->GetFormEditorID()); + ImGui::SameLine(); + ImGui::TextDisabled("(0x%08X)", currentWeather->GetFormID()); + + // Add button to open the current weather + ImGui::SameLine(); + if (ImGui::SmallButton("Open##CurrentWeather")) { + for (auto& widget : weatherWidgets) { + if (widget->form == currentWeather) { widget->SetOpen(true); break; } } } + ImGui::Spacing(); + ImGui::Separator(); + ImGui::Spacing(); } - } - // Create a table for the right column with "Name" and "ID" headers. Different weights to prevent truncation. - if (ImGui::BeginTable("DetailsTable", 5, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingStretchProp | ImGuiTableFlags_Sortable)) { - ImGui::TableSetupColumn("Fav", ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoSort, 25.0f); // Favorite indicator - ImGui::TableSetupColumn("Editor ID", ImGuiTableColumnFlags_WidthStretch, 3.5f); // Largest - weather/template names - ImGui::TableSetupColumn("Form ID", ImGuiTableColumnFlags_WidthFixed, 80.0f); // Fixed - 8 hex chars - ImGui::TableSetupColumn("File", ImGuiTableColumnFlags_WidthStretch, 2.0f); // Medium - plugin names - ImGui::TableSetupColumn("Status", ImGuiTableColumnFlags_WidthStretch, 1.5f); // Smaller - status text - - ImGui::TableHeadersRow(); - - // Handle column sorting - if (ImGuiTableSortSpecs* sortSpecs = ImGui::TableGetSortSpecs()) { - if (sortSpecs->SpecsDirty) { - if (sortSpecs->SpecsCount > 0) { - const ImGuiTableColumnSortSpecs& spec = sortSpecs->Specs[0]; - currentSortColumn = static_cast(spec.ColumnIndex); - sortAscending = (spec.SortDirection == ImGuiSortDirection_Ascending); - } else { - currentSortColumn = SortColumn::None; - } - sortSpecs->SpecsDirty = false; + // Handle Ctrl+F to focus search bar + if (ImGui::IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows)) { + if (ImGui::GetIO().KeyCtrl && ImGui::IsKeyPressed(ImGuiKey_F, false)) { + ImGui::SetKeyboardFocusHere(); } } + ImGui::InputTextWithHint("##ObjectFilter", "Filter... (Ctrl+F)", filterBuffer, sizeof(filterBuffer)); - // Display objects based on the selected category - std::vector> emptyWidgets; - const auto& widgets = selectedCategory == "Weather" ? weatherWidgets : - selectedCategory == "Cell Lighting" ? emptyWidgets : - selectedCategory == "ImageSpace" ? imageSpaceWidgets : - selectedCategory == "Volumetric Lighting" ? volumetricLightingWidgets : - selectedCategory == "Shader Particle Geometry" ? precipitationWidgets : - selectedCategory == "Lens Flare" ? lensFlareWidgets : - selectedCategory == "Visual Effect" ? referenceEffectWidgets : - lightingTemplateWidgets; - // Sort widgets based on current sort column - std::vector sortedWidgets; - sortedWidgets.reserve(widgets.size()); - for (const auto& w : widgets) { - sortedWidgets.push_back(w.get()); + ImGui::SameLine(); + HelpMarker("Type a part of an object name to filter the list.\nCtrl+F: Focus search\nEnter: Open selected"); + + // Quick filter buttons on same row + ImGui::SameLine(); + ImGui::Dummy(ImVec2(10.0f, 0.0f)); // Spacer + ImGui::SameLine(); + if (IconButton("##filterFavorites", showOnlyFavorites, "star")) { + showOnlyFavorites = !showOnlyFavorites; } - if (currentSortColumn != SortColumn::None) { - std::sort(sortedWidgets.begin(), sortedWidgets.end(), [this](Widget* a, Widget* b) { - int comparison = 0; - switch (currentSortColumn) { - case SortColumn::EditorID: - comparison = _stricmp(a->GetEditorID().c_str(), b->GetEditorID().c_str()); - break; - case SortColumn::FormID: - comparison = _stricmp(a->GetFormID().c_str(), b->GetFormID().c_str()); - break; - case SortColumn::File: - comparison = _stricmp(a->GetFilename().c_str(), b->GetFilename().c_str()); - break; - case SortColumn::Status: - { - auto markerA = settings.markedRecords.find(a->GetEditorID()); - auto markerB = settings.markedRecords.find(b->GetEditorID()); - std::string statusA = (markerA != settings.markedRecords.end()) ? markerA->second : ""; - std::string statusB = (markerB != settings.markedRecords.end()) ? markerB->second : ""; - comparison = _stricmp(statusA.c_str(), statusB.c_str()); - break; + ImGui::SameLine(); + ImGui::Text("Favorites"); + + ImGui::SameLine(); + ImGui::Dummy(ImVec2(10.0f, 0.0f)); // Spacer + ImGui::SameLine(); + if (IconButton("##filterFlagged", showOnlyFlagged, "circle")) { + showOnlyFlagged = !showOnlyFlagged; + } + ImGui::SameLine(); + ImGui::Text("Flagged"); + + // Show recent widgets section for current category + auto recentIt = settings.recentWidgets.find(selectedCategory); + if (recentIt != settings.recentWidgets.end() && !recentIt->second.empty()) { + ImGui::Spacing(); + ImGui::TextColored(Menu::GetSingleton()->GetTheme().StatusPalette.InfoColor, "Recent:"); + ImGui::SameLine(); + for (size_t i = 0; i < std::min(size_t(5), recentIt->second.size()); ++i) { + if (i > 0) + ImGui::SameLine(); + if (ImGui::SmallButton(recentIt->second[i].c_str())) { + // Find and open widget in current category's collection + auto& widgets = selectedCategory == "Weather" ? weatherWidgets : + selectedCategory == "Lighting Template" ? lightingTemplateWidgets : + selectedCategory == "ImageSpace" ? imageSpaceWidgets : + selectedCategory == "Volumetric Lighting" ? volumetricLightingWidgets : + selectedCategory == "Shader Particle Geometry" ? precipitationWidgets : + selectedCategory == "Lens Flare" ? lensFlareWidgets : + selectedCategory == "Visual Effect" ? referenceEffectWidgets : + weatherWidgets; + + for (auto& widget : widgets) { + if (widget->GetEditorID() == recentIt->second[i]) { + widget->SetOpen(true); + break; + } } - default: - break; } - return sortAscending ? (comparison < 0) : (comparison > 0); - }); + } } - // Special handling for Cell Lighting category - if (selectedCategory == "Cell Lighting") { - auto player = RE::PlayerCharacter::GetSingleton(); - if (player && player->parentCell) { - auto cell = player->parentCell; - bool isInterior = cell->IsInteriorCell(); - - if (isInterior) { - ImGui::TableNextRow(); - ImGui::TableSetColumnIndex(0); + // Create a table for the right column with "Name" and "ID" headers. Different weights to prevent truncation. + if (ImGui::BeginTable("DetailsTable", 5, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingStretchProp | ImGuiTableFlags_Sortable)) { + ImGui::TableSetupColumn("Fav", ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoSort, 25.0f); // Favorite indicator + ImGui::TableSetupColumn("Editor ID", ImGuiTableColumnFlags_WidthStretch, 3.5f); // Largest - weather/template names + ImGui::TableSetupColumn("Form ID", ImGuiTableColumnFlags_WidthFixed, 80.0f); // Fixed - 8 hex chars + ImGui::TableSetupColumn("File", ImGuiTableColumnFlags_WidthStretch, 2.0f); // Medium - plugin names + ImGui::TableSetupColumn("Status", ImGuiTableColumnFlags_WidthStretch, 1.5f); // Smaller - status text + + ImGui::TableHeadersRow(); + + // Handle column sorting + if (ImGuiTableSortSpecs* sortSpecs = ImGui::TableGetSortSpecs()) { + if (sortSpecs->SpecsDirty) { + if (sortSpecs->SpecsCount > 0) { + const ImGuiTableColumnSortSpecs& spec = sortSpecs->Specs[0]; + currentSortColumn = static_cast(spec.ColumnIndex); + sortAscending = (spec.SortDirection == ImGuiSortDirection_Ascending); + } else { + currentSortColumn = SortColumn::None; + } + sortSpecs->SpecsDirty = false; + } + } - // No favorite star for cell lighting (it's always the current cell) - ImGui::Dummy(ImVec2(24, 24)); + // Display objects based on the selected category + std::vector> emptyWidgets; + const auto& widgets = selectedCategory == "Weather" ? weatherWidgets : + selectedCategory == "Cell Lighting" ? emptyWidgets : + selectedCategory == "ImageSpace" ? imageSpaceWidgets : + selectedCategory == "Volumetric Lighting" ? volumetricLightingWidgets : + selectedCategory == "Shader Particle Geometry" ? precipitationWidgets : + selectedCategory == "Lens Flare" ? lensFlareWidgets : + selectedCategory == "Visual Effect" ? referenceEffectWidgets : + lightingTemplateWidgets; + // Sort widgets based on current sort column + std::vector sortedWidgets; + sortedWidgets.reserve(widgets.size()); + for (const auto& w : widgets) { + sortedWidgets.push_back(w.get()); + } + if (currentSortColumn != SortColumn::None) { + std::sort(sortedWidgets.begin(), sortedWidgets.end(), [this](Widget* a, Widget* b) { + int comparison = 0; + switch (currentSortColumn) { + case SortColumn::EditorID: + comparison = _stricmp(a->GetEditorID().c_str(), b->GetEditorID().c_str()); + break; + case SortColumn::FormID: + comparison = _stricmp(a->GetFormID().c_str(), b->GetFormID().c_str()); + break; + case SortColumn::File: + comparison = _stricmp(a->GetFilename().c_str(), b->GetFilename().c_str()); + break; + case SortColumn::Status: + { + auto markerA = settings.markedRecords.find(a->GetEditorID()); + auto markerB = settings.markedRecords.find(b->GetEditorID()); + std::string statusA = (markerA != settings.markedRecords.end()) ? markerA->second : ""; + std::string statusB = (markerB != settings.markedRecords.end()) ? markerB->second : ""; + comparison = _stricmp(statusA.c_str(), statusB.c_str()); + break; + } + default: + break; + } + return sortAscending ? (comparison < 0) : (comparison > 0); + }); + } - ImGui::TableNextColumn(); + // Special handling for Cell Lighting category + if (selectedCategory == "Cell Lighting") { + auto player = RE::PlayerCharacter::GetSingleton(); + if (player && player->parentCell) { + auto cell = player->parentCell; + bool isInterior = cell->IsInteriorCell(); + + if (isInterior) { + ImGui::TableNextRow(); + ImGui::TableSetColumnIndex(0); + + // No favorite star for cell lighting (it's always the current cell) + ImGui::Dummy(ImVec2(24, 24)); + + ImGui::TableNextColumn(); + + // Display current cell name + const char* cellName = cell->GetName(); + std::string displayName = cellName && cellName[0] ? cellName : "[Unnamed Cell]"; + std::string label = std::format("[CURRENT CELL] {}", displayName); + + bool isOpen = currentCellLightingWidget && currentCellLightingWidget->IsOpen(); + if (ImGui::Selectable(label.c_str(), isOpen, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowDoubleClick)) { + if (ImGui::IsMouseDoubleClicked(0)) { + // Open or reuse the cell lighting widget + if (currentCellLightingWidget && currentCellLightingWidget->cell == cell) { + currentCellLightingWidget->SetOpen(true); + } else { + currentCellLightingWidget = std::make_unique(cell); + currentCellLightingWidget->CacheFormData(); + currentCellLightingWidget->Load(); + currentCellLightingWidget->SetOpen(true); + } + } + } - // Display current cell name - const char* cellName = cell->GetName(); - std::string displayName = cellName && cellName[0] ? cellName : "[Unnamed Cell]"; - std::string label = std::format("[CURRENT CELL] {}", displayName); + // Highlight current cell + auto highlightColor = Menu::GetSingleton()->GetTheme().StatusPalette.InfoColor; + highlightColor.w = 0.3f; + ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0, ImGui::ColorConvertFloat4ToU32(highlightColor)); + ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg1, ImGui::ColorConvertFloat4ToU32(highlightColor)); - bool isOpen = currentCellLightingWidget && currentCellLightingWidget->IsOpen(); - if (ImGui::Selectable(label.c_str(), isOpen, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowDoubleClick)) { - if (ImGui::IsMouseDoubleClicked(0)) { - // Open or reuse the cell lighting widget + // Enter key to open + if (isOpen && ImGui::IsKeyPressed(ImGuiKey_Enter)) { if (currentCellLightingWidget && currentCellLightingWidget->cell == cell) { currentCellLightingWidget->SetOpen(true); - } else { - currentCellLightingWidget = std::make_unique(cell); - currentCellLightingWidget->CacheFormData(); - currentCellLightingWidget->Load(); - currentCellLightingWidget->SetOpen(true); } } + + // Form ID column + ImGui::TableNextColumn(); + ImGui::Text("0x%08X", cell->GetFormID()); + + // File column + ImGui::TableNextColumn(); + auto file = cell->GetFile(0); + if (file) { + ImGui::Text("%s", file->fileName); + } + + // Status column + ImGui::TableNextColumn(); + ImGui::Text("Interior Cell"); + } else { + // Show message that cell lighting is only for interior cells + ImGui::TableNextRow(); + ImGui::TableSetColumnIndex(1); + ImGui::TextColored(Menu::GetSingleton()->GetTheme().StatusPalette.Warning, "Cell Lighting is only available for interior cells."); + ImGui::TextColored(Menu::GetSingleton()->GetTheme().StatusPalette.Disable, "You are currently in an exterior cell."); } + } else { + // No player or cell + ImGui::TableNextRow(); + ImGui::TableSetColumnIndex(1); + ImGui::TextColored(Menu::GetSingleton()->GetTheme().StatusPalette.Error, "Player cell not available."); + } + } + + // Get current cell's lighting template for prioritization + RE::BGSLightingTemplate* currentCellLightingTemplate = nullptr; + if (selectedCategory == "Lighting Template") { + auto player = RE::PlayerCharacter::GetSingleton(); + if (player && player->parentCell) { + auto& cellData = player->parentCell->GetRuntimeData(); + currentCellLightingTemplate = cellData.lightingTemplate; + } + } - // Highlight current cell - auto highlightColor = Menu::GetSingleton()->GetTheme().StatusPalette.InfoColor; + // Filtered display of widgets - show current cell's lighting template first + if (currentCellLightingTemplate && selectedCategory == "Lighting Template") { + for (int i = 0; i < sortedWidgets.size(); ++i) { + auto* ltWidget = dynamic_cast(sortedWidgets[i]); + if (!ltWidget || ltWidget->lightingTemplate != currentCellLightingTemplate) + continue; + + if (!ContainsStringIgnoreCase(sortedWidgets[i]->GetEditorID(), filterBuffer)) + continue; + + // Apply quick filters + if (showOnlyFavorites && !IsFavorite(sortedWidgets[i]->GetEditorID())) + continue; + if (showOnlyFlagged && settings.markedRecords.find(sortedWidgets[i]->GetEditorID()) == settings.markedRecords.end()) + continue; + + auto editorLabel = std::format("[CURRENT] {}", sortedWidgets[i]->GetEditorID()); + auto markedRecord = settings.markedRecords.find(sortedWidgets[i]->GetEditorID()); + ImGui::TableNextRow(); + + // Highlight current cell's lighting template + auto highlightColor = Menu::GetSingleton()->GetSettings().Theme.StatusPalette.InfoColor; highlightColor.w = 0.3f; ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0, ImGui::ColorConvertFloat4ToU32(highlightColor)); ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg1, ImGui::ColorConvertFloat4ToU32(highlightColor)); + ImGui::TableSetColumnIndex(0); + + // Favorite star + if (IconButton("##fav_current", IsFavorite(sortedWidgets[i]->GetEditorID()), "star")) { + ToggleFavorite(sortedWidgets[i]->GetEditorID()); + } + + ImGui::TableNextColumn(); + + // Editor ID column with [CURRENT] prefix + bool isSelected = sortedWidgets[i]->IsOpen(); + if (ImGui::Selectable(editorLabel.c_str(), isSelected, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowDoubleClick)) { + if (ImGui::IsMouseDoubleClicked(0)) { + sortedWidgets[i]->SetOpen(true); + AddToRecent(sortedWidgets[i]->GetEditorID(), selectedCategory); + } + } + // Enter key to open - if (isOpen && ImGui::IsKeyPressed(ImGuiKey_Enter)) { - if (currentCellLightingWidget && currentCellLightingWidget->cell == cell) { - currentCellLightingWidget->SetOpen(true); + if (isSelected && ImGui::IsKeyPressed(ImGuiKey_Enter)) { + sortedWidgets[i]->SetOpen(true); + AddToRecent(sortedWidgets[i]->GetEditorID(), selectedCategory); + } + + // Context menu + if (ImGui::BeginPopupContextItem(std::format("widget_context_menu##{}", sortedWidgets[i]->GetFormID()).c_str(), ImGuiPopupFlags_MouseButtonRight)) { + auto& markedRecords = settings.markedRecords; + + for (auto& recordMarker : settings.recordMarkers) { + if (ImGui::MenuItem(recordMarker.first.c_str())) { + settings.markedRecords[sortedWidgets[i]->GetEditorID()] = recordMarker.first; + Save(); + } + } + + if (ImGui::MenuItem("Remove")) { + markedRecords.erase(sortedWidgets[i]->GetEditorID()); + Save(); } + + ImGui::EndPopup(); } // Form ID column ImGui::TableNextColumn(); - ImGui::Text("0x%08X", cell->GetFormID()); + ImGui::Text(sortedWidgets[i]->GetFormID().c_str()); // File column ImGui::TableNextColumn(); - auto file = cell->GetFile(0); - if (file) { - ImGui::Text("%s", file->fileName); - } + ImGui::Text(sortedWidgets[i]->GetFilename().c_str()); // Status column ImGui::TableNextColumn(); - ImGui::Text("Interior Cell"); - } else { - // Show message that cell lighting is only for interior cells - ImGui::TableNextRow(); - ImGui::TableSetColumnIndex(1); - ImGui::TextColored(Menu::GetSingleton()->GetTheme().StatusPalette.Warning, "Cell Lighting is only available for interior cells."); - ImGui::TextColored(Menu::GetSingleton()->GetTheme().StatusPalette.Disable, "You are currently in an exterior cell."); + if (markedRecord != settings.markedRecords.end()) { + ImGui::Text("%s", markedRecord->second.c_str()); + } } - } else { - // No player or cell - ImGui::TableNextRow(); - ImGui::TableSetColumnIndex(1); - ImGui::TextColored(Menu::GetSingleton()->GetTheme().StatusPalette.Error, "Player cell not available."); } - } - // Get current cell's lighting template for prioritization - RE::BGSLightingTemplate* currentCellLightingTemplate = nullptr; - if (selectedCategory == "Lighting Template") { - auto player = RE::PlayerCharacter::GetSingleton(); - if (player && player->parentCell) { - auto& cellData = player->parentCell->GetRuntimeData(); - currentCellLightingTemplate = cellData.lightingTemplate; - } - } - - // Filtered display of widgets - show current cell's lighting template first - if (currentCellLightingTemplate && selectedCategory == "Lighting Template") { + // Filtered display of widgets - regular list for (int i = 0; i < sortedWidgets.size(); ++i) { - auto* ltWidget = dynamic_cast(sortedWidgets[i]); - if (!ltWidget || ltWidget->lightingTemplate != currentCellLightingTemplate) - continue; + // Skip current cell's lighting template if already shown + if (currentCellLightingTemplate && selectedCategory == "Lighting Template") { + auto* ltWidget = dynamic_cast(sortedWidgets[i]); + if (ltWidget && ltWidget->lightingTemplate == currentCellLightingTemplate) + continue; + } if (!ContainsStringIgnoreCase(sortedWidgets[i]->GetEditorID(), filterBuffer)) continue; @@ -435,26 +533,27 @@ void EditorWindow::ShowObjectsWindow() if (showOnlyFlagged && settings.markedRecords.find(sortedWidgets[i]->GetEditorID()) == settings.markedRecords.end()) continue; - auto editorLabel = std::format("[CURRENT] {}", sortedWidgets[i]->GetEditorID()); - auto markedRecord = settings.markedRecords.find(sortedWidgets[i]->GetEditorID()); + auto editorLabel = sortedWidgets[i]->GetEditorID(); + auto markedRecord = settings.markedRecords.find(editorLabel); ImGui::TableNextRow(); - // Highlight current cell's lighting template - auto highlightColor = Menu::GetSingleton()->GetSettings().Theme.StatusPalette.InfoColor; - highlightColor.w = 0.3f; - ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0, ImGui::ColorConvertFloat4ToU32(highlightColor)); - ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg1, ImGui::ColorConvertFloat4ToU32(highlightColor)); + // Set background colour + if (markedRecord != settings.markedRecords.end()) { + auto& color = settings.recordMarkers[markedRecord->second]; + ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0, ImGui::ColorConvertFloat4ToU32(color)); + ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg1, ImGui::ColorConvertFloat4ToU32(color)); + } ImGui::TableSetColumnIndex(0); // Favorite star - if (IconButton("##fav_current", IsFavorite(sortedWidgets[i]->GetEditorID()), "star")) { + if (IconButton(std::format("##fav_{}", i).c_str(), IsFavorite(sortedWidgets[i]->GetEditorID()), "star")) { ToggleFavorite(sortedWidgets[i]->GetEditorID()); } ImGui::TableNextColumn(); - // Editor ID column with [CURRENT] prefix + // Editor ID column bool isSelected = sortedWidgets[i]->IsOpen(); if (ImGui::Selectable(editorLabel.c_str(), isSelected, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowDoubleClick)) { if (ImGui::IsMouseDoubleClicked(0)) { @@ -463,25 +562,55 @@ void EditorWindow::ShowObjectsWindow() } } + // Show ImageSpace and VolumetricLighting info for weather widgets + if (selectedCategory == "Weather" && ImGui::IsItemHovered()) { + auto* weatherWidget = dynamic_cast(sortedWidgets[i]); + if (weatherWidget && weatherWidget->weather) { + ImGui::BeginTooltip(); + + // ImageSpace info + ImGui::TextColored(Menu::GetSingleton()->GetTheme().StatusPalette.InfoColor, "ImageSpace:"); + for (int tod = 0; tod < 4; tod++) { + auto imgSpace = weatherWidget->weather->imageSpaces[tod]; + ImGui::Text(" %s: %s", + TOD::GetPeriodName(tod), + imgSpace ? imgSpace->GetFormEditorID() : "None"); + } + + ImGui::Spacing(); + + // VolumetricLighting info + ImGui::TextColored(Menu::GetSingleton()->GetTheme().StatusPalette.InfoColor, "Volumetric Lighting:"); + for (int tod = 0; tod < 4; tod++) { + auto volLight = weatherWidget->weather->volumetricLighting[tod]; + ImGui::Text(" %s: %s", + TOD::GetPeriodName(tod), + volLight ? volLight->GetFormEditorID() : "None"); + } + + ImGui::EndTooltip(); + } + } + // Enter key to open if (isSelected && ImGui::IsKeyPressed(ImGuiKey_Enter)) { sortedWidgets[i]->SetOpen(true); AddToRecent(sortedWidgets[i]->GetEditorID(), selectedCategory); } - // Context menu + // Opens a context menu on right click to mark records by color if (ImGui::BeginPopupContextItem(std::format("widget_context_menu##{}", sortedWidgets[i]->GetFormID()).c_str(), ImGuiPopupFlags_MouseButtonRight)) { auto& markedRecords = settings.markedRecords; for (auto& recordMarker : settings.recordMarkers) { if (ImGui::MenuItem(recordMarker.first.c_str())) { - settings.markedRecords[sortedWidgets[i]->GetEditorID()] = recordMarker.first; + settings.markedRecords[editorLabel] = recordMarker.first; Save(); } } if (ImGui::MenuItem("Remove")) { - markedRecords.erase(sortedWidgets[i]->GetEditorID()); + markedRecords.erase(editorLabel); Save(); } @@ -498,134 +627,19 @@ void EditorWindow::ShowObjectsWindow() // Status column ImGui::TableNextColumn(); + + // Re-check if the record exists after potential removal + markedRecord = settings.markedRecords.find(editorLabel); if (markedRecord != settings.markedRecords.end()) { ImGui::Text("%s", markedRecord->second.c_str()); } } - } - - // Filtered display of widgets - regular list - for (int i = 0; i < sortedWidgets.size(); ++i) { - // Skip current cell's lighting template if already shown - if (currentCellLightingTemplate && selectedCategory == "Lighting Template") { - auto* ltWidget = dynamic_cast(sortedWidgets[i]); - if (ltWidget && ltWidget->lightingTemplate == currentCellLightingTemplate) - continue; - } - - if (!ContainsStringIgnoreCase(sortedWidgets[i]->GetEditorID(), filterBuffer)) - continue; - - // Apply quick filters - if (showOnlyFavorites && !IsFavorite(sortedWidgets[i]->GetEditorID())) - continue; - if (showOnlyFlagged && settings.markedRecords.find(sortedWidgets[i]->GetEditorID()) == settings.markedRecords.end()) - continue; - - auto editorLabel = sortedWidgets[i]->GetEditorID(); - auto markedRecord = settings.markedRecords.find(editorLabel); - ImGui::TableNextRow(); - - // Set background colour - if (markedRecord != settings.markedRecords.end()) { - auto& color = settings.recordMarkers[markedRecord->second]; - ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0, ImGui::ColorConvertFloat4ToU32(color)); - ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg1, ImGui::ColorConvertFloat4ToU32(color)); - } - - ImGui::TableSetColumnIndex(0); - - // Favorite star - if (IconButton(std::format("##fav_{}", i).c_str(), IsFavorite(sortedWidgets[i]->GetEditorID()), "star")) { - ToggleFavorite(sortedWidgets[i]->GetEditorID()); - } - - ImGui::TableNextColumn(); - - // Editor ID column - bool isSelected = sortedWidgets[i]->IsOpen(); - if (ImGui::Selectable(editorLabel.c_str(), isSelected, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowDoubleClick)) { - if (ImGui::IsMouseDoubleClicked(0)) { - sortedWidgets[i]->SetOpen(true); - AddToRecent(sortedWidgets[i]->GetEditorID(), selectedCategory); - } - } - - // Show ImageSpace and VolumetricLighting info for weather widgets - if (selectedCategory == "Weather" && ImGui::IsItemHovered()) { - auto* weatherWidget = dynamic_cast(sortedWidgets[i]); - if (weatherWidget && weatherWidget->weather) { - ImGui::BeginTooltip(); - - // ImageSpace info - ImGui::TextColored(Menu::GetSingleton()->GetTheme().StatusPalette.InfoColor, "ImageSpace:"); - for (int tod = 0; tod < 4; tod++) { - auto imgSpace = weatherWidget->weather->imageSpaces[tod]; - ImGui::Text(" %s: %s", - TOD::GetPeriodName(tod), - imgSpace ? imgSpace->GetFormEditorID() : "None"); - } - - ImGui::Spacing(); - - // VolumetricLighting info - ImGui::TextColored(Menu::GetSingleton()->GetTheme().StatusPalette.InfoColor, "Volumetric Lighting:"); - for (int tod = 0; tod < 4; tod++) { - auto volLight = weatherWidget->weather->volumetricLighting[tod]; - ImGui::Text(" %s: %s", - TOD::GetPeriodName(tod), - volLight ? volLight->GetFormEditorID() : "None"); - } - - ImGui::EndTooltip(); - } - } - - // Enter key to open - if (isSelected && ImGui::IsKeyPressed(ImGuiKey_Enter)) { - sortedWidgets[i]->SetOpen(true); - AddToRecent(sortedWidgets[i]->GetEditorID(), selectedCategory); - } - - // Opens a context menu on right click to mark records by color - if (ImGui::BeginPopupContextItem(std::format("widget_context_menu##{}", sortedWidgets[i]->GetFormID()).c_str(), ImGuiPopupFlags_MouseButtonRight)) { - auto& markedRecords = settings.markedRecords; - - for (auto& recordMarker : settings.recordMarkers) { - if (ImGui::MenuItem(recordMarker.first.c_str())) { - settings.markedRecords[editorLabel] = recordMarker.first; - Save(); - } - } - - if (ImGui::MenuItem("Remove")) { - markedRecords.erase(editorLabel); - Save(); - } - - ImGui::EndPopup(); - } - // Form ID column - ImGui::TableNextColumn(); - ImGui::Text(sortedWidgets[i]->GetFormID().c_str()); - - // File column - ImGui::TableNextColumn(); - ImGui::Text(sortedWidgets[i]->GetFilename().c_str()); - - // Status column - ImGui::TableNextColumn(); - - // Re-check if the record exists after potential removal - markedRecord = settings.markedRecords.find(editorLabel); - if (markedRecord != settings.markedRecords.end()) { - ImGui::Text("%s", markedRecord->second.c_str()); - } - } + ImGui::EndTable(); // End DetailsTable + } // End if BeginTable("DetailsTable") - ImGui::EndTable(); // End DetailsTable - } // End if BeginTable("DetailsTable") + } // End if BeginChild("##ObjectsContent") + ImGui::EndChild(); // End ObjectsContent child ImGui::EndTable(); // End ObjectTable } // End if BeginTable("ObjectTable")