Salome HOME
updated copyright message
[modules/gui.git] / src / Style / Style_Tools.cxx
1 // Copyright (C) 2007-2023  CEA, EDF, OPEN CASCADE
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 // File   : Style_Tools.cxx
21 // Author : Natalia Ermolaeva, Open CASCADE S.A.S.
22 //
23 #include "Style_Tools.h"
24
25 #include <QPainter>
26 #include <QPainterPath>
27 #include <QRect>
28 #include <QColor>
29 #include <QSize>
30 #include <QTabWidget>
31
32 /*!
33   \class Style_Tools
34   \brief A set of utility functions used by SALOME style to draw widgets
35 */
36
37 /*!
38   \brief Create painter path for specified rectangle
39   \param r rectangle on which painter path is build
40   \return resulting painter path
41 */
42 QPainterPath Style_Tools::painterPath( const QRect& r )
43 {
44   QPainterPath res;
45   double x = r.x(), y = r.y(), right = r.right(), bottom = r.bottom();
46   res.moveTo( x, y );
47   res.lineTo( right, y );
48   res.lineTo( right, bottom );
49   res.lineTo( x, bottom );
50   res.closeSubpath();
51   return res;
52 }
53
54 /*!
55   \brief Create painter path by subtracting painter path \a path from another
56   painter path \a fromPath
57   \param fromPath initial painter path
58   \param path painter path being subtracted from \a fromPath
59   \return resulting painter path
60 */
61 QPainterPath Style_Tools::substractPath( const QPainterPath& fromPath,
62                                          const QPainterPath& path )
63 {
64   QPainterPath res;
65   QRegion aFromRegion( fromPath.toFillPolygon().toPolygon() );
66   QRegion aRegion( path.toFillPolygon().toPolygon() );
67   aFromRegion -= aRegion;
68   res.addRegion( aFromRegion );
69   return res;
70 }
71
72 /*!
73   \brief Create painter path basing on specified rectangle \a r with rounded corners
74   specified by radius \a r, operation \a type and shadow type \a shType.
75   \param r initial rectangle
76   \param rad rounding radius
77   \param type rounding type operation (Style_Tools::RoundType)
78   \param shType shadow type (Style_Tools::ShadowType)
79   \return resulting painter path
80 */
81 QPainterPath Style_Tools::roundRect( const QRect& r, const double rad, int type,
82                                      int shType )
83 {
84   QPainterPath res;
85   if ( type & None )
86     return painterPath( r );
87   double x = r.x(), y = r.y(), right = r.right(), bottom = r.bottom();
88   int aRad = getMaxRect( r, (int)rad );
89
90   if ( shType == WholePath || shType == TopPath ) {
91     if ( type & ( All | Left | BottomLeft ) ) {
92       res.moveTo( x+aRad, bottom );
93       res.arcTo( x, bottom-2*aRad, 2*aRad, 2*aRad, 270, -90 );
94     }
95     else
96       res.moveTo( x, bottom );
97     res.lineTo( x, y+aRad );
98     if ( type & (All | Left | TopLeft ) )
99       res.arcTo( x, y, 2*aRad, 2*aRad, 180, -90 );
100     else
101       res.lineTo( x, y );
102     res.lineTo( right-aRad, y );
103     if ( type & ( All | Right | TopRight ) )
104       res.arcTo( right-2*aRad, y, 2*aRad, 2*aRad, 90, -90 );
105     else
106       res.lineTo( right, y );
107   }
108   if ( shType == WholePath || shType == BottomPath ) {
109     if ( shType == BottomPath ) {
110       if ( type & ( All | Right | TopRight ) )
111         res.moveTo( right, y+aRad );
112       else
113         res.moveTo( right, y );
114     }
115     res.lineTo( right, bottom-aRad );
116     if ( type & ( All | Right | BottomRight ) )
117       res.arcTo( right-2*aRad, bottom-2*aRad, 2*aRad, 2*aRad, 0, -90 );
118     else
119       res.lineTo( right, bottom );
120
121     if ( type & ( All | Left | BottomLeft ) )
122       res.lineTo( x+aRad, bottom );
123     else
124       res.lineTo( x, bottom ); 
125   }
126   if ( shType == WholePath )
127     res.closeSubpath();
128   return res;
129 }
130
131 /*!
132   \brief Draw rectangle with rounded corners.
133   \param p painter
134   \param r drawing rectangle
135   \param rad corner rounding radius
136   \param type rounding type operation (Style_Tools::RoundType)
137   \param c1 first gradient color
138   \param c2 second gradient color
139   \param fill if \c true rectangle is filled with gradiented background according to \a c1 and \a c2
140   \param antial if \c true, rectangle corners are anti-aliased
141 */
142 void Style_Tools::roundRect( QPainter* p, const QRect& r, const double rad, const int type,
143                              const QColor& c1, const QColor& c2, bool fill, bool antial )
144 {
145   if ( antial )
146     p->setRenderHint( QPainter::Antialiasing );
147
148   QPainterPath path = roundRect( r, rad, type );
149
150   if ( fill ) {
151     QLinearGradient gr( r.x(), r.y(), r.x(), r.bottom() );
152     gr.setColorAt( 0.0, c1 );
153     gr.setColorAt( 0.5, c1 );
154     gr.setColorAt( 1.0, c2 );
155     p->fillPath( path, gr );
156   }
157   p->strokePath( path, QPen( c2, Qt::SolidLine ) );
158 }
159
160 /*!
161   \brief Draw rectangle with rounded corners and shadow.
162   \param p painter
163   \param r drawing rectangle
164   \param rad corner rounding radius
165   \param marg drawing margin
166   \param shad shadow size
167   \param type rounding type operation (Style_Tools::RoundType)
168   \param light background's first gradient color
169   \param dark background's second gradient color
170   \param border_top top-left border's color
171   \param border_bot bottom-right border's color
172   \param antialize if \c true, rectangle corners are anti-aliased
173   \param isButton \c true if button is drawn
174   \param btnOn \c true if button is drawn and it is pressed
175   \param fill if \c true rectangle is filled with gradiented background according to \a light and \a dark
176 */
177 void Style_Tools::shadowRect( QPainter* p, const QRect& r, const double rad, const double marg,
178                               const int shad, int type, const QColor& light, const QColor& dark,
179                               const QColor& border_top, const QColor& border_bot, const bool antialize,
180                               const bool isButton, const bool btnOn, const bool fill )
181 {
182   QColor aLight = light, aDark = dark, aBrdTop = border_top, aBrdBot = border_bot;
183   if ( isButton && btnOn ) {
184     aLight = dark;
185     aDark = light;
186     aBrdTop = border_bot;
187     aBrdBot = border_top;
188   }
189
190   // gradients
191   QLinearGradient
192     gr1( r.x(), r.y(), r.right(), r.y() ),
193     gr2( r.x(), r.y(), r.x(), r.bottom() );
194   if ( fill ) {
195     if ( isButton ) {
196       gr2.setColorAt( 0.0, aLight );
197       if ( marg > 0 )
198         gr2.setColorAt( marg / r.height(), aLight );
199       gr2.setColorAt( 1.0, aDark );
200     }
201     else {
202       QColor _c1 = aLight; _c1.setAlpha( 0 );
203       QColor _c2 = aDark;
204       gr1.setColorAt( 0.0, _c2 );
205       if ( marg > 0 )
206         gr1.setColorAt( marg / r.width(), _c1 );
207       gr1.setColorAt( 1.0, _c1 );
208       gr2.setColorAt( 0.0, _c2 );
209       if ( marg > 0 )
210         gr2.setColorAt( marg / r.height(), _c1 );
211       gr2.setColorAt( 1.0, _c1 );
212     }
213   }
214   // paths
215   int x = r.x(), y = r.y(), right = r.right(), bottom = r.bottom();
216   // main path
217   QRect rCont;
218   if ( antialize )
219    rCont = QRect( QPoint( x+shad, y+shad ), QPoint( right-shad, bottom-shad ) );
220   else
221     rCont = QRect( QPoint( x, y ), QPoint( right, bottom ) );
222
223   QPainterPath path = roundRect( rCont, rad, type );
224
225   // draw paths
226   p->save();
227   if ( antialize )
228     p->setRenderHint( QPainter::Antialiasing, true );
229   else
230     p->setRenderHint( QPainter::Antialiasing, false );
231
232   if( fill ) {
233     p->fillPath( path, aLight );
234     if ( !isButton )
235       p->fillPath( path, gr1 );
236     p->fillPath( path, gr2 );
237   }
238   if ( antialize )
239     p->strokePath( path, QPen( aBrdBot, Qt::SolidLine ) );
240
241   QPainterPath bottomPath = roundRect( rCont, rad, type, BottomPath ),
242                topPath = roundRect( rCont, rad, type, TopPath );
243   p->strokePath( bottomPath, aBrdBot );
244   p->strokePath( topPath, aBrdTop );
245
246   if ( antialize )
247       p->setRenderHint( QPainter::Antialiasing, false );
248   p->restore();
249 }
250
251 /*!
252   \brief Draw shadow of the check-mark
253   \param p painter
254   \param r drawing rectangle
255   \param rad corner rounding radius
256   \param type rounding type operation (Style_Tools::RoundType)
257   \param light background's first gradient color
258   \param dark background's second gradient color
259   \param border_top top-left border's color
260   \param border_bot bottom-right border's color
261 */
262 void Style_Tools::shadowCheck( QPainter* p, const QRect& r, const double rad, const int type,
263                                const QColor& light, const QColor& dark,
264                                const QColor& border_top, const QColor& border_bot  )
265 {
266   // main path
267   QPainterPath path = roundRect( r, rad, type );
268
269   QLinearGradient gr( r.x(), r.y(), r.right(), r.bottom() );
270   gr.setColorAt( 0.0, dark );
271   gr.setColorAt( 1.0, light );
272  
273   p->fillPath( path, gr ); //fill
274
275   QPainterPath bottomPath = roundRect( r, rad, type, BottomPath ),
276                topPath = roundRect( r, rad, type, TopPath );
277   p->strokePath( bottomPath, border_bot );
278   p->strokePath( topPath, border_top );
279 }
280
281 /*!
282   \brief Draw rectnagle arrow
283   \param p painter
284   \param re drawing rectangle
285   \param frame frame color
286   \param gr1 background's first gradient color
287   \param gr2 background's second gradient color
288 */
289 void Style_Tools::arrowRect( QPainter* p, const QRect& re, const QColor& frame,
290                              const QColor& gr1, const QColor& gr2 )
291 {
292   QPainterPath path;
293   const int r = 4;
294   const double d = re.height()/2;
295
296   path.moveTo( re.x()+r,            re.y() );
297   path.lineTo( re.x()+re.width(),   re.y() );
298   path.lineTo( re.x()+re.width()+d, re.y()+d );
299   path.lineTo( re.x()+re.width(),   re.y()+re.height() );
300   path.lineTo( re.x()+r,            re.y()+re.height() );
301   path.arcTo ( re.x(),              re.y()+2*d-2*r, 2*r, 2*r, 270, -90 );
302   path.lineTo( re.x(),              re.y()+r );
303   path.arcTo ( re.x(),              re.y(), 2*r, 2*r, 180, -90 );
304   path.closeSubpath();
305
306   QLinearGradient gr( re.x(), re.y(), re.x(), re.y()+re.height() );
307   gr.setColorAt( 0.0, gr1 );
308   gr.setColorAt( 0.4, gr2 );
309   gr.setColorAt( 0.6, gr2 );
310   gr.setColorAt( 1.0, gr1 );
311
312   p->fillPath( path, gr );
313   p->strokePath( path, QPen( frame, Qt::SolidLine ) );
314 }
315
316 /*!
317   \brief Fill rectangle with gradiented background
318   \param p painter
319   \param re drawing rectangle
320   \param c1 background's first gradient color
321   \param c2 background's second gradient color
322 */
323 void Style_Tools::fillRect( QPainter* p, const QRect& re, const QColor& c1,
324                             const QColor& c2, const int alpha )
325 {
326   QLinearGradient gr( re.x(), re.y(), re.x()+re.width(), re.y()+re.height() );
327   QColor cc1 = c1, cc2 = c2;
328   cc1.setAlpha( alpha );
329   cc2.setAlpha( alpha );
330   gr.setColorAt( 0.0, cc1 );
331   gr.setColorAt( 1.0, cc2 );
332   p->fillRect( re, gr );
333 }
334
335 /*!
336   \brief Draw arrow (for example, for combo-box drop-down menu button)
337   \param type primitive type
338   \param p painter
339   \param r drawing rectangle
340   \param pen foreground painter pen
341   \param brush background painter brush
342 */
343 void Style_Tools::drawArrow( QStyle::PrimitiveElement type, QPainter* p, const QRect& r,
344                              const QColor& pen, const QColor& brush )
345 {
346   p->save();
347   QPainterPath arrow1;
348   int x = r.x(), y = r.y(), w = r.right()-x, h = r.bottom()-y;
349   int x11 = 0, x12 = 0, y11 = 0, y12 = 0;
350   int aDelta = qMin( (int)(w/3.5), (int)(h/3.5) );
351   int deltaX = aDelta, deltaY = aDelta;
352   QLineF line( 0, 0, 1, 0 );
353   int xc = r.center().x(), yc = r.center().y();
354   p->translate( xc, yc );
355   bool correct = false;
356   switch( type ) {
357     case QStyle::PE_IndicatorArrowDown: {
358       correct = true;
359     } // fall through!
360     case QStyle::PE_IndicatorArrowUp: {
361       int widthArr2 = (int)(deltaX/3.);
362       if ( correct )
363         deltaY = -deltaY; // change arrow direction
364       arrow1.moveTo(  0,          deltaY );
365       arrow1.lineTo(  widthArr2,  deltaY );
366       arrow1.lineTo(  widthArr2,  0 );
367       arrow1.lineTo(  deltaX,     0 );
368       arrow1.lineTo(  0,          -deltaY );
369       arrow1.lineTo( -deltaX,     0. );
370       arrow1.lineTo( -widthArr2,  0 );
371       arrow1.lineTo( -widthArr2, deltaY );
372       arrow1.lineTo(  0,         deltaY );
373       if ( correct )
374         deltaX = -deltaX;
375       x11 = -deltaX; y11 = -deltaY; x12 = deltaX; y12 = deltaY;
376       break;
377     }
378     case QStyle::PE_IndicatorArrowLeft: {
379       correct = true;
380     } // fall through!
381     case QStyle::PE_IndicatorArrowRight: {
382       int widthArr2 = (int)(deltaX/3.);
383       if ( correct )
384         deltaX = -deltaX; // change arrow direction
385       arrow1.moveTo( -deltaX,  0 );
386       arrow1.lineTo( -deltaX,  widthArr2 );
387       arrow1.lineTo(  0,       widthArr2 );
388       arrow1.lineTo(  0,       deltaY );
389       arrow1.lineTo(  deltaX,  0 );
390       arrow1.lineTo(  0,      -deltaY );
391       arrow1.lineTo(  0,      -widthArr2 );
392       arrow1.lineTo( -deltaX, -widthArr2 );
393       arrow1.lineTo( -deltaX,  0 );
394       x11 = deltaX; y11 = deltaY; x12 = -deltaX; y12 = -deltaY;
395       break;
396     }
397     case QStyle::PE_IndicatorSpinDown: {
398       correct = true;
399     } // fall through!
400     case QStyle::PE_IndicatorSpinUp: {
401       aDelta = (int)(deltaY/2);
402       if ( correct ) {
403         aDelta = (int)(-aDelta/2);
404         deltaY = -deltaY;
405       }
406       arrow1.moveTo(  deltaX,     -aDelta );
407       arrow1.lineTo(  0,          -aDelta-deltaY );
408       arrow1.lineTo( -deltaX,     -aDelta );
409       arrow1.lineTo(  deltaX,     -aDelta );
410       if ( correct )
411         deltaX = -deltaX;
412       x11 = -deltaX, y11 = -deltaY, x12 = deltaX, y12 = 0;
413       break;
414     }
415     default:
416       p->restore();
417       return;
418   }
419   p->setPen( pen );
420   p->setBrush( brush );
421
422   QLinearGradient gr( x11, y11, x12, y12 );
423   gr.setColorAt( 0.0, pen );                // grayer
424   gr.setColorAt( 1.0, brush);               // lighter
425   p->fillPath( arrow1, gr );
426   p->strokePath( arrow1, QPen( pen, Qt::SolidLine ) );
427
428   p->restore();
429 }
430
431 /*!
432   \brief Draw indicator (for example, for spin box's increment/decrement buttons)
433   \param type primitive type
434   \param p painter
435   \param r drawing rectangle
436   \param pen foreground painter pen
437   \param brush background painter brush
438 */
439 void Style_Tools::drawSign( QStyle::PrimitiveElement type, QPainter* p, const QRect& r,
440                             const QColor& pen, const QColor& brush )
441 {
442   p->save();
443   QPainterPath sign;
444   int x = r.x(), y = r.y(), w = r.right()-x, h = r.bottom()-y;
445   int x11 = 0, x12 = 0, y11 = 0, y12 = 0;
446   int aDelta = qMin( (int)(w/3.5), (int)(h/3.5) );
447   int deltaX = aDelta, deltaY = aDelta;
448   QLineF line( 0, 0, 1, 0 );
449   int xc = r.center().x(), yc = r.center().y();
450   p->translate( xc, yc );
451   bool correct = false;
452   switch( type ) {
453     case QStyle::PE_IndicatorSpinMinus: {
454       correct = true;
455     } // fall through!
456     case QStyle::PE_IndicatorSpinPlus: {
457       aDelta = (int)(deltaY/2);
458       if ( correct ) {
459         aDelta = -aDelta;
460         deltaY = -deltaY;
461       }
462       if ( correct ) 
463         sign.moveTo(  deltaY/2,   -aDelta/2-(deltaY/2-aDelta/3) );
464       else {
465         sign.moveTo(  aDelta/3,   -aDelta/2 );
466         sign.lineTo(  aDelta/3,   -aDelta/2-(deltaY/2-aDelta/3) );
467         sign.lineTo(  deltaY/2,   -aDelta/2-(deltaY/2-aDelta/3) );
468       }
469       
470       sign.lineTo(    deltaY/2,   -aDelta/2-(deltaY/2-aDelta/3)-2*aDelta/3 );
471       
472       if ( !correct ) {
473         sign.lineTo(  aDelta/3,   -aDelta/2-(deltaY/2-aDelta/3)-2*aDelta/3 );
474         sign.lineTo(  aDelta/3,   -aDelta/2-deltaY );
475         sign.lineTo( -aDelta/3,   -aDelta/2-deltaY );
476         sign.lineTo( -aDelta/3,   -aDelta/2-(deltaY/2-aDelta/3)-2*aDelta/3 );
477       }
478       
479       sign.lineTo(   -deltaY/2,   -aDelta/2-(deltaY/2-aDelta/3)-2*aDelta/3 );
480       sign.lineTo(   -deltaY/2,   -aDelta/2-(deltaY/2-aDelta/3) );
481
482       if ( correct ) 
483         sign.lineTo(  deltaY/2,   -aDelta/2-(deltaY/2-aDelta/3) );
484       else {
485         sign.lineTo( -aDelta/3,   -aDelta/2-(deltaY/2-aDelta/3) );
486         sign.lineTo( -aDelta/3,   -aDelta/2 );
487         sign.lineTo(  aDelta/3,   -aDelta/2);
488       }
489
490       if ( correct )
491         deltaX = -deltaX;
492       x11 = -deltaX, y11 = -deltaY, x12 = deltaX, y12 = 0;
493       break;
494     }
495     default:
496       p->restore();
497       return;
498   }
499   p->setPen( pen );
500   p->setBrush( brush );
501
502   QLinearGradient gr( x11, y11, x12, y12 );
503   gr.setColorAt( 0.0, pen );                // grayer
504   gr.setColorAt( 1.0, brush);               // lighter
505   p->fillPath( sign, gr );
506   p->strokePath( sign, QPen( pen, Qt::SolidLine ) );
507
508   p->restore();
509 }
510
511 /*!
512   \brief Create painter path for tab bar and optionally draw it
513   \param p painter
514   \param r drawing rectangle
515   \param position tab position
516   \param rad rounding radius
517   \param delta gap between tabs
518   \param light background's first gradient color
519   \param dark background's second gradient color
520   \param border_top top-left border's color
521   \param border_bot bottom-right border's color
522   \param selected \c true if tab is selected
523   \param isLast \c true if tab is last in the tabs list
524   \param isHover \c true if tab is hovered
525   \param focusRect focus rectangle
526   \param draw if \c true, tab bar is drawn
527   \return tab bar's painter path
528 */
529 QPainterPath Style_Tools::tabRect( QPainter* p, const QRect& r, const int position, const double rad,
530                                    const double delta, const QColor& light, const QColor& dark,
531                                    const QColor& border_top, const QColor& border_bot,
532                                    const bool selected, const bool isLast,  const bool isHover,
533                                    const bool focusRect, const bool draw )
534 {
535   // paths
536   int x = r.x()+1, y = r.y()+1, right = r.right()+1, left = r.left()-1,
537       bottom = r.bottom()-1, top = r.top()+1;
538   int aDelta;
539   if ( position == QTabWidget::North || position == QTabWidget::South )
540     aDelta = (int)((bottom - top)*delta/2);
541   else
542     aDelta = (int)((right-left)*delta/2);  
543
544   int aRad = getMaxRect( r, (int)rad );
545
546   // main path
547   QPainterPath path, strokePath;
548   switch ( position ) {
549     case QTabWidget::North: {
550       path.moveTo( x, bottom );
551       path.lineTo( x, y+aRad );
552       path.arcTo( x, y, 2*aRad, 2*aRad, 180, -90 );
553       if ( isLast )
554         right = right - aDelta;
555       path.lineTo( right-aDelta, y );
556       path.lineTo( right+aDelta, bottom );
557       strokePath.moveTo( x, bottom );
558       strokePath.lineTo( right+aDelta, bottom );
559       break;
560     }
561     case QTabWidget::South: {
562       path.moveTo( x, y );
563       path.lineTo( x, bottom-aRad );
564       path.arcTo( x, bottom-2*aRad, 2*aRad, 2*aRad, 180, 90 );
565       if ( isLast )
566         right = right - aDelta;
567       path.lineTo( right-aDelta, bottom );
568       path.lineTo( right+aDelta, y );
569       strokePath.moveTo( x, y );
570       strokePath.lineTo( right+aDelta, y );
571       break;
572     }
573     case QTabWidget::West: {
574       path.moveTo( right, y );
575       path.lineTo( x+aRad, y );
576       path.arcTo( x, y, 2*aRad, 2*aRad, 90, 90 );
577       if ( isLast )
578         bottom = bottom - aDelta;
579       path.lineTo( x, bottom-aDelta );
580       path.lineTo( right, bottom+aDelta );
581       strokePath.moveTo( right, y );
582       strokePath.lineTo( right, bottom+aDelta );
583       break;
584     }
585     case QTabWidget::East: {
586       path.moveTo( x, y );
587       path.lineTo( right-aRad, y );
588       path.arcTo( right-2*aRad, y, 2*aRad, 2*aRad, 90, -90 );
589       if ( isLast )
590         bottom = bottom - aDelta;
591       path.lineTo( right, bottom-aDelta );
592       path.lineTo( x, bottom+aDelta );
593       strokePath.moveTo( x, y );
594       strokePath.lineTo( x, bottom+aDelta );
595       break;
596     }
597   }
598   if ( !draw )
599     return path;
600
601   // draw path
602   p->save();
603   p->setRenderHint( QPainter::Antialiasing, true );
604   if ( focusRect ) {
605     path.closeSubpath();
606     drawFocus( p, path, dark, false );
607   }
608   else {
609     QLinearGradient gr( x, y, x, bottom );
610     if ( selected ) {
611       gr.setColorAt( 0.0, light );
612       gr.setColorAt( 1.0, light );
613     }
614     else if ( isHover ) {
615       gr.setColorAt( 0.0, dark );
616       gr.setColorAt( 0.2, light );
617       gr.setColorAt( 0.8, light );
618       gr.setColorAt( 1.0, dark );
619       QLinearGradient gr_1( x, y, right, y );
620       QColor aLight = light;
621       aLight.setAlpha( 0 );
622       gr_1.setColorAt( 0.0, dark );
623       gr_1.setColorAt( 0.2, aLight );
624       gr_1.setColorAt( 0.7, aLight );
625       gr_1.setColorAt( 1.0, dark );
626       p->fillPath( path, gr );
627       p->fillPath( path, gr_1 );
628     }
629     else {
630       gr.setColorAt( 0.0, light );
631       gr.setColorAt( 0.3, dark );
632       gr.setColorAt( 0.7, dark );
633       gr.setColorAt( 1.0, light );
634     }
635     if ( !isHover || selected )
636       p->fillPath( path, gr );
637
638     QColor bordCol = border_top;
639     if ( position == QTabWidget::South || position == QTabWidget::East )
640       bordCol = border_bot;
641     else
642       bordCol = border_top;
643     p->strokePath( path, QPen( bordCol, Qt::SolidLine ) );
644     p->setRenderHint( QPainter::Antialiasing, false );
645     p->strokePath( strokePath, QPen( selected ? light : bordCol, Qt::SolidLine ) );
646   }
647   p->restore();
648   return path;
649 }
650
651 /*!
652   \brief Draw widget's focus
653   \param p painter
654   \param aRect drawing rectangle
655   \param rad rounding radius
656   \param type rounding operation type
657   \param border focus rectangle color
658 */
659 void Style_Tools::drawFocus( QPainter* p, const QRect& aRect, const double rad, const int type,
660                              const QColor& border )
661 {
662   QPainterPath path = Style_Tools::roundRect( aRect, rad, type );
663
664   drawFocus( p, path, border );
665 }
666
667 /*!
668   \brief Draw widget's focus
669   \param p painter
670   \param path drawing painter path
671   \param border focus rectangle color
672   \param line if \c true, focus is drawn as dotted line
673 */
674 void Style_Tools::drawFocus( QPainter* p, const QPainterPath& path, const QColor& border,
675                              const bool line )
676 {
677   QPen oldPen = p->pen();
678   QPen aPen = oldPen;
679   aPen.setColor( border );
680   if ( !line )
681     aPen.setStyle( Qt::DotLine );
682   p->setPen( aPen );
683
684   p->drawPath( path );
685   p->setPen( oldPen );
686 }
687
688 /*!
689   \brief Draw slider
690   \param p painter
691   \param r drawing rectangle
692   \param rad rounding radius
693   \param slider slider type
694   \param light background's first gradient color
695   \param dark background's second gradient color
696   \param border_top top-left border's color
697   \param border_bot bottom-right border's color
698 */
699 void Style_Tools::drawSlider( QPainter* p, const QRect& r, const double rad,
700                               SliderType type, const QColor& light, const QColor& dark,
701                               const QColor& /*border_top*/, const QColor& border_bot )
702 {
703   p->save();
704   QPainterPath path, bottomPath;
705   if ( rad == 0 )
706     type = SlNone;
707   int aRad = getMaxRect( r, (int)rad );
708   int w = r.width(), h = r.height();
709   int xc = r.center().x(), yc = r.center().y();
710   p->translate( xc, yc );
711   QLinearGradient gr;
712   switch ( type ) {
713     case SlUp:
714     case SlDown: {
715       int aDeltaX = (int)(w/2), aDeltaY = (int)(h/4), aDeltaArr = (int)(aDeltaY/2);
716       if ( type == SlDown )
717         p->rotate( 180 );
718       path.moveTo(  0,       -2*aDeltaY );
719       path.lineTo(  aDeltaX, -aDeltaY+aDeltaArr );
720       path.lineTo(  aDeltaX, 2*aDeltaY-aRad );
721       path.arcTo(   aDeltaX-2*aRad, 2*aDeltaY-2*aRad, 2*aRad, 2*aRad, 0, -90 );
722       path.lineTo( -aDeltaX+aRad, 2*aDeltaY );
723       path.arcTo(  -aDeltaX,  2*aDeltaY-2*aRad, 2*aRad, 2*aRad, 270, -90 );
724       path.lineTo( -aDeltaX, -aDeltaY+aDeltaArr );
725       path.lineTo( 0,       -2*aDeltaY );
726       bottomPath = path;
727       gr.setStart( 0, -2*aDeltaY );
728       gr.setFinalStop( 0, 2*aDeltaY );
729       break;
730     }
731     case SlLeft:
732     case SlRight: {
733       int aDeltaX = (int)(w/4), aDeltaY = (int)(h/2), aDeltaArr = (int)(aDeltaX/2);
734       if ( type == SlRight )
735         p->rotate( 180 );
736       path.moveTo( -2*aDeltaX,        0 );
737       path.lineTo( -aDeltaX+aDeltaArr,aDeltaY );
738       path.lineTo(  2*aDeltaX-aRad,   aDeltaY );
739       path.arcTo(   2*aDeltaX-2*aRad, aDeltaY-2*aRad, 2*aRad, 2*aRad, 270, 90 );
740       path.lineTo(  2*aDeltaX,       -aDeltaY+aRad );
741       path.arcTo(   2*aDeltaX-2*aRad, -aDeltaY, 2*aRad, 2*aRad, 0, 90 );
742       path.lineTo( -aDeltaX+aDeltaArr,-aDeltaY );
743       path.lineTo( -2*aDeltaX,       0 );
744       gr.setStart( -2*aDeltaX, 0 );
745       gr.setFinalStop( 2*aDeltaX, 0 );
746       bottomPath = path;
747       break;
748     }
749     case SlNone: {
750       p->translate( -xc, -yc );
751       path = Style_Tools::roundRect( r, rad, Style_Tools::All );
752       bottomPath = path;
753       gr.setStart( r.x(), r.y() );
754       gr.setFinalStop( r.x(), r.bottom() );
755       break;
756     }
757     default:
758       return;
759   }
760   p->setRenderHint( QPainter::Antialiasing );
761   gr.setColorAt( 0.0, light );
762   gr.setColorAt( 1.0, dark );
763   p->fillPath( path, gr );
764
765   QColor bottomShadow = border_bot;
766   p->strokePath( bottomPath, bottomShadow );
767   p->setRenderHint( QPainter::Antialiasing, false );
768   p->restore();
769 }
770
771 /*!
772   \brief Draw highlighted rectangle
773   \param p painter
774   \param rect drawing rectangle
775   \param rad rounding radius
776   \param type rounding operation type
777   \parma marg margin size
778   \param center background's center gradient color
779   \param out_center background's second color
780   \param border border color
781 */
782 void Style_Tools::highlightRect( QPainter* p, const QRect& rect, const double rad, const int type,
783                                  const double marg, const QColor& center, const QColor& out_center,
784                                  const QColor& border )
785 {
786   QPainterPath path = Style_Tools::roundRect( rect, rad, type );
787   QLinearGradient gr_h( rect.x(), rect.y(), rect.right(), rect.y() ),
788                   gr_v( rect.x(), rect.y(), rect.x(), rect.bottom() );
789   double aXDelta = marg > 0 ? marg/rect.width() : 0.5;
790   double aYDelta = marg > 0 ? marg/rect.height() : 0.5;
791   if ( aYDelta > 0.5 )
792     aYDelta = 0.25;
793   gr_v.setColorAt( 0.0, out_center );
794   gr_v.setColorAt( aYDelta, center );
795   gr_v.setColorAt( 1-aYDelta, center );
796   gr_v.setColorAt( 1.0, out_center );
797
798   QColor aCenter = center;
799   aCenter.setAlpha( 0 );
800   if ( aXDelta > 0.5 )
801     aXDelta = 0.25;
802   gr_h.setColorAt( 0.0, out_center );
803   gr_h.setColorAt( aXDelta, aCenter );
804   gr_h.setColorAt( 1-aXDelta, aCenter );
805   gr_h.setColorAt( 1.0, out_center );
806
807   p->fillPath( path, gr_v );
808   if ( marg > 0 )
809     p->fillPath( path, gr_h );
810   p->strokePath( path, border );
811 }
812
813 /*!
814   \brief Get minimal delta value (the minimum between \a rect and \a size dimensions)
815   \param rect rectangle
816   \param size size
817   \param defDelta default minimum delta
818   \return resulting minimum value
819 */
820 int Style_Tools::getMinDelta( const QRect& rect, const QSize& size, const int defDelta )
821 {
822   int aDelta = defDelta;
823   aDelta = qMin( aDelta, ( rect.height() - size.height() ) / 2 );
824   aDelta = qMin( aDelta, ( rect.width()  - size.width() )  / 2 );
825   return aDelta;
826 }
827
828 /*!
829   \brief Get halved size of the quadrangle covering specified rectangle
830   \param rect rectangle
831   \param defRect default quadranle size value
832   \return resulting value
833 */
834 int Style_Tools::getMaxRect( const QRect& rect, const int defRect )
835 {
836   int aRect = defRect;
837   aRect = qMin( aRect, rect.height() / 2 );
838   aRect = qMin( aRect, rect.width()  / 2 );
839   return aRect;
840 }