1 // Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
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.
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.
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
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 // File: QtxColorScale.cxx
24 // Author: Sergey TELKOV
26 #include "QtxColorScale.h"
30 #include <QStringList>
33 #include <QTextDocument>
39 \brief Color Scale widget.
44 \param parent parent widget
47 QtxColorScale::QtxColorScale( QWidget* parent, Qt::WindowFlags f )
48 : QFrame( parent, f ),
57 myFlags( AtBorder | WrapTitle ),
61 setWindowTitle( tr ( "Color scale" ) );
66 \param num number of color scale intervals
67 \param parent parent widget
70 QtxColorScale::QtxColorScale( const int num, QWidget* parent, Qt::WindowFlags f )
71 : QFrame( parent, f ),
80 myFlags( AtBorder | WrapTitle ),
84 setWindowTitle( tr ( "Color scale" ) );
90 Does nothing for the moment.
92 QtxColorScale::~QtxColorScale()
97 \brief Get color scale minimum value.
98 \return lower limit of the color scale
100 double QtxColorScale::minimum() const
106 \brief Get color scale maximum value.
107 \return upper limit of the color scale
109 double QtxColorScale::maximum() const
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
119 void QtxColorScale::range( double& min, double& max ) const
126 \brief Get color scale title.
127 \return current title
129 QString QtxColorScale::title() const
135 \brief Get current format of the number presentation.
137 This format is used to output values in the color scale labels
138 in "Auto" label mode. The format uses sprintf specification.
140 \return current format
142 QString QtxColorScale::format() const
148 \brief Get Color scale dump mode.
149 \return current dump mode (QtxColorScale::DumpMode)
151 int QtxColorScale::dumpMode() const
157 \brief Get label mode.
158 \return current label mode (QtxColorScale::Mode)
160 int QtxColorScale::labelMode() const
166 \brief Get color mode.
167 \return current color mode (QtxColorScale::Mode)
169 int QtxColorScale::colorMode() const
175 \brief Get number of color scale intervals.
176 \return number of intervals
178 int QtxColorScale::intervalsNumber() const
184 \brief Get user label for the specified color scale interval.
185 \param idx interval index
186 \return user label for specified interval
188 QString QtxColorScale::label( const int idx ) const
191 if ( idx >= 0 && idx < (int)myLabels.count() )
197 \brief Get user color for the specified color scale interval.
198 \param idx interval index
199 \return user color for specified interval
201 QColor QtxColorScale::color( const int idx ) const
204 if ( idx >= 0 && idx < (int)myColors.count() )
210 \brief Get user labels for all color scale intervals.
211 \param list returning labels list
213 void QtxColorScale::labels( QStringList& list ) const
219 \brief Get user colors for all color scale intervals.
220 \param list returning colors list
222 void QtxColorScale::colors( QList<QColor>& list ) const
228 \brief Get label position.
229 \return label position (QtxColorScale::Position)
231 int QtxColorScale::labelPosition() const
237 \brief Get title position.
238 \return title position (QtxColorScale::Position)
240 int QtxColorScale::titlePosition() const
246 \brief Set color scale minimum value.
247 \param val lower limit of the color scale
249 void QtxColorScale::setMinimum( const double val )
251 setRange( val, maximum() );
255 \brief Set color scale maximum value.
256 \param val upper limit of the color scale
258 void QtxColorScale::setMaximum( const double val )
260 setRange( minimum(), val );
264 \brief Set color scale range.
265 \param min lower limit of the color scale
266 \param max upper limit of the color scale
268 void QtxColorScale::setRange( const double min, const double max )
270 if ( myMin == min && myMax == max )
276 myPrecise = QString();
278 if ( colorMode() == Auto || labelMode() == Auto )
283 \brief Set color scale title.
286 void QtxColorScale::setTitle( const QString& str )
288 if ( myTitle == str )
296 \brief Set current format of the number presentation.
298 \param format new number presentation format
300 void QtxColorScale::setFormat( const QString& format )
302 if ( myFormat == format )
306 myPrecise = QString();
307 if ( colorMode() == Auto )
312 \brief Set number of color scale intervals.
313 \param num number of intervals
315 void QtxColorScale::setIntervalsNumber( const int num )
317 if ( myInterval == num || num < 1 )
321 myPrecise = QString();
327 \brief Set user label for the specified color scale interval.
329 If number of interval is negative then user label will be added
330 as new to the end of list.
332 \param txt user label
333 \param idx interval index
335 void QtxColorScale::setLabel( const QString& txt, const int idx )
337 bool changed = false;
338 int i = idx < 0 ? myLabels.count() : idx;
339 if ( i < myLabels.count() )
341 changed = myLabels[i] != txt;
347 while ( i >= myLabels.count() )
348 myLabels.append( "" );
356 \brief Set user color for the specified color scale interval.
358 If number of interval is negative then user color will be added
359 as new to the end of list.
361 \param clr user color
362 \param idx interval index
364 void QtxColorScale::setColor( const QColor& clr, const int idx )
366 bool changed = false;
367 int i = idx < 0 ? myColors.count() : idx;
368 if ( i < myColors.count() )
370 changed = myColors[i] != clr;
376 while ( i >= myColors.count() )
377 myColors.append( QColor() );
385 \brief Set user labels for all color scale intervals.
386 \param list new labels list
388 void QtxColorScale::setLabels( const QStringList& list )
390 if ( list.isEmpty() )
398 \brief Set user colors for all color scale intervals.
399 \param list new colors list
401 void QtxColorScale::setColors( const QList<QColor>& list )
403 if ( list.isEmpty() )
411 \brief Set color scale color mode.
412 \param mode new color mode (QtxColorScale::Mode)
414 void QtxColorScale::setColorMode( const int mode )
416 if ( myColorMode == mode )
424 \brief Set color scale dump mode.
425 \param mode new dump mode (QtxColorScale::DumpMode)
427 void QtxColorScale::setDumpMode( const int mode )
433 \brief Set color scale label mode.
434 \param mode new label mode (QtxColorScale::Mode)
436 void QtxColorScale::setLabelMode( const int mode )
438 if ( myLabelMode != mode )
446 \brief Set label position.
447 \param pos new label position (QtxColorScale::Position)
449 void QtxColorScale::setLabelPosition( const int pos )
451 if ( myLabelPos != pos && pos >= None && pos <= Center )
459 \brief Set title position.
460 \param pos new title position (QtxColorScale::Position)
462 void QtxColorScale::setTitlePosition( const int pos )
464 if ( myTitlePos != pos && pos >= None && pos <= Center )
472 \brief Set color scale flags.
473 \param flags new flags
475 void QtxColorScale::setFlags( const int flags )
479 if ( prev != myFlags )
484 \brief Test color scale flags.
485 \return \c true if specified flags are set
487 bool QtxColorScale::testFlags( const int flags ) const
489 return ( myFlags & flags ) == flags;
493 \brief Clear (reset) color scale flags.
494 \param flags color scale flags to be cleared
496 void QtxColorScale::clearFlags( const int flags )
500 if ( prev != myFlags )
505 \brief Get widget's minumum size hint.
506 \return minimum size hint
508 QSize QtxColorScale::minimumSizeHint() const
510 QSize sz = calculateSize( true, myFlags, titlePosition() != None, labelPosition() != None, true );
511 return sz + QSize( frameWidth(), frameWidth() );
515 \brief Get widget's default size hint.
518 QSize QtxColorScale::sizeHint() const
520 QSize sz = calculateSize( false, myFlags, titlePosition() != None, labelPosition() != None, true );
521 return sz + QSize( frameWidth(), frameWidth() );
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
533 QSize QtxColorScale::calculateSize( const bool min, const int flags, const bool title,
534 const bool labels, const bool colors ) const
536 int num = intervalsNumber();
540 int textHeight = fontMetrics().height();
543 if ( labels && colors )
545 QtxColorScale* that = (QtxColorScale*)this;
546 QString fmt = that->myFormat;
548 for ( int idx = 0; idx < num; idx++ )
549 textWidth = qMax( textWidth, fontMetrics().width( getLabel( idx ) ) );
552 that->myFormat = that->myFormat.replace( QRegExp( "g" ), "f" );
554 for ( int index = 0; index < num; index++ )
555 textWidth = qMax( textWidth, fontMetrics().width( getLabel( index ) ) );
557 that->myFormat = fmt;
566 if ( flags & AtBorder )
569 if ( min && title && !myTitle.isEmpty() )
575 scaleWidth = colorWidth + textWidth + ( textWidth ? 3 : 2 ) * spacer;
577 scaleHeight = qMax( 2 * num, 3 * textHeight );
579 scaleHeight = (int)( 1.5 * ( num + 1 ) * textHeight );
584 QTextDocument* srt = textDocument( flags );
587 QPainter p( (QtxColorScale*)this );
589 srt->setTextWidth( scaleWidth );
591 titleHeight = (int)srt->size().height() + spacer;
592 titleWidth = (int)srt->size().width() + 10;
598 int W = qMax( titleWidth, scaleWidth ) + width() - contentsRect().width();
599 int H = scaleHeight + titleHeight + height() - contentsRect().height();
601 return QSize( W, H );
605 \brief Dump color scale into pixmap with current size.
606 \return generated pixmap
608 QPixmap QtxColorScale::dump() const
612 if ( dumpMode() != NoDump )
614 aPix = QPixmap( size() );
615 if ( !aPix.isNull() )
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() );
625 p.fillRect( 0, 0, aPix.width(), aPix.height(), bgc );
626 drawScale( &p, bgc, false, 0, 0, aPix.width(), aPix.height(), title, label, scale );
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
640 QPixmap QtxColorScale::dump( const int w, const int h ) const
642 return dump( palette().color( backgroundRole() ), w, h );
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
652 QPixmap QtxColorScale::dump( const QColor& bg, const int w, const int h ) const
655 if ( dumpMode() != NoDump )
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;
665 if ( W < 0 || H < 0 )
667 QSize sz = calculateSize( false, myFlags & ~WrapTitle, title, label, scale );
675 aPix = QPixmap( W, H );
676 if ( !aPix.isNull() )
680 p.fillRect( 0, 0, aPix.width(), aPix.height(), bg );
681 drawScale( &p, bg, false, 0, 0, aPix.width(), aPix.height(), title, label, scale );
690 \brief Show color scale (reimplemented from QFrame).
692 void QtxColorScale::show()
698 \brief Hide color scale (reimplemented from QFrame).
700 void QtxColorScale::hide()
709 void QtxColorScale::paintEvent( QPaintEvent* e )
717 \brief Draw color scale (reimplemented from QFrame).
720 void QtxColorScale::drawContents( QPainter* p )
722 if ( !updatesEnabled() )
725 QRect aDrawRect = contentsRect();
727 drawScale( p, false/*testFlags( Transparent )*/, aDrawRect.x(),
728 aDrawRect.y(), aDrawRect.width(), aDrawRect.height(),
729 titlePosition() != None, labelPosition() != None, true );
733 \brief Draw color scale contents.
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
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
748 QPixmap cache( W, H );
749 QPainter cp( &cache );
751 drawScale( &cp, palette().color( backgroundRole() ), transp, 0, 0, W, H, drawTitle, drawLabel, drawColors );
754 p->drawPixmap( X, Y, cache );
758 \brief Draw color scale contents.
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
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
775 p->fillRect( X, Y, W, H, bg );
777 int num = intervalsNumber();
779 int labPos = labelPosition();
783 int textHeight = p->fontMetrics().height();
785 QString aTitle = title();
790 if ( qGray( bg.rgb() ) < 128 )
791 p->setPen( QColor( 255, 255, 255 ) );
793 p->setPen( QColor( 0, 0, 0 ) );
798 QTextDocument* srt = textDocument( myFlags );
801 srt->setTextWidth( W - 10 );
802 titleHeight = (int)srt->size().height() + spacer;
803 titleWidth = (int)srt->size().width();
805 p->translate( X + 5, Y );
806 srt->drawContents( p );
812 bool reverse = testFlags( Reverse );
814 QList<QColor> colors;
815 QList<QString> labels;
816 for ( int idx = 0; idx < num; idx++ )
820 colors.append( getColor( idx ) );
821 labels.append( getLabel( idx ) );
825 colors.prepend( getColor( idx ) );
826 labels.prepend( getLabel( idx ) );
830 if ( testFlags( AtBorder ) )
833 labels.append( getLabel( num ) );
835 labels.prepend( getLabel( num ) );
837 textWidth = qMax( textWidth, p->fontMetrics().width( labels.last() ) );
842 const QFontMetrics& fm = p->fontMetrics();
843 for ( QStringList::ConstIterator it = labels.begin(); it != labels.end(); ++it )
844 textWidth = qMax( textWidth, fm.width( *it) );
847 int lab = labels.count();
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;
852 double fPart = modf( val, &iPart );
853 int filter = (int)iPart + ( fPart != 0 ? 1 : 0 );
854 filter = qMax( filter, 1 );
856 double step = 1.0 * ( H - ( lab - num + qAbs( lab - num - 1 ) ) * textHeight - titleHeight ) / num;
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;
868 x += textWidth + ( textWidth ? 1 : 0 ) * spacer;
872 double offset = 1.0 * textHeight / 2 * ( lab - num + qAbs( lab - num - 1 ) ) + titleHeight;
873 QList<QColor>::Iterator cit = colors.begin();
875 for ( ci = 0; cit != colors.end() && drawColors; ++cit, ci++ )
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 );
883 p->drawRect( int( x - 1 ), int( Y + offset - 1 ), int( colorWidth + 2 ), int( ci * step + 2 ) );
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() )
893 int last1( i1 ), last2( i2 );
898 x += ( colorWidth - textWidth ) / 2;
901 x += colorWidth + spacer;
904 while ( i2 - i1 >= filter || ( i2 == 0 && i1 == 0 ) )
907 int pos2 = lab - 1 - i2;
908 if ( filter && !( pos1 % filter ) )
910 p->drawText( x, (int)( Y + i1 * step + ascent + offset ), labels[i1] );
913 if ( filter && !( pos2 % filter ) )
915 p->drawText( x, (int)( Y + i2 * step + ascent + offset ), labels[i2] );
923 while ( pos <= i2 && i0 == -1 )
925 if ( filter && !( pos % filter ) &&
926 qAbs( pos - last1 ) >= filter && qAbs( pos - last2 ) >= filter )
932 p->drawText( x, (int)( Y + i0 * step + ascent + offset ), labels[i0] );
937 \brief Generate number presentation format.
938 \return format for number labels
940 QString QtxColorScale::getFormat() const
942 QString aFormat = format();
944 if ( !testFlags( PreciseFormat ) || testFlags( Integer ) )
947 if ( !myPrecise.isEmpty() )
950 if ( !aFormat.contains( QRegExp( "^(%[0-9]*.?[0-9]*[fegFEG])$" ) ) )
953 int pos1 = aFormat.indexOf( '.' );
954 int pos2 = aFormat.indexOf( QRegExp( "[fegFEG]") );
960 aLocFormat = aFormat.mid( 0, pos1 + 1 );
961 precision = aFormat.mid( pos1 + 1, pos2 - pos1 - 1 ).toInt();
968 QtxColorScale* that = (QtxColorScale*)this;
970 // calculate format, maximum precision limited
971 // to 7 digits after the decimal point.
972 while ( myPrecise.isEmpty() && precision < 7 )
974 QString aTmpFormat = aLocFormat;
975 aTmpFormat += QString( "%1" ).arg( precision );
976 aTmpFormat += aFormat.mid( pos2 );
978 QMap<QString, int> map;
979 bool isHasTwinz = false;
981 for ( int idx = 0; idx < intervalsNumber() && !isHasTwinz; idx++ )
983 double val = getNumber( idx );
984 QString tmpname = QString().sprintf( aTmpFormat.toLatin1(), val );
985 isHasTwinz = map.contains( tmpname );
986 map.insert( tmpname, 1 );
990 that->myPrecise = aTmpFormat;
994 if ( !myPrecise.isEmpty() )
1001 \brief Get color scale value corresponding to the specified interval.
1002 \param idx interval index
1003 \return color scale value
1005 double QtxColorScale::getNumber( const int idx ) const
1008 if ( intervalsNumber() > 0 )
1009 val = minimum() + idx * ( qAbs( maximum() - minimum() ) / intervalsNumber() );
1014 \brief Get color scale label text corresponding to the specified interval.
1015 \param idx interval index
1016 \return color scale label text
1018 QString QtxColorScale::getLabel( const int idx ) const
1021 if ( labelMode() == User )
1025 double val = getNumber( idx );
1026 res = QString().sprintf( getFormat().toLatin1(), testFlags( Integer ) ? (int)val : val );
1032 \brief Get color scale color corresponding to the specified interval.
1033 \param idx interval index
1034 \return color scale color
1036 QColor QtxColorScale::getColor( const int idx ) const
1039 if ( colorMode() == User )
1042 res = Qtx::scaleColor( idx, 0, intervalsNumber() - 1 );
1047 \brief Update color scale.
1049 void QtxColorScale::updateScale()
1056 \brief Get text document (rich text) for the color scale title representation.
1058 If title is not defined (empty string) then null pointer is returned.
1059 The calling function is responsible for the returning object deleting.
1061 \param flags color scale flags (not used)
1062 \return text document or 0 if title is not set
1064 QTextDocument* QtxColorScale::textDocument( const int /*flags*/ ) const
1066 QTextDocument* doc = 0;
1069 switch ( titlePosition() )
1072 aTitle = QString( "<p align=\"left\">%1</p>" );
1075 aTitle = QString( "<p align=\"right\">%1</p>" );
1078 aTitle = QString( "<p align=\"center\">%1</p>" );
1085 if ( !aTitle.isEmpty() && !title().isEmpty() )
1088 if ( !myStyleSheet )
1090 QtxColorScale* that = (QtxColorScale*)this;
1091 that->myStyleSheet = new QStyleSheet( that );
1096 QStyleSheetItem* item = myStyleSheet->item( "p" );
1098 item->setWhiteSpaceMode( flags & WrapTitle ? QStyleSheetItem::WhiteSpaceNormal :
1099 QStyleSheetItem::WhiteSpaceNoWrap );
1102 aTitle = aTitle.arg( title() );
1103 doc = new QTextDocument( aTitle );