Merge pull request #13759 from jordan-woyak/calibrate-autocomplete

DolphinQt: Make Calibration autocomplete when data is "sensible" and stick is returned to neutral position.
This commit is contained in:
JMC47
2025-06-24 18:22:48 -04:00
committed by GitHub
4 changed files with 45 additions and 19 deletions

View File

@ -980,12 +980,17 @@ void CalibrationWidget::DrawInProgressCalibration(QPainter& p, Common::DVec2 poi
const auto elapsed_seconds = GetAnimationElapsedSeconds();
const auto stop_spinning_amount =
std::max(DT_s{m_stop_spinning_time - Clock::now()} / STOP_SPINNING_DURATION, 0.0);
const auto stick_pushed_amount =
QEasingCurve(QEasingCurve::OutCirc).valueForProgress(std::min(elapsed_seconds * 2, 1.0)) *
stop_spinning_amount;
// Clockwise spinning stick starting from center.
p.save();
p.rotate(elapsed_seconds * -360.0);
DrawPushedStick(
p, m_indicator,
-QEasingCurve(QEasingCurve::OutCirc).valueForProgress(std::min(elapsed_seconds * 2, 1.0)));
DrawPushedStick(p, m_indicator, -stick_pushed_amount);
p.restore();
const auto center = m_calibrator->GetCenter();
@ -1031,8 +1036,6 @@ void ReshapableInputIndicator::SetCalibrationWidget(CalibrationWidget* widget)
m_calibration_widget = widget;
}
CalibrationWidget::~CalibrationWidget() = default;
CalibrationWidget::CalibrationWidget(MappingWidget& mapping_widget,
ControllerEmu::ReshapableInput& input,
ReshapableInputIndicator& indicator)
@ -1132,13 +1135,7 @@ void CalibrationWidget::StartCalibration(std::optional<Common::DVec2> center)
// i18n: A button to finalize a game controller calibration process.
auto* const finish_action = new QAction(tr("Finish Calibration"), this);
connect(finish_action, &QAction::triggered, this, [this]() {
const auto lock = m_mapping_widget.GetController()->GetStateLock();
m_calibrator->ApplyResults(&m_input);
ResetActions();
});
connect(this, &CalibrationWidget::CalibrationIsSensible, finish_action,
[this, finish_action]() { setDefaultAction(finish_action); });
connect(finish_action, &QAction::triggered, this, &CalibrationWidget::FinishCalibration);
DeleteAllActions();
@ -1147,6 +1144,13 @@ void CalibrationWidget::StartCalibration(std::optional<Common::DVec2> center)
setDefaultAction(cancel_action);
}
void CalibrationWidget::FinishCalibration()
{
const auto lock = m_mapping_widget.GetController()->GetStateLock();
m_calibrator->ApplyResults(&m_input);
ResetActions();
}
void CalibrationWidget::Update(Common::DVec2 point)
{
// FYI: The "StateLock" is always held when this is called.
@ -1194,9 +1198,14 @@ void CalibrationWidget::Update(Common::DVec2 point)
else if (IsCalibrating())
{
m_calibrator->Update(point);
if (m_calibrator->IsCalibrationDataSensible())
if (!m_calibrator->IsCalibrationDataSensible())
{
emit CalibrationIsSensible();
m_stop_spinning_time = Clock::now() + STOP_SPINNING_DURATION;
}
else if (m_calibrator->IsComplete())
{
FinishCalibration();
}
}
else if (IsPointOutsideCalibration(point, m_input))

View File

@ -6,6 +6,7 @@
#include <QToolButton>
#include <QWidget>
#include <chrono>
#include <deque>
#include "Core/HW/WiimoteEmu/Dynamics.h"
@ -238,11 +239,9 @@ private:
class CalibrationWidget : public QToolButton
{
Q_OBJECT
public:
CalibrationWidget(MappingWidget& mapping_widget, ControllerEmu::ReshapableInput& input,
ReshapableInputIndicator& indicator);
~CalibrationWidget() override;
void Update(Common::DVec2 point);
@ -250,9 +249,6 @@ public:
bool IsActive() const;
signals:
void CalibrationIsSensible();
private:
void DrawInProgressMapping(QPainter& p);
void DrawInProgressCalibration(QPainter& p, Common::DVec2 point);
@ -263,6 +259,8 @@ private:
void StartMappingAndCalibration();
void StartCalibration(std::optional<Common::DVec2> center = Common::DVec2{});
void FinishCalibration();
void ResetActions();
void DeleteAllActions();
@ -277,4 +275,8 @@ private:
void RestartAnimation();
Clock::time_point m_animation_start_time{};
static constexpr auto STOP_SPINNING_DURATION = std::chrono::seconds{2};
Clock::time_point m_stop_spinning_time{};
};

View File

@ -5,6 +5,7 @@
#include <algorithm>
#include <chrono>
#include <cmath>
#include <ranges>
#include <string>
#include <vector>
@ -277,6 +278,16 @@ bool CalibrationBuilder::IsCalibrationDataSensible() const
return stats.StandardDeviation() < REASONABLE_DEVIATION;
}
bool CalibrationBuilder::IsComplete() const
{
if (!IsCalibrationDataSensible())
return false;
const auto half_calibration =
0.5 * GetCalibrationRadiusAtAngle(std::atan2(m_prev_point.y, m_prev_point.x) + MathUtil::TAU);
return m_prev_point.LengthSquared() < (half_calibration * half_calibration);
}
ControlState CalibrationBuilder::GetCalibrationRadiusAtAngle(double angle) const
{
return ControllerEmu::ReshapableInput::GetCalibrationDataRadiusAtAngle(m_calibration_data, angle);

View File

@ -85,6 +85,10 @@ public:
// Used to update the UI to encourage the user to click the "Finish" button.
bool IsCalibrationDataSensible() const;
// Returns true when the calibration data seems sensible,
// and the input then approaches the center position.
bool IsComplete() const;
// Grabs the calibration value at the provided angle.
// Used to render the calibration in the UI while it's in progress.
ControlState GetCalibrationRadiusAtAngle(double angle) const;