//////////////////////////////////////////////////////////////////////////////
// smoothblend.cpp
// -------------------
// Smooth Blend window decoration for TDE
// -------------------
// Copyright (c) 2005 Ryan Nickell
// Please see the header file for copyright and license information.
//////////////////////////////////////////////////////////////////////////////

#include <tdeconfig.h>
#include <tdeversion.h>
#include <tdeglobal.h>
#include <tdeglobalsettings.h>
#include <tdeglobal.h>
#include <tdelocale.h>
#include <kpixmap.h>
#include <kimageeffect.h>
#include <kpixmapeffect.h>
#include <kpixmap.h>

#include <tqbitmap.h>
#include <tqlabel.h>
#include <tqlayout.h>
#include <tqpainter.h>
#include <tqtooltip.h>
#include <tqtimer.h>
#include <tqapplication.h>

#include "smoothblend.h"
#include "buttons.h"

using namespace smoothblend;

//////////////////////////////////////////////////////////////////////////////
// smoothblendFactory Class
//////////////////////////////////////////////////////////////////////////////
smoothblendFactory* factory=NULL;

bool smoothblendFactory::initialized_              = false;
TQt::AlignmentFlags smoothblendFactory::titlealign_ = TQt::AlignHCenter;
bool smoothblendFactory::cornerflags_               = true;
int smoothblendFactory::titlesize_                 = 30;
int smoothblendFactory::buttonsize_                = 26;
int smoothblendFactory::framesize_                 = 4;
int smoothblendFactory::roundsize_                 = 50;
bool smoothblendFactory::titleshadow_              = true;
bool smoothblendFactory::animatebuttons            = true;
int smoothblendFactory::btnComboBox                = 0;
bool smoothblendFactory::menuClose                 = false;

// global constants
static const int TOPMARGIN       = 4; // do not change
static const int DECOHEIGHT      = 4; // do not change
static const int SIDETITLEMARGIN = 2;
// Default button layout
const char default_left[]  = "M";
const char default_right[] = "HIAX";

static const uint TIMERINTERVAL = 50; // msec
static const uint ANIMATIONSTEPS = 4;

extern "C"
{
	TDE_EXPORT KDecorationFactory* create_factory()
	{
		return new smoothblend::smoothblendFactory();
	}
}

//////////////////////////////////////////////////////////////////////////////
// smoothblendFactory()
// ----------------
// Constructor

smoothblendFactory::smoothblendFactory() {
    TDEGlobal::locale()->insertCatalogue("twin_clients");
    TDEGlobal::locale()->insertCatalogue("twin_art_clients");
    readConfig();
    initialized_ = true;
}

//////////////////////////////////////////////////////////////////////////////
// ~smoothblendFactory()
// -----------------
// Destructor

smoothblendFactory::~smoothblendFactory() {
    initialized_ = false;
}

//////////////////////////////////////////////////////////////////////////////
// createDecoration()
// -----------------
// Create the decoration

KDecoration* smoothblendFactory::createDecoration(KDecorationBridge* b) {
    return new smoothblendClient(b, this);
}

//////////////////////////////////////////////////////////////////////////////
// reset()
// -------
// Reset the handler. Returns true if decorations need to be remade, false if
// only a repaint is necessary

bool smoothblendFactory::reset(unsigned long changed) {
    // read in the configuration
    initialized_ = false;
    bool confchange = readConfig();
    initialized_ = true;

    if (confchange ||
            (changed & (SettingDecoration | SettingButtons | SettingBorder))) {
        return true;
    } else {
        resetDecorations(changed);
        return false;
    }
}

//////////////////////////////////////////////////////////////////////////////
// readConfig()
// ------------
// Read in the configuration file

bool smoothblendFactory::readConfig() {
    // create a config object
    TDEConfig config("twinsmoothblendrc");
    config.setGroup("General");

    // grab settings
    TQString value = config.readEntry("TitleAlignment", "AlignHCenter");
    if (value == "AlignLeft")
        titlealign_ = TQt::AlignLeft;
    else if (value == "AlignHCenter")
        titlealign_ = TQt::AlignHCenter;
    else if (value == "AlignRight")
        titlealign_ = TQt::AlignRight;

    cornerflags_ = config.readBoolEntry("RoundCorners", true);
    titlesize_ = config.readNumEntry("TitleSize",30);
    buttonsize_ = config.readNumEntry("ButtonSize",26);
    framesize_ = config.readNumEntry("FrameSize",4);
    roundsize_ = config.readNumEntry("RoundPercent",50);
    titleshadow_ = config.readBoolEntry("TitleShadow", true);
    animatebuttons = config.readBoolEntry("AnimateButtons", true);
    btnComboBox = config.readNumEntry("ButtonComboBox", 0);
    menuClose = config.readBoolEntry("CloseOnMenuDoubleClick");

    if(buttonsize_ > titlesize_ - framesize_)
    {
        buttonsize_ = titlesize_-framesize_;
    }

    return true;
}

//////////////////////////////////////////////////////////////////////////////
// smoothblendButton Class 
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
// smoothblendButton()
// ---------------
// Constructor
smoothblendButton::smoothblendButton(smoothblendClient *parent, const char *name, const TQString& tip, ButtonType type, int button_size, bool toggle): TQButton(parent->widget(), name), 
     client_(parent), 
     type_(type), 
     size_(button_size), 
     deco_(0), 
     lastmouse_(TQt::NoButton), 
     hover_(false)
{
    setBackgroundMode(NoBackground);
    setFixedSize( ::factory->buttonSize(), ::factory->buttonSize());
    setCursor(arrowCursor);
    TQToolTip::add(this, tip);
    setToggleButton(toggle);
    //button animation setup
    animTmr = new TQTimer(this);
    connect(animTmr, TQ_SIGNAL(timeout() ), this, TQ_SLOT(animate() ) );
    connect(this, TQ_SIGNAL(pressed() ), this, TQ_SLOT(buttonClicked() ) );
    connect(this, TQ_SIGNAL(released() ), this, TQ_SLOT(buttonReleased() ) );
    animProgress = 0;
    m_clicked=false;
}

