/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ #include "precompiled_svx.hxx" #include #include #include #include #include #include #include #include #include #include #include ////////////////////////////////////////////////////////////////////////////// using namespace com::sun::star; ////////////////////////////////////////////////////////////////////////////// namespace drawinglayer { namespace primitive2d { Primitive2DReference SdrMeasurePrimitive2D::impCreatePart( const attribute::SdrLineAttribute& rLineAttribute, const basegfx::B2DHomMatrix& rObjectMatrix, const basegfx::B2DPoint& rStart, const basegfx::B2DPoint& rEnd, bool bLeftActive, bool bRightActive) const { const attribute::SdrLineStartEndAttribute& rLineStartEnd = getSdrLSTAttribute().getLineStartEnd(); basegfx::B2DPolygon aPolygon; aPolygon.append(rStart); aPolygon.append(rEnd); aPolygon.transform(rObjectMatrix); if(rLineStartEnd.isDefault() || (!bLeftActive && !bRightActive)) { return createPolygonLinePrimitive( aPolygon, rLineAttribute, attribute::SdrLineStartEndAttribute()); } if(bLeftActive && bRightActive) { return createPolygonLinePrimitive( aPolygon, rLineAttribute, rLineStartEnd); } const basegfx::B2DPolyPolygon aEmpty; const attribute::SdrLineStartEndAttribute aLineStartEnd( bLeftActive ? rLineStartEnd.getStartPolyPolygon() : aEmpty, bRightActive ? rLineStartEnd.getEndPolyPolygon() : aEmpty, bLeftActive ? rLineStartEnd.getStartWidth() : 0.0, bRightActive ? rLineStartEnd.getEndWidth() : 0.0, bLeftActive ? rLineStartEnd.isStartActive() : false, bRightActive ? rLineStartEnd.isEndActive() : false, bLeftActive ? rLineStartEnd.isStartCentered() : false, bRightActive? rLineStartEnd.isEndCentered() : false); return createPolygonLinePrimitive( aPolygon, rLineAttribute, aLineStartEnd); } Primitive2DSequence SdrMeasurePrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& aViewInformation) const { Primitive2DSequence aRetval; SdrBlockTextPrimitive2D* pBlockText = 0; basegfx::B2DRange aTextRange; double fTextX((getStart().getX() + getEnd().getX()) * 0.5); double fTextY((getStart().getX() + getEnd().getX()) * 0.5); const basegfx::B2DVector aLine(getEnd() - getStart()); const double fDistance(aLine.getLength()); const double fAngle(atan2(aLine.getY(), aLine.getX())); bool bAutoUpsideDown(false); const attribute::SdrTextAttribute rTextAttribute = getSdrLSTAttribute().getText(); const basegfx::B2DHomMatrix aObjectMatrix( basegfx::tools::createShearXRotateTranslateB2DHomMatrix(0.0, fAngle, getStart())); // preapare text, but do not add yet; it needs to be aligned to // the line geometry if(!rTextAttribute.isDefault()) { basegfx::B2DHomMatrix aTextMatrix; double fTestAngle(fAngle); if(getTextRotation()) { aTextMatrix.rotate(-90.0 * F_PI180); fTestAngle -= (90.0 * F_PI180); if(getTextAutoAngle() && fTestAngle < -F_PI) { fTestAngle += F_2PI; } } if(getTextAutoAngle()) { if(fTestAngle > (F_PI / 4.0) || fTestAngle < (-F_PI * (3.0 / 4.0))) { bAutoUpsideDown = true; } } // create primitive and get text range pBlockText = new SdrBlockTextPrimitive2D( &rTextAttribute.getSdrText(), rTextAttribute.getOutlinerParaObject(), aTextMatrix, SDRTEXTHORZADJUST_CENTER, SDRTEXTVERTADJUST_CENTER, rTextAttribute.isScroll(), false, false, false, false); aTextRange = pBlockText->getB2DRange(aViewInformation); } // prepare line attribute and result { const attribute::SdrLineAttribute rLineAttribute(getSdrLSTAttribute().getLine()); bool bArrowsOutside(false); bool bMainLineSplitted(false); const attribute::SdrLineStartEndAttribute& rLineStartEnd = getSdrLSTAttribute().getLineStartEnd(); double fStartArrowW(0.0); double fStartArrowH(0.0); double fEndArrowW(0.0); double fEndArrowH(0.0); if(!rLineStartEnd.isDefault()) { if(rLineStartEnd.isStartActive()) { const basegfx::B2DRange aArrowRange(basegfx::tools::getRange(rLineStartEnd.getStartPolyPolygon())); fStartArrowW = rLineStartEnd.getStartWidth(); fStartArrowH = aArrowRange.getHeight() * fStartArrowW / aArrowRange.getWidth(); if(rLineStartEnd.isStartCentered()) { fStartArrowH *= 0.5; } } if(rLineStartEnd.isEndActive()) { const basegfx::B2DRange aArrowRange(basegfx::tools::getRange(rLineStartEnd.getEndPolyPolygon())); fEndArrowW = rLineStartEnd.getEndWidth(); fEndArrowH = aArrowRange.getHeight() * fEndArrowW / aArrowRange.getWidth(); if(rLineStartEnd.isEndCentered()) { fEndArrowH *= 0.5; } } } const double fSpaceNeededByArrows(fStartArrowH + fEndArrowH + ((fStartArrowW + fEndArrowW) * 0.5)); const double fArrowsOutsideLen((fStartArrowH + fEndArrowH + fStartArrowW + fEndArrowW) * 0.5); const double fHalfLineWidth(rLineAttribute.getWidth() * 0.5); if(fSpaceNeededByArrows > fDistance) { bArrowsOutside = true; } MeasureTextPosition eHorizontal(getHorizontal()); MeasureTextPosition eVertical(getVertical()); if(MEASURETEXTPOSITION_AUTOMATIC == eVertical) { eVertical = MEASURETEXTPOSITION_NEGATIVE; } if(MEASURETEXTPOSITION_CENTERED == eVertical) { bMainLineSplitted = true; } if(MEASURETEXTPOSITION_AUTOMATIC == eHorizontal) { if(aTextRange.getWidth() > fDistance) { eHorizontal = MEASURETEXTPOSITION_NEGATIVE; } else { eHorizontal = MEASURETEXTPOSITION_CENTERED; } if(bMainLineSplitted) { if(aTextRange.getWidth() + fSpaceNeededByArrows > fDistance) { bArrowsOutside = true; } } else { const double fSmallArrowNeed(fStartArrowH + fEndArrowH + ((fStartArrowW + fEndArrowW) * 0.125)); if(aTextRange.getWidth() + fSmallArrowNeed > fDistance) { bArrowsOutside = true; } } } if(MEASURETEXTPOSITION_CENTERED != eHorizontal) { bArrowsOutside = true; } // switch text above/below? if(getBelow() || (bAutoUpsideDown && !getTextRotation())) { if(MEASURETEXTPOSITION_NEGATIVE == eVertical) { eVertical = MEASURETEXTPOSITION_POSITIVE; } else if(MEASURETEXTPOSITION_POSITIVE == eVertical) { eVertical = MEASURETEXTPOSITION_NEGATIVE; } } const double fMainLineOffset(getBelow() ? getDistance() : -getDistance()); const basegfx::B2DPoint aMainLeft(0.0, fMainLineOffset); const basegfx::B2DPoint aMainRight(fDistance, fMainLineOffset); // main line if(bArrowsOutside) { double fLenLeft(fArrowsOutsideLen); double fLenRight(fArrowsOutsideLen); if(!bMainLineSplitted) { if(MEASURETEXTPOSITION_NEGATIVE == eHorizontal) { fLenLeft = fStartArrowH + aTextRange.getWidth(); } else if(MEASURETEXTPOSITION_POSITIVE == eHorizontal) { fLenRight = fEndArrowH + aTextRange.getWidth(); } } const basegfx::B2DPoint aMainLeftLeft(aMainLeft.getX() - fLenLeft, aMainLeft.getY()); const basegfx::B2DPoint aMainRightRight(aMainRight.getX() + fLenRight, aMainRight.getY()); appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, impCreatePart(rLineAttribute, aObjectMatrix, aMainLeftLeft, aMainLeft, false, true)); appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, impCreatePart(rLineAttribute, aObjectMatrix, aMainRight, aMainRightRight, true, false)); if(!bMainLineSplitted || MEASURETEXTPOSITION_CENTERED != eHorizontal) { appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, impCreatePart(rLineAttribute, aObjectMatrix, aMainLeft, aMainRight, false, false)); } } else { if(bMainLineSplitted) { const double fHalfLength((fDistance - (aTextRange.getWidth() + (fStartArrowH + fEndArrowH) * 0.25)) * 0.5); const basegfx::B2DPoint aMainInnerLeft(aMainLeft.getX() + fHalfLength, aMainLeft.getY()); const basegfx::B2DPoint aMainInnerRight(aMainRight.getX() - fHalfLength, aMainRight.getY()); appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, impCreatePart(rLineAttribute, aObjectMatrix, aMainLeft, aMainInnerLeft, true, false)); appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, impCreatePart(rLineAttribute, aObjectMatrix, aMainInnerRight, aMainRight, false, true)); } else { appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, impCreatePart(rLineAttribute, aObjectMatrix, aMainLeft, aMainRight, true, true)); } } // left/right help line value preparation const double fTopEdge(getBelow() ? getUpper() + getDistance() : -getUpper() - getDistance()); const double fBottomLeft(getBelow() ? getLower() - getLeftDelta() : getLeftDelta() - getLower()); const double fBottomRight(getBelow() ? getLower() - getRightDelta() : getRightDelta() - getLower()); // left help line const basegfx::B2DPoint aLeftUp(0.0, fTopEdge); const basegfx::B2DPoint aLeftDown(0.0, fBottomLeft); appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, impCreatePart(rLineAttribute, aObjectMatrix, aLeftDown, aLeftUp, false, false)); // right help line const basegfx::B2DPoint aRightUp(fDistance, fTopEdge); const basegfx::B2DPoint aRightDown(fDistance, fBottomRight); appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, impCreatePart(rLineAttribute, aObjectMatrix, aRightDown, aRightUp, false, false)); // text horizontal position if(MEASURETEXTPOSITION_NEGATIVE == eHorizontal) { // left const double fSmall(fArrowsOutsideLen * 0.18); fTextX = aMainLeft.getX() - (fStartArrowH + aTextRange.getWidth() + fSmall + fHalfLineWidth); if(bMainLineSplitted) { fTextX -= (fArrowsOutsideLen - fStartArrowH); } if(!rTextAttribute.isDefault()) { fTextX -= rTextAttribute.getTextRightDistance(); } } else if(MEASURETEXTPOSITION_POSITIVE == eHorizontal) { // right const double fSmall(fArrowsOutsideLen * 0.18); fTextX = aMainRight.getX() + (fEndArrowH + fSmall + fHalfLineWidth); if(bMainLineSplitted) { fTextX += (fArrowsOutsideLen - fEndArrowH); } if(!rTextAttribute.isDefault()) { fTextX += rTextAttribute.getTextLeftDistance(); } } else // MEASURETEXTPOSITION_CENTERED { // centered fTextX = aMainLeft.getX() + ((fDistance - aTextRange.getWidth()) * 0.5); if(!rTextAttribute.isDefault()) { fTextX += (rTextAttribute.getTextLeftDistance() - rTextAttribute.getTextRightDistance()) / 2L; } } // text vertical position if(MEASURETEXTPOSITION_NEGATIVE == eVertical) { // top const double fSmall(fArrowsOutsideLen * 0.10); fTextY = aMainLeft.getY() - (aTextRange.getHeight() + fSmall + fHalfLineWidth); if(!rTextAttribute.isDefault()) { fTextY -= rTextAttribute.getTextLowerDistance(); } } else if(MEASURETEXTPOSITION_POSITIVE == eVertical) { // bottom const double fSmall(fArrowsOutsideLen * 0.10); fTextY = aMainLeft.getY() + (fSmall + fHalfLineWidth); if(!rTextAttribute.isDefault()) { fTextY += rTextAttribute.getTextUpperDistance(); } } else // MEASURETEXTPOSITION_CENTERED { // centered fTextY = aMainLeft.getY() - (aTextRange.getHeight() * 0.5); if(!rTextAttribute.isDefault()) { fTextY += (rTextAttribute.getTextUpperDistance() - rTextAttribute.getTextLowerDistance()) / 2L; } } } if(getSdrLSTAttribute().getLine().isDefault()) { // embed line geometry to invisible (100% transparent) line group for HitTest const Primitive2DReference xHiddenLines(new HiddenGeometryPrimitive2D(aRetval)); aRetval = Primitive2DSequence(&xHiddenLines, 1); } if(pBlockText) { // create transformation to text primitive end position basegfx::B2DHomMatrix aChange; // handle auto text rotation if(bAutoUpsideDown) { aChange.rotate(F_PI); } // move from aTextRange.TopLeft to fTextX, fTextY aChange.translate(fTextX - aTextRange.getMinX(), fTextY - aTextRange.getMinY()); // apply object matrix aChange *= aObjectMatrix; // apply to existing text primitive SdrTextPrimitive2D* pNewBlockText = pBlockText->createTransformedClone(aChange); OSL_ENSURE(pNewBlockText, "SdrMeasurePrimitive2D::create2DDecomposition: Could not create transformed clone of text primitive (!)"); delete pBlockText; // add to local primitives appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, Primitive2DReference(pNewBlockText)); } // add shadow if(!getSdrLSTAttribute().getShadow().isDefault()) { aRetval = createEmbeddedShadowPrimitive( aRetval, getSdrLSTAttribute().getShadow()); } return aRetval; } SdrMeasurePrimitive2D::SdrMeasurePrimitive2D( const attribute::SdrLineShadowTextAttribute& rSdrLSTAttribute, const basegfx::B2DPoint& rStart, const basegfx::B2DPoint& rEnd, MeasureTextPosition eHorizontal, MeasureTextPosition eVertical, double fDistance, double fUpper, double fLower, double fLeftDelta, double fRightDelta, bool bBelow, bool bTextRotation, bool bTextAutoAngle) : BufferedDecompositionPrimitive2D(), maSdrLSTAttribute(rSdrLSTAttribute), maStart(rStart), maEnd(rEnd), meHorizontal(eHorizontal), meVertical(eVertical), mfDistance(fDistance), mfUpper(fUpper), mfLower(fLower), mfLeftDelta(fLeftDelta), mfRightDelta(fRightDelta), mbBelow(bBelow), mbTextRotation(bTextRotation), mbTextAutoAngle(bTextAutoAngle) { } bool SdrMeasurePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const { if(BufferedDecompositionPrimitive2D::operator==(rPrimitive)) { const SdrMeasurePrimitive2D& rCompare = (SdrMeasurePrimitive2D&)rPrimitive; return (getStart() == rCompare.getStart() && getEnd() == rCompare.getEnd() && getHorizontal() == rCompare.getHorizontal() && getVertical() == rCompare.getVertical() && getDistance() == rCompare.getDistance() && getUpper() == rCompare.getUpper() && getLower() == rCompare.getLower() && getLeftDelta() == rCompare.getLeftDelta() && getRightDelta() == rCompare.getRightDelta() && getBelow() == rCompare.getBelow() && getTextRotation() == rCompare.getTextRotation() && getTextAutoAngle() == rCompare.getTextAutoAngle() && getSdrLSTAttribute() == rCompare.getSdrLSTAttribute()); } return false; } // provide unique ID ImplPrimitrive2DIDBlock(SdrMeasurePrimitive2D, PRIMITIVE2D_ID_SDRMEASUREPRIMITIVE2D) } // end of namespace primitive2d } // end of namespace drawinglayer ////////////////////////////////////////////////////////////////////////////// // eof