1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the Qt Graphical Effects module.
7**
8** $QT_BEGIN_LICENSE:BSD$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** BSD License Usage
18** Alternatively, you may use this file under the terms of the BSD license
19** as follows:
20**
21** "Redistribution and use in source and binary forms, with or without
22** modification, are permitted provided that the following conditions are
23** met:
24**   * Redistributions of source code must retain the above copyright
25**     notice, this list of conditions and the following disclaimer.
26**   * Redistributions in binary form must reproduce the above copyright
27**     notice, this list of conditions and the following disclaimer in
28**     the documentation and/or other materials provided with the
29**     distribution.
30**   * Neither the name of The Qt Company Ltd nor the names of its
31**     contributors may be used to endorse or promote products derived
32**     from this software without specific prior written permission.
33**
34**
35** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
36** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
38** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
39** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
42** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
43** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
44** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
45** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
46**
47** $QT_END_LICENSE$
48**
49****************************************************************************/
50
51import QtQuick 2.0
52import "private"
53
54/*!
55    \qmltype DropShadow
56    \inqmlmodule QtGraphicalEffects 1.0
57    \since QtGraphicalEffects 1.0
58    \inherits QtQuick2::Item
59    \ingroup qtgraphicaleffects-drop-shadow
60    \brief Generates a colorized and blurred shadow image of the
61    source and places it behind the original, giving the impression that
62    source item is raised from the background.
63
64    By default the effect produces a high quality shadow image, thus the
65    rendering speed of the shadow might not be the highest possible. The
66    rendering speed is reduced especially if the shadow edges are heavily
67    softened.
68
69    For use cases that require faster rendering speed and for which the highest
70    possible visual quality is not necessary, property
71    \l{DropShadow::fast}{fast} can be set to true.
72
73    \table
74    \header
75        \li Source
76        \li Effect applied
77    \row
78        \li \image Original_butterfly.png
79        \li \image DropShadow_butterfly.png
80    \endtable
81
82    \section1 Example
83
84    The following example shows how to apply the effect.
85    \snippet DropShadow-example.qml example
86
87*/
88Item {
89    id: rootItem
90
91    /*!
92        This property defines the source item that is going to be used as the
93        source for the generated shadow.
94
95        \note It is not supported to let the effect include itself, for
96        instance by setting source to the effect's parent.
97    */
98    property variant source
99
100    /*!
101        Radius defines the softness of the shadow. A larger radius causes the
102        edges of the shadow to appear more blurry.
103
104        Depending on the radius value, value of the
105        \l{DropShadow::samples}{samples} should be set to sufficiently large to
106        ensure the visual quality.
107
108        The value ranges from 0.0 (no blur) to inf. By default, the property is
109        set to \c 0.0 (no blur).
110
111        \table
112        \header
113        \li Output examples with different radius values
114        \li
115        \li
116        \row
117            \li \image DropShadow_radius1.png
118            \li \image DropShadow_radius2.png
119            \li \image DropShadow_radius3.png
120        \row
121            \li \b { radius: 0 }
122            \li \b { radius: 6 }
123            \li \b { radius: 12 }
124        \row
125            \li \l samples: 24
126            \li \l samples: 24
127            \li \l samples: 24
128        \row
129            \li \l color: #000000
130            \li \l color: #000000
131            \li \l color: #000000
132        \row
133            \li \l horizontalOffset: 0
134            \li \l horizontalOffset: 0
135            \li \l horizontalOffset: 0
136        \row
137            \li \l verticalOffset: 20
138            \li \l verticalOffset: 20
139            \li \l verticalOffset: 20
140        \row
141            \li \l spread: 0
142            \li \l spread: 0
143            \li \l spread: 0
144        \endtable
145
146    */
147    property real radius: 0.0
148
149    /*!
150        This property defines how many samples are taken per pixel when edge
151        softening blur calculation is done. Larger value produces better
152        quality, but is slower to render.
153
154        Ideally, this value should be twice as large as the highest required
155        radius value, for example, if the radius is animated between 0.0 and
156        4.0, samples should be set to 8.
157
158        The value ranges from 0 to 32. By default, the property is set to \c 0.
159
160        This property is not intended to be animated. Changing this property may
161        cause the underlying OpenGL shaders to be recompiled.
162
163        When \l{DropShadow::fast}{fast} property is set to true, this property
164        has no effect.
165
166    */
167    property int samples: 0
168
169    /*!
170        This property defines the RGBA color value which is used for the shadow.
171
172        By default, the property is set to \c "black".
173
174        \table
175        \header
176        \li Output examples with different color values
177        \li
178        \li
179        \row
180            \li \image DropShadow_color1.png
181            \li \image DropShadow_color2.png
182            \li \image DropShadow_color3.png
183        \row
184            \li \b { color: #000000 }
185            \li \b { color: #0000ff }
186            \li \b { color: #aa000000 }
187        \row
188            \li \l radius: 8
189            \li \l radius: 8
190            \li \l radius: 8
191        \row
192            \li \l samples: 16
193            \li \l samples: 16
194            \li \l samples: 16
195        \row
196            \li \l horizontalOffset: 0
197            \li \l horizontalOffset: 0
198            \li \l horizontalOffset: 0
199        \row
200            \li \l verticalOffset: 20
201            \li \l verticalOffset: 20
202            \li \l verticalOffset: 20
203        \row
204            \li \l spread: 0
205            \li \l spread: 0
206            \li \l spread: 0
207        \endtable
208
209    */
210    property color color: "black"
211
212    /*!
213        \qmlproperty real QtGraphicalEffects1::DropShadow::horizontalOffset
214        \qmlproperty real QtGraphicalEffects1::DropShadow::verticalOffset
215
216        HorizontalOffset and verticalOffset properties define the offset for the
217        rendered shadow compared to the DropShadow item position. Often, the
218        DropShadow item is anchored so that it fills the source element. In this
219        case, if the HorizontalOffset and verticalOffset properties are set to
220        0, the shadow is rendered exactly under the source item. By changing the
221        offset properties, the shadow can be positioned relatively to the source
222        item.
223
224        The values range from -inf to inf. By default, the properties are set to
225        \c 0.
226
227        \table
228        \header
229        \li Output examples with different horizontalOffset values
230        \li
231        \li
232        \row
233            \li \image DropShadow_horizontalOffset1.png
234            \li \image DropShadow_horizontalOffset2.png
235            \li \image DropShadow_horizontalOffset3.png
236        \row
237            \li \b { horizontalOffset: -20 }
238            \li \b { horizontalOffset: 0 }
239            \li \b { horizontalOffset: 20 }
240        \row
241            \li \l radius: 4
242            \li \l radius: 4
243            \li \l radius: 4
244        \row
245            \li \l samples: 8
246            \li \l samples: 8
247            \li \l samples: 8
248        \row
249            \li \l color: #000000
250            \li \l color: #000000
251            \li \l color: #000000
252        \row
253            \li \l verticalOffset: 0
254            \li \l verticalOffset: 0
255            \li \l verticalOffset: 0
256        \row
257            \li \l spread: 0
258            \li \l spread: 0
259            \li \l spread: 0
260        \endtable
261
262    */
263    property real horizontalOffset: 0.0
264    property real verticalOffset: 0.0
265
266    /*!
267        This property defines how large part of the shadow color is strenghtened
268        near the source edges.
269
270        The value ranges from 0.0 to 1.0. By default, the property is set to \c
271        0.5.
272
273        \table
274        \header
275        \li Output examples with different spread values
276        \li
277        \li
278        \row
279            \li \image DropShadow_spread1.png
280            \li \image DropShadow_spread2.png
281            \li \image DropShadow_spread3.png
282        \row
283            \li \b { spread: 0.0 }
284            \li \b { spread: 0.5 }
285            \li \b { spread: 1.0 }
286        \row
287            \li \l radius: 8
288            \li \l radius: 8
289            \li \l radius: 8
290        \row
291            \li \l samples: 16
292            \li \l samples: 16
293            \li \l samples: 16
294        \row
295            \li \l color: #000000
296            \li \l color: #000000
297            \li \l color: #000000
298        \row
299            \li \l horizontalOffset: 0
300            \li \l horizontalOffset: 0
301            \li \l horizontalOffset: 0
302        \row
303            \li \l verticalOffset: 20
304            \li \l verticalOffset: 20
305            \li \l verticalOffset: 20
306        \endtable
307
308    */
309    property real spread: 0.0
310
311    /*!
312        This property selects the blurring algorithm that is used to produce the
313        softness for the effect. Setting this to true enables fast algorithm,
314        setting value to false produces higher quality result.
315
316        By default, the property is set to \c false.
317
318        \table
319        \header
320        \li Output examples with different fast values
321        \li
322        \li
323        \row
324            \li \image DropShadow_fast1.png
325            \li \image DropShadow_fast2.png
326        \row
327            \li \b { fast: false }
328            \li \b { fast: true }
329        \row
330            \li \l radius: 16
331            \li \l radius: 16
332        \row
333            \li \l samples: 24
334            \li \l samples: 24
335        \row
336            \li \l color: #000000
337            \li \l color: #000000
338        \row
339            \li \l horizontalOffset: 0
340            \li \l horizontalOffset: 0
341        \row
342            \li \l verticalOffset: 20
343            \li \l verticalOffset: 20
344        \row
345            \li \l spread: 0
346            \li \l spread: 0
347        \endtable
348
349    */
350    property bool fast: false
351
352    /*!
353        This property allows the effect output pixels to be cached in order to
354        improve the rendering performance. Every time the source or effect
355        properties are changed, the pixels in the cache must be updated. Memory
356        consumption is increased, because an extra buffer of memory is required
357        for storing the effect output.
358
359        It is recommended to disable the cache when the source or the effect
360        properties are animated.
361
362        By default, the property is set to \c false.
363
364    */
365    property bool cached: false
366
367    property bool transparentBorder: false
368
369    Loader {
370        x: rootItem.horizontalOffset
371        y: rootItem.verticalOffset
372        width: parent.width
373        height: parent.height
374        sourceComponent: rootItem.fast ? fastGlow : gaussianGlow
375    }
376
377    Component {
378        id: gaussianGlow
379        GaussianGlow {
380            anchors.fill: parent
381            source: sourceProxy.output
382            radius: rootItem.radius
383            maximumRadius: rootItem.samples * 0.5
384            color: rootItem.color
385            cached: rootItem.cached
386            spread: rootItem.spread
387            transparentBorder: rootItem.transparentBorder
388        }
389    }
390
391    Component {
392        id: fastGlow
393        FastGlow {
394            anchors.fill: parent
395            source: sourceProxy.output
396            blur: Math.pow(rootItem.radius / 64.0, 0.4)
397            color: rootItem.color
398            cached: rootItem.cached
399            spread: rootItem.spread
400            transparentBorder: rootItem.transparentBorder
401        }
402    }
403
404    SourceProxy {
405        id: sourceProxy
406        input: rootItem.source
407        sourceRect: rootItem.transparentBorder ? Qt.rect(-1, -1, parent.width + 2.0, parent.height + 2.0) : Qt.rect(0, 0, 0, 0)
408    }
409    ShaderEffect {
410        anchors.fill: parent
411        property variant source: sourceProxy.output
412    }
413}
414