smoothblendButton::~smoothblendButton() {
    if ( deco_ )
        delete deco_;
}

//////////////////////////////////////////////////////////////////////////////
// sizeHint()
// ----------
// Return size hint

TQSize smoothblendButton::sizeHint() const {
    return TQSize(::factory->buttonSize(), ::factory->buttonSize());
}

//////////////////////////////////////////////////////////////////////////////
// buttonClicked()
// ----------
// Button animation progress reset so we don't get any leave event animation
// when the mouse is still pressed
void smoothblendButton::buttonClicked() {
    m_clicked=true;
    animProgress=0;
}
void smoothblendButton::buttonReleased() {
    //This doesn't work b/c a released() signal is thrown when a leaveEvent occurs
    //m_clicked=false;
}

//////////////////////////////////////////////////////////////////////////////
// animate()
// ----------
// Button animation timing
void smoothblendButton::animate() {
    animTmr->stop();

    if(hover_) {
        if(animProgress < ANIMATIONSTEPS) {
            if (::factory->animateButtons() ) {
                animProgress++;
            } else {
                animProgress = ANIMATIONSTEPS;
            }
            animTmr->start(TIMERINTERVAL, true); // single-shot
        }
    } else {
        if(animProgress > 0) {
            if (::factory->animateButtons() ) {
                animProgress--;
            } else {
                animProgress = 0;
            }
            animTmr->start(TIMERINTERVAL, true); // single-shot
        }
    }
    repaint(false);
}
//////////////////////////////////////////////////////////////////////////////
// enterEvent()
// ------------
// Mouse has entered the button

void smoothblendButton::enterEvent(TQEvent *e) {
    // we wanted to pass on the event
    TQButton::enterEvent(e);
    // we want to do mouseovers, so keep track of it here
    hover_=true;
    if(!m_clicked)
    {
        animate();
    }
}

//////////////////////////////////////////////////////////////////////////////
// leaveEvent()
// ------------
// Mouse has left the button

void smoothblendButton::leaveEvent(TQEvent *e) {
    // we wanted to pass on the event
    TQButton::leaveEvent(e);
    // we want to do mouseovers, so keep track of it here
    hover_=false; 
    if(!m_clicked)
    {
        animate();
    }
}

//////////////////////////////////////////////////////////////////////////////
// mousePressEvent()
// -----------------
// Button has been pressed

void smoothblendButton::mousePressEvent(TQMouseEvent* e) {
    lastmouse_ = e->button();

    // translate and pass on mouse event
    int button = TQt::LeftButton;
    if ((type_ != ButtonMax) && (e->button() != TQt::LeftButton)) {
        button = TQt::NoButton; // middle & right buttons inappropriate
    }
    TQMouseEvent me(e->type(), e->pos(), e->globalPos(),
                   button, e->state());
    TQButton::mousePressEvent(&me);
}

//////////////////////////////////////////////////////////////////////////////
// mouseReleaseEvent()
// -----------------
// Button has been released

void smoothblendButton::mouseReleaseEvent(TQMouseEvent* e) {
    lastmouse_ = e->button();

    // translate and pass on mouse event
    int button = TQt::LeftButton;
    if ((type_ != ButtonMax) && (e->button() != TQt::LeftButton)) {
        button = TQt::NoButton; // middle & right buttons inappropriate
    }
    TQMouseEvent me(e->type(), e->pos(), e->globalPos(), button, e->state());
    TQButton::mouseReleaseEvent(&me);
    if(m_clicked)
    {
        m_clicked=false;
    }
}

void smoothblendButton::setOn(bool on)
{
    TQButton::setOn(on);
}

void smoothblendButton::setDown(bool on)
{
    TQButton::setDown(on);
}

//////////////////////////////////////////////////////////
// getButtonImage()
// ----------------
// get the button TQImage based on type and window mode
TQImage smoothblendButton::getButtonImage(ButtonType type)
{
    TQImage finalImage;
    switch(type) {
        case ButtonClose:
            finalImage = uic_findImage( "close.png" );
            break;
        case ButtonHelp:
            finalImage = uic_findImage( "help.png" );
            break;
        case ButtonMin:
            finalImage = uic_findImage( "minimize.png" );
            break;
        case ButtonMax:
            if(client_->maximizeMode() == KDecorationDefines::MaximizeFull)
            {
                finalImage = uic_findImage( "restore.png" );
            }
            else
            {
                finalImage = uic_findImage( "maximize.png" );
            }
            break;
        case ButtonSticky:
            if(client_->isOnAllDesktops())
            {
                finalImage = uic_findImage( "splat.png" );
            }
            else
            {
                finalImage = uic_findImage( "circle.png" );
            }
            break;
        case ButtonShade:
            if(client_->isShade())
            {
                finalImage = uic_findImage( "shade.png" );
            }
            else
            {
                finalImage = uic_findImage( "shade.png" );
            }
            break;
        case ButtonAbove:
            if(client_->keepAbove())
            {
                finalImage = uic_findImage( "keep_above_lit.png" );
            }
            else
            {
                finalImage = uic_findImage( "keep_above.png" );
            }
            break;
        case ButtonBelow:
            if(client_->keepBelow())
            {
                finalImage = uic_findImage( "keep_below_lit.png" );
            }
            else
            {
                finalImage = uic_findImage( "keep_below.png" );
            }
            break;
        default:
            finalImage = uic_findImage( "splat.png" );
            break;
    }
    return finalImage;
}

//////////////////////////////////////////////////////////
// drawButton()
// -------------------------
// draw the pixmap button

