summaryrefslogtreecommitdiffstats
path: root/demos
diff options
context:
space:
mode:
Diffstat (limited to 'demos')
-rw-r--r--demos/declarative/calculator/CalcButton.qml41
-rw-r--r--demos/declarative/calculator/calculator.js87
-rw-r--r--demos/declarative/calculator/calculator.qml130
-rw-r--r--demos/declarative/contacts/Button.qml60
-rw-r--r--demos/declarative/contacts/Contact.qml116
-rw-r--r--demos/declarative/contacts/ContactField.qml60
-rw-r--r--demos/declarative/contacts/FieldText.qml154
-rw-r--r--demos/declarative/contacts/RemoveButton.qml123
-rw-r--r--demos/declarative/contacts/SearchBar.qml26
-rw-r--r--demos/declarative/contacts/contacts.qml319
-rw-r--r--demos/declarative/contacts/contacts.sqlitebin0 -> 86016 bytes
-rw-r--r--demos/declarative/contacts/pics/cancel.pngbin0 -> 1038 bytes
-rw-r--r--demos/declarative/contacts/pics/email.pngbin0 -> 977 bytes
-rw-r--r--demos/declarative/contacts/pics/new.pngbin0 -> 688 bytes
-rw-r--r--demos/declarative/contacts/pics/ok.pngbin0 -> 655 bytes
-rw-r--r--demos/declarative/contacts/pics/phone.pngbin0 -> 624 bytes
-rw-r--r--demos/declarative/contacts/pics/search.pngbin0 -> 635 bytes
-rw-r--r--demos/declarative/contacts/pics/trash.pngbin0 -> 989 bytes
-rw-r--r--demos/declarative/flickr/common/ImageDetails.qml160
-rw-r--r--demos/declarative/flickr/common/LikeOMeter.qml35
-rw-r--r--demos/declarative/flickr/common/Loading.qml8
-rw-r--r--demos/declarative/flickr/common/MediaButton.qml41
-rw-r--r--demos/declarative/flickr/common/MediaLineEdit.qml104
-rw-r--r--demos/declarative/flickr/common/Progress.qml35
-rw-r--r--demos/declarative/flickr/common/RssModel.qml20
-rw-r--r--demos/declarative/flickr/common/ScrollBar.qml40
-rw-r--r--demos/declarative/flickr/common/Slider.qml36
-rw-r--r--demos/declarative/flickr/common/Star.qml46
-rw-r--r--demos/declarative/flickr/common/pics/background.pngbin0 -> 60504 bytes
-rw-r--r--demos/declarative/flickr/common/pics/button-pressed.pngbin0 -> 571 bytes
-rw-r--r--demos/declarative/flickr/common/pics/button-pressed.sci5
-rw-r--r--demos/declarative/flickr/common/pics/button.pngbin0 -> 564 bytes
-rw-r--r--demos/declarative/flickr/common/pics/button.sci5
-rw-r--r--demos/declarative/flickr/common/pics/ghns_star.pngbin0 -> 891 bytes
-rw-r--r--demos/declarative/flickr/common/pics/loading.pngbin0 -> 813 bytes
-rw-r--r--demos/declarative/flickr/common/pics/reflection.pngbin0 -> 4839 bytes
-rw-r--r--demos/declarative/flickr/common/pics/shadow-bottom.pngbin0 -> 656 bytes
-rw-r--r--demos/declarative/flickr/common/pics/shadow-corner.pngbin0 -> 405 bytes
-rw-r--r--demos/declarative/flickr/common/pics/shadow-right-screen.pngbin0 -> 227 bytes
-rw-r--r--demos/declarative/flickr/common/pics/shadow-right.pngbin0 -> 635 bytes
-rw-r--r--demos/declarative/flickr/flickr-desktop.qml192
-rw-r--r--demos/declarative/flickr/flickr-mobile.qml69
-rw-r--r--demos/declarative/flickr/mobile/Button.qml41
-rw-r--r--demos/declarative/flickr/mobile/GridDelegate.qml72
-rw-r--r--demos/declarative/flickr/mobile/ImageDetails.qml129
-rw-r--r--demos/declarative/flickr/mobile/ListDelegate.qml24
-rw-r--r--demos/declarative/flickr/mobile/TitleBar.qml76
-rw-r--r--demos/declarative/flickr/mobile/ToolBar.qml24
-rw-r--r--demos/declarative/flickr/mobile/images/gloss.pngbin0 -> 1236 bytes
-rw-r--r--demos/declarative/flickr/mobile/images/lineedit.pngbin0 -> 1415 bytes
-rw-r--r--demos/declarative/flickr/mobile/images/lineedit.sci5
-rw-r--r--demos/declarative/flickr/mobile/images/stripes.pngbin0 -> 257 bytes
-rw-r--r--demos/declarative/flickr/mobile/images/titlebar.pngbin0 -> 1436 bytes
-rw-r--r--demos/declarative/flickr/mobile/images/titlebar.sci5
-rw-r--r--demos/declarative/flickr/mobile/images/toolbutton.pngbin0 -> 2619 bytes
-rw-r--r--demos/declarative/flickr/mobile/images/toolbutton.sci5
-rw-r--r--demos/declarative/minehunt/Description.qml34
-rw-r--r--demos/declarative/minehunt/Explosion.qml29
-rw-r--r--demos/declarative/minehunt/main.cpp309
-rw-r--r--demos/declarative/minehunt/minehunt.pro9
-rw-r--r--demos/declarative/minehunt/minehunt.qml195
-rw-r--r--demos/declarative/minehunt/pics/No-Ones-Laughing-3.jpgbin0 -> 30730 bytes
-rw-r--r--demos/declarative/minehunt/pics/back.pngbin0 -> 558 bytes
-rw-r--r--demos/declarative/minehunt/pics/bomb-color.pngbin0 -> 284 bytes
-rw-r--r--demos/declarative/minehunt/pics/bomb.pngbin0 -> 535 bytes
-rw-r--r--demos/declarative/minehunt/pics/face-sad.pngbin0 -> 14844 bytes
-rw-r--r--demos/declarative/minehunt/pics/face-smile-big.pngbin0 -> 13810 bytes
-rw-r--r--demos/declarative/minehunt/pics/face-smile.pngbin0 -> 15408 bytes
-rw-r--r--demos/declarative/minehunt/pics/flag-color.pngbin0 -> 219 bytes
-rw-r--r--demos/declarative/minehunt/pics/flag.pngbin0 -> 196 bytes
-rw-r--r--demos/declarative/minehunt/pics/front.pngbin0 -> 580 bytes
-rw-r--r--demos/declarative/minehunt/pics/star.pngbin0 -> 2677 bytes
-rw-r--r--demos/declarative/samegame/README10
-rw-r--r--demos/declarative/samegame/SameGame.qml71
-rw-r--r--demos/declarative/samegame/content/BoomBlock.qml54
-rw-r--r--demos/declarative/samegame/content/Button.qml25
-rw-r--r--demos/declarative/samegame/content/Dialog.qml21
-rw-r--r--demos/declarative/samegame/content/pics/background.pngbin0 -> 153328 bytes
-rw-r--r--demos/declarative/samegame/content/pics/blueStar.pngbin0 -> 278 bytes
-rw-r--r--demos/declarative/samegame/content/pics/blueStone.pngbin0 -> 2691 bytes
-rw-r--r--demos/declarative/samegame/content/pics/greenStar.pngbin0 -> 273 bytes
-rw-r--r--demos/declarative/samegame/content/pics/greenStone.pngbin0 -> 2662 bytes
-rw-r--r--demos/declarative/samegame/content/pics/redStar.pngbin0 -> 274 bytes
-rw-r--r--demos/declarative/samegame/content/pics/redStone.pngbin0 -> 2604 bytes
-rw-r--r--demos/declarative/samegame/content/pics/star.pngbin0 -> 262 bytes
-rw-r--r--demos/declarative/samegame/content/pics/yellowStone.pngbin0 -> 2667 bytes
-rwxr-xr-xdemos/declarative/samegame/content/samegame.js241
-rw-r--r--demos/declarative/samegame/highscores/README1
-rwxr-xr-xdemos/declarative/samegame/highscores/score_data.xml2
-rwxr-xr-xdemos/declarative/samegame/highscores/score_style.xsl28
-rwxr-xr-xdemos/declarative/samegame/highscores/scores.php34
-rw-r--r--demos/declarative/twitter/content/AuthView.qml86
-rw-r--r--demos/declarative/twitter/content/FatDelegate.qml47
-rw-r--r--demos/declarative/twitter/content/HomeTitleBar.qml122
-rw-r--r--demos/declarative/twitter/content/MultiTitleBar.qml25
-rw-r--r--demos/declarative/twitter/content/RssModel.qml42
-rw-r--r--demos/declarative/twitter/content/UserModel.qml26
-rw-r--r--demos/declarative/twitter/twitter.qml95
-rw-r--r--demos/declarative/webbrowser/content/RectSoftShadow.qml32
-rw-r--r--demos/declarative/webbrowser/content/pics/addressbar-filled.pngbin0 -> 694 bytes
-rw-r--r--demos/declarative/webbrowser/content/pics/addressbar-filled.sci6
-rw-r--r--demos/declarative/webbrowser/content/pics/addressbar.pngbin0 -> 467 bytes
-rw-r--r--demos/declarative/webbrowser/content/pics/addressbar.sci6
-rw-r--r--demos/declarative/webbrowser/content/pics/back-disabled.pngbin0 -> 475 bytes
-rw-r--r--demos/declarative/webbrowser/content/pics/back.pngbin0 -> 707 bytes
-rw-r--r--demos/declarative/webbrowser/content/pics/footer.pngbin0 -> 200 bytes
-rw-r--r--demos/declarative/webbrowser/content/pics/footer.sci6
-rw-r--r--demos/declarative/webbrowser/content/pics/forward-disabled.pngbin0 -> 471 bytes
-rw-r--r--demos/declarative/webbrowser/content/pics/forward.pngbin0 -> 682 bytes
-rw-r--r--demos/declarative/webbrowser/content/pics/header.pngbin0 -> 193 bytes
-rw-r--r--demos/declarative/webbrowser/content/pics/reload.pngbin0 -> 1283 bytes
-rw-r--r--demos/declarative/webbrowser/content/pics/softshadow-bottom.pngbin0 -> 186 bytes
-rw-r--r--demos/declarative/webbrowser/content/pics/softshadow-left.pngbin0 -> 598 bytes
-rw-r--r--demos/declarative/webbrowser/content/pics/softshadow-left.sci5
-rw-r--r--demos/declarative/webbrowser/content/pics/softshadow-right.pngbin0 -> 636 bytes
-rw-r--r--demos/declarative/webbrowser/content/pics/softshadow-right.sci5
-rw-r--r--demos/declarative/webbrowser/content/pics/softshadow-top.pngbin0 -> 186 bytes
-rw-r--r--demos/declarative/webbrowser/fieldtext/FieldText.qml163
-rw-r--r--demos/declarative/webbrowser/fieldtext/pics/cancel.pngbin0 -> 1038 bytes
-rw-r--r--demos/declarative/webbrowser/fieldtext/pics/ok.pngbin0 -> 655 bytes
-rw-r--r--demos/declarative/webbrowser/webbrowser.qml413
121 files changed, 4435 insertions, 0 deletions
diff --git a/demos/declarative/calculator/CalcButton.qml b/demos/declarative/calculator/CalcButton.qml
new file mode 100644
index 0000000..966c8e4
--- /dev/null
+++ b/demos/declarative/calculator/CalcButton.qml
@@ -0,0 +1,41 @@
+import Qt 4.6
+
+Rectangle {
+ property string operation
+ property bool toggable : false
+ property bool toggled : false
+ signal clicked
+
+ id: Button; width: 50; height: 30
+ border.color: Palette.mid; radius: 6
+ gradient: Gradient {
+ GradientStop { id: G1; position: 0.0; color: Palette.lighter(Palette.button) }
+ GradientStop { id: G2; position: 1.0; color: Palette.button }
+ }
+
+ Text { anchors.centerIn: parent; text: operation; color: Palette.buttonText }
+
+ MouseRegion {
+ id: ClickRegion
+ anchors.fill: parent
+ onClicked: {
+ doOp(operation);
+ Button.clicked();
+ if (!Button.toggable) return;
+ Button.toggled ? Button.toggled = false : Button.toggled = true
+ }
+ }
+
+ states: [
+ State {
+ name: "Pressed"; when: ClickRegion.pressed == true
+ PropertyChanges { target: G1; color: Palette.dark }
+ PropertyChanges { target: G2; color: Palette.button }
+ },
+ State {
+ name: "Toggled"; when: Button.toggled == true
+ PropertyChanges { target: G1; color: Palette.dark }
+ PropertyChanges { target: G2; color: Palette.button }
+ }
+ ]
+}
diff --git a/demos/declarative/calculator/calculator.js b/demos/declarative/calculator/calculator.js
new file mode 100644
index 0000000..774b232
--- /dev/null
+++ b/demos/declarative/calculator/calculator.js
@@ -0,0 +1,87 @@
+
+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 == "/") {
+ CurNum.text = Number(Number(curVal) / Number(CurNum.text.valueOf())).toString();
+ } else if (CurrentOperation.text == "=") {
+ }
+
+ if (op == "+" || op == "-" || op == "x" || 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 == "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";
+ }
+}
+
diff --git a/demos/declarative/calculator/calculator.qml b/demos/declarative/calculator/calculator.qml
new file mode 100644
index 0000000..b95cc7ab
--- /dev/null
+++ b/demos/declarative/calculator/calculator.qml
@@ -0,0 +1,130 @@
+import Qt 4.6
+
+Rectangle {
+ id: MainWindow;
+ width: 320; height: 270; color: Palette.window
+
+ SystemPalette { id: Palette; colorGroup: Qt.Active }
+ Script { source: "calculator.js" }
+
+ Column {
+ x: 2; spacing: 10;
+
+ Rectangle {
+ id: Container
+ width: 316; height: 50; z: 2
+ border.color: Palette.dark; color: Palette.base
+
+ Text {
+ id: CurNum
+ font.bold: true; font.pointSize: 16
+ 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: 16
+ anchors.left: Container.left
+ anchors.leftMargin: 5
+ anchors.verticalCenter: Container.verticalCenter
+ }
+ }
+
+ Item {
+ width: 320; height: 30
+
+ CalcButton {
+ id: AdvancedCheckBox
+ x: 55; width: 206
+ operation: "Advanced Mode"
+ toggable: true
+ }
+ }
+
+ Item {
+ width: 320
+
+ Item {
+ id: BasicButtons
+ x: 55; width: 160; height: 160
+
+ CalcButton { operation: "Bksp"; id: Bksp; width: 67; opacity: 0 }
+ CalcButton { operation: "C"; id: C; width: 76 }
+ CalcButton { operation: "AC"; id: AC; x: 78; width: 76 }
+
+ Grid {
+ id: NumKeypad; y: 32; spacing: 2; 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" }
+ }
+
+ Row {
+ y: 128; spacing: 2
+
+ CalcButton { operation: "0"; width: 50 }
+ CalcButton { operation: "."; x: 77; width: 50 }
+ CalcButton { operation: "="; id: Equals; x: 77; width: 102 }
+ }
+
+ Column {
+ id: SimpleOperations
+ x: 156; y: 0; spacing: 2
+
+ CalcButton { operation: "x" }
+ CalcButton { operation: "/" }
+ CalcButton { operation: "-" }
+ CalcButton { operation: "+" }
+ }
+ }
+
+ Grid {
+ id: AdvancedButtons
+ x: 350; spacing: 2; 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: "+/-" }
+ }
+
+ }
+ }
+
+ states: [
+ State {
+ name: "Advanced"; when: AdvancedCheckBox.toggled == true
+ PropertyChanges { target: BasicButtons; x: 0 }
+ PropertyChanges { target: SimpleOperations; y: 32 }
+ PropertyChanges { target: Bksp; opacity: 1 }
+ PropertyChanges { target: C; x: 69; width: 67 }
+ PropertyChanges { target: AC; x: 138; width: 67 }
+ PropertyChanges { target: Equals; width: 50 }
+ PropertyChanges { target: AdvancedButtons; x: 210; opacity: 1 }
+ }
+ ]
+
+ transitions: [
+ Transition {
+ NumberAnimation { properties: "x,y,width"; easing: "easeOutBounce"; duration: 500 }
+ NumberAnimation { properties: "opacity"; easing: "easeInOutQuad"; duration: 500 }
+ }
+ ]
+}
diff --git a/demos/declarative/contacts/Button.qml b/demos/declarative/contacts/Button.qml
new file mode 100644
index 0000000..9719231
--- /dev/null
+++ b/demos/declarative/contacts/Button.qml
@@ -0,0 +1,60 @@
+import Qt 4.6
+
+Item {
+ id: button
+ width: 30
+ height: 30
+ property var icon: ""
+ signal clicked
+ Rectangle {
+ id: buttonRect
+ anchors.fill: parent
+ color: "lightgreen"
+ radius: 5
+ Image {
+ id: iconImage
+ source: button.icon
+ anchors.horizontalCenter: buttonRect.horizontalCenter
+ anchors.verticalCenter: buttonRect.verticalCenter
+ }
+ MouseRegion {
+ id: buttonMouseRegion
+ anchors.fill: buttonRect
+ onClicked: { button.clicked() }
+ }
+ states: [
+ State {
+ name: "pressed"
+ when: buttonMouseRegion.pressed == true
+ PropertyChanges {
+ target: buttonRect
+ color: "green"
+ }
+ }
+ ]
+ transitions: [
+ Transition {
+ from: "*"
+ to: "pressed"
+ ColorAnimation {
+ property: "color"
+ duration: 200
+ }
+ },
+ Transition {
+ from: "pressed"
+ to: "*"
+ ColorAnimation {
+ property: "color"
+ duration: 1000
+ }
+ }
+ ]
+ }
+ opacity: Behavior {
+ NumberAnimation {
+ property: "opacity"
+ duration: 250
+ }
+ }
+}
diff --git a/demos/declarative/contacts/Contact.qml b/demos/declarative/contacts/Contact.qml
new file mode 100644
index 0000000..91510c7
--- /dev/null
+++ b/demos/declarative/contacts/Contact.qml
@@ -0,0 +1,116 @@
+import Qt 4.6
+
+Item {
+ id: contactDetails
+ anchors.fill: parent
+
+ property var contactId: ""
+ property var label: ""
+ property var phone: ""
+ property var email: ""
+
+ onLabelChanged: { labelField.value = label }
+ onEmailChanged: { emailField.value = email }
+ onPhoneChanged: { phoneField.value = phone }
+
+ resources: [
+ SqlQuery {
+ id: updateContactQuery
+ connection: contactDatabase
+ query: "UPDATE contacts SET label = :l, email = :e, phone = :p WHERE recid = :r"
+ bindings: [
+ SqlBind {
+ name: ":r"
+ value: contactId
+ },
+ SqlBind {
+ name: ":l"
+ value: labelField.value
+ },
+ SqlBind {
+ name: ":e"
+ value: emailField.value
+ },
+ SqlBind {
+ name: ":p"
+ value: phoneField.value
+ }
+ ]
+ },
+ SqlQuery {
+ id: insertContactQuery
+ connection: contactDatabase
+ query: "INSERT INTO contacts (label, email, phone) VALUES(:l, :e, :p)"
+ bindings: [
+ SqlBind {
+ name: ":l"
+ value: labelField.value
+ },
+ SqlBind {
+ name: ":e"
+ value: emailField.value
+ },
+ SqlBind {
+ name: ":p"
+ value: phoneField.value
+ }
+ ]
+ },
+ SqlQuery {
+ id: removeContactQuery
+ connection: contactDatabase
+ query: "DELETE FROM contacts WHERE recid = :r"
+ bindings: SqlBind {
+ name: ":r"
+ value: contactId
+ }
+ }
+ ]
+ function refresh() {
+ labelField.value = label;
+ emailField.value = email;
+ phoneField.value = phone;
+ }
+ function update() {
+ updateContactQuery.exec();
+ }
+ function insert() {
+ insertContactQuery.exec();
+ }
+ function remove() {
+ removeContactQuery.exec();
+ }
+ Column {
+ id: layout
+ width: contents.width
+ height:contents.height
+ anchors.centerIn: parent
+ spacing: 5
+ ContactField {
+ id: labelField
+ anchors.left: layout.left
+ anchors.leftMargin: 5
+ anchors.right: layout.right
+ anchors.rightMargin: 5
+ label: "Name"
+ }
+ ContactField {
+ id: phoneField
+ anchors.left: layout.left
+ anchors.leftMargin: 5
+ anchors.right: layout.right
+ anchors.rightMargin: 5
+ icon: "pics/phone.png"
+ label: "Phone"
+ }
+ ContactField {
+ id: emailField
+ anchors.left: layout.left
+ anchors.leftMargin: 5
+ anchors.right: layout.right
+ anchors.rightMargin: 5
+ icon: "pics/email.png"
+ label: "Email"
+ }
+ }
+}
diff --git a/demos/declarative/contacts/ContactField.qml b/demos/declarative/contacts/ContactField.qml
new file mode 100644
index 0000000..6cf7baa
--- /dev/null
+++ b/demos/declarative/contacts/ContactField.qml
@@ -0,0 +1,60 @@
+import Qt 4.6
+
+Item {
+ id: contactField
+ clip: true
+ height: 30
+ property var label: "Name"
+ property var icon: ""
+ property var value: ""
+ onValueChanged: { fieldText.text = contactField.value }
+ RemoveButton {
+ id: removeButton
+ anchors.right: parent.right
+ anchors.top: parent.top
+ anchors.bottom: parent.bottom
+ expandedWidth: contactField.width
+ onConfirmed: { print('Clear field text'); fieldText.text='' }
+ }
+ FieldText {
+ id: fieldText
+ width: contactField.width-70
+ anchors.right: removeButton.left
+ anchors.rightMargin: 5
+ anchors.verticalCenter: parent.verticalCenter
+ label: contactField.label
+ text: contactField.value
+ onConfirmed: { contactField.value=fieldText.text }
+ }
+ Image {
+ anchors.right: fieldText.left
+ anchors.rightMargin: 5
+ anchors.verticalCenter: parent.verticalCenter
+ source: contactField.icon
+ }
+ states: [
+ State {
+ name: "editingText"
+ when: fieldText.state == 'editing'
+ PropertyChanges {
+ target: removeButton.anchors
+ rightMargin: -35
+ }
+ PropertyChanges {
+ target: fieldText
+ width: contactField.width
+ }
+ }
+ ]
+ transitions: [
+ Transition {
+ from: ""
+ to: "*"
+ reversible: true
+ NumberAnimation {
+ properties: "width,rightMargin"
+ duration: 200
+ }
+ }
+ ]
+}
diff --git a/demos/declarative/contacts/FieldText.qml b/demos/declarative/contacts/FieldText.qml
new file mode 100644
index 0000000..d30d4d8
--- /dev/null
+++ b/demos/declarative/contacts/FieldText.qml
@@ -0,0 +1,154 @@
+import Qt 4.6
+
+Rectangle {
+ id: fieldText
+ height: 30
+ radius: 5
+ color: "black"
+ property var text: ""
+ property var label: ""
+ onTextChanged: { reset() }
+ signal confirmed
+ resources: [
+ Script {
+
+ function edit() {
+ if (!contacts.mouseGrabbed) {
+ fieldText.state='editing';
+ contacts.mouseGrabbed=true;
+ }
+ }
+ function confirm() {
+ fieldText.text = textEdit.text;
+ fieldText.state='';
+ contacts.mouseGrabbed=false;
+ fieldText.confirmed();
+ }
+ function reset() {
+ textEdit.text = fieldText.text;
+ fieldText.state='';
+ contacts.mouseGrabbed=false;
+ }
+
+ }
+ ]
+ Image {
+ id: cancelIcon
+ width: 22
+ height: 22
+ anchors.right: parent.right
+ anchors.rightMargin: 4
+ anchors.verticalCenter: parent.verticalCenter
+ source: "pics/cancel.png"
+ opacity: 0
+ }
+ Image {
+ id: confirmIcon
+ width: 22
+ height: 22
+ anchors.left: parent.left
+ anchors.leftMargin: 4
+ anchors.verticalCenter: parent.verticalCenter
+ source: "pics/ok.png"
+ opacity: 0
+ }
+ TextEdit {
+ id: textEdit
+ anchors.left: parent.left
+ anchors.leftMargin: 0
+ anchors.right: parent.right
+ anchors.rightMargin: 0
+ anchors.verticalCenter: parent.verticalCenter
+ color: "white"
+ font.bold: true
+ readOnly: true
+ wrap: false
+ }
+ Text {
+ id: textLabel
+ x: 5
+ width: parent.width-10
+ anchors.verticalCenter: parent.verticalCenter
+ horizontalAlignment: "AlignHCenter"
+ color: contactDetails.state == "editing" ? "#505050" : "#AAAAAA"
+ font.italic: true
+ font.bold: true
+ text: fieldText.label
+ opacity: textEdit.text == '' ? 1 : 0
+ opacity: Behavior {
+ NumberAnimation {
+ property: "opacity"
+ duration: 250
+ }
+ }
+ }
+ MouseRegion {
+ anchors.fill: cancelIcon
+ onClicked: { reset() }
+ }
+ MouseRegion {
+ anchors.fill: confirmIcon
+ onClicked: { confirm() }
+ }
+ MouseRegion {
+ id: editRegion
+ anchors.fill: textEdit
+ onClicked: { edit() }
+ }
+ states: [
+ State {
+ name: "editing"
+ PropertyChanges {
+ target: confirmIcon
+ opacity: 1
+ }
+ PropertyChanges {
+ target: cancelIcon
+ opacity: 1
+ }
+ PropertyChanges {
+ target: fieldText
+ color: "white"
+ }
+ PropertyChanges {
+ target: textEdit
+ color: "black"
+ }
+ PropertyChanges {
+ target: textEdit
+ readOnly: false
+ }
+ PropertyChanges {
+ target: textEdit
+ focus: true
+ }
+ PropertyChanges {
+ target: editRegion
+ opacity: 0
+ }
+ PropertyChanges {
+ target: textEdit.anchors
+ leftMargin: 34
+ }
+ PropertyChanges {
+ target: textEdit.anchors
+ rightMargin: 34
+ }
+ }
+ ]
+ transitions: [
+ Transition {
+ from: ""
+ to: "*"
+ reversible: true
+ NumberAnimation {
+ properties: "opacity,leftMargin,rightMargin"
+ duration: 200
+ }
+ ColorAnimation {
+ property: "color"
+ duration: 150
+ }
+ }
+ ]
+}
diff --git a/demos/declarative/contacts/RemoveButton.qml b/demos/declarative/contacts/RemoveButton.qml
new file mode 100644
index 0000000..cc858c3
--- /dev/null
+++ b/demos/declarative/contacts/RemoveButton.qml
@@ -0,0 +1,123 @@
+import Qt 4.6
+
+Rectangle {
+ id: removeButton
+ width: 30
+ height: 30
+ color: "red"
+ radius: 5
+ property var expandedWidth: 230
+ signal confirmed
+ resources: [
+ Script {
+ function toggle() {
+ if (removeButton.state == 'opened') {
+ removeButton.state = '';
+ contacts.mouseGrabbed=false;
+ } else {
+ if (!contacts.mouseGrabbed) {
+ removeButton.state = 'opened';
+ contacts.mouseGrabbed=true;
+ }
+ }
+ }
+ }
+ ]
+ Image {
+ id: trashIcon
+ width: 22
+ height: 22
+ anchors.right: parent.right
+ anchors.rightMargin: 4
+ anchors.verticalCenter: parent.verticalCenter
+ source: "pics/trash.png"
+ opacity: 1
+ MouseRegion {
+ anchors.fill: parent
+ onClicked: { toggle() }
+ }
+ }
+ Image {
+ id: cancelIcon
+ width: 22
+ height: 22
+ anchors.right: parent.right
+ anchors.rightMargin: 4
+ anchors.verticalCenter: parent.verticalCenter
+ source: "pics/cancel.png"
+ opacity: 0
+ MouseRegion {
+ anchors.fill: parent
+ onClicked: { toggle() }
+ }
+ }
+ Image {
+ id: confirmIcon
+ width: 22
+ height: 22
+ anchors.left: parent.left
+ anchors.leftMargin: 4
+ anchors.verticalCenter: parent.verticalCenter
+ source: "pics/ok.png"
+ opacity: 0
+ MouseRegion {
+ anchors.fill: parent
+ onClicked: { toggle(); removeButton.confirmed() }
+ }
+ }
+ Text {
+ id: text
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.left: confirmIcon.right
+ anchors.leftMargin: 4
+ anchors.right: cancelIcon.left
+ anchors.rightMargin: 4
+ font.bold: true
+ color: "white"
+ horizontalAlignment: "AlignHCenter"
+ text: "Remove"
+ opacity: 0
+ }
+ opacity: Behavior {
+ NumberAnimation {
+ property: "opacity"
+ duration: 250
+ }
+ }
+ states: [
+ State {
+ name: "opened"
+ PropertyChanges {
+ target: removeButton
+ width: removeButton.expandedWidth
+ }
+ PropertyChanges {
+ target: text
+ opacity: 1
+ }
+ PropertyChanges {
+ target: confirmIcon
+ opacity: 1
+ }
+ PropertyChanges {
+ target: cancelIcon
+ opacity: 1
+ }
+ PropertyChanges {
+ target: trashIcon
+ opacity: 0
+ }
+ }
+ ]
+ transitions: [
+ Transition {
+ from: "*"
+ to: "opened"
+ reversible: true
+ NumberAnimation {
+ properties: "opacity,x,width"
+ duration: 200
+ }
+ }
+ ]
+}
diff --git a/demos/declarative/contacts/SearchBar.qml b/demos/declarative/contacts/SearchBar.qml
new file mode 100644
index 0000000..b326fd3
--- /dev/null
+++ b/demos/declarative/contacts/SearchBar.qml
@@ -0,0 +1,26 @@
+import Qt 4.6
+
+Rectangle {
+ id: searchBar
+ color: "white"
+ property var text: searchEdit.text
+ Image {
+ id: searchIcon
+ anchors.left: parent.left
+ anchors.leftMargin: 5
+ anchors.verticalCenter: parent.verticalCenter
+ source: "pics/search.png"
+ }
+ TextEdit {
+ id: searchEdit
+ anchors.left: searchIcon.right
+ anchors.right: parent.right
+ anchors.leftMargin: 5
+ anchors.rightMargin: 5
+ anchors.verticalCenter: parent.verticalCenter
+ readOnly: false
+ wrap: false
+ focus: true
+ text: ""
+ }
+}
diff --git a/demos/declarative/contacts/contacts.qml b/demos/declarative/contacts/contacts.qml
new file mode 100644
index 0000000..278eeb3
--- /dev/null
+++ b/demos/declarative/contacts/contacts.qml
@@ -0,0 +1,319 @@
+import Qt 4.6
+
+Rectangle {
+ id: contacts
+ width: 240
+ height: 320
+ color: "black"
+ property var mode: "list"
+ property var mouseGrabbed: false
+ resources: [
+ SqlConnection {
+ id: contactDatabase
+ name: "qmlConnection"
+ driver: "QSQLITE"
+ databaseName: "contacts.sqlite"
+ },
+ SqlQuery {
+ id: contactList
+ connection: contactDatabase
+ query: "SELECT recid, label, email, phone FROM contacts WHERE lower(label) LIKE lower(:searchTerm) ORDER BY label, recid"
+ bindings: SqlBind {
+ name: ":searchTerm"
+ value: '%' + searchBar.text + '%'
+ }
+ },
+ Component {
+ id: contactDelegate
+ Item {
+ id: wrapper
+ x: 0
+ width: ListView.view.width
+ height: 34
+ Text {
+ id: label
+ x: 40
+ y: 12
+ width: parent.width-30
+ text: model.label
+ color: "white"
+ font.bold: true
+ children: [
+ MouseRegion {
+ anchors.fill: parent
+ onClicked: {
+ Details.source = 'Contact.qml';
+ wrapper.state ='opened';
+ contacts.mode = 'edit';
+ }
+ }
+ ]
+ states: [
+ State {
+ name: "currentItem"
+ when: wrapper.ListView.isCurrentItem
+ PropertyChanges {
+ target: label
+ color: "black"
+ }
+ }
+ ]
+ transitions: [
+ Transition {
+ ColorAnimation {
+ duration: 250
+ property: "color"
+ }
+ }
+ ]
+ }
+ Loader {
+ id: Details
+ anchors.fill: wrapper
+ opacity: 0
+ Binding {
+ target: Details.item
+ property: "contactId"
+ value: model.recid
+ }
+ Binding {
+ target: Details.item
+ property: "label"
+ value: model.label
+ }
+ Binding {
+ target: Details.item
+ property: "phone"
+ value: model.phone
+ }
+ Binding {
+ target: Details.item
+ property: "email"
+ value: model.email
+ }
+ }
+ states: [
+ State {
+ name: "opened"
+ PropertyChanges {
+ target: wrapper
+ height: contactListView.height
+ }
+ PropertyChanges {
+ target: contactListView
+ viewportY: wrapper.y
+ }
+ PropertyChanges {
+ target: contactListView
+ interactive: 0
+ }
+ PropertyChanges {
+ target: label
+ opacity: 0
+ }
+ PropertyChanges {
+ target: Details
+ opacity: 1
+ }
+ }
+ ]
+ transitions: [
+ Transition {
+ NumberAnimation {
+ duration: 500
+ properties: "viewportY,height,opacity"
+ }
+ }
+ ]
+ Connection {
+ sender: confirmEditButton
+ signal: "clicked()"
+ script: {
+ if (wrapper.state == 'opened' && !contacts.mouseGrabbed) {
+ Details.item.update();
+ wrapper.state = '';
+ contacts.mode = 'list';
+ contactList.exec();
+ }
+
+ }
+ }
+ Connection {
+ sender: cancelEditButton
+ signal: "clicked()"
+ script: {
+ if (wrapper.state == 'opened' && !contacts.mouseGrabbed) {
+ wrapper.state = '';
+ contacts.mode = 'list';
+ }
+
+ }
+ }
+ Connection {
+ sender: removeContactButton
+ signal: "confirmed()"
+ script: {
+ if (wrapper.state == 'opened' && !contacts.mouseGrabbed) {
+ Details.item.remove();
+ wrapper.state = '';
+ contacts.mode = 'list';
+ contactList.exec();
+ }
+
+ }
+ }
+ }
+ }
+ ]
+ Button {
+ id: newContactButton
+ anchors.top: parent.top
+ anchors.topMargin: 5
+ anchors.right: parent.right
+ anchors.rightMargin: 5
+ icon: "pics/new.png"
+ onClicked: { newContactItem.refresh(); contacts.mode = 'new' }
+ opacity: contacts.mode == 'list' ? 1 : 0
+ }
+ Button {
+ id: confirmEditButton
+ anchors.top: parent.top
+ anchors.topMargin: 5
+ anchors.left: parent.left
+ anchors.leftMargin: 5
+ icon: "pics/ok.png"
+ opacity: contacts.mode == 'list' || contacts.mouseGrabbed ? 0 : 1
+ }
+ Button {
+ id: cancelEditButton
+ anchors.top: parent.top
+ anchors.topMargin: 5
+ anchors.right: parent.right
+ anchors.rightMargin: 5
+ icon: "pics/cancel.png"
+ opacity: contacts.mode == 'list' || contacts.mouseGrabbed ? 0 : 1
+ }
+ RemoveButton {
+ id: removeContactButton
+ anchors.top: parent.top
+ anchors.topMargin: 5
+ anchors.horizontalCenter: parent.horizontalCenter
+ opacity: (contacts.mode == 'edit' && (!contacts.mouseGrabbed || removeContactButton.state =='opened')) ? 1 : 0
+ }
+ ListView {
+ id: contactListView
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.top: cancelEditButton.bottom
+ anchors.bottom: searchBarWrapper.top
+ anchors.topMargin: 5
+ clip: true
+ model: contactList
+ delegate: contactDelegate
+ highlight: [
+ Rectangle {
+ id: contactHighlight
+ border.width: 0
+ color: 'white'
+ opacity: contacts.mode == 'list' ? 1 : 0
+ opacity: Behavior {
+ NumberAnimation {
+ property: "opacity"
+ duration: 250
+ }
+ }
+ }
+ ]
+ autoHighlight: true
+ focus: false
+ }
+ FocusScope {
+ id: newContactWrapper
+ anchors.fill: contactListView
+ opacity: 0
+ focus: contacts.mode == 'new'
+ Contact {
+ id: newContactItem
+ anchors.fill: parent
+ }
+ }
+ Connection {
+ sender: confirmEditButton
+ signal: "clicked()"
+ script: {
+ if (contacts.mode == 'new' && contacts.mouseGrabbed != 'true') {
+ newContactItem.insert();
+ contacts.mode = 'list';
+ contactList.exec();
+ }
+ }
+ }
+ Connection {
+ sender: cancelEditButton
+ signal: "clicked()"
+ script: {
+ if (contacts.mode == 'new' && contacts.mouseGrabbed != 'true') {
+ contacts.mode = 'list';
+ }
+ }
+ }
+ FocusScope {
+ id: searchBarWrapper
+ height: 30
+ anchors.bottom: parent.bottom
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.bottomMargin: 0
+ focus: false
+ SearchBar {
+ id: searchBar
+ anchors.fill: parent
+ }
+ states: [
+ State {
+ name: "searchHidden"
+ when: searchBar.text == '' || contacts.mode != 'list'
+ PropertyChanges {
+ target: searchBarWrapper.anchors
+ bottomMargin: -30
+ }
+ }
+ ]
+ transitions: [
+ Transition {
+ from: "*"
+ to: "*"
+ NumberAnimation {
+ property: "bottomMargin"
+ duration: 250
+ }
+ }
+ ]
+ }
+ focus: contacts.mode != 'new'
+ forwardTo: { contacts.mode == "list" ? [searchBarWrapper, contactListView] : [contactListView]}
+ states: [
+ State {
+ name: "editNewState"
+ when: contacts.mode == 'new'
+ PropertyChanges {
+ target: contactListView
+ opacity: 0
+ }
+ PropertyChanges {
+ target: newContactWrapper
+ opacity: 1
+ }
+ }
+ ]
+ transitions: [
+ Transition {
+ from: "*"
+ to: "*"
+ NumberAnimation {
+ property: "opacity"
+ duration: 500
+ }
+ }
+ ]
+}
diff --git a/demos/declarative/contacts/contacts.sqlite b/demos/declarative/contacts/contacts.sqlite
new file mode 100644
index 0000000..d33e0c7
--- /dev/null
+++ b/demos/declarative/contacts/contacts.sqlite
Binary files differ
diff --git a/demos/declarative/contacts/pics/cancel.png b/demos/declarative/contacts/pics/cancel.png
new file mode 100644
index 0000000..ecc9533
--- /dev/null
+++ b/demos/declarative/contacts/pics/cancel.png
Binary files differ
diff --git a/demos/declarative/contacts/pics/email.png b/demos/declarative/contacts/pics/email.png
new file mode 100644
index 0000000..04b3865
--- /dev/null
+++ b/demos/declarative/contacts/pics/email.png
Binary files differ
diff --git a/demos/declarative/contacts/pics/new.png b/demos/declarative/contacts/pics/new.png
new file mode 100644
index 0000000..c7ebac3
--- /dev/null
+++ b/demos/declarative/contacts/pics/new.png
Binary files differ
diff --git a/demos/declarative/contacts/pics/ok.png b/demos/declarative/contacts/pics/ok.png
new file mode 100644
index 0000000..5795f04
--- /dev/null
+++ b/demos/declarative/contacts/pics/ok.png
Binary files differ
diff --git a/demos/declarative/contacts/pics/phone.png b/demos/declarative/contacts/pics/phone.png
new file mode 100644
index 0000000..fc9c222
--- /dev/null
+++ b/demos/declarative/contacts/pics/phone.png
Binary files differ
diff --git a/demos/declarative/contacts/pics/search.png b/demos/declarative/contacts/pics/search.png
new file mode 100644
index 0000000..cc74e69
--- /dev/null
+++ b/demos/declarative/contacts/pics/search.png
Binary files differ
diff --git a/demos/declarative/contacts/pics/trash.png b/demos/declarative/contacts/pics/trash.png
new file mode 100644
index 0000000..2042595
--- /dev/null
+++ b/demos/declarative/contacts/pics/trash.png
Binary files differ
diff --git a/demos/declarative/flickr/common/ImageDetails.qml b/demos/declarative/flickr/common/ImageDetails.qml
new file mode 100644
index 0000000..6b42910
--- /dev/null
+++ b/demos/declarative/flickr/common/ImageDetails.qml
@@ -0,0 +1,160 @@
+import Qt 4.6
+
+Flipable {
+ id: Container
+
+ property var frontContainer: ContainerFront
+ property string photoTitle: ""
+ property string photoDescription: ""
+ property string photoTags: ""
+ property int photoWidth
+ property int photoHeight
+ property string photoType
+ property string photoAuthor
+ property string photoDate
+ property string photoUrl
+ property int rating: 2
+ property var prevScale: 1.0
+
+ signal closed
+
+ transform: Rotation {
+ id: DetailsRotation
+ origin.x: Container.width / 2;
+ axis.y: 1; axis.z: 0
+ }
+
+ front: Item {
+ id: ContainerFront; anchors.fill: Container
+
+ Rectangle {
+ anchors.fill: parent
+ color: "black"; opacity: 0.4
+ border.color: "white"; border.width: 2
+ }
+
+ MediaButton {
+ id: BackButton; x: 630; y: 370; text: "Back"
+ onClicked: { Container.closed() }
+ }
+
+ MediaButton {
+ id: MoreButton; x: 530; y: 370; text: "View..."
+ onClicked: { Container.state='Back' }
+ }
+
+ Text { id: TitleText; style: "Raised"; styleColor: "black"; color: "white"; elide: "ElideRight"
+ x: 220; y: 30; width: parent.width - 240; text: Container.photoTitle; font.pointSize: 22 }
+
+ LikeOMeter { x: 40; y: 250; rating: Container.rating }
+
+ Flickable { id: FlickSurface; x: 220; width: 480; height: 210; y: 130; clip: true
+ viewportWidth: 480; viewportHeight: DescriptionText.height
+
+ WebView { id: DescriptionText; width: parent.width
+ html: "<style TYPE=\"text/css\">body {color: white;} a:link {color: cyan; text-decoration: underline; }</style>" + Container.photoDescription }
+ }
+
+ Text { id: Size; color: "white"; width: 300; x: 40; y: 300
+ text: "<b>Size:</b> " + Container.photoWidth + 'x' + Container.photoHeight }
+ Text { id: Type; color: "white"; width: 300; x: 40; anchors.top: Size.bottom
+ text: "<b>Type:</b> " + Container.photoType }
+
+ Text { id: Author; color: "white"; width: 300; x: 220; y: 80
+ text: "<b>Author:</b> " + Container.photoAuthor }
+ Text { id: Date; color: "white"; width: 300; x: 220; anchors.top: Author.bottom
+ text: "<b>Published:</b> " + Container.photoDate }
+ Text { id: TagsLabel; color: "white"; x: 220; anchors.top: Date.bottom;
+ text: Container.photoTags == "" ? "" : "<b>Tags:</b> " }
+ Text { id: Tags; color: "white"; width: parent.width-x-20;
+ anchors.left: TagsLabel.right; anchors.top: Date.bottom;
+ elide: "ElideRight"; text: Container.photoTags }
+
+ ScrollBar { id: ScrollBar; x: 720; y: FlickSurface.y; width: 7; height: FlickSurface.height; opacity: 0;
+ flickableArea: FlickSurface; clip: true }
+ }
+
+ back: Item {
+ anchors.fill: Container
+
+ Rectangle { anchors.fill: parent; color: "black"; opacity: 0.4; border.color: "white"; border.width: 2 }
+
+ Progress { anchors.centerIn: parent; width: 200; height: 18; progress: BigImage.progress; visible: BigImage.status!=1 }
+ Flickable {
+ id: Flick; width: Container.width - 10; height: Container.height - 10
+ x: 5; y: 5; clip: true;
+ viewportWidth: ImageContainer.width; viewportHeight: ImageContainer.height
+
+ Item {
+ id: ImageContainer
+ width: Math.max(BigImage.width * BigImage.scale, Flick.width);
+ height: Math.max(BigImage.height * BigImage.scale, Flick.height);
+
+ Image {
+ id: BigImage; source: Container.photoUrl; scale: Slider.value
+ // Center image if it is smaller than the flickable area.
+ x: ImageContainer.width > width*scale ? (ImageContainer.width - width*scale) / 2 : 0
+ y: ImageContainer.height > height*scale ? (ImageContainer.height - height*scale) / 2 : 0
+ smooth: !Flick.moving
+ onStatusChanged : {
+ // Default scale shows the entire image.
+ if (status == 1 && width != 0) {
+ Slider.minimum = Math.min(Flick.width / width, Flick.height / height);
+ prevScale = Math.min(Slider.minimum, 1);
+ Slider.value = prevScale;
+ }
+ }
+ }
+ }
+ }
+
+ MediaButton {
+ id: BackButton2; x: 630; y: 370; text: "Back"; onClicked: { Container.state = '' }
+ }
+ Text {
+ text: "Image Unavailable"
+ visible: BigImage.status == 'Error'
+ anchors.centerIn: parent; color: "white"; font.bold: true
+ }
+
+ Slider {
+ id: Slider; x: 25; y: 374; visible: { BigImage.status == 1 && maximum > minimum }
+ onValueChanged: {
+ if (BigImage.width * value > Flick.width) {
+ var xoff = (Flick.width/2 + Flick.viewportX) * value / prevScale;
+ Flick.viewportX = xoff - Flick.width/2;
+ }
+ if (BigImage.height * value > Flick.height) {
+ var yoff = (Flick.height/2 + Flick.viewportY) * value / prevScale;
+ Flick.viewportY = yoff - Flick.height/2;
+ }
+ prevScale = value;
+ }
+ }
+ }
+
+ states: [
+ State {
+ name: "Back"
+ PropertyChanges { target: DetailsRotation; angle: 180 }
+ }
+ ]
+
+ transitions: [
+ Transition {
+ SequentialAnimation {
+ PropertyAction {
+ target: BigImage
+ property: "smooth"
+ value: false
+ }
+ NumberAnimation { easing: "easeInOutQuad"; properties: "angle"; duration: 500 }
+ PropertyAction {
+ target: BigImage
+ property: "smooth"
+ value: !Flick.moving
+ }
+ }
+ }
+ ]
+}
diff --git a/demos/declarative/flickr/common/LikeOMeter.qml b/demos/declarative/flickr/common/LikeOMeter.qml
new file mode 100644
index 0000000..754dbb1
--- /dev/null
+++ b/demos/declarative/flickr/common/LikeOMeter.qml
@@ -0,0 +1,35 @@
+import Qt 4.6
+
+Item {
+ id: Container
+
+ property int rating: 2
+
+ Row {
+ Star {
+ rating: 0
+ onClicked: { Container.rating = rating }
+ on: Container.rating >= 0
+ }
+ Star {
+ rating: 1
+ onClicked: { Container.rating = rating }
+ on: Container.rating >= 1
+ }
+ Star {
+ rating: 2
+ onClicked: { Container.rating = rating }
+ on: Container.rating >= 2
+ }
+ Star {
+ rating: 3
+ onClicked: { Container.rating = rating }
+ on: Container.rating >= 3
+ }
+ Star {
+ rating: 4
+ onClicked: { Container.rating = rating }
+ on: Container.rating >= 4
+ }
+ }
+}
diff --git a/demos/declarative/flickr/common/Loading.qml b/demos/declarative/flickr/common/Loading.qml
new file mode 100644
index 0000000..ff2c829
--- /dev/null
+++ b/demos/declarative/flickr/common/Loading.qml
@@ -0,0 +1,8 @@
+import Qt 4.6
+
+Image {
+ id: Loading; source: "pics/loading.png"; transformOrigin: "Center"
+ rotation: NumberAnimation {
+ id: "RotationAnimation"; from: 0; to: 360; running: Loading.visible == true; repeat: true; duration: 900
+ }
+}
diff --git a/demos/declarative/flickr/common/MediaButton.qml b/demos/declarative/flickr/common/MediaButton.qml
new file mode 100644
index 0000000..e1e09e8
--- /dev/null
+++ b/demos/declarative/flickr/common/MediaButton.qml
@@ -0,0 +1,41 @@
+import Qt 4.6
+
+Item {
+ id: Container
+
+ signal clicked
+
+ property string text
+
+ Image {
+ id: ButtonImage
+ source: "pics/button.png"
+ }
+ Image {
+ id: Pressed
+ source: "pics/button-pressed.png"
+ opacity: 0
+ }
+ MouseRegion {
+ id: MyMouseRegion
+ anchors.fill: ButtonImage
+ onClicked: { Container.clicked(); }
+ }
+ Text {
+ font.bold: true
+ color: "white"
+ anchors.centerIn: ButtonImage
+ text: Container.text
+ }
+ width: ButtonImage.width
+ states: [
+ State {
+ name: "Pressed"
+ when: MyMouseRegion.pressed == true
+ PropertyChanges {
+ target: Pressed
+ opacity: 1
+ }
+ }
+ ]
+}
diff --git a/demos/declarative/flickr/common/MediaLineEdit.qml b/demos/declarative/flickr/common/MediaLineEdit.qml
new file mode 100644
index 0000000..7599ce6a05
--- /dev/null
+++ b/demos/declarative/flickr/common/MediaLineEdit.qml
@@ -0,0 +1,104 @@
+import Qt 4.6
+
+Item {
+ id: Container
+
+ property string label
+ property string text
+
+ width: Math.max(94,Label.width + Editor.width + 20)
+ height: ButtonImage.height
+
+ states: [
+ State {
+ name: "Edit"
+ PropertyChanges {
+ target: Label
+ text: Container.label + ": "
+ }
+ PropertyChanges {
+ target: Label
+ x: 10
+ }
+ PropertyChanges {
+ target: Editor
+ cursorVisible: true
+ width: 100
+ }
+ PropertyChanges {
+ target: Container
+ focus: true
+ }
+ StateChangeScript {
+ script:"Editor.selectAll()"
+ }
+ },
+ State {
+ // When returning to default state, typed text is propagated
+ StateChangeScript {
+ script: "Container.text = Editor.text"
+ }
+ }
+ ]
+ transitions: [
+ Transition {
+ NumberAnimation { properties: "x,width"; duration: 500; easing: "easeInOutQuad" }
+ }
+ ]
+
+
+ BorderImage {
+ id: ButtonImage
+ source: "pics/button.sci"
+ anchors.left: Container.left
+ anchors.right: Container.right
+ }
+
+ BorderImage {
+ id: Pressed
+ source: "pics/button-pressed.sci"
+ opacity: 0
+ anchors.left: Container.left
+ anchors.right: Container.right
+ }
+
+ MouseRegion {
+ id: MyMouseRegion
+ anchors.fill: ButtonImage
+ onClicked: { Container.state = Container.state=="Edit" ? "" : "Edit" }
+ states: [
+ State {
+ when: MyMouseRegion.pressed == true
+ PropertyChanges {
+ target: Pressed
+ opacity: 1
+ }
+ }
+ ]
+ }
+
+ Text {
+ id: Label
+ font.bold: true
+ color: "white"
+ anchors.verticalCenter: Container.verticalCenter
+ x: (Container.width - width)/2
+ text: Container.label + "..."
+ }
+
+ TextInput {
+ id: Editor
+ font.bold: true
+ color: "white"
+ selectionColor: "green"
+ width: 0
+ clip: true
+ anchors.left: Label.right
+ anchors.verticalCenter: Container.verticalCenter
+ }
+ Keys.forwardTo: [(ReturnKey), (Editor)]
+ Item {
+ id: ReturnKey
+ Keys.onReturnPressed: "Container.state = ''"
+ }
+}
diff --git a/demos/declarative/flickr/common/Progress.qml b/demos/declarative/flickr/common/Progress.qml
new file mode 100644
index 0000000..00ef901
--- /dev/null
+++ b/demos/declarative/flickr/common/Progress.qml
@@ -0,0 +1,35 @@
+import Qt 4.6
+
+Item {
+ id: Progress;
+
+ property var progress: 0
+
+ Rectangle {
+ id: Container; anchors.fill: parent; smooth: true
+ border.color: "white"; border.width: 0; radius: height/2 - 2
+ gradient: Gradient {
+ GradientStop { position: 0; color: "#66343434" }
+ GradientStop { position: 1.0; color: "#66000000" }
+ }
+ }
+
+ Rectangle {
+ id: Fill
+ y: 2; height: parent.height-4;
+ x: 2; width: Math.max(parent.width * progress - 4, 0);
+ opacity: width < 1 ? 0 : 1; smooth: true
+ gradient: Gradient {
+ GradientStop { position: 0; color: "lightsteelblue" }
+ GradientStop { position: 1.0; color: "steelblue" }
+ }
+ radius: height/2 - 2
+ }
+
+ Text {
+ text: Math.round(progress * 100) + "%"
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.verticalCenter: parent.verticalCenter
+ color: "white"; font.bold: true
+ }
+}
diff --git a/demos/declarative/flickr/common/RssModel.qml b/demos/declarative/flickr/common/RssModel.qml
new file mode 100644
index 0000000..ed9fd5c
--- /dev/null
+++ b/demos/declarative/flickr/common/RssModel.qml
@@ -0,0 +1,20 @@
+import Qt 4.6
+
+XmlListModel {
+ property string tags : ""
+
+ source: "http://api.flickr.com/services/feeds/photos_public.gne?"+(tags ? "tags="+tags+"&" : "")+"format=rss2"
+ query: "/rss/channel/item"
+ namespaceDeclarations: "declare namespace media=\"http://search.yahoo.com/mrss/\";"
+
+ XmlRole { name: "title"; query: "title/string()" }
+ XmlRole { name: "imagePath"; query: "media:thumbnail/@url/string()" }
+ XmlRole { name: "url"; query: "media:content/@url/string()" }
+ XmlRole { name: "description"; query: "description/string()" }
+ XmlRole { name: "tags"; query: "media:category/string()" }
+ XmlRole { name: "photoWidth"; query: "media:content/@width/string()" }
+ XmlRole { name: "photoHeight"; query: "media:content/@height/string()" }
+ XmlRole { name: "photoType"; query: "media:content/@type/string()" }
+ XmlRole { name: "photoAuthor"; query: "author/string()" }
+ XmlRole { name: "photoDate"; query: "pubDate/string()" }
+}
diff --git a/demos/declarative/flickr/common/ScrollBar.qml b/demos/declarative/flickr/common/ScrollBar.qml
new file mode 100644
index 0000000..d31c57c
--- /dev/null
+++ b/demos/declarative/flickr/common/ScrollBar.qml
@@ -0,0 +1,40 @@
+import Qt 4.6
+
+Item {
+ id: Container
+
+ property var flickableArea
+
+ Rectangle {
+ radius: 5
+ color: "black"
+ opacity: 0.3
+ border.color: "white"
+ border.width: 2
+ x: 0
+ y: flickableArea.visibleArea.yPosition * Container.height
+ width: parent.width
+ height: flickableArea.visibleArea.heightRatio * Container.height
+ }
+ states: [
+ State {
+ name: "show"
+ when: flickableArea.moving
+ PropertyChanges {
+ target: Container
+ opacity: 1
+ }
+ }
+ ]
+ transitions: [
+ Transition {
+ from: "*"
+ to: "*"
+ NumberAnimation {
+ target: Container
+ properties: "opacity"
+ duration: 400
+ }
+ }
+ ]
+}
diff --git a/demos/declarative/flickr/common/Slider.qml b/demos/declarative/flickr/common/Slider.qml
new file mode 100644
index 0000000..b88636d
--- /dev/null
+++ b/demos/declarative/flickr/common/Slider.qml
@@ -0,0 +1,36 @@
+import Qt 4.6
+
+Item {
+ id: Slider; width: 400; height: 16
+
+ // value is read/write.
+ property real value
+ onValueChanged: { Handle.x = 2 + (value - minimum) * Slider.xMax / (maximum - minimum); }
+ property real maximum: 1
+ property real minimum: 1
+ property int xMax: Slider.width - Handle.width - 4
+
+ Rectangle {
+ id: Container; anchors.fill: parent
+ border.color: "white"; border.width: 0; radius: 8
+ gradient: Gradient {
+ GradientStop { position: 0.0; color: "#66343434" }
+ GradientStop { position: 1.0; color: "#66000000" }
+ }
+ }
+
+ Rectangle {
+ id: Handle; smooth: true
+ x: Slider.width / 2 - Handle.width / 2; y: 2; width: 30; height: Slider.height-4; radius: 6
+ gradient: Gradient {
+ GradientStop { position: 0.0; color: "lightgray" }
+ GradientStop { position: 1.0; color: "gray" }
+ }
+
+ MouseRegion {
+ anchors.fill: parent; drag.target: parent
+ drag.axis: "XAxis"; drag.minimumX: 2; drag.maximumX: Slider.xMax+2
+ onPositionChanged: { value = (maximum - minimum) * (Handle.x-2) / Slider.xMax + minimum; }
+ }
+ }
+}
diff --git a/demos/declarative/flickr/common/Star.qml b/demos/declarative/flickr/common/Star.qml
new file mode 100644
index 0000000..c4d1bec
--- /dev/null
+++ b/demos/declarative/flickr/common/Star.qml
@@ -0,0 +1,46 @@
+import Qt 4.6
+
+Item {
+ id: Container
+ width: 24
+ height: 24
+
+ property int rating
+ property bool on
+
+ signal clicked
+
+ Image {
+ id: StarImage
+ source: "pics/ghns_star.png"
+ x: 6
+ y: 7
+ opacity: 0.4
+ scale: 0.5
+ }
+ MouseRegion {
+ anchors.fill: Container
+ onClicked: { Container.clicked() }
+ }
+ states: [
+ State {
+ name: "on"
+ when: Container.on == true
+ PropertyChanges {
+ target: StarImage
+ opacity: 1
+ scale: 1
+ x: 1
+ y: 0
+ }
+ }
+ ]
+ transitions: [
+ Transition {
+ NumberAnimation {
+ properties: "opacity,scale,x,y"
+ easing: "easeOutBounce"
+ }
+ }
+ ]
+}
diff --git a/demos/declarative/flickr/common/pics/background.png b/demos/declarative/flickr/common/pics/background.png
new file mode 100644
index 0000000..5b37072
--- /dev/null
+++ b/demos/declarative/flickr/common/pics/background.png
Binary files differ
diff --git a/demos/declarative/flickr/common/pics/button-pressed.png b/demos/declarative/flickr/common/pics/button-pressed.png
new file mode 100644
index 0000000..e434d32
--- /dev/null
+++ b/demos/declarative/flickr/common/pics/button-pressed.png
Binary files differ
diff --git a/demos/declarative/flickr/common/pics/button-pressed.sci b/demos/declarative/flickr/common/pics/button-pressed.sci
new file mode 100644
index 0000000..d3b16e2
--- /dev/null
+++ b/demos/declarative/flickr/common/pics/button-pressed.sci
@@ -0,0 +1,5 @@
+gridLeft: 8
+gridTop: 4
+gridBottom: 4
+gridRight: 8
+imageFile: button.png
diff --git a/demos/declarative/flickr/common/pics/button.png b/demos/declarative/flickr/common/pics/button.png
new file mode 100644
index 0000000..56a63ce
--- /dev/null
+++ b/demos/declarative/flickr/common/pics/button.png
Binary files differ
diff --git a/demos/declarative/flickr/common/pics/button.sci b/demos/declarative/flickr/common/pics/button.sci
new file mode 100644
index 0000000..d3b16e2
--- /dev/null
+++ b/demos/declarative/flickr/common/pics/button.sci
@@ -0,0 +1,5 @@
+gridLeft: 8
+gridTop: 4
+gridBottom: 4
+gridRight: 8
+imageFile: button.png
diff --git a/demos/declarative/flickr/common/pics/ghns_star.png b/demos/declarative/flickr/common/pics/ghns_star.png
new file mode 100644
index 0000000..4ad43cc
--- /dev/null
+++ b/demos/declarative/flickr/common/pics/ghns_star.png
Binary files differ
diff --git a/demos/declarative/flickr/common/pics/loading.png b/demos/declarative/flickr/common/pics/loading.png
new file mode 100644
index 0000000..47a1589
--- /dev/null
+++ b/demos/declarative/flickr/common/pics/loading.png
Binary files differ
diff --git a/demos/declarative/flickr/common/pics/reflection.png b/demos/declarative/flickr/common/pics/reflection.png
new file mode 100644
index 0000000..c143a48
--- /dev/null
+++ b/demos/declarative/flickr/common/pics/reflection.png
Binary files differ
diff --git a/demos/declarative/flickr/common/pics/shadow-bottom.png b/demos/declarative/flickr/common/pics/shadow-bottom.png
new file mode 100644
index 0000000..523f6e7
--- /dev/null
+++ b/demos/declarative/flickr/common/pics/shadow-bottom.png
Binary files differ
diff --git a/demos/declarative/flickr/common/pics/shadow-corner.png b/demos/declarative/flickr/common/pics/shadow-corner.png
new file mode 100644
index 0000000..ef8c856
--- /dev/null
+++ b/demos/declarative/flickr/common/pics/shadow-corner.png
Binary files differ
diff --git a/demos/declarative/flickr/common/pics/shadow-right-screen.png b/demos/declarative/flickr/common/pics/shadow-right-screen.png
new file mode 100644
index 0000000..9856c4f
--- /dev/null
+++ b/demos/declarative/flickr/common/pics/shadow-right-screen.png
Binary files differ
diff --git a/demos/declarative/flickr/common/pics/shadow-right.png b/demos/declarative/flickr/common/pics/shadow-right.png
new file mode 100644
index 0000000..f534a35
--- /dev/null
+++ b/demos/declarative/flickr/common/pics/shadow-right.png
Binary files differ
diff --git a/demos/declarative/flickr/flickr-desktop.qml b/demos/declarative/flickr/flickr-desktop.qml
new file mode 100644
index 0000000..6a4efd9
--- /dev/null
+++ b/demos/declarative/flickr/flickr-desktop.qml
@@ -0,0 +1,192 @@
+import Qt 4.6
+
+import "common"
+
+Item {
+ id: MainWindow; width: 800; height: 450
+
+ property bool showPathView : false
+
+ resources: [
+ Component {
+ id: PhotoDelegate
+ Item {
+ id: Wrapper; width: 85; height: 85
+ scale: Wrapper.PathView.scale; z: Wrapper.PathView.z
+
+ transform: Rotation {
+ id: ItemRotation; origin.x: Wrapper.width/2; origin.y: Wrapper.height/2
+ axis.y: 1; axis.z: 0; angle: Wrapper.PathView.angle
+ }
+
+ Connection {
+ sender: ImageDetails; signal: "closed()"
+ script: {
+ if (Wrapper.state == 'Details') {
+ Wrapper.state = '';
+ ImageDetails.photoUrl = "";
+ }
+ }
+ }
+
+ Script {
+ function photoClicked() {
+ ImageDetails.photoTitle = title;
+ ImageDetails.photoDescription = description;
+ ImageDetails.photoTags = tags;
+ ImageDetails.photoWidth = photoWidth;
+ ImageDetails.photoHeight = photoHeight;
+ ImageDetails.photoType = photoType;
+ ImageDetails.photoAuthor = photoAuthor;
+ ImageDetails.photoDate = photoDate;
+ ImageDetails.photoUrl = url;
+ ImageDetails.rating = 0;
+ Wrapper.state = "Details";
+ }
+ }
+
+ Rectangle {
+ id: WhiteRect; anchors.fill: parent; color: "white"; radius: 5
+
+ Loading { x: 26; y: 26; visible: Thumb.status!=1 }
+ Image { id: Thumb; source: imagePath; x: 5; y: 5 }
+
+ Item {
+ id: Shadows
+ Image { source: "common/pics/shadow-right.png"; x: WhiteRect.width; height: WhiteRect.height }
+ Image { source: "common/pics/shadow-bottom.png"; y: WhiteRect.height; width: WhiteRect.width }
+ Image { id: Corner; source: "common/pics/shadow-corner.png"; x: WhiteRect.width; y: WhiteRect.height }
+ }
+ }
+
+ MouseRegion { anchors.fill: Wrapper; onClicked: { photoClicked() } }
+
+ states: [
+ State {
+ name: "Details"
+ PropertyChanges { target: ImageDetails; z: 2 }
+ ParentChange { target: Wrapper; parent: ImageDetails.frontContainer }
+ PropertyChanges { target: Wrapper; x: 45; y: 35; scale: 1; z: 1000 }
+ PropertyChanges { target: ItemRotation; angle: 0 }
+ PropertyChanges { target: Shadows; opacity: 0 }
+ PropertyChanges { target: ImageDetails; y: 20 }
+ PropertyChanges { target: PhotoGridView; y: "-480" }
+ PropertyChanges { target: PhotoPathView; y: "-480" }
+ PropertyChanges { target: ViewModeButton; opacity: 0 }
+ PropertyChanges { target: TagsEdit; opacity: 0 }
+ PropertyChanges { target: FetchButton; opacity: 0 }
+ PropertyChanges { target: CategoryText; y: "-50" }
+ }
+ ]
+
+ transitions: [
+ Transition {
+ from: "*"; to: "Details"
+ ParentAction { }
+ NumberAnimation { properties: "x,y,scale,opacity,angle"; duration: 500; easing: "easeInOutQuad" }
+ },
+ Transition {
+ from: "Details"; to: "*"
+ SequentialAnimation {
+ ParentAction { }
+ NumberAnimation { properties: "x,y,scale,opacity,angle"; duration: 500; easing: "easeInOutQuad" }
+ PropertyAction { target: Wrapper; properties: "z" }
+ }
+ }
+ ]
+
+ }
+ }
+ ]
+
+ Item {
+ id: Background
+
+ anchors.fill: parent
+
+ Image { source: "common/pics/background.png"; anchors.fill: parent }
+ RssModel { id: RssModel; tags : TagsEdit.text }
+ Loading { anchors.centerIn: parent; visible: RssModel.status == 2 }
+
+ GridView {
+ id: PhotoGridView; model: RssModel; delegate: PhotoDelegate; cacheBuffer: 100
+ cellWidth: 105; cellHeight: 105; x:32; y: 80; width: 800; height: 330; z: 1
+ }
+
+ PathView {
+ id: PhotoPathView; model: RssModel; delegate: PhotoDelegate
+ y: -380; width: 800; height: 330; pathItemCount: 10; z: 1
+ path: Path {
+ startX: -50; startY: 40;
+
+ PathAttribute { name: "scale"; value: 1 }
+ PathAttribute { name: "angle"; value: -45 }
+
+ PathCubic {
+ x: 400; y: 220
+ control1X: 140; control1Y: 40
+ control2X: 210; control2Y: 220
+ }
+
+ PathAttribute { name: "scale"; value: 1.2 }
+ PathAttribute { name: "z"; value: 1 }
+ PathAttribute { name: "angle"; value: 0 }
+
+ PathCubic {
+ x: 850; y: 40
+ control2X: 660; control2Y: 40
+ control1X: 590; control1Y: 220
+ }
+
+ PathAttribute { name: "scale"; value: 1 }
+ PathAttribute { name: "angle"; value: 45 }
+ }
+
+ }
+
+ ImageDetails { id: ImageDetails; width: 750; x: 25; y: 500; height: 410 }
+
+ MediaButton {
+ id: ViewModeButton; x: 680; y: 410; text: "View Mode"
+ onClicked: { if (MainWindow.showPathView == true) MainWindow.showPathView = false; else MainWindow.showPathView = true }
+ }
+
+ MediaButton {
+ id: FetchButton
+ text: "Update"
+ anchors.right: ViewModeButton.left; anchors.rightMargin: 5
+ anchors.top: ViewModeButton.top
+ onClicked: { RssModel.reload(); }
+ }
+
+ MediaLineEdit {
+ id: TagsEdit;
+ label: "Tags"
+ anchors.right: FetchButton.left; anchors.rightMargin: 5
+ anchors.top: ViewModeButton.top
+ }
+
+ states: [
+ State {
+ name: "PathView"
+ when: MainWindow.showPathView == true
+ PropertyChanges { target: PhotoPathView; y: 80 }
+ PropertyChanges { target: PhotoGridView; y: -380 }
+ }
+ ]
+
+ transitions: [
+ Transition {
+ from: "*"; to: "*"
+ NumberAnimation { properties: "y"; duration: 1000; easing: "easeOutBounce(amplitude:0.5)" }
+ }
+ ]
+ }
+
+ Text {
+ id: CategoryText; anchors.horizontalCenter: parent.horizontalCenter; y: 15;
+ text: "Flickr - " +
+ (RssModel.tags=="" ? "Uploads from everyone" : "Recent Uploads tagged " + RssModel.tags)
+ font.pointSize: 20; font.bold: true; color: "white"; style: "Raised"; styleColor: "black"
+ }
+}
diff --git a/demos/declarative/flickr/flickr-mobile.qml b/demos/declarative/flickr/flickr-mobile.qml
new file mode 100644
index 0000000..9d2a3fb
--- /dev/null
+++ b/demos/declarative/flickr/flickr-mobile.qml
@@ -0,0 +1,69 @@
+import Qt 4.6
+import "common" as Common
+import "mobile" as Mobile
+
+Item {
+ id: Screen; width: 320; height: 480
+ property bool inListView : false
+
+ Rectangle {
+ id: Background
+ anchors.fill: parent; color: "#343434";
+
+ Image { source: "mobile/images/stripes.png"; fillMode: "Tile"; anchors.fill: parent; opacity: 0.3 }
+
+ Common.RssModel { id: RssModel }
+ Common.Loading { anchors.centerIn: parent; visible: RssModel.status == 2 }
+
+ Item {
+ id: Views
+ x: 2; width: parent.width - 4
+ anchors.top: TitleBar.bottom; anchors.bottom: ToolBar.top
+
+ Mobile.GridDelegate { id: GridDelegate }
+ GridView {
+ id: PhotoGridView; model: RssModel; delegate: GridDelegate; cacheBuffer: 100
+ cellWidth: 79; cellHeight: 79; width: parent.width; height: parent.height - 1; z: 6
+ }
+
+ Mobile.ListDelegate { id: ListDelegate }
+ ListView {
+ id: PhotoListView; model: RssModel; delegate: ListDelegate; z: 6
+ width: parent.width; height: parent.height; x: -(parent.width * 1.5); cacheBuffer: 100;
+ }
+ states: State {
+ name: "ListView"; when: Screen.inListView == true
+ PropertyChanges { target: PhotoListView; x: 0 }
+ PropertyChanges { target: PhotoGridView; x: -(parent.width * 1.5) }
+ }
+
+ transitions: Transition {
+ NumberAnimation { properties: "x"; duration: 500; easing: "easeInOutQuad" }
+ }
+ }
+
+ Mobile.ImageDetails { id: ImageDetails; width: parent.width; anchors.left: Views.right; height: parent.height; z:1 }
+ Mobile.TitleBar { id: TitleBar; z: 5; width: parent.width; height: 40; opacity: 0.9 }
+
+ Mobile.ToolBar {
+ id: ToolBar; z: 5
+ height: 40; anchors.bottom: parent.bottom; width: parent.width; opacity: 0.9
+ button1Label: "Update"; button2Label: "View mode"
+ onButton1Clicked: RssModel.reload()
+ onButton2Clicked: if (Screen.inListView == true) Screen.inListView = false; else Screen.inListView = true
+ }
+
+ states: State {
+ name: "DetailedView"
+ PropertyChanges { target: Views; x: -parent.width }
+ PropertyChanges { target: ToolBar; button1Label: "More..." }
+ PropertyChanges { target: ToolBar; onButton1Clicked: { } }
+ PropertyChanges { target: ToolBar; button2Label: "Back" }
+ PropertyChanges { target: ToolBar; onButton2Clicked: { } }
+ }
+
+ transitions: Transition {
+ NumberAnimation { properties: "x"; duration: 500; easing: "easeInOutQuad" }
+ }
+ }
+}
diff --git a/demos/declarative/flickr/mobile/Button.qml b/demos/declarative/flickr/mobile/Button.qml
new file mode 100644
index 0000000..6887240
--- /dev/null
+++ b/demos/declarative/flickr/mobile/Button.qml
@@ -0,0 +1,41 @@
+import Qt 4.6
+
+Item {
+ id: Container
+
+ signal clicked
+
+ property string text
+
+ BorderImage {
+ id: ButtonImage
+ source: "images/toolbutton.sci"
+ width: Container.width; height: Container.height
+ }
+ BorderImage {
+ id: Pressed
+ opacity: 0
+ source: "images/toolbutton.sci"
+ width: Container.width; height: Container.height
+ }
+ MouseRegion {
+ id: MyMouseRegion
+ anchors.fill: ButtonImage
+ onClicked: { Container.clicked(); }
+ }
+ Text {
+ color: "white"
+ anchors.centerIn: ButtonImage; font.bold: true
+ text: Container.text; style: "Raised"; styleColor: "black"
+ }
+ states: [
+ State {
+ name: "Pressed"
+ when: MyMouseRegion.pressed == true
+ PropertyChanges {
+ target: Pressed
+ opacity: 1
+ }
+ }
+ ]
+}
diff --git a/demos/declarative/flickr/mobile/GridDelegate.qml b/demos/declarative/flickr/mobile/GridDelegate.qml
new file mode 100644
index 0000000..890e020
--- /dev/null
+++ b/demos/declarative/flickr/mobile/GridDelegate.qml
@@ -0,0 +1,72 @@
+ import Qt 4.6
+
+ Component {
+ id: PhotoDelegate
+ Item {
+ id: Wrapper; width: 79; height: 79
+
+ Script {
+ function photoClicked() {
+ ImageDetails.photoTitle = title;
+ ImageDetails.photoTags = tags;
+ ImageDetails.photoWidth = photoWidth;
+ ImageDetails.photoHeight = photoHeight;
+ ImageDetails.photoType = photoType;
+ ImageDetails.photoAuthor = photoAuthor;
+ ImageDetails.photoDate = photoDate;
+ ImageDetails.photoUrl = url;
+ ImageDetails.rating = 0;
+ ScaleMe.state = "Details";
+ }
+ }
+
+ Item {
+ anchors.centerIn: parent
+ scale: 0.0
+ scale: Behavior { NumberAnimation { easing: "easeInOutQuad"} }
+ id: ScaleMe
+
+ Rectangle { height: 79; width: 79; id: BlackRect; anchors.centerIn: parent; color: "black"; smooth: true }
+ Rectangle {
+ id: WhiteRect; width: 77; height: 77; anchors.centerIn: parent; color: "#dddddd"; smooth: true
+ Image { id: Thumb; source: imagePath; x: 1; y: 1; smooth: true}
+ Image { source: "images/gloss.png" }
+ }
+
+ Connection {
+ sender: ToolBar; signal: "button2Clicked()"
+ script: if (ScaleMe.state == 'Details' ) ScaleMe.state = 'Show';
+ }
+
+ states: [
+ State {
+ name: "Show"; when: Thumb.status == 1
+ PropertyChanges { target: ScaleMe; scale: 1 }
+ },
+ State {
+ name: "Details"; extend: "Show"
+ //PropertyChanges { target: ImageDetails; z: 2 }
+ ParentChange { target: Wrapper; parent: ImageDetails.frontContainer }
+ PropertyChanges { target: Wrapper; x: 20; y: 60; z: 1000 }
+ PropertyChanges { target: Background; state: "DetailedView" }
+ }
+ ]
+ transitions: [
+ Transition {
+ from: "Show"; to: "Details"
+ ParentAction { }
+ NumberAnimation { properties: "x,y"; duration: 500; easing: "easeInOutQuad" }
+ },
+ Transition {
+ from: "Details"; to: "Show"
+ SequentialAnimation {
+ ParentAction { }
+ NumberAnimation { properties: "x,y"; duration: 500; easing: "easeInOutQuad" }
+ PropertyAction { target: Wrapper; properties: "z" }
+ }
+ }
+ ]
+ }
+ MouseRegion { anchors.fill: Wrapper; onClicked: { photoClicked() } }
+ }
+ }
diff --git a/demos/declarative/flickr/mobile/ImageDetails.qml b/demos/declarative/flickr/mobile/ImageDetails.qml
new file mode 100644
index 0000000..617fe40
--- /dev/null
+++ b/demos/declarative/flickr/mobile/ImageDetails.qml
@@ -0,0 +1,129 @@
+import Qt 4.6
+import "../common" as Common
+
+Flipable {
+ id: Container
+
+ property var frontContainer: ContainerFront
+ property string photoTitle: ""
+ property string photoTags: ""
+ property int photoWidth
+ property int photoHeight
+ property string photoType
+ property string photoAuthor
+ property string photoDate
+ property string photoUrl
+ property int rating: 2
+ property var prevScale: 1.0
+
+ signal closed
+
+ transform: Rotation {
+ id: ItemRotation
+ origin.x: Container.width / 2;
+ axis.y: 1; axis.z: 0
+ }
+
+ front: Item {
+ id: ContainerFront; anchors.fill: Container
+
+ Rectangle {
+ anchors.fill: parent
+ color: "black"; opacity: 0.4
+ }
+
+ Connection {
+ sender: ToolBar; signal: "button1Clicked()"
+ script: if (Container.state=='') Container.state='Back'; else Container.state=''
+ }
+
+ Column {
+ spacing: 10
+ anchors {
+ left: parent.left; leftMargin: 20
+ right: parent.right; rightMargin: 20
+ top: parent.top; topMargin: 180
+ }
+ Text { id: TitleText; font.bold: true; color: "white"; elide: "ElideRight"; text: Container.photoTitle }
+ Text { id: Size; color: "white"; elide: "ElideRight"; text: "<b>Size:</b> " + Container.photoWidth + 'x' + Container.photoHeight }
+ Text { id: Type; color: "white"; elide: "ElideRight"; text: "<b>Type:</b> " + Container.photoType }
+ Text { id: Author; color: "white"; elide: "ElideRight"; text: "<b>Author:</b> " + Container.photoAuthor }
+ Text { id: Date; color: "white"; elide: "ElideRight"; text: "<b>Published:</b> " + Container.photoDate }
+ Text { id: TagsLabel; color: "white"; elide: "ElideRight"; text: Container.photoTags == "" ? "" : "<b>Tags:</b> " }
+ Text { id: Tags; color: "white"; elide: "ElideRight"; elide: "ElideRight"; text: Container.photoTags }
+ }
+ }
+
+ back: Item {
+ anchors.fill: Container
+
+ Rectangle { anchors.fill: parent; color: "black"; opacity: 0.4 }
+
+ Common.Progress { anchors.centerIn: parent; width: 200; height: 18; progress: BigImage.progress; visible: BigImage.status!=1 }
+ Flickable {
+ id: Flick; anchors.fill: parent; clip: true
+ viewportWidth: ImageContainer.width; viewportHeight: ImageContainer.height
+
+ Item {
+ id: ImageContainer
+ width: Math.max(BigImage.width * BigImage.scale, Flick.width);
+ height: Math.max(BigImage.height * BigImage.scale, Flick.height);
+
+ Image {
+ id: BigImage; source: Container.photoUrl; scale: Slider.value
+ // Center image if it is smaller than the flickable area.
+ x: ImageContainer.width > width*scale ? (ImageContainer.width - width*scale) / 2 : 0
+ y: ImageContainer.height > height*scale ? (ImageContainer.height - height*scale) / 2 : 0
+ smooth: !Flick.moving
+ onStatusChanged : {
+ // Default scale shows the entire image.
+ if (status == 1 && width != 0) {
+ Slider.minimum = Math.min(Flick.width / width, Flick.height / height);
+ prevScale = Math.min(Slider.minimum, 1);
+ Slider.value = prevScale;
+ }
+ }
+ }
+ }
+ }
+
+ Text {
+ text: "Image Unavailable"
+ visible: BigImage.status == 'Error'
+ anchors.centerIn: parent; color: "white"; font.bold: true
+ }
+
+ Common.Slider {
+ id: Slider; visible: { BigImage.status == 1 && maximum > minimum }
+ anchors {
+ bottom: parent.bottom; bottomMargin: 65
+ left: parent.left; leftMargin: 25
+ right: parent.right; rightMargin: 25
+ }
+ onValueChanged: {
+ if (BigImage.width * value > Flick.width) {
+ var xoff = (Flick.width/2 + Flick.viewportX) * value / prevScale;
+ Flick.viewportX = xoff - Flick.width/2;
+ }
+ if (BigImage.height * value > Flick.height) {
+ var yoff = (Flick.height/2 + Flick.viewportY) * value / prevScale;
+ Flick.viewportY = yoff - Flick.height/2;
+ }
+ prevScale = value;
+ }
+ }
+ }
+
+ states: State {
+ name: "Back"
+ PropertyChanges { target: ItemRotation; angle: 180 }
+ }
+
+ transitions: Transition {
+ SequentialAnimation {
+ PropertyAction { target: BigImage; property: "smooth"; value: false }
+ NumberAnimation { easing: "easeInOutQuad"; properties: "angle"; duration: 500 }
+ PropertyAction { target: BigImage; property: "smooth"; value: !Flick.moving }
+ }
+ }
+}
diff --git a/demos/declarative/flickr/mobile/ListDelegate.qml b/demos/declarative/flickr/mobile/ListDelegate.qml
new file mode 100644
index 0000000..fa6f8ea
--- /dev/null
+++ b/demos/declarative/flickr/mobile/ListDelegate.qml
@@ -0,0 +1,24 @@
+import Qt 4.6
+
+Component {
+ id: ListDelegate
+ Item {
+ id: Wrapper; width: Wrapper.ListView.view.width; height: 86
+ Item {
+ id: MoveMe
+ Rectangle { color: "black"; opacity: index % 2 ? 0.2 : 0.4; height: 84; width: Wrapper.width; y: 1 }
+ Rectangle {
+ id: WhiteRect; x: 6; y: 4; width: 77; height: 77; color: "white"; smooth: true
+
+ Image { id: Thumb; source: imagePath; x: 1; y: 1 }
+ Image { source: "images/gloss.png" }
+ }
+ Column {
+ x: 92; width: Wrapper.ListView.view.width - 95; y: 15; spacing: 2
+ Text { text: title; color: "white"; width: parent.width; font.bold: true; elide: "ElideRight"; style: "Raised"; styleColor: "black" }
+ Text { text: photoAuthor; color: "white"; width: parent.width; elide: "ElideLeft"; color: "#cccccc"; style: "Raised"; styleColor: "black" }
+ Text { text: photoDate; color: "white"; width: parent.width; elide: "ElideRight"; color: "#cccccc"; style: "Raised"; styleColor: "black" }
+ }
+ }
+ }
+}
diff --git a/demos/declarative/flickr/mobile/TitleBar.qml b/demos/declarative/flickr/mobile/TitleBar.qml
new file mode 100644
index 0000000..13484a2
--- /dev/null
+++ b/demos/declarative/flickr/mobile/TitleBar.qml
@@ -0,0 +1,76 @@
+import Qt 4.6
+
+Item {
+ id: TitleBar
+ property string untaggedString: "Uploads from everyone"
+ property string taggedString: "Recent uploads tagged "
+
+ BorderImage { source: "images/titlebar.sci"; width: parent.width; height: parent.height + 14; y: -7 }
+
+ Item {
+ id: Container
+ width: (parent.width * 2) - 55 ; height: parent.height
+
+ Script {
+ function accept() {
+ TitleBar.state = ""
+ Background.state = ""
+ RssModel.tags = Editor.text
+ }
+ }
+
+ Text {
+ id: CategoryText
+ anchors {
+ left: parent.left; right: TagButton.left; leftMargin: 10; rightMargin: 10
+ verticalCenter: parent.verticalCenter
+ }
+ elide: "ElideLeft"
+ text: (RssModel.tags=="" ? untaggedString : taggedString + RssModel.tags)
+ font.bold: true; color: "White"; style: "Raised"; styleColor: "Black"
+ }
+
+ Button {
+ id: TagButton; x: TitleBar.width - 50; width: 45; height: 32; text: "..."
+ onClicked: if (TitleBar.state == "Tags") accept(); else TitleBar.state = "Tags"
+ anchors.verticalCenter: parent.verticalCenter
+ }
+
+ Item {
+ id: LineEdit
+ y: 4; height: parent.height - 9
+ anchors { left: TagButton.right; leftMargin: 5; right: parent.right; rightMargin: 5 }
+
+ BorderImage { source: "images/lineedit.sci"; anchors.fill: parent }
+
+ TextInput {
+ id: Editor
+ anchors {
+ left: parent.left; right: parent.right; leftMargin: 10; rightMargin: 10
+ verticalCenter: parent.verticalCenter
+ }
+ cursorVisible: true; font.bold: true
+ color: "#151515"; selectionColor: "Green"
+ }
+
+ Keys.forwardTo: [ (ReturnKey), (Editor)]
+
+ Item {
+ id: ReturnKey
+ Keys.onReturnPressed: accept()
+ Keys.onEscapePressed: TitleBar.state = ""
+ }
+ }
+ }
+
+ states: State {
+ name: "Tags"
+ PropertyChanges { target: Container; x: -TagButton.x + 5 }
+ PropertyChanges { target: TagButton; text: "OK" }
+ PropertyChanges { target: LineEdit; focus: true }
+ }
+
+ transitions: Transition {
+ NumberAnimation { properties: "x"; easing: "easeInOutQuad" }
+ }
+}
diff --git a/demos/declarative/flickr/mobile/ToolBar.qml b/demos/declarative/flickr/mobile/ToolBar.qml
new file mode 100644
index 0000000..cfdc8fe
--- /dev/null
+++ b/demos/declarative/flickr/mobile/ToolBar.qml
@@ -0,0 +1,24 @@
+import Qt 4.6
+
+Item {
+ id: Toolbar
+
+ property alias button1Label: Button1.text
+ property alias button2Label: Button2.text
+ signal button1Clicked
+ signal button2Clicked
+
+ BorderImage { source: "images/titlebar.sci"; width: parent.width; height: parent.height + 14; y: -7 }
+
+ Button {
+ id: Button1
+ anchors.left: parent.left; anchors.leftMargin: 5; y: 3; width: 140; height: 32
+ onClicked: Toolbar.button1Clicked()
+ }
+
+ Button {
+ id: Button2
+ anchors.right: parent.right; anchors.rightMargin: 5; y: 3; width: 140; height: 32
+ onClicked: Toolbar.button2Clicked()
+ }
+}
diff --git a/demos/declarative/flickr/mobile/images/gloss.png b/demos/declarative/flickr/mobile/images/gloss.png
new file mode 100644
index 0000000..5d370cd
--- /dev/null
+++ b/demos/declarative/flickr/mobile/images/gloss.png
Binary files differ
diff --git a/demos/declarative/flickr/mobile/images/lineedit.png b/demos/declarative/flickr/mobile/images/lineedit.png
new file mode 100644
index 0000000..2cc38dc
--- /dev/null
+++ b/demos/declarative/flickr/mobile/images/lineedit.png
Binary files differ
diff --git a/demos/declarative/flickr/mobile/images/lineedit.sci b/demos/declarative/flickr/mobile/images/lineedit.sci
new file mode 100644
index 0000000..7c5ec6c
--- /dev/null
+++ b/demos/declarative/flickr/mobile/images/lineedit.sci
@@ -0,0 +1,5 @@
+gridLeft: 10
+gridTop: 10
+gridBottom: 10
+gridRight: 10
+imageFile: lineedit.png
diff --git a/demos/declarative/flickr/mobile/images/stripes.png b/demos/declarative/flickr/mobile/images/stripes.png
new file mode 100644
index 0000000..9f36727
--- /dev/null
+++ b/demos/declarative/flickr/mobile/images/stripes.png
Binary files differ
diff --git a/demos/declarative/flickr/mobile/images/titlebar.png b/demos/declarative/flickr/mobile/images/titlebar.png
new file mode 100644
index 0000000..51c9008
--- /dev/null
+++ b/demos/declarative/flickr/mobile/images/titlebar.png
Binary files differ
diff --git a/demos/declarative/flickr/mobile/images/titlebar.sci b/demos/declarative/flickr/mobile/images/titlebar.sci
new file mode 100644
index 0000000..50444e1
--- /dev/null
+++ b/demos/declarative/flickr/mobile/images/titlebar.sci
@@ -0,0 +1,5 @@
+gridLeft: 10
+gridTop: 12
+gridBottom: 12
+gridRight: 10
+imageFile: titlebar.png
diff --git a/demos/declarative/flickr/mobile/images/toolbutton.png b/demos/declarative/flickr/mobile/images/toolbutton.png
new file mode 100644
index 0000000..8862898
--- /dev/null
+++ b/demos/declarative/flickr/mobile/images/toolbutton.png
Binary files differ
diff --git a/demos/declarative/flickr/mobile/images/toolbutton.sci b/demos/declarative/flickr/mobile/images/toolbutton.sci
new file mode 100644
index 0000000..a0a885f
--- /dev/null
+++ b/demos/declarative/flickr/mobile/images/toolbutton.sci
@@ -0,0 +1,5 @@
+gridLeft: 15
+gridTop: 4
+gridBottom: 4
+gridRight: 15
+imageFile: toolbutton.png
diff --git a/demos/declarative/minehunt/Description.qml b/demos/declarative/minehunt/Description.qml
new file mode 100644
index 0000000..df4881c
--- /dev/null
+++ b/demos/declarative/minehunt/Description.qml
@@ -0,0 +1,34 @@
+import Qt 4.6
+
+Item {
+ id: Page
+ height: MyText.height + 20
+ property var text
+ MouseRegion {
+ anchors.fill: parent
+ drag.target: Page
+ drag.axis: "XandYAxis"
+ drag.minimumX: 0
+ drag.maximumX: 1000
+ drag.minimumY: 0
+ drag.maximumY: 1000
+ }
+ Rectangle {
+ radius: 10
+ anchors.fill: parent
+ color: "lightsteelblue"
+ }
+ Item {
+ x: 10
+ y: 10
+ width: parent.width - 20
+ height: parent.height - 20
+ Text {
+ id: MyText
+ text: Page.text
+ width: parent.width
+ clip: true
+ wrap: true
+ }
+ }
+}
diff --git a/demos/declarative/minehunt/Explosion.qml b/demos/declarative/minehunt/Explosion.qml
new file mode 100644
index 0000000..a997048
--- /dev/null
+++ b/demos/declarative/minehunt/Explosion.qml
@@ -0,0 +1,29 @@
+import Qt 4.6
+
+Item {
+ property bool explode : false
+
+ Particles {
+ id: particles
+ width: 40
+ height: 40
+ lifeSpan: 1000
+ lifeSpanDeviation: 0
+ source: "pics/star.png"
+ count: 0
+ angle: 270
+ angleDeviation: 360
+ velocity: 100
+ velocityDeviation: 20
+ z: 100
+ opacity: 0
+ streamIn: false
+ }
+ states: [ State { name: "exploding"; when: explode == true
+ PropertyChanges { target: particles; count: 200 }
+ PropertyChanges { target: particles; opacity: 1 }
+ PropertyChanges { target: particles; emitting: false } // i.e. emit only once
+ }
+ ]
+
+}
diff --git a/demos/declarative/minehunt/main.cpp b/demos/declarative/minehunt/main.cpp
new file mode 100644
index 0000000..20f7492
--- /dev/null
+++ b/demos/declarative/minehunt/main.cpp
@@ -0,0 +1,309 @@
+#include "qmlengine.h"
+#include "qmlcontext.h"
+#include "qml.h"
+#include <qfxitem.h>
+#include <qfxview.h>
+
+#include <QWidget>
+#include <QApplication>
+#include <QFile>
+#include <QTime>
+#include <QTimer>
+#include <QVBoxLayout>
+#include <QFileInfo>
+
+QString fileName = "minehunt.qml";
+
+class Tile : public QObject
+{
+ Q_OBJECT
+public:
+ Tile() : _hasFlag(false), _hasMine(false), _hint(-1), _flipped(false) {}
+
+ Q_PROPERTY(bool hasFlag READ hasFlag WRITE setHasFlag NOTIFY hasFlagChanged);
+ bool hasFlag() const { return _hasFlag; }
+
+ Q_PROPERTY(bool hasMine READ hasMine NOTIFY hasMineChanged);
+ bool hasMine() const { return _hasMine; }
+
+ Q_PROPERTY(int hint READ hint NOTIFY hintChanged);
+ int hint() const { return _hint; }
+
+ Q_PROPERTY(bool flipped READ flipped NOTIFY flippedChanged());
+ bool flipped() const { return _flipped; }
+
+ void setHasFlag(bool flag) {if(flag==_hasFlag) return; _hasFlag = flag; emit hasFlagChanged();}
+ void setHasMine(bool mine) {if(mine==_hasMine) return; _hasMine = mine; emit hasMineChanged();}
+ void setHint(int hint) { if(hint == _hint) return; _hint = hint; emit hintChanged(); }
+ void flip() { if (_flipped) return; _flipped = true; emit flippedChanged(); }
+ void unflip() { if(!_flipped) return; _flipped = false; emit flippedChanged(); }
+
+signals:
+ void flippedChanged();
+ void hasFlagChanged();
+ void hintChanged();
+ void hasMineChanged();
+
+private:
+ bool _hasFlag;
+ bool _hasMine;
+ int _hint;
+ bool _flipped;
+};
+
+QML_DECLARE_TYPE(Tile);
+QML_DEFINE_TYPE(0,0,0,0,Tile,Tile);
+
+class MyWidget : public QWidget
+{
+Q_OBJECT
+public:
+ MyWidget(int = 370, int = 480, QWidget *parent=0, Qt::WindowFlags flags=0);
+ ~MyWidget();
+
+ Q_PROPERTY(QList<Tile *> *tiles READ tiles CONSTANT);
+ QList<Tile *> *tiles() { return &_tiles; }
+
+ Q_PROPERTY(bool isPlaying READ isPlaying NOTIFY isPlayingChanged);
+ bool isPlaying() {return playing;}
+
+ Q_PROPERTY(bool hasWon READ hasWon NOTIFY hasWonChanged);
+ bool hasWon() {return won;}
+
+ Q_PROPERTY(int numMines READ numMines NOTIFY numMinesChanged);
+ int numMines() const{return nMines;}
+
+ Q_PROPERTY(int numFlags READ numFlags NOTIFY numFlagsChanged);
+ int numFlags() const{return nFlags;}
+
+public slots:
+ Q_INVOKABLE void flip(int row, int col);
+ Q_INVOKABLE void flag(int row, int col);
+ void setBoard();
+ void reset();
+
+signals:
+ void isPlayingChanged();
+ void hasWonChanged();
+ void numMinesChanged();
+ void numFlagsChanged();
+
+private:
+ bool onBoard( int r, int c ) const { return r >= 0 && r < numRows && c >= 0 && c < numCols; }
+ Tile *tile( int row, int col ) { return onBoard(row, col) ? _tiles[col+numRows*row] : 0; }
+ int getHint(int row, int col);
+ void setPlaying(bool b){if(b==playing) return; playing=b; emit isPlayingChanged();}
+
+ QFxView *canvas;
+
+ QList<Tile *> _tiles;
+ int numCols;
+ int numRows;
+ bool playing;
+ bool won;
+ int remaining;
+ int nMines;
+ int nFlags;
+};
+
+MyWidget::MyWidget(int width, int height, QWidget *parent, Qt::WindowFlags flags)
+: QWidget(parent, flags), canvas(0), numCols(9), numRows(9), playing(true), won(false)
+{
+ setObjectName("mainWidget");
+ srand(QTime(0,0,0).secsTo(QTime::currentTime()));
+
+ //initialize array
+ for(int ii = 0; ii < numRows * numCols; ++ii) {
+ _tiles << new Tile;
+ }
+
+ reset();
+
+ QVBoxLayout *vbox = new QVBoxLayout;
+ vbox->setMargin(0);
+ setLayout(vbox);
+
+ canvas = new QFxView(this);
+ canvas->setFixedSize(width, height);
+ vbox->addWidget(canvas);
+
+ QFile file(fileName);
+ file.open(QFile::ReadOnly);
+ QString qml = file.readAll();
+ canvas->setQml(qml, fileName);
+
+ QmlContext *ctxt = canvas->rootContext();
+ ctxt->addDefaultObject(this);
+
+ canvas->execute();
+}
+
+MyWidget::~MyWidget()
+{
+}
+
+void MyWidget::setBoard()
+{
+ foreach(Tile* t, _tiles){
+ t->setHasMine(false);
+ t->setHint(-1);
+ }
+ //place mines
+ int mines = nMines;
+ remaining = numRows*numCols-mines;
+ while ( mines ) {
+ int col = int((double(rand()) / double(RAND_MAX)) * numCols);
+ int row = int((double(rand()) / double(RAND_MAX)) * numRows);
+
+ Tile* t = tile( row, col );
+
+ if (t && !t->hasMine()) {
+ t->setHasMine( true );
+ mines--;
+ }
+ }
+
+ //set hints
+ for (int r = 0; r < numRows; r++)
+ for (int c = 0; c < numCols; c++) {
+ Tile* t = tile(r, c);
+ if (t && !t->hasMine()) {
+ int hint = getHint(r,c);
+ t->setHint(hint);
+ }
+ }
+
+ setPlaying(true);
+}
+
+void MyWidget::reset()
+{
+ foreach(Tile* t, _tiles){
+ t->unflip();
+ t->setHasFlag(false);
+ }
+ nMines = 12;
+ nFlags = 0;
+ setPlaying(false);
+ QTimer::singleShot(900,this, SLOT(setBoard()));
+}
+
+int MyWidget::getHint(int row, int col)
+{
+ int hint = 0;
+ for (int c = col-1; c <= col+1; c++)
+ for (int r = row-1; r <= row+1; r++) {
+ Tile* t = tile(r, c);
+ if (t && t->hasMine())
+ hint++;
+ }
+ return hint;
+}
+
+void MyWidget::flip(int row, int col)
+{
+ if(!playing)
+ return;
+
+ Tile *t = tile(row, col);
+ if (!t || t->hasFlag())
+ return;
+
+ if(t->flipped()){
+ int flags = 0;
+ for (int c = col-1; c <= col+1; c++)
+ for (int r = row-1; r <= row+1; r++) {
+ Tile *nearT = tile(r, c);
+ if(!nearT || nearT == t)
+ continue;
+ if(nearT->hasFlag())
+ flags++;
+ }
+ if(!t->hint() || t->hint() != flags)
+ return;
+ for (int c = col-1; c <= col+1; c++)
+ for (int r = row-1; r <= row+1; r++) {
+ Tile *nearT = tile(r, c);
+ if (nearT && !nearT->flipped() && !nearT->hasFlag()) {
+ flip( r, c );
+ }
+ }
+ return;
+ }
+
+ t->flip();
+
+ if (t->hint() == 0) {
+ for (int c = col-1; c <= col+1; c++)
+ for (int r = row-1; r <= row+1; r++) {
+ Tile* t = tile(r, c);
+ if (t && !t->flipped()) {
+ flip( r, c );
+ }
+ }
+ }
+
+ if(t->hasMine()){
+ for (int r = 0; r < numRows; r++)//Flip all other mines
+ for (int c = 0; c < numCols; c++) {
+ Tile* t = tile(r, c);
+ if (t && t->hasMine()) {
+ flip(r, c);
+ }
+ }
+ won = false;
+ hasWonChanged();
+ setPlaying(false);
+ }
+
+ remaining--;
+ if(!remaining){
+ won = true;
+ hasWonChanged();
+ setPlaying(false);
+ }
+}
+
+void MyWidget::flag(int row, int col)
+{
+ Tile *t = tile(row, col);
+ if(!t)
+ return;
+
+ t->setHasFlag(!t->hasFlag());
+ nFlags += (t->hasFlag()?1:-1);
+ emit numFlagsChanged();
+}
+/////////////////////////////////////////////////////////
+
+int main(int argc, char ** argv)
+{
+ QApplication app(argc, argv);
+
+ bool frameless = false;
+
+ int width = 370;
+ int height = 480;
+
+ for (int i = 1; i < argc; ++i) {
+ QString arg = argv[i];
+ if (arg == "-frameless") {
+ frameless = true;
+ } else if(arg == "-width" && i < (argc - 1)) {
+ ++i;
+ width = ::atoi(argv[i]);
+ } else if(arg == "-height" && i < (argc - 1)) {
+ ++i;
+ height = ::atoi(argv[i]);
+ } else if (arg[0] != '-') {
+ fileName = arg;
+ }
+ }
+
+ MyWidget wid(width, height, 0, frameless ? Qt::FramelessWindowHint : Qt::Widget);
+ wid.show();
+
+ return app.exec();
+}
+
+#include "main.moc"
diff --git a/demos/declarative/minehunt/minehunt.pro b/demos/declarative/minehunt/minehunt.pro
new file mode 100644
index 0000000..01791b1
--- /dev/null
+++ b/demos/declarative/minehunt/minehunt.pro
@@ -0,0 +1,9 @@
+SOURCES = main.cpp
+
+QT += script declarative
+contains(QT_CONFIG, opengles2)|contains(QT_CONFIG, opengles1): QT += opengl
+
+target.path = $$[QT_INSTALL_EXAMPLES]/declarative/minehunt
+sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS minehunt.pro
+sources.path = $$[QT_INSTALL_EXAMPLES]/declarative/minehunt
+INSTALLS += target sources
diff --git a/demos/declarative/minehunt/minehunt.qml b/demos/declarative/minehunt/minehunt.qml
new file mode 100644
index 0000000..72431af
--- /dev/null
+++ b/demos/declarative/minehunt/minehunt.qml
@@ -0,0 +1,195 @@
+import Qt 4.6
+
+Item {
+ id: field
+ width: 370
+ height: 480
+
+ property int clickx : 0
+ property int clicky : 0
+
+ resources: [
+ Component {
+ id: tile
+ Flipable {
+ id: flipable
+ width: 40
+ height: 40
+ property int angle: 0;
+ transform: Rotation {
+ origin.x: 20
+ origin.y: 20
+ axis.x: 1
+ axis.z: 0
+ angle: flipable.angle;
+ }
+ front: Image {
+ source: "pics/front.png"
+ width: 40
+ height: 40
+ Image {
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.verticalCenter: parent.verticalCenter
+ source: "pics/flag.png"
+ opacity: modelData.hasFlag
+ opacity: Behavior {
+ NumberAnimation {
+ property: "opacity"
+ duration: 250
+ }
+ }
+ }
+ }
+ back: Image {
+ source: "pics/back.png"
+ width: 40
+ height: 40
+ Text {
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.verticalCenter: parent.verticalCenter
+ text: modelData.hint
+ color: "white"
+ font.bold: true
+ opacity: !modelData.hasMine && modelData.hint > 0
+ }
+ Image {
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.verticalCenter: parent.verticalCenter
+ source: "pics/bomb.png"
+ opacity: modelData.hasMine
+ }
+ Explosion {
+ id: expl
+ }
+ }
+ states: [
+ State {
+ name: "back"
+ when: modelData.flipped
+ PropertyChanges { target: flipable; angle: 180 }
+ }
+ ]
+ transitions: [
+ Transition {
+ SequentialAnimation {
+ PauseAnimation {
+ duration: {
+ var ret;
+ if(flipable.parent != null)
+ ret = Math.abs(flipable.parent.x-field.clickx)
+ + Math.abs(flipable.parent.y-field.clicky);
+ else
+ ret = 0;
+ if (ret > 0) {
+ if (modelData.hasMine && modelData.flipped) {
+ ret*3;
+ } else {
+ ret;
+ }
+ } else {
+ 0;
+ }
+ }
+ }
+ NumberAnimation {
+ easing: "easeInOutQuad"
+ properties: "angle"
+ }
+ ScriptAction{
+ script: "if(modelData.hasMine && modelData.flipped){expl.explode = true;}"
+ }
+ }
+ }
+ ]
+ MouseRegion {
+ anchors.fill: parent
+ acceptedButtons: Qt.LeftButton | Qt.RightButton
+ onPressed: {
+ field.clickx = flipable.parent.x;
+ field.clicky = flipable.parent.y;
+ row = Math.floor(index/9);
+ col = index - (Math.floor(index/9) * 9);
+ if (mouse.button==undefined || mouse.button==Qt.RightButton) {
+ flag(row,col);
+ } else {
+ flip(row,col);
+ }
+ }
+ }
+ }
+ }
+ ]
+ Image {
+ source: "pics/No-Ones-Laughing-3.jpg"
+ fillMode: "Tile"
+ }
+ Description {
+ text: "Use the 'minehunt' executable to run this demo!"
+ width: 300
+ opacity: tiles?0:1
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.verticalCenter: parent.verticalCenter
+ }
+ Repeater {
+ model: tiles
+ x: 1
+ y: 1
+ Component {
+ Loader {
+ sourceComponent: tile
+ x: (index - (Math.floor(index/9) * 9)) * 41
+ y: Math.floor(index/9) * 41
+ }
+ }
+ }
+ Row {
+ id: gamedata
+ // width: 370
+ // height: 100
+ y: 400
+ x: 20
+ spacing: 20
+ Column {
+ spacing: 2
+ width: childrenRect.width
+ Image {
+ // x: 100
+ // y: 20
+ source: "pics/bomb-color.png"
+ }
+ Text {
+ // x: 100
+ // y: 60
+ anchors.horizontalCenter: parent.horizontalCenter
+ color: "white"
+ text: numMines
+ }
+ }
+ Column {
+ spacing: 2
+ width: childrenRect.width
+ Image {
+ // x: 140
+ // y: 20
+ source: "pics/flag-color.png"
+ }
+ Text {
+ // x: 140
+ // y: 60
+ anchors.horizontalCenter: parent.horizontalCenter
+ color: "white"
+ text: numFlags
+ }
+ }
+ }
+ Image {
+ y: 390
+ anchors.right: field.right
+ anchors.rightMargin: 20
+ source: isPlaying ? 'pics/face-smile.png' : hasWon ? 'pics/face-smile-big.png': 'pics/face-sad.png'
+ MouseRegion {
+ anchors.fill: parent
+ onPressed: { reset() }
+ }
+ }
+}
diff --git a/demos/declarative/minehunt/pics/No-Ones-Laughing-3.jpg b/demos/declarative/minehunt/pics/No-Ones-Laughing-3.jpg
new file mode 100644
index 0000000..445567f
--- /dev/null
+++ b/demos/declarative/minehunt/pics/No-Ones-Laughing-3.jpg
Binary files differ
diff --git a/demos/declarative/minehunt/pics/back.png b/demos/declarative/minehunt/pics/back.png
new file mode 100644
index 0000000..f6b3f0b
--- /dev/null
+++ b/demos/declarative/minehunt/pics/back.png
Binary files differ
diff --git a/demos/declarative/minehunt/pics/bomb-color.png b/demos/declarative/minehunt/pics/bomb-color.png
new file mode 100644
index 0000000..61ad0a9
--- /dev/null
+++ b/demos/declarative/minehunt/pics/bomb-color.png
Binary files differ
diff --git a/demos/declarative/minehunt/pics/bomb.png b/demos/declarative/minehunt/pics/bomb.png
new file mode 100644
index 0000000..a992575
--- /dev/null
+++ b/demos/declarative/minehunt/pics/bomb.png
Binary files differ
diff --git a/demos/declarative/minehunt/pics/face-sad.png b/demos/declarative/minehunt/pics/face-sad.png
new file mode 100644
index 0000000..cf00aaf
--- /dev/null
+++ b/demos/declarative/minehunt/pics/face-sad.png
Binary files differ
diff --git a/demos/declarative/minehunt/pics/face-smile-big.png b/demos/declarative/minehunt/pics/face-smile-big.png
new file mode 100644
index 0000000..f9c2335
--- /dev/null
+++ b/demos/declarative/minehunt/pics/face-smile-big.png
Binary files differ
diff --git a/demos/declarative/minehunt/pics/face-smile.png b/demos/declarative/minehunt/pics/face-smile.png
new file mode 100644
index 0000000..3d66d72
--- /dev/null
+++ b/demos/declarative/minehunt/pics/face-smile.png
Binary files differ
diff --git a/demos/declarative/minehunt/pics/flag-color.png b/demos/declarative/minehunt/pics/flag-color.png
new file mode 100644
index 0000000..aadad0f
--- /dev/null
+++ b/demos/declarative/minehunt/pics/flag-color.png
Binary files differ
diff --git a/demos/declarative/minehunt/pics/flag.png b/demos/declarative/minehunt/pics/flag.png
new file mode 100644
index 0000000..39cde4d
--- /dev/null
+++ b/demos/declarative/minehunt/pics/flag.png
Binary files differ
diff --git a/demos/declarative/minehunt/pics/front.png b/demos/declarative/minehunt/pics/front.png
new file mode 100644
index 0000000..834331b
--- /dev/null
+++ b/demos/declarative/minehunt/pics/front.png
Binary files differ
diff --git a/demos/declarative/minehunt/pics/star.png b/demos/declarative/minehunt/pics/star.png
new file mode 100644
index 0000000..3772359
--- /dev/null
+++ b/demos/declarative/minehunt/pics/star.png
Binary files differ
diff --git a/demos/declarative/samegame/README b/demos/declarative/samegame/README
new file mode 100644
index 0000000..244b205
--- /dev/null
+++ b/demos/declarative/samegame/README
@@ -0,0 +1,10 @@
+This demo uses pictures from the KDE project (www.kde.org),
+specifically the images from the KSame game. These images are
+
+background.png
+blueStone.png
+redStone.png
+greenStone.png
+yellowStone.png
+
+and are presumably under the same GPL2 license as the rest of kdegames
diff --git a/demos/declarative/samegame/SameGame.qml b/demos/declarative/samegame/SameGame.qml
new file mode 100644
index 0000000..ede4362
--- /dev/null
+++ b/demos/declarative/samegame/SameGame.qml
@@ -0,0 +1,71 @@
+import Qt 4.6
+import "content"
+
+Rectangle {
+ id: Screen
+ width: 490; height: 720
+
+ Script { source: "content/samegame.js" }
+
+ SystemPalette { id: activePalette; colorGroup: Qt.Active }
+
+ Item {
+ width: parent.width; anchors.top: parent.top; anchors.bottom: ToolBar.top
+
+ Image {
+ id: background
+ anchors.fill: parent; source: "content/pics/background.png"
+ fillMode: "PreserveAspectCrop"
+ }
+
+ Item {
+ id: gameCanvas
+ property int score: 0
+
+ z: 20; anchors.centerIn: parent
+ width: parent.width - (parent.width % tileSize);
+ height: parent.height - (parent.height % tileSize);
+
+ MouseRegion {
+ id: gameMR
+ anchors.fill: parent; onClicked: handleClick(mouse.x,mouse.y);
+ }
+ }
+ }
+
+ Dialog { id: dialog; anchors.centerIn: parent; z: 21 }
+ Dialog {
+ id: scoreName; anchors.centerIn: parent; z: 22;
+ TextInput {
+ id: Editor
+ onAccepted: {
+ if(scoreName.opacity==1&&Editor.text!="")
+ sendHighScore(Editor.text);
+ scoreName.forceClose();
+ }
+ anchors.verticalCenter: parent.verticalCenter
+ width: 72; focus: true
+ anchors.right: scoreName.right
+ }
+ }
+
+ Rectangle {
+ id: ToolBar
+ color: activePalette.window
+ height: 32; width: parent.width
+ anchors.bottom: Screen.bottom
+
+ Button {
+ id: btnA; text: "New Game"; onClicked: {initBoard();}
+ anchors.left: parent.left; anchors.leftMargin: 3
+ anchors.verticalCenter: parent.verticalCenter
+ }
+
+ Text {
+ id: Score
+ text: "Score: " + gameCanvas.score; font.bold: true
+ anchors.right: parent.right; anchors.rightMargin: 3
+ anchors.verticalCenter: parent.verticalCenter
+ }
+ }
+}
diff --git a/demos/declarative/samegame/content/BoomBlock.qml b/demos/declarative/samegame/content/BoomBlock.qml
new file mode 100644
index 0000000..a495cd0
--- /dev/null
+++ b/demos/declarative/samegame/content/BoomBlock.qml
@@ -0,0 +1,54 @@
+import Qt 4.6
+
+Item { id:block
+ property bool dying: false
+ property bool spawned: false
+ property int type: 0
+ property int targetX: 0
+ property int targetY: 0
+
+ x: SpringFollow { enabled: spawned; source: targetX; spring: 2; damping: 0.2 }
+ y: SpringFollow { source: targetY; spring: 2; damping: 0.2 }
+
+ Image { id: img
+ source: {
+ if(type == 0){
+ "pics/redStone.png";
+ } else if(type == 1) {
+ "pics/blueStone.png";
+ } else {
+ "pics/greenStone.png";
+ }
+ }
+ opacity: 0
+ opacity: Behavior { NumberAnimation { properties:"opacity"; duration: 200 } }
+ anchors.fill: parent
+ }
+
+ Particles { id: particles
+ width:1; height:1; anchors.centerIn: parent; opacity: 0
+ lifeSpan: 700; lifeSpanDeviation: 600; count:0; streamIn: false
+ angle: 0; angleDeviation: 360; velocity: 100; velocityDeviation:30
+ source: {
+ if(type == 0){
+ "pics/redStar.png";
+ } else if (type == 1) {
+ "pics/blueStar.png";
+ } else {
+ "pics/greenStar.png";
+ }
+ }
+ }
+
+ states: [
+ State{ name: "AliveState"; when: spawned == true && dying == false
+ PropertyChanges { target: img; opacity: 1 }
+ },
+ State{ name: "DeathState"; when: dying == true
+ PropertyChanges { target: particles; count: 50 }
+ PropertyChanges { target: particles; opacity: 1 }
+ PropertyChanges { target: particles; emitting: false } // i.e. emit only once
+ PropertyChanges { target: img; opacity: 0 }
+ }
+ ]
+}
diff --git a/demos/declarative/samegame/content/Button.qml b/demos/declarative/samegame/content/Button.qml
new file mode 100644
index 0000000..2354218
--- /dev/null
+++ b/demos/declarative/samegame/content/Button.qml
@@ -0,0 +1,25 @@
+import Qt 4.6
+
+Rectangle {
+ id: Container
+
+ signal clicked
+ property string text: "Button"
+
+ color: activePalette.button; smooth: true
+ width: txtItem.width + 20; height: txtItem.height + 6
+ border.width: 1; border.color: activePalette.darker(activePalette.button); radius: 8;
+
+ gradient: Gradient {
+ GradientStop {
+ id: topGrad; position: 0.0
+ color: if (mr.pressed) { activePalette.dark } else { activePalette.light } }
+ GradientStop { position: 1.0; color: activePalette.button }
+ }
+
+ MouseRegion { id: mr; anchors.fill: parent; onClicked: Container.clicked() }
+
+ Text {
+ id: txtItem; text: Container.text; anchors.centerIn: Container; color: activePalette.buttonText
+ }
+}
diff --git a/demos/declarative/samegame/content/Dialog.qml b/demos/declarative/samegame/content/Dialog.qml
new file mode 100644
index 0000000..401d211
--- /dev/null
+++ b/demos/declarative/samegame/content/Dialog.qml
@@ -0,0 +1,21 @@
+import Qt 4.6
+
+Rectangle {
+ id: page
+ function forceClose() {
+ page.closed();
+ page.opacity = 0;
+ }
+ function show(txt) {
+ MyText.text = txt;
+ page.opacity = 1;
+ }
+ signal closed();
+ color: "white"; border.width: 1; width: MyText.width + 20; height: 60;
+ opacity: 0
+ opacity: Behavior {
+ NumberAnimation { duration: 1000 }
+ }
+ Text { id: MyText; anchors.centerIn: parent; text: "Hello World!" }
+ MouseRegion { id: mr; anchors.fill: parent; onClicked: forceClose(); }
+}
diff --git a/demos/declarative/samegame/content/pics/background.png b/demos/declarative/samegame/content/pics/background.png
new file mode 100644
index 0000000..25e885f
--- /dev/null
+++ b/demos/declarative/samegame/content/pics/background.png
Binary files differ
diff --git a/demos/declarative/samegame/content/pics/blueStar.png b/demos/declarative/samegame/content/pics/blueStar.png
new file mode 100644
index 0000000..ff9588f
--- /dev/null
+++ b/demos/declarative/samegame/content/pics/blueStar.png
Binary files differ
diff --git a/demos/declarative/samegame/content/pics/blueStone.png b/demos/declarative/samegame/content/pics/blueStone.png
new file mode 100644
index 0000000..bf342e0
--- /dev/null
+++ b/demos/declarative/samegame/content/pics/blueStone.png
Binary files differ
diff --git a/demos/declarative/samegame/content/pics/greenStar.png b/demos/declarative/samegame/content/pics/greenStar.png
new file mode 100644
index 0000000..cd06854
--- /dev/null
+++ b/demos/declarative/samegame/content/pics/greenStar.png
Binary files differ
diff --git a/demos/declarative/samegame/content/pics/greenStone.png b/demos/declarative/samegame/content/pics/greenStone.png
new file mode 100644
index 0000000..5ac14a5
--- /dev/null
+++ b/demos/declarative/samegame/content/pics/greenStone.png
Binary files differ
diff --git a/demos/declarative/samegame/content/pics/redStar.png b/demos/declarative/samegame/content/pics/redStar.png
new file mode 100644
index 0000000..0a4dffe
--- /dev/null
+++ b/demos/declarative/samegame/content/pics/redStar.png
Binary files differ
diff --git a/demos/declarative/samegame/content/pics/redStone.png b/demos/declarative/samegame/content/pics/redStone.png
new file mode 100644
index 0000000..b099f60
--- /dev/null
+++ b/demos/declarative/samegame/content/pics/redStone.png
Binary files differ
diff --git a/demos/declarative/samegame/content/pics/star.png b/demos/declarative/samegame/content/pics/star.png
new file mode 100644
index 0000000..defbde5
--- /dev/null
+++ b/demos/declarative/samegame/content/pics/star.png
Binary files differ
diff --git a/demos/declarative/samegame/content/pics/yellowStone.png b/demos/declarative/samegame/content/pics/yellowStone.png
new file mode 100644
index 0000000..c56124a
--- /dev/null
+++ b/demos/declarative/samegame/content/pics/yellowStone.png
Binary files differ
diff --git a/demos/declarative/samegame/content/samegame.js b/demos/declarative/samegame/content/samegame.js
new file mode 100755
index 0000000..0a3a4db
--- /dev/null
+++ b/demos/declarative/samegame/content/samegame.js
@@ -0,0 +1,241 @@
+/* This script file handles the game logic */
+//Note that X/Y referred to here are in game coordinates
+var maxX = 10;//Nums are for tileSize 40
+var maxY = 15;
+var tileSize = 40;
+var maxIndex = maxX*maxY;
+var board = new Array(maxIndex);
+var tileSrc = "content/BoomBlock.qml";
+var scoresURL = "http://qtfx-nokia.trolltech.com.au/samegame/scores.php";
+var timer;
+var component;
+
+//Index function used instead of a 2D array
+function index(xIdx,yIdx) {
+ return xIdx + (yIdx * maxX);
+}
+
+function timeStr(msecs) {
+ var secs = Math.floor(msecs/1000);
+ var m = Math.floor(secs/60);
+ var ret = "" + m + "m " + (secs%60) + "s";
+ return ret;
+}
+
+function initBoard()
+{
+ for(i = 0; i<maxIndex; i++){
+ //Delete old blocks
+ if(board[i] != null)
+ board[i].destroy();
+ }
+
+ maxX = Math.floor(gameCanvas.width/tileSize);
+ maxY = Math.floor(gameCanvas.height/tileSize);
+ maxIndex = maxY*maxX;
+
+ //Close dialogs
+ scoreName.forceClose();
+ dialog.forceClose();
+
+ //Initialize Board
+ board = new Array(maxIndex);
+ gameCanvas.score = 0;
+ for(xIdx=0; xIdx<maxX; xIdx++){
+ for(yIdx=0; yIdx<maxY; yIdx++){
+ board[index(xIdx,yIdx)] = null;
+ startCreatingBlock(xIdx,yIdx);
+ }
+ }
+ timer = new Date();
+}
+
+var fillFound;//Set after a floodFill call to the number of tiles found
+var floodBoard;//Set to 1 if the floodFill reaches off that node
+//NOTE: Be careful with vars named x,y, as the calling object's x,y are still in scope
+function handleClick(x,y)
+{
+ xIdx = Math.floor(x/tileSize);
+ yIdx = Math.floor(y/tileSize);
+ if(xIdx >= maxX || xIdx < 0 || yIdx >= maxY || yIdx < 0)
+ return;
+ if(board[index(xIdx, yIdx)] == null)
+ return;
+ //If it's a valid tile, remove it and all connected (does nothing if it's not connected)
+ floodFill(xIdx,yIdx, -1);
+ if(fillFound <= 0)
+ return;
+ gameCanvas.score += (fillFound - 1) * (fillFound - 1);
+ shuffleDown();
+ victoryCheck();
+}
+
+function floodFill(xIdx,yIdx,type)
+{
+ if(board[index(xIdx, yIdx)] == null)
+ return;
+ var first = false;
+ if(type == -1){
+ first = true;
+ type = board[index(xIdx,yIdx)].type;
+
+ //Flood fill initialization
+ fillFound = 0;
+ floodBoard = new Array(maxIndex);
+ }
+ if(xIdx >= maxX || xIdx < 0 || yIdx >= maxY || yIdx < 0)
+ return;
+ if(floodBoard[index(xIdx, yIdx)] == 1 || (!first && type != board[index(xIdx,yIdx)].type))
+ return;
+ floodBoard[index(xIdx, yIdx)] = 1;
+ floodFill(xIdx+1,yIdx,type);
+ floodFill(xIdx-1,yIdx,type);
+ floodFill(xIdx,yIdx+1,type);
+ floodFill(xIdx,yIdx-1,type);
+ if(first==true && fillFound == 0)
+ return;//Can't remove single tiles
+ board[index(xIdx,yIdx)].dying = true;
+ board[index(xIdx,yIdx)] = null;
+ fillFound += 1;
+}
+
+function shuffleDown()
+{
+ //Fall down
+ for(xIdx=0; xIdx<maxX; xIdx++){
+ fallDist = 0;
+ for(yIdx=maxY-1; yIdx>=0; yIdx--){
+ if(board[index(xIdx,yIdx)] == null){
+ fallDist += 1;
+ }else{
+ if(fallDist > 0){
+ obj = board[index(xIdx,yIdx)];
+ obj.targetY += fallDist * tileSize;
+ board[index(xIdx,yIdx+fallDist)] = obj;
+ board[index(xIdx,yIdx)] = null;
+ }
+ }
+ }
+ }
+ //Fall to the left
+ fallDist = 0;
+ for(xIdx=0; xIdx<maxX; xIdx++){
+ if(board[index(xIdx, maxY - 1)] == null){
+ fallDist += 1;
+ }else{
+ if(fallDist > 0){
+ for(yIdx=0; yIdx<maxY; yIdx++){
+ obj = board[index(xIdx,yIdx)];
+ if(obj == null)
+ continue;
+ obj.targetX -= fallDist * tileSize;
+ board[index(xIdx-fallDist,yIdx)] = obj;
+ board[index(xIdx,yIdx)] = null;
+ }
+ }
+ }
+ }
+}
+
+function victoryCheck()
+{
+ //awards bonuses for no tiles left
+ deservesBonus = true;
+ for(xIdx=maxX-1; xIdx>=0; xIdx--)
+ if(board[index(xIdx, maxY - 1)] != null)
+ deservesBonus = false;
+ if(deservesBonus)
+ gameCanvas.score += 500;
+ //Checks for game over
+ if(deservesBonus || !(floodMoveCheck(0,maxY-1, -1))){
+ timer = new Date() - timer;
+ if(scoresURL != "")
+ scoreName.show("You've won! Please enter your name: ");
+ else
+ dialog.show("Game Over. Your score is " + gameCanvas.score);
+ }
+}
+
+//only floods up and right, to see if it can find adjacent same-typed tiles
+function floodMoveCheck(xIdx, yIdx, type)
+{
+ if(xIdx >= maxX || xIdx < 0 || yIdx >= maxY || yIdx < 0)
+ return false;
+ if(board[index(xIdx, yIdx)] == null)
+ return false;
+ myType = board[index(xIdx, yIdx)].type;
+ if(type == myType)
+ return true;
+ return floodMoveCheck(xIdx + 1, yIdx, myType) ||
+ floodMoveCheck(xIdx, yIdx - 1, board[index(xIdx,yIdx)].type);
+}
+
+//If the component isn't ready, then the signal doesn't include the game x,y
+//So we store any x,y sent that we couldn't create at the time, and use those
+//if we are triggered by the signal.
+var waitStack = new Array(maxIndex);
+var waitTop = -1;
+
+function finishCreatingBlock(xIdx,yIdx){
+ if(component.isReady){
+ if(xIdx == undefined){
+ //Called without arguments, create a previously stored (xIdx,yIdx)
+ if(waitTop == -1)
+ return;//Don't have a previously stored (xIdx,yIdx)
+ xIdx = waitStack[waitTop] % maxX;
+ yIdx = Math.floor(waitStack[waitTop] / maxX);
+ waitTop -= 1;
+ }
+ dynamicObject = component.createObject();
+ if(dynamicObject == null){
+ print("error creating block");
+ print(component.errorsString());
+ return false;
+ }
+ dynamicObject.type = Math.floor(Math.random() * 3);
+ dynamicObject.parent = gameCanvas;
+ dynamicObject.x = xIdx*tileSize;
+ dynamicObject.targetX = xIdx*tileSize;
+ dynamicObject.targetY = yIdx*tileSize;
+ dynamicObject.width = tileSize;
+ dynamicObject.height = tileSize;
+ dynamicObject.spawned = true;
+ board[index(xIdx,yIdx)] = dynamicObject;
+ return true;
+ }else if(component.isError){
+ print("error creating block");
+ print(component.errorsString());
+ }else{
+ //It isn't ready, but we'll be called again when it is.
+ //So store the requested (xIdx,yIdx) for later use
+ waitTop += 1;
+ waitStack[waitTop] = index(xIdx,yIdx);
+ }
+ return false;
+}
+
+function startCreatingBlock(xIdx,yIdx){
+ if(component!=null){
+ finishCreatingBlock(xIdx,yIdx);
+ return;
+ }
+
+ component = createComponent(tileSrc);
+ if(finishCreatingBlock(xIdx,yIdx))
+ return;
+ component.statusChanged.connect(finishCreatingBlock());
+ return;
+}
+
+function sendHighScore(name) {
+ var postman = new XMLHttpRequest()
+ var postData = "name="+name+"&score="+gameCanvas.score
+ +"&gridSize="+maxX+"x"+maxY +"&time="+Math.floor(timer/1000);
+ postman.open("POST", scoresURL, true);
+ postman.onreadystatechange = function() {
+ if (postman.readyState == postman.DONE) {
+ dialog.show("Your score has been uploaded.");
+ }
+ }
+ postman.send(postData);
+}
diff --git a/demos/declarative/samegame/highscores/README b/demos/declarative/samegame/highscores/README
new file mode 100644
index 0000000..eaa00fa
--- /dev/null
+++ b/demos/declarative/samegame/highscores/README
@@ -0,0 +1 @@
+The SameGame example can interface with a simple PHP script to store XML high score data on a remote server. We do not have a publically accessible server available for this use, but if you have access to a PHP capable webserver you can copy the files (score_data.xml, score.php, score_style.xsl) to it and alter the highscore_server variable at the top of the samegame.js file to point to it.
diff --git a/demos/declarative/samegame/highscores/score_data.xml b/demos/declarative/samegame/highscores/score_data.xml
new file mode 100755
index 0000000..c3fd90d
--- /dev/null
+++ b/demos/declarative/samegame/highscores/score_data.xml
@@ -0,0 +1,2 @@
+<record><score>1000000</score><name>Alan the Tester</name><gridSize>0x0</gridSize><seconds>0</seconds></record>
+<record><score>6213</score><name>Alan</name><gridSize>12x17</gridSize><seconds>51</seconds></record>
diff --git a/demos/declarative/samegame/highscores/score_style.xsl b/demos/declarative/samegame/highscores/score_style.xsl
new file mode 100755
index 0000000..670354c
--- /dev/null
+++ b/demos/declarative/samegame/highscores/score_style.xsl
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+<xsl:template match="/">
+ <html>
+ <head><title>SameGame High Scores</title></head>
+ <body>
+ <h2>SameGame High Scores</h2>
+ <table border="1">
+ <tr bgcolor="lightsteelblue">
+ <th>Name</th>
+ <th>Score</th>
+ <th>Grid Size</th>
+ <th>Time, s</th>
+ </tr>
+ <xsl:for-each select="records/record">
+ <xsl:sort select="score" data-type="number" order="descending"/>
+ <tr>
+ <td><xsl:value-of select="name"/></td>
+ <td><xsl:value-of select="score"/></td>
+ <td><xsl:value-of select="gridSize"/></td>
+ <td><xsl:value-of select="seconds"/></td>
+ </tr>
+ </xsl:for-each>
+ </table>
+ </body>
+ </html>
+</xsl:template>
+</xsl:stylesheet>
diff --git a/demos/declarative/samegame/highscores/scores.php b/demos/declarative/samegame/highscores/scores.php
new file mode 100755
index 0000000..3cceb2d
--- /dev/null
+++ b/demos/declarative/samegame/highscores/scores.php
@@ -0,0 +1,34 @@
+<?php
+ $score = $_POST["score"];
+ echo "<html>";
+ echo "<head><title>SameGame High Scores</title></head><body>";
+ if($score > 0){#Sending in a new high score
+ $name = $_POST["name"];
+ $grid = $_POST["gridSize"];
+ $time = $_POST["time"];
+ if($name == "")
+ $name = "Anonymous";
+ //if($grid != "10x10"){
+ //Need a standard, so as to reject others?
+ //}
+ $file = fopen("score_data.xml", "a"); #It's XML. Happy?
+ $ret = fwrite($file, "<record><score>". $score . "</score><name>"
+ . $name . "</name><gridSize>" . $grid . "</gridSize><seconds>"
+ . $time . "</seconds></record>\n");
+ echo "Your score has been recorded. Thanks for playing!";
+ if($ret == False)
+ echo "<br/> There was an error though, so don't expect to see that score again.";
+ }else{#Read high score list
+ #Now uses XSLT to display. So just print the file. With XML cruft added.
+ #Note that firefox at least won't apply the XSLT on a php file. So redirecting
+ $file = fopen("scores.xml", "w");
+ $ret = fwrite($file, '<?xml version="1.0" encoding="ISO-8859-1"?>' . "\n"
+ . '<?xml-stylesheet type="text/xsl" href="score_style.xsl"?>' . "\n"
+ . "<records>\n" . file_get_contents("score_data.xml") . "</records>\n");
+ if($ret == False)
+ echo "There was an internal error. Sorry.";
+ else
+ echo '<script type="text/javascript">window.location.replace("scores.xml")</script>';
+ }
+ echo "</body></html>";
+?>
diff --git a/demos/declarative/twitter/content/AuthView.qml b/demos/declarative/twitter/content/AuthView.qml
new file mode 100644
index 0000000..3fe7e7e
--- /dev/null
+++ b/demos/declarative/twitter/content/AuthView.qml
@@ -0,0 +1,86 @@
+import Qt 4.6
+import "../../flickr/common"
+import "../../flickr/mobile"
+
+Item {
+ id: wrapper
+ Column {
+ anchors.centerIn: parent
+ spacing: 20
+ Row{
+ spacing: 4
+ Text {
+ width: 100
+ text: "Screen name:"
+ font.pointSize: 10; font.bold: true; color: "white"; style: "Raised"; styleColor: "black"
+ anchors.verticalCenter: parent.verticalCenter
+ horizontalAlignment: Qt.AlignRight
+ }
+ Item {
+ width: 160
+ height: 28
+ BorderImage { source: "../../flickr/mobile/images/lineedit.sci"; anchors.fill: parent }
+ TextInput{
+ id: nameIn
+ width: parent.width - 8
+ height: parent.height - 12
+ anchors.centerIn: parent
+ maximumLength:21
+ font.bold: true
+ color: "#151515"; selectionColor: "green"
+ Keys.forwardTo: [(tabber), (nameIn)]
+ Item {
+ id: tabber
+ //Note: it's not working yet
+ Keys.onPressed: {if(event.key == Qt.Key_Tab){print('Tab works!'); passIn.focus = true; accept(); }}
+ }
+ }
+ }
+ }
+ Row{
+ spacing: 4
+ Text {
+ width: 100
+ text: "Password:"
+ font.pointSize: 10; font.bold: true; color: "white"; style: "Raised"; styleColor: "black"
+ anchors.verticalCenter: parent.verticalCenter
+ horizontalAlignment: Qt.AlignRight
+ }
+ Item {
+ width: 160
+ height: 28
+ BorderImage { source: "../../flickr/mobile/images/lineedit.sci"; anchors.fill: parent }
+ TextInput{
+ id: passIn
+ width: parent.width - 8
+ height: parent.height - 12
+ anchors.centerIn: parent
+ maximumLength:21
+ echoMode: TextInput.Password
+ font.bold: true
+ color: "#151515"; selectionColor: "green"
+ }
+ }
+ }
+ Item{
+ width: childrenRect.width; height:childrenRect.height;
+ anchors.horizontalCenter: parent.horizontalCenter
+ Button {
+ x: 10
+ width: 100
+ height: 32
+ id: login
+ text: "Log in"
+ onClicked: {RssModel.authName=nameIn.text; RssModel.authPass=passIn.text; RssModel.tags='my timeline';}
+ }
+ Button {
+ x: 120
+ width: 100
+ height: 32
+ id: guest
+ text: "Guest"
+ onClicked: {RssModel.authName='-'; Screen.setMode(true);}
+ }
+ }
+ }
+}
diff --git a/demos/declarative/twitter/content/FatDelegate.qml b/demos/declarative/twitter/content/FatDelegate.qml
new file mode 100644
index 0000000..a2e9c39
--- /dev/null
+++ b/demos/declarative/twitter/content/FatDelegate.qml
@@ -0,0 +1,47 @@
+import Qt 4.6
+import "../../flickr/common"
+
+Component {
+ id: ListDelegate
+ Item {
+ id: Wrapper; width: Wrapper.ListView.view.width; height: if(txt.height > 58){txt.height+8}else{58}//50+4+4
+ Script {
+ function handleLink(link){
+ if(link.slice(0,3) == 'app'){
+ setUser(link.slice(7));
+ Screen.setMode(true);
+ }else if(link.slice(0,4) == 'http'){
+ Qt.DesktopServices.openUrl(link);
+ }
+ }
+ function addTags(str){
+ ret = str.replace(/@[a-zA-Z0-9_]+/g, '<a href="app://$&">$&</a>');//click to jump to user?
+ ret2 = ret.replace(/http:\/\/[^ \n\t]+/g, '<a href="$&">$&</a>');//surrounds http links with html link tags
+ return ret2;
+ }
+ }
+ Item {
+ id: MoveMe; height: parent.height
+ Rectangle {
+ id: BlackRect
+ color: "black"; opacity: Wrapper.ListView.index % 2 ? 0.2 : 0.3; height: Wrapper.height-2; width: Wrapper.width; y: 1
+ }
+ Rectangle {
+ id: WhiteRect; x: 6; width: 50; height: 50; color: "white"; smooth: true
+ anchors.verticalCenter: parent.verticalCenter
+
+ Loading { x: 1; y: 1; width: 48; height: 48; visible: RealImage.status != 1 }
+ Image { id: RealImage; source: userImage; x: 1; y: 1; width:48; height:48 }
+ }
+ Text { id:txt; y:4; x: 56
+ text: '<html><style type="text/css">a:link {color:"#aaccaa"}; a:visited {color:"#336633"}</style>'
+ + '<a href="app://@'+userScreenName+'"><b>'+userScreenName + "</b></a> from " +source
+ + "<br /><b>" + addTags(statusText) + "</b></html>";
+ textFormat: Qt.RichText
+ color: "white"; color: "#cccccc"; style: "Raised"; styleColor: "black"; wrap: true
+ anchors.left: WhiteRect.right; anchors.right: BlackRect.right; anchors.leftMargin: 6; anchors.rightMargin: 6
+ onLinkActivated: handleLink(link)
+ }
+ }
+ }
+}
diff --git a/demos/declarative/twitter/content/HomeTitleBar.qml b/demos/declarative/twitter/content/HomeTitleBar.qml
new file mode 100644
index 0000000..bd3bc2c
--- /dev/null
+++ b/demos/declarative/twitter/content/HomeTitleBar.qml
@@ -0,0 +1,122 @@
+import Qt 4.6
+import "../../flickr/mobile"
+import "../../flickr/common"
+
+Item {
+ id: titleBar
+
+ signal update()
+ onYChanged: state="" //When switching titlebars
+
+ BorderImage { source: "../../flickr/mobile/images/titlebar.sci"; width: parent.width; height: parent.height + 14; y: -7 }
+ Item {
+ id: Container
+ width: (parent.width * 2) - 55 ; height: parent.height
+
+ Script {
+ function accept() {
+ if(RssModel.authName == '' || RssModel.authPass == '')
+ return false;//Can't login like that
+
+ var postData = "status=" + Editor.text;
+ var postman = new XMLHttpRequest();
+ postman.open("POST", "http://twitter.com/statuses/update.xml", true, RssModel.authName, RssModel.authPass);
+ postman.onreadystatechange = function() {
+ if (postman.readyState == postman.DONE) {
+ titleBar.update();
+ }
+ }
+ postman.send(postData);
+
+ Editor.text = ""
+ titleBar.state = ""
+ }
+ }
+
+ Rectangle {
+ id: WhiteRect; x: 6; width: 50; height: 50; color: "white"; smooth: true
+ anchors.verticalCenter: parent.verticalCenter
+
+ UserModel { user: RssModel.authName; id: userModel }
+ Component { id: imgDelegate;
+ Item { id: Wrapper
+ Loading { width:48; height:48; visible: realImage.status != 1 }
+ Image { source: image; width:48; height:48; id: realImage }
+ }
+ }
+ ListView { model: userModel.model; x:1; y:1; delegate: imgDelegate }
+ }
+
+ Text {
+ id: CategoryText
+ anchors.left: parent.left; anchors.right: TagButton.left
+ anchors.leftMargin: 58; anchors.rightMargin: 10
+ anchors.verticalCenter: parent.verticalCenter
+ elide: "ElideLeft"
+ text: "Timeline for " + RssModel.authName
+ font.pointSize: 10; font.bold: true; color: "white"; style: "Raised"; styleColor: "black"
+ }
+
+ Button {
+ id: TagButton; x: titleBar.width - 90; width: 85; height: 32; text: "New Post..."
+ anchors.verticalCenter: parent.verticalCenter;
+ onClicked: if (titleBar.state == "Posting") accept(); else titleBar.state = "Posting"
+ }
+
+ Text {
+ id: charsLeftText; anchors.horizontalCenter: TagButton.horizontalCenter;
+ anchors.top: TagButton.bottom; anchors.topMargin: 2
+ text: {140 - Editor.text.length;} visible: titleBar.state == "Posting"
+ font.pointSize: 10; font.bold: true; color: "white"; style: "Raised"; styleColor: "black"
+ }
+ Item {
+ id: txtEdit;
+ anchors.left: TagButton.right; anchors.leftMargin: 5; y: 4
+ anchors.right: parent.right; anchors.rightMargin: 40; height: parent.height - 9
+ BorderImage { source: "../../flickr/mobile/images/lineedit.sci"; anchors.fill: parent }
+
+ Binding {//TODO: Can this be a function, which also resets the cursor? And flashes?
+ when: Editor.text.length > 140
+ target: Editor
+ property: "text"
+ value: Editor.text.slice(0,140)
+ }
+ TextEdit {
+ id: Editor
+ anchors.left: parent.left;
+ anchors.leftMargin: 8;
+ anchors.bottom: parent.bottom
+ anchors.bottomMargin: 4;
+ cursorVisible: true; font.bold: true
+ width: parent.width - 12
+ height: parent.height - 8
+ font.pointSize: 10
+ wrap:true
+ color: "#151515"; selectionColor: "green"
+ }
+ Keys.forwardTo: [(ReturnKey), (Editor)]
+ Item {
+ id: ReturnKey
+ Keys.onReturnPressed: accept()
+ Keys.onEscapePressed: titleBar.state = ""
+ }
+ }
+ }
+ states: [
+ State {
+ name: "Posting"
+ PropertyChanges { target: Container; x: -TagButton.x + 5 }
+ PropertyChanges { target: titleBar; height: 80 }
+ PropertyChanges { target: TagButton; text: "OK" }
+ PropertyChanges { target: TagButton; width: 28 }
+ PropertyChanges { target: TagButton; height: 24 }
+ PropertyChanges { target: txtEdit; focus: true }
+ }
+ ]
+ transitions: [
+ Transition {
+ from: "*"; to: "*"
+ NumberAnimation { properties: "x,y,width,height"; easing: "easeInOutQuad" }
+ }
+ ]
+}
diff --git a/demos/declarative/twitter/content/MultiTitleBar.qml b/demos/declarative/twitter/content/MultiTitleBar.qml
new file mode 100644
index 0000000..6a6a28f
--- /dev/null
+++ b/demos/declarative/twitter/content/MultiTitleBar.qml
@@ -0,0 +1,25 @@
+import Qt 4.6
+import "../../flickr/mobile"
+
+Item {
+ height: HomeBar.height
+ HomeTitleBar { id: HomeBar; width: parent.width; height: 60;
+ onUpdate: RssModel.reload()
+ }
+ TitleBar { id: TitleBar; width: parent.width; height: 60;
+ y: -80
+ untaggedString: "Latest tweets from everyone"
+ taggedString: "Latest tweets from "
+ }
+ states: [
+ State {
+ name: "search"; when: Screen.userView
+ PropertyChanges { target: TitleBar; y: 0 }
+ PropertyChanges { target: HomeBar; y: -80 }
+ }
+ ]
+ transitions: [
+ Transition { NumberAnimation { properties: "x,y"; duration: 500; easing: "easeInOutQuad" } }
+ ]
+}
+
diff --git a/demos/declarative/twitter/content/RssModel.qml b/demos/declarative/twitter/content/RssModel.qml
new file mode 100644
index 0000000..144d7af
--- /dev/null
+++ b/demos/declarative/twitter/content/RssModel.qml
@@ -0,0 +1,42 @@
+import Qt 4.6
+
+Item { id: wrapper
+ property var model: xmlModel
+ property string tags : ""
+ property string authName : ""
+ property string authPass : ""
+ property string mode : "everyone"
+ property int status: xmlModel.status
+ function reload() { xmlModel.reload(); }
+XmlListModel {
+ id: xmlModel
+
+ source: if (wrapper.authName == ""){
+ ""; //Avoid worthless calls to twitter servers
+ }else if(wrapper.mode == 'user'){
+ "https://"+ ((wrapper.authName!="" && wrapper.authPass!="")? (wrapper.authName+":"+wrapper.authPass+"@") : "" )+"twitter.com/statuses/user_timeline.xml?screen_name="+wrapper.tags;
+ }else if(wrapper.mode == 'self'){
+ "https://"+ ((wrapper.authName!="" && wrapper.authPass!="")? (wrapper.authName+":"+wrapper.authPass+"@") : "" )+"twitter.com/statuses/friends_timeline.xml";
+ }else{//everyone/public
+ "http://twitter.com/statuses/public_timeline.xml";
+ }
+ query: "/statuses/status"
+
+ XmlRole { name: "statusText"; query: "text/string()" }
+ XmlRole { name: "timestamp"; query: "created_at/string()" }
+ XmlRole { name: "source"; query: "source/string()" }
+ XmlRole { name: "userName"; query: "user/name/string()" }
+ XmlRole { name: "userScreenName"; query: "user/screen_name/string()" }
+ XmlRole { name: "userImage"; query: "user/profile_image_url/string()" }
+ XmlRole { name: "userLocation"; query: "user/location/string()" }
+ XmlRole { name: "userDescription"; query: "user/description/string()" }
+ XmlRole { name: "userFollowers"; query: "user/followers_count/string()" }
+ XmlRole { name: "userStatuses"; query: "user/statuses_count/string()" }
+ //TODO: Could also get the user's color scheme, timezone and a few other things
+}
+Binding {
+ property: "mode"
+ target: wrapper
+ value: {if(wrapper.tags==''){"everyone";}else if(wrapper.tags=='my timeline'){"self";}else{"user";}}
+}
+}
diff --git a/demos/declarative/twitter/content/UserModel.qml b/demos/declarative/twitter/content/UserModel.qml
new file mode 100644
index 0000000..c146b84
--- /dev/null
+++ b/demos/declarative/twitter/content/UserModel.qml
@@ -0,0 +1,26 @@
+import Qt 4.6
+
+//This "model" gets the user information about the searched user. Mainly for the icon.
+//Copied from RssModel
+
+Item { id: wrapper
+ property var model: xmlModel
+ property string user : ""
+ property int status: xmlModel.status
+ function reload() { xmlModel.reload(); }
+XmlListModel {
+ id: xmlModel
+
+ source: {if(user!="") {"http://twitter.com/users/show.xml?screen_name="+user;}else{"";}}
+ query: "/user"
+
+ XmlRole { name: "name"; query: "name/string()" }
+ XmlRole { name: "screenName"; query: "screen_name/string()" }
+ XmlRole { name: "image"; query: "profile_image_url/string()" }
+ XmlRole { name: "location"; query: "location/string()" }
+ XmlRole { name: "description"; query: "description/string()" }
+ XmlRole { name: "followers"; query: "followers_count/string()" }
+ //XmlRole { name: "protected"; query: "protected/bool()" }
+ //TODO: Could also get the user's color scheme, timezone and a few other things
+}
+}
diff --git a/demos/declarative/twitter/twitter.qml b/demos/declarative/twitter/twitter.qml
new file mode 100644
index 0000000..eb9f5d6
--- /dev/null
+++ b/demos/declarative/twitter/twitter.qml
@@ -0,0 +1,95 @@
+import Qt 4.6
+import "content" as Twitter
+import "../flickr/common" as Common
+import "../flickr/mobile" as Mobile
+
+Item {
+ id: Screen; width: 320; height: 480
+ property bool userView : false
+ function setMode(m){
+ Screen.userView = m;
+ if(m == false){
+ RssModel.tags='my timeline';
+ RssModel.reload();
+ ToolBar.button2Label = "View others";
+ } else {
+ ToolBar.button2Label = "Return home";
+ }
+ }
+ //Workaround for bug 260266
+ Timer{ interval: 1; running: false; repeat: false; onTriggered: reallySetUser(); id:hack }
+ Script{
+ var tmpStr;
+ function setUser(str){hack.running = true; tmpStr = str}
+ function reallySetUser(){RssModel.tags = tmpStr;}
+ }
+
+ Rectangle {
+ id: Background
+ anchors.fill: parent; color: "#343434";
+
+ Image { source: "mobile/images/stripes.png"; fillMode: "Tile"; anchors.fill: parent; opacity: 0.3 }
+
+ Twitter.RssModel { id: RssModel }
+ Common.Loading { anchors.centerIn: parent; visible: RssModel.status==XmlListModel.Loading && state!='unauthed'}
+ Text {
+ width: 180
+ text: "Could not access twitter using this screen name and password pair.";
+ color: "white"; color: "#cccccc"; style: "Raised"; styleColor: "black"; wrap: true
+ visible: RssModel.status==XmlListModel.Error; anchors.centerIn: parent
+ }
+
+ Item {
+ id: Views
+ x: 2; width: parent.width - 4
+ y:60 //Below the title bars
+ height: 380
+
+ Twitter.AuthView{
+ id: authView
+ anchors.verticalCenter: parent.verticalCenter
+ width: parent.width; height: parent.height-60;
+ x: -(Screen.width * 1.5)
+ }
+
+ Twitter.FatDelegate { id: FatDelegate }
+ ListView {
+ id: MainView; model: RssModel.model; delegate: FatDelegate;
+ width: parent.width; height: parent.height; x: 0; cacheBuffer: 100;
+ }
+ }
+
+ Twitter.MultiTitleBar { id: TitleBar; width: parent.width }
+ Mobile.ToolBar { id: ToolBar; height: 40;
+ //anchors.bottom: parent.bottom;
+ //TODO: Use anchor changes instead of hard coding
+ y: 440
+ width: parent.width; opacity: 0.9
+ button1Label: "Update"
+ button2Label: "View others"
+ onButton1Clicked: RssModel.reload();
+ onButton2Clicked:
+ {
+ if(Screen.userView == true){
+ Screen.setMode(false);
+ }else{
+ RssModel.tags='';
+ Screen.setMode(true);
+ }
+ }
+ }
+
+ states: [
+ State {
+ name: "unauthed"; when: RssModel.authName==""
+ PropertyChanges { target: authView; x: 0 }
+ PropertyChanges { target: MainView; x: -(parent.width * 1.5) }
+ PropertyChanges { target: TitleBar; y: -80 }
+ PropertyChanges { target: ToolBar; y: Screen.height + 80 }
+ }
+ ]
+ transitions: [
+ Transition { NumberAnimation { properties: "x,y"; duration: 500; easing: "easeInOutQuad" } }
+ ]
+ }
+}
diff --git a/demos/declarative/webbrowser/content/RectSoftShadow.qml b/demos/declarative/webbrowser/content/RectSoftShadow.qml
new file mode 100644
index 0000000..5b278ac
--- /dev/null
+++ b/demos/declarative/webbrowser/content/RectSoftShadow.qml
@@ -0,0 +1,32 @@
+import Qt 4.6
+
+Item {
+ BorderImage {
+ source: "pics/softshadow-left.sci"
+ x: -16
+ y: -16
+ width: 16
+ height: parent.height+32
+ }
+ BorderImage {
+ source: "pics/softshadow-right.sci"
+ x: parent.width
+ y: -16
+ width: 16
+ height: parent.height+32
+ }
+ Image {
+ source: "pics/softshadow-top.png"
+ x: 0
+ y: -16
+ width: parent.width
+ height: 16
+ }
+ Image {
+ source: "pics/softshadow-bottom.png"
+ x: 0
+ y: parent.height
+ width: WebView.width*WebView.scale
+ height: 16
+ }
+}
diff --git a/demos/declarative/webbrowser/content/pics/addressbar-filled.png b/demos/declarative/webbrowser/content/pics/addressbar-filled.png
new file mode 100644
index 0000000..d8452ec
--- /dev/null
+++ b/demos/declarative/webbrowser/content/pics/addressbar-filled.png
Binary files differ
diff --git a/demos/declarative/webbrowser/content/pics/addressbar-filled.sci b/demos/declarative/webbrowser/content/pics/addressbar-filled.sci
new file mode 100644
index 0000000..464dbf5
--- /dev/null
+++ b/demos/declarative/webbrowser/content/pics/addressbar-filled.sci
@@ -0,0 +1,6 @@
+gridLeft: 7
+gridTop: 7
+gridBottom: 7
+gridRight: 7
+imageFile: addressbar-filled.png
+
diff --git a/demos/declarative/webbrowser/content/pics/addressbar.png b/demos/declarative/webbrowser/content/pics/addressbar.png
new file mode 100644
index 0000000..3278f58
--- /dev/null
+++ b/demos/declarative/webbrowser/content/pics/addressbar.png
Binary files differ
diff --git a/demos/declarative/webbrowser/content/pics/addressbar.sci b/demos/declarative/webbrowser/content/pics/addressbar.sci
new file mode 100644
index 0000000..23a2a19
--- /dev/null
+++ b/demos/declarative/webbrowser/content/pics/addressbar.sci
@@ -0,0 +1,6 @@
+gridLeft: 7
+gridTop: 7
+gridBottom: 7
+gridRight: 7
+imageFile: addressbar.png
+
diff --git a/demos/declarative/webbrowser/content/pics/back-disabled.png b/demos/declarative/webbrowser/content/pics/back-disabled.png
new file mode 100644
index 0000000..91b9e76
--- /dev/null
+++ b/demos/declarative/webbrowser/content/pics/back-disabled.png
Binary files differ
diff --git a/demos/declarative/webbrowser/content/pics/back.png b/demos/declarative/webbrowser/content/pics/back.png
new file mode 100644
index 0000000..9988dd3
--- /dev/null
+++ b/demos/declarative/webbrowser/content/pics/back.png
Binary files differ
diff --git a/demos/declarative/webbrowser/content/pics/footer.png b/demos/declarative/webbrowser/content/pics/footer.png
new file mode 100644
index 0000000..8391a93
--- /dev/null
+++ b/demos/declarative/webbrowser/content/pics/footer.png
Binary files differ
diff --git a/demos/declarative/webbrowser/content/pics/footer.sci b/demos/declarative/webbrowser/content/pics/footer.sci
new file mode 100644
index 0000000..be1d086
--- /dev/null
+++ b/demos/declarative/webbrowser/content/pics/footer.sci
@@ -0,0 +1,6 @@
+gridLeft: 5
+gridTop: 0
+gridBottom: 0
+gridRight: 5
+imageFile: footer.png
+
diff --git a/demos/declarative/webbrowser/content/pics/forward-disabled.png b/demos/declarative/webbrowser/content/pics/forward-disabled.png
new file mode 100644
index 0000000..cb87f4f
--- /dev/null
+++ b/demos/declarative/webbrowser/content/pics/forward-disabled.png
Binary files differ
diff --git a/demos/declarative/webbrowser/content/pics/forward.png b/demos/declarative/webbrowser/content/pics/forward.png
new file mode 100644
index 0000000..83870ee
--- /dev/null
+++ b/demos/declarative/webbrowser/content/pics/forward.png
Binary files differ
diff --git a/demos/declarative/webbrowser/content/pics/header.png b/demos/declarative/webbrowser/content/pics/header.png
new file mode 100644
index 0000000..26588c3
--- /dev/null
+++ b/demos/declarative/webbrowser/content/pics/header.png
Binary files differ
diff --git a/demos/declarative/webbrowser/content/pics/reload.png b/demos/declarative/webbrowser/content/pics/reload.png
new file mode 100644
index 0000000..45b5535
--- /dev/null
+++ b/demos/declarative/webbrowser/content/pics/reload.png
Binary files differ
diff --git a/demos/declarative/webbrowser/content/pics/softshadow-bottom.png b/demos/declarative/webbrowser/content/pics/softshadow-bottom.png
new file mode 100644
index 0000000..85b0b44
--- /dev/null
+++ b/demos/declarative/webbrowser/content/pics/softshadow-bottom.png
Binary files differ
diff --git a/demos/declarative/webbrowser/content/pics/softshadow-left.png b/demos/declarative/webbrowser/content/pics/softshadow-left.png
new file mode 100644
index 0000000..02926d1
--- /dev/null
+++ b/demos/declarative/webbrowser/content/pics/softshadow-left.png
Binary files differ
diff --git a/demos/declarative/webbrowser/content/pics/softshadow-left.sci b/demos/declarative/webbrowser/content/pics/softshadow-left.sci
new file mode 100644
index 0000000..82e38f8
--- /dev/null
+++ b/demos/declarative/webbrowser/content/pics/softshadow-left.sci
@@ -0,0 +1,5 @@
+gridLeft: 0
+gridTop: 16
+gridBottom: 16
+gridRight: 0
+imageFile: softshadow-left.png
diff --git a/demos/declarative/webbrowser/content/pics/softshadow-right.png b/demos/declarative/webbrowser/content/pics/softshadow-right.png
new file mode 100644
index 0000000..e459f4f
--- /dev/null
+++ b/demos/declarative/webbrowser/content/pics/softshadow-right.png
Binary files differ
diff --git a/demos/declarative/webbrowser/content/pics/softshadow-right.sci b/demos/declarative/webbrowser/content/pics/softshadow-right.sci
new file mode 100644
index 0000000..e9494ed
--- /dev/null
+++ b/demos/declarative/webbrowser/content/pics/softshadow-right.sci
@@ -0,0 +1,5 @@
+gridLeft: 0
+gridTop: 16
+gridBottom: 16
+gridRight: 0
+imageFile: softshadow-right.png
diff --git a/demos/declarative/webbrowser/content/pics/softshadow-top.png b/demos/declarative/webbrowser/content/pics/softshadow-top.png
new file mode 100644
index 0000000..9a9e232
--- /dev/null
+++ b/demos/declarative/webbrowser/content/pics/softshadow-top.png
Binary files differ
diff --git a/demos/declarative/webbrowser/fieldtext/FieldText.qml b/demos/declarative/webbrowser/fieldtext/FieldText.qml
new file mode 100644
index 0000000..fe55185
--- /dev/null
+++ b/demos/declarative/webbrowser/fieldtext/FieldText.qml
@@ -0,0 +1,163 @@
+import Qt 4.6
+
+Item {
+ id: fieldText
+ height: 30
+ property string text: ""
+ property string label: ""
+ property bool mouseGrabbed: false
+ signal confirmed
+ signal cancelled
+ signal startEdit
+
+ resources: [
+ Script {
+
+ function edit() {
+ if (!mouseGrabbed) {
+ fieldText.startEdit();
+ fieldText.state='editing';
+ mouseGrabbed=true;
+ }
+ }
+
+ function confirm() {
+ fieldText.state='';
+ fieldText.text = textEdit.text;
+ mouseGrabbed=false;
+ fieldText.confirmed();
+ }
+
+ function reset() {
+ textEdit.text = fieldText.text;
+ fieldText.state='';
+ mouseGrabbed=false;
+ fieldText.cancelled();
+ }
+
+ }
+ ]
+
+ Image {
+ id: cancelIcon
+ width: 22
+ height: 22
+ anchors.right: parent.right
+ anchors.rightMargin: 4
+ anchors.verticalCenter: parent.verticalCenter
+ source: "pics/cancel.png"
+ opacity: 0
+ }
+
+ Image {
+ id: confirmIcon
+ width: 22
+ height: 22
+ anchors.left: parent.left
+ anchors.leftMargin: 4
+ anchors.verticalCenter: parent.verticalCenter
+ source: "pics/ok.png"
+ opacity: 0
+ }
+
+ TextInput {
+ id: textEdit
+ text: fieldText.text
+ focus: false
+ anchors.left: parent.left
+ anchors.leftMargin: 0
+ anchors.right: parent.right
+ anchors.rightMargin: 0
+ anchors.verticalCenter: parent.verticalCenter
+ color: "black"
+ font.bold: true
+ readOnly: true
+ onAccepted: confirm()
+ Keys.onEscapePressed: reset()
+ }
+
+ Text {
+ id: textLabel
+ x: 5
+ width: parent.width-10
+ anchors.verticalCenter: parent.verticalCenter
+ horizontalAlignment: "AlignHCenter"
+ color: fieldText.state == "editing" ? "#505050" : "#AAAAAA"
+ font.italic: true
+ font.bold: true
+ text: label
+ opacity: textEdit.text == '' ? 1 : 0
+ opacity: Behavior {
+ NumberAnimation {
+ property: "opacity"
+ duration: 250
+ }
+ }
+ }
+
+ MouseRegion {
+ anchors.fill: cancelIcon
+ onClicked: { reset() }
+ }
+
+ MouseRegion {
+ anchors.fill: confirmIcon
+ onClicked: { confirm() }
+ }
+
+ MouseRegion {
+ id: editRegion
+ anchors.fill: textEdit
+ onClicked: { edit() }
+ }
+
+ states: [
+ State {
+ name: "editing"
+ PropertyChanges {
+ target: confirmIcon
+ opacity: 1
+ }
+ PropertyChanges {
+ target: cancelIcon
+ opacity: 1
+ }
+ PropertyChanges {
+ target: textEdit
+ color: "black"
+ readOnly: false
+ focus: true
+ selectionStart: 0
+ selectionEnd: -1
+ }
+ PropertyChanges {
+ target: editRegion
+ opacity: 0
+ }
+ PropertyChanges {
+ target: textEdit.anchors
+ leftMargin: 34
+ }
+ PropertyChanges {
+ target: textEdit.anchors
+ rightMargin: 34
+ }
+ }
+ ]
+
+ transitions: [
+ Transition {
+ from: ""
+ to: "*"
+ reversible: true
+ NumberAnimation {
+ properties: "opacity,leftMargin,rightMargin"
+ duration: 200
+ }
+ ColorAnimation {
+ property: "color"
+ duration: 150
+ }
+ }
+ ]
+}
diff --git a/demos/declarative/webbrowser/fieldtext/pics/cancel.png b/demos/declarative/webbrowser/fieldtext/pics/cancel.png
new file mode 100644
index 0000000..ecc9533
--- /dev/null
+++ b/demos/declarative/webbrowser/fieldtext/pics/cancel.png
Binary files differ
diff --git a/demos/declarative/webbrowser/fieldtext/pics/ok.png b/demos/declarative/webbrowser/fieldtext/pics/ok.png
new file mode 100644
index 0000000..5795f04
--- /dev/null
+++ b/demos/declarative/webbrowser/fieldtext/pics/ok.png
Binary files differ
diff --git a/demos/declarative/webbrowser/webbrowser.qml b/demos/declarative/webbrowser/webbrowser.qml
new file mode 100644
index 0000000..3f23d83
--- /dev/null
+++ b/demos/declarative/webbrowser/webbrowser.qml
@@ -0,0 +1,413 @@
+import Qt 4.6
+
+import "content"
+import "fieldtext"
+
+Item {
+ id: WebBrowser
+
+ property string urlString : "http://qt.nokia.com/"
+
+ state: "Normal"
+
+ width: 640
+ height: 480
+
+ Item {
+ id: WebPanel
+ anchors.fill: parent
+ clip: true
+ Rectangle {
+ color: "#555555"
+ anchors.fill: parent
+ }
+ Image {
+ source: "content/pics/softshadow-bottom.png"
+ width: WebPanel.width
+ height: 16
+ }
+ Image {
+ source: "content/pics/softshadow-top.png"
+ width: WebPanel.width
+ height: 16
+ anchors.bottom: Footer.top
+ }
+ RectSoftShadow {
+ x: -Flick.viewportX
+ y: -Flick.viewportY
+ width: MyWebView.width*MyWebView.scale
+ height: Flick.y+MyWebView.height*MyWebView.scale
+ }
+ Item {
+ id: HeaderSpace
+ width: parent.width
+ height: 60
+ z: 1
+
+ Rectangle {
+ id: HeaderSpaceTint
+ color: "black"
+ opacity: 0
+ anchors.fill: parent
+ }
+
+ Image {
+ id: Header
+ source: "content/pics/header.png"
+ width: parent.width
+ height: 60
+ state: "Normal"
+ x: Flick.viewportX < 0 ? -Flick.viewportX : Flick.viewportX > Flick.viewportWidth-Flick.width
+ ? -Flick.viewportX+Flick.viewportWidth-Flick.width : 0
+ y: Flick.viewportY < 0 ? -Flick.viewportY : progressOff*
+ (Flick.viewportY>height?-height:-Flick.viewportY)
+ Text {
+ id: HeaderText
+
+ text: MyWebView.title!='' || MyWebView.progress == 1.0 ? MyWebView.title : 'Loading...'
+ elide: "ElideRight"
+
+ color: "white"
+ styleColor: "black"
+ style: "Raised"
+
+ font.family: "Helvetica"
+ font.pointSize: 10
+ font.bold: true
+
+ anchors.left: Header.left
+ anchors.right: Header.right
+ anchors.leftMargin: 4
+ anchors.rightMargin: 4
+ anchors.top: Header.top
+ anchors.topMargin: 4
+ horizontalAlignment: "AlignHCenter"
+ }
+ Item {
+ width: parent.width
+ anchors.top: HeaderText.bottom
+ anchors.topMargin: 2
+ anchors.bottom: parent.bottom
+
+ Item {
+ id: UrlBox
+ height: 31
+ anchors.left: parent.left
+ anchors.leftMargin: 12
+ anchors.right: parent.right
+ anchors.rightMargin: 12
+ anchors.top: parent.top
+ clip: true
+ property bool mouseGrabbed: false
+
+ BorderImage {
+ source: "content/pics/addressbar.sci"
+ anchors.fill: UrlBox
+ }
+
+ BorderImage {
+ id: UrlBoxhl
+ source: "content/pics/addressbar-filled.sci"
+ width: parent.width*MyWebView.progress
+ height: parent.height
+ opacity: 1-Header.progressOff
+ clip: true
+ }
+
+ FieldText {
+ id: EditUrl
+ mouseGrabbed: parent.mouseGrabbed
+
+ text: WebBrowser.urlString
+ label: "url:"
+ onConfirmed: { WebBrowser.urlString = EditUrl.text; MyWebView.focus=true }
+ onCancelled: { MyWebView.focus=true }
+ onStartEdit: { MyWebView.focus=false }
+
+ anchors.left: UrlBox.left
+ anchors.right: UrlBox.right
+ anchors.leftMargin: 6
+ anchors.verticalCenter: UrlBox.verticalCenter
+ anchors.verticalCenterOffset: 1
+ }
+ }
+ }
+
+ property real progressOff : 1
+ states: [
+ State {
+ name: "Normal"
+ when: MyWebView.progress == 1.0
+ PropertyChanges { target: Header; progressOff: 1 }
+ },
+ State {
+ name: "ProgressShown"
+ when: MyWebView.progress < 1.0
+ PropertyChanges { target: Header; progressOff: 0; }
+ }
+ ]
+ transitions: [
+ Transition {
+ NumberAnimation {
+ target: Header
+ properties: "progressOff"
+ easing: "easeInOutQuad"
+ duration: 300
+ }
+ }
+ ]
+ }
+ }
+ Flickable {
+ id: Flick
+ width: parent.width
+ viewportWidth: Math.max(parent.width,MyWebView.width*MyWebView.scale)
+ viewportHeight: Math.max(parent.height,MyWebView.height*MyWebView.scale)
+ anchors.top: HeaderSpace.bottom
+ anchors.bottom: Footer.top
+ anchors.left: parent.left
+ anchors.right: parent.right
+ pressDelay: 200
+
+ WebView {
+ id: MyWebView
+ pixelCacheSize: 4000000
+
+ Script {
+ function fixUrl(url)
+ {
+ if (url == "") return url
+ if (url[0] == "/") return "file://"+url
+ if (url.indexOf(":")<0) {
+ if (url.indexOf(".")<0 || url.indexOf(" ")>=0) {
+ // Fall back to a search engine; hard-code Wikipedia
+ return "http://en.wikipedia.org/w/index.php?search="+url
+ } else {
+ return "http://"+url
+ }
+ }
+ return url
+ }
+ }
+
+ url: fixUrl(WebBrowser.urlString)
+ smooth: true
+ fillColor: "white"
+ focus: true
+
+ preferredWidth: Flick.width
+ webPageWidth: 980
+
+ onUrlChanged: { if (url != null) { WebBrowser.urlString = url.toString(); } }
+ onDoubleClick: { heuristicZoom(clickX,clickY) }
+
+ SequentialAnimation {
+ id: QuickZoom
+
+ PropertyAction {
+ target: MyWebView
+ property: "renderingEnabled"
+ value: false
+ }
+ ParallelAnimation {
+ NumberAnimation {
+ id: ScaleAnim
+ target: MyWebView
+ property: "scale"
+ from: 1
+ to: 0 // set before calling
+ easing: "easeLinear"
+ duration: 200
+ }
+ NumberAnimation {
+ id: FlickVX
+ target: Flick
+ property: "viewportX"
+ easing: "easeLinear"
+ duration: 200
+ from: 0 // set before calling
+ to: 0 // set before calling
+ }
+ NumberAnimation {
+ id: FlickVY
+ target: Flick
+ property: "viewportY"
+ easing: "easeLinear"
+ duration: 200
+ from: 0 // set before calling
+ to: 0 // set before calling
+ }
+ }
+ PropertyAction {
+ id: FinalZoom
+ target: MyWebView
+ property: "zoomFactor"
+ }
+ PropertyAction {
+ target: MyWebView
+ property: "scale"
+ value: 1.0
+ }
+ // Have to set the viewportXY, since the above 2
+ // size changes may have started a correction if
+ // zoomFactor < 1.0.
+ PropertyAction {
+ id: FinalX
+ target: Flick
+ property: "viewportX"
+ value: 0 // set before calling
+ }
+ PropertyAction {
+ id: FinalY
+ target: Flick
+ property: "viewportY"
+ value: 0 // set before calling
+ }
+ PropertyAction {
+ target: MyWebView
+ property: "renderingEnabled"
+ value: true
+ }
+ }
+ onZooming: {
+ if (centerX) {
+ sc = zoom/zoomFactor;
+ ScaleAnim.to = sc;
+ FlickVX.from = Flick.viewportX
+ FlickVX.to = Math.min(Math.max(0,centerX-Flick.width/2),MyWebView.width*sc-Flick.width)
+ FinalX.value = Math.min(Math.max(0,centerX-Flick.width/2),MyWebView.width*sc-Flick.width)
+ FlickVY.from = Flick.viewportY
+ FlickVY.to = Math.min(Math.max(0,centerY-Flick.height/2),MyWebView.height*sc-Flick.height)
+ FinalY.value = Math.min(Math.max(0,centerY-Flick.height/2),MyWebView.height*sc-Flick.height)
+ FinalZoom.value = zoom
+ QuickZoom.start()
+ }
+ }
+ }
+ Rectangle {
+ id: WebViewTint
+ color: "black"
+ opacity: 0
+ anchors.fill: MyWebView
+ /*MouseRegion {
+ anchors.fill: WebViewTint
+ onClicked: { proxy.focus=false }
+ }*/
+ }
+ }
+ BorderImage {
+ id: Footer
+ source: "content/pics/footer.sci"
+ width: parent.width
+ height: 43
+ anchors.bottom: parent.bottom
+ Rectangle {
+ y: -1
+ width: parent.width
+ height: 1
+ color: "#555555"
+ }
+ Item {
+ id: backbutton
+ width: back_e.width
+ height: back_e.height
+ anchors.right: reload.left
+ anchors.rightMargin: 10
+ anchors.verticalCenter: parent.verticalCenter
+ Image {
+ id: back_e
+ source: "content/pics/back.png"
+ anchors.fill: parent
+ }
+ Image {
+ id: back_d
+ source: "content/pics/back-disabled.png"
+ anchors.fill: parent
+ }
+ states: [
+ State {
+ name: "Enabled"
+ when: MyWebView.back.enabled==true
+ PropertyChanges { target: back_e; opacity: 1 }
+ PropertyChanges { target: back_d; opacity: 0 }
+ },
+ State {
+ name: "Disabled"
+ when: MyWebView.back.enabled==false
+ PropertyChanges { target: back_e; opacity: 0 }
+ PropertyChanges { target: back_d; opacity: 1 }
+ }
+ ]
+ transitions: [
+ Transition {
+ NumberAnimation {
+ properties: "opacity"
+ easing: "easeInOutQuad"
+ duration: 300
+ }
+ }
+ ]
+ MouseRegion {
+ anchors.fill: back_e
+ onClicked: { if (MyWebView.back.enabled) MyWebView.back.trigger() }
+ }
+ }
+ Image {
+ id: reload
+ source: "content/pics/reload.png"
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.verticalCenter: parent.verticalCenter
+ }
+ MouseRegion {
+ anchors.fill: reload
+ onClicked: { MyWebView.reload.trigger() }
+ }
+ Item {
+ id: forwardbutton
+ width: forward_e.width
+ height: forward_e.height
+ anchors.left: reload.right
+ anchors.leftMargin: 10
+ anchors.verticalCenter: parent.verticalCenter
+ Image {
+ id: forward_e
+ source: "content/pics/forward.png"
+ anchors.fill: parent
+ anchors.verticalCenter: parent.verticalCenter
+ }
+ Image {
+ id: forward_d
+ source: "content/pics/forward-disabled.png"
+ anchors.fill: parent
+ }
+ states: [
+ State {
+ name: "Enabled"
+ when: MyWebView.forward.enabled==true
+ PropertyChanges { target: forward_e; opacity: 1 }
+ PropertyChanges { target: forward_d; opacity: 0 }
+ },
+ State {
+ name: "Disabled"
+ when: MyWebView.forward.enabled==false
+ PropertyChanges { target: forward_e; opacity: 0 }
+ PropertyChanges { target: forward_d; opacity: 1 }
+ }
+ ]
+ transitions: [
+ Transition {
+ NumberAnimation {
+ properties: "opacity"
+ easing: "easeInOutQuad"
+ duration: 320
+ }
+ }
+ ]
+ MouseRegion {
+ anchors.fill: parent
+ onClicked: { if (MyWebView.forward.enabled) MyWebView.forward.trigger() }
+ }
+ }
+ }
+ }
+}