add more spacing
[personal-kdebase.git] / workspace / kwin / clients / plastik / plastikclient.cpp
blob525fae9978d236e078ab2694e07c379e89f4de11
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 "plastikclient.h"
24 #include <klocale.h>
26 #include <QBitmap>
27 #include <QDateTime>
28 #include <QFontMetrics>
29 #include <QImage>
30 #include <QLabel>
31 #include <QLayout>
32 #include <QPainter>
33 #include <QPixmap>
34 #include <QDesktopWidget>
36 #include "plastikbutton.h"
38 #include <KColorScheme>
40 QColor alphaColor(QColor color, double alpha)
42 if (alpha >= 1.0)
43 return color;
44 color.setAlphaF(qMax(0.0, alpha) * color.alphaF());
45 return color;
48 namespace KWinPlastik
51 PlastikClient::PlastikClient(KDecorationBridge* bridge, KDecorationFactory* factory)
52 : KCommonDecoration (bridge, factory),
53 s_titleFont(QFont() )
55 memset(m_captionPixmaps, 0, sizeof(QPixmap*)*2);
58 PlastikClient::~PlastikClient()
60 clearCaptionPixmaps();
63 QString PlastikClient::visibleName() const
65 return i18n("Plastik");
68 bool PlastikClient::decorationBehaviour(DecorationBehaviour behaviour) const
70 switch (behaviour) {
71 case DB_MenuClose:
72 return Handler()->menuClose();
74 case DB_WindowMask:
75 return true;
77 default:
78 return KCommonDecoration::decorationBehaviour(behaviour);
82 int PlastikClient::layoutMetric(LayoutMetric lm, bool respectWindowState, const KCommonDecorationButton *btn) const
84 bool maximized = maximizeMode()==MaximizeFull && !options()->moveResizeMaximizedWindows();
86 switch (lm) {
87 case LM_BorderLeft:
88 case LM_BorderRight:
89 case LM_BorderBottom:
91 if (respectWindowState && maximized) {
92 return 0;
93 } else {
94 return Handler()->borderSize();
98 case LM_TitleEdgeTop:
100 if (respectWindowState && maximized) {
101 return 0;
102 } else {
103 return 4;
107 case LM_TitleEdgeBottom:
109 // if (respectWindowState && maximized) {
110 // return 1;
111 // } else {
112 return 2;
113 // }
116 case LM_TitleEdgeLeft:
117 case LM_TitleEdgeRight:
119 if (respectWindowState && maximized) {
120 return 0;
121 } else {
122 return 6;
126 case LM_TitleBorderLeft:
127 case LM_TitleBorderRight:
128 return 5;
130 case LM_ButtonWidth:
131 case LM_ButtonHeight:
132 case LM_TitleHeight:
134 if (respectWindowState && isToolWindow()) {
135 return Handler()->titleHeightTool();
136 } else {
137 return Handler()->titleHeight();
141 case LM_ButtonSpacing:
142 return 1;
144 case LM_ButtonMarginTop:
145 return 0;
147 default:
148 return KCommonDecoration::layoutMetric(lm, respectWindowState, btn);
152 KCommonDecorationButton *PlastikClient::createButton(ButtonType type)
154 switch (type) {
155 case MenuButton:
156 return new PlastikButton(MenuButton, this);
158 case OnAllDesktopsButton:
159 return new PlastikButton(OnAllDesktopsButton, this);
161 case HelpButton:
162 return new PlastikButton(HelpButton, this);
164 case MinButton:
165 return new PlastikButton(MinButton, this);
167 case MaxButton:
168 return new PlastikButton(MaxButton, this);
170 case CloseButton:
171 return new PlastikButton(CloseButton, this);
173 case AboveButton:
174 return new PlastikButton(AboveButton, this);
176 case BelowButton:
177 return new PlastikButton(BelowButton, this);
179 case ShadeButton:
180 return new PlastikButton(ShadeButton, this);
182 default:
183 return 0;
187 void PlastikClient::init()
189 s_titleFont = isToolWindow() ? Handler()->titleFontTool() : Handler()->titleFont();
191 clearCaptionPixmaps();
193 KCommonDecoration::init();
196 QRegion PlastikClient::cornerShape(WindowCorner corner)
198 int w = widget()->width();
199 int h = widget()->height();
201 switch (corner) {
202 case WC_TopLeft:
203 if (layoutMetric(LM_TitleEdgeLeft) > 0)
204 return QRegion(0, 0, 1, 2) + QRegion(1, 0, 1, 1);
205 else
206 return QRegion();
208 case WC_TopRight:
209 if (layoutMetric(LM_TitleEdgeRight) > 0)
210 return QRegion(w-1, 0, 1, 2) + QRegion(w-2, 0, 1, 1);
211 else
212 return QRegion();
214 case WC_BottomLeft:
215 if (layoutMetric(LM_BorderBottom) > 0)
216 return QRegion(0, h-1, 1, 1);
217 else
218 return QRegion();
220 case WC_BottomRight:
221 if (layoutMetric(LM_BorderBottom) > 0)
222 return QRegion(w-1, h-1, 1, 1);
223 else
224 return QRegion();
226 default:
227 return QRegion();
232 void PlastikClient::paintEvent(QPaintEvent *e)
234 QRegion region = e->region();
236 PlastikHandler *handler = Handler();
238 if (oldCaption != caption() )
239 clearCaptionPixmaps();
241 bool active = isActive();
242 bool toolWindow = isToolWindow();
244 QPainter painter(widget() );
246 // often needed coordinates
247 QRect r = widget()->rect();
249 int r_w = r.width();
250 // int r_h = r.height();
251 int r_x, r_y, r_x2, r_y2;
252 r.getCoords(&r_x, &r_y, &r_x2, &r_y2);
253 const int borderLeft = layoutMetric(LM_BorderLeft);
254 const int borderRight = layoutMetric(LM_BorderRight);
255 const int borderBottom = layoutMetric(LM_BorderBottom);
256 const int titleHeight = layoutMetric(LM_TitleHeight);
257 const int titleEdgeTop = layoutMetric(LM_TitleEdgeTop);
258 const int titleEdgeBottom = layoutMetric(LM_TitleEdgeBottom);
259 const int titleEdgeLeft = layoutMetric(LM_TitleEdgeLeft);
260 const int titleEdgeRight = layoutMetric(LM_TitleEdgeRight);
262 const int borderBottomTop = r_y2-borderBottom+1;
263 const int borderLeftRight = r_x+borderLeft-1;
264 const int borderRightLeft = r_x2-borderRight+1;
265 const int titleEdgeBottomBottom = r_y+titleEdgeTop+titleHeight+titleEdgeBottom-1;
267 const int sideHeight = borderBottomTop-titleEdgeBottomBottom-1;
269 QRect Rtitle = QRect(r_x+titleEdgeLeft+buttonsLeftWidth(), r_y+titleEdgeTop,
270 r_x2-titleEdgeRight-buttonsRightWidth()-(r_x+titleEdgeLeft+buttonsLeftWidth()),
271 titleEdgeBottomBottom-(r_y+titleEdgeTop) );
273 QRect tempRect;
275 // topSpacer
276 if(titleEdgeTop > 0)
278 tempRect.setRect(r_x+2, r_y, r_w-2*2, titleEdgeTop );
279 if (tempRect.isValid() && region.contains(tempRect) ) {
280 painter.drawTiledPixmap(tempRect, handler->pixmap(TitleBarTileTop, active, toolWindow) );
284 // leftTitleSpacer
285 int titleMarginLeft = 0;
286 int titleMarginRight = 0;
287 if(titleEdgeLeft > 0)
289 tempRect.setRect(r_x, r_y, borderLeft, titleEdgeTop+titleHeight+titleEdgeBottom);
290 if (tempRect.isValid() && region.contains(tempRect) ) {
291 painter.drawTiledPixmap(tempRect, handler->pixmap(TitleBarLeft, active, toolWindow) );
292 titleMarginLeft = borderLeft;
296 // rightTitleSpacer
297 if(titleEdgeRight > 0)
299 tempRect.setRect(borderRightLeft, r_y, borderRight, titleEdgeTop+titleHeight+titleEdgeBottom);
300 if (tempRect.isValid() && region.contains(tempRect) ) {
301 painter.drawTiledPixmap(tempRect, handler->pixmap(TitleBarRight, active, toolWindow) );
302 titleMarginRight = borderRight;
306 // titleSpacer
307 const QPixmap &caption = captionPixmap();
308 if(Rtitle.width() > 0)
310 m_captionRect = captionRect(); // also update m_captionRect!
311 if (m_captionRect.isValid() && region.contains(m_captionRect) )
313 painter.drawTiledPixmap(m_captionRect, caption);
316 // left to the title
317 tempRect.setRect(r_x+titleMarginLeft, m_captionRect.top(),
318 m_captionRect.left() - (r_x+titleMarginLeft), m_captionRect.height() );
319 if (tempRect.isValid() && region.contains(tempRect) ) {
320 painter.drawTiledPixmap(tempRect, handler->pixmap(TitleBarTile, active, toolWindow) );
323 // right to the title
324 tempRect.setRect(m_captionRect.right()+1, m_captionRect.top(),
325 (r_x2-titleMarginRight) - m_captionRect.right(), m_captionRect.height() );
326 if (tempRect.isValid() && region.contains(tempRect) ) {
327 painter.drawTiledPixmap(tempRect, handler->pixmap(TitleBarTile, active, toolWindow) );
332 // leftSpacer
333 if(borderLeft > 0 && sideHeight > 0)
335 tempRect.setCoords(r_x, titleEdgeBottomBottom+1, borderLeftRight, borderBottomTop-1);
336 if (tempRect.isValid() && region.contains(tempRect) ) {
337 painter.drawTiledPixmap(tempRect, handler->pixmap(BorderLeftTile, active, toolWindow) );
341 // rightSpacer
342 if(borderRight > 0 && sideHeight > 0)
344 tempRect.setCoords(borderRightLeft, titleEdgeBottomBottom+1, r_x2, borderBottomTop-1);
345 if (tempRect.isValid() && region.contains(tempRect) ) {
346 painter.drawTiledPixmap(tempRect, handler->pixmap(BorderRightTile, active, toolWindow) );
350 // bottomSpacer
351 if(borderBottom > 0)
353 int l = r_x;
354 int r = r_x2;
356 tempRect.setRect(r_x, borderBottomTop, borderLeft, borderBottom);
357 if (tempRect.isValid() && region.contains(tempRect) ) {
358 painter.drawTiledPixmap(tempRect, handler->pixmap(BorderBottomLeft, active, toolWindow) );
359 l = tempRect.right()+1;
362 tempRect.setRect(borderRightLeft, borderBottomTop, borderLeft, borderBottom);
363 if (tempRect.isValid() && region.contains(tempRect) ) {
364 painter.drawTiledPixmap(tempRect, handler->pixmap(BorderBottomRight, active, toolWindow) );
365 r = tempRect.left()-1;
368 tempRect.setCoords(l, borderBottomTop, r, r_y2);
369 if (tempRect.isValid() && region.contains(tempRect) ) {
370 painter.drawTiledPixmap(tempRect, handler->pixmap(BorderBottomTile, active, toolWindow) );
375 QRect PlastikClient::captionRect() const
377 const QPixmap &caption = captionPixmap();
378 QRect r = widget()->rect();
380 const int titleHeight = layoutMetric(LM_TitleHeight);
381 const int titleEdgeBottom = layoutMetric(LM_TitleEdgeBottom);
382 const int titleEdgeTop = layoutMetric(LM_TitleEdgeTop);
383 const int titleEdgeLeft = layoutMetric(LM_TitleEdgeLeft);
384 const int marginLeft = layoutMetric(LM_TitleBorderLeft);
385 const int marginRight = layoutMetric(LM_TitleBorderRight);
387 const int titleLeft = r.left() + titleEdgeLeft + buttonsLeftWidth() + marginLeft;
388 const int titleWidth = r.width() -
389 titleEdgeLeft - layoutMetric(LM_TitleEdgeRight) -
390 buttonsLeftWidth() - buttonsRightWidth() -
391 marginLeft - marginRight;
393 Qt::AlignmentFlag a = Handler()->titleAlign();
395 int tX, tW; // position/width of the title buffer
396 if (caption.width() > titleWidth) {
397 tW = titleWidth;
398 } else {
399 tW = caption.width();
401 if (a == Qt::AlignLeft || (caption.width() > titleWidth) ) {
402 // Align left
403 tX = titleLeft;
404 } else if (a == Qt::AlignHCenter) {
405 // Align center
406 tX = titleLeft+(titleWidth- caption.width() )/2;
407 } else {
408 // Align right
409 tX = titleLeft+titleWidth-caption.width();
412 return QRect(tX, r.top()+titleEdgeTop, tW, titleHeight+titleEdgeBottom);
415 void PlastikClient::updateCaption()
417 QRect oldCaptionRect = m_captionRect;
419 if (oldCaption != caption() )
420 clearCaptionPixmaps();
422 m_captionRect = PlastikClient::captionRect();
424 if (oldCaptionRect.isValid() && m_captionRect.isValid() )
425 widget()->update(oldCaptionRect|m_captionRect);
426 else
427 widget()->update();
430 void PlastikClient::reset( unsigned long changed )
432 if (changed & SettingColors)
434 // repaint the whole thing
435 clearCaptionPixmaps();
436 widget()->update();
437 updateButtons();
438 } else if (changed & SettingFont) {
439 // font has changed -- update title height and font
440 s_titleFont = isToolWindow() ? Handler()->titleFontTool() : Handler()->titleFont();
442 updateLayout();
444 // then repaint
445 clearCaptionPixmaps();
446 widget()->update();
449 KCommonDecoration::reset(changed);
452 const QPixmap &PlastikClient::getTitleBarTile(bool active) const
454 return Handler()->pixmap(TitleBarTile, active, isToolWindow() );
457 const QPixmap &PlastikClient::captionPixmap() const
459 bool active = isActive();
461 if (m_captionPixmaps[active]) {
462 return *m_captionPixmaps[active];
465 // not found, create new pixmap...
467 const int maxCaptionLength = 300; // truncate captions longer than this!
468 QString c(caption() );
469 if (c.length() > maxCaptionLength) {
470 c.truncate(maxCaptionLength);
471 c.append(" [...]");
474 QFontMetrics fm(s_titleFont);
475 int captionWidth = fm.width(c);
476 int captionHeight = fm.height();
478 const int th = layoutMetric(LM_TitleHeight, false) + layoutMetric(LM_TitleEdgeBottom, false);
480 QPainter painter;
482 const int thickness = 2;
484 QPixmap *captionPixmap = new QPixmap(captionWidth+2*thickness, th);
486 painter.begin(captionPixmap);
487 painter.drawTiledPixmap(captionPixmap->rect(),
488 Handler()->pixmap(TitleBarTile, active, isToolWindow()) );
490 painter.setFont(s_titleFont);
491 QPoint tp(1, captionHeight - 3);
492 QColor fontColor = Handler()->getColor(TitleFont,active);
493 if(Handler()->titleShadow())
495 QColor shadowColor = KColorScheme::shade(fontColor, KColorScheme::ShadowShade);
497 painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
498 painter.setPen(alphaColor(shadowColor, 0.3) );
499 painter.drawText(tp+QPoint(1,2), c);
500 painter.setPen(alphaColor(shadowColor, 0.2) );
501 painter.drawText(tp+QPoint(2,2), c);
502 painter.setPen(alphaColor(shadowColor, 0.5) );
503 painter.drawText(tp+QPoint(1,1), c);
505 painter.setPen(fontColor );
506 painter.drawText(tp, c );
507 painter.end();
509 m_captionPixmaps[active] = captionPixmap;
510 return *captionPixmap;
513 void PlastikClient::clearCaptionPixmaps()
515 for (int i = 0; i < 2; ++i) {
516 delete m_captionPixmaps[i];
517 m_captionPixmaps[i] = 0;
520 oldCaption = caption();
523 } // KWinPlastik