void smoothblendButton::drawButton( TQPainter *painter ) {
    if ( !smoothblendFactory::initialized() )
        return ;
    
    int newWidth = width() - 2;
    int newHeight = height() - 2;
    int dx = (width() - newWidth) / 2;
    int dy = (height() - newHeight) / 2;
    TQImage tmpResult;
    TQColorGroup group;
    TQColor redColor(red);
    bool active = client_->isActive();
    TQPixmap backgroundTile = client_->getTitleBarTile(active);
    group = KDecoration::options()->colorGroup(KDecoration::ColorTitleBar, active);

    //draw the titlebar behind the buttons and app icons
    if ((client_->maximizeMode()==client_->MaximizeFull) && !KDecoration::options()->moveResizeMaximizedWindows())
    {
        painter->drawTiledPixmap(0, 0, width(), height(), backgroundTile);
    }
    else
    {
        painter->drawTiledPixmap(0, 0, width(), height(), backgroundTile, 0, y()-::factory->frameSize());
    }
    
    TQImage buttonImage = getButtonImage(type_).smoothScale( width(),height());
    buttonImage = KImageEffect::blend( group.background(), buttonImage, .50);
    if (type_ == ButtonMenu) {
        //slight movement to show the menu button is depressed
        if (isDown()) {
            dx++;
            dy++;
        }
        TQPixmap menuButtonPixmap(client_->icon().pixmap(TQIconSet::Large, TQIconSet::Normal));
        TQImage menuButtonImage(menuButtonPixmap.convertToImage());
        //draw the menu button the same size as the other buttons
        //using TQIconSet::Large gives us a 32x32 icon to resize, resizing larger than
        //that may produce pixilation of the image
        painter->drawImage( dx, dy, menuButtonImage.smoothScale(newWidth, newHeight) );
    } else {
        //highlight on a mouse over repaint
        double factor = animProgress * 0.13;

        if(!isDown())
        {
            switch(::factory->getBtnComboBox())
            {
                case 0:
                    tmpResult = KImageEffect::intensity( buttonImage, factor);
                    break;
                case 1:
                    tmpResult = KImageEffect::fade( buttonImage, factor, group.background());
                    break;
            }
        }
        else
        {
            tmpResult = buttonImage;
        }
        painter->drawPixmap( 0, 0, TQPixmap( tmpResult ) );
    }
}


//////////////////////////////////////////////////////////////////////////////
// smoothblendClient Class
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
// smoothblendClient()
// ---------------
// Constructor

smoothblendClient::smoothblendClient(KDecorationBridge *b, KDecorationFactory *f)
    : KDecoration(b, f),
    mainLayout_(0),
    titleLayout_(0),
    topSpacer_(0),
    titleSpacer_(0),
    leftTitleSpacer_(0), rightTitleSpacer_(0),
    decoSpacer_(0),
    leftSpacer_(0), rightSpacer_(0),
    bottomSpacer_(0), windowSpacer_(0),
    aCaptionBuffer(0), iCaptionBuffer(0),
    aTitleBarTile(0), iTitleBarTile(0), aTitleBarTopTile(0), iTitleBarTopTile(0),
    pixmaps_created(false),
    //captionBufferDirty(true),
    s_titleHeight(0),
    s_titleFont(TQFont()),
    closing(false)
    {
        aCaptionBuffer = new TQPixmap();
        iCaptionBuffer = new TQPixmap();
        //s_titleFont = isTool()?smoothblendFactory::titleFontTool():smoothblendFactory::titleFont();
        s_titleFont = options()->font();
        s_titleHeight = smoothblendFactory::titleSize();
    }
//////////////////////////////////////////////////////////////////////////////////
// ~smoothblendClient()
// --------------------
// Destructor
smoothblendClient::~smoothblendClient() {
    delete aCaptionBuffer;
    delete iCaptionBuffer;
}

void smoothblendClient::create_pixmaps() {
    if(pixmaps_created)
        return;
    KPixmap tempPixmap;
    TQPainter painter;
    TQColorGroup group,widgetGroup;
    int FRAMESIZE = ::factory->frameSize();
    // Get the color groups we need for the gradients
    group = options()->colorGroup(KDecoration::ColorTitleBar, true);
    widgetGroup = widget()->colorGroup();
    
    // active top title bar tile
    tempPixmap.resize(1, TOPMARGIN);
    tempPixmap = KPixmapEffect::unbalancedGradient(tempPixmap,
                                                   group.background(),
                                                   widgetGroup.background(),
                                                   KPixmapEffect::VerticalGradient,
                                                   100,
                                                   -100);
    aTitleBarTopTile = new TQPixmap(1, TOPMARGIN);
    painter.begin(aTitleBarTopTile);
    painter.drawPixmap(0, 0, tempPixmap);
    painter.end();
    
    // inactive top title bar tile
    group = options()->colorGroup(KDecoration::ColorTitleBar, false);
    tempPixmap = KPixmapEffect::unbalancedGradient(tempPixmap,
                                                   group.background(),
                                                   widgetGroup.background(),
                                                   KPixmapEffect::VerticalGradient,
                                                   100,
                                                   -100);
    iTitleBarTopTile = new TQPixmap(1, TOPMARGIN);
    painter.begin(iTitleBarTopTile);
    painter.drawPixmap(0, 0, tempPixmap);
    painter.end();
    
    // active title bar tile
    tempPixmap.resize(1, s_titleHeight+FRAMESIZE);
    group = options()->colorGroup(KDecoration::ColorTitleBar, true);
    tempPixmap = KPixmapEffect::unbalancedGradient(tempPixmap,
                                                   group.background(),
                                                   widgetGroup.background(),
                                                   KPixmapEffect::VerticalGradient,
                                                   100,
                                                   200);
    aTitleBarTile = new TQPixmap(1, s_titleHeight+FRAMESIZE);
    painter.begin(aTitleBarTile);
    painter.drawPixmap(0, 0, tempPixmap);
    painter.end();
    
    // inactive title bar tile
    group = options()->colorGroup(KDecoration::ColorTitleBar, false);
    tempPixmap = KPixmapEffect::unbalancedGradient(tempPixmap,
                                                   group.background(),
                                                   widgetGroup.background(),
                                                   KPixmapEffect::VerticalGradient,
                                                   100,
                                                   200);
    iTitleBarTile = new TQPixmap(1, s_titleHeight+FRAMESIZE);
    painter.begin(iTitleBarTile);
    painter.drawPixmap(0, 0, tempPixmap);
    painter.end();

    pixmaps_created = true;
}

