1 /****************************************************************************
2 * MeshLab o o *
3 * A versatile mesh processing toolbox o o *
4 * _ O _ *
5 * Copyright(C) 2005 \/)\/ *
6 * Visual Computing Lab /\/| *
7 * ISTI - Italian National Research Council | *
8 * \ *
9 * All rights reserved. *
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 * This program is distributed in the hope that it will be useful, *
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
19 * GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
20 * for more details. *
21 * *
22 ****************************************************************************/
23 #include "multiViewer_Container.h"
24 #include "glarea.h"
25 #include <QMouseEvent>
26 #include "mainwindow.h"
27 #include <common/mlapplication.h>
28
29 using namespace vcg;
30
Splitter(QWidget * parent)31 Splitter::Splitter ( QWidget * parent):QSplitter(parent){}
Splitter(Qt::Orientation orientation,QWidget * parent)32 Splitter::Splitter(Qt::Orientation orientation, QWidget *parent):QSplitter(orientation,parent){}
33
createHandle()34 QSplitterHandle *Splitter::createHandle()
35 {
36 return new SplitterHandle(orientation(), this);
37 }
38
getRootContainer()39 MultiViewer_Container *Splitter::getRootContainer()
40 {
41 Splitter * parentSplitter = this;
42 MultiViewer_Container* mvc = qobject_cast<MultiViewer_Container *>(parentSplitter);
43 while(!mvc)
44 {
45 parentSplitter = qobject_cast<Splitter *>(parentSplitter->parent());
46 mvc= qobject_cast<MultiViewer_Container *>(parentSplitter);
47 }
48 return mvc;
49 }
50
SplitterHandle(Qt::Orientation orientation,QSplitter * parent)51 SplitterHandle::SplitterHandle(Qt::Orientation orientation, QSplitter *parent):QSplitterHandle(orientation, parent){}
52
mousePressEvent(QMouseEvent * e)53 void SplitterHandle::mousePressEvent ( QMouseEvent * e )
54 {
55 QSplitterHandle::mousePressEvent(e);
56
57 if(e->button()== Qt::RightButton)
58 {
59 MainWindow *window = qobject_cast<MainWindow *>(QApplication::activeWindow());
60 if (window) window->setHandleMenu(mapToGlobal(e->pos()), orientation(), splitter());
61 }
62 }
63
MultiViewer_Container(vcg::QtThreadSafeMemoryInfo & meminfo,bool highprec,size_t perbatchprimitives,size_t minfacespersmoothrendering,QWidget * parent)64 MultiViewer_Container::MultiViewer_Container(vcg::QtThreadSafeMemoryInfo& meminfo, bool highprec,size_t perbatchprimitives, size_t minfacespersmoothrendering,QWidget *parent)
65 : Splitter(parent),meshDoc()
66 {
67 setChildrenCollapsible(false);
68 scenecontext = new MLSceneGLSharedDataContext(meshDoc,meminfo,highprec,perbatchprimitives,minfacespersmoothrendering);
69 scenecontext->setHidden(true);
70 scenecontext->initializeGL();
71 currentId=-1;
72 currentgla = NULL;
73 }
74
~MultiViewer_Container()75 MultiViewer_Container::~MultiViewer_Container()
76 {
77 /*for(int ii = 0;ii < viewerList.size();++ii)
78 delete viewerList[ii];*/
79
80 //WARNING!!!! here it's just destroyed the pointer to the MLSceneGLSharedDataContext
81 //the data contained in the GPU are deallocated in the closeEvent function
82 delete scenecontext;
83 }
84
getNextViewerId()85 int MultiViewer_Container::getNextViewerId(){
86 int newId=-1;
87
88 foreach(GLArea* view, viewerList)
89 {
90 if(newId < view->getId()) newId = view->getId();
91 }
92
93 return ++newId;
94 }
95
96
97 /*********************************************************************************************************/
98 /*********************************************************************************************************/
99 /*WARNING!!!!!!!!!!!! Horizontal and Vertical in QT are the opposite on how we consider them in Meshlab*/
100 /*********************************************************************************************************/
101 /*********************************************************************************************************/
102
103
addView(GLArea * viewer,Qt::Orientation orient)104 void MultiViewer_Container::addView(GLArea* viewer,Qt::Orientation orient)
105 {
106
107 MLRenderingData dt;
108 MainWindow *window = qobject_cast<MainWindow *>(QApplication::activeWindow());
109 if ((window != NULL) && (scenecontext != NULL))
110 {
111 //window->defaultPerViewRenderingData(dt);
112 scenecontext->addView(viewer->context(),dt);
113 }
114 /* The Viewers are organized like a BSP tree.
115 Every new viewer is added within an Horizontal splitter. Its orientation could change according to next insertions.
116 HSplit
117 / \
118 View1 VSplit
119 / \
120 View2 View3
121
122 In the GUI, when a viewer is split, the new one appears on its right (the space is split in two equal portions).
123 */
124 //CASE 0: only when the first viewer is opened, just add it and return;
125 if (viewerCounter()==0)
126 {
127 viewerList.append(viewer);
128 addWidget(viewer);
129 updateCurrent(viewer->getId());
130 //action for new viewer
131 connect(viewer, SIGNAL(currentViewerChanged(int)), this, SLOT(updateCurrent(int)));
132 return;
133 }
134
135 //CASE 1: happens only at the FIRST split;
136 if (viewerCounter()==1)
137 {
138 viewerList.append(viewer);
139 this->setOrientation(orient);
140 addWidget(viewer);
141 QList<int> sizes;
142 if(this->orientation()== Qt::Horizontal){
143 sizes.append(this->width()/2);
144 sizes.append(this->width()/2);
145 }
146 else{
147 sizes.append(this->height()/2);
148 sizes.append(this->height()/2);
149 }
150
151 this->setSizes(sizes);
152 this->setHandleWidth(2);
153 this->setChildrenCollapsible(false);
154
155 updateCurrent(viewer->getId());
156 //action for new viewer
157 connect(viewer, SIGNAL(currentViewerChanged(int)), this, SLOT(updateCurrent(int)));
158 return;
159 }
160
161 // Generic Case: Each splitter Has ALWAYS two children.
162 viewerList.append(viewer);
163 GLArea* currentGLA = this->currentView();
164 Splitter* currentSplitter = qobject_cast<Splitter *>(currentGLA->parent());
165 QList<int> parentSizes = currentSplitter->sizes();
166
167 int splittedIndex = currentSplitter->indexOf(currentGLA);
168 Splitter* newSplitter = new Splitter(orient);
169 currentSplitter->insertWidget(splittedIndex,newSplitter);
170
171 newSplitter->addWidget(viewer);
172 newSplitter->addWidget(currentGLA);
173
174 QList<int> sizes;
175 if(orient== Qt::Horizontal){
176 sizes.append(currentSplitter->width()/2);
177 sizes.append(currentSplitter->width()/2);
178 }
179 else{
180 sizes.append(currentSplitter->height()/2);
181 sizes.append(currentSplitter->height()/2);
182 }
183 currentSplitter->setSizes(parentSizes);
184 newSplitter->setSizes(sizes);
185 newSplitter->setHandleWidth(2);
186 newSplitter->setChildrenCollapsible(false);
187
188 updateCurrent(viewer->getId());
189 //action for new viewer
190 connect(viewer, SIGNAL(currentViewerChanged(int)), this, SLOT(updateCurrent(int)));
191 return;
192 }
193
removeView(int viewerId)194 void MultiViewer_Container::removeView(int viewerId)
195 {
196 GLArea* viewer = NULL;
197 for (int i=0; i< viewerList.count(); i++)
198 {
199 if(viewerList.at(i)->getId() == viewerId)
200 viewer = viewerList.at(i);
201 }
202 assert(viewer);
203 if (viewer != NULL)
204 scenecontext->removeView(viewer->context());
205 Splitter* parentSplitter = qobject_cast<Splitter *>(viewer->parent());
206 int currentIndex = parentSplitter->indexOf(viewer);
207
208 viewer->deleteLater();
209 // Very basic case of just two son of the MultiviewContainer.
210 if(viewerList.count()==2)
211 {
212 viewerList.removeAll(viewer);
213 updateCurrent(viewerList.first()->getId());
214 return;
215 }
216
217 // generic tree with more of two leaves (some splitter involved)
218 // two cases
219 // 1) the deleted object is a direct child of the root
220 // 2) otherwise; e.g. parent->parent exists.
221
222
223 // First Case: deleting the direct son of the root (the mvc)
224 // the sibling content (that is a splitter) surely will be moved up
225 if(parentSplitter == this)
226 {
227 int insertIndex;
228 if(currentIndex == 0) insertIndex = 1;
229 else insertIndex = 0;
230
231 Splitter *siblingSplitter = qobject_cast<Splitter *>(this->widget(insertIndex));
232 assert(siblingSplitter);
233 siblingSplitter->hide();
234 siblingSplitter->deleteLater();
235
236 QWidget *sonLeft = siblingSplitter->widget(0);
237 QWidget *sonRight = siblingSplitter->widget(1);
238 this->setOrientation(siblingSplitter->orientation());
239 this->insertWidget(0,sonLeft);
240 this->insertWidget(1,sonRight);
241
242 patchForCorrectResize(this);
243 viewerList.removeAll(viewer);
244 //currentId = viewerList.first()->getId();
245 updateCurrent(viewerList.first()->getId());
246 return;
247 }
248
249 // Final case. Very generic, not son of the root.
250
251 Splitter* parentParentSplitter = qobject_cast<Splitter *>(parentSplitter->parent());
252 assert(parentParentSplitter);
253 int parentIndex= parentParentSplitter->indexOf(parentSplitter);
254
255 int siblingIndex;
256 if(currentIndex == 0) siblingIndex = 1;
257 else siblingIndex = 0;
258
259 QWidget *siblingWidget = parentSplitter->widget(siblingIndex);
260
261 parentSplitter->hide();
262 parentSplitter->deleteLater();
263 parentParentSplitter->insertWidget(parentIndex,siblingWidget);
264
265 patchForCorrectResize(parentParentSplitter);
266 viewerList.removeAll(viewer);
267 updateCurrent(viewerList.first()->getId());
268 }
269
updateCurrent(int current)270 void MultiViewer_Container::updateCurrent(int current)
271 {
272 int previousCurrentId = currentId;
273 currentId=current;
274 currentgla = getViewer(currentId);
275 if(getViewer(previousCurrentId))
276 update(previousCurrentId);
277 emit updateMainWindowMenus();
278 if (current != previousCurrentId)
279 emit updateDocumentViewer();
280 }
281
getViewer(int id)282 GLArea * MultiViewer_Container::getViewer(int id)
283 {
284 foreach ( GLArea* viewer, viewerList)
285 if ((viewer != NULL) && (viewer->getId() == id))
286 return viewer;
287 return 0;
288 }
289
getViewerByPicking(QPoint p)290 int MultiViewer_Container::getViewerByPicking(QPoint p){
291 foreach ( GLArea* viewer, viewerList)
292 {
293 if (viewer != NULL)
294 {
295 QPoint pViewer = viewer->mapFromGlobal(p);
296 if (viewer->visibleRegion().contains(pViewer))
297 return viewer->getId();
298 }
299 }
300 return -1;
301 }
302
currentView()303 GLArea* MultiViewer_Container::currentView(){
304 return getViewer(currentId);
305 }
306
viewerCounter()307 int MultiViewer_Container::viewerCounter(){
308 return viewerList.count();
309 }
310
updateAllViewers()311 void MultiViewer_Container::updateAllViewers(){
312 foreach(GLArea* viewer, viewerList)
313 {
314 if (viewer != NULL)
315 viewer->update();
316 }
317 }
318
updateAllDecoratorsForAllViewers()319 void MultiViewer_Container::updateAllDecoratorsForAllViewers()
320 {
321 foreach(GLArea* viewer, viewerList)
322 {
323 if (viewer != NULL)
324 viewer->updateAllPerMeshDecorators();
325 }
326 }
327
328
329
resetAllTrackBall()330 void MultiViewer_Container::resetAllTrackBall()
331 {
332 foreach(GLArea* viewer, viewerList)
333 {
334 if (viewer != NULL)
335 viewer->resetTrackBall();
336 }
337 }
338
update(int id)339 void MultiViewer_Container::update(int id){
340 getViewer(id)->update();
341 }
342
updateTrackballInViewers()343 void MultiViewer_Container::updateTrackballInViewers()
344 {
345 GLArea* glArea = currentView();
346 if(glArea)
347 {
348 QPair<Shotm,float> shotAndScale = glArea->shotFromTrackball();
349 foreach(GLArea* viewer, viewerList)
350 if(viewer->getId() != currentId){
351 ((GLArea*) viewer)->loadShot(shotAndScale);
352 }
353 }
354 }
355
closeEvent(QCloseEvent * event)356 void MultiViewer_Container::closeEvent( QCloseEvent *event )
357 {
358 if (meshDoc.hasBeenModified())
359 {
360 QMessageBox::StandardButton ret=QMessageBox::question(
361 this, tr("MeshLab"), tr("Project '%1' modified.\n\nClose without saving?").arg(meshDoc.docLabel()),
362 QMessageBox::Yes|QMessageBox::No,
363 QMessageBox::No);
364
365 if(ret==QMessageBox::No) // don't close please!
366 {
367 event->ignore();
368 return;
369 }
370 }
371 bool close = true;
372 int ii = 0;
373 scenecontext->deAllocateGPUSharedData();
374 while(close && (ii < viewerList.size()))
375 {
376 close = viewerList.at(ii)->readyToClose();
377 ++ii;
378 }
379
380 if (close)
381 {
382 emit closingMultiViewerContainer();
383 event->accept();
384 }
385 else
386 event->ignore();
387 }
388
patchForCorrectResize(QSplitter * split)389 void MultiViewer_Container::patchForCorrectResize( QSplitter* split )
390 {
391 /***************************patch to avoid a qt problem**********************/
392 /*in qt it's not possible to remove a widget from a splitter (no comment....).
393 it's not sufficient to hide it.
394 it looks like that anyway the framework allocates space on the screen also for the hidden splitter.
395 So we have to resize all the visible glareas to half of the size of the new splitter in which they are going to be inserted and set,
396 by hand, to zero the size of the splitter that is going to be deleted */
397 /***************************************************************************/
398
399 QSize sz = split->size();
400 int newsz = 0;
401 if(split->orientation() == Qt::Horizontal)
402 newsz = sz.width()/2;
403 else
404 newsz = sz.height()/2;
405
406 QList<int> newwigsizes;
407 for(int ii = 0;ii < split->count();++ii)
408 {
409 QWidget* tmpwid = split->widget(ii);
410 if (tmpwid->isVisible())
411 newwigsizes.push_back(newsz);
412 else
413 newwigsizes.push_back(0);
414 }
415
416 split->setSizes(newwigsizes);
417 }
418