Warning, /plasma/kdeplasma-addons/applets/calculator/package/contents/ui/main.qml is written in an unsupported language. File is not indexed.

0001 /*
0002  *   SPDX-FileCopyrightText: 2015 Bernhard Friedreich <friesoft@gmail.com>
0003  *   SPDX-FileCopyrightText: 2014 Martin Yrjölä <martin.yrjola@gmail.com>
0004  *   SPDX-FileCopyrightText: 2012, 2014 Davide Bettio <davide.bettio@kdemail.net>
0005  *   SPDX-FileCopyrightText: 2012, 2014 David Edmundson <davidedmundson@kde.org>
0006  *   SPDX-FileCopyrightText: 2012 Luiz Romário Santana Rios <luizromario@gmail.com>
0007  *   SPDX-FileCopyrightText: 2007 Henry Stanaland <stanaland@gmail.com>
0008  *   SPDX-FileCopyrightText: 2008 Laurent Montel <montel@kde.org>
0009  *
0010  *   SPDX-License-Identifier: GPL-2.0-or-later
0011  */
0012 
0013 import QtQuick 2.5
0014 import QtQuick.Layouts 1.3
0015 import QtQuick.Controls 2.5 as QQC2
0016 import org.kde.kirigami 2.20 as Kirigami
0017 import org.kde.ksvg 1.0 as KSvg
0018 import org.kde.plasma.plasma5support 2.0 as P5Support
0019 import org.kde.plasma.components 3.0 as PlasmaComponents
0020 import org.kde.plasma.plasmoid
0021 
0022 PlasmoidItem {
0023     id: main;
0024 
0025     switchWidth: Kirigami.Units.gridUnit * 7
0026     switchHeight: Math.round(Kirigami.Units.gridUnit * 10.5)
0027 
0028     // Make the buttons' text labels scale with the widget's size
0029     // This is propagated down to all child controls with text
0030 
0031     property real result: 0;
0032     property bool hasResult: false;
0033     property bool showingInput: true;
0034     property bool showingResult: false;
0035     property string operator
0036     property real operand: 0;
0037     property bool commaPressed: false;
0038     property int decimals: 0;
0039     property int inputSize: 0;
0040     property TextEdit display
0041 
0042     readonly property int maxInputLength: 18; // More than that and the number notation
0043                                               // turns scientific (i.e.: 1.32324e+12).
0044                                               // When calculating 1/3 the answer is
0045                                               // 18 characters long.
0046 
0047     function digitClicked(digit) {
0048         if (showingResult) {
0049             allClearClicked();
0050         }
0051 
0052         if (commaPressed) {
0053             ++decimals;
0054             var tenToTheDecimals = Math.pow(10, decimals);
0055             operand = (operand * tenToTheDecimals + digit) / tenToTheDecimals;
0056         } else {
0057             operand = operand * 10 + digit;
0058         }
0059         showingInput = true;
0060         displayNumber(operand);
0061         ++inputSize;
0062     }
0063 
0064     function deleteDigit() {
0065         if (showingResult) {
0066             allClearClicked();
0067         }
0068 
0069         if (showingInput) {
0070             if (commaPressed) {
0071                 if (decimals === 0) {
0072                     commaPressed = false;
0073                 } else if (decimals > 0) {
0074                     operand -= operand % Math.pow(10, 1 - decimals);
0075                     --decimals;
0076                     --inputSize;
0077                 }
0078             } else if (inputSize > 0) {
0079                 operand = (operand - (operand % 10)) / 10;
0080                 --inputSize;
0081             }
0082         }
0083         displayNumber(operand);
0084     }
0085 
0086     function decimalClicked() {
0087         if (showingResult) {
0088             allClearClicked();
0089         }
0090 
0091         commaPressed = true;
0092         showingInput = true;
0093         displayNumber(operand);
0094     }
0095 
0096     function doOperation() {
0097         switch (operator) {
0098         case "+":
0099             result += operand;
0100             break;
0101         case "-":
0102             result -= operand;
0103             break;
0104         case "*":
0105             result *= operand;
0106             break;
0107         case "/":
0108             if (operand === 0) {
0109                 divisionByZero();
0110                 return;
0111             }
0112             result /= operand;
0113             break;
0114         default:
0115             return;
0116         }
0117 
0118         showingInput = false;
0119         displayNumber(result);
0120     }
0121 
0122     function clearOperand() {
0123         operand = 0;
0124         commaPressed = false;
0125         decimals = 0;
0126         inputSize = 0;
0127     }
0128 
0129     function setOperator(op) {
0130         if (!hasResult) {
0131             result = operand;
0132             hasResult = true;
0133         } else if (showingInput) {
0134             doOperation();
0135         }
0136 
0137         clearOperand();
0138         operator = op;
0139         showingResult = false;
0140     }
0141 
0142     function equalsClicked() {
0143         showingResult = true;
0144         doOperation();
0145     }
0146 
0147     function clearClicked() {
0148         clearOperand();
0149         operator = "";
0150         displayNumber(operand);
0151         showingInput = true;
0152         showingResult = false;
0153     }
0154 
0155     function allClearClicked() {
0156         clearClicked();
0157         result = 0;
0158         hasResult = false;
0159     }
0160 
0161     function algarismCount(number) {
0162         return number == 0? 1 :
0163                             Math.floor(Math.log(Math.abs(number))/Math.log(10)) + 1;
0164     }
0165 
0166     // use the clipboard datasource for being able to inspect the clipboard content before pasting it
0167     P5Support.DataSource {
0168         id: clipboardSource
0169         property bool editing: false;
0170         engine: "org.kde.plasma.clipboard"
0171         connectedSources: "clipboard"
0172     }
0173 
0174     function copyToClipboard() {
0175         display.selectAll();
0176         display.copy();
0177         display.deselect();
0178     }
0179 
0180     function pasteFromClipboard() {
0181         var content = clipboardSource.data["clipboard"]["current"];
0182         if (content != "") {
0183             content = content.trim();
0184         }
0185 
0186         // check if the clipboard content as a whole is a valid number (without sign, no operators, ...)
0187         if (isValidClipboardInput(content)) {
0188             var digitRegex = new RegExp('^[0-9]$');
0189             var decimalRegex = new RegExp('^[\.,]$');
0190 
0191             for (var i = 0; i < content.length; i++) {
0192                 if (digitRegex.test(content[i])) {
0193                     digitClicked(parseInt(content[i]));
0194                 } else if (decimalRegex.test(content[i])) {
0195                     decimalClicked();
0196                 }
0197             }
0198         }
0199     }
0200 
0201     function isValidClipboardInput(input) {
0202         return new RegExp('^[0-9]*[\.,]?[0-9]+$').test(input);
0203     }
0204 
0205     function displayNumber(number) {
0206         var text = number.toLocaleString(Qt.locale(), "g", 14);
0207 
0208         // Show all decimals including zeroes and show decimalPoint
0209         if (showingInput && commaPressed) {
0210             text = number.toLocaleString(Qt.locale(), "f", decimals);
0211             if (decimals === 0) {
0212                 text += Qt.locale().decimalPoint;
0213             }
0214         }
0215         display.text = text;
0216 
0217         var decimalsToShow = 9;
0218         // Decrease precision until the text fits to the display.
0219         while (display.contentWidth > display.width && decimalsToShow > 0) {
0220             display.text = number.toLocaleString(Qt.locale(), "g", decimalsToShow--);
0221         }
0222     }
0223 
0224     function divisionByZero() {
0225         showingInput = false;
0226         showingResult = true;
0227         display.text = i18nc("Abbreviation for result (undefined) of division by zero, max. six to nine characters.", "undef");
0228     }
0229 
0230     fullRepresentation: QQC2.Control {
0231         // Make the buttons' text labels scale with the widget's size
0232         // This is propagated down to all child controls with text
0233         font.pixelSize: Math.round(width/12)
0234         padding: 0
0235         Layout.minimumWidth: main.switchWidth
0236         Layout.minimumHeight: main.switchHeight
0237         Layout.preferredWidth: main.switchWidth * 2
0238         Layout.preferredHeight: main.switchHeight * 2
0239 
0240         contentItem: ColumnLayout {
0241             id: mainLayout
0242             anchors.fill: parent
0243             anchors.margins: 4
0244 
0245             focus: true;
0246             spacing: 4;
0247 
0248             Keys.onDigit0Pressed: { digitClicked(0); zeroButton.forceActiveFocus(Qt.TabFocusReason); }
0249             Keys.onDigit1Pressed: { digitClicked(1); oneButton.forceActiveFocus(Qt.TabFocusReason); }
0250             Keys.onDigit2Pressed: { digitClicked(2); twoButton.forceActiveFocus(Qt.TabFocusReason); }
0251             Keys.onDigit3Pressed: { digitClicked(3); threeButton.forceActiveFocus(Qt.TabFocusReason); }
0252             Keys.onDigit4Pressed: { digitClicked(4); fourButton.forceActiveFocus(Qt.TabFocusReason); }
0253             Keys.onDigit5Pressed: { digitClicked(5); fiveButton.forceActiveFocus(Qt.TabFocusReason); }
0254             Keys.onDigit6Pressed: { digitClicked(6); sixButton.forceActiveFocus(Qt.TabFocusReason); }
0255             Keys.onDigit7Pressed: { digitClicked(7); sevenButton.forceActiveFocus(Qt.TabFocusReason); }
0256             Keys.onDigit8Pressed: { digitClicked(8); eightButton.forceActiveFocus(Qt.TabFocusReason); }
0257             Keys.onDigit9Pressed: { digitClicked(9); nineButton.forceActiveFocus(Qt.TabFocusReason); }
0258             Keys.onEscapePressed: { allClearClicked(); allClearButton.forceActiveFocus(Qt.TabFocusReason); }
0259             Keys.onDeletePressed: { clearClicked(); clearButton.forceActiveFocus(Qt.TabFocusReason); }
0260             Keys.onPressed: {
0261                 switch (event.key) {
0262                 case Qt.Key_Plus:
0263                     setOperator("+");
0264                     plusButton.forceActiveFocus(Qt.TabFocusReason);
0265                     break;
0266                 case Qt.Key_Minus:
0267                     setOperator("-");
0268                     minusButton.forceActiveFocus(Qt.TabFocusReason);
0269                     break;
0270                 case Qt.Key_Asterisk:
0271                     setOperator("*");
0272                     multiplyButton.forceActiveFocus(Qt.TabFocusReason);
0273                     break;
0274                 case Qt.Key_Slash:
0275                     setOperator("/");
0276                     divideButton.forceActiveFocus(Qt.TabFocusReason);
0277                     break;
0278                 case Qt.Key_Comma:
0279                 case Qt.Key_Period:
0280                     decimalClicked();
0281                     decimalButton.forceActiveFocus(Qt.TabFocusReason);
0282                     break;
0283                 case Qt.Key_Equal:
0284                 case Qt.Key_Return:
0285                 case Qt.Key_Enter:
0286                     equalsClicked();
0287                     break;
0288                 case Qt.Key_Backspace:
0289                     deleteDigit();
0290                     display.forceActiveFocus(Qt.TabFocusReason);
0291                     break;
0292                 default:
0293                     if (event.matches(StandardKey.Copy)) {
0294                         copyToClipboard();
0295                     } else if (event.matches(StandardKey.Paste)) {
0296                         pasteFromClipboard();
0297                     }
0298                     break;
0299                 }
0300             }
0301 
0302             KeyNavigation.up: zeroButton
0303             KeyNavigation.down: clearButton
0304             KeyNavigation.left: allClearButton
0305             KeyNavigation.right: clearButton
0306 
0307             KSvg.FrameSvgItem {
0308                 id: displayFrame;
0309                 Layout.fillWidth: true
0310                 Layout.minimumHeight: 2 * display.font.pixelSize;
0311                 imagePath: "widgets/frame";
0312                 prefix: "plain";
0313 
0314                 TextEdit {
0315                     id: display;
0316                     anchors {
0317                         fill: parent;
0318                         margins: parent.margins.right;
0319                     }
0320                     text: "0";
0321                     font.pointSize: Kirigami.Theme.defaultFont.pointSize * 2;
0322                     font.weight: Font.Bold;
0323                     Kirigami.Theme.colorSet: Kirigami.Theme.View
0324                     color: Kirigami.Theme.textColor
0325                     horizontalAlignment: TextEdit.AlignRight;
0326                     verticalAlignment: TextEdit.AlignVCenter;
0327                     readOnly: true;
0328 
0329                     focus: main.expanded
0330 
0331                     Accessible.name: text
0332                     Accessible.description: i18nc("@label calculation result", "Result")
0333 
0334                     Binding {
0335                         target: main
0336                         property: "display"
0337                         value: display
0338                     }
0339                 }
0340             }
0341 
0342             GridLayout {
0343                 id: buttonsGrid;
0344                 columns: 4;
0345                 rows: 5;
0346                 columnSpacing: 4
0347                 rowSpacing: 4
0348 
0349                 Layout.fillWidth: true
0350                 Layout.fillHeight: true
0351 
0352                 PlasmaComponents.Button {
0353                     id: clearButton
0354 
0355                     Layout.fillWidth: true
0356                     Layout.fillHeight: true
0357 
0358                     KeyNavigation.down: sevenButton
0359                     KeyNavigation.right: divideButton
0360 
0361                     text: i18nc("Text of the clear button", "C");
0362                     onClicked: clearClicked();
0363                 }
0364 
0365                 PlasmaComponents.Button {
0366                     id: divideButton
0367 
0368                     Layout.fillWidth: true
0369                     Layout.fillHeight: true
0370 
0371                     KeyNavigation.down: eightButton
0372                     KeyNavigation.right: multiplyButton
0373 
0374                     text: i18nc("Text of the division button", "÷");
0375                     onClicked: setOperator("/");
0376                 }
0377 
0378                 PlasmaComponents.Button {
0379                     id: multiplyButton
0380 
0381                     Layout.fillWidth: true
0382                     Layout.fillHeight: true
0383 
0384                     KeyNavigation.down: nineButton
0385                     KeyNavigation.right: allClearButton
0386 
0387                     text: i18nc("Text of the multiplication button", "×");
0388                     onClicked: setOperator("*");
0389                 }
0390 
0391                 PlasmaComponents.Button {
0392                     id: allClearButton
0393 
0394                     Layout.fillWidth: true
0395                     Layout.fillHeight: true
0396 
0397                     KeyNavigation.down: minusButton
0398 
0399                     text: i18nc("Text of the all clear button", "AC");
0400                     onClicked: allClearClicked();
0401                 }
0402 
0403 
0404                 PlasmaComponents.Button {
0405                     id: sevenButton
0406 
0407                     Layout.fillWidth: true
0408                     Layout.fillHeight: true
0409 
0410                     KeyNavigation.down: fourButton
0411                     KeyNavigation.right: eightButton
0412 
0413                     text: "7";
0414                     onClicked: digitClicked(7);
0415                 }
0416 
0417                 PlasmaComponents.Button {
0418                     id: eightButton
0419 
0420                     Layout.fillWidth: true
0421                     Layout.fillHeight: true
0422 
0423                     KeyNavigation.down: fiveButton
0424                     KeyNavigation.right: nineButton
0425 
0426                     text: "8";
0427                     onClicked: digitClicked(8);
0428                 }
0429 
0430                 PlasmaComponents.Button {
0431                     id: nineButton
0432 
0433                     Layout.fillWidth: true
0434                     Layout.fillHeight: true
0435 
0436                     KeyNavigation.down: sixButton
0437                     KeyNavigation.right: minusButton
0438 
0439                     text: "9";
0440                     onClicked: digitClicked(9);
0441                 }
0442 
0443                 PlasmaComponents.Button {
0444                     id: minusButton
0445 
0446                     Layout.fillWidth: true
0447                     Layout.fillHeight: true
0448 
0449                     KeyNavigation.down: plusButton
0450 
0451                     text: i18nc("Text of the minus button", "-");
0452                     onClicked: setOperator("-");
0453                 }
0454 
0455 
0456                 PlasmaComponents.Button {
0457                     id: fourButton
0458 
0459                     Layout.fillWidth: true
0460                     Layout.fillHeight: true
0461 
0462                     KeyNavigation.down: oneButton
0463                     KeyNavigation.right: fiveButton
0464 
0465                     text: "4";
0466                     onClicked: digitClicked(4);
0467                 }
0468 
0469                 PlasmaComponents.Button {
0470                     id: fiveButton
0471 
0472                     Layout.fillWidth: true
0473                     Layout.fillHeight: true
0474 
0475                     KeyNavigation.down: twoButton
0476                     KeyNavigation.right: sixButton
0477 
0478                     text: "5";
0479                     onClicked: digitClicked(5);
0480                 }
0481 
0482                 PlasmaComponents.Button {
0483                     id: sixButton
0484 
0485                     Layout.fillWidth: true
0486                     Layout.fillHeight: true
0487 
0488                     KeyNavigation.down: threeButton
0489                     KeyNavigation.right: plusButton
0490 
0491                     text: "6";
0492                     onClicked: digitClicked(6);
0493                 }
0494 
0495                 PlasmaComponents.Button {
0496                     id: plusButton
0497 
0498                     Layout.fillWidth: true
0499                     Layout.fillHeight: true
0500 
0501                     KeyNavigation.down: ansButton
0502 
0503                     text: i18nc("Text of the plus button", "+");
0504                     onClicked: setOperator("+");
0505                 }
0506 
0507 
0508                 PlasmaComponents.Button {
0509                     id: oneButton
0510 
0511                     Layout.fillWidth: true
0512                     Layout.fillHeight: true
0513 
0514                     KeyNavigation.down: zeroButton
0515                     KeyNavigation.right: twoButton
0516 
0517                     text: "1";
0518                     onClicked: digitClicked(1);
0519                 }
0520 
0521                 PlasmaComponents.Button {
0522                     id: twoButton
0523 
0524                     Layout.fillWidth: true
0525                     Layout.fillHeight: true
0526 
0527                     KeyNavigation.down: zeroButton
0528                     KeyNavigation.right: threeButton
0529 
0530                     text: "2";
0531                     onClicked: digitClicked(2);
0532                 }
0533 
0534                 PlasmaComponents.Button {
0535                     id: threeButton
0536 
0537                     Layout.fillWidth: true
0538                     Layout.fillHeight: true
0539 
0540                     KeyNavigation.down: decimalButton
0541                     KeyNavigation.right: ansButton
0542 
0543                     text: "3";
0544                     onClicked: digitClicked(3);
0545                 }
0546 
0547                 PlasmaComponents.Button {
0548                     id: ansButton
0549 
0550                     Layout.fillWidth: true
0551                     Layout.fillHeight: true
0552 
0553                     Layout.rowSpan: 2
0554                     text: i18nc("Text of the equals button", "=");
0555                     onClicked: equalsClicked();
0556                 }
0557 
0558                 PlasmaComponents.Button {
0559                     id: zeroButton
0560 
0561                     Layout.fillWidth: true
0562                     Layout.fillHeight: true
0563 
0564                     KeyNavigation.right: decimalButton
0565 
0566                     Layout.columnSpan: 2
0567                     text: "0";
0568                     onClicked: digitClicked(0);
0569                 }
0570 
0571                 PlasmaComponents.Button {
0572                     id: decimalButton
0573 
0574                     Layout.fillWidth: true
0575                     Layout.fillHeight: true
0576 
0577                     KeyNavigation.right: ansButton
0578 
0579                     text: Qt.locale().decimalPoint;
0580                     onClicked: decimalClicked();
0581                 }
0582             }
0583         }
0584     }
0585 }
0586