Salome HOME
Merge branch 'V9_2_2_BR'
[modules/gui.git] / src / Plot2d / Plot2d_PlotItems.cxx
1 // Copyright (C) 2007-2019  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 //  File   : Plot2d_PlotItems.cxx
23 //  Author : Natalia ERMOLAEVA, Open CASCADE S.A.S. (natalia.donis@opencascade.com)
24
25 #include "Plot2d_PlotItems.h"
26 #include "Plot2d_Object.h"
27 #include "Plot2d_ViewFrame.h"
28
29 #include <QPainter>
30 #include <QPalette>
31 #include <QLayout>
32 #include <QLine>
33 #include <QVariant>
34 #include <QStyleOption>
35 #include <QPaintEvent>
36 #include <QTileRules>
37
38 #include <qwt_plot.h>
39 #include <qwt_painter.h>
40 #include <qwt_scale_map.h>
41 #include <qwt_legend.h>
42 #include <qwt_legend_label.h>
43 #include <qwt_plot_dict.h>
44
45 const int SPACING = 10;
46 const int SYMBOL_SIZE = 13;
47
48 const char* yAxisLeft[] = {
49   "12 12 2 1",
50   "  c None",
51   ". c #000000",
52   "            ",
53   "   .        ",
54   "  ...       ",
55   " . . .      ",
56   "   .        ",
57   "   .        ",
58   "   .    .   ",
59   "   .     .  ",
60   "   ........ ",
61   "         .  ",
62   "        .   ",
63   "            "};
64
65 const char* yAxisRight[] = {
66   "12 12 2 1",
67   "  c None",
68   ". c #000000",
69   "            ",
70   "        .   ",
71   "       ...  ",
72   "      . . . ",
73   "        .   ",
74   "        .   ",
75   "   .    .   ",
76   "  .     .   ",
77   " ........   ",
78   "  .         ",
79   "   .        ",
80   "            "};
81
82 /*!
83   Constructor of Plot2d_QwtLegendLabel
84 */
85 Plot2d_QwtLegendLabel::Plot2d_QwtLegendLabel( QWidget* parent ) :
86   QwtLegendLabel( parent ),
87   myYAxisIdentifierMode( IM_None ),
88   myIsSelected(false),
89   mySymbol( new QwtSymbol() ),
90   mySymbolType(0),
91   myPen( QPen() )
92 {
93   myYAxisLeftIcon = QPixmap(yAxisLeft);
94   myYAxisRightIcon = QPixmap(yAxisRight);
95   int anIconWidth = qMax( myYAxisLeftIcon.width(), myYAxisRightIcon.width() );
96   setSpacing( SPACING );
97
98   mySpacingCollapsed = spacing();
99   mySpacingExpanded = anIconWidth + mySpacingCollapsed;
100 }
101
102 /*!
103   Destructor of Plot2d_QwtLegendLabel
104 */
105 Plot2d_QwtLegendLabel::~Plot2d_QwtLegendLabel()
106 {
107   delete mySymbol;
108 }
109
110 /*!
111   Set Y axis identifier displaying mode
112 */
113 void Plot2d_QwtLegendLabel::setYAxisIdentifierMode( const int theMode )
114 {
115   myYAxisIdentifierMode = theMode;
116   setSpacing( theMode == IM_None ? mySpacingCollapsed : mySpacingExpanded );
117 }
118
119 /*!
120   Paint the identifier to a given rect.
121   \param painter Painter
122   \param rect Rect where to paint
123 */
124 void Plot2d_QwtLegendLabel::drawIdentifier( QPainter* painter, const QRect& rect )
125 {
126   if ( rect.isEmpty() )
127     return;
128
129   if( myPen.style() != Qt::NoPen ) {
130     painter->save();
131     painter->setPen(myPen);
132     QwtPainter::drawLine( painter, rect.left() - 2, rect.center().y() + mySymbolType * 4,
133                                    rect.right() + 2, rect.center().y() + mySymbolType * 4 );
134     painter->restore();
135   }
136   if ( mySymbol->style() != QwtSymbol::NoSymbol )
137   {
138     QRect symbolRect;
139     symbolRect.setSize( QSize( SYMBOL_SIZE, SYMBOL_SIZE ) );
140     symbolRect.moveCenter( QPoint( rect.center().x(), rect.center().y() - mySymbolType * 4 ) );
141     painter->save();
142     painter->setBrush( mySymbol->brush() );
143     painter->setPen( mySymbol->pen() );
144     mySymbol->drawSymbol( painter, symbolRect );
145     painter->restore();
146   }
147   if( myYAxisIdentifierMode != IM_None ) {
148     QPixmap aPixmap( myYAxisIdentifierMode == IM_Left ? yAxisLeft : yAxisRight );
149     painter->save();
150     painter->drawPixmap( rect.topRight() + QPoint( mySpacingExpanded/2, mySpacingExpanded/2 ), aPixmap );
151     painter->restore();
152   }
153 }
154
155 /*!
156   Update highliting on the item.
157 */
158 void Plot2d_QwtLegendLabel::updateHighlit() {
159   QwtText txt = text();
160   if( isSelected() ) {
161     QColor highlightColor = Plot2d_Object::selectionColor();
162     if( highlightColor != txt.backgroundBrush().color() ) {
163       txt.setBackgroundBrush( highlightColor  );
164       setText(txt);
165     }
166   }
167   else if( this->parent() ) {
168     if(QWidget* parent = qobject_cast<QWidget*>( this->parent()->parent() ) ) {
169       QPalette aPal = parent->palette();
170       if( aPal.color( QPalette::Background) != txt.backgroundBrush().color() ) {
171         txt.setBackgroundBrush( aPal.color( QPalette::Background ) );
172         setText( txt );
173       }
174     }
175   }
176 }
177
178 /*!
179   Sets selected property.
180 */
181 void Plot2d_QwtLegendLabel::setSelected(const bool on) {
182   myIsSelected = on;
183 }
184
185 /*!
186   Gets selected property.
187 */
188 bool Plot2d_QwtLegendLabel::isSelected() const {
189   return myIsSelected;
190 }
191
192
193 /*
194   Draw text of the item.
195 */
196 void  Plot2d_QwtLegendLabel::drawText( QPainter * painter, const QRectF &rect ) {
197   painter->setPen( isSelected() ? Plot2d_Object::highlightedLegendTextColor() :
198                    getColorFromPalette( QPalette::Text) );
199
200   QwtTextLabel::drawText( painter, rect );
201 }
202
203 /*!
204   Sets symbol.
205 */
206 void Plot2d_QwtLegendLabel::setSymbol( const QwtSymbol* theSymbol )
207 {
208   delete mySymbol;
209   mySymbol = new QwtSymbol( theSymbol->style(), theSymbol->brush(),
210                             theSymbol->pen(), theSymbol->size() );
211 }
212
213 /*!
214   Sets symbol type 0(marker on line) or 1(marker above line).
215 */
216 void Plot2d_QwtLegendLabel::setSymbolType( const int theType )
217 {
218   mySymbolType = theType;
219 }
220
221 /*!
222   Sets pen.
223 */
224 void Plot2d_QwtLegendLabel::setPen (const QPen& thePen )
225 {
226   myPen = thePen;
227 }
228
229 /*!
230   Redefined method paintEvent of QwtLegendLabel
231 */
232 void Plot2d_QwtLegendLabel::paintEvent( QPaintEvent *e )
233 {
234   const QRect cr = contentsRect();
235
236   int ButtonFrame = 6;
237   QPainter painter( this );
238   painter.setClipRegion( e->region() );
239
240   if ( isDown() )
241   {
242     qDrawWinButton( &painter, 0, 0, width(), height(),
243                     palette(), true );
244   }
245
246   painter.save();
247   painter.setClipRect( cr );
248
249   drawContents( &painter );
250
251   QRect iconRect = cr;
252   if ( !icon().isNull() )
253   {
254     if ( itemMode() != QwtLegendData::ReadOnly )
255       iconRect.setX( iconRect.x() + ButtonFrame );
256       iconRect.setSize( QSize( icon().size().width() + spacing() ,
257                                    icon().size().height() + spacing() ) );
258       iconRect.moveCenter( QPoint( iconRect.center().x(), cr.center().y() ) );
259   }
260
261   drawIdentifier( &painter, iconRect );
262
263   painter.restore();
264 }
265
266 /*
267   Get color from the legend pallete by 'role' flag.
268 */
269 QColor Plot2d_QwtLegendLabel::getColorFromPalette(QPalette::ColorRole role) {
270   QWidget* pw = parentWidget();
271   QColor  col = palette().color( role );
272   while( pw ) {
273     if ( qobject_cast<QwtLegend*>( pw ) ) {
274       col = pw->palette().color(role );
275       break;
276     }
277     pw = pw->parentWidget();
278   }
279   return col;
280 }
281 /*
282  * Internal class to store deviation data on the curve.
283  */
284 class Plot2d_QwtPlotCurve::Plot2d_DeviationData {
285 public:
286   Plot2d_DeviationData(const double *min, const double *max,const QList<int>& idx)
287   {
288     foreach(int index,idx) {
289       myMin[index] = min[index];
290       myMax[index] = max[index];
291     }
292   }
293   ~Plot2d_DeviationData(){}
294
295   size_t size() const
296   {
297     return qwtMin(myMin.size(), myMax.size());
298   }
299   bool values(size_t i, double &min, double &max) {
300     if(myMin.contains(i) && myMax.contains(i)) {
301       min = myMin[i];
302       max = myMax[i];
303       return true;
304     }
305     return false;
306   }
307 private:
308   QMap<int,double> myMin;
309   QMap<int,double> myMax;
310 };
311
312
313 /*!
314   Constructor of Plot2d_QwtPlotCurve
315 */
316 Plot2d_QwtPlotCurve::Plot2d_QwtPlotCurve( const QString& title,
317                                           QwtPlot::Axis yAxis /*const int index*/ ) :
318   Plot2d_SelectableItem(),
319   QwtPlotCurve( title ),
320   myYAxis( yAxis ),
321   myYAxisIdentifierEnabled( false ),
322   myDeviationData(0)
323 {
324 }
325
326 /*!
327   Destructor of Plot2d_QwtPlotCurve
328 */
329 Plot2d_QwtPlotCurve::~Plot2d_QwtPlotCurve()
330 {
331   clearDeviationData();
332 }
333
334 /*!
335   Enable / disable Y axis identifier
336 */
337 void Plot2d_QwtPlotCurve::setYAxisIdentifierEnabled( const bool on )
338 {
339   myYAxisIdentifierEnabled = on;
340 }
341
342 /*!
343   Redefined method, which updates legend of the curve
344 */
345 void Plot2d_QwtPlotCurve::updateLegend( const QwtPlotItem* thePlotItem,
346                                         const QList<QwtLegendData>& theLegendData )
347 {
348   if ( !thePlotItem || !thePlotItem->plot() )
349     return;
350
351   if ( !testItemAttribute( QwtPlotItem::Legend ) )
352     return;
353
354   QwtPlotCurve::updateLegend( thePlotItem, theLegendData );
355
356   const QVariant itemInfo = thePlotItem->plot()->itemToInfo( const_cast< QwtPlotItem *>( thePlotItem ) );  
357   if( QwtLegend* legend = dynamic_cast<QwtLegend*>( thePlotItem->plot()->legend() ) ) {
358     if( QWidget* widget = legend->legendWidget( itemInfo ) ) {
359       QwtLegendLabel* label = dynamic_cast<QwtLegendLabel*>( widget );
360       if( Plot2d_QwtLegendLabel* anItem = (Plot2d_QwtLegendLabel*)label ) {
361         int aMode = Plot2d_QwtLegendLabel::IM_None;
362         if( myYAxisIdentifierEnabled )
363           aMode = myYAxis == QwtPlot::yRight ?
364             Plot2d_QwtLegendLabel::IM_Right :
365             Plot2d_QwtLegendLabel::IM_Left;
366         anItem->setYAxisIdentifierMode( aMode );
367         
368         anItem->setSymbol( legendSymbol() );
369         if( Plot2d_Plot2d* plot = dynamic_cast<Plot2d_Plot2d*>( thePlotItem->plot() ) )
370           anItem->setSymbolType( plot->getLegendSymbolType() );
371         anItem->setPen( legendPen() );
372         
373         anItem->setSelected( isSelected() );
374         anItem->updateHighlit();
375         anItem->repaint();
376       }
377     }
378   }
379 }
380
381 /*!
382   Redefined method, which updates and calls QwtPlot::autoRefresh() for the parent plot
383 */
384 void Plot2d_QwtPlotCurve::itemChanged()
385 {
386   if ( plot() )
387     updateLegend( this, legendData() );
388
389   QwtPlotItem::itemChanged();
390 }
391
392 /*!
393   Redefined method, which draw a set of points of a curve.
394 */
395 void Plot2d_QwtPlotCurve::drawSeries( QPainter *painter,
396                                       const QwtScaleMap &xMap,
397                                       const QwtScaleMap &yMap,
398                                       const QRectF &canvasRect,
399                                       int from, int to) const
400 {
401   if (to < 0)
402     to = dataSize() - 1;
403   QwtPlotCurve::drawSeries(painter, xMap, yMap, canvasRect, from, to);
404
405   //draw deviation data
406   if(hasDeviationData()) {
407     painter->save();
408     int lineW = deviationMarkerLineWidth();
409     int tickSz = deviationMarkerTickSize() + qRound(double(lineW)/2);
410     double min, max, xi, yi;
411     int xp, ytop, ybtm, tickl, tickr;
412     QColor c = isSelected() ? Plot2d_Object::selectionColor() : deviationMarkerColor();
413     QPen p = QPen(c, lineW, Qt::SolidLine);
414     painter->setPen(p);
415     for (int i = from; i <= to; i++) {
416       if(!myDeviationData->values(i,min,max)) continue;
417       const QPointF sample = data()->sample( i );
418       xi = sample.x();
419       yi = sample.y();
420       xp = xMap.transform(xi);
421       ytop = yMap.transform(yi + max);
422       ybtm = yMap.transform(yi - min);
423       tickl = xp - tickSz;
424       tickr = xp + tickSz;
425       painter->drawLine(tickl,ytop,tickr,ytop);
426       painter->drawLine(xp,ytop,xp,ybtm);
427       painter->drawLine(tickl,ybtm,tickr,ybtm);
428     }
429           painter->restore();
430   }
431 }
432
433 /*!
434  * Return color of the deviation marker.
435  */
436 QColor Plot2d_QwtPlotCurve::deviationMarkerColor() const {
437   QColor c(0, 0, 127);
438   if(plot()) {
439     QVariant var = plot()->property(PLOT2D_DEVIATION_COLOR);
440     if(var.isValid())
441       c = var.value<QColor>();
442   }
443   return c;
444 }
445 /*!
446  * Return line width of the deviation marker.
447  */
448 int Plot2d_QwtPlotCurve::deviationMarkerLineWidth() const {
449   int lw = 1;
450   if(plot()) {
451     QVariant var = plot()->property(PLOT2D_DEVIATION_LW);
452     if(var.isValid())
453       lw = var.toInt();
454   }
455   return lw;
456 }
457
458 /*!
459  * Return tick size of the deviation marker.
460  */
461 int Plot2d_QwtPlotCurve::deviationMarkerTickSize() const {
462   int ts = 2;
463   if(plot()) {
464     QVariant var = plot()->property(PLOT2D_DEVIATION_TS);
465     if(var.isValid())
466       ts = var.toInt();
467   }
468   return ts;
469 }
470
471 /*!
472  * Sets deviation data for the plot item.
473  */
474 void Plot2d_QwtPlotCurve::setDeviationData(const double* min, const double* max,const QList<int> &idx) {
475   clearDeviationData();
476   myDeviationData = new Plot2d_DeviationData(min,max,idx);
477 }
478
479 /*!
480  * Return true if deviation is assigned to the plot item,
481    false otherwise.
482  */
483 bool Plot2d_QwtPlotCurve::hasDeviationData() const {
484   return myDeviationData != 0;
485 }
486
487 /*!
488  * Remove deviation data from the plot item.
489  */
490 void Plot2d_QwtPlotCurve::clearDeviationData()
491 {
492   if(myDeviationData)
493     delete myDeviationData;
494   myDeviationData = 0;
495 }
496
497
498
499 /*!
500   Constructor.
501 */
502 Plot2d_SelectableItem::Plot2d_SelectableItem():
503   myIsSelected(false),
504   myLegendSymbol( new QwtSymbol() ),
505   myLegendPen( QPen() )
506 {
507 }
508
509 /*!
510   Destructor.
511 */
512 Plot2d_SelectableItem::~Plot2d_SelectableItem()
513 {
514 }
515
516 /*!
517   Sets selected property.
518 */
519 void Plot2d_SelectableItem::setSelected( const bool on) {
520   myIsSelected = on;
521 }
522
523 /*!
524   Return selected property.
525 */
526 bool Plot2d_SelectableItem::isSelected() const {
527   return myIsSelected;
528 }
529
530 /*!
531   Sets legend pen property.
532 */
533 void Plot2d_SelectableItem::setLegendPen( const QPen & p) {
534   myLegendPen = p;
535 }
536
537 /*!
538   Return legend pen property.
539 */
540 QPen Plot2d_SelectableItem::legendPen() const {
541   return myLegendPen;
542 }
543
544 /*!
545   Sets legend symbol property.
546 */
547 void Plot2d_SelectableItem::setLegendSymbol( const QwtSymbol* s ) {
548   myLegendSymbol->setStyle( s->style() );
549   myLegendSymbol->setBrush( s->brush() );
550   myLegendSymbol->setPen( s->pen() );
551   myLegendSymbol->setSize( s->size() );
552 }
553
554 /*!
555   Sets legend symbol property.
556 */
557 QwtSymbol* Plot2d_SelectableItem::legendSymbol() const {
558   return new QwtSymbol( myLegendSymbol->style(), myLegendSymbol->brush(),
559                         myLegendSymbol->pen(), myLegendSymbol->size() );
560 }
561
562 /*!
563   Constructor
564 */
565 Plot2d_HistogramQwtItem::Plot2d_HistogramQwtItem( const QwtText& theTitle )
566 : QwtPlotItem( theTitle )
567 {
568   init();
569 }
570
571 /*!
572   Constructor
573 */
574 Plot2d_HistogramQwtItem::Plot2d_HistogramQwtItem( const QString& theTitle )
575 : QwtPlotItem( QwtText( theTitle ) )
576 {
577   init();
578 }
579
580 /*!
581   Destructor
582 */
583 Plot2d_HistogramQwtItem::~Plot2d_HistogramQwtItem()
584 {
585 }
586
587 /*!
588   Initialization of object
589 */
590 void Plot2d_HistogramQwtItem::init()
591 {
592   myReference = 0.0;
593   myAttributes = Plot2d_HistogramQwtItem::Auto;
594
595   setItemAttribute( QwtPlotItem::AutoScale, true );
596   setItemAttribute( QwtPlotItem::Legend,    true );
597
598   setZ( 20.0 );
599 }
600
601 /*!
602   Sets base line to object
603   @param theRef
604 */
605 void Plot2d_HistogramQwtItem::setBaseline( double theRef )
606 {
607   if ( myReference != theRef ) {
608     myReference = theRef;
609     itemChanged();
610   }
611 }
612
613 /*!
614   Returns base line of object
615 */
616 double Plot2d_HistogramQwtItem::baseline() const
617 {
618   return myReference;
619 }
620
621 /*!
622   Sets data to object
623 */
624 void Plot2d_HistogramQwtItem::setData( const QwtIntervalSeriesData& theData )
625 {
626   myData.setSamples( theData.samples() );
627   itemChanged();
628 }
629
630 /*!
631   Returns data from object
632 */
633 const QwtIntervalSeriesData& Plot2d_HistogramQwtItem::data() const
634 {
635   return myData;
636 }
637
638 /*!
639   Sets color to object
640 */
641 void Plot2d_HistogramQwtItem::setColor( const QColor& theColor )
642 {
643   if ( myColor != theColor ) {
644     myColor = theColor;
645     itemChanged();
646   }
647 }
648
649 /*!
650   Returns color from object
651 */
652 QColor Plot2d_HistogramQwtItem::color() const
653 {
654   return myColor;
655 }
656
657 /*!
658   Returns bounding rect of object
659 */
660 QwtDoubleRect Plot2d_HistogramQwtItem::boundingRect() const
661 {
662   QwtDoubleRect aRect = myData.boundingRect();
663   if ( !aRect.isValid() )
664       return aRect;
665
666   if ( myAttributes & Xfy ) {
667     aRect = QwtDoubleRect( aRect.y(), aRect.x(),
668                            aRect.height(), aRect.width() );
669     if ( aRect.left() > myReference )
670       aRect.setLeft( myReference );
671     else if ( aRect.right() < myReference )
672       aRect.setRight( myReference );
673   }
674   else {
675     if ( aRect.bottom() < myReference )
676       aRect.setBottom( myReference );
677     else if ( aRect.top() > myReference )
678       aRect.setTop( myReference );
679   }
680   return aRect;
681 }
682
683 /*!
684   Returns type of plot object
685 */
686 int Plot2d_HistogramQwtItem::rtti() const
687 {
688   return QwtPlotItem::Rtti_PlotHistogram;
689 }
690
691 /*!
692   Sets histogram attributes
693 */
694 void Plot2d_HistogramQwtItem::setHistogramAttribute( HistogramAttribute theAttr,
695                                                      bool isOn )
696 {
697   if ( testHistogramAttribute( theAttr ) != isOn ) {
698     if ( isOn )
699       myAttributes |= theAttr;
700     else
701       myAttributes &= ~theAttr;
702
703     itemChanged();
704   }
705 }
706
707 /*!
708   Tests histogram attributes
709 */
710 bool Plot2d_HistogramQwtItem::testHistogramAttribute( HistogramAttribute theAttr ) const
711 {
712   return myAttributes & theAttr;
713 }
714
715 /*!
716   Draws histogram object
717 */
718 void Plot2d_HistogramQwtItem::draw( QPainter* thePainter,
719                                     const QwtScaleMap& theXMap,
720                                     const QwtScaleMap& theYMap,
721                                     const QRectF& ) const
722 {
723   thePainter->setPen( QPen( myColor ) );
724
725   const int x0 = theXMap.transform( baseline() );
726   const int y0 = theYMap.transform( baseline() );
727
728   for ( int i = 0; i < (int)myData.size(); i++ ) {
729     if ( myAttributes & Plot2d_HistogramQwtItem::Xfy ) {
730       const int x2 = theXMap.transform( myData.sample(i).value );
731       if ( x2 == x0 )
732         continue;
733       int y1 = theYMap.transform( myData.sample( i ).interval.minValue() );
734       int y2 = theYMap.transform( myData.sample( i ).interval.maxValue() );
735       if ( y1 > y2 )
736         qSwap( y1, y2 );
737
738       if ( i < (int)myData.size() - 2 ) {
739         const int yy1 = theYMap.transform( myData.sample(i+1).interval.minValue() );
740         const int yy2 = theYMap.transform( myData.sample(i+1).interval.maxValue() );
741         if ( y2 == qwtMin( yy1, yy2 ) ) {
742           const int xx2 = theXMap.transform( myData.sample(i+1).interval.minValue() );
743           if ( xx2 != x0 && ( ( xx2 < x0 && x2 < x0 ) ||
744                               ( xx2 > x0 && x2 > x0 ) ) ) {
745             // One pixel distance between neighboured bars
746             y2++;
747           }
748         }
749       }
750       drawBar( thePainter, Qt::Horizontal, QRect( x0, y1, x2 - x0, y2 - y1 ) );
751     }
752     else {
753       const int y2 = theYMap.transform( myData.sample( i ).value );
754       if ( y2 == y0 )
755         continue;
756       int x1 = theXMap.transform( myData.sample( i ).interval.minValue() );
757       int x2 = theXMap.transform( myData.sample( i ).interval.maxValue() );
758       if ( x1 > x2 )
759         qSwap( x1, x2 );
760
761       if ( i < (int)myData.size() - 2 ) {
762         const int xx1 = theXMap.transform( myData.sample(i+1).interval.minValue() );
763         const int xx2 = theXMap.transform( myData.sample(i+1).interval.maxValue() );
764         if ( x2 == qwtMin( xx1, xx2 ) ) {
765           const int yy2 = theYMap.transform( myData.sample(i+1).value );
766           if ( yy2 != y0 && ( ( yy2 < y0 && y2 < y0 ) ||
767                               ( yy2 > y0 && y2 > y0 ) ) ) {
768             // One pixel distance between neighboured bars
769             x2--;
770           }
771         }
772       }
773       drawBar( thePainter, Qt::Vertical, QRect( x1, y0, x2 - x1, y2 - y0 ) );
774     }
775   }
776 }
777
778 /*!
779   Draws single bar of histogram
780 */
781 void Plot2d_HistogramQwtItem::drawBar( QPainter* thePainter,
782                                        Qt::Orientation,
783                                        const QRect& theRect ) const
784 {
785   thePainter->save();
786
787   const QColor color( thePainter->pen().color() );
788   QRect r = theRect.normalized();
789
790   const int factor = 125;
791   const QColor light( color.light( factor ) );
792   const QColor dark( color.dark( factor ) );
793
794   thePainter->setBrush( color );
795   thePainter->setPen( Qt::NoPen );
796   QwtPainter::drawRect( thePainter, r.x() + 1, r.y() + 1,
797                         r.width() - 2, r.height() - 2 );
798   thePainter->setBrush( Qt::NoBrush );
799
800   thePainter->setPen( QPen( light, 2 ) );
801   QwtPainter::drawLine( thePainter, r.left() + 1, r.top() + 2,
802                         r.right() + 1, r.top() + 2 );
803
804   thePainter->setPen( QPen( dark, 2 ) );
805   QwtPainter::drawLine( thePainter, r.left() + 1, r.bottom(),
806                         r.right() + 1, r.bottom() );
807   thePainter->setPen( QPen( light, 1 ) );
808
809   QwtPainter::drawLine( thePainter, r.left(), r.top() + 1,
810                         r.left(), r.bottom() );
811   QwtPainter::drawLine( thePainter, r.left() + 1, r.top() + 2,
812                          r.left() + 1, r.bottom() - 1 );
813   thePainter->setPen( QPen( dark, 1 ) );
814
815   QwtPainter::drawLine( thePainter, r.right() + 1, r.top() + 1,
816                         r.right() + 1, r.bottom() );
817   QwtPainter::drawLine(thePainter, r.right(), r.top() + 2,
818                         r.right(), r.bottom() - 1 );
819   thePainter->restore();
820 }
821
822 /*!
823   Constructor
824 */
825 Plot2d_HistogramItem::Plot2d_HistogramItem( const QwtText& theTitle )
826 : Plot2d_HistogramQwtItem( theTitle ),
827   Plot2d_SelectableItem(),
828   myCrossed( true )
829 {
830 }
831
832 /*!
833   Constructor
834 */
835 Plot2d_HistogramItem::Plot2d_HistogramItem( const QString& theTitle )
836 : Plot2d_HistogramQwtItem( theTitle ),
837   myCrossed( true )
838 {
839 }
840
841 /*!
842   Destructor
843 */
844 Plot2d_HistogramItem::~Plot2d_HistogramItem()
845 {
846 }
847
848 /*!
849   Get histogram bar items
850 */
851 QList<QRect> Plot2d_HistogramItem::getBars() const
852 {
853   return myBarItems;
854 }
855
856 /*!
857   Set to legend item symbol with color of item
858 */
859 void Plot2d_HistogramItem::updateLegend( QwtPlotItem* thePlotItem,
860                                          QList<QwtLegendData>& theLegendData )
861 {
862   if ( !thePlotItem || !thePlotItem->plot() )
863     return;
864
865   Plot2d_HistogramQwtItem::updateLegend( thePlotItem, theLegendData );
866
867   const QVariant itemInfo = thePlotItem->plot()->itemToInfo( const_cast< QwtPlotItem *>( thePlotItem ) );
868   QwtLegend *legend = dynamic_cast<QwtLegend *>( thePlotItem->plot()->legend() );
869   QWidget* widget = legend->legendWidget( itemInfo );
870
871   if ( !widget || !widget->inherits( "QwtLegendItem" ) )
872     return;
873
874   QwtLegendLabel* label = dynamic_cast<QwtLegendLabel*>( widget );
875   if( Plot2d_QwtLegendLabel* anItem = (Plot2d_QwtLegendLabel*)( label ) ) {
876     QFontMetrics aFMetrics( anItem->font() );
877     int aSize = aFMetrics.height();
878     QwtSymbol* aSymbol = new QwtSymbol( QwtSymbol::Rect, QBrush( legendPen().color() ),
879                                         QPen( legendPen().color() ), QSize( aSize, aSize ) );
880     anItem->setSymbol( aSymbol );
881     if( Plot2d_Plot2d* plot = dynamic_cast<Plot2d_Plot2d*>( thePlotItem->plot() ) )
882       anItem->setSymbolType( plot->getLegendSymbolType() );
883     anItem->setSelected( isSelected() );
884     anItem->updateHighlit();
885     anItem->update();
886     anItem->repaint();
887   }
888 }
889
890 /*!
891   Draws histogram object
892 */
893 void Plot2d_HistogramItem::draw( QPainter* thePainter,
894                                  const QwtScaleMap& theXMap,
895                                  const QwtScaleMap& theYMap,
896                                  const QRectF& ) const
897 {
898   // nds: clear list of bar items
899   Plot2d_HistogramItem* anItem = (Plot2d_HistogramItem*)this;
900   anItem->myBarItems.clear();
901
902   thePainter->setPen( QPen( color() ) );
903   const int x0 = theXMap.transform( baseline() );
904   const int y0 = theYMap.transform( baseline() );
905
906   const QwtIntervalSeriesData& iData = data();
907
908   for ( int i = 0; i < (int)iData.size(); i++ ) {
909     if ( testHistogramAttribute( Plot2d_HistogramItem::Xfy ) ) {
910       const int x2 = theXMap.transform( iData.sample(i).value );
911       if ( x2 == x0 )
912         continue;
913       int y1 = theYMap.transform( iData.sample(i).interval.minValue() );
914       int y2 = theYMap.transform( iData.sample(i).interval.maxValue() );
915       if ( y1 > y2 )
916         qSwap( y1, y2 );
917
918       if ( i < (int)iData.size() - 2 ) {
919         const int yy1 = theYMap.transform( iData.sample(i+1).interval.minValue() );
920         const int yy2 = theYMap.transform( iData.sample(i+1).interval.maxValue() );
921         if ( y2 == qwtMin( yy1, yy2 ) ) {
922           const int xx2 = theXMap.transform( iData.sample(i+1).interval.minValue() );
923           if ( xx2 != x0 && ( ( xx2 < x0 && x2 < x0 ) ||
924                               ( xx2 > x0 && x2 > x0 ) ) ) {
925             // One pixel distance between neighboured bars
926             y2++;
927           }
928         }
929       }
930       // nds: draw rect with the other lower rects
931       QRect aRect( x0, y1, x2 - x0, y2 - y1 );
932       drawRectAndLowers( thePainter, Qt::Horizontal, aRect );
933       anItem->myBarItems.append( aRect );
934     }
935     else {
936       const int y2 = theYMap.transform( iData.sample(i).value );
937       if ( y2 == y0 )
938         continue;
939       int x1 = theXMap.transform( iData.sample(i).interval.minValue() );
940       int x2 = theXMap.transform( iData.sample(i).interval.maxValue() );
941       if ( x1 > x2 )
942         qSwap( x1, x2 );
943
944       if ( i < (int)iData.size() - 2 ) {
945         const int xx1 = theXMap.transform( iData.sample(i+1).interval.minValue() );
946         const int xx2 = theXMap.transform( iData.sample(i+1).interval.maxValue() );
947         if ( x2 == qwtMin( xx1, xx2 ) ) {
948           const int yy2 = theYMap.transform( iData.sample(i+1).value );
949           if ( yy2 != y0 && ( ( yy2 < y0 && y2 < y0 ) ||
950                               ( yy2 > y0 && y2 > y0 ) ) ) {
951             // One pixel distance between neighboured bars
952             x2--;
953           }
954         }
955       }
956       // nds: draw rect with the other lower rects
957       QRect aRect(x1, y0, x2 - x1, y2 - y0 );
958       drawRectAndLowers( thePainter, Qt::Vertical, aRect );
959       anItem->myBarItems.append( aRect );
960     }
961   }
962 }
963
964 /*!
965   Set/clear "cross items" option
966 */
967 void Plot2d_HistogramItem::setCrossItems( bool theCross )
968 {
969   myCrossed = theCross;
970 }
971
972 /*!
973   Get "cross items" option
974 */
975 bool Plot2d_HistogramItem::isCrossItems() const
976 {
977   return myCrossed;
978 }
979
980 /*!
981   Draws bar of histogram and on it bars of histograms with lower height.
982 */
983 void Plot2d_HistogramItem::drawRectAndLowers( QPainter* thePainter,
984                                               Qt::Orientation theOr,
985                                               const QRect& theRect ) const
986 {
987   QRect aRect = theRect;
988   // theRect has inversed coordinates on Y axis.
989   // The top of the rect is bottom in standard QRect coordinates,
990   // and it bottom is the top.
991   if ( myCrossed )//&& theOr == Qt::Horizontal )
992     aRect.setTop( getCrossedTop( theRect ) );
993
994   drawBar( thePainter, Qt::Horizontal, aRect );
995 }
996
997 /*!
998   Returns top value of the given rect in the context of other bars.
999
1000   It's necessary to remember, that \a theRect has inverted coordinate Y.
1001 */
1002 int Plot2d_HistogramItem::getCrossedTop( const QRect& theRect ) const
1003 {
1004   int aRes = theRect.top();
1005   QwtPlot* aPlot = plot();
1006   // int aHeight = theRect.height();
1007   if ( aPlot ) {
1008     QwtPlotItemList anItems = aPlot->itemList();
1009     QwtPlotItemIterator anIt = anItems.begin(), aLast = anItems.end();
1010     Plot2d_HistogramItem* anItem;
1011     QList<QRect> aRects;
1012     for ( ; anIt != aLast; anIt++ ) {
1013       if ( !((*anIt)->rtti() == QwtPlotItem::Rtti_PlotHistogram) )
1014         continue;
1015       anItem = dynamic_cast<Plot2d_HistogramItem*>( *anIt );
1016       if( !anItem || anItem == this )
1017         continue;
1018       aRects.clear();
1019       aRects = anItem->getBars();
1020       for ( int i = 0, aSize = aRects.size(); i < aSize; i++ ) {
1021         if ( qMax( theRect.x(), aRects[i].x() ) <=
1022              qMin( theRect.left(), aRects[i].left() ) ) {
1023           if ( theRect.bottom() < aRects[i].bottom() )
1024             if ( aRects[i].bottom() < aRes )
1025               aRes = aRects[i].bottom();
1026         }
1027       }
1028     }
1029   }
1030   return aRes;
1031 }
1032
1033 Plot2d_QwtLegend::Plot2d_QwtLegend( QWidget *parent ):
1034 QwtLegend( parent )
1035 {
1036   setAutoFillBackground(true);
1037 }
1038
1039 Plot2d_QwtLegend::~Plot2d_QwtLegend()
1040 {
1041 }
1042
1043 /*!
1044   Redefined method, which create a widget to be inserted into the legend.
1045 */
1046 QWidget *Plot2d_QwtLegend::createWidget( const QwtLegendData &data ) const
1047 {
1048   Q_UNUSED( data );
1049
1050   Plot2d_QwtLegendLabel *label = new Plot2d_QwtLegendLabel();
1051   label->setItemMode( defaultItemMode() );
1052
1053   connect( label, SIGNAL( clicked() ), SLOT( itemClicked() ) );
1054   connect( label, SIGNAL( checked( bool ) ), SLOT( itemChecked( bool ) ) );
1055
1056   return label;
1057 }