QML-EnhancedCalcExample

(CalcButton)
 
(3 intermediate revisions not shown)
Line 1: Line 1:
 +
{{expand}}
 +
== About the Enhanced Calc Example ==
== About the Enhanced Calc Example ==
Line 10: Line 12:
The file below defines the layouts of the calculator. It uses the button below to draw nice looking button shape, that has glow effect.  
The file below defines the layouts of the calculator. It uses the button below to draw nice looking button shape, that has glow effect.  
 +
<source lang="javascript">
import Qt 4.6
import Qt 4.6
Line 17: Line 20:
     SystemPalette { id: palette }
     SystemPalette { id: palette }
     Script { source: "calculator.js" }
     Script { source: "calculator.js" }
 +
</source>
We use the system palette for colors and the calculator.js file for all of the calculation logic.  
We use the system palette for colors and the calculator.js file for all of the calculation logic.  
 +
<source lang="javascript">
     Column {
     Column {
         x: 2; spacing: 2;
         x: 2; spacing: 2;
Line 25: Line 30:
           id: numericOperations
           id: numericOperations
           spacing: 2
           spacing: 2
 +
</source>
-
We use column layout for the numeric operations (the field that shows the calcuations) layout, with small intendation (2 px) and small padding.  
+
We use column layout for the numeric operations (the field that shows the calculations) layout, with small indentation (2 px) and small padding.  
 +
<source lang="javascript">
           Rectangle {
           Rectangle {
               id: container
               id: container
Line 54: Line 61:
           CalcButton { operation: "Bksp"; id: bksp; opacity: 0 }
           CalcButton { operation: "Bksp"; id: bksp; opacity: 0 }
         }
         }
 +
</source>
The Text area for the calculations, surrounded by dark border, with two text areas: the operation and the value. The operation (e.g. "*" to signal multiplication, is anchored left, and the calculation is anchored to the right.
The Text area for the calculations, surrounded by dark border, with two text areas: the operation and the value. The operation (e.g. "*" to signal multiplication, is anchored left, and the calculation is anchored to the right.
 +
<source lang="javascript">
         Item {
         Item {
             height:460; width: 420;
             height:460; width: 420;
Line 63: Line 72:
                 id: basicButtons
                 id: basicButtons
                 x: 55; width: 460; height: 400
                 x: 55; width: 460; height: 400
 +
</source>
The above defines the compound item of the basicButtons. The actual buttons are defined below. We intend by default this with 55 so that the buttons in basic layout don't feel like they are in the left side of the screen. This padding is changed in the transition to advanced layout.                 
The above defines the compound item of the basicButtons. The actual buttons are defined below. We intend by default this with 55 so that the buttons in basic layout don't feel like they are in the left side of the screen. This padding is changed in the transition to advanced layout.                 
-
               
+
 
 +
<source lang="javascript">
                 Row {
                 Row {
                     id: commonOperations
                     id: commonOperations
Line 81: Line 92:
                      
                      
                 }
                 }
 +
</source>
-
Common operations to clean the calcuations are on one row, along with speacial wider toggle button for advanced mode.  
+
Common operations to clean the calculations are on one row, along with special wider toggle button for advanced mode.  
-
 
+
 +
<source lang="javascript">
                 Grid {
                 Grid {
                     id: numKeypad; y:60; spacing: 0; columns: 3
                     id: numKeypad; y:60; spacing: 0; columns: 3
Line 100: Line 112:
                     CalcButton { operation: "=" }                     
                     CalcButton { operation: "=" }                     
                 }
                 }
 +
</source>
Normal numbers and . and = keys are in grid layout
Normal numbers and . and = keys are in grid layout
 +
<source lang="javascript">
                 Column {
                 Column {
                     id: simpleOperations
                     id: simpleOperations
Line 112: Line 126:
                 }
                 }
             }
             }
 +
</source>
Basic calculation operations are in one column (for easy layouting).
Basic calculation operations are in one column (for easy layouting).
 +
<source lang="javascript">
             Grid {
             Grid {
                 id: advancedButtons
                 id: advancedButtons
Line 139: Line 155:
               CalcButton { operation: "x^y" }
               CalcButton { operation: "x^y" }
             }
             }
 +
</source>
Advanced operations are in 2x5 grid and trigonometry operations are on one row. Easy positioning of those compound elements.
Advanced operations are in 2x5 grid and trigonometry operations are on one row. Easy positioning of those compound elements.
 +
<source lang="javascript">
         }
         }
     }
     }
Line 154: Line 172:
          
          
     }
     }
 +
