ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
ecvCustomViewpointButtonDlg.cpp
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 
9 
10 #include "ui_customViewpointButtonDlg.h"
11 
12 // CV_CORE_LIB
13 #include <CVLog.h>
14 #include <CVTools.h>
15 
16 // ECV_DB_TOOL
17 #include <ecvDisplayTools.h>
18 #include <ecvGenericCameraTool.h>
19 
20 #ifdef USE_PCL_BACKEND
22 #endif
23 
24 // LOCAL
25 #include <QDebug>
26 #include <QFileDialog>
27 #include <QToolButton>
28 #include <cassert>
29 #include <sstream>
30 #include <string>
31 
32 #include "ecvFileUtils.h"
33 #include "ecvPersistentSettings.h"
34 #include "ecvSettingManager.h"
35 
36 // User interface
37 //=============================================================================
38 class pqCustomViewpointButtonDialogUI : public Ui::CustomViewpointButtonDlg {
39  struct RowData {
40  QPointer<QLabel> IndexLabel;
41  QPointer<QLineEdit> ToolTipEdit;
42  QPointer<QPushButton> AssignButton;
43  QPointer<QToolButton> DeleteButton;
44  };
45 
46  QPointer<::ecvCustomViewpointButtonDlg> Parent;
47  QList<RowData> Rows;
48 
49 public:
51  : Parent(parent) {}
53 
54  void setNumberOfRows(int rows) {
55  if (this->Rows.size() == rows) {
56  return;
57  }
58 
59  // enable/disable add button.
60  this->add->setEnabled(
62 
63  // remove extra rows.
64  for (int cc = this->Rows.size() - 1; cc >= rows; --cc) {
65  auto& arow = this->Rows[cc];
66  this->gridLayout->removeWidget(arow.IndexLabel);
67  this->gridLayout->removeWidget(arow.ToolTipEdit);
68  this->gridLayout->removeWidget(arow.AssignButton);
69  if (arow.DeleteButton) {
70  this->gridLayout->removeWidget(arow.DeleteButton);
71  }
72  delete arow.IndexLabel;
73  delete arow.ToolTipEdit;
74  delete arow.AssignButton;
75  delete arow.DeleteButton;
76  this->Rows.pop_back();
77  }
78 
79  // add new rows.
80  for (int cc = this->Rows.size(); cc < rows; ++cc) {
81  RowData arow;
82  arow.IndexLabel = new QLabel(QString::number(cc + 1), this->Parent);
83  arow.IndexLabel->setAlignment(Qt::AlignCenter);
84  arow.ToolTipEdit = new QLineEdit(this->Parent);
85  arow.ToolTipEdit->setToolTip(
86  "This text will be set to the buttons tool tip.");
87  arow.ToolTipEdit->setText(
89  arow.ToolTipEdit->setObjectName(QString("toolTip%1").arg(cc));
90  arow.AssignButton =
91  new QPushButton("Current Viewpoint", this->Parent);
92  arow.AssignButton->setProperty(
93  "pqCustomViewpointButtonDialog_INDEX", cc);
94  arow.AssignButton->setObjectName(
95  QString("currentViewpoint%1").arg(cc));
96  this->Parent->connect(arow.AssignButton, SIGNAL(clicked()),
97  SLOT(assignCurrentViewpoint()));
98  this->gridLayout->addWidget(arow.IndexLabel, cc + 1, 0);
99  this->gridLayout->addWidget(arow.ToolTipEdit, cc + 1, 1);
100  this->gridLayout->addWidget(arow.AssignButton, cc + 1, 2);
102  arow.DeleteButton = new QToolButton(this->Parent);
103  arow.DeleteButton->setObjectName(QString("delete%1").arg(cc));
104  arow.DeleteButton->setIcon(
105  QIcon(":/Resources/images/ecvdelete.png"));
106  arow.DeleteButton->setProperty(
107  "pqCustomViewpointButtonDialog_INDEX", cc);
108  this->gridLayout->addWidget(arow.DeleteButton, cc + 1, 3);
109  this->Parent->connect(arow.DeleteButton, SIGNAL(clicked()),
110  SLOT(deleteRow()));
111  }
112  this->Rows.push_back(arow);
113  }
114  }
115 
116  int rowCount() const { return this->Rows.size(); }
117 
118  void setToolTips(const QStringList& txts) {
119  assert(this->Rows.size() == txts.size());
120  for (int cc = 0, max = this->Rows.size(); cc < max; ++cc) {
121  this->Rows[cc].ToolTipEdit->setText(txts[cc]);
122  }
123  }
124 
125  QStringList toolTips() const {
126  QStringList tips;
127  for (const auto& arow : this->Rows) {
128  tips.push_back(arow.ToolTipEdit->text());
129  }
130  return tips;
131  }
132 
133  void setToolTip(int index, const QString& txt) {
134  assert(index >= 0 && index < this->Rows.size());
135  this->Rows[index].ToolTipEdit->setText(txt);
136  this->Rows[index].ToolTipEdit->selectAll();
137  this->Rows[index].ToolTipEdit->setFocus();
138  }
139 
140  QString toolTip(int index) const {
141  assert(index >= 0 && index < this->Rows.size());
142  return this->Rows[index].ToolTipEdit->text();
143  }
144 
145  void deleteRow(int index) {
146  assert(index >= 0 && index < this->Rows.size());
147  auto& arow = this->Rows[index];
148  this->gridLayout->removeWidget(arow.IndexLabel);
149  this->gridLayout->removeWidget(arow.ToolTipEdit);
150  this->gridLayout->removeWidget(arow.AssignButton);
151  if (arow.DeleteButton) {
152  this->gridLayout->removeWidget(arow.DeleteButton);
153  }
154  delete arow.IndexLabel;
155  delete arow.ToolTipEdit;
156  delete arow.AssignButton;
157  delete arow.DeleteButton;
158  this->Rows.removeAt(index);
159 
160  // now update names and widget layout in the grid
161  for (int cc = index; cc < this->Rows.size(); ++cc) {
162  auto& currentRow = this->Rows[cc];
163  currentRow.IndexLabel->setText(QString::number(cc + 1));
164  currentRow.AssignButton->setProperty(
165  "pqCustomViewpointButtonDialog_INDEX", cc);
166  this->gridLayout->addWidget(currentRow.IndexLabel, cc + 1, 0);
167  this->gridLayout->addWidget(currentRow.ToolTipEdit, cc + 1, 1);
168  this->gridLayout->addWidget(currentRow.AssignButton, cc + 1, 2);
169  if (currentRow.DeleteButton) {
170  currentRow.DeleteButton->setProperty(
171  "pqCustomViewpointButtonDialog_INDEX", cc);
172  this->gridLayout->addWidget(currentRow.DeleteButton, cc + 1, 3);
173  }
174  }
175 
176  // enable/disable add button.
177  this->add->setEnabled(
178  this->Rows.size() <
180  }
181 };
182 
183 // Organizes button config file info in a single location.
184 //=============================================================================
186 public:
188  : FileIdentifier("CustomViewpointsConfiguration"),
189  FileDescription("Custom Viewpoints Configuration"),
190  FileExtension(".cam"),
191  WriterVersion("1.0") {}
192  const char* FileIdentifier;
193  const char* FileDescription;
194  const char* FileExtension;
195  const char* WriterVersion;
196 };
197 
198 //------------------------------------------------------------------------------
200  QString("Unnamed Viewpoint");
203 
204 //------------------------------------------------------------------------------
206  Qt::WindowFlags flags,
207  QStringList& toolTips,
208  QStringList& configs,
209  QString& curConfig)
210  : QDialog(Parent, flags), ui(nullptr) {
211  this->ui = new pqCustomViewpointButtonDialogUI(this);
212  this->ui->setupUi(this);
213  this->setToolTipsAndConfigurations(toolTips, configs);
214  this->setCurrentConfiguration(curConfig);
215  QObject::connect(this->ui->add, SIGNAL(clicked()), this, SLOT(appendRow()));
216  QObject::connect(this->ui->clearAll, SIGNAL(clicked()), this,
217  SLOT(clearAll()));
218  QObject::connect(this->ui->importAll, SIGNAL(clicked()), this,
219  SLOT(importConfigurations()));
220  QObject::connect(this->ui->exportAll, SIGNAL(clicked()), this,
221  SLOT(exportConfigurations()));
222 }
223 
224 //------------------------------------------------------------------------------
226  delete this->ui;
227  this->ui = NULL;
228 }
229 
230 //------------------------------------------------------------------------------
232  const QStringList& toolTips, const QStringList& configs) {
233  if (toolTips.size() != configs.size()) {
234  qWarning(
235  "`setToolTipsAndConfigurations` called with mismatched "
236  "lengths.");
237  }
238 
239  int minSize = std::min(toolTips.size(), configs.size());
240  if (minSize > MAXIMUM_NUMBER_OF_ITEMS) {
241  qWarning() << "configs greater than " << MAXIMUM_NUMBER_OF_ITEMS
242  << " will be ignored.";
243  minSize = MAXIMUM_NUMBER_OF_ITEMS;
244  }
245 
246  QStringList realToolTips = toolTips.mid(0, minSize);
247  QStringList realConfigs = configs.mid(0, minSize);
248 
249  // ensure there are at least MINIMUM_NUMBER_OF_ITEMS items.
250  for (int cc = minSize; cc < MINIMUM_NUMBER_OF_ITEMS; ++cc) {
251  realToolTips.push_back(DEFAULT_TOOLTIP);
252  realConfigs.push_back(QString());
253  }
254 
255  this->ui->setNumberOfRows(realToolTips.size());
256  this->ui->setToolTips(realToolTips);
257  this->setConfigurations(realConfigs);
258 }
259 
260 //------------------------------------------------------------------------------
261 void ecvCustomViewpointButtonDlg::setToolTips(const QStringList& toolTips) {
262  if (toolTips.length() != this->ui->rowCount()) {
263  CVLog::Error("Error: Wrong number of tool tips.");
264  return;
265  }
266  this->ui->setToolTips(toolTips);
267 }
268 
269 //------------------------------------------------------------------------------
271  return this->ui->toolTips();
272 }
273 
274 //------------------------------------------------------------------------------
276  const QStringList& configs) {
277  if (configs.length() != this->ui->rowCount()) {
278  CVLog::Error("Error: Wrong number of configurations.");
279  return;
280  }
281  this->Configurations = configs;
282 }
283 
284 //------------------------------------------------------------------------------
286  return this->Configurations;
287 }
288 
289 //------------------------------------------------------------------------------
291  const QString& config) {
292  this->CurrentConfiguration = config;
293 }
294 
295 //------------------------------------------------------------------------------
297  return this->CurrentConfiguration;
298 }
299 
300 //------------------------------------------------------------------------------
301 void ecvCustomViewpointButtonDlg::importConfigurations() {
302  // What follows is a reader for an xml format that contains
303  // a group of nested Camera Configuration XML hierarchies
304  // each written by the vtkSMCameraConfigurationWriter.
305  // The nested configuration hierarchies might be empty.
307 
308  QString filters = QString("%1 (*%2);;All Files (*.*)")
309  .arg(fileInfo.FileDescription)
310  .arg(fileInfo.FileExtension);
311 
312  // persistent settings
313  QString currentPath =
316  .toString();
317  QStringList selectedFiles = QFileDialog::getOpenFileNames(
318  this, QString("Load Custom Viewpoints Configuration"), currentPath,
319  filters);
320 
321  if (selectedFiles.isEmpty()) return;
322  QString filename;
323  filename = selectedFiles[0];
324 
326 
327 #ifdef USE_PCL_BACKEND
329 #else
331  "[ecvCustomViewpointButtonDlg::importConfigurations] please use "
332  "pcl as backend and then try again!");
333 #endif
334 
335  // read buttons, their toolTips, and configurations.
336  QStringList toolTips;
337  toolTips << DEFAULT_TOOLTIP;
338  QStringList configs;
340 
341  // Pass the newly loaded configuration to the GUI.
342  this->setToolTipsAndConfigurations(toolTips, configs);
343 }
344 
345 //------------------------------------------------------------------------------
346 void ecvCustomViewpointButtonDlg::exportConfigurations() {
348 
349  QString filters = QString("%1 (*%2);;All Files (*.*)")
350  .arg(fileInfo.FileDescription)
351  .arg(fileInfo.FileExtension);
352 
353  // default output path (+ filename)
354  QString currentPath =
357  .toString();
358 
359  // ask the user for the output filename
360  QString selectedFilename = QFileDialog::getSaveFileName(
361  this, tr("Save Custom Viewpoints Configuration"), currentPath,
362  filters);
363 
364  if (selectedFilename.isEmpty()) {
365  // process cancelled by the user
366  return;
367  }
368 
369  QString filename = selectedFilename;
371 }
372 
373 //------------------------------------------------------------------------------
374 void ecvCustomViewpointButtonDlg::appendRow() {
375  const int numRows = this->ui->rowCount();
376  assert(numRows < MAXIMUM_NUMBER_OF_ITEMS);
377  this->ui->setNumberOfRows(numRows + 1);
378 #ifdef USE_PCL_BACKEND
380 #else
382  "[ecvCustomViewpointButtonDlg::importConfigurations] please use "
383  "pcl as backend and then try again!");
384 #endif
385 
386  // read configurations.
387  QString curCameraParam =
389  this->Configurations.push_back(curCameraParam);
390 }
391 
392 //------------------------------------------------------------------------------
393 void ecvCustomViewpointButtonDlg::clearAll() {
394  this->setToolTipsAndConfigurations(QStringList(), QStringList());
395 }
396 
397 //------------------------------------------------------------------------------
398 void ecvCustomViewpointButtonDlg::assignCurrentViewpoint() {
399  int row = -1;
400  if (QObject* asender = this->sender()) {
401  row = asender->property("pqCustomViewpointButtonDialog_INDEX").toInt();
402  }
403 
404  if (row >= 0 && row < this->ui->rowCount()) {
405  this->Configurations[row] = this->CurrentConfiguration;
406  if (this->ui->toolTip(row) ==
408  this->ui->setToolTip(
409  row, "Current Viewpoint " + QString::number(row + 1));
410  }
411  }
412 }
413 
414 //------------------------------------------------------------------------------
415 void ecvCustomViewpointButtonDlg::deleteRow() {
416  int row = -1;
417  if (QObject* asender = this->sender()) {
418  row = asender->property("pqCustomViewpointButtonDialog_INDEX").toInt();
419  }
420 
421  if (row >= 0 && row < this->ui->rowCount()) {
422  this->ui->deleteRow(row);
423  this->Configurations.removeAt(row);
424  }
425 }
std::string filename
#define NULL
static bool Warning(const char *format,...)
Prints out a formatted warning message in console.
Definition: CVLog.cpp:133
static bool Error(const char *format,...)
Display an error dialog with formatted message.
Definition: CVLog.cpp:143
static std::string FromQString(const QString &qs)
Definition: CVTools.cpp:100
static void UpdateCameraInfo()
void setConfigurations(const QStringList &configs)
ecvCustomViewpointButtonDlg(QWidget *parent, Qt::WindowFlags f, QStringList &toolTips, QStringList &configurations, QString &currentConfig)
void setToolTips(const QStringList &toolTips)
void setCurrentConfiguration(const QString &config)
void setToolTipsAndConfigurations(const QStringList &toolTips, const QStringList &configs)
static void SaveCameraParameters(const std::string &file)
Save or Load the current rendered camera parameters to disk or current camera.
static void LoadCameraParameters(const std::string &file)
static CameraInfo CurrentCameraParam
static const QString CurrentPath()
static const QString SaveFile()
static const QString LoadFile()
static QVariant getValue(const QString &section, const QString &key, const QVariant &defaultValue=QVariant())
void setToolTips(const QStringList &txts)
pqCustomViewpointButtonDialogUI(::ecvCustomViewpointButtonDlg *parent)
void setToolTip(int index, const QString &txt)
QString defaultDocPath()
Shortcut for getting the documents location path.
Definition: ecvFileUtils.h:30