Files
geant4/source/visualization/OpenGL/src/G4OpenGLQtViewer.cc
T
2017-06-30 10:49:55 +02:00

4804 lines
148 KiB
C++

//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
//
// $Id: G4OpenGLQtViewer.cc 104288 2017-05-23 13:23:23Z gcosmo $
//
//
// G4OpenGLQtViewer : Class to provide Qt specific
// functionality for OpenGL in GEANT4
//
// 27/06/2003 : G.Barrand : implementation (at last !).
// 30/06/2014 : M.Kelsey : Change QPixmap objects to pointers
#ifdef G4VIS_BUILD_OPENGLQT_DRIVER
#include "G4OpenGLQtViewer.hh"
#include "G4OpenGLSceneHandler.hh"
#include "G4VSolid.hh"
#include "G4OpenGLQtExportDialog.hh"
#include "G4OpenGLQtMovieDialog.hh"
#include "G4Qt.hh"
#include "G4UIQt.hh"
#include "G4UImanager.hh"
#include "G4UIcommandTree.hh"
#include "G4LogicalVolumeStore.hh"
#include "G4PhysicalVolumeStore.hh"
#include "G4VisCommandsGeometrySet.hh"
#include "G4PhysicalVolumeModel.hh"
#include "G4Text.hh"
#include "G4UnitsTable.hh"
#include "G4OpenGLStoredQtViewer.hh"
#include "G4Threading.hh"
#include <CLHEP/Units/SystemOfUnits.h>
#include <typeinfo>
#include <qlayout.h>
#include <qlabel.h>
#include <qdialog.h>
#include <qpushbutton.h>
#include <qprocess.h>
#include <qdesktopwidget.h>
#include <qmenu.h>
#include <qimagewriter.h>
#include <qtextedit.h>
#include <qtreewidget.h>
#include <qapplication.h>
#include <qmessagebox.h>
#include <qfiledialog.h>
#include <qprinter.h>
#include <qdatetime.h>
#include <qpainter.h>
#include <qgl.h> // include <qglwidget.h>
#include <qdialog.h>
#include <qcolordialog.h>
#include <qevent.h> //include <qcontextmenuevent.h>
#include <qobject.h>
#include <qgroupbox.h>
#include <qcombobox.h>
#include <qlineedit.h>
#include <qsignalmapper.h>
#include <qmainwindow.h>
#include <qtablewidget.h>
#include <qheaderview.h>
#include <qscrollarea.h>
#include <qsplitter.h>
#include <qcheckbox.h>
#include <qcursor.h>
#include <qthread.h>
#ifdef G4MULTITHREADED
#include "G4Threading.hh"
#endif
#ifdef G4MULTITHREADED
namespace
{
G4Mutex mWaitForVisSubThreadQtOpenGLContextMoved = G4MUTEX_INITIALIZER;
G4Mutex mWaitForVisSubThreadQtOpenGLContextInitialized = G4MUTEX_INITIALIZER;
G4Condition c1_VisSubThreadQtOpenGLContextInitialized = G4CONDITION_INITIALIZER;
G4Condition c2_VisSubThreadQtOpenGLContextMoved = G4CONDITION_INITIALIZER;
}
#endif
//////////////////////////////////////////////////////////////////////////////
void G4OpenGLQtViewer::CreateMainWindow (
QGLWidget* glWidget
,const QString& name
)
//////////////////////////////////////////////////////////////////////////////
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!//
{
if(fGLWidget) return; //Done.
fGLWidget = glWidget ;
// fGLWidget->makeCurrent();
G4Qt* interactorManager = G4Qt::getInstance ();
ResizeWindow(fVP.GetWindowSizeHintX(),fVP.GetWindowSizeHintY());
// FIXME L.Garnier 9/11/09 Has to be check !!!
// Qt UI with Qt Vis
// Qt UI with X Vis
// X UI with Qt Vis
// X UI with X Vis
// Ne marche pas avec un UIBatch !! (ecran blanc)
// return false if G4UIQt was not launch
G4UImanager* UI = G4UImanager::GetUIpointer();
if (UI == NULL) return;
if (! static_cast<G4UIQt*> (UI->GetG4UIWindow())) {
// NO UI, should be batch mode
fBatchMode = true;
return;
}
fUiQt = static_cast<G4UIQt*> (UI->GetG4UIWindow());
bool isTabbedView = false;
if ( fUiQt) {
if (!fBatchMode) {
if (!interactorManager->IsExternalApp()) {
// INIT size
fWinSize_x = fVP.GetWindowSizeHintX();
fWinSize_y = fVP.GetWindowSizeHintY();
isTabbedView = fUiQt->AddTabWidget((QWidget*)fGLWidget,name);
QObject::connect(fUiQt->GetViewerTabWidget(),
SIGNAL(currentChanged(int)),
this,
SLOT(currentTabActivated(int)));
}
createSceneTreeWidget();
// activate them
}
}
if (!isTabbedView) { // we have to do a dialog
QWidget *glDialogWidget = getParentWidget();
if (glDialogWidget == NULL) {
return;
}
glWidget->setParent(glDialogWidget);
QHBoxLayout *mainLayout = new QHBoxLayout();
mainLayout->setMargin(0);
mainLayout->setSpacing(0);
mainLayout->addWidget(fGLWidget);
if (fGLWidget->inherits("QMainWindow")) {
fGLWidget->setWindowTitle( name);
}
glDialogWidget->setLayout(mainLayout);
//useful for MACOSX, we have to compt the menuBar height
int offset = QApplication::desktop()->height()
- QApplication::desktop()->availableGeometry().height();
G4int YPos= fVP.GetWindowAbsoluteLocationHintY(QApplication::desktop()->height());
if (fVP.GetWindowAbsoluteLocationHintY(QApplication::desktop()->height())< offset) {
YPos = offset;
}
glDialogWidget->resize(getWinWidth(), getWinHeight());
glDialogWidget->move(fVP.GetWindowAbsoluteLocationHintX(QApplication::desktop()->width()),YPos);
glDialogWidget->show();
}
if(!fGLWidget) return;
if (!fContextMenu)
createPopupMenu();
}
//////////////////////////////////////////////////////////////////////////////
G4OpenGLQtViewer::G4OpenGLQtViewer (
G4OpenGLSceneHandler& scene
)
:G4VViewer (scene, -1)
,G4OpenGLViewer (scene)
,fGLWidget(NULL)
,fRecordFrameNumber(0)
,fMouseOnSceneTree(false)
,fContextMenu(0)
,fLastPickPoint(-1,-1)
,fDeltaDepth(0.01)
,fDeltaZoom(0.05)
,fHoldKeyEvent(false)
,fHoldMoveEvent(false)
,fHoldRotateEvent(false)
,fAutoMove(false)
,fEncoderPath("")
,fTempFolderPath("")
,fMovieTempFolderPath("")
,fSaveFileName("")
,fParameterFileName("ppmtompeg_encode_parameter_file.par")
,fMovieParametersDialog(NULL)
,fRecordingStep(WAIT)
,fProcess(NULL)
,fNbMaxFramesPerSec(100)
,fNbMaxAnglePerSec(360)
,fLaunchSpinDelay(100)
,fUISceneTreeWidget(NULL)
,fUIViewerPropertiesWidget(NULL)
,fUIPickInfosWidget(NULL)
,fNoKeyPress(true)
,fAltKeyPress(false)
,fControlKeyPress(false)
,fShiftKeyPress(false)
,fBatchMode(false)
,fCheckSceneTreeComponentSignalLock(false)
,fViewerPropertiesTableWidgetIsInit(false)
,fSceneTreeComponentTreeWidget(NULL)
,fSceneTreeWidget(NULL)
,fPVRootNodeCreate(false)
,fFilterOutput(NULL)
,fNbRotation(0)
,fTimeRotation(0)
,fTouchableVolumes("Touchables")
,fShortcutsDialog(NULL)
,fViewerPropertiesTableWidget(NULL)
,fPickInfosWidget(NULL)
,fPickInfosScrollArea(NULL)
,fTreeWidgetInfosIgnoredCommands(0)
,fSceneTreeDepthSlider(NULL)
,fSceneTreeDepth(1)
,fModelShortNameItem(NULL)
,fMaxPOindexInserted(-1)
,fUiQt(NULL)
,fSignalMapperMouse(NULL)
,fSignalMapperSurface(NULL)
,fSignalMapperPicking(NULL)
,fTreeIconOpen(NULL)
,fTreeIconClosed(NULL)
,fLastExportSliderValue(80)
,fLastHighlightColor(G4Color(0,0,0,0))
,fLastHighlightName(0)
,fIsDeleting(false)
{
// launch Qt if not
if (QCoreApplication::instance () == NULL) {
fBatchMode = true;
}
G4Qt::getInstance ();
fLastPos3 = QPoint(-1,-1);
fLastPos2 = QPoint(-1,-1);
fLastPos1 = QPoint(-1,-1);
initMovieParameters();
fLastEventTime = new QTime();
fSignalMapperMouse = new QSignalMapper(this);
fSignalMapperSurface = new QSignalMapper(this);
// Set default path and format
fFileSavePath = QDir::currentPath();
// add available export format
QList<QByteArray> formats = QImageWriter::supportedImageFormats ();
for (int i = 0; i < formats.size(); ++i) {
addExportImageFormat(formats.at(i).data());
}
const char * const icon1[]={
/* columns rows colors chars-per-pixel */
"20 20 34 1",
" c None",
". c #7C7C7C7C7C7C",
"X c #7D7D7D7D7D7D",
"o c #828282828282",
"O c #838383838383",
"+ c #848484848484",
"@ c #858585858585",
"# c #878787878787",
"$ c #888888888888",
"% c #8B8B8B8B8B8B",
"& c #8C8C8C8C8C8C",
"* c #8F8F8F8F8F8F",
"= c #909090909090",
"- c #919191919191",
"; c #999999999999",
": c #9D9D9D9D9D9D",
"> c #A2A2A2A2A2A2",
", c #A3A3A3A3A3A3",
"< c #A5A5A5A5A5A5",
"1 c #A6A6A6A6A6A6",
"2 c #B3B3B3B3B3B3",
"3 c #B6B6B6B6B6B6",
"4 c #C2C2C2C2C2C2",
"5 c #C6C6C6C6C6C6",
"6 c #CACACACACACA",
"7 c #CFCFCFCFCFCF",
"8 c #D0D0D0D0D0D0",
"9 c #D4D4D4D4D4D4",
"0 c #D7D7D7D7D7D7",
"q c #DEDEDEDEDEDE",
"w c #E0E0E0E0E0E0",
"e c #E7E7E7E7E7E7",
"r c #F4F4F4F4F4F4",
"t c #F7F7F7F7F7F7",
" ",
" ",
" ",
" ",
" ",
" ",
" =========> ",
" 7&X+++Oo<e ",
" 2o+@@+-8 ",
" w;.#@+3 ",
" 4$o@:q ",
" r1X%5 ",
" 9*,t ",
" 60 ",
" ",
" ",
" ",
" ",
" ",
" "
};
const char * const icon2[]={
"20 20 68 1",
" c None",
". c #5F5F10102323",
"X c #40405F5F1010",
"o c #696963632E2E",
"O c #101019194C4C",
"+ c #101023237070",
"@ c #70702D2D6363",
"# c #73732D2D6464",
"$ c #79792E2E6767",
"% c #19194C4C5353",
"& c #2D2D63636161",
"* c #2E2E61617070",
"= c #6F6F6E6E4343",
"- c #707065655F5F",
"; c #727279795454",
": c #535341417070",
"> c #797954547979",
", c #434361617474",
"< c #414170707070",
"1 c #686869696363",
"2 c #6C6C69696363",
"3 c #656567676F6F",
"4 c #69696F6F6E6E",
"5 c #747465656767",
"6 c #757562626C6C",
"7 c #70706C6C6969",
"8 c #616174746565",
"9 c #656573736969",
"0 c #616174746969",
"q c #707075756262",
"w c #797970706565",
"e c #636361617474",
"r c #67676F6F7272",
"t c #727261617070",
"y c #616170707070",
"u c #6F6F72727979",
"i c #67676E6ED1D1",
"p c #808080808080",
"a c #828282828282",
"s c #838383838383",
"d c #848484848484",
"f c #858585858585",
"g c #868686868686",
"h c #888888888888",
"j c #8A8A8A8A8A8A",
"k c #8D8D8D8D8D8D",
"l c #8F8F8F8F8F8F",
"z c #909090909090",
"x c #949494949494",
"c c #9C9C9C9C9C9C",
"v c #9F9F9F9F9F9F",
"b c #A2A2A2A2A2A2",
"n c #AEAEAEAEAEAE",
"m c #B7B7B7B7B7B7",
"M c #C7C7C7C7C7C7",
"N c #C9C9C9C9C9C9",
"B c #D1D1D1D1D1D1",
"V c #D4D4D4D4D4D4",
"C c #D9D9D9D9D9D9",
"Z c #E0E0E0E0E0E0",
"A c #E2E2E2E2E2E2",
"S c #EEEEEEEEEEEE",
"D c #F0F0F0F0F0F0",
"F c #F5F5F5F5F5F5",
"G c #F6F6F6F6F6F6",
"H c #F9F9F9F9F9F9",
"J c #FCFCFCFCFCFC",
"K c #FDFDFDFDFDFD",
" ",
" ",
" ",
" ",
" ",
" bC ",
" zjnD ",
" ldjjMK ",
" zdhdjcA ",
" zddhdddVK ",
" zghdalBH ",
" zghamSK ",
" lubZH ",
" xMF ",
" G ",
" ",
" ",
" ",
" ",
" ",
};
const char * const search[] = {
/* columns rows colors chars-per-pixel */
"19 19 8 1",
" c #5C5C5C",
". c #7D7D7D",
"X c #9B9B9B",
"o c #C3C3C3",
"O c None",
"+ c #000000",
"@ c #000000",
"# c None",
/* pixels */
"OOOOOOOOOOOOOOOOOOO",
"OOOOOOOOOOOOOOOOOOO",
"OOOOOOOo. .oOOOOOO",
"OOOOOOX XOOOOO",
"OOOOOo XOOX oOOOO",
"OOOOO. XOOOOX .OOOO",
"OOOOO OOOOOO OOOO",
"OOOOO OOOOOO OOOO",
"OOOOO. XOOOOo .OOOO",
"OOOOOo oOOo oOOOO",
"OOOOOOX XOOOO",
"OOOOOOOo. . XOOO",
"OOOOOOOOOOOOO. XOO",
"OOOOOOOOOOOOOO. XOO",
"OOOOOOOOOOOOOOOoOOO",
"OOOOOOOOOOOOOOOOOOO",
"OOOOOOOOOOOOOOOOOOO",
"OOOOOOOOOOOOOOOOOOO",
"OOOOOOOOOOOOOOOOOOO"
};
fSearchIcon = new QPixmap(search);
fTreeIconOpen = new QPixmap(icon1);
fTreeIconClosed = new QPixmap(icon2);
}
//////////////////////////////////////////////////////////////////////////////
G4OpenGLQtViewer::~G4OpenGLQtViewer (
)
//////////////////////////////////////////////////////////////////////////////
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!//
{
fIsDeleting = true;
// remove scene tree from layout
// Delete all the existing buttons in the layout
QLayoutItem *wItem;
if (fSceneTreeWidget != NULL) {
if (fSceneTreeWidget->layout() != NULL) {
while ((wItem = fSceneTreeWidget->layout()->takeAt(0)) != 0) {
delete wItem->widget();
delete wItem;
}
}
}
// Delete the open/close icons
delete fTreeIconOpen;
delete fTreeIconClosed;
G4cout <<removeTempFolder().toStdString().c_str() <<G4endl;
}
//
// Create a popup menu for the widget. This menu is activated by right-mouse click
//
void G4OpenGLQtViewer::createPopupMenu() {
fContextMenu = new QMenu("All");
QMenu *mMouseAction = fContextMenu->addMenu("&Mouse actions");
fMouseRotateAction = mMouseAction->addAction("Rotate", fSignalMapperMouse, SLOT(map()));
fMouseMoveAction = mMouseAction->addAction("Move", fSignalMapperMouse, SLOT(map()));
fMousePickAction = mMouseAction->addAction("Pick", fSignalMapperMouse, SLOT(map()));
fMouseZoomOutAction = mMouseAction->addAction("Zoom out", fSignalMapperMouse, SLOT(map()));
fMouseZoomInAction = mMouseAction->addAction("Zoom in", fSignalMapperMouse, SLOT(map()));
QAction *shortcutsAction = mMouseAction->addAction("Show shortcuts");
fMouseRotateAction->setCheckable(true);
fMouseMoveAction->setCheckable(true);
fMousePickAction->setCheckable(true);
fMouseZoomOutAction->setCheckable(true);
fMouseZoomInAction->setCheckable(true);
shortcutsAction->setCheckable(false);
connect(fSignalMapperMouse, SIGNAL(mapped(int)),this, SLOT(toggleMouseAction(int)));
fSignalMapperMouse->setMapping(fMouseRotateAction,1);
fSignalMapperMouse->setMapping(fMouseMoveAction,2);
fSignalMapperMouse->setMapping(fMousePickAction,3);
fSignalMapperMouse->setMapping(fMouseZoomOutAction,4);
fSignalMapperMouse->setMapping(fMouseZoomInAction,5);
QObject::connect(shortcutsAction,
SIGNAL(triggered(bool)),
this,
SLOT(showShortcuts()));
// === Style Menu ===
QMenu *mStyle = fContextMenu->addMenu("&Style");
QMenu *mProjection = mStyle->addMenu("&Projection");
fProjectionOrtho = mProjection->addAction("Orthographic", fSignalMapperSurface, SLOT(map()));
fProjectionPerspective = mProjection->addAction("Persepective", fSignalMapperSurface, SLOT(map()));
// INIT mProjection
if (fVP.GetFieldHalfAngle() == 0) {
createRadioAction(fProjectionOrtho, fProjectionPerspective,SLOT(toggleProjection(bool)),1);
} else {
createRadioAction(fProjectionOrtho, fProjectionPerspective,SLOT(toggleProjection(bool)),2);
}
// === Drawing Menu ===
QMenu *mDrawing = mStyle->addMenu("&Drawing");
fDrawingWireframe = mDrawing->addAction("Wireframe", fSignalMapperSurface, SLOT(map()));
fDrawingLineRemoval = mDrawing->addAction("Hidden line removal", fSignalMapperSurface, SLOT(map()));
fDrawingSurfaceRemoval = mDrawing->addAction("Hidden Surface removal", fSignalMapperSurface, SLOT(map()));
fDrawingLineSurfaceRemoval = mDrawing->addAction("Hidden line and surface removal", fSignalMapperSurface, SLOT(map()));
fDrawingWireframe->setCheckable(true);
fDrawingLineRemoval->setCheckable(true);
fDrawingSurfaceRemoval->setCheckable(true);
fDrawingLineSurfaceRemoval->setCheckable(true);
connect(fSignalMapperSurface, SIGNAL(mapped(int)),this, SLOT(toggleSurfaceAction(int)));
fSignalMapperSurface->setMapping(fDrawingWireframe,1);
fSignalMapperSurface->setMapping(fDrawingLineRemoval,2);
fSignalMapperSurface->setMapping(fDrawingSurfaceRemoval,3);
fSignalMapperSurface->setMapping(fDrawingLineSurfaceRemoval,4);
// Background Color
QAction *backgroundColorChooser ;
// === Action Menu ===
backgroundColorChooser = mStyle->addAction("Background color");
QObject ::connect(backgroundColorChooser,
SIGNAL(triggered()),
this,
SLOT(actionChangeBackgroundColor()));
// Text Color
QAction *textColorChooser ;
// === Action Menu ===
textColorChooser = mStyle->addAction("Text color");
QObject ::connect(textColorChooser,
SIGNAL(triggered()),
this,
SLOT(actionChangeTextColor()));
// Default Color
QAction *defaultColorChooser ;
// === Action Menu ===
defaultColorChooser = mStyle->addAction("Default color");
QObject ::connect(defaultColorChooser,
SIGNAL(triggered()),
this,
SLOT(actionChangeDefaultColor()));
// === Action Menu ===
QMenu *mActions = fContextMenu->addMenu("&Actions");
QAction *createEPS = mActions->addAction("Save as ...");
QObject ::connect(createEPS,
SIGNAL(triggered()),
this,
SLOT(actionSaveImage()));
// === Action Menu ===
QAction *movieParameters = mActions->addAction("Save as movie...");
QObject ::connect(movieParameters,
SIGNAL(triggered()),
this,
SLOT(actionMovieParameters()));
// === Special Menu ===
QMenu *mSpecial = fContextMenu->addMenu("S&pecial");
QMenu *mTransparency = mSpecial->addMenu("Transparency");
QAction *transparencyOn = mTransparency->addAction("On");
QAction *transparencyOff = mTransparency->addAction("Off");
if (transparency_enabled == false) {
createRadioAction(transparencyOn,transparencyOff,SLOT(toggleTransparency(bool)),2);
} else if (transparency_enabled == true) {
createRadioAction(transparencyOn,transparencyOff,SLOT(toggleTransparency(bool)),1);
} else {
mSpecial->clear();
}
QMenu *mAntialiasing = mSpecial->addMenu("Antialiasing");
QAction *antialiasingOn = mAntialiasing->addAction("On");
QAction *antialiasingOff = mAntialiasing->addAction("Off");
if (antialiasing_enabled == false) {
createRadioAction(antialiasingOn,antialiasingOff,SLOT(toggleAntialiasing(bool)),2);
} else if (antialiasing_enabled == true) {
createRadioAction(antialiasingOn,antialiasingOff,SLOT(toggleAntialiasing(bool)),1);
} else {
mAntialiasing->clear();
}
QMenu *mHaloing = mSpecial->addMenu("Haloing");
QAction *haloingOn = mHaloing->addAction("On");
QAction *haloingOff = mHaloing->addAction("Off");
if (haloing_enabled == false) {
createRadioAction(haloingOn,haloingOff,SLOT(toggleHaloing(bool)),2);
} else if (haloing_enabled == true) {
createRadioAction(haloingOn,haloingOff,SLOT(toggleHaloing(bool)),1);
} else {
mHaloing->clear();
}
QMenu *mAux = mSpecial->addMenu("Auxiliary edges");
QAction *auxOn = mAux->addAction("On");
QAction *auxOff = mAux->addAction("Off");
if (!fVP.IsAuxEdgeVisible()) {
createRadioAction(auxOn,auxOff,SLOT(toggleAux(bool)),2);
} else {
createRadioAction(auxOn,auxOff,SLOT(toggleAux(bool)),1);
}
QMenu *mHiddenMarkers = mSpecial->addMenu("Hidden markers");
QAction *hiddenMarkersOn = mHiddenMarkers->addAction("On");
QAction *hiddenMarkersOff = mHiddenMarkers->addAction("Off");
if (fVP.IsMarkerNotHidden()) {
createRadioAction(hiddenMarkersOn,hiddenMarkersOff,SLOT(toggleHiddenMarkers(bool)),2);
} else {
createRadioAction(hiddenMarkersOn,hiddenMarkersOff,SLOT(toggleHiddenMarkers(bool)),1);
}
QMenu *mFullScreen = mSpecial->addMenu("&Full screen");
fFullScreenOn = mFullScreen->addAction("On");
fFullScreenOff = mFullScreen->addAction("Off");
createRadioAction(fFullScreenOn,fFullScreenOff,SLOT(toggleFullScreen(bool)),2);
// INIT All
updateToolbarAndMouseContextMenu();
}
void G4OpenGLQtViewer::G4manageContextMenuEvent(QContextMenuEvent *e)
{
if (!fGLWidget) {
G4cerr << "Visualization window not defined, please choose one before" << G4endl;
} else {
if (!fContextMenu)
createPopupMenu();
// launch menu
if ( fContextMenu ) {
fContextMenu->exec( e->globalPos() );
// delete fContextMenu;
}
}
e->accept();
}
/**
Create a radio button menu. The two menu will be connected. When click on one,
eatch state will be invert and callback method will be called.
@param action1 first action to connect
@param action2 second action to connect
@param method callback method
@param nCheck: 1 : first action will be set true. 2 : second action will be set true
*/
void G4OpenGLQtViewer::createRadioAction(QAction *action1,QAction *action2, const std::string& method,unsigned int nCheck) {
action1->setCheckable(true);
action2->setCheckable(true);
if (nCheck ==1)
action1->setChecked (true);
else
action2->setChecked (true);
QObject ::connect(action1, SIGNAL(triggered(bool)),action2, SLOT(toggle()));
QObject ::connect(action2, SIGNAL(triggered(bool)),action1, SLOT(toggle()));
QObject ::connect(action1, SIGNAL(toggled(bool)),this, method.c_str());
}
/**
Show shortcuts for this mouse action
*/
void G4OpenGLQtViewer::showShortcuts() {
G4String text;
text = "========= Mouse Shortcuts =========\n";
if (fUiQt != NULL) {
if (fUiQt->IsIconRotateSelected()) { // rotate
text += "Click and move mouse to rotate volume \n";
text += "ALT + Click and move mouse to rotate volume (Toggle View/Theta-Phi Direction) \n";
text += "CTRL + Click and move mouse to zoom in/out \n";
text += "SHIFT + Click and move mouse to change camera point of view \n";
} else if (fUiQt->IsIconMoveSelected()) { //move
text += "Move camera point of view with mouse \n";
} else if (fUiQt->IsIconPickSelected()) { //pick
text += "Click and pick \n";
}
} else {
text += "Click and move mouse to rotate volume \n";
text += "ALT + Click and move mouse to rotate volume (Toggle View/Theta-Phi Direction) \n";
text += "CTRL + Click and zoom mouse to zoom in/out \n";
text += "SHIFT + Click and zoommove camera point of view \n";
}
text += "========= Move Shortcuts ========= \n";
text += "Press left/right arrows to move volume left/right \n";
text += "Press up/down arrows to move volume up/down \n";
text += "Press '+'/'-' to move volume toward/forward \n";
text += "\n";
text += "========= Rotation (Theta/Phi) Shortcuts ========= \n";
text += "Press SHIFT + left/right arrows to rotate volume left/right \n";
text += "Press SHIFT + up/down arrows to rotate volume up/down \n";
text += "\n";
text += "========= Rotation (View Direction) Shortcuts ========= \n";
text += "Press ALT + left/right to rotate volume around vertical direction \n";
text += "Press ALT + up/down to rotate volume around horizontal direction \n";
text += "\n";
text += "========= Zoom View ========= \n";
text += "Press CTRL + '+'/'-' to zoom into volume \n";
text += "\n";
text += "========= Misc ========= \n";
text += "Press ALT +/- to slow/speed rotation/move \n";
text += "Press H to reset view \n";
text += "Press Esc to exit FullScreen \n";
text += "\n";
text += "========= Video ========= \n";
text += "In video mode : \n";
text += " Press SPACE to Start/Pause video recording \n";
text += " Press RETURN to Stop video recording \n";
text += "\n";
G4cout << text;
if ( fShortcutsDialog == NULL) {
fShortcutsDialog = new QDialog();
fShortcutsDialogInfos = new QTextEdit() ;
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addWidget(fShortcutsDialogInfos);
fShortcutsDialog->setLayout(mainLayout);
fShortcutsDialog->setWindowTitle(tr("Shortcuts"));
}
fShortcutsDialogInfos->setPlainText(text.data());
fShortcutsDialog->show();
}
/**
Slot activated when mouse action is toggle
@param aAction : 1 rotate, 2 move, 3 pick, 4 zoom out, 5 zoom in
@see G4OpenGLStoredQtViewer::DrawView
@see G4XXXStoredViewer::CompareForKernelVisit
*/
void G4OpenGLQtViewer::toggleMouseAction(int aAction) {
if (aAction == 1) {
fUiQt->SetIconRotateSelected();
} else if (aAction == 2) {
fUiQt->SetIconMoveSelected();
} else if (aAction == 3) {
togglePicking();
} else if (aAction == 4) {
fUiQt->SetIconZoomOutSelected();
} else if (aAction == 5) {
fUiQt->SetIconZoomInSelected();
}
updateQWidget();
updateToolbarAndMouseContextMenu();
}
/**
Slot activated when drawing menu is toggle
Warning : When G4OpenGLStoredQtViewer::DrawView() method call,
KernelVisitDecision () will be call and will set the fNeedKernelVisit
to 1. See G4XXXStoredViewer::CompareForKernelVisit for explanations.
It will cause a redraw of the view
@param aAction : 1 wireframe, 2 line removal, 3 surface removal, 4 line & surface removal
@see G4OpenGLStoredQtViewer::DrawView
@see G4XXXStoredViewer::CompareForKernelVisit
*/
void G4OpenGLQtViewer::toggleSurfaceAction(int aAction) {
G4ViewParameters::DrawingStyle d_style = G4ViewParameters::wireframe;
if (aAction ==1) {
d_style = G4ViewParameters::wireframe;
} else if (aAction ==2) {
d_style = G4ViewParameters::hlr;
} else if (aAction ==3) {
d_style = G4ViewParameters::hsr;
} else if (aAction ==4) {
d_style = G4ViewParameters::hlhsr;
}
fVP.SetDrawingStyle(d_style);
updateToolbarAndMouseContextMenu();
updateQWidget();
}
/**
SLOT Activate by a click on the projection menu
Warning : When G4OpenGLStoredQtViewer::DrawView() method call,
KernelVisitDecision () will be call and will set the fNeedKernelVisit
to 1. See G4XXXStoredViewer::CompareForKernelVisit for explanations.
It will cause a redraw of the view
@param check : 1 orthographic, 2 perspective
@see G4OpenGLStoredQtViewer::DrawView
@see G4XXXStoredViewer::CompareForKernelVisit
*/
void G4OpenGLQtViewer::toggleProjection(bool check) {
if (check == 1) {
fVP.SetOrthogonalProjection ();
} else {
fVP.SetPerspectiveProjection();
}
updateToolbarAndMouseContextMenu();
updateQWidget();
}
/**
SLOT Activate by a click on the transparency menu
@param check : 1 , 0
*/
void G4OpenGLQtViewer::toggleTransparency(bool check) {
if (check) {
transparency_enabled = true;
} else {
transparency_enabled = false;
}
SetNeedKernelVisit (true);
updateToolbarAndMouseContextMenu();
updateQWidget();
}
/**
SLOT Activate by a click on the antialiasing menu
@param check : 1 , 0
*/
void G4OpenGLQtViewer::toggleAntialiasing(bool check) {
if (!check) {
antialiasing_enabled = false;
glDisable (GL_LINE_SMOOTH);
glDisable (GL_POLYGON_SMOOTH);
} else {
antialiasing_enabled = true;
glEnable (GL_LINE_SMOOTH);
glHint (GL_LINE_SMOOTH_HINT, GL_NICEST);
glEnable (GL_POLYGON_SMOOTH);
glHint (GL_POLYGON_SMOOTH_HINT, GL_NICEST);
}
updateToolbarAndMouseContextMenu();
updateQWidget();
}
/**
SLOT Activate by a click on the haloing menu
@param check : 1 , 0
*/
//FIXME : I SEE NOTHING...
void G4OpenGLQtViewer::toggleHaloing(bool check) {
if (check) {
haloing_enabled = false;
} else {
haloing_enabled = true;
}
updateToolbarAndMouseContextMenu();
updateQWidget();
}
/**
SLOT Activate by a click on the auxiliaire edges menu
@param check : 1 , 0
*/
void G4OpenGLQtViewer::toggleAux(bool check) {
if (check) {
fVP.SetAuxEdgeVisible(true);
} else {
fVP.SetAuxEdgeVisible(false);
}
SetNeedKernelVisit (true);
updateToolbarAndMouseContextMenu();
updateQWidget();
}
void G4OpenGLQtViewer::togglePicking() {
// FIXME : Not the good way to do, we should handle the multiple cases of Icon/ContextMenu and CheckBox in a better way
if (fUiQt) {
if (!fVP.IsPicking()) {
fUiQt->SetIconPickSelected();
} else {
fUiQt->SetIconRotateSelected();
}
}
G4UImanager* UI = G4UImanager::GetUIpointer();
if(UI != NULL) {
if (!fVP.IsPicking()) {
UI->ApplyCommand(std::string("/vis/viewer/set/picking true"));
} else {
UI->ApplyCommand(std::string("/vis/viewer/set/picking false"));
}
}
}
/**
SLOT Activate by a click on the hidden marker menu
@param check : 1 , 0
*/
void G4OpenGLQtViewer::toggleHiddenMarkers(bool check) {
if (check) {
fVP.SetMarkerHidden();
} else {
fVP.SetMarkerNotHidden();
}
// SetNeedKernelVisit (true);
updateToolbarAndMouseContextMenu();
updateQWidget();
}
/**
SLOT Activate by a click on the full screen menu
*/
void G4OpenGLQtViewer::toggleFullScreen(bool check) {
if (check != fGLWidget->isFullScreen()) { //toggle
fGLWidget->setWindowState(fGLWidget->windowState() ^ Qt::WindowFullScreen);
}
}
void G4OpenGLQtViewer::savePPMToTemp() {
if (fMovieTempFolderPath == "") {
return;
}
QGLWidget* qGLW = dynamic_cast<QGLWidget*> (fGLWidget) ;
if (! qGLW) {
return;
}
QString fileName ="Test"+QString::number(fRecordFrameNumber)+".ppm";
QString filePath =fMovieTempFolderPath+fileName;
QImage image;
image = qGLW->grabFrameBuffer();
bool res = false;
res = image.save(filePath,0);
if (res == false) {
resetRecording();
setRecordingInfos("Can't save tmp file "+filePath);
return;
}
setRecordingInfos("File "+fileName+" saved");
fRecordFrameNumber++;
}
void G4OpenGLQtViewer::actionSaveImage() {
QString filters;
for (unsigned int i = 0; i < fExportImageFormatVector.size(); ++i) {
filters += QString("*.") + fExportImageFormatVector.at(i).c_str() + ";;";
}
QString* selectedFormat = new QString(fDefaultExportImageFormat.c_str());
QString qFilename;
qFilename = QFileDialog::getSaveFileName ( fGLWidget,
tr("Save as ..."),
fFileSavePath,
filters,
selectedFormat );
std::string name = qFilename.toStdString().c_str();
// bmp jpg jpeg png ppm xbm xpm
if (name.empty()) {
return;
}
fFileSavePath = QFileInfo(qFilename).path();
std::string format = selectedFormat->toLower().toStdString().c_str();
// set the format to current
fExportImageFormat = format.substr(format.find_last_of(".") + 1);
std::string filename = name;
std::string extension = "";
if (name.find_last_of(".") != std::string::npos) {
filename = name.substr(0,name.find_last_of(".") + 1);
extension = name.substr(name.find_last_of(".") + 1);
} else {
extension = fExportImageFormat;
}
filename+= "."+ extension;
if (!setExportFilename(filename.c_str(),0)) {
return;
}
G4OpenGLQtExportDialog* exportDialog= new G4OpenGLQtExportDialog(fGLWidget,format.c_str(),fGLWidget->height(),fGLWidget->width());
if( exportDialog->exec()) {
if ((exportDialog->getWidth() !=fGLWidget->width()) ||
(exportDialog->getHeight() !=fGLWidget->height())) {
setExportSize(exportDialog->getWidth(),exportDialog->getHeight());
}
if (fExportImageFormat == "eps") {
fVectoredPs = exportDialog->getVectorEPS();
} else if (fExportImageFormat == "ps") {
fVectoredPs = true;
}
fLastExportSliderValue = exportDialog->getSliderValue();
if (exportImage(filename)) {
// set the default format to current
fDefaultExportImageFormat = format;
}
} else { // cancel selected
return;
}
}
void G4OpenGLQtViewer::actionChangeBackgroundColor() {
// //I need to revisit the kernel if the background colour changes and
// //hidden line removal is enabled, because hlr drawing utilises the
// //background colour in its drawing...
// // (Note added by JA 13/9/2005) Background now handled in view
// // parameters. A kernel visit is triggered on change of background.
#if QT_VERSION < 0x040500
bool a;
const QColor color = QColor(QColorDialog::getRgba (QColor(Qt::black).rgba(),&a,fGLWidget));
#else
const QColor color =
QColorDialog::getColor(Qt::black,
fGLWidget,
" Get background color and transparency",
QColorDialog::ShowAlphaChannel);
#endif
if (color.isValid()) {
G4Colour colour(((G4double)color.red())/255,
((G4double)color.green())/255,
((G4double)color.blue())/255,
((G4double)color.alpha())/255);
fVP.SetBackgroundColour(colour);
updateToolbarAndMouseContextMenu();
updateQWidget();
}
}
void G4OpenGLQtViewer::actionChangeTextColor() {
#if QT_VERSION < 0x040500
bool a;
const QColor color = QColor(QColorDialog::getRgba (QColor(Qt::yellow).rgba(),&a,fGLWidget));
#else
const QColor& color =
QColorDialog::getColor(Qt::yellow,
fGLWidget,
" Get text color and transparency",
QColorDialog::ShowAlphaChannel);
#endif
if (color.isValid()) {
G4Colour colour(((G4double)color.red())/255,
((G4double)color.green())/255,
((G4double)color.blue())/255,
((G4double)color.alpha())/255);
fVP.SetDefaultTextColour(colour);
updateToolbarAndMouseContextMenu();
updateQWidget();
}
}
void G4OpenGLQtViewer::actionChangeDefaultColor() {
#if QT_VERSION < 0x040500
bool a;
const QColor color = QColor(QColorDialog::getRgba (QColor(Qt::white).rgba(),&a,fGLWidget));
#else
const QColor& color =
QColorDialog::getColor(Qt::white,
fGLWidget,
" Get default color and transparency",
QColorDialog::ShowAlphaChannel);
#endif
if (color.isValid()) {
G4Colour colour(((G4double)color.red())/255,
((G4double)color.green())/255,
((G4double)color.blue())/255,
((G4double)color.alpha())/255);
fVP.SetDefaultColour(colour);
updateToolbarAndMouseContextMenu();
updateQWidget();
}
}
void G4OpenGLQtViewer::actionMovieParameters() {
showMovieParametersDialog();
}
void G4OpenGLQtViewer::showMovieParametersDialog() {
if (!fMovieParametersDialog) {
fMovieParametersDialog= new G4OpenGLQtMovieDialog(this,fGLWidget);
displayRecordingStatus();
fMovieParametersDialog->checkEncoderSwParameters();
fMovieParametersDialog->checkSaveFileNameParameters();
fMovieParametersDialog->checkTempFolderParameters();
if (getEncoderPath() == "") {
setRecordingInfos("ppmtompeg is needed to encode in video format. It is available here: http://netpbm.sourceforge.net ");
}
}
fMovieParametersDialog->show();
}
void G4OpenGLQtViewer::FinishView()
{
/* From Apple doc:
CGLFlushDrawable : Copies the back buffer of a double-buffered context to the front buffer.
If the backing store attribute is set to false, the buffers can be exchanged rather than copied
*/
glFlush ();
// L. Garnier 10/2009 : Not necessary and cause problems on mac OS X 10.6
// fGLWidget->swapBuffers ();
}
/**
Save the current mouse press point
@param p mouse click point
*/
void G4OpenGLQtViewer::G4MousePressEvent(QMouseEvent *evnt)
{
if (evnt->button() == Qt::RightButton) {
return;
}
if ((evnt->button() & Qt::LeftButton) && (! (evnt->modifiers() & Qt::ControlModifier ))){
fGLWidget->setMouseTracking(true);
fAutoMove = false; // stop automove
fLastPos1 = evnt->pos();
fLastPos2 = fLastPos1;
fLastPos3 = fLastPos2;
fLastEventTime->start();
if (fUiQt != NULL) {
if (fUiQt->IsIconZoomInSelected()) { // zoomIn
// Move click point to center of OGL
float deltaX = ((float)getWinWidth()/2-evnt->pos().x());
float deltaY = ((float)getWinHeight()/2-evnt->pos().y());
G4double coefTrans = 0;
coefTrans = ((G4double)getSceneNearWidth())/((G4double)getWinWidth());
if (getWinHeight() <getWinWidth()) {
coefTrans = ((G4double)getSceneNearWidth())/((G4double)getWinHeight());
}
fVP.IncrementPan(-deltaX*coefTrans,deltaY*coefTrans,0);
fVP.SetZoomFactor(1.5 * fVP.GetZoomFactor());
updateQWidget();
} else if (fUiQt->IsIconZoomOutSelected()) { // zoomOut
// Move click point to center of OGL
moveScene(((float)getWinWidth()/2-evnt->pos().x()),((float)getWinHeight()/2-evnt->pos().y()),0,true);
fVP.SetZoomFactor(0.75 * fVP.GetZoomFactor());
updateQWidget();
} else if (fUiQt->IsIconRotateSelected() ) {
if (fShiftKeyPress) { // move
fGLWidget->setCursor(QCursor(Qt::SizeAllCursor));
} else { // rotate
fGLWidget->setCursor(QCursor(Qt::ClosedHandCursor));
}
} else if (fUiQt->IsIconMoveSelected()) {
fGLWidget->setCursor(QCursor(Qt::SizeAllCursor));
} else if (fUiQt->IsIconPickSelected()) {
fGLWidget->setCursor(QCursor(Qt::PointingHandCursor));
}
}
}
}
/**
*/
void G4OpenGLQtViewer::G4MouseReleaseEvent(QMouseEvent *evnt)
{
GLint viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);
// factorX == factorY
double factorX = ((double)viewport[2]/fGLWidget->width());
double factorY = ((double)viewport[3]/fGLWidget->height());
fSpinningDelay = fLastEventTime->elapsed();
QPoint delta = (fLastPos3-fLastPos1)*factorX;
// reset cursor state
fGLWidget->setCursor(QCursor(Qt::ArrowCursor));
if (fVP.IsPicking()){ // pick
if ((delta.x() != 0) || (delta.y() != 0)) {
return;
}
updatePickInfosWidget(evnt->pos().x()*factorX,evnt->pos().y()*factorY);
} else if (fSpinningDelay < fLaunchSpinDelay ) {
if ((delta.x() == 0) && (delta.y() == 0)) {
return;
}
fAutoMove = true;
QTime lastMoveTime;
lastMoveTime.start();
// try to addapt speed move/rotate looking to drawing speed
float correctionFactor = 5;
while (fAutoMove) {
if ( lastMoveTime.elapsed() >= (int)(1000/fNbMaxFramesPerSec)) {
float lTime = 1000/lastMoveTime.elapsed();
if (((((float)delta.x())/correctionFactor)*lTime > fNbMaxAnglePerSec) ||
((((float)delta.x())/correctionFactor)*lTime < -fNbMaxAnglePerSec) ) {
correctionFactor = (float)delta.x()*(lTime/fNbMaxAnglePerSec);
if (delta.x() <0 ) {
correctionFactor = -correctionFactor;
}
}
if (((((float)delta.y())/correctionFactor)*lTime > fNbMaxAnglePerSec) ||
((((float)delta.y())/correctionFactor)*lTime < -fNbMaxAnglePerSec) ) {
correctionFactor = (float)delta.y()*(lTime/fNbMaxAnglePerSec);
if (delta.y() <0 ) {
correctionFactor = -correctionFactor;
}
}
// Check Qt Versions for META Keys
// Click and move mouse to rotate volume
// ALT + Click and move mouse to rotate volume (View Direction)
// SHIFT + Click and move camera point of view
// CTRL + Click and zoom mouse to zoom in/out
lastMoveTime.start();
bool rotate = false;
bool move = false;
if (fUiQt != NULL) {
if (fUiQt->IsIconRotateSelected()) { // rotate
rotate = true;
} else if (fUiQt->IsIconMoveSelected()) { // move
move = true;
}
} else {
rotate = true;
}
// prevent from closing widget when rotating (cause a crash)
if (fIsDeleting) {
return;
}
if (rotate) { // rotate
if (fNoKeyPress) {
rotateQtScene(((float)delta.x())/correctionFactor,((float)delta.y())/correctionFactor);
} else if (fAltKeyPress) {
rotateQtSceneToggle(((float)delta.x())/correctionFactor,((float)delta.y())/correctionFactor);
}
} else if (move) { // move
moveScene(-((float)delta.x())/correctionFactor,-((float)delta.y())/correctionFactor,0,true);
}
}
((QApplication*)G4Qt::getInstance ())->processEvents();
}
}
fGLWidget->setMouseTracking(false);
}
void G4OpenGLQtViewer::G4MouseDoubleClickEvent()
{
fGLWidget->setMouseTracking(true);
}
/**
@param pos_x mouse x position
@param pos_y mouse y position
@param mButtons mouse button active
@param mAutoMove true: apply this move till another evnt came, false :one time move
*/
void G4OpenGLQtViewer::G4MouseMoveEvent(QMouseEvent *evnt)
{
Qt::MouseButtons mButtons = evnt->buttons();
updateKeyModifierState(evnt->modifiers());
if (fAutoMove) {
return;
}
fLastPos3 = fLastPos2;
fLastPos2 = fLastPos1;
fLastPos1 = QPoint(evnt->x(), evnt->y());
int deltaX = fLastPos2.x()-fLastPos1.x();
int deltaY = fLastPos2.y()-fLastPos1.y();
bool move = false;
if (fUiQt != NULL) {
if (fUiQt->IsIconMoveSelected()) { // move
move = true;
}
}
if (!move) { // rotate, pick, zoom...
if (mButtons & Qt::LeftButton) {
if (fNoKeyPress) {
rotateQtScene(((float)deltaX),((float)deltaY));
} else if (fAltKeyPress) {
rotateQtSceneToggle(((float)deltaX),((float)deltaY));
} else if (fShiftKeyPress) {
unsigned int sizeWin;
sizeWin = getWinWidth();
if (getWinHeight() < getWinWidth()) {
sizeWin = getWinHeight();
}
// L.Garnier : 08/2010 100 is the good value, but don't ask me why !
float factor = ((float)100/(float)sizeWin) ;
moveScene(-(float)deltaX*factor,-(float)deltaY*factor,0,false);
} else if (fControlKeyPress) {
fVP.SetZoomFactor(fVP.GetZoomFactor()*(1+((float)deltaY)));
}
}
} else if (move) { // move
if (mButtons & Qt::LeftButton) {
moveScene(-(float)deltaX,-(float)deltaY,0,true);
}
}
fLastEventTime->start();
}
/**
Move the scene of dx, dy, dz values.
@param dx delta mouse x position
@param dy delta mouse y position
@param mouseMove : true if event comes from a mouse move, false if event comes from key action
*/
void G4OpenGLQtViewer::moveScene(float dx,float dy, float dz,bool mouseMove)
{
if (fHoldMoveEvent)
return;
fHoldMoveEvent = true;
G4double coefTrans = 0;
GLdouble coefDepth = 0;
if(mouseMove) {
coefTrans = ((G4double)getSceneNearWidth())/((G4double)getWinWidth());
if (getWinHeight() <getWinWidth()) {
coefTrans = ((G4double)getSceneNearWidth())/((G4double)getWinHeight());
}
} else {
coefTrans = getSceneNearWidth()*fPan_sens;
coefDepth = getSceneDepth()*fDeltaDepth;
}
fVP.IncrementPan(-dx*coefTrans,dy*coefTrans,dz*coefDepth);
updateQWidget();
if (fAutoMove)
((QApplication*)G4Qt::getInstance ())->processEvents();
fHoldMoveEvent = false;
}
/**
@param dx delta mouse x position
@param dy delta mouse y position
*/
void G4OpenGLQtViewer::rotateQtScene(float dx, float dy)
{
if (fHoldRotateEvent)
return;
fHoldRotateEvent = true;
rotateScene(dx,dy);
updateQWidget();
fHoldRotateEvent = false;
}
/**
@param dx delta mouse x position
@param dy delta mouse y position
*/
void G4OpenGLQtViewer::rotateQtSceneToggle(float dx, float dy)
{
if (fHoldRotateEvent)
return;
fHoldRotateEvent = true;
rotateSceneToggle(dx,dy);
updateQWidget();
fHoldRotateEvent = false;
}
/** This is the benning of a rescale function. It does nothing for the moment
@param aWidth : new width
@param aHeight : new height
*/
void G4OpenGLQtViewer::rescaleImage(
int /* aWidth */
,int /* aHeight */
){
// GLfloat* feedback_buffer;
// GLint returned;
// FILE* file;
// feedback_buffer = new GLfloat[size];
// glFeedbackBuffer (size, GL_3D_COLOR, feedback_buffer);
// glRenderMode (GL_FEEDBACK);
// DrawView();
// returned = glRenderMode (GL_RENDER);
}
void G4OpenGLQtViewer::G4wheelEvent (QWheelEvent * evnt)
{
fVP.SetZoomFactor(fVP.GetZoomFactor()+(fVP.GetZoomFactor()*(evnt->delta())/1200));
updateQWidget();
}
void G4OpenGLQtViewer::G4keyPressEvent (QKeyEvent * evnt)
{
if (fHoldKeyEvent)
return;
fHoldKeyEvent = true;
// with no modifiers
updateKeyModifierState(evnt->modifiers());
if ((fNoKeyPress) || (evnt->modifiers() == Qt::KeypadModifier )) {
if (evnt->key() == Qt::Key_Down) { // go down
moveScene(0,1,0,false);
}
else if (evnt->key() == Qt::Key_Up) { // go up
moveScene(0,-1,0,false);
}
if (evnt->key() == Qt::Key_Left) { // go left
moveScene(-1,0,0,false);
}
else if (evnt->key() == Qt::Key_Right) { // go right
moveScene(1,0,0,false);
}
if (evnt->key() == Qt::Key_Minus) { // go backward
moveScene(0,0,1,false);
}
else if (evnt->key() == Qt::Key_Plus) { // go forward
moveScene(0,0,-1,false);
}
// escaped from full screen
if (evnt->key() == Qt::Key_Escape) {
toggleFullScreen(false);
}
}
// several case here : If return is pressed, in every case -> display the movie parameters dialog
// If one parameter is wrong -> put it in red (only save filenam could be wrong..)
// If encoder not found-> does nothing.Only display a message in status box
// If all ok-> generate parameter file
// If ok -> put encoder button enabled
if ((evnt->key() == Qt::Key_Return) || (evnt->key() == Qt::Key_Enter)){ // end of video
stopVideo();
}
if (evnt->key() == Qt::Key_Space){ // start/pause of video
startPauseVideo();
}
// H : Return Home view
if (evnt->key() == Qt::Key_H){ // go Home
ResetView();
updateQWidget();
}
// Shift Modifier
if (fShiftKeyPress) {
fGLWidget->setCursor(QCursor(Qt::SizeAllCursor));
if (evnt->key() == Qt::Key_Down) { // rotate phi
rotateQtScene(0,-fRot_sens);
}
else if (evnt->key() == Qt::Key_Up) { // rotate phi
rotateQtScene(0,fRot_sens);
}
if (evnt->key() == Qt::Key_Left) { // rotate theta
rotateQtScene(fRot_sens,0);
}
else if (evnt->key() == Qt::Key_Right) { // rotate theta
rotateQtScene(-fRot_sens,0);
}
if (evnt->key() == Qt::Key_Plus) { // go forward ("Plus" imply
// "Shift" on Mac French keyboard
moveScene(0,0,-1,false);
}
// Alt Modifier
}
if ((fAltKeyPress)) {
fGLWidget->setCursor(QCursor(Qt::ClosedHandCursor));
if (evnt->key() == Qt::Key_Down) { // rotate phi
rotateQtSceneToggle(0,-fRot_sens);
}
else if (evnt->key() == Qt::Key_Up) { // rotate phi
rotateQtSceneToggle(0,fRot_sens);
}
if (evnt->key() == Qt::Key_Left) { // rotate theta
rotateQtSceneToggle(fRot_sens,0);
}
else if (evnt->key() == Qt::Key_Right) { // rotate theta
rotateQtSceneToggle(-fRot_sens,0);
}
// Rotatio +/-
if (evnt->key() == Qt::Key_Plus) {
fRot_sens = fRot_sens/0.7;
G4cout << "Auto-rotation set to : " << fRot_sens << G4endl;
}
else if (evnt->key() == Qt::Key_Minus) {
fRot_sens = fRot_sens*0.7;
G4cout << "Auto-rotation set to : " << fRot_sens << G4endl;
}
// Control Modifier OR Command on MAC
}
if ((fControlKeyPress)) {
if (evnt->key() == Qt::Key_Plus) {
fVP.SetZoomFactor(fVP.GetZoomFactor()*(1+fDeltaZoom));
updateQWidget();
}
else if (evnt->key() == Qt::Key_Minus) {
fVP.SetZoomFactor(fVP.GetZoomFactor()*(1-fDeltaZoom));
updateQWidget();
}
}
fHoldKeyEvent = false;
}
void G4OpenGLQtViewer::G4keyReleaseEvent (QKeyEvent *)
{
fGLWidget->setCursor(QCursor(Qt::ArrowCursor));
}
void G4OpenGLQtViewer::updateKeyModifierState(const Qt::KeyboardModifiers& modifier) {
// Check Qt Versions for META Keys
fNoKeyPress = true;
fAltKeyPress = false;
fShiftKeyPress = false;
fControlKeyPress = false;
if (modifier & Qt::AltModifier ) {
fAltKeyPress = true;
fNoKeyPress = false;
}
if (modifier & Qt::ShiftModifier ) {
fShiftKeyPress = true;
fNoKeyPress = false;
}
if (modifier & Qt::ControlModifier ) {
fControlKeyPress = true;
fNoKeyPress = false;
}
}
/** Stop the video. Check all parameters and enable encoder button if all is ok.
*/
void G4OpenGLQtViewer::stopVideo() {
// if encoder parameter is wrong, display parameters dialog and return
if (!fMovieParametersDialog) {
showMovieParametersDialog();
}
setRecordingStatus(STOP);
if (fRecordFrameNumber >0) {
// check parameters if they were modified (Re APPLY them...)
if (!(fMovieParametersDialog->checkEncoderSwParameters())) {
setRecordingStatus(BAD_ENCODER);
} else if (!(fMovieParametersDialog->checkSaveFileNameParameters())) {
setRecordingStatus(BAD_OUTPUT);
}
} else {
resetRecording();
setRecordingInfos("No frame to encode.");
}
}
/** Stop the video. Check all parameters and enable encoder button if all is ok.
*/
void G4OpenGLQtViewer::saveVideo() {
// if encoder parameter is wrong, display parameters dialog and return
if (!fMovieParametersDialog) {
showMovieParametersDialog();
}
fMovieParametersDialog->checkEncoderSwParameters();
fMovieParametersDialog->checkSaveFileNameParameters();
if (fRecordingStep == STOP) {
setRecordingStatus(SAVE);
generateMpegEncoderParameters();
encodeVideo();
}
}
/** Start/Pause the video..
*/
void G4OpenGLQtViewer::startPauseVideo() {
// first time, if temp parameter is wrong, display parameters dialog and return
if ( fRecordingStep == WAIT) {
if ( fRecordFrameNumber == 0) {
if (getTempFolderPath() == "") { // BAD_OUTPUT
showMovieParametersDialog();
setRecordingInfos("You should specified the temp folder in order to make movie");
return;
} else {
// remove temp folder if it was create
QString tmp = removeTempFolder();
if (tmp !="") {
setRecordingInfos(tmp);
return;
}
tmp = createTempFolder();
if (tmp != "") {
setRecordingInfos("Can't create temp folder."+tmp);
return;
}
}
}
}
if (fRecordingStep == WAIT) {
setRecordingStatus(START);
} else if (fRecordingStep == START) {
setRecordingStatus(PAUSE);
} else if (fRecordingStep == PAUSE) {
setRecordingStatus(CONTINUE);
} else if (fRecordingStep == CONTINUE) {
setRecordingStatus(PAUSE);
}
}
void G4OpenGLQtViewer::setRecordingStatus(RECORDING_STEP step) {
fRecordingStep = step;
displayRecordingStatus();
}
void G4OpenGLQtViewer::displayRecordingStatus() {
QString txtStatus = "";
if (fRecordingStep == WAIT) {
txtStatus = "Waiting to start...";
fRecordFrameNumber = 0; // reset the frame number
} else if (fRecordingStep == START) {
txtStatus = "Start Recording...";
} else if (fRecordingStep == PAUSE) {
txtStatus = "Pause Recording...";
} else if (fRecordingStep == CONTINUE) {
txtStatus = "Continue Recording...";
} else if (fRecordingStep == STOP) {
txtStatus = "Stop Recording...";
} else if (fRecordingStep == READY_TO_ENCODE) {
txtStatus = "Ready to Encode...";
} else if (fRecordingStep == ENCODING) {
txtStatus = "Encoding...";
} else if (fRecordingStep == FAILED) {
txtStatus = "Failed to encode...";
} else if ((fRecordingStep == BAD_ENCODER)
|| (fRecordingStep == BAD_OUTPUT)
|| (fRecordingStep == BAD_TMP)) {
txtStatus = "Correct above errors first";
} else if (fRecordingStep == SUCCESS) {
txtStatus = "File encoded successfully";
} else {
}
if (fMovieParametersDialog) {
fMovieParametersDialog->setRecordingStatus(txtStatus);
} else {
G4cout << txtStatus.toStdString().c_str() << G4endl;
}
setRecordingInfos("");
}
void G4OpenGLQtViewer::setRecordingInfos(const QString& txt) {
if (fMovieParametersDialog) {
fMovieParametersDialog->setRecordingInfos(txt);
} else {
G4cout << txt.toStdString().c_str() << G4endl;
}
}
/** Init the movie parameters. Temp dir and encoder path
*/
void G4OpenGLQtViewer::initMovieParameters() {
//init encoder
//look for encoderPath
fProcess = new QProcess();
QObject ::connect(fProcess,SIGNAL(finished ( int)),
this,SLOT(processLookForFinished()));
fProcess->setReadChannelMode(QProcess::MergedChannels);
fProcess->start ("which ppmtompeg");
}
/** @return encoder path or "" if it does not exist
*/
QString G4OpenGLQtViewer::getEncoderPath() {
return fEncoderPath;
}
/**
* set the new encoder path
* @return "" if correct. The error otherwise
*/
QString G4OpenGLQtViewer::setEncoderPath(QString path) {
if (path == "") {
return "ppmtompeg is needed to encode in video format. It is available here: http://netpbm.sourceforge.net ";
}
path = QDir::cleanPath(path);
QFileInfo *f = new QFileInfo(path);
if (!f->exists()) {
return "File does not exist";
} else if (f->isDir()) {
return "This is a directory";
} else if (!f->isExecutable()) {
return "File exist but is not executable";
} else if (!f->isFile()) {
return "This is not a file";
}
fEncoderPath = path;
if (fRecordingStep == BAD_ENCODER) {
setRecordingStatus(STOP);
}
return "";
}
bool G4OpenGLQtViewer::isRecording(){
if ((fRecordingStep == START) || (fRecordingStep == CONTINUE)) {
return true;
}
return false;
}
bool G4OpenGLQtViewer::isPaused(){
if (fRecordingStep == PAUSE) {
return true;
}
return false;
}
bool G4OpenGLQtViewer::isEncoding(){
if (fRecordingStep == ENCODING) {
return true;
}
return false;
}
bool G4OpenGLQtViewer::isWaiting(){
if (fRecordingStep == WAIT) {
return true;
}
return false;
}
bool G4OpenGLQtViewer::isStopped(){
if (fRecordingStep == STOP) {
return true;
}
return false;
}
bool G4OpenGLQtViewer::isFailed(){
if (fRecordingStep == FAILED) {
return true;
}
return false;
}
bool G4OpenGLQtViewer::isSuccess(){
if (fRecordingStep == SUCCESS) {
return true;
}
return false;
}
bool G4OpenGLQtViewer::isBadEncoder(){
if (fRecordingStep == BAD_ENCODER) {
return true;
}
return false;
}
bool G4OpenGLQtViewer::isBadTmp(){
if (fRecordingStep == BAD_TMP) {
return true;
}
return false;
}
bool G4OpenGLQtViewer::isBadOutput(){
if (fRecordingStep == BAD_OUTPUT) {
return true;
}
return false;
}
void G4OpenGLQtViewer::setBadEncoder(){
fRecordingStep = BAD_ENCODER;
displayRecordingStatus();
}
void G4OpenGLQtViewer::setBadTmp(){
fRecordingStep = BAD_TMP;
displayRecordingStatus();
}
void G4OpenGLQtViewer::setBadOutput(){
fRecordingStep = BAD_OUTPUT;
displayRecordingStatus();
}
void G4OpenGLQtViewer::setWaiting(){
fRecordingStep = WAIT;
displayRecordingStatus();
}
bool G4OpenGLQtViewer::isReadyToEncode(){
if (fRecordingStep == READY_TO_ENCODE) {
return true;
}
return false;
}
void G4OpenGLQtViewer::resetRecording() {
setRecordingStatus(WAIT);
}
/**
* set the temp folder path
* @return "" if correct. The error otherwise
*/
QString G4OpenGLQtViewer::setTempFolderPath(QString path) {
if (path == "") {
return "Path does not exist";
}
path = QDir::cleanPath(path);
QFileInfo *d = new QFileInfo(path);
if (!d->exists()) {
return "Path does not exist";
} else if (!d->isDir()) {
return "This is not a directory";
} else if (!d->isReadable()) {
return path +" is read protected";
} else if (!d->isWritable()) {
return path +" is write protected";
}
if (fRecordingStep == BAD_TMP) {
setRecordingStatus(WAIT);
}
fTempFolderPath = path;
return "";
}
/** @return the temp folder path or "" if it does not exist
*/
QString G4OpenGLQtViewer::getTempFolderPath() {
return fTempFolderPath;
}
/**
* set the save file name path
* @return "" if correct. The error otherwise
*/
QString G4OpenGLQtViewer::setSaveFileName(QString path) {
if (path == "") {
return "Path does not exist";
}
QFileInfo *file = new QFileInfo(path);
QDir dir = file->dir();
path = QDir::cleanPath(path);
if (file->exists()) {
return "File already exist, please choose a new one";
} else if (!dir.exists()) {
return "Dir does not exist";
} else if (!dir.isReadable()) {
return path +" is read protected";
}
if (fRecordingStep == BAD_OUTPUT) {
setRecordingStatus(STOP);
}
fSaveFileName = path;
return "";
}
/** @return the save file path
*/
QString G4OpenGLQtViewer::getSaveFileName() {
return fSaveFileName ;
}
/** Create a Qt_temp folder in the temp folder given
* The temp folder will be like this /tmp/QtMovie_12-02-2008_12_12_58/
* @return "" if success. Error message if not.
*/
QString G4OpenGLQtViewer::createTempFolder() {
fMovieTempFolderPath = "";
//check
QString tmp = setTempFolderPath(fTempFolderPath);
if (tmp != "") {
return tmp;
}
QString sep = QString(QDir::separator());
QString path = sep+"QtMovie_"+QDateTime::currentDateTime ().toString("dd-MM-yyyy_hh-mm-ss")+sep;
QDir *d = new QDir(QDir::cleanPath(fTempFolderPath));
// check if it is already present
if (d->exists(path)) {
return "Folder "+path+" already exists.Please remove it first";
}
if (d->mkdir(fTempFolderPath+path)) {
fMovieTempFolderPath = fTempFolderPath+path;
return "";
}
return "Can't create "+fTempFolderPath+path;
}
/** Remove the Qt_temp folder in the temp folder
*/
QString G4OpenGLQtViewer::removeTempFolder() {
// remove files in Qt_temp folder
if (fMovieTempFolderPath == "") {
return "";
}
QDir *d = new QDir(QDir::cleanPath(fMovieTempFolderPath));
if (!d->exists()) {
return ""; // already remove
}
d->setFilter( QDir::Files );
QStringList subDirList = d->entryList();
int res = true;
QString error = "";
for (QStringList::ConstIterator it = subDirList.begin() ;(it != subDirList.end()) ; it++) {
const QString currentFile = *it;
if (!d->remove(currentFile)) {
res = false;
QString file = fMovieTempFolderPath+currentFile;
error +="Removing file failed : "+file;
} else {
}
}
if (res) {
if (d->rmdir(fMovieTempFolderPath)) {
fMovieTempFolderPath = "";
return "";
} else {
return "Dir "+fMovieTempFolderPath+" should be empty, but could not remove it";
}
}
return "Could not remove "+fMovieTempFolderPath+" because of the following errors :"+error;
}
/**
Export image. Try to get the format according to the file extention.
If not present, the last one choosen by /vis/ogl/set/exportFormat
If not, will take the default format : eps
Best format actually available is pdf (vectored and allow transparency)
If name is not set, it will take the default name value given by /vis/ogl/set/printFilename
*/
bool G4OpenGLQtViewer::exportImage(std::string name, int width, int height) {
QGLWidget* qGLW = dynamic_cast<QGLWidget*> (fGLWidget) ;
if (! qGLW) {
return false;
}
// If there is already an extention
bool increaseFileNumber = true;
// if
if (name.size() != name.substr(name.find_last_of(".") + 1).size()) {
increaseFileNumber = false;
}
if (! setExportFilename(name,increaseFileNumber)) {
return false;
}
if ((width !=-1) && (height != -1)) {
setExportSize(width, height);
}
// first, try to do it with generic function
if (G4OpenGLViewer::exportImage(name, width, height)) {
return true;
// Then try Qt saving functions
} else {
QImage image;
image = qGLW->grabFrameBuffer();
bool res = image.save(QString(getRealPrintFilename().c_str()),0,fLastExportSliderValue);
if (!res) {
G4cerr << "Error saving file... " << getRealPrintFilename().c_str() << G4endl;
return false;
} else {
G4cout << "File " << getRealPrintFilename().c_str() << " size: " << fGLWidget->width() << "x" << fGLWidget->height() << " has been saved " << G4endl;
fExportFilenameIndex++;
}
}
return true;
}
bool G4OpenGLQtViewer::hasPendingEvents () {
return ((QApplication*)G4Qt::getInstance ())->hasPendingEvents ();
}
bool G4OpenGLQtViewer::generateMpegEncoderParameters () {
// save the parameter file
FILE* fp;
fp = fopen (QString(fMovieTempFolderPath+fParameterFileName).toStdString().c_str(), "w");
if (fp == NULL) {
setRecordingInfos("Generation of parameter file failed");
return false;
}
fprintf (fp,"# Pattern affects speed, quality and compression. See the User's Guide\n");
fprintf (fp,"# for more info.\n");
fprintf (fp,"\n");
fprintf (fp,"PATTERN I\n");
fprintf (fp,"OUTPUT %s\n",getSaveFileName().toStdString().c_str());
fprintf (fp,"\n");
fprintf (fp,"# You must specify the type of the input files. The choices are:\n");
fprintf (fp,"# YUV, PPM, JMOVIE, Y, JPEG, PNM\n");
fprintf (fp,"# (must be upper case)\n");
fprintf (fp,"#\n");
fprintf (fp,"BASE_FILE_FORMAT PPM\n");
fprintf (fp,"\n");
fprintf (fp,"\n");
fprintf (fp,"# If you are using YUV, there are different supported file formats.\n");
fprintf (fp,"# EYUV or UCB are the same as previous versions of this encoder.\n");
fprintf (fp,"# (All the Y's, then U's then V's, in 4:2:0 subsampling.)\n");
fprintf (fp,"# Other formats, such as Abekas, Phillips, or a general format are\n");
fprintf (fp,"# permissible, the general format is a string of Y's, U's, and V's\n");
fprintf (fp,"# to specify the file order.\n");
fprintf (fp,"\n");
fprintf (fp,"INPUT_FORMAT UCB\n");
fprintf (fp,"\n");
fprintf (fp,"# the conversion statement\n");
fprintf (fp,"#\n");
fprintf (fp,"# Each occurrence of '*' will be replaced by the input file\n");
fprintf (fp,"#\n");
fprintf (fp,"# e.g., if you have a bunch of GIF files, then this might be:\n");
fprintf (fp,"# INPUT_CONVERT giftoppm *\n");
fprintf (fp,"#\n");
fprintf (fp,"# e.g., if you have a bunch of files like a.Y a.U a.V, etc., then:\n");
fprintf (fp,"# INPUT_CONVERT cat *.Y *.U *.V\n");
fprintf (fp,"#\n");
fprintf (fp,"# e.g., if you are grabbing from laser disc you might have something like\n");
fprintf (fp,"# INPUT_CONVERT goto frame *; grabppm\n");
fprintf (fp,"# 'INPUT_CONVERT *' means the files are already in the base file format\n");
fprintf (fp,"#\n");
fprintf (fp,"INPUT_CONVERT * \n");
fprintf (fp,"\n");
fprintf (fp,"# number of frames in a GOP.\n");
fprintf (fp,"#\n");
fprintf (fp,"# since each GOP must have at least one I-frame, the encoder will find the\n");
fprintf (fp,"# the first I-frame after GOP_SIZE frames to start the next GOP\n");
fprintf (fp,"#\n");
fprintf (fp,"# later, will add more flexible GOP signalling\n");
fprintf (fp,"#\n");
fprintf (fp,"GOP_SIZE 1\n");
fprintf (fp,"\n");
fprintf (fp,"# number of slices in a frame\n");
fprintf (fp,"#\n");
fprintf (fp,"# 1 is a good number. another possibility is the number of macroblock rows\n");
fprintf (fp,"# (which is the height divided by 16)\n");
fprintf (fp,"#\n");
fprintf (fp,"SLICES_PER_FRAME 1\n");
fprintf (fp,"PIXEL HALF");
fprintf (fp,"\n");
fprintf (fp,"# directory to get all input files from (makes this file easier to read)\n");
fprintf (fp,"INPUT_DIR %s\n",fMovieTempFolderPath.toStdString().c_str());
fprintf (fp,"\n");
fprintf (fp,"# There are a bunch of ways to specify the input files.\n");
fprintf (fp,"# from a simple one-per-line listing, to the following \n");
fprintf (fp,"# way of numbering them. See the manual for more information.\n");
fprintf (fp,"INPUT\n");
fprintf (fp,"# '*' is replaced by the numbers 01, 02, 03, 04\n");
fprintf (fp,"# if I instead do [01-11], it would be 01, 02, ..., 09, 10, 11\n");
fprintf (fp,"# if I instead do [1-11], it would be 1, 2, 3, ..., 9, 10, 11\n");
fprintf (fp,"# if I instead do [1-11+3], it would be 1, 4, 7, 10\n");
fprintf (fp,"# the program assumes none of your input files has a name ending in ']'\n");
fprintf (fp,"# if you do, too bad!!!\n");
fprintf (fp,"#\n");
fprintf (fp,"#\n");
fprintf (fp,"Test*.ppm [0-%d]\n",fRecordFrameNumber-1);
fprintf (fp,"# can have more files here if you want...there is no limit on the number\n");
fprintf (fp,"# of files\n");
fprintf (fp,"END_INPUT\n");
fprintf (fp,"\n");
fprintf (fp,"\n");
fprintf (fp,"\n");
fprintf (fp,"# Many of the remaining options have to do with the motion search and qscale\n");
fprintf (fp,"\n");
fprintf (fp,"# FULL or HALF -- must be upper case\n");
fprintf (fp,"# Should be FULL for computer generated images\n");
fprintf (fp,"PIXEL FULL\n");
fprintf (fp,"\n");
fprintf (fp,"# means +/- this many pixels for both P and B frame searches\n");
fprintf (fp,"# specify two numbers if you wish to serc different ranges in the two.\n");
fprintf (fp,"RANGE 10\n");
fprintf (fp,"\n");
fprintf (fp,"# The two search algorithm parameters below mostly affect speed,\n");
fprintf (fp,"# with some affect on compression and almost none on quality.\n");
fprintf (fp,"\n");
fprintf (fp,"# this must be one of {EXHAUSTIVE, SUBSAMPLE, LOGARITHMIC}\n");
fprintf (fp,"PSEARCH_ALG LOGARITHMIC\n");
fprintf (fp,"\n");
fprintf (fp,"# this must be one of {SIMPLE, CROSS2, EXHAUSTIVE}\n");
fprintf (fp,"#\n");
fprintf (fp,"# note that EXHAUSTIVE is really, really, really slow\n");
fprintf (fp,"#\n");
fprintf (fp,"BSEARCH_ALG SIMPLE\n");
fprintf (fp,"\n");
fprintf (fp,"#\n");
fprintf (fp,"# these specify the q-scale for I, P, and B frames\n");
fprintf (fp,"# (values must be between 1 and 31)\n");
fprintf (fp,"# These are the Qscale values for the entire frame in variable bit-rate\n");
fprintf (fp,"# mode, and starting points (but not important) for constant bit rate\n");
fprintf (fp,"#\n");
fprintf (fp,"\n");
fprintf (fp,"# Qscale (Quantization scale) affects quality and compression,\n");
fprintf (fp,"# but has very little effect on speed.\n");
fprintf (fp,"\n");
fprintf (fp,"IQSCALE 4\n");
fprintf (fp,"PQSCALE 5\n");
fprintf (fp,"BQSCALE 12\n");
fprintf (fp,"\n");
fprintf (fp,"# this must be ORIGINAL or DECODED\n");
fprintf (fp,"REFERENCE_FRAME ORIGINAL\n");
fprintf (fp,"\n");
fprintf (fp,"# for parallel parameters see parallel.param in the exmaples subdirectory\n");
fprintf (fp,"\n");
fprintf (fp,"# if you want constant bit-rate mode, specify it as follows (number is bits/sec):\n");
fprintf (fp,"#BIT_RATE 1000000\n");
fprintf (fp,"\n");
fprintf (fp,"# To specify the buffer size (327680 is default, measused in bits, for 16bit words)\n");
fprintf (fp,"BUFFER_SIZE 327680\n");
fprintf (fp,"\n");
fprintf (fp,"# The frame rate is the number of frames/second (legal values:\n");
fprintf (fp,"# 23.976, 24, 25, 29.97, 30, 50 ,59.94, 60\n");
fprintf (fp,"FRAME_RATE 30\n");
fprintf (fp,"\n");
fprintf (fp,"# There are many more options, see the users manual for examples....\n");
fprintf (fp,"# ASPECT_RATIO, USER_DATA, GAMMA, IQTABLE, etc.\n");
fprintf (fp,"\n");
fprintf (fp,"\n");
fclose (fp);
setRecordingInfos("Parameter file "+fParameterFileName+" generated in "+fMovieTempFolderPath);
setRecordingStatus(READY_TO_ENCODE);
return true;
}
void G4OpenGLQtViewer::encodeVideo()
{
if ((getEncoderPath() != "") && (getSaveFileName() != "")) {
setRecordingStatus(ENCODING);
fProcess = new QProcess();
#if QT_VERSION > 0x040100
QObject ::connect(fProcess,SIGNAL(finished ( int,QProcess::ExitStatus)),
this,SLOT(processEncodeFinished()));
QObject ::connect(fProcess,SIGNAL(readyReadStandardOutput ()),
this,SLOT(processEncodeStdout()));
#else
QObject ::connect(fProcess,SIGNAL(finished ( int)),
this,SLOT(processEncodeFinished()));
QObject ::connect(fProcess,SIGNAL(readyReadStandardOutput ()),
this,SLOT(processEncodeStdout()));
#endif
fProcess->setReadChannelMode(QProcess::MergedChannels);
fProcess->start (fEncoderPath, QStringList(fMovieTempFolderPath+fParameterFileName));
}
}
// FIXME : does not work on Qt3
void G4OpenGLQtViewer::processEncodeStdout()
{
QString tmp = fProcess->readAllStandardOutput ().data();
int start = tmp.lastIndexOf("ESTIMATED TIME");
tmp = tmp.mid(start,tmp.indexOf("\n",start)-start);
setRecordingInfos(tmp);
}
void G4OpenGLQtViewer::processEncodeFinished()
{
QString txt = "";
txt = getProcessErrorMsg();
if (txt == "") {
setRecordingStatus(SUCCESS);
} else {
setRecordingStatus(FAILED);
}
// setRecordingInfos(txt+removeTempFolder());
}
void G4OpenGLQtViewer::processLookForFinished()
{
QString txt = getProcessErrorMsg();
if (txt != "") {
fEncoderPath = "";
} else {
fEncoderPath = QString(fProcess->readAllStandardOutput ().data()).trimmed();
// if not found, return "not found"
if (fEncoderPath.contains(" ")) {
fEncoderPath = "";
} else if (!fEncoderPath.contains("ppmtompeg")) {
fEncoderPath = "";
}
setEncoderPath(fEncoderPath);
}
// init temp folder
setTempFolderPath(QDir::temp ().absolutePath ());
}
QString G4OpenGLQtViewer::getProcessErrorMsg()
{
QString txt = "";
if (fProcess->exitCode() != 0) {
switch (fProcess->error()) {
case QProcess::FailedToStart:
txt = "The process failed to start. Either the invoked program is missing, or you may have insufficient permissions to invoke the program.\n";
break;
case QProcess::Crashed:
txt = "The process crashed some time after starting successfully.\n";
break;
case QProcess::Timedout:
txt = "The last waitFor...() function timed out. The state of QProcess is unchanged, and you can try calling waitFor...() again.\n";
break;
case QProcess::WriteError:
txt = "An error occurred when attempting to write to the process. For example, the process may not be running, or it may have closed its input channel.\n";
break;
case QProcess::ReadError:
txt = "An error occurred when attempting to read from the process. For example, the process may not be running.\n";
break;
case QProcess::UnknownError:
txt = "An unknown error occurred. This is the default return value of error().\n";
break;
}
}
return txt;
}
QWidget *G4OpenGLQtViewer::getParentWidget()
{
// launch Qt if not
G4Qt* interactorManager = G4Qt::getInstance ();
// G4UImanager* UI =
// G4UImanager::GetUIpointer();
bool found = false;
QDialog* dialog = NULL;
// create window
if (((QApplication*)interactorManager->GetMainInteractor())) {
// look for the main window
QWidgetList wl = QApplication::allWidgets();
QWidget *widget = NULL;
for (int i=0; i < wl.size(); i++) {
widget = wl.at(i);
if ((found== false) && (widget->inherits("QMainWindow"))) {
dialog = new QDialog(widget,Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowMinMaxButtonsHint);
found = true;
}
}
if (found==false) {
dialog = new QDialog();
}
} else {
dialog= new QDialog();
}
if (found) {
return dialog;
} else {
return NULL;
}
}
void G4OpenGLQtViewer::createSceneTreeWidget() {
fUISceneTreeWidget = fUiQt->GetSceneTreeWidget();
if (!fUISceneTreeWidget) {
return;
}
// do not remove previous widgets, hide them!
QLayoutItem * wItem;
bool found = false;
if (fUISceneTreeWidget->layout()->count() ) {
for(int idx = 0; idx < fUISceneTreeWidget->layout()->count(); idx++){
wItem = fUISceneTreeWidget->layout()->itemAt(idx);
if (fSceneTreeWidget) {
if(dynamic_cast<QWidget *>(wItem->widget())) {
if (wItem->widget()->windowTitle() == fSceneTreeWidget->windowTitle()) {
wItem->widget()->show();
found = true;
} else {
wItem->widget()->hide();
}
}
} else {
wItem->widget()->hide();
}
}
}
if (!found) {
// initialize scene tree / viewer properties / picking
fSceneTreeWidget = new QWidget();
QVBoxLayout* layoutSceneTree = new QVBoxLayout();
fSceneTreeWidget->setStyleSheet ("padding: 0px ");
fSceneTreeWidget->setLayout(layoutSceneTree);
fSceneTreeWidget->layout()->setContentsMargins(5,5,5,5);
fSceneTreeWidget->setWindowTitle(QString(GetName().data()));
if (fUISceneTreeWidget != NULL) {
fUISceneTreeWidget->layout()->addWidget(fSceneTreeWidget);
}
// not available for Immediate mode
if (dynamic_cast<G4OpenGLStoredQtViewer*> (this)) {
createSceneTreeComponent();
}
}
}
void G4OpenGLQtViewer::createSceneTreeComponent(){
QLayout* vLayout = fSceneTreeWidget->layout();
// Search line
QWidget* coutButtonWidget = new QWidget();
QHBoxLayout* layoutCoutTBButtons = new QHBoxLayout();
fFilterOutput = new QLineEdit();
fFilterOutput->setToolTip("Filter output by...");
fFilterOutput->setStyleSheet ("padding: 0px ");
QPixmap* searchIcon = fUiQt->getSearchIcon();
#if QT_VERSION > 0x050100
fFilterOutput->addAction(*searchIcon,QLineEdit::TrailingPosition);
fFilterOutput->setStyleSheet ("border-radius:7px;");
#else
QPushButton *coutTBFilterButton = new QPushButton();
coutTBFilterButton->setIcon(*searchIcon);
coutTBFilterButton->setStyleSheet ("padding-left: 0px; border:0px;");
fFilterOutput->setStyleSheet ("padding-right: 0px;");
#endif
layoutCoutTBButtons->addWidget(fFilterOutput);
#if QT_VERSION <= 0x050100
layoutCoutTBButtons->addWidget(coutTBFilterButton);
#endif
coutButtonWidget->setLayout(layoutCoutTBButtons);
vLayout->addWidget(coutButtonWidget);
// reduce margins
vLayout->setContentsMargins(0,0,0,0);
fSceneTreeComponentTreeWidget = new QTreeWidget();
fSceneTreeComponentTreeWidget->setSelectionMode(QAbstractItemView::SingleSelection);
fSceneTreeComponentTreeWidget->setHeaderLabel ("Scene tree : "+QString(GetName().data()));
fSceneTreeComponentTreeWidget->setColumnHidden (1,true); // copy number
fSceneTreeComponentTreeWidget->setColumnHidden (2,true); // PO index
fSceneTreeComponentTreeWidget->setColumnHidden (3,true); // Informations
// data(0) : POindex
// data(1) : copy number
// data(2) : g4color
vLayout->addWidget(fSceneTreeComponentTreeWidget);
connect(fSceneTreeComponentTreeWidget,SIGNAL(itemChanged(QTreeWidgetItem*, int)),SLOT(sceneTreeComponentItemChanged(QTreeWidgetItem*, int)));
connect(fSceneTreeComponentTreeWidget,SIGNAL(itemSelectionChanged ()),SLOT(sceneTreeComponentSelected()));
connect(fSceneTreeComponentTreeWidget,SIGNAL(itemDoubleClicked ( QTreeWidgetItem*, int)),SLOT(changeColorAndTransparency( QTreeWidgetItem*, int)));
// Depth slider
QWidget *helpWidget = new QWidget();
QHBoxLayout *helpLayout = new QHBoxLayout();
QWidget* depthWidget = new QWidget();
QWidget *showBox = new QWidget(depthWidget);
QHBoxLayout *showBoxLayout = new QHBoxLayout();
// reduce margins
showBoxLayout->setContentsMargins(5,5,5,5);
QLabel *zero = new QLabel();
zero->setText("Show all");
QLabel *one = new QLabel();
one->setText("Hide all");
fSceneTreeDepthSlider = new QSlider ( Qt::Horizontal);
fSceneTreeDepthSlider->setMaximum (1000);
fSceneTreeDepthSlider->setMinimum (0);
fSceneTreeDepthSlider->setTickPosition(QSlider::TicksAbove);
// set a minimum size
fSceneTreeDepthSlider->setMinimumWidth (40);
showBoxLayout->addWidget(zero);
showBoxLayout->addWidget(fSceneTreeDepthSlider);
showBoxLayout->addWidget(one);
showBox->setLayout(showBoxLayout);
helpLayout->addWidget(showBox);
helpWidget->setLayout(helpLayout);
helpLayout->setContentsMargins(0,0,0,0);
vLayout->addWidget(helpWidget);
connect( fSceneTreeDepthSlider, SIGNAL( valueChanged(int) ), this, SLOT( changeDepthInSceneTree(int) ) );
connect( fFilterOutput, SIGNAL( textEdited ( const QString &) ), this, SLOT(changeSearchSelection()));
fTreeItemModels.clear();
fPVRootNodeCreate = false;
fMaxPOindexInserted = -1;
}
void G4OpenGLQtViewer::createViewerPropertiesWidget() {
// Get the pointer to the Viewer Properties widget
fUIViewerPropertiesWidget = fUiQt->GetViewerPropertiesWidget();
if (!fUIViewerPropertiesWidget) {
return;
}
// remove previous widgets
QLayoutItem * wItem;
if (fUIViewerPropertiesWidget->layout()->count()) {
while ((wItem = fUIViewerPropertiesWidget->layout()->takeAt(0)) != 0) {
delete wItem->widget();
delete wItem;
}
}
// add properties
QGroupBox *groupBox = new QGroupBox();
groupBox->setTitle(GetName().data());
QVBoxLayout *vbox = new QVBoxLayout;
// add properties content
fViewerPropertiesTableWidget = new QTableWidget();
QSizePolicy vPolicy = fViewerPropertiesTableWidget->sizePolicy();
vPolicy.setVerticalStretch(4);
vbox->addWidget(fViewerPropertiesTableWidget);
groupBox->setLayout(vbox);
fUIViewerPropertiesWidget->layout()->addWidget(groupBox);
connect(fViewerPropertiesTableWidget, SIGNAL(itemChanged(QTableWidgetItem*)),this, SLOT(tableWidgetViewerSetItemChanged(QTableWidgetItem *)));
updateViewerPropertiesTableWidget();
QDialog* dial = static_cast<QDialog*> (fUIViewerPropertiesWidget->parent());
if (dial) {
// change name
dial->setWindowTitle(QString("Viewer properties - ")+GetName());
}
}
void G4OpenGLQtViewer::createPickInfosWidget(){
// Get the pointer to the Pick infos widget
fUIPickInfosWidget = fUiQt->GetPickInfosWidget();
if (!fUIPickInfosWidget) {
return;
}
// remove previous widgets
QLayoutItem * wItem;
if (fUIPickInfosWidget->layout()->count()) {
while ((wItem = fUIPickInfosWidget->layout()->takeAt(0)) != 0) {
delete wItem->widget();
delete wItem;
}
}
QGroupBox *groupBox = new QGroupBox("");
QVBoxLayout *vbox = new QVBoxLayout;
// add picking infos
QWidget *pickingInfoWidget = new QWidget();
QHBoxLayout *pickingInfoLayout = new QHBoxLayout();
pickingInfoWidget->setStyleSheet ("padding-left: 0px; border:0px;");
pickingInfoWidget->setLayout(pickingInfoLayout);
vbox->addWidget(pickingInfoWidget);
// add picking content
fPickInfosScrollArea = new QScrollArea();
fPickInfosScrollArea->setWidgetResizable(true);
fPickInfosWidget = new QWidget();
fPickInfosWidget->setStyleSheet ("padding: 0px ");
QVBoxLayout* vLayout = new QVBoxLayout();
fPickInfosWidget->setLayout (vLayout);
fPickInfosScrollArea->setWidget(fPickInfosWidget);
QSizePolicy vPolicy = fPickInfosWidget->sizePolicy();
vPolicy.setVerticalStretch(4);
vbox->addWidget(fPickInfosScrollArea);
pickingInfoLayout->setContentsMargins(0,0,0,0);
vLayout->setContentsMargins(0,0,0,0);
vbox->setContentsMargins(1,1,1,1);
groupBox->setLayout(vbox);
fUIPickInfosWidget->layout()->addWidget(groupBox);
updatePickInfosWidget(fLastPickPoint.x(),fLastPickPoint.y());
}
// set the component to check/unchecked, also go into its child
// and set the same status to all his childs
void G4OpenGLQtViewer::setCheckComponent(QTreeWidgetItem* item,bool check)
{
if (item) {
const PVPath& fullPath = fTreeItemModels[item->data(0,Qt::UserRole).toInt()];
// If a physical volume
if (fullPath.size() > 0) {
SetTouchable(fullPath);
TouchableSetVisibility(fullPath, check);
fMouseOnSceneTree = true;
}
}
if (item != NULL) {
if (check) {
item->setCheckState(0,Qt::Checked);
} else {
item->setCheckState(0,Qt::Unchecked);
}
updatePositivePoIndexSceneTreeWidgetQuickMap(item->data(0,Qt::UserRole).toInt(),item);
int nChildCount = item->childCount();
for (int i = 0; i < nChildCount; i++) {
setCheckComponent(item->child(i),check);
}
}
}
void G4OpenGLQtViewer::DrawText(const G4Text& g4text)
{
QGLWidget* qGLW = dynamic_cast<QGLWidget*> (fGLWidget) ;
if (! qGLW) {
return;
}
if (isGl2psWriting()) {
G4OpenGLViewer::DrawText(g4text);
} else {
if (!fGLWidget) return;
#ifdef G4MULTITHREADED
if (G4Threading::G4GetThreadId() != G4Threading::MASTER_ID) return;
#endif
G4VSceneHandler::MarkerSizeType sizeType;
G4double size = fSceneHandler.GetMarkerSize(g4text,sizeType);
QFont font = QFont();
font.setPointSizeF(size);
const G4Colour& c = fSceneHandler.GetTextColour(g4text);
glColor4d(c.GetRed(),c.GetGreen(),c.GetBlue(),c.GetAlpha());
G4Point3D position = g4text.GetPosition();
const G4String& textString = g4text.GetText();
const char* textCString = textString.c_str();
glRasterPos3d(position.x(),position.y(),position.z());
// Calculate move for centre and right adjustment
QFontMetrics* f = new QFontMetrics (font);
G4double span = f->width(textCString);
G4double xmove = 0., ymove = 0.;
switch (g4text.GetLayout()) {
case G4Text::left: break;
case G4Text::centre: xmove -= span / 2.; break;
case G4Text::right: xmove -= span;
}
//Add offsets
xmove += g4text.GetXOffset();
ymove += g4text.GetYOffset();
qGLW->renderText
((position.x()+(2*xmove)/getWinWidth()),
(position.y()+(2*ymove)/getWinHeight()),
position.z(),
textCString,
font);
}
}
void G4OpenGLQtViewer::ResetView () {
G4OpenGLViewer::ResetView();
fDeltaDepth = 0.01;
fDeltaZoom = 0.05;
}
void G4OpenGLQtViewer::addPVSceneTreeElement(const G4String& model, G4PhysicalVolumeModel* pPVModel, int currentPOIndex) {
const QString& modelShortName = getModelShortName(model);
if (modelShortName == "") {
return ;
}
// try to init it
if (fSceneTreeComponentTreeWidget == NULL) {
createSceneTreeComponent();
}
// if no UI
if (fSceneTreeComponentTreeWidget == NULL) {
return;
}
fSceneTreeComponentTreeWidget->blockSignals(true);
// Create the "volume" node if not
// if (fSceneTreeComponentTreeWidget->topLevelItemCount () == 0) {
if (!fPVRootNodeCreate) {
const G4Colour& color = fSceneHandler.GetColour();
fModelShortNameItem = createTreeWidgetItem(pPVModel->GetFullPVPath(),
modelShortName,
0, // currentPVCopyNb
-1, // currentPVPOIndex
"",
Qt::Checked,
NULL,
color);
fPVRootNodeCreate = true;
}
bool added = parseAndInsertInSceneTree(fModelShortNameItem,pPVModel,0,modelShortName,0,currentPOIndex);
if (!added) {
}
fSceneTreeComponentTreeWidget->blockSignals(false);
}
/**
if treeNode is NULL, then add this treeNode to the TreeWidget
@return the inserted item
*/
QTreeWidgetItem* G4OpenGLQtViewer::createTreeWidgetItem(
const PVPath& fullPath
,const QString& name
,int copyNb
,int POIndex
,const QString& logicalName
,Qt::CheckState state
,QTreeWidgetItem * parentTreeNode
,const G4Colour& color
) {
// Set depth
if (fullPath.size() > fSceneTreeDepth) {
fSceneTreeDepth = fullPath.size();
// Change slider value
if (fSceneTreeDepthSlider) {
fSceneTreeDepthSlider->setTickInterval(1000/(fSceneTreeDepth+1));
}
}
QTreeWidgetItem * newItem = NULL;
if (parentTreeNode == NULL) {
newItem = new QTreeWidgetItem();
fSceneTreeComponentTreeWidget->addTopLevelItem(newItem);
} else {
newItem = new QTreeWidgetItem(parentTreeNode);
fSceneTreeComponentTreeWidget->addTopLevelItem(parentTreeNode);
}
newItem->setText(0,name);
newItem->setData(1,Qt::UserRole,copyNb);
newItem->setText(2,QString::number(POIndex));
newItem->setData(0, Qt::UserRole, POIndex);
newItem->setText(3,logicalName);
newItem->setFlags(newItem->flags()|Qt::ItemIsUserCheckable);
newItem->setCheckState(0,state);
newItem->setExpanded(true);
updatePositivePoIndexSceneTreeWidgetQuickMap(POIndex,newItem);
changeQColorForTreeWidgetItem(newItem,QColor((int)(color.GetRed()*255),
(int)(color.GetGreen()*255),
(int)(color.GetBlue()*255),
(int)(color.GetAlpha()*255)));
// If invisible
if ((state == Qt::Unchecked) && (POIndex == -1)) {
newItem->setForeground (0, QBrush( Qt::gray) );
// Set a tootip
newItem->setToolTip (0,QString(
"This node exists in the geometry but has not been\n")+
"drawn, perhaps because it has been set invisible. It \n"+
"cannot be made visible with a click on the button.\n"+
"To see it, change the visibility, for example, with \n"+
"/vis/geometry/set/visibility " + logicalName + " 0 true\n"+
"and rebuild the view with /vis/viewer/rebuild.\n"+
"Click here will only show/hide all child components");
} else {
// Set a tootip
newItem->setToolTip (0,QString("double-click to change the color"));
}
// special case: if alpha=0, it is a totally transparent objet,
// then, do not redraw it
if (color.GetAlpha() == 0) {
state = Qt::Unchecked;
newItem->setCheckState(0,state);
updatePositivePoIndexSceneTreeWidgetQuickMap(POIndex,newItem);
}
fTreeItemModels.insert(std::pair <int, PVPath > (POIndex,fullPath) );
// Check last status of this item and change if necessary
// open/close/hidden/visible/selected
changeOpenCloseVisibleHiddenSelectedColorSceneTreeElement(newItem);
return newItem;
}
//
// Recursive function.
// Try to insert the given item :
// - If not present and last item of the path: insert it and mark it CHECK
// - If not present and NOT last item of the path: insert it and mark it UNCHECKED
// - If already present and name/PO/Transformation identical, then it is a transparent
// object : Change the PO number and transparency
// - If already present and PO different, then it is an unvisible item : Have to
// set it visible
// - else : Create a new element
// @return true if inserted, false if already present
//
bool G4OpenGLQtViewer::parseAndInsertInSceneTree(
QTreeWidgetItem * parentItem
,G4PhysicalVolumeModel* pPVModel
,unsigned int fullPathIndex
,const QString& parentRoot
,unsigned int currentIndexInTreeSceneHandler
,int currentPVPOIndex
) {
if (parentItem == NULL) {
return false;
}
const PVPath& fullPath = pPVModel->GetFullPVPath();
std::ostringstream oss;
oss << fullPath.at(fullPathIndex).GetCopyNo();
std::string currentPVName = G4String(fullPath.at(fullPathIndex).GetPhysicalVolume()->GetName()+" ["+oss.str()+"]").data();
int currentPVCopyNb = fullPath.at(fullPathIndex).GetCopyNo();
const G4Colour& color = fSceneHandler.GetColour();
// look in all children in order to get if their is already a
// child corresponding:
// - if so, go into this child
// - if not : create it as invisible
// Realy quick check if the POindex is already there
QTreeWidgetItem* subItem = NULL;
QList<QTreeWidgetItem *> parentItemList;
// first of all, very quick check if it was not the same as last one
// Check only if it is a transparent object
// If it is the last item and it is not transparent -> nothing to look for,
// simply add it.
if ((currentIndexInTreeSceneHandler == (fullPath.size()-1)) && ((color.GetAlpha() == 1.))) {
} else {
QString lookForString = QString(currentPVName.c_str());
for (int i = 0;i < parentItem->childCount(); i++ ) {
if (parentItem->child(i)->text(0) == lookForString) {
parentItemList.push_back(parentItem->child(i));
}
}
}
for (int i = 0; i < parentItemList.size(); ++i) {
const std::string& parentItemName = parentItemList.at(i)->text(0).toStdString();
int parentItemCopyNb = parentItemList.at(i)->data(1,Qt::UserRole).toInt();
int parentItemPOIndex = parentItemList.at(i)->data(0,Qt::UserRole).toInt();
// if already inside
// -> return true
// special case, do not have to deal with hierarchy except for PhysicalVolume
/* Physical Volume AND copy number equal AND name equal */
if (((parentRoot == fTouchableVolumes) && (currentPVCopyNb == parentItemCopyNb)
&& (currentPVName == parentItemName)) ||
/* NOT a Physical Volume AND copy number equal */
((parentRoot != fTouchableVolumes) && (currentPVCopyNb == parentItemCopyNb)
/*AND name equal AND PO index equal*/
&& (currentPVName == parentItemName) && (currentPVPOIndex == parentItemPOIndex) )) {
// then check for the Transform3D
bool sameTransform = true;
if (parentItemPOIndex >= 0) {
const PVPath& fullPathTmp = fTreeItemModels[parentItemPOIndex];
if (fullPathTmp.size() > 0) {
if (fullPathTmp.at(fullPathTmp.size()-1).GetTransform () == pPVModel->GetTransformation ()) {
sameTransform = true;
} else {
sameTransform = false;
}
}
}
// Same transformation, then try to change the PO index
if (sameTransform == true) {
// already exist in the tree, is it a transparent object ?
// If so, then have to change the PO index ONLY if it is the last
// and then change the state ONLY if POIndex has change
// If not, then go deaper
// last element
if (currentIndexInTreeSceneHandler == (fullPath.size()-1)) {
parentItemList.at(i)->setText(2,QString::number(currentPVPOIndex));
parentItemList.at(i)->setData(0, Qt::UserRole,currentPVPOIndex);
fTreeItemModels.insert(std::pair <int, PVPath >(currentPVPOIndex,fullPath) );
// Then remove tooltip and special font
QFont f = QFont();
parentItemList.at(i)->setFont (0,f);
// set foreground
parentItemList.at(i)->setForeground (0,QBrush());
// Set a tootip
parentItemList.at(i)->setToolTip (0,"");
changeQColorForTreeWidgetItem(parentItemList.at(i),QColor((int)(color.GetRed()*255),
(int)(color.GetGreen()*255),
(int)(color.GetBlue()*255),
(int)(color.GetAlpha()*255)));
// set check only if there is something to display
if (color.GetAlpha() > 0) {
parentItemList.at(i)->setCheckState(0,Qt::Checked);
updatePositivePoIndexSceneTreeWidgetQuickMap(currentPVPOIndex,parentItemList.at(i));
}
return false;
} else {
subItem = parentItemList.at(i);
}
// Exists but not the end of path, then forget get it
} else if (currentIndexInTreeSceneHandler < (fullPath.size()-1)) {
subItem = parentItemList.at(i);
}
}
} // end for
// if it the last, then add it and set it checked
if (currentIndexInTreeSceneHandler == (fullPath.size()-1)) {
/* subItem =*/ createTreeWidgetItem(fullPath,
QString(currentPVName.c_str()),
currentPVCopyNb,
currentPVPOIndex,
QString(fullPath.at(fullPathIndex).GetPhysicalVolume()->GetLogicalVolume()->GetName().data()),
Qt::Checked,
parentItem,
color);
if (currentPVPOIndex > fMaxPOindexInserted) {
fMaxPOindexInserted = currentPVPOIndex;
}
} else {
// if no child found, then this child is create and marked as invisible, then go inside
if (subItem == NULL) {
if (currentIndexInTreeSceneHandler < (fullPath.size()-1)) {
subItem = createTreeWidgetItem(fullPath,
QString(currentPVName.c_str()),
currentPVCopyNb,
-1,
QString(fullPath.at(fullPathIndex).GetPhysicalVolume()->GetLogicalVolume()->GetName().data()),
Qt::Unchecked,
parentItem,
color);
}
}
return parseAndInsertInSceneTree(subItem,pPVModel,fullPathIndex+1,parentRoot,currentIndexInTreeSceneHandler+1,currentPVPOIndex);
}
return true;
}
void G4OpenGLQtViewer::changeOpenCloseVisibleHiddenSelectedColorSceneTreeElement(
QTreeWidgetItem* subItem
)
{
// Check if object with the same POIndex is the same in old tree
QTreeWidgetItem* oldItem = NULL;
QTreeWidgetItem* foundItem = getOldTreeWidgetItem(subItem->data(0,Qt::UserRole).toInt());
if (foundItem != NULL) {
if (isSameSceneTreeElement(foundItem,subItem)) {
oldItem = foundItem;
}
}
if (foundItem == NULL) { // PO should have change, parse all
// POindex > 0
std::map <int, QTreeWidgetItem*>::const_iterator i;
i = fOldPositivePoIndexSceneTreeWidgetQuickMap.begin();
while (i != fOldPositivePoIndexSceneTreeWidgetQuickMap.end()) {
if (isSameSceneTreeElement(i->second,subItem)) {
oldItem = i->second;
i = fOldPositivePoIndexSceneTreeWidgetQuickMap.end();
} else {
i++;
}
}
// POindex == 0 ?
if (oldItem == NULL) {
unsigned int a = 0;
while (a < fOldNullPoIndexSceneTreeWidgetQuickVector.size()) {
if (isSameSceneTreeElement(fOldNullPoIndexSceneTreeWidgetQuickVector[a],subItem)) {
oldItem = fOldNullPoIndexSceneTreeWidgetQuickVector[a];
a = fOldNullPoIndexSceneTreeWidgetQuickVector.size();
} else {
a++;
}
}
}
}
// if found : retore old state
if (oldItem != NULL) {
subItem->setFlags(oldItem->flags()); // flags
subItem->setCheckState(0,oldItem->checkState(0)); // check state
subItem->setSelected(oldItem->isSelected()); // selected
subItem->setExpanded(oldItem->isExpanded ()); // expand
// change color
// when we call this function, the color in the item is the one of vis Attr
std::map <int, QTreeWidgetItem* >::iterator it;
// getOldPO
int oldPOIndex = oldItem->data(0,Qt::UserRole).toInt();
it = fOldPositivePoIndexSceneTreeWidgetQuickMap.find(oldPOIndex);
QColor color;
// get old Vis Attr Color
std::map <int, QColor >::iterator itVis;
itVis = fOldVisAttrColorMap.find(oldPOIndex);
QColor oldVisAttrColor;
const QColor& newVisAttrColor = subItem->data(2,Qt::UserRole).value<QColor>();
bool visAttrChange = false;
// if old vis attr color found
if (itVis != fOldVisAttrColorMap.end()) {
oldVisAttrColor = itVis->second;
if (oldVisAttrColor != newVisAttrColor) {
visAttrChange = true;
}
} else {
visAttrChange = true;
}
if (visAttrChange) {
fOldVisAttrColorMap.insert(std::pair <int, QColor > (subItem->data(0,Qt::UserRole).toInt(),newVisAttrColor) );
} else { // if no changes, get old PO value
// if old PO found
if (it != fOldPositivePoIndexSceneTreeWidgetQuickMap.end()) {
color = (it->second)->data(2,Qt::UserRole).value<QColor>();
} else {
color = oldItem->data(2,Qt::UserRole).value<QColor>();
}
changeQColorForTreeWidgetItem(subItem,color);
}
}
return;
}
// Check if both items are identical.
// For that, check name, copy number, transformation
// special case for "non Touchables", do not check the PO index, check only the name
bool G4OpenGLQtViewer::isSameSceneTreeElement(
QTreeWidgetItem* parentOldItem
,QTreeWidgetItem* parentNewItem
) {
int newPO = -1;
int oldPO = -1;
int newCpNumber = -1;
int oldCpNumber = -1;
bool firstWhile = true;
while ((parentOldItem != NULL) && (parentNewItem != NULL)) {
// check transform, optimize getting data(..,..) that consume lot of time
if (!firstWhile) {
oldPO = parentOldItem->data(0,Qt::UserRole).toInt();
newPO = parentNewItem->data(0,Qt::UserRole).toInt();
}
firstWhile = false;
if ((oldPO >= 0) &&
(newPO >= 0)) {
const PVPath& oldFullPath = fOldTreeItemModels[oldPO];
const PVPath& newFullPath = fTreeItemModels[newPO];
if ((oldFullPath.size() > 0) &&
(newFullPath.size() > 0)) {
if (oldFullPath.size() != newFullPath.size()) {
return false;
}
if (oldFullPath.at(oldFullPath.size()-1).GetTransform () == newFullPath.at(newFullPath.size()-1).GetTransform ()) {
newCpNumber = newFullPath.at(newFullPath.size()-1).GetCopyNo();
oldCpNumber = oldFullPath.at(oldFullPath.size()-1).GetCopyNo();
// ok
} else {
return false;
}
}
}
// Check copy Number
if (oldCpNumber == -1) {
oldCpNumber = parentOldItem->data(1,Qt::UserRole).toInt();
}
if (newCpNumber == -1) {
newCpNumber = parentNewItem->data(1,Qt::UserRole).toInt();
}
if ((oldCpNumber != newCpNumber) ||
// Check name
(parentOldItem->text(0) != parentNewItem->text(0)) ) {
// try to optimize
return false;
} else if ((parentOldItem->text(0) != parentNewItem->text(0)) || // Logical Name
(parentOldItem->text(3) != parentNewItem->text(3))) { // Check logical name
return false;
} else {
parentOldItem = parentOldItem->parent();
parentNewItem = parentNewItem->parent();
}
} // end while
return true;
}
void G4OpenGLQtViewer::addNonPVSceneTreeElement(
const G4String& model
,int currentPOIndex
,const std::string& modelDescription
,const G4Visible& visible
) {
QString modelShortName = getModelShortName(model);
G4Colour color;
// Special case for text
try {
const G4Text& g4Text = dynamic_cast<const G4Text&>(visible);
color = fSceneHandler.GetTextColour(g4Text);
}
catch (std::bad_cast) {
color = fSceneHandler.GetColour();
}
if (modelShortName == "") {
return ;
}
// try to init it
if (fSceneTreeComponentTreeWidget == NULL) {
createSceneTreeComponent();
}
// if no UI
if (fSceneTreeComponentTreeWidget == NULL) {
return;
}
fSceneTreeComponentTreeWidget->blockSignals(true);
// Create the "Model" node if not
QList<QTreeWidgetItem *> resItem;
resItem = fSceneTreeComponentTreeWidget->findItems (modelShortName, Qt::MatchExactly, 0 );
QTreeWidgetItem * currentItem = NULL;
const PVPath tmpFullPath;
if (resItem.empty()) {
currentItem = createTreeWidgetItem(tmpFullPath,
modelShortName,
0, // currentPVCopyNb
-1, // currentPVPOIndex
"",
Qt::Checked,
NULL,
color);
} else {
currentItem = resItem.first();
}
// Is this volume already in the tree AND PO is not the same?
const QList<QTreeWidgetItem *>&
resItems = fSceneTreeComponentTreeWidget->findItems (QString(modelDescription.c_str()), Qt::MatchFixedString| Qt::MatchCaseSensitive|Qt::MatchRecursive, 0 );
bool alreadyPresent = false;
for (int i = 0; i < resItems.size(); ++i) {
if (currentPOIndex == resItems.at(i)->data(0,Qt::UserRole).toInt()) {
alreadyPresent = true;
}
}
if (!alreadyPresent) {
createTreeWidgetItem(tmpFullPath,
QString(modelDescription.c_str()),
0, // currentPVCopyNb
currentPOIndex,
"",
Qt::Checked,
currentItem,
color);
}
fSceneTreeComponentTreeWidget->blockSignals(false);
}
/**
Get the short name for a given label
*/
QString G4OpenGLQtViewer::getModelShortName(const G4String& model) {
QString modelShortName = model.data();
if (modelShortName.mid(0,modelShortName.indexOf(" ")) == "G4PhysicalVolumeModel") {
modelShortName = fTouchableVolumes;
} else {
if (modelShortName.mid(0,2) == "G4") {
modelShortName = modelShortName.mid(2);
}
if (modelShortName.indexOf("Model") != -1) {
modelShortName = modelShortName.mid(0,modelShortName.indexOf("Model"));
}
}
return modelShortName;
}
bool G4OpenGLQtViewer::isTouchableVisible(int POindex){
// If no scene tree (Immediate viewer)
if (fSceneTreeComponentTreeWidget == NULL) {
return false;
}
// should be the next one
// Prevent to get out the std::map
if (fLastSceneTreeWidgetAskForIterator != fLastSceneTreeWidgetAskForIteratorEnd) {
fLastSceneTreeWidgetAskForIterator++;
}
QTreeWidgetItem* item = getTreeWidgetItem(POindex);
if (item != NULL) {
if ( item->checkState(0) == Qt::Checked) {
return true;
}
}
return false;
}
bool G4OpenGLQtViewer::parseAndCheckVisibility(QTreeWidgetItem * treeNode,int POindex){
bool isFound = false;
for (int i = 0; i < treeNode->childCount() ; ++i) {
if (treeNode->child(i)->data(0,Qt::UserRole).toInt() == POindex) {
if (treeNode->child(i)->checkState(0) == Qt::Checked) {
return true;
}
}
isFound = parseAndCheckVisibility(treeNode->child(i),POindex);
if (isFound) {
return true;
}
} // end for
return false;
}
std::string G4OpenGLQtViewer::parseSceneTreeAndSaveState(){
std::string commandLine = "";
for (int b=0;b<fSceneTreeComponentTreeWidget->topLevelItemCount();b++) {
commandLine += parseSceneTreeElementAndSaveState(fSceneTreeComponentTreeWidget->topLevelItem(b),1)+"\n";
}
if (commandLine != "") {
commandLine = std::string("# Disable auto refresh and quieten vis messages whilst scene and\n") +
"# trajectories are established:\n" +
"/vis/viewer/set/autoRefresh false\n" +
"/vis/verbose errors" +
commandLine +
"# Re-establish auto refreshing and verbosity:\n" +
"/vis/viewer/set/autoRefresh true\n" +
"/vis/verbose confirmations\n";
}
return commandLine;
}
std::string G4OpenGLQtViewer::parseSceneTreeElementAndSaveState(QTreeWidgetItem* item, unsigned int level){
// parse current item
std::string str( level, ' ' );
std::string commandLine = "\n#"+ str + "PV Name: " + item->text(0).toStdString();
if (item->text(3) != "") {
commandLine += " LV Name: "+item->text(3).toStdString()+"\n";
// save check state
commandLine += "/vis/geometry/set/visibility " + item->text(3).toStdString() + " ! "; // let default value for depth
if (item->checkState(0) == Qt::Checked) {
commandLine += "1";
}
if (item->checkState(0) == Qt::Unchecked) {
commandLine += "0";
}
commandLine +="\n";
// save color
const QColor& c = item->data(2,Qt::UserRole).value<QColor>();
std::stringstream red;
red << ((double)c.red())/255;
std::stringstream green;
green << (double)c.green()/255;
std::stringstream blue;
blue << ((double)c.blue())/255;
std::stringstream alpha;
alpha << ((double)c.alpha())/255;
commandLine += "/vis/geometry/set/colour " + item->text(3).toStdString() + " ! " + red.str() + " " + green.str() + " " + blue.str() + " " + alpha.str()+"\n";
} else {
commandLine += "\n";
}
// parse childs
for (int b=0;b< item->childCount();b++) {
commandLine += parseSceneTreeElementAndSaveState(item->child(b),level+1);
}
return commandLine;
}
void G4OpenGLQtViewer::sceneTreeComponentItemChanged(QTreeWidgetItem* item, int) {
if (fCheckSceneTreeComponentSignalLock == false) {
fCheckSceneTreeComponentSignalLock = true;
G4bool checked = false;
if (item->checkState(0) == Qt::Checked) {
checked = true;
}
setCheckComponent(item,checked);
updateQWidget();
fCheckSceneTreeComponentSignalLock = false;
}
}
void G4OpenGLQtViewer::sceneTreeComponentSelected() {
}
void G4OpenGLQtViewer::changeDepthInSceneTree (int val){
// If no scene tree (Immediate viewer)
if (fSceneTreeComponentTreeWidget == NULL) {
return;
}
// max depth : fSceneTreeDepth
// val is between 0 and 1
// 0 .1 .2 .3 .4 .5 .6 .7 .8 .9 1
// 1 1.4 2
// 1 2 3 4
// Get the depth :
double depth = 1 + ((double)val)/1000 * ((double)fSceneTreeDepth+1);
// lock update on scene tree items
fCheckSceneTreeComponentSignalLock = true;
// Disable redraw each time !
G4bool currentAutoRefresh = fVP.IsAutoRefresh();
fVP.SetAutoRefresh(false);
for (int b=0;b<fSceneTreeComponentTreeWidget->topLevelItemCount();b++) {
changeDepthOnSceneTreeItem(depth,1.,fSceneTreeComponentTreeWidget->topLevelItem(b));
}
// Enable redraw !
fVP.SetAutoRefresh(currentAutoRefresh);
updateQWidget();
// unlock update on scene tree items
fCheckSceneTreeComponentSignalLock = false;
}
void G4OpenGLQtViewer::changeColorAndTransparency(QTreeWidgetItem* item,int) {
if (item == NULL) {
return;
}
const QColor& old = QColor(item->data(2,Qt::UserRole).value<QColor>());
#if QT_VERSION < 0x040500
bool a;
const QColor& color = QColor(QColorDialog::getRgba (old.rgba(),&a,fSceneTreeComponentTreeWidget));
#else
const QColor& color = QColorDialog::getColor(old,
fSceneTreeComponentTreeWidget,
" Get color and transparency",
QColorDialog::ShowAlphaChannel);
#endif
if (color.isValid()) {
changeColorAndTransparency(item->data(0,Qt::UserRole).toInt(),
G4Colour (((G4double)color.red())/255,
((G4double)color.green())/255,
((G4double)color.blue())/255,
((G4double)color.alpha())/255));
// set scene tree parameters
changeQColorForTreeWidgetItem(item,color);
}
}
void G4OpenGLQtViewer::changeColorAndTransparency(GLuint index, G4Color color) {
// change vis attributes to set new colour
G4int iPO = index;
if (iPO >= 0 && fTreeItemModels.find(iPO) != fTreeItemModels.end()) {
const PVPath& fullPath = fTreeItemModels[iPO];
// If a physical volume
if (fullPath.size()) {
SetTouchable(fullPath);
TouchableSetColour(fullPath, color);
fMouseOnSceneTree = true;
}
}
}
G4Colour G4OpenGLQtViewer::getColorForPoIndex(int poIndex) {
// FIXME 09/2014 : Could be optimize by searching in a tab instead of item->data
QTreeWidgetItem* item = getTreeWidgetItem(poIndex);
if (item != NULL) {
const QColor& color = item->data(2,Qt::UserRole).value<QColor>();
G4Colour g4c(((G4double)color.red())/255,
((G4double)color.green())/255,
((G4double)color.blue())/255,
((G4double)color.alpha())/255);
return g4c;
}
return G4Colour();
}
const std::vector<G4ModelingParameters::VisAttributesModifier>*
G4OpenGLQtViewer::GetPrivateVisAttributesModifiers() const
{
static std::vector<G4ModelingParameters::VisAttributesModifier>
privateVisAttributesModifiers;
privateVisAttributesModifiers.clear();
// I don't think we need this. (JA Sep 2016).
// // For each modified touchable...
// std::map<int,PVPath>::const_iterator i;
// for (i = fTreeItemModels.begin();
// i != fTreeItemModels.end();
// ++i) {
//
// // How do I know if it's been modified or not?
//
// int iPO = i->first;
// const PVPath& fullPath = i->second;
//
// // If a physical volume
// if (fullPath.size()) {
//
// // const G4bool& visibilityChanged = ???
// // const G4bool& visibility = ???
// // const G4bool& colourChanged = ???
// // const QColor& colour = ???
// // G4Colour g4colour(((G4double)colour.red())/255,
// // ((G4double)colour.green())/255,
// // ((G4double)colour.blue())/255,
// // ((G4double)colour.alpha())/255);
// // Next 4 lines are for testing, to be replaced by the above...
// G4bool visibilityChanged = true;
// G4bool visibility = true;
// G4bool colourChanged = true;
// G4Colour g4colour(G4Colour::Red());
//
// // Instantiate a working copy of a G4VisAttributes object...
// G4VisAttributes workingVisAtts;
// // ...and use it to create vis attribute modifiers...
// if (visibilityChanged) {
// workingVisAtts.SetVisibility(visibility);
// privateVisAttributesModifiers.push_back
// (G4ModelingParameters::VisAttributesModifier
// (workingVisAtts,
// G4ModelingParameters::VASVisibility,
// fullPath));
// }
// if (colourChanged) {
// workingVisAtts.SetColour(g4colour);
// privateVisAttributesModifiers.push_back
// (G4ModelingParameters::VisAttributesModifier
// (workingVisAtts,
// G4ModelingParameters::VASColour,
// fullPath));
// }
// }
// }
return &privateVisAttributesModifiers;
}
void G4OpenGLQtViewer::changeSearchSelection()
{
const QString& searchText = fFilterOutput->text();
if (fSceneTreeComponentTreeWidget == NULL) {
return;
}
// unselect all
for (int a=0; a<fSceneTreeComponentTreeWidget->topLevelItemCount(); a++) {
fSceneTreeComponentTreeWidget->topLevelItem(a)->setExpanded(false);
fSceneTreeComponentTreeWidget->topLevelItem(a)->setSelected(false);
clearSceneTreeSelection(fSceneTreeComponentTreeWidget->topLevelItem(a));
}
QList<QTreeWidgetItem *> itemList = fSceneTreeComponentTreeWidget->findItems (searchText,Qt::MatchContains | Qt::MatchRecursive,0);
for (int i = 0; i < itemList.size(); ++i) {
QTreeWidgetItem* expandParentItem = itemList.at(i);
while (expandParentItem->parent() != NULL) {
expandParentItem->parent()->setExpanded(true);
expandParentItem = expandParentItem->parent();
}
itemList.at(i)->setSelected(true);
}
}
void G4OpenGLQtViewer::clearSceneTreeSelection(QTreeWidgetItem* item) {
for (int a=0; a<item->childCount(); a++) {
item->child(a)->setSelected(false);
item->child(a)->setExpanded(false);
clearSceneTreeSelection(item->child(a));
}
}
bool G4OpenGLQtViewer::isPVVolume(QTreeWidgetItem* item) {
QTreeWidgetItem* sParent = item;
while (sParent->parent() != NULL) {
sParent = sParent->parent();
}
if (sParent->text(0) != fTouchableVolumes) {
return false;
}
// item is the "Touchable" node
if (item->text(0) == fTouchableVolumes) {
return false;
}
return true;
}
void G4OpenGLQtViewer::changeDepthOnSceneTreeItem(
double lookForDepth
,double currentDepth
,QTreeWidgetItem* item
) {
double transparencyLevel = 0.;
// look for a 2.2 depth and we are at level 3
// -> Set all theses items to Opaque
// ONLY if it is a PV volume !
if (isPVVolume(item)) {
if ((lookForDepth-currentDepth) < 0) {
item->setCheckState(0,Qt::Checked);
updatePositivePoIndexSceneTreeWidgetQuickMap(item->data(0,Qt::UserRole).toInt(),item);
transparencyLevel = 1;
} else if ((lookForDepth-currentDepth) > 1 ){
item->setCheckState(0,Qt::Unchecked);
updatePositivePoIndexSceneTreeWidgetQuickMap(item->data(0,Qt::UserRole).toInt(),item);
transparencyLevel = 0;
} else {
item->setCheckState(0,Qt::Checked);
updatePositivePoIndexSceneTreeWidgetQuickMap(item->data(0,Qt::UserRole).toInt(),item);
transparencyLevel = 1-(lookForDepth-currentDepth);
}
}
if (item->data(0,Qt::UserRole).toInt() >= 0) {
const G4Colour& color = getColorForPoIndex(item->data(0,Qt::UserRole).toInt());
// We are less depper (ex:tree depth:2) than lookForDepth (ex:3.1)
// -> Have to hide this level ONLY if it was not hidden before
// Not on a top level item case
// Do not set if it was already set
// Should add them all the time in case of an older command has change transparency
// before. Should be checked in changeDepthInSceneTree for duplicated commands
// Do not change transparency if not visible by humain (and avoid precision value
// problems..)
if (((color.GetAlpha()-transparencyLevel) > 0.000001) ||
((color.GetAlpha()-transparencyLevel) < -0.000001)) {
if ((item->text(3) != "")) {
// FIXME : Should not test this here because of transparent
// volume that will came after and with a different alpha level
// Good thing to do is to check and suppress doubles in changeDepthInSceneTree
// and then check if last (transparents volumes) has to change alpha
changeQColorForTreeWidgetItem(item,QColor((int)(color.GetRed()*255),
(int)(color.GetGreen()*255),
(int)(color.GetBlue()*255),
(int)(transparencyLevel*255)));
}
}
}
for (int b=0;b< item->childCount();b++) {
changeDepthOnSceneTreeItem(lookForDepth,currentDepth+1,item->child(b));
}
}
void G4OpenGLQtViewer::clearTreeWidget(){
// be careful about calling this twice
if (fSceneTreeComponentTreeWidget) {
if (fSceneTreeComponentTreeWidget->topLevelItemCount () > 0) {
fPVRootNodeCreate = false;
// reset all old
fOldPositivePoIndexSceneTreeWidgetQuickMap.clear();
fOldNullPoIndexSceneTreeWidgetQuickVector.clear();
fOldTreeItemModels.clear();
// Clone everything
for (int b =0; b <fSceneTreeComponentTreeWidget->topLevelItemCount();b++) {
// All tree widgets are in :
// then we could get the old POindex and get
// .visible/Hidden
// .Check/Uncheck
// .selected
// .colour status from std::map
// clone top level items
int poIndex = fSceneTreeComponentTreeWidget->topLevelItem(b)->data(0,Qt::UserRole).toInt();
if (poIndex != -1) {
fOldPositivePoIndexSceneTreeWidgetQuickMap.insert(std::pair <int, QTreeWidgetItem*> (poIndex,cloneWidgetItem(fSceneTreeComponentTreeWidget->topLevelItem(b))));
} else {
fOldNullPoIndexSceneTreeWidgetQuickVector.push_back(cloneWidgetItem(fSceneTreeComponentTreeWidget->topLevelItem(b)));
}
// clone leaves
cloneSceneTree(fSceneTreeComponentTreeWidget->topLevelItem(b));
}
// delete all elements
fOldTreeItemModels.insert(fTreeItemModels.begin(), fTreeItemModels.end());
// all is copy, then clear scene tree
int tmp2 = fSceneTreeComponentTreeWidget->topLevelItemCount();
while (tmp2 > 0) {
delete fSceneTreeComponentTreeWidget->takeTopLevelItem (0);
tmp2 = fSceneTreeComponentTreeWidget->topLevelItemCount();
}
fPositivePoIndexSceneTreeWidgetQuickMap.clear();
// put correct value in paramaters
fOldLastSceneTreeWidgetAskForIterator = fOldPositivePoIndexSceneTreeWidgetQuickMap.begin();
fOldLastSceneTreeWidgetAskForIteratorEnd = fOldPositivePoIndexSceneTreeWidgetQuickMap.end();
fSceneTreeDepth = 1;
fModelShortNameItem = NULL;
fMaxPOindexInserted = -1;
}
}
}
/**
Clone :
- Open/close
- Visible/hidden
- Selected
*/
QTreeWidgetItem * G4OpenGLQtViewer::cloneWidgetItem(QTreeWidgetItem* item) {
QTreeWidgetItem* cloneItem = new QTreeWidgetItem();
// Clone what is create createTreeWidgetItem step
cloneItem->setText(0,item->text(0));
cloneItem->setData(1,Qt::UserRole,item->data(1,Qt::UserRole).toInt());
cloneItem->setText(2,item->text(2));
cloneItem->setData(0, Qt::UserRole,item->data(0,Qt::UserRole).toInt());
cloneItem->setText(3,item->text(3));
cloneItem->setFlags(item->flags());
cloneItem->setToolTip(0,item->toolTip(0));
cloneItem->setCheckState(0,item->checkState(0));
cloneItem->setSelected(item->isSelected());
cloneItem->setExpanded(item->isExpanded ());
cloneItem->setData(2,Qt::UserRole,item->data(2,Qt::UserRole).value<QColor>());
return cloneItem;
}
/**
Clone the current tree in order to get a snapshot of old version
*/
void G4OpenGLQtViewer::cloneSceneTree(
QTreeWidgetItem* rootItem
) {
for (int b=0;b< rootItem->childCount();b++) {
QTreeWidgetItem *child = rootItem->child(b);
// clone top level items
int poIndex = child->data(0,Qt::UserRole).toInt();
if (poIndex != -1) {
fOldPositivePoIndexSceneTreeWidgetQuickMap.insert(std::pair <int, QTreeWidgetItem*> (poIndex,cloneWidgetItem(child)));
} else {
fOldNullPoIndexSceneTreeWidgetQuickVector.push_back(cloneWidgetItem(child));
}
cloneSceneTree(child);
}
}
/**
Update the quick scene tree visibility map (used by parseAndCheckVisibility)
*/
void G4OpenGLQtViewer::updatePositivePoIndexSceneTreeWidgetQuickMap(int POindex,QTreeWidgetItem* item) {
// Check state
std::map <int, QTreeWidgetItem*>::iterator i;
i = fPositivePoIndexSceneTreeWidgetQuickMap.find(POindex);
if (i == fPositivePoIndexSceneTreeWidgetQuickMap.end()) {
fPositivePoIndexSceneTreeWidgetQuickMap.insert(std::pair <int, QTreeWidgetItem*> (POindex,item) );
fLastSceneTreeWidgetAskForIterator = fPositivePoIndexSceneTreeWidgetQuickMap.end();
fLastSceneTreeWidgetAskForIteratorEnd = fPositivePoIndexSceneTreeWidgetQuickMap.end();
} else {
i->second = item;
}
}
void G4OpenGLQtViewer::changeQColorForTreeWidgetItem(QTreeWidgetItem* item,const QColor& qc) {
int POIndex = item->data(0,Qt::UserRole).toInt();
updatePositivePoIndexSceneTreeWidgetQuickMap(POIndex,item );
QPixmap pixmap = QPixmap(QSize(16, 16));
if (item->data(0,Qt::UserRole).toInt() != -1) {
pixmap.fill (qc);
} else {
pixmap.fill (QColor(255,255,255,255));
}
QPainter painter(&pixmap);
painter.setPen(Qt::black);
painter.drawRect(0,0,15,15); // Draw contour
item->setIcon(0,pixmap);
item->setData(2,Qt::UserRole,qc);
}
/**
@return the corresponding item if existing.
Look into fPositivePoIndexSceneTreeWidgetQuickMap
*/
QTreeWidgetItem* G4OpenGLQtViewer::getTreeWidgetItem(int POindex){
// -1 is not a visible item
if (POindex == -1) {
return NULL;
}
if (fPositivePoIndexSceneTreeWidgetQuickMap.size() == 0){
return NULL;
}
if (fLastSceneTreeWidgetAskForIterator != fLastSceneTreeWidgetAskForIteratorEnd) {
if (POindex == fLastSceneTreeWidgetAskForIterator->first) {
if (fLastSceneTreeWidgetAskForIterator->second != NULL) {
return fLastSceneTreeWidgetAskForIterator->second;
}
}
}
// if not, use the "find" algorithm
fLastSceneTreeWidgetAskForIterator = fPositivePoIndexSceneTreeWidgetQuickMap.find(POindex);
fLastSceneTreeWidgetAskForIteratorEnd = fPositivePoIndexSceneTreeWidgetQuickMap.end();
if (fLastSceneTreeWidgetAskForIterator != fPositivePoIndexSceneTreeWidgetQuickMap.end()) {
return fLastSceneTreeWidgetAskForIterator->second;
}
return NULL;
}
/**
@return the corresponding item if existing in the old tree
Look into fOldPositivePoIndexSceneTreeWidgetQuickMap
*/
QTreeWidgetItem* G4OpenGLQtViewer::getOldTreeWidgetItem(int POindex){
// -1 is not a visible item
if (POindex == -1) {
return NULL;
}
if (fOldPositivePoIndexSceneTreeWidgetQuickMap.size() == 0){
return NULL;
}
// Should be call only once by item addition
// Prevent to get out the std::map
if (fOldLastSceneTreeWidgetAskForIterator != fOldLastSceneTreeWidgetAskForIteratorEnd) {
fOldLastSceneTreeWidgetAskForIterator++;
}
if (fOldLastSceneTreeWidgetAskForIterator != fOldPositivePoIndexSceneTreeWidgetQuickMap.end()) {
if (POindex == fOldLastSceneTreeWidgetAskForIterator->first) {
if (fOldLastSceneTreeWidgetAskForIterator->second != NULL) {
return fOldLastSceneTreeWidgetAskForIterator->second;
}
}
}
// if not, use the "find" algorithm
fOldLastSceneTreeWidgetAskForIterator = fOldPositivePoIndexSceneTreeWidgetQuickMap.find(POindex);
fOldLastSceneTreeWidgetAskForIteratorEnd = fOldPositivePoIndexSceneTreeWidgetQuickMap.end();
if (fOldLastSceneTreeWidgetAskForIterator != fOldPositivePoIndexSceneTreeWidgetQuickMap.end()) {
return fOldLastSceneTreeWidgetAskForIterator->second;
}
return NULL;
}
/**
Should replace actual tree by the one in this class
and update tree
*/
void G4OpenGLQtViewer::displaySceneTreeComponent() {
// no UI
if (fUISceneTreeWidget == NULL) {
return;
}
if (fSceneTreeComponentTreeWidget == NULL) {
return;
}
// sort tree items
fSceneTreeComponentTreeWidget->sortItems (0, Qt::AscendingOrder );
return;
}
/**
Update the toolbar Icons/Mouse context menu
- Change ortho/perspective
- Change surface style
- Change cursor style
*/
void G4OpenGLQtViewer::updateToolbarAndMouseContextMenu(){
if (fBatchMode) {
return;
}
G4ViewParameters::DrawingStyle
d_style = fVP.GetDrawingStyle();
// Surface style
if (d_style == G4ViewParameters::wireframe) {
if (fUiQt) fUiQt->SetIconWireframeSelected();
if (fContextMenu) {
fDrawingWireframe->setChecked(true);
fDrawingLineRemoval->setChecked(false);
fDrawingSurfaceRemoval->setChecked(false);
fDrawingLineSurfaceRemoval->setChecked(false);
}
} else if (d_style == G4ViewParameters::hlr) {
if (fUiQt) fUiQt->SetIconHLRSelected();
if (fContextMenu) {
fDrawingLineRemoval->setChecked(true);
fDrawingWireframe->setChecked(false);
fDrawingSurfaceRemoval->setChecked(false);
fDrawingLineSurfaceRemoval->setChecked(false);
}
} else if (d_style == G4ViewParameters::hsr) {
if (fUiQt) fUiQt->SetIconSolidSelected();
if (fContextMenu) {
fDrawingSurfaceRemoval->setChecked(true);
fDrawingWireframe->setChecked(false);
fDrawingLineRemoval->setChecked(false);
fDrawingLineSurfaceRemoval->setChecked(false);
}
} else if (d_style == G4ViewParameters::hlhsr) {
if (fUiQt) fUiQt->SetIconHLHSRSelected();
if (fContextMenu) {
fDrawingLineSurfaceRemoval->setChecked(true);
fDrawingWireframe->setChecked(false);
fDrawingLineRemoval->setChecked(false);
fDrawingSurfaceRemoval->setChecked(false);
fDrawingLineSurfaceRemoval->setChecked(false);
}
}
// projection style
G4double d_proj = fVP.GetFieldHalfAngle () ;
if (d_proj == 0.) { // ortho
if (fUiQt) fUiQt->SetIconOrthoSelected();
if (fContextMenu) {
fProjectionOrtho->setChecked(true);
fProjectionPerspective->setChecked(false);
}
} else {
if (fUiQt) fUiQt->SetIconPerspectiveSelected();
if (fContextMenu) {
fProjectionPerspective->setChecked(true);
fProjectionOrtho->setChecked(false);
}
}
// mouse style : They are controlled by UI !
if (fUiQt && fContextMenu) {
if (fUiQt->IsIconPickSelected()) {
fMousePickAction->setChecked(true);
fMouseZoomOutAction->setChecked(false);
fMouseZoomInAction->setChecked(false);
fMouseRotateAction->setChecked(false);
fMouseMoveAction->setChecked(false);
} else if (fUiQt->IsIconZoomOutSelected()) {
fMouseZoomOutAction->setChecked(true);
fMousePickAction->setChecked(false);
fMouseZoomInAction->setChecked(false);
fMouseRotateAction->setChecked(false);
fMouseMoveAction->setChecked(false);
} else if (fUiQt->IsIconZoomInSelected()) {
fMouseZoomInAction->setChecked(true);
fMousePickAction->setChecked(false);
fMouseZoomOutAction->setChecked(false);
fMouseRotateAction->setChecked(false);
fMouseMoveAction->setChecked(false);
} else if (fUiQt->IsIconRotateSelected()) {
fMouseRotateAction->setChecked(true);
fMousePickAction->setChecked(false);
fMouseZoomOutAction->setChecked(false);
fMouseZoomInAction->setChecked(false);
fMouseMoveAction->setChecked(false);
} else if (fUiQt->IsIconMoveSelected()) {
fMouseMoveAction->setChecked(true);
fMousePickAction->setChecked(false);
fMouseZoomOutAction->setChecked(false);
fMouseZoomInAction->setChecked(false);
fMouseRotateAction->setChecked(false);
}
}
}
/**
Update the scene tree widget
*/
void G4OpenGLQtViewer::updateSceneTreeWidget() {
// Ensure case where closing a UI tab close the widget
if (!fSceneTreeWidget) {
createSceneTreeWidget();
}
}
/**
Update the viewer properties component widget
Clear it only if the number of command is less than the previous table widget row count
*/
void G4OpenGLQtViewer::updateViewerPropertiesTableWidget() {
if (!isCurrentWidget()) {
return;
}
// Ensure case where closing a UI tab close the widget
if (!fViewerPropertiesTableWidget) {
createViewerPropertiesWidget();
}
int treeWidgetInfosIgnoredCommands = 0;
G4UImanager* UI = G4UImanager::GetUIpointer();
G4UIcommandTree * commandTreeTop = UI->GetTree();
G4UIcommandTree* path = commandTreeTop->FindCommandTree("/vis/viewer/set/");
if (!path) {
return;
}
// clear old table
if ((path->GetCommandEntry()-fTreeWidgetInfosIgnoredCommands) != fViewerPropertiesTableWidget->rowCount()) {
fViewerPropertiesTableWidget->clear();
}
fViewerPropertiesTableWidget->blockSignals(true);
// TODO : Could be optimized by comparing current command to old commands. That should not change so much
fViewerPropertiesTableWidget->setColumnCount (2);
fViewerPropertiesTableWidget->setRowCount (path->GetCommandEntry()-fTreeWidgetInfosIgnoredCommands);
fViewerPropertiesTableWidget->setHorizontalHeaderLabels(QStringList() << tr("Property")
<< tr("Value"));
fViewerPropertiesTableWidget->verticalHeader()->setVisible(false);
fViewerPropertiesTableWidget->setAlternatingRowColors (true);
// For the moment, we do only command that have a "set" command in UI
for (int a=0;a<path->GetCommandEntry();a++) {
G4UIcommand* commandTmp = path->GetCommand(a+1);
// get current parameters
QString params = "";
if(commandTmp->GetCommandName() == "autoRefresh") {
if (fVP.IsAutoRefresh()) {
params = "True";
} else {
params = "False";
}
} else if(commandTmp->GetCommandName() == "auxiliaryEdge") {
if (fVP.IsAuxEdgeVisible()) {
params = "True";
} else {
params = "False";
}
} else if(commandTmp->GetCommandName() == "background") {
params = QString().number(fVP.GetBackgroundColour().GetRed()) + " "+
QString().number(fVP.GetBackgroundColour().GetGreen()) + " "+
QString().number(fVP.GetBackgroundColour().GetBlue()) + " "+
QString().number(fVP.GetBackgroundColour().GetAlpha());
} else if(commandTmp->GetCommandName() == "culling") {
params = QString().number(fVP. IsCulling ());
} else if(commandTmp->GetCommandName() == "cutawayMode") {
if (fVP.GetCutawayMode() == G4ViewParameters::cutawayUnion) {
params = "union";
} else {
params = "intersection";
}
} else if(commandTmp->GetCommandName() == "defaultColour") {
params = QString().number(fVP.GetDefaultVisAttributes()->GetColor().GetRed()) + " "+
QString().number(fVP.GetDefaultVisAttributes()->GetColor().GetGreen()) + " "+
QString().number(fVP.GetDefaultVisAttributes()->GetColor().GetBlue()) + " "+
QString().number(fVP.GetDefaultVisAttributes()->GetColor().GetAlpha());
} else if(commandTmp->GetCommandName() == "defaultTextColour") {
params = QString().number(fVP.GetDefaultTextVisAttributes()->GetColor().GetRed()) + " "+
QString().number(fVP.GetDefaultTextVisAttributes()->GetColor().GetGreen()) + " "+
QString().number(fVP.GetDefaultTextVisAttributes()->GetColor().GetBlue()) + " "+
QString().number(fVP.GetDefaultTextVisAttributes()->GetColor().GetAlpha());
} else if(commandTmp->GetCommandName() == "edge") {
G4ViewParameters::DrawingStyle existingStyle = fVP.GetDrawingStyle();
params = "False";
if (existingStyle == G4ViewParameters::hsr) {
params = "True";
}
} else if(commandTmp->GetCommandName() == "explodeFactor") {
params = QString().number(fVP.GetExplodeFactor()) + " " + QString(G4String(G4BestUnit(fVP.GetExplodeFactor(),"Length")).data());
} else if(commandTmp->GetCommandName() == "globalLineWidthScale") {
params = QString().number(fVP.GetGlobalLineWidthScale());
} else if(commandTmp->GetCommandName() == "globalMarkerScale") {
params = QString().number(fVP.GetGlobalMarkerScale());
} else if(commandTmp->GetCommandName() == "hiddenEdge") {
G4ViewParameters::DrawingStyle style = fVP.GetDrawingStyle();
if ((style == G4ViewParameters::hlr) ||
(style == G4ViewParameters::hlhsr)) {
params = "True";
} else {
params = "False";
}
} else if(commandTmp->GetCommandName() == "hiddenMarker") {
if (fVP.IsMarkerNotHidden()) {
params = "False";
} else {
params = "True";
}
} else if(commandTmp->GetCommandName() == "lightsMove") {
if (fVP.GetLightsMoveWithCamera()) {
params = "camera";
} else {
params = "object";
}
} else if(commandTmp->GetCommandName() == "lightsThetaPhi") {
G4Vector3D direction = fVP.GetLightpointDirection();
// degree
params = QString().number(direction.theta()/CLHEP::degree)+ " "+ QString().number(direction.phi()/CLHEP::degree)+" deg";
if (commandTmp->GetParameterEntries() == 3) {
if (commandTmp->GetParameter(2)->GetDefaultValue() != "deg") {
params = QString().number(direction.theta())+ " "+ QString().number(direction.phi())+" "+commandTmp->GetParameter(2)->GetDefaultValue().data();
}
}
} else if(commandTmp->GetCommandName() == "lightsVector") {
params = QString().number(fVP.GetLightpointDirection().x()) + " "+
QString().number(fVP.GetLightpointDirection().y()) + " "+
QString().number(fVP.GetLightpointDirection().z());
} else if(commandTmp->GetCommandName() == "lineSegmentsPerCircle") {
params = QString().number(fVP.GetNoOfSides());
} else if(commandTmp->GetCommandName() == "picking") {
if (fVP.IsPicking()) {
params = "True";
} else {
params = "False";
}
} else if(commandTmp->GetCommandName() == "projection") {
if (fVP.GetFieldHalfAngle() == 0.) {
params = "orthogonal";
} else {
params = QString("perspective ") + QString().number(fVP.GetFieldHalfAngle()/CLHEP::degree) + " deg";
}
} else if(commandTmp->GetCommandName() == "rotationStyle") {
if (fVP.GetRotationStyle() == G4ViewParameters::constrainUpDirection) {
params = "constrainUpDirection";
} else {
params = "freeRotation";
}
} else if(commandTmp->GetCommandName() == "sectionPlane") {
if (fVP.IsSection()) {
params = QString("on ") +
G4String(G4BestUnit(fVP.GetSectionPlane().point(),"Length")).data()+
QString().number(fVP.GetSectionPlane().normal().x())
+ " " + QString().number(fVP.GetSectionPlane().normal().y())
+ " " + QString().number(fVP.GetSectionPlane().normal().z());
} else {
params = "off";
}
} else if(commandTmp->GetCommandName() == "style") {
if (fVP.GetDrawingStyle() == G4ViewParameters::wireframe || fVP.GetDrawingStyle() == G4ViewParameters::hlr) {
params = "wireframe";
} else {
params = "surface";
}
} else if(commandTmp->GetCommandName() == "targetPoint") {
G4Point3D point = fVP.GetCurrentTargetPoint();
if (fSceneHandler.GetScene()) {
G4String b = G4BestUnit(fSceneHandler.GetScene()->GetStandardTargetPoint() + fVP.GetCurrentTargetPoint(),"Length");
params = b.data();
}
} else if(commandTmp->GetCommandName() == "upThetaPhi") {
G4Vector3D up = fVP.GetUpVector();
// degree
params = QString().number(up.theta()/CLHEP::degree)+ " "+ QString().number(up.phi()/CLHEP::degree)+" deg";
if (commandTmp->GetParameterEntries() == 3) {
if (commandTmp->GetParameter(2)->GetDefaultValue() != "deg") {
params = QString().number(up.theta())+ " "+ QString().number(up.phi())+" "+commandTmp->GetParameter(2)->GetDefaultValue().data();
}
}
} else if(commandTmp->GetCommandName() == "upVector") {
G4Vector3D up = fVP.GetUpVector();
params = QString().number(up.x())+ " "+ QString().number(up.y())+" "+QString().number(up.z())+ " ";
} else if(commandTmp->GetCommandName() == "viewpointThetaPhi") {
G4Vector3D direction = fVP.GetViewpointDirection();
// degree
params = QString().number(direction.theta()/CLHEP::degree)+ " "+ QString().number(direction.phi()/CLHEP::degree)+" deg";
if (commandTmp->GetParameterEntries() == 3) {
if (commandTmp->GetParameter(2)->GetDefaultValue() != "deg") {
params = QString().number(direction.theta())+ " "+ QString().number(direction.phi())+" "+commandTmp->GetParameter(2)->GetDefaultValue().data();
}
}
} else if(commandTmp->GetCommandName() == "viewpointVector") {
G4Vector3D direction = fVP.GetViewpointDirection();
params = QString().number(direction.x())+ " "+ QString().number(direction.y())+" "+QString().number(direction.z());
} else {
// No help
}
/* DO NOT DISPLAY COMMANDS WITHOUT ANY PARAMETERS SET
if (params == "") {
// TODO : display default parameters // should not be editable ?
for( G4int i_thParameter=0; i_thParameter<commandTmp->GetParameterEntries(); i_thParameter++ ) {
commandParam = commandTmp->GetParameter(i_thParameter);
if (QString(QChar(commandParam->GetParameterType())) == "b") {
if (commandParam->GetDefaultValue().data()) {
params += "True";
} else {
params += "False";
}
} else {
params += QString((char*)(commandParam->GetDefaultValue()).data());
}
if (i_thParameter<commandTmp->GetParameterEntries()-1) {
params += " ";
}
}
}
*/
if (params != "") {
QTableWidgetItem *nameItem;
QTableWidgetItem *paramItem;
// already present ?
QList<QTableWidgetItem *> list = fViewerPropertiesTableWidget->findItems (commandTmp->GetCommandName().data(),Qt::MatchExactly);
if (list.size() == 1) {
nameItem = list.first();
paramItem = fViewerPropertiesTableWidget->item(nameItem->row(),1);
} else {
nameItem = new QTableWidgetItem();
paramItem = new QTableWidgetItem();
fViewerPropertiesTableWidget->setItem(a-treeWidgetInfosIgnoredCommands, 0, nameItem);
fViewerPropertiesTableWidget->setItem(a-treeWidgetInfosIgnoredCommands, 1, paramItem);
// Set Guidance
QString guidance;
G4int n_guidanceEntry = commandTmp->GetGuidanceEntries();
for( G4int i_thGuidance=0; i_thGuidance < n_guidanceEntry; i_thGuidance++ ) {
guidance += QString((char*)(commandTmp->GetGuidanceLine(i_thGuidance)).data()) + "\n";
}
nameItem->setToolTip(guidance);
paramItem->setToolTip(GetCommandParameterList(commandTmp));
fViewerPropertiesTableWidget->setRowHeight(a-treeWidgetInfosIgnoredCommands,15);
}
// set current name and parameters
nameItem->setText(commandTmp->GetCommandName().data());
paramItem->setText(params);
nameItem->setFlags(Qt::NoItemFlags);
nameItem->setForeground(QBrush());
} else {
treeWidgetInfosIgnoredCommands++;
}
}
// remove empty content row
for (int i=0; i<treeWidgetInfosIgnoredCommands; i++) {
fViewerPropertiesTableWidget->removeRow (fViewerPropertiesTableWidget->rowCount() - 1);
}
// The resize should done only at creation
if (!fViewerPropertiesTableWidgetIsInit) {
fViewerPropertiesTableWidgetIsInit = true;
fViewerPropertiesTableWidget->resizeColumnsToContents();
int x = fViewerPropertiesTableWidget->horizontalHeader()->length();
int y = fViewerPropertiesTableWidget->verticalHeader()->length()+ fViewerPropertiesTableWidget->horizontalHeader()->sizeHint().height() + 2;
// fViewerPropertiesTableWidget->verticalHeader()->setResizeMode(QHeaderView::ResizeToContents);
// fViewerPropertiesTableWidget->horizontalHeader()->setResizeMode(QHeaderView::ResizeToContents);
// resize to fit content
QDialog* dial = static_cast<QDialog*> (fUIViewerPropertiesWidget->parent());
if (dial) {
dial->resize(x+56,y+46); // more or less (margins) ...
}
}
fViewerPropertiesTableWidget->blockSignals(false);
fTreeWidgetInfosIgnoredCommands = treeWidgetInfosIgnoredCommands;
}
/**
Update the pick infos component widget
*/
void G4OpenGLQtViewer::updatePickInfosWidget(int aX, int aY) {
fLastPickPoint = QPoint(aX,aY);
if (!isCurrentWidget()) {
return;
}
// Ensure case where closing a UI tab close the widget
if (!fPickInfosWidget) {
createPickInfosWidget();
}
const std::vector < G4OpenGLViewerPickMap* > & pickMap = GetPickDetails(aX,aY);
// remove all previous widgets
if (fPickInfosWidget) {
QLayoutItem * wItem;
if (fPickInfosWidget->layout()->count()) {
while ((wItem = fPickInfosWidget->layout()->takeAt(0)) != 0) {
delete wItem->widget();
delete wItem;
}
}
} else {
// Ensure case where closing a UI tab close the widget
if (!fPickInfosWidget) {
createPickInfosWidget();
}
}
// Create a new signalMapper
delete fSignalMapperPicking;
fSignalMapperPicking = new QSignalMapper(this);
// parse all pick results
for (unsigned int a=0; a< pickMap.size(); a++) {
// Add a box inside the pick viewer box
std::ostringstream label;
if (pickMap[a]->getAttributes().size() > 0) {
std::string txt = pickMap[a]->getAttributes()[0].data();
// Look for Volumes
std::size_t pos = txt.find("Physical Volume Path (PVPath):") + 31;
if (pos != 31-1) {
std::size_t pos2 = txt.find("\n",pos);
label << "Volume: " + txt.substr(pos,pos2-pos);
} else {
// Look for tracks
if (pickMap[a]->getAttributes().size() > 1) {
std::string txt1 = pickMap[a]->getAttributes()[1].data();
pos = txt.find("Run ID (RunID):") + 16;
if (pos != 16-1) {
std::size_t pos2 = txt.find("\n",pos);
std::size_t posEID = txt.find("Event ID (EventID):",pos2) + 20;
std::size_t posEID2 = txt.find("\n",posEID);
std::size_t posPN = txt1.find("Particle Name (PN):") + 20;
std::size_t posPN2 = txt1.find("\n",posPN);
std::size_t posCh = txt1.find("Charge (Ch):",posPN2) + 13;
std::size_t posCh2 = txt1.find("\n",posCh);
label << "RunID:" << txt.substr(pos,pos2-pos)
<< " EventID:" << txt.substr(posEID,posEID2-posEID)
<< " PN:" << txt1.substr(posPN,posPN2-posPN)
<< " Ch:" << txt1.substr(posCh,posCh2-posCh);
}
} else {
label << "Hit number:" << a << ", PickName: " << pickMap[a]->getPickName();
}
}
} else {
label << "Hit number:" << a << ", PickName: " << pickMap[a]->getPickName();
}
QPushButton* pickCoutButton = new QPushButton(label.str().c_str());
pickCoutButton->setStyleSheet ("text-align: left; padding: 1px; border: 0px;");
pickCoutButton->setIcon(*fTreeIconClosed);
fPickInfosWidget->layout()->addWidget(pickCoutButton);
QStringList newStr;
// Add to stringList
newStr = QStringList(QString(pickMap[a]->print().data()).trimmed());
QTextEdit* ed = new QTextEdit();
ed->setFontFamily("Courier");
ed->setFontPointSize(12);
ed->setReadOnly(true);
fPickInfosWidget->layout()->addWidget(ed);
ed->setVisible((false));
ed->append(newStr.join(""));
connect(pickCoutButton, SIGNAL(clicked()), fSignalMapperPicking, SLOT(map()));
fSignalMapperPicking->setMapping(pickCoutButton,fPickInfosWidget->layout()->count()-1);
}
connect(fSignalMapperPicking, SIGNAL(mapped(int)),this, SLOT(toggleSceneTreeComponentPickingCout(int)));
// add a label to push everything up!
QLabel * pushUp = new QLabel("");
QSizePolicy vPolicy = QSizePolicy(QSizePolicy::Minimum,QSizePolicy::Minimum);
vPolicy.setVerticalStretch(10);
pushUp->setSizePolicy(vPolicy);
fPickInfosWidget->layout()->addWidget(pushUp);
/* // highlight the first one :
// first un-highlight the last selected
changeColorAndTransparency(fLastHighlightName,fLastHighlightColor);
if (pickMap.size() > 0 ) {
// get the new one
fLastHighlightName = pickMap[0]->getPickName();
fLastHighlightColor = getColorForPoIndex(fLastHighlightName);
// set the new one
changeColorAndTransparency(fLastHighlightName,G4Color(1,1,1,1));
updateQWidget();
}
*/
QDialog* dial = static_cast<QDialog*> (fUIPickInfosWidget->parent());
if (dial) {
// change name
std::ostringstream oss;
if (pickMap.size() == 0) {
oss << "No object";
} else if (pickMap.size() == 1) {
oss << "1 object";
} else {
oss << QString::number(pickMap.size()).toStdString() << " objects";
}
oss << " selected - " << GetName();
dial->setWindowTitle(oss.str().c_str());
}
// set picking cout visible
fPickInfosScrollArea->setVisible(true);
}
void G4OpenGLQtViewer::toggleSceneTreeComponentPickingCout(int pickItem) {
QWidget* w;
// close other items, it could take too much space
for (int a=0; a<fPickInfosWidget->layout()->count(); a++) {
w = fPickInfosWidget->layout()->itemAt(a)->widget();
QTextEdit* ed = dynamic_cast<QTextEdit*>(w);
QPushButton* button;
if (ed) {
if (a == pickItem) {
w->setVisible(!w->isVisible());
} else {
w->setVisible(false);
}
if (a >= 1) {
button = dynamic_cast<QPushButton*>(fPickInfosWidget->layout()->itemAt(a-1)->widget());
if (button) {
if (button->isVisible()) {
button->setIcon(*fTreeIconOpen);
} else {
button->setIcon(*fTreeIconClosed);
}
}
}
}
}
}
void G4OpenGLQtViewer::currentTabActivated(int currentTab) {
if (fUiQt->GetViewerTabWidget()->tabText(currentTab) == GetName()) {
createViewerPropertiesWidget();
createPickInfosWidget();
createSceneTreeWidget();
}
}
void G4OpenGLQtViewer::tableWidgetViewerSetItemChanged(QTableWidgetItem * item) {
G4UImanager* UI = G4UImanager::GetUIpointer();
if(UI != NULL) {
QTableWidgetItem* previous = fViewerPropertiesTableWidget->item(fViewerPropertiesTableWidget->row(item),0);
if (previous) {
fViewerPropertiesTableWidget->blockSignals(true);
UI->ApplyCommand((std::string("/vis/viewer/set/")
+ previous->text().toStdString()
+ " "
+ item->text().toStdString()).c_str());
fViewerPropertiesTableWidget->blockSignals(false);
}
}
}
bool G4OpenGLQtViewer::isCurrentWidget(){
// Prevent from repainting a hidden tab (the current tab name has to be the one of th GL viewer)
if ( GetName() != fUiQt->GetViewerTabWidget()->tabText(fUiQt->GetViewerTabWidget()->currentIndex()).toStdString().c_str()) {
return false;
}
return true;
}
/** Build the parameter list parameters in a QString<br>
Reimplement partialy the G4UIparameter.cc
@param aCommand : command to list parameters
@see G4UIparameter::List()
@see G4UIcommand::List()
@return the command list parameters, or "" if nothing
*/
QString G4OpenGLQtViewer::GetCommandParameterList (
const G4UIcommand *aCommand
)
{
G4int n_parameterEntry = aCommand->GetParameterEntries();
QString txt;
if( n_parameterEntry > 0 ) {
G4UIparameter *param;
// Re-implementation of G4UIparameter.cc
for( G4int i_thParameter=0; i_thParameter<n_parameterEntry; i_thParameter++ ) {
param = aCommand->GetParameter(i_thParameter);
txt += "\nParameter : " + QString((char*)(param->GetParameterName()).data()) + "\n";
if( ! param->GetParameterGuidance().isNull() )
txt += QString((char*)(param->GetParameterGuidance()).data())+ "\n" ;
txt += " Parameter type : " + QString(QChar(param->GetParameterType())) + "\n";
if(param->IsOmittable()){
txt += " Omittable : True\n";
} else {
txt += " Omittable : False\n";
}
if( param->GetCurrentAsDefault() ) {
txt += " Default value : taken from the current value\n";
} else if( ! param->GetDefaultValue().isNull() ) {
txt += " Default value : " + QString((char*)(param->GetDefaultValue()).data())+ "\n";
}
if( ! param->GetParameterRange().isNull() ) {
txt += " Parameter range : " + QString((char*)(param->GetParameterRange()).data())+ "\n";
}
if( ! param->GetParameterCandidates().isNull() ) {
txt += " Candidates : " + QString((char*)(param->GetParameterCandidates()).data())+ "\n";
}
}
}
return txt;
}
#ifdef G4MULTITHREADED
void G4OpenGLQtViewer::DoneWithMasterThread()
{
// Called by Main Thread !
// Useful to avoid two vis thread at the same time
G4MUTEXLOCK(&mWaitForVisSubThreadQtOpenGLContextInitialized);
}
void G4OpenGLQtViewer::SwitchToVisSubThread()
{
// Called by VisSub Thread !
QGLWidget* qGLW = dynamic_cast<QGLWidget*> (fGLWidget) ;
if (! qGLW) {
return;
}
// Set the current QThread to its static variable
SetQGLContextVisSubThread(QThread::currentThread());
// - Wait for the vis thread to set its QThread
G4CONDITIONBROADCAST(&c1_VisSubThreadQtOpenGLContextInitialized);
// Unlock the vis thread if it is Qt Viewer
G4CONDITIONWAIT(&c2_VisSubThreadQtOpenGLContextMoved, &mWaitForVisSubThreadQtOpenGLContextMoved);
// make context current
qGLW->makeCurrent();
}
void G4OpenGLQtViewer::DoneWithVisSubThread()
{
// Called by vis sub thread
QGLWidget* qGLW = dynamic_cast<QGLWidget*> (fGLWidget) ;
if (! qGLW) {
return;
}
// finish with this vis sub thread context
qGLW->doneCurrent();
#if QT_VERSION > 0x050000
// and move it back to the main thread
qGLW->context()->moveToThread(fQGLContextMainThread);
#endif
}
void G4OpenGLQtViewer::SwitchToMasterThread()
{
// Called by VisSub Thread !
QGLWidget* qGLW = dynamic_cast<QGLWidget*> (fGLWidget) ;
if (! qGLW) {
return;
}
// Useful to avoid two vis thread at the same time
G4MUTEXUNLOCK(&mWaitForVisSubThreadQtOpenGLContextInitialized);
qGLW->makeCurrent();
}
void G4OpenGLQtViewer::MovingToVisSubThread(){
// Called by Main Thread !
QGLWidget* qGLW = dynamic_cast<QGLWidget*> (fGLWidget) ;
if (! qGLW) {
return;
}
// - Wait for the vis sub thread to set its QThread
G4CONDITIONWAIT( &c1_VisSubThreadQtOpenGLContextInitialized, &mWaitForVisSubThreadQtOpenGLContextInitialized);
// Set current QThread for the way back
SetQGLContextMainThread(QThread::currentThread());
// finish with this main thread context
qGLW->doneCurrent();
#if QT_VERSION > 0x050000
qGLW->context()->moveToThread(fQGLContextVisSubThread);
#endif
G4CONDITIONBROADCAST(&c2_VisSubThreadQtOpenGLContextMoved);
}
#endif
/*
void MultiLayer::exportToSVG(const QString& fname)
{
QPicture picture;
QPainter p(&picture);
for (int i=0;i<(int)graphsList->count();i++)
{
Graph *gr=(Graph *)graphsList->at(i);
Plot *myPlot= (Plot *)gr->plotWidget();
QPoint pos=gr->pos();
int width=int(myPlot->frameGeometry().width());
int height=int(myPlot->frameGeometry().height());
myPlot->print(&p, QRect(pos,QSize(width,height)));
}
p.end();
picture.save(fname, "svg");
}
*/
#endif