Hugin trunk 0.1
Loading...
Searching...
No Matches
EditOutputIniDialog.cpp
Go to the documentation of this file.
1// -*- c-basic-offset: 4 -*-
2
11/* This is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public
13 * License as published by the Free Software Foundation; either
14 * version 2 of the License, or (at your option) any later version.
15 *
16 * This software is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public
22 * License along with this software. If not, see
23 * <http://www.gnu.org/licenses/>.
24 *
25 */
26
27#include "EditOutputIniDialog.h"
28#include "hugin_config.h"
29#include "panoinc_WX.h"
30#include "hugin/huginApp.h"
31#include "base_wx/wxutils.h"
32#include <wx/fileconf.h>
33#include <wx/wfstream.h>
34#include <wx/sstream.h>
35#include <wx/propgrid/advprops.h>
36
42
44{
45 BlenderArray.Add("Enblend");
46 BlenderArray.Add("Internal");
47
49 for (int n = 0; n < nP; n++)
50 {
53 {
54 ProjectionArray.Add(wxString(proj.name, wxConvLocal));
55 };
56 };
57
58 OutputTypeArray.Add("Normal");
59 OutputTypeArray.Add("StacksFusedBlended");
60 OutputTypeArray.Add("ExposureLayersFused");
61 OutputTypeArray.Add("HDR");
62 OutputTypeArray.Add("Remap");
63 OutputTypeArray.Add("RemapOrig");
64 OutputTypeArray.Add("HDRRemap");
65 OutputTypeArray.Add("FusedStacks");
66 OutputTypeArray.Add("HDRStacks");
67 OutputTypeArray.Add("ExposureLayers");
68
69 LDRFileTypeArray.Add("jpg");
70 LDRFileTypeArray.Add("tif");
71 LDRFileTypeArray.Add("png");
72
73 HDRFileTypeArray.Add("exr");
74 HDRFileTypeArray.Add("tif");
75}
76
78static const wxString defaultIni
79{
80 "[Cylindrical]\n"
81 "Canvas=70%\n"
82 "Condition1=ImageCount>1\n"
83 "Condition2=PanoVFOV<100\n"
84 "Condition3=PanoHFOV>=100\n"
85 "Crop=auto\n"
86 "FOV=auto\n"
87 "Projection=Cylindrical\n"
88 "[Equirectangular]\n"
89 "Canvas=70%\n"
90 "Condition1=ImageCount>1\n"
91 "Condition2=PanoVFOV>=100\n"
92 "Crop=auto\n"
93 "FOV=auto\n"
94 "Projection=Equirectangular\n"
95 "[Rectilinear]\n"
96 "Canvas=70%\n"
97 "Condition1=ImageCount>1\n"
98 "Condition2=PanoHFOV<100\n"
99 "Condition3=PanoVFOV<100\n"
100 "Crop=auto\n"
101 "FOV=auto\n"
102 "Projection=Rectilinear"
103};
104
106bool contains(const wxArrayString& stringArray, const wxString& string, bool caseInSensitive = true)
107{
108 if (caseInSensitive)
109 {
110 for (size_t i = 0; i < stringArray.GetCount(); ++i)
111 {
112 if (stringArray[i].CmpNoCase(string) == 0)
113 {
114 return true;
115 };
116 };
117 }
118 else
119 {
120 for (size_t i = 0; i < stringArray.GetCount(); ++i)
121 {
122 if (stringArray[i].Cmp(string) == 0)
123 {
124 return true;
125 };
126 };
127 };
128 return false;
129}
130
132{
135 // bind context menu only to the grid
136 // when binding to whole control it would also be invoked above the text area below
138 topSizer->Add(m_grid, wxSizerFlags(1).Expand().Border(wxALL, 10));
140 buttonSizer->GetAffirmativeButton()->Bind(wxEVT_BUTTON, &EditOutputIniDialog::OnOk, this);
141 topSizer->Add(buttonSizer, wxSizerFlags().Expand().Border(wxALL, 6));
143 InitArrays();
144 ReadIni();
145 hugin_utils::RestoreFramePosition(this, "EditOutputIniDialog");
146}
147
152
153void EditOutputIniDialog::OnOk(wxCommandEvent& e)
154{
155 WriteIni();
156 EndModal(wxOK);
157}
158
160{
161 if (key.SubString(0, 8).CmpNoCase("Condition") == 0)
162 {
163 wxPGProperty* p = m_grid->AppendIn(section, new wxStringProperty(key, wxPG_LABEL, value));
164 p->SetHelpString(_("Define which condition should be fulfilled to apply this setting.\nThe variables CameraModel, CameraMaker, Lens, HFOV, LensType, Focallength, Focallength35mm, Filename, Path, ImageCount, PanoHFOV and PanoVFOV can be used.\nFor comparison you can use ==, !=, =~ and !~ for strings and ==, !=, <, <=, > and >= for numbers."));
165 return;
166 };
167 if (key.CmpNoCase("Projection") == 0)
168 {
170 if (value.IsEmpty())
171 {
172 p->SetValue(ProjectionArray[0]);
173 }
174 else
175 {
176 p->SetValue(value);
177 };
178 p->SetHelpString(_("Select which projection should be selected."));
179 return;
180 };
181 if (key.CmpNoCase("FOV") == 0)
182 {
183 wxPGProperty* p = m_grid->AppendIn(section, new wxStringProperty(key, wxPG_LABEL, value));
184 p->SetHelpString(_("Select which field of view should be set.\nCan be Auto for automatic detection, or a fixed horizontal field of view (e.g. 120) or horizontal x vertical field of view (e.g. 140x70)."));
185 return;
186 };
187 if (key.CmpNoCase("Canvas") == 0)
188 {
189 wxPGProperty* p = m_grid->AppendIn(section, new wxStringProperty(key, wxPG_LABEL, value));
190 p->SetHelpString(_("Select to which size the canvas should be set.\nFor automatic detection use Auto or a scale factor in percent (e.g. 70%).\nOr give a width x height (e.g. 8000x4000)."));
191 return;
192 };
193 if (key.CmpNoCase("Crop") == 0)
194 {
195 wxPGProperty* p = m_grid->AppendIn(section, new wxStringProperty(key, wxPG_LABEL, value));
196 p->SetHelpString(_("Select which crop should be used.\nFor automatic detection use Auto, AutoOutside or AutoHDR.\nOr give 4 numbers as left, right, top and bottom. You can use absolute pixel values (e.g. 100,7900,1000,3900) or relative values by appending a percentage sign (e.g. 10,90,10,90%)."));
197 return;
198 };
199 if (key.CmpNoCase("OutputExposure") == 0)
200 {
201 wxPGProperty* p = m_grid->AppendIn(section, new wxStringProperty(key, wxPG_LABEL, value));
202 p->SetHelpString(_("Select which output exposure value should be used.\nFor automatic detection use Auto or give a fixed exposure value."));
203 return;
204 };
205 if (key.CmpNoCase("OutputType") == 0)
206 {
207 // split string into individual items
208 wxArrayString values = wxStringTokenize(value, ",");
209 for (size_t i = 0; i < values.size(); ++i)
210 {
211 // remove whitespace from begin and end
212 values[i].Trim(true).Trim(false);
213 }
215 p->SetHelpString(_("Select which output types should be activated."));
216 return;
217 };
218 if (key.CmpNoCase("Blender") == 0)
219 {
221 if (value.IsEmpty())
222 {
223 p->SetValue(BlenderArray[0]);
224 }
225 else
226 {
227 p->SetValue(value);
228 };
229 p->SetHelpString(_("Select which blender should be used (can be enblend or internal)."));
230 return;
231 };
232 if (key.CmpNoCase("BlenderArgs") == 0)
233 {
234 wxPGProperty* p = m_grid->AppendIn(section, new wxStringProperty(key, wxPG_LABEL, value));
235 p->SetHelpString(_("Select which arguments should be passed to the blender."));
236 return;
237 };
238 if (key.CmpNoCase("LDRFileType") == 0)
239 {
241 if (value.IsEmpty())
242 {
243 p->SetValue(LDRFileTypeArray[0]);
244 }
245 else
246 {
247 p->SetValue(value);
248 };
249 p->SetHelpString(_("Select fileformat for LDR output should be set."));
250 return;
251 };
252 if (key.CmpNoCase("LDRCompression") == 0)
253 {
254 wxPGProperty* p = m_grid->AppendIn(section, new wxStringProperty(key, wxPG_LABEL, value));
255 p->SetHelpString(_("Select which compressions should be used for LDR images.\nFor TIFF images NONE, PACKBITS, LZW and DEFLATE are supported.\nFor JPEG image give a number as quality (0-100)."));
256 return;
257 };
258 if (key.CmpNoCase("HDRFileType") == 0)
259 {
261 if (value.IsEmpty())
262 {
263 p->SetValue(HDRFileTypeArray[0]);
264 }
265 else
266 {
267 p->SetValue(value);
268 };
269 p->SetHelpString(_("Select fileformat for HDR output should be set."));
270 return;
271 };
272 if (key.CmpNoCase("HDRCompression") == 0)
273 {
274 wxPGProperty* p = m_grid->AppendIn(section, new wxStringProperty(key, wxPG_LABEL, value));
275 p->SetHelpString(_("Select which compressions should be used for HDR images.\nFor TIFF images NONE, PACKBITS, LZW and DEFLATE are supported."));
276 return;
277 }
278 // fall-through, should not be called
280};
281
283{
285 wxInputStream* iniStream{ nullptr };
286
287 if (iniFilename.FileExists())
288 {
289 iniStream = new wxFileInputStream(iniFilename.GetFullPath());
290 if (!iniStream->IsOk())
291 {
292 delete iniStream;
293 iniStream = nullptr;
294 }
295 };
296 if (iniStream == nullptr)
297 {
299 };
300 // now read from stream
302 m_grid->Freeze();
304 long index;
305 bool hasSections = iniFile.GetFirstGroup(section, index);
306 while (hasSections)
307 {
309 m_grid->Append(pgSection);
310 iniFile.SetPath(section);
312 long indexKey;
313 bool hasKeys = iniFile.GetFirstEntry(key, indexKey);
314 while (hasKeys)
315 {
317 hasKeys = iniFile.GetNextEntry(key, indexKey);
318 };
319 iniFile.SetPath("/");
320 hasSections = iniFile.GetNextGroup(section, index);
321 };
322 m_grid->Thaw();
323 delete iniStream;
324};
325
327{
329 // iterate all entries
330 for (wxPropertyGridIterator it = m_grid->GetIterator(wxPG_ITERATE_ALL); !it.AtEnd(); it++)
331 {
332 wxPGProperty* p = it.GetProperty();
333 if (!p)
334 {
335 continue;
336 };
337 if (p->IsCategory())
338 {
339 iniFile.SetPath("/" + p->GetLabel());
340 }
341 else
342 {
343 wxVariant value = p->GetValue();
344 if (!value.IsNull())
345 {
346 if (value.GetType().CmpNoCase("string") == 0)
347 {
348 const wxString s(value.GetString());
349 iniFile.Write(p->GetLabel(), s);
350 }
351 else
352 {
353 if (value.GetType().CmpNoCase("long") == 0)
354 {
355 const long i = value.GetLong();
356 wxPGChoices choices = p->GetChoices();
357 iniFile.Write(p->GetLabel(), choices[i].GetText());
358 }
359 else
360 {
361 if (value.GetType().CmpNoCase("arrstring") == 0)
362 {
363 wxArrayString values = value.GetArrayString();
364 wxString s;
365 for (size_t i = 0; i < values.size(); ++i)
366 {
367 s << values[i] << ",";
368 };
369 if (!s.IsEmpty())
370 {
371 // remove the last separator
372 s.RemoveLast();
373 };
374 iniFile.Write(p->GetLabel(), s);
375 };
376 };
377 };
378 };
379 };
380 };
381 // finally write to disc
383 bool success = true;
384 if (iniStream.IsOk())
385 {
386 success = iniFile.Save(iniStream);
387 };
388 if (!success)
389 {
390 hugin_utils::HuginMessageBox(wxString::Format(_("Could not save ini file \"%s\"."), GetIniFileName().GetFullPath()), _("Hugin"), wxOK | wxICON_ERROR, this);
391 };
392}
393
398
400{
401 // first get list of known values
404 wxMenuItem* item = menu.Append(wxID_ANY, _("Add condition"));
406 wxString val;
407#define ADDKEYITEM(s) val=s;\
408 if (!contains(knownValues, val))\
409 {\
410 item = menu.Append(wxID_ANY, wxString::Format(_("Add %s"), val.c_str()));\
411 Bind(wxEVT_MENU, [this, category, val](wxCommandEvent&) { AddKey(category, val, wxEmptyString); m_grid->RefreshGrid(); }, item->GetId());\
412 };
413 ADDKEYITEM("Projection")
414 ADDKEYITEM("FOV")
415 ADDKEYITEM("Canvas")
416 ADDKEYITEM("Crop")
417 ADDKEYITEM("OutputExposure")
418 ADDKEYITEM("OutputType")
419 ADDKEYITEM("Blender")
420 ADDKEYITEM("BlenderArgs")
421 ADDKEYITEM("LDRFileType")
422 ADDKEYITEM("LDRCompression")
423 ADDKEYITEM("HDRFileType")
424 ADDKEYITEM("HDRCompression")
425#undef ADDKEYITEM
426 // and finally a separator
427 if (addSeparator)
428 {
429 menu.AppendSeparator();
430 };
431}
432
434{
435 wxPropertyGridHitTestResult hitTest = m_grid->GetGrid()->HitTest(m_grid->GetGrid()->CalcScrolledPosition(m_grid->ScreenToClient(e.GetPosition())));
437 wxMenuItem* menuItem = contextMenu.Append(wxID_ANY, _("Create new section"));
439 contextMenu.AppendSeparator();
440 wxPGProperty* prop = hitTest.GetProperty();
441 if (prop)
442 {
443 if (prop->IsCategory())
444 {
446 // rename section menu item
447 menuItem = contextMenu.Append(wxID_ANY, wxString::Format(_("Rename section %s"), prop->GetLabel().c_str()));
449 }
450 else
451 {
452 BuildAddContextMenu(contextMenu, prop->GetParent(), true);
453 };
454 // remove section/item menu item
455 if (prop->IsCategory())
456 {
457 menuItem = contextMenu.Append(wxID_ANY, wxString::Format(_("Remove section %s"), prop->GetLabel().c_str()));
458 }
459 else
460 {
461 menuItem = contextMenu.Append(wxID_ANY, wxString::Format(_("Remove item %s"), prop->GetLabel().c_str()));
462 };
463 Bind(wxEVT_MENU, [this, prop](wxCommandEvent&) { m_grid->DeleteProperty(prop); m_grid->RefreshGrid(); }, menuItem->GetId());
464 }
465 else
466 {
467 // user clicked below last entry, take last category as target
468 wxPGProperty* lastCategory{ nullptr };
469 for (wxPropertyGridIterator it = m_grid->GetGrid()->GetIterator(wxPG_ITERATE_CATEGORIES); !it.AtEnd(); it++)
470 {
471 lastCategory = it.GetProperty();
472 }
473 if(lastCategory)
474 {
476 };
477 };
478 // show popup menu
480}
481
483{
485 for (wxPropertyGridIterator it = m_grid->GetIterator(wxPG_ITERATE_CATEGORIES); !it.AtEnd(); it++)
486 {
487 sections.Add(it.GetProperty()->GetLabel());
488 };
489 return sections;
490}
491
493{
494 wxArrayString values;
495 size_t counter = 0;
496 for (wxPropertyGridIterator it = m_grid->GetIterator(wxPG_ITERATE_DEFAULT, prop); !it.AtEnd() && counter < prop->GetChildCount(); it++, ++counter)
497 {
498 values.Add(it.GetProperty()->GetLabel());
499 };
500 return values;
501}
502
504{
505 // get list of known sections
507 // ask user for new name
508 wxTextEntryDialog dialog(this, _("Name of new section:"), _("Create new section"));
509 if (dialog.ShowModal() == wxID_OK)
510 {
511 const wxString newSection = dialog.GetValue();
512 // check if new name is unique
514 {
515 hugin_utils::HuginMessageBox(wxString::Format(_("Section \"%s\" is already defined.\nPlease use another name."), newSection), _("Hugin"), wxOK | wxICON_ERROR, this);
516 }
517 else
518 {
519 // all ok, finally add new section to grid
521 m_grid->AppendIn(m_grid->GetPageRoot(0), pgSection);
522 m_grid->RefreshGrid();
523 };
524 };
525}
526
528{
529 wxPGProperty* currentSection = m_grid->GetSelection();
530 if (!currentSection->IsCategory())
531 {
532 return;
533 };
534 // get list of known sections, ignore current selected section
536 knownSections.Remove(currentSection->GetLabel());
537 // ask user for new name
538 wxTextEntryDialog dialog(this, _("New name of section:"), _("Create new section"), currentSection->GetLabel());
539 if (dialog.ShowModal() == wxID_OK)
540 {
541 const wxString newSection = dialog.GetValue();
542 // check if new name is unique
544 {
545 hugin_utils::HuginMessageBox(wxString::Format(_("Section \"%s\" is already defined.\nPlease use another name."), newSection), _("Hugin"), wxOK | wxICON_ERROR, this);
546 }
547 else
548 {
549 // all ok, finally add new section to grid
550 currentSection->SetLabel(newSection);
551 m_grid->RefreshGrid();
552 };
553 };
554}
555
557{
559 // get currently highest used number on condition
560 size_t index = 0;
561 for (size_t i = 0; i < children.GetCount(); ++i)
562 {
563 if (children[i].SubString(0, 8).CmpNoCase("Condition") == 0)
564 {
565 long x;
566 if (children[i].Mid(9).ToLong(&x))
567 {
568 index = std::max<long>(index, x);
569 };
570 };
571 };
572 ++index;
573 const wxString val = wxString::Format("Condition%d", index);
575 m_grid->RefreshGrid();
576}
static wxArrayString ProjectionArray
static wxArrayString BlenderArray
bool contains(const wxArrayString &stringArray, const wxString &string, bool caseInSensitive=true)
check if given string is in wxArrayString, do comparison case insentive or case sensitive
#define ADDKEYITEM(s)
static wxArrayString OutputTypeArray
static const wxString defaultIni
default ini, if no one exists load this one
static wxArrayString HDRFileTypeArray
static wxArrayString LDRFileTypeArray
void InitArrays()
Definition of dialog for editing user-defined output ini file.
wxPGProperty * m_currentSection
void AddKey(wxPGProperty *section, const wxString &key, const wxString &value)
add key with value to wxPropertyGrid, generate if necessary all sub properties
wxArrayString GetChildren(wxPGProperty *prop) const
return wxArrayString with all sub-entries of given wxPGProperty
void BuildAddContextMenu(wxMenu &menu, wxPGProperty *category, const bool addSeparator)
function to build context menu with all missing entries
EditOutputIniDialog(wxWindow *parent)
Constructor, constructs dialog; restore last uses settings, size and position.
void OnRenameSection(wxCommandEvent &e)
renames a new section
void OnOk(wxCommandEvent &e)
save ini and close dialog
void OnContextMenu(wxContextMenuEvent &e)
right click handler, show popup menu
wxArrayString GetSections() const
return wxArrayString with all sections
void OnAddSection(wxCommandEvent &e)
add a new section
wxPropertyGridManager * m_grid
void ReadIni()
read the ini file and populate the control
~EditOutputIniDialog()
destructor, saves size and position
void OnAddCondition(wxCommandEvent &e)
adds a new condition to list
wxFileName GetIniFileName()
return the filename of the default ini file
void WriteIni()
write the ini to disc
int HuginMessageBox(const wxString &message, const wxString &caption, int style, wxWindow *parent)
Definition wxutils.cpp:176
std::string GetUserAppDataDir()
returns the directory for user specific Hugin settings, e.g.
Definition utils.cpp:497
void StoreFramePosition(wxTopLevelWindow *frame, const wxString &basename, const bool ignoreMaximize)
Definition wxutils.cpp:106
void RestoreFramePosition(wxTopLevelWindow *frame, const wxString &basename, const bool ignoreMaximize)
Definition wxutils.cpp:67
include file for the hugin project
std::vector< deghosting::BImagePtr > threshold(const std::vector< deghosting::FImagePtr > &inputImages, const double threshold, const uint16_t flags)
Threshold function used for creating alpha masks for images.
Definition threshold.h:41