|
|
|
/* This file is part of the KDE project
|
|
|
|
Copyright (C) 2003 Ariya Hidayat <ariya@kde.org>
|
|
|
|
Copyright (C) 2003 Norbert Andres <nandres@web.de>
|
|
|
|
Copyright (C) 2002 Laurent Montel <montel@kde.org>
|
|
|
|
Copyright (C) 1999 David Faure <faure@kde.org>
|
|
|
|
Copyright (C) 1999 Boris Wedl <boris.wedl@kfunigraz.ac.at>
|
|
|
|
Copyright (C) 1998-2000 Torben Weis <weis@kde.org>
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU Library General Public
|
|
|
|
License as published by the Free Software Foundation; either
|
|
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
Library General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
|
|
along with this library; see the file COPYING.LIB. If not, write to
|
|
|
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
|
|
* Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "KoTabBar.h"
|
|
|
|
|
|
|
|
#include <tqdrawutil.h>
|
|
|
|
#include <tqpainter.h>
|
|
|
|
#include <tqstring.h>
|
|
|
|
#include <tqstringlist.h>
|
|
|
|
#include <tqstyle.h>
|
|
|
|
#include <tqtimer.h>
|
|
|
|
#include <tqtoolbutton.h>
|
|
|
|
#include <tqvaluevector.h>
|
|
|
|
#include <tqwidget.h>
|
|
|
|
|
|
|
|
// TODO
|
|
|
|
// improvement possibilities
|
|
|
|
// - use offscreen buffer to reduce flicker even more
|
|
|
|
// - keep track of tabs, only (re)layout when necessary
|
|
|
|
// - paint all tabs to buffer, show only by shifting
|
|
|
|
// - customizable button pixmaps
|
|
|
|
// - use TQStyle to paint the tabs & buttons (is it good/possible?)
|
|
|
|
|
|
|
|
|
|
|
|
class KoTabBarPrivate
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
KoTabBar* tabbar;
|
|
|
|
|
|
|
|
// scroll buttons
|
|
|
|
TQToolButton* scrollFirstButton;
|
|
|
|
TQToolButton* scrollLastButton;
|
|
|
|
TQToolButton* scrollBackButton;
|
|
|
|
TQToolButton* scrollForwardButton;
|
|
|
|
|
|
|
|
// read-only: no mouse drag, double-click, right-click
|
|
|
|
bool readOnly;
|
|
|
|
|
|
|
|
// if true, layout is from right to left
|
|
|
|
bool reverseLayout;
|
|
|
|
|
|
|
|
// list of all tabs, in order of appearance
|
|
|
|
TQStringList tabs;
|
|
|
|
|
|
|
|
// array of TQRect for each visible tabs
|
|
|
|
TQValueVector<TQRect> tabRects;
|
|
|
|
|
|
|
|
// leftmost tab (or rightmost if reverseLayout)
|
|
|
|
int firstTab;
|
|
|
|
|
|
|
|
// rightmost tab (or leftmost if reverseLayout)
|
|
|
|
int lastTab;
|
|
|
|
|
|
|
|
// the active tab in the range form 1..n.
|
|
|
|
// if this value is 0, that means that no tab is active.
|
|
|
|
int activeTab;
|
|
|
|
|
|
|
|
// unusable space on the left, taken by the scroll buttons
|
|
|
|
int offset;
|
|
|
|
|
|
|
|
// when the user drag the tab (in order to move it)
|
|
|
|
// this is the target position, it's 0 if no tab is dragged
|
|
|
|
int targetTab;
|
|
|
|
|
|
|
|
// wheel movement since selected tab was last changed by the
|
|
|
|
// mouse wheel
|
|
|
|
int wheelDelta;
|
|
|
|
|
|
|
|
// true if autoscroll is active
|
|
|
|
bool autoScroll;
|
|
|
|
|
|
|
|
// calculate the bounding rectangle for each visible tab
|
|
|
|
void layoutTabs();
|
|
|
|
|
|
|
|
// reposition scroll buttons
|
|
|
|
void layoutButtons();
|
|
|
|
|
|
|
|
// find a tab whose bounding rectangle contains the pos
|
|
|
|
// return -1 if no such tab is found
|
|
|
|
int tabAt( const TQPoint& pos );
|
|
|
|
|
|
|
|
// draw a single tab
|
|
|
|
void drawTab( TQPainter& painter, TQRect& rect, const TQString& text, bool active );
|
|
|
|
|
|
|
|
// draw a marker to indicate tab moving
|
|
|
|
void drawMoveMarker( TQPainter& painter, int x, int y );
|
|
|
|
|
|
|
|
// update the enable/disable status of scroll buttons
|
|
|
|
void updateButtons();
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
// built-in pixmap for scroll-first button
|
|
|
|
static const char * arrow_leftmost_xpm[] = {
|
|
|
|
"10 10 2 1",
|
|
|
|
" c None",
|
|
|
|
". c #000000",
|
|
|
|
" ",
|
|
|
|
" . . ",
|
|
|
|
" . .. ",
|
|
|
|
" . ... ",
|
|
|
|
" . .... ",
|
|
|
|
" . ... ",
|
|
|
|
" . .. ",
|
|
|
|
" . . ",
|
|
|
|
" ",
|
|
|
|
" "};
|
|
|
|
|
|
|
|
// built-in pixmap for scroll-last button
|
|
|
|
static const char * arrow_rightmost_xpm[] = {
|
|
|
|
"10 10 2 1",
|
|
|
|
" c None",
|
|
|
|
". c #000000",
|
|
|
|
" ",
|
|
|
|
" . . ",
|
|
|
|
" .. . ",
|
|
|
|
" ... . ",
|
|
|
|
" .... . ",
|
|
|
|
" ... . ",
|
|
|
|
" .. . ",
|
|
|
|
" . . ",
|
|
|
|
" ",
|
|
|
|
" "};
|
|
|
|
|
|
|
|
// built-in pixmap for scroll-left button
|
|
|
|
static const char * arrow_left_xpm[] = {
|
|
|
|
"10 10 2 1",
|
|
|
|
" c None",
|
|
|
|
". c #000000",
|
|
|
|
" ",
|
|
|
|
" . ",
|
|
|
|
" .. ",
|
|
|
|
" ... ",
|
|
|
|
" .... ",
|
|
|
|
" ... ",
|
|
|
|
" .. ",
|
|
|
|
" . ",
|
|
|
|
" ",
|
|
|
|
" "};
|
|
|
|
|
|
|
|
// built-in pixmap for scroll-right button
|
|
|
|
static const char * arrow_right_xpm[] = {
|
|
|
|
"10 10 2 1",
|
|
|
|
" c None",
|
|
|
|
". c #000000",
|
|
|
|
" ",
|
|
|
|
" . ",
|
|
|
|
" .. ",
|
|
|
|
" ... ",
|
|
|
|
" .... ",
|
|
|
|
" ... ",
|
|
|
|
" .. ",
|
|
|
|
" . ",
|
|
|
|
" ",
|
|
|
|
" "};
|
|
|
|
|
|
|
|
|
|
|
|
void KoTabBarPrivate::layoutTabs()
|
|
|
|
{
|
|
|
|
tabRects.clear();
|
|
|
|
|
|
|
|
TQPainter painter( tabbar );
|
|
|
|
|
|
|
|
TQFont f = painter.font();
|
|
|
|
f.setBold( true );
|
|
|
|
painter.setFont( f );
|
|
|
|
TQFontMetrics fm = painter.fontMetrics();
|
|
|
|
|
|
|
|
if( !reverseLayout )
|
|
|
|
{
|
|
|
|
// left to right
|
|
|
|
int x = 0;
|
|
|
|
for( unsigned c = 0; c < tabs.count(); c++ )
|
|
|
|
{
|
|
|
|
TQRect rect;
|
|
|
|
if( (int)c >= firstTab-1 )
|
|
|
|
{
|
|
|
|
TQString text = tabs[ c ];
|
|
|
|
int tw = fm.width( text ) + 4;
|
|
|
|
rect = TQRect( x, 0, tw + 20, tabbar->height() );
|
|
|
|
x = x + tw + 20;
|
|
|
|
}
|
|
|
|
tabRects.append( rect );
|
|
|
|
}
|
|
|
|
|
|
|
|
lastTab = tabRects.count();
|
|
|
|
for( unsigned i = 0; i < tabRects.count(); i++ )
|
|
|
|
if( tabRects[i].right()-10+offset > tabbar->width() )
|
|
|
|
{
|
|
|
|
lastTab = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// right to left
|
|
|
|
int x = tabbar->width() - offset;
|
|
|
|
for( unsigned c = 0; c < tabs.count(); c++ )
|
|
|
|
{
|
|
|
|
TQRect rect;
|
|
|
|
if( (int)c >= firstTab-1 )
|
|
|
|
{
|
|
|
|
TQString text = tabs[ c ];
|
|
|
|
int tw = fm.width( text ) + 4;
|
|
|
|
rect = TQRect( x - tw - 20, 0, tw + 20, tabbar->height() );
|
|
|
|
x = x - tw - 20;
|
|
|
|
}
|
|
|
|
tabRects.append( rect );
|
|
|
|
}
|
|
|
|
|
|
|
|
lastTab = tabRects.count();
|
|
|
|
for( unsigned i = tabRects.count()-1; i>0; i-- )
|
|
|
|
if( tabRects[i].left() > 0 )
|
|
|
|
{
|
|
|
|
lastTab = i+1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int KoTabBarPrivate::tabAt( const TQPoint& pos )
|
|
|
|
{
|
|
|
|
for( unsigned i = 0; i < tabRects.count(); i++ )
|
|
|
|
{
|
|
|
|
TQRect rect = tabRects[ i ];
|
|
|
|
if( rect.isNull() ) continue;
|
|
|
|
if( rect.contains( pos ) ) return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1; // not found
|
|
|
|
}
|
|
|
|
|
|
|
|
void KoTabBarPrivate::drawTab( TQPainter& painter, TQRect& rect, const TQString& text, bool active )
|
|
|
|
{
|
|
|
|
TQPointArray polygon;
|
|
|
|
|
|
|
|
if( !reverseLayout )
|
|
|
|
polygon.setPoints( 6, rect.x(), rect.y(),
|
|
|
|
rect.x(), rect.bottom()-3,
|
|
|
|
rect.x()+2, rect.bottom(),
|
|
|
|
rect.right()-4, rect.bottom(),
|
|
|
|
rect.right()-2, rect.bottom()-2,
|
|
|
|
rect.right()+5, rect.top() );
|
|
|
|
else
|
|
|
|
polygon.setPoints( 6, rect.right(), rect.top(),
|
|
|
|
rect.right(), rect.bottom()-3,
|
|
|
|
rect.right()-2, rect.bottom(),
|
|
|
|
rect.x()+4, rect.bottom(),
|
|
|
|
rect.x()+2, rect.bottom()-2,
|
|
|
|
rect.x()-5, rect.top() );
|
|
|
|
|
|
|
|
painter.save();
|
|
|
|
|
|
|
|
// fill it first
|
|
|
|
TQBrush bg = tabbar->colorGroup().background();
|
|
|
|
if( active ) bg = TQBrush(tabbar->colorGroup().base());
|
|
|
|
painter.setBrush( bg );
|
|
|
|
painter.setPen( TQPen( TQt::NoPen ) );
|
|
|
|
painter.drawPolygon( polygon );
|
|
|
|
|
|
|
|
// draw the lines
|
|
|
|
painter.setPen( tabbar->colorGroup().dark() );
|
|
|
|
if( !active )
|
|
|
|
painter.drawLine( rect.x()-25, rect.y(), rect.right()+25, rect.top() );
|
|
|
|
// TQt4: painter.setRenderHint( TQPainter::Antialiasing );
|
|
|
|
painter.drawPolyline( polygon );
|
|
|
|
|
|
|
|
painter.setPen( tabbar->colorGroup().buttonText() );
|
|
|
|
TQFont f = painter.font();
|
|
|
|
if( active ) f.setBold( true );
|
|
|
|
painter.setFont( f );
|
|
|
|
TQFontMetrics fm = painter.fontMetrics();
|
|
|
|
int tx = rect.x() + ( rect.width() - fm.width( text ) ) / 2;
|
|
|
|
int ty = rect.y() + ( rect.height() - fm.height() ) / 2 + fm.ascent();
|
|
|
|
painter.drawText( tx, ty, text );
|
|
|
|
|
|
|
|
painter.restore();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KoTabBarPrivate::drawMoveMarker( TQPainter& painter, int x, int y )
|
|
|
|
{
|
|
|
|
TQPointArray movmark;
|
|
|
|
movmark.setPoints( 3, x, y, x + 7, y, x + 4, y + 6);
|
|
|
|
TQBrush oldBrush = painter.brush();
|
|
|
|
painter.setBrush( TQt::black );
|
|
|
|
painter.drawPolygon(movmark);
|
|
|
|
painter.setBrush( oldBrush );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KoTabBarPrivate::layoutButtons()
|
|
|
|
{
|
|
|
|
int bw = tabbar->height();
|
|
|
|
int w = tabbar->width();
|
|
|
|
offset = bw * 4;
|
|
|
|
|
|
|
|
if( !reverseLayout )
|
|
|
|
{
|
|
|
|
scrollFirstButton->setGeometry( 0, 0, bw, bw );
|
|
|
|
scrollFirstButton->setPixmap( arrow_leftmost_xpm );
|
|
|
|
scrollBackButton->setGeometry( bw, 0, bw, bw );
|
|
|
|
scrollBackButton->setPixmap( arrow_left_xpm );
|
|
|
|
scrollForwardButton->setGeometry( bw*2, 0, bw, bw );
|
|
|
|
scrollForwardButton->setPixmap( arrow_right_xpm );
|
|
|
|
scrollLastButton->setGeometry( bw*3, 0, bw, bw );
|
|
|
|
scrollLastButton->setPixmap( arrow_rightmost_xpm );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
scrollFirstButton->setGeometry( w-bw, 0, bw, bw );
|
|
|
|
scrollFirstButton->setPixmap( arrow_rightmost_xpm );
|
|
|
|
scrollBackButton->setGeometry( w-2*bw, 0, bw, bw );
|
|
|
|
scrollBackButton->setPixmap( arrow_right_xpm );
|
|
|
|
scrollForwardButton->setGeometry( w-3*bw, 0, bw, bw );
|
|
|
|
scrollForwardButton->setPixmap( arrow_left_xpm );
|
|
|
|
scrollLastButton->setGeometry( w-4*bw, 0, bw, bw );
|
|
|
|
scrollLastButton->setPixmap( arrow_leftmost_xpm );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KoTabBarPrivate::updateButtons()
|
|
|
|
{
|
|
|
|
scrollFirstButton->setEnabled( tabbar->canScrollBack() );
|
|
|
|
scrollBackButton->setEnabled( tabbar->canScrollBack() );
|
|
|
|
scrollForwardButton->setEnabled( tabbar->canScrollForward() );
|
|
|
|
scrollLastButton->setEnabled( tabbar->canScrollForward() );
|
|
|
|
}
|
|
|
|
|
|
|
|
// creates a new tabbar
|
|
|
|
KoTabBar::KoTabBar( TQWidget* parent, const char* name )
|
|
|
|
: TQWidget( parent, name, TQt::WResizeNoErase | TQt::WRepaintNoErase )
|
|
|
|
{
|
|
|
|
d = new KoTabBarPrivate;
|
|
|
|
d->tabbar = this;
|
|
|
|
d->readOnly = false;
|
|
|
|
d->reverseLayout = false;
|
|
|
|
d->firstTab = 1;
|
|
|
|
d->lastTab = 0;
|
|
|
|
d->activeTab = 0;
|
|
|
|
d->targetTab = 0;
|
|
|
|
d->wheelDelta = 0;
|
|
|
|
d->autoScroll = false;
|
|
|
|
d->offset = 64;
|
|
|
|
|
|
|
|
// initialize the scroll buttons
|
|
|
|
d->scrollFirstButton = new TQToolButton( this );
|
|
|
|
connect( d->scrollFirstButton, TQT_SIGNAL( clicked() ),
|
|
|
|
this, TQT_SLOT( scrollFirst() ) );
|
|
|
|
d->scrollLastButton = new TQToolButton( this );
|
|
|
|
connect( d->scrollLastButton, TQT_SIGNAL( clicked() ),
|
|
|
|
this, TQT_SLOT( scrollLast() ) );
|
|
|
|
d->scrollBackButton = new TQToolButton( this );
|
|
|
|
connect( d->scrollBackButton, TQT_SIGNAL( clicked() ),
|
|
|
|
this, TQT_SLOT( scrollBack() ) );
|
|
|
|
d->scrollForwardButton = new TQToolButton( this );
|
|
|
|
connect( d->scrollForwardButton, TQT_SIGNAL( clicked() ),
|
|
|
|
this, TQT_SLOT( scrollForward() ) );
|
|
|
|
d->layoutButtons();
|
|
|
|
d->updateButtons();
|
|
|
|
}
|
|
|
|
|
|
|
|
// destroys the tabbar
|
|
|
|
KoTabBar::~KoTabBar()
|
|
|
|
{
|
|
|
|
delete d;
|
|
|
|
}
|
|
|
|
|
|
|
|
// adds a new visible tab
|
|
|
|
void KoTabBar::addTab( const TQString& text )
|
|
|
|
{
|
|
|
|
d->tabs.append( text );
|
|
|
|
|
|
|
|
update();
|
|
|
|
}
|
|
|
|
|
|
|
|
// removes a tab
|
|
|
|
void KoTabBar::removeTab( const TQString& text )
|
|
|
|
{
|
|
|
|
int i = d->tabs.findIndex( text );
|
|
|
|
if ( i == -1 ) return;
|
|
|
|
|
|
|
|
if ( d->activeTab == i + 1 )
|
|
|
|
d->activeTab = 0;
|
|
|
|
|
|
|
|
d->tabs.remove( text );
|
|
|
|
|
|
|
|
update();
|
|
|
|
}
|
|
|
|
|
|
|
|
// removes all tabs
|
|
|
|
void KoTabBar::clear()
|
|
|
|
{
|
|
|
|
d->tabs.clear();
|
|
|
|
d->activeTab = 0;
|
|
|
|
d->firstTab = 1;
|
|
|
|
|
|
|
|
update();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KoTabBar::readOnly() const
|
|
|
|
{
|
|
|
|
return d->readOnly;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KoTabBar::setReadOnly( bool ro )
|
|
|
|
{
|
|
|
|
d->readOnly = ro;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KoTabBar::reverseLayout() const
|
|
|
|
{
|
|
|
|
return d->reverseLayout;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KoTabBar::setReverseLayout( bool reverse )
|
|
|
|
{
|
|
|
|
if( reverse != d->reverseLayout )
|
|
|
|
{
|
|
|
|
d->reverseLayout = reverse;
|
|
|
|
d->layoutTabs();
|
|
|
|
d->layoutButtons();
|
|
|
|
d->updateButtons();
|
|
|
|
update();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KoTabBar::setTabs( const TQStringList& list )
|
|
|
|
{
|
|
|
|
TQString left, active;
|
|
|
|
|
|
|
|
if( d->activeTab > 0 )
|
|
|
|
active = d->tabs[ d->activeTab-1 ];
|
|
|
|
if( d->firstTab > 0 )
|
|
|
|
left = d->tabs[ d->firstTab-1 ];
|
|
|
|
|
|
|
|
d->tabs = list;
|
|
|
|
|
|
|
|
if( !left.isNull() )
|
|
|
|
{
|
|
|
|
d->firstTab = d->tabs.findIndex( left ) + 1;
|
|
|
|
if( d->firstTab > (int)d->tabs.count() )
|
|
|
|
d->firstTab = 1;
|
|
|
|
if( d->firstTab <= 0 )
|
|
|
|
d->firstTab = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
d->activeTab = 0;
|
|
|
|
if( !active.isNull() )
|
|
|
|
setActiveTab( active );
|
|
|
|
|
|
|
|
update();
|
|
|
|
}
|
|
|
|
|
|
|
|
TQStringList KoTabBar::tabs() const
|
|
|
|
{
|
|
|
|
return d->tabs;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned KoTabBar::count() const
|
|
|
|
{
|
|
|
|
return d->tabs.count();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KoTabBar::canScrollBack() const
|
|
|
|
{
|
|
|
|
if ( d->tabs.count() == 0 )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return d->firstTab > 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KoTabBar::canScrollForward() const
|
|
|
|
{
|
|
|
|
if ( d->tabs.count() == 0 )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return d->lastTab < (int)d->tabs.count();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KoTabBar::scrollBack()
|
|
|
|
{
|
|
|
|
if ( !canScrollBack() )
|
|
|
|
return;
|
|
|
|
|
|
|
|
d->firstTab--;
|
|
|
|
if( d->firstTab < 1 ) d->firstTab = 1;
|
|
|
|
|
|
|
|
d->layoutTabs();
|
|
|
|
d->updateButtons();
|
|
|
|
update();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KoTabBar::scrollForward()
|
|
|
|
{
|
|
|
|
if ( !canScrollForward() )
|
|
|
|
return;
|
|
|
|
|
|
|
|
d->firstTab ++;
|
|
|
|
if( d->firstTab > (int)d->tabs.count() )
|
|
|
|
d->firstTab = d->tabs.count();
|
|
|
|
|
|
|
|
d->layoutTabs();
|
|
|
|
d->updateButtons();
|
|
|
|
update();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KoTabBar::scrollFirst()
|
|
|
|
{
|
|
|
|
if ( !canScrollBack() )
|
|
|
|
return;
|
|
|
|
|
|
|
|
d->firstTab = 1;
|
|
|
|
d->layoutTabs();
|
|
|
|
d->updateButtons();
|
|
|
|
update();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KoTabBar::scrollLast()
|
|
|
|
{
|
|
|
|
if ( !canScrollForward() )
|
|
|
|
return;
|
|
|
|
|
|
|
|
d->layoutTabs();
|
|
|
|
|
|
|
|
if( !d->reverseLayout )
|
|
|
|
{
|
|
|
|
int fullWidth = d->tabRects[ d->tabRects.count()-1 ].right();
|
|
|
|
int delta = fullWidth - width() + d->offset;
|
|
|
|
for( unsigned i = 0; i < d->tabRects.count(); i++ )
|
|
|
|
if( d->tabRects[i].x() > delta )
|
|
|
|
{
|
|
|
|
d->firstTab = i+1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// FIXME optimize this, perhaps without loop
|
|
|
|
for( ; d->firstTab <= (int)d->tabRects.count();)
|
|
|
|
{
|
|
|
|
int x = d->tabRects[ d->tabRects.count()-1 ].x();
|
|
|
|
if( x > 0 ) break;
|
|
|
|
d->firstTab++;
|
|
|
|
d->layoutTabs();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
d->layoutTabs();
|
|
|
|
d->updateButtons();
|
|
|
|
update();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KoTabBar::ensureVisible( const TQString& tab )
|
|
|
|
{
|
|
|
|
int i = d->tabs.findIndex( tab );
|
|
|
|
if ( i == -1 )
|
|
|
|
return;
|
|
|
|
i++;
|
|
|
|
|
|
|
|
// already visible, then do nothing
|
|
|
|
if( ( i >= d->firstTab ) && ( i <= d->lastTab ) )
|
|
|
|
return;
|
|
|
|
|
|
|
|
if( i < d->firstTab )
|
|
|
|
while( i < d->firstTab )
|
|
|
|
scrollBack();
|
|
|
|
|
|
|
|
if( i > d->lastTab )
|
|
|
|
while( i > d->lastTab )
|
|
|
|
scrollForward();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KoTabBar::moveTab( unsigned tab, unsigned target )
|
|
|
|
{
|
|
|
|
TQString tabName = d->tabs[ tab ];
|
|
|
|
TQStringList::Iterator it;
|
|
|
|
|
|
|
|
it = d->tabs.at( tab );
|
|
|
|
d->tabs.remove( it );
|
|
|
|
|
|
|
|
if( target > tab ) target--;
|
|
|
|
it = d->tabs.at( target );
|
|
|
|
if( target >= d->tabs.count() )
|
|
|
|
it = d->tabs.end();
|
|
|
|
d->tabs.insert( it, tabName );
|
|
|
|
|
|
|
|
if( d->activeTab == (int)tab+1 )
|
|
|
|
d->activeTab = target+1;
|
|
|
|
|
|
|
|
update();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KoTabBar::setActiveTab( const TQString& text )
|
|
|
|
{
|
|
|
|
int i = d->tabs.findIndex( text );
|
|
|
|
if ( i == -1 )
|
|
|
|
return;
|
|
|
|
|
|
|
|
if ( i + 1 == d->activeTab )
|
|
|
|
return;
|
|
|
|
|
|
|
|
d->activeTab = i + 1;
|
|
|
|
d->updateButtons();
|
|
|
|
update();
|
|
|
|
|
|
|
|
emit tabChanged( text );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KoTabBar::autoScrollBack()
|
|
|
|
{
|
|
|
|
if( !d->autoScroll ) return;
|
|
|
|
|
|
|
|
scrollBack();
|
|
|
|
|
|
|
|
if( !canScrollBack() )
|
|
|
|
d->autoScroll = false;
|
|
|
|
else
|
|
|
|
TQTimer::singleShot( 400, this, TQT_SLOT( autoScrollBack() ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KoTabBar::autoScrollForward()
|
|
|
|
{
|
|
|
|
if( !d->autoScroll ) return;
|
|
|
|
|
|
|
|
scrollForward();
|
|
|
|
|
|
|
|
if( !canScrollForward() )
|
|
|
|
d->autoScroll = false;
|
|
|
|
else
|
|
|
|
TQTimer::singleShot( 400, this, TQT_SLOT( autoScrollForward() ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KoTabBar::paintEvent( TQPaintEvent* )
|
|
|
|
{
|
|
|
|
if ( d->tabs.count() == 0 )
|
|
|
|
{
|
|
|
|
erase();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQPainter painter;
|
|
|
|
TQPixmap pm( size() );
|
|
|
|
pm.fill( colorGroup().background() );
|
|
|
|
painter.begin( TQT_TQPAINTDEVICE(&pm), this );
|
|
|
|
|
|
|
|
painter.setPen( colorGroup().dark() );
|
|
|
|
painter.drawLine( 0, 0, width(), 0 );
|
|
|
|
|
|
|
|
if( !d->reverseLayout )
|
|
|
|
painter.translate( 5, 0 );
|
|
|
|
|
|
|
|
d->layoutTabs();
|
|
|
|
d->updateButtons();
|
|
|
|
|
|
|
|
// draw first all non-active, visible tabs
|
|
|
|
for( int c = d->tabRects.count()-1; c>=0; c-- )
|
|
|
|
{
|
|
|
|
TQRect rect = d->tabRects[ c ];
|
|
|
|
if( rect.isNull() ) continue;
|
|
|
|
TQString text = d->tabs[ c ];
|
|
|
|
d->drawTab( painter, rect, text, false );
|
|
|
|
}
|
|
|
|
|
|
|
|
// draw the active tab
|
|
|
|
if( d->activeTab > 0 )
|
|
|
|
{
|
|
|
|
TQRect rect = d->tabRects[ d->activeTab-1 ];
|
|
|
|
if( !rect.isNull() )
|
|
|
|
{
|
|
|
|
TQString text = d->tabs[ d->activeTab-1 ];
|
|
|
|
d->drawTab( painter, rect, text, true );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// draw the move marker
|
|
|
|
if( d->targetTab > 0 )
|
|
|
|
{
|
|
|
|
int p = TQMIN( d->targetTab, (int)d->tabRects.count() );
|
|
|
|
TQRect rect = d->tabRects[ p-1 ];
|
|
|
|
if( !rect.isNull() )
|
|
|
|
{
|
|
|
|
int x = !d->reverseLayout ? rect.x() : rect.right()-7;
|
|
|
|
if( d->targetTab > (int)d->tabRects.count() )
|
|
|
|
x = !d->reverseLayout ? rect.right()-7 : rect.x()-3;
|
|
|
|
d->drawMoveMarker( painter, x, rect.y() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
painter.end();
|
|
|
|
|
|
|
|
if( !d->reverseLayout )
|
|
|
|
bitBlt( this, d->offset, 0, &pm );
|
|
|
|
else
|
|
|
|
bitBlt( this, 0, 0, &pm );
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void KoTabBar::resizeEvent( TQResizeEvent* )
|
|
|
|
{
|
|
|
|
d->layoutButtons();
|
|
|
|
d->updateButtons();
|
|
|
|
update();
|
|
|
|
}
|
|
|
|
|
|
|
|
TQSize KoTabBar::sizeHint() const
|
|
|
|
{
|
|
|
|
return TQSize( 40, style().pixelMetric( TQStyle::PM_ScrollBarExtent, this ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KoTabBar::renameTab( const TQString& old_name, const TQString& new_name )
|
|
|
|
{
|
|
|
|
TQStringList::Iterator it = d->tabs.find( old_name );
|
|
|
|
(*it) = new_name;
|
|
|
|
|
|
|
|
update();
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString KoTabBar::activeTab() const
|
|
|
|
{
|
|
|
|
if( d->activeTab == 0 )
|
|
|
|
return TQString();
|
|
|
|
else
|
|
|
|
return d->tabs[ d->activeTab ];
|
|
|
|
}
|
|
|
|
|
|
|
|
void KoTabBar::mousePressEvent( TQMouseEvent* ev )
|
|
|
|
{
|
|
|
|
if ( d->tabs.count() == 0 )
|
|
|
|
{
|
|
|
|
erase();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
d->layoutTabs();
|
|
|
|
|
|
|
|
TQPoint pos = ev->pos();
|
|
|
|
if( !d->reverseLayout ) pos = pos - TQPoint( d->offset,0 );
|
|
|
|
|
|
|
|
int tab = d->tabAt( pos ) + 1;
|
|
|
|
if( ( tab > 0 ) && ( tab != d->activeTab ) )
|
|
|
|
{
|
|
|
|
d->activeTab = tab;
|
|
|
|
update();
|
|
|
|
|
|
|
|
emit tabChanged( d->tabs[ d->activeTab-1] );
|
|
|
|
|
|
|
|
// scroll if partially visible
|
|
|
|
if( d->tabRects[ tab-1 ].right() > width() - d->offset )
|
|
|
|
scrollForward();
|
|
|
|
}
|
|
|
|
|
|
|
|
if( ev->button() == Qt::RightButton )
|
|
|
|
if( !d->readOnly )
|
|
|
|
emit contextMenu( ev->globalPos() );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KoTabBar::mouseReleaseEvent( TQMouseEvent* ev )
|
|
|
|
{
|
|
|
|
if ( d->readOnly ) return;
|
|
|
|
|
|
|
|
d->autoScroll = false;
|
|
|
|
|
|
|
|
if ( ev->button() == Qt::LeftButton && d->targetTab != 0 )
|
|
|
|
{
|
|
|
|
emit tabMoved( d->activeTab-1, d->targetTab-1 );
|
|
|
|
d->targetTab = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KoTabBar::mouseMoveEvent( TQMouseEvent* ev )
|
|
|
|
{
|
|
|
|
if ( d->readOnly ) return;
|
|
|
|
|
|
|
|
TQPoint pos = ev->pos();
|
|
|
|
if( !d->reverseLayout) pos = pos - TQPoint( d->offset,0 );
|
|
|
|
|
|
|
|
// check if user drags a tab to move it
|
|
|
|
int i = d->tabAt( pos ) + 1;
|
|
|
|
if( ( i > 0 ) && ( i != d->targetTab ) )
|
|
|
|
{
|
|
|
|
if( i == d->activeTab ) i = 0;
|
|
|
|
if( i == d->activeTab+1 ) i = 0;
|
|
|
|
|
|
|
|
if( i != d->targetTab )
|
|
|
|
{
|
|
|
|
d->targetTab = i;
|
|
|
|
d->autoScroll = false;
|
|
|
|
update();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// drag past the very latest visible tab
|
|
|
|
// e.g move a tab to the last ordering position
|
|
|
|
TQRect r = d->tabRects[ d->tabRects.count()-1 ];
|
|
|
|
bool moveToLast = false;
|
|
|
|
if( r.isValid() )
|
|
|
|
{
|
|
|
|
if( !d->reverseLayout )
|
|
|
|
if( pos.x() > r.right() )
|
|
|
|
if( pos.x() < width() )
|
|
|
|
moveToLast = true;
|
|
|
|
if( d->reverseLayout )
|
|
|
|
if( pos.x() < r.x() )
|
|
|
|
if( pos.x() > 0 )
|
|
|
|
moveToLast = true;
|
|
|
|
}
|
|
|
|
if( moveToLast )
|
|
|
|
if( d->targetTab != (int)d->tabRects.count()+1 )
|
|
|
|
{
|
|
|
|
d->targetTab = d->tabRects.count()+1;
|
|
|
|
d->autoScroll = false;
|
|
|
|
update();
|
|
|
|
}
|
|
|
|
|
|
|
|
// outside far too left ? activate autoscroll...
|
|
|
|
if ( pos.x() < 0 && !d->autoScroll )
|
|
|
|
{
|
|
|
|
d->autoScroll = true;
|
|
|
|
autoScrollBack();
|
|
|
|
}
|
|
|
|
|
|
|
|
// outside far too right ? activate autoscroll...
|
|
|
|
int w = width() - d->offset;
|
|
|
|
if ( pos.x() > w && !d->autoScroll )
|
|
|
|
{
|
|
|
|
d->autoScroll = true;
|
|
|
|
autoScrollForward();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KoTabBar::mouseDoubleClickEvent( TQMouseEvent* ev )
|
|
|
|
{
|
|
|
|
int offset = d->reverseLayout ? 0 : d->offset;
|
|
|
|
if( ev->pos().x() > offset )
|
|
|
|
if( !d->readOnly )
|
|
|
|
emit doubleClicked();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KoTabBar::wheelEvent( TQWheelEvent * e )
|
|
|
|
{
|
|
|
|
if ( d->tabs.count() == 0 )
|
|
|
|
{
|
|
|
|
erase();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Currently one wheel movement is a delta of 120.
|
|
|
|
// The 'unused' delta is stored for devices that allow
|
|
|
|
// a higher scrolling resolution.
|
|
|
|
// The delta required to move one tab is one wheel movement:
|
|
|
|
const int deltaRequired = 120;
|
|
|
|
|
|
|
|
d->wheelDelta += e->delta();
|
|
|
|
int tabDelta = - (d->wheelDelta / deltaRequired);
|
|
|
|
d->wheelDelta = d->wheelDelta % deltaRequired;
|
|
|
|
int numTabs = d->tabs.size();
|
|
|
|
|
|
|
|
if(d->activeTab + tabDelta > numTabs)
|
|
|
|
{
|
|
|
|
// Would take us past the last tab
|
|
|
|
d->activeTab = numTabs;
|
|
|
|
}
|
|
|
|
else if (d->activeTab + tabDelta < 1)
|
|
|
|
{
|
|
|
|
// Would take us before the first tab
|
|
|
|
d->activeTab = 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
d->activeTab = d->activeTab + tabDelta;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Find the left and right edge of the new tab. If we're
|
|
|
|
// going forward, and the right of the new tab isn't visible
|
|
|
|
// then scroll forward. Likewise, if going back, and the
|
|
|
|
// left of the new tab isn't visible, then scroll back.
|
|
|
|
int activeTabRight = d->tabRects[ d->activeTab-1 ].right();
|
|
|
|
int activeTabLeft = d->tabRects[ d->activeTab-1 ].left();
|
|
|
|
if(tabDelta > 0 && activeTabRight > width() - d->offset )
|
|
|
|
{
|
|
|
|
scrollForward();
|
|
|
|
}
|
|
|
|
else if(tabDelta < 0 && activeTabLeft < width() - d->offset )
|
|
|
|
{
|
|
|
|
scrollBack();
|
|
|
|
}
|
|
|
|
|
|
|
|
update();
|
|
|
|
emit tabChanged( d->tabs[ d->activeTab-1] );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#include "KoTabBar.moc"
|