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             setImage(nrImages-1);
00378         else
00379             // update changed images
00380             if(set_contains(changed,GetImgNr()))
00381             {
00382                 unsigned int countOldMasks=m_currentMasks.size();
00383                 setImage(GetImgNr());
00384                 if(countOldMasks!=pano.getImage(GetImgNr()).getMasks().size())
00385                     SelectMask(UINT_MAX);
00386             };
00387     };
00388 
00389     if (m_selectedImages.size() > 0)
00390     {
00391         if (set_contains(changed, GetImgNr()))
00392         {
00393             DisplayCrop(GetImgNr());
00394         }
00395     }
00396     else
00397     {
00398         UpdateCropDisplay();
00399     }
00400 
00401 }
00402 
00403 void MaskEditorPanel::OnImageSelect(wxListEvent &e)
00404 {
00405     m_selectedImages=m_imagesListMask->GetSelected();
00406     //select no mask
00407     setMask(UINT_MAX);
00408     setImage(GetImgNr());
00409 
00410     bool hasImage = (m_selectedImages.size() > 0);
00411     m_left_textctrl->Enable(hasImage);
00412     m_top_textctrl->Enable(hasImage);
00413     m_bottom_textctrl->Enable(hasImage);
00414     m_right_textctrl->Enable(hasImage);
00415     if (hasImage)
00416     {
00417         // show first image.
00418         DisplayCrop(GetImgNr());
00419     };
00420 };
00421 
00422 void MaskEditorPanel::OnMaskSelect(wxListEvent &e)
00423 {
00424     setMask(GetSelectedMask());
00425 };
00426 
00427 void MaskEditorPanel::OnMaskTypeChange(wxCommandEvent &e)
00428 {
00429     if(GetImgNr()<UINT_MAX && m_MaskNr<UINT_MAX)
00430     {
00431         m_currentMasks[m_MaskNr].setMaskType((HuginBase::MaskPolygon::MaskType)e.GetSelection());
00432         m_defaultMaskType=(HuginBase::MaskPolygon::MaskType)e.GetSelection();
00433         PanoCommand::GlobalCmdHist::getInstance().addCommand(new PanoCommand::UpdateMaskForImgCmd(*m_pano, GetImgNr(), m_currentMasks));
00434     };
00435 };
00436 
00437 void MaskEditorPanel::OnMaskAdd(wxCommandEvent &e)
00438 {
00439     if(GetImgNr()<UINT_MAX)
00440     {
00441         //deselect current selected mask
00442         if(m_MaskNr<UINT_MAX)
00443             m_maskList->SetItemState(m_MaskNr,0,wxLIST_STATE_SELECTED);
00444         setMask(UINT_MAX);
00445         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);
00446         m_editImg->startNewPolygon();
00447     };
00448 };
00449 
00450 void MaskEditorPanel::OnMaskSave(wxCommandEvent &e)
00451 {
00452     if(GetImgNr()<UINT_MAX && m_MaskNr<UINT_MAX)
00453     {
00454         wxFileDialog dlg(this, _("Save mask"),
00455                 wxConfigBase::Get()->Read(wxT("/actualPath"), wxT("")),
00456                 wxT(""), _("Mask files (*.msk)|*.msk|All files (*)|*"), 
00457                 wxFD_SAVE | wxFD_OVERWRITE_PROMPT, wxDefaultPosition);
00458         if (dlg.ShowModal() == wxID_OK) 
00459         {
00460             wxString fn = dlg.GetPath();
00461             if (fn.Right(4) != wxT(".msk"))
00462             {
00463                 fn.Append(wxT(".msk"));
00464                 if (wxFile::Exists(fn))
00465                 {
00466                     int d = wxMessageBox(wxString::Format(_("File %s exists. Overwrite?"),
00467                         fn.c_str()), _("Save mask"),
00468                         wxYES_NO | wxICON_QUESTION);
00469                     if (d != wxYES) {
00470                         return;
00471                     }
00472                 }
00473             };
00474             wxFileName filename = fn;
00475             std::ofstream maskFile(filename.GetFullPath().mb_str(HUGIN_CONV_FILENAME));
00476             SaveMaskToStream(maskFile, m_pano->getImage(GetImgNr()).getSize(), m_currentMasks[m_MaskNr], GetImgNr());
00477             maskFile.close();
00478         };
00479     }
00480 };
00481 
00482 void MaskEditorPanel::OnMaskLoad(wxCommandEvent &e)
00483 {
00484     if (GetImgNr()<UINT_MAX)
00485     {
00486         wxFileDialog dlg(this,_("Load mask"),
00487                 wxConfigBase::Get()->Read(wxT("/actualPath"),wxT("")),
00488                 wxT(""),_("Mask files (*.msk)|*.msk|All files (*)|*"),
00489                 wxFD_OPEN, wxDefaultPosition);
00490         if (dlg.ShowModal() != wxID_OK)
00491         {
00492             MainFrame::Get()->SetStatusText(_("Load mask: cancel"));
00493             return;
00494         }
00495         wxFileName filename(dlg.GetPath());
00496         std::ifstream in(filename.GetFullPath().mb_str(HUGIN_CONV_FILENAME));
00497         vigra::Size2D maskImageSize;
00498         HuginBase::MaskPolygonVector loadedMasks;
00499         LoadMaskFromStream(in, maskImageSize, loadedMasks, GetImgNr());
00500         in.close();
00501         if(maskImageSize.area()==0 || loadedMasks.size()==0)
00502         {
00503             wxMessageBox(wxString::Format(_("Could not parse mask from file %s."),dlg.GetPath().c_str()),_("Warning"),wxOK | wxICON_EXCLAMATION,this);
00504             return;
00505         };
00506         // compare image size from file with that of current image alert user
00507         // if different.
00508         if (maskImageSize != m_pano->getImage(GetImgNr()).getSize()) 
00509         {
00510             MaskLoadDialog dlg(this);
00511             dlg.initValues(m_pano->getImage(GetImgNr()),loadedMasks,maskImageSize);
00512             if(dlg.ShowModal()!=wxID_OK)
00513             {
00514                 // abort
00515                 return;
00516             }
00517             loadedMasks=dlg.getProcessedMask();
00518         }
00519         for(unsigned int i=0;i<loadedMasks.size();i++)
00520             m_currentMasks.push_back(loadedMasks[i]);
00521         // Update the pano with the imported masks
00522         PanoCommand::GlobalCmdHist::getInstance().addCommand(new PanoCommand::UpdateMaskForImgCmd(*m_pano, GetImgNr(), m_currentMasks));
00523     }
00524 };
00525 
00526 void MaskEditorPanel::OnMaskCopy(wxCommandEvent &e)
00527 {
00528     if(GetImgNr()<UINT_MAX && m_MaskNr<UINT_MAX && m_maskMode)
00529     {
00530         std::ostringstream stream;
00531         SaveMaskToStream(stream, m_pano->getImage(GetImgNr()).getSize(), m_currentMasks[m_MaskNr], GetImgNr());
00532         if (wxTheClipboard->Open())
00533         {
00534             // This data objects are held by the clipboard,
00535             // so do not delete them in the app.
00536             wxTheClipboard->SetData(new wxTextDataObject(wxString(stream.str().c_str(),wxConvLocal)));
00537             wxTheClipboard->Close();
00538         };
00539     };
00540 };
00541 
00542 void MaskEditorPanel::OnMaskPaste(wxCommandEvent &e)
00543 {
00544     if(GetImgNr()<UINT_MAX && m_maskMode)
00545     {
00546         if (wxTheClipboard->Open())
00547         {
00548             vigra::Size2D maskImageSize;
00549             HuginBase::MaskPolygonVector loadedMasks;
00550             if (wxTheClipboard->IsSupported( wxDF_TEXT ))
00551             {
00552                 wxTextDataObject data;
00553                 wxTheClipboard->GetData(data);
00554                 std::istringstream stream(std::string(data.GetText().mb_str()));
00555                 LoadMaskFromStream(stream, maskImageSize, loadedMasks, GetImgNr());
00556             }
00557             wxTheClipboard->Close();
00558             if(maskImageSize.area()==0 || loadedMasks.size()==0)
00559             {
00560                 wxBell();
00561                 return;
00562             };
00563             // compare image size from file with that of current image alert user
00564             // if different.
00565             if (maskImageSize != m_pano->getImage(GetImgNr()).getSize()) 
00566             {
00567                 MaskLoadDialog dlg(this);
00568                 dlg.initValues(m_pano->getImage(GetImgNr()),loadedMasks,maskImageSize);
00569                 if(dlg.ShowModal()!=wxID_OK)
00570                 {
00571                     // abort
00572                     return;
00573                 }
00574                 loadedMasks=dlg.getProcessedMask();
00575             }
00576             for(unsigned int i=0;i<loadedMasks.size();i++)
00577                 m_currentMasks.push_back(loadedMasks[i]);
00578             // Update the pano with the imported masks
00579             PanoCommand::GlobalCmdHist::getInstance().addCommand(new PanoCommand::UpdateMaskForImgCmd(*m_pano, GetImgNr(), m_currentMasks));
00580         };
00581     };
00582 };
00583 
00584 void MaskEditorPanel::OnMaskDelete(wxCommandEvent &e)
00585 {
00586     if(GetImgNr()<UINT_MAX && m_MaskNr<UINT_MAX)
00587     {
00588         HuginBase::MaskPolygonVector editedMasks=m_currentMasks;
00589         editedMasks.erase(editedMasks.begin()+m_MaskNr);
00590         //setMask(UINT_MAX);
00591         PanoCommand::GlobalCmdHist::getInstance().addCommand(new PanoCommand::UpdateMaskForImgCmd(*m_pano, GetImgNr(), editedMasks));
00592     };
00593 };
00594 
00595 void MaskEditorPanel::OnZoom(wxCommandEvent & e)
00596 {
00597     int posX = 0;
00598     int posY = 0;
00599     const wxSize ctrlSize = m_editImg->GetClientSize();
00600     if (m_editImg->getScale() > 0)
00601     {
00602         // remember old scroll position
00603         posX = (m_editImg->GetScrollPos(wxHORIZONTAL) + ctrlSize.GetWidth() / 2) / m_editImg->getScale();
00604         posY = (m_editImg->GetScrollPos(wxVERTICAL) + ctrlSize.GetHeight() / 2) / m_editImg->getScale();
00605     };
00606     double factor;
00607     switch (e.GetSelection()) 
00608     {
00609         case 0:
00610             factor = 1;
00611             break;
00612         case 1:
00613             // fit to window
00614             factor = 0;
00615             break;
00616         case 2:
00617             factor = 2;
00618             break;
00619         case 3:
00620             factor = 1.5;
00621             break;
00622         case 4:
00623             factor = 0.75;
00624             break;
00625         case 5:
00626             factor = 0.5;
00627             break;
00628         case 6:
00629             factor = 0.25;
00630             break;
00631         default:
00632             DEBUG_ERROR("unknown scale factor");
00633             factor = 1;
00634     }
00635     m_editImg->setScale(factor);
00636     if (factor > 0)
00637     {
00638         m_editImg->Scroll(posX*factor - ctrlSize.GetWidth() / 2, posY*factor - ctrlSize.GetHeight() / 2);
00639     };
00640 }
00641 
00642 void MaskEditorPanel::OnColourChanged(wxColourPickerEvent &e)
00643 {
00644     if(e.GetId()==XRCID("mask_editor_colour_polygon_negative"))
00645     {
00646         m_editImg->SetUserColourPolygonNegative(e.GetColour());
00647         wxConfigBase::Get()->Write(wxT("/MaskEditorPanel/ColourPolygonNegative"),e.GetColour().GetAsString(wxC2S_HTML_SYNTAX));
00648     }
00649     else 
00650         if(e.GetId()==XRCID("mask_editor_colour_polygon_positive"))
00651         {
00652             m_editImg->SetUserColourPolygonPositive(e.GetColour());
00653             wxConfigBase::Get()->Write(wxT("/MaskEditorPanel/ColourPolygonPositive"),e.GetColour().GetAsString(wxC2S_HTML_SYNTAX));
00654         }
00655         else
00656             if(e.GetId()==XRCID("mask_editor_colour_point_selected"))
00657             {
00658                 m_editImg->SetUserColourPointSelected(e.GetColour());
00659                 wxConfigBase::Get()->Write(wxT("/MaskEditorPanel/ColourPointSelected"),e.GetColour().GetAsString(wxC2S_HTML_SYNTAX));
00660             }
00661             else
00662             {
00663                 m_editImg->SetUserColourPointUnselected(e.GetColour());
00664                 wxConfigBase::Get()->Write(wxT("/MaskEditorPanel/ColourPointUnselected"),e.GetColour().GetAsString(wxC2S_HTML_SYNTAX));
00665             }
00666     m_editImg->Refresh(true);
00667 };
00668 
00669 void MaskEditorPanel::UpdateMaskList(bool restoreSelection)
00670 {
00671     unsigned int oldSelection=GetSelectedMask();
00672     m_maskList->Freeze();
00673     if(GetImgNr()<UINT_MAX)
00674     {
00675         if(m_currentMasks.size()>0)
00676         {
00677             if(m_maskList->GetItemCount()!=m_currentMasks.size())
00678             {
00679                 if(m_maskList->GetItemCount()<(int)m_currentMasks.size())
00680                 {
00681                     //added masks
00682                     for(int i=m_maskList->GetItemCount();i<(int)m_currentMasks.size();i++)
00683                         m_maskList->InsertItem(i,wxString::Format(wxT("%d"),i));
00684                 }
00685                 else
00686                 {
00687                     //deleted masks
00688                     for(int i=m_maskList->GetItemCount()-1;i>=(int)m_currentMasks.size();i--)
00689                         m_maskList->DeleteItem(i);
00690                 };
00691             };
00692             for(unsigned int i=0;i<m_currentMasks.size();i++)
00693             {
00694                 m_maskList->SetItem(i,1,m_maskType->GetString(m_currentMasks[i].getMaskType()));
00695                 if(!restoreSelection && i==oldSelection)
00696                     m_maskList->SetItemState(i,0, wxLIST_STATE_SELECTED);
00697             };
00698         }
00699         else
00700             m_maskList->DeleteAllItems();
00701     }
00702     else
00703         m_maskList->DeleteAllItems();
00704     m_maskList->Thaw();
00705     m_maskType->Enable(m_maskList->GetSelectedItemCount()>0);
00706 }
00707 
00708 unsigned int MaskEditorPanel::GetSelectedMask()
00709 {
00710     for(unsigned int i=0;i<(unsigned int)m_maskList->GetItemCount();i++)
00711     {
00712         if(m_maskList->GetItemState(i,wxLIST_STATE_SELECTED) & wxLIST_STATE_SELECTED)
00713             return i;
00714     };
00715     return UINT_MAX;
00716 };
00717 
00718 void MaskEditorPanel::OnColumnWidthChange( wxListEvent & e )
00719 {
00720     int colNum = e.GetColumn();
00721     wxConfigBase::Get()->Write( wxString::Format(wxT("/MaskEditorPanel/ColumnWidth%d"),colNum), m_maskList->GetColumnWidth(colNum) );
00722 }
00723 
00724 MaskImageCtrl::ImageRotation MaskEditorPanel::GetRot(const unsigned int imgNr)
00725 {
00726     if(imgNr==UINT_MAX)
00727         return MaskImageCtrl::ROT0;
00728 
00729     double pitch=m_pano->getImage(imgNr).getPitch();
00730     double roll=m_pano->getImage(imgNr).getRoll();
00731     
00732     MaskImageCtrl::ImageRotation rot = MaskImageCtrl::ROT0;
00733     // normalize roll angle
00734     while (roll > 360) roll-= 360;
00735     while (roll < 0) roll += 360;
00736 
00737     while (pitch > 180) pitch -= 360;
00738     while (pitch < -180) pitch += 360;
00739     bool headOver = (pitch > 90 || pitch < -90);
00740 
00741     if (roll >= 315 || roll < 45) 
00742     {
00743         rot = headOver ? MaskImageCtrl::ROT180 : MaskImageCtrl::ROT0;
00744     } 
00745     else 
00746         if (roll >= 45 && roll < 135) 
00747         {
00748             rot = headOver ? MaskImageCtrl::ROT270 : MaskImageCtrl::ROT90;
00749         }
00750         else 
00751             if (roll >= 135 && roll < 225) 
00752             {
00753                 rot = headOver ? MaskImageCtrl::ROT0 : MaskImageCtrl::ROT180;
00754             } 
00755             else 
00756             {
00757                 rot = headOver ? MaskImageCtrl::ROT90 : MaskImageCtrl::ROT270;
00758             }
00759     return rot;
00760 }
00761 
00762 void MaskEditorPanel::OnShowActiveMasks(wxCommandEvent &e)
00763 {
00764     m_editImg->setDrawingActiveMasks(e.IsChecked());
00765 };
00766 
00767 void MaskEditorPanel::DisplayCrop(int imgNr)
00768 {
00769     const HuginBase::SrcPanoImage & img = m_pano->getImage(imgNr);
00770     m_cropMode=img.getCropMode();
00771     m_cropRect=img.getCropRect();
00772     m_autoCenterCrop=img.getAutoCenterCrop();
00773 
00774     int dx = hugin_utils::roundi(img.getRadialDistortionCenterShift().x);
00775     int dy = hugin_utils::roundi(img.getRadialDistortionCenterShift().y);
00777     m_cropCenter = vigra::Point2D(img.getSize().width()/2 + dx, img.getSize().height()/2 + dy);
00778 
00779     UpdateCropDisplay();
00780 }
00781 
00782 // transfer our state to panorama
00783 void MaskEditorPanel::UpdateCrop(bool updateFromImgCtrl)
00784 {
00785     // set crop image options.
00786     if(updateFromImgCtrl)
00787     {
00788         m_cropRect=m_editImg->getCrop();
00789     };
00790     std::vector<HuginBase::SrcPanoImage> srcImgs;
00791     HuginBase::UIntSet imgs;
00792     if (m_cropLens->IsChecked())
00793     {
00794         const HuginBase::UIntSetVector lensImageVector = m_imageGroups->getLenses().getPartsSet();
00795         for (auto i : m_selectedImages)
00796         {
00797             for (auto j : lensImageVector)
00798             {
00799                 if (set_contains(j, i))
00800                 {
00801                     std::copy(j.begin(), j.end(), std::inserter(imgs, imgs.begin()));
00802                     break;
00803                 };
00804             };
00805         };
00806     }
00807     else
00808     {
00809         imgs = m_selectedImages;
00810     }
00811     for (auto i:imgs)
00812     {
00813         HuginBase::SrcPanoImage img=m_pano->getSrcImage(i);
00814         img.setCropRect(m_cropRect);
00815         img.setAutoCenterCrop(m_autoCenterCrop);
00816         srcImgs.push_back(img);
00817     };
00818 
00819     PanoCommand::GlobalCmdHist::getInstance().addCommand(
00820             new PanoCommand::UpdateSrcImagesCmd(*m_pano, imgs, srcImgs)
00821     );
00822 }
00823 
00824 void MaskEditorPanel::UpdateCropFromImage()
00825 {
00826     m_cropRect=m_editImg->getCrop();
00827     UpdateCropDisplay();
00828 };
00829 
00830 // redraw display with new information
00831 void MaskEditorPanel::UpdateCropDisplay()
00832 {
00833     DEBUG_TRACE("")
00834     m_autocenter_cb->SetValue(m_autoCenterCrop);
00835     m_left_textctrl->SetValue(wxString::Format(wxT("%d"),m_cropRect.left()));
00836     m_right_textctrl->SetValue(wxString::Format(wxT("%d"),m_cropRect.right()));
00837     m_top_textctrl->SetValue(wxString::Format(wxT("%d"),m_cropRect.top()));
00838     m_bottom_textctrl->SetValue(wxString::Format(wxT("%d"),m_cropRect.bottom()));
00839 }
00840 
00841 
00842 void MaskEditorPanel::OnSetTop(wxCommandEvent & e)
00843 {
00844     long val;
00845     if (m_top_textctrl->GetValue().ToLong(&val))
00846     {
00847         m_cropRect.setUpperLeft(vigra::Point2D(m_cropRect.left(), val));
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::OnSetBottom(wxCommandEvent & e)
00862 {
00863     long val;
00864     if (m_bottom_textctrl->GetValue().ToLong(&val))
00865     {
00866         m_cropRect.setLowerRight(vigra::Point2D(m_cropRect.right(), val));
00867         if (m_autoCenterCrop)
00868         {
00869             CenterCrop();
00870             UpdateCropDisplay();
00871         }
00872         UpdateCrop();
00873     }
00874     else
00875     {
00876         wxLogError(_("Please enter a valid number"));
00877     };
00878 };
00879 
00880 void MaskEditorPanel::OnSetLeft(wxCommandEvent & e)
00881 {
00882     long val = 0;
00883     if (m_left_textctrl->GetValue().ToLong(&val))
00884     {
00885         m_cropRect.setUpperLeft(vigra::Point2D(val, m_cropRect.top()));
00886         if (m_autoCenterCrop)
00887         {
00888             CenterCrop();
00889             UpdateCropDisplay();
00890         }
00891         UpdateCrop();
00892     }
00893     else
00894     {
00895         wxLogError(_("Please enter a valid number"));
00896     };
00897 };
00898 
00899 void MaskEditorPanel::OnSetRight(wxCommandEvent & e)
00900 {
00901     long val = 0;
00902     if (m_right_textctrl->GetValue().ToLong(&val))
00903     {
00904         m_cropRect.setLowerRight(vigra::Point2D(val, m_cropRect.bottom()));
00905         if (m_autoCenterCrop)
00906         {
00907             CenterCrop();
00908             UpdateCropDisplay();
00909         };
00910         UpdateCrop();
00911     }
00912     else
00913     {
00914         wxLogError(_("Please enter a valid number"));
00915     };
00916 };
00917 
00918 void MaskEditorPanel::OnResetButton(wxCommandEvent & e)
00919 {
00920     // suitable defaults.
00921     m_cropRect.setUpperLeft(vigra::Point2D(0,0));
00922     m_cropRect.setLowerRight(vigra::Point2D(0,0));
00923     m_autoCenterCrop = true;
00924     m_cropMode=HuginBase::SrcPanoImage::NO_CROP;
00925     UpdateCropDisplay();
00926     UpdateCrop();
00927 }
00928 
00929 void MaskEditorPanel::OnAutoCenter(wxCommandEvent & e)
00930 {
00931     m_autoCenterCrop = e.IsChecked();
00932     if (m_autoCenterCrop)
00933     {
00934         CenterCrop();
00935         UpdateCropDisplay();
00936     };
00937     UpdateCrop();
00938 }
00939 
00940 void MaskEditorPanel::CenterCrop()
00941 {
00942     vigra::Diff2D d(m_cropRect.width()/2, m_cropRect.height() / 2);
00943     m_cropRect.setUpperLeft( m_cropCenter - d);
00944     m_cropRect.setLowerRight( m_cropCenter + d);
00945 }
00946 
00947 void MaskEditorPanel::OnModeChanged(wxNotebookEvent& e)
00948 {
00949     if(m_maskCropCtrl==NULL)
00950     {
00951         return;
00952     };
00953     if(m_maskCropCtrl->GetSelection()==0)
00954     {
00955         m_maskMode=true;
00956         size_t imgNr=GetImgNr();
00957         m_selectedImages.clear();
00958         m_selectedImages.insert(imgNr);
00959         m_imagesListMask->SetSingleSelect(true);
00960         m_imagesListMask->SelectSingleImage(imgNr);
00961         m_editImg->SetMaskMode(true);
00962     }
00963     else
00964     {
00965         m_maskMode=false;
00966         m_imagesListMask->SetSingleSelect(false);
00967         m_editImg->SetMaskMode(false);
00968         SelectMask(UINT_MAX);
00969     };
00970     m_editImg->Refresh();
00971 };
00972 
00973 IMPLEMENT_DYNAMIC_CLASS(MaskEditorPanel, wxPanel)
00974 
00975 MaskEditorPanelXmlHandler::MaskEditorPanelXmlHandler()
00976                 : wxXmlResourceHandler()
00977 {
00978     AddWindowStyles();
00979 }
00980 
00981 wxObject *MaskEditorPanelXmlHandler::DoCreateResource()
00982 {
00983     XRC_MAKE_INSTANCE(cp, MaskEditorPanel)
00984 
00985     cp->Create(m_parentAsWindow,
00986                    GetID(),
00987                    GetPosition(), GetSize(),
00988                    GetStyle(wxT("style")),
00989                    GetName());
00990 
00991     SetupWindow(cp);
00992 
00993     return cp;
00994 }
00995 
00996 bool MaskEditorPanelXmlHandler::CanHandle(wxXmlNode *node)
00997 {
00998     return IsOfClass(node, wxT("MaskEditorPanel"));
00999 }
01000 
01001 IMPLEMENT_DYNAMIC_CLASS(MaskEditorPanelXmlHandler, wxXmlResourceHandler)

Generated on 30 Jul 2016 for Hugintrunk by  doxygen 1.4.7