Salome HOME
no message
[modules/gui.git] / src / Qtx / QtxColorScale.cxx
1 // File:      QtxColorScale.cxx
2 // Author:    Sergey TELKOV
3
4 #include "QtxColorScale.h"
5
6 #include <qmap.h>
7 #include <qimage.h>
8 #include <qregexp.h>
9 #include <qpixmap.h>
10 #include <qbitmap.h>
11 #include <qpainter.h>
12 #include <qmainwindow.h>
13 #include <qstringlist.h>
14 #include <qstylesheet.h>
15 #include <qsimplerichtext.h>
16
17 #include <math.h>
18
19 /*********************************************************************
20 **  Class:  QtxColorScale
21 **  Descr:  Color Scale widget.
22 **  Level:  Public
23 *********************************************************************/
24
25 QtxColorScale::QtxColorScale( QWidget* parent, const char* name, WFlags f )
26 : QFrame( parent, name, f | WResizeNoErase | WRepaintNoErase ),
27 myDock( 0 ),
28 myMin( 0.0 ),
29 myMax( 1.0 ),
30 myTitle( "" ),
31 myInterval( 10 ),
32 myStyleSheet( 0 ),
33 myFormat( "%.4g" ),
34 myColorMode( Auto ),
35 myLabelMode( Auto ),
36 myLabelPos( Right ),
37 myTitlePos( Center ),
38 myDumpMode( NoDump ),
39 myFlags( AtBorder | WrapTitle )
40 {
41         setCaption( tr ( "Color scale" ) );
42 }
43
44 QtxColorScale::QtxColorScale( const int num, QWidget* parent, const char* name, WFlags f )
45 : QFrame( parent, name, f | WResizeNoErase | WRepaintNoErase ),
46 myDock( 0 ),
47 myMin( 0.0 ),
48 myMax( 1.0 ),
49 myTitle( "" ),
50 myInterval( num ),
51 myStyleSheet( 0 ),
52 myFormat( "%.4g" ),
53 myColorMode( Auto ),
54 myLabelMode( Auto ),
55 myLabelPos( Right ),
56 myTitlePos( Center ),
57 myDumpMode( NoDump ),
58 myFlags( AtBorder | WrapTitle )
59 {
60         setCaption( tr ( "Color scale" ) );
61 }
62
63 #if QT_VER == 3
64
65 QtxColorScale::QtxColorScale( Dock* dock, const char* name, WFlags f )
66 : QFrame( dock, name, f | WResizeNoErase | WRepaintNoErase ),
67 myMin( 0.0 ),
68 myMax( 1.0 ),
69 myTitle( "" ),
70 myDock( dock ),
71 myInterval( 10 ),
72 myStyleSheet( 0 ),
73 myFormat( "%.4g" ),
74 myColorMode( Auto ),
75 myLabelMode( Auto ),
76 myLabelPos( Right ),
77 myTitlePos( Center ),
78 myDumpMode( NoDump ),
79 myFlags( AtBorder | WrapTitle )
80 {
81         setCaption( tr ( "Color scale" ) );
82 }
83
84 #endif
85
86 QtxColorScale::~QtxColorScale()
87 {
88 }
89
90 //================================================================
91 // Function : minimum
92 // Purpose  : Returns minimal limit of scale.
93 //================================================================
94
95 double QtxColorScale::minimum() const
96 {
97         return myMin;
98 }
99
100 //================================================================
101 // Function : maximum
102 // Purpose  : Returns maximal limit of scale.
103 //================================================================
104
105 double QtxColorScale::maximum() const
106 {
107         return myMax;
108 }
109
110 //================================================================
111 // Function : range
112 // Purpose  : Returns range (minimal and maximal limits) of scale.
113 //================================================================
114
115 void QtxColorScale::range( double& min, double& max ) const
116 {
117         min = myMin;
118         max = myMax;
119 }
120
121 //================================================================
122 // Function : title
123 // Purpose  : Returns the current title string.
124 //================================================================
125
126 QString QtxColorScale::title() const
127 {
128         return myTitle;
129 }
130
131 //================================================================
132 // Function : format
133 // Purpose  : Returns the current format of number presentation in
134 //            labels for Auto label mode (sprintf specification).
135 //================================================================
136
137 QString QtxColorScale::format() const
138 {
139         return myFormat;
140 }
141
142 //================================================================
143 // Function : dumpMode
144 // Purpose  : Returns dump mode.
145 //================================================================
146
147 int QtxColorScale::dumpMode() const
148 {
149         return myDumpMode;
150 }
151
152 //================================================================
153 // Function : labelMode
154 // Purpose  : Returns label mode.
155 //================================================================
156
157 int QtxColorScale::labelMode() const
158 {
159         return myLabelMode;
160 }
161
162 //================================================================
163 // Function : colorMode
164 // Purpose  : Returns color mode.
165 //================================================================
166
167 int QtxColorScale::colorMode() const
168 {
169         return myColorMode;
170 }
171
172 //================================================================
173 // Function : intervalsNumber
174 // Purpose  : Returns intervals number of color scale.
175 //================================================================
176
177 int QtxColorScale::intervalsNumber() const
178 {
179         return myInterval;
180 }
181
182 //================================================================
183 // Function : label
184 // Purpose  : Returns the user label of specified interval.
185 //================================================================
186
187 QString QtxColorScale::label( const int idx ) const
188 {
189         QString res;
190         if ( idx >= 0 && idx < (int)myLabels.count() )
191                 res = *myLabels.at( idx );
192         return res;
193 }
194
195 //================================================================
196 // Function : color
197 // Purpose  : Returns the user color of specified interval.
198 //================================================================
199
200 QColor QtxColorScale::color( const int idx ) const
201 {
202         QColor res;
203         if ( idx >= 0 && idx < (int)myColors.count() )
204                 res = *myColors.at( idx );
205         return res;
206 }
207
208 //================================================================
209 // Function : labels
210 // Purpose  : Returns the user labels.
211 //================================================================
212
213 void QtxColorScale::labels( QStringList& list ) const
214 {
215         list = myLabels;
216 }
217
218 //================================================================
219 // Function : colors
220 // Purpose  : Returns the user color.
221 //================================================================
222
223 void QtxColorScale::colors( QValueList<QColor>& list ) const
224 {
225         list = myColors;
226 }
227
228 //================================================================
229 // Function : labelPosition
230 // Purpose  : Returns the label position.
231 //================================================================
232
233 int QtxColorScale::labelPosition() const
234 {
235         return myLabelPos;
236 }
237
238 //================================================================
239 // Function : titlePosition
240 // Purpose  : Returns the title position.
241 //================================================================
242
243 int QtxColorScale::titlePosition() const
244 {
245         return myTitlePos;
246 }
247
248 //================================================================
249 // Function : setMinimum
250 // Purpose  : Sets the minimum limit.
251 //================================================================
252
253 void QtxColorScale::setMinimum( const double val )
254 {
255         setRange( val, maximum() );
256 }
257
258 //================================================================
259 // Function : setMaximum
260 // Purpose  : Sets the maximum limit.
261 //================================================================
262
263 void QtxColorScale::setMaximum( const double val )
264 {
265         setRange( minimum(), val );
266 }
267
268 //================================================================
269 // Function : setRange
270 // Purpose  : Sets the minimum and maximum limits.
271 //================================================================
272
273 void QtxColorScale::setRange( const double min, const double max )
274 {
275         if ( myMin == min && myMax == max )
276                 return;
277
278         myMin = min;
279         myMax = max;
280
281         myPrecise = QString::null;
282
283         if ( colorMode() == Auto || labelMode() == Auto )
284                 updateScale();
285 }
286
287 //================================================================
288 // Function : setTitle
289 // Purpose  : Sets the title string.
290 //================================================================
291
292 void QtxColorScale::setTitle( const QString& str )
293 {
294         if ( myTitle == str )
295                 return;
296
297         myTitle = str;
298         updateScale();
299 }
300
301 //================================================================
302 // Function : setFormat
303 // Purpose  : Sets the format of number presentation in labels for
304 //            Auto label mode (sprintf specification).
305 //================================================================
306
307 void QtxColorScale::setFormat( const QString& format )
308 {
309         if ( myFormat == format )
310                 return;
311
312         myFormat = format;
313         myPrecise = QString::null;
314         if ( colorMode() == Auto )
315                 updateScale();
316 }
317
318 //================================================================
319 // Function : setIntervalsNumber
320 // Purpose  : Sets the number of intervals.
321 //================================================================
322
323 void QtxColorScale::setIntervalsNumber( const int num )
324 {
325         if ( myInterval == num || num < 1 )
326                 return;
327
328         myInterval = num;
329         myPrecise = QString::null;
330
331         updateScale();
332 }
333
334 //================================================================
335 // Function : setLabel
336 // Purpose  : Sets the user label for specified interval. If number
337 //            of interval is negative then user label will be added
338 //            as new at the end of list.
339 //================================================================
340
341 void QtxColorScale::setLabel( const QString& txt, const int idx )
342 {
343         bool changed = false;
344         uint i = idx < 0 ? myLabels.count() : idx;
345         if ( i < myLabels.count() )
346         {
347                 changed = *myLabels.at( i ) != txt;
348                 myLabels[i] = txt;
349         }
350         else
351         {
352                 changed = true;
353                 while ( i >= myLabels.count() )
354                     myLabels.append( "" );
355                 myLabels[i] = txt;
356         }
357         if ( changed )
358                 updateScale();
359 }
360
361 //================================================================
362 // Function : setColor
363 // Purpose  : Sets the user color for specified interval. If number
364 //            of interval is negative then user color will be added
365 //            as new at the end of list.
366 //================================================================
367
368 void QtxColorScale::setColor( const QColor& clr, const int idx )
369 {
370         bool changed = false;
371         uint i = idx < 0 ? myColors.count() : idx;
372         if ( i < myColors.count() )
373         {
374                 changed = *myColors.at( i ) != clr;
375                 myColors[i] = clr;
376         }
377         else
378         {
379                 changed = true;
380         while ( i >= myColors.count() )
381             myColors.append( QColor() );
382                 myColors[i] = clr;
383         }
384         if ( changed )
385                 updateScale();
386 }
387
388 //================================================================
389 // Function : setLabels
390 // Purpose  : Replace the all user label with specified list.
391 //================================================================
392
393 void QtxColorScale::setLabels( const QStringList& list )
394 {
395         if ( list.isEmpty() )
396                 return;
397
398         myLabels = list;
399         updateScale();
400 }
401
402 //================================================================
403 // Function : setColors
404 // Purpose  : Replace the all user colors with specified list.
405 //================================================================
406
407 void QtxColorScale::setColors( const QValueList<QColor>& list )
408 {
409         if ( list.isEmpty() )
410             return;
411
412         myColors = list;
413         updateScale();
414 }
415
416 //================================================================
417 // Function : setColorMode
418 // Purpose  : Sets the color mode (Auto or User).
419 //================================================================
420
421 void QtxColorScale::setColorMode( const int mode )
422 {
423         if ( myColorMode == mode )
424                 return;
425
426         myColorMode = mode;
427         updateScale();
428 }
429
430 //================================================================
431 // Function : setDumpMode
432 // Purpose  : Sets the dump mode.
433 //================================================================
434
435 void QtxColorScale::setDumpMode( const int mode )
436 {
437         myDumpMode = mode;
438 }
439
440 //================================================================
441 // Function : setLabelMode
442 // Purpose  : Sets the label mode (Auto or User).
443 //================================================================
444
445 void QtxColorScale::setLabelMode( const int mode )
446 {
447         if ( myLabelMode != mode )
448         {
449                 myLabelMode = mode;
450                 updateScale();
451         }
452 }
453
454 //================================================================
455 // Function : setLabelPosition
456 // Purpose  : Sets the label position.
457 //================================================================
458
459 void QtxColorScale::setLabelPosition( const int pos )
460 {
461         if ( myLabelPos != pos && pos >= None && pos <= Center )
462         {
463                 myLabelPos = pos;
464                 updateScale();
465         }
466 }
467
468 //================================================================
469 // Function : setTitlePosition
470 // Purpose  : Sets the title position.
471 //================================================================
472
473 void QtxColorScale::setTitlePosition( const int pos )
474 {
475         if ( myTitlePos != pos && pos >= None && pos <= Center )
476         {
477                 myTitlePos = pos;
478                 updateScale();
479         }
480 }
481
482 //================================================================
483 // Function : setFlags
484 // Purpose  : Set the specified flags.
485 //================================================================
486
487 void QtxColorScale::setFlags( const int flags )
488 {
489         int prev = myFlags;
490         myFlags |= flags;
491         if ( prev != myFlags )
492                 updateScale();
493 }
494
495 //================================================================
496 // Function : testFlags
497 // Purpose  : Returns true if specified flags are setted.
498 //================================================================
499
500 bool QtxColorScale::testFlags( const int flags ) const
501 {
502         return ( myFlags & flags ) == flags;
503 }
504
505 //================================================================
506 // Function : clearFlags
507 // Purpose  : Clear (reset) the specified flags.
508 //================================================================
509
510 void QtxColorScale::clearFlags( const int flags )
511 {
512         int prev = myFlags;
513         myFlags &= ~flags;
514         if ( prev != myFlags )
515                 updateScale();
516 }
517
518 //================================================================
519 // Function : minimumSizeHint
520 // Purpose  : 
521 //================================================================
522
523 QSize QtxColorScale::minimumSizeHint() const
524 {
525   QSize sz = calculateSize( true, myFlags, titlePosition() != None, labelPosition() != None, true );
526         return sz + QSize( frameWidth(), frameWidth() );
527 }
528
529 //================================================================
530 // Function : sizeHint
531 // Purpose  : 
532 //================================================================
533
534 QSize QtxColorScale::sizeHint() const
535 {
536   QSize sz = calculateSize( false, myFlags, titlePosition() != None, labelPosition() != None, true );
537         return sz + QSize( frameWidth(), frameWidth() );
538 }
539
540 //================================================================
541 // Function : calculateSize
542 // Purpose  : Dump color scale into pixmap with current size.
543 //================================================================
544
545 QSize QtxColorScale::calculateSize( const bool min, const int flags, const bool title,
546                                                                                     const bool labels, const bool colors ) const
547 {
548         int num = intervalsNumber();
549
550         int spacer = 5;
551         int textWidth = 0;
552         int textHeight = fontMetrics().height();
553         int colorWidth = 20;
554
555         if ( labels && colors )
556   {
557     QtxColorScale* that = (QtxColorScale*)this;
558     QString fmt = that->myFormat;
559
560                 for ( int idx = 0; idx < num; idx++ )
561                         textWidth = QMAX( textWidth, fontMetrics().width( getLabel( idx ) ) );
562
563     if ( !min )
564       that->myFormat = that->myFormat.replace( QRegExp( "g" ), "f" );
565
566                 for ( int index = 0; index < num; index++ )
567                         textWidth = QMAX( textWidth, fontMetrics().width( getLabel( index ) ) );
568
569     that->myFormat = fmt;
570   }
571
572         int scaleWidth = 0;
573         int scaleHeight = 0;
574
575         int titleWidth = 0;
576         int titleHeight = 0;
577
578         if ( flags & AtBorder )
579         {
580                 num++;
581                 if ( min && title && !myTitle.isEmpty() )
582                         titleHeight += 10;
583         }
584
585         if ( colors )
586         {
587                 scaleWidth = colorWidth + textWidth + ( textWidth ? 3 : 2 ) * spacer;
588                 if ( min )
589                         scaleHeight = QMAX( 2 * num, 3 * textHeight );
590                 else
591                         scaleHeight = (int)( 1.5 * ( num + 1 ) * textHeight );
592         }
593
594         if ( title )
595         {
596                 QSimpleRichText* srt = simpleRichText( flags );
597                 if ( srt )
598                 {
599                         QPainter p( this );
600                         if ( scaleWidth )
601                                 srt->setWidth( &p, scaleWidth );
602
603                         titleHeight = srt->height() + spacer;
604                         titleWidth = srt->widthUsed() + 10;
605
606                         delete srt;
607                 }
608         }
609
610         int W = QMAX( titleWidth, scaleWidth ) + width() - contentsRect().width();
611         int H = scaleHeight + titleHeight + height() - contentsRect().height();
612
613         return QSize( W, H );
614 }
615
616 //================================================================
617 // Function : dump
618 // Purpose  : Dump color scale into pixmap with current size.
619 //================================================================
620
621 QPixmap QtxColorScale::dump() const
622 {
623         QPixmap aPix;
624   
625         if ( dumpMode() != NoDump )
626         {
627                 aPix = QPixmap( size() );
628                 if ( !aPix.isNull() )
629                 {
630                         bool scale = ( myDumpMode == ScaleDump || myDumpMode == FullDump );
631                         bool label = ( myDumpMode == ScaleDump || myDumpMode == FullDump ) &&
632                                                  labelPosition() != None;
633                         bool title = ( myDumpMode == TitleDump || myDumpMode == FullDump ) &&
634                                                  titlePosition() != None;
635
636 #if QT_VER < 3
637             QColor bgc = backgroundColor();
638 #else
639             QColor bgc = paletteBackgroundColor();
640 #endif
641                         QPainter p;
642                         p.begin( &aPix );
643                         p.fillRect( 0, 0, aPix.width(), aPix.height(), bgc );
644                         drawScale( &p, bgc, false, 0, 0, aPix.width(), aPix.height(), title, label, scale );
645                         p.end();
646                 }
647         }
648
649         return aPix;
650 }
651
652 //================================================================
653 // Function : dump
654 // Purpose  : Dump color scale into pixmap with specified size.
655 //================================================================
656
657 QPixmap QtxColorScale::dump( const int w, const int h ) const
658 {
659 #if QT_VER < 3
660         return dump( backgroundColor(), w, h );
661 #else
662         return dump( paletteBackgroundColor(), w, h );
663 #endif
664 }
665
666 //================================================================
667 // Function : dump
668 // Purpose  : Dump color scale into pixmap with specified size
669 //            and background color.
670 //================================================================
671
672 QPixmap QtxColorScale::dump( const QColor& bg, const int w, const int h ) const
673 {
674         QPixmap aPix;
675         if ( dumpMode() != NoDump )
676         {
677                 bool scale = ( myDumpMode == ScaleDump || myDumpMode == FullDump );
678                 bool label = ( myDumpMode == ScaleDump || myDumpMode == FullDump ) &&
679                                          labelPosition() != None;
680                 bool title = ( myDumpMode == TitleDump || myDumpMode == FullDump ) &&
681                                          titlePosition() != None;
682
683                 int W = w;
684                 int H = h;
685                 if ( W < 0 || H < 0 )
686                 {
687                         QSize sz = calculateSize( false, myFlags & ~WrapTitle, title, label, scale );
688
689                         if ( W < 0 )
690                                 W = sz.width();
691                         if ( H < 0 )
692                                 H = sz.height();
693                 }
694
695                 aPix = QPixmap( W, H );
696                 if ( !aPix.isNull() )
697                 {
698                         QPainter p;
699                         p.begin( &aPix );
700                         p.fillRect( 0, 0, aPix.width(), aPix.height(), bg );
701                         drawScale( &p, bg, false, 0, 0, aPix.width(), aPix.height(), title, label, scale );
702                         p.end();
703                 }
704         }
705
706         return aPix;
707 }
708
709 //================================================================
710 // Function : show
711 // Purpose  : Show the color scale. [Reimplemented]
712 //================================================================
713
714 void QtxColorScale::show()
715 {
716 #if QT_VER == 3
717         if ( myDock )
718                 myDock->activate();
719         else
720 #endif
721         QFrame::show();
722 }
723
724 //================================================================
725 // Function : hide
726 // Purpose  : Hides the color scale. [Reimplemented]
727 //================================================================
728
729 void QtxColorScale::hide()
730 {
731 #if QT_VER == 3
732         if ( myDock )
733                 myDock->deactivate();
734         else
735 #endif
736         QFrame::hide();
737 }
738
739 //================================================================
740 // Function : drawContents
741 // Purpose  : Draw color scale contents. [Reimplemented]
742 //================================================================
743
744 void QtxColorScale::drawContents( QPainter* p )
745 {
746         if ( !isUpdatesEnabled() )
747                 return;
748
749         QRect aDrawRect = contentsRect();
750
751         drawScale( p, false/*testFlags( Transparent )*/, aDrawRect.x(),
752                            aDrawRect.y(), aDrawRect.width(), aDrawRect.height(),
753                            titlePosition() != None, labelPosition() != None, true );
754 }
755
756 //================================================================
757 // Function : drawScale
758 // Purpose  : Draw color scale contents.
759 //================================================================
760
761 void QtxColorScale::drawScale( QPainter* p, const bool transp, const int X, const int Y,
762                                const int W, const int H, const bool title,
763                                const bool label, const bool scale ) const
764 {
765         QPixmap cache( W, H );
766         QPainter cp( &cache );
767
768 #if QT_VER < 3
769         drawScale( &cp, backgroundColor(), transp, 0, 0, W, H, title, label, scale );
770 #else
771         drawScale( &cp, paletteBackgroundColor(), transp, 0, 0, W, H, title, label, scale );
772 #endif
773         cp.end();
774
775         p->drawPixmap( X, Y, cache );
776 }
777
778 //================================================================
779 // Function : drawScale
780 // Purpose  : Draw color scale contents.
781 //================================================================
782
783 void QtxColorScale::drawScale( QPainter* p, const QColor& bg, const bool transp,
784                                const int X, const int Y, const int W, const int H,
785                                const bool drawTitle, const bool drawLabel, const bool drawColors ) const
786 {
787         if ( !transp )
788                 p->fillRect( X, Y, W, H, bg );
789
790         int num = intervalsNumber();
791
792         int labPos = labelPosition();
793
794         int spacer = 5;
795         int textWidth = 0;
796         int textHeight = p->fontMetrics().height();
797
798         QString aTitle = title();
799
800         int titleWidth = 0;
801         int titleHeight = 0;
802
803         if ( qGray( bg.rgb() ) < 128 )
804                 p->setPen( QColor( 255, 255, 255 ) );
805         else
806             p->setPen( QColor( 0, 0, 0 ) );
807
808         // Draw title
809         if ( drawTitle )
810         {
811                 QSimpleRichText* srt = simpleRichText( myFlags );
812                 if ( srt )
813                 {
814                         srt->setWidth( p, W - 10 );
815                         titleHeight = srt->height() + spacer;
816                         titleWidth = srt->widthUsed();
817                         QColorGroup cg = colorGroup();
818                         cg.setColor( QColorGroup::Text, p->pen().color() );
819                         srt->draw( p, X + 5, Y, QRect( 0, 0, srt->width(), srt->height() ), cg );
820
821                         delete srt;
822                 }
823         }
824
825         bool reverse = testFlags( Reverse );
826
827         QValueList<QColor>  colors;
828         QValueList<QString> labels;
829         for ( int idx = 0; idx < num; idx++ )
830         {
831                 if ( reverse )
832                 {
833                         colors.append( getColor( idx ) );
834                         labels.append( getLabel( idx ) );
835                 }
836                 else
837                 {
838                         colors.prepend( getColor( idx ) );
839                         labels.prepend( getLabel( idx ) );
840                 }
841         }
842
843         if ( testFlags( AtBorder ) )
844         {
845                 if ( reverse )
846                         labels.append( getLabel( num ) );
847                 else
848                         labels.prepend( getLabel( num ) );
849                 if ( drawLabel )
850                         textWidth = QMAX( textWidth, p->fontMetrics().width( labels.last() ) );
851         }
852
853         if ( drawLabel )
854         {
855                 const QFontMetrics& fm = p->fontMetrics();
856                 for ( QStringList::ConstIterator it = labels.begin(); it != labels.end(); ++it )
857                         textWidth = QMAX( textWidth, fm.width( *it) );
858         }
859
860         int lab = labels.count();
861
862         double spc = ( H - ( ( QMIN( lab, 2 ) + QABS( lab - num - 1 ) ) * textHeight ) - titleHeight );
863         double val = spc != 0 ? 1.0 * ( lab - QMIN( lab, 2 ) ) * textHeight / spc : 0;
864         double iPart;
865         double fPart = modf( val, &iPart );
866         int filter = (int)iPart + ( fPart != 0 ? 1 : 0 );
867         filter = QMAX( filter, 1 );
868
869         double step = 1.0 * ( H - ( lab - num + QABS( lab - num - 1 ) ) * textHeight - titleHeight ) / num;
870
871         int ascent = p->fontMetrics().ascent();
872         int colorWidth = QMAX( 5, QMIN( 20, W - textWidth - 3 * spacer ) );
873         if ( labPos == Center || !drawLabel )
874                 colorWidth = W - 2 * spacer;
875
876         // Draw colors
877         int x = X + spacer;
878         switch ( labPos )
879         {
880         case Left:
881             x += textWidth + ( textWidth ? 1 : 0 ) * spacer;
882                 break;
883         }
884
885         double offset = 1.0 * textHeight / 2 * ( lab - num + QABS( lab - num - 1 ) ) + titleHeight;
886         QValueList<QColor>::Iterator cit = colors.begin();
887   uint ci = 0;
888         for ( ci = 0; cit != colors.end() && drawColors; ++cit, ci++ )
889         {
890                 int y = (int)( Y + ci * step + offset );
891                 int h = (int)( Y + ( ci + 1 ) * step + offset ) - y;
892                 p->fillRect( x, y, colorWidth, h, *cit );
893         }
894
895         if ( drawColors )
896                 p->drawRect( int( x - 1 ), int( Y + offset - 1 ), int( colorWidth + 2 ), int( ci * step + 2 ) );
897
898         // Draw labels
899         offset = 1.0 * QABS( lab - num - 1 ) * ( step - textHeight ) / 2 +
900                                                  1.0 * QABS( lab - num - 1 ) * textHeight / 2;
901         offset += titleHeight;
902         if ( drawLabel && !labels.isEmpty() )
903         {
904                 int i1 = 0;
905                 int i2 = lab - 1;
906                 int last1( i1 ), last2( i2 );
907                 int x = X + spacer;
908                 switch ( labPos )
909                 {
910                 case Center:
911                         x += ( colorWidth - textWidth ) / 2;
912                         break;
913                 case Right:
914                         x += colorWidth + spacer;
915                         break;
916                 }
917                 while ( i2 - i1 >= filter || ( i2 == 0 && i1 == 0 ) )
918                 {
919                         int pos1 = i1;
920                         int pos2 = lab - 1 - i2;
921                         if ( filter && !( pos1 % filter ) )
922                         {
923                                 p->drawText( x, (int)( Y + i1 * step + ascent + offset ), *labels.at( i1 ) );
924                                 last1 = i1;
925                         }
926                         if ( filter && !( pos2 % filter ) )
927                         {
928                                 p->drawText( x, (int)( Y + i2 * step + ascent + offset ), *labels.at( i2 ) );
929                                 last2 = i2;
930                         }
931                         i1++;
932                         i2--;
933                 }
934                 int pos = i1;
935                 int i0 = -1;
936                 while ( pos <= i2 && i0 == -1 )
937                 {
938                         if ( filter && !( pos % filter ) &&
939                                  QABS( pos - last1 ) >= filter && QABS( pos - last2 ) >= filter )
940                                 i0 = pos;
941                         pos++;
942                 }
943
944                 if ( i0 != -1 )
945                         p->drawText( x, (int)( Y + i0 * step + ascent + offset ), *labels.at( i0 ) );
946         }
947 }
948
949 //================================================================
950 // Function : getFormat
951 // Purpose  : Returns the format for number labels.
952 //================================================================
953
954 QString QtxColorScale::getFormat() const
955 {
956         QString aFormat = format();
957
958         if ( !testFlags( PreciseFormat ) || testFlags( Integer ) )
959                 return aFormat;
960
961         if ( !myPrecise.isEmpty() )
962                 return myPrecise;
963
964         if ( aFormat.find( QRegExp( "^(%[0-9]*.?[0-9]*[fegFEG])$" ) ) != 0 )
965                 return aFormat;
966
967         int pos1 = aFormat.find( '.' );
968         int pos2 = aFormat.find( QRegExp( "[fegFEG]") );
969
970         QString aLocFormat;
971         int precision = 1;
972         if ( pos1 > 0 )
973         {
974                 aLocFormat = aFormat.mid( 0, pos1 + 1 );
975                 precision = aFormat.mid( pos1 + 1, pos2 - pos1 - 1 ).toInt();
976                 if ( precision < 1 )
977                         precision = 1;
978         }
979         else
980                 return aFormat;
981   
982         QtxColorScale* that = (QtxColorScale*)this;
983
984         // calculate format, maximum precision limited
985         // to 7 digits after the decimal point.
986         while ( myPrecise.isEmpty() && precision < 7 )
987         {
988                 QString aTmpFormat = aLocFormat;
989                 aTmpFormat += QString( "%1" ).arg( precision );
990                 aTmpFormat += aFormat.mid( pos2 );
991
992                 QMap<QString, int> map;
993                 bool isHasTwinz = false;
994
995                 for ( int idx = 0; idx < intervalsNumber() && !isHasTwinz; idx++ )
996                 {
997                         double val = getNumber( idx );
998                         QString tmpname = QString().sprintf( aTmpFormat, val );
999                         isHasTwinz = map.contains( tmpname );
1000                         map.insert( tmpname, 1 );
1001                 }
1002
1003                 if ( !isHasTwinz )
1004                         that->myPrecise = aTmpFormat;
1005                 precision++;
1006         }
1007
1008         if ( !myPrecise.isEmpty() )
1009                 aFormat = myPrecise;
1010
1011         return aFormat;
1012 }
1013
1014 //================================================================
1015 // Function : getNumber
1016 // Purpose  : Returns the number for specified interval.
1017 //================================================================
1018
1019 double QtxColorScale::getNumber( const int idx ) const
1020 {
1021         double val = 0;
1022         if ( intervalsNumber() > 0 )
1023                 val = minimum() + idx * ( QABS( maximum() - minimum() ) / intervalsNumber() );
1024         return val;
1025 }
1026
1027 //================================================================
1028 // Function : getLabel
1029 // Purpose  : Returns the label for specified interval according
1030 //            to the current label mode.
1031 //================================================================
1032
1033 QString QtxColorScale::getLabel( const int idx ) const
1034 {
1035         QString res;
1036         if ( labelMode() == User )
1037                 res = label( idx );
1038         else
1039         {
1040                 double val = getNumber( idx );
1041                 res = QString().sprintf( getFormat(), testFlags( Integer ) ? (int)val : val );
1042         }
1043         return res;
1044 }
1045
1046 //================================================================
1047 // Function : getColor
1048 // Purpose  : Returns the color for specified interval according
1049 //            to the current color mode.
1050 //================================================================
1051
1052 QColor QtxColorScale::getColor( const int idx ) const
1053 {
1054         QColor res;
1055         if ( colorMode() == User )
1056                 res = color( idx );
1057         else
1058                 res = QColor( hueFromValue( idx, 0, intervalsNumber() - 1 ), 255, 255, QColor::Hsv );
1059         return res;
1060 }
1061
1062 //================================================================
1063 // Function : updateScale
1064 // Purpose  : Update color scale if it required.
1065 //================================================================
1066
1067 void QtxColorScale::updateScale()
1068 {
1069   update();
1070         updateGeometry();
1071 }
1072
1073 //================================================================
1074 // Function : simpleRichText
1075 // Purpose  : Return QSimpleRichText object for title. If title
1076 //            not defined (empty string) then return null pointer.
1077 //            Object should be deleted by caller function.
1078 //================================================================
1079
1080 QSimpleRichText* QtxColorScale::simpleRichText( const int flags ) const
1081 {
1082         QSimpleRichText* srt = 0;
1083
1084         QString aTitle;
1085         switch ( titlePosition() )
1086         {
1087         case Left:
1088                 aTitle = QString( "<p align=\"left\">%1</p>" );
1089                 break;
1090         case Right:
1091                 aTitle = QString( "<p align=\"right\">%1</p>" );
1092                 break;
1093         case Center:
1094                 aTitle = QString( "<p align=\"center\">%1</p>" );
1095                 break;
1096         case None:
1097         default:
1098                 break;
1099         }
1100
1101         if ( !aTitle.isEmpty() && !title().isEmpty() )
1102         {
1103                 if ( !myStyleSheet )
1104                 {
1105                         QtxColorScale* that = (QtxColorScale*)this;
1106                         that->myStyleSheet = new QStyleSheet( that );
1107                 }
1108
1109                 if ( myStyleSheet )
1110                 {
1111                         QStyleSheetItem* item = myStyleSheet->item( "p" );
1112                         if ( item )
1113                                 item->setWhiteSpaceMode( flags & WrapTitle ? QStyleSheetItem::WhiteSpaceNormal :
1114                                                                                                                      QStyleSheetItem::WhiteSpaceNoWrap );
1115                 }
1116
1117                 aTitle = aTitle.arg( title() );
1118                 srt = new QSimpleRichText( aTitle, font(), QString::null, myStyleSheet );
1119         }
1120
1121         return srt;
1122 }
1123
1124 //================================================================
1125 // Function : hueFromValue
1126 // Purpose  : 
1127 //================================================================
1128
1129 int QtxColorScale::hueFromValue( const int value, const int min, const int max ) const
1130 {
1131   static const int HUE[10] = {230, 210, 195, 180, 160, 80, 60, 50, 30, 0};
1132
1133         if ( min == max )
1134     return HUE[0];
1135
1136   double aPosition = 9.0 * ( value - min ) / ( max - min );
1137
1138   if ( aPosition <= 0. )
1139     return HUE[0];
1140
1141   if ( aPosition >= 9. )
1142     return HUE[9];
1143
1144   int idx = (int)aPosition;
1145
1146   return HUE[idx] + int( ( aPosition - idx ) * ( HUE[idx + 1] - HUE[idx] ) );
1147 }
1148
1149 #if QT_VER == 3
1150
1151 /*********************************************************************
1152 **  Class:  QtxColorScale::Dock
1153 **  Descr:  Dockable window contains the color scale.
1154 **  Level:  Public
1155 *********************************************************************/
1156
1157 //================================================================
1158 // Function : Dock
1159 // Purpose  : Constructor.
1160 //================================================================
1161
1162 QtxColorScale::Dock::Dock( Place p, QWidget* parent, const char* name, WFlags f )
1163 : QDockWindow( p, parent, name, f ),
1164 myBlockShow( false ),
1165 myBlockResize( false )
1166 {
1167         myScale = new QtxColorScale( this );
1168
1169         setWidget( myScale );
1170
1171         setCloseMode( Always );
1172         setMovingEnabled( true );
1173         setResizeEnabled( true );
1174         setHorizontalStretchable( false );
1175
1176         setCaption( tr ( "Color scale" ) );
1177 }
1178
1179 //================================================================
1180 // Function : ~Dock
1181 // Purpose  : Destructor.
1182 //================================================================
1183
1184 QtxColorScale::Dock::~Dock()
1185 {
1186 }
1187
1188 //================================================================
1189 // Function : colorScale
1190 // Purpose  : Returns color scale widget.
1191 //================================================================
1192
1193 QtxColorScale* QtxColorScale::Dock::colorScale() const
1194 {
1195         return myScale;
1196 }
1197
1198 //================================================================
1199 // Function : activate
1200 // Purpose  : Set the dockable window is visible for main window.
1201 //================================================================
1202
1203 void QtxColorScale::Dock::activate()
1204 {
1205         if ( myBlockShow )
1206                 return;
1207
1208         QMainWindow* mw = 0;
1209         QWidget* p = parentWidget();
1210         while ( !mw && p )
1211         {
1212                 if ( p->inherits( "QMainWindow" ) )
1213                         mw = (QMainWindow*)p;
1214                 p = p->parentWidget();
1215         }
1216         if ( mw )
1217                 mw->setAppropriate( this, true );
1218 }
1219
1220 //================================================================
1221 // Function : deactivate
1222 // Purpose  : Set the dockable window is hidden for main window.
1223 //================================================================
1224
1225 void QtxColorScale::Dock::deactivate()
1226 {
1227         if ( myBlockShow )
1228                 return;
1229
1230         QMainWindow* mw = 0;
1231         QWidget* p = parentWidget();
1232         while ( !mw && p )
1233         {
1234                 if ( p->inherits( "QMainWindow" ) )
1235                         mw = (QMainWindow*)p;
1236                 p = p->parentWidget();
1237         }
1238         if ( mw )
1239                 mw->setAppropriate( this, false );
1240 }
1241
1242 //================================================================
1243 // Function : isActive
1244 // Purpose  : Returns true if the dockable window is visible.
1245 //================================================================
1246
1247 bool QtxColorScale::Dock::isActive() const
1248 {
1249         QMainWindow* mw = 0;
1250         QWidget* p = parentWidget();
1251         while ( !mw && p )
1252         {
1253                 if ( p->inherits( "QMainWindow" ) )
1254                         mw = (QMainWindow*)p;
1255                 p = p->parentWidget();
1256         }
1257         if ( mw )
1258                 return mw->appropriate( (QDockWindow*)this );
1259         else
1260                 return false;
1261 }
1262
1263 //================================================================
1264 // Function : show
1265 // Purpose  : Reimplemented for internal reasons.
1266 //================================================================
1267
1268 void QtxColorScale::Dock::show()
1269 {
1270         bool f = myBlockShow;
1271         myBlockShow = true;
1272         QDockWindow::show();
1273         myBlockShow = f;
1274 }
1275
1276 //================================================================
1277 // Function : hide
1278 // Purpose  : Reimplemented for internal reasons.
1279 //================================================================
1280
1281 void QtxColorScale::Dock::hide()
1282 {
1283         bool f = myBlockShow;
1284         myBlockShow = false;
1285         QDockWindow::hide();
1286         myBlockShow = f;
1287 }
1288
1289 //================================================================
1290 // Function : resize
1291 // Purpose  : Make extent width as maximum value of widget width.
1292 //================================================================
1293
1294 void QtxColorScale::Dock::resize( int w, int h )
1295 {
1296         QDockWindow::resize( w, h );
1297
1298         if ( myBlockResize )
1299                 return;
1300
1301         if ( orientation() == Qt::Vertical )
1302                 setFixedExtentWidth( QMAX( fixedExtent().width(), w ) );
1303         else if ( orientation() == Qt::Horizontal )
1304                 setFixedExtentHeight( QMAX( fixedExtent().height(), h ) );
1305 }
1306
1307 //================================================================
1308 // Function : setOrientation
1309 // Purpose  : 
1310 //================================================================
1311
1312 void QtxColorScale::Dock::setOrientation( Orientation o )
1313 {
1314         bool b = myBlockResize;
1315         myBlockResize = true;
1316         QDockWindow::setOrientation( o );
1317         myBlockResize = b;
1318 }
1319
1320 #endif