Adapt to new KWarning/kFatal/kDebug api
[kdeartwork.git] / kwin-styles / kstep / nextclient.cpp
blob00f26dfaab8bf49a1cf461788aa692230e4cb5da
1 #include "nextclient.h"
2 #include <qdatetime.h>
3 #include <qdrawutil.h>
4 #include <qlayout.h>
5 #include <qpainter.h>
6 #include <qbitmap.h>
7 #include <qlabel.h>
8 #include <qtooltip.h>
9 //Added by qt3to4:
10 #include <QPaintEvent>
11 #include <QEvent>
12 #include <QHBoxLayout>
13 #include <QBoxLayout>
14 #include <QShowEvent>
15 #include <QVBoxLayout>
16 #include <QResizeEvent>
17 #include <QMouseEvent>
18 #include <kdebug.h>
19 #include <klocale.h>
20 #include <kpixmapeffect.h>
22 namespace KStep {
24 static const unsigned char close_bits[] = {
25 0x03, 0x03, 0x87, 0x03, 0xce, 0x01, 0xfc, 0x00, 0x78, 0x00, 0x78, 0x00,
26 0xfc, 0x00, 0xce, 0x01, 0x87, 0x03, 0x03, 0x03};
28 static const unsigned char iconify_bits[] = {
29 0xff, 0x03, 0xff, 0x03, 0xff, 0x03, 0xff, 0x03, 0x03, 0x03, 0x03, 0x03,
30 0x03, 0x03, 0x03, 0x03, 0xff, 0x03, 0xff, 0x03};
32 static const unsigned char question_bits[] = {
33 0x00, 0x00, 0x78, 0x00, 0xcc, 0x00, 0xc0, 0x00, 0x60, 0x00, 0x30, 0x00,
34 0x00, 0x00, 0x30, 0x00, 0x30, 0x00, 0x00, 0x00};
36 static const unsigned char sticky_bits[] = {
37 0x00, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0xfe, 0x01, 0xfe, 0x01,
38 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x00, 0x00};
40 static const unsigned char unsticky_bits[] = {
41 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x01, 0xfe, 0x01,
42 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
44 static const unsigned char maximize_bits[] = {
45 0x30, 0x00, 0x78, 0x00, 0xfc, 0x00, 0xfe, 0x01, 0x00, 0x00, 0xfe, 0x01,
46 0x02, 0x01, 0x84, 0x00, 0x48, 0x00, 0x30, 0x00 };
48 static const unsigned char shade_bits[] = {
49 0xff,0x03,
50 0xff,0x03,
51 0x03,0x03,
52 0xff,0x03,
53 0xff,0x03,
54 0x00,0x00,
55 0x00,0x00,
56 0x00,0x00,
57 0x00,0x00,
58 0x00,0x00
61 static const unsigned char unshade_bits[] = {
62 0xff,0x03,
63 0xff,0x03,
64 0x03,0x03,
65 0x03,0x03,
66 0x03,0x03,
67 0x03,0x03,
68 0x03,0x03,
69 0x03,0x03,
70 0xff,0x03,
71 0xff,0x03
74 static const unsigned char keep_above_bits[] = {
75 0x30,0x00,
76 0x78,0x00,
77 0xfc,0x00,
78 0x00,0x00,
79 0xff,0x03,
80 0xff,0x03,
81 0x00,0x00,
82 0x00,0x00,
83 0x00,0x00,
84 0x00,0x00
87 static const unsigned char from_above_bits[] = {
88 0xff,0x03,
89 0xff,0x03,
90 0x00,0x00,
91 0xfc,0x00,
92 0x78,0x00,
93 0x30,0x00,
94 0x00,0x00,
95 0x00,0x00,
96 0x00,0x00,
97 0x00,0x00
100 static const unsigned char keep_below_bits[] = {
101 0x00,0x00,
102 0x00,0x00,
103 0x00,0x00,
104 0x00,0x00,
105 0xff,0x03,
106 0xff,0x03,
107 0x00,0x00,
108 0xfc,0x00,
109 0x78,0x00,
110 0x30,0x00
113 static const unsigned char from_below_bits[] = {
114 0x00,0x00,
115 0x00,0x00,
116 0x00,0x00,
117 0x00,0x00,
118 0x30,0x00,
119 0x78,0x00,
120 0xfc,0x00,
121 0x00,0x00,
122 0xff,0x03,
123 0xff,0x03
126 static const unsigned char resize_bits[] = {
127 0xff, 0x03,
128 0xff, 0x03,
129 0x33, 0x03,
130 0x33, 0x03,
131 0xf3, 0x03,
132 0xf3, 0x03,
133 0x03, 0x03,
134 0x03, 0x03,
135 0xff, 0x03,
136 0xff, 0x03
140 // If the maximize graphic above (which I did quickly in about a
141 // minute, just so I could have something) doesn't please, maybe one
142 // of the following would be better. IMO it doesn't matter, as long
143 // as it's not offensive---people will get used to whatever you use.
144 // True NeXT fans won't turn on the maximize button anyway.
146 // static const unsigned char maximize_bits[] = {
147 // 0xcf, 0x03, 0x87, 0x03, 0xcf, 0x03, 0xfd, 0x02, 0x48, 0x00, 0x48, 0x00,
148 // 0xfd, 0x02, 0xcf, 0x03, 0x87, 0x03, 0xcf, 0x03 };
150 // static const unsigned char maximize_bits[] = {
151 // 0xcf, 0x03, 0x87, 0x03, 0x87, 0x03, 0x79, 0x02, 0x48, 0x00, 0x48, 0x00,
152 // 0x79, 0x02, 0x87, 0x03, 0x87, 0x03, 0xcf, 0x03 };
154 // static const unsigned char maximize_bits[] = {
155 // 0x87, 0x03, 0x03, 0x03, 0xfd, 0x02, 0x84, 0x00, 0x84, 0x00, 0x84, 0x00,
156 // 0x84, 0x00, 0xfd, 0x02, 0x03, 0x03, 0x87, 0x03 };
158 // static const unsigned char maximize_bits[] = {
159 // 0x30, 0x00, 0x78, 0x00, 0xcc, 0x00, 0x86, 0x01, 0x33, 0x03, 0x79, 0x02,
160 // 0xcd, 0x02, 0x87, 0x03, 0x03, 0x03, 0x01, 0x02 };
162 // static const unsigned char maximize_bits[] = {
163 // 0x30, 0x00, 0x78, 0x00, 0x78, 0x00, 0xfc, 0x00, 0xfc, 0x00, 0xfe, 0x01,
164 // 0xfe, 0x01, 0xff, 0x03, 0xff, 0x03, 0xff, 0x03 };
167 static KPixmap *aTitlePix;
168 static KPixmap *iTitlePix;
169 static KPixmap *aFramePix;
170 static KPixmap *iFramePix;
171 static KPixmap *aHandlePix;
172 static KPixmap *iHandlePix;
173 static KPixmap *aBtn;
174 static KPixmap *aBtnDown;
175 static KPixmap *iBtn;
176 static KPixmap *iBtnDown;
177 static QColor *btnForeground;
178 static bool pixmaps_created = false;
180 static int titleHeight = 16;
182 // Precomputed border sizes for accessibility
183 // The sizes are applied for tiny -> normal -> large -> very large -> huge -> very huge -> oversized
184 static const int borderSizes[] = { 4, 6, 9, 14, 21, 32, 48 };
186 static int handleSize = 6; // the resize handle size in pixels
188 static inline const KDecorationOptions* options()
190 return KDecoration::options();
193 static void create_pixmaps(NextClientFactory *f)
195 if(pixmaps_created)
196 return;
197 pixmaps_created = true;
199 // find preferred border size
200 int i = options()->preferredBorderSize(f);
201 if (i >= 0 && i <= 6) handleSize = borderSizes[i];
203 titleHeight = QFontMetrics(options()->font(true)).height() + 4;
204 if (titleHeight < handleSize) titleHeight = handleSize;
205 titleHeight &= ~1; // Make title height even
206 if (titleHeight < 16) titleHeight = 16;
208 aTitlePix = new KPixmap();
209 aTitlePix->resize(32, titleHeight - 2);
210 KPixmapEffect::gradient(*aTitlePix,
211 options()->color(KDecoration::ColorTitleBar, true),
212 options()->color(KDecoration::ColorTitleBlend, true),
213 KPixmapEffect::VerticalGradient);
214 iTitlePix = new KPixmap();
215 iTitlePix->resize(32, titleHeight - 2);
216 KPixmapEffect::gradient(*iTitlePix,
217 options()->color(KDecoration::ColorTitleBar, false),
218 options()->color(KDecoration::ColorTitleBlend, false),
219 KPixmapEffect::VerticalGradient);
220 // Bottom frame gradient
221 aFramePix = new KPixmap();
222 aFramePix->resize(32, handleSize);
223 KPixmapEffect::gradient(*aFramePix,
224 options()->color(KDecoration::ColorFrame, true).light(150),
225 options()->color(KDecoration::ColorFrame, true).dark(120),
226 KPixmapEffect::VerticalGradient);
227 iFramePix = new KPixmap();
228 iFramePix->resize(32, handleSize);
229 KPixmapEffect::gradient(*iFramePix,
230 options()->color(KDecoration::ColorFrame, false).light(150),
231 options()->color(KDecoration::ColorFrame, false).dark(120),
232 KPixmapEffect::VerticalGradient);
234 // Handle gradient
235 aHandlePix = new KPixmap();
236 aHandlePix->resize(32, handleSize);
237 KPixmapEffect::gradient(*aHandlePix,
238 options()->color(KDecoration::ColorHandle, true).light(150),
239 options()->color(KDecoration::ColorHandle, true).dark(120),
240 KPixmapEffect::VerticalGradient);
241 iHandlePix = new KPixmap();
242 iHandlePix->resize(32, handleSize);
243 KPixmapEffect::gradient(*iHandlePix,
244 options()->color(KDecoration::ColorHandle, false).light(150),
245 options()->color(KDecoration::ColorHandle, false).dark(120),
246 KPixmapEffect::VerticalGradient);
248 int btnWidth = titleHeight;
249 iBtn = new KPixmap;
250 iBtn->resize(btnWidth, btnWidth);
251 iBtnDown = new KPixmap;
252 iBtnDown->resize(btnWidth, btnWidth);
253 aBtn = new KPixmap;
254 aBtn->resize(btnWidth, btnWidth);
255 aBtnDown = new KPixmap;
256 aBtnDown->resize(btnWidth, btnWidth);
257 KPixmap internal;
258 int internalHeight = btnWidth - 6;
259 internal.resize(internalHeight, internalHeight);
261 // inactive buttons
262 QColor c(options()->color(KDecoration::ColorButtonBg, false));
263 KPixmapEffect::gradient(*iBtn, c.light(120), c.dark(120),
264 KPixmapEffect::DiagonalGradient);
265 KPixmapEffect::gradient(internal, c.dark(120), c.light(120),
266 KPixmapEffect::DiagonalGradient);
267 bitBlt(iBtn, 3, 3, &internal, 0, 0, internalHeight, internalHeight, Qt::CopyROP, true);
269 KPixmapEffect::gradient(*iBtnDown, c.dark(120), c.light(120),
270 KPixmapEffect::DiagonalGradient);
271 KPixmapEffect::gradient(internal, c.light(120), c.dark(120),
272 KPixmapEffect::DiagonalGradient);
273 bitBlt(iBtnDown, 3, 3, &internal, 0, 0, internalHeight, internalHeight, Qt::CopyROP, true);
275 // active buttons
276 c = options()->color(KDecoration::ColorButtonBg, true);
277 KPixmapEffect::gradient(*aBtn, c.light(120), c.dark(120),
278 KPixmapEffect::DiagonalGradient);
279 KPixmapEffect::gradient(internal, c.dark(120), c.light(120),
280 KPixmapEffect::DiagonalGradient);
281 bitBlt(aBtn, 3, 3, &internal, 0, 0, internalHeight, internalHeight, Qt::CopyROP, true);
283 KPixmapEffect::gradient(*aBtnDown, c.dark(120), c.light(120),
284 KPixmapEffect::DiagonalGradient);
285 KPixmapEffect::gradient(internal, c.light(120), c.dark(120),
286 KPixmapEffect::DiagonalGradient);
287 bitBlt(aBtnDown, 3, 3, &internal, 0, 0, internalHeight, internalHeight, Qt::CopyROP, true);
289 QPainter p;
290 p.begin(aBtn);
291 p.setPen(Qt::black);
292 p.drawRect(0, 0, btnWidth, btnWidth);
293 p.end();
294 p.begin(iBtn);
295 p.setPen(Qt::black);
296 p.drawRect(0, 0, btnWidth, btnWidth);
297 p.end();
298 p.begin(aBtnDown);
299 p.setPen(Qt::black);
300 p.drawRect(0, 0, btnWidth, btnWidth);
301 p.end();
302 p.begin(iBtnDown);
303 p.setPen(Qt::black);
304 p.drawRect(0, 0, btnWidth, btnWidth);
305 p.end();
307 if(qGray(options()->color(KDecoration::ColorButtonBg, true).rgb()) > 128)
308 btnForeground = new QColor(Qt::black);
309 else
310 btnForeground = new QColor(Qt::white);
313 static void delete_pixmaps()
315 delete aTitlePix;
316 delete iTitlePix;
317 delete aFramePix;
318 delete iFramePix;
319 delete aHandlePix;
320 delete iHandlePix;
321 delete aBtn;
322 delete iBtn;
323 delete aBtnDown;
324 delete iBtnDown;
325 delete btnForeground;
327 pixmaps_created = false;
330 // =====================================
332 NextButton::NextButton(NextClient *parent, const char *name,
333 const unsigned char *bitmap, int bw, int bh,
334 const QString& tip, const int realizeBtns)
335 : Q3Button(parent->widget(), name),
336 deco(NULL), client(parent), last_button(Qt::NoButton)
338 realizeButtons = realizeBtns;
340 setBackgroundMode( Qt::NoBackground );
341 resize(titleHeight, titleHeight);
342 setFixedSize(titleHeight, titleHeight);
344 if(bitmap)
345 setBitmap(bitmap, bw, bh);
347 this->setToolTip( tip);
350 void NextButton::reset()
352 repaint(false);
355 void NextButton::setBitmap(const unsigned char *bitmap, int w, int h)
357 deco = new QBitmap(w, h, bitmap, true);
358 deco->setMask(*deco);
359 repaint();
362 void NextButton::drawButton(QPainter *p)
364 if(client->isActive())
365 p->drawPixmap(0, 0, isDown() ? *aBtnDown : *aBtn);
366 else
367 p->drawPixmap(0, 0, isDown() ? *iBtnDown : *iBtn);
369 // If we have a decoration, draw it; otherwise, we have the menu
370 // button (remember, we set the bitmap to NULL).
371 int offset;
372 if (deco) {
373 offset = (titleHeight - 10) / 2 + (isDown() ? 1 : 0);
374 p->setPen(*btnForeground);
375 p->drawPixmap(offset, offset, *deco);
376 } else {
377 offset = (titleHeight - 16) / 2;
378 KPixmap btnpix = client->icon().pixmap(QIcon::Small,
379 client->isActive() ? QIcon::Normal : QIcon::Disabled);
380 p->drawPixmap( offset, offset, btnpix );
384 void NextButton::mousePressEvent( QMouseEvent* e )
386 last_button = e->button();
387 QMouseEvent me( e->type(), e->pos(), e->globalPos(),
388 (e->button()&realizeButtons)?Qt::LeftButton:Qt::NoButton, e->state() );
389 Q3Button::mousePressEvent( &me );
392 void NextButton::mouseReleaseEvent( QMouseEvent* e )
394 last_button = e->button();
395 QMouseEvent me( e->type(), e->pos(), e->globalPos(),
396 (e->button()&realizeButtons)?Qt::LeftButton:Qt::NoButton, e->state() );
397 Q3Button::mouseReleaseEvent( &me );
400 // =====================================
402 NextClient::NextClient(KDecorationBridge *b, KDecorationFactory *f)
403 : KDecoration(b, f)
407 void NextClient::init()
409 createMainWidget(WResizeNoErase | WStaticContents);
410 widget()->installEventFilter(this);
412 widget()->setBackgroundMode( NoBackground );
414 QVBoxLayout *mainLayout = new QVBoxLayout(widget());
415 QBoxLayout *titleLayout = new QBoxLayout(0, QBoxLayout::LeftToRight, 0, 0, 0);
416 QHBoxLayout *windowLayout = new QHBoxLayout();
417 mainLayout->addLayout(titleLayout);
418 mainLayout->addLayout(windowLayout, 1);
419 mainLayout->addSpacing(mustDrawHandle() ? handleSize : 1);
421 windowLayout->addSpacing(1);
422 if (isPreview())
423 windowLayout->addWidget(new QLabel(i18n(
424 "<center><b>KStep preview</b></center>"), widget()));
425 else
426 windowLayout->addItem(new QSpacerItem( 0, 0 ));
428 windowLayout->addSpacing(1);
430 initializeButtonsAndTitlebar(titleLayout);
434 Preconditions:
435 + button is an array of length MAX_NUM_BUTTONS
437 Postconditions:
438 + Title bar and buttons have been initialized and laid out
439 + for all i in 0..(MAX_NUM_BUTTONS-1), button[i] points to
440 either (1) a valid NextButton instance, if the corresponding
441 button is selected in the current button scheme, or (2) null
442 otherwise.
444 void NextClient::initializeButtonsAndTitlebar(QBoxLayout* titleLayout)
446 // Null the buttons to begin with (they are not guaranteed to be null).
447 for (int i=0; i<MAX_NUM_BUTTONS; i++) {
448 button[i] = NULL;
451 // The default button positions for other styles do not match the
452 // behavior of older versions of KStep, so we have to set these
453 // manually when customButtonPositions isn't enabled.
454 QString left, right;
455 if (options()->customButtonPositions()) {
456 left = options()->titleButtonsLeft();
457 right = options()->titleButtonsRight();
458 } else {
459 left = QString("I");
460 right = QString("SX");
463 // Do actual creation and addition to titleLayout
464 addButtons(titleLayout, left);
466 titlebar = new QSpacerItem(10, titleHeight, QSizePolicy::Expanding,
467 QSizePolicy::Minimum );
468 titleLayout->addItem(titlebar);
469 addButtons(titleLayout, right);
471 // Finally, activate all live buttons
472 for ( int i = 0; i < MAX_NUM_BUTTONS; i++) {
473 if (button[i]) {
474 button[i]->setMouseTracking( TRUE );
479 /** Adds the buttons for one side of the title bar, based on the spec
480 * string; see the KWin::KDecoration class, methods
481 * titleButtonsLeft and titleBUttonsRight. */
482 void NextClient::addButtons(QBoxLayout* titleLayout, const QString& spec)
484 for (unsigned int i=0; i<spec.length(); i++) {
485 switch (spec[i].latin1()) {
486 case 'A':
487 if (isMaximizable()) {
488 button[MAXIMIZE_IDX] =
489 new NextButton(this, "maximize", maximize_bits, 10, 10,
490 i18n("Maximize"), Qt::LeftButton|Qt::MidButton|Qt::RightButton);
491 titleLayout->addWidget( button[MAXIMIZE_IDX] );
492 connect( button[MAXIMIZE_IDX], SIGNAL(clicked()),
493 this, SLOT(maximizeButtonClicked()) );
495 break;
497 case 'H':
498 if (providesContextHelp()) {
499 button[HELP_IDX] = new NextButton(this,
500 "help", question_bits, 10, 10, i18n("Help"));
501 titleLayout->addWidget( button[HELP_IDX] );
502 connect( button[HELP_IDX], SIGNAL(clicked()),
503 this, SLOT(showContextHelp()) );
505 break;
507 case 'I':
508 if (isMinimizable()) {
509 button[ICONIFY_IDX] =
510 new NextButton(this, "iconify", iconify_bits, 10, 10,
511 i18n("Minimize"));
512 titleLayout->addWidget( button[ICONIFY_IDX] );
513 connect( button[ICONIFY_IDX], SIGNAL(clicked()),
514 this, SLOT(minimize()) );
516 break;
518 case 'M':
519 button[MENU_IDX] =
520 new NextButton(this, "menu", NULL, 10, 10, i18n("Menu"), Qt::LeftButton|Qt::RightButton);
521 titleLayout->addWidget( button[MENU_IDX] );
522 // NOTE DIFFERENCE: capture pressed(), not clicked()
523 connect( button[MENU_IDX], SIGNAL(pressed()),
524 this, SLOT(menuButtonPressed()) );
525 break;
527 case 'L':
528 button[SHADE_IDX] =
529 new NextButton(this, "shade", NULL, 0, 0, i18n("Shade"));
530 titleLayout->addWidget( button[SHADE_IDX] );
531 connect( button[SHADE_IDX], SIGNAL(clicked()),
532 this, SLOT(shadeClicked()) );
533 // NOTE DIFFERENCE: set the pixmap separately (2 states)
534 shadeChange();
535 break;
537 case 'S':
538 button[STICKY_IDX] =
539 new NextButton(this, "sticky", NULL, 0, 0, i18n("On all desktops"));
540 titleLayout->addWidget( button[STICKY_IDX] );
541 connect( button[STICKY_IDX], SIGNAL(clicked()),
542 this, SLOT(toggleOnAllDesktops()) );
543 // NOTE DIFFERENCE: set the pixmap separately (2 states)
544 desktopChange();
545 break;
547 case 'F':
548 button[ABOVE_IDX] = new NextButton(this, "above", NULL, 0, 0, "");
549 titleLayout->addWidget( button[ABOVE_IDX] );
550 connect( button[ABOVE_IDX], SIGNAL(clicked()),
551 this, SLOT(aboveClicked()) );
552 connect(this, SIGNAL(keepAboveChanged(bool)),
553 SLOT(keepAboveChange(bool)));
554 keepAboveChange(keepAbove());
555 break;
557 case 'B':
558 button[BELOW_IDX] = new NextButton(this, "below", NULL, 0, 0, "");
559 titleLayout->addWidget( button[BELOW_IDX] );
560 connect( button[BELOW_IDX], SIGNAL(clicked()),
561 this, SLOT(belowClicked()) );
562 connect(this, SIGNAL(keepBelowChanged(bool)),
563 SLOT(keepBelowChange(bool)));
564 keepBelowChange(keepBelow());
565 break;
567 case 'X':
568 if (isCloseable()) {
569 button[CLOSE_IDX] =
570 new NextButton(this, "close", close_bits, 10, 10,
571 i18n("Close"));
572 titleLayout->addWidget(button[CLOSE_IDX]);
573 connect(button[CLOSE_IDX], SIGNAL(clicked()),
574 this, SLOT(closeWindow()));
576 break;
578 case 'R':
579 if (mustDrawHandle()) {
580 button[RESIZE_IDX] =
581 new NextButton(this, "resize", resize_bits, 10, 10,
582 i18n("Resize"));
583 titleLayout->addWidget(button[RESIZE_IDX]);
584 // NOTE DIFFERENCE: capture pressed(), not clicked()
585 connect(button[RESIZE_IDX], SIGNAL(pressed()),
586 this, SLOT(resizePressed()));
588 break;
589 case '_':
590 // TODO: Add spacer handling
591 break;
593 default:
594 kDebug() << " Can't happen: unknown button code "
595 << QString(spec[i]);
596 break;
601 bool NextClient::mustDrawHandle() const
603 bool drawSmallBorders = !options()->moveResizeMaximizedWindows();
604 if (drawSmallBorders && (maximizeMode() & MaximizeVertical)) {
605 return false;
606 } else {
607 return isResizable();
611 void NextClient::iconChange()
613 if (button[MENU_IDX] && button[MENU_IDX]->isVisible())
614 button[MENU_IDX]->repaint(false);
617 void NextClient::menuButtonPressed()
619 // Probably don't need this null check, but we might as well.
620 if (button[MENU_IDX]) {
621 QRect menuRect = button[MENU_IDX]->rect();
622 QPoint menuTop = button[MENU_IDX]->mapToGlobal(menuRect.topLeft());
623 QPoint menuBottom = button[MENU_IDX]->mapToGlobal(menuRect.bottomRight());
624 menuTop += QPoint(1, 1);
625 menuBottom += QPoint(1, 1);
626 KDecorationFactory* f = factory();
627 showWindowMenu(QRect(menuTop, menuBottom));
628 if( !f->exists( this )) // 'this' was deleted
629 return;
630 button[MENU_IDX]->setDown(false);
634 // Copied, with minor edits, from KDEDefaultClient::slotMaximize()
635 void NextClient::maximizeButtonClicked()
637 if (button[MAXIMIZE_IDX]) {
638 maximize(button[MAXIMIZE_IDX]->lastButton());
642 void NextClient::shadeClicked()
644 setShade(!isSetShade());
647 void NextClient::aboveClicked()
649 setKeepAbove(!keepAbove());
652 void NextClient::belowClicked()
654 setKeepBelow(!keepBelow());
655 keepAboveChange(keepAbove());
656 keepBelowChange(keepBelow());
659 void NextClient::resizePressed()
661 performWindowOperation(ResizeOp);
664 void NextClient::resizeEvent(QResizeEvent *)
666 if (widget()->isVisible()) {
667 // TODO ? update border area only?
668 widget()->update();
669 #if 0
670 widget()->update(titlebar->geometry());
671 QPainter p(widget());
672 QRect t = titlebar->geometry();
673 t.setTop( 0 );
674 QRegion r = widget()->rect();
675 r = r.subtract( t );
676 p.setClipRegion( r );
677 p.eraseRect(widget()->rect());
678 #endif
682 void NextClient::captionChange()
684 widget()->repaint(titlebar->geometry(), false);
688 void NextClient::paintEvent( QPaintEvent* )
690 QPainter p(widget());
692 // Draw black frame
693 QRect fr = widget()->rect();
694 p.setPen(Qt::black);
695 p.drawRect(fr);
697 // Draw title bar
698 QRect t = titlebar->geometry();
699 t.setTop(1);
700 p.drawTiledPixmap(t.x()+1, t.y()+1, t.width()-2, t.height()-2,
701 isActive() ? *aTitlePix : *iTitlePix);
702 qDrawShadePanel(&p, t.x(), t.y(), t.width(), t.height()-1,
703 options()->colorGroup(KDecoration::ColorTitleBar, isActive()));
704 p.drawLine(t.x(), t.bottom(), t.right(), t.bottom());
706 #if 0
707 // Why setting up a clipping region if it is not used? (setClipping(false))
708 QRegion r = fr;
709 r = r.subtract( t );
710 p.setClipRegion( r );
711 p.setClipping(false);
712 #endif
714 t.setTop( 1 );
715 t.setHeight(t.height()-2);
716 t.setLeft( t.left() + 4 );
717 t.setRight( t.right() - 2 );
719 p.setPen(options()->color(KDecoration::ColorFont, isActive()));
720 p.setFont(options()->font(isActive()));
721 p.drawText( t, Qt::AlignCenter | Qt::AlignVCenter, caption() );
723 // Draw resize handle
724 if (mustDrawHandle()) {
725 int corner = 16 + 3*handleSize/2;
726 qDrawShadePanel(&p,
727 fr.x() + 1, fr.bottom() - handleSize, corner-1, handleSize,
728 options()->colorGroup(KDecoration::ColorHandle, isActive()),
729 false);
730 p.drawTiledPixmap(fr.x() + 2, fr.bottom() - handleSize + 1,
731 corner - 3, handleSize - 2, isActive() ? *aHandlePix : *iHandlePix);
733 qDrawShadePanel(&p,
734 fr.x() + corner, fr.bottom() - handleSize,
735 fr.width() - 2*corner, handleSize,
736 options()->colorGroup(KDecoration::ColorFrame, isActive()),
737 false);
738 p.drawTiledPixmap(fr.x() + corner + 1, fr.bottom() - handleSize + 1,
739 fr.width() - 2*corner - 2, handleSize - 2,
740 isActive() ? *aFramePix : *iFramePix);
742 qDrawShadePanel(&p,
743 fr.right() - corner + 1, fr.bottom() - handleSize, corner - 1, handleSize,
744 options()->colorGroup(KDecoration::ColorHandle, isActive()),
745 false);
746 p.drawTiledPixmap(fr.right() - corner + 2, fr.bottom() - handleSize + 1,
747 corner - 3, handleSize - 2, isActive() ? *aHandlePix : *iHandlePix);
751 void NextClient::mouseDoubleClickEvent( QMouseEvent * e )
753 if (e->button() == Qt::LeftButton && titlebar->geometry().contains( e->pos() ) )
754 titlebarDblClickOperation();
757 void NextClient::showEvent(QShowEvent *)
759 widget()->repaint();
762 void NextClient::desktopChange()
764 bool on = isOnAllDesktops();
765 if (NextButton * b = button[STICKY_IDX]) {
766 b->setBitmap( on ? unsticky_bits : sticky_bits, 10, 10);
767 QToolTip::remove(b);
768 b->setToolTip( on ? i18n("Not on all desktops") : i18n("On all desktops"));
772 void NextClient::maximizeChange()
774 if (button[MAXIMIZE_IDX]) {
775 bool m = maximizeMode() == MaximizeFull;
776 //button[MAXIMIZE_IDX]->setBitmap(m ? minmax_bits : maximize_bits);
777 QToolTip::remove(button[MAXIMIZE_IDX]);
778 button[MAXIMIZE_IDX]->setToolTip(
779 m ? i18n("Restore") : i18n("Maximize"));
781 //spacer->changeSize(10, mustDrawHandle() ? handleSize : 1,
782 // QSizePolicy::Expanding, QSizePolicy::Minimum);
783 //mainLayout->activate();
786 void NextClient::activeChange()
788 widget()->repaint(false);
789 slotReset();
792 void NextClient::slotReset()
794 for (int i=0; i<MAX_NUM_BUTTONS; i++) {
795 if (button[i]) {
796 button[i]->reset();
801 KDecoration::Position
802 NextClient::mousePosition( const QPoint& p ) const
804 Position m = PositionCenter;
806 if (p.y() < (height() - handleSize))
807 m = KDecoration::mousePosition(p);
809 else {
810 int corner = 16 + 3*handleSize/2;
811 if (p.x() >= (width() - corner))
812 m = PositionBottomRight;
813 else if (p.x() <= corner)
814 m = PositionBottomLeft;
815 else
816 m = PositionBottom;
819 return m;
822 void NextClient::borders(int &left, int &right, int &top, int &bottom) const
824 left = right = 1;
825 top = titleHeight; // FRAME is this ok?
826 bottom = mustDrawHandle() ? handleSize : 1;
829 void NextClient::shadeChange()
831 if (NextButton *b = button[SHADE_IDX]) {
832 b->setBitmap(isSetShade() ? unshade_bits : shade_bits, 10, 10);
833 QToolTip::remove(b);
834 b->setToolTip( isSetShade() ? i18n("Unshade") : i18n("Shade"));
838 void NextClient::keepAboveChange(bool above)
840 if (NextButton *b = button[ABOVE_IDX]) {
841 b->setBitmap(above ? from_above_bits : keep_above_bits, 10, 10);
842 QToolTip::remove(b);
843 b->setToolTip( above ?
844 i18n("Do not keep above others") : i18n("Keep above others"));
845 b->repaint(false);
849 void NextClient::keepBelowChange(bool below)
851 if (NextButton *b = button[BELOW_IDX]) {
852 b->setBitmap(below ? from_below_bits : keep_below_bits, 10, 10);
853 QToolTip::remove(b);
854 b->setToolTip( below ?
855 i18n("Do not keep below others") : i18n("Keep below others"));
856 b->repaint(false);
860 QSize NextClient::minimumSize() const
862 return QSize(titleHeight * 6 + 2, titleHeight + handleSize + 2);
865 void NextClient::resize(const QSize& s)
867 widget()->resize(s);
870 void NextClient::reset(unsigned long)
872 for (int i = 0; i < MAX_NUM_BUTTONS; ++i) {
873 if (button[i])
874 button[i]->reset();
876 widget()->repaint();
879 bool NextClient::eventFilter(QObject *o, QEvent *e)
881 if (o != widget())
882 return false;
883 switch (e->type()) {
884 case QEvent::Resize:
885 resizeEvent(static_cast< QResizeEvent* >( e ));
886 return true;
887 case QEvent::Paint:
888 paintEvent(static_cast< QPaintEvent* >( e ));
889 return true;
890 case QEvent::MouseButtonDblClick:
891 mouseDoubleClickEvent(static_cast< QMouseEvent* >( e ));
892 return true;
893 case QEvent::MouseButtonPress:
894 processMousePressEvent(static_cast< QMouseEvent* >( e ));
895 return true;
896 case QEvent::Show:
897 showEvent(static_cast< QShowEvent* >( e ));
898 return true;
899 default:
900 break;
902 return false;
905 bool NextClient::drawbound(const QRect& geom, bool /* clear */)
907 QPainter p(workspaceWidget());
908 p.setPen(QPen(Qt::white, 3));
909 p.setRasterOp(Qt::XorROP);
910 p.drawRect(geom);
911 int leftMargin = geom.left() + 2;
912 p.fillRect(leftMargin, geom.top() + titleHeight - 1,
913 geom.width() - 4, 3, Qt::white);
914 if (mustDrawHandle()) {
915 p.fillRect(leftMargin, geom.bottom() - handleSize - 1,
916 geom.width() - 4, 3, Qt::white);
918 return true;
921 // =====================================
923 NextClientFactory::NextClientFactory()
925 create_pixmaps(this);
928 NextClientFactory::~NextClientFactory()
930 delete_pixmaps();
933 KDecoration *NextClientFactory::createDecoration(KDecorationBridge *b)
935 return new NextClient(b, this);
938 bool NextClientFactory::reset(unsigned long /*changed*/)
940 // TODO Do not recreate decorations if it is not needed. Look at
941 // ModernSystem for how to do that
942 delete_pixmaps();
943 create_pixmaps(this);
944 // For now just return true.
945 return true;
948 bool NextClientFactory::supports( Ability ability )
950 switch( ability )
952 case AbilityAnnounceButtons:
953 case AbilityButtonMenu:
954 case AbilityButtonOnAllDesktops:
955 case AbilityButtonHelp:
956 case AbilityButtonMinimize:
957 case AbilityButtonMaximize:
958 case AbilityButtonClose:
959 case AbilityButtonAboveOthers:
960 case AbilityButtonBelowOthers:
961 case AbilityButtonShade:
962 case AbilityButtonResize:
963 return true;
964 default:
965 return false;
969 QList< NextClientFactory::BorderSize >
970 NextClientFactory::borderSizes() const
972 // the list must be sorted
973 return QList< BorderSize >() << BorderTiny << BorderNormal <<
974 BorderLarge << BorderVeryLarge << BorderHuge <<
975 BorderVeryHuge << BorderOversized;
978 } // KStep namespace
980 extern "C" KDE_EXPORT KDecorationFactory* create_factory()
982 return new KStep::NextClientFactory();
985 #include "nextclient.moc"
987 // vim: sw=4