diff --git a/Source/Core/DolphinQt/Config/Mapping/IOWindow.cpp b/Source/Core/DolphinQt/Config/Mapping/IOWindow.cpp index b4dd1aa54a..aa0f1efa0d 100644 --- a/Source/Core/DolphinQt/Config/Mapping/IOWindow.cpp +++ b/Source/Core/DolphinQt/Config/Mapping/IOWindow.cpp @@ -544,7 +544,7 @@ void InputStateDelegate::paint(QPainter* painter, const QStyleOptionViewItem& op rect.setWidth(rect.width() * std::clamp(state, 0.0, 1.0)); // Create a temporary indicator object to retreive color constants. - MappingIndicator indicator(nullptr); + MappingIndicator indicator; painter->save(); diff --git a/Source/Core/DolphinQt/Config/Mapping/MappingIndicator.cpp b/Source/Core/DolphinQt/Config/Mapping/MappingIndicator.cpp index e6549e48d6..f29555c2ef 100644 --- a/Source/Core/DolphinQt/Config/Mapping/MappingIndicator.cpp +++ b/Source/Core/DolphinQt/Config/Mapping/MappingIndicator.cpp @@ -37,11 +37,32 @@ const QColor TILT_GATE_COLOR = 0xa2d9ce; const QColor SWING_GATE_COLOR = 0xcea2d9; constexpr int INPUT_DOT_RADIUS = 2; + +constexpr int NORMAL_INDICATOR_WIDTH = 100; +constexpr int NORMAL_INDICATOR_HEIGHT = 100; +constexpr int NORMAL_INDICATOR_PADDING = 2; + +// Per trigger. +constexpr int TRIGGER_INDICATOR_HEIGHT = 32; + +QPen GetCosmeticPen(QPen pen) +{ + pen.setCosmetic(true); + return pen; +} + +QPen GetInputDotPen(QPen pen) +{ + pen.setWidth(INPUT_DOT_RADIUS * 2); + pen.setCapStyle(Qt::PenCapStyle::RoundCap); + return GetCosmeticPen(pen); +} + } // namespace QPen MappingIndicator::GetBBoxPen() const { - return palette().shadow().color(); + return QPen(palette().shadow().color(), 0); } QBrush MappingIndicator::GetBBoxBrush() const @@ -51,18 +72,18 @@ QBrush MappingIndicator::GetBBoxBrush() const QColor MappingIndicator::GetRawInputColor() const { - return palette().shadow().color(); + QColor color = palette().text().color(); + color.setAlphaF(0.5); + return color; } QPen MappingIndicator::GetInputShapePen() const { - return QPen{GetRawInputColor(), 1.0, Qt::DashLine}; + return QPen{GetRawInputColor(), 0.0, Qt::DashLine}; } QColor MappingIndicator::GetAdjustedInputColor() const { - // Using highlight color works (typically blue) but the contrast is pretty low. - // return palette().highlight().color(); return Qt::red; } @@ -80,12 +101,14 @@ QColor MappingIndicator::GetDeadZoneColor() const QPen MappingIndicator::GetDeadZonePen() const { - return GetDeadZoneColor(); + return QPen(GetDeadZoneColor(), 0); } -QBrush MappingIndicator::GetDeadZoneBrush() const +QBrush MappingIndicator::GetDeadZoneBrush(QPainter& painter) const { - return QBrush{GetDeadZoneColor(), Qt::BDiagPattern}; + QBrush brush{GetDeadZoneColor(), Qt::FDiagPattern}; + brush.setTransform(painter.transform().inverted()); + return brush; } QColor MappingIndicator::GetTextColor() const @@ -105,20 +128,17 @@ void MappingIndicator::AdjustGateColor(QColor* color) color->setHsvF(color->hueF(), color->saturationF(), 1 - color->valueF()); } -MappingIndicator::MappingIndicator(ControllerEmu::ControlGroup* group) : m_group(group) +SquareIndicator::SquareIndicator() { - // TODO: Make these magic numbers less ugly. - int required_height = 106; - - if (group && ControllerEmu::GroupType::MixedTriggers == group->type) - required_height = 64 + 1; - - setFixedHeight(required_height); + // Additional pixel for border. + setFixedWidth(NORMAL_INDICATOR_WIDTH + (NORMAL_INDICATOR_PADDING + 1) * 2); + setFixedHeight(NORMAL_INDICATOR_HEIGHT + (NORMAL_INDICATOR_PADDING + 1) * 2); } -double MappingIndicator::GetScale() const +MixedTriggersIndicator::MixedTriggersIndicator(ControllerEmu::MixedTriggers& group) : m_group(group) { - return height() / 2 - 2; + setSizePolicy(QSizePolicy::Policy::Expanding, QSizePolicy::Policy::Ignored); + setFixedHeight(TRIGGER_INDICATOR_HEIGHT * int(group.GetTriggerCount()) + 1); } namespace @@ -129,8 +149,7 @@ constexpr int SPHERE_POINT_COUNT = 200; // Constructs a polygon by querying a radius at varying angles: template -QPolygonF GetPolygonFromRadiusGetter(F&& radius_getter, double scale, - Common::DVec2 center = {0.0, 0.0}) +QPolygonF GetPolygonFromRadiusGetter(F&& radius_getter, Common::DVec2 center = {0.0, 0.0}) { // A multiple of 8 (octagon) and enough points to be visibly pleasing: constexpr int shape_point_count = 32; @@ -140,10 +159,9 @@ QPolygonF GetPolygonFromRadiusGetter(F&& radius_getter, double scale, for (auto& point : shape) { const double angle = MathUtil::TAU * p / shape.size(); - const double radius = radius_getter(angle) * scale; + const double radius = radius_getter(angle); - point = {std::cos(angle) * radius + center.x * scale, - std::sin(angle) * radius + center.y * scale}; + point = {std::cos(angle) * radius + center.x, std::sin(angle) * radius + center.y}; ++p; } @@ -209,194 +227,142 @@ void GenerateFibonacciSphere(int point_count, F&& callback) } // namespace -void MappingIndicator::DrawCursor(ControllerEmu::Cursor& cursor) +void MappingIndicator::paintEvent(QPaintEvent*) { - const auto center = cursor.GetCenter(); + const auto lock = ControllerEmu::EmulatedController::GetStateLock(); + Draw(); +} - QColor tv_brush_color = CURSOR_TV_COLOR; - QColor tv_pen_color = tv_brush_color.darker(125); +void CursorIndicator::Draw() +{ + const auto adj_coord = m_cursor_group.GetState(true); - AdjustGateColor(&tv_brush_color); - AdjustGateColor(&tv_pen_color); + DrawReshapableInput(m_cursor_group, CURSOR_TV_COLOR, + adj_coord.IsVisible() ? + std::make_optional(Common::DVec2(adj_coord.x, adj_coord.y)) : + std::nullopt); +} - const auto raw_coord = cursor.GetState(false); - const auto adj_coord = cursor.GetState(true); +qreal SquareIndicator::GetContentsScale() const +{ + return (NORMAL_INDICATOR_WIDTH - 1.0) / 2; +} - UpdateCalibrationWidget({raw_coord.x, raw_coord.y}); - - // Bounding box size: - const double scale = GetScale(); - - QPainter p(this); - p.translate(width() / 2, height() / 2); - - // Bounding box. +void SquareIndicator::DrawBoundingBox(QPainter& p) +{ p.setBrush(GetBBoxBrush()); p.setPen(GetBBoxPen()); - p.drawRect(-scale - 1, -scale - 1, scale * 2 + 1, scale * 2 + 1); + p.drawRect(QRectF{NORMAL_INDICATOR_PADDING + 0.5, NORMAL_INDICATOR_PADDING + 0.5, + NORMAL_INDICATOR_WIDTH + 1.0, NORMAL_INDICATOR_HEIGHT + 1.0}); +} - // UI y-axis is opposite that of stick. - p.scale(1.0, -1.0); - - // Enable AA after drawing bounding box. +void SquareIndicator::TransformPainter(QPainter& p) +{ p.setRenderHint(QPainter::Antialiasing, true); p.setRenderHint(QPainter::SmoothPixmapTransform, true); - if (IsCalibrating()) - { - DrawCalibration(p, {raw_coord.x, raw_coord.y}); - return; - } - - // TV screen or whatever you want to call this: - constexpr double TV_SCALE = 0.75; - - p.setPen(tv_pen_color); - p.setBrush(tv_brush_color); - p.drawPolygon(GetPolygonFromRadiusGetter( - [&cursor](double ang) { return cursor.GetGateRadiusAtAngle(ang); }, scale * TV_SCALE)); - - // Deadzone. - p.setPen(GetDeadZonePen()); - p.setBrush(GetDeadZoneBrush()); - p.drawPolygon(GetPolygonFromRadiusGetter( - [&cursor](double ang) { return cursor.GetDeadzoneRadiusAtAngle(ang); }, scale, center)); - - // Input shape. - p.setPen(GetInputShapePen()); - p.setBrush(Qt::NoBrush); - p.drawPolygon(GetPolygonFromRadiusGetter( - [&cursor](double ang) { return cursor.GetInputRadiusAtAngle(ang); }, scale, center)); - - // Center. - if (center.x || center.y) - { - p.setPen(Qt::NoPen); - p.setBrush(GetCenterColor()); - p.drawEllipse(QPointF{center.x, center.y} * scale, INPUT_DOT_RADIUS, INPUT_DOT_RADIUS); - } - - // Raw stick position. - p.setPen(Qt::NoPen); - p.setBrush(GetRawInputColor()); - p.drawEllipse(QPointF{raw_coord.x, raw_coord.y} * scale, INPUT_DOT_RADIUS, INPUT_DOT_RADIUS); - - // Adjusted cursor position (if not hidden): - if (adj_coord.IsVisible()) - { - p.setPen(Qt::NoPen); - p.setBrush(GetAdjustedInputColor()); - p.drawEllipse(QPointF{adj_coord.x, adj_coord.y} * scale * TV_SCALE, INPUT_DOT_RADIUS, - INPUT_DOT_RADIUS); - } + p.translate(width() / 2, height() / 2); + const auto scale = GetContentsScale(); + p.scale(scale, scale); } -void MappingIndicator::DrawReshapableInput(ControllerEmu::ReshapableInput& stick) +void ReshapableInputIndicator::DrawReshapableInput( + ControllerEmu::ReshapableInput& stick, QColor gate_brush_color, + std::optional adj_coord) { - // Some hacks for pretty colors: - const bool is_c_stick = m_group->name == "C-Stick"; - const bool is_tilt = m_group->name == "Tilt"; + QPainter p(this); + DrawBoundingBox(p); + TransformPainter(p); - const auto center = stick.GetCenter(); - - QColor gate_brush_color = STICK_GATE_COLOR; - - if (is_c_stick) - gate_brush_color = C_STICK_GATE_COLOR; - else if (is_tilt) - gate_brush_color = TILT_GATE_COLOR; - - QColor gate_pen_color = gate_brush_color.darker(125); - - AdjustGateColor(&gate_brush_color); - AdjustGateColor(&gate_pen_color); + // UI y-axis is opposite that of stick. + p.scale(1.0, -1.0); const auto raw_coord = stick.GetReshapableState(false); - Common::DVec2 adj_coord; - if (is_tilt) - { - WiimoteEmu::EmulateTilt(&m_motion_state, static_cast(&stick), - 1.f / INDICATOR_UPDATE_FREQ); - adj_coord = Common::DVec2{-m_motion_state.angle.y, m_motion_state.angle.x} / MathUtil::PI; - } - else - { - adj_coord = stick.GetReshapableState(true); - } - UpdateCalibrationWidget(raw_coord); - // Bounding box size: - const double scale = GetScale(); - - QPainter p(this); - p.translate(width() / 2, height() / 2); - - // Bounding box. - p.setBrush(GetBBoxBrush()); - p.setPen(GetBBoxPen()); - p.drawRect(-scale - 1, -scale - 1, scale * 2 + 1, scale * 2 + 1); - - // UI y-axis is opposite that of stick. - p.scale(1.0, -1.0); - - // Enable AA after drawing bounding box. - p.setRenderHint(QPainter::Antialiasing, true); - p.setRenderHint(QPainter::SmoothPixmapTransform, true); - if (IsCalibrating()) { DrawCalibration(p, raw_coord); return; } + DrawUnderGate(p); + + QColor gate_pen_color = gate_brush_color.darker(125); + + AdjustGateColor(&gate_brush_color); + AdjustGateColor(&gate_pen_color); + // Input gate. (i.e. the octagon shape) - p.setPen(gate_pen_color); + p.setPen(QPen(gate_pen_color, 0)); p.setBrush(gate_brush_color); - p.drawPolygon(GetPolygonFromRadiusGetter( - [&stick](double ang) { return stick.GetGateRadiusAtAngle(ang); }, scale)); + p.drawPolygon( + GetPolygonFromRadiusGetter([&stick](double ang) { return stick.GetGateRadiusAtAngle(ang); })); + + const auto center = stick.GetCenter(); // Deadzone. p.setPen(GetDeadZonePen()); - p.setBrush(GetDeadZoneBrush()); + p.setBrush(GetDeadZoneBrush(p)); p.drawPolygon(GetPolygonFromRadiusGetter( - [&stick](double ang) { return stick.GetDeadzoneRadiusAtAngle(ang); }, scale, center)); + [&stick](double ang) { return stick.GetDeadzoneRadiusAtAngle(ang); }, center)); // Input shape. p.setPen(GetInputShapePen()); p.setBrush(Qt::NoBrush); p.drawPolygon(GetPolygonFromRadiusGetter( - [&stick](double ang) { return stick.GetInputRadiusAtAngle(ang); }, scale, center)); + [&stick](double ang) { return stick.GetInputRadiusAtAngle(ang); }, center)); // Center. if (center.x || center.y) { - p.setPen(Qt::NoPen); - p.setBrush(GetCenterColor()); - p.drawEllipse(QPointF{center.x, center.y} * scale, INPUT_DOT_RADIUS, INPUT_DOT_RADIUS); + p.setPen(GetInputDotPen(GetCenterColor())); + p.drawPoint(QPointF{center.x, center.y}); } // Raw stick position. - p.setPen(Qt::NoPen); - p.setBrush(GetRawInputColor()); - p.drawEllipse(QPointF{raw_coord.x, raw_coord.y} * scale, INPUT_DOT_RADIUS, INPUT_DOT_RADIUS); + p.setPen(GetInputDotPen(GetRawInputColor())); + p.drawPoint(QPointF{raw_coord.x, raw_coord.y}); // Adjusted stick position. - if (adj_coord.x || adj_coord.y) + if (adj_coord) { - p.setPen(Qt::NoPen); - p.setBrush(GetAdjustedInputColor()); - p.drawEllipse(QPointF{adj_coord.x, adj_coord.y} * scale, INPUT_DOT_RADIUS, INPUT_DOT_RADIUS); + p.setPen(GetInputDotPen(GetAdjustedInputColor())); + p.drawPoint(QPointF{adj_coord->x, adj_coord->y}); } } -void MappingIndicator::DrawMixedTriggers() +void AnalogStickIndicator::Draw() +{ + // Some hacks for pretty colors: + const bool is_c_stick = m_group.name == "C-Stick"; + + const auto gate_brush_color = is_c_stick ? C_STICK_GATE_COLOR : STICK_GATE_COLOR; + + const auto adj_coord = m_group.GetReshapableState(true); + + DrawReshapableInput(m_group, gate_brush_color, + (adj_coord.x || adj_coord.y) ? std::make_optional(adj_coord) : std::nullopt); +} + +void TiltIndicator::Draw() +{ + WiimoteEmu::EmulateTilt(&m_motion_state, &m_group, 1.f / INDICATOR_UPDATE_FREQ); + + const auto adj_coord = + Common::DVec2{-m_motion_state.angle.y, m_motion_state.angle.x} / MathUtil::PI; + + DrawReshapableInput(m_group, TILT_GATE_COLOR, + (adj_coord.x || adj_coord.y) ? std::make_optional(adj_coord) : std::nullopt); +} + +void MixedTriggersIndicator::Draw() { QPainter p(this); p.setRenderHint(QPainter::TextAntialiasing, true); - const auto& triggers = *static_cast(m_group); + const auto& triggers = m_group; const ControlState threshold = triggers.GetThreshold(); const ControlState deadzone = triggers.GetDeadzone(); @@ -411,15 +377,15 @@ void MappingIndicator::DrawMixedTriggers() triggers.GetState(&button_state, button_masks.data(), adj_analog_state.data(), true); // Rectangle sizes: - const int trigger_height = 32; + const int trigger_height = TRIGGER_INDICATOR_HEIGHT; const int trigger_width = width() - 1; - const int trigger_button_width = 32; + const int trigger_button_width = trigger_height; const int trigger_analog_width = trigger_width - trigger_button_width; // Bounding box background: p.setPen(Qt::NoPen); p.setBrush(GetBBoxBrush()); - p.drawRect(0, 0, trigger_width, trigger_height * TRIGGER_COUNT); + p.drawRect(QRectF(0.5, 0.5, trigger_width, trigger_height * TRIGGER_COUNT)); for (int t = 0; t != TRIGGER_COUNT; ++t) { @@ -429,35 +395,35 @@ void MappingIndicator::DrawMixedTriggers() auto const analog_name = QString::fromStdString(triggers.controls[TRIGGER_COUNT + t]->ui_name); auto const button_name = QString::fromStdString(triggers.controls[t]->ui_name); - const QRectF trigger_rect(0, 0, trigger_width, trigger_height); + const QRectF trigger_rect(0.5, 0.5, trigger_width, trigger_height); - const QRectF analog_rect(0, 0, trigger_analog_width, trigger_height); + const QRectF analog_rect(0.5, 0.5, trigger_analog_width, trigger_height); // Unactivated analog text: p.setPen(GetTextColor()); p.drawText(analog_rect, Qt::AlignCenter, analog_name); - const QRectF adj_analog_rect(0, 0, adj_analog * trigger_analog_width, trigger_height); + const QRectF adj_analog_rect(0.5, 0.5, adj_analog * trigger_analog_width, trigger_height); // Trigger analog: p.setPen(Qt::NoPen); - p.setBrush(GetRawInputColor()); - p.drawEllipse(QPoint(raw_analog * trigger_analog_width, trigger_height - INPUT_DOT_RADIUS), - INPUT_DOT_RADIUS, INPUT_DOT_RADIUS); p.setBrush(GetAdjustedInputColor()); p.drawRect(adj_analog_rect); + p.setPen(GetInputDotPen(GetRawInputColor())); + p.drawPoint(QPoint(raw_analog * trigger_analog_width, trigger_height - INPUT_DOT_RADIUS)); + // Deadzone: p.setPen(GetDeadZonePen()); - p.setBrush(GetDeadZoneBrush()); - p.drawRect(0, 0, trigger_analog_width * deadzone, trigger_height); + p.setBrush(GetDeadZoneBrush(p)); + p.drawRect(QRectF(1.5, 1.5, trigger_analog_width * deadzone, trigger_height - 2)); // Threshold setting: const int threshold_x = trigger_analog_width * threshold; p.setPen(GetInputShapePen()); p.drawLine(threshold_x, 0, threshold_x, trigger_height); - const QRectF button_rect(trigger_analog_width, 0, trigger_button_width, trigger_height); + const QRectF button_rect(trigger_analog_width + 0.5, 0.5, trigger_button_width, trigger_height); // Trigger button: p.setPen(GetBBoxPen()); @@ -486,150 +452,51 @@ void MappingIndicator::DrawMixedTriggers() } } -void MappingIndicator::DrawForce(ControllerEmu::Force& force) +void SwingIndicator::DrawUnderGate(QPainter& p) { - const auto center = force.GetCenter(); - - QColor gate_brush_color = SWING_GATE_COLOR; - QColor gate_pen_color = gate_brush_color.darker(125); - - AdjustGateColor(&gate_brush_color); - AdjustGateColor(&gate_pen_color); - - const auto raw_coord = force.GetState(false); - WiimoteEmu::EmulateSwing(&m_motion_state, &force, 1.f / INDICATOR_UPDATE_FREQ); - const auto& adj_coord = m_motion_state.position; - - UpdateCalibrationWidget({raw_coord.x, raw_coord.y}); - - // Bounding box size: - const double scale = GetScale(); - - QPainter p(this); - p.translate(width() / 2, height() / 2); - - // Bounding box. - p.setBrush(GetBBoxBrush()); - p.setPen(GetBBoxPen()); - p.drawRect(-scale - 1, -scale - 1, scale * 2 + 1, scale * 2 + 1); - - // UI y-axis is opposite that of stick. - p.scale(1.0, -1.0); - - // Enable AA after drawing bounding box. - p.setRenderHint(QPainter::Antialiasing, true); - p.setRenderHint(QPainter::SmoothPixmapTransform, true); - - if (IsCalibrating()) - { - DrawCalibration(p, {raw_coord.x, raw_coord.y}); - return; - } + auto& force = m_swing_group; // Deadzone for Z (forward/backward): const double deadzone = force.GetDeadzonePercentage(); if (deadzone > 0.0) { p.setPen(GetDeadZonePen()); - p.setBrush(GetDeadZoneBrush()); - p.drawRect(QRectF(-scale, -deadzone * scale, scale * 2, deadzone * scale * 2)); + p.setBrush(GetDeadZoneBrush(p)); + p.drawRect(QRectF(-1, -deadzone, 2, deadzone * 2)); } // Raw Z: - p.setPen(Qt::NoPen); - p.setBrush(GetRawInputColor()); - p.drawRect( - QRectF(-scale, raw_coord.z * scale - INPUT_DOT_RADIUS / 2, scale * 2, INPUT_DOT_RADIUS)); + const auto raw_coord = force.GetState(false); + p.setPen(GetCosmeticPen(QPen(GetRawInputColor(), INPUT_DOT_RADIUS))); + p.drawLine(QLineF(-1, raw_coord.z, 1, raw_coord.z)); // Adjusted Z: + const auto& adj_coord = m_motion_state.position; const auto curve_point = std::max(std::abs(m_motion_state.angle.x), std::abs(m_motion_state.angle.z)) / MathUtil::TAU; if (adj_coord.y || curve_point) { // Show off the angle somewhat with a curved line. QPainterPath path; - path.moveTo(-scale, (adj_coord.y + curve_point) * -scale); - path.quadTo({0, (adj_coord.y - curve_point) * -scale}, - {scale, (adj_coord.y + curve_point) * -scale}); + path.moveTo(-1.0, (adj_coord.y + curve_point) * -1); + path.quadTo({0, (adj_coord.y - curve_point) * -1}, {1, (adj_coord.y + curve_point) * -1}); p.setBrush(Qt::NoBrush); - p.setPen(QPen(GetAdjustedInputColor(), INPUT_DOT_RADIUS)); + p.setPen(GetCosmeticPen(QPen(GetAdjustedInputColor(), INPUT_DOT_RADIUS))); p.drawPath(path); } - - // Draw "gate" shape. - p.setPen(gate_pen_color); - p.setBrush(gate_brush_color); - p.drawPolygon(GetPolygonFromRadiusGetter( - [&force](double ang) { return force.GetGateRadiusAtAngle(ang); }, scale)); - - // Deadzone. - p.setPen(GetDeadZoneColor()); - p.setBrush(GetDeadZoneBrush()); - p.drawPolygon(GetPolygonFromRadiusGetter( - [&force](double ang) { return force.GetDeadzoneRadiusAtAngle(ang); }, scale, center)); - - // Input shape. - p.setPen(GetInputShapePen()); - p.setBrush(Qt::NoBrush); - p.drawPolygon(GetPolygonFromRadiusGetter( - [&force](double ang) { return force.GetInputRadiusAtAngle(ang); }, scale, center)); - - // Center. - if (center.x || center.y) - { - p.setPen(Qt::NoPen); - p.setBrush(GetCenterColor()); - p.drawEllipse(QPointF{center.x, center.y} * scale, INPUT_DOT_RADIUS, INPUT_DOT_RADIUS); - } - - // Raw stick position. - p.setPen(Qt::NoPen); - p.setBrush(GetRawInputColor()); - p.drawEllipse(QPointF{raw_coord.x, raw_coord.y} * scale, INPUT_DOT_RADIUS, INPUT_DOT_RADIUS); - - // Adjusted position: - if (adj_coord.x || adj_coord.z) - { - p.setPen(Qt::NoPen); - p.setBrush(GetAdjustedInputColor()); - p.drawEllipse(QPointF{-adj_coord.x, adj_coord.z} * scale, INPUT_DOT_RADIUS, INPUT_DOT_RADIUS); - } } -void MappingIndicator::paintEvent(QPaintEvent*) +void SwingIndicator::Draw() { - switch (m_group->type) - { - case ControllerEmu::GroupType::Cursor: - DrawCursor(*static_cast(m_group)); - break; - case ControllerEmu::GroupType::Stick: - case ControllerEmu::GroupType::Tilt: - DrawReshapableInput(*static_cast(m_group)); - break; - case ControllerEmu::GroupType::MixedTriggers: - DrawMixedTriggers(); - break; - case ControllerEmu::GroupType::Force: - DrawForce(*static_cast(m_group)); - break; - default: - break; - } + auto& force = m_swing_group; + WiimoteEmu::EmulateSwing(&m_motion_state, &force, 1.f / INDICATOR_UPDATE_FREQ); + + DrawReshapableInput(force, SWING_GATE_COLOR, + Common::DVec2{-m_motion_state.position.x, m_motion_state.position.z}); } -ShakeMappingIndicator::ShakeMappingIndicator(ControllerEmu::Shake* group) - : MappingIndicator(group), m_shake_group(*group) -{ -} - -void ShakeMappingIndicator::paintEvent(QPaintEvent*) -{ - DrawShake(); -} - -void ShakeMappingIndicator::DrawShake() +void ShakeMappingIndicator::Draw() { constexpr std::size_t HISTORY_COUNT = INDICATOR_UPDATE_FREQ; @@ -642,37 +509,24 @@ void ShakeMappingIndicator::DrawShake() if (m_position_samples.size() > HISTORY_COUNT + 1) m_position_samples.pop_back(); - // Bounding box size: - const double scale = GetScale(); - QPainter p(this); - p.translate(width() / 2, height() / 2); - - // Bounding box. - p.setBrush(GetBBoxBrush()); - p.setPen(GetBBoxPen()); - p.drawRect(-scale - 1, -scale - 1, scale * 2 + 1, scale * 2 + 1); + DrawBoundingBox(p); + TransformPainter(p); // UI y-axis is opposite that of acceleration Z. p.scale(1.0, -1.0); - // Enable AA after drawing bounding box. - p.setRenderHint(QPainter::Antialiasing, true); - p.setRenderHint(QPainter::SmoothPixmapTransform, true); - // Deadzone. p.setPen(GetDeadZonePen()); - p.setBrush(GetDeadZoneBrush()); - p.drawRect(-scale, 0, scale * 2, m_shake_group.GetDeadzone() * scale); + p.setBrush(GetDeadZoneBrush(p)); + p.drawRect(-1.0, 0, 2, m_shake_group.GetDeadzone()); // Raw input. const auto raw_coord = m_shake_group.GetState(false); - p.setPen(Qt::NoPen); - p.setBrush(GetRawInputColor()); + p.setPen(GetInputDotPen(GetRawInputColor())); for (std::size_t c = 0; c != raw_coord.data.size(); ++c) { - p.drawEllipse(QPointF{-0.5 + c * 0.5, raw_coord.data[c]} * scale, INPUT_DOT_RADIUS, - INPUT_DOT_RADIUS); + p.drawPoint(QPointF{-0.5 + c * 0.5, raw_coord.data[c]}); } // Grid line. @@ -684,8 +538,8 @@ void ShakeMappingIndicator::DrawShake() m_grid_line_position = (m_grid_line_position + 1) % HISTORY_COUNT; } const double grid_line_x = 1.0 - m_grid_line_position * 2.0 / HISTORY_COUNT; - p.setPen(GetRawInputColor()); - p.drawLine(QPointF{grid_line_x, -1.0} * scale, QPointF{grid_line_x, 1.0} * scale); + p.setPen(QPen(GetRawInputColor(), 0)); + p.drawLine(QPointF{grid_line_x, -1.0}, QPointF{grid_line_x, 1.0}); // Position history. const QColor component_colors[] = {Qt::blue, Qt::green, Qt::red}; @@ -697,60 +551,44 @@ void ShakeMappingIndicator::DrawShake() int i = 0; for (auto& sample : m_position_samples) { - polyline.append(QPointF{1.0 - i * 2.0 / HISTORY_COUNT, sample.data[c]} * scale); + polyline.append(QPointF{1.0 - i * 2.0 / HISTORY_COUNT, sample.data[c]}); ++i; } - p.setPen(component_colors[c]); + p.setPen(QPen(component_colors[c], 0)); p.drawPolyline(polyline); } } -AccelerometerMappingIndicator::AccelerometerMappingIndicator(ControllerEmu::IMUAccelerometer* group) - : MappingIndicator(group), m_accel_group(*group) -{ -} - -void AccelerometerMappingIndicator::paintEvent(QPaintEvent*) +void AccelerometerMappingIndicator::Draw() { const auto accel_state = m_accel_group.GetState(); const auto state = accel_state.value_or(Common::Vec3{}); - // Bounding box size: - const double scale = GetScale(); - QPainter p(this); - p.translate(width() / 2, height() / 2); - - // Bounding box. - p.setBrush(GetBBoxBrush()); - p.setPen(GetBBoxPen()); - p.drawRect(-scale - 1, -scale - 1, scale * 2 + 1, scale * 2 + 1); + p.setRenderHint(QPainter::TextAntialiasing, true); + DrawBoundingBox(p); + TransformPainter(p); // UI axes are opposite that of Wii remote accelerometer. p.scale(-1.0, -1.0); - // Enable AA after drawing bounding box. - p.setRenderHint(QPainter::Antialiasing, true); - p.setRenderHint(QPainter::SmoothPixmapTransform, true); - const auto rotation = WiimoteEmu::GetMatrixFromAcceleration(state); // Draw sphere. - p.setPen(Qt::NoPen); - p.setBrush(GetRawInputColor()); + p.setPen(GetCosmeticPen(QPen(GetRawInputColor(), 0.5))); GenerateFibonacciSphere(SPHERE_POINT_COUNT, [&](const Common::Vec3& point) { const auto pt = rotation * point; if (pt.y > 0) - p.drawEllipse(QPointF(pt.x, pt.z) * scale * SPHERE_SIZE, 0.5f, 0.5f); + p.drawPoint(QPointF(pt.x, pt.z) * SPHERE_SIZE); }); // Sphere outline. - p.setPen(GetRawInputColor()); + p.setPen(QPen(GetRawInputColor(), 0)); p.setBrush(Qt::NoBrush); - p.drawEllipse(QPointF{}, scale * SPHERE_SIZE, scale * SPHERE_SIZE); + p.drawEllipse(QPointF{}, SPHERE_SIZE, SPHERE_SIZE); p.setPen(Qt::NoPen); @@ -758,27 +596,32 @@ void AccelerometerMappingIndicator::paintEvent(QPaintEvent*) const auto point = rotation * Common::Vec3{0, 0, SPHERE_INDICATOR_DIST}; if (point.y > 0 || Common::Vec2(point.x, point.z).Length() > SPHERE_SIZE) { - p.setBrush(GetAdjustedInputColor()); - p.drawEllipse(QPointF(point.x, point.z) * scale, INPUT_DOT_RADIUS, INPUT_DOT_RADIUS); + p.setPen(GetInputDotPen(GetAdjustedInputColor())); + p.drawPoint(QPointF(point.x, point.z)); } // Blue dot. const auto point2 = -point; if (point2.y > 0 || Common::Vec2(point2.x, point2.z).Length() > SPHERE_SIZE) { - p.setBrush(Qt::blue); - p.drawEllipse(QPointF(point2.x, point2.z) * scale, INPUT_DOT_RADIUS, INPUT_DOT_RADIUS); + p.setPen(GetInputDotPen(GetCenterColor())); + p.drawPoint(QPointF(point2.x, point2.z)); } p.setBrush(Qt::NoBrush); + p.resetTransform(); + p.translate(width() / 2, height() / 2); + // Red dot upright target. - p.setPen(QPen(GetAdjustedInputColor(), INPUT_DOT_RADIUS / 2)); - p.drawEllipse(QPointF{0, SPHERE_INDICATOR_DIST} * scale, INPUT_DOT_RADIUS, INPUT_DOT_RADIUS); + p.setPen(GetAdjustedInputColor()); + p.drawEllipse(QPointF{0, -SPHERE_INDICATOR_DIST} * GetContentsScale(), INPUT_DOT_RADIUS, + INPUT_DOT_RADIUS); // Blue dot target. - p.setPen(QPen(Qt::blue, INPUT_DOT_RADIUS / 2)); - p.drawEllipse(QPointF{0, -SPHERE_INDICATOR_DIST} * scale, INPUT_DOT_RADIUS, INPUT_DOT_RADIUS); + p.setPen(GetCenterColor()); + p.drawEllipse(QPointF{0, SPHERE_INDICATOR_DIST} * GetContentsScale(), INPUT_DOT_RADIUS, + INPUT_DOT_RADIUS); // Only draw g-force text if acceleration data is present. if (!accel_state.has_value()) @@ -786,19 +629,14 @@ void AccelerometerMappingIndicator::paintEvent(QPaintEvent*) // G-force text: p.setPen(GetTextColor()); - p.scale(-1.0, -1.0); - p.drawText(QRectF(-2, 0, scale, scale), Qt::AlignBottom | Qt::AlignRight, + p.drawText(QRect(0, 0, NORMAL_INDICATOR_WIDTH / 2 - 2, NORMAL_INDICATOR_HEIGHT / 2 - 1), + Qt::AlignBottom | Qt::AlignRight, QString::fromStdString( // i18n: "g" is the symbol for "gravitational force equivalent" (g-force). fmt::format("{:.2f} g", state.Length() / WiimoteEmu::GRAVITY_ACCELERATION))); } -GyroMappingIndicator::GyroMappingIndicator(ControllerEmu::IMUGyroscope* group) - : MappingIndicator(group), m_gyro_group(*group), m_state(Common::Matrix33::Identity()) -{ -} - -void GyroMappingIndicator::paintEvent(QPaintEvent*) +void GyroMappingIndicator::Draw() { const auto gyro_state = m_gyro_group.GetState(); const auto raw_gyro_state = m_gyro_group.GetRawState(); @@ -825,20 +663,9 @@ void GyroMappingIndicator::paintEvent(QPaintEvent*) // Use an empty rotation matrix if gyroscope data is not present. const auto rotation = (gyro_state.has_value() ? m_state : Common::Matrix33{}); - // Bounding box size: - const double scale = GetScale(); - QPainter p(this); - p.translate(width() / 2, height() / 2); - - // Bounding box. - p.setBrush(GetBBoxBrush()); - p.setPen(GetBBoxPen()); - p.drawRect(-scale - 1, -scale - 1, scale * 2 + 1, scale * 2 + 1); - - // Enable AA after drawing bounding box. - p.setRenderHint(QPainter::Antialiasing, true); - p.setRenderHint(QPainter::SmoothPixmapTransform, true); + DrawBoundingBox(p); + TransformPainter(p); // Deadzone. if (const auto deadzone_value = m_gyro_group.GetDeadzone(); deadzone_value) @@ -847,10 +674,8 @@ void GyroMappingIndicator::paintEvent(QPaintEvent*) static constexpr auto DEADZONE_DRAW_BOTTOM = 1; p.setPen(GetDeadZonePen()); - p.setBrush(GetDeadZoneBrush()); - p.scale(-1.0, 1.0); - p.drawRect(-scale, DEADZONE_DRAW_BOTTOM * scale, scale * 2, -scale * DEADZONE_DRAW_SIZE); - p.scale(-1.0, 1.0); + p.setBrush(GetDeadZoneBrush(p)); + p.drawRect(QRectF{-1, DEADZONE_DRAW_BOTTOM, 2, -DEADZONE_DRAW_SIZE}); if (gyro_state.has_value()) { @@ -858,34 +683,33 @@ void GyroMappingIndicator::paintEvent(QPaintEvent*) std::max({std::abs(jitter.x), std::abs(jitter.y), std::abs(jitter.z)}); const auto jitter_line_y = std::min(max_jitter / deadzone_value * DEADZONE_DRAW_SIZE - DEADZONE_DRAW_BOTTOM, 1.0); - p.setPen(QPen(GetRawInputColor(), INPUT_DOT_RADIUS)); - p.drawLine(-scale, jitter_line_y * -scale, scale, jitter_line_y * -scale); + p.setPen(GetCosmeticPen(QPen(GetRawInputColor(), INPUT_DOT_RADIUS))); + p.drawLine(-1.0, jitter_line_y * -1.0, 1.0, jitter_line_y * -1.0); // Sphere background. p.setPen(Qt::NoPen); p.setBrush(GetBBoxBrush()); - p.drawEllipse(QPointF{}, scale * SPHERE_SIZE, scale * SPHERE_SIZE); + p.drawEllipse(QPointF{}, SPHERE_SIZE, SPHERE_SIZE); } } // Sphere dots. - p.setPen(Qt::NoPen); - p.setBrush(GetRawInputColor()); + p.setPen(GetCosmeticPen(QPen(GetRawInputColor(), 0.5))); GenerateFibonacciSphere(SPHERE_POINT_COUNT, [&](const Common::Vec3& point) { const auto pt = rotation * point; if (pt.y > 0) - p.drawEllipse(QPointF(pt.x, pt.z) * scale * SPHERE_SIZE, 0.5f, 0.5f); + p.drawPoint(QPointF(pt.x, pt.z) * SPHERE_SIZE); }); // Sphere outline. - const auto outline_color = is_stable ? - (m_gyro_group.IsCalibrating() ? Qt::blue : GetRawInputColor()) : - GetAdjustedInputColor(); - p.setPen(outline_color); + const auto outline_color = + is_stable ? (m_gyro_group.IsCalibrating() ? GetCenterColor() : GetRawInputColor()) : + GetAdjustedInputColor(); + p.setPen(QPen(outline_color, 0)); p.setBrush(Qt::NoBrush); - p.drawEllipse(QPointF{}, scale * SPHERE_SIZE, scale * SPHERE_SIZE); + p.drawEllipse(QPointF{}, SPHERE_SIZE, SPHERE_SIZE); p.setPen(Qt::NoPen); @@ -893,32 +717,35 @@ void GyroMappingIndicator::paintEvent(QPaintEvent*) const auto point = rotation * Common::Vec3{0, 0, -SPHERE_INDICATOR_DIST}; if (point.y > 0 || Common::Vec2(point.x, point.z).Length() > SPHERE_SIZE) { - p.setBrush(GetAdjustedInputColor()); - p.drawEllipse(QPointF(point.x, point.z) * scale, INPUT_DOT_RADIUS, INPUT_DOT_RADIUS); + p.setPen(GetInputDotPen(GetAdjustedInputColor())); + p.drawPoint(QPointF(point.x, point.z)); } // Blue dot. const auto point2 = rotation * Common::Vec3{0, SPHERE_INDICATOR_DIST, 0}; if (point2.y > 0 || Common::Vec2(point2.x, point2.z).Length() > SPHERE_SIZE) { - p.setBrush(Qt::blue); - p.drawEllipse(QPointF(point2.x, point2.z) * scale, INPUT_DOT_RADIUS, INPUT_DOT_RADIUS); + p.setPen(GetInputDotPen(GetCenterColor())); + p.drawPoint(QPointF(point2.x, point2.z)); } p.setBrush(Qt::NoBrush); + p.resetTransform(); + p.translate(width() / 2, height() / 2); + // Red dot upright target. - p.setPen(QPen(GetAdjustedInputColor(), INPUT_DOT_RADIUS / 2)); - p.drawEllipse(QPointF{0, -SPHERE_INDICATOR_DIST} * scale, INPUT_DOT_RADIUS, INPUT_DOT_RADIUS); + p.setPen(GetAdjustedInputColor()); + p.drawEllipse(QPointF{0, -SPHERE_INDICATOR_DIST} * GetContentsScale(), INPUT_DOT_RADIUS, + INPUT_DOT_RADIUS); // Blue dot target. - p.setPen(QPen(Qt::blue, INPUT_DOT_RADIUS / 2)); + p.setPen(GetCenterColor()); p.drawEllipse(QPointF{}, INPUT_DOT_RADIUS, INPUT_DOT_RADIUS); } -void MappingIndicator::DrawCalibration(QPainter& p, Common::DVec2 point) +void ReshapableInputIndicator::DrawCalibration(QPainter& p, Common::DVec2 point) { // Bounding box size: - const double scale = GetScale(); const auto center = m_calibration_widget->GetCenter(); // Input shape. @@ -926,40 +753,38 @@ void MappingIndicator::DrawCalibration(QPainter& p, Common::DVec2 point) p.setBrush(Qt::NoBrush); p.drawPolygon(GetPolygonFromRadiusGetter( [this](double angle) { return m_calibration_widget->GetCalibrationRadiusAtAngle(angle); }, - scale, center)); + center)); // Center. if (center.x || center.y) { - p.setPen(Qt::NoPen); - p.setBrush(GetCenterColor()); - p.drawEllipse(QPointF{center.x, center.y} * scale, INPUT_DOT_RADIUS, INPUT_DOT_RADIUS); + p.setPen(GetInputDotPen(GetCenterColor())); + p.drawPoint(QPointF{center.x, center.y}); } // Stick position. - p.setPen(Qt::NoPen); - p.setBrush(GetAdjustedInputColor()); - p.drawEllipse(QPointF{point.x, point.y} * scale, INPUT_DOT_RADIUS, INPUT_DOT_RADIUS); + p.setPen(GetInputDotPen(GetAdjustedInputColor())); + p.drawPoint(QPointF{point.x, point.y}); } -void MappingIndicator::UpdateCalibrationWidget(Common::DVec2 point) +void ReshapableInputIndicator::UpdateCalibrationWidget(Common::DVec2 point) { if (m_calibration_widget) m_calibration_widget->Update(point); } -bool MappingIndicator::IsCalibrating() const +bool ReshapableInputIndicator::IsCalibrating() const { return m_calibration_widget && m_calibration_widget->IsCalibrating(); } -void MappingIndicator::SetCalibrationWidget(CalibrationWidget* widget) +void ReshapableInputIndicator::SetCalibrationWidget(CalibrationWidget* widget) { m_calibration_widget = widget; } CalibrationWidget::CalibrationWidget(ControllerEmu::ReshapableInput& input, - MappingIndicator& indicator) + ReshapableInputIndicator& indicator) : m_input(input), m_indicator(indicator), m_completion_action{} { m_indicator.SetCalibrationWidget(this); diff --git a/Source/Core/DolphinQt/Config/Mapping/MappingIndicator.h b/Source/Core/DolphinQt/Config/Mapping/MappingIndicator.h index 2405ebcc0c..7a57af3fb0 100644 --- a/Source/Core/DolphinQt/Config/Mapping/MappingIndicator.h +++ b/Source/Core/DolphinQt/Config/Mapping/MappingIndicator.h @@ -18,6 +18,7 @@ class Control; class ControlGroup; class Cursor; class Force; +class MixedTriggers; } // namespace ControllerEmu class QPainter; @@ -29,10 +30,6 @@ class CalibrationWidget; class MappingIndicator : public QWidget { public: - explicit MappingIndicator(ControllerEmu::ControlGroup* group); - - void SetCalibrationWidget(CalibrationWidget* widget); - QPen GetBBoxPen() const; QBrush GetBBoxBrush() const; QColor GetRawInputColor() const; @@ -41,66 +38,145 @@ public: QColor GetAdjustedInputColor() const; QColor GetDeadZoneColor() const; QPen GetDeadZonePen() const; - QBrush GetDeadZoneBrush() const; + QBrush GetDeadZoneBrush(QPainter&) const; QColor GetTextColor() const; QColor GetAltTextColor() const; void AdjustGateColor(QColor*); protected: - double GetScale() const; - - WiimoteEmu::MotionState m_motion_state{}; + virtual void Draw() {} private: - void DrawCursor(ControllerEmu::Cursor& cursor); - void DrawReshapableInput(ControllerEmu::ReshapableInput& stick); - void DrawMixedTriggers(); - void DrawForce(ControllerEmu::Force&); - void DrawCalibration(QPainter& p, Common::DVec2 point); - void paintEvent(QPaintEvent*) override; +}; + +class SquareIndicator : public MappingIndicator +{ +protected: + SquareIndicator(); + + qreal GetContentsScale() const; + void DrawBoundingBox(QPainter&); + void TransformPainter(QPainter&); +}; + +class ReshapableInputIndicator : public SquareIndicator +{ +public: + void SetCalibrationWidget(CalibrationWidget* widget); + +protected: + void DrawReshapableInput(ControllerEmu::ReshapableInput& group, QColor gate_color, + std::optional adj_coord); + + virtual void DrawUnderGate(QPainter&) {} bool IsCalibrating() const; + + void DrawCalibration(QPainter& p, Common::DVec2 point); void UpdateCalibrationWidget(Common::DVec2 point); - ControllerEmu::ControlGroup* const m_group; +private: CalibrationWidget* m_calibration_widget{}; }; -class ShakeMappingIndicator : public MappingIndicator +class AnalogStickIndicator : public ReshapableInputIndicator { public: - explicit ShakeMappingIndicator(ControllerEmu::Shake* group); - - void DrawShake(); - void paintEvent(QPaintEvent*) override; + explicit AnalogStickIndicator(ControllerEmu::ReshapableInput& stick) : m_group(stick) {} private: - std::deque m_position_samples; - int m_grid_line_position = 0; + void Draw() override; - ControllerEmu::Shake& m_shake_group; + ControllerEmu::ReshapableInput& m_group; }; -class AccelerometerMappingIndicator : public MappingIndicator +class TiltIndicator : public ReshapableInputIndicator { public: - explicit AccelerometerMappingIndicator(ControllerEmu::IMUAccelerometer* group); - void paintEvent(QPaintEvent*) override; + explicit TiltIndicator(ControllerEmu::Tilt& tilt) : m_group(tilt) {} private: + void Draw() override; + + ControllerEmu::Tilt& m_group; + WiimoteEmu::MotionState m_motion_state{}; +}; + +class CursorIndicator : public ReshapableInputIndicator +{ +public: + explicit CursorIndicator(ControllerEmu::Cursor& cursor) : m_cursor_group(cursor) {} + +private: + void Draw() override; + + ControllerEmu::Cursor& m_cursor_group; +}; + +class MixedTriggersIndicator : public MappingIndicator +{ +public: + explicit MixedTriggersIndicator(ControllerEmu::MixedTriggers& triggers); + +private: + void Draw() override; + + ControllerEmu::MixedTriggers& m_group; +}; + +class SwingIndicator : public ReshapableInputIndicator +{ +public: + explicit SwingIndicator(ControllerEmu::Force& swing) : m_swing_group(swing) {} + +private: + void Draw() override; + + void DrawUnderGate(QPainter& p) override; + + ControllerEmu::Force& m_swing_group; + WiimoteEmu::MotionState m_motion_state{}; +}; + +class ShakeMappingIndicator : public SquareIndicator +{ +public: + explicit ShakeMappingIndicator(ControllerEmu::Shake& shake) : m_shake_group(shake) {} + +private: + void Draw() override; + + ControllerEmu::Shake& m_shake_group; + WiimoteEmu::MotionState m_motion_state{}; + std::deque m_position_samples; + int m_grid_line_position = 0; +}; + +class AccelerometerMappingIndicator : public SquareIndicator +{ +public: + explicit AccelerometerMappingIndicator(ControllerEmu::IMUAccelerometer& accel) + : m_accel_group(accel) + { + } + +private: + void Draw() override; + ControllerEmu::IMUAccelerometer& m_accel_group; }; -class GyroMappingIndicator : public MappingIndicator +class GyroMappingIndicator : public SquareIndicator { public: - explicit GyroMappingIndicator(ControllerEmu::IMUGyroscope* group); - void paintEvent(QPaintEvent*) override; + explicit GyroMappingIndicator(ControllerEmu::IMUGyroscope& gyro) : m_gyro_group(gyro) {} private: + void Draw() override; + ControllerEmu::IMUGyroscope& m_gyro_group; - Common::Matrix33 m_state; + Common::Matrix33 m_state = Common::Matrix33::Identity(); Common::Vec3 m_previous_velocity = {}; u32 m_stable_steps = 0; }; @@ -108,7 +184,7 @@ private: class CalibrationWidget : public QToolButton { public: - CalibrationWidget(ControllerEmu::ReshapableInput& input, MappingIndicator& indicator); + CalibrationWidget(ControllerEmu::ReshapableInput& input, ReshapableInputIndicator& indicator); void Update(Common::DVec2 point); @@ -123,7 +199,7 @@ private: void SetupActions(); ControllerEmu::ReshapableInput& m_input; - MappingIndicator& m_indicator; + ReshapableInputIndicator& m_indicator; QAction* m_completion_action; ControllerEmu::ReshapableInput::CalibrationData m_calibration_data; QTimer* m_informative_timer; diff --git a/Source/Core/DolphinQt/Config/Mapping/MappingWidget.cpp b/Source/Core/DolphinQt/Config/Mapping/MappingWidget.cpp index eb39bac64f..09d136d0f9 100644 --- a/Source/Core/DolphinQt/Config/Mapping/MappingWidget.cpp +++ b/Source/Core/DolphinQt/Config/Mapping/MappingWidget.cpp @@ -19,6 +19,7 @@ #include "InputCommon/ControlReference/ControlReference.h" #include "InputCommon/ControllerEmu/Control/Control.h" #include "InputCommon/ControllerEmu/ControlGroup/ControlGroup.h" +#include "InputCommon/ControllerEmu/ControlGroup/MixedTriggers.h" #include "InputCommon/ControllerEmu/ControllerEmu.h" #include "InputCommon/ControllerEmu/Setting/NumericSetting.h" #include "InputCommon/ControllerEmu/StickGate.h" @@ -52,52 +53,66 @@ QGroupBox* MappingWidget::CreateGroupBox(const QString& name, ControllerEmu::Con group_box->setLayout(form_layout); - const bool need_indicator = group->type == ControllerEmu::GroupType::Cursor || - group->type == ControllerEmu::GroupType::Stick || - group->type == ControllerEmu::GroupType::Tilt || - group->type == ControllerEmu::GroupType::MixedTriggers || - group->type == ControllerEmu::GroupType::Force || - group->type == ControllerEmu::GroupType::IMUAccelerometer || - group->type == ControllerEmu::GroupType::IMUGyroscope || - group->type == ControllerEmu::GroupType::Shake; + MappingIndicator* indicator = nullptr; - const bool need_calibration = group->type == ControllerEmu::GroupType::Cursor || - group->type == ControllerEmu::GroupType::Stick || - group->type == ControllerEmu::GroupType::Tilt || - group->type == ControllerEmu::GroupType::Force; - - if (need_indicator) + switch (group->type) { - MappingIndicator* indicator; + case ControllerEmu::GroupType::Shake: + indicator = new ShakeMappingIndicator(*static_cast(group)); + break; - switch (group->type) - { - case ControllerEmu::GroupType::Shake: - indicator = new ShakeMappingIndicator(static_cast(group)); - break; + case ControllerEmu::GroupType::MixedTriggers: + indicator = new MixedTriggersIndicator(*static_cast(group)); + break; - case ControllerEmu::GroupType::IMUAccelerometer: - indicator = - new AccelerometerMappingIndicator(static_cast(group)); - break; + case ControllerEmu::GroupType::Tilt: + indicator = new TiltIndicator(*static_cast(group)); + break; - case ControllerEmu::GroupType::IMUGyroscope: - indicator = new GyroMappingIndicator(static_cast(group)); - break; + case ControllerEmu::GroupType::Cursor: + indicator = new CursorIndicator(*static_cast(group)); + break; - default: - indicator = new MappingIndicator(group); - break; - } + case ControllerEmu::GroupType::Force: + indicator = new SwingIndicator(*static_cast(group)); + break; - form_layout->addRow(indicator); + case ControllerEmu::GroupType::IMUAccelerometer: + indicator = + new AccelerometerMappingIndicator(*static_cast(group)); + break; + + case ControllerEmu::GroupType::IMUGyroscope: + indicator = new GyroMappingIndicator(*static_cast(group)); + break; + + case ControllerEmu::GroupType::Stick: + indicator = new AnalogStickIndicator(*static_cast(group)); + break; + + default: + break; + } + + if (indicator) + { + const auto indicator_layout = new QBoxLayout(QBoxLayout::Direction::Down); + indicator_layout->addWidget(indicator); + indicator_layout->setAlignment(Qt::AlignCenter); + form_layout->addRow(indicator_layout); connect(this, &MappingWidget::Update, indicator, QOverload<>::of(&MappingIndicator::update)); + const bool need_calibration = group->type == ControllerEmu::GroupType::Cursor || + group->type == ControllerEmu::GroupType::Stick || + group->type == ControllerEmu::GroupType::Tilt || + group->type == ControllerEmu::GroupType::Force; + if (need_calibration) { const auto calibrate = - new CalibrationWidget(*static_cast(group), *indicator); + new CalibrationWidget(*static_cast(group), + *static_cast(indicator)); form_layout->addRow(calibrate); } @@ -105,7 +120,7 @@ QGroupBox* MappingWidget::CreateGroupBox(const QString& name, ControllerEmu::Con for (auto& control : group->controls) { - auto* button = new MappingButton(this, control->control_ref.get(), !need_indicator); + auto* button = new MappingButton(this, control->control_ref.get(), !indicator); button->setMinimumWidth(100); button->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); diff --git a/Source/Core/DolphinQt/Config/Mapping/MappingWindow.cpp b/Source/Core/DolphinQt/Config/Mapping/MappingWindow.cpp index dd5768e3f2..0052278b90 100644 --- a/Source/Core/DolphinQt/Config/Mapping/MappingWindow.cpp +++ b/Source/Core/DolphinQt/Config/Mapping/MappingWindow.cpp @@ -71,7 +71,7 @@ MappingWindow::MappingWindow(QWidget* parent, Type type, int port_num) timer->start(1000 / INDICATOR_UPDATE_FREQ); - GetController()->GetStateLock(); + const auto lock = GetController()->GetStateLock(); emit ConfigChanged(); } @@ -245,7 +245,7 @@ void MappingWindow::OnLoadProfilePressed() m_controller->LoadConfig(ini.GetOrCreateSection("Profile")); m_controller->UpdateReferences(g_controller_interface); - GetController()->GetStateLock(); + const auto lock = GetController()->GetStateLock(); emit ConfigChanged(); } @@ -438,7 +438,7 @@ void MappingWindow::OnDefaultFieldsPressed() m_controller->LoadDefaults(g_controller_interface); m_controller->UpdateReferences(g_controller_interface); - GetController()->GetStateLock(); + const auto lock = GetController()->GetStateLock(); emit ConfigChanged(); emit Save(); } @@ -455,7 +455,7 @@ void MappingWindow::OnClearFieldsPressed() m_controller->UpdateReferences(g_controller_interface); - GetController()->GetStateLock(); + const auto lock = GetController()->GetStateLock(); emit ConfigChanged(); emit Save(); } diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/MixedTriggers.cpp b/Source/Core/InputCommon/ControllerEmu/ControlGroup/MixedTriggers.cpp index 50a787b41d..55199ec0d1 100644 --- a/Source/Core/InputCommon/ControllerEmu/ControlGroup/MixedTriggers.cpp +++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/MixedTriggers.cpp @@ -74,4 +74,9 @@ ControlState MixedTriggers::GetThreshold() const return m_threshold_setting.GetValue() / 100; } +size_t MixedTriggers::GetTriggerCount() const +{ + return controls.size() / 2; +} + } // namespace ControllerEmu diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/MixedTriggers.h b/Source/Core/InputCommon/ControllerEmu/ControlGroup/MixedTriggers.h index 250466dc9d..ade18b9f3b 100644 --- a/Source/Core/InputCommon/ControllerEmu/ControlGroup/MixedTriggers.h +++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/MixedTriggers.h @@ -22,6 +22,8 @@ public: ControlState GetDeadzone() const; ControlState GetThreshold() const; + size_t GetTriggerCount() const; + private: SettingValue m_threshold_setting; SettingValue m_deadzone_setting; diff --git a/Source/Core/InputCommon/ControllerEmu/ControllerEmu.h b/Source/Core/InputCommon/ControllerEmu/ControllerEmu.h index 3f497b1f88..3301672ccf 100644 --- a/Source/Core/InputCommon/ControllerEmu/ControllerEmu.h +++ b/Source/Core/InputCommon/ControllerEmu/ControllerEmu.h @@ -153,7 +153,7 @@ public: // references and GetState(), by extension. This prevents a race condition // which happens while handling a hotplug event because a control reference's State() // could be called before we have finished updating the reference. - static std::unique_lock GetStateLock(); + [[nodiscard]] static std::unique_lock GetStateLock(); std::vector> groups; diff --git a/Source/Core/InputCommon/ControllerInterface/Device.cpp b/Source/Core/InputCommon/ControllerInterface/Device.cpp index 15c403ca24..ebed1ad421 100644 --- a/Source/Core/InputCommon/ControllerInterface/Device.cpp +++ b/Source/Core/InputCommon/ControllerInterface/Device.cpp @@ -309,7 +309,6 @@ DeviceContainer::DetectInput(u32 wait_ms, const std::vector& device for (auto& device_state : device_states) { - device_state.device->UpdateInput(); for (auto& input_state : device_state.input_states) { // We want an input that was initially 0.0 and currently 1.0.