1 // Copyright (c) 2018, ETH Zurich and UNC Chapel Hill.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are met:
6 //
7 //     * Redistributions of source code must retain the above copyright
8 //       notice, this list of conditions and the following disclaimer.
9 //
10 //     * Redistributions in binary form must reproduce the above copyright
11 //       notice, this list of conditions and the following disclaimer in the
12 //       documentation and/or other materials provided with the distribution.
13 //
14 //     * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
15 //       its contributors may be used to endorse or promote products derived
16 //       from this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
22 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 // POSSIBILITY OF SUCH DAMAGE.
29 //
30 // Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
31 
32 #include "ui/options_widget.h"
33 
34 namespace colmap {
35 
OptionsWidget(QWidget * parent)36 OptionsWidget::OptionsWidget(QWidget* parent) : QWidget(parent) {
37   setWindowFlags(Qt::Dialog);
38   setWindowModality(Qt::ApplicationModal);
39 
40   QFont font;
41   font.setPointSize(10);
42   setFont(font);
43 
44   grid_layout_ = new QGridLayout(this);
45   grid_layout_->setVerticalSpacing(3);
46   grid_layout_->setAlignment(Qt::AlignTop);
47   setLayout(grid_layout_);
48 }
49 
AddOptionRow(const std::string & label_text,QWidget * widget,void * option)50 void OptionsWidget::AddOptionRow(const std::string& label_text, QWidget* widget,
51                                  void* option) {
52   QLabel* label = new QLabel(tr(label_text.c_str()), this);
53   label->setFont(font());
54   label->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
55   grid_layout_->addWidget(label, grid_layout_->rowCount(), 0);
56 
57   widget->setFont(font());
58   grid_layout_->addWidget(widget, grid_layout_->rowCount() - 1, 1);
59 
60   option_rows_.emplace(option, std::make_pair(label, widget));
61   widget_rows_.emplace(widget, std::make_pair(label, widget));
62 }
63 
AddWidgetRow(const std::string & label_text,QWidget * widget)64 void OptionsWidget::AddWidgetRow(const std::string& label_text,
65                                  QWidget* widget) {
66   QLabel* label = new QLabel(tr(label_text.c_str()), this);
67   label->setFont(font());
68   label->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
69   grid_layout_->addWidget(label, grid_layout_->rowCount(), 0);
70 
71   widget->setFont(font());
72   grid_layout_->addWidget(widget, grid_layout_->rowCount() - 1, 1);
73 
74   widget_rows_.emplace(widget, std::make_pair(label, widget));
75 }
76 
AddLayoutRow(const std::string & label_text,QLayout * layout)77 void OptionsWidget::AddLayoutRow(const std::string& label_text,
78                                  QLayout* layout) {
79   QLabel* label = new QLabel(tr(label_text.c_str()), this);
80   label->setFont(font());
81   label->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
82   grid_layout_->addWidget(label, grid_layout_->rowCount(), 0);
83 
84   QWidget* layout_widget = new QWidget(this);
85   layout_widget->setLayout(layout);
86   layout->setContentsMargins(0, 0, 0, 0);
87 
88   grid_layout_->addWidget(layout_widget, grid_layout_->rowCount() - 1, 1);
89 
90   layout_rows_.emplace(layout, std::make_pair(label, layout_widget));
91 }
92 
AddOptionInt(int * option,const std::string & label_text,const int min,const int max)93 QSpinBox* OptionsWidget::AddOptionInt(int* option,
94                                       const std::string& label_text,
95                                       const int min, const int max) {
96   QSpinBox* spinbox = new QSpinBox(this);
97   spinbox->setMinimum(min);
98   spinbox->setMaximum(max);
99 
100   AddOptionRow(label_text, spinbox, option);
101 
102   options_int_.emplace_back(spinbox, option);
103 
104   return spinbox;
105 }
106 
AddOptionDouble(double * option,const std::string & label_text,const double min,const double max,const double step,const int decimals)107 QDoubleSpinBox* OptionsWidget::AddOptionDouble(
108     double* option, const std::string& label_text, const double min,
109     const double max, const double step, const int decimals) {
110   QDoubleSpinBox* spinbox = new QDoubleSpinBox(this);
111   spinbox->setMinimum(min);
112   spinbox->setMaximum(max);
113   spinbox->setSingleStep(step);
114   spinbox->setDecimals(decimals);
115 
116   AddOptionRow(label_text, spinbox, option);
117 
118   options_double_.emplace_back(spinbox, option);
119 
120   return spinbox;
121 }
122 
AddOptionDoubleLog(double * option,const std::string & label_text,const double min,const double max,const double step,const int decimals)123 QDoubleSpinBox* OptionsWidget::AddOptionDoubleLog(
124     double* option, const std::string& label_text, const double min,
125     const double max, const double step, const int decimals) {
126   QDoubleSpinBox* spinbox = new QDoubleSpinBox(this);
127   spinbox->setMinimum(min);
128   spinbox->setMaximum(max);
129   spinbox->setSingleStep(step);
130   spinbox->setDecimals(decimals);
131 
132   AddOptionRow(label_text, spinbox, option);
133 
134   options_double_log_.emplace_back(spinbox, option);
135 
136   return spinbox;
137 }
138 
AddOptionBool(bool * option,const std::string & label_text)139 QCheckBox* OptionsWidget::AddOptionBool(bool* option,
140                                         const std::string& label_text) {
141   QCheckBox* checkbox = new QCheckBox(this);
142 
143   AddOptionRow(label_text, checkbox, option);
144 
145   options_bool_.emplace_back(checkbox, option);
146 
147   return checkbox;
148 }
149 
AddOptionText(std::string * option,const std::string & label_text)150 QLineEdit* OptionsWidget::AddOptionText(std::string* option,
151                                         const std::string& label_text) {
152   QLineEdit* line_edit = new QLineEdit(this);
153 
154   AddOptionRow(label_text, line_edit, option);
155 
156   options_text_.emplace_back(line_edit, option);
157 
158   return line_edit;
159 }
160 
AddOptionFilePath(std::string * option,const std::string & label_text)161 QLineEdit* OptionsWidget::AddOptionFilePath(std::string* option,
162                                             const std::string& label_text) {
163   QLineEdit* line_edit = new QLineEdit(this);
164 
165   AddOptionRow(label_text, line_edit, option);
166 
167   auto SelectPathFunc = [this, line_edit]() {
168     line_edit->setText(QFileDialog::getOpenFileName(this, tr("Select file")));
169   };
170 
171   QPushButton* select_button = new QPushButton(tr("Select file"), this);
172   select_button->setFont(font());
173   connect(select_button, &QPushButton::released, this, SelectPathFunc);
174   grid_layout_->addWidget(select_button, grid_layout_->rowCount(), 1);
175 
176   options_path_.emplace_back(line_edit, option);
177 
178   return line_edit;
179 }
180 
AddOptionDirPath(std::string * option,const std::string & label_text)181 QLineEdit* OptionsWidget::AddOptionDirPath(std::string* option,
182                                            const std::string& label_text) {
183   QLineEdit* line_edit = new QLineEdit(this);
184 
185   AddOptionRow(label_text, line_edit, option);
186 
187   auto SelectPathFunc = [this, line_edit]() {
188     line_edit->setText(
189         QFileDialog::getExistingDirectory(this, tr("Select folder")));
190   };
191 
192   QPushButton* select_button = new QPushButton(tr("Select folder"), this);
193   select_button->setFont(font());
194   connect(select_button, &QPushButton::released, this, SelectPathFunc);
195   grid_layout_->addWidget(select_button, grid_layout_->rowCount(), 1);
196 
197   options_path_.emplace_back(line_edit, option);
198 
199   return line_edit;
200 }
201 
AddSpacer()202 void OptionsWidget::AddSpacer() {
203   QLabel* label = new QLabel("", this);
204   label->setFont(font());
205   grid_layout_->addWidget(label, grid_layout_->rowCount(), 0, 2, 1);
206 }
207 
AddSection(const std::string & title)208 void OptionsWidget::AddSection(const std::string& title) {
209   QLabel* label = new QLabel(tr(title.c_str()), this);
210   label->setFont(font());
211   label->setContentsMargins(0, 0, 0, 5);
212   grid_layout_->addWidget(label, grid_layout_->rowCount(), 0, 1, 2,
213                           Qt::AlignHCenter);
214 }
215 
ReadOptions()216 void OptionsWidget::ReadOptions() {
217   for (auto& option : options_int_) {
218     option.first->setValue(*option.second);
219   }
220 
221   for (auto& option : options_double_) {
222     option.first->setValue(*option.second);
223   }
224 
225   for (auto& option : options_double_log_) {
226     option.first->setValue(std::log10(*option.second));
227   }
228 
229   for (auto& option : options_bool_) {
230     option.first->setChecked(*option.second);
231   }
232 
233   for (auto& option : options_text_) {
234     option.first->setText(QString::fromStdString(*option.second));
235   }
236 
237   for (auto& option : options_path_) {
238     option.first->setText(QString::fromStdString(*option.second));
239   }
240 }
241 
WriteOptions()242 void OptionsWidget::WriteOptions() {
243   for (auto& option : options_int_) {
244     *option.second = option.first->value();
245   }
246 
247   for (auto& option : options_double_) {
248     *option.second = option.first->value();
249   }
250 
251   for (auto& option : options_double_log_) {
252     *option.second = std::pow(10, option.first->value());
253   }
254 
255   for (auto& option : options_bool_) {
256     *option.second = option.first->isChecked();
257   }
258 
259   for (auto& option : options_text_) {
260     *option.second = option.first->text().toUtf8().constData();
261   }
262 
263   for (auto& option : options_path_) {
264     *option.second = option.first->text().toUtf8().constData();
265   }
266 }
267 
showEvent(QShowEvent * event)268 void OptionsWidget::showEvent(QShowEvent* event) { ReadOptions(); }
269 
closeEvent(QCloseEvent * event)270 void OptionsWidget::closeEvent(QCloseEvent* event) { WriteOptions(); }
271 
hideEvent(QHideEvent * event)272 void OptionsWidget::hideEvent(QHideEvent* event) { WriteOptions(); }
273 
ShowOption(void * option)274 void OptionsWidget::ShowOption(void* option) {
275   auto& option_row = option_rows_.at(option);
276   option_row.first->show();
277   option_row.second->show();
278 }
279 
HideOption(void * option)280 void OptionsWidget::HideOption(void* option) {
281   auto& option_row = option_rows_.at(option);
282   option_row.first->hide();
283   option_row.second->hide();
284 }
285 
ShowWidget(QWidget * widget)286 void OptionsWidget::ShowWidget(QWidget* widget) {
287   auto& widget_row = widget_rows_.at(widget);
288   widget_row.first->show();
289   widget_row.second->show();
290 }
291 
HideWidget(QWidget * widget)292 void OptionsWidget::HideWidget(QWidget* widget) {
293   auto& widget_row = widget_rows_.at(widget);
294   widget_row.first->hide();
295   widget_row.second->hide();
296 }
297 
ShowLayout(QLayout * layout)298 void OptionsWidget::ShowLayout(QLayout* layout) {
299   auto& layout_row = layout_rows_.at(layout);
300   layout_row.first->show();
301   layout_row.second->show();
302 }
303 
HideLayout(QLayout * layout)304 void OptionsWidget::HideLayout(QLayout* layout) {
305   auto& layout_row = layout_rows_.at(layout);
306   layout_row.first->hide();
307   layout_row.second->hide();
308 }
309 
310 }  // namespace colmap
311