breezehelper.cpp 56.8 KB
Newer Older
1
2
3
4
5
/*
 * SPDX-FileCopyrightText: 2014 Hugo Pereira Da Costa <hugo.pereira@free.fr>
 *
 * SPDX-License-Identifier: GPL-2.0-or-later
 */
6
7
8

#include "breezehelper.h"

9
#include "breeze.h"
10
#include "breezestyleconfigdata.h"
11

David Redondo's avatar
David Redondo committed
12
#include <KColorScheme>
13
#include <KColorUtils>
14
#include <KIconLoader>
15
16
#include <KWindowSystem>

17
#include <QApplication>
Jan Blackquill's avatar
Jan Blackquill committed
18
#include <QDBusConnection>
Alexander Lohnau's avatar
Alexander Lohnau committed
19
#include <QDockWidget>
Jan Blackquill's avatar
Jan Blackquill committed
20
21
22
#include <QFileInfo>
#include <QMainWindow>
#include <QMdiArea>
Alexander Lohnau's avatar
Alexander Lohnau committed
23
24
#include <QMenuBar>
#include <QPainter>
Jan Blackquill's avatar
Jan Blackquill committed
25
#include <QWindow>
26

27
#if BREEZE_HAVE_QTX11EXTRAS
28
29
30
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
#include <private/qtx11extras_p.h>
#else
31
32
#include <QX11Info>
#endif
33
#endif
34

Jan Blackquill's avatar
Jan Blackquill committed
35
#include <QDialog>
Alexander Lohnau's avatar
Alexander Lohnau committed
36
#include <algorithm>
37

