improved desktop UI
[mardrone] / mardrone / imports / com / nokia / meego / QueryDialog.qml
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the Qt Components project.
8 **
9 ** $QT_BEGIN_LICENSE:BSD$
10 ** You may use this file under the terms of the BSD license as follows:
11 **
12 ** "Redistribution and use in source and binary forms, with or without
13 ** modification, are permitted provided that the following conditions are
14 ** met:
15 **   * Redistributions of source code must retain the above copyright
16 **     notice, this list of conditions and the following disclaimer.
17 **   * Redistributions in binary form must reproduce the above copyright
18 **     notice, this list of conditions and the following disclaimer in
19 **     the documentation and/or other materials provided with the
20 **     distribution.
21 **   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
22 **     the names of its contributors may be used to endorse or promote
23 **     products derived from this software without specific prior written
24 **     permission.
25 **
26 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
29 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
30 ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
36 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
37 ** $QT_END_LICENSE$
38 **
39 ****************************************************************************/
40
41 import QtQuick 1.1
42 import "." 1.0
43 import "UIConstants.js" as UI
44
45 Dialog {
46     id: root
47     objectName: "queryDialog"
48
49     property string titleText
50     property string message
51
52     //are they necessary?
53     property alias acceptButtonText: acceptButton.text
54     property alias rejectButtonText: rejectButton.text
55
56     //ToDo
57     property alias icon: iconImage.source
58
59     property Style platformStyle: QueryDialogStyle {}
60
61     //__centerContentField: true
62
63     __dim: platformStyle.dim
64     __fadeInDuration:  platformStyle.fadeInDuration
65     __fadeOutDuration: platformStyle.fadeOutDuration
66     __fadeInDelay:     platformStyle.fadeInDelay
67     __fadeOutDelay:    platformStyle.fadeOutDelay
68
69     __animationChief: "queryDialog"
70
71     //Deprecated, TODO Remove this on w13
72     property alias style: root.platformStyle
73
74     // the title field consists of the following parts: title string and
75     // a close button (which is in fact an image)
76     // it can additionally have an icon
77     title: Item {
78         id: titleField
79         width: parent.width
80         height: titleText == "" ? titleBarIconField.height :
81                     titleBarIconField.height + titleLabel.height + root.platformStyle.titleColumnSpacing
82         Column {
83             id: titleFieldCol
84             spacing: root.platformStyle.titleColumnSpacing
85
86             anchors.left:  parent.left
87             anchors.right:  parent.right
88             anchors.top:  parent.top
89
90             width: root.width
91
92             Item {
93                 id: titleBarIconField
94                 height: iconImage.height
95                 width: parent.width
96                 Image {
97                     id: iconImage
98                     anchors.horizontalCenter: titleBarIconField.horizontalCenter
99                     source: ""
100                 }
101
102             }
103
104
105             Item {
106                 id: titleBarTextField
107                 height: titleLabel.height
108                 width: parent.width
109
110                 Text {
111                     id: titleLabel
112                     width: parent.width
113
114                     horizontalAlignment: Text.AlignHCenter
115                     verticalAlignment:   Text.AlignVCenter
116
117                     font.family: root.platformStyle.titleFontFamily
118                     font.pixelSize: root.platformStyle.titleFontPixelSize
119                     font.bold:  root.platformStyle.titleFontBold
120                     font.capitalization: root.platformStyle.titleFontCapitalization
121                     elide: root.platformStyle.titleElideMode
122                     wrapMode: elide == Text.ElideNone ? Text.Wrap : Text.NoWrap
123                     color: root.platformStyle.titleTextColor
124                     text: root.titleText
125
126                 }
127             }
128
129             // needed for animation
130             transform: Scale {
131                 id: titleScale
132                 xScale: 1.0; yScale: 1.0
133                 origin.x: mapFromItem(queryContent, queryContent.width / 2, queryContent.height / 2).x
134                 origin.y: mapFromItem(queryContent, queryContent.width / 2, queryContent.height / 2).y
135             }
136
137         }
138     }
139
140     // the content field which contains the message text
141     content: Item {
142         id: queryContentWrapper
143
144         property int upperBound: visualParent ? visualParent.height - titleField.height - buttonColFiller.height - 64
145                                                 : root.parent.height - titleField.height - buttonColFiller.height - 64
146         property int __sizeHint: Math.min(Math.max(root.platformStyle.contentFieldMinSize, queryText.height), upperBound)
147
148         height: __sizeHint + root.platformStyle.contentTopMargin
149         width: root.width
150
151         Item {
152             id: queryContent
153             width: parent.width
154
155             y: root.platformStyle.contentTopMargin
156
157             Flickable {
158                 id: queryFlickable
159                 anchors.left: parent.left
160                 anchors.right: parent.right
161                 anchors.top: parent.top
162                 //anchors.bottom: parent.bottom
163                 height: queryContentWrapper.__sizeHint
164
165                 contentHeight: queryText.height
166                 flickableDirection: Flickable.VerticalFlick
167                 clip: true
168
169                 interactive:  queryText.height > queryContentWrapper.__sizeHint
170
171                 Text {
172                     id: queryText
173                     width: queryFlickable.width
174                     horizontalAlignment: Text.AlignHCenter
175                     font.family: root.platformStyle.messageFontFamily
176                     font.pixelSize: root.platformStyle.messageFontPixelSize
177                     color: root.platformStyle.messageTextColor
178                     wrapMode: Text.WordWrap
179                     text: root.message
180                 }
181
182             }
183
184
185             ScrollDecorator {
186                 id: scrollDecorator
187                 flickableItem: queryFlickable
188                 anchors.rightMargin: - UI.SCROLLDECORATOR_LONG_MARGIN - 10 //ToDo: Don't use a hard-coded gap
189             }
190
191         }
192     }
193
194
195     buttons: Item {
196         id: buttonColFiller
197         width: parent.width
198         height: childrenRect.height
199
200         anchors.top: parent.top
201
202         //ugly hack to assure, that we're always evaluating the correct height
203         //otherwise the topMargin wouldn't be considered
204         Item {id: dummy; anchors.fill:  parent}
205
206         Column {
207             id: buttonCol
208             anchors.top: parent.top
209             anchors.topMargin: root.platformStyle.buttonTopMargin
210             spacing: root.platformStyle.buttonsColumnSpacing
211
212             height: (acceptButton.text  == "" ? 0 : acceptButton.height)
213                     + (rejectButton.text == "" ? 0 : rejectButton.height)
214                     + anchors.buttonTopMargin  + spacing
215
216             anchors.horizontalCenter: parent.horizontalCenter
217
218             Button {
219                 id: acceptButton
220                 text: ""
221                 onClicked: accept()
222                 visible: text != ""
223                 __dialogButton: true
224                 platformStyle: ButtonStyle {inverted: true}
225             }
226             Button {
227                 id: rejectButton
228                 text: ""
229                 onClicked: reject()
230                 visible: text != ""
231                 __dialogButton: true
232                 platformStyle: ButtonStyle {inverted: true}
233             }
234         }
235     }
236
237     StateGroup {
238         id: statesWrapper
239
240         state: "__query__hidden"
241
242         // needed for button animation
243         // without resetting the button row's coordinate system would be translated
244         property int __buttonSaver: buttonColFiller.y
245
246         states: [
247             State {
248                 name: "__query__visible"
249                 when: root.__animationChief == "queryDialog" && (root.status == DialogStatus.Opening || root.status == DialogStatus.Open)
250                 PropertyChanges {
251                     target: root
252                     opacity: 1.0
253                 }
254             },
255             State {
256                 name: "__query__hidden"
257                 when: root.__animationChief == "queryDialog" && (root.status == DialogStatus.Closing || root.status == DialogStatus.Closed)
258                 PropertyChanges {
259                     target: root
260                     opacity: 0.0
261                 }
262             }
263         ]
264
265         transitions: [
266             Transition {
267                 from: "__query__visible"; to: "__query__hidden"
268                 SequentialAnimation {
269                     ScriptAction {script: {
270                             __fader().state = "hidden";
271
272                             statesWrapper.__buttonSaver = buttonColFiller.y
273                             root.status = DialogStatus.Closing;
274
275                         }
276                     }
277
278                     NumberAnimation { target: root; properties: "opacity"; from: 0.0; to: 1.0; duration: 0 }
279
280                     // With a 100ms delay the background
281                     // fades to alpha 0% (500ms, quint ease out).
282                     // ---> done in the fader
283
284                     ParallelAnimation {
285                         // The closing transition starts with the message dimming to alpha 0% and
286                         // scaling to 80% (anchorpoint in the middle of the message, 100ms, quint
287                         // ease in).
288
289                         // With no delay the buttons fade to alpha 0% and translate 30
290                         // pixels upwards (100ms, quint ease in).
291                         NumberAnimation {target: queryContent; properties: "opacity"; from: 1.0; to: 0.0; duration: 100}
292                         NumberAnimation {target: titleField; properties: "opacity"; from: 1.0; to: 0.0; duration: 100}
293                         NumberAnimation {target: titleScale; properties: "xScale,yScale"; from: 1.0 ; to: 0.8; duration: 100; easing.type: Easing.InQuint}
294                         NumberAnimation {target: queryContent; property: "scale"; from: 1.0 ; to: 0.8; duration: 100; easing.type: Easing.InQuint}
295                         NumberAnimation {target: buttonColFiller; properties: "opacity"; from: 1.0; to: 0.0; duration: 100}
296                         NumberAnimation {target: buttonColFiller
297                             properties: "y"
298                             from: buttonColFiller.y
299                             to: buttonColFiller.y-30
300                             duration: 100
301                             easing.type: Easing.InQuint
302                         }
303                     }
304
305                     ScriptAction {script: {
306
307                             // reset button
308                             buttonColFiller.y = statesWrapper.__buttonSaver
309
310                             // make sure, root isn't visible:
311                             root.opacity = 0.0;
312                             status = DialogStatus.Closed;
313
314                         }
315                     }
316
317                 }
318             },
319             Transition {
320                 from: "__query__hidden"; to: "__query__visible"
321                 SequentialAnimation {
322                     ScriptAction {script: {
323                             __fader().state = "visible";
324
325                             statesWrapper.__buttonSaver = buttonColFiller.y
326
327                             root.status = DialogStatus.Opening;
328                             // UPPERCASE-UGLY, but necessary to avoid flicker
329                             root.opacity = 1.0
330                             titleField.opacity = 0.0
331                             queryContent.opacity = 0.0
332                             buttonColFiller.opacity = 0.0
333                         }
334                     }
335
336                     // The opening transition starts by dimming the background to 90% (250ms,
337                     // quint ease in).
338                     // ---> done in the fader
339                     ParallelAnimation {
340                         SequentialAnimation {
341
342                             // With a 200ms delay from the beginning the message fades
343                             // from alpha 0% to 100% and scales from 80% to 100% (anchorpoint in the
344                             // middle of the message, 550ms, custom ease).
345                             PauseAnimation { duration: 200 }
346                             ParallelAnimation {
347                                 NumberAnimation {target: queryContent; properties: "opacity"; from: 0.0; to: 1.0; duration: 550}
348                                 NumberAnimation {target: titleField; properties: "opacity"; from: 0.0; to: 1.0; duration: 550}
349                                 NumberAnimation {target: titleScale; properties: "xScale,yScale"; from: 0.8 ; to: 1.0; duration: 550; easing.type: Easing.OutBack}
350                                 NumberAnimation {target: queryContent; property: "scale"; from: 0.8 ; to: 1.0; duration: 550; easing.type: Easing.OutBack}
351                             }
352                         }
353                         SequentialAnimation {
354                             // With a 250ms delay from the
355                             // beginning the buttons fade from alpha 0% to 100% and translate 25 pixels
356                             // in Y axis away from their final destination (400ms, custom ease).
357                             PauseAnimation { duration: 250 }
358                             ParallelAnimation {
359                                 NumberAnimation {target: buttonColFiller; properties: "opacity"; from: 0.0; to: 1.0; duration: 400; }
360                                 NumberAnimation {target: buttonColFiller
361                                     properties: "y"
362                                     from: buttonColFiller.y-25
363                                     to: buttonColFiller.y
364                                     duration: 400
365                                     easing.type: Easing.OutBack
366                                 }
367                             }
368                         }
369                     }
370
371                     ScriptAction {script: {
372
373                             // reset button
374                             buttonColFiller.y = statesWrapper.__buttonSaver
375
376                             root.status = DialogStatus.Open;
377                         }
378                     }
379                 }
380             }
381         ]
382     }
383
384 }