28 #include "hugin_config.h"
31 #include <wx/fileconf.h>
32 #include <wx/wfstream.h>
33 #include <wx/sstream.h>
34 #include <wx/propgrid/advprops.h>
47 int nP = panoProjectionFormatCount();
48 for (
int n = 0; n < nP; n++)
50 pano_projection_features proj;
51 if (panoProjectionFeaturesQuery(n, &proj))
81 "Condition1=ImageCount>1\n"
82 "Condition2=PanoVFOV<100\n"
83 "Condition3=PanoHFOV>=100\n"
86 "Projection=Cylindrical\n"
89 "Condition1=ImageCount>1\n"
90 "Condition2=PanoVFOV>=100\n"
93 "Projection=Equirectangular\n"
96 "Condition1=ImageCount>1\n"
97 "Condition2=PanoHFOV<100\n"
98 "Condition3=PanoVFOV<100\n"
101 "Projection=Rectilinear"
105 bool contains(
const wxArrayString& stringArray,
const wxString&
string,
bool caseInSensitive =
true)
109 for (
size_t i = 0; i < stringArray.GetCount(); ++i)
111 if (stringArray[i].CmpNoCase(
string) == 0)
119 for (
size_t i = 0; i < stringArray.GetCount(); ++i)
121 if (stringArray[i].Cmp(
string) == 0)
132 wxSizer* topSizer =
new wxBoxSizer(wxVERTICAL);
133 m_grid =
new wxPropertyGridManager(
this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxPG_AUTO_SORT | wxPG_DESCRIPTION | wxPG_SPLITTER_AUTO_CENTER);
137 topSizer->Add(
m_grid, wxSizerFlags(1).Expand().Border(wxALL, 10));
138 wxStdDialogButtonSizer* buttonSizer = CreateStdDialogButtonSizer(wxOK | wxCANCEL);
140 topSizer->Add(buttonSizer, wxSizerFlags().Expand().Border(wxALL, 6));
141 SetSizerAndFit(topSizer);
160 if (key.SubString(0, 8).CmpNoCase(
"Condition") == 0)
162 wxPGProperty* p =
m_grid->AppendIn(section,
new wxStringProperty(key, wxPG_LABEL, value));
163 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."));
166 if (key.CmpNoCase(
"Projection") == 0)
177 p->SetHelpString(_(
"Select which projection should be selected."));
180 if (key.CmpNoCase(
"FOV") == 0)
182 wxPGProperty* p =
m_grid->AppendIn(section,
new wxStringProperty(key, wxPG_LABEL, value));
183 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)."));
186 if (key.CmpNoCase(
"Canvas") == 0)
188 wxPGProperty* p =
m_grid->AppendIn(section,
new wxStringProperty(key, wxPG_LABEL, value));
189 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)."));
192 if (key.CmpNoCase(
"Crop") == 0)
194 wxPGProperty* p =
m_grid->AppendIn(section,
new wxStringProperty(key, wxPG_LABEL, value));
195 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%)."));
198 if (key.CmpNoCase(
"OutputExposure") == 0)
200 wxPGProperty* p =
m_grid->AppendIn(section,
new wxStringProperty(key, wxPG_LABEL, value));
201 p->SetHelpString(_(
"Select which output exposure value should be used.\nFor automatic detection use Auto or give a fixed exposure value."));
204 if (key.CmpNoCase(
"OutputType") == 0)
207 wxArrayString values = wxStringTokenize(value,
",");
208 for (
size_t i = 0; i < values.size(); ++i)
211 values[i].Trim(
true).Trim(
false);
213 wxPGProperty* p =
m_grid->AppendIn(section,
new wxMultiChoiceProperty(key, wxPG_LABEL,
OutputTypeArray, values));
214 p->SetHelpString(_(
"Select which output types should be activated."));
217 if (key.CmpNoCase(
"Blender") == 0)
219 wxPGProperty* p =
m_grid->AppendIn(section,
new wxEnumProperty(key, wxPG_LABEL,
BlenderArray));
228 p->SetHelpString(_(
"Select which blender should be used (can be enblend or internal)."));
231 if (key.CmpNoCase(
"BlenderArgs") == 0)
233 wxPGProperty* p =
m_grid->AppendIn(section,
new wxStringProperty(key, wxPG_LABEL, value));
234 p->SetHelpString(_(
"Select which arguments should be passed to the blender."));
237 if (key.CmpNoCase(
"LDRFileType") == 0)
248 p->SetHelpString(_(
"Select fileformat for LDR output should be set."));
251 if (key.CmpNoCase(
"LDRCompression") == 0)
253 wxPGProperty* p =
m_grid->AppendIn(section,
new wxStringProperty(key, wxPG_LABEL, value));
254 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)."));
257 if (key.CmpNoCase(
"HDRFileType") == 0)
268 p->SetHelpString(_(
"Select fileformat for HDR output should be set."));
271 if (key.CmpNoCase(
"HDRCompression") == 0)
273 wxPGProperty* p =
m_grid->AppendIn(section,
new wxStringProperty(key, wxPG_LABEL, value));
274 p->SetHelpString(_(
"Select which compressions should be used for HDR images.\nFor TIFF images NONE, PACKBITS, LZW and DEFLATE are supported."));
278 wxPGProperty* newProperty =
m_grid->AppendIn(section,
new wxStringProperty(key, wxPG_LABEL, value));
284 wxInputStream* iniStream{
nullptr };
286 if (iniFilename.FileExists())
288 iniStream =
new wxFileInputStream(iniFilename.GetFullPath());
289 if (!iniStream->IsOk())
295 if (iniStream ==
nullptr)
297 iniStream =
new wxStringInputStream(
defaultIni);
300 wxFileConfig iniFile(*iniStream);
304 bool hasSections = iniFile.GetFirstGroup(section, index);
307 wxPGProperty* pgSection =
new wxPropertyCategory(section);
308 m_grid->Append(pgSection);
309 iniFile.SetPath(section);
312 bool hasKeys = iniFile.GetFirstEntry(key, indexKey);
315 AddKey(pgSection, key, iniFile.Read(key, wxEmptyString));
316 hasKeys = iniFile.GetNextEntry(key, indexKey);
318 iniFile.SetPath(
"/");
319 hasSections = iniFile.GetNextGroup(section, index);
327 wxFileConfig iniFile;
329 for (wxPropertyGridIterator it =
m_grid->GetIterator(wxPG_ITERATE_ALL); !it.AtEnd(); it++)
331 wxPGProperty* p = it.GetProperty();
338 iniFile.SetPath(
"/" + p->GetLabel());
342 wxVariant value = p->GetValue();
345 if (value.GetType().CmpNoCase(
"string") == 0)
347 const wxString s(value.GetString());
348 iniFile.Write(p->GetLabel(), s);
352 if (value.GetType().CmpNoCase(
"long") == 0)
354 const long i = value.GetLong();
355 wxPGChoices choices = p->GetChoices();
356 iniFile.Write(p->GetLabel(), choices[i].GetText());
360 if (value.GetType().CmpNoCase(
"arrstring") == 0)
362 wxArrayString values = value.GetArrayString();
364 for (
size_t i = 0; i < values.size(); ++i)
366 s << values[i] <<
",";
373 iniFile.Write(p->GetLabel(), s);
383 if (iniStream.IsOk())
385 success = iniFile.Save(iniStream);
389 wxMessageBox(wxString::Format(_(
"Could not save ini file \"%s\"."),
GetIniFileName().GetFullPath()), _(
"Error"), wxOK | wxICON_ERROR,
this);
403 wxMenuItem* item = menu.Append(wxID_ANY, _(
"Add condition"));
406 #define ADDKEYITEM(s) val=s;\
407 if (!contains(knownValues, val))\
409 item = menu.Append(wxID_ANY, wxString::Format(_("Add %s"), val.c_str()));\
410 Bind(wxEVT_MENU, [this, category, val](wxCommandEvent&) { AddKey(category, val, wxEmptyString); m_grid->RefreshGrid(); }, item->GetId());\
428 menu.AppendSeparator();
434 wxPropertyGridHitTestResult hitTest =
m_grid->GetGrid()->HitTest(
m_grid->GetGrid()->CalcScrolledPosition(
m_grid->ScreenToClient(e.GetPosition())));
436 wxMenuItem* menuItem = contextMenu.Append(wxID_ANY, _(
"Create new section"));
438 contextMenu.AppendSeparator();
439 wxPGProperty* prop = hitTest.GetProperty();
442 if (prop->IsCategory())
446 menuItem = contextMenu.Append(wxID_ANY, wxString::Format(_(
"Rename section %s"), prop->GetLabel().c_str()));
454 if (prop->IsCategory())
456 menuItem = contextMenu.Append(wxID_ANY, wxString::Format(_(
"Remove section %s"), prop->GetLabel().c_str()));
460 menuItem = contextMenu.Append(wxID_ANY, wxString::Format(_(
"Remove item %s"), prop->GetLabel().c_str()));
462 Bind(wxEVT_MENU, [
this, prop](wxCommandEvent&) {
m_grid->DeleteProperty(prop);
m_grid->RefreshGrid(); }, menuItem->GetId());
467 wxPGProperty* lastCategory{
nullptr };
468 for (wxPropertyGridIterator it =
m_grid->GetGrid()->GetIterator(wxPG_ITERATE_CATEGORIES); !it.AtEnd(); it++)
470 lastCategory = it.GetProperty();
478 PopupMenu(&contextMenu);
483 wxArrayString sections;
484 for (wxPropertyGridIterator it =
m_grid->GetIterator(wxPG_ITERATE_CATEGORIES); !it.AtEnd(); it++)
486 sections.Add(it.GetProperty()->GetLabel());
493 wxArrayString values;
495 for (wxPropertyGridIterator it =
m_grid->GetIterator(wxPG_ITERATE_DEFAULT, prop); !it.AtEnd() && counter < prop->GetChildCount(); it++, ++counter)
497 values.Add(it.GetProperty()->GetLabel());
507 wxTextEntryDialog dialog(
this, _(
"Name of new section:"), _(
"Create new section"));
508 if (dialog.ShowModal() == wxID_OK)
510 const wxString newSection = dialog.GetValue();
512 if (
contains(knownSections, newSection))
514 wxMessageBox(wxString::Format(_(
"Section \"%s\" is already defined.\nPlease use another name."), newSection.c_str()), _(
"Duplicate value."), wxOK | wxICON_ERROR);
519 wxPGProperty* pgSection =
new wxPropertyCategory(newSection);
528 wxPGProperty* currentSection =
m_grid->GetSelection();
529 if (!currentSection->IsCategory())
535 knownSections.Remove(currentSection->GetLabel());
537 wxTextEntryDialog dialog(
this, _(
"New name of section:"), _(
"Create new section"), currentSection->GetLabel());
538 if (dialog.ShowModal() == wxID_OK)
540 const wxString newSection = dialog.GetValue();
542 if (
contains(knownSections, newSection))
544 wxMessageBox(wxString::Format(_(
"Section \"%s\" is already defined.\nPlease use another name."), newSection.c_str()), _(
"Duplicate value."), wxOK | wxICON_ERROR);
549 currentSection->SetLabel(newSection);
560 for (
size_t i = 0; i < children.GetCount(); ++i)
562 if (children[i].SubString(0, 8).CmpNoCase(
"Condition") == 0)
565 if (children[i].Mid(9).ToLong(&x))
567 index = std::max<long>(index, x);
572 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 StoreFramePosition(wxTopLevelWindow *frame, const wxString &basename)
Store window size and position in configfile/registry.
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 RestoreFramePosition(wxTopLevelWindow *frame, const wxString &basename)
Restore window size and position from 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