Salome HOME
Issue #2309 Possibility to hide faces : transparency using
[modules/shaper.git] / src / XGUI / XGUI_FacesPanel.cpp
1 // Copyright (C) 2014-2017  CEA/DEN, EDF R&D
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
18 // email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
19 //
20
21 #include "XGUI_FacesPanel.h"
22
23 #include <Config_PropManager.h>
24 #include <Events_Loop.h>
25 #include <GeomAlgoAPI_CompoundBuilder.h>
26
27 #include <ModelAPI_Events.h>
28
29 #include <ModuleBase_ISelection.h>
30 #include "ModuleBase_IWorkshop.h"
31 #include "ModuleBase_ListView.h"
32 #include "ModuleBase_ResultPrs.h"
33 #include "ModuleBase_Tools.h"
34 #include "ModuleBase_ViewerPrs.h"
35
36 #include "XGUI_Displayer.h"
37 #include "XGUI_Tools.h"
38 #include "XGUI_Workshop.h"
39
40 #include <QAction>
41 #include <QCheckBox>
42 #include <QFocusEvent>
43 #include <QGridLayout>
44 #include <QListWidget>
45 #include <QMainWindow>
46
47 static const int LayoutMargin = 3;
48
49 //********************************************************************
50 XGUI_FacesPanel::XGUI_FacesPanel(QWidget* theParent, ModuleBase_IWorkshop* theWorkshop)
51   : QDockWidget(theParent), myIsActive(false), myWorkshop(theWorkshop)
52 {
53   setWindowTitle(tr("Hide Faces"));
54   QAction* aViewAct = toggleViewAction();
55   setStyleSheet("::title { position: relative; padding-left: 5px; text-align: left center }");
56
57   QWidget* aContent = new QWidget(this);
58   QGridLayout* aMainLayout = new QGridLayout(aContent);
59   aMainLayout->setContentsMargins(LayoutMargin, LayoutMargin, LayoutMargin, LayoutMargin);
60   setWidget(aContent);
61
62   myHiddenOrTransparent = new QCheckBox(tr("Transparent"), aContent);
63   myListView = new ModuleBase_ListView(aContent, "", "Hidden/transparent faces in 3D view");
64   connect(myListView, SIGNAL(deleteActionClicked()), SLOT(onDeleteItem()));
65
66   aMainLayout->addWidget(myHiddenOrTransparent, 0, 0);
67   aMainLayout->addWidget(myListView->getControl(), 1, 0);
68
69   myListView->getControl()->setFocusPolicy(Qt::StrongFocus);
70   myListView->getControl()->viewport()->installEventFilter(this);
71 }
72
73 //********************************************************************
74 void XGUI_FacesPanel::reset(const bool isToFlushRedisplay)
75 {
76   // restore presentation state
77   bool isModified = false;
78   std::set<ObjectPtr> aRestoredObjects;
79   for (QMap<int, ModuleBase_ViewerPrsPtr>::const_iterator anIt = myItems.begin();
80     anIt != myItems.end(); anIt++) {
81     if (aRestoredObjects.find(anIt.value()->object()) == aRestoredObjects.end())
82       aRestoredObjects.insert(anIt.value()->object());
83   }
84   // clear internal containers
85   myListView->getControl()->clear();
86   myLastItemIndex = 0;
87   myItems.clear();
88
89   isModified = redisplayObjects(aRestoredObjects, isToFlushRedisplay);
90
91   if (isToFlushRedisplay && isModified)
92     XGUI_Tools::workshop(myWorkshop)->displayer()->updateViewer();
93 }
94
95 //********************************************************************
96 bool XGUI_FacesPanel::eventFilter(QObject* theObject, QEvent *theEvent)
97 {
98   QWidget* aWidget = qobject_cast<QWidget*>(theObject);
99   if (theEvent->type() == QEvent::MouseButtonRelease)
100   {
101     if (myListView->getControl()->viewport() == aWidget)
102       setActivePanel(true);
103   }
104   // pass the event on to the parent class
105   return QObject::eventFilter(theObject, theEvent);
106 }
107
108 //********************************************************************
109 void XGUI_FacesPanel::setActivePanel(const bool theIsActive)
110 {
111   if (myIsActive == theIsActive)
112     return;
113
114   ModuleBase_Tools::setShadowEffect(myListView->getControl(), theIsActive);
115   myIsActive = theIsActive;
116
117   if (myIsActive)
118   {
119     emit activated();
120     // selection should be activated after emit signal, that deactivates current widget(selection)
121     activateSelection(theIsActive);
122   }
123   else
124   {
125     // selection should be activated after emit signal, that deactivates current widget(selection)
126     activateSelection(theIsActive);
127     emit deactivated();
128   }
129 }
130
131 //********************************************************************
132 bool XGUI_FacesPanel::useTransparency() const
133 {
134   return myHiddenOrTransparent->isChecked();
135 }
136
137 //********************************************************************
138 void XGUI_FacesPanel::restoreObjects(const std::set<ObjectPtr>& theHiddenObjects)
139 {
140   std::set<int> anIndicesToBeRemoved;
141   for (QMap<int, ModuleBase_ViewerPrsPtr>::const_iterator anItemsIt = myItems.begin();
142     anItemsIt != myItems.end(); anItemsIt++)
143   {
144     ModuleBase_ViewerPrsPtr aPrs = anItemsIt.value();
145     ObjectPtr anObject = aPrs->object();
146     if (theHiddenObjects.find(anObject) == theHiddenObjects.end()) // not found
147       continue;
148     anIndicesToBeRemoved.insert(anItemsIt.key());
149   }
150
151   // remove from myItes container
152   for (std::set<int>::const_iterator aToBeRemovedIt = anIndicesToBeRemoved.begin();
153     aToBeRemovedIt != anIndicesToBeRemoved.end(); aToBeRemovedIt++)
154     myItems.remove(*aToBeRemovedIt);
155
156   myListView->removeItems(anIndicesToBeRemoved);
157
158   // remove from container of hidden objects
159   for (std::set<ObjectPtr>::const_iterator aHiddenIt = theHiddenObjects.begin();
160     aHiddenIt != theHiddenObjects.end(); aHiddenIt++)
161   {
162     if (myHiddenObjects.find(*aHiddenIt) != myHiddenObjects.end()) ///< found objects
163       myHiddenObjects.erase(*aHiddenIt);
164   }
165 }
166
167 //********************************************************************
168 bool XGUI_FacesPanel::processAction(ModuleBase_ActionType theActionType)
169 {
170   switch (theActionType) {
171     //case ActionEnter:
172     //  return processEnter();
173     case ActionEscape:
174       setActivePanel(false);
175       return true;
176     case ActionDelete:
177       return processDelete();
178     //case ActionUndo:
179     //case ActionRedo:
180     default:
181       return false;
182   }
183 }
184
185 //********************************************************************
186 void XGUI_FacesPanel::processSelection()
187 {
188   QList<ModuleBase_ViewerPrsPtr> aSelected = myWorkshop->selection()->getSelected(
189                                                        ModuleBase_ISelection::Viewer);
190   bool isModified = false;
191   for (int i = 0; i < aSelected.size(); i++) {
192     ModuleBase_ViewerPrsPtr aPrs = aSelected[i];
193     ObjectPtr anObject = aPrs->object();
194     if (!anObject.get())
195       continue;
196
197     if (ModuleBase_Tools::getSelectedShape(aPrs).ShapeType() != TopAbs_FACE)
198       continue;
199
200     myItems.insert(myLastItemIndex, aPrs);
201     myListView->addItem(generateName(aPrs), myLastItemIndex);
202     isModified = hideFace(myLastItemIndex) || isModified;
203
204     myLastItemIndex++;
205   }
206
207   if (isModified)
208     XGUI_Tools::workshop(myWorkshop)->displayer()->updateViewer();
209 }
210
211 //********************************************************************
212 bool XGUI_FacesPanel::processDelete()
213 {
214   //appendFirstSelectionInHistory();
215   QModelIndexList anIndices = myListView->getControl()->selectionModel()->selectedIndexes();
216
217   std::set<int> aSelectedIds;
218   myListView->getSelectedIndices(aSelectedIds);
219   if (aSelectedIds.empty())
220     return false;
221
222   bool isModified = false;
223   std::set<ObjectPtr> aRestoredObjects;
224   XGUI_Displayer* aDisplayer = XGUI_Tools::workshop(myWorkshop)->displayer();
225   for (std::set<int>::const_iterator anIt = aSelectedIds.begin(); anIt != aSelectedIds.end();
226        anIt++) {
227     ModuleBase_ViewerPrsPtr aPrs = myItems[*anIt];
228     if (aRestoredObjects.find(aPrs->object()) == aRestoredObjects.end())
229       aRestoredObjects.insert(aPrs->object());
230     myItems.remove(*anIt);
231   }
232   myListView->removeSelectedItems();
233
234   isModified = redisplayObjects(aRestoredObjects, true) || isModified;
235   if (isModified)
236     XGUI_Tools::workshop(myWorkshop)->displayer()->updateViewer();
237
238   // Restore selection
239   myListView->restoreSelection(anIndices);
240   //appendSelectionInHistory();
241   return true;
242 }
243
244 //********************************************************************
245 bool XGUI_FacesPanel::redisplayObjects(
246   const std::set<std::shared_ptr<ModelAPI_Object> >& theObjects,
247   const bool isToFlushRedisplay)
248 {
249   bool isModified = false;
250   XGUI_Displayer* aDisplayer = XGUI_Tools::workshop(myWorkshop)->displayer();
251   static Events_ID aDispEvent = Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);
252
253   for (std::set<ObjectPtr>::const_iterator anIt = theObjects.begin(); anIt != theObjects.end();
254        anIt++)
255   {
256     ObjectPtr anObject = *anIt;
257     if (!anObject->isDisplayed()) {
258       // if the object was hidden by this panel
259       if (myHiddenObjects.find(anObject) != myHiddenObjects.end())
260         myHiddenObjects.erase(anObject);
261       anObject->setDisplayed(true); // it means that the object is hidden by hide all faces
262       ModelAPI_EventCreator::get()->sendUpdated(anObject, aDispEvent);
263       isModified = true;
264       //isModified = aDisplayer->display(anObject, false) || isModified;
265     }
266     else {
267       ModelAPI_EventCreator::get()->sendUpdated(anObject, aDispEvent);
268       isModified = true;
269     }
270   }
271   if (isToFlushRedisplay)
272     Events_Loop::loop()->flush(aDispEvent);
273   return isModified;
274 }
275
276 //********************************************************************
277 bool XGUI_FacesPanel::hideFace(const int theIndex)
278 {
279   XGUI_Displayer* aDisplayer = XGUI_Tools::workshop(myWorkshop)->displayer();
280
281   if (!myItems.contains(theIndex))
282     return false;
283
284   ModuleBase_ViewerPrsPtr aPrs = myItems[theIndex];
285
286   AISObjectPtr aAISObj = aDisplayer->getAISObject(aPrs->object());
287   if (aAISObj.get() == NULL)
288     return false;
289   Handle(ModuleBase_ResultPrs) aResultPrs = Handle(ModuleBase_ResultPrs)::DownCast(
290     aAISObj->impl<Handle(AIS_InteractiveObject)>());
291   if (aResultPrs.IsNull())
292     return false;
293   // set shape hidden to check whether the presentation should be erased from the viewer
294   bool isModified = false;
295   if (aResultPrs->hasSubShapeVisible(ModuleBase_Tools::getSelectedShape(aPrs)))
296     isModified = aDisplayer->redisplay(aPrs->object(), false) || isModified;
297   else
298   {
299     ObjectPtr anObject = aPrs->object();
300     myHiddenObjects.insert(anObject);
301     static Events_ID aDispEvent = Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);
302     anObject->setDisplayed(false);
303     isModified = aDisplayer->erase(anObject, false) || isModified;
304     ModelAPI_EventCreator::get()->sendUpdated(anObject, aDispEvent);
305     Events_Loop::loop()->flush(aDispEvent);
306   }
307   return isModified;
308 }
309
310 //********************************************************************
311 void XGUI_FacesPanel::closeEvent(QCloseEvent* theEvent)
312 {
313   QDockWidget::closeEvent(theEvent);
314   emit closed();
315 }
316
317 //********************************************************************
318 void XGUI_FacesPanel::activateSelection(bool toActivate)
319 {
320   QIntList aShapeTypes;
321   aShapeTypes.append(TopAbs_FACE);
322
323   if (toActivate) {
324     myWorkshop->activateSubShapesSelection(aShapeTypes);
325   } else {
326     myWorkshop->deactivateSubShapesSelection();
327   }
328   if (toActivate)
329     activateSelectionFilters();
330   else
331     deactivateSelectionFilters();
332 }
333
334 //********************************************************************
335 QString XGUI_FacesPanel::generateName(const ModuleBase_ViewerPrsPtr& thePrs)
336 {
337   if (!thePrs.get() || !thePrs->object().get())
338     return "Undefined";
339
340   GeomShapePtr aContext;
341   ObjectPtr anObject = thePrs->object();
342   ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(anObject);
343   if (aResult.get())
344     aContext = aResult->shape();
345   else {
346     // TODO if there is this case
347   }
348
349   QString aName = anObject->data()->name().c_str();
350   if (aContext.get()) {
351     GeomShapePtr aSubShape(new GeomAPI_Shape());
352     aSubShape->setImpl(new TopoDS_Shape(ModuleBase_Tools::getSelectedShape(thePrs)));
353     if (!aSubShape->isEqual(aContext))
354       aName += QString("_%1").arg(GeomAlgoAPI_CompoundBuilder::id(aContext, aSubShape));
355   }
356   return aName;
357 }
358
359 //********************************************************************
360 bool XGUI_FacesPanel::customizeObject(const ObjectPtr& theObject, const bool isDisplayed)
361 {
362   if (isDisplayed && myItems.isEmpty())
363     return false;
364
365   XGUI_Displayer* aDisplayer = XGUI_Tools::workshop(myWorkshop)->displayer();
366
367   AISObjectPtr aAISObj = aDisplayer->getAISObject(theObject);
368   if (aAISObj.get() == NULL)
369     return false;
370   Handle(ModuleBase_ResultPrs) aResultPrs = Handle(ModuleBase_ResultPrs)::DownCast(
371     aAISObj->impl<Handle(AIS_InteractiveObject)>());
372   if (aResultPrs.IsNull())
373     return false;
374
375   // if the object is displayed, the hidden faces are collected and set to the presentation
376   bool isModified = false;
377   NCollection_List<TopoDS_Shape> aHiddenSubShapes;
378   for (QMap<int, ModuleBase_ViewerPrsPtr>::const_iterator anIt = myItems.begin();
379     anIt != myItems.end(); anIt++) {
380     ModuleBase_ViewerPrsPtr aPrs = anIt.value();
381     if (aPrs.get() && aPrs->object() != theObject)
382       continue;
383     TopoDS_Shape aShape = ModuleBase_Tools::getSelectedShape(aPrs);
384     if (!aHiddenSubShapes.Contains(aShape))
385       aHiddenSubShapes.Append(aShape);
386   }
387   isModified = aResultPrs->setSubShapeHidden(aHiddenSubShapes);
388   double aTransparency = !useTransparency() ? 1
389     : Config_PropManager::real("Visualization", "hidden_face_transparency");
390   aResultPrs->setHiddenSubShapeTransparency(aTransparency);
391
392   return isModified;
393 }
394
395 //********************************************************************
396 void XGUI_FacesPanel::onDeleteItem()
397 {
398   processDelete();
399 }
400
401 //********************************************************************
402 void XGUI_FacesPanel::onClosed()
403 {
404   reset(true);
405 }