67fff81f73205a750094e785814cbf4d6591d585
[occt.git] / tools / ViewControl / ViewControl_ColorSelector.cxx
1 // Created on: 2021-04-27
2 // Created by: Natalia ERMOLAEVA
3 // Copyright (c) 2021 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement. 
15
16 #include <inspector/ViewControl_ColorSelector.hxx>
17 #include <inspector/ViewControl_TableItemDelegate.hxx>
18 #include <inspector/ViewControl_TableModel.hxx>
19 #include <inspector/ViewControl_TableModelValues.hxx>
20 #include <inspector/ViewControl_Tools.hxx>
21 #include <inspector/TreeModel_Tools.hxx>
22
23 #include <Standard_Dump.hxx>
24
25 #include <Standard_WarningsDisable.hxx>
26 #include <QAbstractTableModel>
27 #include <QDialogButtonBox>
28 #include <QHeaderView>
29 #include <QGridLayout>
30 #include <QItemSelectionModel>
31 #include <QPainter>
32 #include <QPushButton>
33 #include <QTableView>
34 #include <QWidget>
35 #include <Standard_WarningsRestore.hxx>
36
37 //! Kinds of delegate cell in OCCT Color model to present a custom presentation (rect bounded by a colored frame)
38 enum ViewControl_ColorDelegateKind
39 {
40   ViewControl_ColorDelegateKind_None, //!< usual item
41   ViewControl_ColorDelegateKind_Activated, //!< active item
42   ViewControl_ColorDelegateKind_Highlighted, //!< highlighted item
43   ViewControl_ColorDelegateKind_Selected //!< selected item
44 };
45
46 //! Model for a table of parameters: Current Color, Red, Green, Blue, Alpha, OCCT color name
47 class ViewControl_ParametersModel : public ViewControl_TableModelValues
48 {
49 public:
50   ViewControl_ParametersModel (ViewControl_ColorSelector* theSelector)
51     : ViewControl_TableModelValues(), mySelector (theSelector) {}
52   virtual ~ViewControl_ParametersModel() {}
53
54   //! Inits model by the parameter color
55   //! \param theColor model active color
56   void SetColor (const Quantity_ColorRGBA& theColor, ViewControl_TableModel* theModel)
57   { myColor = theColor; theModel->EmitLayoutChanged(); }
58
59   //! Returns current selected color
60   //! \return color value
61   Quantity_ColorRGBA GetColor() const { return myColor; }
62
63   //! Returns item information(short) for display role.
64   //! \param theIndex a model index
65   //! \param theRole a view role
66   //! \return value intepreted depending on the given role
67   Standard_EXPORT virtual QVariant Data (const int theRow, const int theColumn,
68                                          int theRole = Qt::DisplayRole) const Standard_OVERRIDE
69   {
70     //(void)theRow; (void)theColumn; (void) theRole;
71     if (theRole == Qt::BackgroundRole && theColumn == 1 && theRow == 0)
72       return ViewControl_ColorSelector::ColorToQColor (myColor);
73
74     if (theRole == Qt::ForegroundRole && theColumn == 1 && theRow >= 2 && theRow <= 5)
75       return ViewControl_TableModelValues::EditCellColor();
76
77     if (theRole != Qt::DisplayRole)
78     return QVariant();
79
80     bool isFirstColumn = theColumn == 0;
81     switch (theRow)
82     {
83       case 0: return isFirstColumn ? QVariant ("Color") : QVariant ();
84       case 1:
85       {
86         if (isFirstColumn)
87           return QVariant ("Name");
88         Quantity_NameOfColor aColorName;
89         if (ViewControl_ColorSelector::IsExactColorName(myColor, aColorName))
90           return Quantity_Color::StringName(aColorName);
91       }
92       break;
93       case 2: return isFirstColumn ? QVariant ("Red") : ViewControl_Tools::ToVariant (myColor.GetRGB().Red());
94       case 3: return isFirstColumn ? QVariant ("Green") : ViewControl_Tools::ToVariant (myColor.GetRGB().Green());
95       case 4: return isFirstColumn ? QVariant ("Blue") : ViewControl_Tools::ToVariant (myColor.GetRGB().Blue());
96       case 5: return isFirstColumn ? QVariant ("Alpha") : ViewControl_Tools::ToVariant (myColor.Alpha());
97       case 6: return isFirstColumn ? QVariant ("Near Name") 
98                                    : Quantity_Color::StringName(myColor.GetRGB().Name());
99     }
100     return QVariant();
101   }
102
103   //! Sets content of the model index for the given role, it is applyed to internal container of values
104   //! \param theRow a model index row
105   //! \param theColumn a model index column
106   //! \param theRole a view role
107   //! \return true if the value is changed
108   virtual bool SetData (const int theRow, const int theColumn, const QVariant& theValue, int)
109   {
110     if (theColumn != 1 || theRow < 2 || theRow > 5)
111       return false;
112
113     switch (theRow)
114     {
115       case 2:
116       case 3:
117       case 4:
118       {
119         myColor.ChangeRGB().SetValues (theRow == 2 ? ViewControl_Tools::ToShortRealValue (theValue) : myColor.GetRGB().Red(),
120                                        theRow == 3 ? ViewControl_Tools::ToShortRealValue (theValue) : myColor.GetRGB().Green(),
121                                        theRow == 4 ? ViewControl_Tools::ToShortRealValue (theValue) : myColor.GetRGB().Blue(),
122                                        Quantity_TOC_RGB);
123       }
124       break;
125       case 5: myColor.SetAlpha (ViewControl_Tools::ToShortRealValue (theValue)); break;
126     }
127     mySelector->ParameterColorChanged();
128     return true;
129   }
130
131   //! Returns number of tree level line items = colums in table view
132   virtual int ColumnCount (const QModelIndex& theParent = QModelIndex()) const Standard_OVERRIDE
133   { (void)theParent; return 2; }
134
135   //! Returns onlly one row in table view
136   virtual int RowCount (const QModelIndex& theParent = QModelIndex()) const Standard_OVERRIDE
137   { (void)theParent; return 7; }
138
139   //! Returns editable flag for color RGB and alpha rows
140   //! \return flags
141   Qt::ItemFlags Flags (const QModelIndex& theIndex) const
142   {
143     Qt::ItemFlags aFlags = ViewControl_TableModelValues::Flags (theIndex);
144
145     if (theIndex.column() == 1 && theIndex.row() >= 2 && theIndex.row() <= 5)
146       aFlags = aFlags | Qt::ItemIsEditable;
147
148     return aFlags;
149   }
150
151   //! Returns type of edit control for the model index. By default, it is an empty control
152   //! \param theRow a model index row
153   //! \param theColumn a model index column
154   //! \return edit type
155   virtual ViewControl_EditType GetEditType (const int theRow, const int theColumn) const
156   {
157     if (theColumn == 1 && theRow >= 2 && theRow <= 5)
158       return ViewControl_EditType_Double;
159
160     return ViewControl_EditType_None;
161   }
162
163 private:
164   Quantity_ColorRGBA myColor;
165   ViewControl_ColorSelector* mySelector;
166 };
167
168 //! Table of parameters: Red, Green, Blue, Alpha, OCCT color name
169 class ViewControl_OCCTColorModel : public QAbstractTableModel
170 {
171 public:
172   ViewControl_OCCTColorModel (QObject* theParent)
173     : QAbstractTableModel (theParent), myCurrentIndexKind (ViewControl_ColorDelegateKind_None) {}
174   virtual ~ViewControl_OCCTColorModel() {}
175
176   //! Sets current color, that should have custom presented
177   //! \param theColor current color
178   //! \param theKind presentation kind
179   void SetColor (const Quantity_NameOfColor& theColor, const ViewControl_ColorDelegateKind theKind)
180   {
181     int aColorPosition = (int)theColor;
182     int aRow = (int) (aColorPosition / columnCount());
183     int aColumn = aColorPosition - aRow * columnCount();
184     myCurrentIndex = index (aRow, aColumn);
185     myCurrentIndexKind = theKind;
186
187     emit layoutChanged();
188   }
189
190   //! Returns OCCT name of color if index position does not exceed Quantity_NameOfColor elements
191   //! \param theIndex model index
192   //! \param theNameOfColor [out] OCCT color name
193   //! \return true if the color is found
194   bool GetOCCTColor (const QModelIndex& theIndex, Quantity_NameOfColor& theNameOfColor) const
195   {
196     int aNameOfColorId = theIndex.row() * columnCount() + theIndex.column();
197     if (aNameOfColorId > Quantity_NOC_WHITE)
198       return false;
199     theNameOfColor = (Quantity_NameOfColor)aNameOfColorId;
200     return true;
201   }
202
203   //! Returns index that has custom presentation
204   //! \return model index
205   QModelIndex GetCurrentIndex() const { return myCurrentIndex; }
206
207   //! Returns index color kind that has custom presentation
208   //! \return kind
209   ViewControl_ColorDelegateKind GetCurrentIndexKind() const { return myCurrentIndexKind; }
210
211   //! Returns item information(short) for display role.
212   //! \param theIndex a model index
213   //! \param theRole a view role
214   //! \return value intepreted depending on the given role
215   Standard_EXPORT virtual QVariant data (const QModelIndex& theIndex,
216                                          int theRole = Qt::DisplayRole) const Standard_OVERRIDE
217   {
218     if (theRole != Qt::ToolTipRole) // background is processed in table item delegate
219       return QVariant();
220
221     Quantity_NameOfColor aNameOfColor;
222     if (!GetOCCTColor (theIndex, aNameOfColor))
223       return QVariant();
224
225     if (theRole == Qt::ToolTipRole)
226       return QString("%1").arg (ViewControl_ColorSelector::ColorToString (Quantity_Color (aNameOfColor)));
227     return QVariant();
228   }
229
230   //! Returns number of tree level line items = colums in table view
231   virtual int columnCount (const QModelIndex& theParent = QModelIndex()) const Standard_OVERRIDE
232   { (void)theParent; return 26; }
233
234   //! Returns onlly one row in table view
235   virtual int rowCount (const QModelIndex& theParent = QModelIndex()) const Standard_OVERRIDE
236   { (void)theParent; return 20; }
237
238   //! Returns color for the delegate kind
239   //! \param theKind kind
240   //! \return color
241   static QColor GetKindColor (const ViewControl_ColorDelegateKind theKind)
242   {
243     switch (theKind)
244     {
245       case ViewControl_ColorDelegateKind_Activated:
246       case ViewControl_ColorDelegateKind_Highlighted: return Qt::blue;
247       case ViewControl_ColorDelegateKind_Selected: return Qt::black;
248       default: break;
249     }
250     return QColor();
251   }
252
253 private:
254   QModelIndex myCurrentIndex; //!< index to be presented through item delegate
255   ViewControl_ColorDelegateKind myCurrentIndexKind; //!< kind of custom item
256 };
257
258 //! \class DFBrowser_HighlightDelegate
259 //! \brief An item delegate to paint in highlight color the cell when the mouse cursor is over it
260 class ViewControl_OCCTColorDelegate : public QItemDelegate
261 {
262 public:
263
264   //! Constructor
265   ViewControl_OCCTColorDelegate (QObject* theParent = 0) : QItemDelegate (theParent) {}
266
267   //! Destructor
268   virtual ~ViewControl_OCCTColorDelegate() Standard_OVERRIDE {}
269
270   //! Redefine of the parent virtual method to color the cell rectangle in highlight style
271   //! \param thePainter a painter
272   //! \param theOption a paint options
273   //! \param theIndex a view index
274   virtual void paint (QPainter* thePainter, const QStyleOptionViewItem& theOption,
275                       const QModelIndex& theIndex) const Standard_OVERRIDE
276   {
277     QRect aBaseRect = theOption.rect;
278     int aNameOfColorId = theIndex.row() * theIndex.model()->columnCount(theIndex) + theIndex.column();
279     Quantity_NameOfColor aNameOfColor = Quantity_NOC_WHITE;
280     if (aNameOfColorId < (int)Quantity_NOC_WHITE)
281       aNameOfColor = (Quantity_NameOfColor)aNameOfColorId;
282
283     Quantity_Color anOCCTColor (aNameOfColor);
284     QColor aQColor = ViewControl_ColorSelector::ColorToQColor (Quantity_ColorRGBA (anOCCTColor));
285     thePainter->fillRect (aBaseRect, aQColor);
286
287     QColor aColor;
288     // highlight cell
289     if (theOption.state & QStyle::State_MouseOver)
290       aColor = ViewControl_OCCTColorModel::GetKindColor (ViewControl_ColorDelegateKind_Highlighted);
291     else
292     {
293       const ViewControl_OCCTColorModel* aTableModel = dynamic_cast<const ViewControl_OCCTColorModel*> (theIndex.model());
294       QModelIndex anIndex = aTableModel->GetCurrentIndex();
295       if (anIndex.isValid() && anIndex.row() == theIndex.row() && anIndex.column() == theIndex.column())
296         aColor = ViewControl_OCCTColorModel::GetKindColor (aTableModel->GetCurrentIndexKind());
297     }
298     
299     if (aColor.isValid())
300     {
301       int aRectSize = 2;
302       thePainter->fillRect (QRect (aBaseRect.topLeft(), QPoint (aBaseRect.bottomLeft().x() + aRectSize, aBaseRect.bottomLeft().y())),
303                             aColor);
304       thePainter->fillRect (QRect (QPoint (aBaseRect.topRight().x() - aRectSize, aBaseRect.topRight().y()), aBaseRect.bottomRight()),
305                             aColor);
306       thePainter->fillRect (QRect (QPoint (aBaseRect.topLeft().x() + aRectSize, aBaseRect.topLeft().y()),
307                                    QPoint (aBaseRect.topRight().x() - aRectSize, aBaseRect.topRight().y() + aRectSize)),
308                             aColor);
309       thePainter->fillRect (QRect (QPoint (aBaseRect.bottomLeft().x() + aRectSize, aBaseRect.bottomLeft().y() - aRectSize),
310                                    QPoint (aBaseRect.bottomRight().x() - aRectSize, aBaseRect.bottomRight().y())),
311                             aColor);
312     }
313   }
314 };
315
316 //! Color picker class
317 class ViewControl_ColorPicker : public QWidget
318 {
319 public:
320   ViewControl_ColorPicker (QWidget* theParent) : QWidget (theParent) {}
321   virtual ~ViewControl_ColorPicker() {}
322 };
323
324 // =======================================================================
325 // function : Constructor
326 // purpose :
327 // =======================================================================
328 ViewControl_ColorSelector::ViewControl_ColorSelector (QWidget* theParent)
329 : QDialog (theParent)
330 {
331   QGridLayout* aLayout = new QGridLayout (this);
332   aLayout->setContentsMargins (0, 0, 0, 0);
333
334   myParameters = new QTableView (this);
335   ViewControl_TableModel* aTableModel = new ViewControl_TableModel (myParameters);
336   aTableModel->SetModelValues (new ViewControl_ParametersModel (this));
337   myParameters->setModel(aTableModel);
338
339   ViewControl_TableItemDelegate* anItemDelegate = new ViewControl_TableItemDelegate();
340   anItemDelegate->SetModelValues (aTableModel->ModelValues());
341   myParameters->setItemDelegate(anItemDelegate);
342
343   myParameters->verticalHeader()->setDefaultSectionSize (myParameters->verticalHeader()->minimumSectionSize());
344   myParameters->verticalHeader()->setVisible (false);
345   myParameters->horizontalHeader()->setVisible (false);
346   myParameters->setMinimumHeight (myParameters->verticalHeader()->minimumSectionSize() * aTableModel->rowCount() +
347                                   TreeModel_Tools::HeaderSectionMargin());
348
349   QItemSelectionModel* aSelectionModel = new QItemSelectionModel (myParameters->model());
350   myParameters->setSelectionMode (QAbstractItemView::SingleSelection);
351   myParameters->setSelectionModel (aSelectionModel);
352
353   aLayout->addWidget (myParameters, 0, 0);
354
355   myColorPicker = new ViewControl_ColorPicker (this);
356   aLayout->addWidget (myColorPicker, 0, 1);
357
358   myOCCTColors = new QTableView (this);
359   myOCCTColors->setFixedSize (525, 405);
360   myOCCTColors->verticalHeader()->setDefaultSectionSize (20);
361   myOCCTColors->verticalHeader()->setVisible (false);
362   myOCCTColors->horizontalHeader()->setDefaultSectionSize (20);
363   myOCCTColors->horizontalHeader()->setVisible (false);
364   myOCCTColors->setModel(new ViewControl_OCCTColorModel(myOCCTColors));
365
366   myOCCTColors->viewport()->setAttribute (Qt::WA_Hover);
367   myOCCTColors->setItemDelegate (new ViewControl_OCCTColorDelegate (myOCCTColors));
368
369   aSelectionModel = new QItemSelectionModel (myOCCTColors->model());
370   myOCCTColors->setSelectionMode (QAbstractItemView::SingleSelection);
371   myOCCTColors->setSelectionModel (aSelectionModel);
372   connect (aSelectionModel, SIGNAL (selectionChanged (const QItemSelection&, const QItemSelection&)),
373           this, SLOT (onOCCTColorsTableSelectionChanged (const QItemSelection&, const QItemSelection&)));
374   aLayout->addWidget (myOCCTColors, 1, 0, 1, 2);
375
376   QWidget* aBtnWidget = new QWidget (this);
377   aLayout->addWidget (aBtnWidget, 2, 0, 1, 2);
378
379   QHBoxLayout* aBtnLayout = new QHBoxLayout (aBtnWidget);
380   myOkButton = new QPushButton ("Ok", aBtnWidget);
381   myCancelButton = new QPushButton ("Cancel", aBtnWidget);
382   connect (myOkButton, SIGNAL (clicked()), this, SLOT (accept()));
383   connect (myCancelButton, SIGNAL (clicked()), this, SLOT (reject()));
384   aBtnLayout->addStretch ();
385   aBtnLayout->addWidget (myOkButton);
386   aBtnLayout->addWidget (myCancelButton);
387 }
388
389 // =======================================================================
390 // function : SetStreamValue
391 // purpose :
392 // =======================================================================
393 void ViewControl_ColorSelector::SetStreamValue (const QString& theValue)
394 {
395   Quantity_ColorRGBA aColor = StringToColorRGBA (theValue);
396   // parameters model
397   ViewControl_TableModel* aTableModel = dynamic_cast<ViewControl_TableModel*> (myParameters->model());
398   ViewControl_ParametersModel* aParametersModel = dynamic_cast<ViewControl_ParametersModel*> (aTableModel->ModelValues());
399   aParametersModel->SetColor (aColor, aTableModel);
400
401   // OCCT color model
402   Quantity_NameOfColor aColorName;
403   bool isExactColorName = ViewControl_ColorSelector::IsExactColorName(aColor, aColorName);
404   ViewControl_OCCTColorModel* anOCCTColorModel = dynamic_cast<ViewControl_OCCTColorModel*>(myOCCTColors->model());
405   anOCCTColorModel->SetColor (aColorName, isExactColorName ? ViewControl_ColorDelegateKind_Selected
406                                                            : ViewControl_ColorDelegateKind_Activated);
407 }
408
409 // =======================================================================
410 // function : GetStreamValue
411 // purpose :
412 // =======================================================================
413 QString ViewControl_ColorSelector::GetStreamValue() const
414 {
415   ViewControl_TableModel* aTableModel = dynamic_cast<ViewControl_TableModel*> (myParameters->model());
416   ViewControl_ParametersModel* aParametersModel = dynamic_cast<ViewControl_ParametersModel*> (aTableModel->ModelValues());
417
418   Quantity_ColorRGBA aColor = aParametersModel->GetColor();
419
420   Standard_SStream aStream;
421   aColor.DumpJson (aStream);
422
423   return Standard_Dump::Text (aStream).ToCString();
424 }
425
426 // =======================================================================
427 // function : ParameterColorChanged
428 // purpose :
429 // =======================================================================
430 void ViewControl_ColorSelector::ParameterColorChanged()
431 {
432   ViewControl_TableModel* aTableModel = dynamic_cast<ViewControl_TableModel*> (myParameters->model());
433   ViewControl_ParametersModel* aParametersModel = dynamic_cast<ViewControl_ParametersModel*> (aTableModel->ModelValues());
434   Quantity_ColorRGBA aColor = aParametersModel->GetColor();
435
436   // OCCT color model
437   Quantity_NameOfColor aColorName;
438   bool isExactColorName = ViewControl_ColorSelector::IsExactColorName(aColor, aColorName);
439   ViewControl_OCCTColorModel* anOCCTColorModel = dynamic_cast<ViewControl_OCCTColorModel*>(myOCCTColors->model());
440   anOCCTColorModel->SetColor (aColorName, isExactColorName ? ViewControl_ColorDelegateKind_Selected
441                                                            : ViewControl_ColorDelegateKind_Activated);
442 }
443
444 // =======================================================================
445 // function : ColorToString
446 // purpose :
447 // =======================================================================
448 QString ViewControl_ColorSelector::ColorToString (const Quantity_Color& theColor)
449 {
450   Standard_Real aRed, aGreen, aBlue;
451   theColor.Values (aRed, aGreen, aBlue, Quantity_TOC_RGB);
452   return QString::number (aRed) + ViewControl_ColorSelector::ColorSeparator() +
453          QString::number (aGreen) + ViewControl_ColorSelector::ColorSeparator() +
454          QString::number (aBlue);
455 }
456
457 // =======================================================================
458 // function : ColorToQColor
459 // purpose :
460 // =======================================================================
461 QColor ViewControl_ColorSelector::ColorToQColor (const Quantity_ColorRGBA& theColor)
462 {
463   int aDelta = 255;
464
465   Standard_Real aRed, aGreen, aBlue;
466   theColor.GetRGB().Values (aRed, aGreen, aBlue, Quantity_TOC_RGB);
467
468   return QColor((int)(aRed * aDelta), (int)(aGreen * aDelta), (int)(aBlue * aDelta));
469 }
470
471 // =======================================================================
472 // function : StringToColorRGBA
473 // purpose :
474 // =======================================================================
475 Quantity_ColorRGBA ViewControl_ColorSelector::StringToColorRGBA (const QString& theColor)
476 {
477   Quantity_ColorRGBA aColorRGBA;
478   Standard_SStream aStream;
479   aStream << theColor.toStdString();
480   int aStreamPos = 1;
481   aColorRGBA.InitFromJson (aStream, aStreamPos);
482   return aColorRGBA;
483 }
484
485 // =======================================================================
486 // function : IsExactColorName
487 // purpose :
488 // =======================================================================
489 Standard_Boolean ViewControl_ColorSelector::IsExactColorName (const Quantity_ColorRGBA& theColor,
490                                                               Quantity_NameOfColor& theColorName)
491 {
492   theColorName = theColor.GetRGB().Name();
493   return Quantity_Color (theColorName).IsEqual (theColor.GetRGB());
494 }
495
496 // =======================================================================
497 // function : onOCCTColorsTableSelectionChanged
498 // purpose :
499 // =======================================================================
500 void ViewControl_ColorSelector::onOCCTColorsTableSelectionChanged (const QItemSelection& theSelected, const QItemSelection&)
501 {
502   QModelIndexList aSelectedIndices = theSelected.indexes();
503   if (aSelectedIndices.size() != 1)
504     return;
505
506   ViewControl_OCCTColorModel* anOCCTColorModel = dynamic_cast<ViewControl_OCCTColorModel*>(myOCCTColors->model());
507   Quantity_NameOfColor aNameOfColor;
508   if (!anOCCTColorModel->GetOCCTColor (aSelectedIndices.first(), aNameOfColor))
509     return;
510
511   anOCCTColorModel->SetColor (aNameOfColor, ViewControl_ColorDelegateKind_Selected);
512
513   // parameters model
514   ViewControl_TableModel* aTableModel = dynamic_cast<ViewControl_TableModel*> (myParameters->model());
515   ViewControl_ParametersModel* aParametersModel = dynamic_cast<ViewControl_ParametersModel*> (aTableModel->ModelValues());
516   Quantity_Color anOCCTColor (aNameOfColor);
517   aParametersModel->SetColor (Quantity_ColorRGBA (anOCCTColor), aTableModel);
518 }