improved desktop UI
[mardrone] / mardrone / imports / com / nokia / meego / NotificationBanner.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 com.nokia.meego 1.0
44
45 /*
46    Class: InfoBanner
47    The InfoBanner component is used to display information to the user. The number of lines of text
48    shouldn't exceed 3.
49 */
50
51 Item {
52     id: root
53
54     /*
55      * Property: iconSource
56      * [url] The path to the icon image
57      */
58     property url iconSource: ""
59
60     /*
61      * Property: text
62      * [string] Text to be displayed in InfoBanner
63      */
64     property alias text: text.text
65
66     /*
67      * Property: timerEnabled
68      * [bool=true] Enable/disable timer that dismisses InfoBanner
69      */
70     property bool timerEnabled: true
71
72     /*
73      * Property: timerShowTime
74      * [int=3000ms] For setting how long InfoBanner stays visible to user before being dismissed
75      */
76     property alias timerShowTime: sysBannerTimer.interval
77
78     /*
79      * Property: topMargin
80      * [int=8 pix] Allows user to customize top margin if needed
81      */
82     property alias topMargin: root.y
83
84     /*
85      * Property: leftMargin
86      * [int=8 pix] Allows user to customize left margin if needed
87      */
88     property alias leftMargin: root.x
89
90     /*
91      * Function: show
92      * Show InfoBanner
93      */
94     function show() {
95         parent = __findParent();
96         animationShow.running = true;
97         if (root.timerEnabled)
98             sysBannerTimer.restart();
99     }
100
101     function __findParent() {
102         var next = parent;
103         while (next && next.parent && next.objectName != "appWindowContent") {
104             next = next.parent;
105         }
106         return next;
107     }
108
109     /*
110      * Function: hide
111      * Hide InfoBanner
112      */
113     function hide() {
114         animationHide.running = true;
115     }
116
117     implicitHeight: internal.getBannerHeight()
118     implicitWidth: internal.getBannerWidth()
119     x:8; y:8
120     scale: 0
121
122     BorderImage {
123         source: "image://theme/meegotouch-notification-system-background"
124         anchors.fill: root
125         horizontalTileMode: BorderImage.Stretch
126         verticalTileMode: BorderImage.Stretch
127         border { left: 10; top: 10; right: 10; bottom: 10 }
128         opacity: 1
129     }
130
131     Image {
132         id: image
133         anchors { left: parent.left; leftMargin: 16; top: parent.top; topMargin: 16 }
134         source: root.iconSource
135         visible: root.iconSource != ""
136     }
137
138     Text {
139         id: text
140         width: internal.getTextWidth()
141         anchors { left: (image.visible ? image.right : parent.left); leftMargin: (image.visible ? 14:16);
142             top: parent.top; topMargin: internal.getTopMargin(); bottom: parent.bottom }
143         color: "white"
144         wrapMode: Text.Wrap
145         verticalAlignment: Text.AlignHCenter
146         font.pixelSize: 24
147         font.family: "Nokia Pure"
148         font.letterSpacing: -1.2
149         maximumLineCount: 3
150         elide: Text.ElideRight
151     }
152
153     QtObject {
154         id: internal
155
156         function getBannerHeight() {
157             if (image.visible) {
158                 if (text.lineCount <= 2)
159                     return 80; 
160                 else
161                     return 80; //106
162             } else {
163                 if (text.lineCount <= 1)
164                     return 80; //64
165                 else if (text.lineCount <= 2)
166                     return 80; 
167                 else
168                     return 80; //106
169             }
170         }
171
172         function getBannerWidth() {
173             if ( screen.currentOrientation==Screen.Portrait || screen.currentOrientation==Screen.PortraitInverted ) {
174                 // In portrait mode, the width of the banner is equal to the width of parent minus left
175                 // and right margins in-between banner and parent.
176                 return parent.width-root.x*2;
177             } else {
178                 if (image.visible) {
179                     // If an icon image is specified...
180                     if ((image.width+text.paintedWidth+46) <= parent.width*0.54 && text.lineCount <= 1) {
181                         // 46 is the sum of all horizontal margins within the banner. The above condition basically
182                         // says that if there's only one line of text, and the sum of width of icon, text, and required
183                         // margins is less then 54% of the screen width, banner width should be 54% of the screen.
184                         return parent.width*0.54;
185                     } else {
186                         return parent.width-root.x*2;
187                     }
188                 } else {
189                     // If no icon image specified...
190                     if ((text.paintedWidth+32) <= parent.width*0.54 && text.lineCount <= 1) {
191                         // 32 is the sum of all horizontal margins within the banner. The above condition basically
192                         // says that if there's only one line of text, and the sum of width of text and required
193                         // margins is less then 54% of the screen width, banner width should be 54% of the screen.
194                         return parent.width-root.x*2;
195                     } else {
196                         return parent.width-root.x*2;
197                     }
198                 }
199             }
200         }
201
202         function getTopMargin() {
203             if (text.lineCount <= 1 && !image.visible) {
204                 // If there's only one line of text and no icon image, top and bottom margins are equal.
205                 return (root.height-text.paintedHeight)/2;
206             } else {
207                 // In all other cases, top margin is 4 px more than bottom margin.
208                 return (root.height-text.paintedHeight)/2 + 2;
209             }
210         }
211
212         function getTextWidth() {
213             // 46(32 when there's no icon) is sum of all margins within banner. root.x*2 is sum of margins outside banner.
214             // Text element width is dertermined by substracting parent width(screen width) by all the margins and
215             // icon width(if applicable).
216             return image.visible ? (parent.width-root.x*2-46-image.width) : (parent.width-root.x*2-32);
217         }
218
219         function getScaleValue() {
220             // When banner is displayed, as part of transition effect, it'll first be enlarged to the point where its width
221             // is equal to screen width. root.x*2/root.width calculates the amount of expanding required, where root.x*2 is
222             // equal to screen.displayWidth minus banner.width
223             return root.x*2/root.width + 1;
224         }
225     }
226
227     Timer {
228         id: sysBannerTimer
229         repeat: false
230         running: false
231         interval: 3000
232         onTriggered: hide()
233     }
234
235     MouseArea {
236         anchors.fill: parent
237         onClicked: hide()
238     }
239
240     SequentialAnimation {
241         id: animationShow
242         NumberAnimation { target: root; property: "scale"; from: 0; to: internal.getScaleValue(); duration: 200; easing.type: Easing.OutQuad}
243         NumberAnimation { target: root; property: "scale"; from: internal.getScaleValue(); to: 1; duration: 200 }
244     }
245
246     NumberAnimation {
247         id: animationHide
248         target: root; property: "scale"; to: 0; duration: 200; easing.type: Easing.InExpo
249     }
250
251     Component.onCompleted: {
252         //__owner = parent;
253     }
254 }
255