Hugintrunk  0.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ImagesTree.cpp
Go to the documentation of this file.
1 // -*- c-basic-offset: 4 -*-
2 
10 /* This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This software is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18  * General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public
21  * License along with this software. If not, see
22  * <http://www.gnu.org/licenses/>.
23  *
24  */
25 
26 #include "hugin_config.h"
27 #include "panoinc_WX.h"
28 #include "panoinc.h"
29 
30 #include "base_wx/wxPlatform.h"
31 #include "base_wx/LensTools.h"
32 #include "hugin/ImagesTree.h"
33 #include "base_wx/wxImageCache.h"
34 #include "base_wx/platform.h"
38 #include "base_wx/CommandHistory.h"
39 #include "base_wx/PanoCommand.h"
40 #include <hugin_utils/stl_utils.h>
42 #include "hugin/huginApp.h"
43 #include "hugin/MainFrame.h"
44 #include "hugin/GLPreviewFrame.h"
45 #include <wx/renderer.h>
46 
47 enum
48 {
49  ID_LINK=wxID_HIGHEST+230,
58  ID_OPERATION_START=wxID_HIGHEST+300
59 };
60 
61 class ImagesTreeData : public wxTreeItemData
62 {
63 public:
64  explicit ImagesTreeData(const long& nr) : m_nr(nr) { };
65  const long GetImgNr() const { return m_nr;};
66  void SetImgNr(long newImgNr) { m_nr=newImgNr;};
67  const long GetGroupNr() const { return -(m_nr+1);};
68  const bool IsGroup() const { return (m_nr<0); };
69 
70 private:
71  long m_nr;
72 };
73 
74 // Define a constructor for the Images Panel
76 {
77  m_pano = NULL;
80  m_dragging=false;
82  m_optimizerMode=false;
83  m_needsUpdate=true;
84  m_markDisabledImages = false;
85 }
86 
87 bool ImagesTreeCtrl::Create(wxWindow* parent, wxWindowID id,
88  const wxPoint& pos,
89  const wxSize& size,
90  long style,
91  const wxString& name)
92 {
93  DEBUG_TRACE("List");
94  if (! wxTreeListCtrl::Create(parent, id, pos, size, style | wxTR_DEFAULT_STYLE|wxTR_HIDE_ROOT|wxTR_NO_LINES|wxTR_FULL_ROW_HIGHLIGHT|wxTR_ROW_LINES|wxTR_LINES_AT_ROOT|wxTR_MULTIPLE) )
95  {
96  return false;
97  }
98 
99  DEBUG_TRACE("Tree, adding columns");
100  m_configClassName = wxT("/ImagesTree");
101  CreateColumns();
102  DEBUG_TRACE("");
103  m_degDigits = wxConfigBase::Get()->Read(wxT("/General/DegreeFractionalDigits"),1);
104  m_pixelDigits = wxConfigBase::Get()->Read(wxT("/General/PixelFractionalDigits"),1);
105  m_distDigits = wxConfigBase::Get()->Read(wxT("/General/DistortionFractionalDigits"),3);
106  //create root
107  m_root=AddRoot(wxT("root"));
108  // bind event handler
109  Bind(wxEVT_LIST_COL_END_DRAG, &ImagesTreeCtrl::OnColumnWidthChange, this);
110  Bind(wxEVT_TREE_ITEM_MENU, &ImagesTreeCtrl::OnContextMenu, this);
111  Bind(wxEVT_LIST_COL_RIGHT_CLICK, &ImagesTreeCtrl::OnHeaderContextMenu, this);
112  Bind(wxEVT_TREE_BEGIN_DRAG, &ImagesTreeCtrl::OnBeginDrag, this);
113  Bind(wxEVT_LEFT_UP, &ImagesTreeCtrl::OnLeftUp, this);
114  Bind(wxEVT_LEFT_DCLICK, &ImagesTreeCtrl::OnLeftDblClick, this);
115  // for working double click we need also the menu handler on ID_EDIT
116  Bind(wxEVT_MENU, &ImagesTreeCtrl::OnEditImageVariables, this, ID_EDIT);
117  Bind(wxEVT_TREE_KEY_DOWN, &ImagesTreeCtrl::OnChar, this);
118  Bind(wxEVT_TREE_BEGIN_LABEL_EDIT, &ImagesTreeCtrl::OnBeginEdit, this);
119  Bind(wxEVT_TREE_END_LABEL_EDIT, &ImagesTreeCtrl::OnEndEdit, this);
120  Bind(wxEVT_DPI_CHANGED, &ImagesTreeCtrl::OnDpiChanged, this);
121 
122  return true;
123 }
124 
126 {
127  size_t counter=0;
128 #define ADDCOLUMN(header, mapName, width, align, isEditable, IVE, tooltip) \
129  AddColumn(header, width, align, -1, true, false, tooltip);\
130  m_columnMap[mapName]=counter;\
131  m_columnVector.push_back(mapName);\
132  if(isEditable)\
133  {\
134  m_editableColumns.insert(counter);\
135  };\
136  m_variableVector.push_back(IVE);\
137  counter++;
138  ADDCOLUMN(wxT("#"), "imgNr", 35, wxALIGN_LEFT, false, HuginBase::ImageVariableGroup::IVE_Filename, _("Image number"))
139  ADDCOLUMN(_("Filename"), "filename", 200, wxALIGN_LEFT, false, HuginBase::ImageVariableGroup::IVE_Filename, _("Filename"))
140  ADDCOLUMN(_("Width"), "width", 60, wxALIGN_RIGHT, false, HuginBase::ImageVariableGroup::IVE_Filename, _("Image width"))
141  ADDCOLUMN(_("Height"), "height", 60, wxALIGN_RIGHT, false, HuginBase::ImageVariableGroup::IVE_Filename, _("Image height"))
142  ADDCOLUMN(_("Anchor"), "anchor", 60, wxALIGN_RIGHT, false, HuginBase::ImageVariableGroup::IVE_Filename, _("Anchor image for position and/or exposure"))
143  ADDCOLUMN(_("# Ctrl Pnts"), "cps", 60, wxALIGN_RIGHT, false, HuginBase::ImageVariableGroup::IVE_Filename, _("Number of control points in this image"))
144  ADDCOLUMN(_("Lens no."), "lensNr", 60, wxALIGN_RIGHT, false, HuginBase::ImageVariableGroup::IVE_Filename, _("Assigned lens number"))
145  ADDCOLUMN(_("Stack no."), "stackNr", 60, wxALIGN_RIGHT, false, HuginBase::ImageVariableGroup::IVE_Filename, _("Assigned stack number"))
146 
147  ADDCOLUMN(_("Maker"), "maker", 100, wxALIGN_LEFT, false, HuginBase::ImageVariableGroup::IVE_Filename, _("Camera maker"))
148  ADDCOLUMN(_("Model"), "model", 100, wxALIGN_LEFT, false, HuginBase::ImageVariableGroup::IVE_Filename, _("Camera model"))
149  ADDCOLUMN(_("Lens"), "lens", 100, wxALIGN_LEFT, false, HuginBase::ImageVariableGroup::IVE_Filename, _("Used lens"))
150  ADDCOLUMN(_("Capture date"), "date", 100, wxALIGN_LEFT, false, HuginBase::ImageVariableGroup::IVE_Filename, _("Date, image was taken"))
151  ADDCOLUMN(_("Focal length"), "focallength", 80, wxALIGN_LEFT, false, HuginBase::ImageVariableGroup::IVE_Filename, _("Focal length"))
152  ADDCOLUMN(_("Aperture"), "aperture", 50, wxALIGN_LEFT, false, HuginBase::ImageVariableGroup::IVE_Filename, _("Aperture"))
153  ADDCOLUMN(_("Shutter Speed"), "time", 50, wxALIGN_LEFT, false, HuginBase::ImageVariableGroup::IVE_Filename, _("Shutter speed"))
154  ADDCOLUMN(_("ISO"), "iso", 50, wxALIGN_LEFT, false, HuginBase::ImageVariableGroup::IVE_Filename, _("ISO speed"))
155 
156  ADDCOLUMN(_("Yaw (y)"), "y", 60, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_Yaw, _("Yaw"))
157  ADDCOLUMN(_("Pitch (p)"), "p", 60, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_Yaw, _("Pitch"))
158  ADDCOLUMN(_("Roll (r)"), "r", 60, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_Yaw, _("Roll"))
159  ADDCOLUMN(wxT("X (TrX)"), "TrX", 60, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_Yaw, _("Camera translation X"))
160  ADDCOLUMN(wxT("Y (TrY)"), "TrY", 60, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_Yaw, _("Camera translation Y"))
161  ADDCOLUMN(wxT("Z (TrZ)"), "TrZ", 60, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_Yaw, _("Camera translation Z"))
162  ADDCOLUMN(_("Plane yaw"), "Tpy", 60, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_Yaw, _("Translation remap plane yaw"))
163  ADDCOLUMN(_("Plane pitch"), "Tpp", 60, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_Yaw, _("Translation remap plane pitch"))
164  ADDCOLUMN(_("Camera translation"), "cam_trans", 60, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_Yaw, _("Camera translation"))
165 
166  ADDCOLUMN(_("Lens type (f)"), "projection", 100, wxALIGN_LEFT, false, HuginBase::ImageVariableGroup::IVE_Filename, _("Lens type (rectilinear, fisheye, equirectangular, ...)"))
167  ADDCOLUMN(_("Hfov (v)"), "v", 80, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_HFOV, _("Horizontal field of view (v)"))
168  ADDCOLUMN(wxT("a"), "a", 40, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_RadialDistortion, _("Radial distortion (a)"))
169  ADDCOLUMN(wxT("b"), "b", 40, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_RadialDistortion, _("Radial distortion (b, barrel)"))
170  ADDCOLUMN(wxT("c"), "c", 40, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_RadialDistortion, _("Radial distortion (c)"))
171  ADDCOLUMN(wxT("d"), "d", 40, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_RadialDistortionCenterShift, _("Horizontal image center shift (d)"))
172  ADDCOLUMN(wxT("e"), "e", 40, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_RadialDistortionCenterShift, _("Vertical image center shift (e)"))
173  ADDCOLUMN(wxT("g"), "g", 40, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_Shear, _("Horizontal image shearing (g)"))
174  ADDCOLUMN(wxT("t"), "t", 40, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_Shear, _("Vertical image shearing (t)"))
175 
176  ADDCOLUMN(wxT("EV"), "Eev", 50, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_ExposureValue, _("Exposure value (Eev)"))
177  ADDCOLUMN(wxT("Er"), "Er", 40, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_WhiteBalanceRed, _("Red multiplier (Er)"))
178  ADDCOLUMN(wxT("Eb"), "Eb", 40, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_WhiteBalanceBlue, _("Blue multiplier (Eb)"))
179  ADDCOLUMN(wxT("Vb"), "Vb", 40, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_RadialVigCorrCoeff, _("Vignetting (Vb, Vc, Vd)"))
180  ADDCOLUMN(wxT("Vc"), "Vc", 40, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_RadialVigCorrCoeff, _("Vignetting (Vb, Vc, Vd)"))
181  ADDCOLUMN(wxT("Vd"), "Vd", 40, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_RadialVigCorrCoeff, _("Vignetting (Vb, Vc, Vd)"))
182  ADDCOLUMN(wxT("Vx"), "Vx", 40, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_RadialVigCorrCenterShift, _("Horizontal vignetting center shift (Vx)"))
183  ADDCOLUMN(wxT("Vy"), "Vy", 40, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_RadialVigCorrCenterShift, _("Vertical vignetting center shift (Vy)"))
184  ADDCOLUMN(_("Response type"), "response", 80, wxALIGN_LEFT, false, HuginBase::ImageVariableGroup::IVE_Filename, _("Camera response type"))
185  ADDCOLUMN(wxT("Ra"), "Ra", 40, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_EMoRParams, _("Camera response parameter"))
186  ADDCOLUMN(wxT("Rb"), "Rb", 40, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_EMoRParams, _("Camera response parameter"))
187  ADDCOLUMN(wxT("Rc"), "Rc", 40, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_EMoRParams, _("Camera response parameter"))
188  ADDCOLUMN(wxT("Rd"), "Rd", 40, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_EMoRParams, _("Camera response parameter"))
189  ADDCOLUMN(wxT("Re"), "Re", 40, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_EMoRParams, _("Camera response parameter"))
190 
191  //empty column to have enough space on the right side
192  AddColumn(wxEmptyString,10);
193 
194  //get saved width
195  for ( int j=0; j < GetColumnCount() ; j++ )
196  {
197  // -1 is auto
198  int width = wxConfigBase::Get()->Read(wxString::Format(m_configClassName+wxT("/ColumnWidth%d"), j ), -1);
199  if(width != -1)
200  SetColumnWidth(j, width);
201  }
202 };
203 
205 {
206  m_pano = panorama;
207  m_pano->addObserver(this);
208 
212 
213 #ifdef __WXMAC__
214  SetDropTarget(new PanoDropTarget(*m_pano, true));
215 #endif
216 }
217 
219 {
220  DEBUG_TRACE("");
221  m_pano->removeObserver(this);
222  delete m_variable_groups;
223 };
224 
226 {
227  if(m_optimizerMode)
228  {
229  Freeze();
231  Thaw();
232 #ifdef __WXGTK__
233  Refresh();
234 #endif
235  };
237  {
238  HuginBase::UIntSet imgs;
239  fill_set(imgs, 0, pano.getNrOfImages()-1);
240  panoramaImagesChanged(pano, imgs);
241  };
242  m_needsUpdate=true;
243 };
244 
246 {
247  DEBUG_TRACE("");
248 
249  Freeze();
250  HuginBase::UIntSet changedImgs(changed);
251  // Make sure the part numbers are up to date before writing them to the table.
252  size_t oldLensCount=m_variable_groups->getLenses().getNumberOfParts();
253  size_t oldStackCount=m_variable_groups->getStacks().getNumberOfParts();
255  //if the number of lenses or stacks have changed we need to update all images
256  //because the changed images set contains only the list of the changed imagges
257  //but not these images where the stack or lens number has changed because
258  //an images has been inserted
259  if(pano.getNrOfImages()>0)
260  {
261  if(m_variable_groups->getLenses().getNumberOfParts()!=oldLensCount ||
262  m_variable_groups->getStacks().getNumberOfParts()!=oldStackCount)
263  {
264  fill_set(changedImgs, 0, pano.getNrOfImages()-1);
265  };
266  };
267  if(m_optimizerMode)
268  {
270  {
272  };
274  {
276  };
277  };
279  {
280  HuginBase::UIntSet imgs;
281  if(m_pano->getNrOfImages()>0)
282  {
283  fill_set(imgs,0,m_pano->getNrOfImages()-1);
284  };
285  UpdateGroup(m_root,imgs,changedImgs);
286  }
287  else
288  {
289  HuginBase::UIntSetVector imageGroups;
290  switch (m_groupMode)
291  {
292  case GROUP_LENS:
293  imageGroups = m_variable_groups->getLenses().getPartsSet();
294  break;
295  case GROUP_STACK:
296  imageGroups = m_variable_groups->getStacks().getPartsSet();
297  break;
298  case GROUP_OUTPUTSTACK:
300  break;
301  case GROUP_OUTPUTLAYERS:
303  break;
304  };
305 
306  size_t nrItems=GetChildrenCount(m_root,false);
307  if(nrItems!=imageGroups.size())
308  {
309  if(nrItems<imageGroups.size())
310  {
311  for(size_t i=nrItems;i<imageGroups.size();i++)
312  {
313  AppendItem(m_root,wxEmptyString,-1,-1,new ImagesTreeData(-(long)i-1));
314  };
315  }
316  else
317  {
318  while(GetChildrenCount(m_root,false)>imageGroups.size())
319  {
320  wxTreeItemIdValue cookie;
321  wxTreeItemId item=GetLastChild(m_root,cookie);
322  Delete(item);
323  };
324  };
325  };
326 
327  wxTreeItemIdValue cookie;
328  wxTreeItemId item=GetFirstChild(m_root, cookie);
329  size_t i=0;
330  while(item.IsOk())
331  {
332  UpdateGroup(item,imageGroups[i++],changedImgs);
333  UpdateGroupText(item);
334  item=GetNextChild(m_root, cookie);
335  };
336  };
337  // updates checkboxes images for optimizer variables
338  if(m_optimizerMode)
339  {
341  };
343  {
344  UpdateItemFont();
345  };
346 
347  Thaw();
348  m_needsUpdate = false;
349 
350  // HACK! need to notify clients anyway... send dummy event..
351  // lets hope our clients query for the selected images with GetSelected()
352  // and do not try to interpret the event.
353  wxListEvent e;
354  e.SetEventType(wxEVT_COMMAND_LIST_ITEM_SELECTED);
355  e.m_itemIndex = -1;
356  GetEventHandler()->ProcessEvent(e);
357 }
358 
359 void ImagesTreeCtrl::UpdateImageText(wxTreeItemId item)
360 {
361  ImagesTreeData* itemData=static_cast<ImagesTreeData*>(GetItemData(item));
362  // NAMEisLinked returns always false, if the lens or stacks contains only a single image
363  // so add a special handling for this case
364  bool isSingleImage = false;
365  if (m_groupMode != GROUP_NONE)
366  {
367  isSingleImage = (GetChildrenCount(GetItemParent(item)) == 1);
368  };
369  wxString s;
370  const size_t imgNr=itemData->GetImgNr();
371  const HuginBase::SrcPanoImage & img = m_pano->getImage(imgNr);
372  wxFileName fn(wxString (img.getFilename().c_str(), HUGIN_CONV_FILENAME));
373 
374  s << imgNr;
375  SetItemText(item, m_columnMap["imgNr"], s);
376  s.Clear();
377  SetItemText(item, m_columnMap["filename"], fn.GetFullName() );
378  SetItemText(item, m_columnMap["width"], wxString::Format(wxT("%d"), img.getSize().width()));
379  SetItemText(item, m_columnMap["height"], wxString::Format(wxT("%d"), img.getSize().height()));
380 
381  wxChar flags[] = wxT("--");
382  if (m_pano->getOptions().optimizeReferenceImage == imgNr)
383  {
384  flags[0]='A';
385  }
386  if (m_pano->getOptions().colorReferenceImage == imgNr)
387  {
388  flags[1]='C';
389  }
390  SetItemText(item, m_columnMap["anchor"], wxString(flags, wxConvLocal));
391  std::vector<unsigned int> cps = m_pano->getCtrlPointsForImage(imgNr);
392  s << cps.size();
393  SetItemText(item, m_columnMap["cps"], s);
394  s.Clear();
395  const unsigned int stackNumber = m_variable_groups->getStacks().getPartNumber(imgNr);
396  SetItemText(item, m_columnMap["stackNr"], wxString::Format(wxT("%u"), stackNumber));
397  const unsigned int lensNr=m_variable_groups->getLenses().getPartNumber(imgNr);
398  SetItemText(item, m_columnMap["lensNr"], wxString::Format(wxT("%u"), lensNr));
399 
400  SetItemText(item, m_columnMap["maker"], wxString(img.getExifMake().c_str(), wxConvLocal));
401  SetItemText(item, m_columnMap["model"], wxString(img.getExifModel().c_str(), wxConvLocal));
402  SetItemText(item, m_columnMap["lens"], wxString(img.getExifLens().c_str(), wxConvLocal));
404  SetItemText(item, m_columnMap["focallength"], FormatString::GetFocalLength(&img));
405  SetItemText(item, m_columnMap["aperture"], FormatString::GetAperture(&img));
407  SetItemText(item, m_columnMap["iso"], FormatString::GetIso(&img));
408 
409  if (m_groupMode == GROUP_STACK && (img.YawisLinked() || isSingleImage))
410  {
411  SetItemText(item, m_columnMap["y"], wxEmptyString);
412  SetItemText(item, m_columnMap["p"], wxEmptyString);
413  SetItemText(item, m_columnMap["r"], wxEmptyString);
414  SetItemText(item, m_columnMap["TrX"], wxEmptyString);
415  SetItemText(item, m_columnMap["TrY"], wxEmptyString);
416  SetItemText(item, m_columnMap["TrZ"], wxEmptyString);
417  SetItemText(item, m_columnMap["Tpy"], wxEmptyString);
418  SetItemText(item, m_columnMap["Tpp"], wxEmptyString);
419  SetItemText(item, m_columnMap["cam_trans"], wxEmptyString);
420  }
421  else
422  {
429  SetItemText(item, m_columnMap["Tpy"], hugin_utils::doubleTowxString(img.getTranslationPlaneYaw(), m_degDigits));
430  SetItemText(item, m_columnMap["Tpp"], hugin_utils::doubleTowxString(img.getTranslationPlanePitch(), m_degDigits));
431  wxString text=_("not active");
432  if(img.getX()!=0.0 || img.getY()!=0.0 || img.getZ()!=0.0 || img.getTranslationPlaneYaw()!=0.0 || img.getTranslationPlanePitch()!=0.0)
433  {
434  text=_("active");
435  };
436  text.Prepend(wxT(" "));
437  SetItemText(item, m_columnMap["cam_trans"], text);
438  };
439 
441  {
442  SetItemText(item, m_columnMap["projection"], wxEmptyString);
443  SetItemText(item, m_columnMap["response"], wxEmptyString);
444  }
445  else
446  {
447  SetItemText(item, m_columnMap["projection"], getProjectionString(img));
448  SetItemText(item, m_columnMap["response"], getResponseString(img));
449  };
450 
451  if (m_groupMode == GROUP_LENS && (img.HFOVisLinked() || isSingleImage))
452  {
453  SetItemText(item, m_columnMap["v"], wxEmptyString);
454  }
455  else
456  {
458  };
459 
460  if (m_groupMode == GROUP_LENS && (img.RadialDistortionisLinked() || isSingleImage))
461  {
462  SetItemText(item, m_columnMap["a"], wxEmptyString);
463  SetItemText(item, m_columnMap["b"], wxEmptyString);
464  SetItemText(item, m_columnMap["c"], wxEmptyString);
465  }
466  else
467  {
468  std::vector<double> dist=img.getRadialDistortion();
472  };
473 
474  if (m_groupMode == GROUP_LENS && (img.RadialDistortionCenterShiftisLinked() || isSingleImage))
475  {
476  SetItemText(item, m_columnMap["d"], wxEmptyString);
477  SetItemText(item, m_columnMap["e"], wxEmptyString);
478  }
479  else
480  {
481  hugin_utils::FDiff2D p=img.getRadialDistortionCenterShift();
484  };
485 
486  if (m_groupMode == GROUP_LENS && (img.ShearisLinked() || isSingleImage))
487  {
488  SetItemText(item, m_columnMap["g"], wxEmptyString);
489  SetItemText(item, m_columnMap["t"], wxEmptyString);
490  }
491  else
492  {
493  hugin_utils::FDiff2D p=img.getShear();
496  };
497 
498  if (m_groupMode == GROUP_LENS && (img.ExposureValueisLinked() || isSingleImage))
499  {
500  SetItemText(item, m_columnMap["Eev"], wxEmptyString);
501  }
502  else
503  {
504  SetItemText(item, m_columnMap["Eev"], hugin_utils::doubleTowxString(img.getExposureValue(), m_pixelDigits));
505  };
506 
507  if (m_groupMode == GROUP_LENS && (img.WhiteBalanceRedisLinked() || isSingleImage))
508  {
509  SetItemText(item, m_columnMap["Er"], wxEmptyString);
510  }
511  else
512  {
513  SetItemText(item, m_columnMap["Er"], hugin_utils::doubleTowxString(img.getWhiteBalanceRed(), m_pixelDigits+1));
514  };
515 
516  if (m_groupMode == GROUP_LENS && (img.WhiteBalanceBlueisLinked() || isSingleImage))
517  {
518  SetItemText(item, m_columnMap["Eb"], wxEmptyString);
519  }
520  else
521  {
522  SetItemText(item, m_columnMap["Eb"], hugin_utils::doubleTowxString(img.getWhiteBalanceBlue(), m_pixelDigits+1));
523  };
524 
525  if (m_groupMode == GROUP_LENS && (img.RadialVigCorrCoeffisLinked() || isSingleImage))
526  {
527  SetItemText(item, m_columnMap["Vb"], wxEmptyString);
528  SetItemText(item, m_columnMap["Vc"], wxEmptyString);
529  SetItemText(item, m_columnMap["Vd"], wxEmptyString);
530  }
531  else
532  {
533  std::vector<double> dist=img.getRadialVigCorrCoeff();
537  };
538 
539  if (m_groupMode == GROUP_LENS && (img.RadialVigCorrCenterShiftisLinked() || isSingleImage))
540  {
541  SetItemText(item, m_columnMap["Vx"], wxEmptyString);
542  SetItemText(item, m_columnMap["Vy"], wxEmptyString);
543  }
544  else
545  {
546  hugin_utils::FDiff2D p=img.getRadialVigCorrCenterShift();
549  };
550 
551  if (m_groupMode == GROUP_LENS && (img.EMoRParamsisLinked() || isSingleImage))
552  {
553  SetItemText(item, m_columnMap["Ra"], wxEmptyString);
554  SetItemText(item, m_columnMap["Rb"], wxEmptyString);
555  SetItemText(item, m_columnMap["Rc"], wxEmptyString);
556  SetItemText(item, m_columnMap["Rd"], wxEmptyString);
557  SetItemText(item, m_columnMap["Re"], wxEmptyString);
558  }
559  else
560  {
561  if (img.getResponseType() == HuginBase::SrcPanoImage::RESPONSE_EMOR)
562  {
563  // display Ra..Re only when response type is emor
564  // otherwise they have no meaning
565  std::vector<float> vec = img.getEMoRParams();
571  }
572  else
573  {
574  SetItemText(item, m_columnMap["Ra"], wxEmptyString);
575  SetItemText(item, m_columnMap["Rb"], wxEmptyString);
576  SetItemText(item, m_columnMap["Rc"], wxEmptyString);
577  SetItemText(item, m_columnMap["Rd"], wxEmptyString);
578  SetItemText(item, m_columnMap["Re"], wxEmptyString);
579  };
580  };
581 };
582 
583 void ImagesTreeCtrl::UpdateGroupText(wxTreeItemId item)
584 {
585  ImagesTreeData* itemData=static_cast<ImagesTreeData*>(GetItemData(item));
586  switch(m_groupMode)
587  {
588  case GROUP_LENS:
589  SetItemText(item, 1, wxString::Format(_("Lens %ld"),itemData->GetGroupNr()));
590  break;
591  case GROUP_STACK:
592  SetItemText(item, 1, wxString::Format(_("Stack %ld"),itemData->GetGroupNr()));
593  break;
594  case GROUP_OUTPUTSTACK:
595  SetItemText(item, 1, wxString::Format(_("Output stack %ld"),itemData->GetGroupNr()));
596  break;
597  case GROUP_OUTPUTLAYERS:
598  SetItemText(item, 1, wxString::Format(_("Output exposure layer %ld"),itemData->GetGroupNr()));
599  break;
600  };
601  SetItemBold(item,1,true);
602  wxTreeItemIdValue cookie;
603  wxTreeItemId childItem=GetFirstChild(item,cookie);
604  // NAMEisLinked returns always false, if the lens or stacks contains only a single image
605  // so add a special handling for this case
606  bool haveSingleChild = false;
607  if (m_groupMode != GROUP_NONE)
608  {
609  haveSingleChild = (GetChildrenCount(item, false) == 1);
610  };
611  if(childItem.IsOk())
612  {
613  ImagesTreeData* data=static_cast<ImagesTreeData*>(GetItemData(childItem));
614  const HuginBase::SrcPanoImage& img=m_pano->getImage(data->GetImgNr());
615 
616  if (m_groupMode == GROUP_STACK && (img.YawisLinked() || haveSingleChild))
617  {
624  SetItemText(item, m_columnMap["Tpy"], hugin_utils::doubleTowxString(img.getTranslationPlaneYaw(), m_degDigits));
625  SetItemText(item, m_columnMap["Tpp"], hugin_utils::doubleTowxString(img.getTranslationPlanePitch(), m_degDigits));
626  wxString text=_("not active");
627  if(img.getX()!=0.0 || img.getY()!=0.0 || img.getZ()!=0.0 || img.getTranslationPlaneYaw()!=0.0 || img.getTranslationPlanePitch()!=0.0)
628  {
629  text=_("active");
630  };
631  text.Prepend(wxT(" "));
632  SetItemText(item, m_columnMap["cam_trans"], text);
633  }
634  else
635  {
636  SetItemText(item, m_columnMap["y"], wxEmptyString);
637  SetItemText(item, m_columnMap["p"], wxEmptyString);
638  SetItemText(item, m_columnMap["r"], wxEmptyString);
639  SetItemText(item, m_columnMap["TrX"], wxEmptyString);
640  SetItemText(item, m_columnMap["TrY"], wxEmptyString);
641  SetItemText(item, m_columnMap["TrZ"], wxEmptyString);
642  SetItemText(item, m_columnMap["Tpy"], wxEmptyString);
643  SetItemText(item, m_columnMap["Tpp"], wxEmptyString);
644  SetItemText(item, m_columnMap["cam_trans"], wxEmptyString);
645  };
646 
648  {
649  SetItemText(item, m_columnMap["projection"], getProjectionString(img));
650  SetItemText(item, m_columnMap["response"], getResponseString(img));
651  }
652  else
653  {
654  SetItemText(item, m_columnMap["projection"], wxEmptyString);
655  SetItemText(item, m_columnMap["response"], wxEmptyString);
656  };
657 
658  if (m_groupMode == GROUP_LENS && (img.HFOVisLinked() || haveSingleChild))
659  {
661  }
662  else
663  {
664  SetItemText(item, m_columnMap["v"], wxEmptyString);
665  };
666 
667  if (m_groupMode == GROUP_LENS && (img.RadialDistortionisLinked() || haveSingleChild))
668  {
669  std::vector<double> dist=img.getRadialDistortion();
673  }
674  else
675  {
676  SetItemText(item, m_columnMap["a"], wxEmptyString);
677  SetItemText(item, m_columnMap["b"], wxEmptyString);
678  SetItemText(item, m_columnMap["c"], wxEmptyString);
679  };
680 
681  if (m_groupMode == GROUP_LENS && (img.RadialDistortionCenterShiftisLinked() || haveSingleChild))
682  {
683  hugin_utils::FDiff2D p=img.getRadialDistortionCenterShift();
686  }
687  else
688  {
689  SetItemText(item, m_columnMap["d"], wxEmptyString);
690  SetItemText(item, m_columnMap["e"], wxEmptyString);
691  };
692 
693  if (m_groupMode == GROUP_LENS && (img.ShearisLinked() || haveSingleChild))
694  {
695  hugin_utils::FDiff2D p=img.getShear();
698  }
699  else
700  {
701  SetItemText(item, m_columnMap["g"], wxEmptyString);
702  SetItemText(item, m_columnMap["t"], wxEmptyString);
703  };
704 
705  if (m_groupMode == GROUP_LENS && (img.ExposureValueisLinked() || haveSingleChild))
706  {
707  SetItemText(item, m_columnMap["Eev"], hugin_utils::doubleTowxString(img.getExposureValue(), m_pixelDigits));
708  }
709  else
710  {
711  SetItemText(item, m_columnMap["Eev"], wxEmptyString);
712  };
713 
714  if (m_groupMode == GROUP_LENS && (img.WhiteBalanceRedisLinked() || haveSingleChild))
715  {
716  SetItemText(item, m_columnMap["Er"], hugin_utils::doubleTowxString(img.getWhiteBalanceRed(), m_pixelDigits+1));
717  }
718  else
719  {
720  SetItemText(item, m_columnMap["Er"], wxEmptyString);
721  };
722 
723  if (m_groupMode == GROUP_LENS && (img.WhiteBalanceBlueisLinked() || haveSingleChild))
724  {
725  SetItemText(item, m_columnMap["Eb"], hugin_utils::doubleTowxString(img.getWhiteBalanceBlue(), m_pixelDigits+1));
726  }
727  else
728  {
729  SetItemText(item, m_columnMap["Eb"], wxEmptyString);
730  };
731 
732  if (m_groupMode == GROUP_LENS && (img.RadialVigCorrCoeffisLinked() || haveSingleChild))
733  {
734  std::vector<double> dist=img.getRadialVigCorrCoeff();
738  }
739  else
740  {
741  SetItemText(item, m_columnMap["Vb"], wxEmptyString);
742  SetItemText(item, m_columnMap["Vc"], wxEmptyString);
743  SetItemText(item, m_columnMap["Vd"], wxEmptyString);
744  };
745 
746  if (m_groupMode == GROUP_LENS && (img.RadialVigCorrCenterShiftisLinked() || haveSingleChild))
747  {
748  hugin_utils::FDiff2D p=img.getRadialVigCorrCenterShift();
751  }
752  else
753  {
754  SetItemText(item, m_columnMap["Vx"], wxEmptyString);
755  SetItemText(item, m_columnMap["Vy"], wxEmptyString);
756  };
757 
758  if (m_groupMode == GROUP_LENS && (img.getResponseType() == HuginBase::SrcPanoImage::RESPONSE_EMOR && (img.EMoRParamsisLinked()) || haveSingleChild))
759  {
760  std::vector<float> vec=img.getEMoRParams();
766  }
767  else
768  {
769  SetItemText(item, m_columnMap["Ra"], wxEmptyString);
770  SetItemText(item, m_columnMap["Rb"], wxEmptyString);
771  SetItemText(item, m_columnMap["Rc"], wxEmptyString);
772  SetItemText(item, m_columnMap["Rd"], wxEmptyString);
773  SetItemText(item, m_columnMap["Re"], wxEmptyString);
774  };
775  };
776 };
777 
778 void ImagesTreeCtrl::UpdateGroup(wxTreeItemId parent, const HuginBase::UIntSet imgs, HuginBase::UIntSet& changed)
779 {
780  size_t nrItems=GetChildrenCount(parent,false);
781  bool forceUpdate=false;
782  if(nrItems!=imgs.size())
783  {
784  forceUpdate=true;
785  if(nrItems<imgs.size())
786  {
787  for(size_t i=nrItems;i<imgs.size();i++)
788  {
789  AppendItem(parent,wxEmptyString,-1,-1,new ImagesTreeData(-1));
790  };
791  }
792  else
793  {
794  while(GetChildrenCount(parent,false)>imgs.size())
795  {
796  wxTreeItemIdValue cookie;
797  wxTreeItemId item=GetLastChild(parent,cookie);
798  Delete(item);
799  };
800  };
801  };
802  //now update values
803  wxTreeItemIdValue cookie;
804  wxTreeItemId item=GetFirstChild(parent,cookie);
805  HuginBase::UIntSet::const_iterator it=imgs.begin();
806  while(item.IsOk())
807  {
808  ImagesTreeData* data=static_cast<ImagesTreeData*>(GetItemData(item));
809  if(it==imgs.end())
810  {
811  break;
812  };
813  bool needsUpdate=false;
814  if(data->GetImgNr()!=*it)
815  {
816  data->SetImgNr(*it);
817  needsUpdate=true;
818  }
819  else
820  {
821  if(set_contains(changed,*it))
822  {
823  needsUpdate=true;
824  };
825  };
826  if(needsUpdate || forceUpdate)
827  {
828  UpdateImageText(item);
829  changed.erase(*it);
830  };
831  item=GetNextChild(parent, cookie);
832  ++it;
833  };
834 };
835 
837 {
839  wxTreeItemIdValue cookie;
840  wxTreeItemId item=GetFirstChild(m_root, cookie);
841  while(item.IsOk())
842  {
843  ImagesTreeData* data=static_cast<ImagesTreeData*>(GetItemData(item));
844  HuginBase::UIntSet imgNrs;
845  if(data->IsGroup())
846  {
847  wxTreeItemIdValue childCookie;
848  wxTreeItemId child=GetFirstChild(item, childCookie);
849  while(child.IsOk())
850  {
851  data=static_cast<ImagesTreeData*>(GetItemData(child));
852  imgNrs.insert(data->GetImgNr());
853  child=GetNextChild(item, childCookie);
854  };
855  }
856  else
857  {
858  imgNrs.insert(data->GetImgNr());
859  };
860  if(!imgNrs.empty())
861  {
862  for(size_t i=0;i<GetColumnCount();i++)
863  {
865  {
866  if (GetItemText(item, i).IsEmpty())
867  {
868  // item with no text can have no checkbox
869  // this can happen with linked variables
870  SetItemImage(item, i, -1);
871  }
872  else
873  {
874  bool opt=false;
875  for(HuginBase::UIntSet::const_iterator it=imgNrs.begin(); it!=imgNrs.end() && !opt;++it)
876  {
877  if(m_columnVector[i]=="cam_trans")
878  {
879  opt=set_contains(optVec[*it], "TrX") &&
880  set_contains(optVec[*it], "TrY") &&
881  set_contains(optVec[*it], "TrZ") &&
882  set_contains(optVec[*it], "Tpy") &&
883  set_contains(optVec[*it], "Tpp");
884  }
885  else
886  {
887  opt=set_contains(optVec[*it], m_columnVector[i]);
888  };
889  };
890  SetItemImage(item, i, opt ? 1 : 0);
891  };
892  };
893  };
894  };
895  item=GetNext(item);
896  };
897 };
898 
900 {
901  wxArrayTreeItemIds selected;
902  HuginBase::UIntSet imgs;
903  if(GetSelections (selected)>0)
904  {
905  for(size_t i=0;i<selected.size();i++)
906  {
907  ImagesTreeData* data=static_cast<ImagesTreeData*>(GetItemData(selected[i]));
908  if(data->IsGroup())
909  {
910  wxTreeItemIdValue cookie;
911  wxTreeItemId item=GetFirstChild(selected[i],cookie);
912  while(item.IsOk())
913  {
914  data=static_cast<ImagesTreeData*>(GetItemData(item));
915  imgs.insert(data->GetImgNr());
916  item=GetNextChild(selected[i], cookie);
917  };
918  }
919  else
920  {
921  imgs.insert(data->GetImgNr());
922  };
923  };
924  }
925  return imgs;
926 }
927 
928 void ImagesTreeCtrl::MarkActiveImages(const bool markActive)
929 {
930  m_markDisabledImages = markActive;
931  UpdateItemFont();
932 };
933 
934 void ImagesTreeCtrl::OnColumnWidthChange( wxListEvent & e )
935 {
936  if(m_configClassName != wxT(""))
937  {
938  int colNum = e.GetColumn();
939  wxConfigBase::Get()->Write( m_configClassName+wxString::Format(wxT("/ColumnWidth%d"),colNum), GetColumnWidth(colNum) );
940  }
941 }
942 
944 {
945  m_guiLevel=newSetting;
946  //update visible column
948 };
949 
951 {
952  //create bitmaps for different checkboxes state
953  wxRendererNative& renderer = wxRendererNative::Get();
954  const wxSize checkBoxSize = renderer.GetCheckBoxSize(this);
955  wxImageList* checkboxImageList = new wxImageList(checkBoxSize.GetWidth(), checkBoxSize.GetHeight(), true, 0);
956  wxBitmap checkBoxImage(checkBoxSize, 32);
957  wxMemoryDC dc(checkBoxImage);
958  // unchecked checkbox
959  dc.Clear();
960  renderer.DrawCheckBox(this, dc, wxRect(checkBoxSize));
961  dc.SelectObject(wxNullBitmap);
962  checkboxImageList->Add(checkBoxImage);
963  // checked checkbox
964  dc.SelectObject(checkBoxImage);
965  dc.Clear();
966  renderer.DrawCheckBox(this, dc, wxRect(checkBoxSize), wxCONTROL_CHECKED);
967  dc.SelectObject(wxNullBitmap);
968  checkboxImageList->Add(checkBoxImage);
969  // mouse over unchecked checkbox
970  dc.SelectObject(checkBoxImage);
971  dc.Clear();
972  renderer.DrawCheckBox(this, dc, wxRect(checkBoxSize), wxCONTROL_CURRENT);
973  dc.SelectObject(wxNullBitmap);
974  checkboxImageList->Add(checkBoxImage);
975  // mouse over checked checkbox
976  dc.SelectObject(checkBoxImage);
977  dc.Clear();
978  renderer.DrawCheckBox(this, dc, wxRect(checkBoxSize), wxCONTROL_CHECKED | wxCONTROL_CURRENT);
979  dc.SelectObject(wxNullBitmap);
980  checkboxImageList->Add(checkBoxImage);
981 
982  AssignImageList(checkboxImageList);
983 }
984 
986 {
987  m_optimizerMode=true;
988  // connnect events with handlers
989  Bind(wxEVT_MOTION, &ImagesTreeCtrl::OnMouseMove, this);
990  Bind(wxEVT_LEFT_DOWN, &ImagesTreeCtrl::OnLeftDown, this);
991  // build image list with check box images
993  // activate edit mode
994  for(HuginBase::UIntSet::const_iterator it=m_editableColumns.begin(); it!=m_editableColumns.end(); ++it)
995  {
996  if(m_columnVector[*it]!="cam_trans")
997  {
998  SetColumnEditable(*it,true);
999  };
1000  };
1001 }
1002 
1003 void ImagesTreeCtrl::OnDpiChanged(wxDPIChangedEvent& e)
1004 {
1005  // dpi has changed, we need to update the images of the checkboxes
1006  if (m_optimizerMode)
1007  {
1009  Refresh();
1010  };
1011 }
1012 
1014 {
1015  if(newGroup!=m_groupMode)
1016  {
1017  m_groupMode=newGroup;
1018  if(m_groupMode==GROUP_NONE)
1019  {
1020  SetWindowStyle(GetWindowStyle() | wxTR_NO_LINES);
1021  }
1022  else
1023  {
1024  SetWindowStyle(GetWindowStyle() & ~wxTR_NO_LINES);
1025  };
1027  HuginBase::UIntSet imgs;
1028  if(m_pano->getNrOfImages()>0)
1029  {
1030  fill_set(imgs,0,m_pano->getNrOfImages()-1);
1031  };
1033  // reset already modified tag
1034  m_needsUpdate = true;
1035  ExpandAll(m_root);
1036  };
1037 };
1038 
1040 {
1041  m_displayMode=newMode;
1042 
1049 
1058 
1068 
1078 
1093 
1094  Refresh();
1095 };
1096 
1097 void ImagesTreeCtrl::OnContextMenu(wxTreeEvent & e)
1098 {
1099  m_selectedColumn=e.GetInt();
1100  wxMenu menu;
1101  bool allowMenuExtension=true;
1102  if(e.GetItem().IsOk())
1103  {
1104  //click on item
1106  {
1107  bool emptyText=GetItemText(e.GetItem(),m_selectedColumn).IsEmpty();
1108  ImagesTreeData* data=static_cast<ImagesTreeData*>(GetItemData(e.GetItem()));
1109  bool varIsLinkable = false;
1110  if (m_groupMode == GROUP_LENS)
1111  {
1112  varIsLinkable = m_variableVector[m_selectedColumn] != HuginBase::ImageVariableGroup::IVE_Yaw &&
1114  }
1115  else
1116  {
1117  if (m_groupMode == GROUP_STACK)
1118  {
1119  varIsLinkable = m_variableVector[m_selectedColumn] == HuginBase::ImageVariableGroup::IVE_Yaw;
1120  }
1121  };
1122  if(varIsLinkable)
1123  {
1124  if(data->IsGroup())
1125  {
1126  if(emptyText)
1127  {
1128  menu.Append(ID_LINK,_("Link"));
1129  Bind(wxEVT_MENU, &ImagesTreeCtrl::OnLinkImageVariables, this, ID_LINK);
1130  }
1131  else
1132  {
1133  menu.Append(ID_UNLINK, _("Unlink"));
1134  Bind(wxEVT_MENU, &ImagesTreeCtrl::OnUnlinkImageVariables, this, ID_UNLINK);
1135  };
1136  }
1137  else
1138  {
1139  if(emptyText)
1140  {
1141  menu.Append(ID_UNLINK,_("Unlink"));
1142  Bind(wxEVT_MENU, &ImagesTreeCtrl::OnUnlinkImageVariables, this, ID_UNLINK);
1143  }
1144  else
1145  {
1146  menu.Append(ID_LINK, _("Link"));
1147  Bind(wxEVT_MENU, &ImagesTreeCtrl::OnLinkImageVariables, this, ID_LINK);
1148  };
1149  };
1150  menu.AppendSeparator();
1151  };
1152  if(m_optimizerMode)
1153  {
1154  if(data->IsGroup() == emptyText)
1155  {
1156  if(m_groupMode==GROUP_LENS && m_variableVector[m_selectedColumn]!=HuginBase::ImageVariableGroup::IVE_Yaw)
1157  {
1158  menu.Append(ID_SELECT_LENS_STACK, _("Select all for current lens"));
1159  Bind(wxEVT_MENU, &ImagesTreeCtrl::OnSelectLensStack, this, ID_SELECT_LENS_STACK);
1160  menu.Append(ID_UNSELECT_LENS_STACK, _("Unselect all for current lens"));
1162  };
1163  if(m_groupMode==GROUP_STACK && m_variableVector[m_selectedColumn]==HuginBase::ImageVariableGroup::IVE_Yaw)
1164  {
1165  menu.Append(ID_SELECT_LENS_STACK, _("Select all for current stack"));
1166  Bind(wxEVT_MENU, &ImagesTreeCtrl::OnSelectLensStack, this, ID_SELECT_LENS_STACK);
1167  menu.Append(ID_UNSELECT_LENS_STACK, _("Unselect all for current stack"));
1169  };
1170  };
1171  if(m_columnVector[m_selectedColumn]!="cam_trans")
1172  {
1173  menu.Append(ID_SELECT_ALL, _("Select all"));
1174  Bind(wxEVT_MENU, &ImagesTreeCtrl::OnSelectAll, this, ID_SELECT_ALL);
1175  };
1176  menu.Append(ID_UNSELECT_ALL, _("Unselect all"));
1177  Bind(wxEVT_MENU, &ImagesTreeCtrl::OnUnselectAll, this, ID_UNSELECT_ALL);
1178  menu.AppendSeparator();
1179  }
1180  };
1181  menu.Append(ID_EDIT, _("Edit image variables..."));
1182  // handler for ID_EDIT is already Bind() in ImagesTreeCtrl::Create to make it work with double click,
1183  // so no need to call Bind again
1185  {
1186  const HuginBase::UIntSet selectedImages = GetSelectedImages();
1187  if (selectedImages.size() == 1)
1188  {
1189  if (m_pano->getImage(*selectedImages.begin()).getActive())
1190  {
1191  menu.Append(ID_DEACTIVATE_IMAGE, _("Deactivate image"));
1192  Bind(wxEVT_MENU, &ImagesTreeCtrl::OnDeactivateImage, this, ID_DEACTIVATE_IMAGE);
1193  }
1194  else
1195  {
1196  menu.Append(ID_ACTIVATE_IMAGE, _("Activate image"));
1197  Bind(wxEVT_MENU, &ImagesTreeCtrl::OnActivateImage, this, ID_ACTIVATE_IMAGE);
1198  };
1199  }
1200  else
1201  {
1202  menu.Append(ID_ACTIVATE_IMAGE, _("Activate images"));
1203  Bind(wxEVT_MENU, &ImagesTreeCtrl::OnActivateImage, this, ID_ACTIVATE_IMAGE);
1204  menu.Append(ID_DEACTIVATE_IMAGE, _("Deactivate images"));
1205  Bind(wxEVT_MENU, &ImagesTreeCtrl::OnDeactivateImage, this, ID_DEACTIVATE_IMAGE);
1206  };
1207  };
1208  }
1209  else
1210  {
1211  if(m_optimizerMode && set_contains(m_editableColumns, e.GetInt()))
1212  {
1213  if(m_columnVector[m_selectedColumn]!="cam_trans")
1214  {
1215  menu.Append(ID_SELECT_ALL, _("Select all"));
1216  Bind(wxEVT_MENU, &ImagesTreeCtrl::OnSelectAll, this, ID_SELECT_ALL);
1217  };
1218  menu.Append(ID_UNSELECT_ALL, _("Unselect all"));
1219  Bind(wxEVT_MENU, &ImagesTreeCtrl::OnUnselectAll, this, ID_UNSELECT_ALL);
1220  allowMenuExtension=false;
1221  }
1222  };
1223  if(allowMenuExtension)
1224  {
1225  if(menu.GetMenuItemCount()>0)
1226  {
1227  menu.AppendSeparator();
1228  };
1229  int id=ID_OPERATION_START;
1230  m_menuOperation.clear();
1232  wxMenu* subMenu=new wxMenu();
1234  if(subMenu->GetMenuItemCount()>0)
1235  {
1236  menu.Append(-1,_("Lens"), subMenu);
1237  }
1238  else
1239  {
1240  delete subMenu;
1241  };
1243  {
1244  subMenu=new wxMenu();
1246  if(subMenu->GetMenuItemCount()>0)
1247  {
1248  menu.Append(-1,_("Stacks"), subMenu);
1249  }
1250  else
1251  {
1252  delete subMenu;
1253  };
1254  };
1255  subMenu=new wxMenu();
1257  if(subMenu->GetMenuItemCount()>0)
1258  {
1259  menu.Append(-1, _("Control points"), subMenu);
1260  }
1261  else
1262  {
1263  delete subMenu;
1264  };
1265  subMenu=new wxMenu();
1267  if(subMenu->GetMenuItemCount()>0)
1268  {
1269  menu.Append(-1, _("Reset"), subMenu);
1270  }
1271  else
1272  {
1273  delete subMenu;
1274  };
1275  };
1276  if(menu.GetMenuItemCount()>0)
1277  {
1278  PopupMenu(&menu);
1279  };
1280  e.Skip();
1281 };
1282 
1284 {
1286  for(size_t i=0; i<operations->size(); i++)
1287  {
1288  if((*operations)[i]->IsEnabled(*m_pano, imgs, m_guiLevel))
1289  {
1290  menu->Append(id, (*operations)[i]->GetLabel());
1291  m_menuOperation[id]=(*operations)[i];
1292  Bind(wxEVT_MENU, &ImagesTreeCtrl::OnExecuteOperation, this, id);
1293  id++;
1294  }
1295  };
1296 }
1297 
1299 {
1300  const wxColour normalColour = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
1301  const wxColour disabledColour = wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT);
1303  {
1304  wxTreeItemIdValue cookie;
1305  wxTreeItemId item = GetFirstChild(m_root, cookie);
1306  while (item.IsOk())
1307  {
1308  ImagesTreeData* itemData = static_cast<ImagesTreeData*>(GetItemData(item));
1309  bool isActive = true;
1310  if (itemData->IsGroup())
1311  {
1312  wxTreeItemIdValue childCookie;
1313  wxTreeItemId child = GetFirstChild(item, childCookie);
1314  while (child.IsOk())
1315  {
1316  ImagesTreeData* childItemData = static_cast<ImagesTreeData*>(GetItemData(child));
1317  isActive = m_pano->getImage(childItemData->GetImgNr()).getActive();
1318  if (isActive)
1319  {
1320  break;
1321  };
1322  child = GetNextChild(item, childCookie);
1323  };
1324  }
1325  else
1326  {
1327  isActive = m_pano->getImage(itemData->GetImgNr()).getActive();
1328  };
1329  if (isActive)
1330  {
1331  SetItemTextColour(item, normalColour);
1332  }
1333  else
1334  {
1335  SetItemTextColour(item, disabledColour);
1336  };
1337  if(itemData->IsGroup())
1338  {
1339  wxTreeItemIdValue childCookie;
1340  wxTreeItemId child = GetFirstChild(item, childCookie);
1341  while (child.IsOk())
1342  {
1343  ImagesTreeData* childItemData = static_cast<ImagesTreeData*>(GetItemData(child));
1344  if (m_pano->getImage(childItemData->GetImgNr()).getActive())
1345  {
1346  SetItemTextColour(child, normalColour);
1347  }
1348  else
1349  {
1350  SetItemTextColour(child, disabledColour);
1351  };
1352  child = GetNextChild(item, childCookie);
1353  };
1354  };
1355  item = GetNextChild(m_root, cookie);
1356  };
1357  }
1358  else
1359  {
1360  wxTreeItemIdValue cookie;
1361  wxTreeItemId item = GetFirstChild(m_root, cookie);
1362  while (item.IsOk())
1363  {
1364  ImagesTreeData* itemData=static_cast<ImagesTreeData*>(GetItemData(item));
1365  SetItemTextColour(item, normalColour);
1366  if (itemData->IsGroup())
1367  {
1368  wxTreeItemIdValue childCookie;
1369  wxTreeItemId child = GetFirstChild(item, childCookie);
1370  while (child.IsOk())
1371  {
1372  SetItemTextColour(child, normalColour);
1373  child = GetNextChild(item, childCookie);
1374  };
1375  };
1376  item = GetNextChild(m_root, cookie);
1377  };
1378  };
1379 };
1380 
1382 {
1383  m_selectedColumn=e.GetColumn();
1384  wxMenu menu;
1386  {
1387  menu.Append(ID_SELECT_ALL, _("Select all"));
1388  Bind(wxEVT_MENU, &ImagesTreeCtrl::OnSelectAll, this, ID_SELECT_ALL);
1389  menu.Append(ID_UNSELECT_ALL, _("Unselect all"));
1390  Bind(wxEVT_MENU, &ImagesTreeCtrl::OnUnselectAll, this, ID_UNSELECT_ALL);
1391  PopupMenu(&menu);
1392  };
1393  e.Skip();
1394 }
1395 void ImagesTreeCtrl::OnActivateImage(wxCommandEvent & e)
1396 {
1397  HuginBase::UIntSet activeImages = m_pano->getActiveImages();
1398  const HuginBase::UIntSet selectedImages = GetSelectedImages();
1399  std::copy(selectedImages.begin(), selectedImages.end(), std::inserter(activeImages, activeImages.end()));
1401  new PanoCommand::SetActiveImagesCmd(*m_pano, activeImages)
1402  );
1403 };
1404 
1405 void ImagesTreeCtrl::OnDeactivateImage(wxCommandEvent & e)
1406 {
1407  HuginBase::UIntSet activeImages = m_pano->getActiveImages();
1408  const HuginBase::UIntSet selectedImages = GetSelectedImages();
1409  HuginBase::UIntSet newActiveImages;
1410  std::set_difference(activeImages.begin(), activeImages.end(), selectedImages.begin(), selectedImages.end(), std::inserter(newActiveImages, newActiveImages.end()));
1412  new PanoCommand::SetActiveImagesCmd(*m_pano, newActiveImages)
1413  );
1414 };
1415 
1417 {
1419  if(!images.empty() && m_variableVector[m_selectedColumn]!=HuginBase::ImageVariableGroup::IVE_Filename)
1420  {
1421  std::set<HuginBase::ImageVariableGroup::ImageVariableEnum> variables;
1422  variables.insert(m_variableVector[m_selectedColumn]);
1423  if(m_variableVector[m_selectedColumn]==HuginBase::ImageVariableGroup::IVE_Yaw)
1424  {
1425  variables.insert(HuginBase::ImageVariableGroup::IVE_Pitch);
1426  variables.insert(HuginBase::ImageVariableGroup::IVE_Roll);
1427  variables.insert(HuginBase::ImageVariableGroup::IVE_X);
1428  variables.insert(HuginBase::ImageVariableGroup::IVE_Y);
1429  variables.insert(HuginBase::ImageVariableGroup::IVE_Z);
1430  variables.insert(HuginBase::ImageVariableGroup::IVE_TranslationPlaneYaw);
1431  variables.insert(HuginBase::ImageVariableGroup::IVE_TranslationPlanePitch);
1432  };
1433  if(m_groupMode==GROUP_LENS)
1434  {
1437  );
1438  }
1439  else
1440  {
1443  );
1444  };
1445  };
1446 };
1447 
1449 {
1450  UnLinkImageVariables(true);
1451 };
1452 
1454 {
1455  UnLinkImageVariables(false);
1456 };
1457 
1459 {
1461  if(!imgs.empty())
1462  {
1463  ImageVariableDialog dlg(this, m_pano, imgs);
1464  dlg.SetGuiLevel(m_guiLevel);
1465  switch(m_displayMode)
1466  {
1467  case DISPLAY_LENS:
1468  dlg.SelectTab(1);
1469  break;
1470  case DISPLAY_PHOTOMETRICS:
1473  if(m_selectedColumn==m_columnMap["response"] ||
1474  m_selectedColumn==m_columnMap["Ra"] ||
1475  m_selectedColumn==m_columnMap["Rb"] ||
1476  m_selectedColumn==m_columnMap["Rc"] ||
1477  m_selectedColumn==m_columnMap["Rd"] ||
1478  m_selectedColumn==m_columnMap["Re"] )
1479  {
1480  dlg.SelectTab(3);
1481  }
1482  else
1483  {
1484  dlg.SelectTab(2);
1485  };
1486  break;
1487  default:
1488  break;
1489  };
1490  dlg.ShowModal();
1491  };
1492 };
1493 
1494 void ImagesTreeCtrl::OnBeginDrag(wxTreeEvent &e)
1495 {
1496  const bool ctrlPressed=wxGetKeyState(WXK_COMMAND);
1497  if(m_pano->getNrOfImages()>0 && !m_dragging)
1498  {
1500  if(!m_draggingImages.empty())
1501  {
1502  if((m_groupMode==GROUP_NONE && m_draggingImages.size()==1 && !ctrlPressed) ||
1504  {
1505  e.Allow();
1506  SetCursor(wxCURSOR_HAND);
1507  m_dragging=true;
1508  };
1509  };
1510  };
1511 };
1512 
1513 void ImagesTreeCtrl::OnLeftUp(wxMouseEvent &e)
1514 {
1515  //we can't use wxEVT_TREE_END_DRAG because this event is fire several times, e.g. when
1516  // the mouse leaves the area of the tree
1517  // so we are listing to left mouse up, as described in documentation
1518  if(m_dragging)
1519  {
1520  SetCursor(wxCURSOR_ARROW);
1521  m_dragging=false;
1522  wxTreeItemId item=HitTest(e.GetPosition());
1523  if(m_groupMode==GROUP_NONE)
1524  {
1525  size_t img1=*m_draggingImages.begin();
1526  size_t img2=-1;
1527  if(item.IsOk())
1528  {
1529  ImagesTreeData* data=static_cast<ImagesTreeData*>(GetItemData(item));
1530  img2=data->GetImgNr();
1531  }
1532  else
1533  {
1534  //we are checking the points above, if we find then
1535  // an item, the user drop it below the last item, if not
1536  // the drop happened right beside the item
1537  wxPoint pos(e.GetPosition());
1538  pos.y-=10;
1539  while(pos.y>0)
1540  {
1541  item=HitTest(pos);
1542  if(item.IsOk())
1543  {
1544  img2=m_pano->getNrOfImages()-1;
1545  break;
1546  };
1547  pos.y-=10;
1548  };
1549  };
1550  if(img2!=-1)
1551  {
1552  if(img1!=img2)
1553  {
1555  new PanoCommand::MoveImageCmd(*m_pano, img1, img2)
1556  );
1557  // now update drag images groups in fast preview window, this information is not stored in Panorama class
1559  if (!images.empty() && images.size() < m_pano->getNrOfImages())
1560  {
1561  std::vector<bool> imgList(m_pano->getNrOfImages(), false);
1562  for (auto& i : images)
1563  {
1564  imgList[i] = true;
1565  };
1566  const bool moveImageChecked = imgList[img1];
1567  imgList.erase(imgList.begin() + img1);
1568  if (img2 < imgList.size())
1569  {
1570  imgList.insert(imgList.begin() + img2, moveImageChecked);
1571  }
1572  else
1573  {
1574  imgList.push_back(moveImageChecked);
1575  };
1576  images.clear();
1577  for (size_t i = 0; i < imgList.size(); ++i)
1578  {
1579  if (imgList[i])
1580  {
1581  images.insert(i);
1582  };
1583  };
1584  MainFrame::Get()->getGLPreview()->SetDragGroupImages(images, true);
1585  };
1586  };
1587  };
1588  }
1589  else
1590  {
1591  //dragging to stack/lenses
1592  if(item.IsOk())
1593  {
1594  ImagesTreeData* data=static_cast<ImagesTreeData*>(GetItemData(item));
1595  long groupNr=-1;
1596  if(data->IsGroup())
1597  {
1598  groupNr=data->GetGroupNr();
1599  }
1600  else
1601  {
1602  item=GetItemParent(item);
1603  if(item.IsOk())
1604  {
1605  data=static_cast<ImagesTreeData*>(GetItemData(item));
1606  groupNr=data->GetGroupNr();
1607  };
1608  };
1609  if(groupNr>=0)
1610  {
1611  if(m_groupMode==GROUP_LENS)
1612  {
1615  );
1616  }
1617  else
1618  {
1621  );
1622  };
1623  };
1624  }
1625  else // item not ok, drop not on existing item, create new lens/stack
1626  {
1627  if(m_groupMode==GROUP_LENS)
1628  {
1631  );
1632  }
1633  else
1634  {
1637  );
1638  }
1639  };
1640  }
1641  m_draggingImages.clear();
1642  }
1643  else
1644  {
1645  if (m_optimizerMode && m_leftDownItem.IsOk())
1646  {
1647  int flags;
1648  int col;
1649  wxTreeItemId item = HitTest(e.GetPosition(), flags, col);
1650  // check if left up is on the same item as left down
1651  if (item.IsOk() && item == m_leftDownItem && col == m_leftDownColumn && (flags & wxTREE_HITTEST_ONITEMICON))
1652  {
1653  HuginBase::UIntSet imgs;
1654  const bool markSelected = IsSelected(m_leftDownItem);
1655  if (markSelected)
1656  {
1657  // if the user clicked on one of the selected pass the selection to all selected images
1658  imgs = GetSelectedImages();
1659  }
1660  else
1661  {
1662  // the user clicked on a non-selected images, work only on this image
1663  // or all images of the clicked lens/stack
1665  if (data->IsGroup())
1666  {
1667  wxTreeItemIdValue cookie;
1668  wxTreeItemId childItem = GetFirstChild(m_leftDownItem, cookie);
1669  while (childItem.IsOk())
1670  {
1671  data = static_cast<ImagesTreeData*>(GetItemData(childItem));
1672  imgs.insert(data->GetImgNr());
1673  childItem = GetNextChild(m_leftDownItem, cookie);
1674  };
1675  }
1676  else
1677  {
1678  imgs.insert(data->GetImgNr());
1679  };
1680  };
1682  std::set<std::string> var;
1683  if (m_columnVector[m_leftDownColumn] == "cam_trans")
1684  {
1685  var.insert("TrX");
1686  var.insert("TrY");
1687  var.insert("TrZ");
1688  var.insert("Tpy");
1689  var.insert("Tpp");
1690  }
1691  else
1692  {
1693  var.insert(m_columnVector[m_leftDownColumn]);
1694  if (m_columnVector[m_leftDownColumn] == "Tpy" || m_columnVector[m_leftDownColumn] == "Tpp")
1695  {
1696  var.insert("Tpy");
1697  var.insert("Tpp");
1698  };
1699  if (m_columnVector[m_leftDownColumn] == "Vb" || m_columnVector[m_leftDownColumn] == "Vc" || m_columnVector[m_leftDownColumn] == "Vd")
1700  {
1701  var.insert("Vb");
1702  var.insert("Vc");
1703  var.insert("Vd");
1704  };
1705  if (m_columnVector[m_leftDownColumn] == "Vx" || m_columnVector[m_leftDownColumn] == "Vy")
1706  {
1707  var.insert("Vx");
1708  var.insert("Vy");
1709  };
1710  if (m_columnVector[m_leftDownColumn] == "Ra" || m_columnVector[m_leftDownColumn] == "Rb" || m_columnVector[m_leftDownColumn] == "Rc" ||
1711  m_columnVector[m_leftDownColumn] == "Rd" || m_columnVector[m_leftDownColumn] == "Re")
1712  {
1713  var.insert("Ra");
1714  var.insert("Rb");
1715  var.insert("Rc");
1716  var.insert("Rd");
1717  var.insert("Re");
1718  };
1719  };
1720  bool deactivate = false;
1721  if (markSelected)
1722  {
1723  // check which state the clicked image have
1724  deactivate = GetItemImage(m_leftDownItem, m_leftDownColumn) & 1;
1725  }
1726  else
1727  {
1728  for (std::set<std::string>::const_iterator varIt = var.begin(); varIt != var.end(); ++varIt)
1729  {
1730  //search, if image variable is marked for optimise for at least one image of group
1731  for (HuginBase::UIntSet::const_iterator imgIt = imgs.begin(); imgIt != imgs.end() && !deactivate; ++imgIt)
1732  {
1733  if (set_contains(optVec[*imgIt], *varIt))
1734  {
1735  deactivate = true;
1736  };
1737  };
1738  };
1739  };
1740  // now deactivate or activate the image variable for optimisation
1741  if (deactivate)
1742  {
1743  for (std::set<std::string>::const_iterator varIt = var.begin(); varIt != var.end(); ++varIt)
1744  {
1745  for (HuginBase::UIntSet::const_iterator imgIt = imgs.begin(); imgIt != imgs.end(); ++imgIt)
1746  {
1747  optVec[*imgIt].erase(*varIt);
1748  };
1749  }
1750  }
1751  else
1752  {
1753  for (std::set<std::string>::const_iterator varIt = var.begin(); varIt != var.end(); ++varIt)
1754  {
1755  for (HuginBase::UIntSet::const_iterator imgIt = imgs.begin(); imgIt != imgs.end(); ++imgIt)
1756  {
1757  optVec[*imgIt].insert(*varIt);
1758  };
1759  };
1760  };
1763  );
1764  m_leftDownItem.Unset();
1765  return;
1766  };
1767  };
1768  if (m_leftDownItem.IsOk())
1769  {
1770  m_leftDownItem.Unset();
1771  };
1772  e.Skip();
1773  };
1774 };
1775 
1776 void ImagesTreeCtrl::OnLeftDown(wxMouseEvent &e)
1777 {
1778  if (!m_dragging)
1779  {
1780  if (e.LeftDown())
1781  {
1782  // force end editing
1783  EndEdit(false);
1784  // find where user clicked
1785  int flags;
1786  int col;
1787  wxTreeItemId item = HitTest(e.GetPosition(), flags, col);
1788  if (item.IsOk() && (flags & wxTREE_HITTEST_ONITEMICON))
1789  {
1790  if (set_contains(m_editableColumns, col))
1791  {
1792  if (!GetItemText(item, col).IsEmpty())
1793  {
1794  // store for later and stop processing this event further
1795  m_leftDownItem = item;
1796  m_leftDownColumn = col;
1797  return;
1798  };
1799  };
1800  };
1801  };
1802  };
1803  e.Skip();
1804 };
1805 
1806 void ImagesTreeCtrl::OnMouseMove(wxMouseEvent &e)
1807 {
1808  int flags;
1809  int col;
1810  wxTreeItemId item = HitTest(e.GetPosition(), flags, col);
1811  if (item.IsOk() && (flags & wxTREE_HITTEST_ONITEMICON))
1812  {
1813  // mouse moved over optimizer checkbox
1814  int imgNr = GetItemImage(item, col);
1815  if (imgNr >= 0 && imgNr < 2)
1816  {
1817  // update checkbox image and store position for later
1818  SetItemImage(item, col, imgNr + 2);
1819  m_lastCurrentItem = item;
1820  m_lastCurrentCol = col;
1821  };
1822  }
1823  else
1824  {
1825  // mouse moved from checkbox away, so update images
1826  if (m_lastCurrentItem.IsOk())
1827  {
1829  if (imgNr > 1)
1830  {
1832  };
1833  m_lastCurrentItem.Unset();
1834  };
1835  };
1836  e.Skip();
1837 };
1838 
1839 void ImagesTreeCtrl::SelectAllParameters(bool select, bool allImages)
1840 {
1841  std::set<std::string> imgVars;
1842  std::string var=m_columnVector[m_selectedColumn];
1843  if(var=="cam_trans")
1844  {
1845  imgVars.insert("TrX");
1846  imgVars.insert("TrY");
1847  imgVars.insert("TrZ");
1848  imgVars.insert("Tpy");
1849  imgVars.insert("Tpp");
1850  }
1851  else
1852  {
1853  imgVars.insert(var);
1854  if(var=="Vb" || var=="Vc" || var=="Vd")
1855  {
1856  imgVars.insert("Vb");
1857  imgVars.insert("Vc");
1858  imgVars.insert("Vd");
1859  };
1860  if(var=="Vx" || var=="Vy")
1861  {
1862  imgVars.insert("Vx");
1863  imgVars.insert("Vy");
1864  };
1865  if(var=="Ra" || var=="Rb" || var=="Rc" || var=="Rd" || var=="Re")
1866  {
1867  imgVars.insert("Ra");
1868  imgVars.insert("Rb");
1869  imgVars.insert("Rc");
1870  imgVars.insert("Rd");
1871  imgVars.insert("Re");
1872  };
1873 
1874  };
1875 
1876  HuginBase::UIntSet imgs;
1877  if(allImages)
1878  {
1879  fill_set(imgs, 0, m_pano->getNrOfImages()-1);
1880  }
1881  else
1882  {
1883  wxArrayTreeItemIds selectedItem;
1884  if(GetSelections(selectedItem)>0)
1885  {
1886  for(size_t i=0;i<selectedItem.size();i++)
1887  {
1888  ImagesTreeData* data=static_cast<ImagesTreeData*>(GetItemData(selectedItem[i]));
1889  wxTreeItemId startItem;
1890  if(data->IsGroup())
1891  {
1892  startItem=selectedItem[i];
1893  }
1894  else
1895  {
1896  startItem=GetItemParent(selectedItem[i]);
1897  };
1898  wxTreeItemIdValue cookie;
1899  wxTreeItemId item=GetFirstChild(startItem,cookie);
1900  while(item.IsOk())
1901  {
1902  data=static_cast<ImagesTreeData*>(GetItemData(item));
1903  imgs.insert(data->GetImgNr());
1904  item=GetNextChild(startItem, cookie);
1905  };
1906  };
1907  };
1908  };
1909 
1911  for(HuginBase::UIntSet::iterator img=imgs.begin(); img!=imgs.end(); ++img)
1912  {
1913  for(std::set<std::string>::const_iterator it=imgVars.begin(); it!=imgVars.end(); ++it)
1914  {
1915  if(select)
1916  {
1917  if((*it=="y" || *it=="p" || *it=="r" || *it=="TrX" || *it=="TrY" || *it=="TrZ" || *it=="Tpy" || *it=="Tpp") &&
1919  {
1920  optVec[*img].erase(*it);
1921  continue;
1922  };
1923  if(*it=="Eev" && (*img==m_pano->getOptions().colorReferenceImage || m_pano->getImage(*img).ExposureValueisLinkedWith(m_pano->getImage(m_pano->getOptions().colorReferenceImage))))
1924  {
1925  optVec[*img].erase(*it);
1926  continue;
1927  };
1928  if (*it == "Er" && (*img == m_pano->getOptions().colorReferenceImage || m_pano->getImage(*img).WhiteBalanceRedisLinkedWith(m_pano->getImage(m_pano->getOptions().colorReferenceImage))))
1929  {
1930  optVec[*img].erase(*it);
1931  continue;
1932  };
1933  if (*it == "Eb" && (*img == m_pano->getOptions().colorReferenceImage || m_pano->getImage(*img).WhiteBalanceBlueisLinkedWith(m_pano->getImage(m_pano->getOptions().colorReferenceImage))))
1934  {
1935  optVec[*img].erase(*it);
1936  continue;
1937  };
1938  optVec[*img].insert(*it);
1939  }
1940  else
1941  {
1942  optVec[*img].erase(*it);
1943  };
1944  };
1945  };
1948  );
1949 };
1950 
1951 void ImagesTreeCtrl::OnSelectAll(wxCommandEvent &e)
1952 {
1953  SelectAllParameters(true, true);
1954 };
1955 
1956 void ImagesTreeCtrl::OnUnselectAll(wxCommandEvent &e)
1957 {
1958  SelectAllParameters(false, true);
1959 };
1960 
1961 void ImagesTreeCtrl::OnSelectLensStack(wxCommandEvent &e)
1962 {
1963  SelectAllParameters(true, false);
1964 };
1965 
1967 {
1968  SelectAllParameters(false, false);
1969 };
1970 
1971 void ImagesTreeCtrl::OnChar(wxTreeEvent &e)
1972 {
1973  switch(e.GetKeyCode())
1974  {
1975  case WXK_INSERT:
1976  {
1977  wxCommandEvent ev(wxEVT_COMMAND_MENU_SELECTED, XRCID("action_add_images"));
1978  MainFrame::Get()->GetEventHandler()->AddPendingEvent(ev);
1979  break;
1980  };
1981  case WXK_DELETE:
1982  {
1984  if(!imgs.empty())
1985  {
1986  // remove all marked images from cache
1987  for (auto& img : imgs)
1988  {
1989  ImageCache::getInstance().removeImage(m_pano->getImage(img).getFilename());
1990  };
1991  // now remove images from panorama object
1994  );
1995  };
1996  break;
1997  };
1998 #if defined __WXMAC__
1999  case 'A':
2000  case 'a':
2001  // check for cmd+A -> select all
2002  if (e.GetExtraLong() == wxMOD_CMD)
2003  {
2004  SelectAll();
2005  };
2006  break;
2007 #endif
2008  case 1: //Ctrl+A
2009  {
2010  SelectAll();
2011  break;
2012  }
2013  default:
2014  e.Skip();
2015  };
2016 };
2017 
2018 void ImagesTreeCtrl::OnBeginEdit(wxTreeEvent &e)
2019 {
2020  m_editOldString=GetItemText(e.GetItem(), e.GetInt());
2021  if(m_editOldString.IsEmpty())
2022  {
2023  e.Veto();
2024  }
2025  else
2026  {
2027  ImagesTreeData* data=static_cast<ImagesTreeData*>(GetItemData(e.GetItem()));
2028  if(data->IsGroup())
2029  {
2030  wxTreeItemIdValue cookie;
2031  wxTreeItemId item=GetFirstChild(e.GetItem(), cookie);
2032  data=static_cast<ImagesTreeData*>(GetItemData(item));
2033  };
2034  m_editVal=m_pano->getImage(data->GetImgNr()).getVar(m_columnVector[e.GetInt()]);
2035  SetItemText(e.GetItem(), e.GetInt(), hugin_utils::doubleTowxString(m_editVal));
2036  e.Allow();
2037  };
2038 };
2039 
2040 void ImagesTreeCtrl::OnEndEdit(wxTreeEvent &e)
2041 {
2042  if(e.IsEditCancelled())
2043  {
2044  //restore old string
2045  SetItemText(e.GetItem(), e.GetInt(), m_editOldString);
2046  Refresh();
2047  }
2048  else
2049  {
2050  double val;
2051  if(!hugin_utils::str2double(e.GetLabel(),val))
2052  {
2053  //restore old string
2054  SetItemText(e.GetItem(), e.GetInt(), m_editOldString);
2055  Refresh();
2056  e.Veto();
2057  }
2058  else
2059  {
2060  //only update if value was changed
2061  if(val!=m_editVal)
2062  {
2063  ImagesTreeData* data=static_cast<ImagesTreeData*>(GetItemData(e.GetItem()));
2064  if(data->IsGroup())
2065  {
2066  wxTreeItemIdValue cookie;
2067  wxTreeItemId item=GetFirstChild(e.GetItem(), cookie);
2068  data=static_cast<ImagesTreeData*>(GetItemData(item));
2069  };
2070  HuginBase::UIntSet imgs;
2071  imgs.insert(data->GetImgNr());
2072  if(m_columnVector[e.GetInt()]=="v")
2073  {
2074  if(m_pano->getImage(data->GetImgNr()).getProjection()==HuginBase::SrcPanoImage::FISHEYE_ORTHOGRAPHIC && val>190)
2075  {
2076  if(wxMessageBox(
2077  wxString::Format(_("You have given a field of view of %.2f degrees.\n But the orthographic projection is limited to a field of view of 180 degress.\nDo you want still use that high value?"), val),
2078 #ifdef __WXMSW__
2079  _("Hugin"),
2080 #else
2081  wxT(""),
2082 #endif
2083  wxICON_EXCLAMATION | wxYES_NO)==wxNO)
2084  {
2085  //restore old string
2086  SetItemText(e.GetItem(), e.GetInt(), m_editOldString);
2087  Refresh();
2088  e.Veto();
2089  e.Skip();
2090  return;
2091  };
2092  };
2093  };
2094  HuginBase::Variable var(m_columnVector[e.GetInt()], val);
2096  new PanoCommand::SetVariableCmd(*m_pano, imgs, var)
2097  );
2098  //we need to veto the event otherwise the internal
2099  //function does update the text to the full number
2100  e.Veto();
2101  }
2102  else
2103  {
2104  //restore old string
2105  SetItemText(e.GetItem(), e.GetInt(), m_editOldString);
2106  Refresh();
2107  };
2108  };
2109  };
2110  e.Skip();
2111 };
2112 
2113 void ImagesTreeCtrl::OnExecuteOperation(wxCommandEvent & e)
2114 {
2117  if(cmd!=NULL)
2118  {
2120  };
2121 };
2122 
2123 void ImagesTreeCtrl::OnLeftDblClick(wxMouseEvent &e)
2124 {
2125  if(!m_optimizerMode)
2126  {
2127  int flags;
2128  int col;
2129  wxTreeItemId item=HitTest(e.GetPosition(), flags, col);
2130  m_selectedColumn=col;
2131  wxCommandEvent commandEvent(wxEVT_COMMAND_MENU_SELECTED, ID_EDIT);
2132  GetEventHandler()->AddPendingEvent(commandEvent);
2133  };
2134  e.Skip();
2135 };
2136 
2137 IMPLEMENT_DYNAMIC_CLASS(ImagesTreeCtrl, wxTreeListCtrl)
2138 
2140  : wxTreeListCtrlXmlHandler()
2141 {
2142 }
2143 
2145 {
2146  XRC_MAKE_INSTANCE(cp, ImagesTreeCtrl)
2147 
2148  cp->Create(m_parentAsWindow,
2149  GetID(),
2150  GetPosition(), GetSize(),
2151  GetStyle(wxT("style")),
2152  GetName());
2153 
2154  SetupWindow( cp);
2155 
2156  return cp;
2157 }
2158 
2160 {
2161  return IsOfClass(node, wxT("ImagesTreeList"));
2162 }
2163 
2164 IMPLEMENT_DYNAMIC_CLASS(ImagesTreeCtrlXmlHandler, wxTreeListCtrlXmlHandler)
2165 
2166 
HuginBase::UIntSet GetDragGroupImages()
ImagesTreeCtrl()
general constructor
Definition: ImagesTree.cpp:75
Base class for all panorama commands.
Definition: Command.h:38
void Refresh(bool erase=TRUE, const wxRect *rect=NULL)
std::map< std::string, size_t > m_columnMap
map for easier access to column information
Definition: ImagesTree.h:188
static const std::set< ConstImageVariableGroup::ImageVariableEnum > & getLensVariables()
Get the set of lens image variables.
void OnChar(wxTreeEvent &e)
event handler for key events
GroupMode m_groupMode
the active group mode
Definition: ImagesTree.h:170
std::vector< UIntSet > getHDRStacks(const PanoramaData &pano, UIntSet allImgs, PanoramaOptions opts)
returns vector of set of output stacks
Definition: LayerStacks.cpp:35
implementation of huginApp Class
declaration of functions to handle stacks and layers
void SetGroupMode(GroupMode newMode)
sets the group mode to given mode
std::vector< UIntSet > UIntSetVector
Definition: PanoramaData.h:56
std::vector< UIntSet > getExposureLayers(const PanoramaData &pano, UIntSet allImgs, PanoramaOptions opts)
returns vector of set of output exposure layers
Definition: LayerStacks.cpp:96
void OnHeaderContextMenu(wxListEvent &e)
event handler for context menu on header
size_t GetChildrenCount(const wxTreeItemId &item, bool recursively=true)
move image from position1 to position2
Definition: PanoCommand.h:361
virtual PanoCommand::PanoCommand * GetCommand(wxWindow *parent, HuginBase::Panorama &pano, HuginBase::UIntSet images, GuiLevel guiLevel)
returns the appropriate PanoCommand::PanoCommand to be inserted into GlobalCmdHistory, checks if operation is enabled
unsigned int getPartNumber(unsigned int imageNr) const
Get a part number from an image number.
Change the linking of some variables across parts of an ImageVariableGroup containing some specified ...
Definition: PanoCommand.h:524
virtual wxObject * DoCreateResource()
bool str2double(const wxString &s, double &d)
Definition: wxPlatform.cpp:37
void OnEndEdit(wxTreeEvent &e)
event handler for ending editing, updates the Panorama with modified value
void OnLeftDown(wxMouseEvent &e)
event handler for left mouse down, handles toggle of optimizer variables
void OnExecuteOperation(wxCommandEvent &e)
menu event handler for PanoOperation (context menu items)
void OnLeftUp(wxMouseEvent &e)
event handler for left up, handles end of dragging and updates of optimizer variables states ...
DisplayMode m_displayMode
the active display mode
Definition: ImagesTree.h:186
void SetGuiLevel(GuiLevel newLevel)
sets the GuiLevel
declaration of main image tree control
void SetColumnWidth(int column, int width)
bool removeObserver(PanoramaObserver *observer)
remove a panorama observer.
Definition: Panorama.cpp:1551
#define HUGIN_CONV_FILENAME
Definition: platform.h:40
ImageVariableGroup & getStacks()
Get the ImageVariableGroup representing the group of stack variables.
bool m_dragging
true, if dragging
Definition: ImagesTree.h:202
void UpdateGroup(wxTreeItemId parent, const HuginBase::UIntSet imgs, HuginBase::UIntSet &changed)
updates the given group, updates number of images and the images itself
Definition: ImagesTree.cpp:778
#define DEBUG_TRACE(msg)
Definition: utils.h:67
std::vector< HuginBase::ImageVariableGroup::ImageVariableEnum > m_variableVector
vector for easier access to linking information
Definition: ImagesTree.h:194
Somewhere to specify what variables belong to what.
wxTreeItemId AppendItem(const wxTreeItemId &parent, const wxString &text, int image=-1, int selectedImage=-1, wxTreeItemData *data=NULL)
void OnUnlinkImageVariables(wxCommandEvent &e)
event handler for unlinking image variables
wxTreeItemId m_root
pointer to root item, not shown
Definition: ImagesTree.h:211
void SetColumnShown(int column, bool shown=true)
some helper classes for graphes
wxTreeItemData * GetItemData(const wxTreeItemId &item) const
void EndEdit(bool isCancelled)
wxTreeItemId AddRoot(const wxString &text, int image=-1, int selectedImage=-1, wxTreeItemData *data=NULL)
void SetImgNr(long newImgNr)
Definition: ImagesTree.cpp:66
virtual void panoramaChanged(HuginBase::Panorama &pano)
receives notification about panorama changes
Definition: ImagesTree.cpp:225
wxString doubleTowxString(double d, int digits)
Definition: wxPlatform.cpp:31
void SelectTab(size_t i)
selects the tab with index i
void DeleteChildren(const wxTreeItemId &item)
a variable has a value and a name.
bool set_contains(const _Container &c, const typename _Container::key_type &key)
Definition: stl_utils.h:74
#define DEBUG_ASSERT(cond)
Definition: utils.h:80
simple class that forward the drop to the mainframe
Definition: MainFrame.h:61
include file for the hugin project
void AssignImageList(wxImageList *imageList)
void SetColumnEditable(int column, bool edit=true)
wxTreeItemId GetLastChild(const wxTreeItemId &item, wxTreeItemIdValue &cookie) const
wxTreeItemId GetItemParent(const wxTreeItemId &item) const
long m_leftDownColumn
Definition: ImagesTree.h:218
wxTreeItemId GetFirstChild(const wxTreeItemId &item, wxTreeItemIdValue &cookie) const
bool m_markDisabledImages
true, if disabled images should be marked with other font color
Definition: ImagesTree.h:184
void OnDeactivateImage(wxCommandEvent &e)
event handler for deactivate image
wxTreeItemId HitTest(const wxPoint &point)
Definition: treelistctrl.h:490
void OnLeftDblClick(wxMouseEvent &e)
event handler for left double click
Declare the ImageVariableGroup and ImageVariableGroupObserver classes.
void OnDpiChanged(wxDPIChangedEvent &e)
event handler for updating dpi
void Init(HuginBase::Panorama *pano)
initialization, connects all control with Panorama, register observer
Definition: ImagesTree.cpp:204
wxTreeItemId m_leftDownItem
stores where left mouse click happend
Definition: ImagesTree.h:217
long m_lastCurrentCol
Definition: ImagesTree.h:215
#define ADDCOLUMN(header, mapName, width, align, isEditable, IVE, tooltip)
std::set< unsigned int > UIntSet
Definition: PanoramaData.h:51
void OnContextMenu(wxTreeEvent &e)
event handler to display context menu
DisplayMode
enumeration for display mode, limits the displayed columns
Definition: ImagesTree.h:49
wxString getResponseString(const HuginBase::SrcPanoImage &img)
Returns translated response type for given SrcPanoImage.
Definition: LensTools.cpp:125
void OnLinkImageVariables(wxCommandEvent &e)
event handler for linking image variables
bool m_needsUpdate
helper variable for update of output stacks/layers
Definition: ImagesTree.h:208
wxTreeItemId GetNext(const wxTreeItemId &item) const
void SetItemImage(const wxTreeItemId &item, int image, wxTreeItemIcon which=wxTreeItemIcon_Normal)
updates the optimize vector, aka all variables which should be optimized
Definition: PanoCommand.h:201
Model for a panorama.
Definition: Panorama.h:152
void MarkActiveImages(const bool markActive)
sets the flag, if active/disabled image should be marked with different colour
Definition: ImagesTree.cpp:928
empirical model of response
Definition: SrcPanoImage.h:100
UIntSetVector getPartsSet() const
return a vector which contains a HuginBase::UIntSet for each group with the corresponding images numb...
void OnBeginEdit(wxTreeEvent &e)
event handler for beginning editing
void UpdateImageText(wxTreeItemId item)
updates the information for the given image in tree
Definition: ImagesTree.cpp:359
wxString m_configClassName
Definition: ImagesTree.h:221
const OptimizeVector & getOptimizeVector() const
return the optimize settings stored inside panorama
Definition: Panorama.h:454
void SetDisplayMode(DisplayMode newMode)
sets the display mode to given mode
Make a new part in a ImageVariableGroup for a set of images, given the variables that make up the gro...
Definition: PanoCommand.h:591
Definition of dialog to edit image variables.
const long GetGroupNr() const
Definition: ImagesTree.cpp:67
bool IsSelected(const wxTreeItemId &item) const
void SetDragGroupImages(HuginBase::UIntSet imageDragGroup_in, bool update_check_box=true)
void UnLinkImageVariables(bool linked)
helper procedure for link/unlink image variables
std::size_t getNrOfImages() const
number of images.
Definition: Panorama.h:205
static MainFrame * Get()
hack.. kind of a pseudo singleton...
Definition: MainFrame.cpp:2153
std::vector< unsigned int > getCtrlPointsForImage(unsigned int imgNr) const
return all control points for a given image.
Definition: Panorama.cpp:83
GroupMode
enumeration for grouping mode
Definition: ImagesTree.h:40
ImagesTreeData(const long &nr)
Definition: ImagesTree.cpp:64
PanoOperationVector * GetLensesOperationVector()
returns list of PanoOperation for work with lenses
double m_editVal
value, which is currently edited
Definition: ImagesTree.h:204
Switch the part number of an image.
Definition: PanoCommand.h:506
PanoOperationVector * GetControlPointsOperationVector()
returns list of PanoOperation for work with control points
base class for different PanoOperations derived classes should overwrite protected PanoOperation::Get...
Definition: PanoOperation.h:39
IMPLEMENT_DYNAMIC_CLASS(wxTreeListHeaderWindow, wxWindow)
ImageVariableGroup & getLenses()
Get the ImageVariableGroup representing the group of lens variables.
void SetItemBold(const wxTreeItemId &item, bool bold=true)
void AddColumn(const wxString &text, int width=DEFAULT_COL_WIDTH, int flag=wxALIGN_LEFT, int image=-1, bool shown=true, bool edit=false, const wxString &tooltip=wxEmptyString)
Definition: treelistctrl.h:219
std::vector< std::string > m_columnVector
vector for easier access to column information
Definition: ImagesTree.h:190
bool Create(wxWindow *parent, wxWindowID id=wxID_ANY, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=wxTAB_TRAVERSAL, const wxString &name=wxT("panel"))
creates the control
Definition: ImagesTree.cpp:87
void OnColumnWidthChange(wxListEvent &e)
event handler, when column width was changed, save into wxConfig
Definition: ImagesTree.cpp:934
wxTreeItemId GetNextChild(const wxTreeItemId &item, wxTreeItemIdValue &cookie) const
static GlobalCmdHist & getInstance()
HuginBase::Panorama * m_pano
Definition: ImagesTree.h:168
void addCommand(PanoCommand *command, bool execute=true)
Adds a command to the history.
bool m_optimizerMode
true, if in optimizer mode
Definition: ImagesTree.h:182
wxTreeItemId m_lastCurrentItem
stores last item on which the mouse was hovering
Definition: ImagesTree.h:214
void SetGuiLevel(GuiLevel newSetting)
sets the GuiLevel of the control
Definition: ImagesTree.cpp:943
UIntSet getActiveImages() const
get active images
Definition: Panorama.cpp:1585
const bool IsGroup() const
Definition: ImagesTree.cpp:68
wxString GetExposureTime(const HuginBase::SrcPanoImage *img)
returns formatted exposure time
Definition: LensTools.cpp:554
update a single variable, possibly for a group of images
Definition: PanoCommand.h:236
HuginBase::UIntSet GetSelectedImages()
returns the selected images
Definition: ImagesTree.cpp:899
void OnEditImageVariables(wxCommandEvent &e)
event handler for showing image variables editing dialog
void SetItemTextColour(const wxTreeItemId &item, const wxColour &colour)
void OnSelectAll(wxCommandEvent &e)
event handler for select all optimizer variables
void addObserver(PanoramaObserver *o)
add a panorama observer.
Definition: Panorama.cpp:1546
void OnSelectLensStack(wxCommandEvent &e)
event handler for select all optimizer variables for selected lens/stack
size_t m_selectedColumn
selected column
Definition: ImagesTree.h:198
include file for the hugin project
const PanoramaOptions & getOptions() const
returns the options for this panorama
Definition: Panorama.h:481
std::map< int, PanoOperation::PanoOperation * > m_menuOperation
map with current active context menu PanoOperation
Definition: ImagesTree.h:196
void OnBeginDrag(wxTreeEvent &e)
event handler when dragging begins, veto if dragging is not possible
wxString GetExifDateTime(const HuginBase::SrcPanoImage *img)
returns Exif DateTimeOriginal as formatted wxString
Definition: LensTools.cpp:503
the main images tree control, used on images and optimizer tabs
Definition: ImagesTree.h:36
GLPreviewFrame * getGLPreview()
Definition: MainFrame.cpp:2234
options wxIntPtr wxIntPtr sortData std::vector< PanoInfo > * data
void OnActivateImage(wxCommandEvent &e)
event handler for activate image
void OnMouseMove(wxMouseEvent &e)
event handler for mouse motion, handles focussing of check boxes
void GenerateSubMenu(wxMenu *menu, PanoOperation::PanoOperationVector *operations, int &id)
generates submenu for given PanoOperationVector
int GetItemImage(const wxTreeItemId &item, wxTreeItemIcon which=wxTreeItemIcon_Normal) const
GuiLevel m_guiLevel
stores the active GuiLevel
Definition: ImagesTree.h:180
wxString m_editOldString
wxString, as shown before editing started
Definition: ImagesTree.h:206
PanoOperationVector * GetResetOperationVector()
returns list of PanoOperation for resetting
void update()
Update part numbers for each variable group.
void SelectAllParameters(bool select, bool allImages)
select/unselect all variables in the active column true selects all, false unselect all true works ...
PanoOperationVector * GetImagesOperationVector()
returns list of PanoOperation for work with images
platform/compiler specific stuff.
size_t GetSelections(wxArrayTreeItemIds &) const
std::vector< std::set< std::string > > OptimizeVector
std::vector< PanoOperation * > PanoOperationVector
HuginBase::StandardImageVariableGroups * m_variable_groups
Definition: ImagesTree.h:173
void ExpandAll(const wxTreeItemId &item)
HuginBase::UIntSet m_draggingImages
UIntSet of dragging images.
Definition: ImagesTree.h:200
const SrcPanoImage & getImage(std::size_t nr) const
get a panorama image, counting starts with 0
Definition: Panorama.h:211
remove multiple images from a panorama
Definition: PanoCommand.h:94
GuiLevel
Definition: GuiLevel.h:31
void UpdateGroupText(wxTreeItemId item)
updates the information fot the given lens/stack in the tree
Definition: ImagesTree.cpp:583
void fill_set(_Container &c, typename _Container::key_type begin, typename _Container::key_type end)
Definition: stl_utils.h:81
wxString GetFocalLength(const HuginBase::SrcPanoImage *img)
return focallength and focallength 35 mm as wxString
Definition: LensTools.cpp:519
static uint16_t flags
void UpdateItemFont()
update the font colour for all items
void OnUnselectLensStack(wxCommandEvent &e)
event handler for unselect all optimizer variables for selected lens/stack
std::size_t getNumberOfParts() const
get the number of parts.
All variables of a source image.
Definition: SrcPanoImage.h:194
PanoOperationVector * GetStacksOperationVector()
returns list of PanoOperation for stacks
wxString GetAperture(const HuginBase::SrcPanoImage *img)
returns formatted aperture value
Definition: LensTools.cpp:540
wxString GetItemText(const wxTreeItemId &item) const
Definition: treelistctrl.h:281
HuginBase::UIntSet m_editableColumns
set, which contains editable columns (all column which contains numeric image variables ...
Definition: ImagesTree.h:192
virtual bool CanHandle(wxXmlNode *node)
wxString getProjectionString(const HuginBase::SrcPanoImage &img)
Returns translated projection for given image.
Definition: LensTools.cpp:107
const long GetImgNr() const
Definition: ImagesTree.cpp:65
static const std::set< ConstImageVariableGroup::ImageVariableEnum > & getStackVariables()
Get the set of stack image variables.
void CreateColumns()
creates all columns and stores information in m_columnMap, m_columnVector, m_editableColumns and m_va...
Definition: ImagesTree.cpp:125
wxString GetIso(const HuginBase::SrcPanoImage *img)
returns formatted iso value
Definition: LensTools.cpp:591
void panoramaImagesChanged(HuginBase::Panorama &pano, const HuginBase::UIntSet &imgNr)
receive the update signal and update display accordingly
Definition: ImagesTree.cpp:245
void SetItemText(const wxTreeItemId &item, const wxString &text)
void Delete(const wxTreeItemId &item)
void OnUnselectAll(wxCommandEvent &e)
event handler for unselect all optimizer variables
void UpdateOptimizerVariables()
updates the display of the optimizer variables (set font)
Definition: ImagesTree.cpp:836
void CreateCheckboxImages()
create image list with necessary images of checkboxes
Definition: ImagesTree.cpp:950
int GetColumnWidth(int column) const
Dialog for editing image variables.
void SetOptimizerMode()
sets to control into optimizer mode
Definition: ImagesTree.cpp:985
virtual ~ImagesTreeCtrl(void)
destructor
Definition: ImagesTree.cpp:218