// MassBuilderSaveTool // Copyright (C) 2021-2023 Guillaume Jacquemin // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . #include #include #include #include "../Configuration/Configuration.h" #include "../FontAwesome/IconsFontAwesome5.h" #include "../Maps/Accessories.h" #define STYLENAMES_DEFINITION #include "../Maps/StyleNames.h" #include "Application.h" namespace mbst { void Application::drawMassViewer() { if(!_currentMass || _currentMass->state() != GameObjects::Mass::State::Valid) { _currentMass = nullptr; _currentWeapon = nullptr; _uiState = UiState::MainManager; _queue.addToast(Toast::Type::Error, "The selected M.A.S.S. isn't valid anymore."); return; } ImGui::SetNextWindowPos({0.0f, ImGui::GetItemRectSize().y}, ImGuiCond_Always); ImGui::SetNextWindowSize(ImVec2{Vector2{float(windowSize().x()), float(windowSize().y()) - ImGui::GetItemRectSize().y} / dpiScaling()}, ImGuiCond_Always); if(!ImGui::Begin("##MassViewer", nullptr, ImGuiWindowFlags_NoDecoration|ImGuiWindowFlags_NoMove| ImGuiWindowFlags_NoBackground|ImGuiWindowFlags_NoBringToFrontOnFocus)) { ImGui::End(); return; } if(ImGui::BeginChild("##MassInfo", {0.0f, 0.0f}, ImGuiChildFlags_Border, ImGuiWindowFlags_MenuBar)) { if(ImGui::BeginMenuBar()) { if(ImGui::BeginTable("##MassViewerMenuTable", 4)) { ImGui::TableSetupColumn("##MassName"); ImGui::TableSetupColumn("##Spacer", ImGuiTableColumnFlags_WidthStretch); ImGui::TableSetupColumn("##Updates"); ImGui::TableSetupColumn("##Close", ImGuiTableColumnFlags_WidthFixed); ImGui::TableNextRow(); ImGui::TableSetColumnIndex(0); ImGui::Text("M.A.S.S.: %s", _currentMass->name().data()); drawTooltip(_currentMass->filename()); ImGui::TableSetColumnIndex(2); if(_currentMass->dirty()) { ImGui::TextUnformatted("External changes detected"); ImGui::SameLine(); if(ImGui::SmallButton(ICON_FA_SYNC_ALT " Refresh")) { _currentMass->refreshValues(); _currentMass->setDirty(false); _jointsDirty = false; _stylesDirty = false; _eyeFlareDirty = false; } } ImGui::TableSetColumnIndex(3); if(ImGui::SmallButton(ICON_FA_TIMES)) { _currentWeapon = nullptr; _currentMass = nullptr; _uiState = UiState::MainManager; _jointsDirty = false; _stylesDirty = false; _eyeFlareDirty = false; _selectedArmourSlot = Containers::NullOpt; _selectedArmourDecals = Containers::StaticArray<38, std::int32_t>{ValueInit}; _selectedArmourAccessories = Containers::StaticArray<38, std::int32_t>{ValueInit}; _selectedBLPlacement = 0; _selectedWeaponPart = 0; _selectedWeaponDecal = 0; _selectedWeaponAccessory = 0; } ImGui::EndTable(); } ImGui::EndMenuBar(); } ImGui::TextColored(ImColor(255, 255, 0), ICON_FA_EXCLAMATION_TRIANGLE); ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); ImGui::TextWrapped("WARNING: Colours in this app may look different from in-game colours, due to unavoidable differences in the rendering pipeline."); ImGui::TextColored(ImColor(255, 255, 0), ICON_FA_EXCLAMATION_TRIANGLE); ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); ImGui::TextWrapped("Real-time updates are disabled on this screen."); if(_currentMass) { if(ImGui::BeginTabBar("##MassTabBar")) { if(ImGui::BeginTabItem("Frame")) { drawFrameInfo(); ImGui::EndTabItem(); } if(ImGui::BeginTabItem("Custom frame styles")) { drawCustomFrameStyles(); ImGui::EndTabItem(); } if(ImGui::BeginTabItem("Armour")) { drawArmour(); ImGui::EndTabItem(); } if(_currentMass->bulletLauncherAttachmentStyle() != GameObjects::BulletLauncherAttachmentStyle::NotFound && ImGui::BeginTabItem("Bullet launcher attachment")) { drawBLAttachment(); ImGui::EndTabItem(); } if(ImGui::BeginTabItem("Custom armour styles")) { drawCustomArmourStyles(); ImGui::EndTabItem(); } if(ImGui::BeginTabItem("Weapons")) { drawWeapons(); ImGui::EndTabItem(); } if(!_currentMass->globalStyles().isEmpty() && ImGui::BeginTabItem("Global styles")) { drawGlobalStyles(); ImGui::EndTabItem(); } #ifdef SAVETOOL_DEBUG_BUILD if(ImGui::BeginTabItem("Tuning (WIP)")) { drawTuning(); ImGui::EndTabItem(); } #endif ImGui::EndTabBar(); } } } ImGui::EndChild(); ImGui::End(); } void Application::drawGlobalStyles() { if(!_currentMass || _currentMass->state() != GameObjects::Mass::State::Valid) { return; } if(!ImGui::BeginChild("##GlobalStyles")) { ImGui::EndChild(); return; } ImGui::TextWrapped("In-game values are multiplied by 100. For example, 0.500 here is equal to 50 in-game."); for(std::uint32_t i = 0; i < _currentMass->globalStyles().size(); i++) { ImGui::PushID(int(i)); DCSResult result; result = drawCustomStyle(_currentMass->globalStyles()[i]); switch(result) { case DCS_ResetStyle: _currentMass->getGlobalStyles(); break; case DCS_Save: _modifiedBySaveTool = true; if(!_currentMass->writeGlobalStyle(i)) { _modifiedBySaveTool = false; _queue.addToast(Toast::Type::Error, _currentMass->lastError()); } break; default: break; } ImGui::PopID(); } ImGui::EndChild(); } void Application::drawTuning() { if(!_currentMass || _currentMass->state() != GameObjects::Mass::State::Valid) { return; } if(!ImGui::BeginTable("##TuningTable", 3)) { return; } ImGui::TableSetupColumn("##EngineColumn"); ImGui::TableSetupColumn("##OSColumn"); ImGui::TableSetupColumn("##ArchitectureColumn"); ImGui::TableNextRow(); ImGui::TableSetColumnIndex(0); if(ImGui::BeginTable("##EngineTable", 1, ImGuiTableFlags_Borders)) { ImGui::TableSetupColumn("##Engine"); ImGui::TableNextRow(ImGuiTableRowFlags_Headers); ImGui::TableNextColumn(); ImGui::TextUnformatted("Engine"); ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::Text("%i", _currentMass->engine()); ImGui::TableNextRow(ImGuiTableRowFlags_Headers); ImGui::TableNextColumn(); ImGui::TextUnformatted("Gears"); for(std::uint32_t i = 0; i < _currentMass->gears().size(); i++) { ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::Text("%i", _currentMass->gears()[i]); } ImGui::EndTable(); } ImGui::TableSetColumnIndex(1); if(ImGui::BeginTable("##OSTable", 1, ImGuiTableFlags_Borders)) { ImGui::TableSetupColumn("##OS"); ImGui::TableNextRow(ImGuiTableRowFlags_Headers); ImGui::TableNextColumn(); ImGui::TextUnformatted("OS"); ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::Text("%i", _currentMass->os()); ImGui::TableNextRow(ImGuiTableRowFlags_Headers); ImGui::TableNextColumn(); ImGui::TextUnformatted("Modules"); for(std::uint32_t i = 0; i < _currentMass->modules().size(); i++) { ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::Text("%i", _currentMass->modules()[i]); } ImGui::EndTable(); } ImGui::TableSetColumnIndex(2); if(ImGui::BeginTable("##ArchTable", 1, ImGuiTableFlags_Borders)) { ImGui::TableSetupColumn("##Arch"); ImGui::TableNextRow(ImGuiTableRowFlags_Headers); ImGui::TableNextColumn(); ImGui::TextUnformatted("Architecture"); ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::Text("%i", _currentMass->architecture()); ImGui::TableNextRow(ImGuiTableRowFlags_Headers); ImGui::TableNextColumn(); ImGui::TextUnformatted("Techs"); for(std::uint32_t i = 0; i < _currentMass->techs().size(); i++) { ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::Text("%i", _currentMass->techs()[i]); } ImGui::EndTable(); } ImGui::EndTable(); } Application::DCSResult Application::drawCustomStyle(GameObjects::CustomStyle& style) { if(!_currentMass || _currentMass->state() != GameObjects::Mass::State::Valid) { return DCS_Fail; } ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, {8.0f, 0.0f}); Containers::ScopeGuard guard{[]{ ImGui::PopStyleVar(); }}; DCSResult return_value = DCS_Fail; if(!ImGui::BeginChild("##CustomStyle", {}, ImGuiChildFlags_Border|ImGuiChildFlags_AutoResizeY, ImGuiWindowFlags_MenuBar)) { ImGui::EndChild(); return DCS_Fail; } if(ImGui::BeginMenuBar()) { ImGui::TextUnformatted(style.name.data()); static Containers::StaticArray<33, char> name_buf{ValueInit}; if(ImGui::SmallButton(ICON_FA_EDIT " Rename")) { for(auto& c : name_buf) { c = '\0'; } std::strncpy(name_buf.data(), style.name.data(), 32); ImGui::OpenPopup("name_edit"); } if(drawRenamePopup(name_buf)) { style.name = name_buf.data(); } ImGui::EndMenuBar(); } if(ImGui::BeginTable("##StyleTable", 2, ImGuiTableFlags_BordersInnerV)) { ImGui::TableSetupColumn("##Colour", ImGuiTableColumnFlags_WidthStretch); ImGui::TableSetupColumn("##Pattern", ImGuiTableColumnFlags_WidthStretch); ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::BeginGroup(); drawAlignedText("Colour:"); drawAlignedText("Metallic:"); drawAlignedText("Gloss:"); drawAlignedText("Glow:"); ImGui::EndGroup(); ImGui::SameLine(); ImGui::BeginGroup(); ImGui::ColorEdit3("##Picker", &style.colour.r()); ImGui::SameLine(); drawHelpMarker("Right-click for more option, click the coloured square for the full picker."); ImGui::SetNextItemWidth(-FLT_MIN); ImGui::SliderFloat("##SliderMetallic", &style.metallic, 0.0f, 1.0f); ImGui::SetNextItemWidth(-FLT_MIN); ImGui::SliderFloat("##SliderGloss", &style.gloss,0.0f, 1.0f); ImGui::Checkbox("##Glow", &style.glow); ImGui::EndGroup(); ImGui::TableNextColumn(); ImGui::BeginGroup(); drawAlignedText("Pattern:"); drawAlignedText("Opacity:"); drawAlignedText("X offset:"); drawAlignedText("Y offset:"); drawAlignedText("Rotation:"); drawAlignedText("Scale:"); ImGui::EndGroup(); ImGui::SameLine(); ImGui::BeginGroup(); drawAlignedText("%i", style.patternId); ImGui::PushItemWidth(-FLT_MIN); ImGui::SliderFloat("##SliderOpacity", &style.opacity, 0.0f, 1.0f); ImGui::SliderFloat("##SliderOffsetX", &style.offset.x(), 0.0f, 1.0f); ImGui::SliderFloat("##SliderOffsetY", &style.offset.y(), 0.0f, 1.0f); ImGui::SliderFloat("##SliderRotation", &style.rotation, 0.0f, 1.0f); ImGui::SliderFloat("##SliderScale", &style.scale, 0.0f, 1.0f); ImGui::PopItemWidth(); ImGui::EndGroup(); ImGui::EndTable(); } if(drawUnsafeWidget([]{ return ImGui::Button(ICON_FA_SAVE " Save"); })) { return_value = DCS_Save; } ImGui::SameLine(); if(ImGui::Button(ICON_FA_UNDO " Reset")) { return_value = DCS_ResetStyle; } ImGui::EndChild(); return return_value; } void Application::drawDecalEditor(GameObjects::Decal& decal) { ImGui::Text("ID: %i", decal.id); if(ImGui::BeginTable("##DecalTable", conf().advancedMode() ? 2 : 1, ImGuiTableFlags_BordersInnerV)) { ImGui::TableSetupColumn("##Normal", ImGuiTableColumnFlags_WidthStretch); if(conf().advancedMode()) { ImGui::TableSetupColumn("##Advanced", ImGuiTableColumnFlags_WidthStretch); } ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::BeginGroup(); drawAlignedText("Colour:"); drawAlignedText("Offset:"); drawAlignedText("Rotation:"); drawAlignedText("Scale:"); drawAlignedText("Flip X:"); drawAlignedText("Surface wrap:"); ImGui::EndGroup(); ImGui::SameLine(); ImGui::BeginGroup(); ImGui::ColorEdit3("##Picker", &decal.colour.r()); ImGui::SameLine(); drawHelpMarker("Right-click for more option, click the coloured square for the full picker."); ImGui::PushMultiItemsWidths(2, ImGui::CalcItemWidth()); ImGui::SliderFloat("##OffsetX", &decal.offset.x(), 0.0f, 1.0f, "X: %.3f"); ImGui::PopItemWidth(); ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); ImGui::SliderFloat("##OffsetY", &decal.offset.y(), 0.0f, 1.0f, "Y: %.3f"); ImGui::PopItemWidth(); ImGui::SameLine(); drawHelpMarker("0.0 = -100 in-game\n1.0 = 100 in-game"); ImGui::SliderFloat("##Rotation", &decal.rotation, 0.0f, 1.0f); ImGui::SameLine(); drawHelpMarker("0.0 = 0 in-game\n1.0 = 360 in-game"); ImGui::SliderFloat("##Scale", &decal.scale, 0.0f, 1.0f); ImGui::SameLine(); drawHelpMarker("0.0 = 1 in-game\n1.0 = 100 in-game"); ImGui::Checkbox("##Flip", &decal.flip); ImGui::Checkbox("##Wrap", &decal.wrap); ImGui::EndGroup(); if(conf().advancedMode()) { ImGui::TableNextColumn(); ImGui::TextColored(ImColor(255, 255, 0), ICON_FA_EXCLAMATION_TRIANGLE); ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); ImGui::TextUnformatted("Advanced settings. Touch these at your own risk."); ImGui::BeginGroup(); drawAlignedText("Position:"); drawAlignedText("U axis:"); drawAlignedText("V axis:"); ImGui::EndGroup(); ImGui::SameLine(); ImGui::BeginGroup(); ImGui::PushItemWidth(-1.0f); ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth()); ImGui::DragFloat("##PosX", &decal.position.x(), 1.0f, -FLT_MAX, +FLT_MAX, "X: %.3f"); ImGui::PopItemWidth(); ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); ImGui::DragFloat("##PosY", &decal.position.y(), 1.0f, -FLT_MAX, +FLT_MAX, "Y: %.3f"); ImGui::PopItemWidth(); ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); ImGui::DragFloat("##PosZ", &decal.position.z(), 1.0f, -FLT_MAX, +FLT_MAX, "Z: %.3f"); ImGui::PopItemWidth(); ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth()); ImGui::DragFloat("##UX", &decal.uAxis.x(), 1.0f, -FLT_MAX, +FLT_MAX, "X: %.3f"); ImGui::PopItemWidth(); ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); ImGui::DragFloat("##UY", &decal.uAxis.y(), 1.0f, -FLT_MAX, +FLT_MAX, "Y: %.3f"); ImGui::PopItemWidth(); ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); ImGui::DragFloat("##UZ", &decal.uAxis.z(), 1.0f, -FLT_MAX, +FLT_MAX, "Z: %.3f"); ImGui::PopItemWidth(); ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth()); ImGui::DragFloat("##VX", &decal.vAxis.x(), 1.0f, -FLT_MAX, +FLT_MAX, "X: %.3f"); ImGui::PopItemWidth(); ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); ImGui::DragFloat("##VY", &decal.vAxis.y(), 1.0f, -FLT_MAX, +FLT_MAX, "Y: %.3f"); ImGui::PopItemWidth(); ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); ImGui::DragFloat("##VZ", &decal.vAxis.z(), 1.0f, -FLT_MAX, +FLT_MAX, "Z: %.3f"); ImGui::PopItemWidth(); ImGui::PopItemWidth(); ImGui::EndGroup(); } ImGui::EndTable(); } } void Application::drawAccessoryEditor(GameObjects::Accessory& accessory, Containers::ArrayView style_view) { if(accessory.id < 1) { ImGui::TextUnformatted("Accessory: "); } else if(GameData::accessories.find(accessory.id) != GameData::accessories.cend()) { ImGui::Text("Accessory #%.4i - %s", accessory.id, GameData::accessories.at(accessory.id).name.data()); } else { ImGui::Text("Accessory #%i", accessory.id); drawTooltip("WARNING: accessory mapping is a WIP."); } ImGui::SameLine(); static std::int32_t tab = 0; static Containers::Optional size = Containers::NullOpt; if(ImGui::SmallButton("Change")) { ImGui::OpenPopup("##AccessoryPopup"); if(accessory.id >= 3000) { tab = 3; } else if(accessory.id >= 2000) { tab = 2; } else if(accessory.id >= 1000) { tab = 1; } else { tab = 0; } } if(ImGui::BeginPopup("##AccessoryPopup")) { static const char* size_labels[] = { "S", "M", "L", "XL" }; static const float selectable_width = 90.0f; ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, {0.5f, 0.0f}); if(ImGui::Selectable("Primitives", tab == 0, ImGuiSelectableFlags_DontClosePopups, {selectable_width, 0.0f})) { tab = 0; } ImGui::SameLine(); ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical); ImGui::SameLine(); if(ImGui::Selectable("Armours", tab == 1, ImGuiSelectableFlags_DontClosePopups, {selectable_width, 0.0f})) { tab = 1; } ImGui::SameLine(); ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical); ImGui::SameLine(); if(ImGui::Selectable("Components", tab == 2, ImGuiSelectableFlags_DontClosePopups, {selectable_width, 0.0f})) { tab = 2; } ImGui::SameLine(); ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical); ImGui::SameLine(); if(ImGui::Selectable("Connectors", tab == 3, ImGuiSelectableFlags_DontClosePopups, {selectable_width, 0.0f})) { tab = 3; } ImGui::PopStyleVar(); ImGui::Separator(); ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, {0.5f, 0.0f}); if(ImGui::Selectable("All", !size, ImGuiSelectableFlags_DontClosePopups, {70.0f, 0.0f})) { size = Containers::NullOpt; } ImGui::SameLine(); ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical); ImGui::SameLine(); if(ImGui::Selectable("S", size && *size == GameData::Accessory::Size::S, ImGuiSelectableFlags_DontClosePopups, {70.0f, 0.0f})) { if(!size) { size.emplace(); } *size = GameData::Accessory::Size::S; } ImGui::SameLine(); ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical); ImGui::SameLine(); if(ImGui::Selectable("M", size && *size == GameData::Accessory::Size::M, ImGuiSelectableFlags_DontClosePopups, {70.0f, 0.0f})) { if(!size) { size.emplace(); } *size = GameData::Accessory::Size::M; } ImGui::SameLine(); ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical); ImGui::SameLine(); if(ImGui::Selectable("L", size && *size == GameData::Accessory::Size::L, ImGuiSelectableFlags_DontClosePopups, {70.0f, 0.0f})) { if(!size) { size.emplace(); } *size = GameData::Accessory::Size::L; } ImGui::SameLine(); ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical); ImGui::SameLine(); if(ImGui::Selectable("XL", size && *size == GameData::Accessory::Size::XL, ImGuiSelectableFlags_DontClosePopups, {70.0f, 0.0f})) { if(!size) { size.emplace(); } *size = GameData::Accessory::Size::XL; } ImGui::PopStyleVar(); ImGui::Separator(); if(ImGui::BeginListBox("##AccessoryListbox", {-1.0f, 0.0f})) { for(const auto& acc : GameData::accessories) { if(acc.first >= tab * 1000 && acc.first < ((tab + 1) * 1000) && (!size || *size == acc.second.size)) { if(ImGui::Selectable(Utility::format("#{:.4d} - {} ({})", acc.first, acc.second.name, size_labels[acc.second.size]).data(), acc.first == accessory.id)) { accessory.id = acc.first; accessory.attachIndex = 0; } if(acc.first == accessory.id) { ImGui::SetItemDefaultFocus(); } } } ImGui::EndListBox(); } ImGui::EndPopup(); } if(accessory.id > 0) { ImGui::SameLine(); if(ImGui::SmallButton("Unequip")) { accessory.id = 0; accessory.attachIndex = -1; } } ImGui::BeginGroup(); drawAlignedText("Styles:"); if(conf().advancedMode()) { drawAlignedText("Base position:"); } drawAlignedText("Position offset:"); if(conf().advancedMode()) { drawAlignedText("Base rotation:"); } drawAlignedText("Rotation offset:"); drawAlignedText("Scale:"); ImGui::EndGroup(); ImGui::SameLine(); ImGui::BeginGroup(); ImGui::PushMultiItemsWidths(2, ImGui::CalcItemWidth()); if(ImGui::BeginCombo("##Style1", getStyleName(accessory.styles[0], style_view).data())) { for(const auto& style : GameData::style_names) { if(ImGui::Selectable(getStyleName(style.first, style_view).data(), accessory.styles[0] == style.first)) { accessory.styles[0] = style.first; } } ImGui::EndCombo(); } ImGui::PopItemWidth(); ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); if(ImGui::BeginCombo("##Style2", getStyleName(accessory.styles[1], style_view).data())) { for(const auto& style : GameData::style_names) { if(ImGui::Selectable(getStyleName(style.first, style_view).data(), accessory.styles[1] == style.first)) { accessory.styles[1] = style.first; } } ImGui::EndCombo(); } ImGui::PopItemWidth(); if(conf().advancedMode()) { ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth()); ImGui::DragFloat("##PosX", &accessory.relativePosition.x(), 1.0f, -FLT_MAX, +FLT_MAX, "X: %.3f"); ImGui::PopItemWidth(); ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); ImGui::DragFloat("##PosY", &accessory.relativePosition.y(), 1.0f, -FLT_MAX, +FLT_MAX, "Y: %.3f"); ImGui::PopItemWidth(); ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); ImGui::DragFloat("##PosZ", &accessory.relativePosition.z(), 1.0f, -FLT_MAX, +FLT_MAX, "Z: %.3f"); ImGui::PopItemWidth(); } ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth()); ImGui::SliderFloat("##PosOffsetX", &accessory.relativePositionOffset.x(), -500.0f, +500.0f, "X: %.3f"); ImGui::PopItemWidth(); ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); ImGui::SliderFloat("##PosOffsetY", &accessory.relativePositionOffset.y(), -500.0f, +500.0f, "Y: %.3f"); ImGui::PopItemWidth(); ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); ImGui::SliderFloat("##PosOffsetZ", &accessory.relativePositionOffset.z(), -500.0f, +500.0f, "Z: %.3f"); ImGui::PopItemWidth(); ImGui::SameLine(); drawHelpMarker("+/-500.0 = +/-250 in-game"); if(conf().advancedMode()) { ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth()); ImGui::DragFloat("##RotX", &accessory.relativeRotation.x(), 1.0f, -FLT_MAX, +FLT_MAX, "Roll: %.3f"); ImGui::PopItemWidth(); ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); ImGui::DragFloat("##RotY", &accessory.relativeRotation.y(), 1.0f, -FLT_MAX, +FLT_MAX, "Yaw: %.3f"); ImGui::PopItemWidth(); ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); ImGui::DragFloat("##RotZ", &accessory.relativeRotation.z(), 1.0f, -FLT_MAX, +FLT_MAX, "Pitch: %.3f"); ImGui::PopItemWidth(); } ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth()); ImGui::SliderFloat("##RotOffsetX", &accessory.relativeRotationOffset.x(), -180.0f, +180.0f, "Roll: %.3f"); ImGui::PopItemWidth(); ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); ImGui::SliderFloat("##RotOffsetY", &accessory.relativeRotationOffset.y(), -180.0f, +180.0f, "Yaw: %.3f"); ImGui::PopItemWidth(); ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); ImGui::SliderFloat("##RotOffsetZ", &accessory.relativeRotationOffset.z(), -180.0f, +180.0f, "Pitch: %.3f"); ImGui::PopItemWidth(); ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth()); ImGui::SliderFloat("##ScaleX", &accessory.localScale.x(), -3.0f, +3.0f, "X: %.3f"); ImGui::PopItemWidth(); ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); ImGui::SliderFloat("##ScaleY", &accessory.localScale.y(), -3.0f, +3.0f, "Y: %.3f"); ImGui::PopItemWidth(); ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); ImGui::SliderFloat("##ScaleZ", &accessory.localScale.z(), -3.0f, +3.0f, "Z: %.3f"); ImGui::PopItemWidth(); ImGui::SameLine(); drawHelpMarker("+/-3.0 = +/-150 in-game"); ImGui::EndGroup(); } Containers::StringView Application::getStyleName(std::int32_t id, Containers::ArrayView view) { if(id >= 0 && id <= 15) { return view[id].name; } else if(id >= 50 && id <= 65) { return _currentMass->globalStyles()[id - 50].name; } else { return GameData::style_names.at(id); } } }