Salome HOME
4d4296e35d3ba6213a5171d4735f45b6b4041b82
[modules/gui.git] / src / Plot2d / Plot2d_PlotItems.cxx
1 // Copyright (C) 2007-2023  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
262   drawIdentifier( &painter, iconRect );
263
264   painter.restore();
265 }
266
267 /*
268   Get color from the legend pallete by 'role' flag.
269 */
270 QColor Plot2d_QwtLegendLabel::getColorFromPalette(QPalette::ColorRole role) {
271   QWidget* pw = parentWidget();
272   QColor  col = palette().color( role );
273   while( pw ) {
274     if ( qobject_cast<QwtLegend*>( pw ) ) {
275       col = pw->palette().color(role );
276       break;
277     }
278     pw = pw->parentWidget();
279   }
280   return col;
281 }
282 /*
283  * Internal class to store deviation data on the curve.
284  */
285 class Plot2d_QwtPlotCurve::Plot2d_DeviationData {
286 public:
287   Plot2d_DeviationData(const double *min, const double *max,const QList<int>& idx)
288   {
289     foreach(int index,idx) {
290       myMin[index] = min[index];
291       myMax[index] = max[index];
292     }
293   }
294   ~Plot2d_DeviationData(){}
295
296   size_t size() const
297   {
298     return qwtMin(myMin.size(), myMax.size());
299   }
300   bool values(size_t i, double &min, double &max) {
301     if(myMin.contains((int)i) && myMax.contains((int)i)) { //!< TODO: conversion from size_t to int
302       min = myMin[(int)i];
303       max = myMax[(int)i];
304       return true;
305     }
306     return false;
307   }
308 private:
309   QMap<int,double> myMin;
310   QMap<int,double> myMax;
311 };
312
313
314 /*!
315   Constructor of Plot2d_QwtPlotCurve
316 */
317 Plot2d_QwtPlotCurve::Plot2d_QwtPlotCurve( const QString& title,
318                                           QwtPlot::Axis yAxis /*const int index*/ ) :
319   QwtPlotCurve( title ),
320   Plot2d_SelectableItem(),
321   myYAxis( yAxis ),
322   myYAxisIdentifierEnabled( false ),
323   myDeviationData(0)
324 {
325 }
326
327 /*!
328   Destructor of Plot2d_QwtPlotCurve
329 */
330 Plot2d_QwtPlotCurve::~Plot2d_QwtPlotCurve()
331 {
332   clearDeviationData();
333 }
334
335 /*!
336   Enable / disable Y axis identifier
337 */
338 void Plot2d_QwtPlotCurve::setYAxisIdentifierEnabled( const bool on )
339 {
340   myYAxisIdentifierEnabled = on;
341 }
342
343 /*!
344   Redefined method, which updates legend of the curve
345 */
346 void Plot2d_QwtPlotCurve::updateLegend( const QwtPlotItem* thePlotItem,
347                                         const QList<QwtLegendData>& theLegendData )
348 {
349   if ( !thePlotItem || !thePlotItem->plot() )
350     return;
351
352   if ( !testItemAttribute( QwtPlotItem::Legend ) )
353     return;
354
355   QwtPlotCurve::updateLegend( thePlotItem, theLegendData );
356
357   const QVariant itemInfo = thePlotItem->plot()->itemToInfo( const_cast< QwtPlotItem *>( thePlotItem ) );  
358   if( QwtLegend* legend = dynamic_cast<QwtLegend*>( thePlotItem->plot()->legend() ) ) {
359     if( QWidget* widget = legend->legendWidget( itemInfo ) ) {
360       QwtLegendLabel* label = dynamic_cast<QwtLegendLabel*>( widget );
361       if( Plot2d_QwtLegendLabel* anItem = (Plot2d_QwtLegendLabel*)label ) {
362         int aMode = Plot2d_QwtLegendLabel::IM_None;
363         if( myYAxisIdentifierEnabled )
364           aMode = myYAxis == QwtPlot::yRight ?
365             Plot2d_QwtLegendLabel::IM_Right :
366             Plot2d_QwtLegendLabel::IM_Left;
367         anItem->setYAxisIdentifierMode( aMode );
368         
369         anItem->setSymbol( legendSymbol() );
370         if( Plot2d_Plot2d* plot = dynamic_cast<Plot2d_Plot2d*>( thePlotItem->plot() ) )
371           anItem->setSymbolType( plot->getLegendSymbolType() );
372         anItem->setPen( legendPen() );
373         
374         anItem->setSelected( isSelected() );
375         anItem->updateHighlit();
376         anItem->repaint();
377       }
378     }
379   }
380 }
381
382 /*!
383   Redefined method, which updates and calls QwtPlot::autoRefresh() for the parent plot
384 */
385 void Plot2d_QwtPlotCurve::itemChanged()
386 {
387   if ( plot() )
388     updateLegend( this, legendData() );
389
390   QwtPlotItem::itemChanged();
391 }
392
393 /*!
394   Redefined method, which draw a set of points of a curve.
395 */
396 void Plot2d_QwtPlotCurve::drawSeries( QPainter *painter,
397                                       const QwtScaleMap &xMap,
398                                       const QwtScaleMap &yMap,
399                                       const QRectF &canvasRect,
400                                       int from, int to) const
401 {
402   if (to < 0)
403     to = (int)dataSize() - 1; //!< TODO: conversion from size_t to int
404   QwtPlotCurve::drawSeries(painter, xMap, yMap, canvasRect, from, to);
405
406   //draw deviation data
407   if(hasDeviationData()) {
408     painter->save();
409     int lineW = deviationMarkerLineWidth();
410     int tickSz = deviationMarkerTickSize() + qRound(double(lineW)/2);
411     double min, max, xi, yi;
412     int xp, ytop, ybtm, tickl, tickr;
413     QColor c = isSelected() ? Plot2d_Object::selectionColor() : deviationMarkerColor();
414     QPen p = QPen(c, lineW, Qt::SolidLine);
415     painter->setPen(p);
416     for (int i = from; i <= to; i++) {
417       if(!myDeviationData->values(i,min,max)) continue;
418       const QPointF sample = data()->sample( i );
419       xi = sample.x();
420       yi = sample.y();
421       xp = xMap.transform(xi);
422       ytop = yMap.transform(yi + max);
423       ybtm = yMap.transform(yi - min);
424       tickl = xp - tickSz;
425       tickr = xp + tickSz;
426       painter->drawLine(tickl,ytop,tickr,ytop);
427       painter->drawLine(xp,ytop,xp,ybtm);
428       painter->drawLine(tickl,ybtm,tickr,ybtm);
429     }
430           painter->restore();
431   }
432 }
433
434 /*!
435  * Return color of the deviation marker.
436  */
437 QColor Plot2d_QwtPlotCurve::deviationMarkerColor() const {
438   QColor c(0, 0, 127);
439   if(plot()) {
440     QVariant var = plot()->property(PLOT2D_DEVIATION_COLOR);
441     if(var.isValid())
442       c = var.value<QColor>();
443   }
444   return c;
445 }
446 /*!
447  * Return line width of the deviation marker.
448  */
449 int Plot2d_QwtPlotCurve::deviationMarkerLineWidth() const {
450   int lw = 1;
451   if(plot()) {
452     QVariant var = plot()->property(PLOT2D_DEVIATION_LW);
453     if(var.isValid())
454       lw = var.toInt();
455   }
456   return lw;
457 }
458
459 /*!
460  * Return tick size of the deviation marker.
461  */
462 int Plot2d_QwtPlotCurve::deviationMarkerTickSize() const {
463   int ts = 2;
464   if(plot()) {
465     QVariant var = plot()->property(PLOT2D_DEVIATION_TS);
466     if(var.isValid())
467       ts = var.toInt();
468   }
469   return ts;
470 }
471
472 /*!
473  * Sets deviation data for the plot item.
474  */
475 void Plot2d_QwtPlotCurve::setDeviationData(const double* min, const double* max,const QList<int> &idx) {
476   clearDeviationData();
477   myDeviationData = new Plot2d_DeviationData(min,max,idx);
478 }
479
480 /*!
481  * Return true if deviation is assigned to the plot item,
482    false otherwise.
483  */
484 bool Plot2d_QwtPlotCurve::hasDeviationData() const {
485   return myDeviationData != 0;
486 }
487
488 /*!
489  * Remove deviation data from the plot item.
490  */
491 void Plot2d_QwtPlotCurve::clearDeviationData()
492 {
493   if(myDeviationData)
494     delete myDeviationData;
495   myDeviationData = 0;
496 }
497
498
499
500 /*!
501   Constructor.
502 */
503 Plot2d_SelectableItem::Plot2d_SelectableItem():
504   myIsSelected(false),
505   myLegendPen( QPen() ),
506   myLegendSymbol( new QwtSymbol() )
507 {
508 }
509
510 /*!
511   Destructor.
512 */
513 Plot2d_SelectableItem::~Plot2d_SelectableItem()
514 {
515 }
516
517 /*!
518   Sets selected property.
519 */
520 void Plot2d_SelectableItem::setSelected( const bool on) {
521   myIsSelected = on;
522 }
523
524 /*!
525   Return selected property.
526 */
527 bool Plot2d_SelectableItem::isSelected() const {
528   return myIsSelected;
529 }
530
531 /*!
532   Sets legend pen property.
533 */
534 void Plot2d_SelectableItem::setLegendPen( const QPen & p) {
535   myLegendPen = p;
536 }
537
538 /*!
539   Return legend pen property.
540 */
541 QPen Plot2d_SelectableItem::legendPen() const {
542   return myLegendPen;
543 }
544
545 /*!
546   Sets legend symbol property.
547 */
548 void Plot2d_SelectableItem::setLegendSymbol( const QwtSymbol* s ) {
549   myLegendSymbol->setStyle( s->style() );
550   myLegendSymbol->setBrush( s->brush() );
551   myLegendSymbol->setPen( s->pen() );
552   myLegendSymbol->setSize( s->size() );
553 }
554
555 /*!
556   Sets legend symbol property.
557 */
558 QwtSymbol* Plot2d_SelectableItem::legendSymbol() const {
559   return new QwtSymbol( myLegendSymbol->style(), myLegendSymbol->brush(),
560                         myLegendSymbol->pen(), myLegendSymbol->size() );
561 }
562
563 /*!
564   Constructor
565 */
566 Plot2d_HistogramQwtItem::Plot2d_HistogramQwtItem( const QwtText& theTitle )
567 : QwtPlotItem( theTitle )
568 {
569   init();
570 }
571
572 /*!
573   Constructor
574 */
575 Plot2d_HistogramQwtItem::Plot2d_HistogramQwtItem( const QString& theTitle )
576 : QwtPlotItem( QwtText( theTitle ) )
577 {
578   init();
579 }
580
581 /*!
582   Destructor
583 */
584 Plot2d_HistogramQwtItem::~Plot2d_HistogramQwtItem()
585 {
586 }
587
588 /*!
589   Initialization of object
590 */
591 void Plot2d_HistogramQwtItem::init()
592 {
593   myReference = 0.0;
594   myAttributes = Plot2d_HistogramQwtItem::Auto;
595
596   setItemAttribute( QwtPlotItem::AutoScale, true );
597   setItemAttribute( QwtPlotItem::Legend,    true );
598
599   setZ( 20.0 );
600 }
601
602 /*!
603   Sets base line to object
604   @param theRef
605 */
606 void Plot2d_HistogramQwtItem::setBaseline( double theRef )
607 {
608   if ( myReference != theRef ) {
609     myReference = theRef;
610     itemChanged();
611   }
612 }
613
614 /*!
615   Returns base line of object
616 */
617 double Plot2d_HistogramQwtItem::baseline() const
618 {
619   return myReference;
620 }
621
622 /*!
623   Sets data to object
624 */
625 void Plot2d_HistogramQwtItem::setData( const QwtIntervalSeriesData& theData )
626 {
627   myData.setSamples( theData.samples() );
628   itemChanged();
629 }
630
631 /*!
632   Returns data from object
633 */
634 const QwtIntervalSeriesData& Plot2d_HistogramQwtItem::data() const
635 {
636   return myData;
637 }
638
639 /*!
640   Sets color to object
641 */
642 void Plot2d_HistogramQwtItem::setColor( const QColor& theColor )
643 {
644   if ( myColor != theColor ) {
645     myColor = theColor;
646     itemChanged();
647   }
648 }
649
650 /*!
651   Returns color from object
652 */
653 QColor Plot2d_HistogramQwtItem::color() const
654 {
655   return myColor;
656 }
657
658 /*!
659   Returns bounding rect of object
660 */
661 QwtDoubleRect Plot2d_HistogramQwtItem::boundingRect() const
662 {
663   QwtDoubleRect aRect = myData.boundingRect();
664   if ( !aRect.isValid() )
665       return aRect;
666
667   if ( myAttributes & Xfy ) {
668     aRect = QwtDoubleRect( aRect.y(), aRect.x(),
669                            aRect.height(), aRect.width() );
670     if ( aRect.left() > myReference )
671       aRect.setLeft( myReference );
672     else if ( aRect.right() < myReference )
673       aRect.setRight( myReference );
674   }
675   else {
676     if ( aRect.bottom() < myReference )
677       aRect.setBottom( myReference );
678     else if ( aRect.top() > myReference )
679       aRect.setTop( myReference );
680   }
681   return aRect;
682 }
683
684 /*!
685   Returns type of plot object
686 */
687 int Plot2d_HistogramQwtItem::rtti() const
688 {
689   return QwtPlotItem::Rtti_PlotHistogram;
690 }
691
692 /*!
693   Sets histogram attributes
694 */
695 void Plot2d_HistogramQwtItem::setHistogramAttribute( HistogramAttribute theAttr,
696                                                      bool isOn )
697 {
698   if ( testHistogramAttribute( theAttr ) != isOn ) {
699     if ( isOn )
700       myAttributes |= theAttr;
701     else
702       myAttributes &= ~theAttr;
703
704     itemChanged();
705   }
706 }
707
708 /*!
709   Tests histogram attributes
710 */
711 bool Plot2d_HistogramQwtItem::testHistogramAttribute( HistogramAttribute theAttr ) const
712 {
713   return myAttributes & theAttr;
714 }
715
716 /*!
717   Draws histogram object
718 */
719 void Plot2d_HistogramQwtItem::draw( QPainter* thePainter,
720                                     const QwtScaleMap& theXMap,
721                                     const QwtScaleMap& theYMap,
722                                     const QRectF& ) const
723 {
724   thePainter->setPen( QPen( myColor ) );
725
726   const int x0 = theXMap.transform( baseline() );
727   const int y0 = theYMap.transform( baseline() );
728
729   for ( int i = 0; i < (int)myData.size(); i++ ) {
730     if ( myAttributes & Plot2d_HistogramQwtItem::Xfy ) {
731       const int x2 = theXMap.transform( myData.sample(i).value );
732       if ( x2 == x0 )
733         continue;
734       int y1 = theYMap.transform( myData.sample( i ).interval.minValue() );
735       int y2 = theYMap.transform( myData.sample( i ).interval.maxValue() );
736       if ( y1 > y2 )
737         qSwap( y1, y2 );
738
739       if ( i < (int)myData.size() - 2 ) {
740         const int yy1 = theYMap.transform( myData.sample(i+1).interval.minValue() );
741         const int yy2 = theYMap.transform( myData.sample(i+1).interval.maxValue() );
742         if ( y2 == qwtMin( yy1, yy2 ) ) {
743           const int xx2 = theXMap.transform( myData.sample(i+1).interval.minValue() );
744           if ( xx2 != x0 && ( ( xx2 < x0 && x2 < x0 ) ||
745                               ( xx2 > x0 && x2 > x0 ) ) ) {
746             // One pixel distance between neighboured bars
747             y2++;
748           }
749         }
750       }
751       drawBar( thePainter, Qt::Horizontal, QRect( x0, y1, x2 - x0, y2 - y1 ) );
752     }
753     else {
754       const int y2 = theYMap.transform( myData.sample( i ).value );
755       if ( y2 == y0 )
756         continue;
757       int x1 = theXMap.transform( myData.sample( i ).interval.minValue() );
758       int x2 = theXMap.transform( myData.sample( i ).interval.maxValue() );
759       if ( x1 > x2 )
760         qSwap( x1, x2 );
761
762       if ( i < (int)myData.size() - 2 ) {
763         const int xx1 = theXMap.transform( myData.sample(i+1).interval.minValue() );
764         const int xx2 = theXMap.transform( myData.sample(i+1).interval.maxValue() );
765         if ( x2 == qwtMin( xx1, xx2 ) ) {
766           const int yy2 = theYMap.transform( myData.sample(i+1).value );
767           if ( yy2 != y0 && ( ( yy2 < y0 && y2 < y0 ) ||
768                               ( yy2 > y0 && y2 > y0 ) ) ) {
769             // One pixel distance between neighboured bars
770             x2--;
771           }
772         }
773       }
774       drawBar( thePainter, Qt::Vertical, QRect( x1, y0, x2 - x1, y2 - y0 ) );
775     }
776   }
777 }
778
779 /*!
780   Draws single bar of histogram
781 */
782 void Plot2d_HistogramQwtItem::drawBar( QPainter* thePainter,
783                                        Qt::Orientation,
784                                        const QRect& theRect ) const
785 {
786   thePainter->save();
787
788   const QColor color( thePainter->pen().color() );
789   QRect r = theRect.normalized();
790
791   const int factor = 125;
792   const QColor light( color.light( factor ) );
793   const QColor dark( color.dark( factor ) );
794
795   thePainter->setBrush( color );
796   thePainter->setPen( Qt::NoPen );
797   QwtPainter::drawRect( thePainter, r.x() + 1, r.y() + 1,
798                         r.width() - 2, r.height() - 2 );
799   thePainter->setBrush( Qt::NoBrush );
800
801   thePainter->setPen( QPen( light, 2 ) );
802   QwtPainter::drawLine( thePainter, r.left() + 1, r.top() + 2,
803                         r.right() + 1, r.top() + 2 );
804
805   thePainter->setPen( QPen( dark, 2 ) );
806   QwtPainter::drawLine( thePainter, r.left() + 1, r.bottom(),
807                         r.right() + 1, r.bottom() );
808   thePainter->setPen( QPen( light, 1 ) );
809
810   QwtPainter::drawLine( thePainter, r.left(), r.top() + 1,
811                         r.left(), r.bottom() );
812   QwtPainter::drawLine( thePainter, r.left() + 1, r.top() + 2,
813                          r.left() + 1, r.bottom() - 1 );
814   thePainter->setPen( QPen( dark, 1 ) );
815
816   QwtPainter::drawLine( thePainter, r.right() + 1, r.top() + 1,
817                         r.right() + 1, r.bottom() );
818   QwtPainter::drawLine(thePainter, r.right(), r.top() + 2,
819                         r.right(), r.bottom() - 1 );
820   thePainter->restore();
821 }
822
823 /*!
824   Constructor
825 */
826 Plot2d_HistogramItem::Plot2d_HistogramItem( const QwtText& theTitle )
827 : Plot2d_HistogramQwtItem( theTitle ),
828   Plot2d_SelectableItem(),
829   myCrossed( true )
830 {
831 }
832
833 /*!
834   Constructor
835 */
836 Plot2d_HistogramItem::Plot2d_HistogramItem( const QString& theTitle )
837 : Plot2d_HistogramQwtItem( theTitle ),
838   myCrossed( true )
839 {
840 }
841
842 /*!
843   Destructor
844 */
845 Plot2d_HistogramItem::~Plot2d_HistogramItem()
846 {
847 }
848
849 /*!
850   Get histogram bar items
851 */
852 QList<QRect> Plot2d_HistogramItem::getBars() const
853 {
854   return myBarItems;
855 }
856
857 /*!
858   Set to legend item symbol with color of item
859 */
860 void Plot2d_HistogramItem::updateLegend( const QwtPlotItem* thePlotItem,
861                                          const QList<QwtLegendData>& theLegendData )
862 {
863   if ( !thePlotItem || !thePlotItem->plot() )
864     return;
865
866   Plot2d_HistogramQwtItem::updateLegend( thePlotItem, theLegendData );
867
868   const QVariant itemInfo = thePlotItem->plot()->itemToInfo( const_cast< QwtPlotItem *>( thePlotItem ) );
869   QwtLegend *legend = dynamic_cast<QwtLegend *>( thePlotItem->plot()->legend() );
870   QWidget* widget = legend->legendWidget( itemInfo );
871
872   if ( !widget || !widget->inherits( "QwtLegendLabel" ) )
873     return;
874
875   QwtLegendLabel* label = dynamic_cast<QwtLegendLabel*>( widget );
876   if( Plot2d_QwtLegendLabel* anItem = (Plot2d_QwtLegendLabel*)( label ) ) {
877     QFontMetrics aFMetrics( anItem->font() );
878     int aSize = aFMetrics.height();
879     QPen aPen( legendPen().color() );
880     aPen.setStyle(Qt::NoPen);
881     anItem->setPen(aPen);
882     QwtSymbol* aSymbol = new QwtSymbol( QwtSymbol::Rect, QBrush( legendPen().color() ),
883                                         aPen, QSize( aSize, aSize ) );
884     anItem->setSymbol( aSymbol );
885     if( Plot2d_Plot2d* plot = dynamic_cast<Plot2d_Plot2d*>( thePlotItem->plot() ) )
886       anItem->setSymbolType( plot->getLegendSymbolType() );
887     anItem->setSelected( isSelected() );
888     anItem->updateHighlit();
889     anItem->update();
890     anItem->repaint();
891   }
892 }
893
894 /*!
895   Draws histogram object
896 */
897 void Plot2d_HistogramItem::draw( QPainter* thePainter,
898                                  const QwtScaleMap& theXMap,
899                                  const QwtScaleMap& theYMap,
900                                  const QRectF& ) const
901 {
902   // nds: clear list of bar items
903   Plot2d_HistogramItem* anItem = (Plot2d_HistogramItem*)this;
904   anItem->myBarItems.clear();
905
906   thePainter->setPen( QPen( color() ) );
907   const int x0 = theXMap.transform( baseline() );
908   const int y0 = theYMap.transform( baseline() );
909
910   const QwtIntervalSeriesData& iData = data();
911
912   for ( int i = 0; i < (int)iData.size(); i++ ) {
913     if ( testHistogramAttribute( Plot2d_HistogramItem::Xfy ) ) {
914       const int x2 = theXMap.transform( iData.sample(i).value );
915       if ( x2 == x0 )
916         continue;
917       int y1 = theYMap.transform( iData.sample(i).interval.minValue() );
918       int y2 = theYMap.transform( iData.sample(i).interval.maxValue() );
919       if ( y1 > y2 )
920         qSwap( y1, y2 );
921
922       if ( i < (int)iData.size() - 2 ) {
923         const int yy1 = theYMap.transform( iData.sample(i+1).interval.minValue() );
924         const int yy2 = theYMap.transform( iData.sample(i+1).interval.maxValue() );
925         if ( y2 == qwtMin( yy1, yy2 ) ) {
926           const int xx2 = theXMap.transform( iData.sample(i+1).interval.minValue() );
927           if ( xx2 != x0 && ( ( xx2 < x0 && x2 < x0 ) ||
928                               ( xx2 > x0 && x2 > x0 ) ) ) {
929             // One pixel distance between neighboured bars
930             y2++;
931           }
932         }
933       }
934       // nds: draw rect with the other lower rects
935       QRect aRect( x0, y1, x2 - x0, y2 - y1 );
936       drawRectAndLowers( thePainter, Qt::Horizontal, aRect );
937       anItem->myBarItems.append( aRect );
938     }
939     else {
940       const int y2 = theYMap.transform( iData.sample(i).value );
941       if ( y2 == y0 )
942         continue;
943       int x1 = theXMap.transform( iData.sample(i).interval.minValue() );
944       int x2 = theXMap.transform( iData.sample(i).interval.maxValue() );
945       if ( x1 > x2 )
946         qSwap( x1, x2 );
947
948       if ( i < (int)iData.size() - 2 ) {
949         const int xx1 = theXMap.transform( iData.sample(i+1).interval.minValue() );
950         const int xx2 = theXMap.transform( iData.sample(i+1).interval.maxValue() );
951         if ( x2 == qwtMin( xx1, xx2 ) ) {
952           const int yy2 = theYMap.transform( iData.sample(i+1).value );
953           if ( yy2 != y0 && ( ( yy2 < y0 && y2 < y0 ) ||
954                               ( yy2 > y0 && y2 > y0 ) ) ) {
955             // One pixel distance between neighboured bars
956             x2--;
957           }
958         }
959       }
960       // nds: draw rect with the other lower rects
961       QRect aRect(x1, y0, x2 - x1, y2 - y0 );
962       drawRectAndLowers( thePainter, Qt::Vertical, aRect );
963       anItem->myBarItems.append( aRect );
964     }
965   }
966 }
967
968 /*!
969   Set/clear "cross items" option
970 */
971 void Plot2d_HistogramItem::setCrossItems( bool theCross )
972 {
973   myCrossed = theCross;
974 }
975
976 /*!
977   Get "cross items" option
978 */
979 bool Plot2d_HistogramItem::isCrossItems() const
980 {
981   return myCrossed;
982 }
983
984 /*!
985   Draws bar of histogram and on it bars of histograms with lower height.
986 */
987 void Plot2d_HistogramItem::drawRectAndLowers( QPainter* thePainter,
988                                               Qt::Orientation /*theOr*/,
989                                               const QRect& theRect ) const
990 {
991   QRect aRect = theRect;
992   // theRect has inversed coordinates on Y axis.
993   // The top of the rect is bottom in standard QRect coordinates,
994   // and it bottom is the top.
995   if ( myCrossed )//&& theOr == Qt::Horizontal )
996     aRect.setTop( getCrossedTop( theRect ) );
997
998   drawBar( thePainter, Qt::Horizontal, aRect );
999 }
1000
1001 void Plot2d_HistogramItem::itemChanged()
1002 {
1003   if ( plot() )
1004     updateLegend( this, legendData() );
1005
1006   QwtPlotItem::itemChanged();
1007 }
1008
1009
1010 /*!
1011   Returns top value of the given rect in the context of other bars.
1012
1013   It's necessary to remember, that \a theRect has inverted coordinate Y.
1014 */
1015 int Plot2d_HistogramItem::getCrossedTop( const QRect& theRect ) const
1016 {
1017   int aRes = theRect.top();
1018   QwtPlot* aPlot = plot();
1019   // int aHeight = theRect.height();
1020   if ( aPlot ) {
1021     QwtPlotItemList anItems = aPlot->itemList();
1022     QwtPlotItemIterator anIt = anItems.begin(), aLast = anItems.end();
1023     Plot2d_HistogramItem* anItem;
1024     QList<QRect> aRects;
1025     for ( ; anIt != aLast; anIt++ ) {
1026       if ( !((*anIt)->rtti() == QwtPlotItem::Rtti_PlotHistogram) )
1027         continue;
1028       anItem = dynamic_cast<Plot2d_HistogramItem*>( *anIt );
1029       if( !anItem || anItem == this )
1030         continue;
1031       aRects.clear();
1032       aRects = anItem->getBars();
1033       for ( int i = 0, aSize = aRects.size(); i < aSize; i++ ) {
1034         if ( qMax( theRect.x(), aRects[i].x() ) <=
1035              qMin( theRect.left(), aRects[i].left() ) ) {
1036           if ( theRect.bottom() < aRects[i].bottom() )
1037             if ( aRects[i].bottom() < aRes )
1038               aRes = aRects[i].bottom();
1039         }
1040       }
1041     }
1042   }
1043   return aRes;
1044 }
1045
1046 QwtGraphic Plot2d_HistogramItem::legendIcon( int /*index*/, const QSizeF &size ) const
1047 {   
1048     return defaultIcon( color(), size );
1049 }
1050
1051 Plot2d_QwtLegend::Plot2d_QwtLegend( QWidget *parent ):
1052 QwtLegend( parent )
1053 {
1054   setAutoFillBackground(true);
1055 }
1056
1057 Plot2d_QwtLegend::~Plot2d_QwtLegend()
1058 {
1059 }
1060
1061 /*!
1062   Redefined method, which create a widget to be inserted into the legend.
1063 */
1064 QWidget *Plot2d_QwtLegend::createWidget( const QwtLegendData& /*data*/ ) const
1065 {
1066   Plot2d_QwtLegendLabel *label = new Plot2d_QwtLegendLabel();
1067   label->setItemMode( defaultItemMode() );
1068
1069   connect( label, SIGNAL( clicked() ), SLOT( itemClicked() ) );
1070   connect( label, SIGNAL( checked( bool ) ), SLOT( itemChecked( bool ) ) );
1071
1072   return label;
1073 }