ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
cvSelectionLabelPropertiesDialog.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 
11 
12 #include <QCheckBox>
13 #include <QDoubleSpinBox>
14 #include <QFormLayout>
15 #include <QGroupBox>
16 #include <QHBoxLayout>
17 #include <QLabel>
18 #include <QLineEdit>
19 #include <QPushButton>
20 #include <QSlider>
21 #include <QSpinBox>
22 #include <QStyle>
23 #include <QToolButton>
24 #include <QVBoxLayout>
25 
26 //-----------------------------------------------------------------------------
28  QWidget* parent, bool isInteractive)
29  : QDialog(parent), m_isInteractive(isInteractive) {
30  setWindowTitle(isInteractive ? tr("Interactive Selection Label Properties")
31  : tr("Selection Label Properties"));
32  setMinimumWidth(480);
33  loadDefaults();
34  setupUi();
35 }
36 
37 //-----------------------------------------------------------------------------
39 
40 //-----------------------------------------------------------------------------
41 void cvSelectionLabelPropertiesDialog::loadDefaults() {
42  m_defaultProperties = LabelProperties();
43  m_properties = m_defaultProperties;
44 }
45 
46 //-----------------------------------------------------------------------------
47 void cvSelectionLabelPropertiesDialog::setupUi() {
48  QVBoxLayout* mainLayout = new QVBoxLayout(this);
49  mainLayout->setSpacing(10);
50 
51  // === General Settings ===
52  QFormLayout* generalLayout = new QFormLayout();
53  generalLayout->setSpacing(8);
54 
55  // Opacity
56  QHBoxLayout* opacityLayout = new QHBoxLayout();
57  m_opacitySlider = new QSlider(Qt::Horizontal);
58  m_opacitySlider->setRange(0, 100);
59  m_opacitySlider->setValue(static_cast<int>(m_properties.opacity * 100));
60  m_opacitySpin = new QDoubleSpinBox();
61  m_opacitySpin->setRange(0.0, 1.0);
62  m_opacitySpin->setSingleStep(0.1);
63  m_opacitySpin->setDecimals(2);
64  m_opacitySpin->setValue(m_properties.opacity);
65  opacityLayout->addWidget(m_opacitySlider, 1);
66  opacityLayout->addWidget(m_opacitySpin);
67  connect(m_opacitySlider, &QSlider::valueChanged, this,
68  &cvSelectionLabelPropertiesDialog::onOpacitySliderChanged);
69  connect(m_opacitySpin, QOverload<double>::of(&QDoubleSpinBox::valueChanged),
70  [this](double value) {
71  m_opacitySlider->blockSignals(true);
72  m_opacitySlider->setValue(static_cast<int>(value * 100));
73  m_opacitySlider->blockSignals(false);
74  m_properties.opacity = value;
75  });
76  generalLayout->addRow(tr("Opacity"), opacityLayout);
77 
78  // Point Size
79  m_pointSizeSpin = new QSpinBox();
80  m_pointSizeSpin->setRange(1, 50);
81  m_pointSizeSpin->setValue(m_properties.pointSize);
82  connect(m_pointSizeSpin, QOverload<int>::of(&QSpinBox::valueChanged),
83  [this](int value) { m_properties.pointSize = value; });
84  generalLayout->addRow(tr("Point Size"), m_pointSizeSpin);
85 
86  // Line Width
87  m_lineWidthSpin = new QSpinBox();
88  m_lineWidthSpin->setRange(1, 20);
89  m_lineWidthSpin->setValue(m_properties.lineWidth);
90  connect(m_lineWidthSpin, QOverload<int>::of(&QSpinBox::valueChanged),
91  [this](int value) { m_properties.lineWidth = value; });
92  generalLayout->addRow(tr("Line Width"), m_lineWidthSpin);
93 
94  mainLayout->addLayout(generalLayout);
95 
96  // === Cell Label Font ===
97  QGroupBox* cellFontGroup = new QGroupBox(tr("Cell Label Font"));
98  QVBoxLayout* cellFontLayout = new QVBoxLayout();
99 
100  // Font property widget for cell labels
101  m_cellFontWidget = new ecvFontPropertyWidget(this);
102  m_cellFontWidget->setFontProperties(
103  labelPropertiesToFontProperties(m_properties, true));
104  connect(m_cellFontWidget, &ecvFontPropertyWidget::fontPropertiesChanged,
105  this,
106  &cvSelectionLabelPropertiesDialog::onCellFontPropertiesChanged);
107  cellFontLayout->addWidget(m_cellFontWidget);
108 
109  // Cell Label Format
110  QHBoxLayout* cellFormatLayout = new QHBoxLayout();
111  QLabel* cellFormatLabel = new QLabel(tr("Cell Label Format"));
112  m_cellFormatEdit = new QLineEdit();
113  m_cellFormatEdit->setText(m_properties.cellLabelFormat);
114  m_cellFormatEdit->setPlaceholderText(tr("Leave empty for auto format"));
115  connect(m_cellFormatEdit, &QLineEdit::textChanged,
116  [this](const QString& text) {
117  m_properties.cellLabelFormat = text;
118  });
119  cellFormatLayout->addWidget(cellFormatLabel);
120  cellFormatLayout->addWidget(m_cellFormatEdit, 1);
121  cellFontLayout->addLayout(cellFormatLayout);
122 
123  cellFontGroup->setLayout(cellFontLayout);
124  mainLayout->addWidget(cellFontGroup);
125 
126  // === Point Label Font ===
127  QGroupBox* pointFontGroup = new QGroupBox(tr("Point Label Font"));
128  QVBoxLayout* pointFontLayout = new QVBoxLayout();
129 
130  // Font property widget for point labels
131  m_pointFontWidget = new ecvFontPropertyWidget(this);
132  m_pointFontWidget->setFontProperties(
133  labelPropertiesToFontProperties(m_properties, false));
134  connect(m_pointFontWidget, &ecvFontPropertyWidget::fontPropertiesChanged,
135  this,
136  &cvSelectionLabelPropertiesDialog::onPointFontPropertiesChanged);
137  pointFontLayout->addWidget(m_pointFontWidget);
138 
139  // Point Label Format
140  QHBoxLayout* pointFormatLayout = new QHBoxLayout();
141  QLabel* pointFormatLabel = new QLabel(tr("Point Label Format"));
142  m_pointFormatEdit = new QLineEdit();
143  m_pointFormatEdit->setText(m_properties.pointLabelFormat);
144  m_pointFormatEdit->setPlaceholderText(tr("Leave empty for auto format"));
145  connect(m_pointFormatEdit, &QLineEdit::textChanged,
146  [this](const QString& text) {
147  m_properties.pointLabelFormat = text;
148  });
149  pointFormatLayout->addWidget(pointFormatLabel);
150  pointFormatLayout->addWidget(m_pointFormatEdit, 1);
151  pointFontLayout->addLayout(pointFormatLayout);
152 
153  pointFontGroup->setLayout(pointFontLayout);
154  mainLayout->addWidget(pointFontGroup);
155 
156  // === Tooltip Settings ===
157  QGroupBox* tooltipGroup = new QGroupBox(tr("Tooltip Settings"));
158  QFormLayout* tooltipLayout = new QFormLayout();
159  tooltipLayout->setSpacing(8);
160 
161  m_showTooltipsCheckBox = new QCheckBox(tr("Show tooltips on hover"));
162  m_showTooltipsCheckBox->setChecked(m_properties.showTooltips);
163  connect(m_showTooltipsCheckBox, &QCheckBox::toggled,
164  [this](bool checked) { m_properties.showTooltips = checked; });
165  tooltipLayout->addRow(m_showTooltipsCheckBox);
166 
167  m_maxTooltipAttributesSpin = new QSpinBox();
168  m_maxTooltipAttributesSpin->setRange(1, 50);
169  m_maxTooltipAttributesSpin->setValue(m_properties.maxTooltipAttributes);
170  connect(m_maxTooltipAttributesSpin,
171  QOverload<int>::of(&QSpinBox::valueChanged),
172  [this](int value) { m_properties.maxTooltipAttributes = value; });
173  tooltipLayout->addRow(tr("Max attributes:"), m_maxTooltipAttributesSpin);
174 
175  tooltipGroup->setLayout(tooltipLayout);
176  mainLayout->addWidget(tooltipGroup);
177 
178  // === Dialog Buttons ===
179  QHBoxLayout* buttonLayout = new QHBoxLayout();
180 
181  // Left side buttons
182  m_refreshButton = new QToolButton();
183  m_refreshButton->setIcon(style()->standardIcon(QStyle::SP_BrowserReload));
184  m_refreshButton->setToolTip(tr("Refresh from settings"));
185  buttonLayout->addWidget(m_refreshButton);
186 
187  m_saveButton = new QToolButton();
188  m_saveButton->setIcon(style()->standardIcon(QStyle::SP_DialogSaveButton));
189  m_saveButton->setToolTip(tr("Save as default"));
190  buttonLayout->addWidget(m_saveButton);
191 
192  buttonLayout->addStretch();
193 
194  // Right side buttons
195  m_applyButton = new QPushButton(tr("Apply"));
196  m_applyButton->setIcon(style()->standardIcon(QStyle::SP_DialogApplyButton));
197  connect(m_applyButton, &QPushButton::clicked, this,
198  &cvSelectionLabelPropertiesDialog::onApplyClicked);
199  buttonLayout->addWidget(m_applyButton);
200 
201  m_resetButton = new QPushButton(tr("Reset"));
202  m_resetButton->setIcon(style()->standardIcon(QStyle::SP_DialogResetButton));
203  connect(m_resetButton, &QPushButton::clicked, this,
204  &cvSelectionLabelPropertiesDialog::onResetClicked);
205  buttonLayout->addWidget(m_resetButton);
206 
207  m_cancelButton = new QPushButton(tr("Cancel"));
208  m_cancelButton->setIcon(
209  style()->standardIcon(QStyle::SP_DialogCancelButton));
210  connect(m_cancelButton, &QPushButton::clicked, this, &QDialog::reject);
211  buttonLayout->addWidget(m_cancelButton);
212 
213  m_okButton = new QPushButton(tr("OK"));
214  m_okButton->setIcon(style()->standardIcon(QStyle::SP_DialogOkButton));
215  m_okButton->setDefault(true);
216  connect(m_okButton, &QPushButton::clicked, [this]() {
217  onApplyClicked();
218  accept();
219  });
220  buttonLayout->addWidget(m_okButton);
221 
222  mainLayout->addLayout(buttonLayout);
223 
224  setLayout(mainLayout);
225 }
226 
227 //-----------------------------------------------------------------------------
229  const LabelProperties& props) {
230  m_properties = props;
231 
232  // Update UI
233  m_opacitySlider->setValue(static_cast<int>(props.opacity * 100));
234  m_opacitySpin->setValue(props.opacity);
235  m_pointSizeSpin->setValue(props.pointSize);
236  m_lineWidthSpin->setValue(props.lineWidth);
237 
238  // Cell font
239  if (m_cellFontWidget) {
240  m_cellFontWidget->setFontProperties(
241  labelPropertiesToFontProperties(props, true));
242  }
243  m_cellFormatEdit->setText(props.cellLabelFormat);
244 
245  // Point font
246  if (m_pointFontWidget) {
247  m_pointFontWidget->setFontProperties(
248  labelPropertiesToFontProperties(props, false));
249  }
250  m_pointFormatEdit->setText(props.pointLabelFormat);
251 
252  // Tooltip settings
253  m_showTooltipsCheckBox->setChecked(props.showTooltips);
254  m_maxTooltipAttributesSpin->setValue(props.maxTooltipAttributes);
255 }
256 
257 //-----------------------------------------------------------------------------
260  return m_properties;
261 }
262 
263 //-----------------------------------------------------------------------------
264 void cvSelectionLabelPropertiesDialog::updatePropertiesFromWidgets() {
265  // Cell font properties
266  if (m_cellFontWidget) {
267  fontPropertiesToLabelProperties(m_cellFontWidget->fontProperties(),
268  m_properties, true);
269  }
270 
271  // Point font properties
272  if (m_pointFontWidget) {
273  fontPropertiesToLabelProperties(m_pointFontWidget->fontProperties(),
274  m_properties, false);
275  }
276 }
277 
278 //-----------------------------------------------------------------------------
279 void cvSelectionLabelPropertiesDialog::onApplyClicked() {
280  updatePropertiesFromWidgets();
281  Q_EMIT propertiesApplied(m_properties);
282 }
283 
284 //-----------------------------------------------------------------------------
285 void cvSelectionLabelPropertiesDialog::onResetClicked() {
286  setProperties(m_defaultProperties);
287 }
288 
289 //-----------------------------------------------------------------------------
290 void cvSelectionLabelPropertiesDialog::onOpacitySliderChanged(int value) {
291  double opacity = value / 100.0;
292  m_opacitySpin->blockSignals(true);
293  m_opacitySpin->setValue(opacity);
294  m_opacitySpin->blockSignals(false);
295  m_properties.opacity = opacity;
296 }
297 
298 //-----------------------------------------------------------------------------
299 void cvSelectionLabelPropertiesDialog::onCellFontPropertiesChanged() {
300  if (m_cellFontWidget) {
301  fontPropertiesToLabelProperties(m_cellFontWidget->fontProperties(),
302  m_properties, true);
303  }
304 }
305 
306 //-----------------------------------------------------------------------------
307 void cvSelectionLabelPropertiesDialog::onPointFontPropertiesChanged() {
308  if (m_pointFontWidget) {
309  fontPropertiesToLabelProperties(m_pointFontWidget->fontProperties(),
310  m_properties, false);
311  }
312 }
313 
314 //-----------------------------------------------------------------------------
316 cvSelectionLabelPropertiesDialog::labelPropertiesToFontProperties(
317  const LabelProperties& props, bool isCellLabel) {
319  if (isCellLabel) {
320  fontProps.family = props.cellLabelFontFamily;
321  fontProps.size = props.cellLabelFontSize;
322  fontProps.color = props.cellLabelColor;
323  fontProps.opacity = props.cellLabelOpacity;
324  fontProps.bold = props.cellLabelBold;
325  fontProps.italic = props.cellLabelItalic;
326  fontProps.shadow = props.cellLabelShadow;
327  fontProps.horizontalJustification =
328  props.cellLabelHorizontalJustification;
329  fontProps.verticalJustification = props.cellLabelVerticalJustification;
330  } else {
331  fontProps.family = props.pointLabelFontFamily;
332  fontProps.size = props.pointLabelFontSize;
333  fontProps.color = props.pointLabelColor;
334  fontProps.opacity = props.pointLabelOpacity;
335  fontProps.bold = props.pointLabelBold;
336  fontProps.italic = props.pointLabelItalic;
337  fontProps.shadow = props.pointLabelShadow;
338  fontProps.horizontalJustification =
339  props.pointLabelHorizontalJustification;
340  fontProps.verticalJustification = props.pointLabelVerticalJustification;
341  }
342  return fontProps;
343 }
344 
345 //-----------------------------------------------------------------------------
346 void cvSelectionLabelPropertiesDialog::fontPropertiesToLabelProperties(
347  const ecvFontPropertyWidget::FontProperties& fontProps,
348  LabelProperties& props,
349  bool isCellLabel) {
350  if (isCellLabel) {
351  props.cellLabelFontFamily = fontProps.family;
352  props.cellLabelFontSize = fontProps.size;
353  props.cellLabelColor = fontProps.color;
354  props.cellLabelOpacity = fontProps.opacity;
355  props.cellLabelBold = fontProps.bold;
356  props.cellLabelItalic = fontProps.italic;
357  props.cellLabelShadow = fontProps.shadow;
358  props.cellLabelHorizontalJustification =
359  fontProps.horizontalJustification;
360  props.cellLabelVerticalJustification = fontProps.verticalJustification;
361  } else {
362  props.pointLabelFontFamily = fontProps.family;
363  props.pointLabelFontSize = fontProps.size;
364  props.pointLabelColor = fontProps.color;
365  props.pointLabelOpacity = fontProps.opacity;
366  props.pointLabelBold = fontProps.bold;
367  props.pointLabelItalic = fontProps.italic;
368  props.pointLabelShadow = fontProps.shadow;
369  props.pointLabelHorizontalJustification =
370  fontProps.horizontalJustification;
371  props.pointLabelVerticalJustification = fontProps.verticalJustification;
372  }
373 }
LabelProperties properties() const
Get the current properties.
void propertiesApplied(const LabelProperties &props)
Emitted when Apply is clicked.
cvSelectionLabelPropertiesDialog(QWidget *parent=nullptr, bool isInteractive=false)
void setProperties(const LabelProperties &props)
Set the current properties.
A reusable font property widget matching ParaView's font editor style.
FontProperties fontProperties() const
void setFontProperties(const FontProperties &props)
void fontPropertiesChanged()
Emitted when any font property changes.
Font property structure for convenience.