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 tools applications of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
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 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #include "qtgradientdialog.h"
41 #include "ui_qtgradientdialog.h"
42 #include <QtWidgets/QPushButton>
43 
44 QT_BEGIN_NAMESPACE
45 
46 class QtGradientDialogPrivate
47 {
48     QtGradientDialog *q_ptr;
49     Q_DECLARE_PUBLIC(QtGradientDialog)
50 public:
51 
52     void slotAboutToShowDetails(bool details, int extensionWidthHint);
53 
54     Ui::QtGradientDialog m_ui;
55 };
56 
slotAboutToShowDetails(bool details,int extensionWidthHint)57 void QtGradientDialogPrivate::slotAboutToShowDetails(bool details, int extensionWidthHint)
58 {
59     if (details) {
60         q_ptr->resize(q_ptr->size() + QSize(extensionWidthHint, 0));
61     } else {
62         q_ptr->setMinimumSize(1, 1);
63         q_ptr->resize(q_ptr->size() - QSize(extensionWidthHint, 0));
64         q_ptr->setMinimumSize(0, 0);
65     }
66 }
67 
68 /*!
69     \class QtGradientDialog
70 
71     \brief The QtGradientDialog class provides a dialog for specifying gradients.
72 
73     The gradient dialog's function is to allow users to edit gradients.
74     For example, you might use this in a drawing program to allow the user to set the brush gradient.
75 
76     \table
77     \row
78     \li \inlineimage qtgradientdialog.png
79     \li \inlineimage qtgradientdialogextension.png
80     \header
81     \li Details extension hidden
82     \li Details extension visible
83     \endtable
84 
85     Starting from the top of the dialog there are several buttons:
86 
87     \image qtgradientdialogtopbuttons.png
88 
89     The first three buttons allow for changing a type of the gradient (QGradient::Type), while the second three allow for
90     changing spread of the gradient (QGradient::Spread). The last button shows or hides the details extension of the dialog.
91     Conceptually the default view with hidden details provides the full functional control over gradient editing.
92     The additional extension with details allows to set gradient's parameters more precisely. The visibility
93     of extension can be controlled by detailsVisible property. Moreover, if you don't want the user to
94     switch on or off the visibility of extension you can set the detailsButtonVisible property to false.
95 
96     Below top buttons there is an area where edited gradient is interactively previewed.
97     In addition the user can edit gradient type's specific parameters directly in this area by dragging
98     appropriate handles.
99 
100     \table
101     \row
102     \li \inlineimage qtgradientdialoglineareditor.png
103     \li \inlineimage qtgradientdialogradialeditor.png
104     \li \inlineimage qtgradientdialogconicaleditor.png
105     \header
106     \li Editing linear type
107     \li Editing radial type
108     \li Editing conical type
109     \row
110     \li The user can change the start and final point positions by dragging the circular handles.
111     \li The user can change the center and focal point positions by dragging the circular handles
112         and can change the gradient's radius by dragging horizontal or vertical line.
113     \li The user can change the center point by dragging the circular handle
114         and can change the gradient's angle by dragging the big wheel.
115     \endtable
116 
117     In the middle of the dialog there is an area where the user can edit gradient stops.
118 
119     \table
120     \row
121     \li \inlineimage qtgradientdialogstops.png
122     \li \inlineimage qtgradientdialogstopszoomed.png
123     \endtable
124 
125     The top part of this area contains stop handles, and bottom part shows the preview of gradient stops path.
126     In order to create a new gradient stop double click inside the view over the desired position.
127     If you double click on existing stop handle in the top part of the view, clicked handle will be duplicated
128     (duplicate will contain the same color).
129     The stop can be activated by clicking on its handle. You can activate previous or next stop by pressing
130     left or right key respectively. To jump to the first or last stop press home or end key respectively.
131     The gradient stops editor supports multiselection.
132     Clicking a handle holding the shift modifier key down will select a range of stops between
133     the active stop and clicked one. Clicking a handle holding control modifier key down will remove from or
134     add to selection the clicked stop depending if it was or wasn't already selected respectively.
135     Multiselection can also be created using rubberband (by pressing the left mouse button outside
136     of any handle and dragging).
137     Sometimes it's hard to select a stop because its handle can be partially covered by other handle.
138     In that case the user can zoom in the view by spinning mouse wheel.
139     The selected stop handles can be moved by drag & drop. In order to remove selected stops press delete key.
140     For convenience context menu is provided with the following actions:
141 
142     \list
143     \li New Stop - creates a new gradient stop
144     \li Delete - removes the active and all selected stops
145     \li Flip All - mirrors all stops
146     \li Select All - selects all stops
147     \li Zoom In - zooms in
148     \li Zoom Out - zooms out
149     \li Zoom All - goes back to original 100% zoom
150     \endlist
151 
152     The bottom part of the QtGradientDialog contains a set of widgets allowing to control the color of
153     the active and selected stops.
154 
155     \table
156     \row
157     \li \inlineimage qtgradientdialogcolorhsv.png
158     \li \inlineimage qtgradientdialogcolorrgb.png
159     \endtable
160 
161 
162     The color button shows the color of the active gradient stop. It also allows for choosing
163     a color from standard color dialog and applying it to the
164     active stop and all selected stops. It's also possible to drag a color directly from the color button
165     and to drop it in gradient stops editor at desired position (it will create new stop with dragged color)
166     or at desired stop handle (it will change the color of that handle).
167 
168     To the right of color button there is a set of 2 radio buttons which allows to switch between
169     HVS and RGB color spec.
170 
171     Finally there are 4 color sliders working either in HSVA (hue saturation value alpha) or
172     RGBA (red green blue alpha) mode, depending on which radio button is chosen. The radio buttons
173     can be controlled programatically by spec() and setSpec() methods. The sliders show the
174     color of the active stop. By double clicking inside color slider you can set directly the desired color.
175     Changes of slider's are applied to stop selection in the way that the color
176     component being changed is applied to stops in selection only, while other components
177     remain unchanged in selected stops (e.g. when the user is changing the saturation,
178     new saturation is applied to selected stops preventing original hue, value and alpha in multiselection).
179 
180     The convenient static functions getGradient() provide modal gradient dialogs, e.g.:
181 
182     \snippet doc/src/snippets/code/tools_shared_qtgradienteditor_qtgradientdialog.cpp 0
183 
184     In order to have more control over the properties of QtGradientDialog use
185     standard QDialog::exec() method:
186 
187     \snippet doc/src/snippets/code/tools_shared_qtgradienteditor_qtgradientdialog.cpp 1
188 
189     \sa {Gradient View Example}
190 */
191 
192 /*!
193     Constructs a gradient dialog with \a parent as parent widget.
194 */
195 
QtGradientDialog(QWidget * parent)196 QtGradientDialog::QtGradientDialog(QWidget *parent)
197     : QDialog(parent), d_ptr(new QtGradientDialogPrivate())
198 {
199 //    setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
200     d_ptr->q_ptr = this;
201     d_ptr->m_ui.setupUi(this);
202     QPushButton *button = d_ptr->m_ui.buttonBox->button(QDialogButtonBox::Ok);
203     if (button)
204         button->setAutoDefault(false);
205     button = d_ptr->m_ui.buttonBox->button(QDialogButtonBox::Cancel);
206     if (button)
207         button->setAutoDefault(false);
208     connect(d_ptr->m_ui.gradientEditor, SIGNAL(aboutToShowDetails(bool,int)),
209                 this, SLOT(slotAboutToShowDetails(bool,int)));
210 }
211 
212 /*!
213     Destroys the gradient dialog
214 */
215 
~QtGradientDialog()216 QtGradientDialog::~QtGradientDialog()
217 {
218 }
219 
220 /*!
221     \property QtGradientDialog::gradient
222     \brief the gradient of the dialog
223 */
setGradient(const QGradient & gradient)224 void QtGradientDialog::setGradient(const QGradient &gradient)
225 {
226     d_ptr->m_ui.gradientEditor->setGradient(gradient);
227 }
228 
gradient() const229 QGradient QtGradientDialog::gradient() const
230 {
231     return d_ptr->m_ui.gradientEditor->gradient();
232 }
233 
234 /*!
235     \property QtGradientDialog::backgroundCheckered
236     \brief whether the background of widgets able to show the colors with alpha channel is checkered.
237 
238     \table
239     \row
240     \li \inlineimage qtgradientdialogbackgroundcheckered.png
241     \li \inlineimage qtgradientdialogbackgroundtransparent.png
242     \row
243     \li \snippet doc/src/snippets/code/tools_shared_qtgradienteditor_qtgradientdialog.cpp 2
244     \li \snippet doc/src/snippets/code/tools_shared_qtgradienteditor_qtgradientdialog.cpp 3
245     \endtable
246 
247     When this property is set to true (the default) widgets inside gradient dialog like color button,
248     color sliders, gradient stops editor and gradient editor will show checkered background
249     in case of transparent colors. Otherwise the background of these widgets is transparent.
250 */
251 
isBackgroundCheckered() const252 bool QtGradientDialog::isBackgroundCheckered() const
253 {
254     return d_ptr->m_ui.gradientEditor->isBackgroundCheckered();
255 }
256 
setBackgroundCheckered(bool checkered)257 void QtGradientDialog::setBackgroundCheckered(bool checkered)
258 {
259     d_ptr->m_ui.gradientEditor->setBackgroundCheckered(checkered);
260 }
261 
262 /*!
263     \property QtGradientDialog::detailsVisible
264     \brief whether details extension is visible.
265 
266     When this property is set to true the details extension is visible. By default
267     this property is set to false and the details extension is hidden.
268 
269     \sa detailsButtonVisible
270 */
detailsVisible() const271 bool QtGradientDialog::detailsVisible() const
272 {
273     return d_ptr->m_ui.gradientEditor->detailsVisible();
274 }
275 
setDetailsVisible(bool visible)276 void QtGradientDialog::setDetailsVisible(bool visible)
277 {
278     d_ptr->m_ui.gradientEditor->setDetailsVisible(visible);
279 }
280 
281 /*!
282     \property QtGradientDialog::detailsButtonVisible
283     \brief whether the details button allowing for showing and hiding details extension is visible.
284 
285     When this property is set to true (the default) the details button is visible and the user
286     can show and hide details extension interactively. Otherwise the button is hidden and the details
287     extension is always visible or hidded depending on the value of detailsVisible property.
288 
289     \sa detailsVisible
290 */
isDetailsButtonVisible() const291 bool QtGradientDialog::isDetailsButtonVisible() const
292 {
293     return d_ptr->m_ui.gradientEditor->isDetailsButtonVisible();
294 }
295 
setDetailsButtonVisible(bool visible)296 void QtGradientDialog::setDetailsButtonVisible(bool visible)
297 {
298     d_ptr->m_ui.gradientEditor->setDetailsButtonVisible(visible);
299 }
300 
301 /*!
302     Returns the current QColor::Spec used for the color sliders in the dialog.
303 */
spec() const304 QColor::Spec QtGradientDialog::spec() const
305 {
306     return d_ptr->m_ui.gradientEditor->spec();
307 }
308 
309 /*!
310     Sets the current QColor::Spec to \a spec used for the color sliders in the dialog.
311 */
setSpec(QColor::Spec spec)312 void QtGradientDialog::setSpec(QColor::Spec spec)
313 {
314     d_ptr->m_ui.gradientEditor->setSpec(spec);
315 }
316 
317 /*!
318     Executes a modal gradient dialog, lets the user to specify a gradient, and returns that gradient.
319 
320     If the user clicks \gui OK, the gradient specified by the user is returned. If the user clicks \gui Cancel, the \a initial gradient is returned.
321 
322     The dialog is constructed with the given \a parent. \a caption is shown as the window title of the dialog and
323     \a initial is the initial gradient shown in the dialog. If the \a ok parameter is not-null,
324     the value it refers to is set to true if the user clicks \gui OK, and set to false if the user clicks \gui Cancel.
325 */
getGradient(bool * ok,const QGradient & initial,QWidget * parent,const QString & caption)326 QGradient QtGradientDialog::getGradient(bool *ok, const QGradient &initial, QWidget *parent, const QString &caption)
327 {
328     QtGradientDialog dlg(parent);
329     if (!caption.isEmpty())
330         dlg.setWindowTitle(caption);
331     dlg.setGradient(initial);
332     const int res = dlg.exec();
333     if (ok) {
334         *ok = (res == QDialog::Accepted) ? true : false;
335     }
336     if (res == QDialog::Accepted)
337         return dlg.gradient();
338     return initial;
339 }
340 
341 /*!
342     This method calls getGradient(ok, QLinearGradient(), parent, caption).
343 */
getGradient(bool * ok,QWidget * parent,const QString & caption)344 QGradient QtGradientDialog::getGradient(bool *ok, QWidget *parent, const QString &caption)
345 {
346     return getGradient(ok, QLinearGradient(), parent, caption);
347 }
348 
349 QT_END_NAMESPACE
350 
351 #include "moc_qtgradientdialog.cpp"
352