|
|
|
/*
|
|
|
|
kopetelistviewitem.cpp - Kopete's modular TQListViewItems
|
|
|
|
|
|
|
|
Copyright (c) 2005 by Engin AYDOGAN <engin@bzzzt.biz>
|
|
|
|
Copyright (c) 2004 by Richard Smith <kde@metafoo.co.uk>
|
|
|
|
|
|
|
|
Kopete (c) 2002-2004 by the Kopete developers <kopete-devel@kde.org>
|
|
|
|
|
|
|
|
*************************************************************************
|
|
|
|
* *
|
|
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
|
|
* it under the terms of the GNU General Public License as published by *
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
|
|
* (at your option) any later version. *
|
|
|
|
* *
|
|
|
|
*************************************************************************
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "kopeteprefs.h"
|
|
|
|
#include "kopetecontact.h"
|
|
|
|
#include "kopetelistviewitem.h"
|
|
|
|
#include "kopeteemoticons.h"
|
|
|
|
#include "kopeteonlinestatus.h"
|
|
|
|
|
|
|
|
#include <kdebug.h>
|
|
|
|
#include <kiconloader.h>
|
|
|
|
#include <kstringhandler.h>
|
|
|
|
|
|
|
|
#include <tqapplication.h>
|
|
|
|
#include <tqpixmap.h>
|
|
|
|
#include <tqpainter.h>
|
|
|
|
#include <tqptrlist.h>
|
|
|
|
#include <tqrect.h>
|
|
|
|
#include <tqtimer.h>
|
|
|
|
#include <tqheader.h>
|
|
|
|
#include <tqstyle.h>
|
|
|
|
|
|
|
|
#ifdef HAVE_XRENDER
|
|
|
|
# include <X11/Xlib.h>
|
|
|
|
# include <X11/extensions/Xrender.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <limits.h>
|
|
|
|
|
|
|
|
namespace Kopete {
|
|
|
|
namespace UI {
|
|
|
|
namespace ListView {
|
|
|
|
|
|
|
|
// ComponentBase --------
|
|
|
|
|
|
|
|
class ComponentBase::Private
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
TQPtrList<Component> components;
|
|
|
|
};
|
|
|
|
|
|
|
|
ComponentBase::ComponentBase()
|
|
|
|
: d( new Private )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
ComponentBase::~ComponentBase()
|
|
|
|
{
|
|
|
|
d->components.setAutoDelete( true );
|
|
|
|
delete d;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint ComponentBase::components() { return d->components.count(); }
|
|
|
|
Component *ComponentBase::component( uint n ) { return d->components.at( n ); }
|
|
|
|
|
|
|
|
Component *ComponentBase::componentAt( const TQPoint &pt )
|
|
|
|
{
|
|
|
|
for ( uint n = 0; n < components(); ++n )
|
|
|
|
{
|
|
|
|
if ( component( n )->rect().contains( pt ) )
|
|
|
|
{
|
|
|
|
if ( Component *comp = component( n )->componentAt( pt ) )
|
|
|
|
return comp;
|
|
|
|
return component( n );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ComponentBase::componentAdded( Component *component )
|
|
|
|
{
|
|
|
|
d->components.append( component );
|
|
|
|
}
|
|
|
|
|
|
|
|
void ComponentBase::componentRemoved( Component *component )
|
|
|
|
{
|
|
|
|
//TODO: make sure the component is in d->components once and only once.
|
|
|
|
// if not, the situation is best referred to as 'very very broken indeed'.
|
|
|
|
d->components.remove( component );
|
|
|
|
}
|
|
|
|
|
|
|
|
void ComponentBase::clear()
|
|
|
|
{
|
|
|
|
/* I'm switching setAutoDelete back and forth instead of turning it
|
|
|
|
* on permenantly, because original author of this class set it to
|
|
|
|
* auto delete in the dtor, that might have a reason that I can't
|
|
|
|
* imagine right now */
|
|
|
|
bool tmp = d->components.autoDelete();
|
|
|
|
d->components.setAutoDelete( true );
|
|
|
|
d->components.clear();
|
|
|
|
d->components.setAutoDelete( tmp );
|
|
|
|
}
|
|
|
|
|
|
|
|
void ComponentBase::componentResized( Component * )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
std::pair<TQString,TQRect> ComponentBase::toolTip( const TQPoint &relativePos )
|
|
|
|
{
|
|
|
|
for ( uint n = 0; n < components(); ++n )
|
|
|
|
if ( component( n )->rect().contains( relativePos ) )
|
|
|
|
return component( n )->toolTip( relativePos );
|
|
|
|
|
|
|
|
return std::make_pair( TQString(), TQRect() );
|
|
|
|
}
|
|
|
|
|
|
|
|
void ComponentBase::updateAnimationPosition( int p, int s )
|
|
|
|
{
|
|
|
|
for ( uint n = 0; n < components(); ++n )
|
|
|
|
{
|
|
|
|
Component *comp = component( n );
|
|
|
|
TQRect start = comp->startRect();
|
|
|
|
TQRect target = comp->targetRect();
|
|
|
|
TQRect rc( start.left() + ((target.left() - start.left()) * p) / s,
|
|
|
|
start.top() + ((target.top() - start.top()) * p) / s,
|
|
|
|
start.width() + ((target.width() - start.width()) * p) / s,
|
|
|
|
start.height() + ((target.height() - start.height()) * p) / s );
|
|
|
|
comp->setRect( rc );
|
|
|
|
comp->updateAnimationPosition( p, s );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Component --------
|
|
|
|
|
|
|
|
class Component::Private
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
Private( ComponentBase *parent )
|
|
|
|
: parent( parent ), minWidth( 0 ), minHeight( 0 )
|
|
|
|
, growHoriz( false ), growVert( false )
|
|
|
|
, tipSource( 0 )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
ComponentBase *parent;
|
|
|
|
TQRect rect;
|
|
|
|
TQRect startRect, targetRect;
|
|
|
|
int minWidth, minHeight;
|
|
|
|
bool growHoriz, growVert;
|
|
|
|
bool show; /** @since 23-03-2005 */
|
|
|
|
ToolTipSource *tipSource;
|
|
|
|
};
|
|
|
|
|
|
|
|
Component::Component( ComponentBase *parent )
|
|
|
|
: d( new Private( parent ) )
|
|
|
|
{
|
|
|
|
d->parent->componentAdded( this );
|
|
|
|
d->show = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
int Component::RTTI = Rtti_Component;
|
|
|
|
|
|
|
|
Component::~Component()
|
|
|
|
{
|
|
|
|
d->parent->componentRemoved( this );
|
|
|
|
delete d;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Component::hide()
|
|
|
|
{
|
|
|
|
d->show = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Component::show()
|
|
|
|
{
|
|
|
|
d->show = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Component::isShown()
|
|
|
|
{
|
|
|
|
return d->show;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Component::isHidden()
|
|
|
|
{
|
|
|
|
return !d->show;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Component::setToolTipSource( ToolTipSource *source )
|
|
|
|
{
|
|
|
|
d->tipSource = source;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::pair<TQString,TQRect> Component::toolTip( const TQPoint &relativePos )
|
|
|
|
{
|
|
|
|
if ( !d->tipSource )
|
|
|
|
return ComponentBase::toolTip( relativePos );
|
|
|
|
|
|
|
|
TQRect rc = rect();
|
|
|
|
TQString result = (*d->tipSource)( this, relativePos, rc );
|
|
|
|
return std::make_pair(result, rc);
|
|
|
|
}
|
|
|
|
|
|
|
|
TQRect Component::rect() { return d->rect; }
|
|
|
|
TQRect Component::startRect() { return d->startRect; }
|
|
|
|
TQRect Component::targetRect() { return d->targetRect; }
|
|
|
|
|
|
|
|
int Component::minWidth() { return d->minWidth; }
|
|
|
|
int Component::minHeight() { return d->minHeight; }
|
|
|
|
int Component::widthForHeight( int ) { return minWidth(); }
|
|
|
|
int Component::heightForWidth( int ) { return minHeight(); }
|
|
|
|
|
|
|
|
bool Component::setMinWidth( int width )
|
|
|
|
{
|
|
|
|
if ( d->minWidth == width ) return false;
|
|
|
|
d->minWidth = width;
|
|
|
|
|
|
|
|
d->parent->componentResized( this );
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
bool Component::setMinHeight( int height )
|
|
|
|
{
|
|
|
|
if ( d->minHeight == height ) return false;
|
|
|
|
d->minHeight = height;
|
|
|
|
|
|
|
|
d->parent->componentResized( this );
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Component::layout( const TQRect &newRect )
|
|
|
|
{
|
|
|
|
if ( rect().isNull() )
|
|
|
|
d->startRect = TQRect( newRect.topLeft(), newRect.topLeft() );
|
|
|
|
else
|
|
|
|
d->startRect = rect();
|
|
|
|
d->targetRect = newRect;
|
|
|
|
//kdDebug(14000) << k_funcinfo << "At " << rect << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Component::setRect( const TQRect &rect )
|
|
|
|
{
|
|
|
|
d->rect = rect;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Component::paint( TQPainter *painter, const TQColorGroup &cg )
|
|
|
|
{
|
|
|
|
/*painter->setPen( TQt::red );
|
|
|
|
painter->drawRect( rect() );*/
|
|
|
|
for ( uint n = 0; n < components(); ++n )
|
|
|
|
{
|
|
|
|
if( component( n )->isShown() )
|
|
|
|
component( n )->paint( painter, cg );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Component::repaint()
|
|
|
|
{
|
|
|
|
d->parent->repaint();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Component::relayout()
|
|
|
|
{
|
|
|
|
d->parent->relayout();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Component::componentAdded( Component *component )
|
|
|
|
{
|
|
|
|
ComponentBase::componentAdded( component );
|
|
|
|
//update( Relayout );
|
|
|
|
}
|
|
|
|
|
|
|
|
void Component::componentRemoved( Component *component )
|
|
|
|
{
|
|
|
|
ComponentBase::componentRemoved( component );
|
|
|
|
//update( Relayout );
|
|
|
|
}
|
|
|
|
|
|
|
|
// BoxComponent --------
|
|
|
|
|
|
|
|
class BoxComponent::Private
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
Private( BoxComponent::Direction dir ) : direction( dir ) {}
|
|
|
|
BoxComponent::Direction direction;
|
|
|
|
|
|
|
|
static const int padding = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
BoxComponent::BoxComponent( ComponentBase *parent, Direction dir )
|
|
|
|
: Component( parent ), d( new Private( dir ) )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
int BoxComponent::RTTI = Rtti_BoxComponent;
|
|
|
|
|
|
|
|
BoxComponent::~BoxComponent()
|
|
|
|
{
|
|
|
|
delete d;
|
|
|
|
}
|
|
|
|
|
|
|
|
int BoxComponent::widthForHeight( int height )
|
|
|
|
{
|
|
|
|
if ( d->direction !=Qt::Horizontal )
|
|
|
|
{
|
|
|
|
int width = 0;
|
|
|
|
for ( uint n = 0; n < components(); ++n )
|
|
|
|
width = TQMAX( width, component( n )->widthForHeight( height ) );
|
|
|
|
return width;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int width = (components() - 1) * Private::padding;
|
|
|
|
for ( uint n = 0; n < components(); ++n )
|
|
|
|
width += component( n )->widthForHeight( height );
|
|
|
|
return width;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int BoxComponent::heightForWidth( int width )
|
|
|
|
{
|
|
|
|
if ( d->direction ==Qt::Horizontal )
|
|
|
|
{
|
|
|
|
int height = 0;
|
|
|
|
for ( uint n = 0; n < components(); ++n )
|
|
|
|
height = TQMAX( height, component( n )->heightForWidth( width ) );
|
|
|
|
return height;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int height = (components() - 1) * Private::padding;
|
|
|
|
for ( uint n = 0; n < components(); ++n )
|
|
|
|
height += component( n )->heightForWidth( width );
|
|
|
|
return height;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void BoxComponent::calcMinSize()
|
|
|
|
{
|
|
|
|
int sum = (components() - 1) * Private::padding, max = 0;
|
|
|
|
for ( uint n = 0; n < components(); ++n )
|
|
|
|
{
|
|
|
|
Component *comp = component( n );
|
|
|
|
if ( d->direction ==Qt::Horizontal )
|
|
|
|
{
|
|
|
|
max = TQMAX( max, comp->minHeight() );
|
|
|
|
sum += comp->minWidth();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
max = TQMAX( max, comp->minWidth() );
|
|
|
|
sum += comp->minHeight();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool sizeChanged = false;
|
|
|
|
if ( d->direction ==Qt::Horizontal )
|
|
|
|
{
|
|
|
|
if ( setMinWidth( sum ) ) sizeChanged = true;
|
|
|
|
if ( setMinHeight( max ) ) sizeChanged = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ( setMinWidth( max ) ) sizeChanged = true;
|
|
|
|
if ( setMinHeight( sum ) ) sizeChanged = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( sizeChanged )
|
|
|
|
repaint();
|
|
|
|
else
|
|
|
|
relayout();
|
|
|
|
}
|
|
|
|
|
|
|
|
void BoxComponent::layout( const TQRect &rect )
|
|
|
|
{
|
|
|
|
Component::layout( rect );
|
|
|
|
|
|
|
|
bool horiz = (d->direction ==Qt::Horizontal);
|
|
|
|
int fixedSize = 0;
|
|
|
|
for ( uint n = 0; n < components(); ++n )
|
|
|
|
{
|
|
|
|
Component *comp = component( n );
|
|
|
|
if ( horiz )
|
|
|
|
fixedSize += comp->minWidth();
|
|
|
|
else
|
|
|
|
fixedSize += comp->minHeight();
|
|
|
|
}
|
|
|
|
|
|
|
|
// remaining space after all fixed items have been allocated
|
|
|
|
int padding = Private::padding;
|
|
|
|
|
|
|
|
// ensure total is at least minXXX. the only time the rect
|
|
|
|
// will be smaller than that is when we don't fit, and in
|
|
|
|
// that cases we should pretend that we're wide/high enough.
|
|
|
|
int total;
|
|
|
|
if ( horiz )
|
|
|
|
total = TQMAX( rect.width(), minWidth() );
|
|
|
|
else
|
|
|
|
total = TQMAX( rect.height(), minHeight() );
|
|
|
|
|
|
|
|
int remaining = total - fixedSize - padding * (components() - 1);
|
|
|
|
|
|
|
|
// finally, lay everything out
|
|
|
|
int pos = 0;
|
|
|
|
for ( uint n = 0; n < components(); ++n )
|
|
|
|
{
|
|
|
|
Component *comp = component( n );
|
|
|
|
|
|
|
|
TQRect rc;
|
|
|
|
if ( horiz )
|
|
|
|
{
|
|
|
|
rc.setLeft( rect.left() + pos );
|
|
|
|
rc.setTop( rect.top() );
|
|
|
|
rc.setHeight( rect.height() );
|
|
|
|
int minWidth = comp->minWidth();
|
|
|
|
int desiredWidth = comp->widthForHeight( rect.height() );
|
|
|
|
rc.setWidth( TQMIN( remaining + minWidth, desiredWidth ) );
|
|
|
|
pos += rc.width();
|
|
|
|
remaining -= rc.width() - minWidth;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
rc.setLeft( rect.left() );
|
|
|
|
rc.setTop( rect.top() + pos );
|
|
|
|
rc.setWidth( rect.width() );
|
|
|
|
int minHeight = comp->minHeight();
|
|
|
|
int desiredHeight = comp->heightForWidth( rect.width() );
|
|
|
|
rc.setHeight( TQMIN( remaining + minHeight, desiredHeight ) );
|
|
|
|
pos += rc.height();
|
|
|
|
remaining -= rc.height() - minHeight;
|
|
|
|
}
|
|
|
|
comp->layout( rc & rect );
|
|
|
|
pos += padding;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void BoxComponent::componentAdded( Component *component )
|
|
|
|
{
|
|
|
|
Component::componentAdded( component );
|
|
|
|
calcMinSize();
|
|
|
|
}
|
|
|
|
|
|
|
|
void BoxComponent::componentRemoved( Component *component )
|
|
|
|
{
|
|
|
|
Component::componentRemoved( component );
|
|
|
|
calcMinSize();
|
|
|
|
}
|
|
|
|
|
|
|
|
void BoxComponent::componentResized( Component *component )
|
|
|
|
{
|
|
|
|
Component::componentResized( component );
|
|
|
|
calcMinSize();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*= ContactBoxComponent =====================================================*/
|
|
|
|
|
|
|
|
class ContactBoxComponent::Private
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
TQRect sub;
|
|
|
|
|
|
|
|
TQPixmap back_pixmap;
|
|
|
|
|
|
|
|
TQPixmap corner_tl_pixmap;
|
|
|
|
TQPixmap corner_bl_pixmap;
|
|
|
|
TQPixmap corner_tr_pixmap;
|
|
|
|
TQPixmap corner_br_pixmap;
|
|
|
|
|
|
|
|
TQPixmap top_pixmap;
|
|
|
|
TQPixmap left_pixmap;
|
|
|
|
TQPixmap right_pixmap;
|
|
|
|
TQPixmap bottom_pixmap;
|
|
|
|
};
|
|
|
|
|
|
|
|
ContactBoxComponent::ContactBoxComponent(ComponentBase *parent, Direction dir)
|
|
|
|
: BoxComponent(parent, dir), d(new Private())
|
|
|
|
{}
|
|
|
|
|
|
|
|
ContactBoxComponent::~ContactBoxComponent()
|
|
|
|
{
|
|
|
|
delete d;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ContactBoxComponent::reloadTheme()
|
|
|
|
{
|
|
|
|
TQString path = KopetePrefs::prefs()->themeURL();
|
|
|
|
TQString str;
|
|
|
|
|
|
|
|
str = path + "ContactBackground.png";
|
|
|
|
d->back_pixmap.load(str);
|
|
|
|
|
|
|
|
str = path + "ContactTopLeft.png";
|
|
|
|
d->corner_tl_pixmap.load(str);
|
|
|
|
str = path + "ContactBottomLeft.png";
|
|
|
|
d->corner_bl_pixmap.load(str);
|
|
|
|
str = path + "ContactTopRight.png";
|
|
|
|
d->corner_tr_pixmap.load(str);
|
|
|
|
str = path + "ContactBottomRight.png";
|
|
|
|
d->corner_br_pixmap.load(str);
|
|
|
|
|
|
|
|
str = path + "ContactTop.png";
|
|
|
|
d->top_pixmap.load(str);
|
|
|
|
str = path + "ContactLeft.png";
|
|
|
|
d->left_pixmap.load(str);
|
|
|
|
str = path + "ContactRight.png";
|
|
|
|
d->right_pixmap.load(str);
|
|
|
|
str = path + "ContactBottom.png";
|
|
|
|
d->bottom_pixmap.load(str);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ContactBoxComponent::layout(const TQRect &rect)
|
|
|
|
{
|
|
|
|
d->sub.setLeft(rect.left() +
|
|
|
|
d->left_pixmap.width());
|
|
|
|
d->sub.setTop(rect.top() +
|
|
|
|
d->top_pixmap.height());
|
|
|
|
d->sub.setRight(rect.right() -
|
|
|
|
d->right_pixmap.width());
|
|
|
|
d->sub.setBottom(rect.bottom() -
|
|
|
|
d->bottom_pixmap.height());
|
|
|
|
|
|
|
|
BoxComponent::layout(d->sub);
|
|
|
|
Component::layout(rect);
|
|
|
|
}
|
|
|
|
|
|
|
|
int ContactBoxComponent::widthForHeight(int height)
|
|
|
|
{
|
|
|
|
return BoxComponent::widthForHeight(height) +
|
|
|
|
d->left_pixmap.width() +
|
|
|
|
d->right_pixmap.width();
|
|
|
|
}
|
|
|
|
|
|
|
|
int ContactBoxComponent::heightForWidth(int width)
|
|
|
|
{
|
|
|
|
return BoxComponent::heightForWidth(width) +
|
|
|
|
d->top_pixmap.height() +
|
|
|
|
d->bottom_pixmap.height();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ContactBoxComponent::paint(TQPainter *painter, const TQColorGroup &cg)
|
|
|
|
{
|
|
|
|
painter->drawPixmap(0,
|
|
|
|
0,
|
|
|
|
d->corner_tl_pixmap);
|
|
|
|
|
|
|
|
painter->drawPixmap(0,
|
|
|
|
d->sub.bottom()+1,
|
|
|
|
d->corner_bl_pixmap);
|
|
|
|
|
|
|
|
painter->drawPixmap(d->sub.right()+1,
|
|
|
|
0,
|
|
|
|
d->corner_tr_pixmap);
|
|
|
|
|
|
|
|
painter->drawPixmap(d->sub.right()+1,
|
|
|
|
d->sub.bottom()+1,
|
|
|
|
d->corner_br_pixmap);
|
|
|
|
|
|
|
|
painter->drawTiledPixmap(0,
|
|
|
|
d->sub.top(),
|
|
|
|
d->left_pixmap.width(),
|
|
|
|
d->sub.height(),
|
|
|
|
d->left_pixmap);
|
|
|
|
|
|
|
|
painter->drawTiledPixmap(d->sub.left(),
|
|
|
|
0,
|
|
|
|
d->sub.width(),
|
|
|
|
d->top_pixmap.height(),
|
|
|
|
d->top_pixmap);
|
|
|
|
|
|
|
|
painter->drawTiledPixmap(d->sub.left(),
|
|
|
|
d->sub.bottom()+1,
|
|
|
|
d->sub.width(),
|
|
|
|
d->bottom_pixmap.height(),
|
|
|
|
d->bottom_pixmap);
|
|
|
|
|
|
|
|
painter->drawTiledPixmap(d->sub.right()+1,
|
|
|
|
d->sub.top(),
|
|
|
|
d->right_pixmap.width(),
|
|
|
|
d->sub.height(),
|
|
|
|
d->right_pixmap);
|
|
|
|
|
|
|
|
painter->drawTiledPixmap(d->sub,
|
|
|
|
d->back_pixmap);
|
|
|
|
|
|
|
|
return BoxComponent::paint(painter, cg);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*= GroupBoxComponent =======================================================*/
|
|
|
|
|
|
|
|
class GroupBoxComponent::Private
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
TQRect sub;
|
|
|
|
|
|
|
|
TQPixmap back_pixmap;
|
|
|
|
|
|
|
|
TQPixmap open_pixmap;
|
|
|
|
TQPixmap closed_pixmap;
|
|
|
|
|
|
|
|
TQPixmap corner_tl_pixmap;
|
|
|
|
TQPixmap corner_bl_pixmap;
|
|
|
|
TQPixmap corner_tr_pixmap;
|
|
|
|
TQPixmap corner_br_pixmap;
|
|
|
|
|
|
|
|
TQPixmap top_pixmap;
|
|
|
|
TQPixmap left_pixmap;
|
|
|
|
TQPixmap right_pixmap;
|
|
|
|
TQPixmap bottom_pixmap;
|
|
|
|
};
|
|
|
|
|
|
|
|
GroupBoxComponent::GroupBoxComponent(ComponentBase *parent, Direction dir)
|
|
|
|
: BoxComponent(parent, dir), d(new Private())
|
|
|
|
{}
|
|
|
|
|
|
|
|
GroupBoxComponent::~GroupBoxComponent()
|
|
|
|
{
|
|
|
|
delete d;
|
|
|
|
}
|
|
|
|
|
|
|
|
void GroupBoxComponent::reloadTheme()
|
|
|
|
{
|
|
|
|
TQString path = KopetePrefs::prefs()->themeURL();
|
|
|
|
TQString str;
|
|
|
|
|
|
|
|
str = path + "GroupBackground.png";
|
|
|
|
d->back_pixmap.load(str);
|
|
|
|
|
|
|
|
str = path + "GroupOpen.png";
|
|
|
|
d->open_pixmap.load(str);
|
|
|
|
str = path + "GroupClosed.png";
|
|
|
|
d->closed_pixmap.load(str);
|
|
|
|
|
|
|
|
str = path + "GroupTopLeft.png";
|
|
|
|
d->corner_tl_pixmap.load(str);
|
|
|
|
str = path + "GroupBottomLeft.png";
|
|
|
|
d->corner_bl_pixmap.load(str);
|
|
|
|
str = path + "GroupTopRight.png";
|
|
|
|
d->corner_tr_pixmap.load(str);
|
|
|
|
str = path + "GroupBottomRight.png";
|
|
|
|
d->corner_br_pixmap.load(str);
|
|
|
|
|
|
|
|
str = path + "GroupTop.png";
|
|
|
|
d->top_pixmap.load(str);
|
|
|
|
str = path + "GroupLeft.png";
|
|
|
|
d->left_pixmap.load(str);
|
|
|
|
str = path + "GroupRight.png";
|
|
|
|
d->right_pixmap.load(str);
|
|
|
|
str = path + "GroupBottom.png";
|
|
|
|
d->bottom_pixmap.load(str);
|
|
|
|
}
|
|
|
|
|
|
|
|
void GroupBoxComponent::layout(const TQRect &rect)
|
|
|
|
{
|
|
|
|
d->sub.setLeft(rect.left() +
|
|
|
|
d->left_pixmap.width());
|
|
|
|
d->sub.setTop(rect.top() +
|
|
|
|
d->top_pixmap.height());
|
|
|
|
d->sub.setRight(rect.right() -
|
|
|
|
d->right_pixmap.width());
|
|
|
|
d->sub.setBottom(rect.bottom() -
|
|
|
|
d->bottom_pixmap.height());
|
|
|
|
|
|
|
|
BoxComponent::layout(d->sub);
|
|
|
|
Component::layout(rect);
|
|
|
|
}
|
|
|
|
|
|
|
|
int GroupBoxComponent::widthForHeight(int height)
|
|
|
|
{
|
|
|
|
return BoxComponent::widthForHeight(height) +
|
|
|
|
d->left_pixmap.width() +
|
|
|
|
d->right_pixmap.width();
|
|
|
|
}
|
|
|
|
|
|
|
|
int GroupBoxComponent::heightForWidth( int width )
|
|
|
|
{
|
|
|
|
return BoxComponent::heightForWidth(width) +
|
|
|
|
d->top_pixmap.height() +
|
|
|
|
d->bottom_pixmap.height();
|
|
|
|
}
|
|
|
|
|
|
|
|
void GroupBoxComponent::paint( TQPainter *painter, const TQColorGroup &cg )
|
|
|
|
{
|
|
|
|
painter->drawPixmap(0,
|
|
|
|
0,
|
|
|
|
d->corner_tl_pixmap);
|
|
|
|
|
|
|
|
painter->drawPixmap(0,
|
|
|
|
d->sub.bottom()+1,
|
|
|
|
d->corner_bl_pixmap);
|
|
|
|
|
|
|
|
painter->drawPixmap(d->sub.right()+1,
|
|
|
|
0,
|
|
|
|
d->corner_tr_pixmap);
|
|
|
|
|
|
|
|
painter->drawPixmap(d->sub.right()+1,
|
|
|
|
d->sub.bottom()+1,
|
|
|
|
d->corner_br_pixmap);
|
|
|
|
|
|
|
|
painter->drawTiledPixmap(0,
|
|
|
|
d->sub.top(),
|
|
|
|
d->left_pixmap.width(),
|
|
|
|
d->sub.height(),
|
|
|
|
d->left_pixmap);
|
|
|
|
|
|
|
|
painter->drawTiledPixmap(d->sub.left(),
|
|
|
|
0,
|
|
|
|
d->sub.width(),
|
|
|
|
d->top_pixmap.height(),
|
|
|
|
d->top_pixmap);
|
|
|
|
|
|
|
|
painter->drawTiledPixmap(d->sub.left(),
|
|
|
|
d->sub.bottom()+1,
|
|
|
|
d->sub.width(),
|
|
|
|
d->bottom_pixmap.height(),
|
|
|
|
d->bottom_pixmap);
|
|
|
|
|
|
|
|
painter->drawTiledPixmap(d->sub.right()+1,
|
|
|
|
d->sub.top(),
|
|
|
|
d->right_pixmap.width(),
|
|
|
|
d->sub.height(),
|
|
|
|
d->right_pixmap);
|
|
|
|
|
|
|
|
painter->drawTiledPixmap(d->sub,
|
|
|
|
d->back_pixmap);
|
|
|
|
|
|
|
|
return BoxComponent::paint(painter, cg);
|
|
|
|
}
|
|
|
|
|
|
|
|
// ImageComponent --------
|
|
|
|
|
|
|
|
class ImageComponent::Private
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
TQPixmap image;
|
|
|
|
};
|
|
|
|
|
|
|
|
ImageComponent::ImageComponent( ComponentBase *parent )
|
|
|
|
: Component( parent ), d( new Private )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
int ImageComponent::RTTI = Rtti_ImageComponent;
|
|
|
|
|
|
|
|
ImageComponent::ImageComponent( ComponentBase *parent, int minW, int minH )
|
|
|
|
: Component( parent ), d( new Private )
|
|
|
|
{
|
|
|
|
setMinWidth( minW );
|
|
|
|
setMinHeight( minH );
|
|
|
|
repaint();
|
|
|
|
}
|
|
|
|
|
|
|
|
ImageComponent::~ImageComponent()
|
|
|
|
{
|
|
|
|
delete d;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQPixmap ImageComponent::pixmap()
|
|
|
|
{
|
|
|
|
return d->image;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ImageComponent::setPixmap( const TQPixmap &img, bool)
|
|
|
|
{
|
|
|
|
d->image = img;
|
|
|
|
setMinWidth(d->image.width());
|
|
|
|
setMinHeight(d->image.height());
|
|
|
|
|
|
|
|
repaint();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ImageComponent::paint( TQPainter *painter, const TQColorGroup & )
|
|
|
|
{
|
|
|
|
TQRect ourRc = rect();
|
|
|
|
TQRect rc = d->image.rect();
|
|
|
|
// center rc within our rect
|
|
|
|
rc.moveTopLeft(ourRc.topLeft());
|
|
|
|
// paint, shrunk to be within our rect
|
|
|
|
painter->drawPixmap( rc & ourRc, d->image );
|
|
|
|
}
|
|
|
|
|
|
|
|
void ImageComponent::scale( int w, int h, TQ_ScaleMode mode )
|
|
|
|
{
|
|
|
|
TQImage im = d->image.convertToImage();
|
|
|
|
setPixmap( TQPixmap( im.smoothScale( w, h, mode ) ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*= FaceComponent ===========================================================*/
|
|
|
|
|
|
|
|
void FaceComponent::setPixmap(const TQPixmap &img, bool)
|
|
|
|
{
|
|
|
|
d->image = img;
|
|
|
|
|
|
|
|
setMinWidth(d->image.width());
|
|
|
|
setMinHeight(d->image.height());
|
|
|
|
|
|
|
|
if (img.width() >= 30)
|
|
|
|
{
|
|
|
|
d->image = TQPixmap(img.convertToImage().smoothScale(30, 30));
|
|
|
|
setMinWidth(d->image.width() + 4);
|
|
|
|
setMinHeight(d->image.height() + 4);
|
|
|
|
}
|
|
|
|
|
|
|
|
repaint();
|
|
|
|
}
|
|
|
|
|
|
|
|
static TQPoint operator+(const TQPoint &pt, const TQSize &sz)
|
|
|
|
{
|
|
|
|
return TQPoint(pt.x() + sz.width(), pt.y() + sz.height());
|
|
|
|
}
|
|
|
|
|
|
|
|
void FaceComponent::paint(TQPainter *painter, const TQColorGroup &)
|
|
|
|
{
|
|
|
|
TQRect outRc = rect();
|
|
|
|
TQRect pixRc = d->image.rect();
|
|
|
|
|
|
|
|
pixRc.moveTopLeft(outRc.topLeft() + (outRc.size() - pixRc.size()) / 2);
|
|
|
|
|
|
|
|
if (d->image.width() == 30)
|
|
|
|
{
|
|
|
|
TQPixmap pixBorder;
|
|
|
|
TQString path = KopetePrefs::prefs()->themeURL();
|
|
|
|
TQString str = path + "ContactFace.png";
|
|
|
|
|
|
|
|
pixBorder.load(str);
|
|
|
|
TQRect pixRc2 = pixBorder.rect();
|
|
|
|
|
|
|
|
pixRc2.moveTopLeft(outRc.topLeft() + (outRc.size() - pixRc2.size()) / 2);
|
|
|
|
painter->drawPixmap(pixRc2, pixBorder);
|
|
|
|
}
|
|
|
|
|
|
|
|
painter->drawPixmap(pixRc, d->image);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// TextComponent
|
|
|
|
|
|
|
|
class TextComponent::Private
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
Private() : customColor( false ) {}
|
|
|
|
TQString text;
|
|
|
|
bool customColor;
|
|
|
|
TQColor color;
|
|
|
|
TQFont font;
|
|
|
|
};
|
|
|
|
|
|
|
|
TextComponent::TextComponent( ComponentBase *parent, const TQFont &font, const TQString &text )
|
|
|
|
: Component( parent ), d( new Private )
|
|
|
|
{
|
|
|
|
setFont( font );
|
|
|
|
setText( text );
|
|
|
|
}
|
|
|
|
|
|
|
|
int TextComponent::RTTI = Rtti_TextComponent;
|
|
|
|
|
|
|
|
TextComponent::~TextComponent()
|
|
|
|
{
|
|
|
|
delete d;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString TextComponent::text()
|
|
|
|
{
|
|
|
|
return d->text;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TextComponent::setText( const TQString &text )
|
|
|
|
{
|
|
|
|
if ( text == d->text ) return;
|
|
|
|
d->text = text;
|
|
|
|
relayout();
|
|
|
|
calcMinSize();
|
|
|
|
}
|
|
|
|
|
|
|
|
TQFont TextComponent::font()
|
|
|
|
{
|
|
|
|
return d->font;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TextComponent::setFont( const TQFont &font )
|
|
|
|
{
|
|
|
|
if ( font == d->font ) return;
|
|
|
|
d->font = font;
|
|
|
|
calcMinSize();
|
|
|
|
}
|
|
|
|
|
|
|
|
void TextComponent::calcMinSize()
|
|
|
|
{
|
|
|
|
setMinWidth( 0 );
|
|
|
|
|
|
|
|
if ( !d->text.isEmpty() )
|
|
|
|
setMinHeight( TQFontMetrics( font() ).height() );
|
|
|
|
else
|
|
|
|
setMinHeight( 0 );
|
|
|
|
|
|
|
|
repaint();
|
|
|
|
}
|
|
|
|
|
|
|
|
int TextComponent::widthForHeight( int )
|
|
|
|
{
|
|
|
|
// add 2 to place an extra gap between the text and things to its right.
|
|
|
|
// allegedly if this is not done the protocol icons overlap the text.
|
|
|
|
// i however have never seen this problem (which would almost certainly
|
|
|
|
// be a bug somewhere else).
|
|
|
|
return TQFontMetrics( font() ).width( d->text ) + 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQColor TextComponent::color()
|
|
|
|
{
|
|
|
|
return d->customColor ? d->color : TQColor();
|
|
|
|
}
|
|
|
|
|
|
|
|
void TextComponent::setColor( const TQColor &color )
|
|
|
|
{
|
|
|
|
d->color = color;
|
|
|
|
d->customColor = true;
|
|
|
|
repaint();
|
|
|
|
}
|
|
|
|
|
|
|
|
void TextComponent::setDefaultColor()
|
|
|
|
{
|
|
|
|
d->customColor = false;
|
|
|
|
repaint();
|
|
|
|
}
|
|
|
|
|
|
|
|
void TextComponent::paint( TQPainter *painter, const TQColorGroup &cg )
|
|
|
|
{
|
|
|
|
if ( d->customColor )
|
|
|
|
painter->setPen( d->color );
|
|
|
|
else
|
|
|
|
painter->setPen( cg.text() );
|
|
|
|
TQString dispStr = KStringHandler::rPixelSqueeze( d->text, TQFontMetrics( font() ), rect().width() );
|
|
|
|
painter->setFont( font() );
|
|
|
|
painter->drawText( rect(), TQt::SingleLine, dispStr );
|
|
|
|
}
|
|
|
|
|
|
|
|
// DisplayNameComponent
|
|
|
|
|
|
|
|
class DisplayNameComponent::Private
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
TQString text;
|
|
|
|
TQFont font;
|
|
|
|
};
|
|
|
|
|
|
|
|
DisplayNameComponent::DisplayNameComponent( ComponentBase *parent )
|
|
|
|
: BoxComponent( parent ), d( new Private )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
int DisplayNameComponent::RTTI = Rtti_DisplayNameComponent;
|
|
|
|
|
|
|
|
DisplayNameComponent::~DisplayNameComponent()
|
|
|
|
{
|
|
|
|
delete d;
|
|
|
|
}
|
|
|
|
|
|
|
|
void DisplayNameComponent::layout( const TQRect &rect )
|
|
|
|
{
|
|
|
|
Component::layout( rect );
|
|
|
|
|
|
|
|
// finally, lay everything out
|
|
|
|
TQRect rc;
|
|
|
|
int totalWidth = rect.width();
|
|
|
|
int usedWidth = 0;
|
|
|
|
bool exceeded = false;
|
|
|
|
for ( uint n = 0; n < components(); ++n )
|
|
|
|
{
|
|
|
|
Component *comp = component( n );
|
|
|
|
if ( !exceeded )
|
|
|
|
{
|
|
|
|
if ( ( usedWidth + comp->widthForHeight( rect.height() ) ) > totalWidth )
|
|
|
|
{
|
|
|
|
exceeded = true;
|
|
|
|
// TextComponents can squeeze themselves
|
|
|
|
if ( comp->rtti() == Rtti_TextComponent )
|
|
|
|
{
|
|
|
|
comp->show();
|
|
|
|
comp->layout( TQRect( usedWidth+ rect.left(), rect.top(),
|
|
|
|
totalWidth - usedWidth,
|
|
|
|
comp->heightForWidth( totalWidth - usedWidth ) ) );
|
|
|
|
} else {
|
|
|
|
comp->hide();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
comp->show();
|
|
|
|
comp->layout( TQRect( usedWidth+ rect.left(), rect.top(),
|
|
|
|
comp->widthForHeight( rect.height() ),
|
|
|
|
comp->heightForWidth( rect.width() ) ) );
|
|
|
|
}
|
|
|
|
usedWidth+= comp->widthForHeight( rect.height() );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Shall we implement a hide()/show() in Component class ?
|
|
|
|
comp->hide();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void DisplayNameComponent::setText( const TQString& text )
|
|
|
|
{
|
|
|
|
if ( d->text == text )
|
|
|
|
return;
|
|
|
|
d->text = text;
|
|
|
|
|
|
|
|
redraw();
|
|
|
|
}
|
|
|
|
|
|
|
|
void DisplayNameComponent::redraw()
|
|
|
|
{
|
|
|
|
TQColor color;
|
|
|
|
for ( uint n = 0; n < components(); ++n )
|
|
|
|
if( component( n )->rtti() == Rtti_TextComponent )
|
|
|
|
{
|
|
|
|
((TextComponent*)component(n))->color();
|
|
|
|
}
|
|
|
|
|
|
|
|
TQValueList<Kopete::Emoticons::Token> tokens;
|
|
|
|
TQValueList<Kopete::Emoticons::Token>::const_iterator token;
|
|
|
|
|
|
|
|
clear(); // clear childs
|
|
|
|
|
|
|
|
tokens = Kopete::Emoticons::tokenizeEmoticons( d->text );
|
|
|
|
ImageComponent *ic;
|
|
|
|
TextComponent *t;
|
|
|
|
|
|
|
|
TQFontMetrics fontMetrics( d->font );
|
|
|
|
int fontHeight = fontMetrics.height();
|
|
|
|
for ( token = tokens.begin(); token != tokens.end(); ++token )
|
|
|
|
{
|
|
|
|
switch ( (*token).type )
|
|
|
|
{
|
|
|
|
case Kopete::Emoticons::Text:
|
|
|
|
t = new TextComponent( this, d->font, (*token).text );
|
|
|
|
break;
|
|
|
|
case Kopete::Emoticons::Image:
|
|
|
|
ic = new ImageComponent( this );
|
|
|
|
ic->setPixmap( TQPixmap( (*token).picPath ) );
|
|
|
|
ic->scale( INT_MAX, fontHeight, TQ_ScaleMin );
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
kdDebug( 14010 ) << k_funcinfo << "This should have not happened!" << endl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(color.isValid())
|
|
|
|
setColor( color );
|
|
|
|
}
|
|
|
|
|
|
|
|
void DisplayNameComponent::setFont( const TQFont& font )
|
|
|
|
{
|
|
|
|
for ( uint n = 0; n < components(); ++n )
|
|
|
|
if( component( n )->rtti() == Rtti_TextComponent )
|
|
|
|
((TextComponent*)component(n))->setFont( font );
|
|
|
|
d->font = font;
|
|
|
|
}
|
|
|
|
|
|
|
|
void DisplayNameComponent::setColor( const TQColor& color )
|
|
|
|
{
|
|
|
|
for ( uint n = 0; n < components(); ++n )
|
|
|
|
if( component( n )->rtti() == Rtti_TextComponent )
|
|
|
|
((TextComponent*)component(n))->setColor( color );
|
|
|
|
}
|
|
|
|
|
|
|
|
void DisplayNameComponent::setDefaultColor()
|
|
|
|
{
|
|
|
|
for ( uint n = 0; n < components(); ++n )
|
|
|
|
if( component( n )->rtti() == Rtti_TextComponent )
|
|
|
|
((TextComponent*)component(n))->setDefaultColor();
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString DisplayNameComponent::text()
|
|
|
|
{
|
|
|
|
return d->text;
|
|
|
|
}
|
|
|
|
|
|
|
|
// HSpacerComponent --------
|
|
|
|
|
|
|
|
HSpacerComponent::HSpacerComponent( ComponentBase *parent )
|
|
|
|
: Component( parent )
|
|
|
|
{
|
|
|
|
setMinWidth( 0 );
|
|
|
|
setMinHeight( 0 );
|
|
|
|
}
|
|
|
|
|
|
|
|
int HSpacerComponent::RTTI = Rtti_HSpacerComponent;
|
|
|
|
|
|
|
|
int HSpacerComponent::widthForHeight( int )
|
|
|
|
{
|
|
|
|
return INT_MAX;
|
|
|
|
}
|
|
|
|
|
|
|
|
// VSpacerComponent --------
|
|
|
|
|
|
|
|
VSpacerComponent::VSpacerComponent( ComponentBase *parent )
|
|
|
|
: Component( parent )
|
|
|
|
{
|
|
|
|
setMinWidth( 0 );
|
|
|
|
setMinHeight( 0 );
|
|
|
|
}
|
|
|
|
|
|
|
|
int VSpacerComponent::RTTI = Rtti_VSpacerComponent;
|
|
|
|
|
|
|
|
int VSpacerComponent::heightForWidth( int )
|
|
|
|
{
|
|
|
|
return INT_MAX;
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////// ContactComponent /////////////////////////
|
|
|
|
|
|
|
|
class ContactComponent::Private
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
Kopete::Contact *contact;
|
|
|
|
int iconSize;
|
|
|
|
};
|
|
|
|
|
|
|
|
ContactComponent::ContactComponent( ComponentBase *parent, Kopete::Contact *contact, int) : ImageComponent( parent ) , d( new Private )
|
|
|
|
{
|
|
|
|
d->contact = contact;
|
|
|
|
d->iconSize = 12; // size of the image is fixed to 12 pixels
|
|
|
|
updatePixmap();
|
|
|
|
}
|
|
|
|
|
|
|
|
ContactComponent::~ContactComponent()
|
|
|
|
{
|
|
|
|
delete d;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ContactComponent::updatePixmap()
|
|
|
|
{
|
|
|
|
setPixmap( contact()->onlineStatus().iconFor( contact(), d->iconSize ) );
|
|
|
|
}
|
|
|
|
Kopete::Contact *ContactComponent::contact()
|
|
|
|
{
|
|
|
|
return d->contact;
|
|
|
|
}
|
|
|
|
|
|
|
|
// we don't need to use a tooltip source here - this way is simpler
|
|
|
|
std::pair<TQString,TQRect> ContactComponent::toolTip( const TQPoint &/*relativePos*/ )
|
|
|
|
{
|
|
|
|
return std::make_pair(d->contact->toolTip(),rect());
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////// SpacerComponent /////////////////////////
|
|
|
|
|
|
|
|
SpacerComponent::SpacerComponent( ComponentBase *parent, int w, int h ) : Component( parent )
|
|
|
|
{
|
|
|
|
setMinWidth(w);
|
|
|
|
setMinHeight(h);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Item --------
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A periodic timer intended to be shared amongst multiple objects. Will run only
|
|
|
|
* if an object is attached to it.
|
|
|
|
*/
|
|
|
|
class SharedTimer : private TQTimer
|
|
|
|
{
|
|
|
|
int period;
|
|
|
|
int users;
|
|
|
|
public:
|
|
|
|
SharedTimer( int period ) : period(period), users(0) {}
|
|
|
|
void attach( TQObject *target, const char *slot )
|
|
|
|
{
|
|
|
|
connect( this, TQT_SIGNAL(timeout()), target, slot );
|
|
|
|
if( users++ == 0 )
|
|
|
|
start( period );
|
|
|
|
//kdDebug(14000) << "SharedTimer::attach: users is now " << users << "\n";
|
|
|
|
}
|
|
|
|
void detach( TQObject *target, const char *slot )
|
|
|
|
{
|
|
|
|
disconnect( this, TQT_SIGNAL(timeout()), target, slot );
|
|
|
|
if( --users == 0 )
|
|
|
|
stop();
|
|
|
|
//kdDebug(14000) << "SharedTimer::detach: users is now " << users << "\n";
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class SharedTimerRef
|
|
|
|
{
|
|
|
|
SharedTimer &timer;
|
|
|
|
TQObject * const object;
|
|
|
|
const char * const slot;
|
|
|
|
bool attached;
|
|
|
|
public:
|
|
|
|
SharedTimerRef( SharedTimer &timer, TQObject *obj, const char *slot )
|
|
|
|
: timer(timer), object(obj), slot(slot), attached(false)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
void start()
|
|
|
|
{
|
|
|
|
if( attached ) return;
|
|
|
|
timer.attach( object, slot );
|
|
|
|
attached = true;
|
|
|
|
}
|
|
|
|
void stop()
|
|
|
|
{
|
|
|
|
if( !attached ) return;
|
|
|
|
timer.detach( object, slot );
|
|
|
|
attached = false;
|
|
|
|
}
|
|
|
|
bool isActive()
|
|
|
|
{
|
|
|
|
return attached;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class Item::Private
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
Private( Item *item )
|
|
|
|
: layoutAnimateTimer( theLayoutAnimateTimer(), item, TQT_SLOT( slotLayoutAnimateItems() ) )
|
|
|
|
, animateLayout( true ), opacity( 1.0 )
|
|
|
|
, visibilityTimer( theVisibilityTimer(), item, TQT_SLOT( slotUpdateVisibility() ) )
|
|
|
|
, visibilityLevel( 0 ), visibilityTarget( false ), searchMatch( true )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
TQTimer layoutTimer;
|
|
|
|
|
|
|
|
//TQTimer layoutAnimateTimer;
|
|
|
|
SharedTimerRef layoutAnimateTimer;
|
|
|
|
SharedTimer &theLayoutAnimateTimer()
|
|
|
|
{
|
|
|
|
static SharedTimer timer( 10 );
|
|
|
|
return timer;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool animateLayout;
|
|
|
|
int layoutAnimateSteps;
|
|
|
|
static const int layoutAnimateStepsTotal = 10;
|
|
|
|
|
|
|
|
float opacity;
|
|
|
|
|
|
|
|
//TQTimer visibilityTimer;
|
|
|
|
SharedTimerRef visibilityTimer;
|
|
|
|
SharedTimer &theVisibilityTimer()
|
|
|
|
{
|
|
|
|
static SharedTimer timer( 40 );
|
|
|
|
return timer;
|
|
|
|
}
|
|
|
|
|
|
|
|
int visibilityLevel;
|
|
|
|
bool visibilityTarget;
|
|
|
|
static const int visibilityFoldSteps = 7;
|
|
|
|
#ifdef HAVE_XRENDER
|
|
|
|
static const int visibilityFadeSteps = 7;
|
|
|
|
#else
|
|
|
|
static const int visibilityFadeSteps = 0;
|
|
|
|
#endif
|
|
|
|
static const int visibilityStepsTotal = visibilityFoldSteps + visibilityFadeSteps;
|
|
|
|
|
|
|
|
bool searchMatch;
|
|
|
|
|
|
|
|
static bool animateChanges;
|
|
|
|
static bool fadeVisibility;
|
|
|
|
static bool foldVisibility;
|
|
|
|
};
|
|
|
|
|
|
|
|
bool Item::Private::animateChanges = true;
|
|
|
|
bool Item::Private::fadeVisibility = true;
|
|
|
|
bool Item::Private::foldVisibility = true;
|
|
|
|
|
|
|
|
Item::Item( TQListViewItem *parent, TQObject *owner, const char *name )
|
|
|
|
: TQObject( owner, name ), TDEListViewItem( parent ), d( new Private(this) )
|
|
|
|
{
|
|
|
|
initLVI();
|
|
|
|
}
|
|
|
|
|
|
|
|
Item::Item( TQListView *parent, TQObject *owner, const char *name )
|
|
|
|
: TQObject( owner, name ), TDEListViewItem( parent ), d( new Private(this) )
|
|
|
|
{
|
|
|
|
initLVI();
|
|
|
|
}
|
|
|
|
|
|
|
|
Item::~Item()
|
|
|
|
{
|
|
|
|
delete d;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Item::setEffects( bool animation, bool fading, bool folding )
|
|
|
|
{
|
|
|
|
Private::animateChanges = animation;
|
|
|
|
Private::fadeVisibility = fading;
|
|
|
|
Private::foldVisibility = folding;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Item::initLVI()
|
|
|
|
{
|
|
|
|
connect( listView()->header(), TQT_SIGNAL( sizeChange( int, int, int ) ), TQT_SLOT( slotColumnResized() ) );
|
|
|
|
connect( &d->layoutTimer, TQT_SIGNAL( timeout() ), TQT_SLOT( slotLayoutItems() ) );
|
|
|
|
//connect( &d->layoutAnimateTimer, TQT_SIGNAL( timeout() ), TQT_SLOT( slotLayoutAnimateItems() ) );
|
|
|
|
//connect( &d->visibilityTimer, TQT_SIGNAL( timeout() ), TQT_SLOT( slotUpdateVisibility() ) );
|
|
|
|
setVisible( false );
|
|
|
|
setTargetVisibility( true );
|
|
|
|
}
|
|
|
|
|
|
|
|
void Item::slotColumnResized()
|
|
|
|
{
|
|
|
|
scheduleLayout();
|
|
|
|
// if we've been resized, don't animate the layout
|
|
|
|
d->animateLayout = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Item::scheduleLayout()
|
|
|
|
{
|
|
|
|
// perform a delayed layout in order to speed it all up
|
|
|
|
if ( ! d->layoutTimer.isActive() )
|
|
|
|
d->layoutTimer.start( 30, true );
|
|
|
|
}
|
|
|
|
|
|
|
|
void Item::slotLayoutItems()
|
|
|
|
{
|
|
|
|
d->layoutTimer.stop();
|
|
|
|
|
|
|
|
for ( uint n = 0; n < components(); ++n )
|
|
|
|
{
|
|
|
|
int width = listView()->columnWidth(n);
|
|
|
|
if ( n == 0 )
|
|
|
|
{
|
|
|
|
int d = depth() + (listView()->rootIsDecorated() ? 1 : 0);
|
|
|
|
width -= d * listView()->treeStepSize();
|
|
|
|
}
|
|
|
|
|
|
|
|
int height = component( n )->heightForWidth( width );
|
|
|
|
component( n )->layout( TQRect( 0, 0, width, height ) );
|
|
|
|
//kdDebug(14000) << k_funcinfo << "Component " << n << " is " << width << " x " << height << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( Private::animateChanges && d->animateLayout && !d->visibilityTimer.isActive() )
|
|
|
|
{
|
|
|
|
d->layoutAnimateTimer.start();
|
|
|
|
//if ( !d->layoutAnimateTimer.isActive() )
|
|
|
|
// d->layoutAnimateTimer.start( 10 );
|
|
|
|
d->layoutAnimateSteps = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
d->layoutAnimateSteps = Private::layoutAnimateStepsTotal;
|
|
|
|
d->animateLayout = true;
|
|
|
|
}
|
|
|
|
slotLayoutAnimateItems();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Item::slotLayoutAnimateItems()
|
|
|
|
{
|
|
|
|
if ( ++d->layoutAnimateSteps >= Private::layoutAnimateStepsTotal )
|
|
|
|
d->layoutAnimateTimer.stop();
|
|
|
|
|
|
|
|
const int s = Private::layoutAnimateStepsTotal;
|
|
|
|
const int p = TQMIN( d->layoutAnimateSteps, s );
|
|
|
|
|
|
|
|
updateAnimationPosition( p, s );
|
|
|
|
setHeight(0);
|
|
|
|
repaint();
|
|
|
|
}
|
|
|
|
|
|
|
|
float Item::opacity()
|
|
|
|
{
|
|
|
|
return d->opacity;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Item::setOpacity( float opacity )
|
|
|
|
{
|
|
|
|
if ( d->opacity == opacity ) return;
|
|
|
|
d->opacity = opacity;
|
|
|
|
repaint();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Item::setSearchMatch( bool match )
|
|
|
|
{
|
|
|
|
d->searchMatch = match;
|
|
|
|
|
|
|
|
if ( !match )
|
|
|
|
setVisible( false );
|
|
|
|
else
|
|
|
|
{
|
|
|
|
kdDebug(14000) << k_funcinfo << " match: " << match << ", vis timer active: " << d->visibilityTimer.isActive()
|
|
|
|
<< ", target visibility: " << targetVisibility() << endl;
|
|
|
|
if ( d->visibilityTimer.isActive() )
|
|
|
|
setVisible( true );
|
|
|
|
else
|
|
|
|
setVisible( targetVisibility() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Item::targetVisibility()
|
|
|
|
{
|
|
|
|
return d->visibilityTarget;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Item::setTargetVisibility( bool vis )
|
|
|
|
{
|
|
|
|
if ( d->visibilityTarget == vis )
|
|
|
|
{
|
|
|
|
// in case we're getting called because our parent was shown and
|
|
|
|
// we need to be rehidden
|
|
|
|
if ( !d->visibilityTimer.isActive() )
|
|
|
|
setVisible( vis && d->searchMatch );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
d->visibilityTarget = vis;
|
|
|
|
d->visibilityTimer.start();
|
|
|
|
//d->visibilityTimer.start( 40 );
|
|
|
|
if ( targetVisibility() )
|
|
|
|
setVisible( d->searchMatch );
|
|
|
|
slotUpdateVisibility();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Item::slotUpdateVisibility()
|
|
|
|
{
|
|
|
|
if ( targetVisibility() )
|
|
|
|
++d->visibilityLevel;
|
|
|
|
else
|
|
|
|
--d->visibilityLevel;
|
|
|
|
|
|
|
|
if ( !Private::foldVisibility && !Private::fadeVisibility )
|
|
|
|
d->visibilityLevel = targetVisibility() ? Private::visibilityStepsTotal : 0;
|
|
|
|
else if ( !Private::fadeVisibility && d->visibilityLevel >= Private::visibilityFoldSteps )
|
|
|
|
d->visibilityLevel = targetVisibility() ? Private::visibilityStepsTotal : Private::visibilityFoldSteps - 1;
|
|
|
|
else if ( !Private::foldVisibility && d->visibilityLevel <= Private::visibilityFoldSteps )
|
|
|
|
d->visibilityLevel = targetVisibility() ? Private::visibilityFoldSteps + 1 : 0;
|
|
|
|
|
|
|
|
if ( d->visibilityLevel >= Private::visibilityStepsTotal )
|
|
|
|
{
|
|
|
|
d->visibilityLevel = Private::visibilityStepsTotal;
|
|
|
|
d->visibilityTimer.stop();
|
|
|
|
}
|
|
|
|
else if ( d->visibilityLevel <= 0 )
|
|
|
|
{
|
|
|
|
d->visibilityLevel = 0;
|
|
|
|
d->visibilityTimer.stop();
|
|
|
|
setVisible( false );
|
|
|
|
}
|
|
|
|
setHeight( 0 );
|
|
|
|
repaint();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Item::repaint()
|
|
|
|
{
|
|
|
|
// if we're about to relayout, don't bother painting yet.
|
|
|
|
if ( d->layoutTimer.isActive() )
|
|
|
|
return;
|
|
|
|
listView()->repaintItem( this );
|
|
|
|
}
|
|
|
|
|
|
|
|
void Item::relayout()
|
|
|
|
{
|
|
|
|
scheduleLayout();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Item::setup()
|
|
|
|
{
|
|
|
|
TDEListViewItem::setup();
|
|
|
|
slotLayoutItems();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Item::setHeight( int )
|
|
|
|
{
|
|
|
|
int minHeight = 0;
|
|
|
|
for ( uint n = 0; n < components(); ++n )
|
|
|
|
minHeight = TQMAX( minHeight, component( n )->rect().height() );
|
|
|
|
//kdDebug(14000) << k_funcinfo << "Height is " << minHeight << endl;
|
|
|
|
if ( Private::foldVisibility && d->visibilityTimer.isActive() )
|
|
|
|
{
|
|
|
|
int vis = TQMIN( d->visibilityLevel, Private::visibilityFoldSteps );
|
|
|
|
minHeight = (minHeight * vis) / Private::visibilityFoldSteps;
|
|
|
|
}
|
|
|
|
TDEListViewItem::setHeight( minHeight );
|
|
|
|
}
|
|
|
|
|
|
|
|
int Item::width( const TQFontMetrics &, const TQListView *lv, int c ) const
|
|
|
|
{
|
|
|
|
// TQt computes the itemRect from this. we want the whole item to be
|
|
|
|
// clickable, so we return the widest we could possibly be.
|
|
|
|
return lv->header()->sectionSize( c );
|
|
|
|
}
|
|
|
|
|
|
|
|
void Item::paintCell( TQPainter *p, const TQColorGroup &cg, int column, int width, int align )
|
|
|
|
{
|
|
|
|
TQPixmap back( width, height() );
|
|
|
|
TQPainter paint( &back );
|
|
|
|
//TDEListViewItem::paintCell( &paint, cg, column, width, align );
|
|
|
|
// PASTED FROM KLISTVIEWITEM:
|
|
|
|
// set the alternate cell background colour if necessary
|
|
|
|
TQColorGroup _cg = cg;
|
|
|
|
if (isAlternate())
|
|
|
|
if (listView()->viewport()->backgroundMode()==TQt::FixedColor)
|
|
|
|
_cg.setColor(TQColorGroup::Background, static_cast< TDEListView* >(listView())->alternateBackground());
|
|
|
|
else
|
|
|
|
_cg.setColor(TQColorGroup::Base, static_cast< TDEListView* >(listView())->alternateBackground());
|
|
|
|
// PASTED FROM TQLISTVIEWITEM
|
|
|
|
{
|
|
|
|
TQPainter *p = &paint;
|
|
|
|
|
|
|
|
TQListView *lv = listView();
|
|
|
|
if ( !lv )
|
|
|
|
return;
|
|
|
|
TQFontMetrics fm( p->fontMetrics() );
|
|
|
|
|
|
|
|
// any text we render is done by the Components, not by this class, so make sure we've nothing to write
|
|
|
|
TQString t;
|
|
|
|
|
|
|
|
// removed text truncating code from TQt - we do that differently, further on
|
|
|
|
|
|
|
|
int marg = lv->itemMargin();
|
|
|
|
int r = marg;
|
|
|
|
// const TQPixmap * icon = pixmap( column );
|
|
|
|
|
|
|
|
const BackgroundMode bgmode = lv->viewport()->backgroundMode();
|
|
|
|
const TQColorGroup::ColorRole crole = TQPalette::backgroundRoleFromMode( bgmode );
|
|
|
|
|
|
|
|
if ( _cg.brush( crole ) != lv->colorGroup().brush( crole ) )
|
|
|
|
p->fillRect( 0, 0, width, height(), _cg.brush( crole ) );
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// all copied from TQListView::paintEmptyArea
|
|
|
|
|
|
|
|
//lv->paintEmptyArea( p, TQRect( 0, 0, width, height() ) );
|
|
|
|
TQStyleOption opt( lv->sortColumn(), 0 ); // ### hack; in 3.1, add a property in TQListView and TQHeader
|
|
|
|
TQStyle::SFlags how = TQStyle::Style_Default;
|
|
|
|
if ( lv->isEnabled() )
|
|
|
|
how |= TQStyle::Style_Enabled;
|
|
|
|
|
|
|
|
lv->style().drawComplexControl( TQStyle::CC_ListView,
|
|
|
|
p, lv, TQRect( 0, 0, width, height() ), lv->colorGroup(),
|
|
|
|
how, TQStyle::SC_ListView, TQStyle::SC_None,
|
|
|
|
opt );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ( isSelected() &&
|
|
|
|
(column == 0 || lv->allColumnsShowFocus()) ) {
|
|
|
|
p->fillRect( r - marg, 0, width - r + marg, height(),
|
|
|
|
_cg.brush( TQColorGroup::Highlight ) );
|
|
|
|
// removed text pen setting code from TQt
|
|
|
|
}
|
|
|
|
|
|
|
|
// removed icon drawing code from TQt
|
|
|
|
|
|
|
|
// draw the tree gubbins
|
|
|
|
if ( multiLinesEnabled() && column == 0 && isOpen() && childCount() ) {
|
|
|
|
int textheight = fm.size( align, t ).height() + 2 * lv->itemMargin();
|
|
|
|
textheight = TQMAX( textheight, TQApplication::globalStrut().height() );
|
|
|
|
if ( textheight % 2 > 0 )
|
|
|
|
textheight++;
|
|
|
|
if ( textheight < height() ) {
|
|
|
|
int w = lv->treeStepSize() / 2;
|
|
|
|
lv->style().drawComplexControl( TQStyle::CC_ListView, p, lv,
|
|
|
|
TQRect( 0, textheight, w + 1, height() - textheight + 1 ), _cg,
|
|
|
|
lv->isEnabled() ? TQStyle::Style_Enabled : TQStyle::Style_Default,
|
|
|
|
TQStyle::SC_ListViewExpand,
|
|
|
|
(uint)TQStyle::SC_All, TQStyleOption( this ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// END OF PASTE
|
|
|
|
|
|
|
|
|
|
|
|
//do you see a better way to tell the TextComponent we are selected ? - Olivier 2004-09-02
|
|
|
|
if ( isSelected() )
|
|
|
|
_cg.setColor(TQColorGroup::Text , _cg.highlightedText() );
|
|
|
|
|
|
|
|
if ( Component *comp = component( column ) )
|
|
|
|
comp->paint( &paint, _cg );
|
|
|
|
paint.end();
|
|
|
|
|
|
|
|
#ifdef HAVE_XRENDER
|
|
|
|
TQColor rgb = cg.base();//backgroundColor();
|
|
|
|
float opac = 1.0;
|
|
|
|
if ( d->visibilityTimer.isActive() && Private::fadeVisibility )
|
|
|
|
{
|
|
|
|
int vis = TQMAX( d->visibilityLevel - Private::visibilityFoldSteps, 0 );
|
|
|
|
opac = float(vis) / Private::visibilityFadeSteps;
|
|
|
|
}
|
|
|
|
opac *= opacity();
|
|
|
|
const int alpha = 257 - int(opac * 257);
|
|
|
|
if ( alpha != 0 )
|
|
|
|
{
|
|
|
|
XRenderColor clr = { alpha * rgb.red(), alpha * rgb.green(), alpha * rgb.blue(), alpha * 0xff };
|
|
|
|
XRenderFillRectangle( back.x11Display(), PictOpOver, back.x11RenderHandle(),
|
|
|
|
&clr, 0, 0, width, height() );
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
p->drawPixmap( 0, 0, back );
|
|
|
|
}
|
|
|
|
|
|
|
|
void Item::componentAdded( Component *component )
|
|
|
|
{
|
|
|
|
ComponentBase::componentAdded( component );
|
|
|
|
scheduleLayout();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Item::componentRemoved( Component *component )
|
|
|
|
{
|
|
|
|
ComponentBase::componentRemoved( component );
|
|
|
|
scheduleLayout();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Item::componentResized( Component *component )
|
|
|
|
{
|
|
|
|
ComponentBase::componentResized( component );
|
|
|
|
scheduleLayout();
|
|
|
|
}
|
|
|
|
|
|
|
|
} // END namespace ListView
|
|
|
|
} // END namespace UI
|
|
|
|
} // END namespace Kopete
|
|
|
|
|
|
|
|
#include "kopetelistviewitem.moc"
|
|
|
|
|
|
|
|
// vim: set noet ts=4 sts=4 sw=4:
|