MaskImageCtrl.cpp

Go to the documentation of this file.
00001 // -*- c-basic-offset: 4 -*-
00002 
00013 /*  This program is free software; you can redistribute it and/or
00014  *  modify it under the terms of the GNU General Public
00015  *  License as published by the Free Software Foundation; either
00016  *  version 2 of the License, or (at your option) any later version.
00017  *
00018  *  This software is distributed in the hope that it will be useful,
00019  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00020  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00021  *  General Public License for more details.
00022  *
00023  *  You should have received a copy of the GNU General Public
00024  *  License along with this software. If not, see
00025  *  <http://www.gnu.org/licenses/>.
00026  *
00027  */
00028 
00029 #include "panoinc_WX.h"
00030 #include "panoinc.h"
00031 #include "base_wx/platform.h"
00032 #include "base_wx/wxcms.h"
00033 #include "hugin/MainFrame.h"
00034 #include "hugin/huginApp.h"
00035 #include "hugin/config_defaults.h"
00036 #include "hugin/MaskImageCtrl.h"
00037 #include "hugin/MaskEditorPanel.h"
00038 #include "base_wx/wxImageCache.h"
00039 #ifndef SUPPORTS_WXINVERT
00040 #include <vigra/inspectimage.hxx>
00041 #endif
00042 
00044 const int polygonPointSize=3;
00046 const int maxSelectionDistance=20;
00047 
00048 #if !wxCHECK_VERSION(3,0,0)
00049 #define wxPENSTYLE_SOLID wxSOLID
00050 #define wxPENSTYLE_DOT wxDOT
00051 #define wxBRUSHSTYLE_TRANSPARENT wxTRANSPARENT
00052 #define wxBRUSHSTYLE_SOLID wxSOLID
00053 #endif
00054 
00055 // our image control
00056 
00057 BEGIN_EVENT_TABLE(MaskImageCtrl, wxScrolledWindow)
00058     EVT_SIZE(MaskImageCtrl::OnSize)
00059     EVT_MOTION(MaskImageCtrl::OnMouseMove)
00060     EVT_LEFT_DOWN(MaskImageCtrl::OnLeftMouseDown)
00061     EVT_LEFT_UP(MaskImageCtrl::OnLeftMouseUp)
00062     EVT_LEFT_DCLICK(MaskImageCtrl::OnLeftMouseDblClick)
00063     EVT_RIGHT_DOWN(MaskImageCtrl::OnRightMouseDown)
00064     EVT_RIGHT_UP(MaskImageCtrl::OnRightMouseUp)
00065     EVT_KEY_UP(MaskImageCtrl::OnKeyUp)
00066     EVT_MOUSE_CAPTURE_LOST(MaskImageCtrl::OnCaptureLost)
00067     EVT_KILL_FOCUS(MaskImageCtrl::OnKillFocus)
00068     EVT_SCROLLWIN(MaskImageCtrl::OnScroll)
00069 END_EVENT_TABLE()
00070 
00071 bool MaskImageCtrl::Create(wxWindow * parent, wxWindowID id,
00072                          const wxPoint& pos,
00073                          const wxSize& size,
00074                          long style,
00075                          const wxString& name)
00076 {
00077     wxScrolledWindow::Create(parent, id, pos, size, style, name);
00078     m_maskEditState = NO_IMAGE;
00079     m_imgRotation = ROT0;
00080     m_scaleFactor = 1;
00081     m_fitToWindow = false;
00082     m_previewOnly = false;
00083     m_activeMask = UINT_MAX;
00084     m_showActiveMasks = false;
00085     m_maskMode = true;
00086     m_oldScrollPosX = -1;
00087     m_oldScrollPosY = -1;
00088 
00089     return true;
00090 }
00091 
00092 void MaskImageCtrl::Init(MaskEditorPanel * parent)
00093 {
00094     m_editPanel = parent;
00095 }
00096 
00097 void MaskImageCtrl::SetMaskMode(bool newMaskMode)
00098 {
00099     m_maskMode=newMaskMode;
00100     if(m_maskMode)
00101     {
00102         SetCursor(wxNullCursor);
00103         if(m_maskEditState!=NO_IMAGE)
00104         {
00105             m_maskEditState=NO_SELECTION;
00106             setActiveMask(UINT_MAX,false);
00107         };
00108     }
00109     else
00110     {
00111         if(m_maskEditState!=NO_IMAGE)
00112         {
00113             m_maskEditState=CROP_SHOWING;
00114         };
00115     };
00116 };
00117 
00118 void MaskImageCtrl::setImage(const std::string & file, HuginBase::MaskPolygonVector newMask, HuginBase::MaskPolygonVector masksToDraw, ImageRotation rot)
00119 {
00120     DEBUG_TRACE("setting Image " << file);
00121     m_imageFilename = file;
00122     wxString fn(m_imageFilename.c_str(),HUGIN_CONV_FILENAME);
00123     if (wxFileName::FileExists(fn))
00124     {
00125         m_img = ImageCache::getInstance().getImage(m_imageFilename);
00126         if(m_maskMode)
00127         {
00128             m_maskEditState = NO_MASK;
00129         }
00130         else
00131         {
00132             m_maskEditState = CROP_SHOWING;
00133         };
00134         m_imageMask=newMask;
00135         m_masksToDraw=masksToDraw;
00136         m_imgRotation=rot;
00137         setActiveMask(UINT_MAX,false);
00138         rescaleImage();
00139         Scroll(m_oldScrollPosX, m_oldScrollPosY);
00140     }
00141     else
00142     {
00143         m_maskEditState = NO_IMAGE;
00144         m_bitmap = wxBitmap();
00145         // delete the image (release shared_ptr)
00146         // create an empty image.
00147         m_img = ImageCache::EntryPtr(new ImageCache::Entry);
00148         HuginBase::MaskPolygonVector mask;
00149         m_imageMask=mask;
00150         m_masksToDraw=mask;
00151         m_imgRotation=ROT0;
00152         setActiveMask(UINT_MAX,false);
00153         SetVirtualSize(100,100);
00154         Refresh(true);
00155     }
00156 }
00157 
00158 void MaskImageCtrl::setNewMasks(HuginBase::MaskPolygonVector newMasks, HuginBase::MaskPolygonVector masksToDraw)
00159 {
00160     m_imageMask=newMasks;
00161     m_masksToDraw=masksToDraw;
00162     if (m_activeMask >= m_imageMask.size())
00163     {
00164         setActiveMask(UINT_MAX);
00165     }
00166     else
00167     {
00168         setActiveMask(m_activeMask);
00169     };
00170     Refresh(false);
00171 };
00172 
00173 void MaskImageCtrl::setCrop(HuginBase::SrcPanoImage::CropMode newCropMode, vigra::Rect2D newCropRect, bool isCentered, hugin_utils::FDiff2D center, bool isCircleCrop)
00174 {
00175     m_cropMode=newCropMode;
00176     m_cropRect=newCropRect;
00177     m_cropCentered=isCentered;
00178     m_cropCenter=center;
00179     m_cropCircle=isCircleCrop;
00180 };
00181 
00182 void MaskImageCtrl::setActiveMask(unsigned int newMask, bool doUpdate)
00183 {
00184     if(m_activeMask!=newMask)
00185     {
00186         m_activeMask=newMask;
00187         m_selectedPoints.clear();
00188     };
00189     if(newMask<UINT_MAX)
00190     {
00191         if(m_maskMode)
00192         {
00193             if(m_selectedPoints.empty())
00194             {
00195                 m_maskEditState=NO_SELECTION;
00196             }
00197             else
00198             {
00199                 m_maskEditState=POINTS_SELECTED;
00200             };
00201         }
00202         else
00203         {
00204             m_selectedPoints.clear();
00205             m_maskEditState=CROP_SHOWING;
00206         };
00207         m_editingMask=m_imageMask[m_activeMask];
00208     }
00209     else
00210     {
00211         if(!m_imageFilename.empty())
00212         {
00213             if(m_maskMode)
00214             {
00215                 m_maskEditState=NO_MASK;
00216             }
00217             else
00218             {
00219                 m_maskEditState=CROP_SHOWING;
00220             };
00221         };
00222         HuginBase::MaskPolygon mask;
00223         m_editingMask=mask;
00224     };
00225     if(doUpdate)
00226         Refresh(true);
00227 };
00228 
00229 void MaskImageCtrl::selectAllMarkers()
00230 {
00231     m_selectedPoints.clear();
00232     if(m_activeMask<UINT_MAX)
00233         fill_set(m_selectedPoints,0,m_imageMask[m_activeMask].getMaskPolygon().size()-1);
00234 };
00235 
00236 // returns where the user clicked
00237 MaskImageCtrl::ClickPos MaskImageCtrl::GetClickPos(vigra::Point2D pos)
00238 {
00239     vigra::Rect2D testRect(pos.x-maxSelectionDistance, pos.y-maxSelectionDistance, pos.x+maxSelectionDistance, pos.y+maxSelectionDistance);
00240     if (m_cropMode == HuginBase::SrcPanoImage::CROP_CIRCLE)
00241     {
00242         double radius=std::min<int>(m_cropRect.width(), m_cropRect.height())/2.0;
00243         vigra::Point2D pos_center((m_cropRect.left()+m_cropRect.right())/2, (m_cropRect.top()+m_cropRect.bottom())/2);
00244         double dist=sqrt(double((pos-pos_center).squaredMagnitude()));
00245         if(dist-maxSelectionDistance<radius && radius<dist+maxSelectionDistance)
00246         {
00247             return CLICK_CIRCLE;
00248         };
00249     };
00250     if(m_cropRect.intersects(testRect))
00251     {
00252         if(abs(pos.x-m_cropRect.left())<maxSelectionDistance)
00253         {
00254             return CLICK_LEFT;
00255         };
00256         if(abs(pos.x-m_cropRect.right())<maxSelectionDistance)
00257         {
00258             return CLICK_RIGHT;
00259         };
00260         if(abs(pos.y-m_cropRect.top())<maxSelectionDistance)
00261         {
00262             return CLICK_TOP;
00263         };
00264         if(abs(pos.y-m_cropRect.bottom())<maxSelectionDistance)
00265         {
00266             return CLICK_BOTTOM;
00267         };
00268     };
00269     if(m_cropRect.contains(pos))
00270     {
00271         return CLICK_INSIDE;
00272     };
00273     return CLICK_OUTSIDE;
00274 };
00275 
00276 void MaskImageCtrl::UpdateCrop(hugin_utils::FDiff2D pos)
00277 {
00278     hugin_utils::FDiff2D delta=pos-applyRotInv(invtransform(m_currentPos));
00279     int newLeft, newRight, newTop, newBottom;
00280     bool needsUpdate=false;
00281     switch (m_maskEditState)
00282     {
00283         case CROP_MOVING:
00284             m_cropRect.moveBy(delta.x,delta.y);
00285             break;
00286         case CROP_LEFT_MOVING:
00287             if(m_cropCentered)
00288             {
00289                 double newHalfWidth=m_cropRect.width()/2.0-delta.x;
00290                 newLeft=hugin_utils::roundi(m_cropCenter.x-newHalfWidth);
00291                 newRight=hugin_utils::roundi(m_cropCenter.x+newHalfWidth);
00292             }
00293             else
00294             {
00295                 newLeft=m_cropRect.left()+delta.x;
00296                 newRight=m_cropRect.right();
00297             };
00298             newTop=m_cropRect.top();
00299             newBottom=m_cropRect.bottom();
00300             needsUpdate=true;
00301             break;
00302         case CROP_RIGHT_MOVING:
00303             if(m_cropCentered)
00304             {
00305                 double newHalfWidth=m_cropRect.width()/2.0+delta.x;
00306                 newLeft=hugin_utils::roundi(m_cropCenter.x-newHalfWidth);
00307                 newRight=hugin_utils::roundi(m_cropCenter.x+newHalfWidth);
00308             }
00309             else
00310             {
00311                 newLeft=m_cropRect.left();
00312                 newRight=m_cropRect.right()+delta.x;
00313             };
00314             newTop=m_cropRect.top();
00315             newBottom=m_cropRect.bottom();
00316             needsUpdate=true;
00317             break;
00318         case CROP_TOP_MOVING:
00319             if(m_cropCentered)
00320             {
00321                 double newHalfHeight=m_cropRect.height()/2.0-delta.y;
00322                 newTop=hugin_utils::roundi(m_cropCenter.y-newHalfHeight);
00323                 newBottom=hugin_utils::roundi(m_cropCenter.y+newHalfHeight);
00324             }
00325             else
00326             {
00327                 newTop=m_cropRect.top()+delta.y;
00328                 newBottom=m_cropRect.bottom();
00329             };
00330             newLeft=m_cropRect.left();
00331             newRight=m_cropRect.right();
00332             needsUpdate=true;
00333             break;
00334         case CROP_BOTTOM_MOVING:
00335             if(m_cropCentered)
00336             {
00337                 double newHalfHeight=m_cropRect.height()/2.0+delta.y;
00338                 newTop=hugin_utils::roundi(m_cropCenter.y-newHalfHeight);
00339                 newBottom=hugin_utils::roundi(m_cropCenter.y+newHalfHeight);
00340             }
00341             else
00342             {
00343                 newTop=m_cropRect.top();
00344                 newBottom=m_cropRect.bottom()+delta.y;
00345             };
00346             newLeft=m_cropRect.left();
00347             newRight=m_cropRect.right();
00348             needsUpdate=true;
00349             break;
00350         case CROP_CIRCLE_SCALING:
00351             {
00352                 double radius=sqrt(hugin_utils::sqr(pos.x-m_dragStartPos.x)+hugin_utils::sqr(pos.y-m_dragStartPos.y));
00353                 newLeft=m_dragStartPos.x-radius;
00354                 newRight=m_dragStartPos.x+radius;
00355                 newTop=m_dragStartPos.y-radius;
00356                 newBottom=m_dragStartPos.y+radius;
00357                 needsUpdate=true;
00358             };
00359             break;
00360         default:
00361             // in all other cases the crop is not changed
00362             // this should not happen
00363             break;
00364     };
00365     if(needsUpdate)
00366     {
00367         // switch left/right or top/bottom if necessary
00368         if(newLeft>newRight)
00369         {
00370             int temp=newLeft;
00371             newLeft=newRight;
00372             newRight=temp;
00373         };
00374         if(newTop>newBottom)
00375         {
00376             int temp=newTop;
00377             newTop=newBottom;
00378             newBottom=temp;
00379         };
00380         m_cropRect.setUpperLeft(vigra::Point2D(newLeft, newTop));
00381         m_cropRect.setLowerRight(vigra::Point2D(newRight, newBottom));
00382     };
00383 };
00384 
00385 void MaskImageCtrl::OnMouseMove(wxMouseEvent& mouse)
00386 {
00387     if(m_previewOnly)
00388         return;
00389     wxPoint mpos;
00390     CalcUnscrolledPosition(mouse.GetPosition().x, mouse.GetPosition().y,
00391                            &mpos.x, & mpos.y);
00392     hugin_utils::FDiff2D currentPos=applyRotInv(invtransform(mpos));
00393     bool doUpdate = false;
00394     switch(m_maskEditState)
00395     {
00396         case NEW_POLYGON_CREATING:
00397             doUpdate=true;
00398             m_editingMask.movePointTo(m_editingMask.getMaskPolygon().size()-1,currentPos);
00399             break;
00400         case POLYGON_SELECTING:
00401         case REGION_SELECTING:
00402         case POINTS_DELETING:
00403 #if defined SUPPORTS_WXINVERT
00404             DrawSelectionRectangle();
00405 #endif
00406             m_currentPos=mpos;
00407             DrawSelectionRectangle();
00408             break;
00409         case POINTS_MOVING:
00410             doUpdate=true;
00411             m_editingMask=m_imageMask[m_activeMask];
00412             {
00413                 hugin_utils::FDiff2D delta=currentPos-applyRotInv(invtransform(m_dragStartPos));
00414                 for(HuginBase::UIntSet::const_iterator it=m_selectedPoints.begin();it!=m_selectedPoints.end();++it)
00415                     m_editingMask.movePointBy(*it,delta);
00416             };
00417             break;
00418         case POINTS_ADDING:
00419             doUpdate=true;
00420             for(HuginBase::UIntSet::const_iterator it=m_selectedPoints.begin();it!=m_selectedPoints.end();++it)
00421                 m_editingMask.movePointTo(*it,currentPos);
00422             break;
00423         case CROP_SHOWING:
00424             switch(GetClickPos(vigra::Point2D(currentPos.x, currentPos.y)))
00425             {
00426                 case CLICK_INSIDE:
00427                     if(!m_cropCentered)
00428                     {
00429                         SetCursor(wxCURSOR_HAND);
00430                     }
00431                     else
00432                     {
00433                         SetCursor(wxNullCursor);
00434                     };
00435                     break;
00436                 case CLICK_LEFT:
00437                 case CLICK_RIGHT:
00438                     switch (m_imgRotation)
00439                     {
00440                         case ROT90:
00441                         case ROT270:
00442                             SetCursor(wxCURSOR_SIZENS);
00443                             break;
00444                         default:
00445                             SetCursor(wxCURSOR_SIZEWE);
00446                     };
00447                     break;
00448                 case CLICK_TOP:
00449                 case CLICK_BOTTOM:
00450                     switch (m_imgRotation)
00451                     {
00452                         case ROT90:
00453                         case ROT270:
00454                             SetCursor(wxCURSOR_SIZEWE);
00455                             break;
00456                         default:
00457                             SetCursor(wxCURSOR_SIZENS);
00458                     };
00459                     break;
00460                 case CLICK_CIRCLE:
00461                     SetCursor(wxCURSOR_SIZING);
00462                     break;
00463                 default:
00464                     SetCursor(wxNullCursor);
00465             };
00466             break;
00467         case CROP_MOVING:
00468         case CROP_LEFT_MOVING:
00469         case CROP_RIGHT_MOVING:
00470         case CROP_TOP_MOVING:
00471         case CROP_BOTTOM_MOVING:
00472         case CROP_CIRCLE_SCALING:
00473 #if defined SUPPORTS_WXINVERT
00474             DrawCrop();
00475 #else
00476             doUpdate=true;
00477 #endif
00478             UpdateCrop(currentPos);
00479             m_currentPos=mpos;
00480 #if defined SUPPORTS_WXINVERT
00481             DrawCrop();
00482 #endif
00483             m_editPanel->UpdateCropFromImage();
00484             break;
00485         case NO_IMAGE:
00486         case NO_MASK:
00487         case NO_SELECTION:
00488         case POINTS_SELECTED:
00489         case NEW_POLYGON_STARTED:
00490             // in all other cases do nothing
00491             break;
00492     };
00493     if(doUpdate)
00494         update();
00495 }
00496 
00497 void MaskImageCtrl::OnLeftMouseDown(wxMouseEvent& mouse)
00498 {
00499     if(m_previewOnly)
00500         return;
00501     DEBUG_DEBUG("LEFT MOUSE DOWN");
00502     CalcUnscrolledPosition(mouse.GetPosition().x, mouse.GetPosition().y,
00503                            &m_dragStartPos.x, & m_dragStartPos.y);
00504     hugin_utils::FDiff2D currentPos=applyRotInv(invtransform(m_dragStartPos));
00505     m_currentPos=m_dragStartPos;
00506     if(!HasCapture())
00507         CaptureMouse();
00508     SetFocus();
00509     switch(m_maskEditState)
00510     {
00511         case NEW_POLYGON_STARTED:
00512             //starting polygon creating
00513             m_editingMask.addPoint(currentPos);
00514             m_selectedPoints.insert(m_editingMask.getMaskPolygon().size()-1);
00515             break;
00516         case NO_MASK:
00517             if(m_maskMode)
00518             {
00519                 m_maskEditState=POLYGON_SELECTING;
00520                 DrawSelectionRectangle();
00521             };
00522             break;
00523         case NO_SELECTION:
00524             if(mouse.CmdDown())
00525             {
00526                 // check if mouse clicks happens near one line of active polygon
00527                 unsigned int index=m_editingMask.FindPointNearPos(currentPos,5*maxSelectionDistance);
00528                 if(index<UINT_MAX)
00529                 {
00530                     m_selectedPoints.clear();
00531                     m_editingMask.insertPoint(index,currentPos);
00532                     m_selectedPoints.insert(index);
00533                     m_maskEditState=POINTS_ADDING;
00534                 };
00535             }
00536             else
00537             {
00538                 HuginBase::UIntSet points;
00539                 if(SelectPointsInsideMouseRect(points,false))
00540                 {
00541                     for(HuginBase::UIntSet::const_iterator it=points.begin();it!=points.end();++it)
00542                         m_selectedPoints.insert(*it);
00543                     m_maskEditState=POINTS_MOVING;
00544                 }
00545                 else
00546                 {
00547                     m_maskEditState=REGION_SELECTING;
00548                     DrawSelectionRectangle();
00549                 }
00550             };
00551             break;
00552         case POINTS_SELECTED:
00553             if(mouse.CmdDown())
00554             {
00555                 // check if mouse clicks happens near one line of active polygon
00556                 unsigned int index=m_editingMask.FindPointNearPos(currentPos, 5*maxSelectionDistance);
00557                 if(index<UINT_MAX)
00558                 {
00559                     m_selectedPoints.clear();
00560                     m_editingMask.insertPoint(index,currentPos);
00561                     m_selectedPoints.insert(index);
00562                     m_maskEditState=POINTS_ADDING;
00563                 };
00564             }
00565             else
00566             {
00567                 HuginBase::UIntSet points;
00568                 if(SelectPointsInsideMouseRect(points,true))
00569                 {
00570                     //selected point clicked, starting moving
00571                     m_maskEditState=POINTS_MOVING;
00572                 }
00573                 else
00574                 {
00575                     //unselected point clicked
00576                     if(SelectPointsInsideMouseRect(points,false))
00577                     {
00578                         //clicked near other point
00579                         if(!mouse.ShiftDown())
00580                             m_selectedPoints.clear();
00581                         for(HuginBase::UIntSet::const_iterator it=points.begin();it!=points.end();++it)
00582                             m_selectedPoints.insert(*it);
00583                         m_maskEditState=POINTS_MOVING;
00584                     }
00585                     else
00586                     {
00587                         m_maskEditState=REGION_SELECTING;
00588                         DrawSelectionRectangle();
00589                     };
00590                 }
00591             };
00592             break;
00593         case CROP_SHOWING:
00594             switch(GetClickPos(vigra::Point2D(currentPos.x,currentPos.y)))
00595             {
00596                 case CLICK_OUTSIDE:
00597                     // clicked outside, do nothing
00598                     break;
00599                 case CLICK_INSIDE:
00600                     if(!m_cropCentered)
00601                     {
00602                         m_maskEditState=CROP_MOVING;
00603                     };
00604                     break;
00605                 case CLICK_LEFT:
00606                     m_maskEditState=CROP_LEFT_MOVING;
00607                     break;
00608                 case CLICK_RIGHT:
00609                     m_maskEditState=CROP_RIGHT_MOVING;
00610                     break;
00611                 case CLICK_TOP:
00612                     m_maskEditState=CROP_TOP_MOVING;
00613                     break;
00614                 case CLICK_BOTTOM:
00615                     m_maskEditState=CROP_BOTTOM_MOVING;
00616                     break;
00617                 case CLICK_CIRCLE:
00618                     m_dragStartPos.x=(m_cropRect.left()+m_cropRect.right())/2;
00619                     m_dragStartPos.y=(m_cropRect.top()+m_cropRect.bottom())/2;
00620                     m_maskEditState=CROP_CIRCLE_SCALING;
00621                     break;
00622             };
00623             if(m_maskEditState!=CROP_SHOWING)
00624             {
00625                 if (m_cropMode == HuginBase::SrcPanoImage::NO_CROP && m_cropCircle)
00626                 {
00627 #if defined SUPPORTS_WXINVERT
00628                     DrawCrop();
00629                     m_cropMode = HuginBase::SrcPanoImage::CROP_CIRCLE;
00630                     DrawCrop();
00631 #else
00632                     m_cropMode=HuginBase::SrcPanoImage::CROP_CIRCLE;
00633                     update();
00634 #endif
00635                 };
00636             };
00637             break;
00638         default:
00639             // otherwise do nothing
00640             break;
00641     };
00642 };
00643 
00644 void MaskImageCtrl::OnLeftMouseUp(wxMouseEvent& mouse)
00645 {
00646     if(m_previewOnly)
00647         return;
00648     DEBUG_DEBUG("LEFT MOUSE UP");
00649     wxPoint mpos;
00650     CalcUnscrolledPosition(mouse.GetPosition().x, mouse.GetPosition().y,
00651                            &mpos.x, & mpos.y);
00652     hugin_utils::FDiff2D currentPos=applyRotInv(invtransform(mpos));
00653     bool doUpdate=false;
00654     switch(m_maskEditState)
00655     {
00656         case NEW_POLYGON_STARTED:
00657             doUpdate=true;
00658             m_editingMask.addPoint(currentPos);
00659             m_selectedPoints.insert(m_editingMask.getMaskPolygon().size()-1);
00660             m_maskEditState=NEW_POLYGON_CREATING;
00661             break;
00662         case NEW_POLYGON_CREATING:
00663             //next point of polygen selected
00664             doUpdate=true;
00665             m_editingMask.addPoint(currentPos);
00666             m_selectedPoints.insert(m_editingMask.getMaskPolygon().size()-1);
00667             break;
00668         case POINTS_MOVING:
00669             if(HasCapture())
00670                 ReleaseMouse();
00671             {
00672                 hugin_utils::FDiff2D delta=currentPos-applyRotInv(invtransform(m_dragStartPos));
00673                 if(hugin_utils::sqr(delta.x)+hugin_utils::sqr(delta.y)>hugin_utils::sqr(maxSelectionDistance))
00674                 {
00675                     for(HuginBase::UIntSet::const_iterator it=m_selectedPoints.begin();it!=m_selectedPoints.end();++it)
00676                         m_imageMask[m_activeMask].movePointBy(*it,delta);
00677                     m_maskEditState=POINTS_SELECTED;
00678                     m_editPanel->UpdateMask();
00679                 }
00680                 else
00681                 {
00682                     m_editingMask=m_imageMask[m_activeMask];
00683                     m_maskEditState=POINTS_SELECTED;
00684                     doUpdate=true;
00685                 };
00686             };
00687             break;
00688         case POLYGON_SELECTING:
00689             if(HasCapture())
00690                 ReleaseMouse();
00691 #if defined SUPPORTS_WXINVERT
00692             DrawSelectionRectangle();
00693 #else
00694             doUpdate=true;
00695 #endif
00696             m_currentPos=mpos;
00697             m_maskEditState=NO_SELECTION;
00698             {
00699                 hugin_utils::FDiff2D p;
00700                 p.x=invtransform(m_dragStartPos.x+(m_currentPos.x-m_dragStartPos.x)/2);
00701                 p.y=invtransform(m_dragStartPos.y+(m_currentPos.y-m_dragStartPos.y)/2);
00702                 p=applyRotInv(p);
00703                 FindPolygon(p);
00704             };
00705             break;
00706         case REGION_SELECTING:
00707             {
00708                 if(HasCapture())
00709                     ReleaseMouse();
00710                 DrawSelectionRectangle();
00711                 m_currentPos=mpos;
00712                 bool selectedPoints=!m_selectedPoints.empty();
00713                 if(!mouse.ShiftDown())
00714                     m_selectedPoints.clear();
00715                 if(SelectPointsInsideMouseRect(m_selectedPoints,false))
00716                 {
00717                     //new points selected
00718                     if(m_selectedPoints.empty())
00719                         m_maskEditState=NO_SELECTION;
00720                     else
00721                         m_maskEditState=POINTS_SELECTED;
00722                 }
00723                 else
00724                 {
00725                     //there were no points selected
00726                     if(!selectedPoints)
00727                     {
00728                         //if there where no points selected before, we searching for an other polygon
00729                         hugin_utils::FDiff2D p;
00730                         p.x=invtransform(m_dragStartPos.x+(m_currentPos.x-m_dragStartPos.x)/2);
00731                         p.y=invtransform(m_dragStartPos.y+(m_currentPos.y-m_dragStartPos.y)/2);
00732                         p=applyRotInv(p);
00733                         FindPolygon(p);
00734                     };
00735                     m_maskEditState=NO_SELECTION;
00736                 };
00737                 doUpdate=true;
00738                 break;
00739             };
00740         case POINTS_ADDING:
00741             if(HasCapture())
00742                 ReleaseMouse();
00743             for(HuginBase::UIntSet::const_iterator it=m_selectedPoints.begin();it!=m_selectedPoints.end();++it)
00744                 m_editingMask.movePointTo(*it,currentPos);
00745             m_imageMask[m_activeMask]=m_editingMask;
00746             m_editPanel->UpdateMask();
00747             m_maskEditState=POINTS_SELECTED;
00748             break;
00749         case CROP_MOVING:
00750         case CROP_LEFT_MOVING:
00751         case CROP_RIGHT_MOVING:
00752         case CROP_TOP_MOVING:
00753         case CROP_BOTTOM_MOVING:
00754         case CROP_CIRCLE_SCALING:
00755             if(HasCapture())
00756                 ReleaseMouse();
00757 #if defined SUPPORTS_WXINVERT
00758             DrawCrop();
00759 #else
00760             doUpdate=true;
00761 #endif
00762             UpdateCrop(currentPos);
00763 #if defined SUPPORTS_WXINVERT
00764             DrawCrop();
00765 #endif
00766             m_maskEditState=CROP_SHOWING;
00767             SetCursor(wxNullCursor);
00768             m_editPanel->UpdateCrop(true);
00769             break;
00770         default:
00771             if(HasCapture())
00772                 ReleaseMouse();
00773     };
00774     if(doUpdate)
00775         update();
00776 }
00777 
00778 void MaskImageCtrl::OnLeftMouseDblClick(wxMouseEvent &mouse)
00779 {
00780     if(m_previewOnly)
00781         return;
00782     switch(m_maskEditState)
00783     {
00784         case NEW_POLYGON_STARTED:
00785             {
00786                 m_maskEditState=NO_SELECTION;
00787                 HuginBase::MaskPolygon mask;
00788                 m_editingMask=mask;
00789                 m_selectedPoints.clear();
00790                 MainFrame::Get()->SetStatusText(wxT(""),0);
00791                 break;
00792             };
00793         case NEW_POLYGON_CREATING:
00794             {
00795                 //close newly generated polygon
00796                 m_maskEditState=NO_SELECTION;
00797                 //delete last point otherwise it would be added twice, because we added it
00798                 //already in release left mouse button
00799                 m_editingMask.removePoint(m_editingMask.getMaskPolygon().size()-1);
00800                 if(m_editingMask.getMaskPolygon().size()>2)
00801                 {
00802                     m_imageMask.push_back(m_editingMask);
00803                     m_activeMask=m_imageMask.size()-1;
00804                     m_editPanel->AddMask();
00805                 }
00806                 else
00807                 {
00808                     HuginBase::MaskPolygon mask;
00809                     m_editingMask=mask;
00810                     m_selectedPoints.clear();
00811                     update();
00812                 };
00813                 MainFrame::Get()->SetStatusText(wxT(""),0);
00814                 break;
00815             };
00816         default:
00817             // the other case do nothing here
00818             break;
00819     };
00820 };
00821 
00822 void MaskImageCtrl::OnRightMouseDown(wxMouseEvent& mouse)
00823 {
00824     if(m_previewOnly)
00825         return;
00826     CalcUnscrolledPosition(mouse.GetPosition().x, mouse.GetPosition().y,
00827                            &m_dragStartPos.x, & m_dragStartPos.y);
00828     hugin_utils::FDiff2D currentPos=applyRotInv(invtransform(m_dragStartPos));
00829     m_currentPos=m_dragStartPos;
00830     if(!HasCapture())
00831         CaptureMouse();
00832     SetFocus();
00833     if(m_maskEditState==NO_SELECTION || m_maskEditState==POINTS_SELECTED)
00834     {
00835         if(mouse.CmdDown())
00836         {
00837             m_maskEditState=POINTS_DELETING;
00838             DrawSelectionRectangle();
00839         }
00840         else
00841         {
00842             if (m_editingMask.isInside(currentPos))
00843             {
00844                 fill_set(m_selectedPoints,0,m_editingMask.getMaskPolygon().size()-1);
00845                 m_maskEditState=POINTS_MOVING;
00846                 update();
00847             };
00848         };
00849     };
00850 };
00851 
00852 void MaskImageCtrl::OnRightMouseUp(wxMouseEvent& mouse)
00853 {
00854     if(m_previewOnly)
00855         return;
00856     wxPoint mpos;
00857     CalcUnscrolledPosition(mouse.GetPosition().x, mouse.GetPosition().y,
00858                            &mpos.x, & mpos.y);
00859     hugin_utils::FDiff2D currentPos=applyRotInv(invtransform(mpos));
00860     if(HasCapture())
00861         ReleaseMouse();
00862     switch(m_maskEditState)
00863     {
00864         case NEW_POLYGON_STARTED:
00865             {
00866                 m_maskEditState=NO_SELECTION;
00867                 HuginBase::MaskPolygon mask;
00868                 m_editingMask=mask;
00869                 m_selectedPoints.clear();
00870                 MainFrame::Get()->SetStatusText(wxT(""),0);
00871                 break;
00872             };
00873         case NEW_POLYGON_CREATING:
00874             {
00875                 //close newly generated polygon
00876                 m_maskEditState=NO_SELECTION;
00877                 m_editingMask.movePointTo(m_editingMask.getMaskPolygon().size()-1,currentPos);
00878                 if(m_editingMask.getMaskPolygon().size()>2)
00879                 {
00880                     m_imageMask.push_back(m_editingMask);
00881                     m_activeMask=m_imageMask.size()-1;
00882                     m_editPanel->AddMask();
00883                 }
00884                 else
00885                 {
00886                     HuginBase::MaskPolygon mask;
00887                     m_editingMask=mask;
00888                     m_selectedPoints.clear();
00889                     update();
00890                 };
00891                 MainFrame::Get()->SetStatusText(wxT(""),0);
00892                 break;
00893             };
00894         case POINTS_DELETING:
00895             {
00896                 DrawSelectionRectangle();
00897                 HuginBase::UIntSet points;
00898                 m_currentPos=mpos;
00899                 if(SelectPointsInsideMouseRect(points,false))
00900                 {
00901                     if(m_editingMask.getMaskPolygon().size()-points.size()>2)
00902                     {
00903                         // clear all selected points
00904                         for(HuginBase::UIntSet::const_reverse_iterator it=points.rbegin();it!=points.rend();++it)
00905                             m_editingMask.removePoint(*it);
00906                         // now update set of selected points
00907                         if(m_selectedPoints.size()>0)
00908                         {
00909                             std::vector<unsigned int> mappedSelectedPoints(m_imageMask[m_activeMask].getMaskPolygon().size());
00910                             for(unsigned int i=0;i<mappedSelectedPoints.size();i++)
00911                                 mappedSelectedPoints[i]=i;
00912                             HuginBase::UIntSet temp=m_selectedPoints;
00913                             m_selectedPoints.clear();
00914                             for(HuginBase::UIntSet::const_iterator it=points.begin();it!=points.end();++it)
00915                             {
00916                                 if((*it)<mappedSelectedPoints.size()-1)
00917                                     for(unsigned int i=(*it)+1;i<mappedSelectedPoints.size();i++)
00918                                         mappedSelectedPoints[i]--;
00919                             };
00920                             for(HuginBase::UIntSet::const_iterator it=temp.begin();it!=temp.end();++it)
00921                                 if(!set_contains(points,*it))
00922                                     m_selectedPoints.insert(mappedSelectedPoints[*it]);
00923                         };
00924                         //now update the saved mask
00925                         m_imageMask[m_activeMask]=m_editingMask;
00926                         m_editPanel->UpdateMask();
00927                     }
00928                     else
00929                         wxBell();
00930                 };
00931                 if(m_selectedPoints.size()==0)
00932                     m_maskEditState=NO_SELECTION;
00933                 else
00934                     m_maskEditState=POINTS_SELECTED;
00935                 break;
00936             };
00937         case POINTS_MOVING:
00938             {
00939                 hugin_utils::FDiff2D delta=currentPos-applyRotInv(invtransform(m_dragStartPos));
00940                 if(hugin_utils::sqr(delta.x)+hugin_utils::sqr(delta.y)>hugin_utils::sqr(maxSelectionDistance))
00941                 {
00942                     for(HuginBase::UIntSet::const_iterator it=m_selectedPoints.begin();it!=m_selectedPoints.end();++it)
00943                         m_imageMask[m_activeMask].movePointBy(*it,delta);
00944                     m_maskEditState=POINTS_SELECTED;
00945                     m_editPanel->UpdateMask();
00946                 }
00947                 else
00948                 {
00949                     m_editingMask=m_imageMask[m_activeMask];
00950                     m_maskEditState=POINTS_SELECTED;
00951                 };
00952                 break;
00953             };
00954         default:
00955             break;
00956     };
00957 };
00958 
00959 void MaskImageCtrl::OnKeyUp(wxKeyEvent &e)
00960 {
00961     int key=e.GetKeyCode();
00962     bool processed=false;
00963     if((key==WXK_DELETE) || (key==WXK_NUMPAD_DELETE))
00964     {
00965         if(m_activeMask<UINT_MAX)
00966         {
00967             if (m_maskEditState == POINTS_SELECTED)
00968             {
00969                 if ((m_selectedPoints.size()>0) && (m_editingMask.getMaskPolygon().size() - m_selectedPoints.size() > 2))
00970                 {
00971                     for (HuginBase::UIntSet::const_reverse_iterator it = m_selectedPoints.rbegin(); it != m_selectedPoints.rend(); ++it)
00972                         m_editingMask.removePoint(*it);
00973                     m_imageMask[m_activeMask] = m_editingMask;
00974                     processed = true;
00975                     m_editPanel->UpdateMask();
00976                 }
00977                 else
00978                 {
00979                     if (m_editingMask.getMaskPolygon().size() == m_selectedPoints.size())
00980                     {
00981                         wxCommandEvent dummy;
00982                         processed = true;
00983                         m_editPanel->OnMaskDelete(dummy);
00984                     }
00985                     else
00986                         wxBell();
00987                 };
00988             }
00989             else
00990             {
00991                 if(m_maskEditState==NO_SELECTION)
00992                 {
00993                     wxCommandEvent dummy;
00994                     processed=true;
00995                     m_editPanel->OnMaskDelete(dummy);
00996                 };
00997             };
00998         };
00999     };
01000     if(!processed)
01001         e.Skip();
01002 };
01003 
01004 void MaskImageCtrl::OnCaptureLost(wxMouseCaptureLostEvent &e)
01005 {
01006     wxFocusEvent dummy;
01007     OnKillFocus(dummy);
01008 };
01009 
01010 void MaskImageCtrl::OnKillFocus(wxFocusEvent &e)
01011 {
01012     if(HasCapture())
01013         ReleaseMouse();
01014     if(m_maskEditState==NEW_POLYGON_CREATING || m_maskEditState==NEW_POLYGON_STARTED)
01015     {
01016         wxBell();
01017         m_maskEditState=NO_SELECTION;
01018         HuginBase::MaskPolygon mask;
01019         m_editingMask=mask;
01020         m_selectedPoints.clear();
01021         update();
01022     };
01023 };
01024 
01025 void MaskImageCtrl::startNewPolygon()
01026 {
01027     m_maskEditState=NEW_POLYGON_STARTED;
01028     HuginBase::MaskPolygon newMask;
01029     m_editingMask=newMask;
01030     m_selectedPoints.clear();
01031 };
01032 
01033 wxSize MaskImageCtrl::DoGetBestSize() const
01034 {
01035     return wxSize(m_imageSize.GetWidth(),m_imageSize.GetHeight());
01036 };
01037 
01038 void MaskImageCtrl::update()
01039 {
01040     wxClientDC dc(this);
01041     PrepareDC(dc);
01042     OnDraw(dc);
01043 };
01044 
01045 void MaskImageCtrl::DrawPolygon(wxDC &dc, HuginBase::MaskPolygon poly, bool isSelected, bool drawMarker)
01046 {
01047     unsigned int nrOfPoints=poly.getMaskPolygon().size();
01048     if (nrOfPoints<2)
01049         return;
01050     wxPoint *polygonPoints=new wxPoint[nrOfPoints];
01051     for(unsigned int j=0;j<nrOfPoints;j++)
01052     {
01053         polygonPoints[j]=transform(applyRot(poly.getMaskPolygon()[j]));
01054     };
01055     if(isSelected)
01056         dc.SetPen(wxPen(m_colour_point_unselected, 1, wxPENSTYLE_SOLID));
01057     else
01058         switch(poly.getMaskType())
01059         {
01060             case HuginBase::MaskPolygon::Mask_negative:
01061             case HuginBase::MaskPolygon::Mask_Stack_negative:
01062             case HuginBase::MaskPolygon::Mask_negative_lens:
01063                 dc.SetPen(wxPen(m_colour_polygon_negative, 1, wxPENSTYLE_SOLID));
01064                 break;
01065             case HuginBase::MaskPolygon::Mask_positive:
01066             case HuginBase::MaskPolygon::Mask_Stack_positive:
01067                 dc.SetPen(wxPen(m_colour_polygon_positive, 1, wxPENSTYLE_SOLID));
01068                  break;
01069         };
01070     dc.SetBrush(*wxTRANSPARENT_BRUSH);
01071     if(nrOfPoints>2)
01072         dc.DrawPolygon(nrOfPoints,polygonPoints);
01073     else
01074         dc.DrawLine(polygonPoints[0],polygonPoints[1]);
01075     if(drawMarker)
01076     {
01077         wxPen penSelected(m_colour_point_selected);
01078         wxPen penUnselected(m_colour_point_unselected);
01079         wxBrush brushSelected(m_colour_point_selected);
01080         wxBrush brushUnselected(m_colour_point_unselected);
01081         for(unsigned int j=0;j<nrOfPoints;j++)
01082         {
01083             if(set_contains(m_selectedPoints,j))
01084             {
01085                 dc.SetPen(penSelected);
01086                 dc.SetBrush(brushSelected);
01087             }
01088             else
01089             {
01090                 dc.SetPen(penUnselected);
01091                 dc.SetBrush(brushUnselected);
01092             };
01093             dc.DrawRectangle(polygonPoints[j].x-polygonPointSize,polygonPoints[j].y-polygonPointSize,
01094                             2*polygonPointSize,2*polygonPointSize);
01095         };
01096     };
01097     delete []polygonPoints;
01098 };
01099 
01100 void MaskImageCtrl::DrawCrop()
01101 {
01102     wxClientDC dc(this);
01103     PrepareDC(dc);
01104     DrawCrop(dc);
01105 };
01106 
01107 void MaskImageCtrl::DrawCrop(wxDC & dc)
01108 {
01109     // draw crop rectangle/circle
01110     if(!m_maskMode)
01111     {
01112         // draw all areas without fillings
01113         dc.SetBrush(*wxTRANSPARENT_BRUSH);
01114 #if defined SUPPORTS_WXINVERT
01115         dc.SetLogicalFunction (wxINVERT);
01116 #else
01117         dc.SetPen(wxPen(m_color_selection, 1, wxPENSTYLE_SOLID));
01118 #endif
01119         wxPoint middle=transform(applyRot((m_cropRect.lowerRight()+m_cropRect.upperLeft())/2));
01120 
01121         int c = 8; // size of midpoint cross
01122         dc.DrawLine( middle.x + c, middle.y + c, middle.x - c, middle.y - c);
01123         dc.DrawLine( middle.x - c, middle.y + c, middle.x + c, middle.y - c);
01124         dc.DrawRectangle(wxRect(transform(applyRot(hugin_utils::FDiff2D(m_cropRect.left(), m_cropRect.top()))),
01125                                 transform(applyRot(hugin_utils::FDiff2D(m_cropRect.right(), m_cropRect.bottom())))));
01126 
01127         // draw crop circle as well, if requested.
01128         if (m_cropMode==HuginBase::BaseSrcPanoImage::CROP_CIRCLE)
01129         {
01130             double radius=std::min<int>(m_cropRect.width(),m_cropRect.height())/2.0;
01131             dc.DrawCircle(middle.x, middle.y, scale(radius));
01132         }
01133     };
01134 };
01135 
01136 void MaskImageCtrl::OnDraw(wxDC & dc)
01137 {
01138     if(m_maskEditState!=NO_IMAGE)
01139     {
01140         int offset=scale(HuginBase::maskOffset);
01141         //draw border around image to allow drawing mask over boudaries of image
01142         //don't draw as one complete rectangle to prevent flickering
01143         dc.SetPen(wxPen(GetBackgroundColour(), 1, wxPENSTYLE_SOLID));
01144         dc.SetBrush(wxBrush(GetBackgroundColour(), wxBRUSHSTYLE_SOLID));
01145         dc.DrawRectangle(0,0,offset,m_bitmap.GetHeight()+2*offset);
01146         dc.DrawRectangle(0,0,m_bitmap.GetWidth()+2*offset,offset);
01147         dc.DrawRectangle(m_bitmap.GetWidth()+offset,0,m_bitmap.GetWidth()+2*offset,m_bitmap.GetHeight()+2*offset);
01148         dc.DrawRectangle(0,m_bitmap.GetHeight()+offset,m_bitmap.GetWidth()+2*offset,m_bitmap.GetHeight()+2*offset);
01149         dc.DrawBitmap(m_bitmap,offset,offset);
01150         if(m_fitToWindow)
01151         {
01152             //draw border when image is fit to window, otherwise the border (without image) is not updated
01153             wxSize clientSize=GetClientSize();
01154             if(m_bitmap.GetWidth()+2*offset<clientSize.GetWidth())
01155             {
01156                 dc.DrawRectangle(m_bitmap.GetWidth()+2*offset,0,clientSize.GetWidth()-m_bitmap.GetWidth()+2*offset,clientSize.GetHeight());
01157             };
01158             if(m_bitmap.GetHeight()+2*offset<clientSize.GetHeight())
01159             {
01160                 dc.DrawRectangle(0,m_bitmap.GetHeight()+2*offset,clientSize.GetWidth(),clientSize.GetHeight()-m_bitmap.GetHeight()+2*offset);
01161             };
01162         };
01163         if (m_maskMode && m_showActiveMasks && (m_cropMode != HuginBase::SrcPanoImage::NO_CROP || m_masksToDraw.size()>0))
01164         {
01165             //whole image, we need it several times
01166             wxRegion wholeImage(transform(applyRot(hugin_utils::FDiff2D(0,0))),
01167                                 transform(applyRot(hugin_utils::FDiff2D(m_realSize.GetWidth(),m_realSize.GetHeight()))));
01168             wxRegion region;
01169             if (m_cropMode != HuginBase::SrcPanoImage::NO_CROP)
01170             {
01171                 region.Union(wholeImage);
01172                 //now the crop
01173                 switch(m_cropMode)
01174                 {
01175                     case HuginBase::SrcPanoImage::CROP_RECTANGLE:
01176                         region.Subtract(wxRegion(transform(applyRot(m_cropRect.upperLeft())),
01177                             transform(applyRot(m_cropRect.lowerRight()))));
01178                         break;
01179                     case HuginBase::SrcPanoImage::CROP_CIRCLE:
01180                         {
01181                             unsigned int nrOfPoints = dc.GetSize().GetWidth() * 2;
01182                             wxPoint* circlePoints = new wxPoint[nrOfPoints];
01183                             vigra::Point2D middle = (m_cropRect.lowerRight() + m_cropRect.upperLeft()) / 2;
01184                             double radius = std::min<int>(m_cropRect.width(), m_cropRect.height()) / 2;
01185                             double interval = 2 * PI / nrOfPoints;
01186                             for (unsigned int i = 0; i < nrOfPoints; i++)
01187                             {
01188                                 circlePoints[i] = transform(applyRot(hugin_utils::FDiff2D(middle.x + radius*cos(i*interval), middle.y + radius*sin(i*interval))));
01189                             };
01190                             region.Subtract(wxRegion(nrOfPoints, circlePoints));
01191                             delete[]circlePoints;
01192                         }
01193                         break;
01194                     case HuginBase::BaseSrcPanoImage::NO_CROP:
01195                         break;
01196                 };
01197             };
01198             if(m_masksToDraw.size()>0)
01199             {
01200                 for(unsigned int i=0;i<m_masksToDraw.size();i++)
01201                 {
01202                     HuginBase::VectorPolygon poly=m_masksToDraw[i].getMaskPolygon();
01203                     wxPoint *polygonPoints=new wxPoint[poly.size()];
01204                     for(unsigned int j=0;j<poly.size();j++)
01205                     {
01206                         polygonPoints[j]=transform(applyRot(poly[j]));
01207                     };
01208                     wxRegion singleRegion(poly.size(),polygonPoints,wxWINDING_RULE);
01209                     if(m_masksToDraw[i].isInverted())
01210                     {
01211                         wxRegion newRegion(wholeImage);
01212                         newRegion.Subtract(singleRegion);
01213                         region.Union(newRegion);
01214                     }
01215                     else
01216                     {
01217                         region.Union(singleRegion);
01218                     };
01219                     delete []polygonPoints;
01220                 };
01221             };
01222 #ifndef __WXMAC__
01223             // on Windows and GTK we need to compensate to clipping region
01224             // by the scroll offset
01225             // this seems not to be necessary for wxMac
01226             int x;
01227             int y;
01228             GetViewStart(&x,&y);
01229             region.Offset(-x,-y);
01230 #endif
01231             dc.SetDeviceClippingRegion(region);
01232             dc.DrawBitmap(m_disabledBitmap,offset,offset);
01233             dc.DestroyClippingRegion();
01234         };
01235         DrawCrop(dc);
01236         if(m_maskMode && m_imageMask.size()>0)
01237         {
01238             //now draw all polygons
01239             HuginBase::MaskPolygonVector maskList=m_imageMask;
01240             bool drawSelected=(m_maskEditState!=POINTS_ADDING && m_maskEditState!=POINTS_MOVING);
01241             for(unsigned int i=0;i<maskList.size();i++)
01242             {
01243                 if(i!=m_activeMask)
01244                     DrawPolygon(dc,maskList[i],false,false);
01245                 else
01246                     if(drawSelected)
01247                         DrawPolygon(dc,maskList[i],true,true);
01248             };
01249         };
01250         //and now the actual polygon
01251         if(m_maskEditState==POINTS_ADDING || m_maskEditState==POINTS_MOVING || m_maskEditState==NEW_POLYGON_CREATING)
01252             DrawPolygon(dc,m_editingMask,true,true);
01253     }
01254     else
01255     {
01256         // clear the rectangle and exit
01257         dc.SetPen(wxPen(GetBackgroundColour(), 1, wxPENSTYLE_SOLID));
01258         dc.SetBrush(wxBrush(GetBackgroundColour(), wxBRUSHSTYLE_SOLID));
01259         dc.Clear();
01260         return;
01261     };
01262 }
01263 
01264 void MaskImageCtrl::OnSize(wxSizeEvent &e)
01265 {
01266     DEBUG_TRACE("size: " << e.GetSize().GetWidth() << "x" << e.GetSize().GetHeight());
01267     // rescale m_bitmap if needed.
01268     if (m_imageFilename != "") {
01269         if (m_fitToWindow) {
01270             setScale(0);
01271         }
01272     }
01273 };
01274 
01275 void MaskImageCtrl::OnScroll(wxScrollWinEvent &e)
01276 {
01277     m_oldScrollPosX = GetScrollPos(wxHORIZONTAL);
01278     m_oldScrollPosY = GetScrollPos(wxVERTICAL);
01279     e.Skip();
01280 }
01281 
01282 void MaskImageCtrl::rescaleImage()
01283 {
01284     if (m_maskEditState == NO_IMAGE)
01285     {
01286         return;
01287     }
01288 #ifndef SUPPORTS_WXINVERT
01289     //determine average colour and set selection colour corresponding
01290     vigra::FindAverage<vigra::RGBValue<vigra::UInt8> > average;
01291     vigra::inspectImage(vigra::srcImageRange(*(m_img->get8BitImage())), average);
01292     vigra::RGBValue<vigra::UInt8> RGBaverage=average.average();
01293     if(RGBaverage[0]<180 && RGBaverage[1]<180 && RGBaverage[2]<180)
01294     {
01295         m_color_selection=*wxWHITE;
01296     }
01297     else
01298     {
01299         m_color_selection=*wxBLACK;
01300     };
01301 #endif
01302     wxImage img = imageCacheEntry2wxImage(m_img);
01303     if (img.GetWidth() == 0)
01304     {
01305         return;
01306     }
01307     m_imageSize = wxSize(img.GetWidth(), img.GetHeight());
01308     m_realSize = m_imageSize;
01309     m_imageSize.IncBy(2*HuginBase::maskOffset);
01310     if (m_fitToWindow)
01311         m_scaleFactor = calcAutoScaleFactor(m_imageSize);
01312 
01313     //scaling image to screen size
01314     if (getScaleFactor()!=1.0)
01315     {
01316         m_imageSize.SetWidth(scale(m_imageSize.GetWidth()));
01317         m_imageSize.SetHeight(scale(m_imageSize.GetHeight()));
01318         img=img.Scale(scale(m_realSize.GetWidth()), scale(m_realSize.GetHeight()));
01319     }
01320     else
01321     {
01322         //the conversion to disabled m_bitmap would work on the original cached image file
01323         //therefore we need to create a copy to work on it
01324         img=img.Copy();
01325     };
01326     //and now rotating
01327     switch(m_imgRotation)
01328     {
01329         case ROT90:
01330             img = img.Rotate90(true);
01331             break;
01332         case ROT180:
01333                 // this is slower than it needs to be...
01334             img = img.Rotate90(true);
01335             img = img.Rotate90(true);
01336             break;
01337         case ROT270:
01338             img = img.Rotate90(false);
01339             break;
01340         default:
01341             break;
01342     }
01343     // do color correction only if input image has icc profile or if we found a monitor profile
01344     if (!m_img->iccProfile->empty() || huginApp::Get()->HasMonitorProfile())
01345     {
01346         HuginBase::Color::CorrectImage(img, *(m_img->iccProfile), huginApp::Get()->GetMonitorProfile());
01347     };
01348     m_bitmap=wxBitmap(img);
01349 
01350     //create disabled m_bitmap for drawing active masks
01351 #if wxCHECK_VERSION(2,9,0)
01352     img = img.ConvertToDisabled(192);
01353 #else
01354     {
01355         int width = img.GetWidth();
01356         int height = img.GetHeight();
01357         for (int y = height-1; y >= 0; --y)
01358         {
01359             for (int x = width-1; x >= 0; --x)
01360             {
01361                 unsigned char* data = img.GetData() + (y*(width*3))+(x*3);
01362                 unsigned char* r = data;
01363                 unsigned char* g = data+1;
01364                 unsigned char* b = data+2;
01365                 *r=(unsigned char)wxMin(0.6*(*r)+77,255);
01366                 *b=(unsigned char)wxMin(0.6*(*b)+77,255);
01367                 *g=(unsigned char)wxMin(0.6*(*g)+77,255);
01368             }
01369         }
01370     }
01371 #endif
01372     m_disabledBitmap=wxBitmap(img);
01373     if (m_imgRotation == ROT90 || m_imgRotation == ROT270)
01374     {
01375         SetVirtualSize(m_imageSize.GetHeight(), m_imageSize.GetWidth());
01376     }
01377     else
01378     {
01379         SetVirtualSize(m_imageSize.GetWidth(), m_imageSize.GetHeight());
01380     };
01381     SetScrollRate(1,1);
01382     Refresh(true);
01383 };
01384 
01385 void MaskImageCtrl::DrawSelectionRectangle()
01386 {
01387     wxClientDC dc(this);
01388     PrepareDC(dc);
01389 #if defined SUPPORTS_WXINVERT
01390     dc.SetLogicalFunction(wxINVERT);
01391     dc.SetPen(wxPen(*wxWHITE, 1, wxPENSTYLE_DOT));
01392 #else
01393     OnDraw(dc);
01394     dc.SetPen(wxPen(m_color_selection, scale(1), wxPENSTYLE_DOT));
01395 #endif
01396     dc.SetBrush(*wxTRANSPARENT_BRUSH);
01397     dc.DrawRectangle(m_dragStartPos.x,m_dragStartPos.y,
01398         (m_currentPos.x-m_dragStartPos.x),(m_currentPos.y-m_dragStartPos.y));
01399 };
01400 
01401 void MaskImageCtrl::FindPolygon(hugin_utils::FDiff2D p)
01402 {
01403     unsigned int selectedPolygon=UINT_MAX;
01404     unsigned int i=0;
01405     while(selectedPolygon==UINT_MAX && i<m_imageMask.size())
01406     {
01407         if(m_imageMask[i].isInside(p))
01408             selectedPolygon=i;
01409         i++;
01410     };
01411     if(selectedPolygon<UINT_MAX)
01412         m_editPanel->SelectMask(selectedPolygon);
01413 };
01414 
01415 bool MaskImageCtrl::SelectPointsInsideMouseRect(HuginBase::UIntSet &points,const bool considerSelectedOnly)
01416 {
01417     bool found=false;
01418     hugin_utils::FDiff2D p1=applyRotInv(invtransform(m_dragStartPos));
01419     hugin_utils::FDiff2D p2=applyRotInv(invtransform(m_currentPos));
01420     double xmin=std::min(p1.x,p2.x)-maxSelectionDistance;
01421     double xmax=std::max(p1.x,p2.x)+maxSelectionDistance;
01422     double ymin=std::min(p1.y,p2.y)-maxSelectionDistance;
01423     double ymax=std::max(p1.y,p2.y)+maxSelectionDistance;
01424     const HuginBase::VectorPolygon poly=m_editingMask.getMaskPolygon();
01425     for(unsigned int i=0;i<poly.size();i++)
01426     {
01427         bool activePoints=true;
01428         if(considerSelectedOnly)
01429             activePoints=set_contains(m_selectedPoints,i);
01430         if(activePoints && xmin<=poly[i].x && poly[i].x<=xmax && ymin<=poly[i].y && poly[i].y<=ymax)
01431         {
01432             points.insert(i);
01433             found=true;
01434         };
01435     };
01436     return found;
01437 };
01438 
01439 void MaskImageCtrl::setScale(double factor)
01440 {
01441     if (factor == 0)
01442     {
01443         m_fitToWindow = true;
01444         factor = calcAutoScaleFactor(m_imageSize);
01445     }
01446     else
01447     {
01448         m_fitToWindow = false;
01449     }
01450     DEBUG_DEBUG("new scale factor:" << factor);
01451     // update if factor changed
01452     if (factor != m_scaleFactor)
01453     {
01454         m_scaleFactor = factor;
01455         // keep existing scale focussed.
01456         rescaleImage();
01457     }
01458 };
01459 
01460 double MaskImageCtrl::calcAutoScaleFactor(wxSize size)
01461 {
01462     int w = size.GetWidth();
01463     int h = size.GetHeight();
01464     if (m_imgRotation ==  ROT90 || m_imgRotation == ROT270)
01465     {
01466         int t = w;
01467         w = h;
01468         h = t;
01469     }
01470 
01471     wxSize csize = GetSize();
01472     DEBUG_DEBUG("csize: " << csize.GetWidth() << "x" << csize.GetHeight() << "image: " << w << "x" << h);
01473     double s1 = (double)csize.GetWidth()/w;
01474     double s2 = (double)csize.GetHeight()/h;
01475     DEBUG_DEBUG("s1: " << s1 << "  s2:" << s2);
01476     return s1 < s2 ? s1 : s2;
01477 };
01478 
01479 double MaskImageCtrl::getScaleFactor() const
01480 {
01481     return m_scaleFactor;
01482 };
01483 
01484 void MaskImageCtrl::setDrawingActiveMasks(bool newDrawActiveMasks)
01485 {
01486     m_showActiveMasks=newDrawActiveMasks;
01487     update();
01488 };
01489 
01490 IMPLEMENT_DYNAMIC_CLASS(MaskImageCtrl, wxScrolledWindow)
01491 
01492 MaskImageCtrlXmlHandler::MaskImageCtrlXmlHandler()
01493                 : wxXmlResourceHandler()
01494 {
01495     AddWindowStyles();
01496 };
01497 
01498 wxObject *MaskImageCtrlXmlHandler::DoCreateResource()
01499 {
01500     XRC_MAKE_INSTANCE(cp, MaskImageCtrl)
01501 
01502     cp->Create(m_parentAsWindow,
01503                    GetID(),
01504                    GetPosition(), GetSize(),
01505                    GetStyle(wxT("style")),
01506                    GetName());
01507 
01508     SetupWindow(cp);
01509 
01510     return cp;
01511 };
01512 
01513 bool MaskImageCtrlXmlHandler::CanHandle(wxXmlNode *node)
01514 {
01515     return IsOfClass(node, wxT("MaskImageCtrl"));
01516 };
01517 
01518 IMPLEMENT_DYNAMIC_CLASS(MaskImageCtrlXmlHandler, wxXmlResourceHandler)

Generated on 28 May 2016 for Hugintrunk by  doxygen 1.4.7