1/*
2 SPDX-FileCopyrightText: 2001-2013 Evan Teran <evan.teran@gmail.com>
3 SPDX-FileCopyrightText: 2006 Michel Marti <mma@objectxp.com>
4 SPDX-FileCopyrightText: 1996-2000 Bernd Johannes Wuebben <wuebben@kde.org>
5
6 SPDX-License-Identifier: GPL-2.0-or-later
7*/
8
9#include "kcalc.h"
10#include "kcalc_version.h"
11
12#include <clocale>
13
14#include <QActionGroup>
15#include <QApplication>
16#include <QButtonGroup>
17#include <QCommandLineParser>
18#include <QCursor>
19#include <QKeyEvent>
20#include <QMenuBar>
21#include <QShortcut>
22#include <QStyle>
23
24#include <KAboutData>
25#include <KAcceleratorManager>
26#include <KActionCollection>
27#include <KColorMimeData>
28#include <KConfigDialog>
29#include <KCrash>
30#include <KStandardAction>
31#include <KToggleAction>
32#include <KToolBar>
33#include <KXMLGUIFactory>
34
35#include "kcalc_bitset.h"
36#include "kcalc_const_menu.h"
37#include "kcalc_settings.h"
38#include "kcalc_statusbar.h"
39#include "kcalcdisplay.h"
40#include "kcalchistory.h"
41
42namespace
43{
44const int maxprecision = 1000;
45}
46
47//------------------------------------------------------------------------------
48// Name: KCalculator
49// Desc: constructor
50//------------------------------------------------------------------------------
51KCalculator::KCalculator(QWidget *parent)
52 : KXmlGuiWindow(parent)
53 , memory_num_(0.0)
54 , core()
55{
56 // central widget to contain all the elements
57 auto const central = new QWidget(this);
58 central->setLayoutDirection(Qt::LeftToRight);
59 setCentralWidget(central);
60 KAcceleratorManager::setNoAccel(central);
61
62 setAutoSaveSettings(group: QStringLiteral("KCalcMainWindow"));
63
64 // load science constants_ from xml-file
65 KCalcConstMenu::init_consts();
66
67 // setup interface (order is critical)
68 setupUi(central);
69 setupMainActions();
70 setStatusBar(new KCalcStatusBar(this));
71 createGUI();
72 setupKeys();
73
74 toolBar()->hide(); // hide by default
75
76 // create button groups
77 base_choose_group_ = new QButtonGroup(this);
78 base_choose_group_->setExclusive(true);
79 base_choose_group_->addButton(hexRadio, HexMode);
80 base_choose_group_->addButton(decRadio, DecMode);
81 base_choose_group_->addButton(octRadio, OctMode);
82 base_choose_group_->addButton(binRadio, BinMode);
83 connect(base_choose_group_, &QButtonGroup::buttonClicked, this, &KCalculator::slotBaseSelected);
84
85 base_conversion_labels_ = {binDisplay, hexDisplay, decDisplay, octDisplay};
86
87 angle_choose_group_ = new QButtonGroup(this);
88 angle_choose_group_->
89 setExclusive(true);
90 angle_choose_group_->addButton(degRadio, DegMode);
91 angle_choose_group_->addButton(radRadio, RadMode);
92 angle_choose_group_->addButton(gradRadio, GradMode);
93 connect(angle_choose_group_, &QButtonGroup::buttonClicked, this, &KCalculator::slotAngleSelected);
94
95 // additional menu setup
96 constants_menu_ = createConstantsMenu();
97 menuBar()->insertMenu((menuBar()->actions)()[2], constants_menu_);
98
99 // misc setup
100 setColors();
101 setBaseFont(KCalcSettings::buttonFont());
102 setFonts();
103
104 // Show the result in the app's caption in taskbar (wishlist - bug #52858)
105 if (KCalcSettings::captionResult()) {
106 connect(calc_display, &KCalcDisplay::changedText, this, &KCalculator::setWindowTitle);
107 }
108
109 calc_display->changeSettings();
110 calc_history->changeSettings();
111 update_history_window_ = true;
112 setPrecision();
113
114 updateGeometry();
115
116 updateDisplay(UPDATE_FROM_CORE);
117 // clear history, otherwise we have a leading "0" in it
118 calc_history->clearHistory();
119
120 // misc settings
121 KCalcSettings::EnumCalculatorMode::type calculatorMode = KCalcSettings::calculatorMode();
122
123 switch (calculatorMode) {
124 case KCalcSettings::EnumCalculatorMode::science:
125 action_mode_science_->setChecked(true);
126 break;
127 case KCalcSettings::EnumCalculatorMode::statistics:
128 action_mode_statistic_->setChecked(true);
129 break;
130 case KCalcSettings::EnumCalculatorMode::numeral:
131 action_mode_numeral_->setChecked(true);
132 break;
133 case KCalcSettings::EnumCalculatorMode::simple:
134 default:
135 action_mode_simple_->setChecked(true);
136 }
137 is_still_in_launch_ = false;
138
139 setAngle();
140 setBase();
141
142 calc_display->setFocus();
143}
144
145//------------------------------------------------------------------------------
146// Name: ~KCalculator
147// Desc: deconstructor
148//------------------------------------------------------------------------------
149KCalculator::~KCalculator()
150{
151 KCalcSettings::self()->save();
152}
153
154//------------------------------------------------------------------------------
155// Name: setupMainActions
156// Desc: connects all of the basic actions
157//------------------------------------------------------------------------------
158void KCalculator::setupMainActions()
159{
160 // file menu
161 KStandardAction::quit(this, SLOT(close()), actionCollection());
162
163 // edit menu
164 KStandardAction::undo(calc_display, SLOT(slotHistoryBack()), actionCollection());
165 KStandardAction::redo(calc_display, SLOT(slotHistoryForward()), actionCollection());
166 KStandardAction::cut(calc_display, SLOT(slotCut()), actionCollection());
167 KStandardAction::copy(calc_display, SLOT(slotCopy()), actionCollection());
168 KStandardAction::paste(this, SLOT(slotPaste()), actionCollection());
169
170 // mode menu
171 auto modeGroup = new QActionGroup(this);
172
173 action_mode_simple_ = actionCollection()->add<KToggleAction>(QStringLiteral("mode_simple"));
174 action_mode_simple_->setActionGroup(modeGroup);
175 action_mode_simple_->setText(i18n("Simple Mode"));
176 connect(action_mode_simple_, &KToggleAction::toggled, this, &KCalculator::slotSetSimpleMode);
177
178 action_mode_science_ = actionCollection()->add<KToggleAction>(QStringLiteral("mode_science"));
179 action_mode_science_->setActionGroup(modeGroup);
180 action_mode_science_->setText(i18n("Science Mode"));
181 connect(action_mode_science_, &KToggleAction::toggled, this, &KCalculator::slotSetScienceMode);
182
183 action_mode_statistic_ = actionCollection()->add<KToggleAction>(QStringLiteral("mode_statistics"));
184 action_mode_statistic_->setActionGroup(modeGroup);
185 action_mode_statistic_->setText(i18n("Statistic Mode"));
186 connect(action_mode_statistic_, &KToggleAction::toggled, this, &KCalculator::slotSetStatisticMode);
187
188 action_mode_numeral_ = actionCollection()->add<KToggleAction>(QStringLiteral("mode_numeral"));
189 action_mode_numeral_->setActionGroup(modeGroup);
190 action_mode_numeral_->setText(i18n("Numeral System Mode"));
191 connect(action_mode_numeral_, &KToggleAction::toggled, this, &KCalculator::slotSetNumeralMode);
192
193 // settings menu
194 action_history_show_ = actionCollection()->add<KToggleAction>(QStringLiteral("show_history"));
195 action_history_show_->setText(i18n("Show &History"));
196 action_history_show_->setChecked(true);
197 actionCollection()->setDefaultShortcut(action_history_show_, Qt::CTRL | Qt::Key_H);
198 connect(action_history_show_, &KToggleAction::toggled, this, &KCalculator::slotHistoryshow);
199
200 action_constants_show_ = actionCollection()->add<KToggleAction>(QStringLiteral("show_constants"));
201 action_constants_show_->setText(i18n("Constants &Buttons"));
202 action_constants_show_->setChecked(true);
203 connect(action_constants_show_, &KToggleAction::toggled, this, &KCalculator::slotConstantsShow);
204
205 action_bitset_show_ = actionCollection()->add<KToggleAction>(QStringLiteral("show_bitset"));
206 action_bitset_show_->setText(i18n("Show B&it Edit"));
207 action_bitset_show_->setChecked(true);
208 connect(action_bitset_show_, &KToggleAction::toggled, this, &KCalculator::slotBitsetshow);
209
210 KStandardAction::preferences(this, &KCalculator::showSettings, actionCollection());
211
212 KStandardAction::keyBindings(guiFactory(), &KXMLGUIFactory::showConfigureShortcutsDialog, actionCollection());
213}
214
215//------------------------------------------------------------------------------
216// Name: createConstantsMenu
217// Desc: creates and returns a pointer to the constant menu
218//------------------------------------------------------------------------------
219KCalcConstMenu *KCalculator::createConstantsMenu()
220{
221 auto const menu = new KCalcConstMenu(i18n("&Constants"), this);
222 connect(menu, &KCalcConstMenu::triggeredConstant, this, &KCalculator::slotConstantToDisplay);
223 return menu;
224}
225
226//------------------------------------------------------------------------------
227// Name: statusBar
228// Desc: returns a pointer to the status bar
229//------------------------------------------------------------------------------
230KCalcStatusBar *KCalculator::statusBar()
231{
232 return static_cast<KCalcStatusBar *>(KXmlGuiWindow::statusBar());
233}
234
235//------------------------------------------------------------------------------
236// Name: setupNumberKeys
237// Desc: sets up number keys and related shortcuts
238//------------------------------------------------------------------------------
239void KCalculator::setupNumberKeys()
240{
241 num_button_group_ = new QButtonGroup(this);
242 connect(num_button_group_, &QButtonGroup::buttonClicked, this, &KCalculator::slotNumberclicked);
243
244 num_button_group_->addButton(pb0, 0);
245 num_button_group_->addButton(pb1, 1);
246 num_button_group_->addButton(pb2, 2);
247 num_button_group_->addButton(pb3, 3);
248 num_button_group_->addButton(pb4, 4);
249 num_button_group_->addButton(pb5, 5);
250 num_button_group_->addButton(pb6, 6);
251 num_button_group_->addButton(pb7, 7);
252 num_button_group_->addButton(pb8, 8);
253 num_button_group_->addButton(pb9, 9);
254 num_button_group_->addButton(pbA, 0xA);
255 num_button_group_->addButton(pbB, 0xB);
256 num_button_group_->addButton(pbC, 0xC);
257 num_button_group_->addButton(pbD, 0xD);
258 num_button_group_->addButton(pbE, 0xE);
259 num_button_group_->addButton(pbF, 0xF);
260 connect(this, &KCalculator::switchShowAccels, pb0, &KCalcButton::slotSetAccelDisplayMode);
261 connect(this, &KCalculator::switchShowAccels, pb1, &KCalcButton::slotSetAccelDisplayMode);
262 connect(this, &KCalculator::switchShowAccels, pb2, &KCalcButton::slotSetAccelDisplayMode);
263 connect(this, &KCalculator::switchShowAccels, pb3, &KCalcButton::slotSetAccelDisplayMode);
264 connect(this, &KCalculator::switchShowAccels, pb4, &KCalcButton::slotSetAccelDisplayMode);
265 connect(this, &KCalculator::switchShowAccels, pb5, &KCalcButton::slotSetAccelDisplayMode);
266 connect(this, &KCalculator::switchShowAccels, pb6, &KCalcButton::slotSetAccelDisplayMode);
267 connect(this, &KCalculator::switchShowAccels, pb7, &KCalcButton::slotSetAccelDisplayMode);
268 connect(this, &KCalculator::switchShowAccels, pb8, &KCalcButton::slotSetAccelDisplayMode);
269 connect(this, &KCalculator::switchShowAccels, pb9, &KCalcButton::slotSetAccelDisplayMode);
270 connect(this, &KCalculator::switchShowAccels, pbA, &KCalcButton::slotSetAccelDisplayMode);
271 connect(this, &KCalculator::switchShowAccels, pbB, &KCalcButton::slotSetAccelDisplayMode);
272 connect(this, &KCalculator::switchShowAccels, pbC, &KCalcButton::slotSetAccelDisplayMode);
273 connect(this, &KCalculator::switchShowAccels, pbD, &KCalcButton::slotSetAccelDisplayMode);
274 connect(this, &KCalculator::switchShowAccels, pbE, &KCalcButton::slotSetAccelDisplayMode);
275 connect(this, &KCalculator::switchShowAccels, pbF, &KCalcButton::slotSetAccelDisplayMode);
276}
277
278//------------------------------------------------------------------------------
279// Name: setupRightKeypad
280// Desc: sets up right keypad keys and related shortcuts
281//------------------------------------------------------------------------------
282void KCalculator::setupRightKeypad()
283{
284 connect(pbShift, &KCalcButton::toggled, this, &KCalculator::slotShifttoggled);
285 connect(this, &KCalculator::switchShowAccels, pbShift, &KCalcButton::slotSetAccelDisplayMode);
286
287 pbBackspace->setShortcut(QKeySequence(Qt::Key_Backspace));
288 new QShortcut(Qt::Key_PageUp, pbBackspace, SLOT(animateClick()));
289 connect(pbBackspace, &KCalcButton::clicked, this, &KCalculator::slotBackspaceclicked);
290 connect(this, &KCalculator::switchShowAccels, pbBackspace, &KCalcButton::slotSetAccelDisplayMode);
291
292 pbClear->setShortcut(QKeySequence(Qt::Key_Escape));
293 new QShortcut(Qt::Key_PageUp, pbClear, SLOT(animateClick()));
294 connect(pbClear, &KCalcButton::clicked, this, &KCalculator::slotClearclicked);
295 connect(this, &KCalculator::switchShowAccels, pbClear, &KCalcButton::slotSetAccelDisplayMode);
296
297 pbAllClear->setShortcut(QKeySequence(Qt::Key_Delete));
298 new QShortcut(Qt::Key_PageDown, pbAllClear, SLOT(animateClick()));
299 connect(pbAllClear, &KCalcButton::clicked, this, &KCalculator::slotAllClearclicked);
300 connect(this, &KCalculator::switchShowAccels, pbAllClear, &KCalcButton::slotSetAccelDisplayMode);
301 // also clear the content of the history when clicked
302 connect(pbAllClear, &KCalcButton::clicked, calc_history, &KCalcHistory::clearHistory);
303
304 pbParenOpen->setShortcut(QKeySequence(Qt::Key_ParenLeft));
305 connect(pbParenOpen, &KCalcButton::clicked, this, &KCalculator::slotParenOpenclicked);
306 connect(this, &KCalculator::switchShowAccels, pbParenOpen, &KCalcButton::slotSetAccelDisplayMode);
307
308 pbParenClose->setShortcut(QKeySequence(Qt::Key_ParenRight));
309 connect(pbParenClose, &KCalcButton::clicked, this, &KCalculator::slotParenCloseclicked);
310 connect(this, &KCalculator::switchShowAccels, pbParenClose, &KCalcButton::slotSetAccelDisplayMode);
311
312 pbMemRecall->setDisabled(true); // nothing in memory at start
313 connect(pbMemRecall, &KCalcButton::clicked, this, &KCalculator::slotMemRecallclicked);
314 connect(this, &KCalculator::switchShowAccels, pbMemRecall, &KCalcButton::slotSetAccelDisplayMode);
315
316 connect(pbMemClear, &KCalcButton::clicked, this, &KCalculator::slotMemClearclicked);
317 connect(this, &KCalculator::switchShowAccels, pbMemClear, &KCalcButton::slotSetAccelDisplayMode);
318
319 pbMemPlusMinus->addMode(ModeNormal, i18nc("Add display to memory", "M+"), i18n("Add display to memory"));
320 pbMemPlusMinus->addMode(ModeShift, i18nc("Subtract from memory", "M\xe2\x88\x92"), i18n("Subtract from memory"));
321 connect(pbMemPlusMinus, &KCalcButton::clicked, this, &KCalculator::slotMemPlusMinusclicked);
322 connect(this, &KCalculator::switchShowAccels, pbMemPlusMinus, &KCalcButton::slotSetAccelDisplayMode);
323 connect(this, &KCalculator::switchMode, pbMemPlusMinus, &KCalcButton::slotSetMode);
324
325 connect(pbMemStore, &KCalcButton::clicked, this, &KCalculator::slotMemStoreclicked);
326 connect(this, &KCalculator::switchShowAccels, pbMemStore, &KCalcButton::slotSetAccelDisplayMode);
327
328 pbPercent->setShortcut(QKeySequence(Qt::Key_Percent));
329 connect(pbPercent, &KCalcButton::clicked, this, &KCalculator::slotPercentclicked);
330 connect(this, &KCalculator::switchShowAccels, pbPercent, &KCalcButton::slotSetAccelDisplayMode);
331
332 pbPlusMinus->setShortcut(QKeySequence(Qt::Key_Backslash));
333 connect(pbPlusMinus, &KCalcButton::clicked, this, &KCalculator::slotPlusMinusclicked);
334 connect(this, &KCalculator::switchShowAccels, pbPlusMinus, &KCalcButton::slotSetAccelDisplayMode);
335}
336
337//------------------------------------------------------------------------------
338// Name: setupNumericKeypad
339// Desc: sets up numeric keys and related shortcuts
340//------------------------------------------------------------------------------
341void KCalculator::setupNumericKeypad()
342{
343 pbCube->addMode(ModeNormal, i18nc("Third power", "x<sup>3</sup>"), i18n("Third power"));
344 pbCube->addMode(ModeShift, QStringLiteral("<sup>3</sup>&radic;x"), i18n("Cube root"));
345 connect(pbCube, &KCalcButton::clicked, this, &KCalculator::slotCubeclicked);
346 connect(this, &KCalculator::switchShowAccels, pbCube, &KCalcButton::slotSetAccelDisplayMode);
347 connect(this, &KCalculator::switchMode, pbCube, &KCalcButton::slotSetMode);
348
349 pbDivision->setShortcut(QKeySequence(Qt::Key_Slash));
350 new QShortcut(Qt::Key_division, pbDivision, SLOT(animateClick()));
351 connect(pbDivision, &KCalcButton::clicked, this, &KCalculator::slotDivisionclicked);
352 connect(this, &KCalculator::switchShowAccels, pbDivision, &KCalcButton::slotSetAccelDisplayMode);
353
354 pbMultiplication->setShortcut(QKeySequence(Qt::Key_Asterisk));
355 new QShortcut(Qt::Key_X, pbMultiplication, SLOT(animateClick()));
356 new QShortcut(Qt::Key_multiply, pbMultiplication, SLOT(animateClick()));
357 connect(pbMultiplication, &KCalcButton::clicked, this, &KCalculator::slotMultiplicationclicked);
358 connect(this, &KCalculator::switchShowAccels, pbMultiplication, &KCalcButton::slotSetAccelDisplayMode);
359
360 pbMinus->setShortcut(QKeySequence(Qt::Key_Minus));
361 connect(pbMinus, &KCalcButton::clicked, this, &KCalculator::slotMinusclicked);
362 connect(this, &KCalculator::switchShowAccels, pbMinus, &KCalcButton::slotSetAccelDisplayMode);
363
364 pbPlus->setShortcut(QKeySequence(Qt::Key_Plus));
365 connect(pbPlus, &KCalcButton::clicked, this, &KCalculator::slotPlusclicked);
366 connect(this, &KCalculator::switchShowAccels, pbPlus, &KCalcButton::slotSetAccelDisplayMode);
367
368 // set decimal separator from locale
369 pbPeriod->setText(QString(QLocale().decimalPoint()));
370 pbPeriod->setShortcut(QString(QLocale().decimalPoint()));
371
372 // add shortcut for the other decimal separator (point or comma)
373 if (QLocale().decimalPoint() == QLatin1Char('.')) {
374 new QShortcut(Qt::Key_Comma, pbPeriod, SLOT(animateClick()));
375 } else if (QLocale().decimalPoint() == QLatin1Char(',')) {
376 new QShortcut(Qt::Key_Period, pbPeriod, SLOT(animateClick()));
377 }
378
379 connect(pbPeriod, &KCalcButton::clicked, this, &KCalculator::slotPeriodclicked);
380 connect(this, &KCalculator::switchShowAccels, pbPeriod, &KCalcButton::slotSetAccelDisplayMode);
381
382 pbEqual->setShortcut(QKeySequence(Qt::Key_Enter));
383 new QShortcut(Qt::Key_Equal, pbEqual, SLOT(animateClick()));
384 new QShortcut(Qt::Key_Return, pbEqual, SLOT(animateClick()));
385 connect(pbEqual, &KCalcButton::clicked, this, &KCalculator::slotEqualclicked);
386 connect(this, &KCalculator::switchShowAccels, pbEqual, &KCalcButton::slotSetAccelDisplayMode);
387}
388
389//------------------------------------------------------------------------------
390// Name: setupLogicKeys
391// Desc: sets up logic keys and related shortcuts
392//------------------------------------------------------------------------------
393void KCalculator::setupLogicKeys()
394{
395 logic_buttons_.append(pbAND);
396 logic_buttons_.append(pbOR);
397 logic_buttons_.append(pbXOR);
398 logic_buttons_.append(pbLsh);
399 logic_buttons_.append(pbRsh);
400 logic_buttons_.append(pbCmp);
401
402 pbAND->setShortcut(QKeySequence(Qt::Key_Ampersand));
403 connect(this, &KCalculator::switchShowAccels, pbAND, &KCalcButton::slotSetAccelDisplayMode);
404 connect(pbAND, &KCalcButton::clicked, this, &KCalculator::slotANDclicked);
405
406 pbOR->setShortcut(QKeySequence(Qt::Key_Bar));
407 connect(this, &KCalculator::switchShowAccels, pbOR, &KCalcButton::slotSetAccelDisplayMode);
408 connect(pbOR, &KCalcButton::clicked, this, &KCalculator::slotORclicked);
409
410 connect(this, &KCalculator::switchShowAccels, pbXOR, &KCalcButton::slotSetAccelDisplayMode);
411 connect(pbXOR, &KCalcButton::clicked, this, &KCalculator::slotXORclicked);
412
413 pbLsh->setShortcut(QKeySequence(Qt::Key_Less));
414 connect(this, &KCalculator::switchShowAccels, pbLsh, &KCalcButton::slotSetAccelDisplayMode);
415 connect(pbLsh, &KCalcButton::clicked, this, &KCalculator::slotLeftShiftclicked);
416
417 pbRsh->setShortcut(QKeySequence(Qt::Key_Greater));
418 connect(this, &KCalculator::switchShowAccels, pbRsh, &KCalcButton::slotSetAccelDisplayMode);
419 connect(pbRsh, &KCalcButton::clicked, this, &KCalculator::slotRightShiftclicked);
420
421 pbCmp->setShortcut(QKeySequence(Qt::Key_AsciiTilde));
422 connect(this, &KCalculator::switchShowAccels, pbCmp, &KCalcButton::slotSetAccelDisplayMode);
423 connect(pbCmp, &KCalcButton::clicked, this, &KCalculator::slotNegateclicked);
424}
425
426//------------------------------------------------------------------------------
427// Name: setupLogicKeys
428// Desc: sets up scientific keys and related shortcuts
429//------------------------------------------------------------------------------
430void KCalculator::setupScientificKeys()
431{
432 scientific_buttons_.append(pbHyp);
433 scientific_buttons_.append(pbSin);
434 scientific_buttons_.append(pbCos);
435 scientific_buttons_.append(pbTan);
436 scientific_buttons_.append(pbLog);
437 scientific_buttons_.append(pbLn);
438
439 connect(this, &KCalculator::switchShowAccels, pbHyp, &KCalcButton::slotSetAccelDisplayMode);
440 connect(pbHyp, &KCalcButton::toggled, this, &KCalculator::slotHyptoggled);
441
442 pbSin->addMode(ModeNormal, i18nc("Sine", "sin"), i18n("Sine"));
443 pbSin->addMode(ModeShift, i18nc("Arc sine", "asin"), i18n("Arc sine"));
444 pbSin->addMode(ModeHyperbolic, i18nc("Hyperbolic sine", "sinh"), i18n("Hyperbolic sine"));
445 pbSin->addMode(ButtonModeFlags(ModeShift | ModeHyperbolic), i18nc("Inverse hyperbolic sine", "asinh"), i18n("Inverse hyperbolic sine"));
446 connect(this, &KCalculator::switchShowAccels, pbSin, &KCalcButton::slotSetAccelDisplayMode);
447 connect(this, &KCalculator::switchMode, pbSin, &KCalcButton::slotSetMode);
448 connect(pbSin, &KCalcButton::clicked, this, &KCalculator::slotSinclicked);
449
450 pbCos->addMode(ModeNormal, i18nc("Cosine", "cos"), i18n("Cosine"));
451 pbCos->addMode(ModeShift, i18nc("Arc cosine", "acos"), i18n("Arc cosine"));
452 pbCos->addMode(ModeHyperbolic, i18nc("Hyperbolic cosine", "cosh"), i18n("Hyperbolic cosine"));
453 pbCos->addMode(ButtonModeFlags(ModeShift | ModeHyperbolic), i18nc("Inverse hyperbolic cosine", "acosh"), i18n("Inverse hyperbolic cosine"));
454 connect(this, &KCalculator::switchShowAccels, pbCos, &KCalcButton::slotSetAccelDisplayMode);
455 connect(this, &KCalculator::switchMode, pbCos, &KCalcButton::slotSetMode);
456 connect(pbCos, &KCalcButton::clicked, this, &KCalculator::slotCosclicked);
457
458 pbTan->addMode(ModeNormal, i18nc("Tangent", "tan"), i18n("Tangent"));
459 pbTan->addMode(ModeShift, i18nc("Arc tangent", "atan"), i18n("Arc tangent"));
460 pbTan->addMode(ModeHyperbolic, i18nc("Hyperbolic tangent", "tanh"), i18n("Hyperbolic tangent"));
461 pbTan->addMode(ButtonModeFlags(ModeShift | ModeHyperbolic), i18nc("Inverse hyperbolic tangent", "atanh"), i18n("Inverse hyperbolic tangent"));
462 connect(this, &KCalculator::switchShowAccels, pbTan, &KCalcButton::slotSetAccelDisplayMode);
463 connect(this, &KCalculator::switchMode, pbTan, &KCalcButton::slotSetMode);
464 connect(pbTan, &KCalcButton::clicked, this, &KCalculator::slotTanclicked);
465
466 pbLog->addMode(ModeNormal, i18nc("Logarithm to base 10", "log"), i18n("Logarithm to base 10"));
467 pbLog->addMode(ModeShift, i18nc("10 to the power of x", "10<sup>x</sup>"), i18n("10 to the power of x"));
468 connect(this, &KCalculator::switchShowAccels, pbLog, &KCalcButton::slotSetAccelDisplayMode);
469 connect(this, &KCalculator::switchMode, pbLog, &KCalcButton::slotSetMode);
470 connect(pbLog, &KCalcButton::clicked, this, &KCalculator::slotLogclicked);
471 pbLn->addMode(ModeNormal, i18nc("Natural log", "ln"), i18n("Natural log"));
472 pbLn->addMode(ModeShift, i18nc("Exponential function", "e<sup>x</sup>"), i18n("Exponential function"));
473 connect(this, &KCalculator::switchShowAccels, pbLn, &KCalcButton::slotSetAccelDisplayMode);
474 connect(this, &KCalculator::switchMode, pbLn, &KCalcButton::slotSetMode);
475 connect(pbLn, &KCalcButton::clicked, this, &KCalculator::slotLnclicked);
476}
477
478//------------------------------------------------------------------------------
479// Name: setupStatisticKeys
480// Desc: sets up statistical keys and related shortcuts
481//------------------------------------------------------------------------------
482void KCalculator::setupStatisticKeys()
483{
484 stat_buttons_.append(pbNData);
485 stat_buttons_.append(pbMean);
486 stat_buttons_.append(pbSd);
487 stat_buttons_.append(pbMed);
488 stat_buttons_.append(pbDat);
489 stat_buttons_.append(pbCSt);
490
491 pbNData->addMode(ModeNormal, i18nc("Number of data entered", "N"), i18n("Number of data entered"));
492 pbNData->addMode(ModeShift, QString::fromUtf8("\xce\xa3") + QLatin1Char('x'), i18n("Sum of all data items"));
493 connect(this, &KCalculator::switchShowAccels, pbNData, &KCalcButton::slotSetAccelDisplayMode);
494 connect(this, &KCalculator::switchMode, pbNData, &KCalcButton::slotSetMode);
495 connect(pbNData, &KCalcButton::clicked, this, &KCalculator::slotStatNumclicked);
496
497 pbMean->addMode(ModeNormal, i18nc("Mean", "Mea"), i18n("Mean"));
498 pbMean->addMode(ModeShift, QString::fromUtf8("\xce\xa3") + QLatin1String("x<sup>2</sup>"), i18n("Sum of all data items squared"));
499 connect(this, &KCalculator::switchShowAccels, pbMean, &KCalcButton::slotSetAccelDisplayMode);
500 connect(this, &KCalculator::switchMode, pbMean, &KCalcButton::slotSetMode);
501 connect(pbMean, &KCalcButton::clicked, this, &KCalculator::slotStatMeanclicked);
502
503 pbSd->addMode(ModeNormal, QString::fromUtf8("\xcf\x83") + QLatin1String("<sub>N</sub>"), i18n("Standard deviation"));
504 pbSd->addMode(ModeShift, QString::fromUtf8("\xcf\x83") + QLatin1String("<sub>N-1</sub>"), i18n("Sample standard deviation"));
505 connect(this, &KCalculator::switchShowAccels, pbSd, &KCalcButton::slotSetAccelDisplayMode);
506 connect(this, &KCalculator::switchMode, pbSd, &KCalcButton::slotSetMode);
507 connect(pbSd, &KCalcButton::clicked, this, &KCalculator::slotStatStdDevclicked);
508
509 connect(this, &KCalculator::switchShowAccels, pbMed, &KCalcButton::slotSetAccelDisplayMode);
510 connect(pbMed, &KCalcButton::clicked, this, &KCalculator::slotStatMedianclicked);
511
512 pbDat->addMode(ModeNormal, i18nc("Enter data", "Dat"), i18n("Enter data"));
513 pbDat->addMode(ModeShift, i18nc("Delete last data item", "CDat"), i18n("Delete last data item"));
514 connect(this, &KCalculator::switchShowAccels, pbDat, &KCalcButton::slotSetAccelDisplayMode);
515 connect(this, &KCalculator::switchMode, pbDat, &KCalcButton::slotSetMode);
516 connect(pbDat, &KCalcButton::clicked, this, &KCalculator::slotStatDataInputclicked);
517
518 connect(this, &KCalculator::switchShowAccels, pbCSt, &KCalcButton::slotSetAccelDisplayMode);
519 connect(pbCSt, &KCalcButton::clicked, this, &KCalculator::slotStatClearDataclicked);
520}
521
522//------------------------------------------------------------------------------
523// Name: setupConstantsKeys
524// Desc: sets up constants keys and related shortcuts
525//------------------------------------------------------------------------------
526void KCalculator::setupConstantsKeys()
527{
528 const_buttons_.append(pbC1);
529 const_buttons_.append(pbC2);
530 const_buttons_.append(pbC3);
531 const_buttons_.append(pbC4);
532 const_buttons_.append(pbC5);
533 const_buttons_.append(pbC6);
534
535 pbC1->setButtonNumber(0);
536 connect(this, &KCalculator::switchShowAccels, pbC1, &KCalcConstButton::slotSetAccelDisplayMode);
537 connect(this, &KCalculator::switchMode, pbC1, &KCalcConstButton::slotSetMode);
538 connect(pbC1, &KCalcConstButton::constButtonClicked, this, &KCalculator::slotConstclicked);
539
540 pbC2->setButtonNumber(1);
541 connect(this, &KCalculator::switchShowAccels, pbC2, &KCalcConstButton::slotSetAccelDisplayMode);
542 connect(this, &KCalculator::switchMode, pbC2, &KCalcConstButton::slotSetMode);
543 connect(pbC2, &KCalcConstButton::constButtonClicked, this, &KCalculator::slotConstclicked);
544
545 pbC3->setButtonNumber(2);
546 connect(this, &KCalculator::switchShowAccels, pbC3, &KCalcConstButton::slotSetAccelDisplayMode);
547 connect(this, &KCalculator::switchMode, pbC3, &KCalcConstButton::slotSetMode);
548 connect(pbC3, &KCalcConstButton::constButtonClicked, this, &KCalculator::slotConstclicked);
549
550 pbC4->setButtonNumber(3);
551 connect(this, &KCalculator::switchShowAccels, pbC4, &KCalcConstButton::slotSetAccelDisplayMode);
552 connect(this, &KCalculator::switchMode, pbC4, &KCalcConstButton::slotSetMode);
553 connect(pbC4, &KCalcConstButton::constButtonClicked, this, &KCalculator::slotConstclicked);
554
555 pbC5->setButtonNumber(4);
556 connect(this, &KCalculator::switchShowAccels, pbC5, &KCalcConstButton::slotSetAccelDisplayMode);
557 connect(this, &KCalculator::switchMode, pbC5, &KCalcConstButton::slotSetMode);
558 connect(pbC5, &KCalcConstButton::constButtonClicked, this, &KCalculator::slotConstclicked);
559
560 pbC6->setButtonNumber(5);
561 connect(this, &KCalculator::switchShowAccels, pbC6, &KCalcConstButton::slotSetAccelDisplayMode);
562 connect(this, &KCalculator::switchMode, pbC6, &KCalcConstButton::slotSetMode);
563 connect(pbC6, &KCalcConstButton::constButtonClicked, this, &KCalculator::slotConstclicked);
564
565 changeButtonNames();
566}
567
568//------------------------------------------------------------------------------
569// Name: setupMiscKeys
570// Desc: sets up misc keys and related shortcuts
571//------------------------------------------------------------------------------
572void KCalculator::setupMiscKeys()
573{
574 pbMod->addMode(ModeNormal, i18nc("Modulo", "mod"), i18n("Modulo"));
575 pbMod->addMode(ModeShift, i18nc("Integer division", "IntDiv"), i18n("Integer division"));
576 connect(this, &KCalculator::switchMode, pbMod, &KCalcButton::slotSetMode);
577 connect(this, &KCalculator::switchShowAccels, pbMod, &KCalcButton::slotSetAccelDisplayMode);
578 pbMod->setShortcut(QKeySequence(Qt::Key_Colon));
579 connect(pbMod, &KCalcButton::clicked, this, &KCalculator::slotModclicked);
580
581 pbReci->addMode(ModeNormal, i18nc("Reciprocal", "1/x"), i18n("Reciprocal"));
582 pbReci->addMode(ModeShift, i18nc("n Choose m", "nCm"), i18n("n Choose m"));
583 connect(this, &KCalculator::switchMode, pbReci, &KCalcButton::slotSetMode);
584 connect(this, &KCalculator::switchShowAccels, pbReci, &KCalcButton::slotSetAccelDisplayMode);
585 connect(pbReci, &KCalcButton::clicked, this, &KCalculator::slotReciclicked);
586
587 pbFactorial->addMode(ModeNormal, i18nc("Factorial", "x!"), i18n("Factorial"));
588 pbFactorial->addMode(ModeShift, QStringLiteral("&#915;"), i18n("Gamma"));
589 pbFactorial->setShortcut(QKeySequence(Qt::Key_Exclam));
590 connect(this, &KCalculator::switchShowAccels, pbFactorial, &KCalcButton::slotSetAccelDisplayMode);
591 connect(this, &KCalculator::switchMode, pbFactorial, &KCalcButton::slotSetMode);
592 connect(pbFactorial, &KCalcButton::clicked, this, &KCalculator::slotFactorialclicked);
593
594 pbSquare->addMode(ModeNormal, i18nc("Square", "x<sup>2</sup>"), i18n("Square"));
595 pbSquare->addMode(ModeShift, QStringLiteral("&radic;x"), i18n("Square root"));
596 pbSquare->setShortcut(QKeySequence(Qt::Key_BracketLeft));
597 new QShortcut(Qt::Key_twosuperior, pbSquare, SLOT(animateClick()));
598 connect(this, &KCalculator::switchShowAccels, pbSquare, &KCalcButton::slotSetAccelDisplayMode);
599 connect(this, &KCalculator::switchMode, pbSquare, &KCalcButton::slotSetMode);
600 connect(pbSquare, &KCalcButton::clicked, this, &KCalculator::slotSquareclicked);
601
602 pbPower->addMode(ModeNormal, i18nc("x to the power of y", "x<sup>y</sup>"), i18n("x to the power of y"));
603 pbPower->addMode(ModeShift, i18nc("x to the power of 1/y", "x<sup>1/y</sup>"), i18n("x to the power of 1/y"));
604 connect(this, &KCalculator::switchShowAccels, pbPower, &KCalcButton::slotSetAccelDisplayMode);
605 connect(this, &KCalculator::switchMode, pbPower, &KCalcButton::slotSetMode);
606 pbPower->setShortcut(QKeySequence(Qt::Key_AsciiCircum));
607 connect(pbPower, &KCalcButton::clicked, this, &KCalculator::slotPowerclicked);
608
609 pbEE->addMode(ModeNormal,
610 QStringLiteral("x<small>"
611 "\xb7"
612 "10</small><sup>y</sup>"),
613 i18n("Exponent"));
614 connect(this, &KCalculator::switchShowAccels, pbEE, &KCalcButton::slotSetAccelDisplayMode);
615 connect(pbEE, &KCalcButton::clicked, this, &KCalculator::slotEEclicked);
616}
617
618//------------------------------------------------------------------------------
619// Name: createConstantsMenu
620// Desc: additional setup for button keys
621// NOTE: all alphanumeric shorts set in ui file
622//------------------------------------------------------------------------------
623void KCalculator::setupKeys()
624{
625 setupNumberKeys();
626 setupRightKeypad();
627 setupNumericKeypad();
628 setupLogicKeys();
629 setupScientificKeys();
630 setupStatisticKeys();
631 setupConstantsKeys();
632 setupMiscKeys();
633
634 // other button lists
635
636 function_button_list_.append(pbHyp);
637 function_button_list_.append(pbShift);
638 function_button_list_.append(pbEE);
639 function_button_list_.append(pbSin);
640 function_button_list_.append(pbPlusMinus);
641 function_button_list_.append(pbCos);
642 function_button_list_.append(pbReci);
643 function_button_list_.append(pbTan);
644 function_button_list_.append(pbFactorial);
645 function_button_list_.append(pbLog);
646 function_button_list_.append(pbSquare);
647 function_button_list_.append(pbLn);
648 function_button_list_.append(pbPower);
649 function_button_list_.append(pbCube);
650
651 mem_button_list_.append(pbMemRecall);
652 mem_button_list_.append(pbMemPlusMinus);
653 mem_button_list_.append(pbMemStore);
654 mem_button_list_.append(pbMemClear);
655 mem_button_list_.append(pbClear);
656 mem_button_list_.append(pbAllClear);
657 mem_button_list_.append(pbBackspace);
658
659 operation_button_list_.append(pbMultiplication);
660 operation_button_list_.append(pbParenOpen);
661 operation_button_list_.append(pbParenClose);
662 operation_button_list_.append(pbAND);
663 operation_button_list_.append(pbDivision);
664 operation_button_list_.append(pbOR);
665 operation_button_list_.append(pbXOR);
666 operation_button_list_.append(pbPlus);
667 operation_button_list_.append(pbMinus);
668 operation_button_list_.append(pbLsh);
669 operation_button_list_.append(pbRsh);
670 operation_button_list_.append(pbPeriod);
671 operation_button_list_.append(pbEqual);
672 operation_button_list_.append(pbPercent);
673 operation_button_list_.append(pbCmp);
674 operation_button_list_.append(pbMod);
675}
676
677//------------------------------------------------------------------------------
678// Name: updateGeometry
679// Desc: makes all the buttons have reasonable sizes
680//------------------------------------------------------------------------------
681void KCalculator::updateGeometry()
682{
683 // Create font metrics using base font (at base size)
684 const QFontMetrics fm(baseFont());
685
686 // Calculate some useful values
687 const QSize em = fm.size(0, QStringLiteral("M"));
688 int margin = QApplication::style()->pixelMetric(QStyle::PM_ButtonMargin, nullptr, nullptr);
689 margin = qMax(qMin(margin / 2, 3), 3);
690
691 // left pad
692 const auto leftPadList = leftPad->children();
693 for (QObject *obj : leftPadList) {
694 if (auto const button = qobject_cast<KCalcButton *>(obj)) {
695 button->setMinimumWidth(em.width() * 4 + margin * 2);
696 button->setMinimumHeight(em.height() * 1.25 + margin * 2);
697 button->installEventFilter(this);
698 }
699 }
700
701 // right pad
702 const auto rightPadList = rightPad->children();
703 for (QObject *obj : rightPadList) {
704 if (auto const button = qobject_cast<KCalcButton *>(obj)) {
705 button->setMinimumWidth(em.width() * 3 + margin * 2);
706 button->setMinimumHeight(em.height() * 1.25 + margin * 2);
707 button->installEventFilter(this);
708 }
709 }
710
711 // numeric pad
712 const auto numericPadList = numericPad->children();
713 for (QObject *obj : numericPadList) {
714 if (auto const button = qobject_cast<KCalcButton *>(obj)) {
715 button->setMinimumWidth(em.width() * 3 + margin * 2);
716 button->setMinimumHeight(em.height() * 1.25 + margin * 2);
717 button->installEventFilter(this);
718 }
719 }
720}
721
722//------------------------------------------------------------------------------
723// Name: slotConstantToDisplay
724// Desc: inserts a constant
725//------------------------------------------------------------------------------
726void KCalculator::slotConstantToDisplay(const science_constant &const_chosen)
727{
728 QString val = const_chosen.value;
729 val.replace(QLatin1Char('.'), KNumber::decimalSeparator());
730 calc_display->setAmount(KNumber(val));
731 updateDisplay({});
732 core.setOnlyUpdateOperation(false);
733}
734
735//------------------------------------------------------------------------------
736// Name: slotBaseSelected
737// Desc: changes the selected numeric base
738//------------------------------------------------------------------------------
739void KCalculator::slotBaseSelected(QAbstractButton *button)
740{
741 if (button) {
742 const int base = base_choose_group_->id(button);
743 int current_base;
744
745 // set display & statusbar (if item exist in statusbar)
746 statusBar()->setBase(base);
747 switch (base) {
748 case BinMode:
749 current_base = calc_display->setBase(NumBase(2));
750 calc_display->setStatusText(BaseField, QStringLiteral("Bin"));
751 break;
752 case OctMode:
753 current_base = calc_display->setBase(NumBase(8));
754 calc_display->setStatusText(BaseField, QStringLiteral("Oct"));
755 break;
756 case DecMode:
757 current_base = calc_display->setBase(NumBase(10));
758 calc_display->setStatusText(BaseField, QStringLiteral("Dec"));
759 break;
760 case HexMode:
761 current_base = calc_display->setBase(NumBase(16));
762 calc_display->setStatusText(BaseField, QStringLiteral("Hex"));
763 break;
764 default:
765 calc_display->setStatusText(BaseField, QStringLiteral("Error"));
766 return;
767 }
768
769 // Enable the buttons available in this base
770 for (int i = 0; i < current_base; ++i) {
771 (num_button_group_->buttons().at(i))->setEnabled(true);
772 }
773
774 // Disable the buttons not available in this base
775 for (int i = current_base; i < 16; ++i) {
776 (num_button_group_->buttons().at(i))->setEnabled(false);
777 }
778
779 // Only enable the decimal point in decimal
780 pbPeriod->setEnabled(current_base == NB_DECIMAL);
781
782 // Only enable the x*10^y button in decimal
783 pbEE->setEnabled(current_base == NB_DECIMAL);
784
785 // Disable buttons that make only sense with floating point numbers
786 if (current_base != NB_DECIMAL) {
787 for (QAbstractButton *btn : std::as_const(scientific_buttons_)) {
788 btn->setEnabled(false);
789 }
790 } else {
791 for (QAbstractButton *btn : std::as_const(scientific_buttons_)) {
792 btn->setEnabled(true);
793 }
794 }
795
796 KCalcSettings::setBaseMode(base);
797 }
798}
799
800//------------------------------------------------------------------------------
801// Name: keyPressEvent
802// Desc: handles keypress events
803//------------------------------------------------------------------------------
804void KCalculator::keyPressEvent(QKeyEvent *e)
805{
806 // Fix for bug #314586
807 // Basically, on some keyboards such as French, even though the decimal separator
808 // is "," the numeric keypad has a "." key. So we fake it so people can more seamlessly
809 // enter numbers using the keypad
810 if (KNumber::decimalSeparator() != QLatin1String(".")) {
811 if (e->key() == Qt::Key_Period && e->modifiers() & Qt::KeypadModifier) {
812 pbPeriod->animateClick();
813 }
814 }
815
816 if (((e->modifiers() & Qt::NoModifier) == 0) || (e->modifiers() & Qt::ShiftModifier)) {
817 switch (e->key()) {
818 case Qt::Key_Backspace:
819 calc_display->deleteLastDigit();
820 break;
821 }
822 }
823
824 if (e->key() == Qt::Key_Control) {
825 Q_EMIT switchShowAccels(true);
826 }
827
828 // Workaround for bug #283521
829 // Unfortunately adding multiple shortcuts (A, Shift+A) to pushbuttons
830 // does not work properly, so we handle the A-F keypresses with shift in Hex mode here
831 if (hexRadio->isChecked() && e->modifiers() & Qt::ShiftModifier) {
832 switch (e->key()) {
833 case Qt::Key_A:
834 pbA->animateClick();
835 break;
836 case Qt::Key_B:
837 pbB->animateClick();
838 break;
839 case Qt::Key_C:
840 pbC->animateClick();
841 break;
842 case Qt::Key_D:
843 pbD->animateClick();
844 break;
845 case Qt::Key_E:
846 pbE->animateClick();
847 break;
848 case Qt::Key_F:
849 pbF->animateClick();
850 break;
851 default:
852 break;
853 }
854 }
855}
856
857//------------------------------------------------------------------------------
858// Name: keyReleaseEvent
859// Desc: handles keyrelease events
860//------------------------------------------------------------------------------
861void KCalculator::keyReleaseEvent(QKeyEvent *e)
862{
863 if (e->key() == Qt::Key_Control) {
864 Q_EMIT switchShowAccels(false);
865 }
866}
867
868//------------------------------------------------------------------------------
869// Name: slotAngleSelected
870// Desc: changes the selected angle system
871//------------------------------------------------------------------------------
872void KCalculator::slotAngleSelected(QAbstractButton *button)
873{
874 if (button) {
875 const int mode = angle_choose_group_->id(button);
876 angle_mode_ = mode;
877
878 statusBar()->setAngleMode(KCalcStatusBar::AngleMode(mode));
879 switch (mode) {
880 case DegMode:
881 calc_display->setStatusText(AngleField, QStringLiteral("Deg"));
882 break;
883 case RadMode:
884 calc_display->setStatusText(AngleField, QStringLiteral("Rad"));
885 break;
886 case GradMode:
887 calc_display->setStatusText(AngleField, QStringLiteral("Gra"));
888 break;
889 default: // we shouldn't ever end up here
890 angle_mode_ = RadMode;
891 }
892
893 KCalcSettings::setAngleMode(angle_mode_);
894 }
895}
896
897//------------------------------------------------------------------------------
898// Name: slotEEclicked
899// Desc: starts the entering of numbers using scientific notation
900//------------------------------------------------------------------------------
901void KCalculator::slotEEclicked()
902{
903 calc_display->newCharacter(QLatin1Char('e'));
904}
905
906//------------------------------------------------------------------------------
907// Name: slotShifttoggled
908// Desc: updates the shift state for alternate button functionality
909//------------------------------------------------------------------------------
910void KCalculator::slotShifttoggled(bool flag)
911{
912 shift_mode_ = flag;
913
914 Q_EMIT switchMode(ModeShift, flag);
915
916 statusBar()->setShiftIndicator(shift_mode_);
917 if (shift_mode_) {
918 calc_display->setStatusText(ShiftField, i18n("Shift"));
919 } else {
920 calc_display->setStatusText(ShiftField, QString());
921 }
922}
923
924//------------------------------------------------------------------------------
925// Name: slotHyptoggled
926// Desc: updates the Hyp state for alternate trig button functionality
927//------------------------------------------------------------------------------
928void KCalculator::slotHyptoggled(bool flag)
929{
930 // toggle between hyperbolic and standard trig functions
931 hyp_mode_ = flag;
932
933 Q_EMIT switchMode(ModeHyperbolic, flag);
934}
935
936//------------------------------------------------------------------------------
937// Name: slotMemRecallclicked
938// Desc: recalls a value from memory
939//------------------------------------------------------------------------------
940void KCalculator::slotMemRecallclicked()
941{
942 // temp. work-around
943 calc_display->sendEvent(event: KCalcDisplay::EventReset);
944
945 // temp. work-around
946 calc_display->sendEvent(event: KCalcDisplay::EventReset);
947
948 calc_history->addToHistory(QStringLiteral("MR"), false);
949
950 calc_display->setAmount(memory_num_);
951 updateDisplay({});
952 core.setOnlyUpdateOperation(false);
953 calc_history->addResultToHistory(memory_num_.toQString());
954}
955
956//------------------------------------------------------------------------------
957// Name: slotMemStoreclicked
958// Desc: stores a value into memory
959//------------------------------------------------------------------------------
960void KCalculator::slotMemStoreclicked()
961{
962 calc_history->addToHistory(QStringLiteral("M"), false);
963 update_history_window_ = false;
964 EnterEqual(allow_repeat: CalcEngine::REPEAT_PREVENT);
965
966 memory_num_ = calc_display->getAmount();
967 calc_display->setStatusText(MemField, QStringLiteral("M"));
968 statusBar()->setMemoryIndicator(true);
969 pbMemRecall->setEnabled(true);
970}
971
972//------------------------------------------------------------------------------
973// Name: slotNumberclicked
974// Desc: user has entered a digit
975//------------------------------------------------------------------------------
976void KCalculator::slotNumberclicked(QAbstractButton *button)
977{
978 if (button) {
979 const int number_clicked = num_button_group_->id(button);
980 calc_display->enterDigit(data: number_clicked);
981 core.setOnlyUpdateOperation(false);
982 }
983}
984
985//------------------------------------------------------------------------------
986// Name: slotSinclicked
987// Desc: executes the sine function
988//------------------------------------------------------------------------------
989void KCalculator::slotSinclicked()
990{
991 if (hyp_mode_) {
992 // sinh or arcsinh
993 if (!shift_mode_) {
994 calc_history->addFuncToHistory(QStringLiteral("sinh"));
995 core.SinHyp(calc_display->getAmount());
996 } else {
997 calc_history->addFuncToHistory(QStringLiteral("arcsinh"));
998 core.AreaSinHyp(calc_display->getAmount());
999 }
1000 } else {
1001 // sin or arcsin
1002 if (!shift_mode_) {
1003 calc_history->addFuncToHistory(QStringLiteral("sin"));
1004 switch (angle_mode_) {
1005 case DegMode:
1006 core.SinDeg(calc_display->getAmount());
1007 break;
1008 case RadMode:
1009 core.SinRad(calc_display->getAmount());
1010 break;
1011 case GradMode:
1012 core.SinGrad(calc_display->getAmount());
1013 break;
1014 }
1015 } else {
1016 calc_history->addFuncToHistory(QStringLiteral("arcsin"));
1017 switch (angle_mode_) {
1018 case DegMode:
1019 core.ArcSinDeg(calc_display->getAmount());
1020 break;
1021 case RadMode:
1022 core.ArcSinRad(calc_display->getAmount());
1023 break;
1024 case GradMode:
1025 core.ArcSinGrad(calc_display->getAmount());
1026 break;
1027 }
1028 }
1029 }
1030
1031 updateDisplay(UPDATE_FROM_CORE);
1032 calc_history->addResultToHistory(calc_display->getAmount().toQString(KCalcSettings::precision()));
1033}
1034
1035//------------------------------------------------------------------------------
1036// Name: slotPlusMinusclicked
1037// Desc: changes sign of number being displayed
1038//------------------------------------------------------------------------------
1039void KCalculator::slotPlusMinusclicked()
1040{
1041 // display can only change sign, when in input mode, otherwise we
1042 // need the core to do this.
1043 if (!calc_display->sendEvent(event: KCalcDisplay::EventChangeSign)) {
1044 core.InvertSign(calc_display->getAmount());
1045 update_history_window_ = false;
1046 updateDisplay(UPDATE_FROM_CORE);
1047 }
1048}
1049
1050//------------------------------------------------------------------------------
1051// Name: slotMemPlusMinusclicked
1052// Desc: handles arithmetic on values stored in memory
1053//------------------------------------------------------------------------------
1054void KCalculator::slotMemPlusMinusclicked()
1055{
1056 bool tmp_shift_mode = shift_mode_; // store this, because next command deletes shift_mode_
1057 update_history_window_ = false;
1058 if (!tmp_shift_mode) {
1059 calc_history->addToHistory(QStringLiteral("M+"), false);
1060 } else {
1061 calc_history->addToHistory(QStringLiteral("M-"), false);
1062 }
1063
1064 EnterEqual(); // finish calculation so far, to store result into MEM
1065
1066 if (!tmp_shift_mode) {
1067 memory_num_ += calc_display->getAmount();
1068 } else {
1069 memory_num_ -= calc_display->getAmount();
1070 }
1071
1072 pbShift->setChecked(false);
1073 statusBar()->setMemoryIndicator(true);
1074 calc_display->setStatusText(MemField, i18n("M"));
1075 pbMemRecall->setEnabled(true);
1076}
1077
1078//------------------------------------------------------------------------------
1079// Name: slotSinclicked
1080// Desc: executes the cosine function
1081//------------------------------------------------------------------------------
1082void KCalculator::slotCosclicked()
1083{
1084 if (hyp_mode_) {
1085 // cosh or arcosh
1086 if (!shift_mode_) {
1087 calc_history->addFuncToHistory(QStringLiteral("cosh"));
1088 core.CosHyp(calc_display->getAmount());
1089 } else {
1090 calc_history->addFuncToHistory(QStringLiteral("arcosh"));
1091 core.AreaCosHyp(calc_display->getAmount());
1092 }
1093 } else {
1094 // cosine or arccosine
1095 if (!shift_mode_) {
1096 calc_history->addFuncToHistory(QStringLiteral("cos"));
1097 switch (angle_mode_) {
1098 case DegMode:
1099 core.CosDeg(calc_display->getAmount());
1100 break;
1101 case RadMode:
1102 core.CosRad(calc_display->getAmount());
1103 break;
1104 case GradMode:
1105 core.CosGrad(calc_display->getAmount());
1106 break;
1107 }
1108 } else {
1109 calc_history->addFuncToHistory(QStringLiteral("arccos"));
1110 switch (angle_mode_) {
1111 case DegMode:
1112 core.ArcCosDeg(calc_display->getAmount());
1113 break;
1114 case RadMode:
1115 core.ArcCosRad(calc_display->getAmount());
1116 break;
1117 case GradMode:
1118 core.ArcCosGrad(calc_display->getAmount());
1119 break;
1120 }
1121 }
1122 }
1123
1124 updateDisplay(UPDATE_FROM_CORE);
1125 calc_history->addResultToHistory(calc_display->getAmount().toQString(KCalcSettings::precision()));
1126}
1127
1128//------------------------------------------------------------------------------
1129// Name: slotSinclicked
1130// Desc: executes the reciprocal function
1131//------------------------------------------------------------------------------
1132void KCalculator::slotReciclicked()
1133{
1134 if (shift_mode_) {
1135 calc_history->addFuncToHistory(QStringLiteral("nCm"));
1136 core.enterOperation(calc_display->getAmount(), CalcEngine::FUNC_BINOM);
1137 } else {
1138 calc_history->addFuncToHistory(QStringLiteral("1/"));
1139 core.Reciprocal(calc_display->getAmount());
1140 updateDisplay(UPDATE_FROM_CORE);
1141 calc_history->addResultToHistory(calc_display->getAmount().toQString(KCalcSettings::precision()));
1142 return;
1143 }
1144
1145 // temp. work-around
1146 KNumber tmp_num = calc_display->getAmount();
1147 calc_display->sendEvent(event: KCalcDisplay::EventReset);
1148 calc_display->setAmount(tmp_num);
1149 updateDisplay({});
1150 calc_history->addResultToHistory(calc_display->getAmount().toQString(KCalcSettings::precision()));
1151 if (shift_mode_) {
1152 updateHistoryWithFunction(CalcEngine::FUNC_BINOM);
1153 }
1154}
1155
1156//------------------------------------------------------------------------------
1157// Name: slotSinclicked
1158// Desc: executes the tangent function
1159//------------------------------------------------------------------------------
1160void KCalculator::slotTanclicked()
1161{
1162 if (hyp_mode_) {
1163 // tanh or artanh
1164 if (!shift_mode_) {
1165 calc_history->addFuncToHistory(QStringLiteral("tanh"));
1166 core.TangensHyp(calc_display->getAmount());
1167 } else {
1168 calc_history->addFuncToHistory(QStringLiteral("artanh"));
1169 core.AreaTangensHyp(calc_display->getAmount());
1170 }
1171 } else {
1172 // tan or arctan
1173 if (!shift_mode_) {
1174 calc_history->addFuncToHistory(QStringLiteral("tan"));
1175 switch (angle_mode_) {
1176 case DegMode:
1177 core.TangensDeg(calc_display->getAmount());
1178 break;
1179 case RadMode:
1180 core.TangensRad(calc_display->getAmount());
1181 break;
1182 case GradMode:
1183 core.TangensGrad(calc_display->getAmount());
1184 break;
1185 }
1186 } else {
1187 calc_history->addFuncToHistory(QStringLiteral("arctan"));
1188 switch (angle_mode_) {
1189 case DegMode:
1190 core.ArcTangensDeg(calc_display->getAmount());
1191 break;
1192 case RadMode:
1193 core.ArcTangensRad(calc_display->getAmount());
1194 break;
1195 case GradMode:
1196 core.ArcTangensGrad(calc_display->getAmount());
1197 break;
1198 }
1199 }
1200 }
1201
1202 updateDisplay(UPDATE_FROM_CORE);
1203 calc_history->addResultToHistory(calc_display->getAmount().toQString(KCalcSettings::precision()));
1204}
1205
1206//------------------------------------------------------------------------------
1207// Name: slotFactorialclicked
1208// Desc: executes the factorial function
1209//------------------------------------------------------------------------------
1210void KCalculator::slotFactorialclicked()
1211{
1212 bool gamma_ = false;
1213 // Set WaitCursor, as this operation may take a long
1214 // time and the UI freezes with large numbers. User needs some
1215 // visual feedback.
1216 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
1217 if (!shift_mode_) {
1218 core.Factorial(calc_display->getAmount());
1219 } else {
1220 core.Gamma(calc_display->getAmount());
1221 gamma_ = true;
1222 }
1223 QApplication::restoreOverrideCursor();
1224 updateDisplay(UPDATE_FROM_CORE);
1225 if (gamma_) {
1226 calc_history->addFuncToHistory(QStringLiteral("&#915;"));
1227 } else {
1228 calc_history->addFuncToHistory(QStringLiteral("!"));
1229 }
1230 calc_history->addResultToHistory(calc_display->getAmount().toQString(KCalcSettings::precision()));
1231}
1232
1233//------------------------------------------------------------------------------
1234// Name: slotLogclicked
1235// Desc: executes the Log function
1236//------------------------------------------------------------------------------
1237void KCalculator::slotLogclicked()
1238{
1239 if (!shift_mode_) {
1240 core.Log10(calc_display->getAmount());
1241 calc_history->addFuncToHistory(QStringLiteral("log"));
1242 } else {
1243 update_history_window_ = false;
1244 core.Exp10(calc_display->getAmount());
1245 calc_history->addFuncToHistory(QStringLiteral("10<sup>") + calc_display->getAmount().toQString(KCalcSettings::precision()) + QStringLiteral("</sup>"));
1246 }
1247
1248 updateDisplay(UPDATE_FROM_CORE);
1249 calc_history->addResultToHistory(calc_display->getAmount().toQString(KCalcSettings::precision()));
1250}
1251
1252//------------------------------------------------------------------------------
1253// Name: slotSquareclicked
1254// Desc: executes the x^2 function
1255//------------------------------------------------------------------------------
1256void KCalculator::slotSquareclicked()
1257{
1258 bool tmp_shift_mode = shift_mode_;
1259 if (!shift_mode_) {
1260 core.Square(calc_display->getAmount());
1261 } else {
1262 calc_history->addFuncToHistory(QStringLiteral("&radic;"));
1263 core.SquareRoot(calc_display->getAmount());
1264 }
1265
1266 updateDisplay(UPDATE_FROM_CORE);
1267 if (!tmp_shift_mode) {
1268 calc_history->addFuncToHistory(QStringLiteral("<sup>2</sup>"));
1269 }
1270 calc_history->addResultToHistory(calc_display->getAmount().toQString(KCalcSettings::precision()));
1271}
1272
1273//------------------------------------------------------------------------------
1274// Name: slotCubeclicked
1275// Desc: executes the x^3 function
1276//------------------------------------------------------------------------------
1277void KCalculator::slotCubeclicked()
1278{
1279 bool tmp_shift_mode = shift_mode_;
1280 if (!shift_mode_) {
1281 core.Cube(calc_display->getAmount());
1282 } else {
1283 calc_history->addFuncToHistory(QStringLiteral("<sup>3</sup>&radic;"));
1284 core.CubeRoot(calc_display->getAmount());
1285 }
1286
1287 updateDisplay(UPDATE_FROM_CORE);
1288 if (!tmp_shift_mode) {
1289 calc_history->addFuncToHistory(QStringLiteral("<sup>3</sup>"));
1290 }
1291 calc_history->addResultToHistory(calc_display->formatDecimalNumber(calc_display->getAmount().toQString(KCalcSettings::precision())));
1292}
1293
1294//------------------------------------------------------------------------------
1295// Name: slotCubeclicked
1296// Desc: executes the ln function
1297//------------------------------------------------------------------------------
1298void KCalculator::slotLnclicked()
1299{
1300 if (!shift_mode_) {
1301 calc_history->addFuncToHistory(QStringLiteral("ln"));
1302 core.Ln(calc_display->getAmount());
1303 } else {
1304 calc_history->addFuncToHistory(QStringLiteral("e<sup>") + calc_display->getAmount().toQString(KCalcSettings::precision()) + QStringLiteral("</sup>"));
1305 core.Exp(calc_display->getAmount());
1306 }
1307
1308 updateDisplay(UPDATE_FROM_CORE);
1309 calc_history->addResultToHistory(calc_display->getAmount().toQString(KCalcSettings::precision()));
1310}
1311
1312//------------------------------------------------------------------------------
1313// Name: slotPowerclicked
1314// Desc: executes the x^y function
1315//------------------------------------------------------------------------------
1316void KCalculator::slotPowerclicked()
1317{
1318 if (shift_mode_) {
1319 calc_history->addToHistory(calc_display->getAmount().toQString(KCalcSettings::precision()) + QStringLiteral("&nbsp;^ 1/"), false);
1320 core.enterOperation(calc_display->getAmount(), CalcEngine::FUNC_PWR_ROOT);
1321 pbShift->setChecked(false);
1322 } else {
1323 calc_history->addToHistory(calc_display->getAmount().toQString(KCalcSettings::precision()), false);
1324 calc_history->addFuncToHistory(QStringLiteral("^"));
1325 core.enterOperation(calc_display->getAmount(), CalcEngine::FUNC_POWER);
1326 }
1327
1328 // temp. work-around
1329 KNumber tmp_num = calc_display->getAmount();
1330 calc_display->sendEvent(event: KCalcDisplay::EventReset);
1331 calc_display->setAmount(tmp_num);
1332 updateDisplay({});
1333}
1334
1335//------------------------------------------------------------------------------
1336// Name: slotMemClearclicked
1337// Desc: executes the MC function
1338//------------------------------------------------------------------------------
1339void KCalculator::slotMemClearclicked()
1340{
1341 memory_num_ = KNumber::Zero;
1342 statusBar()->setMemoryIndicator(false);
1343 calc_display->setStatusText(MemField, QString());
1344 pbMemRecall->setDisabled(true);
1345 calc_history->addToHistory(QStringLiteral("M cleared"), true);
1346}
1347
1348//------------------------------------------------------------------------------
1349// Name: slotBackspaceclicked
1350// Desc: removes the last input digit
1351//------------------------------------------------------------------------------
1352void KCalculator::slotBackspaceclicked()
1353{
1354 calc_display->deleteLastDigit();
1355}
1356
1357//------------------------------------------------------------------------------
1358// Name: slotClearclicked
1359// Desc: clears the display
1360//------------------------------------------------------------------------------
1361void KCalculator::slotClearclicked()
1362{
1363 calc_display->sendEvent(event: KCalcDisplay::EventClear);
1364}
1365
1366//------------------------------------------------------------------------------
1367// Name: slotAllClearclicked
1368// Desc: clears everything
1369//------------------------------------------------------------------------------
1370void KCalculator::slotAllClearclicked()
1371{
1372 core.Reset();
1373 calc_display->sendEvent(event: KCalcDisplay::EventReset);
1374 updateDisplay(UPDATE_FROM_CORE);
1375}
1376
1377//------------------------------------------------------------------------------
1378// Name: slotParenOpenclicked
1379// Desc: starts a sub-expression
1380//------------------------------------------------------------------------------
1381void KCalculator::slotParenOpenclicked()
1382{
1383 core.ParenOpen(calc_display->getAmount());
1384 calc_history->addFuncToHistory(QStringLiteral("("));
1385}
1386
1387//------------------------------------------------------------------------------
1388// Name: slotParenCloseclicked
1389// Desc: ends a sub-expression
1390//------------------------------------------------------------------------------
1391void KCalculator::slotParenCloseclicked()
1392{
1393 core.ParenClose(calc_display->getAmount());
1394 updateDisplay(UPDATE_FROM_CORE);
1395 calc_history->addFuncToHistory(QStringLiteral(")"));
1396 update_history_window_ = false;
1397}
1398
1399//------------------------------------------------------------------------------
1400// Name: slotANDclicked
1401// Desc: executes a bitwise AND
1402//------------------------------------------------------------------------------
1403void KCalculator::slotANDclicked()
1404{
1405 core.enterOperation(calc_display->getAmount(), CalcEngine::FUNC_AND);
1406 updateDisplay(UPDATE_FROM_CORE);
1407 updateHistoryWithFunction(CalcEngine::FUNC_AND);
1408}
1409
1410//------------------------------------------------------------------------------
1411// Name: slotMultiplicationclicked
1412// Desc: executes multiplication
1413//------------------------------------------------------------------------------
1414void KCalculator::slotMultiplicationclicked()
1415{
1416 core.enterOperation(calc_display->getAmount(), CalcEngine::FUNC_MULTIPLY);
1417 updateDisplay(UPDATE_FROM_CORE);
1418 updateHistoryWithFunction(CalcEngine::FUNC_MULTIPLY);
1419}
1420
1421//------------------------------------------------------------------------------
1422// Name: slotDivisionclicked
1423// Desc: executes division
1424//------------------------------------------------------------------------------
1425void KCalculator::slotDivisionclicked()
1426{
1427 core.enterOperation(calc_display->getAmount(), CalcEngine::FUNC_DIVIDE);
1428 updateDisplay(UPDATE_FROM_CORE);
1429 updateHistoryWithFunction(CalcEngine::FUNC_DIVIDE);
1430}
1431
1432//------------------------------------------------------------------------------
1433// Name: slotORclicked
1434// Desc: executes a bitwise OR
1435//------------------------------------------------------------------------------
1436void KCalculator::slotORclicked()
1437{
1438 core.enterOperation(calc_display->getAmount(), CalcEngine::FUNC_OR);
1439 updateDisplay(UPDATE_FROM_CORE);
1440 updateHistoryWithFunction(CalcEngine::FUNC_OR);
1441}
1442
1443//------------------------------------------------------------------------------
1444// Name: slotXORclicked
1445// Desc: executes a bitwise XOR
1446//------------------------------------------------------------------------------
1447void KCalculator::slotXORclicked()
1448{
1449 core.enterOperation(calc_display->getAmount(), CalcEngine::FUNC_XOR);
1450 updateDisplay(UPDATE_FROM_CORE);
1451 updateHistoryWithFunction(CalcEngine::FUNC_XOR);
1452}
1453
1454//------------------------------------------------------------------------------
1455// Name: slotPlusclicked
1456// Desc: executes addition
1457//------------------------------------------------------------------------------
1458void KCalculator::slotPlusclicked()
1459{
1460 core.enterOperation(calc_display->getAmount(), CalcEngine::FUNC_ADD);
1461 updateDisplay(UPDATE_FROM_CORE);
1462 updateHistoryWithFunction(CalcEngine::FUNC_ADD);
1463}
1464
1465//------------------------------------------------------------------------------
1466// Name: slotPlusclicked
1467// Desc: executes subtraction
1468//------------------------------------------------------------------------------
1469void KCalculator::slotMinusclicked()
1470{
1471 core.enterOperation(calc_display->getAmount(), CalcEngine::FUNC_SUBTRACT);
1472 updateDisplay(UPDATE_FROM_CORE);
1473 updateHistoryWithFunction(CalcEngine::FUNC_SUBTRACT);
1474}
1475
1476//------------------------------------------------------------------------------
1477// Name: slotLeftShiftclicked
1478// Desc: executes a bitwise left shift
1479//------------------------------------------------------------------------------
1480void KCalculator::slotLeftShiftclicked()
1481{
1482 core.enterOperation(calc_display->getAmount(), CalcEngine::FUNC_LSH);
1483 updateDisplay(UPDATE_FROM_CORE);
1484 updateHistoryWithFunction(CalcEngine::FUNC_LSH);
1485}
1486
1487//------------------------------------------------------------------------------
1488// Name: slotLeftShiftclicked
1489// Desc: executes a bitwise right shift
1490//------------------------------------------------------------------------------
1491void KCalculator::slotRightShiftclicked()
1492{
1493 core.enterOperation(calc_display->getAmount(), CalcEngine::FUNC_RSH);
1494 updateDisplay(UPDATE_FROM_CORE);
1495 updateHistoryWithFunction(CalcEngine::FUNC_RSH);
1496}
1497
1498//------------------------------------------------------------------------------
1499// Name: slotPeriodclicked
1500// Desc: enters a decimal into the input stream
1501//------------------------------------------------------------------------------
1502void KCalculator::slotPeriodclicked()
1503{
1504 // I know this isn't locale friendly, should be converted to appropriate
1505 // value at lower levels
1506 const auto decimalPoint = QLocale().decimalPoint();
1507 for (const auto c : decimalPoint) {
1508 calc_display->newCharacter(c);
1509 }
1510}
1511
1512//------------------------------------------------------------------------------
1513// Name: EnterEqual
1514// Desc: calculates and displays the result of the pending operations
1515//------------------------------------------------------------------------------
1516void KCalculator::EnterEqual(CalcEngine::Repeat allow_repeat)
1517{
1518 core.enterOperation(calc_display->getAmount(), CalcEngine::FUNC_EQUAL, allow_repeat);
1519 updateDisplay(UPDATE_FROM_CORE | UPDATE_STORE_RESULT);
1520 calc_history->addResultToHistory(calc_display->getAmount().toQString(KCalcSettings::precision()));
1521}
1522
1523//------------------------------------------------------------------------------
1524// Name: slotEqualclicked
1525// Desc: calculates and displays the result of the pending operations
1526//------------------------------------------------------------------------------
1527void KCalculator::slotEqualclicked()
1528{
1529 EnterEqual();
1530}
1531
1532//------------------------------------------------------------------------------
1533// Name: slotPercentclicked
1534// Desc: calculates and displays the result of the pending operations as a percent
1535//------------------------------------------------------------------------------
1536void KCalculator::slotPercentclicked()
1537{
1538 core.enterOperation(calc_display->getAmount(), CalcEngine::FUNC_PERCENT);
1539 updateDisplay(UPDATE_FROM_CORE);
1540 updateHistoryWithFunction(CalcEngine::FUNC_PERCENT);
1541 calc_history->addResultToHistory(calc_display->getAmount().toQString(KCalcSettings::precision()));
1542}
1543
1544//------------------------------------------------------------------------------
1545// Name: slotNegateclicked
1546// Desc: executes a bitwise 2's compliment
1547// NOTE: implicitly converts the value to an unsigned quantity
1548//------------------------------------------------------------------------------
1549void KCalculator::slotNegateclicked()
1550{
1551 calc_history->addFuncToHistory(QStringLiteral("~"));
1552 core.Complement(calc_display->getAmount());
1553 updateDisplay(UPDATE_FROM_CORE);
1554 calc_history->addResultToHistory(calc_display->getAmount().toQString(KCalcSettings::precision()));
1555}
1556
1557//------------------------------------------------------------------------------
1558// Name: slotModclicked
1559// Desc: executes modulous (remainder division)
1560//------------------------------------------------------------------------------
1561void KCalculator::slotModclicked()
1562{
1563 if (shift_mode_) {
1564 core.enterOperation(calc_display->getAmount(), CalcEngine::FUNC_INTDIV);
1565 } else {
1566 core.enterOperation(calc_display->getAmount(), CalcEngine::FUNC_MOD);
1567 }
1568
1569 updateDisplay(UPDATE_FROM_CORE);
1570
1571 if (shift_mode_) {
1572 updateHistoryWithFunction(CalcEngine::FUNC_INTDIV);
1573 } else {
1574 updateHistoryWithFunction(CalcEngine::FUNC_MOD);
1575 }
1576}
1577
1578//------------------------------------------------------------------------------
1579// Name: slotStatNumclicked
1580// Desc: executes Sum function
1581//------------------------------------------------------------------------------
1582void KCalculator::slotStatNumclicked()
1583{
1584 update_history_window_ = false;
1585 if (!shift_mode_) {
1586 core.StatCount(KNumber::Zero);
1587 calc_history->addToHistory(i18n("Number of data entered"), false);
1588 } else {
1589 pbShift->setChecked(false);
1590 core.StatSum(KNumber::Zero);
1591 calc_history->addToHistory(QString::fromUtf8("\xce\xa3") + QLatin1Char('x'), false);
1592 }
1593
1594 updateDisplay(UPDATE_FROM_CORE);
1595 core.setOnlyUpdateOperation(false);
1596 calc_history->addResultToHistory(calc_display->getAmount().toQString(KCalcSettings::precision()));
1597}
1598
1599//------------------------------------------------------------------------------
1600// Name: slotStatMeanclicked
1601// Desc: executes Mean function
1602//------------------------------------------------------------------------------
1603void KCalculator::slotStatMeanclicked()
1604{
1605 update_history_window_ = false;
1606 if (!shift_mode_) {
1607 core.StatMean(KNumber::Zero);
1608 calc_history->addToHistory(i18n("Mean"), false);
1609 } else {
1610 pbShift->setChecked(false);
1611 core.StatSumSquares(KNumber::Zero);
1612 calc_history->addToHistory(QString::fromUtf8("\xce\xa3") + QStringLiteral("x<sup>2</sup>"), false);
1613 }
1614
1615 updateDisplay(UPDATE_FROM_CORE);
1616 core.setOnlyUpdateOperation(false);
1617 calc_history->addResultToHistory(calc_display->getAmount().toQString(KCalcSettings::precision()));
1618}
1619
1620//------------------------------------------------------------------------------
1621// Name: slotStatStdDevclicked
1622// Desc: executes STD function
1623//------------------------------------------------------------------------------
1624void KCalculator::slotStatStdDevclicked()
1625{
1626 update_history_window_ = false;
1627 if (shift_mode_) {
1628 // std (n-1)
1629 core.StatStdSample(KNumber::Zero);
1630 pbShift->setChecked(false);
1631 calc_history->addToHistory(QString::fromUtf8("\xcf\x83") + QStringLiteral("<sub>N-1</sub>"), false);
1632 } else {
1633 // std (n)
1634 core.StatStdDeviation(KNumber::Zero);
1635 calc_history->addToHistory(QString::fromUtf8("\xcf\x83") + QStringLiteral("N"), false);
1636 }
1637
1638 updateDisplay(UPDATE_FROM_CORE);
1639 core.setOnlyUpdateOperation(false);
1640 calc_history->addResultToHistory(calc_display->getAmount().toQString(KCalcSettings::precision()));
1641}
1642
1643//------------------------------------------------------------------------------
1644// Name: slotStatMedianclicked
1645// Desc: executes Median function
1646//------------------------------------------------------------------------------
1647void KCalculator::slotStatMedianclicked()
1648{
1649 update_history_window_ = false;
1650 if (!shift_mode_) {
1651 core.StatMedian(KNumber::Zero);
1652 } else {
1653 core.StatMedian(KNumber::Zero);
1654 pbShift->setChecked(false);
1655 }
1656
1657 calc_history->addToHistory(i18n("Median"), false);
1658 // TODO: it seems two different modes should be implemented, but...?
1659 updateDisplay(UPDATE_FROM_CORE);
1660 core.setOnlyUpdateOperation(false);
1661 calc_history->addResultToHistory(calc_display->getAmount().toQString(KCalcSettings::precision()));
1662}
1663
1664//------------------------------------------------------------------------------
1665// Name: slotStatDataInputclicked
1666// Desc: enters a value for statistical functions
1667//------------------------------------------------------------------------------
1668void KCalculator::slotStatDataInputclicked()
1669{
1670 update_history_window_ = false;
1671 if (!shift_mode_) {
1672 bool tmp_error;
1673 core.StatDataNew(calc_display->getAmount());
1674 calc_history->addToHistory(i18n("DAT [") + core.lastOutput(tmp_error).toQString() + i18n("] = ")
1675 + calc_display->getAmount().toQString(KCalcSettings::precision()),
1676 true);
1677 } else {
1678 pbShift->setChecked(false);
1679 core.StatDataDel(KNumber::Zero);
1680 statusBar()->showMessage(i18n("Last stat item erased"), 3000);
1681 calc_history->addToHistory(i18n("Last stat item erased"), true);
1682 }
1683
1684 updateDisplay(UPDATE_FROM_CORE);
1685 core.setOnlyUpdateOperation(false);
1686}
1687
1688//------------------------------------------------------------------------------
1689// Name: slotStatClearDataclicked
1690// Desc: clears memory for statical functions
1691//------------------------------------------------------------------------------
1692void KCalculator::slotStatClearDataclicked()
1693{
1694 if (!shift_mode_) {
1695 core.StatClearAll(KNumber::Zero);
1696 statusBar()->showMessage(i18n("Stat mem cleared"), 3000);
1697 calc_history->addToHistory(i18n("Stat mem cleared"), true);
1698 } else {
1699 pbShift->setChecked(false);
1700 updateDisplay({});
1701 }
1702}
1703
1704//------------------------------------------------------------------------------
1705// Name: slotConstclicked
1706// Desc: enters a constant
1707//------------------------------------------------------------------------------
1708void KCalculator::slotConstclicked(int button)
1709{
1710 if (auto btn = qobject_cast<KCalcConstButton *>(const_buttons_[button])) {
1711 if (!shift_mode_) {
1712 // set the display to the configured value of constant button
1713 // internally, we deal with C locale style numbers, we need to convert
1714 QString val = btn->constant();
1715 val.replace(QLatin1Char('.'), KNumber::decimalSeparator());
1716 calc_display->setAmount(KNumber(val));
1717
1718 } else {
1719 pbShift->setChecked(false);
1720
1721 // internally, we deal with C locale style numbers, we need to convert
1722 QString val = calc_display->text();
1723 val.replace(KNumber::decimalSeparator(), QLatin1String("."));
1724 KCalcSettings::setValueConstant(i: button, v: val);
1725
1726 // below set new tooltip
1727 btn->setLabelAndTooltip();
1728
1729 // work around: after storing a number, pressing a digit should start
1730 // a new number
1731 calc_display->setAmount(calc_display->getAmount());
1732 }
1733
1734 updateDisplay({});
1735 core.setOnlyUpdateOperation(false);
1736 }
1737}
1738
1739//------------------------------------------------------------------------------
1740// Name: showSettings
1741// Desc: opens the shows the settings dialog
1742//------------------------------------------------------------------------------
1743void KCalculator::showSettings()
1744{
1745 // Check if there is already a dialog and if so bring
1746 // it to the foreground.
1747 if (KConfigDialog::showDialog(name: QStringLiteral("settings"))) {
1748 return;
1749 }
1750
1751 // Create a new dialog with the same name as the above checking code.
1752 auto const dialog = new KConfigDialog(this, QStringLiteral("settings"), KCalcSettings::self());
1753
1754 // general settings
1755 auto const general = new General(nullptr);
1756 general->kcfg_Precision->setMaximum(maxprecision);
1757 dialog->addPage(general, i18n("General"), QStringLiteral("accessories-calculator"), i18n("General Settings"));
1758
1759 // font settings
1760 auto const fonts = new Fonts(nullptr);
1761 dialog->addPage(fonts, i18n("Font"), QStringLiteral("preferences-desktop-font"), i18n("Select Display Font"));
1762
1763 // color settings
1764 auto const color = new Colors(nullptr);
1765 dialog->addPage(color, i18n("Colors"), QStringLiteral("preferences-desktop-color"), i18n("Button & Display Colors"));
1766
1767 // constant settings
1768 if (!constants_) {
1769 constants_ = new Constants(nullptr);
1770
1771 KCalcConstMenu *tmp_menu;
1772 tmp_menu = new KCalcConstMenu(constants_);
1773 connect(tmp_menu, &KCalcConstMenu::triggeredConstant, this, &KCalculator::slotChooseScientificConst0);
1774 constants_->pushButton0->setMenu(tmp_menu);
1775
1776 tmp_menu = new KCalcConstMenu(constants_);
1777 connect(tmp_menu, &KCalcConstMenu::triggeredConstant, this, &KCalculator::slotChooseScientificConst1);
1778 constants_->pushButton1->setMenu(tmp_menu);
1779
1780 tmp_menu = new KCalcConstMenu(constants_);
1781 connect(tmp_menu, &KCalcConstMenu::triggeredConstant, this, &KCalculator::slotChooseScientificConst2);
1782 constants_->pushButton2->setMenu(tmp_menu);
1783
1784 tmp_menu = new KCalcConstMenu(constants_);
1785 connect(tmp_menu, &KCalcConstMenu::triggeredConstant, this, &KCalculator::slotChooseScientificConst3);
1786 constants_->pushButton3->setMenu(tmp_menu);
1787
1788 tmp_menu = new KCalcConstMenu(constants_);
1789 connect(tmp_menu, &KCalcConstMenu::triggeredConstant, this, &KCalculator::slotChooseScientificConst4);
1790 constants_->pushButton4->setMenu(tmp_menu);
1791
1792 tmp_menu = new KCalcConstMenu(constants_);
1793 connect(tmp_menu, &KCalcConstMenu::triggeredConstant, this, &KCalculator::slotChooseScientificConst5);
1794 constants_->pushButton5->setMenu(tmp_menu);
1795 }
1796
1797 dialog->addPage(constants_, i18n("Constants"), QStringLiteral("preferences-kcalc-constants"), i18n("Define Constants"));
1798
1799 // When the user clicks OK or Apply we want to update our settings.
1800 connect(dialog, &KConfigDialog::settingsChanged, this, &KCalculator::updateSettings);
1801
1802 // Display the dialog.
1803 dialog->show();
1804}
1805
1806// these 6 slots are just a quick hack, instead of setting the
1807// TextEdit fields in the configuration dialog, we are setting the
1808// Settingvalues themselves!!
1809
1810//------------------------------------------------------------------------------
1811// Name: slotChooseScientificConst0
1812// Desc: updates constants value
1813//------------------------------------------------------------------------------
1814void KCalculator::slotChooseScientificConst0(const science_constant &chosen_const)
1815{
1816 constants_->kcfg_valueConstant0->setText(chosen_const.value);
1817 constants_->kcfg_nameConstant0->setText(chosen_const.label);
1818}
1819
1820//------------------------------------------------------------------------------
1821// Name: slotChooseScientificConst1
1822// Desc: updates constants value
1823//------------------------------------------------------------------------------
1824void KCalculator::slotChooseScientificConst1(const science_constant &chosen_const)
1825{
1826 constants_->kcfg_valueConstant1->setText(chosen_const.value);
1827 constants_->kcfg_nameConstant1->setText(chosen_const.label);
1828}
1829
1830//------------------------------------------------------------------------------
1831// Name: slotChooseScientificConst2
1832// Desc: updates constants value
1833//------------------------------------------------------------------------------
1834void KCalculator::slotChooseScientificConst2(const science_constant &chosen_const)
1835{
1836 constants_->kcfg_valueConstant2->setText(chosen_const.value);
1837 constants_->kcfg_nameConstant2->setText(chosen_const.label);
1838}
1839
1840//------------------------------------------------------------------------------
1841// Name: slotChooseScientificConst3
1842// Desc: updates constants value
1843//------------------------------------------------------------------------------
1844void KCalculator::slotChooseScientificConst3(const science_constant &chosen_const)
1845{
1846 constants_->kcfg_valueConstant3->setText(chosen_const.value);
1847 constants_->kcfg_nameConstant3->setText(chosen_const.label);
1848}
1849
1850//------------------------------------------------------------------------------
1851// Name: slotChooseScientificConst4
1852// Desc: updates constants value
1853//------------------------------------------------------------------------------
1854void KCalculator::slotChooseScientificConst4(const science_constant &chosen_const)
1855{
1856 constants_->kcfg_valueConstant4->setText(chosen_const.value);
1857 constants_->kcfg_nameConstant4->setText(chosen_const.label);
1858}
1859
1860//------------------------------------------------------------------------------
1861// Name: slotChooseScientificConst5
1862// Desc: updates constants value
1863//------------------------------------------------------------------------------
1864void KCalculator::slotChooseScientificConst5(const science_constant &chosen_const)
1865{
1866 constants_->kcfg_valueConstant5->setText(chosen_const.value);
1867 constants_->kcfg_nameConstant5->setText(chosen_const.label);
1868}
1869
1870//------------------------------------------------------------------------------
1871// Name: slotSetSimpleMode
1872// Desc: sets the calculator to have a simple layout
1873//------------------------------------------------------------------------------
1874void KCalculator::slotSetSimpleMode()
1875{
1876 bool wasMinimumSize = isMinimumSize();
1877
1878 action_constants_show_->setChecked(false);
1879 action_constants_show_->setEnabled(false);
1880 action_bitset_show_->setEnabled(false);
1881 action_history_show_->setChecked(KCalcSettings::showHistory());
1882 showMemButtons(toggled: false);
1883 showScienceButtons(toggled: false);
1884 showStatButtons(toggled: false);
1885 showLogicButtons(toggled: false);
1886
1887 // hide some individual buttons, which are not in one of the above groups
1888 pbShift->hide();
1889 pbMod->hide();
1890 pbReci->hide();
1891 pbFactorial->hide();
1892 pbSquare->hide();
1893 pbPower->hide();
1894 pbCube->hide();
1895 pbEE->hide();
1896
1897 // delete the constant menu since it doesn't fit
1898 delete constants_menu_;
1899 constants_menu_ = nullptr;
1900
1901 KCalcSettings::setCalculatorMode(KCalcSettings::EnumCalculatorMode::simple);
1902 // must be done after setting the calculator mode because the
1903 // slotBitsetshow slot should save the state only in numeral mode
1904 action_bitset_show_->setChecked(false);
1905
1906 // disable leftPad from affecting the layout
1907 setLeftPadLayoutActive(false);
1908
1909 // update font size
1910 QApplication::processEvents();
1911 setFonts();
1912 updateGeometry();
1913
1914 if (!is_still_in_launch_) {
1915 forceResizeEvent();
1916 QApplication::processEvents();
1917 if (wasMinimumSize) {
1918 resize(minimumSize());
1919 }
1920 }
1921}
1922
1923//------------------------------------------------------------------------------
1924// Name: slotSetScienceMode
1925// Desc: sets the calculator to science mode
1926//------------------------------------------------------------------------------
1927void KCalculator::slotSetScienceMode()
1928{
1929 bool wasMinimumSize = isMinimumSize();
1930
1931 action_constants_show_->setEnabled(true);
1932 action_constants_show_->setChecked(KCalcSettings::showConstants());
1933 action_bitset_show_->setEnabled(false);
1934 action_history_show_->setChecked(KCalcSettings::showHistory());
1935
1936 // show some individual buttons
1937 pbShift->show();
1938 pbMod->show();
1939 pbReci->show();
1940 pbFactorial->show();
1941 pbSquare->show();
1942 pbPower->show();
1943 pbCube->show();
1944 pbEE->show();
1945
1946 // show or hide some groups of buttons
1947 showStatButtons(toggled: false);
1948 showLogicButtons(toggled: false);
1949 showMemButtons(toggled: true);
1950 showScienceButtons(toggled: true);
1951
1952 if (!constants_menu_) {
1953 constants_menu_ = createConstantsMenu();
1954 menuBar()->insertMenu((menuBar()->actions)()[2], constants_menu_);
1955 }
1956
1957 KCalcSettings::setCalculatorMode(KCalcSettings::EnumCalculatorMode::science);
1958 // must be done after setting the calculator mode because the
1959 // slotBitsetshow slot should save the state only in numeral mode
1960 action_bitset_show_->setChecked(false);
1961
1962 // enable leftPad to affect the layout
1963 setLeftPadLayoutActive(true);
1964
1965 // update font size
1966 QApplication::processEvents();
1967 setFonts();
1968 updateGeometry();
1969
1970 if (!is_still_in_launch_) {
1971 forceResizeEvent();
1972 QApplication::processEvents();
1973 if (wasMinimumSize) {
1974 resize(minimumSize());
1975 }
1976 }
1977}
1978
1979//------------------------------------------------------------------------------
1980// Name: slotSetStatisticMode
1981// Desc: sets the calculator to stats mode
1982//------------------------------------------------------------------------------
1983void KCalculator::slotSetStatisticMode()
1984{
1985 bool wasMinimumSize = isMinimumSize();
1986
1987 action_constants_show_->setEnabled(true);
1988 action_constants_show_->setChecked(KCalcSettings::showConstants());
1989 action_bitset_show_->setEnabled(false);
1990 action_history_show_->setChecked(KCalcSettings::showHistory());
1991
1992 // show some individual buttons
1993 pbShift->show();
1994 pbMod->show();
1995 pbReci->show();
1996 pbFactorial->show();
1997 pbSquare->show();
1998 pbPower->show();
1999 pbCube->show();
2000 pbEE->show();
2001
2002 // show or hide some groups of buttons
2003 showLogicButtons(toggled: false);
2004 showMemButtons(toggled: true);
2005 showScienceButtons(toggled: true);
2006 showStatButtons(toggled: true);
2007
2008 if (!constants_menu_) {
2009 constants_menu_ = createConstantsMenu();
2010 menuBar()->insertMenu((menuBar()->actions)()[2], constants_menu_);
2011 }
2012
2013 KCalcSettings::setCalculatorMode(KCalcSettings::EnumCalculatorMode::statistics);
2014 // must be done after setting the calculator mode because the
2015 // slotBitsetshow slot should save the state only in numeral mode
2016 action_bitset_show_->setChecked(false);
2017
2018 // enable leftPad to affect the layout
2019 setLeftPadLayoutActive(true);
2020
2021 // update font size
2022 QApplication::processEvents();
2023 setFonts();
2024 updateGeometry();
2025
2026 if (!is_still_in_launch_) {
2027 forceResizeEvent();
2028 QApplication::processEvents();
2029 if (wasMinimumSize) {
2030 resize(minimumSize());
2031 }
2032 }
2033}
2034
2035//------------------------------------------------------------------------------
2036// Name: slotSetNumeralMode
2037// Desc: sets the calculator to numerical ("programmers") mode
2038//------------------------------------------------------------------------------
2039void KCalculator::slotSetNumeralMode()
2040{
2041 bool wasMinimumSize = isMinimumSize();
2042
2043 action_constants_show_->setChecked(false);
2044 action_constants_show_->setEnabled(false);
2045 action_bitset_show_->setEnabled(true);
2046 action_bitset_show_->setChecked(KCalcSettings::showBitset());
2047 action_history_show_->setChecked(KCalcSettings::showHistory());
2048
2049 // show some individual buttons
2050 pbShift->show();
2051 pbMod->show();
2052 pbReci->show();
2053 pbFactorial->show();
2054 pbSquare->show();
2055 pbPower->show();
2056 pbCube->show();
2057 pbEE->show();
2058
2059 // show or hide some groups of buttons
2060 showScienceButtons(toggled: false);
2061 showStatButtons(toggled: false);
2062 showMemButtons(toggled: true);
2063 showLogicButtons(toggled: true);
2064
2065 if (!constants_menu_) {
2066 constants_menu_ = createConstantsMenu();
2067 menuBar()->insertMenu((menuBar()->actions)()[2], constants_menu_);
2068 }
2069
2070 KCalcSettings::setCalculatorMode(KCalcSettings::EnumCalculatorMode::numeral);
2071
2072 // enable leftPad to affect the layout
2073 setLeftPadLayoutActive(true);
2074
2075 // update font size
2076 QApplication::processEvents();
2077 setFonts();
2078 updateGeometry();
2079
2080 if (!is_still_in_launch_) {
2081 forceResizeEvent();
2082 QApplication::processEvents();
2083 if (wasMinimumSize) {
2084 resize(minimumSize());
2085 }
2086 }
2087}
2088
2089//------------------------------------------------------------------------------
2090// Name: slotBaseModeAmountChanged
2091// Desc: updates numerical base conversions
2092//------------------------------------------------------------------------------
2093void KCalculator::slotBaseModeAmountChanged(const KNumber &number)
2094{
2095 quint64 n = number.toUint64();
2096
2097 decDisplay->setText(QString::number(n, 10));
2098 binDisplay->setText(QString::number(n, 2));
2099 octDisplay->setText(QString::number(n, 8));
2100 hexDisplay->setText(QString::number(n, 16).toUpper());
2101}
2102
2103//------------------------------------------------------------------------------
2104// Name: showMemButtons
2105// Desc: hides or shows the memory buttons
2106//------------------------------------------------------------------------------
2107void KCalculator::showMemButtons(bool toggled)
2108{
2109 if (toggled) {
2110 for (QAbstractButton *btn : std::as_const(mem_button_list_)) {
2111 btn->show();
2112 }
2113 } else {
2114 for (QAbstractButton *btn : std::as_const(mem_button_list_)) {
2115 btn->hide();
2116 }
2117
2118 // these are in the mem_button_list_ but should not be hidden
2119 pbClear->show();
2120 pbAllClear->show();
2121 }
2122}
2123
2124//------------------------------------------------------------------------------
2125// Name: showStatButtons
2126// Desc: hides or shows the stat buttons
2127//------------------------------------------------------------------------------
2128void KCalculator::showStatButtons(bool toggled)
2129{
2130 if (toggled) {
2131 for (QAbstractButton *btn : std::as_const(stat_buttons_)) {
2132 btn->show();
2133 }
2134 } else {
2135 for (QAbstractButton *btn : std::as_const(stat_buttons_)) {
2136 btn->hide();
2137 }
2138 }
2139}
2140
2141//------------------------------------------------------------------------------
2142// Name: showScienceButtons
2143// Desc: hides or shows the science buttons
2144//------------------------------------------------------------------------------
2145void KCalculator::showScienceButtons(bool toggled)
2146{
2147 if (toggled) {
2148 for (QAbstractButton *btn : std::as_const(scientific_buttons_)) {
2149 btn->show();
2150 }
2151 const auto buttons = angle_choose_group_->buttons();
2152 for (QAbstractButton *btn : buttons) {
2153 btn->show();
2154 }
2155
2156 setAngle();
2157 statusBar()->setAngleModeIndicatorVisible(true);
2158 } else {
2159 for (QAbstractButton *btn : std::as_const(scientific_buttons_)) {
2160 btn->hide();
2161 }
2162
2163 const auto buttons = angle_choose_group_->buttons();
2164 for (QAbstractButton *btn : buttons) {
2165 btn->hide();
2166 }
2167
2168 statusBar()->setAngleModeIndicatorVisible(false);
2169 calc_display->setStatusText(AngleField, QString());
2170 }
2171}
2172
2173//------------------------------------------------------------------------------
2174// Name: showLogicButtons
2175// Desc: hides or shows the logic buttons
2176//------------------------------------------------------------------------------
2177void KCalculator::showLogicButtons(bool toggled)
2178{
2179 if (toggled) {
2180 mBitset->setEnabled(true);
2181 connect(mBitset, &KCalcBitset::valueChanged, this, &KCalculator::slotBitsetChanged);
2182 connect(calc_display, &KCalcDisplay::changedAmount, this, &KCalculator::slotUpdateBitset);
2183
2184 for (QAbstractButton *btn : std::as_const(logic_buttons_)) {
2185 btn->show();
2186 }
2187
2188 setBase();
2189 statusBar()->setBaseIndicatorVisible(true);
2190
2191 const auto buttons = base_choose_group_->buttons();
2192 for (QAbstractButton *btn : buttons) {
2193 btn->show();
2194 }
2195
2196 for (QLabel *lbl : base_conversion_labels_) {
2197 lbl->show();
2198 }
2199 connect(calc_display, &KCalcDisplay::changedAmount, this, &KCalculator::slotBaseModeAmountChanged);
2200
2201 for (int i = 10; i < 16; ++i) {
2202 (num_button_group_->button(i))->show();
2203 }
2204 } else {
2205 mBitset->setEnabled(false);
2206 disconnect(mBitset, &KCalcBitset::valueChanged, this, &KCalculator::slotBitsetChanged);
2207 disconnect(calc_display, &KCalcDisplay::changedAmount, this, &KCalculator::slotUpdateBitset);
2208
2209 for (QAbstractButton *btn : std::as_const(logic_buttons_)) {
2210 btn->hide();
2211 }
2212
2213 // Hide Hex-Buttons, but first switch back to decimal
2214 decRadio->animateClick();
2215
2216 const auto buttons = base_choose_group_->buttons();
2217 for (QAbstractButton *btn : buttons) {
2218 btn->hide();
2219 }
2220
2221 for (QLabel *lbl : base_conversion_labels_) {
2222 lbl->hide();
2223 }
2224 connect(calc_display, &KCalcDisplay::changedAmount, this, &KCalculator::slotBaseModeAmountChanged);
2225
2226 statusBar()->setBaseIndicatorVisible(false);
2227 calc_display->setStatusText(BaseField, QString());
2228 for (int i = 10; i < 16; ++i) {
2229 (num_button_group_->button(i))->hide();
2230 }
2231 }
2232}
2233
2234//------------------------------------------------------------------------------
2235// Name: slotHistoryshow
2236// Desc: hides or shows the history
2237//------------------------------------------------------------------------------
2238void KCalculator::slotHistoryshow(bool toggled) {
2239 bool wasMinimumSize = isMinimumSize();
2240
2241 calc_history->setVisible(toggled);
2242 KCalcSettings::setShowHistory(toggled);
2243 updateGeometry();
2244
2245 if (!is_still_in_launch_) {
2246 forceResizeEvent();
2247 QApplication::processEvents();
2248 if (wasMinimumSize) {
2249 resize(minimumSize());
2250 }
2251 }
2252}
2253
2254//------------------------------------------------------------------------------
2255// Name: slotConstantsShow
2256// Desc: hides or shows the constants buttons
2257//------------------------------------------------------------------------------
2258void KCalculator::slotConstantsShow(bool toggled)
2259{
2260 bool wasMinimumSize = isMinimumSize();
2261
2262 if (toggled) {
2263 for (QAbstractButton *btn : std::as_const(const_buttons_)) {
2264 btn->show();
2265 }
2266 } else {
2267 for (QAbstractButton *btn : std::as_const(const_buttons_)) {
2268 btn->hide();
2269 }
2270 }
2271
2272 KCalcSettings::setShowConstants(toggled);
2273 updateGeometry();
2274
2275 if (!is_still_in_launch_) {
2276 forceResizeEvent();
2277 QApplication::processEvents();
2278 if (wasMinimumSize) {
2279 // In this specific case, we need to invalidate the layout before resize
2280 layout()->invalidate();
2281 QApplication::processEvents();
2282 resize(minimumSize());
2283 }
2284 }
2285}
2286
2287//------------------------------------------------------------------------------
2288// Name: slotBitsetshow
2289// Desc: hides or shows the bitset buttons
2290//------------------------------------------------------------------------------
2291void KCalculator::slotBitsetshow(bool toggled)
2292{
2293 bool wasMinimumSize = isMinimumSize();
2294
2295 mBitset->setVisible(toggled);
2296 setBitsetLayoutActive(toggled);
2297 if (KCalcSettings::calculatorMode() == KCalcSettings::EnumCalculatorMode::numeral) {
2298 KCalcSettings::setShowBitset(toggled);
2299 }
2300 updateGeometry();
2301
2302 if (!is_still_in_launch_) {
2303 forceResizeEvent();
2304 QApplication::processEvents();
2305 if (wasMinimumSize) {
2306 resize(minimumSize());
2307 }
2308 }
2309}
2310
2311//------------------------------------------------------------------------------
2312// Name: slotBitsetshow
2313// Desc: This function is for setting the constant names configured in the
2314// kcalc settings menu. If the user doesn't enter a name for the
2315// constant C1 to C6 is used.
2316//------------------------------------------------------------------------------
2317void KCalculator::changeButtonNames()
2318{
2319 for (QAbstractButton *btn : std::as_const(const_buttons_)) {
2320 if (auto const constbtn = qobject_cast<KCalcConstButton *>(btn)) {
2321 constbtn->setLabelAndTooltip();
2322 }
2323 }
2324}
2325
2326//------------------------------------------------------------------------------
2327// Name: slotBitsetChanged
2328// Desc: updates the bitset display
2329// NOTE: sets display to *unsigned* value
2330//------------------------------------------------------------------------------
2331void KCalculator::slotBitsetChanged(quint64 value)
2332{
2333 calc_display->setAmount(KNumber(value));
2334 updateDisplay({});
2335 core.setOnlyUpdateOperation(false);
2336}
2337
2338//------------------------------------------------------------------------------
2339// Name: slotUpdateBitset
2340// Desc: updates the bitset itself
2341//------------------------------------------------------------------------------
2342void KCalculator::slotUpdateBitset(const KNumber &nr)
2343{
2344 mBitset->setValue(nr.toUint64());
2345}
2346
2347//------------------------------------------------------------------------------
2348// Name: updateSettings
2349// Desc: updates the persistent settings
2350//------------------------------------------------------------------------------
2351void KCalculator::updateSettings()
2352{
2353 changeButtonNames();
2354 setColors();
2355 setBaseFont(KCalcSettings::buttonFont());
2356 setFonts();
2357 setPrecision();
2358
2359 // Show the result in the app's caption in taskbar (wishlist - bug #52858)
2360 disconnect(calc_display, SIGNAL(changedText(QString)), this, nullptr);
2361
2362 if (KCalcSettings::captionResult()) {
2363 connect(calc_display, &KCalcDisplay::changedText, this, &KCalculator::setWindowTitle);
2364 } else {
2365 setCaption(QString());
2366 }
2367
2368 calc_display->changeSettings();
2369 calc_history->changeSettings();
2370 updateGeometry();
2371}
2372
2373//------------------------------------------------------------------------------
2374// Name: updateDisplay
2375// Desc: updates the display
2376//------------------------------------------------------------------------------
2377
2378void KCalculator::updateDisplay(UpdateFlags flags)
2379{
2380 if (flags & UPDATE_FROM_CORE) {
2381 if (update_history_window_) {
2382 calc_history->addToHistory(calc_display->getAmount().toQString(KCalcSettings::precision()), false);
2383 } else {
2384 update_history_window_ = true;
2385 }
2386 calc_display->updateFromCore(core, (flags & UPDATE_STORE_RESULT) != 0);
2387 } else {
2388 calc_display->update();
2389 }
2390
2391 pbShift->setChecked(false);
2392}
2393
2394//------------------------------------------------------------------------------
2395// Name: updateHistoryWithFunction
2396// Desc: updates the history with the last used function
2397//------------------------------------------------------------------------------
2398void KCalculator::updateHistoryWithFunction(CalcEngine::Operation func) {
2399 calc_history->addFuncToHistory(func);
2400}
2401
2402//------------------------------------------------------------------------------
2403// Name: setColors
2404// Desc: set the various colours
2405//------------------------------------------------------------------------------
2406void KCalculator::setColors()
2407{
2408 calc_display->changeSettings();
2409 calc_history->changeSettings();
2410
2411 const QColor numFontColor(KCalcSettings::numberFontsColor());
2412 for (int i = 0; i < 10; ++i) {
2413 qobject_cast<KCalcButton *>((num_button_group_->button(i)))->setTextColor(numFontColor);
2414 }
2415
2416 const QColor funcFontColor(KCalcSettings::functionFontsColor());
2417 for (QAbstractButton *btn : std::as_const(function_button_list_)) {
2418 qobject_cast<KCalcButton *>(btn)->setTextColor(funcFontColor);
2419 }
2420
2421 const QColor statFontColor(KCalcSettings::statFontsColor());
2422 for (QAbstractButton *btn : std::as_const(stat_buttons_)) {
2423 qobject_cast<KCalcButton *>(btn)->setTextColor(statFontColor);
2424 }
2425
2426 const QColor hexFontColor(KCalcSettings::hexFontsColor());
2427 for (int i = 10; i < 16; ++i) {
2428 qobject_cast<KCalcButton *>((num_button_group_->button(i)))->setTextColor(hexFontColor);
2429 }
2430
2431 const QColor memFontColor(KCalcSettings::memoryFontsColor());
2432 for (QAbstractButton *btn : std::as_const(mem_button_list_)) {
2433 qobject_cast<KCalcButton *>(btn)->setTextColor(memFontColor);
2434 }
2435
2436 const QColor opFontColor(KCalcSettings::operationFontsColor());
2437 for (QAbstractButton *btn : std::as_const(operation_button_list_)) {
2438 qobject_cast<KCalcButton *>(btn)->setTextColor(opFontColor);
2439 }
2440
2441 const QColor coFontColor(KCalcSettings::constantsFontsColor());
2442 for (QAbstractButton *btn : std::as_const(const_buttons_)) {
2443 qobject_cast<KCalcButton *>(btn)->setTextColor(coFontColor);
2444 }
2445
2446 KColorScheme schemeButtons(QPalette::Active, KColorScheme::Button);
2447 const QColor defaultColor = schemeButtons.background().color();
2448
2449 // Do not apply style sheets when using default background colors, see bug #237513
2450 if (KCalcSettings::numberButtonsColor() == defaultColor && KCalcSettings::functionButtonsColor() == defaultColor
2451 && KCalcSettings::statButtonsColor() == defaultColor && KCalcSettings::hexButtonsColor() == defaultColor
2452 && KCalcSettings::memoryButtonsColor() == defaultColor && KCalcSettings::operationButtonsColor() == defaultColor
2453 && KCalcSettings::constantsButtonsColor() == defaultColor) {
2454 return;
2455 }
2456
2457 const QString sheet = QStringLiteral("QPushButton { background-color: %1 }");
2458
2459 const QColor numPal(KCalcSettings::numberButtonsColor());
2460 for (int i = 0; i < 10; ++i) {
2461 (num_button_group_->button(i))->setStyleSheet(sheet.arg(numPal.name()));
2462 }
2463
2464 const QColor funcPal(KCalcSettings::functionButtonsColor());
2465 for (QAbstractButton *btn : std::as_const(function_button_list_)) {
2466 btn->setStyleSheet(sheet.arg(funcPal.name()));
2467 }
2468
2469 const QColor statPal(KCalcSettings::statButtonsColor());
2470 for (QAbstractButton *btn : std::as_const(stat_buttons_)) {
2471 btn->setStyleSheet(sheet.arg(statPal.name()));
2472 }
2473
2474 const QColor hexPal(KCalcSettings::hexButtonsColor());
2475 for (int i = 10; i < 16; ++i) {
2476 (num_button_group_->button(i))->setStyleSheet(sheet.arg(hexPal.name()));
2477 }
2478
2479 const QColor memPal(KCalcSettings::memoryButtonsColor());
2480 for (QAbstractButton *btn : std::as_const(mem_button_list_)) {
2481 btn->setStyleSheet(sheet.arg(memPal.name()));
2482 }
2483
2484 const QColor opPal(KCalcSettings::operationButtonsColor());
2485 for (QAbstractButton *btn : std::as_const(operation_button_list_)) {
2486 btn->setStyleSheet(sheet.arg(opPal.name()));
2487 }
2488
2489 const QColor coPal(KCalcSettings::constantsButtonsColor());
2490 for (QAbstractButton *btn : std::as_const(const_buttons_)) {
2491 btn->setStyleSheet(sheet.arg(coPal.name()));
2492 }
2493}
2494
2495//------------------------------------------------------------------------------
2496// Name: setFonts
2497// Desc: set the various fonts
2498//------------------------------------------------------------------------------
2499void KCalculator::setFonts()
2500{
2501 // Get the font selected in the settings
2502 QFont buttonFont = baseFont();
2503
2504 // Step 1: Gather the minimum button width and height of all buttons
2505
2506 int minButtonWidth = INT_MAX;
2507 int minButtonHeight = INT_MAX;
2508
2509 const auto leftPadLst = leftPad->children();
2510 for (QObject *obj : leftPadLst) {
2511 if (auto const button = qobject_cast<KCalcButton *>(obj)) {
2512 if (button->isVisible()) {
2513 if (button->width() < minButtonWidth)
2514 minButtonWidth = button->width();
2515 if (button->height() < minButtonHeight)
2516 minButtonHeight = button->height();
2517 }
2518 }
2519 }
2520
2521 const auto numericPadLst = numericPad->children();
2522 for (QObject *obj : numericPadLst) {
2523 if (auto const button = qobject_cast<KCalcButton *>(obj)) {
2524 if (button->isVisible()) {
2525 if (button->width() < minButtonWidth)
2526 minButtonWidth = button->width();
2527 if (button->height() < minButtonHeight)
2528 minButtonHeight = button->height();
2529 }
2530 }
2531 }
2532
2533 const auto rightPadLst = rightPad->children();
2534 for (QObject *obj : rightPadLst) {
2535 if (auto const button = qobject_cast<KCalcButton *>(obj)) {
2536 if (button->isVisible() && button != pbShift) {
2537 if (button->width() < minButtonWidth)
2538 minButtonWidth = button->width();
2539 if (button->height() < minButtonHeight)
2540 minButtonHeight = button->height();
2541 }
2542 }
2543 }
2544
2545 // Step 2: If step 1 worked, calculate new font size
2546
2547 if (!(minButtonWidth == INT_MAX || minButtonHeight == INT_MAX)) {
2548
2549 // Calculate new font size. Use the font size from the settings as minimum font size.
2550 // Please note these constants are arbitrarily chosen for lack of a better solution.
2551 // If issues with scaling arise (due to abnormally wide/tall fonts), increase them to compensate.
2552 buttonFont.setPointSizeF(qMax(KCalcSettings::buttonFont().pointSizeF(), qMin(minButtonWidth / 4.8, minButtonHeight / 3.6)));
2553
2554 }
2555
2556 // Step 3: Apply the new font (and size) to all buttons.
2557
2558 for (QObject *obj : leftPadLst) {
2559 if (auto const button = qobject_cast<KCalcButton *>(obj)) {
2560 button->setFont(buttonFont);
2561 }
2562 }
2563
2564 for (QObject *obj : numericPadLst) {
2565 if (auto const button = qobject_cast<KCalcButton *>(obj)) {
2566 button->setFont(buttonFont);
2567 }
2568 }
2569
2570 for (QObject *obj : rightPadLst) {
2571 if (auto const button = qobject_cast<KCalcButton *>(obj)) {
2572 button->setFont(buttonFont);
2573 }
2574 }
2575}
2576
2577//------------------------------------------------------------------------------
2578// Name: setBaseFont
2579// Desc: set the base font
2580//------------------------------------------------------------------------------
2581void KCalculator::setBaseFont(const QFont &font)
2582{
2583 // Overwrite current baseFont
2584 baseFont_ = font;
2585}
2586
2587//------------------------------------------------------------------------------
2588// Name: baseFont
2589// Desc: get the base font
2590//------------------------------------------------------------------------------
2591const QFont& KCalculator::baseFont() const
2592{
2593 return baseFont_;
2594}
2595
2596//------------------------------------------------------------------------------
2597// Name: isMinimumSize
2598// Desc: Is KCalc currently at minimum size?
2599//------------------------------------------------------------------------------
2600bool KCalculator::isMinimumSize()
2601{
2602 QSize contentSize = KCalculator::contentsRect().size();
2603 QMargins contentMargins = KCalculator::contentsMargins();
2604 QSize actualSize(contentSize.width() + contentMargins.left() + contentMargins.right(),
2605 contentSize.height() + contentMargins.top() + contentMargins.bottom());
2606 QSize minSize = KCalculator::minimumSize();
2607 return actualSize == minSize;
2608}
2609
2610//------------------------------------------------------------------------------
2611// Name: forceResizeEvent
2612// Desc: Force a resize event with no size changes
2613//------------------------------------------------------------------------------
2614void KCalculator::forceResizeEvent()
2615{
2616 QApplication::postEvent(this, new QResizeEvent(size(), size()));
2617}
2618
2619//------------------------------------------------------------------------------
2620// Name: setLeftPadLayoutActive
2621// Desc: Enable/disable whether leftPad affects the layout
2622//------------------------------------------------------------------------------
2623void KCalculator::setLeftPadLayoutActive(bool active)
2624{
2625 leftPad->setVisible(active);
2626}
2627
2628//------------------------------------------------------------------------------
2629// Name: setBitsetLayoutActive
2630// Desc: Enable/disable whether mBitset affects the layout
2631//------------------------------------------------------------------------------
2632void KCalculator::setBitsetLayoutActive(bool active)
2633{
2634 firstVerticalLayout->setStretch(1, (int)active); // 0 or 1
2635}
2636
2637//------------------------------------------------------------------------------
2638// Name: event
2639// Desc: catch application's palette and font change events
2640//------------------------------------------------------------------------------
2641bool KCalculator::event(QEvent *e)
2642{
2643 switch (e->type()) {
2644 case QEvent::ApplicationFontChange:
2645 setBaseFont(KCalcSettings::buttonFont());
2646 setFonts();
2647 updateGeometry();
2648 break;
2649 case QEvent::ApplicationPaletteChange:
2650 setColors();
2651 break;
2652 default:
2653 break;
2654 }
2655 return KXmlGuiWindow::event(e);
2656}
2657
2658//------------------------------------------------------------------------------
2659// Name: setPrecision
2660// Desc: set the precision of the display
2661//------------------------------------------------------------------------------
2662void KCalculator::setPrecision()
2663{
2664 KNumber::setDefaultFloatPrecision(KCalcSettings::precision());
2665 updateDisplay({});
2666}
2667
2668//------------------------------------------------------------------------------
2669// Name: setAngle
2670// Desc: sets the angle mode
2671//------------------------------------------------------------------------------
2672void KCalculator::setAngle()
2673{
2674 if (QAbstractButton *const btn = angle_choose_group_->button(KCalcSettings::angleMode())) {
2675 btn->animateClick();
2676 }
2677}
2678
2679//------------------------------------------------------------------------------
2680// Name: setBase
2681// Desc: sets the numeric base
2682//------------------------------------------------------------------------------
2683void KCalculator::setBase()
2684{
2685 if (QAbstractButton *const btn = base_choose_group_->button(KCalcSettings::baseMode())) {
2686 btn->animateClick();
2687 }
2688}
2689
2690//------------------------------------------------------------------------------
2691// Name: eventFilter
2692// Desc: general event filter used to track events like drag/drop
2693//------------------------------------------------------------------------------
2694bool KCalculator::eventFilter(QObject *o, QEvent *e)
2695{
2696 switch (e->type()) {
2697 case QEvent::DragEnter: {
2698 auto const ev = reinterpret_cast<QDragEnterEvent *>(e);
2699 ev->setAccepted(KColorMimeData::canDecode(mimeData: ev->mimeData()));
2700 return true;
2701 }
2702 case QEvent::DragLeave: {
2703 return true;
2704 }
2705 case QEvent::Drop: {
2706 auto const calcButton = qobject_cast<KCalcButton *>(o);
2707 if (!calcButton) {
2708 return false;
2709 }
2710
2711 auto const ev = reinterpret_cast<QDropEvent *>(e);
2712 QColor c = KColorMimeData::fromMimeData(ev->mimeData());
2713
2714 if (c.isValid()) {
2715 QString cn = c.name();
2716 QString sheet = QStringLiteral("background-color: %1");
2717
2718 QList<QAbstractButton *> *list;
2719 const int num_but = num_button_group_->buttons().indexOf(calcButton);
2720 if (num_but != -1) {
2721 // Was it hex-button or normal digit??
2722 if (num_but < 10) {
2723 for (int i = 0; i < 10; ++i) {
2724 (num_button_group_->buttons().at(i))->setStyleSheet(sheet.arg(cn));
2725 }
2726 } else {
2727 for (int i = 10; i < 16; ++i) {
2728 (num_button_group_->buttons().at(i))->setStyleSheet(sheet.arg(cn));
2729 }
2730 }
2731 return true;
2732 } else if (function_button_list_.contains(calcButton)) {
2733 list = &function_button_list_;
2734 } else if (stat_button_list_.contains(calcButton)) {
2735 list = &stat_button_list_;
2736 } else if (mem_button_list_.contains(calcButton)) {
2737 list = &mem_button_list_;
2738 } else if (operation_button_list_.contains(calcButton)) {
2739 list = &operation_button_list_;
2740 } else {
2741 return false;
2742 }
2743
2744 for (int i = 0; i < list->size(); ++i) {
2745 list->at(i)->setStyleSheet(sheet.arg(cn));
2746 }
2747 }
2748 return true;
2749 }
2750 // FALL THROUGH
2751 default:
2752 return KXmlGuiWindow::eventFilter(o, e);
2753 }
2754}
2755
2756//------------------------------------------------------------------------------
2757// Name: slotPaste
2758// Desc: paste a number from the clipboard
2759//------------------------------------------------------------------------------
2760void KCalculator::slotPaste()
2761{
2762 calc_display->slotPaste();
2763 core.setOnlyUpdateOperation(false);
2764}
2765
2766//------------------------------------------------------------------------------
2767// Name: resizeEvent
2768// Desc: resize window and make sure it's large enough for its content
2769//------------------------------------------------------------------------------
2770void KCalculator::resizeEvent(QResizeEvent* event)
2771{
2772 // Call the overridden resize event
2773 KXmlGuiWindow::resizeEvent(event);
2774
2775 updateGeometry();
2776
2777 // If the content size is now larger than the window size, resize window to fit
2778 QSize actualSize = KCalculator::size();
2779 QSize minSize = KCalculator::minimumSize();
2780 if (actualSize.width() < minSize.width() || actualSize.height() < minSize.height()) {
2781 KCalculator::resize(minSize); // force window as small as possible for current layout
2782 }
2783
2784 // Adjust button fonts
2785 setFonts();
2786
2787 // Force mBitset to call its resizeEvent
2788 mBitset->resize(0, 0);
2789}
2790
2791
2792////////////////////////////////////////////////////////////////
2793// Include the meta-object code for classes in this file
2794//
2795
2796//------------------------------------------------------------------------------
2797// Name: main
2798// Desc: entry point of the application
2799//------------------------------------------------------------------------------
2800int main(int argc, char *argv[])
2801{
2802 QApplication app(argc, argv);
2803
2804 KLocalizedString::setApplicationDomain(QByteArrayLiteral("kcalc"));
2805 KCrash::initialize();
2806 KAboutData aboutData(QStringLiteral("kcalc"),
2807 i18n("KCalc"),
2808 QStringLiteral(KCALC_VERSION_STRING),
2809 i18n("KDE Calculator"),
2810 KAboutLicense::GPL,
2811 i18n("Copyright © 2008-2013, Evan Teran\n"
2812 "Copyright © 2000-2008, The KDE Team\n"
2813 "Copyright © 2003-2005, Klaus Niederkr"
2814 "\xc3\xbc"
2815 "ger\n"
2816 "Copyright © 1996-2000, Bernd Johannes Wuebben"),
2817 QString(),
2818 QStringLiteral("https://apps.kde.org/kcalc/"));
2819
2820 // Klaus Niederkrueger
2821 aboutData.addAuthor(i18n("Klaus Niederkr"
2822 "\xc3\xbc"
2823 "ger"),
2824 QString(),
2825 QStringLiteral("kniederk@math.uni-koeln.de"));
2826 aboutData.addAuthor(i18n("Bernd Johannes Wuebben"), QString(), QStringLiteral("wuebben@kde.org"));
2827 aboutData.addAuthor(i18n("Evan Teran"), i18n("Maintainer"), QStringLiteral("eteran@alum.rit.edu"));
2828 aboutData.addAuthor(i18n("Espen Sand"), QString(), QStringLiteral("espen@kde.org"));
2829 aboutData.addAuthor(i18n("Chris Howells"), QString(), QStringLiteral("howells@kde.org"));
2830 aboutData.addAuthor(i18n("Aaron J. Seigo"), QString(), QStringLiteral("aseigo@olympusproject.org"));
2831 aboutData.addAuthor(i18n("Charles Samuels"), QString(), QStringLiteral("charles@altair.dhs.org"));
2832 // Rene Merou
2833 aboutData.addAuthor(i18n("Ren"
2834 "\xc3\xa9"
2835 " M"
2836 "\xc3\xa9"
2837 "rou"),
2838 QString(),
2839 QStringLiteral("ochominutosdearco@yahoo.es"));
2840 aboutData.addAuthor(i18n("Michel Marti"), QString(), QStringLiteral("mma@objectxp.com"));
2841 aboutData.addAuthor(i18n("David Johnson"), QString(), QStringLiteral("david@usermode.org"));
2842 aboutData.addAuthor(i18n("Niklas Freund"), QString(), QStringLiteral("nalquas.dev@gmail.com"));
2843
2844 KAboutData::setApplicationData(aboutData);
2845 app.setWindowIcon(QIcon::fromTheme(QStringLiteral("accessories-calculator"), app.windowIcon()));
2846
2847 QCommandLineParser parser;
2848 aboutData.setupCommandLine(&parser);
2849 parser.process(app);
2850 aboutData.processCommandLine(parser: &parser);
2851
2852 // Force system locale to "C" internally. Fix for bug #159168, showing multiple commas
2853 // in floating point operations because of different thousands separator and comma separator.
2854 setlocale(LC_NUMERIC, locale: "C");
2855
2856 KNumber::setGroupSeparator(QLocale().groupSeparator());
2857 KNumber::setDecimalSeparator(QString(QLocale().decimalPoint()));
2858
2859 auto calc = new KCalculator(nullptr);
2860
2861 calc->show();
2862 return app.exec();
2863}
2864
2865#include "moc_kcalc.cpp"
2866

source code of kcalc/kcalc.cpp