38
39
namespace Breeze
{
Alexander Lohnau's avatar
Alexander Lohnau committed
40
41
//* contrast for arrow and treeline rendering
static const qreal arrowShade = 0.15;
42

Alexander Lohnau's avatar
Alexander Lohnau committed
43
static const qreal highlightBackgroundAlpha = 0.33;
44

Alexander Lohnau's avatar
Alexander Lohnau committed
45
static const auto radioCheckSunkenDarkeningFactor = 110;
Jan Blackquill's avatar
Jan Blackquill committed
46

Alexander Lohnau's avatar
Alexander Lohnau committed
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
//____________________________________________________________________
Helper::Helper(KSharedConfig::Ptr config, QObject *parent)
    : QObject(parent)
    , _config(std::move(config))
    , _kwinConfig(KSharedConfig::openConfig("kwinrc"))
    , _decorationConfig(new InternalSettings())
{
    if (qApp) {
        connect(qApp, &QApplication::paletteChanged, this, [=]() {
            if (qApp->property("KDE_COLOR_SCHEME_PATH").isValid()) {
                const auto path = qApp->property("KDE_COLOR_SCHEME_PATH").toString();
                KConfig config(path, KConfig::SimpleConfig);
                KConfigGroup group(config.group("WM"));
                const QPalette palette(QApplication::palette());
                _activeTitleBarColor = group.readEntry("activeBackground", palette.color(QPalette::Active, QPalette::Highlight));
                _activeTitleBarTextColor = group.readEntry("activeForeground", palette.color(QPalette::Active, QPalette::HighlightedText));
                _inactiveTitleBarColor = group.readEntry("inactiveBackground", palette.color(QPalette::Disabled, QPalette::Highlight));
                _inactiveTitleBarTextColor = group.readEntry("inactiveForeground", palette.color(QPalette::Disabled, QPalette::HighlightedText));
            }
        });
67
    }
Alexander Lohnau's avatar
Alexander Lohnau committed
68
}
69

Alexander Lohnau's avatar
Alexander Lohnau committed
70
71
72
73
74
//____________________________________________________________________
KSharedConfig::Ptr Helper::config() const
{
    return _config;
}
75

Alexander Lohnau's avatar
Alexander Lohnau committed
76
77
78
79
80
//____________________________________________________________________
QSharedPointer<InternalSettings> Helper::decorationConfig() const
{
    return _decorationConfig;
}
81

Alexander Lohnau's avatar
Alexander Lohnau committed
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
//____________________________________________________________________
void Helper::loadConfig()
{
    _viewFocusBrush = KStatefulBrush(KColorScheme::View, KColorScheme::FocusColor);
    _viewHoverBrush = KStatefulBrush(KColorScheme::View, KColorScheme::HoverColor);
    _buttonFocusBrush = KStatefulBrush(KColorScheme::Button, KColorScheme::FocusColor);
    _buttonHoverBrush = KStatefulBrush(KColorScheme::Button, KColorScheme::HoverColor);
    _viewNegativeTextBrush = KStatefulBrush(KColorScheme::View, KColorScheme::NegativeText);
    _viewNeutralTextBrush = KStatefulBrush(KColorScheme::View, KColorScheme::NeutralText);

    const QPalette palette(QApplication::palette());
    _config->reparseConfiguration();
    _kwinConfig->reparseConfiguration();
    _cachedAutoValid = false;
    _decorationConfig->load();

    KConfig config(qApp->property("KDE_COLOR_SCHEME_PATH").toString(), KConfig::SimpleConfig);
    KConfigGroup appGroup(config.group("WM"));
    KConfigGroup globalGroup(_config->group("WM"));
    _activeTitleBarColor =
        appGroup.readEntry("activeBackground", globalGroup.readEntry("activeBackground", palette.color(QPalette::Active, QPalette::Highlight)));
    _activeTitleBarTextColor =
        appGroup.readEntry("activeForeground", globalGroup.readEntry("activeForeground", palette.color(QPalette::Active, QPalette::HighlightedText)));
    _inactiveTitleBarColor =
        appGroup.readEntry("inactiveBackground", globalGroup.readEntry("inactiveBackground", palette.color(QPalette::Disabled, QPalette::Highlight)));
    _inactiveTitleBarTextColor =
        appGroup.readEntry("inactiveForeground", globalGroup.readEntry("inactiveForeground", palette.color(QPalette::Disabled, QPalette::HighlightedText)));
}
110

Alexander Lohnau's avatar
Alexander Lohnau committed
111
112
113
114
115
116
QColor transparentize(const QColor &color, qreal amount)
{
    auto clone = color;
    clone.setAlphaF(amount);
    return clone;
}
117

Alexander Lohnau's avatar
Alexander Lohnau committed
118
119
120
121
//____________________________________________________________________
QColor Helper::frameOutlineColor(const QPalette &palette, bool mouseOver, bool hasFocus, qreal opacity, AnimationMode mode) const
{
    QColor outline(KColorUtils::mix(palette.color(QPalette::Window), palette.color(QPalette::WindowText), 0.25));
122

Alexander Lohnau's avatar
Alexander Lohnau committed
123
124
125
126
    // focus takes precedence over hover
    if (mode == AnimationFocus) {
        const QColor focus(focusColor(palette));
        const QColor hover(hoverColor(palette));
127

Alexander Lohnau's avatar
Alexander Lohnau committed
128
129
130
131
        if (mouseOver)
            outline = KColorUtils::mix(hover, focus, opacity);
        else
            outline = KColorUtils::mix(outline, focus, opacity);
132

Alexander Lohnau's avatar
Alexander Lohnau committed
133
134
    } else if (hasFocus) {
        outline = focusColor(palette);
135

Alexander Lohnau's avatar
Alexander Lohnau committed
136
137
138
    } else if (mode == AnimationHover) {
        const QColor hover(hoverColor(palette));
        outline = KColorUtils::mix(outline, hover, opacity);
139

Alexander Lohnau's avatar
Alexander Lohnau committed
140
141
    } else if (mouseOver) {
        outline = hoverColor(palette);
142
143
    }

Alexander Lohnau's avatar
Alexander Lohnau committed
144
145
    return outline;
}
146

Alexander Lohnau's avatar
Alexander Lohnau committed
147
148
149
150
151
//____________________________________________________________________
QColor Helper::focusOutlineColor(const QPalette &palette) const
{
    return KColorUtils::mix(focusColor(palette), palette.color(QPalette::WindowText), 0.15);
}
152

Alexander Lohnau's avatar
Alexander Lohnau committed
153
154
155
156
157
//____________________________________________________________________
QColor Helper::hoverOutlineColor(const QPalette &palette) const
{
    return KColorUtils::mix(hoverColor(palette), palette.color(QPalette::WindowText), 0.15);
}
158

Alexander Lohnau's avatar
Alexander Lohnau committed
159
160
161
162
163
//____________________________________________________________________
QColor Helper::buttonFocusOutlineColor(const QPalette &palette) const
{
    return KColorUtils::mix(buttonFocusColor(palette), palette.color(QPalette::ButtonText), 0.15);
}
164

Alexander Lohnau's avatar
Alexander Lohnau committed
165
166
167
168
169
//____________________________________________________________________
QColor Helper::buttonHoverOutlineColor(const QPalette &palette) const
{
    return KColorUtils::mix(buttonHoverColor(palette), palette.color(QPalette::ButtonText), 0.15);
}
170

Alexander Lohnau's avatar
Alexander Lohnau committed
171
172
173
174
175
//____________________________________________________________________
QColor Helper::sidePanelOutlineColor(const QPalette &palette, bool hasFocus, qreal opacity, AnimationMode mode) const
{
    QColor outline(palette.color(QPalette::Inactive, QPalette::Highlight));
    const QColor &focus = palette.color(QPalette::Active, QPalette::Highlight);
176

Alexander Lohnau's avatar
Alexander Lohnau committed
177
178
    if (mode == AnimationFocus) {
        outline = KColorUtils::mix(outline, focus, opacity);
179

Alexander Lohnau's avatar
Alexander Lohnau committed
180
181
    } else if (hasFocus) {
        outline = focus;
182
183
    }

Alexander Lohnau's avatar
Alexander Lohnau committed
184
185
    return outline;
}
186

Alexander Lohnau's avatar
Alexander Lohnau committed
187
188
189
190
191
//____________________________________________________________________
QColor Helper::frameBackgroundColor(const QPalette &palette, QPalette::ColorGroup group) const
{
    return KColorUtils::mix(palette.color(group, QPalette::Window), palette.color(group, QPalette::Base), 0.3);
}
192

Alexander Lohnau's avatar
Alexander Lohnau committed
193
194
195
196
197
198
199
200
201
202
203
204
//____________________________________________________________________
QColor Helper::arrowColor(const QPalette &palette, QPalette::ColorGroup group, QPalette::ColorRole role) const
{
    switch (role) {
    case QPalette::Text:
        return KColorUtils::mix(palette.color(group, QPalette::Text), palette.color(group, QPalette::Base), arrowShade);
    case QPalette::WindowText:
        return KColorUtils::mix(palette.color(group, QPalette::WindowText), palette.color(group, QPalette::Window), arrowShade);
    case QPalette::ButtonText:
        return KColorUtils::mix(palette.color(group, QPalette::ButtonText), palette.color(group, QPalette::Button), arrowShade);
    default:
        return palette.color(group, role);
205
    }
Alexander Lohnau's avatar
Alexander Lohnau committed
206
}
207

Alexander Lohnau's avatar
Alexander Lohnau committed
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
//____________________________________________________________________
QColor Helper::arrowColor(const QPalette &palette, bool mouseOver, bool hasFocus, qreal opacity, AnimationMode mode) const
{
    QColor outline(arrowColor(palette, QPalette::WindowText));
    if (mode == AnimationHover) {
        const QColor focus(focusColor(palette));
        const QColor hover(hoverColor(palette));
        if (hasFocus)
            outline = KColorUtils::mix(focus, hover, opacity);
        else
            outline = KColorUtils::mix(outline, hover, opacity);

    } else if (mouseOver) {
        outline = hoverColor(palette);

    } else if (mode == AnimationFocus) {
        const QColor focus(focusColor(palette));
        outline = KColorUtils::mix(outline, focus, opacity);

    } else if (hasFocus) {
        outline = focusColor(palette);
229
230
    }

Alexander Lohnau's avatar
Alexander Lohnau committed
231
232
    return outline;
}
233

Alexander Lohnau's avatar
Alexander Lohnau committed
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
//____________________________________________________________________
QColor Helper::sliderOutlineColor(const QPalette &palette, bool mouseOver, bool hasFocus, qreal opacity, AnimationMode mode) const
{
    QColor outline(KColorUtils::mix(palette.color(QPalette::Window), palette.color(QPalette::WindowText), 0.4));

    // hover takes precedence over focus
    if (mode == AnimationHover) {
        const QColor hover(hoverColor(palette));
        const QColor focus(focusColor(palette));
        if (hasFocus)
            outline = KColorUtils::mix(focus, hover, opacity);
        else
            outline = KColorUtils::mix(outline, hover, opacity);

    } else if (mouseOver) {
        outline = hoverColor(palette);

    } else if (mode == AnimationFocus) {
        const QColor focus(focusColor(palette));
        outline = KColorUtils::mix(outline, focus, opacity);

    } else if (hasFocus) {
        outline = focusColor(palette);
    }
258

Alexander Lohnau's avatar
Alexander Lohnau committed
259
260
    return outline;
}
261

Alexander Lohnau's avatar
Alexander Lohnau committed
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
//____________________________________________________________________
QColor Helper::scrollBarHandleColor(const QPalette &palette, bool mouseOver, bool hasFocus, qreal opacity, AnimationMode mode) const
{
    QColor color(alphaColor(palette.color(QPalette::WindowText), 0.5));

    // hover takes precedence over focus
    if (mode == AnimationHover) {
        const QColor hover(hoverColor(palette));
        const QColor focus(focusColor(palette));
        if (hasFocus)
            color = KColorUtils::mix(focus, hover, opacity);
        else
            color = KColorUtils::mix(color, hover, opacity);

    } else if (mouseOver) {
        color = hoverColor(palette);

    } else if (mode == AnimationFocus) {
        const QColor focus(focusColor(palette));
        color = KColorUtils::mix(color, focus, opacity);

    } else if (hasFocus) {
        color = focusColor(palette);
    }
286

Alexander Lohnau's avatar
Alexander Lohnau committed
287
288
    return color;
}
289

Alexander Lohnau's avatar
Alexander Lohnau committed
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
//______________________________________________________________________________
QColor Helper::checkBoxIndicatorColor(const QPalette &palette, bool mouseOver, bool active, qreal opacity, AnimationMode mode) const
{
    QColor color(KColorUtils::mix(palette.color(QPalette::Window), palette.color(QPalette::WindowText), 0.6));
    if (mode == AnimationHover) {
        const QColor focus(focusColor(palette));
        const QColor hover(hoverColor(palette));
        if (active)
            color = KColorUtils::mix(focus, hover, opacity);
        else
            color = KColorUtils::mix(color, hover, opacity);

    } else if (mouseOver) {
        color = hoverColor(palette);

    } else if (active) {
        color = focusColor(palette);
    }
308

Alexander Lohnau's avatar
Alexander Lohnau committed
309
310
    return color;
}
311

Alexander Lohnau's avatar
Alexander Lohnau committed
312
313
314
315
316
//______________________________________________________________________________
QColor Helper::separatorColor(const QPalette &palette) const
{
    return KColorUtils::mix(palette.color(QPalette::Window), palette.color(QPalette::WindowText), 0.25);
}
317

Alexander Lohnau's avatar
Alexander Lohnau committed
318
319
320
321
//______________________________________________________________________________
QPalette Helper::disabledPalette(const QPalette &source, qreal ratio) const
{
    QPalette copy(source);
322

Alexander Lohnau's avatar
Alexander Lohnau committed
323
324
325
326
327
    const QList<QPalette::ColorRole> roles =
        {QPalette::Window, QPalette::Highlight, QPalette::WindowText, QPalette::ButtonText, QPalette::Text, QPalette::Button};
    foreach (const QPalette::ColorRole &role, roles) {
        copy.setColor(role, KColorUtils::mix(source.color(QPalette::Active, role), source.color(QPalette::Disabled, role), 1.0 - ratio));
    }
328

Alexander Lohnau's avatar
Alexander Lohnau committed
329
330
    return copy;
}
331

Alexander Lohnau's avatar
Alexander Lohnau committed
332
333
334
335
336
//____________________________________________________________________
QColor Helper::alphaColor(QColor color, qreal alpha) const
{
    if (alpha >= 0 && alpha < 1.0) {
        color.setAlphaF(alpha * color.alphaF());
337
    }
Alexander Lohnau's avatar
Alexander Lohnau committed
338
339
    return color;
}
340

Alexander Lohnau's avatar
Alexander Lohnau committed
341
342
343
344
345
346
347
348
349
350
//______________________________________________________________________________
void Helper::renderDebugFrame(QPainter *painter, const QRect &rect) const
{
    painter->save();
    painter->setRenderHints(QPainter::Antialiasing);
    painter->setBrush(Qt::NoBrush);
    painter->setPen(Qt::red);
    painter->drawRect(strokedRect(rect));
    painter->restore();
}
351

Alexander Lohnau's avatar
Alexander Lohnau committed
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
//______________________________________________________________________________
void Helper::renderFocusRect(QPainter *painter, const QRect &rect, const QColor &color, const QColor &outline, Sides sides) const
{
    if (!color.isValid())
        return;

    painter->save();
    painter->setRenderHints(QPainter::Antialiasing);
    painter->setBrush(color);

    if (!(outline.isValid() && sides)) {
        painter->setPen(Qt::NoPen);
        painter->drawRect(rect);

    } else {
        painter->setClipRect(rect);

        QRectF copy(strokedRect(rect));

        const qreal radius(frameRadius(PenWidth::Frame));
        if (!(sides & SideTop))
            copy.adjust(0, -radius, 0, 0);
        if (!(sides & SideBottom))
            copy.adjust(0, 0, 0, radius);
        if (!(sides & SideLeft))
            copy.adjust(-radius, 0, 0, 0);
        if (!(sides & SideRight))
            copy.adjust(0, 0, radius, 0);

        painter->setPen(outline);
        // painter->setBrush( Qt::NoBrush );
        painter->drawRoundedRect(copy, radius, radius);
    }
385

Alexander Lohnau's avatar
Alexander Lohnau committed
386
387
    painter->restore();
}
388

Alexander Lohnau's avatar
Alexander Lohnau committed
389
390
391
392
393
//______________________________________________________________________________
void Helper::renderFocusLine(QPainter *painter, const QRect &rect, const QColor &color) const
{
    if (!color.isValid())
        return;
394

Alexander Lohnau's avatar
Alexander Lohnau committed
395
396
397
398
    painter->save();
    painter->setRenderHint(QPainter::Antialiasing, false);
    painter->setBrush(Qt::NoBrush);
    painter->setPen(color);
399

Alexander Lohnau's avatar
Alexander Lohnau committed
400
401
402
403
    painter->translate(0, 2);
    painter->drawLine(rect.bottomLeft(), rect.bottomRight());
    painter->restore();
}
404

Alexander Lohnau's avatar
Alexander Lohnau committed
405
406
407
408
//______________________________________________________________________________
void Helper::renderFrameWithSides(QPainter *painter, const QRect &rect, const QColor &color, Qt::Edges edges, const QColor &outline) const
{
    painter->save();
409

Alexander Lohnau's avatar
Alexander Lohnau committed
410
    painter->setRenderHint(QPainter::Antialiasing);
411

Alexander Lohnau's avatar
Alexander Lohnau committed
412
    QRectF frameRect(rect);
413

Alexander Lohnau's avatar
Alexander Lohnau committed
414
415
416
    // set brush
    painter->setBrush(color);
    painter->setPen(Qt::NoPen);
417

Alexander Lohnau's avatar
Alexander Lohnau committed
418
419
    // render
    painter->drawRect(frameRect);
420

Alexander Lohnau's avatar
Alexander Lohnau committed
421
422
423
    // set brush again
    painter->setBrush(Qt::NoBrush);
    painter->setPen(outline);
424

Alexander Lohnau's avatar
Alexander Lohnau committed
425
426
427
    // manually apply the effects of StrokedRect here but only to the edges with a frame
    if (edges & Qt::LeftEdge) {
        frameRect.adjust(0.5, 0.0, 0.0, 0.0);
428
    }
Alexander Lohnau's avatar
Alexander Lohnau committed
429
430
    if (edges & Qt::RightEdge) {
        frameRect.adjust(0.0, 0, -0.5, 0.0);
431
    }
Alexander Lohnau's avatar
Alexander Lohnau committed
432
433
    if (edges & Qt::TopEdge) {
        frameRect.adjust(0.0, 0.5, 0.0, 0.0);
434
    }
Alexander Lohnau's avatar
Alexander Lohnau committed
435
436
    if (edges & Qt::BottomEdge) {
        frameRect.adjust(0.0, 0.0, 0.0, -0.5);
437
438
    }

Alexander Lohnau's avatar
Alexander Lohnau committed
439
440
441
    // draw lines
    if (edges & Qt::LeftEdge) {
        painter->drawLine(QLineF(frameRect.topLeft(), frameRect.bottomLeft()));
442
    }
Alexander Lohnau's avatar
Alexander Lohnau committed
443
444
    if (edges & Qt::RightEdge) {
        painter->drawLine(QLineF(frameRect.topRight(), frameRect.bottomRight()));
445
    }
Alexander Lohnau's avatar
Alexander Lohnau committed
446
447
448
449
450
    if (edges & Qt::TopEdge) {
        painter->drawLine(QLineF(frameRect.topLeft(), frameRect.topRight()));
    }
    if (edges & Qt::BottomEdge) {
        painter->drawLine(QLineF(frameRect.bottomLeft(), frameRect.bottomRight()));
451
452
    }

Alexander Lohnau's avatar
Alexander Lohnau committed
453
454
    painter->restore();
}
Hugo Pereira Da Costa's avatar
cleanup    
Hugo Pereira Da Costa committed
455

Alexander Lohnau's avatar
Alexander Lohnau committed
456
457
458
459
//______________________________________________________________________________
void Helper::renderFrame(QPainter *painter, const QRect &rect, const QColor &color, const QColor &outline) const
{
    painter->setRenderHint(QPainter::Antialiasing);
460

Alexander Lohnau's avatar
Alexander Lohnau committed
461
462
    QRectF frameRect(rect.adjusted(1, 1, -1, -1));
    qreal radius(frameRadius(PenWidth::NoPen));
463

Alexander Lohnau's avatar
Alexander Lohnau committed
464
465
466
467
468
    // set pen
    if (outline.isValid()) {
        painter->setPen(outline);
        frameRect = strokedRect(frameRect);
        radius = frameRadiusForNewPenWidth(radius, PenWidth::Frame);
469

Alexander Lohnau's avatar
Alexander Lohnau committed
470
471
472
    } else {
        painter->setPen(Qt::NoPen);
    }
473

Alexander Lohnau's avatar
Alexander Lohnau committed
474
475
476
477
478
    // set brush
    if (color.isValid())
        painter->setBrush(color);
    else
        painter->setBrush(Qt::NoBrush);
479

Alexander Lohnau's avatar
Alexander Lohnau committed
480
481
482
    // render
    painter->drawRoundedRect(frameRect, radius, radius);
}
483

Alexander Lohnau's avatar
Alexander Lohnau committed
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
//______________________________________________________________________________
void Helper::renderSidePanelFrame(QPainter *painter, const QRect &rect, const QColor &outline, Side side) const
{
    // check color
    if (!outline.isValid())
        return;

    // adjust rect
    QRectF frameRect(strokedRect(rect));

    // setup painter
    painter->setRenderHint(QPainter::Antialiasing);
    painter->setPen(outline);

    // render
    switch (side) {
    default:
    case SideLeft:
        painter->drawLine(frameRect.topRight(), frameRect.bottomRight());
        break;

    case SideTop:
        painter->drawLine(frameRect.topLeft(), frameRect.topRight());
        break;

    case SideRight:
        painter->drawLine(frameRect.topLeft(), frameRect.bottomLeft());
        break;

    case SideBottom:
        painter->drawLine(frameRect.bottomLeft(), frameRect.bottomRight());
        break;

    case AllSides: {
        const qreal radius(frameRadius(PenWidth::Frame));
        painter->drawRoundedRect(frameRect, radius, radius);
        break;
    }
    }
}
524

Alexander Lohnau's avatar
Alexander Lohnau committed
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
//______________________________________________________________________________
void Helper::renderMenuFrame(QPainter *painter, const QRect &rect, const QColor &color, const QColor &outline, bool roundCorners, bool isTopMenu) const
{
    painter->save();

    // set brush
    if (color.isValid())
        painter->setBrush(color);
    else
        painter->setBrush(Qt::NoBrush);

    // We simulate being able to independently adjust corner radii by
    // setting a clip region and then extending the rectangle beyond it.
    if (isTopMenu) {
        painter->setClipRect(rect);
540
541
    }

Alexander Lohnau's avatar
Alexander Lohnau committed
542
543
544
545
    if (roundCorners) {
        painter->setRenderHint(QPainter::Antialiasing);
        QRectF frameRect(rect);
        qreal radius(frameRadius(PenWidth::NoPen));
546

Alexander Lohnau's avatar
Alexander Lohnau committed
547
548
        if (isTopMenu)
            frameRect.adjust(0, -radius, 0, 0);
549

Alexander Lohnau's avatar
Alexander Lohnau committed
550
551
552
553
554
        // set pen
        if (outline.isValid()) {
            painter->setPen(outline);
            frameRect = strokedRect(frameRect);
            radius = frameRadiusForNewPenWidth(radius, PenWidth::Frame);
555

Alexander Lohnau's avatar
Alexander Lohnau committed
556
557
        } else
            painter->setPen(Qt::NoPen);
558

559
        // render
Alexander Lohnau's avatar
Alexander Lohnau committed
560
        painter->drawRoundedRect(frameRect, radius, radius);
561

Alexander Lohnau's avatar
Alexander Lohnau committed
562
563
564
565
566
    } else {
        painter->setRenderHint(QPainter::Antialiasing, false);
        QRect frameRect(rect);
        if (isTopMenu)
            frameRect.adjust(0, 1, 0, 0);
567

Alexander Lohnau's avatar
Alexander Lohnau committed
568
569
570
        if (outline.isValid()) {
            painter->setPen(outline);
            frameRect.adjust(0, 0, -1, -1);
571

Alexander Lohnau's avatar
Alexander Lohnau committed
572
573
        } else
            painter->setPen(Qt::NoPen);
574

Alexander Lohnau's avatar
Alexander Lohnau committed
575
        painter->drawRect(frameRect);
576
577
    }

Alexander Lohnau's avatar
Alexander Lohnau committed
578
579
    painter->restore();
}
580

Alexander Lohnau's avatar
Alexander Lohnau committed
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
//______________________________________________________________________________
void Helper::renderButtonFrame(QPainter *painter,
                               const QRect &rect,
                               const QPalette &palette,
                               const QHash<QByteArray, bool> &stateProperties,
                               qreal bgAnimation,
                               qreal penAnimation) const
{
    bool enabled = stateProperties.value("enabled", true);
    bool visualFocus = stateProperties.value("visualFocus");
    bool hovered = stateProperties.value("hovered");
    bool down = stateProperties.value("down");
    bool checked = stateProperties.value("checked");
    bool flat = stateProperties.value("flat");
    bool defaultButton = stateProperties.value("defaultButton");
    bool hasNeutralHighlight = stateProperties.value("hasNeutralHighlight");
    bool isActiveWindow = stateProperties.value("isActiveWindow");

    // don't render background if flat and not hovered, down, checked, or given visual focus
    if (flat && !(hovered || down || checked || visualFocus) && bgAnimation == AnimationData::OpacityInvalid && penAnimation == AnimationData::OpacityInvalid) {
        return;
602
603
    }

Alexander Lohnau's avatar
Alexander Lohnau committed
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
    QRectF shadowedRect = this->shadowedRect(rect);
    QRectF frameRect = strokedRect(shadowedRect);
    qreal radius = frameRadius(PenWidth::Frame);
    // setting color group to work around KColorScheme feature
    const QColor &highlightColor = palette.color(!enabled ? QPalette::Disabled : QPalette::Active, QPalette::Highlight);
    QBrush bgBrush;
    QBrush penBrush;

    // Colors
    if (flat) {
        if (down && enabled) {
            bgBrush = alphaColor(highlightColor, highlightBackgroundAlpha);
        } else if (checked) {
            bgBrush = hasNeutralHighlight ? alphaColor(neutralText(palette), highlightBackgroundAlpha) : alphaColor(palette.buttonText().color(), 0.125);
            penBrush = hasNeutralHighlight ? neutralText(palette) : KColorUtils::mix(palette.button().color(), palette.buttonText().color(), 0.3);
        } else if (isActiveWindow && defaultButton) {
            bgBrush = alphaColor(highlightColor, 0.125);
            penBrush = KColorUtils::mix(highlightColor, KColorUtils::mix(palette.button().color(), palette.buttonText().color(), 0.333), 0.5);
622
        } else {
Alexander Lohnau's avatar
Alexander Lohnau committed
623
624
            bgBrush = alphaColor(highlightColor, 0);
            penBrush = hasNeutralHighlight ? neutralText(palette) : bgBrush;
625
        }
Alexander Lohnau's avatar
Alexander Lohnau committed
626
627
628
629
630
631
632
633
634
635
636
637
638
    } else {
        if (down && enabled) {
            bgBrush = KColorUtils::mix(palette.button().color(), highlightColor, 0.333);
        } else if (checked) {
            bgBrush = hasNeutralHighlight ? KColorUtils::mix(palette.button().color(), neutralText(palette), 0.333)
                                          : KColorUtils::mix(palette.button().color(), palette.buttonText().color(), 0.125);
            penBrush = hasNeutralHighlight ? neutralText(palette) : KColorUtils::mix(palette.button().color(), palette.buttonText().color(), 0.3);
        } else if (isActiveWindow && defaultButton) {
            bgBrush = KColorUtils::mix(palette.button().color(), highlightColor, 0.2);
            penBrush = KColorUtils::mix(highlightColor, KColorUtils::mix(palette.button().color(), palette.buttonText().color(), 0.333), 0.5);
        } else {
            bgBrush = palette.button().color();
            penBrush = hasNeutralHighlight ? neutralText(palette) : KColorUtils::mix(palette.button().color(), palette.buttonText().color(), 0.3);
639
640
641
        }
    }

Alexander Lohnau's avatar
Alexander Lohnau committed
642
643
    if ((hovered || visualFocus || down) && enabled) {
        penBrush = highlightColor;
644
645
    }

Alexander Lohnau's avatar
Alexander Lohnau committed
646
647
648
649
650
    // Animations
    if (bgAnimation != AnimationData::OpacityInvalid && enabled) {
        QColor color1 = bgBrush.color();
        QColor color2 = flat ? alphaColor(highlightColor, highlightBackgroundAlpha) : KColorUtils::mix(palette.button().color(), highlightColor, 0.333);
        bgBrush = KColorUtils::mix(color1, color2, bgAnimation);
651
    }
Alexander Lohnau's avatar
Alexander Lohnau committed
652
653
654
655
    if (penAnimation != AnimationData::OpacityInvalid && enabled) {
        QColor color1 = penBrush.color();
        QColor color2 = highlightColor;
        penBrush = KColorUtils::mix(color1, color2, penAnimation);
Hugo Pereira Da Costa's avatar
Hugo Pereira Da Costa committed
656
657
    }

Alexander Lohnau's avatar
Alexander Lohnau committed
658
659
660
661
662
663
664
665
666
667
668
669
    // Gradient
    if (isActiveWindow && !(flat || down || hovered || checked) && enabled) {
        QLinearGradient bgGradient(frameRect.topLeft(), frameRect.bottomLeft());
        bgGradient.setColorAt(0, KColorUtils::mix(bgBrush.color(), Qt::white, 0.03125));
        bgGradient.setColorAt(0.5, bgBrush.color());
        bgGradient.setColorAt(1, KColorUtils::mix(bgBrush.color(), Qt::black, 0.03125));
        QLinearGradient penGradient(frameRect.topLeft(), frameRect.bottomLeft());
        penGradient.setColorAt(0, KColorUtils::mix(penBrush.color(), Qt::white, 0.03125));
        penGradient.setColorAt(1, KColorUtils::mix(penBrush.color(), Qt::black, 0.0625));
        bgBrush = bgGradient;
        penBrush = penGradient;
    }
670

Alexander Lohnau's avatar
Alexander Lohnau committed
671
672
673
674
    // Shadow
    if (isActiveWindow && !(flat || down || checked) && enabled) {
        renderRoundedRectShadow(painter, shadowedRect, shadowColor(palette));
    }
675

Alexander Lohnau's avatar
Alexander Lohnau committed
676
677
678
679
680
681
    // Render button
    painter->setRenderHint(QPainter::Antialiasing, true);
    painter->setBrush(bgBrush);
    painter->setPen(QPen(penBrush, PenWidth::Frame));
    painter->drawRoundedRect(frameRect, radius, radius);
}
682

Alexander Lohnau's avatar
Alexander Lohnau committed
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
//______________________________________________________________________________
void Helper::renderToolBoxFrame(QPainter *painter, const QRect &rect, int tabWidth, const QColor &outline) const
{
    if (!outline.isValid())
        return;

    // round radius
    const qreal radius(frameRadius(PenWidth::Frame));
    const QSizeF cornerSize(2 * radius, 2 * radius);

    // if rect - tabwidth is even, need to increase tabWidth by 1 unit
    // for anti aliasing
    if (!((rect.width() - tabWidth) % 2))
        ++tabWidth;

    // adjust rect for antialiasing
    QRectF baseRect(strokedRect(rect));

    // create path
    QPainterPath path;
    path.moveTo(0, baseRect.height() - 1);
    path.lineTo((baseRect.width() - tabWidth) / 2 - radius, baseRect.height() - 1);
    path.arcTo(QRectF(QPointF((baseRect.width() - tabWidth) / 2 - 2 * radius, baseRect.height() - 1 - 2 * radius), cornerSize), 270, 90);
    path.lineTo((baseRect.width() - tabWidth) / 2, radius);
    path.arcTo(QRectF(QPointF((baseRect.width() - tabWidth) / 2, 0), cornerSize), 180, -90);
    path.lineTo((baseRect.width() + tabWidth) / 2 - 1 - radius, 0);
    path.arcTo(QRectF(QPointF((baseRect.width() + tabWidth) / 2 - 1 - 2 * radius, 0), cornerSize), 90, -90);
    path.lineTo((baseRect.width() + tabWidth) / 2 - 1, baseRect.height() - 1 - radius);
    path.arcTo(QRectF(QPointF((baseRect.width() + tabWidth) / 2 - 1, baseRect.height() - 1 - 2 * radius), cornerSize), 180, 90);
    path.lineTo(baseRect.width() - 1, baseRect.height() - 1);

    // render
    painter->setRenderHints(QPainter::Antialiasing);
    painter->setBrush(Qt::NoBrush);
    painter->setPen(outline);
    painter->translate(baseRect.topLeft());
    painter->drawPath(path);
}
721

Alexander Lohnau's avatar
Alexander Lohnau committed
722
723
724
725
//______________________________________________________________________________
void Helper::renderTabWidgetFrame(QPainter *painter, const QRect &rect, const QColor &color, const QColor &outline, Corners corners) const
{
    painter->setRenderHint(QPainter::Antialiasing);
726

Alexander Lohnau's avatar
Alexander Lohnau committed
727
728
    QRectF frameRect(rect.adjusted(1, 1, -1, -1));
    qreal radius(frameRadius(PenWidth::NoPen));
729

Alexander Lohnau's avatar
Alexander Lohnau committed
730
731
732
    // set pen
    if (outline.isValid()) {
        painter->setPen(outline);
733
        frameRect = strokedRect(frameRect);
Alexander Lohnau's avatar
Alexander Lohnau committed
734
        radius = frameRadiusForNewPenWidth(radius, PenWidth::Frame);
735

Alexander Lohnau's avatar
Alexander Lohnau committed
736
737
    } else
        painter->setPen(Qt::NoPen);
738

Alexander Lohnau's avatar
Alexander Lohnau committed
739
740
741
742
743
    // set brush
    if (color.isValid())
        painter->setBrush(color);
    else
        painter->setBrush(Qt::NoBrush);
744

Alexander Lohnau's avatar
Alexander Lohnau committed
745
746
747
748
    // render
    QPainterPath path(roundedPath(frameRect, corners, radius));
    painter->drawPath(path);
}
749

Alexander Lohnau's avatar
Alexander Lohnau committed
750
751
752
753
754
755
756
757
//______________________________________________________________________________
void Helper::renderSelection(QPainter *painter, const QRect &rect, const QColor &color) const
{
    painter->setRenderHint(QPainter::Antialiasing);
    painter->setPen(Qt::NoPen);
    painter->setBrush(color);
    painter->drawRect(rect);
}
758

Alexander Lohnau's avatar
Alexander Lohnau committed
759
760
761
762
763
764
//______________________________________________________________________________
void Helper::renderSeparator(QPainter *painter, const QRect &rect, const QColor &color, bool vertical) const
{
    painter->setRenderHint(QPainter::Antialiasing, false);
    painter->setBrush(Qt::NoBrush);
    painter->setPen(color);
765

Alexander Lohnau's avatar
Alexander Lohnau committed
766
767
768
    if (vertical) {
        painter->translate(rect.width() / 2, 0);
        painter->drawLine(rect.topLeft(), rect.bottomLeft());
769

Alexander Lohnau's avatar
Alexander Lohnau committed
770
771
772
    } else {
        painter->translate(0, rect.height() / 2);
        painter->drawLine(rect.topLeft(), rect.topRight());
773
    }
Alexander Lohnau's avatar
Alexander Lohnau committed
774
}
775

Alexander Lohnau's avatar
Alexander Lohnau committed
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
//______________________________________________________________________________
void Helper::renderCheckBoxBackground(QPainter *painter,
                                      const QRect &rect,
                                      const QPalette &palette,
                                      CheckBoxState state,
                                      bool neutalHighlight,
                                      bool sunken,
                                      qreal animation) const
{
    // setup painter
    painter->setRenderHint(QPainter::Antialiasing, true);

    // copy rect
    QRectF frameRect(rect);
    frameRect.adjust(2, 2, -2, -2);
    frameRect = strokedRect(frameRect);

    auto transparent = neutalHighlight ? neutralText(palette) : palette.highlight().color();
    transparent.setAlphaF(highlightBackgroundAlpha);

    QBrush penBrush;
    if (neutalHighlight) {
        penBrush = neutralText(palette);
    } else if (state == CheckOn || state == CheckPartial) {
        penBrush = palette.highlight().color();
    } else {
        penBrush = transparentize(palette.text().color(), highlightBackgroundAlpha);
    }
    painter->setPen(QPen(penBrush, PenWidth::Frame));
805

Alexander Lohnau's avatar
Alexander Lohnau committed
806
    const auto radius = Metrics::CheckBox_Radius;
807

Alexander Lohnau's avatar
Alexander Lohnau committed
808
809
810
811
812
    switch (state) {
    case CheckOff:
        painter->setBrush(palette.base().color().darker(sunken ? radioCheckSunkenDarkeningFactor : 100));
        painter->drawRoundedRect(frameRect, radius, radius);
        break;
813

Alexander Lohnau's avatar
Alexander Lohnau committed
814
815
816
817
818
    case CheckPartial:
    case CheckOn:
        painter->setBrush(transparent);
        painter->drawRoundedRect(frameRect, radius, radius);
        break;
819

Alexander Lohnau's avatar
Alexander Lohnau committed
820
821
822
823
824
825
826
827
828
    case CheckAnimated:
        painter->setBrush(palette.base().color().darker(sunken ? radioCheckSunkenDarkeningFactor : 100));
        painter->drawRoundedRect(frameRect, radius, radius);
        painter->setBrush(transparent);
        painter->setOpacity(animation);
        painter->drawRoundedRect(frameRect, radius, radius);
        break;
    }
}
829

Alexander Lohnau's avatar
Alexander Lohnau committed
830
831
832
833
834
835
836
837
838
839
840
841
842
//______________________________________________________________________________
void Helper::renderCheckBox(QPainter *painter,
                            const QRect &rect,
                            const QPalette &palette,
                            bool mouseOver,
                            CheckBoxState state,
                            CheckBoxState target,
                            bool neutalHighlight,
                            bool sunken,
                            qreal animation,
                            qreal hoverAnimation) const
{
    Q_UNUSED(sunken)
843

Alexander Lohnau's avatar
Alexander Lohnau committed
844
845
    // setup painter
    painter->setRenderHint(QPainter::Antialiasing, true);
846

Alexander Lohnau's avatar
Alexander Lohnau committed
847
848
849
    // copy rect and radius
    QRectF frameRect(rect);
    frameRect.adjust(2, 2, -2, -2);
850

Alexander Lohnau's avatar
Alexander Lohnau committed
851
852
    if (mouseOver) {
        painter->save();
853

Alexander Lohnau's avatar
Alexander Lohnau committed
854
855
856
        if (hoverAnimation != AnimationData::OpacityInvalid) {
            painter->setOpacity(hoverAnimation);
        }
857

Alexander Lohnau's avatar
Alexander Lohnau committed
858
859
        painter->setPen(QPen(neutalHighlight ? neutralText(palette).lighter() : focusColor(palette), PenWidth::Frame));
        painter->setBrush(Qt::NoBrush);
860

Alexander Lohnau's avatar
Alexander Lohnau committed
861
        painter->drawRoundedRect(frameRect.adjusted(0.5, 0.5, -0.5, -0.5), Metrics::CheckBox_Radius, Metrics::CheckBox_Radius);
862

Alexander Lohnau's avatar
Alexander Lohnau committed
863
864
        painter->restore();
    }
865

Alexander Lohnau's avatar
Alexander Lohnau committed
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
    // check
    auto leftPoint = frameRect.center();
    leftPoint.setX(frameRect.left() + 4);

    auto bottomPoint = frameRect.center();
    bottomPoint.setX(bottomPoint.x() - 1);
    bottomPoint.setY(frameRect.bottom() - 5);

    auto rightPoint = frameRect.center();
    rightPoint.setX(rightPoint.x() + 4.5);
    rightPoint.setY(frameRect.top() + 5.5);

    QPainterPath path;
    path.moveTo(leftPoint);
    path.lineTo(bottomPoint);
    path.lineTo(rightPoint);

    // dots
    auto centerDot = QRectF(frameRect.center(), QSize(2, 2));
    centerDot.adjust(-1, -1, -1, -1);
    auto leftDot = centerDot.adjusted(-4, 0, -4, 0);
    auto rightDot = centerDot.adjusted(4, 0, 4, 0);

    painter->setPen(Qt::transparent);
    painter->setBrush(Qt::transparent);

    auto checkPen = QPen(palette.text(), PenWidth::Frame * 2);
    checkPen.setJoinStyle(Qt::MiterJoin);

    switch (state) {
    case CheckOff:
        break;
    case CheckOn:
        painter->setPen(checkPen);
        painter->drawPath(path);
        break;
    case CheckPartial:
        painter->setBrush(palette.text());
        painter->drawRect(leftDot);
        painter->drawRect(centerDot);
        painter->drawRect(rightDot);
        break;
    case CheckAnimated:
        checkPen.setDashPattern({path.length() * animation, path.length()});

        switch (target) {
912
913
914
        case CheckOff:
            break;
        case CheckOn:
Alexander Lohnau's avatar
Alexander Lohnau committed
915
916
            painter->setPen(checkPen);
            painter->drawPath(path);
917
918
            break;
        case CheckPartial:
Alexander Lohnau's avatar
Alexander Lohnau committed
919
920
921
922
923
924
            if (animation >= 3 / 3)
                painter->drawRect(rightDot);
            if (animation >= 2 / 3)
                painter->drawRect(centerDot);
            if (animation >= 1 / 3)
                painter->drawRect(leftDot);
925
926
927
            break;
        case CheckAnimated:
            break;
928
        }
Alexander Lohnau's avatar
Alexander Lohnau committed
929
        break;
930
    }
Alexander Lohnau's avatar
Alexander Lohnau committed
931
}
932

Alexander Lohnau's avatar
Alexander Lohnau committed
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
//______________________________________________________________________________
void Helper::renderRadioButtonBackground(QPainter *painter,
                                         const QRect &rect,
                                         const QPalette &palette,
                                         RadioButtonState state,
                                         bool neutalHighlight,
                                         bool sunken,
                                         qreal animation) const
{
    // setup painter
    painter->setRenderHint(QPainter::Antialiasing, true);

    // copy rect
    QRectF frameRect(rect);
    frameRect.adjust(2, 2, -2, -2);
    frameRect.adjust(0.5, 0.5, -0.5, -0.5);

    auto transparent = neutalHighlight ? neutralText(palette) : palette.highlight().color();
    transparent.setAlphaF(highlightBackgroundAlpha);

    QBrush penBrush;
    if (neutalHighlight) {
        penBrush = neutralText(palette);
    } else if (state == RadioOn) {
        penBrush = palette.highlight().color();
    } else {
        penBrush = transparentize(palette.text().color(), highlightBackgroundAlpha);
960
    }
Alexander Lohnau's avatar
Alexander Lohnau committed
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
    painter->setPen(QPen(penBrush, PenWidth::Frame));

    switch (state) {
    case RadioOff:
        painter->setBrush(palette.base().color().darker(sunken ? radioCheckSunkenDarkeningFactor : 100));
        painter->drawEllipse(frameRect);
        break;
    case RadioOn:
        painter->setBrush(transparent);
        painter->drawEllipse(frameRect);
        break;
    case RadioAnimated:
        painter->setBrush(palette.base().color().darker(sunken ? radioCheckSunkenDarkeningFactor : 100));
        painter->drawEllipse(frameRect);
        painter->setBrush(transparent);
        painter->setOpacity(animation);
        painter->drawEllipse(frameRect);
        break;
979
    }
Alexander Lohnau's avatar
Alexander Lohnau committed
980
}
981

Alexander Lohnau's avatar
Alexander Lohnau committed
982
983
984
985
986
987
988
989
990
991
992
993
//______________________________________________________________________________
void Helper::renderRadioButton(QPainter *painter,
                               const QRect &rect,
                               const QPalette &palette,
                               bool mouseOver,
                               RadioButtonState state,
                               bool neutralHighlight,
                               bool sunken,
                               qreal animation,
                               qreal animationHover) const
{
    Q_UNUSED(sunken)
994

Alexander Lohnau's avatar
Alexander Lohnau committed
995
996
    // setup painter
    painter->setRenderHint(QPainter::Antialiasing, true);
997

Alexander Lohnau's avatar
Alexander Lohnau committed
998
999
1000
    // copy rect
    QRectF frameRect(rect);
    frameRect.adjust(1, 1, -1, -1);