Salome HOME
Copyright update 2021
[modules/gui.git] / src / Qtx / QtxColorScale.cxx
1 // Copyright (C) 2007-2021  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 // File:      QtxColorScale.cxx
24 // Author:    Sergey TELKOV
25 //
26 #include "QtxColorScale.h"
27
28 #include <QMap>
29 #include <QRegExp>
30 #include <QStringList>
31 #include <QPixmap>
32 #include <QPainter>
33 #include <QTextDocument>
34
35 #include <math.h>
36
37 /*!
38   \class QtxColorScale
39   \brief Color Scale widget.
40 */
41
42 /*!
43   \brief Constructor.
44   \param parent parent widget
45   \param f widget flags
46 */
47 QtxColorScale::QtxColorScale( QWidget* parent, Qt::WindowFlags f )
48 : QFrame( parent, f ),
49   myMin( 0.0 ),
50   myMax( 1.0 ),
51   myTitle( "" ),
52   myFormat( "%.4g" ),
53   myInterval( 10 ),
54   myDumpMode( NoDump ),
55   myColorMode( Auto ),
56   myLabelMode( Auto ),
57   myFlags( AtBorder | WrapTitle ),
58   myLabelPos( Right ),
59   myTitlePos( Center )
60 {
61   setWindowTitle( tr ( "Color scale" ) );
62 }
63
64 /*!
65   \brief Constructor.
66   \param num number of color scale intervals
67   \param parent parent widget
68   \param f widget flags
69 */
70 QtxColorScale::QtxColorScale( const int num, QWidget* parent, Qt::WindowFlags f )
71 : QFrame( parent, f ),
72   myMin( 0.0 ),
73   myMax( 1.0 ),
74   myTitle( "" ),
75   myFormat( "%.4g" ),
76   myInterval( num ),
77   myDumpMode( NoDump ),
78   myColorMode( Auto ),
79   myLabelMode( Auto ),
80   myFlags( AtBorder | WrapTitle ),
81   myLabelPos( Right ),
82   myTitlePos( Center )
83 {
84   setWindowTitle( tr ( "Color scale" ) );
85 }
86
87 /*!
88   \brief Destructor.
89
90   Does nothing for the moment.
91 */
92 QtxColorScale::~QtxColorScale()
93 {
94 }
95
96 /*!
97   \brief Get color scale minimum value.
98   \return lower limit of the color scale
99 */
100 double QtxColorScale::minimum() const
101 {
102   return myMin;
103 }
104
105 /*!
106   \brief Get color scale maximum value.
107   \return upper limit of the color scale
108 */
109 double QtxColorScale::maximum() const
110 {
111   return myMax;
112 }
113
114 /*!
115   \brief Get color scale range.
116   \param min returning lower limit of the color scale
117   \param max returning upper limit of the color scale
118 */
119 void QtxColorScale::range( double& min, double& max ) const
120 {
121   min = myMin;
122   max = myMax;
123 }
124
125 /*!
126   \brief Get color scale title.
127   \return current title
128 */
129 QString QtxColorScale::title() const
130 {
131   return myTitle;
132 }
133
134 /*!
135   \brief Get current format of the number presentation.
136
137   This format is used to output values in the color scale labels
138   in "Auto" label mode. The format uses sprintf specification.
139
140   \return current format
141 */
142 QString QtxColorScale::format() const
143 {
144   return myFormat;
145 }
146
147 /*!
148   \brief Get Color scale dump mode.
149   \return current dump mode (QtxColorScale::DumpMode)
150 */
151 int QtxColorScale::dumpMode() const
152 {
153   return myDumpMode;
154 }
155
156 /*!
157   \brief Get label mode.
158   \return current label mode (QtxColorScale::Mode)
159 */
160 int QtxColorScale::labelMode() const
161 {
162   return myLabelMode;
163 }
164
165 /*!
166   \brief Get color mode.
167   \return current color mode (QtxColorScale::Mode)
168 */
169 int QtxColorScale::colorMode() const
170 {
171   return myColorMode;
172 }
173
174 /*!
175   \brief Get number of color scale intervals.
176   \return number of intervals
177 */
178 int QtxColorScale::intervalsNumber() const
179 {
180   return myInterval;
181 }
182
183 /*!
184   \brief Get user label for the specified color scale interval.
185   \param idx interval index
186   \return user label for specified interval
187 */
188 QString QtxColorScale::label( const int idx ) const
189 {
190   QString res;
191   if ( idx >= 0 && idx < (int)myLabels.count() )
192     res = myLabels[idx];
193   return res;
194 }
195
196 /*!
197   \brief Get user color for the specified color scale interval.
198   \param idx interval index
199   \return user color for specified interval
200 */
201 QColor QtxColorScale::color( const int idx ) const
202 {
203   QColor res;
204   if ( idx >= 0 && idx < (int)myColors.count() )
205     res = myColors[idx];
206   return res;
207 }
208
209 /*!
210   \brief Get user labels for all color scale intervals.
211   \param list returning labels list
212 */
213 void QtxColorScale::labels( QStringList& list ) const
214 {
215   list = myLabels;
216 }
217
218 /*!
219   \brief Get user colors for all color scale intervals.
220   \param list returning colors list
221 */
222 void QtxColorScale::colors( QList<QColor>& list ) const
223 {
224   list = myColors;
225 }
226
227 /*!
228   \brief Get label position.
229   \return label position (QtxColorScale::Position)
230 */
231 int QtxColorScale::labelPosition() const
232 {
233   return myLabelPos;
234 }
235
236 /*!
237   \brief Get title position.
238   \return title position (QtxColorScale::Position)
239 */
240 int QtxColorScale::titlePosition() const
241 {
242   return myTitlePos;
243 }
244
245 /*!
246   \brief Set color scale minimum value.
247   \param val lower limit of the color scale
248 */
249 void QtxColorScale::setMinimum( const double val )
250 {
251   setRange( val, maximum() );
252 }
253
254 /*!
255   \brief Set color scale maximum value.
256   \param val upper limit of the color scale
257 */
258 void QtxColorScale::setMaximum( const double val )
259 {
260   setRange( minimum(), val );
261 }
262
263 /*!
264   \brief Set color scale range.
265   \param min lower limit of the color scale
266   \param max upper limit of the color scale
267 */
268 void QtxColorScale::setRange( const double min, const double max )
269 {
270   if ( myMin == min && myMax == max )
271     return;
272   
273   myMin = min;
274   myMax = max;
275   
276   myPrecise = QString();
277
278   if ( colorMode() == Auto || labelMode() == Auto )
279     updateScale();
280 }
281
282 /*!
283   \brief Set color scale title.
284   \param str new title
285 */
286 void QtxColorScale::setTitle( const QString& str )
287 {
288   if ( myTitle == str )
289     return;
290   
291   myTitle = str;
292   updateScale();
293 }
294
295 /*!
296   \brief Set current format of the number presentation.
297   \sa format()
298   \param format new number presentation format
299 */
300 void QtxColorScale::setFormat( const QString& format )
301 {
302   if ( myFormat == format )
303     return;
304
305   myFormat = format;
306   myPrecise = QString();
307   if ( colorMode() == Auto )
308     updateScale();
309 }
310
311 /*!
312   \brief Set number of color scale intervals.
313   \param num number of intervals
314 */
315 void QtxColorScale::setIntervalsNumber( const int num )
316 {
317   if ( myInterval == num || num < 1 )
318     return;
319   
320   myInterval = num;
321   myPrecise = QString();
322   
323   updateScale();
324 }
325
326 /*!
327   \brief Set user label for the specified color scale interval.
328
329   If number of interval is negative then user label will be added
330   as new to the end of list.
331
332   \param txt user label
333   \param idx interval index
334 */
335 void QtxColorScale::setLabel( const QString& txt, const int idx )
336 {
337   bool changed = false;
338   int i = idx < 0 ? myLabels.count() : idx;
339   if ( i < myLabels.count() )
340   {
341     changed = myLabels[i] != txt;
342     myLabels[i] = txt;
343   }
344   else
345   {
346     changed = true;
347     while ( i >= myLabels.count() )
348       myLabels.append( "" );
349     myLabels[i] = txt;
350   }
351   if ( changed )
352     updateScale();
353 }
354
355 /*!
356   \brief Set user color for the specified color scale interval.
357
358   If number of interval is negative then user color will be added
359   as new to the end of list.
360
361   \param clr user color
362   \param idx interval index
363 */
364 void QtxColorScale::setColor( const QColor& clr, const int idx )
365 {
366   bool changed = false;
367   int i = idx < 0 ? myColors.count() : idx;
368   if ( i < myColors.count() )
369   {
370     changed = myColors[i] != clr;
371     myColors[i] = clr;
372   }
373   else
374   {
375     changed = true;
376     while ( i >= myColors.count() )
377       myColors.append( QColor() );
378     myColors[i] = clr;
379   }
380   if ( changed )
381     updateScale();
382 }
383
384 /*!
385   \brief Set user labels for all color scale intervals.
386   \param list new labels list
387 */
388 void QtxColorScale::setLabels( const QStringList& list )
389 {
390   if ( list.isEmpty() )
391     return;
392
393   myLabels = list;
394   updateScale();
395 }
396
397 /*!
398   \brief Set user colors for all color scale intervals.
399   \param list new colors list
400 */
401 void QtxColorScale::setColors( const QList<QColor>& list )
402 {
403   if ( list.isEmpty() )
404     return;
405
406   myColors = list;
407   updateScale();
408 }
409
410 /*!
411   \brief Set color scale color mode.
412   \param mode new color mode (QtxColorScale::Mode)
413 */
414 void QtxColorScale::setColorMode( const int mode )
415 {
416   if ( myColorMode == mode )
417     return;
418   
419   myColorMode = mode;
420   updateScale();
421 }
422
423 /*!
424   \brief Set color scale dump mode.
425   \param mode new dump mode (QtxColorScale::DumpMode)
426 */
427 void QtxColorScale::setDumpMode( const int mode )
428 {
429   myDumpMode = mode;
430 }
431
432 /*!
433   \brief Set color scale label mode.
434   \param mode new label mode (QtxColorScale::Mode)
435 */
436 void QtxColorScale::setLabelMode( const int mode )
437 {
438   if ( myLabelMode != mode )
439   {
440     myLabelMode = mode;
441     updateScale();
442   }
443 }
444
445 /*!
446   \brief Set label position.
447   \param pos new label position (QtxColorScale::Position)
448 */
449 void QtxColorScale::setLabelPosition( const int pos )
450 {
451   if ( myLabelPos != pos && pos >= None && pos <= Center )
452   {
453     myLabelPos = pos;
454     updateScale();
455   }
456 }
457
458 /*!
459   \brief Set title position.
460   \param pos new title position (QtxColorScale::Position)
461 */
462 void QtxColorScale::setTitlePosition( const int pos )
463 {
464   if ( myTitlePos != pos && pos >= None && pos <= Center )
465   {
466     myTitlePos = pos;
467     updateScale();
468   }
469 }
470
471 /*!
472   \brief Set color scale flags.
473   \param flags new flags
474 */
475 void QtxColorScale::setFlags( const int flags )
476 {
477   int prev = myFlags;
478   myFlags |= flags;
479   if ( prev != myFlags )
480     updateScale();
481 }
482
483 /*!
484   \brief Test color scale flags.
485   \return \c true if specified flags are set
486 */
487 bool QtxColorScale::testFlags( const int flags ) const
488 {
489   return ( myFlags & flags ) == flags;
490 }
491
492 /*!
493   \brief Clear (reset) color scale flags.
494   \param flags color scale flags to be cleared
495 */
496 void QtxColorScale::clearFlags( const int flags )
497 {
498   int prev = myFlags;
499   myFlags &= ~flags;
500   if ( prev != myFlags )
501     updateScale();
502 }
503
504 /*!
505   \brief Get widget's minumum size hint.
506   \return minimum size hint
507 */
508 QSize QtxColorScale::minimumSizeHint() const
509 {
510   QSize sz = calculateSize( true, myFlags, titlePosition() != None, labelPosition() != None, true );
511   return sz + QSize( frameWidth(), frameWidth() );
512 }
513
514 /*!
515   \brief Get widget's default size hint.
516   \return size hint
517 */
518 QSize QtxColorScale::sizeHint() const
519 {
520   QSize sz = calculateSize( false, myFlags, titlePosition() != None, labelPosition() != None, true );
521   return sz + QSize( frameWidth(), frameWidth() );
522 }
523
524 /*!
525   \brief Calculate color scale size.
526   \param min if \c true, color scale size is calculated to be as smallest as possible
527   \param flags color scale flags
528   \param title color scale title
529   \param labels if \c true take into account labels
530   \param colors if \c true take into account colors
531   \return color scale size
532 */
533 QSize QtxColorScale::calculateSize( const bool min, const int flags, const bool title,
534                                     const bool labels, const bool colors ) const
535 {
536   int num = intervalsNumber();
537   
538   int spacer = 5;
539   int textWidth = 0;
540   int textHeight = fontMetrics().height();
541   int colorWidth = 20;
542   
543   if ( labels && colors )
544   {
545     QtxColorScale* that = (QtxColorScale*)this;
546     QString fmt = that->myFormat;
547
548     for ( int idx = 0; idx < num; idx++ )
549       textWidth = qMax( textWidth, fontMetrics().width( getLabel( idx ) ) );
550     
551     if ( !min )
552       that->myFormat = that->myFormat.replace( QRegExp( "g" ), "f" );
553     
554     for ( int index = 0; index < num; index++ )
555       textWidth = qMax( textWidth, fontMetrics().width( getLabel( index ) ) );
556     
557     that->myFormat = fmt;
558   }
559   
560   int scaleWidth = 0;
561   int scaleHeight = 0;
562   
563   int titleWidth = 0;
564   int titleHeight = 0;
565   
566   if ( flags & AtBorder )
567   {
568     num++;
569     if ( min && title && !myTitle.isEmpty() )
570       titleHeight += 10;
571   }
572   
573   if ( colors )
574   {
575     scaleWidth = colorWidth + textWidth + ( textWidth ? 3 : 2 ) * spacer;
576     if ( min )
577       scaleHeight = qMax( 2 * num, 3 * textHeight );
578     else
579       scaleHeight = (int)( 1.5 * ( num + 1 ) * textHeight );
580   }
581
582   if ( title )
583   {
584     QTextDocument* srt = textDocument( flags );
585     if ( srt )
586     {
587       QPainter p( (QtxColorScale*)this );
588       if ( scaleWidth )
589         srt->setTextWidth( scaleWidth );
590       
591       titleHeight = (int)srt->size().height() + spacer;
592       titleWidth = (int)srt->size().width() + 10;
593       
594     }
595     delete srt;
596   }
597
598   int W = qMax( titleWidth, scaleWidth ) + width() - contentsRect().width();
599   int H = scaleHeight + titleHeight + height() - contentsRect().height();
600   
601   return QSize( W, H );
602 }
603
604 /*!
605   \brief Dump color scale into pixmap with current size.
606   \return generated pixmap
607 */
608 QPixmap QtxColorScale::dump() const
609 {
610   QPixmap aPix;
611   
612   if ( dumpMode() != NoDump )
613   {
614     aPix = QPixmap( size() );
615     if ( !aPix.isNull() )
616     {
617       bool scale = ( myDumpMode == ScaleDump || myDumpMode == FullDump );
618       bool label = ( myDumpMode == ScaleDump || myDumpMode == FullDump ) &&
619         labelPosition() != None;
620       bool title = ( myDumpMode == TitleDump || myDumpMode == FullDump ) &&
621         titlePosition() != None;
622       QColor bgc = palette().color( backgroundRole() );
623       QPainter p;
624       p.begin( &aPix );
625       p.fillRect( 0, 0, aPix.width(), aPix.height(), bgc );
626       drawScale( &p, bgc, false, 0, 0, aPix.width(), aPix.height(), title, label, scale );
627       p.end();
628     }
629   }
630   
631   return aPix;
632 }
633
634 /*!
635   \brief Dump color scale into pixmap with the specified size.
636   \param w pixmap width
637   \param h pixmap height
638   \return generated pixmap
639 */
640 QPixmap QtxColorScale::dump( const int w, const int h ) const
641 {
642   return dump( palette().color( backgroundRole() ), w, h );
643 }
644
645 /*!
646   \brief Dump color scale into pixmap with the specified size and background color.
647   \param bg pixmap background color
648   \param w pixmap width
649   \param h pixmap height
650   \return generated pixmap
651 */
652 QPixmap QtxColorScale::dump( const QColor& bg, const int w, const int h ) const
653 {
654   QPixmap aPix;
655   if ( dumpMode() != NoDump )
656   {
657     bool scale = ( myDumpMode == ScaleDump || myDumpMode == FullDump );
658     bool label = ( myDumpMode == ScaleDump || myDumpMode == FullDump ) &&
659       labelPosition() != None;
660     bool title = ( myDumpMode == TitleDump || myDumpMode == FullDump ) &&
661       titlePosition() != None;
662     
663     int W = w;
664     int H = h;
665     if ( W < 0 || H < 0 )
666     {
667       QSize sz = calculateSize( false, myFlags & ~WrapTitle, title, label, scale );
668       
669       if ( W < 0 )
670         W = sz.width();
671       if ( H < 0 )
672         H = sz.height();
673     }
674     
675     aPix = QPixmap( W, H );
676     if ( !aPix.isNull() )
677     {
678       QPainter p;
679       p.begin( &aPix );
680       p.fillRect( 0, 0, aPix.width(), aPix.height(), bg );
681       drawScale( &p, bg, false, 0, 0, aPix.width(), aPix.height(), title, label, scale );
682       p.end();
683     }
684   }
685   
686   return aPix;
687 }
688
689 /*!
690   \brief Show color scale (reimplemented from QFrame).
691 */
692 void QtxColorScale::show()
693 {
694   QFrame::show();
695 }
696
697 /*!
698   \brief Hide color scale (reimplemented from QFrame).
699 */
700 void QtxColorScale::hide()
701 {
702   QFrame::hide();
703 }
704
705 /*!
706   \brief Paint widget
707   \param e paint event
708 */
709 void QtxColorScale::paintEvent( QPaintEvent* /*e*/ )
710 {
711   QPainter p( this );
712   drawFrame( &p );
713   drawContents( &p );
714 }
715
716 /*!
717   \brief Draw color scale (reimplemented from QFrame).
718   \param p painter
719 */
720 void QtxColorScale::drawContents( QPainter* p )
721 {
722   if ( !updatesEnabled() )
723     return;
724   
725   QRect aDrawRect = contentsRect();
726   
727   drawScale( p, false/*testFlags( Transparent )*/, aDrawRect.x(),
728              aDrawRect.y(), aDrawRect.width(), aDrawRect.height(),
729              titlePosition() != None, labelPosition() != None, true );
730 }
731
732 /*!
733   \brief Draw color scale contents.
734   \param p painter
735   \param transp if \c true color scale is drawn on transparent background
736   \param X color scale x coordinate
737   \param Y color scale y coordinate
738   \param W color scale width
739   \param H color scale height
740   \param drawTitle if \c true, draw title
741   \param drawLabel if \c true, draw labels
742   \param drawColors if \c true, draw colors
743 */
744 void QtxColorScale::drawScale( QPainter* p, const bool transp, const int X, const int Y,
745                                const int W, const int H, const bool drawTitle,
746                                const bool drawLabel, const bool drawColors ) const
747 {
748   QPixmap cache( W, H );
749   QPainter cp( &cache );
750   
751   drawScale( &cp, palette().color( backgroundRole() ), transp, 0, 0, W, H, drawTitle, drawLabel, drawColors );
752   cp.end();
753   
754   p->drawPixmap( X, Y, cache );
755 }
756
757 /*!
758   \brief Draw color scale contents.
759   \param p painter
760   \param bg background color
761   \param transp if \c true color scale is drawn on transparent background
762   \param X color scale x coordinate
763   \param Y color scale y coordinate
764   \param W color scale width
765   \param H color scale height
766   \param drawTitle if \c true, draw title
767   \param drawLabel if \c true, draw labels
768   \param drawColors if \c true, draw colors
769 */
770 void QtxColorScale::drawScale( QPainter* p, const QColor& bg, const bool transp,
771                                const int X, const int Y, const int W, const int H,
772                                const bool drawTitle, const bool drawLabel, const bool drawColors ) const
773 {
774   if ( !transp )
775     p->fillRect( X, Y, W, H, bg );
776   
777   int num = intervalsNumber();
778   
779   int labPos = labelPosition();
780   
781   int spacer = 5;
782   int textWidth = 0;
783   int textHeight = p->fontMetrics().height();
784   
785   QString aTitle = title();
786   
787   //int titleWidth = 0; // unused
788   int titleHeight = 0;
789   
790   if ( qGray( bg.rgb() ) < 128 )
791     p->setPen( QColor( 255, 255, 255 ) );
792   else
793     p->setPen( QColor( 0, 0, 0 ) );
794   
795   // Draw title
796   if ( drawTitle )
797   {
798     QTextDocument* srt = textDocument( myFlags );
799     if ( srt )
800     {
801       srt->setTextWidth( W - 10 );
802       titleHeight = (int)srt->size().height() + spacer;
803       //titleWidth = (int)srt->size().width(); // unused
804       p->save();
805       p->translate( X + 5, Y );
806       srt->drawContents( p );
807       p->restore();
808     }
809     delete srt;
810   }
811
812   bool reverse = testFlags( Reverse );
813   
814   QList<QColor>  colors;
815   QList<QString> labels;
816   for ( int idx = 0; idx < num; idx++ )
817   {
818     if ( reverse )
819     {
820       colors.append( getColor( idx ) );
821       labels.append( getLabel( idx ) );
822     }
823     else
824     {
825       colors.prepend( getColor( idx ) );
826       labels.prepend( getLabel( idx ) );
827     }
828   }
829   
830   if ( testFlags( AtBorder ) )
831   {
832     if ( reverse )
833       labels.append( getLabel( num ) );
834     else
835       labels.prepend( getLabel( num ) );
836     if ( drawLabel )
837       textWidth = qMax( textWidth, p->fontMetrics().width( labels.last() ) );
838   }
839   
840   if ( drawLabel )
841   {
842     const QFontMetrics& fm = p->fontMetrics();
843     for ( QStringList::ConstIterator it = labels.begin(); it != labels.end(); ++it )
844       textWidth = qMax( textWidth, fm.width( *it) );
845   }
846   
847   int lab = labels.count();
848   
849   double spc = ( H - ( ( qMin( lab, 2 ) + qAbs( lab - num - 1 ) ) * textHeight ) - titleHeight );
850   double val = spc != 0 ? 1.0 * ( lab - qMin( lab, 2 ) ) * textHeight / spc : 0;
851   double iPart;
852   double fPart = modf( val, &iPart );
853   int filter = (int)iPart + ( fPart != 0 ? 1 : 0 );
854   filter = qMax( filter, 1 );
855   
856   double step = 1.0 * ( H - ( lab - num + qAbs( lab - num - 1 ) ) * textHeight - titleHeight ) / num;
857   
858   int ascent = p->fontMetrics().ascent();
859   int colorWidth = qMax( 5, qMin( 20, W - textWidth - 3 * spacer ) );
860   if ( labPos == Center || !drawLabel )
861     colorWidth = W - 2 * spacer;
862   
863   // Draw colors
864   int x = X + spacer;
865   switch ( labPos )
866   {
867   case Left:
868     x += textWidth + ( textWidth ? 1 : 0 ) * spacer;
869     break;
870   }
871
872   double offset = 1.0 * textHeight / 2 * ( lab - num + qAbs( lab - num - 1 ) ) + titleHeight;
873   QList<QColor>::Iterator cit = colors.begin();
874   uint ci = 0;
875   for ( ci = 0; cit != colors.end() && drawColors; ++cit, ci++ )
876   {
877     int y = (int)( Y + ci * step + offset );
878     int h = (int)( Y + ( ci + 1 ) * step + offset ) - y;
879     p->fillRect( x, y, colorWidth, h, *cit );
880   }
881   
882   if ( drawColors )
883     p->drawRect( int( x - 1 ), int( Y + offset - 1 ), int( colorWidth + 2 ), int( ci * step + 2 ) );
884   
885   // Draw labels
886   offset = 1.0 * qAbs( lab - num - 1 ) * ( step - textHeight ) / 2 +
887     1.0 * qAbs( lab - num - 1 ) * textHeight / 2;
888   offset += titleHeight;
889   if ( drawLabel && !labels.isEmpty() )
890   {
891     int i1 = 0;
892     int i2 = lab - 1;
893     int last1( i1 ), last2( i2 );
894     int x = X + spacer;
895     switch ( labPos )
896     {
897     case Center:
898       x += ( colorWidth - textWidth ) / 2;
899       break;
900     case Right:
901       x += colorWidth + spacer;
902       break;
903     }
904     while ( i2 - i1 >= filter || ( i2 == 0 && i1 == 0 ) )
905     {
906       int pos1 = i1;
907       int pos2 = lab - 1 - i2;
908       if ( filter && !( pos1 % filter ) )
909       {
910         p->drawText( x, (int)( Y + i1 * step + ascent + offset ), labels[i1] );
911         last1 = i1;
912       }
913       if ( filter && !( pos2 % filter ) )
914       {
915         p->drawText( x, (int)( Y + i2 * step + ascent + offset ), labels[i2] );
916         last2 = i2;
917       }
918       i1++;
919       i2--;
920     }
921     int pos = i1;
922     int i0 = -1;
923     while ( pos <= i2 && i0 == -1 )
924     {
925       if ( filter && !( pos % filter ) &&
926            qAbs( pos - last1 ) >= filter && qAbs( pos - last2 ) >= filter )
927         i0 = pos;
928       pos++;
929     }
930
931     if ( i0 != -1 )
932       p->drawText( x, (int)( Y + i0 * step + ascent + offset ), labels[i0] );
933   }
934 }
935
936 /*!
937   \brief Generate number presentation format.
938   \return format for number labels
939 */
940 QString QtxColorScale::getFormat() const
941 {
942   QString aFormat = format();
943   
944   if ( !testFlags( PreciseFormat ) || testFlags( Integer ) )
945     return aFormat;
946   
947   if ( !myPrecise.isEmpty() )
948     return myPrecise;
949   
950   if ( !aFormat.contains( QRegExp( "^(%[0-9]*.?[0-9]*[fegFEG])$" ) ) )
951     return aFormat;
952   
953   int pos1 = aFormat.indexOf( '.' );
954   int pos2 = aFormat.indexOf( QRegExp( "[fegFEG]") );
955   
956   QString aLocFormat;
957   int precision = 1;
958   if ( pos1 > 0 )
959   {
960     aLocFormat = aFormat.mid( 0, pos1 + 1 );
961     precision = aFormat.mid( pos1 + 1, pos2 - pos1 - 1 ).toInt();
962     if ( precision < 1 )
963       precision = 1;
964   }
965   else
966     return aFormat;
967   
968   QtxColorScale* that = (QtxColorScale*)this;
969   
970   // calculate format, maximum precision limited
971   // to 7 digits after the decimal point.
972   while ( myPrecise.isEmpty() && precision < 7 )
973   {
974     QString aTmpFormat = aLocFormat;
975     aTmpFormat += QString( "%1" ).arg( precision );
976     aTmpFormat += aFormat.mid( pos2 );
977     
978     QMap<QString, int> map;
979     bool isHasTwinz = false;
980     
981     for ( int idx = 0; idx < intervalsNumber() && !isHasTwinz; idx++ )
982     {
983       double val = getNumber( idx );
984       QString tmpname = QString().sprintf( aTmpFormat.toLatin1(), val );
985       isHasTwinz = map.contains( tmpname );
986       map.insert( tmpname, 1 );
987     }
988     
989     if ( !isHasTwinz )
990       that->myPrecise = aTmpFormat;
991     precision++;
992   }
993   
994   if ( !myPrecise.isEmpty() )
995     aFormat = myPrecise;
996   
997   return aFormat;
998 }
999
1000 /*!
1001   \brief Get color scale value corresponding to the specified interval.
1002   \param idx interval index
1003   \return color scale value
1004 */
1005 double QtxColorScale::getNumber( const int idx ) const
1006 {
1007   double val = 0;
1008   if ( intervalsNumber() > 0 )
1009     val = minimum() + idx * ( qAbs( maximum() - minimum() ) / intervalsNumber() );
1010   return val;
1011 }
1012
1013 /*!
1014   \brief Get color scale label text corresponding to the specified interval.
1015   \param idx interval index
1016   \return color scale label text
1017 */
1018 QString QtxColorScale::getLabel( const int idx ) const
1019 {
1020   QString res;
1021   if ( labelMode() == User )
1022     res = label( idx );
1023   else
1024   {
1025     double val = getNumber( idx );
1026     res = QString().sprintf( getFormat().toLatin1(), testFlags( Integer ) ? (int)val : val );
1027   }
1028   return res;
1029 }
1030
1031 /*!
1032   \brief Get color scale color corresponding to the specified interval.
1033   \param idx interval index
1034   \return color scale color
1035 */
1036 QColor QtxColorScale::getColor( const int idx ) const
1037 {
1038   QColor res;
1039   if ( colorMode() == User )
1040     res = color( idx );
1041   else
1042     res = Qtx::scaleColor( idx, 0, intervalsNumber() - 1 );
1043   return res;
1044 }
1045
1046 /*!
1047   \brief Update color scale.
1048 */
1049 void QtxColorScale::updateScale()
1050 {
1051   update();
1052   updateGeometry();
1053 }
1054
1055 /*!
1056   \brief Get text document (rich text) for the color scale title representation.
1057
1058   If title is not defined (empty string) then null pointer is returned.
1059   The calling function is responsible for the returning object deleting.
1060
1061   \param flags color scale flags (not used)
1062   \return text document or 0 if title is not set
1063 */
1064 QTextDocument* QtxColorScale::textDocument( const int /*flags*/ ) const
1065 {
1066   QTextDocument* doc = 0;
1067
1068   QString aTitle;
1069   switch ( titlePosition() )
1070   {
1071   case Left:
1072     aTitle = QString( "<p align=\"left\">%1</p>" );
1073     break;
1074   case Right:
1075     aTitle = QString( "<p align=\"right\">%1</p>" );
1076     break;
1077   case Center:
1078     aTitle = QString( "<p align=\"center\">%1</p>" );
1079     break;
1080   case None:
1081   default:
1082     break;
1083   }
1084   
1085   if ( !aTitle.isEmpty() && !title().isEmpty() )
1086   {
1087     /*
1088     if ( !myStyleSheet )
1089     {
1090       QtxColorScale* that = (QtxColorScale*)this;
1091       that->myStyleSheet = new QStyleSheet( that );
1092     }
1093       
1094     if ( myStyleSheet )
1095     {
1096       QStyleSheetItem* item = myStyleSheet->item( "p" );
1097       if ( item )
1098       item->setWhiteSpaceMode( flags & WrapTitle ? QStyleSheetItem::WhiteSpaceNormal :
1099       QStyleSheetItem::WhiteSpaceNoWrap );
1100     }
1101     */
1102     aTitle = aTitle.arg( title() );
1103     doc = new QTextDocument( aTitle );
1104   }
1105
1106   return doc;
1107 }