/*************************************************************************** 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 @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 ***************************************************************************/ #include #include #include BCValueSlider::BCValueSlider( QWidget *parent ) : QWidget(parent) { setupUi(this); // wir wollen ja modern sein _slider->setStyle(new BCValueSliderStyle()); setAutoFillBackground(true); QSizePolicy sp = _commitButton->sizePolicy(); sp.setRetainSizeWhenHidden(true); // <--- Das ist der magische Schalter _commitButton->setSizePolicy(sp); // Wenn Slider bewegt wird -> Signal nach außen senden connect(_slider, &QSlider::valueChanged, this, [this](int val) { emit valueChanged(val); }); // Wenn Reset gedrückt wird -> Slider auf 0 (löst auch valueChanged aus) connect(_commitButton, &QPushButton::clicked, this, [this]() { emit valueCommited( value() ); }); } int BCValueSlider::value() const { return _slider->value(); } void BCValueSlider::setValueAndRange( const BCValue::ValueRange& params ) { _slider->setRange( params.min, params.max); // Block Signals verhindern Endlosschleifen, falls das Model // das Widget während des Updates neu setzt (passiert manchmal bei Live-Updates). if (params.value != _slider->value()) { bool blocked = _slider->blockSignals(true); _slider->setValue(params.value); _slider->blockSignals(blocked); } } QRect BCValueSlider::updateEditorRect( const QRect& rect) { return rect.adjusted ( rect.width() - cTextBlockOffset, // Von rechts: cTextBlockOffset (==130) px (Breite der Progress Bar) 0, // Oben: kein Offset -cPaddingRight, // Rechts: 8px Padding 0 // Unten: kein Offset ); } /** * @brief Zeichnet eine passiven Slider, um den möglichen Wertebereich des übergebenen BCValue anzuzeigen. */ void BCValueSlider::paintSliderIndicator(QPainter* painter, const QRect& rect, double ratio ) { return; // Kleinen Slider-Indikator zeichnen painter->save(); painter->setRenderHint(QPainter::Antialiasing); int adjX = rect.width() - 130; //cTextBlockOffset; // Mini Progress Bar: der Gesamtbereich QRect barRect = rect.adjusted( adjX, 12, -10-24, -12 ); painter->setPen(Qt::NoPen); painter->setBrush(QColor(0xE0E0E0)); painter->drawRoundedRect(barRect, 2, 2); qDebug() << " --- doPaint: in paintSliderIndicator1: " << rect; qDebug() << " --- doPaint: in paintSliderIndicator2: " << barRect; // Mini Progress Bar: der Wertebereich barRect.setWidth( ratio * barRect.width() ); painter->setBrush(QColor(0x0078D4)); painter->drawRoundedRect(barRect, 2, 2); painter->restore(); } void BCValueSlider::paintSliderIndicator2(QPainter* painter, const QRect& rect, double ratio ) { // Kleinen Slider-Indikator zeichnen painter->save(); painter->setRenderHint(QPainter::Antialiasing); qDebug() << " --- doPaint: in paintSliderIndicator: " <setPen(Qt::NoPen); painter->setBrush(QColor(0xE0E0E0)); painter->drawRoundedRect(barRect, 2, 2); // Mini Progress Bar: der Wertebereich barRect.setWidth( ratio * barRect.width() ); painter->setBrush(QColor(0x0078D4)); painter->drawRoundedRect(barRect, 2, 2); */ BCValueSlider::updateEditorRect( rect ); painter->setBrush(Qt::gray); painter->drawRoundedRect(rect, 2, 2); painter->setBrush(Qt::blue); painter->drawRoundedRect(barRect, 2, 2); painter->restore(); } BCValueSlider::BCValueSliderStyle::BCValueSliderStyle() : QProxyStyle() { } int BCValueSlider::BCValueSliderStyle::pixelMetric(PixelMetric metric, const QStyleOption* option, const QWidget* widget ) const { switch (metric) { case PM_SliderThickness: return 24; // Höhe für horizontalen Slider case PM_SliderLength: return 16; // Handle-Größe case PM_SliderControlThickness: return 16; case PM_SliderSpaceAvailable: if (option) { if (const QStyleOptionSlider* sliderOpt = qstyleoption_cast(option)) { return sliderOpt->rect.width() - 20; } } return QProxyStyle::pixelMetric(metric, option, widget); default: return QProxyStyle::pixelMetric(metric, option, widget); } } QRect BCValueSlider::BCValueSliderStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex* opt,SubControl sc, const QWidget* widget) const { if (cc == CC_Slider) { if (const QStyleOptionSlider* slider = qstyleoption_cast(opt)) { QRect rect = slider->rect; int handleSize = 16; if (sc == SC_SliderHandle) { // Handle Position korrekt berechnen int range = slider->maximum - slider->minimum; int pos = slider->sliderPosition - slider->minimum; int pixelRange = rect.width() - handleSize; int pixelPos = (range != 0) ? (pos * pixelRange) / range : 0; return QRect(rect.x() + pixelPos, rect.center().y() - handleSize / 2, handleSize, handleSize); } } } return QProxyStyle::subControlRect(cc, opt, sc, widget); } void BCValueSlider::BCValueSliderStyle::drawComplexControl(ComplexControl control, const QStyleOptionComplex* option, QPainter* painter, const QWidget* widget) const { if (control == CC_Slider) { if (const QStyleOptionSlider* slider = qstyleoption_cast(option)) { painter->setRenderHint(QPainter::Antialiasing); // Fluent Colors QColor accentColor(0, 120, 212); // #0078D4 QColor bgColor(255, 255, 255); // White background drawHorizontalFluentSlider(painter, slider, accentColor, bgColor); return; } } QProxyStyle::drawComplexControl(control, option, painter, widget); } void BCValueSlider::BCValueSliderStyle::drawHorizontalFluentSlider(QPainter* painter, const QStyleOptionSlider* slider, const QColor& activeColor, const QColor& bgColor) const { QRect groove = slider->rect; QRect handleRect = subControlRect(CC_Slider, slider, SC_SliderHandle, nullptr); // Das 'subControlRect' für den SC_SliderHandle ist _nicht_ mittig handleRect.setY( handleRect.y() + 2 ); qDebug() << " --- doPaint: drawHorizontalFluentSlider" << groove << " Handle: " << handleRect; paintSliderIndicator2(painter, groove, 0.5 ); painter->setBrush(Qt::red); painter->drawRect(handleRect); return; // Handle (Thumb) - Fluent style is more subtle int handleSize = 14; QRect thumbRect(handleRect.center().x() - handleSize / 2, handleRect.center().y() - handleSize / 2, handleSize, handleSize); /* // Hover effect - subtle glow if (slider->state & State_MouseOver) { painter->setBrush(QColor(activeColor.red(), activeColor.green(), activeColor.blue(), 30)); int glowSize = 16; QRect glow(handle.center().x() - glowSize / 2, handle.center().y() - glowSize / 2, glowSize, glowSize); painter->drawEllipse(glow); } */ // Thumb painter->setBrush(bgColor); painter->setPen(QPen(activeColor, 2)); painter->drawEllipse(thumbRect); /* // Inner circle for pressed state if (slider->state & State_Sunken) { int innerSize = 6; QRect inner(handle.center().x() - innerSize / 2, handle.center().y() - innerSize / 2, innerSize, innerSize); painter->setPen(Qt::NoPen); painter->setBrush(activeColor); painter->drawEllipse(inner); } */ }