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