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.qml115
-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.qml321
-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/content/ImageDetails.qml160
-rw-r--r--demos/declarative/flickr/content/LikeOMeter.qml35
-rw-r--r--demos/declarative/flickr/content/Loading.qml8
-rw-r--r--demos/declarative/flickr/content/MediaButton.qml41
-rw-r--r--demos/declarative/flickr/content/MediaLineEdit.qml109
-rw-r--r--demos/declarative/flickr/content/Progress.qml35
-rw-r--r--demos/declarative/flickr/content/ScrollBar.qml40
-rw-r--r--demos/declarative/flickr/content/Slider.qml36
-rw-r--r--demos/declarative/flickr/content/Star.qml46
-rw-r--r--demos/declarative/flickr/content/pics/background.pngbin0 -> 60504 bytes
-rw-r--r--demos/declarative/flickr/content/pics/button-pressed.pngbin0 -> 571 bytes
-rw-r--r--demos/declarative/flickr/content/pics/button-pressed.sci5
-rw-r--r--demos/declarative/flickr/content/pics/button.pngbin0 -> 564 bytes
-rw-r--r--demos/declarative/flickr/content/pics/button.sci5
-rw-r--r--demos/declarative/flickr/content/pics/ghns_star.pngbin0 -> 891 bytes
-rw-r--r--demos/declarative/flickr/content/pics/loading.pngbin0 -> 813 bytes
-rw-r--r--demos/declarative/flickr/content/pics/reflection.pngbin0 -> 4839 bytes
-rw-r--r--demos/declarative/flickr/content/pics/shadow-bottom.pngbin0 -> 656 bytes
-rw-r--r--demos/declarative/flickr/content/pics/shadow-corner.pngbin0 -> 405 bytes
-rw-r--r--demos/declarative/flickr/content/pics/shadow-right-screen.pngbin0 -> 227 bytes
-rw-r--r--demos/declarative/flickr/content/pics/shadow-right.pngbin0 -> 635 bytes
-rw-r--r--demos/declarative/flickr/flickr.qml211
-rw-r--r--demos/declarative/flickr/flickr2.qml261
-rw-r--r--demos/declarative/samegame/README10
-rw-r--r--demos/declarative/samegame/SameGame.qml34
-rw-r--r--demos/declarative/samegame/content/BoomBlock.qml54
-rw-r--r--demos/declarative/samegame/content/Button.qml18
-rw-r--r--demos/declarative/samegame/content/Dialog.qml15
-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.js211
-rw-r--r--demos/declarative/webbrowser/README6
-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/webbrowser.qml374
77 files changed, 2891 insertions, 0 deletions
diff --git a/demos/declarative/calculator/CalcButton.qml b/demos/declarative/calculator/CalcButton.qml
new file mode 100644
index 0000000..ebb1967
--- /dev/null
+++ b/demos/declarative/calculator/CalcButton.qml
@@ -0,0 +1,41 @@
+import Qt 4.6
+
+Rect {
+ 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: MouseRegion
+ 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: MouseRegion.pressed == true
+ SetProperties { target: G1; color: Palette.dark }
+ SetProperties { target: G2; color: Palette.button }
+ },
+ State {
+ name: "Toggled"; when: Button.toggled == true
+ SetProperties { target: G1; color: Palette.dark }
+ SetProperties { 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..a4e16e4
--- /dev/null
+++ b/demos/declarative/calculator/calculator.qml
@@ -0,0 +1,130 @@
+import Qt 4.6
+
+Rect {
+ id: MainWindow;
+ width: 320; height: 270; color: Palette.window
+
+ Palette { id: Palette }
+ Script { source: "calculator.js" }
+
+ VerticalLayout {
+ x: 2; spacing: 10; margin: 2
+
+ Rect {
+ id: Container
+ width: 316; height: 50; z: 2
+ border.color: Palette.dark; color: Palette.base
+
+ Text {
+ id: CurNum
+ font.bold: true; font.size: 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.size: 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 }
+
+ GridLayout {
+ 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" }
+ }
+
+ HorizontalLayout {
+ y: 128; spacing: 2
+
+ CalcButton { operation: "0"; width: 50 }
+ CalcButton { operation: "."; x: 77; width: 50 }
+ CalcButton { operation: "="; id: Equals; x: 77; width: 102 }
+ }
+
+ VerticalLayout {
+ id: SimpleOperations
+ x: 156; y: 0; spacing: 2
+
+ CalcButton { operation: "x" }
+ CalcButton { operation: "/" }
+ CalcButton { operation: "-" }
+ CalcButton { operation: "+" }
+ }
+ }
+
+ GridLayout {
+ 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
+ SetProperties { target: BasicButtons; x: 0 }
+ SetProperties { target: SimpleOperations; y: 32 }
+ SetProperties { target: Bksp; opacity: 1 }
+ SetProperties { target: C; x: 69; width: 67 }
+ SetProperties { target: AC; x: 138; width: 67 }
+ SetProperties { target: Equals; width: 50 }
+ SetProperties { 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..f5024e5
--- /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
+ Rect {
+ 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
+ SetProperties {
+ target: buttonRect
+ color: "green"
+ }
+ }
+ ]
+ transitions: [
+ Transition {
+ fromState: "*"
+ toState: "pressed"
+ ColorAnimation {
+ property: "color"
+ duration: 200
+ }
+ },
+ Transition {
+ fromState: "pressed"
+ toState: "*"
+ 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..77189e9
--- /dev/null
+++ b/demos/declarative/contacts/Contact.qml
@@ -0,0 +1,115 @@
+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();
+ }
+ VerticalLayout {
+ id: layout
+ anchors.fill: parent
+ spacing: 5
+ margin: 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..69401f9
--- /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'
+ SetProperties {
+ target: removeButton.anchors
+ rightMargin: -35
+ }
+ SetProperties {
+ target: fieldText
+ width: contactField.width
+ }
+ }
+ ]
+ transitions: [
+ Transition {
+ fromState: ""
+ toState: "*"
+ 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..a28fbbc
--- /dev/null
+++ b/demos/declarative/contacts/FieldText.qml
@@ -0,0 +1,154 @@
+import Qt 4.6
+
+Rect {
+ 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
+ hAlign: "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"
+ SetProperties {
+ target: confirmIcon
+ opacity: 1
+ }
+ SetProperties {
+ target: cancelIcon
+ opacity: 1
+ }
+ SetProperties {
+ target: fieldText
+ color: "white"
+ }
+ SetProperties {
+ target: textEdit
+ color: "black"
+ }
+ SetProperties {
+ target: textEdit
+ readOnly: false
+ }
+ SetProperties {
+ target: textEdit
+ focus: true
+ }
+ SetProperties {
+ target: editRegion
+ opacity: 0
+ }
+ SetProperties {
+ target: textEdit.anchors
+ leftMargin: 34
+ }
+ SetProperties {
+ target: textEdit.anchors
+ rightMargin: 34
+ }
+ }
+ ]
+ transitions: [
+ Transition {
+ fromState: ""
+ toState: "*"
+ 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..d42d359
--- /dev/null
+++ b/demos/declarative/contacts/RemoveButton.qml
@@ -0,0 +1,123 @@
+import Qt 4.6
+
+Rect {
+ 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"
+ hAlign: "AlignHCenter"
+ text: "Remove"
+ opacity: 0
+ }
+ opacity: Behavior {
+ NumberAnimation {
+ property: "opacity"
+ duration: 250
+ }
+ }
+ states: [
+ State {
+ name: "opened"
+ SetProperties {
+ target: removeButton
+ width: removeButton.expandedWidth
+ }
+ SetProperties {
+ target: text
+ opacity: 1
+ }
+ SetProperties {
+ target: confirmIcon
+ opacity: 1
+ }
+ SetProperties {
+ target: cancelIcon
+ opacity: 1
+ }
+ SetProperties {
+ target: trashIcon
+ opacity: 0
+ }
+ }
+ ]
+ transitions: [
+ Transition {
+ fromState: "*"
+ toState: "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..b3faa9d
--- /dev/null
+++ b/demos/declarative/contacts/SearchBar.qml
@@ -0,0 +1,26 @@
+import Qt 4.6
+
+Rect {
+ 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..353040c
--- /dev/null
+++ b/demos/declarative/contacts/contacts.qml
@@ -0,0 +1,321 @@
+import Qt 4.6
+
+Rect {
+ 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
+ SetProperties {
+ target: label
+ color: "black"
+ }
+ }
+ ]
+ transitions: [
+ Transition {
+ ColorAnimation {
+ duration: 250
+ property: "color"
+ }
+ }
+ ]
+ }
+ Loader {
+ id: Details
+ anchors.fill: wrapper
+ opacity: 0
+ Bind {
+ target: Details.item
+ property: "contactId"
+ value: model.recid
+ }
+ Bind {
+ target: Details.item
+ property: "label"
+ value: model.label
+ }
+ Bind {
+ target: Details.item
+ property: "phone"
+ value: model.phone
+ }
+ Bind {
+ target: Details.item
+ property: "email"
+ value: model.email
+ }
+ }
+ states: [
+ State {
+ name: "opened"
+ SetProperties {
+ target: wrapper
+ height: contactListView.height
+ }
+ SetProperties {
+ target: contactListView
+ yPosition: wrapper.y
+ }
+ SetProperties {
+ target: contactListView
+ locked: 1
+ }
+ SetProperties {
+ target: label
+ opacity: 0
+ }
+ SetProperties {
+ target: Details
+ opacity: 1
+ }
+ }
+ ]
+ transitions: [
+ Transition {
+ NumberAnimation {
+ duration: 500
+ properties: "yPosition,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: [
+ Rect {
+ 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'
+ SetProperties {
+ target: searchBarWrapper.anchors
+ bottomMargin: -30
+ }
+ }
+ ]
+ transitions: [
+ Transition {
+ fromState: "*"
+ toState: "*"
+ NumberAnimation {
+ property: "bottomMargin"
+ duration: 250
+ }
+ }
+ ]
+ }
+ KeyProxy {
+ focus: contacts.mode != 'new'
+ targets: { contacts.mode == "list" ? [searchBarWrapper, contactListView] : [contactListView]}
+ }
+ states: [
+ State {
+ name: "editNewState"
+ when: contacts.mode == 'new'
+ SetProperties {
+ target: contactListView
+ opacity: 0
+ }
+ SetProperties {
+ target: newContactWrapper
+ opacity: 1
+ }
+ }
+ ]
+ transitions: [
+ Transition {
+ fromState: "*"
+ toState: "*"
+ 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/content/ImageDetails.qml b/demos/declarative/flickr/content/ImageDetails.qml
new file mode 100644
index 0000000..a18c230
--- /dev/null
+++ b/demos/declarative/flickr/content/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: Rotation3D {
+ id: Rotation
+ origin.x: Container.width / 2;
+ axis.y: 1;
+ }
+
+ front: Item {
+ id: ContainerFront; anchors.fill: Container
+
+ Rect {
+ 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.size: 22 }
+
+ LikeOMeter { x: 40; y: 250; rating: Container.rating }
+
+ Flickable { id: Flickable; 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: Flickable.y; width: 7; height: Flickable.height; opacity: 0;
+ flickableArea: Flickable; clip: true }
+ }
+
+ back: Item {
+ anchors.fill: Container
+
+ Rect { 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.xPosition) * value / prevScale;
+ Flick.xPosition = xoff - Flick.width/2;
+ }
+ if (BigImage.height * value > Flick.height) {
+ var yoff = (Flick.height/2 + Flick.yPosition) * value / prevScale;
+ Flick.yPosition = yoff - Flick.height/2;
+ }
+ prevScale = value;
+ }
+ }
+ }
+
+ states: [
+ State {
+ name: "Back"
+ SetProperties { target: Rotation; angle: 180 }
+ }
+ ]
+
+ transitions: [
+ Transition {
+ SequentialAnimation {
+ SetPropertyAction {
+ target: BigImage
+ property: "smooth"
+ value: false
+ }
+ NumberAnimation { easing: "easeInOutQuad"; properties: "angle"; duration: 500 }
+ SetPropertyAction {
+ target: BigImage
+ property: "smooth"
+ value: !Flick.moving
+ }
+ }
+ }
+ ]
+}
diff --git a/demos/declarative/flickr/content/LikeOMeter.qml b/demos/declarative/flickr/content/LikeOMeter.qml
new file mode 100644
index 0000000..88a28b6
--- /dev/null
+++ b/demos/declarative/flickr/content/LikeOMeter.qml
@@ -0,0 +1,35 @@
+import Qt 4.6
+
+Item {
+ id: Container
+
+ property int rating: 2
+
+ HorizontalLayout {
+ 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/content/Loading.qml b/demos/declarative/flickr/content/Loading.qml
new file mode 100644
index 0000000..ff2c829
--- /dev/null
+++ b/demos/declarative/flickr/content/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/content/MediaButton.qml b/demos/declarative/flickr/content/MediaButton.qml
new file mode 100644
index 0000000..2a6dbae
--- /dev/null
+++ b/demos/declarative/flickr/content/MediaButton.qml
@@ -0,0 +1,41 @@
+import Qt 4.6
+
+Item {
+ id: Container
+
+ signal clicked
+
+ property string text
+
+ Image {
+ id: Image
+ source: "pics/button.png"
+ }
+ Image {
+ id: Pressed
+ source: "pics/button-pressed.png"
+ opacity: 0
+ }
+ MouseRegion {
+ id: MouseRegion
+ anchors.fill: Image
+ onClicked: { Container.clicked(); }
+ }
+ Text {
+ font.bold: true
+ color: "white"
+ anchors.centerIn: Image
+ text: Container.text
+ }
+ width: Image.width
+ states: [
+ State {
+ name: "Pressed"
+ when: MouseRegion.pressed == true
+ SetProperties {
+ target: Pressed
+ opacity: 1
+ }
+ }
+ ]
+}
diff --git a/demos/declarative/flickr/content/MediaLineEdit.qml b/demos/declarative/flickr/content/MediaLineEdit.qml
new file mode 100644
index 0000000..4a55ff5
--- /dev/null
+++ b/demos/declarative/flickr/content/MediaLineEdit.qml
@@ -0,0 +1,109 @@
+import Qt 4.6
+
+Item {
+ id: Container
+
+ property string label
+ property string text
+
+ width: Math.max(94,Label.width + Editor.width + 20)
+ height: Image.height
+
+ states: [
+ State {
+ name: "Edit"
+ SetProperties {
+ target: Label
+ text: Container.label + ": "
+ }
+ SetProperties {
+ target: Label
+ x: 10
+ }
+ SetProperties {
+ target: Editor
+ cursorVisible: true
+ width: 100
+ }
+ SetProperties {
+ target: Proxy
+ focus: true
+ }
+ RunScript {
+ script:"Editor.selectAll()"
+ }
+ },
+ State {
+ // When returning to default state, typed text is propagated
+ RunScript {
+ script: "Container.text = Editor.text"
+ }
+ }
+ ]
+ transitions: [
+ Transition {
+ NumberAnimation { properties: "x,width"; duration: 500; easing: "easeInOutQuad" }
+ }
+ ]
+
+
+ BorderImage {
+ id: Image
+ 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: MouseRegion
+ anchors.fill: Image
+ onClicked: { Container.state = Container.state=="Edit" ? "" : "Edit" }
+ states: [
+ State {
+ when: MouseRegion.pressed == true
+ SetProperties {
+ target: Pressed
+ opacity: 1
+ }
+ }
+ ]
+ }
+
+ Text {
+ id: Label
+ font.bold: true
+ color: "white"
+ anchors.verticalCenter: Container.verticalCenter
+ x: (Container.width - width)/2
+ text: Container.label + "..."
+ }
+
+ TextEdit {
+ id: Editor
+ font.bold: true
+ color: "white"
+ highlightColor: "green"
+ width: 0
+ clip: true
+ anchors.left: Label.right
+ anchors.verticalCenter: Container.verticalCenter
+ }
+ KeyProxy {
+ id: Proxy
+ anchors.left: Container.left
+ anchors.fill: Container
+ targets: [(ReturnKey), (Editor)]
+ }
+ KeyActions {
+ id: ReturnKey
+ keyReturn: "Container.state = ''"
+ }
+}
diff --git a/demos/declarative/flickr/content/Progress.qml b/demos/declarative/flickr/content/Progress.qml
new file mode 100644
index 0000000..4268963
--- /dev/null
+++ b/demos/declarative/flickr/content/Progress.qml
@@ -0,0 +1,35 @@
+import Qt 4.6
+
+Item {
+ id: Progress;
+
+ property var progress: 0
+
+ Rect {
+ 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" }
+ }
+ }
+
+ Rect {
+ 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/content/ScrollBar.qml b/demos/declarative/flickr/content/ScrollBar.qml
new file mode 100644
index 0000000..e9a461c
--- /dev/null
+++ b/demos/declarative/flickr/content/ScrollBar.qml
@@ -0,0 +1,40 @@
+import Qt 4.6
+
+Item {
+ id: Container
+
+ property var flickableArea
+
+ Rect {
+ radius: 5
+ color: "black"
+ opacity: 0.3
+ border.color: "white"
+ border.width: 2
+ x: 0
+ y: flickableArea.pageYPosition * Container.height
+ width: parent.width
+ height: flickableArea.pageHeight * Container.height
+ }
+ states: [
+ State {
+ name: "show"
+ when: flickableArea.moving
+ SetProperties {
+ target: Container
+ opacity: 1
+ }
+ }
+ ]
+ transitions: [
+ Transition {
+ fromState: "*"
+ toState: "*"
+ NumberAnimation {
+ target: Container
+ properties: "opacity"
+ duration: 400
+ }
+ }
+ ]
+}
diff --git a/demos/declarative/flickr/content/Slider.qml b/demos/declarative/flickr/content/Slider.qml
new file mode 100644
index 0000000..51385bc
--- /dev/null
+++ b/demos/declarative/flickr/content/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
+
+ Rect {
+ 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" }
+ }
+ }
+
+ Rect {
+ 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: "x"; drag.xmin: 2; drag.xmax: Slider.xMax+2
+ onPositionChanged: { value = (maximum - minimum) * (Handle.x-2) / Slider.xMax + minimum; }
+ }
+ }
+}
diff --git a/demos/declarative/flickr/content/Star.qml b/demos/declarative/flickr/content/Star.qml
new file mode 100644
index 0000000..5a6a95d
--- /dev/null
+++ b/demos/declarative/flickr/content/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: Image
+ 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
+ SetProperties {
+ target: Image
+ opacity: 1
+ scale: 1
+ x: 1
+ y: 0
+ }
+ }
+ ]
+ transitions: [
+ Transition {
+ NumberAnimation {
+ properties: "opacity,scale,x,y"
+ easing: "easeOutBounce"
+ }
+ }
+ ]
+}
diff --git a/demos/declarative/flickr/content/pics/background.png b/demos/declarative/flickr/content/pics/background.png
new file mode 100644
index 0000000..5b37072
--- /dev/null
+++ b/demos/declarative/flickr/content/pics/background.png
Binary files differ
diff --git a/demos/declarative/flickr/content/pics/button-pressed.png b/demos/declarative/flickr/content/pics/button-pressed.png
new file mode 100644
index 0000000..e434d32
--- /dev/null
+++ b/demos/declarative/flickr/content/pics/button-pressed.png
Binary files differ
diff --git a/demos/declarative/flickr/content/pics/button-pressed.sci b/demos/declarative/flickr/content/pics/button-pressed.sci
new file mode 100644
index 0000000..d3b16e2
--- /dev/null
+++ b/demos/declarative/flickr/content/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/content/pics/button.png b/demos/declarative/flickr/content/pics/button.png
new file mode 100644
index 0000000..56a63ce
--- /dev/null
+++ b/demos/declarative/flickr/content/pics/button.png
Binary files differ
diff --git a/demos/declarative/flickr/content/pics/button.sci b/demos/declarative/flickr/content/pics/button.sci
new file mode 100644
index 0000000..d3b16e2
--- /dev/null
+++ b/demos/declarative/flickr/content/pics/button.sci
@@ -0,0 +1,5 @@
+gridLeft: 8
+gridTop: 4
+gridBottom: 4
+gridRight: 8
+imageFile: button.png
diff --git a/demos/declarative/flickr/content/pics/ghns_star.png b/demos/declarative/flickr/content/pics/ghns_star.png
new file mode 100644
index 0000000..4ad43cc
--- /dev/null
+++ b/demos/declarative/flickr/content/pics/ghns_star.png
Binary files differ
diff --git a/demos/declarative/flickr/content/pics/loading.png b/demos/declarative/flickr/content/pics/loading.png
new file mode 100644
index 0000000..47a1589
--- /dev/null
+++ b/demos/declarative/flickr/content/pics/loading.png
Binary files differ
diff --git a/demos/declarative/flickr/content/pics/reflection.png b/demos/declarative/flickr/content/pics/reflection.png
new file mode 100644
index 0000000..c143a48
--- /dev/null
+++ b/demos/declarative/flickr/content/pics/reflection.png
Binary files differ
diff --git a/demos/declarative/flickr/content/pics/shadow-bottom.png b/demos/declarative/flickr/content/pics/shadow-bottom.png
new file mode 100644
index 0000000..523f6e7
--- /dev/null
+++ b/demos/declarative/flickr/content/pics/shadow-bottom.png
Binary files differ
diff --git a/demos/declarative/flickr/content/pics/shadow-corner.png b/demos/declarative/flickr/content/pics/shadow-corner.png
new file mode 100644
index 0000000..ef8c856
--- /dev/null
+++ b/demos/declarative/flickr/content/pics/shadow-corner.png
Binary files differ
diff --git a/demos/declarative/flickr/content/pics/shadow-right-screen.png b/demos/declarative/flickr/content/pics/shadow-right-screen.png
new file mode 100644
index 0000000..9856c4f
--- /dev/null
+++ b/demos/declarative/flickr/content/pics/shadow-right-screen.png
Binary files differ
diff --git a/demos/declarative/flickr/content/pics/shadow-right.png b/demos/declarative/flickr/content/pics/shadow-right.png
new file mode 100644
index 0000000..f534a35
--- /dev/null
+++ b/demos/declarative/flickr/content/pics/shadow-right.png
Binary files differ
diff --git a/demos/declarative/flickr/flickr.qml b/demos/declarative/flickr/flickr.qml
new file mode 100644
index 0000000..c0a1a87
--- /dev/null
+++ b/demos/declarative/flickr/flickr.qml
@@ -0,0 +1,211 @@
+import Qt 4.6
+
+import "content"
+
+Item {
+ id: MainWindow; width: 800; height: 450
+
+ property bool showPathView : false
+
+ resources: [
+ XmlListModel {
+ id: FeedModel
+ property string tags : TagsEdit.text
+ 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()" }
+ },
+
+ Component {
+ id: PhotoDelegate
+ Item {
+ id: Wrapper; width: 85; height: 85
+ scale: Wrapper.PathView.scale; z: Wrapper.PathView.z
+
+ transform: Rotation3D {
+ id: Rotation; origin.x: Wrapper.width/2; origin.y: Wrapper.height/2
+ axis.y: 1; 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";
+ }
+ }
+
+ Rect {
+ 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: "content/pics/shadow-right.png"; x: WhiteRect.width; height: WhiteRect.height }
+ Image { source: "content/pics/shadow-bottom.png"; y: WhiteRect.height; width: WhiteRect.width }
+ Image { id: Corner; source: "content/pics/shadow-corner.png"; x: WhiteRect.width; y: WhiteRect.height }
+ }
+ }
+
+ MouseRegion { anchors.fill: Wrapper; onClicked: { photoClicked() } }
+
+ states: [
+ State {
+ name: "Details"
+ SetProperties { target: ImageDetails; z: 2 }
+ ParentChange { target: Wrapper; parent: ImageDetails.frontContainer }
+ SetProperties { target: Wrapper; x: 45; y: 35; scale: 1; z: 1000 }
+ SetProperties { target: Rotation; angle: 0 }
+ SetProperties { target: Shadows; opacity: 0 }
+ SetProperties { target: ImageDetails; y: 20 }
+ SetProperties { target: PhotoGridView; y: "-480" }
+ SetProperties { target: PhotoPathView; y: "-480" }
+ SetProperties { target: ViewModeButton; opacity: 0 }
+ SetProperties { target: TagsEdit; opacity: 0 }
+ SetProperties { target: FetchButton; opacity: 0 }
+ SetProperties { target: CategoryText; y: "-50" }
+ }
+ ]
+
+ transitions: [
+ Transition {
+ fromState: "*"; toState: "Details"
+ ParentChangeAction { }
+ NumberAnimation { properties: "x,y,scale,opacity,angle"; duration: 500; easing: "easeInOutQuad" }
+ },
+ Transition {
+ fromState: "Details"; toState: "*"
+ SequentialAnimation {
+ ParentChangeAction { }
+ NumberAnimation { properties: "x,y,scale,opacity,angle"; duration: 500; easing: "easeInOutQuad" }
+ SetPropertyAction { filter: Wrapper; properties: "z" }
+ }
+ }
+ ]
+
+ }
+ }
+ ]
+
+ Item {
+ id: Background
+
+ anchors.fill: parent
+
+ Image { source: "content/pics/background.png"; anchors.fill: parent }
+
+ Loading { anchors.centerIn: parent; visible: FeedModel.status }
+
+ GridView {
+ id: PhotoGridView; model: FeedModel; delegate: PhotoDelegate; cacheBuffer: 100
+ cellWidth: 105; cellHeight: 105; x:32; y: 80; width: 800; height: 330; z: 1
+ }
+
+ PathView {
+ id: PhotoPathView; model: FeedModel; 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: { FeedModel.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
+ SetProperties { target: PhotoPathView; y: 80 }
+ SetProperties { target: PhotoGridView; y: -380 }
+ }
+ ]
+
+ transitions: [
+ Transition {
+ fromState: "*"; toState: "*"
+ NumberAnimation { properties: "y"; duration: 1000; easing: "easeOutBounce(amplitude:0.5)" }
+ }
+ ]
+ }
+
+ Text {
+ id: CategoryText; anchors.horizontalCenter: parent.horizontalCenter; y: 15;
+ text: "Flickr - " +
+ (FeedModel.tags=="" ? "Uploads from everyone" : "Recent Uploads tagged " + FeedModel.tags)
+ font.size: 20; font.bold: true; color: "white"; style: "Raised"; styleColor: "black"
+ }
+}
diff --git a/demos/declarative/flickr/flickr2.qml b/demos/declarative/flickr/flickr2.qml
new file mode 100644
index 0000000..c972edf
--- /dev/null
+++ b/demos/declarative/flickr/flickr2.qml
@@ -0,0 +1,261 @@
+import Qt 4.6
+
+import "content"
+
+Item {
+ id: MainWindow; width: 800; height: 450
+
+ property bool showPathView : false
+
+ VisualModel {
+ id: MyVisualModel
+ model:
+ XmlListModel {
+ id: FeedModel
+ property string tags : TagsEdit.text
+ 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()" }
+ }
+
+ delegate: Package {
+ Item {
+ id: Wrapper; width: 85; height: 85; scale: {1.0}
+ z: PathViewPackage.PathView.z
+ property real angle: 0 * 0
+
+ transform: [
+ Rotation3D {
+ id: Rotation; origin.x: 30; axis.x: 30; axis.y: 60
+ angle: Wrapper.angle
+ }
+ ]
+
+ Connection {
+ sender: Background.imageDetails; signal: "closed()"
+ script: { if (Wrapper.state == 'Details') Wrapper.state = '' }
+ }
+
+ Script {
+ function photoClicked() {
+ Background.imageDetails.photoTitle = title;
+ Background.imageDetails.photoDescription = description;
+ Background.imageDetails.photoTags = tags;
+ Background.imageDetails.photoWidth = photoWidth;
+ Background.imageDetails.photoHeight = photoHeight;
+ Background.imageDetails.photoType = photoType;
+ Background.imageDetails.photoAuthor = photoAuthor;
+ Background.imageDetails.photoDate = photoDate;
+ Background.imageDetails.photoUrl = url;
+ Background.imageDetails.rating = 0;
+ Wrapper.state = "Details";
+ }
+ }
+
+ Rect {
+ 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: "content/pics/shadow-right.png"; x: WhiteRect.width; height: WhiteRect.height }
+ Image { source: "content/pics/shadow-bottom.png"; y: WhiteRect.height; width: WhiteRect.width }
+ Image { id: Corner; source: "content/pics/shadow-corner.png"; x: WhiteRect.width; y: WhiteRect.height }
+ }
+ }
+
+ MouseRegion { anchors.fill: Wrapper; onClicked: { photoClicked() } }
+
+ states: [
+ State {
+ name: "Details"
+ SetProperties { target: Background.imageDetails; z: 2 }
+ ParentChange { target: Wrapper; parent: Background.imageDetails.frontContainer }
+ SetProperties { target: Wrapper; x: 45; y: 35; scale: 1; z: 1000 }
+ SetProperties { target: Rotation; angle: 0 }
+ SetProperties { target: Shadows; opacity: 0 }
+ SetProperties { target: Background.imageDetails; y: 20 }
+ SetProperties { target: PhotoGridView; y: "-480" }
+ SetProperties { target: PhotoPathView; y: "-480" }
+ SetProperties { target: ViewModeButton; opacity: 0 }
+ SetProperties { target: TagsEdit; opacity: 0 }
+ SetProperties { target: FetchButton; opacity: 0 }
+ SetProperties { target: CategoryText; y: "-50" }
+ }
+ ]
+
+ transitions: [
+ Transition {
+ fromState: "*"; toState: "Details"
+ ParentChangeAction { }
+ NumberAnimation { properties: "x,y,scale,opacity,angle"; duration: 500; easing: "easeInOutQuad" }
+ },
+ Transition {
+ fromState: "Details"; toState: "*"
+ SequentialAnimation {
+ ParentChangeAction { }
+ NumberAnimation { properties: "x,y,scale,opacity,angle"; duration: 500; easing: "easeInOutQuad" }
+ SetPropertyAction { filter: Wrapper; properties: "z" }
+ }
+ }
+ ]
+ }
+
+ Item {
+ Package.name: "pathView"
+ id: PathViewPackage; width: 85; height: 85
+ }
+
+ Item {
+ Package.name: "gridView"
+ id: GridViewPackage; width: 85; height: 85
+ }
+
+ Item {
+ id: MyItem
+ state: MainWindow.showPathView ? "pathView" : "gridView"
+ states: [
+ State {
+ name: "gridView"
+ SetProperties { target: Wrapper; explicit: true; property: "moveToParent"; value: GridViewPackage }
+ },
+ State {
+ name: "pathView"
+ SetProperties { target: Wrapper; scale: PathViewPackage.PathView.scale; angle: PathViewPackage.PathView.angle; }
+ SetProperties { target: Wrapper; explicit: true; moveToParent: PathViewPackage }
+ }
+ ]
+ transitions: [
+ Transition {
+ toState: "pathView"
+ SequentialAnimation {
+ SetPropertyAction { target: Wrapper; property: "moveToParent" }
+ ParallelAnimation {
+ NumberAnimation {
+ target: Wrapper
+ properties: "x,y"
+ to: 0
+ easing: "easeOutQuad"
+ duration: 350
+ }
+ NumberAnimation { target: Wrapper; properties: "scale,angle"; duration: 350 }
+ }
+ }
+ },
+ Transition {
+ toState: "gridView"
+ SequentialAnimation {
+ PauseAnimation { duration: Math.floor(index/7)*100 }
+ SetPropertyAction { target: Wrapper; property: "moveToParent" }
+ ParallelAnimation {
+ NumberAnimation {
+ target: Wrapper
+ properties: "x,y"
+ to: 0
+ easing: "easeOutQuad"
+ duration: 250
+ }
+ NumberAnimation { target: Wrapper; properties: "scale,angle"; duration: 250 }
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+
+
+ Item {
+ id: Background
+ property var imageDetails: ImageDetails
+
+ Image { source: "content/pics/background.png" }
+
+ GridView {
+ id: PhotoGridView; model: MyVisualModel.parts.gridView
+ cellWidth: 105; cellHeight: 105; x:32; y: 80; width: 800; height: 330; z: 1
+ cacheBuffer: 100
+ }
+
+ PathView {
+ id: PhotoPathView; model: MyVisualModel.parts.pathView
+ y: 80; width: 800; height: 330; z: 1
+ pathItemCount: 10; snapPosition: 0.001
+ path: Path {
+ startX: -150; startY: 40;
+
+ PathAttribute { name: "scale"; value: 0.9 }
+ PathAttribute { name: "angle"; value: -45 }
+ PathPercent { value: 0 }
+ PathLine { x: -50; y: 40 }
+
+ PathPercent { value: 0.001 }
+
+ 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
+ }
+
+ PathPercent { value: 0.999 }
+ PathLine { x: 950; y: 40 }
+ PathPercent { value: 1.0 }
+ PathAttribute { name: "scale"; value: 0.9 }
+ 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: { FeedModel.reload(); }
+ }
+
+ MediaLineEdit {
+ id: TagsEdit;
+ label: "Tags"
+ anchors.right: FetchButton.left; anchors.rightMargin: 5
+ anchors.top: ViewModeButton.top
+ }
+
+ }
+
+ Text {
+ id: CategoryText; anchors.horizontalCenter: parent.horizontalCenter; y: 15;
+ text: "Flickr - " +
+ (FeedModel.tags=="" ? "Uploads from everyone" : "Recent Uploads tagged " + FeedModel.tags)
+ font.size: 16; font.bold: true; color: "white"; style: "Raised"; styleColor: "black"
+ }
+}
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..e74646d
--- /dev/null
+++ b/demos/declarative/samegame/SameGame.qml
@@ -0,0 +1,34 @@
+import Qt 4.6
+
+import "content"
+
+Rect {
+ id: page; width: 460; height: 700; color: activePalette.window
+ Script { source: "content/samegame.js" }
+ Palette { id: activePalette; colorGroup: "Active" }
+ Rect {
+ id: gameCanvas
+ property int score: 0
+ z:20; y:20; color: "white"; border.width: 1
+ width:parent.width - tileSize - (parent.width % tileSize);
+ height:parent.height - tileSize - (parent.height % tileSize);
+ anchors.horizontalCenter: parent.horizontalCenter
+ Image { id:background;
+ source: "content/pics/background.png"
+ anchors.fill: parent
+ }
+ MouseRegion { id: gameMR
+ anchors.fill: parent; onClicked: handleClick(mouse.x,mouse.y);
+ }
+ }
+
+ Dialog { id: dialog; anchors.centerIn: parent; z: 21}
+ Button {
+ id: btnA; text: "New Game"; onClicked: {initBoard();}
+ anchors.top: gameCanvas.bottom; anchors.topMargin: 4; anchors.left: gameCanvas.left;
+ }
+ Text {
+ text: "Score: " + gameCanvas.score; width:100; font.size:14
+ anchors.top: gameCanvas.bottom; anchors.topMargin: 4; anchors.right: gameCanvas.right;
+ }
+}
diff --git a/demos/declarative/samegame/content/BoomBlock.qml b/demos/declarative/samegame/content/BoomBlock.qml
new file mode 100644
index 0000000..8a505da
--- /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: Follow { enabled: spawned; source: targetX; spring: 2; damping: 0.2 }
+ y: Follow { 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
+ SetProperties { target: img; opacity: 1 }
+ },
+ State{ name: "DeathState"; when: dying == true
+ SetProperties { target: particles; count: 50 }
+ SetProperties { target: particles; opacity: 1 }
+ SetProperties { target: particles; emitting: false } // i.e. emit only once
+ SetProperties { 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..c7a49f1
--- /dev/null
+++ b/demos/declarative/samegame/content/Button.qml
@@ -0,0 +1,18 @@
+import Qt 4.6
+
+Rect {
+ id: page; color: activePalette.button; width: txtItem.width+20; height: txtItem.height+4
+ border.width: 1; border.color: activePalette.mid; radius: 10;
+ signal clicked
+ property string text: "Button"
+ 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: page.clicked() }
+ Text {
+ id: txtItem; text: page.text; anchors.centerIn: page; color: activePalette.buttonText
+ font.size: 14;
+ }
+}
diff --git a/demos/declarative/samegame/content/Dialog.qml b/demos/declarative/samegame/content/Dialog.qml
new file mode 100644
index 0000000..7326d73
--- /dev/null
+++ b/demos/declarative/samegame/content/Dialog.qml
@@ -0,0 +1,15 @@
+import Qt 4.6
+
+Rect {
+ id: page
+ color: "white"; border.width: 1; width: 200; height: 60;
+ property string text: "Hello World!"
+ opacity: 0
+ opacity: Behavior {
+ SequentialAnimation {
+ NumberAnimation {property: "opacity"; from: 0; duration: 1500 }
+ NumberAnimation {property: "opacity"; to: 0; duration: 1500 }
+ }
+ }
+ Text { anchors.centerIn: parent; text: parent.text }
+}
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..f04fb4c
--- /dev/null
+++ b/demos/declarative/samegame/content/samegame.js
@@ -0,0 +1,211 @@
+/* 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 component;
+
+//Index function used instead of a 2D array
+function index(xIdx,yIdx){
+ return xIdx + (yIdx * maxX);
+}
+
+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;
+
+ //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);
+ }
+ }
+}
+
+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))){
+ dialog.text = "Game Over. Your score is " + gameCanvas.score;
+ dialog.opacity = 1;
+ }
+}
+
+//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;
+}
diff --git a/demos/declarative/webbrowser/README b/demos/declarative/webbrowser/README
new file mode 100644
index 0000000..7bfd41f
--- /dev/null
+++ b/demos/declarative/webbrowser/README
@@ -0,0 +1,6 @@
+For good performance, be sure to use disk cache for remote content:
+
+ duiviewer -cache webbrowser.qml
+
+Otherwise everything always re-loads over the network.
+
diff --git a/demos/declarative/webbrowser/content/RectSoftShadow.qml b/demos/declarative/webbrowser/content/RectSoftShadow.qml
new file mode 100644
index 0000000..8b337cd
--- /dev/null
+++ b/demos/declarative/webbrowser/content/RectSoftShadow.qml
@@ -0,0 +1,32 @@
+import Qt 4.6
+
+Item {
+ Image {
+ source: "pics/softshadow-left.sci"
+ x: -16
+ y: -16
+ width: 16
+ height: parent.height+32
+ }
+ Image {
+ 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/webbrowser.qml b/demos/declarative/webbrowser/webbrowser.qml
new file mode 100644
index 0000000..7a7d9e2
--- /dev/null
+++ b/demos/declarative/webbrowser/webbrowser.qml
@@ -0,0 +1,374 @@
+import Qt 4.6
+
+import "content"
+
+Item {
+ id: WebBrowser
+
+ property var url : "http://www.qtsoftware.com"
+
+ width: 640
+ height: 480
+ state: "Normal"
+
+ Script {
+ function zoomOut() {
+ WebBrowser.state = "ZoomedOut";
+ }
+ function toggleZoom() {
+ if(WebBrowser.state == "ZoomedOut") {
+ Flick.centerX = MyWebView.mouseX;
+ Flick.centerY = MyWebView.mouseY;
+ WebBrowser.state = "Normal";
+ } else {
+ zoomOut();
+ }
+ }
+ }
+
+ Item {
+ id: WebPanel
+ anchors.fill: parent
+ clip: true
+ Rect {
+ 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.xPosition
+ y: -Flick.yPosition
+ width: MyWebView.width*MyWebView.scale
+ height: Flick.y+MyWebView.height*MyWebView.scale
+ }
+ Item {
+ id: HeaderSpace
+ width: parent.width
+ height: 60
+ z: 1
+
+ Image {
+ id: Header
+ source: "content/pics/header.png"
+ width: parent.width
+ height: 64
+ state: "Normal"
+ x: Flick.xPosition < 0 ? -Flick.xPosition : Flick.xPosition > Flick.viewportWidth-Flick.width
+ ? -Flick.xPosition+Flick.viewportWidth-Flick.width : 0
+ y: Flick.yPosition < 0 ? -Flick.yPosition : progressOff*
+ (Flick.yPosition>height?-height:-Flick.yPosition)
+ 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.size: 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
+ hAlign: "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
+ Image {
+ source: "content/pics/addressbar.sci"
+ anchors.fill: UrlBox
+ }
+ Image {
+ id: UrlBoxhl
+ source: "content/pics/addressbar-filled.sci"
+ width: parent.width*MyWebView.progress
+ height: parent.height
+ opacity: 1-Header.progressOff
+ clip: true
+ }
+
+ /*
+ KeyProxy {
+ id: proxy
+ anchors.left: UrlBox.left
+ anchors.fill: UrlBox
+ targets: [keyActions,EditUrl]
+ }
+ KeyActions {
+ id: keyActions
+ keyReturn: "WebBrowser.url = EditUrl.text; proxy.focus=false;"
+ }
+ */
+ TextEdit {
+ id: EditUrl
+
+ text: MyWebView.url == '' ? ' ' : MyWebView.url
+ wrap: false
+ font.size: 11
+ color: "#555555"
+ focusOnPress: true
+
+ 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
+ SetProperties { target: Header; progressOff: 1 }
+ },
+ State {
+ name: "ProgressShown"
+ when: MyWebView.progress < 1.0
+ SetProperties { 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
+
+ property real centerX : 0
+ property real centerY : 0
+
+ WebView {
+ id: MyWebView
+ cacheSize: 4000000
+
+ url: WebBrowser.url
+ smooth: !Flick.moving
+ fillColor: "white"
+ focus: true
+
+ idealWidth: Flick.width
+ idealHeight: Flick.height/scale
+ scale: (width > 0) ? Flick.width/width*zoomedOut+(1-zoomedOut) : 1
+
+ onUrlChanged: { Flick.xPosition=0; Flick.yPosition=0; zoomOut() }
+ onDoubleClick: { toggleZoom() }
+
+ property real zoomedOut : 1
+ }
+ Rect {
+ id: WebViewTint
+ color: "black"
+ opacity: 0
+ anchors.fill: MyWebView
+ MouseRegion {
+ anchors.fill: WebViewTint
+ onClicked: { proxy.focus=false }
+ }
+ }
+ }
+ Image {
+ id: Footer
+ source: "content/pics/footer.sci"
+ width: parent.width
+ height: 43
+ anchors.bottom: parent.bottom
+ Rect {
+ 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
+ SetProperties { target: back_e; opacity: 1 }
+ SetProperties { target: back_d; opacity: 0 }
+ },
+ State {
+ name: "Disabled"
+ when: MyWebView.back.enabled==false
+ SetProperties { target: back_e; opacity: 0 }
+ SetProperties { 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
+ SetProperties { target: forward_e; opacity: 1 }
+ SetProperties { target: forward_d; opacity: 0 }
+ },
+ State {
+ name: "Disabled"
+ when: MyWebView.forward.enabled==false
+ SetProperties { target: forward_e; opacity: 0 }
+ SetProperties { 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() }
+ }
+ }
+ }
+ }
+ states: [
+ State {
+ name: "Normal"
+ SetProperties { target: MyWebView; zoomedOut: 0 }
+ SetProperties { target: Flick; explicit: true; xPosition: Math.min(MyWebView.width-Flick.width,Math.max(0,Flick.centerX-Flick.width/2)) }
+ SetProperties { target: Flick; explicit: true; yPosition: Math.min(MyWebView.height-Flick.height,Math.max(0,Flick.centerY-Flick.height/2)) }
+ },
+ State {
+ name: "ZoomedOut"
+ SetProperties { target: MyWebView; zoomedOut: 1 }
+ }
+ ]
+ transitions: [
+ Transition {
+ SequentialAnimation {
+ SetPropertyAction {
+ target: MyWebView
+ property: "smooth"
+ value: false
+ }
+ ParallelAnimation {
+ NumberAnimation {
+ target: MyWebView
+ properties: "zoomedOut"
+ easing: "easeInOutQuad"
+ duration: 200
+ }
+ NumberAnimation {
+ target: Flick
+ properties: "xPosition,yPosition"
+ easing: "easeInOutQuad"
+ duration: 200
+ }
+ }
+ SetPropertyAction {
+ target: MyWebView
+ property: "smooth"
+ value: !Flick.moving
+ }
+ }
+ }
+ ]
+}