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