1 /* Plastik KWin window decoration
2 Copyright (C) 2003-2005 Sandro Giessl <sandro@giessl.com>
4 based on the window decoration "Web":
5 Copyright (C) 2001 Rik Hemsley (rikkus) <rik@kde.org>
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public
9 License as published by the Free Software Foundation; either
10 version 2 of the License, or (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; see the file COPYING. If not, write to
19 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 Boston, MA 02110-1301, USA.
23 #include "plastikbutton.h"
25 // #include <kwin/options.h>
27 #include <QAbstractButton>
34 #include "plastikbutton.moc"
35 #include "plastikclient.h"
37 #include <KGlobalSettings>
38 #include <KColorScheme>
39 #include <KColorUtils>
44 static const uint TIMERINTERVAL
= 50; // msec
45 static const uint ANIMATIONSTEPS
= 4;
47 PlastikButton::PlastikButton(ButtonType type
, PlastikClient
*parent
)
48 : KCommonDecorationButton(type
, parent
),
50 m_iconType(NumButtonIcons
),
53 setAttribute(Qt::WA_NoSystemBackground
);
55 // no need to reset here as the button will be reseted on first resize.
57 animTmr
= new QTimer(this);
58 animTmr
->setSingleShot(true); // single-shot
59 connect(animTmr
, SIGNAL(timeout() ), this, SLOT(animate() ) );
63 PlastikButton::~PlastikButton()
67 void PlastikButton::reset(unsigned long changed
)
69 if (changed
&DecorationReset
|| changed
&ManualReset
|| changed
&SizeChange
|| changed
&StateChange
) {
72 m_iconType
= CloseIcon
;
75 m_iconType
= HelpIcon
;
82 m_iconType
= MaxRestoreIcon
;
87 case OnAllDesktopsButton
:
89 m_iconType
= NotOnAllDesktopsIcon
;
91 m_iconType
= OnAllDesktopsIcon
;
96 m_iconType
= UnShadeIcon
;
98 m_iconType
= ShadeIcon
;
103 m_iconType
= NoKeepAboveIcon
;
105 m_iconType
= KeepAboveIcon
;
110 m_iconType
= NoKeepBelowIcon
;
112 m_iconType
= KeepBelowIcon
;
116 m_iconType
= NumButtonIcons
; // empty...
124 void PlastikButton::animate()
129 if(animProgress
< ANIMATIONSTEPS
) {
130 if (Handler()->animateButtons() ) {
133 animProgress
= ANIMATIONSTEPS
;
135 animTmr
->start(TIMERINTERVAL
); // single-shot timer
138 if(animProgress
> 0) {
139 if (Handler()->animateButtons() ) {
144 animTmr
->start(TIMERINTERVAL
); // single-shot timer
151 void PlastikButton::enterEvent(QEvent
*e
)
153 QAbstractButton::enterEvent(e
);
159 void PlastikButton::leaveEvent(QEvent
*e
)
161 QAbstractButton::leaveEvent(e
);
167 void PlastikButton::paintEvent(QPaintEvent
*)
173 void PlastikButton::drawButton(QPainter
*painter
)
175 QRect
r(0,0,width(),height());
177 bool active
= m_client
->isActive();
181 double c
= KGlobalSettings::contrastF();
182 QColor titleBar
= KDecoration::options()->color(KDecoration::ColorTitleBar
, active
);
183 QColor contourTop
= KColorScheme::shade(titleBar
, KColorScheme::DarkShade
, c
- 0.4);
184 QColor contourBottom
= KColorScheme::shade(titleBar
, KColorScheme::MidShade
, c
);
185 QColor surfaceTop
= KColorScheme::shade(titleBar
, KColorScheme::MidlightShade
, c
- 0.4);
186 QColor surfaceBottom
= KColorScheme::shade(titleBar
, KColorScheme::LightShade
, c
- 0.4);
188 QColor highlightColor
= titleBar
;
190 if (type() == CloseButton
) {
191 KColorScheme
kcs(active
? QPalette::Active
: QPalette::Inactive
, KColorScheme::Button
);
192 highlightColor
= kcs
.foreground(KColorScheme::NegativeText
).color();
195 highlightColor
= KColorScheme::shade(highlightColor
, KColorScheme::ShadowShade
);
198 else if (animProgress
> 0) {
199 alpha
= 0.6 * (double)animProgress
/ (double)ANIMATIONSTEPS
;
200 highlightColor
= KColorScheme::shade(highlightColor
, KColorScheme::LightShade
, qMin(1.0, c
+ 0.4));
204 contourTop
= KColorUtils::mix(contourTop
, highlightColor
, alpha
*0.4);
205 contourBottom
= KColorUtils::mix(contourBottom
, highlightColor
, alpha
*0.4);
206 surfaceTop
= KColorUtils::mix(surfaceTop
, highlightColor
, alpha
);
207 surfaceBottom
= KColorUtils::mix(surfaceBottom
, highlightColor
, alpha
);
210 QPixmap
buffer(width(), height());
211 QPainter
bP(&buffer
);
213 // fake the titlebar background
214 bP
.drawTiledPixmap(0, 0, width(), width(), m_client
->getTitleBarTile(active
) );
216 if (type() != MenuButton
|| hover
|| animProgress
!= 0) {
217 qreal rxo
= 600/width();
218 qreal ryo
= 600/height();
219 qreal rxi
= 500/width();
220 qreal ryi
= 500/height();
221 bP
.setPen(Qt::NoPen
);
222 bP
.setRenderHints(QPainter::Antialiasing
);
224 QLinearGradient
outlineGradient(0, 0, 0, r
.height());
225 outlineGradient
.setColorAt(0.0, contourTop
);
226 outlineGradient
.setColorAt(1.0, contourBottom
);
227 bP
.setBrush(outlineGradient
);
228 bP
.drawRoundRect(r
, rxo
, ryo
);
230 QLinearGradient
surfaceGradient(0, 0, 0, r
.height());
231 surfaceGradient
.setColorAt(0.0, surfaceTop
);
232 surfaceGradient
.setColorAt(1.0, surfaceBottom
);
233 bP
.setBrush(surfaceGradient
);
234 bP
.drawRoundRect(r
.adjusted(1,1,-1,-1), rxi
, ryi
);
237 if (type() == MenuButton
)
239 QPixmap
menuIcon(m_client
->icon().pixmap( style()->pixelMetric( QStyle::PM_SmallIconSize
) ));
240 if (width() < menuIcon
.width() || height() < menuIcon
.height() ) {
241 menuIcon
= menuIcon
.scaled(width(), height());
243 bP
.drawPixmap((width()-menuIcon
.width())/2, (height()-menuIcon
.height())/2, menuIcon
);
248 const QBitmap
&icon
= Handler()->buttonBitmap(m_iconType
, size(), decoration()->isToolWindow() );
249 dX
= r
.x()+(r
.width()-icon
.width())/2;
250 dY
= r
.y()+(r
.height()-icon
.height())/2;
255 QColor fontColor
= Handler()->getColor(TitleFont
,active
);
256 if(!isDown() && Handler()->titleShadow() ) {
257 QColor shadowColor
= KColorScheme::shade(fontColor
, KColorScheme::ShadowShade
);
258 shadowColor
.setAlphaF(shadowColor
.alphaF() * 0.3);
259 bP
.setPen(shadowColor
);
260 bP
.drawPixmap(dX
+1, dY
+1, icon
);
263 bP
.setPen(fontColor
);
264 bP
.drawPixmap(dX
, dY
, icon
);
268 painter
->drawPixmap(0, 0, buffer
);
271 QBitmap
IconEngine::icon(ButtonIcon icon
, int size
)
276 QBitmap
bitmap(size
,size
);
277 bitmap
.fill(Qt::color0
);
280 p
.setPen(Qt::color1
);
282 QRect r
= bitmap
.rect();
286 if (r
.width() > 16) {
288 } else if (r
.width() > 4) {
292 if (r
.width() > 16) {
294 } else if (r
.width() > 7) {
302 if (r
.width() > 16) {
304 } else if (r
.width() > 4) {
308 drawObject(p
, DiagonalLine
, r
.x(), r
.y(), r
.width(), lineWidth
);
309 drawObject(p
, CrossDiagonalLine
, r
.x(), r
.bottom(), r
.width(), lineWidth
);
316 int lineWidth2
= 1; // frame
317 if (r
.width() > 16) {
319 } else if (r
.width() > 4) {
323 drawObject(p
, HorizontalLine
, r
.x(), r
.top(), r
.width(), lwTitleBar
);
324 drawObject(p
, HorizontalLine
, r
.x(), r
.bottom()-(lineWidth2
-1), r
.width(), lineWidth2
);
325 drawObject(p
, VerticalLine
, r
.x(), r
.top(), r
.height(), lineWidth2
);
326 drawObject(p
, VerticalLine
, r
.right()-(lineWidth2
-1), r
.top(), r
.height(), lineWidth2
);
333 int lineWidth2
= 1; // frame
334 if (r
.width() > 16) {
336 } else if (r
.width() > 4) {
340 int margin1
, margin2
;
341 margin1
= margin2
= lineWidth2
*2;
346 drawObject(p
, HorizontalLine
, r
.x()+margin1
, r
.top(), r
.width()-margin1
, lineWidth2
);
347 drawObject(p
, HorizontalLine
, r
.right()-margin2
, r
.bottom()-(lineWidth2
-1)-margin1
, margin2
, lineWidth2
);
348 drawObject(p
, VerticalLine
, r
.x()+margin1
, r
.top(), margin2
, lineWidth2
);
349 drawObject(p
, VerticalLine
, r
.right()-(lineWidth2
-1), r
.top(), r
.height()-margin1
, lineWidth2
);
352 drawObject(p
, HorizontalLine
, r
.x(), r
.top()+margin2
, r
.width()-margin2
, lwTitleBar
);
353 drawObject(p
, HorizontalLine
, r
.x(), r
.bottom()-(lineWidth2
-1), r
.width()-margin2
, lineWidth2
);
354 drawObject(p
, VerticalLine
, r
.x(), r
.top()+margin2
, r
.height(), lineWidth2
);
355 drawObject(p
, VerticalLine
, r
.right()-(lineWidth2
-1)-margin2
, r
.top()+margin2
, r
.height(), lineWidth2
);
362 drawObject(p
, HorizontalLine
, r
.x(), r
.bottom()-(lwTitleBar
-1), r
.width(), lwTitleBar
);
369 int center
= r
.x()+r
.width()/2 -1;
370 int side
= r
.width()/4;
372 // paint a question mark... code is quite messy, to be cleaned up later...! :o
374 if (r
.width() > 16) {
378 drawObject(p
, HorizontalLine
, center
-side
+3, r
.y(), 2*side
-3-1, lineWidth
);
380 drawObject(p
, CrossDiagonalLine
, center
-side
-1, r
.y()+5, 6, lineWidth
);
381 drawObject(p
, DiagonalLine
, center
+side
-3, r
.y(), 5, lineWidth
);
383 drawObject(p
, VerticalLine
, center
+side
+2-lineWidth
, r
.y()+3, r
.height()-(2*lineWidth
+side
+2+1), lineWidth
);
385 drawObject(p
, CrossDiagonalLine
, center
, r
.bottom()-2*lineWidth
, side
+2, lineWidth
);
386 drawObject(p
, HorizontalLine
, center
, r
.bottom()-3*lineWidth
+2, lineWidth
, lineWidth
);
388 drawObject(p
, HorizontalLine
, center
, r
.bottom()-(lineWidth
-1), lineWidth
, lineWidth
);
389 } else if (r
.width() > 8) {
393 drawObject(p
, HorizontalLine
, center
-(side
-1), r
.y(), 2*side
-1, lineWidth
);
396 drawObject(p
, CrossDiagonalLine
, center
-side
-1, r
.y()+3, 3, lineWidth
);
398 drawObject(p
, CrossDiagonalLine
, center
-side
-1, r
.y()+2, 3, lineWidth
);
400 drawObject(p
, DiagonalLine
, center
+side
-1, r
.y(), 3, lineWidth
);
402 drawObject(p
, VerticalLine
, center
+side
+2-lineWidth
, r
.y()+2, r
.height()-(2*lineWidth
+side
+1), lineWidth
);
404 drawObject(p
, CrossDiagonalLine
, center
, r
.bottom()-2*lineWidth
+1, side
+2, lineWidth
);
406 drawObject(p
, HorizontalLine
, center
, r
.bottom()-(lineWidth
-1), lineWidth
, lineWidth
);
411 drawObject(p
, HorizontalLine
, center
-(side
-1), r
.y(), 2*side
, lineWidth
);
413 drawObject(p
, CrossDiagonalLine
, center
-side
-1, r
.y()+1, 2, lineWidth
);
415 drawObject(p
, VerticalLine
, center
+side
+1, r
.y(), r
.height()-(side
+2+1), lineWidth
);
417 drawObject(p
, CrossDiagonalLine
, center
, r
.bottom()-2, side
+2, lineWidth
);
419 drawObject(p
, HorizontalLine
, center
, r
.bottom(), 1, 1);
425 case NotOnAllDesktopsIcon
:
427 int lwMark
= r
.width()-lwTitleBar
*2-2;
431 drawObject(p
, HorizontalLine
, r
.x()+(r
.width()-lwMark
)/2, r
.y()+(r
.height()-lwMark
)/2, lwMark
, lwMark
);
433 // Fall through to OnAllDesktopsIcon intended!
435 case OnAllDesktopsIcon
:
438 drawObject(p
, HorizontalLine
, r
.x()+lwTitleBar
, r
.y(), r
.width()-2*lwTitleBar
, lwTitleBar
);
439 drawObject(p
, HorizontalLine
, r
.x()+lwTitleBar
, r
.bottom()-(lwTitleBar
-1), r
.width()-2*lwTitleBar
, lwTitleBar
);
441 drawObject(p
, VerticalLine
, r
.x(), r
.y()+lwTitleBar
, r
.height()-2*lwTitleBar
, lwTitleBar
);
442 drawObject(p
, VerticalLine
, r
.right()-(lwTitleBar
-1), r
.y()+lwTitleBar
, r
.height()-2*lwTitleBar
, lwTitleBar
);
448 case NoKeepAboveIcon
:
450 int center
= r
.x()+r
.width()/2;
453 drawObject(p
, CrossDiagonalLine
, r
.x(), center
+2*lwArrow
, center
-r
.x(), lwArrow
);
454 drawObject(p
, DiagonalLine
, r
.x()+center
, r
.y()+1+2*lwArrow
, center
-r
.x(), lwArrow
);
456 drawObject(p
, HorizontalLine
, center
-(lwArrow
-2), r
.y()+2*lwArrow
, (lwArrow
-2)*2, lwArrow
);
458 // Fall through to KeepAboveIcon intended!
462 int center
= r
.x()+r
.width()/2;
465 drawObject(p
, CrossDiagonalLine
, r
.x(), center
, center
-r
.x(), lwArrow
);
466 drawObject(p
, DiagonalLine
, r
.x()+center
, r
.y()+1, center
-r
.x(), lwArrow
);
468 drawObject(p
, HorizontalLine
, center
-(lwArrow
-2), r
.y(), (lwArrow
-2)*2, lwArrow
);
473 case NoKeepBelowIcon
:
475 int center
= r
.x()+r
.width()/2;
478 drawObject(p
, DiagonalLine
, r
.x(), center
-2*lwArrow
, center
-r
.x(), lwArrow
);
479 drawObject(p
, CrossDiagonalLine
, r
.x()+center
, r
.bottom()-1-2*lwArrow
, center
-r
.x(), lwArrow
);
481 drawObject(p
, HorizontalLine
, center
-(lwArrow
-2), r
.bottom()-(lwArrow
-1)-2*lwArrow
, (lwArrow
-2)*2, lwArrow
);
483 // Fall through to KeepBelowIcon intended!
487 int center
= r
.x()+r
.width()/2;
490 drawObject(p
, DiagonalLine
, r
.x(), center
, center
-r
.x(), lwArrow
);
491 drawObject(p
, CrossDiagonalLine
, r
.x()+center
, r
.bottom()-1, center
-r
.x(), lwArrow
);
493 drawObject(p
, HorizontalLine
, center
-(lwArrow
-2), r
.bottom()-(lwArrow
-1), (lwArrow
-2)*2, lwArrow
);
500 drawObject(p
, HorizontalLine
, r
.x(), r
.y(), r
.width(), lwTitleBar
);
509 if (r
.width() > 16) {
512 } else if (r
.width() > 7) {
517 int h
= qMax( (r
.width()/2), (lw1
+2*lw2
) );
520 drawObject(p
, HorizontalLine
, r
.x(), r
.y(), r
.width(), lw1
);
521 drawObject(p
, HorizontalLine
, r
.x(), r
.x()+h
-(lw2
-1), r
.width(), lw2
);
523 drawObject(p
, VerticalLine
, r
.x(), r
.y(), h
, lw2
);
524 drawObject(p
, VerticalLine
, r
.right()-(lw2
-1), r
.y(), h
, lw2
);
535 bitmap
.setMask(bitmap
);
540 void IconEngine::drawObject(QPainter
&p
, Object object
, int x
, int y
, int length
, int lineWidth
)
544 if (lineWidth
<= 1) {
545 for (int i
= 0; i
< length
; ++i
) {
546 p
.drawPoint(x
+i
,y
+i
);
548 } else if (lineWidth
<= 2) {
549 for (int i
= 0; i
< length
; ++i
) {
550 p
.drawPoint(x
+i
,y
+i
);
552 for (int i
= 0; i
< (length
-1); ++i
) {
553 p
.drawPoint(x
+1+i
,y
+i
);
554 p
.drawPoint(x
+i
,y
+1+i
);
557 for (int i
= 1; i
< (length
-1); ++i
) {
558 p
.drawPoint(x
+i
,y
+i
);
560 for (int i
= 0; i
< (length
-1); ++i
) {
561 p
.drawPoint(x
+1+i
,y
+i
);
562 p
.drawPoint(x
+i
,y
+1+i
);
564 for (int i
= 0; i
< (length
-2); ++i
) {
565 p
.drawPoint(x
+2+i
,y
+i
);
566 p
.drawPoint(x
+i
,y
+2+i
);
570 case CrossDiagonalLine
:
571 if (lineWidth
<= 1) {
572 for (int i
= 0; i
< length
; ++i
) {
573 p
.drawPoint(x
+i
,y
-i
);
575 } else if (lineWidth
<= 2) {
576 for (int i
= 0; i
< length
; ++i
) {
577 p
.drawPoint(x
+i
,y
-i
);
579 for (int i
= 0; i
< (length
-1); ++i
) {
580 p
.drawPoint(x
+1+i
,y
-i
);
581 p
.drawPoint(x
+i
,y
-1-i
);
584 for (int i
= 1; i
< (length
-1); ++i
) {
585 p
.drawPoint(x
+i
,y
-i
);
587 for (int i
= 0; i
< (length
-1); ++i
) {
588 p
.drawPoint(x
+1+i
,y
-i
);
589 p
.drawPoint(x
+i
,y
-1-i
);
591 for (int i
= 0; i
< (length
-2); ++i
) {
592 p
.drawPoint(x
+2+i
,y
-i
);
593 p
.drawPoint(x
+i
,y
-2-i
);
598 for (int i
= 0; i
< lineWidth
; ++i
) {
599 p
.drawLine(x
,y
+i
, x
+length
-1, y
+i
);
603 for (int i
= 0; i
< lineWidth
; ++i
) {
604 p
.drawLine(x
+i
,y
, x
+i
, y
+length
-1);