30 #include "wx/busyinfo.h"
39 wxDEFINE_EVENT(wxEVT_COMMAND_THUMBNAILTHREAD_UPDATE, wxCommandEvent);
76 : wxThread(wxTHREAD_DETACHED)
93 for (
int i = 0; i <
m_files.size(); ++i)
96 vigra::BRGBImage* preview=
new vigra::BRGBImage();
97 vigra::BImage* mask =
new vigra::BImage();
98 vigra::ImageImportInfo::ICCProfile iccProfile;
113 vigra::BRGBImage* scaledPreview =
new vigra::BRGBImage(vigra::Diff2D(
m_thumbnailSize.GetWidth(),
m_thumbnailSize.GetHeight()), vigra::RGBValue<vigra::UInt8>(255, 255, 255));
114 vigra::BImage* scaledMask =
new vigra::BImage(scaledPreview->size(), vigra::UInt8(0));
115 vigra::Point2D offset((scaledPreview->width() - preview->width()) / 2, (scaledPreview->height() - preview->height()) / 2);
120 preview = scaledPreview;
126 wxCommandEvent*
event =
new wxCommandEvent(wxEVT_COMMAND_THUMBNAILTHREAD_UPDATE);
128 event->SetEventObject(thumbnailImageData);
135 delete thumbnailImageData;
144 return (wxThread::ExitCode)0;
152 #define THUMBNAIL_SIZE 128
158 wxXmlResource::Get()->LoadDialog(
this, parent,
"browse_pto_dialog");
161 wxIconBundle myIcons(
huginApp::Get()->GetXRCPath() + wxT(
"data/hugin.ico"),wxBITMAP_TYPE_ICO);
164 wxIcon myIcon(
huginApp::Get()->GetXRCPath() + wxT(
"data/hugin.png"),wxBITMAP_TYPE_PNG);
167 m_dirCtrl = XRCCTRL(*
this,
"browse_dirctrl", wxGenericDirCtrl);
169 m_listCtrl = XRCCTRL(*
this,
"browse_listctrl", wxListCtrl);
172 m_previewCtrl = XRCCTRL(*
this,
"browse_preview", wxStaticBitmap);
173 m_splitter1 = XRCCTRL(*
this,
"browse_splitter1", wxSplitterWindow);
174 m_splitter2 = XRCCTRL(*
this,
"browse_splitter2", wxSplitterWindow);
175 m_showMap = XRCCTRL(*
this,
"browse_show_map", wxButton);
176 m_labelControl = XRCCTRL(*
this,
"browse_statictext", wxStaticText);
179 m_listCtrl->SetWindowStyle(wxLC_REPORT | wxLC_AUTOARRANGE | wxLC_SINGLE_SEL | wxLC_HRULES | wxLC_VRULES);
182 m_listCtrl->InsertColumn(0, _(
"Filename"), wxLIST_FORMAT_LEFT, 300);
183 m_listCtrl->InsertColumn(1, _(
"# images"), wxLIST_FORMAT_RIGHT, 50);
184 m_listCtrl->InsertColumn(2, _(
"# active images"), wxLIST_FORMAT_RIGHT, 50);
185 m_listCtrl->InsertColumn(3, _(
"Projection"), wxLIST_FORMAT_LEFT, 200);
186 m_listCtrl->InsertColumn(4, _(
"Field of view"), wxLIST_FORMAT_LEFT, 100);
187 m_listCtrl->InsertColumn(5, _(
"Canvas size"), wxLIST_FORMAT_LEFT, 100);
188 m_listCtrl->InsertColumn(6, _(
"Model"), wxLIST_FORMAT_LEFT, 200);
189 m_listCtrl->InsertColumn(7, _(
"Lens"), wxLIST_FORMAT_LEFT, 250);
190 m_listCtrl->InsertColumn(8, _(
"Focal length"), wxLIST_FORMAT_LEFT, 150);
191 m_listCtrl->InsertColumn(9, _(
"Capture date"), wxLIST_FORMAT_LEFT, 150);
192 m_listCtrl->InsertColumn(10, _(
"Duration"), wxLIST_FORMAT_LEFT, 50);
193 m_listType = XRCCTRL(*
this,
"browse_list_type", wxChoice);
197 wxConfigBase* config = wxConfigBase::Get();
199 int splitter_pos = config->Read(
"/BrowsePTODialog/splitterPos1", -1l);
200 if (splitter_pos > 0)
204 splitter_pos = config->Read(
"/BrowsePTODialog/splitterPos2", -1l);
205 if (splitter_pos > 0)
210 for (
int j = 0; j <
m_listCtrl->GetColumnCount(); j++)
213 int width = config->Read(wxString::Format(
"/BrowsePTODialog/ColumnWidth%d", j), -1);
214 if (width != -1 && width > 5)
219 m_sortCol = config->Read(
"/BrowsePTODialog/SortColumn", -1);
220 m_sortAscending = config->Read(
"/BrowsePTODialog/SortAscending", 1) == 1 ?
true :
false;
227 if (!startDirectory.IsEmpty())
231 long listType = config->Read(
"/BrowsePTODialog/ListType", 0l);
233 wxCommandEvent event;
234 event.SetInt(listType);
247 wxConfigBase* config = wxConfigBase::Get();
248 config->Write(
"/BrowsePTODialog/splitterPos1",
m_splitter1->GetSashPosition());
249 config->Write(
"/BrowsePTODialog/splitterPos2",
m_splitter2->GetSashPosition());
251 for (
int j = 0; j <
m_listCtrl->GetColumnCount(); j++)
253 config->Write(wxString::Format(
"/BrowsePTODialog/ColumnWidth%d", j),
m_listCtrl->GetColumnWidth(j));
255 config->Write(
"/BrowsePTODialog/ListType",
m_listType->GetSelection());
256 config->Write(wxT(
"/BrowsePTODialog/SortColumn"),
m_sortCol);
257 config->Write(wxT(
"/BrowsePTODialog/SortAscending"),
m_sortAscending ? 1 : 0);
266 index =
m_listCtrl->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
268 if (index >= 0 && index <
m_ptoInfo.size())
274 return wxEmptyString;
312 pano_projection_features proj;
316 wxString str2(proj.name, wxConvLocal);
322 if (!activeImages.empty())
330 info.
camera = img0.getExifModel();
331 info.
lens = img0.getExifLens();
335 info.
focalLength35 = img0.getExifFocalLength() * img0.getCropFactor();
343 if (!img0.getExifDate().empty())
345 struct tm exifdatetime;
348 info.
start = wxDateTime(exifdatetime);
353 imgs.erase(imgs.begin());
354 for (
const auto& img : imgs)
362 memset(&exifdatetime, 0,
sizeof(exifdatetime));
363 if (!imgSrcImage.getExifDate().empty() && imgSrcImage.
getExifDateTime(&exifdatetime) == 0)
365 const wxDateTime dateTime = wxDateTime(exifdatetime);
366 if (info.
start.IsValid())
368 if (dateTime.IsEarlierThan(info.
start))
370 info.
start = dateTime;
372 if (dateTime.IsLaterThan(info.
end))
379 info.
start = dateTime;
384 if (info.
start.IsValid())
389 const auto& fileMetadata = img0.getFileMetadata();
390 const auto& latitude = fileMetadata.find(
"latitude");
391 const auto& longitude = fileMetadata.find(
"longitude");
392 if (latitude != fileMetadata.end())
396 if (longitude != fileMetadata.end())
419 if (info.
start.IsValid())
436 for (
size_t i = 0; i <
m_ptoInfo.size(); ++i)
450 wxWindowDisabler disableAll;
451 wxBusyInfo busy(wxBusyInfoFlags().Icon(
MainFrame::Get()->GetIcon()).Label(wxString::Format(_(
"Reading directory %s"),
m_dirCtrl->GetPath().c_str())));
457 SetTitle(wxString::Format(_(
"Browse project files in %s"),
m_dirCtrl->GetPath().c_str()));
459 wxDir::GetAllFiles(
m_dirCtrl->GetPath(), &files,
"*.pto", wxDIR_FILES | wxDIR_HIDDEN | wxDIR_NO_FOLLOW);
463 for (
size_t i = 0; i < files.size(); ++i)
465 const wxFileName filename(files[i]);
490 if (e.GetIndex() >= 0)
506 const int newCol = e.GetColumn();
524 const int index = e.GetInt();
527 for (
size_t i = 0; i <
m_listCtrl->GetItemCount(); ++i)
546 if (e.GetSelection() == 0)
557 UpdateItemTexts(wxLC_REPORT | wxLC_AUTOARRANGE | wxLC_SINGLE_SEL | wxLC_HRULES | wxLC_VRULES);
572 index =
m_listCtrl->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
574 if (index >= 0 && index <
m_ptoInfo.size())
578 const wxString openstreetMapLink =
"https://www.openstreetmap.org/?mlat=" + wxString::FromCDouble(
m_ptoInfo[index].GPSLatitude) +
"&mlon=" + wxString::FromCDouble(
m_ptoInfo[index].GPSLongitude);
579 wxLaunchDefaultBrowser(openstreetMapLink);
589 template <
class Type>
608 template <
class Type>
627 #define SORTASCENDING(functionName, var) \
628 int wxCALLBACK functionName(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData)\
630 std::vector<PanoInfo>* data = (std::vector<PanoInfo>*)(sortData);\
631 return GreaterComparisonOperator(data->at(item1).var, data->at(item2).var);\
633 #define SORTDESCENDING(functionName, var) \
634 int wxCALLBACK functionName(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData)\
636 std::vector<PanoInfo>* data = (std::vector<PanoInfo>*)(sortData);\
637 return SmallerComparisonOperator(data->at(item1).var, data->at(item2).var);\
640 SORTASCENDING(SortFilenameAscending, ptoFilename.GetFullName())
654 #undef SORTDESCENDING
657 #define SORTASCENDING(functionName, var) \
658 int wxCALLBACK functionName(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData)\
660 std::vector<PanoInfo>* data = (std::vector<PanoInfo>*)(sortData);\
661 return data->at(item1).var.CmpNoCase(data->at(item2).var);\
663 #define SORTDESCENDING(functionName, var) \
664 int wxCALLBACK functionName(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData)\
666 std::vector<PanoInfo>* data = (std::vector<PanoInfo>*)(sortData);\
667 return -(data->at(item1).var.CmpNoCase(data->at(item2).var));\
675 #undef SORTDESCENDING
678 int wxCALLBACK SortFieldOfViewAscending(wxIntPtr item1, wxIntPtr
item2, wxIntPtr sortData)
680 std::vector<PanoInfo>*
data = (std::vector<PanoInfo>*)(sortData);
681 const float fieldOfView1 = data->at(item1).options.getHFOV() * 1000 + data->at(item1).options.getVFOV();
682 const float fieldOfView2 = data->at(item2).options.getHFOV() * 1000 + data->at(item2).options.getVFOV();
688 std::vector<PanoInfo>* data = (std::vector<PanoInfo>*)(sortData);
689 const float fieldOfView1 = data->at(item1).options.getHFOV() * 1000 + data->at(item1).options.getVFOV();
690 const float fieldOfView2 = data->at(item2).options.getHFOV() * 1000 + data->at(item2).options.getVFOV();
697 std::vector<PanoInfo>* data = (std::vector<PanoInfo>*)(sortData);
698 if (data->at(item1).start.IsLaterThan(data->at(item2).start))
702 if (data->at(item1).start.IsEarlierThan(data->at(item2).start))
711 std::vector<PanoInfo>* data = (std::vector<PanoInfo>*)(sortData);
712 if (data->at(item1).start.IsEarlierThan(data->at(item2).start))
716 if (data->at(item1).start.IsLaterThan(data->at(item2).start))
726 std::vector<PanoInfo>* data = (std::vector<PanoInfo>*)(sortData);
727 if (data->at(item1).duration.IsLongerThan(data->at(item2).duration))
731 if (data->at(item1).duration.IsShorterThan(data->at(item2).duration))
740 std::vector<PanoInfo>* data = (std::vector<PanoInfo>*)(sortData);
741 if (data->at(item1).duration.IsShorterThan(data->at(item2).duration))
745 if (data->at(item1).duration.IsLongerThan(data->at(item2).duration))
878 bool deleteStoppedThread =
false;
889 deleteStoppedThread =
true;
893 if (deleteStoppedThread)
911 wxThread::This()->Sleep(1);
921 wxWindowDisabler disableAll;
922 wxBusyInfo busyInfo(wxBusyInfoFlags().Icon(
MainFrame::Get()->GetIcon()).Label(wxString::Format(_(
"Generating preview for %s"),
m_ptoInfo[index].ptoFilename.GetFullName().c_str())));
924 vigra::BRGBImage preview;
926 vigra::ImageImportInfo::ICCProfile iccProfile;
929 wxImage image(preview.width(), preview.height(), (
unsigned char*)preview.data(), (
unsigned char*)mask.data(),
true);
wxDEFINE_EVENT(EVT_QUEUE_PROGRESS, wxCommandEvent)
~BrowsePTOFilesDialog()
destructor, saves position
BrowsePTOFilesDialog(wxWindow *parent, const wxString startDirectory)
Constructor, read from xrc ressource; restore last uses settings and position.
WXIMPEX wxString GetFormattedTimeSpan(const wxTimeSpan &timeSpan)
PanoramaOptions::ProjectionFormat getProjection() const
generate thumbnail from given pto file
bool FileExists(const std::string &filename)
checks if file exists
int SmallerComparisonOperator(const Type &a, const Type &b)
SrcPanoImage getSrcImage(unsigned imgNr) const
get a description of a source image
unsigned int getHeight() const
get panorama height
int wxCALLBACK SortFieldOfViewDescending(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData)
ThumbnailThread(BrowsePTOFilesDialog *parentDialog, const wxArrayString &fileList, const wxSize size)
void FillPanoInfo(const PanoInfo &info, long index)
add a new item to wxListCtrl and populate all columns
#define SORTASCENDING(functionName, var)
void OnFileChanged(wxListEvent &e)
new file selected, generate preview for new file
friend class ThumbnailThread
void OnThumbnailUpdate(wxCommandEvent &e)
for notifing from ThumbnailThread about new generated thumbnail generated thumbnail is transfered in ...
void GetMonitorProfile(wxString &profileName, cmsHPROFILE &profile)
wxImage * GetwxImage() const
static huginApp * Get()
hack.. kind of a pseudo singleton...
void OnDblClickListCtrl(wxMouseEvent &e)
double click does open file
std::set< unsigned int > UIntSet
wxSplitterWindow * m_splitter1
PanoInfo ParsePTOFile(const wxFileName file)
read the given pto file and add all information to wxListCtrl
options getSize().area()) int wxCALLBACK SortFieldOfViewAscending(wxIntPtr item1
std::string getPathPrefix(const std::string &filename)
Get the path to a filename.
int wxCALLBACK SortDateAscending(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData)
void OnListColClick(wxListEvent &e)
click on header to sort by column
void CorrectImage(wxImage &image, const vigra::ImageImportInfo::ICCProfile &iccProfile, const cmsHPROFILE &monitorProfile)
apply color correction to given image using input iccProfile and monitor profile
wxString focalLengthString
std::size_t getNrOfImages() const
number of images.
static MainFrame * Get()
hack.. kind of a pseudo singleton...
wxStaticText * m_labelControl
int wxCALLBACK SortDurationAscending(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData)
#define SORTDESCENDING(functionName, var)
const int getExifDateTime(struct tm *datetime) const
try to convert Exif date time string to struct tm
Dialog for browsing pto files.
void StoreFramePosition(wxTopLevelWindow *frame, const wxString &basename)
Store window size and position in configfile/registry.
wxGenericDirCtrl * m_dirCtrl
vigra::BRGBImage * m_preview
bool ReadPTOFile(const std::string &filename, const std::string &prefix="")
read pto file from the given filename into Panorama object it does some checks on the file and issues...
void OnDirectoryChanged(wxTreeEvent &e)
directory changed, load files from new directory
wxImageList m_thumbnails
image list with all thumbnails
helper class to transfer thumbnail data from worker thread to GUI thread
bool HasMonitorProfile() const
return true if we found a suitable monitor profile and could loading it
wxDECLARE_EVENT(wxEVT_COMMAND_THUMBNAILTHREAD_UPDATE, wxCommandEvent)
HuginBase::PanoramaOptions options
void RestoreFramePosition(wxTopLevelWindow *frame, const wxString &basename)
Restore window size and position from configfile/registry.
void GeneratePreview(int index)
generate preview for pto file with index
wxSplitterWindow * m_splitter2
static double calcFocalLength(SrcPanoImage::Projection proj, double hfov, double crop, vigra::Size2D imageSize)
calcualte focal length, given crop factor and hfov
vigra::pair< typename ROIImage< Image, Alpha >::image_traverser, typename ROIImage< Image, Alpha >::ImageAccessor > destImage(ROIImage< Image, Alpha > &img)
bool stringToDouble(const STR &str_, double &dest)
convert a string to a double, ignore localisation.
std::vector< PanoInfo > m_ptoInfo
info about the pto file
void SortItems()
sort the items according to selected column
vigra::triple< typename ROIImage< Image, Mask >::image_const_traverser, typename ROIImage< Image, Mask >::image_const_traverser, typename ROIImage< Image, Mask >::ImageConstAccessor > srcImageRange(const ROIImage< Image, Mask > &img)
helper function for ROIImages
UIntSet getActiveImages() const
get active images
wxString GetSelectedProject()
return full path of selected project
unsigned int getWidth() const
const PanoramaOptions & getOptions() const
returns the options for this panorama
wxCriticalSection m_ThreadCS
critical section to synchronize with ThumbnailThread
options wxIntPtr wxIntPtr sortData std::vector< PanoInfo > * data
background thread to generate thumbnails of all pto files
wxStaticBitmap * m_previewCtrl
bool readEXIF()
try to fill out information about the image, by examining the exif data
bool GenerateThumbnail(const std::string pto_filename, const wxSize size, vigra::BRGBImage &panoImage, vigra::BImage &panoMask, vigra::ImageImportInfo::ICCProfile &iccProfile)
generate thumbnail image for given pto_filename
Definition of dialog to browse directory with pto files.
void OnListTypeChanged(wxCommandEvent &e)
Change display of wxListCtrl.
int wxCALLBACK SortDateDesending(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData)
void copyImage(SrcImageIterator src_upperleft, SrcImageIterator src_lowerright, SrcAccessor src_acc, DestImageIterator dest_upperleft, DestAccessor dest_acc)
BrowsePTOFilesDialog * m_parentDialog
static void info(const char *fmt,...)
class to store some information about a pto file on disc
void OnOk(wxCommandEvent &e)
Saves current expression when closing dialog with Ok.
ThreadImage(vigra::BRGBImage *thumbnail, vigra::BImage *mask)
int GreaterComparisonOperator(const Type &a, const Type &b)
All variables of a source image.
ThumbnailThread * m_thumbnailThread
background thumbnail creater thread
long TranslateIndex(const long index)
translate the index to the index of m_ptoInfo
int wxCALLBACK SortDurationDesending(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData)
void OnShowOnMap(wxCommandEvent &e)
show current pano on Openstreetmap
void EndThumbnailThread()
end background thumbnail creating thread
void UpdateItemTexts(long newStyle)
update all item texts
wxString GetSelectedPath()
return last selected path