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