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

Generated on 31 Oct 2014 for Hugintrunk by  doxygen 1.4.7