1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20 #include <prcntfld.hxx>
21 #include <vcl/field.hxx>
22
SwPercentField(std::unique_ptr<weld::MetricSpinButton> pControl)23 SwPercentField::SwPercentField(std::unique_ptr<weld::MetricSpinButton> pControl)
24 : m_pField(std::move(pControl))
25 , nOldMax(0)
26 , nOldMin(0)
27 , nLastPercent(-1)
28 , nLastValue(-1)
29 , nOldDigits(m_pField->get_digits())
30 , eOldUnit(FieldUnit::NONE)
31 , bLockAutoCalculation(false)
32 {
33 int nMin, nMax;
34 m_pField->get_range(nMin, nMax, FieldUnit::TWIP);
35 nRefValue = DenormalizePercent(nMax);
36 m_pField->get_increments(nOldSpinSize, nOldPageSize, FieldUnit::NONE);
37 }
38
SetRefValue(int nValue)39 void SwPercentField::SetRefValue(int nValue)
40 {
41 int nRealValue = GetRealValue(eOldUnit);
42
43 nRefValue = nValue;
44
45 if (!bLockAutoCalculation && (m_pField->get_unit() == FieldUnit::PERCENT))
46 set_value(nRealValue, eOldUnit);
47 }
48
ShowPercent(bool bPercent)49 void SwPercentField::ShowPercent(bool bPercent)
50 {
51 if ((bPercent && m_pField->get_unit() == FieldUnit::PERCENT) ||
52 (!bPercent && m_pField->get_unit() != FieldUnit::PERCENT))
53 return;
54
55 int nOldValue;
56
57 if (bPercent)
58 {
59 nOldValue = get_value();
60
61 eOldUnit = m_pField->get_unit();
62 nOldDigits = m_pField->get_digits();
63 m_pField->get_range(nOldMin, nOldMax, FieldUnit::NONE);
64 m_pField->get_increments(nOldSpinSize, nOldPageSize, FieldUnit::NONE);
65 m_pField->set_unit(FieldUnit::PERCENT);
66 m_pField->set_digits(0);
67
68 int nCurrentWidth = MetricField::ConvertValue(nOldMin, 0, nOldDigits, eOldUnit, FieldUnit::TWIP);
69 // round to 0.5 percent
70 int nPercent = nRefValue ? (((nCurrentWidth * 10) / nRefValue + 5) / 10) : 0;
71
72 m_pField->set_range(std::max(1, nPercent), 100, FieldUnit::NONE);
73 m_pField->set_increments(5, 10, FieldUnit::NONE);
74 if (nOldValue != nLastValue)
75 {
76 nCurrentWidth = MetricField::ConvertValue(nOldValue, 0, nOldDigits, eOldUnit, FieldUnit::TWIP);
77 nPercent = nRefValue ? (((nCurrentWidth * 10) / nRefValue + 5) / 10) : 0;
78 m_pField->set_value(nPercent, FieldUnit::NONE);
79 nLastPercent = nPercent;
80 nLastValue = nOldValue;
81 }
82 else
83 m_pField->set_value(nLastPercent, FieldUnit::NONE);
84 }
85 else
86 {
87 int nOldPercent = get_value(FieldUnit::PERCENT);
88
89 nOldValue = Convert(get_value(), m_pField->get_unit(), eOldUnit);
90
91 m_pField->set_unit(eOldUnit);
92 m_pField->set_digits(nOldDigits);
93 m_pField->set_range(nOldMin, nOldMax, FieldUnit::NONE);
94 m_pField->set_increments(nOldSpinSize, nOldPageSize, FieldUnit::NONE);
95
96 if (nOldPercent != nLastPercent)
97 {
98 set_value(nOldValue, eOldUnit);
99 nLastPercent = nOldPercent;
100 nLastValue = nOldValue;
101 }
102 else
103 set_value(nLastValue, eOldUnit);
104 }
105 }
106
set_value(int nNewValue,FieldUnit eInUnit)107 void SwPercentField::set_value(int nNewValue, FieldUnit eInUnit)
108 {
109 if (m_pField->get_unit() != FieldUnit::PERCENT || eInUnit == FieldUnit::PERCENT)
110 m_pField->set_value(Convert(nNewValue, eInUnit, m_pField->get_unit()), FieldUnit::NONE);
111 else
112 {
113 // Overwrite output value, do not restore later
114 int nPercent, nCurrentWidth;
115 if(eInUnit == FieldUnit::TWIP)
116 {
117 nCurrentWidth = MetricField::ConvertValue(nNewValue, 0, nOldDigits, FieldUnit::TWIP, FieldUnit::TWIP);
118 }
119 else
120 {
121 int nValue = Convert(nNewValue, eInUnit, eOldUnit);
122 nCurrentWidth = MetricField::ConvertValue(nValue, 0, nOldDigits, eOldUnit, FieldUnit::TWIP);
123 }
124 nPercent = nRefValue ? (((nCurrentWidth * 10) / nRefValue + 5) / 10) : 0;
125 m_pField->set_value(nPercent, FieldUnit::NONE);
126 }
127 }
128
get_value(FieldUnit eOutUnit)129 int SwPercentField::get_value(FieldUnit eOutUnit)
130 {
131 return Convert(m_pField->get_value(FieldUnit::NONE), m_pField->get_unit(), eOutUnit);
132 }
133
set_min(int nNewMin,FieldUnit eInUnit)134 void SwPercentField::set_min(int nNewMin, FieldUnit eInUnit)
135 {
136 if (m_pField->get_unit() != FieldUnit::PERCENT)
137 m_pField->set_min(nNewMin, eInUnit);
138 else
139 {
140 if (eInUnit == FieldUnit::NONE)
141 eInUnit = eOldUnit;
142 nOldMin = Convert(nNewMin, eInUnit, eOldUnit);
143
144 int nPercent = Convert(nNewMin, eInUnit, FieldUnit::PERCENT);
145 m_pField->set_min(std::max(1, nPercent), FieldUnit::NONE);
146 }
147 }
148
set_max(int nNewMax,FieldUnit eInUnit)149 void SwPercentField::set_max(int nNewMax, FieldUnit eInUnit)
150 {
151 if (m_pField->get_unit() != FieldUnit::PERCENT)
152 m_pField->set_max(nNewMax, eInUnit);
153 }
154
NormalizePercent(int nValue)155 int SwPercentField::NormalizePercent(int nValue)
156 {
157 if (m_pField->get_unit() != FieldUnit::PERCENT)
158 nValue = m_pField->normalize(nValue);
159 else
160 nValue = nValue * ImpPower10(nOldDigits);
161 return nValue;
162 }
163
DenormalizePercent(int nValue)164 int SwPercentField::DenormalizePercent(int nValue)
165 {
166 if (m_pField->get_unit() != FieldUnit::PERCENT)
167 nValue = m_pField->denormalize(nValue);
168 else
169 {
170 int nFactor = ImpPower10(nOldDigits);
171 nValue = ((nValue+(nFactor/2)) / nFactor);
172 }
173 return nValue;
174 }
175
ImpPower10(sal_uInt16 n)176 int SwPercentField::ImpPower10(sal_uInt16 n)
177 {
178 int nValue = 1;
179
180 for (sal_uInt16 i=0; i < n; ++i)
181 nValue *= 10;
182
183 return nValue;
184 }
185
GetRealValue(FieldUnit eOutUnit)186 int SwPercentField::GetRealValue(FieldUnit eOutUnit)
187 {
188 if (m_pField->get_unit() != FieldUnit::PERCENT)
189 return get_value(eOutUnit);
190 else
191 return Convert(get_value(), m_pField->get_unit(), eOutUnit);
192 }
193
Convert(int nValue,FieldUnit eInUnit,FieldUnit eOutUnit)194 int SwPercentField::Convert(int nValue, FieldUnit eInUnit, FieldUnit eOutUnit)
195 {
196 if (eInUnit == eOutUnit ||
197 (eInUnit == FieldUnit::NONE && eOutUnit == m_pField->get_unit()) ||
198 (eOutUnit == FieldUnit::NONE && eInUnit == m_pField->get_unit()))
199 return nValue;
200
201 if (eInUnit == FieldUnit::PERCENT)
202 {
203 // Convert to metric
204 int nTwipValue = (nRefValue * nValue + 50) / 100;
205
206 if (eOutUnit == FieldUnit::TWIP) // Only convert if necessary
207 return NormalizePercent(nTwipValue);
208 else
209 return MetricField::ConvertValue(NormalizePercent(nTwipValue), 0, nOldDigits, FieldUnit::TWIP, eOutUnit);
210 }
211
212 if (eOutUnit == FieldUnit::PERCENT)
213 {
214 // Convert to percent
215 int nCurrentWidth;
216 nValue = DenormalizePercent(nValue);
217
218 if (eInUnit == FieldUnit::TWIP) // Only convert if necessary
219 nCurrentWidth = nValue;
220 else
221 nCurrentWidth = MetricField::ConvertValue(nValue, 0, nOldDigits, eInUnit, FieldUnit::TWIP);
222 // Round to 0.5 percent
223 return nRefValue ? (((nCurrentWidth * 1000) / nRefValue + 5) / 10) : 0;
224 }
225
226 return MetricField::ConvertValue(nValue, 0, nOldDigits, eInUnit, eOutUnit);
227 }
228 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
229