diff options
Diffstat (limited to 'demos')
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 Binary files differnew file mode 100644 index 0000000..d33e0c7 --- /dev/null +++ b/demos/declarative/contacts/contacts.sqlite diff --git a/demos/declarative/contacts/pics/cancel.png b/demos/declarative/contacts/pics/cancel.png Binary files differnew file mode 100644 index 0000000..ecc9533 --- /dev/null +++ b/demos/declarative/contacts/pics/cancel.png diff --git a/demos/declarative/contacts/pics/email.png b/demos/declarative/contacts/pics/email.png Binary files differnew file mode 100644 index 0000000..04b3865 --- /dev/null +++ b/demos/declarative/contacts/pics/email.png diff --git a/demos/declarative/contacts/pics/new.png b/demos/declarative/contacts/pics/new.png Binary files differnew file mode 100644 index 0000000..c7ebac3 --- /dev/null +++ b/demos/declarative/contacts/pics/new.png diff --git a/demos/declarative/contacts/pics/ok.png b/demos/declarative/contacts/pics/ok.png Binary files differnew file mode 100644 index 0000000..5795f04 --- /dev/null +++ b/demos/declarative/contacts/pics/ok.png diff --git a/demos/declarative/contacts/pics/phone.png b/demos/declarative/contacts/pics/phone.png Binary files differnew file mode 100644 index 0000000..fc9c222 --- /dev/null +++ b/demos/declarative/contacts/pics/phone.png diff --git a/demos/declarative/contacts/pics/search.png b/demos/declarative/contacts/pics/search.png Binary files differnew file mode 100644 index 0000000..cc74e69 --- /dev/null +++ b/demos/declarative/contacts/pics/search.png diff --git a/demos/declarative/contacts/pics/trash.png b/demos/declarative/contacts/pics/trash.png Binary files differnew file mode 100644 index 0000000..2042595 --- /dev/null +++ b/demos/declarative/contacts/pics/trash.png 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 Binary files differnew file mode 100644 index 0000000..5b37072 --- /dev/null +++ b/demos/declarative/flickr/common/pics/background.png diff --git a/demos/declarative/flickr/common/pics/button-pressed.png b/demos/declarative/flickr/common/pics/button-pressed.png Binary files differnew file mode 100644 index 0000000..e434d32 --- /dev/null +++ b/demos/declarative/flickr/common/pics/button-pressed.png 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 Binary files differnew file mode 100644 index 0000000..56a63ce --- /dev/null +++ b/demos/declarative/flickr/common/pics/button.png 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 Binary files differnew file mode 100644 index 0000000..4ad43cc --- /dev/null +++ b/demos/declarative/flickr/common/pics/ghns_star.png diff --git a/demos/declarative/flickr/common/pics/loading.png b/demos/declarative/flickr/common/pics/loading.png Binary files differnew file mode 100644 index 0000000..47a1589 --- /dev/null +++ b/demos/declarative/flickr/common/pics/loading.png diff --git a/demos/declarative/flickr/common/pics/reflection.png b/demos/declarative/flickr/common/pics/reflection.png Binary files differnew file mode 100644 index 0000000..c143a48 --- /dev/null +++ b/demos/declarative/flickr/common/pics/reflection.png diff --git a/demos/declarative/flickr/common/pics/shadow-bottom.png b/demos/declarative/flickr/common/pics/shadow-bottom.png Binary files differnew file mode 100644 index 0000000..523f6e7 --- /dev/null +++ b/demos/declarative/flickr/common/pics/shadow-bottom.png diff --git a/demos/declarative/flickr/common/pics/shadow-corner.png b/demos/declarative/flickr/common/pics/shadow-corner.png Binary files differnew file mode 100644 index 0000000..ef8c856 --- /dev/null +++ b/demos/declarative/flickr/common/pics/shadow-corner.png diff --git a/demos/declarative/flickr/common/pics/shadow-right-screen.png b/demos/declarative/flickr/common/pics/shadow-right-screen.png Binary files differnew file mode 100644 index 0000000..9856c4f --- /dev/null +++ b/demos/declarative/flickr/common/pics/shadow-right-screen.png diff --git a/demos/declarative/flickr/common/pics/shadow-right.png b/demos/declarative/flickr/common/pics/shadow-right.png Binary files differnew file mode 100644 index 0000000..f534a35 --- /dev/null +++ b/demos/declarative/flickr/common/pics/shadow-right.png 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 Binary files differnew file mode 100644 index 0000000..5d370cd --- /dev/null +++ b/demos/declarative/flickr/mobile/images/gloss.png diff --git a/demos/declarative/flickr/mobile/images/lineedit.png b/demos/declarative/flickr/mobile/images/lineedit.png Binary files differnew file mode 100644 index 0000000..2cc38dc --- /dev/null +++ b/demos/declarative/flickr/mobile/images/lineedit.png 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 Binary files differnew file mode 100644 index 0000000..9f36727 --- /dev/null +++ b/demos/declarative/flickr/mobile/images/stripes.png diff --git a/demos/declarative/flickr/mobile/images/titlebar.png b/demos/declarative/flickr/mobile/images/titlebar.png Binary files differnew file mode 100644 index 0000000..51c9008 --- /dev/null +++ b/demos/declarative/flickr/mobile/images/titlebar.png 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 Binary files differnew file mode 100644 index 0000000..8862898 --- /dev/null +++ b/demos/declarative/flickr/mobile/images/toolbutton.png 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 Binary files differnew file mode 100644 index 0000000..445567f --- /dev/null +++ b/demos/declarative/minehunt/pics/No-Ones-Laughing-3.jpg diff --git a/demos/declarative/minehunt/pics/back.png b/demos/declarative/minehunt/pics/back.png Binary files differnew file mode 100644 index 0000000..f6b3f0b --- /dev/null +++ b/demos/declarative/minehunt/pics/back.png diff --git a/demos/declarative/minehunt/pics/bomb-color.png b/demos/declarative/minehunt/pics/bomb-color.png Binary files differnew file mode 100644 index 0000000..61ad0a9 --- /dev/null +++ b/demos/declarative/minehunt/pics/bomb-color.png diff --git a/demos/declarative/minehunt/pics/bomb.png b/demos/declarative/minehunt/pics/bomb.png Binary files differnew file mode 100644 index 0000000..a992575 --- /dev/null +++ b/demos/declarative/minehunt/pics/bomb.png diff --git a/demos/declarative/minehunt/pics/face-sad.png b/demos/declarative/minehunt/pics/face-sad.png Binary files differnew file mode 100644 index 0000000..cf00aaf --- /dev/null +++ b/demos/declarative/minehunt/pics/face-sad.png diff --git a/demos/declarative/minehunt/pics/face-smile-big.png b/demos/declarative/minehunt/pics/face-smile-big.png Binary files differnew file mode 100644 index 0000000..f9c2335 --- /dev/null +++ b/demos/declarative/minehunt/pics/face-smile-big.png diff --git a/demos/declarative/minehunt/pics/face-smile.png b/demos/declarative/minehunt/pics/face-smile.png Binary files differnew file mode 100644 index 0000000..3d66d72 --- /dev/null +++ b/demos/declarative/minehunt/pics/face-smile.png diff --git a/demos/declarative/minehunt/pics/flag-color.png b/demos/declarative/minehunt/pics/flag-color.png Binary files differnew file mode 100644 index 0000000..aadad0f --- /dev/null +++ b/demos/declarative/minehunt/pics/flag-color.png diff --git a/demos/declarative/minehunt/pics/flag.png b/demos/declarative/minehunt/pics/flag.png Binary files differnew file mode 100644 index 0000000..39cde4d --- /dev/null +++ b/demos/declarative/minehunt/pics/flag.png diff --git a/demos/declarative/minehunt/pics/front.png b/demos/declarative/minehunt/pics/front.png Binary files differnew file mode 100644 index 0000000..834331b --- /dev/null +++ b/demos/declarative/minehunt/pics/front.png diff --git a/demos/declarative/minehunt/pics/star.png b/demos/declarative/minehunt/pics/star.png Binary files differnew file mode 100644 index 0000000..3772359 --- /dev/null +++ b/demos/declarative/minehunt/pics/star.png 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 Binary files differnew file mode 100644 index 0000000..25e885f --- /dev/null +++ b/demos/declarative/samegame/content/pics/background.png diff --git a/demos/declarative/samegame/content/pics/blueStar.png b/demos/declarative/samegame/content/pics/blueStar.png Binary files differnew file mode 100644 index 0000000..ff9588f --- /dev/null +++ b/demos/declarative/samegame/content/pics/blueStar.png diff --git a/demos/declarative/samegame/content/pics/blueStone.png b/demos/declarative/samegame/content/pics/blueStone.png Binary files differnew file mode 100644 index 0000000..bf342e0 --- /dev/null +++ b/demos/declarative/samegame/content/pics/blueStone.png diff --git a/demos/declarative/samegame/content/pics/greenStar.png b/demos/declarative/samegame/content/pics/greenStar.png Binary files differnew file mode 100644 index 0000000..cd06854 --- /dev/null +++ b/demos/declarative/samegame/content/pics/greenStar.png diff --git a/demos/declarative/samegame/content/pics/greenStone.png b/demos/declarative/samegame/content/pics/greenStone.png Binary files differnew file mode 100644 index 0000000..5ac14a5 --- /dev/null +++ b/demos/declarative/samegame/content/pics/greenStone.png diff --git a/demos/declarative/samegame/content/pics/redStar.png b/demos/declarative/samegame/content/pics/redStar.png Binary files differnew file mode 100644 index 0000000..0a4dffe --- /dev/null +++ b/demos/declarative/samegame/content/pics/redStar.png diff --git a/demos/declarative/samegame/content/pics/redStone.png b/demos/declarative/samegame/content/pics/redStone.png Binary files differnew file mode 100644 index 0000000..b099f60 --- /dev/null +++ b/demos/declarative/samegame/content/pics/redStone.png diff --git a/demos/declarative/samegame/content/pics/star.png b/demos/declarative/samegame/content/pics/star.png Binary files differnew file mode 100644 index 0000000..defbde5 --- /dev/null +++ b/demos/declarative/samegame/content/pics/star.png diff --git a/demos/declarative/samegame/content/pics/yellowStone.png b/demos/declarative/samegame/content/pics/yellowStone.png Binary files differnew file mode 100644 index 0000000..c56124a --- /dev/null +++ b/demos/declarative/samegame/content/pics/yellowStone.png 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 Binary files differnew file mode 100644 index 0000000..d8452ec --- /dev/null +++ b/demos/declarative/webbrowser/content/pics/addressbar-filled.png 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 Binary files differnew file mode 100644 index 0000000..3278f58 --- /dev/null +++ b/demos/declarative/webbrowser/content/pics/addressbar.png 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 Binary files differnew file mode 100644 index 0000000..91b9e76 --- /dev/null +++ b/demos/declarative/webbrowser/content/pics/back-disabled.png diff --git a/demos/declarative/webbrowser/content/pics/back.png b/demos/declarative/webbrowser/content/pics/back.png Binary files differnew file mode 100644 index 0000000..9988dd3 --- /dev/null +++ b/demos/declarative/webbrowser/content/pics/back.png diff --git a/demos/declarative/webbrowser/content/pics/footer.png b/demos/declarative/webbrowser/content/pics/footer.png Binary files differnew file mode 100644 index 0000000..8391a93 --- /dev/null +++ b/demos/declarative/webbrowser/content/pics/footer.png 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 Binary files differnew file mode 100644 index 0000000..cb87f4f --- /dev/null +++ b/demos/declarative/webbrowser/content/pics/forward-disabled.png diff --git a/demos/declarative/webbrowser/content/pics/forward.png b/demos/declarative/webbrowser/content/pics/forward.png Binary files differnew file mode 100644 index 0000000..83870ee --- /dev/null +++ b/demos/declarative/webbrowser/content/pics/forward.png diff --git a/demos/declarative/webbrowser/content/pics/header.png b/demos/declarative/webbrowser/content/pics/header.png Binary files differnew file mode 100644 index 0000000..26588c3 --- /dev/null +++ b/demos/declarative/webbrowser/content/pics/header.png diff --git a/demos/declarative/webbrowser/content/pics/reload.png b/demos/declarative/webbrowser/content/pics/reload.png Binary files differnew file mode 100644 index 0000000..45b5535 --- /dev/null +++ b/demos/declarative/webbrowser/content/pics/reload.png diff --git a/demos/declarative/webbrowser/content/pics/softshadow-bottom.png b/demos/declarative/webbrowser/content/pics/softshadow-bottom.png Binary files differnew file mode 100644 index 0000000..85b0b44 --- /dev/null +++ b/demos/declarative/webbrowser/content/pics/softshadow-bottom.png diff --git a/demos/declarative/webbrowser/content/pics/softshadow-left.png b/demos/declarative/webbrowser/content/pics/softshadow-left.png Binary files differnew file mode 100644 index 0000000..02926d1 --- /dev/null +++ b/demos/declarative/webbrowser/content/pics/softshadow-left.png 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 Binary files differnew file mode 100644 index 0000000..e459f4f --- /dev/null +++ b/demos/declarative/webbrowser/content/pics/softshadow-right.png 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 Binary files differnew file mode 100644 index 0000000..9a9e232 --- /dev/null +++ b/demos/declarative/webbrowser/content/pics/softshadow-top.png 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 Binary files differnew file mode 100644 index 0000000..ecc9533 --- /dev/null +++ b/demos/declarative/webbrowser/fieldtext/pics/cancel.png diff --git a/demos/declarative/webbrowser/fieldtext/pics/ok.png b/demos/declarative/webbrowser/fieldtext/pics/ok.png Binary files differnew file mode 100644 index 0000000..5795f04 --- /dev/null +++ b/demos/declarative/webbrowser/fieldtext/pics/ok.png 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() } + } + } + } + } +} |