diff --git a/BionxControl.pro b/BionxControl.pro index 57e49c8..87f4e0b 100644 --- a/BionxControl.pro +++ b/BionxControl.pro @@ -47,6 +47,7 @@ windows SOURCES += \ bc.cpp \ bcanimateddelegate.cpp \ + bcdelightpmwidget.cpp \ bcdeviceview.cpp \ bcdriver.cpp \ bcdriverstatewidget.cpp \ @@ -66,6 +67,7 @@ SOURCES += \ HEADERS += \ bc.h \ bcanimateddelegate.h \ + bcdelightpmwidget.h \ bcdeviceview.h \ bcdriver.h \ bcdriverstatewidget.h \ diff --git a/bcdelightpmwidget.cpp b/bcdelightpmwidget.cpp new file mode 100644 index 0000000..6f56102 --- /dev/null +++ b/bcdelightpmwidget.cpp @@ -0,0 +1,209 @@ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +BCDelightPMWidget::BCDelightPMWidget(QWidget *parent) + : QObject(parent), _playGround{parent} +{ + loadWidgetsFromResources(); +} + + +// Die Methode zum automatischen Einlesen +void BCDelightPMWidget::loadWidgetsFromResources() +{ + + QString resourcePath = ":/resources/smile"; + + // 2. Iterator erstellen + // QDir::Files sorgt dafür, dass wir nur echte Dateien finden, keine Ordner wie "." oder ".." + // QDirIterator::Subdirectories würde auch in Unterordnern suchen (falls nötig) + QDirIterator it(resourcePath, QDir::Files); + + //QFileInfoList fileList: + // 3. Schleife: Solange es noch Einträge gibt + while (it.hasNext()) + { + // Iteriert zum nächsten Eintrag und gibt den kompletten virtuellen Pfad zurück + // z.B. ":/icons/ball_red.png" + QString fullPath = it.next(); + + // Optional: Nur den Dateinamen holen (z.B. "ball_red.png") + // QString fileName = it.fileName(); + + qDebug() << "Gefundenes Icon:" << fullPath; + + // Eine Zufallsfarbe für den Button-Hintergrund generieren + QStringList colors = {"#ff5555", "#50fa7b", "#8be9fd", "#ffb86c"}; + QString randomColor = colors.at(QRandomGenerator::global()->bounded(colors.size())); + + // Ihre Funktion aufrufen und den Pfad übergeben + createFlyingWidget(fullPath, randomColor); + } + + +} + +void BCDelightPMWidget::createFlyingWidget(const QString& iconPath, const QString &color) +{ + // 1. Button als Kind des Playground erstellen + QPushButton *btn = new QPushButton(_playGround); + + // 2. Das Icon laden und setzen + QPixmap pixmap(iconPath); + QIcon icon(pixmap); + btn->setIcon(icon); + + // 3. WICHTIG: Icon-Größe und Button-Größe synchronisieren + // Damit das Bild den Button voll ausfüllt + QSize size(128, 128); + btn->setFixedSize(size); // Die Klick-Fläche + btn->setIconSize(size); // Das Bild darin + + // 4. Stylesheet: Alle Standard-Rahmen und Hintergründe entfernen + // "border: none" entfernt den 3D-Rahmen + // "background: transparent" macht den Rest unsichtbar + btn->setStyleSheet( + "QPushButton {" + " border: none;" + " background-color: transparent;" + " outline: none;" /* Entfernt den Fokus-Rahmen beim Klicken */ + "}" + // Optional: Kleiner visueller Effekt beim Drücken (Bild bewegt sich leicht) + "QPushButton:pressed {" + " padding-top: 4px;" + " padding-left: 4px;" + "}" + ); + + btn->show(); + + // --- NEU: Opacity Effekt hinzufügen --- + // 1. Effekt erstellen. 'btn' wird der Parent und kümmert sich ums Löschen. + QGraphicsOpacityEffect *opacityEff = new QGraphicsOpacityEffect(btn); + + // 2. Startwert setzen (1.0 = voll sichtbar) + opacityEff->setOpacity(1.0); + + // 3. Dem Widget zuweisen. WICHTIG: Das Widget übernimmt den Besitz. + btn->setGraphicsEffect(opacityEff); + // -------------------------------------- + + btn->show(); + // ... (Rest der Funktion: move und append) ... + btn->move(50 + _flyingWidgets.size() * 60, 50); + _flyingWidgets.append(btn); + + + // Startzustand: Unsichtbar in der Mitte + btn->move(_playGround->width()/2, _playGround->height()/2); + opacityEff->setOpacity(0.0); + +} +void BCDelightPMWidget::onStartChaos() +{ + // Master-Gruppe, damit alle Widgets gleichzeitig starten + QParallelAnimationGroup *masterGroup = new QParallelAnimationGroup(this); + + // Gemeinsamer Startpunkt berechnen (Mitte des Playgrounds) + // Wir ziehen die halbe Größe eines Widgets (ca. 25px) ab, damit sie wirklich zentriert sind + int centerX = (_playGround->width() / 2) - 25; + int centerY = (_playGround->height() / 2) - 25; + QPoint startPoint(centerX, centerY); + + for (QWidget *widget : std::as_const(_flyingWidgets)) + { + + QParallelAnimationGroup *widgetGroup = new QParallelAnimationGroup(masterGroup); + + // --------------------------------------------------------- + // 1. Die Bogen-Animation (QVariantAnimation statt QPropertyAnimation) + // --------------------------------------------------------- + + // ZIELE UND STÜTZPUNKTE BERECHNEN + int maxX = _playGround->width() - widget->width(); + int maxY = _playGround->height() - widget->height(); + QPoint endPoint( + QRandomGenerator::global()->bounded(qMax(0, maxX)), + QRandomGenerator::global()->bounded(qMax(0, maxY)) + ); + + // Der Kontrollpunkt bestimmt die Kurve. + // Für eine Rakete muss er viel HÖHER liegen als Start und Ziel. + // Wir nehmen die Mitte zwischen Start/Ziel und gehen 300px nach oben (Y minus). + int controlX = (startPoint.x() + endPoint.x()) / 2; + int controlY = qMin(startPoint.y(), endPoint.y()) - 300; + + // Pfad erstellen (Quadratische Bézierkurve) + QPainterPath path; + path.moveTo(startPoint); + // quadTo(Kontrollpunkt, Endpunkt) + path.quadTo(controlX, controlY, endPoint.x(), endPoint.y()); + + // Die Animation treibt den Fortschritt von 0.0 bis 1.0 + QVariantAnimation *animCurve = new QVariantAnimation(); + int duration = 2600 + QRandomGenerator::global()->bounded(800); + animCurve->setDuration(duration); + animCurve->setStartValue(0.0); + animCurve->setEndValue(1.0); + + // Für ballistische Flugbahnen ist 'OutQuad' oder 'OutSine' realistisch + // (Schneller Start, oben langsamer, unten wieder schneller - physikalisch komplex, + // aber OutQuad sieht gut aus für "Wurf") + animCurve->setEasingCurve(QEasingCurve::OutQuad); + + // WICHTIG: Lambda, um bei jedem Schritt die Position zu setzen + // Wir müssen 'widget' und 'path' in das Lambda capturen (by value für path ist ok) + connect(animCurve, &QVariantAnimation::valueChanged, [widget, path](const QVariant &val){ + qreal progress = val.toReal(); + + // Magie: Berechne den Punkt auf der Kurve bei 'progress' Prozent + QPointF currentPos = path.pointAtPercent(progress); + + widget->move(currentPos.toPoint()); + }); + + widgetGroup->addAnimation(animCurve); + + // --------------------------------------------------------- + // 2. Fade-Out (Bleibt fast gleich) + // --------------------------------------------------------- + QGraphicsOpacityEffect *eff = qobject_cast(widget->graphicsEffect()); + if (eff) { + QPropertyAnimation *animFade = new QPropertyAnimation(eff, "opacity"); + animFade->setDuration(duration); + animFade->setStartValue(1.0); + animFade->setEndValue(0.0); + // Erst am Ende ausblenden (ExpoCurve), damit man den Flugbogen sieht + animFade->setEasingCurve(QEasingCurve::InExpo); + widgetGroup->addAnimation(animFade); + } + + masterGroup->addAnimation(widgetGroup); + } + + + + + + // Speicher aufräumen, wenn alles vorbei ist + // Hinweis: Die Widgets bleiben danach unsichtbar (Opacity 0), existieren aber noch. + connect(masterGroup, &QAbstractAnimation::finished, masterGroup, &QObject::deleteLater); + + masterGroup->start(); +} diff --git a/bcdelightpmwidget.h b/bcdelightpmwidget.h new file mode 100644 index 0000000..5d3fe51 --- /dev/null +++ b/bcdelightpmwidget.h @@ -0,0 +1,33 @@ +#ifndef BCDELIGHTPMWIDGET_H +#define BCDELIGHTPMWIDGET_H + +#include + +/** + * @brief The BCDelightPMWidget class : Graphische Effekte für unseren Produktmanager Simon. + */ + +class BCDelightPMWidget : public QObject +{ + Q_OBJECT + +public: + + BCDelightPMWidget( QWidget* parent ); + +public slots: + + void onStartChaos(); + +protected: + + void loadWidgetsFromResources(); + void createFlyingWidget(const QString& iconPath, const QString &color); + + QWidget *_playGround{}; + + // Liste der Widgets, die wir bewegen + QList _flyingWidgets; +}; + +#endif // BCDELIGHTPMWIDGET_H diff --git a/bcdeviceview.h b/bcdeviceview.h index af21cfe..da49569 100644 --- a/bcdeviceview.h +++ b/bcdeviceview.h @@ -64,9 +64,9 @@ protected: void resizeEvent(QResizeEvent *event) override; - bool _firstExpose{true}; - BCDevice::ID _devideID{BCDevice::ID::Invalid}; - BCValueModel _valueModel; + bool _firstExpose{true}; + BCDevice::ID _devideID{BCDevice::ID::Invalid}; + BCValueModel _valueModel; BCAnimatedDelegate* _itemDelegate{}; diff --git a/bcmainwindow.cpp b/bcmainwindow.cpp index d849d97..52fb3d8 100644 --- a/bcmainwindow.cpp +++ b/bcmainwindow.cpp @@ -99,15 +99,17 @@ void BCMainWindow::initMainWindow() }); if( _devicePanels.contains(deviceID) ) - { - BCDeviceView* currentPanel = _devicePanels[deviceID]; - // ... und ihre device ID - currentPanel->setDeviceID( deviceID ); - // Wenn ein Device (entspricht einem Datenmodel) fertig eingelesen wurde, - // wird es weitergereicht. - // Problem: alle Panels bekommen alle Datenmodelle angeboten. - connect( &_dataManager, &BCXmlLoader::valueListReady, currentPanel, &BCDeviceView::onValueListReady ); - } + { + BCDeviceView* currentPanel = _devicePanels[deviceID]; + // ... und ihre device ID + currentPanel->setDeviceID( deviceID ); + // Wenn ein Device (entspricht einem Datenmodel) fertig eingelesen wurde, + // wird es weitergereicht. + // Problem: alle Panels bekommen alle Datenmodelle angeboten. + connect( &_dataManager, &BCXmlLoader::valueListReady, currentPanel, &BCDeviceView::onValueListReady ); + + connect( currentPanel->model(), SIGNAL(makeSimonHappy()), this, SLOT(onStartAnimation() ) ); + } }; // Wir wollen die Devices den Views zuordnen können @@ -162,6 +164,9 @@ void BCMainWindow::initMainWindow() }); */ + // not least + _delightWidget = new BCDelightPMWidget(this); + } /* @@ -255,6 +260,13 @@ void BCMainWindow::onShowMessage( const QString& message, int timeOut ) } +void BCMainWindow::onStartAnimation() +{ + qDebug() << " FEIN!"; + _delightWidget->onStartChaos(); +} + + void BCMainWindow::onDriverStateChanged( BCDriver::DriverState state, const QString& message ) { Q_UNUSED(state) diff --git a/bcmainwindow.h b/bcmainwindow.h index 07adfdd..57c61f2 100644 --- a/bcmainwindow.h +++ b/bcmainwindow.h @@ -39,6 +39,7 @@ #include #include #include +#include class BCDeviceView; @@ -65,6 +66,7 @@ public slots: void onSyncDeviceView(); void onShowMessage( const QString& message, int timeOut=3000); + void onStartAnimation(); signals: @@ -86,11 +88,11 @@ protected: // und dem Device, das sie darstellen. using BCDeviceViews = QHash; - BCDeviceViews _devicePanels; - BCDeviceView* _currentPanel{}; - - QThread _worker; - BCTransmitter _transmitter; + BCDeviceViews _devicePanels; + BCDeviceView* _currentPanel{}; + BCDelightPMWidget* _delightWidget{}; + QThread _worker; + BCTransmitter _transmitter; static constexpr const char* cBCKeyHeaderLabel = "BCHeaderLabel"; static constexpr const char* cDarkModeStyle = ":bc_dark.qss"; diff --git a/bctoggleswitch.cpp b/bctoggleswitch.cpp index 9eedb6b..f5facb4 100644 --- a/bctoggleswitch.cpp +++ b/bctoggleswitch.cpp @@ -7,9 +7,6 @@ #include - - - BCToggleSwitch::BCToggleSwitch(QWidget *parent) : QAbstractButton(parent) , m_position(0.0f) diff --git a/bcvaluemodel.cpp b/bcvaluemodel.cpp index 43f1669..dd62ca6 100644 --- a/bcvaluemodel.cpp +++ b/bcvaluemodel.cpp @@ -190,6 +190,12 @@ bool BCValueModel::setData(const QModelIndex& index, const QVariant& variant, in // Checken ob Int oder Double if (variant.canConvert()) { + qDebug() << "--- new VALUE: " << variant.toInt(); + if( variant.toInt() == 42) + { + qDebug() << "--- YES! " << variant.toInt(); + emit makeSimonHappy(); + } value->rawValue = variant.toInt(); } diff --git a/bcvaluemodel.h b/bcvaluemodel.h index f0f61c7..9c05ec4 100644 --- a/bcvaluemodel.h +++ b/bcvaluemodel.h @@ -64,9 +64,12 @@ public: QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override; - void updateValue(int row, BCValue::Flags newState, uint32_t rawValue ); +signals: + + void makeSimonHappy(); + protected: // Die eigentlichen Werte wohnen im tatsächlich hier, im Model. diff --git a/bionxcontrol.qrc b/bionxcontrol.qrc index 42ebb57..ef3ffb3 100644 --- a/bionxcontrol.qrc +++ b/bionxcontrol.qrc @@ -12,5 +12,22 @@ resources/sync_yellow.png resources/sync.png resources/bc_dark.qss + resources/smile/face-angel.png + resources/smile/face-angry.png + resources/smile/face-cool.png + resources/smile/face-crying.png + resources/smile/face-embarrassed.png + resources/smile/face-glasses.png + resources/smile/face-kiss.png + resources/smile/face-laugh.png + resources/smile/face-monkey.png + resources/smile/face-plain.png + resources/smile/face-raspberry.png + resources/smile/face-sad.png + resources/smile/face-sick.png + resources/smile/face-smile.png + resources/smile/face-smile-big.png + resources/smile/face-smirk.png + resources/smile/face-surprise.png diff --git a/resources/smile/face-angel.png b/resources/smile/face-angel.png new file mode 100644 index 0000000..9666048 Binary files /dev/null and b/resources/smile/face-angel.png differ diff --git a/resources/smile/face-angry.png b/resources/smile/face-angry.png new file mode 100644 index 0000000..5d721a3 Binary files /dev/null and b/resources/smile/face-angry.png differ diff --git a/resources/smile/face-cool.png b/resources/smile/face-cool.png new file mode 100644 index 0000000..36cc42e Binary files /dev/null and b/resources/smile/face-cool.png differ diff --git a/resources/smile/face-crying.png b/resources/smile/face-crying.png new file mode 100644 index 0000000..8c72f43 Binary files /dev/null and b/resources/smile/face-crying.png differ diff --git a/resources/smile/face-embarrassed.png b/resources/smile/face-embarrassed.png new file mode 100644 index 0000000..686d5ec Binary files /dev/null and b/resources/smile/face-embarrassed.png differ diff --git a/resources/smile/face-glasses.png b/resources/smile/face-glasses.png new file mode 100644 index 0000000..0b512c5 Binary files /dev/null and b/resources/smile/face-glasses.png differ diff --git a/resources/smile/face-kiss.png b/resources/smile/face-kiss.png new file mode 100644 index 0000000..21d59ab Binary files /dev/null and b/resources/smile/face-kiss.png differ diff --git a/resources/smile/face-laugh.png b/resources/smile/face-laugh.png new file mode 100644 index 0000000..3109357 Binary files /dev/null and b/resources/smile/face-laugh.png differ diff --git a/resources/smile/face-monkey.png b/resources/smile/face-monkey.png new file mode 100644 index 0000000..0354d24 Binary files /dev/null and b/resources/smile/face-monkey.png differ diff --git a/resources/smile/face-plain.png b/resources/smile/face-plain.png new file mode 100644 index 0000000..62de047 Binary files /dev/null and b/resources/smile/face-plain.png differ diff --git a/resources/smile/face-raspberry.png b/resources/smile/face-raspberry.png new file mode 100644 index 0000000..0d6eb39 Binary files /dev/null and b/resources/smile/face-raspberry.png differ diff --git a/resources/smile/face-sad.png b/resources/smile/face-sad.png new file mode 100644 index 0000000..65adb64 Binary files /dev/null and b/resources/smile/face-sad.png differ diff --git a/resources/smile/face-sick.png b/resources/smile/face-sick.png new file mode 100644 index 0000000..05bf5a6 Binary files /dev/null and b/resources/smile/face-sick.png differ diff --git a/resources/smile/face-smile-big.png b/resources/smile/face-smile-big.png new file mode 100644 index 0000000..572aa0a Binary files /dev/null and b/resources/smile/face-smile-big.png differ diff --git a/resources/smile/face-smile.png b/resources/smile/face-smile.png new file mode 100644 index 0000000..0199dcc Binary files /dev/null and b/resources/smile/face-smile.png differ diff --git a/resources/smile/face-smirk.png b/resources/smile/face-smirk.png new file mode 100644 index 0000000..27b77f9 Binary files /dev/null and b/resources/smile/face-smirk.png differ diff --git a/resources/smile/face-surprise.png b/resources/smile/face-surprise.png new file mode 100644 index 0000000..e5737ef Binary files /dev/null and b/resources/smile/face-surprise.png differ