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