1 /********************************************************************
6 Karol Szwed <gallium@kde.org>
9 Based on the default KWin client.
11 Updated to support toolwindows 3/2001 (KS)
13 This program is free software; you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation; either version 2 of the License, or
16 (at your option) any later version.
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
23 You should have received a copy of the GNU General Public License
24 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 *********************************************************************/
29 #include <QtGui/qdrawutil.h>
33 #include <QPaintEvent>
38 #include <QApplication>
43 static const char *kdelogo
[] = {
44 /* columns rows colors chars-per-pixel */
71 static unsigned char iconify_bits
[] = {
72 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
73 0x00, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x00, 0x00};
75 static unsigned char close_bits
[] = {
76 0x00, 0x00, 0x86, 0x01, 0xcc, 0x00, 0x78, 0x00, 0x30, 0x00, 0x78, 0x00,
77 0xcc, 0x00, 0x86, 0x01, 0x00, 0x00, 0x00, 0x00};
79 static unsigned char maximize_bits
[] = {
80 0xff, 0x01, 0xff, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
81 0x01, 0x01, 0x01, 0x01, 0xff, 0x01, 0x00, 0x00};
83 static unsigned char minmax_bits
[] = {
84 0xfc, 0x00, 0xfc, 0x00, 0x84, 0x00, 0xbf, 0x00, 0xbf, 0x00, 0xe1, 0x00,
85 0x21, 0x00, 0x21, 0x00, 0x3f, 0x00, 0x00, 0x00};
87 static unsigned char question_bits
[] = {
88 0x00, 0x00, 0x3c, 0x00, 0x66, 0x00, 0x60, 0x00, 0x30, 0x00, 0x18, 0x00,
89 0x00, 0x00, 0x18, 0x00, 0x18, 0x00, 0x00, 0x00};
92 // Up / Down titlebar button images
93 static QPixmap
*btnPix1
;
94 static QPixmap
*iBtnPix1
;
95 static QPixmap
*btnDownPix1
;
96 static QPixmap
*iBtnDownPix1
;
98 static QPixmap
*miniBtnPix1
;
99 static QPixmap
*iMiniBtnPix1
;
100 static QPixmap
*miniBtnDownPix1
;
101 static QPixmap
*iMiniBtnDownPix1
;
103 static QPixmap
*defaultMenuPix
;
104 static QColor
*btnForeground
;
105 static bool pixmaps_created
= false;
107 static int toolTitleHeight
;
108 static int normalTitleHeight
;
109 static int borderWidth
;
111 static inline const KDecorationOptions
*options()
113 return KDecoration::options();
116 static void drawButtonFrame( QPixmap
*pix
, const QPalette
&g
, bool sunken
)
119 int x2
= pix
->width() - 1;
120 int y2
= pix
->height() - 1;
123 // titlebar button frame
124 p
.setPen( sunken
? g
.color(QPalette::Dark
).dark(155) : g
.color(QPalette::Light
));
125 p
.drawLine(0, 0, x2
-1, 0);
126 p
.drawLine(0, 0, 0, y2
-1);
130 p
.setPen( g
.color(QPalette::Mid
).dark(135) );
131 p
.drawLine(1, 1, x2
-2, 1);
132 p
.drawLine(1, 1, 1, y2
-2);
135 p
.setPen( sunken
? g
.color(QPalette::Light
) : g
.color(QPalette::Mid
).dark(135));
136 p
.drawLine(1, y2
-1, x2
-1, y2
-1);
137 p
.drawLine(x2
-1, 1, x2
-1, y2
-1);
139 p
.setPen( sunken
? g
.color(QPalette::Light
) : g
.color(QPalette::Dark
).dark(155));
140 p
.drawLine(0, y2
, x2
, y2
);
141 p
.drawLine(x2
, 0, x2
, y2
);
144 static void gradientFill(QPixmap
*pixmap
,
145 const QColor
&color1
, const QColor
&color2
, bool horizontal
= false)
148 QLinearGradient
gradient(0, 0,
149 horizontal
? pixmap
->width() : 0,
150 horizontal
? 0 : pixmap
->height());
151 gradient
.setColorAt(0.0, color1
);
152 gradient
.setColorAt(1.0, color2
);
153 QBrush
brush(gradient
);
154 p
.fillRect(pixmap
->rect(), brush
);
157 static void create_pixmaps ()
162 pixmaps_created
= true;
164 bool highcolor
= QPixmap::defaultDepth() > 8;
166 btnPix1
= new QPixmap
;
167 btnDownPix1
= new QPixmap
;
168 iBtnPix1
= new QPixmap
;
169 iBtnDownPix1
= new QPixmap
;
170 miniBtnPix1
= new QPixmap
;
171 miniBtnDownPix1
= new QPixmap
;
172 iMiniBtnPix1
= new QPixmap
;
173 iMiniBtnDownPix1
= new QPixmap
;
174 defaultMenuPix
= new QPixmap(kdelogo
);
176 // buttons (active/inactive, sunken/unsunken)
177 QColorGroup g
= options()->palette(KDecoration::ColorButtonBg
, true).active();
178 QColor c
= g
.background();
179 *btnPix1
= QPixmap(normalTitleHeight
, normalTitleHeight
-2);
180 *btnDownPix1
= QPixmap(normalTitleHeight
, normalTitleHeight
-2);
181 *iBtnPix1
= QPixmap(normalTitleHeight
, normalTitleHeight
-2);
182 *iBtnDownPix1
= QPixmap(normalTitleHeight
, normalTitleHeight
-2);
184 *miniBtnPix1
= QPixmap(toolTitleHeight
, toolTitleHeight
);
185 *miniBtnDownPix1
= QPixmap(toolTitleHeight
, toolTitleHeight
);
186 *iMiniBtnPix1
= QPixmap(toolTitleHeight
, toolTitleHeight
);
187 *iMiniBtnDownPix1
= QPixmap(toolTitleHeight
, toolTitleHeight
);
189 if (highcolor
&& false) {
190 gradientFill(btnPix1
, c
.light(130), c
.dark(130));
191 gradientFill(btnDownPix1
, c
.dark(130), c
.light(130));
192 gradientFill(miniBtnPix1
, c
.light(130), c
.dark(130));
193 gradientFill(miniBtnDownPix1
, c
.dark(130), c
.light(130));
195 g
= options()->palette(KDecoration::ColorButtonBg
, false);
196 g
.setCurrentColorGroup( QPalette::Active
);
198 gradientFill(iBtnPix1
, c
.light(130), c
.dark(130));
199 gradientFill(iBtnDownPix1
, c
.dark(130), c
.light(130));
200 gradientFill(iMiniBtnPix1
, c
.light(130), c
.dark(130));
201 gradientFill(iMiniBtnDownPix1
, c
.dark(130), c
.light(130));
203 btnPix1
->fill(c
.rgb());
204 btnDownPix1
->fill(c
.rgb());
205 miniBtnPix1
->fill(c
.rgb());
206 miniBtnDownPix1
->fill(c
.rgb());
208 g
= options()->palette(KDecoration::ColorButtonBg
, false);
209 g
.setCurrentColorGroup( QPalette::Active
);
211 iBtnPix1
->fill(c
.rgb());
212 iBtnDownPix1
->fill(c
.rgb());
213 iMiniBtnPix1
->fill(c
.rgb());
214 iMiniBtnDownPix1
->fill(c
.rgb());
217 g
= options()->palette(KDecoration::ColorButtonBg
, true);
218 g
.setCurrentColorGroup( QPalette::Active
);
219 drawButtonFrame(btnPix1
, g
, false);
220 drawButtonFrame(btnDownPix1
, g
, true);
221 drawButtonFrame(miniBtnPix1
, g
, false);
222 drawButtonFrame(miniBtnDownPix1
, g
, true);
224 g
= options()->palette(KDecoration::ColorButtonBg
, false);
225 g
.setCurrentColorGroup( QPalette::Active
);
226 drawButtonFrame(iBtnPix1
, g
, false);
227 drawButtonFrame(iBtnDownPix1
, g
, true);
228 drawButtonFrame(iMiniBtnPix1
, g
, false);
229 drawButtonFrame(iMiniBtnDownPix1
, g
, true);
231 // Make sure button pixmaps contrast with the current colour scheme.
232 if (qGray(options()->color(KDecoration::ColorButtonBg
, true).rgb()) > 127)
233 btnForeground
= new QColor(Qt::black
);
235 btnForeground
= new QColor(Qt::white
);
238 void delete_pixmaps()
245 delete miniBtnDownPix1
;
247 delete iMiniBtnDownPix1
;
248 delete defaultMenuPix
;
249 delete btnForeground
;
250 pixmaps_created
= false;
253 RedmondButton::RedmondButton(ButtonType type
, RedmondDeco
*parent
)
254 : KCommonDecorationButton(type
, parent
)
256 // Eliminate background flicker
257 setAttribute(Qt::WA_NoSystemBackground
, true);
259 miniBtn
= decoration()->isToolWindow();
262 void RedmondButton::reset(unsigned long changed
)
264 if (changed
&DecorationReset
|| changed
&ManualReset
|| changed
&SizeChange
|| changed
&StateChange
) {
267 setBitmap(close_bits
);
270 setBitmap(question_bits
);
273 setBitmap(iconify_bits
);
276 setBitmap( isChecked() ? minmax_bits
: maximize_bits
);
280 QPixmap miniIcon
= decoration()->icon().pixmap(QIcon::Small
, QIcon::Normal
);
281 if (!miniIcon
.isNull()) {
284 setPixmap(*defaultMenuPix
);
298 void RedmondButton::setBitmap(const unsigned char *bitmap
)
303 deco
= QBitmap::fromData( QSize(10, 10), bitmap
);
305 deco
= QBitmap(10,10);
306 deco
.fill(Qt::color0
);
312 void RedmondButton::setPixmap( const QPixmap
&p
)
320 void RedmondButton::paintEvent(QPaintEvent
*)
326 void RedmondButton::drawButton(QPainter
*p
)
328 if ( pix
.isNull() ) {
329 if ( decoration()->isActive() ) {
331 p
->drawPixmap(0, 0, miniBtn
? *miniBtnDownPix1
: *btnDownPix1
);
333 p
->drawPixmap(0, 0, miniBtn
? *miniBtnPix1
: *btnPix1
);
336 p
->drawPixmap(0, 0, miniBtn
? *iMiniBtnDownPix1
: *iBtnDownPix1
);
338 p
->drawPixmap(0, 0, miniBtn
? *iMiniBtnPix1
: *iBtnPix1
);
341 p
->setPen( *btnForeground
);
342 int xOff
= (width()-10)/2;
343 int yOff
= (height()-10)/2;
344 p
->drawPixmap(isDown() ? xOff
+1: xOff
, isDown() ? yOff
+1 : yOff
, deco
);
347 p
->fillRect(0, 0, width(), height(),
348 options()->color(KDecoration::ColorTitleBar
, decoration()->isActive()));
350 p
->fillRect(0, 0, width(), height(),
351 options()->color(KDecoration::ColorTitleBlend
, decoration()->isActive()));
354 if ( type()==MenuButton
&& height() < 16) {
356 // Smooth scale the menu button pixmap
357 QPixmap tmpPix
= QPixmap::fromImage(
358 pix
.toImage().scaled( height(), height(), Qt::IgnoreAspectRatio
, Qt::SmoothTransformation
));
360 p
->drawPixmap( 0, 0, tmpPix
);
362 int xOff
= (width() -pix
.width() )/2;
363 int yOff
= (height()-pix
.height())/2;
364 p
->drawPixmap(xOff
, yOff
, pix
);
370 RedmondDeco::RedmondDeco(KDecorationBridge
*b
, KDecorationFactory
*f
)
371 : KCommonDecoration(b
, f
)
375 QString
RedmondDeco::visibleName() const
377 return i18n("Redmond");
380 QString
RedmondDeco::defaultButtonsLeft() const
385 QString
RedmondDeco::defaultButtonsRight() const
390 bool RedmondDeco::decorationBehaviour(DecorationBehaviour behaviour
) const
403 return KCommonDecoration::decorationBehaviour(behaviour
);
407 int RedmondDeco::layoutMetric(LayoutMetric lm
, bool respectWindowState
, const KCommonDecorationButton
*btn
) const
409 bool border
= !(maximizeMode()==MaximizeFull
&& !options()->moveResizeMaximizedWindows());
414 case LM_BorderBottom
:
415 return border
? borderWidth
: 0;
417 case LM_TitleEdgeLeft
:
418 case LM_TitleEdgeRight
:
419 return border
? borderWidth
+2 : 2;
421 case LM_TitleEdgeTop
:
422 return border
? borderWidth
+2 : 2;
424 case LM_TitleEdgeBottom
:
425 return border
? 1 : 0;
427 case LM_TitleBorderLeft
:
428 case LM_TitleBorderRight
:
429 return border
? 1 : 0;
432 return titleHeight
-2;
435 return titleHeight
-2;
436 case LM_ButtonHeight
:
437 if (isToolWindow() || (btn
&& btn
->type()==MenuButton
) ) {
438 return titleHeight
-2;
440 return titleHeight
-2-2;
443 case LM_ButtonSpacing
:
447 return KCommonDecoration::layoutMetric(lm
, respectWindowState
, btn
);
451 KCommonDecorationButton
*RedmondDeco::createButton(ButtonType type
)
455 return new RedmondButton(MenuButton
, this);
457 return new RedmondButton(HelpButton
, this);
459 return new RedmondButton(MinButton
, this);
461 return new RedmondButton(MaxButton
, this);
463 return new RedmondButton(CloseButton
, this);
470 void RedmondDeco::init()
472 // Finally, toolwindows look small
473 if ( isToolWindow() ) {
474 titleHeight
= toolTitleHeight
;
476 titleHeight
= normalTitleHeight
;
479 KCommonDecoration::init();
482 void RedmondDeco::reset( unsigned long changed
)
484 KCommonDecoration::reset(changed
);
487 void RedmondDeco::paintEvent( QPaintEvent
* )
489 bool hicolor
= QPixmap::defaultDepth() > 8;
492 // Modify borderWith used by titlebar to 0, when maximized and not move or resize able
493 bool border
= !(maximizeMode()==MaximizeFull
&& !options()->moveResizeMaximizedWindows());
494 int modBorderWidth
= border
? borderWidth
: 0;
496 QPainter
p(widget());
498 // Obtain widget bounds.
499 QRect
r(widget()->rect());
502 int x2
= r
.width()-1;
503 int y2
= r
.height()-1;
507 // Draw part of the frame that is the frame color
508 // ==============================================
509 QPalette g
= options()->palette(KDecoration::ColorFrame
, isActive());
510 g
.setCurrentColorGroup( QPalette::Active
);
511 p
.setPen( g
.background().color() );
512 p
.drawLine( x
, y
, x2
-1, y
);
513 p
.drawLine( x
, y
, x
, y2
-1 );
515 // Draw line under title bar
516 p
.drawLine( x
+borderWidth
, y
+titleHeight
+borderWidth
, x2
-borderWidth
, y
+titleHeight
+borderWidth
);
517 // Draw a hidden line that appears during shading
518 p
.drawLine( x
+borderWidth
, y2
-borderWidth
, x2
-borderWidth
, y2
-borderWidth
);
520 // Fill out the border edges
521 for (int i
= 1; i
< borderWidth
; i
++)
522 p
.drawRect( x
+i
, y
+i
, x2
-2*i
, y2
-2*i
);
524 // Draw highlights and lowlights
525 p
.setPen(g
.color( QPalette::Light
));
526 for (int i
= 1; i
<= borderWidth
/3; i
++) {
527 p
.drawLine( x
+i
, y
+i
, x2
-i
-1, y
+i
);
528 p
.drawLine( x
+i
, y
+i
, x
+i
, y2
-i
-1);
531 p
.setPen(g
.color(QPalette::Dark
).dark(135));
532 for (int i
= 1; i
<= borderWidth
/3; i
++) {
533 p
.drawLine( x2
-i
, y
+i
+1, x2
-i
, y2
-i
);
534 p
.drawLine( x
+i
+1, y2
-i
, x2
-i
, y2
-i
);
538 p
.setPen( g
.color(QPalette::Dark
).dark(155) );
539 p
.drawLine(x2
, y
, x2
, y2
);
540 p
.drawLine(x
, y2
, x2
, y2
);
542 // Draw the title bar.
543 // ===================
545 // QFontMetrics fm(options()->font(true));
547 // Obtain blend colours.
548 QColor c1
= options()->color(KDecoration::ColorTitleBar
, isActive() );
549 QColor c2
= options()->color(KDecoration::ColorTitleBlend
, isActive() );
551 QFont fnt
= options()->font(true, isToolWindow() );
552 if (isToolWindow() ) {
553 fnt
.setWeight( QFont::Normal
);
557 // Paint without a buffer if the colours are the same to
558 // improve performance, and only draw gradients on hicolor displays.
559 if ((c1
!= c2
) && hicolor
) {
560 // KS - Add gradient caching if needed at a later stage.
562 // Create a disposable pixmap buffer for the title blend
563 QPixmap
* titleBuffer
= new QPixmap
;
564 *titleBuffer
= QPixmap(w
-2*modBorderWidth
, titleHeight
);
566 if (titleBuffer
->depth() > 16) {
567 gradientFill(titleBuffer
, c1
, c2
, true);
570 QPainter
p2( titleBuffer
);
572 // Since drawing the gradient is (relatively) slow, it is best
573 // to draw the title text on the pixmap.
576 p2
.setPen( options()->color(KDecoration::ColorFont
, isActive() ));
577 p2
.drawText( r
.x(), fontoffset
, r
.width()-3, r
.height()-1,
578 Qt::AlignLeft
| Qt::AlignVCenter
, caption() );
581 p
.drawPixmap( modBorderWidth
, modBorderWidth
, *titleBuffer
);
586 // Assume lower ended hardware, so don't use buffers.
587 // Don't draw a gradient either.
588 p
.fillRect( modBorderWidth
, modBorderWidth
, w
-2*modBorderWidth
, titleHeight
, c1
);
590 // Draw the title text.
592 p
.setPen(options()->color(KDecoration::ColorFont
, isActive() ));
593 p
.drawText(r
.x()+4, r
.y()+fontoffset
-2, r
.width()-3, r
.height()-1,
594 Qt::AlignLeft
| Qt::AlignVCenter
, caption() );
599 void RedmondDecoFactory::readConfig() {
600 normalTitleHeight
= QFontMetrics(options()->font(true)).height();
601 QFont toolFont
= options()->font(true, true);
602 toolFont
.setWeight(QFont::Normal
);
603 toolTitleHeight
= QFontMetrics(toolFont
).height();
604 switch(options()->preferredBorderSize(this)) {
607 if (normalTitleHeight
< 20) normalTitleHeight
= 20;
608 if (toolTitleHeight
< 20) toolTitleHeight
= 20;
610 case BorderVeryLarge
:
612 if (normalTitleHeight
< 24) normalTitleHeight
= 24;
613 if (toolTitleHeight
< 24) toolTitleHeight
= 24;
617 if (normalTitleHeight
< 28) normalTitleHeight
= 28;
618 if (toolTitleHeight
< 28) toolTitleHeight
= 28;
622 if (normalTitleHeight
< 33) normalTitleHeight
= 33;
623 if (toolTitleHeight
< 33) toolTitleHeight
= 33;
625 case BorderOversized
:
627 if (normalTitleHeight
< 40) normalTitleHeight
= 40;
628 if (toolTitleHeight
< 40) toolTitleHeight
= 40;
634 if (normalTitleHeight
< 16) normalTitleHeight
= 16;
635 if (toolTitleHeight
< 16) toolTitleHeight
= 16;
639 RedmondDecoFactory::RedmondDecoFactory()
645 RedmondDecoFactory::~RedmondDecoFactory()
647 Redmond::delete_pixmaps();
650 KDecoration
*RedmondDecoFactory::createDecoration( KDecorationBridge
*b
)
652 return (new RedmondDeco(b
, this))->decoration();
655 bool RedmondDecoFactory::reset( unsigned long changed
)
657 // SettingButtons is handled by KCommonDecoration
658 if ( changed
& ( SettingFont
| SettingBorder
| SettingColors
| SettingButtons
) ) {
662 resetDecorations(changed
);
665 resetDecorations(changed
);
670 bool RedmondDecoFactory::supports( Ability ability
) const
675 case AbilityAnnounceButtons
:
676 case AbilityAnnounceColors
:
678 case AbilityButtonMenu
:
679 case AbilityButtonHelp
:
680 case AbilityButtonMinimize
:
681 case AbilityButtonMaximize
:
682 case AbilityButtonClose
:
683 case AbilityButtonSpacer
:
685 case AbilityColorTitleBack
:
686 case AbilityColorTitleBlend
:
687 case AbilityColorTitleFore
:
694 QList
< RedmondDecoFactory::BorderSize
> RedmondDecoFactory::borderSizes() const
695 { // the list must be sorted
696 return QList
< BorderSize
>() << BorderNormal
<< BorderLarge
<<
697 BorderVeryLarge
<< BorderHuge
<< BorderVeryHuge
<< BorderOversized
;
702 extern "C" KDE_EXPORT KDecorationFactory
*create_factory()
704 return new Redmond::RedmondDecoFactory();
708 #include "redmond.moc"
710 // kate: space-indent off; tab-width 4;