Salome HOME
10d1e397bc4cf8b2890e4ab54893f365ccc276e6
[modules/gui.git] / src / Style / Style_PrefDlg.cxx
1 //  Copyright (C) 2007-2008  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 //  Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 //  This library is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU Lesser General Public
8 //  License as published by the Free Software Foundation; either
9 //  version 2.1 of the License.
10 //
11 //  This library is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 //  Lesser General Public License for more details.
15 //
16 //  You should have received a copy of the GNU Lesser General Public
17 //  License along with this library; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 //  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22 // File   : Style_PrefDlg.cxx
23 // Author : Vadim SANDLER, Open CASCADE S.A.S (vadim.sandler@opencascade.com)
24 //
25 #include "Style_PrefDlg.h"
26 #include "Style_ResourceMgr.h"
27 #include "Style_Model.h"
28 #include "Style_Salome.h"
29
30 #include <QtxColorButton.h>
31 #include <QtxDoubleSpinBox.h>
32 #include <QtxFontEdit.h>
33
34 #include <QApplication>
35 #include <QButtonGroup>
36 #include <QCheckBox>
37 #include <QColorDialog>
38 #include <QComboBox>
39 #include <QGridLayout>
40 #include <QGroupBox>
41 #include <QHBoxLayout>
42 #include <QKeyEvent>
43 #include <QLabel>
44 #include <QListWidget>
45 #include <QMap>
46 #include <QMessageBox>
47 #include <QPushButton>
48 #include <QRadioButton>
49 #include <QSlider>
50 #include <QSpinBox>
51 #include <QStackedWidget>
52 #include <QTabWidget>
53 #include <QVBoxLayout>
54
55 static const int MARGIN  = 9;
56 static const int SPACING = 6;
57
58 /*!
59   \class Style_PrefDlg::PaletteEditor
60   \brief SALOME style palette editor widget
61   \internal
62 */
63
64 /*!
65   \brief Constructor
66   \param parent parent widget
67   \internal
68 */
69 Style_PrefDlg::PaletteEditor::PaletteEditor( QWidget* parent )
70   : QFrame( parent ), myCurrentRow( 0 ), myCurrentColumn( -1 )
71 {
72   QGridLayout* l = new QGridLayout( this );
73   l->setMargin( MARGIN ); l->setSpacing( SPACING );
74   l->addWidget( myQuickButton = new QPushButton( tr( "Quick" ), this ), 0, 0 );
75   l->addWidget( myAutoCheck   = new QCheckBox( tr( "Auto" ),    this ), 0, 1 );
76   l->addWidget( myContainer   = new QFrame( this ),                     1, 0, 1, 2 );
77
78   l = new QGridLayout( myContainer );
79   l->setMargin( 0 ); l->setSpacing( SPACING );
80
81   addColumn( tr( "Base colors" ) );
82   for ( int i = (int)Style_Model::WindowText; i < (int)Style_Model::NColorRoles; i++ ) {
83     if ( i == Style_Model::NoRole ) continue;
84     addItem( i );
85   }
86
87   addColumn( tr( "Additional colors" ) );
88   for ( int i = (int)Style_Model::BorderTop; i < (int)Style_Model::LastColor; i++ )
89     addItem( i );
90
91   connect( myQuickButton, SIGNAL( clicked() ),       this, SLOT( onQuick() ) );
92   connect( myAutoCheck,   SIGNAL( toggled( bool ) ), this, SLOT( onAuto()  ) );
93 }
94
95 /*!
96   \brief Destructor
97   \internal
98 */
99 Style_PrefDlg::PaletteEditor::~PaletteEditor()
100 {
101 }
102
103 /*!
104   \brief Add new color properties column to the widget
105   \param title column title
106   \sa addItem()
107   \internal
108 */
109 void Style_PrefDlg::PaletteEditor::addColumn( const QString& title )
110 {
111   QGridLayout* l = qobject_cast<QGridLayout*>( myContainer->layout() );
112   myCurrentRow = 0;
113   myCurrentColumn++;
114
115   if ( !title.isEmpty() ) {
116     QHBoxLayout* hbox = new QHBoxLayout;
117     hbox->setMargin( 0 ); hbox->setSpacing( SPACING );
118     QWidget* ln = line();
119     hbox->addWidget( ln );
120     hbox->setStretchFactor( ln, 5 );
121     QLabel* tlt = new QLabel( title, myContainer );
122     tlt->setAlignment( Qt::AlignCenter );
123     hbox->addWidget( tlt );
124     ln = line();
125     hbox->addWidget( ln );
126     hbox->setStretchFactor( ln, 5 );
127     l->addLayout( hbox, myCurrentRow++, myCurrentColumn*4, 1, 4 );
128   }
129
130   l->addWidget( myActiveLab   = new QLabel( tr( "Active" ),   myContainer ), myCurrentRow, myCurrentColumn*4+1 );
131   l->addWidget( myInactiveLab = new QLabel( tr( "Inactive" ), myContainer ), myCurrentRow, myCurrentColumn*4+2 );
132   l->addWidget( myDisabledLab = new QLabel( tr( "Disable" ),  myContainer ), myCurrentRow, myCurrentColumn*4+3 );
133   int w = 0;
134   w = qMax( w, myActiveLab->sizeHint().width() );
135   w = qMax( w, myInactiveLab->sizeHint().width() );
136   w = qMax( w, myDisabledLab->sizeHint().width() );
137   myActiveLab->setMinimumWidth( w );
138   myInactiveLab->setMinimumWidth( w );
139   myDisabledLab->setMinimumWidth( w );
140   
141   for( int i = 1; i < 4; i++ ) l->setColumnStretch( myCurrentColumn*4+i, 5 );
142
143   myCurrentRow++;
144 }
145
146 /*!
147   \brief Add color item to the widget (to the current column)
148   \param id color palette identifier (Style_Model::ColorRole)
149   \sa addColumn(), items()
150   \internal
151 */
152 void Style_PrefDlg::PaletteEditor::addItem( int id )
153 {
154   if ( myButtons.contains( id ) )
155     return;
156
157   myButtons[ id ] = Btns();
158   myButtons[ id ][ QPalette::Active ]   = new QtxColorButton( myContainer );
159   myButtons[ id ][ QPalette::Inactive ] = new QtxColorButton( myContainer );
160   myButtons[ id ][ QPalette::Disabled ] = new QtxColorButton( myContainer );
161   myButtons[ id ][ QPalette::Active ]->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ) );
162   myButtons[ id ][ QPalette::Inactive ]->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ) );
163   myButtons[ id ][ QPalette::Disabled ]->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ) );
164
165   QGridLayout* l = qobject_cast<QGridLayout*>( myContainer->layout() );
166   l->addWidget( new QLabel( idToName( id ), myContainer ), myCurrentRow, myCurrentColumn*4 );
167   l->addWidget( myButtons[ id ][ QPalette::Active ],       myCurrentRow, myCurrentColumn*4+1 );
168   l->addWidget( myButtons[ id ][ QPalette::Inactive ],     myCurrentRow, myCurrentColumn*4+2 );
169   l->addWidget( myButtons[ id ][ QPalette::Disabled ],     myCurrentRow, myCurrentColumn*4+3 );
170
171   connect( myButtons[ id ][ QPalette::Active   ], SIGNAL( changed( QColor ) ), this, SIGNAL( changed() ) );
172   connect( myButtons[ id ][ QPalette::Inactive ], SIGNAL( changed( QColor ) ), this, SIGNAL( changed() ) );
173   connect( myButtons[ id ][ QPalette::Disabled ], SIGNAL( changed( QColor ) ), this, SIGNAL( changed() ) );
174
175   myCurrentRow++;
176 }
177
178 /*!
179   \brief Get list of currently available color items
180   \return list of items identifiers (Style_Model::ColorRole)
181   \sa addColumn(), addItem()
182   \internal
183 */
184 QList<int> Style_PrefDlg::PaletteEditor::items() const
185 {
186   return myButtons.keys();
187 }
188
189 /*!
190   \brief Set color value to the item
191   \param id item identifier (Style_Model::ColorRole)
192   \param cg color group
193   \param c color value
194   \sa color()
195   \internal
196 */
197 void Style_PrefDlg::PaletteEditor::setColor( int id, QPalette::ColorGroup cg, const QColor& c )
198 {
199   if ( myButtons.contains( id ) ) {
200     myButtons[ id ][ cg ]->setColor( c );
201   }
202 }
203
204 /*!
205   \brief Set color value to the item
206   \param id item identifier (Style_Model::ColorRole)
207   \param active color to be used with active color group (QPalette::Active)
208   \param inactive color to be used with inactive color group (QPalette::Inactive)
209   \param disabled color to be used with disabled color group (QPalette::Disabled)
210   \sa color()
211   \internal
212 */
213 void Style_PrefDlg::PaletteEditor::setColor( int id, const QColor& active,
214                                              const QColor& inactive, const QColor& disabled )
215 {
216   setColor( id, QPalette::Active,   active );
217   setColor( id, QPalette::Inactive, inactive.isValid() ? inactive : active );
218   setColor( id, QPalette::Disabled, disabled.isValid() ? disabled : active );
219 }
220
221 /*!
222   \brief Get color value assigned to the item
223   \param id item identifier (Style_Model::ColorRole)
224   \param cg color group
225   \return color value
226   \sa setColor()
227   \internal
228 */
229 QColor Style_PrefDlg::PaletteEditor::color( int id, QPalette::ColorGroup cg ) const
230 {
231   QColor c;
232   if ( myButtons.contains( id ) ) {
233     c = myButtons[ id ][ cg ]->color();
234   }
235   return c;
236 }
237
238 /*!
239   \brief Get 'auto-palette' flag value
240   \return \c true if inactive/disabled palette colors should be calculated from active one
241   \sa setAuto()
242   \internal
243 */
244 bool Style_PrefDlg::PaletteEditor::isAuto() const
245 {
246   return myAutoCheck->isChecked();
247 }
248
249 /*!
250   \brief Set/clear 'auto-palette' flag value
251   \param on if \c true, inactive/disabled palette colors should be calculated from active one
252   \sa isAuto()
253   \internal
254 */
255 void Style_PrefDlg::PaletteEditor::setAuto( bool on )
256 {
257   myAutoCheck->setChecked( on );
258 }
259
260 /*!
261   \brief Initialize all palette colors from color \a c
262   \param c button color value
263   \internal
264 */
265 void Style_PrefDlg::PaletteEditor::fromColor( const QColor& c )
266 {
267   const QPalette pal = QPalette( c );
268   for ( int i = 0; i < (int)Style_Model::NColorRoles; i++ ) {
269     setColor( i,
270               pal.color( QPalette::Active,   (QPalette::ColorRole)i ), 
271               pal.color( QPalette::Inactive, (QPalette::ColorRole)i ),
272               pal.color( QPalette::Disabled, (QPalette::ColorRole)i ) );
273   }
274
275   // Header
276   setColor( Style_Model::Header,
277             pal.color( QPalette::Active,   QPalette::Button ), 
278             pal.color( QPalette::Inactive, QPalette::Button ),
279             pal.color( QPalette::Disabled, QPalette::Button ) );
280   // Checked
281   setColor( Style_Model::Checked,
282             pal.color( QPalette::Active,   QPalette::Base ),
283             pal.color( QPalette::Inactive, QPalette::Base ),
284             pal.color( QPalette::Disabled, QPalette::Base ) );
285   // Lines
286   setColor( Style_Model::Lines,
287             pal.color( QPalette::Active,   QPalette::Mid ),
288             pal.color( QPalette::Inactive, QPalette::Mid ),
289             pal.color( QPalette::Disabled, QPalette::Mid ) );
290   // Slider
291   setColor( Style_Model::Slider,
292             pal.color( QPalette::Active,   QPalette::Button ),
293             pal.color( QPalette::Inactive, QPalette::Button ),
294             pal.color( QPalette::Disabled, QPalette::Button ) );
295   // ProgressBar
296   setColor( Style_Model::ProgressBar,
297             pal.color( QPalette::Active,   QPalette::Highlight ),
298             pal.color( QPalette::Inactive, QPalette::Highlight ),
299             pal.color( QPalette::Disabled, QPalette::Highlight ) );
300   // FieldLight
301   setColor( Style_Model::FieldLight,
302             pal.color( QPalette::Active,   QPalette::Light ),
303             pal.color( QPalette::Inactive, QPalette::Light ),
304             pal.color( QPalette::Disabled, QPalette::Light ) );
305   // FieldDark
306   setColor( Style_Model::FieldDark,
307             pal.color( QPalette::Active,   QPalette::Mid ).light( 125 ),
308             pal.color( QPalette::Inactive, QPalette::Mid ).light( 125 ),
309             pal.color( QPalette::Disabled, QPalette::Mid ).light( 125 ) );
310   // GridLine
311   setColor( Style_Model::GridLine,
312             pal.color( QPalette::Active,   QPalette::Mid ),
313             pal.color( QPalette::Inactive, QPalette::Mid ),
314             pal.color( QPalette::Disabled, QPalette::Mid ) );
315   // HighlightWidget
316   setColor( Style_Model::HighlightWidget,
317             pal.color( QPalette::Active,   QPalette::Button ),
318             pal.color( QPalette::Inactive, QPalette::Button ),
319             pal.color( QPalette::Disabled, QPalette::Button ) );
320   // HighlightWidget
321   setColor( Style_Model::HighlightBorder,
322             pal.color( QPalette::Active,   QPalette::Button ).dark( 100 ),
323             pal.color( QPalette::Inactive, QPalette::Button ).dark( 100 ),
324             pal.color( QPalette::Disabled, QPalette::Button ).dark( 100 ) );
325   // Pointer
326   setColor( Style_Model::Pointer, Qt::black, Qt::black, Qt::black );
327
328   QColor aDarkActive   = pal.color( QPalette::Active,   QPalette::Dark );
329   QColor aDarkInactive = pal.color( QPalette::Inactive, QPalette::Dark );
330   QColor aDarkDisabled = pal.color( QPalette::Disabled, QPalette::Dark );
331
332   // BorderTop
333   setColor( Style_Model::BorderTop,
334             aDarkActive.lighter(),
335             aDarkInactive.lighter(),
336             aDarkDisabled.lighter() );
337   // BorderBottom
338   setColor( Style_Model::BorderBottom,
339             aDarkActive.darker(),
340             aDarkInactive.darker(),
341             aDarkDisabled.darker() );
342   // TabBorderTop
343   setColor( Style_Model::TabBorderTop,
344             aDarkActive.light().light().light(),
345             aDarkInactive.light().light().light(), 
346             aDarkDisabled.light().light().light() );
347   // TabBorderBottom
348   setColor( Style_Model::TabBorderBottom,
349             aDarkActive.dark().dark().dark(),
350             aDarkInactive.dark().dark().dark(),
351             aDarkDisabled.dark().dark().dark() );
352 }
353
354 /*!
355   \brief Get title of the item
356   \param id item identifier (Style_Model::ColorRole)
357   \return item title
358   \internal
359 */
360 QString Style_PrefDlg::PaletteEditor::idToName( int id )
361 {
362   QString name;
363   switch ( id ) {
364   case Style_Model::WindowText:        //  0
365     name = tr( "Window text" ); break;
366   case Style_Model::Button:            //  1
367     name = tr( "Button" ); break;
368   case Style_Model::Light:             //  2
369     name = tr( "Light" ); break;
370   case Style_Model::Midlight:          //  3
371     name = tr( "Midlight" ); break;
372   case Style_Model::Dark:              //  4
373     name = tr( "Dark" ); break;
374   case Style_Model::Mid:               //  5
375     name = tr( "Mid" );             break;
376   case Style_Model::Text:              //  6
377     name = tr( "Text" );             break;
378   case Style_Model::BrightText:        //  7
379     name = tr( "Bright text" );      break;
380   case Style_Model::ButtonText:        //  8
381     name = tr( "Buttont text" );      break;
382   case Style_Model::Base:              //  9
383     name = tr( "Base" );             break;
384   case Style_Model::Window:            // 10
385     name = tr( "Window" );           break;
386   case Style_Model::Shadow:            // 11
387     name = tr( "Shadow" );           break;
388   case Style_Model::Highlight:         // 12
389     name = tr( "Highlight" );        break;
390   case Style_Model::HighlightedText:   // 13
391     name = tr( "Highlighted text" ); break;
392   case Style_Model::Link:              // 14
393     name = tr( "Link" );             break;
394   case Style_Model::LinkVisited:       // 15
395     name = tr( "Visited link" );     break;
396   case Style_Model::AlternateBase:     // 16
397     name = tr( "Alternate base" );   break;
398   case Style_Model::ToolTipBase:       // 18
399     name = tr( "Tooltip base" );    break;
400   case Style_Model::ToolTipText:       // 19
401     name = tr( "Tooltip text" );    break;
402   case Style_Model::BorderTop:
403     name = tr( "Border top" ); break;
404   case Style_Model::BorderBottom:
405     name = tr( "Border bottom" ); break;
406   case Style_Model::TabBorderTop:
407     name = tr( "Tab border top" ); break;
408   case Style_Model::TabBorderBottom:
409     name = tr( "Tab border bottom" ); break;
410   case Style_Model::FieldLight:
411     name = tr( "Field light" ); break;
412   case Style_Model::FieldDark:
413     name = tr( "Field dark" ); break;
414   case Style_Model::Slider:
415     name = tr( "Slider" ); break;
416   case Style_Model::Lines:
417     name = tr( "Lines" ); break;
418   case Style_Model::HighlightWidget:
419     name = tr( "Widget center" ); break;
420   case Style_Model::HighlightBorder:
421     name = tr( "Widget border" ); break;
422   case Style_Model::Header:
423     name = tr( "Header" ); break;
424   case Style_Model::ProgressBar:
425     name = tr( "Progress bar" ); break;
426   case Style_Model::Pointer:
427     name = tr( "Pointer" ); break;
428   case Style_Model::Checked:
429     name = tr( "Checked" ); break;
430   case Style_Model::GridLine:
431     name = tr( "Table grid" ); break;
432   default:
433     break;
434   }
435   return name;
436 }
437
438 /*!
439   \brief Create horizontal line widget
440   \return new line widget
441   \internal
442 */
443 QWidget* Style_PrefDlg::PaletteEditor::line()
444 {
445   QFrame* hline = new QFrame( myContainer );
446   hline->setFrameStyle( QFrame::HLine | QFrame::Sunken );
447   return hline;
448 }
449
450 /*!
451   \brief Called when "Quick" button is clicked
452   \internal
453 */
454 void Style_PrefDlg::PaletteEditor::onQuick()
455 {
456   static QColor lastColor = Qt::white;
457   QColor c = QColorDialog::getColor( lastColor, this );
458   if ( c.isValid() ) {
459     fromColor( lastColor = c );
460     emit( changed() );
461   }
462 }
463
464 /*!
465   \brief Called when "Auto" check box is clicked
466   \internal
467 */
468 void Style_PrefDlg::PaletteEditor::onAuto()
469 {
470   foreach( Btns btn, myButtons ) {
471     btn[ QPalette::Inactive ]->setEnabled( !myAutoCheck->isChecked() );
472     btn[ QPalette::Disabled ]->setEnabled( !myAutoCheck->isChecked() );
473   }
474   emit( changed() );
475 }
476
477 /*!
478   \class Style_PrefDlg
479   \brief SALOME style prefences dialog box class.
480
481   The dialog box lists all SALOME style themes available via the application and allows
482   user to create own schemas.
483 */
484
485 /*!
486   \brief Constructor
487   \param parent parent widget
488 */
489 Style_PrefDlg::Style_PrefDlg( QWidget* parent )
490   : QtxDialog( parent, true, true, OK | Close | Apply ),
491     myResMgr( 0 )
492 {
493   // set title
494   setWindowTitle( tr( "SALOME style preferences" ) );
495
496   // create main layout
497   QVBoxLayout* main = new QVBoxLayout( mainFrame() );
498   main->setMargin( 0 ); main->setSpacing( SPACING );
499
500   // create main widgets
501   myStyleCheck = new QCheckBox( tr( "Use SALOME Style" ), this );
502   QFrame* fr = new QFrame( this );
503   fr->setFrameStyle( QFrame::Box | QFrame::Sunken );
504
505   main->addWidget( myStyleCheck );
506   main->addWidget( fr );
507
508   // create editor widgets
509   myStylesList = new QListWidget( fr );
510   myStylesTab  = new QTabWidget( fr );
511
512   QHBoxLayout* frLayout = new QHBoxLayout( fr );
513   frLayout->setMargin( MARGIN ); frLayout->setSpacing( SPACING );
514   frLayout->addWidget( myStylesList );
515   frLayout->addWidget( myStylesTab );
516   frLayout->setStretchFactor( myStylesList, 1 );
517   frLayout->setStretchFactor( myStylesTab, 2 );
518
519   // ...
520   QWidget* w1 = new QWidget( myStylesTab );
521   QVBoxLayout* vLayout = new QVBoxLayout( w1 );
522   vLayout->setMargin( 0 ); vLayout->setSpacing( SPACING );
523
524   myPaletteEditor = new PaletteEditor( w1 );
525   vLayout->addWidget( myPaletteEditor );
526   vLayout->addStretch();
527
528   // ...
529   QWidget* w2 = new QWidget( myStylesTab );
530   vLayout = new QVBoxLayout( w2 );
531   vLayout->setMargin( MARGIN ); vLayout->setSpacing( SPACING );
532
533   QGroupBox* fontGroup = new QGroupBox( tr( "Font" ), w2 );
534   myFontEdit = new QtxFontEdit( fontGroup );
535
536   QHBoxLayout* fontLayout = new QHBoxLayout( fontGroup );
537   fontLayout->setMargin( MARGIN ); fontLayout->setSpacing( SPACING );
538   fontLayout->addWidget( myFontEdit );
539
540   QGroupBox* linesGroup = new QGroupBox( tr( "Lines" ), w2 );
541   QLabel* linesTypeLab = new QLabel( tr( "Type" ), linesGroup );
542   myLinesCombo  = new QComboBox( linesGroup );
543   myLinesCombo->addItem( tr( "None" ),       Style_Model::NoLines );
544   myLinesCombo->addItem( tr( "Horizontal" ), Style_Model::Horizontal );
545   myLinesCombo->addItem( tr( "Inclined" ),   Style_Model::Inclined );
546   QLabel* linesTranspLab = new QLabel( tr( "Transparency" ), linesGroup );
547   myLinesTransparency = new QSlider( Qt::Horizontal, linesGroup );
548   myLinesTransparency->setMinimum( 0 );
549   myLinesTransparency->setMaximum( 100 );
550   myLinesTransparency->setSingleStep( 1 );
551   myLinesTransparency->setTracking( false );
552
553   QHBoxLayout* linesLayout = new QHBoxLayout( linesGroup );
554   linesLayout->setMargin( MARGIN ); linesLayout->setSpacing( SPACING );
555   linesLayout->addWidget( linesTypeLab );
556   linesLayout->addWidget( myLinesCombo );
557   linesLayout->addWidget( linesTranspLab );
558   linesLayout->addWidget( myLinesTransparency );
559
560   QGroupBox* roundGroup = new QGroupBox( tr( "Widgets rounding" ), w2 );
561   QLabel* roundButtonLab = new QLabel( tr( "Buttons" ), roundGroup );
562   myButtonRound = new QtxDoubleSpinBox( roundGroup );
563   QLabel* roundEditLab = new QLabel( tr( "Edit boxes" ), roundGroup );
564   myEditRound = new QtxDoubleSpinBox( roundGroup );
565   QLabel* roundFrameLab = new QLabel( tr( "Frames" ), roundGroup );
566   myFrameRound = new QtxDoubleSpinBox( roundGroup );
567   QLabel* roundSliderLab = new QLabel( tr( "Sliders" ), roundGroup );
568   mySliderRound = new QtxDoubleSpinBox( roundGroup );
569   myAntiAliasing = new QCheckBox( tr( "Anti-aliased borders" ), roundGroup );
570
571   QGridLayout* roundLayout = new QGridLayout( roundGroup );
572   roundLayout->setMargin( MARGIN ); roundLayout->setSpacing( SPACING );
573   roundLayout->addWidget( roundButtonLab, 0, 0 );
574   roundLayout->addWidget( myButtonRound,  0, 1 );
575   roundLayout->addWidget( roundEditLab,   0, 2 );
576   roundLayout->addWidget( myEditRound,    0, 3 );
577   roundLayout->addWidget( roundFrameLab,  1, 0 );
578   roundLayout->addWidget( myFrameRound,   1, 1 );
579   roundLayout->addWidget( roundSliderLab, 1, 2 );
580   roundLayout->addWidget( mySliderRound,  1, 3 );
581   roundLayout->addWidget( myAntiAliasing, 2, 0, 1, 4 );
582   
583   QGroupBox* handleGroup       = new QGroupBox( tr( "Handle" ), w2 );
584   QLabel*    horHandleLab      = new QLabel( tr( "Horizontal spacing" ), handleGroup );
585   myHorHandleDelta  = new QSpinBox( handleGroup );
586   QLabel*    verHandleLab      = new QLabel( tr( "Vertical spacing" ), handleGroup );
587   myVerHandleDelta  = new QSpinBox( handleGroup );
588   QLabel*    splitterLengthLab = new QLabel( tr( "Splitter handle size" ), handleGroup );
589   mySplitterLength  = new QSpinBox( handleGroup );
590   QLabel*    sliderLengthLab   = new QLabel( tr( "Slider handle size" ), handleGroup );
591   mySliderSize      = new QSpinBox( handleGroup );
592   
593   QGridLayout* handleLayout = new QGridLayout( handleGroup );
594   handleLayout->setMargin( MARGIN ); handleLayout->setSpacing( SPACING );
595   handleLayout->addWidget( horHandleLab,      0, 0 );
596   handleLayout->addWidget( myHorHandleDelta,  0, 1 );
597   handleLayout->addWidget( verHandleLab,      0, 2);
598   handleLayout->addWidget( myVerHandleDelta,  0, 3 );
599   handleLayout->addWidget( splitterLengthLab, 1, 0 );
600   handleLayout->addWidget( mySplitterLength,  1, 1 );
601   handleLayout->addWidget( sliderLengthLab,   1, 2 );
602   handleLayout->addWidget( mySliderSize,      1, 3 );
603
604   QGroupBox* effectGroup = new QGroupBox( tr( "Widget effect" ), w2 );
605   myEffectNone      = new QRadioButton( tr( "None" ),               effectGroup );
606   myEffectHighlight = new QRadioButton( tr( "Highlight widgets" ),  effectGroup );
607   myEffectAutoRaise = new QRadioButton( tr( "Auto raise widgets" ), effectGroup );
608   QButtonGroup* aGroup = new QButtonGroup( w2 );
609   aGroup->addButton( myEffectNone );
610   aGroup->addButton( myEffectHighlight );
611   aGroup->addButton( myEffectAutoRaise );
612   myEffectNone->setChecked( true );
613   myCurrentEffect = myEffectNone;
614
615   QHBoxLayout* effectLayout = new QHBoxLayout( effectGroup );
616   effectLayout->setMargin( MARGIN ); effectLayout->setSpacing( SPACING );
617   effectLayout->addWidget( myEffectNone );
618   effectLayout->addWidget( myEffectHighlight );
619   effectLayout->addWidget( myEffectAutoRaise );
620
621   vLayout->addWidget( fontGroup );
622   vLayout->addWidget( linesGroup );
623   vLayout->addWidget( roundGroup );
624   vLayout->addWidget( handleGroup );
625   vLayout->addWidget( effectGroup );
626   vLayout->addStretch();
627
628   // ...
629   myStylesTab->addTab( w1, tr( "Colors" )  );
630   myStylesTab->addTab( w2, tr( "Properties" )  );
631
632   // initialize dialog box
633   setFocusProxy( fr );
634   setButtonPosition( Right, Close );
635   setDialogFlags( AlignOnce );
636   myStylesList->setEditTriggers( QAbstractItemView::EditKeyPressed );
637
638   QStringList globalStyles = resourceMgr()->styles( Style_ResourceMgr::Global );
639   QStringList userStyles   = resourceMgr()->styles( Style_ResourceMgr::User );
640
641   QListWidgetItem* item;
642
643   // current style
644   item = new QListWidgetItem( tr( "[ Current ]" ) );
645   item->setForeground( QColor( Qt::red ) );
646   item->setData( TypeRole, QVariant( Current ) );
647   myStylesList->addItem( item );
648   // default style
649   item = new QListWidgetItem( tr( "[ Default ]" ) );
650   item->setForeground( QColor( Qt::green ) );
651   item->setData( TypeRole, QVariant( Default ) );
652   myStylesList->addItem( item );
653   // global styles
654   foreach ( QString sname, globalStyles ) {
655     item = new QListWidgetItem( sname );
656     item->setForeground( QColor( Qt::blue ) );
657     item->setData( TypeRole, QVariant( Global ) );
658     item->setData( NameRole, QVariant( sname ) );
659     myStylesList->addItem( item );
660   }
661   // user styles
662   foreach ( QString sname, userStyles ) {
663     item = new QListWidgetItem( sname );
664     item->setData( TypeRole, QVariant( User ) );
665     item->setData( NameRole, QVariant( sname ) );
666     item->setFlags( item->flags() | Qt::ItemIsEditable );
667     myStylesList->addItem( item );
668   }
669   
670   // connect widgets
671   connect( myStyleCheck,        SIGNAL( toggled( bool ) ),        fr,   SLOT( setEnabled( bool ) ) );
672   connect( myStylesList,        SIGNAL( itemSelectionChanged() ), this, SLOT( onStyleChanged() ) );
673   connect( myStylesList,        SIGNAL( itemChanged( QListWidgetItem* ) ),       
674            this, SLOT( onItemChanged( QListWidgetItem* ) ) );
675   connect( myStylesList,        SIGNAL( itemDoubleClicked( QListWidgetItem* ) ), 
676            this, SLOT( onApply() ) );
677   connect( myLinesCombo,        SIGNAL( activated( int ) ),       this, SLOT( onLinesType() ) );
678   connect( myPaletteEditor,     SIGNAL( changed() ),              this, SIGNAL( styleChanged() ) );
679   connect( myFontEdit,          SIGNAL( changed( QFont ) ),       this, SIGNAL( styleChanged() ) );
680   connect( myLinesTransparency, SIGNAL( valueChanged( int ) ),    this, SIGNAL( styleChanged() ) );
681   connect( myButtonRound,       SIGNAL( valueChanged( double ) ), this, SIGNAL( styleChanged() ) );
682   connect( myEditRound,         SIGNAL( valueChanged( double ) ), this, SIGNAL( styleChanged() ) );
683   connect( myFrameRound,        SIGNAL( valueChanged( double ) ), this, SIGNAL( styleChanged() ) );
684   connect( mySliderRound,       SIGNAL( valueChanged( double ) ), this, SIGNAL( styleChanged() ) );
685   connect( myAntiAliasing,      SIGNAL( toggled( bool ) ),        this, SIGNAL( styleChanged() ) );
686   connect( myHorHandleDelta,    SIGNAL( valueChanged( int ) ),    this, SIGNAL( styleChanged() ) );
687   connect( myVerHandleDelta,    SIGNAL( valueChanged( int ) ),    this, SIGNAL( styleChanged() ) );
688   connect( mySplitterLength,    SIGNAL( valueChanged( int ) ),    this, SIGNAL( styleChanged() ) );
689   connect( mySliderSize,        SIGNAL( valueChanged( int ) ),    this, SIGNAL( styleChanged() ) );
690   connect( aGroup,              SIGNAL( buttonClicked( QAbstractButton* ) ),
691            this, SLOT( onEffectChanged( QAbstractButton* ) ) );
692   connect( this,                SIGNAL( styleChanged() ),         this, SLOT( onChanged() ) );
693   
694   connect( this, SIGNAL( dlgApply() ), this, SLOT( onApply() ) );
695   connect( this, SIGNAL( dlgHelp() ),  this, SLOT( onHelp() ) );
696
697   myStylesList->setCurrentRow( 0 );
698   
699   myStyleCheck->setChecked( Style_Salome::isActive() );
700   fr->setEnabled( Style_Salome::isActive() );
701 }
702
703 /*!
704   \brief Destructor
705 */
706 Style_PrefDlg::~Style_PrefDlg()
707 {
708 }
709
710 /*!
711   \brief Called when "OK" button is clicked
712 */
713 void Style_PrefDlg::accept()
714 {
715   onApply();
716   QtxDialog::accept();
717 }
718
719 /*!
720   \brief Process key press event
721   \param e key event
722 */
723 void Style_PrefDlg::keyPressEvent( QKeyEvent* e )
724 {
725   if ( e->key() == Qt::Key_Delete ) {
726     QListWidgetItem* item = myStylesList->currentItem();
727     if ( item && item->data( TypeRole ).toInt() == User ) {
728       if ( QMessageBox::question( this,
729                                   tr( "Delete user theme" ),
730                                   tr( "Remove theme %1?" ).arg( item->text() ),
731                                   QMessageBox::Yes | QMessageBox::No,
732                                   QMessageBox::Yes ) == QMessageBox::Yes ) {
733         resourceMgr()->remove( item->data( NameRole ).toString() );
734         resourceMgr()->save();
735         delete item;
736       }
737     }
738   }
739   QtxDialog::keyPressEvent( e );
740 }
741
742 /*!
743   \brief Get SALOME themes resource manager
744   \return themes resource manager
745 */
746 Style_ResourceMgr* Style_PrefDlg::resourceMgr()
747 {
748   if ( !myResMgr )
749     myResMgr = new Style_ResourceMgr();
750   return myResMgr;
751 }
752
753 /*!
754   \brief Initialize dialog box fields from SALOME style model
755   \param model style model
756 */
757 void Style_PrefDlg::fromModel( Style_Model* model )
758 {
759   if ( !model ) return;
760   
761   // colors
762   for ( int i = (int)Style_Model::WindowText; i < (int)Style_Model::LastColor; i++ ) {
763     if ( i == Style_Model::NoRole ) continue;
764     myPaletteEditor->setColor( i, QPalette::Active,   model->color( (Style_Model::ColorRole)i, QPalette::Active ) );
765     myPaletteEditor->setColor( i, QPalette::Inactive, model->color( (Style_Model::ColorRole)i, QPalette::Inactive ) );
766     myPaletteEditor->setColor( i, QPalette::Disabled, model->color( (Style_Model::ColorRole)i, QPalette::Disabled ) );
767   }
768   myPaletteEditor->setAuto( model->isAutoPalette() );
769   // font
770   myFontEdit->setCurrentFont( model->applicationFont() );
771   // lines type
772   int idx = myLinesCombo->findData( QVariant( model->linesType() ) );
773   if ( idx >= 0 ) myLinesCombo->setCurrentIndex( idx );
774   // lines transparency
775   myLinesTransparency->setValue( model->linesTransparency() );
776   // widgets rounding
777   myButtonRound->setValue( model->widgetRounding( Style_Model::ButtonRadius ) );
778   myEditRound->setValue( model->widgetRounding( Style_Model::EditRadius ) );
779   myFrameRound->setValue( model->widgetRounding( Style_Model::FrameRadius ) );
780   mySliderRound->setValue( model->widgetRounding( Style_Model::SliderRadius ) );
781   // widgets antialiasing
782   myAntiAliasing->setChecked( model->antialiasing() );
783   // handle delta
784   myHorHandleDelta->setValue( model->handleDelta( Qt::Horizontal ) );
785   myVerHandleDelta->setValue( model->handleDelta( Qt::Vertical ) );
786   // splitter handle lentgh
787   mySplitterLength->setValue( model->splitHandleLength() );
788   // slider size
789   mySliderSize->setValue( model->sliderSize() );
790   // widgets effect
791   Style_Model::WidgetEffect we = model->widgetEffect();
792   if ( we == Style_Model::HighlightEffect ) myEffectHighlight->setChecked( true );
793   else if ( we == Style_Model::AutoRaiseEffect ) myEffectAutoRaise->setChecked( true );
794   else myEffectNone->setChecked( true );
795 }
796  
797 /*!
798   \brief Save values from dialog box fields to SALOME style model
799   \param model style model
800 */
801 void Style_PrefDlg::toModel( Style_Model* model ) const
802 {
803   if ( !model ) return;
804   
805   // colors
806   // ... first set Button color 'cause it is used to calculate other ones
807   if ( myPaletteEditor->isAuto() )
808     model->setColor( Style_Model::Button,
809                      myPaletteEditor->color( Style_Model::Button, QPalette::Active ) );
810   else 
811     model->setColor( Style_Model::Button,
812                      myPaletteEditor->color( Style_Model::Button, QPalette::Active ),
813                      myPaletteEditor->color( Style_Model::Button, QPalette::Inactive ),
814                      myPaletteEditor->color( Style_Model::Button, QPalette::Disabled ));
815   // ... then set all other colors
816   for ( int i = (int)Style_Model::WindowText; i < (int)Style_Model::LastColor; i++ ) {
817     if ( i == Style_Model::NoRole ) continue; // not supported
818     if ( i == Style_Model::Button ) continue; // already set
819     if ( myPaletteEditor->isAuto() )
820       model->setColor( (Style_Model::ColorRole)i,
821                        myPaletteEditor->color( i, QPalette::Active ) );
822     else 
823       model->setColor( (Style_Model::ColorRole)i,
824                        myPaletteEditor->color( i, QPalette::Active ),
825                        myPaletteEditor->color( i, QPalette::Inactive ),
826                        myPaletteEditor->color( i, QPalette::Disabled ));
827   }
828   model->setAutoPalette( myPaletteEditor->isAuto() ); // internal
829   // font
830   model->setApplicationFont( myFontEdit->currentFont() );
831   // lines type
832   model->setLinesType( (Style_Model::LineType)myLinesCombo->itemData( myLinesCombo->currentIndex() ).toInt() );
833   // lines transparency
834   model->setLinesTransparency( myLinesTransparency->value() );
835   // widgets rounding
836   model->setWidgetRounding( Style_Model::ButtonRadius, myButtonRound->value() );
837   model->setWidgetRounding( Style_Model::EditRadius,   myEditRound->value() );
838   model->setWidgetRounding( Style_Model::FrameRadius,  myFrameRound->value() );
839   model->setWidgetRounding( Style_Model::SliderRadius, mySliderRound->value() );
840   // widgets antialiasing
841   model->setAntialiasing( myAntiAliasing->isChecked() );
842   // handle delta
843   model->setHandleDelta( Qt::Horizontal, myHorHandleDelta->value() );
844   model->setHandleDelta( Qt::Vertical,   myVerHandleDelta->value() );
845   // splitter handle lentgh
846   model->setSplitHandleLength( mySplitterLength->value() );
847   // slider size
848   model->setSliderSize( mySliderSize->value() );
849   // widgets effect
850   if      ( myEffectHighlight->isChecked() ) model->setWidgetEffect( Style_Model::HighlightEffect );
851   else if ( myEffectAutoRaise->isChecked() ) model->setWidgetEffect( Style_Model::AutoRaiseEffect );
852   else                                       model->setWidgetEffect( Style_Model::NoEffect );
853 }
854
855 /*!
856   \brief Find unique name for the theme name
857   \param name theme name template
858   \param item if not 0, used to be ignored when browsing through items list
859   \param addSuffix if \c true, the integrer suffix is always added to the theme name (otherwise
860   suffix is added only if item name is not unique)
861   \return new unique theme name
862 */
863 QString Style_PrefDlg::findUniqueName( const QString& name, QListWidgetItem* item, bool addSuffix )
864 {
865   bool found = false;
866   int idx = 0;
867   for( int i = 2; i < myStylesList->count(); i++ ) {
868     if ( item == myStylesList->item( i ) ) continue;
869     QString iname = myStylesList->item( i )->text();
870     if ( iname == name ) {
871       found = true;
872     }
873     else {
874       iname = iname.mid( name.length() ).trimmed();
875       bool ok = false;
876       int nx = iname.toInt( &ok );
877       if ( ok ) idx = qMax( idx, nx );
878     }
879   }
880   return found || addSuffix ? QString( "%1 %2" ).arg( name ).arg( idx+1 ) : name;
881 }
882
883 /*!
884   \brief Called when "Apply" button is pressed
885 */
886 void Style_PrefDlg::onApply()
887 {
888   // save user schemas
889   resourceMgr()->save();
890   // set selected schema as current
891   if ( myStylesList->currentRow() >= 0 ) {
892     Style_Model* model = Style_Salome::model();
893     toModel( model );
894     model->save();
895     Style_Salome::update();
896     if ( myStyleCheck->isChecked() )
897       Style_Salome::apply();
898     else
899       Style_Salome::restore();
900   }
901 }
902
903 /*!
904   \brief Called when "Help" button is pressed
905 */
906 void Style_PrefDlg::onHelp()
907 {
908 }
909
910 /*!
911   \brief Called when user selects any theme item in the themes list
912 */
913 void Style_PrefDlg::onStyleChanged()
914 {
915   blockSignals( true );
916
917   QListWidgetItem* item = myStylesList->currentItem();
918   int type = item->data( TypeRole ).toInt();
919
920   Style_Model* model = 0;
921
922   switch ( type ) {
923   case Current:
924     // current style
925     model = Style_Salome::model();
926     break;
927   case Default:
928     // default style
929     model = new Style_Model();
930     break;
931   case Global:
932   case User:
933     // global style, user style
934     model = new Style_Model();
935     model->fromResources( resourceMgr(), item->data( NameRole ).toString() );
936     break;
937   default:
938     break;
939   }
940
941   fromModel( model );
942   if ( type != Current )
943     delete model;
944
945   onLinesType();
946
947   blockSignals( false );
948 }
949
950 /*!
951   \brief Called when lines type is changed
952 */
953 void Style_PrefDlg::onLinesType()
954 {
955   myLinesTransparency->setEnabled( myLinesCombo->itemData( myLinesCombo->currentIndex() ) != Style_Model::NoLines );
956   emit( styleChanged() );
957 }
958
959 /*!
960   \brief Called when any style parameter is changed by the user
961 */
962 void Style_PrefDlg::onChanged()
963 {
964   QListWidgetItem* item = myStylesList->currentItem();
965   int type = item->data( TypeRole ).toInt();
966
967   // for the current and user schemas do not perform any actions
968   if ( type == Current ) {
969     Style_Model model = *( Style_Salome::model() );
970     toModel( &model );
971     model.save();
972     blockSignals( true );
973     fromModel( &model );
974     blockSignals( false );
975   }
976   else if ( type == User ) {
977     Style_Model model;
978     toModel( &model );
979     QString oldName = item->data( NameRole ).toString(), newName = item->text();
980     if ( oldName == newName ) {
981       model.save( resourceMgr(), oldName );
982     }
983     else {
984       resourceMgr()->remove( oldName );
985       model.save( resourceMgr(), newName );
986       item->setData( NameRole, newName );
987     }
988     blockSignals( true );
989     fromModel( &model );
990     blockSignals( false );
991   }
992   else {
993     // if user tries to change global (or default) schema, we create new user schema basing on selected one
994     QString newName = findUniqueName( tr( "Custom schema" ), 0, true );
995     item = new QListWidgetItem( newName );
996     item->setData( TypeRole, QVariant( User ) );
997     item->setData( NameRole, QVariant( newName ) );
998     item->setFlags( item->flags() | Qt::ItemIsEditable );
999     myStylesList->addItem( item );
1000     
1001     Style_Model model;
1002     toModel( &model );
1003     model.save( resourceMgr(), newName );
1004     
1005     myStylesList->setCurrentItem( item );
1006   }
1007 }
1008
1009 /*!
1010   \brief Called when user theme is renamed by the user
1011 */
1012 void Style_PrefDlg::onItemChanged( QListWidgetItem* item )
1013 {
1014   QString newName = item->text();
1015   QString uniqueName = findUniqueName( newName, item );
1016   if ( uniqueName != newName ) {
1017     myStylesList->blockSignals( true );
1018     item->setText( uniqueName );
1019     myStylesList->blockSignals( false );
1020   }
1021   onChanged();
1022 }                               
1023
1024 /*!
1025   \brief Called when widget effect is changed
1026 */
1027 void Style_PrefDlg::onEffectChanged( QAbstractButton* rb )
1028 {
1029   if ( rb != myCurrentEffect )
1030     emit( styleChanged() );
1031   myCurrentEffect = qobject_cast<QRadioButton*>( rb );
1032 }