Hugintrunk  0.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
BrowseDialog.cpp
Go to the documentation of this file.
1 // -*- c-basic-offset: 4 -*-
2 
11 /* This is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public
13  * License as published by the Free Software Foundation; either
14  * version 2 of the License, or (at your option) any later version.
15  *
16  * This software is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public
22  * License along with this software. If not, see
23  * <http://www.gnu.org/licenses/>.
24  *
25  */
26 
27 #include "hugin/BrowseDialog.h"
28 #include "hugin/huginApp.h"
29 #include "wx/dir.h"
30 #include "wx/busyinfo.h"
32 #include "hugin/MainFrame.h"
33 #include "base_wx/wxcms.h"
34 #include "base_wx/LensTools.h"
35 #include "base_wx/platform.h"
36 
37 wxDECLARE_EVENT(wxEVT_COMMAND_THUMBNAILTHREAD_UPDATE, wxCommandEvent);
38 wxDEFINE_EVENT(wxEVT_COMMAND_THUMBNAILTHREAD_UPDATE, wxCommandEvent);
39 
41 class ThreadImage : public wxObject
42 {
43 public:
44  // explicit disable default contructor
45  ThreadImage() = delete;
46  // construct wxImage with given vigra image classes
47  ThreadImage(vigra::BRGBImage* thumbnail, vigra::BImage* mask)
48  {
49  // save pointer to raw image data for cleanup in destructor
50  m_preview = thumbnail;
51  m_mask = mask;
52  // construct wxImage, we keep track of the raw data
53  m_image=new wxImage(m_preview->width(), m_preview->height(), (unsigned char*)m_preview->data(), (unsigned char*)m_mask->data(), true);
54  }
55  // clean up
57  {
58  delete m_image;
59  delete m_preview;
60  delete m_mask;
61  }
62  // return pointer to wxImage
63  wxImage* GetwxImage() const { return m_image; }
64 private:
65  wxImage* m_image;
66  vigra::BRGBImage* m_preview;
67  vigra::BImage* m_mask;
68 };
69 
71 class ThumbnailThread : public wxThread
72 {
73 public:
74  ThumbnailThread(BrowsePTOFilesDialog* parentDialog, const wxArrayString& fileList, const wxSize size)
75  : wxThread(wxTHREAD_DETACHED)
76  {
77  m_parentDialog = parentDialog;
78  m_files = fileList;
79  m_thumbnailSize = size;
80  }
82  {
83  wxCriticalSectionLocker enter(m_parentDialog->m_ThreadCS);
84  // the thread is being destroyed; make sure not to leave dangling pointers around
86  }
87 
88 protected:
89  // main worker thread
90  virtual ExitCode Entry()
91  {
92  for (int i = 0; i < m_files.size(); ++i)
93  {
94  // generate thumbnail
95  vigra::BRGBImage* preview=new vigra::BRGBImage();
96  vigra::BImage* mask = new vigra::BImage();
97  vigra::ImageImportInfo::ICCProfile iccProfile;
98  if (!GenerateThumbnail(m_files[i].ToStdString(), m_thumbnailSize, *preview, *mask, iccProfile))
99  {
100  // generation of thumbnail failed, skip file
101  delete preview;
102  delete mask;
103  continue;
104  };
105  if (TestDestroy())
106  {
107  break;
108  };
109  // fit generated thumbnail into the full thumbnail rectangle
110  if (m_thumbnailSize.GetWidth() != preview->size().width() || m_thumbnailSize.GetHeight() != preview->size().height())
111  {
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);
115  vigra::copyImage(vigra::srcImageRange(*preview), vigra::destImage(*scaledPreview, offset));
116  vigra::copyImage(vigra::srcImageRange(*mask), vigra::destImage(*scaledMask, offset));
117  delete preview;
118  delete mask;
119  preview = scaledPreview;
120  mask = scaledMask;
121  }
122  // convert vigra image to wxImage
123  ThreadImage* thumbnailImageData = new ThreadImage(preview, mask);
124  // notify dialog about new available thumbnail
125  wxCommandEvent* event = new wxCommandEvent(wxEVT_COMMAND_THUMBNAILTHREAD_UPDATE);
126  event->SetInt(i);
127  event->SetEventObject(thumbnailImageData);
128  // check if we need to cancel
129  if (TestDestroy())
130  {
131  // we are destroying the thread
132  // clean up all unneeded pointer
133  delete event;
134  delete thumbnailImageData;
135  break;
136  }
137  else
138  {
139  // all ok, notify dialog to update its image list
140  wxQueueEvent(m_parentDialog, event);
141  };
142  };
143  return (wxThread::ExitCode)0;
144  }
145 
147  wxArrayString m_files;
149 };
150 
151 #define THUMBNAIL_SIZE 128
152 
153 #if !wxCHECK_VERSION(3,1,6)
154 // helper function to set image in header
155 void SetMyColumnImage(wxListCtrl* list, int col, int image)
156 {
157  wxListItem item;
158  item.SetMask(wxLIST_MASK_IMAGE);
159  item.SetImage(image);
160  list->SetColumn(col, item);
161 }
162 #endif
163 
164 BEGIN_EVENT_TABLE(BrowsePTOFilesDialog, wxDialog)
165  EVT_BUTTON(wxID_OK, BrowsePTOFilesDialog::OnOk)
166  EVT_BUTTON(XRCID("browse_show_map"), BrowsePTOFilesDialog::OnShowOnMap)
167  EVT_DIRCTRL_SELECTIONCHANGED(XRCID("browse_dirctrl"), BrowsePTOFilesDialog::OnDirectoryChanged)
168  EVT_LIST_ITEM_SELECTED(XRCID("browse_listctrl"), BrowsePTOFilesDialog::OnFileChanged)
169  EVT_LIST_COL_CLICK(XRCID("browse_listctrl"), BrowsePTOFilesDialog::OnListColClick)
170  EVT_COMMAND(wxID_ANY, wxEVT_COMMAND_THUMBNAILTHREAD_UPDATE, BrowsePTOFilesDialog::OnThumbnailUpdate)
171  EVT_CHOICE(XRCID("browse_list_type"), BrowsePTOFilesDialog::OnListTypeChanged)
173 
174 BrowsePTOFilesDialog::BrowsePTOFilesDialog(wxWindow *parent, const wxString startDirectory)
175 {
176  // load our children. some children might need special
177  // initialization. this will be done later.
178  wxXmlResource::Get()->LoadDialog(this, parent, "browse_pto_dialog");
179 
180 #ifdef __WXMSW__
181  wxIconBundle myIcons(huginApp::Get()->GetXRCPath() + wxT("data/hugin.ico"),wxBITMAP_TYPE_ICO);
182  SetIcons(myIcons);
183 #else
184  wxIcon myIcon(huginApp::Get()->GetXRCPath() + wxT("data/hugin.png"),wxBITMAP_TYPE_PNG);
185  SetIcon(myIcon);
186 #endif
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());
195  m_thumbnails.Create(THUMBNAIL_SIZE, THUMBNAIL_SIZE, true, 0);
196  m_listCtrl->SetWindowStyle(wxLC_REPORT | wxLC_AUTOARRANGE | wxLC_SINGLE_SEL | wxLC_HRULES | wxLC_VRULES);
197  m_listCtrl->SetImageList(&m_thumbnails, wxIMAGE_LIST_NORMAL);
198  m_listCtrl->Bind(wxEVT_LEFT_DCLICK, &BrowsePTOFilesDialog::OnDblClickListCtrl, this);
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);
211  // restore some settings
212  RestoreFramePosition(this, "BrowsePTODialog");
213  wxConfigBase* config = wxConfigBase::Get();
214  //splitter position
215  int splitter_pos = config->Read("/BrowsePTODialog/splitterPos1", -1l);
216  if (splitter_pos > 0)
217  {
218  m_splitter1->SetSashPosition(splitter_pos);
219  };
220  splitter_pos = config->Read("/BrowsePTODialog/splitterPos2", -1l);
221  if (splitter_pos > 0)
222  {
223  m_splitter2->SetSashPosition(splitter_pos);
224  };
225  //get saved width
226  for (int j = 0; j < m_listCtrl->GetColumnCount(); j++)
227  {
228  // -1 is auto
229  int width = config->Read(wxString::Format("/BrowsePTODialog/ColumnWidth%d", j), -1);
230  if (width != -1 && width > 5)
231  {
232  m_listCtrl->SetColumnWidth(j, width);
233  };
234  };
235  m_sortCol = config->Read("/BrowsePTODialog/SortColumn", -1);
236  m_sortAscending = config->Read("/BrowsePTODialog/SortAscending", 1) == 1 ? true : false;
237  if (m_sortCol != -1)
238  {
239 #if wxCHECK_VERSION(3,1,6)
240  m_listCtrl->ShowSortIndicator(m_sortCol, m_sortAscending);
241 #else
242  SetMyColumnImage(m_listCtrl, m_sortCol, m_sortAscending ? 0 : 1);
243 #endif
244  };
245 
246 #if !wxCHECK_VERSION(3,1,6)
247  // creating bitmaps for indicating sorting order
248  wxMemoryDC memDC;
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);
253  {
254  wxBitmap bmp(charSize, charSize);
255  wxMemoryDC dc(bmp);
256  dc.SetBackgroundMode(wxPENSTYLE_TRANSPARENT);
257  dc.SetBackground(GetBackgroundColour());
258  dc.Clear();
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());
263  };
264  {
265  wxBitmap bmp(charSize, charSize);
266  wxMemoryDC dc(bmp);
267  dc.SetBackgroundMode(wxPENSTYLE_TRANSPARENT);
268  dc.SetBackground(GetBackgroundColour());
269  dc.Clear();
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());
274  };
275  m_listCtrl->AssignImageList(sortIcons, wxIMAGE_LIST_SMALL);
276 #endif
277 
278  // fill values for start directory
279  if (!startDirectory.IsEmpty())
280  {
281  m_dirCtrl->SetPath(startDirectory);
282  };
283  long listType = config->Read("/BrowsePTODialog/ListType", 0l);
284  m_listType->SetSelection(listType);
285  wxCommandEvent event;
286  event.SetInt(listType);
287  OnListTypeChanged(event);
288 };
289 
291 {
292  // stop working thread
294  // save some settings
295  StoreFramePosition(this, "BrowsePTODialog");
296  wxConfigBase* config = wxConfigBase::Get();
297  config->Write("/BrowsePTODialog/splitterPos1", m_splitter1->GetSashPosition());
298  config->Write("/BrowsePTODialog/splitterPos2", m_splitter2->GetSashPosition());
299  // save width of all columns in wxListCtrl
300  for (int j = 0; j < m_listCtrl->GetColumnCount(); j++)
301  {
302  config->Write(wxString::Format("/BrowsePTODialog/ColumnWidth%d", j), m_listCtrl->GetColumnWidth(j));
303  };
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);
307  config->Flush();
308 }
309 
311 {
312  long index = -1;
313  if (m_listCtrl->GetSelectedItemCount() == 1)
314  {
315  index = m_listCtrl->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
316  };
317  if (index >= 0 && index < m_ptoInfo.size())
318  {
319  return m_ptoInfo[TranslateIndex(index)].ptoFilename.GetFullPath();
320  }
321  else
322  {
323  return wxEmptyString;
324  };
325 }
326 
328 {
329  return m_dirCtrl->GetPath();
330 }
331 
332 void BrowsePTOFilesDialog::OnOk(wxCommandEvent& e)
333 {
334  if (m_listCtrl->GetSelectedItemCount() == 1)
335  {
336  EndModal(wxID_OK);
337  }
338  else
339  {
340  wxBell();
341  }
342 }
343 
345 {
346  PanoInfo info;
347  info.ptoFilename = file;
348  // read pto file
349  HuginBase::Panorama pano;
350  const std::string input(file.GetFullPath().mb_str(HUGIN_CONV_FILENAME));
351  if (!pano.ReadPTOFile(input, hugin_utils::getPathPrefix(input)))
352  {
353  return info;
354  };
355  // fill class to store some information about the pano
356  info.nrImages = pano.getNrOfImages();
357  info.nrActiveImages = pano.getActiveImages().size();
358  info.options = pano.getOptions();
359  // translate projection name
360  {
361  pano_projection_features proj;
362  wxString s;
363  if (panoProjectionFeaturesQuery(info.options.getProjection(), &proj))
364  {
365  wxString str2(proj.name, wxConvLocal);
366  info.projectionName = wxGetTranslation(str2);
367  };
368  };
369  // read some EXIF data
370  const HuginBase::UIntSet activeImages = pano.getActiveImages();
371  if (!activeImages.empty())
372  {
373  HuginBase::SrcPanoImage img0 = pano.getSrcImage(*activeImages.begin());
374  if(!hugin_utils::FileExists(img0.getFilename()))
375  {
376  return info;
377  }
378  img0.readEXIF();
379  info.camera = img0.getExifModel();
380  info.lens = img0.getExifLens();
381  info.focalLength35 = img0.getExifFocalLength35();
382  if (info.focalLength35 < 0.01 && img0.getCropFactor()>0)
383  {
384  info.focalLength35 = img0.getExifFocalLength() * img0.getCropFactor();
385  };
386  if (info.focalLength35 < 0.01)
387  {
388  info.focalLength35 = HuginBase::SrcPanoImage::calcFocalLength(img0.getProjection(), img0.getHFOV(), 1.0, img0.getSize());
389  };
391  // read date/time of all active images
392  if (!img0.getExifDate().empty())
393  {
394  struct tm exifdatetime;
395  if (img0.getExifDateTime(&exifdatetime) == 0)
396  {
397  info.start = wxDateTime(exifdatetime);
398  info.end = info.start;
399  };
400  // iterate all images, except the first one, this image is already handled before
401  HuginBase::UIntSet imgs(activeImages);
402  imgs.erase(imgs.begin());
403  for (const auto& img : imgs)
404  {
405  HuginBase::SrcPanoImage imgSrcImage = pano.getSrcImage(img);
406  if (!hugin_utils::FileExists(imgSrcImage.getFilename()))
407  {
408  continue;
409  };
410  imgSrcImage.readEXIF();
411  memset(&exifdatetime, 0, sizeof(exifdatetime));
412  if (!imgSrcImage.getExifDate().empty() && imgSrcImage.getExifDateTime(&exifdatetime) == 0)
413  {
414  const wxDateTime dateTime = wxDateTime(exifdatetime);
415  if (info.start.IsValid())
416  {
417  if (dateTime.IsEarlierThan(info.start))
418  {
419  info.start = dateTime;
420  }
421  if (dateTime.IsLaterThan(info.end))
422  {
423  info.end = dateTime;
424  }
425  }
426  else
427  {
428  info.start = dateTime;
429  info.end = dateTime;
430  }
431  }
432  }
433  if (info.start.IsValid())
434  {
435  info.duration = info.end.Subtract(info.start);
436  }
437  };
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())
442  {
443  hugin_utils::stringToDouble(latitude->second, info.GPSLatitude);
444  };
445  if (longitude != fileMetadata.end())
446  {
447  hugin_utils::stringToDouble(longitude->second, info.GPSLongitude);
448  };
449  };
450  return info;
451 }
452 
453 wxString FormatDateTimeSpan(const wxTimeSpan timespan)
454 {
455  if (timespan.GetSeconds() > 60)
456  {
457  return timespan.Format(_("%M:%S min"));
458  }
459  else
460  {
461  if (timespan.GetSeconds() < 1)
462  {
463  return wxEmptyString;
464  }
465  else
466  {
467  return timespan.Format(_("%S s"));
468  };
469  };
470 }
471 
473 {
474 #ifndef __WXMSW__
475  // in generic implementation we can add text to column only in report view
476  if (m_listCtrl->InReportView())
477 #endif
478  {
479  m_listCtrl->SetItem(index, 1, wxString::Format("%zu", info.nrImages));
480  m_listCtrl->SetItem(index, 2, wxString::Format("%zu", info.nrActiveImages));
481  m_listCtrl->SetItem(index, 3, info.projectionName);
482  m_listCtrl->SetItem(index, 4, wxString::Format("%.0f x %.0f", info.options.getHFOV(), info.options.getVFOV()));
483  m_listCtrl->SetItem(index, 5, wxString::Format("%u x %u", info.options.getWidth(), info.options.getHeight()));
484  m_listCtrl->SetItem(index, 6, info.camera);
485  m_listCtrl->SetItem(index, 7, info.lens);
486  m_listCtrl->SetItem(index, 8, info.focalLengthString);
487  if (info.start.IsValid())
488  {
489  m_listCtrl->SetItem(index, 9, info.start.Format());
490  };
491  m_listCtrl->SetItem(index, 10, FormatDateTimeSpan(info.duration));
492  };
493 }
494 
496 {
497 #ifndef __WXMSW__
498  m_listCtrl->DeleteAllItems();
499 #endif
500  m_listCtrl->SetWindowStyle(newStyle);
501 #ifndef __WXMSW__
502  // changing the window style does invalidate the items, so we delete all items
503  // and add then again
504  for (size_t i = 0; i < m_ptoInfo.size(); ++i)
505  {
506  m_listCtrl->InsertItem(i, m_ptoInfo[i].ptoFilename.GetFullName(), -1);
507  m_listCtrl->SetItemData(i, i);
508  FillPanoInfo(m_ptoInfo[i], i);
509  };
510  SortItems();
511 #endif
512 }
513 
514 #if !wxCHECK_VERSION(3,1,6)
516 {
517  if (m_listCtrl->InReportView())
518  {
519  for (size_t i = 0; i < m_listCtrl->GetItemCount(); ++i)
520  {
521  // don't show images in report view
522  m_listCtrl->SetItemImage(i, -1);
523  };
524  }
525  else
526  {
527  // update image index only in icon view
528  for (size_t i = 0; i < m_listCtrl->GetItemCount(); ++i)
529  {
530  m_listCtrl->SetItemImage(i, m_ptoInfo[TranslateIndex(i)].imageIndex);
531  };
532  };
533 }
534 #endif
535 
537 {
538  if (m_dirCtrl && m_listCtrl)
539  {
540  wxWindowDisabler disableAll;
541  wxBusyInfo busy(wxBusyInfoFlags().Icon(MainFrame::Get()->GetIcon()).Label(wxString::Format(_("Reading directory %s"), m_dirCtrl->GetPath().c_str())));
542  // stop running thumbnail thread from last directory if not finished yet
544  // find all pto files in directory
545  m_ptoInfo.clear();
546  m_thumbnails.RemoveAll();
547  SetTitle(wxString::Format(_("Browse project files in %s"), m_dirCtrl->GetPath().c_str()));
548  wxArrayString files;
549  wxDir::GetAllFiles(m_dirCtrl->GetPath(), &files, "*.pto", wxDIR_FILES | wxDIR_HIDDEN | wxDIR_NO_FOLLOW);
550  // add to wxListCtrl
551  m_listCtrl->DeleteAllItems();
552  m_ptoInfo.resize(files.size());
553  for (size_t i = 0; i < files.size(); ++i)
554  {
555  const wxFileName filename(files[i]);
556  m_ptoInfo[i] = ParsePTOFile(filename);
557  m_listCtrl->InsertItem(i, m_ptoInfo[i].ptoFilename.GetFullName(), -1);
558  m_listCtrl->SetItemData(i, i);
559  FillPanoInfo(m_ptoInfo[i], i);
560  };
561  SortItems();
562  // start background thread for creating all thumbnails
563  m_thumbnailThread = new ThumbnailThread(this, files, m_thumbnails.GetSize());
564  if (!m_listCtrl->InReportView())
565  {
566  m_thumbnailThread->Run();
567  };
568  // clear preview area
569  m_previewCtrl->SetBitmap(wxBitmap());
570  m_previewCtrl->Show(true);
571  m_labelControl->Show(false);
572  m_showMap->Show(false);
573  m_showMap->Enable(false);
574  m_showMap->GetParent()->Layout();
575  };
576 }
577 
579 {
580  if (e.GetIndex() >= 0)
581  {
582  GeneratePreview(TranslateIndex(e.GetIndex()));
583  };
584 }
585 
587 {
588  if (m_listCtrl->GetSelectedItemCount() == 1)
589  {
590  EndModal(wxID_OK);
591  };
592 }
593 
595 {
596  const int newCol = e.GetColumn();
597 #if wxCHECK_VERSION(3,1,6)
598  if (m_sortCol == newCol)
599  {
601  }
602  else
603  {
604  m_sortCol = newCol;
605  m_sortAscending = true;
606  };
607  m_listCtrl->ShowSortIndicator(m_sortCol, m_sortAscending);
608 #else
609  if (m_sortCol == newCol)
610  {
613  }
614  else
615  {
616  if (m_sortCol != -1)
617  {
619  };
620  m_sortCol = newCol;
622  m_sortAscending = true;
623  };
624 #endif
625  SortItems();
626  Refresh();
627 }
628 
630 {
631  // we have created a new thumbnail, make the wxListCtrl aware of it
632  const int index = e.GetInt();
633  ThreadImage* thumbnail= wxDynamicCast(e.GetEventObject(), ThreadImage);
634  m_ptoInfo[index].imageIndex = m_thumbnails.Add(*(thumbnail->GetwxImage()));
635 #if wxCHECK_VERSION(3,1,6)
636  for (size_t i = 0; i < m_listCtrl->GetItemCount(); ++i)
637  {
638  if (m_listCtrl->GetItemData(i) == index)
639  {
640  m_listCtrl->SetItemImage(i, m_ptoInfo[index].imageIndex);
641  break;
642  };
643  };
644 #else
646 #endif
647  delete thumbnail;
648 #ifndef __WXMSW__
649  // a simple Refresh for repainting the control is not working
650  // all thumbnails are drawn on top of each other
651  // only when all done after a size event all is drawn correctly
652  m_listCtrl->SendSizeEvent();
653 #endif
654 }
655 
657 {
658  if (e.GetSelection() == 0)
659  {
660  UpdateItemTexts(wxLC_ICON | wxLC_AUTOARRANGE | wxLC_SINGLE_SEL);
661  // start creating thumbnail images in background thread
662  if (m_thumbnailThread && !m_thumbnailThread->IsRunning())
663  {
664  m_thumbnailThread->Run();
665  };
666  }
667  else
668  {
669  UpdateItemTexts(wxLC_REPORT | wxLC_AUTOARRANGE | wxLC_SINGLE_SEL | wxLC_HRULES | wxLC_VRULES);
670  };
671 #if !wxCHECK_VERSION(3,1,6)
673 #endif
674 #ifndef __WXMSW__
675  // a simple Refresh for repainting the control is not working
676  // all thumbnails are drawn on top of each other
677  // only when all done after a size event all is drawn correctly
678  m_listCtrl->SendSizeEvent();
679 #endif
680 }
681 
682 void BrowsePTOFilesDialog::OnShowOnMap(wxCommandEvent& e)
683 {
684  long index = -1;
685  if (m_listCtrl->GetSelectedItemCount() == 1)
686  {
687  index = m_listCtrl->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
688  };
689  if (index >= 0 && index < m_ptoInfo.size())
690  {
691  if (m_ptoInfo[index].HasGPS())
692  {
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);
695  }
696  }
697 }
698 
700 {
701  return m_listCtrl->GetItemData(index);
702 }
703 
704 template <class Type>
705 int GreaterComparisonOperator(const Type& a, const Type& b)
706 {
707  if (a > b)
708  {
709  return 1;
710  }
711  else
712  {
713  if (a < b)
714  {
715  return -1;
716  }
717  else {
718  return 0;
719  };
720  }
721 }
722 
723 template <class Type>
724 int SmallerComparisonOperator(const Type& a, const Type& b)
725 {
726  if (a < b)
727  {
728  return 1;
729  }
730  else
731  {
732  if (a > b)
733  {
734  return -1;
735  }
736  else {
737  return 0;
738  };
739  }
740 }
741 
742 #define SORTASCENDING(functionName, var) \
743 int wxCALLBACK functionName(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData)\
744 {\
745  std::vector<PanoInfo>* data = (std::vector<PanoInfo>*)(sortData);\
746  return GreaterComparisonOperator(data->at(item1).var, data->at(item2).var);\
747 }
748 #define SORTDESCENDING(functionName, var) \
749 int wxCALLBACK functionName(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData)\
750 {\
751  std::vector<PanoInfo>* data = (std::vector<PanoInfo>*)(sortData);\
752  return SmallerComparisonOperator(data->at(item1).var, data->at(item2).var);\
753 }
754 
755 SORTASCENDING(SortFilenameAscending, ptoFilename.GetFullName())
756 SORTDESCENDING(SortFilenameDescending, ptoFilename.GetFullName())
757 SORTASCENDING(SortNrImagesAscending, nrImages)
758 SORTDESCENDING(SortNrImagesDescending, nrImages)
759 SORTASCENDING(SortNrActiveImagesAscending, nrActiveImages)
760 SORTDESCENDING(SortNrActiveImagesDescending, nrActiveImages)
761 SORTASCENDING(SortProjectionAscending, projectionName)
762 SORTDESCENDING(SortProjectionDescending, projectionName)
763 SORTASCENDING(SortCanvasSizeAcending, options.getSize().area())
764 SORTDESCENDING(SortCanvasSizeDescending, options.getSize().area())
765 SORTASCENDING(SortFocalLengthAscending, focalLength35)
766 SORTDESCENDING(SortFocalLengthDescending, focalLength35)
767 
768 #undef SORTASCENDING
769 #undef SORTDESCENDING
770 
771 // special variant for wxStrings
772 #define SORTASCENDING(functionName, var) \
773 int wxCALLBACK functionName(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData)\
774 {\
775  std::vector<PanoInfo>* data = (std::vector<PanoInfo>*)(sortData);\
776  return data->at(item1).var.CmpNoCase(data->at(item2).var);\
777 }
778 #define SORTDESCENDING(functionName, var) \
779 int wxCALLBACK functionName(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData)\
780 {\
781  std::vector<PanoInfo>* data = (std::vector<PanoInfo>*)(sortData);\
782  return -(data->at(item1).var.CmpNoCase(data->at(item2).var));\
783 }
784 SORTASCENDING(SortCameraAscending, camera)
785 SORTDESCENDING(SortCameraDescending, camera)
786 SORTASCENDING(SortLensAscending, lens)
787 SORTDESCENDING(SortLensDescending, lens)
788 
789 #undef SORTASCENDING
790 #undef SORTDESCENDING
791 
792 // sort by field of view
793 int wxCALLBACK SortFieldOfViewAscending(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData)
794 {
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();
798  return GreaterComparisonOperator(fieldOfView1, fieldOfView2);
799 }
800 
801 int wxCALLBACK SortFieldOfViewDescending(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData)
802 {
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();
806  return SmallerComparisonOperator(fieldOfView1, fieldOfView2);
807 }
808 
809 // sort by date
810 int wxCALLBACK SortDateAscending(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData)
811 {
812  std::vector<PanoInfo>* data = (std::vector<PanoInfo>*)(sortData);
813  if (data->at(item1).start.IsLaterThan(data->at(item2).start))
814  {
815  return 1;
816  }
817  if (data->at(item1).start.IsEarlierThan(data->at(item2).start))
818  {
819  return -1;
820  }
821  return 0;
822 };
823 
824 int wxCALLBACK SortDateDesending(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData)
825 {
826  std::vector<PanoInfo>* data = (std::vector<PanoInfo>*)(sortData);
827  if (data->at(item1).start.IsEarlierThan(data->at(item2).start))
828  {
829  return 1;
830  }
831  if (data->at(item1).start.IsLaterThan(data->at(item2).start))
832  {
833  return -1;
834  }
835  return 0;
836 };
837 
838 // sort by duration
839 int wxCALLBACK SortDurationAscending(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData)
840 {
841  std::vector<PanoInfo>* data = (std::vector<PanoInfo>*)(sortData);
842  if (data->at(item1).duration.IsLongerThan(data->at(item2).duration))
843  {
844  return 1;
845  }
846  if (data->at(item1).duration.IsShorterThan(data->at(item2).duration))
847  {
848  return -1;
849  }
850  return 0;
851 };
852 
853 int wxCALLBACK SortDurationDesending(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData)
854 {
855  std::vector<PanoInfo>* data = (std::vector<PanoInfo>*)(sortData);
856  if (data->at(item1).duration.IsShorterThan(data->at(item2).duration))
857  {
858  return 1;
859  }
860  if (data->at(item1).duration.IsLongerThan(data->at(item2).duration))
861  {
862  return -1;
863  }
864  return 0;
865 };
866 
868 {
869  if (m_sortCol > -1)
870  {
871  switch (m_sortCol)
872  {
873  default:
874  case 0: // filename
875  if (m_sortAscending)
876  {
877  m_listCtrl->SortItems(SortFilenameAscending, wxIntPtr(&m_ptoInfo));
878  }
879  else
880  {
881  m_listCtrl->SortItems(SortFilenameDescending, wxIntPtr(&m_ptoInfo));
882  };
883  break;
884  case 1: // number of images
885  if (m_sortAscending)
886  {
887  m_listCtrl->SortItems(SortNrImagesAscending, wxIntPtr(&m_ptoInfo));
888  }
889  else
890  {
891  m_listCtrl->SortItems(SortNrImagesDescending, wxIntPtr(&m_ptoInfo));
892  };
893  break;
894  case 2: // number of active images
895  if (m_sortAscending)
896  {
897  m_listCtrl->SortItems(SortNrActiveImagesAscending, wxIntPtr(&m_ptoInfo));
898  }
899  else
900  {
901  m_listCtrl->SortItems(SortNrActiveImagesDescending, wxIntPtr(&m_ptoInfo));
902  };
903  break;
904  case 3: // projection
905  if (m_sortAscending)
906  {
907  m_listCtrl->SortItems(SortProjectionAscending, wxIntPtr(&m_ptoInfo));
908  }
909  else
910  {
911  m_listCtrl->SortItems(SortProjectionDescending, wxIntPtr(&m_ptoInfo));
912  };
913  break;
914  case 4: // field of view
915  if (m_sortAscending)
916  {
917  m_listCtrl->SortItems(SortFieldOfViewAscending, wxIntPtr(&m_ptoInfo));
918  }
919  else
920  {
921  m_listCtrl->SortItems(SortFieldOfViewDescending, wxIntPtr(&m_ptoInfo));
922  };
923  break;
924  case 5: // canvas size
925  if (m_sortAscending)
926  {
927  m_listCtrl->SortItems(SortCanvasSizeAcending, wxIntPtr(&m_ptoInfo));
928  }
929  else
930  {
931  m_listCtrl->SortItems(SortCanvasSizeDescending, wxIntPtr(&m_ptoInfo));
932  };
933  break;
934  case 6: // model
935  if (m_sortAscending)
936  {
937  m_listCtrl->SortItems(SortCameraAscending, wxIntPtr(&m_ptoInfo));
938  }
939  else
940  {
941  m_listCtrl->SortItems(SortCameraDescending, wxIntPtr(&m_ptoInfo));
942  };
943  break;
944  case 7: // lens
945  if (m_sortAscending)
946  {
947  m_listCtrl->SortItems(SortLensAscending, wxIntPtr(&m_ptoInfo));
948  }
949  else
950  {
951  m_listCtrl->SortItems(SortLensDescending, wxIntPtr(&m_ptoInfo));
952  };
953  break;
954  case 8: // focal length
955  if (m_sortAscending)
956  {
957  m_listCtrl->SortItems(SortFocalLengthAscending, wxIntPtr(&m_ptoInfo));
958  }
959  else
960  {
961  m_listCtrl->SortItems(SortFocalLengthDescending, wxIntPtr(&m_ptoInfo));
962  };
963  break;
964  case 9: // capture date
965  if (m_sortAscending)
966  {
967  m_listCtrl->SortItems(SortDateAscending, wxIntPtr(&m_ptoInfo));
968  }
969  else
970  {
971  m_listCtrl->SortItems(SortDateDesending, wxIntPtr(&m_ptoInfo));
972  };
973  break;
974  case 10: // duration
975  if (m_sortAscending)
976  {
977  m_listCtrl->SortItems(SortDurationAscending, wxIntPtr(&m_ptoInfo));
978  }
979  else
980  {
981  m_listCtrl->SortItems(SortDurationDesending, wxIntPtr(&m_ptoInfo));
982  };
983  break;
984  };
985  };
986 };
987 
989 {
990  // delete running background thread
991  wxBusyCursor busy;
992  {
993  bool deleteStoppedThread = false;
994  {
995  wxCriticalSectionLocker enter(m_ThreadCS);
996  if (m_thumbnailThread)
997  {
998  if (m_thumbnailThread->IsRunning())
999  {
1000  m_thumbnailThread->Delete();
1001  }
1002  else
1003  {
1004  deleteStoppedThread = true;
1005  };
1006  };
1007  };
1008  if (deleteStoppedThread)
1009  {
1010  delete m_thumbnailThread;
1011  };
1012  };
1013  // exit from the critical section to give the thread
1014  // the possibility to enter its destructor
1015  // (which is guarded with m_ThreadCS critical section!)
1016  while (1)
1017  {
1018  {
1019  wxCriticalSectionLocker enter(m_ThreadCS);
1020  if (!m_thumbnailThread)
1021  {
1022  break;
1023  };
1024  };
1025  // wait for thread completion
1026  wxThread::This()->Sleep(1);
1027  };
1028 }
1029 
1031 {
1032  if (index<0 || index>m_ptoInfo.size())
1033  {
1034  return;
1035  };
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())));
1038  wxSize previewSize = m_previewCtrl->GetParent()->GetSize();
1039  vigra::BRGBImage preview;
1040  vigra::BImage mask;
1041  vigra::ImageImportInfo::ICCProfile iccProfile;
1042  if (GenerateThumbnail(m_ptoInfo[index].ptoFilename.GetFullPath().ToStdString(), previewSize, preview, mask, iccProfile))
1043  {
1044  wxImage image(preview.width(), preview.height(), (unsigned char*)preview.data(), (unsigned char*)mask.data(), true);
1045  // now apply color profile
1046  if (!iccProfile.empty() || huginApp::Get()->HasMonitorProfile())
1047  {
1049  };
1050  // now show in GUI
1051  m_previewCtrl->SetBitmap(image);
1052  m_previewCtrl->Show(true);
1053  m_labelControl->Show(false);
1054  m_showMap->Show(m_ptoInfo[index].HasGPS());
1055  m_showMap->Enable(m_ptoInfo[index].HasGPS());
1056  m_showMap->GetParent()->Layout();
1057  }
1058  else
1059  {
1060  // could not create preview, disable control and show error message
1061  m_previewCtrl->Show(false);
1062  m_labelControl->Show(true);
1063  m_showMap->Show(false);
1064  m_showMap->Enable(false);
1065  m_showMap->GetParent()->Layout();
1066  };
1067  Update();
1068 }
wxDEFINE_EVENT(EVT_QUEUE_PROGRESS, wxCommandEvent)
~BrowsePTOFilesDialog()
destructor, saves position
PanoramaOptions::ProjectionFormat getProjection() const
implementation of huginApp Class
generate thumbnail from given pto file
bool FileExists(const std::string &filename)
checks if file exists
Definition: utils.cpp:362
const float fieldOfView1
wxListCtrl * m_listCtrl
Definition: BrowseDialog.h:124
int SmallerComparisonOperator(const Type &a, const Type &b)
SrcPanoImage getSrcImage(unsigned imgNr) const
get a description of a source image
Definition: Panorama.cpp:1620
size_t nrActiveImages
Definition: BrowseDialog.h:53
#define THUMBNAIL_SIZE
#define HUGIN_CONV_FILENAME
Definition: platform.h:40
virtual ExitCode Entry()
unsigned int getHeight() const
get panorama height
some helper classes for graphes
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)
double focalLength35
Definition: BrowseDialog.h:60
END_EVENT_TABLE()
void OnFileChanged(wxListEvent &e)
new file selected, generate preview for new file
friend class ThumbnailThread
Definition: BrowseDialog.h:142
wxString projectionName
Definition: BrowseDialog.h:55
void SetMyColumnImage(wxListCtrl *list, int col, int image)
double GPSLongitude
Definition: BrowseDialog.h:63
void OnThumbnailUpdate(wxCommandEvent &e)
for notifing from ThumbnailThread about new generated thumbnail generated thumbnail is transfered in ...
wxString lens
Definition: BrowseDialog.h:59
wxDateTime end
Definition: BrowseDialog.h:56
void GetMonitorProfile(wxString &profileName, cmsHPROFILE &profile)
Definition: wxcms.cpp:195
wxImage * GetwxImage() const
static huginApp * Get()
hack.. kind of a pseudo singleton...
Definition: huginApp.cpp:649
void OnDblClickListCtrl(wxMouseEvent &e)
double click does open file
std::set< unsigned int > UIntSet
Definition: PanoramaData.h:51
wxSplitterWindow * m_splitter1
Definition: BrowseDialog.h:132
PanoInfo ParsePTOFile(const wxFileName file)
read the given pto file and add all information to wxListCtrl
options getSize().area()) int wxCALLBACK SortFieldOfViewAscending(wxIntPtr item1
Model for a panorama.
Definition: Panorama.h:152
std::string getPathPrefix(const std::string &filename)
Get the path to a filename.
Definition: utils.cpp:184
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
Definition: wxcms.cpp:218
wxString focalLengthString
Definition: BrowseDialog.h:61
std::size_t getNrOfImages() const
number of images.
Definition: Panorama.h:205
static MainFrame * Get()
hack.. kind of a pseudo singleton...
Definition: MainFrame.cpp:2183
wxStaticText * m_labelControl
Definition: BrowseDialog.h:131
int wxCALLBACK SortDurationAscending(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData)
wxString camera
Definition: BrowseDialog.h:58
#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.
Definition: BrowseDialog.h:72
void StoreFramePosition(wxTopLevelWindow *frame, const wxString &basename)
Store window size and position in configfile/registry.
Definition: LensCalApp.cpp:212
wxGenericDirCtrl * m_dirCtrl
Definition: BrowseDialog.h:123
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...
Definition: Panorama.cpp:2023
void OnDirectoryChanged(wxTreeEvent &e)
directory changed, load files from new directory
wxImageList m_thumbnails
image list with all thumbnails
Definition: BrowseDialog.h:137
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
Definition: huginApp.h:156
wxString FormatDateTimeSpan(const wxTimeSpan timespan)
wxDECLARE_EVENT(wxEVT_COMMAND_THUMBNAILTHREAD_UPDATE, wxCommandEvent)
HuginBase::PanoramaOptions options
Definition: BrowseDialog.h:54
void RestoreFramePosition(wxTopLevelWindow *frame, const wxString &basename)
Restore window size and position from configfile/registry.
Definition: LensCalApp.cpp:158
void GeneratePreview(int index)
generate preview for pto file with index
options wxIntPtr item2
wxArrayString m_files
wxSplitterWindow * m_splitter2
Definition: BrowseDialog.h:133
const float fieldOfView2
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)
Definition: ROIImage.h:324
bool stringToDouble(const STR &str_, double &dest)
convert a string to a double, ignore localisation.
Definition: utils.h:114
std::vector< PanoInfo > m_ptoInfo
info about the pto file
Definition: BrowseDialog.h:135
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
Definition: ROIImage.h:287
wxDateTime start
Definition: BrowseDialog.h:56
UIntSet getActiveImages() const
get active images
Definition: Panorama.cpp:1585
wxString GetSelectedProject()
return full path of selected project
wxImage * m_image
wxFileName ptoFilename
Definition: BrowseDialog.h:49
unsigned int getWidth() const
const PanoramaOptions & getOptions() const
returns the options for this panorama
Definition: Panorama.h:481
wxCriticalSection m_ThreadCS
critical section to synchronize with ThumbnailThread
Definition: BrowseDialog.h:141
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
Definition: BrowseDialog.h:130
size_t nrImages
Definition: BrowseDialog.h:51
static T max(T x, T y)
Definition: svm.cpp:65
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)
Definition: openmp_vigra.h:305
BrowsePTOFilesDialog * m_parentDialog
static void info(const char *fmt,...)
Definition: svm.cpp:95
class to store some information about a pto file on disc
Definition: BrowseDialog.h:46
double GPSLatitude
Definition: BrowseDialog.h:64
void OnOk(wxCommandEvent &e)
Saves current expression when closing dialog with Ok.
wxString GetFocalLength(const HuginBase::SrcPanoImage *img)
return focallength and focallength 35 mm as wxString
Definition: LensTools.cpp:519
ThreadImage(vigra::BRGBImage *thumbnail, vigra::BImage *mask)
ThreadImage()=delete
int GreaterComparisonOperator(const Type &a, const Type &b)
All variables of a source image.
Definition: SrcPanoImage.h:194
ThumbnailThread * m_thumbnailThread
background thumbnail creater thread
Definition: BrowseDialog.h:139
long TranslateIndex(const long index)
translate the index to the index of m_ptoInfo
wxTimeSpan duration
Definition: BrowseDialog.h:57
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
vigra::BImage * m_mask
wxString GetSelectedPath()
return last selected path