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
163 s << _(
"Number of active images:") <<
" " <<
nrActiveImages <<
"\n";
174 wxXmlResource::Get()->LoadDialog(
this, parent,
"browse_pto_dialog");
176 m_dirCtrl = XRCCTRL(*
this,
"browse_dirctrl", wxGenericDirCtrl);
178 m_listCtrl = XRCCTRL(*
this,
"browse_listctrl", wxListCtrl);
181 m_previewCtrl = XRCCTRL(*
this,
"browse_preview", wxStaticBitmap);
182 m_splitter1 = XRCCTRL(*
this,
"browse_splitter1", wxSplitterWindow);
183 m_splitter2 = XRCCTRL(*
this,
"browse_splitter2", wxSplitterWindow);
184 m_showMap = XRCCTRL(*
this,
"browse_show_map", wxButton);
185 m_labelControl = XRCCTRL(*
this,
"browse_statictext", wxStaticText);
188 m_listCtrl->SetWindowStyle(wxLC_REPORT | wxLC_AUTOARRANGE | wxLC_SINGLE_SEL | wxLC_HRULES | wxLC_VRULES);
191 m_listCtrl->InsertColumn(0, _(
"Filename"), wxLIST_FORMAT_LEFT, 300);
192 m_listCtrl->InsertColumn(1, _(
"# images"), wxLIST_FORMAT_RIGHT, 50);
193 m_listCtrl->InsertColumn(2, _(
"# active images"), wxLIST_FORMAT_RIGHT, 50);
194 m_listCtrl->InsertColumn(3, _(
"Projection"), wxLIST_FORMAT_LEFT, 200);
195 m_listCtrl->InsertColumn(4, _(
"Field of view"), wxLIST_FORMAT_LEFT, 100);
196 m_listCtrl->InsertColumn(5, _(
"Canvas size"), wxLIST_FORMAT_LEFT, 100);
197 m_listCtrl->InsertColumn(6, _(
"Model"), wxLIST_FORMAT_LEFT, 200);
198 m_listCtrl->InsertColumn(7, _(
"Lens"), wxLIST_FORMAT_LEFT, 250);
199 m_listCtrl->InsertColumn(8, _(
"Focal length"), wxLIST_FORMAT_LEFT, 150);
200 m_listCtrl->InsertColumn(9, _(
"Capture date"), wxLIST_FORMAT_LEFT, 150);
201 m_listCtrl->InsertColumn(10, _(
"Duration"), wxLIST_FORMAT_LEFT, 50);
202 m_listType = XRCCTRL(*
this,
"browse_list_type", wxChoice);
206 wxConfigBase* config = wxConfigBase::Get();
208 int splitter_pos = config->Read(
"/BrowsePTODialog/splitterPos1", -1l);
209 if (splitter_pos > 0)
213 splitter_pos = config->Read(
"/BrowsePTODialog/splitterPos2", -1l);
214 if (splitter_pos > 0)
219 for (
int j = 0; j <
m_listCtrl->GetColumnCount(); j++)
222 int width = config->Read(wxString::Format(
"/BrowsePTODialog/ColumnWidth%d", j), -1);
223 if (width != -1 && width > 5)
228 m_sortCol = config->Read(
"/BrowsePTODialog/SortColumn", -1);
229 m_sortAscending = config->Read(
"/BrowsePTODialog/SortAscending", 1) == 1 ?
true :
false;
236 if (!startDirectory.IsEmpty())
240 long listType = config->Read(
"/BrowsePTODialog/ListType", 0l);
242 wxCommandEvent event;
243 event.SetInt(listType);
257 wxConfigBase* config = wxConfigBase::Get();
258 config->Write(
"/BrowsePTODialog/splitterPos1",
m_splitter1->GetSashPosition());
259 config->Write(
"/BrowsePTODialog/splitterPos2",
m_splitter2->GetSashPosition());
261 for (
int j = 0; j <
m_listCtrl->GetColumnCount(); j++)
263 config->Write(wxString::Format(
"/BrowsePTODialog/ColumnWidth%d", j),
m_listCtrl->GetColumnWidth(j));
265 config->Write(
"/BrowsePTODialog/ListType",
m_listType->GetSelection());
266 config->Write(
"/BrowsePTODialog/SortColumn",
m_sortCol);
267 config->Write(
"/BrowsePTODialog/SortAscending",
m_sortAscending ? 1 : 0);
276 index =
m_listCtrl->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
278 if (index >= 0 && index <
m_ptoInfo.size())
284 return wxEmptyString;
322 pano_projection_features proj;
326 wxString str2(proj.name, wxConvLocal);
332 if (!activeImages.empty())
340 info.
camera = img0.getExifModel();
341 info.
lens = img0.getExifLens();
345 info.
focalLength35 = img0.getExifFocalLength() * img0.getCropFactor();
353 if (!img0.getExifDate().empty())
355 struct tm exifdatetime;
358 info.
start = wxDateTime(exifdatetime);
363 imgs.erase(imgs.begin());
364 for (
const auto& img : imgs)
372 memset(&exifdatetime, 0,
sizeof(exifdatetime));
373 if (!imgSrcImage.getExifDate().empty() && imgSrcImage.
getExifDateTime(&exifdatetime) == 0)
375 const wxDateTime dateTime = wxDateTime(exifdatetime);
376 if (info.
start.IsValid())
378 if (dateTime.IsEarlierThan(info.
start))
380 info.
start = dateTime;
382 if (dateTime.IsLaterThan(info.
end))
389 info.
start = dateTime;
394 if (info.
start.IsValid())
399 const auto& fileMetadata = img0.getFileMetadata();
400 const auto& latitude = fileMetadata.find(
"latitude");
401 const auto& longitude = fileMetadata.find(
"longitude");
402 if (latitude != fileMetadata.end())
406 if (longitude != fileMetadata.end())
429 if (info.
start.IsValid())
446 for (
size_t i = 0; i <
m_ptoInfo.size(); ++i)
460 wxWindowDisabler disableAll;
461 wxBusyInfo busy(wxBusyInfoFlags().Parent(
this).Icon(
MainFrame::Get()->GetIcon()).Label(wxString::Format(_(
"Reading directory %s"),
m_dirCtrl->GetPath().c_str())));
467 SetTitle(wxString::Format(_(
"Browse project files in %s"),
m_dirCtrl->GetPath().c_str()));
469 wxDir::GetAllFiles(
m_dirCtrl->GetPath(), &files,
"*.pto", wxDIR_FILES | wxDIR_HIDDEN | wxDIR_NO_FOLLOW);
473 for (
size_t i = 0; i < files.size(); ++i)
475 const wxFileName filename(files[i]);
500 if (e.GetIndex() >= 0)
516 const int newCol = e.GetColumn();
538 if (item != wxNOT_FOUND && (flags & wxLIST_HITTEST_ONITEM) && item <
m_ptoInfo.size())
553 const int index = e.GetInt();
556 for (
size_t i = 0; i <
m_listCtrl->GetItemCount(); ++i)
575 if (e.GetSelection() == 0)
586 UpdateItemTexts(wxLC_REPORT | wxLC_AUTOARRANGE | wxLC_SINGLE_SEL | wxLC_HRULES | wxLC_VRULES);
602 index =
m_listCtrl->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
604 if (index >= 0 && index <
m_ptoInfo.size())
608 const wxString openstreetMapLink =
"https://www.openstreetmap.org/?mlat=" + wxString::FromCDouble(
m_ptoInfo[index].GPSLatitude) +
"&mlon=" + wxString::FromCDouble(
m_ptoInfo[index].GPSLongitude);
609 wxLaunchDefaultBrowser(openstreetMapLink);
619 template <
class Type>
638 template <
class Type>
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 GreaterComparisonOperator(data->at(item1).var, 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 SmallerComparisonOperator(data->at(item1).var, data->at(item2).var);\
670 SORTASCENDING(SortFilenameAscending, ptoFilename.GetFullName())
684 #undef SORTDESCENDING
687 #define SORTASCENDING(functionName, var) \
688 int wxCALLBACK functionName(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData)\
690 std::vector<PanoInfo>* data = (std::vector<PanoInfo>*)(sortData);\
691 return data->at(item1).var.CmpNoCase(data->at(item2).var);\
693 #define SORTDESCENDING(functionName, var) \
694 int wxCALLBACK functionName(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData)\
696 std::vector<PanoInfo>* data = (std::vector<PanoInfo>*)(sortData);\
697 return -(data->at(item1).var.CmpNoCase(data->at(item2).var));\
705 #undef SORTDESCENDING
708 int wxCALLBACK SortFieldOfViewAscending(wxIntPtr item1, wxIntPtr
item2, wxIntPtr sortData)
710 std::vector<PanoInfo>*
data = (std::vector<PanoInfo>*)(sortData);
711 const float fieldOfView1 = data->at(item1).options.getHFOV() * 1000 + data->at(item1).options.getVFOV();
712 const float fieldOfView2 = data->at(item2).options.getHFOV() * 1000 + data->at(item2).options.getVFOV();
718 std::vector<PanoInfo>* data = (std::vector<PanoInfo>*)(sortData);
719 const float fieldOfView1 = data->at(item1).options.getHFOV() * 1000 + data->at(item1).options.getVFOV();
720 const float fieldOfView2 = data->at(item2).options.getHFOV() * 1000 + data->at(item2).options.getVFOV();
727 std::vector<PanoInfo>* data = (std::vector<PanoInfo>*)(sortData);
728 if (data->at(item1).start.IsLaterThan(data->at(item2).start))
732 if (data->at(item1).start.IsEarlierThan(data->at(item2).start))
741 std::vector<PanoInfo>* data = (std::vector<PanoInfo>*)(sortData);
742 if (data->at(item1).start.IsEarlierThan(data->at(item2).start))
746 if (data->at(item1).start.IsLaterThan(data->at(item2).start))
756 std::vector<PanoInfo>* data = (std::vector<PanoInfo>*)(sortData);
757 if (data->at(item1).duration.IsLongerThan(data->at(item2).duration))
761 if (data->at(item1).duration.IsShorterThan(data->at(item2).duration))
770 std::vector<PanoInfo>* data = (std::vector<PanoInfo>*)(sortData);
771 if (data->at(item1).duration.IsShorterThan(data->at(item2).duration))
775 if (data->at(item1).duration.IsLongerThan(data->at(item2).duration))
908 bool deleteStoppedThread =
false;
919 deleteStoppedThread =
true;
923 if (deleteStoppedThread)
941 wxThread::This()->Sleep(1);
951 wxWindowDisabler disableAll;
952 wxBusyInfo busyInfo(wxBusyInfoFlags().Parent(
this).Icon(
MainFrame::Get()->GetIcon()).Label(wxString::Format(_(
"Generating preview for %s"),
m_ptoInfo[index].ptoFilename.GetFullName().c_str())));
954 vigra::BRGBImage preview;
956 vigra::ImageImportInfo::ICCProfile iccProfile;
959 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.
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)
void RestoreFramePosition(wxTopLevelWindow *frame, const wxString &basename, const bool ignoreMaximize)
void StoreFramePosition(wxTopLevelWindow *frame, const wxString &basename, const bool ignoreMaximize)
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
WXIMPEX wxString GetFormattedTimeSpan(const wxTimeSpan &timeSpan)
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.
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 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
void OnListMouseMove(wxMouseEvent &e)
mouse move handler to update tooltips