void AbstractDiagram::paintMarker( QPainter* painter,
                                   const DataValueAttributes& a,
                                   const QModelIndex& index,
                                   const QPointF& pos )
{
    if ( !checkInvariants() || !a.isVisible() ) return;
    const MarkerAttributes ma = a.markerAttributes();
    if ( !ma.isVisible() ) return;

    const PainterSaver painterSaver( painter );

    QSizeF maSize = ma.markerSize();
    const qreal diagramWidth = d->diagramSize.width();
    const qreal diagramHeight = d->diagramSize.height();

    switch( ma.markerSizeMode() ) {
    case MarkerAttributes::AbsoluteSize:
        // Unscaled, i.e. without the painter's "zoom"
        maSize.rwidth()  /= painter->matrix().m11();
        maSize.rheight() /= painter->matrix().m22();
        break;
    case MarkerAttributes::AbsoluteSizeScaled:
        // Keep maSize as is. It is specified directly in pixels and desired
        // to be effected by the painter's "zoom".
        break;
    case MarkerAttributes::RelativeToDiagramWidth:
        maSize *= diagramWidth;
        break;
    case MarkerAttributes::RelativeToDiagramHeight:
        maSize *= diagramHeight;
        break;
    case MarkerAttributes::RelativeToDiagramWidthHeightMin:
        maSize *= qMin( diagramWidth, diagramHeight );
        break;
    }

    QBrush indexBrush( brush( index ) );
    QPen indexPen( ma.pen() );
    if ( ma.markerColor().isValid() )
        indexBrush.setColor( ma.markerColor() );

    paintMarker( painter, ma, indexBrush, indexPen, pos, maSize );

    // workaround: BC cannot be changed, otherwise we would pass the
    // index down to next-lower paintMarker function. So far, we
    // basically save a circle of radius maSize at pos in the
    // reverseMapper. This means that ^^^ this version of paintMarker
    // needs to be called to reverse-map the marker.
    d->reverseMapper.addCircle( index.row(), index.column(), pos, 2 * maSize );
}
Esempio n. 2
0
void MainWindow::on_paintValuesCB_toggled( bool checked )
{
    const int colCount = m_lines->model()->columnCount();
    for ( int iColumn = 0; iColumn<colCount; ++iColumn ) {
        DataValueAttributes a = m_lines->dataValueAttributes( iColumn );
        a.setVisible( true );

        TextAttributes ta = a.textAttributes();
        ta.setRotation( 0 );
        ta.setFont( QFont( "Comic", 10 ) );
        ta.setPen( m_lines->brush( iColumn ).color() );
        ta.setVisible( checked );

        a.setTextAttributes( ta );
        m_lines->setDataValueAttributes( iColumn, a);
    }
}
Esempio n. 3
0
void markPeak(Plotter* p, const QModelIndex& peak, quint64 cost, const KColorScheme& scheme)
{
    QBrush brush = p->model()->data(peak, DatasetBrushRole).value<QBrush>();

    QColor outline = brush.color();
    QColor foreground = scheme.foreground().color();
    QBrush background = scheme.background();

    DataValueAttributes dataAttributes = p->dataValueAttributes(peak);
    dataAttributes.setDataLabel(prettyCost(cost));
    dataAttributes.setVisible(true);
    dataAttributes.setShowRepetitiveDataLabels(true);
    dataAttributes.setShowOverlappingDataLabels(false);

    FrameAttributes frameAttrs = dataAttributes.frameAttributes();
    QPen framePen(outline);
    framePen.setWidth(2);
    frameAttrs.setPen(framePen);
    frameAttrs.setVisible(true);
    dataAttributes.setFrameAttributes(frameAttrs);

    MarkerAttributes a = dataAttributes.markerAttributes();
    a.setMarkerSize(QSizeF(7, 7));
    a.setPen(outline);
    a.setMarkerStyle(KChart::MarkerAttributes::MarkerDiamond);
    a.setVisible(true);
    dataAttributes.setMarkerAttributes(a);

    TextAttributes txtAttrs = dataAttributes.textAttributes();
    txtAttrs.setPen(foreground);
    txtAttrs.setFontSize(Measure(12));
    dataAttributes.setTextAttributes(txtAttrs);

    BackgroundAttributes bkgAtt = dataAttributes.backgroundAttributes();

    bkgAtt.setBrush(background);
    bkgAtt.setVisible(true);
    dataAttributes.setBackgroundAttributes(bkgAtt);

    p->setDataValueAttributes(peak, dataAttributes);
}
bool DataValueAttributes::operator==( const DataValueAttributes& r ) const
{
    /*
    qDebug() << "DataValueAttributes::operator== finds"
            << "b" << (isVisible() == r.isVisible())
            << "c" << (textAttributes() == r.textAttributes())
            << "d" << (frameAttributes() == r.frameAttributes())
            << "e" << (backgroundAttributes() == r.backgroundAttributes())
            << "f" << (markerAttributes() == r.markerAttributes())
            << "g" << (decimalDigits() == r.decimalDigits())
            << "h" << (prefix() == r.prefix())
            << "i" << (suffix() == r.suffix())
            << "j" << (dataLabel() == r.dataLabel())
            << "k" << (powerOfTenDivisor() == r.powerOfTenDivisor())
            << "l" << (showInfinite() == r.showInfinite())
            << "m" << (negativePosition() == r.negativePosition())
            << "n" << (positivePosition() == r.positivePosition())
            << "o" << (showRepetitiveDataLabels() == r.showRepetitiveDataLabels())
            << "p" << (showOverlappingDataLabels() == r.showOverlappingDataLabels());
    */
    return ( isVisible() == r.isVisible() &&
            textAttributes() == r.textAttributes() &&
            frameAttributes() == r.frameAttributes() &&
            backgroundAttributes() == r.backgroundAttributes() &&
            markerAttributes() == r.markerAttributes() &&
            decimalDigits() == r.decimalDigits() &&
            prefix() == r.prefix() &&
            suffix() == r.suffix() &&
            dataLabel() == r.dataLabel() &&
            powerOfTenDivisor() == r.powerOfTenDivisor() &&
            showInfinite() == r.showInfinite() &&
            negativePosition() == r.negativePosition() &&
            positivePosition() == r.positivePosition() &&
            showRepetitiveDataLabels() == r.showRepetitiveDataLabels() &&
            showOverlappingDataLabels() == r.showOverlappingDataLabels() &&
            usePercentage() == r.usePercentage() );
}
Esempio n. 5
0
void AbstractDiagram::Private::addLabel(
    LabelPaintCache* cache,
    const QModelIndex& index,
    const CartesianDiagramDataCompressor::CachePosition* position,
    const PositionPoints& points,
    const Position& autoPositionPositive, const Position& autoPositionNegative,
    const qreal value, qreal favoriteAngle /* = 0.0 */ )
{
    CartesianDiagramDataCompressor::AggregatedDataValueAttributes allAttrs(
        aggregatedAttrs( index, position ) );

    QMap<QModelIndex, DataValueAttributes>::const_iterator it;
    for ( it = allAttrs.constBegin(); it != allAttrs.constEnd(); ++it ) {
        DataValueAttributes dva = it.value();
        if ( !dva.isVisible() ) {
            continue;
        }

        const bool isPositive = ( value >= 0.0 );

        RelativePosition relPos( dva.position( isPositive ) );
        relPos.setReferencePoints( points );
        if ( relPos.referencePosition().isUnknown() ) {
            relPos.setReferencePosition( isPositive ? autoPositionPositive : autoPositionNegative );
        }

        // Rotate the label position (not the label itself) if the diagram is rotated so that the defaults still work
        if ( isTransposed() ) {
            KChartEnums::PositionValue posValue = relPos.referencePosition().value();
            if ( posValue >= KChartEnums::PositionNorthWest && posValue <= KChartEnums::PositionWest ) {
                // rotate 90 degrees clockwise
                posValue = static_cast< KChartEnums::PositionValue >( posValue + 2 );
                if ( posValue > KChartEnums::PositionWest ) {
                    // wraparound
                    posValue = static_cast< KChartEnums::PositionValue >( posValue -
                                ( KChartEnums::PositionWest - KChartEnums::PositionNorthWest ) );
                }
                relPos.setReferencePosition( Position( posValue ) );
            }
        }

        const QPointF referencePoint = relPos.referencePoint();
        if ( !diagram->coordinatePlane()->isVisiblePoint( referencePoint ) ) {
            continue;
        }

        const qreal fontHeight = cachedFontMetrics( dva.textAttributes().
                calculatedFont( plane, KChartEnums::MeasureOrientationMinimum ), diagram )->height();

        // Note: When printing data value texts and padding's Measure is using automatic reference area
        //       detection, the font height is used as reference size for both horizontal and vertical
        //       padding.
        QSizeF relativeMeasureSize( fontHeight, fontHeight );

        if ( !dva.textAttributes().hasRotation() ) {
            TextAttributes ta = dva.textAttributes();
            ta.setRotation( favoriteAngle );
            dva.setTextAttributes( ta );
        }

        // get the size of the label text using a subset of the information going into the final layout
        const QString text = formatDataValueText( dva, index, value );
        QTextDocument doc;
        doc.setDocumentMargin( 0 );
        if ( Qt::mightBeRichText( text ) ) {
            doc.setHtml( text );
        } else {
            doc.setPlainText( text );
        }
        const QFont calculatedFont( dva.textAttributes()
                                    .calculatedFont( plane, KChartEnums::MeasureOrientationMinimum ) );
        doc.setDefaultFont( calculatedFont );

        const QRectF plainRect = doc.documentLayout()->frameBoundingRect( doc.rootFrame() );

        /**
        * A few hints on how the positioning of the text frame is done:
        *
        * Let's assume we have a bar chart, a text for a positive value
        * to be drawn, and "North" as attrs.positivePosition().
        *
        * The reference point (pos) is then set to the top center point
        * of a bar. The offset now depends on the alignment:
        *
        *    Top: text is centered horizontally to the bar, bottom of
        *         text frame starts at top of bar
        *
        *    Bottom: text is centered horizontally to the bar, top of
        *            text frame starts at top of bar
        *
        *    Center: text is centered horizontally to the bar, center
        *            line of text frame is same as top of bar
        *
        *    TopLeft: right edge of text frame is horizontal center of
        *             bar, bottom of text frame is top of bar.
        *
        *    ...
        *
        * Positive and negative value labels are treated equally, "North"
        * also refers to the top of a negative bar, and *not* to the bottom.
        *
        *
        * "NorthEast" likewise refers to the top right edge of the bar,
        * "NorthWest" to the top left edge of the bar, and so on.
        *
        * In other words, attrs.positivePosition() always refers to a
        * position of the *bar*, and relPos.alignment() always refers
        * to an alignment of the text frame relative to this position.
        */

        QTransform transform;
        {
            // move to the general area where the label should be
            QPointF calcPoint = relPos.calculatedPoint( relativeMeasureSize );
            transform.translate( calcPoint.x(), calcPoint.y() );
            // align the text rect; find out by how many half-widths / half-heights to move.
            int dx = -1;
            if ( relPos.alignment() & Qt::AlignLeft ) {
                dx -= 1;
            } else if ( relPos.alignment() & Qt::AlignRight ) {
                 dx += 1;
            }

            int dy = -1;
            if ( relPos.alignment() & Qt::AlignTop ) {
                dy -= 1;
            } else if ( relPos.alignment() & Qt::AlignBottom ) {
                dy += 1;
            }
            transform.translate( qreal( dx ) * plainRect.width() * 0.5,
                                 qreal( dy ) * plainRect.height() * 0.5 );

            // rotate the text rect around its center
            transform.translate( plainRect.center().x(), plainRect.center().y() );
            int rotation = dva.textAttributes().rotation();
            if ( !isPositive && dva.mirrorNegativeValueTextRotation() ) {
                rotation *= -1;
            }
            transform.rotate( rotation );
            transform.translate( -plainRect.center().x(), -plainRect.center().y() );
        }

        QPainterPath labelArea;
        //labelArea.addPolygon( transform.mapToPolygon( plainRect.toRect() ) );
        //labelArea.closeSubpath();
        // Not doing that because QTransform has a special case for 180° that gives a different than
        // usual ordering of the points in the polygon returned by mapToPolygon( const QRect & ).
        // We expect a particular ordering in paintDataValueTextsAndMarkers() by using elementAt( 0 ),
        // and similar things might happen elsewhere.
        labelArea.addPolygon( transform.map( QPolygon( plainRect.toRect(), true ) ) );

        // store the label geometry and auxiliary data
        cache->paintReplay.append( LabelPaintInfo( it.key(), dva, labelArea,
                                                   referencePoint, value >= 0.0, text ) );
    }
}
Esempio n. 6
0
// since DataValue markers have no relative sizing mode we need to scale them for printing
void MainWindow::paintMarkers( bool checked, const QSize& printSize )
{
    MarkerAttributes::MarkerStylesMap map;
    map.insert( 0, MarkerAttributes::MarkerSquare );
    map.insert( 1, MarkerAttributes::MarkerCircle );
    map.insert( 2, MarkerAttributes::MarkerRing );
    map.insert( 3, MarkerAttributes::MarkerCross );
    map.insert( 4, MarkerAttributes::MarkerDiamond );

    // next: Specify column- / cell-specific attributes!
    const int colCount = m_lines->model()->columnCount();
    for ( int iColumn = 0; iColumn<colCount; ++iColumn ) {
        DataValueAttributes dva = m_lines->dataValueAttributes( iColumn );
        dva.setVisible( true );
        MarkerAttributes ma( dva.markerAttributes() );

    switch ( markersStyleCB->currentIndex() ) {
        case 0:
                   ma.setMarkerStyle( MarkerAttributes::MarkerSquare );
                   break;
        case 1:
                   // Column-specific attributes
                   ma.setMarkerStyle( map.value( iColumn ) );
                   break;
        case 2:
                   ma.setMarkerStyle( MarkerAttributes::MarkerCircle );
                   break;
        case 3:
                   ma.setMarkerStyle( MarkerAttributes::MarkerDiamond );
                   break;
        case 4:
                   ma.setMarkerStyle( MarkerAttributes::Marker1Pixel );
                   break;
        case 5:
                   ma.setMarkerStyle( MarkerAttributes::Marker4Pixels );
                   break;
        case 6:
                   ma.setMarkerStyle( MarkerAttributes::MarkerRing );
                   break;
        case 7:
                   ma.setMarkerStyle( MarkerAttributes::MarkerCross );
                   break;
        case 8:
                   ma.setMarkerStyle( MarkerAttributes::MarkerFastCross );
                   break;
        default:
            Q_ASSERT( false );
    }
    ma.setVisible( checked );

        qreal factorWidth = printSize.isValid() ? ( printSize.width() / m_chart->rect().width() ) : 1.0f;
        qreal factorHeight = printSize.isValid() ? ( printSize.height() / m_chart->rect().height() ) : 1.0f;
        ma.setMarkerSize( QSize( markersWidthSB->value() * factorWidth, markersHeightSB->value() * factorHeight ) );

        dva.setMarkerAttributes( ma );
        m_lines->setDataValueAttributes( iColumn, dva );

    // make a special one for certain values
    DataValueAttributes yellowAttributes( dva );
    MarkerAttributes yellowMarker( yellowAttributes.markerAttributes() );
    yellowMarker.setMarkerColor( Qt::yellow );
    yellowAttributes.setMarkerAttributes( yellowMarker );

    const int rowCount = m_lines->model()->rowCount();
        for ( int j=0; j< rowCount; ++j ) {
            QModelIndex index = m_lines->model()->index( j, iColumn, QModelIndex() );
            QBrush brush = m_lines->model()->headerData( iColumn, Qt::Vertical, DatasetBrushRole ).value<QBrush>();
            qreal value = m_lines->model()->data( index ).toReal();
            /* Set a specific color - marker for a specific value */
            if ( value == 13 ) {
                m_lines->setDataValueAttributes( index, yellowAttributes );
            }
        }
    }
}