Hugintrunk  0.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
MaskEditorPanel.cpp
Go to the documentation of this file.
1 // -*- c-basic-offset: 4 -*-
2 
11 /* This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public
13  * License as published by the Free Software Foundation; either
14  * version 2 of the License, or (at your option) any later version.
15  *
16  * This software is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  * General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public
22  * License along with this software. If not, see
23  * <http://www.gnu.org/licenses/>.
24  *
25  */
26 
27 #include "panoinc_WX.h"
28 #include "panoinc.h"
29 #include <hugin_utils/stl_utils.h>
30 
31 // hugin's
32 #include "base_wx/platform.h"
33 #include "hugin/MainFrame.h"
34 #include "hugin/config_defaults.h"
35 #include "base_wx/CommandHistory.h"
36 #include "base_wx/PanoCommand.h"
37 #include "hugin/MaskEditorPanel.h"
38 #include "hugin/MaskLoadDialog.h"
39 #include <wx/clipbrd.h>
41 
43 {
44  DEBUG_TRACE("**********************");
45  m_pano = 0;
46  m_maskCropCtrl=NULL;
48 }
49 
50 bool MaskEditorPanel::Create(wxWindow* parent, wxWindowID id,
51  const wxPoint& pos,
52  const wxSize& size,
53  long style,
54  const wxString& name)
55 {
56  DEBUG_TRACE(" Create called *************");
57  if (! wxPanel::Create(parent, id, pos, size, style, name))
58  {
59  return false;
60  }
61 
62  m_MaskNr=UINT_MAX;
63  m_File="";
64 
65  wxXmlResource::Get()->LoadPanel(this, wxT("mask_panel"));
66  wxPanel * panel = XRCCTRL(*this, "mask_panel", wxPanel);
67 
68  wxBoxSizer *topsizer = new wxBoxSizer( wxVERTICAL );
69  topsizer->Add(panel, 1, wxEXPAND, 0);
70  SetSizer(topsizer);
71 
72  m_editImg = XRCCTRL(*this, "mask_editor_polygon_editor", MaskImageCtrl);
73  assert(m_editImg);
74  m_editImg->Init(this);
75 
76  // images list
77  m_imagesListMask = XRCCTRL(*this, "mask_editor_images_list", wxListCtrl);
78  m_imagesListMask->InsertColumn(0, wxT("#"), wxLIST_FORMAT_RIGHT, 35);
79  m_imagesListMask->InsertColumn(1, _("Filename"), wxLIST_FORMAT_LEFT, 200);
80  m_imagesListMask->InsertColumn(2, _("Number of masks"), wxLIST_FORMAT_RIGHT, 120);
81  m_imagesListMask->InsertColumn(3, _("Crop"), wxLIST_FORMAT_RIGHT, 120);
82  m_imagesListMask->Bind(wxEVT_LIST_ITEM_SELECTED, &MaskEditorPanel::OnImageSelect, this);
83  m_imagesListMask->Bind(wxEVT_LIST_ITEM_DESELECTED, &MaskEditorPanel::OnImageSelect, this);
84  m_imagesListMask->Bind(wxEVT_LIST_COL_END_DRAG, &MaskEditorPanel::OnImagesColumnWidthChange, this);
85  m_imagesListMask->Bind(wxEVT_CHAR, &MaskEditorPanel::OnImageListChar, this);
86 
87  //get saved width
88  wxConfigBase* config = wxConfigBase::Get();
89  for (int j = 0; j < m_imagesListMask->GetColumnCount(); j++)
90  {
91  // -1 is auto
92  int width = config->Read(wxString::Format("/ImagesListMask/ColumnWidth%d", j), -1);
93  if (width != -1)
94  {
95  m_imagesListMask->SetColumnWidth(j, width);
96  }
97  }
98  // mask list
99  m_maskList = XRCCTRL(*this, "mask_editor_mask_list", wxListCtrl);
100  m_maskList->InsertColumn( 0, wxT("#"), wxLIST_FORMAT_RIGHT, 35);
101  m_maskList->InsertColumn( 1, _("Mask type"), wxLIST_FORMAT_LEFT, 120);
102  m_maskList->Bind(wxEVT_LIST_ITEM_SELECTED, &MaskEditorPanel::OnMaskSelect, this);
103  m_maskList->Bind(wxEVT_LIST_ITEM_DESELECTED, &MaskEditorPanel::OnMaskSelect, this);
104  m_maskList->Bind(wxEVT_LIST_COL_END_DRAG, &MaskEditorPanel::OnMaskColumnWidthChange, this);
105 
106  m_maskCropCtrl = XRCCTRL(*this, "mask_editor_mask_crop_notebook", wxNotebook);
108  m_maskCropCtrl->SetSelection(0);
109  m_maskCropCtrl->Bind(wxEVT_NOTEBOOK_PAGE_CHANGED, &MaskEditorPanel::OnModeChanged, this);
110  m_maskMode=true;
111 
112  //get saved width
113  for ( int j=0; j < m_maskList->GetColumnCount() ; j++ )
114  {
115  // -1 is auto
116  int width = config->Read(wxString::Format( wxT("/MaskEditorPanel/ColumnWidth%d"), j ), -1);
117  if(width != -1)
118  m_maskList->SetColumnWidth(j, width);
119  }
120  bool activeMasks;
121  config->Read(wxT("/MaskEditorPanel/ShowActiveMasks"),&activeMasks,false);
122  XRCCTRL(*this,"mask_editor_show_active_masks",wxCheckBox)->SetValue(activeMasks);
123  m_editImg->setDrawingActiveMasks(activeMasks);
124 
125  //load and set colours
126  wxColour defaultColour;
127  defaultColour.Set(wxT(HUGIN_MASK_COLOUR_POLYGON_NEGATIVE));
128  wxColour colour = config->Read(wxT("/MaskEditorPanel/ColourPolygonNegative"), defaultColour.GetAsString(wxC2S_HTML_SYNTAX));
129  XRCCTRL(*this,"mask_editor_colour_polygon_negative",wxColourPickerCtrl)->SetColour(colour);
131  defaultColour.Set(wxT(HUGIN_MASK_COLOUR_POLYGON_POSITIVE));
132  colour = config->Read(wxT("/MaskEditorPanel/ColourPolygonPositive"), defaultColour.GetAsString(wxC2S_HTML_SYNTAX));
133  XRCCTRL(*this,"mask_editor_colour_polygon_positive",wxColourPickerCtrl)->SetColour(colour);
135  defaultColour.Set(wxT(HUGIN_MASK_COLOUR_POINT_SELECTED));
136  colour = config->Read(wxT("/MaskEditorPanel/ColourPointSelected"), defaultColour.GetAsString(wxC2S_HTML_SYNTAX));
137  XRCCTRL(*this,"mask_editor_colour_point_selected",wxColourPickerCtrl)->SetColour(colour);
139  defaultColour.Set(wxT(HUGIN_MASK_COLOUR_POINT_UNSELECTED));
140  colour = config->Read(wxT("/MaskEditorPanel/ColourPointUnselected"), defaultColour.GetAsString(wxC2S_HTML_SYNTAX));
141  XRCCTRL(*this,"mask_editor_colour_point_unselected",wxColourPickerCtrl)->SetColour(colour);
143  Bind(wxEVT_COLOURPICKER_CHANGED, &MaskEditorPanel::OnColourChanged, this);
144 
145  // other controls
146  m_maskType = XRCCTRL(*this, "mask_editor_choice_masktype", wxChoice);
147  m_defaultMaskType=(HuginBase::MaskPolygon::MaskType)config->Read(wxT("/MaskEditorPanel/DefaultMaskType"), 0l);
148  m_maskType->SetSelection((int)m_defaultMaskType);
149  m_maskType->Bind(wxEVT_CHOICE, &MaskEditorPanel::OnMaskTypeChange, this);
150  // disable some controls
151  m_maskType->Disable();
152  XRCCTRL(*this, "mask_editor_choice_zoom", wxChoice)->Disable();
153  XRCCTRL(*this, "mask_editor_add", wxButton)->Disable();
154  XRCCTRL(*this, "mask_editor_load", wxButton)->Disable();
155  XRCCTRL(*this, "mask_editor_save", wxButton)->Disable();
156  XRCCTRL(*this, "mask_editor_copy", wxButton)->Disable();
157  XRCCTRL(*this, "mask_editor_paste", wxButton)->Disable();
158  XRCCTRL(*this, "mask_editor_delete", wxButton)->Disable();
159 
160  m_left_textctrl = XRCCTRL(*this,"crop_left_text", wxTextCtrl);
162  m_left_textctrl->PushEventHandler(new TextKillFocusHandler(this));
163  m_left_textctrl->Bind(wxEVT_TEXT_ENTER, &MaskEditorPanel::OnSetLeft, this);
164 
165  m_cropLens = XRCCTRL(*this, "crop_all_images_lens", wxCheckBox);
167  bool doCropImagesLens;
168  config->Read(wxT("/MaskEditorPanel/CropImagesLens"), &doCropImagesLens, true);
169  m_cropLens->SetValue(doCropImagesLens);
170  m_top_textctrl = XRCCTRL(*this,"crop_top_text", wxTextCtrl);
172  m_top_textctrl->PushEventHandler(new TextKillFocusHandler(this));
173  m_top_textctrl->Bind(wxEVT_TEXT_ENTER, &MaskEditorPanel::OnSetTop, this);
174 
175  m_right_textctrl = XRCCTRL(*this,"crop_right_text", wxTextCtrl);
177  m_right_textctrl->PushEventHandler(new TextKillFocusHandler(this));
178  m_right_textctrl->Bind(wxEVT_TEXT_ENTER, &MaskEditorPanel::OnSetRight, this);
179 
180  m_bottom_textctrl = XRCCTRL(*this,"crop_bottom_text", wxTextCtrl);
182  m_bottom_textctrl->PushEventHandler(new TextKillFocusHandler(this));
183  m_bottom_textctrl->Bind(wxEVT_TEXT_ENTER, &MaskEditorPanel::OnSetBottom, this);
184 
185 
186  m_autocenter_cb = XRCCTRL(*this,"crop_autocenter_cb", wxCheckBox);
188  m_autocenter_cb->Bind(wxEVT_CHECKBOX, &MaskEditorPanel::OnAutoCenter, this);
189 
190  //set shortcuts
191  wxAcceleratorEntry entries[2];
192  entries[0].Set(wxACCEL_CMD,(int)'C',XRCID("mask_editor_copy"));
193  entries[1].Set(wxACCEL_CMD,(int)'V',XRCID("mask_editor_paste"));
194  wxAcceleratorTable accel(2, entries);
195  SetAcceleratorTable(accel);
196 
197  // apply zoom specified in xrc file
198  wxCommandEvent dummy;
199  dummy.SetInt(XRCCTRL(*this,"mask_editor_choice_zoom",wxChoice)->GetSelection());
200  OnZoom(dummy);
201  // bind remaining event handler
202  Bind(wxEVT_CHOICE, &MaskEditorPanel::OnZoom, this);
203  Bind(wxEVT_BUTTON, &MaskEditorPanel::OnMaskAdd, this, XRCID("mask_editor_add"));
204  Bind(wxEVT_BUTTON, &MaskEditorPanel::OnMaskLoad, this, XRCID("mask_editor_load"));
205  Bind(wxEVT_BUTTON, &MaskEditorPanel::OnMaskSave, this, XRCID("mask_editor_save"));
206  Bind(wxEVT_BUTTON, &MaskEditorPanel::OnMaskCopy, this, XRCID("mask_editor_copy"));
207  Bind(wxEVT_BUTTON, &MaskEditorPanel::OnMaskPaste, this, XRCID("mask_editor_paste"));
208  Bind(wxEVT_BUTTON, &MaskEditorPanel::OnMaskDelete, this, XRCID("mask_editor_delete"));
209  Bind(wxEVT_CHECKBOX, &MaskEditorPanel::OnShowActiveMasks, this, XRCID("mask_editor_show_active_masks"));
210  Bind(wxEVT_BUTTON, &MaskEditorPanel::OnResetButton, this, XRCID("crop_reset_button"));
211  return true;
212 }
213 
215 {
216  m_pano=pano;
218  // observe the panorama
219  m_pano->addObserver(this);
220 }
221 
223 {
224  m_left_textctrl->PopEventHandler(true);
225  m_right_textctrl->PopEventHandler(true);
226  m_top_textctrl->PopEventHandler(true);
227  m_bottom_textctrl->PopEventHandler(true);
228  wxConfigBase* config = wxConfigBase::Get();
229  config->Write(wxT("/MaskEditorPanel/ShowActiveMasks"),XRCCTRL(*this,"mask_editor_show_active_masks",wxCheckBox)->GetValue());
230  config->Write(wxT("/MaskEditorPanel/DefaultMaskType"),(long)m_defaultMaskType);
231  config->Write(wxT("/MaskEditorPanel/CropImagesLens"), m_cropLens->GetValue());
232  config->Flush();
233 
234  DEBUG_TRACE("dtor");
235  if (m_imageGroups)
236  {
237  delete m_imageGroups;
238  }
239  m_pano->removeObserver(this);
240 }
241 
243 {
244  if(m_imagesListMask->GetSelectedItemCount()==0)
245  {
246  return UINT_MAX;
247  }
248  else
249  {
250  return *(GetSelectedImages().begin());
251  };
252 };
253 
254 void SelectSingleImage(wxListCtrl* list, unsigned int imgNr)
255 {
256  unsigned int nrItems = list->GetItemCount();
257  // remove potentially existing selection
258  for (unsigned int i = 0; i < nrItems; i++)
259  {
260  if (i == imgNr)
261  {
262  continue;
263  };
264  list->SetItemState(i, 0, wxLIST_STATE_SELECTED);
265  }
266  list->SetItemState(imgNr, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
267 }
268 
269 void MaskEditorPanel::setImage(unsigned int imgNr, bool updateListSelection)
270 {
271  DEBUG_TRACE("image " << imgNr);
272  bool restoreMaskSelection=(imgNr==GetImgNr());
273  bool updateImage=true;
274  HuginBase::MaskPolygonVector masksToDraw;
275  if (imgNr == UINT_MAX)
276  {
277  m_File = "";
279  m_currentMasks=mask;
280  m_editImg->setCrop(HuginBase::SrcPanoImage::NO_CROP,vigra::Rect2D(), false, hugin_utils::FDiff2D(), false);
281  }
282  else
283  {
284  const HuginBase::SrcPanoImage& image=m_pano->getImage(imgNr);
285  updateImage=(m_File!=image.getFilename());
286  if(updateImage)
287  m_File=image.getFilename();
288  else
289  if(GetRot(imgNr)!=m_editImg->getCurrentRotation())
290  {
291  updateImage=true;
292  m_File=image.getFilename();
293  };
294  m_currentMasks=image.getMasks();
295  masksToDraw=image.getActiveMasks();
296  m_editImg->setCrop(image.getCropMode(),image.getCropRect(), image.getAutoCenterCrop(), image.getRadialDistortionCenter(), image.isCircularCrop());
297  };
298  // update mask editor
299  if(updateImage)
300  m_editImg->setImage(m_File,m_currentMasks,masksToDraw,GetRot(imgNr));
301  else
302  m_editImg->setNewMasks(m_currentMasks,masksToDraw);
303  if (m_currentMasks.empty() || m_MaskNr >= m_currentMasks.size())
304  setMask(UINT_MAX);
305  // enables or disables controls
306  bool enableCtrl=(imgNr<UINT_MAX);
307  XRCCTRL(*this, "mask_editor_choice_zoom", wxChoice)->Enable(enableCtrl);
308  XRCCTRL(*this, "mask_editor_add", wxButton)->Enable(enableCtrl);
309  XRCCTRL(*this, "mask_editor_delete", wxButton)->Enable(enableCtrl && m_MaskNr<UINT_MAX);
310  XRCCTRL(*this, "mask_editor_load", wxButton)->Enable(enableCtrl);
311  XRCCTRL(*this, "mask_editor_save", wxButton)->Enable(enableCtrl && m_MaskNr<UINT_MAX);
312  XRCCTRL(*this, "mask_editor_paste", wxButton)->Enable(enableCtrl);
313  XRCCTRL(*this, "mask_editor_copy", wxButton)->Enable(enableCtrl && m_MaskNr<UINT_MAX);
314  UpdateMaskList(restoreMaskSelection);
315  // FIXME: lets hope that nobody holds references to these images..
316  ImageCache::getInstance().softFlush();
317  if(updateListSelection)
318  {
320  m_imagesListMask->EnsureVisible(imgNr);
321  };
322 }
323 
324 void MaskEditorPanel::setMask(unsigned int maskNr)
325 {
326  m_MaskNr=maskNr;
327  m_maskType->Enable(m_MaskNr<UINT_MAX);
329  XRCCTRL(*this,"mask_editor_delete", wxButton)->Enable(m_MaskNr<UINT_MAX);
330  XRCCTRL(*this, "mask_editor_save", wxButton)->Enable(m_MaskNr<UINT_MAX);
331  XRCCTRL(*this, "mask_editor_copy", wxButton)->Enable(m_MaskNr<UINT_MAX);
332  if(GetImgNr()<UINT_MAX && m_MaskNr<UINT_MAX)
333  m_maskType->SetSelection(m_currentMasks[m_MaskNr].getMaskType());
334  else
335  m_maskType->SetSelection((int)m_defaultMaskType);
336 };
337 
339 {
340  if(GetImgNr()<UINT_MAX)
341  {
344  };
345 };
346 
348 {
349  if(GetImgNr()<UINT_MAX)
350  {
352  m_currentMasks[m_currentMasks.size()-1].setMaskType(m_defaultMaskType);
354  //select added mask
355  SelectMask(m_currentMasks.size()-1);
357  };
358 };
359 
360 void MaskEditorPanel::SelectMask(unsigned int newMaskNr)
361 {
362  if (GetImgNr() < UINT_MAX)
363  {
364  if (newMaskNr < m_currentMasks.size())
365  {
366  m_maskList->SetItemState(newMaskNr, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
367  }
368  else
369  {
370  if (m_MaskNr < UINT_MAX)
371  {
372  m_maskList->SetItemState(m_MaskNr, 0, wxLIST_STATE_SELECTED);
373  };
374  };
375  };
376 };
377 
379 {
380 };
381 
383 {
384  const HuginBase::SrcPanoImage& img = m_pano->getImage(imgNr);
385  wxFileName fn(wxString(img.getFilename().c_str(), HUGIN_CONV_FILENAME));
386  m_imagesListMask->SetItem(imgNr, 1, fn.GetFullName());
387 
388  wxString maskstr;
389  if (img.hasMasks())
390  {
391  maskstr = wxString::Format("%lu", (unsigned long int) m_pano->getImage(imgNr).getMasks().size());
392  }
393  else
394  {
395  maskstr = wxString("-");
396  };
397  m_imagesListMask->SetItem(imgNr, 2, maskstr);
398 
399  wxString cropstr("-");
400  if (img.getCropMode() != HuginBase::SrcPanoImage::NO_CROP)
401  {
402  vigra::Rect2D c = img.getCropRect();
403  cropstr.Printf("%d,%d,%d,%d", c.left(), c.right(), c.top(), c.bottom());
404  }
405  m_imagesListMask->SetItem(imgNr, 3, cropstr);
406 }
407 
409 {
410  const long nrImages = pano.getNrOfImages();
412  ImageCache::getInstance().softFlush();
414  {
415  m_imagesListMask->Freeze();
416  const size_t nrItems = m_imagesListMask->GetItemCount();
417  // remove items for nonexisting images
418  if (nrItems > nrImages)
419  {
420  for (long i = nrItems - 1; i >= nrImages; i--)
421  {
422  m_imagesListMask->DeleteItem(i);
423  }
424  }
425  // add newly added images
426  if (nrImages >= nrItems)
427  {
428  for (HuginBase::UIntSet::const_iterator it = changed.begin(); it != changed.end(); ++it)
429  {
430  if (*it >= nrItems)
431  {
432  m_imagesListMask->InsertItem(*it, wxString::Format("%d", *it));
433  }
434  }
435  }
436  // update existing items
437  for (HuginBase::UIntSet::const_iterator it = changed.begin(); it != changed.end(); ++it)
438  {
439  UpdateImage(*it);
440  }
441  m_imagesListMask->Thaw();
442  }
443 
444  if (nrImages == 0)
445  {
446  setImage(UINT_MAX);
447  }
448  else
449  {
450  // select some other image if we deleted the current image
451  if ((GetImgNr() < UINT_MAX) && (GetImgNr() >= nrImages))
452  {
453  setImage(nrImages - 1);
454  }
455  else
456  // update changed images
457  if(set_contains(changed,GetImgNr()))
458  {
459  unsigned int countOldMasks=m_currentMasks.size();
460  setImage(GetImgNr());
461  if(countOldMasks!=pano.getImage(GetImgNr()).getMasks().size())
462  SelectMask(UINT_MAX);
463  };
464  };
465 
466  if (m_imagesListMask->GetSelectedItemCount() > 0)
467  {
468  if (set_contains(changed, GetImgNr()))
469  {
471  }
472  }
473  else
474  {
476  }
477 
478 }
479 
481 {
482  // only for multi selection mode
483  if ((m_imagesListMask->GetWindowStyle() & wxLC_SINGLE_SEL) == 0)
484  {
485  // ctrl + a
486  if (e.GetKeyCode() == 1 && e.CmdDown())
487  {
488  // select all
489  for (int i = 0; i < m_imagesListMask->GetItemCount(); i++)
490  {
491  m_imagesListMask->SetItemState(i, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
492  }
493  }
494  }
495  e.Skip();
496 }
497 
498 void MaskEditorPanel::OnImageSelect(wxListEvent &e)
499 {
500  const HuginBase::UIntSet selectedImages=GetSelectedImages();
501  //select no mask
502  setMask(UINT_MAX);
503  setImage(GetImgNr());
504 
505  const bool hasImage = !selectedImages.empty();
506  m_left_textctrl->Enable(hasImage);
507  m_top_textctrl->Enable(hasImage);
508  m_bottom_textctrl->Enable(hasImage);
509  m_right_textctrl->Enable(hasImage);
510  if (hasImage)
511  {
512  // show first image.
514  };
515 };
516 
517 void MaskEditorPanel::OnMaskSelect(wxListEvent &e)
518 {
520 };
521 
522 void MaskEditorPanel::OnMaskTypeChange(wxCommandEvent &e)
523 {
524  if(GetImgNr()<UINT_MAX && m_MaskNr<UINT_MAX)
525  {
526  m_currentMasks[m_MaskNr].setMaskType((HuginBase::MaskPolygon::MaskType)e.GetSelection());
529  };
530 };
531 
532 void MaskEditorPanel::OnMaskAdd(wxCommandEvent &e)
533 {
534  if(GetImgNr()<UINT_MAX)
535  {
536  //deselect current selected mask
537  if(m_MaskNr<UINT_MAX)
538  m_maskList->SetItemState(m_MaskNr,0,wxLIST_STATE_SELECTED);
539  setMask(UINT_MAX);
540  MainFrame::Get()->SetStatusText(_("Create a polygon mask by clicking with the left mouse button on image, set the last point with the right mouse button."),0);
542  };
543 };
544 
545 void MaskEditorPanel::OnMaskSave(wxCommandEvent &e)
546 {
547  if(GetImgNr()<UINT_MAX && m_MaskNr<UINT_MAX)
548  {
549  wxFileDialog dlg(this, _("Save mask"),
550  wxConfigBase::Get()->Read(wxT("/actualPath"), wxT("")),
551  wxT(""), _("Mask files (*.msk)|*.msk|All files (*)|*"),
552  wxFD_SAVE | wxFD_OVERWRITE_PROMPT, wxDefaultPosition);
553  if (dlg.ShowModal() == wxID_OK)
554  {
555  wxString fn = dlg.GetPath();
556  if (fn.Right(4) != wxT(".msk"))
557  {
558  fn.Append(wxT(".msk"));
559  if (wxFile::Exists(fn))
560  {
561  int d = wxMessageBox(wxString::Format(_("File %s exists. Overwrite?"),
562  fn.c_str()), _("Save mask"),
563  wxYES_NO | wxICON_QUESTION);
564  if (d != wxYES) {
565  return;
566  }
567  }
568  };
569  wxFileName filename = fn;
570  std::ofstream maskFile(filename.GetFullPath().mb_str(HUGIN_CONV_FILENAME));
572  maskFile.close();
573  };
574  }
575 };
576 
577 void MaskEditorPanel::OnMaskLoad(wxCommandEvent &e)
578 {
579  if (GetImgNr()<UINT_MAX)
580  {
581  wxFileDialog dlg(this,_("Load mask"),
582  wxConfigBase::Get()->Read(wxT("/actualPath"),wxT("")),
583  wxT(""),_("Mask files (*.msk)|*.msk|All files (*)|*"),
584  wxFD_OPEN, wxDefaultPosition);
585  if (dlg.ShowModal() != wxID_OK)
586  {
587  MainFrame::Get()->SetStatusText(_("Load mask: cancel"));
588  return;
589  }
590  wxFileName filename(dlg.GetPath());
591  std::ifstream in(filename.GetFullPath().mb_str(HUGIN_CONV_FILENAME));
592  vigra::Size2D maskImageSize;
593  HuginBase::MaskPolygonVector loadedMasks;
594  LoadMaskFromStream(in, maskImageSize, loadedMasks, GetImgNr());
595  in.close();
596  if(maskImageSize.area()==0 || loadedMasks.empty())
597  {
598  wxMessageBox(wxString::Format(_("Could not parse mask from file %s."),dlg.GetPath().c_str()),_("Warning"),wxOK | wxICON_EXCLAMATION,this);
599  return;
600  };
601  // compare image size from file with that of current image alert user
602  // if different.
603  if (maskImageSize != m_pano->getImage(GetImgNr()).getSize())
604  {
605  MaskLoadDialog dlg(this);
606  dlg.initValues(m_pano->getImage(GetImgNr()),loadedMasks,maskImageSize);
607  if(dlg.ShowModal()!=wxID_OK)
608  {
609  // abort
610  return;
611  }
612  loadedMasks=dlg.getProcessedMask();
613  }
614  for(unsigned int i=0;i<loadedMasks.size();i++)
615  m_currentMasks.push_back(loadedMasks[i]);
616  // Update the pano with the imported masks
618  }
619 };
620 
621 void MaskEditorPanel::OnMaskCopy(wxCommandEvent &e)
622 {
623  if(GetImgNr()<UINT_MAX && m_MaskNr<UINT_MAX && m_maskMode)
624  {
625  std::ostringstream stream;
627  if (wxTheClipboard->Open())
628  {
629  // This data objects are held by the clipboard,
630  // so do not delete them in the app.
631  wxTheClipboard->SetData(new wxTextDataObject(wxString(stream.str().c_str(),wxConvLocal)));
632  wxTheClipboard->Close();
633  };
634  };
635 };
636 
637 void MaskEditorPanel::OnMaskPaste(wxCommandEvent &e)
638 {
639  if(GetImgNr()<UINT_MAX && m_maskMode)
640  {
641  if (wxTheClipboard->Open())
642  {
643  vigra::Size2D maskImageSize;
644  HuginBase::MaskPolygonVector loadedMasks;
645  if (wxTheClipboard->IsSupported( wxDF_TEXT ))
646  {
647  wxTextDataObject data;
648  wxTheClipboard->GetData(data);
649  std::istringstream stream(std::string(data.GetText().mb_str()));
650  LoadMaskFromStream(stream, maskImageSize, loadedMasks, GetImgNr());
651  }
652  wxTheClipboard->Close();
653  if(maskImageSize.area()==0 || loadedMasks.empty())
654  {
655  wxBell();
656  return;
657  };
658  // compare image size from file with that of current image alert user
659  // if different.
660  if (maskImageSize != m_pano->getImage(GetImgNr()).getSize())
661  {
662  MaskLoadDialog dlg(this);
663  dlg.initValues(m_pano->getImage(GetImgNr()),loadedMasks,maskImageSize);
664  if(dlg.ShowModal()!=wxID_OK)
665  {
666  // abort
667  return;
668  }
669  loadedMasks=dlg.getProcessedMask();
670  }
671  for(unsigned int i=0;i<loadedMasks.size();i++)
672  m_currentMasks.push_back(loadedMasks[i]);
673  // Update the pano with the imported masks
675  };
676  };
677 };
678 
679 void MaskEditorPanel::OnMaskDelete(wxCommandEvent &e)
680 {
681  if(GetImgNr()<UINT_MAX && m_MaskNr<UINT_MAX)
682  {
684  editedMasks.erase(editedMasks.begin()+m_MaskNr);
685  //setMask(UINT_MAX);
687  };
688 };
689 
690 void MaskEditorPanel::OnZoom(wxCommandEvent & e)
691 {
692  int posX = 0;
693  int posY = 0;
694  const wxSize ctrlSize = m_editImg->GetClientSize();
695  if (m_editImg->getScale() > 0)
696  {
697  // remember old scroll position
698  posX = (m_editImg->GetScrollPos(wxHORIZONTAL) + ctrlSize.GetWidth() / 2) / m_editImg->getScale();
699  posY = (m_editImg->GetScrollPos(wxVERTICAL) + ctrlSize.GetHeight() / 2) / m_editImg->getScale();
700  };
701  double factor;
702  switch (e.GetSelection())
703  {
704  case 0:
705  factor = 1;
706  break;
707  case 1:
708  // fit to window
709  factor = 0;
710  break;
711  case 2:
712  factor = 2;
713  break;
714  case 3:
715  factor = 1.5;
716  break;
717  case 4:
718  factor = 0.75;
719  break;
720  case 5:
721  factor = 0.5;
722  break;
723  case 6:
724  factor = 0.25;
725  break;
726  default:
727  DEBUG_ERROR("unknown scale factor");
728  factor = 1;
729  }
730  m_editImg->setScale(factor);
731  if (factor > 0)
732  {
733  m_editImg->Scroll(posX*factor - ctrlSize.GetWidth() / 2, posY*factor - ctrlSize.GetHeight() / 2);
734  };
735  if (e.GetString() == "update_selection")
736  {
737  XRCCTRL(*this, "mask_editor_choice_zoom", wxChoice)->SetSelection(e.GetSelection());
738  };
739 }
740 
741 void MaskEditorPanel::OnColourChanged(wxColourPickerEvent &e)
742 {
743  if(e.GetId()==XRCID("mask_editor_colour_polygon_negative"))
744  {
745  m_editImg->SetUserColourPolygonNegative(e.GetColour());
746  wxConfigBase::Get()->Write(wxT("/MaskEditorPanel/ColourPolygonNegative"),e.GetColour().GetAsString(wxC2S_HTML_SYNTAX));
747  }
748  else
749  if(e.GetId()==XRCID("mask_editor_colour_polygon_positive"))
750  {
751  m_editImg->SetUserColourPolygonPositive(e.GetColour());
752  wxConfigBase::Get()->Write(wxT("/MaskEditorPanel/ColourPolygonPositive"),e.GetColour().GetAsString(wxC2S_HTML_SYNTAX));
753  }
754  else
755  if(e.GetId()==XRCID("mask_editor_colour_point_selected"))
756  {
757  m_editImg->SetUserColourPointSelected(e.GetColour());
758  wxConfigBase::Get()->Write(wxT("/MaskEditorPanel/ColourPointSelected"),e.GetColour().GetAsString(wxC2S_HTML_SYNTAX));
759  }
760  else
761  {
762  m_editImg->SetUserColourPointUnselected(e.GetColour());
763  wxConfigBase::Get()->Write(wxT("/MaskEditorPanel/ColourPointUnselected"),e.GetColour().GetAsString(wxC2S_HTML_SYNTAX));
764  }
765  m_editImg->Refresh(true);
766 };
767 
768 void MaskEditorPanel::UpdateMaskList(bool restoreSelection)
769 {
770  unsigned int oldSelection=GetSelectedMask();
771  m_maskList->Freeze();
772  if(GetImgNr()<UINT_MAX)
773  {
774  if(!m_currentMasks.empty())
775  {
776  if(m_maskList->GetItemCount()!=m_currentMasks.size())
777  {
778  if(m_maskList->GetItemCount()<(int)m_currentMasks.size())
779  {
780  //added masks
781  for(int i=m_maskList->GetItemCount();i<(int)m_currentMasks.size();i++)
782  m_maskList->InsertItem(i,wxString::Format(wxT("%d"),i));
783  }
784  else
785  {
786  //deleted masks
787  for(int i=m_maskList->GetItemCount()-1;i>=(int)m_currentMasks.size();i--)
788  m_maskList->DeleteItem(i);
789  };
790  };
791  for(unsigned int i=0;i<m_currentMasks.size();i++)
792  {
793  m_maskList->SetItem(i,1,m_maskType->GetString(m_currentMasks[i].getMaskType()));
794  if(!restoreSelection && i==oldSelection)
795  m_maskList->SetItemState(i,0, wxLIST_STATE_SELECTED);
796  };
797  }
798  else
799  m_maskList->DeleteAllItems();
800  }
801  else
802  m_maskList->DeleteAllItems();
803  m_maskList->Thaw();
804  m_maskType->Enable(m_maskList->GetSelectedItemCount()>0);
805 }
806 
808 {
809  for(unsigned int i=0;i<(unsigned int)m_maskList->GetItemCount();i++)
810  {
811  if(m_maskList->GetItemState(i,wxLIST_STATE_SELECTED) & wxLIST_STATE_SELECTED)
812  return i;
813  };
814  return UINT_MAX;
815 };
816 
818 {
819  HuginBase::UIntSet selectedImages;
820  for (unsigned int i = 0; i < (unsigned int)m_imagesListMask->GetItemCount(); i++)
821  {
822  if (m_imagesListMask->GetItemState(i, wxLIST_STATE_SELECTED) & wxLIST_STATE_SELECTED)
823  {
824  selectedImages.insert(i);
825  }
826  }
827  return selectedImages;
828 }
829 
831 {
832  int colNum = e.GetColumn();
833  wxConfigBase::Get()->Write(wxString::Format("/ImagesListMask/ColumnWidth%d", colNum), m_imagesListMask->GetColumnWidth(colNum));
834 }
835 
837 {
838  int colNum = e.GetColumn();
839  wxConfigBase::Get()->Write( wxString::Format("/MaskEditorPanel/ColumnWidth%d",colNum), m_maskList->GetColumnWidth(colNum) );
840 }
841 
843 {
844  if(imgNr==UINT_MAX)
845  return MaskImageCtrl::ROT0;
846 
847  double pitch=m_pano->getImage(imgNr).getPitch();
848  double roll=m_pano->getImage(imgNr).getRoll();
849 
851  // normalize roll angle
852  while (roll > 360) roll-= 360;
853  while (roll < 0) roll += 360;
854 
855  while (pitch > 180) pitch -= 360;
856  while (pitch < -180) pitch += 360;
857  const bool headOver = (pitch > 90 || pitch < -90);
858 
859  if (wxConfig::Get()->Read("/CPEditorPanel/AutoRot", 1L))
860  {
861  if (roll >= 315 || roll < 45)
862  {
863  rot = headOver ? MaskImageCtrl::ROT180 : MaskImageCtrl::ROT0;
864  }
865  else
866  {
867  if (roll >= 45 && roll < 135)
868  {
869  rot = headOver ? MaskImageCtrl::ROT270 : MaskImageCtrl::ROT90;
870  }
871  else
872  {
873  if (roll >= 135 && roll < 225)
874  {
875  rot = headOver ? MaskImageCtrl::ROT0 : MaskImageCtrl::ROT180;
876  }
877  else
878  {
879  rot = headOver ? MaskImageCtrl::ROT90 : MaskImageCtrl::ROT270;
880  };
881  };
882  };
883  };
884  return rot;
885 }
886 
887 void MaskEditorPanel::OnShowActiveMasks(wxCommandEvent &e)
888 {
889  m_editImg->setDrawingActiveMasks(e.IsChecked());
890 };
891 
893 {
894  const HuginBase::SrcPanoImage & img = m_pano->getImage(imgNr);
895  m_cropMode=img.getCropMode();
896  m_cropRect=img.getCropRect();
897  m_autoCenterCrop=img.getAutoCenterCrop();
898 
899  int dx = hugin_utils::roundi(img.getRadialDistortionCenterShift().x);
900  int dy = hugin_utils::roundi(img.getRadialDistortionCenterShift().y);
902  m_cropCenter = vigra::Point2D(img.getSize().width()/2 + dx, img.getSize().height()/2 + dy);
903 
905 }
906 
907 // transfer our state to panorama
908 void MaskEditorPanel::UpdateCrop(bool updateFromImgCtrl)
909 {
910  // set crop image options.
911  if(updateFromImgCtrl)
912  {
914  };
915  std::vector<HuginBase::SrcPanoImage> srcImgs;
916  HuginBase::UIntSet imgs;
917  if (m_cropLens->IsChecked())
918  {
919  const HuginBase::UIntSetVector lensImageVector = m_imageGroups->getLenses().getPartsSet();
920  for (auto i : GetSelectedImages())
921  {
922  for (auto j : lensImageVector)
923  {
924  if (set_contains(j, i))
925  {
926  std::copy(j.begin(), j.end(), std::inserter(imgs, imgs.begin()));
927  break;
928  };
929  };
930  };
931  }
932  else
933  {
934  imgs = GetSelectedImages();
935  }
936  for (auto i:imgs)
937  {
939  img.setCropRect(m_cropRect);
940  img.setAutoCenterCrop(m_autoCenterCrop);
941  srcImgs.push_back(img);
942  };
943 
945  new PanoCommand::UpdateSrcImagesCmd(*m_pano, imgs, srcImgs)
946  );
947 }
948 
950 {
953 };
954 
955 // redraw display with new information
957 {
958  DEBUG_TRACE("")
960  m_left_textctrl->SetValue(wxString::Format(wxT("%d"),m_cropRect.left()));
961  m_right_textctrl->SetValue(wxString::Format(wxT("%d"),m_cropRect.right()));
962  m_top_textctrl->SetValue(wxString::Format(wxT("%d"),m_cropRect.top()));
963  m_bottom_textctrl->SetValue(wxString::Format(wxT("%d"),m_cropRect.bottom()));
964 }
965 
966 
967 void MaskEditorPanel::OnSetTop(wxCommandEvent & e)
968 {
969  long val;
970  if (m_top_textctrl->GetValue().ToLong(&val))
971  {
972  m_cropRect.setUpperLeft(vigra::Point2D(m_cropRect.left(), val));
973  if (m_autoCenterCrop)
974  {
975  CenterCrop();
977  };
978  UpdateCrop();
979  }
980  else
981  {
982  wxLogError(_("Please enter a valid number"));
983  };
984 };
985 
986 void MaskEditorPanel::OnSetBottom(wxCommandEvent & e)
987 {
988  long val;
989  if (m_bottom_textctrl->GetValue().ToLong(&val))
990  {
991  m_cropRect.setLowerRight(vigra::Point2D(m_cropRect.right(), val));
992  if (m_autoCenterCrop)
993  {
994  CenterCrop();
996  }
997  UpdateCrop();
998  }
999  else
1000  {
1001  wxLogError(_("Please enter a valid number"));
1002  };
1003 };
1004 
1005 void MaskEditorPanel::OnSetLeft(wxCommandEvent & e)
1006 {
1007  long val = 0;
1008  if (m_left_textctrl->GetValue().ToLong(&val))
1009  {
1010  m_cropRect.setUpperLeft(vigra::Point2D(val, m_cropRect.top()));
1011  if (m_autoCenterCrop)
1012  {
1013  CenterCrop();
1015  }
1016  UpdateCrop();
1017  }
1018  else
1019  {
1020  wxLogError(_("Please enter a valid number"));
1021  };
1022 };
1023 
1024 void MaskEditorPanel::OnSetRight(wxCommandEvent & e)
1025 {
1026  long val = 0;
1027  if (m_right_textctrl->GetValue().ToLong(&val))
1028  {
1029  m_cropRect.setLowerRight(vigra::Point2D(val, m_cropRect.bottom()));
1030  if (m_autoCenterCrop)
1031  {
1032  CenterCrop();
1034  };
1035  UpdateCrop();
1036  }
1037  else
1038  {
1039  wxLogError(_("Please enter a valid number"));
1040  };
1041 };
1042 
1043 void MaskEditorPanel::OnResetButton(wxCommandEvent & e)
1044 {
1045  // suitable defaults.
1046  m_cropRect.setUpperLeft(vigra::Point2D(0,0));
1047  m_cropRect.setLowerRight(vigra::Point2D(0,0));
1048  m_autoCenterCrop = true;
1051  UpdateCrop();
1052 }
1053 
1054 void MaskEditorPanel::OnAutoCenter(wxCommandEvent & e)
1055 {
1056  m_autoCenterCrop = e.IsChecked();
1057  if (m_autoCenterCrop)
1058  {
1059  CenterCrop();
1061  };
1062  UpdateCrop();
1063 }
1064 
1066 {
1067  vigra::Diff2D d(m_cropRect.width()/2, m_cropRect.height() / 2);
1068  m_cropRect.setUpperLeft( m_cropCenter - d);
1069  m_cropRect.setLowerRight( m_cropCenter + d);
1070 }
1071 
1072 void MaskEditorPanel::OnModeChanged(wxNotebookEvent& e)
1073 {
1074  if(m_maskCropCtrl==NULL)
1075  {
1076  return;
1077  };
1078  if(m_maskCropCtrl->GetSelection()==0)
1079  {
1080  m_maskMode=true;
1081  size_t imgNr=GetImgNr();
1082  m_imagesListMask->SetSingleStyle(wxLC_SINGLE_SEL, true);
1084  m_editImg->SetMaskMode(true);
1085  }
1086  else
1087  {
1088  m_maskMode=false;
1089  m_imagesListMask->SetSingleStyle(wxLC_SINGLE_SEL, false);
1090  m_editImg->SetMaskMode(false);
1091  SelectMask(UINT_MAX);
1092  };
1093  m_editImg->Refresh();
1094 };
1095 
1097 {
1098  m_maskCropCtrl->SetSelection(1);
1099  wxNotebookEvent dummy;
1100  OnModeChanged(dummy);
1101 }
1102 
1104 
1106  : wxXmlResourceHandler()
1107 {
1108  AddWindowStyles();
1109 }
1110 
1112 {
1113  XRC_MAKE_INSTANCE(cp, MaskEditorPanel)
1114 
1115  cp->Create(m_parentAsWindow,
1116  GetID(),
1117  GetPosition(), GetSize(),
1118  GetStyle(wxT("style")),
1119  GetName());
1120 
1121  SetupWindow(cp);
1122 
1123  return cp;
1124 }
1125 
1127 {
1128  return IsOfClass(node, wxT("MaskEditorPanel"));
1129 }
1130 
void OnResetButton(wxCommandEvent &e)
update source images
Definition: PanoCommand.h:404
ImageRotation
image rotation.
Definition: MaskImageCtrl.h:55
HuginBase::ConstStandardImageVariableGroups * m_imageGroups
void OnSetTop(wxCommandEvent &e)
void SaveMaskToStream(std::ostream &stream, vigra::Size2D imageSize, MaskPolygon &maskToWrite, size_t imgNr)
save the mask into stream
Definition: Mask.cpp:685
implementation of huginApp Class
hugin_utils::FDiff2D getRadialDistortionCenter() const
std::vector< UIntSet > UIntSetVector
Definition: PanoramaData.h:56
void UpdateMaskList(bool restoreSelection=false)
updates the display after another image has been selected.
void UpdateCropFromImage()
updates the displayed crop in the text boxes (for dragging)
unsigned int m_MaskNr
int roundi(T x)
Definition: hugin_math.h:73
SrcPanoImage getSrcImage(unsigned imgNr) const
get a description of a source image
Definition: Panorama.cpp:1620
wxListCtrl * m_imagesListMask
wxListCtrl * m_maskList
bool isCircularCrop() const
returns true, if projection requires cicular crop
bool removeObserver(PanoramaObserver *observer)
remove a panorama observer.
Definition: Panorama.cpp:1551
#define HUGIN_CONV_FILENAME
Definition: platform.h:40
void setActiveMask(unsigned int newMask, bool doUpdate=true)
mark mask with image as beeing editing
HuginBase::Panorama * m_pano
void LoadMaskFromStream(std::istream &stream, vigra::Size2D &imageSize, MaskPolygonVector &newMasks, size_t imgNr)
load the mask from stream
Definition: Mask.cpp:640
#define DEBUG_TRACE(msg)
Definition: utils.h:67
void OnMaskPaste(wxCommandEvent &e)
called when user wants to paste a mask from clipboard
void SelectMask(unsigned int newMaskNr)
selects the mask with index newMaskNr in the listbox
void SetUserColourPointUnselected(wxColour newColour)
xrc handler for handling mask editor panel
MaskImageCtrl * m_editImg
HuginBase::MaskPolygonVector getProcessedMask() const
return the processed mask
void OnMaskColumnWidthChange(wxListEvent &e)
called, when column with of mask list box was changed
void OnImageSelect(wxListEvent &e)
called when user selected another image
bool set_contains(const _Container &c, const typename _Container::key_type &key)
Definition: stl_utils.h:74
virtual bool CanHandle(wxXmlNode *node)
#define DEBUG_ASSERT(cond)
Definition: utils.h:80
wxChoice * m_maskType
HuginBase::SrcPanoImage::CropMode m_cropMode
include file for the hugin project
mask editor panel.
void setImage(unsigned int imgNr, bool updateListSelection=false)
sets the image, which is currently edited
vigra::Rect2D getCrop()
returns the current crop rect
Definition: MaskImageCtrl.h:66
void OnMaskLoad(wxCommandEvent &e)
called when user wants to load a mask into the selected image
HuginBase::MaskPolygonVector m_currentMasks
void OnImageListChar(wxKeyEvent &e)
key handler for images list
void OnAutoCenter(wxCommandEvent &e)
wxTextCtrl * m_right_textctrl
void OnSetBottom(wxCommandEvent &e)
void OnSetRight(wxCommandEvent &e)
bool hasMasks() const
returns true, if image has masks associated
void SetUserColourPolygonNegative(wxColour newColour)
sets the colour for different parts
const HuginBase::UIntSet GetSelectedImages()
return the currently selected image(s)
void SetUserColourPointSelected(wxColour newColour)
mask editor
Definition: MaskImageCtrl.h:38
void setMask(unsigned int maskNr)
sets active mask number, set to UINT_MAX, if no mask is currently editing
vigra::Rect2D m_cropRect
std::set< unsigned int > UIntSet
Definition: PanoramaData.h:51
void OnZoom(wxCommandEvent &e)
sets the actual zoom factor
update mask for given image
Definition: PanoCommand.h:612
Model for a panorama.
Definition: Panorama.h:152
void setImage(const std::string &filename, HuginBase::MaskPolygonVector newMask, HuginBase::MaskPolygonVector masksToDraw, ImageRotation rot)
set the current image and mask list, this loads also the image from cache
ConstImageVariableGroup & getLenses()
Get the ImageVariableGroup representing the group of lens variables.
UIntSetVector getPartsSet() const
return a vector which contains a HuginBase::UIntSet for each group with the corresponding images numb...
void panoramaImagesChanged(HuginBase::Panorama &pano, const HuginBase::UIntSet &imgNr)
notifies about changes to images
HuginBase::MaskPolygon::MaskType m_defaultMaskType
void OnMaskTypeChange(wxCommandEvent &e)
handler when mask type was changed
void OnImagesColumnWidthChange(wxListEvent &e)
called, when column with of images list box was changed
HuginBase::MaskPolygonVector getNewMask() const
returns the vector of all mask (including new created mask)
Definition: MaskImageCtrl.h:70
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
void SwitchToCropMode()
switches the controls to crop mode
MaskType
enumeration with type of possible masks
Definition: Mask.h:56
void OnColourChanged(wxColourPickerEvent &e)
event handler for changing colours
IMPLEMENT_DYNAMIC_CLASS(wxTreeListHeaderWindow, wxWindow)
void OnModeChanged(wxNotebookEvent &e)
ImageRotation getCurrentRotation()
returns the current rotation of displayed image
vigra::Point2D m_cropCenter
double getScale()
return scale factor, 0 for autoscale
void UpdateMask()
called when mask where changed in MaskImageCtrl
Make an ImageVariableGroup for lenses and other common concepts.
static GlobalCmdHist & getInstance()
void UpdateCrop(bool updateFromImgCtrl=false)
updated the crop in the Panorama object with the current values from GUI
void SelectSingleImage(wxListCtrl *list, unsigned int imgNr)
void addCommand(PanoCommand *command, bool execute=true)
Adds a command to the history.
wxCheckBox * m_autocenter_cb
void OnMaskSave(wxCommandEvent &e)
called when user wants to save active mask
std::vector< MaskPolygon > MaskPolygonVector
Definition: Mask.h:147
#define DEBUG_ERROR(msg)
Definition: utils.h:76
void Init(HuginBase::Panorama *pano)
wxCheckBox * m_cropLens
#define HUGIN_MASK_COLOUR_POINT_UNSELECTED
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"))
void selectAllMarkers()
select all points of active mask
std::string m_File
Dialog for loading masks.
void setNewMasks(HuginBase::MaskPolygonVector newMasks, HuginBase::MaskPolygonVector masksToDraw)
updates masks for currently selected image
void OnSetLeft(wxCommandEvent &e)
void addObserver(PanoramaObserver *o)
add a panorama observer.
Definition: Panorama.cpp:1546
include file for the hugin project
Handle EVT_KILL_FOCUS and convert it to a EVT_TEXT_ENTER event.
wxNotebook * m_maskCropCtrl
virtual ~MaskEditorPanel()
dtor.
options wxIntPtr wxIntPtr sortData std::vector< PanoInfo > * data
void DisplayCrop(int imgNr)
copies the crop information from the Panorama object to GUI
void setScale(double factor)
set the scaling factor for mask editing display.
#define HUGIN_MASK_COLOUR_POINT_SELECTED
void Init(MaskEditorPanel *parent)
void UpdateCropDisplay()
update GUI display
wxTextCtrl * m_bottom_textctrl
void SetMaskMode(bool newMaskMode)
sets the control to mask (newMaskMode=true) or crop (newMaskMode=false) mode
#define HUGIN_MASK_COLOUR_POLYGON_NEGATIVE
MaskImageCtrl::ImageRotation GetRot(const unsigned int imgNr)
determines, if the image should be rotated for display
void OnMaskDelete(wxCommandEvent &e)
called when user wants to delete active mask
void update()
Update part numbers for each variable group.
Definition of mask load dialog.
const SrcPanoImage & getImage(std::size_t nr) const
get a panorama image, counting starts with 0
Definition: Panorama.h:211
void UpdateImage(size_t imgNr)
update the list box for the given imgNr
void SetUserColourPolygonPositive(wxColour newColour)
void OnMaskSelect(wxListEvent &e)
called when user selected another mask
void OnMaskAdd(wxCommandEvent &e)
called when user wants to create new polygon
void panoramaChanged(HuginBase::Panorama &pano)
called when the panorama changes and we should update our display
void OnShowActiveMasks(wxCommandEvent &e)
event handler for changing option if active masks should be drawn
#define HUGIN_MASK_COLOUR_POLYGON_POSITIVE
void startNewPolygon()
starts creating a new polygon
void AddMask()
called when new mask added in MaskImageCtrl
wxTextCtrl * m_top_textctrl
All variables of a source image.
Definition: SrcPanoImage.h:194
void setCrop(HuginBase::SrcPanoImage::CropMode newCropMode, vigra::Rect2D newCropRect, bool isCentered, hugin_utils::FDiff2D center, bool isCircleCrop)
updates the crop mode and crop rect
virtual wxObject * DoCreateResource()
void initValues(const HuginBase::SrcPanoImage image, const HuginBase::MaskPolygonVector newMask, const vigra::Size2D maskSize)
sets the default values
wxTextCtrl * m_left_textctrl
unsigned int GetSelectedMask()
return index of currently selected masks, return UINT_MAX if no mask is selected
void setDrawingActiveMasks(bool newDrawActiveMasks)
set if active masks should be drawn
void OnMaskCopy(wxCommandEvent &e)
called when user wants to copy a mask to clipboard