</source>
-
States definition for advanced mode. Basic mode doesn't need to be defined, as we have defined that already as the default mode of operation. For advanced state, we modify the bacspace to be visible, we move basic buttons a bit, we enable advanced and trigonometry buttons and move them a bit for visual candy.
+
States definition for advanced mode. Basic mode doesn't need to be defined, as we have defined that already as the default mode of operation. For advanced state, we modify the backspace to be visible, we move basic buttons a bit, we enable advanced and trigonometry buttons and move them a bit for visual candy.
-
 
+
 +
<source lang="javascript">
     transitions: Transition {
     transitions: Transition {
         NumberAnimation { matchProperties: "x,y,width"; easing: "easeOutBounce"; duration: 500 }
         NumberAnimation { matchProperties: "x,y,width"; easing: "easeOutBounce"; duration: 500 }
Line 163: Line 182:
     }
     }
  }
  }
 +
</source>
Above defines the animations for the transition to and from advanced mode.
Above defines the animations for the transition to and from advanced mode.
-
 
== CalcButton ==
== CalcButton ==
The code below makes a button that has a glow effect when tapped on.  
The code below makes a button that has a glow effect when tapped on.  
 +
<source lang="javascript">
import Qt 4.6
import Qt 4.6
Line 200: Line 220:
     }
     }
     Text { id: label; anchors.centerIn: parent; color: palette.buttonText }
     Text { id: label; anchors.centerIn: parent; color: palette.buttonText }
 +
</source>
-
On the above, we define the bg of the button and the highlight of the button. THe highlight is img and the bg image is, well, bgimg.
+
On the above, we define the bg of the button and the highlight of the button. The highlight is img and the bg image is, well, bgimg.
-
 
+
 +
<source lang="javascript">
     MouseRegion {
     MouseRegion {
         id: clickRegion
         id: clickRegion
Line 214: Line 235:
         }
         }
     }
     }
 +
</source>
Above handles the mouse clicks.
Above handles the mouse clicks.
 +
<source lang="javascript">
     states: [
     states: [
         State {
         State {
Line 229: Line 252:
         }
         }
     ]
     ]
 +
</source>
Above defines state "pressed", which triggers the highlight to come up all the way, moves all of the parent objects also up in the stack and sets target opacity for the highlight to be 0.
Above defines state "pressed", which triggers the highlight to come up all the way, moves all of the parent objects also up in the stack and sets target opacity for the highlight to be 0.
-
   
+
 
 +
<source lang="javascript">
         transitions: Transition {
         transitions: Transition {
             NumberAnimation { matchProperties: "z,scale"; easing: "easeOutExpo"; duration: 200 }
             NumberAnimation { matchProperties: "z,scale"; easing: "easeOutExpo"; duration: 200 }
Line 237: Line 262:
              
              
         }
         }
-
Above defines the transitions for the button.
+
}
-
 
+
</source>
-
}
+
 +
Above defines the transitions for the button.
== Calculator.js ==
== Calculator.js ==
Line 247: Line 272:
-
 
+
<source lang="javascript">
var curVal = 0;
var curVal = 0;
var memory = 0;
var memory = 0;
Line 345: Line 370:
     }
     }
}
}
 +
</source>
[[Category:Development]]
[[Category:Development]]
[[Category:Qt]]
[[Category:Qt]]

Latest revision as of 17:05, 15 June 2010

Image:Ambox_notice.png
This article does not provide enough information, and needs to be expanded to more fully cover the topic.
Please see the talk page for discussion.

Contents

[edit] About the Enhanced Calc Example

See Youtube video for demo of the app.


Source code available from qml examples garage page

[edit] Calculator.qml

The file below defines the layouts of the calculator. It uses the button below to draw nice looking button shape, that has glow effect.