void smoothblendClient::delete_pixmaps() {
    delete aTitleBarTopTile;
    aTitleBarTopTile = 0;

    delete iTitleBarTopTile;
    iTitleBarTopTile = 0;

    delete aTitleBarTile;
    aTitleBarTile = 0;

    delete iTitleBarTile;
    iTitleBarTile = 0;

    pixmaps_created = false;
}
//////////////////////////////////////////////////////////////////////////////
// init()
// ------
// Actual initializer for class

void smoothblendClient::init() {
    createMainWidget(WResizeNoErase | WRepaintNoErase);
    widget()->installEventFilter(this);
    handlebar = ::factory->frameSize() < 4 ? 4 - ::factory->frameSize() : 0;
    // for flicker-free redraws
    widget()->setBackgroundMode(NoBackground);

    _resetLayout();

    create_pixmaps();
}
void smoothblendClient::_resetLayout()
{
    // basic layout:
    //  _______________________________________________________________
    // |                         topSpacer                             |
    // |_______________________________________________________________|
    // | leftTitleSpacer | btns |  titlebar   | bts | rightTitleSpacer |
    // |_________________|______|_____________|_____|__________________|
    // |                         decoSpacer                            |
    // |_______________________________________________________________|
    // | |                                                           | |
    // | |                      windowWrapper                        | |
    // | |                                                           | |
    // |leftSpacer                                          rightSpacer|
    // |_|___________________________________________________________|_|
    // |                           bottomSpacer                        |
    // |_______________________________________________________________|
    //
    if (!::factory->initialized()) return;
    
    delete mainLayout_;
    delete titleLayout_;
    delete topSpacer_;
    delete titleSpacer_;
    delete leftTitleSpacer_;
    delete rightTitleSpacer_;
    delete decoSpacer_;
    delete leftSpacer_;
    delete rightSpacer_;
    delete bottomSpacer_;
    delete windowSpacer_;

    mainLayout_ = new TQVBoxLayout(widget());
    // title
    titleLayout_ = new TQHBoxLayout();
    TQHBoxLayout *windowLayout_ = new TQHBoxLayout();
    int FRAMESIZE = ::factory->frameSize();

    topSpacer_        = new TQSpacerItem(1, FRAMESIZE, TQSizePolicy::Expanding, TQSizePolicy::Fixed);
    titlebar_         = new TQSpacerItem(1, ::factory->buttonSize(),
                                        TQSizePolicy::Expanding, TQSizePolicy::Fixed);
    leftTitleSpacer_  = new TQSpacerItem(FRAMESIZE, s_titleHeight,
                                        TQSizePolicy::Fixed, TQSizePolicy::Fixed);
    rightTitleSpacer_ = new TQSpacerItem(FRAMESIZE, s_titleHeight,
                                        TQSizePolicy::Fixed, TQSizePolicy::Fixed);
    decoSpacer_       = new TQSpacerItem(1, FRAMESIZE, TQSizePolicy::Expanding, TQSizePolicy::Fixed);
    leftSpacer_       = new TQSpacerItem(::factory->frameSize(), 1,
                                        TQSizePolicy::Fixed, TQSizePolicy::Expanding);
    rightSpacer_      = new TQSpacerItem(::factory->frameSize(), 1,
                                        TQSizePolicy::Fixed, TQSizePolicy::Expanding);
    bottomSpacer_     = new TQSpacerItem(1, ::factory->frameSize(),
                                        TQSizePolicy::Expanding, TQSizePolicy::Fixed);
    
    // sizeof(...) is calculated at compile time
    memset(button, 0, sizeof(smoothblendButton *) * ButtonTypeCount);

    // message in preview widget
    if (isPreview()) {
        windowLayout_->addWidget(
            new TQLabel( i18n("<b><center>Smooth Blend</center></b>"), widget() ), 1 ); 
    } else {
        windowLayout_->addItem(new TQSpacerItem(0, 0));
    }

    // setup titlebar buttons
    for (int n=0; n<ButtonTypeCount; n++)
        button[n] = 0;
    //Deal with the title and buttons
    titleLayout_->addItem(leftTitleSpacer_);
    addButtons(titleLayout_,
               options()->customButtonPositions() ? options()->titleButtonsLeft() : TQString(default_left),
               ::factory->titleSize()-1);
    titleLayout_->addItem(titlebar_);
    addButtons(titleLayout_,
               options()->customButtonPositions() ? options()->titleButtonsRight() : TQString(default_right),
               ::factory->titleSize()-1);
    titleLayout_->addItem(rightTitleSpacer_);

    //Mid - left side, middle contents and right side
    TQHBoxLayout * midLayout_   = new TQHBoxLayout();
    midLayout_->addItem(leftSpacer_);
    midLayout_->addLayout(windowLayout_);
    midLayout_->addItem(rightSpacer_);

    //Layout order
    mainLayout_->addItem( topSpacer_ );
    mainLayout_->addLayout( titleLayout_ );
    mainLayout_->addItem( decoSpacer_ );
    mainLayout_->addLayout( midLayout_ );
    mainLayout_->addItem( bottomSpacer_ );
    
    // connections
    connect(this, TQ_SIGNAL(keepAboveChanged(bool)), TQ_SLOT(keepAboveChange(bool)));
    connect(this, TQ_SIGNAL(keepBelowChanged(bool)), TQ_SLOT(keepBelowChange(bool)));
}

//////////////////////////////////////////////////////////////////////////////
// addButtons()
// ------------
// Add buttons to title layout

