1 // Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D
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.
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.
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
17 // See http://www.salome-platform.org/
19 // File: QtxColorScale.cxx
20 // Author: Sergey TELKOV
22 #include "QtxColorScale.h"
30 #include <qmainwindow.h>
31 #include <qstringlist.h>
32 #include <qstylesheet.h>
33 #include <qsimplerichtext.h>
40 QtxColorScale::QtxColorScale( QWidget* parent, const char* name, WFlags f )
41 : QFrame( parent, name, f | WResizeNoErase | WRepaintNoErase ),
54 myFlags( AtBorder | WrapTitle )
56 setCaption( tr ( "Color scale" ) );
62 QtxColorScale::QtxColorScale( const int num, QWidget* parent, const char* name, WFlags f )
63 : QFrame( parent, name, f | WResizeNoErase | WRepaintNoErase ),
76 myFlags( AtBorder | WrapTitle )
78 setCaption( tr ( "Color scale" ) );
86 QtxColorScale::QtxColorScale( Dock* dock, const char* name, WFlags f )
87 : QFrame( dock, name, f | WResizeNoErase | WRepaintNoErase ),
100 myFlags( AtBorder | WrapTitle )
102 setCaption( tr ( "Color scale" ) );
110 QtxColorScale::~QtxColorScale()
115 \returns minimal limit of scale.
117 double QtxColorScale::minimum() const
123 \return maximal limit of scale.
125 double QtxColorScale::maximum() const
131 \return range (minimal and maximal limits) of scale.
133 void QtxColorScale::range( double& min, double& max ) const
140 \return the current title string.
142 QString QtxColorScale::title() const
148 \returns the current format of number presentation in labels for Auto label mode (sprintf specification).
150 QString QtxColorScale::format() const
158 int QtxColorScale::dumpMode() const
166 int QtxColorScale::labelMode() const
174 int QtxColorScale::colorMode() const
180 \return intervals number of color scale.
182 int QtxColorScale::intervalsNumber() const
188 \return the user label of specified interval.
190 QString QtxColorScale::label( const int idx ) const
193 if ( idx >= 0 && idx < (int)myLabels.count() )
194 res = *myLabels.at( idx );
199 \return the user color of specified interval.
201 QColor QtxColorScale::color( const int idx ) const
204 if ( idx >= 0 && idx < (int)myColors.count() )
205 res = *myColors.at( idx );
210 \return the user labels.
212 void QtxColorScale::labels( QStringList& list ) const
218 \return the user color.
220 void QtxColorScale::colors( QValueList<QColor>& list ) const
226 \return the label position.
228 int QtxColorScale::labelPosition() const
234 \return the title position.
236 int QtxColorScale::titlePosition() const
242 Sets the minimum limit.
244 void QtxColorScale::setMinimum( const double val )
246 setRange( val, maximum() );
250 Sets the maximum limit.
252 void QtxColorScale::setMaximum( const double val )
254 setRange( minimum(), val );
258 Sets the minimum and maximum limits.
260 void QtxColorScale::setRange( const double min, const double max )
262 if ( myMin == min && myMax == max )
268 myPrecise = QString::null;
270 if ( colorMode() == Auto || labelMode() == Auto )
275 Sets the title string.
277 void QtxColorScale::setTitle( const QString& str )
279 if ( myTitle == str )
287 Sets the format of number presentation in labels for
288 Auto label mode (sprintf specification).
290 void QtxColorScale::setFormat( const QString& format )
292 if ( myFormat == format )
296 myPrecise = QString::null;
297 if ( colorMode() == Auto )
302 Sets the number of intervals.
304 void QtxColorScale::setIntervalsNumber( const int num )
306 if ( myInterval == num || num < 1 )
310 myPrecise = QString::null;
316 Sets the user label for specified interval. If number
317 of interval is negative then user label will be added
318 as new at the end of list.
320 void QtxColorScale::setLabel( const QString& txt, const int idx )
322 bool changed = false;
323 uint i = idx < 0 ? myLabels.count() : idx;
324 if ( i < myLabels.count() )
326 changed = *myLabels.at( i ) != txt;
332 while ( i >= myLabels.count() )
333 myLabels.append( "" );
341 Sets the user color for specified interval. If number
342 of interval is negative then user color will be added
343 as new at the end of list.
345 void QtxColorScale::setColor( const QColor& clr, const int idx )
347 bool changed = false;
348 uint i = idx < 0 ? myColors.count() : idx;
349 if ( i < myColors.count() )
351 changed = *myColors.at( i ) != clr;
357 while ( i >= myColors.count() )
358 myColors.append( QColor() );
366 Replace the all user label with specified list.
368 void QtxColorScale::setLabels( const QStringList& list )
370 if ( list.isEmpty() )
378 Replace the all user colors with specified list.
380 void QtxColorScale::setColors( const QValueList<QColor>& list )
382 if ( list.isEmpty() )
390 Sets the color mode (Auto or User).
392 void QtxColorScale::setColorMode( const int mode )
394 if ( myColorMode == mode )
404 void QtxColorScale::setDumpMode( const int mode )
410 Sets the label mode (Auto or User).
412 void QtxColorScale::setLabelMode( const int mode )
414 if ( myLabelMode != mode )
422 Sets the label position.
424 void QtxColorScale::setLabelPosition( const int pos )
426 if ( myLabelPos != pos && pos >= None && pos <= Center )
434 Sets the title position.
436 void QtxColorScale::setTitlePosition( const int pos )
438 if ( myTitlePos != pos && pos >= None && pos <= Center )
446 Set the specified flags.
448 void QtxColorScale::setFlags( const int flags )
452 if ( prev != myFlags )
457 \return true if specified flags are setted.
459 bool QtxColorScale::testFlags( const int flags ) const
461 return ( myFlags & flags ) == flags;
465 Clear (reset) the specified flags.
467 void QtxColorScale::clearFlags( const int flags )
471 if ( prev != myFlags )
476 \return minimum size hint
478 QSize QtxColorScale::minimumSizeHint() const
480 QSize sz = calculateSize( true, myFlags, titlePosition() != None, labelPosition() != None, true );
481 return sz + QSize( frameWidth(), frameWidth() );
487 QSize QtxColorScale::sizeHint() const
489 QSize sz = calculateSize( false, myFlags, titlePosition() != None, labelPosition() != None, true );
490 return sz + QSize( frameWidth(), frameWidth() );
494 Dump color scale into pixmap with current size.
496 QSize QtxColorScale::calculateSize( const bool min, const int flags, const bool title,
497 const bool labels, const bool colors ) const
499 int num = intervalsNumber();
503 int textHeight = fontMetrics().height();
506 if ( labels && colors )
508 QtxColorScale* that = (QtxColorScale*)this;
509 QString fmt = that->myFormat;
511 for ( int idx = 0; idx < num; idx++ )
512 textWidth = QMAX( textWidth, fontMetrics().width( getLabel( idx ) ) );
515 that->myFormat = that->myFormat.replace( QRegExp( "g" ), "f" );
517 for ( int index = 0; index < num; index++ )
518 textWidth = QMAX( textWidth, fontMetrics().width( getLabel( index ) ) );
520 that->myFormat = fmt;
529 if ( flags & AtBorder )
532 if ( min && title && !myTitle.isEmpty() )
538 scaleWidth = colorWidth + textWidth + ( textWidth ? 3 : 2 ) * spacer;
540 scaleHeight = QMAX( 2 * num, 3 * textHeight );
542 scaleHeight = (int)( 1.5 * ( num + 1 ) * textHeight );
547 QSimpleRichText* srt = simpleRichText( flags );
552 srt->setWidth( &p, scaleWidth );
554 titleHeight = srt->height() + spacer;
555 titleWidth = srt->widthUsed() + 10;
561 int W = QMAX( titleWidth, scaleWidth ) + width() - contentsRect().width();
562 int H = scaleHeight + titleHeight + height() - contentsRect().height();
564 return QSize( W, H );
568 Dump color scale into pixmap with current size.
570 QPixmap QtxColorScale::dump() const
574 if ( dumpMode() != NoDump )
576 aPix = QPixmap( size() );
577 if ( !aPix.isNull() )
579 bool scale = ( myDumpMode == ScaleDump || myDumpMode == FullDump );
580 bool label = ( myDumpMode == ScaleDump || myDumpMode == FullDump ) &&
581 labelPosition() != None;
582 bool title = ( myDumpMode == TitleDump || myDumpMode == FullDump ) &&
583 titlePosition() != None;
586 QColor bgc = backgroundColor();
588 QColor bgc = paletteBackgroundColor();
592 p.fillRect( 0, 0, aPix.width(), aPix.height(), bgc );
593 drawScale( &p, bgc, false, 0, 0, aPix.width(), aPix.height(), title, label, scale );
602 Dump color scale into pixmap with specified size.
604 QPixmap QtxColorScale::dump( const int w, const int h ) const
607 return dump( backgroundColor(), w, h );
609 return dump( paletteBackgroundColor(), w, h );
614 Dump color scale into pixmap with specified size and background color.
616 QPixmap QtxColorScale::dump( const QColor& bg, const int w, const int h ) const
619 if ( dumpMode() != NoDump )
621 bool scale = ( myDumpMode == ScaleDump || myDumpMode == FullDump );
622 bool label = ( myDumpMode == ScaleDump || myDumpMode == FullDump ) &&
623 labelPosition() != None;
624 bool title = ( myDumpMode == TitleDump || myDumpMode == FullDump ) &&
625 titlePosition() != None;
629 if ( W < 0 || H < 0 )
631 QSize sz = calculateSize( false, myFlags & ~WrapTitle, title, label, scale );
639 aPix = QPixmap( W, H );
640 if ( !aPix.isNull() )
644 p.fillRect( 0, 0, aPix.width(), aPix.height(), bg );
645 drawScale( &p, bg, false, 0, 0, aPix.width(), aPix.height(), title, label, scale );
654 Show the color scale. [Reimplemented]
656 void QtxColorScale::show()
667 Hides the color scale. [Reimplemented]
669 void QtxColorScale::hide()
673 myDock->deactivate();
680 Draw color scale contents. [Reimplemented]
682 void QtxColorScale::drawContents( QPainter* p )
684 if ( !isUpdatesEnabled() )
687 QRect aDrawRect = contentsRect();
689 drawScale( p, false/*testFlags( Transparent )*/, aDrawRect.x(),
690 aDrawRect.y(), aDrawRect.width(), aDrawRect.height(),
691 titlePosition() != None, labelPosition() != None, true );
695 Draw color scale contents.
697 void QtxColorScale::drawScale( QPainter* p, const bool transp, const int X, const int Y,
698 const int W, const int H, const bool title,
699 const bool label, const bool scale ) const
701 QPixmap cache( W, H );
702 QPainter cp( &cache );
705 drawScale( &cp, backgroundColor(), transp, 0, 0, W, H, title, label, scale );
707 drawScale( &cp, paletteBackgroundColor(), transp, 0, 0, W, H, title, label, scale );
711 p->drawPixmap( X, Y, cache );
715 Draw color scale contents.
717 void QtxColorScale::drawScale( QPainter* p, const QColor& bg, const bool transp,
718 const int X, const int Y, const int W, const int H,
719 const bool drawTitle, const bool drawLabel, const bool drawColors ) const
722 p->fillRect( X, Y, W, H, bg );
724 int num = intervalsNumber();
726 int labPos = labelPosition();
730 int textHeight = p->fontMetrics().height();
732 QString aTitle = title();
737 if ( qGray( bg.rgb() ) < 128 )
738 p->setPen( QColor( 255, 255, 255 ) );
740 p->setPen( QColor( 0, 0, 0 ) );
745 QSimpleRichText* srt = simpleRichText( myFlags );
748 srt->setWidth( p, W - 10 );
749 titleHeight = srt->height() + spacer;
750 titleWidth = srt->widthUsed();
751 QColorGroup cg = colorGroup();
752 cg.setColor( QColorGroup::Text, p->pen().color() );
753 srt->draw( p, X + 5, Y, QRect( 0, 0, srt->width(), srt->height() ), cg );
759 bool reverse = testFlags( Reverse );
761 QValueList<QColor> colors;
762 QValueList<QString> labels;
763 for ( int idx = 0; idx < num; idx++ )
767 colors.append( getColor( idx ) );
768 labels.append( getLabel( idx ) );
772 colors.prepend( getColor( idx ) );
773 labels.prepend( getLabel( idx ) );
777 if ( testFlags( AtBorder ) )
780 labels.append( getLabel( num ) );
782 labels.prepend( getLabel( num ) );
784 textWidth = QMAX( textWidth, p->fontMetrics().width( labels.last() ) );
789 const QFontMetrics& fm = p->fontMetrics();
790 for ( QStringList::ConstIterator it = labels.begin(); it != labels.end(); ++it )
791 textWidth = QMAX( textWidth, fm.width( *it) );
794 int lab = labels.count();
796 double spc = ( H - ( ( QMIN( lab, 2 ) + QABS( lab - num - 1 ) ) * textHeight ) - titleHeight );
797 double val = spc != 0 ? 1.0 * ( lab - QMIN( lab, 2 ) ) * textHeight / spc : 0;
799 double fPart = modf( val, &iPart );
800 int filter = (int)iPart + ( fPart != 0 ? 1 : 0 );
801 filter = QMAX( filter, 1 );
803 double step = 1.0 * ( H - ( lab - num + QABS( lab - num - 1 ) ) * textHeight - titleHeight ) / num;
805 int ascent = p->fontMetrics().ascent();
806 int colorWidth = QMAX( 5, QMIN( 20, W - textWidth - 3 * spacer ) );
807 if ( labPos == Center || !drawLabel )
808 colorWidth = W - 2 * spacer;
815 x += textWidth + ( textWidth ? 1 : 0 ) * spacer;
819 double offset = 1.0 * textHeight / 2 * ( lab - num + QABS( lab - num - 1 ) ) + titleHeight;
820 QValueList<QColor>::Iterator cit = colors.begin();
822 for ( ci = 0; cit != colors.end() && drawColors; ++cit, ci++ )
824 int y = (int)( Y + ci * step + offset );
825 int h = (int)( Y + ( ci + 1 ) * step + offset ) - y;
826 p->fillRect( x, y, colorWidth, h, *cit );
830 p->drawRect( int( x - 1 ), int( Y + offset - 1 ), int( colorWidth + 2 ), int( ci * step + 2 ) );
833 offset = 1.0 * QABS( lab - num - 1 ) * ( step - textHeight ) / 2 +
834 1.0 * QABS( lab - num - 1 ) * textHeight / 2;
835 offset += titleHeight;
836 if ( drawLabel && !labels.isEmpty() )
840 int last1( i1 ), last2( i2 );
845 x += ( colorWidth - textWidth ) / 2;
848 x += colorWidth + spacer;
851 while ( i2 - i1 >= filter || ( i2 == 0 && i1 == 0 ) )
854 int pos2 = lab - 1 - i2;
855 if ( filter && !( pos1 % filter ) )
857 p->drawText( x, (int)( Y + i1 * step + ascent + offset ), *labels.at( i1 ) );
860 if ( filter && !( pos2 % filter ) )
862 p->drawText( x, (int)( Y + i2 * step + ascent + offset ), *labels.at( i2 ) );
870 while ( pos <= i2 && i0 == -1 )
872 if ( filter && !( pos % filter ) &&
873 QABS( pos - last1 ) >= filter && QABS( pos - last2 ) >= filter )
879 p->drawText( x, (int)( Y + i0 * step + ascent + offset ), *labels.at( i0 ) );
884 \return the format for number labels.
886 QString QtxColorScale::getFormat() const
888 QString aFormat = format();
890 if ( !testFlags( PreciseFormat ) || testFlags( Integer ) )
893 if ( !myPrecise.isEmpty() )
896 if ( aFormat.find( QRegExp( "^(%[0-9]*.?[0-9]*[fegFEG])$" ) ) != 0 )
899 int pos1 = aFormat.find( '.' );
900 int pos2 = aFormat.find( QRegExp( "[fegFEG]") );
906 aLocFormat = aFormat.mid( 0, pos1 + 1 );
907 precision = aFormat.mid( pos1 + 1, pos2 - pos1 - 1 ).toInt();
914 QtxColorScale* that = (QtxColorScale*)this;
916 // calculate format, maximum precision limited
917 // to 7 digits after the decimal point.
918 while ( myPrecise.isEmpty() && precision < 7 )
920 QString aTmpFormat = aLocFormat;
921 aTmpFormat += QString( "%1" ).arg( precision );
922 aTmpFormat += aFormat.mid( pos2 );
924 QMap<QString, int> map;
925 bool isHasTwinz = false;
927 for ( int idx = 0; idx < intervalsNumber() && !isHasTwinz; idx++ )
929 double val = getNumber( idx );
930 QString tmpname = QString().sprintf( aTmpFormat, val );
931 isHasTwinz = map.contains( tmpname );
932 map.insert( tmpname, 1 );
936 that->myPrecise = aTmpFormat;
940 if ( !myPrecise.isEmpty() )
947 \return the number for specified interval.
949 double QtxColorScale::getNumber( const int idx ) const
952 if ( intervalsNumber() > 0 )
953 val = minimum() + idx * ( QABS( maximum() - minimum() ) / intervalsNumber() );
958 \return the label for specified interval according to the current label mode.
960 QString QtxColorScale::getLabel( const int idx ) const
963 if ( labelMode() == User )
967 double val = getNumber( idx );
968 res = QString().sprintf( getFormat(), testFlags( Integer ) ? (int)val : val );
974 \return the color for specified interval according to the current color mode.
976 QColor QtxColorScale::getColor( const int idx ) const
979 if ( colorMode() == User )
982 res = Qtx::scaleColor( idx, 0, intervalsNumber() - 1 );
987 Update color scale if it required.
989 void QtxColorScale::updateScale()
996 \return QSimpleRichText object for title. If title
997 not defined (empty string) then return null pointer.
998 Object should be deleted by caller function.
1000 QSimpleRichText* QtxColorScale::simpleRichText( const int flags ) const
1002 QSimpleRichText* srt = 0;
1005 switch ( titlePosition() )
1008 aTitle = QString( "<p align=\"left\">%1</p>" );
1011 aTitle = QString( "<p align=\"right\">%1</p>" );
1014 aTitle = QString( "<p align=\"center\">%1</p>" );
1021 if ( !aTitle.isEmpty() && !title().isEmpty() )
1023 if ( !myStyleSheet )
1025 QtxColorScale* that = (QtxColorScale*)this;
1026 that->myStyleSheet = new QStyleSheet( that );
1031 QStyleSheetItem* item = myStyleSheet->item( "p" );
1033 item->setWhiteSpaceMode( flags & WrapTitle ? QStyleSheetItem::WhiteSpaceNormal :
1034 QStyleSheetItem::WhiteSpaceNoWrap );
1037 aTitle = aTitle.arg( title() );
1038 srt = new QSimpleRichText( aTitle, font(), QString::null, myStyleSheet );
1047 \class QtxColorScale::Dock
1048 Dockable window contains the color scale.
1054 QtxColorScale::Dock::Dock( Place p, QWidget* parent, const char* name, WFlags f )
1055 : QDockWindow( p, parent, name, f ),
1056 myBlockShow( false ),
1057 myBlockResize( false )
1059 myScale = new QtxColorScale( this );
1061 setWidget( myScale );
1063 setCloseMode( Always );
1064 setMovingEnabled( true );
1065 setResizeEnabled( true );
1066 setHorizontalStretchable( false );
1068 setCaption( tr ( "Color scale" ) );
1074 QtxColorScale::Dock::~Dock()
1079 \return color scale widget.
1081 QtxColorScale* QtxColorScale::Dock::colorScale() const
1087 Set the dockable window is visible for main window.
1089 void QtxColorScale::Dock::activate()
1094 QMainWindow* mw = 0;
1095 QWidget* p = parentWidget();
1098 if ( p->inherits( "QMainWindow" ) )
1099 mw = (QMainWindow*)p;
1100 p = p->parentWidget();
1103 mw->setAppropriate( this, true );
1107 Set the dockable window is hidden for main window.
1109 void QtxColorScale::Dock::deactivate()
1114 QMainWindow* mw = 0;
1115 QWidget* p = parentWidget();
1118 if ( p->inherits( "QMainWindow" ) )
1119 mw = (QMainWindow*)p;
1120 p = p->parentWidget();
1123 mw->setAppropriate( this, false );
1127 \return true if the dockable window is visible.
1129 bool QtxColorScale::Dock::isActive() const
1131 QMainWindow* mw = 0;
1132 QWidget* p = parentWidget();
1135 if ( p->inherits( "QMainWindow" ) )
1136 mw = (QMainWindow*)p;
1137 p = p->parentWidget();
1140 return mw->appropriate( (QDockWindow*)this );
1148 void QtxColorScale::Dock::show()
1150 bool f = myBlockShow;
1152 QDockWindow::show();
1159 void QtxColorScale::Dock::hide()
1161 bool f = myBlockShow;
1162 myBlockShow = false;
1163 QDockWindow::hide();
1168 Make extent width as maximum value of widget width.
1170 void QtxColorScale::Dock::resize( int w, int h )
1172 QDockWindow::resize( w, h );
1174 if ( myBlockResize )
1177 if ( orientation() == Qt::Vertical )
1178 setFixedExtentWidth( QMAX( fixedExtent().width(), w ) );
1179 else if ( orientation() == Qt::Horizontal )
1180 setFixedExtentHeight( QMAX( fixedExtent().height(), h ) );
1185 \param o - new orientation
1187 void QtxColorScale::Dock::setOrientation( Orientation o )
1189 bool b = myBlockResize;
1190 myBlockResize = true;
1191 QDockWindow::setOrientation( o );