30 #include "wx/busyinfo.h"
38 wxDEFINE_EVENT(wxEVT_COMMAND_THUMBNAILTHREAD_UPDATE, wxCommandEvent);
75 : wxThread(wxTHREAD_DETACHED)
92 for (
int i = 0; i <
m_files.size(); ++i)
95 vigra::BRGBImage* preview=
new vigra::BRGBImage();
96 vigra::BImage* mask =
new vigra::BImage();
97 vigra::ImageImportInfo::ICCProfile iccProfile;
112 vigra::BRGBImage* scaledPreview =
new vigra::BRGBImage(vigra::Diff2D(
m_thumbnailSize.GetWidth(),
m_thumbnailSize.GetHeight()), vigra::RGBValue<vigra::UInt8>(255, 255, 255));
113 vigra::BImage* scaledMask =
new vigra::BImage(scaledPreview->size(), vigra::UInt8(0));
114 vigra::Point2D offset((scaledPreview->width() - preview->width()) / 2, (scaledPreview->height() - preview->height()) / 2);
119 preview = scaledPreview;
125 wxCommandEvent*
event =
new wxCommandEvent(wxEVT_COMMAND_THUMBNAILTHREAD_UPDATE);
127 event->SetEventObject(thumbnailImageData);
134 delete thumbnailImageData;
143 return (wxThread::ExitCode)0;
151 #define THUMBNAIL_SIZE 128
153 #if !wxCHECK_VERSION(3,1,6)
158 item.SetMask(wxLIST_MASK_IMAGE);
159 item.SetImage(image);
160 list->SetColumn(col, item);
170 EVT_COMMAND(wxID_ANY, wxEVT_COMMAND_THUMBNAILTHREAD_UPDATE,
BrowsePTOFilesDialog::OnThumbnailUpdate)
178 wxXmlResource::Get()->LoadDialog(
this, parent,
"browse_pto_dialog");
181 wxIconBundle myIcons(
huginApp::Get()->GetXRCPath() + wxT(
"data/hugin.ico"),wxBITMAP_TYPE_ICO);
184 wxIcon myIcon(
huginApp::Get()->GetXRCPath() + wxT(
"data/hugin.png"),wxBITMAP_TYPE_PNG);
187 m_dirCtrl = XRCCTRL(*
this,
"browse_dirctrl", wxGenericDirCtrl);
188 m_listCtrl = XRCCTRL(*
this,
"browse_listctrl", wxListCtrl);
189 m_previewCtrl = XRCCTRL(*
this,
"browse_preview", wxStaticBitmap);
190 m_splitter1 = XRCCTRL(*
this,
"browse_splitter1", wxSplitterWindow);
191 m_splitter2 = XRCCTRL(*
this,
"browse_splitter2", wxSplitterWindow);
192 m_showMap = XRCCTRL(*
this,
"browse_show_map", wxButton);
193 m_labelControl = XRCCTRL(*
this,
"browse_statictext", wxStaticText);
194 m_labelControl->SetFont(m_labelControl->GetFont().Larger().Larger());
196 m_listCtrl->SetWindowStyle(wxLC_REPORT | wxLC_AUTOARRANGE | wxLC_SINGLE_SEL | wxLC_HRULES | wxLC_VRULES);
197 m_listCtrl->SetImageList(&m_thumbnails, wxIMAGE_LIST_NORMAL);
199 m_listCtrl->InsertColumn(0, _(
"Filename"), wxLIST_FORMAT_LEFT, 300);
200 m_listCtrl->InsertColumn(1, _(
"# images"), wxLIST_FORMAT_RIGHT, 50);
201 m_listCtrl->InsertColumn(2, _(
"# active images"), wxLIST_FORMAT_RIGHT, 50);
202 m_listCtrl->InsertColumn(3, _(
"Projection"), wxLIST_FORMAT_LEFT, 200);
203 m_listCtrl->InsertColumn(4, _(
"Field of view"), wxLIST_FORMAT_LEFT, 100);
204 m_listCtrl->InsertColumn(5, _(
"Canvas size"), wxLIST_FORMAT_LEFT, 100);
205 m_listCtrl->InsertColumn(6, _(
"Model"), wxLIST_FORMAT_LEFT, 200);
206 m_listCtrl->InsertColumn(7, _(
"Lens"), wxLIST_FORMAT_LEFT, 250);
207 m_listCtrl->InsertColumn(8, _(
"Focal length"), wxLIST_FORMAT_LEFT, 150);
208 m_listCtrl->InsertColumn(9, _(
"Capture date"), wxLIST_FORMAT_LEFT, 150);
209 m_listCtrl->InsertColumn(10, _(
"Duration"), wxLIST_FORMAT_LEFT, 50);
210 m_listType = XRCCTRL(*
this,
"browse_list_type", wxChoice);
213 wxConfigBase* config = wxConfigBase::Get();
215 int splitter_pos = config->Read(
"/BrowsePTODialog/splitterPos1", -1l);
216 if (splitter_pos > 0)
218 m_splitter1->SetSashPosition(splitter_pos);
220 splitter_pos = config->Read(
"/BrowsePTODialog/splitterPos2", -1l);
221 if (splitter_pos > 0)
223 m_splitter2->SetSashPosition(splitter_pos);
226 for (
int j = 0; j < m_listCtrl->GetColumnCount(); j++)
229 int width = config->Read(wxString::Format(
"/BrowsePTODialog/ColumnWidth%d", j), -1);
230 if (width != -1 && width > 5)
232 m_listCtrl->SetColumnWidth(j, width);
235 m_sortCol = config->Read(
"/BrowsePTODialog/SortColumn", -1);
236 m_sortAscending = config->Read(
"/BrowsePTODialog/SortAscending", 1) == 1 ?
true :
false;
239 #if wxCHECK_VERSION(3,1,6)
240 m_listCtrl->ShowSortIndicator(m_sortCol, m_sortAscending);
246 #if !wxCHECK_VERSION(3,1,6)
249 memDC.SetFont(GetFont());
250 wxSize fontSize = memDC.GetTextExtent(wxT(
"\u25b3"));
251 wxCoord charSize =
std::max(fontSize.GetWidth(), fontSize.GetHeight());
252 wxImageList* sortIcons =
new wxImageList(charSize, charSize,
true, 0);
254 wxBitmap bmp(charSize, charSize);
256 dc.SetBackgroundMode(wxPENSTYLE_TRANSPARENT);
257 dc.SetBackground(GetBackgroundColour());
259 dc.SetFont(GetFont());
260 dc.DrawText(wxT(
"\u25b3"), (charSize - fontSize.GetWidth()) / 2, (charSize - fontSize.GetHeight()) / 2);
261 dc.SelectObject(wxNullBitmap);
262 sortIcons->Add(bmp, GetBackgroundColour());
265 wxBitmap bmp(charSize, charSize);
267 dc.SetBackgroundMode(wxPENSTYLE_TRANSPARENT);
268 dc.SetBackground(GetBackgroundColour());
270 dc.SetFont(GetFont());
271 dc.DrawText(wxT(
"\u25bd"), (charSize - fontSize.GetWidth()) / 2, (charSize - fontSize.GetHeight()) / 2);
272 dc.SelectObject(wxNullBitmap);
273 sortIcons->Add(bmp, GetBackgroundColour());
275 m_listCtrl->AssignImageList(sortIcons, wxIMAGE_LIST_SMALL);
279 if (!startDirectory.IsEmpty())
281 m_dirCtrl->SetPath(startDirectory);
283 long listType = config->Read(
"/BrowsePTODialog/ListType", 0l);
284 m_listType->SetSelection(listType);
285 wxCommandEvent event;
286 event.SetInt(listType);
287 OnListTypeChanged(event);
296 wxConfigBase* config = wxConfigBase::Get();
297 config->Write(
"/BrowsePTODialog/splitterPos1",
m_splitter1->GetSashPosition());
298 config->Write(
"/BrowsePTODialog/splitterPos2",
m_splitter2->GetSashPosition());
300 for (
int j = 0; j <
m_listCtrl->GetColumnCount(); j++)
302 config->Write(wxString::Format(
"/BrowsePTODialog/ColumnWidth%d", j),
m_listCtrl->GetColumnWidth(j));
304 config->Write(
"/BrowsePTODialog/ListType",
m_listType->GetSelection());
305 config->Write(wxT(
"/BrowsePTODialog/SortColumn"),
m_sortCol);
306 config->Write(wxT(
"/BrowsePTODialog/SortAscending"),
m_sortAscending ? 1 : 0);
315 index =
m_listCtrl->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
317 if (index >= 0 && index <
m_ptoInfo.size())
323 return wxEmptyString;
361 pano_projection_features proj;
365 wxString str2(proj.name, wxConvLocal);
371 if (!activeImages.empty())
379 info.
camera = img0.getExifModel();
380 info.
lens = img0.getExifLens();
384 info.
focalLength35 = img0.getExifFocalLength() * img0.getCropFactor();
392 if (!img0.getExifDate().empty())
394 struct tm exifdatetime;
397 info.
start = wxDateTime(exifdatetime);
402 imgs.erase(imgs.begin());
403 for (
const auto& img : imgs)
411 memset(&exifdatetime, 0,
sizeof(exifdatetime));
412 if (!imgSrcImage.getExifDate().empty() && imgSrcImage.
getExifDateTime(&exifdatetime) == 0)
414 const wxDateTime dateTime = wxDateTime(exifdatetime);
415 if (info.
start.IsValid())
417 if (dateTime.IsEarlierThan(info.
start))
419 info.
start = dateTime;
421 if (dateTime.IsLaterThan(info.
end))
428 info.
start = dateTime;
433 if (info.
start.IsValid())
438 const auto& fileMetadata = img0.getFileMetadata();
439 const auto& latitude = fileMetadata.find(
"latitude");
440 const auto& longitude = fileMetadata.find(
"longitude");
441 if (latitude != fileMetadata.end())
445 if (longitude != fileMetadata.end())
455 if (timespan.GetSeconds() > 60)
457 return timespan.Format(_(
"%M:%S min"));
461 if (timespan.GetSeconds() < 1)
463 return wxEmptyString;
467 return timespan.Format(_(
"%S s"));
487 if (info.
start.IsValid())
504 for (
size_t i = 0; i <
m_ptoInfo.size(); ++i)
514 #if !wxCHECK_VERSION(3,1,6)
519 for (
size_t i = 0; i <
m_listCtrl->GetItemCount(); ++i)
528 for (
size_t i = 0; i <
m_listCtrl->GetItemCount(); ++i)
540 wxWindowDisabler disableAll;
541 wxBusyInfo busy(wxBusyInfoFlags().Icon(
MainFrame::Get()->GetIcon()).Label(wxString::Format(_(
"Reading directory %s"),
m_dirCtrl->GetPath().c_str())));
547 SetTitle(wxString::Format(_(
"Browse project files in %s"),
m_dirCtrl->GetPath().c_str()));
549 wxDir::GetAllFiles(
m_dirCtrl->GetPath(), &files,
"*.pto", wxDIR_FILES | wxDIR_HIDDEN | wxDIR_NO_FOLLOW);
553 for (
size_t i = 0; i < files.size(); ++i)
555 const wxFileName filename(files[i]);
580 if (e.GetIndex() >= 0)
596 const int newCol = e.GetColumn();
597 #if wxCHECK_VERSION(3,1,6)
632 const int index = e.GetInt();
635 #if wxCHECK_VERSION(3,1,6)
636 for (
size_t i = 0; i <
m_listCtrl->GetItemCount(); ++i)
658 if (e.GetSelection() == 0)
669 UpdateItemTexts(wxLC_REPORT | wxLC_AUTOARRANGE | wxLC_SINGLE_SEL | wxLC_HRULES | wxLC_VRULES);
671 #if !wxCHECK_VERSION(3,1,6)
687 index =
m_listCtrl->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
689 if (index >= 0 && index <
m_ptoInfo.size())
693 const wxString openstreetMapLink =
"https://www.openstreetmap.org/?mlat=" + wxString::FromCDouble(
m_ptoInfo[index].GPSLatitude) +
"&mlon=" + wxString::FromCDouble(
m_ptoInfo[index].GPSLongitude);
694 wxLaunchDefaultBrowser(openstreetMapLink);
704 template <
class Type>
723 template <
class Type>
742 #define SORTASCENDING(functionName, var) \
743 int wxCALLBACK functionName(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData)\
745 std::vector<PanoInfo>* data = (std::vector<PanoInfo>*)(sortData);\
746 return GreaterComparisonOperator(data->at(item1).var, data->at(item2).var);\
748 #define SORTDESCENDING(functionName, var) \
749 int wxCALLBACK functionName(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData)\
751 std::vector<PanoInfo>* data = (std::vector<PanoInfo>*)(sortData);\
752 return SmallerComparisonOperator(data->at(item1).var, data->at(item2).var);\
755 SORTASCENDING(SortFilenameAscending, ptoFilename.GetFullName())
769 #undef SORTDESCENDING
772 #define SORTASCENDING(functionName, var) \
773 int wxCALLBACK functionName(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData)\
775 std::vector<PanoInfo>* data = (std::vector<PanoInfo>*)(sortData);\
776 return data->at(item1).var.CmpNoCase(data->at(item2).var);\
778 #define SORTDESCENDING(functionName, var) \
779 int wxCALLBACK functionName(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData)\
781 std::vector<PanoInfo>* data = (std::vector<PanoInfo>*)(sortData);\
782 return -(data->at(item1).var.CmpNoCase(data->at(item2).var));\
790 #undef SORTDESCENDING
793 int wxCALLBACK SortFieldOfViewAscending(wxIntPtr item1, wxIntPtr
item2, wxIntPtr sortData)
795 std::vector<PanoInfo>*
data = (std::vector<PanoInfo>*)(sortData);
796 const float fieldOfView1 = data->at(item1).options.getHFOV() * 1000 + data->at(item1).options.getVFOV();
797 const float fieldOfView2 = data->at(item2).options.getHFOV() * 1000 + data->at(item2).options.getVFOV();
803 std::vector<PanoInfo>* data = (std::vector<PanoInfo>*)(sortData);
804 const float fieldOfView1 = data->at(item1).options.getHFOV() * 1000 + data->at(item1).options.getVFOV();
805 const float fieldOfView2 = data->at(item2).options.getHFOV() * 1000 + data->at(item2).options.getVFOV();
812 std::vector<PanoInfo>* data = (std::vector<PanoInfo>*)(sortData);
813 if (data->at(item1).start.IsLaterThan(data->at(item2).start))
817 if (data->at(item1).start.IsEarlierThan(data->at(item2).start))
826 std::vector<PanoInfo>* data = (std::vector<PanoInfo>*)(sortData);
827 if (data->at(item1).start.IsEarlierThan(data->at(item2).start))
831 if (data->at(item1).start.IsLaterThan(data->at(item2).start))
841 std::vector<PanoInfo>* data = (std::vector<PanoInfo>*)(sortData);
842 if (data->at(item1).duration.IsLongerThan(data->at(item2).duration))
846 if (data->at(item1).duration.IsShorterThan(data->at(item2).duration))
855 std::vector<PanoInfo>* data = (std::vector<PanoInfo>*)(sortData);
856 if (data->at(item1).duration.IsShorterThan(data->at(item2).duration))
860 if (data->at(item1).duration.IsLongerThan(data->at(item2).duration))
993 bool deleteStoppedThread =
false;
1004 deleteStoppedThread =
true;
1008 if (deleteStoppedThread)
1026 wxThread::This()->Sleep(1);
1036 wxWindowDisabler disableAll;
1037 wxBusyInfo busyInfo(wxBusyInfoFlags().Icon(
MainFrame::Get()->GetIcon()).Label(wxString::Format(_(
"Generating preview for %s"),
m_ptoInfo[index].ptoFilename.GetFullName().c_str())));
1039 vigra::BRGBImage preview;
1041 vigra::ImageImportInfo::ICCProfile iccProfile;
1044 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
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 SetMyColumnImage(wxListCtrl *list, int col, int image)
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
wxString FormatDateTimeSpan(const wxTimeSpan timespan)
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
void UpdateImagesIndex()
update the image indexes
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