diff options
Diffstat (limited to 'svx/source/dialog/framelink.cxx')
-rw-r--r-- | svx/source/dialog/framelink.cxx | 341 |
1 files changed, 341 insertions, 0 deletions
diff --git a/svx/source/dialog/framelink.cxx b/svx/source/dialog/framelink.cxx new file mode 100644 index 0000000000..887fc445dc --- /dev/null +++ b/svx/source/dialog/framelink.cxx @@ -0,0 +1,341 @@ +/* -*- 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 . + */ + +#include <sal/config.h> + +#include <rtl/math.hxx> +#include <svx/framelink.hxx> + +#include <editeng/borderline.hxx> +#include <o3tl/hash_combine.hxx> + + +using namespace ::com::sun::star; +using namespace editeng; + +namespace svx::frame +{ + +Style::Style( double nP, double nD, double nS, SvxBorderLineStyle nType, double fScale ) +{ + Clear(); + mnType = nType; + mfPatternScale = fScale; + Set( nP, nD, nS ); +} + +Style::Style( const Color& rColorPrim, const Color& rColorSecn, const Color& rColorGap, bool bUseGapColor, double nP, double nD, double nS, SvxBorderLineStyle nType, double fScale ) +{ + Clear(); + mnType = nType; + mfPatternScale = fScale; + Set( rColorPrim, rColorSecn, rColorGap, bUseGapColor, nP, nD, nS ); +} + +Style::Style( const editeng::SvxBorderLine* pBorder, double fScale ) +{ + Clear(); + if(nullptr != pBorder) + { + mfPatternScale = fScale; + Set( pBorder, fScale ); + } +} + +void Style::Clear() +{ + maColorPrim = Color(); + maColorSecn = Color(); + maColorGap = Color(); + mbUseGapColor = false; + meRefMode = RefMode::Centered; + mfPrim = 0.0; + mfDist = 0.0; + mfSecn = 0.0; + mfPatternScale = 1.0; + mnType = SvxBorderLineStyle::SOLID; + mbWordTableCell = false; +} + +void Style::Set( double nP, double nD, double nS ) +{ + /* nP nD nS -> mfPrim mfDist mfSecn + -------------------------------------- + any any 0 nP 0 0 + 0 any >0 nS 0 0 + >0 0 >0 nP 0 0 + >0 >0 >0 nP nD nS + */ + mfPrim = rtl::math::round(nP ? nP : nS, 2); + mfDist = rtl::math::round((nP && nS) ? nD : 0, 2); + mfSecn = rtl::math::round((nP && nD) ? nS : 0, 2); +} + +void Style::Set( const Color& rColorPrim, const Color& rColorSecn, const Color& rColorGap, bool bUseGapColor, double nP, double nD, double nS ) +{ + maColorPrim = rColorPrim; + maColorSecn = rColorSecn; + maColorGap = rColorGap; + mbUseGapColor = bUseGapColor; + Set( nP, nD, nS ); +} + +void Style::Set( const SvxBorderLine* pBorder, double fScale, sal_uInt16 nMaxWidth ) +{ + if(nullptr == pBorder) + { + Clear(); + return; + } + + maColorPrim = pBorder->GetColorOut(); + maColorSecn = pBorder->GetColorIn(); + maColorGap = pBorder->GetColorGap(); + mbUseGapColor = pBorder->HasGapColor(); + + const sal_uInt16 nPrim(pBorder->GetOutWidth()); + const sal_uInt16 nDist(pBorder->GetDistance()); + const sal_uInt16 nSecn(pBorder->GetInWidth()); + + mnType = pBorder->GetBorderLineStyle(); + mfPatternScale = fScale; + + if( !nSecn ) // no or single frame border + { + Set( std::min<double>(nPrim * fScale, nMaxWidth), 0, 0 ); + } + else + { + Set(std::min<double>(nPrim * fScale, nMaxWidth), std::min<double>(nDist * fScale, nMaxWidth), std::min<double>(nSecn * fScale, nMaxWidth)); + // Enlarge the style if distance is too small due to rounding losses. + double nPixWidth = std::min<double>((nPrim + nDist + nSecn) * fScale, nMaxWidth); + + if( nPixWidth > GetWidth() ) + { + mfDist = nPixWidth - mfPrim - mfSecn; + } + + // Shrink the style if it is too thick for the control. + while( GetWidth() > nMaxWidth ) + { + // First decrease space between lines. + if (mfDist) + { + --mfDist; + continue; + } + + // Still too thick? Decrease the line widths. + if (mfPrim != 0.0 && rtl::math::approxEqual(mfPrim, mfSecn)) + { + // Both lines equal - decrease both to keep symmetry. + --mfPrim; + --mfSecn; + continue; + } + + // Decrease each line for itself + if (mfPrim) + --mfPrim; + + if ((GetWidth() > nMaxWidth) && mfSecn != 0.0) + --mfSecn; + } + } +} + +Style& Style::MirrorSelf() +{ + if (mfSecn) + { + std::swap( mfPrim, mfSecn ); + // also need to swap colors + std::swap( maColorPrim, maColorSecn ); + } + + if( meRefMode != RefMode::Centered ) + { + meRefMode = (meRefMode == RefMode::Begin) ? RefMode::End : RefMode::Begin; + } + + return *this; +} + +bool Style::operator==( const Style& rOther) const +{ + if (this == &rOther) + // ptr compare (same instance) + return true; + + return (Prim() == rOther.Prim() + && Dist() == rOther.Dist() + && Secn() == rOther.Secn() + && GetColorPrim() == rOther.GetColorPrim() + && GetColorSecn() == rOther.GetColorSecn() + && GetColorGap() == rOther.GetColorGap() + && GetRefMode() == rOther.GetRefMode() + && UseGapColor() == rOther.UseGapColor() + && Type() == rOther.Type()); +} + +size_t Style::hashCode() const +{ + std::size_t seed = 0; + o3tl::hash_combine(seed, Prim()); + o3tl::hash_combine(seed, Dist()); + o3tl::hash_combine(seed, Secn()); + o3tl::hash_combine(seed, static_cast<sal_Int32>(GetColorPrim())); + o3tl::hash_combine(seed, static_cast<sal_Int32>(GetColorSecn())); + o3tl::hash_combine(seed, static_cast<sal_Int32>(GetColorGap())); + o3tl::hash_combine(seed, GetRefMode()); + o3tl::hash_combine(seed, UseGapColor()); + o3tl::hash_combine(seed, Type()); + return seed; +} + + +namespace +{ +/** + * Gets the weight of rStyle, according to [MS-OI29500] v20171130, 2.1.168 Part 1 Section 17.4.66, + * tcBorders (Table Cell Borders). + */ +double GetWordTableCellBorderWeight(const Style& rStyle) +{ + double fWidth = rStyle.GetWidth(); + int nBorderNumber = 0; + + // See lcl_convertBorderStyleFromToken() in writerfilter/ and ConvertBorderStyleFromWord() in + // editeng/, this is the opposite of the combination of those functions. + switch (rStyle.Type()) + { + case SvxBorderLineStyle::NONE: + return 0.0; + case SvxBorderLineStyle::DOTTED: + case SvxBorderLineStyle::DASHED: + return 1.0; + case SvxBorderLineStyle::SOLID: + // single = 1 + // thick = 2 + // wave = 20 + nBorderNumber = 1; + break; + case SvxBorderLineStyle::DOUBLE: + case SvxBorderLineStyle::DOUBLE_THIN: + // double = 3 + // triple = 10 + // doubleWave = 21 + // dashDotStroked = 23 + nBorderNumber = 3; + break; + case SvxBorderLineStyle::DASH_DOT: + // dotDash = 8 + nBorderNumber = 8; + break; + case SvxBorderLineStyle::DASH_DOT_DOT: + // dotDotDash = 9 + nBorderNumber = 9; + break; + case SvxBorderLineStyle::THINTHICK_SMALLGAP: + // thinThickSmallGap = 11 + nBorderNumber = 11; + break; + case SvxBorderLineStyle::THICKTHIN_SMALLGAP: + // thickThinSmallGap = 12 + // thinThickThinSmallGap = 13 + nBorderNumber = 12; + break; + case SvxBorderLineStyle::THINTHICK_MEDIUMGAP: + // thinThickMediumGap = 14 + nBorderNumber = 14; + break; + case SvxBorderLineStyle::THICKTHIN_MEDIUMGAP: + // thickThinMediumGap = 15 + // thinThickThinMediumGap = 16 + nBorderNumber = 15; + break; + case SvxBorderLineStyle::THINTHICK_LARGEGAP: + // thinThickLargeGap = 17 + nBorderNumber = 17; + break; + case SvxBorderLineStyle::THICKTHIN_LARGEGAP: + // thickThinLargeGap = 18 + // thinThickThinLargeGap = 19 + nBorderNumber = 18; + break; + case SvxBorderLineStyle::FINE_DASHED: + // dashSmallGap = 22 + nBorderNumber = 22; + break; + case SvxBorderLineStyle::EMBOSSED: + // threeDEmboss = 24 + nBorderNumber = 24; + break; + case SvxBorderLineStyle::ENGRAVED: + // threeDEngrave = 25 + nBorderNumber = 25; + break; + case SvxBorderLineStyle::OUTSET: + // outset = 26 + nBorderNumber = 25; + break; + case SvxBorderLineStyle::INSET: + // inset = 27 + nBorderNumber = 27; + break; + } + + return nBorderNumber * fWidth; +} +} + +bool Style::operator<( const Style& rOther) const +{ + if (mbWordTableCell) + { + // The below code would first compare based on the border width, Word compares based on its + // calculated weight, do that in the compat case. + double fLW = GetWordTableCellBorderWeight(*this); + double fRW = GetWordTableCellBorderWeight(rOther); + if (!rtl::math::approxEqual(fLW, fRW)) + { + return fLW < fRW; + } + } + + // different total widths -> this<rOther, if this is thinner + double nLW = GetWidth(); + double nRW = rOther.GetWidth(); + if( !rtl::math::approxEqual(nLW, nRW) ) return nLW < nRW; + + // one line double, the other single -> this<rOther, if this is single + if( (Secn() == 0) != (rOther.Secn() == 0) ) return Secn() == 0; + + // both lines double with different distances -> this<rOther, if distance of this greater + if( (Secn() && rOther.Secn()) && !rtl::math::approxEqual(Dist(), rOther.Dist()) ) return Dist() > rOther.Dist(); + + // both lines single and 1 unit thick, only one is dotted -> this<rOther, if this is dotted + if ((nLW == 1) && !Secn() && !rOther.Secn() && (Type() != rOther.Type())) return Type() > rOther.Type(); + + // seem to be equal + return false; +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |