#pragma once #include "Core.h" #include #include #include #include namespace XCEngine { namespace Editor { namespace UI { struct AxisFloatControlSpec { const char* label = nullptr; float* value = nullptr; }; inline bool DrawAxisFloatControls( const AxisFloatControlSpec* axes, int axisCount, float dragSpeed, bool useResetButtons, float resetValue, bool* isActive = nullptr ) { bool changed = false; bool anyItemActive = false; ImGui::PushStyleVar( ImGuiStyleVar_ItemSpacing, useResetButtons ? VectorAxisControlSpacing() : VectorAxisInputSpacing()); const float availableWidth = ImGui::GetContentRegionAvail().x; const float spacing = ImGui::GetStyle().ItemSpacing.x; if (useResetButtons) { const float lineHeight = ImGui::GetFontSize() + ImGui::GetStyle().FramePadding.y * 2.0f; const ImVec2 buttonSize(lineHeight + VectorAxisResetButtonExtraWidth(), lineHeight); float itemWidth = (availableWidth - buttonSize.x * static_cast(axisCount)) / static_cast(axisCount); if (itemWidth < 0.0f) { itemWidth = 0.0f; } const ImVec4 buttonColor = VectorAxisButtonColor(); const ImVec4 buttonHoverColor = VectorAxisButtonHoveredColor(); for (int i = 0; i < axisCount; ++i) { ImGui::PushStyleColor(ImGuiCol_Button, buttonColor); ImGui::PushStyleColor(ImGuiCol_ButtonHovered, buttonHoverColor); ImGui::PushStyleColor(ImGuiCol_ButtonActive, buttonColor); if (ImGui::Button(axes[i].label, buttonSize)) { *axes[i].value = resetValue; changed = true; } ImGui::PopStyleColor(3); ImGui::SameLine(); ImGui::SetNextItemWidth(itemWidth); if (ImGui::DragFloat((std::string("##") + axes[i].label).c_str(), axes[i].value, dragSpeed, 0.0f, 0.0f, "%.2f")) { changed = true; } anyItemActive = anyItemActive || ImGui::IsItemActive(); if (i + 1 < axisCount) { ImGui::SameLine(); } } } else { const float axisLabelWidth = ImGui::CalcTextSize("Z").x; float itemWidth = (availableWidth - axisLabelWidth * static_cast(axisCount) - spacing * static_cast(axisCount * 2 - 1)) / static_cast(axisCount); if (itemWidth < 0.0f) { itemWidth = 0.0f; } for (int i = 0; i < axisCount; ++i) { ImGui::AlignTextToFramePadding(); ImGui::TextDisabled("%s", axes[i].label); ImGui::SameLine(); ImGui::SetNextItemWidth(itemWidth); if (ImGui::DragFloat((std::string("##") + axes[i].label).c_str(), axes[i].value, dragSpeed, 0.0f, 0.0f, "%.2f")) { changed = true; } anyItemActive = anyItemActive || ImGui::IsItemActive(); if (i + 1 < axisCount) { ImGui::SameLine(); } } } ImGui::PopStyleVar(); if (isActive) { *isActive = anyItemActive; } return changed; } inline bool DrawVec3Input( const char* label, ::XCEngine::Math::Vector3& values, float columnWidth = DefaultControlLabelWidth(), float dragSpeed = 0.1f, bool* isActive = nullptr ) { const AxisFloatControlSpec axes[] = { { "X", &values.x }, { "Y", &values.y }, { "Z", &values.z } }; return DrawControlRow(label, columnWidth, [&]() { return DrawAxisFloatControls(axes, 3, dragSpeed, false, 0.0f, isActive); }); } inline bool DrawVec3( const char* label, ::XCEngine::Math::Vector3& values, float resetValue = 0.0f, float columnWidth = DefaultControlLabelWidth(), float dragSpeed = 0.1f, bool* isActive = nullptr ) { const AxisFloatControlSpec axes[] = { { "X", &values.x }, { "Y", &values.y }, { "Z", &values.z } }; return DrawControlRow(label, columnWidth, [&]() { return DrawAxisFloatControls(axes, 3, dragSpeed, true, resetValue, isActive); }); } inline bool DrawVec2( const char* label, ::XCEngine::Math::Vector2& values, float resetValue = 0.0f, float columnWidth = DefaultControlLabelWidth(), float dragSpeed = 0.1f ) { const AxisFloatControlSpec axes[] = { { "X", &values.x }, { "Y", &values.y } }; return DrawControlRow(label, columnWidth, [&]() { return DrawAxisFloatControls(axes, 2, dragSpeed, true, resetValue); }); } } } }