/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * 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 .
*/
struct ImpMeasurePoly
{
ImpLineRec aMainline1; // those with the 1st arrowhead
ImpLineRec aMainline2; // those with the 2nd arrowhead
ImpLineRec aMainline3; // those in between
ImpLineRec aHelpline1;
ImpLineRec aHelpline2;
Size aTextSize;
tools::Long nLineLen;
Degree100 nLineAngle;
Degree100 nTextAngle;
Degree100 nHlpAngle; double nLineSin; double nLineCos;
sal_uInt16 nMainlineCnt;
css::drawing::MeasureTextHorzPos eUsedTextHPos;
css::drawing::MeasureTextVertPos eUsedTextVPos;
tools::Long nLineWdt2; // half the line width
tools::Long nArrow1Len; // length of 1st arrowhead; for Center, use only half
tools::Long nArrow2Len; // length of 2nd arrowhead; for Center, use only half
tools::Long nArrow1Wdt; // width of 1st arrow
tools::Long nArrow2Wdt; // width of 2nd arrow
tools::Long nShortLineLen; // line length, if PfeileAussen (arrowheads on the outside) bool bAutoUpsideDown; // UpsideDown via automation bool bBreakedLine;
};
void SdrMeasureObj::ImpCalcGeometrics(const ImpMeasureRec& rRec, ImpMeasurePoly& rPol) const
{
Point aP1(rRec.aPt1);
Point aP2(rRec.aPt2);
Point aDelt(aP2); aDelt-=aP1;
// nArrowLen is already halved at bCenter. // In the case of 2 arrowheads each 4mm long, we can't go below 10mm.
nArrowNeed=nArrow1Len+nArrow2Len+(nArrow1Wdt+nArrow2Wdt)/2; if (rPol.nLineLen<nArrowNeed) bPfeileAussen = true;
nShortLen=(nArrow1Len+nArrow1Wdt + nArrow2Len+nArrow2Wdt) /2;
rPol.eUsedTextHPos=rRec.eWantTextHPos;
rPol.eUsedTextVPos=rRec.eWantTextVPos; if (rPol.eUsedTextVPos == css::drawing::MeasureTextVertPos_AUTO)
rPol.eUsedTextVPos = css::drawing::MeasureTextVertPos_EAST; bool bBrkLine=false; if (rPol.eUsedTextVPos == css::drawing::MeasureTextVertPos_CENTERED)
{
OutlinerParaObject* pOutlinerParaObject = SdrTextObj::GetOutlinerParaObject(); if (pOutlinerParaObject!=nullptr && pOutlinerParaObject->GetTextObject().GetParagraphCount()==1)
{
bBrkLine=true; // dashed line if there's only on paragraph.
}
}
rPol.bBreakedLine=bBrkLine; if (rPol.eUsedTextHPos==css::drawing::MeasureTextHorzPos_AUTO) { // if text is too wide, push it outside bool bOutside = false;
tools::Long nNeedSiz=!rRec.bTextRota90 ? rPol.aTextSize.Width() : rPol.aTextSize.Height(); if (nNeedSiz>rPol.nLineLen) bOutside = true; // text doesn't fit in between if (bBrkLine) { if (nNeedSiz+nArrowNeed>rPol.nLineLen) bPfeileAussen = true; // text fits in between, if arrowheads are on the outside
} else {
tools::Long nSmallNeed=nArrow1Len+nArrow2Len+(nArrow1Wdt+nArrow2Wdt)/2/4; if (nNeedSiz+nSmallNeed>rPol.nLineLen) bPfeileAussen = true; // text fits in between, if arrowheads are on the outside
}
rPol.eUsedTextHPos=bOutside ? css::drawing::MeasureTextHorzPos_LEFTOUTSIDE : css::drawing::MeasureTextHorzPos_INSIDE;
} if (rPol.eUsedTextHPos != css::drawing::MeasureTextHorzPos_INSIDE) bPfeileAussen = true;
rPol.nArrow1Wdt=nArrow1Wdt;
rPol.nArrow2Wdt=nArrow2Wdt;
rPol.nShortLineLen=nShortLen;
rPol.nArrow1Len=nArrow1Len;
rPol.nArrow2Len=nArrow2Len;
// determine TextSize including text frame margins
Size aTextSize2(aMPol.aTextSize); if (aTextSize2.Width()<1) aTextSize2.setWidth(1 ); if (aTextSize2.Height()<1) aTextSize2.setHeight(1 );
aTextSize2.AdjustWidth(GetTextLeftDistance()+GetTextRightDistance() );
aTextSize2.AdjustHeight(GetTextUpperDistance()+GetTextLowerDistance() );
Point aPt1b(aMPol.aMainline1.aP1);
tools::Long nLen=aMPol.nLineLen;
tools::Long nLWdt=aMPol.nLineWdt2;
tools::Long nArr1Len=aMPol.nArrow1Len;
tools::Long nArr2Len=aMPol.nArrow2Len; if (aMPol.bBreakedLine) { // In the case of a dashed line and Outside, the text should be // placed next to the line at the arrowhead instead of directly // at the arrowhead.
nArr1Len=aMPol.nShortLineLen+aMPol.nArrow1Wdt/4;
nArr2Len=aMPol.nShortLineLen+aMPol.nArrow2Wdt/4;
}
Point aTextPos; bool bRota90=aRec.bTextRota90; bool bUpsideDown=aRec.bTextUpsideDown!=aMPol.bAutoUpsideDown; bool bBelowRefEdge=aRec.bBelowRefEdge;
css::drawing::MeasureTextHorzPos eMH=aMPol.eUsedTextHPos;
css::drawing::MeasureTextVertPos eMV=aMPol.eUsedTextVPos; if (!bRota90) { switch (eMH) { case css::drawing::MeasureTextHorzPos_LEFTOUTSIDE: aTextPos.setX(aPt1b.X()-aTextSize2.Width()-nArr1Len-nLWdt ); break; case css::drawing::MeasureTextHorzPos_RIGHTOUTSIDE: aTextPos.setX(aPt1b.X()+nLen+nArr2Len+nLWdt ); break; default: aTextPos.setX(aPt1b.X() ); aTextSize2.setWidth(nLen );
} switch (eMV) { case css::drawing::MeasureTextVertPos_CENTERED:
aTextPos.setY(aPt1b.Y()-aTextSize2.Height()/2 ); break; case css::drawing::MeasureTextVertPos_WEST: { if (!bUpsideDown) aTextPos.setY(aPt1b.Y()+nLWdt ); else aTextPos.setY(aPt1b.Y()-aTextSize2.Height()-nLWdt );
} break; default: { if (!bUpsideDown) aTextPos.setY(aPt1b.Y()-aTextSize2.Height()-nLWdt ); else aTextPos.setY(aPt1b.Y()+nLWdt );
}
} if (bUpsideDown) {
aTextPos.AdjustX(aTextSize2.Width() );
aTextPos.AdjustY(aTextSize2.Height() );
}
} else { // also if bTextRota90==TRUE switch (eMH) { case css::drawing::MeasureTextHorzPos_LEFTOUTSIDE: aTextPos.setX(aPt1b.X()-aTextSize2.Height()-nArr1Len ); break; case css::drawing::MeasureTextHorzPos_RIGHTOUTSIDE: aTextPos.setX(aPt1b.X()+nLen+nArr2Len ); break; default: aTextPos.setX(aPt1b.X() ); aTextSize2.setHeight(nLen );
} switch (eMV) { case css::drawing::MeasureTextVertPos_CENTERED:
aTextPos.setY(aPt1b.Y()+aTextSize2.Width()/2 ); break; case css::drawing::MeasureTextVertPos_WEST: { if (!bBelowRefEdge) aTextPos.setY(aPt1b.Y()+aTextSize2.Width()+nLWdt ); else aTextPos.setY(aPt1b.Y()-nLWdt );
} break; default: { if (!bBelowRefEdge) aTextPos.setY(aPt1b.Y()-nLWdt ); else aTextPos.setY(aPt1b.Y()+aTextSize2.Width()+nLWdt );
}
} if (bUpsideDown) {
aTextPos.AdjustX(aTextSize2.Height() );
aTextPos.AdjustY( -(aTextSize2.Width()) );
}
} if (aMPol.nTextAngle != maGeo.m_nRotationAngle) { const_cast<SdrMeasureObj*>(this)->maGeo.m_nRotationAngle=aMPol.nTextAngle; const_cast<SdrMeasureObj*>(this)->maGeo.RecalcSinCos();
}
RotatePoint(aTextPos,aPt1b,aMPol.nLineSin,aMPol.nLineCos);
aTextSize2.AdjustWidth( 1 ); aTextSize2.AdjustHeight( 1 ); // because of the Rect-Ctor's odd behavior
rRect=tools::Rectangle(aTextPos,aTextSize2);
rRect.Normalize(); const_cast<SdrMeasureObj*>(this)->setRectangle(rRect);
if (aMPol.nTextAngle != maGeo.m_nRotationAngle) { const_cast<SdrMeasureObj*>(this)->maGeo.m_nRotationAngle=aMPol.nTextAngle; const_cast<SdrMeasureObj*>(this)->maGeo.RecalcSinCos();
}
}
rtl::Reference<SdrObject> SdrMeasureObj::DoConvertToPolyObj(bool bBezier, bool bAddText) const
{ // get XOR Poly as base
XPolyPolygon aTmpPolyPolygon(TakeXorPoly());
// get local ItemSet and StyleSheet
SfxItemSet aSet(GetObjectItemSet());
SfxStyleSheet* pStyleSheet = GetStyleSheet();
// prepare group
rtl::Reference<SdrObjGroup> pGroup(new SdrObjGroup(getSdrModelFromSdrObject()));
if(nCount == 3)
{ // three lines, first one is the middle one
aPolyPoly.clear();
aPolyPoly.append(aTmpPolyPolygon[0].getB2DPolygon());
pPath = new SdrPathObj(
getSdrModelFromSdrObject(),
SdrObjKind::PathLine,
aPolyPoly);
pPath->SetMergedItemSet(aSet);
pPath->SetStyleSheet(pStyleSheet, true);
pGroup->GetSubList()->NbcInsertObject(pPath.get());
aSet.Put(XLineStartWidthItem(0));
aSet.Put(XLineEndWidthItem(0));
nLoopStart = 1;
} elseif(nCount == 4)
{ // four lines, middle line with gap, so there are two lines used // which have one arrow each
sal_Int32 nEndWidth = aSet.Get(XATTR_LINEENDWIDTH).GetValue();
aSet.Put(XLineEndWidthItem(0));
aPolyPoly.clear();
aPolyPoly.append(aTmpPolyPolygon[0].getB2DPolygon());
pPath = new SdrPathObj(
getSdrModelFromSdrObject(),
SdrObjKind::PathLine,
aPolyPoly);
aSet.Put(XLineEndWidthItem(0));
nLoopStart = 2;
} elseif(nCount == 5)
{ // five lines, first two are the outer ones
sal_Int32 nEndWidth = aSet.Get(XATTR_LINEENDWIDTH).GetValue();
aSet.Put(XLineEndWidthItem(0));
aPolyPoly.clear();
aPolyPoly.append(aTmpPolyPolygon[0].getB2DPolygon());
pPath = new SdrPathObj(
getSdrModelFromSdrObject(),
SdrObjKind::PathLine,
aPolyPoly);
// TODO: bTextUpsideDown should be interpreted here! if (!bTextRota90) { if (eMH==css::drawing::MeasureTextHorzPos_LEFTOUTSIDE) eTH=SDRTEXTHORZADJUST_RIGHT; if (eMH==css::drawing::MeasureTextHorzPos_RIGHTOUTSIDE) eTH=SDRTEXTHORZADJUST_LEFT; // at eMH==css::drawing::MeasureTextHorzPos_INSIDE we can anchor horizontally if (eMV==css::drawing::MeasureTextVertPos_EAST) eTV=SDRTEXTVERTADJUST_BOTTOM; if (eMV==css::drawing::MeasureTextVertPos_WEST) eTV=SDRTEXTVERTADJUST_TOP; if (eMV==css::drawing::MeasureTextVertPos_CENTERED) eTV=SDRTEXTVERTADJUST_CENTER;
} else { if (eMH==css::drawing::MeasureTextHorzPos_LEFTOUTSIDE) eTV=SDRTEXTVERTADJUST_BOTTOM; if (eMH==css::drawing::MeasureTextHorzPos_RIGHTOUTSIDE) eTV=SDRTEXTVERTADJUST_TOP; // at eMH==css::drawing::MeasureTextHorzPos_INSIDE we can anchor vertically if (!bBelowRefEdge) { if (eMV==css::drawing::MeasureTextVertPos_EAST) eTH=SDRTEXTHORZADJUST_LEFT; if (eMV==css::drawing::MeasureTextVertPos_WEST) eTH=SDRTEXTHORZADJUST_RIGHT;
} else { if (eMV==css::drawing::MeasureTextVertPos_EAST) eTH=SDRTEXTHORZADJUST_RIGHT; if (eMV==css::drawing::MeasureTextVertPos_WEST) eTH=SDRTEXTHORZADJUST_LEFT;
} if (eMV==css::drawing::MeasureTextVertPos_CENTERED) eTH=SDRTEXTHORZADJUST_CENTER;
}
EEAnchorMode eRet=EEAnchorMode::BottomHCenter; if (eTH==SDRTEXTHORZADJUST_LEFT) { if (eTV==SDRTEXTVERTADJUST_TOP) eRet=EEAnchorMode::TopLeft; elseif (eTV==SDRTEXTVERTADJUST_BOTTOM) eRet=EEAnchorMode::BottomLeft; else eRet=EEAnchorMode::VCenterLeft;
} elseif (eTH==SDRTEXTHORZADJUST_RIGHT) { if (eTV==SDRTEXTVERTADJUST_TOP) eRet=EEAnchorMode::TopRight; elseif (eTV==SDRTEXTVERTADJUST_BOTTOM) eRet=EEAnchorMode::BottomRight; else eRet=EEAnchorMode::VCenterRight;
} else { if (eTV==SDRTEXTVERTADJUST_TOP) eRet=EEAnchorMode::TopHCenter; elseif (eTV==SDRTEXTVERTADJUST_BOTTOM) eRet=EEAnchorMode::BottomHCenter; else eRet=EEAnchorMode::VCenterHCenter;
} return eRet;
}
// #i97878# // TRGetBaseGeometry/TRSetBaseGeometry needs to be based on two positions, // same as line geometry in SdrPathObj. Thus needs to be overridden and // implemented since currently it is derived from SdrTextObj which uses // a functionality based on SnapRect which is not useful here
bool SdrMeasureObj::TRGetBaseGeometry(basegfx::B2DHomMatrix& rMatrix, basegfx::B2DPolyPolygon& /*rPolyPolygon*/) const
{ // handle the same as a simple line since the definition is based on two points const basegfx::B2DRange aRange(m_aPt1.X(), m_aPt1.Y(), m_aPt2.X(), m_aPt2.Y());
basegfx::B2DTuple aScale(aRange.getRange());
basegfx::B2DTuple aTranslate(aRange.getMinimum());
// build return value matrix
rMatrix = basegfx::utils::createScaleTranslateB2DHomMatrix(aScale, aTranslate);
returntrue;
}
void SdrMeasureObj::TRSetBaseGeometry(const basegfx::B2DHomMatrix& rMatrix, const basegfx::B2DPolyPolygon& /*rPolyPolygon*/)
{ // use given transformation to derive the two defining points from unit line
basegfx::B2DPoint aPosA(rMatrix * basegfx::B2DPoint(0.0, 0.0));
basegfx::B2DPoint aPosB(rMatrix * basegfx::B2DPoint(1.0, 0.0));
if( getSdrModelFromSdrObject().IsWriter() )
{ // if anchor is used, make position relative to it if(GetAnchorPos().X() || GetAnchorPos().Y())
{ const basegfx::B2DVector aAnchorOffset(GetAnchorPos().X(), GetAnchorPos().Y());
// derive new model data const Point aNewPt1(basegfx::fround<tools::Long>(aPosA.getX()), basegfx::fround<tools::Long>(aPosA.getY())); const Point aNewPt2(basegfx::fround<tools::Long>(aPosB.getX()), basegfx::fround<tools::Long>(aPosB.getY()));
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.