12#include "mouseclickconfig.h"
20#include <KConfigGroup>
21#include <KGlobalAccel>
24#include <QTabletEvent>
36 QAction *a =
new QAction(
this);
37 a->setObjectName(QStringLiteral(
"ToggleMouseClick"));
38 a->setText(i18n(
"Toggle Mouse Click Effect"));
39 KGlobalAccel::self()->setDefaultShortcut(a, QList<QKeySequence>() << (Qt::META | Qt::Key_Asterisk));
40 KGlobalAccel::self()->setShortcut(a, QList<QKeySequence>() << (Qt::META | Qt::Key_Asterisk));
41 connect(a, &QAction::triggered,
this, &MouseClickEffect::toggleEnabled);
45 m_buttons[0] = std::make_unique<MouseButton>(i18nc(
"Left mouse button",
"Left"), Qt::LeftButton);
46 m_buttons[1] = std::make_unique<MouseButton>(i18nc(
"Middle mouse button",
"Middle"), Qt::MiddleButton);
47 m_buttons[2] = std::make_unique<MouseButton>(i18nc(
"Right mouse button",
"Right"), Qt::RightButton);
59 MouseClickConfig::self()->read();
60 m_colors[0] = MouseClickConfig::color1();
61 m_colors[1] = MouseClickConfig::color2();
62 m_colors[2] = MouseClickConfig::color3();
63 m_lineWidth = MouseClickConfig::lineWidth();
64 m_ringLife = MouseClickConfig::ringLife();
65 m_ringMaxSize = MouseClickConfig::ringSize();
66 m_ringCount = MouseClickConfig::ringCount();
67 m_showText = MouseClickConfig::showText();
68 m_font = MouseClickConfig::font();
73 const int time = m_lastPresentTime.count() ? (presentTime - m_lastPresentTime).count() : 0;
75 for (
auto &click : m_clicks) {
76 click->m_time += time;
80 if (m_buttons[i]->m_isPressed) {
81 m_buttons[i]->m_time += time;
85 while (m_clicks.size() > 0) {
86 if (m_clicks.front()->m_time <= m_ringLife) {
93 m_lastPresentTime = presentTime;
95 m_lastPresentTime = std::chrono::milliseconds::zero();
108 for (
const auto &click : m_clicks) {
109 for (
int i = 0; i < m_ringCount; ++i) {
110 float alpha = computeAlpha(click.get(), i);
111 float size = computeRadius(click.get(), i);
112 if (size > 0 && alpha > 0) {
113 QColor color = m_colors[click->m_button];
114 color.setAlphaF(alpha);
115 drawCircle(viewport, color, click->m_pos.x(), click->m_pos.y(), size);
119 if (m_showText && click->m_frame) {
120 float frameAlpha = (click->m_time * 2.0f - m_ringLife) / m_ringLife;
121 frameAlpha = frameAlpha < 0 ? 1 : -(frameAlpha * frameAlpha) + 1;
122 click->m_frame->render(renderTarget, viewport,
infiniteRegion(), frameAlpha, frameAlpha);
125 for (
const auto &tool : std::as_const(m_tabletTools)) {
126 const int step = m_ringMaxSize * (1. - tool.m_pressure);
127 for (qreal size = m_ringMaxSize; size > 0; size -= step) {
128 drawCircle(viewport, tool.m_color, tool.m_globalPosition.x(), tool.m_globalPosition.y(), size);
132 paintScreenFinishGl();
142float MouseClickEffect::computeRadius(
const MouseEvent *click,
int ring)
144 float ringDistance = m_ringLife / (m_ringCount * 3);
146 return ((click->
m_time - ringDistance * ring) / m_ringLife) * m_ringMaxSize;
148 return ((m_ringLife - click->
m_time - ringDistance * ring) / m_ringLife) * m_ringMaxSize;
151float MouseClickEffect::computeAlpha(
const MouseEvent *click,
int ring)
153 float ringDistance = m_ringLife / (m_ringCount * 3);
154 return (m_ringLife - (
float)click->m_time - ringDistance * (ring)) / m_ringLife;
157void MouseClickEffect::slotMouseChanged(
const QPointF &pos,
const QPointF &,
158 Qt::MouseButtons buttons, Qt::MouseButtons oldButtons,
159 Qt::KeyboardModifiers, Qt::KeyboardModifiers)
161 if (buttons == oldButtons) {
165 std::unique_ptr<MouseEvent> m;
168 MouseButton *b = m_buttons[i].get();
169 if (isPressed(b->m_button, buttons, oldButtons)) {
170 m = std::make_unique<MouseEvent>(i, pos.toPoint(), 0, createEffectFrame(pos.toPoint(), b->m_labelDown),
true);
172 }
else if (isReleased(b->m_button, buttons, oldButtons) && (!b->m_isPressed || b->m_time > m_ringLife)) {
174 m = std::make_unique<MouseEvent>(i, pos.toPoint(), 0, createEffectFrame(pos.toPoint(), b->m_labelUp),
false);
177 b->setPressed(b->m_button & buttons);
181 m_clicks.push_back(std::move(m));
186std::unique_ptr<EffectFrame> MouseClickEffect::createEffectFrame(
const QPoint &pos,
const QString &text)
191 QPoint point(pos.x() + m_ringMaxSize, pos.y());
192 std::unique_ptr<EffectFrame> frame = std::make_unique<EffectFrame>(
EffectFrameStyled,
false, point, Qt::AlignLeft);
193 frame->setFont(m_font);
194 frame->setText(text);
198void MouseClickEffect::repaint()
200 if (m_clicks.size() > 0) {
202 const int radius = m_ringMaxSize + m_lineWidth;
203 for (
auto &click : m_clicks) {
204 dirtyRegion += QRect(click->m_pos.x() - radius, click->m_pos.y() - radius, 2 * radius, 2 * radius);
205 if (click->m_frame) {
206 dirtyRegion += click->m_frame->geometry();
211 if (!m_tabletTools.isEmpty()) {
213 const int radius = m_ringMaxSize + m_lineWidth;
214 for (
const auto &event : std::as_const(m_tabletTools)) {
215 dirtyRegion += QRect(event.m_globalPosition.x() - radius, event.m_globalPosition.y() - radius, 2 * radius, 2 * radius);
221bool MouseClickEffect::isReleased(Qt::MouseButtons button, Qt::MouseButtons buttons, Qt::MouseButtons oldButtons)
223 return !(button & buttons) && (button & oldButtons);
226bool MouseClickEffect::isPressed(Qt::MouseButtons button, Qt::MouseButtons buttons, Qt::MouseButtons oldButtons)
228 return (button & buttons) && !(button & oldButtons);
231void MouseClickEffect::toggleEnabled()
233 m_enabled = !m_enabled;
244 m_tabletTools.clear();
247 m_buttons[i]->m_time = 0;
248 m_buttons[i]->m_isPressed =
false;
254 return m_enabled && (m_clicks.size() != 0 || !m_tabletTools.isEmpty());
257void MouseClickEffect::drawCircle(
const RenderViewport &viewport,
const QColor &color,
float cx,
float cy,
float r)
260 drawCircleGl(viewport, color, cx, cy, r);
262 drawCircleQPainter(color, cx, cy, r);
266void MouseClickEffect::drawCircleGl(
const RenderViewport &viewport,
const QColor &color,
float cx,
float cy,
float r)
268 static const int num_segments = 80;
269 static const float theta = 2 * 3.1415926 / float(num_segments);
270 static const float c = cosf(theta);
271 static const float s = sinf(theta);
272 const float scale = viewport.scale();
280 QList<QVector2D> verts;
281 verts.reserve(num_segments * 2);
283 for (
int ii = 0; ii < num_segments; ++ii) {
284 verts.push_back(QVector2D((x + cx) * scale, (y + cy) * scale));
290 vbo->setVertices(verts);
292 vbo->render(GL_LINE_LOOP);
295void MouseClickEffect::drawCircleQPainter(
const QColor &color,
float cx,
float cy,
float r)
299 painter->setPen(color);
300 painter->drawArc(cx - r, cy - r, r * 2, r * 2, 0, 5760);
304void MouseClickEffect::paintScreenSetupGl(
const RenderTarget &renderTarget,
const QMatrix4x4 &projectionMatrix)
308 shader->setColorspaceUniformsFromSRGB(renderTarget.colorDescription());
310 glLineWidth(m_lineWidth);
312 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
315void MouseClickEffect::paintScreenFinishGl()
324 auto &tabletEvent = m_tabletTools[
event->uniqueId()];
325 if (!tabletEvent.m_color.isValid()) {
326 switch (event->pointerType()) {
327 case QPointingDevice::PointerType::Unknown:
328 case QPointingDevice::PointerType::Generic:
329 case QPointingDevice::PointerType::Finger:
330 case QPointingDevice::PointerType::Pen:
331 tabletEvent.m_color = MouseClickConfig::color1();
333 case QPointingDevice::PointerType::Eraser:
334 tabletEvent.m_color = MouseClickConfig::color2();
336 case QPointingDevice::PointerType::Cursor:
337 tabletEvent.m_color = MouseClickConfig::color3();
339 case QPointingDevice::PointerType::AllPointerTypes:
344 switch (event->type()) {
345 case QEvent::TabletPress:
346 tabletEvent.m_pressed =
true;
348 case QEvent::TabletRelease:
349 tabletEvent.m_pressed =
false;
351 case QEvent::TabletLeaveProximity:
352 m_tabletTools.remove(event->uniqueId());
357 tabletEvent.m_globalPosition =
event->globalPos();
358 tabletEvent.m_pressure =
event->pressure();
390 return m_ringMaxSize;
415#include "moc_mouseclick.cpp"
void paintScreen(const RenderTarget &renderTarget, const RenderViewport &viewport, int mask, const QRegion ®ion, Output *screen)
Q_SCRIPTABLE void addRepaint(const QRectF &r)
CompositingType compositingType
void prePaintScreen(ScreenPrePaintData &data, std::chrono::milliseconds presentTime)
bool isOpenGLCompositing() const
Whether the Compositor is OpenGL based (either GL 1 or 2).
void mouseChanged(const QPointF &pos, const QPointF &oldpos, Qt::MouseButtons buttons, Qt::MouseButtons oldbuttons, Qt::KeyboardModifiers modifiers, Qt::KeyboardModifiers oldmodifiers)
KSharedConfigPtr config() const
QPainter * scenePainter()
Provides access to the QPainter which is rendering to the back buffer.
@ ModelViewProjectionMatrix
bool setUniform(const char *name, float value)
static GLVertexBuffer * streamingBuffer()
~MouseClickEffect() override
void prePaintScreen(ScreenPrePaintData &data, std::chrono::milliseconds presentTime) override
void paintScreen(const RenderTarget &renderTarget, const RenderViewport &viewport, int mask, const QRegion ®ion, Output *screen) override
void postPaintScreen() override
void reconfigure(ReconfigureFlags) override
bool tabletToolEvent(QTabletEvent *event) override
bool isActive() const override
QMatrix4x4 projectionMatrix() const
GLShader * getBoundShader() const
static ShaderManager * instance()
GLShader * pushShader(ShaderTraits traits)
KWIN_EXPORT QRect infiniteRegion()
@ EffectFrameStyled
Displays a Plasma-styled frame around the contents.