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