1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the examples of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:BSD$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** BSD License Usage
18** Alternatively, you may use this file under the terms of the BSD license
19** as follows:
20**
21** "Redistribution and use in source and binary forms, with or without
22** modification, are permitted provided that the following conditions are
23** met:
24** * Redistributions of source code must retain the above copyright
25** notice, this list of conditions and the following disclaimer.
26** * Redistributions in binary form must reproduce the above copyright
27** notice, this list of conditions and the following disclaimer in
28** the documentation and/or other materials provided with the
29** distribution.
30** * Neither the name of The Qt Company Ltd nor the names of its
31** contributors may be used to endorse or promote products derived
32** from this software without specific prior written permission.
33**
34**
35** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
36** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
38** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
39** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
42** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
43** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
44** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
45** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
46**
47** $QT_END_LICENSE$
48**
49****************************************************************************/
50
51#include "calculator.h"
52#include "button.h"
53
54#include <QGridLayout>
55#include <QLineEdit>
56#include <QtMath>
57
58//! [0]
59Calculator::Calculator(QWidget *parent)
60 : QWidget(parent), sumInMemory(0.0), sumSoFar(0.0)
61 , factorSoFar(0.0), waitingForOperand(true)
62{
63//! [0]
64
65//! [1]
66 display = new QLineEdit("0");
67//! [1] //! [2]
68 display->setReadOnly(true);
69 display->setAlignment(Qt::AlignRight);
70 display->setMaxLength(15);
71
72 QFont font = display->font();
73 font.setPointSize(font.pointSize() + 8);
74 display->setFont(font);
75//! [2]
76
77//! [4]
78 for (int i = 0; i < NumDigitButtons; ++i)
79 digitButtons[i] = createButton(text: QString::number(i), SLOT(digitClicked()));
80
81 Button *pointButton = createButton(text: tr(s: "."), SLOT(pointClicked()));
82 Button *changeSignButton = createButton(text: tr(s: "\302\261"), SLOT(changeSignClicked()));
83
84 Button *backspaceButton = createButton(text: tr(s: "Backspace"), SLOT(backspaceClicked()));
85 Button *clearButton = createButton(text: tr(s: "Clear"), SLOT(clear()));
86 Button *clearAllButton = createButton(text: tr(s: "Clear All"), SLOT(clearAll()));
87
88 Button *clearMemoryButton = createButton(text: tr(s: "MC"), SLOT(clearMemory()));
89 Button *readMemoryButton = createButton(text: tr(s: "MR"), SLOT(readMemory()));
90 Button *setMemoryButton = createButton(text: tr(s: "MS"), SLOT(setMemory()));
91 Button *addToMemoryButton = createButton(text: tr(s: "M+"), SLOT(addToMemory()));
92
93 Button *divisionButton = createButton(text: tr(s: "\303\267"), SLOT(multiplicativeOperatorClicked()));
94 Button *timesButton = createButton(text: tr(s: "\303\227"), SLOT(multiplicativeOperatorClicked()));
95 Button *minusButton = createButton(text: tr(s: "-"), SLOT(additiveOperatorClicked()));
96 Button *plusButton = createButton(text: tr(s: "+"), SLOT(additiveOperatorClicked()));
97
98 Button *squareRootButton = createButton(text: tr(s: "Sqrt"), SLOT(unaryOperatorClicked()));
99 Button *powerButton = createButton(text: tr(s: "x\302\262"), SLOT(unaryOperatorClicked()));
100 Button *reciprocalButton = createButton(text: tr(s: "1/x"), SLOT(unaryOperatorClicked()));
101 Button *equalButton = createButton(text: tr(s: "="), SLOT(equalClicked()));
102//! [4]
103
104//! [5]
105 QGridLayout *mainLayout = new QGridLayout;
106//! [5] //! [6]
107 mainLayout->setSizeConstraint(QLayout::SetFixedSize);
108 mainLayout->addWidget(display, row: 0, column: 0, rowSpan: 1, columnSpan: 6);
109 mainLayout->addWidget(backspaceButton, row: 1, column: 0, rowSpan: 1, columnSpan: 2);
110 mainLayout->addWidget(clearButton, row: 1, column: 2, rowSpan: 1, columnSpan: 2);
111 mainLayout->addWidget(clearAllButton, row: 1, column: 4, rowSpan: 1, columnSpan: 2);
112
113 mainLayout->addWidget(clearMemoryButton, row: 2, column: 0);
114 mainLayout->addWidget(readMemoryButton, row: 3, column: 0);
115 mainLayout->addWidget(setMemoryButton, row: 4, column: 0);
116 mainLayout->addWidget(addToMemoryButton, row: 5, column: 0);
117
118 for (int i = 1; i < NumDigitButtons; ++i) {
119 int row = ((9 - i) / 3) + 2;
120 int column = ((i - 1) % 3) + 1;
121 mainLayout->addWidget(digitButtons[i], row, column);
122 }
123
124 mainLayout->addWidget(digitButtons[0], row: 5, column: 1);
125 mainLayout->addWidget(pointButton, row: 5, column: 2);
126 mainLayout->addWidget(changeSignButton, row: 5, column: 3);
127
128 mainLayout->addWidget(divisionButton, row: 2, column: 4);
129 mainLayout->addWidget(timesButton, row: 3, column: 4);
130 mainLayout->addWidget(minusButton, row: 4, column: 4);
131 mainLayout->addWidget(plusButton, row: 5, column: 4);
132
133 mainLayout->addWidget(squareRootButton, row: 2, column: 5);
134 mainLayout->addWidget(powerButton, row: 3, column: 5);
135 mainLayout->addWidget(reciprocalButton, row: 4, column: 5);
136 mainLayout->addWidget(equalButton, row: 5, column: 5);
137 setLayout(mainLayout);
138
139 setWindowTitle(tr(s: "Calculator"));
140}
141//! [6]
142
143//! [7]
144void Calculator::digitClicked()
145{
146 Button *clickedButton = qobject_cast<Button *>(object: sender());
147 int digitValue = clickedButton->text().toInt();
148 if (display->text() == "0" && digitValue == 0.0)
149 return;
150
151 if (waitingForOperand) {
152 display->clear();
153 waitingForOperand = false;
154 }
155 display->setText(display->text() + QString::number(digitValue));
156}
157//! [7]
158
159//! [8]
160void Calculator::unaryOperatorClicked()
161//! [8] //! [9]
162{
163 Button *clickedButton = qobject_cast<Button *>(object: sender());
164 QString clickedOperator = clickedButton->text();
165 double operand = display->text().toDouble();
166 double result = 0.0;
167
168 if (clickedOperator == tr(s: "Sqrt")) {
169 if (operand < 0.0) {
170 abortOperation();
171 return;
172 }
173 result = std::sqrt(x: operand);
174 } else if (clickedOperator == tr(s: "x\302\262")) {
175 result = std::pow(x: operand, y: 2.0);
176 } else if (clickedOperator == tr(s: "1/x")) {
177 if (operand == 0.0) {
178 abortOperation();
179 return;
180 }
181 result = 1.0 / operand;
182 }
183 display->setText(QString::number(result));
184 waitingForOperand = true;
185}
186//! [9]
187
188//! [10]
189void Calculator::additiveOperatorClicked()
190//! [10] //! [11]
191{
192 Button *clickedButton = qobject_cast<Button *>(object: sender());
193 if (!clickedButton)
194 return;
195 QString clickedOperator = clickedButton->text();
196 double operand = display->text().toDouble();
197
198//! [11] //! [12]
199 if (!pendingMultiplicativeOperator.isEmpty()) {
200//! [12] //! [13]
201 if (!calculate(rightOperand: operand, pendingOperator: pendingMultiplicativeOperator)) {
202 abortOperation();
203 return;
204 }
205 display->setText(QString::number(factorSoFar));
206 operand = factorSoFar;
207 factorSoFar = 0.0;
208 pendingMultiplicativeOperator.clear();
209 }
210
211//! [13] //! [14]
212 if (!pendingAdditiveOperator.isEmpty()) {
213//! [14] //! [15]
214 if (!calculate(rightOperand: operand, pendingOperator: pendingAdditiveOperator)) {
215 abortOperation();
216 return;
217 }
218 display->setText(QString::number(sumSoFar));
219 } else {
220 sumSoFar = operand;
221 }
222
223//! [15] //! [16]
224 pendingAdditiveOperator = clickedOperator;
225//! [16] //! [17]
226 waitingForOperand = true;
227}
228//! [17]
229
230//! [18]
231void Calculator::multiplicativeOperatorClicked()
232{
233 Button *clickedButton = qobject_cast<Button *>(object: sender());
234 if (!clickedButton)
235 return;
236 QString clickedOperator = clickedButton->text();
237 double operand = display->text().toDouble();
238
239 if (!pendingMultiplicativeOperator.isEmpty()) {
240 if (!calculate(rightOperand: operand, pendingOperator: pendingMultiplicativeOperator)) {
241 abortOperation();
242 return;
243 }
244 display->setText(QString::number(factorSoFar));
245 } else {
246 factorSoFar = operand;
247 }
248
249 pendingMultiplicativeOperator = clickedOperator;
250 waitingForOperand = true;
251}
252//! [18]
253
254//! [20]
255void Calculator::equalClicked()
256{
257 double operand = display->text().toDouble();
258
259 if (!pendingMultiplicativeOperator.isEmpty()) {
260 if (!calculate(rightOperand: operand, pendingOperator: pendingMultiplicativeOperator)) {
261 abortOperation();
262 return;
263 }
264 operand = factorSoFar;
265 factorSoFar = 0.0;
266 pendingMultiplicativeOperator.clear();
267 }
268 if (!pendingAdditiveOperator.isEmpty()) {
269 if (!calculate(rightOperand: operand, pendingOperator: pendingAdditiveOperator)) {
270 abortOperation();
271 return;
272 }
273 pendingAdditiveOperator.clear();
274 } else {
275 sumSoFar = operand;
276 }
277
278 display->setText(QString::number(sumSoFar));
279 sumSoFar = 0.0;
280 waitingForOperand = true;
281}
282//! [20]
283
284//! [22]
285void Calculator::pointClicked()
286{
287 if (waitingForOperand)
288 display->setText("0");
289 if (!display->text().contains(c: '.'))
290 display->setText(display->text() + tr(s: "."));
291 waitingForOperand = false;
292}
293//! [22]
294
295//! [24]
296void Calculator::changeSignClicked()
297{
298 QString text = display->text();
299 double value = text.toDouble();
300
301 if (value > 0.0) {
302 text.prepend(s: tr(s: "-"));
303 } else if (value < 0.0) {
304 text.remove(i: 0, len: 1);
305 }
306 display->setText(text);
307}
308//! [24]
309
310//! [26]
311void Calculator::backspaceClicked()
312{
313 if (waitingForOperand)
314 return;
315
316 QString text = display->text();
317 text.chop(n: 1);
318 if (text.isEmpty()) {
319 text = "0";
320 waitingForOperand = true;
321 }
322 display->setText(text);
323}
324//! [26]
325
326//! [28]
327void Calculator::clear()
328{
329 if (waitingForOperand)
330 return;
331
332 display->setText("0");
333 waitingForOperand = true;
334}
335//! [28]
336
337//! [30]
338void Calculator::clearAll()
339{
340 sumSoFar = 0.0;
341 factorSoFar = 0.0;
342 pendingAdditiveOperator.clear();
343 pendingMultiplicativeOperator.clear();
344 display->setText("0");
345 waitingForOperand = true;
346}
347//! [30]
348
349//! [32]
350void Calculator::clearMemory()
351{
352 sumInMemory = 0.0;
353}
354
355void Calculator::readMemory()
356{
357 display->setText(QString::number(sumInMemory));
358 waitingForOperand = true;
359}
360
361void Calculator::setMemory()
362{
363 equalClicked();
364 sumInMemory = display->text().toDouble();
365}
366
367void Calculator::addToMemory()
368{
369 equalClicked();
370 sumInMemory += display->text().toDouble();
371}
372//! [32]
373//! [34]
374Button *Calculator::createButton(const QString &text, const char *member)
375{
376 Button *button = new Button(text);
377 connect(sender: button, SIGNAL(clicked()), receiver: this, member);
378 return button;
379}
380//! [34]
381
382//! [36]
383void Calculator::abortOperation()
384{
385 clearAll();
386 display->setText(tr(s: "####"));
387}
388//! [36]
389
390//! [38]
391bool Calculator::calculate(double rightOperand, const QString &pendingOperator)
392{
393 if (pendingOperator == tr(s: "+")) {
394 sumSoFar += rightOperand;
395 } else if (pendingOperator == tr(s: "-")) {
396 sumSoFar -= rightOperand;
397 } else if (pendingOperator == tr(s: "\303\227")) {
398 factorSoFar *= rightOperand;
399 } else if (pendingOperator == tr(s: "\303\267")) {
400 if (rightOperand == 0.0)
401 return false;
402 factorSoFar /= rightOperand;
403 }
404 return true;
405}
406//! [38]
407

source code of qtbase/examples/widgets/widgets/calculator/calculator.cpp