add more spacing
[personal-kdebase.git] / workspace / kwin / clients / plastik / plastik.cpp
blobff9825f879f3f8f95774b514a055b3285a147a35
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 "plastik.h"
25 #include <QBitmap>
26 #include <QPainter>
27 #include <QImage>
28 #include <QPixmap>
30 #include "plastik.moc"
31 #include "plastikclient.h"
32 #include "plastikbutton.h"
33 #include <QApplication>
34 #include <KConfig>
35 #include <KConfigGroup>
36 #include <KColorUtils>
37 #include <KColorScheme>
38 #include <KGlobalSettings>
40 namespace KWinPlastik
43 PlastikHandler::PlastikHandler()
45 memset(m_pixmaps, 0, sizeof(QPixmap*)*NumPixmaps*2*2); // set elements to 0
46 memset(m_bitmaps, 0, sizeof(QBitmap*)*NumButtonIcons*2);
48 reset(0);
51 PlastikHandler::~PlastikHandler()
53 for (int t=0; t < 2; ++t)
54 for (int a=0; a < 2; ++a)
55 for (int i=0; i < NumPixmaps; ++i)
56 delete m_pixmaps[t][a][i];
57 for (int t=0; t < 2; ++t)
58 for (int i=0; i < NumButtonIcons; ++i)
59 delete m_bitmaps[t][i];
62 bool PlastikHandler::reset(unsigned long changed)
64 // we assume the active font to be the same as the inactive font since the control
65 // center doesn't offer different settings anyways.
66 m_titleFont = KDecoration::options()->font(true, false); // not small
67 m_titleFontTool = KDecoration::options()->font(true, true); // small
69 switch(KDecoration::options()->preferredBorderSize( this )) {
70 case BorderTiny:
71 m_borderSize = 3;
72 break;
73 case BorderLarge:
74 m_borderSize = 8;
75 break;
76 case BorderVeryLarge:
77 m_borderSize = 12;
78 break;
79 case BorderHuge:
80 m_borderSize = 18;
81 break;
82 case BorderVeryHuge:
83 m_borderSize = 27;
84 break;
85 case BorderOversized:
86 m_borderSize = 40;
87 break;
88 case BorderNormal:
89 default:
90 m_borderSize = 4;
93 // check if we are in reverse layout mode
94 m_reverse = QApplication::isRightToLeft();
96 // read in the configuration
97 readConfig();
99 // pixmaps probably need to be updated, so delete the cache.
100 for (int t=0; t < 2; ++t) {
101 for (int a=0; a < 2; ++a) {
102 for (int i=0; i < NumPixmaps; i++) {
103 if (m_pixmaps[t][a][i]) {
104 delete m_pixmaps[t][a][i];
105 m_pixmaps[t][a][i] = 0;
110 for (int t=0; t < 2; ++t) {
111 for (int i=0; i < NumButtonIcons; i++) {
112 if (m_bitmaps[t][i]) {
113 delete m_bitmaps[t][i];
114 m_bitmaps[t][i] = 0;
119 // Do we need to "hit the wooden hammer" ?
120 bool needHardReset = true;
121 // TODO: besides the Color and Font settings I can maybe handle more changes
122 // without a hard reset. I will do this later...
123 if ((changed & ~(SettingColors | SettingFont | SettingButtons)) == 0 )
125 needHardReset = false;
128 if (needHardReset) {
129 return true;
130 } else {
131 resetDecorations(changed);
132 return false;
136 KDecoration* PlastikHandler::createDecoration( KDecorationBridge* bridge )
138 return ( new PlastikClient( bridge, this ))->decoration();
141 bool PlastikHandler::supports( Ability ability ) const
143 switch( ability )
145 // announce
146 case AbilityAnnounceButtons:
147 case AbilityAnnounceColors:
148 // buttons
149 case AbilityButtonMenu:
150 case AbilityButtonOnAllDesktops:
151 case AbilityButtonSpacer:
152 case AbilityButtonHelp:
153 case AbilityButtonMinimize:
154 case AbilityButtonMaximize:
155 case AbilityButtonClose:
156 case AbilityButtonAboveOthers:
157 case AbilityButtonBelowOthers:
158 case AbilityButtonShade:
159 // colors
160 case AbilityColorTitleBack:
161 case AbilityColorTitleFore:
162 case AbilityColorFrame:
163 return true;
164 default:
165 return false;
169 void PlastikHandler::readConfig()
171 // create a config object
172 KConfig configFile("kwinplastikrc");
173 const KConfigGroup config( &configFile, "General");
175 // grab settings
176 m_titleShadow = config.readEntry("TitleShadow", true);
178 QFontMetrics fm(m_titleFont); // active font = inactive font
179 int titleHeightMin = config.readEntry("MinTitleHeight", 16);
180 // The title should stretch with bigger font sizes!
181 m_titleHeight = qMax(titleHeightMin, fm.height() + 4); // 4 px for the shadow etc.
182 // have an even title/button size so the button icons are fully centered...
183 if ( m_titleHeight%2 == 0)
184 m_titleHeight++;
186 fm = QFontMetrics(m_titleFontTool); // active font = inactive font
187 int titleHeightToolMin = config.readEntry("MinTitleHeightTool", 13);
188 // The title should stretch with bigger font sizes!
189 m_titleHeightTool = qMax(titleHeightToolMin, fm.height() ); // don't care about the shadow etc.
190 // have an even title/button size so the button icons are fully centered...
191 if ( m_titleHeightTool%2 == 0)
192 m_titleHeightTool++;
194 QString value = config.readEntry("TitleAlignment", "AlignLeft");
195 if (value == "AlignLeft") m_titleAlign = Qt::AlignLeft;
196 else if (value == "AlignHCenter") m_titleAlign = Qt::AlignHCenter;
197 else if (value == "AlignRight") m_titleAlign = Qt::AlignRight;
199 m_coloredBorder = config.readEntry("ColoredBorder", true);
200 m_animateButtons = config.readEntry("AnimateButtons", true);
201 m_menuClose = config.readEntry("CloseOnMenuDoubleClick", true);
204 QColor PlastikHandler::getColor(KWinPlastik::ColorType type, const bool active)
206 double c = KGlobalSettings::contrastF();
207 switch (type) {
208 case WindowContour:
209 return KColorScheme::shade(KDecoration::options()->color(ColorTitleBar, active), KColorScheme::DarkShade, c);
210 case TitleGradient1:
211 return KColorScheme::shade(KDecoration::options()->color(ColorTitleBar, active), KColorScheme::MidlightShade, c-0.4);
212 break;
213 case TitleGradient2:
214 return KColorScheme::shade(KDecoration::options()->color(ColorTitleBar, active), KColorScheme::MidShade, c-0.4);
215 break;
216 case TitleGradient3:
217 return KDecoration::options()->color(ColorTitleBar, active);
218 break;
219 case ShadeTitleLight:
220 return KColorScheme::shade(KDecoration::options()->color(ColorTitleBar, active), KColorScheme::LightShade, active?c-0.4:c-0.8);
221 break;
222 case ShadeTitleDark:
223 return KColorScheme::shade(KDecoration::options()->color(ColorTitleBar, active), KColorScheme::DarkShade, active?c-0.4:c-0.8);
224 break;
225 case Border:
226 return KDecoration::options()->color(ColorFrame, active);
227 case TitleFont:
228 return KDecoration::options()->color(ColorFont, active);
229 default:
230 return Qt::black;
234 const QPixmap &PlastikHandler::pixmap(Pixmaps type, bool active, bool toolWindow)
236 if (m_pixmaps[toolWindow][active][type])
237 return *m_pixmaps[toolWindow][active][type];
239 QPixmap *pm = 0;
241 switch (type) {
242 case TitleBarTileTop:
243 case TitleBarTile:
245 const int titleBarTileHeight = (toolWindow ? m_titleHeightTool : m_titleHeight)+2;
246 // gradient used as well in TitleBarTileTop as TitleBarTile
247 const int gradientHeight = 2 + titleBarTileHeight-1;
248 QPixmap gradient(1, gradientHeight);
249 QPainter painter(&gradient);
250 painter.setPen(Qt::NoPen);
251 QLinearGradient grad(0, 0, 0, gradientHeight);
252 grad.setColorAt(0.0, getColor(TitleGradient1, active));
253 grad.setColorAt(4.0 / (double)gradientHeight, getColor(TitleGradient2, active));
254 grad.setColorAt(1.0, getColor(TitleGradient3, active));
255 painter.setBrush(grad);
256 painter.drawRect(0, 0, 1, gradientHeight);
257 painter.end();
259 // actual titlebar tiles
260 if (type == TitleBarTileTop) {
261 pm = new QPixmap(1, 4);
262 painter.begin(pm);
263 // contour
264 painter.setPen(getColor(WindowContour, active) );
265 painter.drawPoint(0,0);
266 // top highlight
267 painter.setPen(getColor(ShadeTitleLight, active) );
268 painter.drawPoint(0,1);
269 // gradient
270 painter.drawPixmap(0, 2, gradient);
271 painter.end();
272 } else {
273 pm = new QPixmap(1, titleBarTileHeight);
274 painter.begin(pm);
275 painter.drawPixmap(0, 0, gradient, 0,2 ,-1,-1);
276 if (m_coloredBorder) {
277 painter.setPen(KColorScheme::shade(getColor(TitleGradient3, active), KColorScheme::MidShade) );
278 } else {
279 painter.setPen(getColor(TitleGradient3, active) );
281 painter.drawPoint(0,titleBarTileHeight-1);
282 painter.end();
285 break;
288 case TitleBarLeft:
290 const int w = m_borderSize;
291 const int h = 4 + (toolWindow ? m_titleHeightTool : m_titleHeight) + 2;
293 pm = new QPixmap(w, h);
294 QPainter painter(pm);
296 painter.drawTiledPixmap(0,0, w, 4, pixmap(TitleBarTileTop, active, toolWindow) );
297 painter.drawTiledPixmap(0,4, w, h-4, pixmap(TitleBarTile, active, toolWindow) );
299 painter.setPen(getColor(WindowContour, active) );
300 painter.drawLine(0,0, 0,h);
301 painter.drawPoint(1,1);
303 const QColor highlightTitleLeft = getColor(ShadeTitleLight, active);
304 painter.setPen(highlightTitleLeft);
305 painter.drawLine(1,2, 1,h);
307 if (m_coloredBorder) {
308 painter.setPen(getColor(TitleGradient3, active) );
309 painter.drawLine(2,h-1, w-1,h-1);
312 // outside the region normally masked by doShape
313 painter.setPen(QColor(0,0,0) );
314 painter.drawLine(0, 0, 1, 0 );
315 painter.drawPoint(0, 1);
317 break;
320 case TitleBarRight:
322 const int w = m_borderSize;
323 const int h = 4 + (toolWindow ? m_titleHeightTool : m_titleHeight) + 2;
325 pm = new QPixmap(w, h);
326 QPainter painter(pm);
328 painter.drawTiledPixmap(0,0, w, 4, pixmap(TitleBarTileTop, active, toolWindow) );
329 painter.drawTiledPixmap(0,4, w, h-4, pixmap(TitleBarTile, active, toolWindow) );
331 painter.setPen(getColor(WindowContour, active) );
332 painter.drawLine(w-1,0, w-1,h);
333 painter.drawPoint(w-2,1);
335 const QColor highlightTitleRight = getColor(ShadeTitleDark, active);
336 painter.setPen(highlightTitleRight);
337 painter.drawLine(w-2,2, w-2,h);
339 if (m_coloredBorder) {
340 painter.setPen(getColor(TitleGradient3, active) );
341 painter.drawLine(0,h-1, w-3,h-1);
344 // outside the region normally masked by doShape
345 painter.setPen(QColor(0,0,0) );
346 painter.drawLine(w-2, 0, w-1, 0 );
347 painter.drawPoint(w-1, 1);
349 break;
352 case BorderLeftTile:
354 const int w = m_borderSize;
356 pm = new QPixmap(w, 1);
357 QPainter painter(pm);
358 if (m_coloredBorder) {
359 painter.setPen(getColor(WindowContour, active) );
360 painter.drawPoint(0, 0);
361 painter.setPen(getColor(ShadeTitleLight, active) );
362 painter.drawPoint(1, 0);
363 if (w > 3) {
364 painter.setPen(getColor(TitleGradient3, active) );
365 painter.drawLine(2,0, w-2,0);
367 painter.setPen(KColorScheme::shade(getColor(TitleGradient3, active), KColorScheme::MidShade) );
368 painter.drawPoint(w-1,0);
369 } else {
370 painter.setPen(getColor(WindowContour, active) );
371 painter.drawPoint(0, 0);
372 painter.setPen(KColorUtils::mix(getColor(Border, active), getColor(ShadeTitleLight, active) ) );
373 painter.drawPoint(1, 0);
374 painter.setPen(getColor(Border, active) );
375 painter.drawLine(2,0, w-1,0);
378 painter.end();
380 break;
383 case BorderRightTile:
385 const int w = m_borderSize;
387 pm = new QPixmap(w, 1);
388 QPainter painter(pm);
389 if (m_coloredBorder) {
390 painter.setPen(KColorScheme::shade(getColor(TitleGradient3, active), KColorScheme::MidShade) );
391 painter.drawPoint(0,0);
392 if (w > 3) {
393 painter.setPen(getColor(TitleGradient3, active) );
394 painter.drawLine(1,0, w-3,0);
396 painter.setPen(getColor(ShadeTitleDark, active) );
397 painter.drawPoint(w-2, 0);
398 painter.setPen(getColor(WindowContour, active) );
399 painter.drawPoint(w-1, 0);
400 } else {
401 painter.setPen(getColor(Border, active) );
402 painter.drawLine(0,0, w-3,0);
403 painter.setPen(KColorUtils::mix(getColor(Border, active), getColor(ShadeTitleDark, active) ) );
404 painter.drawPoint(w-2, 0);
405 painter.setPen(getColor(WindowContour, active) );
406 painter.drawPoint(w-1, 0);
408 painter.end();
410 break;
413 case BorderBottomLeft:
415 const int w = m_borderSize;
416 const int h = m_borderSize;
418 pm = new QPixmap(w, h);
419 QPainter painter(pm);
420 painter.drawTiledPixmap(0,0,w,h, pixmap(BorderBottomTile, active, toolWindow) );
421 painter.setPen(getColor(WindowContour, active) );
422 painter.drawLine(0,0, 0,h);
423 if (m_coloredBorder) {
424 if (h > 3) {
425 painter.setPen(getColor(ShadeTitleLight, active) );
426 painter.drawLine(1,0, 1,h-2);
429 painter.setPen(getColor(TitleGradient3, active) );
430 painter.drawLine(2,0, w-1,0);
431 } else {
432 painter.setPen(KColorUtils::mix(getColor(Border, active), getColor(ShadeTitleLight, active) ) );
433 painter.drawLine(1,0, 1,h-2);
436 painter.end();
438 break;
441 case BorderBottomRight:
443 const int w = m_borderSize;
444 const int h = m_borderSize;
446 pm = new QPixmap(w, h);
447 QPainter painter(pm);
448 painter.drawTiledPixmap(0,0,w,h, pixmap(BorderBottomTile, active, toolWindow) );
449 painter.setPen(getColor(WindowContour, active) );
450 painter.drawLine(w-1,0, w-1,h);
451 if (m_coloredBorder) {
452 painter.setPen(getColor(ShadeTitleDark, active) );
453 painter.drawLine(w-2,0, w-2,h-2);
455 painter.setPen(getColor(TitleGradient3, active) );
456 painter.drawLine(0,0, w-3,0);
457 } else {
458 painter.setPen(KColorUtils::mix(getColor(Border, active), getColor(ShadeTitleDark, active) ) );
459 painter.drawLine(w-2,0, w-2,h-2);
462 painter.end();
464 break;
467 case BorderBottomTile:
468 default:
470 const int h = m_borderSize;
472 pm = new QPixmap(1, m_borderSize);
473 QPainter painter(pm);
475 if (m_coloredBorder) {
476 painter.setPen(KColorScheme::shade(getColor(TitleGradient3, active), KColorScheme::MidShade) );
477 painter.drawPoint(0,0);
478 painter.setPen(getColor(TitleGradient3, active) );
479 painter.drawLine(0,1, 0,h-3);
480 painter.setPen(getColor(ShadeTitleDark, active) );
481 painter.drawPoint(0, h-2);
482 } else {
483 painter.setPen(getColor(Border, active) );
484 painter.drawLine(0,0, 0,h-3);
485 painter.setPen(KColorUtils::mix(getColor(Border, active), getColor(ShadeTitleDark, active) ) );
486 painter.drawPoint(0, h-2);
488 painter.setPen(getColor(WindowContour, active) );
489 painter.drawPoint(0, h-1);
490 painter.end();
492 break;
496 m_pixmaps[toolWindow][active][type] = pm;
497 return *pm;
500 const QBitmap &PlastikHandler::buttonBitmap(ButtonIcon type, const QSize &size, bool toolWindow)
502 int typeIndex = type;
504 // btn icon size...
505 int reduceW = 0, reduceH = 0;
506 if(size.width()>14) {
507 reduceW = static_cast<int>(2*(size.width()/3.5) );
509 else
510 reduceW = 6;
511 if(size.height()>14)
512 reduceH = static_cast<int>(2*(size.height()/3.5) );
513 else
514 reduceH = 6;
516 int w = size.width() - reduceW;
517 int h = size.height() - reduceH;
519 if (m_bitmaps[toolWindow][typeIndex] && m_bitmaps[toolWindow][typeIndex]->size()==QSize(w,h) )
520 return *m_bitmaps[toolWindow][typeIndex];
522 // no matching pixmap found, create a new one...
524 delete m_bitmaps[toolWindow][typeIndex];
525 m_bitmaps[toolWindow][typeIndex] = 0;
527 QBitmap bmp = IconEngine::icon(type /*icon*/, qMin(w,h) );
528 QBitmap *bitmap = new QBitmap(bmp);
529 m_bitmaps[toolWindow][typeIndex] = bitmap;
530 return *bitmap;
533 QList< PlastikHandler::BorderSize >
534 PlastikHandler::borderSizes() const
536 // the list must be sorted
537 return QList< BorderSize >() << BorderTiny << BorderNormal <<
538 BorderLarge << BorderVeryLarge << BorderHuge <<
539 BorderVeryHuge << BorderOversized;
542 // make the handler accessible to other classes...
543 static PlastikHandler *handler = 0;
544 PlastikHandler* Handler()
546 return handler;
549 } // KWinPlastik
551 //////////////////////////////////////////////////////////////////////////////
552 // Plugin Stuff //
553 //////////////////////////////////////////////////////////////////////////////
555 extern "C"
557 KDE_EXPORT KDecorationFactory *create_factory()
559 KWinPlastik::handler = new KWinPlastik::PlastikHandler();
560 return KWinPlastik::handler;