| /************************************************************** |
| * |
| * 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. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_sw.hxx" |
| #include <ascharanchoredobjectposition.hxx> |
| #include <frame.hxx> |
| #include <txtfrm.hxx> |
| #include <flyfrms.hxx> |
| #ifndef _SVX_SVDOBJ_HXX |
| #include <svx/svdobj.hxx> |
| #endif |
| #include <dcontact.hxx> |
| #include <frmfmt.hxx> |
| #include <frmatr.hxx> |
| #include <editeng/lrspitem.hxx> |
| #include <editeng/ulspitem.hxx> |
| #include <fmtornt.hxx> |
| |
| #include <com/sun/star/text/HoriOrientation.hpp> |
| |
| |
| using namespace ::com::sun::star; |
| using namespace objectpositioning; |
| |
| /** constructor |
| |
| @author OD |
| */ |
| SwAsCharAnchoredObjectPosition::SwAsCharAnchoredObjectPosition( |
| SdrObject& _rDrawObj, |
| const Point& _rProposedAnchorPos, |
| const AsCharFlags _nFlags, |
| const SwTwips _nLineAscent, |
| const SwTwips _nLineDescent, |
| const SwTwips _nLineAscentInclObjs, |
| const SwTwips _nLineDescentInclObjs ) |
| : SwAnchoredObjectPosition( _rDrawObj ), |
| mrProposedAnchorPos( _rProposedAnchorPos ), |
| mnFlags( _nFlags ), |
| mnLineAscent( _nLineAscent ), |
| mnLineDescent( _nLineDescent ), |
| mnLineAscentInclObjs( _nLineAscentInclObjs ), |
| mnLineDescentInclObjs( _nLineDescentInclObjs ), |
| maAnchorPos ( Point() ), |
| mnRelPos ( 0 ), |
| maObjBoundRect ( SwRect() ), |
| mnLineAlignment ( 0 ) |
| {} |
| |
| /** destructor |
| |
| @author OD |
| */ |
| SwAsCharAnchoredObjectPosition::~SwAsCharAnchoredObjectPosition() |
| {} |
| |
| /** method to cast <SwAnchoredObjectPosition::GetAnchorFrm()> to needed type |
| |
| @author OD |
| */ |
| const SwTxtFrm& SwAsCharAnchoredObjectPosition::GetAnchorTxtFrm() const |
| { |
| ASSERT( GetAnchorFrm().ISA(SwTxtFrm), |
| "SwAsCharAnchoredObjectPosition::GetAnchorTxtFrm() - wrong anchor frame type" ); |
| |
| return static_cast<const SwTxtFrm&>(GetAnchorFrm()); |
| } |
| |
| /** calculate position for object |
| |
| OD 30.07.2003 #110978# |
| members <maAnchorPos>, <mnRelPos>, <maObjBoundRect> and |
| <mnLineAlignment> are calculated. |
| calculated position is set at the given object. |
| |
| @author OD |
| */ |
| void SwAsCharAnchoredObjectPosition::CalcPosition() |
| { |
| const SwTxtFrm& rAnchorFrm = GetAnchorTxtFrm(); |
| // swap anchor frame, if swapped. Note: destructor takes care of the 'undo' |
| SwFrmSwapper aFrmSwapper( &rAnchorFrm, false ); |
| |
| SWRECTFN( ( &rAnchorFrm ) ) |
| |
| Point aAnchorPos( mrProposedAnchorPos ); |
| |
| const SwFrmFmt& rFrmFmt = GetFrmFmt(); |
| |
| SwRect aObjBoundRect( GetAnchoredObj().GetObjRect() ); |
| SwTwips nObjWidth = (aObjBoundRect.*fnRect->fnGetWidth)(); |
| |
| // determine spacing values considering layout-/text-direction |
| const SvxLRSpaceItem& rLRSpace = rFrmFmt.GetLRSpace(); |
| const SvxULSpaceItem& rULSpace = rFrmFmt.GetULSpace(); |
| SwTwips nLRSpaceLeft, nLRSpaceRight, nULSpaceUpper, nULSpaceLower; |
| { |
| if ( rAnchorFrm.IsVertical() ) |
| { |
| // Seems to be easier to do it all the horizontal way |
| // So, from now on think horizontal. |
| rAnchorFrm.SwitchVerticalToHorizontal( aObjBoundRect ); |
| rAnchorFrm.SwitchVerticalToHorizontal( aAnchorPos ); |
| |
| // convert the spacing values |
| nLRSpaceLeft = rULSpace.GetUpper(); |
| nLRSpaceRight = rULSpace.GetLower(); |
| nULSpaceUpper = rLRSpace.GetRight(); |
| nULSpaceLower = rLRSpace.GetLeft(); |
| } |
| else |
| { |
| if ( rAnchorFrm.IsRightToLeft() ) |
| { |
| nLRSpaceLeft = rLRSpace.GetRight(); |
| nLRSpaceRight = rLRSpace.GetLeft(); |
| } |
| else |
| { |
| nLRSpaceLeft = rLRSpace.GetLeft(); |
| nLRSpaceRight = rLRSpace.GetRight(); |
| } |
| |
| nULSpaceUpper = rULSpace.GetUpper(); |
| nULSpaceLower = rULSpace.GetLower(); |
| } |
| } |
| |
| // consider left and upper spacing by adjusting anchor position. |
| // left spacing is only considered, if requested. |
| if( mnFlags & AS_CHAR_ULSPACE ) |
| { |
| aAnchorPos.X() += nLRSpaceLeft; |
| } |
| aAnchorPos.Y() += nULSpaceUpper; |
| |
| // for drawing objects: consider difference between its bounding rectangle |
| // and its snapping rectangle by adjusting anchor position. |
| // left difference is only considered, if requested. |
| if( !IsObjFly() ) |
| { |
| SwRect aSnapRect = GetObject().GetSnapRect(); |
| if ( rAnchorFrm.IsVertical() ) |
| { |
| rAnchorFrm.SwitchVerticalToHorizontal( aSnapRect ); |
| } |
| |
| if( mnFlags & AS_CHAR_ULSPACE ) |
| { |
| aAnchorPos.X() += aSnapRect.Left() - aObjBoundRect.Left(); |
| } |
| aAnchorPos.Y() += aSnapRect.Top() - aObjBoundRect.Top(); |
| } |
| |
| // enlarge bounding rectangle of object by its spacing. |
| aObjBoundRect.Left( aObjBoundRect.Left() - nLRSpaceLeft ); |
| aObjBoundRect.Width( aObjBoundRect.Width() + nLRSpaceRight ); |
| aObjBoundRect.Top( aObjBoundRect.Top() - nULSpaceUpper ); |
| aObjBoundRect.Height( aObjBoundRect.Height() + nULSpaceLower ); |
| |
| // calculate relative position to given base line. |
| const SwFmtVertOrient& rVert = rFrmFmt.GetVertOrient(); |
| const SwTwips nObjBoundHeight = ( mnFlags & AS_CHAR_ROTATE ) |
| ? aObjBoundRect.Width() |
| : aObjBoundRect.Height(); |
| const SwTwips nRelPos = _GetRelPosToBase( nObjBoundHeight, rVert ); |
| |
| // for initial positioning: |
| // adjust the proposed anchor position by difference between |
| // calculated relative position to base line and current maximal line ascent. |
| // Note: In the following line formatting the base line will be adjusted |
| // by the same difference. |
| if( mnFlags & AS_CHAR_INIT && nRelPos < 0 && mnLineAscentInclObjs < -nRelPos ) |
| { |
| if( mnFlags & AS_CHAR_ROTATE ) |
| aAnchorPos.X() -= mnLineAscentInclObjs + nRelPos; |
| else |
| aAnchorPos.Y() -= mnLineAscentInclObjs + nRelPos; |
| } |
| |
| // consider BIDI-multiportion by adjusting proposed anchor position |
| if( mnFlags & AS_CHAR_BIDI ) |
| aAnchorPos.X() -= aObjBoundRect.Width(); |
| |
| // calculate relative position considering rotation and inside rotation |
| // reverse direction. |
| Point aRelPos; |
| { |
| if( mnFlags & AS_CHAR_ROTATE ) |
| { |
| if( mnFlags & AS_CHAR_REVERSE ) |
| aRelPos.X() = -nRelPos - aObjBoundRect.Width(); |
| else |
| { |
| aRelPos.X() = nRelPos; |
| aRelPos.Y() = -aObjBoundRect.Height(); |
| } |
| } |
| else |
| aRelPos.Y() = nRelPos; |
| } |
| |
| if( !IsObjFly() ) |
| { |
| if( !( mnFlags & AS_CHAR_QUICK ) ) |
| { |
| // save calculated Y-position value for 'automatic' vertical positioning, |
| // in order to avoid a switch to 'manual' vertical positioning in |
| // <SwDrawContact::_Changed(..)>. |
| const sal_Int16 eVertOrient = rVert.GetVertOrient(); |
| if( rVert.GetPos() != nRelPos && eVertOrient != text::VertOrientation::NONE ) |
| { |
| SwFmtVertOrient aVert( rVert ); |
| aVert.SetPos( nRelPos ); |
| const_cast<SwFrmFmt&>(rFrmFmt).LockModify(); |
| const_cast<SwFrmFmt&>(rFrmFmt).SetFmtAttr( aVert ); |
| const_cast<SwFrmFmt&>(rFrmFmt).UnlockModify(); |
| } |
| |
| // determine absolute anchor position considering layout directions. |
| // Note: Use copy of <aAnchorPos>, because it's needed for |
| // setting relative position. |
| Point aAbsAnchorPos( aAnchorPos ); |
| if ( rAnchorFrm.IsRightToLeft() ) |
| { |
| rAnchorFrm.SwitchLTRtoRTL( aAbsAnchorPos ); |
| aAbsAnchorPos.X() -= nObjWidth; |
| } |
| if ( rAnchorFrm.IsVertical() ) |
| rAnchorFrm.SwitchHorizontalToVertical( aAbsAnchorPos ); |
| |
| // set proposed anchor position at the drawing object. |
| // OD 2004-04-06 #i26791# - distinction between 'master' drawing |
| // object and 'virtual' drawing object no longer needed. |
| GetObject().SetAnchorPos( aAbsAnchorPos ); |
| |
| // move drawing object to set its correct relative position. |
| { |
| SwRect aSnapRect = GetObject().GetSnapRect(); |
| if ( rAnchorFrm.IsVertical() ) |
| rAnchorFrm.SwitchVerticalToHorizontal( aSnapRect ); |
| |
| Point aDiff; |
| if ( rAnchorFrm.IsRightToLeft() ) |
| aDiff = aRelPos + aAbsAnchorPos - aSnapRect.TopLeft(); |
| else |
| aDiff = aRelPos + aAnchorPos - aSnapRect.TopLeft(); |
| |
| if ( rAnchorFrm.IsVertical() ) |
| aDiff = Point( -aDiff.Y(), aDiff.X() ); |
| |
| // OD 2004-04-06 #i26791# - distinction between 'master' drawing |
| // object and 'virtual' drawing object no longer needed. |
| GetObject().Move( Size( aDiff.X(), aDiff.Y() ) ); |
| } |
| } |
| |
| // switch horizontal, LTR anchor position to absolute values. |
| if ( rAnchorFrm.IsRightToLeft() ) |
| { |
| rAnchorFrm.SwitchLTRtoRTL( aAnchorPos ); |
| aAnchorPos.X() -= nObjWidth; |
| } |
| if ( rAnchorFrm.IsVertical() ) |
| rAnchorFrm.SwitchHorizontalToVertical( aAnchorPos ); |
| |
| // --> OD 2005-03-09 #i44347# - keep last object rectangle at anchored object |
| ASSERT ( GetAnchoredObj().ISA(SwAnchoredDrawObject), |
| "<SwAsCharAnchoredObjectPosition::CalcPosition()> - wrong type of anchored object." ); |
| SwAnchoredDrawObject& rAnchoredDrawObj = |
| static_cast<SwAnchoredDrawObject&>( GetAnchoredObj() ); |
| rAnchoredDrawObj.SetLastObjRect( rAnchoredDrawObj.GetObjRect().SVRect() ); |
| // <-- |
| } |
| else |
| { |
| // determine absolute anchor position and calculate corresponding |
| // relative position and its relative position attribute. |
| // Note: The relative position contains the spacing values. |
| Point aRelAttr; |
| if ( rAnchorFrm.IsRightToLeft() ) |
| { |
| rAnchorFrm.SwitchLTRtoRTL( aAnchorPos ); |
| aAnchorPos.X() -= nObjWidth; |
| } |
| if ( rAnchorFrm.IsVertical() ) |
| { |
| rAnchorFrm.SwitchHorizontalToVertical( aAnchorPos ); |
| aRelAttr = Point( -nRelPos, 0 ); |
| aRelPos = Point( -aRelPos.Y(), aRelPos.X() ); |
| } |
| else |
| aRelAttr = Point( 0, nRelPos ); |
| |
| // OD 2004-03-23 #i26791# |
| ASSERT( GetAnchoredObj().ISA(SwFlyInCntFrm), |
| "<SwAsCharAnchoredObjectPosition::CalcPosition()> - wrong anchored object." ); |
| const SwFlyInCntFrm& rFlyInCntFrm = |
| static_cast<const SwFlyInCntFrm&>(GetAnchoredObj()); |
| if ( !(mnFlags & AS_CHAR_QUICK) && |
| ( aAnchorPos != rFlyInCntFrm.GetRefPoint() || |
| aRelAttr != rFlyInCntFrm.GetCurrRelPos() ) ) |
| { |
| // set new anchor position and relative position |
| SwFlyInCntFrm* pFlyInCntFrm = &(const_cast<SwFlyInCntFrm&>(rFlyInCntFrm)); |
| pFlyInCntFrm->SetRefPoint( aAnchorPos, aRelAttr, aRelPos ); |
| if( nObjWidth != (pFlyInCntFrm->Frm().*fnRect->fnGetWidth)() ) |
| { |
| // recalculate object bound rectangle, if object width has changed. |
| aObjBoundRect = GetAnchoredObj().GetObjRect(); |
| aObjBoundRect.Left( aObjBoundRect.Left() - rLRSpace.GetLeft() ); |
| aObjBoundRect.Width( aObjBoundRect.Width() + rLRSpace.GetRight() ); |
| aObjBoundRect.Top( aObjBoundRect.Top() - rULSpace.GetUpper() ); |
| aObjBoundRect.Height( aObjBoundRect.Height() + rULSpace.GetLower() ); |
| } |
| } |
| ASSERT( (rFlyInCntFrm.Frm().*fnRect->fnGetHeight)(), |
| "SwAnchoredObjectPosition::CalcPosition(..) - fly frame has an invalid height" ); |
| } |
| |
| // keep calculated values |
| maAnchorPos = aAnchorPos; |
| mnRelPos = nRelPos; |
| maObjBoundRect = aObjBoundRect; |
| } |
| |
| /** determine the relative position to base line for object position type AS_CHAR |
| |
| OD 29.07.2003 #110978# |
| Note about values set at member <mnLineAlignment> - |
| value gives feedback for the line formatting. |
| 0 - no feedback; 1|2|3 - proposed formatting of characters |
| at top|at center|at bottom of line. |
| |
| @author OD |
| */ |
| SwTwips SwAsCharAnchoredObjectPosition::_GetRelPosToBase( |
| const SwTwips _nObjBoundHeight, |
| const SwFmtVertOrient& _rVert ) |
| { |
| SwTwips nRelPosToBase = 0; |
| |
| mnLineAlignment = 0; |
| |
| const sal_Int16 eVertOrient = _rVert.GetVertOrient(); |
| |
| if ( eVertOrient == text::VertOrientation::NONE ) |
| nRelPosToBase = _rVert.GetPos(); |
| else |
| { |
| if ( eVertOrient == text::VertOrientation::CENTER ) |
| nRelPosToBase -= _nObjBoundHeight / 2; |
| else if ( eVertOrient == text::VertOrientation::TOP ) |
| nRelPosToBase -= _nObjBoundHeight; |
| else if ( eVertOrient == text::VertOrientation::BOTTOM ) |
| nRelPosToBase = 0; |
| else if ( eVertOrient == text::VertOrientation::CHAR_CENTER ) |
| nRelPosToBase -= ( _nObjBoundHeight + mnLineAscent - mnLineDescent ) / 2; |
| else if ( eVertOrient == text::VertOrientation::CHAR_TOP ) |
| nRelPosToBase -= mnLineAscent; |
| else if ( eVertOrient == text::VertOrientation::CHAR_BOTTOM ) |
| nRelPosToBase += mnLineDescent - _nObjBoundHeight; |
| else |
| { |
| if( _nObjBoundHeight >= mnLineAscentInclObjs + mnLineDescentInclObjs ) |
| { |
| // object is at least as high as the line. Thus, no more is |
| // positioning necessary. Also, the max. ascent isn't changed. |
| nRelPosToBase -= mnLineAscentInclObjs; |
| if ( eVertOrient == text::VertOrientation::LINE_CENTER ) |
| mnLineAlignment = 2; |
| else if ( eVertOrient == text::VertOrientation::LINE_TOP ) |
| mnLineAlignment = 1; |
| else if ( eVertOrient == text::VertOrientation::LINE_BOTTOM ) |
| mnLineAlignment = 3; |
| } |
| else if ( eVertOrient == text::VertOrientation::LINE_CENTER ) |
| { |
| nRelPosToBase -= ( _nObjBoundHeight + mnLineAscentInclObjs - mnLineDescentInclObjs ) / 2; |
| mnLineAlignment = 2; |
| } |
| else if ( eVertOrient == text::VertOrientation::LINE_TOP ) |
| { |
| nRelPosToBase -= mnLineAscentInclObjs; |
| mnLineAlignment = 1; |
| } |
| else if ( eVertOrient == text::VertOrientation::LINE_BOTTOM ) |
| { |
| nRelPosToBase += mnLineDescentInclObjs - _nObjBoundHeight; |
| mnLineAlignment = 3; |
| } |
| } |
| } |
| |
| return nRelPosToBase; |
| } |
| |
| /** calculated anchored position for object position |
| |
| @author OD |
| */ |
| Point SwAsCharAnchoredObjectPosition::GetAnchorPos() const |
| { |
| return maAnchorPos; |
| } |
| |
| /** calculated relative position to base line for object position |
| |
| @author OD |
| */ |
| SwTwips SwAsCharAnchoredObjectPosition::GetRelPosY() const |
| { |
| return mnRelPos; |
| } |
| |
| /** determined object rectangle including spacing for object |
| |
| @author OD |
| */ |
| SwRect SwAsCharAnchoredObjectPosition::GetObjBoundRectInclSpacing() const |
| { |
| return maObjBoundRect; |
| } |
| |
| /** determined line alignment |
| |
| @author OD |
| */ |
| sal_uInt8 SwAsCharAnchoredObjectPosition::GetLineAlignment() const |
| { |
| return mnLineAlignment; |
| } |
| |