From 49b2179ed410a3fccc7f9dff5426809ee7fa6821 Mon Sep 17 00:00:00 2001 From: Luciano Montanaro Date: Sun, 23 May 2004 22:59:13 +0000 Subject: [PATCH] Implemented 'hover' effect for titlebar buttons. svn path=/trunk/kdebase/kwin/; revision=313969 --- clients/b2/b2client.cpp | 246 +++++++++++++++++++++++----------------- clients/b2/b2client.h | 12 +- 2 files changed, 153 insertions(+), 105 deletions(-) diff --git a/clients/b2/b2client.cpp b/clients/b2/b2client.cpp index 4de127c3db..917631b9d2 100644 --- a/clients/b2/b2client.cpp +++ b/clients/b2/b2client.cpp @@ -4,8 +4,9 @@ * Changes: * Customizable button positions by Karol Szwed * - * Thin frame in fixed size windows, titlebar gradient support and - * accessibility improvements are + * Thin frame in fixed size windows, titlebar gradient support, accessibility + * improvements, customizable menu double click action and button hover + * effects are * Copyright (c) 2003,2004 Luciano Montanaro */ @@ -14,6 +15,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -27,26 +31,34 @@ namespace B2 { #include "bitmaps.h" -#define P_CLOSE 0 -#define P_MAX 1 -#define P_NORMALIZE 2 -#define P_ICONIFY 3 -#define P_PINUP 4 -#define P_MENU 5 -#define P_HELP 6 -#define P_SHADE 7 -#define NUM_PIXMAPS ((P_SHADE + 1) * 4) +enum { + Norm = 0, + Hover, Down, INorm, IHover, IDown, + NumStates +}; + +enum { + P_CLOSE = 0, + P_MAX, P_NORMALIZE, P_ICONIFY, P_PINUP, P_MENU, P_HELP, P_SHADE, + P_NUM_BUTTON_TYPES +}; + +#define NUM_PIXMAPS (P_NUM_BUTTON_TYPES * NumStates) static KPixmap *pixmap[NUM_PIXMAPS]; -//active -#define PIXMAP_A(i) (pixmap[(i)*4]) -//active, down -#define PIXMAP_AD(i) (pixmap[(i)*4 +1]) -//inactive -#define PIXMAP_I(i) (pixmap[(i)*4 +2]) -//inactive, down -#define PIXMAP_ID(i) (pixmap[(i)*4 +3]) +// active +#define PIXMAP_A(i) (pixmap[(i) * NumStates + Norm]) +// active, hover +#define PIXMAP_AH(i) (pixmap[(i) * NumStates + Hover]) +// active, down +#define PIXMAP_AD(i) (pixmap[(i) * NumStates + Down]) +// inactive +#define PIXMAP_I(i) (pixmap[(i) * NumStates + INorm]) +// inactive, hover +#define PIXMAP_IH(i) (pixmap[(i) * NumStates + IHover]) +// inactive, down +#define PIXMAP_ID(i) (pixmap[(i) * NumStates + IDown]) static KPixmap* titleGradient[2] = {0, 0}; @@ -169,7 +181,7 @@ static void create_pixmaps() for (i = 0; i < NUM_PIXMAPS; i++) { pixmap[i] = new KPixmap; - switch (i / 4) { + switch (i / NumStates) { case P_MAX: // will be initialized by copying P_CLOSE break; case P_ICONIFY: @@ -192,10 +204,12 @@ static void create_pixmaps() PIXMAP_ID(P_PINUP)->setMask(pindownMask); QBitmap menuMask(16, 16, menu_mask_bits, true); - for (i = 0; i < 4; i++) pixmap[P_MENU * 4 + i]->setMask(menuMask); + for (i = 0; i < NumStates; i++) + pixmap[P_MENU * NumStates + i]->setMask(menuMask); QBitmap helpMask(16, 16, help_mask_bits, true); - for (i = 0; i < 4; i++) pixmap[P_HELP * 4 + i]->setMask(helpMask); + for (i = 0; i < NumStates; i++) + pixmap[P_HELP * NumStates + i]->setMask(helpMask); QBitmap normalizeMask(16, 16, true); // draw normalize icon mask @@ -208,13 +222,15 @@ static void create_pixmaps() mask.fillRect(0, 0, 10, 10, one); mask.end(); - for (i = 0; i < 4; i++) pixmap[P_NORMALIZE * 4 + i]->setMask(normalizeMask); + for (i = 0; i < NumStates; i++) + pixmap[P_NORMALIZE * NumStates + i]->setMask(normalizeMask); QBitmap shadeMask(bsize, bsize, true); mask.begin(&shadeMask); mask.fillRect(0, 0, bsize, 6, one); mask.end(); - for (i = 0; i < 4; i++) pixmap[P_SHADE * 4 + i]->setMask(shadeMask); + for (i = 0; i < NumStates; i++) + pixmap[P_SHADE * NumStates + i]->setMask(shadeMask); titleGradient[0] = 0; titleGradient[1] = 0; @@ -400,7 +416,7 @@ void B2Client::addButtons(const QString& s, const QString tips[], LeftButton | RightButton); button[BtnMenu]->setPixmaps(P_MENU); button[BtnMenu]->setUseMiniIcon(); - connect(button[BtnMenu], SIGNAL(clicked()), + connect(button[BtnMenu], SIGNAL(pressed()), this, SLOT(menuButtonPressed())); titleLayout->addWidget(button[BtnMenu]); } @@ -821,10 +837,18 @@ void B2Client::menuButtonPressed() lastClient = this; time.start(); if (!dbl) { + KDecorationFactory* f = factory(); +#if 0 + QPoint menutop = button[BtnMenu]->mapToGlobal( + button[BtnMenu]->rect().topLeft()); + QPoint menubottom = button[BtnMenu]->mapToGlobal( + button[BtnMenu]->rect().bottomRight()); + showWindowMenu(QRect(menutop, menubottom)); +#else QPoint menupoint = button[BtnMenu]->mapToGlobal( button[BtnMenu]->rect().bottomLeft()); - KDecorationFactory* f = factory(); showWindowMenu(menupoint); +#endif if (!f->exists(this)) // 'this' was destroyed return; button[BtnMenu]->setDown(false); @@ -876,18 +900,20 @@ static void redraw_pixmaps() // close drawB2Rect(PIXMAP_A(P_CLOSE), aGrp.button(), false); + drawB2Rect(PIXMAP_AH(P_CLOSE), aGrp.button(), true); drawB2Rect(PIXMAP_AD(P_CLOSE), aGrp.button(), true); drawB2Rect(PIXMAP_I(P_CLOSE), iGrp.button(), false); + drawB2Rect(PIXMAP_IH(P_CLOSE), iGrp.button(), true); drawB2Rect(PIXMAP_ID(P_CLOSE), iGrp.button(), true); // shade KPixmap thinBox; thinBox.resize(buttonSize - 2, 6); - for (i = 0; i < 4; i++) { + for (i = 0; i < NumStates; i++) { bool is_act = (i < 2); bool is_down = ((i & 1) == 1); - KPixmap *pix = pixmap[P_SHADE * 4 + i]; + KPixmap *pix = pixmap[P_SHADE * NumStates + i]; QColor color = is_act ? aGrp.button() : iGrp.button(); drawB2Rect(&thinBox, color, is_down); pix->fill(Qt::black); @@ -896,9 +922,9 @@ static void redraw_pixmaps() } // maximize - for (i = 0; i < 4; i++) { - *pixmap[P_MAX*4 + i] = *pixmap[P_CLOSE*4 + i]; - pixmap[P_MAX*4 + i]->detach(); + for (i = 0; i < NumStates; i++) { + *pixmap[P_MAX * NumStates + i] = *pixmap[P_CLOSE * NumStates + i]; + pixmap[P_MAX * NumStates + i]->detach(); } // normalize + iconify @@ -907,10 +933,10 @@ static void redraw_pixmaps() KPixmap largeBox; largeBox.resize(12, 12); - for (i = 0; i < 4; i++) { - bool is_act = (i < 2); - bool is_down = ((i & 1) == 1); - KPixmap *pix = pixmap[P_NORMALIZE*4 + i]; + for (i = 0; i < 6; i++) { + bool is_act = (i < 3); + bool is_down = (i == Down || i == IDown); + KPixmap *pix = pixmap[P_NORMALIZE * NumStates + i]; drawB2Rect(&smallBox, is_act ? aGrp.button() : iGrp.button(), is_down); drawB2Rect(&largeBox, is_act ? aGrp.button() : iGrp.button(), is_down); pix->fill(options()->color(KDecoration::ColorTitleBar, is_act)); @@ -918,51 +944,62 @@ static void redraw_pixmaps() 0, 0, 12, 12, Qt::CopyROP, true); bitBlt(pix, 0, 0, &smallBox, 0, 0, 10, 10, Qt::CopyROP, true); - bitBlt(pixmap[P_ICONIFY * 4 + i], 0, 0, + bitBlt(pixmap[P_ICONIFY * NumStates + i], 0, 0, &smallBox, 0, 0, 10, 10, Qt::CopyROP, true); } QPainter p; // x for close + menu + help - int pix = P_CLOSE; - const unsigned char *light = close_white_bits; - const unsigned char *dark = close_dgray_bits; - int off = (pixmap[pix * 4]->width() - 16) / 2; - for (i = 0; i < 4; i++) { - p.begin(pixmap[pix * 4 + i]); - kColorBitmaps(&p, (i < 2) ? aGrp : iGrp, off, off, 16, 16, true, - light, NULL, NULL, dark, NULL, NULL); - p.end(); - } - // x for close + menu + help - for (int j = 0; j < 2; j++) { + for (int j = 0; j < 3; j++) { + int pix; + unsigned const char *light, *dark; switch (j) { - case 1: - pix = P_MENU; light = menu_white_bits; dark = menu_dgray_bits; - break; + case 0: + pix = P_CLOSE; light = close_white_bits; dark = close_dgray_bits; + break; + case 1: + pix = P_MENU; light = menu_white_bits; dark = menu_dgray_bits; + break; default: - pix = P_HELP; light = help_light_bits; dark = help_dark_bits; - break; + pix = P_HELP; light = help_light_bits; dark = help_dark_bits; + break; } - for (i = 0; i < 4; i++) { - p.begin(pixmap[pix * 4 + i]); - kColorBitmaps(&p, (i < 2) ? aGrp : iGrp, 0, 0, 16, 16, true, + int off = (pixmap[pix * NumStates]->width() - 16) / 2; + for (i = 0; i < NumStates; i++) { + p.begin(pixmap[pix * NumStates + i]); + kColorBitmaps(&p, (i < 3) ? aGrp : iGrp, off, off, 16, 16, true, light, NULL, NULL, dark, NULL, NULL); p.end(); } } // pin - for (i = 0; i < 4; i++) { - const unsigned char *white = (i&1) ? pindown_white_bits : pinup_white_bits; - const unsigned char *gray = (i&1) ? pindown_gray_bits : pinup_gray_bits; - const unsigned char *dgray = (i&1) ? pindown_dgray_bits : pinup_dgray_bits; - p.begin(pixmap[P_PINUP*4 + i]); - kColorBitmaps(&p, (i<2)?aGrp:iGrp, 0, 0, 16, 16, true, white, + for (i = 0; i < NumStates; i++) { + bool isDown = (i == Down || i == IDown); + unsigned const char *white = isDown ? pindown_white_bits : pinup_white_bits; + unsigned const char *gray = isDown ? pindown_gray_bits : pinup_gray_bits; + unsigned const char *dgray =isDown ? pindown_dgray_bits : pinup_dgray_bits; + p.begin(pixmap[P_PINUP * NumStates + i]); + kColorBitmaps(&p, (i < 3) ? aGrp : iGrp, 0, 0, 16, 16, true, white, gray, NULL, dgray, NULL, NULL); p.end(); } + // Apply the hilight effect to the 'Hover' icons + KIconEffect ie; + QPixmap hilighted; + for (i = 0; i < P_NUM_BUTTON_TYPES; i++) { + int offset = i * NumStates; + hilighted = ie.apply(*pixmap[offset + Norm], + KIcon::Small, KIcon::ActiveState); + *pixmap[offset + Hover] = hilighted; + + hilighted = ie.apply(*pixmap[offset + INorm], + KIcon::Small, KIcon::ActiveState); + *pixmap[offset + IHover] = hilighted; + } + + // Create the titlebar gradients if (QPixmap::defaultDepth() > 8) { QColor titleColor[4] = { @@ -1082,8 +1119,9 @@ bool B2Client::eventFilter(QObject *o, QEvent *e) // ===================================== -B2Button::B2Button(B2Client *_client, QWidget *parent, const QString& tip, const int realizeBtns) - : QButton(parent, 0) +B2Button::B2Button(B2Client *_client, QWidget *parent, + const QString& tip, const int realizeBtns) + : QButton(parent, 0), hover(false) { setBackgroundMode(NoBackground); realizeButtons = realizeBtns; @@ -1115,62 +1153,68 @@ void B2Button::drawButton(QPainter *p) if (useMiniIcon) { QPixmap miniIcon = client->icon().pixmap(QIconSet::Small, client->isActive() ? QIconSet::Normal : QIconSet::Disabled); - p->drawPixmap((width()-miniIcon.width())/2, - (height()-miniIcon.height())/2, miniIcon); - } - else{ - if(client->isActive()){ - if (isDown()) - p->drawPixmap((width()-pDown->width())/2, - (height()-pDown->height())/2, *pDown); + p->drawPixmap((width() - miniIcon.width()) / 2, + (height() - miniIcon.height()) / 2, miniIcon); + } else { + int type; + if (client->isActive()) { + if (isOn() || isDown()) + type = Down; + else if (hover) + type = Hover; + else + type = Norm; + } else { + if (isOn() || isDown()) + type = IDown; + else if (hover) + type = IHover; else - p->drawPixmap((width()-pNorm->width())/2, - (height()-pNorm->height())/2, *pNorm); - } - else{ - if (isDown()) - p->drawPixmap((width()-pDown->width())/2, - (height()-pDown->height())/2, *iDown); - else - p->drawPixmap((width()-pNorm->width())/2, - (height()-pNorm->height())/2, *iNorm); + type = INorm; } + p->drawPixmap((width() - icon[type]->width()) / 2, + (height() - icon[type]->height()) / 2, *icon[type]); } } -void B2Button::setPixmaps(KPixmap *pix, KPixmap *pixDown, KPixmap *iPix, - KPixmap *iPixDown) -{ - pNorm = pix; - pDown = pixDown; - iNorm = iPix; - iDown = iPixDown; - repaint(false); -} - void B2Button::setPixmaps(int button_id) { - button_id *= 4; - setPixmaps(B2::pixmap[button_id], B2::pixmap[button_id+1], - B2::pixmap[button_id+2], B2::pixmap[button_id+3]); + button_id *= NumStates; + for (int i = 0; i < NumStates; i++) { + icon[i] = B2::pixmap[button_id + i]; + } + repaint(false); } -void B2Button::mousePressEvent( QMouseEvent* e ) +void B2Button::mousePressEvent(QMouseEvent * e) { last_button = e->button(); - QMouseEvent me(e->type(), e->pos(), e->globalPos(), - (e->button()&realizeButtons)?LeftButton:NoButton, e->state()); + QMouseEvent me(e->type(), e->pos(), e->globalPos(), + (e->button() & realizeButtons) ? LeftButton : NoButton, + e->state()); QButton::mousePressEvent(&me); } -void B2Button::mouseReleaseEvent( QMouseEvent* e ) +void B2Button::mouseReleaseEvent(QMouseEvent * e) { last_button = e->button(); - QMouseEvent me(e->type(), e->pos(), e->globalPos(), - (e->button()&realizeButtons)?LeftButton:NoButton, e->state()); + QMouseEvent me(e->type(), e->pos(), e->globalPos(), + (e->button() & realizeButtons) ? LeftButton : NoButton, + e->state()); QButton::mouseReleaseEvent(&me); } +void B2Button::enterEvent(QEvent *) +{ + hover = true; + repaint(false); +} + +void B2Button::leaveEvent(QEvent *) +{ + hover = false; + repaint(false); +} // ===================================== B2Titlebar::B2Titlebar(B2Client *parent) diff --git a/clients/b2/b2client.h b/clients/b2/b2client.h index a4968ca0de..cb9c7c66ec 100644 --- a/clients/b2/b2client.h +++ b/clients/b2/b2client.h @@ -44,17 +44,21 @@ protected: virtual void drawButton(QPainter *p); void drawButtonLabel(QPainter *){;} - bool useMiniIcon; - KPixmap *pNorm, *pDown, *iNorm, *iDown; - QColor bg; //only use one color (the rest is pixmap) so forget QPalette ;) - void mousePressEvent( QMouseEvent* e ); void mouseReleaseEvent( QMouseEvent* e ); +private: + void enterEvent(QEvent *e); + void leaveEvent(QEvent *e); + + bool useMiniIcon; + KPixmap *icon[6]; + QColor bg; //only use one color (the rest is pixmap) so forget QPalette ;) public: B2Client* client; int last_button; int realizeButtons; + bool hover; }; class B2Titlebar : public QWidget