void smoothblendClient::addButtons(TQBoxLayout *layout, const TQString& s, int button_size) {
    TQString tip;
    if (s.length() > 0) {
        for (unsigned n=0; n < s.length(); n++) {
            switch (s[n]) {
            case 'M': // Menu button
                if (!button[ButtonMenu]) {
                    button[ButtonMenu] =
                        new smoothblendButton(this, "splat.png", i18n("Menu"),ButtonMenu,button_size);
                    connect(button[ButtonMenu], TQ_SIGNAL(pressed()), this, TQ_SLOT(menuButtonPressed()));
                    connect(button[ButtonMenu], TQ_SIGNAL(released()), this, TQ_SLOT(menuButtonReleased()));
                    layout->addWidget(button[ButtonMenu]);
                    if (n < s.length()-1) layout->addSpacing(1);
                }
                break;

            case 'S': // Sticky button
                if (!button[ButtonSticky]) {
                    if (isOnAllDesktops()) {
                        tip = i18n("Un-Sticky");
                    } else {
                        tip = i18n("Sticky");
                    }
                    button[ButtonSticky] =
                        new smoothblendButton(this, "circle.png", tip, ButtonSticky, button_size, true);
                    connect(button[ButtonSticky], TQ_SIGNAL(clicked()),
                            this, TQ_SLOT(toggleOnAllDesktops()));
                    layout->addWidget(button[ButtonSticky]);
                    if (n < s.length()-1) layout->addSpacing(1);
                }
                break;

            case 'H': // Help button
                if ((!button[ButtonHelp]) && providesContextHelp()) {
                    button[ButtonHelp] =
                        new smoothblendButton(this, "help.png", i18n("Help"), ButtonHelp, button_size);
                    connect(button[ButtonHelp], TQ_SIGNAL(clicked()),
                            this, TQ_SLOT(showContextHelp()));
                    layout->addWidget(button[ButtonHelp]);
                    if (n < s.length()-1) layout->addSpacing(1);
                }
                break;

            case 'I': // Minimize button
                if ((!button[ButtonMin]) && isMinimizable())  {
                    button[ButtonMin] =
                        new smoothblendButton(this, "minimize.png", i18n("Minimize"), ButtonMin, button_size);
                    connect(button[ButtonMin], TQ_SIGNAL(clicked()),
                            this, TQ_SLOT(minimize()));
                    layout->addWidget(button[ButtonMin]);
                    if (n < s.length()-1) layout->addSpacing(1);
                }
                break;

            case 'A': // Maximize button
                if ((!button[ButtonMax]) && isMaximizable()) {
                    if (maximizeMode() == MaximizeFull) {
                        tip = i18n("Restore");
                    } else {
                        tip = i18n("Maximize");
                    }
                    button[ButtonMax]  =
                        new smoothblendButton(this, "maximize.png", tip, ButtonMax, button_size, true);
                    connect(button[ButtonMax], TQ_SIGNAL(clicked()),
                            this, TQ_SLOT(maxButtonPressed()));
                    layout->addWidget(button[ButtonMax]);
                    if (n < s.length()-1) layout->addSpacing(1);
                }
                break;

            case 'X': // Close button
                if ((!button[ButtonClose]) && isCloseable()) {
                    button[ButtonClose] =
                        new smoothblendButton(this, "close.png", i18n("Close"), ButtonClose, button_size);
                    connect(button[ButtonClose], TQ_SIGNAL(clicked()),
                            this, TQ_SLOT(closeWindow()));
                    layout->addWidget(button[ButtonClose]);
                    if (n < s.length()-1) layout->addSpacing(1);
                }
                break;

            case 'F': // Above button
                if ((!button[ButtonAbove])) {
                    button[ButtonAbove] =
                        new smoothblendButton(this, "keep_above.png",
                                          i18n("Keep Above Others"), ButtonAbove, button_size, true);
                    connect(button[ButtonAbove], TQ_SIGNAL(clicked()),
                            this, TQ_SLOT(aboveButtonPressed()));
                    layout->addWidget(button[ButtonAbove]);
                    if (n < s.length()-1) layout->addSpacing(1);
                }
                break;

            case 'B': // Below button
                if ((!button[ButtonBelow])) {
                    button[ButtonBelow] =
                        new smoothblendButton(this, "keep_below.png",
                                          i18n("Keep Below Others"), ButtonBelow, button_size, true);
                    connect(button[ButtonBelow], TQ_SIGNAL(clicked()),
                            this, TQ_SLOT(belowButtonPressed()));
                    layout->addWidget(button[ButtonBelow]);
                    if (n < s.length()-1) layout->addSpacing(1);
                }
                break;

            case 'L': // Shade button
                if ((!button[ButtonShade]) && isShadeable()) {
                    if ( isSetShade()) {
                        tip = i18n("Unshade");
                    } else {
                        tip = i18n("Shade");
                    }
                    button[ButtonShade] =
                        new smoothblendButton(this, "shade.png", tip, ButtonShade, button_size, true);
                    connect(button[ButtonShade], TQ_SIGNAL(clicked()),
                            this, TQ_SLOT(shadeButtonPressed()));
                    layout->addWidget(button[ButtonShade]);
                    if (n < s.length()-1) layout->addSpacing(1);
                }
                break;

            case '_': // Spacer item
                layout->addSpacing(::factory->frameSize());
            }
        }
    }
}

//////////////////////////////////////////////////////////////////////////////
// activeChange()
// --------------
// window active state has changed

void smoothblendClient::activeChange() {
    for (int n=0; n<ButtonTypeCount; n++)
        if (button[n])
            button[n]->reset();
    widget()->repaint(false);
}

//////////////////////////////////////////////////////////////////////////////
// captionChange()
// ---------------
// The title has changed

void smoothblendClient::captionChange() {
    widget()->repaint(titlebar_->geometry(), false);
}

//////////////////////////////////////////////////////////////////////////////
// desktopChange()
// ---------------
// Called when desktop/sticky changes

