gui
Loading...
Searching...
No Matches
gui.cc
Go to the documentation of this file.
1// gui
2#include "gui.h"
3#include "gtree.h"
4#include "g4SceneProperties.h"
5#ifdef GEMC_HAS_QTCHARTS
6#include "gAnalysisView.h"
7#endif
8
9// geant4
10#include "G4UImanager.hh"
11
12// c++
13#include <algorithm>
14#include <utility>
15
16
17namespace {
18void resetSceneBeforeGeometryReload(G4UImanager* g4uim) {
19 if (!g4uim) { return; }
20
21 g4uim->ApplyCommand("/vis/viewer/set/autoRefresh false");
22 g4uim->ApplyCommand("/vis/scene/endOfEventAction accumulate 0");
23 g4uim->ApplyCommand("/vis/scene/endOfRunAction refresh");
24 g4uim->ApplyCommand("/vis/scene/removeModel all");
25 g4uim->ApplyCommand("/vis/viewer/clearTransients");
26 g4uim->ApplyCommand("/vis/viewer/clear");
27 g4uim->ApplyCommand("/vis/viewer/set/autoRefresh true");
28 g4uim->ApplyCommand("/vis/viewer/flush");
29 g4uim->ApplyCommand("/vis/viewer/clearTransients");
30}
31
32void resetEventDrawingBeforeRun(G4UImanager* g4uim) {
33 if (!g4uim) { return; }
34
35 g4uim->ApplyCommand("/vis/viewer/set/autoRefresh false");
36 g4uim->ApplyCommand("/vis/scene/endOfEventAction accumulate 0");
37 g4uim->ApplyCommand("/vis/scene/endOfRunAction refresh");
38 g4uim->ApplyCommand("/vis/viewer/clearTransients");
39 g4uim->ApplyCommand("/vis/viewer/clear");
40 g4uim->ApplyCommand("/vis/viewer/flush");
41 g4uim->ApplyCommand("/vis/viewer/clearTransients");
42}
43
44void restoreSceneModels(G4UImanager* g4uim, const std::shared_ptr<GOptions>& gopts, bool includeEventModels) {
45 if (!g4uim) { return; }
46
47 const auto g4view = g4display::getG4View(gopts);
48 G4SceneProperties g4SceneProperties(gopts);
49
50 g4uim->ApplyCommand("/vis/viewer/set/autoRefresh false");
51 g4uim->ApplyCommand("/vis/scene/removeModel all");
52 g4uim->ApplyCommand("/vis/viewer/clearTransients");
53 g4uim->ApplyCommand("/vis/viewer/clear");
54 g4uim->ApplyCommand("/vis/drawVolume");
55 g4uim->ApplyCommand("/vis/viewer/set/background " + g4view.background);
56 g4uim->ApplyCommand("/vis/viewer/set/numberOfCloudPoints " + std::to_string(g4view.cloudPoints));
57 for (const auto& command : g4SceneProperties.addSceneDecorations(gopts)) { g4uim->ApplyCommand(command); }
58 for (const auto& command : g4SceneProperties.addSceneTexts(gopts)) { g4uim->ApplyCommand(command); }
59 if (includeEventModels) {
60 const auto decorations = g4display::getG4Decorations(gopts);
61 g4uim->ApplyCommand("/vis/scene/add/trajectories smooth");
62 g4uim->ApplyCommand("/vis/modeling/trajectories/create/drawByCharge");
63 g4uim->ApplyCommand("/vis/modeling/trajectories/drawByCharge-0/default/setDrawStepPts true");
64 g4uim->ApplyCommand("/vis/modeling/trajectories/drawByCharge-0/default/setStepPtsSize 2");
65 g4uim->ApplyCommand("/vis/scene/add/hits");
66 g4uim->ApplyCommand("/vis/scene/endOfEventAction accumulate 10000");
67 if (decorations.eventID) {
68 g4uim->ApplyCommand("/vis/scene/add/eventID " + std::to_string(decorations.eventIDSize));
69 }
70 }
71 g4uim->ApplyCommand("/vis/viewer/set/autoRefresh true");
72 g4uim->ApplyCommand("/vis/viewer/flush");
73}
74}
75
76
77GemcGUI::GemcGUI(std::shared_ptr<GOptions> gopts,
78 std::shared_ptr<EventDispenser> ed,
80 std::shared_ptr<GAnalysisAccumulator> analyzer,
81 bool viewerAlreadyInitialized,
82 QWidget* parent) :
83 QWidget(parent),
85 analysisAccumulator(std::move(analyzer)),
86 guiOptions(gopts),
87 detectorConstruction(dc),
88 viewerInitialized(viewerAlreadyInitialized) {
89
90 // Create the left navigation pane first; right content initialization uses it to sync selection state.
91 createLeftButtons(); // instantiates leftButtons
92
93 // The board is a long-lived widget attached to this GUI; it is used by other pages (e.g. dialog).
94 auto* gboard = new GBoard(gopts, this);
95
96 // Session object ties together options and the board; it is kept alive for the GUI lifetime.
97 guiSession = std::make_unique<GUI_Session>(gopts, gboard);
98
99 // Create the right stacked content pages (display, dialog, setup, tree) and synchronize default selection.
100 createRightContent(gopts, dc, gboard); // instantiates rightContent: g4control, g4dialog, etc
101
102 // Top row control buttons (run controls and counters).
103 auto* topLayout = new QHBoxLayout;
104 createTopButtons(topLayout);
105
106 // Bottom row contains left navigation and right content; stretch factor favors the content area.
107 auto* bottomLayout = new QHBoxLayout;
108 bottomLayout->setContentsMargins(0, 0, 0, 0);
109 bottomLayout->setSpacing(6);
110 // second argument is stretch factor. Right content can have 10 times more space.
111 bottomLayout->addWidget(leftButtons, 1);
112 bottomLayout->addWidget(rightContent, 10);
113
114 // Main layout: top controls, bottom panes, and board.
115 auto* mainLayout = new QVBoxLayout;
116 mainLayout->setContentsMargins(6, 6, 6, 6);
117 mainLayout->setSpacing(6);
118 mainLayout->addLayout(topLayout);
119 mainLayout->addLayout(bottomLayout, 1);
120 mainLayout->addWidget(gboard, 0);
121
122 setLayout(mainLayout);
123 setWindowTitle(tr("GEMC: Geant4 Monte-Carlo"));
124 setFixedWidth(1000);
125 setMinimumHeight(760);
126 resize(1000, std::max(sizeHint().height(), 760));
127 QTimer::singleShot(0, this, [this]() {
128 adjustSize();
129 const int preferredHeight = std::max(sizeHint().height(), 760);
130 setMinimumHeight(preferredHeight);
131 resize(1000, preferredHeight);
132 });
133
134 // Timer used for cycle mode; timeouts are connected to cycleBeamOn().
135 gtimer = new QTimer(this);
136 connect(gtimer, SIGNAL(timeout()), this, SLOT(cycleBeamOn()));
137
138 // Page switching: left button selection drives the stacked widget page index.
139 connect(leftButtons->buttonsWidget,
140 SIGNAL(currentItemChanged(QListWidgetItem *, QListWidgetItem*)),
141 this, SLOT(change_page(QListWidgetItem *, QListWidgetItem*)));
142}
143
144
145void GemcGUI::updateGui() {
146 // Parse the current label text and increment by the amount run in the most recent batch.
147 std::vector<std::string> sBefore =
148 gutilities::getStringVectorFromString(eventNumberLabel->text().toStdString());
149
150 int nThatWasRun = nEvents->text().toInt();
151 int nBefore = stoi(sBefore[2]);
152
153 QString newNEvents("Event Number: ");
154 newNEvents.append(std::to_string(nBefore + nThatWasRun).c_str());
155
156 eventNumberLabel->setText(newNEvents);
157}
158
159
160void GemcGUI::resetVisualizationBeforeGeometryReload() {
161#ifdef GEMC_HAS_QTCHARTS
162 if (analysisView != nullptr) { analysisView->clearForGeometryReload(); }
163#endif
164 resetSceneBeforeGeometryReload(G4UImanager::GetUIpointer());
165}
166
167void GemcGUI::refreshVisualizationFromOptions() {
168 if (!detectorConstruction || !detectorConstruction->has_built_geometry()) { return; }
169
170 auto* g4uim = G4UImanager::GetUIpointer();
171 if (!g4uim) { return; }
172
173 restoreSceneModels(g4uim, guiOptions, false);
174 visualizationNeedsRunRestore = true;
175}
176
177void GemcGUI::refreshGeometryTree() {
178 if (!rightContent || !detectorConstruction || !guiOptions || !geometryTree) { return; }
179
180 geometryReloadedSinceRun = true;
181
182 const int treeIndex = rightContent->indexOf(geometryTree);
183 if (treeIndex < 0) { return; }
184
185 const int currentIndex = rightContent->currentIndex();
186 auto* g4uim = G4UImanager::GetUIpointer();
187 if (!g4uim) { return; }
188
189 const auto g4volumes = detectorConstruction->has_built_geometry()
190 ? detectorConstruction->get_g4volumes_map()
191 : std::unordered_map<std::string, G4Volume*>{};
192 const auto gvolumes = detectorConstruction->has_built_geometry()
193 ? detectorConstruction->get_gvolumes_flat_map()
194 : std::unordered_map<std::string, const GVolume*>{};
195 const auto gmirrors = detectorConstruction->has_built_geometry()
196 ? detectorConstruction->get_gmirrors_flat_map()
197 : std::unordered_map<std::string, const GMirror*>{};
198 auto* refreshedTree = new GTree(guiOptions, g4volumes, gvolumes, nullptr, gmirrors);
199
200 rightContent->removeWidget(geometryTree);
201 geometryTree->deleteLater();
202 geometryTree = refreshedTree;
203 rightContent->insertWidget(treeIndex, geometryTree);
204 rightContent->setCurrentIndex(currentIndex == treeIndex ? treeIndex : currentIndex);
205
206 if (g4volumes.size() > 1) {
207 if (!viewerInitialized) {
208 // First geometry load: no viewer exists yet; create the named scene and open one.
209 G4SceneProperties g4SceneProperties(guiOptions);
210 auto commands = g4SceneProperties.scene_commands(guiOptions);
211 for (const auto& command : commands) { g4uim->ApplyCommand(command); }
212 viewerInitialized = true;
213 }
214
215 restoreSceneModels(g4uim, guiOptions, false);
216 }
217}
218
219void GemcGUI::prepareGeometryForBeamOn() {
220 if ((!geometryReloadedSinceRun && !visualizationNeedsRunRestore) || !detectorConstruction) { return; }
221 if (!detectorConstruction->has_built_geometry()) { return; }
222
223 auto* g4uim = G4UImanager::GetUIpointer();
224 resetEventDrawingBeforeRun(g4uim);
225
226 if (geometryReloadedSinceRun) {
227 detectorConstruction->prepare_geometry_for_run();
228 if (eventDispenser) {
229 eventDispenser->resetRunContext();
230 }
231 }
232
233 // Restore visualization models after geometry reinitialization.
234 // The run reinitialization can replace the world volume, so restore the same
235 // persistent models used by refreshGeometryTree() before BeamOn draws events.
236 restoreSceneModels(g4uim, guiOptions, true);
237
238 geometryReloadedSinceRun = false;
239 visualizationNeedsRunRestore = false;
240}
241
242
244 // All widgets are owned via Qt parent/child relationships once placed into the layout hierarchy.
245 // Rely on Qt to destroy children when GemcGUI is destroyed.
246}
247
248
249void GemcGUI::change_page(QListWidgetItem* current, QListWidgetItem* previous) {
250
251 // Qt may emit selection changes with a null current item; fall back to the previous selection.
252 if (!current)
253 current = previous;
254
255 // The left button widget provides the active page index; apply it to the stacked widget.
256 int thisIndex = leftButtons->button_pressed();
257 rightContent->setCurrentIndex(thisIndex);
258}
int button_pressed() const
GemcGUI(std::shared_ptr< GOptions > gopts, std::shared_ptr< EventDispenser > ed, GDetectorConstruction *dc, std::shared_ptr< GAnalysisAccumulator > analysisAccumulator, bool viewerAlreadyInitialized=false, QWidget *parent=nullptr)
Construct the main GUI widget.
Definition gui.cc:77
~GemcGUI() override
Destroy the GUI widget and release explicitly owned resources.
Definition gui.cc:243
G4View getG4View(const std::shared_ptr< GOptions > &gopts)
G4Decorations getG4Decorations(const std::shared_ptr< GOptions > &gopts)
vector< std::string > getStringVectorFromString(const std::string &input)