Files
BionxControl/bctoggleswitch.cpp

225 lines
5.8 KiB
C++
Raw Normal View History

2026-02-09 16:03:09 +01:00
/***************************************************************************
BionxControl
© 2025 -2026 christoph holzheuer
christoph.holzheuer@gmail.com
Using:
mhs_can_drv.c
© 2011 - 2023 by MHS-Elektronik GmbH & Co. KG, Germany
Klaus Demlehner, klaus@mhs-elektronik.de
@see www.mhs-elektronik.de
Based on Bionx data type descriptions from:
BigXionFlasher USB V 0.2.4 rev. 97
© 2011-2013 by Thomas Koenig <info@bigxionflasher.org>
@see www.bigxionflasher.org
Bionx Bike Info
© 2018 Thorsten Schmidt (tschmidt@ts-soft.de)
@see www.ts-soft.de
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.
@see https://github.com/bikemike/bionx-bikeinfo
***************************************************************************/
2026-01-10 16:37:59 +01:00
2026-01-15 21:26:10 +01:00
#include "bctoggleswitch.h"
2026-01-10 16:37:59 +01:00
#include <QPainter>
#include <QPropertyAnimation>
#include <QEasingCurve>
#include <QEnterEvent>
#include <QEvent>
BCToggleSwitch::BCToggleSwitch(QWidget *parent)
: QAbstractButton(parent)
, m_position(0.0f)
{
setCheckable(true);
setCursor(Qt::PointingHandCursor);
setFixedSize(44, 22); // Standardgröße
// Animation initialisieren
m_animation = new QPropertyAnimation(this, "position", this);
m_animation->setDuration(200);
m_animation->setEasingCurve(QEasingCurve::OutQuad);
// Signal verknüpfen
2026-03-29 23:30:42 +02:00
connect(this, &QAbstractButton::toggled, this, [this](bool checked)
{
2026-01-10 16:37:59 +01:00
m_animation->stop();
m_animation->setStartValue(m_position);
m_animation->setEndValue(checked ? 1.0f : 0.0f);
m_animation->start();
});
}
float BCToggleSwitch::position() const
{
return m_position;
}
2026-01-15 21:26:10 +01:00
void BCToggleSwitch::setPosition(float pos)
{
2026-01-10 16:37:59 +01:00
m_position = pos;
update(); // Trigger Repaint
}
QSize BCToggleSwitch::sizeHint() const
{
return QSize(44, 22);
}
void BCToggleSwitch::paintEvent(QPaintEvent *)
{
QPainter p(this);
p.setRenderHint(QPainter::Antialiasing);
2026-03-30 21:24:29 +02:00
// Option A: Nutze die Standard-Hintergrundfarbe des aktuellen Qt-Themes
p.fillRect(rect(), palette().window());
2026-03-31 18:18:37 +02:00
// Auf deaktivierten Zustand prüfen und die statische Methode aufrufen
if (!isEnabled()) {
paintToggleIndicator(&p, rect(), isChecked(), m_position, palette());
return;
}
2026-01-10 16:37:59 +01:00
// --- Farben ---
// Tipp: In einem echten Projekt diese Farben als const statics
// oder aus der QPalette laden.
2026-01-15 21:26:10 +01:00
QColor offBorderColor = QColor(0x8D8D8D);
QColor offKnobColor = QColor(0x5D5D5D);
QColor onColor = QColor(0x0078D4); // Fluent Blue
2026-01-10 16:37:59 +01:00
QColor white = Qt::white;
QRectF rect = this->rect();
qreal radius = rect.height() / 2.0;
// 1. Hintergrund (Track) zeichnen
p.setPen(Qt::NoPen);
if (isChecked() || m_position > 0.5f)
{
// AN-Zustand: Hintergrund gefüllt
p.setBrush(onColor);
p.drawRoundedRect(rect, radius, radius);
}
else
{
// AUS-Zustand: Nur Rahmen
p.setBrush(Qt::NoBrush);
// Hover-Status prüfen
if (underMouse())
p.setPen(QPen(offBorderColor.darker(120), 1.5));
else
p.setPen(QPen(offBorderColor, 1.5));
// Rechteck etwas verkleinern, damit der Rahmen nicht abgeschnitten wird
p.drawRoundedRect(rect.adjusted(1, 1, -1, -1), radius - 1, radius - 1);
}
// 2. Knopf (Thumb) zeichnen
qreal padding = 3.0;
qreal knobDiameter = rect.height() - (2 * padding);
// Interpolation der Position
qreal startX = padding;
qreal endX = rect.width() - knobDiameter - padding;
qreal currentX = startX + (m_position * (endX - startX));
QRectF knobRect(currentX, padding, knobDiameter, knobDiameter);
2026-01-15 21:26:10 +01:00
if (isChecked() || m_position > 0.5f)
{
2026-01-10 16:37:59 +01:00
p.setBrush(white);
2026-01-15 21:26:10 +01:00
}
else
{
if (underMouse())
p.setBrush(offKnobColor.darker(110));
else
p.setBrush(offKnobColor);
2026-01-10 16:37:59 +01:00
}
p.setPen(Qt::NoPen);
p.drawEllipse(knobRect);
}
2026-03-31 18:18:37 +02:00
void BCToggleSwitch::paintToggleIndicator(QPainter* p, const QRect& rect, bool isChecked, float position, const QPalette& palette)
{
// --- Farben für den deaktivierten Zustand ---
QColor disabledBorderColor = palette.color(QPalette::Disabled, QPalette::Window);
if (!disabledBorderColor.isValid() || disabledBorderColor == Qt::black) {
disabledBorderColor = QColor(0xCCCCCC); // Fallback auf ein neutrales Hellgrau
}
QColor disabledKnobColor = QColor(0xAAAAAA);
QColor disabledOnColor = QColor(0x99C2E3); // Entsättigtes, blasses "Fluent Blue"
QColor white = QColor(0xF0F0F0); // Leicht abgedunkeltes Weiß
QRectF r(rect);
qreal radius = r.height() / 2.0;
// 1. Hintergrund (Track) zeichnen
p->setPen(Qt::NoPen);
if (isChecked || position > 0.5f)
{
// AN-Zustand (deaktiviert)
p->setBrush(disabledOnColor);
p->drawRoundedRect(r, radius, radius);
}
else
{
// AUS-Zustand (deaktiviert)
p->setBrush(Qt::NoBrush);
p->setPen(QPen(disabledBorderColor, 1.5));
// Rechteck etwas verkleinern, damit der Rahmen nicht abgeschnitten wird
p->drawRoundedRect(r.adjusted(1, 1, -1, -1), radius - 1, radius - 1);
}
// 2. Knopf (Thumb) zeichnen
qreal padding = 3.0;
qreal knobDiameter = r.height() - (2 * padding);
// X- und Y-Offsets des übergebenen Rects berücksichtigen!
qreal startX = r.x() + padding;
qreal endX = r.x() + r.width() - knobDiameter - padding;
qreal currentX = startX + (position * (endX - startX));
QRectF knobRect(currentX, r.y() + padding, knobDiameter, knobDiameter);
p->setPen(Qt::NoPen);
if (isChecked || position > 0.5f)
{
p->setBrush(white);
}
else
{
p->setBrush(disabledKnobColor);
}
p->drawEllipse(knobRect);
}
2026-01-10 16:37:59 +01:00
void BCToggleSwitch::enterEvent(QEnterEvent *event)
{
update(); // Für Hover-Effekt neu zeichnen
QAbstractButton::enterEvent(event);
}
void BCToggleSwitch::leaveEvent(QEvent *event)
{
update(); // Hover entfernen
QAbstractButton::leaveEvent(event);
}