void smoothblendClient::desktopChange() {
    bool d = isOnAllDesktops();
    if (button[ButtonSticky]) {
        TQToolTip::remove(button[ButtonSticky]);
        TQToolTip::add(button[ButtonSticky], d ? i18n("Un-Sticky") : i18n("Sticky"));
        button[ButtonSticky]->repaint(false);
    }
}

//////////////////////////////////////////////////////////////////////////////
// iconChange()
// ------------
// The title has changed

void smoothblendClient::iconChange() {
    if (button[ButtonMenu]) {
        button[ButtonMenu]->repaint(false);
    }
}

//////////////////////////////////////////////////////////////////////////////
// maximizeChange()
// ----------------
// Maximized state has changed

void smoothblendClient::maximizeChange() {
    bool m = (maximizeMode() == MaximizeFull);
    if (button[ButtonMax]) {
        TQToolTip::remove(button[ButtonMax]);
        TQToolTip::add(button[ButtonMax], m ? i18n("Restore") : i18n("Maximize"));
        button[ButtonMax]->repaint(false);
    }
}

//////////////////////////////////////////////////////////////////////////////
// shadeChange()
// -------------
// Called when window shading changes

void smoothblendClient::shadeChange() {
    bool s = isSetShade();
    if (button[ButtonShade]) {
        TQToolTip::remove(button[ButtonShade]);
        TQToolTip::add(button[ButtonShade], s ? i18n("Unshade") : i18n("Shade"));
        button[ButtonShade]->repaint(false);
    }
}

//////////////////////////////////////////////////////////////////////////////
// keepAboveChange()
// ------------
// The above state has changed

void smoothblendClient::keepAboveChange(bool a) {
    if (button[ButtonAbove]) {
        button[ButtonAbove]->setOn(a);
        button[ButtonAbove]->repaint(false);
    }
}

//////////////////////////////////////////////////////////////////////////////
// keepBelowChange()
// ------------
// The below state has changed

void smoothblendClient::keepBelowChange(bool b) {
    if (button[ButtonBelow]) {
        button[ButtonBelow]->setOn(b);
        button[ButtonBelow]->repaint(false);
    }
}

//////////////////////////////////////////////////////////////////////////////
// borders()
// ----------
// Get the size of the borders

void smoothblendClient::borders(int &left, int &right, int &top, int &bottom) const {
    int FRAMESIZE = ::factory->frameSize();

    if ((maximizeMode()==MaximizeFull) && !options()->moveResizeMaximizedWindows()) {
        left = right = bottom = 0;
        top = ::factory->buttonSize();

        // update layout etc.
        topSpacer_->changeSize(1, 0, TQSizePolicy::Expanding, TQSizePolicy::Fixed);
        decoSpacer_->changeSize(1, 0, TQSizePolicy::Expanding, TQSizePolicy::Fixed);
        leftSpacer_->changeSize(left, 1, TQSizePolicy::Fixed, TQSizePolicy::Expanding);
        leftTitleSpacer_->changeSize(left, top, TQSizePolicy::Fixed, TQSizePolicy::Fixed);
        rightSpacer_->changeSize(right, 1, TQSizePolicy::Fixed, TQSizePolicy::Expanding);
        rightTitleSpacer_->changeSize(right, top, TQSizePolicy::Fixed, TQSizePolicy::Fixed);
        bottomSpacer_->changeSize(1, bottom, TQSizePolicy::Expanding, TQSizePolicy::Fixed);
    } else {
        left = right = bottom = ::factory->frameSize();
        top = ::factory->titleSize() + (FRAMESIZE*2);

        // update layout etc.
        topSpacer_->changeSize(1, FRAMESIZE, TQSizePolicy::Expanding, TQSizePolicy::Fixed);
        decoSpacer_->changeSize(1, FRAMESIZE, TQSizePolicy::Expanding, TQSizePolicy::Fixed);
        leftSpacer_->changeSize(left, 1, TQSizePolicy::Fixed, TQSizePolicy::Expanding);
        leftTitleSpacer_->changeSize(left, s_titleHeight, TQSizePolicy::Fixed, TQSizePolicy::Fixed);
        rightSpacer_->changeSize(right, 1, TQSizePolicy::Fixed, TQSizePolicy::Expanding);
        rightTitleSpacer_->changeSize(right,s_titleHeight,TQSizePolicy::Fixed, TQSizePolicy::Fixed);
        bottomSpacer_->changeSize(1, bottom, TQSizePolicy::Expanding, TQSizePolicy::Fixed);
    }
    widget()->layout()->activate();
}

//////////////////////////////////////////////////////////////////////////////
// resize()
// --------
// Called to resize the window

void smoothblendClient::resize(const TQSize &size) {
    widget()->resize(size);
}

//////////////////////////////////////////////////////////////////////////////
// minimumSize()
// -------------
// Return the minimum allowable size for this window

TQSize smoothblendClient::minimumSize() const {
    return widget()->minimumSize();
}

//////////////////////////////////////////////////////////////////////////////
// mousePosition()
// ---------------
// Return logical mouse position

KDecoration::Position smoothblendClient::mousePosition(const TQPoint &point) const {
    const int corner = 24;
    Position pos;
    int fs = ::factory->frameSize() + handlebar;
    //int fs = ::factory->frameSize();

    if (point.y() <= fs) {
        // inside top frame
        if (point.x() <= corner)
            pos = PositionTopLeft;
        else if (point.x() >= (width()-corner))
            pos = PositionTopRight;
        else
            pos = PositionTop;
    } else if (point.y() >= (height()-fs*2)) {
        // inside handle
        if (point.x() <= corner)
            pos = PositionBottomLeft;
        else if (point.x() >= (width()-corner))
            pos = PositionBottomRight;
        else
            pos = PositionBottom;
    } else if (point.x() <= fs ) {
        // on left frame
        if (point.y() <= corner)
            pos = PositionTopLeft;
        else if (point.y() >= (height()-corner))
            pos = PositionBottomLeft;
        else
            pos = PositionLeft;
    } else if (point.x() >= width()-fs) {
        // on right frame
        if (point.y() <= corner)
            pos = PositionTopRight;
        else if (point.y() >= (height()-corner))
            pos = PositionBottomRight;
        else
            pos = PositionRight;
    } else {
        // inside the frame
        pos = PositionCenter;
    }
    return pos;
}