import Qt 4.6
 
 Rectangle {
    width: parent.width; height: 480; color: palette.window
    anchors.fill: parent;
    SystemPalette { id: palette }
    Script { source: "calculator.js" }

We use the system palette for colors and the calculator.js file for all of the calculation logic.

    Column {
        x: 2; spacing: 2;
        Row {
          id: numericOperations
          spacing: 2

We use column layout for the numeric operations (the field that shows the calculations) layout, with small indentation (2 px) and small padding.

          Rectangle {
              id: container
              width: 400; height: 55
              border.color: palette.dark; color: palette.base
 
              Text {
                  id: curNum
                  font.bold: true; font.pointSize: 22
                  color: palette.text
                  anchors.right: container.right
                  anchors.rightMargin: 5
                  anchors.verticalCenter: container.verticalCenter
              }
 
              Text {
                  id: currentOperation
                  color: palette.text
                  font.bold: true; font.pointSize: 26
                  anchors.left: container.left
                  anchors.leftMargin: 5
                  anchors.verticalCenter: container.verticalCenter
              }
 
          }
          CalcButton { operation: "Bksp"; id: bksp; opacity: 0 }
        }

The Text area for the calculations, surrounded by dark border, with two text areas: the operation and the value. The operation (e.g. "*" to signal multiplication, is anchored left, and the calculation is anchored to the right.

        Item {
            height:460; width: 420;
 
            Item {
                id: basicButtons
                x: 55; width: 460; height: 400

The above defines the compound item of the basicButtons. The actual buttons are defined below. We intend by default this with 55 so that the buttons in basic layout don't feel like they are in the left side of the screen. This padding is changed in the transition to advanced layout.

                Row {
                    id: commonOperations
                    spacing: 0
                    height:150
 
                    CalcButton { 
                        operation: "Advanced"
                        id: advancedCheckBox
                        width: 160
                        toggable: true
                    }
                    CalcButton { operation: "C"; id: c; }
                    CalcButton { operation: "AC"; id: ac;}
 
                }

Common operations to clean the calculations are on one row, along with special wider toggle button for advanced mode.

                Grid {
                    id: numKeypad; y:60; spacing: 0; columns: 3
                    CalcButton { operation: "7" }
                    CalcButton { operation: "8" }
                    CalcButton { operation: "9" }
                    CalcButton { operation: "4" }
                    CalcButton { operation: "5" }
                    CalcButton { operation: "6" }
                    CalcButton { operation: "1" }
                    CalcButton { operation: "2" }
                    CalcButton { operation: "3" }
                    CalcButton { operation: "0" }
                    CalcButton { operation: "." }
                    CalcButton { operation: "=" }                    
                }

Normal numbers and . and = keys are in grid layout

                Column {
                    id: simpleOperations
                    x: 240;  y: 60; spacing: 0
                    CalcButton { operation: "x" }
                    CalcButton { operation: "/" }
                    CalcButton { operation: "-" }
                    CalcButton { operation: "+" }
                }
            }

Basic calculation operations are in one column (for easy layouting).

            Grid {
                id: advancedButtons
                x: 250; spacing: 0; columns: 2; opacity: 0
                CalcButton { operation: "Abs" }
                CalcButton { operation: "Int" }
                CalcButton { operation: "MC" }
                CalcButton { operation: "Sqrt" }
                CalcButton { operation: "MR" }
                CalcButton { operation: "^2" }
                CalcButton { operation: "MS" }
                CalcButton { operation: "1/x" }
                CalcButton { operation: "M+" }
                CalcButton { operation: "+/-" }
            }
            Row {
              id: trigonometryOperations
              spacing: 0;opacity: 0;y: 280;x:40
              CalcButton { operation: "Sin" }
              CalcButton { operation: "Cos" }
              CalcButton { operation: "Tan" }
              CalcButton { operation: "Log" }
              CalcButton { operation: "e^x" }
              CalcButton { operation: "x^y" }
            }

Advanced operations are in 2x5 grid and trigonometry operations are on one row. Easy positioning of those compound elements.

        }
    }
 
    states: State {
        name: "Advanced"; when: advancedCheckBox.toggled == true
        PropertyChanges { target: basicButtons; x: 0 }
        PropertyChanges { target: bksp; opacity: 1 }
        PropertyChanges { target: commonOperations; x: 0;  }
        PropertyChanges { target: advancedButtons; x: 320; opacity: 1 }
        PropertyChanges { target: trigonometryOperations; x:0; y: 300; opacity: 1 }
 
    }

States definition for advanced mode. Basic mode doesn't need to be defined, as we have defined that already as the default mode of operation. For advanced state, we modify the backspace to be visible, we move basic buttons a bit, we enable advanced and trigonometry buttons and move them a bit for visual candy.

    transitions: Transition {
        NumberAnimation { matchProperties: "x,y,width"; easing: "easeOutBounce"; duration: 500 }
        NumberAnimation { matchProperties: "opacity"; easing: "easeInOutQuad"; duration: 500 }
    }
 }

Above defines the animations for the transition to and from advanced mode.

[edit] CalcButton

The code below makes a button that has a glow effect when tapped on.

import Qt 4.6
 
 
 Rectangle {
    property alias operation: label.text
    property bool toggable: false
    property bool toggled: false
    signal clicked
    id: button; width: 80; height: 60
    color: "black"      
    BorderImage {
      id: img
      width: parent.width
      height: parent.height
      border.left: 14
      border.right: 14      
      source:"Button_h.png"
      transformOrigin: Item.Center  
 
    }
 
    BorderImage {
      id: bgimg
      width: parent.width
      height: parent.height
      border.left: 14
      border.right: 14      
      source:"Button.png"  
    }
    Text { id: label; anchors.centerIn: parent; color: palette.buttonText }

On the above, we define the bg of the button and the highlight of the button. The highlight is img and the bg image is, well, bgimg.

    MouseRegion {
        id: clickRegion
        anchors.fill: parent
        onClicked: {
            doOp(operation);
            button.clicked();
            if (!button.toggable) return;
            button.toggled ? button.toggled = false : button.toggled = true
        }
    }

Above handles the mouse clicks.

    states: [
        State {
            name: "Pressed"; when: clickRegion.pressed == true
            PropertyChanges { target: img; scale: 2.0 }
            PropertyChanges { target: button; z: 1 }
            PropertyChanges { target: button.parent; z: 1 }
            PropertyChanges { target: button.parent.parent; z: 1 }
            PropertyChanges { target: img; z: 1.1 }
            PropertyChanges { target: img; opacity: 0 }
 
        }
    ]

Above defines state "pressed", which triggers the highlight to come up all the way, moves all of the parent objects also up in the stack and sets target opacity for the highlight to be 0.

        transitions: Transition {
            NumberAnimation { matchProperties: "z,scale"; easing: "easeOutExpo"; duration: 200 }
            NumberAnimation { matchProperties: "opacity"; easing: "easeInQuad"; duration: 300 }
 
        }
}

Above defines the transitions for the button.

[edit] Calculator.js

I won't comment the javascript code. It's self explanatory.


var curVal = 0;
var memory = 0;
var lastOp = "";
var timer = 0;
 
function disabled(op) {
    if (op == "." && curNum.text.toString().search(/\./) != -1) {
        return true;
    } else if (op == "Sqrt" &&  curNum.text.toString().search(/-/) != -1) {
        return true;
    } else {
        return false;
    }
}
 
function doOp(op) {
    if (disabled(op)) {
        return;
    }
 
    if (op.toString().length==1 && ((op >= "0" && op <= "9") || op==".") ) {
        if (curNum.text.toString().length >= 14)
            return; // No arbitrary length numbers
        if (lastOp.toString().length == 1 && ((lastOp >= "0" && lastOp <= "9") || lastOp==".") ) {
            curNum.text = curNum.text + op.toString();
        } else {
            curNum.text = op;
        }
        lastOp = op;
        return;
    }
    lastOp = op;
 
    // Pending operations
    if (currentOperation.text == "+") {
        curNum.text = Number(curNum.text.valueOf()) + Number(curVal.valueOf());
    } else if (currentOperation.text == "-") {
        curNum.text = Number(curVal) - Number(curNum.text.valueOf());
    } else if (currentOperation.text == "x") {
        curNum.text = Number(curVal) * Number(curNum.text.valueOf());
    } else if (currentOperation.text == "x^y") {
        curNum.text = (Math.pow(Number(curVal),curNum.text.valueOf())).toString();
    } else if (currentOperation.text == "/") {
        curNum.text = Number(Number(curVal) / Number(curNum.text.valueOf())).toString();
    } else if (currentOperation.text == "=") {
    }
 
    if (op == "+" || op == "-" || op == "x" || op=="x^y" || op == "/") {
        currentOperation.text = op;
        curVal = curNum.text.valueOf();
        return;
    }
    curVal = 0;
    currentOperation.text = "";
 
    // Immediate operations
    if (op == "1/x") { // reciprocal
        curNum.text = (1 / curNum.text.valueOf()).toString();
    } else if (op == "^2") { // squared
        curNum.text = (curNum.text.valueOf() * curNum.text.valueOf()).toString();
    } else if (op == "Abs") {
        curNum.text = (Math.abs(curNum.text.valueOf())).toString();
    } else if (op == "Sin") {
        curNum.text = (Math.sin(curNum.text.valueOf())).toString();
    } else if (op == "Cos") {
        curNum.text = (Math.cos(curNum.text.valueOf())).toString();
    } else if (op == "Tan") {
        curNum.text = (Math.tan(curNum.text.valueOf())).toString();
    } else if (op == "Log") {
        curNum.text = (Math.log(curNum.text.valueOf())).toString();
    } else if (op == "e^x") {
        curNum.text = (Math.exp(curNum.text.valueOf())).toString();
    } else if (op == "Int") {
        curNum.text = (Math.floor(curNum.text.valueOf())).toString();
    } else if (op == "+/-") { // plus/minus
        curNum.text = (curNum.text.valueOf() * -1).toString();
    } else if (op == "Sqrt") { // square root
        curNum.text = (Math.sqrt(curNum.text.valueOf())).toString();
    } else if (op == "MC") { // memory clear
        memory = 0;
    } else if (op == "M+") { // memory increment
        memory += curNum.text.valueOf();
    } else if (op == "MR") { // memory recall
        curNum.text = memory.toString();
    } else if (op == "MS") { // memory set
        memory = curNum.text.valueOf();
    } else if (op == "Bksp") {
        curNum.text = curNum.text.toString().slice(0, -1);
    } else if (op == "C") {
        curNum.text = "0";
    } else if (op == "AC") {
        curVal = 0;
        memory = 0;
        lastOp = "";
        curNum.text ="0";
    }
}