void Ambitus::draw(QPainter* p) const { qreal _spatium = spatium(); qreal lw = lineWidth().val() * _spatium; p->setPen(QPen(curColor(), lw, Qt::SolidLine, Qt::RoundCap)); drawSymbol(noteHead(), p, _topPos); drawSymbol(noteHead(), p, _bottomPos); if (_hasLine) p->drawLine(_line); // draw ledger lines (if not in a palette) if (segment() && track() > -1) { int tick = segment()->tick(); Staff* stf = score()->staff(staffIdx()); qreal lineDist = stf->lineDistance(tick); int numOfLines = stf->lines(tick); qreal step = lineDist * _spatium; qreal stepTolerance = step * 0.1; qreal ledgerOffset = score()->styleS(Sid::ledgerLineLength).val() * 0.5 * _spatium; p->setPen(QPen(curColor(), score()->styleS(Sid::ledgerLineWidth).val() * _spatium, Qt::SolidLine, Qt::RoundCap) ); if (_topPos.y()-stepTolerance <= -step) { qreal xMin = _topPos.x() - ledgerOffset; qreal xMax = _topPos.x() + headWidth() + ledgerOffset; for (qreal y = -step; y >= _topPos.y()-stepTolerance; y -= step) p->drawLine(QPointF(xMin, y), QPointF(xMax, y)); } if (_bottomPos.y()+stepTolerance >= numOfLines * step) { qreal xMin = _bottomPos.x() - ledgerOffset; qreal xMax = _bottomPos.x() + headWidth() + ledgerOffset; for (qreal y = numOfLines*step; y <= _bottomPos.y()+stepTolerance; y += step) p->drawLine(QPointF(xMin, y), QPointF(xMax, y)); } } }
QgsStringMap QgsArrowSymbolLayer::properties() const { QgsStringMap map; map["arrow_width"] = QString::number( arrowWidth() ); map["arrow_width_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( arrowWidthUnit() ); map["arrow_width_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( arrowWidthUnitScale() ); map["arrow_start_width"] = QString::number( arrowStartWidth() ); map["arrow_start_width_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( arrowStartWidthUnit() ); map["arrow_start_width_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( arrowStartWidthUnitScale() ); map["is_curved"] = QString::number( isCurved() ? 1 : 0 ); map["is_repeated"] = QString::number( isRepeated() ? 1 : 0 ); map["head_width"] = QString::number( headWidth() ); map["head_width_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( headWidthUnit() ); map["head_width_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( headWidthUnitScale() ); map["head_height"] = QString::number( headHeight() ); map["head_height_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( headHeightUnit() ); map["head_height_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( headHeightUnitScale() ); map["head_type"] = QString::number( headType() ); map["arrow_type"] = QString::number( arrowType() ); map["offset"] = QString::number( offset() ); map["offset_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( offsetUnit() ); map["offset_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( offsetMapUnitScale() ); saveDataDefinedProperties( map ); return map; }
void Ambitus::layout() { int bottomLine, topLine; ClefType clf; qreal headWdt = headWidth(); Key key; qreal lineDist; int numOfLines; Segment* segm = segment(); qreal _spatium = spatium(); Staff* stf = nullptr; if (segm && track() > -1) { int tick = segm->tick(); stf = score()->staff(staffIdx()); lineDist = stf->lineDistance(tick) * _spatium; numOfLines = stf->lines(tick); clf = stf->clef(tick); } else { // for use in palettes lineDist = _spatium; numOfLines = 3; clf = ClefType::G; } // // NOTEHEADS Y POS // // if pitch == INVALID_PITCH oor tpc == INALID_TPC, set to some default: // for use in palettes and when actual range cannot be calculated (new ambitus or no notes in staff) // qreal xAccidOffTop = 0; qreal xAccidOffBottom = 0; if (stf) key = stf->key(segm->tick()); else key = Key::C; // top notehead if (_topPitch == INVALID_PITCH || _topTpc == Tpc::TPC_INVALID) _topPos.setY(0); // if uninitialized, set to top staff line else { topLine = absStep(_topTpc, _topPitch); topLine = relStep(topLine, clf); _topPos.setY(topLine * lineDist * 0.5); // compute accidental AccidentalType accidType; // if (13 <= (tpc - key) <= 19) there is no accidental) if (_topTpc - int(key) >= 13 && _topTpc - int(key) <= 19) accidType = AccidentalType::NONE; else { AccidentalVal accidVal = AccidentalVal( (_topTpc - Tpc::TPC_MIN) / TPC_DELTA_SEMITONE - 2 ); accidType = Accidental::value2subtype(accidVal); if (accidType == AccidentalType::NONE) accidType = AccidentalType::NATURAL; } _topAccid.setAccidentalType(accidType); if (accidType != AccidentalType::NONE) _topAccid.layout(); else _topAccid.setbbox(QRect()); _topAccid.rypos() = _topPos.y(); } // bottom notehead if (_bottomPitch == INVALID_PITCH || _bottomTpc == Tpc::TPC_INVALID) _bottomPos.setY( (numOfLines-1) * lineDist); // if uninitialized, set to last staff line else { bottomLine = absStep(_bottomTpc, _bottomPitch); bottomLine = relStep(bottomLine, clf); _bottomPos.setY(bottomLine * lineDist * 0.5); // compute accidental AccidentalType accidType; if (_bottomTpc - int(key) >= 13 && _bottomTpc - int(key) <= 19) accidType = AccidentalType::NONE; else { AccidentalVal accidVal = AccidentalVal( (_bottomTpc - Tpc::TPC_MIN) / TPC_DELTA_SEMITONE - 2 ); accidType = Accidental::value2subtype(accidVal); if (accidType == AccidentalType::NONE) accidType = AccidentalType::NATURAL; } _bottomAccid.setAccidentalType(accidType); if (accidType != AccidentalType::NONE) _bottomAccid.layout(); else _bottomAccid.setbbox(QRect()); _bottomAccid.rypos() = _bottomPos.y(); } // // NOTEHEAD X POS // // Note: manages colliding accidentals // qreal accNoteDist = point(score()->styleS(Sid::accidentalNoteDistance)); xAccidOffTop = _topAccid.width() + accNoteDist; xAccidOffBottom = _bottomAccid.width() + accNoteDist; // if top accidental extends down more than bottom accidental extends up, // AND ambitus is not leaning right, bottom accidental needs to be displaced bool collision = (_topAccid.ipos().y() + _topAccid.bbox().y() + _topAccid.height() > _bottomAccid.ipos().y() + _bottomAccid.bbox().y() ) && _dir != MScore::DirectionH::RIGHT; if (collision) { // displace bottom accidental (also attempting to 'undercut' flats) xAccidOffBottom = xAccidOffTop + ((_bottomAccid.accidentalType() == AccidentalType::FLAT || _bottomAccid.accidentalType() == AccidentalType::FLAT2 || _bottomAccid.accidentalType() == AccidentalType::NATURAL) ? _bottomAccid.width() * 0.5 : _bottomAccid.width()); } switch (_dir) { case MScore::DirectionH::AUTO: // noteheads one above the other // left align noteheads and right align accidentals 'hanging' on the left _topPos.setX(0.0); _bottomPos.setX(0.0); _topAccid.rxpos() = - xAccidOffTop; _bottomAccid.rxpos() = - xAccidOffBottom; break; case MScore::DirectionH::LEFT: // top notehead at the left of bottom notehead // place top notehead at left margin; bottom notehead at right of top head; // top accid. 'hanging' on left of top head and bottom accid. 'hanging' at left of bottom head _topPos.setX(0.0); _bottomPos.setX(headWdt); _topAccid.rxpos() = - xAccidOffTop; _bottomAccid.rxpos() = collision ? - xAccidOffBottom : headWdt - xAccidOffBottom; break; case MScore::DirectionH::RIGHT: // top notehead at the right of bottom notehead // bottom notehead at left margin; top notehead at right of bottomnotehead // top accid. 'hanging' on left of top head and bottom accid. 'hanging' at left of bottom head _bottomPos.setX(0.0); _topPos.setX(headWdt); _bottomAccid.rxpos() = - xAccidOffBottom; _topAccid.rxpos() = headWdt - xAccidOffTop; break; } // compute line from top note centre to bottom note centre QLineF fullLine(_topPos.x() + headWdt*0.5, _topPos.y(), _bottomPos.x() + headWdt*0.5, _bottomPos.y()); // shorten line on each side by offsets qreal yDelta = _bottomPos.y() - _topPos.y(); if (yDelta != 0.0) { qreal off = _spatium * LINEOFFSET_DEFAULT; QPointF p1 = fullLine.pointAt(off / yDelta); QPointF p2 = fullLine.pointAt(1 - (off / yDelta)); _line = QLineF(p1, p2); } else _line = fullLine; QRectF headRect = QRectF(0, -0.5*_spatium, headWdt, 1*_spatium); setbbox(headRect.translated(_topPos).united(headRect.translated(_bottomPos)) .united(_topAccid.bbox().translated(_topAccid.ipos())) .united(_bottomAccid.bbox().translated(_bottomAccid.ipos())) ); }
void QgsArrowSymbolLayer::_resolveDataDefined( QgsSymbolV2RenderContext& context ) { if ( !hasDataDefinedProperties() ) return; // shortcut if case there is no data defined properties at all bool ok; if ( hasDataDefinedProperty( "arrow_width" ) ) { context.setOriginalValueVariable( arrowWidth() ); double w = evaluateDataDefinedProperty( "arrow_width", context, QVariant(), &ok ).toDouble(); if ( ok ) { mScaledArrowWidth = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), w, arrowWidthUnit(), arrowWidthUnitScale() ); } } if ( hasDataDefinedProperty( "arrow_start_width" ) ) { context.setOriginalValueVariable( arrowStartWidth() ); double w = evaluateDataDefinedProperty( "arrow_start_width", context, QVariant(), &ok ).toDouble(); if ( ok ) { mScaledArrowStartWidth = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), w, arrowStartWidthUnit(), arrowStartWidthUnitScale() ); } } if ( hasDataDefinedProperty( "head_width" ) ) { context.setOriginalValueVariable( headWidth() ); double w = evaluateDataDefinedProperty( "head_width", context, QVariant(), &ok ).toDouble(); if ( ok ) { mScaledHeadWidth = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), w, headWidthUnit(), headWidthUnitScale() ); } } if ( hasDataDefinedProperty( "head_height" ) ) { context.setOriginalValueVariable( headHeight() ); double w = evaluateDataDefinedProperty( "head_height", context, QVariant(), &ok ).toDouble(); if ( ok ) { mScaledHeadHeight = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), w, headHeightUnit(), headHeightUnitScale() ); } } if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_OFFSET ) ) { context.setOriginalValueVariable( offset() ); double w = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_OFFSET, context, QVariant(), &ok ).toDouble(); if ( ok ) { mScaledOffset = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), w, offsetUnit(), offsetMapUnitScale() ); } } if ( hasDataDefinedProperty( "head_type" ) ) { context.setOriginalValueVariable( headType() ); int h = evaluateDataDefinedProperty( "head_type", context, QVariant(), &ok ).toInt(); if ( ok ) { mComputedHeadType = static_cast<HeadType>( h ); } } if ( hasDataDefinedProperty( "arrow_type" ) ) { context.setOriginalValueVariable( arrowType() ); int h = evaluateDataDefinedProperty( "arrow_type", context, QVariant(), &ok ).toInt(); if ( ok ) { mComputedArrowType = static_cast<ArrowType>( h ); } } }
void QgsArrowSymbolLayer::startRender( QgsSymbolV2RenderContext& context ) { mExpressionScope.reset( new QgsExpressionContextScope() ); mScaledArrowWidth = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), arrowWidth(), arrowWidthUnit(), arrowWidthUnitScale() ); mScaledArrowStartWidth = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), arrowStartWidth(), arrowStartWidthUnit(), arrowStartWidthUnitScale() ); mScaledHeadWidth = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), headWidth(), headWidthUnit(), headWidthUnitScale() ); mScaledHeadHeight = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), headHeight(), headHeightUnit(), headHeightUnitScale() ); mScaledOffset = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), offset(), offsetUnit(), offsetMapUnitScale() ); mComputedHeadType = headType(); mComputedArrowType = arrowType(); mSymbol->startRender( context.renderContext() ); }