Added smiles.
@@ -47,6 +47,7 @@ windows
|
|||||||
SOURCES += \
|
SOURCES += \
|
||||||
bc.cpp \
|
bc.cpp \
|
||||||
bcanimateddelegate.cpp \
|
bcanimateddelegate.cpp \
|
||||||
|
bcdelightpmwidget.cpp \
|
||||||
bcdeviceview.cpp \
|
bcdeviceview.cpp \
|
||||||
bcdriver.cpp \
|
bcdriver.cpp \
|
||||||
bcdriverstatewidget.cpp \
|
bcdriverstatewidget.cpp \
|
||||||
@@ -66,6 +67,7 @@ SOURCES += \
|
|||||||
HEADERS += \
|
HEADERS += \
|
||||||
bc.h \
|
bc.h \
|
||||||
bcanimateddelegate.h \
|
bcanimateddelegate.h \
|
||||||
|
bcdelightpmwidget.h \
|
||||||
bcdeviceview.h \
|
bcdeviceview.h \
|
||||||
bcdriver.h \
|
bcdriver.h \
|
||||||
bcdriverstatewidget.h \
|
bcdriverstatewidget.h \
|
||||||
|
|||||||
209
bcdelightpmwidget.cpp
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
|
||||||
|
|
||||||
|
#include <QPropertyAnimation>
|
||||||
|
#include <QSequentialAnimationGroup>
|
||||||
|
#include <QParallelAnimationGroup>
|
||||||
|
#include <QRandomGenerator>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QGraphicsOpacityEffect>
|
||||||
|
#include <QPainterPath>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QIcon>
|
||||||
|
#include <QDirIterator>
|
||||||
|
#include <QPushButton>
|
||||||
|
|
||||||
|
#include <bcdelightpmwidget.h>
|
||||||
|
|
||||||
|
|
||||||
|
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<QGraphicsOpacityEffect*>(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();
|
||||||
|
}
|
||||||
33
bcdelightpmwidget.h
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
#ifndef BCDELIGHTPMWIDGET_H
|
||||||
|
#define BCDELIGHTPMWIDGET_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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<QWidget*> _flyingWidgets;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // BCDELIGHTPMWIDGET_H
|
||||||
@@ -107,6 +107,8 @@ void BCMainWindow::initMainWindow()
|
|||||||
// wird es weitergereicht.
|
// wird es weitergereicht.
|
||||||
// Problem: alle Panels bekommen alle Datenmodelle angeboten.
|
// Problem: alle Panels bekommen alle Datenmodelle angeboten.
|
||||||
connect( &_dataManager, &BCXmlLoader::valueListReady, currentPanel, &BCDeviceView::onValueListReady );
|
connect( &_dataManager, &BCXmlLoader::valueListReady, currentPanel, &BCDeviceView::onValueListReady );
|
||||||
|
|
||||||
|
connect( currentPanel->model(), SIGNAL(makeSimonHappy()), this, SLOT(onStartAnimation() ) );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -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 )
|
void BCMainWindow::onDriverStateChanged( BCDriver::DriverState state, const QString& message )
|
||||||
{
|
{
|
||||||
Q_UNUSED(state)
|
Q_UNUSED(state)
|
||||||
|
|||||||
@@ -39,6 +39,7 @@
|
|||||||
#include <ui_bcmainwindow.h>
|
#include <ui_bcmainwindow.h>
|
||||||
#include <bcxmlloader.h>
|
#include <bcxmlloader.h>
|
||||||
#include <bctransmitter.h>
|
#include <bctransmitter.h>
|
||||||
|
#include <bcdelightpmwidget.h>
|
||||||
|
|
||||||
class BCDeviceView;
|
class BCDeviceView;
|
||||||
|
|
||||||
@@ -65,6 +66,7 @@ public slots:
|
|||||||
void onSyncDeviceView();
|
void onSyncDeviceView();
|
||||||
|
|
||||||
void onShowMessage( const QString& message, int timeOut=3000);
|
void onShowMessage( const QString& message, int timeOut=3000);
|
||||||
|
void onStartAnimation();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
@@ -88,7 +90,7 @@ protected:
|
|||||||
using BCDeviceViews = QHash<BCDevice::ID, BCDeviceView*>;
|
using BCDeviceViews = QHash<BCDevice::ID, BCDeviceView*>;
|
||||||
BCDeviceViews _devicePanels;
|
BCDeviceViews _devicePanels;
|
||||||
BCDeviceView* _currentPanel{};
|
BCDeviceView* _currentPanel{};
|
||||||
|
BCDelightPMWidget* _delightWidget{};
|
||||||
QThread _worker;
|
QThread _worker;
|
||||||
BCTransmitter _transmitter;
|
BCTransmitter _transmitter;
|
||||||
|
|
||||||
|
|||||||
@@ -7,9 +7,6 @@
|
|||||||
|
|
||||||
#include <bctoggleswitch.h>
|
#include <bctoggleswitch.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
BCToggleSwitch::BCToggleSwitch(QWidget *parent)
|
BCToggleSwitch::BCToggleSwitch(QWidget *parent)
|
||||||
: QAbstractButton(parent)
|
: QAbstractButton(parent)
|
||||||
, m_position(0.0f)
|
, m_position(0.0f)
|
||||||
|
|||||||
@@ -190,6 +190,12 @@ bool BCValueModel::setData(const QModelIndex& index, const QVariant& variant, in
|
|||||||
// Checken ob Int oder Double
|
// Checken ob Int oder Double
|
||||||
if (variant.canConvert<int>())
|
if (variant.canConvert<int>())
|
||||||
{
|
{
|
||||||
|
qDebug() << "--- new VALUE: " << variant.toInt();
|
||||||
|
if( variant.toInt() == 42)
|
||||||
|
{
|
||||||
|
qDebug() << "--- YES! " << variant.toInt();
|
||||||
|
emit makeSimonHappy();
|
||||||
|
}
|
||||||
value->rawValue = variant.toInt();
|
value->rawValue = variant.toInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -64,9 +64,12 @@ public:
|
|||||||
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
|
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
|
||||||
bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override;
|
bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override;
|
||||||
|
|
||||||
|
|
||||||
void updateValue(int row, BCValue::Flags newState, uint32_t rawValue );
|
void updateValue(int row, BCValue::Flags newState, uint32_t rawValue );
|
||||||
|
|
||||||
|
signals:
|
||||||
|
|
||||||
|
void makeSimonHappy();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
// Die eigentlichen Werte wohnen im tatsächlich hier, im Model.
|
// Die eigentlichen Werte wohnen im tatsächlich hier, im Model.
|
||||||
|
|||||||
@@ -12,5 +12,22 @@
|
|||||||
<file alias="sync_yellow.png">resources/sync_yellow.png</file>
|
<file alias="sync_yellow.png">resources/sync_yellow.png</file>
|
||||||
<file alias="sync.png">resources/sync.png</file>
|
<file alias="sync.png">resources/sync.png</file>
|
||||||
<file alias="bc_dark.qss">resources/bc_dark.qss</file>
|
<file alias="bc_dark.qss">resources/bc_dark.qss</file>
|
||||||
|
<file>resources/smile/face-angel.png</file>
|
||||||
|
<file>resources/smile/face-angry.png</file>
|
||||||
|
<file>resources/smile/face-cool.png</file>
|
||||||
|
<file>resources/smile/face-crying.png</file>
|
||||||
|
<file>resources/smile/face-embarrassed.png</file>
|
||||||
|
<file>resources/smile/face-glasses.png</file>
|
||||||
|
<file>resources/smile/face-kiss.png</file>
|
||||||
|
<file>resources/smile/face-laugh.png</file>
|
||||||
|
<file>resources/smile/face-monkey.png</file>
|
||||||
|
<file>resources/smile/face-plain.png</file>
|
||||||
|
<file>resources/smile/face-raspberry.png</file>
|
||||||
|
<file>resources/smile/face-sad.png</file>
|
||||||
|
<file>resources/smile/face-sick.png</file>
|
||||||
|
<file>resources/smile/face-smile.png</file>
|
||||||
|
<file>resources/smile/face-smile-big.png</file>
|
||||||
|
<file>resources/smile/face-smirk.png</file>
|
||||||
|
<file>resources/smile/face-surprise.png</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|||||||
BIN
resources/smile/face-angel.png
Normal file
|
After Width: | Height: | Size: 50 KiB |
BIN
resources/smile/face-angry.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
resources/smile/face-cool.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
resources/smile/face-crying.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
resources/smile/face-embarrassed.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
resources/smile/face-glasses.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
resources/smile/face-kiss.png
Normal file
|
After Width: | Height: | Size: 42 KiB |
BIN
resources/smile/face-laugh.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
resources/smile/face-monkey.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
resources/smile/face-plain.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
resources/smile/face-raspberry.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
resources/smile/face-sad.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
resources/smile/face-sick.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
resources/smile/face-smile-big.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
resources/smile/face-smile.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
resources/smile/face-smirk.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
resources/smile/face-surprise.png
Normal file
|
After Width: | Height: | Size: 14 KiB |