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)
133 wxIconBundle myIcons(
huginApp::Get()->GetXRCPath() + wxT(
"data/hugin.ico"), wxBITMAP_TYPE_ICO);
136 wxIcon myIcon(
huginApp::Get()->GetXRCPath() + wxT(
"data/hugin.png"), wxBITMAP_TYPE_PNG);
141 wxSizer* topSizer =
new wxBoxSizer(wxVERTICAL);
142 m_grid =
new wxPropertyGridManager(
this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxPG_AUTO_SORT | wxPG_DESCRIPTION | wxPG_SPLITTER_AUTO_CENTER);
146 topSizer->Add(
m_grid, wxSizerFlags(1).Expand().Border(wxALL, 10));
147 wxStdDialogButtonSizer* buttonSizer = CreateStdDialogButtonSizer(wxOK | wxCANCEL);
149 topSizer->Add(buttonSizer, wxSizerFlags().Expand().Border(wxALL, 6));
150 SetSizerAndFit(topSizer);
169 if (key.SubString(0, 8).CmpNoCase(
"Condition") == 0)
171 wxPGProperty* p =
m_grid->AppendIn(section,
new wxStringProperty(key, wxPG_LABEL, value));
172 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."));
175 if (key.CmpNoCase(
"Projection") == 0)
186 p->SetHelpString(_(
"Select which projection should be selected."));
189 if (key.CmpNoCase(
"FOV") == 0)
191 wxPGProperty* p =
m_grid->AppendIn(section,
new wxStringProperty(key, wxPG_LABEL, value));
192 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)."));
195 if (key.CmpNoCase(
"Canvas") == 0)
197 wxPGProperty* p =
m_grid->AppendIn(section,
new wxStringProperty(key, wxPG_LABEL, value));
198 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)."));
201 if (key.CmpNoCase(
"Crop") == 0)
203 wxPGProperty* p =
m_grid->AppendIn(section,
new wxStringProperty(key, wxPG_LABEL, value));
204 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%)."));
207 if (key.CmpNoCase(
"OutputExposure") == 0)
209 wxPGProperty* p =
m_grid->AppendIn(section,
new wxStringProperty(key, wxPG_LABEL, value));
210 p->SetHelpString(_(
"Select which output exposure value should be used.\nFor automatic detection use Auto or give a fixed exposure value."));
213 if (key.CmpNoCase(
"OutputType") == 0)
216 wxArrayString values = wxStringTokenize(value,
",");
217 for (
size_t i = 0; i < values.size(); ++i)
220 values[i].Trim(
true).Trim(
false);
222 wxPGProperty* p =
m_grid->AppendIn(section,
new wxMultiChoiceProperty(key, wxPG_LABEL,
OutputTypeArray, values));
223 p->SetHelpString(_(
"Select which output types should be activated."));
226 if (key.CmpNoCase(
"Blender") == 0)
228 wxPGProperty* p =
m_grid->AppendIn(section,
new wxEnumProperty(key, wxPG_LABEL,
BlenderArray));
237 p->SetHelpString(_(
"Select which blender should be used (can be enblend or internal)."));
240 if (key.CmpNoCase(
"BlenderArgs") == 0)
242 wxPGProperty* p =
m_grid->AppendIn(section,
new wxStringProperty(key, wxPG_LABEL, value));
243 p->SetHelpString(_(
"Select which arguments should be passed to the blender."));
246 if (key.CmpNoCase(
"LDRFileType") == 0)
257 p->SetHelpString(_(
"Select fileformat for LDR output should be set."));
260 if (key.CmpNoCase(
"LDRCompression") == 0)
262 wxPGProperty* p =
m_grid->AppendIn(section,
new wxStringProperty(key, wxPG_LABEL, value));
263 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)."));
266 if (key.CmpNoCase(
"HDRFileType") == 0)
277 p->SetHelpString(_(
"Select fileformat for HDR output should be set."));
280 if (key.CmpNoCase(
"HDRCompression") == 0)
282 wxPGProperty* p =
m_grid->AppendIn(section,
new wxStringProperty(key, wxPG_LABEL, value));
283 p->SetHelpString(_(
"Select which compressions should be used for HDR images.\nFor TIFF images NONE, PACKBITS, LZW and DEFLATE are supported."));
287 wxPGProperty* newProperty =
m_grid->AppendIn(section,
new wxStringProperty(key, wxPG_LABEL, value));
293 wxInputStream* iniStream{
nullptr };
295 if (iniFilename.FileExists())
297 iniStream =
new wxFileInputStream(iniFilename.GetFullPath());
298 if (!iniStream->IsOk())
304 if (iniStream ==
nullptr)
306 iniStream =
new wxStringInputStream(
defaultIni);
309 wxFileConfig iniFile(*iniStream);
313 bool hasSections = iniFile.GetFirstGroup(section, index);
316 wxPGProperty* pgSection =
new wxPropertyCategory(section);
317 m_grid->Append(pgSection);
318 iniFile.SetPath(section);
321 bool hasKeys = iniFile.GetFirstEntry(key, indexKey);
324 AddKey(pgSection, key, iniFile.Read(key, wxEmptyString));
325 hasKeys = iniFile.GetNextEntry(key, indexKey);
327 iniFile.SetPath(
"/");
328 hasSections = iniFile.GetNextGroup(section, index);
336 wxFileConfig iniFile;
338 for (wxPropertyGridIterator it =
m_grid->GetIterator(wxPG_ITERATE_ALL); !it.AtEnd(); it++)
340 wxPGProperty* p = it.GetProperty();
347 iniFile.SetPath(
"/" + p->GetLabel());
351 wxVariant value = p->GetValue();
354 if (value.GetType().CmpNoCase(
"string") == 0)
356 const wxString s(value.GetString());
357 iniFile.Write(p->GetLabel(), s);
361 if (value.GetType().CmpNoCase(
"long") == 0)
363 const long i = value.GetLong();
364 wxPGChoices choices = p->GetChoices();
365 iniFile.Write(p->GetLabel(), choices[i].GetText());
369 if (value.GetType().CmpNoCase(
"arrstring") == 0)
371 wxArrayString values = value.GetArrayString();
373 for (
size_t i = 0; i < values.size(); ++i)
375 s << values[i] <<
",";
382 iniFile.Write(p->GetLabel(), s);
392 if (iniStream.IsOk())
394 success = iniFile.Save(iniStream);
398 wxMessageBox(wxString::Format(_(
"Could not save ini file \"%s\"."),
GetIniFileName().GetFullPath()), _(
"Error"), wxOK | wxICON_ERROR,
this);
412 wxMenuItem* item = menu.Append(wxID_ANY, _(
"Add condition"));
415 #define ADDKEYITEM(s) val=s;\
416 if (!contains(knownValues, val))\
418 item = menu.Append(wxID_ANY, wxString::Format(_("Add %s"), val.c_str()));\
419 Bind(wxEVT_MENU, [this, category, val](wxCommandEvent&) { AddKey(category, val, wxEmptyString); m_grid->RefreshGrid(); }, item->GetId());\
437 menu.AppendSeparator();
443 wxPropertyGridHitTestResult hitTest =
m_grid->GetGrid()->HitTest(
m_grid->GetGrid()->CalcScrolledPosition(
m_grid->ScreenToClient(e.GetPosition())));
445 wxMenuItem* menuItem = contextMenu.Append(wxID_ANY, _(
"Create new section"));
447 contextMenu.AppendSeparator();
448 wxPGProperty* prop = hitTest.GetProperty();
451 if (prop->IsCategory())
455 menuItem = contextMenu.Append(wxID_ANY, wxString::Format(_(
"Rename section %s"), prop->GetLabel().c_str()));
463 if (prop->IsCategory())
465 menuItem = contextMenu.Append(wxID_ANY, wxString::Format(_(
"Remove section %s"), prop->GetLabel().c_str()));
469 menuItem = contextMenu.Append(wxID_ANY, wxString::Format(_(
"Remove item %s"), prop->GetLabel().c_str()));
471 Bind(wxEVT_MENU, [
this, prop](wxCommandEvent&) {
m_grid->DeleteProperty(prop);
m_grid->RefreshGrid(); }, menuItem->GetId());
476 wxPGProperty* lastCategory{
nullptr };
477 for (wxPropertyGridIterator it =
m_grid->GetGrid()->GetIterator(wxPG_ITERATE_CATEGORIES); !it.AtEnd(); it++)
479 lastCategory = it.GetProperty();
487 PopupMenu(&contextMenu);
492 wxArrayString sections;
493 for (wxPropertyGridIterator it =
m_grid->GetIterator(wxPG_ITERATE_CATEGORIES); !it.AtEnd(); it++)
495 sections.Add(it.GetProperty()->GetLabel());
502 wxArrayString values;
504 for (wxPropertyGridIterator it =
m_grid->GetIterator(wxPG_ITERATE_DEFAULT, prop); !it.AtEnd() && counter < prop->GetChildCount(); it++, ++counter)
506 values.Add(it.GetProperty()->GetLabel());
516 wxTextEntryDialog dialog(
this, _(
"Name of new section:"), _(
"Create new section"));
517 if (dialog.ShowModal() == wxID_OK)
519 const wxString newSection = dialog.GetValue();
521 if (
contains(knownSections, newSection))
523 wxMessageBox(wxString::Format(_(
"Section \"%s\" is already defined.\nPlease use another name."), newSection.c_str()), _(
"Duplicate value."), wxOK | wxICON_ERROR);
528 wxPGProperty* pgSection =
new wxPropertyCategory(newSection);
537 wxPGProperty* currentSection =
m_grid->GetSelection();
538 if (!currentSection->IsCategory())
544 knownSections.Remove(currentSection->GetLabel());
546 wxTextEntryDialog dialog(
this, _(
"New name of section:"), _(
"Create new section"), currentSection->GetLabel());
547 if (dialog.ShowModal() == wxID_OK)
549 const wxString newSection = dialog.GetValue();
551 if (
contains(knownSections, newSection))
553 wxMessageBox(wxString::Format(_(
"Section \"%s\" is already defined.\nPlease use another name."), newSection.c_str()), _(
"Duplicate value."), wxOK | wxICON_ERROR);
558 currentSection->SetLabel(newSection);
569 for (
size_t i = 0; i < children.GetCount(); ++i)
571 if (children[i].SubString(0, 8).CmpNoCase(
"Condition") == 0)
574 if (children[i].Mid(9).ToLong(&x))
576 index = std::max<long>(index, x);
581 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
static huginApp * Get()
hack.. kind of a pseudo singleton...
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