You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
529 lines
15 KiB
529 lines
15 KiB
/* Plastik KWin window decoration |
|
Copyright (C) 2003-2005 Sandro Giessl <sandro@giessl.com> |
|
|
|
based on the window decoration "Web": |
|
Copyright (C) 2001 Rik Hemsley (rikkus) <rik@kde.org> |
|
|
|
This program is free software; you can redistribute it and/or |
|
modify it under the terms of the GNU General Public |
|
License as published by the Free Software Foundation; either |
|
version 2 of the License, or (at your option) any later version. |
|
|
|
This program is distributed in the hope that it will be useful, |
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
General Public License for more details. |
|
|
|
You should have received a copy of the GNU General Public License |
|
along with this program; see the file COPYING. If not, write to |
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
|
Boston, MA 02110-1301, USA. |
|
*/ |
|
|
|
#include "plastikclient.h" |
|
#include <klocale.h> |
|
|
|
#include <QBitmap> |
|
#include <QDateTime> |
|
#include <QFontMetrics> |
|
#include <QImage> |
|
#include <QLabel> |
|
#include <QLayout> |
|
#include <QPainter> |
|
#include <QPixmap> |
|
#include <QDesktopWidget> |
|
|
|
#include "plastikbutton.h" |
|
|
|
#include <KColorScheme> |
|
|
|
QColor alphaColor(QColor color, double alpha) |
|
{ |
|
if (alpha >= 1.0) |
|
return color; |
|
color.setAlphaF(qMax(0.0, alpha) * color.alphaF()); |
|
return color; |
|
} |
|
|
|
namespace KWinPlastik |
|
{ |
|
|
|
PlastikClient::PlastikClient(KDecorationBridge* bridge, KDecorationFactory* factory) |
|
: KCommonDecoration (bridge, factory), |
|
s_titleFont(QFont() ) |
|
{ |
|
memset(m_captionPixmaps, 0, sizeof(QPixmap*)*2); |
|
} |
|
|
|
PlastikClient::~PlastikClient() |
|
{ |
|
clearCaptionPixmaps(); |
|
} |
|
|
|
QString PlastikClient::visibleName() const |
|
{ |
|
return i18n("Plastik"); |
|
} |
|
|
|
bool PlastikClient::decorationBehaviour(DecorationBehaviour behaviour) const |
|
{ |
|
switch (behaviour) { |
|
case DB_MenuClose: |
|
return Handler()->menuClose(); |
|
|
|
case DB_WindowMask: |
|
return true; |
|
|
|
default: |
|
return KCommonDecoration::decorationBehaviour(behaviour); |
|
} |
|
} |
|
|
|
int PlastikClient::layoutMetric(LayoutMetric lm, bool respectWindowState, const KCommonDecorationButton *btn) const |
|
{ |
|
bool maximized = maximizeMode()==MaximizeFull && !options()->moveResizeMaximizedWindows(); |
|
|
|
switch (lm) { |
|
case LM_BorderLeft: |
|
case LM_BorderRight: |
|
case LM_BorderBottom: |
|
{ |
|
if (respectWindowState && maximized) { |
|
return 0; |
|
} else { |
|
return Handler()->borderSize(); |
|
} |
|
} |
|
|
|
case LM_TitleEdgeTop: |
|
{ |
|
if (respectWindowState && maximized) { |
|
return 0; |
|
} else { |
|
return 4; |
|
} |
|
} |
|
|
|
case LM_TitleEdgeBottom: |
|
{ |
|
// if (respectWindowState && maximized) { |
|
// return 1; |
|
// } else { |
|
return 2; |
|
// } |
|
} |
|
|
|
case LM_TitleEdgeLeft: |
|
case LM_TitleEdgeRight: |
|
{ |
|
if (respectWindowState && maximized) { |
|
return 0; |
|
} else { |
|
return 6; |
|
} |
|
} |
|
|
|
case LM_TitleBorderLeft: |
|
case LM_TitleBorderRight: |
|
return 5; |
|
|
|
case LM_ButtonWidth: |
|
case LM_ButtonHeight: |
|
case LM_TitleHeight: |
|
{ |
|
if (respectWindowState && isToolWindow()) { |
|
return Handler()->titleHeightTool(); |
|
} else { |
|
return Handler()->titleHeight(); |
|
} |
|
} |
|
|
|
case LM_ButtonSpacing: |
|
return 1; |
|
|
|
case LM_ButtonMarginTop: |
|
return 0; |
|
|
|
default: |
|
return KCommonDecoration::layoutMetric(lm, respectWindowState, btn); |
|
} |
|
} |
|
|
|
KCommonDecorationButton *PlastikClient::createButton(ButtonType type) |
|
{ |
|
switch (type) { |
|
case MenuButton: |
|
return new PlastikButton(MenuButton, this); |
|
|
|
case OnAllDesktopsButton: |
|
return new PlastikButton(OnAllDesktopsButton, this); |
|
|
|
case HelpButton: |
|
return new PlastikButton(HelpButton, this); |
|
|
|
case MinButton: |
|
return new PlastikButton(MinButton, this); |
|
|
|
case MaxButton: |
|
return new PlastikButton(MaxButton, this); |
|
|
|
case CloseButton: |
|
return new PlastikButton(CloseButton, this); |
|
|
|
case AboveButton: |
|
return new PlastikButton(AboveButton, this); |
|
|
|
case BelowButton: |
|
return new PlastikButton(BelowButton, this); |
|
|
|
case ShadeButton: |
|
return new PlastikButton(ShadeButton, this); |
|
|
|
default: |
|
return 0; |
|
} |
|
} |
|
|
|
void PlastikClient::init() |
|
{ |
|
s_titleFont = isToolWindow() ? Handler()->titleFontTool() : Handler()->titleFont(); |
|
|
|
clearCaptionPixmaps(); |
|
|
|
KCommonDecoration::init(); |
|
} |
|
|
|
QRegion PlastikClient::cornerShape(WindowCorner corner) |
|
{ |
|
int w = widget()->width(); |
|
int h = widget()->height(); |
|
|
|
switch (corner) { |
|
case WC_TopLeft: |
|
if (layoutMetric(LM_TitleEdgeLeft) > 0) |
|
return QRegion(0, 0, 1, 2) + QRegion(1, 0, 1, 1); |
|
else |
|
return QRegion(); |
|
|
|
case WC_TopRight: |
|
if (layoutMetric(LM_TitleEdgeRight) > 0) |
|
return QRegion(w-1, 0, 1, 2) + QRegion(w-2, 0, 1, 1); |
|
else |
|
return QRegion(); |
|
|
|
case WC_BottomLeft: |
|
if (layoutMetric(LM_BorderBottom) > 0) |
|
return QRegion(0, h-1, 1, 1); |
|
else |
|
return QRegion(); |
|
|
|
case WC_BottomRight: |
|
if (layoutMetric(LM_BorderBottom) > 0) |
|
return QRegion(w-1, h-1, 1, 1); |
|
else |
|
return QRegion(); |
|
|
|
default: |
|
return QRegion(); |
|
} |
|
|
|
} |
|
|
|
void PlastikClient::paintEvent(QPaintEvent *e) |
|
{ |
|
QRegion region = e->region(); |
|
|
|
PlastikHandler *handler = Handler(); |
|
|
|
if (oldCaption != caption() ) |
|
clearCaptionPixmaps(); |
|
|
|
bool active = isActive(); |
|
bool toolWindow = isToolWindow(); |
|
|
|
QPainter painter(widget() ); |
|
|
|
// often needed coordinates |
|
QRect r = widget()->rect(); |
|
|
|
int r_w = r.width(); |
|
// int r_h = r.height(); |
|
int r_x, r_y, r_x2, r_y2; |
|
r.getCoords(&r_x, &r_y, &r_x2, &r_y2); |
|
const int borderLeft = layoutMetric(LM_BorderLeft); |
|
const int borderRight = layoutMetric(LM_BorderRight); |
|
const int borderBottom = layoutMetric(LM_BorderBottom); |
|
const int titleHeight = layoutMetric(LM_TitleHeight); |
|
const int titleEdgeTop = layoutMetric(LM_TitleEdgeTop); |
|
const int titleEdgeBottom = layoutMetric(LM_TitleEdgeBottom); |
|
const int titleEdgeLeft = layoutMetric(LM_TitleEdgeLeft); |
|
const int titleEdgeRight = layoutMetric(LM_TitleEdgeRight); |
|
|
|
const int borderBottomTop = r_y2-borderBottom+1; |
|
const int borderLeftRight = r_x+borderLeft-1; |
|
const int borderRightLeft = r_x2-borderRight+1; |
|
const int titleEdgeBottomBottom = r_y+titleEdgeTop+titleHeight+titleEdgeBottom-1; |
|
|
|
const int sideHeight = borderBottomTop-titleEdgeBottomBottom-1; |
|
|
|
QRect Rtitle = QRect(r_x+titleEdgeLeft+buttonsLeftWidth(), r_y+titleEdgeTop, |
|
r_x2-titleEdgeRight-buttonsRightWidth()-(r_x+titleEdgeLeft+buttonsLeftWidth()), |
|
titleEdgeBottomBottom-(r_y+titleEdgeTop) ); |
|
|
|
QRect tempRect; |
|
|
|
// topSpacer |
|
if(titleEdgeTop > 0) |
|
{ |
|
tempRect.setRect(r_x+2, r_y, r_w-2*2, titleEdgeTop ); |
|
if (tempRect.isValid() && region.contains(tempRect) ) { |
|
painter.drawTiledPixmap(tempRect, handler->pixmap(TitleBarTileTop, active, toolWindow) ); |
|
} |
|
} |
|
|
|
// leftTitleSpacer |
|
int titleMarginLeft = 0; |
|
int titleMarginRight = 0; |
|
if(titleEdgeLeft > 0) |
|
{ |
|
tempRect.setRect(r_x, r_y, borderLeft, titleEdgeTop+titleHeight+titleEdgeBottom); |
|
if (tempRect.isValid() && region.contains(tempRect) ) { |
|
painter.drawTiledPixmap(tempRect, handler->pixmap(TitleBarLeft, active, toolWindow) ); |
|
titleMarginLeft = borderLeft; |
|
} |
|
} |
|
|
|
// rightTitleSpacer |
|
if(titleEdgeRight > 0) |
|
{ |
|
tempRect.setRect(borderRightLeft, r_y, borderRight, titleEdgeTop+titleHeight+titleEdgeBottom); |
|
if (tempRect.isValid() && region.contains(tempRect) ) { |
|
painter.drawTiledPixmap(tempRect, handler->pixmap(TitleBarRight, active, toolWindow) ); |
|
titleMarginRight = borderRight; |
|
} |
|
} |
|
|
|
// titleSpacer |
|
const QPixmap &caption = captionPixmap(); |
|
if(Rtitle.width() > 0) |
|
{ |
|
m_captionRect = captionRect(); // also update m_captionRect! |
|
if (m_captionRect.isValid() && region.contains(m_captionRect) ) |
|
{ |
|
painter.drawTiledPixmap(m_captionRect, caption); |
|
} |
|
|
|
// left to the title |
|
tempRect.setRect(r_x+titleMarginLeft, m_captionRect.top(), |
|
m_captionRect.left() - (r_x+titleMarginLeft), m_captionRect.height() ); |
|
if (tempRect.isValid() && region.contains(tempRect) ) { |
|
painter.drawTiledPixmap(tempRect, handler->pixmap(TitleBarTile, active, toolWindow) ); |
|
} |
|
|
|
// right to the title |
|
tempRect.setRect(m_captionRect.right()+1, m_captionRect.top(), |
|
(r_x2-titleMarginRight) - m_captionRect.right(), m_captionRect.height() ); |
|
if (tempRect.isValid() && region.contains(tempRect) ) { |
|
painter.drawTiledPixmap(tempRect, handler->pixmap(TitleBarTile, active, toolWindow) ); |
|
} |
|
|
|
} |
|
|
|
// leftSpacer |
|
if(borderLeft > 0 && sideHeight > 0) |
|
{ |
|
tempRect.setCoords(r_x, titleEdgeBottomBottom+1, borderLeftRight, borderBottomTop-1); |
|
if (tempRect.isValid() && region.contains(tempRect) ) { |
|
painter.drawTiledPixmap(tempRect, handler->pixmap(BorderLeftTile, active, toolWindow) ); |
|
} |
|
} |
|
|
|
// rightSpacer |
|
if(borderRight > 0 && sideHeight > 0) |
|
{ |
|
tempRect.setCoords(borderRightLeft, titleEdgeBottomBottom+1, r_x2, borderBottomTop-1); |
|
if (tempRect.isValid() && region.contains(tempRect) ) { |
|
painter.drawTiledPixmap(tempRect, handler->pixmap(BorderRightTile, active, toolWindow) ); |
|
} |
|
} |
|
|
|
// bottomSpacer |
|
if(borderBottom > 0) |
|
{ |
|
int l = r_x; |
|
int r = r_x2; |
|
|
|
tempRect.setRect(r_x, borderBottomTop, borderLeft, borderBottom); |
|
if (tempRect.isValid() && region.contains(tempRect) ) { |
|
painter.drawTiledPixmap(tempRect, handler->pixmap(BorderBottomLeft, active, toolWindow) ); |
|
l = tempRect.right()+1; |
|
} |
|
|
|
tempRect.setRect(borderRightLeft, borderBottomTop, borderLeft, borderBottom); |
|
if (tempRect.isValid() && region.contains(tempRect) ) { |
|
painter.drawTiledPixmap(tempRect, handler->pixmap(BorderBottomRight, active, toolWindow) ); |
|
r = tempRect.left()-1; |
|
} |
|
|
|
tempRect.setCoords(l, borderBottomTop, r, r_y2); |
|
if (tempRect.isValid() && region.contains(tempRect) ) { |
|
painter.drawTiledPixmap(tempRect, handler->pixmap(BorderBottomTile, active, toolWindow) ); |
|
} |
|
} |
|
} |
|
|
|
QRect PlastikClient::captionRect() const |
|
{ |
|
const QPixmap &caption = captionPixmap(); |
|
QRect r = widget()->rect(); |
|
|
|
const int titleHeight = layoutMetric(LM_TitleHeight); |
|
const int titleEdgeBottom = layoutMetric(LM_TitleEdgeBottom); |
|
const int titleEdgeTop = layoutMetric(LM_TitleEdgeTop); |
|
const int titleEdgeLeft = layoutMetric(LM_TitleEdgeLeft); |
|
const int marginLeft = layoutMetric(LM_TitleBorderLeft); |
|
const int marginRight = layoutMetric(LM_TitleBorderRight); |
|
|
|
const int titleLeft = r.left() + titleEdgeLeft + buttonsLeftWidth() + marginLeft; |
|
const int titleWidth = r.width() - |
|
titleEdgeLeft - layoutMetric(LM_TitleEdgeRight) - |
|
buttonsLeftWidth() - buttonsRightWidth() - |
|
marginLeft - marginRight; |
|
|
|
Qt::AlignmentFlag a = Handler()->titleAlign(); |
|
|
|
int tX, tW; // position/width of the title buffer |
|
if (caption.width() > titleWidth) { |
|
tW = titleWidth; |
|
} else { |
|
tW = caption.width(); |
|
} |
|
if (a == Qt::AlignLeft || (caption.width() > titleWidth) ) { |
|
// Align left |
|
tX = titleLeft; |
|
} else if (a == Qt::AlignHCenter) { |
|
// Align center |
|
tX = titleLeft+(titleWidth- caption.width() )/2; |
|
} else { |
|
// Align right |
|
tX = titleLeft+titleWidth-caption.width(); |
|
} |
|
|
|
return QRect(tX, r.top()+titleEdgeTop, tW, titleHeight+titleEdgeBottom); |
|
} |
|
|
|
void PlastikClient::updateCaption() |
|
{ |
|
QRect oldCaptionRect = m_captionRect; |
|
|
|
if (oldCaption != caption() ) |
|
clearCaptionPixmaps(); |
|
|
|
m_captionRect = PlastikClient::captionRect(); |
|
|
|
if (oldCaptionRect.isValid() && m_captionRect.isValid() ) |
|
widget()->update(oldCaptionRect|m_captionRect); |
|
else |
|
widget()->update(); |
|
} |
|
|
|
void PlastikClient::reset( unsigned long changed ) |
|
{ |
|
if (changed & SettingColors) |
|
{ |
|
// repaint the whole thing |
|
clearCaptionPixmaps(); |
|
widget()->update(); |
|
updateButtons(); |
|
} else if (changed & SettingFont) { |
|
// font has changed -- update title height and font |
|
s_titleFont = isToolWindow() ? Handler()->titleFontTool() : Handler()->titleFont(); |
|
|
|
updateLayout(); |
|
|
|
// then repaint |
|
clearCaptionPixmaps(); |
|
widget()->update(); |
|
} |
|
|
|
KCommonDecoration::reset(changed); |
|
} |
|
|
|
const QPixmap &PlastikClient::getTitleBarTile(bool active) const |
|
{ |
|
return Handler()->pixmap(TitleBarTile, active, isToolWindow() ); |
|
} |
|
|
|
const QPixmap &PlastikClient::captionPixmap() const |
|
{ |
|
bool active = isActive(); |
|
|
|
if (m_captionPixmaps[active]) { |
|
return *m_captionPixmaps[active]; |
|
} |
|
|
|
// not found, create new pixmap... |
|
|
|
const int maxCaptionLength = 300; // truncate captions longer than this! |
|
QString c(caption() ); |
|
if (c.length() > maxCaptionLength) { |
|
c.truncate(maxCaptionLength); |
|
c.append(" [...]"); |
|
} |
|
|
|
QFontMetrics fm(s_titleFont); |
|
int captionWidth = fm.width(c); |
|
int captionDescent = fm.descent(); |
|
|
|
const int th = layoutMetric(LM_TitleHeight, false) + layoutMetric(LM_TitleEdgeBottom, false); |
|
|
|
QPainter painter; |
|
|
|
const int thickness = 2; |
|
|
|
QPixmap *captionPixmap = new QPixmap(captionWidth+2*thickness, th); |
|
|
|
painter.begin(captionPixmap); |
|
painter.drawTiledPixmap(captionPixmap->rect(), |
|
Handler()->pixmap(TitleBarTile, active, isToolWindow()) ); |
|
|
|
painter.setFont(s_titleFont); |
|
|
|
QRect boundingRect = painter.boundingRect(captionPixmap->rect(), |
|
Qt::AlignVCenter | Handler()->titleAlign(), c); |
|
|
|
|
|
QPoint tp = boundingRect.bottomLeft() - QPoint(0, captionDescent); |
|
|
|
QColor fontColor = Handler()->getColor(TitleFont,active); |
|
if(Handler()->titleShadow()) |
|
{ |
|
QColor shadowColor = KColorScheme::shade(fontColor, KColorScheme::ShadowShade); |
|
|
|
painter.setCompositionMode(QPainter::CompositionMode_SourceOver); |
|
painter.setPen(alphaColor(shadowColor, 0.3) ); |
|
painter.drawText(tp+QPoint(1,2), c); |
|
painter.setPen(alphaColor(shadowColor, 0.2) ); |
|
painter.drawText(tp+QPoint(2,2), c); |
|
painter.setPen(alphaColor(shadowColor, 0.5) ); |
|
painter.drawText(tp+QPoint(1,1), c); |
|
} |
|
painter.setPen(fontColor ); |
|
painter.drawText(tp, c ); |
|
painter.end(); |
|
|
|
m_captionPixmaps[active] = captionPixmap; |
|
return *captionPixmap; |
|
} |
|
|
|
void PlastikClient::clearCaptionPixmaps() |
|
{ |
|
for (int i = 0; i < 2; ++i) { |
|
delete m_captionPixmaps[i]; |
|
m_captionPixmaps[i] = 0; |
|
} |
|
|
|
oldCaption = caption(); |
|
} |
|
|
|
} // KWinPlastik
|
|
|