Skip to content

Commit

Permalink
Merge pull request #12990 from m0dB/anim-longpresslatching
Browse files Browse the repository at this point in the history
animate long press latching

taking the liberty to merge this myself, as it was approved to merge by @daschuer
  • Loading branch information
m0dB authored Apr 20, 2024
2 parents 82d601c + 5606c3a commit d20b804
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 5 deletions.
79 changes: 74 additions & 5 deletions src/widget/wpushbutton.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,9 +155,13 @@ void WPushButton::setup(const QDomNode& node, const SkinContext& context) {
switch (m_leftButtonMode) {
case ControlPushButton::PUSH:
case ControlPushButton::POWERWINDOW:
leftConnection->setEmitOption(
ControlParameterWidgetConnection::EMIT_ON_PRESS_AND_RELEASE);
break;
case ControlPushButton::LONGPRESSLATCHING:
leftConnection->setEmitOption(
ControlParameterWidgetConnection::EMIT_ON_PRESS_AND_RELEASE);
m_pLongPressLatching = std::make_unique<LongPressLatching>(this);
break;
case ControlPushButton::TOGGLE:
case ControlPushButton::TRIGGER:
Expand Down Expand Up @@ -302,17 +306,21 @@ void WPushButton::onConnectedControlChanged(double dParameter, double dValue) {

void WPushButton::paintEvent(QPaintEvent* e) {
Q_UNUSED(e);
paintOnDevice(nullptr);
}

void WPushButton::paintOnDevice(QPaintDevice* pd) {
QStyleOption option;
option.initFrom(this);
QStylePainter p(this);
p.drawPrimitive(QStyle::PE_Widget, option);
std::unique_ptr<QStylePainter> p(pd ? new QStylePainter(pd, this) : new QStylePainter(this));
p->drawPrimitive(QStyle::PE_Widget, option);

if (m_iNoStates == 0) {
return;
}

if (m_pPixmapBack) {
m_pPixmapBack->draw(rect(), &p);
m_pPixmapBack->draw(rect(), p.get());
}

const QVector<PaintablePointer>& pixmaps = m_bPressed ?
Expand All @@ -335,7 +343,7 @@ void WPushButton::paintEvent(QPaintEvent* e) {

PaintablePointer pPixmap = pixmaps.at(idx);
if (!pPixmap.isNull() && !pPixmap->isNull()) {
pPixmap->draw(rect(), &p);
pPixmap->draw(rect(), p.get());
}

QString text = m_text.at(idx);
Expand All @@ -348,7 +356,11 @@ void WPushButton::paintEvent(QPaintEvent* e) {
// int textWidth = width() - lPad - rPad;
// QRect textRect = rect().adjust(x1, y1, x2, y2);
QString elidedText = metrics.elidedText(text, m_elideMode, width());
p.drawText(rect(), m_align.at(idx), elidedText);
p->drawText(rect(), m_align.at(idx), elidedText);
}

if (pd == nullptr && m_pLongPressLatching) {
m_pLongPressLatching->paint(p.get(), m_clickTimer.remainingTime());
}
}

Expand Down Expand Up @@ -395,12 +407,16 @@ void WPushButton::mousePressEvent(QMouseEvent * e) {
} else {
// Toggle through the states
emitValue = getControlParameterLeft();
const auto oldValue = emitValue;
if (!util_isnan(emitValue) && m_iNoStates > 0) {
emitValue = static_cast<int>(emitValue + 1.0) % m_iNoStates;
}
if (m_leftButtonMode == ControlPushButton::LONGPRESSLATCHING) {
m_clickTimer.setSingleShot(true);
m_clickTimer.start(ControlPushButtonBehavior::kLongPressLatchingTimeMillis);
if (oldValue == 0.0 && m_pLongPressLatching) {
m_pLongPressLatching->start();
}
}
}
setControlParameterLeftDown(emitValue);
Expand Down Expand Up @@ -455,6 +471,10 @@ void WPushButton::mouseReleaseEvent(QMouseEvent * e) {
const bool leftClick = e->button() == Qt::LeftButton;
const bool rightClick = e->button() == Qt::RightButton;

if (m_pLongPressLatching) {
m_pLongPressLatching->stop();
}

if (m_leftButtonMode == ControlPushButton::POWERWINDOW
&& m_iNoStates == 2) {
if (leftClick) {
Expand Down Expand Up @@ -520,3 +540,52 @@ void WPushButton::fillDebugTooltip(QStringList* debug) {
<< QString("RightButtonMode: %1")
.arg(ControlPushButton::buttonModeToString(m_rightButtonMode));
}

void WPushButton::updateSlot() {
update();
}

WPushButton::LongPressLatching::LongPressLatching(WPushButton* pButton)
: m_pButton(pButton) {
// To animate the long press latching
connect(&m_animTimer, &QTimer::timeout, m_pButton, &WPushButton::updateSlot);
}

void WPushButton::LongPressLatching::paint(QPainter* p, int remainingTime) {
if (m_animTimer.isActive()) {
// Animate the long press latching by capturing the off state in a pixmap
// and gradually draw less of it over the duration of the long press latching.

remainingTime = std::max(0, remainingTime);

if (remainingTime == 0) {
m_animTimer.stop();
} else {
qreal x = m_pButton->width() * static_cast<qreal>(remainingTime) /
static_cast<qreal>(ControlPushButtonBehavior::
kLongPressLatchingTimeMillis);
p->drawPixmap(QPointF(m_pButton->width() - x, 0),
m_preLongPressPixmap,
QRectF((m_pButton->width() - x) * m_pButton->devicePixelRatio(),
0,
x * m_pButton->devicePixelRatio(),
m_pButton->height() * m_pButton->devicePixelRatio()));
}
}
}

void WPushButton::LongPressLatching::start() {
// Capture pixmap with the off state ...
m_preLongPressPixmap = QPixmap(static_cast<int>(m_pButton->width() *
m_pButton->devicePixelRatio()),
static_cast<int>(
m_pButton->height() * m_pButton->devicePixelRatio()));
m_preLongPressPixmap.setDevicePixelRatio(m_pButton->devicePixelRatio());
m_pButton->paintOnDevice(&m_preLongPressPixmap);
// ... and start the long press latching animation
m_animTimer.start(1000 / 60);
}

void WPushButton::LongPressLatching::stop() {
m_animTimer.stop();
}
27 changes: 27 additions & 0 deletions src/widget/wpushbutton.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <QString>
#include <QTimer>
#include <QVector>
#include <memory>

#include "control/controlpushbutton.h"
#include "util/fpclassify.h"
Expand Down Expand Up @@ -61,6 +62,9 @@ class WPushButton : public WWidget {
public slots:
void onConnectedControlChanged(double dParameter, double dValue) override;

private slots:
void updateSlot();

protected:
bool event(QEvent* e) override;
void paintEvent(QPaintEvent* e) override;
Expand All @@ -86,6 +90,8 @@ class WPushButton : public WWidget {
Paintable::DrawMode mode,
double scaleFactor);

void paintOnDevice(QPaintDevice* pd);

// True, if the button is currently pressed
bool m_bPressed;
// True, if the button is pointer is above button
Expand All @@ -106,4 +112,25 @@ class WPushButton : public WWidget {
ControlPushButton::ButtonMode m_rightButtonMode;
QTimer m_clickTimer;
QVector<int> m_align;

// Animates long press latching by storing the off state of the
// WPushButton in a pixmap and gradually (from left to right)
// drawing less of the off state on top of the on state, to
// give a visual indication that the long press latching is in
// progress.
class LongPressLatching {
public:
LongPressLatching(WPushButton* pButton);
void paint(QPainter* p, int remainingTime);
void start();
void stop();

private:
WPushButton* m_pButton;
QPixmap m_preLongPressPixmap;
QTimer m_animTimer;
};

// Only assigned for WPushButtons that use long press latching
std::unique_ptr<LongPressLatching> m_pLongPressLatching;
};

0 comments on commit d20b804

Please sign in to comment.