1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <prcntfld.hxx>
21 #include <vcl/fieldvalues.hxx>
23 SwPercentField::SwPercentField(std::unique_ptr
<weld::MetricSpinButton
> pControl
)
24 : m_pField(std::move(pControl
))
29 , m_nOldDigits(m_pField
->get_digits())
30 , m_eOldUnit(FieldUnit::NONE
)
31 , m_bLockAutoCalculation(false)
34 m_pField
->get_range(nMin
, nMax
, FieldUnit::TWIP
);
35 m_nRefValue
= DenormalizePercent(nMax
);
36 m_pField
->get_increments(m_nOldSpinSize
, m_nOldPageSize
, FieldUnit::NONE
);
39 void SwPercentField::SetRefValue(sal_Int64 nValue
)
41 sal_Int64 nRealValue
= GetRealValue(m_eOldUnit
);
45 if (!m_bLockAutoCalculation
&& (m_pField
->get_unit() == FieldUnit::PERCENT
))
46 set_value(nRealValue
, m_eOldUnit
);
49 static sal_Int64
UpscaleTwoDecimalPlaces(sal_Int64 nCurrentWidth
, int nOldDigits
)
51 // tdf#145847 Typically nOldDigits is two so deriving percentage is direct division
52 // by m_nRefValue but it is one for points
53 for (int i
= nOldDigits
; i
< 2; ++i
)
58 void SwPercentField::ShowPercent(bool bPercent
)
60 if ((bPercent
&& m_pField
->get_unit() == FieldUnit::PERCENT
)
61 || (!bPercent
&& m_pField
->get_unit() != FieldUnit::PERCENT
))
68 nOldValue
= get_value();
70 m_eOldUnit
= m_pField
->get_unit();
71 m_nOldDigits
= m_pField
->get_digits();
72 m_pField
->get_range(m_nOldMin
, m_nOldMax
, FieldUnit::NONE
);
73 m_pField
->get_increments(m_nOldSpinSize
, m_nOldPageSize
, FieldUnit::NONE
);
74 m_pField
->set_unit(FieldUnit::PERCENT
);
75 m_pField
->set_digits(0);
77 sal_Int64 nCurrentWidth
78 = vcl::ConvertValue(m_nOldMin
, 0, m_nOldDigits
, m_eOldUnit
, FieldUnit::TWIP
);
79 nCurrentWidth
= UpscaleTwoDecimalPlaces(nCurrentWidth
, m_nOldDigits
);
81 // round to 0.5 percent
82 int nPercent
= m_nRefValue
? (((nCurrentWidth
* 10) / m_nRefValue
+ 5) / 10) : 0;
84 m_pField
->set_range(std::max(1, nPercent
), 100, FieldUnit::NONE
);
85 m_pField
->set_increments(5, 10, FieldUnit::NONE
);
86 if (nOldValue
!= m_nLastValue
)
89 = vcl::ConvertValue(nOldValue
, 0, m_nOldDigits
, m_eOldUnit
, FieldUnit::TWIP
);
90 nCurrentWidth
= UpscaleTwoDecimalPlaces(nCurrentWidth
, m_nOldDigits
);
91 nPercent
= m_nRefValue
? (((nCurrentWidth
* 10) / m_nRefValue
+ 5) / 10) : 0;
92 m_pField
->set_value(nPercent
, FieldUnit::NONE
);
93 m_nLastPercent
= nPercent
;
94 m_nLastValue
= nOldValue
;
97 m_pField
->set_value(m_nLastPercent
, FieldUnit::NONE
);
101 sal_Int64 nOldPercent
= get_value(FieldUnit::PERCENT
);
103 nOldValue
= Convert(get_value(), m_pField
->get_unit(), m_eOldUnit
);
105 m_pField
->set_unit(m_eOldUnit
);
106 m_pField
->set_digits(m_nOldDigits
);
107 m_pField
->set_range(m_nOldMin
, m_nOldMax
, FieldUnit::NONE
);
108 m_pField
->set_increments(m_nOldSpinSize
, m_nOldPageSize
, FieldUnit::NONE
);
110 if (nOldPercent
!= m_nLastPercent
)
112 set_value(nOldValue
, m_eOldUnit
);
113 m_nLastPercent
= nOldPercent
;
114 m_nLastValue
= nOldValue
;
117 set_value(m_nLastValue
, m_eOldUnit
);
121 void SwPercentField::set_value(sal_Int64 nNewValue
, FieldUnit eInUnit
)
123 if (m_pField
->get_unit() != FieldUnit::PERCENT
|| eInUnit
== FieldUnit::PERCENT
)
124 m_pField
->set_value(Convert(nNewValue
, eInUnit
, m_pField
->get_unit()), FieldUnit::NONE
);
127 // Overwrite output value, do not restore later
128 sal_Int64 nPercent
, nCurrentWidth
;
129 if (eInUnit
== FieldUnit::TWIP
)
132 = vcl::ConvertValue(nNewValue
, 0, m_nOldDigits
, FieldUnit::TWIP
, FieldUnit::TWIP
);
136 sal_Int64 nValue
= Convert(nNewValue
, eInUnit
, m_eOldUnit
);
137 nCurrentWidth
= vcl::ConvertValue(nValue
, 0, m_nOldDigits
, m_eOldUnit
, FieldUnit::TWIP
);
139 nCurrentWidth
= UpscaleTwoDecimalPlaces(nCurrentWidth
, m_nOldDigits
);
140 nPercent
= m_nRefValue
? (((nCurrentWidth
* 10) / m_nRefValue
+ 5) / 10) : 0;
141 m_pField
->set_value(nPercent
, FieldUnit::NONE
);
145 sal_Int64
SwPercentField::get_value(FieldUnit eOutUnit
)
147 return Convert(m_pField
->get_value(FieldUnit::NONE
), m_pField
->get_unit(), eOutUnit
);
150 void SwPercentField::set_min(sal_Int64 nNewMin
, FieldUnit eInUnit
)
152 if (m_pField
->get_unit() != FieldUnit::PERCENT
)
153 m_pField
->set_min(nNewMin
, eInUnit
);
156 if (eInUnit
== FieldUnit::NONE
)
157 eInUnit
= m_eOldUnit
;
158 m_nOldMin
= Convert(nNewMin
, eInUnit
, m_eOldUnit
);
160 int nPercent
= Convert(nNewMin
, eInUnit
, FieldUnit::PERCENT
);
161 m_pField
->set_min(std::max(1, nPercent
), FieldUnit::NONE
);
165 void SwPercentField::set_max(sal_Int64 nNewMax
, FieldUnit eInUnit
)
167 if (m_pField
->get_unit() != FieldUnit::PERCENT
)
168 m_pField
->set_max(nNewMax
, eInUnit
);
171 sal_Int64
SwPercentField::NormalizePercent(sal_Int64 nValue
)
173 if (m_pField
->get_unit() != FieldUnit::PERCENT
)
174 nValue
= m_pField
->normalize(nValue
);
176 nValue
= nValue
* ImpPower10(m_nOldDigits
);
180 sal_Int64
SwPercentField::DenormalizePercent(sal_Int64 nValue
)
182 if (m_pField
->get_unit() != FieldUnit::PERCENT
)
183 nValue
= m_pField
->denormalize(nValue
);
186 int nFactor
= ImpPower10(m_nOldDigits
);
187 nValue
= ((nValue
+ (nFactor
/ 2)) / nFactor
);
192 int SwPercentField::ImpPower10(sal_uInt16 n
)
196 for (sal_uInt16 i
= 0; i
< n
; ++i
)
202 sal_Int64
SwPercentField::GetRealValue(FieldUnit eOutUnit
)
204 if (m_pField
->get_unit() != FieldUnit::PERCENT
)
205 return get_value(eOutUnit
);
207 return Convert(get_value(), m_pField
->get_unit(), eOutUnit
);
210 sal_Int64
SwPercentField::Convert(sal_Int64 nValue
, FieldUnit eInUnit
, FieldUnit eOutUnit
)
212 if (eInUnit
== eOutUnit
|| (eInUnit
== FieldUnit::NONE
&& eOutUnit
== m_pField
->get_unit())
213 || (eOutUnit
== FieldUnit::NONE
&& eInUnit
== m_pField
->get_unit()))
216 if (eInUnit
== FieldUnit::PERCENT
)
219 sal_Int64 nTwipValue
= (m_nRefValue
* nValue
+ 50) / 100;
221 if (eOutUnit
== FieldUnit::TWIP
) // Only convert if necessary
222 return NormalizePercent(nTwipValue
);
224 return vcl::ConvertValue(NormalizePercent(nTwipValue
), 0, m_nOldDigits
, FieldUnit::TWIP
,
228 if (eOutUnit
== FieldUnit::PERCENT
)
230 // Convert to percent
231 sal_Int64 nCurrentWidth
;
232 nValue
= DenormalizePercent(nValue
);
234 if (eInUnit
== FieldUnit::TWIP
) // Only convert if necessary
235 nCurrentWidth
= nValue
;
237 nCurrentWidth
= vcl::ConvertValue(nValue
, 0, m_nOldDigits
, eInUnit
, FieldUnit::TWIP
);
238 nCurrentWidth
= UpscaleTwoDecimalPlaces(nCurrentWidth
, m_nOldDigits
);
239 // Round to 0.5 percent
240 return m_nRefValue
? (((nCurrentWidth
* 1000) / m_nRefValue
+ 5) / 10) : 0;
243 return vcl::ConvertValue(nValue
, 0, m_nOldDigits
, eInUnit
, eOutUnit
);
245 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */