diff options
Diffstat (limited to 'demos')
122 files changed, 3812 insertions, 0 deletions
diff --git a/demos/declarative/calculator/CalcButton.qml b/demos/declarative/calculator/CalcButton.qml new file mode 100644 index 0000000..c2e3a81 --- /dev/null +++ b/demos/declarative/calculator/CalcButton.qml @@ -0,0 +1,41 @@ +import Qt 4.6 + +Rectangle { + property alias operation: label.text + 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 { id: label; anchors.centerIn: parent; 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..cd6490a --- /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..8041025 --- /dev/null +++ b/demos/declarative/calculator/calculator.qml @@ -0,0 +1,128 @@ +import Qt 4.6 + +Rectangle { + 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 + 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/flickr/common/ImageDetails.qml b/demos/declarative/flickr/common/ImageDetails.qml new file mode 100644 index 0000000..19cad06 --- /dev/null +++ b/demos/declarative/flickr/common/ImageDetails.qml @@ -0,0 +1,161 @@ +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.y: container.height / 2; + 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: Text.Raised; styleColor: "black"; color: "white"; elide: Text.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: flickable; x: 220; width: 480; height: 210; y: 130; clip: true + viewportWidth: 480; viewportHeight: descriptionText.height + + WebView { id: descriptionText; width: parent.width + html: "<style TYPE=\"text/css\">body {color: white;} a:link {color: cyan; text-decoration: underline; }</style>" + container.photoDescription } + } + + Text { id: size; color: "white"; width: 300; x: 40; y: 300 + text: "<b>Size:</b> " + container.photoWidth + 'x' + container.photoHeight } + Text { id: type; color: "white"; width: 300; x: 40; anchors.top: size.bottom + text: "<b>Type:</b> " + container.photoType } + + Text { id: author; color: "white"; width: 300; x: 220; y: 80 + text: "<b>Author:</b> " + container.photoAuthor } + Text { id: date; color: "white"; width: 300; x: 220; anchors.top: author.bottom + text: "<b>Published:</b> " + container.photoDate } + Text { id: tagsLabel; color: "white"; x: 220; anchors.top: date.bottom; + text: container.photoTags == "" ? "" : "<b>Tags:</b> " } + Text { id: tags; color: "white"; width: parent.width-x-20; + anchors.left: tagsLabel.right; anchors.top: date.bottom; + elide: Text.ElideRight; text: container.photoTags } + + ScrollBar { id: scrollBar; x: 720; y: flickable.y; width: 7; height: flickable.height; opacity: 0; + flickableArea: flickable; clip: true } + } + + back: Item { + anchors.fill: container + + 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..5ee048b --- /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..64a04c4 --- /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..c12b642 --- /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: mouseRegion + 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: mouseRegion.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..b24b296 --- /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,labeltext.width + editor.width + 20) + height: buttonImage.height + + states: [ + State { + name: "Edit" + PropertyChanges { + target: labeltext + text: container.label + ": " + } + PropertyChanges { + target: labeltext + 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: mouseRegion + anchors.fill: buttonImage + onClicked: { container.state = container.state=="Edit" ? "" : "Edit" } + states: [ + State { + when: mouseRegion.pressed == true + PropertyChanges { + target: pressed + opacity: 1 + } + } + ] + } + + Text { + id: labeltext + 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: labeltext.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..fd9be10 --- /dev/null +++ b/demos/declarative/flickr/common/Progress.qml @@ -0,0 +1,32 @@ +import Qt 4.6 + +Item { + property var progress: 0 + + Rectangle { + 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 { + 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..feebcb0 --- /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..fa1645c --- /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 { + 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..173021b --- /dev/null +++ b/demos/declarative/flickr/common/Star.qml @@ -0,0 +1,45 @@ +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..b8db272 --- /dev/null +++ b/demos/declarative/flickr/common/pics/button-pressed.sci @@ -0,0 +1,5 @@ +border.left: 8 +border.top: 4 +border.bottom: 4 +border.right: 8 +source: 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..b8db272 --- /dev/null +++ b/demos/declarative/flickr/common/pics/button.sci @@ -0,0 +1,5 @@ +border.left: 8 +border.top: 4 +border.bottom: 4 +border.right: 8 +source: 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/common/qmldir b/demos/declarative/flickr/common/qmldir new file mode 100644 index 0000000..0c94f60 --- /dev/null +++ b/demos/declarative/flickr/common/qmldir @@ -0,0 +1,10 @@ +ImageDetails 0.0 ImageDetails.qml +LikeOMeter 0.0 LikeOMeter.qml +Loading 0.0 Loading.qml +MediaButton 0.0 MediaButton.qml +MediaLineEdit 0.0 MediaLineEdit.qml +Progress 0.0 Progress.qml +RssModel 0.0 RssModel.qml +ScrollBar 0.0 ScrollBar.qml +Slider 0.0 Slider.qml +Star 0.0 Star.qml diff --git a/demos/declarative/flickr/flickr-desktop.qml b/demos/declarative/flickr/flickr-desktop.qml new file mode 100644 index 0000000..337f77c --- /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" + SequentialAnimation { + 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: Text.Raised; styleColor: "black" + } +} diff --git a/demos/declarative/flickr/flickr-mobile-90.qml b/demos/declarative/flickr/flickr-mobile-90.qml new file mode 100644 index 0000000..259ff10 --- /dev/null +++ b/demos/declarative/flickr/flickr-mobile-90.qml @@ -0,0 +1,10 @@ +import Qt 4.6 + +Item { + width: 480; height: 320 + + Loader { + y: 320; rotation: -90 + source: "flickr-mobile.qml" + } +} diff --git a/demos/declarative/flickr/flickr-mobile.qml b/demos/declarative/flickr/flickr-mobile.qml new file mode 100644 index 0000000..0a89c4f --- /dev/null +++ b/demos/declarative/flickr/flickr-mobile.qml @@ -0,0 +1,82 @@ +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: Image.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 + } + + Connection { + sender: imageDetails; signal: "closed()" + script: { + if (background.state == "DetailedView") { + background.state = ''; + imageDetails.photoUrl = ""; + } + } + } + + states: State { + name: "DetailedView" + PropertyChanges { target: views; x: -parent.width } + PropertyChanges { target: toolBar; button1Label: "More..." } + PropertyChanges { + target: toolBar + onButton1Clicked: if (imageDetails.state=='') imageDetails.state='Back'; else imageDetails.state='' + } + PropertyChanges { target: toolBar; button2Label: "Back" } + PropertyChanges { target: toolBar; onButton2Clicked: imageDetails.closed() } + } + + 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..770330c --- /dev/null +++ b/demos/declarative/flickr/mobile/Button.qml @@ -0,0 +1,38 @@ +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: mouseRegion + anchors.fill: buttonImage + onClicked: { container.clicked(); } + } + Text { + color: "white" + anchors.centerIn: buttonImage; font.bold: true + text: container.text; style: Text.Raised; styleColor: "black" + } + states: [ + State { + name: "Pressed" + when: mouseRegion.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..9b9fb24 --- /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" + PropertyChanges { target: scaleMe; scale: 1 } + 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..1963bf5 --- /dev/null +++ b/demos/declarative/flickr/mobile/ImageDetails.qml @@ -0,0 +1,124 @@ +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 + } + + Column { + spacing: 10 + anchors { + left: parent.left; leftMargin: 20 + right: parent.right; rightMargin: 20 + top: parent.top; topMargin: 180 + } + Text { font.bold: true; color: "white"; elide: Text.ElideRight; text: container.photoTitle } + Text { color: "white"; elide: Text.ElideRight; text: "<b>Size:</b> " + container.photoWidth + 'x' + container.photoHeight } + Text { color: "white"; elide: Text.ElideRight; text: "<b>Type:</b> " + container.photoType } + Text { color: "white"; elide: Text.ElideRight; text: "<b>Author:</b> " + container.photoAuthor } + Text { color: "white"; elide: Text.ElideRight; text: "<b>Published:</b> " + container.photoDate } + Text { color: "white"; elide: Text.ElideRight; text: container.photoTags == "" ? "" : "<b>Tags:</b> " } + Text { color: "white"; elide: Text.ElideRight; elide: Text.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: flickable; anchors.fill: parent; clip: true + viewportWidth: imageContainer.width; viewportHeight: imageContainer.height + + Item { + id: imageContainer + width: Math.max(bigImage.width * bigImage.scale, flickable.width); + height: Math.max(bigImage.height * bigImage.scale, flickable.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: !flickable.moving + onStatusChanged : { + // Default scale shows the entire image. + if (status == 1 && width != 0) { + slider.minimum = Math.min(flickable.width / width, flickable.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 > flickable.width) { + var xoff = (flickable.width/2 + flickable.viewportX) * value / prevScale; + flickable.viewportX = xoff - flickable.width/2; + } + if (bigImage.height * value > flickable.height) { + var yoff = (flickable.height/2 + flickable.viewportY) * value / prevScale; + flickable.viewportY = yoff - flickable.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: !flickable.moving } + } + } +} diff --git a/demos/declarative/flickr/mobile/ListDelegate.qml b/demos/declarative/flickr/mobile/ListDelegate.qml new file mode 100644 index 0000000..75c4572 --- /dev/null +++ b/demos/declarative/flickr/mobile/ListDelegate.qml @@ -0,0 +1,23 @@ +import Qt 4.6 + +Component { + 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 { + x: 6; y: 4; width: 77; height: 77; color: "white"; smooth: true + + Image { 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: Text.ElideRight; style: Text.Raised; styleColor: "black" } + Text { text: photoAuthor; color: "white"; width: parent.width; elide: Text.ElideLeft; color: "#cccccc"; style: Text.Raised; styleColor: "black" } + Text { text: photoDate; color: "white"; width: parent.width; elide: Text.ElideRight; color: "#cccccc"; style: Text.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..07b9762 --- /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: Text.ElideLeft + text: (rssModel.tags=="" ? untaggedString : taggedString + rssModel.tags) + font.bold: true; color: "White"; style: Text.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..f96c767 --- /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..054bff7 --- /dev/null +++ b/demos/declarative/flickr/mobile/images/lineedit.sci @@ -0,0 +1,5 @@ +border.left: 10 +border.top: 10 +border.bottom: 10 +border.right: 10 +source: 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..0418d94 --- /dev/null +++ b/demos/declarative/flickr/mobile/images/titlebar.sci @@ -0,0 +1,5 @@ +border.left: 10 +border.top: 12 +border.bottom: 12 +border.right: 10 +source: 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..1131001 --- /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..9e4f965 --- /dev/null +++ b/demos/declarative/flickr/mobile/images/toolbutton.sci @@ -0,0 +1,5 @@ +border.left: 15 +border.top: 4 +border.bottom: 4 +border.right: 15 +source: toolbutton.png diff --git a/demos/declarative/minehunt/Description.qml b/demos/declarative/minehunt/Description.qml new file mode 100644 index 0000000..440dd2e --- /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..f4cd6a5 --- /dev/null +++ b/demos/declarative/minehunt/main.cpp @@ -0,0 +1,349 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the demonstration applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "qmlengine.h" +#include "qmlcontext.h" +#include "qml.h" +#include <qmlgraphicsitem.h> +#include <qmlview.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();} + + QmlView *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 QmlView(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..e71ce90 --- /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: Image.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/content/BoomBlock.qml b/demos/declarative/samegame/content/BoomBlock.qml new file mode 100644 index 0000000..b0c297b --- /dev/null +++ b/demos/declarative/samegame/content/BoomBlock.qml @@ -0,0 +1,55 @@ +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 { 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 } + StateChangeScript { script: block.destroy(1000); } + } + ] +} diff --git a/demos/declarative/samegame/content/Button.qml b/demos/declarative/samegame/content/Button.qml new file mode 100644 index 0000000..301124e --- /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..f9a281a --- /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: myText.height + 40; + 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/qmldir b/demos/declarative/samegame/content/qmldir new file mode 100644 index 0000000..a8f8a98 --- /dev/null +++ b/demos/declarative/samegame/content/qmldir @@ -0,0 +1,3 @@ +BoomBlock 0.0 BoomBlock.qml +Button 0.0 Button.qml +Dialog 0.0 Dialog.qml diff --git a/demos/declarative/samegame/content/samegame.js b/demos/declarative/samegame/content/samegame.js new file mode 100755 index 0000000..4d5a6be --- /dev/null +++ b/demos/declarative/samegame/content/samegame.js @@ -0,0 +1,256 @@ +/* This script file handles the game logic */ +//Note that X/Y referred to here are in game coordinates +var maxX = 10;//Nums are for gameCanvas.tileSize 40 +var maxY = 15; +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 scoresURL = ""; +var timer; +var component = createComponent(tileSrc); + +//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 getTileSize() +{ + return tileSize; +} + +function initBoard() +{ + for(var i = 0; i<maxIndex; i++){ + //Delete old blocks + if(board[i] != null) + board[i].destroy(); + } + + //Calculate board size + maxX = Math.floor(gameCanvas.width/gameCanvas.tileSize); + maxY = Math.floor(gameCanvas.height/gameCanvas.tileSize); + maxIndex = maxY*maxX; + + //Close dialogs + scoreName.forceClose(); + dialog.forceClose(); + + var a = new Date(); + //Initialize Board + board = new Array(maxIndex); + gameCanvas.score = 0; + for(var xIdx=0; xIdx<maxX; xIdx++){ + for(var yIdx=0; yIdx<maxY; yIdx++){ + board[index(xIdx,yIdx)] = null; + createBlock(xIdx,yIdx); + } + } + timer = new Date(); + + print(timer.valueOf() - a.valueOf()); +} + +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) +{ + var xIdx = Math.floor(x/gameCanvas.tileSize); + var yIdx = Math.floor(y/gameCanvas.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(var xIdx=0; xIdx<maxX; xIdx++){ + var fallDist = 0; + for(var yIdx=maxY-1; yIdx>=0; yIdx--){ + if(board[index(xIdx,yIdx)] == null){ + fallDist += 1; + }else{ + if(fallDist > 0){ + var obj = board[index(xIdx,yIdx)]; + obj.targetY += fallDist * gameCanvas.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 * gameCanvas.tileSize; + board[index(xIdx-fallDist,yIdx)] = obj; + board[index(xIdx,yIdx)] = null; + } + } + } + } +} + +function victoryCheck() +{ + //awards bonuses for no tiles left + var deservesBonus = true; + for(var 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; + scoreName.show("You won! Please enter your name: "); + //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; + var 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); +} + +function createBlock(xIdx,yIdx){ + // Note that we don't wait for the component to become ready. This will + // only work if the block QML is a local file. Otherwise the component will + // not be ready immediately. There is a statusChanged signal on the + // component you could use if you want to wait to load remote files. + if(component.isReady){ + var 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*gameCanvas.tileSize; + dynamicObject.targetX = xIdx*gameCanvas.tileSize; + dynamicObject.targetY = yIdx*gameCanvas.tileSize; + dynamicObject.width = gameCanvas.tileSize; + dynamicObject.height = gameCanvas.tileSize; + dynamicObject.spawned = true; + board[index(xIdx,yIdx)] = dynamicObject; + }else{//isError or isLoading + print("error loading block component"); + print(component.errorsString()); + return false; + } + return true; +} + +function saveHighScore(name) { + if(scoresURL!="") + sendHighScore(name); + //OfflineStorage + var db = openDatabase("SameGameScores", "1.0", "Local SameGame High Scores",100); + var dataStr = "INSERT INTO Scores VALUES(?, ?, ?, ?)"; + var data = [name, gameCanvas.score, maxX+"x"+maxY ,Math.floor(timer/1000)]; + db.transaction( + function(tx) { + tx.executeSql('CREATE TABLE IF NOT EXISTS Scores(name TEXT, score NUMBER, gridSize TEXT, time NUMBER)',[]); + tx.executeSql(dataStr, data); + + tx.executeSql('SELECT * FROM Scores WHERE gridSize = "12x17" ORDER BY score desc LIMIT 10',[], + function(tx, rs) { + var r = "\nHIGH SCORES for a standard sized grid\n\n" + for(var i = 0; i < rs.rows.length; i++){ + r += (i+1)+". " + rs.rows.item(i).name +' got ' + + rs.rows.item(i).score + ' points in ' + + rs.rows.item(i).time + ' seconds.\n'; + } + dialog.show(r); + }, + function(tx, error) { + print("ERROR:", error.message); + } + ); + }, + function() { + print("ERROR in transaction"); + }, + function() { + //print("Transaction successful"); + } + ); +} + +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/samegame/samegame.qml b/demos/declarative/samegame/samegame.qml new file mode 100644 index 0000000..4560b56 --- /dev/null +++ b/demos/declarative/samegame/samegame.qml @@ -0,0 +1,77 @@ +import Qt 4.6 +import "content" + +Rectangle { + id: screen + width: 490; height: 720 + + 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: Image.PreserveAspectCrop + } + + Item { + id: gameCanvas + property int score: 0 + property int tileSize: 40 + + Script { source: "content/samegame.js" } + + z: 20; anchors.centerIn: parent + width: parent.width - (parent.width % getTileSize()); + height: parent.height - (parent.height % getTileSize()); + + 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; + Text { + id: spacer + opacity: 0 + text: " You won! Please enter your name:" + } + TextInput { + id: editor + onAccepted: { + if(scoreName.opacity==1&&editor.text!="") + saveHighScore(editor.text); + scoreName.forceClose(); + } + anchors.verticalCenter: parent.verticalCenter + width: 72; focus: true + anchors.left: spacer.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/twitter/content/AuthView.qml b/demos/declarative/twitter/content/AuthView.qml new file mode 100644 index 0000000..c924649 --- /dev/null +++ b/demos/declarative/twitter/content/AuthView.qml @@ -0,0 +1,84 @@ +import Qt 4.6 + +Item { + id: wrapper + Column { + anchors.centerIn: parent + spacing: 20 + Row{ + spacing: 4 + Text { + width: 100 + text: "Screen name:" + font.pointSize: 14; font.bold: true; color: "white"; style: Text.Raised; styleColor: "black" + anchors.verticalCenter: parent.verticalCenter + horizontalAlignment: Qt.AlignRight + } + Item { + width: 160 + height: 28 + BorderImage { source: "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: 14; font.bold: true; color: "white"; style: Text.Raised; styleColor: "black" + anchors.verticalCenter: parent.verticalCenter + horizontalAlignment: Qt.AlignRight + } + Item { + width: 160 + height: 28 + BorderImage { source: "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/Button.qml b/demos/declarative/twitter/content/Button.qml new file mode 100644 index 0000000..770330c --- /dev/null +++ b/demos/declarative/twitter/content/Button.qml @@ -0,0 +1,38 @@ +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: mouseRegion + anchors.fill: buttonImage + onClicked: { container.clicked(); } + } + Text { + color: "white" + anchors.centerIn: buttonImage; font.bold: true + text: container.text; style: Text.Raised; styleColor: "black" + } + states: [ + State { + name: "Pressed" + when: mouseRegion.pressed == true + PropertyChanges { target: pressed; opacity: 1 } + } + ] +} diff --git a/demos/declarative/twitter/content/FatDelegate.qml b/demos/declarative/twitter/content/FatDelegate.qml new file mode 100644 index 0000000..7125746 --- /dev/null +++ b/demos/declarative/twitter/content/FatDelegate.qml @@ -0,0 +1,46 @@ +import Qt 4.6 + +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){ + var ret = str.replace(/@[a-zA-Z0-9_]+/g, '<a href="app://$&">$&</a>');//click to jump to user? + var 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: Text.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..f0d6d75 --- /dev/null +++ b/demos/declarative/twitter/content/HomeTitleBar.qml @@ -0,0 +1,120 @@ +import Qt 4.6 + +Item { + id: titleBar + + signal update() + onYChanged: state="" //When switching titlebars + + 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() { + 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 { + x: 6; width: 50; height: 50; color: "white"; smooth: true + anchors.verticalCenter: parent.verticalCenter + + UserModel { user: rssModel.authName; id: userModel } + Component { id: imgDelegate; + Item { + 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: Text.ElideLeft + text: "Timeline for " + rssModel.authName + font.pointSize: 10; font.bold: true; color: "white"; style: Text.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: Text.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: "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/Loading.qml b/demos/declarative/twitter/content/Loading.qml new file mode 100644 index 0000000..8b22e70 --- /dev/null +++ b/demos/declarative/twitter/content/Loading.qml @@ -0,0 +1,8 @@ +import Qt 4.6 + +Image { + id: loading; source: "images/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/twitter/content/MultiTitleBar.qml b/demos/declarative/twitter/content/MultiTitleBar.qml new file mode 100644 index 0000000..ef7de65 --- /dev/null +++ b/demos/declarative/twitter/content/MultiTitleBar.qml @@ -0,0 +1,24 @@ +import Qt 4.6 + +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/TitleBar.qml b/demos/declarative/twitter/content/TitleBar.qml new file mode 100644 index 0000000..07b9762 --- /dev/null +++ b/demos/declarative/twitter/content/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: Text.ElideLeft + text: (rssModel.tags=="" ? untaggedString : taggedString + rssModel.tags) + font.bold: true; color: "White"; style: Text.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/twitter/content/ToolBar.qml b/demos/declarative/twitter/content/ToolBar.qml new file mode 100644 index 0000000..f96c767 --- /dev/null +++ b/demos/declarative/twitter/content/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/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/content/images/gloss.png b/demos/declarative/twitter/content/images/gloss.png Binary files differnew file mode 100644 index 0000000..5d370cd --- /dev/null +++ b/demos/declarative/twitter/content/images/gloss.png diff --git a/demos/declarative/twitter/content/images/lineedit.png b/demos/declarative/twitter/content/images/lineedit.png Binary files differnew file mode 100644 index 0000000..2cc38dc --- /dev/null +++ b/demos/declarative/twitter/content/images/lineedit.png diff --git a/demos/declarative/twitter/content/images/lineedit.sci b/demos/declarative/twitter/content/images/lineedit.sci new file mode 100644 index 0000000..054bff7 --- /dev/null +++ b/demos/declarative/twitter/content/images/lineedit.sci @@ -0,0 +1,5 @@ +border.left: 10 +border.top: 10 +border.bottom: 10 +border.right: 10 +source: lineedit.png diff --git a/demos/declarative/twitter/content/images/loading.png b/demos/declarative/twitter/content/images/loading.png Binary files differnew file mode 100644 index 0000000..47a1589 --- /dev/null +++ b/demos/declarative/twitter/content/images/loading.png diff --git a/demos/declarative/twitter/content/images/stripes.png b/demos/declarative/twitter/content/images/stripes.png Binary files differnew file mode 100644 index 0000000..9f36727 --- /dev/null +++ b/demos/declarative/twitter/content/images/stripes.png diff --git a/demos/declarative/twitter/content/images/titlebar.png b/demos/declarative/twitter/content/images/titlebar.png Binary files differnew file mode 100644 index 0000000..51c9008 --- /dev/null +++ b/demos/declarative/twitter/content/images/titlebar.png diff --git a/demos/declarative/twitter/content/images/titlebar.sci b/demos/declarative/twitter/content/images/titlebar.sci new file mode 100644 index 0000000..0418d94 --- /dev/null +++ b/demos/declarative/twitter/content/images/titlebar.sci @@ -0,0 +1,5 @@ +border.left: 10 +border.top: 12 +border.bottom: 12 +border.right: 10 +source: titlebar.png diff --git a/demos/declarative/twitter/content/images/toolbutton.png b/demos/declarative/twitter/content/images/toolbutton.png Binary files differnew file mode 100644 index 0000000..1131001 --- /dev/null +++ b/demos/declarative/twitter/content/images/toolbutton.png diff --git a/demos/declarative/twitter/content/images/toolbutton.sci b/demos/declarative/twitter/content/images/toolbutton.sci new file mode 100644 index 0000000..9e4f965 --- /dev/null +++ b/demos/declarative/twitter/content/images/toolbutton.sci @@ -0,0 +1,5 @@ +border.left: 15 +border.top: 4 +border.bottom: 4 +border.right: 15 +source: toolbutton.png diff --git a/demos/declarative/twitter/twitter.qml b/demos/declarative/twitter/twitter.qml new file mode 100644 index 0000000..6cc67a1 --- /dev/null +++ b/demos/declarative/twitter/twitter.qml @@ -0,0 +1,93 @@ +import Qt 4.6 +import "content" as Twitter + +Item { + id: screen; width: 320; height: 480 + property bool userView : false + property var tmpStr + 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 { + function setUser(str){hack.running = true; tmpStr = str} + function reallySetUser(){rssModel.tags = tmpStr;} + } + + Rectangle { + id: background + anchors.fill: parent; color: "#343434"; + + Image { source: "content/images/stripes.png"; fillMode: Image.Tile; anchors.fill: parent; opacity: 0.3 } + + Twitter.RssModel { id: rssModel } + Twitter.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: Text.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 } + Twitter.ToolBar { id: toolBar; height: 40; + //anchors.bottom: parent.bottom; + //TODO: Use anchor changes instead of hard coding + y: screen.height - 40 + 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 } + } + ] + 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..6bba98e --- /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..96c5efb --- /dev/null +++ b/demos/declarative/webbrowser/content/pics/addressbar-filled.sci @@ -0,0 +1,6 @@ +border.left: 7 +border.top: 7 +border.bottom: 7 +border.right: 7 +source: 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..8f1cd18 --- /dev/null +++ b/demos/declarative/webbrowser/content/pics/addressbar.sci @@ -0,0 +1,6 @@ +border.left: 7 +border.top: 7 +border.bottom: 7 +border.right: 7 +source: 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..7be58f1 --- /dev/null +++ b/demos/declarative/webbrowser/content/pics/footer.sci @@ -0,0 +1,6 @@ +border.left: 5 +border.top: 0 +border.bottom: 0 +border.right: 5 +source: 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..45c88d5 --- /dev/null +++ b/demos/declarative/webbrowser/content/pics/softshadow-left.sci @@ -0,0 +1,5 @@ +border.left: 0 +border.top: 16 +border.bottom: 16 +border.right: 0 +source: 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..4d459c0 --- /dev/null +++ b/demos/declarative/webbrowser/content/pics/softshadow-right.sci @@ -0,0 +1,5 @@ +border.left: 0 +border.top: 16 +border.bottom: 16 +border.right: 0 +source: 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..b1c1938 --- /dev/null +++ b/demos/declarative/webbrowser/fieldtext/FieldText.qml @@ -0,0 +1,161 @@ +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 + + 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: Text.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..cfc2aa7 --- /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: -flickable.viewportX + y: -flickable.viewportY + width: webView.width*webView.scale + height: flickable.y+webView.height*webView.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: flickable.viewportX < 0 ? -flickable.viewportX : flickable.viewportX > flickable.viewportWidth-flickable.width + ? -flickable.viewportX+flickable.viewportWidth-flickable.width : 0 + y: flickable.viewportY < 0 ? -flickable.viewportY : progressOff* + (flickable.viewportY>height?-height:-flickable.viewportY) + Text { + id: headerText + + text: webView.title!='' || webView.progress == 1.0 ? webView.title : 'Loading...' + elide: Text.ElideRight + + color: "white" + styleColor: "black" + style: Text.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: Text.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*webView.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; webView.focus=true } + onCancelled: { webView.focus=true } + onStartEdit: { webView.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: webView.progress == 1.0 + PropertyChanges { target: header; progressOff: 1 } + }, + State { + name: "ProgressShown" + when: webView.progress < 1.0 + PropertyChanges { target: header; progressOff: 0; } + } + ] + transitions: [ + Transition { + NumberAnimation { + target: header + properties: "progressOff" + easing: "easeInOutQuad" + duration: 300 + } + } + ] + } + } + Flickable { + id: flickable + width: parent.width + viewportWidth: Math.max(parent.width,webView.width*webView.scale) + viewportHeight: Math.max(parent.height,webView.height*webView.scale) + anchors.top: headerSpace.bottom + anchors.bottom: footer.top + anchors.left: parent.left + anchors.right: parent.right + pressDelay: 200 + + WebView { + id: webView + 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: flickable.width + webPageWidth: 980 + + onUrlChanged: { if (url != null) { webBrowser.urlString = url.toString(); } } + onDoubleClick: { heuristicZoom(clickX,clickY) } + + SequentialAnimation { + id: quickZoom + + PropertyAction { + target: webView + property: "renderingEnabled" + value: false + } + ParallelAnimation { + NumberAnimation { + id: scaleAnim + target: webView + property: "scale" + from: 1 + to: 0 // set before calling + easing: "easeLinear" + duration: 200 + } + NumberAnimation { + id: flickVX + target: flickable + property: "viewportX" + easing: "easeLinear" + duration: 200 + from: 0 // set before calling + to: 0 // set before calling + } + NumberAnimation { + id: flickVY + target: flickable + property: "viewportY" + easing: "easeLinear" + duration: 200 + from: 0 // set before calling + to: 0 // set before calling + } + } + PropertyAction { + id: finalZoom + target: webView + property: "zoomFactor" + } + PropertyAction { + target: webView + 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: flickable + property: "viewportX" + value: 0 // set before calling + } + PropertyAction { + id: finalY + target: flickable + property: "viewportY" + value: 0 // set before calling + } + PropertyAction { + target: webView + property: "renderingEnabled" + value: true + } + } + onZooming: { + if (centerX) { + var sc = zoom/zoomFactor; + scaleAnim.to = sc; + flickVX.from = flickable.viewportX + flickVX.to = Math.min(Math.max(0,centerX-flickable.width/2),webView.width*sc-flickable.width) + finalX.value = Math.min(Math.max(0,centerX-flickable.width/2),webView.width*sc-flickable.width) + flickVY.from = flickable.viewportY + flickVY.to = Math.min(Math.max(0,centerY-flickable.height/2),webView.height*sc-flickable.height) + finalY.value = Math.min(Math.max(0,centerY-flickable.height/2),webView.height*sc-flickable.height) + finalZoom.value = zoom + quickZoom.start() + } + } + } + Rectangle { + id: webViewTint + color: "black" + opacity: 0 + anchors.fill: webView + /*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: webView.back.enabled==true + PropertyChanges { target: back_e; opacity: 1 } + PropertyChanges { target: back_d; opacity: 0 } + }, + State { + name: "Disabled" + when: webView.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 (webView.back.enabled) webView.back.trigger() } + } + } + Image { + id: reload + source: "content/pics/reload.png" + anchors.horizontalCenter: parent.horizontalCenter + anchors.verticalCenter: parent.verticalCenter + } + MouseRegion { + anchors.fill: reload + onClicked: { webView.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: webView.forward.enabled==true + PropertyChanges { target: forward_e; opacity: 1 } + PropertyChanges { target: forward_d; opacity: 0 } + }, + State { + name: "Disabled" + when: webView.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 (webView.forward.enabled) webView.forward.trigger() } + } + } + } + } +} |