//////////////////////////////////////////////////////////////////////////////
// eventFilter()
// -------------
// Event filter

bool smoothblendClient::eventFilter(TQObject *obj, TQEvent *e) {
    if (obj != widget())
        return false;

    switch (e->type()) {
    case TQEvent::MouseButtonDblClick: {
            mouseDoubleClickEvent(static_cast<TQMouseEvent*>(e));
            return true;
        }
    case TQEvent::MouseButtonPress: {
            processMousePressEvent(static_cast<TQMouseEvent*>(e));
            return true;
        }
    case TQEvent::Paint: {
            paintEvent(static_cast<TQPaintEvent*>(e));
            return true;
        }
    case TQEvent::Resize: {
            resizeEvent(static_cast<TQResizeEvent*>(e));
            return true;
        }
    case TQEvent::Show: {
            showEvent(static_cast<TQShowEvent*>(e));
            return true;
        }
    case TQEvent::Wheel: {
            wheelEvent(static_cast<TQWheelEvent*>( e ));
            return true;
        }
    default: {
            return false;
        }
    }

    return false;
}

//////////////////////////////////////////////////////////////////////////////
// mouseDoubleClickEvent()
// -----------------------
// Doubleclick on title

void smoothblendClient::mouseDoubleClickEvent(TQMouseEvent *e) {
    if (titlebar_->geometry().contains(e->pos()))
        titlebarDblClickOperation();
}

//////////////////////////////////////////////////////////////////////////////
// wheelEvent()
// ------------
// Mouse wheel on titlebar

void smoothblendClient::wheelEvent(TQWheelEvent *e)
{
    if (titleLayout_->geometry().contains(e->pos()) )
        titlebarMouseWheelOperation( e->delta());
}

//////////////////////////////////////////////////////////////////////////////
// paintEvent()
// ------------
// Repaint the window

void smoothblendClient::paintEvent(TQPaintEvent*) {
    if (!::factory->initialized())
    {
        return;
    }
    
    //int FRAMESIZE = ::factory->frameSize();
    const uint maxCaptionLength = 300; // truncate captions longer than this!
    TQString captionText(caption());
    if (captionText.length() > maxCaptionLength) {
        captionText.truncate(maxCaptionLength);
        captionText.append(" [...]");
    }

    TQColor blackColor(black);
    TQColor redColor(red);
    TQColorGroup group,widgetGroup;
    TQPainter painter(widget());
    bool active = isActive();
    //get group information first
    group = options()->colorGroup(KDecoration::ColorTitleBar, isActive());
    widgetGroup = widget()->colorGroup();

    TQRect topRect( topSpacer_->geometry() );
    TQRect titleRect( titleLayout_->geometry() );
    TQRect textRect( titlebar_->geometry() );
    TQRect Rltitle( leftTitleSpacer_->geometry() );
    TQRect Rrtitle( rightTitleSpacer_->geometry() );
    TQRect Rdeco( decoSpacer_->geometry() );
    TQRect Rleft( leftSpacer_->geometry() );
    TQRect Rright( rightSpacer_->geometry() );
    TQRect Rbottom( bottomSpacer_->geometry() );
    TQRect tempRect;
    
    
    /*
    if(active)
    {
        tqDebug("paintEvent() topRect.y()   = %i\tbottom() = %i",topRect.top(),topRect.bottom());
        tqDebug("paintEvent() titleRect.y() = %i\tbottom() = %i",titleRect.top(),titleRect.bottom());
        tqDebug("paintEvent() textRect.y()  = %i\tbottom() = %i",textRect.top(),textRect.bottom());
        tqDebug("paintEvent() Rltitle.y()   = %i\tbottom() = %i",Rltitle.top(),Rltitle.bottom());
        tqDebug("paintEvent() Rrtitle.y()   = %i\tbottom() = %i",Rrtitle.top(),Rrtitle.bottom());
        tqDebug("paintEvent() Rdeco.y()     = %i\tbottom() = %i",Rdeco.top(),Rdeco.bottom());
        tqDebug("paintEvent() Rleft.y()     = %i\tbottom() = %i",Rleft.top(),Rleft.bottom());
        tqDebug("paintEvent() Rright.y()    = %i\tbottom() = %i",Rright.top(),Rright.bottom());
        tqDebug("paintEvent() Rbottom.y()   = %i\tbottom() = %i",Rbottom.top(),Rbottom.bottom());
    }
    */

    // top
    painter.drawTiledPixmap(topRect, active ? *aTitleBarTopTile:*iTitleBarTopTile);
    painter.drawTiledPixmap(titleRect.x(),
                            titleRect.y(),
                            titleRect.width(),
                            titleRect.height() + Rdeco.height(),
                            active ? *aTitleBarTile:*iTitleBarTile);

    textRect.setRect(textRect.x()+SIDETITLEMARGIN,
                     textRect.y(),
                     textRect.width()-SIDETITLEMARGIN*2,
                     textRect.height());
    TQRect shadowRect(textRect.x()+1,textRect.y()+1,textRect.width(),textRect.height());
    //if we are shadowing title bar text
    if(::factory->titleShadow())
    {
        //shadow text
        painter.setFont(options()->font(isActive(), false));
        painter.setPen(blackColor);
        painter.drawText(shadowRect,
                         ::factory->titleAlign() | AlignVCenter | TQt::SingleLine,
                         captionText);
    }
    // draw title text
    painter.setFont(options()->font(isActive(), false));
    painter.setPen(options()->color(KDecoration::ColorFont, isActive()));
    painter.drawText(textRect,
                     ::factory->titleAlign() | AlignVCenter | TQt::SingleLine,
                     captionText);
    
    //left of buttons and title
    painter.drawTiledPixmap(Rltitle.x(),
                            Rltitle.y(),
                            Rltitle.width(),
                            Rltitle.height()+Rdeco.height(),
                            active ? *aTitleBarTile:*iTitleBarTile);
    // left mid layout
    painter.fillRect(Rleft,widgetGroup.background());

    // right of buttons and title
    painter.drawTiledPixmap(Rrtitle.x(),
                            Rrtitle.y(),
                            Rrtitle.width(),
                            Rrtitle.height()+Rdeco.height(),
                            active ? *aTitleBarTile:*iTitleBarTile);
    // right mid layout
    painter.fillRect(Rright,widgetGroup.background());
    
    // bottom
    /*
    if(isShade())
    {
        frame.setRect(0,::factory->titleSize()+FRAMESIZE, width(), FRAMESIZE);
    }
    else
    {
        frame.setRect(0, height() - (FRAMESIZE*2), width(),  (FRAMESIZE*2));
    }
    */
    painter.fillRect(Rbottom, widgetGroup.background());

    //draw a line between title bar and window contents
    painter.setPen(group.background());

    // outline outside the frame but not the corners if they are rounded
    tempRect = widget()->rect();
    painter.drawRect(tempRect);

    bool cornersFlag = ::factory->roundedCorners();
    if(cornersFlag) {
        // local temp right and bottom
        int r(width());
        painter.setPen(group.background());
        painter.drawPoint(4, 1);
        painter.drawPoint(3, 1);
        painter.drawPoint(2, 2);
        painter.drawPoint(1, 3);
        painter.drawPoint(1, 4);
        painter.drawPoint(r - 5, 1);
        painter.drawPoint(r - 4, 1);
        painter.drawPoint(r - 3, 2);
        painter.drawPoint(r - 2, 3);
        painter.drawPoint(r - 2, 4);
    } 

}

