// MassBuilderSaveTool
// Copyright (C) 2021-2022 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 "../Maps/Accessories.h"
#include "../Maps/ArmourSets.h"
#include "../Maps/StyleNames.h"
#include "../FontAwesome/IconsFontAwesome5.h"
#include "SaveTool.h"
static Weapon* current_weapon = nullptr;
void SaveTool::drawMassViewer() {
if(!_currentMass || _currentMass->state() != Mass::State::Valid) {
_currentMass = nullptr;
current_weapon = 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({Float(windowSize().x()), Float(windowSize().y()) - ImGui::GetItemRectSize().y},
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},
true, 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()).c_str());
drawTooltip(_currentMass->filename().c_str());
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)) {
current_weapon = nullptr;
_currentMass = nullptr;
_uiState = UiState::MainManager;
_jointsDirty = false;
_stylesDirty = false;
_eyeFlareDirty = false;
_selectedArmourDecals = Containers::StaticArray<38, Int>{ValueInit};
_selectedArmourAccessories = Containers::StaticArray<38, Int>{ValueInit};
_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 parts")) {
drawArmour();
ImGui::EndTabItem();
}
if(ImGui::BeginTabItem("Custom armour styles")) {
drawCustomArmourStyles();
ImGui::EndTabItem();
}
if(ImGui::BeginTabItem("Weapons (WIP)")) {
drawWeapons();
ImGui::EndTabItem();
}
if(!_currentMass->globalStyles().size() != 0 && ImGui::BeginTabItem("Global styles")) {
drawGlobalStyles();
ImGui::EndTabItem();
}
if(ImGui::BeginTabItem("Tuning (WIP)")) {
drawTuning();
ImGui::EndTabItem();
}
ImGui::EndTabBar();
}
}
}
ImGui::EndChild();
ImGui::End();
}
void SaveTool::drawFrameInfo() {
if(!_currentMass || _currentMass->state() != Mass::State::Valid) {
return;
}
if(!ImGui::BeginChild("##FrameInfo")) {
ImGui::EndChild();
return;
}
ImGui::BeginGroup();
if(ImGui::BeginChild("##JointSliders", {(ImGui::GetContentRegionAvailWidth() / 2.0f) - (ImGui::GetStyle().WindowPadding.x / 2.0f), 300.0f}, true, ImGuiWindowFlags_MenuBar)) {
if(ImGui::BeginMenuBar()) {
ImGui::TextUnformatted("Joint sliders");
ImGui::EndMenuBar();
}
drawJointSliders();
}
ImGui::EndChild();
if(ImGui::BeginChild("##FrameStyles", {(ImGui::GetContentRegionAvailWidth() / 2.0f) - (ImGui::GetStyle().WindowPadding.x / 2.0f), 0.0f}, true, ImGuiWindowFlags_MenuBar)) {
if(ImGui::BeginMenuBar()) {
ImGui::TextUnformatted("Frame styles");
ImGui::EndMenuBar();
}
drawFrameStyles();
}
ImGui::EndChild();
ImGui::EndGroup();
ImGui::SameLine();
if(ImGui::BeginChild("##EyeFlare", {0.0f, 0.0f}, true, ImGuiWindowFlags_MenuBar)) {
if(ImGui::BeginMenuBar()) {
ImGui::TextUnformatted("Eye flare colour");
drawHelpMarker("Right-click the picker for more options.", 250.0f);
ImGui::EndMenuBar();
}
drawEyeColourPicker();
}
ImGui::EndChild();
ImGui::EndChild();
}
void SaveTool::drawJointSliders() {
if(!_currentMass || _currentMass->state() != Mass::State::Valid) {
return;
}
ImGui::TextWrapped("In-game values are multiplied by 100.\nFor example, 0.500 here is equal to 50 in-game.");
if(ImGui::BeginTable("##JointSliderTable", 2, ImGuiTableFlags_Borders)) {
ImGui::TableSetupColumn("##SliderLabel", ImGuiTableColumnFlags_WidthFixed);
ImGui::TableSetupColumn("##Sliders", ImGuiTableColumnFlags_WidthStretch);
ImGui::TableNextRow();
ImGui::TableSetColumnIndex(0);
ImGui::AlignTextToFramePadding();
ImGui::TextUnformatted("Neck");
ImGui::TableSetColumnIndex(1);
ImGui::SetNextItemWidth(-1.0f);
if(ImGui::SliderFloat("##NeckSlider", &_currentMass->jointSliders().neck, 0.0f, 1.0f)) {
_jointsDirty = true;
}
ImGui::TableNextRow();
ImGui::TableSetColumnIndex(0);
ImGui::AlignTextToFramePadding();
ImGui::TextUnformatted("Body");
ImGui::TableSetColumnIndex(1);
ImGui::SetNextItemWidth(-1.0f);
if(ImGui::SliderFloat("##BodySlider", &_currentMass->jointSliders().body, 0.0f, 1.0f)) {
_jointsDirty = true;
}
ImGui::TableNextRow();
ImGui::TableSetColumnIndex(0);
ImGui::AlignTextToFramePadding();
ImGui::TextUnformatted("Shoulders");
ImGui::TableSetColumnIndex(1);
ImGui::SetNextItemWidth(-1.0f);
if(ImGui::SliderFloat("##ShouldersSlider", &_currentMass->jointSliders().shoulders, 0.0f, 1.0f)) {
_jointsDirty = true;
}
ImGui::TableNextRow();
ImGui::TableSetColumnIndex(0);
ImGui::AlignTextToFramePadding();
ImGui::TextUnformatted("Hips");
ImGui::TableSetColumnIndex(1);
ImGui::SetNextItemWidth(-1.0f);
if(ImGui::SliderFloat("##HipsSlider", &_currentMass->jointSliders().hips, 0.0f, 1.0f)) {
_jointsDirty = true;
}
ImGui::TableNextRow();
ImGui::TableSetColumnIndex(0);
ImGui::AlignTextToFramePadding();
ImGui::TextUnformatted("Arms");
ImGui::TableSetColumnIndex(1);
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2{2.0f, 1.0f});
if(ImGui::BeginTable("##UpperLowerArmsLayoutTable", 2)) {
ImGui::TableSetupColumn("##UpperArms", ImGuiTableColumnFlags_WidthStretch);
ImGui::TableSetupColumn("##LowerArms", ImGuiTableColumnFlags_WidthStretch);
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(-1.0f);
if(ImGui::SliderFloat("##UpperArmsSlider", &_currentMass->jointSliders().upperArms, 0.0f, 1.0f, "Upper: %.3f")) {
_jointsDirty = true;
}
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(-1.0f);
if(ImGui::SliderFloat("##LowerArmsSlider", &_currentMass->jointSliders().lowerArms, 0.0f, 1.0f, "Lower: %.3f")) {
_jointsDirty = true;
}
ImGui::EndTable();
}
ImGui::PopStyleVar();
ImGui::TableNextRow();
ImGui::TableSetColumnIndex(0);
ImGui::AlignTextToFramePadding();
ImGui::TextUnformatted("Legs");
ImGui::TableSetColumnIndex(1);
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2{2.0f, 1.0f});
if(ImGui::BeginTable("##UpperLowerLegsLayoutTable", 2)) {
ImGui::TableSetupColumn("##UpperLegs", ImGuiTableColumnFlags_WidthStretch);
ImGui::TableSetupColumn("##LowerLegs", ImGuiTableColumnFlags_WidthStretch);
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(-1.0f);
if(ImGui::SliderFloat("##UpperLegsSlider", &_currentMass->jointSliders().upperLegs, 0.0f, 1.0f, "Upper: %.3f")) {
_jointsDirty = true;
}
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(-1.0f);
if(ImGui::SliderFloat("##LowerLegsSlider", &_currentMass->jointSliders().lowerLegs, 0.0f, 1.0f, "Lower: %.3f")) {
_jointsDirty = true;
}
ImGui::EndTable();
}
ImGui::PopStyleVar();
ImGui::EndTable();
}
if(!_jointsDirty) {
ImGui::BeginDisabled();
ImGui::Button(ICON_FA_SAVE " Save");
ImGui::SameLine();
ImGui::Button(ICON_FA_UNDO " Reset");
ImGui::EndDisabled();
}
else {
if(drawUnsafeWidget([]{ return ImGui::Button(ICON_FA_SAVE " Save"); })) {
if(!_currentMass->writeJointSliders()) {
_queue.addToast(Toast::Type::Error, "Error: " + Mass::lastError());
}
_jointsDirty = false;
}
ImGui::SameLine();
if(ImGui::Button(ICON_FA_UNDO " Reset")) {
_currentMass->getJointSliders();
_jointsDirty = false;
}
}
}
void SaveTool::drawFrameStyles() {
if(!_currentMass || _currentMass->state() != Mass::State::Valid) {
return;
}
for(Int i = 0; i < 4; i++) {
ImGui::AlignTextToFramePadding();
ImGui::Text("Slot %d:", i + 1);
ImGui::SameLine();
ImGui::PushID(i);
if(ImGui::BeginCombo("##Style", getStyleName(_currentMass->frameStyles()[i], _currentMass->frameCustomStyles()))) {
for(const auto& style : style_names) {
if(ImGui::Selectable(getStyleName(style.first, _currentMass->frameCustomStyles()), _currentMass->frameStyles()[i] == style.first)) {
_currentMass->frameStyles()[i] = style.first;
_stylesDirty = true;
}
}
ImGui::EndCombo();
}
ImGui::PopID();
}
if(!_stylesDirty) {
ImGui::BeginDisabled();
ImGui::Button(ICON_FA_SAVE " Save");
ImGui::SameLine();
ImGui::Button(ICON_FA_UNDO " Reset");
ImGui::EndDisabled();
}
else {
if(drawUnsafeWidget([]{ return ImGui::Button(ICON_FA_SAVE " Save"); })) {
if(!_currentMass->writeFrameStyles()) {
_queue.addToast(Toast::Type::Error, "Error: " + Mass::lastError());
}
_stylesDirty = false;
}
ImGui::SameLine();
if(ImGui::Button(ICON_FA_UNDO " Reset")) {
_currentMass->getFrameStyles();
_stylesDirty = false;
}
}
}
void SaveTool::drawEyeColourPicker() {
if(!_currentMass || _currentMass->state() != Mass::State::Valid) {
return;
}
if(ImGui::ColorPicker3("##EyeFlarePicker", &_currentMass->eyeFlareColour().x())) {
_eyeFlareDirty = true;
}
if(!_eyeFlareDirty) {
ImGui::BeginDisabled();
ImGui::Button(ICON_FA_SAVE " Save");
ImGui::SameLine();
ImGui::Button(ICON_FA_UNDO " Reset");
ImGui::EndDisabled();
}
else {
if(drawUnsafeWidget([]{ return ImGui::Button(ICON_FA_SAVE " Save"); })) {
if(!_currentMass->writeEyeFlareColour()) {
_queue.addToast(Toast::Type::Error, "Error writing the eye flare colour.");
}
_eyeFlareDirty = false;
}
ImGui::SameLine();
if(ImGui::Button(ICON_FA_UNDO " Reset")) {
_currentMass->getEyeFlareColour();
_eyeFlareDirty = false;
}
}
}
void SaveTool::drawCustomFrameStyles() {
if(!_currentMass || _currentMass->state() != Mass::State::Valid) {
return;
}
if(!ImGui::BeginChild("##FrameStyles")) {
ImGui::EndChild();
return;
}
ImGui::TextWrapped("In-game values are multiplied by 100. For example, 0.500 here is equal to 50 in-game.");
for(UnsignedInt i = 0; i < _currentMass->frameCustomStyles().size(); i++) {
ImGui::PushID(i);
DCSResult result;
result = drawCustomStyle(_currentMass->frameCustomStyles()[i]);
switch(result) {
case DCS_ResetStyle:
_currentMass->getFrameCustomStyles();
break;
case DCS_Save:
_currentMass->writeFrameCustomStyle(i);
break;
default:
break;
}
ImGui::PopID();
}
ImGui::EndChild();
}
void SaveTool::drawArmour() {
if(!_currentMass || _currentMass->state() != Mass::State::Valid) {
return;
}
if(ImGui::Button(ICON_FA_UNDO_ALT " Reset all")) {
_currentMass->getArmourParts();
}
if(!ImGui::BeginChild("##ArmourParts")) {
ImGui::EndChild();
return;
}
static const char* slot_labels[] = {
#define c(enumerator, strenum, name) name,
#include "../Maps/ArmourSlots.hpp"
#undef c
};
for(UnsignedInt i = 0; i < _currentMass->armourParts().size(); i++) {
ImGui::PushID(i);
auto& part = _currentMass->armourParts()[i];
static char header[129] = {'\0'};
std::memset(header, '\0', 129);
if(armour_sets.find(part.id) != armour_sets.cend()) {
std::snprintf(header, 128, "%s: %s###%u", slot_labels[UnsignedInt(part.slot)], armour_sets.at(part.id).name, UnsignedInt(part.slot));
}
else {
std::snprintf(header, 128, "%s: %i###%u", slot_labels[UnsignedInt(part.slot)], part.id, UnsignedInt(part.slot));
}
if(ImGui::CollapsingHeader(header)) {
ImGui::BeginGroup();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvailWidth() * 0.491f);
if(ImGui::BeginListBox("##ChangePart")) {
if(std::strncmp("Neck", slot_labels[UnsignedInt(part.slot)], 4) != 0) {
for(auto& set : armour_sets) {
if(ImGui::Selectable(set.second.name, set.first == part.id, ImGuiSelectableFlags_SpanAvailWidth)) {
part.id = set.first;
}
}
}
else {
for(auto& set : armour_sets) {
if(!set.second.neck_compatible) {
continue;
}
if(ImGui::Selectable(set.second.name, set.first == part.id, ImGuiSelectableFlags_SpanAvailWidth)) {
part.id = set.first;
}
}
}
ImGui::EndListBox();
}
ImGui::EndGroup();
ImGui::SameLine();
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
ImGui::SameLine();
ImGui::BeginGroup();
ImGui::TextUnformatted("Styles:");
for(Int j = 0; j < 4; j++) {
ImGui::AlignTextToFramePadding();
ImGui::Text("Slot %d:", j + 1);
ImGui::SameLine();
ImGui::PushID(j);
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvailWidth() - 2.0f);
if(ImGui::BeginCombo("##Style", getStyleName(part.styles[j], _currentMass->armourCustomStyles()))) {
for(const auto& style : style_names) {
if(ImGui::Selectable(getStyleName(style.first, _currentMass->armourCustomStyles()), part.styles[j] == style.first)) {
part.styles[j] = style.first;
}
}
ImGui::EndCombo();
}
ImGui::PopID();
}
ImGui::EndGroup();
ImGui::Separator();
ImGui::PushID("Decal");
ImGui::AlignTextToFramePadding();
ImGui::TextUnformatted("Showing/editing decal");
for(UnsignedLong j = 0; j < part.decals.size(); j++) {
ImGui::SameLine();
ImGui::RadioButton(std::to_string(j + 1).c_str(), &_selectedArmourDecals[i], j);
}
drawDecalEditor(part.decals[_selectedArmourDecals[i]]);
ImGui::PopID();
if(!part.accessories.size()) {
ImGui::Separator();
ImGui::PushID("Accessory");
ImGui::AlignTextToFramePadding();
ImGui::TextUnformatted("Showing/editing accessory");
for(UnsignedInt j = 0; j < part.accessories.size(); j++) {
ImGui::SameLine();
ImGui::RadioButton(std::string{char(65 + j)}.c_str(), &_selectedArmourAccessories[i], j);
}
drawAccessoryEditor(part.accessories[_selectedArmourAccessories[i]], _currentMass->armourCustomStyles());
ImGui::PopID();
}
ImGui::Separator();
if(drawUnsafeWidget([]{ return ImGui::Button(ICON_FA_SAVE " Save"); })) {
_currentMass->writeArmourPart(part.slot);
}
}
ImGui::PopID();
}
ImGui::EndChild();
}
void SaveTool::drawCustomArmourStyles() {
if(!_currentMass || _currentMass->state() != Mass::State::Valid) {
return;
}
if(!ImGui::BeginChild("##ArmourStyles")) {
ImGui::EndChild();
return;
}
ImGui::TextWrapped("In-game values are multiplied by 100. For example, 0.500 here is equal to 50 in-game.");
for(UnsignedInt i = 0; i < _currentMass->armourCustomStyles().size(); i++) {
ImGui::PushID(i);
DCSResult result;
result = drawCustomStyle(_currentMass->armourCustomStyles()[i]);
switch(result) {
case DCS_ResetStyle:
_currentMass->getArmourCustomStyles();
break;
case DCS_Save:
_currentMass->writeArmourCustomStyle(i);
break;
default:
break;
}
ImGui::PopID();
}
ImGui::EndChild();
}
void SaveTool::drawWeapons() {
if(!_currentMass || _currentMass->state() != Mass::State::Valid) {
current_weapon = nullptr;
return;
}
const Float footer_height_to_reserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing();
ImGui::BeginGroup();
if(!ImGui::BeginTable("##WeaponsList", 1,
ImGuiTableFlags_ScrollY|ImGuiTableFlags_BordersOuter|ImGuiTableFlags_BordersInnerH,
{ImGui::GetContentRegionAvailWidth() * 0.2f, -footer_height_to_reserve}))
{
return;
}
ImGui::TableSetupColumn("Weapon");
int id = 0;
#define weapcat(header, array, dirty, payload_type, payload_tooltip) \
ImGui::TableNextRow(ImGuiTableRowFlags_Headers); \
ImGui::TableNextColumn(); \
ImGui::TextUnformatted(header); \
\
for(UnsignedInt i = 0; i < _currentMass->array().size(); i++) { \
auto& weapon = _currentMass->array()[i]; \
\
ImGui::TableNextRow(); \
ImGui::TableNextColumn(); \
ImGui::PushID(id); \
if(ImGui::Selectable(weapon.name.c_str(), current_weapon == &weapon)) { \
current_weapon = &weapon; \
} \
if(ImGui::BeginDragDropSource()) { \
ImGui::SetDragDropPayload(payload_type, &i, sizeof(UnsignedInt)); \
if(ImGui::GetIO().KeyCtrl) { \
ImGui::Text(payload_tooltip " %i - %s (copy)", i + 1, weapon.name.c_str()); \
} \
else { \
ImGui::Text(payload_tooltip " %i - %s", i + 1, weapon.name.c_str()); \
} \
ImGui::EndDragDropSource(); \
} \
if(ImGui::BeginDragDropTarget()) { \
if(const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(payload_type)) { \
int index = *static_cast(payload->Data); \
\
if(!ImGui::GetIO().KeyCtrl) { \
if(current_weapon == &_currentMass->array()[index]) { \
current_weapon = &_currentMass->array()[i]; \
} \
else if (current_weapon == &_currentMass->array()[i]) { \
current_weapon = &_currentMass->array()[index]; \
} \
\
std::swap(_currentMass->array()[index], _currentMass->array()[i]); \
} \
else { \
_currentMass->array()[i] = _currentMass->array()[index]; \
} \
(dirty) = true; \
} \
\
ImGui::EndDragDropTarget(); \
} \
\
ImGui::PopID(); \
id++; \
\
if(weapon.attached == true) { \
ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, 0x1F008CFFu); \
} \
}
weapcat("Melee weapons", meleeWeapons, _meleeDirty, "MeleeWeapon", "Melee weapon")
weapcat("Shield", shields, _shieldsDirty, "Shield", "Shield")
weapcat("Bullet shooters", bulletShooters, _bShootersDirty, "BShooter", "Bullet shooter")
weapcat("Energy shooters", energyShooters, _eShootersDirty, "EShooter", "Energy shooter")
weapcat("Bullet launchers", bulletLaunchers, _bLaunchersDirty, "BLauncher", "Bullet launcher")
weapcat("Energy launchers", energyLaunchers, _eLaunchersDirty, "ELauncher", "Energy launcher")
#undef weapcat
ImGui::EndTable();
bool dirty = _meleeDirty || _shieldsDirty || _bShootersDirty || _eShootersDirty || _bLaunchersDirty || _eLaunchersDirty;
if(!dirty) {
ImGui::BeginDisabled();
}
if(drawUnsafeWidget([]{ return ImGui::Button(ICON_FA_SAVE " Save"); })) {
if(_meleeDirty) {
_currentMass->writeMeleeWeapons();
_meleeDirty = false;
}
if(_shieldsDirty) {
_currentMass->writeShields();
_shieldsDirty = false;
}
if(_bShootersDirty) {
_currentMass->writeBulletShooters();
_bShootersDirty = false;
}
if(_eShootersDirty) {
_currentMass->writeEnergyShooters();
_eShootersDirty = false;
}
if(_bLaunchersDirty) {
_currentMass->writeBulletLaunchers();
_bLaunchersDirty = false;
}
if(_eLaunchersDirty) {
_currentMass->writeEnergyLaunchers();
_eLaunchersDirty = false;
}
}
ImGui::SameLine();
if(ImGui::Button(ICON_FA_UNDO_ALT " Reset")) {
if(_meleeDirty) {
_currentMass->getMeleeWeapons();
_meleeDirty = false;
}
if(_shieldsDirty) {
_currentMass->getShields();
_shieldsDirty = false;
}
if(_bShootersDirty) {
_currentMass->getBulletShooters();
_bShootersDirty = false;
}
if(_eShootersDirty) {
_currentMass->getEnergyShooters();
_eShootersDirty = false;
}
if(_bLaunchersDirty) {
_currentMass->getBulletLaunchers();
_bLaunchersDirty = false;
}
if(_eLaunchersDirty) {
_currentMass->getEnergyLaunchers();
_eLaunchersDirty = false;
}
}
if(!dirty) {
ImGui::EndDisabled();
}
ImGui::EndGroup();
ImGui::SameLine();
if(!current_weapon) {
ImGui::TextUnformatted("No weapon selected.");
return;
}
ImGui::BeginGroup();
if(!ImGui::BeginChild("##WeaponChild", {0.0f, -footer_height_to_reserve})) {
ImGui::EndChild();
return;
}
drawWeaponEditor(*current_weapon);
ImGui::EndChild();
ImGui::Separator();
if(drawUnsafeWidget([](){ return ImGui::Button(ICON_FA_SAVE " Save changes to weapon category"); })) {
switch(current_weapon->type) {
case WeaponType::Melee:
if(!_currentMass->writeMeleeWeapons()) {
_queue.addToast(Toast::Type::Error, "Couldn't save melee weapons");
}
break;
case WeaponType::Shield:
if(!_currentMass->writeShields()) {
_queue.addToast(Toast::Type::Error, "Couldn't save shields");
}
break;
case WeaponType::BulletShooter:
if(!_currentMass->writeBulletShooters()) {
_queue.addToast(Toast::Type::Error, "Couldn't save bullet shooters");
}
break;
case WeaponType::EnergyShooter:
if(!_currentMass->writeEnergyShooters()) {
_queue.addToast(Toast::Type::Error, "Couldn't save energy shooters");
}
break;
case WeaponType::BulletLauncher:
if(!_currentMass->writeBulletLaunchers()) {
_queue.addToast(Toast::Type::Error, "Couldn't save bullet launchers");
}
break;
case WeaponType::EnergyLauncher:
if(!_currentMass->writeEnergyLaunchers()) {
_queue.addToast(Toast::Type::Error, "Couldn't save energy launchers");
}
break;
default:
_queue.addToast(Toast::Type::Error, "Unknown weapon type");
}
}
ImGui::SameLine();
if(ImGui::Button(ICON_FA_UNDO_ALT " Reset weapon category")) {
switch(current_weapon->type) {
case WeaponType::Melee:
_currentMass->getMeleeWeapons();
break;
case WeaponType::Shield:
_currentMass->getShields();
break;
case WeaponType::BulletShooter:
_currentMass->getBulletShooters();
break;
case WeaponType::EnergyShooter:
_currentMass->getEnergyShooters();
break;
case WeaponType::BulletLauncher:
_currentMass->getBulletLaunchers();
break;
case WeaponType::EnergyLauncher:
_currentMass->getEnergyLaunchers();
break;
default:
_queue.addToast(Toast::Type::Error, "Unknown weapon type");
}
}
ImGui::EndGroup();
}
void SaveTool::drawWeaponEditor(Weapon& weapon) {
if(!_currentMass || _currentMass->state() != Mass::State::Valid || !current_weapon) {
return;
}
ImGui::AlignTextToFramePadding();
static const char* labels[] {
#define c(enumerator, strenum, name) name,
#include "../Maps/WeaponTypes.hpp"
#undef c
};
ImGui::Text("%s: %s", labels[UnsignedInt(weapon.type)], weapon.name.c_str());
ImGui::SameLine();
static Containers::StaticArray<33, char> name_buf{ValueInit};
if(ImGui::Button(ICON_FA_EDIT " Rename")) {
for(auto& c : name_buf) {
c = '\0';
}
std::strncpy(name_buf.data(), weapon.name.c_str(), 32);
ImGui::OpenPopup("name_edit");
}
if(drawRenamePopup(name_buf)) {
weapon.name = name_buf.data();
}
ImGui::BeginGroup();
ImGui::AlignTextToFramePadding();
ImGui::TextUnformatted("Equipped:");
if(weapon.type != WeaponType::Shield) {
ImGui::AlignTextToFramePadding();
ImGui::TextUnformatted("Damage type:");
}
if(weapon.type == WeaponType::Melee) {
ImGui::AlignTextToFramePadding();
ImGui::TextUnformatted("Dual-wield:");
ImGui::AlignTextToFramePadding();
ImGui::TextUnformatted("Custom effect mode:");
ImGui::AlignTextToFramePadding();
ImGui::TextUnformatted("Custom effect colour:");
}
ImGui::EndGroup();
ImGui::SameLine();
ImGui::BeginGroup();
ImGui::Checkbox("##EquippedCheckbox", &weapon.attached);
if(weapon.type != WeaponType::Shield) {
if(weapon.type == WeaponType::Melee &&
ImGui::RadioButton("Physical##NoElement", weapon.damageType == DamageType::Physical))
{
weapon.damageType = DamageType::Physical;
}
else if((weapon.type == WeaponType::BulletShooter || weapon.type == WeaponType::BulletLauncher) &&
ImGui::RadioButton("Piercing##NoElement", weapon.damageType == DamageType::Piercing))
{
weapon.damageType = DamageType::Piercing;
}
else if((weapon.type == WeaponType::EnergyShooter || weapon.type == WeaponType::EnergyLauncher) &&
ImGui::RadioButton("Plasma##NoElement", weapon.damageType == DamageType::Plasma))
{
weapon.damageType = DamageType::Plasma;
}
ImGui::SameLine();
if(ImGui::RadioButton("Heat##Heat", weapon.damageType == DamageType::Heat)) {
weapon.damageType = DamageType::Heat;
}
ImGui::SameLine();
if(ImGui::RadioButton("Freeze##Freeze", weapon.damageType == DamageType::Freeze)) {
weapon.damageType = DamageType::Freeze;
}
ImGui::SameLine();
if(ImGui::RadioButton("Shock##Shock", weapon.damageType == DamageType::Freeze)) {
weapon.damageType = DamageType::Freeze;
}
}
if(weapon.type == WeaponType::Melee) {
ImGui::Checkbox("##DualWield", &weapon.dualWield);
if(ImGui::RadioButton("Default##Default", weapon.effectColourMode == "enuWeaponEffectColorMode::NewEnumerator0")) {
weapon.effectColourMode = "enuWeaponEffectColorMode::NewEnumerator0";
}
ImGui::SameLine();
if(ImGui::RadioButton("Custom##Custom", weapon.effectColourMode == "enuWeaponEffectColorMode::NewEnumerator1")) {
weapon.effectColourMode = "enuWeaponEffectColorMode::NewEnumerator1";
}
bool custom_effect = (weapon.effectColourMode == "enuWeaponEffectColorMode::NewEnumerator1");
if(!custom_effect) {
ImGui::BeginDisabled();
}
ImGui::ColorEdit3("##CustomEffectColourPicker", &weapon.effectColour.x(), ImGuiColorEditFlags_HDR|ImGuiColorEditFlags_Float);
if(!custom_effect) {
ImGui::EndDisabled();
}
}
ImGui::EndGroup();
ImGui::Separator();
if(ImGui::CollapsingHeader("Weapon parts")) {
ImGui::AlignTextToFramePadding();
ImGui::TextUnformatted("Viewing/editing part:");
for(Int i = 0; UnsignedLong(i) < weapon.parts.size(); i++) {
if(UnsignedLong(_selectedWeaponPart) >= weapon.parts.size()) {
_selectedWeaponPart = 0;
}
ImGui::SameLine();
ImGui::RadioButton(std::to_string(i + 1).c_str(), &_selectedWeaponPart, i);
}
auto& part = weapon.parts[_selectedWeaponPart];
ImGui::Text("ID: %i", part.id);
if(ImGui::BeginChild("##PartDetails", {0.0f, 0.0f}, true)) {
ImGui::TextUnformatted("Styles:");
for(Int i = 0; i < 4; i++) {
ImGui::AlignTextToFramePadding();
ImGui::Text("Slot %d:", i + 1);
ImGui::SameLine();
ImGui::PushID(i);
if(ImGui::BeginCombo("##Style", getStyleName(part.styles[i], weapon.customStyles))) {
for(const auto& style: style_names) {
if(ImGui::Selectable(getStyleName(style.first, weapon.customStyles),
part.styles[i] == style.first)) {
part.styles[i] = style.first;
}
}
ImGui::EndCombo();
}
ImGui::PopID();
}
ImGui::Separator();
ImGui::PushID("Decal");
ImGui::AlignTextToFramePadding();
ImGui::TextUnformatted("Showing/editing decal");
for(UnsignedLong i = 0; i < part.decals.size(); i++) {
ImGui::SameLine();
ImGui::RadioButton(std::to_string(i + 1).c_str(), &_selectedWeaponDecal, i);
}
drawDecalEditor(part.decals[_selectedWeaponDecal]);
ImGui::PopID();
if(part.accessories.size() != 0) {
ImGui::Separator();
ImGui::PushID("Accessory");
ImGui::AlignTextToFramePadding();
ImGui::TextUnformatted("Showing/editing accessory");
for(UnsignedLong i = 0; i < part.accessories.size(); i++) {
ImGui::SameLine();
ImGui::RadioButton(std::string{char(65 + i)}.c_str(), &_selectedWeaponAccessory, i);
}
drawAccessoryEditor(part.accessories[_selectedWeaponAccessory], weapon.customStyles);
ImGui::PopID();
}
}
ImGui::EndChild();
}
}
void SaveTool::drawGlobalStyles() {
if(!_currentMass || _currentMass->state() != 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(UnsignedInt i = 0; i < _currentMass->globalStyles().size(); i++) {
ImGui::PushID(i);
DCSResult result;
result = drawCustomStyle(_currentMass->globalStyles()[i]);
switch(result) {
case DCS_ResetStyle:
_currentMass->getGlobalStyles();
break;
case DCS_Save:
_currentMass->writeGlobalStyle(i);
break;
default:
break;
}
ImGui::PopID();
}
ImGui::EndChild();
}
void SaveTool::drawTuning() {
if(!_currentMass || _currentMass->state() != 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(UnsignedInt 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(UnsignedInt 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(UnsignedInt i = 0; i < _currentMass->techs().size(); i++) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("%i", _currentMass->techs()[i]);
}
ImGui::EndTable();
}
ImGui::EndTable();
}
auto SaveTool::drawCustomStyle(CustomStyle& style) -> DCSResult {
if(!_currentMass || _currentMass->state() != 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", {0.0f, 244.0f}, true, ImGuiWindowFlags_MenuBar)) {
ImGui::EndChild();
return DCS_Fail;
}
if(ImGui::BeginMenuBar()) {
ImGui::TextUnformatted(style.name.c_str());
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.c_str(), 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();
ImGui::AlignTextToFramePadding();
ImGui::TextUnformatted("Colour:");
ImGui::AlignTextToFramePadding();
ImGui::TextUnformatted("Metallic:");
ImGui::AlignTextToFramePadding();
ImGui::TextUnformatted("Gloss:");
ImGui::AlignTextToFramePadding();
ImGui::TextUnformatted("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();
ImGui::AlignTextToFramePadding();
ImGui::TextUnformatted("Pattern:");
ImGui::AlignTextToFramePadding();
ImGui::TextUnformatted("Opacity:");
ImGui::AlignTextToFramePadding();
ImGui::TextUnformatted("X offset:");
ImGui::AlignTextToFramePadding();
ImGui::TextUnformatted("Y offset:");
ImGui::AlignTextToFramePadding();
ImGui::TextUnformatted("Rotation:");
ImGui::AlignTextToFramePadding();
ImGui::TextUnformatted("Scale:");
ImGui::EndGroup();
ImGui::SameLine();
ImGui::BeginGroup();
ImGui::AlignTextToFramePadding();
ImGui::Text("%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 SaveTool::drawDecalEditor(Decal& decal) {
ImGui::Text("ID: %i", decal.id);
if(ImGui::BeginTable("##DecalTable", 2, ImGuiTableFlags_BordersInnerV)) {
ImGui::TableSetupColumn("##Normal", ImGuiTableColumnFlags_WidthStretch);
ImGui::TableSetupColumn("##Advanced", ImGuiTableColumnFlags_WidthStretch);
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::BeginGroup();
ImGui::AlignTextToFramePadding();
ImGui::TextUnformatted("Colour:");
ImGui::AlignTextToFramePadding();
ImGui::TextUnformatted("Offset:");
ImGui::AlignTextToFramePadding();
ImGui::TextUnformatted("Rotation:");
ImGui::AlignTextToFramePadding();
ImGui::TextUnformatted("Scale:");
ImGui::AlignTextToFramePadding();
ImGui::TextUnformatted("Flip X:");
ImGui::AlignTextToFramePadding();
ImGui::TextUnformatted("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();
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();
ImGui::AlignTextToFramePadding();
ImGui::TextUnformatted("Position:");
ImGui::AlignTextToFramePadding();
ImGui::TextUnformatted("U axis:");
ImGui::AlignTextToFramePadding();
ImGui::TextUnformatted("V axis:");
ImGui::EndGroup();
ImGui::SameLine();
ImGui::BeginGroup();
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::EndGroup();
ImGui::EndTable();
}
}
void SaveTool::drawAccessoryEditor(Accessory& accessory, Containers::ArrayView style_view) {
if(accessory.id < 1) {
ImGui::TextUnformatted("Accessory: ");
}
else if(accessories.find(accessory.id) != accessories.cend()) {
ImGui::Text("Accessory #%i - %s", accessory.id, accessories.at(accessory.id));
}
else {
ImGui::Text("Accessory #%i", accessory.id);
drawTooltip("WARNING: accessory mapping is a WIP.");
}
#ifdef SAVETOOL_DEBUG_BUILD
ImGui::SameLine(0.0f, ImGui::GetStyle().FramePadding.x * 5.0f);
ImGui::Text("Attach index: %i", accessory.attachIndex);
#endif
ImGui::BeginGroup();
ImGui::AlignTextToFramePadding();
ImGui::TextUnformatted("Styles:");
ImGui::AlignTextToFramePadding();
ImGui::TextUnformatted("Base position:");
ImGui::AlignTextToFramePadding();
ImGui::TextUnformatted("Position offset:");
ImGui::AlignTextToFramePadding();
ImGui::TextUnformatted("Base rotation:");
ImGui::AlignTextToFramePadding();
ImGui::TextUnformatted("Rotation offset:");
ImGui::AlignTextToFramePadding();
ImGui::TextUnformatted("Scale:");
ImGui::EndGroup();
ImGui::SameLine();
ImGui::BeginGroup();
ImGui::PushMultiItemsWidths(2, ImGui::CalcItemWidth());
if(ImGui::BeginCombo("##Style1", getStyleName(accessory.styles[0], style_view))) {
for(const auto& style : style_names) {
if(ImGui::Selectable(getStyleName(style.first, style_view), 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))) {
for(const auto& style : style_names) {
if(ImGui::Selectable(getStyleName(style.first, style_view), accessory.styles[1] == style.first)) {
accessory.styles[1] = style.first;
}
}
ImGui::EndCombo();
}
ImGui::PopItemWidth();
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");
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();
}
auto SaveTool::getStyleName(Int id, Containers::ArrayView view) -> const char* {
if(id >= 0 && id <= 15) {
return view[id].name.c_str();
}
else if(id >= 50 && id <= 65) {
return _currentMass->globalStyles()[id - 50].name.c_str();
}
else {
return style_names.at(id);
}
}