| /************************************************************** |
| * |
| * 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 <svx/sdr/primitive2d/sdrmeasureprimitive2d.hxx> |
| #include <svx/sdr/primitive2d/sdrdecompositiontools.hxx> |
| #include <basegfx/matrix/b2dhommatrix.hxx> |
| #include <svx/sdr/primitive2d/sdrtextprimitive2d.hxx> |
| #include <svx/sdr/attribute/sdrtextattribute.hxx> |
| #include <basegfx/polygon/b2dpolypolygontools.hxx> |
| #include <basegfx/tools/canvastools.hxx> |
| #include <drawinglayer/primitive2d/groupprimitive2d.hxx> |
| #include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx> |
| #include <basegfx/matrix/b2dhommatrixtools.hxx> |
| #include <drawinglayer/primitive2d/hiddengeometryprimitive2d.hxx> |
| |
| ////////////////////////////////////////////////////////////////////////////// |
| |
| 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); |
| |
| if(rLineStartEnd.isDefault() || (!bLeftActive && !bRightActive)) |
| { |
| return createPolygonLinePrimitive( |
| aPolygon, |
| rObjectMatrix, |
| rLineAttribute, |
| attribute::SdrLineStartEndAttribute()); |
| } |
| |
| if(bLeftActive && bRightActive) |
| { |
| return createPolygonLinePrimitive( |
| aPolygon, |
| rObjectMatrix, |
| 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, rObjectMatrix, 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 |