//////////////////////////////////////////////////////////////////////////////
// updateMask()
// ------------
// update the frame mask
void smoothblendClient::updateMask() {
    bool cornersFlag = ::factory->roundedCorners();
    if ( (!options()->moveResizeMaximizedWindows() && maximizeMode() == MaximizeFull ) ) 
    {
        setMask(TQRegion(widget()->rect()));
        return;
    }

    int r(width());
    int b(height());
    TQRegion mask;

    mask=TQRegion(widget()->rect());

   // Remove top-left corner.
    if(cornersFlag) {
        mask -= TQRegion(0, 0, 5, 1);
        mask -= TQRegion(0, 1, 3, 1);
        mask -= TQRegion(0, 2, 2, 1);
        mask -= TQRegion(0, 3, 1, 2);
        mask -= TQRegion(r - 5, 0, 5, 1);
        mask -= TQRegion(r - 3, 1, 3, 1);
        mask -= TQRegion(r - 2, 2, 2, 1);
        mask -= TQRegion(r - 1, 3, 1, 2);
    }
    //always remove one corner pixel so it simulates a soft corner like plastik
    mask -= TQRegion(0,0,1,1);
    mask -= TQRegion(r-1,0,1,1);
    mask -= TQRegion(0, b-1, 1,1);
    mask -= TQRegion(r-1,b-1,1,1);

    setMask(mask);
}

//////////////////////////////////////////////////////////////////////////////
// resizeEvent()
// -------------
// Window is being resized

void smoothblendClient::resizeEvent(TQResizeEvent *) {
    if (widget()->isShown()) {
        TQRegion region = widget()->rect();
        region = region.subtract(titlebar_->geometry());
        widget()->erase(region);
        updateMask();
    }
}

//////////////////////////////////////////////////////////////////////////////
// showEvent()
// -----------
// Window is being shown

void smoothblendClient::showEvent(TQShowEvent *) {
    updateMask();
    widget()->repaint();
}

//////////////////////////////////////////////////////////////////////////////
// maxButtonPressed()
// -----------------
// Max button was pressed

void smoothblendClient::maxButtonPressed() {
    if (button[ButtonMax]) {
        maximize(button[ButtonMax]->lastMousePress());
    }
}

//////////////////////////////////////////////////////////////////////////////
// shadeButtonPressed()
// -----------------
// Shade button was pressed

void smoothblendClient::shadeButtonPressed() {
    if (button[ButtonShade]) {
        setShade( !isSetShade());
    }
}

//////////////////////////////////////////////////////////////////////////////
// aboveButtonPressed()
// -----------------
// Above button was pressed

void smoothblendClient::aboveButtonPressed() {
    if (button[ButtonAbove]) {
        setKeepAbove( !keepAbove());
    }
}

//////////////////////////////////////////////////////////////////////////////
// belowButtonPressed()
// -----------------
// Below button was pressed

void smoothblendClient::belowButtonPressed() {
    if (button[ButtonBelow]) {
        setKeepBelow( !keepBelow());
    }
}

//////////////////////////////////////////////////////////////////////////////
// menuButtonPressed()
// -------------------
// Menu button was pressed (popup the menu)

void smoothblendClient::menuButtonPressed() {
    static TQTime* t = NULL;
    static smoothblendClient* lastClient = NULL;
    if (t == NULL)
        t = new TQTime;
    bool dbl = (lastClient==this && t->elapsed() <= TQApplication::doubleClickInterval());
    lastClient = this;
    t->start();
    //if (button[ButtonMenu] && !dbl && !::factory->menuClosed()) {
    if ( !dbl || !::factory->menuClosed()) {
        TQPoint p(button[ButtonMenu]->rect().bottomLeft().x(),
                 button[ButtonMenu]->rect().bottomLeft().y());
        KDecorationFactory* f = factory();
        showWindowMenu(button[ButtonMenu]->mapToGlobal(p));
        if (!f->exists(this))
            return; // decoration was destroyed
        button[ButtonMenu]->setDown(false);
    }
    else
    {
        closing = true;
    }
}

void smoothblendClient::menuButtonReleased()
{
    if(closing)
    {
        closeWindow();
    }
}

#include "smoothblend.moc"
