1 // Copyright (C) 2007-2013 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.
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
22 // File : Plot2d_PlotItems.cxx
23 // Author : Natalia ERMOLAEVA, Open CASCADE S.A.S. (natalia.donis@opencascade.com)
25 #include "Plot2d_PlotItems.h"
26 #include "Plot2d_Object.h"
34 #include <qwt_painter.h>
35 #include <qwt_scale_map.h>
36 #include <qwt_legend.h>
37 #include <qwt_legend_item.h>
38 #include <qwt_plot_dict.h>
40 const char* yAxisLeft[] = {
57 const char* yAxisRight[] = {
75 Constructor of Plot2d_QwtLegendItem
77 Plot2d_QwtLegendItem::Plot2d_QwtLegendItem( QWidget* parent ) :
78 QwtLegendItem( parent ),
79 myYAxisIdentifierMode( IM_None ),
82 myYAxisLeftIcon = yAxisLeft;
83 myYAxisRightIcon = yAxisRight;
84 int anIconWidth = qMax( myYAxisLeftIcon.width(), myYAxisRightIcon.width() );
86 mySpacingCollapsed = spacing();
87 mySpacingExpanded = anIconWidth - mySpacingCollapsed;
91 Destructor of Plot2d_QwtLegendItem
93 Plot2d_QwtLegendItem::~Plot2d_QwtLegendItem()
98 Set Y axis identifier displaying mode
100 void Plot2d_QwtLegendItem::setYAxisIdentifierMode( const int theMode )
102 myYAxisIdentifierMode = theMode;
103 setSpacing( theMode == IM_None ? mySpacingCollapsed : mySpacingExpanded );
107 Redefined method of drawing identifier of legend item
109 void Plot2d_QwtLegendItem::drawIdentifier( QPainter* painter, const QRect& rect ) const
111 QwtLegendItem::drawIdentifier( painter, rect );
113 if( myYAxisIdentifierMode != IM_None ) {
114 QPixmap aPixmap( myYAxisIdentifierMode == IM_Left ? yAxisLeft : yAxisRight );
116 painter->drawPixmap( rect.topRight() + QPoint( mySpacingExpanded/2, mySpacingExpanded/2 ), aPixmap );
122 Update highliting on the item.
124 void Plot2d_QwtLegendItem::updateHighlit() {
125 QwtText txt = text();
127 QColor highlightColor = Plot2d_Object::selectionColor();
128 if(highlightColor != txt.backgroundBrush().color()) {
129 txt.setBackgroundBrush(highlightColor);
132 } else if( QWidget* parent = qobject_cast<QWidget*>(this->parent()->parent()) ) {
133 QPalette aPal = parent->palette();
134 if(aPal.color(QPalette::Background) != txt.backgroundBrush().color()) {
135 txt.setBackgroundBrush(aPal.color(QPalette::Background));
142 Sets selected property.
144 void Plot2d_QwtLegendItem::setSelected(const bool on) {
149 Gets selected property.
151 bool Plot2d_QwtLegendItem::isSelected() const {
157 Draw text of the item.
159 void Plot2d_QwtLegendItem::drawText(QPainter * painter, const QRect &rect) {
160 painter->setPen( isSelected() ? Plot2d_Object::highlightedLegendTextColor() :
161 getColorFromPalette( QPalette::Text) );
163 QwtLegendItem::drawText( painter, rect );
167 Get color from the legend pallete by 'role' flag.
169 QColor Plot2d_QwtLegendItem::getColorFromPalette(QPalette::ColorRole role) {
170 QWidget* pw = parentWidget();
171 QColor col = palette().color( role );
173 if ( qobject_cast<QwtLegend*>( pw ) ) {
174 col = pw->palette().color(role );
177 pw = pw->parentWidget();
182 * Internal class to store deviation data on the curve.
184 class Plot2d_QwtPlotCurve::Plot2d_DeviationData {
186 Plot2d_DeviationData(const double *min, const double *max,const QList<int>& idx)
188 foreach(int index,idx) {
189 myMin[index] = min[index];
190 myMax[index] = max[index];
193 ~Plot2d_DeviationData(){}
197 return qwtMin(myMin.size(), myMax.size());
199 bool values(size_t i, double &min, double &max) {
200 if(myMin.contains(i) && myMax.contains(i)) {
208 QMap<int,double> myMin;
209 QMap<int,double> myMax;
214 Constructor of Plot2d_QwtPlotCurve
216 Plot2d_QwtPlotCurve::Plot2d_QwtPlotCurve( const QString& title,
217 QwtPlot::Axis yAxis /*const int index*/ ) :
218 Plot2d_SelectableItem(),
219 QwtPlotCurve( title ),
221 myYAxisIdentifierEnabled( false ),
227 Destructor of Plot2d_QwtPlotCurve
229 Plot2d_QwtPlotCurve::~Plot2d_QwtPlotCurve()
231 clearDeviationData();
235 Enable / disable Y axis identifier
237 void Plot2d_QwtPlotCurve::setYAxisIdentifierEnabled( const bool on )
239 myYAxisIdentifierEnabled = on;
243 Redefined method, which updates legend of the curve
245 void Plot2d_QwtPlotCurve::updateLegend( QwtLegend* legend ) const
250 QWidget* widget = legend->find( this );
252 if ( testItemAttribute(QwtPlotItem::Legend) ) {
254 if ( widget == NULL ) {
255 widget = legendItem();
257 if ( widget->inherits("QwtLegendItem") ) {
258 QwtLegendItem *label = (QwtLegendItem *)widget;
259 label->setItemMode(legend->itemMode());
262 QObject::connect(label, SIGNAL(clicked()),
263 plot(), SLOT(legendItemClicked()));
264 QObject::connect(label, SIGNAL(checked(bool)),
265 plot(), SLOT(legendItemChecked(bool)));
268 legend->contentsWidget()->layout()->addWidget(widget);
269 legend->insert(this, widget);
273 QwtPlotCurve::updateLegend( legend );
276 if( Plot2d_QwtLegendItem* anItem = dynamic_cast<Plot2d_QwtLegendItem*>( widget ) ) {
277 int aMode = Plot2d_QwtLegendItem::IM_None;
278 if( myYAxisIdentifierEnabled )
279 aMode = myYAxis == QwtPlot::yRight ?
280 Plot2d_QwtLegendItem::IM_Right :
281 Plot2d_QwtLegendItem::IM_Left;
282 anItem->setYAxisIdentifierMode( aMode );
284 anItem->setCurvePen(legendPen());
285 anItem->setSymbol(legendSymbol());
287 anItem->setSelected(isSelected());
288 anItem->updateHighlit();
294 Redefined method, which creates and returns legend item of the curve
296 QWidget* Plot2d_QwtPlotCurve::legendItem() const
298 return new Plot2d_QwtLegendItem;
302 Redefined method, which draw a set of points of a curve.
304 void Plot2d_QwtPlotCurve::draw(QPainter *painter,
305 const QwtScaleMap &xMap, const QwtScaleMap &yMap,
306 int from, int to) const
310 QwtPlotCurve::draw(painter, xMap, yMap, from, to);
312 //draw deviation data
313 if(hasDeviationData()) {
315 int lineW = deviationMarkerLineWidth();
316 int tickSz = deviationMarkerTickSize() + qRound(lineW/2);
317 double min, max, xi, yi;
318 int xp, ytop, ybtm, tickl, tickr;
319 QColor c = isSelected() ? Plot2d_Object::selectionColor() : deviationMarkerColor();
320 QPen p = QPen(c, lineW, Qt::SolidLine);
322 for (int i = from; i <= to; i++) {
323 if(!myDeviationData->values(i,min,max)) continue;
326 xp = xMap.transform(xi);
327 ytop = yMap.transform(yi + max);
328 ybtm = yMap.transform(yi - min);
331 painter->drawLine(tickl,ytop,tickr,ytop);
332 painter->drawLine(xp,ytop,xp,ybtm);
333 painter->drawLine(tickl,ybtm,tickr,ybtm);
340 * Return color of the deviation marker.
342 QColor Plot2d_QwtPlotCurve::deviationMarkerColor() const {
345 QVariant var = plot()->property(PLOT2D_DEVIATION_COLOR);
347 c = var.value<QColor>();
352 * Return line width of the deviation marker.
354 int Plot2d_QwtPlotCurve::deviationMarkerLineWidth() const {
357 QVariant var = plot()->property(PLOT2D_DEVIATION_LW);
365 * Return tick size of the deviation marker.
367 int Plot2d_QwtPlotCurve::deviationMarkerTickSize() const {
370 QVariant var = plot()->property(PLOT2D_DEVIATION_TS);
378 * Sets deviation data for the plot item.
380 void Plot2d_QwtPlotCurve::setDeviationData(const double* min, const double* max,const QList<int> &idx) {
381 clearDeviationData();
382 myDeviationData = new Plot2d_DeviationData(min,max,idx);
386 * Return true if deviation is assigned to the plot item,
389 bool Plot2d_QwtPlotCurve::hasDeviationData() const {
390 return myDeviationData != 0;
394 * Remove deviation data from the plot item.
396 void Plot2d_QwtPlotCurve::clearDeviationData()
399 delete myDeviationData;
408 Plot2d_SelectableItem::Plot2d_SelectableItem():
416 Plot2d_SelectableItem::~Plot2d_SelectableItem()
421 Sets selected property.
423 void Plot2d_SelectableItem::setSelected( const bool on) {
428 Return selected property.
430 bool Plot2d_SelectableItem::isSelected() const {
435 Sets legend pen property.
437 void Plot2d_SelectableItem::setLegendPen( const QPen & p) {
442 Return legend pen property.
444 QPen Plot2d_SelectableItem::legendPen() const {
449 Sets legend symbol property.
451 void Plot2d_SelectableItem::setLegendSymbol(const QwtSymbol& s) {
456 Sets legend symbol property.
458 QwtSymbol Plot2d_SelectableItem::legendSymbol() const {
459 return myLegendSymbol;
465 Plot2d_HistogramQwtItem::Plot2d_HistogramQwtItem( const QwtText& theTitle )
466 : QwtPlotItem( theTitle )
474 Plot2d_HistogramQwtItem::Plot2d_HistogramQwtItem( const QString& theTitle )
475 : QwtPlotItem( QwtText( theTitle ) )
483 Plot2d_HistogramQwtItem::~Plot2d_HistogramQwtItem()
488 Initialization of object
490 void Plot2d_HistogramQwtItem::init()
493 myAttributes = Plot2d_HistogramQwtItem::Auto;
495 setItemAttribute( QwtPlotItem::AutoScale, true );
496 setItemAttribute( QwtPlotItem::Legend, true );
502 Sets base line to object
505 void Plot2d_HistogramQwtItem::setBaseline( double theRef )
507 if ( myReference != theRef ) {
508 myReference = theRef;
514 Returns base line of object
516 double Plot2d_HistogramQwtItem::baseline() const
524 void Plot2d_HistogramQwtItem::setData( const QwtIntervalData& theData )
531 Returns data from object
533 const QwtIntervalData& Plot2d_HistogramQwtItem::data() const
541 void Plot2d_HistogramQwtItem::setColor( const QColor& theColor )
543 if ( myColor != theColor ) {
550 Returns color from object
552 QColor Plot2d_HistogramQwtItem::color() const
558 Returns bounding rect of object
560 QwtDoubleRect Plot2d_HistogramQwtItem::boundingRect() const
562 QwtDoubleRect aRect = myData.boundingRect();
563 if ( !aRect.isValid() )
566 if ( myAttributes & Xfy ) {
567 aRect = QwtDoubleRect( aRect.y(), aRect.x(),
568 aRect.height(), aRect.width() );
569 if ( aRect.left() > myReference )
570 aRect.setLeft( myReference );
571 else if ( aRect.right() < myReference )
572 aRect.setRight( myReference );
575 if ( aRect.bottom() < myReference )
576 aRect.setBottom( myReference );
577 else if ( aRect.top() > myReference )
578 aRect.setTop( myReference );
584 Returns type of plot object
586 int Plot2d_HistogramQwtItem::rtti() const
588 return QwtPlotItem::Rtti_PlotHistogram;
592 Sets histogram attributes
594 void Plot2d_HistogramQwtItem::setHistogramAttribute( HistogramAttribute theAttr,
597 if ( testHistogramAttribute( theAttr ) != isOn ) {
599 myAttributes |= theAttr;
601 myAttributes &= ~theAttr;
608 Tests histogram attributes
610 bool Plot2d_HistogramQwtItem::testHistogramAttribute( HistogramAttribute theAttr ) const
612 return myAttributes & theAttr;
616 Draws histogram object
618 void Plot2d_HistogramQwtItem::draw( QPainter* thePainter,
619 const QwtScaleMap& theXMap,
620 const QwtScaleMap& theYMap,
623 thePainter->setPen( QPen( myColor ) );
625 const int x0 = theXMap.transform( baseline() );
626 const int y0 = theYMap.transform( baseline() );
628 for ( int i = 0; i < (int)myData.size(); i++ ) {
629 if ( myAttributes & Plot2d_HistogramQwtItem::Xfy ) {
630 const int x2 = theXMap.transform( myData.value( i ) );
633 int y1 = theYMap.transform( myData.interval( i ).minValue() );
634 int y2 = theYMap.transform( myData.interval( i ).maxValue() );
638 if ( i < (int)myData.size() - 2 ) {
639 const int yy1 = theYMap.transform( myData.interval(i+1).minValue() );
640 const int yy2 = theYMap.transform( myData.interval(i+1).maxValue() );
641 if ( y2 == qwtMin( yy1, yy2 ) ) {
642 const int xx2 = theXMap.transform( myData.interval(i+1).minValue() );
643 if ( xx2 != x0 && ( ( xx2 < x0 && x2 < x0 ) ||
644 ( xx2 > x0 && x2 > x0 ) ) ) {
645 // One pixel distance between neighboured bars
650 drawBar( thePainter, Qt::Horizontal, QRect( x0, y1, x2 - x0, y2 - y1 ) );
653 const int y2 = theYMap.transform( myData.value( i ) );
656 int x1 = theXMap.transform( myData.interval( i ).minValue() );
657 int x2 = theXMap.transform( myData.interval( i ).maxValue() );
661 if ( i < (int)myData.size() - 2 ) {
662 const int xx1 = theXMap.transform( myData.interval(i+1).minValue() );
663 const int xx2 = theXMap.transform( myData.interval(i+1).maxValue() );
664 if ( x2 == qwtMin( xx1, xx2 ) ) {
665 const int yy2 = theYMap.transform( myData.value(i+1) );
666 if ( yy2 != y0 && ( ( yy2 < y0 && y2 < y0 ) ||
667 ( yy2 > y0 && y2 > y0 ) ) ) {
668 // One pixel distance between neighboured bars
673 drawBar( thePainter, Qt::Vertical, QRect( x1, y0, x2 - x1, y2 - y0 ) );
679 Draws single bar of histogram
681 void Plot2d_HistogramQwtItem::drawBar( QPainter* thePainter,
683 const QRect& theRect ) const
687 const QColor color( thePainter->pen().color() );
688 QRect r = theRect.normalized();
690 const int factor = 125;
691 const QColor light( color.light( factor ) );
692 const QColor dark( color.dark( factor ) );
694 thePainter->setBrush( color );
695 thePainter->setPen( Qt::NoPen );
696 QwtPainter::drawRect( thePainter, r.x() + 1, r.y() + 1,
697 r.width() - 2, r.height() - 2 );
698 thePainter->setBrush( Qt::NoBrush );
700 thePainter->setPen( QPen( light, 2 ) );
701 QwtPainter::drawLine( thePainter, r.left() + 1, r.top() + 2,
702 r.right() + 1, r.top() + 2 );
704 thePainter->setPen( QPen( dark, 2 ) );
705 QwtPainter::drawLine( thePainter, r.left() + 1, r.bottom(),
706 r.right() + 1, r.bottom() );
707 thePainter->setPen( QPen( light, 1 ) );
709 QwtPainter::drawLine( thePainter, r.left(), r.top() + 1,
710 r.left(), r.bottom() );
711 QwtPainter::drawLine( thePainter, r.left() + 1, r.top() + 2,
712 r.left() + 1, r.bottom() - 1 );
713 thePainter->setPen( QPen( dark, 1 ) );
715 QwtPainter::drawLine( thePainter, r.right() + 1, r.top() + 1,
716 r.right() + 1, r.bottom() );
717 QwtPainter::drawLine(thePainter, r.right(), r.top() + 2,
718 r.right(), r.bottom() - 1 );
719 thePainter->restore();
725 Plot2d_HistogramItem::Plot2d_HistogramItem( const QwtText& theTitle )
726 : Plot2d_HistogramQwtItem( theTitle ),
727 Plot2d_SelectableItem(),
735 Plot2d_HistogramItem::Plot2d_HistogramItem( const QString& theTitle )
736 : Plot2d_HistogramQwtItem( theTitle ),
744 Plot2d_HistogramItem::~Plot2d_HistogramItem()
749 Get histogram bar items
751 QList<QRect> Plot2d_HistogramItem::getBars() const
757 Set to legend item symbol with color of item
759 void Plot2d_HistogramItem::updateLegend( QwtLegend* theLegend ) const
764 Plot2d_HistogramQwtItem::updateLegend( theLegend );
766 QWidget* theWidget = theLegend->find( this );
767 if ( !theWidget || !theWidget->inherits( "QwtLegendItem" ) )
770 Plot2d_QwtLegendItem* anItem = ( Plot2d_QwtLegendItem* )theWidget;
771 QFontMetrics aFMetrics( anItem->font() );
772 int aSize = aFMetrics.height();
773 QwtSymbol aSymbol( QwtSymbol::Rect, QBrush( legendPen().color() ),
774 QPen( legendPen().color() ), QSize( aSize, aSize ) );
775 anItem->setSymbol( aSymbol );
776 anItem->setIdentifierMode( theLegend->identifierMode()
777 | QwtLegendItem::ShowSymbol );
778 anItem->setSelected(isSelected());
779 anItem->updateHighlit();
784 Draws histogram object
786 void Plot2d_HistogramItem::draw( QPainter* thePainter,
787 const QwtScaleMap& theXMap,
788 const QwtScaleMap& theYMap,
791 // nds: clear list of bar items
792 Plot2d_HistogramItem* anItem = (Plot2d_HistogramItem*)this;
793 anItem->myBarItems.clear();
795 thePainter->setPen( QPen( color() ) );
796 const int x0 = theXMap.transform( baseline() );
797 const int y0 = theYMap.transform( baseline() );
799 const QwtIntervalData& iData = data();
801 for ( int i = 0; i < (int)iData.size(); i++ ) {
802 if ( testHistogramAttribute( Plot2d_HistogramItem::Xfy ) ) {
803 const int x2 = theXMap.transform( iData.value( i ) );
806 int y1 = theYMap.transform( iData.interval( i ).minValue() );
807 int y2 = theYMap.transform( iData.interval( i ).maxValue() );
811 if ( i < (int)iData.size() - 2 ) {
812 const int yy1 = theYMap.transform( iData.interval(i+1).minValue() );
813 const int yy2 = theYMap.transform( iData.interval(i+1).maxValue() );
814 if ( y2 == qwtMin( yy1, yy2 ) ) {
815 const int xx2 = theXMap.transform( iData.interval(i+1).minValue() );
816 if ( xx2 != x0 && ( ( xx2 < x0 && x2 < x0 ) ||
817 ( xx2 > x0 && x2 > x0 ) ) ) {
818 // One pixel distance between neighboured bars
823 // nds: draw rect with the other lower rects
824 QRect aRect( x0, y1, x2 - x0, y2 - y1 );
825 drawRectAndLowers( thePainter, Qt::Horizontal, aRect );
826 anItem->myBarItems.append( aRect );
829 const int y2 = theYMap.transform( iData.value( i ) );
832 int x1 = theXMap.transform( iData.interval( i ).minValue() );
833 int x2 = theXMap.transform( iData.interval( i ).maxValue() );
837 if ( i < (int)iData.size() - 2 ) {
838 const int xx1 = theXMap.transform( iData.interval(i+1).minValue() );
839 const int xx2 = theXMap.transform( iData.interval(i+1).maxValue() );
840 if ( x2 == qwtMin( xx1, xx2 ) ) {
841 const int yy2 = theYMap.transform( iData.value(i+1) );
842 if ( yy2 != y0 && ( ( yy2 < y0 && y2 < y0 ) ||
843 ( yy2 > y0 && y2 > y0 ) ) ) {
844 // One pixel distance between neighboured bars
849 // nds: draw rect with the other lower rects
850 QRect aRect(x1, y0, x2 - x1, y2 - y0 );
851 drawRectAndLowers( thePainter, Qt::Vertical, aRect );
852 anItem->myBarItems.append( aRect );
858 Set/clear "cross items" option
860 void Plot2d_HistogramItem::setCrossItems( bool theCross )
862 myCrossed = theCross;
866 Get "cross items" option
868 bool Plot2d_HistogramItem::isCrossItems() const
874 Redefined method, which creates and returns legend item of the curve
876 QWidget* Plot2d_HistogramItem::legendItem() const
878 return new Plot2d_QwtLegendItem;
883 Draws bar of histogram and on it bars of histograms with lower height.
885 void Plot2d_HistogramItem::drawRectAndLowers( QPainter* thePainter,
886 Qt::Orientation theOr,
887 const QRect& theRect ) const
889 QRect aRect = theRect;
890 // theRect has inversed coordinates on Y axis.
891 // The top of the rect is bottom in standard QRect coordinates,
892 // and it bottom is the top.
893 if ( myCrossed )//&& theOr == Qt::Horizontal )
894 aRect.setTop( getCrossedTop( theRect ) );
896 drawBar( thePainter, Qt::Horizontal, aRect );
900 Returns top value of the given rect in the context of other bars.
902 It's necessary to remember, that \a theRect has inverted coordinate Y.
904 int Plot2d_HistogramItem::getCrossedTop( const QRect& theRect ) const
906 int aRes = theRect.top();
907 QwtPlot* aPlot = plot();
908 // int aHeight = theRect.height();
910 QwtPlotItemList anItems = aPlot->itemList();
911 QwtPlotItemIterator anIt = anItems.begin(), aLast = anItems.end();
912 Plot2d_HistogramItem* anItem;
914 for ( ; anIt != aLast; anIt++ ) {
915 if ( !((*anIt)->rtti() == QwtPlotItem::Rtti_PlotHistogram) )
917 anItem = dynamic_cast<Plot2d_HistogramItem*>( *anIt );
918 if( !anItem || anItem == this )
921 aRects = anItem->getBars();
922 for ( int i = 0, aSize = aRects.size(); i < aSize; i++ ) {
923 if ( qMax( theRect.x(), aRects[i].x() ) <=
924 qMin( theRect.left(), aRects[i].left() ) ) {
925 if ( theRect.bottom() < aRects[i].bottom() )
926 if ( aRects[i].bottom() < aRes )
927 aRes = aRects[i].bottom();