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