28 #include "hugin_config.h"
32 #include <wx/fileconf.h>
33 #include <wx/wfstream.h>
34 #include <wx/sstream.h>
35 #include <wx/propgrid/advprops.h>
48 int nP = panoProjectionFormatCount();
49 for (
int n = 0; n < nP; n++)
51 pano_projection_features proj;
52 if (panoProjectionFeaturesQuery(n, &proj))
82 "Condition1=ImageCount>1\n"
83 "Condition2=PanoVFOV<100\n"
84 "Condition3=PanoHFOV>=100\n"
87 "Projection=Cylindrical\n"
90 "Condition1=ImageCount>1\n"
91 "Condition2=PanoVFOV>=100\n"
94 "Projection=Equirectangular\n"
97 "Condition1=ImageCount>1\n"
98 "Condition2=PanoHFOV<100\n"
99 "Condition3=PanoVFOV<100\n"
102 "Projection=Rectilinear"
106 bool contains(
const wxArrayString& stringArray,
const wxString&
string,
bool caseInSensitive =
true)
110 for (
size_t i = 0; i < stringArray.GetCount(); ++i)
112 if (stringArray[i].CmpNoCase(
string) == 0)
120 for (
size_t i = 0; i < stringArray.GetCount(); ++i)
122 if (stringArray[i].Cmp(
string) == 0)
133 wxSizer* topSizer =
new wxBoxSizer(wxVERTICAL);
134 m_grid =
new wxPropertyGridManager(
this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxPG_AUTO_SORT | wxPG_DESCRIPTION | wxPG_SPLITTER_AUTO_CENTER);
138 topSizer->Add(
m_grid, wxSizerFlags(1).Expand().Border(wxALL, 10));
139 wxStdDialogButtonSizer* buttonSizer = CreateStdDialogButtonSizer(wxOK | wxCANCEL);
141 topSizer->Add(buttonSizer, wxSizerFlags().Expand().Border(wxALL, 6));
142 SetSizerAndFit(topSizer);
161 if (key.SubString(0, 8).CmpNoCase(
"Condition") == 0)
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."));
167 if (key.CmpNoCase(
"Projection") == 0)
178 p->SetHelpString(_(
"Select which projection should be selected."));
181 if (key.CmpNoCase(
"FOV") == 0)
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)."));
187 if (key.CmpNoCase(
"Canvas") == 0)
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)."));
193 if (key.CmpNoCase(
"Crop") == 0)
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%)."));
199 if (key.CmpNoCase(
"OutputExposure") == 0)
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."));
205 if (key.CmpNoCase(
"OutputType") == 0)
208 wxArrayString values = wxStringTokenize(value,
",");
209 for (
size_t i = 0; i < values.size(); ++i)
212 values[i].Trim(
true).Trim(
false);
214 wxPGProperty* p =
m_grid->AppendIn(section,
new wxMultiChoiceProperty(key, wxPG_LABEL,
OutputTypeArray, values));
215 p->SetHelpString(_(
"Select which output types should be activated."));
218 if (key.CmpNoCase(
"Blender") == 0)
220 wxPGProperty* p =
m_grid->AppendIn(section,
new wxEnumProperty(key, wxPG_LABEL,
BlenderArray));
229 p->SetHelpString(_(
"Select which blender should be used (can be enblend or internal)."));
232 if (key.CmpNoCase(
"BlenderArgs") == 0)
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."));
238 if (key.CmpNoCase(
"LDRFileType") == 0)
249 p->SetHelpString(_(
"Select fileformat for LDR output should be set."));
252 if (key.CmpNoCase(
"LDRCompression") == 0)
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)."));
258 if (key.CmpNoCase(
"HDRFileType") == 0)
269 p->SetHelpString(_(
"Select fileformat for HDR output should be set."));
272 if (key.CmpNoCase(
"HDRCompression") == 0)
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."));
279 wxPGProperty* newProperty =
m_grid->AppendIn(section,
new wxStringProperty(key, wxPG_LABEL, value));
285 wxInputStream* iniStream{
nullptr };
287 if (iniFilename.FileExists())
289 iniStream =
new wxFileInputStream(iniFilename.GetFullPath());
290 if (!iniStream->IsOk())
296 if (iniStream ==
nullptr)
298 iniStream =
new wxStringInputStream(
defaultIni);
301 wxFileConfig iniFile(*iniStream);
305 bool hasSections = iniFile.GetFirstGroup(section, index);
308 wxPGProperty* pgSection =
new wxPropertyCategory(section);
309 m_grid->Append(pgSection);
310 iniFile.SetPath(section);
313 bool hasKeys = iniFile.GetFirstEntry(key, indexKey);
316 AddKey(pgSection, key, iniFile.Read(key, wxEmptyString));
317 hasKeys = iniFile.GetNextEntry(key, indexKey);
319 iniFile.SetPath(
"/");
320 hasSections = iniFile.GetNextGroup(section, index);
328 wxFileConfig iniFile;
330 for (wxPropertyGridIterator it =
m_grid->GetIterator(wxPG_ITERATE_ALL); !it.AtEnd(); it++)
332 wxPGProperty* p = it.GetProperty();
339 iniFile.SetPath(
"/" + p->GetLabel());
343 wxVariant value = p->GetValue();
346 if (value.GetType().CmpNoCase(
"string") == 0)
348 const wxString s(value.GetString());
349 iniFile.Write(p->GetLabel(), s);
353 if (value.GetType().CmpNoCase(
"long") == 0)
355 const long i = value.GetLong();
356 wxPGChoices choices = p->GetChoices();
357 iniFile.Write(p->GetLabel(), choices[i].GetText());
361 if (value.GetType().CmpNoCase(
"arrstring") == 0)
363 wxArrayString values = value.GetArrayString();
365 for (
size_t i = 0; i < values.size(); ++i)
367 s << values[i] <<
",";
374 iniFile.Write(p->GetLabel(), s);
384 if (iniStream.IsOk())
386 success = iniFile.Save(iniStream);
390 wxMessageBox(wxString::Format(_(
"Could not save ini file \"%s\"."),
GetIniFileName().GetFullPath()), _(
"Error"), wxOK | wxICON_ERROR,
this);
404 wxMenuItem* item = menu.Append(wxID_ANY, _(
"Add condition"));
407 #define ADDKEYITEM(s) val=s;\
408 if (!contains(knownValues, val))\
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());\
429 menu.AppendSeparator();
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();
443 if (prop->IsCategory())
447 menuItem = contextMenu.Append(wxID_ANY, wxString::Format(_(
"Rename section %s"), prop->GetLabel().c_str()));
455 if (prop->IsCategory())
457 menuItem = contextMenu.Append(wxID_ANY, wxString::Format(_(
"Remove section %s"), prop->GetLabel().c_str()));
461 menuItem = contextMenu.Append(wxID_ANY, wxString::Format(_(
"Remove item %s"), prop->GetLabel().c_str()));
463 Bind(wxEVT_MENU, [
this, prop](wxCommandEvent&) {
m_grid->DeleteProperty(prop);
m_grid->RefreshGrid(); }, menuItem->GetId());
468 wxPGProperty* lastCategory{
nullptr };
469 for (wxPropertyGridIterator it =
m_grid->GetGrid()->GetIterator(wxPG_ITERATE_CATEGORIES); !it.AtEnd(); it++)
471 lastCategory = it.GetProperty();
479 PopupMenu(&contextMenu);
484 wxArrayString sections;
485 for (wxPropertyGridIterator it =
m_grid->GetIterator(wxPG_ITERATE_CATEGORIES); !it.AtEnd(); it++)
487 sections.Add(it.GetProperty()->GetLabel());
494 wxArrayString values;
496 for (wxPropertyGridIterator it =
m_grid->GetIterator(wxPG_ITERATE_DEFAULT, prop); !it.AtEnd() && counter < prop->GetChildCount(); it++, ++counter)
498 values.Add(it.GetProperty()->GetLabel());
508 wxTextEntryDialog dialog(
this, _(
"Name of new section:"), _(
"Create new section"));
509 if (dialog.ShowModal() == wxID_OK)
511 const wxString newSection = dialog.GetValue();
513 if (
contains(knownSections, newSection))
515 wxMessageBox(wxString::Format(_(
"Section \"%s\" is already defined.\nPlease use another name."), newSection.c_str()), _(
"Duplicate value."), wxOK | wxICON_ERROR);
520 wxPGProperty* pgSection =
new wxPropertyCategory(newSection);
529 wxPGProperty* currentSection =
m_grid->GetSelection();
530 if (!currentSection->IsCategory())
536 knownSections.Remove(currentSection->GetLabel());
538 wxTextEntryDialog dialog(
this, _(
"New name of section:"), _(
"Create new section"), currentSection->GetLabel());
539 if (dialog.ShowModal() == wxID_OK)
541 const wxString newSection = dialog.GetValue();
543 if (
contains(knownSections, newSection))
545 wxMessageBox(wxString::Format(_(
"Section \"%s\" is already defined.\nPlease use another name."), newSection.c_str()), _(
"Duplicate value."), wxOK | wxICON_ERROR);
550 currentSection->SetLabel(newSection);
561 for (
size_t i = 0; i < children.GetCount(); ++i)
563 if (children[i].SubString(0, 8).CmpNoCase(
"Condition") == 0)
566 if (children[i].Mid(9).ToLong(&x))
568 index = std::max<long>(index, x);
573 const wxString val = wxString::Format(
"Condition%d", index);
void ReadIni()
read the ini file and populate the control
void OnAddSection(wxCommandEvent &e)
add a new section
Definition of dialog for editing user-defined output ini file.
wxArrayString GetSections() const
return wxArrayString with all sections
wxPGProperty * m_currentSection
EditOutputIniDialog(wxWindow *parent)
Constructor, constructs dialog; restore last uses settings, size and position.
wxPropertyGridManager * m_grid
static wxArrayString OutputTypeArray
static wxArrayString HDRFileTypeArray
static wxArrayString LDRFileTypeArray
void BuildAddContextMenu(wxMenu &menu, wxPGProperty *category, const bool addSeparator)
function to build context menu with all missing entries
wxArrayString GetChildren(wxPGProperty *prop) const
return wxArrayString with all sub-entries of given wxPGProperty
wxFileName GetIniFileName()
return the filename of the default ini file
void OnContextMenu(wxContextMenuEvent &e)
right click handler, show popup menu
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 ...
void StoreFramePosition(wxTopLevelWindow *frame, const wxString &basename)
Store window size and position in configfile/registry.
void OnOk(wxCommandEvent &e)
save ini and close dialog
static wxArrayString ProjectionArray
void OnAddCondition(wxCommandEvent &e)
adds a new condition to list
void AddKey(wxPGProperty *section, const wxString &key, const wxString &value)
add key with value to wxPropertyGrid, generate if necessary all sub properties
include file for the hugin project
void OnRenameSection(wxCommandEvent &e)
renames a new section
~EditOutputIniDialog()
destructor, saves size and position
std::string GetUserAppDataDir()
returns the directory for user specific Hugin settings, e.g.
static const wxString defaultIni
default ini, if no one exists load this one
void WriteIni()
write the ini to disc
static wxArrayString BlenderArray
void RestoreFramePosition(wxTopLevelWindow *frame, const wxString &basename)
Restore window size and position from configfile/registry.