/*************************************************************************** BionxControl Copyright © 2025 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 #include #include #include #include #include #include #include #include #include "bcanimateddelegate.h" #include "bcvalue.h" BCAnimatedDelegate::BCAnimatedDelegate(const BCValueList& valueList, QTableView* view) : QStyledItemDelegate{view}, _valueList{valueList}, _view{view} { } /* QString BCAnimatedDelegate::displayText(const QVariant& dataValue, const QLocale& locale) const { // Wir prüfen, ob im Variant unser Struct steckt if (dataValue.canConvert()) { const BCValue& bc = *dataValue.value(); //qDebug() << " --- YES: " << bc.label; // Hier bauen wir den String zusammen, den man sieht, // wenn KEIN Editor offen ist. // Format: "Label: Wert Einheit" return QString("%1: %2 %3").arg(bc.label, bc.visibleValue, "mmX"); } else { qDebug() << " --- Nö!"; } // Fallback für normale Strings/Zahlen return QStyledItemDelegate::displayText(dataValue, locale); } */ QWidget *BCAnimatedDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex& index) const { QVariant rawData = index.data(Qt::EditRole); //if (!rawData.canConvert()) return QStyledItemDelegate::createEditor(parent, option, index); /* const BCValue& bc = *rawData.value(); // Nur bei Integern den Slider-Editor bauen if (bc.value.typeId() == QMetaType::Int) { QWidget *container = new QWidget(parent); container->setAutoFillBackground(true); QHBoxLayout *layout = new QHBoxLayout(container); layout->setContentsMargins(4, 0, 4, 0); layout->setSpacing(10); // Linkes Label (Name) QLabel *lblName = new QLabel(bc.label, container); lblName->setFixedWidth(80); // Slider QSlider *slider = new QSlider(Qt::Horizontal, container); slider->setRange(0, 100); slider->setObjectName("slider"); // Rechtes Label (Vorschau Wert + Einheit) QLabel *lblUnit = new QLabel(container); lblUnit->setFixedWidth(60); lblUnit->setAlignment(Qt::AlignRight | Qt::AlignVCenter); lblUnit->setObjectName("lblUnit"); layout->addWidget(lblName); layout->addWidget(slider); layout->addWidget(lblUnit); // Live-Update des Labels im Editor (aber noch kein Speichern im Model) connect(slider, &QSlider::valueChanged, this, [=](int val){ lblUnit->setText(QString("%1 %2").arg(val).arg("mm2")); }); return container; } return QStyledItemDelegate::createEditor(parent, option, index); */ } void BCAnimatedDelegate::setEditorData(QWidget *editor, const QModelIndex& index) const { // Daten vom Model in den Editor laden const BCValue& bc = *index.data(Qt::EditRole).value(); QSlider *slider = editor->findChild("slider"); QLabel *lblUnit = editor->findChild("lblUnit"); if (slider && lblUnit) { bool olDriverState = slider->blockSignals(true); slider->setValue(bc.visibleValue.toInt()); slider->blockSignals(olDriverState); lblUnit->setText(QString("%1 %2").arg(bc.visibleValue.toInt()).arg( "mm3")); } else { QStyledItemDelegate::setEditorData(editor, index); } } void BCAnimatedDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex& index) const { // Daten vom Editor zurück ins Model speichern (Beim Schließen) QSlider *slider = editor->findChild("slider"); if (slider) { int value = slider->value(); model->setData(index, value, Qt::EditRole); } else { QStyledItemDelegate::setModelData(editor, model, index); } } void BCAnimatedDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex& index) const { // __fix! editor->setGeometry(option.rect); } QSize BCAnimatedDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex& index) const { return QStyledItemDelegate::sizeHint(option,index); /* QStyleOptionViewItem opt = option; initStyleOption(&opt, index); opt.text = formatDisplayString(index); QStyle *style = opt.widget ? opt.widget->style() : QApplication::style(); return style->sizeFromContents(QStyle::CT_ItemViewItem, &opt, QSize(), opt.widget); */ } void BCAnimatedDelegate::paint(QPainter *painter, const QStyleOptionViewItem& option, const QModelIndex& index) const { // 1. Standard-Zeichnen (Text, Hintergrund, Selection) durchführen QStyledItemDelegate::paint(painter, option, index); //QPen pen(QColor(255, 165, 0)); // Orange /* if (index.row() == _highlightedRow && _opacity > 0.0) { painter->save(); qDebug() << " --- is highlight: " << index.row(); QColor highlightColor( 0xFF9800 ); highlightColor.setAlphaF(_opacity); QPen pen(highlightColor, 3); painter->setPen(pen); painter->setBrush(Qt::NoBrush); painter->drawRoundedRect(option.rect.adjusted(2, 2, -2, -2), 8, 8); painter->restore(); } */ int row = index.row(); if (index.column() == 1 ) { if( m_rowOpacities.contains(row)) { paintHighlightRow(painter,option,index); } } } /* qreal opacity = m_rowOpacities.value(row); if (opacity > 0.01) { painter->save(); painter->setOpacity(opacity); painter->fillRect(option.rect, QColor(255, 140, 0, 120)); painter->restore(); } */ void BCAnimatedDelegate::paintHighlightRow(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const { painter->save(); painter->setRenderHint(QPainter::Antialiasing); int row = index.row(); qreal opacity = m_rowOpacities.value(row); painter->setOpacity(opacity); // Margin von 4px QRect itemRect = option.rect.adjusted(3, 3, -3, -3); // Border von 2px berücksichtigen (nach innen) //QRect contentRect = itemRect.adjusted(2, 2, -2, -2); // painter->fillRect(contentRect,Qt::green); /* // Hintergrund (weiß) painter->setBrush(Qt::white); painter->setPen(Qt::NoPen); painter->drawRoundedRect(itemRect, 8, 8); */ // Border (2px solid #2196F3) QPen borderPen( Qt::red, 1); painter->setPen(borderPen); painter->setBrush(Qt::NoBrush); painter->drawRoundedRect(itemRect, 2, 2); // Padding von 8px für den Content //QRect textRect = contentRect.adjusted(8, 8, -8, -8); /* // Text zeichnen painter->setPen(Qt::black); // oder option.palette.color(QPalette::Text) QString text = index.data(Qt::DisplayRole).toString(); painter->drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, text); */ painter->restore(); } void BCAnimatedDelegate::onHighlightRow(int row) { // Alte Animation für diese Zeile stoppen falls vorhanden if (m_rowAnimations.contains(row)) { m_rowAnimations[row]->stop(); m_rowAnimations[row]->deleteLater(); } // QVariantAnimation ist flexibler als QPropertyAnimation auto* anim = new QVariantAnimation(this); anim->setDuration(800); anim->setStartValue(0.0); anim->setEndValue(1.0); // Custom Easing für Fade-in/out Effekt anim->setEasingCurve(QEasingCurve::OutQuad); connect(anim, &QVariantAnimation::valueChanged, this, [this, row](const QVariant& value) { qreal progress = value.toReal(); qreal opacity; // Schnelles Fade-in (20%), langsames Fade-out (80%) if (progress < 0.2) { opacity = progress * 5.0; // 0->1 in 20% } else { opacity = 1.0 - ((progress - 0.2) / 0.8); // 1->0 in 80% } m_rowOpacities[row] = opacity; updateRow(row); }); connect(anim, &QVariantAnimation::finished, this, [this, row, anim]() { m_rowOpacities.remove(row); m_rowAnimations.remove(row); updateRow(row); anim->deleteLater(); }); m_rowAnimations[row] = anim; anim->start(QAbstractAnimation::DeleteWhenStopped); } // Optional: alle Highlights sofort clearen void BCAnimatedDelegate::clearAllHighlights() { for(auto* anim : std::as_const(m_rowAnimations)) { anim->stop(); anim->deleteLater(); } m_rowAnimations.clear(); m_rowOpacities.clear(); if (_view) { _view->viewport()->update(); } } void BCAnimatedDelegate::updateRow(int row) { if (_view && _view->model() && row >= 0) { QModelIndex idx = _view->model()->index(row,1); QRect rect = _view->visualRect(idx); if (!rect.isEmpty()) { _view->viewport()->update(rect); } } }