Salome HOME
Fix pb with persistence of "light" modules: SaveAs operation leads to loss of non...
[modules/gui.git] / src / Plot2d / Plot2d_PlotItems.cxx
1 // Copyright (C) 2007-2014  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
28 #include <QPainter>
29 #include <QPalette>
30 #include <QLayout>
31 #include <QLine>
32 #include <QVariant>
33 #include <qwt_plot.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>
39
40 const char* yAxisLeft[] = {
41   "12 12 2 1",
42   "  c None",
43   ". c #000000",
44   "            ",
45   "   .        ",
46   "  ...       ",
47   " . . .      ",
48   "   .        ",
49   "   .        ",
50   "   .    .   ",
51   "   .     .  ",
52   "   ........ ",
53   "         .  ",
54   "        .   ",
55   "            "};
56
57 const char* yAxisRight[] = {
58   "12 12 2 1",
59   "  c None",
60   ". c #000000",
61   "            ",
62   "        .   ",
63   "       ...  ",
64   "      . . . ",
65   "        .   ",
66   "        .   ",
67   "   .    .   ",
68   "  .     .   ",
69   " ........   ",
70   "  .         ",
71   "   .        ",
72   "            "};
73
74 /*!
75   Constructor of Plot2d_QwtLegendItem
76 */
77 Plot2d_QwtLegendItem::Plot2d_QwtLegendItem( QWidget* parent ) :
78   QwtLegendItem( parent ),
79   myYAxisIdentifierMode( IM_None ),
80   myIsSelected(false)
81 {
82   myYAxisLeftIcon = yAxisLeft;
83   myYAxisRightIcon = yAxisRight;
84   int anIconWidth = qMax( myYAxisLeftIcon.width(), myYAxisRightIcon.width() );
85
86   mySpacingCollapsed = spacing();
87   mySpacingExpanded = anIconWidth - mySpacingCollapsed;
88 }
89
90 /*!
91   Destructor of Plot2d_QwtLegendItem
92 */
93 Plot2d_QwtLegendItem::~Plot2d_QwtLegendItem()
94 {
95 }
96
97 /*!
98   Set Y axis identifier displaying mode
99 */
100 void Plot2d_QwtLegendItem::setYAxisIdentifierMode( const int theMode )
101 {
102   myYAxisIdentifierMode = theMode;
103   setSpacing( theMode == IM_None ? mySpacingCollapsed : mySpacingExpanded );
104 }
105
106 /*!
107   Redefined method of drawing identifier of legend item
108 */
109 void Plot2d_QwtLegendItem::drawIdentifier( QPainter* painter, const QRect& rect ) const
110 {
111   QwtLegendItem::drawIdentifier( painter, rect );
112
113   if( myYAxisIdentifierMode != IM_None ) {
114     QPixmap aPixmap( myYAxisIdentifierMode == IM_Left ? yAxisLeft : yAxisRight );
115     painter->save();
116     painter->drawPixmap( rect.topRight() + QPoint( mySpacingExpanded/2, mySpacingExpanded/2 ), aPixmap );
117     painter->restore();
118   }
119 }
120
121 /*!
122   Update highliting on the item.
123 */
124 void Plot2d_QwtLegendItem::updateHighlit() {
125   QwtText txt = text();
126   if(isSelected()) {
127     QColor highlightColor = Plot2d_Object::selectionColor();
128     if(highlightColor != txt.backgroundBrush().color()) {
129       txt.setBackgroundBrush(highlightColor);
130       setText(txt);
131     }
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));
136       setText(txt);
137     }
138   }
139 }
140
141 /*!
142   Sets selected property.
143 */
144 void Plot2d_QwtLegendItem::setSelected(const bool on) {
145   myIsSelected = on;
146 }
147
148 /*!
149   Gets selected property.
150 */
151 bool Plot2d_QwtLegendItem::isSelected() const {
152   return myIsSelected;
153 }
154
155
156 /*
157   Draw text of the item.
158 */
159 void  Plot2d_QwtLegendItem::drawText(QPainter * painter, const QRect &rect) {
160   painter->setPen( isSelected() ? Plot2d_Object::highlightedLegendTextColor() :
161                    getColorFromPalette( QPalette::Text) );
162
163   QwtLegendItem::drawText( painter, rect );
164 }
165
166 /*
167   Get color from the legend pallete by 'role' flag.
168 */
169 QColor Plot2d_QwtLegendItem::getColorFromPalette(QPalette::ColorRole role) {
170   QWidget* pw = parentWidget();
171   QColor  col = palette().color( role );
172   while( pw ) {
173     if ( qobject_cast<QwtLegend*>( pw ) ) {
174       col = pw->palette().color(role );
175       break;
176     }
177     pw = pw->parentWidget();
178   }
179   return col;
180 }
181 /*
182  * Internal class to store deviation data on the curve.
183  */
184 class Plot2d_QwtPlotCurve::Plot2d_DeviationData {
185 public:
186   Plot2d_DeviationData(const double *min, const double *max,const QList<int>& idx)
187   {
188     foreach(int index,idx) {
189       myMin[index] = min[index];
190       myMax[index] = max[index];
191     }
192   }
193   ~Plot2d_DeviationData(){}
194
195   size_t size() const
196   {
197     return qwtMin(myMin.size(), myMax.size());
198   }
199   bool values(size_t i, double &min, double &max) {
200     if(myMin.contains(i) && myMax.contains(i)) {
201       min = myMin[i];
202       max = myMax[i];
203       return true;
204     }
205     return false;
206   }
207 private:
208   QMap<int,double> myMin;
209   QMap<int,double> myMax;
210 };
211
212
213 /*!
214   Constructor of Plot2d_QwtPlotCurve
215 */
216 Plot2d_QwtPlotCurve::Plot2d_QwtPlotCurve( const QString& title,
217                                           QwtPlot::Axis yAxis /*const int index*/ ) :
218   Plot2d_SelectableItem(),
219   QwtPlotCurve( title ),
220   myYAxis( yAxis ),
221   myYAxisIdentifierEnabled( false ),
222   myDeviationData(0)
223 {
224 }
225
226 /*!
227   Destructor of Plot2d_QwtPlotCurve
228 */
229 Plot2d_QwtPlotCurve::~Plot2d_QwtPlotCurve()
230 {
231   clearDeviationData();
232 }
233
234 /*!
235   Enable / disable Y axis identifier
236 */
237 void Plot2d_QwtPlotCurve::setYAxisIdentifierEnabled( const bool on )
238 {
239   myYAxisIdentifierEnabled = on;
240 }
241
242 /*!
243   Redefined method, which updates legend of the curve
244 */
245 void Plot2d_QwtPlotCurve::updateLegend( QwtLegend* legend ) const
246 {
247   if ( !legend )
248     return;
249
250   QWidget* widget = legend->find( this );
251
252   if ( testItemAttribute(QwtPlotItem::Legend) ) {
253
254     if ( widget == NULL ) {
255       widget = legendItem();
256       if ( widget ) {
257         if ( widget->inherits("QwtLegendItem") ) {
258           QwtLegendItem *label = (QwtLegendItem *)widget;
259           label->setItemMode(legend->itemMode());
260
261           if ( plot() ) {
262             QObject::connect(label, SIGNAL(clicked()),
263                              plot(), SLOT(legendItemClicked()));
264             QObject::connect(label, SIGNAL(checked(bool)),
265                              plot(), SLOT(legendItemChecked(bool)));
266           }
267         }
268         legend->contentsWidget()->layout()->addWidget(widget);
269         legend->insert(this, widget);
270       }
271     }
272
273     QwtPlotCurve::updateLegend( legend );
274
275
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 );
283       if(isSelected()) {
284         anItem->setCurvePen(legendPen());
285         anItem->setSymbol(legendSymbol());
286       }
287       anItem->setSelected(isSelected());
288       anItem->updateHighlit();
289     }
290   }
291 }
292
293 /*!
294   Redefined method, which creates and returns legend item of the curve
295 */
296 QWidget* Plot2d_QwtPlotCurve::legendItem() const
297 {
298   return new Plot2d_QwtLegendItem;
299 }
300
301 /*!
302   Redefined method, which draw a set of points of a curve.
303 */
304 void Plot2d_QwtPlotCurve::draw(QPainter *painter,
305                                const QwtScaleMap &xMap, const QwtScaleMap &yMap,
306                                int from, int to) const
307 {
308   if (to < 0)
309     to = dataSize() - 1;
310   QwtPlotCurve::draw(painter, xMap, yMap, from, to);
311
312   //draw deviation data
313   if(hasDeviationData()) {
314     painter->save();
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);
321     painter->setPen(p);
322     for (int i = from; i <= to; i++) {
323       if(!myDeviationData->values(i,min,max)) continue;
324       xi = x(i);
325       yi = y(i);
326       xp = xMap.transform(xi);
327       ytop = yMap.transform(yi + max);
328       ybtm = yMap.transform(yi - min);
329       tickl = xp - tickSz;
330       tickr = xp + tickSz;
331       painter->drawLine(tickl,ytop,tickr,ytop);
332       painter->drawLine(xp,ytop,xp,ybtm);
333       painter->drawLine(tickl,ybtm,tickr,ybtm);
334     }
335           painter->restore();
336   }
337 }
338
339 /*!
340  * Return color of the deviation marker.
341  */
342 QColor Plot2d_QwtPlotCurve::deviationMarkerColor() const {
343   QColor c(0, 0, 127);
344   if(plot()) {
345     QVariant var = plot()->property(PLOT2D_DEVIATION_COLOR);
346     if(var.isValid())
347       c = var.value<QColor>();
348   }
349   return c;
350 }
351 /*!
352  * Return line width of the deviation marker.
353  */
354 int Plot2d_QwtPlotCurve::deviationMarkerLineWidth() const {
355   int lw = 1;
356   if(plot()) {
357     QVariant var = plot()->property(PLOT2D_DEVIATION_LW);
358     if(var.isValid())
359       lw = var.toInt();
360   }
361   return lw;
362 }
363
364 /*!
365  * Return tick size of the deviation marker.
366  */
367 int Plot2d_QwtPlotCurve::deviationMarkerTickSize() const {
368   int ts = 2;
369   if(plot()) {
370     QVariant var = plot()->property(PLOT2D_DEVIATION_TS);
371     if(var.isValid())
372       ts = var.toInt();
373   }
374   return ts;
375 }
376
377 /*!
378  * Sets deviation data for the plot item.
379  */
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);
383 }
384
385 /*!
386  * Return true if deviation is assigned to the plot item,
387    false otherwise.
388  */
389 bool Plot2d_QwtPlotCurve::hasDeviationData() const {
390   return myDeviationData != 0;
391 }
392
393 /*!
394  * Remove deviation data from the plot item.
395  */
396 void Plot2d_QwtPlotCurve::clearDeviationData()
397 {
398   if(myDeviationData)
399     delete myDeviationData;
400   myDeviationData = 0;
401 }
402
403
404
405 /*!
406   Constructor.
407 */
408 Plot2d_SelectableItem::Plot2d_SelectableItem():
409   myIsSelected(false)
410 {
411 }
412
413 /*!
414   Destructor.
415 */
416 Plot2d_SelectableItem::~Plot2d_SelectableItem()
417 {
418 }
419
420 /*!
421   Sets selected property.
422 */
423 void Plot2d_SelectableItem::setSelected( const bool on) {
424   myIsSelected = on;
425 }
426
427 /*!
428   Return selected property.
429 */
430 bool Plot2d_SelectableItem::isSelected() const {
431   return myIsSelected;
432 }
433
434 /*!
435   Sets legend pen property.
436 */
437 void Plot2d_SelectableItem::setLegendPen( const QPen & p) {
438   myLegendPen = p;
439 }
440
441 /*!
442   Return legend pen property.
443 */
444 QPen Plot2d_SelectableItem::legendPen() const {
445   return myLegendPen;
446 }
447
448 /*!
449   Sets legend symbol property.
450 */
451 void Plot2d_SelectableItem::setLegendSymbol(const QwtSymbol& s) {
452   myLegendSymbol = s;
453 }
454
455 /*!
456   Sets legend symbol property.
457 */
458 QwtSymbol Plot2d_SelectableItem::legendSymbol() const {
459   return myLegendSymbol;
460 }
461
462 /*!
463   Constructor
464 */
465 Plot2d_HistogramQwtItem::Plot2d_HistogramQwtItem( const QwtText& theTitle )
466 : QwtPlotItem( theTitle )
467 {
468   init();
469 }
470
471 /*!
472   Constructor
473 */
474 Plot2d_HistogramQwtItem::Plot2d_HistogramQwtItem( const QString& theTitle )
475 : QwtPlotItem( QwtText( theTitle ) )
476 {
477   init();
478 }
479
480 /*!
481   Destructor
482 */
483 Plot2d_HistogramQwtItem::~Plot2d_HistogramQwtItem()
484 {
485 }
486
487 /*!
488   Initialization of object
489 */
490 void Plot2d_HistogramQwtItem::init()
491 {
492   myReference = 0.0;
493   myAttributes = Plot2d_HistogramQwtItem::Auto;
494
495   setItemAttribute( QwtPlotItem::AutoScale, true );
496   setItemAttribute( QwtPlotItem::Legend,    true );
497
498   setZ( 20.0 );
499 }
500
501 /*!
502   Sets base line to object
503   @param theRef
504 */
505 void Plot2d_HistogramQwtItem::setBaseline( double theRef )
506 {
507   if ( myReference != theRef ) {
508     myReference = theRef;
509     itemChanged();
510   }
511 }
512
513 /*!
514   Returns base line of object
515 */
516 double Plot2d_HistogramQwtItem::baseline() const
517 {
518   return myReference;
519 }
520
521 /*!
522   Sets data to object
523 */
524 void Plot2d_HistogramQwtItem::setData( const QwtIntervalData& theData )
525 {
526   myData = theData;
527   itemChanged();
528 }
529
530 /*!
531   Returns data from object
532 */
533 const QwtIntervalData& Plot2d_HistogramQwtItem::data() const
534 {
535   return myData;
536 }
537
538 /*!
539   Sets color to object
540 */
541 void Plot2d_HistogramQwtItem::setColor( const QColor& theColor )
542 {
543   if ( myColor != theColor ) {
544     myColor = theColor;
545     itemChanged();
546   }
547 }
548
549 /*!
550   Returns color from object
551 */
552 QColor Plot2d_HistogramQwtItem::color() const
553 {
554   return myColor;
555 }
556
557 /*!
558   Returns bounding rect of object
559 */
560 QwtDoubleRect Plot2d_HistogramQwtItem::boundingRect() const
561 {
562   QwtDoubleRect aRect = myData.boundingRect();
563   if ( !aRect.isValid() )
564       return aRect;
565
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 );
573   }
574   else {
575     if ( aRect.bottom() < myReference )
576       aRect.setBottom( myReference );
577     else if ( aRect.top() > myReference )
578       aRect.setTop( myReference );
579   }
580   return aRect;
581 }
582
583 /*!
584   Returns type of plot object
585 */
586 int Plot2d_HistogramQwtItem::rtti() const
587 {
588   return QwtPlotItem::Rtti_PlotHistogram;
589 }
590
591 /*!
592   Sets histogram attributes
593 */
594 void Plot2d_HistogramQwtItem::setHistogramAttribute( HistogramAttribute theAttr,
595                                                      bool isOn )
596 {
597   if ( testHistogramAttribute( theAttr ) != isOn ) {
598     if ( isOn )
599       myAttributes |= theAttr;
600     else
601       myAttributes &= ~theAttr;
602
603     itemChanged();
604   }
605 }
606
607 /*!
608   Tests histogram attributes
609 */
610 bool Plot2d_HistogramQwtItem::testHistogramAttribute( HistogramAttribute theAttr ) const
611 {
612   return myAttributes & theAttr;
613 }
614
615 /*!
616   Draws histogram object
617 */
618 void Plot2d_HistogramQwtItem::draw( QPainter* thePainter,
619                                     const QwtScaleMap& theXMap,
620                                     const QwtScaleMap& theYMap,
621                                     const QRect& ) const
622 {
623   thePainter->setPen( QPen( myColor ) );
624
625   const int x0 = theXMap.transform( baseline() );
626   const int y0 = theYMap.transform( baseline() );
627
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 ) );
631       if ( x2 == x0 )
632         continue;
633       int y1 = theYMap.transform( myData.interval( i ).minValue() );
634       int y2 = theYMap.transform( myData.interval( i ).maxValue() );
635       if ( y1 > y2 )
636         qSwap( y1, y2 );
637
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
646             y2++;
647           }
648         }
649       }
650       drawBar( thePainter, Qt::Horizontal, QRect( x0, y1, x2 - x0, y2 - y1 ) );
651     }
652     else {
653       const int y2 = theYMap.transform( myData.value( i ) );
654       if ( y2 == y0 )
655         continue;
656       int x1 = theXMap.transform( myData.interval( i ).minValue() );
657       int x2 = theXMap.transform( myData.interval( i ).maxValue() );
658       if ( x1 > x2 )
659         qSwap( x1, x2 );
660
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
669             x2--;
670           }
671         }
672       }
673       drawBar( thePainter, Qt::Vertical, QRect( x1, y0, x2 - x1, y2 - y0 ) );
674     }
675   }
676 }
677
678 /*!
679   Draws single bar of histogram
680 */
681 void Plot2d_HistogramQwtItem::drawBar( QPainter* thePainter,
682                                        Qt::Orientation,
683                                        const QRect& theRect ) const
684 {
685   thePainter->save();
686
687   const QColor color( thePainter->pen().color() );
688   QRect r = theRect.normalized();
689
690   const int factor = 125;
691   const QColor light( color.light( factor ) );
692   const QColor dark( color.dark( factor ) );
693
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 );
699
700   thePainter->setPen( QPen( light, 2 ) );
701   QwtPainter::drawLine( thePainter, r.left() + 1, r.top() + 2,
702                         r.right() + 1, r.top() + 2 );
703
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 ) );
708
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 ) );
714
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();
720 }
721
722 /*!
723   Constructor
724 */
725 Plot2d_HistogramItem::Plot2d_HistogramItem( const QwtText& theTitle )
726 : Plot2d_HistogramQwtItem( theTitle ),
727   Plot2d_SelectableItem(),
728   myCrossed( true )
729 {
730 }
731
732 /*!
733   Constructor
734 */
735 Plot2d_HistogramItem::Plot2d_HistogramItem( const QString& theTitle )
736 : Plot2d_HistogramQwtItem( theTitle ),
737   myCrossed( true )
738 {
739 }
740
741 /*!
742   Destructor
743 */
744 Plot2d_HistogramItem::~Plot2d_HistogramItem()
745 {
746 }
747
748 /*!
749   Get histogram bar items
750 */
751 QList<QRect> Plot2d_HistogramItem::getBars() const
752 {
753   return myBarItems;
754 }
755
756 /*!
757   Set to legend item symbol with color of item
758 */
759 void Plot2d_HistogramItem::updateLegend( QwtLegend* theLegend ) const
760 {
761   if ( !theLegend )
762     return;
763
764   Plot2d_HistogramQwtItem::updateLegend( theLegend );
765
766   QWidget* theWidget = theLegend->find( this );
767   if ( !theWidget || !theWidget->inherits( "QwtLegendItem" ) )
768     return;
769
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();
780   anItem->update();
781 }
782
783 /*!
784   Draws histogram object
785 */
786 void Plot2d_HistogramItem::draw( QPainter* thePainter,
787                                  const QwtScaleMap& theXMap,
788                                  const QwtScaleMap& theYMap,
789                                  const QRect& ) const
790 {
791   // nds: clear list of bar items
792   Plot2d_HistogramItem* anItem = (Plot2d_HistogramItem*)this;
793   anItem->myBarItems.clear();
794
795   thePainter->setPen( QPen( color() ) );
796   const int x0 = theXMap.transform( baseline() );
797   const int y0 = theYMap.transform( baseline() );
798
799   const QwtIntervalData& iData = data();
800
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 ) );
804       if ( x2 == x0 )
805         continue;
806       int y1 = theYMap.transform( iData.interval( i ).minValue() );
807       int y2 = theYMap.transform( iData.interval( i ).maxValue() );
808       if ( y1 > y2 )
809         qSwap( y1, y2 );
810
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
819             y2++;
820           }
821         }
822       }
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 );
827     }
828     else {
829       const int y2 = theYMap.transform( iData.value( i ) );
830       if ( y2 == y0 )
831         continue;
832       int x1 = theXMap.transform( iData.interval( i ).minValue() );
833       int x2 = theXMap.transform( iData.interval( i ).maxValue() );
834       if ( x1 > x2 )
835         qSwap( x1, x2 );
836
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
845             x2--;
846           }
847         }
848       }
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 );
853     }
854   }
855 }
856
857 /*!
858   Set/clear "cross items" option
859 */
860 void Plot2d_HistogramItem::setCrossItems( bool theCross )
861 {
862   myCrossed = theCross;
863 }
864
865 /*!
866   Get "cross items" option
867 */
868 bool Plot2d_HistogramItem::isCrossItems() const
869 {
870   return myCrossed;
871 }
872
873 /*!
874   Redefined method, which creates and returns legend item of the curve
875 */
876 QWidget* Plot2d_HistogramItem::legendItem() const
877 {
878   return new Plot2d_QwtLegendItem;
879 }
880
881
882 /*!
883   Draws bar of histogram and on it bars of histograms with lower height.
884 */
885 void Plot2d_HistogramItem::drawRectAndLowers( QPainter* thePainter,
886                                               Qt::Orientation theOr,
887                                               const QRect& theRect ) const
888 {
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 ) );
895
896   drawBar( thePainter, Qt::Horizontal, aRect );
897 }
898
899 /*!
900   Returns top value of the given rect in the context of other bars.
901
902   It's necessary to remember, that \a theRect has inverted coordinate Y.
903 */
904 int Plot2d_HistogramItem::getCrossedTop( const QRect& theRect ) const
905 {
906   int aRes = theRect.top();
907   QwtPlot* aPlot = plot();
908   // int aHeight = theRect.height();
909   if ( aPlot ) {
910     QwtPlotItemList anItems = aPlot->itemList();
911     QwtPlotItemIterator anIt = anItems.begin(), aLast = anItems.end();
912     Plot2d_HistogramItem* anItem;
913     QList<QRect> aRects;
914     for ( ; anIt != aLast; anIt++ ) {
915       if ( !((*anIt)->rtti() == QwtPlotItem::Rtti_PlotHistogram) )
916         continue;
917       anItem = dynamic_cast<Plot2d_HistogramItem*>( *anIt );
918       if( !anItem || anItem == this )
919         continue;
920       aRects.clear();
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();
928         }
929       }
930     }
931   }
932   return aRes;
933 }