MaskEditorPanel.cpp

Go to the documentation of this file.
00001 // -*- c-basic-offset: 4 -*-
00002 
00011 /*  This program is free software; you can redistribute it and/or
00012  *  modify it under the terms of the GNU General Public
00013  *  License as published by the Free Software Foundation; either
00014  *  version 2 of the License, or (at your option) any later version.
00015  *
00016  *  This software is distributed in the hope that it will be useful,
00017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019  *  General Public License for more details.
00020  *
00021  *  You should have received a copy of the GNU General Public
00022  *  License along with this software. If not, see
00023  *  <http://www.gnu.org/licenses/>.
00024  *
00025  */
00026 
00027 // often necessary before panoinc.h
00028 #ifdef __APPLE__
00029 #include "panoinc_WX.h"
00030 #endif
00031 
00032 #include "panoinc.h"
00033 #include <hugin_utils/stl_utils.h>
00034 
00035 // hugin's
00036 #include "base_wx/platform.h"
00037 #include "hugin/MainFrame.h"
00038 #include "hugin/config_defaults.h"
00039 #include "base_wx/CommandHistory.h"
00040 #include "base_wx/PanoCommand.h"
00041 #include "hugin/MaskEditorPanel.h"
00042 #include "hugin/MaskLoadDialog.h"
00043 #include <wx/clipbrd.h>
00044 #include "hugin/TextKillFocusHandler.h"
00045 
00046 BEGIN_EVENT_TABLE(MaskEditorPanel, wxPanel)
00047     EVT_LIST_ITEM_SELECTED(XRCID("mask_editor_images_list"), MaskEditorPanel::OnImageSelect)
00048     EVT_LIST_ITEM_DESELECTED(XRCID("mask_editor_images_list"), MaskEditorPanel::OnImageSelect)
00049     EVT_LIST_ITEM_SELECTED(XRCID("mask_editor_mask_list"), MaskEditorPanel::OnMaskSelect)
00050     EVT_LIST_ITEM_DESELECTED(XRCID("mask_editor_mask_list"), MaskEditorPanel::OnMaskSelect)
00051     EVT_LIST_COL_END_DRAG(XRCID("mask_editor_mask_list"), MaskEditorPanel::OnColumnWidthChange)
00052     EVT_CHOICE(XRCID("mask_editor_choice_zoom"), MaskEditorPanel::OnZoom)
00053     EVT_CHOICE(XRCID("mask_editor_choice_masktype"), MaskEditorPanel::OnMaskTypeChange)
00054     EVT_BUTTON(XRCID("mask_editor_add"), MaskEditorPanel::OnMaskAdd)
00055     EVT_BUTTON(XRCID("mask_editor_load"), MaskEditorPanel::OnMaskLoad)
00056     EVT_BUTTON(XRCID("mask_editor_save"), MaskEditorPanel::OnMaskSave)
00057     EVT_BUTTON(XRCID("mask_editor_copy"), MaskEditorPanel::OnMaskCopy)
00058     EVT_BUTTON(XRCID("mask_editor_paste"), MaskEditorPanel::OnMaskPaste)
00059     EVT_BUTTON(XRCID("mask_editor_delete"), MaskEditorPanel::OnMaskDelete)
00060     EVT_CHECKBOX(XRCID("mask_editor_show_active_masks"), MaskEditorPanel::OnShowActiveMasks)
00061     EVT_COLOURPICKER_CHANGED(XRCID("mask_editor_colour_polygon_negative"),MaskEditorPanel::OnColourChanged)
00062     EVT_COLOURPICKER_CHANGED(XRCID("mask_editor_colour_polygon_positive"),MaskEditorPanel::OnColourChanged)
00063     EVT_COLOURPICKER_CHANGED(XRCID("mask_editor_colour_point_selected"),MaskEditorPanel::OnColourChanged)
00064     EVT_COLOURPICKER_CHANGED(XRCID("mask_editor_colour_point_unselected"),MaskEditorPanel::OnColourChanged)
00065     EVT_TEXT_ENTER (XRCID("crop_left_text") ,MaskEditorPanel::OnSetLeft )
00066     EVT_TEXT_ENTER (XRCID("crop_right_text") ,MaskEditorPanel::OnSetRight )
00067     EVT_TEXT_ENTER (XRCID("crop_top_text") ,MaskEditorPanel::OnSetTop )
00068     EVT_TEXT_ENTER (XRCID("crop_bottom_text") ,MaskEditorPanel::OnSetBottom )
00069     EVT_BUTTON ( XRCID("crop_reset_button") , MaskEditorPanel::OnResetButton )
00070     EVT_CHECKBOX( XRCID("crop_autocenter_cb") , MaskEditorPanel::OnAutoCenter)
00071     EVT_NOTEBOOK_PAGE_CHANGED(XRCID("mask_editor_mask_crop_notebook"), MaskEditorPanel::OnModeChanged)
00072 END_EVENT_TABLE()
00073 
00074 MaskEditorPanel::MaskEditorPanel()
00075 {
00076     DEBUG_TRACE("**********************");
00077     m_pano = 0;
00078     m_maskCropCtrl=NULL;
00079     m_defaultMaskType=HuginBase::MaskPolygon::Mask_negative;
00080 }
00081 
00082 bool MaskEditorPanel::Create(wxWindow* parent, wxWindowID id,
00083                     const wxPoint& pos,
00084                     const wxSize& size,
00085                     long style,
00086                     const wxString& name)
00087 {
00088     DEBUG_TRACE(" Create called *************");
00089     if (! wxPanel::Create(parent, id, pos, size, style, name))
00090     {
00091         return false;
00092     }
00093 
00094     m_selectedImages.clear();
00095     m_MaskNr=UINT_MAX;
00096     m_File="";
00097 
00098     wxXmlResource::Get()->LoadPanel(this, wxT("mask_panel"));
00099     wxPanel * panel = XRCCTRL(*this, "mask_panel", wxPanel);
00100 
00101     wxBoxSizer *topsizer = new wxBoxSizer( wxVERTICAL );
00102     topsizer->Add(panel, 1, wxEXPAND, 0);
00103     SetSizer(topsizer);
00104 
00105     m_editImg = XRCCTRL(*this, "mask_editor_polygon_editor", MaskImageCtrl);
00106     assert(m_editImg);
00107     m_editImg->Init(this);
00108 
00109     // images list
00110     m_imagesListMask = XRCCTRL(*this, "mask_editor_images_list", ImagesListMask);
00111     // mask list
00112     m_maskList = XRCCTRL(*this, "mask_editor_mask_list", wxListCtrl);
00113     m_maskList->InsertColumn( 0, wxT("#"), wxLIST_FORMAT_RIGHT, 35);
00114     m_maskList->InsertColumn( 1, _("Mask type"), wxLIST_FORMAT_LEFT, 120);
00115 
00116     m_maskCropCtrl = XRCCTRL(*this, "mask_editor_mask_crop_notebook", wxNotebook);
00117     DEBUG_ASSERT(m_maskCropCtrl);
00118     m_maskCropCtrl->SetSelection(0);
00119     m_maskMode=true;
00120 
00121     //get saved width
00122     wxConfigBase *config=wxConfigBase::Get();
00123     for ( int j=0; j < m_maskList->GetColumnCount() ; j++ )
00124     {
00125         // -1 is auto
00126         int width = config->Read(wxString::Format( wxT("/MaskEditorPanel/ColumnWidth%d"), j ), -1);
00127         if(width != -1)
00128             m_maskList->SetColumnWidth(j, width);
00129     }
00130     bool activeMasks;
00131     config->Read(wxT("/MaskEditorPanel/ShowActiveMasks"),&activeMasks,false);
00132     XRCCTRL(*this,"mask_editor_show_active_masks",wxCheckBox)->SetValue(activeMasks);
00133     m_editImg->setDrawingActiveMasks(activeMasks);
00134 
00135     //load and set colours
00136     wxColour defaultColour;
00137     defaultColour.Set(wxT(HUGIN_MASK_COLOUR_POLYGON_NEGATIVE));
00138     wxColour colour = config->Read(wxT("/MaskEditorPanel/ColourPolygonNegative"), defaultColour.GetAsString(wxC2S_HTML_SYNTAX));
00139     XRCCTRL(*this,"mask_editor_colour_polygon_negative",wxColourPickerCtrl)->SetColour(colour);
00140     m_editImg->SetUserColourPolygonNegative(colour);
00141     defaultColour.Set(wxT(HUGIN_MASK_COLOUR_POLYGON_POSITIVE));
00142     colour = config->Read(wxT("/MaskEditorPanel/ColourPolygonPositive"), defaultColour.GetAsString(wxC2S_HTML_SYNTAX));
00143     XRCCTRL(*this,"mask_editor_colour_polygon_positive",wxColourPickerCtrl)->SetColour(colour);
00144     m_editImg->SetUserColourPolygonPositive(colour);
00145     defaultColour.Set(wxT(HUGIN_MASK_COLOUR_POINT_SELECTED));
00146     colour = config->Read(wxT("/MaskEditorPanel/ColourPointSelected"), defaultColour.GetAsString(wxC2S_HTML_SYNTAX));
00147     XRCCTRL(*this,"mask_editor_colour_point_selected",wxColourPickerCtrl)->SetColour(colour);
00148     m_editImg->SetUserColourPointSelected(colour);
00149     defaultColour.Set(wxT(HUGIN_MASK_COLOUR_POINT_UNSELECTED));
00150     colour = config->Read(wxT("/MaskEditorPanel/ColourPointUnselected"), defaultColour.GetAsString(wxC2S_HTML_SYNTAX));
00151     XRCCTRL(*this,"mask_editor_colour_point_unselected",wxColourPickerCtrl)->SetColour(colour);
00152     m_editImg->SetUserColourPointUnselected(colour);
00153 
00154     // other controls
00155     m_maskType = XRCCTRL(*this, "mask_editor_choice_masktype", wxChoice);
00156     m_defaultMaskType=(HuginBase::MaskPolygon::MaskType)config->Read(wxT("/MaskEditorPanel/DefaultMaskType"), 0l);
00157     m_maskType->SetSelection((int)m_defaultMaskType);
00158     // disable some controls
00159     m_maskType->Disable();
00160     XRCCTRL(*this, "mask_editor_choice_zoom", wxChoice)->Disable();
00161     XRCCTRL(*this, "mask_editor_add", wxButton)->Disable();
00162     XRCCTRL(*this, "mask_editor_load", wxButton)->Disable();
00163     XRCCTRL(*this, "mask_editor_save", wxButton)->Disable();
00164     XRCCTRL(*this, "mask_editor_copy", wxButton)->Disable();
00165     XRCCTRL(*this, "mask_editor_paste", wxButton)->Disable();
00166     XRCCTRL(*this, "mask_editor_delete", wxButton)->Disable();
00167 
00168     m_left_textctrl = XRCCTRL(*this,"crop_left_text", wxTextCtrl);
00169     DEBUG_ASSERT(m_left_textctrl);
00170     m_left_textctrl->PushEventHandler(new TextKillFocusHandler(this));
00171 
00172     m_cropLens = XRCCTRL(*this, "crop_all_images_lens", wxCheckBox);
00173     DEBUG_ASSERT(m_cropLens);
00174     bool doCropImagesLens;
00175     config->Read(wxT("/MaskEditorPanel/CropImagesLens"), &doCropImagesLens, true);
00176     m_cropLens->SetValue(doCropImagesLens);
00177     m_top_textctrl = XRCCTRL(*this,"crop_top_text", wxTextCtrl);
00178     DEBUG_ASSERT(m_top_textctrl);
00179     m_top_textctrl->PushEventHandler(new TextKillFocusHandler(this));
00180 
00181     m_right_textctrl = XRCCTRL(*this,"crop_right_text", wxTextCtrl);
00182     DEBUG_ASSERT(m_right_textctrl);
00183     m_right_textctrl->PushEventHandler(new TextKillFocusHandler(this));
00184 
00185     m_bottom_textctrl = XRCCTRL(*this,"crop_bottom_text", wxTextCtrl);
00186     DEBUG_ASSERT(m_bottom_textctrl);
00187     m_bottom_textctrl->PushEventHandler(new TextKillFocusHandler(this));
00188 
00189     m_autocenter_cb = XRCCTRL(*this,"crop_autocenter_cb", wxCheckBox);
00190     DEBUG_ASSERT(m_autocenter_cb);
00191 
00192     //set shortcuts
00193     wxAcceleratorEntry entries[2];
00194     entries[0].Set(wxACCEL_CMD,(int)'C',XRCID("mask_editor_copy"));
00195     entries[1].Set(wxACCEL_CMD,(int)'V',XRCID("mask_editor_paste"));
00196     wxAcceleratorTable accel(2, entries);
00197     SetAcceleratorTable(accel);
00198 
00199     // apply zoom specified in xrc file
00200     wxCommandEvent dummy;
00201     dummy.SetInt(XRCCTRL(*this,"mask_editor_choice_zoom",wxChoice)->GetSelection());
00202     OnZoom(dummy);
00203     return true;
00204 }
00205 
00206 void MaskEditorPanel::Init(HuginBase::Panorama * pano)
00207 {
00208     m_pano=pano;
00209     m_imagesListMask->Init(m_pano);
00210     m_imageGroups = new HuginBase::ConstStandardImageVariableGroups(*m_pano);
00211     // observe the panorama
00212     m_pano->addObserver(this);
00213 }
00214 
00215 MaskEditorPanel::~MaskEditorPanel()
00216 {
00217     m_left_textctrl->PopEventHandler(true);
00218     m_right_textctrl->PopEventHandler(true);
00219     m_top_textctrl->PopEventHandler(true);
00220     m_bottom_textctrl->PopEventHandler(true);
00221     wxConfigBase* config = wxConfigBase::Get();
00222     config->Write(wxT("/MaskEditorPanel/ShowActiveMasks"),XRCCTRL(*this,"mask_editor_show_active_masks",wxCheckBox)->GetValue());
00223     config->Write(wxT("/MaskEditorPanel/DefaultMaskType"),(long)m_defaultMaskType);
00224     config->Write(wxT("/MaskEditorPanel/CropImagesLens"), m_cropLens->GetValue());
00225     
00226     DEBUG_TRACE("dtor");
00227     if (m_imageGroups)
00228     {
00229         delete m_imageGroups;
00230     }
00231     m_pano->removeObserver(this);
00232 }
00233 
00234 size_t MaskEditorPanel::GetImgNr()
00235 {
00236     if(m_selectedImages.size()==0)
00237     {
00238         return UINT_MAX;
00239     }
00240     else
00241     {
00242         return *(m_selectedImages.begin());
00243     };
00244 };
00245 
00246 void MaskEditorPanel::setImage(unsigned int imgNr, bool updateListSelection)
00247 {
00248     DEBUG_TRACE("image " << imgNr);
00249     bool restoreMaskSelection=(imgNr==GetImgNr());
00250     bool updateImage=true;
00251     if(imgNr==UINT_MAX)
00252     {
00253         m_selectedImages.clear();
00254     }
00255     else
00256     {
00257         m_selectedImages.insert(imgNr);
00258     };
00259     HuginBase::MaskPolygonVector masksToDraw;
00260     if (imgNr == UINT_MAX) 
00261     {
00262         m_File = "";
00263         HuginBase::MaskPolygonVector mask;
00264         m_currentMasks=mask;
00265         m_editImg->setCrop(HuginBase::SrcPanoImage::NO_CROP,vigra::Rect2D(), false, hugin_utils::FDiff2D(), false);
00266     } 
00267     else 
00268     {
00269         const HuginBase::SrcPanoImage& image=m_pano->getImage(imgNr);
00270         updateImage=(m_File!=image.getFilename());
00271         if(updateImage)
00272             m_File=image.getFilename();
00273         else
00274             if(GetRot(imgNr)!=m_editImg->getCurrentRotation())
00275             {
00276                 updateImage=true;
00277                 m_File=image.getFilename();
00278             };
00279         m_currentMasks=image.getMasks();
00280         masksToDraw=image.getActiveMasks();
00281         m_editImg->setCrop(image.getCropMode(),image.getCropRect(), image.getAutoCenterCrop(), image.getRadialDistortionCenter(), image.isCircularCrop());
00282     };
00283     // update mask editor
00284     if(updateImage)
00285         m_editImg->setImage(m_File,m_currentMasks,masksToDraw,GetRot(imgNr));
00286     else
00287         m_editImg->setNewMasks(m_currentMasks,masksToDraw);
00288     if(m_currentMasks.size()==0)
00289         setMask(UINT_MAX);
00290     // enables or disables controls
00291     bool enableCtrl=(imgNr<UINT_MAX);
00292     XRCCTRL(*this, "mask_editor_choice_zoom", wxChoice)->Enable(enableCtrl);
00293     XRCCTRL(*this, "mask_editor_add", wxButton)->Enable(enableCtrl);
00294     XRCCTRL(*this, "mask_editor_delete", wxButton)->Enable(enableCtrl && m_MaskNr<UINT_MAX);
00295     XRCCTRL(*this, "mask_editor_load", wxButton)->Enable(enableCtrl);
00296     XRCCTRL(*this, "mask_editor_save", wxButton)->Enable(enableCtrl && m_MaskNr<UINT_MAX);
00297     XRCCTRL(*this, "mask_editor_paste", wxButton)->Enable(enableCtrl);
00298     XRCCTRL(*this, "mask_editor_copy", wxButton)->Enable(enableCtrl && m_MaskNr<UINT_MAX);
00299     UpdateMaskList(restoreMaskSelection);
00300     // FIXME: lets hope that nobody holds references to these images..
00301     ImageCache::getInstance().softFlush();
00302     if(updateListSelection)
00303     {
00304         m_imagesListMask->SelectSingleImage(imgNr);
00305     };
00306 }
00307 
00308 void MaskEditorPanel::setMask(unsigned int maskNr)
00309 {
00310     m_MaskNr=maskNr;
00311     m_maskType->Enable(m_MaskNr<UINT_MAX);
00312     m_editImg->setActiveMask(m_MaskNr);
00313     XRCCTRL(*this,"mask_editor_delete", wxButton)->Enable(m_MaskNr<UINT_MAX);
00314     XRCCTRL(*this, "mask_editor_save", wxButton)->Enable(m_MaskNr<UINT_MAX);
00315     XRCCTRL(*this, "mask_editor_copy", wxButton)->Enable(m_MaskNr<UINT_MAX);
00316     if(GetImgNr()<UINT_MAX && m_MaskNr<UINT_MAX)
00317         m_maskType->SetSelection(m_currentMasks[m_MaskNr].getMaskType());
00318     else
00319         m_maskType->SetSelection((int)m_defaultMaskType);
00320 };
00321 
00322 void MaskEditorPanel::UpdateMask()
00323 {
00324     if(GetImgNr()<UINT_MAX)
00325     {
00326         m_currentMasks=m_editImg->getNewMask();
00327         PanoCommand::GlobalCmdHist::getInstance().addCommand(new PanoCommand::UpdateMaskForImgCmd(*m_pano, GetImgNr(), m_currentMasks));
00328     };
00329 };
00330 
00331 void MaskEditorPanel::AddMask()
00332 {
00333     if(GetImgNr()<UINT_MAX)
00334     {
00335         m_currentMasks=m_editImg->getNewMask();
00336         m_currentMasks[m_currentMasks.size()-1].setMaskType(m_defaultMaskType);
00337         PanoCommand::GlobalCmdHist::getInstance().addCommand(new PanoCommand::UpdateMaskForImgCmd(*m_pano, GetImgNr(), m_currentMasks));
00338         //select added mask
00339         SelectMask(m_currentMasks.size()-1);
00340         m_editImg->selectAllMarkers();
00341     };
00342 };
00343 
00344 void MaskEditorPanel::SelectMask(unsigned int newMaskNr)
00345 {
00346     if (GetImgNr() < UINT_MAX)
00347     {
00348         if (newMaskNr < m_currentMasks.size())
00349         {
00350             m_maskList->SetItemState(newMaskNr, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
00351         }
00352         else
00353         {
00354             if (m_MaskNr < UINT_MAX)
00355             {
00356                 m_maskList->SetItemState(m_MaskNr, 0, wxLIST_STATE_SELECTED);
00357             };
00358         };
00359     };
00360 };
00361 
00362 void MaskEditorPanel::panoramaChanged(HuginBase::Panorama &pano)
00363 {
00364 };
00365 
00366 void MaskEditorPanel::panoramaImagesChanged(HuginBase::Panorama &pano, const HuginBase::UIntSet &changed)
00367 {
00368     unsigned int nrImages = pano.getNrOfImages();
00369     m_imageGroups->update();
00370     ImageCache::getInstance().softFlush();
00371     if (nrImages==0)
00372         setImage(UINT_MAX);
00373     else
00374     {
00375         // select some other image if we deleted the current image
00376         if ((GetImgNr() < UINT_MAX) && (GetImgNr() >= nrImages))
00377         {
00378             for (auto i : m_selectedImages)
00379             {
00380                 if (i >= nrImages)
00381                 {
00382                     m_selectedImages.erase(i);
00383                 };
00384             };
00385             setImage(nrImages - 1);
00386         }
00387         else
00388             // update changed images
00389             if(set_contains(changed,GetImgNr()))
00390             {
00391                 unsigned int countOldMasks=m_currentMasks.size();
00392                 setImage(GetImgNr());
00393                 if(countOldMasks!=pano.getImage(GetImgNr()).getMasks().size())
00394                     SelectMask(UINT_MAX);
00395             };
00396     };
00397 
00398     if (m_selectedImages.size() > 0)
00399     {
00400         if (set_contains(changed, GetImgNr()))
00401         {
00402             DisplayCrop(GetImgNr());
00403         }
00404     }
00405     else
00406     {
00407         UpdateCropDisplay();
00408     }
00409 
00410 }
00411 
00412 void MaskEditorPanel::OnImageSelect(wxListEvent &e)
00413 {
00414     m_selectedImages=m_imagesListMask->GetSelected();
00415     //select no mask
00416     setMask(UINT_MAX);
00417     setImage(GetImgNr());
00418 
00419     bool hasImage = (m_selectedImages.size() > 0);
00420     m_left_textctrl->Enable(hasImage);
00421     m_top_textctrl->Enable(hasImage);
00422     m_bottom_textctrl->Enable(hasImage);
00423     m_right_textctrl->Enable(hasImage);
00424     if (hasImage)
00425     {
00426         // show first image.
00427         DisplayCrop(GetImgNr());
00428     };
00429 };
00430 
00431 void MaskEditorPanel::OnMaskSelect(wxListEvent &e)
00432 {
00433     setMask(GetSelectedMask());
00434 };
00435 
00436 void MaskEditorPanel::OnMaskTypeChange(wxCommandEvent &e)
00437 {
00438     if(GetImgNr()<UINT_MAX && m_MaskNr<UINT_MAX)
00439     {
00440         m_currentMasks[m_MaskNr].setMaskType((HuginBase::MaskPolygon::MaskType)e.GetSelection());
00441         m_defaultMaskType=(HuginBase::MaskPolygon::MaskType)e.GetSelection();
00442         PanoCommand::GlobalCmdHist::getInstance().addCommand(new PanoCommand::UpdateMaskForImgCmd(*m_pano, GetImgNr(), m_currentMasks));
00443     };
00444 };
00445 
00446 void MaskEditorPanel::OnMaskAdd(wxCommandEvent &e)
00447 {
00448     if(GetImgNr()<UINT_MAX)
00449     {
00450         //deselect current selected mask
00451         if(m_MaskNr<UINT_MAX)
00452             m_maskList->SetItemState(m_MaskNr,0,wxLIST_STATE_SELECTED);
00453         setMask(UINT_MAX);
00454         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);
00455         m_editImg->startNewPolygon();
00456     };
00457 };
00458 
00459 void MaskEditorPanel::OnMaskSave(wxCommandEvent &e)
00460 {
00461     if(GetImgNr()<UINT_MAX && m_MaskNr<UINT_MAX)
00462     {
00463         wxFileDialog dlg(this, _("Save mask"),
00464                 wxConfigBase::Get()->Read(wxT("/actualPath"), wxT("")),
00465                 wxT(""), _("Mask files (*.msk)|*.msk|All files (*)|*"), 
00466                 wxFD_SAVE | wxFD_OVERWRITE_PROMPT, wxDefaultPosition);
00467         if (dlg.ShowModal() == wxID_OK) 
00468         {
00469             wxString fn = dlg.GetPath();
00470             if (fn.Right(4) != wxT(".msk"))
00471             {
00472                 fn.Append(wxT(".msk"));
00473                 if (wxFile::Exists(fn))
00474                 {
00475                     int d = wxMessageBox(wxString::Format(_("File %s exists. Overwrite?"),
00476                         fn.c_str()), _("Save mask"),
00477                         wxYES_NO | wxICON_QUESTION);
00478                     if (d != wxYES) {
00479                         return;
00480                     }
00481                 }
00482             };
00483             wxFileName filename = fn;
00484             std::ofstream maskFile(filename.GetFullPath().mb_str(HUGIN_CONV_FILENAME));
00485             SaveMaskToStream(maskFile, m_pano->getImage(GetImgNr()).getSize(), m_currentMasks[m_MaskNr], GetImgNr());
00486             maskFile.close();
00487         };
00488     }
00489 };
00490 
00491 void MaskEditorPanel::OnMaskLoad(wxCommandEvent &e)
00492 {
00493     if (GetImgNr()<UINT_MAX)
00494     {
00495         wxFileDialog dlg(this,_("Load mask"),
00496                 wxConfigBase::Get()->Read(wxT("/actualPath"),wxT("")),
00497                 wxT(""),_("Mask files (*.msk)|*.msk|All files (*)|*"),
00498                 wxFD_OPEN, wxDefaultPosition);
00499         if (dlg.ShowModal() != wxID_OK)
00500         {
00501             MainFrame::Get()->SetStatusText(_("Load mask: cancel"));
00502             return;
00503         }
00504         wxFileName filename(dlg.GetPath());
00505         std::ifstream in(filename.GetFullPath().mb_str(HUGIN_CONV_FILENAME));
00506         vigra::Size2D maskImageSize;
00507         HuginBase::MaskPolygonVector loadedMasks;
00508         LoadMaskFromStream(in, maskImageSize, loadedMasks, GetImgNr());
00509         in.close();
00510         if(maskImageSize.area()==0 || loadedMasks.size()==0)
00511         {
00512             wxMessageBox(wxString::Format(_("Could not parse mask from file %s."),dlg.GetPath().c_str()),_("Warning"),wxOK | wxICON_EXCLAMATION,this);
00513             return;
00514         };
00515         // compare image size from file with that of current image alert user
00516         // if different.
00517         if (maskImageSize != m_pano->getImage(GetImgNr()).getSize()) 
00518         {
00519             MaskLoadDialog dlg(this);
00520             dlg.initValues(m_pano->getImage(GetImgNr()),loadedMasks,maskImageSize);
00521             if(dlg.ShowModal()!=wxID_OK)
00522             {
00523                 // abort
00524                 return;
00525             }
00526             loadedMasks=dlg.getProcessedMask();
00527         }
00528         for(unsigned int i=0;i<loadedMasks.size();i++)
00529             m_currentMasks.push_back(loadedMasks[i]);
00530         // Update the pano with the imported masks
00531         PanoCommand::GlobalCmdHist::getInstance().addCommand(new PanoCommand::UpdateMaskForImgCmd(*m_pano, GetImgNr(), m_currentMasks));
00532     }
00533 };
00534 
00535 void MaskEditorPanel::OnMaskCopy(wxCommandEvent &e)
00536 {
00537     if(GetImgNr()<UINT_MAX && m_MaskNr<UINT_MAX && m_maskMode)
00538     {
00539         std::ostringstream stream;
00540         SaveMaskToStream(stream, m_pano->getImage(GetImgNr()).getSize(), m_currentMasks[m_MaskNr], GetImgNr());
00541         if (wxTheClipboard->Open())
00542         {
00543             // This data objects are held by the clipboard,
00544             // so do not delete them in the app.
00545             wxTheClipboard->SetData(new wxTextDataObject(wxString(stream.str().c_str(),wxConvLocal)));
00546             wxTheClipboard->Close();
00547         };
00548     };
00549 };
00550 
00551 void MaskEditorPanel::OnMaskPaste(wxCommandEvent &e)
00552 {
00553     if(GetImgNr()<UINT_MAX && m_maskMode)
00554     {
00555         if (wxTheClipboard->Open())
00556         {
00557             vigra::Size2D maskImageSize;
00558             HuginBase::MaskPolygonVector loadedMasks;
00559             if (wxTheClipboard->IsSupported( wxDF_TEXT ))
00560             {
00561                 wxTextDataObject data;
00562                 wxTheClipboard->GetData(data);
00563                 std::istringstream stream(std::string(data.GetText().mb_str()));
00564                 LoadMaskFromStream(stream, maskImageSize, loadedMasks, GetImgNr());
00565             }
00566             wxTheClipboard->Close();
00567             if(maskImageSize.area()==0 || loadedMasks.size()==0)
00568             {
00569                 wxBell();
00570                 return;
00571             };
00572             // compare image size from file with that of current image alert user
00573             // if different.
00574             if (maskImageSize != m_pano->getImage(GetImgNr()).getSize()) 
00575             {
00576                 MaskLoadDialog dlg(this);
00577                 dlg.initValues(m_pano->getImage(GetImgNr()),loadedMasks,maskImageSize);
00578                 if(dlg.ShowModal()!=wxID_OK)
00579                 {
00580                     // abort
00581                     return;
00582                 }
00583                 loadedMasks=dlg.getProcessedMask();
00584             }
00585             for(unsigned int i=0;i<loadedMasks.size();i++)
00586                 m_currentMasks.push_back(loadedMasks[i]);
00587             // Update the pano with the imported masks
00588             PanoCommand::GlobalCmdHist::getInstance().addCommand(new PanoCommand::UpdateMaskForImgCmd(*m_pano, GetImgNr(), m_currentMasks));
00589         };
00590     };
00591 };
00592 
00593 void MaskEditorPanel::OnMaskDelete(wxCommandEvent &e)
00594 {
00595     if(GetImgNr()<UINT_MAX && m_MaskNr<UINT_MAX)
00596     {
00597         HuginBase::MaskPolygonVector editedMasks=m_currentMasks;
00598         editedMasks.erase(editedMasks.begin()+m_MaskNr);
00599         //setMask(UINT_MAX);
00600         PanoCommand::GlobalCmdHist::getInstance().addCommand(new PanoCommand::UpdateMaskForImgCmd(*m_pano, GetImgNr(), editedMasks));
00601     };
00602 };
00603 
00604 void MaskEditorPanel::OnZoom(wxCommandEvent & e)
00605 {
00606     int posX = 0;
00607     int posY = 0;
00608     const wxSize ctrlSize = m_editImg->GetClientSize();
00609     if (m_editImg->getScale() > 0)
00610     {
00611         // remember old scroll position
00612         posX = (m_editImg->GetScrollPos(wxHORIZONTAL) + ctrlSize.GetWidth() / 2) / m_editImg->getScale();
00613         posY = (m_editImg->GetScrollPos(wxVERTICAL) + ctrlSize.GetHeight() / 2) / m_editImg->getScale();
00614     };
00615     double factor;
00616     switch (e.GetSelection()) 
00617     {
00618         case 0:
00619             factor = 1;
00620             break;
00621         case 1:
00622             // fit to window
00623             factor = 0;
00624             break;
00625         case 2:
00626             factor = 2;
00627             break;
00628         case 3:
00629             factor = 1.5;
00630             break;
00631         case 4:
00632             factor = 0.75;
00633             break;
00634         case 5:
00635             factor = 0.5;
00636             break;
00637         case 6:
00638             factor = 0.25;
00639             break;
00640         default:
00641             DEBUG_ERROR("unknown scale factor");
00642             factor = 1;
00643     }
00644     m_editImg->setScale(factor);
00645     if (factor > 0)
00646     {
00647         m_editImg->Scroll(posX*factor - ctrlSize.GetWidth() / 2, posY*factor - ctrlSize.GetHeight() / 2);
00648     };
00649 }
00650 
00651 void MaskEditorPanel::OnColourChanged(wxColourPickerEvent &e)
00652 {
00653     if(e.GetId()==XRCID("mask_editor_colour_polygon_negative"))
00654     {
00655         m_editImg->SetUserColourPolygonNegative(e.GetColour());
00656         wxConfigBase::Get()->Write(wxT("/MaskEditorPanel/ColourPolygonNegative"),e.GetColour().GetAsString(wxC2S_HTML_SYNTAX));
00657     }
00658     else 
00659         if(e.GetId()==XRCID("mask_editor_colour_polygon_positive"))
00660         {
00661             m_editImg->SetUserColourPolygonPositive(e.GetColour());
00662             wxConfigBase::Get()->Write(wxT("/MaskEditorPanel/ColourPolygonPositive"),e.GetColour().GetAsString(wxC2S_HTML_SYNTAX));
00663         }
00664         else
00665             if(e.GetId()==XRCID("mask_editor_colour_point_selected"))
00666             {
00667                 m_editImg->SetUserColourPointSelected(e.GetColour());
00668                 wxConfigBase::Get()->Write(wxT("/MaskEditorPanel/ColourPointSelected"),e.GetColour().GetAsString(wxC2S_HTML_SYNTAX));
00669             }
00670             else
00671             {
00672                 m_editImg->SetUserColourPointUnselected(e.GetColour());
00673                 wxConfigBase::Get()->Write(wxT("/MaskEditorPanel/ColourPointUnselected"),e.GetColour().GetAsString(wxC2S_HTML_SYNTAX));
00674             }
00675     m_editImg->Refresh(true);
00676 };
00677 
00678 void MaskEditorPanel::UpdateMaskList(bool restoreSelection)
00679 {
00680     unsigned int oldSelection=GetSelectedMask();
00681     m_maskList->Freeze();
00682     if(GetImgNr()<UINT_MAX)
00683     {
00684         if(m_currentMasks.size()>0)
00685         {
00686             if(m_maskList->GetItemCount()!=m_currentMasks.size())
00687             {
00688                 if(m_maskList->GetItemCount()<(int)m_currentMasks.size())
00689                 {
00690                     //added masks
00691                     for(int i=m_maskList->GetItemCount();i<(int)m_currentMasks.size();i++)
00692                         m_maskList->InsertItem(i,wxString::Format(wxT("%d"),i));
00693                 }
00694                 else
00695                 {
00696                     //deleted masks
00697                     for(int i=m_maskList->GetItemCount()-1;i>=(int)m_currentMasks.size();i--)
00698                         m_maskList->DeleteItem(i);
00699                 };
00700             };
00701             for(unsigned int i=0;i<m_currentMasks.size();i++)
00702             {
00703                 m_maskList->SetItem(i,1,m_maskType->GetString(m_currentMasks[i].getMaskType()));
00704                 if(!restoreSelection && i==oldSelection)
00705                     m_maskList->SetItemState(i,0, wxLIST_STATE_SELECTED);
00706             };
00707         }
00708         else
00709             m_maskList->DeleteAllItems();
00710     }
00711     else
00712         m_maskList->DeleteAllItems();
00713     m_maskList->Thaw();
00714     m_maskType->Enable(m_maskList->GetSelectedItemCount()>0);
00715 }
00716 
00717 unsigned int MaskEditorPanel::GetSelectedMask()
00718 {
00719     for(unsigned int i=0;i<(unsigned int)m_maskList->GetItemCount();i++)
00720     {
00721         if(m_maskList->GetItemState(i,wxLIST_STATE_SELECTED) & wxLIST_STATE_SELECTED)
00722             return i;
00723     };
00724     return UINT_MAX;
00725 };
00726 
00727 void MaskEditorPanel::OnColumnWidthChange( wxListEvent & e )
00728 {
00729     int colNum = e.GetColumn();
00730     wxConfigBase::Get()->Write( wxString::Format(wxT("/MaskEditorPanel/ColumnWidth%d"),colNum), m_maskList->GetColumnWidth(colNum) );
00731 }
00732 
00733 MaskImageCtrl::ImageRotation MaskEditorPanel::GetRot(const unsigned int imgNr)
00734 {
00735     if(imgNr==UINT_MAX)
00736         return MaskImageCtrl::ROT0;
00737 
00738     double pitch=m_pano->getImage(imgNr).getPitch();
00739     double roll=m_pano->getImage(imgNr).getRoll();
00740     
00741     MaskImageCtrl::ImageRotation rot = MaskImageCtrl::ROT0;
00742     // normalize roll angle
00743     while (roll > 360) roll-= 360;
00744     while (roll < 0) roll += 360;
00745 
00746     while (pitch > 180) pitch -= 360;
00747     while (pitch < -180) pitch += 360;
00748     bool headOver = (pitch > 90 || pitch < -90);
00749 
00750     if (roll >= 315 || roll < 45) 
00751     {
00752         rot = headOver ? MaskImageCtrl::ROT180 : MaskImageCtrl::ROT0;
00753     } 
00754     else 
00755         if (roll >= 45 && roll < 135) 
00756         {
00757             rot = headOver ? MaskImageCtrl::ROT270 : MaskImageCtrl::ROT90;
00758         }
00759         else 
00760             if (roll >= 135 && roll < 225) 
00761             {
00762                 rot = headOver ? MaskImageCtrl::ROT0 : MaskImageCtrl::ROT180;
00763             } 
00764             else 
00765             {
00766                 rot = headOver ? MaskImageCtrl::ROT90 : MaskImageCtrl::ROT270;
00767             }
00768     return rot;
00769 }
00770 
00771 void MaskEditorPanel::OnShowActiveMasks(wxCommandEvent &e)
00772 {
00773     m_editImg->setDrawingActiveMasks(e.IsChecked());
00774 };
00775 
00776 void MaskEditorPanel::DisplayCrop(int imgNr)
00777 {
00778     const HuginBase::SrcPanoImage & img = m_pano->getImage(imgNr);
00779     m_cropMode=img.getCropMode();
00780     m_cropRect=img.getCropRect();
00781     m_autoCenterCrop=img.getAutoCenterCrop();
00782 
00783     int dx = hugin_utils::roundi(img.getRadialDistortionCenterShift().x);
00784     int dy = hugin_utils::roundi(img.getRadialDistortionCenterShift().y);
00786     m_cropCenter = vigra::Point2D(img.getSize().width()/2 + dx, img.getSize().height()/2 + dy);
00787 
00788     UpdateCropDisplay();
00789 }
00790 
00791 // transfer our state to panorama
00792 void MaskEditorPanel::UpdateCrop(bool updateFromImgCtrl)
00793 {
00794     // set crop image options.
00795     if(updateFromImgCtrl)
00796     {
00797         m_cropRect=m_editImg->getCrop();
00798     };
00799     std::vector<HuginBase::SrcPanoImage> srcImgs;
00800     HuginBase::UIntSet imgs;
00801     if (m_cropLens->IsChecked())
00802     {
00803         const HuginBase::UIntSetVector lensImageVector = m_imageGroups->getLenses().getPartsSet();
00804         for (auto i : m_selectedImages)
00805         {
00806             for (auto j : lensImageVector)
00807             {
00808                 if (set_contains(j, i))
00809                 {
00810                     std::copy(j.begin(), j.end(), std::inserter(imgs, imgs.begin()));
00811                     break;
00812                 };
00813             };
00814         };
00815     }
00816     else
00817     {
00818         imgs = m_selectedImages;
00819     }
00820     for (auto i:imgs)
00821     {
00822         HuginBase::SrcPanoImage img=m_pano->getSrcImage(i);
00823         img.setCropRect(m_cropRect);
00824         img.setAutoCenterCrop(m_autoCenterCrop);
00825         srcImgs.push_back(img);
00826     };
00827 
00828     PanoCommand::GlobalCmdHist::getInstance().addCommand(
00829             new PanoCommand::UpdateSrcImagesCmd(*m_pano, imgs, srcImgs)
00830     );
00831 }
00832 
00833 void MaskEditorPanel::UpdateCropFromImage()
00834 {
00835     m_cropRect=m_editImg->getCrop();
00836     UpdateCropDisplay();
00837 };
00838 
00839 // redraw display with new information
00840 void MaskEditorPanel::UpdateCropDisplay()
00841 {
00842     DEBUG_TRACE("")
00843     m_autocenter_cb->SetValue(m_autoCenterCrop);
00844     m_left_textctrl->SetValue(wxString::Format(wxT("%d"),m_cropRect.left()));
00845     m_right_textctrl->SetValue(wxString::Format(wxT("%d"),m_cropRect.right()));
00846     m_top_textctrl->SetValue(wxString::Format(wxT("%d"),m_cropRect.top()));
00847     m_bottom_textctrl->SetValue(wxString::Format(wxT("%d"),m_cropRect.bottom()));
00848 }
00849 
00850 
00851 void MaskEditorPanel::OnSetTop(wxCommandEvent & e)
00852 {
00853     long val;
00854     if (m_top_textctrl->GetValue().ToLong(&val))
00855     {
00856         m_cropRect.setUpperLeft(vigra::Point2D(m_cropRect.left(), val));
00857         if (m_autoCenterCrop)
00858         {
00859             CenterCrop();
00860             UpdateCropDisplay();
00861         };
00862         UpdateCrop();
00863     }
00864     else
00865     {
00866         wxLogError(_("Please enter a valid number"));
00867     };
00868 };
00869 
00870 void MaskEditorPanel::OnSetBottom(wxCommandEvent & e)
00871 {
00872     long val;
00873     if (m_bottom_textctrl->GetValue().ToLong(&val))
00874     {
00875         m_cropRect.setLowerRight(vigra::Point2D(m_cropRect.right(), val));
00876         if (m_autoCenterCrop)
00877         {
00878             CenterCrop();
00879             UpdateCropDisplay();
00880         }
00881         UpdateCrop();
00882     }
00883     else
00884     {
00885         wxLogError(_("Please enter a valid number"));
00886     };
00887 };
00888 
00889 void MaskEditorPanel::OnSetLeft(wxCommandEvent & e)
00890 {
00891     long val = 0;
00892     if (m_left_textctrl->GetValue().ToLong(&val))
00893     {
00894         m_cropRect.setUpperLeft(vigra::Point2D(val, m_cropRect.top()));
00895         if (m_autoCenterCrop)
00896         {
00897             CenterCrop();
00898             UpdateCropDisplay();
00899         }
00900         UpdateCrop();
00901     }
00902     else
00903     {
00904         wxLogError(_("Please enter a valid number"));
00905     };
00906 };
00907 
00908 void MaskEditorPanel::OnSetRight(wxCommandEvent & e)
00909 {
00910     long val = 0;
00911     if (m_right_textctrl->GetValue().ToLong(&val))
00912     {
00913         m_cropRect.setLowerRight(vigra::Point2D(val, m_cropRect.bottom()));
00914         if (m_autoCenterCrop)
00915         {
00916             CenterCrop();
00917             UpdateCropDisplay();
00918         };
00919         UpdateCrop();
00920     }
00921     else
00922     {
00923         wxLogError(_("Please enter a valid number"));
00924     };
00925 };
00926 
00927 void MaskEditorPanel::OnResetButton(wxCommandEvent & e)
00928 {
00929     // suitable defaults.
00930     m_cropRect.setUpperLeft(vigra::Point2D(0,0));
00931     m_cropRect.setLowerRight(vigra::Point2D(0,0));
00932     m_autoCenterCrop = true;
00933     m_cropMode=HuginBase::SrcPanoImage::NO_CROP;
00934     UpdateCropDisplay();
00935     UpdateCrop();
00936 }
00937 
00938 void MaskEditorPanel::OnAutoCenter(wxCommandEvent & e)
00939 {
00940     m_autoCenterCrop = e.IsChecked();
00941     if (m_autoCenterCrop)
00942     {
00943         CenterCrop();
00944         UpdateCropDisplay();
00945     };
00946     UpdateCrop();
00947 }
00948 
00949 void MaskEditorPanel::CenterCrop()
00950 {
00951     vigra::Diff2D d(m_cropRect.width()/2, m_cropRect.height() / 2);
00952     m_cropRect.setUpperLeft( m_cropCenter - d);
00953     m_cropRect.setLowerRight( m_cropCenter + d);
00954 }
00955 
00956 void MaskEditorPanel::OnModeChanged(wxNotebookEvent& e)
00957 {
00958     if(m_maskCropCtrl==NULL)
00959     {
00960         return;
00961     };
00962     if(m_maskCropCtrl->GetSelection()==0)
00963     {
00964         m_maskMode=true;
00965         size_t imgNr=GetImgNr();
00966         m_selectedImages.clear();
00967         m_selectedImages.insert(imgNr);
00968         m_imagesListMask->SetSingleSelect(true);
00969         m_imagesListMask->SelectSingleImage(imgNr);
00970         m_editImg->SetMaskMode(true);
00971     }
00972     else
00973     {
00974         m_maskMode=false;
00975         m_imagesListMask->SetSingleSelect(false);
00976         m_editImg->SetMaskMode(false);
00977         SelectMask(UINT_MAX);
00978     };
00979     m_editImg->Refresh();
00980 };
00981 
00982 IMPLEMENT_DYNAMIC_CLASS(MaskEditorPanel, wxPanel)
00983 
00984 MaskEditorPanelXmlHandler::MaskEditorPanelXmlHandler()
00985                 : wxXmlResourceHandler()
00986 {
00987     AddWindowStyles();
00988 }
00989 
00990 wxObject *MaskEditorPanelXmlHandler::DoCreateResource()
00991 {
00992     XRC_MAKE_INSTANCE(cp, MaskEditorPanel)
00993 
00994     cp->Create(m_parentAsWindow,
00995                    GetID(),
00996                    GetPosition(), GetSize(),
00997                    GetStyle(wxT("style")),
00998                    GetName());
00999 
01000     SetupWindow(cp);
01001 
01002     return cp;
01003 }
01004 
01005 bool MaskEditorPanelXmlHandler::CanHandle(wxXmlNode *node)
01006 {
01007     return IsOfClass(node, wxT("MaskEditorPanel"));
01008 }
01009 
01010 IMPLEMENT_DYNAMIC_CLASS(MaskEditorPanelXmlHandler, wxXmlResourceHandler)

Generated on 6 Dec 2016 for Hugintrunk by  doxygen 1.4.7