Merged latest fixes and improvements from 1.2 branch.
[kdbg.git] / STabCtl / stabbar.cpp
blobebbc2bb74f20971dcde2e2a3d2aa4686c394c51c
1 /***************************************************************************
2 STabCtl part of KDEStudio
3 -------------------
4 copyright : (C) 1999 by Judin Maximus
5 email : novaprint@mtu-net.ru
6 ***************************************************************************/
8 #include "stabbar.h"
10 #include <qapp.h>
11 #include <qwmatrix.h>
12 #include <qpushbutton.h>
13 #include <qpainter.h>
16 BarPainter::BarPainter( STabBar* parent )
17 :QWidget( parent )
19 delta = 0;
20 buffer = new QPixmap(0,0);
23 BarPainter::~BarPainter()
25 delete buffer;
28 void BarPainter::paintEvent( QPaintEvent* )
30 if ( buffer->isNull() ) return;
31 drawBuffer();
33 switch ( ((STabBar*)parent())->tabPos )
34 case STabBar::TAB_TOP:{
35 bitBlt( this, 0, 0, buffer, 0, 0, width(), height() );
36 break;
37 case STabBar::TAB_RIGHT:{
38 QWMatrix m;
39 m.rotate( -90 );
40 QPixmap xbuffer = buffer->xForm(m);
41 bitBlt( this, 0, 0, &xbuffer, 0, 0, width(), height() );
42 break;
47 void BarPainter::resizeEvent( QResizeEvent *e )
49 delete buffer;
50 switch ( ((STabBar*)parent())->tabPos )
51 case STabBar::TAB_TOP:{
52 buffer = new QPixmap( width(), height() );
53 break;
54 case STabBar::TAB_RIGHT:{
55 buffer = new QPixmap( height(), width() );
56 break;
61 void BarPainter::drawBuffer()
63 QColor c1 = white;
64 QColor c2 = colorGroup().dark();
65 QColor c4 = white; // for paint top line;
67 int W = 0;
68 int H = 0;
69 int shadowX = 1;
70 int shadowY = 1;
71 switch ( ((STabBar*)parent())->tabPos )
72 case STabBar::TAB_TOP:{
73 W = width();
74 H = height();
75 break;
76 case STabBar::TAB_RIGHT:{
77 shadowX = -1;
78 c1 = colorGroup().dark();
79 c2 = white;
80 H = width();
81 W = height();
82 break;
86 QPainter paint;
87 paint.begin(buffer);
88 paint.setBrushOrigin(0,0);
89 #if QT_VERSION >= 200
90 QBrush bgBrush = colorGroup().brush(QColorGroup::Background);
91 #else
92 QBrush bgBrush(colorGroup().background());
93 #endif
94 paint.fillRect( 0, 0, W, H, bgBrush);
96 int x = 2;
97 int curTab = ((STabBar*)parent())->_currentTab;
98 int curTabNum = -1;
99 int leftTab = ((STabBar*)parent())->leftTab;
100 int curx = -1; // start current tab ( selected )
101 int curWidth = -1;
102 int broken = -1;
103 bool iconShow = ((STabBar*)parent())->iconShow;
105 QList<TabBarData> *mainData = ((STabBar*)parent())->mainData;
106 for ( uint k = 0; k < mainData->count(); k++ ){
107 int x1 = x;
108 int y1 = 2;
109 int width = mainData->at(k)->width;
111 if ( mainData->at(k)->id == curTab ){ // store current tab start x
112 curTabNum = k;
113 curx = x;
114 curWidth = width;
115 x1 -= 1;
116 y1 -= 1;
119 if ( mainData->at(k)->pix != 0L && iconShow ){
120 QWMatrix m;
121 switch ( ((STabBar*)parent())->tabPos )
122 case STabBar::TAB_TOP:{
123 break;
124 case STabBar::TAB_RIGHT:{
125 m.rotate( 90 );
126 break;
129 paint.drawPixmap( x1+ 11, y1 + 2 , mainData->at(k)->pix->xForm(m) );
132 int ty = ( H + fontMetrics().height() ) / 2 - 2;
133 int tx = ( mainData->at(k)->pix != 0L && iconShow ) ? 32:12;
135 paint.setFont( parentWidget()->font() );
137 if ( mainData->at(k)->enabled ){
138 paint.setPen( mainData->at(k)->textColor );
139 paint.drawText( x1 + tx , ty + y1 , mainData->at(k)->label );
140 } else {
141 paint.setPen( colorGroup().light() );
142 paint.drawText( x1 + tx + shadowX, ty + y1 + shadowY, mainData->at(k)->label );
143 paint.setPen( colorGroup().mid() );
144 paint.drawText( x1 + tx , ty + y1 , mainData->at(k)->label );
147 paint.setPen( c1 );
148 paint.moveTo( x1, H + 1 -y1 );
149 paint.lineTo( x1, y1 );
151 paint.setPen( c4 );
152 paint.lineTo( x1 + width - 1, y1 );
154 paint.setPen( c2 );
155 paint.lineTo( x1 + width - 1, H+1-y1 );
157 /***************************************************************/
158 paint.setPen( c1 );
159 paint.moveTo( x1 + 4, y1 + H - 5 );
160 paint.lineTo( x1 + 4, 3+y1 );
162 paint.moveTo( x1 + 7, y1 + H - 5 );
163 paint.lineTo( x1 + 7, 3+y1 );
165 paint.setPen( c2 );
166 paint.moveTo( x1 + 5, y1 + H - 5 );
167 paint.lineTo( x1 + 5, 3+y1 );
169 paint.moveTo( x1 + 8, y1 + H - 5 );
170 paint.lineTo( x1 + 8, 3+y1 );
171 /***************************************************************/
173 // fixed picture for leftTab
174 if ( leftTab == (int)k + 1 ){
175 paint.fillRect( x1 + width - 2, 0, 2, H - 1, bgBrush);
178 // paint broken left
179 if ( (int)k == leftTab && k != 0 )
181 int yy = y1;
182 int xx = x1 - 2;
183 paint.fillRect( x1, 0, 1, H - 1, bgBrush);
184 paint.setPen( c1 );
185 do {
186 paint.drawPoint( xx + 2, yy );
187 paint.drawPoint( xx + 1, yy + 1 );
188 paint.moveTo( xx + 1, yy + 1 );
189 paint.lineTo( xx + 1, yy + 3 );
190 paint.drawPoint( xx + 2, yy + 4 );
191 paint.lineTo( xx + 2, yy + 6 );
192 paint.drawPoint( xx + 3, yy + 7 );
193 paint.lineTo( xx + 3, yy + 9 );
194 paint.drawPoint( xx + 2, yy + 10 );
195 paint.drawPoint( xx + 2, yy + 11 );
196 yy+= 12;
197 } while ( yy < H );
200 x += width;
201 if ( x >= W && broken == -1 ) broken = k; // store right broken tab
204 // modify ( paint ) selected tab
205 if ( curx != -1 && curTabNum >= leftTab ){
206 curx -= 2;
207 curWidth += 4;
208 paint.setPen( c1 );
209 paint.moveTo( curx, H-1 );
210 paint.lineTo( curx, 0 );
211 paint.setPen( c4 );
212 paint.lineTo( curx + curWidth - 2, 0 );
214 paint.setPen( c2 );
215 paint.moveTo( curx + curWidth - 1, 0 );
216 paint.lineTo( curx + curWidth - 1, H-1 );
218 paint.fillRect( curx + 1, 1, 2, H - 1, bgBrush);
219 paint.fillRect( curx + curWidth - 4, 1, 3, H - 1, bgBrush);
220 paint.fillRect( curx + 1, 1, curWidth - 3, 2, bgBrush);
223 if ( curTabNum == leftTab && curTabNum != 0 )
225 int yy = 0;
226 int xx = curx;
227 paint.fillRect( curx, 0, 1, H - 1, bgBrush);
228 paint.setPen( c1 );
229 do {
230 paint.drawPoint( xx + 2, yy );
231 paint.drawPoint( xx + 1, yy + 1 );
232 paint.moveTo( xx + 1, yy + 1 );
233 paint.lineTo( xx + 1, yy + 3 );
234 paint.drawPoint( xx + 2, yy + 4 );
235 paint.lineTo( xx + 2, yy + 6 );
236 paint.drawPoint( xx + 3, yy + 7 );
237 paint.lineTo( xx + 3, yy + 9 );
238 paint.drawPoint( xx + 2, yy + 10 );
239 paint.drawPoint( xx + 2, yy + 11 );
240 yy+= 12;
241 } while ( yy < H );
244 // paint broken right
245 if ( broken != -1 )
247 int yy = broken == curTabNum ? 0:2;
248 int xx = W;
249 paint.fillRect( xx - 2, 0, 2, H - 1, bgBrush );
250 paint.fillRect( xx - 5, yy + 1, 5, H - 2 - yy, bgBrush );
251 paint.setPen( c2 );
252 do {
253 paint.drawPoint( xx - 2, yy );
254 paint.drawPoint( xx - 1, yy + 1 );
255 paint.moveTo( xx - 1, yy + 1 );
256 paint.lineTo( xx - 1, yy + 3 );
257 paint.drawPoint( xx - 2, yy + 4 );
258 paint.lineTo( xx - 2, yy + 6 );
259 paint.drawPoint( xx - 3, yy + 7 );
260 paint.lineTo( xx - 3, yy + 9 );
261 paint.drawPoint( xx - 2, yy + 10 );
262 paint.drawPoint( xx - 2, yy + 11 );
263 yy+= 12;
264 } while ( yy < H );
266 paint.end();
269 int BarPainter::findBarByPos( int x, int y )
271 int dx = 5; // overlaped
273 switch ( ((STabBar*)parent())->tabPos ){
274 case STabBar::TAB_TOP:
275 break;
276 case STabBar::TAB_RIGHT:
277 x = height() - y;
278 break;
281 STabBar* bar = (STabBar*)parent();
283 QList<TabBarData> *mainData = bar->mainData;
284 if ( mainData->isEmpty() ) return -1;
286 int end = 0;
287 int find = -1;
288 int findWidth = -1;
289 for ( uint k = 0; k < mainData->count(); k++ ){
290 end += mainData->at(k)->width;
291 if ( x < end ){
292 find = k;
293 findWidth = mainData->at(k)->width;
294 break;
298 int idCurTab = bar->_currentTab;
299 int curTab = -1;
300 for ( uint k = 0; k < mainData->count(); k++ )
301 if ( mainData->at(k)->id == idCurTab ){
302 curTab = k;
303 break;
306 // process first Tab manualy
307 if ( x < dx && curTab != mainData->at(0)->id ) return -1;
309 // process last Tab manyaly
310 if ( find == -1 )
311 if ( x < (end + dx) && curTab == (int)mainData->count() - 1 )
312 find = mainData->count() - 1;
314 if ( find == -1 ) return -1;
316 // process overlaped
317 if ( find > 0 )
318 if ( curTab == (find - 1) && x < (end - findWidth + dx ) ) find -= 1;
320 if ( find < (int)mainData->count() - 1 )
321 if ( curTab == (find + 1) && x > (end - dx ) ) find += 1;
323 return mainData->at(find)->id;
326 void BarPainter::mousePressEvent( QMouseEvent* e )
328 int cur = findBarByPos( e->x(), e->y() );
329 if ( e->button() == RightButton )
330 emit ((STabBar*)parent())->rightButtonPress( cur, e->globalPos() );
331 else
332 mousePressTab = cur;
335 void BarPainter::mouseReleaseEvent( QMouseEvent* e )
337 int cur = findBarByPos( e->x(), e->y() );
338 if ( cur != -1 && cur == mousePressTab ){
339 ((STabBar*)parent())->setCurrentTab( cur );
343 /***************************************************************************/
345 STabBar::STabBar( QWidget * parent, const char * name )
346 :QWidget( parent, name )
348 /* Set up bitmaps */
349 #include "b_left.xpm"
350 left_xpm = new QPixmap( b_left_xpm );
352 QWMatrix m;
353 m.scale( -1, 1 );
354 right_xpm = new QPixmap( left_xpm->xForm(m) );
356 m.reset();
357 m.rotate( 90 );
358 down_xpm = new QPixmap( left_xpm->xForm(m) );
360 m.reset();
361 m.scale( 1, -1 );
362 up_xpm = new QPixmap( down_xpm->xForm(m) );
363 /****************************************************************/
365 tabPos = TAB_TOP;
366 iconShow = true;
368 barPainter = new BarPainter( this );
369 move( 0, 0 );
371 mainData = new QList<TabBarData>;
372 mainData->setAutoDelete( true );
373 _currentTab = -1;
374 leftTab = 0;
376 left = new QPushButton(this); left->hide();
377 left->setAutoRepeat( true );
378 connect( left, SIGNAL(clicked()), SLOT( leftClicked()) );
379 right = new QPushButton(this); right->hide();
380 right->setAutoRepeat( true );
381 connect( right, SIGNAL(clicked()), SLOT( rightClicked()) );
383 setFixedHeight( fontMetrics().height() + 10 );
385 setButtonPixmap();
388 STabBar::~STabBar()
390 delete barPainter;
391 delete left;
392 delete right;
393 delete mainData;
396 void STabBar::paintEvent(QPaintEvent *)
398 QPainter paint;
399 paint.begin( this );
401 // find current ( selected ) tab data
402 TabBarData* data = 0L;
403 int curx = 2 - barPainter->delta;
404 int curWidth = 0;
405 for ( uint k = 0; k < mainData->count(); k++ ){
406 data = mainData->at(k);
407 if ( data->id == _currentTab ){
408 curWidth = data->width + 4 ;
409 curx -= 2;
410 break;
412 curx += data->width;
415 if ( curWidth == 0 ) curx = 0; // no tab selected
417 #if QT_VERSION >= 200
418 QBrush bgBrush = colorGroup().brush(QColorGroup::Background);
419 #else
420 QBrush bgBrush(colorGroup().background());
421 #endif
423 // paint button line
424 switch ( tabPos ){
425 case TAB_TOP:
426 paint.fillRect( 0, height()-1, width(), 1, bgBrush);
427 paint.setPen( white );
428 paint.moveTo( 0, height()-1 );
429 paint.lineTo( curx, height()-1 );
430 paint.moveTo( QMIN( curx + curWidth, width() - 50 ), height()-1 );
431 paint.lineTo( width() - 1, height()-1 );
432 break;
433 case TAB_RIGHT:
434 paint.fillRect( width() - 1, 0, 1, height(), bgBrush);
435 curx = height() - curx;
436 paint.setPen( colorGroup().dark() );
437 paint.drawPoint( width() - 1, height()-1 );
439 paint.moveTo( width() - 1, height()-2 );
440 paint.setPen( white );
441 if ( curx != height() ) paint.lineTo( width() - 1, curx );
442 paint.moveTo( width() - 1, QMAX( curx - curWidth, 50 ) );
443 paint.lineTo( width() - 1, 0 );
444 break;
446 paint.end();
447 barPainter->repaint( false );
450 int STabBar::insertTab( const QString &label, int id )
452 if ( id == -1 ){
453 id = 0;
454 for ( uint k = 0; k < mainData->count(); k++ )
455 if ( mainData->at(k)->id > id ) id = mainData->at(k)->id;
457 TabBarData* data = new TabBarData( id, label );
459 data->width = 4 + fontMetrics().width( label ) + 14;
460 mainData->append( data );
462 resizeEvent(0);
463 repaint( false );
464 return id;
467 void STabBar::showTabIcon( bool show )
469 if ( iconShow == show ) return;
470 iconShow = show;
471 updateHeight();
472 tabsRecreate();
475 TabBarData* STabBar::findData( int id )
477 TabBarData* data = 0L;
478 for ( uint k = 0; k < mainData->count(); k++ )
479 if ( mainData->at(k)->id == id ){
480 data = mainData->at(k);
481 break;
483 return data;
486 void STabBar::setPixmap( int id, const QPixmap &pix )
488 TabBarData* data = findData( id );
489 if ( data != 0L ){
490 if ( data->pix != 0L ) delete data->pix;
491 data->pix = new QPixmap( pix );
492 if ( iconShow ) data->width += 16 + 4;
493 tabsRecreate();
497 void STabBar::setTextColor( int id, const QColor &color )
499 TabBarData* data = findData( id );
500 if ( data != 0L ){
501 data->textColor = color;
502 repaint( false );
506 void STabBar::removeTab( int id )
508 TabBarData* data = findData( id );
509 if ( data != 0L ){
510 if ( _currentTab == data->id )
512 for ( uint k = 0; k < mainData->count(); k++ )
514 if ( mainData->at(k)->id == data->id ){
515 if ( mainData->count() == 1 ){
516 setCurrentTab( -1 );
517 } else {
518 setCurrentTab( mainData->at(k+1)->id );
520 break;
523 if ( mainData->at(k+1)->id == data->id ){
524 setCurrentTab( mainData->at(k)->id );
525 break;
529 mainData->remove( data );
530 resizeEvent(0);
531 repaint( false );
535 void STabBar::setCurrentTab( int id, bool allowDisable )
537 TabBarData* data = findData( id );
538 if ( data != 0L )
539 if ( (data->enabled || allowDisable ) && _currentTab != data->id )
541 _currentTab = data->id;
542 repaint( false );
544 int curx = 2;
545 for ( uint k = 0; k < mainData->count(); k++ ){
546 data = mainData->at(k);
547 if ( data->id == id ){
548 curx += 30;
549 break;
551 curx += data->width;
554 switch ( tabPos ){
555 case TAB_TOP:
556 while ( width() - 50 > 30 && ((-barPainter->delta + curx < 0) || (-barPainter->delta + curx > width() - 50)) ){
557 if ( -barPainter->delta + curx < 0 )
558 leftClicked();
559 else
560 rightClicked();
562 break;
563 case TAB_RIGHT:
564 while ( height() - 50 > 30 && ((-barPainter->delta + curx < 0) || (-barPainter->delta + curx > height() - 50)) ){
565 if ( -barPainter->delta + curx < 0 )
566 leftClicked();
567 else
568 rightClicked();
570 break;
572 emit tabSelected( id );
576 void STabBar::setTabEnabled( int id , bool enabled )
578 TabBarData* data = findData( id );
579 if ( data == 0L ) return;
581 if ( data->enabled != enabled )
583 data->enabled = enabled;
584 if ( _currentTab == data->id ){
585 for ( uint k = 0; k < mainData->count(); k++ ){
586 if ( mainData->at(k)->enabled ){
587 setCurrentTab( mainData->at(k)->id );
588 break;
592 if ( enabled ){
593 data = findData( _currentTab );
594 if ( !data->enabled ) setCurrentTab( id );
596 repaint( false );
600 bool STabBar::isTabEnabled( int id )
602 TabBarData* data = findData( id );
603 return data == 0L ? false:data->enabled;
606 void STabBar::show()
608 if ( _currentTab == 0 )
609 if ( !mainData->isEmpty() )
610 _currentTab = mainData->at(0)->id;
612 if ( _currentTab != 0 ){
613 setCurrentTab( _currentTab );
615 QWidget::show();
618 int STabBar::tabsWidth()
620 int width = 0;
621 for ( uint k = 0; k < mainData->count(); k++ ){
622 width += mainData->at(k)->width;
624 return width == 0 ? 0:width + 4;
627 void STabBar::resizeEvent(QResizeEvent *)
629 int maxAllowWidth = 0;
630 int maxAllowHeight = 0;
631 switch ( tabPos ){
632 case TAB_TOP:
633 if ( width() - 50 > tabsWidth() ){
634 barPainter->delta = 0;
635 leftTab = 0;
637 maxAllowWidth = width() - 50 + barPainter->delta;
638 barPainter->move( -barPainter->delta, 0 );
639 barPainter->resize( QMIN(tabsWidth(),maxAllowWidth), height() - 1 );
640 break;
641 case TAB_RIGHT:
642 if ( height() - 50 > tabsWidth() ){
643 barPainter->delta = 0;
644 leftTab = 0;
646 maxAllowHeight = height() - 50 + barPainter->delta;
647 barPainter->resize( width() - 1, QMIN(tabsWidth(),maxAllowHeight) );
648 barPainter->move( 0, height() - barPainter->height() + barPainter->delta );
649 break;
652 if ( tabPos == TAB_TOP ){
653 left->setGeometry( width()-2*18-2, height()-20, 18, 18 );
654 right->setGeometry( width()-18, height()-20, 18, 18 );
656 if ( barPainter->delta > 0 || tabsWidth() > maxAllowWidth ){
657 left->show();
658 right->show();
659 } else {
660 left->hide();
661 right->hide();
665 if ( tabPos == TAB_RIGHT ){
666 left->setGeometry( width()-20, 18+2, 18, 18 );
667 right->setGeometry( width()-20, 0, 18, 18 );
669 if ( barPainter->delta > 0 || tabsWidth() > maxAllowHeight ){
670 left->show();
671 right->show();
672 } else {
673 left->hide();
674 right->hide();
679 void STabBar::leftClicked()
681 if ( leftTab > 0 ){
682 leftTab--;
683 int dx = mainData->at( leftTab )->width;
684 barPainter->delta -= dx;
685 barPainter->move( barPainter->x() + dx, barPainter->y() );
686 resizeEvent(0);
687 repaint( false );
691 void STabBar::rightClicked()
693 if ( leftTab != (int)mainData->count() - 1 ){
694 int dx = mainData->at( leftTab )->width;
695 barPainter->delta += dx;
696 leftTab++;
697 barPainter->move( barPainter->x() - dx, barPainter->y() );
698 resizeEvent(0);
699 repaint( false );
703 void STabBar::setTabPos( TabPos pos )
705 tabPos = pos;
706 updateHeight();
707 setButtonPixmap();
708 tabsRecreate();
711 void STabBar::updateHeight()
713 switch ( tabPos ){
714 case TAB_TOP:
715 setMaximumWidth(32767);
716 if ( iconShow )
717 setFixedHeight( fontMetrics().height() + 10 );
718 else
719 setFixedHeight( fontMetrics().height() + 4 );
720 break;
721 case TAB_RIGHT:
722 setMaximumHeight(32767);
723 if ( iconShow )
724 setFixedWidth( fontMetrics().height() + 10 );
725 else
726 setFixedWidth( fontMetrics().height() + 4 );
727 break;
731 void STabBar::setButtonPixmap()
733 switch ( tabPos ){
734 case TAB_TOP:
735 left->setPixmap( *left_xpm );
736 right->setPixmap( *right_xpm );
737 break;
738 case TAB_RIGHT:
739 left->setPixmap( *up_xpm );
740 right->setPixmap( *down_xpm );
741 break;
745 void STabBar::setFont( const QFont &f )
747 QWidget::setFont( f );
748 tabsRecreate();
751 void STabBar::setTabCaption( int id, const QString &caption )
753 TabBarData* data = findData( id );
754 if ( data != 0L ){
755 data->label = caption;
756 tabsRecreate();
760 QString STabBar::tabCaption( int id )
762 TabBarData* data = findData( id );
763 return data == 0L ? QString(""):data->label;
766 void STabBar::tabsRecreate()
768 for ( uint k = 0; k < mainData->count(); k++ ){
769 TabBarData* data = mainData->at(k);
770 data->width = 4 + fontMetrics().width( data->label ) + 14;
771 if ( iconShow && data->pix != 0L ) data->width += 16 + 4;
773 resizeEvent(0);
774 repaint( false );
777 const QColor& STabBar::textColor( int id )
779 TabBarData* data = findData( id );
780 if ( data != 0L ){
781 return data->textColor;
783 return black;