1 /*****************************************************************************
2  *   Copyright 2003 - 2010 Craig Drummond <craig.p.drummond@gmail.com>       *
3  *   Copyright 2013 - 2015 Yichao Yu <yyc1992@gmail.com>                     *
4  *                                                                           *
5  *   This program is free software; you can redistribute it and/or modify    *
6  *   it under the terms of the GNU Lesser General Public License as          *
7  *   published by the Free Software Foundation; either version 2.1 of the    *
8  *   License, or (at your option) version 3, or any later version accepted   *
9  *   by the membership of KDE e.V. (or its successor approved by the         *
10  *   membership of KDE e.V.), which shall act as a proxy defined in          *
11  *   Section 6 of version 3 of the license.                                  *
12  *                                                                           *
13  *   This program is distributed in the hope that it will be useful,         *
14  *   but WITHOUT ANY WARRANTY; without even the implied warranty of          *
15  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU       *
16  *   Lesser General Public License for more details.                         *
17  *                                                                           *
18  *   You should have received a copy of the GNU Lesser General Public        *
19  *   License along with this library. If not,                                *
20  *   see <http://www.gnu.org/licenses/>.                                     *
21  *****************************************************************************/
22 
23 #include <stdarg.h>
24 #include "common.h"
25 
26 void
qtcSetupGradient(Gradient * grad,EGradientBorder border,int numStops,...)27 qtcSetupGradient(Gradient *grad, EGradientBorder border, int numStops, ...)
28 {
29     va_list ap;
30     int i;
31 
32     grad->border = border;
33 #ifndef QTC_UTILS_QT
34     grad->numStops = numStops;
35     grad->stops = qtcNew(GradientStop, numStops);
36 #endif
37     va_start(ap, numStops);
38     for (i = 0;i < numStops;++i) {
39         double pos = va_arg(ap, double);
40         double val = va_arg(ap, double);
41 #ifdef QTC_UTILS_QT
42         grad->stops.insert(GradientStop(pos, val));
43 #else
44         grad->stops[i].pos = pos;
45         grad->stops[i].val = val;
46         grad->stops[i].alpha = 1.0;
47 #endif
48     }
49     va_end(ap);
50 }
51 
52 const Gradient*
qtcGetGradient(EAppearance app,const Options * opts)53 qtcGetGradient(EAppearance app, const Options *opts)
54 {
55     if (IS_CUSTOM(app)) {
56 #ifdef QTC_UTILS_QT
57         auto grad = opts->customGradient.find(app);
58 
59         if (grad != opts->customGradient.end()) {
60             return &grad->second;
61         }
62 #else
63         Gradient *grad = opts->customGradient[app - APPEARANCE_CUSTOM1];
64 
65         if (grad) {
66             return grad;
67         }
68 #endif
69         app = APPEARANCE_RAISED;
70     }
71 
72     static Gradient stdGradients[NUM_STD_APP];
73     static bool init = false;
74 
75     if (!init) {
76         qtcSetupGradient(&stdGradients[APPEARANCE_FLAT - APPEARANCE_FLAT],
77                          GB_3D, 2, 0.0, 1.0, 1.0, 1.0);
78         qtcSetupGradient(&stdGradients[APPEARANCE_RAISED - APPEARANCE_FLAT],
79                          GB_3D_FULL, 2, 0.0, 1.0, 1.0, 1.0);
80         qtcSetupGradient(&stdGradients[APPEARANCE_DULL_GLASS -
81                                        APPEARANCE_FLAT], GB_LIGHT, 4, 0.0,
82                          1.05, 0.499, 0.984, 0.5, 0.928,
83                          1.0, 1.0);
84         qtcSetupGradient(&stdGradients[APPEARANCE_SHINY_GLASS -
85                                        APPEARANCE_FLAT], GB_LIGHT, 4, 0.0,
86                          1.2, 0.499, 0.984, 0.5, 0.9,
87                          1.0, 1.06);
88         qtcSetupGradient(&stdGradients[APPEARANCE_AGUA - APPEARANCE_FLAT],
89                          GB_SHINE, 2, 0.0, 0.6, 1.0, 1.1);
90         qtcSetupGradient(&stdGradients[APPEARANCE_SOFT_GRADIENT -
91                                        APPEARANCE_FLAT], GB_3D, 2, 0.0,
92                          1.04, 1.0, 0.98);
93         qtcSetupGradient(
94             &stdGradients[APPEARANCE_GRADIENT - APPEARANCE_FLAT], GB_3D, 2,
95             0.0, 1.1, 1.0, 0.94);
96         qtcSetupGradient(&stdGradients[APPEARANCE_HARSH_GRADIENT -
97                                        APPEARANCE_FLAT], GB_3D, 2, 0.0, 1.3,
98                          1.0, 0.925);
99         qtcSetupGradient(
100             &stdGradients[APPEARANCE_INVERTED - APPEARANCE_FLAT], GB_3D, 2,
101             0.0, 0.93, 1.0, 1.04);
102         qtcSetupGradient(&stdGradients[APPEARANCE_DARK_INVERTED -
103                                        APPEARANCE_FLAT], GB_NONE, 3, 0.0,
104                          0.8, 0.7, 0.95, 1.0, 1.0);
105         qtcSetupGradient(&stdGradients[APPEARANCE_SPLIT_GRADIENT -
106                                        APPEARANCE_FLAT], GB_3D, 4, 0.0,
107                          1.06, 0.499, 1.004, 0.5, 0.986,
108                          1.0, 0.92);
109         qtcSetupGradient(
110             &stdGradients[APPEARANCE_BEVELLED - APPEARANCE_FLAT], GB_3D, 4,
111             0.0, 1.05, 0.1, 1.02, 0.9, 0.985, 1.0, 0.94);
112         qtcSetupGradient(&stdGradients[APPEARANCE_LV_BEVELLED -
113                                        APPEARANCE_FLAT], GB_3D, 3, 0.0,
114                          1.00, 0.85, 1.0, 1.0, 0.90);
115         qtcSetupGradient(
116             &stdGradients[APPEARANCE_AGUA_MOD - APPEARANCE_FLAT], GB_NONE,
117             3, 0.0, 1.5, 0.49, 0.85, 1.0, 1.3);
118         qtcSetupGradient(
119             &stdGradients[APPEARANCE_LV_AGUA - APPEARANCE_FLAT], GB_NONE, 4,
120             0.0, 0.98, 0.35, 0.95, 0.4, 0.93, 1.0, 1.15);
121         init = true;
122     }
123 
124     return &stdGradients[app - APPEARANCE_FLAT];
125 }
126 
127 EAppearance
128 #ifdef QTC_UTILS_QT
qtcWidgetApp(EWidget w,const Options * opts,bool active)129 qtcWidgetApp(EWidget w, const Options *opts, bool active)
130 #else
131 qtcWidgetApp(EWidget w, const Options *opts)
132 #endif
133 {
134     switch (w) {
135     case WIDGET_SB_BGND:
136         return opts->sbarBgndAppearance;
137     case WIDGET_LISTVIEW_HEADER:
138         return opts->lvAppearance;
139     case WIDGET_SB_BUTTON:
140     case WIDGET_SLIDER:
141     case WIDGET_SB_SLIDER:
142         return opts->sliderAppearance;
143     case WIDGET_FILLED_SLIDER_TROUGH:
144         return opts->sliderFill;
145     case WIDGET_TAB_TOP:
146     case WIDGET_TAB_BOT:
147         return opts->tabAppearance;
148     case WIDGET_MENU_ITEM:
149         return opts->menuitemAppearance;
150     case WIDGET_PROGRESSBAR:
151 #ifndef QTC_UTILS_QT
152     case WIDGET_ENTRY_PROGRESSBAR:
153 #endif
154         return opts->progressAppearance;
155     case WIDGET_PBAR_TROUGH:
156         return opts->progressGrooveAppearance;
157     case WIDGET_SELECTION:
158         return opts->selectionAppearance;
159 #ifdef QTC_UTILS_QT
160     case WIDGET_DOCK_WIDGET_TITLE:
161         return opts->dwtAppearance;
162     case WIDGET_MDI_WINDOW:
163     case WIDGET_MDI_WINDOW_TITLE:
164         return (active ? opts->titlebarAppearance :
165                 opts->inactiveTitlebarAppearance);
166     case WIDGET_MDI_WINDOW_BUTTON:
167         return opts->titlebarButtonAppearance;
168     case WIDGET_DIAL:
169         return qtcIsFlat(opts->appearance) ? APPEARANCE_RAISED :
170         APPEARANCE_SOFT_GRADIENT;
171 #endif
172     case WIDGET_TROUGH:
173     case WIDGET_SLIDER_TROUGH:
174         return opts->grooveAppearance;
175 #ifndef QTC_UTILS_QT
176     case WIDGET_SPIN_UP:
177     case WIDGET_SPIN_DOWN:
178 #endif
179     case WIDGET_SPIN:
180         return MODIFY_AGUA(opts->appearance);
181     case WIDGET_TOOLBAR_BUTTON:
182         return (APPEARANCE_NONE == opts->tbarBtnAppearance ?
183                 opts->appearance : opts->tbarBtnAppearance);
184     default:
185         break;
186     }
187     return opts->appearance;
188 }
189 
190 #define CAN_EXTRA_ROUND(MOD)                                            \
191     (QtCurve::isExtraRoundWidget(widget) &&                             \
192      (IS_SLIDER(widget) || WIDGET_TROUGH == widget ||                   \
193       (((w > (MIN_ROUND_EXTRA_SIZE(widget) + MOD)) ||                   \
194         (WIDGET_NO_ETCH_BTN == widget || WIDGET_MENU_BUTTON == widget)) && \
195        (h > (MIN_ROUND_EXTRA_SIZE(widget) + MOD)))))
196 #define CAN_FULL_ROUND(MOD)                                             \
197     (w > (MIN_ROUND_FULL_SIZE + MOD) && h > (MIN_ROUND_FULL_SIZE + MOD))
198 
199 // **NOTE** MUST KEEP IN SYNC WITH getRadius/RADIUS_ETCH !!!
200 ERound
qtcGetWidgetRound(const Options * opts,int w,int h,EWidget widget)201 qtcGetWidgetRound(const Options *opts, int w, int h, EWidget widget)
202 {
203     ERound r = opts->round;
204 
205     if ((QtCurve::oneOf(widget, WIDGET_PBAR_TROUGH, WIDGET_PROGRESSBAR) &&
206          (opts->square & SQUARE_PROGRESS)) ||
207         (widget == WIDGET_ENTRY && (opts->square & SQUARE_ENTRY)) ||
208         (widget == WIDGET_SCROLLVIEW && (opts->square & SQUARE_SCROLLVIEW))) {
209         return ROUND_NONE;
210     }
211 
212     if (QtCurve::oneOf(widget, WIDGET_CHECKBOX, WIDGET_FOCUS) &&
213         r != ROUND_NONE) {
214         r = ROUND_SLIGHT;
215     }
216 
217 #ifdef QTC_UTILS_QT
218     if ((widget == WIDGET_MDI_WINDOW_BUTTON &&
219          (opts->titlebarButtons & TITLEBAR_BUTTON_ROUND)) ||
220         QtCurve::oneOf(widget, WIDGET_RADIO_BUTTON, WIDGET_DIAL)) {
221         return ROUND_MAX;
222     }
223 #endif
224 #ifndef QTC_UTILS_QT
225     if (widget == WIDGET_RADIO_BUTTON) {
226         return ROUND_MAX;
227     }
228 #endif
229     if (QtCurve::oneOf(opts->sliderStyle, SLIDER_ROUND, SLIDER_ROUND_ROTATED,
230                        SLIDER_CIRCULAR) && widget == WIDGET_SLIDER) {
231         return ROUND_MAX;
232     }
233     switch (r) {
234     case ROUND_MAX:
235         if (IS_SLIDER(widget) || widget == WIDGET_TROUGH ||
236             (w > (MIN_ROUND_MAX_WIDTH + 2) && h > (MIN_ROUND_MAX_HEIGHT + 2) &&
237              QtCurve::isMaxRoundWidget(widget))) {
238             return ROUND_MAX;
239         }
240     case ROUND_EXTRA:
241         if (CAN_EXTRA_ROUND(2)) {
242             return ROUND_EXTRA;
243         }
244     case ROUND_FULL:
245         if (CAN_FULL_ROUND(2)) {
246             return ROUND_FULL;
247         }
248     case ROUND_SLIGHT:
249         return ROUND_SLIGHT;
250     case ROUND_NONE:
251         return ROUND_NONE;
252     }
253     return ROUND_NONE;
254 }
255 
256 double
qtcGetRadius(const Options * opts,int w,int h,EWidget widget,ERadius rad)257 qtcGetRadius(const Options *opts, int w, int h, EWidget widget, ERadius rad)
258 {
259     ERound r = opts->round;
260 
261     if (QtCurve::oneOf(widget, WIDGET_CHECKBOX, WIDGET_FOCUS) &&
262         ROUND_NONE != r) {
263         r = ROUND_SLIGHT;
264     }
265 
266     if ((QtCurve::oneOf(widget, WIDGET_PBAR_TROUGH, WIDGET_PROGRESSBAR) &&
267          (opts->square & SQUARE_PROGRESS)) ||
268         (widget == WIDGET_ENTRY && (opts->square & SQUARE_ENTRY)) ||
269         (widget == WIDGET_SCROLLVIEW && (opts->square & SQUARE_SCROLLVIEW))) {
270         return 0.0;
271     }
272 
273 #ifdef QTC_UTILS_QT
274     if ((widget == WIDGET_MDI_WINDOW_BUTTON &&
275          (opts->titlebarButtons & TITLEBAR_BUTTON_ROUND)) ||
276         QtCurve::oneOf(widget, WIDGET_RADIO_BUTTON, WIDGET_DIAL)) {
277         return (w > h ? h : w) / 2.0;
278     }
279 #endif
280 #ifndef QTC_UTILS_QT
281     if (widget == WIDGET_RADIO_BUTTON) {
282         return (w > h ? h : w) / 2.0;
283     }
284 #endif
285 
286     if (QtCurve::oneOf(opts->sliderStyle, SLIDER_ROUND, SLIDER_ROUND_ROTATED,
287                        SLIDER_CIRCULAR) && widget == WIDGET_SLIDER) {
288         return (w > h ? h : w) / 2.0;
289     }
290 
291     if (rad == RADIUS_EXTERNAL && !opts->fillProgress &&
292         (widget == WIDGET_PROGRESSBAR
293 #ifndef QTC_UTILS_QT
294          || widget == WIDGET_ENTRY_PROGRESSBAR
295 #endif
296             )) {
297         rad = RADIUS_INTERNAL;
298     }
299 
300     switch (rad) {
301     case RADIUS_SELECTION:
302         switch (r) {
303         case ROUND_MAX:
304         case ROUND_EXTRA:
305             if (/* (WIDGET_RUBBER_BAND==widget && w>14 && h>14) || */
306                 (w > 48 && h > 48)) {
307                 return 6.0;
308             }
309         case ROUND_FULL:
310             /* if( /\*(WIDGET_RUBBER_BAND==widget && w>11 && h>11) || *\/ */
311             /*     (w>48 && h>48)) */
312             /*     return 3.0; */
313             if (w > MIN_ROUND_FULL_SIZE && h > MIN_ROUND_FULL_SIZE) {
314                 return 3.0;
315             }
316         case ROUND_SLIGHT:
317             return 2.0;
318         case ROUND_NONE:
319             return 0;
320         }
321     case RADIUS_INTERNAL:
322         switch (r) {
323         case ROUND_MAX:
324             if (IS_SLIDER(widget) || WIDGET_TROUGH == widget) {
325                 double r = ((w > h ? h : w) -
326                             (WIDGET_SLIDER == widget ? 1 : 0)) / 2.0;
327                 return r > MAX_RADIUS_INTERNAL ? MAX_RADIUS_INTERNAL : r;
328             }
329             if (w > (MIN_ROUND_MAX_WIDTH - 2) &&
330                 h > (MIN_ROUND_MAX_HEIGHT - 2) &&
331                 QtCurve::isMaxRoundWidget(widget)) {
332                 double r = ((w > h ? h : w) - 2.0) / 2.0;
333                 return r > 9.5 ? 9.5 : r;
334             }
335         case ROUND_EXTRA:
336             if (CAN_EXTRA_ROUND(-2)) {
337                 return EXTRA_INNER_RADIUS;
338             }
339         case ROUND_FULL:
340             if (CAN_FULL_ROUND(-2)) {
341                 return FULL_INNER_RADIUS;
342             }
343         case ROUND_SLIGHT:
344             return SLIGHT_INNER_RADIUS;
345         case ROUND_NONE:
346             return 0;
347         }
348     case RADIUS_EXTERNAL:
349         switch (r) {
350         case ROUND_MAX:
351             if (IS_SLIDER(widget) || WIDGET_TROUGH == widget) {
352                 double r = ((w > h ? h : w) -
353                             (WIDGET_SLIDER == widget ? 1 : 0)) / 2.0;
354                 return r > MAX_RADIUS_EXTERNAL ? MAX_RADIUS_EXTERNAL : r;
355             }
356             if (w > MIN_ROUND_MAX_WIDTH && h > MIN_ROUND_MAX_HEIGHT &&
357                 QtCurve::isMaxRoundWidget(widget)) {
358                 double r = ((w > h ? h : w) - 2.0) / 2.0;
359                 return r > 10.5 ? 10.5 : r;
360             }
361         case ROUND_EXTRA:
362             if (CAN_EXTRA_ROUND(0)) {
363                 return EXTRA_OUTER_RADIUS;
364             }
365         case ROUND_FULL:
366             if (CAN_FULL_ROUND(0)) {
367                 return FULL_OUTER_RADIUS;
368             }
369         case ROUND_SLIGHT:
370             return SLIGHT_OUTER_RADIUS;
371         case ROUND_NONE:
372             return 0;
373         }
374     case RADIUS_ETCH:
375         // **NOTE** MUST KEEP IN SYNC WITH getWidgetRound !!!
376         switch (r) {
377         case ROUND_MAX:
378             if (IS_SLIDER(widget) || WIDGET_TROUGH == widget) {
379                 double r = ((w > h ? h : w) -
380                             (WIDGET_SLIDER == widget ? 1 : 0)) / 2.0;
381                 return r > MAX_RADIUS_EXTERNAL ? MAX_RADIUS_EXTERNAL : r;
382             }
383             if (w > (MIN_ROUND_MAX_WIDTH + 2) &&
384                 h > (MIN_ROUND_MAX_HEIGHT + 2) &&
385                 QtCurve::isMaxRoundWidget(widget)) {
386                 double r = ((w > h ? h : w) - 2.0) / 2.0;
387                 return r > 11.5 ? 11.5 : r;
388             }
389         case ROUND_EXTRA:
390             if (CAN_FULL_ROUND(2)) {
391                 return EXTRA_ETCH_RADIUS;
392             }
393         case ROUND_FULL:
394             if (w > (MIN_ROUND_FULL_SIZE + 2) &&
395                 h > (MIN_ROUND_FULL_SIZE + 2)) {
396                 return FULL_ETCH_RADIUS;
397             }
398         case ROUND_SLIGHT:
399             return SLIGHT_ETCH_RADIUS;
400         case ROUND_NONE:
401             return 0;
402         }
403     }
404     return 0;
405 }
406