swift
simulatorselector.cpp
1 // SPDX-FileCopyrightText: Copyright (C) 2015 swift Project Community / Contributors
2 // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
3 
5 
6 #include <QCheckBox>
7 #include <QPointer>
8 #include <QRadioButton>
9 #include <QWidget>
10 #include <QtGlobal>
11 
12 #include "ui_simulatorselector.h"
13 
14 #include "config/buildconfig.h"
16 #include "gui/guiapplication.h"
17 #include "gui/guiutility.h"
18 #include "misc/icons.h"
20 
21 using namespace swift::config;
22 using namespace swift::misc;
23 using namespace swift::misc::simulation;
24 using namespace swift::core::context;
25 
26 namespace swift::gui::components
27 {
28  CSimulatorSelector::CSimulatorSelector(QWidget *parent) : QFrame(parent), ui(new Ui::CSimulatorSelector)
29  {
30  ui->setupUi(this);
31 
32  this->addComboxBoxValues();
33  this->setMode(CheckBoxes, true);
34 
35  connect(ui->rb_FS9, &QRadioButton::toggled, this, &CSimulatorSelector::radioButtonChanged);
36  connect(ui->rb_FSX, &QRadioButton::toggled, this, &CSimulatorSelector::radioButtonChanged);
37  connect(ui->rb_P3D, &QRadioButton::toggled, this, &CSimulatorSelector::radioButtonChanged);
38  connect(ui->rb_FG, &QRadioButton::toggled, this, &CSimulatorSelector::radioButtonChanged);
39  connect(ui->rb_XPlane, &QRadioButton::toggled, this, &CSimulatorSelector::radioButtonChanged);
40  connect(ui->rb_MSFS, &QRadioButton::toggled, this, &CSimulatorSelector::radioButtonChanged);
41  connect(ui->rb_MSFS2024, &QRadioButton::toggled, this, &CSimulatorSelector::radioButtonChanged);
42 
43  connect(ui->cb_FS9, &QRadioButton::toggled, this, &CSimulatorSelector::checkBoxChanged);
44  connect(ui->cb_FSX, &QRadioButton::toggled, this, &CSimulatorSelector::checkBoxChanged);
45  connect(ui->cb_P3D, &QRadioButton::toggled, this, &CSimulatorSelector::checkBoxChanged);
46  connect(ui->cb_FG, &QRadioButton::toggled, this, &CSimulatorSelector::checkBoxChanged);
47  connect(ui->cb_XPlane, &QRadioButton::toggled, this, &CSimulatorSelector::checkBoxChanged);
48  connect(ui->cb_MSFS, &QRadioButton::toggled, this, &CSimulatorSelector::checkBoxChanged);
49  connect(ui->cb_MSFS2024, &QRadioButton::toggled, this, &CSimulatorSelector::checkBoxChanged);
50 
51  connect(ui->cb_Simulators, &QComboBox::currentTextChanged, this, &CSimulatorSelector::comboBoxChanged);
52  }
53 
55 
57  {
58  if (m_mode == mode && !forced) { return; }
59  m_mode = mode;
60 
61  ui->wi_CheckBoxes->setVisible(false);
62  ui->wi_RadioButtons->setVisible(false);
63  ui->wi_ComboBox->setVisible(false);
64 
65  switch (mode)
66  {
67  default:
68  case CheckBoxes: ui->wi_CheckBoxes->setVisible(true); break;
69  case RadioButtons: ui->wi_RadioButtons->setVisible(true); break;
70  case ComboBox: ui->wi_ComboBox->setVisible(true); break;
71  }
72  this->setToLastSelection();
73  }
74 
76  {
77  if (m_noSelectionMeansAll && this->isUnselected()) { return CSimulatorInfo::allSimulators(); }
78 
79  switch (m_mode)
80  {
81  default:
82  case CheckBoxes:
83  return CSimulatorInfo(ui->cb_FSX->isChecked(), ui->cb_FS9->isChecked(), ui->cb_XPlane->isChecked(),
84  ui->cb_P3D->isChecked(), ui->cb_FG->isChecked(), ui->cb_MSFS->isChecked(),
85  ui->cb_MSFS2024->isChecked());
86  case RadioButtons:
87  return CSimulatorInfo(ui->rb_FSX->isChecked(), ui->rb_FS9->isChecked(), ui->rb_XPlane->isChecked(),
88  ui->rb_P3D->isChecked(), ui->rb_FG->isChecked(), ui->rb_MSFS->isChecked(),
89  ui->rb_MSFS2024->isChecked());
90  case ComboBox: return CSimulatorInfo(ui->cb_Simulators->currentText());
91  }
92  }
93 
95  {
96  const CSimulatorInfo current(this->getValue());
97  if (simulator == current) { return; } // avoid unnecessary signals
98 
99  // checkboxes
100  ui->cb_FSX->setChecked(simulator.isFSX());
101  ui->cb_FS9->setChecked(simulator.isFS9());
102  ui->cb_XPlane->setChecked(simulator.isXPlane());
103  ui->cb_P3D->setChecked(simulator.isP3D());
104  ui->cb_FG->setChecked(simulator.isFG());
105  ui->cb_MSFS->setChecked(simulator.isMSFS());
106  ui->cb_MSFS2024->setChecked(simulator.isMSFS2024());
107 
108  // Combo
109  ui->cb_Simulators->setCurrentText(simulator.toQString(true));
110 
111  // radio buttons
112  if (simulator.isFSX())
113  {
114  ui->rb_FSX->setChecked(simulator.isFSX());
115  return;
116  }
117  if (simulator.isFS9())
118  {
119  ui->rb_FS9->setChecked(simulator.isFS9());
120  return;
121  }
122  if (simulator.isXPlane())
123  {
124  ui->rb_XPlane->setChecked(simulator.isXPlane());
125  return;
126  }
127  if (simulator.isP3D())
128  {
129  ui->rb_P3D->setChecked(simulator.isP3D());
130  return;
131  }
132  if (simulator.isFG())
133  {
134  ui->rb_FG->setChecked(simulator.isFG());
135  return;
136  }
137  if (simulator.isMSFS())
138  {
139  ui->rb_MSFS->setChecked(simulator.isMSFS());
140  return;
141  }
142  if (simulator.isMSFS2024())
143  {
144  ui->rb_MSFS2024->setChecked(simulator.isMSFS2024());
145  return;
146  }
147  }
148 
150  {
151  const CSimulatorInfo simulator =
152  (m_mode == RadioButtons || m_mode == ComboBox) ? m_currentSimulator.get() : m_currentSimulators.get();
153  this->setValue(simulator);
154  }
155 
157  {
159  {
161  if (!this->isSingleSelection()) { this->setMode(RadioButtons); } // only one sim can be connected
162 
163  if (pluginInfo.isValid())
164  {
165  this->setReadOnly(makeReadOnly);
166  this->setValue(pluginInfo.getSimulator());
167  }
168  else
169  {
170  if (makeReadOnly) { this->setReadOnly(false); }
172  if (simulator.isSingleSimulator()) { this->setValue(simulator); }
173  }
174  }
175  else
176  {
177  if (makeReadOnly) { this->setReadOnly(false); }
178  }
179  }
180 
181  void CSimulatorSelector::setToConnectedSimulator(int deferredMs, bool makeReadOnly)
182  {
183  if (deferredMs < 1)
184  {
185  this->setToConnectedSimulator(makeReadOnly);
186  return;
187  }
188 
189  if (!sGui || sGui->isShuttingDown()) { return; }
190  QPointer<CSimulatorSelector> myself(this);
191  QTimer::singleShot(deferredMs, this, [=] {
192  if (!sGui || sGui->isShuttingDown() || !myself) { return; }
193  this->setToConnectedSimulator(makeReadOnly);
194  });
195  }
196 
198  {
199  ui->cb_FS9->setVisible(false);
200  ui->cb_XPlane->setVisible(false);
201  ui->cb_FG->setVisible(false);
202  ui->rb_FS9->setVisible(false);
203  ui->rb_XPlane->setVisible(false);
204  ui->rb_FG->setVisible(false);
205  }
206 
207  void CSimulatorSelector::enableFG(bool enabled)
208  {
209  ui->cb_FG->setVisible(enabled);
210  ui->rb_FG->setVisible(enabled);
211  ui->cb_FG->setChecked(false);
212  ui->rb_FG->setChecked(false);
213  }
214 
216  {
217  // checkboxes
218  ui->cb_FSX->setChecked(true);
219  ui->cb_FS9->setChecked(true);
220  ui->cb_XPlane->setChecked(true);
221  ui->cb_P3D->setChecked(true);
222  ui->cb_FG->setChecked(true);
223  ui->cb_MSFS->setChecked(true);
224  ui->cb_MSFS2024->setChecked(true);
225 
226  // radio
227  ui->rb_P3D->setChecked(true);
228  }
229 
231  {
232  // checkboxes
233  ui->cb_FSX->setChecked(false);
234  ui->cb_FS9->setChecked(false);
235  ui->cb_XPlane->setChecked(false);
236  ui->cb_P3D->setChecked(false);
237  ui->cb_FG->setChecked(false);
238  ui->cb_MSFS->setChecked(false);
239  ui->cb_MSFS2024->setChecked(false);
240  }
241 
243  {
244  bool c = false;
245  switch (m_mode)
246  {
247  default:
248  case CheckBoxes:
249  c = ui->cb_FSX->isChecked() || ui->cb_FS9->isChecked() || ui->cb_XPlane->isChecked() ||
250  ui->cb_P3D->isChecked() || ui->cb_FG->isChecked() || ui->cb_MSFS->isChecked() ||
251  ui->cb_MSFS2024->isChecked();
252  break;
253  case RadioButtons:
254  c = ui->rb_FSX->isChecked() || ui->rb_FS9->isChecked() || ui->rb_XPlane->isChecked() ||
255  ui->rb_P3D->isChecked() || ui->rb_FG->isChecked() || ui->rb_MSFS->isChecked() ||
256  ui->rb_MSFS2024->isChecked();
257  break;
258  case ComboBox:
259  const int i = ui->cb_Simulators->currentIndex();
260  c = i < 0;
261  break;
262  }
263  return !c;
264  }
265 
267  {
268  bool c = false;
269  switch (m_mode)
270  {
271  default:
272  case CheckBoxes:
273  c = ui->cb_FSX->isChecked() && ui->cb_FS9->isChecked() && ui->cb_XPlane->isChecked() &&
274  ui->cb_P3D->isChecked() && ui->cb_FG->isChecked() && ui->cb_MSFS->isChecked() &&
275  ui->cb_MSFS2024->isChecked();
276  break;
277  case RadioButtons:
278  // actually this should never be true
279  c = false;
280  break;
281  case ComboBox:
282  // actually this should never be true
283  c = false;
284  break;
285  }
286  return c;
287  }
288 
290  {
291  QMargins m = ui->hl_RadioButtons->contentsMargins();
292  m.setLeft(margin);
293  ui->hl_RadioButtons->setContentsMargins(m);
294 
295  m = ui->hl_CheckBoxes->contentsMargins();
296  m.setLeft(margin);
297  ui->hl_CheckBoxes->setContentsMargins(m);
298  }
299 
301  {
302  this->setRememberSelection(true);
303  this->setToLastSelection();
304  }
305 
307  {
308  if (m_mode == CheckBoxes) { this->uncheckAll(); }
309  }
310 
311  bool CSimulatorSelector::isSingleSelection() const { return m_mode == RadioButtons || m_mode == ComboBox; }
312 
314  {
315  CGuiUtility::checkBoxesReadOnly(this, readOnly);
316  ui->rb_FSX->setEnabled(!readOnly);
317  ui->rb_FS9->setEnabled(!readOnly);
318  ui->rb_XPlane->setEnabled(!readOnly);
319  ui->rb_P3D->setEnabled(!readOnly);
320  ui->rb_FG->setEnabled(!readOnly);
321  ui->rb_MSFS->setEnabled(!readOnly);
322  ui->rb_MSFS2024->setEnabled(!readOnly);
323 
324  ui->cb_Simulators->setEnabled(!readOnly);
325 
326  this->setEnabled(!readOnly);
327  }
328 
329  void CSimulatorSelector::radioButtonChanged(bool checked)
330  {
331  if (m_mode != RadioButtons) { return; }
332  if (!checked)
333  {
334  return;
335  } // only the checked ones are relevant, as the unchecked ones are accompanied with checked events
336  m_digestButtonsChanged.inputSignal();
337  }
338 
339  void CSimulatorSelector::checkBoxChanged(bool checked)
340  {
341  if (m_mode != CheckBoxes) { return; }
342  Q_UNUSED(checked);
343  m_digestButtonsChanged.inputSignal();
344  }
345 
346  void CSimulatorSelector::comboBoxChanged(const QString &value)
347  {
348  if (m_mode != ComboBox) { return; }
349  Q_UNUSED(value);
350  m_digestButtonsChanged.inputSignal();
351  }
352 
353  void CSimulatorSelector::rememberSelection()
354  {
355  if (!m_rememberSelection) { return; }
356  if (this->isSingleSelection())
357  {
358  // single
359  const CSimulatorInfo sim = this->getValue();
360  m_currentSimulator.set(sim);
361  }
362  else
363  {
364  // multiple
365  const CSimulatorInfo sim = this->getValue();
366  m_currentSimulators.set(sim);
367  }
368  }
369 
370  void CSimulatorSelector::changedLastSelection()
371  {
372  // force decoupled update
373  this->triggerSetToLastSelection();
374  }
375 
376  void CSimulatorSelector::changedLastSelectionRb()
377  {
378  // force decoupled update
379  if (m_mode != RadioButtons) { return; }
380  this->triggerSetToLastSelection();
381  }
382 
383  void CSimulatorSelector::changedLastSelectionCb()
384  {
385  // force decoupled update
386  if (m_mode != CheckBoxes) { return; }
387  this->triggerSetToLastSelection();
388  }
389 
390  void CSimulatorSelector::triggerSetToLastSelection()
391  {
392  QPointer<CSimulatorSelector> myself(this);
393  QTimer::singleShot(100, this, [=] {
394  if (!myself) { return; }
395  this->setToLastSelection();
396  });
397  }
398 
399  void CSimulatorSelector::emitChangedSignal()
400  {
401  const CSimulatorInfo simulator(this->getValue());
402  this->rememberSelection();
403  emit this->changed(simulator);
404  }
405 
406  void CSimulatorSelector::addComboxBoxValues()
407  {
408  int cbi = 0;
409  ui->cb_Simulators->clear();
410  ui->cb_Simulators->insertItem(cbi++, CSimulatorInfo::fs9().toQString());
411  ui->cb_Simulators->insertItem(cbi++, CSimulatorInfo::fsx().toQString());
412  ui->cb_Simulators->insertItem(cbi++, CSimulatorInfo::p3d().toQString());
413  ui->cb_Simulators->insertItem(cbi++, CSimulatorInfo::xplane().toQString());
414  ui->cb_Simulators->insertItem(cbi++, CSimulatorInfo::fg().toQString());
415  ui->cb_Simulators->insertItem(cbi++, CSimulatorInfo::msfs().toQString());
416  ui->cb_Simulators->insertItem(cbi++, CSimulatorInfo::msfs2024().toQString());
417  }
418 } // namespace swift::gui::components
bool isShuttingDown() const
Is application shutting down?
const context::IContextSimulator * getIContextSimulator() const
Direct access to contexts if a CCoreFacade has been initialized.
bool supportsContexts(bool ignoreShutdownTest=false) const
Supports contexts.
virtual swift::misc::simulation::CSimulatorPluginInfo getSimulatorPluginInfo() const =0
Simulator info, currently loaded plugin.
virtual swift::misc::simulation::CSimulatorInfo getModelSetLoaderSimulator() const =0
Get the model set loader simulator directly.
static void checkBoxesReadOnly(QWidget *parent, bool readOnly)
Pseudo readonly state for checkboxes of widget.
Definition: guiutility.cpp:476
Select simulator (as radio buttons or checkboxes)
void setToLastSelection()
Set to last selection.
void setMode(Mode mode, bool forced=false)
How to display.
bool isUnselected() const
Not selected at all.
bool isSingleSelection() const
Single selection mode (radio buttons)
void setRememberSelectionAndSetToLastSelection()
Remember selection.
void setReadOnly(bool readOnly)
Set read only.
void setValue(const swift::misc::simulation::CSimulatorInfo &simulator)
Set the value.
void setRememberSelection(bool remember)
Remember selection.
void setLeftMargin(int margin)
Set left margin.
void uncheckAll()
Unset all, only making sense with checkboxes.
void changed(const swift::misc::simulation::CSimulatorInfo &simulator)
Value has been changed.
void setToConnectedSimulator(bool makeReadOnly=true)
Set to the connected simulator.
swift::misc::simulation::CSimulatorInfo getValue() const
Get the value.
void checkAll()
Set all, only making sense with checkboxes.
T get() const
Get a copy of the current value.
Definition: valuecache.h:408
CStatusMessage set(const typename Trait::type &value, qint64 timestamp=0)
Write a new value. Must be called from the thread in which the owner lives.
Definition: datacache.h:350
void inputSignal()
Received input signal, or manually trigger.
QString toQString(bool i18n=false) const
Cast as QString.
Definition: mixinstring.h:76
Simple hardcoded info about the corresponding simulator.
Definition: simulatorinfo.h:41
bool isSingleSimulator() const
Single simulator selected.
const QString & getSimulator() const
Simulator.
bool isValid() const
Check if the provided plugin metadata is valid. Simulator plugin (driver) has to meet the following r...
SWIFT_GUI_EXPORT swift::gui::CGuiApplication * sGui
Single instance of GUI application object.
High level reusable GUI components.
Definition: aboutdialog.cpp:13
Free functions in swift::misc.
auto singleShot(int msec, QObject *target, F &&task)
Starts a single-shot timer which will call a task in the thread of the given object when it times out...
Definition: threadutils.h:30