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.
989 lines
29 KiB
989 lines
29 KiB
#include "nextclient.h"
|
|
#include <tqdatetime.h>
|
|
#include <tqdrawutil.h>
|
|
#include <tqlayout.h>
|
|
#include <tqpainter.h>
|
|
#include <tqbitmap.h>
|
|
#include <tqlabel.h>
|
|
#include <tqtooltip.h>
|
|
#include <kdebug.h>
|
|
#include <tdeglobal.h>
|
|
#include <tdelocale.h>
|
|
#include <kpixmapeffect.h>
|
|
|
|
namespace KStep {
|
|
|
|
static const unsigned char close_bits[] = {
|
|
0x03, 0x03, 0x87, 0x03, 0xce, 0x01, 0xfc, 0x00, 0x78, 0x00, 0x78, 0x00,
|
|
0xfc, 0x00, 0xce, 0x01, 0x87, 0x03, 0x03, 0x03};
|
|
|
|
static const unsigned char iconify_bits[] = {
|
|
0xff, 0x03, 0xff, 0x03, 0xff, 0x03, 0xff, 0x03, 0x03, 0x03, 0x03, 0x03,
|
|
0x03, 0x03, 0x03, 0x03, 0xff, 0x03, 0xff, 0x03};
|
|
|
|
static const unsigned char question_bits[] = {
|
|
0x00, 0x00, 0x78, 0x00, 0xcc, 0x00, 0xc0, 0x00, 0x60, 0x00, 0x30, 0x00,
|
|
0x00, 0x00, 0x30, 0x00, 0x30, 0x00, 0x00, 0x00};
|
|
|
|
static const unsigned char sticky_bits[] = {
|
|
0x00, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0xfe, 0x01, 0xfe, 0x01,
|
|
0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x00, 0x00};
|
|
|
|
static const unsigned char unsticky_bits[] = {
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x01, 0xfe, 0x01,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
|
|
|
static const unsigned char maximize_bits[] = {
|
|
0x30, 0x00, 0x78, 0x00, 0xfc, 0x00, 0xfe, 0x01, 0x00, 0x00, 0xfe, 0x01,
|
|
0x02, 0x01, 0x84, 0x00, 0x48, 0x00, 0x30, 0x00 };
|
|
|
|
static const unsigned char shade_bits[] = {
|
|
0xff,0x03,
|
|
0xff,0x03,
|
|
0x03,0x03,
|
|
0xff,0x03,
|
|
0xff,0x03,
|
|
0x00,0x00,
|
|
0x00,0x00,
|
|
0x00,0x00,
|
|
0x00,0x00,
|
|
0x00,0x00
|
|
};
|
|
|
|
static const unsigned char unshade_bits[] = {
|
|
0xff,0x03,
|
|
0xff,0x03,
|
|
0x03,0x03,
|
|
0x03,0x03,
|
|
0x03,0x03,
|
|
0x03,0x03,
|
|
0x03,0x03,
|
|
0x03,0x03,
|
|
0xff,0x03,
|
|
0xff,0x03
|
|
};
|
|
|
|
static const unsigned char keep_above_bits[] = {
|
|
0x30,0x00,
|
|
0x78,0x00,
|
|
0xfc,0x00,
|
|
0x00,0x00,
|
|
0xff,0x03,
|
|
0xff,0x03,
|
|
0x00,0x00,
|
|
0x00,0x00,
|
|
0x00,0x00,
|
|
0x00,0x00
|
|
};
|
|
|
|
static const unsigned char from_above_bits[] = {
|
|
0xff,0x03,
|
|
0xff,0x03,
|
|
0x00,0x00,
|
|
0xfc,0x00,
|
|
0x78,0x00,
|
|
0x30,0x00,
|
|
0x00,0x00,
|
|
0x00,0x00,
|
|
0x00,0x00,
|
|
0x00,0x00
|
|
};
|
|
|
|
static const unsigned char keep_below_bits[] = {
|
|
0x00,0x00,
|
|
0x00,0x00,
|
|
0x00,0x00,
|
|
0x00,0x00,
|
|
0xff,0x03,
|
|
0xff,0x03,
|
|
0x00,0x00,
|
|
0xfc,0x00,
|
|
0x78,0x00,
|
|
0x30,0x00
|
|
};
|
|
|
|
static const unsigned char from_below_bits[] = {
|
|
0x00,0x00,
|
|
0x00,0x00,
|
|
0x00,0x00,
|
|
0x00,0x00,
|
|
0x30,0x00,
|
|
0x78,0x00,
|
|
0xfc,0x00,
|
|
0x00,0x00,
|
|
0xff,0x03,
|
|
0xff,0x03
|
|
};
|
|
|
|
static const unsigned char resize_bits[] = {
|
|
0xff, 0x03,
|
|
0xff, 0x03,
|
|
0x33, 0x03,
|
|
0x33, 0x03,
|
|
0xf3, 0x03,
|
|
0xf3, 0x03,
|
|
0x03, 0x03,
|
|
0x03, 0x03,
|
|
0xff, 0x03,
|
|
0xff, 0x03
|
|
};
|
|
|
|
|
|
// If the maximize graphic above (which I did quickly in about a
|
|
// minute, just so I could have something) doesn't please, maybe one
|
|
// of the following would be better. IMO it doesn't matter, as long
|
|
// as it's not offensive---people will get used to whatever you use.
|
|
// True NeXT fans won't turn on the maximize button anyway.
|
|
//
|
|
// static const unsigned char maximize_bits[] = {
|
|
// 0xcf, 0x03, 0x87, 0x03, 0xcf, 0x03, 0xfd, 0x02, 0x48, 0x00, 0x48, 0x00,
|
|
// 0xfd, 0x02, 0xcf, 0x03, 0x87, 0x03, 0xcf, 0x03 };
|
|
//
|
|
// static const unsigned char maximize_bits[] = {
|
|
// 0xcf, 0x03, 0x87, 0x03, 0x87, 0x03, 0x79, 0x02, 0x48, 0x00, 0x48, 0x00,
|
|
// 0x79, 0x02, 0x87, 0x03, 0x87, 0x03, 0xcf, 0x03 };
|
|
//
|
|
// static const unsigned char maximize_bits[] = {
|
|
// 0x87, 0x03, 0x03, 0x03, 0xfd, 0x02, 0x84, 0x00, 0x84, 0x00, 0x84, 0x00,
|
|
// 0x84, 0x00, 0xfd, 0x02, 0x03, 0x03, 0x87, 0x03 };
|
|
//
|
|
// static const unsigned char maximize_bits[] = {
|
|
// 0x30, 0x00, 0x78, 0x00, 0xcc, 0x00, 0x86, 0x01, 0x33, 0x03, 0x79, 0x02,
|
|
// 0xcd, 0x02, 0x87, 0x03, 0x03, 0x03, 0x01, 0x02 };
|
|
//
|
|
// static const unsigned char maximize_bits[] = {
|
|
// 0x30, 0x00, 0x78, 0x00, 0x78, 0x00, 0xfc, 0x00, 0xfc, 0x00, 0xfe, 0x01,
|
|
// 0xfe, 0x01, 0xff, 0x03, 0xff, 0x03, 0xff, 0x03 };
|
|
|
|
|
|
static KPixmap *aTitlePix;
|
|
static KPixmap *iTitlePix;
|
|
static KPixmap *aFramePix;
|
|
static KPixmap *iFramePix;
|
|
static KPixmap *aHandlePix;
|
|
static KPixmap *iHandlePix;
|
|
static KPixmap *aBtn;
|
|
static KPixmap *aBtnDown;
|
|
static KPixmap *iBtn;
|
|
static KPixmap *iBtnDown;
|
|
static TQColor *btnForeground;
|
|
static bool pixmaps_created = false;
|
|
|
|
static int titleHeight = 16;
|
|
|
|
// Precomputed border sizes for accessibility
|
|
// The sizes are applied for tiny -> normal -> large -> very large -> huge -> very huge -> oversized
|
|
static const int borderSizes[] = { 4, 6, 9, 14, 21, 32, 48 };
|
|
|
|
static int handleSize = 6; // the resize handle size in pixels
|
|
|
|
static inline const KDecorationOptions* options()
|
|
{
|
|
return KDecoration::options();
|
|
}
|
|
|
|
static void create_pixmaps(NextClientFactory *f)
|
|
{
|
|
if(pixmaps_created)
|
|
return;
|
|
pixmaps_created = true;
|
|
|
|
// find preferred border size
|
|
int i = options()->preferredBorderSize(f);
|
|
if (i >= 0 && i <= 6) handleSize = borderSizes[i];
|
|
|
|
titleHeight = TQFontMetrics(options()->font(true)).height() + 4;
|
|
if (titleHeight < handleSize) titleHeight = handleSize;
|
|
titleHeight &= ~1; // Make title height even
|
|
if (titleHeight < 16) titleHeight = 16;
|
|
|
|
aTitlePix = new KPixmap();
|
|
aTitlePix->resize(32, titleHeight - 2);
|
|
KPixmapEffect::gradient(*aTitlePix,
|
|
options()->color(KDecoration::ColorTitleBar, true),
|
|
options()->color(KDecoration::ColorTitleBlend, true),
|
|
KPixmapEffect::VerticalGradient);
|
|
iTitlePix = new KPixmap();
|
|
iTitlePix->resize(32, titleHeight - 2);
|
|
KPixmapEffect::gradient(*iTitlePix,
|
|
options()->color(KDecoration::ColorTitleBar, false),
|
|
options()->color(KDecoration::ColorTitleBlend, false),
|
|
KPixmapEffect::VerticalGradient);
|
|
// Bottom frame gradient
|
|
aFramePix = new KPixmap();
|
|
aFramePix->resize(32, handleSize);
|
|
KPixmapEffect::gradient(*aFramePix,
|
|
options()->color(KDecoration::ColorFrame, true).light(150),
|
|
options()->color(KDecoration::ColorFrame, true).dark(120),
|
|
KPixmapEffect::VerticalGradient);
|
|
iFramePix = new KPixmap();
|
|
iFramePix->resize(32, handleSize);
|
|
KPixmapEffect::gradient(*iFramePix,
|
|
options()->color(KDecoration::ColorFrame, false).light(150),
|
|
options()->color(KDecoration::ColorFrame, false).dark(120),
|
|
KPixmapEffect::VerticalGradient);
|
|
|
|
// Handle gradient
|
|
aHandlePix = new KPixmap();
|
|
aHandlePix->resize(32, handleSize);
|
|
KPixmapEffect::gradient(*aHandlePix,
|
|
options()->color(KDecoration::ColorHandle, true).light(150),
|
|
options()->color(KDecoration::ColorHandle, true).dark(120),
|
|
KPixmapEffect::VerticalGradient);
|
|
iHandlePix = new KPixmap();
|
|
iHandlePix->resize(32, handleSize);
|
|
KPixmapEffect::gradient(*iHandlePix,
|
|
options()->color(KDecoration::ColorHandle, false).light(150),
|
|
options()->color(KDecoration::ColorHandle, false).dark(120),
|
|
KPixmapEffect::VerticalGradient);
|
|
|
|
int btnWidth = titleHeight;
|
|
iBtn = new KPixmap;
|
|
iBtn->resize(btnWidth, btnWidth);
|
|
iBtnDown = new KPixmap;
|
|
iBtnDown->resize(btnWidth, btnWidth);
|
|
aBtn = new KPixmap;
|
|
aBtn->resize(btnWidth, btnWidth);
|
|
aBtnDown = new KPixmap;
|
|
aBtnDown->resize(btnWidth, btnWidth);
|
|
KPixmap internal;
|
|
int internalHeight = btnWidth - 6;
|
|
internal.resize(internalHeight, internalHeight);
|
|
|
|
// inactive buttons
|
|
TQColor c(options()->color(KDecoration::ColorButtonBg, false));
|
|
KPixmapEffect::gradient(*iBtn, c.light(120), c.dark(120),
|
|
KPixmapEffect::DiagonalGradient);
|
|
KPixmapEffect::gradient(internal, c.dark(120), c.light(120),
|
|
KPixmapEffect::DiagonalGradient);
|
|
bitBlt(TQT_TQPAINTDEVICE(iBtn), 3, 3, TQT_TQPAINTDEVICE(&internal), 0, 0, internalHeight, internalHeight, TQt::CopyROP, true);
|
|
|
|
KPixmapEffect::gradient(*iBtnDown, c.dark(120), c.light(120),
|
|
KPixmapEffect::DiagonalGradient);
|
|
KPixmapEffect::gradient(internal, c.light(120), c.dark(120),
|
|
KPixmapEffect::DiagonalGradient);
|
|
bitBlt(TQT_TQPAINTDEVICE(iBtnDown), 3, 3, TQT_TQPAINTDEVICE(&internal), 0, 0, internalHeight, internalHeight, TQt::CopyROP, true);
|
|
|
|
// active buttons
|
|
c = options()->color(KDecoration::ColorButtonBg, true);
|
|
KPixmapEffect::gradient(*aBtn, c.light(120), c.dark(120),
|
|
KPixmapEffect::DiagonalGradient);
|
|
KPixmapEffect::gradient(internal, c.dark(120), c.light(120),
|
|
KPixmapEffect::DiagonalGradient);
|
|
bitBlt(TQT_TQPAINTDEVICE(aBtn), 3, 3, TQT_TQPAINTDEVICE(&internal), 0, 0, internalHeight, internalHeight, TQt::CopyROP, true);
|
|
|
|
KPixmapEffect::gradient(*aBtnDown, c.dark(120), c.light(120),
|
|
KPixmapEffect::DiagonalGradient);
|
|
KPixmapEffect::gradient(internal, c.light(120), c.dark(120),
|
|
KPixmapEffect::DiagonalGradient);
|
|
bitBlt(TQT_TQPAINTDEVICE(aBtnDown), 3, 3, TQT_TQPAINTDEVICE(&internal), 0, 0, internalHeight, internalHeight, TQt::CopyROP, true);
|
|
|
|
TQPainter p;
|
|
p.begin(aBtn);
|
|
p.setPen(TQt::black);
|
|
p.drawRect(0, 0, btnWidth, btnWidth);
|
|
p.end();
|
|
p.begin(iBtn);
|
|
p.setPen(TQt::black);
|
|
p.drawRect(0, 0, btnWidth, btnWidth);
|
|
p.end();
|
|
p.begin(aBtnDown);
|
|
p.setPen(TQt::black);
|
|
p.drawRect(0, 0, btnWidth, btnWidth);
|
|
p.end();
|
|
p.begin(iBtnDown);
|
|
p.setPen(TQt::black);
|
|
p.drawRect(0, 0, btnWidth, btnWidth);
|
|
p.end();
|
|
|
|
if(tqGray(options()->color(KDecoration::ColorButtonBg, true).rgb()) > 128)
|
|
btnForeground = new TQColor(TQt::black);
|
|
else
|
|
btnForeground = new TQColor(TQt::white);
|
|
}
|
|
|
|
static void delete_pixmaps()
|
|
{
|
|
delete aTitlePix;
|
|
delete iTitlePix;
|
|
delete aFramePix;
|
|
delete iFramePix;
|
|
delete aHandlePix;
|
|
delete iHandlePix;
|
|
delete aBtn;
|
|
delete iBtn;
|
|
delete aBtnDown;
|
|
delete iBtnDown;
|
|
delete btnForeground;
|
|
|
|
pixmaps_created = false;
|
|
}
|
|
|
|
// =====================================
|
|
|
|
NextButton::NextButton(NextClient *parent, const char *name,
|
|
const unsigned char *bitmap, int bw, int bh,
|
|
const TQString& tip, const int realizeBtns)
|
|
: TQButton(parent->widget(), name),
|
|
deco(NULL), client(parent), last_button(TQt::NoButton)
|
|
{
|
|
realizeButtons = realizeBtns;
|
|
|
|
setBackgroundMode( NoBackground );
|
|
resize(titleHeight, titleHeight);
|
|
setFixedSize(titleHeight, titleHeight);
|
|
|
|
if(bitmap)
|
|
setBitmap(bitmap, bw, bh);
|
|
|
|
TQToolTip::add(this, tip);
|
|
}
|
|
|
|
void NextButton::reset()
|
|
{
|
|
repaint(false);
|
|
}
|
|
|
|
void NextButton::setBitmap(const unsigned char *bitmap, int w, int h)
|
|
{
|
|
deco = new TQBitmap(w, h, bitmap, true);
|
|
deco->setMask(*deco);
|
|
repaint();
|
|
}
|
|
|
|
void NextButton::drawButton(TQPainter *p)
|
|
{
|
|
if(client->isActive())
|
|
p->drawPixmap(0, 0, isDown() ? *aBtnDown : *aBtn);
|
|
else
|
|
p->drawPixmap(0, 0, isDown() ? *iBtnDown : *iBtn);
|
|
|
|
// If we have a decoration, draw it; otherwise, we have the menu
|
|
// button (remember, we set the bitmap to NULL).
|
|
int offset;
|
|
if (deco) {
|
|
offset = (titleHeight - 10) / 2 + (isDown() ? 1 : 0);
|
|
p->setPen(*btnForeground);
|
|
p->drawPixmap(offset, offset, *deco);
|
|
} else {
|
|
offset = (titleHeight - 16) / 2;
|
|
KPixmap btnpix = client->icon().pixmap(TQIconSet::Small,
|
|
client->isActive() ? TQIconSet::Normal : TQIconSet::Disabled);
|
|
p->drawPixmap( offset, offset, btnpix );
|
|
}
|
|
}
|
|
|
|
void NextButton::mousePressEvent( TQMouseEvent* e )
|
|
{
|
|
last_button = e->button();
|
|
TQMouseEvent me( e->type(), e->pos(), e->globalPos(),
|
|
(e->button()&realizeButtons)?TQt::LeftButton:TQt::NoButton, e->state() );
|
|
TQButton::mousePressEvent( &me );
|
|
}
|
|
|
|
void NextButton::mouseReleaseEvent( TQMouseEvent* e )
|
|
{
|
|
last_button = e->button();
|
|
TQMouseEvent me( e->type(), e->pos(), e->globalPos(),
|
|
(e->button()&realizeButtons)?TQt::LeftButton:TQt::NoButton, e->state() );
|
|
TQButton::mouseReleaseEvent( &me );
|
|
}
|
|
|
|
// =====================================
|
|
|
|
NextClient::NextClient(KDecorationBridge *b, KDecorationFactory *f)
|
|
: KDecoration(b, f)
|
|
{
|
|
}
|
|
|
|
void NextClient::init()
|
|
{
|
|
createMainWidget(WResizeNoErase | WStaticContents);
|
|
widget()->installEventFilter(this);
|
|
|
|
widget()->setBackgroundMode( NoBackground );
|
|
|
|
TQVBoxLayout *mainLayout = new TQVBoxLayout(widget());
|
|
TQBoxLayout *titleLayout = new TQBoxLayout(0, TQBoxLayout::LeftToRight, 0, 0, 0);
|
|
TQHBoxLayout *windowLayout = new TQHBoxLayout();
|
|
mainLayout->addLayout(titleLayout);
|
|
mainLayout->addLayout(windowLayout, 1);
|
|
mainLayout->addSpacing(mustDrawHandle() ? handleSize : 1);
|
|
|
|
windowLayout->addSpacing(1);
|
|
if (isPreview())
|
|
windowLayout->addWidget(new TQLabel(i18n(
|
|
"<center><b>KStep preview</b></center>"), widget()));
|
|
else
|
|
windowLayout->addItem(new TQSpacerItem( 0, 0 ));
|
|
|
|
windowLayout->addSpacing(1);
|
|
|
|
initializeButtonsAndTitlebar(titleLayout);
|
|
}
|
|
|
|
/**
|
|
Preconditions:
|
|
+ button is an array of length MAX_NUM_BUTTONS
|
|
|
|
Postconditions:
|
|
+ Title bar and buttons have been initialized and laid out
|
|
+ for all i in 0..(MAX_NUM_BUTTONS-1), button[i] points to
|
|
either (1) a valid NextButton instance, if the corresponding
|
|
button is selected in the current button scheme, or (2) null
|
|
otherwise.
|
|
*/
|
|
void NextClient::initializeButtonsAndTitlebar(TQBoxLayout* titleLayout)
|
|
{
|
|
// Null the buttons to begin with (they are not guaranteed to be null).
|
|
for (int i=0; i<MAX_NUM_BUTTONS; i++) {
|
|
button[i] = NULL;
|
|
}
|
|
|
|
// The default button positions for other styles do not match the
|
|
// behavior of older versions of KStep, so we have to set these
|
|
// manually when customButtonPositions isn't enabled.
|
|
TQString left, right;
|
|
if (options()->customButtonPositions()) {
|
|
left = options()->titleButtonsLeft();
|
|
right = options()->titleButtonsRight();
|
|
} else {
|
|
left = TQString("I");
|
|
right = TQString("SX");
|
|
}
|
|
|
|
// Do actual creation and addition to titleLayout
|
|
addButtons(titleLayout, left);
|
|
|
|
titlebar = new TQSpacerItem(10, titleHeight, TQSizePolicy::Expanding,
|
|
TQSizePolicy::Minimum );
|
|
titleLayout->addItem(titlebar);
|
|
addButtons(titleLayout, right);
|
|
|
|
// Finally, activate all live buttons
|
|
for ( int i = 0; i < MAX_NUM_BUTTONS; i++) {
|
|
if (button[i]) {
|
|
button[i]->setMouseTracking( TRUE );
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Adds the buttons for one side of the title bar, based on the spec
|
|
* string; see the KWinInternal::KDecoration class, methods
|
|
* titleButtonsLeft and titleBUttonsRight. */
|
|
void NextClient::addButtons(TQBoxLayout* titleLayout, const TQString& spec)
|
|
{
|
|
for (unsigned int i=0; i<spec.length(); i++) {
|
|
switch (spec[i].latin1()) {
|
|
case 'A':
|
|
if (isMaximizable()) {
|
|
button[MAXIMIZE_IDX] =
|
|
new NextButton(this, "maximize", maximize_bits, 10, 10,
|
|
i18n("Maximize"), TQt::LeftButton|TQt::MidButton|TQt::RightButton);
|
|
titleLayout->addWidget( button[MAXIMIZE_IDX] );
|
|
connect( button[MAXIMIZE_IDX], TQT_SIGNAL(clicked()),
|
|
this, TQT_SLOT(maximizeButtonClicked()) );
|
|
}
|
|
break;
|
|
|
|
case 'H':
|
|
if (providesContextHelp()) {
|
|
button[HELP_IDX] = new NextButton(this,
|
|
"help", question_bits, 10, 10, i18n("Help"));
|
|
titleLayout->addWidget( button[HELP_IDX] );
|
|
connect( button[HELP_IDX], TQT_SIGNAL(clicked()),
|
|
this, TQT_SLOT(showContextHelp()) );
|
|
}
|
|
break;
|
|
|
|
case 'I':
|
|
if (isMinimizable()) {
|
|
button[ICONIFY_IDX] =
|
|
new NextButton(this, "iconify", iconify_bits, 10, 10,
|
|
i18n("Minimize"));
|
|
titleLayout->addWidget( button[ICONIFY_IDX] );
|
|
connect( button[ICONIFY_IDX], TQT_SIGNAL(clicked()),
|
|
this, TQT_SLOT(minimize()) );
|
|
}
|
|
break;
|
|
|
|
case 'M':
|
|
button[MENU_IDX] =
|
|
new NextButton(this, "menu", NULL, 10, 10, i18n("Menu"), TQt::LeftButton|TQt::RightButton);
|
|
titleLayout->addWidget( button[MENU_IDX] );
|
|
// NOTE DIFFERENCE: capture pressed(), not clicked()
|
|
connect( button[MENU_IDX], TQT_SIGNAL(pressed()),
|
|
this, TQT_SLOT(menuButtonPressed()) );
|
|
break;
|
|
|
|
case 'L':
|
|
button[SHADE_IDX] =
|
|
new NextButton(this, "shade", NULL, 0, 0, i18n("Shade"));
|
|
titleLayout->addWidget( button[SHADE_IDX] );
|
|
connect( button[SHADE_IDX], TQT_SIGNAL(clicked()),
|
|
this, TQT_SLOT(shadeClicked()) );
|
|
// NOTE DIFFERENCE: set the pixmap separately (2 states)
|
|
shadeChange();
|
|
break;
|
|
|
|
case 'S':
|
|
button[STICKY_IDX] =
|
|
new NextButton(this, "sticky", NULL, 0, 0, i18n("On all desktops"));
|
|
titleLayout->addWidget( button[STICKY_IDX] );
|
|
connect( button[STICKY_IDX], TQT_SIGNAL(clicked()),
|
|
this, TQT_SLOT(toggleOnAllDesktops()) );
|
|
// NOTE DIFFERENCE: set the pixmap separately (2 states)
|
|
desktopChange();
|
|
break;
|
|
|
|
case 'F':
|
|
button[ABOVE_IDX] = new NextButton(this, "above", NULL, 0, 0, "");
|
|
titleLayout->addWidget( button[ABOVE_IDX] );
|
|
connect( button[ABOVE_IDX], TQT_SIGNAL(clicked()),
|
|
this, TQT_SLOT(aboveClicked()) );
|
|
connect(this, TQT_SIGNAL(keepAboveChanged(bool)),
|
|
TQT_SLOT(keepAboveChange(bool)));
|
|
keepAboveChange(keepAbove());
|
|
break;
|
|
|
|
case 'B':
|
|
button[BELOW_IDX] = new NextButton(this, "below", NULL, 0, 0, "");
|
|
titleLayout->addWidget( button[BELOW_IDX] );
|
|
connect( button[BELOW_IDX], TQT_SIGNAL(clicked()),
|
|
this, TQT_SLOT(belowClicked()) );
|
|
connect(this, TQT_SIGNAL(keepBelowChanged(bool)),
|
|
TQT_SLOT(keepBelowChange(bool)));
|
|
keepBelowChange(keepBelow());
|
|
break;
|
|
|
|
case 'X':
|
|
if (isCloseable()) {
|
|
button[CLOSE_IDX] =
|
|
new NextButton(this, "close", close_bits, 10, 10,
|
|
i18n("Close"));
|
|
titleLayout->addWidget(button[CLOSE_IDX]);
|
|
connect(button[CLOSE_IDX], TQT_SIGNAL(clicked()),
|
|
this, TQT_SLOT(closeWindow()));
|
|
}
|
|
break;
|
|
|
|
case 'R':
|
|
if (mustDrawHandle()) {
|
|
button[RESIZE_IDX] =
|
|
new NextButton(this, "resize", resize_bits, 10, 10,
|
|
i18n("Resize"));
|
|
titleLayout->addWidget(button[RESIZE_IDX]);
|
|
// NOTE DIFFERENCE: capture pressed(), not clicked()
|
|
connect(button[RESIZE_IDX], TQT_SIGNAL(pressed()),
|
|
this, TQT_SLOT(resizePressed()));
|
|
}
|
|
break;
|
|
case '_':
|
|
// TODO: Add spacer handling
|
|
break;
|
|
|
|
default:
|
|
kdDebug() << " Can't happen: unknown button code "
|
|
<< TQString(spec[i]);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool NextClient::mustDrawHandle() const
|
|
{
|
|
bool drawSmallBorders = !options()->moveResizeMaximizedWindows();
|
|
if (drawSmallBorders && (maximizeMode() & MaximizeVertical)) {
|
|
return false;
|
|
} else {
|
|
return isResizable();
|
|
}
|
|
}
|
|
|
|
void NextClient::iconChange()
|
|
{
|
|
if (button[MENU_IDX] && button[MENU_IDX]->isVisible())
|
|
button[MENU_IDX]->repaint(false);
|
|
}
|
|
|
|
void NextClient::menuButtonPressed()
|
|
{
|
|
// Probably don't need this null check, but we might as well.
|
|
if (button[MENU_IDX]) {
|
|
TQRect menuRect = button[MENU_IDX]->rect();
|
|
TQPoint menuTop = button[MENU_IDX]->mapToGlobal(menuRect.topLeft());
|
|
TQPoint menuBottom = button[MENU_IDX]->mapToGlobal(menuRect.bottomRight());
|
|
menuTop += TQPoint(1, 1);
|
|
menuBottom += TQPoint(1, 1);
|
|
KDecorationFactory* f = factory();
|
|
showWindowMenu(TQRect(menuTop, menuBottom));
|
|
if( !f->exists( this )) // 'this' was deleted
|
|
return;
|
|
button[MENU_IDX]->setDown(false);
|
|
}
|
|
}
|
|
|
|
// Copied, with minor edits, from TDEDefaultClient::slotMaximize()
|
|
void NextClient::maximizeButtonClicked()
|
|
{
|
|
if (button[MAXIMIZE_IDX]) {
|
|
maximize(button[MAXIMIZE_IDX]->lastButton());
|
|
}
|
|
}
|
|
|
|
void NextClient::shadeClicked()
|
|
{
|
|
setShade(!isSetShade());
|
|
}
|
|
|
|
void NextClient::aboveClicked()
|
|
{
|
|
setKeepAbove(!keepAbove());
|
|
}
|
|
|
|
void NextClient::belowClicked()
|
|
{
|
|
setKeepBelow(!keepBelow());
|
|
keepAboveChange(keepAbove());
|
|
keepBelowChange(keepBelow());
|
|
}
|
|
|
|
void NextClient::resizePressed()
|
|
{
|
|
performWindowOperation(ResizeOp);
|
|
}
|
|
|
|
void NextClient::resizeEvent(TQResizeEvent *)
|
|
{
|
|
if (widget()->isVisible()) {
|
|
// TODO ? update border area only?
|
|
widget()->update();
|
|
#if 0
|
|
widget()->update(titlebar->geometry());
|
|
TQPainter p(widget());
|
|
TQRect t = titlebar->geometry();
|
|
t.setTop( 0 );
|
|
TQRegion r = widget()->rect();
|
|
r = r.subtract( t );
|
|
p.setClipRegion( r );
|
|
p.eraseRect(widget()->rect());
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void NextClient::captionChange()
|
|
{
|
|
widget()->repaint(titlebar->geometry(), false);
|
|
}
|
|
|
|
|
|
void NextClient::paintEvent( TQPaintEvent* )
|
|
{
|
|
TQPainter p(widget());
|
|
|
|
// Draw black frame
|
|
TQRect fr = widget()->rect();
|
|
p.setPen(TQt::black);
|
|
p.drawRect(fr);
|
|
|
|
// Draw title bar
|
|
TQRect t = titlebar->geometry();
|
|
t.setTop(1);
|
|
p.drawTiledPixmap(t.x()+1, t.y()+1, t.width()-2, t.height()-2,
|
|
isActive() ? *aTitlePix : *iTitlePix);
|
|
qDrawShadePanel(&p, t.x(), t.y(), t.width(), t.height()-1,
|
|
options()->colorGroup(KDecoration::ColorTitleBar, isActive()));
|
|
p.drawLine(t.x(), t.bottom(), t.right(), t.bottom());
|
|
|
|
#if 0
|
|
// Why setting up a clipping region if it is not used? (setClipping(false))
|
|
TQRegion r = fr;
|
|
r = r.subtract( t );
|
|
p.setClipRegion( r );
|
|
p.setClipping(false);
|
|
#endif
|
|
|
|
t.setTop( 1 );
|
|
t.setHeight(t.height()-2);
|
|
t.setLeft( t.left() + 4 );
|
|
t.setRight( t.right() - 2 );
|
|
|
|
p.setPen(options()->color(KDecoration::ColorFont, isActive()));
|
|
p.setFont(options()->font(isActive()));
|
|
p.drawText( t, AlignCenter | AlignVCenter, caption() );
|
|
|
|
// Draw resize handle
|
|
if (mustDrawHandle()) {
|
|
int corner = 16 + 3*handleSize/2;
|
|
qDrawShadePanel(&p,
|
|
fr.x() + 1, fr.bottom() - handleSize, corner-1, handleSize,
|
|
options()->colorGroup(KDecoration::ColorHandle, isActive()),
|
|
false);
|
|
p.drawTiledPixmap(fr.x() + 2, fr.bottom() - handleSize + 1,
|
|
corner - 3, handleSize - 2, isActive() ? *aHandlePix : *iHandlePix);
|
|
|
|
qDrawShadePanel(&p,
|
|
fr.x() + corner, fr.bottom() - handleSize,
|
|
fr.width() - 2*corner, handleSize,
|
|
options()->colorGroup(KDecoration::ColorFrame, isActive()),
|
|
false);
|
|
p.drawTiledPixmap(fr.x() + corner + 1, fr.bottom() - handleSize + 1,
|
|
fr.width() - 2*corner - 2, handleSize - 2,
|
|
isActive() ? *aFramePix : *iFramePix);
|
|
|
|
qDrawShadePanel(&p,
|
|
fr.right() - corner + 1, fr.bottom() - handleSize, corner - 1, handleSize,
|
|
options()->colorGroup(KDecoration::ColorHandle, isActive()),
|
|
false);
|
|
p.drawTiledPixmap(fr.right() - corner + 2, fr.bottom() - handleSize + 1,
|
|
corner - 3, handleSize - 2, isActive() ? *aHandlePix : *iHandlePix);
|
|
}
|
|
}
|
|
|
|
void NextClient::mouseDoubleClickEvent( TQMouseEvent * e )
|
|
{
|
|
if (e->button() == TQt::LeftButton && titlebar->geometry().contains( e->pos() ) )
|
|
titlebarDblClickOperation();
|
|
}
|
|
|
|
void NextClient::wheelEvent( TQWheelEvent * e )
|
|
{
|
|
if (isSetShade() || TQRect( 0, 0, width(), titleHeight ).contains( e->pos() ) )
|
|
titlebarMouseWheelOperation( e->delta());
|
|
}
|
|
|
|
void NextClient::showEvent(TQShowEvent *)
|
|
{
|
|
widget()->repaint();
|
|
}
|
|
|
|
void NextClient::desktopChange()
|
|
{
|
|
bool on = isOnAllDesktops();
|
|
if (NextButton * b = button[STICKY_IDX]) {
|
|
b->setBitmap( on ? unsticky_bits : sticky_bits, 10, 10);
|
|
TQToolTip::remove(b);
|
|
TQToolTip::add(b, on ? i18n("Not on all desktops") : i18n("On all desktops"));
|
|
}
|
|
}
|
|
|
|
void NextClient::maximizeChange()
|
|
{
|
|
if (button[MAXIMIZE_IDX]) {
|
|
bool m = maximizeMode() == MaximizeFull;
|
|
//button[MAXIMIZE_IDX]->setBitmap(m ? minmax_bits : maximize_bits);
|
|
TQToolTip::remove(button[MAXIMIZE_IDX]);
|
|
TQToolTip::add(button[MAXIMIZE_IDX],
|
|
m ? i18n("Restore") : i18n("Maximize"));
|
|
}
|
|
//spacer->changeSize(10, mustDrawHandle() ? handleSize : 1,
|
|
// TQSizePolicy::Expanding, TQSizePolicy::Minimum);
|
|
//mainLayout->activate();
|
|
}
|
|
|
|
void NextClient::activeChange()
|
|
{
|
|
widget()->repaint(false);
|
|
slotReset();
|
|
}
|
|
|
|
void NextClient::slotReset()
|
|
{
|
|
for (int i=0; i<MAX_NUM_BUTTONS; i++) {
|
|
if (button[i]) {
|
|
button[i]->reset();
|
|
}
|
|
}
|
|
}
|
|
|
|
KDecoration::Position
|
|
NextClient::mousePosition( const TQPoint& p ) const
|
|
{
|
|
Position m = PositionCenter;
|
|
|
|
if (p.y() < (height() - handleSize))
|
|
m = KDecoration::mousePosition(p);
|
|
|
|
else {
|
|
int corner = 16 + 3*handleSize/2;
|
|
if (p.x() >= (width() - corner))
|
|
m = PositionBottomRight;
|
|
else if (p.x() <= corner)
|
|
m = PositionBottomLeft;
|
|
else
|
|
m = PositionBottom;
|
|
}
|
|
|
|
return m;
|
|
}
|
|
|
|
void NextClient::borders(int &left, int &right, int &top, int &bottom) const
|
|
{
|
|
left = right = 1;
|
|
top = titleHeight; // FRAME is this ok?
|
|
bottom = mustDrawHandle() ? handleSize : 1;
|
|
}
|
|
|
|
void NextClient::shadeChange()
|
|
{
|
|
if (NextButton *b = button[SHADE_IDX]) {
|
|
b->setBitmap(isSetShade() ? unshade_bits : shade_bits, 10, 10);
|
|
TQToolTip::remove(b);
|
|
TQToolTip::add(b, isSetShade() ? i18n("Unshade") : i18n("Shade"));
|
|
}
|
|
}
|
|
|
|
void NextClient::keepAboveChange(bool above)
|
|
{
|
|
if (NextButton *b = button[ABOVE_IDX]) {
|
|
b->setBitmap(above ? from_above_bits : keep_above_bits, 10, 10);
|
|
TQToolTip::remove(b);
|
|
TQToolTip::add(b, above ?
|
|
i18n("Do not keep above others") : i18n("Keep above others"));
|
|
b->repaint(false);
|
|
}
|
|
}
|
|
|
|
void NextClient::keepBelowChange(bool below)
|
|
{
|
|
if (NextButton *b = button[BELOW_IDX]) {
|
|
b->setBitmap(below ? from_below_bits : keep_below_bits, 10, 10);
|
|
TQToolTip::remove(b);
|
|
TQToolTip::add(b, below ?
|
|
i18n("Do not keep below others") : i18n("Keep below others"));
|
|
b->repaint(false);
|
|
}
|
|
}
|
|
|
|
TQSize NextClient::minimumSize() const
|
|
{
|
|
return TQSize(titleHeight * 6 + 2, titleHeight + handleSize + 2);
|
|
}
|
|
|
|
void NextClient::resize(const TQSize& s)
|
|
{
|
|
widget()->resize(s);
|
|
}
|
|
|
|
void NextClient::reset(unsigned long)
|
|
{
|
|
for (int i = 0; i < MAX_NUM_BUTTONS; ++i) {
|
|
if (button[i])
|
|
button[i]->reset();
|
|
}
|
|
widget()->repaint();
|
|
}
|
|
|
|
bool NextClient::eventFilter(TQObject *o, TQEvent *e)
|
|
{
|
|
if (o != widget())
|
|
return false;
|
|
switch (e->type()) {
|
|
case TQEvent::Resize:
|
|
resizeEvent(TQT_TQRESIZEEVENT( e ));
|
|
return true;
|
|
case TQEvent::Paint:
|
|
paintEvent(TQT_TQPAINTEVENT( e ));
|
|
return true;
|
|
case TQEvent::MouseButtonDblClick:
|
|
mouseDoubleClickEvent(TQT_TQMOUSEEVENT( e ));
|
|
return true;
|
|
case TQEvent::Wheel:
|
|
wheelEvent( TQT_TQWHEELEVENT( e ));
|
|
return true;
|
|
case TQEvent::MouseButtonPress:
|
|
processMousePressEvent(TQT_TQMOUSEEVENT( e ));
|
|
return true;
|
|
case TQEvent::Show:
|
|
showEvent(TQT_TQSHOWEVENT( e ));
|
|
return true;
|
|
default:
|
|
break;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool NextClient::drawbound(const TQRect& geom, bool /* clear */)
|
|
{
|
|
TQPainter p(workspaceWidget());
|
|
p.setPen(TQPen(TQt::white, 3));
|
|
p.setRasterOp(TQt::XorROP);
|
|
p.drawRect(geom);
|
|
int leftMargin = geom.left() + 2;
|
|
p.fillRect(leftMargin, geom.top() + titleHeight - 1,
|
|
geom.width() - 4, 3, TQt::white);
|
|
if (mustDrawHandle()) {
|
|
p.fillRect(leftMargin, geom.bottom() - handleSize - 1,
|
|
geom.width() - 4, 3, TQt::white);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// =====================================
|
|
|
|
NextClientFactory::NextClientFactory()
|
|
{
|
|
TDEGlobal::locale()->insertCatalogue("twin_clients");
|
|
TDEGlobal::locale()->insertCatalogue("twin_art_clients");
|
|
create_pixmaps(this);
|
|
}
|
|
|
|
NextClientFactory::~NextClientFactory()
|
|
{
|
|
delete_pixmaps();
|
|
}
|
|
|
|
KDecoration *NextClientFactory::createDecoration(KDecorationBridge *b)
|
|
{
|
|
return new NextClient(b, this);
|
|
}
|
|
|
|
bool NextClientFactory::reset(unsigned long /*changed*/)
|
|
{
|
|
// TODO Do not recreate decorations if it is not needed. Look at
|
|
// ModernSystem for how to do that
|
|
delete_pixmaps();
|
|
create_pixmaps(this);
|
|
// For now just return true.
|
|
return true;
|
|
}
|
|
|
|
bool NextClientFactory::supports( Ability ability )
|
|
{
|
|
switch( ability )
|
|
{
|
|
case AbilityAnnounceButtons:
|
|
case AbilityButtonMenu:
|
|
case AbilityButtonOnAllDesktops:
|
|
case AbilityButtonHelp:
|
|
case AbilityButtonMinimize:
|
|
case AbilityButtonMaximize:
|
|
case AbilityButtonClose:
|
|
case AbilityButtonAboveOthers:
|
|
case AbilityButtonBelowOthers:
|
|
case AbilityButtonShade:
|
|
case AbilityButtonResize:
|
|
return true;
|
|
default:
|
|
return false;
|
|
};
|
|
}
|
|
|
|
TQValueList< NextClientFactory::BorderSize >
|
|
NextClientFactory::borderSizes() const
|
|
{
|
|
// the list must be sorted
|
|
return TQValueList< BorderSize >() << BorderTiny << BorderNormal <<
|
|
BorderLarge << BorderVeryLarge << BorderHuge <<
|
|
BorderVeryHuge << BorderOversized;
|
|
}
|
|
|
|
} // KStep namespace
|
|
|
|
extern "C" KDE_EXPORT KDecorationFactory* create_factory()
|
|
{
|
|
return new KStep::NextClientFactory();
|
|
}
|
|
|
|
#include "nextclient.moc"
|