/* 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 <tdelocale.h> #include <tqbitmap.h> #include <tqdatetime.h> #include <tqfontmetrics.h> #include <tqimage.h> #include <tqlabel.h> #include <tqlayout.h> #include <tqpainter.h> #include <tqpixmap.h> #include <tqdesktopwidget.h> #include "plastikclient.h" #include "plastikbutton.h" #include "misc.h" namespace KWinPlastik { PlastikClient::PlastikClient(KDecorationBridge* bridge, KDecorationFactory* factory) : KCommonDecoration (bridge, factory), s_titleFont(TQFont() ) { memset(m_captionPixmaps, 0, sizeof(TQPixmap*)*2); } PlastikClient::~PlastikClient() { clearCaptionPixmaps(); } TQString PlastikClient::visibleName() const { return i18n("Plastik"); } TQString PlastikClient::defaultButtonsLeft() const { return "M"; } TQString PlastikClient::defaultButtonsRight() const { return "HIAX"; } 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; case LM_ExplicitButtonSpacer: return 3; default: return KCommonDecoration::layoutMetric(lm, respectWindowState, btn); } } KCommonDecorationButton *PlastikClient::createButton(ButtonType type) { switch (type) { case MenuButton: return new PlastikButton(MenuButton, this, "menu"); case OnAllDesktopsButton: return new PlastikButton(OnAllDesktopsButton, this, "on_all_desktops"); case HelpButton: return new PlastikButton(HelpButton, this, "help"); case MinButton: return new PlastikButton(MinButton, this, "minimize"); case MaxButton: return new PlastikButton(MaxButton, this, "maximize"); case CloseButton: return new PlastikButton(CloseButton, this, "close"); case AboveButton: return new PlastikButton(AboveButton, this, "above"); case BelowButton: return new PlastikButton(BelowButton, this, "below"); case ShadeButton: return new PlastikButton(ShadeButton, this, "shade"); default: return 0; } } void PlastikClient::init() { s_titleFont = isToolWindow() ? Handler()->titleFontTool() : Handler()->titleFont(); clearCaptionPixmaps(); KCommonDecoration::init(); } TQRegion PlastikClient::cornerShape(WindowCorner corner) { int w = widget()->width(); int h = widget()->height(); switch (corner) { case WC_TopLeft: if (layoutMetric(LM_TitleEdgeLeft) > 0) return TQRegion(0, 0, 1, 2) + TQRegion(1, 0, 1, 1); else return TQRegion(); case WC_TopRight: if (layoutMetric(LM_TitleEdgeRight) > 0) return TQRegion(w-1, 0, 1, 2) + TQRegion(w-2, 0, 1, 1); else return TQRegion(); case WC_BottomLeft: if (layoutMetric(LM_BorderBottom) > 0) return TQRegion(0, h-1, 1, 1); else return TQRegion(); case WC_BottomRight: if (layoutMetric(LM_BorderBottom) > 0) return TQRegion(w-1, h-1, 1, 1); else return TQRegion(); default: return TQRegion(); } } void PlastikClient::paintEvent(TQPaintEvent *e) { TQRegion region = e->region(); PlastikHandler *handler = Handler(); if (oldCaption != caption() ) clearCaptionPixmaps(); bool active = isActive(); bool toolWindow = isToolWindow(); TQPainter painter(widget() ); // often needed coordinates TQRect r = widget()->rect(); int r_w = r.width(); // int r_h = r.height(); int r_x, r_y, r_x2, r_y2; r.coords(&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; TQRect Rtitle = TQRect(r_x+titleEdgeLeft+buttonsLeftWidth(), r_y+titleEdgeTop, r_x2-titleEdgeRight-buttonsRightWidth()-(r_x+titleEdgeLeft+buttonsLeftWidth()), titleEdgeBottomBottom-(r_y+titleEdgeTop) ); TQRect 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 TQPixmap &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) ); } } } TQRect PlastikClient::captionRect() const { const TQPixmap &caption = captionPixmap(); TQRect 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; TQ_Alignment 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 TQRect(tX, r.top()+titleEdgeTop, tW, titleHeight+titleEdgeBottom); } void PlastikClient::updateCaption() { TQRect 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 TQPixmap &PlastikClient::getTitleBarTile(bool active) const { return Handler()->pixmap(TitleBarTile, active, isToolWindow() ); } const TQPixmap &PlastikClient::captionPixmap() const { bool active = isActive(); if (m_captionPixmaps[active]) { return *m_captionPixmaps[active]; } // not found, create new pixmap... const uint maxCaptionLength = 300; // truncate captions longer than this! TQString c(caption() ); if (c.length() > maxCaptionLength) { c.truncate(maxCaptionLength); c.append(" [...]"); } TQFontMetrics fm(s_titleFont); int captionWidth = fm.width(c); int captionHeight = fm.height(); const int th = layoutMetric(LM_TitleHeight, false) + layoutMetric(LM_TitleEdgeBottom, false); TQPainter painter; const int thickness = 2; TQPixmap *captionPixmap = new TQPixmap(captionWidth+2*thickness, th); painter.begin(captionPixmap); painter.drawTiledPixmap(captionPixmap->rect(), Handler()->pixmap(TitleBarTile, active, isToolWindow()) ); painter.setFont(s_titleFont); TQPoint tp(1, captionHeight-1); if(Handler()->titleShadow()) { TQColor shadowColor; if (tqGray(Handler()->getColor(TitleFont,active).rgb()) < 100) shadowColor = TQColor(255, 255, 255); else shadowColor = TQColor(0,0,0); painter.setPen(alphaBlendColors(options()->color(ColorTitleBar, active), shadowColor, 205) ); painter.drawText(tp+TQPoint(1,2), c); painter.setPen(alphaBlendColors(options()->color(ColorTitleBar, active), shadowColor, 225) ); painter.drawText(tp+TQPoint(2,2), c); painter.setPen(alphaBlendColors(options()->color(ColorTitleBar, active), shadowColor, 165) ); painter.drawText(tp+TQPoint(1,1), c); } painter.setPen(Handler()->getColor(TitleFont,active) ); 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